From ae90f9d5654fbd350fd8a298797a47d5d4d39a14 Mon Sep 17 00:00:00 2001 From: Clay Uy <227580+clayuy@users.noreply.github.com> Date: Thu, 29 Sep 2022 19:46:24 -0400 Subject: [PATCH] Update ExifTool to 12.45 Update ExifTool to version 12.45 released on Sep 16, 2022. --- src/Image-ExifTool/Changes | 1754 ++- src/Image-ExifTool/README | 105 +- src/Image-ExifTool/exiftool | 1701 ++- src/Image-ExifTool/lib/File/RandomAccess.pm | 2 +- src/Image-ExifTool/lib/File/RandomAccess.pod | 4 +- src/Image-ExifTool/lib/Image/ExifTool.pm | 1554 +- src/Image-ExifTool/lib/Image/ExifTool.pod | 615 +- src/Image-ExifTool/lib/Image/ExifTool/AES.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/AFCP.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/AIFF.pm | 29 +- src/Image-ExifTool/lib/Image/ExifTool/APE.pm | 6 +- .../lib/Image/ExifTool/APP12.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/ASF.pm | 2 +- .../lib/Image/ExifTool/Apple.pm | 20 +- .../lib/Image/ExifTool/Audible.pm | 317 + src/Image-ExifTool/lib/Image/ExifTool/BMP.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/BPG.pm | 253 + src/Image-ExifTool/lib/Image/ExifTool/BZZ.pm | 2 +- .../lib/Image/ExifTool/BigTIFF.pm | 45 +- .../lib/Image/ExifTool/BuildTagLookup.pm | 309 +- src/Image-ExifTool/lib/Image/ExifTool/CBOR.pm | 331 + .../lib/Image/ExifTool/Canon.pm | 857 +- .../lib/Image/ExifTool/CanonCustom.pm | 160 +- .../lib/Image/ExifTool/CanonRaw.pm | 6 +- .../lib/Image/ExifTool/CanonVRD.pm | 51 +- .../lib/Image/ExifTool/CaptureOne.pm | 2 +- .../lib/Image/ExifTool/Casio.pm | 4 +- .../lib/Image/ExifTool/Charset.pm | 15 +- .../lib/Image/ExifTool/Charset/DOSCyrillic.pm | 49 + .../lib/Image/ExifTool/Charset/DOSLatin1.pm | 49 + .../lib/Image/ExifTool/Charset/DOSLatinUS.pm | 49 + .../lib/Image/ExifTool/DICOM.pm | 17 +- src/Image-ExifTool/lib/Image/ExifTool/DJI.pm | 223 + src/Image-ExifTool/lib/Image/ExifTool/DNG.pm | 14 +- src/Image-ExifTool/lib/Image/ExifTool/DPX.pm | 73 +- src/Image-ExifTool/lib/Image/ExifTool/DV.pm | 26 +- .../lib/Image/ExifTool/DarwinCore.pm | 43 +- src/Image-ExifTool/lib/Image/ExifTool/DjVu.pm | 16 +- src/Image-ExifTool/lib/Image/ExifTool/EXE.pm | 31 +- src/Image-ExifTool/lib/Image/ExifTool/Exif.pm | 837 +- src/Image-ExifTool/lib/Image/ExifTool/FITS.pm | 159 + src/Image-ExifTool/lib/Image/ExifTool/FLAC.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/FLIF.pm | 353 + src/Image-ExifTool/lib/Image/ExifTool/FLIR.pm | 87 +- .../lib/Image/ExifTool/Fixup.pm | 2 +- .../lib/Image/ExifTool/Flash.pm | 4 +- .../lib/Image/ExifTool/FlashPix.pm | 150 +- src/Image-ExifTool/lib/Image/ExifTool/Font.pm | 27 +- .../lib/Image/ExifTool/FotoStation.pm | 2 +- .../lib/Image/ExifTool/FujiFilm.pm | 223 +- src/Image-ExifTool/lib/Image/ExifTool/GE.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/GIF.pm | 21 +- src/Image-ExifTool/lib/Image/ExifTool/GIMP.pm | 4 +- src/Image-ExifTool/lib/Image/ExifTool/GPS.pm | 96 +- .../lib/Image/ExifTool/GeoTiff.pm | 6 +- .../lib/Image/ExifTool/Geotag.pm | 213 +- .../lib/Image/ExifTool/GoPro.pm | 757 + src/Image-ExifTool/lib/Image/ExifTool/H264.pm | 33 +- src/Image-ExifTool/lib/Image/ExifTool/HP.pm | 4 +- src/Image-ExifTool/lib/Image/ExifTool/HTML.pm | 27 +- .../lib/Image/ExifTool/HtmlDump.pm | 88 +- .../lib/Image/ExifTool/ICC_Profile.pm | 123 +- src/Image-ExifTool/lib/Image/ExifTool/ID3.pm | 134 +- src/Image-ExifTool/lib/Image/ExifTool/IPTC.pm | 41 +- src/Image-ExifTool/lib/Image/ExifTool/ISO.pm | 206 + src/Image-ExifTool/lib/Image/ExifTool/ITC.pm | 2 +- .../lib/Image/ExifTool/Import.pm | 27 +- .../lib/Image/ExifTool/InDesign.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/JPEG.pm | 138 +- .../lib/Image/ExifTool/JPEGDigest.pm | 4 +- src/Image-ExifTool/lib/Image/ExifTool/JSON.pm | 190 + src/Image-ExifTool/lib/Image/ExifTool/JVC.pm | 2 +- .../lib/Image/ExifTool/Jpeg2000.pm | 533 +- .../lib/Image/ExifTool/Kodak.pm | 13 +- .../lib/Image/ExifTool/KyoceraRaw.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/LIF.pm | 153 + src/Image-ExifTool/lib/Image/ExifTool/LNK.pm | 9 +- .../lib/Image/ExifTool/Lang/cs.pm | 2 +- .../lib/Image/ExifTool/Lang/de.pm | 64 +- .../lib/Image/ExifTool/Lang/en_ca.pm | 2 +- .../lib/Image/ExifTool/Lang/en_gb.pm | 2 +- .../lib/Image/ExifTool/Lang/es.pm | 8 +- .../lib/Image/ExifTool/Lang/fi.pm | 50 +- .../lib/Image/ExifTool/Lang/fr.pm | 6 +- .../lib/Image/ExifTool/Lang/it.pm | 11 +- .../lib/Image/ExifTool/Lang/ja.pm | 18 +- .../lib/Image/ExifTool/Lang/ko.pm | 7 +- .../lib/Image/ExifTool/Lang/nl.pm | 126 +- .../lib/Image/ExifTool/Lang/pl.pm | 6 +- .../lib/Image/ExifTool/Lang/ru.pm | 5884 ++++++- .../lib/Image/ExifTool/Lang/sv.pm | 2 +- .../lib/Image/ExifTool/Lang/tr.pm | 6 +- .../lib/Image/ExifTool/Lang/zh_cn.pm | 2 +- .../lib/Image/ExifTool/Lang/zh_tw.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/Leaf.pm | 2 +- .../lib/Image/ExifTool/Lytro.pm | 3 +- src/Image-ExifTool/lib/Image/ExifTool/M2TS.pm | 212 +- src/Image-ExifTool/lib/Image/ExifTool/MIE.pm | 26 +- .../lib/Image/ExifTool/MIEUnits.pod | 2 +- src/Image-ExifTool/lib/Image/ExifTool/MIFF.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/MNG.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/MOI.pm | 159 + src/Image-ExifTool/lib/Image/ExifTool/MPC.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/MPEG.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/MPF.pm | 10 +- src/Image-ExifTool/lib/Image/ExifTool/MRC.pm | 341 + src/Image-ExifTool/lib/Image/ExifTool/MWG.pm | 32 +- src/Image-ExifTool/lib/Image/ExifTool/MXF.pm | 4 +- .../lib/Image/ExifTool/MacOS.pm | 735 + .../lib/Image/ExifTool/MakerNotes.pm | 67 +- .../lib/Image/ExifTool/Matroska.pm | 56 +- .../lib/Image/ExifTool/Microsoft.pm | 384 +- .../lib/Image/ExifTool/Minolta.pm | 214 +- .../lib/Image/ExifTool/MinoltaRaw.pm | 23 +- .../lib/Image/ExifTool/Motorola.pm | 178 + .../lib/Image/ExifTool/Nikon.pm | 3682 ++++- .../lib/Image/ExifTool/NikonCapture.pm | 2 +- .../lib/Image/ExifTool/NikonCustom.pm | 580 +- .../lib/Image/ExifTool/NikonSettings.pm | 2093 +++ .../lib/Image/ExifTool/Nintendo.pm | 2 +- .../lib/Image/ExifTool/OOXML.pm | 5 +- src/Image-ExifTool/lib/Image/ExifTool/Ogg.pm | 2 +- .../lib/Image/ExifTool/Olympus.pm | 160 +- .../lib/Image/ExifTool/OpenEXR.pm | 15 +- src/Image-ExifTool/lib/Image/ExifTool/Opus.pm | 98 + .../lib/Image/ExifTool/Other.pm | 93 + src/Image-ExifTool/lib/Image/ExifTool/PCX.pm | 138 + src/Image-ExifTool/lib/Image/ExifTool/PDF.pm | 147 +- src/Image-ExifTool/lib/Image/ExifTool/PGF.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/PICT.pm | 8 +- .../lib/Image/ExifTool/PLIST.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/PLUS.pm | 2607 ++++ src/Image-ExifTool/lib/Image/ExifTool/PNG.pm | 303 +- src/Image-ExifTool/lib/Image/ExifTool/PPM.pm | 12 +- src/Image-ExifTool/lib/Image/ExifTool/PSP.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/Palm.pm | 2 +- .../lib/Image/ExifTool/Panasonic.pm | 282 +- .../lib/Image/ExifTool/PanasonicRaw.pm | 100 +- .../lib/Image/ExifTool/Parrot.pm | 846 + .../lib/Image/ExifTool/Pentax.pm | 138 +- .../lib/Image/ExifTool/PhaseOne.pm | 12 +- .../lib/Image/ExifTool/PhotoCD.pm | 5 +- .../lib/Image/ExifTool/PhotoMechanic.pm | 6 +- .../lib/Image/ExifTool/Photoshop.pm | 63 +- .../lib/Image/ExifTool/PostScript.pm | 128 +- .../lib/Image/ExifTool/PrintIM.pm | 2 +- .../lib/Image/ExifTool/Qualcomm.pm | 2 +- .../lib/Image/ExifTool/QuickTime.pm | 2720 +++- .../lib/Image/ExifTool/QuickTimeStream.pl | 2934 ++++ src/Image-ExifTool/lib/Image/ExifTool/README | 294 +- src/Image-ExifTool/lib/Image/ExifTool/RIFF.pm | 376 +- src/Image-ExifTool/lib/Image/ExifTool/RSRC.pm | 30 +- src/Image-ExifTool/lib/Image/ExifTool/RTF.pm | 23 +- .../lib/Image/ExifTool/Radiance.pm | 11 +- .../lib/Image/ExifTool/Rawzor.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/Real.pm | 2 +- .../lib/Image/ExifTool/Reconyx.pm | 131 +- src/Image-ExifTool/lib/Image/ExifTool/Red.pm | 325 + .../lib/Image/ExifTool/Ricoh.pm | 30 +- .../lib/Image/ExifTool/Samsung.pm | 453 +- .../lib/Image/ExifTool/Sanyo.pm | 2 +- .../lib/Image/ExifTool/Scalado.pm | 2 +- .../lib/Image/ExifTool/Shift.pl | 39 +- .../lib/Image/ExifTool/Shortcuts.pm | 18 +- .../lib/Image/ExifTool/Sigma.pm | 198 +- .../lib/Image/ExifTool/SigmaRaw.pm | 75 +- src/Image-ExifTool/lib/Image/ExifTool/Sony.pm | 1296 +- .../lib/Image/ExifTool/SonyIDC.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/Stim.pm | 6 +- .../lib/Image/ExifTool/TagInfoXML.pm | 34 +- .../lib/Image/ExifTool/TagLookup.pm | 12693 +++++++++------- .../lib/Image/ExifTool/TagNames.pod | 7834 ++++++++-- src/Image-ExifTool/lib/Image/ExifTool/Text.pm | 245 + .../lib/Image/ExifTool/Theora.pm | 2 +- .../lib/Image/ExifTool/Torrent.pm | 43 +- .../lib/Image/ExifTool/Unknown.pm | 2 +- .../lib/Image/ExifTool/VCard.pm | 443 + .../lib/Image/ExifTool/Validate.pm | 672 + .../lib/Image/ExifTool/Vorbis.pm | 2 +- src/Image-ExifTool/lib/Image/ExifTool/WTV.pm | 319 + .../lib/Image/ExifTool/WriteCanonRaw.pl | 14 +- .../lib/Image/ExifTool/WriteExif.pl | 150 +- .../lib/Image/ExifTool/WriteIPTC.pl | 20 +- .../lib/Image/ExifTool/WritePDF.pl | 13 +- .../lib/Image/ExifTool/WritePNG.pl | 88 +- .../lib/Image/ExifTool/WritePhotoshop.pl | 8 +- .../lib/Image/ExifTool/WritePostScript.pl | 92 +- .../lib/Image/ExifTool/WriteQuickTime.pl | 1864 ++- .../lib/Image/ExifTool/WriteXMP.pl | 308 +- .../lib/Image/ExifTool/Writer.pl | 671 +- src/Image-ExifTool/lib/Image/ExifTool/XMP.pm | 577 +- src/Image-ExifTool/lib/Image/ExifTool/XMP2.pl | 378 +- .../lib/Image/ExifTool/XMPStruct.pl | 76 +- src/Image-ExifTool/lib/Image/ExifTool/ZIP.pm | 52 +- .../lib/Image/ExifTool/ZISRAW.pm | 242 + .../lib/Image/ExifTool/iWork.pm | 11 +- 196 files changed, 56906 insertions(+), 12527 deletions(-) create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/Audible.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/BPG.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/CBOR.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/Charset/DOSCyrillic.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/Charset/DOSLatin1.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/Charset/DOSLatinUS.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/DJI.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/FITS.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/FLIF.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/GoPro.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/ISO.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/JSON.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/LIF.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/MOI.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/MRC.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/MacOS.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/Motorola.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/NikonSettings.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/Opus.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/Other.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/PCX.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/PLUS.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/Parrot.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/QuickTimeStream.pl create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/Red.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/Text.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/VCard.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/Validate.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/WTV.pm create mode 100644 src/Image-ExifTool/lib/Image/ExifTool/ZISRAW.pm diff --git a/src/Image-ExifTool/Changes b/src/Image-ExifTool/Changes index b4a11492..6ecfebbd 100644 --- a/src/Image-ExifTool/Changes +++ b/src/Image-ExifTool/Changes @@ -2,10 +2,1686 @@ DO NOT EDIT THIS FILE -- it is generated from the html history files. ExifTool Version History -RSS feed: http://owl.phy.queensu.ca/~phil/exiftool/rss.xml +RSS feed: https://exiftool.org/rss.xml -Note: The most recent production release is Version 11.11. (Other versions are -considered development releases, and are not uploaded to CPAN.) +Note: The most recent production release is Version 12.42. (Other versions are +considered development releases, and are not uploaded to MetaCPAN.) + +Sept. 16, 2022 - Version 12.45 + + - Added new IPTC Video Metadata version 1.3 tags + - Added a couple of new Canon lenses (thanks Norbert Wasser) + - Added a new Sony LensType (thanks Jos Roost) + - Added known Unknown value for IPTC ChromaticityColorant (thanks Herb) + - Added new Nikon WhiteBalanceFineTune tag (thanks Milos Komarcevic) + - Extract the raw thermal data from all frames of a SEQ file when -ee2 is used + - Decode individual tags in QuickTime ColorRepresentation + - Decode a new Matroska tag + - Improved verbose "nothing changed" messages when writing + - Patched -ee option to extract metadata after the first Cluster in MKV videos + (previously only -U and -v did this) + - Patched to differentiate Java bytecode .class files from Mach-O fat binaries + - Patched to avoid "Use of uninitialized value" warning when deleting GPS + coordinates via the newly writable Composite tags + - Patched to avoid duplicating raw data when writing Sony ARW images where the + raw data is double-referenced as both strips and tiles (affects ARW images + from some newer models like the ILCE-1 when SonyRawFileType is "Lossless + Compressed RAW 2") + - Patched to avoid "fixing" the order of IFD entries in TIFF-based RAW files + to improve compatibility with some RAW viewers + - Minor change to Composite FileNumber to remove "-" when -n is used + - Fixed problem extracting some timed metadata when "-api ignoretags=all" was + used with "-api requesttags" to request the specific information + - Fixed -validate feature to avoid incorrectly warning about non-capitalized + boolean values in XMP + +July 21, 2022 - Version 12.44 + + - Added a few new Sony lenses (thanks Jos Roost) + - Decode Accelerometer and Gyroscope data from ARCore videos + - Decode a couple of new Motorola tags (thanks Neal Krawetz) + - Decode FujiFilm FirmwareVersion (thanks Justin Arkinson) + - Decode MetaType for timed metadata in videos + - Decode a number of new Nikon Z tags (thanks Warren Hatch) + - Extract more types of embedded images from FlashPix-format files + - Made Composite GPSLatitude and GPSLongitude writable for setting GPS + coordinates and reference directions with one assignment + - Fixed bug introduced in 12.39 which broke extraction of timed GPS from some + INNOVV videos + - Fixed bug introduced in 12.43 which broke extraction of timed GPSDateTime + from Insta360 videos + +July 6, 2022 - Version 12.43 + + - Added the ability to geotag from Google Takeout JSON files + - Added a few new Canon RF LensType values and a couple of new CanonModelID's + (thanks Norbert Wasser) + - Added new values to a couple of FujiFilm tags (thanks Greybeard) + - Added a new Nikon LensID (thanks BertJan Bakker) + - Recognize Autodesk Revit files (but don't yet support reading metadata) + - Decode DriveSerialNumber from LNK files (github #145) + - Decode Apple FocusDistanceRange (thanks Neal Krawetz) + - Made a number of Sony SR2SubIFD tags writable + - Tolerate dashes instead of colons as date separators in -geotag CSV files + - Patched to read new format accelerometer data from Insta360 files + - Patched to avoid outputting some Unknown tags when the -validate option is + used after a previously -execute'd command used the -u option + - Fixed names of Canon G9 WB levels tags (changed from GRGB to GRBG) (thanks + Christoph) + - Fixed typo in new Olympus AISubjectTrackingMode value + - Fixed "use of undefined value" warning when reading DJI metadata + - API Changes: + - Added IgnoreTags option + +June 1, 2022 - Version 12.42 (production release) + + - Added support for reading maker notes from Panasonic DC-GH6 videos + - Added conversion for Samsung MCCData + - Added a new Nikon LensID (thanks Chris) + - Added a few new Canon LensType values + - Added a couple of new Olympus StackedImage values (thanks Eberhard) + - Added a few new values for some Nikon Settings tags (thanks Warren Hatch) + - Added a "lang:" element to the -json output for alternate language tags when + -D, -H or -t is used + - Update DNG writer to not issue an error when writing DNG 1.6 files + - Decode information from DJI "ae_dbg_info" maker notes + - Decode Olympus AISubjectTrackingMode + - Changed ExifTool FileSize print conversion to use kB/MB/GB units instead of + KiB/MiB/GiB + - Changed "is not shiftable" warning to appear in -v (instead of just -v3) + output + - Patched to allow PDF Encrypt object to be "null" + - Fixed bug reading ICC_Profile 'meta' tags + +Apr. 7, 2022 - Version 12.41 + + - Added support for "OM SYSTEM" maker notes + - Added 2 new Sony LensType values (thanks Jos Roost) + - Added some new Canon lenses (thanks LibRaw) + - Added a new Nikon LensID (thanks Bert Ligtvoet) + - Added a new Canon ContinuousDrive value (thanks Wolfgang Gulcker) + - Enhanced -v0 option to also print new file name when renaming, moving or + copying a file + - Updated xmp2exif.args and exif2xmp.args helper files to reflect the IPTC + Photometadata Mapping Guidelines version 2202.1 + - Made "Invalid Xxx data" a minor warning for MakerNote data + - Patched to allow writing of MP4 videos which have other tracks with a + missing sample description entry + - Patched MacOS version to specify directory for external utilities (setfile, + xattr, stat, mdls and osascript from /usr/bin, and tag from /usr/local/bin) + - Fixed long-standing problem where Windows version could behave differently + for -if conditions containing undefined tags + - Fixed problem where -W+! combined with -j or -X produced invalid JSON or XML + when processing multiple files + - Fixed potential "uninitialized value $time in division" runtime warning when + reading MP4 videos + +Feb. 9, 2022 - Version 12.40 + + - Added PageCount tag to return the number of pages in a multi-page TIFF + - Added a new Nikon LensID (thanks Wolfgang Exler) + - Added a few more Sony LensTypes (thanks Jos Roost) + - Decode some new Canon tags (thanks Mark Reid) + - Decode another Nikon Z9 tag (thanks Warren Hatch) + - Decode Nikon NKSC GPSImgDirection (thanks Olaf) + - Improved handling of empty XMP structures in lists + - Tolerate leading UTF-8 BOM in -geotag log files + - Updated photoshop_paths.config to include WorkingPath + - Patched to allow writing of MP4 videos which have url tracks with a missing + sample description entry + - Fixed deep recursion error when reading multi-page TIFF images with more + than 100 pages + - Fixed potential deep recursion runtime error when writing nested XMP + structures + - Fixed warning which could be generated when writing new + Composite:GPSCoordinates tag + - Fixed description of GPR (General Purpose RAW) file type + - Fixed typo in the name of a new Nikon tag (thanks Herb) + +Jan. 13, 2022 - Version 12.39 + + - Added a new Pentax LensType (thanks Christian Shulz) + - Added a couple of new Nikon LensID's + - Added support for Nikon NKSC sidecar files + - Decode another type of timed GPS from MP4 videos + - Decode more tags for the Nikon Z7 and Z9 (thanks Warren Hatch) + - Decode a couple more FLIR tags + - Extract ZIP file comments + - Made PNG ProfileName, SRGBRendering and Gamma writable + - Patched to avoid possible problem running "more" to show documentation in + Windows version + - Fixed problem writing Composite:GPSPosition with coordinates in DMS format, + and made this tag protected when writing + - Fixed bug where invalid date/time tags could be written to PNG files when + attempting to shift a non-existent date/time tag + - Fixed spelling of a few Matroska tag names (thanks Martin Hoppenheit) + +Dec. 20, 2021 - Version 12.38 + + - Decode a number of new tags for the Nikon Z9 (thanks Warren Hatch) + - Patched incorrect decoding of AEBShotCount for the Canon EOS 90D + - Patched EXR reader to support long tag names + - Patched security issue (thanks Joe Lothan) + - Fixed an incorrect tag ID for a new Nikon MakerNote tag (github #108) + - Fixed XMP-exif:GPSMeasureMode conversions to match EXIF + - Fixed problem where some namespaces may be undeclared in the -X output when + using the -struct option + +Dec. 8, 2021 - Version 12.37 + + - Decode timed GPS from Vantrue S1 dashcam MP4 videos + - Decode ColorData tags for the Canon EOS R3 (thanks LibRaw) + - Decode more makernotes tags for Nikon Z cameras (thanks Warren Hatch) + - Extract TransparentColor from GIF images + - Improved parsing of input time values for GPSTimeStamp to properly handle a + "." separator + - Improved warning when incorrectly using " + +Nov. 16, 2021 - Version 12.36 + + - IMPORTANT: Fixed bug introduced in 12.35 which corrupted JPEG 2000 images + when removing all metadata with -all= + - Added feature to bypass processing of specified XMP namespaces and + properties (to improve performance in cases where the XMP suffers from + Adobe-editing bloat) + - Added a number of new XMP tags used by Lightroom 11.0 + - Decode a number of new Nikon tags (thanks Warren Hatch) + - Made the Composite GPSPosition tag writable + - Fixed erroneous "Skipped unknown bytes after JPEG SOS" warning + - Fixed group for new writable Jpeg2000 color tags in -listx output + - Fixed problem finding files in Windows when using wildcards in file name and + a drive letter with no slash + +Nov. 11, 2021 - Version 12.35 + + - Added ability to write ICC_Profile (and other color specifications) to + Jpeg2000 images + - Added %o code to -W option format string + - Added %f code to -d option for fractional seconds + - Added a couple of new Sony LensType values (thanks Jos Roost) + - Added a new CanonModelID (thanks Norbert Wasser) + - Added a new Nikon LensID + - Decode more Nikon MakerNotes tags for some new models (thanks Warren Hatch) + - Extract ThumbnailImage from some DJI drone videos + - Enhanced -ee option to extract metadata from all frames in a SEQ file + - Patched to avoid possible "Use of uninitialized value" runtime warning + - Fixed a couple of misspelt new ICC_Profile tag names (thanks Herb) + - Fixed problem generating the correct file extension when extracting + OriginalRawImage from a DNG file using the -W option with the %s format code + - Fixed bug introduced in 11.91 where exiftool couldn't find its libraries + when run via a soft link. Also changed to look for config file in the link + target directory instead of the directory of the link itself + +Oct. 27, 2021 - Version 12.34 + + - Added support for ICC.2:2019 (Profile version 5.0.0 - iccMAX) color profiles + - Added ability to detect/delete a Windows Zone.Identifier alternate data + stream (ADS) via the new ZoneIdentifier tag (thanks Alex Xu) + - Added support for the Sony ILCE-7M4 (thanks Jos Roost) + - Added a new Sony lens (thanks LibRaw and Jos Roost) + - Added a new SonyModelID (thanks LibRaw) + - Added a new Canon RF lens (thanks Norbert Wasser) + - Improved handling of some SVG files + - Patched -overwrite_original_in_place option to open the output file in + update mode rather than write mode (to allow some write optimizations on + certain filesystems) (thanks Joel Low) + - Fixed case of tag ID for new XMP-iptcExt:EventID (thanks Michael Steidl) + - Fixed problem extracting ICC_Profile information from some PDF files + - API Changes: + - Added QuickTimePad option + +Oct. 16, 2021 - Version 12.33 + + - Added support for DNG version 1.6.0.0 + - Added two new Sony LensType values (thanks Jos Roost and LibRaw) + - Added some new elements to the XMP-crs:Look structure (thanks Herb) + - Added a few new IPTC XMP tags (thanks Michael Steidl) + - Added a new Canon RF lens (thanks Norbert Wasser) + - Decode Canon ShutterMode (thanks John Moyer) + - Extract LensModel from some Olympus MOV videos + - Generate MediaDataOffset/Size for MOV videos with zero-sized MDAT chunk + - Improvements to CBOR reader, including hex dump with -v3 option + - Recognize Final Cut Pro XML files + - Allow binary data of Protected tags to be extracted with the -X -j and -php + options with -b by setting the API RequestAll option to 3 + - Changed name of "Canon EF 80-200mm f/4.5-5.6" lens with LensType 38 to add + "II" to the name (Exiv2 issue 1906) + - Fixed runtime warning when processing files with a .DIR extension + +Sept. 30, 2021 - Version 12.32 + + - Added support for CBOR-format metadata in JUMBF (note that JUMBF support is + still experimental) + - Added a new Nikon LensID + - Added a new Pentax LensType + - Decode timed GPS for two more dashcam formats + - Support reference direction columns in -geotag CSV input + - Removed generation of GPSSpeedRef and GPSTrackRef tags in timed metadata for + most dashcam formats when speed is km/h and track is relative to true north + - Patched to allow writing of console output to named pipes + - Fixed formatting of InternalSerialNumber for some Panasonic cameras + - Fixed bug in arg_files/xmp2exif.args support file + +Sept. 22, 2021 - Version 12.31 + + - Added a new SonyModelID and a couple of new Sony lenses (thanks Jos Roost) + - Added a new Canon LensType (thanks Chris Skopec) + - Added Composite GPSLatitude/Longitude tags for Sony videos to combine the + reference hemispheres as with the Composite tags for EXIF GPS + - Decode DPX AspectRatio + - Decode more GoPro MP4 tags + - Extract ICC_Profile from CS0 object in PDF files + - Extract encrypted GPS from Akaso V1 dashcam videos (can't yet decrypt) + - Improved handling of QuickTime iTunesInfo tags, and created new "iTunes" + family 1 group for these + - Patched so NoPDFList option also applies when writing + - Patched to allow user-defined PNG TextualData tags to be written only as iTXt + - Patched PDF reader to avoid concatenating values of multiple List-type tags + into a single tag + +Aug. 12, 2021 - Version 12.30 (production release) + + - Added read support for Portable FloatMap (PFM) images (this was a bit of a + pain because they have the same file extension as Printer Font Metrix files) + - Added a few new Nikon LensID values (thanks LibRaw) + - Added a new Canon LensType + - Added a new Olympus CameraType (thanks LibRaw) + - Added minor warning about unknown data between JPEG segments + - Added a couple of new NikonSettings tags (thanks Warren Hatch) + - Added a new Sony LensType (thanks Jos Roost) + - Decode 'id3 ' chunk in WAV audio files + - Decode timed GPS from concatenated Garmin dashcam videos + - Decode SamsungTrailer information from sefd atom in HEIC images + - Decode more Sony MakerNote tags for the ZV-E10 (thanks Jos Roost) + - Decode DepthMapTiff from JPEG images of more Samsung models + - Decode timed GPS from M2TS videos of yet another type of dashcam + - Extract PreviewImage from Xaiomi MP4 videos + - Changed name of second EmbeddedImage in Samsung trailer to EmbeddedImage2 + - Improved Dutch translations for GPS tags (thanks Peter Dubbelman) + - Allow ICC_Profile to be "deleted" from AVIF files (actually, the profile + isn't really deleted. Instead, a zero-length profile is written to allow a + profile to be added back later since QuickTime item property containers + currently can't be created) + - Patched to remove 2 GB size limit when reading Photoshop ImageSourceData + +July 9, 2021 - Version 12.29 + + - Added a few new Nikon and Olympus lenses (thanks LibRaw) + - Improved a QuickTime "File format error" message to be more meaningful, and + made it a minor error + - Changed PNG writer to add EXIF before IDAT + - Some changes the way JUMBF metadata is handled + - Patched to read timed GPS from a different type of INSV videos + - Patched a security issue + - Fixed problem where ExifTool could hang when processing mebx timed metadata + +June 22, 2021 - Version 12.28 + + - Added read support for Leica Image File (LIF) images + - Added a new Olympus LensType (thanks LibRaw) + - Decode another Panasonic tag (thanks LibRaw) + - Decode more timed metadata from Sony MP4 videos + - Attempt to shorten tag names for metadata in CZI files + - Allow full QuickTime Keys tag ID's in UserDefined tags (fixes backward + incompatibility introduced in 12.02) + - Patched to handle special characters in Torrent tag values + +June 9, 2021 - Version 12.27 + + - Added a new SonyModelID value + - Added two new Nikon LensID values (thanks Daniel) + - Added a new Pentax RawDevelopmentProcess value + - Added a few new Sony LensType values (thanks Jos Roost) + - Added warning if IPTCDigest is not current + - Decode a couple more Pentax tags (thanks LibRaw) + - Decode streaming GPS from Novatek INNOVV MP4 and TS videos + - Improved tag names in config_files/covert_regions.config (thanks StarGeek) + - Changed MIME types for MS Office macro-enabled formats to add the .12 + - Patched Canon LensID logic to properly identify the Canon RF 24-105mm F4 L + IS USM lens + - Patched decoding of camm6 GPSDateTime to use a flexible epoch because other + apps don't seem to use a consistent time zero + - Fixed family 7 group names for QuickTime Keys tags + - Fixed problem reading BeatsPerMinute from some MP4 files + - Fixed hemisphere problem when extracting GPS from 70mai dashcam videos + +May 20, 2021 - Version 12.26 (production release) + + - Added support for JPEG Stereo (JPS) images + - Added a new Sony LensType (thanks LibRaw) + - Added a new PentaxModelID (thanks LibRaw) + - Changed ExifTool namespace URI to use exiftool.org instead of exiftool.ca in + the -X option output (exiftool.ca is still recognized when reading XML) + - Improved handling of large-array warnings in -htmldump output + - Changed handling of escaped characters in #[CSTR] lines of -@ argfile + - Patched security vulnerability in argument of -lang option + - Fixed problem which could cause a "Wide character" warning and generate a + corrupted output file when writing some illegal values + +History of older versions (back to Nov. 19, 2003 - Version 1.00) --> + +Apr. 22, 2021 - Version 12.25 + + - JPEG XL support is now official + - Added read support for Medical Research Council (MRC) image files + - Added ability to write a number of 3gp tags in video files + - Added a new Sony PictureProfile value (thanks Jos Roost) + - Added a new Sony LensType (thanks LibRaw) + - Added a new Nikon LensID (thanks Niels Kristian Bech Jensen) + - Added a new Canon LensType + - Decode more GPS information from Blackvue dashcam videos + - Decode a couple of new NikonSettings tags (thanks Warren Hatch) + - Decode a few new RIFF tags + - Improved Validate option to add minor warning if standard XMP is missing + xpacket wrapper + - Avoid decoding some large arrays in DNG images to improve performance unless + the -m option is used + - Patched bug that could give runtime warning when trying to write an empty + XMP structure + - Fixed decoding of ImageWidth/Height for JPEG XL images + - Fixed problem were Microsoft Xtra tags couldn't be deleted + +Apr. 13, 2021 - Version 12.24 + + - Added a new PhaseOne RawFormat value (thanks LibRaw) + - Decode a new Sony tag (thanks Jos Roost) + - Decode a few new Panasonic and FujiFilm tags (thanks LibRaw and Greybeard) + - Updated acdsee.config in distribution (thanks StarGeek) + - Recognize AutoCAD DXF files + - More work on experimental JUMBF read support + - More work on experimental JPEG XL read/write support + - Patched security vulnerability in DjVu reader + +Apr. 1, 2021 - Version 12.23 + + - Added support for Olympus ORI files + - Added experimental read/write support for JPEG XL images + - Added experimental read support for JUMBF metadata in JPEG and Jpeg2000 + images + - Added built-in support for parsing GPS track from Denver ACG-8050 videos + with the -ee option + - Added a some new Sony lenses (thanks Jos Roost and LibRaw) + - Changed priority of Samsung trailer tags so the first DepthMapImage takes + precedence when -a is not used + - Improved identification of M4A audio files + - Patched to avoid escaping ',' in "Binary data" message when -struct is used + - Removed Unknown flag from MXF VideoCodingSchemeID tag + - Fixed -forcewrite=EXIF to apply to EXIF in binary header of EPS files + - API Changes: + - Added BlockExtract option + +Mar. 17, 2021 - Version 12.22 + + - Added a few new Sony LensTypes and a new SonyModelID (thanks Jos Roost and + LibRaw) + - Added Extra BaseName tag + - Added a new CanonModelID (thanks LibRaw) + - Decode timed GPS from unlisted programs in M2TS videos with the -ee3 option + - Decode more Sony rtmd tags + - Decode some tags for the Sony ILME-FX3 (thanks Jos Roost) + - Allow negative values to be written to XMP-aux:LensID + - Recognize HEVC video program in M2TS files + - Enhanced -b option so --b suppresses tags with binary data + - Improved flexibility when writing GPS coordinates: + - Now pulls latitude and longitude from a combined GPSCoordinates string + - Recognize full word "South" and "West" to write negative coordinates + - Improved warning when trying to write an integer QuickTime date/time tag and + Time::Local is not available + - Convert GPSSpeed from mph to km/h in timed GPS from Garmin MP4 videos + +Feb. 24, 2021 - Version 12.21 + + - Added a few new iOS QuickTime tags + - Decode a couple more Sony rtmd tags + - Patch to avoid possible "Use of uninitialized value" warning when attempting + to write QuickTime date/time tags with an invalid value + - Fixed problem writing Microsoft Xtra tags + - Fixed Windows daylight savings time patch for file times that was broken in + 12.19 (however directory times will not yet handle DST properly) + +Feb. 23, 2021 - Version 12.20 + + - Added ability to write some Microsoft Xtra tags in MOV/MP4 videos + - Added two new Canon LensType values (thanks Norbert Wasser) + - Added a new Nikon LensID + - Fixed problem reading FITS comments that start before column 11 + +Feb. 18, 2021 - Version 12.19 + + - Added -list_dir option + - Added the "ls-l" Shortcut tag + - Extract Comment and History from FITS files + - Enhanced FilePermissions to include device type (similar to "ls -l") + - Changed the name of Apple ContentIdentifier tag to MediaGroupUUID + (thanks Neal Krawetz) + - Fixed a potential "substr outside of string" runtime error when reading + corrupted EXIF + - Fixed edge case where NikonScanIFD may not be copied properly when copying + MakerNotes to another file + - API Changes: + - Added ability to read/write System tags of directories + - Enhanced GetAllGroups() to support family 7 and take optional ExifTool + reference + - Changed QuickTimeHandler option default to 1 + +Feb. 9, 2021 - Version 12.18 + + - Added a new SonyModelID + - Decode a number of Sony tags for the ILCE-1 (thanks Jos Roost) + - Decode a couple of new Canon tags (thanks LibRaw) + - Patched to read differently formatted UserData:Keywords as written by iPhone + - Patched to tolerate out-of-order Nikon MakerNote IFD entries when obtaining + tags necessary for decryption + - Fixed a few possible Condition warnings for some NikonSettings tags + +Feb. 3, 2021 - Version 12.17 + + - Added a new Canon FocusMode value + - Added a new FujiFilm FilmMode value + - Added a number of new XMP-crs tags (thanks Herb) + - Decode a new H264 MDPM tag + - Allow non-conforming lower-case XMP boolean "true" and "false" values to be + written, but only when print conversion is disabled + - Improved Validate option to warn about non-capitalized boolean XMP values + - Improved logic for setting GPSLatitude/LongitudeRef values when writing + - Changed -json and -php options so the -a option is implied even without the + -g option + - Avoid extracting audio/video data from AVI videos when -ee -u is used + - Patched decoding of Canon ContinuousShootingSpeed for newer firmware + versions of the EOS-1DXmkIII + - Re-worked LensID patch of version 12.00 (github issue #51) + - Fixed a few typos in newly-added NikonSettings tags (thanks Herb) + - Fixed problem where group could not be specified for PNG-pHYs tags when + writing + +Jan. 21, 2021 - Version 12.16 (production release) + + - Extract another form of video subtitle text + - Enhanced -ee option with -ee2 and -ee3 to allow parsing of the H264 video + stream in MP4 files + - Changed a Nikon FlashMode value + - Fixed problem that caused a failed DPX test on Strawberry Perl + - API Changes: + - Enhanced ExtractEmbedded option + +Jan. 18, 2021 - Version 12.15 (production release) + + - Added a couple of new Sony LensType values (thanks LibRaw and Jos Roost) + - Added a new Nikon FlashMode value (thanks Mike) + - Decode NikonSettings (thanks Warren Hatch) + - Decode thermal information from DJI RJPEG images + - Fixed extra newline in -echo3 and -echo4 outputs added in version 12.10 + - Fixed out-of-memory problem when writing some very large PNG files under + Windows + +Jan. 6, 2021 - Version 12.14 + + - Added support for 2 more types of timed GPS in video files (that makes 49 + different formats now supported) + - Added validity check for PDF trailer dictionary Size + - Added a new Pentax LensType + - Extract metadata from Jpeg2000 Association box + - Changed -g:XX:YY and -G:XX:YY options to show empty strings for non-existent + groups + - Patched to issue warning and avoid writing date/time values with a zero + month or day number + - Patched to avoid runtime warnings if trying to set FileName to an empty + string + - Fixed issue that could cause GPS test number 12 to fail on some systems + - Fixed problem extracting XML as a block from Jpeg2000 images, and extract + XML tags in the XML group instead of XMP + +Dec. 24, 2020 - Version 12.13 + + - Added -i HIDDEN option to ignore files with names that start with "." + - Added a few new Nikon ShutterMode values (thanks Jan Skoda) + - Added ability to write Google GCamera MicroVideo XMP tags + - Add time zone automatically to most string-based QuickTime date/time tags + when writing unless the PrintConv option is disabled + - Decode a new Sony tag (thanks LibRaw) + - Changed behaviour when writing only pseudo tags to return an error and avoid + writing any other tags if writing FileName fails + - Print "X image files read" message even if only 1 file is read when at least + one other file has failed the -if condition + +Dec. 4, 2020 - Version 12.12 + + - Added ability to geotag from DJI CSV log files + - Added a new CanonModelID + - Added a couple of new Sony LensType values (thanks LibRaw) + - Enhanced -csvDelim option to allow "\t", "\n", "\r" and "\\" + - Unescape "\b" and "\f" in imported JSON values + - Fixed bug introduced in 12.10 which generated a "Not an integer" warning + when attempting to shift some QuickTime date/time tags + - Fixed shared-write permission problem with -@ argfile when using -stay_open + and a filename containing special characters on Windows + +Nov. 27, 2020 - Version 12.11 + + - Added -csvDelim option + - Added new Canon and Olympus LensType values (thanks LibRaw) + - Added a warning if ICC_Profile is deleted from an image (github issue #63) + - EndDir() function for -if option now works when -fileOrder is used + - Changed FileSize conversion to use binary prefixes since that is how the + conversion is currently done (eg. MiB instead of MB) + - Patched -csv option so columns aren't resorted when using -G option and one + of the tags is missing from a file + - Fixed incompatiblity with Google Photos when writing UserData:GPSCoordinates + to MP4 videos + - Fixed problem where the tags available in a -p format string were limited to + the same as the -if[NUM] option when NUM was specified + - Fixed incorrect decoding of SourceFileIndex/SourceDirectoryIndex for Ricoh + models + +Nov. 12, 2020 - Version 12.10 + + - Added -validate test for proper TIFF magic number in JPEG EXIF header + - Added support for Nikon Z7 LensData version 0801 + - Added a new XMP-GPano tag + - Decode ColorData for the Canon EOS 1DXmkIII (thanks LibRaw) + - Decode more tags for the Sony ILCE-7SM3 (thanks Jos Roost) + - Automatically apply QuickTimeUTC option for CR3 files + - Improved decoding of XAttrMDLabel from MacOS files + - Ignore time zones when writing date/time values and using the -d option + - Enhanced -echo3 and -echo4 options to allow exit status to be returned + - Changed -execute so the -q option no longer suppresses the "{ready}" message + when a synchronization number is used (eg. -execute123) + +Oct. 29, 2020 - Version 12.09 + + - Added ability to copy CanonMakerNotes from CR3 images to other file types + - Added read support for ON1 presets file (.ONP) + - Added two new CanonModelID values + - Added trailing "/" when writing QuickTime:GPSCoordinates + - Added a number of new XMP-crs tags + - Added a new Sony LensType (thanks Jos Roost) + - Added a new Nikon Z lens (thanks LibRaw) + - Added a new Canon LensType + - Decode ColorData for Canon EOS R5/R6 + - Decode a couple of new HEIF tags + - Decode FirmwareVersion for Canon M50 + - Improved decoding of Sony CreativeStyle tags (thanks Jos Roost) + - Improved parsing of Radiance files to recognize comments + - Renamed GIF AspectRatio tag to PixelAspectRatio + - Patched EndDir() feature so subdirectories are always processed when -r is + used (previously, EndDir() would end processing of a directory completely) + - Yet another tweak to the EventTime formatting rules (also allow time-only + values with fractional seconds and a time zone) + - Avoid loading GoPro module unnecessarily when reading MP4 videos from some + other cameras + - Fixed problem with an incorrect naming of CodecID tags in some MKV videos + - Fixed verbose output to avoid "adding" messages for existing flattened XMP + tags + +Oct. 15, 2020 - Version 12.08 + + - Added read support for MacOS "._" sidecar files + - Added a new Sony LensType (thanks Jos Roost) + - Recognize Mac OS X xattr files + - Extract ThumbnailImage from MP4 videos of more dashcam models + - Improved decoding of a number of Sony tags (thanks Jos Roost) + - Fixed problem where the special -if EndDir() function didn't work properly + for directories after the one in which it was initially called + - Patched to read DLL files which don't have a .rsrc section (thanks Hank) + - Patched to support new IGC date format when geotagging + - Patched to read DLL files with an invalid size in the header + +Oct. 2, 2020 - Version 12.07 + + - Added support for GoPro .360 videos + - Added some new Canon RF and Nikkor Z lenses (thanks LibRaw) + - Added some new Sony LensType and CreativeStyle values and decode some + ILCE-7C tags (thanks Jos Roost) + - Added a number of new Olympus SceneMode values (thanks Herb) + - Added a new Nikon LensID + - Decode more timed metadata from Insta360 videos (thanks Thomas Allen) + - Decode timed GPS from videos of more Garmin dashcam models + - Decode a new GoPro video tag + - Reformat time-only EventTime values when writing and prevent arbitrary + strings from being written + - Patched to accept backslashes in SourceFile entries for -csv option + +Sept. 11, 2020 - Version 12.06 + + - Added read support for Lyrics3 metadata (and fixed problem where APE + metadata may be ignored if Lyrics3 exists) + - Added a new Panasonic VideoBurstMode value (thanks Klaus Homeister) + - Added a new Olympus MultipleExposureMode value + - Added a new Nikon LensID + - Added back conversions for XMP-dwc EventTime that were removed in 12.04 with + a patch to allow time-only values + - Decode GIF AspectRatio + - Decode Olympus FocusBracketStepSize (thanks Karsten) + - Extract PNG iDOT chunk in Binary format with the name AppleDataOffsets + - Process PNG images which do not start with mandatory IHDR chunk + +Aug. 24, 2020 - Version 12.05 + + - Added a new Panasonic SelfTimer value (thanks Herb) + - Decode a few more DPX tags (thanks Harry Mallon) + - Extract AIFF APPL tag as ApplicationData + - Fixed bug writing QuickTime ItemList 'gnre' Genre values + - Fixed an incorrect value for Panasonic VideoBurstResolution (thanks Herb) + - Fixed problem when applying a time shift to some invalid makernote date/time + values + +Aug. 10, 2020 - Version 12.04 + + - Added read support for Zeiss ZISRAW CZI files + - Added some new values for a couple of Olympus tags (thanks Sebastian) + - Decode a number of new tags for the Sony ILCE-7SM3 (thanks Jos Roost) + - Removed formatting restrictions on XMP-dwc:EventTime to allow a time-only + value to be written + - Moved new QuckTime ItemList tags added in version 12.02 to the proper group + (they were incorrectly added to the Keys group) + - Improved QuickTime -v3 output to show default language codes + - Patched -lang option to work for the values of somet tags with coded + translations + - Patched the format of a number of QuickTime tags when writing for improved + compatibility with iTunes and AtomicParsley + - Patched to write a default QuickTime language code of 0x0000 (null) instead + of 0x55c4 ('und') + +July 29, 2020 - Version 12.03 + + - Added family 7 group names to allow tag ID's to be specified when reading + and writing + - Fixed a couple of typos in tag values (thanks Herb) + - API Changes: + - Added HexTagIDs option + - Enhanced GetNewValue() to allow family 7 groups names to be used + - Internal Changes: + - Changed Composite tag ID's to use "-" instead of "::" as a separator + +July 27, 2020 - Version 12.02 + + - Added support for a number of new QuickTime ItemList tags + - Added support for writing XMP-xmp:RatingPercent + - Added a new Sony LensType (thanks Jos Roost and LibRaw) + - Added a new Pentax LensType (thanks James O'Neill) + - Decode barcodes from Ricoh APP5 RMETA segment + - Decode a few new QuickTime tags written by Ricoh and Garmin cameras + - Decode timed GPS from Sony A7R IV MP4 videos + - Decode timed GPS from 70mai dashcam videos + - Decode a few new Panasonic tags (thanks Klaus Homeister) + - Decode altitude and more accurate latitude/longitude from Transcend Driver + Pro 230 MP4 videos + - Improved decoding of some Canon EOS 1DXmkIII custom functions + - Allow integer QuickTime TrackNumber and DiskNumber values + - Relax validity check of QuickTime:ContentCreateDate when writing with -n + - Removed "Com" from the start of some unknown QuickTime ItemList tag names + - Patched CanonCustom decoding for bug in Canon EOS-1DX firmware + - Changed QuickTime CleanAperture tags decode as signed rationals + +June 24, 2020 - Version 12.01 + + - Added a new NEFCompression value (thanks Warren Hatch) + - Added a new Sony LensType (thanks Jos Roost) + - Decode timed GPS from Rove Stealth 4K dashcam videos + - Fixed bug which would corrupt TIFF images with 16-bit image data offsets + when writing (these are very rare) + +June 11, 2020 - Version 12.00 (production release) + + - Added two new Olympus LensTypes (thanks Don Komarechka for one) + - Added two new Sony LensType values (thanks Jos Roost) + - Added a few new Nikon LensID's (thanks Mathieu Carbou) + - Added support for the Sony ZV-1 (thanks Jos Roost) + - Added a new CanonModelID (thanks Jos Roost) + - Added missing MimeType values for HEICS and HEIFS files + - Added definitions for a number of new XMP-crs tags + - Recognize WOFF and WOFF2 font files + - Decode streaming GPS from Roadhawk, EEEkit and 360Fly MP4 videos + - Decode a number of new tags for the Nikon D6 (thanks Warren Hatch) + - Decode a couple more AF tags for the D500/D850 + - Decode a number of new Panasonic tags + - Improved Composite LensID logic (thanks Matt Stancliff) + - Enhanced -v option to state when a directory has 0 entries + - Removed a couple of incorrect Validate warnings for bilevel TIFF images + - Drop ContrastCurve tag when copying from NEF to JPEG + - Changed -csv output to add "Unknown" group name to column headings for + missing tags when -f and -G options are used + - Patched to support new XMP LensID format for Nikon cameras as written by + Apple Photos (thanks Mattsta) + - Fixed problem extracting metadata from Sigma DP2 Quattro X3F files + - Fixed End() and EndDir() functions so they work when writing and when the -v + option is used + - Fixed problem recognizing some PGM files + - Fixed bug in offsets for some Photoshop information in -v3 output + - Fixed problem writing a list containing empty elements inside an XMP + structure + - API Changes: + - Added NoMultiExif option + - Changed FilterW option to not write tag if $_ is set to undef + +May 11, 2020 - Version 11.99 + + - Added a new Nikon LensID (thanks Mykyta Kozlov) + - Added a new Canon LensType + - Added a newn PentaxModelID + - Decode a few new QuickTime tags + - Decode new ID3 Grouping tag + - Decode a few more MinoltaRaw tags (thanks LibRaw) + - Fixed runtime warning which could occur when reading corrupted RTF files + - Fixed another potential pitfall in M2TS Duration calculation + - Fixed problem extracting some unknown QuickTime:Keys tags + - Fixed problem decoding Nikon D850 orientation tags + - Fixed bug where TIFF image data may not be padded to an even number of bytes + +May 1, 2020 - Version 11.98 + + - Added a new Nikon LensID (thanks Warren Hatch) + - Added a new Sony LensType (thanks LibRaw) + - Added a new Canon LensType + - Patched to extract EXIF with an "Exif\0\0" header from WebP images + - Enhanced -efile option and added to the documentation + - Minor tweak to -htmlDump output (disallow locking of empty selection) + - Fixed problem determining Duration of some M2TS videos + +Apr. 27, 2020 - Version 11.97 + + - Added experimental -efile option (undocumented) + - Decode NMEA GGA sentence from streaming GPS of some dashcam videos + +Apr. 24, 2020 - Version 11.96 + + - Decode streaming GPS from Lucas LK-7900 Ace AVI videos + - Changed new Exit/ExitDir function names to End/EndDir + - Fixed inconsistencies when using "-use mwg" together with the -wm option + +Apr. 23, 2020 - Version 11.95 + + - Added Exit() and ExitDir() functions for use in -if conditions (NOTE: these + function names changed to End() and EndDir() in ExifTool 11.96) + - Enhanced -geotag feature to support a more flexible input CSV file format + - Enhanced -if and API Filter options to allow access to ExifTool object via + $self + - Fixed problem reading HEIC Exif with a missing header + +Apr. 17, 2020 - Version 11.94 + + - Added support for QuickTime ItemList:GPSCoordinates + - Added additional Validate test for overlapping EXIF values + - Added a new Sony LensType (thanks Jos Roost) + - Added a new Nikon LensID + - Decode a few more Nikon tags (thanks Warren Hatch) + - Decode Pentax ShutterType + - Changed color of locked highlighted selection in -htmlDump output + - Fixed problem reading PDF files written by Microsoft Print-to-PDF + - Fixed problem where -X output would produce invalid XML for MP4 files + containing an HTCTrack + +Apr. 3, 2020 - Version 11.93 + + - Added new config file to the distribution for writing Pix4D XMP-Camera tags + (config_files/pix4d.config) + - Added support for the DOSCyrillic (cp866) character set + - Added IO::String to the Windows EXE version + - Improved identification of Canon RF lenses (thanks LibRaw) + - Enhanced -htmlDump output to add "File offset" entry for EXIF tags and + ability lock highlighted selection by clicking the mouse + - Enhanced -srcfile option to generate OriginalFileName and OriginalDirectory + UserParam tags + - Patched HEIC writer to add missing pitm box if necessary + - Fixed problem adding back EXIF after deleting it from HEIC file + - Fixed minor problem with incorrect number of bytes being reported for + invalid header in corrupt files + - API Changes: + - Enhanced UserParam option to allow parameters to be extracted as if + they were normal tags + +Mar. 19, 2020 - Version 11.92 + + - Added a new Nikon LensID (thanks Wolfgang Exler) + - Decode a few new Leica tags (thanks Tim Gray) + - Decode AccelerometerData from Samsung Gear 360 videos + - Fixed a couple of problems decoding timed GPS metadata from NextBase dashcam + videos + - Fixed problem where -X option could produce invalid XML when reading + corrupted XMP + +Mar. 5, 2020 - Version 11.91 + + - Added undocumented -xpath option for use by alternate Windows version + - Decode a couple of new Panasonic tags + - Documented -ec option (available since version 11.54) + - Reverted -htmlDump fix of 11.90 because it broke more than it fixed, and + instead applied a targeted patch to fix this problem for RW2 files + +Mar. 3, 2020 - Version 11.90 + + - Added a new Sony LensType (thanks LibRaw and Jos Roost) + - Added two new Olympus LensType values + - Added a new Canon LensType + - Added some new Canon RecordMode values + - Added some new QuickTime GeneralProfileIDC values + - Added new values for a couple of FujiFilm tags + - Added a number of new QuickTime GenreID values + - Decode Nikon Z6/Z7 phase-detect AF points (thanks Andy Dragon) + - Patched to avoid possible "Undefined subroutine" error in MacOS 10.15 + - Fixed incorrect offsets in -htmlDump output for some file types + +Feb. 25, 2020 - Version 11.89 + + - Added support for Exif 2.32 for XMP + - Recognize the HIF file extension + - Improved verbose output for QuickTime iref items + - Patched to create new GPS metadata in Canon CR3 images using a default byte + order that is the same as existing EXIF boxes + - Patched to add missing newline that could occur in XMP with the API Compact + Shorthand option + +Feb. 20, 2020 - Version 11.88 + + - Added write support for new Google depth-map XMP tags + - Added config_files/depthmap.config to the distribution + - Added minor error when attempting to write FFF images due to incompatibility + with Hasselblad Phocus software + - Patched to avoid "Invalid iloc offset size" error when writing some + QuickTime-based files + - Fixed incorrect ColumnCount for CSV files + - Fixed various spelling errors (thanks Jens Schleusener) + - Fixed bug writing QuickTime:Rotation in HEIC files + +Feb. 13, 2020 - Version 11.87 + + - Added read support for CSV files + - Added "--" option to indicate the end of options + - Added ability to read/write/copy/delete the JPEG trailer as a block + - Added new Olympus CameraType and LensType values (thanks LibRaw) + - Decode a few more FujiFilm tags + - Enhanced -fast option (API FastScan) to bypass PNG CRC validation when + writing + +Feb. 4, 2020 - Version 11.86 + + - Added support for DNG version 1.5 + - Added config_files/acdsee.config to the full distribution (thanks StarGeek) + - Added a new Sony LensType (thanks Jos Roost and LibRaw) + - Decode two more bits from Nikon LensType (thanks LibRaw) + - Decode QuickTime MovieFragmentSequence + - Patched HEIC writer to add missing iref box if necessary + - Fixed typo in a Canon LensType value + - API Changes: + - Patched ImageInfo() to recognize a stringified object as a file name + +Jan. 28, 2020 - Version 11.85 (production release) + + - Added a new Sony LensType (thanks Jos Roost) + - Added a new Olympus CameraType (thanks LibRaw) + - Added a two new Pentax LensType values + - Added a new FujiFilm FocusMode + - Decode timed GPS from Akaso dashcam MOV videos + - Decode Insta360 trailer from INSP images and made Insta360 a deletable group + - Patched kml.fmt file to limit maximum image size (thanks Fedor Kotov) + - Fixed problem decoding values from Leica M10 and S maker notes + +Jan. 10, 2020 - Version 11.84 + + - Decode accelerometer data from timed metadata of more dashcam videos + - Decode Canon G9 white balance tags (thanks LibRaw) + - Recognize INSP files + +Jan. 9, 2020 - Version 11.83 + + - Added a couple of new XMP-crs tags (thanks Herb) + - Fixed bug introduced in 11.82 with the -php -D output + - Fixed problem where some flattened XMP tags could be written when they + should be avoided + +Jan. 8, 2020 - Version 11.82 + + - Added a new Canon LensType + - Added a new CanonModelID (thanks LibRaw) + - Added ability to process SubDirectories in QuickTime Keys tags + - Removed minor error when writing PDF 2.0 files (github issue #30) + - Fixed problem where trailing null bytes were removed from binary values in + the -php output when the -b option was used + +Jan. 2, 2020 - Version 11.81 + + - Added a new Nikon LensID + - Added two new CanonModelID's (thanks LibRaw) + - Decode AVIF AV1 configuration record + - Changed names of QuickTime MovieData tags to "MediaData" + - Patched to use 4-digit years in Time::Local calls + - Patched Composite sub-second date/time tags to do additional validation of + source EXIF date/time tags before adding sub seconds + - Fixed problem where -json output could produce invalid JSON when -struct was + used and the structure field names contained special characters (github + issue #32) + - Fixed spelling in a Panasonic SceneMode value (thanks Hubert) + +Dec. 17, 2019 - Version 11.80 + + - Added a new Canon LensType + - Added a new Nikon Z LensID (thanks LibRaw) + - Added a few new Sony LensType values (thanks Jos Roost) + - Attempt to improve reliability of Samsung DepthMapWidth/Height decoding + - Updated a number of Canon-mount Tamron lens names to include the Tamron + model number + - Patched MOV/MP4 writer to allow a small amount of garbage at the end of a + file to be deleted when writing with the -m option + - Fixed bug where some Composite tags may not have taken priority over other + tags as they should have + +Dec. 12, 2019 - Version 11.79 + + - Added support for AVIF files + - Added new Canon, Sigma and Sony LensType values (thanks LibRaw) + - Made PDF 2.0 writable at your own risk with the -m option (github issue #30) + - Enhanced -validate feature to warn about duplicate languages in an XMP + lang-alt list + - Fixed inconsistency between documentation and ExifTool capabilities for + "Writable" status of some tags + +Dec. 5, 2019 - Version 11.78 + + - Added a new Nikon LensID (thanks Chris) + - Added two new FujiFilm SceneRecognition values + - Patched to avoid crash in Windows when writing a negative epoch time using + the "-d %s" option + - Fixed problem editing MIE tags when using the "-wm w" option + +Nov. 27, 2019 - Version 11.77 + + - Added a new Nikon LensID (thanks Joe Schonberg) + - Added a number of new Olympus LensType values (thanks LibRaw) + - Added a new Canon LensType + - Decode timed GPS from Ambarella A12 dash cam MP4 videos + - Decode a number of new Sigma tags (thanks LibRaw) + - Decode a couple of new PanasonicRaw tags (thanks LibRaw) + - Enhanced -fileOrder option to add -fast feature + +Nov. 12, 2019 - Version 11.76 + + - Added support for the Sony ILCE-9M2 (thanks Jos Roost) + - Added a couple of new XMP-GCamera tags + - Added MIMEType values for some formats that previously reported + "application/unknown" + - Enhanced -geotag feature to write pitch to CameraElevationAngle if available + - Improved determination of MIMEEncoding for TXT files + +Nov. 4, 2019 - Version 11.75 + + - Added ability to read some basic characteristics of TXT files + - Added kml_track.fmt to the fmt_files of the full distribution + - Added built-in support for decoding GPS from the four video subtitle text + formats that were previously handled by separate config files, and removed + these config files from the distribution + - Derive GPSDateTime from CreateDate and SampleTime if not already available + when extracting timed GPS metadata from QuickTime-format videos + - Changed family 2 groups of some Extra tags + +Oct. 29, 2019 - Version 11.74 + + - Added support for new XMP IPTC Extension version 1.5 tags + - Added a new Nikon LensID (thanks LibRaw) + - Decode GPS track from Auto-Vox dashcam MOV videos + - Improved Russian translations (thanks Andrei Korzhyts and Alexander) + - Enhanced convert_regions.config to support new IPTC Extension 1.5 ImageRegion + - Changed the way the FlatName element works when used in a structure element + (the structure name is now added as a prefix to the flattened tag name) + - Patched gpx.fmt and gpx_wpt.fmt to support sub-seconds in GPSDateTime value + +Oct. 23, 2019 - Version 11.73 + + - Decode timed metadata from Parrot drone videos + - Patched dji.config file to properly handle time zones + - Fixed bug which caused runtime error when reading timed metadata from Cobra + Dash Cam AVI videos + +Oct. 22, 2019 - Version 11.72 + + - Added warning messages for corrupted Photoshop document data + - Added a new Olympus CameraType + - Added a new Canon LensType + - Decode more Sigma tags + - Improved Russian translations (thanks Alexander) + - Updated decoding of some CanonCustom settings for recent models + - Documented DNG OpcodeList values + +Oct. 16, 2019 - Version 11.71 + + - Added a new Sony LensType (thanks Jos Roost) + - Added a few new Nikon Z LensID's + - Added a simple print conversion for DNG OpcodeList tags (note that due to + this, these tags must now be copied using the -n option) + - Fixed problems determining some video parameters for DV files + - Changed behaviour of -sep option when writing empty list items + - API Changes: + - Changed ListSplit option to preserve empty list items + +Oct. 10, 2019 - Version 11.70 (production release) + + - Added a new CanonModelID (thanks Laurent Clevy) + - Improved identification of Office Open XML files (github issue #27) + - Removed RAF version check when writing FujiFilm RAF files + - Limited the number of accelerometer records that ExifTool will read by + default with the -ee option from INSV files to avoid excessive processing + times and memory usage + - Patched Windows version to allow reading of shared files with Unicode names + (thanks Eriksson) + - Patched to avoid converting some bad GPS coordinates (thanks Csaba Toth) + - Fixed verbose output to include YCbCrSubSampling for JPEG files + - Fixed conversion and group names for the new FujiFilm tag added in 11.68 + - Fixed format of GeoTiffDirectory and GeoTiffDoubleParams when writing + +Oct. 2, 2019 - Version 11.69 + + - Fixed bug introduced in version 11.66 where the sign was lost when writing + coordinate values between 0 and -1 to QuickTime:GPSCoordinates + +Oct. 1, 2019 - Version 11.68 + + - Added read support for yet another type of streaming GPS in MP4 videos + - Added a number of new FujiFlashMode values + - Decode a new FujiFilm tag + - Made NikonCaptureOffsets and NikonCaptureVersion deletable + - Enhanced tag name documentation to indicate deletable MakerNotes tags + +Sept. 30, 2019 - Version 11.67 + + - Added config_files/thinkware.config to the distribution + - Fixed bug decoding negative GPS coordinates from INSV videos + +Sept. 30, 2019 - Version 11.66 + + - Added a new Nikon LensID (thanks LibRaw) + - Added a few new Canon LensType values (thanks LibRaw and Tom Lachecki) + - Decode a few more Hasselblad tags (thanks LibRaw) + - Decode a new Canon tag (thanks Laurent Clevy) + - Decode more Samsung trailer tags + - Extract BWF iXML, aXML and UMID from RIFF-format files + - Extract ICC_Profile from more types of PDF files + - Enhanced %s of the -W option to recognize the PICT format + - Recognize MacOS alias files + - Changed name of Ricoh CropMode35mm tag and added a new value (thanks LibRaw) + - Minor change to a Minolta lens name (thanks Jos Roost) + - Fixed problem where NikonCapture information couldn't be deleted from an NEF + - Fixed problem identifying some SVG files + - Fixed typo in a CanonModelID value (thanks Dmitry) + - Fixed bug which could result in "Internal error: no list index" warning when + creating nested XMP lang-alt lists + - Fixed the names of a few Tamron lenses for Nikon (thanks Tom Lachecki) + - Fixed problem extracting Layer information from some PSD files + - Fixed writing of QuickTime GPSCoordinates to use the correct number of + digits before the decimal point for latitude and longitude + +Aug. 29, 2019 - Version 11.65 + + - Added new SonyModelID and Sony LensType values (thanks LibRaw and Jos Roost) + - Added support for some new Sony models (thanks Jos Roost) + - Added a couple of new CanonModelID values (thanks LibRaw) + - Added a new Canon ColorDataVersion value + - Enhanced FastScan option so a setting of 2 stops processing PNG images at + the IDAT chunk when reading + - Preserve order of nested lang-alt list entries when -struct option is used + +Aug. 28, 2019 - Version 11.64 + + - Added a new Canon LensType (thanks LibRaw) + - Added a new Nikon LensID (thanks Bruno) + - Added config file for converting streaming GPS from BlueSkySea dashcam + - Decode FocusDistance for Nikon Z6/Z7 + - Documented groups in families 5 and 6 (available but undocumented since + Exiftool version 8.22 and 11.50 respectively) + - Fixed some ordering problems when writing/copying nested XMP lang-alt lists + - Fixed some minor quirks with QuickTime language codes (thanks Hayo Baan) + - Fixed a CanonModelID value (thanks Dmitry) + - API Changes: + - Documented SavePath and SaveFormat options + +Aug. 20, 2019 - Version 11.63 - "PNG Early Text" + + - Added a few new Sigma lenses (thanks LibRaw) + - Improved handling of Canon CNTH atom in MOV/MP4 videos + - Changed PNG writer to place all text chunks before IDAT (not just XMP) + (github issue #23) + - Issue minor warning for any text chunk after PNG IDAT (not just XMP) + - Enhanced ForceWrite feature to allow "PNG" to be specified (to move existing + text chunks to before IDAT without editing any metadata) + - Removed Windows "surrogate" warning for files that wouldn't be processed + anyway + - Fixed some entries in the Minolta LensType list (thanks Jos Roost) + - Fixed identification of a Sony lens (thanks Jos Roost) + +Aug. 15, 2019 - Version 11.62 + + - Added a number of new Canon, Pentax, Sony and Sigma lenses (thanks LibRaw) + - Removed some extraneous verbose warnings when geotagging + - Removed Minolta LensType value for a non-existent lens (thanks LibRaw) + - Patched problem writing some simple qualified XMP values + - Patched to avoid writing files in Windows with Unicode surrogate characters + in their name unless the -overwrite_original_in_place option is used + - Fixed an incorrect Pentax LensType (thanks LibRaw) + - Fixed family 2 group names of some XMP-exifEX and XMP Composite tags + +Aug. 7, 2019 - Version 11.61 + + - Added a new FujiFilm CropMode (thanks LibRaw) + - Added a few new proprietary CustomRendered values (thanks Jeffrey Friedl) + - Added a new Nikon LensID and fixed a Canon LensType (thanks LibRaw) + - Added a new CanonModelID + - Decode more Sony DSC-RX100M7 tags (thanks Jos Roost) + - Write standard EXIF to PNG even if non-standard EXIF already exists + - Changed a Minolta/Sony LensType (thanks LibRaw) + - Changed Composite GPS reference direction tags to be derived from only the + XMP-exif GPS coordinate tags (and not other XMP GPS coordinates) + - Reverted a PNG Validation check that was removed from 11.60 + - Patched to avoid problems overriding new values when writing thumbnail and + preview images + +July 30, 2019 - Version 11.60 + + - Added a few new Sigma LensType values (thanks LibRaw) + - Updated Sony makernote decoding for the DSC-RX100M7 (thanks Jos Roost) + - Various internal improvements to PNG reader/writer + - Fixed bug in RIFF decoder that could cause an "undefined subroutine" error + (thanks Hayo Baan) + - Fixed problem writing some QuickTime tags if the PREFERRED levels were + changed via the config file + - Install Changes: + - Properly erase all temporary files after validation tests + +July 25, 2019 - Version 11.59 + + - Added a new SonyModelID (thanks LibRaw) + - Changed block delete to allow subsequent writing of tags from the same group + (like a group delete) + - Minor changes to warnings and verbose output when writing PNG images + - Fixed potential runtime warning on an error rewriting XMP in a PNG image + +July 25, 2019 - Version 11.58 + + - Added a number of new Canon and Sony LensType values (thanks LibRaw) + - Decode NikonMeteringMode for the D500 + - Decode LensID for Nikon Z lenses + - Extract RawThermalImage from Parrot Bebop-Pro Thermal images + - Validate PNG CRC values when writing or using the Validate option + - Improved Russian translation (thanks Andrei Korzhyts) + - Improved identification of some Tamron lenses for Canon cameras + - Changed name of D810MeteringMode tag to NikonMeteringMode + - Patched writing of XMP in PNG images to always come before IDAT, and warn if + XMP comes after IDAT when reading + - Fixed problem replacing multiple lang-alt default-language structure + elements in lists of XMP structures (behaviour for other languages still not + ideal) + - API Changes: + - Removed PNGEarlyXMP option + - Fixed problem introduced in 11.54 which caused Options('UserParam') to + return undef + - Internal Changes: + - A block delete of EXIF, XMP, IPTC, etc now sets the group delete flag + +July 19, 2019 - Version 11.57 + + - Improved decoding of some tags for the Sony ILCE-7RM4 (thanks Jos Roost) + - Minor change to a Sony lens name + - Fixed format of a number of 8-bit integer QuickTime tags when writing + - Fixed problem replacing multiple structure elements in lists of XMP + structures + +July 18, 2019 - Version 11.56 + + - Added support for the Sony ILCE-7RM4 (thanks Jos Roost) + - Added a new SonyModelID (thanks LibRaw) + - Added a few new Sony/Minolta LensType values (thanks LibRaw and Jos Roost) + - Decode some new Nikon and Motorola tags (thanks Neal Krawetz) + - Decode a couple more ColorData tags for some Canon models + - Extract PreviewImage from DNG files which don't have a .DNG extension + - Extract Huawei APP7 maker notes with the Unknown (-u) option + - Internal change in LensID logic for Sony E-type lenses + +July 12, 2019 - Version 11.55 + + - Added write support for XMP-crs:Texture and XMP-drs tags + - Added a number of new Panasonic NoiseReduction values + - Added definition for a new Kodak tag (thanks LibRaw) + - Added a couple of new Panasonic AFAreaMode values (thanks Daniel Beichl) + - Added a couple of new Sony/Minolta LensTypes (thanks Jos Roost and LibRaw) + - Added a new CanonModelID + - Decode HEVCConfiguration record from HEIC images + - Decode a new Panasonic tag + - Decode a new QuickTime tag + - Changed internal handling of Composite tag ID's to include module name + - Removed "FE" designation from Samyang E-mount lenses + - Dropped Validate warning about missing GPSProcessingMethod tag + +July 2, 2019 - Version 11.54 + + - Added new Canon and Sony/Minolta LensType values (thanks LibRaw) + - Added a number of new Sony/Minolta LensType values (thanks Jos Roost) + - Added "Unknown" value for new EXIF CompositeImage tag + - Added ability to write GSpherical tags in video track of MOV/MP4 files + - Added support for geotagging from GPS/IMU CSV-format files + - Improved Russian translation (thanks Alexander) + - Improved Validate feature to check ExifVersion/GPSVersionID numbers + - Accept unsigned numbers when setting GPSAltitudeRef from a numerical value + - Fixed decoding of DepthMapWidth/Height for some Samsung live-focus images + - Fixed a couple of incorrect/incomplete CanonModelID values (thanks LibRaw) + - Fixed problem identifying some Canon lenses when used on a Sony camera with + a Metabones adapter + - API Changes: + - Added FilterW option + - Enhanced Compact option to improve flexibility and include features of + XMPShorthand option + - Removed XMPShorthand option from documentation + +June 24, 2019 - Version 11.53 - "Exif 2.32" + + - Added support for the new tags of the Exif 2.32 specification + - Added a new SamsungModelID (thanks LibRaw) + - Added warning if extracting ZIP file contents without the -a option + - Added ability to extract EmbeddedVideo from the trailer of Android JPEG + images with the ExtractEmbedded option + - Decode timed GPS from Cobra Dash Cam AVI videos + - Decode a new GoPro tag + - Enhanced -struct option to allow extraction of structured Torrent Info + - Improved error handling when an unexpected terminator is encountered while + writing a QuickTime-format file + - Renamed one of the Nikon Saturation tags to "SaturationAdj" + - Removed warning message when writing FujiFilm RAFVersion 0240 and 0261 files + - Fixed encoding problem when writing some QuickTime UserData tags with + strings containing special characters + - API Changes: + - Enhanced XMPShorthand option to add level 2 + +June 17, 2019 - Version 11.52 + + - Added a few new Nikon CropHiSpeed values (thanks Hayo Baan) + - Added a new Nikon LensID (thanks Yves) + - Fixed problem where reading a large, corrupt AIFF file may could take an + excessively long time + - API Changes: + - Enhanced Compact option to add levels 3, 4 and 5 (github issue #16) + +June 13, 2019 - Version 11.51 + + - Decode Canon DistortionCorrection tags + - Removed a minor EXIF warning when processing EPS files with a DOS header + - Fixed bug which caused an error when rewriting some EPS files multiple times + +June 11, 2019 - Version 11.50 (production release) + + - Added a new Canon LensType and two new Sony LensTypes (thanks LibRaw) + - Added tiff_version and rotate_regions config files to the distribution + - Added two new QuickTime Keys tags and made some existing Keys unwritable + - Improved Composite LensID logic to make better use of EXIF LensModel + - Improved logic when writing BinaryData tags to allow multiple interdependent + tags to be written in a single command + - Improved -htmldump output to show names of Unknown tags + - Allow advanced formatting expressions to access the current tag key ($tag) + - Remove escaped nulls from -json string values + - Reverted change in ExifTool 11.38 so that Composite GPS reference directions + are generated again even if the EXIF versions of these tags already exist + - Fixed an incorrect FlashPix CodePage conversion + +June 5, 2019 - Version 11.49 + + - Added inverse print conversion for one of the QuickTime ItemList Genre tags + - Avoid creating a few obscure QuickTime UserData tags when writing + - Fixed problem where some QuickTime groups were not being created when + writing QuickTime tags without specifying a group + - Fixed problem where QuickTime Keys tags could be duplicated when writing an + existing alternate-language tag + - Fixed problem were QuickTime Keys alternate-language tags would not be + written when deleting the corresponding default-language tag in the same + command + - Fixed some inconsistencies when writing QuickTime tags using the -wm + (WriteMode) option + - Fixed an incorrect Pentax Sigma LensType value + +June 1, 2019 - Version 11.48 + + - Added write support for Google GCamera and GCreation XMP tags + - Renamed XMP-GDepth "Data" tag to "DepthImage" + - Fixed bug where some QuickTime UserData tags could be duplicated when + writing + +May 31, 2019 - Version 11.47 + + - Fixed problem which resulted in a warning for one of the CanonVRD tests on + some platforms + +May 31, 2019 - Version 11.46 - "CR3 update" + + - Added ability to write CanonVRD tags in CR3 images + - Decode a couple more tags from Canon CR3 images + - Enhanced Validate option to check for duplicate QuickTime atoms + - Relaxed constraints when writing IPTC date tags to allow use of separators + other than a colon + - Fixed CR3 writing to update CTBO table with any changed offsets or sizes + (although this table doesn't seem to be used by any RAW viewer, it may be + used in-camera to improve response time when browsing images) + +May 29, 2019 - Version 11.45 + + - CORRUPTION WARNING: Patched problem where Canon DPP would destroy a CR3 + image if the file had previously been edited by DPP then Exiftool + (If you have edited any CR3 images with ExifTool that had been previously + edited by DPP, then re-edit with ExifTool 11.45 or later to restructure the + file so DPP doesn't destroy it if used later to edit the file again) + - Added ability to create and delete QuickTime Keys tags + - Added sample config file (mini0806.config) to generate GPS tags from + subtitle Text in Mini 0806 dashcam videos + - Added new Canon and Nikon lenses (thanks LibRaw) + - Added a new Olympus CameraType (thanks LibRaw) + - Decode CanonVRD tags from CR3 images + - Improved handling of QuickTime language tags when writing + - Fixed bug introduced in 11.38 which could cause "Use of uninitialized value" + runtime warning when reading XMP GPS tags + - Fixed bug where QuickTime tags could be written when another group was + specified + - API Changes: + - Added QuickTimeHandler option + +May 21, 2019 - Version 11.44 + + - Added ability to extract XMP as a block from XMP files + - Prevent ExifIFD from being deleted from any RAW file type + - Fixed problem where some Canon tags couldn't be written in CR3 files + - Fixed problem reading QuickTime Keys tags with a space in the tag ID + - Fixed incorrect family 1 group when reading some QuickTime Keys tags + +May 17, 2019 - Version 11.43 - "Write HEIC and CR3" + + - Added ability to write/create EXIF and write ICC_Profile in HEIC images + - Added ability to write/create EXIF and write MakerNotes in CR3 images + (one might hope/expect EXIF to be stored in the same location for HEIC and + CR3 since they are both based on the QuickTime file format, but in fact they + couldn't be more different, and both are much more complicated than + necessary, which of course follows the seemingly established practice of + intentional obfuscation and zero standardization in video metadata) + - Added support for QuickTime ItemList:Author and Keys:DisplayName tags + - Prevent MakerNotes from being deleted from any RAW file type + - Fixed writing of XMP in HEIC files to conform with the HEIC specification + (obviously, Apple couldn't put this XMP in the same place as any other + QuickTime-based file format, because Apple is, after all, king of "Let's + reinvent the wheel!") + - Fixed problem where API WriteMode option wouldn't always prevent groups from + being created when group creation was disabled + +May 13, 2019 - Version 11.42 + + - Added ability to edit ThumbnailImage in Canon MOV videos + - Improved verbose hex dump for HEIC files + - Fixed another "Chunk offset outside movie data" error when writing some HEIC + files + +May 9, 2019 - Version 11.41 + + - Added write support and improved language handling for 3GP QuickTime tags + - Fixed format problems writing some binary values to QuickTime tags + - Fixed some language translations (thanks Herbert Kauer) + +May 7, 2019 - Version 11.40 + + - Added a new Canon LensType + - Added a new value for EXIF:SceneCaptureType used by some Samsung cameras + - Fixed QuickTime writing to preserve existing same-named default-language + tags in other groups when writing a default language tag + +May 3, 2019 - Version 11.39 - "Create QuickTime tags" + + - Added ability to create new QuickTime tags in MOV/MP4 videos + - Added two new Canon LensTypes and a new CanonModelID (thanks LibRaw) + - Added a few new Sony/Minolta LensType values (thanks Jos Roost) + - Added a number of new QuickTime GenreID values + - Added range check on date/time values when writing + - Decode Canon EOS D60 black levels + - Split off some QuickTime tags into different family 1 groups + - Fixed "Chunk offset outside movie data" error when writing some HEIC files + - Fixed decoding of Pentax AutoBracketing for K-1 and K-5 (github issue #15) + - Fixed some QuickTime family 2 group names + - Fixed bug introduced in 11.38 that broke extraction of thumbnail images from + Canon MOV videos + +Apr. 24, 2019 - Version 11.38 + + - Added Extra JPEGImageLength tag + - Added nksc.config to the sample config files + - Added a couple more Sony/Minolta LensTypes (thanks Jos Roost) + - Added a couple of new Sigma LensType values + - Decode a couple more tags from Pittasoft dashcam videos + - Decode two new FLIR tags (thanks Corinne Berthier) + - Decode a new ERF tag, and fix wrong format for some others (thanks LibRaw) + - Improved decoding of Sigma maker notes for some models + - Enhanced Composite tag logic to allow a scalar Inhibit entry + - Enhanced XMP processing to support readable subdirectories embedded in a tag + - Updated some language translations + - Patched Composite GPS reference direction tags to prevent them from being + created if these tags already exist + - Fixed problem reading some odd PDF files + +Apr. 17, 2019 - Version 11.37 + + - Added a new Sony AFAreaMode (thanks Jos Roost) + - Decode GPS and other tags from Pittasoft Blackvue dashcam videos + - Improved decoding of FujiFilm FlickerReduction + - Ignore any garbage before an NMEA sentence when geotagging + - Fixed bug which could result in loss of timed GPS metadata when writing MP4 + videos + +Apr. 15, 2019 - Version 11.36 + + - Added a number of new MacOS tags + - Added a new CanonModelID (thanks Laurent Clevy) + - Added some new Canon EasyMode and AFAreaMode values + - Added two new Canon AspectRatio values (thanks LibRaw) + - Decode a new Nikon tag (thanks LibRaw) + - Decode some new FujiFilm tags + - Updated Sony maker notes for the DSC-RX0M2 (thanks Jos Roost) + - Hide the Nikon ShotInfo offset tags + - Fixed problem decoding NikonCustom settings for some D810 firmware versions + - Fixed typo in a warning message (thanks Hayo Baan) + +Apr. 9, 2019 - Version 11.35 + + - Added print conversion for MDItemFSLabel + - Added a new Sony LensType (thanks Jos Roost) + - Added an additional -validate check for PNG images + - Decode a few more FujiFilm RAF tags (thanks LibRaw) + - Decode a couple more QuickTime tags + - Allow "Copy0" to be specified as a group name for the copy number of the + primary tag when extracting information + - Improved the Composite ImageSize tag to report the RawImageCroppedSize for + FujiFilm RAF images + - Changed Composite ImageSize tag to use a space instead of "x" as a separator + when the -n option is used + - Fixed problem writing user-defined PhaseOne SensorCalibration tags + - Fixed problem where a List-type tag may not be split into individual items + with the -sep option when using the advanced-formatting "@" feature + - API Changes: + - Patched a potential pitfall if calling code used both the old List and + ListSep options at the same time as the new ListJoin option + +Apr. 4, 2019 - Version 11.34 + + - Added a couple of new Canon LensType values (thanks LibRaw for one) + - Added a new CanonExposureMode value (thanks Arnold van Oostrum) + - Added support for FujiFilm X-H1 Ver2.01 RAF images + - Decode a couple of new Sony tags (thanks LibRaw) + - Improved decoding of Sony Shutter tag (thanks Jos Roost) + - Improved identification of some Sony lenses (thanks Jos Roost) + - Improved parsing of streamed metadata from TomTom Bandit videos + - Improved warning for truncated QuickTime atom + - Accept wider range of formats when writing QuickTime:GPSCoordinates + - API Changes: + - Changed SetFileName() 'Link' option name to 'HardLink' (but still allow + 'Link' for backward compatibility) + +Mar. 28, 2019 - Version 11.33 + + - Added write support for HEIC/HEIF files + - Added new write-only SymLink tag for creating symbolic links + - Made EXIF GDALMetadata and GDALNoData writable + - Enhanced writing capabilities for MOV/MP4 videos + - Enhanced -validate option to add more IPTC checks + - Updated decoding of Sony ILCE-9 maker notes for firmware version 5.00 + (thanks Jos Roost) + - Fixed problem reading streamed metadata from some TomTom Bandit videos + - API Changes: + - Added SymLink option to SetFileName() + +Mar. 14, 2019 - Version 11.32 + + - Added a new Nikon LensID (thanks Kenneth Cochran) + - Added a couple of new QuickTime HandlerType values + - Decode streamed metadata from DuDuBell M1 and VSYS M6L dashcam videos + - Attempt to improve Nikon lens identification + - API Changes: + - Added new single-argument version of ShiftTime() + +Mar. 7, 2019 - Version 11.31 + + - Added read support for FITS images + - Another try at removing spaces from some DICOM values (github issues #10/12) + +Mar. 6, 2019 - Version 11.30 (production release) + + - Added a new Sony/Minolta LensType (thanks Jos Roost) + - Decode streaming metadata from TomTom Bandit Action Cam MP4 videos + - Decode Reconyx HF2 PRO maker notes + - Decode ColorData for some new Canon models (thanks LibRaw) + - Enhanced -geotag feature to set AmbientTemperature if available + - Remove non-significant spaces from some DICOM values (github issues #10/12) + - Fixed possible "'x' outside of string" error when reading corrupted EXIF + - Fixed incorrect write group for GeoTIFF tags added in version 11.24 + +Feb. 28, 2019 - Version 11.29 + + - Added support for Ricoh GR III maker notes + - Added a new Canon LensType (thanks Claude Jolicoeur) + - Added a new XMP-crs tag (github issue #8) + - Enhanced -csv option to output base64-encoded binary data when combined with + -b or when the -charset option is used and the text has invalid characters + (github issue #11) + - Remove trailing space from even-length DICOM values (github issue #9) + - Patched to avoid "Hexadecimal number > 0xffffffff non-portable" warning + (github issue #6) + - Fixed meta charset attribute in -htmlDump output + +Feb. 21, 2019 - Version 11.28 + + - Added support for reading INSV video and decode streaming GPS + - Added a new Pentax LensType (thanks Louis Granboulan) + - Added a new FujiFilm ImageStabilization value + - Allow exiftool to be run via a symbolic link on Mac/Linux + - Reverted INDD patch of version 11.27 (ie. raise error again on incorrectly + terminated INDD object list) + - Changed handling of temporary documentation file in Windows version + +Feb. 14, 2019 - Version 11.27 + + - Added support for more XMP-dji-drone tags + - Added new Olympus CameraType and LensType values (thanks LibRaw) + - Added a new Canon LensType (thanks LibRaw) + - Added a new CanonModelID + - Decode yet another type of GPS from DashCam videos + - Allow FileName to be written when only case is changed on case-insensitive + filesystems + - Improved identification of some iWork file types + - Recognize the LRV file extension + - Changed Windows version to use the parent folder of PAR_GLOBAL_TEMP for the + temporary documentation file + - Don't raise an error if an INDD object list is terminated by spaces instead + of nulls + - Fixed some problems with new -htmldump IFD highlighting feature + - Fixed bug introduced in 11.24 with "-o -.EXT" feature + +Jan. 21, 2019 - Version 11.26 + + - Added a new Nikon LensID (thanks LibRaw) + - Decode more tags for the Sony ICLE-6400 (thanks Jos Roost and LibRaw) + - Enhanced -htmldump feature to highlight IFD when mousing over IFD offset + +Jan. 15, 2019 - Version 11.25 + + - Added a new Sony/Minolta LensType (thanks LibRaw) + - Added a new Nikon LensID + - Decode Leica D-Lux7 maker notes + - Decode more Nikon AF tags for newer models + - Decode Samsung Type2 maker notes with lower case Make + - Decode another Sony tag (thanks Jos Roost) + - Improved decoding of Nikon LensType + - Improved time shift feature to fix some incorrectly formatted date/time + values + - Renamed some Sony ImageCount tags to ShutterCount (thanks Jos Roost) + - Fixed problem reading back metadata written to some odd PDF files + +Jan. 8, 2019 - Version 11.24 + + - Compatibility Notice: Changed the meaning of '-' and '+' modifiers for %C + formatting code (does not affect lower-case %c code) + - Decode a number of new Nikon tags (thanks Michael Tapes for samples) + - Added new Olympus FlashType and FlashModel values (thanks Per) + - Added a new Canon LensType + - Added a new Nikon LensID + - Made more GeoTIFF tags writable + - Handle XMP rdf:value when reading + - Improved warning when trying to read a file with a zero-length name + - Fixed decoding of PictureControl tags for Nikon Z-7 + - Fixed problem writing date/time values with " DST" designator at end of + date/time string + - Fixed problem in Windows which could cause ExifTool to abort due to a + Win32::FindFile error if a file name contained surrogate Unicode characters + +Dec. 21, 2018 - Version 11.23 + + - Recognize DWG and DWF files + - Minor improvement to some -validate warnings + - Tolerate leading UTF-8 byte order mark (BOM) at start of JSON files + - Fixed problem recognizing some streaming camm metadata in QuickTime videos + +Dec. 13, 2018 - Version 11.22 + + - Added read support for PC Paintbrush (PCX) files + - Added two new Sony/Minolta LensTypes (thanks Jos Roost and LibRaw) + - Decode LensData tags for some newer Nikon models + - Decode ColorData for the Canon EOS R (thanks LibRaw) + - Recognize DCX files + +Dec. 7, 2018 - Version 11.21 + + - Added a new Sony/Minolta LensType (thanks Jos Roost) + - Added a new Olympus FlashModel (thanks Michael Meissner) + - Improved decoding of FujiFilm InternalSerialNumber (thanks LibRaw) + - Minor improvements to decoding of GPS from some dashcam videos + - Made XMP-getty:Personality a List-type tag + - Made it an error to use the -o option or write FileName or Directory tags + when using the TestName dry-run feature + - Fixed problem using -E with other character sets when writing + +Nov. 20, 2018 - Version 11.20 + + - Added a new Panasonic WhiteBalance value + - Added a new Nikon LensID (thanks LibRaw) + - Decode streaming GPS from MOV videos for another dashcam model + - Improved -E option to support character sets other than UTF-8 + +Nov. 14, 2018 - Version 11.19 + + - Added -fast4 option + - Enhanced -if option to allow arbitrary Perl expressions instead of just + logic expressions + - API Changes: + - Enhanced FastScan option to add a setting of 4 + +Nov. 12, 2018 - Version 11.18 + + - Decode a new Nikon tag (thanks Richard Butler) + - Decode a new FujiFilm tag + - Updated decoding of Sony maker notes for newer models (thanks Jos Roost) + - Enhanced -if option to allow fast processing pass to evaluate the condition + - Improved warning for unknown JPEG APP segment + +Nov. 4, 2018 - Version 11.17 + + - Added a new Canon LensType (thanks Norbert Wasser) + - Added a new Sony/Minolta LensType and a new SonyModelID (thanks LibRaw) + - Decode GPS from Garmin Dashcam videos + - Changed type of J2C files from a JPEG 2000 image to a JPEG 2000 codestream Oct. 26, 2018 - Version 11.16 @@ -52,8 +1728,8 @@ Oct. 9, 2018 - Version 11.13 - Added a new Canon LensType (thanks LibRaw) - Minor improvements to verbose dump of streaming GPS metadata - Reverted change of version 10.71 which resulted in Windows not recognizing - PNG CreationTime as written by ExifTool (added this feature to the - StrictDate API option instead) + PNG CreationTime as written by ExifTool (added this feature to the API + StrictDate option instead) - Improved decoding of Nikon CropHiSpeed (thanks LibRaw) - Improved -fast option to reduce memory usage when reading JPG, PNG, QuickTime-based and RIFF-based files via a sequential stream @@ -167,7 +1843,7 @@ June 21, 2018 - Version 11.03 June 13, 2018 - Version 11.02 - Added support for a different format of Apple iWorks files - - Added undocumented FixCorruptedMOV API option to allow fixing MOV videos + - Added undocumented API FixCorruptedMOV option to allow fixing MOV videos with multiple 'mdat' atoms which were corrupted by ExifTool - Decode more QuickTime tags - Decode more PanasonicRaw tags (thanks Klaus Homeister) @@ -392,7 +2068,7 @@ Feb. 22, 2018 - Version 10.80 (production release) Feb. 11, 2018 - Version 10.79 - Added a new Olympus CameraType (thanks LibRaw) - - Added a new XMP-microsoft tag (thanks José Oliver-Didier) + - Added a new XMP-microsoft tag (thanks Jose Oliver-Didier) - Decode a new GoPro QuickTime tag - Convert nulls IPTC:DocumentHistory to newlines - Removed all null terminators from JSON and PHP output @@ -741,7 +2417,7 @@ Apr. 10, 2017 - Version 10.49 - Decode a new Panasonic tag - Fixed problem decoding Sony VariableLowPassFilter values (thanks Jos Roost) - Fixed problem setting XMP:About when creating new XMP in a file - - Fixed an incorect Pentax DriveMode value (thanks Andras Salamon) + - Fixed an incorrect Pentax DriveMode value (thanks Andras Salamon) - API Changes - Allow access to the advanced formatting expression via a new ExifTool "FMT_EXPR" member variable @@ -983,16 +2659,16 @@ Oct. 5, 2016 - Version 10.29 (ie. the date/time is not converted) unless the API StrictDate option is set in which case a warning is issued and the tag is not written -Sept. 27, 2016 - Version 10.28 - "EXIF 2.31" +Sept. 27, 2016 - Version 10.28 - "Exif 2.31" - - Added support for new EXIF 2.31 tags + - Added support for new Exif 2.31 tags - Added some new Canon LensType values (thanks Norbert Wasser for one) - Added a new Olympus LensType (thanks LibRaw and Niels Kristian Bech Jensen) - Added a new Sony LensType and SonyModelID (thanks Jos Roost) - Added a new Pentax LensType - Added fotoware.config and bibble.config files to the distribution - Made Composite SubSecDateTimeOriginal, SubSecCreateDate and SubSecModifyDate - tags writable, and expanded to include new EXIF 2.31 time zone tags + tags writable, and expanded to include new Exif 2.31 time zone tags - Fixed problem writing user-defined structured tag elements with a dot (.) in their tag ID @@ -1260,7 +2936,7 @@ Jan. 4, 2016 - Version 10.09 - Added ability to extract OS X system metadata ("MDItem" tags) - Added a value conversion for GoogleTrackDuration - - Enchanced the -i option to allow full path names to be specified + - Enhanced the -i option to allow full path names to be specified - Fixed a potential runtime error when writing corrupted JPEG images - API Changes: - Added MDItemTags option @@ -2579,7 +4255,7 @@ Jan. 18, 2013 - Version 9.14 - Decode new Canon 6D CustomFunctions - Improved calculation of ScaleFactor35efl for Canon cameras - Changed priority of PDF Info tags so tags from most recent Info dictionary - take precedence (to partially accomodate the questionable Acrobat Pro + take precedence (to partially accommodate the questionable Acrobat Pro incremental update technique) - Changed some verbose warnings when attempting to write "unsafe" tags - Changed behaviour so that "unsafe" tags are not copied for any tag specified @@ -2925,7 +4601,7 @@ Apr. 3, 2012 - Version 8.86 - Decode some new CanonVRD DLO tags - Changed decoding of CanonVRD VRDVersion tag - Changed formatting of a Pentax LensType for consistency with other lenses - - Patched decoding of Reconyx:DateTimeOriginal to accomodate values written + - Patched decoding of Reconyx:DateTimeOriginal to accommodate values written with an incorrect byte order by some models Mar. 25, 2012 - Version 8.85 (production release) @@ -3493,7 +5169,7 @@ Jan. 29, 2011 - Version 8.47 Jan. 22, 2011 - Version 8.46 - - Simpified definition of user-defined XMP structures: flattened tags are now + - Simplified definition of user-defined XMP structures: flattened tags are now automatically generated, and UserDefined::xmpStruct is no longer needed (but backward compatibility is maintained with the old-style definitions) - Added ability to handle multi-dimensional arrays in structured output @@ -3873,7 +5549,7 @@ June 2, 2010 - Version 8.21 - Updated default GPSVersionID to 2.3.0.0 when writing - Fixed bug geotagging from KML file (lat/long were swapped) -May 26, 2010 - Version 8.20 +May 26, 2010 - Version 8.20 - "Exif 2.3" - Added read support for Open Document files (ODP, ODS, ODT) - Added Composite:AudioBitrate tag for VBR MPEG audio @@ -4516,7 +6192,7 @@ June 7, 2009 - Version 7.77 - Decode large preview in APP2 of images from newer Samsung models - Extract FujiFilm PreviewImage from improperly written FPXR segment - Improved decoding of Nikon WB levels for some models - - Reduced memory useage when writing DNG and some other RAW image files + - Reduced memory usage when writing DNG and some other RAW image files - Changed format of Canon D30 SerialNumber to remove the hyphen and add leading 0's if less than 9 characters (now same format as printed on camera) - Changed writing of GPSTimeStamp and GPSDateStamp to adjust date/time to UTC @@ -5179,7 +6855,7 @@ May 28, 2008 - Version 7.29 - Renamed Pentax ModelRevision tag to ProductionCode and improved print conversion to indicate if camera has been serviced - Added check to prevent EXIF tags from being written to JPEG images if they - would obviously exceed the maximimum JPEG segment size limit + would obviously exceed the maximum JPEG segment size limit - Relaxed error checks when writing JPEG images to allow MakerNotes to be rebuilt if the MakerNote IFD is not contained within the MakerNotes data - Fixed decoding of Pentax ExternalFlashGuideNumber when AF360 is used with @@ -5925,7 +7601,7 @@ Feb. 20, 2007 - Version 6.77 - "XML/HTML special characters" - Translate all non-ASCII characters to HTML character entities with -h or -E - Added full UTF-8 translation support when run with Perl pre-5.6.1 - Decode a few new Sigma SD14 tags - - Decode a couple more Nikon tags + - Decode a couple more Nikon tags (thanks Greg Troxel) Feb. 16, 2007 - Version 6.76 (production release) @@ -6313,7 +7989,7 @@ Sept. 21, 2006 - Version 6.42 (production release) Sept. 18, 2006 - Version 6.41 - Fixed calculation of Canon ISO in some images and renamed ShotISO to BaseISO - - Minor improvment to order of operations when deleting multiple groups and + - Minor improvement to order of operations when deleting multiple groups and adding back information in batch mode Sept. 14, 2006 - Version 6.40 @@ -6438,7 +8114,7 @@ June 19, 2006 - Version 6.25 - Added read/write support for WDP (Windows Media Photo) images - Improved algorithm to recognize maker notes offsets which need fixing - Properly handle maker notes which have value offsets relative to the - individial IFD entries (Kyocera, Rollei and some Konica and Toshiba models) + individual IFD entries (Kyocera, Rollei and some Konica and Toshiba models) - Decode a couple of new Sigma lens values in Canon LensType - Decreased block size for buffered files to improve performance over slow pipes @@ -6479,7 +8155,8 @@ May 24, 2006 - Version 6.20 - Fixed bug where IgnoreMinorErrors option could get set when writing images with NikonCapture information - Fixed two ID3 tag names which contained spaces - - Fixed problem parsing DateTimeOriginal in Casio EX-Z30 AVI files + - Fixed problem parsing DateTimeOriginal in Casio EX-Z30 AVI files (thanks + Joachim Loehr) - Fixed problem with apostrophes in HTML documentation for some browsers - API Changes: - Can now call Options() with undefined value to set option value to undef @@ -6695,7 +8372,7 @@ Feb. 1, 2006 - Version 5.99 - Added Canon maker note footer when rewriting Canon maker notes - Attempt to fix problem where ScaleFactor35efl was calculated incorrectly for some Canon images - - Reduce memory useage and speed up writing of large TIFF images + - Reduce memory usage and speed up writing of large TIFF images - Fixed problem with binary data offsets in verbose dump - Fixed problem writing Comment if 'File' group specified - Fixed bug which could cause formatting error in htmlDump output @@ -6921,7 +8598,7 @@ Oct. 24, 2005 - Version 5.71 Oct. 23, 2005 - Version 5.70 - - Significant internal changes to improve speed and reduce memory useage + - Significant internal changes to improve speed and reduce memory usage - Fixed a bug introduced in version 5.63 which caused incorrect XMP GPS coordinates to be returned - Changed handling of Kodak date records @@ -6975,7 +8652,7 @@ Oct. 7, 2005 - Version 5.65 - Decode a few more Photoshop tags - Issue an error if there is extra data after the normal end of file when rewriting TIFF images (avoids possible data loss if attempting to write an - unsuported RAW image with a TIFF-like data structure) + unsupported RAW image with a TIFF-like data structure) - Added ability to replace existing tags with user defined tags - Denote minor errors/warnings by adding '[minor]' to the message (these are the errors which can be ignored with the -m option) @@ -7451,7 +9128,7 @@ Apr. 2, 2005 - Version 4.93 (production release) Mar. 31, 2005 - Version 4.92 - Added support for Kodak and Ricoh cameras - - Decode still more Olympus E-1/E-300 tags + - Decode still more Olympus E-1/E-300 tags (thanks Markku Hanninen) - Added 'Directory' tag - Decode a few more Pentax tags (thanks to John Francis) - Allow newlines in tag values on command line when writing @@ -7459,13 +9136,13 @@ Mar. 31, 2005 - Version 4.92 Mar. 28, 2005 - Version 4.91 - - Decode yet more Olympus E-1/E-300 tags + - Decode yet more Olympus E-1/E-300 tags (thanks Markku Hanninen) - Changed decoding of Olympus E-300 Quality tag - Patched bug in Olympus maker notes that was causing ExifTool to report an error when reading ORF files - Fixed problem where strings weren't being properly truncated at the null terminator if there was a newline after the terminator - - Improved decoding for some Nikon tags (credit Tom Christiansen) + - Improved decoding for some Nikon tags (thanks Tom Christiansen) - Added Nikon shortcut - Added composite SubSecDateTimeOriginal tag - Fixed problem where CRW file without file extension wasn't being identified @@ -7682,7 +9359,7 @@ Jan. 28, 2005 - Version 4.42 specific IPTC tag values with 'TAG-=VALUE' - Made EXIF SceneType writable - Renamed Nikon ISOUsed tag to ISO - - Added documention of Canon RAW (CRW) file format + - Added documentation of Canon RAW (CRW) file format Jan. 27, 2005 - Version 4.41 @@ -7873,7 +9550,7 @@ Jan. 7, 2005 - Version 4.10 Dec. 15, 2004 - Version 4.05 - - Added a couple of Nikon tags + - Added a couple of Nikon tags (thanks Brian Ristuccia) - Now preserves original file by renaming to "NAME_original" when writing information - Don't preserve file time by default when writing. Added -P option to do @@ -7891,7 +9568,7 @@ Dec. 6, 2004 - Version 4.03 - Major overhaul of verbose message output - Change -v option to allow verbose level to be specified (eg. -v3 = very very verbose) - - Added a new Nikon tag (SceneMode) + - Added a new Nikon tag (thanks Thomas Walter) - Count images which were unchanged when writing tags - Changed FileType 'JPG' to 'JPEG' @@ -8121,7 +9798,7 @@ Apr. 6, 2004 - Version 3.37 Apr. 6, 2004 - Version 3.36 - Added support for Sanyo and Minolta maker notes - - Added skeleton for interpeting Sony maker notes + - Added skeleton for interpreting Sony maker notes - Interpret Pentax PrintIM Apr. 6, 2004 - Version 3.35 @@ -8165,7 +9842,7 @@ Mar. 26, 2004 - Version 3.27 - Optimized a few routines to speed things up a bit - API Changes: - - Changed GetDescription() documention to indicate it is called with an + - Changed GetDescription() documentation to indicate it is called with an ExifTool object (this is still optional, but will be mandatory with the next version) @@ -8292,7 +9969,7 @@ Feb. 17, 2004 - Version 3.03 - Fixed RandomAccessFile package name (should have been File::RandomAccessFile) - - Added IxusAFPoint tag to Canon maker notes + - Added IxusAFPoint tag to Canon maker notes (thanks Michael Rommel) - Avoid scanning past end of Canon binary data blocks - API Changes: - GetFoundTags() and GetRequestedTags() now return list instead of list @@ -8349,7 +10026,7 @@ Feb. 11, 2004 - Version 2.70 Feb. 10, 2004 - Version 2.62 - Added -u option to allow display of unknown tags - - Major changes to Pentax maker notes (still needs work) + - Major changes to Pentax maker notes (still needs work) (thanks Wayne Smith) Feb. 09, 2004 - Version 2.61 @@ -8379,7 +10056,7 @@ Jan. 30, 2004 - Version 2.51 Jan. 29, 2004 - Version 2.50 - Changed API to return binary data as SCALAR reference and - list of values as ARRAY reference + list of values as ARRAY reference (thanks Dan Heller for the suggestions) - Attempt to make case of tag descriptions more consistent Jan. 28, 2004 - Version 2.41 @@ -8428,7 +10105,8 @@ Jan. 6, 2004 - Version 2.25 - Fixed problem with ImageInfo() function prototype - Fixed printout of JpgFromRaw message (doesn't affect JPG extraction) - - Set output files to binmode (including STDOUT) if -b option used + - Set output files to binmode (including STDOUT) if -b option used (thanks + David Anson) Jan. 1, 2004 - Version 2.24 @@ -8506,7 +10184,7 @@ Nov. 26, 2003 - Version 1.40 Nov. 25, 2003 - Version 1.30 - - Added experimental Canon RAW (CRW) file support + - Added experimental Canon RAW (CRW) file support Nov. 22, 2003 - Version 1.20 diff --git a/src/Image-ExifTool/README b/src/Image-ExifTool/README index 61524fe9..959c0ec2 100644 --- a/src/Image-ExifTool/README +++ b/src/Image-ExifTool/README @@ -1,4 +1,4 @@ -ExifTool by Phil Harvey (phil at owl.phy.queensu.ca) +ExifTool by Phil Harvey (philharvey66 at gmail.com) ---------------------------------------------------------------------------- ExifTool is a customizable set of Perl modules plus a full-featured @@ -14,44 +14,48 @@ supported by ExifTool (r = read, w = write, c = create): File Types ------------+-------------+-------------+-------------+------------ - 3FR r | DR4 r/w/c | J2C r | ODP r | RAW r/w - 3G2 r/w | DSS r | JNG r/w | ODS r | RIFF r - 3GP r/w | DV r | JP2 r/w | ODT r | RSRC r - A r | DVB r/w | JPEG r/w | OFR r | RTF r - AA r | DVR-MS r | JSON r | OGG r | RW2 r/w - AAE r | DYLIB r | K25 r | OGV r | RWL r/w - AAX r/w | EIP r | KDC r | OPUS r | RWZ r - ACR r | EPS r/w | KEY r | ORF r/w | RM r - AFM r | EPUB r | LA r | OTF r | SEQ r - AI r/w | ERF r/w | LFP r | PAC r | SKETCH r - AIFF r | EXE r | LNK r | PAGES r | SO r - APE r | EXIF r/w/c | M2TS r | PBM r/w | SR2 r/w - ARQ r/w | EXR r | M4A/V r/w | PCD r | SRF r - ARW r/w | EXV r/w/c | MAX r | PDB r | SRW r/w - ASF r | F4A/V r/w | MEF r/w | PDF r/w | SVG r - AVI r | FFF r/w | MIE r/w/c | PEF r/w | SWF r - AZW r | FLA r | MIFF r | PFA r | THM r/w - BMP r | FLAC r | MKA r | PFB r | TIFF r/w - BPG r | FLIF r/w | MKS r | PFM r | TORRENT r - BTF r | FLV r | MKV r | PGF r | TTC r - CHM r | FPF r | MNG r/w | PGM r/w | TTF r - COS r | FPX r | MOBI r | PLIST r | VCF r - CR2 r/w | GIF r/w | MODD r | PICT r | VRD r/w/c - CR3 r/w | GPR r/w | MOI r | PMP r | VSD r - CRM r/w | GZ r | MOS r/w | PNG r/w | WAV r - CRW r/w | HDP r/w | MOV r/w | PPM r/w | WDP r/w - CS1 r/w | HDR r | MP3 r | PPT r | WEBP r - DCM r | HEIC r | MP4 r/w | PPTX r | WEBM r - DCP r/w | HEIF r | MPC r | PS r/w | WMA r - DCR r | HTML r | MPG r | PSB r/w | WMV r - DFONT r | ICC r/w/c | MPO r/w | PSD r/w | WTV r - DIVX r | ICS r | MQV r/w | PSP r | WV r - DJVU r | IDML r | MRW r/w | QTIF r/w | X3F r/w - DLL r | IIQ r/w | MXF r | R3D r | XCF r - DNG r/w | IND r/w | NEF r/w | RA r | XLS r - DOC r | INX r | NRW r/w | RAF r/w | XLSX r - DOCX r | ISO r | NUMBERS r | RAM r | XMP r/w/c - DPX r | ITC r | O r | RAR r | ZIP r + 360 r/w | DR4 r/w/c | JNG r/w | O r | RAW r/w + 3FR r | DSS r | JP2 r/w | ODP r | RIFF r + 3G2 r/w | DV r | JPEG r/w | ODS r | RSRC r + 3GP r/w | DVB r/w | JSON r | ODT r | RTF r + A r | DVR-MS r | JXL r | OFR r | RW2 r/w + AA r | DYLIB r | K25 r | OGG r | RWL r/w + AAE r | EIP r | KDC r | OGV r | RWZ r + AAX r/w | EPS r/w | KEY r | ONP r | RM r + ACR r | EPUB r | LA r | OPUS r | SEQ r + AFM r | ERF r/w | LFP r | ORF r/w | SKETCH r + AI r/w | EXE r | LIF r | ORI r/w | SO r + AIFF r | EXIF r/w/c | LNK r | OTF r | SR2 r/w + APE r | EXR r | LRV r/w | PAC r | SRF r + ARQ r/w | EXV r/w/c | M2TS r | PAGES r | SRW r/w + ARW r/w | F4A/V r/w | M4A/V r/w | PBM r/w | SVG r + ASF r | FFF r/w | MACOS r | PCD r | SWF r + AVI r | FITS r | MAX r | PCX r | THM r/w + AVIF r/w | FLA r | MEF r/w | PDB r | TIFF r/w + AZW r | FLAC r | MIE r/w/ | PDF r/w | TORRENT r + BMP r | FLIF r/w | MIFF r c | PEF r/w | TTC r + BPG r | FLV r | MKA r | PFA r | TTF r + BTF r | FPF r | MKS r | PFB r | TXT r + CHM r | FPX r | MKV r | PFM r | VCF r + COS r | GIF r/w | MNG r/w | PGF r | VRD r/w/c + CR2 r/w | GPR r/w | MOBI r | PGM r/w | VSD r + CR3 r/w | GZ r | MODD r | PLIST r | WAV r + CRM r/w | HDP r/w | MOI r | PICT r | WDP r/w + CRW r/w | HDR r | MOS r/w | PMP r | WEBP r + CS1 r/w | HEIC r/w | MOV r/w | PNG r/w | WEBM r + CSV r | HEIF r/w | MP3 r | PPM r/w | WMA r + CZI r | HTML r | MP4 r/w | PPT r | WMV r + DCM r | ICC r/w/c | MPC r | PPTX r | WTV r + DCP r/w | ICS r | MPG r | PS r/w | WV r + DCR r | IDML r | MPO r/w | PSB r/w | X3F r/w + DFONT r | IIQ r/w | MQV r/w | PSD r/w | XCF r + DIVX r | IND r/w | MRC r | PSP r | XLS r + DJVU r | INSP r/w | MRW r/w | QTIF r/w | XLSX r + DLL r | INSV r | MXF r | R3D r | XMP r/w/c + DNG r/w | INX r | NEF r/w | RA r | ZIP r + DOC r | ISO r | NKSC r/w | RAF r/w | + DOCX r | ITC r | NRW r/w | RAM r | + DPX r | J2C r | NUMBERS r | RAR r | Meta Information ----------------------+----------------------+--------------------- @@ -75,7 +79,7 @@ See html/index.html for more details about ExifTool features. ExifTool can be downloaded from - http://owl.phy.queensu.ca/~phil/exiftool/ + https://exiftool.org/ RUNNING @@ -103,8 +107,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-11.16.tar.gz | tar -xf - - cd Image-ExifTool-11.16 + gzip -dc Image-ExifTool-12.45.tar.gz | tar -xf - + cd Image-ExifTool-12.45 ./exiftool t/images/ExifTool.jpg Note: These commands extract meta information from one of the test images. @@ -158,7 +162,7 @@ for calculating digest values and providing other features listed below: COPYRIGHT AND LICENSE -Copyright 2003-2018, Phil Harvey +Copyright 2003-2022, Phil Harvey This is free software; you can redistribute it and/or modify it under the same terms as Perl itself. @@ -187,21 +191,28 @@ distribution package: xmp2iptc.args - Arguments for converting XMP to IPTC xmp2pdf.args - Arguments for converting XMP to PDF config_files/ - Sample ExifTool configuration files: + acdsee.config - Definitions for writing ACDSee XMP regions age.config - Calculate Age of person in photo bibble.config - Definitions for writing Bibble XMP tags - convert_regions.config - Convert between MWG and MP face regions - dji.config - Composite tags for metadata in DJI videos + convert_regions.config - Convert between MWG, MP and IPTC regions + cuepointlist.config - Extract cue points and labels as a list + depthmap.config - Extract Google DepthMap images example.config - General example showing config features fotoware.config - Definitions for writing Fotoware XMP tags gps2utm.config - Generate UTM coordinate tags from GPS info + gpsdatetime.config - Make GPSDateTime from CreateDate+SampleTime + nksc.config - Decode tags in Nikon ViewNX NKSC files photoshop_paths.config - For extracting or copying Photoshop paths picasa_faces.config - Convert from Picasa to MWG/MP face regions - time_zone.config - Calcuate time zone from EXIF tags + rotate_regions.config - Rotate MWG and MP region tags + tiff_version.config - Determine the version of a TIFF file + time_zone.config - Calculate time zone from EXIF tags exiftool - The exiftool application (Perl script) fmt_files/ - Output formatting example files: gpx.fmt - Format file for creating GPX track gpx_wpt.fmt - Format file for creating GPX waypoints - kml.fmt - Format file for creating KML output files + kml.fmt - Format file for creating KML placemarks + kml_track.fmt - Format file for creating KML track html/ - HTML documentation html/TagNames/ - HTML tag name documentation lib/ - ExifTool Perl library modules diff --git a/src/Image-ExifTool/exiftool b/src/Image-ExifTool/exiftool index 3039cc61..c08302f0 100755 --- a/src/Image-ExifTool/exiftool +++ b/src/Image-ExifTool/exiftool @@ -6,21 +6,31 @@ # # Revisions: Nov. 12/03 - P. Harvey Created # (See html/history.html for revision history) -# -# References: ATV - Alexander Vonk, private communication #------------------------------------------------------------------------------ use strict; +use warnings; require 5.004; -my $version = '11.16'; +my $version = '12.45'; # add our 'lib' directory to the include list BEFORE 'use Image::ExifTool' -my $exeDir; BEGIN { + # (undocumented -xpath option added in 11.91, must come before other options) + my $exePath = @ARGV && lc($ARGV[0]) eq '-xpath' && shift() ? $^X : $0; # get exe directory - $exeDir = ($0 =~ /(.*)[\\\/]/) ? $1 : '.'; + my $exeDir = ($exePath =~ /(.*)[\\\/]/) ? $1 : '.'; + my $incDir = ($0 =~ /(.*)[\\\/]/) ? "$1/lib" : './lib'; + if (-l $0) { + my $lnk = eval { readlink $0 }; + if (defined $lnk) { + my $lnkDir = ($lnk =~ /(.*)[\\\/]/) ? $1 : '.'; + $exeDir = (($lnk =~ m(^/)) ? '' : $exeDir . '/') . $lnkDir; + $incDir = "$exeDir/lib"; + } + } + $Image::ExifTool::exeDir = $exeDir; # use our exeDir for loading config file # add lib directory at start of include path - unshift @INC, "$exeDir/lib"; + unshift @INC, $incDir; # load or disable config file if specified if (@ARGV and lc($ARGV[0]) eq '-config') { shift; @@ -35,7 +45,7 @@ sub SigCont(); sub Cleanup(); sub GetImageInfo($$); sub SetImageInfo($$$); -sub DoHardLink($$$$); +sub DoHardLink($$$$$); sub CleanXML($); sub EncodeXML($); sub FormatXML($$$); @@ -60,7 +70,7 @@ sub MyConvertFileName($$); sub SuggestedExtension($$$); sub LoadPrintFormat($); sub FilenameSPrintf($;$@); -sub NextUnusedFilename($;$$); +sub NextUnusedFilename($;$); sub CreateDirectory($); sub OpenOutputFile($;@); sub AcceptFile($); @@ -78,10 +88,12 @@ END { # declare all static file-scope variables my @commonArgs; # arguments common to all commands +my @condition; # conditional processing of files my @csvFiles; # list of files when reading with CSV option (in ExifTool Charset) my @csvTags; # order of tags for first file with CSV option (lower case) my @delFiles; # list of files to delete my @dynamicFiles; # list of -tagsFromFile files with dynamic names and -TAG<=FMT pairs +my @efile; # files for writing list of error/fail/same file names my @exclude; # list of excluded tags my (@echo3, @echo4);# stdout and stderr echo after processing is complete my @files; # list of files and directories to scan @@ -91,11 +103,15 @@ my @requestTags; # tags to request (for -p or -if option arguments) my @srcFmt; # source file name format strings my @tags; # list of tags to extract my %appended; # list of files appended to +my %countLink; # count hard and symbolic links made my %created; # list of files we created my %csvTags; # lookup for all found tags with CSV option (lower case keys) my %database; # lookup for database information based on file name (in ExifTool Charset) my %filterExt; # lookup for filtered extensions my %ignore; # directory names to ignore +my $ignoreHidden; # flag to ignore hidden files +my %outComma; # flag that output text file needs a comma +my %outTrailer; # trailer for output text file my %preserveTime; # preserved timestamps for files my %printFmt; # the contents of the print format file my %setTags; # hash of list references for tags to set from files @@ -105,38 +121,40 @@ my %utf8FileName; # lookup for file names that are UTF-8 encoded my %warnedOnce; # lookup for once-only warnings my %wext; # -W extensions to write my $allGroup; # show group name for all tags +my $altEnc; # alternate character encoding if not UTF-8 my $argFormat; # use exiftool argument-format output my $binaryOutput; # flag for binary output (undef or 1, or 0 for binary XML/PHP) my $binaryStdout; # flag set if we output binary to stdout my $binSep; # separator used for list items in binary output my $binTerm; # terminator used for binary output my $comma; # flag set if we need a comma in JSON output -my $condition; # conditional processing of files my $count; # count of files scanned when reading or deleting originals my $countBad; # count of files with errors my $countBadCr; # count files not created due to errors -my $countBadLink; # count bad links my $countBadWr; # count write errors my $countCopyWr; # count of files copied without being changed my $countDir; # count of directories scanned my $countFailed; # count files that failed condition my $countGoodCr; # count files created OK my $countGoodWr; # count files written OK -my $countLink; # count number of links created my $countNewDir; # count of directories created my $countSameWr; # count files written OK but not changed my $critical; # flag for critical operations (disable CTRL-C) my $csv; # flag for CSV option (set to "CSV", or maybe "JSON" when writing) my $csvAdd; # flag to add CSV information to existing lists +my $csvDelim; # delimiter for CSV files my $csvSaveCount; # save counter for last CSV file loaded my $deleteOrig; # 0=restore original files, 1=delete originals, 2=delete w/o asking my $disableOutput; # flag to disable normal output my $doSetFileName; # flag set if FileName may be written my $doUnzip; # flag to extract info from .gz and .bz2 files +my ($end,$endDir,%endDir); # flags to end processing +my $escapeC; # C-style escape my $escapeHTML; # flag to escape printed values for html my $evalWarning; # warning from eval my $executeID; # -execute ID number my $failCondition; # flag to fail -if condition +my $fastCondition; # flag for fast -if condition my $fileHeader; # header to print to output file (or console, once) my $fileTrailer; # trailer for output file my $filtered; # flag indicating file was filtered by name @@ -146,14 +164,17 @@ my $forcePrint; # string to use for missing tag values (undef to not print t my $helped; # flag to avoid printing help if no tags specified my $html; # flag for html-formatted output (2=html dump) my $interrupted; # flag set if CTRL-C is pressed during a critical process +my $isBinary; # true if value is a SCALAR ref my $isWriting; # flag set if we are writing tags my $joinLists; # flag set to join list values into a single string my $json; # flag for JSON/PHP output format (1=JSON, 2=PHP) my $langOpt; # language option +my $listDir; # treat a directory as a regular file my $listItem; # item number for extracting single item from a list my $listSep; # list item separator (', ' by default) my $mt; # main ExifTool object my $multiFile; # non-zero if we are scanning multiple files +my $noBinary; # flag set to ignore binary tags my $outFormat; # -1=Canon format, 0=same-line, 1=tag names, 2=values only my $outOpt; # output file or directory name my $overwriteOrig; # flag to overwrite original file (1=overwrite, 2=in place) @@ -172,7 +193,9 @@ my $saveCount; # count the number of times we will/did call SaveNewValues() my $scanWritable; # flag to process only writable file types my $sectHeader; # current section header for -p option my $sectTrailer; # section trailer for -p option +my $seqFileBase; # sequential file number at start of directory my $seqFileNum; # sequential file number used for %C +my $setCharset; # character set setting ('default' if not set and -csv -b used) my $showGroup; # number of group to show (may be zero or '') my $showTagID; # non-zero to show tag ID's my $stayOpenBuff='';# buffer for -stay_open file @@ -184,7 +207,6 @@ my $textOut; # extension for text output file (or undef for no output) my $textOverwrite; # flag to overwrite existing text output file (2=append, 3=over+append) my $tmpFile; # temporary file to delete on exit my $tmpText; # temporary text file -my $utf8; # flag set if we are using UTF-8 encoding my $validFile; # flag indicating we processed a valid file my $verbose; # verbose setting my $vout; # verbose output file reference (\*STDOUT or \*STDERR) @@ -211,6 +233,11 @@ my $isCRLF = { MSWin32 => 1, os2 => 1, dos => 1 }->{$^O}; # lookup for JSON characters that we escape specially my %jsonChar = ( '"'=>'"', '\\'=>'\\', "\t"=>'t', "\n"=>'n', "\r"=>'r' ); +# lookup for C-style escape sequences +my %escC = ( "\n" => '\n', "\r" => '\r', "\t" => '\t', '\\' => '\\\\'); +my %unescC = ( a => "\a", b => "\b", f => "\f", n => "\n", r => "\r", + t => "\t", 0 => "\0", '\\' => '\\' ); + # options requiring additional arguments # (used only to skip over these arguments when reading -stay_open ARGFILE) # (arg is converted to lower case then tested again unless an entry was found with the same case) @@ -221,16 +248,20 @@ my %optArgs = ( '-c' => 1, '-coordformat' => 1, '-charset' => 0, # (optional arg; OK because arg cannot begin with "-") '-config' => 1, + '-csvdelim' => 1, '-d' => 1, '-dateformat' => 1, '-D' => 0, # necessary to avoid matching lower-case equivalent '-echo' => 1, '-echo1' => 1, '-echo2' => 1, '-echo3' => 1, '-echo4' => 1, + '-efile' => 1, '-efile1' => 1, '-efile2' => 1, '-efile3' => 1, '-efile4' => 1, + '-efile!' => 1, '-efile1!' => 1, '-efile2!' => 1, '-efile3!' => 1, '-efile4!' => 1, '-ext' => 1, '--ext' => 1, '-ext+' => 1, '--ext+' => 1, '-extension' => 1, '--extension' => 1, '-extension+' => 1, '--extension+' => 1, - '-fileorder' => 1, + '-fileorder' => 1, '-fileorder0' => 1, '-fileorder1' => 1, '-fileorder2' => 1, + '-fileorder3' => 1, '-fileorder4' => 1, '-fileorder5' => 1, '-geotag' => 1, '-globaltimeshift' => 1, '-i' => 1, '-ignore' => 1, - '-if' => 1, + '-if' => 1, '-if0' => 1, '-if1' => 1, '-if2' => 1, '-if3' => 1, '-if4' => 1, '-if5' => 1, '-lang' => 0, # (optional arg; cannot begin with "-") '-listitem' => 1, '-o' => 1, '-out' => 1, @@ -260,6 +291,7 @@ my @recommends = qw( Digest::SHA IO::Compress::Bzip2 POSIX::strptime + Time::Local Unicode::LineBreak IO::Compress::RawDeflate IO::Uncompress::RawInflate @@ -273,6 +305,10 @@ my %altRecommends = ( my %unescapeChar = ( 't'=>"\t", 'n'=>"\n", 'r'=>"\r" ); +# special subroutines used in -if condition +sub Image::ExifTool::EndDir() { return $endDir = 1 } +sub Image::ExifTool::End() { return $end = 1 } + # exit routine sub Exit { if ($pause) { @@ -342,13 +378,21 @@ if (grep /^-common_args$/i, @ARGV) { # loop over sets of command-line arguments separated by "-execute" Command: for (;;) { -@echo3 and print STDOUT join("\n", @echo3), "\n"; -@echo4 and print STDERR join("\n", @echo4), "\n"; +if (@echo3) { + my $str = join("\n", @echo3) . "\n"; + $str =~ s/\$\{status\}/$rtnVal/ig; + print STDOUT $str; +} +if (@echo4) { + my $str = join("\n", @echo4) . "\n"; + $str =~ s/\$\{status\}/$rtnVal/ig; + print STDERR $str; +} $rafStdin->Close() if $rafStdin; undef $rafStdin; -# save or previous return codes +# save our previous return codes $rtnValPrev = $rtnVal; $rtnValApp = $rtnVal if $rtnVal; @@ -363,7 +407,7 @@ if ($binaryStdout) { # flush console and print "{ready}" message if -stay_open is in effect if ($stayOpen >= 2) { - if ($quiet) { + if ($quiet and not defined $executeID) { # flush output if possible eval { require IO::Handle } and STDERR->flush(), STDOUT->flush(); } else { @@ -379,23 +423,29 @@ if ($stayOpen >= 2) { # initialize necessary static file-scope variables # (not done: @commonArgs, @moreArgs, $critical, $binaryStdout, $helped, # $interrupted, $mt, $pause, $rtnValApp, $rtnValPrev, $stayOpen, $stayOpenBuff, $stayOpenFile) +undef @condition; undef @csvFiles; undef @csvTags; undef @delFiles; undef @dynamicFiles; undef @echo3; undef @echo4; +undef @efile; undef @exclude; undef @files; undef @newValues; undef @srcFmt; undef @tags; undef %appended; +undef %countLink; undef %created; undef %csvTags; undef %database; +undef %endDir; undef %filterExt; undef %ignore; +undef %outComma; +undef %outTrailer; undef %printFmt; undef %preserveTime; undef %setTags; @@ -405,30 +455,36 @@ undef %utf8FileName; undef %warnedOnce; undef %wext; undef $allGroup; +undef $altEnc; undef $argFormat; undef $binaryOutput; undef $binSep; undef $binTerm; undef $comma; -undef $condition; undef $csv; undef $csvAdd; undef $deleteOrig; undef $disableOutput; undef $doSetFileName; undef $doUnzip; +undef $end; +undef $endDir; undef $escapeHTML; +undef $escapeC; undef $evalWarning; undef $executeID; undef $failCondition; +undef $fastCondition; undef $fileHeader; undef $filtered; undef $fixLen; undef $forcePrint; +undef $ignoreHidden; undef $joinLists; undef $langOpt; undef $listItem; undef $multiFile; +undef $noBinary; undef $outOpt; undef $preserveTime; undef $progress; @@ -437,6 +493,7 @@ undef $progressMax; undef $recurse; undef $scanWritable; undef $sectHeader; +undef $setCharset; undef $showGroup; undef $showTagID; undef $structOpt; @@ -452,16 +509,15 @@ undef $windowTitle; $count = 0; $countBad = 0; $countBadCr = 0; -$countBadLink = 0; $countBadWr = 0; $countCopyWr = 0; $countDir = 0; $countFailed = 0; $countGoodCr = 0; $countGoodWr = 0; -$countLink = 0; $countNewDir = 0; $countSameWr = 0; +$csvDelim = ','; $csvSaveCount = 0; $fileTrailer = ''; $filterFlag = 0; @@ -476,18 +532,18 @@ $quiet = 0; $rtnVal = 0; $saveCount = 0; $sectTrailer = ''; +$seqFileBase = 0; $seqFileNum = 0; $tabFormat = 0; -$utf8 = 1; $vout = \*STDOUT; $xml = 0; # define local variables used only in this command loop my @fileOrder; # tags to use for ordering of input files -my %excludeGrp; # hash of tags excluded by group +my $fileOrderFast; # -fast level for -fileOrder option my $addGeotime; # automatically added geotime argument -my $allInGroup; # flag to show all tags in a group my $doGlob; # flag set to do filename wildcard expansion +my $endOfOpts; # flag set if "--" option encountered my $escapeXML; # flag to escape printed values for xml my $setTagsFile; # filename for last TagsFromFile option my $sortOpt; # sort option is used @@ -524,7 +580,7 @@ if (not $preserveTime and $^O eq 'MSWin32') { for (;;) { # execute the command now if no more arguments or -execute is used - if (not @ARGV or $ARGV[0] =~ /^(-|\xe2\x88\x92)execute(\d*)$/i) { + if (not @ARGV or ($ARGV[0] =~ /^(-|\xe2\x88\x92)execute(\d+)?$/i and not $endOfOpts)) { if (@ARGV) { $executeID = $2; # save -execute number for "{ready}" response $helped = 1; # don't show help if we used -execute @@ -575,6 +631,7 @@ for (;;) { # process arguments which were deferred to the next pass unshift @ARGV, @nextPass; undef @nextPass; + undef $endOfOpts; ++$pass; next; } @@ -584,8 +641,14 @@ for (;;) { $_ = shift; next if $badCmd; # flush remaining arguments if aborting this command - if (s/^(-|\xe2\x88\x92)//) { # allow funny dashes (nroff dash bug for cut-n-paste from pod) + # allow funny dashes (nroff dash bug for cut-n-paste from pod) + if (not $endOfOpts and s/^(-|\xe2\x88\x92)//) { s/^\xe2\x88\x92/-/; # translate double-dash too + if ($_ eq '-') { + $pass or push @nextPass, '--'; + $endOfOpts = 1; + next; + } my $a = lc $_; if (/^list([wfrdx]|wf|g(\d*))?$/i) { $pass or push @nextPass, "-$_"; @@ -600,7 +663,7 @@ for (;;) { } $group = $2; shift; - $group =~ /IFD/i and Warn("Can't list tags for specific IFD\n"), next; + $group =~ /IFD/i and Warn("Can't list tags for specific IFD\n"), $helped=1, next; $group =~ /^(all|\*)$/ and undef $group; } else { $pass or next; @@ -639,7 +702,7 @@ for (;;) { } else { # 'g(\d*)' # list all groups in specified family my $family = $2 || 0; - PrintTagList("Groups in family $family", GetAllGroups($family)); + PrintTagList("Groups in family $family", $mt->GetAllGroups($family)); } next; } @@ -701,7 +764,7 @@ for (;;) { } my $fp = ($stayOpen == 1 ? \*STAYOPEN : \*ARGFILE); unless ($mt->Open($fp, $argFile)) { - unless ($argFile !~ /^\// and $mt->Open($fp, "$exeDir/$argFile")) { + unless ($argFile !~ /^\// and $mt->Open($fp, "$Image::ExifTool::exeDir/$argFile")) { Error "Error opening arg file $argFile\n"; $badCmd = 1; next @@ -740,7 +803,11 @@ for (;;) { next; } /^arg(s|format)$/i and $argFormat = 1, next; - /^b(inary)?$/i and $mt->Options(Binary => 1, NoPDFList => 1), $binaryOutput = 1, next; + if (/^(-?)b(inary)?$/i) { + ($binaryOutput, $noBinary) = $1 ? (undef, 1) : (1, undef); + $mt->Options(Binary => $binaryOutput, NoPDFList => $binaryOutput); + next; + } if (/^c(oordFormat)?$/i) { my $fmt = shift; $fmt or Error("Expecting coordinate format for -c option\n"), $badCmd=1, next; @@ -756,8 +823,16 @@ for (;;) { PrintTagList('Available character sets', sort keys %charsets); $helped = 1; } elsif ($charset !~ s/^(\w+)=// or lc($1) eq 'exiftool') { - $mt->Options(Charset => $charset); - $utf8 = ($mt->Options('Charset') eq 'UTF8'); + { + local $SIG{'__WARN__'} = sub { $evalWarning = $_[0] }; + undef $evalWarning; + $mt->Options(Charset => $charset); + } + if ($evalWarning) { + warn $evalWarning; + } else { + $setCharset = $mt->Options('Charset'); + } } else { # set internal encoding of specified metadata type my $type = { id3 => 'ID3', iptc => 'IPTC', exif => 'EXIF', filename => 'FileName', @@ -768,7 +843,7 @@ for (;;) { next; } /^config$/i and Warn("Ignored -config option (not first on command line)\n"), shift, next; - if (/^csv(\+?=.*)?/i) { + if (/^csv(\+?=.*)?$/i) { my $csvFile = $1; # must process on 2nd pass so -f and -charset options are available unless ($pass) { @@ -788,7 +863,7 @@ for (;;) { if ($mt->Open(\*CSVFILE, $csvFile)) { binmode CSVFILE; require Image::ExifTool::Import; - $msg = Image::ExifTool::Import::ReadCSV(\*CSVFILE, \%database, $forcePrint); + $msg = Image::ExifTool::Import::ReadCSV(\*CSVFILE, \%database, $forcePrint, $csvDelim); close(CSVFILE); } else { $msg = "Error opening CSV file '${csvFile}'"; @@ -799,6 +874,15 @@ for (;;) { $csv = 'CSV'; next; } + if (/^csvdelim$/i) { + $csvDelim = shift; + defined $csvDelim or Error("Expecting argument for -csvDelim option\n"), $badCmd=1, next; + $csvDelim =~ /"/ and Error("CSV delimiter can not contain a double quote\n"), $badCmd=1, next; + my %unescape = ( 't'=>"\t", 'n'=>"\n", 'r'=>"\r", '\\' => '\\' ); + $csvDelim =~ s/\\(.)/$unescape{$1}||"\\$1"/sge; + $mt->Options(CSVDelim => $csvDelim); + next; + } if (/^d$/ or $a eq 'dateformat') { my $fmt = shift; $fmt or Error("Expecting date format for -d option\n"), $badCmd=1, next; @@ -807,9 +891,11 @@ for (;;) { } (/^D$/ or $a eq 'decimal') and $showTagID = 'D', next; /^delete_original(!?)$/i and $deleteOrig = ($1 ? 2 : 1), next; + /^list_dir$/i and $listDir = 1, next; (/^e$/ or $a eq '-composite') and $mt->Options(Composite => 0), next; (/^-e$/ or $a eq 'composite') and $mt->Options(Composite => 1), next; (/^E$/ or $a eq 'escapehtml') and require Image::ExifTool::HTML and $escapeHTML = 1, next; + ($a eq 'ec' or $a eq 'escapec') and $escapeC = 1, next; ($a eq 'ex' or $a eq 'escapexml') and $escapeXML = 1, next; if (/^echo(\d)?$/i) { my $n = $1 || 1; @@ -824,11 +910,20 @@ for (;;) { $helped = 1; next; } - if (/^(ee|extractembedded)$/i) { - $mt->Options(ExtractEmbedded => 1); + if (/^(ee|extractembedded)(\d*)$/i) { + $mt->Options(ExtractEmbedded => $2 || 1); $mt->Options(Duplicates => 1); next; } + if (/^efile(\d)?(!)?$/i) { + my $arg = shift; + defined $arg or Error("Expecting file name for -$_ option\n"), $badCmd=1, next; + $efile[0] = $arg if not $1 or $1 & 0x01; + $efile[1] = $arg if $1 and $1 & 0x02; + $efile[2] = $arg if $1 and $1 & 0x04; + unlink $arg if $2; + next; + } # (-execute handled at top of loop) if (/^-?ext(ension)?(\+)?$/i) { my $ext = shift; @@ -851,8 +946,10 @@ for (;;) { $mt->Options(FastScan => (length $1 ? $1 : 1)); next; } - if ($a eq 'fileorder') { + if (/^fileorder(\d*)$/i) { push @fileOrder, shift if @ARGV; + my $num = $1 || 0; + $fileOrderFast = $num if not defined $fileOrderFast or $fileOrderFast > $num; next; } $a eq 'globaltimeshift' and $mt->Options(GlobalTimeShift => shift), next; @@ -860,6 +957,7 @@ for (;;) { $showGroup = $3 || 0; $allGroup = ($2 ? lc($2) eq 'roupnames' : $1 eq 'G'); $mt->Options(SavePath => 1) if $showGroup =~ /\b5\b/; + $mt->Options(SaveFormat => 1) if $showGroup =~ /\b6\b/; next; } if ($a eq 'geotag') { @@ -906,20 +1004,18 @@ for (;;) { my $dir = shift; defined $dir or Error("Expecting directory name for -i option\n"), $badCmd=1, next; $ignore{$dir} = 1; + $dir eq 'HIDDEN' and $ignoreHidden = 1; next; } - if ($a eq 'if') { + if (/^if(\d*)$/i) { my $cond = shift; + $fastCondition = $1 if length $1; defined $cond or Error("Expecting expression for -if option\n"), $badCmd=1, next; # prevent processing file unnecessarily for simple case of failed '$ok' or 'not $ok' $cond =~ /^\s*(not\s*)\$ok\s*$/i and ($1 xor $rtnValPrev) and $failCondition=1; # add to list of requested tags push @requestTags, $cond =~ /\$\{?((?:[-\w]+:)*[-\w?*]+)/g; - if (defined $condition) { - $condition .= " and ($cond)"; - } else { - $condition = "($cond)"; - } + push @condition, $cond; next; } if (/^j(son)?(\+?=.*)?$/i) { @@ -959,7 +1055,7 @@ for (;;) { } /^(k|pause)$/i and $pause = 1, next; (/^l$/ or $a eq 'long') and --$outFormat, next; - (/^L$/ or $a eq 'latin') and $utf8 = 0, $mt->Options(Charset => 'Latin'), next; + (/^L$/ or $a eq 'latin') and $mt->Options(Charset => 'Latin'), next; if ($a eq 'lang') { $langOpt = (@ARGV and $ARGV[0] !~ /^(-|\xe2\x88\x92)/) ? shift : undef; if ($langOpt) { @@ -973,8 +1069,8 @@ for (;;) { my $langs = "Available languages:\n"; $langs .= " $_ - $Image::ExifTool::langName{$_}\n" foreach @Image::ExifTool::langs; $langs =~ tr/_/-/; # display dashes instead of underlines in language codes - $langs = $mt->Decode($langs, 'UTF8'); $langs = Image::ExifTool::HTML::EscapeHTML($langs) if $escapeHTML; + $langs = $mt->Decode($langs, 'UTF8'); $langOpt and Error("Invalid or unsupported language '${langOpt}'.\n$langs"), $badCmd=1, next; print $langs; $helped = 1; @@ -990,6 +1086,7 @@ for (;;) { /^(m|ignoreminorerrors)$/i and $mt->Options(IgnoreMinorErrors => 1), next; /^(n|-printconv)$/i and $mt->Options(PrintConv => 0), next; /^(-n|printconv)$/i and $mt->Options(PrintConv => 1), next; + $a eq 'nop' and $helped=1, next; # (undocumented) no operation, added in 11.25 if (/^o(ut)?$/i) { $outOpt = shift; defined $outOpt or Error("Expected output file or directory name for -o option\n"), $badCmd=1, next; @@ -1032,7 +1129,7 @@ for (;;) { } /^q(uiet)?$/i and ++$quiet, next; /^r(ecurse)?(\.?)$/i and $recurse = ($2 ? 2 : 1), next; - if ($a eq 'require') { # undocumented, added in version 8.65 + if ($a eq 'require') { # (undocumented) added in version 8.65 my $ver = shift; unless (defined $ver and Image::ExifTool::IsFloat($ver)) { Error("Expecting version number for -require option\n"); @@ -1145,7 +1242,7 @@ for (;;) { $textOverwrite += 2 if $t2 =~ /\+/; # append if ($t1 ne 'W' and lc($t1) ne 'tagout') { undef $tagOut; - } elsif ($textOverwrite >= 2 and $textOut !~ /%[-+]?\d*[.:]?\d*[lu]?[tgs]/) { + } elsif ($textOverwrite >= 2 and $textOut !~ /%[-+]?\d*[.:]?\d*[lu]?[tgso]/) { $tagOut = 0; # append tags to one file } else { $tagOut = 1; # separate file for each tag @@ -1183,7 +1280,7 @@ for (;;) { if (/^php$/i) { $json = 2; $html = $xml = 0; - $mt->Options(Duplicates=>1); + $mt->Options(Duplicates => 1); next; } if (/^z(ip)?$/i) { @@ -1203,7 +1300,7 @@ for (;;) { push @newValues, $_; if (/^mwg:/i) { $useMWG = 1; - } elsif (/^([-\w]+:)*(filename|directory)\b/i) { + } elsif (/^([-\w]+:)*(filename|directory|testname)\b/i) { $doSetFileName = 1; } elsif (/^([-\w]+:)*(geotag|geotime|geosync)\b/i) { if (lc $2 eq 'geotime') { @@ -1224,14 +1321,14 @@ for (;;) { push @{$setTags{$setTagsFile}}, $_; if (/>/) { $useMWG = 1 if /^(.*>\s*)?mwg:/si; - if (/\b(filename|directory)#?$/i) { + if (/\b(filename|directory|testname)#?$/i) { $doSetFileName = 1; } elsif (/\bgeotime#?$/i) { $addGeotime = ''; } } else { $useMWG = 1 if /^([^<]+<\s*(.*\$\{?)?)?mwg:/si; - if (/^([-\w]+:)*(filename|directory)\b/i) { + if (/^([-\w]+:)*(filename|directory|testname)\b/i) { $doSetFileName = 1; } elsif (/^([-\w]+:)*geotime\b/i) { $addGeotime = ''; @@ -1240,7 +1337,7 @@ for (;;) { } else { my $lst = s/^-// ? \@exclude : \@tags; unless (/^([-\w*]+:)*([-\w*?]+)#?$/) { - Warn(qq(Invalid TAG name: $_\n)); + Warn(qq(Invalid TAG name: "$_"\n)); } push @$lst, $_; # (push everything for backward compatibility) } @@ -1337,15 +1434,22 @@ if ($tagOut and ($csv or %printFmt or $tabFormat or $xml or ($verbose and $html) next; } -if ($csv and $csv eq 'CSV' and not $isWriting and ($textOut or $binaryOutput)) { - Warn 'Sorry, ' . ($textOut ? '-w' : '-b') . " may not be combined with -csv\n"; - $rtnVal = 1; - next; +if ($csv and $csv eq 'CSV' and not $isWriting) { + if ($textOut) { + Warn "Sorry, -w may not be combined with -csv\n"; + $rtnVal = 1; + next; + } + if ($binaryOutput) { + $binaryOutput = 0; + $setCharset = 'default' unless defined $setCharset; + } + require Image::ExifTool::XMP if $setCharset; } if ($escapeHTML or $json) { # must be UTF8 for HTML conversion and JSON output - $mt->Options(Charset => 'UTF8'); + $mt->Options(Charset => 'UTF8') if $json; # use Escape option to do our HTML escaping unless XML output $mt->Options(Escape => 'HTML') if $escapeHTML and not $xml; } elsif ($escapeXML and not $xml) { @@ -1417,7 +1521,6 @@ if ($xml) { require Image::ExifTool::XMP if $json == 1; # (for EncodeBase64) } $mt->Options(List => 1) unless $joinLists; - $mt->Options(Duplicates => 0) unless defined $showGroup; $showTagID = 'D' if $tabFormat and not $showTagID; } elsif ($structOpt) { $mt->Options(List => 1); @@ -1523,7 +1626,7 @@ if (@newValues) { next; } my %opts = ( Shift => 0 ); # shift values if possible instead of adding/deleting - # allow writing of 'unsafe' tags unless specified by wildcard + # allow writing of 'Unsafe' tags unless specified by wildcard $opts{Protected} = 1 unless $tag =~ /[?*]/; if ($tag =~ s/SetNewValue($tag, $newVal, %opts); $needSave = 1; ++$isWriting if $rtn; @@ -1625,8 +1731,12 @@ if ($outOpt) { $scanWritable = 1; } +# initialize alternate encoding flag +$altEnc = $mt->Options('Charset'); +undef $altEnc if $altEnc eq 'UTF8'; + # set flag to fix description lengths if necessary -if ($utf8 and $mt->Options('Lang') ne 'en' and eval { require Encode }) { +if (not $altEnc and $mt->Options('Lang') ne 'en' and eval { require Encode }) { # (note that Unicode::GCString is part of the Unicode::LineBreak package) $fixLen = eval { require Unicode::GCString } ? 2 : 1; } @@ -1636,6 +1746,7 @@ if (@fileOrder) { my @allFiles; ProcessFiles($mt, \@allFiles); my $sortTool = new Image::ExifTool; + $sortTool->Options(FastScan => $fileOrderFast) if $fileOrderFast; $sortTool->Options(PrintConv => $mt->Options('PrintConv')); $sortTool->Options(Duplicates => 0); my (%sortBy, %isFloat, @rev, $file); @@ -1687,13 +1798,17 @@ if (@dbKeys) { undef $evalWarning; local $SIG{'__WARN__'} = sub { $evalWarning = $_[0] }; foreach (@dbKeys) { + my $db = $database{$_}; + tr/\\/\// and $database{$_} = $db; # allow for backslashes in SourceFile # (punt on using ConvertFileName here, so $absPath may be a mix of encodings) my $absPath = AbsPath($_); if (defined $absPath) { - $database{$absPath} = $database{$_} unless $database{$absPath}; + $database{$absPath} = $db unless $database{$absPath}; if ($verbose and $verbose > 1) { print $vout "Imported entry for '${_}' (full path: '${absPath}')\n"; } + } elsif ($verbose and $verbose > 1) { + print $vout "Imported entry for '${_}' (non-existent file)\n"; } } } @@ -1711,8 +1826,21 @@ if ($filtered and not $validFile) { PrintCSV() if $csv and not $isWriting; # print folder/file trailer if necessary -print $sectTrailer if $sectTrailer and not $textOut; -print $fileTrailer if $fileTrailer and not $textOut and not $fileHeader; +if ($textOut) { + foreach (keys %outTrailer) { + next unless $outTrailer{$_}; + if ($mt->Open(\*OUTTRAIL, $_, '>>')) { + my $fp = \*OUTTRAIL; + print $fp $outTrailer{$_}; + close $fp; + } else { + Error("Error appending to $_\n"); + } + } +} else { + print $sectTrailer if $sectTrailer; + print $fileTrailer if $fileTrailer and not $fileHeader; +} my $totWr = $countGoodWr + $countBadWr + $countSameWr + $countCopyWr + $countGoodCr + $countBadCr; @@ -1755,7 +1883,7 @@ if (defined $deleteOrig) { # print summary my $tot = $count + $countBad; - if ($countDir or $totWr or $countFailed or $tot > 1 or $textOut or $countLink or $countBadLink) { + if ($countDir or $totWr or $countFailed or $tot > 1 or $textOut or %countLink) { my $o = (($html or $json or $xml or %printFmt or $csv) and not $textOut) ? \*STDERR : $vout; printf($o "%5d directories scanned\n", $countDir) if $countDir; printf($o "%5d directories created\n", $countNewDir) if $countNewDir; @@ -1766,12 +1894,14 @@ if (defined $deleteOrig) { printf($o "%5d image files %s\n", $countCopyWr, $overwriteOrig ? 'moved' : 'copied') if $countCopyWr; printf($o "%5d files weren't updated due to errors\n", $countBadWr) if $countBadWr; printf($o "%5d files weren't created due to errors\n", $countBadCr) if $countBadCr; - printf($o "%5d image files read\n", $count) if $tot>1 or ($countDir and not $totWr); + printf($o "%5d image files read\n", $count) if ($tot+$countFailed)>1 or ($countDir and not $totWr); printf($o "%5d files could not be read\n", $countBad) if $countBad; printf($o "%5d output files created\n", scalar(keys %created)) if $textOut; printf($o "%5d output files appended\n", scalar(keys %appended)) if %appended; - printf($o "%5d hard links created\n", $countLink) if $countLink or $countBadLink; - printf($o "%5d hard links could not be created\n", $countBadLink) if $countBadLink; + printf($o "%5d hard links created\n", $countLink{Hard} || 0) if $countLink{Hard} or $countLink{BadHard}; + printf($o "%5d hard links could not be created\n", $countLink{BadHard}) if $countLink{BadHard}; + printf($o "%5d symbolic links created\n", $countLink{Sym} || 0) if $countLink{Sym} or $countLink{BadSym}; + printf($o "%5d symbolic links could not be created\n", $countLink{BadSym}) if $countLink{BadSym}; } } @@ -1818,6 +1948,11 @@ sub GetImageInfo($$) $title =~ s/%([%bfpr])/$lkup{$1}/eg; SetWindowTitle($title); } + unless (length $orig or $outOpt) { + Warn qq(Error: Zero-length file name - ""\n); + ++$countBad; + return; + } # determine the name of the source file based on the original input file name if (@srcFmt) { my ($fmt, $first); @@ -1829,6 +1964,9 @@ sub GetImageInfo($$) $first = $file unless defined $first; } $file = $first if defined $first; + my ($d, $f) = Image::ExifTool::SplitFileName($orig); + $et->Options(UserParam => "OriginalDirectory#=$d"); + $et->Options(UserParam => "OriginalFileName#=$f"); } else { $file = $orig; } @@ -1836,16 +1974,27 @@ sub GetImageInfo($$) my $pipe = $file; if ($doUnzip) { # pipe through gzip or bzip2 if necessary - if ($file =~ /\.gz$/i) { - $pipe = qq{gzip -dc "$file" |}; - } elsif ($file =~ /\.bz2$/i) { - $pipe = qq{bzip2 -dc "$file" |}; + if ($file =~ /\.(gz|bz2)$/i) { + my $type = lc $1; + if ($file =~ /[^-_.'A-Za-z0-9\/\\]/) { + Warn "Error: Insecure zip file name. Skipped\n"; + EFile($file); + ++$countBad; + return; + } + if ($type eq 'gz') { + $pipe = qq{gzip -dc "$file" |}; + } else { + $pipe = qq{bzip2 -dc "$file" |}; + } + $$et{TRUST_PIPE} = 1; } } # evaluate -if expression for conditional processing - if (defined $condition) { + if (@condition) { unless ($file eq '-' or $et->Exists($file)) { Warn "Error: File not found - $file\n"; + EFile($file); FileNotFound($file); ++$countBad; return; @@ -1857,37 +2006,48 @@ sub GetImageInfo($$) undef $evalWarning; local $SIG{'__WARN__'} = sub { $evalWarning = $_[0] }; - my %info; + my (%info, $condition); # extract information and build expression for evaluation my $opts = { Duplicates => 1, RequestTags => \@requestTags, Verbose => 0, HtmlDump => 0 }; + $$opts{FastScan} = $fastCondition if defined $fastCondition; # return all tags but explicitly mention tags on command line so # requested images will generate the appropriate warnings @foundTags = ('*', @tags) if @tags; $info = $et->ImageInfo(Infile($pipe,$isWriting), \@foundTags, $opts); - my $cond = $et->InsertTagValues(\@foundTags, $condition, \%info); + foreach $condition (@condition) { + my $cond = $et->InsertTagValues(\@foundTags, $condition, \%info); + { + # set package so eval'd functions are in Image::ExifTool namespace + package Image::ExifTool; - #### eval "-if" condition (%info) - $result = eval $cond; + my $self = $et; + #### eval "-if" condition (%info, $self) + $result = eval $cond; - $@ and $evalWarning = $@; - if ($evalWarning) { - # fail condition if warning is issued - undef $result; - if ($verbose) { - chomp $evalWarning; - $evalWarning =~ s/ at \(eval .*//s; - Warn "Condition: $evalWarning - $file\n"; + $@ and $evalWarning = $@; + } + if ($evalWarning) { + # fail condition if warning is issued + undef $result; + if ($verbose) { + chomp $evalWarning; + $evalWarning =~ s/ at \(eval .*//s; + Warn "Condition: $evalWarning - $file\n"; + } } + last unless $result; } + undef @foundTags if $fastCondition; # ignore if we didn't get all tags } unless ($result) { $verbose and print $vout "-------- $file (failed condition)$progStr\n"; + EFile($file, 2); ++$countFailed; return; } # can't make use of $info if verbose because we must reprocess # the file anyway to generate the verbose output - undef $info if $verbose; + undef $info if $verbose or defined $fastCondition; } if (defined $deleteOrig) { print $vout "======== $file$progStr\n" if defined $verbose; @@ -1902,6 +2062,7 @@ sub GetImageInfo($$) ++$countGoodWr; } else { Warn "Error renaming $original\n"; + EFile($file); ++$countBad; } return; @@ -1912,7 +2073,7 @@ sub GetImageInfo($$) my ($fp, $outfile, $append); if ($textOut and $verbose and not $tagOut) { ($fp, $outfile, $append) = OpenOutputFile($orig); - $fp or ++$countBad, return; + $fp or EFile($file), ++$countBad, return; # delete file if we exit prematurely (unless appending) $tmpText = $outfile unless $append; $et->Options(TextOut => $fp); @@ -1944,6 +2105,7 @@ sub GetImageInfo($$) Warn "Error: File not found - $file\n"; FileNotFound($file); $outfile and close($fp), undef($tmpText), $et->Unlink($outfile); + EFile($file); ++$countBad; return; } @@ -1993,6 +2155,7 @@ sub GetImageInfo($$) } if ($info->{Error}) { Warn "Error: $info->{Error} - $file\n"; + EFile($file); ++$countBad; return; } @@ -2003,7 +2166,7 @@ sub GetImageInfo($$) # or if there is none of the requested information available if ($binaryOutput or not %$info) { my $errs = $et->GetInfo('Warning', 'Error'); - PrintErrors($et, $errs, $file) and $rtnVal = 1; + PrintErrors($et, $errs, $file) and EFile($file), $rtnVal = 1; } elsif ($et->GetValue('Error') or ($$et{Validate} and $et->GetValue('Warning'))) { $rtnVal = 1; } @@ -2011,10 +2174,13 @@ sub GetImageInfo($$) # open output file (or stdout if no output file) if not done already unless ($outfile or $tagOut) { ($fp, $outfile, $append) = OpenOutputFile($orig); - $fp or ++$countBad, return; + $fp or EFile($file), ++$countBad, return; $tmpText = $outfile unless $append; } + # restore state of comma flag for this file if appending + $comma = $outComma{$outfile} if $append and ($textOverwrite & 0x02); + # print the results for this file if (%printFmt) { # output using print format file (-p) option @@ -2070,13 +2236,13 @@ sub GetImageInfo($$) } delete $printFmt{HEAD} unless $outfile; # print header only once per output file my $errs = $et->GetInfo('Warning', 'Error'); - PrintErrors($et, $errs, $file); + PrintErrors($et, $errs, $file) and EFile($file); } elsif (not $disableOutput) { my ($tag, $line, %noDups, %csvInfo, $bra, $ket, $sep); if ($fp) { # print file header (only once) if ($fileHeader) { - print $fp $fileHeader; + print $fp $fileHeader unless defined $outfile and ($created{$outfile} or $appended{$outfile}); undef $fileHeader unless $textOut; } if ($html) { @@ -2085,7 +2251,7 @@ sub GetImageInfo($$) my $f = $file; CleanXML(\$f); print $fp "\n' if $outFormat < 1; # finish rdf:Description token unless short format $ind = $outFormat >= 0 ? ' ' : ' '; @@ -2128,21 +2295,26 @@ sub GetImageInfo($$) my $noDups = ($json or ($xml and $outFormat > 0)); my $printConv = $et->Options('PrintConv'); my $lastGroup = ''; + my $i = -1; TAG: foreach $tag (@foundTags) { + ++$i; # keep track on index in @foundTags my $tagName = GetTagName($tag); my ($group, $valList); - # make sure this tag has a value + # get the value for this tag my $val = $$info{$tag}; + # set flag if this is binary data + $isBinary = (ref $val eq 'SCALAR' and defined $binaryOutput); if (ref $val) { # happens with -X, -j or -php when combined with -b: if (defined $binaryOutput and not $binaryOutput and $$et{TAG_INFO}{$tag}{Protected}) { - # avoid extracting Protected binary tags (eg. data blocks) [insider information] + # avoid extracting Unsafe binary tags (eg. data blocks) [insider information] my $lcTag = lc $tag; $lcTag =~ s/ .*//; - next unless $$et{REQ_TAG_LOOKUP}{$lcTag}; + next unless $$et{REQ_TAG_LOOKUP}{$lcTag} or ($$et{OPTIONS}{RequestAll} || 0) > 2; } $val = ConvertBinary($val); # convert SCALAR references - if ($structOpt) { + next unless defined $val; + if ($structOpt and ref $val) { # serialize structure if necessary $val = Image::ExifTool::XMP::SerializeStruct($val) unless $xml or $json; } elsif (ref $val eq 'ARRAY') { @@ -2175,9 +2347,9 @@ TAG: foreach $tag (@foundTags) { $group = $et->GetGroup($tag, $showGroup); # look ahead to see if this tag may suppress a priority tag in # the same group, and if so suppress this tag instead - next if $noDups and $tag =~ /^(.*?) ?\(/ and defined $$info{$1} and + next if $noDups and $tag =~ /^(.*?) \(/ and defined $$info{$1} and $group eq $et->GetGroup($1, $showGroup); - $group = 'Unknown' if not $group and ($xml or $json); + $group = 'Unknown' if not $group and ($xml or $json or $csv); if ($fp and not ($allGroup or $csv)) { if ($lastGroup ne $group) { if ($html) { @@ -2198,6 +2370,9 @@ TAG: foreach $tag (@foundTags) { } undef $group; # undefine so we don't print it below } + } elsif ($noDups) { + # don't allow duplicates, but avoid suppressing the priority tag + next if $tag =~ /^(.*?) \(/ and defined $$info{$1}; } ++$lineCount; # we are printing something meaningful @@ -2215,7 +2390,8 @@ TAG: foreach $tag (@foundTags) { } my @groups = $et->GetGroup($tag); $outfile and close($fp), undef($tmpText); # (shouldn't happen) - ($fp, $outfile, $append) = OpenOutputFile($orig, $tagName, \@groups, $ext); + my $org = $et->GetValue('OriginalRawFileName') || $et->GetValue('OriginalFileName'); + ($fp, $outfile, $append) = OpenOutputFile($orig, $tagName, \@groups, $ext, $org); $fp or ++$countBad, next TAG; $tmpText = $outfile unless $append; } @@ -2244,26 +2420,38 @@ TAG: foreach $tag (@foundTags) { } # save information for CSV output if ($csv) { - my $t = $group ? "$group:$tagName" : $tagName; - $t .= '#' if $tag =~ /#/; # add ValueConv "#" suffix if used + my $tn = $tagName; + $tn .= '#' if $tag =~ /#/; # add ValueConv "#" suffix if used + my $gt = $group ? "$group:$tn" : $tn; # (tag-name case may be different if some tags don't exist # in a file, so all logic must use lower-case tag names) - my $lcTag = lc $t; + my $lcTag = lc $gt; # override existing entry only if top priority next if defined $csvInfo{$lcTag} and $tag =~ /\(/; $csvInfo{$lcTag} = $val; if (defined $csvTags{$lcTag}) { # overwrite with actual extracted tag name # (note: can't check "if defined $val" here because -f may be used) - $csvTags{$lcTag} = $t if defined $$info{$tag}; - } else { - # (don't save unextracted tag name unless -f was used) - $csvTags{$lcTag} = defined($val) ? $t : ''; - if (@csvFiles == 1) { - push @csvTags, $lcTag; # save order of tags for first file - } elsif (@csvTags) { - undef @csvTags; - } + $csvTags{$lcTag} = $gt if defined $$info{$tag}; + next; + } + # must check for "Unknown" group (for tags that don't exist) + if ($group and defined $csvTags[$i] and $csvTags[$i] =~ /^(.*):$tn$/i) { + next if $group eq 'Unknown'; # nothing more to do if we don't know tag group + if ($1 eq 'unknown') { + # replace unknown entry in CSV tag lookup and list + delete $csvTags{$csvTags[$i]}; + $csvTags{$lcTag} = defined($val) ? $gt : ''; + $csvTags[$i] = $lcTag; + next; + } + } + # (don't save unextracted tag name unless -f was used) + $csvTags{$lcTag} = defined($val) ? $gt : ''; + if (@csvFiles == 1) { + push @csvTags, $lcTag; # save order of tags for first file + } elsif (@csvTags) { + undef @csvTags; } next; } @@ -2280,8 +2468,8 @@ TAG: foreach $tag (@foundTags) { } if ($escapeHTML) { $val =~ tr/\0-\x08\x0b\x0c\x0e-\x1f/./; - Image::ExifTool::XMP::FixUTF8(\$val) if $utf8; - $val = Image::ExifTool::HTML::EscapeHTML($val); + Image::ExifTool::XMP::FixUTF8(\$val) unless $altEnc; + $val = Image::ExifTool::HTML::EscapeHTML($val, $altEnc); } else { CleanXML(\$val); } @@ -2366,8 +2554,9 @@ TAG: foreach $tag (@foundTags) { if ($showTagID or $outFormat < 0) { $val = { val => $val }; if ($showTagID) { - my $id = $et->GetTagID($tag); + my ($id, $lang) = $et->GetTagID($tag); $id = sprintf('0x%.4x', $id) if $showTagID eq 'H' and $id =~ /^\d+$/; + $$val{lang} = $lang if $lang; $$val{id} = $id; } if ($tabFormat) { @@ -2397,10 +2586,14 @@ TAG: foreach $tag (@foundTags) { } } - # translate unprintable chars in value and remove trailing spaces - $val =~ tr/\x01-\x1f\x7f/./; - $val =~ s/\x00//g; - $val =~ s/\s+$//; + if ($escapeC) { + $val =~ s/([\0-\x1f\\\x7f])/$escC{$1} || sprintf('\x%.2x', ord $1)/eg; + } else { + # translate unprintable chars in value and remove trailing spaces + $val =~ tr/\x01-\x1f\x7f/./; + $val =~ s/\x00//g; + $val =~ s/\s+$//; + } if ($html) { print $fp ""; @@ -2503,9 +2696,17 @@ TAG: foreach $tag (@foundTags) { } } if ($outfile) { - # write section and file trailers before closing the file - print $fp $sectTrailer and $sectTrailer = '' if $sectTrailer; - print $fp $fileTrailer if $fileTrailer; + if ($textOverwrite & 0x02) { + # save state of this file if we may be appending + $outComma{$outfile} = $comma; + $outTrailer{$outfile} = ''; + $outTrailer{$outfile} .= $sectTrailer and $sectTrailer = '' if $sectTrailer; + $outTrailer{$outfile} .= $fileTrailer if $fileTrailer; + } else { + # write section and file trailers before closing the file + print $fp $sectTrailer and $sectTrailer = '' if $sectTrailer; + print $fp $fileTrailer if $fileTrailer; + } close($fp); undef $tmpText; if ($lineCount) { @@ -2530,7 +2731,8 @@ TAG: foreach $tag (@foundTags) { sub SetImageInfo($$$) { my ($et, $file, $orig) = @_; - my ($outfile, $restored, $isTemporary, $isStdout, $outType, $tagsFromSrc, $hardLink, $testName); + my ($outfile, $restored, $isTemporary, $isStdout, $outType, $tagsFromSrc); + my ($hardLink, $symLink, $testName, $sameFile); my $infile = $file; # save infile in case we change it again # clean up old temporary file if necessary @@ -2555,11 +2757,12 @@ sub SetImageInfo($$$) $outfile = FilenameSPrintf($outOpt, $orig); if ($outfile eq '') { Warn "Error: Can't create file with zero-length name from $orig\n"; + EFile($infile); ++$countBadCr; return 0; } } - if (not $isStdout and ($et->IsDirectory($outfile) or $outfile =~ /\/$/)) { + if (not $isStdout and (($et->IsDirectory($outfile) and not $listDir) or $outfile =~ /\/$/)) { $outfile .= '/' unless $outfile =~ /\/$/; my $name = $file; $name =~ s/^.*\///s; # remove directory name @@ -2571,6 +2774,7 @@ sub SetImageInfo($$$) unless (CanCreate($outType)) { my $what = $srcType ? 'other types' : 'scratch'; WarnOnce "Error: Can't create $outType files from $what\n"; + EFile($infile); ++$countBadCr; return 0; } @@ -2608,6 +2812,7 @@ sub SetImageInfo($$$) $outfile = NextUnusedFilename($outfile); if ($et->Exists($outfile) and not $doSetFileName) { Warn "Error: '${outfile}' already exists - $infile\n"; + EFile($infile); ++$countBadWr; return 0; } @@ -2628,7 +2833,7 @@ sub SetImageInfo($$$) $setTags = $tagsFromSrc || $setTags{$dyFile}; } else { $fromFile = FilenameSPrintf($dyFile, $orig); - ++$countBadWr, return 0 unless defined $fromFile; + defined $fromFile or EFile($infile), ++$countBadWr, return 0; $setTags = $setTags{$dyFile}; } # do we have multiple -tagsFromFile options with this file? @@ -2702,15 +2907,25 @@ sub SetImageInfo($$$) } else { # get name of hard link if we are creating one $hardLink = $et->GetNewValues('HardLink'); + $symLink = $et->GetNewValues('SymLink'); $testName = $et->GetNewValues('TestName'); $hardLink = FilenameSPrintf($hardLink, $orig) if defined $hardLink; + $symLink = FilenameSPrintf($symLink, $orig) if defined $symLink; + # determine what our output file name should be + my $newFileName = $et->GetNewValues('FileName'); + my $newDir = $et->GetNewValues('Directory'); + if (defined $newFileName and not length $newFileName) { + Warn "Warning: New file name is empty - $ infile\n"; + undef $newFileName; + } if (defined $testName) { + my $err; + $err = "You shouldn't write FileName or Directory with TestFile" if defined $newFileName or defined $newDir; + $err = "The -o option shouldn't be used with TestFile" if defined $outfile; + $err and Warn("Error: $err - $infile\n"), EFile($infile), ++$countBadWr, return 0; $testName = FilenameSPrintf($testName, $orig); $testName = Image::ExifTool::GetNewFileName($file, $testName) if $file ne ''; } - # determine what our output file name should be - my $newFileName = $et->GetNewValues('FileName'); - my $newDir = $et->GetNewValues('Directory'); if (defined $newFileName or defined $newDir or ($doSetFileName and defined $outfile)) { if ($newFileName) { $newFileName = FilenameSPrintf($newFileName, $orig); @@ -2727,16 +2942,21 @@ sub SetImageInfo($$$) } $outfile = NextUnusedFilename($outfile, $infile); if ($et->Exists($outfile)) { - if ($infile ne $outfile) { + if ($infile eq $outfile) { + undef $outfile; # not changing the file name after all + # (allow for case-insensitive filesystems) + } elsif ($et->IsSameFile($infile, $outfile)) { + $sameFile = $outfile; # same file, but the name has a different case + } else { Warn "Error: '${outfile}' already exists - $infile\n"; + EFile($infile); ++$countBadWr; return 0; } - undef $outfile; # not changing the file name after all } } if (defined $outfile) { - $verbose and print $vout "'${infile}' --> '${outfile}'\n"; + defined $verbose and print $vout "'${infile}' --> '${outfile}'\n"; # create output directory if necessary CreateDirectory($outfile); # set temporary file (automatically erased on abnormal exit) @@ -2745,10 +2965,15 @@ sub SetImageInfo($$$) unless (defined $tmpFile) { # count the number of tags and pseudo-tags we are writing my ($numSet, $numPseudo) = $et->CountNewValues(); + if ($numSet != $numPseudo and $et->IsDirectory($file)) { + print $vout "Can't write real tags to a directory - $infile\n" if defined $verbose; + $numSet = $numPseudo; + } if ($et->Exists($file)) { unless ($numSet) { # no need to write if no tags set print $vout "Nothing changed in $file\n" if defined $verbose; + EFile($infile, 1); ++$countSameWr; return 1; } @@ -2756,6 +2981,7 @@ sub SetImageInfo($$$) if ($numSet == $numPseudo) { # no need to write if no real tags Warn("Error: Nothing to write - $file\n"); + EFile($infile, 1); ++$countBadWr; return 0; } @@ -2767,36 +2993,44 @@ sub SetImageInfo($$$) } else { # file doesn't exist, and we can't create it Warn "Error: File not found - $file\n"; + EFile($infile); FileNotFound($file); ++$countBadWr; return 0; } # quickly rename file and/or set file date if this is all we are doing if ($numSet == $numPseudo) { - my $r1 = $et->SetFileModifyDate($file,undef,'FileCreateDate'); - my $r2 = $et->SetFileModifyDate($file); - my $r3 = $et->SetSystemTags($file); - my $r4 = 0; - $r4 = $et->SetFileName($file, $outfile) if defined $outfile; - if ($r1 > 0 or $r2 > 0 or $r3 > 0 or $r4 > 0) { + my ($r0, $r1, $r2, $r3) = (0, 0, 0, 0); + if (defined $outfile) { + $r0 = $et->SetFileName($file, $outfile); + $file = $$et{NewName} if $r0 > 0; # continue with new name if changed + } + unless ($r0 < 0) { + $r1 = $et->SetFileModifyDate($file,undef,'FileCreateDate'); + $r2 = $et->SetFileModifyDate($file); + $r3 = $et->SetSystemTags($file); + } + if ($r0 > 0 or $r1 > 0 or $r2 > 0 or $r3 > 0) { ++$countGoodWr; - } elsif ($r1 < 0 or $r2 < 0 or $r3 < 0 or $r4 < 0) { + } elsif ($r0 < 0 or $r1 < 0 or $r2 < 0 or $r3 < 0) { + EFile($infile); ++$countBadWr; return 0; } else { + EFile($infile, 1); ++$countSameWr; } - if (defined $hardLink or defined $testName) { - my $src = (defined $outfile and $r4 > 0) ? $outfile : $file; - DoHardLink($et, $src, $hardLink, $testName); + if (defined $hardLink or defined $symLink or defined $testName) { + DoHardLink($et, $file, $hardLink, $symLink, $testName); } return 1; } - unless (defined $outfile) { + if (not defined $outfile or defined $sameFile) { # write to a truly temporary file $outfile = "${file}_exiftool_tmp"; if ($et->Exists($outfile)) { Warn("Error: Temporary file already exists: $outfile\n"); + EFile($infile); ++$countBadWr; return 0; } @@ -2810,9 +3044,9 @@ sub SetImageInfo($$$) my $success = $et->WriteInfo(Infile($file), $outfile, $outType); # create hard link if specified - if ($success and (defined $hardLink or defined $testName)) { + if ($success and (defined $hardLink or defined $symLink or defined $testName)) { my $src = defined $outfile ? $outfile : $file; - DoHardLink($et, $src, $hardLink, $testName); + DoHardLink($et, $src, $hardLink, $symLink, $testName); } # get file time if preserving it @@ -2850,6 +3084,7 @@ sub SetImageInfo($$$) return 0; } } + my $dstFile = defined $sameFile ? $sameFile : $file; if ($overwriteOrig > 1) { # copy temporary file over top of original to preserve attributes my ($err, $buff); @@ -2861,12 +3096,14 @@ sub SetImageInfo($$$) # temporarily disable CTRL-C during this critical operation $critical = 1; undef $tmpFile; # handle deletion of temporary file ourself - if ($et->Open(\*ORIG_FILE, $file, '>')) { + if ($et->Open(\*ORIG_FILE, $file, '+<')) { binmode(ORIG_FILE); while (read(NEW_FILE, $buff, 65536)) { print ORIG_FILE $buff or $err = 1; } close(NEW_FILE); + # Handle files being shorter than the original + eval { truncate(ORIG_FILE, tell(ORIG_FILE)) } or $err = 1; close(ORIG_FILE) or $err = 1; if ($err) { Warn "Couldn't overwrite in place - $file\n"; @@ -2892,6 +3129,7 @@ sub SetImageInfo($$$) } else { close(NEW_FILE); Warn "Error opening $file for writing\n"; + EFile($infile); $et->Unlink($newFile); ++$countBadWr; } @@ -2901,19 +3139,21 @@ sub SetImageInfo($$$) # simply rename temporary file to replace original # (if we didn't already rename it to add "_original") - } elsif ($et->Rename($tmpFile, $file)) { + } elsif ($et->Rename($tmpFile, $dstFile)) { ++$countGoodWr; } else { my $newFile = $tmpFile; undef $tmpFile; # (avoid deleting file if we get interrupted) # unlink may fail if already renamed or no permission if (not $et->Unlink($file)) { - Warn "Error renaming temporary file to $file\n"; + Warn "Error renaming temporary file to $dstFile\n"; + EFile($infile); $et->Unlink($newFile); ++$countBadWr; # try renaming again now that the target has been deleted - } elsif (not $et->Rename($newFile, $file)) { - Warn "Error renaming temporary file to $file\n"; + } elsif (not $et->Rename($newFile, $dstFile)) { + Warn "Error renaming temporary file to $dstFile\n"; + EFile($infile); # (don't delete tmp file now because it is all we have left) ++$countBadWr; } else { @@ -2935,6 +3175,7 @@ sub SetImageInfo($$$) ++$countGoodWr; } } elsif ($success) { + EFile($infile, 1); if ($isTemporary) { # just erase the temporary file since no changes were made $et->Unlink($tmpFile); @@ -2948,6 +3189,7 @@ sub SetImageInfo($$$) } print $vout "Nothing changed in $file\n" if defined $verbose; } else { + EFile($infile); $et->Unlink($tmpFile) if defined $tmpFile; ++$countBadWr; } @@ -2957,20 +3199,29 @@ sub SetImageInfo($$$) #------------------------------------------------------------------------------ # Make hard link and handle TestName if specified -# Inputs: 0) ExifTool ref, 1) source file name, 2) HardLink name, 3) TestFile name -sub DoHardLink($$$$) +# Inputs: 0) ExifTool ref, 1) source file name, 2) HardLink name, +# 3) SymLink name, 4) TestFile name +sub DoHardLink($$$$$) { - my ($et, $src, $hardLink, $testName) = @_; + my ($et, $src, $hardLink, $symLink, $testName) = @_; if (defined $hardLink) { $hardLink = NextUnusedFilename($hardLink); if ($et->SetFileName($src, $hardLink, 'Link') > 0) { - ++$countLink; + $countLink{Hard} = ($countLink{Hard} || 0) + 1; + } else { + $countLink{BadHard} = ($countLink{BadHard} || 0) + 1; + } + } + if (defined $symLink) { + $symLink = NextUnusedFilename($symLink); + if ($et->SetFileName($src, $symLink, 'SymLink') > 0) { + $countLink{Sym} = ($countLink{Sym} || 0) + 1; } else { - ++$countBadLink; + $countLink{BadSym} = ($countLink{BadSym} || 0) + 1; } } if (defined $testName) { - $testName = NextUnusedFilename($testName, $src, 1); + $testName = NextUnusedFilename($testName, $src); if ($usedFileName{$testName}) { $et->Warn("File '${testName}' would exist"); } elsif ($et->SetFileName($src, $testName, 'Test', $usedFileName{$testName}) == 1) { @@ -2990,7 +3241,7 @@ sub CleanXML($) # translate control characters that are invalid in XML $$strPt =~ tr/\0-\x08\x0b\x0c\x0e-\x1f/./; # fix malformed UTF-8 characters - Image::ExifTool::XMP::FixUTF8($strPt) if $utf8; + Image::ExifTool::XMP::FixUTF8($strPt) unless $altEnc; # escape necessary characters for XML $$strPt = Image::ExifTool::XMP::EscapeXML($$strPt); } @@ -3003,13 +3254,14 @@ sub EncodeXML($) { my $strPt = shift; if ($$strPt =~ /[\0-\x08\x0b\x0c\x0e-\x1f]/ or - ($utf8 and Image::ExifTool::XMP::IsUTF8($strPt) < 0)) + (not $altEnc and Image::ExifTool::XMP::IsUTF8($strPt) < 0)) { # encode binary data and non-UTF8 with special characters as base64 $$strPt = Image::ExifTool::XMP::EncodeBase64($$strPt); + # #ATV = Alexander Vonk, private communication return 'http://www.w3.org/2001/XMLSchema#base64Binary'; #ATV } elsif ($escapeHTML) { - $$strPt = Image::ExifTool::HTML::EscapeHTML($$strPt); + $$strPt = Image::ExifTool::HTML::EscapeHTML($$strPt, $altEnc); } else { $$strPt = Image::ExifTool::XMP::EscapeXML($$strPt); } @@ -3035,7 +3287,8 @@ sub FormatXML($$$) } elsif (ref $val eq 'HASH') { $gt = " rdf:parseType='Resource'>"; my $val2 = ''; - foreach (sort keys %$val) { + my @keys = $$val{_ordered_keys_} ? @{$$val{_ordered_keys_}} : sort keys %$val; + foreach (@keys) { # (some variable-namespace XML structure fields may have a different group) my $tok = /:/ ? $_ : ($grp . ':' . $_); $val2 .= "\n$ind <$tok" . FormatXML($$val{$_}, "$ind ", $grp) . ""; @@ -3064,19 +3317,20 @@ sub EscapeJSON($;$) # (these big numbers caused problems for some JSON parsers, so be more conservative) return $str if $str =~ /^-?(\d|[1-9]\d{1,14})(\.\d{1,16})?(e[-+]?\d{1,3})?$/i; } - # encode JSON string as Base64 if necessary + # encode JSON string in base64 if necessary if ($json < 2 and defined $binaryOutput and Image::ExifTool::XMP::IsUTF8(\$str) < 0) { return '"base64:' . Image::ExifTool::XMP::EncodeBase64($str, 1) . '"'; } - $str =~ s/\0+$//; # remove trailing nulls # escape special characters $str =~ s/(["\t\n\r\\])/\\$jsonChar{$1}/sg; if ($json < 2) { # JSON + $str =~ tr/\0//d; # remove all nulls # escape other control characters with \u $str =~ s/([\0-\x1f])/sprintf("\\u%.4X",ord $1)/sge; # JSON strings must be valid UTF8 - Image::ExifTool::XMP::FixUTF8(\$str) if $utf8; + Image::ExifTool::XMP::FixUTF8(\$str) unless $altEnc; } else { # PHP + $str =~ s/\0+$// unless $isBinary; # remove trailing nulls unless binary # must escape "$" too for PHP $str =~ s/\$/\\\$/sg; # escape other control characters with \x @@ -3111,9 +3365,11 @@ sub FormatJSON($$$) } elsif (ref $val eq 'HASH') { my ($bra, $ket, $sep) = $json == 1 ? ('{','}',':') : ('Array(',')',' =>'); print $fp $bra; - foreach (sort keys %$val) { + my @keys = $$val{_ordered_keys_} ? @{$$val{_ordered_keys_}} : sort keys %$val; + foreach (@keys) { print $fp ',' if $comma; - print $fp qq(\n$ind "$_"$sep ); + my $key = EscapeJSON($_, 1); + print $fp qq(\n$ind $key$sep ); # hack to force decimal id's to be printed as strings with -H if ($showTagID and $_ eq 'id' and $showTagID eq 'H' and $$val{$_} =~ /^\d+\.\d+$/) { print $fp qq{"$$val{$_}"}; @@ -3136,11 +3392,17 @@ sub FormatJSON($$$) sub FormatCSV($) { my $val = shift; - # currently, the value may contain NULL characters. It is unclear - # whether or not this is valid CSV, but some readers may not like it. - # (if this becomes a problem, in the future values may need to be truncated at - # the first NULL character, but this would disable the use of CSV for binary data) - $val = qq{"$val"} if $val =~ s/"/""/g or $val =~ /(^\s+|\s+$)/ or $val =~ /[,\n\r]/; + # check for valid encoding if the Charset option was used + if ($setCharset and ($val =~ /[^\x09\x0a\x0d\x20-\x7e\x80-\xff]/ or + ($setCharset eq 'UTF8' and Image::ExifTool::XMP::IsUTF8(\$val) < 0))) + { + $val = 'base64:' . Image::ExifTool::XMP::EncodeBase64($val, 1); + } + # currently, there is a chance that the value may contain NULL characters unless + # the -b option is used to encode as Base64. It is unclear whether or not this + # is valid CSV, but some readers may not like it. (If this becomes a problem, + # in the future values may need to be truncated at the first NULL character.) + $val = qq{"$val"} if $val =~ s/"/""/g or $val =~ /(^\s+|\s+$)/ or $val =~ /[\n\r]|\Q$csvDelim/; return $val; } @@ -3153,9 +3415,9 @@ sub PrintCSV() @csvTags or @csvTags = sort keys %csvTags; # make a list of tags actually found foreach $lcTag (@csvTags) { - push @tags, $csvTags{$lcTag} if $csvTags{$lcTag}; + push @tags, FormatCSV($csvTags{$lcTag}) if $csvTags{$lcTag}; } - print join(',', 'SourceFile', @tags), "\n"; + print join($csvDelim, 'SourceFile', @tags), "\n"; my $empty = defined($forcePrint) ? $forcePrint : ''; foreach $file (@csvFiles) { my @vals = (FormatCSV($file)); # start with full file name @@ -3166,7 +3428,7 @@ sub PrintCSV() defined $val or push(@vals,$empty), next; push @vals, FormatCSV($val); } - print join(',', @vals), "\n"; + print join($csvDelim, @vals), "\n"; } } @@ -3195,24 +3457,29 @@ sub AddGroups($$$$) #------------------------------------------------------------------------------ # Convert binary data (SCALAR references) for printing # Inputs: 0) object reference -# Returns: converted object +# Returns: converted object, or undef if we don't want binary objects sub ConvertBinary($) { my $obj = shift; my ($key, $val); if (ref $obj eq 'HASH') { foreach $key (keys %$obj) { - $$obj{$key} = ConvertBinary($$obj{$key}) if ref $$obj{$key}; + next unless ref $$obj{$key}; + $$obj{$key} = ConvertBinary($$obj{$key}); + return undef unless defined $$obj{$key}; } } elsif (ref $obj eq 'ARRAY') { foreach $val (@$obj) { - $val = ConvertBinary($val) if ref $val; + next unless ref $val; + $val = ConvertBinary($val); + return undef unless defined $val; } } elsif (ref $obj eq 'SCALAR') { + return undef if $noBinary; # (binaryOutput flag is set to 0 for binary mode of XML/PHP/JSON output formats) if (defined $binaryOutput) { $obj = $$obj; - # encode in base64 if necessary + # encode in base64 if necessary (0xf7 allows for up to 21-bit UTF-8 code space) if ($json == 1 and ($obj =~ /[^\x09\x0a\x0d\x20-\x7e\x80-\xf7]/ or Image::ExifTool::XMP::IsUTF8(\$obj) < 0)) { @@ -3220,7 +3487,7 @@ sub ConvertBinary($) } } else { # (-b is not valid for HTML output) - my $bOpt = ($html or ($csv and $csv eq 'CSV')) ? '' : ', use -b option to extract'; + my $bOpt = $html ? '' : ', use -b option to extract'; if ($$obj =~ /^Binary data \d+ bytes$/) { $obj = "($$obj$bOpt)"; } else { @@ -3232,18 +3499,26 @@ sub ConvertBinary($) } #------------------------------------------------------------------------------ -# Compare two tag values to see if they are equal +# Compare ValueConv and PrintConv values of a tag to see if they are equal # Inputs: 0) value1, 1) value2 # Returns: true if they are equal sub IsEqual($$) { - return 1 if ref $_[0] eq 'SCALAR' or $_[0] eq $_[1]; - return 0 if ref $_[0] ne 'ARRAY' or ref $_[1] ne 'ARRAY' or - @{$_[0]} ne @{$_[1]}; - # test all elements of an array - my $i = 0; - for ($i=0; $iIsDirectory($file)) { + if ($et->IsDirectory($file) and not $listDir) { $multiFile = $validFile = 1; ScanDir($et, $file, $list); } elsif ($filterFlag and not AcceptFile($file)) { @@ -3402,10 +3677,22 @@ sub ProcessFiles($;$) if ($list) { push(@$list, $file); } else { + if (%endDir) { + my ($d, $f) = Image::ExifTool::SplitFileName($file); + next if $endDir{$d}; + } GetImageInfo($et, $file); + $end and Warn("End called - $file\n"); + if ($endDir) { + Warn("EndDir called - $file\n"); + my ($d, $f) = Image::ExifTool::SplitFileName($file); + $endDir{$d} = 1; + undef $endDir; + } } } $et->Options(CharsetFileName => $enc) if $utf8FileName{$file}; + last if $end; } } @@ -3416,7 +3703,7 @@ sub ScanDir($$;$) { local $_; my ($et, $dir, $list) = @_; - my (@fileList, $done, $file, $utf8Name); + my (@fileList, $done, $file, $utf8Name, $winSurrogate, $endThisDir); my $enc = $et->Options('CharsetFileName'); # recode as UTF-8 if necessary if ($enc) { @@ -3427,17 +3714,30 @@ sub ScanDir($$;$) $utf8Name = 1; } return if $ignore{$dir}; + my $oldBase = $seqFileBase; + $seqFileBase = $seqFileNum; # use Win32::FindFile on Windows if available # (ReadDir will croak if there is a wildcard, so check for this) if ($^O eq 'MSWin32' and $dir !~ /[*?]/) { + undef $evalWarning; local $SIG{'__WARN__'} = sub { $evalWarning = $_[0] };; if (CheckUTF8($dir, $enc) >= 0) { if (eval { require Win32::FindFile }) { - @fileList = Win32::FindFile::ReadDir($dir); - $_ = $_->cFileName foreach @fileList; - $et->Options(CharsetFileName => 'UTF8'); # now using UTF8 - $utf8Name = 1; # ReadDir returns UTF-8 file names - $done = 1; + eval { + @fileList = Win32::FindFile::ReadDir($dir); + $_ = $_->cFileName foreach @fileList; + }; + $@ and $evalWarning = $@; + if ($evalWarning) { + chomp $evalWarning; + $evalWarning =~ s/ at .*//s; + Warn "Warning: [Win32::FindFile] $evalWarning - $dir\n"; + $winSurrogate = 1 if $evalWarning =~ /surrogate/; + } else { + $et->Options(CharsetFileName => 'UTF8'); # now using UTF8 + $utf8Name = 1; # ReadDir returns UTF-8 file names + $done = 1; + } } else { $done = 0; } @@ -3445,7 +3745,11 @@ sub ScanDir($$;$) } unless ($done) { # use standard perl library routines to read directory - opendir(DIR_HANDLE, $dir) or Warn("Error opening directory $dir\n"), return; + unless (opendir(DIR_HANDLE, $dir)) { + Warn("Error opening directory $dir\n"); + $seqFileBase = $oldBase + ($seqFileNum - $seqFileBase); + return; + } @fileList = readdir(DIR_HANDLE); closedir(DIR_HANDLE); if (defined $done) { @@ -3466,8 +3770,11 @@ sub ScanDir($$;$) next if $file =~ /^\./ and ($recurse == 1 or $file eq '.' or $file eq '..'); next if $ignore{$file} or ($ignore{SYMLINKS} and -l $path); ScanDir($et, $path, $list); + last if $end; next; } + next if $endThisDir; + next if $ignoreHidden and $file =~ /^\./; # ignore hidden files if specified # apply rules from -ext options my $accepted; if ($filterFlag) { @@ -3489,15 +3796,39 @@ sub ScanDir($$;$) next unless $file =~ /\.(gz|bz2)$/i; } } + # Windows patch to avoid replacing filename containing Unicode surrogate with 8.3 name + if ($winSurrogate and $isWriting and + (not $overwriteOrig or $overwriteOrig != 2) and + not $doSetFileName and $file =~ /~/) # (8.3 name will contain a tilde) + { + Warn("Not writing $path\n"); + WarnOnce("Use -overwrite_original_in_place to write files with Unicode surrogate characters\n"); + EFile($file); + ++$countBad; + next; + } $utf8FileName{$path} = 1 if $utf8Name; if ($list) { push(@$list, $path); } else { GetImageInfo($et, $path); + if ($end) { + Warn("End called - $file\n"); + last; + } + if ($endDir) { + $path =~ s(/$)(); + Warn("EndDir called - $path\n"); + $endDir{$path} = 1; + $endThisDir = 1; + undef $endDir; + } } } ++$countDir; $et->Options(CharsetFileName => $enc); # restore original setting + # update sequential file base for parent directory + $seqFileBase = $oldBase + ($seqFileNum - $seqFileBase); } #------------------------------------------------------------------------------ @@ -3515,29 +3846,42 @@ sub FindFileWindows($$) my $enc = $et->Options('CharsetFileName'); $wildfile = $et->Decode($wildfile, $enc, undef, 'UTF8') if $enc and $enc ne 'UTF8'; $wildfile =~ tr/\\/\//; # use forward slashes - my ($dir, $wildname) = ($wildfile =~ m{(.*/)(.*)}) ? ($1, $2) : ('', $wildfile); + my ($dir, $wildname) = ($wildfile =~ m{(.*[:/])(.*)}) ? ($1, $2) : ('', $wildfile); if ($dir =~ /[*?]/) { Warn "Wildcards don't work in the directory specification\n"; return (); } CheckUTF8($wildfile, $enc) >= 0 or return (); - local $SIG{'__WARN__'} = sub { $evalWarning = $_[0] };; - my @names = Win32::FindFile::FindFile($wildfile) or return (); - # (apparently this isn't always sorted, so do a case-insensitive sort here) - @names = sort { uc($a) cmp uc($b) } @names; - my ($rname, $nm, @files); - # replace "\?" with ".", and "\*" with ".*" for regular expression - ($rname = quotemeta $wildname) =~ s/\\\?/./g; - $rname =~ s/\\\*/.*/g; - foreach $nm (@names) { - $nm = $nm->cFileName; - # make sure that FindFile behaves - # (otherwise "*.jpg" matches things like "a.jpg_original"!) - next unless $nm =~ /^$rname$/i; - next if $nm eq '.' or $nm eq '..'; # don't match "." and ".." - my $file = "$dir$nm"; # add back directory name - push @files, $file; - $utf8FileName{$file} = 1; # flag this file name as UTF-8 encoded + undef $evalWarning; + local $SIG{'__WARN__'} = sub { $evalWarning = $_[0] }; + my @files; + eval { + my @names = Win32::FindFile::FindFile($wildfile) or return; + # (apparently this isn't always sorted, so do a case-insensitive sort here) + @names = sort { uc($a) cmp uc($b) } @names; + my ($rname, $nm); + # replace "\?" with ".", and "\*" with ".*" for regular expression + ($rname = quotemeta $wildname) =~ s/\\\?/./g; + $rname =~ s/\\\*/.*/g; + foreach $nm (@names) { + $nm = $nm->cFileName; + # make sure that FindFile behaves + # (otherwise "*.jpg" matches things like "a.jpg_original"!) + next unless $nm =~ /^$rname$/i; + next if $nm eq '.' or $nm eq '..'; # don't match "." and ".." + my $file = "$dir$nm"; # add back directory name + push @files, $file; + $utf8FileName{$file} = 1; # flag this file name as UTF-8 encoded + } + }; + $@ and $evalWarning = $@; + if ($evalWarning) { + chomp $evalWarning; + $evalWarning =~ s/ at .*//s; + Warn "Error: [Win32::FindFile] $evalWarning - $wildfile\n"; + undef @files; + EFile($wildfile); + ++$countBad; } return @files; } @@ -3642,9 +3986,7 @@ sub SuggestedExtension($$$) $ext = 'xml'; } elsif ($$valPt =~ /^RIFF....WAVE/s) { $ext = 'wav'; - } elsif ($tag eq 'OriginalRawFileData' and - defined($ext = $et->GetValue('OriginalRawFileName'))) - { + } elsif ($tag eq 'OriginalRawImage' and defined($ext = $et->GetValue('OriginalRawFileName'))) { $ext =~ s/^.*\.//s; $ext = $ext ? lc($ext) : 'raw'; } elsif ($tag eq 'EXIF') { @@ -3658,12 +4000,14 @@ sub SuggestedExtension($$$) $ext = $movType{$1} || $1; } elsif ($$valPt !~ /^.{0,4096}\0/s) { $ext = 'txt'; - } elsif ($$valPt =~ /^BM/) { + } elsif ($$valPt =~ /^BM.{15}\0/s) { $ext = 'bmp'; } elsif ($$valPt =~ /^CANON OPTIONAL DATA\0/) { $ext = 'vrd'; } elsif ($$valPt =~ /^IIII\x04\0\x04\0/) { $ext = 'dr4'; + } elsif ($$valPt =~ /^(.{10}|.{522})(\x11\x01|\x00\x11)/s) { + $ext = 'pict'; } else { $ext = 'dat'; } @@ -3694,14 +4038,15 @@ sub LoadPrintFormat($) # A sort of sprintf for filenames # Inputs: 0) format string (%d=dir, %f=file name, %e=ext), # 1) source filename or undef to test format string -# 2-4) [%t %g %s only] tag name, ref to array of group names, suggested extension +# 2-4) [%t %g %s %o only] tag name, ref to array of group names, +# suggested extension, original raw file name # Returns: new filename or undef on error (or if no file and fmt contains token) sub FilenameSPrintf($;$@) { my ($fmt, $file, @extra) = @_; local $_; # return format string straight away if no tokens - return $fmt unless $fmt =~ /%[-+]?\d*[.:]?\d*[lu]?[dDfFeEtgs]/; + return $fmt unless $fmt =~ /%[-+]?\d*[.:]?\d*[lu]?[dDfFeEtgso]/; return undef unless defined $file; CleanFilename($file); # make sure we are using forward slashes # split filename into directory, file, extension @@ -3715,9 +4060,9 @@ sub FilenameSPrintf($;$@) } $part{F} = $part{f} . $part{E}; ($part{D} = $part{d}) =~ s{/+$}{}; - @part{qw(t g s)} = @extra; + @part{qw(t g s o)} = @extra; my ($filename, $pos) = ('', 0); - while ($fmt =~ /(%([-+]?)(\d*)([.:]?)(\d*)([lu]?)([dDfFeEtgs]))/g) { + while ($fmt =~ /(%([-+]?)(\d*)([.:]?)(\d*)([lu]?)([dDfFeEtgso]))/g) { $filename .= substr($fmt, $pos, pos($fmt) - $pos - length($1)); $pos = pos($fmt); my ($sign, $wid, $dot, $skip, $mod, $code) = ($2, $3, $4, $5 || 0, $6, $7); @@ -3772,11 +4117,10 @@ sub Num2Alpha($) #------------------------------------------------------------------------------ # Expand '%c' and '%C' codes if filename to get next unused file name # Inputs: 0) file name format string, 1) filename ok to use even if it exists -# 2) dry run (won't really be renaming file) # Returns: new file name -sub NextUnusedFilename($;$$) +sub NextUnusedFilename($;$) { - my ($fmt, $okfile, $dryRun) = @_; + my ($fmt, $okfile) = @_; return $fmt unless $fmt =~ /%[-+]?\d*\.?\d*[lun]?[cC]/; my %sep = ( '-' => '-', '+' => '_' ); my ($copy, $alpha) = (0, 'a'); @@ -3787,24 +4131,24 @@ sub NextUnusedFilename($;$$) $filename .= substr($fmt, $pos, pos($fmt) - $pos - length($1)); $pos = pos($fmt); my ($sign, $wid, $dec, $wid2, $mod, $tok) = ($2, $3 || 0, $4, $5 || 0, $6, $7); - my $diff = 0; + my $diff; if ($tok eq 'C') { - $diff = $wid; + $diff = $wid - ($sign eq '-' ? $seqFileBase : 0); $wid = $wid2; } else { next unless $dec or $copy; $wid = $wid2 if $wid < $wid2; + # add dash or underline separator if '-' or '+' specified + $filename .= $sep{$sign} if $sign; } - # add dash or underline separator if '-' or '+' specified - $filename .= $sep{$sign} if $sign; if ($mod and $mod ne 'n') { - my $a = $tok eq 'C' ? Num2Alpha($diff + $seq++) : $alpha; + my $a = $tok eq 'C' ? Num2Alpha($diff + $seq) : $alpha; my $str = ($wid and $wid > length $a) ? 'a' x ($wid - length($a)) : ''; $str .= $a; $str = uc $str if $mod eq 'u'; $filename .= $str; } else { - my $c = $tok eq 'C' ? ($diff + $seq++) : $copy; + my $c = $tok eq 'C' ? ($diff + $seq) : $copy; my $num = $c + ($mod ? 1 : 0); $filename .= $wid ? sprintf("%.${wid}d",$num) : $num; } @@ -3819,6 +4163,7 @@ sub NextUnusedFilename($;$$) } ++$copy; ++$alpha; + ++$seq; } } @@ -3863,8 +4208,8 @@ sub CreateDirectory($) } $dir .= '/'; } + ++$countNewDir if $created; } - ++$countNewDir if $created; return $created; } @@ -3880,7 +4225,7 @@ sub OpenOutputFile($;@) if ($textOut) { $outfile = $file; CleanFilename($outfile); - if ($textOut =~ /%[-+]?\d*[.:]?\d*[lun]?[dDfFeEtgscC]/ or defined $tagOut) { + if ($textOut =~ /%[-+]?\d*[.:]?\d*[lun]?[dDfFeEtgsocC]/ or defined $tagOut) { # make filename from printf-like $textOut $outfile = FilenameSPrintf($textOut, $file, @args); return () unless defined $outfile; @@ -3975,7 +4320,10 @@ sub FilterArgfileLine($) # escaped by an odd number of backslashes, and escape a single backslash # if it occurs at the end of the string $arg =~ s{\\(.)|(["\$\@]|\\$)}{'\\'.($2 || $1)}sge; - $arg = eval qq{"$arg"}; # un-escape characters in C string + # un-escape characters in C string + my %esc = ( a => "\a", b => "\b", f => "\f", n => "\n", + r => "\r", t => "\t", '"' => '"', '\\' => '\\' ); + $arg =~ s/\\(.)/$esc{$1}||'\\'.$1/egs; } else { $arg =~ s/^\s+//; # remove leading white space $arg =~ s/[\x0d\x0a]+$//s; # remove trailing newline @@ -4051,6 +4399,29 @@ sub ReadStayOpen($) } } +#------------------------------------------------------------------------------ +# Add new entry to -efile output file +# Inputs: 0) file name, 1) -efile option number (0=error, 1=same, 2=failed) +sub EFile($$) +{ + my $entry = shift; + my $efile = $efile[shift || 0]; + if (defined $efile and length $entry and $entry ne '-') { + my $err; + CreateDirectory($efile); + if ($mt->Open(\*EFILE_FILE, $efile, '>>')) { + print EFILE_FILE $entry, "\n" or Warn("Error writing to $efile\n"), $err = 1; + close EFILE_FILE; + } else { + Warn("Error opening '${efile}' for append\n"); + $err = 1; + } + if ($err) { + defined $_ and $_ eq $efile and undef $_ foreach @efile; + } + } +} + #------------------------------------------------------------------------------ # Print list of tags # Inputs: 0) message, 1-N) list of tag names @@ -4065,18 +4436,18 @@ sub PrintTagList($@) } return; } - print ' '; - my $len = 1; + my ($len, $pad) = (0, $quiet ? '' : ' '); foreach $tag (@_) { my $taglen = length($tag); - if ($len + $taglen > 78) { - print "\n "; - $len = 1; + if ($len + $taglen > 77) { + print "\n"; + ($len, $pad) = (0, $quiet ? '' : ' '); } - print " $tag"; + print $pad, $tag; $len += $taglen + 1; + $pad = ' '; } - @_ or print ' [empty list]'; + @_ or print $pad, '[empty list]'; print "\n"; } @@ -4118,7 +4489,7 @@ B [I] -I[+-E]=[I]... I... =head2 Copying B [I] B<-tagsFromFile> I -[-I[EI]...] I... +[-[IE]I...] I... =head2 Other @@ -4150,52 +4521,56 @@ directory are processed (in write mode only writable types are processed). However, files may be specified by name, or the B<-ext> option may be used to force processing of files with any extension. Hidden files in the directory are also processed. Adding the B<-r> option causes subdirectories -to be processed recursively, but those with names beginning with "." are -skipped unless B<-r.> is used. +to be processed recursively, but subdirectories with names beginning with +"." are skipped unless B<-r.> is used. Below is a list of file types and meta information formats currently supported by ExifTool (r = read, w = write, c = create): File Types ------------+-------------+-------------+-------------+------------ - 3FR r | DR4 r/w/c | J2C r | ODP r | RAW r/w - 3G2 r/w | DSS r | JNG r/w | ODS r | RIFF r - 3GP r/w | DV r | JP2 r/w | ODT r | RSRC r - A r | DVB r/w | JPEG r/w | OFR r | RTF r - AA r | DVR-MS r | JSON r | OGG r | RW2 r/w - AAE r | DYLIB r | K25 r | OGV r | RWL r/w - AAX r/w | EIP r | KDC r | OPUS r | RWZ r - ACR r | EPS r/w | KEY r | ORF r/w | RM r - AFM r | EPUB r | LA r | OTF r | SEQ r - AI r/w | ERF r/w | LFP r | PAC r | SKETCH r - AIFF r | EXE r | LNK r | PAGES r | SO r - APE r | EXIF r/w/c | M2TS r | PBM r/w | SR2 r/w - ARQ r/w | EXR r | M4A/V r/w | PCD r | SRF r - ARW r/w | EXV r/w/c | MAX r | PDB r | SRW r/w - ASF r | F4A/V r/w | MEF r/w | PDF r/w | SVG r - AVI r | FFF r/w | MIE r/w/c | PEF r/w | SWF r - AZW r | FLA r | MIFF r | PFA r | THM r/w - BMP r | FLAC r | MKA r | PFB r | TIFF r/w - BPG r | FLIF r/w | MKS r | PFM r | TORRENT r - BTF r | FLV r | MKV r | PGF r | TTC r - CHM r | FPF r | MNG r/w | PGM r/w | TTF r - COS r | FPX r | MOBI r | PLIST r | VCF r - CR2 r/w | GIF r/w | MODD r | PICT r | VRD r/w/c - CR3 r/w | GPR r/w | MOI r | PMP r | VSD r - CRM r/w | GZ r | MOS r/w | PNG r/w | WAV r - CRW r/w | HDP r/w | MOV r/w | PPM r/w | WDP r/w - CS1 r/w | HDR r | MP3 r | PPT r | WEBP r - DCM r | HEIC r | MP4 r/w | PPTX r | WEBM r - DCP r/w | HEIF r | MPC r | PS r/w | WMA r - DCR r | HTML r | MPG r | PSB r/w | WMV r - DFONT r | ICC r/w/c | MPO r/w | PSD r/w | WTV r - DIVX r | ICS r | MQV r/w | PSP r | WV r - DJVU r | IDML r | MRW r/w | QTIF r/w | X3F r/w - DLL r | IIQ r/w | MXF r | R3D r | XCF r - DNG r/w | IND r/w | NEF r/w | RA r | XLS r - DOC r | INX r | NRW r/w | RAF r/w | XLSX r - DOCX r | ISO r | NUMBERS r | RAM r | XMP r/w/c - DPX r | ITC r | O r | RAR r | ZIP r + 360 r/w | DR4 r/w/c | JNG r/w | O r | RAW r/w + 3FR r | DSS r | JP2 r/w | ODP r | RIFF r + 3G2 r/w | DV r | JPEG r/w | ODS r | RSRC r + 3GP r/w | DVB r/w | JSON r | ODT r | RTF r + A r | DVR-MS r | JXL r | OFR r | RW2 r/w + AA r | DYLIB r | K25 r | OGG r | RWL r/w + AAE r | EIP r | KDC r | OGV r | RWZ r + AAX r/w | EPS r/w | KEY r | ONP r | RM r + ACR r | EPUB r | LA r | OPUS r | SEQ r + AFM r | ERF r/w | LFP r | ORF r/w | SKETCH r + AI r/w | EXE r | LIF r | ORI r/w | SO r + AIFF r | EXIF r/w/c | LNK r | OTF r | SR2 r/w + APE r | EXR r | LRV r/w | PAC r | SRF r + ARQ r/w | EXV r/w/c | M2TS r | PAGES r | SRW r/w + ARW r/w | F4A/V r/w | M4A/V r/w | PBM r/w | SVG r + ASF r | FFF r/w | MACOS r | PCD r | SWF r + AVI r | FITS r | MAX r | PCX r | THM r/w + AVIF r/w | FLA r | MEF r/w | PDB r | TIFF r/w + AZW r | FLAC r | MIE r/w/ | PDF r/w | TORRENT r + BMP r | FLIF r/w | MIFF r c | PEF r/w | TTC r + BPG r | FLV r | MKA r | PFA r | TTF r + BTF r | FPF r | MKS r | PFB r | TXT r + CHM r | FPX r | MKV r | PFM r | VCF r + COS r | GIF r/w | MNG r/w | PGF r | VRD r/w/c + CR2 r/w | GPR r/w | MOBI r | PGM r/w | VSD r + CR3 r/w | GZ r | MODD r | PLIST r | WAV r + CRM r/w | HDP r/w | MOI r | PICT r | WDP r/w + CRW r/w | HDR r | MOS r/w | PMP r | WEBP r + CS1 r/w | HEIC r/w | MOV r/w | PNG r/w | WEBM r + CSV r | HEIF r/w | MP3 r | PPM r/w | WMA r + CZI r | HTML r | MP4 r/w | PPT r | WMV r + DCM r | ICC r/w/c | MPC r | PPTX r | WTV r + DCP r/w | ICS r | MPG r | PS r/w | WV r + DCR r | IDML r | MPO r/w | PSB r/w | X3F r/w + DFONT r | IIQ r/w | MQV r/w | PSD r/w | XCF r + DIVX r | IND r/w | MRC r | PSP r | XLS r + DJVU r | INSP r/w | MRW r/w | QTIF r/w | XLSX r + DLL r | INSV r | MXF r | R3D r | XMP r/w/c + DNG r/w | INX r | NEF r/w | RA r | ZIP r + DOC r | ISO r | NKSC r/w | RAF r/w | + DOCX r | ITC r | NRW r/w | RAM r | + DPX r | J2C r | NUMBERS r | RAR r | Meta Information ----------------------+----------------------+--------------------- @@ -4226,7 +4601,7 @@ interpreted as tag names (for this reason, multiple single-character options may NOT be combined into one argument). Contrary to standard practice, options may appear after source file names on the exiftool command line. -=head2 Option Summary +=head2 Option Overview L @@ -4245,13 +4620,14 @@ L -c FMT (-coordFormat) Set format for GPS coordinates -charset [[TYPE=]CHARSET] Specify encoding for special characters -csv[[+]=CSVFILE] Export/import tags in CSV format + -csvDelim STR Set delimiter for CSV file -d FMT (-dateFormat) Set format for date/time values -D (-decimal) Show tag ID numbers in decimal - -E, -ex (-escape(HTML|XML)) Escape values for HTML (-E) or XML (-ex) + -E,-ex,-ec (-escape(HTML|XML|C))Escape tag values for HTML, XML or C -f (-forcePrint) Force printing of all specified tags -g[NUM...] (-groupHeadings) Organize output by tag group -G[NUM...] (-groupNames) Print group name for each tag - -h (-htmlFormat) Use HMTL formatting for output + -h (-htmlFormat) Use HTML formatting for output -H (-hex) Show tag ID numbers in hexadecimal -htmlDump[OFFSET] Generate HTML-format binary dump -j[[+]=JSONFILE] (-json) Export/import tags in JSON format @@ -4278,14 +4654,14 @@ L L -a (-duplicates) Allow duplicate tags to be extracted - -e (--composite) Do not calculate composite tags - -ee (-extractEmbedded) Extract information from embedded files + -e (--composite) Do not generate composite tags + -ee[NUM] (-extractEmbedded) Extract information from embedded files -ext[+] EXT (-extension) Process files with specified extension -F[OFFSET] (-fixBase) Fix the base for maker notes offsets - -fast[NUM] Increase speed for slow devices - -fileOrder [-]TAG Set file processing order + -fast[NUM] Increase speed when extracting metadata + -fileOrder[NUM] [-]TAG Set file processing order -i DIR (-ignore) Ignore specified directory name - -if EXPR Conditionally process files + -if[NUM] EXPR Conditionally process files -m (-ignoreMinorErrors) Ignore minor errors and warnings -o OUTFILE (-out) Set output file or directory name -overwrite_original Overwrite original by renaming tmp file @@ -4307,6 +4683,7 @@ L -k (-pause) Pause before terminating -list[w|f|wf|g[NUM]|d|x] List various exiftool capabilities -ver Print exiftool version number + -- End of options L @@ -4325,7 +4702,9 @@ L -common_args Define common arguments -config CFGFILE Specify configuration file name -echo[NUM] TEXT Echo text to stdout or stderr + -efile[NUM][!] ERRFILE Save names of files with errors -execute[NUM] Execute multiple commands on one line + -list_dir List directories, not their contents -srcfile FMT Process a different source file -stay_open FLAG Keep reading -@ argfile even after EOF -userParam PARAM[[^]=[VAL]] Set user parameter (API UserParam opt) @@ -4349,15 +4728,15 @@ C<-1IPTC:City>). Use the B<-listg> option to list available group names by family. A special tag name of C may be used to indicate all meta information -(ie. B<-All>). This is particularly useful when a group name is specified to -extract all information in a group (but beware that unless the B<-a> option -is also used, some tags in the group may be suppressed by same-named tags in -other groups). The wildcard characters C and C<*> may be used in a tag -name to match any single character and zero or more characters respectively. - These may not be used in a group name, with the exception that a group name -of C<*> (or C) may be used to extract all instances of a tag (as if -B<-a> was used). Note that arguments containing wildcards must be quoted on -the command line of most systems to prevent shell globbing. +(ie. B<-All>). This is particularly useful when a group name is specified +to extract all information in a group (but beware that unless the B<-a> +option is also used, some tags in the group may be suppressed by same-named +tags in other groups). The wildcard characters C and C<*> may be used in +a tag name to match any single character and zero or more characters +respectively. These may not be used in a group name, with the exception that +a group name of C<*> (or C) may be used to extract all instances of a +tag (as if B<-a> was used). Note that arguments containing wildcards must +be quoted on the command line of most systems to prevent shell globbing. A C<#> may be appended to the tag name to disable the print conversion on a per-tag basis (see the B<-n> option). This may also be used when writing or @@ -4383,6 +4762,14 @@ group delete (unless a family 2 group is specified, see note 4 below). Instead, individual tags may be recovered using the B<-tagsFromFile> option (eg. C<-all= -tagsfromfile @ -artist>). +To speed processing when reading XMP, exclusions in XMP groups also bypass +processing of the corresponding XMP property and any contained properties. +For example, C<--xmp-crs:all> may speed processing significantly in cases +where a large number of XMP-crs tags exist. To use this feature to bypass +processing of a specific XMP property, the property name must be used +instead of the ExifTool tag name (eg. C<--xmp-crs:dabs>). Also, C +may be used to to indicate any XMP namespace (eg. ). + =item B<->I[+-^]B<=>[I] Write a new value for the specified tag (eg. C<-comment=wow>), or delete the @@ -4393,17 +4780,18 @@ for more details). C<+=> may also be used to increment numerical values (or decrement if I is negative), and C<-=> may be used to conditionally delete or replace a tag (see L for examples). C<^=> is used to write an empty string instead of deleting the tag when no I -is given, but otherwise it is equivalent to C<=>. +is given, but otherwise it is equivalent to C<=>, but note that the caret +must be quoted on the Windows command line. -I may contain one or more leading family 0, 1 or 2 group names, +I may contain one or more leading family 0, 1, 2 or 7 group names, prefixed by optional family numbers, and separated colons. If no group name is specified, the tag is created in the preferred group, and updated in any other location where a same-named tag already exists. The preferred group -is the first group in the following list where I is valid: 1) EXIF, 2) -IPTC, 3) XMP. +in JPEG and TIFF-format images is the first group in the following list +where I is valid: 1) EXIF, 2) IPTC, 3) XMP. The wildcards C<*> and C may be used in tag names to assign the same -value to multiple tags. When specified with wildcards, "unsafe" tags are +value to multiple tags. When specified with wildcards, "Unsafe" tags are not written. A tag name of C is equivalent to C<*> (except that it doesn't require quoting, while arguments with wildcards do on systems with shell globbing), and is often used when deleting all metadata (ie. C<-All=>) @@ -4450,7 +4838,7 @@ the specified group(s) are removed individually, and in this case is it possible to exclude individual tags from a mass delete. For example, C<-time:all --Exif:Time:All> removes all deletable Time tags except those in the EXIF. This difference also applies if family 2 is specified when -deleting all groups. For example, C<-2all:all=> deletes tags individually, +deleting all groups. For example, C<-2all:all=> deletes tags individually, while C<-all:all=> deletes entire blocks. 5) The "APP" group names ("APP0" through "APP15") are used to delete JPEG @@ -4517,19 +4905,20 @@ with a different name or group. This is done using E'-IEI'E or E'-IEI'E on the command line after B<-tagsFromFile>, and causes the value of I to be copied from -I and written to I in I. Note that this argument -must be quoted to prevent shell redirection, and there is no C<=> sign as -when assigning new values. Source and/or destination tags may be prefixed -by a group name and/or suffixed by C<#>. Wildcards are allowed in both the -source and destination tag names. A destination group and/or tag name of -C or C<*> writes to the same family 1 group and/or tag name as the -source. If no destination group is specified, the information is written to -the preferred group. Whitespace around the C> or C> is ignored. -As a convenience, C<-tagsFromFile @> is assumed for any redirected tags -which are specified without a prior B<-tagsFromFile> option. Copied tags -may also be added or deleted from a list with arguments of the form +I and written to I in I. Has no effect unless +I exists in I. Note that this argument must be quoted to +prevent shell redirection, and there is no C<=> sign as when assigning new +values. Source and/or destination tags may be prefixed by a group name +and/or suffixed by C<#>. Wildcards are allowed in both the source and +destination tag names. A destination group and/or tag name of C or +C<*> writes to the same family 1 group and/or tag name as the source. If no +destination group is specified, the information is written to the preferred +group. Whitespace around the C> or C> is ignored. As a +convenience, C<-tagsFromFile @> is assumed for any redirected tags which are +specified without a prior B<-tagsFromFile> option. Copied tags may also be +added or deleted from a list with arguments of the form E'-I+EI'E or -E'-I-EI'E. +E'-I-EI'E (but see Note 5 below). An extension of the redirection feature allows strings involving tag names to be used on the right hand side of the C> symbol with the syntax @@ -4548,10 +4937,10 @@ See L for examples using B<-tagsFromFile>. Notes: 1) Some tags (generally tags which may affect the appearance of the image) -are considered "unsafe" to write, and are only copied if specified +are considered "Unsafe" to write, and are only copied if specified explicitly (ie. no wildcards). See the L for more details about -"unsafe" tags. +"Unsafe" tags. 2) Be aware of the difference between excluding a tag from being copied (--I), and deleting a tag (-I=). Excluding a tag prevents it from @@ -4592,7 +4981,8 @@ Other than these differences, the B<-tagsFromFile> and B<-addTagsFromFile> options are equivalent. 6) The B<-a> option (allow duplicate tags) is always in effect when copying -tags from I. +tags from I, but the highest priority tag is always copied last so +it takes precedence. 7) Structured tags are copied by default when copying tags. See the B<-struct> option for details. @@ -4600,13 +4990,27 @@ B<-struct> option for details. 8) With the redirection feature, copying a tag directly (ie. E'-IEI'E) is not the same as interpolating its value inside a string (ie. E'-IE$I'E) -for list-type tags, L, or tag -names containing wildcards. When copying directly, the values of each -matching source tag are copied individually to the destination tag (as if -they were separate assignments). However, when interpolated inside a -string, list items and the values of shortcut tags are concatenated (with a -separator set by the B<-sep> option), and wildcards are not allowed. Also, -UserParam variables are available only when interpolated in a string. +for source tags which are list-type tags, +L, tag names containing wildcards, +or UserParam variables. When copying directly, the values of each matching +source tag are copied individually to the destination tag (as if they were +separate assignments). However, when interpolated inside a string, list +items and the values of shortcut tags are concatenated (with a separator set +by the B<-sep> option), and wildcards are not allowed. Also, UserParam +variables are available only when interpolated in a string. Another +difference is that a minor warning is generated if a tag doesn't exist when +interpolating its value in a string (with C<$>), but isn't when copying the +tag directly. + +Finally, the behaviour is different when a destination tag or group of +C is used. When copying directly, a destination group and/or tag name +of C writes to the same family 1 group and/or tag name as the source. +But when interpolated in a string, the identity of the source tags are lost +and the value is written to all possible groups/tags. For example, the +string form must be used in the following command since the intent is to set +the value of all existing date/time tags from C: + + exiftool '-time:all<$createdate' -wm w FILE =item B<-x> I (B<-exclude>) @@ -4619,7 +5023,7 @@ documentation above for a complete description. =head3 Input-output text formatting Note that trailing spaces are removed from extracted values for most output -text formats. The exceptions are C<-b>, C<-csv>, C<-j> and C<-X>. +text formats. The exceptions are B<-b>, B<-csv>, B<-j> and B<-X>. =over 5 @@ -4632,10 +5036,10 @@ between images, but allows the metadata to be altered by editing the intermediate file (C in this example): exiftool -args -G1 --filename --directory src.jpg > out.args - exiftool -@ out.args -sep ", " dst.jpg + exiftool -@ out.args -sep ', ' dst.jpg Note: Be careful when copying information with this technique since it is -easy to write tags which are normally considered "unsafe". For instance, +easy to write tags which are normally considered "Unsafe". For instance, the FileName and Directory tags are excluded in the example above to avoid renaming and moving the destination file. Also note that the second command above will produce warning messages for any tags which are not writable. @@ -4645,17 +5049,21 @@ maintain separate list items when writing metadata back to image files, and the B<-struct> option may be used when extracting to preserve structured XMP information. -=item B<-b> (B<-binary>) +=item B<-b>, B<--b> (B<-binary>, B<--binary>) + +Output requested metadata in binary format without tag names or descriptions +(B<-b> or B<-binary>). This option is mainly used for extracting embedded +images or other binary data, but it may also be useful for some text strings +since control characters (such as newlines) are not replaced by '.' as they +are in the default output. By default, list items are separated by a +newline when extracted with the B<-b> option, but this may be changed (see +the B<-sep> option for details). May be combined with B<-j>, B<-php> or +B<-X> to extract binary data in JSON, PHP or XML format, but note that +"Unsafe" tags are not extracted as binary unless they are specified explicitly or +the API RequestAll option is set to 3 or higher. -Output requested metadata in binary format without tag names or -descriptions. This option is mainly used for extracting embedded images or -other binary data, but it may also be useful for some text strings since -control characters (such as newlines) are not replaced by '.' as they are in -the default output. By default, list items are separated by a newline when -extracted with the B<-b> option, but this may be changed (see the B<-sep> -option for details). May be combined with C<-j>, C<-php> or C<-X> to -extract binary data in JSON, PHP or XML format, but note that "unsafe" tags -must be specified explicitly to be extracted as binary in these formats. +With a leading double dash (B<--b> or B<--binary>), tags which contain +binary data are suppressed in the output when reading. =item B<-c> I (B<-coordFormat>) @@ -4688,9 +5096,8 @@ coordinates as signed decimal degrees. If I is C or not specified, this option sets the ExifTool character encoding for output tag values when reading and input values when -writing. The default ExifTool encoding is C. If no I is -given, a list of available character sets is returned. Valid I -values are: +writing, with a default of C. If no I is given, a list of +available character sets is returned. Valid I values are: CHARSET Alias(es) Description ---------- --------------- ---------------------------------- @@ -4707,6 +5114,7 @@ values are: Thai cp874 Windows Thai DOSLatinUS cp437 DOS Latin US DOSLatin1 cp850 DOS Latin1 + DOSCyrillic cp866 DOS Cyrillic MacRoman cp10000, Roman Macintosh Roman MacLatin2 cp10029 Macintosh Latin2 (Central Europe) MacCyrillic cp10007 Macintosh Cyrillic @@ -4734,10 +5142,9 @@ encoding of various meta information formats. QuickTime Internal encoding of QuickTime strings MacRoman RIFF Internal encoding of RIFF strings 0 -See L for more -information about coded character sets, and the -L for more details about -the B<-charset> settings. +See L for more information about coded +character sets, and the L +for more details about the B<-charset> settings. =item B<-csv>[[+]=I] @@ -4748,8 +5155,11 @@ tag names (with optional group names) for each column of the file, and values must be separated by commas. A special "SourceFile" column specifies the files associated with each row of information (and a SourceFile of "*" may be used to define default tags to be imported for all files which are -combined with any tags specified for the specific SourceFile processed). -The following examples demonstrate basic use of this option: +combined with any tags specified for the specific SourceFile processed). The +B<-csvDelim> option may be used to change the input/output field delimiter +if something other than a comma is required. + +The following examples demonstrate basic use of the B<-csv> option: # generate CSV file with common tags from all images in a directory exiftool -common -csv dir > out.csv @@ -4757,22 +5167,27 @@ The following examples demonstrate basic use of this option: # update metadata for all images in a directory from CSV file exiftool -csv=a.csv dir -Empty values are ignored when importing (unless the B<-f> option is used and -the API MissingTagValue is set to an empty string, in which case the tag is +When importing, empty values are ignored unless the B<-f> option is used and +the API MissingTagValue is set to an empty string (in which case the tag is deleted). Also, FileName and Directory columns are ignored if they exist -(ie. ExifTool will not attempt to write these tags with a CSV import). To -force a tag to be deleted, use the B<-f> option and set the value to "-" in -the CSV file (or to the MissingTagValue if this API option was used). -Multiple databases may be imported in a single command. +(ie. ExifTool will not attempt to write these tags with a CSV import), but +all other columns are imported. To force a tag to be deleted, use the B<-f> +option and set the value to "-" in the CSV file (or to the MissingTagValue +if this API option was used). Multiple databases may be imported in a +single command. When exporting a CSV file, the B<-g> or B<-G> option adds group names to the tag headings. If the B<-a> option is used to allow duplicate tag names, the duplicate tags are only included in the CSV output if the column headings are unique. Adding the B<-G4> option ensures a unique column heading for -each tag. When exporting specific tags, the CSV columns are arranged in the -same order as the specified tags provided the column headings exactly match -the specified tag names, otherwise the columns are sorted in alphabetical -order. +each tag. The B<-b> option may be added to output binary data, encoded in +base64 if necessary (indicated by ASCII "base64:" as the first 7 bytes of +the value). Values may also be encoded in base64 if the B<-charset> option +is used and the value contains invalid characters. + +When exporting specific tags, the CSV columns are arranged in the same order +as the specified tags provided the column headings exactly match the +specified tag names, otherwise the columns are sorted in alphabetical order. When importing from a CSV file, only files specified on the command line are processed. Any extra entries in the CSV file are ignored. @@ -4788,7 +5203,16 @@ format options because it requires information from all input files to be buffered in memory before the output is written. This may result in excessive memory usage when processing a very large number of files with a single command. Also, it makes this option incompatible with the B<-w> -option. +option. When processing a large number of files, it is recommended to +either use the JSON (B<-j>) or XML (B<-X>) output format, or use B<-p> to +generate a fixed-column CSV file instead of using the B<-csv> option. + +=item B<-csvDelim> I + +Set the delimiter for separating CSV entries for CSV file input/output via +the B<-csv> option. I may contain "\t", "\n", "\r" and "\\" to +represent TAB, LF, CR and '\' respectively. A double quote is not allowed +in the delimiter. Default is ','. =item B<-d> I (B<-dateFormat>) @@ -4798,22 +5222,25 @@ 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. Only one B<-d> option may be used per command. -Requires POSIX::strptime or Time::Piece for the inversion conversion when -writing. +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>). Only one B<-d> option may be used per command. Requires +POSIX::strptime or Time::Piece for the inversion conversion when writing. =item B<-D> (B<-decimal>) Show tag ID number in decimal when extracting information. -=item B<-E>, B<-ex> (B<-escapeHTML>, B<-escapeXML>) +=item B<-E>, B<-ex>, B<-ec> (B<-escapeHTML>, B<-escapeXML>, B<-escapeC>) -Escape characters in output values for HTML (B<-E>) or XML (B<-ex>). For -HTML, all characters with Unicode code points above U+007F are escaped as -well as the following 5 characters: & (&) E<39> (') E (") -E (>) and E (<). For XML, only these 5 characters are -escaped. The B<-E> option is implied with B<-h>, and B<-ex> is implied with -B<-X>. The inverse conversion is applied when writing tags. +Escape characters in output tag values for HTML (B<-E>), XML (B<-ex>) or C +(B<-ec>). For HTML, all characters with Unicode code points above U+007F +are escaped as well as the following 5 characters: & (&) E<39> (') +E (") E (>) and E (<). For XML, only these 5 +characters are escaped. The B<-E> option is implied with B<-h>, and B<-ex> +is implied with B<-X>. For C, all control characters and the backslash are +escaped. The inverse conversion is applied when writing tags. =item B<-f> (B<-forcePrint>) @@ -4829,14 +5256,17 @@ B<-csv>=I feature. Organize output by tag group. I specifies a group family number, and may be 0 (general location), 1 (specific location), 2 (category), 3 -(document number) or 4 (instance number). B<-g0> is assumed if a family -number is not specified, and family numbers may be added wherever B<-g> is -mentioned in the documentation. Multiple families may be specified by -separating them with colons. By default the resulting group name is -simplified by removing any leading C and collapsing adjacent -identical group names, but this can be avoided by placing a colon before the -first family number (eg. B<-g:3:1>). Use the B<-listg> option to list group -names for a specified family. +(document number), 4 (instance number), 5 (metadata path), 6 (EXIF/TIFF +format) or 7 (tag ID). B<-g0> is assumed if a family number is not +specified. May be combined with other options to add group names to the +output. Multiple families may be specified by separating them with colons. +By default the resulting group name is simplified by removing any leading +C and collapsing adjacent identical group names, but this can be +avoided by placing a colon before the first family number (eg. B<-g:3:1>). +Use the B<-listg> option to list group names for a specified family. The +API SavePath and SaveFormat options are automatically enabled if the +respective family 5 or 6 group names are requested. See the +L for more information. =item B<-G>[I][:I...] (B<-groupNames>) @@ -4877,18 +5307,20 @@ JSON arrays unless B<-sep> is used. By default XMP structures are flattened into individual tags in the JSON output, but the original structure may be preserved with the B<-struct> option (this also causes all list-type XMP tags to be output as JSON arrays, otherwise single-item lists would be -output as simple strings). The B<-a> option is implied if the B<-g> or -B<-G> options are used, otherwise it is ignored and tags with identical -JSON names are suppressed. (B<-g4> may be used to ensure that all tags have -unique JSON names.) Adding the B<-D> or B<-H> option changes tag values to -JSON objects with "val" and "id" fields, and adding B<-l> adds a "desc" -field, and a "num" field if the numerical value is different from the -converted "val". The B<-b> option may be added to output binary data, -encoded in base64 if necessary (indicated by "base64:" as the first 7 bytes -of the value), and B<-t> may be added to include tag table information (see -B<-t> for details). The JSON output is UTF-8 regardless of any B<-L> or -B<-charset> option setting, but the UTF-8 validation is disabled if a -character set other than UTF-8 is specified. +output as simple strings). The B<-a> option is implied when B<-json> is +used, but entries with identical JSON names are suppressed in the output. +(B<-G4> may be used to ensure that all tags have unique JSON names.) Adding +the B<-D> or B<-H> option changes tag values to JSON objects with "val" and +"id" fields, and adding B<-l> adds a "desc" field, and a "num" field if the +numerical value is different from the converted "val". The B<-b> option may +be added to output binary data, encoded in base64 if necessary (indicated by +ASCII "base64:" as the first 7 bytes of the value), and B<-t> may be added +to include tag table information (see B<-t> for details). The JSON output +is UTF-8 regardless of any B<-L> or B<-charset> option setting, but the +UTF-8 validation is disabled if a character set other than UTF-8 is +specified. Note that ExifTool quotes JSON values only if they don't look +like numbers (regardless of the original storage format or the relevant +metadata specification). If I is specified, the file is imported and the tag definitions from the file are used to set tag values on a per-file basis. The special @@ -4932,18 +5364,42 @@ been implemented. May also be combined with B<-listx> to output descriptions in one language only. By default, ExifTool uses UTF-8 encoding for special characters, but the -the B<-L> or B<-charset> option may be used to invoke other encodings. +B<-L> or B<-charset> option may be used to invoke other encodings. Note +that ExifTool uses Unicode::LineBreak if available to help preserve the +column alignment of the plain text output for languages with a +variable-width character set. Currently, the language support is not complete, but users are welcome to -help improve this by submitting their own translations. To submit a set of -translations, first use the B<-listx> option and redirect the output to a -file to generate an XML tag database, then add entries for other languages, -zip this file, and email it to phil at owl.phy.queensu.ca for inclusion in -ExifTool. +help improve this by submitting their own translations. To submit a +translation, follow these steps (you must have Perl installed for this): -Note: ExifTool uses Unicode::LineBreak if available to help preserve the -column alignment of the plain text output for languages with a -variable-width character set. +1. Download and unpack the latest Image-ExifTool full distribution. + +2. 'cd' into the Image-ExifTool directory. + +3. Run this command to make an XML file of the desired tags (eg. EXIF): + + ./exiftool -listx -exif:all > out.xml + +4. Copy this text into a file called 'import.pl' in the exiftool directory: + + push @INC, 'lib'; + require Image::ExifTool::TagInfoXML; + my $file = shift or die "Expected XML file name\n"; + $Image::ExifTool::TagInfoXML::makeMissing = shift; + Image::ExifTool::TagInfoXML::BuildLangModules($file,8); + +5. Run the 'import.pl' script to Import the XML file, generating the +'MISSING' entries for your language (eg. Russian): + + perl import.pl out.xml ru + +6. Edit the generated language module lib/Image/ExifTool/Lang/ru.pm, and +search and replace all 'MISSING' strings in the file with your translations. + +7. Email the module ('ru.pm' in this example) to philharvey66 at gmail.com + +8. Thank you!! =item B<-listItem> I @@ -4983,22 +5439,24 @@ when writing. For example, the following commands all have the same effect: Print output in the format specified by the given file or string. The argument is interpreted as a string unless a file of that name exists, in which case the string is loaded from the contents of the file. Tag names in -the format file or string begin with a C<$> symbol and may contain a leading -group names and/or a trailing C<#>. Case is not significant. Braces C<{}> -may be used around the tag name to separate it from subsequent text. Use -C<$$> to represent a C<$> symbol, and C<$/> for a newline. +the format file or string begin with a C<$> symbol and may contain leading +group names and/or a trailing C<#> (to disable print conversion). Case is +not significant. Braces C<{}> may be used around the tag name to separate +it from subsequent text. Use C<$$> to represent a C<$> symbol, and C<$/> +for a newline. Multiple B<-p> options may be used, each contributing a line (or more) of text to the output. Lines beginning with C<#[HEAD]> and C<#[TAIL]> are output before the first processed file and after the last processed file respectively. Lines beginning with C<#[SECT]> and C<#[ENDS]> are output -around each section of files. A section is defined as a group of +before and after each section of files. A section is defined as a group of consecutive files with the same section header (eg. files are grouped by directory if C<#[SECT]> contains C<$directory>). Lines beginning with C<#[BODY]> and lines not beginning with C<#> are output for each processed file. Lines beginning with C<#[IF]> are not output, but all BODY lines are skipped if any tag on an IF line doesn't exist. Other lines beginning with -C<#> are ignored. For example, this format file: +C<#> are ignored. (To output a line beginning with C<#>, use C<#[BODY]#>.) +For example, this format file: # this is a comment line #[HEAD]-- Generated by ExifTool $exifToolVersion -- @@ -5012,7 +5470,7 @@ with this command: produces output like this: - -- Generated by ExifTool 11.16 -- + -- Generated by ExifTool 12.45 -- 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 @@ -5020,8 +5478,8 @@ produces output like this: -- end -- The values of List-type tags with multiple items and Shortcut tags -representing multiple tags are joined according the the B<-sep> option -setting when interpolated in the string. +representing multiple tags are joined according the B<-sep> option setting +when interpolated in the string. When B<-ee> (B<-extractEmbedded>) is combined with B<-p>, embedded documents are effectively processed as separate input files. @@ -5029,8 +5487,9 @@ are effectively processed as separate input files. If a specified tag does not exist, a minor warning is issued and the line with the missing tag is not printed. However, the B<-f> option may be used to set the value of missing tags to '-' (but this may be configured via the -MissingTagValue API option), or the B<-m> option may be used to ignore minor -warnings and leave the missing values empty. +API MissingTagValue option), or the B<-m> option may be used to ignore minor +warnings and leave the missing values empty. Alternatively, B<-q -q> may be +used to simply suppress the warning messages. The L may be used to modify the values of individual tags with the B<-p> option. @@ -5079,10 +5538,10 @@ separator when reading, or split the value into individual characters when writing. For pure binary output (B<-b> used without B<-j>, B<-php> or B<-X>), the -first B<-sep> option specifies a list-item separator, and subsequent B<-sep> -options specify a terminator added to the end of the list (or after each -value if not a list). In these strings, C<\n>, C<\r> and C<\t> may be used -to represent a newline, carriage return and tab respectively. By default, +first B<-sep> option specifies a list-item separator, and a second B<-sep> +option specifies a terminator for the end of the list (or after each value +if not a list). In these strings, C<\n>, C<\r> and C<\t> may be used to +represent a newline, carriage return and tab respectively. By default, binary list items are separated by a newline, and no terminator is added. =item B<-sort>, B<--sort> @@ -5101,12 +5560,12 @@ Output structured XMP information instead of flattening to individual tags. This option works well when combined with the XML (B<-X>) and JSON (B<-j>) output formats. For other output formats, XMP structures and lists are serialized into the same format as when writing structured information (see -L for details). When -copying, structured tags are copied by default unless B<--struct> is used to -disable this feature (although flattened tags may still be copied by -specifying them individually unless B<-struct> is used). These options have -no effect when assigning new values since both flattened and structured tags -may always be used when writing. +L for details). When copying, structured +tags are copied by default unless B<--struct> is used to disable this +feature (although flattened tags may still be copied by specifying them +individually unless B<-struct> is used). These options have no effect when +assigning new values since both flattened and structured tags may always be +used when writing. =item B<-t> (B<-tab>) @@ -5130,7 +5589,9 @@ level greater than 0, most other options are ignored and normal console output is suppressed unless specific tags are extracted. Using B<-v0> causes the console output buffer to be flushed after each line (which may be useful to avoid delays when piping exiftool output), and prints the name of -each processed file when writing. Also see the B<-progress> option. +each processed file when writing and the new file name when renaming, +moving or copying. Verbose levels above B<-v0> do not flush after each +line. Also see the B<-progress> option. =item B<-w>[+|!] I or I (B<-textOut>) @@ -5171,18 +5632,18 @@ Notes: argument like C<%d%f.txt> is written as C<%%d%%f.txt>. 2) If the argument for B<-w> does not contain a valid format code (eg. %f), -then it is interpreted as a file extension. It is not possible to specify a -simple filename as an argument -- creating a single output file from -multiple source files is typically done by shell redirection, ie) +then it is interpreted as a file extension, but there are three different +ways to create a single output file from multiple source files: + # 1. Shell redirection exiftool FILE1 FILE2 ... > out.txt -But if necessary, an empty format code may be used to force the argument to -be interpreted as a format string, and the same result may be obtained -without the use of shell redirection: - + # 2. With the -w option and a zero-width format code exiftool -w+! %0fout.txt FILE1 FILE2 ... + # 3. With the -W option (see the -W option below) + exiftool -W+! out.txt FILE1 FILE2 ... + Advanced features: A substring of the original file name, directory or extension may be taken @@ -5237,10 +5698,11 @@ A special feature allows the copy number to be incremented for each processed file by using %C (upper case) instead of %c. This allows a sequential number to be added to output file names, even if the names are different. For %C, a copy number of zero is not omitted as it is with %c. -The number before the decimal place gives the starting index, the number -after the decimal place gives the field width. The following examples show -the output filenames when used with the command -C: +A leading '-' causes the number to be reset at the start of each new +directory, and '+' has no effect. The number before the decimal place gives +the starting index, the number after the decimal place gives the field +width. The following examples show the output filenames when used with the +command C: -w %C%f.txt # 0rose.txt, 1star.txt, 2jet.txt -w %f-%10C.txt # rose-10.txt, star-11.txt, jet-12.txt @@ -5265,12 +5727,14 @@ between B<-W> and B<-w>: 1) With B<-W>, a new output file is created for each extracted tag. -2) B<-W> supports three additional format codes: %t, %g and %s represent -the tag name, group name, and suggested extension for the output file (based -on the format of the data). The %g code may be followed by a single digit -to specify the group family number (eg. %g1), otherwise family 0 is assumed. -The substring width/position/case specifiers may be used with these format -codes in exactly the same way as with %f and %e. +2) B<-W> supports four additional format codes: %t, %g and %s represent the +tag name, group name, and suggested extension for the output file (based on +the format of the data), and %o represents the value of the +OriginalRawFileName or OriginalFileName tag from the input file (including +extension). The %g code may be followed by a single digit to specify the +group family number (eg. %g1), otherwise family 0 is assumed. The substring +width/position/case specifiers may be used with these format codes in +exactly the same way as with %f and %e. 3) The argument for B<-W> is interpreted as a file name if it contains no format codes. (For B<-w>, this would be a file extension.) This change @@ -5287,10 +5751,10 @@ example, the following pairs of commands give the same result: exiftool test.jpg >> out.txt # shell redirection exiftool test.jpg -W+ out.txt # equivalent -W option -4) Adding the B<-v> option to B<-W> generates a list of the tags and output -file names instead of giving a verbose dump of the entire file. (Unless -appending all output to one file for each source file by using B<-W+> with -an output file I that does not contain %t, $g or %s.) +4) Adding the B<-v> option to B<-W> sends a list of the tags and output file +names to the console instead of giving a verbose dump of the entire file. +(Unless appending all output to one file for each source file by using +B<-W+> with an output file I that does not contain %t, %g, %s or %o.) 5) Individual list items are stored in separate files when B<-W> is combined with B<-b>, but note that for separate files to be created %c or %C must be @@ -5326,9 +5790,10 @@ The B<-t> option adds tag table information to the output (see B<-t> for details). Note: This output is NOT the same as XMP because it uses -dynamically-generated property names corresponding to the ExifTool tag -names, and not the standard XMP properties. To write XMP instead, use the -B<-o> option with an XMP extension for the output file. +dynamically-generated property names corresponding to the ExifTool tag names +with ExifTool family 1 group names as namespaces, and not the standard XMP +properties and namespaces. To write XMP instead, use the B<-o> option with +an XMP extension for the output file. =back @@ -5339,16 +5804,16 @@ B<-o> option with an XMP extension for the output file. =item B<-a>, B<--a> (B<-duplicates>, B<--duplicates>) Allow (B<-a>) or suppress (B<--a>) duplicate tag names to be extracted. By -default, duplicate tags are suppressed unless the B<-ee> or B<-X> options -are used or the Duplicates option is enabled in the configuration file. -This option also has an affect when writing to allow duplicate Warning -messages to be shown. +default, duplicate tags are suppressed when reading unless the B<-ee> or B<-X> +options are used or the Duplicates option is enabled in the configuration file. +When writing, this option allows multiple Warning messages to be shown. +Duplicate tags are always extracted when copying. =item B<-e> (B<--composite>) -Extract existing tags only -- don't calculate composite tags. +Extract existing tags only -- don't generate composite tags. -=item B<-ee> (B<-extractEmbedded>) +=item B<-ee>[I] (B<-extractEmbedded>) Extract information from embedded documents in EPS files, embedded EPS information and JPEG and Jpeg2000 images in PDF files, embedded MPF images @@ -5358,13 +5823,19 @@ identify the originating document for extracted information. Embedded documents containing sub-documents are indicated with dashes in the family 3 group name. (eg. C is the 3rd sub-document of the 2nd embedded document.) Note that this option may increase processing time substantially, -especially for PDF files with many embedded images. +especially for PDF files with many embedded images or videos with streaming +metadata. When used with B<-ee>, the B<-p> option is evaluated for each embedded document as if it were a separate input file. This allows, for example, generation of GPS track logs from timed metadata in videos. See -L for -examples. +L for examples. + +Setting I to 2 causes the H264 video stream in MP4 videos to be parsed +until the first Supplemental Enhancement Information (SEI) message is +decoded, or 3 to parse the entire H624 stream and decode all SEI +information. For M2TS videos, a setting of 3 causes the entire file to be +parsed in search of unlisted programs which may contain timed GPS. =item B<-ext>[+] I, B<--ext> I (B<-extension>) @@ -5406,32 +5877,46 @@ permanently if B<-F> is used when writing EXIF to an image. eg) =item B<-fast>[I] -Increase speed of extracting information. With this option, ExifTool will -not scan to the end of a JPEG image to check for an AFCP or PreviewImage -trailer, or past the first comment in GIF images or the audio/video data in -WAV/AVI files to search for additional metadata. These speed benefits are -small when reading images directly from disk, but can be substantial if -piping images through a network connection. For more substantial speed -benefits, B<-fast2> also causes exiftool to avoid extracting any EXIF -MakerNote information. B<-fast3> avoids processing the file entirely, and -returns only an initial guess at FileType and the pseudo System tags. Has -no effect when writing. - -=item B<-fileOrder> [-]I +Increase speed of extracting information. With B<-fast> (or B<-fast1>), +ExifTool will not scan to the end of a JPEG image to check for an AFCP or +PreviewImage trailer, or past the first comment in GIF images or the +audio/video data in WAV/AVI files to search for additional metadata. These +speed benefits are small when reading images directly from disk, but can be +substantial if piping images through a network connection. For more +substantial speed benefits, B<-fast2> also causes exiftool to avoid +extracting any EXIF MakerNote information. B<-fast3> avoids extracting +metadata from the file, and returns only pseudo System tags, but still reads +the file header to obtain an educated guess at FileType. B<-fast4> doesn't +even read the file header, and returns only System tags and a FileType based +on the file extension. B<-fast5> also disables generation of the Composite +tags (like B<-e>). Has no effect when writing. + +Note that a separate B<-fast> setting may be used for evaluation of a B<-if> +condition, or when ordering files with the B<-fileOrder> option. See the +B<-if> and B<-fileOrder> options for details. + +=item B<-fileOrder>[I] [-]I Set file processing order according to the sorted value of the specified I. For example, to process files in order of date: exiftool -fileOrder DateTimeOriginal DIR -Additional B<-fileOrder> options may be added for secondary sort keys. +Additional B<-fileOrder> options may be added for secondary sort keys. Numbers are sorted numerically, and all other values are sorted -alphabetically. The sort order may be reversed by prefixing the tag name -with a C<-> (eg. C<-fileOrder -createdate>). Print conversion of the sorted -values is disabled with the B<-n> option, or a C<#> appended to the tag -name. Other formatting options (eg. B<-d>) have no effect on the sorted -values. Note that the B<-fileOrder> option has a large performance impact -since it involves an additional processing pass of each file. +alphabetically. Files missing the specified tag are sorted last. The sort +order may be reversed by prefixing the tag name with a C<-> (eg. +C<-fileOrder -createdate>). Print conversion of the sorted values is +disabled with the B<-n> option, or a C<#> appended to the tag name. Other +formatting options (eg. B<-d>) have no effect on the sorted values. Note +that the B<-fileOrder> option can have a large performance impact since it +involves an additional processing pass of each file, but this impact may be +reduced by specifying a I for the B<-fast> level used during the +metadata-extraction phase. For example, B<-fileOrder4> may be used if +I is a pseudo System tag. If multiple B<-fileOrder> options are used, +the extraction is done at the lowest B<-fast> level. Note that files are +sorted across directory boundaries if multiple input directories are +specified. =item B<-i> I (B<-ignore>) @@ -5439,10 +5924,12 @@ Ignore specified directory name. I may be either an individual folder name, or a full path. If a full path is specified, it must match the Directory tag exactly to be ignored. Use multiple B<-i> options to ignore more than one directory name. A special I value of C (case -sensitive) may be specified to ignore symbolic links when the B<-r> option -is used. +sensitive) may be specified to avoid recursing into directories which are +symbolic links when the B<-r> option is used. As well, a value of C +(case sensitive) may be used to ignore files with names that start with a +"." (ie. hidden files on Unix systems) when scanning a directory. -=item B<-if> I +=item B<-if>[I] I Specify a condition to be evaluated before processing each I. I is a Perl-like logic expression containing tag names prefixed by C<$> @@ -5468,6 +5955,22 @@ conditions must be satisfied to process the file. Returns an exit status of # find images containing a specific keyword (case insensitive) exiftool -if '$keywords =~ /harvey/i' -filename dir +Adding I to the B<-if> option causes a separate processing pass to be +executed for evaluating I at a B<-fast> level given by I (see the +B<-fast> option documentation for details). Without I, only one +processing pass is done at the level specified by the B<-fast> option. For +example, using B<-if5> is possible if I uses only pseudo System tags, +and may significantly speed processing if enough files fail the condition. + +The expression has access to the current ExifTool object through C<$self>, +and the following special functions are available to allow short-circuiting +of the file processing. Both functions have a return value of 1. Case is +significant for function names. + + End() - end processing after this file + EndDir() - end processing of files in this directory (not + compatible with the B<-fileOrder> option) + Notes: 1) The B<-n> and B<-b> options also apply to tags used in I. @@ -5478,10 +5981,11 @@ also specified on the command line. The alternative is to use the C<$GROUP:all> syntax. (eg. Use C<$exif:all> instead of C<$exif> in I to test for the existence of EXIF tags.) -3) Tags in the string are interpolated the same way as with B<-p> before the +3) Tags in the string are interpolated in a similar way to B<-p> before the expression is evaluated. In this interpolation, C<$/> is converted to a -newline and C<$$> represents a single C<$> symbol (so Perl variables, if -used, require a double C<$>). +newline and C<$$> represents a single C<$> symbol. So Perl variables, if +used, require a double C<$>, and regular expressions ending in C<$/> must +use C<$$/> instead. 4) The condition may only test tags from the file being processed. To process one file based on tags from another, two steps are required. For @@ -5569,16 +6073,19 @@ of a temporary file before deleting the temporary. The extra step results in slower performance, so the B<-overwrite_original> option should be used instead unless necessary. +Note that this option reverts to the behaviour of the B<-overwrite_original> +option when also writing the FileName and/or Directory tags. + =item B<-P> (B<-preserve>) Preserve the filesystem modification date/time (C) of the original file when writing. Note that some filesystems store a creation -date (Windows C or Mac C) -which is not affected by this option. The creation date is preserved on -Windows systems where Win32API::File and Win32::API are available regardless -of this setting. For other systems, the B<-overwrite_original_in_place> -option may be used if necessary to preserve the creation date. This option -is superseded by any value written to the FileModifyDate tag. +date (ie. C on Windows and Mac systems) which is not +affected by this option. This creation date is preserved on Windows systems +where Win32API::File and Win32::API are available regardless of this +setting. For other systems, the B<-overwrite_original_in_place> option may +be used if necessary to preserve the creation date. The B<-P> option is +superseded by any value written to the FileModifyDate tag. =item B<-password> I @@ -5668,7 +6175,7 @@ available). When writing, causes compressed information to be written if supported by the metadata format (eg. compressed textual metadata in PNG), disables the recommended padding in embedded XMP (saving 2424 bytes when writing XMP in a file), and writes XMP in shorthand format -- the equivalent -of setting the API Compress, Compact and XMPShorthand options to 1. +of setting the API Compress=1 and Compact="NoPadding,Shorthand". =back @@ -5757,6 +6264,11 @@ addition system information (see the README file of the full distribution for more details about optional libraries), or B<-v2> to also list the Perl include directories. +=item B<--> + +Indicates the end of options. Any remaining arguments are treated as file +names, even if they begin with a dash (C<->). + =back =head3 Special features @@ -5766,12 +6278,12 @@ include directories. =item B<-geotag> I Geotag images from the specified GPS track log file. Using the B<-geotag> -option is equivalent to writing a value to the C tag. After the -B<-geotag> option has been specified, the value of the C tag is -written to define a date/time for the position interpolation. If C -is not specified, the value is copied from C (the C<#> is -added to copy the unformatted value, avoiding potential conflicts with the -B<-d> option). For example, the following two commands are equivalent: +option is equivalent to writing a value to the C tag. The GPS +position is interpolated from the track at a time specified by the value +written to the C tag. If C is not specified, the value is +copied from C (the C<#> is added to copy the unformatted +value, avoiding potential conflicts with the B<-d> option). For example, +the following two commands are equivalent: exiftool -geotag trk.log image.jpg exiftool -geotag trk.log "-Geotime or C may be specified to write only EXIF or XMP -tags respectively. Note that GPSPitch and GPSRoll are non-standard, and -require user-defined tags in order to be written. +GPSImgDirectionRef, GPSPitch, GPSRoll, AmbientTemperature and +CameraElevationAngle. By default, tags are created in EXIF, and updated in +XMP only if they already exist. However, C or C +may be specified to write only EXIF or XMP tags respectively. Note that +GPSPitch and GPSRoll are non-standard, and require user-defined tags in +order to be written. The C tag may be used to specify a time correction which is applied to each C value for synchronization with GPS time. For example, @@ -5796,7 +6309,6 @@ seconds behind GPS: exiftool -geosync=+1:20 -geotag a.log DIR -C must be set before C (if specified) to be effective. Advanced C features allow a linear time drift correction and synchronization from previously geotagged images. See "geotag.html" in the full ExifTool distribution for more information. @@ -5810,9 +6322,9 @@ Windows) to prevent filename expansion. For example: exiftool -geotag "TRACKDIR/*.log" IMAGEDIR Currently supported track file formats are GPX, NMEA RMC/GGA/GLL, KML, IGC, -Garmin XML and TCX, Magellan PMGNTRK, Honeywell PTNTHPR, Winplus Beacon -text, and Bramor gEO log files. See L for examples. -Also see "geotag.html" in the full ExifTool distribution and the +Garmin XML and TCX, Magellan PMGNTRK, Honeywell PTNTHPR, Bramor gEO, Winplus +Beacon TXT, and GPS/IMU CSV files. See L for +examples. Also see "geotag.html" in the full ExifTool distribution and the L for more details and for information about geotag configuration options. @@ -5838,11 +6350,11 @@ I string. For example: Add features from specified plug-in I. Currently, the MWG module is the only plug-in module distributed with exiftool. This module adds read/write support for tags as recommended by the Metadata Working Group. -To save typing, C<-use MWG> is assumed if the C group is specified for -any tag on the command line. See the -L for more -details. Note that this option is not reversible, and remains in effect -until the application terminates, even across the C<-execute> option. +As a convenience, C<-use MWG> is assumed if the C group is specified +for any tag on the command line. See the L for more details. Note +that this option is not reversible, and remains in effect until the +application terminates, even across the B<-execute> option. =back @@ -5911,7 +6423,7 @@ line and applies to all B<-execute>'d commands. The I must exist relative to the current working directory or the exiftool application directory unless an absolute path is specified. Loading of the default config file may be disabled by setting I to an empty string (ie. -""). See L and +""). See L and config_files/example.config in the full ExifTool distribution for details about the configuration file syntax. @@ -5920,7 +6432,20 @@ about the configuration file syntax. Echo I to stdout (B<-echo> or B<-echo1>) or stderr (B<-echo2>). Text is output as the command line is parsed, before the processing of any input files. I may also be 3 or 4 to output text (to stdout or stderr -respectively) after processing is complete. +respectively) after processing is complete. For B<-echo3> and B<-echo4>, +"${status}" may be used in the I string to represent the numerical +exit status of the command (see L). + +=item B<-efile>[I][!] I + +Save the names of files giving errors (I missing or 1), files that were +unchanged (I is 2), files that fail the B<-if> condition (I is 4), +or any combination thereof by summing I (eg. B<-efile3> is the same +has having both B<-efile> and B<-efile2> options with the same I). +By default, file names are appended to any existing I, but +I is overwritten if an exclamation point is added to the option +(eg. B<-efile!>). Saves the name of the file specified by the B<-srcfile> +option if applicable. =item B<-execute>[I] @@ -5930,7 +6455,22 @@ commands were executed as separate command lines (with the exception of the B<-config> and B<-use> options which remain in effect for subsequent commands). Allows multiple commands to be executed from a single command line. I is an optional number that is echoed in the "{ready}" message -when using the B<-stay_open> feature. +when using the B<-stay_open> feature. If a I is specified, the B<-q> +option no longer suppresses the output "{readyNUM}" message. + +=item B<-list_dir> + +List directories themselves instead of their contents. This option +effectively causes directories to be treated as normal files when reading +and writing. For example, with this option the output of the C +command on Mac/Linux may be approximated by this exiftool command: + + exiftool -list_dir -T -ls-l -api systemtags -fast5 .* * + +(The B<-T> option formats the output in tab-separated columns, B<-ls-l> is a +L, the API SystemTags option is +required to extract some necessary tags, and the B<-fast5> option is added +for speed since only system tags are being extracted.) =item B<-srcfile> I @@ -5946,20 +6486,25 @@ previews in a directory where other JPG images may exist: exiftool -ext nef -tagsfromfile @ -srcfile %d%f.jpg dir -If than one B<-srcfile> option is specified, the files are tested in order -and the first existing source file is processed. If none of the source -files already exist, then exiftool uses the first B<-srcfile> specified. +If more than one B<-srcfile> option is specified, the files are tested in +order and the first existing source file is processed. If none of the +source files already exist, then exiftool uses the first B<-srcfile> +specified. A I of C<@> may be used to represent the original I, which may be useful when specifying multiple B<-srcfile> options (eg. to fall back to processing the original I if no sidecar exists). +When this option is used, two special UserParam tags (OriginalFileName and +OriginalDirectory) are generated to allow access to the original I +name and directory. + =item B<-stay_open> I -If I is C<1> or C, causes exiftool keep reading from the B<-@> -I even after reaching the end of file. This feature allows calling -applications to pre-load exiftool, thus avoiding the overhead of loading -exiftool for each command. The procedure is as follows: +If I is C<1> or C (case insensitive), causes exiftool keep +reading from the B<-@> I even after reaching the end of file. This +feature allows calling applications to pre-load exiftool, thus avoiding the +overhead of loading exiftool for each command. The procedure is as follows: 1) Execute C>, where I is the name of an existing (possibly empty) argument file or C<-> to pipe arguments @@ -5970,17 +6515,21 @@ line (see the B<-@> option for details). 3) Write C<-execute\n> to I, where C<\n> represents a newline sequence. (Note: You may need to flush your write buffers here if using -buffered output.) Exiftool will then execute the command with the arguments +buffered output.) ExifTool will then execute the command with the arguments received up to this point, send a "{ready}" message to stdout when done (unless the B<-q> or B<-T> option is used), and continue trying to read arguments for the next command from I. To aid in command/response -synchronization, any number appended to the C<-execute> option is echoed in -the "{ready}" message. For example, C<-execute613> results in "{ready613}". +synchronization, any number appended to the B<-execute> option is echoed in +the "{ready}" message. For example, C<-execute613> results in "{ready613}". +When this number is added, B<-q> no longer suppresses the "{ready}" message. +(Also, see the B<-echo3> and B<-echo4> options for additional ways to pass +signals back to your application.) 4) Repeat steps 2 and 3 for each command. -5) Write C<-stay_open\nFalse\n> to I when done. This will cause -exiftool to process any remaining command-line arguments then exit normally. +5) Write C<-stay_open\nFalse\n> (or C<-stay_open\n0\n>) to I when +done. This will cause exiftool to process any remaining command-line +arguments then exit normally. The input I may be changed at any time before step 5 above by writing the following lines to the currently open I: @@ -5990,7 +6539,7 @@ writing the following lines to the currently open I: -@ NEWARGFILE -This causes I to be closed, and I to be kept open. +This causes I to be closed, and I to be kept open. (Without the B<-stay_open> here, exiftool would have returned to reading arguments from I after reaching the end of I.) @@ -6003,14 +6552,15 @@ necessary when using this technique.) =item B<-userParam> I -Set user parameter. I is an arbitrary user parameter name. This -is an interface to the API UserParam option (see the +Set user parameter. I is an arbitrary user parameter name. This is +an interface to the API UserParam option (see the L documentation), and -provides a method to access user-defined parameters from inside tag name -expressions (as if it were any other tag, see example below), and from -PrintConv/ValueConv logic (via the ExifTool Options function). Similar to -the B<-api> option, the parameter value is set to 1 if I<=VAL> is omitted, -undef if just I is omitted with C<=>, or an empty string if +provides a method to access user-defined parameters in arguments to the +B<-if> and B<-p> options as if they were any other tag. Appending a hash +tag (C<#>) to I (eg. C<-userParam MyTag#=yes>) also causes the +parameter to be extracted as a normal tag in the UserParam group. Similar +to the B<-api> option, the parameter value is set to 1 if I<=VAL> is +omitted, undef if just I is omitted with C<=>, or an empty string if I is omitted with C<^=>. exiftool -p '$test from $filename' -userparam test=Hello FILE @@ -6027,11 +6577,11 @@ placing braces around the tag name and inserting the expression after the name, separated by a semicolon (ie. C<${TAG;EXPR}>). The expression acts on the value of the tag through the default input variable (C<$_>), and has access to the full ExifTool API through the current ExifTool object -(C<$self>). It may contain any valid Perl code, including translation -(C) and substitution (C) operations, but note that braces -within the expression must be balanced. The example below prints the camera -Make with spaces translated to underlines, and multiple consecutive -underlines replaced by a single underline: +(C<$self>) and the tag key (C<$tag>). It may contain any valid Perl code, +including translation (C) and substitution (C) operations, but +note that braces within the expression must be balanced. The example below +prints the camera Make with spaces translated to underlines, and multiple +consecutive underlines replaced by a single underline: exiftool -p '${make;tr/ /_/;s/__+/_/g}' image.jpg @@ -6050,28 +6600,40 @@ used in file names.) =head4 Helper functions -ExifTool provides a C utility to simplify reformatting of -individual date/time values. The function acts on a standard EXIF-formatted -date/time value in C<$_> and formats it according to the specified format -string (see the B<-d> option). To avoid trying to reformat an already -formatted date/time value, a C<#> must be added to the tag name (as in the -example below) if the B<-d> option is also used. For example: +C + +Simplifies reformatting of individual date/time values. This function acts +on a standard EXIF-formatted date/time value in C<$_> and formats it +according to the specified format string (see the B<-d> option). To avoid +trying to reformat an already-formatted date/time value, a C<#> must be +added to the tag name (as in the example below) if the B<-d> option is also +used. For example: exiftool -p '${createdate#;DateFmt("%Y-%m-%d_%H%M%S")}' a.jpg -A C utility is also provided to remove duplicate items from a list -with a separator specified by the B<-sep> option. This function is most -useful when copying list-type tags. For example, the following command may -be used to remove duplicate Keywords: +C + +Shifts EXIF-formatted date/time string by a specified amount. Start with a +leading minus sign to shift backwards in time. See +L for details about +shift syntax. For example, to shift a date/time value back by one year: + + exiftool -p '${createdate;ShiftTime("-1:0:0 0")}' a.jpg + +C + +Removes duplicate items from a list with a separator specified by the +B<-sep> option. This function is most useful when copying list-type tags. +For example, the following command may be used to remove duplicate Keywords: exiftool -sep '##' '-keywords<${keywords;NoDups}' a.jpg The B<-sep> option is necessary to split the string back into individual list items when writing to a list-type tag. -An optional flag argument may be set to 1 to cause C to return undef -if no duplicates existed, thus preventing the file from being rewritten -unnecessarily: +An optional flag argument may be set to 1 to cause C to set C<$_> to +undef if no duplicates existed, thus preventing the file from being +rewritten unnecessarily: exiftool -sep '##' '-keywords<${keywords;NoDups(1)}' a.jpg @@ -6089,10 +6651,10 @@ ExifTool 9.79 and later allow the file name encoding to be specified with C<-charset filename=CHARSET>, where C is the name of a valid ExifTool character set, preferably C (see the B<-charset> option for a complete list). Setting this triggers the use of Windows wide-character i/o -routines, thus providing support for all Unicode file names. But note that -it is not trivial to pass properly encoded file names on the Windows command -line (see L for -details), so placing them in a UTF-8 encoded B<-@> argfile and using +routines, thus providing support for most Unicode file names (see note 4). +But note that it is not trivial to pass properly encoded file names on the +Windows command line (see L for details), +so placing them in a UTF-8 encoded B<-@> argfile and using C<-charset filename=utf8> is recommended if possible. A warning is issued if a specified filename contains special characters and @@ -6125,6 +6687,9 @@ like Cygwin. 3) See L below for a note about editing read-only files with Unicode names. +4) Unicode file names with surrogate pairs (code points over U+FFFF) still +cause problems. + =head1 WRITING READ-ONLY FILES In general, ExifTool may be used to write metadata to read-only files @@ -6139,6 +6704,14 @@ there are three cases where file write permission is also required: B<-overwrite_original> option is used, or b) the C<_original> backup already exists. +Hidden files in Windows behave as read-only files when attempting to write +any real tags to the file -- an error is generated when using the +B<-overwrite_original_in_place>, otherwise writing should be successful and +the hidden attribute will be removed. But the B<-if> option may be used to +avoid processing hidden files (provided Win32API::File is available): + + exiftool -if "$fileattributes !~ /Hidden/" ... + =head1 READING EXAMPLES B: Beware when cutting and pasting these examples into your terminal! @@ -6153,7 +6726,11 @@ arguments containing special characters. =item exiftool -a -u -g1 a.jpg Print all meta information in an image, including duplicate and unknown -tags, sorted by group (for family 1). +tags, sorted by group (for family 1). For performance reasons, this command +may not extract all available metadata. (Metadata in embedded documents, +metadata extracted by external utilities, and metadata requiring excessive +processing time may not be extracted). Add C<-ee3> and C<-api RequestAll=3> +to the command to extract absolutely everything available. =item exiftool -common dir @@ -6221,7 +6798,7 @@ L). Print one line of output containing the file name and DateTimeOriginal for each image in directory C. -=item exiftool -ee -p '$gpslatitude, $gpslongitude, $gpstimestamp' a.m2ts +=item exiftool -ee3 -p '$gpslatitude, $gpslongitude, $gpstimestamp' a.m2ts Extract all GPS positions from an AVCHD video. @@ -6375,8 +6952,8 @@ Write ICC_Profile to an image from a C<.icc> file of the same name. =item exiftool -hierarchicalkeywords='{keyword=one,children={keyword=B}}' -Write structured XMP information. See -L for more details. +Write structured XMP information. See L +for more details. =item exiftool -trailer:all= image.jpg @@ -6537,8 +7114,8 @@ an extra '%' must be added to pass these codes through the date/time parser. (And further note that in a Windows batch file, all '%' characters must also be escaped, so in this extreme case '%%%%f' is necessary to pass a simple '%f' through the two levels of parsing.) See -L for additional -documentation and examples. +L for additional documentation and +examples. =over 5 @@ -6597,8 +7174,7 @@ CreateDate and FileNumber tags, in the form "20060507_118-1861.jpg". ExifTool implements geotagging via 3 special tags: Geotag (which for convenience is also implemented as an exiftool option), Geosync and Geotime. The examples below highlight some geotagging features. See -L for additional -documentation. +L for additional documentation. =over 5 @@ -6656,7 +7232,7 @@ Combine multiple track logs and geotag an entire directory tree of images. Read all track logs from the C directory. -=item exiftool -p gpx.fmt -d %Y-%m-%dT%H:%M:%SZ dir > out.gpx +=item exiftool -p gpx.fmt dir > out.gpx Generate a GPX track log from all images in directory C. This example uses the C file included in the full ExifTool distribution package @@ -6695,6 +7271,13 @@ flexibility of ExifTool.) =back +=head1 INTERRUPTING EXIFTOOL + +Interrupting exiftool with a CTRL-C or SIGINT will not result in partially +written files or temporary files remaining on the hard disk. The exiftool +application traps SIGINT and defers it until the end of critical processes +if necessary, then does a proper cleanup before exiting. + =head1 EXIT STATUS The exiftool application exits with a status of 0 on success, or 1 if an @@ -6703,7 +7286,7 @@ the commands if B<-execute> was used). =head1 AUTHOR -Copyright 2003-2018, Phil Harvey +Copyright 2003-2022, Phil Harvey This is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/File/RandomAccess.pm b/src/Image-ExifTool/lib/File/RandomAccess.pm index c689f56b..d6e11aa9 100644 --- a/src/Image-ExifTool/lib/File/RandomAccess.pm +++ b/src/Image-ExifTool/lib/File/RandomAccess.pm @@ -25,7 +25,7 @@ # # May also be used for string i/o (just pass a scalar reference) # -# Legal: Copyright (c) 2003-2018 Phil Harvey (phil at owl.phy.queensu.ca) +# Legal: Copyright (c) 2003-2022 Phil Harvey (philharvey66 at gmail.com) # This library is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. #------------------------------------------------------------------------------ diff --git a/src/Image-ExifTool/lib/File/RandomAccess.pod b/src/Image-ExifTool/lib/File/RandomAccess.pod index d3a26f37..edfbbe0a 100644 --- a/src/Image-ExifTool/lib/File/RandomAccess.pod +++ b/src/Image-ExifTool/lib/File/RandomAccess.pod @@ -3,7 +3,7 @@ # # Description: Buffer to support random access reading of sequential file # -# Legal: Copyright (c) 2003-2018 Phil Harvey (phil at owl.phy.queensu.ca) +# Legal: Copyright (c) 2003-2022 Phil Harvey (philharvey66 at gmail.com) # This library is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. #------------------------------------------------------------------------------ @@ -236,7 +236,7 @@ the end of file is not allowed. =head1 AUTHOR -Copyright 2003-2018 Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022 Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool.pm b/src/Image-ExifTool/lib/Image/ExifTool.pm index 40a86b7a..070c4ca6 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool.pm @@ -3,12 +3,12 @@ # # Description: Read and write meta information # -# URL: http://owl.phy.queensu.ca/~phil/exiftool/ +# URL: https://exiftool.org/ # # Revisions: Nov. 12/2003 - P. Harvey Created # (See html/history.html for revision history) # -# Legal: Copyright (c) 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +# Legal: Copyright (c) 2003-2022, Phil Harvey (philharvey66 at gmail.com) # This library is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. #------------------------------------------------------------------------------ @@ -19,15 +19,17 @@ use strict; require 5.004; # require 5.004 for UNIVERSAL::isa (otherwise 5.002 would do) require Exporter; use File::RandomAccess; +use overload; use vars qw($VERSION $RELEASE @ISA @EXPORT_OK %EXPORT_TAGS $AUTOLOAD @fileTypes %allTables @tableOrder $exifAPP1hdr $xmpAPP1hdr $xmpExtAPP1hdr $psAPP13hdr $psAPP13old @loadAllTables %UserDefined $evalWarning %noWriteFile %magicNumber @langs $defaultLang %langName %charsetName %mimeType $swapBytes $swapWords $currentByteOrder %unpackStd - %jpegMarker %specialTags %fileTypeLookup); + %jpegMarker %specialTags %fileTypeLookup $testLen $exeDir + %static_vars); -$VERSION = '11.16'; +$VERSION = '12.45'; $RELEASE = ''; @ISA = qw(Exporter); %EXPORT_TAGS = ( @@ -41,7 +43,7 @@ $RELEASE = ''; DataAccess => [qw( ReadValue GetByteOrder SetByteOrder ToggleByteOrder Get8u Get8s Get16u Get16s Get32u Get32s Get64u GetFloat GetDouble GetFixed32s Write - WriteValue Tell Set8u Set8s Set16u Set32u + WriteValue Tell Set8u Set8s Set16u Set32u Set64u Set64s )], Utils => [qw(GetTagTable TagTableKeys GetTagInfoList AddTagToTable HexDump)], Vars => [qw(%allTables @tableOrder @fileTypes)], @@ -53,7 +55,7 @@ Exporter::export_ok_tags(keys %EXPORT_TAGS); # test for problems that can arise if encoding.pm is used { my $t = "\xff"; die "Incompatible encoding!\n" if ord($t) != 0xff; } -# The following functions defined in Image::ExifTool::Writer are declared +# The following functions defined in Image::ExifTool::Writer.pl are declared # here so their prototypes will be available. These Writer routines will be # autoloaded when any of them is called. sub SetNewValue($;$$%); @@ -69,13 +71,15 @@ sub SetFileName($$;$$$); sub SetSystemTags($$); sub GetAllTags(;$); sub GetWritableTags(;$); -sub GetAllGroups($); +sub GetAllGroups($;$); sub GetNewGroups($); sub GetDeleteGroups(); sub AddUserDefinedTags($%); # non-public routines below sub InsertTagValues($$$;$$$); sub IsWritable($); +sub IsSameFile($$$); +sub IsRawType($); sub GetNewFileName($$); sub LoadAllTables(); sub GetNewTagInfoList($;$); @@ -85,8 +89,11 @@ sub Get64s($$); sub Get64u($$); sub GetFixed64s($$); sub GetExtended($$); +sub Set64u(@); +sub Set64s(@); sub DecodeBits($$;$); sub EncodeBits($$;$$); +sub Filter($$$); sub HexDump($;$%); sub DumpTrailer($$); sub DumpUnknownTrailer($$); @@ -105,7 +112,7 @@ sub CheckBinaryData($$$); sub WriteTIFF($$$); sub PackUTF8(@); sub UnpackUTF8($); -sub SetPreferredByteOrder($); +sub SetPreferredByteOrder($;$); sub CopyBlock($$$); sub CopyFileAttrs($$$); sub TimeNow(;$$); @@ -113,6 +120,7 @@ sub NewGUID(); sub MakeTiffHeader($$$$;$$); # other subroutine definitions +sub SplitFileName($); sub EncodeFileName($$;$); sub Open($*$;$); sub Exists($$); @@ -123,7 +131,7 @@ sub SetFileTime($$;$$$$); sub DoEscape($$); sub ConvertFileSize($); sub ParseArguments($;@); #(defined in attempt to avoid mod_perl problem) -sub ReadValue($$$$$;$); +sub ReadValue($$$;$$$); # list of main tag tables to load in LoadAllTables() (sub-tables are recursed # automatically). Note: They will appear in this order in the documentation @@ -131,17 +139,18 @@ sub ReadValue($$$$$;$); @loadAllTables = qw( PhotoMechanic Exif GeoTiff CanonRaw KyoceraRaw Lytro MinoltaRaw PanasonicRaw SigmaRaw JPEG GIMP Jpeg2000 GIF BMP BMP::OS2 BMP::Extra BPG BPG::Extensions - PICT PNG MNG FLIF DjVu DPX OpenEXR MIFF PGF PSP PhotoCD Radiance PDF - PostScript Photoshop::Header Photoshop::Layers Photoshop::ImageData - FujiFilm::RAF FujiFilm::IFD Samsung::Trailer Sony::SRF2 Sony::SR2SubIFD - Sony::PMP ITC ID3 FLAC Ogg Vorbis APE APE::NewHeader APE::OldHeader Audible - MPC MPEG::Audio MPEG::Video MPEG::Xing M2TS QuickTime QuickTime::ImageFile - QuickTime::Stream Matroska MOI MXF DV Flash Flash::FLV Real::Media - Real::Audio Real::Metafile Red RIFF AIFF ASF WTV DICOM MIE JSON HTML + PICT PNG MNG FLIF DjVu DPX OpenEXR ZISRAW MRC LIF MRC::FEI12 MIFF PCX PGF + PSP PhotoCD Radiance Other::PFM PDF PostScript Photoshop::Header + Photoshop::Layers Photoshop::ImageData FujiFilm::RAF FujiFilm::IFD + Samsung::Trailer Sony::SRF2 Sony::SR2SubIFD Sony::PMP ITC ID3 ID3::Lyrics3 + FLAC Ogg Vorbis APE APE::NewHeader APE::OldHeader Audible MPC MPEG::Audio + MPEG::Video MPEG::Xing M2TS QuickTime QuickTime::ImageFile QuickTime::Stream + QuickTime::Tags360Fly Matroska MOI MXF DV Flash Flash::FLV Real::Media + Real::Audio Real::Metafile Red RIFF AIFF ASF WTV DICOM FITS MIE JSON HTML XMP::SVG Palm Palm::MOBI Palm::EXTH Torrent EXE EXE::PEVersion EXE::PEString - EXE::MachO EXE::PEF EXE::ELF EXE::AR EXE::CHM LNK Font VCard + EXE::MachO EXE::PEF EXE::ELF EXE::AR EXE::CHM LNK Font VCard Text VCard::VCalendar RSRC Rawzor ZIP ZIP::GZIP ZIP::RAR RTF OOXML iWork ISO - FLIR::AFF FLIR::FPF MacOS::MDItem MacOS::XAttr FlashPix::DocTable + FLIR::AFF FLIR::FPF MacOS MacOS::MDItem FlashPix::DocTable ); # alphabetical list of current Lang modules @@ -179,31 +188,33 @@ $defaultLang = 'en'; # default language @fileTypes = qw(JPEG EXV CRW DR4 TIFF GIF MRW RAF X3F JP2 PNG MIE MIFF PS PDF PSD XMP BMP BPG PPM RIFF AIFF ASF MOV MPEG Real SWF PSP FLV OGG FLAC APE MPC MKV MXF DV PMP IND PGF ICC ITC FLIR FLIF FPF LFP - HTML VRD RTF XCF DSS QTIF FPX PICT ZIP GZIP PLIST RAR BZ2 TAR - RWZ EXE EXR HDR CHM LNK WMF AVC DEX DPX RAW Font RSRC M2TS PHP - WTV Torrent VCard LRI R3D AA PDB MOI ISO JSON MP3 DICOM PCD); + HTML VRD RTF FITS XCF DSS QTIF FPX PICT ZIP GZIP PLIST RAR BZ2 + CZI TAR EXE EXR HDR CHM LNK WMF AVC DEX DPX RAW Font RSRC M2TS + MacOS PHP PCX DCX DWF DWG DXF WTV Torrent VCard LRI R3D AA PDB + PFM2 MRC LIF JXL MOI ISO ALIAS JSON MP3 DICOM PCD TXT); # file types that we can write (edit) my @writeTypes = qw(JPEG TIFF GIF CRW MRW ORF RAF RAW PNG MIE PSD XMP PPM EPS - X3F PS PDF ICC VRD DR4 JP2 EXIF AI AIT IND MOV EXV FLIF); + X3F PS PDF ICC VRD DR4 JP2 JXL EXIF AI AIT IND MOV EXV FLIF); my %writeTypes; # lookup for writable file types (hash filled if required) # file extensions that we can't write for various base types %noWriteFile = ( TIFF => [ qw(3FR DCR K25 KDC SRF) ], - XMP => [ 'SVG', 'INX' ], - JP2 => [ 'J2C', 'JPC' ], - MOV => [ 'HEIC', 'HEIF' ], + XMP => [ qw(SVG INX) ], + JP2 => [ qw(J2C JPC) ], + MOV => [ qw(INSV) ], ); # file types that we can create from scratch # - must update CanCreate() documentation if this list is changed! my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); -# file type lookup for all recognized file extensions +# file type lookup for all recognized file extensions (upper case) # (if extension may be more than one type, the type is a list where # the writable type should come first if it exists) %fileTypeLookup = ( + '360' => ['MOV', 'GoPro 360 video'], '3FR' => ['TIFF', 'Hasselblad RAW format'], '3G2' => ['MOV', '3rd Gen. Partnership Project 2 audio/video'], '3GP' => ['MOV', '3rd Gen. Partnership Project audio/video'], @@ -222,6 +233,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); AIFC => ['AIFF', 'Audio Interchange File Format Compressed'], AIFF => ['AIFF', 'Audio Interchange File Format'], AIT => 'AI', + ALIAS=> ['ALIAS','MacOS file alias'], APE => ['APE', "Monkey's Audio format"], APNG => ['PNG', 'Animated Portable Network Graphics'], ARW => ['TIFF', 'Sony Alpha RAW format'], @@ -229,6 +241,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); ASF => ['ASF', 'Microsoft Advanced Systems Format'], AVC => ['AVC', 'Advanced Video Connection'], # (extensions are actually _AU,_AD,_IM,_ID) AVI => ['RIFF', 'Audio Video Interleaved'], + AVIF => ['MOV', 'AV1 Image File Format'], AZW => 'MOBI', # (see http://wiki.mobileread.com/wiki/AZW) AZW3 => 'MOBI', BMP => ['BMP', 'Windows Bitmap'], @@ -243,15 +256,19 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); CRM => ['MOV', 'Canon RAW Movie'], CRW => ['CRW', 'Canon RAW format'], CS1 => ['PSD', 'Sinar CaptureShop 1-Shot RAW'], + CSV => ['TXT', 'Comma-Separated Values'], + CZI => ['CZI', 'Zeiss Integrated Software RAW'], DC3 => 'DICM', DCM => 'DICM', DCP => ['TIFF', 'DNG Camera Profile'], DCR => ['TIFF', 'Kodak Digital Camera RAW'], + DCX => ['DCX', 'Multi-page PC Paintbrush'], DEX => ['DEX', 'Dalvik Executable format'], DFONT=> ['Font', 'Macintosh Data fork Font'], DIB => ['BMP', 'Device Independent Bitmap'], DIC => 'DICM', DICM => ['DICOM','Digital Imaging and Communications in Medicine'], + DIR => ['DIR', 'Directory'], DIVX => ['ASF', 'DivX media format'], DJV => 'DJVU', DJVU => ['AIFF', 'DjVu image'], @@ -273,7 +290,10 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); DV => ['DV', 'Digital Video'], DVB => ['MOV', 'Digital Video Broadcasting'], 'DVR-MS'=>['ASF', 'Microsoft Digital Video recording'], + DWF => ['DWF', 'Autodesk drawing (Design Web Format)'], + DWG => ['DWG', 'AutoCAD Drawing'], DYLIB=> ['EXE', 'Mach-O Dynamic Link Library'], + DXF => ['DXF', 'AutoCAD Drawing Exchange Format'], EIP => ['ZIP', 'Capture One Enhanced Image Package'], EPS => ['EPS', 'Encapsulated PostScript Format'], EPS2 => 'EPS', @@ -290,6 +310,8 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); F4P => ['MOV', 'Adobe Flash Player 9+ Protected'], F4V => ['MOV', 'Adobe Flash Player 9+ Video'], FFF => [['TIFF','FLIR'], 'Hasselblad Flexible File Format'], + FIT => 'FITS', + FITS => ['FITS', 'Flexible Image Transport System'], FLAC => ['FLAC', 'Free Lossless Audio Codec'], FLA => ['FPX', 'Macromedia/Adobe Flash project'], FLIF => ['FLIF', 'Free Lossless Image Format'], @@ -298,13 +320,14 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); FPF => ['FPF', 'FLIR Public image Format'], FPX => ['FPX', 'FlashPix'], GIF => ['GIF', 'Compuserve Graphics Interchange Format'], - GPR => ['TIFF', 'GoPro RAW'], + GPR => ['TIFF', 'General Purpose RAW'], # https://gopro.github.io/gpr/ GZ => 'GZIP', GZIP => ['GZIP', 'GNU ZIP compressed archive'], HDP => ['TIFF', 'Windows HD Photo'], HDR => ['HDR', 'Radiance RGBE High Dynamic Range'], HEIC => ['MOV', 'High Efficiency Image Format still image'], HEIF => ['MOV', 'High Efficiency Image Format'], + HIF => 'HEIF', HTM => 'HTML', HTML => ['HTML', 'HyperText Markup Language'], ICAL => 'ICS', @@ -316,11 +339,13 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); IND => ['IND', 'Adobe InDesign'], INDD => ['IND', 'Adobe InDesign Document'], INDT => ['IND', 'Adobe InDesign Template'], + INSV => ['MOV', 'Insta360 Video'], + INSP => ['JPEG', 'Insta360 Picture'], INX => ['XMP', 'Adobe InDesign Interchange'], ISO => ['ISO', 'ISO 9660 disk image'], ITC => ['ITC', 'iTunes Cover Flow'], J2C => ['JP2', 'JPEG 2000 codestream'], - J2K => 'JP2', + J2K => 'J2C', JNG => ['PNG', 'JPG Network Graphics'], JP2 => ['JP2', 'JPEG 2000 file'], # JP4? - looks like a JPEG but the image data is different @@ -330,8 +355,10 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); JPF => 'JP2', JPG => 'JPEG', JPM => ['JP2', 'JPEG 2000 compound image'], + JPS => ['JPEG', 'JPEG Stereo image'], JPX => ['JP2', 'JPEG 2000 with extensions'], JSON => ['JSON', 'JavaScript Object Notation'], + JXL => ['JXL', 'JPEG XL'], JXR => ['TIFF', 'JPEG XR'], K25 => ['TIFF', 'Kodak DC25 RAW'], KDC => ['TIFF', 'Kodak Digital Camera RAW'], @@ -340,8 +367,10 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); LA => ['RIFF', 'Lossless Audio'], LFP => ['LFP', 'Lytro Light Field Picture'], LFR => 'LFP', # (Light Field RAW) + LIF => ['LIF', 'Leica Image File'], LNK => ['LNK', 'Windows shortcut'], LRI => ['LRI', 'Light RAW'], + LRV => ['MOV', 'Low-Resolution Video'], M2T => 'M2TS', M2TS => ['M2TS', 'MPEG-2 Transport Stream'], M2V => ['MPEG', 'MPEG-2 Video'], @@ -370,12 +399,15 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); MPG => 'MPEG', MPO => ['JPEG', 'Extended Multi-Picture format'], MQV => ['MOV', 'Sony Mobile Quicktime Video'], + MRC => ['MRC', 'Medical Research Council image'], MRW => ['MRW', 'Minolta RAW format'], MTS => 'M2TS', MXF => ['MXF', 'Material Exchange Format'], # NDPI => ['TIFF', 'Hamamatsu NanoZoomer Digital Pathology Image'], NEF => ['TIFF', 'Nikon (RAW) Electronic Format'], NEWER => 'COS', + NKSC => ['XMP', 'Nikon Sidecar'], + NMBTEMPLATE => ['ZIP','Apple Numbers Template'], NRW => ['TIFF', 'Nikon RAW (2)'], NUMBERS => ['ZIP','Apple Numbers spreadsheet'], @@ -391,20 +423,23 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); OFR => ['RIFF', 'OptimFROG audio'], OGG => ['OGG', 'Ogg Vorbis audio file'], OGV => ['OGG', 'Ogg Video file'], + ONP => ['JSON', 'ON1 Presets'], OPUS => ['OGG', 'Ogg Opus audio file'], ORF => ['ORF', 'Olympus RAW format'], + ORI => 'ORF', OTF => ['Font', 'Open Type Font'], PAC => ['RIFF', 'Lossless Predictive Audio Compression'], PAGES => ['ZIP', 'Apple Pages document'], PBM => ['PPM', 'Portable BitMap'], PCD => ['PCD', 'Kodak Photo CD Image Pac'], PCT => 'PICT', + PCX => ['PCX', 'PC Paintbrush'], PDB => ['PDB', 'Palm Database'], PDF => ['PDF', 'Adobe Portable Document Format'], PEF => ['TIFF', 'Pentax (RAW) Electronic Format'], PFA => ['Font', 'PostScript Font ASCII'], PFB => ['Font', 'PostScript Font Binary'], - PFM => ['Font', 'Printer Font Metrics'], + PFM => [['Font','PFM2'], 'Printer Font Metrics'], # (description is overridden for Portable FloatMap images) PGF => ['PGF', 'Progressive Graphics File'], PGM => ['PPM', 'Portable Gray Map'], PHP => ['PHP', 'PHP Hypertext Preprocessor'], @@ -420,6 +455,8 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); POT => ['FPX', 'Microsoft PowerPoint Template'], POTM => [['ZIP','FPX'], 'Office Open XML Presentation Template Macro-enabled'], POTX => [['ZIP','FPX'], 'Office Open XML Presentation Template'], + PPAM => [['ZIP','FPX'], 'Office Open XML Presentation Addin Macro-enabled'], + PPAX => [['ZIP','FPX'], 'Office Open XML Presentation Addin'], PPM => ['PPM', 'Portable Pixel Map'], PPS => ['FPX', 'Microsoft PowerPoint Slideshow'], PPSM => [['ZIP','FPX'], 'Office Open XML Presentation Slideshow Macro-enabled'], @@ -469,7 +506,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); SVG => ['XMP', 'Scalable Vector Graphics'], SWF => ['SWF', 'Shockwave Flash'], TAR => ['TAR', 'TAR archive'], - THM => ['JPEG', 'Canon Thumbnail'], + THM => ['JPEG', 'Thumbnail'], THMX => [['ZIP','FPX'], 'Office Open XML Theme'], TIF => 'TIFF', TIFF => ['TIFF', 'Tagged Image File Format'], @@ -478,6 +515,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); TTC => ['Font', 'True Type Font Collection'], TTF => ['Font', 'True Type Font'], TUB => 'PSP', + TXT => ['TXT', 'Text file'], VCARD=> ['VCard','Virtual Card'], VCF => 'VCARD', VOB => ['MPEG', 'Video Object'], @@ -492,6 +530,7 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); WMV => ['ASF', 'Windows Media Video'], WV => ['RIFF', 'WavePack lossless audio'], X3F => ['X3F', 'Sigma RAW format'], + MACOS=> ['MacOS','MacOS ._ sidecar file'], XCF => ['XCF', 'GIMP native image format'], XHTML=> ['HTML', 'Extensible HyperText Markup Language'], XLA => ['FPX', 'Microsoft Excel Add-in'], @@ -504,6 +543,8 @@ my %createTypes = map { $_ => 1 } qw(XMP ICC MIE VRD DR4 EXIF EXV); XLTM => [['ZIP','FPX'], 'Office Open XML Spreadsheet Template Macro-enabled'], XLTX => [['ZIP','FPX'], 'Office Open XML Spreadsheet Template'], XMP => ['XMP', 'Extensible Metadata Platform'], + WOFF => ['Font', 'Web Open Font Format'], + WOFF2=> ['Font', 'Web Open Font Format2'], WTV => ['WTV', 'Windows recorded TV show'], ZIP => ['ZIP', 'ZIP archive'], ); @@ -541,6 +582,7 @@ my %fileDescription = ( AAE => 'application/vnd.apple.photos', AI => 'application/vnd.adobe.illustrator', AIFF => 'audio/x-aiff', + ALIAS=> 'application/x-macos', APE => 'audio/x-monkeys-audio', APNG => 'image/apng', ASF => 'video/x-ms-asf', @@ -551,11 +593,16 @@ my %fileDescription = ( BZ2 => 'application/bzip2', 'Canon 1D RAW' => 'image/x-raw', # (uses .TIF file extension) CHM => 'application/x-chm', + COS => 'application/octet-stream', #PH (NC) CR2 => 'image/x-canon-cr2', CR3 => 'image/x-canon-cr3', CRM => 'video/x-canon-crm', CRW => 'image/x-canon-crw', + CSV => 'text/csv', + CZI => 'image/x-zeiss-czi', #PH (NC) + DCP => 'application/octet-stream', #PH (NC) DCR => 'image/x-kodak-dcr', + DCX => 'image/dcx', DEX => 'application/octet-stream', DFONT=> 'application/x-dfont', DICOM=> 'application/dicom', @@ -563,27 +610,35 @@ my %fileDescription = ( DJVU => 'image/vnd.djvu', DNG => 'image/x-adobe-dng', DOC => 'application/msword', - DOCM => 'application/vnd.ms-word.document.macroEnabled', + DOCM => 'application/vnd.ms-word.document.macroEnabled.12', DOCX => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', DOT => 'application/msword', DOTM => 'application/vnd.ms-word.template.macroEnabledTemplate', DOTX => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', DPX => 'image/x-dpx', + DR4 => 'application/octet-stream', #PH (NC) DS2 => 'audio/x-ds2', DSS => 'audio/x-dss', DV => 'video/x-dv', 'DVR-MS' => 'video/x-ms-dvr', + DWF => 'model/vnd.dwf', + DWG => 'image/vnd.dwg', + DXF => 'application/dxf', EIP => 'application/x-captureone', #(NC) EPS => 'application/postscript', ERF => 'image/x-epson-erf', EXE => 'application/octet-stream', + EXR => 'image/x-exr', EXV => 'image/x-exv', FFF => 'image/x-hasselblad-fff', + FITS => 'image/fits', FLA => 'application/vnd.adobe.fla', FLAC => 'audio/flac', FLIF => 'image/flif', + FLIR => 'image/x-flir-fff', #PH (NC) FLV => 'video/x-flv', Font => 'application/x-font-type1', # covers PFA, PFB and PFM (not sure about PFM) + FPF => 'image/x-flir-fpf', #PH (NC) FPX => 'image/vnd.fpx', GIF => 'image/gif', GPR => 'image/x-gopro-gpr', @@ -599,22 +654,26 @@ my %fileDescription = ( INX => 'application/x-indesign-interchange', #PH (NC) ISO => 'application/x-iso9660-image', ITC => 'application/itunes', - JNG => 'image/jng', J2C => 'image/x-j2c', #PH (NC) + JNG => 'image/jng', JP2 => 'image/jp2', JPEG => 'image/jpeg', JPM => 'image/jpm', + JPS => 'image/x-jps', JPX => 'image/jpx', JSON => 'application/json', + JXL => 'image/jxl', #PH (NC) + JXR => 'image/jxr', K25 => 'image/x-kodak-k25', KDC => 'image/x-kodak-kdc', KEY => 'application/x-iwork-keynote-sffkey', LFP => 'image/x-lytro-lfp', #PH (NC) + LIF => 'image/x-lif', LNK => 'application/octet-stream', LRI => 'image/x-light-lri', - MAX => 'application/x-3ds', M2T => 'video/mpeg', M2TS => 'video/m2ts', + MAX => 'application/x-3ds', MEF => 'image/x-mamiya-mef', MIE => 'application/x-mie', MIFF => 'application/x-magick-image', @@ -623,15 +682,18 @@ my %fileDescription = ( MKV => 'video/x-matroska', MNG => 'video/mng', MOBI => 'application/x-mobipocket-ebook', + MOI => 'application/octet-stream', #PH (NC) MOS => 'image/x-raw', MOV => 'video/quicktime', MP3 => 'audio/mpeg', MP4 => 'video/mp4', MPC => 'audio/x-musepack', MPEG => 'video/mpeg', + MRC => 'image/x-mrc', MRW => 'image/x-minolta-mrw', MXF => 'application/mxf', NEF => 'image/x-nikon-nef', + NKSC => 'application/x-nikon-nxstudio', NRW => 'image/x-nikon-nrw', NUMBERS => 'application/x-iwork-numbers-sffnumbers', ODB => 'application/vnd.oasis.opendocument.database', @@ -644,12 +706,13 @@ my %fileDescription = ( ODT => 'application/vnd.oasis.opendocument.text', OGG => 'audio/ogg', OGV => 'video/ogg', - EXR => 'image/x-exr', + ONP => 'application/on1', ORF => 'image/x-olympus-orf', OTF => 'application/x-font-otf', PAGES=> 'application/x-iwork-pages-sffpages', PBM => 'image/x-portable-bitmap', PCD => 'image/x-photo-cd', + PCX => 'image/pcx', PDB => 'application/vnd.palm', PDF => 'application/pdf', PEF => 'image/x-pentax-pef', @@ -659,16 +722,19 @@ my %fileDescription = ( PHP => 'application/x-httpd-php', PICT => 'image/pict', PLIST=> 'application/xml', # (binary PLIST format is 'application/x-plist', recognized at run time) + PMP => 'image/x-sony-pmp', #PH (NC) PNG => 'image/png', POT => 'application/vnd.ms-powerpoint', - POTM => 'application/vnd.ms-powerpoint.template.macroEnabled', + POTM => 'application/vnd.ms-powerpoint.template.macroEnabled.12', POTX => 'application/vnd.openxmlformats-officedocument.presentationml.template', + PPAM => 'application/vnd.ms-powerpoint.addin.macroEnabled.12', + PPAX => 'application/vnd.openxmlformats-officedocument.presentationml.addin', # (NC, PH invented) PPM => 'image/x-portable-pixmap', PPS => 'application/vnd.ms-powerpoint', - PPSM => 'application/vnd.ms-powerpoint.slideshow.macroEnabled', + PPSM => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', PPSX => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', PPT => 'application/vnd.ms-powerpoint', - PPTM => 'application/vnd.ms-powerpoint.presentation.macroEnabled', + PPTM => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', PPTX => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', PS => 'application/postscript', PSD => 'application/vnd.adobe.photoshop', @@ -689,6 +755,7 @@ my %fileDescription = ( RW2 => 'image/x-panasonic-rw2', RWL => 'image/x-leica-rwl', RWZ => 'image/x-rawzor', #(duplicated in Rawzor.pm) + SEQ => 'image/x-flir-seq', #PH (NC) SKETCH => 'application/sketch', SR2 => 'image/x-sony-sr2', SRF => 'image/x-sony-srf', @@ -701,7 +768,9 @@ my %fileDescription = ( Torrent => 'application/x-bittorrent', TTC => 'application/x-font-ttf', TTF => 'application/x-font-ttf', + TXT => 'text/plain', VCard=> 'text/vcard', + VRD => 'application/octet-stream', #PH (NC) VSD => 'application/x-visio', WDP => 'image/vnd.ms-photo', WEBM => 'video/webm', @@ -712,13 +781,13 @@ my %fileDescription = ( X3F => 'image/x-sigma-x3f', XCF => 'image/x-xcf', XLA => 'application/vnd.ms-excel', - XLAM => 'application/vnd.ms-excel.addin.macroEnabled', + XLAM => 'application/vnd.ms-excel.addin.macroEnabled.12', XLS => 'application/vnd.ms-excel', - XLSB => 'application/vnd.ms-excel.sheet.binary.macroEnabled', - XLSM => 'application/vnd.ms-excel.sheet.macroEnabled', + XLSB => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + XLSM => 'application/vnd.ms-excel.sheet.macroEnabled.12', XLSX => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', XLT => 'application/vnd.ms-excel', - XLTM => 'application/vnd.ms-excel.template.macroEnabled', + XLTM => 'application/vnd.ms-excel.template.macroEnabled.12', XLTX => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', XML => 'application/xml', XMP => 'application/rdf+xml', @@ -731,16 +800,23 @@ my %fileDescription = ( # - module name '0' indicates a recognized but unsupported file my %moduleName = ( AA => 'Audible', + ALIAS=> 0, AVC => 0, BTF => 'BigTIFF', BZ2 => 0, CRW => 'CanonRaw', CHM => 'EXE', COS => 'CaptureOne', + CZI => 'ZISRAW', DEX => 0, DOCX => 'OOXML', + DCX => 0, + DIR => 0, DR4 => 'CanonVRD', DSS => 'Olympus', + DWF => 0, + DWG => 0, + DXF => 0, EPS => 'PostScript', EXIF => '', EXR => 'OpenEXR', @@ -754,6 +830,7 @@ my %moduleName = ( HDR => 'Radiance', JP2 => 'Jpeg2000', JPEG => '', + JXL => 'Jpeg2000', LFP => 'Lytro', LRI => 0, MOV => 'QuickTime', @@ -764,6 +841,7 @@ my %moduleName = ( ORF => 'Olympus', PDB => 'Palm', PCD => 'PhotoCD', + PFM2 => 'Other', PHP => 0, PMP => 'Sony', PS => 'PostScript', @@ -777,19 +855,23 @@ my %moduleName = ( SWF => 'Flash', TAR => 0, TIFF => '', + TXT => 'Text', VRD => 'CanonVRD', WMF => 0, X3F => 'SigmaRaw', XCF => 'GIMP', ); +$testLen = 1024; # number of bytes to read when testing for magic number + # quick "magic number" file test used to avoid loading module unnecessarily: -# - regular expression evaluated on first 1024 bytes of file +# - regular expression evaluated on first $testLen bytes of file # - must match beginning at first byte in file # - this test must not be more stringent than module logic %magicNumber = ( AA => '.{4}\x57\x90\x75\x36', AIFF => '(FORM....AIF[FC]|AT&TFORM)', + ALIAS=> "book\0\0\0\0mark\0\0\0\0", APE => '(MAC |APETAGEX|ID3)', ASF => '\x30\x26\xb2\x75\x8e\x66\xcf\x11\xa6\xd9\x00\xaa\x00\x62\xce\x6c', AVC => '\+A\+V\+C\+', @@ -800,6 +882,8 @@ my %moduleName = ( BZ2 => 'BZh[1-9]\x31\x41\x59\x26\x53\x59', CHM => 'ITSF.{20}\x10\xfd\x01\x7c\xaa\x7b\xd0\x11\x9e\x0c\0\xa0\xc9\x22\xe6\xec', CRW => '(II|MM).{4}HEAP(CCDR|JPGM)', + CZI => 'ZISRAWFILE\0{6}', + DCX => '\xb1\x68\xde\x3a', DEX => "dex\n035\0", DICOM=> '(.{128}DICM|\0[\x02\x04\x06\x08]\0[\0-\x20]|[\x02\x04\x06\x08]\0[\0-\x20]\0)', DOCX => 'PK\x03\x04', @@ -807,31 +891,37 @@ my %moduleName = ( DR4 => 'IIII\x04\0\x04\0', DSS => '(\x02dss|\x03ds2)', DV => '\x1f\x07\0[\x3f\xbf]', # (not tested if extension recognized) + DWF => '\(DWF V\d', + DWG => 'AC10\d{2}\0', + DXF => '\s*0\s+\0?\s*SECTION\s+2\s+HEADER', EPS => '(%!PS|%!Ad|\xc5\xd0\xd3\xc6)', EXE => '(MZ|\xca\xfe\xba\xbe|\xfe\xed\xfa[\xce\xcf]|[\xce\xcf]\xfa\xed\xfe|Joy!peff|\x7fELF|#!\s*/\S*bin/|!\x0a)', EXIF => '(II\x2a\0|MM\0\x2a)', EXR => '\x76\x2f\x31\x01', EXV => '\xff\x01Exiv2', + FITS => 'SIMPLE = {20}T', FLAC => '(fLaC|ID3)', FLIF => 'FLIF[0-\x6f][0-2]', FLIR => '[AF]FF\0', FLV => 'FLV\x01', Font => '((\0\x01\0\0|OTTO|true|typ1)[\0\x01]|ttcf\0[\x01\x02]\0\0|\0[\x01\x02]|' . - '(.{6})?%!(PS-(AdobeFont-|Bitstream )|FontType1-)|Start(Comp|Master)?FontMetrics)', + '(.{6})?%!(PS-(AdobeFont-|Bitstream )|FontType1-)|Start(Comp|Master)?FontMetrics|wOF[F2])', FPF => 'FPF Public Image Format\0', FPX => '\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1', GIF => 'GIF8[79]a', GZIP => '\x1f\x8b\x08', HDR => '#\?(RADIANCE|RGBE)\x0a', HTML => '(\xef\xbb\xbf)?\s*(?i)<(!DOCTYPE\s+HTML|HTML|\?xml)', # (case insensitive) - ICC => '.{12}(scnr|mntr|prtr|link|spac|abst|nmcl|nkpf)(XYZ |Lab |Luv |YCbr|Yxy |RGB |GRAY|HSV |HLS |CMYK|CMY |[2-9A-F]CLR){2}', + ICC => '.{12}(scnr|mntr|prtr|link|spac|abst|nmcl|nkpf|cenc|mid |mlnk|mvis)(XYZ |Lab |Luv |YCbr|Yxy |RGB |GRAY|HSV |HLS |CMYK|CMY |[2-9A-F]CLR|nc..|\0{4}){2}', IND => '\x06\x06\xed\xf5\xd8\x1d\x46\xe5\xbd\x31\xef\xe7\xfe\x74\xb7\x1d', # ISO => signature is at byte 32768 ITC => '.{4}itch', JP2 => '(\0\0\0\x0cjP( |\x1a\x1a)\x0d\x0a\x87\x0a|\xff\x4f\xff\x51\0)', JPEG => '\xff\xd8\xff', - JSON => '\s*(\[\s*)?\{\s*"[^"]+"\s*:', + JSON => '(\xef\xbb\xbf)?\s*(\[\s*)?\{\s*"[^"]*"\s*:', + JXL => '\xff\x0a|\0\0\0\x0cJXL \x0d\x0a......ftypjxl ', LFP => '\x89LFP\x0d\x0a\x1a\x0a', + LIF => '\x70\0{3}.{4}\x2a.{4}<\0', LNK => '.{4}\x01\x14\x02\0{5}\xc0\0{6}\x46', LRI => 'LELR \0', M2TS => '(....)?\x47', @@ -843,13 +933,16 @@ my %moduleName = ( MPC => '(MP\+|ID3)', MOI => 'V6', MPEG => '\0\0\x01[\xb0-\xbf]', + 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', MRW => '\0MR[MI]', MXF => '\x06\x0e\x2b\x34\x02\x05\x01\x01\x0d\x01\x02', # (not tested if extension recognized) OGG => '(OggS|ID3)', ORF => '(II|MM)', - PDB => '.{60}(\.pdfADBE|TEXtREAd|BVokBDIC|DB99DBOS|PNRdPPrs|DataPPrs|vIMGView|PmDBPmDB|InfoINDB|ToGoToGo|SDocSilX|JbDbJBas|JfDbJFil|DATALSdb|Mdb1Mdb1|BOOKMOBI|DataPlkr|DataSprd|SM01SMem|TEXtTlDc|InfoTlIf|DataTlMl|DataTlPt|dataTDBP|TdatTide|ToRaTRPW|zTXTGPlm|BDOCWrdS)', # PCD => signature is at byte 2048 + PCX => '\x0a[\0-\x05]\x01[\x01\x02\x04\x08].{64}[\0-\x02]', + PDB => '.{60}(\.pdfADBE|TEXtREAd|BVokBDIC|DB99DBOS|PNRdPPrs|DataPPrs|vIMGView|PmDBPmDB|InfoINDB|ToGoToGo|SDocSilX|JbDbJBas|JfDbJFil|DATALSdb|Mdb1Mdb1|BOOKMOBI|DataPlkr|DataSprd|SM01SMem|TEXtTlDc|InfoTlIf|DataTlMl|DataTlPt|dataTDBP|TdatTide|ToRaTRPW|zTXTGPlm|BDOCWrdS)', PDF => '\s*%PDF-\d+\.\d+', + PFM => 'P[Ff]\x0a\d+ \d+\x0a[-+0-9.]+\x0a', PGF => 'PGF', PHP => '<\?php\s', PICT => '(.{10}|.{522})(\x11\x01|\x00\x11)', @@ -872,12 +965,14 @@ my %moduleName = ( RWZ => 'rawzor', SWF => '[FC]WS[^\0]', TAR => '.{257}ustar( )?\0', # (this doesn't catch old-style tar files) + TXT => '(\xff\xfe|(\0\0)?\xfe\xff|(\xef\xbb\xbf)?[\x07-\x0d\x20-\x7e\x80-\xfe]*$)', TIFF => '(II|MM)', # don't test magic number (some raw formats are different) VCard=> '(?i)BEGIN:(VCARD|VCALENDAR)\r\n', VRD => 'CANON OPTIONAL DATA\0', WMF => '(\xd7\xcd\xc6\x9a\0\0|\x01\0\x09\0\0\x03)', WTV => '\xb7\xd8\x00\x20\x37\x49\xda\x11\xa6\x4e\x00\x07\xe9\x5e\xad\x8d', X3F => 'FOVb', + MacOS=> '\0\x05\x16\x07\0.\0\0Mac OS X ', XCF => 'gimp xcf ', XMP => '\0{0,3}(\xfe\xff|\xff\xfe|\xef\xbb\xbf)?\0{0,3}\s*<', ZIP => 'PK\x03\x04', @@ -888,7 +983,26 @@ my %weakMagic = ( MP3 => 1 ); # file types that are determined by the process proc when FastScan == 3 # (when done, the process proc must exit after SetFileType if FastScan is 3) -my %processType = map { $_ => 1 } qw(JPEG TIFF XMP AIFF EXE Font PS Real VCard); +my %processType = map { $_ => 1 } qw(JPEG TIFF XMP AIFF EXE Font PS Real VCard TXT); + +# Compact/XMPShorthand option settings +my %compactOpt = ( + nopadding => 'NoPadding', noindent => 'NoIndent', nonewline => 'NoNewline', + shorthand => 'Shorthand', onedesc => 'OneDesc', + all => ['NoPadding','NoIndent','NoNewline','Shorthand','OneDesc'], + allspace => ['NoPadding','NoIndent','NoNewline'], allformat => ['Shorthand','OneDesc'], + # aliases to cover anticipated user typos + nonewlines => 'NoNewline', nospace => 'NoIndent', nospaces => 'NoIndent', + nopad => 'NoPadding', onedescr => 'OneDesc', + # allow numerical settings for backward compatibility + 0 => 'None', + 1 => 'NoPadding', + 2 => ['NoPadding','NoIndent'], + 3 => ['NoPadding','NoIndent','OneDesc'], + 4 => ['NoPadding','NoIndent','OneDesc','NoNewline'], + 5 => ['NoPadding','NoIndent','OneDesc','NoNewline','Shorthand'], +); +my %xmpShorthandOpt = ( 0 => 'None', 1 => 'Shorthand', 2 => ['Shorthand','OneDesc'] ); # lookup for valid character set names (keys are all lower case) %charsetName = ( @@ -907,6 +1021,7 @@ my %processType = map { $_ => 1 } qw(JPEG TIFF XMP AIFF EXE Font PS Real VCard); thai => 'Thai', cp874 => 'Thai', doslatinus => 'DOSLatinUS', cp437 => 'DOSLatinUS', doslatin1 => 'DOSLatin1', cp850 => 'DOSLatin1', + doscyrillic => 'DOSCyrillic', cp866 => 'DOSCyrillic', macroman => 'MacRoman', cp10000 => 'MacRoman', mac => 'MacRoman', roman => 'MacRoman', maclatin2 => 'MacLatin2', cp10029 => 'MacLatin2', maccyrillic => 'MacCyrillic', cp10007 => 'MacCyrillic', @@ -917,10 +1032,12 @@ my %processType = map { $_ => 1 } qw(JPEG TIFF XMP AIFF EXE Font PS Real VCard); maccroatian => 'MacCroatian', cp10082 => 'MacCroatian', ); -# default group priority for writing +# default family 0 group priority for writing # (NOTE: tags in groups not specified here will not be written unless # overridden by the module or specified when writing) -my @defaultWriteGroups = qw(EXIF IPTC XMP MakerNotes Photoshop ICC_Profile CanonVRD Adobe); +my @defaultWriteGroups = qw( + EXIF IPTC XMP MakerNotes QuickTime Photoshop ICC_Profile CanonVRD Adobe +); # group hash for ExifTool-generated tags my %allGroupsExifTool = ( 0 => 'ExifTool', 1 => 'ExifTool', 2 => 'ExifTool' ); @@ -932,7 +1049,7 @@ my %allGroupsExifTool = ( 0 => 'ExifTool', 1 => 'ExifTool', 2 => 'ExifTool' ); WRITABLE TABLE_DESC NOTES IS_OFFSET IS_SUBDIR EXTRACT_UNKNOWN NAMESPACE PREFERRED SRC_TABLE PRIORITY AVOID WRITE_GROUP LANG_INFO VARS DATAMEMBER - SET_GROUP1 + SET_GROUP1 PERMANENT INIT_TABLE ); # headers for various segment types @@ -953,7 +1070,7 @@ sub DummyWriteProc { return 1; } my %systemTagsNotes = ( Notes => q{ - extracted only if specifically requested or the SystemTags or RequestAll API + extracted only if specifically requested or the L or L API option is set }, ); @@ -969,7 +1086,7 @@ my %systemTagsNotes = ( # accept either scalar or scalar reference RawConv => '$self->ValidateImage(ref $val ? $val : \$val, $tag)', # we allow preview image to be set to '', but we don't want a zero-length value - # in the IFD, so set it temorarily to 'none'. Note that the length is <= 4, + # in the IFD, so set it temporarily to 'none'. Note that the length is <= 4, # so this value will fit in the IFD so the preview fixup won't be generated. ValueConvInv => '$val eq "" and $val="none"; $val', ); @@ -987,7 +1104,7 @@ my %systemTagsNotes = ( Notes => q{ returns errors that may have occurred while reading or writing a file. Any Error will prevent the file from being processed. Minor errors may be - downgraded to warnings with the -m or IgnoreMinorErrors option + downgraded to warnings with the -m or L option }, }, Warning => { @@ -995,8 +1112,8 @@ my %systemTagsNotes = ( Groups => \%allGroupsExifTool, Notes => q{ returns warnings that may have occurred while reading or writing a file. - Use the -a or Duplicates option to see all warnings if more than one - occurred. Minor warnings may be ignored with the -m or IgnoreMinorErrors + Use the -a or L option to see all warnings if more than one + occurred. Minor warnings may be ignored with the -m or L option. Minor warnings with a capital "M" in the "[Minor]" designation indicate that the processing is affected by ignoring the warning }, @@ -1008,7 +1125,7 @@ my %systemTagsNotes = ( Priority => 0, # to preserve order of JPEG COM segments }, Directory => { - Groups => { 1 => 'System' }, + Groups => { 1 => 'System', 2 => 'Other' }, Notes => q{ the directory of the file as specified in the call to ExifTool, or "." if no directory was specified. May be written to move the file to another @@ -1023,7 +1140,7 @@ my %systemTagsNotes = ( ValueConvInv => '$_ = $self->InverseFileName($val); m{[^/]$} and $_ .= "/"; $_', }, FileName => { - Groups => { 1 => 'System' }, + Groups => { 1 => 'System', 2 => 'Other' }, Writable => 1, WritePseudo => 1, DelCheck => q{"Can't delete"}, @@ -1038,11 +1155,18 @@ my %systemTagsNotes = ( RawConv => '$self->ConvertFileName($val)', ValueConvInv => '$self->InverseFileName($val)', }, + BaseName => { + Groups => { 1 => 'System', 2 => 'Other' }, + Notes => q{ + file name without extension. Not generated unless specifically requested or + the API L option is set + }, + }, FilePath => { - Groups => { 1 => 'System' }, + Groups => { 1 => 'System', 2 => 'Other' }, Notes => q{ absolute path of source file. Not generated unless specifically requested or - the RequestAll API option is set. Does not support Windows Unicode file + the API L option is set. Does not support Windows Unicode file names }, }, @@ -1065,11 +1189,11 @@ my %systemTagsNotes = ( sequence number for each source file when extracting or copying information, including files that fail the -if condition of the command-line application, beginning at 0 for the first file. Not generated unless specifically - requested or the RequestAll API option is set + requested or the API L option is set }, }, FileSize => { - Groups => { 1 => 'System' }, + Groups => { 1 => 'System', 2 => 'Other' }, Notes => q{ note that the print conversion for this tag uses historic prefixes: 1 kB = 1024 bytes, etc. @@ -1077,23 +1201,37 @@ my %systemTagsNotes = ( PrintConv => \&ConvertFileSize, }, ResourceForkSize => { - Groups => { 1 => 'System' }, + Groups => { 1 => 'System', 2 => 'Other' }, Notes => q{ size of the file's resource fork if it contains data. Mac OS only. If this - tag is generated the ExtractEmbedded option may be used to extract + tag is generated the L option may be used to extract resource-fork information as a sub-document. When writing, the resource fork is preserved by default, but it may be deleted with C<-rsrc:all=> on the command line }, PrintConv => \&ConvertFileSize, }, + ZoneIdentifier => { + Groups => { 1 => 'System', 2 => 'Other' }, + Notes => q{ + Windows only. Existence indicates that the file has a Zone.Identifier + alternate data stream, which is used by some Windows browsers to mark + downloaded files as possibly unsafe to run. May be deleted to remove this + stream. Requires Win32API::File + }, + Writable => 1, + WritePseudo => 1, + Protected => 1, + }, FileType => { + Groups => { 2 => 'Other' }, Notes => q{ a short description of the file type. For many file types this is the just the uppercase file extension }, }, FileTypeExtension => { + Groups => { 2 => 'Other' }, Notes => q{ a common lowercase extension for this file type, or uppercase with the -n option @@ -1136,8 +1274,9 @@ my %systemTagsNotes = ( the filesystem creation date/time. Windows/Mac only. In Windows, the file creation date/time is preserved by default when writing if Win32API::File and Win32::API are available. On Mac, this tag is extracted only if it or - the MacOS group is specifically requested or the RequestAll API option is - set to 2 or higher. Requires "setfile" for writing on Mac + the MacOS group is specifically requested or the API L option is + set to 2 or higher. Requires "setfile" for writing on Mac, which may be + installed by typing C in the Terminal }, Groups => { 1 => 'System', 2 => 'Time' }, Writable => 1, @@ -1166,7 +1305,7 @@ my %systemTagsNotes = ( PrintConv => '$self->ConvertDateTime($val)', }, FilePermissions => { - Groups => { 1 => 'System' }, + Groups => { 1 => 'System', 2 => 'Other' }, Notes => q{ r=read, w=write and x=execute permissions for the file owner, group and others. The ValueConv value is an octal number so bit test operations on @@ -1176,10 +1315,19 @@ my %systemTagsNotes = ( WritePseudo => 1, DelCheck => q{"Can't delete"}, Protected => 1, # all writable pseudo-tags must be protected! - ValueConv => 'sprintf("%.3o", $val & 0777)', - ValueConvInv => 'oct($val)', + ValueConv => 'sprintf("%.3o", $val)', + ValueConvInv => 'oct($val & 07777)', PrintConv => sub { - my ($mask, $str, $val) = (0400, '', oct(shift)); + my ($mask, $val) = (0400, oct(shift)); + my %types = ( + 0010000 => 'p', + 0020000 => 'c', + 0040000 => 'd', + 0060000 => 'b', + 0120000 => 'l', + 0140000 => 's', + ); + my $str = $types{$val & 0170000} || '-'; while ($mask) { foreach (qw(r w x)) { $str .= $val & $mask ? $_ : '-'; @@ -1190,6 +1338,7 @@ my %systemTagsNotes = ( }, PrintConvInv => sub { my ($bit, $val, $str) = (8, 0, shift); + $str = substr($str, 1) if length($str) == 10; return undef if length($str) != 9; while ($bit >= 0) { foreach (qw(r w x)) { @@ -1201,9 +1350,9 @@ my %systemTagsNotes = ( }, }, FileAttributes => { - Groups => { 1 => 'System' }, + Groups => { 1 => 'System', 2 => 'Other' }, Notes => q{ - extracted only if specifically requested or the SystemTags or RequestAll API + extracted only if specifically requested or the L or L API option is set. 2 or 3 values: 0. File type, 1. Attribute bits, 2. Windows attribute bits if Win32API::File is available }, @@ -1248,17 +1397,17 @@ my %systemTagsNotes = ( }}], }, FileDeviceID => { - Groups => { 1 => 'System' }, + Groups => { 1 => 'System', 2 => 'Other' }, %systemTagsNotes, PrintConv => '(($val >> 24) & 0xff) . "." . ($val & 0xffffff)', # (major.minor) }, - FileDeviceNumber => { Groups => { 1 => 'System' }, %systemTagsNotes }, - FileInodeNumber => { Groups => { 1 => 'System' }, %systemTagsNotes }, - FileHardLinks => { Groups => { 1 => 'System' }, %systemTagsNotes }, + FileDeviceNumber => { Groups => { 1 => 'System', 2 => 'Other' }, %systemTagsNotes }, + FileInodeNumber => { Groups => { 1 => 'System', 2 => 'Other' }, %systemTagsNotes }, + FileHardLinks => { Groups => { 1 => 'System', 2 => 'Other' }, %systemTagsNotes }, FileUserID => { - Groups => { 1 => 'System' }, + Groups => { 1 => 'System', 2 => 'Other' }, Notes => q{ - extracted only if specifically requested or the SystemTags or RequestAll API + extracted only if specifically requested or the L or L API option is set. Returns user ID number with the -n option, or name otherwise. May be written with either user name or number }, @@ -1270,9 +1419,9 @@ my %systemTagsNotes = ( PrintConvInv => 'eval { getpwnam($val) } || ($val=~/[^0-9]/ ? undef : $val)', }, FileGroupID => { - Groups => { 1 => 'System' }, + Groups => { 1 => 'System', 2 => 'Other' }, Notes => q{ - extracted only if specifically requested or the SystemTags or RequestAll API + extracted only if specifically requested or the L or L API option is set. Returns group ID number with the -n option, or name otherwise. May be written with either group name or number }, @@ -1283,8 +1432,8 @@ my %systemTagsNotes = ( PrintConv => 'eval { getgrgid($val) } || $val', PrintConvInv => 'eval { getgrnam($val) } || ($val=~/[^0-9]/ ? undef : $val)', }, - FileBlockSize => { Groups => { 1 => 'System' }, %systemTagsNotes }, - FileBlockCount => { Groups => { 1 => 'System' }, %systemTagsNotes }, + FileBlockSize => { Groups => { 1 => 'System', 2 => 'Other' }, %systemTagsNotes }, + FileBlockCount => { Groups => { 1 => 'System', 2 => 'Other' }, %systemTagsNotes }, HardLink => { Writable => 1, DelCheck => q{"Can't delete"}, @@ -1292,16 +1441,34 @@ my %systemTagsNotes = ( WritePseudo => 1, Protected => 1, Notes => q{ - this write-only tag is used to create a hard link to the file. If the file - is edited, copied, renamed or moved in the same operation as writing - HardLink, then the link is made to the updated file. Note that subsequent - editing of either the linked file or the original by the exiftool - application will break the link unless the -overwrite_original_in_place - option is used + this write-only tag is used to create a hard link with the specified name to + the source file. If the source file is edited, copied, renamed or moved in + the same operation as writing HardLink, then the link is made to the updated + file. Note that subsequent editing of either hard-linked file by exiftool + will break the link unless the -overwrite_original_in_place option is used }, ValueConvInv => '$val=~tr/\\\\/\//; $val', }, - MIMEType => { Notes => 'the MIME type of the source file' }, + SymLink => { + Writable => 1, + DelCheck => q{"Can't delete"}, + WriteOnly => 1, + WritePseudo => 1, + Protected => 1, + Notes => q{ + this write-only tag is used to create a symbolic link with the specified + name to the source file. If the source file is edited, copied, renamed or + moved in the same operation as writing SymLink, then the link is made to the + updated file. The link uses an absolute path unless it is created in the + current working directory. Valid only for file systems that support + symbolic links. Note that subsequent editing of the file via the symbolic + link by exiftool will cause the link to be replaced by the edited file + without changing the original unless the -overwrite_original_in_place option + is used + }, + ValueConvInv => '$val=~tr/\\\\/\//; $val', + }, + MIMEType => { Notes => 'the MIME type of the source file', Groups => { 2 => 'Other' } }, ImageWidth => { Notes => 'the width of the image in number of pixels' }, ImageHeight => { Notes => 'the height of the image in number of pixels' }, XResolution => { Notes => 'the horizontal pixel resolution' }, @@ -1313,7 +1480,7 @@ my %systemTagsNotes = ( is generated only if specifically requested }, Groups => { 0 => 'EXIF', 1 => 'EXIF' }, - Flags => ['Writable' ,'Protected', 'Binary'], + Flags => ['Writable' ,'Protected', 'Binary', 'DelGroup'], WriteCheck => q{ return undef if $val =~ /^(II\x2a\0|MM\0\x2a)/; return 'Invalid EXIF data'; @@ -1325,7 +1492,7 @@ my %systemTagsNotes = ( requested }, Groups => { 0 => 'IPTC', 1 => 'IPTC' }, - Flags => ['Writable', 'Protected', 'Binary'], + Flags => ['Writable', 'Protected', 'Binary', 'DelGroup'], Priority => 0, # so main IPTC (which hopefully comes first) takes priority WriteCheck => q{ return undef if $val =~ /^(\x1c|\0+$)/; @@ -1338,20 +1505,25 @@ my %systemTagsNotes = ( into multiple blocks. This tag is generated only if specifically requested }, Groups => { 0 => 'XMP', 1 => 'XMP' }, - Flags => ['Writable', 'Protected', 'Binary'], + Flags => ['Writable', 'Protected', 'Binary', 'DelGroup'], Priority => 0, # so main xmp (which usually comes first) takes priority WriteCheck => q{ require Image::ExifTool::XMP; return Image::ExifTool::XMP::CheckXMP($self, $tagInfo, \$val); }, }, + XML => { + Notes => 'the XML data block, extracted for some file types', + Groups => { 0 => 'XML', 1 => 'XML' }, + Binary => 1, + }, ICC_Profile => { Notes => q{ the full ICC_Profile data block. This tag is generated only if specifically requested }, Groups => { 0 => 'ICC_Profile', 1 => 'ICC_Profile' }, - Flags => ['Writable' ,'Protected', 'Binary'], + Flags => ['Writable' ,'Protected', 'Binary', 'DelGroup'], WriteCheck => q{ require Image::ExifTool::ICC_Profile; return Image::ExifTool::ICC_Profile::ValidateICC(\$val); @@ -1363,7 +1535,7 @@ my %systemTagsNotes = ( specifically requested }, Groups => { 0 => 'CanonVRD', 1 => 'CanonVRD' }, - Flags => ['Writable' ,'Protected', 'Binary'], + Flags => ['Writable' ,'Protected', 'Binary', 'DelGroup'], Permanent => 0, # (this is 1 by default for MakerNotes tags) WriteCheck => q{ return undef if $val =~ /^CANON OPTIONAL DATA\0/; @@ -1481,7 +1653,7 @@ my %systemTagsNotes = ( Groups => { 0 => 'ExifTool', 1 => 'ExifTool', 2 => 'Other' }, Notes => q{ the clock time in seconds taken by ExifTool to extract information from this - file. Not generated unless specifically requested or the RequestAll API + file. Not generated unless specifically requested or the L API option is set. Requires Time::HiRes }, PrintConv => 'sprintf("%.3g s", $val)', @@ -1493,7 +1665,7 @@ my %systemTagsNotes = ( sub-sampling values to generate the value of this tag. The result is compared to known values in an attempt to deduce the originating software based only on the JPEG image data. For performance reasons, this tag is - generated only if specifically requested or the RequestAll API option is set + generated only if specifically requested or the API L option is set to 3 or higher }, }, @@ -1501,17 +1673,24 @@ my %systemTagsNotes = ( Notes => q{ an estimate of the IJG JPEG quality setting for the image, calculated from the quantization tables. For performance reasons, this tag is generated - only if specifically requested or the RequestAll API option is set to 3 or + only if specifically requested or the API L option is set to 3 or higher }, }, + JPEGImageLength => { + Notes => q{ + byte length of JPEG image without metadata. For performance reasons, this + tag is generated only if specifically requested or the API L option + is set to 3 or higher + }, + }, # Validate (added from Validate.pm) Now => { Groups => { 0 => 'ExifTool', 1 => 'ExifTool', 2 => 'Time' }, Notes => q{ the current date/time. Useful when setting the tag values, eg. C<"-modifydate. Not generated unless specifically requested or the - RequestAll API option is set + API L option is set }, PrintConv => '$self->ConvertDateTime($val)', }, @@ -1522,7 +1701,7 @@ my %systemTagsNotes = ( YYYYmmdd-HHMM-SSNN-PPPP-RRRRRRRRRRRR, where Y=year, m=month, d=day, H=hour, M=minute, S=second, N=file sequence number in hex, P=process ID in hex, and R=random hex number; without dashes with the -n option. Not generated - unless specifically requested or the RequestAll API option is set + unless specifically requested or the API L option is set }, PrintConv => '$val =~ s/(.{8})(.{4})(.{4})(.{4})/$1-$2-$3-$4-/; $val', }, @@ -1564,7 +1743,7 @@ my %systemTagsNotes = ( causes GPS information to be written into the EXIF or XMP of the target files. The local system timezone is assumed if the date/time value does not contain a timezone. May be deleted to delete associated GPS tags. A group - name of 'EXIF' or 'XMP' may be specified to write or delete only EXIF or XMP + name of "EXIF" or "XMP" may be specified to write or delete only EXIF or XMP GPS tags }, DelCheck => q{ @@ -1602,14 +1781,31 @@ my %systemTagsNotes = ( Writable => 1, WriteOnly => 1, Notes => q{ - write-only tag used to force EXIF, IPTC and/or XMP in a file to be - rewritten. May be set to "EXIF", "IPTC" or "XMP" to force the corresponding - metadata type to be rewritten, "FixBase" to cause EXIF to be rewritten only if - the MakerNotes offset base was fixed, or "All" to rewrite all of these metadata - types. Values are case insensitive, and multiple values may be separated with - commas, eg. C<-ForceWrite=exif,xmp> + write-only tag used to force metadata in a file to be rewritten even if no + tag values are changed. May be set to "EXIF", "IPTC", "XMP" or "PNG" to + force the corresponding metadata type to be rewritten, "FixBase" to cause + EXIF to be rewritten only if the MakerNotes offset base was fixed, or "All" + to rewrite all of these metadata types. Values are case insensitive, and + multiple values may be separated with commas, eg. C<-ForceWrite=exif,xmp> }, }, + EmbeddedVideo => { Groups => { 0 => 'Trailer', 2 => 'Video' } }, + Trailer => { + Groups => { 0 => 'Trailer' }, + Notes => q{ + the full JPEG trailer data block. Extracted only if specifically requested + or the API RequestAll option is set to 3 or higher + }, + Writable => 1, + Protected => 1, + }, + PageCount => { Notes => 'the number of pages in a multi-page TIFF document' }, +); + +# tags defined by UserParam option (added at runtime) +%Image::ExifTool::UserParam = ( + GROUPS => { 0 => 'UserParam', 1 => 'UserParam', 2 => 'Other' }, + PRIORITY => 0, ); # YCbCrSubSampling values (used by JPEG SOF, EXIF and XMP) @@ -1761,6 +1957,8 @@ my %systemTagsNotes = ( return \$img; }, }, + # Apple may add "AMPF" to the end of the JFIF record, + # possibly indicating the existence of MPF images (ref forum12677) ); # Composite tags (accumulation of all Composite tag tables) @@ -1772,6 +1970,8 @@ my %systemTagsNotes = ( WRITE_PROC => \&DummyWriteProc, ); +my %compositeID; # lookup for new ID's of Composite tags based on original ID + # static private ExifTool variables %allTables = ( ); # list of all tables loaded (except Composite tags) @@ -1898,6 +2098,10 @@ sub Options($$;@) } } $oldVal = $$options{$param}; + if (ref $oldVal eq 'HASH' and ($param eq 'Compact' or $param eq 'XMPShorthand')) { + # get previous Compact/XMPShorthand setting + $oldVal = $$oldVal{$param}; + } last unless @_; my $newVal = shift; if ($param eq 'Lang') { @@ -1907,12 +2111,15 @@ sub Options($$;@) $$options{$param} = $newVal; delete $$self{CUR_LANG}; # make sure the language is available - } elsif (eval "require Image::ExifTool::Lang::$newVal") { - my $xlat = "Image::ExifTool::Lang::${newVal}::Translate"; - no strict 'refs'; - if (%$xlat) { - $$self{CUR_LANG} = \%$xlat; - $$options{$param} = $newVal; + } else { + my %langs = map { $_ => 1 } @langs; + if ($langs{$newVal} and eval "require Image::ExifTool::Lang::$newVal") { + my $xlat = "Image::ExifTool::Lang::${newVal}::Translate"; + no strict 'refs'; + if (%$xlat) { + $$self{CUR_LANG} = \%$xlat; + $$options{$param} = $newVal; + } } } # else don't change Lang } elsif ($param eq 'Exclude' and defined $newVal) { @@ -1946,31 +2153,45 @@ sub Options($$;@) } elsif ($param eq 'UserParam') { # clear options if $newVal is undef defined $newVal or $$options{$param} = {}, next; + my $table = GetTagTable('Image::ExifTool::UserParam'); # allow initialization of entire UserParam hash if (ref $newVal eq 'HASH') { my %newParams; - $newParams{lc $_} = $$newVal{$_} foreach sort keys %$newVal; + foreach (sort keys %$newVal) { + my $lcTag = lc $_; + $newParams{$lcTag} = $$newVal{$_}; + delete $$table{$lcTag}; + AddTagToTable($table, $lcTag, $_); + } $$options{$param} = \%newParams; next; } - my $force; + my ($force, $paramName); # set/reset single UserParam parameter if ($newVal =~ /(.*?)=(.*)/s) { - $param = lc $1; + $paramName = $1; $newVal = $2; - $force = 1 if $param =~ s/\^$//; + $force = 1 if $paramName =~ s/\^$//; + $paramName =~ tr/-_a-zA-Z0-9#//dc; + $param = lc $paramName; } else { - $param = lc $newVal; + ($param = lc $newVal) =~ tr/-_a-zA-Z0-9#//dc; undef $newVal; } + delete $$table{$param}; $oldVal = $$options{UserParam}{$param}; if (defined $newVal) { if (length $newVal or $force) { $$options{UserParam}{$param} = $newVal; + AddTagToTable($table, $param, $paramName); } else { delete $$options{UserParam}{$param}; } } + # remove alternate version of tag + $param .= '#' unless $param =~ s/#$//; + delete $$table{$param}; + delete $$options{UserParam}{$param}; } elsif ($param eq 'RequestTags') { if (defined $newVal) { # parse list from delimited string if necessary @@ -1982,14 +2203,29 @@ sub Options($$;@) /^(.*:)?([-\w?*]*)#?$/ or next; push @{$$options{$param}}, lc($2) if $2; next unless $1; + # add requested groups with trailing colon push @{$$options{$param}}, lc($_).':' foreach split /:/, $1; } } else { $$options{$param} = undef; # clear the list } + } elsif ($param eq 'IgnoreTags') { + if (defined $newVal) { + # parse list from delimited string if necessary + my @ignoreList = (ref $newVal eq 'ARRAY') ? @$newVal : ($newVal =~ /[-\w?*:]+/g); + ExpandShortcuts(\@ignoreList); + # add to existing tags to ignore + $$options{$param} or $$options{$param} = { }; + foreach (@ignoreList) { + /^(.*:)?([-\w?*]+)#?$/ or next; + $$options{$param}{lc $2} = 1; + } + } else { + $$options{$param} = undef; # clear the option + } } elsif ($param eq 'ListJoin') { $$options{$param} = $newVal; - # ListJoin just sets the List and ListSep options for backward compatibility + # set the old List and ListSep options for backward compatibility if (defined $newVal) { $$options{List} = 0; $$options{ListSep} = $newVal; @@ -1997,6 +2233,27 @@ sub Options($$;@) $$options{List} = 1; # (ListSep must be defined) } + } elsif ($param eq 'List') { + $$options{$param} = $newVal; + # set the new ListJoin option for forward compatibility + $$options{ListJoin} = $newVal ? undef : $$options{ListSep}; + } elsif ($param eq 'Compact' or $param eq 'XMPShorthand') { + # set Compact and XMPShorthand options, preserving backward compatibility + my ($p, %compact); + foreach $p ('Compact','XMPShorthand') { + my $val = $param eq $p ? $newVal : $$options{Compact}{$p}; + if (defined $val) { + my @v = ($val =~ /\w+/g); + my $opt = ($p eq 'Compact') ? \%compactOpt : \%xmpShorthandOpt; + foreach (@v) { + my $set = $$opt{lc $_} or warn("Invalid $p setting '${_}'\n"), return $oldVal; + ref $set or $compact{$set} = 1, next; + $compact{$_} = 1 foreach @$set; + } + } + $compact{$p} = $val; # preserve most recent setting + } + $$options{Compact} = $$options{XMPShorthand} = \%compact; } else { if ($param eq 'Escape') { # set ESCAPE_PROC @@ -2052,7 +2309,7 @@ sub ClearOptions($) CharsetPhotoshop => 'Latin', # internal encoding for Photoshop resource names CharsetQuickTime => 'MacRoman', # internal QuickTime string encoding CharsetRIFF => 0, # internal RIFF string encoding (0=default to Latin) - Compact => undef, # compact XMP and IPTC data + Compact => { }, # write compact XMP Composite => 1, # flag to calculate Composite tags Compress => undef, # flag to write new values as compressed if possible CoordFormat => undef, # GPS lat/long coordinate format @@ -2064,6 +2321,7 @@ sub ClearOptions($) ExtractEmbedded =>undef,# flag to extract information from embedded documents FastScan => undef, # flag to avoid scanning for trailer Filter => undef, # output filter for all tag values + FilterW => undef, # input filter when writing tag values FixBase => undef, # fix maker notes base offsets GeoMaxIntSecs => 1800, # geotag maximum interpolation time (secs) GeoMaxExtSecs => 1800, # geotag maximum extrapolation time (secs) @@ -2073,9 +2331,11 @@ sub ClearOptions($) GeoSpeedRef => undef, # geotag GPSSpeedRef GlobalTimeShift => undef, # apply time shift to all extracted date/time values # Group# => undef, # return tags for specified groups in family # + HexTagIDs => 0, # use hex tag ID's in family 7 group names HtmlDump => 0, # HTML dump (0-3, higher # = bigger limit) HtmlDumpBase => undef, # base address for HTML dump IgnoreMinorErrors => undef, # ignore minor errors when reading/writing + IgnoreTags => undef, # list of tags to ignore when extracting Lang => $defaultLang,# localized language for descriptions etc LargeFileSupport => undef, # flag indicating support of 64-bit file offsets List => undef, # extract lists of PrintConv values into arrays [no longer documented] @@ -2086,14 +2346,17 @@ sub ClearOptions($) MakerNotes => undef, # extract maker notes as a block MDItemTags => undef, # extract MacOS metadata item tags MissingTagValue =>undef,# value for missing tags when expanded in expressions + NoMultiExif => undef, # raise error when writing multi-segment EXIF NoPDFList => undef, # flag to avoid splitting PDF List-type tag values Password => undef, # password for password-protected PDF documents - PNGEarlyXMP => undef, # write XMP in PNG images before IDAT chunk PrintConv => 1, # flag to enable print conversion + QuickTimeHandler => 1, # flag to add mdir Handler to newly created Meta box + QuickTimePad=> undef, # flag to preserve padding of QuickTime CR3 tags QuickTimeUTC=> undef, # assume that QuickTime date/time tags are stored as UTC RequestAll => undef, # extract all tags that must be specifically requested RequestTags => undef, # extra tags to request (on top of those in the tag list) - SavePath => undef, # (undocumented) save family 5 location path + SaveFormat => undef, # save family 6 tag TIFF format + SavePath => undef, # save family 5 location path ScanForXMP => undef, # flag to scan for XMP information in all files Sort => 'Input', # order to sort found tags (Input, File, Tag, Descr, Group#) Sort2 => 'File', # secondary sort order for tags in a group (File, Tag, Descr) @@ -2103,12 +2366,13 @@ sub ClearOptions($) TextOut => \*STDOUT,# file for Verbose/HtmlDump output TimeZone => undef, # local time zone Unknown => 0, # flag to get values of unknown tags (0-2) - UserParam => { }, # user parameters for InsertTagValues() + UserParam => { }, # user parameters for additional user-defined tag values Validate => undef, # perform additional validation Verbose => 0, # print verbose messages (0-5, higher # = more verbose) WriteMode => 'wcg', # enable all write modes by default XAttrTags => undef, # extract MacOS extended attribute tags XMPAutoConv => 1, # automatic conversion of unknown XMP tag values + XMPShorthand=> 0, # (unused, but needed for backward compatibility) }; # keep necessary member variables in sync with options delete $$self{CUR_LANG}; @@ -2134,10 +2398,10 @@ sub ExtractInfo($;@) local $_; my $self = shift; my $options = $$self{OPTIONS}; # pointer to current options - my $fast = $$options{FastScan}; + my $fast = $$options{FastScan} || 0; my $req = $$self{REQ_TAG_LOOKUP}; my $reqAll = $$options{RequestAll} || 0; - my (%saveOptions, $reEntry, $rsize, $type, @startTime); + my (%saveOptions, $reEntry, $rsize, $zid, $type, @startTime, $saveOrder, $isDir); # check for internal ReEntry option to allow recursive calls to ExtractInfo if (ref $_[1] eq 'HASH' and $_[1]{ReEntry} and @@ -2151,6 +2415,7 @@ sub ExtractInfo($;@) EXIF_POS => $$self{EXIF_POS}, FILE_TYPE => $$self{FILE_TYPE}, }; + $saveOrder = GetByteOrder(), $$self{RAF} = new File::RandomAccess($_[0]); $$self{PROCESSED} = { }; delete $$self{EXIF_DATA}; @@ -2207,16 +2472,13 @@ sub ExtractInfo($;@) unless ($filename eq '-') { # extract file name from pipe if necessary $realname =~ /\|$/ and $realname =~ s/^.*?"(.*?)".*/$1/s; - my ($dir, $name); - if (eval { require File::Basename }) { - $dir = File::Basename::dirname($realname); - $name = File::Basename::basename($realname); - } else { - ($name = $realname) =~ tr/\\/\//; - # remove path - $dir = length($1) ? $1 : '/' if $name =~ s/(.*)\///; - } + my ($dir, $name) = SplitFileName($realname); $self->FoundTag('FileName', $name); + if ($$req{basename} or + ($reqAll and not $$self{EXCL_TAG_LOOKUP}{basename})) + { + $self->FoundTag('BaseName', $name =~ /(.*)\./ ? $1 : $name); + } $self->FoundTag('Directory', $dir) if defined $dir and length $dir; if ($$req{filepath} or ($reqAll and not $$self{EXCL_TAG_LOOKUP}{filepath})) @@ -2231,6 +2493,17 @@ sub ExtractInfo($;@) } # get size of resource fork on Mac OS $rsize = -s "$filename/..namedfork/rsrc" if $^O eq 'darwin' and not $$self{IN_RESOURCE}; + # check to see if Zone.Identifier file exists in Windows + if ($^O eq 'MSWin32' and eval { require Win32API::File }) { + my $wattr; + my $zfile = "${filename}:Zone.Identifier"; + if ($self->EncodeFileName($zfile)) { + $wattr = eval { Win32API::File::GetFileAttributesW($zfile) }; + } else { + $wattr = eval { Win32API::File::GetFileAttributes($zfile) }; + } + $zid = 1 unless $wattr == Win32API::File::INVALID_FILE_ATTRIBUTES(); + } } # open the file if ($self->Open(\*EXIFTOOL_FILE, $filename)) { @@ -2240,6 +2513,8 @@ sub ExtractInfo($;@) # in Windows cmd shell pipe even though it really failed $$raf{TESTED} = -1 if $filename eq '-' or $filename =~ /\|$/; $$self{RAF} = $raf; + } elsif ($self->IsDirectory($filename)) { + $isDir = 1; } else { $self->Error('Error opening file'); } @@ -2248,28 +2523,35 @@ sub ExtractInfo($;@) } } - if ($raf) { - my (@stat, $fileSize); + while ($raf or $isDir) { + my (@stat, $plainFile); if ($reEntry) { # we already set these tags + } elsif (not $raf) { + @stat = stat $filename; } elsif (not $$raf{FILE_PT}) { # get file size from image in memory $self->FoundTag('FileSize', length ${$$raf{BUFF_PT}}); } elsif (-f $$raf{FILE_PT}) { # get file tags if this is a plain file - $fileSize = -s _; @stat = stat _; - my ($aTime, $mTime, $cTime) = $self->GetFileTime($$raf{FILE_PT}); - $self->FoundTag('FileSize', $fileSize) if defined $fileSize; - $self->FoundTag('ResourceForkSize', $rsize) if $rsize; - $self->FoundTag('FileModifyDate', $mTime) if defined $mTime; - $self->FoundTag('FileAccessDate', $aTime) if defined $aTime; - my $cTag = $^O eq 'MSWin32' ? 'FileCreateDate' : 'FileInodeChangeDate'; - $self->FoundTag($cTag, $cTime) if defined $cTime; - $self->FoundTag('FilePermissions', $stat[2]) if defined $stat[2]; + $plainFile = 1; + # hack to patch Windows daylight savings time bug + @stat[8,9,10] = $self->GetFileTime($$raf{FILE_PT}) if $^O eq 'MSWin32'; } else { + # (note that Windows directories will still show the + # daylight savings time bug -- should fix this sometime) @stat = stat $$raf{FILE_PT}; } + my $fileSize = $stat[7]; + $self->FoundTag('FileSize', $stat[7]) if defined $stat[7]; + $self->FoundTag('ResourceForkSize', $rsize) if $rsize; + $self->FoundTag('ZoneIdentifier', 'Exists') if $zid; + $self->FoundTag('FileModifyDate', $stat[9]) if defined $stat[9]; + $self->FoundTag('FileAccessDate', $stat[8]) if defined $stat[8]; + my $cTag = $^O eq 'MSWin32' ? 'FileCreateDate' : 'FileInodeChangeDate'; + $self->FoundTag($cTag, $stat[10]) if defined $stat[10]; + $self->FoundTag('FilePermissions', $stat[2]) if defined $stat[2]; # extract more system info if SystemTags option is set if (@stat) { my $sys = $$options{SystemTags} || ($reqAll and not defined $$options{SystemTags}); @@ -2309,11 +2591,18 @@ sub ExtractInfo($;@) if ($crDate or $mdItem or $xattr) { require Image::ExifTool::MacOS; Image::ExifTool::MacOS::GetFileCreateDate($self, $filename) if $crDate; - Image::ExifTool::MacOS::ExtractMDItemTags($self, $filename) if $mdItem; + Image::ExifTool::MacOS::ExtractMDItemTags($self, $filename) if $mdItem and $plainFile; Image::ExifTool::MacOS::ExtractXAttrTags($self, $filename) if $xattr; } } - + # do whatever else we can with directories, then return + if ($isDir or (defined $stat[2] and ($stat[2] & 0170000) == 0040000)) { + $self->FoundTag('FileType', 'DIR'); + $self->FoundTag('FileTypeExtension', ''); + $self->BuildCompositeTags() if $$options{Composite}; + $raf->Close() if $raf; + return 1; + } # get list of file types to check my ($tiffType, %noMagic, $recognizedExt); my $ext = $$self{FILE_EXT} = GetFileExtension($realname); @@ -2321,12 +2610,22 @@ sub ExtractInfo($;@) $recognizedExt = $ext if defined $ext and not defined $magicNumber{$ext} and defined $moduleName{$ext} and not $moduleName{$ext}; my @fileTypeList = GetFileType($realname); + if ($fast >= 4) { + if (@fileTypeList) { + $type = shift @fileTypeList; + $self->SetFileType($$self{FILE_TYPE} = $type); + } else { + $self->Error('Unknown file type'); + } + $self->BuildCompositeTags() if $fast == 4 and $$options{Composite}; + last; # don't read the file + } if (@fileTypeList) { # add remaining types to end of list so we test them all my $pat = join '|', @fileTypeList; push @fileTypeList, grep(!/^($pat)$/, @fileTypes); $tiffType = $$self{FILE_EXT}; - unless ($fast and $fast == 3) { + unless ($fast == 3) { $noMagic{MXF} = 1; # don't do magic number test on MXF or DV files $noMagic{DV} = 1; } @@ -2339,20 +2638,24 @@ sub ExtractInfo($;@) # initialize the input file for seeking in binary data $raf->BinMode(); # set binary mode before we start reading my $pos = $raf->Tell(); # get file position so we can rewind - my %dirInfo = ( RAF => $raf, Base => $pos ); # loop through list of file types to test my ($buff, $seekErr); + my %dirInfo = ( RAF => $raf, Base => $pos, TestBuff => \$buff ); # read start of file for testing - my $testLen = 1024; $raf->Read($buff, $testLen) or $buff = ''; $raf->Seek($pos, 0) or $seekErr = 1; until ($seekErr) { my $unkHeader; $type = shift @fileTypeList; if ($type) { - # do quick test for this file type to avoid loading module unnecessarily - next if $magicNumber{$type} and $buff !~ /^$magicNumber{$type}/s and - not $noMagic{$type}; + if ($magicNumber{$type}) { + # do quick test for this file type to avoid loading module unnecessarily + next if $buff !~ /^$magicNumber{$type}/s and not $noMagic{$type}; + } else { + # keep checking for other types if we recognize this file only by extension + next if defined $moduleName{$type} and not $moduleName{$type}; + next if $fast > 2; # keep checking if we aren't processing the file + } next if $weakMagic{$type} and defined $recognizedExt; } elsif (not defined $type) { last; @@ -2372,7 +2675,7 @@ sub ExtractInfo($;@) $$self{FILE_TYPE} = $type; $dirInfo{Parent} = ($type eq 'TIFF') ? $tiffType : $type; # don't process the file when FastScan == 3 - if ($fast and $fast == 3 and not $processType{$type}) { + if ($fast == 3 and not $processType{$type}) { unless ($weakMagic{$type} and (not $ext or $ext ne $type)) { $self->SetFileType($dirInfo{Parent}); } @@ -2435,7 +2738,7 @@ sub ExtractInfo($;@) if ($$self{OPTIONS}{FastScan}) { $err = 'File header is all'; } else { - my $num = length $buff; + my $num = 0; for (;;) { $raf->Read($buff, 65536) or undef($num), last; $buff =~ /[^\Q$ch\E]/g and $num += pos($buff) - 1, last; @@ -2513,6 +2816,7 @@ sub ExtractInfo($;@) } } } + last; # (loop was a cheap "goto") } # generate Validate tag if requested @@ -2522,12 +2826,27 @@ sub ExtractInfo($;@) @startTime and $self->FoundTag('ProcessingTime', Time::HiRes::tv_interval(\@startTime)); + # add user-defined parameters that ended with '!' + if (%{$$options{UserParam}}) { + my $doMsg = $$options{Verbose}; + my $table = GetTagTable('Image::ExifTool::UserParam'); + foreach (sort keys %{$$options{UserParam}}) { + next unless /#$/; + if ($doMsg) { + $self->VPrint(0, "UserParam tags:\n"); + undef $doMsg; + } + $self->HandleTag($table, $_, $$options{UserParam}{$_}); + } + } + # restore original options %saveOptions and $$self{OPTIONS} = \%saveOptions; if ($reEntry) { # restore necessary members when exiting re-entrant code $$self{$_} = $$reEntry{$_} foreach keys %$reEntry; + SetByteOrder($saveOrder); } # ($type may be undef without an Error when processing sub-documents) @@ -2893,6 +3212,7 @@ sub GetValue($$;$) my $oldFilter = $$self{OPTIONS}{Filter}; delete $$self{OPTIONS}{Filter}; foreach (keys %$val) { + next unless defined $$val{$_}; $raw[$_] = $$rawValue{$$val{$_}}; ($val[$_], $prt[$_]) = $self->GetValue($$val{$_}, 'Both'); next if defined $val[$_] or not $$tagInfo{Require}{$_}; @@ -2907,30 +3227,9 @@ sub GetValue($$;$) } if (ref $conv eq 'HASH') { # look up converted value in hash - my $lc; - if (defined($value = $$conv{$val})) { - # override with our localized language PrintConv if available - if ($$self{CUR_LANG} and $convType eq 'PrintConv' and - # (no need to check for lang-alt tag names -- they won't have a PrintConv) - ref($lc = $$self{CUR_LANG}{$$tagInfo{Name}}) eq 'HASH' and - ($lc = $$lc{PrintConv}) and ($lc = $$lc{$value})) - { - $value = $self->Decode($lc, 'UTF8'); - } - } else { + if (not defined($value = $$conv{$val})) { if ($$conv{BITMASK}) { $value = DecodeBits($val, $$conv{BITMASK}, $$tagInfo{BitsPerWord}); - # override with localized language strings - if (defined $value and $$self{CUR_LANG} and $convType eq 'PrintConv' and - ref($lc = $$self{CUR_LANG}{$$tagInfo{Name}}) eq 'HASH' and - ($lc = $$lc{PrintConv})) - { - my @vals = split ', ', $value; - foreach (@vals) { - $_ = $$lc{$_} if defined $$lc{$_}; - } - $value = join ', ', @vals; - } } else { # use alternate conversion routine if available if ($$conv{OTHER}) { @@ -2943,12 +3242,30 @@ sub GetValue($$;$) if ($$tagInfo{PrintHex} and $val and IsInt($val) and $convType eq 'PrintConv') { - $val = sprintf('0x%x',$val); + $value = sprintf('Unknown (0x%x)',$val); + } else { + $value = "Unknown ($val)"; } - $value = "Unknown ($val)"; } } } + # override with our localized language PrintConv if available + my $tmp; + if ($$self{CUR_LANG} and $convType eq 'PrintConv' and + # (no need to check for lang-alt tag names -- they won't have a PrintConv) + ref($tmp = $$self{CUR_LANG}{$$tagInfo{Name}}) eq 'HASH' and + ($tmp = $$tmp{PrintConv})) + { + if ($$conv{BITMASK} and not defined $$conv{$val}) { + my @vals = split ', ', $value; + foreach (@vals) { + $_ = $$tmp{$_} if defined $$tmp{$_}; + } + $value = join ', ', @vals; + } elsif (defined($tmp = $$tmp{$value})) { + $value = $self->Decode($tmp, 'UTF8'); + } + } } else { # call subroutine or do eval to convert value local $SIG{'__WARN__'} = \&SetWarning; @@ -3010,7 +3327,7 @@ sub GetValue($$;$) # $valueConv is undefined if there was no print conversion done $valueConv = $value; } - $self->Filter(\$value) if defined $$self{OPTIONS}{Filter}; + $self->Filter($$self{OPTIONS}{Filter}, \$value); # return Both values as a list (ValueConv, PrintConv) return ($valueConv, $value); } @@ -3018,7 +3335,7 @@ sub GetValue($$;$) DoEscape($value, $$self{ESCAPE_PROC}) if $$self{ESCAPE_PROC}; # filter if necessary - $self->Filter(\$value) if defined $$self{OPTIONS}{Filter} and $type eq 'PrintConv'; + $self->Filter($$self{OPTIONS}{Filter}, \$value) if $$self{OPTIONS}{Filter} and $type eq 'PrintConv'; if (ref $value eq 'ARRAY') { if (defined $$self{OPTIONS}{ListItem}) { @@ -3045,8 +3362,9 @@ sub GetTagID($$) my ($self, $tag) = @_; my $tagInfo = $$self{TAG_INFO}{$tag}; return '' unless $tagInfo and defined $$tagInfo{TagID}; - return ($$tagInfo{TagID}, $$tagInfo{LangCode}) if wantarray; - return $$tagInfo{TagID}; + my $id = $$tagInfo{KeysID} || $$tagInfo{TagID}; + return ($id, $$tagInfo{LangCode}) if wantarray; + return $id; } #------------------------------------------------------------------------------ @@ -3101,12 +3419,12 @@ sub GetDescription($$) # Returns: Scalar context: group name (for family 0 if not otherwise specified) # List context: group name if family specified, otherwise list of # group names for each family. Returns '' for undefined tag. -# Notes: Mutiple families may be specified with ':' in family argument (eg. '1:2') +# Notes: Multiple families may be specified with ':' in family argument (eg. '1:2') sub GetGroup($$;$) { local $_; my ($self, $tag, $family) = @_; - my ($tagInfo, @groups, @families, $simplify, $byTagInfo, $ex); + my ($tagInfo, @groups, @families, $simplify, $byTagInfo, $ex, $noID); if (ref $tag eq 'HASH') { $tagInfo = $tag; $tag = $$tagInfo{Name}; @@ -3137,6 +3455,7 @@ sub GetGroup($$;$) $simplify = 1 unless $family =~ /^:/; undef $family; foreach (0..2) { $groups[$_] = $$groups{$_}; } + $noID = 1 if @families == 1 and $families[0] != 7; } else { return(($ex && $$ex{"G$family"}) || $$groups{$family}) if $family == 0 or $family == 2; $groups[1] = $$groups{1}; @@ -3148,11 +3467,30 @@ sub GetGroup($$;$) $groups[3] = 'Main'; $groups[4] = ($tag =~ /\((\d+)\)$/) ? "Copy$1" : ''; # handle dynamic group names if necessary - if ($ex and not $byTagInfo) { - $groups[0] = $$ex{G0} if $$ex{G0}; - $groups[1] = $$ex{G1} =~ /^\+(.*)/ ? "$groups[1]$1" : $$ex{G1} if $$ex{G1}; - $groups[3] = 'Doc' . $$ex{G3} if $$ex{G3}; - $groups[5] = $$ex{G5} || $groups[1] if defined $$ex{G5}; + unless ($byTagInfo) { + if ($ex) { + $groups[0] = $$ex{G0} if $$ex{G0}; + $groups[1] = $$ex{G1} =~ /^\+(.*)/ ? "$groups[1]$1" : $$ex{G1} if $$ex{G1}; + $groups[3] = 'Doc' . $$ex{G3} if $$ex{G3}; + $groups[5] = $$ex{G5} || $groups[1] if defined $$ex{G5}; + if (defined $$ex{G6}) { + $groups[5] = '' unless defined $groups[5]; # (can't leave a hole in the array) + $groups[6] = $$ex{G6}; + } + } + # generate tag ID group names unless obviously not needed + unless ($noID) { + my $id = $$tagInfo{KeysID} || $$tagInfo{TagID}; + if (not defined $id) { + $id = ''; # (just to be safe) + } elsif ($id =~ /^\d+$/) { + $id = sprintf('0x%x', $id) if $$self{OPTIONS}{HexTagIDs}; + } else { + $id =~ s/([^-_A-Za-z0-9])/sprintf('%.2x',ord $1)/ge; + } + $groups[7] = 'ID-' . $id; + defined $groups[$_] or $groups[$_] = '' foreach (5,6); + } } if ($family) { return $groups[$family] || '' if $family > 0; @@ -3170,7 +3508,11 @@ sub GetGroup($$;$) my @grps; # create list of group names (without identical adjacent groups if simplifying) foreach (@families) { - my $grp = $groups[$_] or next; + my $grp = $groups[$_]; + unless ($grp) { + next if $simplify; + $grp = ''; + } push @grps, $grp unless $simplify and @grps and $grp eq $grps[-1]; } # remove leading "Main:" if simplifying @@ -3215,18 +3557,20 @@ sub GetGroups($;$$) # Set priority for group where new values are written # Inputs: 0) ExifTool object reference, # 1-N) group names (reset to default if no groups specified) +# - used when new tag values are set (ie. before files are written) sub SetNewGroups($;@) { local $_; my ($self, @groups) = @_; @groups or @groups = @defaultWriteGroups; - my $count = @groups; + my $count = @groups * 10; my %priority; foreach (@groups) { - $priority{lc($_)} = $count--; + $priority{lc($_)} = $count; + $count -= 10; } - $priority{file} = 10; # 'File' group is always written (Comment) - $priority{composite} = 10; # 'Composite' group is always written + $priority{file} = 500; # 'File' group is always written (Comment) + $priority{composite} = 500; # 'Composite' group is always written # set write priority (higher # is higher priority) $$self{WRITE_PRIORITY} = \%priority; $$self{WRITE_GROUPS} = \@groups; @@ -3244,20 +3588,24 @@ sub BuildCompositeTags($) my $self = shift; $$self{BuildingComposite} = 1; - + my $compTable = GetTagTable('Image::ExifTool::Composite'); my @tagList = sort keys %$compTable; my $rawValue = $$self{VALUE}; - my (%tagsUsed, %cache); + my $compKeys = $$self{COMP_KEYS}; + my (%cache, $allBuilt); for (;;) { my (%notBuilt, $tag, @deferredTags); - $notBuilt{$_} = 1 foreach @tagList; + foreach (@tagList) { + $notBuilt{$$compTable{$_}{Name}} = 1 unless $specialTags{$_}; + } COMPOSITE_TAG: foreach $tag (@tagList) { next if $specialTags{$tag}; my $tagInfo = $self->GetTagInfo($compTable, $tag); next unless $tagInfo; + my $tagName = $$compTable{$tag}{Name}; # put required tags into array and make sure they all exist my $subDoc = ($$tagInfo{SubDoc} and $$self{DOC_COUNT}); my $require = $$tagInfo{Require} || { }; @@ -3308,8 +3656,12 @@ COMPOSITE_TAG: } elsif ($reqTag =~ /^(.*):(.+)/) { my ($reqGroup, $name) = ($1, $2); if ($reqGroup eq 'Composite' and $notBuilt{$name}) { - push @deferredTags, $tag; - next COMPOSITE_TAG; + # defer only until all other tags are built if + # we are inhibiting based on another Composite tag + unless ($$inhibit{$index} and $allBuilt) { + push @deferredTags, $tag; + next COMPOSITE_TAG; + } } # (CAREFUL! keys may not be sequential if one was deleted) my ($i, $key, @keys); @@ -3321,7 +3673,7 @@ COMPOSITE_TAG: # find first matching tag $key = $self->GroupMatches($reqGroup, \@keys); $reqTag = $key || "$name (0)"; - } elsif ($notBuilt{$reqTag}) { + } elsif ($notBuilt{$reqTag} and not $$inhibit{$index}) { # calculate this tag later if it relies on another # Composite tag which hasn't been calculated yet push @deferredTags, $tag; @@ -3343,34 +3695,34 @@ COMPOSITE_TAG: if ($docNum) { if ($found) { $$self{DOC_NUM} = $docNum; + # save pointers to all used tag keys + foreach (keys %tagKey) { + $$compKeys{$_} or $$compKeys{$_} = [ ]; + push @{$$compKeys{$tagKey{$_}}}, [ \%tagKey, $_ ]; + } $self->FoundTag($tagInfo, \%tagKey); delete $$self{DOC_NUM}; } next if ++$docNum <= $$self{DOC_COUNT}; last; } elsif ($found) { - delete $notBuilt{$tag}; # this tag is OK to build now + delete $notBuilt{$tagName}; # this tag is OK to build now # keep track of all Require'd tag keys foreach (keys %tagKey) { # only tag keys with same name as a Composite tag # can be replaced (also eliminates keys with # instance numbers which can't be replaced either) - next unless $$compTable{$tagKey{$_}}; - my $keyRef = \$tagKey{$_}; - $tagsUsed{$$keyRef} or $tagsUsed{$$keyRef} = [ ]; - push @{$tagsUsed{$$keyRef}}, $keyRef; + next unless $compositeID{$tagKey{$_}}; + } + # save pointers to all used tag keys + foreach (keys %tagKey) { + $$compKeys{$_} or $$compKeys{$_} = [ ]; + push @{$$compKeys{$tagKey{$_}}}, [ \%tagKey, $_ ]; } # save reference to tag key lookup as value for Composite tag my $key = $self->FoundTag($tagInfo, \%tagKey); - # check to see if we just replaced one of the tag keys we Require'd - if (defined $key and $tagsUsed{$key}) { - foreach (@{$tagsUsed{$key}}) { - $$_ = $$self{MOVED_KEY}; # replace with new tag key - } - delete $tagsUsed{$key}; # can't be replaced again - } } elsif (not defined $found) { - delete $notBuilt{$tag}; # tag can't be built anyway + delete $notBuilt{$tagName}; # tag can't be built anyway } last unless $subDoc; # don't process sub-documents if there is no chance to build this tag @@ -3396,16 +3748,30 @@ COMPOSITE_TAG: } last unless @deferredTags; if (@deferredTags == @tagList) { - # everything was deferred in the last pass, - # must be a circular dependency - warn "Circular dependency in Composite tags\n"; - last; + if ($allBuilt) { + # everything was deferred in the last pass, + # must be a circular dependency + warn "Circular dependency in Composite tags\n"; + last; + } + $allBuilt = 1; # try once more, ignoring Composite Inhibit tags } @tagList = @deferredTags; # calculate deferred tags now } delete $$self{BuildingComposite}; } +#------------------------------------------------------------------------------ +# Get reference to Composite tag info hash +# Inputs: 0) case-sensitive Composite tag name +# Returns: tagInfo hash or undef +sub GetCompositeTagInfo($) +{ + my $tag = shift; + return undef unless $compositeID{$tag}; + return $Image::ExifTool::Composite{$compositeID{$tag}[0]}; +} + #------------------------------------------------------------------------------ # Get tag name (removes copy index) # Inputs: 0) Tag key @@ -3469,7 +3835,15 @@ sub GetFileType(;$$) # return description if specified # (allow input $file to be a FileType for this purpose) if ($desc) { - $desc = $fileType ? $$fileType[1] : $fileDescription{$file}; + if ($fileType) { + if ($static_vars{OverrideFileDescription} and $static_vars{OverrideFileDescription}{$fileExt}) { + $desc = $static_vars{OverrideFileDescription}{$fileExt}; + } else { + $desc = $$fileType[1]; + } + } else { + $desc = $fileDescription{$file}; + } $desc .= ", $subType" if $subType; return $desc; } elsif ($fileType and (not defined $desc or $desc ne '0')) { @@ -3534,6 +3908,7 @@ sub Init($) foreach (keys %$self) { /[a-z]/ and delete $$self{$_}; } + undef %static_vars; # clear all static variables delete $$self{FOUND_TAGS}; # list of found tags delete $$self{EXIF_DATA}; # the EXIF data block delete $$self{EXIF_POS}; # EXIF position in file @@ -3559,6 +3934,7 @@ sub Init($) $$self{WRITTEN} = { }; # list of tags written (selected tags only) $$self{FORCE_WRITE}= { }; # ForceWrite lookup (set from ForceWrite tag) $$self{FOUND_DIR} = { }; # hash of directory names found in file + $$self{COMP_KEYS} = { }; # lookup for tag keys used in Composite tags $$self{PATH} = [ ]; # current subdirectory path in file when reading $$self{NUM_FOUND} = 0; # total number of tags found (incl. duplicates) $$self{CHANGED} = 0; # number of tags changed (writer only) @@ -3570,6 +3946,7 @@ sub Init($) $$self{Make} = ''; # camera make $$self{Model} = ''; # camera model $$self{CameraType} = ''; # Olympus camera type + $$self{FileType} = ''; # identified file type if ($self->Options('HtmlDump')) { require Image::ExifTool::HtmlDump; $$self{HTML_DUMP} = new Image::ExifTool::HtmlDump; @@ -3665,6 +4042,25 @@ sub NextTagKey($$) return undef; } +#------------------------------------------------------------------------------ +# Split file name into directory and name parts +# Inptus: 0) file name +# Returns: 0) directory, 1) filename +sub SplitFileName($) +{ + my $file = shift; + my ($dir, $name); + if (eval { require File::Basename }) { + $dir = File::Basename::dirname($file); + $name = File::Basename::basename($file); + } else { + ($name = $file) =~ tr/\\/\//; + # remove path + $dir = length($1) ? $1 : '/' if $name =~ s/(.*)\///; + } + return ($dir, $name); +} + #------------------------------------------------------------------------------ # Encode file name for calls to system i/o routines # Inputs: 0) ExifTool ref, 1) file name in CharSetFileName, 2) flag to force conversion @@ -3711,8 +4107,9 @@ sub Open($*$;$) my ($self, $fh, $file, $mode) = @_; $file =~ s/^([\s&])/.\/$1/; # protect leading whitespace or ampersand - # default to read mode ('<') unless input is a pipe - $mode = ($file =~ /\|$/ ? '' : '<') unless $mode; + # default to read mode ('<') unless input is a trusted pipe + $mode = (($file =~ /\|$/ and $$self{TRUST_PIPE}) ? '' : '<') unless $mode; + delete $$self{TRUST_PIPE}; if ($mode) { if ($self->EncodeFileName($file)) { # handle Windows Unicode file name @@ -3730,7 +4127,13 @@ sub Open($*$;$) $create = Win32API::File::OPEN_EXISTING(); } } - my $wh = eval { Win32API::File::CreateFileW($file, $access, 0, [], $create, 0, []) }; + my $share = 0; + eval { + unless ($access & Win32API::File::GENERIC_WRITE()) { + $share = Win32API::File::FILE_SHARE_READ() | Win32API::File::FILE_SHARE_WRITE(); + } + }; + my $wh = eval { Win32API::File::CreateFileW($file, $access, $share, [], $create, 0, []) }; return undef unless $wh; my $fd = eval { Win32API::File::OsFHandleOpenFd($wh, 0) }; if (not defined $fd or $fd < 0) { @@ -3758,12 +4161,15 @@ sub Exists($$) if ($self->EncodeFileName($file)) { local $SIG{'__WARN__'} = \&SetWarning; my $wh = eval { Win32API::File::CreateFileW($file, - Win32API::File::GENERIC_READ(), 0, [], + Win32API::File::GENERIC_READ(), + Win32API::File::FILE_SHARE_READ(), [], Win32API::File::OPEN_EXISTING(), 0, []) }; return 0 unless $wh; eval { Win32API::File::CloseHandle($wh) }; } else { - return -e $file; + # (named pipes already exist, but we pretend that they don't + # so we will be able to write them, so test with for pipe -p) + return(-e $file and not -p $file); } return 1; } @@ -3798,7 +4204,14 @@ sub GetFileTime($$) # open file by name if necessary unless (ref $file) { local *FH; - $self->Open(\*FH, $file) or $self->Warn("GetFileTime error for '${file}'"), return (); + unless ($self->Open(\*FH, $file)) { + if ($self->IsDirectory($file)) { + my @rtn = (stat $file)[8, 9, 10]; + return @rtn if defined $rtn[0]; + } + $self->Warn("GetFileTime error for '${file}'"); + return (); + } $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 time is in effect @@ -3859,11 +4272,12 @@ sub ParseArguments($;@) $$self{REQ_TAG_LOOKUP} = { }; $$self{EXCL_TAG_LOOKUP} = { }; $$self{IO_TAG_LIST} = undef; + delete $$self{EXCL_XMP_LOOKUP}; # handle our input arguments while (@_) { my $arg = shift; - if (ref $arg) { + if (ref $arg and not overload::Method($arg, q[""])) { if (ref $arg eq 'ARRAY') { $$self{IO_TAG_LIST} = $arg; foreach (@$arg) { @@ -3942,13 +4356,33 @@ sub ParseArguments($;@) # generate lookup for excluded tags if ($$options{Exclude}) { foreach (@{$$options{Exclude}}) { - /([-\w]+)#?$/ and $$self{EXCL_TAG_LOOKUP}{lc($1)} = 1; + /([-\w]+)#?$/ and $$self{EXCL_TAG_LOOKUP}{lc $1} = 1; + if (/(xmp-.*:[-\w]+)#?/i) { + $$self{EXCL_XMP_LOOKUP} or $$self{EXCL_XMP_LOOKUP} = { }; + $$self{EXCL_XMP_LOOKUP}{lc $1} = 1; + } } # exclude list is used only for EXCL_TAG_LOOKUP when TAGS_FROM_FILE is set undef $$options{Exclude} if $$self{TAGS_FROM_FILE}; } } +#------------------------------------------------------------------------------ +# Does group name match the tag ID? +# Inputs: 0) tag ID, 1) group name (with "ID-" removed) +# Returns: true on success +sub IsSameID($$) +{ + my ($id, $grp) = @_; + return 1 if $grp eq $id; # decimal ID's or raw ID's + if ($id =~ /^\d+$/) { # numerical numerical ID's may be in hex + return 1 if $grp =~ s/^0x0*// and $grp eq sprintf('%x', $id); + } else { # other ID's may conform to ExifTool group name conventions + return 1 if $id =~ s/([^-_A-Za-z0-9])/sprintf('%.2x',ord $1)/ge and $grp eq $id; + } + return 0; +} + #------------------------------------------------------------------------------ # Get list of tags in specified group # Inputs: 0) ExifTool ref, 1) group spec, 2) tag key or reference to list of tag keys @@ -3960,38 +4394,41 @@ sub GroupMatches($$$) my ($self, $group, $tagList) = @_; $tagList = [ $tagList ] unless ref $tagList; my ($tag, @matches); - if ($group =~ /:/) { - # check each group name individually (eg. "Author:1IPTC") - my @grps = split ':', lc $group; - my (@fmys, $g); + # check each group name individually (eg. "Author:1IPTC") + my @grps = split ':', $group; + my (@fmys, $g); + for ($g=0; $g<@grps; ++$g) { + if ($grps[$g] =~ s/^(\d*)(id-)?//i) { + $fmys[$g] = $1 if length $1; + if ($2) { + $fmys[$g] = 7; + next; # (don't convert tag ID's to lower case) + } + } + $grps[$g] = lc $grps[$g]; + $grps[$g] = '' if $grps[$g] eq 'copy0'; # accept 'Copy0' for primary tag + } + foreach $tag (@$tagList) { + my @groups = $self->GetGroup($tag, -1); for ($g=0; $g<@grps; ++$g) { - $fmys[$g] = $1 if $grps[$g] =~ s/^(\d+)//; - } - foreach $tag (@$tagList) { - my @groups = $self->GetGroup($tag, -1); - for ($g=0; $g<@grps; ++$g) { - my $grp = $grps[$g]; - next if $grp eq '*' or $grp eq 'all'; - if (defined $fmys[$g]) { - my $f = $fmys[$g]; - last unless $groups[$f] and $grps[$g] eq lc $groups[$f]; + my $grp = $grps[$g]; + next if $grp eq '*' or $grp eq 'all'; + my $f; + if (defined($f = $fmys[$g])) { + last unless defined $groups[$f]; + if ($f == 7) { + next if IsSameID($self->GetTagID($tag), $grp); } else { - last unless grep /^$grps[$g]$/i, @groups; + next if $grp eq lc $groups[$f]; } - } - if ($g == @grps) { - return $tag unless wantarray; - push @matches, $tag; + last; + } else { + last unless grep /^$grp$/i, @groups; } } - } else { - my $family = ($group =~ s/^(\d+)//) ? $1 : -1; - foreach $tag (@$tagList) { - my @groups = $self->GetGroup($tag, $family); - if (grep(/^$group$/i, @groups)) { - return $tag unless wantarray; - push @matches, $tag; - } + if ($g == @grps) { + return $tag unless wantarray; + push @matches, $tag; } } return wantarray ? @matches : $matches[0]; @@ -4447,12 +4884,16 @@ sub AddCompositeTags($;$) { local $_; my ($add, $override) = @_; - my $module; + my ($module, $prefix, $tagID); unless (ref $add) { + ($prefix = $add) =~ s/.*:://; $module = $add; $add .= '::Composite'; no strict 'refs'; $add = \%$add; + $prefix .= '-'; + } else { + $prefix = 'UserDefined-'; } my $defaultGroups = $$add{GROUPS}; my $compTable = GetTagTable('Image::ExifTool::Composite'); @@ -4466,43 +4907,62 @@ sub AddCompositeTags($;$) $defaultGroups = $$add{GROUPS} = { 0 => 'Composite', 1 => 'Composite', 2 => 'Other' }; } SetupTagTable($add); # generate Name, TagID, etc - my $tagID; foreach $tagID (sort keys %$add) { next if $specialTags{$tagID}; # must skip special tags my $tagInfo = $$add{$tagID}; - # tagID's MUST be the exact tag name for logic in BuildCompositeTags() - my $tag = $$tagInfo{Name}; + my $new = $prefix . $tagID; # new tag ID for Composite table $$tagInfo{Module} = $module if $$tagInfo{Writable}; $$tagInfo{Override} = 1 if $override and not defined $$tagInfo{Override}; $$tagInfo{IsComposite} = 1; - # allow Composite tags with the same name - if ($$compTable{$tag}) { + # handle Composite tags with the same name + if ($compositeID{$tagID}) { # determine if we want to override this tag # (=0 keep both, >0 override, <0 keep existing) - my $over = ($$tagInfo{Override} || 0) - ($$compTable{$tag}{Override} || 0); + my $over = ($$tagInfo{Override} || 0) - ($$compTable{$compositeID{$tagID}[0]}{Override} || 0); next if $over < 0; - my $n; - my $new = $tag; - while ($$compTable{$new}) { - delete $$compTable{$new} if $over; # delete existing entries - $n = ($n || 1) + 1; - $new = "${tag}-$n"; - } - # use new ID and save it so we can use it in TagLookup - $$tagInfo{NewTagID} = $tag = $new unless $over; - } - # convert scalar Require/Desire entries - my $type; - foreach $type ('Require','Desire') { + if ($over) { + # remove existing tags with this ID + delete $$compTable{$_} foreach @{$compositeID{$tagID}}; + delete $compositeID{$tagID}; + } + } + # make sure new TagID is unique by adding index if necessary + # (could only happen for UserDefined tags now that module name is added to tag ID) + my $n = 0; + while ($$compTable{$new}) { + $new =~ s/-\d+$// if $n++; + $new .= "-$n"; + } + # use new ID and save it so we can use it in TagLookup + $$tagInfo{NewTagID} = $new unless $tagID eq $new; + + # add new ID to lookup of Composite tag ID's + $compositeID{$tagID} = [ ] unless $compositeID{$tagID}; + unshift @{$compositeID{$tagID}}, $new; # (most recent one first) + + # convert scalar Require/Desire/Inhibit entries + my ($type, @hashes, @scalars, %used); + foreach $type ('Require','Desire','Inhibit') { my $req = $$tagInfo{$type} or next; - $$tagInfo{$type} = { 0 => $req } if ref($req) ne 'HASH'; + push @{ref($req) eq 'HASH' ? \@hashes : \@scalars}, $type; + } + if (@scalars) { + # make lookup for indices that are used + foreach $type (@hashes) { + $used{$_} = 1 foreach keys %{$$tagInfo{$type}}; + } + my $next = 0; + foreach $type (@scalars) { + ++$next while $used{$next}; + $$tagInfo{$type} = { $next++ => $$tagInfo{$type} }; + } } # add this Composite tag to our main Composite table $$tagInfo{Table} = $compTable; # (use the original TagID, even if we changed it, so don't do this:) - # $$tagInfo{TagID} = $tag; - # save tag under NewTagID in Composite table - $$compTable{$tag} = $tagInfo; + $$tagInfo{TagID} = $new; + # save tag under new ID in Composite table + $$compTable{$new} = $tagInfo; # set all default groups in tag my $groups = $$tagInfo{Groups}; $groups or $groups = $$tagInfo{Groups} = { }; @@ -4926,11 +5386,12 @@ sub FormatSize($) { return $formatSize{$_[0]}; } #------------------------------------------------------------------------------ # Read value from binary data (with current byte ordering) # Inputs: 0) data reference, 1) value offset, 2) format string, -# 3) number of values (or undef to use all data) -# 4) valid data length relative to offset, 5) optional pointer to returned rational +# 3) number of values (or undef to use all data), +# 4) valid data length relative to offset (or undef to use all data), +# 5) optional pointer to returned rational # Returns: converted value, or undefined if data isn't there # or list of values in list context -sub ReadValue($$$$$;$) +sub ReadValue($$$;$$$) { my ($dataPt, $offset, $format, $count, $size, $ratPt) = @_; @@ -4939,6 +5400,7 @@ sub ReadValue($$$$$;$) warn "Unknown format $format"; $len = 1; } + $size = length($$dataPt) - $offset unless defined $size; unless ($count) { return '' if defined $count or $size < $len; $count = int($size / $len); @@ -5146,35 +5608,38 @@ sub GetDescriptions($$) #------------------------------------------------------------------------------ # Apply filter to value(s) if necessary -# Inputs: 0) ExifTool ref, 1-N) references to values(s) to filter -# Returns: nothing, but changes values if necessary -sub Filter($@) +# Inputs: 0) ExifTool ref, 1) filter expression, 2) reference to value to filter +# Returns: true unless a filter returned undef; changes value if necessary +sub Filter($$$) { local $_; - my $self = shift; - return unless defined $$self{OPTIONS}{Filter}; - while (@_) { - my $valPt = shift; - next unless defined $$valPt; - if (not ref $$valPt) { - $_ = $$valPt; - #### eval Filter ($_) - eval $$self{OPTIONS}{Filter}; - $$valPt = $_ if defined $_; - } elsif (ref $$valPt eq 'SCALAR') { - my $val = $$$valPt; # make a copy to avoid filtering twice - $self->Filter(\$val); - $$valPt = \$val; - } elsif (ref $$valPt eq 'ARRAY') { - my @val = @{$$valPt}; # make a copy to avoid filtering twice - $self->Filter(\$_) foreach @val; - $$valPt = \@val; - } elsif (ref $$valPt eq 'HASH') { - my %val = %{$$valPt}; # make a copy to avoid filtering twice - $self->Filter(\$val{$_}) foreach keys %val; - $$valPt = \%val; - } + my ($self, $filter, $valPt) = @_; + return 1 unless defined $filter and defined $$valPt; + my $rtnVal; + if (not ref $$valPt) { + $_ = $$valPt; + #### eval Filter ($_, $self) + eval $filter; + if (defined $_) { + $$valPt = $_; + $rtnVal = 1; + } + } elsif (ref $$valPt eq 'SCALAR') { + my $val = $$$valPt; # make a copy to avoid filtering twice + $rtnVal = $self->Filter($filter, \$val); + $$valPt = \$val; + } elsif (ref $$valPt eq 'ARRAY') { + my @val = @{$$valPt}; # make a copy to avoid filtering twice + $self->Filter($filter, \$_) and $rtnVal = 1 foreach @val; + $$valPt = \@val; + } elsif (ref $$valPt eq 'HASH') { + my %val = %{$$valPt}; # make a copy to avoid filtering twice + $self->Filter($filter, \$val{$_}) and $rtnVal = 1 foreach keys %val; + $$valPt = \%val; + } else { + $rtnVal = 1; } + return $rtnVal; } #------------------------------------------------------------------------------ @@ -5236,8 +5701,39 @@ sub ConvertDateTime($$) shift @a while @a > 6; # remove superfluous entries unshift @a, 1 while @a < 3; # add month and day if necessary unshift @a, 0 while @a < 6; # add h,m,s if necessary - $a[5] -= 1900; # base year is 1900 $a[4] -= 1; # base month is 1 + # parse our %f fractional seconds first (and round up seconds if necessary) + # - if there are multiple %f codes, they all get the same number of digits as the first + if ($fmt =~ /%\.?(\d*)f/) { + my $dig = $1; + my $frac = $date =~ /(\.\d+)/ ? $1 : ''; + if (not $frac) { + $frac = '.' . ('0' x $dig) if $dig; + } elsif (length $dig) { + if ($dig+1 > length($frac)) { + $frac .= '0' x ($dig+1-length($frac)); + } elsif ($dig+1 < length($frac)) { + $frac = sprintf("%.${dig}f", $frac); + while ($frac =~ s/^(\d)// and $1 ne '0') { + # this is a pain, but we must round up to the next second + ++$a[0] < 60 and last; + $a[0] = 0; + ++$a[1] < 60 and last; + $a[1] = 0; + ++$a[2] < 24 and last; + $a[2] = 0; + require 'Image/ExifTool/Shift.pl'; + ++$a[3] <= DaysInMonth($a[4]+1, $a[5]) and last; + $a[3] = 1; + ++$a[4] < 12 and last; + $a[4] = 0; + ++$a[5]; + last; # (this was a goto) + } + } + } + $fmt =~ s/(^|[^%])((%%)*)%\.?\d*f/$1$2$frac/g; + } # parse %z and %s ourself (to handle time zones properly) if ($fmt =~ /%[sz]/) { # use system time zone unless otherwise specified @@ -5251,6 +5747,7 @@ sub ConvertDateTime($$) $fmt =~ s/(^|[^%])((%%)*)%s/$1$2$s/g; # convert '%s' format codes } } + $a[5] -= 1900; # strftime year starts from 1900 $date = POSIX::strftime($fmt, @a); # generate the formatted date/time } elsif ($$self{OPTIONS}{StrictDate}) { undef $date; @@ -5342,15 +5839,25 @@ sub TimeZoneString($;$) #------------------------------------------------------------------------------ # Convert Unix time to EXIF date/time string -# Inputs: 0) Unix time value, 1) non-zero to convert to local time +# Inputs: 0) Unix time value, 1) non-zero to convert to local time, +# 2) number of digits after the decimal for fractional seconds # Returns: EXIF date/time string (with timezone for local times) -# Notes: fractional seconds are ignored -sub ConvertUnixTime($;$) +sub ConvertUnixTime($;$$) { - my ($time, $toLocal) = @_; + my ($time, $toLocal, $dec) = @_; return '0000:00:00 00:00:00' if $time == 0; - $time = int($time + 1e-6) if $time != int($time); # avoid round-off errors my (@tm, $tz); + if ($dec) { + my $frac = $time - int($time); + $time = int($time); + $frac < 0 and $frac += 1, $time -= 1; + $dec = sprintf('%.*f', $dec, $frac); + # remove number before decimal and increment integer time if it was rounded up + $dec =~ s/^(\d)// and $1 eq '1' and $time += 1; + } else { + $time = int($time + 1e-6) if $time != int($time); # avoid round-off errors + $dec = ''; + } if ($toLocal) { @tm = localtime($time); $tz = TimeZoneString(\@tm, $time); @@ -5358,33 +5865,43 @@ sub ConvertUnixTime($;$) @tm = gmtime($time); $tz = ''; } - my $str = sprintf("%4d:%.2d:%.2d %.2d:%.2d:%.2d%s", + my $str = sprintf("%4d:%.2d:%.2d %.2d:%.2d:%.2d$dec%s", $tm[5]+1900, $tm[4]+1, $tm[3], $tm[2], $tm[1], $tm[0], $tz); return $str; } #------------------------------------------------------------------------------ # Get Unix time from EXIF-formatted date/time string with optional timezone -# Inputs: 0) EXIF date/time string, 1) non-zero if time is local +# Inputs: 0) EXIF date/time string, 1) non-zero if time is local, or 2 to assume UTC # Returns: Unix time (seconds since 0:00 GMT Jan 1, 1970) or undefined on error sub GetUnixTime($;$) { my ($timeStr, $isLocal) = @_; return 0 if $timeStr eq '0000:00:00 00:00:00'; - my @tm = ($timeStr =~ /^(\d+):(\d+):(\d+)\s+(\d+):(\d+):(\d+)/); - return undef unless @tm == 6 and eval { require Time::Local }; - my $tzsec = 0; + my @tm = ($timeStr =~ /^(\d+)[-:](\d+)[-:](\d+)\s+(\d+):(\d+):(\d+)(.*)/); + return undef unless @tm == 7; + unless (eval { require Time::Local }) { + warn "Time::Local is not installed\n"; + return undef; + } + my ($tzStr, $tzSec) = (pop(@tm), 0); # use specified timezone offset (if given) instead of local system time # if we are converting a local time value - if ($isLocal and $timeStr =~ /(?:Z|([-+])(\d+):(\d+))$/i) { - # use specified timezone if one exists - $tzsec = ($2 * 60 + $3) * ($1 eq '-' ? -60 : 60) if $1; - undef $isLocal; # convert using GMT corrected for specified timezone + if ($isLocal) { + if ($tzStr =~ /(?:Z|([-+])(\d+):(\d+))/i) { + # use specified timezone if one exists + $tzSec = ($2 * 60 + $3) * ($1 eq '-' ? -60 : 60) if $1; + undef $isLocal; # convert using GMT corrected for specified timezone + } elsif ($isLocal eq '2') { + undef $isLocal; + } } - $tm[0] -= 1900; # convert year $tm[1] -= 1; # convert month @tm = reverse @tm; # change to order required by timelocal() - return $isLocal ? TimeLocal(@tm) : Time::Local::timegm(@tm) - $tzsec; + my $val = $isLocal ? TimeLocal(@tm) : Time::Local::timegm(@tm) - $tzSec; + # handle fractional seconds + $val += $1 if $tzStr and $tzStr =~ /^(\.\d+)/; + return $val; } #------------------------------------------------------------------------------ @@ -5394,19 +5911,19 @@ sub GetUnixTime($;$) sub ConvertFileSize($) { my $val = shift; - $val < 2048 and return "$val bytes"; - $val < 10240 and return sprintf('%.1f kB', $val / 1024); - $val < 2097152 and return sprintf('%.0f kB', $val / 1024); - $val < 10485760 and return sprintf('%.1f MB', $val / 1048576); - $val < 2147483648 and return sprintf('%.0f MB', $val / 1048576); - $val < 10737418240 and return sprintf('%.1f GB', $val / 1073741824); - return sprintf('%.0f GB', $val / 1073741824); + $val < 2000 and return "$val bytes"; + $val < 10000 and return sprintf('%.1f kB', $val / 1000); + $val < 2000000 and return sprintf('%.0f kB', $val / 1000); + $val < 10000000 and return sprintf('%.1f MB', $val / 1000000); + $val < 2000000000 and return sprintf('%.0f MB', $val / 1000000); + $val < 10000000000 and return sprintf('%.1f GB', $val / 1000000000); + return sprintf('%.0f GB', $val / 1000000000); } #------------------------------------------------------------------------------ # Convert seconds to duration string (handles negative durations) # Inputs: 0) floating point seconds -# Returns: duration string in form "S.SS s", "MM:SS" or "H:MM:SS" +# Returns: duration string in form "S.SS s", "H:MM:SS" or "DD days HH:MM:SS" sub ConvertDuration($) { my $time = shift; @@ -5473,12 +5990,12 @@ sub InverseFileName($$) #------------------------------------------------------------------------------ # Save information for HTML dump # Inputs: 0) ExifTool hash ref, 1) start offset, 2) data size -# 3) comment string, 4) tool tip (or SAME), 5) flags -sub HDump($$$$;$$) +# 3) comment string, 4) tool tip (or SAME), 5) flags, 6) IFD name +sub HDump($$$$;$$$) { my $self = shift; $$self{HTML_DUMP} or return; - my ($pos, $len, $com, $tip, $flg) = @_; + my ($pos, $len, $com, $tip, $flg, $ifd) = @_; $pos += $$self{BASE} if $$self{BASE}; # skip structural data blocks which have been removed from the middle of this dump # (SkipData list contains ordered [start,end+1] offsets to skip) @@ -5489,14 +6006,14 @@ sub HDump($$$$;$$) $end <= $$skip[0] and last; $pos >= $$skip[1] and $pos += $$skip[1] - $$skip[0], next; if ($pos != $$skip[0]) { - $$self{HTML_DUMP}->Add($pos, $$skip[0]-$pos, $com, $tip, $flg); + $$self{HTML_DUMP}->Add($pos, $$skip[0]-$pos, $com, $tip, $flg, $ifd); $len -= $$skip[0] - $pos; $tip = 'SAME'; } $pos = $$skip[1]; } } - $$self{HTML_DUMP}->Add($pos, $len, $com, $tip, $flg); + $$self{HTML_DUMP}->Add($pos, $len, $com, $tip, $flg, $ifd); } #------------------------------------------------------------------------------ @@ -5529,6 +6046,10 @@ sub IdentifyTrailer($;$) $type = 'MIE'; } elsif ($buff =~ /\0\0(QDIOBS|SEFT)$/) { $type = 'Samsung'; + } elsif ($buff =~ /8db42d694ccc418790edff439fe026bf$/s) { + $type = 'Insta360'; + } elsif ($buff =~ m(\0{6}/NIKON APP$)) { + $type = 'NikonApp'; } last; } @@ -5560,9 +6081,17 @@ sub ProcessTrailers($$) my $path = $$self{PATH}; for (;;) { # loop through all trailers - require "Image/ExifTool/$dirName.pm"; - my $proc = "Image::ExifTool::${dirName}::Process$dirName"; - my $outBuff; + my ($proc, $outBuff); + if ($dirName eq 'Insta360') { + require 'Image/ExifTool/QuickTimeStream.pl'; + $proc = 'Image::ExifTool::QuickTime::ProcessInsta360'; + } elsif ($dirName eq 'NikonApp') { + require Image::ExifTool::Nikon; + $proc = 'Image::ExifTool::Nikon::ProcessNikonApp'; + } else { + require "Image/ExifTool/$dirName.pm"; + $proc = "Image::ExifTool::${dirName}::Process$dirName"; + } if ($outfile) { # write to local buffer so we can add trailer in proper order later $$outfile and $$dirInfo{OutFile} = \$outBuff, $outBuff = ''; @@ -5577,8 +6106,9 @@ sub ProcessTrailers($$) push @$path, 'Trailer', $dirName; # read or write this trailer - # (proc takes Offset as offset from end of trailer to end of file, - # and returns DataPos and DirLen, and Fixup if applicable) + # (proc takes Offset as positive offset from end of trailer to end of file, + # and returns DataPos and DirLen, and Fixup if applicable, and updates + # OutFile when writing) no strict 'refs'; my $result = &$proc($self, $dirInfo); use strict 'refs'; @@ -5713,13 +6243,15 @@ sub ProcessJPEG($$) local $_; my ($self, $dirInfo) = @_; my ($ch, $s, $length); - my $verbose = $$self{OPTIONS}{Verbose}; - my $out = $$self{OPTIONS}{TextOut}; - my $fast = $$self{OPTIONS}{FastScan}; + my $options = $$self{OPTIONS}; + my $verbose = $$options{Verbose}; + my $out = $$options{TextOut}; + my $fast = $$options{FastScan} || 0; my $raf = $$dirInfo{RAF}; + my $req = $$self{REQ_TAG_LOOKUP}; my $htmlDump = $$self{HTML_DUMP}; my %dumpParms = ( Out => $out ); - my ($success, $wantTrailer, $trailInfo, $foundSOS); + my ($success, $wantTrailer, $trailInfo, $foundSOS, %jumbfChunk); my (@iccChunk, $iccChunkCount, $iccChunksTotal, @flirChunk, $flirCount, $flirTotal); my ($preview, $scalado, @dqt, $subSampling, $dumpEnd, %extendedXMP); @@ -5729,9 +6261,14 @@ sub ProcessJPEG($$) return 0 unless $raf->Read($s, 5) == 5 and $s eq 'Exiv2'; $$self{FILE_TYPE} = 'EXV'; } - if (not $$self{VALUE}{FileType} or ($$self{DOC_NUM} and $$self{OPTIONS}{ExtractEmbedded})) { + my $appBytes = 0; + my $calcImageLen = $$req{jpegimagelength}; + if ($$options{RequestAll} and $$options{RequestAll} > 2) { + $calcImageLen = 1; + } + if (not $$self{VALUE}{FileType} or ($$self{DOC_NUM} and $$options{ExtractEmbedded})) { $self->SetFileType(); # set FileType tag - return 1 if $fast and $fast == 3; # don't process file when FastScan == 3 + return 1 if $fast == 3; # don't process file when FastScan == 3 $$self{LOW_PRIORITY_DIR}{IFD1} = 1; # lower priority of IFD1 tags } $$raf{NoBuffer} = 1 if $self->Options('FastScan'); # disable buffering in FastScan mode @@ -5758,6 +6295,7 @@ sub ProcessJPEG($$) my $marker = $nextMarker; my $segDataPt = $nextSegDataPt; my $segPos = $nextSegPos; + my $skipped; undef $nextMarker; undef $nextSegDataPt; # @@ -5767,11 +6305,13 @@ sub ProcessJPEG($$) # read up to next marker (JPEG markers begin with 0xff) my $buff; $raf->ReadLine($buff) or last; + $skipped = length($buff) - 1; # JPEG markers can be padded with unlimited 0xff's for (;;) { $raf->Read($ch, 1) or last Marker; $nextMarker = ord($ch); last unless $nextMarker == 0xff; + ++$skipped; } # read segment data if it exists if (not defined $markerLenBytes{$nextMarker}) { @@ -5798,6 +6338,14 @@ sub ProcessJPEG($$) # set some useful variables for the current segment my $markerName = JpegMarkerName($marker); $$path[$pn] = $markerName; + # issue warning if we skipped some garbage + if ($skipped and not $foundSOS and $markerName ne 'SOS') { + $self->Warn("Skipped unknown $skipped bytes after JPEG $markerName segment", 1); + if ($htmlDump) { + $self->HDump($nextSegPos-4-$skipped, $skipped, "[unknown $skipped bytes]", undef, 0x08); + $dumpEnd = $nextSegPos - 4; + } + } # # parse the current segment # @@ -5842,7 +6390,7 @@ sub ProcessJPEG($$) } if ($hmin and $vmin) { my ($hs, $vs) = ($hmax / $hmin, $vmax / $vmin); - $self->FoundTag($$sof{YCbCrSubSampling}, "$hs $vs"); + $self->HandleTag($sof, 'YCbCrSubSampling', "$hs $vs"); } next; } elsif ($marker == 0xd9) { # EOI @@ -5859,32 +6407,67 @@ sub ProcessJPEG($$) } else { $self->Warn('Missing JPEG SOS'); } + if ($$req{trailer}) { + # read entire trailer into memory + if ($raf->Seek(0,2)) { + my $len = $raf->Tell() - $pos; + if ($len) { + my $buff; + $raf->Seek($pos, 0); + $self->FoundTag(Trailer => \$buff) if $raf->Read($buff,$len) == $len; + $raf->Seek($pos, 0); + } + } else { + $self->Warn('Error seeking in file'); + } + } # we are here because we are looking for trailer information if ($wantTrailer) { my $start = $$self{PreviewImageStart}; - if ($start) { + if ($start or $$options{ExtractEmbedded}) { my $buff; # most previews start right after the JPEG EOI, but the Olympus E-20 # preview is 508 bytes into the trailer, the K-M Maxxum 7D preview is # 979 bytes in, and Sony previews can start up to 32 kB into the trailer. # (and Minolta and Sony previews can have a random first byte...) my $scanLen = $$self{Make} =~ /Sony/i ? 65536 : 1024; - if ($raf->Read($buff, $scanLen) and ($buff =~ /\xff\xd8\xff./g or - ($$self{Make} =~ /(Minolta|Sony)/i and $buff =~ /.\xd8\xff\xdb/g))) - { - # adjust PreviewImageStart to this location - my $actual = $pos + pos($buff) - 4; - if ($start ne $actual and $verbose > 1) { - print $out "(Fixed PreviewImage location: $start -> $actual)\n"; - } - # update preview image offsets - $$self{VALUE}{PreviewImageStart} = $actual if $$self{VALUE}{PreviewImageStart}; - $$self{PreviewImageStart} = $actual; - # load preview now if we tried and failed earlier - if ($$self{PreviewError} and $$self{PreviewImageLength}) { - if ($raf->Seek($actual, 0) and $raf->Read($buff, $$self{PreviewImageLength})) { - $self->FoundTag('PreviewImage', $buff); - delete $$self{PreviewError}; + if ($raf->Read($buff, $scanLen)) { + if ($buff =~ /^.{4}ftyp/s) { + my $val; + if ($raf->Seek(0,2)) { + my $len = $raf->Tell() - $pos; + if ($$options{Binary}) { + $val = \$buff if $raf->Seek($pos,0) and $raf->Read($buff,$len)==$len; + } else { + $val = \ "Binary data $len bytes"; + } + if ($val) { + $self->FoundTag('EmbeddedVideo', $val); + } else { + $self->Warn('Error reading trailer'); + } + } else { + $self->Warn('Error seeking to end of file'); + } + } elsif ($buff =~ /\xff\xd8\xff./g or + ($$self{Make} =~ /(Minolta|Sony)/i and $buff =~ /.\xd8\xff\xdb/g)) + { + # adjust PreviewImageStart to this location + my $actual = $pos + pos($buff) - 4; + if ($start and $start ne $actual and $verbose > 1) { + print $out "(Fixed PreviewImage location: $start -> $actual)\n"; + } + # update preview image offsets + if ($start) { + $$self{VALUE}{PreviewImageStart} = $actual if $$self{VALUE}{PreviewImageStart}; + $$self{PreviewImageStart} = $actual; + } + # load preview now if we tried and failed earlier + if ($$self{PreviewError} and $$self{PreviewImageLength}) { + if ($raf->Seek($actual, 0) and $raf->Read($buff, $$self{PreviewImageLength})) { + $self->FoundTag('PreviewImage', $buff); + delete $$self{PreviewError}; + } } } } @@ -5920,6 +6503,7 @@ sub ProcessJPEG($$) DirLen => $endPos - $pos }) if $endPos > $pos; } + $self->FoundTag('JPEGImageLength', $pos - $appBytes) if $calcImageLen; last; # all done parsing file } elsif ($marker == 0xda) { # SOS pop @$path; @@ -5934,7 +6518,7 @@ sub ProcessJPEG($$) # only if we can't finish without scanning from end of file) $self->ProcessTrailers($trailInfo) and undef $trailInfo; } - if ($wantTrailer) { + if ($wantTrailer and $$self{PreviewImageStart}) { # seek ahead and validate preview image my $buff; my $curPos = $raf->Tell(); @@ -5951,10 +6535,13 @@ sub ProcessJPEG($$) require Image::ExifTool::Panasonic; Image::ExifTool::Panasonic::ProcessLeicaTrailer($self); $wantTrailer = 1 if $$self{LeicaTrailer}; + } else { + $wantTrailer = 1 if $$options{ExtractEmbedded}; } next if $trailInfo or $wantTrailer or $verbose > 2 or $htmlDump; } - next if $$self{OPTIONS}{Validate}; # (validate to EOI) + # must scan to EOI if Validate or JpegCompressionFactor used + next if $$options{Validate} or $calcImageLen or $$req{trailer}; # nothing interesting to parse after start of scan (SOS) $success = 1; last; # all done parsing file @@ -5970,20 +6557,21 @@ sub ProcessJPEG($$) next; } elsif ($marker == 0xdb and length($$segDataPt) and # DQT # save the DQT data only if JPEGDigest has been requested - # (Note: since we aren't checking the RequestAll API option here, the application + # (Note: since we aren't checking the API RequestAll option here, the application # must use the RequestTags option to generate these tags if they have not been # specifically requested. The reason is that there is too much overhead involved # in the calculation of this tag to make this worth the CPU time.) - ($$self{REQ_TAG_LOOKUP}{jpegdigest} or $$self{REQ_TAG_LOOKUP}{jpegqualityestimate} - or ($$self{OPTIONS}{RequestAll} and $$self{OPTIONS}{RequestAll} > 2))) + ($$req{jpegdigest} or $$req{jpegqualityestimate} + or ($$options{RequestAll} and $$options{RequestAll} > 2))) { my $num = unpack('C',$$segDataPt) & 0x0f; # get table index $dqt[$num] = $$segDataPt if $num < 4; # save for MD5 calculation } # handle all other markers my $dumpType = ''; - my ($desc, $tip); + my ($desc, $tip, $xtra); $length = length $$segDataPt; + $appBytes += $length + 4 if ($marker & 0xf0) == 0xe0; # total size of APP segments if ($verbose) { print $out "JPEG $markerName ($length bytes):\n"; if ($verbose > 2) { @@ -6016,7 +6604,7 @@ sub ProcessJPEG($$) my $tagInfo = $self->GetTagInfo($tagTablePtr, $tag); $self->FoundTag($tagInfo, substr($$segDataPt, 6)); } elsif ($$segDataPt =~ /^(II|MM).{4}HEAPJPGM/s) { - next if $fast and $fast > 1; # skip processing for very fast + next if $fast > 1; # skip processing for very fast $dumpType = 'CIFF'; my %dirInfo = ( RAF => new File::RandomAccess($segDataPt) ); $$self{SET_GROUP1} = 'CIFF'; @@ -6032,7 +6620,7 @@ sub ProcessJPEG($$) DirStart(\%dirInfo, 4); $self->ProcessDirectory(\%dirInfo, $tagTablePtr); } - } elsif ($marker == 0xe1) { # APP1 (EXIF, XMP, QVCI) + } elsif ($marker == 0xe1) { # APP1 (EXIF, XMP, QVCI, PARROT) # (some Kodak cameras don't put a second "\0", and I have seen an # example where there was a second 4-byte APP1 segment header) if ($$segDataPt =~ /^(.{0,4})Exif\0/is) { @@ -6079,7 +6667,7 @@ sub ProcessJPEG($$) DirStart(\%dirInfo, $hdrLen, $hdrLen); $$self{SkipData} = \@skipData if @skipData; # extract the EXIF information (it is in standard TIFF format) - $self->ProcessTIFF(\%dirInfo); + $self->ProcessTIFF(\%dirInfo) or $self->Warn('Malformed APP1 EXIF segment'); # avoid looking for preview unless necessary because it really slows # us down -- only look for it if we found pointer, and preview is # outside EXIF, and PreviewImage is specifically requested @@ -6091,9 +6679,9 @@ sub ProcessJPEG($$) } if ($start and $plen and IsInt($start) and IsInt($plen) and $start + $plen > $$self{EXIF_POS} + length($$self{EXIF_DATA}) and - ($$self{REQ_TAG_LOOKUP}{previewimage} or + ($$req{previewimage} or # (extracted normally, so check Binary option) - ($$self{OPTIONS}{Binary} and not $$self{EXCL_TAG_LOOKUP}{previewimage}))) + ($$options{Binary} and not $$self{EXCL_TAG_LOOKUP}{previewimage}))) { $$self{PreviewImageStart} = $start; $$self{PreviewImageLength} = $plen; @@ -6176,6 +6764,11 @@ sub ProcessJPEG($$) } else { $self->WarnOnce('Invalid or extraneous FLIR chunk(s)'); } + } elsif ($$segDataPt =~ /^PARROT\0(II\x2a\0|MM\0\x2a)/) { + # (don't know if this could span multiple segments) + my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::Main'); + $self->HandleTag($tagTablePtr, 'APP1', $$segDataPt); + $dumpType = 'Parrot'; } else { # Hmmm. Could be XMP, let's see my $processed; @@ -6240,7 +6833,7 @@ sub ProcessJPEG($$) $self->WarnOnce('Invalid or extraneous ICC_Profile chunk(s)'); } } elsif ($$segDataPt =~ /^FPXR\0/) { - next if $fast and $fast > 1; # skip processing for very fast + next if $fast > 1; # skip processing for very fast $dumpType = 'FPXR'; my $tagTablePtr = GetTagTable('Image::ExifTool::FlashPix::Main'); # set flag if this is the last FPXR segment @@ -6292,6 +6885,28 @@ sub ProcessJPEG($$) # extract the Stim information (it is in standard TIFF format) my $tagTablePtr = GetTagTable('Image::ExifTool::Stim::Main'); $self->ProcessTIFF(\%dirInfo, $tagTablePtr); + } elsif ($$segDataPt =~ /^_JPSJPS_/) { + $dumpType = 'JPS'; + $self->OverrideFileType('JPS') if $$self{FILE_TYPE} eq 'JPEG'; + SetByteOrder('MM'); + my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::JPS'); + $self->ProcessDirectory(\%dirInfo, $tagTablePtr); + } elsif ($$self{Make} eq 'DJI') { + $dumpType = 'DJI ThermalData'; + # add this data to the combined data if it exists + my $dataPt = $segDataPt; + if (defined $combinedSegData) { + $combinedSegData .= $$segDataPt; + $dataPt = \$combinedSegData; + } + if ($nextMarker == $marker) { + $combinedSegData = $$segDataPt unless defined $combinedSegData; + } else { + # process DJI FLIR thermal data + my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::Main'); + $self->HandleTag($tagTablePtr, 'APP3', $$dataPt); + undef $combinedSegData; + } } elsif ($$segDataPt =~ /^\xff\xd8\xff\xdb/) { $dumpType = 'PreviewImage'; # (Samsung, HP, BenQ) $preview = $$segDataPt; @@ -6320,17 +6935,23 @@ sub ProcessJPEG($$) undef $scalado; } } elsif ($$segDataPt =~ /^FPXR\0/) { - next if $fast and $fast > 1; # skip processing for very fast + next if $fast > 1; # skip processing for very fast $dumpType = 'FPXR'; my $tagTablePtr = GetTagTable('Image::ExifTool::FlashPix::Main'); # set flag if this is the last FPXR segment $dirInfo{LastFPXR} = not ($nextMarker==$marker and $$nextSegDataPt=~/^FPXR\0/), $self->ProcessDirectory(\%dirInfo, $tagTablePtr); + } elsif ($$self{Make} eq 'DJI' and $$segDataPt =~ /^\xaa\x55\x12\x06/) { + $dumpType = 'DJI ThermalParams'; + DirStart(\%dirInfo, 0, 0); + my $tagTablePtr = GetTagTable('Image::ExifTool::DJI::ThermalParams'); + $self->ProcessDirectory(\%dirInfo, $tagTablePtr); } elsif ($preview) { # continued Samsung S1060 preview from APP3 $dumpType = 'PreviewImage'; $preview .= $$segDataPt; } + # (also seen "QTI Debug Metadata\0" segment in some newer Samsung images) # BenQ DC E1050 continues preview in APP5 if ($preview and $nextMarker ne 0xe5) { $self->FoundTag('PreviewImage', $preview); @@ -6344,6 +6965,13 @@ sub ProcessJPEG($$) DirStart(\%dirInfo, 6, 6); my $tagTablePtr = GetTagTable('Image::ExifTool::Ricoh::RMETA'); $self->ProcessDirectory(\%dirInfo, $tagTablePtr); + } elsif ($$segDataPt =~ /^ssuniqueid\0/) { + my $tagTablePtr = GetTagTable('Image::ExifTool::Samsung::APP5'); + $self->HandleTag($tagTablePtr, 'ssuniqueid', substr($$segDataPt, 11)); + } elsif ($$self{Make} eq 'DJI') { + $dumpType = 'DJI ThermalCal'; + my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::Main'); + $self->HandleTag($tagTablePtr, 'APP5', $$segDataPt); } elsif ($preview) { $dumpType = 'PreviewImage'; $preview .= $$segDataPt; @@ -6379,8 +7007,12 @@ sub ProcessJPEG($$) my $tagTablePtr = GetTagTable('Image::ExifTool::GoPro::GPMF'); DirStart(\%dirInfo, 6); $self->ProcessDirectory(\%dirInfo, $tagTablePtr); + } elsif ($$segDataPt =~ /^DTAT\0\0.\{/s) { + $dumpType = 'DJI_DTAT'; + my $tagTablePtr = GetTagTable('Image::ExifTool::JPEG::Main'); + $self->HandleTag($tagTablePtr, 'APP6', $$segDataPt); } - } elsif ($marker == 0xe7) { # APP7 (Pentax, Qualcomm) + } elsif ($marker == 0xe7) { # APP7 (Pentax, Huawei, Qualcomm) if ($$segDataPt =~ /^PENTAX \0(II|MM)/) { # found in K-3 images (is this multi-segment??) SetByteOrder($1); @@ -6395,6 +7027,23 @@ sub ProcessJPEG($$) $dumpEnd = $segPos + $length; } $self->ProcessDirectory(\%dirInfo, $tagTablePtr); + } elsif ($$segDataPt =~ /^HUAWEI\0\0(II|MM)/) { + SetByteOrder($1); + undef $dumpType; # (dump this ourself) + my $hdrLen = 16; + my $tagTablePtr = GetTagTable('Image::ExifTool::Unknown::Main'); + DirStart(\%dirInfo, $hdrLen, 8); + $dirInfo{DirName} = 'Huawei APP7'; + if ($htmlDump) { + $self->HDump($segPos-4, 4, 'APP7 header', "Data size: $length bytes"); + $self->HDump($segPos, $hdrLen, 'Huawei header', 'APP7 data type: Huawei'); + $dumpEnd = $segPos + $length; + } + $$self{SET_GROUP0} = 'APP7'; + $$self{SET_GROUP1} = 'Huawei'; + $self->ProcessDirectory(\%dirInfo, $tagTablePtr); + delete $$self{SET_GROUP0}; + delete $$self{SET_GROUP1}; } elsif ($$segDataPt =~ /^\x1aQualcomm Camera Attributes/) { # found in HP iPAQ_VoiceMessenger $dumpType = 'Qualcomm'; @@ -6426,8 +7075,12 @@ sub ProcessJPEG($$) $dumpType = 'PhotoStudio'; my $comment = $self->Decode(substr($$segDataPt,8), 'UCS2', 'MM'); $self->FoundTag('Comment', $comment); + } elsif ($$segDataPt =~ /^AROT\0/ and $length > 10) { + # iPhone "AROT" segment containing integrated intensity per 16 scan lines + # (with number of elements N = ImageHeight / 16 - 1, ref PH/NealKrawetz) + $xtra = 'segment (N=' . unpack('x6N', $$segDataPt) . ')'; } - } elsif ($marker == 0xeb) { # APP11 (JPEG-HDR) + } elsif ($marker == 0xeb) { # APP11 (JPEG-HDR, JUMBF) if ($$segDataPt =~ /^HDR_RI /) { $dumpType = 'JPEG-HDR'; my $dataPt = $segDataPt; @@ -6447,6 +7100,47 @@ sub ProcessJPEG($$) $self->ProcessDirectory(\%dirInfo, $tagTablePtr); undef $combinedSegData; } + } elsif ($$segDataPt =~ /^(JP..)/s and length($$segDataPt) >= 16) { + # JUMBF extension marker + my $hdr = $1; + $dumpType = 'JUMBF'; + SetByteOrder('MM'); + my $seq = Get32u($segDataPt, 4) - 1; # (start from 0) + my $len = Get32u($segDataPt, 8); + my $type = substr($$segDataPt, 12, 4); + my $hdrLen; + if ($len == 1 and length($$segDataPt) >= 24) { + $len = Get64u($$segDataPt, 16); + $hdrLen = 16; + } else { + $hdrLen = 8; + } + $jumbfChunk{$type} or $jumbfChunk{$type} = [ ]; + if ($len < $hdrLen) { + $self->Warn('Invalid JUMBF segment'); + } elsif ($seq < 0) { + $self->Warn('Invalid JUMBF sequence number'); + } elsif (defined $jumbfChunk{$type}[$seq]) { + $self->Warn('Duplicate JUMBF sequence number'); + } else { + # add to list of JUMBF chunks + $jumbfChunk{$type}[$seq] = substr($$segDataPt, 8 + $hdrLen); + # check to see if we have a complete JUMBF box + my $size = $hdrLen; + foreach (@{$jumbfChunk{$type}}) { + defined $_ or $size = 0, last; + $size += length $_; + } + if ($size == $len) { + my $buff = join '', substr($$segDataPt,8,$hdrLen), @{$jumbfChunk{$type}}; + $dirInfo{DataPt} = \$buff; + $dirInfo{DataPos} = $segPos + 8; # (shows correct offsets for single-segment JUMBF) + $dirInfo{DataLen} = $dirInfo{DirLen} = $size; + my $tagTablePtr = GetTagTable('Image::ExifTool::Jpeg2000::Main'); + $self->ProcessDirectory(\%dirInfo, $tagTablePtr); + delete $jumbfChunk{$type}; + } + } } } elsif ($marker == 0xec) { # APP12 (Ducky, Picture Info) if ($$segDataPt =~ /^Ducky/) { @@ -6498,7 +7192,7 @@ sub ProcessJPEG($$) } elsif ($marker == 0xee) { # APP14 (Adobe) if ($$segDataPt =~ /^Adobe/) { # extract as a block if requested, or if copying tags from file - if ($$self{REQ_TAG_LOOKUP}{adobe} or + if ($$req{adobe} or # (not extracted normally, so check TAGS_FROM_FILE) ($$self{TAGS_FROM_FILE} and not $$self{EXCL_TAG_LOOKUP}{adobe})) { @@ -6538,8 +7232,10 @@ sub ProcessJPEG($$) $desc = "[JPEG $markerName]"; # (other known JPEG segments) } if (defined $dumpType) { - if (not $dumpType and $$self{OPTIONS}{Unknown}) { - $self->Warn("Unknown $markerName segment", 1); + if (not $dumpType and ($$options{Unknown} or $$options{Validate})) { + my $str = ($$segDataPt =~ /^([\x20-\x7e]{1,20})\0/) ? " '${1}'" : ''; + $xtra = 'segment' unless $xtra; + $self->Warn("Unknown $markerName$str $xtra", 1); } if ($htmlDump) { $desc or $desc = $markerName . ($dumpType ? " $dumpType" : '') . ' segment'; @@ -6555,7 +7251,7 @@ sub ProcessJPEG($$) # GUID indicated by the last main XMP segment my $goodGuid = $$self{VALUE}{HasExtendedXMP} || ''; # GUID of the extended XMP that we will process ('2' for all) - my $readGuid = $$self{OPTIONS}{ExtendedXMP} || 0; + my $readGuid = $$options{ExtendedXMP} || 0; $readGuid = $goodGuid if $readGuid eq '1'; foreach $guid (sort keys %extendedXMP) { next unless length $guid == 32; # ignore other (internal) keys @@ -6599,6 +7295,7 @@ sub ProcessJPEG($$) Image::ExifTool::JPEGDigest::Calculate($self, \@dqt, $subSampling); } # issue necessary warnings + $self->Warn('Invalid JUMBF size or missing JUMBF chunk') if %jumbfChunk; $self->Warn('Incomplete ICC_Profile record', 1) if defined $iccChunkCount; $self->Warn('Incomplete FLIR record', 1) if defined $flirCount; $self->Warn('Error reading PreviewImage', 1) if $$self{PreviewError}; @@ -6698,15 +7395,20 @@ sub DoProcessTIFF($$;$) $$self{EXIF_DATA} = ''; } unless (defined $$self{EXIF_DATA}) { + # set default byte order for creating new GPS in CR3 images + my $defaultByteOrder; + if ($$dirInfo{DirName} and $$dirInfo{DirName} eq 'GPS') { + $defaultByteOrder = $$self{SaveExifByteOrder}; + } # create TIFF information from scratch - if ($self->SetPreferredByteOrder() eq 'MM') { + if ($self->SetPreferredByteOrder($defaultByteOrder) eq 'MM') { $$self{EXIF_DATA} = "MM\0\x2a\0\0\0\x08"; } else { $$self{EXIF_DATA} = "II\x2a\0\x08\0\0\0"; } } - $$self{FIRST_EXIF_POS} = $base + $$self{BASE} unless defined $$self{FIRST_EXIF_POS}; $$self{EXIF_POS} = $base + $$self{BASE}; + $$self{FIRST_EXIF_POS} = $$self{EXIF_POS} unless defined $$self{FIRST_EXIF_POS}; $dataPt = \$$self{EXIF_DATA}; # set byte ordering @@ -6719,8 +7421,10 @@ sub DoProcessTIFF($$;$) # no longer do this because various files use different values # (TIFF=0x2a, RW2/RWL=0x55, HDP=0xbc, BTF=0x2b, ORF=0x4f52/0x5352/0x????) # return 0 unless $identifier == 0x2a; + $self->Warn('Invalid magic number in EXIF TIFF header') if $fileType eq 'APP1' and $identifier != 0x2a; # get offset to IFD0 + return 0 if length $$dataPt < 8; my $offset = Get32u($dataPt, 4); $offset >= 8 or return 0; @@ -6760,7 +7464,11 @@ sub DoProcessTIFF($$;$) # this looks like a BigTIFF image $raf->Seek(0); require Image::ExifTool::BigTIFF; - return 1 if Image::ExifTool::BigTIFF::ProcessBTF($self, $dirInfo); + my $result = Image::ExifTool::BigTIFF::ProcessBTF($self, $dirInfo); + if ($result) { + $self->FoundTag(PageCount => $$self{PageCount}) if $$self{MultiPage}; + return 1; + } } elsif ($identifier == 0x4f52 or $identifier == 0x5352) { # Olympus ORF image (set FileType now because base type is 'ORF') $self->SetFileType($fileType = 'ORF'); @@ -6788,10 +7496,12 @@ sub DoProcessTIFF($$;$) # don't process file if FastScan == 3 return 1 if not $outfile and $$self{OPTIONS}{FastScan} and $$self{OPTIONS}{FastScan} == 3; } - # (accomodate CR3 images which have a TIFF directory with ExifIFD at the top level) + # (accommodate CR3 images which have a TIFF directory with ExifIFD at the top level) my $ifdName = ($$dirInfo{DirName} and $$dirInfo{DirName} =~ /^(ExifIFD|GPS)$/) ? $1 : 'IFD0'; if (not $tagTablePtr or $$tagTablePtr{GROUPS}{0} eq 'EXIF') { $self->FoundTag('ExifByteOrder', $byteOrder) unless $outfile; + } elsif ($$tagTablePtr{GROUPS}{0} eq 'MakerNotes') { # (for writing CR3 maker notes) + $ifdName = $$tagTablePtr{GROUPS}{0}; } else { $ifdName = $$tagTablePtr{GROUPS}{1}; } @@ -6851,6 +7561,9 @@ sub DoProcessTIFF($$;$) # override whatever FileType we set since we now know it is DNG $self->OverrideFileType($$self{TIFF_TYPE} = 'DNG'); } + if ($$self{TIFF_TYPE} eq 'TIFF') { + $self->FoundTag(PageCount => $$self{PageCount}) if $$self{MultiPage}; + } return 1; } # @@ -6988,8 +7701,8 @@ sub DoProcessTIFF($$;$) # check DNG version if ($$self{DNGVersion}) { my $ver = $$self{DNGVersion}; - # currently support up to DNG version 1.4 - unless ($ver =~ /^(\d+) (\d+)/ and "$1.$2" <= 1.4) { + # currently support up to DNG version 1.6 + unless ($ver =~ /^(\d+) (\d+)/ and "$1.$2" <= 1.6) { $ver =~ tr/ /./; $self->Error("DNG Version $ver not yet tested", 1); } @@ -7056,6 +7769,7 @@ sub GetTagTable($) no strict 'refs'; $table = \%$tableName; use strict 'refs'; + &{$$table{INIT_TABLE}}($table) if $$table{INIT_TABLE}; $$table{TABLE_NAME} = $tableName; # set table name ($$table{SHORT_NAME} = $tableName) =~ s/^Image::ExifTool:://; # set default group 0 and 1 from module name unless already specified @@ -7139,7 +7853,7 @@ sub ProcessDirectory($$$;$) $dirName = $$tagTablePtr{GROUPS}{1} if $dirName =~ /^APP\d+$/; # (use specific APP name) $$dirInfo{DirName} = $dirName; } - + # guard against cyclical recursion into the same directory if (defined $$dirInfo{DirStart} and defined $$dirInfo{DataPos} and # directories don't overlap if the length is zero @@ -7162,7 +7876,9 @@ sub ProcessDirectory($$$;$) $$self{FOUND_DIR}{$dirName} = 1; # process the directory + no strict 'refs'; my $rtnVal = &$proc($self, $dirInfo, $tagTablePtr); + use strict 'refs'; pop @{$$self{PATH}}; @$self{'INDENT','DIR_NAME','Compression','SubfileType'} = @save; @@ -7172,7 +7888,7 @@ sub ProcessDirectory($$$;$) #------------------------------------------------------------------------------ # Get Metadata path -# Inputs: 0) Exiftool object ref +# Inputs: 0) ExifTool object ref # Return: Metadata path string sub MetadataPath($) { @@ -7254,8 +7970,11 @@ sub GetTagInfo($$$;$$$) next; } } - if ($$tagInfo{Unknown} and not $$self{OPTIONS}{Unknown} and not $$self{OPTIONS}{Verbose}) { - # don't return Unknown tags unless that option is set + # don't return Unknown tags unless that option is set (also see forum13716) + if ($$tagInfo{Unknown} and not $$self{OPTIONS}{Unknown} and not + ($$self{OPTIONS}{Verbose} or $$self{HTML_DUMP} or + ($$self{OPTIONS}{Validate} and not $$tagInfo{AddedUnknown}))) + { return undef; } # return the tag information we found @@ -7280,6 +7999,7 @@ sub GetTagInfo($$$;$$$) Unknown => 1, Writable => 0, # can't write unknown tags PrintConv => $printConv, + AddedUnknown => 1, }; # add tag information to table AddTagToTable($tagTablePtr, $tagID, $tagInfo); @@ -7294,9 +8014,10 @@ sub GetTagInfo($$$;$$$) # Inputs: 0) reference to tag table, 1) tag ID # 2) [optional] tag name or reference to tag information hash # 3) [optional] flag to avoid adding prefix when generating tag name +# Returns: tagInfo ref # Notes: - will not override existing entry in table # - info need contain no entries when this routine is called -# - tag name is made valid if necessary +# - tag name is cleaned if necessary sub AddTagToTable($$;$$) { my ($tagTablePtr, $tagID, $tagInfo, $noPrefix) = @_; @@ -7318,6 +8039,9 @@ sub AddTagToTable($$;$$) $$tagInfo{GotGroups} = 1, $$tagInfo{Table} = $tagTablePtr; $$tagInfo{TagID} = $tagID; + if (defined $$tagTablePtr{AVOID} and not defined $$tagInfo{Avoid}) { + $$tagInfo{Avoid} = $$tagTablePtr{AVOID}; + } my $name = $$tagInfo{Name}; $name = $tagID unless defined $name; @@ -7337,13 +8061,14 @@ sub AddTagToTable($$;$$) unless (defined $$tagTablePtr{$tagID} or $specialTags{$tagID}) { $$tagTablePtr{$tagID} = $tagInfo; } + return $tagInfo; } #------------------------------------------------------------------------------ # Handle simple extraction of new tag information # Inputs: 0) ExifTool object ref, 1) tag table reference, 2) tagID, 3) value, # 4-N) parameters hash: Index, DataPt, DataPos, Base, Start, Size, Parent, -# TagInfo, ProcessProc, RAF, Format +# TagInfo, ProcessProc, RAF, Format, Count # Returns: tag key or undef if tag not found # Notes: if value is not defined, it is extracted from DataPt using TagInfo # Format and Count if provided @@ -7357,7 +8082,7 @@ sub HandleTag($$$$;%) my ($subdir, $format, $noTagInfo, $rational); if ($tagInfo) { - $subdir = $$tagInfo{SubDirectory} + $subdir = $$tagInfo{SubDirectory}; } else { return undef unless $verbose; $tagInfo = { Name => "tag $tag" }; # create temporary tagInfo hash @@ -7524,6 +8249,14 @@ sub FoundTag($$$;@) $self->Warn("RawConv $tag: " . CleanWarning()) if $evalWarning; return undef unless defined $value; } + # ignore specified tags (AFTER doing RawConv if necessary!) + if ($$options{IgnoreTags}) { + if ($$options{IgnoreTags}{all}) { + return undef unless $$self{REQ_TAG_LOOKUP}{lc $tag}; + } else { + return undef if $$options{IgnoreTags}{lc $tag}; + } + } # handle duplicate tag names if (defined $$valueHash{$tag}) { # add to list if there is an active list for this tag @@ -7569,15 +8302,19 @@ sub FoundTag($$$;@) # increase 0-priority tags if this is the priority directory $priority = 1 if not $priority and $$self{DIR_NAME} and $$self{DIR_NAME} eq $$self{PRIORITY_DIR}; - } elsif ($$self{DIR_NAME} and $$self{LOW_PRIORITY_DIR}{$$self{DIR_NAME}}) { + } elsif ($$self{LOW_PRIORITY_DIR}{'*'} or + ($$self{DIR_NAME} and $$self{LOW_PRIORITY_DIR}{$$self{DIR_NAME}})) + { $priority = 0; # default is 0 for a LOW_PRIORITY_DIR } else { $priority = 1; # the normal default } - if ($priority >= $oldPriority and not $$self{DOC_NUM} and not $noListDel) { + if ($priority >= $oldPriority and (not $$self{DOC_NUM} or + ($$self{TAG_EXTRA}{$tag} and $$self{TAG_EXTRA}{$tag}{G3} and + $$self{DOC_NUM} eq $$self{TAG_EXTRA}{$tag}{G3})) and not $noListDel) + { # move existing tag out of the way since this tag is higher priority # (NOTE: any new members added here must also be added to DeleteTag()) - $$self{MOVED_KEY} = $nextTag; # used in BuildCompositeTags() $$self{PRIORITY}{$nextTag} = $$self{PRIORITY}{$tag}; $$valueHash{$nextTag} = $$valueHash{$tag}; $$self{FILE_ORDER}{$nextTag} = $$self{FILE_ORDER}{$tag}; @@ -7591,6 +8328,12 @@ sub FoundTag($$$;@) delete $$self{BOTH}{$tag}; # update tag key for list if necessary $$self{LIST_TAGS}{$oldInfo} = $nextTag if $$self{LIST_TAGS}{$oldInfo}; + # update this key if used in a Composite tag + if ($$self{COMP_KEYS}{$tag}) { + $$_[0]{$$_[1]} = $nextTag foreach @{$$self{COMP_KEYS}{$tag}}; + $$self{COMP_KEYS}{$nextTag} = $$self{COMP_KEYS}{$tag}; + delete $$self{COMP_KEYS}{$tag}; + } } else { $tag = $nextTag; # don't override the existing tag } @@ -7716,6 +8459,7 @@ sub SetFileType($;$$$) $normExt = $fileTypeExt{$fileType}; $normExt = $fileType unless defined $normExt; } + $$self{FileType} = $fileType; $self->FoundTag('FileType', $fileType); $self->FoundTag('FileTypeExtension', uc $normExt); $self->FoundTag('MIMEType', $mimeType || 'application/unknown'); @@ -7724,12 +8468,13 @@ sub SetFileType($;$$$) #------------------------------------------------------------------------------ # Override the FileType and MIMEType tags -# Inputs: 0) ExifTool object ref, 1) file type, 2) MIME type, 3) normal extension +# Inputs: 0) ExifTool object ref, 1) file type, 2) MIME type, 3) normal extension (lower case) # Notes: does nothing if FileType was not previously defined (ie. when writing) sub OverrideFileType($$;$$) { my ($self, $fileType, $mimeType, $normExt) = @_; if (defined $$self{VALUE}{FileType} and $fileType ne $$self{VALUE}{FileType}) { + $$self{FileType} = $fileType; $$self{VALUE}{FileType} = $fileType; unless (defined $normExt) { $normExt = $fileTypeExt{$fileType}; @@ -7795,7 +8540,7 @@ sub VerboseDir($$;$$) } my $indent = substr($$self{INDENT}, 0, -2); my $out = $$self{OPTIONS}{TextOut}; - my $str = $entries ? " with $entries entries" : ''; + my $str = ($entries or defined $entries and not $size) ? " with $entries entries" : ''; $str .= ", $size bytes" if $size; print $out "$indent+ [$name directory$str]\n"; } @@ -8043,7 +8788,8 @@ sub ProcessBinaryData($$$) # hook to allow format, etc to be set dynamically if (defined $$tagInfo{Hook}) { my $oldVarSize = $varSize; - #### eval Hook ($format, $varSize, $size) + my $pos = $entry + $offset; + #### eval Hook ($format, $varSize, $size, $dataPt, $pos) eval $$tagInfo{Hook}; # save variable size data if required for writing (in case changed by Hook) if ($$dirInfo{VarFormatData}) { @@ -8068,6 +8814,7 @@ sub ProcessBinaryData($$$) # read value now if necessary unless (defined $val and not $$tagInfo{SubDirectory}) { $val = ReadValue($dataPt, $entry+$offset, $format, $count, $more, \$rational); + next unless defined $val; $mask = $$tagInfo{Mask}; $val = ($val & $mask) >> $$tagInfo{BitShift} if $mask; } @@ -8169,7 +8916,8 @@ until ($Image::ExifTool::noConfig) { $file = $config; } # also check executable directory unless path is absolute - -r $file or $config =~ /^\// or $file = ($0 =~ /(.*[\\\/])/ ? $1 : './') . $config; + $exeDir = ($0 =~ /(.*)[\\\/]/) ? $1 : '.' unless defined $exeDir; + -r $file or $config =~ /^\// or $file = "$exeDir/$config"; unless (-r $file) { warn("Config file not found\n") if defined $Image::ExifTool::configFile; last; diff --git a/src/Image-ExifTool/lib/Image/ExifTool.pod b/src/Image-ExifTool/lib/Image/ExifTool.pod index 62caae75..73330464 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool.pod +++ b/src/Image-ExifTool/lib/Image/ExifTool.pod @@ -3,9 +3,9 @@ # # Description: Read and write meta information # -# URL: http://owl.phy.queensu.ca/~phil/exiftool/ +# URL: https://exiftool.org/ # -# Legal: Copyright (c) 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +# Legal: Copyright (c) 2003-2022, Phil Harvey (philharvey66 at gmail.com) # This library is free software; you can redistribute it and/or # modify it under the same terms as Perl itself. #------------------------------------------------------------------------------ @@ -65,44 +65,48 @@ supported by ExifTool (r = read, w = write, c = create): File Types ------------+-------------+-------------+-------------+------------ - 3FR r | DR4 r/w/c | J2C r | ODP r | RAW r/w - 3G2 r/w | DSS r | JNG r/w | ODS r | RIFF r - 3GP r/w | DV r | JP2 r/w | ODT r | RSRC r - A r | DVB r/w | JPEG r/w | OFR r | RTF r - AA r | DVR-MS r | JSON r | OGG r | RW2 r/w - AAE r | DYLIB r | K25 r | OGV r | RWL r/w - AAX r/w | EIP r | KDC r | OPUS r | RWZ r - ACR r | EPS r/w | KEY r | ORF r/w | RM r - AFM r | EPUB r | LA r | OTF r | SEQ r - AI r/w | ERF r/w | LFP r | PAC r | SKETCH r - AIFF r | EXE r | LNK r | PAGES r | SO r - APE r | EXIF r/w/c | M2TS r | PBM r/w | SR2 r/w - ARQ r/w | EXR r | M4A/V r/w | PCD r | SRF r - ARW r/w | EXV r/w/c | MAX r | PDB r | SRW r/w - ASF r | F4A/V r/w | MEF r/w | PDF r/w | SVG r - AVI r | FFF r/w | MIE r/w/c | PEF r/w | SWF r - AZW r | FLA r | MIFF r | PFA r | THM r/w - BMP r | FLAC r | MKA r | PFB r | TIFF r/w - BPG r | FLIF r/w | MKS r | PFM r | TORRENT r - BTF r | FLV r | MKV r | PGF r | TTC r - CHM r | FPF r | MNG r/w | PGM r/w | TTF r - COS r | FPX r | MOBI r | PLIST r | VCF r - CR2 r/w | GIF r/w | MODD r | PICT r | VRD r/w/c - CR3 r/w | GPR r/w | MOI r | PMP r | VSD r - CRM r/w | GZ r | MOS r/w | PNG r/w | WAV r - CRW r/w | HDP r/w | MOV r/w | PPM r/w | WDP r/w - CS1 r/w | HDR r | MP3 r | PPT r | WEBP r - DCM r | HEIC r | MP4 r/w | PPTX r | WEBM r - DCP r/w | HEIF r | MPC r | PS r/w | WMA r - DCR r | HTML r | MPG r | PSB r/w | WMV r - DFONT r | ICC r/w/c | MPO r/w | PSD r/w | WTV r - DIVX r | ICS r | MQV r/w | PSP r | WV r - DJVU r | IDML r | MRW r/w | QTIF r/w | X3F r/w - DLL r | IIQ r/w | MXF r | R3D r | XCF r - DNG r/w | IND r/w | NEF r/w | RA r | XLS r - DOC r | INX r | NRW r/w | RAF r/w | XLSX r - DOCX r | ISO r | NUMBERS r | RAM r | XMP r/w/c - DPX r | ITC r | O r | RAR r | ZIP r + 360 r/w | DR4 r/w/c | JNG r/w | O r | RAW r/w + 3FR r | DSS r | JP2 r/w | ODP r | RIFF r + 3G2 r/w | DV r | JPEG r/w | ODS r | RSRC r + 3GP r/w | DVB r/w | JSON r | ODT r | RTF r + A r | DVR-MS r | JXL r | OFR r | RW2 r/w + AA r | DYLIB r | K25 r | OGG r | RWL r/w + AAE r | EIP r | KDC r | OGV r | RWZ r + AAX r/w | EPS r/w | KEY r | ONP r | RM r + ACR r | EPUB r | LA r | OPUS r | SEQ r + AFM r | ERF r/w | LFP r | ORF r/w | SKETCH r + AI r/w | EXE r | LIF r | ORI r/w | SO r + AIFF r | EXIF r/w/c | LNK r | OTF r | SR2 r/w + APE r | EXR r | LRV r/w | PAC r | SRF r + ARQ r/w | EXV r/w/c | M2TS r | PAGES r | SRW r/w + ARW r/w | F4A/V r/w | M4A/V r/w | PBM r/w | SVG r + ASF r | FFF r/w | MACOS r | PCD r | SWF r + AVI r | FITS r | MAX r | PCX r | THM r/w + AVIF r/w | FLA r | MEF r/w | PDB r | TIFF r/w + AZW r | FLAC r | MIE r/w/ | PDF r/w | TORRENT r + BMP r | FLIF r/w | MIFF r c | PEF r/w | TTC r + BPG r | FLV r | MKA r | PFA r | TTF r + BTF r | FPF r | MKS r | PFB r | TXT r + CHM r | FPX r | MKV r | PFM r | VCF r + COS r | GIF r/w | MNG r/w | PGF r | VRD r/w/c + CR2 r/w | GPR r/w | MOBI r | PGM r/w | VSD r + CR3 r/w | GZ r | MODD r | PLIST r | WAV r + CRM r/w | HDP r/w | MOI r | PICT r | WDP r/w + CRW r/w | HDR r | MOS r/w | PMP r | WEBP r + CS1 r/w | HEIC r/w | MOV r/w | PNG r/w | WEBM r + CSV r | HEIF r/w | MP3 r | PPM r/w | WMA r + CZI r | HTML r | MP4 r/w | PPT r | WMV r + DCM r | ICC r/w/c | MPC r | PPTX r | WTV r + DCP r/w | ICS r | MPG r | PS r/w | WV r + DCR r | IDML r | MPO r/w | PSB r/w | X3F r/w + DFONT r | IIQ r/w | MQV r/w | PSD r/w | XCF r + DIVX r | IND r/w | MRC r | PSP r | XLS r + DJVU r | INSP r/w | MRW r/w | QTIF r/w | XLSX r + DLL r | INSV r | MXF r | R3D r | XMP r/w/c + DNG r/w | INX r | NEF r/w | RA r | ZIP r + DOC r | ISO r | NKSC r/w | RAF r/w | + DOCX r | ITC r | NRW r/w | RAM r | + DPX r | J2C r | NUMBERS r | RAR r | Meta Information ----------------------+----------------------+--------------------- @@ -173,6 +177,9 @@ Creates a new ExifTool object. $exifTool = new Image::ExifTool; +One ExifTool object may be used to process many files, so creating multiple +ExifTool objects usually is not necessary. + Note that ExifTool uses AUTOLOAD to load non-member methods, so any class using Image::ExifTool as a base class must define an AUTOLOAD which calls Image::ExifTool::DoAutoLoad(). eg) @@ -304,7 +311,7 @@ L settings. =item Return Values: -L returns a reference to a hash of tag key/value pairs. The tag +L returns a reference to a hash of tag-key/value pairs. The tag keys are identifiers -- essentially case-sensitive tag names with an appended instance number if multiple tags with the same name were extracted from the image. Many of the ExifTool functions require a tag key as an @@ -383,7 +390,8 @@ to some functions. Option names are not case sensitive. The default option values may be changed by defining a %Image::ExifTool::UserDefined::Options hash. See the ExifTool_config file -in the full ExifTool distribution for examples. +in the full ExifTool distribution for examples. A default of undef has the +same behaviour as a value of 0 for numerical options. # exclude the 'OwnerName' tag from returned information $exifTool->Options(Exclude => 'OwnerName'); @@ -423,6 +431,9 @@ in the full ExifTool distribution for examples. =item Option Parameters: +Note that these API options may also be used in the exiftool application via +the command-line B<-api> option. + =over 4 =item Binary @@ -432,6 +443,13 @@ large binary data blocks (eg. ThumbnailImage) are not necessarily extracted unless this option is set or the tag is specifically requested by name. Default is undef. +=item BlockExtract + +Flag to extract some directories (mentioned in the +L) as a block. +Setting this to a value of 2 also prevents parsing the block to extract tags +contained within. + =item ByteOrder The byte order for newly created EXIF segments when writing. Note that if @@ -463,6 +481,7 @@ below, case is not significant: Thai cp874 Windows Thai DOSLatinUS cp437 DOS Latin US DOSLatin1 cp850 DOS Latin1 + DOSCyrillic cp866 DOS Cyrillic MacRoman cp10000, Roman Macintosh Roman MacLatin2 cp10029 Macintosh Latin2 (Central Europe) MacCyrillic cp10007 Macintosh Cyrillic @@ -525,12 +544,22 @@ without recoding. Default is 0. =item Compact -Option to write compact XMP output. The XMP specification suggests that the -data be padded with blanks to allow in-place editing. With this flag set to -1, the 2 kB of padding is not written. Note that this only effects embedded -XMP since padding is never written for stand-alone XMP files. When set to -2, spaces to indent XMP for readability are also dropped. Default is undef. -Also see the XMPShorthand option for reducing the size of XMP. +Comma-delimited list of settings for writing compact XMP. Below is a list +of available settings. Note that 'NoPadding' effects only embedded XMP +since padding is never written for stand-alone XMP files. Also note that +'OneDesc' is not recommended when writing XMP larger than 64 kB to a JPG +file because it interferes with ExifTool's technique of splitting off large +rdf:Description elements into the extended XMP. Case is not significant for +any of these options. Aliases are given in brackets. Default is undef. + + NoPadding - Avoid 2 kB of recommended padding at end of XMP (NoPad) + NoIndent - No spaces to indent lines (NoSpace, NoSpaces) + NoNewline - Avoid unnecessary newlines (NoNewlines) + Shorthand - Use XMP Shorthand format + OneDesc - Combine properties into a single rdf:Description (OneDescr) + AllSpace - Equivalent to 'NoPadding,NoIndent,NoNewline' + AllFormat - Equivalent to 'Shorthand,OneDesc' + All - Equivalent to 'AllSpace,AllFormat' =item Composite @@ -564,12 +593,13 @@ different when copying tags with L. =item DateFormat Format for printing date/time values. See C in the L -package for details about the format string. If date can not be converted, -value is left unchanged unless the StrictDate option is set. Timezones are -ignored. 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"). +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 +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"). =item Duplicates @@ -599,39 +629,59 @@ GUID specified by the HasExtendedXMP tag, so by default ExifTool will ignore other extended XMP, but this option allows full control over the extended XMP to be extracted. - 0 - ignore all extended XMP - 1 - read extended XMP with valid GUID only (default) - 2 - read extended XMP with any GUID - - read extended XMP with a specific GUID + 0 - Ignore all extended XMP + 1 - Read extended XMP with valid GUID only (default) + 2 - Read extended XMP with any GUID + - Read extended XMP with a specific GUID =item ExtractEmbedded Flag to extract information from embedded documents in EPS files, embedded EPS information and JPEG and Jpeg2000 images in PDF files, embedded MPF -images in JPEG and MPO files, streaming metadata in AVCHD videos, and the -resource fork of Mac OS files. Default is undef. +images in JPEG and MPO files, metadata after the first Cluster in MKV files, +timed metadata in videos, and the resource fork of Mac OS files. A setting +of 2 also causes the H264 video stream in MP4 files to be parsed until the +first SEI message is decoded, or 3 to parse the entire H264 stream in MP4 +videos and the entire M2TS file to look for any unlisted program containing +GPS metadata. Default is undef. =item FastScan -Flag to increase speed of extracting information from JPEG images. With -this option set to 1, ExifTool will not scan to the end of a JPEG image to -check for an AFCP, CanonVRD, FotoStation, PhotoMechanic, MIE or PreviewImage -trailer. This also stops the parsing after the first comment in GIF images, -and at the audio/video data with RIFF-format files (AVI, WAV, etc), so any -trailing metadata (eg. XMP written by some utilities) may be missed. Also -disables input buffering for some types of files to reduce memory usage when -reading from a non-seekable stream. When combined with the ScanForXMP -option, prevents scanning for XMP in recognized file types. With a value of -2, ExifTool will also avoid extracting any EXIF MakerNote information. When -set to 3, the file is not actually parsed, and only an initial guess at -FileType and some pseudo tags are returned. Default is undef. +Flag to increase speed when reading files by avoiding extraction of some +types of metadata. With this option set to 1, ExifTool will not scan to the +end of a JPEG image to check for an AFCP, CanonVRD, FotoStation, +PhotoMechanic, MIE or PreviewImage trailer. This also stops the parsing +after the first comment in GIF images, and at the audio/video data of +RIFF-format files (AVI, WAV, etc), so any trailing metadata (eg. XMP written +by some utilities) may be missed. Also disables input buffering for some +types of files to reduce memory usage when reading from a non-seekable +stream, and bypasses CRC validation for speed when writing PNG files. When +combined with the ScanForXMP option, prevents scanning for XMP in recognized +file types. With a value of 2, ExifTool will also avoid extracting any EXIF +MakerNote information, and will stop parsing at the IDAT chunk of PNG +images. (By the PNG specification, metadata is allowed after IDAT, but +ExifTool always writes it before because some utilities will ignore it +otherwise.) When set to 3 or higher, only pseudo system tags and FileType +are generated. For 3, the file header is read to provide an educated guess +at FileType. For 4, the file is not read at all and FileType is determined +based on the file's extension. For 5, generation of Composite tags is also +disabled (like setting L to 0). Default is undef. =item Filter Perl expression used to filter values for all tags. The expression acts on the value of the Perl default variable ($_), and changes the value of this -variable as required. The value is not changed if $_ is set to undef. -Applies to all returned values unless PrintConv option is disabled. +variable as required. The current ExifTool object may be accessed through +$self. The value is not changed if $_ is set to undef. List items are +filtered individually. Applies to all returned values unless PrintConv +option is disabled. + +=item FilterW + +Perl expression used to filter PrintConv values when writing. The +expression acts on the value of the Perl default variable ($_), and changes +the value of this variable as required. The current ExifTool object may be +accessed through $self. The tag is not written if $_ is set to undef. =item FixBase @@ -657,8 +707,9 @@ it is within GeoMaxExtSecs, otherwise geotagging fails). Default is 1800. Maximum extrapolation time in seconds for geotagging. Geotagging fails if the Geotime value lies outside a GPS track by a number of seconds greater -than this. Otherwise, the coordinates of the nearest fix are taken. -Default is 1800. +than this. Otherwise, for an extrapolation the coordinates of the nearest +fix are taken (ie. it is assumed that you weren't moving during this +period). Default is 1800. =item GeoMaxHDOP @@ -699,6 +750,11 @@ to be excluded by preceding group name with a '-'. See L for a description of group families, and L for lists of group names. +=item HexTagIDs + +Return hexadecimal instead of decimal for the family 7 group names of tags +with numerical ID's. + =item HtmlDump Dump information in hex to dynamic HTML web page. The value may be 0-3 for @@ -721,6 +777,15 @@ images even if they don't have a recognizable header). Minor errors and warnings are denoted by "[minor]" at the start of the message, or "[Minor]" (with a capital "M") for warnings that affect processing when ignored. +=item IgnoreTags + +List of tag names to ignore when reading. This may help in situations where +memory is limited because the ignored tag values are not stored in memory. +The tag names are case insensitive and group names and wildcards are not +allowed. A special tag name of "All" may be used to ignore all tags except +those specified by the L option. Set to undef to clear the +previous IgnoreTags list. Default is undef. + =item Lang Localized language for exiftool tag descriptions, etc. Available languages @@ -772,9 +837,15 @@ L for more information). =item MissingTagValue -Value for missing tags in tag name expressions. If not set, a minor error -is issued for missing values, or the value is set to '' if -L is set. Default is undef. +Value for missing tags in tag name expressions (or tags where the advanced +formatting expression returns undef). If not set, a minor error is issued +for missing values, or the value is set to '' if L is +set. Default is undef. + +=item NoMultiExif + +Raise error when attempting to write multi-segment EXIF in a JPEG image. +Default is undef. =item NoPDFList @@ -787,28 +858,27 @@ Password for reading/writing password-protected PDF documents. Ignored if a password is not required. Character encoding of the password is determined by the value of the Charset option at processing time. Default is undef. -=item PNGEarlyXMP - -Flag to write XMP in PNG images before the IDAT (image data) chunk. By -default, ExifTool adds new XMP to the end of a PNG file (just before IEND). -This is allowed by the PNG and XMP specifications, but some utilities seem -to ignore XMP if it comes after the image data. The PNGEarlyXMP option -causes ExifTool to instead add new XMP before the PNG IDAT chunk. However, -since ExifTool uses a single-pass writing algorithm, it has no way to tell -if XMP already exists later in the file before writing the new XMP in this -location. If this happens, a minor error is issued when the extra XMP is -encountered, and the file is not written. Adding the L -option causes the XMP after IDAT to be deleted, thus resolving the conflict -(at the expense of possible metadata loss), and allowing the file to be -written. The PNGEarlyXMP option is applied automatically when deleting all -XMP and writing new XMP back in one step. When reading, this option causes -a warning to be issued if standard XMP is found after the IDAT chunk. - =item PrintConv Flag to enable automatic print conversion. Also enables inverse print conversion for writing. Default is 1. +=item QuickTimeHandler + +Flag set to add an 'mdir' Handler to a newly created Meta box when adding +QuickTime ItemList tags. Adobe Bridge does not add this Handler, but it is +commonly found in samples from other software, and it has been reported that +Apple QuickTime Player and Photos.apps will ignore ItemList tags if this is +missing. Default is 1. + +=item QuickTimePad + +Flag to preserve the padding of some QuickTime atoms when writing. +QuickTime-based Canon CR3 files pad the values of container atoms with null +bytes. This padding is removed by default when the file is rewritten, but +setting this option to 1 adds padding to preserve the original atom size if +the new atom would be smaller than the original. Default is undef. + =item QuickTimeUTC Flag set to assume that QuickTime date/time values are stored as UTC, @@ -816,9 +886,10 @@ causing conversion to local time when they are extracted and from local time when written. According to the QuickTime specification date/time values should be UTC, but many digital cameras store local time instead (presumably because they don't know the time zone), so the default is to not convert -these times. This option also disables the autodetection of incorrect -time-zero offsets in QuickTime date/time values, and enforces a time zero of -1904 as per the QuickTime specification. +these times (except for Canon CR3 files, which always use UTC times). This +option also disables the autodetection of incorrect time-zero offsets in +QuickTime date/time values, and enforces a time zero of 1904 as per the +QuickTime specification. =item RequestAll @@ -838,6 +909,19 @@ current RequestTags list. Groups are requested by adding a colon after the name (eg. "MacOS:"). Names are converted to lower case as they are added to the list. Default is undef. +=item SaveFormat + +Flag to save EXIF/TIFF format type as the family 6 group name when +extracting information. Without this option set, the family 6 group names +are not generated. Default is undef. See the L option for more +details. + +=item SavePath + +Flag to save the metadata path as the family 5 group name when extracting +information. Without this option set, the family 5 group names are not +generated. Default is undef. See the L option for more details. + =item ScanForXMP Flag to scan all files (even unrecognized formats) for XMP information @@ -937,14 +1021,16 @@ Where I is the user-defined parameter name (case insensitive). User-defined parameters may be accessed in tag name expressions by prefixing the parameter name with a dollar sign just like normal tags, or via the API -by calling C. If called without no additional -arguments, C returns a reference to the hash of all -user parameters (with lower-case names). +by calling C. Appending a hash tag (C<#>) to +the parameter name also causes the parameter to be extracted as a normal tag +(in the UserParam group). If called without additional arguments, +C returns a reference to the hash of all user +parameters (with lower-case names). =item Validate -Flag to perform extra validation checks when reading, causing extra warnings -to be generated if problems are found. Default is undef. +Flag to perform extra validation metadata checks when reading, causing extra +warnings to be generated if problems are found. Default is undef. =item Verbose @@ -967,7 +1053,9 @@ list below. Default is 'wcg'. The level of the group differs for different types of metadata. For XMP or IPTC this is the full XMP/IPTC block (the family 0 group), but for EXIF this -is the individual IFD (the family 1 group). +is the individual IFD (the family 1 group). The 'w' and 'c' modes are +tested only when L is called, but the 'g' mode is also tested +in L. =item XAttrTags @@ -979,10 +1067,6 @@ and L for more information). Flag to enable automatic conversion for unknown XMP tags with values that look like rational numbers or dates. Default is 1. -=item XMPShorthand - -Flag set to write xmp in shorthand format. Default is undef. - =back =item Return Values: @@ -1029,10 +1113,10 @@ L: Binary, Charset, CharsetEXIF, CharsetFileName, CharsetID3, CharsetIPTC, CharsetPhotoshop, CharsetQuickTime, CharsetRIFF, Composite, ExtendedXMP, ExtractEmbedded, FastScan, FixBase, HtmlDump, HtmlDumpBase, -IgnoreMinorErrors, Lang, LargeFileSupport, MakerNotes, MDItemTags, -NoPDFList, Password, PNGEarlyXMP, QuickTimeUTC (enforced 1904 time zero), -RequestAll, RequestTags, ScanForXMP, Struct, TextOut, Unknown, Verbose, -XAttrTags and XMPAutoConv. +IgnoreMinorErrors, IgnoreTags, Lang, LargeFileSupport, MakerNotes, +MDItemTags, NoPDFList, Password, QuickTimeUTC (enforced 1904 time zero), +RequestAll, RequestTags, SaveFormat, SavePath, ScanForXMP, Struct, TextOut, +Unknown, Verbose, XAttrTags and XMPAutoConv. =item Return Value: @@ -1092,11 +1176,17 @@ created in the destination file as required to store the specified information. May be called repeatedly to write the same information to additional files without the need to call L again. -Note that it is NOT necessary to call L or L +ExifTool queues all new values that are assigned via calls to +L, then applies them to any number of files through one or +more calls to L. These queued values may be accessed through +L, and are completely separate from metadata extracted from +files via L or L and accessed through L +or L. + +To be clear, it is NOT necessary to call L or L before L. L changes only metadata specified by previous calls to L. - # add information to a source file, writing output to new file $exifTool->WriteInfo($srcfile, $dstfile); @@ -1117,8 +1207,9 @@ file from scratch. A reference to a L object is also allowed as a source, but in this case the destination is not optional. -2) [optional] Destination file name, file reference, scalar reference, or -undef to overwrite the original file. May be '-' to write to stdout. +2) [optional] Destination file name, file reference, scalar reference to +write to memory, or undef to overwrite the original file. May be '-' to +write to stdout. 3) [optional] Destination file type. Ignored if a source is defined. @@ -1163,7 +1254,8 @@ called with a source file name. The following ExifTool options are effective in the call to L: ByteOrder, Charset, CharsetEXIF, CharsetFileName, CharsetIPTC, Compact, -Compress, FixBase, IgnoreMinorErrors, Password, PNGEarlyXMP and Verbose. +Compress, FixBase, IgnoreMinorErrors, NoMultiExif, NoPDFList, Password, +QuickTimeHandler, QuickTimePad, Verbose and WriteMode. =head2 GetTagList @@ -1290,8 +1382,8 @@ optional group specifier), use L instead. The following options are in effect when L is called: Charset, CoordFormat, DateFormat, Escape, Filter, GlobalTimeShift, Lang, -ListItem, ListJoin, PrintConv, QuickTimeUTC (conversion to local time), and -StrictDate. +ListItem, ListJoin, PrintConv, QuickTimeUTC (conversion to local time), +StrictDate and TimeZone. =over 4 @@ -1398,8 +1490,8 @@ name for each value, or call with a reference to the list of values. # write structured information as a serialized string $exifTool->SetNewValue('XMP:Flash'=>'{mode=on,fired=true,return=not}'); -(See L for -a description of the structure serialization technique.) +(See L for a description of the +structure serialization technique.) =over 4 @@ -1413,13 +1505,13 @@ optional leading family numbers, separated by colons (eg. 'EXIF:Artist', 'XMP:Time:*'), which is equivalent to using a Group option argument. Also, a '#' may be appended to the tag name (eg. 'EXIF:Orientation#'), with the same effect as setting Type to 'ValueConv'. Wildcards ('*' and '?') may be -used in the tag name to assign multiple tags simultaneously. A tag name of -'*' is special when deleting information, and will delete an entire group -even if some individual tags in the group are not writable, but only if a -single family 0 or 1 group is specified (otherwise the tags are deleted -individually). Use L to get a list of deletable group -names, and see L for a -complete list of tag names. +used in the tag name to assign or delete multiple tags simultaneously. A +tag name of '*' is special when deleting information, and will delete an +entire group even if some individual tags in the group are not writable, but +only if a single family 0 or 1 group is specified (otherwise the tags are +deleted individually). Use L to get a list of deletable +group names, and see L +for a complete list of tag names. 2) [optional] New value for tag. Undefined to delete tag from file. May be a scalar, scalar reference, list reference to set a list of values, or hash @@ -1437,9 +1529,9 @@ hash reference or a serialized string (see the last two examples above). =item AddValue Specifies that the value be added to an existing list in a file rather than -overwriting. Valid settings are 0 (overwrite any existing tag value), 1 -(add to an existing list and warn for non-list tags) or 2 (add to existing -list and overwrite non-list tags). Default is 0. +overwriting the existing values. Valid settings are 0 (overwrite any +existing tag value), 1 (add to an existing list and warn for non-list tags) +or 2 (add to existing list and overwrite non-list tags). Default is 0. =item DelValue @@ -1501,8 +1593,8 @@ Flag to replace the previous new values for this tag (ie. replace the values set in previous calls to L). This option is most commonly used to replace previously-set new values for list-type tags. Valid values are 0 (set new value normally -- adds to new values for list-type tags), 1 -(reset previous new values for this tag and replace with the specified new -value) or 2 (reset previous new values only). +(reset any previous new values before setting new value) or 2 (reset +previous new values only; new value argument is ignored). Default is 0. =item Shift @@ -1546,7 +1638,7 @@ explicitly, either by group (with 'Adobe:*') or as a block (with 'Adobe'). The following ExifTool options are effective in the call to L: Charset, DateFormat, Escape, IgnoreMinorErrors, Lang, ListJoin, ListSplit, -PrintConv, QuickTimeUTC, StrictDate, Verbose and WriteMode. +PrintConv, QuickTimeUTC, StrictDate, TimeZone, Verbose and WriteMode. =head2 GetNewValue @@ -1564,7 +1656,8 @@ values in list context. 0) ExifTool object reference -1) Tag name (case sensitive, may be prefixed by family 0 or 1 group name) +1) Tag name (case sensitive, may be prefixed by family 0, 1 or 7 group +names, separated by colons) =item Return Values: @@ -1626,34 +1719,35 @@ in a specified file. 2-N) [optional] List of tag names to set or options hash references. All writable tags are set if none are specified. The tag names are not case -sensitive, and may be prefixed by one or more family 0, 1 or 2 group names -with optional leading family numbers, separated by colons (eg. 'exif:iso'). -A leading '-' indicates tags to be excluded (eg. '-comment'), or a trailing -'#' causes the ValueConv value to be copied (same as setting the Type option -to 'ValueConv' for this tag only). Wildcards ('*' and '?') may be used in -the tag name. A tag name of '*' is commonly used when a group is specified -to copy all tags in the group (eg. 'XMP:*'). A special feature allows tag -names of the form 'DSTTAGESRCTAG' (or 'SRCTAGEDSTTAG') to be -specified to copy information to a tag with a different name or a specified -group. Both 'SRCTAG' and 'DSTTAG' may contain wildcards and/or be prefixed -by a group name (eg. 'fileModifyDateEmodifyDate' or 'xmp:*E*'), -and/or suffixed by a '#' to disable print conversion. Copied tags may also -be added or deleted from a list with arguments of the form -'DSTTAG+ESRCTAG' or 'DSTTAG-ESRCTAG'. Tags are evaluated in order, -so exclusions apply only to tags included earlier in the list. An extension -of this feature allows the tag value to be set from a string containing tag -names with leading '$' symbols (eg. 'CommentEthe file is $filename'). -Braces '{}' may be used around the tag name to separate it from subsequent -text, and a '$$' is used to to represent a '$' symbol. The behaviour for -missing tags in expressions is defined by the L option. -The tag value may be modified via changes to the default input variable ($_) -in a Perl expression placed inside the braces and after a semicolon -following the tag name (see the last example above). A '@' may be added -after the tag name (before the semicolon) to make the expression act on -individual list items instead of the concatenated string for list-type tags. -Braces within the expression must be balanced. Multiple options hash -references may be passed to set different options for different tags. -Options apply to subsequent tags in the argument list. +sensitive, and may be prefixed by one or more family 0, 1, 2 or 7 group +names with optional leading family numbers, separated by colons (eg. +'exif:iso'). A leading '-' indicates tags to be excluded (eg. '-comment'), +or a trailing '#' causes the ValueConv value to be copied (same as setting +the Type option to 'ValueConv' for this tag only). Wildcards ('*' and '?') +may be used in the tag name. A tag name of '*' is commonly used when a +group is specified to copy all tags in the group (eg. 'XMP:*'). A special +feature allows tag names of the form 'DSTTAGESRCTAG' (or +'SRCTAGEDSTTAG') to be specified to copy information to a tag with a +different name or a specified group. Both 'SRCTAG' and 'DSTTAG' may contain +wildcards and/or be prefixed by a group name (eg. +'fileModifyDateEmodifyDate' or 'xmp:*E*'), and/or suffixed by a '#' +to disable print conversion. Copied tags may also be added or deleted from +a list with arguments of the form 'DSTTAG+ESRCTAG' or +'DSTTAG-ESRCTAG'. Tags are evaluated in order, so exclusions apply only +to tags included earlier in the list. An extension of this feature allows +the tag value to be set from a string containing tag names with leading '$' +symbols (eg. 'CommentEthe file is $filename'). Braces '{}' may be used +around the tag name to separate it from subsequent text, and a '$$' is used +to to represent a '$' symbol. The behaviour for missing tags in expressions +is defined by the L option. The tag value may be modified +via changes to the default input variable ($_) in a Perl expression placed +inside the braces and after a semicolon following the tag name (see the last +example above). A '@' may be added after the tag name (before the +semicolon) to make the expression act on individual list items instead of +the concatenated string for list-type tags. Braces within the expression +must be balanced. Multiple options hash references may be passed to set +different options for different tags. Options apply to subsequent tags in +the argument list. By default, this routine will commute information between same-named tags in different groups, allowing information to be translated between images with @@ -1814,11 +1908,11 @@ systems only. Set the file name and directory, or create a hard link. If not specified, the new file name is derived from the new values of the FileName and -Directory tags, or from the HardLink tag if creating a link. If the -FileName tag contains a '/', then the file is renamed into a new directory. -If FileName ends with '/', then it is taken as a directory name and the file -is moved into the new directory. The new value for the Directory tag takes -precedence over any directory specified in FileName. +Directory tags, or from the HardLink or SymLink tag if creating a link. If +the FileName tag contains a '/', then the file is renamed into a new +directory. If FileName ends with '/', then it is taken as a directory name +and the file is moved into the new directory. The new value for the +Directory tag takes precedence over any directory specified in FileName. $result = $exifTool->SetFileName($file); $result = $exifTool->SetFileName($file, $newName); @@ -1833,18 +1927,20 @@ precedence over any directory specified in FileName. 2) [optional] New file name -3) [optional] 'Link' to create a hard link instead of renaming the file, or -'Test' to test renaming feature by printing the old and new names instead of -changing anything. +3) [optional] 'HardLink' or 'SymLink' to create a hard or symbolic link +instead of renaming the file, or 'Test' to test renaming feature by printing +the old and new names instead of changing anything. =item Return Value: -1 if the file name or directory was changed, 0 if nothing was done, or -1 if -there was an error renaming the file. +1 on success, 0 if nothing was done, or -1 if there was an error renaming the +file or creating the link. =item Notes: -Will not overwrite existing files. New directories are created as necessary. +Will not overwrite existing files. New directories are created as necessary. +If the file is successfully renamed, the new file name may be accessed via +C<$$exifTool{NewName}>. =back @@ -1854,8 +1950,9 @@ Set the order of the preferred groups when adding new information. In subsequent calls to L, new information will be created in the first valid group of this list. This has an impact only if the group is not specified when calling L and if the tag name exists in more -than one group. The default order is EXIF, IPTC then XMP. Any family 0 -group name may be used. Case is not significant. +than one group. The default order is EXIF, IPTC, XMP, MakerNotes, +QuickTime, Photoshop, ICC_Profile, CanonVRD, Adobe. Any family 0 group name +may be used. Case is not significant. $exifTool->SetNewGroups('XMP','EXIF','IPTC'); @@ -1984,6 +2081,9 @@ The group family numbers are currently available: 2) Category (eg. Author, Time) 3) Document Number (eg. Main, Doc1, Doc3-2) 4) Instance Number (eg. Copy1, Copy2, Copy3...) + 5) Metadata Path (eg. JPEG-APP1-IFD0-ExifIFD) + 6) EXIF/TIFF Format (eg. int8u, int32u, undef, string) + 7) Tag ID (eg. ID-271, ID-rights, ID-a9aut) Families 0 and 1 are based on the file structure, and are similar except that family 1 is more specific and sub-divides some groups to give more @@ -2009,13 +2109,32 @@ L option for extracting tags from embedded documents.) Nested sub-documents (if they exist) are indicated by numbers separated with dashes in the group name, to an arbitrary depth. (eg. 'Doc2-3-1' is the 1st sub-sub-document of the 3rd sub-document of the 2nd embedded document of the -main file.) +main file.) Document numbers are also used to differentiate samples for +timed metadata in videos. Family 4 provides a method for differentiating tags when multiple tags exist with the same name in the same location. The primary instance of a tag (the tag extracted when the Duplicates option is disabled and no group is -specified) has no family 4 group name, but additional instances have have -family 4 group names of 'Copy1', 'Copy2', 'Copy3', etc. +specified) has no family 4 group name, but additional instances have family +4 group names of 'Copy1', 'Copy2', 'Copy3', etc. For convenience, the +primary tag may also be accessed using a group name of 'Copy0'. + +Family 5 is experimental, and gives the complete path for the metadata in +the file. Generated only if the L option is used when +extracting. + +Family 6 is currently used only for EXIF/TIFF metadata, and gives the format +type of the extracted value. Generated only if the L option is +used when extracting. + +Family 7 is used for tag ID's. The group names are the actual tag ID's, +with a leading "ID-" string. Non-numerical ID's have characters other than +[-_A-Za-z0-9] converted to hex. Numerical tag ID's are returned in hex if +the L option is set, otherwise decimal is used. When specifying +a family 7 group name, numerical ID's may be in hex or decimal, and +non-numerical ID's may or may not have characters other than [-_A-Za-z0-9] +converted to hex. Note that unlike other group names, the tag ID's of +family 7 group names are case sensitive (but the leading "ID-" is not). See L for complete lists of group names. @@ -2172,7 +2291,7 @@ Get list of all group names in specified family. =item Inputs: -0) Group family number (0-4) +0) Group family number (0-7) =item Return Values: @@ -2186,59 +2305,62 @@ Here is a complete list of groups for each of these families: =item Family 0 (Information Type): -AFCP, AIFF, APE, APP0, APP1, APP11, APP12, APP13, APP14, APP15, APP4, APP5, -APP6, APP8, ASF, Audible, CanonVRD, Composite, DICOM, DNG, DV, DjVu, Ducky, -EXE, EXIF, ExifTool, FLAC, FLIR, File, Flash, FlashPix, Font, FotoStation, -GIF, GIMP, GeoTiff, GoPro, H264, HTML, ICC_Profile, ID3, IPTC, ISO, ITC, -JFIF, JPEG, JSON, Jpeg2000, LNK, Leaf, Lytro, M2TS, MIE, MIFF, MNG, MOI, -MPC, MPEG, MPF, MXF, MakerNotes, Matroska, Meta, Ogg, OpenEXR, Opus, PDF, -PICT, PLIST, PNG, PSP, Palm, PanasonicRaw, PhotoCD, PhotoMechanic, -Photoshop, PostScript, PrintIM, QuickTime, RAF, RIFF, RSRC, RTF, Radiance, -Rawzor, Real, Red, SVG, SigmaRaw, Stim, Theora, Torrent, VCard, Vorbis, WTV, -XML, XMP, ZIP +AFCP, AIFF, APE, APP0, APP1, APP11, APP12, APP13, APP14, APP15, APP3, APP4, +APP5, APP6, APP8, ASF, Audible, CanonVRD, Composite, DICOM, DNG, DV, DjVu, +Ducky, EXE, EXIF, ExifTool, FITS, FLAC, FLIR, File, Flash, FlashPix, Font, +FotoStation, GIF, GIMP, GeoTiff, GoPro, H264, HTML, ICC_Profile, ID3, IPTC, +ISO, ITC, JFIF, JPEG, JSON, JUMBF, Jpeg2000, LNK, Leaf, Lytro, M2TS, MIE, +MIFF, MNG, MOI, MPC, MPEG, MPF, MXF, MakerNotes, Matroska, Meta, Ogg, +OpenEXR, Opus, PDF, PICT, PLIST, PNG, PSP, Palm, Parrot, PanasonicRaw, +PhotoCD, PhotoMechanic, Photoshop, PostScript, PrintIM, QuickTime, RAF, +RIFF, RSRC, RTF, Radiance, Rawzor, Real, Red, SVG, SigmaRaw, Stim, Theora, +Torrent, Trailer, UserParam, VCard, Vorbis, WTV, XML, XMP, ZIP =item Family 1 (Specific Location): AC3, AFCP, AIFF, APE, ASF, AVI1, Adobe, AdobeCM, AdobeDNG, Apple, Audible, -CIFF, CameraIFD, Canon, CanonCustom, CanonRaw, CanonVRD, Casio, Chapter#, -Composite, DICOM, DJI, DNG, DV, DjVu, DjVu-Meta, Ducky, EPPIM, EXE, EXIF, -ExifIFD, ExifTool, FLAC, FLIR, File, Flash, FlashPix, Font, FotoStation, -FujiFilm, FujiIFD, GE, GIF, GIMP, GPS, 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, InteropIFD, JFIF, JFXX, -JPEG, JPEG-HDR, JSON, JVC, Jpeg2000, KDC_IFD, Kodak, KodakBordersIFD, -KodakEffectsIFD, KodakIFD, KyoceraRaw, LNK, Leaf, LeafSubIFD, Leica, Lytro, -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, MNG, MOBI, MOI, MPC, MPEG, MPF0, MPImage, MS-DOC, MXF, -MacOS, MakerNotes, MakerUnknown, Matroska, MediaJukebox, MetaIFD, Microsoft, +CBOR, CIFF, CameraIFD, Canon, CanonCustom, CanonRaw, CanonVRD, Casio, +Chapter#, Composite, DICOM, DJI, DNG, DV, DjVu, DjVu-Meta, Ducky, EPPIM, +EXE, EXIF, ExifIFD, ExifTool, FITS, FLAC, FLIR, File, Flash, FlashPix, Font, +FotoStation, FujiFilm, FujiIFD, GE, GIF, GIMP, GPS, 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, Insta360, +InteropIFD, ItemList, JFIF, JFXX, JPEG, JPEG-HDR, JPS, JSON, JUMBF, JVC, +Jpeg2000, KDC_IFD, Keys, Kodak, KodakBordersIFD, KodakEffectsIFD, KodakIFD, +KyoceraRaw, LNK, Leaf, LeafSubIFD, Leica, Lyrics3, Lytro, 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, MNG, MOBI, MOI, MPC, MPEG, MPF0, MPImage, MS-DOC, MXF, MacOS, +MakerNotes, MakerUnknown, Matroska, MediaJukebox, Meta, MetaIFD, Microsoft, Minolta, MinoltaRaw, Motorola, NITF, Nikon, NikonCapture, NikonCustom, -NikonScan, Nintendo, Ocad, Ogg, Olympus, OpenEXR, Opus, PDF, PICT, PNG, -PNG-pHYs, PSP, Palm, Panasonic, PanasonicRaw, 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, SPIFF, SR2, SR2DataIFD, SR2SubIFD, -SRF#, SVG, Samsung, Sanyo, Scalado, Sigma, SigmaRaw, Sony, SonyIDC, Stim, -SubIFD, System, Theora, Torrent, Track#, VCalendar, VCard, Version0, Vorbis, -WTV, XML, XMP, XMP-DICOM, XMP-GAudio, XMP-GImage, XMP-GPano, XMP-GSpherical, -XMP-MP, XMP-MP1, XMP-PixelLive, XMP-aas, XMP-acdsee, XMP-album, -XMP-apple-fi, XMP-aux, XMP-cc, XMP-cell, XMP-creatorAtom, XMP-crs, XMP-dc, -XMP-dex, XMP-digiKam, XMP-drone-dji, XMP-dwc, XMP-exif, XMP-exifEX, -XMP-expressionmedia, XMP-extensis, XMP-fpv, XMP-getty, XMP-ics, -XMP-iptcCore, XMP-iptcExt, XMP-lr, XMP-mediapro, XMP-microsoft, -XMP-mwg-coll, XMP-mwg-kw, XMP-mwg-rs, XMP-pdf, XMP-pdfx, XMP-photomech, -XMP-photoshop, XMP-plus, XMP-pmi, XMP-prism, XMP-prl, XMP-prm, XMP-pur, -XMP-rdf, XMP-swf, XMP-tiff, XMP-x, XMP-xmp, XMP-xmpBJ, XMP-xmpDM, XMP-xmpMM, -XMP-xmpNote, XMP-xmpPLUS, XMP-xmpRights, XMP-xmpTPg, ZIP +NikonScan, NikonSettings, NineEdits, Nintendo, Ocad, Ogg, Olympus, OpenEXR, +Opus, PDF, PICT, PNG, PNG-pHYs, PSP, Palm, Panasonic, PanasonicRaw, 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, SPIFF, SR2, +SR2DataIFD, SR2SubIFD, SRF#, SVG, Samsung, Sanyo, Scalado, Sigma, SigmaRaw, +Sony, SonyIDC, Stim, SubIFD, System, Theora, Torrent, Track#, UserData, +UserParam, VCalendar, VCard, Version0, Vorbis, WTV, XML, XMP, XMP-DICOM, +XMP-Device, XMP-GAudio, XMP-GDepth, XMP-GFocus, XMP-GImage, XMP-GPano, +XMP-GSpherical, XMP-LImage, XMP-MP, XMP-MP1, XMP-PixelLive, XMP-aas, +XMP-acdsee, XMP-album, XMP-apple-fi, XMP-aux, XMP-cc, XMP-cell, +XMP-creatorAtom, XMP-crs, XMP-dc, XMP-dex, XMP-digiKam, XMP-drone-dji, +XMP-dwc, XMP-exif, XMP-exifEX, XMP-expressionmedia, XMP-extensis, XMP-fpv, +XMP-getty, XMP-ics, XMP-iptcCore, XMP-iptcExt, XMP-lr, XMP-mediapro, +XMP-microsoft, XMP-mwg-coll, XMP-mwg-kw, XMP-mwg-rs, XMP-pdf, XMP-pdfx, +XMP-photomech, XMP-photoshop, XMP-plus, XMP-pmi, XMP-prism, XMP-prl, +XMP-prm, XMP-pur, XMP-rdf, XMP-swf, XMP-tiff, XMP-x, XMP-xmp, XMP-xmpBJ, +XMP-xmpDM, XMP-xmpMM, XMP-xmpNote, XMP-xmpPLUS, XMP-xmpRights, XMP-xmpTPg, +ZIP, iTunes =item Family 2 (Category): -Audio, Author, Camera, Document, ExifTool, Image, Location, Other, Preview, -Printing, Time, Unknown, Video +Audio, Author, Camera, Device, Document, ExifTool, Image, Location, Other, +Preview, Printing, Time, Unknown, Video =item Family 3 (Document Number): @@ -2248,8 +2370,27 @@ Doc#, Main Copy# +=item Family 5 (Metadata Path): + +eg. JPEG-APP1-IFD0-ExifIFD + +=item Family 6 (EXIF/TIFF Format): + +int8u, string, int16u, int32u, rational64u, int8s, undef, int16s, int32s, +rational64s, float, double, ifd, unicode, complex, int64u, int64s, ifd64 + +=item Family 7 (Tag ID): + +ID-xxx (Where xxx is the tag ID. Numerical ID's are returned in hex with a +leading "0x" if the HexTagIDs option is set, or decimal otherwise. +Characters in non-numerical ID's which are not valid in a group name are +returned as 2 hex digits.) + =back +Note: This function may also be called as an ExifTool member function to +allow the HexTagIDs option to be set when retrieving family 7 group names. + =head2 GetDeleteGroups [static] Get list of all deletable group names. @@ -2267,14 +2408,14 @@ None. A list of deletable group names in alphabetical order. The current list of deletable group names is: -AFCP, APP0, APP1, APP10, APP11, APP12, APP13, APP14, APP15, APP2, APP3, -APP4, APP5, APP6, APP7, APP8, APP9, Adobe, Audio, Author, CIFF, Camera, -CanonVRD, Document, Ducky, EXIF, ExifIFD, ExifTool, File, FlashPix, -FotoStation, GPS, GlobParamIFD, ICC_Profile, IFD0, IFD1, IPTC, Image, -InteropIFD, JFIF, Jpeg2000, Location, MIE, MPF, MakerNotes, Meta, MetaIFD, -NikonCapture, Other, PDF, PDF-update, PNG, PNG-pHYs, PhotoMechanic, -Photoshop, Preview, PrintIM, Printing, RMETA, RSRC, SubIFD, Time, Trailer, -Video, XML, XML-*, XMP, XMP-* +Adobe, AFCP, APP0, APP1, APP10, APP11, APP12, APP13, APP14, APP15, APP2, +APP3, APP4, APP5, APP6, APP7, APP8, APP9, Audio, Author, Camera, CanonVRD, +CIFF, Document, Ducky, EXIF, ExifIFD, ExifTool, File, FlashPix, FotoStation, +GlobParamIFD, GPS, ICC_Profile, IFD0, IFD1, Image, Insta360, InteropIFD, +IPTC, ItemList, JFIF, Jpeg2000, Keys, Location, MakerNotes, Meta, MetaIFD, +Microsoft, MIE, MPF, NikonCapture, Other, PDF, PDF-update, PhotoMechanic, +Photoshop, PNG, PNG-pHYs, Preview, PrintIM, Printing, QuickTime, RMETA, +RSRC, SubIFD, Time, Trailer, UserData, Video, XML, XML-*, XMP, XMP-* To schedule a group for deletion, call L with a tag name like 'EXIF:*' and an undefined tag value. @@ -2527,13 +2668,13 @@ IPTC Core and Extension specifications actually use the XMP format.) =head2 XMP -Exiftool reads XMP encoded as UTF-8, UTF-16 or UTF-32, and converts them all +ExifTool reads XMP encoded as UTF-8, UTF-16 or UTF-32, and converts them all to UTF-8 internally. Also, all XML character entity references and numeric character references are converted. When writing, ExifTool always encodes XMP as UTF-8, converting the following 5 characters to XML character references: E E E E<39> E. By default no further conversion is performed, however if the L option is other than -'UTF8' then text is converted to/from a specified character set when +'UTF8' then text is converted to/from the specified character set when reading/writing. =head2 PNG @@ -2613,7 +2754,7 @@ specified by the L option. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey +Copyright 2003-2022, Phil Harvey This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/AES.pm b/src/Image-ExifTool/lib/Image/ExifTool/AES.pm index b949e3d0..c7996cdf 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/AES.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/AES.pm @@ -477,7 +477,7 @@ main purpose of encryption, so this really can't be considered a bug. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/AFCP.pm b/src/Image-ExifTool/lib/Image/ExifTool/AFCP.pm index 1d4da145..dcd89ca6 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/AFCP.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/AFCP.pm @@ -259,7 +259,7 @@ scanning for AFCP information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/AIFF.pm b/src/Image-ExifTool/lib/Image/ExifTool/AIFF.pm index 6241c5d1..3fe6c4a6 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/AIFF.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/AIFF.pm @@ -18,7 +18,7 @@ use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::ID3; -$VERSION = '1.09'; +$VERSION = '1.11'; # information for time/date-based tags (time zero is Jan 1, 1904) my %timeInfo = ( @@ -73,12 +73,12 @@ my %timeInfo = ( ProcessProc => \&Image::ExifTool::ID3::ProcessID3, }, }, + APPL => 'ApplicationData', # (first 4 bytes are the application signature) # SSND => 'SoundData', # MARK => 'Marker', # INST => 'Instrument', # MIDI => 'MidiData', # AESD => 'AudioRecording', -# APPL => 'ApplicationSpecific', ); %Image::ExifTool::AIFF::Common = ( @@ -185,7 +185,7 @@ sub ProcessAIFF($$) { my ($et, $dirInfo) = @_; my $raf = $$dirInfo{RAF}; - my ($buff, $err, $tagTablePtr, $page, $type); + my ($buff, $err, $tagTablePtr, $page, $type, $n); # verify this is a valid AIFF file return 0 unless $raf->Read($buff, 12) == 12; @@ -202,7 +202,7 @@ sub ProcessAIFF($$) $et->SetFileType('DJVU'); return 1 if $fast3; $tagTablePtr = GetTagTable('Image::ExifTool::DjVu::Main'); - # modifiy FileType to indicate a multi-page document + # modify FileType to indicate a multi-page document $$et{VALUE}{FileType} .= " (multi-page)" if $buf2 eq 'DJVM'; $type = 'DjVu'; } else { @@ -217,14 +217,24 @@ sub ProcessAIFF($$) # # Read through the IFF chunks # - for (;;) { + for ($n=0;;++$n) { $raf->Read($buff, 8) == 8 or last; $pos += 8; my ($tag, $len) = unpack('a4N', $buff); my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); - $et->VPrint(0, "AIFF '${tag}' chunk ($len bytes of data):\n"); + $et->VPrint(0, "AIFF '${tag}' chunk ($len bytes of data): ", $raf->Tell(),"\n"); # AIFF chunks are padded to an even number of bytes my $len2 = $len + ($len & 0x01); + if ($len2 > 100000000) { + if ($len2 >= 0x80000000 and not $et->Options('LargeFileSupport')) { + $et->Warn('End of processing at large chunk (LargeFileSupport not enabled)'); + last; + } + if ($tagInfo) { + $et->Warn("Skipping large $$tagInfo{Name} chunk (> 100 MB)"); + undef $tagInfo; + } + } if ($tagInfo) { if ($$tagInfo{TypeOnly}) { $len = $len2 = 4; @@ -241,6 +251,10 @@ sub ProcessAIFF($$) Start => 0, Size => $len, ); + } elsif (not $len) { + next if ++$n < 100; + $et->Warn('Aborting scan. Too many empty chunks'); + last; } elsif ($verbose > 2 and $len2 < 1024000) { $raf->Read($buff, $len2) == $len2 or $err = 1, last; $et->VerboseDump(\$buff); @@ -248,6 +262,7 @@ sub ProcessAIFF($$) $raf->Seek($len2, 1) or $err=1, last; } $pos += $len2; + $n = 0; } $err and $et->Warn("Error reading $type file (corrupted?)"); return 1; @@ -272,7 +287,7 @@ information from AIFF (Audio Interchange File Format) audio files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/APE.pm b/src/Image-ExifTool/lib/Image/ExifTool/APE.pm index ee1f71fc..ac603796 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/APE.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/APE.pm @@ -15,7 +15,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.05'; +$VERSION = '1.06'; # APE metadata blocks %Image::ExifTool::APE::Main = ( @@ -166,7 +166,7 @@ sub ProcessAPE($$) # look for the APE trailer footer... my $footPos = -32; # (...but before the ID3v1 trailer if it exists) - $footPos -= 128 if $$et{DoneID3} == 2; + $footPos -= $$et{DoneID3} if $$et{DoneID3} > 1; $raf->Seek($footPos, 2) or return 1; $raf->Read($buff, 32) == 32 or return 1; $buff =~ /^APETAGEX/ or return 1; @@ -263,7 +263,7 @@ Currently doesn't parse MAC header unless it is at the start of the file. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/APP12.pm b/src/Image-ExifTool/lib/Image/ExifTool/APP12.pm index 023506f2..d5091171 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/APP12.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/APP12.pm @@ -305,7 +305,7 @@ APP12 meta information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/ASF.pm b/src/Image-ExifTool/lib/Image/ExifTool/ASF.pm index 1af2010b..64689c8b 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/ASF.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/ASF.pm @@ -876,7 +876,7 @@ Windows Media Audio (WMA) and Windows Media Video (WMV) files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Apple.pm b/src/Image-ExifTool/lib/Image/ExifTool/Apple.pm index aac34b38..61aa039a 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Apple.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Apple.pm @@ -15,7 +15,7 @@ use vars qw($VERSION); use Image::ExifTool::Exif; use Image::ExifTool::PLIST; -$VERSION = '1.04'; +$VERSION = '1.06'; # Apple iPhone metadata (ref PH) %Image::ExifTool::Apple::Main = ( @@ -66,13 +66,23 @@ $VERSION = '1.04'; Writable => 'string', Notes => 'unique ID for all images in a burst', }, - # 0x000c - rational64s[2]: eg) "0.1640625 0.19921875" + 0x000c => { # ref forum13710 (Neal Krawetz) + Name => 'FocusDistanceRange', + Writable => 'rational64s', + Count => 2, + PrintConv => q{ + my @a = split ' ', $val; + sprintf('%.2f - %.2f m', $a[0] <= $a[1] ? @a : reverse @a); + }, + PrintConvInv => '$val =~ s/ - //; $val =~ s/ ?m$//; $val', + }, # 0x000d - int32s: 0,1,6,20,24,32,40 - # 0x000e - int32s: 0,1,4,12 (Orienation? 0=landscape? 4=portrait? ref 1) + # 0x000e - int32s: 0,1,4,12 (Orientation? 0=landscape? 4=portrait? ref 1) # 0x000f - int32s: 2,3 # 0x0010 - int32s: 1 0x0011 => { - Name => 'ContentIdentifier', #forum8750 + Name => 'MediaGroupUUID', #NealKrawetz private communication + # (changed in 12.19 from Name => 'ContentIdentifier', #forum8750) Writable => 'string', }, # 0x0014 - int32s: 1,2,3,4,5 (iPhone 6s, iOS 6.1) @@ -148,7 +158,7 @@ Apple maker notes in EXIF information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Audible.pm b/src/Image-ExifTool/lib/Image/ExifTool/Audible.pm new file mode 100644 index 00000000..75560a70 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/Audible.pm @@ -0,0 +1,317 @@ +#------------------------------------------------------------------------------ +# File: Audible.pm +# +# Description: Read metadata from Audible audio books +# +# Revisions: 2015/04/05 - P. Harvey Created +# +# References: 1) https://github.com/jteeuwen/audible +# 2) https://code.google.com/p/pyaudibletags/ +# 3) http://wiki.multimedia.cx/index.php?title=Audible_Audio +#------------------------------------------------------------------------------ + +package Image::ExifTool::Audible; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.02'; + +sub ProcessAudible_meta($$$); +sub ProcessAudible_cvrx($$$); + +%Image::ExifTool::Audible::Main = ( + GROUPS => { 2 => 'Audio' }, + NOTES => q{ + ExifTool will extract any information found in the metadata dictionary of + Audible .AA files, even if not listed in the table below. + }, + # tags found in the metadata dictionary (chunk 2) + pubdate => { Name => 'PublishDate', Groups => { 2 => 'Time' } }, + pub_date_start => { Name => 'PublishDateStart', Groups => { 2 => 'Time' } }, + author => { Name => 'Author', Groups => { 2 => 'Author' } }, + copyright => { Name => 'Copyright', Groups => { 2 => 'Author' } }, + # also seen (ref PH): + # product_id, parent_id, title, provider, narrator, price, description, + # long_description, short_title, is_aggregation, title_id, codec, HeaderSeed, + # EncryptedBlocks, HeaderKey, license_list, CPUType, license_count, <12 hex digits>, + # parent_short_title, parent_title, aggregation_id, short_description, user_alias + + # information extracted from other chunks + _chapter_count => { Name => 'ChapterCount' }, # from chunk 6 + _cover_art => { # from chunk 11 + Name => 'CoverArt', + Groups => { 2 => 'Preview' }, + Binary => 1, + }, +); + +# 'tags' atoms observed in Audible .m4b audio books (ref PH) +%Image::ExifTool::Audible::tags = ( + GROUPS => { 0 => 'QuickTime', 2 => 'Audio' }, + NOTES => 'Information found in "tags" atom of Audible M4B audio books.', + meta => { + Name => 'Audible_meta', + SubDirectory => { TagTable => 'Image::ExifTool::Audible::meta' }, + }, + cvrx => { + Name => 'Audible_cvrx', + SubDirectory => { TagTable => 'Image::ExifTool::Audible::cvrx' }, + }, + tseg => { + Name => 'Audible_tseg', + SubDirectory => { TagTable => 'Image::ExifTool::Audible::tseg' }, + }, +); + +# 'meta' information observed in Audible .m4b audio books (ref PH) +%Image::ExifTool::Audible::meta = ( + PROCESS_PROC => \&ProcessAudible_meta, + GROUPS => { 0 => 'QuickTime', 2 => 'Audio' }, + NOTES => 'Information found in Audible M4B "meta" atom.', + Album => 'Album', + ALBUMARTIST => { Name => 'AlbumArtist', Groups => { 2 => 'Author' } }, + Artist => { Name => 'Artist', Groups => { 2 => 'Author' } }, + Comment => 'Comment', + Genre => 'Genre', + itunesmediatype => { Name => 'iTunesMediaType', Description => 'iTunes Media Type' }, + SUBTITLE => 'Subtitle', + Title => 'Title', + TOOL => 'CreatorTool', + Year => { Name => 'Year', Groups => { 2 => 'Time' } }, + track => 'ChapterName', # (found in 'meta' of 'tseg' atom) +); + +# 'cvrx' information observed in Audible .m4b audio books (ref PH) +%Image::ExifTool::Audible::cvrx = ( + PROCESS_PROC => \&ProcessAudible_cvrx, + GROUPS => { 0 => 'QuickTime', 2 => 'Audio' }, + NOTES => 'Audible cover art information in M4B audio books.', + VARS => { NO_ID => 1 }, + CoverArtType => 'CoverArtType', + CoverArt => { + Name => 'CoverArt', + Groups => { 2 => 'Preview' }, + Binary => 1, + }, +); + +# 'tseg' information observed in Audible .m4b audio books (ref PH) +%Image::ExifTool::Audible::tseg = ( + GROUPS => { 0 => 'QuickTime', 2 => 'Audio' }, + tshd => { + Name => 'ChapterNumber', + Format => 'int32u', + ValueConv => '$val + 1', # start counting from 1 + }, + meta => { + Name => 'Audible_meta2', + SubDirectory => { TagTable => 'Image::ExifTool::Audible::meta' }, + }, +); + +#------------------------------------------------------------------------------ +# Process Audible 'meta' tags from M4B files (ref PH) +# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub ProcessAudible_meta($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dataPos = $$dirInfo{DataPos}; + my $dirLen = length $$dataPt; + return 0 if $dirLen < 4; + my $num = Get32u($dataPt, 0); + $et->VerboseDir('Audible_meta', $num); + my $pos = 4; + my $index; + for ($index=0; $index<$num; ++$index) { + last if $pos + 3 > $dirLen; + my $unk = Get8u($dataPt, $pos); # ? (0x80 or 0x00) + last unless $unk == 0x80 or $unk == 0x00; + my $len = Get16u($dataPt, $pos + 1); # tag length + $pos += 3; + last if $pos + $len + 6 > $dirLen or not $len; + my $tag = substr($$dataPt, $pos, $len); # tag ID + my $ver = Get16u($dataPt, $pos + $len); # version? + last unless $ver == 0x0001; + my $size = Get32u($dataPt, $pos + $len + 2);# data size + $pos += $len + 6; + last if $pos + $size > $dirLen; + my $val = $et->Decode(substr($$dataPt, $pos, $size), 'UTF8'); + unless ($$tagTablePtr{$tag}) { + my $name = Image::ExifTool::MakeTagName(($tag =~ /[a-z]/) ? $tag : lc($tag)); + AddTagToTable($tagTablePtr, $tag, { Name => $name }); + } + $et->HandleTag($tagTablePtr, $tag, $val, + DataPt => $dataPt, + DataPos => $dataPos, + Start => $pos, + Size => $size, + Index => $index, + ); + $pos += $size; + } + return 1; +} + +#------------------------------------------------------------------------------ +# Process Audible 'cvrx' cover art atom from M4B files (ref PH) +# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub ProcessAudible_cvrx($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dataPos = $$dirInfo{DataPos}; + my $dirLen = length $$dataPt; + return 0 if 0x0a > $dirLen; + my $len = Get16u($dataPt, 0x08); + return 0 if 0x0a + $len + 6 > $dirLen; + my $size = Get32u($dataPt, 0x0a + $len + 2); + return 0 if 0x0a + $len + 6 + $size > $dirLen; + $et->VerboseDir('Audible_cvrx', undef, $dirLen); + $et->HandleTag($tagTablePtr, 'CoverArtType', undef, + DataPt => $dataPt, + DataPos => $dataPos, + Start => 0x0a, + Size => $len, + ); + $et->HandleTag($tagTablePtr, 'CoverArt', undef, + DataPt => $dataPt, + DataPos => $dataPos, + Start => 0x0a + $len + 6, + Size => $size, + ); + return 1; +} + +#------------------------------------------------------------------------------ +# Read information from an Audible .AA file +# Inputs: 0) ExifTool ref, 1) dirInfo ref +# Returns: 1 on success, 0 if this wasn't a valid AA file +sub ProcessAA($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my ($buff, $toc, $entry, $i); + + # check magic number + return 0 unless $raf->Read($buff, 16) == 16 and $buff=~/^.{4}\x57\x90\x75\x36/s; + # check file size + if (defined $$et{VALUE}{FileSize}) { + # first 4 bytes of the file should be the filesize + unpack('N', $buff) == $$et{VALUE}{FileSize} or return 0; + } + $et->SetFileType(); + SetByteOrder('MM'); + my $bytes = 12 * Get32u(\$buff, 8); # table of contents size in bytes + $bytes > 0xc00 and $et->Warn('Invalid TOC'), return 1; + # read the table of contents + $raf->Read($toc, $bytes) == $bytes or $et->Warn('Truncated TOC'), return 1; + my $tagTablePtr = GetTagTable('Image::ExifTool::Audible::Main'); + # parse table of contents (in $toc) + for ($entry=0; $entry<$bytes; $entry+=12) { + my $type = Get32u(\$toc, $entry); + next unless $type == 2 or $type == 6 or $type == 11; + my $offset = Get32u(\$toc, $entry + 4); + my $length = Get32u(\$toc, $entry + 8) or next; + $raf->Seek($offset, 0) or $et->Warn("Chunk $type seek error"), last; + if ($type == 6) { # offset table + next if $length < 4 or $raf->Read($buff, 4) != 4; # only read the chapter count + $et->HandleTag($tagTablePtr, '_chapter_count', Get32u(\$buff, 0)); + next; + } + # read the chunk + $length > 100000000 and $et->Warn("Chunk $type too big"), next; + $raf->Read($buff, $length) == $length or $et->Warn("Chunk $type read error"), last; + if ($type == 11) { # cover art + next if $length < 8; + my $len = Get32u(\$buff, 0); + my $off = Get32u(\$buff, 4); + next if $off < $offset + 8 or $off - $offset + $len > $length; + $et->HandleTag($tagTablePtr, '_cover_art', substr($buff, $off-$offset, $len)); + next; + } + # parse metadata dictionary (in $buff) + $length < 4 and $et->Warn('Bad dictionary'), next; + my $num = Get32u(\$buff, 0); + $num > 0x200 and $et->Warn('Bad dictionary count'), next; + my $pos = 4; # dictionary starts immediately after count + require Image::ExifTool::HTML; # (for UnescapeHTML) + $et->VerboseDir('Audible Metadata', $num); + for ($i=0; $i<$num; ++$i) { + my $tagPos = $pos + 9; # position of tag string + $tagPos > $length and $et->Warn('Truncated dictionary'), last; + # (1 unknown byte ignored at start of each dictionary entry) + my $tagLen = Get32u(\$buff, $pos + 1); # tag string length + my $valLen = Get32u(\$buff, $pos + 5); # value string length + my $valPos = $tagPos + $tagLen; # position of value string + my $nxtPos = $valPos + $valLen; # position of next entry + $nxtPos > $length and $et->Warn('Bad dictionary entry'), last; + my $tag = substr($buff, $tagPos, $tagLen); + my $val = substr($buff, $valPos, $valLen); + unless ($$tagTablePtr{$tag}) { + my $name = Image::ExifTool::MakeTagName($tag); + $name =~ s/_(.)/\U$1/g; # change from underscore-separated to mixed case + AddTagToTable($tagTablePtr, $tag, { Name => $name }); + } + # unescape HTML character references and convert from UTF-8 + $val = $et->Decode(Image::ExifTool::HTML::UnescapeHTML($val), 'UTF8'); + $et->HandleTag($tagTablePtr, $tag, $val, + DataPos => $offset, + DataPt => \$buff, + Start => $valPos, + Size => $valLen, + Index => $i, + ); + $pos = $nxtPos; # step to next dictionary entry + } + } + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::Audible - Read meta information from Audible audio books + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to read meta +information from Audible audio books. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L + +=item L + +=item L + +=back + +=head1 SEE ALSO + +L, +L + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/BMP.pm b/src/Image-ExifTool/lib/Image/ExifTool/BMP.pm index 161a3be9..5244f7a0 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/BMP.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/BMP.pm @@ -335,7 +335,7 @@ This module contains definitions required by Image::ExifTool to read BMP =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/BPG.pm b/src/Image-ExifTool/lib/Image/ExifTool/BPG.pm new file mode 100644 index 00000000..4d2c91af --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/BPG.pm @@ -0,0 +1,253 @@ +#------------------------------------------------------------------------------ +# File: BPG.pm +# +# Description: Read BPG meta information +# +# Revisions: 2016-07-05 - P. Harvey Created +# +# References: 1) http://bellard.org/bpg/ +#------------------------------------------------------------------------------ + +package Image::ExifTool::BPG; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.01'; + +# BPG information +%Image::ExifTool::BPG::Main = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' }, + NOTES => q{ + The information listed below is extracted from BPG (Better Portable + Graphics) images. See L for the specification. + }, + 4 => { + Name => 'PixelFormat', + Format => 'int16u', + Mask => 0xe000, + PrintConv => { + 0 => 'Grayscale', + 1 => '4:2:0 (chroma at 0.5, 0.5)', + 2 => '4:2:2 (chroma at 0.5, 0)', + 3 => '4:4:4', + 4 => '4:2:0 (chroma at 0, 0.5)', + 5 => '4:2:2 (chroma at 0, 0)', + }, + }, + 4.1 => { + Name => 'Alpha', + Format => 'int16u', + Mask => 0x1004, + BitShift => 0, + PrintHex => 1, + PrintConv => { + 0x0000 => 'No Alpha Plane', + 0x1000 => 'Alpha Exists (color not premultiplied)', + 0x1004 => 'Alpha Exists (color premultiplied)', + 0x0004 => 'Alpha Exists (W color component)', + }, + }, + 4.2 => { + Name => 'BitDepth', + Format => 'int16u', + Mask => 0x0f00, + ValueConv => '$val + 8', + }, + 4.3 => { + Name => 'ColorSpace', + Format => 'int16u', + Mask => 0x00f0, + PrintConv => { + 0 => 'YCbCr (BT 601)', + 1 => 'RGB', + 2 => 'YCgCo', + 3 => 'YCbCr (BT 709)', + 4 => 'YCbCr (BT 2020)', + 5 => 'BT 2020 Constant Luminance', + }, + }, + 4.4 => { + Name => 'Flags', + Format => 'int16u', + Mask => 0x000b, + PrintConv => { BITMASK => { + 0 => 'Animation', + 1 => 'Limited Range', + 3 => 'Extension Present', + }}, + }, + 6 => { Name => 'ImageWidth', Format => 'var_ue7' }, + 7 => { Name => 'ImageHeight', Format => 'var_ue7' }, + # length of image data or 0 to EOF + # (must be decoded so we know where the extension data starts) + 8 => { Name => 'ImageLength', Format => 'var_ue7' }, +); + +%Image::ExifTool::BPG::Extensions = ( + GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' }, + VARS => { ALPHA_FIRST => 1 }, + 1 => { + Name => 'EXIF', + SubDirectory => { + TagTable => 'Image::ExifTool::Exif::Main', + ProcessProc => \&Image::ExifTool::ProcessTIFF, + }, + }, + 2 => { + Name => 'ICC_Profile', + SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' }, + }, + 3 => { + Name => 'XMP', + SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' }, + }, + 4 => { + Name => 'ThumbnailBPG', + Binary => 1, + }, + 5 => { + Name => 'AnimationControl', + Binary => 1, + Unknown => 1, + }, +); + +#------------------------------------------------------------------------------ +# Get ue7 integer from binary data (max 32 bits) +# Inputs: 0) data ref, 1) location in data (undef for 0) +# Returns: 0) ue7 as integer or undef on error, 1) length of ue7 in bytes +sub Get_ue7($;$) +{ + my $dataPt = shift; + my $pos = shift || 0; + my $size = length $$dataPt; + my $val = 0; + my $i; + for ($i=0; ; ) { + return() if $pos+$i >= $size or $i >= 5; + my $byte = Get8u($dataPt, $pos + $i); + $val = ($val << 7) | ($byte & 0x7f); + unless ($byte & 0x80) { + return() if $i == 4 and $byte & 0x70; # error if bits 32-34 are set + last; # this was the last byte + } + return() if $i == 0 and $byte == 0x80; # error if first byte is 0x80 + ++$i; # step to the next byte + } + return($val, $i+1); +} + +#------------------------------------------------------------------------------ +# Extract EXIF information from a BPG image +# Inputs: 0) ExifTool object reference, 1) dirInfo reference +# Returns: 1 on success, 0 if this wasn't a valid BPG file +sub ProcessBPG($$) +{ + local $_; + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my ($buff, $size, $n, $len, $pos); + + # verify this is a valid BPG file + return 0 unless $raf->Read($buff, 21) == 21; # (21 bytes is maximum header length) + return 0 unless $buff =~ /^BPG\xfb/; + $et->SetFileType(); # set the FileType tag + + SetByteOrder('MM'); + my %dirInfo = ( + DataPt => \$buff, + DirStart => 0, + DirLen => length($buff), + VarFormatData => [ ], + ); + $et->ProcessDirectory(\%dirInfo, GetTagTable('Image::ExifTool::BPG::Main')); + + return 1 unless $$et{VALUE}{Flags} & 0x0008; # all done unless extension flag is set + + # add varSize from last entry in VarFormatData to determine + # the current read position in the file + my $dataPos = 9 + $dirInfo{VarFormatData}[-1][1]; + # read extension length + unless ($raf->Seek($dataPos, 0) and $raf->Read($buff, 5) == 5) { + $et->Warn('Missing BPG extension data'); + return 1; + } + ($size, $n) = Get_ue7(\$buff); + defined $size or $et->Warn('Corrupted BPG extension length'), return 1; + $dataPos += $n; + $size > 10000000 and $et->Warn('BPG extension is too large'), return 1; + unless ($raf->Seek($dataPos, 0) and $raf->Read($buff, $size) == $size) { + $et->Warn('Truncated BPG extension'); + return 1; + } + my $tagTablePtr = GetTagTable('Image::ExifTool::BPG::Extensions'); + # loop through the individual extensions + for ($pos=0; $pos<$size; $pos+=$len) { + my $type = Get8u(\$buff, $pos); + # get length of this extension + ($len, $n) = Get_ue7(\$buff, ++$pos); + defined $len or $et->Warn('Corrupted BPG extension'), last; + $pos += $n; # point to start of data for this extension + $pos + $len > $size and $et->Warn('Invalid BPG extension size'), last; + $$tagTablePtr{$type} or $et->Warn("Unrecognized BPG extension $type ($len bytes)", 1), next; + # libbpg (in my opinion) incorrectly copies the padding byte after the + # "EXIF\0" APP1 header to the start of the BPG EXIF extension, so issue a + # minor warning and ignore the padding if we find it before the TIFF header + if ($type == 1 and $len > 3 and substr($buff,$pos,3)=~/^.(II|MM)/s) { + $et->Warn("Ignored extra byte at start of EXIF extension", 1); + ++$pos; + --$len; + } + $et->HandleTag($tagTablePtr, $type, undef, + DataPt => \$buff, + DataPos => $dataPos, + Start => $pos, + Size => $len, + Parent => 'BPG', + ); + } + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::BPG - Read BPG meta information + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to read BPG +(Better Portable Graphics) images. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L + +=back + +=head1 SEE ALSO + +L, +L + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/BZZ.pm b/src/Image-ExifTool/lib/Image/ExifTool/BZZ.pm index ac2da1bf..d1baae1d 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/BZZ.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/BZZ.pm @@ -445,7 +445,7 @@ compression ability). =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) Copyright 2002, Leon Bottou and Yann Le Cun Copyright 2001, AT&T Copyright 1999-2001, LizardTech Inc. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/BigTIFF.pm b/src/Image-ExifTool/lib/Image/ExifTool/BigTIFF.pm index 9e8ed0f6..c0601101 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/BigTIFF.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/BigTIFF.pm @@ -15,7 +15,7 @@ use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; -$VERSION = '1.06'; +$VERSION = '1.07'; my $maxOffset = 0x7fffffff; # currently supported maximum data offset/size @@ -31,8 +31,12 @@ sub ProcessBigIFD($$$) my $htmlDump = $$et{HTML_DUMP}; my $dirName = $$dirInfo{DirName}; my $dirStart = $$dirInfo{DirStart}; + my ($offName, $nextOffName); - $verbose = -1 if $htmlDump; # mix htmlDump into verbose so we can test for both at once + if ($htmlDump) { + $verbose = -1; # mix htmlDump into verbose so we can test for both at once + $offName = $$dirInfo{OffsetName}; + } # loop through IFD chain for (;;) { @@ -64,10 +68,13 @@ sub ProcessBigIFD($$$) my $nextIFD; $raf->Read($nextIFD, 8) == 8 or undef $nextIFD; # try to read next IFD pointer if ($htmlDump) { - $et->HDump($bufPos-8, 8, "$dirName entries", "Entry count: $numEntries"); + $et->HDump($bufPos-8, 8, "$dirName entries", "Entry count: $numEntries", undef, $offName); if (defined $nextIFD) { - my $tip = sprintf("Offset: 0x%.8x", Image::ExifTool::Get64u(\$nextIFD, 0)); - $et->HDump($bufPos + 20 * $numEntries, 8, "Next IFD", $tip, 0); + my $off = Image::ExifTool::Get64u(\$nextIFD, 0); + my $tip = sprintf("Offset: 0x%.8x", $off); + my $id = $offName; + ($nextOffName, $id) = Image::ExifTool::Exif::NextOffsetName($et, $id) if $off; + $et->HDump($bufPos + 20 * $numEntries, 8, "Next IFD", $tip, 0, $id); } } # loop through all entries in this BigTIFF IFD @@ -79,7 +86,7 @@ sub ProcessBigIFD($$$) my $formatSize = $Image::ExifTool::Exif::formatSize[$format]; unless (defined $formatSize) { $et->HDump($bufPos+$entry,20,"[invalid IFD entry]", - "Bad format value: $format", 1); + "Bad format value: $format", 1, $offName); # warn unless the IFD was just padded with zeros $et->Warn(sprintf("Unknown format ($format) for $dirName tag 0x%x",$tagID)); return 0; # assume corrupted IFD @@ -89,7 +96,7 @@ sub ProcessBigIFD($$$) my $tagInfo = $et->GetTagInfo($tagTablePtr, $tagID); next unless defined $tagInfo or $verbose; my $valuePtr = $entry + 12; - my ($valBuff, $valBase, $rational); + my ($valBuff, $valBase, $rational, $subOffName); if ($size > 8) { if ($size > $maxOffset) { $et->Warn("Can't handle $dirName entry $index (huge size)"); @@ -148,11 +155,17 @@ sub ProcessBigIFD($$$) } } $tip .= "Value: $tval"; - $et->HDump($entry+$bufPos, 20, "$dname $colName", $tip, 1); + my ($id, $sid); + if ($tagInfo and $$tagInfo{SubIFD}) { + ($subOffName, $id, $sid) = Image::ExifTool::Exif::NextOffsetName($et, $offName); + } else { + $id = $offName; + } + $et->HDump($entry+$bufPos, 20, "$dname $colName", $tip, 1, $id); if ($size > 8) { # add value data block my $flg = ($tagInfo and $$tagInfo{SubDirectory} and $$tagInfo{MakerNotes}) ? 4 : 0; - $et->HDump($valuePtr,$size,"$tagName value",'SAME', $flg); + $et->HDump($valuePtr,$size,"$tagName value",'SAME', $flg, $sid); } } if ($tagInfo and $$tagInfo{SubIFD}) { @@ -174,11 +187,12 @@ sub ProcessBigIFD($$$) my $subdirName = $$tagInfo{Name}; $subdirName .= $i if $i; my %subdirInfo = ( - RAF => $raf, - DataPos => 0, - DirStart => $offsets[$i], - DirName => $subdirName, - Parent => $dirInfo, + RAF => $raf, + DataPos => 0, + DirStart => $offsets[$i], + DirName => $subdirName, + Parent => $dirName, + OffsetName => $subOffName, ); $et->ProcessDirectory(\%subdirInfo, $tagTablePtr, \&ProcessBigIFD); } @@ -201,6 +215,7 @@ sub ProcessBigIFD($$$) defined $nextIFD or $et->Warn("Bad $dirName pointer"), return 0; $dirStart = Image::ExifTool::Get64u(\$nextIFD, 0); $dirStart or last; + $offName = $nextOffName; } return 1; } @@ -260,7 +275,7 @@ information in BigTIFF images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/BuildTagLookup.pm b/src/Image-ExifTool/lib/Image/ExifTool/BuildTagLookup.pm index f15e2bd2..f00e7b6a 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/BuildTagLookup.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/BuildTagLookup.pm @@ -31,15 +31,18 @@ use Image::ExifTool::IPTC; use Image::ExifTool::XMP; use Image::ExifTool::Canon; use Image::ExifTool::Nikon; +use Image::ExifTool::Sony; use Image::ExifTool::Validate; use Image::ExifTool::MacOS; -$VERSION = '3.18'; +$VERSION = '3.48'; @ISA = qw(Exporter); sub NumbersFirst($$); sub SortedTagTablekeys($); +my $createDate = 'Feb 15, 2005'; + # global variables to control sorting order of table entries my $numbersFirst = 1; # set to -1 to sort numbers last, or 2 to put negative numbers last my $caseInsensitive; # flag to ignore case when sorting tag names @@ -55,7 +58,7 @@ my $docType = q{ }; -my $homePage = 'http://owl.phy.queensu.ca/~phil/exiftool'; +my $homePage = 'https://exiftool.org'; # tweak the ordering of tables in the documentation my %tweakOrder = ( @@ -65,9 +68,11 @@ my %tweakOrder = ( IPTC => 'Exif', # put IPTC after EXIF, GPS => 'XMP', # etc... Composite => 'Extra', + CBOR => 'JSON', GeoTiff => 'GPS', CanonVRD=> 'CanonCustom', - FLIR => 'Casio', + DJI => 'Casio', + FLIR => 'DJI', FujiFilm => 'FLIR', Kodak => 'JVC', Leaf => 'Kodak', @@ -109,6 +114,7 @@ my %formatOK = ( %Image::ExifTool::Exif::formatNumber, 0 => 1, 1 => 1, + 2 => 1, # (writable for docs only) real => 1, integer => 1, date => 1, @@ -136,6 +142,9 @@ my %formatOK = ( signed => 1, unsigned => 1, utf8 => 1, + Unicode => 1, # (Microsoft Xtra) + GUID => 1, # (Microsoft Xtra) + vt_filetime => 1, # (Microsoft Xtra) ); # Descriptions for the TagNames documentation @@ -158,6 +167,7 @@ meta information extracted from or written to a file. }, ExifTool => q{ The tables listed below give the names of all tags recognized by ExifTool. +They contain a total of $$self{COUNT}{'total tags'} tags, with $$self{COUNT}{'unique tag names'} unique tag names. }, ExifTool2 => q{ B, B or B is given in the first column of each @@ -166,8 +176,10 @@ is the identifier that is actually stored in the file. B refers to the offset of a value when found at a fixed position within a data block (B<#> is the multiplier for calculating a byte offset: B<1>, B<2>, B<4> or B<8>). These offsets may have a decimal part which is used only to -differentiate tags which have values stored at the same position. -B gives the order of values for a serial data stream. +differentiate tags with values stored at the same position. (Note that +writable tags within binary data blocks are not individually deletable, +and the usual alternative is to set them to a value of zero.) B +gives the order of values for a serial data stream. A B is the handle by which the information is accessed in ExifTool. In some instances, more than one name may correspond to a single @@ -175,7 +187,7 @@ tag ID. In these cases, the actual name used depends on the context in which the information is found. Case is not significant for tag names. A question mark (C) after a tag name indicates that the information is either not understood, not verified, or not very useful -- these tags are -not extracted by ExifTool unless the Unknown (-u) option is enabled. Be +not extracted by ExifTool unless the L (-u) option is enabled. Be aware that some tag names are different than the descriptions printed out by default when extracting information with exiftool. To see the tag names instead of the descriptions, use C. @@ -183,20 +195,20 @@ instead of the descriptions, use C. The B column indicates whether the tag is writable by ExifTool. Anything but a C in this column means the tag is writable. A C indicates writable information that is either unformatted or written using -the existing format. Other expressions give details about the information -format, and vary depending on the general type of information. The format -name may be followed by a number in square brackets to indicate the number -of values written, or the number of characters in a fixed-length string -(including a null terminator which is added if required). +the existing format. Other expressions give details about the format of the +stored value, and vary depending on the general type of information. The +format name may be followed by a number in square brackets to indicate the +number of values written, or the number of characters in a fixed-length +string (including a null terminator which is added if required). A plus sign (C<+>) after an entry in the B column indicates a I tag which supports multiple values and allows individual values to be added and deleted. A slash (C) indicates a tag that ExifTool will -I when writing. These tags are not created when writing if another -same-named tag may be created instead. To write these tags, the group +I when writing. These will be edited but not created if another +same-named tag may be created instead. To create these tags, the group should be specified. A tilde (C<~>) indicates a tag this is writable only -when the print conversion is disabled (by setting PrintConv to 0, using the --n option, or suffixing the tag name with a C<#> character). An exclamation +when the print conversion is disabled (by setting L to 0, using the +-n option, or suffixing the tag name with a C<#> character). An exclamation point (C) indicates a tag that is considered I to write under normal circumstances. These tags are not written unless specified explicitly (ie. not when wildcards or "all" are used), and care should be @@ -206,15 +218,16 @@ writable directly, but is written automatically by ExifTool (often when a corresponding L or L tag is written). A colon (C<:>) indicates a I tag which may be added automatically when -writing. +writing. Normally MakerNotes tags may not be deleted individually, but a +caret (C<^>) indicates a I MakerNotes tag. The HTML version of these tables also lists possible B for discrete-valued tags, as well as B for some tags. The B are -listed as the computer-readable and human-readable values on the left and -right hand side of an equals sign (C<=>) respectively. The human-readable +listed with the computer-readable values on the left of the equals sign +(C<=>), and the human-readable values on the right. The human-readable values are used by default when reading and writing, but the computer-readable values may be accessed by disabling the value conversion -with the -n option on the command line, by setting the ValueConv option to 0 +with the -n option on the command line, by setting the L option to 0 in the API, or or on a per-tag basis by adding a hash (C<#>) after the tag name. @@ -252,11 +265,11 @@ tags remain. The table below lists all EXIF tags. Also listed are TIFF, DNG, HDP and other tags which are not part of the EXIF specification, but may co-exist -with EXIF tags in some images. Tags which are part of the EXIF 2.31 +with EXIF tags in some images. Tags which are part of the EXIF 2.32 specification have an underlined B in the HTML version of this documentation. See -L for the -official EXIF 2.31 specification. +L +for the official EXIF 2.32 specification. }, GPS => q{ These GPS tags are part of the EXIF standard, and are stored in a separate @@ -272,7 +285,7 @@ Some GPS tags have values which are fixed-length strings. For these, the indicated string lengths include a null terminator which is added automatically by ExifTool. Remember that the descriptive values are used when writing (eg. 'Above Sea Level', not '0') unless the print conversion is -disabled (with '-n' on the command line or the PrintConv option in the API, +disabled (with '-n' on the command line or the L option in the API, or by suffixing the tag name with a C<#> character). When adding GPS information to an image, it is important to set all of the @@ -301,21 +314,22 @@ C is a string of digits (possibly beginning with a '+' or '-'), C is a floating point number, C is entered as a floating point number but stored as two C strings separated by a '/' character, C is a date/time string entered in the format "YYYY:mm:dd -HH:MM:SS[.ss][+/-HH:MM]", C is either "True" or "False", C -indicates a structured tag, and C is a tag that supports alternate -languages. +HH:MM:SS[.ss][+/-HH:MM]", C is either "True" or "False" (but "true" +and "false" may be written as a ValueConv value for compatibility with +non-conforming applications), C indicates a structured tag, and +C is a tag that supports alternate languages. -When reading, C tags are extracted only if the Struct (-struct) +When reading, C tags are extracted only if the L (-struct) option is used. Otherwise the corresponding I tags, indicated by an underline (C<_>) after the B type, are extracted. When copying, by default both structured and flattened tags are available, but -the flattened tags are considered "unsafe" so they they aren't copied unless -specified explicitly. The Struct option may be disabled by setting Struct +the flattened tags are considered "unsafe" so they aren't copied unless +specified explicitly. The L option may be disabled by setting Struct to 0 via the API or with --struct on the command line to copy only flattened tags, or enabled by setting Struct to 1 via the API or with -struct on the -command line to copy only as structures. When writing, the Struct option +command line to copy only as structures. When writing, the L option has no effect, and both structured and flattened tags may be written. See -L for more details. +L for more details. Individual languages for C tags are accessed by suffixing the tag name with a '-', followed by an RFC 3066 language code (eg. "XMP:Title-fr", @@ -327,12 +341,13 @@ to preserve other existing languages (eg. "XMP-dc:Description-x-default"). When reading, "x-default" is not specified. The XMP tags are organized according to schema B in the following -tables. In general, the ExifTool family 1 group names are derived from the -namespace prefixes by adding a leading "XMP-" (eg. "XMP-dc"), but a few of -the longer prefixes have been shortened for convenience (as mentioned in the -documentation below). The tags of any namespace may be deleted as a group -by specifying the family 1 group name (eg. "-XMP-dc:all=" on the command -line). This includes namespaces which are not pre-defined by ExifTool. +tables. The ExifTool family 1 group names are derived from the namespace +prefixes by adding a leading "XMP-" (eg. "XMP-dc"). A few of the longer +prefixes have been shortened (as mentioned in the documentation below) to +avoid excessively long ExifTool group names. The tags of any namespace may +be deleted as a group by specifying the family 1 group name (eg. +"-XMP-dc:all=" on the command line). This includes namespaces which are not +pre-defined by ExifTool. In cases where a tag name exists in more than one namespace, less common namespaces are avoided when writing. However, a specific namespace may be @@ -345,7 +360,7 @@ recommended if possible. For structures, the heading of the first column is B. Field names are very similar to tag names, except they are used to identify fields inside structures instead of stand-alone tags. See -L for more +L for more details. ExifTool will extract XMP information even if it is not listed in these @@ -379,7 +394,7 @@ the B format name. For tags where a range of lengths is allowed, the minimum and maximum lengths are separated by a comma within the brackets. When writing, ExifTool issues a minor warning and truncates the value if it is longer than allowed by the IPTC specification. Minor errors -may be ignored with the IgnoreMinorErrors (-m) option, allowing longer +may be ignored with the L (-m) option, allowing longer values to be written, but beware that values like this may cause problems for some other IPTC readers. ExifTool will happily read IPTC values of any length. @@ -402,6 +417,66 @@ number added for non-standard IPTC ("IPTC2", "IPTC3", etc), but when writing only "IPTC" may be specified as the group. To keep the IPTC consistent, ExifTool updates tags in all existing IPTC locations, but will create a new IPTC group only in the standard location. +}, + QuickTime => q{ +The QuickTime format is used for many different types of audio, video and +image files (most notably, MOV/MP4 videos and HEIC/CR3 images). ExifTool +extracts standard meta information and a variety of audio, video and image +parameters, as well as proprietary information written by many camera +models. Tags with a question mark after their name are not extracted unless +the L option is set. + +When writing, ExifTool creates both QuickTime and XMP tags by default, but +the group may be specified to write one or the other separately. If no +location is specified, newly created QuickTime tags are added in the +L location if +possible, otherwise in +L, and +finally in L, +but this order may be changed by setting the PREFERRED level of the +appropriate table in the config file (see +L in the full distribution for an +example). Note that some tags with the same name but different ID's may +exist in the same location, but the family 7 group names may be used to +differentiate these. ExifTool currently writes only top-level metadata in +QuickTime-based files; it extracts other track-specific and timed metadata, +but can not yet edit tags in these locations (with the exception of +track-level date/time tags). + +Alternate language tags may be accessed for +L and +L tags by adding +a 3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2 +country code to the tag name (eg. "ItemList:Artist-deu" or +"ItemList::Artist-deu-DE"). Most +L tags support a +language code, but without a country code. If no language code is specified +when writing, the default language is written and alternate languages for +the tag are deleted. Use the "und" language code to write the default +language without deleting alternate languages. Note that "eng" is treated +as a default language when reading, but not when writing. + +According to the specification, integer-format QuickTime date/time tags +should be stored as UTC. Unfortunately, digital cameras often store local +time values instead (presumably because they don't know the time zone). For +this reason, by default ExifTool does not assume a time zone for these +values. However, if the API L option is set, then ExifTool will +assume these values are properly stored as UTC, and will convert them to +local time when extracting. + +When writing string-based date/time tags, the system time zone is added if +the PrintConv option is enabled and no time zone is specified. This is +because Apple software may display crazy values if the time zone is missing +for some tags. + +By default ExifTool will remove null padding from some QuickTime containers +in Canon CR3 files when writing, but the +L option may be used to preserve +the original size by padding with nulls if necessary. + +See +L +for the official specification. }, Photoshop => q{ Photoshop tags are found in PSD and PSB files, as well as inside embedded @@ -411,7 +486,7 @@ a few). Many Photoshop tags are marked as Unknown (indicated by a question mark after the tag name) because the information they provide is not very useful under normal circumstances. These unknown tags are not extracted unless the -Unknown (-u) option is used. See +L (-u) option is used. See L for the official specification @@ -422,7 +497,7 @@ access to this information. }, PrintIM => q{ The format of the PrintIM information is known, however no PrintIM tags have -been decoded. Use the Unknown (-u) option to extract PrintIM information. +been decoded. Use the L (-u) option to extract PrintIM information. }, GeoTiff => q{ ExifTool extracts the following tags from GeoTIFF images. See @@ -470,7 +545,9 @@ These tags apply to CRW-format Canon RAW files and information in the APP0 "CIFF" segment of JPEG images. When writing CanonRaw/CIFF information, the length of the information is preserved (and the new information is truncated or padded as required) unless B is C. Currently, only -JpgFromRaw and ThumbnailImage are allowed to change size. +JpgFromRaw and ThumbnailImage are allowed to change size. See +L for a description of the Canon CRW +format. CRW images also support the addition of a CanonVRD trailer, which in turn supports XMP. This trailer is created automatically if necessary when @@ -485,7 +562,7 @@ settings have not been decoded for all models. The tables below list the custom settings for the currently supported models. }, Unknown => q{ -The following tags are decoded in unsupported maker notes. Use the Unknown +The following tags are decoded in unsupported maker notes. Use the L (-u) option to display other unknown tags. }, PDF => q{ @@ -497,7 +574,7 @@ specification. ExifTool supports reading and writing PDF documents up to version 1.7 extension level 3, including support for RC4, AES-128 and AES-256 -encryption. A Password option is provided to allow processing of +encryption. A L option is provided to allow processing of password-protected PDF files. ExifTool may be used to write native PDF and XMP metadata to PDF files. It @@ -568,13 +645,14 @@ overlapping EXIF, IPTC and XMP tags to be reconciled when reading, and synchronized when writing. The MWG Composite tags below are designed to aid in the implementation of these recommendations. As well, the MWG defines new XMP tags which are listed in the subsequent tables below. See -L for the official MWG specification. +L +for the official MWG specification. }, MacOS => q{ -On MacOS systems, there are a number of additional tags with names beginning -with "MDItem" and "XAttr" that may be extracted. These tags are not -extracted by default -- they must be specifically requested or enabled via -an API option. +On MacOS systems, the there are additional MDItem and XAttr Finder tags that +may be extracted. These tags are not extracted by default -- they must be +specifically requested or enabled via an API option. (Except when reading +MacOS "._" files directly, see below.) The tables below list some of the tags that may be extracted, but ExifTool will extract all available information even for tags not listed. @@ -591,7 +669,7 @@ L. ~head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. @@ -632,10 +710,14 @@ my %shortcutNotes = ( large binary data tags which may be excluded to reduce memory usage if memory limitations are a problem }, + 'ls-l' => q{ + mimics columns shown by Unix "ls -l" command. Includes some tags which are + extracted only if the API L option + is enabled + }, ); - -# same thing for RIFF INFO tags found in the EXIF spec +# lookup for RIFF INFO tags which are found in the EXIF spec my %riffSpec = ( IARL => 1, ICRD => 1, IGNR => 1, IPLT => 1, ISRC => 1, IART => 1, ICRP => 1, IKEY => 1, IPRD => 1, ISRF => 1, @@ -664,7 +746,7 @@ sub new my $that = shift; my $class = ref($that) || $that || 'Image::ExifTool::BuildTagLookup'; my $self = bless {}, $class; - my (%subdirs, %isShortcut, %allStructs); + my (%subdirs, %isShortcut); my %count = ( 'unique tag names' => 0, 'total tags' => 0, @@ -675,7 +757,7 @@ sub new my (%tagNameInfo, %id, %longID, %longName, %shortName, %tableNum, %tagLookup, %tagExists, %noLookup, %tableWritable, %sepTable, %case, %structs, %compositeModules, %isPlugin, %flattened, %structLookup, - @writePseudo); + @writePseudo, %dupXmpTag); $self->{TAG_NAME_INFO} = \%tagNameInfo; $self->{ID_LOOKUP} = \%id; $self->{LONG_ID} = \%longID; @@ -767,7 +849,8 @@ sub new $hexID = $$vars{HEX_ID}; my $processBinaryData = ($$table{PROCESS_PROC} and ( $$table{PROCESS_PROC} eq \&Image::ExifTool::ProcessBinaryData or - $$table{PROCESS_PROC} eq \&Image::ExifTool::Nikon::ProcessNikonEncrypted)); + $$table{PROCESS_PROC} eq \&Image::ExifTool::Nikon::ProcessNikonEncrypted or + $$table{PROCESS_PROC} eq \&Image::ExifTool::Sony::ProcessEnciphered)); if ($$vars{ID_LABEL} or $processBinaryData) { my $s = $$table{FORMAT} ? Image::ExifTool::FormatSize($$table{FORMAT}) || 1 : 1; $binaryTable = 1; @@ -817,6 +900,17 @@ TagID: foreach $tagID (@keys) { $case{$lc} = $name; } my $format = $$tagInfo{Format}; + # check TagID's to make sure they don't start with 'ID-' + my @grps = $et->GetGroup($tagInfo); + foreach (@grps) { + warn "Group name starts with 'ID-' for $short $name\n" if /^ID-/i; + } + if ($isXMP and not $$tagInfo{Avoid} and not $$tagInfo{Struct} and + ($$tagInfo{Writable} or $$table{WRITABLE})) + { + $dupXmpTag{$name} and warn "Duplicate writable XMP tag $name\n"; + $dupXmpTag{$name} = 1; + } # validate Name (must not start with a digit or else XML output will not be valid; # must not start with a dash or exiftool command line may get confused) if ($name !~ /^[_A-Za-z][-\w]+$/ and @@ -883,6 +977,10 @@ TagID: foreach $tagID (@keys) { } elsif (not $$tagInfo{SubDirectory}) { $writable = $$table{WRITABLE}; } + # in general, we can't write unless we have a WRITE_PROC + if ($writable and not ($$table{WRITE_PROC} or $tableName =~ /Shortcuts/ or $writable eq '2')) { + undef $writable; + } # 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 @@ -905,6 +1003,11 @@ TagID: foreach $tagID (@keys) { $$tagInfo{Groups}{2} ne 'Time') and $short ne 'DICOM') { warn "$short $name should be in 'Time' group!\n"; } + if ($name eq 'DateTimeOriginal' and (not $$tagInfo{Description} or + $$tagInfo{Description} ne 'Date/Time Original')) + { + warn "Need Description for $short DateTimeOriginal\n"; + } # validate Description (can't contain special characters) if ($$tagInfo{Description} and $$tagInfo{Description} ne EscapeHTML($$tagInfo{Description})) @@ -954,9 +1057,14 @@ TagID: foreach $tagID (@keys) { $note =~ s/(^[ \t]+|[ \t]+$)//mg; push @values, "($note)"; } - if ($isXMP and lc $tagID ne lc $name) { - # add note about different XMP Tag ID - my $note = $$tagInfo{RootTagInfo} ? $tagID : "called $tagID by the spec"; + if ($isXMP and (lc $tagID ne lc $name or $$tagInfo{NotFlat})) { + my $note; + if ($$tagInfo{NotFlat}) { + $note = 'NOT a flattened tag!'; + } else { + # add note about different XMP Tag ID + $note = $$tagInfo{RootTagInfo} ? $tagID : "called $tagID by the spec"; + } if ($$tagInfo{Notes}) { $values[-1] =~ s/^\(/($note; /; } else { @@ -1101,7 +1209,7 @@ TagID: foreach $tagID (@keys) { my $n = scalar @values; my ($bits, $i, $v); foreach (@pk) { - next if $_ eq ''; + next if $_ eq '' and $$printConv{$_} eq ''; $_ eq 'BITMASK' and $bits = $$printConv{$_}, next; $_ eq 'OTHER' and next; my $index; @@ -1195,21 +1303,33 @@ TagID: foreach $tagID (@keys) { } } if ($subdir and not $$tagInfo{SeparateTable}) { - # subdirectories are only writable if specified explicitly - my $tw = $$tagInfo{Writable}; - $writable = 'yes' if $tw and $writable eq '1'; - $writable = '-' . ($tw ? $writable : ''); - $writable .= '!' if $tw and ($$tagInfo{Protected} || 0) & 0x01; - $writable .= '+' if $$tagInfo{List}; + if ($writable) { + # subdirectories are only writable if specified explicitly + my $tw = $$tagInfo{Writable}; + $writable = 'yes' if $tw and $writable eq '1' or $writable eq '2'; + $writable = '-' . ($tw ? $writable : ''); + $writable .= '!' if $tw and ($$tagInfo{Protected} || 0) & 0x01; + $writable .= '+' if $$tagInfo{List}; + if (defined $$tagInfo{Permanent}) { + $writable .= '^' unless $$tagInfo{Permanent}; + } elsif (defined $$table{PERMANENT}) { + $writable .= '^' unless $$table{PERMANENT}; + } + } else { + $writable = '-'; + } } else { # not writable if we can't do the inverse conversions my $noPrintConvInv; if ($writable) { foreach ('PrintConv','ValueConv') { next unless $$tagInfo{$_}; - next if $$tagInfo{$_ . 'Inv'}; - next if ref($$tagInfo{$_}) =~ /^(HASH|ARRAY)$/; - next if $$tagInfo{WriteAlso}; + next if defined $$tagInfo{$_ . 'Inv'}; + # (undefined inverse conversion overrides hash lookup) + unless (exists $$tagInfo{$_ . 'Inv'}) { + next if ref($$tagInfo{$_}) =~ /^(HASH|ARRAY)$/; + next if $$tagInfo{WriteAlso}; + } if ($_ eq 'ValueConv') { undef $writable; } else { @@ -1220,10 +1340,11 @@ TagID: foreach $tagID (@keys) { if (not $writable) { $writable = 'no'; } else { - $writable eq '1' and $writable = $format ? $format : 'yes'; + $writable = $format ? $format : 'yes' if $writable eq '1' or $writable eq '2'; my $count = $$tagInfo{Count} || 1; # adjust count to Writable size if different than Format if ($writable and $format and $writable ne $format and + $writable ne 'string' and $format ne 'string' and $Image::ExifTool::Exif::formatNumber{$writable} and $Image::ExifTool::Exif::formatNumber{$format}) { @@ -1248,6 +1369,11 @@ TagID: foreach $tagID (@keys) { $writable .= '_' if defined $$tagInfo{Flat}; $writable .= '+' if $$tagInfo{List}; $writable .= ':' if $$tagInfo{Mandatory}; + if (defined $$tagInfo{Permanent}) { + $writable .= '^' unless $$tagInfo{Permanent}; + } elsif (defined $$table{PERMANENT}) { + $writable .= '^' unless $$table{PERMANENT}; + } # separate tables link like subdirectories (flagged with leading '-') $writable = "-$writable" if $subdir; } @@ -1371,11 +1497,13 @@ TagID: foreach $tagID (@keys) { if ($$table{$var}) { foreach $tagID (@{$$table{$var}}) { $$hash{$tagID} and delete($$hash{$tagID}), next; - warn "Warning: Extra $var for $short tag $tagID\n"; + warn sprintf("Warning: Extra %s for %s tag %d (0x%.4x)\n", + $var, $short, $tagID, $tagID); } } foreach $tagID (sort keys %$hash) { - warn "Warning: Missing $var for $short $$hash{$tagID}\n"; + warn sprintf("Warning: Missing %s for %s %s, tag %d (0x%.4x)\n", + $var, $short, $$hash{$tagID}, $tagID, $tagID); } } } @@ -1389,7 +1517,8 @@ TagID: foreach $tagID (@keys) { my $tag; foreach $tag (sort keys %$struct) { my $tagInfo = $$struct{$tag}; - next unless ref $tagInfo eq 'HASH'; + next unless ref $tagInfo eq 'HASH' and $tag ne 'NAMESPACE' and $tag ne 'GROUPS'; + warn "WARNING: $strName Struct containes $tag\n" if $Image::ExifTool::specialTags{$tag}; my $writable = $$tagInfo{Writable}; my @vals; unless ($writable) { @@ -1513,7 +1642,10 @@ sub WriteTagLookup($$) } elsif ($tagID =~ /^\d+$/) { $entry = sprintf('0x%x',$tagID); } else { - $entry = "'${tagID}'"; + my $quot = "'"; + # escape non-printable characters in tag ID if necessary + $quot = '"' if $tagID =~ s/[\x00-\x1f,\x7f-\xff]/sprintf('\\x%.2x',ord($&))/ge; + $entry = "$quot${tagID}$quot"; } my $wrNum = $wrNum{$tableNum}; push @entries, "$wrNum => $entry"; @@ -1652,9 +1784,9 @@ sub Doc2Html($) $doc =~ s/B<(.*?)>/$1<\/b>/sg; $doc =~ s/C<(.*?)>/$1<\/code>/sg; $doc =~ s/I<(.*?)>/$1<\/i>/sg; - # L --> some text + # L --> some text $doc =~ s{L<([^&]+?)\|\Q$homePage\E/(.*?)>}{$1<\/a>}sg; - # L --> http://owl.phy.queensu.ca/~phil/exiftool/struct.html + # L --> https://exiftool.org/struct.html $doc =~ s{L<\Q$homePage\E/(.*?)>}{$1<\/a>}sg; # L --> <a href="XMP.html#DICOM">XMP DICOM Tags</a> # (specify "Image::ExifTool::TagNames" to link to another html file) @@ -1851,7 +1983,9 @@ sub OpenHtmlFile($;$$) open(HTMLFILE, ">>${htmlFile}_tmp") or return 0; } else { open(HTMLFILE, ">${htmlFile}_tmp") or return 0; - print HTMLFILE "$docType<html>\n<head>\n<title>$title</title>\n"; + print HTMLFILE "$docType<html>\n"; + print HTMLFILE "<!-- (this file generated automatically by Image::ExifTool::BuildTagLookup) -->\n"; + print HTMLFILE "<head>\n<title>$title</title>\n"; print HTMLFILE "<link rel=stylesheet type='text/css' href='style.css' title='Style'>\n"; print HTMLFILE "</head>\n<body>\n"; if ($category ne $class and $docs{$class}) { @@ -1896,6 +2030,7 @@ sub CloseHtmlFiles($) # write the trailers print HTMLFILE "<hr>\n"; print HTMLFILE "(This document generated automatically by Image::ExifTool::BuildTagLookup)\n"; + print HTMLFILE "<br><i>Created $createDate</i>\n" if $htmlFile eq 'html/TagNames/index.html'; print HTMLFILE "<br><i>Last revised $fileDate</i>\n"; print HTMLFILE "<p class=lf><a href="; if ($htmlFile =~ /index\.html$/) { @@ -1977,6 +2112,7 @@ sub WriteTagNames($$) # open the file and write the header open(PODFILE, ">$podFile") or return 0; + $docs{ExifTool} = eval qq{"$docs{ExifTool}"}; print PODFILE Doc2Pod($docs{PodHeader}, $docs{ExifTool}, $docs{ExifTool2}); mkdir "$htmldir/TagNames", 0777; OpenHtmlFile($htmldir) or return 0; @@ -1996,7 +2132,7 @@ sub WriteTagNames($$) $short = $$shortName{$tableName}; my @names = split ' ', $short; my $class = shift @names; - if (@names) { + if (@names and $class ne 'Other') { # add heading for tables without a Main unless ($heading eq $class) { $heading = $class; @@ -2024,6 +2160,13 @@ sub WriteTagNames($$) $short = $$shortName{$tableName}; $short = $tableName unless $short; $url = "$short.html"; + # handle various tables in "Other.pm" + if ($short =~ /^Other (.*)/) { + $short = $1; + $url = 'Other.html#' . $1; + } else { + $url = "$short.html"; + } print HTMLFILE "<a href='${url}'>$short</a>"; ++$count; } @@ -2060,6 +2203,9 @@ sub WriteTagNames($$) my $w = length($_) + length($$printConv{$_}); $wid = $w if $wid < $w; push @keys, $_; + if ($$printConv{$_} =~ /[\0-\x1f\x7f-\xff]/) { + warn "Warning: Special characters in $tableName PrintConv ($$printConv{$_})\n"; + } } $wid = length($tableName)+7 if $wid < length($tableName)+7; # print in multiple columns if there is room @@ -2438,10 +2584,11 @@ sub WriteTagNames($$) '!' => 'Unsafe', '*' => 'Protected', ':' => 'Mandatory', + '^' => 'Deletable', ); my ($wstr, %hasAttr, @hasAttr); foreach $wstr (@$writable) { - next unless $wstr =~ m{([+/~!*:_]+)$}; + next unless $wstr =~ m{([+/~!*:_^]+)$}; my @a = split //, $1; foreach (@a) { next if $hasAttr{$_}; @@ -2472,6 +2619,7 @@ sub WriteTagNames($$) my ($smallNote, @values); foreach (@$values) { if (/^\(/) { + $_ = Doc2Html($_); # set the note font $smallNote = 1 if $numTags < 2; push @values, ($smallNote ? $noteFontSmall : $noteFont) . "$_</span>"; @@ -2482,6 +2630,7 @@ sub WriteTagNames($$) if (s/^\[!HTML\]//) { push @values, $_; } else { + $_ = Doc2Html($_); push @values, "<span class=s>$_</span>"; } next; @@ -2610,13 +2759,13 @@ WriteTagNames(). =item WRITE_PSEUDO -List of writable pseudo tags. +Returned list of writable pseudo tags. =back =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/CBOR.pm b/src/Image-ExifTool/lib/Image/ExifTool/CBOR.pm new file mode 100644 index 00000000..267c1cbc --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/CBOR.pm @@ -0,0 +1,331 @@ +#------------------------------------------------------------------------------ +# File: CBOR.pm +# +# Description: Read CBOR format metadata +# +# Revisions: 2021-09-30 - P. Harvey Created +# +# References: 1) https://c2pa.org/public-draft/ +# 2) https://datatracker.ietf.org/doc/html/rfc7049 +#------------------------------------------------------------------------------ + +package Image::ExifTool::CBOR; +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); +use Image::ExifTool::JSON; + +$VERSION = '1.01'; + +sub ProcessCBOR($$$); +sub ReadCBORValue($$$$); + +# optional CBOR type code +my %cborType6 = ( + 0 => 'date/time string', + 1 => 'epoch-based date/time', + 2 => 'positive bignum', + 3 => 'negative bignum', + 4 => 'decimal fraction', + 5 => 'bigfloat', + 21 => 'expected base64url encoding', + 22 => 'expected base64 encoding', + 23 => 'expected base16 encoding', + 24 => 'encoded CBOR data', + 32 => 'URI', + 33 => 'base64url', + 34 => 'base64', + 35 => 'regular expression', + 36 => 'MIME message', + 55799 => 'CBOR magic number', +); + +my %cborType7 = ( + 20 => 'False', + 21 => 'True', + 22 => 'null', + 23 => 'undef', +); + +%Image::ExifTool::CBOR::Main = ( + GROUPS => { 0 => 'JUMBF', 1 => 'CBOR', 2 => 'Other' }, + VARS => { NO_ID => 1 }, + PROCESS_PROC => \&ProcessCBOR, + NOTES => q{ + The tags below are extracted from CBOR (Concise Binary Object + Representation) metadata. The C2PA specification uses this format for some + metadata. As well as these tags, ExifTool will read any existing tags. + }, + 'dc:title' => 'Title', + 'dc:format' => 'Format', + # my sample file has the following 2 tags in CBOR, but they should be JSON + authorName => { Name => 'AuthorName', Groups => { 2 => 'Author' } }, + authorIdentifier=> { Name => 'AuthorIdentifier', Groups => { 2 => 'Author' } }, + documentID => { }, + instanceID => { }, + thumbnailHash => { List => 1 }, + thumbnailUrl => { Name => 'ThumbnailURL' }, + relationship => { } +); + +#------------------------------------------------------------------------------ +# Read CBOR value +# Inputs: 0) ExifTool ref, 1) data ref, 2) position in data, 3) data end +# Returns: 0) value, 1) error string, 2) new data position +sub ReadCBORValue($$$$) +{ + my ($et, $dataPt, $pos, $end) = @_; + return(undef, 'Truncated CBOR data', $pos) if $pos >= $end; + my $verbose = $$et{OPTIONS}{Verbose}; + my $indent = $$et{INDENT}; + my $dumpStart = $pos; + my $fmt = Get8u($dataPt, $pos++); + my $dat = $fmt & 0x1f; + my ($num, $val, $err, $size); + $fmt >>= 5; + if ($dat < 24) { + $num = $dat; + } elsif ($dat == 31) { # indefinite count (not used in C2PA) + $num = -1; # (flag for indefinite count) + $et->VPrint(1, "$$et{INDENT} (indefinite count):\n"); + } else { + my $format = { 24 => 'int8u', 25 => 'int16u', 26 => 'int32u', 27 => 'int64u' }->{$dat}; + return(undef, "Invalid CBOR integer type $dat", $pos) unless $format; + $size = Image::ExifTool::FormatSize($format); + return(undef, 'Truncated CBOR integer value', $pos) if $pos + $size > $end; + $num = ReadValue($dataPt, $pos, $format, 1, $size); + $pos += $size; + } + my $pre = ''; + if (defined $$et{cbor_pre} and $fmt != 6) { + $pre = $$et{cbor_pre}; + delete $$et{cbor_pre}; + } + if ($fmt == 0) { # positive integer + $val = $num; + $et->VPrint(1, "$$et{INDENT} ${pre}int+: $val\n"); + } elsif ($fmt == 1) { # negative integer + $val = -1 * $num; + $et->VPrint(1, "$$et{INDENT} ${pre}int-: $val\n"); + } elsif ($fmt == 2 or $fmt == 3) { # byte/UTF8 string + return(undef, 'Truncated CBOR string value', $pos) if $pos + $num > $end; + if ($num < 0) { # (should not happen in C2PA) + my $string = ''; + $$et{INDENT} .= ' '; + for (;;) { + ($val, $err, $pos) = ReadCBORValue($et, $dataPt, $pos, $end); + return(undef, $err, $pos) if $err; + last if not defined $val; # hit the break? + # (note: strictly we should be checking that this was a string we read) + $string .= $val; + } + $$et{INDENT} = $indent; + return($string, undef, $pos); # return concatenated byte/text string + } else { + $val = substr($$dataPt, $pos, $num); + } + $pos += $num; + if ($fmt == 2) { # (byte string) + $et->VPrint(1, "$$et{INDENT} ${pre}byte: <binary data ".length($val)." bytes>\n"); + my $dat = $val; + $val = \$dat; # use scalar reference for binary data + } else { # (text string) + $val = $et->Decode($val, 'UTF8'); + $et->VPrint(1, "$$et{INDENT} ${pre}text: '${val}'\n"); + } + } elsif ($fmt == 4 or $fmt == 5) { # list/hash + if ($fmt == 4) { + $et->VPrint(1, "$$et{INDENT} ${pre}list: <$num elements>\n"); + } else { + $et->VPrint(1, "$$et{INDENT} ${pre}hash: <$num pairs>\n"); + $num *= 2; + } + $$et{INDENT} .= ' '; + my $i = 0; + my @list; + Image::ExifTool::HexDump($dataPt, $pos - $dumpStart, + Start => $dumpStart, + DataPos => $$et{cbor_datapos}, + Prefix => $$et{INDENT}, + ) if $verbose > 2; + while ($num) { + $$et{cbor_pre} = "$i) "; + if ($fmt == 4) { + ++$i; + } elsif ($num & 0x01) { + $$et{cbor_pre} = ' ' x length($$et{cbor_pre}); + ++$i; + } + ($val, $err, $pos) = ReadCBORValue($et, $dataPt, $pos, $end); + return(undef, $err, $pos) if $err; + if (not defined $val) { + return(undef, 'Unexpected list terminator', $pos) unless $num < 0; + last; + } + push @list, $val; + --$num; + } + $dumpStart = $pos; + $$et{INDENT} = $indent; + if ($fmt == 5) { + my ($i, @keys); + my %hash = ( _ordered_keys_ => \@keys ); + for ($i=0; $i<@list-1; $i+=2) { + $hash{$list[$i]} = $list[$i+1]; + push @keys, $list[$i]; # save ordered list of keys + } + $val = \%hash; + } else { + $val = \@list; + } + } elsif ($fmt == 6) { # optional tag + if ($verbose) { + my $str = "$num (" . ($cborType6{$num} || 'unknown') . ')'; + my $spc = $$et{cbor_pre} ? (' ' x length $$et{cbor_pre}) : ''; + $et->VPrint(1, "$$et{INDENT} $spc<CBOR optional type $str>\n"); + Image::ExifTool::HexDump($dataPt, $pos - $dumpStart, + Start => $dumpStart, + DataPos => $$et{cbor_datapos}, + Prefix => $$et{INDENT} . ' ', + ) if $verbose > 2; + } + # read next value (note: in the case of multiple tags, + # this nesting will apply the tags in the correct order) + ($val, $err, $pos) = ReadCBORValue($et, $dataPt, $pos, $end); + $dumpStart = $pos; + # convert some values according to the optional tag number (untested) + if ($num == 0 and not ref $val) { # date/time string + require Image::ExifTool::XMP; + $val = Image::ExifTool::XMP::ConvertXMPDate($val); + } elsif ($num == 1 and not ref $val) { # epoch-based date/time + if (Image::ExifTool::IsFloat($val)) { + my $dec = ($val == int($val)) ? undef : 6; + $val = Image::ExifTool::ConvertUnixTime($val, 1, $dec); + } + } elsif (($num == 2 or $num == 3) and ref($val) eq 'SCALAR') { # pos/neg bignum + my $big = 0; + $big = 256 * $big + Get8u($val,$_) foreach 0..(length($$val) - 1); + $val = $num==2 ? $big : -$big; + } elsif (($num == 4 or $num == 5) and # decimal fraction or bigfloat + ref($val) eq 'ARRAY' and @$val == 2 and + Image::ExifTool::IsInt($$val[0]) and Image::ExifTool::IsInt($$val[1])) + { + $val = $$val[1] * ($num == 4 ? 10 : 2) ** $$val[0]; + } + } elsif ($fmt == 7) { + if ($dat == 31) { + undef $val; # "break" = end of indefinite array/hash (not used in C2PA) + } elsif ($dat < 24) { + $val = $cborType7{$num}; + $val = "Unknown ($val)" unless defined $val; + } elsif ($dat == 25) { # half-precision float + my $exp = ($num >> 10) & 0x1f; + my $mant = $num & 0x3ff; + if ($exp == 0) { + $val = $mant ** -24; + $val *= -1 if $num & 0x8000; + } elsif (exp != 31) { + $val = ($mant + 1024) ** ($exp - 25); + $val *= -1 if $num & 0x8000; + } else { + $val = $mant == 0 ? '<inf>' : '<nan>'; + } + } elsif ($dat == 26) { # float + $val = GetFloat($dataPt, $pos - $size); + } elsif ($dat == 27) { # double + $val = GetDouble($dataPt, $pos - $size); + } else { + return(undef, "Invalid CBOR type 7 variant $num", $pos); + } + $et->VPrint(1, "$$et{INDENT} ${pre}typ7: ".(defined $val ? $val : '<break>')."\n"); + } else { + return(undef, "Unknown CBOR format $fmt", $pos); + } + Image::ExifTool::HexDump($dataPt, $pos - $dumpStart, + Start => $dumpStart, + DataPos => $$et{cbor_datapos}, + Prefix => $$et{INDENT} . ' ', + MaxLen => $verbose < 5 ? ($verbose == 3 ? 96 : 2048) : undef, + ) if $verbose > 2; + return($val, $err, $pos); +} + +#------------------------------------------------------------------------------ +# Read CBOR box +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub ProcessCBOR($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $pos = $$dirInfo{DirStart}; + my $end = $pos + $$dirInfo{DirLen}; + my ($val, $err, $tag, $i); + + $et->VerboseDir('CBOR', undef, $$dirInfo{DirLen}); + + $$et{cbor_datapos} = $$dirInfo{DataPos} + $$dirInfo{Base}; + + while ($pos < $end) { + ($val, $err, $pos) = ReadCBORValue($et, $dataPt, $pos, $end); + $err and $et->Warn($err), last; + if (ref $val eq 'HASH') { + foreach $tag (@{$$val{_ordered_keys_}}) { + Image::ExifTool::JSON::ProcessTag($et, $tagTablePtr, $tag, $$val{$tag}); + } + } elsif (ref $val eq 'ARRAY') { + for ($i=0; $i<@$val; ++$i) { + Image::ExifTool::JSON::ProcessTag($et, $tagTablePtr, "Item$i", $$val[$i]); + } + } elsif ($val eq '0') { + $et->VPrint(1, "$$et{INDENT} <CBOR end>\n"); + last; # (treat as padding) + } else { + $et->VPrint(1, "$$et{INDENT} Unknown value: $val\n"); + } + } + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::CBOR - Read CBOR format metadata + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool read Concise +Binary Object Representation (CBOR) formatted metadata, used by the C2PA +specification. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<https://c2pa.org/public-draft/> + +=item L<https://datatracker.ietf.org/doc/html/rfc7049> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/CBOR Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Canon.pm b/src/Image-ExifTool/lib/Image/ExifTool/Canon.pm index f214ba35..85122a2d 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Canon.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Canon.pm @@ -63,10 +63,11 @@ # 47) http://www.exiv2.org/ # 48) Tomasz A. Kawecki private communication (550D, firmware 1.0.6, 1.0.8) # 49) http://www.listware.net/201101/digikam-users/49795-digikam-users-re-lens-recognition.html -# 50) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3833.0.html -# 51) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,4110.0.html +# 50) https://exiftool.org/forum/index.php/topic,3833.0.html +# 51) https://exiftool.org/forum/index.php/topic,4110.0.html # 52) Kai Harrekilde-Petersen private communication # 53) Anton Reiser private communication +# 54) https://github.com/lclevy/canon_cr3 # IB) Iliah Borg private communication (LibRaw) # JD) Jens Duttke private communication # JR) Jos Roost private communication @@ -87,7 +88,7 @@ sub ProcessCTMD($$$); sub ProcessExifInfo($$$); sub SwapWords($); -$VERSION = '4.02'; +$VERSION = '4.60'; # Note: Removed 'USM' from 'L' lenses since it is redundant - PH # (or is it? Ref 32 shows 5 non-USM L-type lenses) @@ -101,7 +102,8 @@ $VERSION = '4.02'; }, -1 => 'n/a', 1 => 'Canon EF 50mm f/1.8', - 2 => 'Canon EF 28mm f/2.8', + 2 => 'Canon EF 28mm f/2.8 or Sigma Lens', + 2.1 => 'Sigma 24mm f/2.8 Super Wide II', #ClaudeJolicoeur # (3 removed in current Kamisaka list) 3 => 'Canon EF 135mm f/2.8 Soft', #15/32 4 => 'Canon EF 35-105mm f/3.5-4.5 or Sigma Lens', #28 @@ -143,11 +145,14 @@ $VERSION = '4.02'; 26.2 => 'Tamron SP AF 90mm f/2.8 Di Macro', #15 26.3 => 'Tamron SP AF 180mm f/3.5 Di Macro', #15 26.4 => 'Carl Zeiss Planar T* 50mm f/1.4', #PH + 26.5 => 'Voigtlander APO Lanthar 125mm F2.5 SL Macro', #JR + 26.6 => 'Carl Zeiss Planar T 85mm f/1.4 ZE', #IB 27 => 'Canon EF 35-80mm f/4-5.6', #32 # 27 => 'Carl Zeiss Distagon T* 28mm f/2 ZF', #PH (must be with an adapter, because the ZF version is a Nikon mount) # 27 => 'EMF adapter for Canon EOS digital cameras', #50 (reports MaxFocalLength of 65535) # 27 => optix adapter # 27 => Venus Optics Laowa 12mm f2.8 Zero-D or 105mm f2 (T3.2) Smooth Trans Focus (ref IB) + # 27 => Venus Optics Laowa 105mm f2 STF (ref IB) 28 => 'Canon EF 80-200mm f/4.5-5.6 or Tamron Lens', #32 28.1 => 'Tamron SP AF 28-105mm f/2.8 LD Aspherical IF', #15 28.2 => 'Tamron SP AF 28-75mm f/2.8 XR Di LD Aspherical [IF] Macro', #4 @@ -179,21 +184,23 @@ $VERSION = '4.02'; 36 => 'Canon EF 38-76mm f/4.5-5.6', #32 37 => 'Canon EF 35-80mm f/4-5.6 or Tamron Lens', #32 37.1 => 'Tamron 70-200mm f/2.8 Di LD IF Macro', #PH - 37.2 => 'Tamron AF 28-300mm f/3.5-6.3 XR Di VC LD Aspherical [IF] Macro Model A20', #38 + 37.2 => 'Tamron AF 28-300mm f/3.5-6.3 XR Di VC LD Aspherical [IF] Macro (A20)', #38 37.3 => 'Tamron SP AF 17-50mm f/2.8 XR Di II VC LD Aspherical [IF]', #34 37.4 => 'Tamron AF 18-270mm f/3.5-6.3 Di II VC LD Aspherical [IF] Macro', #forum2937 - 38 => 'Canon EF 80-200mm f/4.5-5.6', #32 + 38 => 'Canon EF 80-200mm f/4.5-5.6 II', #32 (II added ref https://github.com/Exiv2/exiv2/issues/1906) 39 => 'Canon EF 75-300mm f/4-5.6', 40 => 'Canon EF 28-80mm f/3.5-5.6', 41 => 'Canon EF 28-90mm f/4-5.6', #32 42 => 'Canon EF 28-200mm f/3.5-5.6 or Tamron Lens', #32 - 42.1 => 'Tamron AF 28-300mm f/3.5-6.3 XR Di VC LD Aspherical [IF] Macro Model A20', #15 + 42.1 => 'Tamron AF 28-300mm f/3.5-6.3 XR Di VC LD Aspherical [IF] Macro (A20)', #15 43 => 'Canon EF 28-105mm f/4-5.6', #10 44 => 'Canon EF 90-300mm f/4.5-5.6', #32 45 => 'Canon EF-S 18-55mm f/3.5-5.6 [II]', #PH (same ID for version II, ref 20) 46 => 'Canon EF 28-90mm f/4-5.6', #32 + # 46 => 'Tamron 28-300mm f/3.5-6.3 Di VC PZD (A010)', # (also possibly?) 47 => 'Zeiss Milvus 35mm f/2 or 50mm f/2', #IB 47.1 => 'Zeiss Milvus 50mm f/2 Makro', #IB + 47.2 => 'Zeiss Milvus 135mm f/2 ZE', #IB 48 => 'Canon EF-S 18-55mm f/3.5-5.6 IS', #20 49 => 'Canon EF-S 55-250mm f/4-5.6 IS', #23 50 => 'Canon EF-S 18-200mm f/3.5-5.6 IS', @@ -202,6 +209,7 @@ $VERSION = '4.02'; 53 => 'Canon EF-S 18-55mm f/3.5-5.6 III', #Jon Charnas 54 => 'Canon EF-S 55-250mm f/4-5.6 IS II', #47 60 => 'Irix 11mm f/4', #50 + 63 => 'Irix 30mm F1.4 Dragonfly', #IB 80 => 'Canon TS-E 50mm f/2.8L Macro', #42 81 => 'Canon TS-E 90mm f/2.8L Macro', #42 82 => 'Canon TS-E 135mm f/4L Macro', #42 @@ -210,10 +218,17 @@ $VERSION = '4.02'; 103 => 'Samyang AF 14mm f/2.8 EF or Rokinon Lens', #IB 103.1 => 'Rokinon SP 14mm f/2.4', #IB 103.2 => 'Rokinon AF 14mm f/2.8 EF', #IB + 106 => 'Rokinon SP / Samyang XP 35mm f/1.2', #IB + 112 => 'Sigma 28mm f/1.5 FF High-speed Prime or other Sigma Lens', #IB + 112.1 => 'Sigma 40mm f/1.5 FF High-speed Prime', #IB + 112.2 => 'Sigma 105mm f/1.5 FF High-speed Prime', #IB + 117 => 'Tamron 35-150mm f/2.8-4.0 Di VC OSD (A043) or other Tamron Lens', #IB + 117.1 => 'Tamron SP 35mm f/1.4 Di USD (F045)', #Exiv2#1064 124 => 'Canon MP-E 65mm f/2.8 1-5x Macro Photo', #9 125 => 'Canon TS-E 24mm f/3.5L', 126 => 'Canon TS-E 45mm f/2.8', #15 - 127 => 'Canon TS-E 90mm f/2.8', #15 + 127 => 'Canon TS-E 90mm f/2.8 or Tamron Lens', #15 + 127.1 => 'Tamron 18-200mm f/3.5-6.3 Di II VC (B018)', #TomLachecki 129 => 'Canon EF 300mm f/2.8L USM', #32 130 => 'Canon EF 50mm f/1.0L USM', #10/15 131 => 'Canon EF 28-80mm f/2.8-4L USM or Sigma Lens', #32 @@ -226,10 +241,12 @@ $VERSION = '4.02'; # 'Sigma APO 120-300mm f/2.8 EX DG HSM + 2x', #15 131.6 => 'Sigma 4.5mm f/2.8 EX DC HSM Circular Fisheye', #PH 131.7 => 'Sigma 70-200mm f/2.8 APO EX HSM', #PH (http://www.lensrentals.com/blog/2012/08/canon-illumination-correction-and-third-party-lenses) + 131.8 => 'Sigma 28-70mm f/2.8-4 DG', #IB 132 => 'Canon EF 1200mm f/5.6L USM', #32 134 => 'Canon EF 600mm f/4L IS USM', #15 135 => 'Canon EF 200mm f/1.8L USM', 136 => 'Canon EF 300mm f/2.8L USM', + 136.1 => 'Tamron SP 15-30mm f/2.8 Di VC USD (A012)', #TomLachecki 137 => 'Canon EF 85mm f/1.2L USM or Sigma or Tamron Lens', #10 137.1 => 'Sigma 18-50mm f/2.8-4.5 DC OS HSM', #PH 137.2 => 'Sigma 50-200mm f/4-5.6 DC OS HSM', #PH @@ -239,14 +256,15 @@ $VERSION = '4.02'; 137.6 => 'Sigma 17-70mm f/2.8-4 DC Macro OS HSM | C', #forum2819 (Contemporary version has this ID - PH) 137.7 => 'Sigma 17-50mm f/2.8 OS HSM', #47 137.8 => 'Sigma 18-200mm f/3.5-6.3 DC OS HSM [II]', #PH - 137.9 => 'Tamron AF 18-270mm f/3.5-6.3 Di II VC PZD', #(model B008)forum3090 + 137.9 => 'Tamron AF 18-270mm f/3.5-6.3 Di II VC PZD (B008)', #forum3090 '137.10' => 'Sigma 8-16mm f/4.5-5.6 DC HSM', #50-Zwielicht - '137.11' => 'Tamron SP 17-50mm f/2.8 XR Di II VC', #50 (model B005) - '137.12' => 'Tamron SP 60mm f/2 Macro Di II', #50 (model G005) + '137.11' => 'Tamron SP 17-50mm f/2.8 XR Di II VC (B005)', #50 + '137.12' => 'Tamron SP 60mm f/2 Macro Di II (G005)', #50 '137.13' => 'Sigma 10-20mm f/3.5 EX DC HSM', #Gerald Erdmann '137.14' => 'Tamron SP 24-70mm f/2.8 Di VC USD', #PH '137.15' => 'Sigma 18-35mm f/1.8 DC HSM', #David Monro '137.16' => 'Sigma 12-24mm f/4.5-5.6 DG HSM II', #IB + '137.17' => 'Sigma 70-300mm f/4-5.6 DG OS', #IB 138 => 'Canon EF 28-80mm f/2.8-4L', #32 139 => 'Canon EF 400mm f/2.8L USM', 140 => 'Canon EF 500mm f/4.5L USM', #32 @@ -265,23 +283,28 @@ $VERSION = '4.02'; 150.2 => 'Sigma 30mm f/1.4 DC HSM', #15 150.3 => 'Sigma 24mm f/1.8 DG Macro EX', #15 150.4 => 'Sigma 28mm f/1.8 DG Macro EX', #IB + 150.5 => 'Sigma 18-35mm f/1.8 DC HSM | A', #IB 151 => 'Canon EF 200mm f/2.8L USM', 152 => 'Canon EF 300mm f/4L IS USM or Sigma Lens', #15 152.1 => 'Sigma 12-24mm f/4.5-5.6 EX DG ASPHERICAL HSM', #15 152.2 => 'Sigma 14mm f/2.8 EX Aspherical HSM', #15 152.3 => 'Sigma 10-20mm f/4-5.6', #14 152.4 => 'Sigma 100-300mm f/4', # (ref Bozi) + 152.5 => 'Sigma 300-800mm f/5.6 APO EX DG HSM', #IB 153 => 'Canon EF 35-350mm f/3.5-5.6L USM or Sigma or Tamron Lens', #PH 153.1 => 'Sigma 50-500mm f/4-6.3 APO HSM EX', #15 153.2 => 'Tamron AF 28-300mm f/3.5-6.3 XR LD Aspherical [IF] Macro', - 153.3 => 'Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical [IF] Macro Model A14', #15 + 153.3 => 'Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical [IF] Macro (A14)', #15 153.4 => 'Tamron 18-250mm f/3.5-6.3 Di II LD Aspherical [IF] Macro', #PH 154 => 'Canon EF 20mm f/2.8 USM or Zeiss Lens', #15 154.1 => 'Zeiss Milvus 21mm f/2.8', #IB - 155 => 'Canon EF 85mm f/1.8 USM', + 154.2 => 'Zeiss Milvus 15mm f/2.8 ZE', #IB + 154.3 => 'Zeiss Milvus 18mm f/2.8 ZE', #IB + 155 => 'Canon EF 85mm f/1.8 USM or Sigma Lens', + 155.1 => 'Sigma 14mm f/1.8 DG HSM | A', #IB (A017) 156 => 'Canon EF 28-105mm f/3.5-4.5 USM or Tamron Lens', - 156.1 => 'Tamron SP 70-300mm f/4-5.6 Di VC USD', #PH (model A005) - 156.2 => 'Tamron SP AF 28-105mm f/2.8 LD Aspherical IF', #JR (Model 176D) + 156.1 => 'Tamron SP 70-300mm f/4-5.6 Di VC USD (A005)', #PH + 156.2 => 'Tamron SP AF 28-105mm f/2.8 LD Aspherical IF (176D)', #JR 160 => 'Canon EF 20-35mm f/3.5-4.5 USM or Tamron or Tokina Lens', 160.1 => 'Tamron AF 19-35mm f/3.5-4.5', #44 160.2 => 'Tokina AT-X 124 AF Pro DX 12-24mm f/4', #49 @@ -294,7 +317,7 @@ $VERSION = '4.02'; 161.3 => 'Sigma 24-60mm f/2.8 EX DG', #PH (http://www.lensrentals.com/blog/2012/08/canon-illumination-correction-and-third-party-lenses) 161.4 => 'Tamron AF 17-50mm f/2.8 Di-II LD Aspherical', #40 161.5 => 'Tamron 90mm f/2.8', - 161.6 => 'Tamron SP AF 17-35mm f/2.8-4 Di LD Aspherical IF', #IB (A05) + 161.6 => 'Tamron SP AF 17-35mm f/2.8-4 Di LD Aspherical IF (A05)', #IB 161.7 => 'Tamron SP AF 28-75mm f/2.8 XR Di LD Aspherical [IF] Macro', #IB/NJ 161.8 => 'Tokina AT-X 24-70mm f/2.8 PRO FX (IF)', #IB 162 => 'Canon EF 200mm f/2.8L USM', #32 @@ -314,18 +337,30 @@ $VERSION = '4.02'; 169.6 => 'Sigma 30mm f/1.4 EX DC HSM', #Rodolfo Borges 169.7 => 'Sigma 35mm f/1.4 DG HSM', #PH (also "| A" version, ref 50) 169.8 => 'Sigma 35mm f/1.5 FF High-Speed Prime | 017', #IB - 170 => 'Canon EF 200mm f/2.8L II USM', #9 + 169.9 => 'Sigma 70mm f/2.8 Macro EX DG', #IB + 170 => 'Canon EF 200mm f/2.8L II USM or Sigma Lens', #9 + 170.1 => 'Sigma 300mm f/2.8 APO EX DG HSM', #IB + 170.2 => 'Sigma 800mm f/5.6 APO EX DG HSM', #IB 171 => 'Canon EF 300mm f/4L USM', #15 172 => 'Canon EF 400mm f/5.6L USM or Sigma Lens', #32 172.1 =>'Sigma 150-600mm f/5-6.3 DG OS HSM | S', #50 + 172.2 => 'Sigma 500mm f/4.5 APO EX DG HSM', #IB 173 => 'Canon EF 180mm Macro f/3.5L USM or Sigma Lens', #9 173.1 => 'Sigma 180mm EX HSM Macro f/3.5', #14 173.2 => 'Sigma APO Macro 150mm f/2.8 EX DG HSM', #14 + 173.3 => 'Sigma 10mm f/2.8 EX DC Fisheye', #IB + 173.4 => 'Sigma 15mm f/2.8 EX DG Diagonal Fisheye', #IB + 173.5 => 'Venus Laowa 100mm F2.8 2X Ultra Macro APO', #IB 174 => 'Canon EF 135mm f/2L USM or Other Lens', #9 174.1 => 'Sigma 70-200mm f/2.8 EX DG APO OS HSM', #PH (probably version II of this lens) 174.2 => 'Sigma 50-500mm f/4.5-6.3 APO DG OS HSM', #forum4031 174.3 => 'Sigma 150-500mm f/5-6.3 APO DG OS HSM', #47 174.4 => 'Zeiss Milvus 100mm f/2 Makro', #IB + 174.5 => 'Sigma APO 50-150mm f/2.8 EX DC OS HSM', #IB + 174.6 => 'Sigma APO 120-300mm f/2.8 EX DG OS HSM', #IB + 174.7 => 'Sigma 120-300mm f/2.8 DG OS HSM S013', #IB + 174.8 => 'Sigma 120-400mm f/4.5-5.6 APO DG OS HSM', #IB + 174.9 => 'Sigma 200-500mm f/2.8 APO EX DG', #IB 175 => 'Canon EF 400mm f/2.8L USM', #32 176 => 'Canon EF 24-85mm f/3.5-4.5 USM', 177 => 'Canon EF 300mm f/4L IS USM', #9 @@ -340,6 +375,8 @@ $VERSION = '4.02'; 180.6 => 'Sigma 24mm f/1.5 FF High-Speed Prime | 017', #IB 180.7 => 'Sigma 50mm f/1.5 FF High-Speed Prime | 017', #IB 180.8 => 'Sigma 85mm f/1.5 FF High-Speed Prime | 017', #IB + 180.9 => 'Tokina Opera 50mm f/1.4 FF', #IB + '180.10' => 'Sigma 20mm f/1.4 DG HSM | A', #IB (015) 181 => 'Canon EF 100-400mm f/4.5-5.6L IS USM + 1.4x or Sigma Lens', #15 181.1 => 'Sigma 150-600mm f/5-6.3 DG OS HSM | S + 1.4x', #50 182 => 'Canon EF 100-400mm f/4.5-5.6L IS USM + 2x or Sigma Lens', @@ -366,28 +403,32 @@ $VERSION = '4.02'; 195 => 'Canon EF 35-105mm f/4.5-5.6 USM', #32 196 => 'Canon EF 75-300mm f/4-5.6 USM', #15/32 197 => 'Canon EF 75-300mm f/4-5.6 IS USM or Sigma Lens', - 197.1 => 'Sigma 18-300mm f/3.5-6.3 DC Macro OS HS', #50 - 198 => 'Canon EF 50mm f/1.4 USM or Zeiss Lens', + 197.1 => 'Sigma 18-300mm f/3.5-6.3 DC Macro OS HSM', #50 + 198 => 'Canon EF 50mm f/1.4 USM or Other Lens', 198.1 => 'Zeiss Otus 55mm f/1.4 ZE', #JR (seen only on Sony camera) 198.2 => 'Zeiss Otus 85mm f/1.4 ZE', #JR (NC) 198.3 => 'Zeiss Milvus 25mm f/1.4', #IB + 198.4 => 'Zeiss Otus 100mm f/1.4', #IB + 198.5 => 'Zeiss Milvus 35mm f/1.4 ZE', #IB + 198.6 => 'Yongnuo YN 35mm f/2', #IB 199 => 'Canon EF 28-80mm f/3.5-5.6 USM', #32 200 => 'Canon EF 75-300mm f/4-5.6 USM', #32 201 => 'Canon EF 28-80mm f/3.5-5.6 USM', #32 202 => 'Canon EF 28-80mm f/3.5-5.6 USM IV', 208 => 'Canon EF 22-55mm f/4-5.6 USM', #32 - 209 => 'Canon EF 55-200mm f/4.5-5.6', #32 + 209 => 'Canon EF 55-200mm f/4.5-5.6', #32 (USM mk I version? ref IB) 210 => 'Canon EF 28-90mm f/4-5.6 USM', #32 211 => 'Canon EF 28-200mm f/3.5-5.6 USM', #15 212 => 'Canon EF 28-105mm f/4-5.6 USM', #15 213 => 'Canon EF 90-300mm f/4.5-5.6 USM or Tamron Lens', - 213.1 => 'Tamron SP 150-600mm f/5-6.3 Di VC USD', #topic5565 (model A011) - 213.2 => 'Tamron 16-300mm f/3.5-6.3 Di II VC PZD Macro', #PH (model B016) - 213.3 => 'Tamron SP 35mm f/1.8 Di VC USD', #PH (model F012) - 213.4 => 'Tamron SP 45mm f/1.8 Di VC USD', #PH (model F013) + 213.1 => 'Tamron SP 150-600mm f/5-6.3 Di VC USD (A011)', #forum5565 + 213.2 => 'Tamron 16-300mm f/3.5-6.3 Di II VC PZD Macro (B016)', #PH + 213.3 => 'Tamron SP 35mm f/1.8 Di VC USD (F012)', #PH + 213.4 => 'Tamron SP 45mm f/1.8 Di VC USD (F013)', #PH 214 => 'Canon EF-S 18-55mm f/3.5-5.6 USM', #PH/34 215 => 'Canon EF 55-200mm f/4.5-5.6 II USM', 217 => 'Tamron AF 18-270mm f/3.5-6.3 Di II VC PZD', #47 + 220 => 'Yongnuo YN 50mm f/1.8', #IB 224 => 'Canon EF 70-200mm f/2.8L IS USM', #11 225 => 'Canon EF 70-200mm f/2.8L IS USM + 1.4x', #11 226 => 'Canon EF 70-200mm f/2.8L IS USM + 2x', #14 @@ -395,7 +436,8 @@ $VERSION = '4.02'; 228 => 'Canon EF 28-105mm f/3.5-4.5 USM', #32 229 => 'Canon EF 16-35mm f/2.8L USM', #PH 230 => 'Canon EF 24-70mm f/2.8L USM', #9 - 231 => 'Canon EF 17-40mm f/4L USM', + 231 => 'Canon EF 17-40mm f/4L USM or Sigma Lens', + 231.1 => 'Sigma 12-24mm f/4 DG HSM A016', #IB 232 => 'Canon EF 70-300mm f/4.5-5.6 DO IS USM', #15 233 => 'Canon EF 28-300mm f/3.5-5.6L IS USM', #PH 234 => 'Canon EF-S 17-85mm f/4-5.6 IS USM or Tokina Lens', #19 @@ -419,22 +461,38 @@ $VERSION = '4.02'; 248.1 => 'Sigma 24-35mm f/2 DG HSM | A', #JR 248.2 => 'Sigma 135mm f/2 FF High-Speed Prime | 017', #IB 248.3 => 'Sigma 24-35mm f/2.2 FF Zoom | 017', #IB + 248.4 => 'Sigma 135mm f/1.8 DG HSM A017', #IB 249 => 'Canon EF 800mm f/5.6L IS USM', #35 250 => 'Canon EF 24mm f/1.4L II USM or Sigma Lens', #41 250.1 => 'Sigma 20mm f/1.4 DG HSM | A', #IB 250.2 => 'Sigma 20mm f/1.5 FF High-Speed Prime | 017', #IB + 250.3 => 'Tokina Opera 16-28mm f/2.8 FF', #IB + 250.4 => 'Sigma 85mm f/1.4 DG HSM A016', #IB 251 => 'Canon EF 70-200mm f/2.8L IS II USM', + 251.1 => 'Canon EF 70-200mm f/2.8L IS III USM', #IB 252 => 'Canon EF 70-200mm f/2.8L IS II USM + 1.4x', #50 (1.4x Mk II) + 252.1 => 'Canon EF 70-200mm f/2.8L IS III USM + 1.4x', #PH (NC) 253 => 'Canon EF 70-200mm f/2.8L IS II USM + 2x', #PH (NC) - # 253.1 => 'Tamron SP 70-200mm f/2.8 Di VC USD G2 (A025) + 2x', #forum9367 - 254 => 'Canon EF 100mm f/2.8L Macro IS USM', #42 - 255 => 'Sigma 24-105mm f/4 DG OS HSM | A or Other Sigma Lens', #50 + 253.1 => 'Canon EF 70-200mm f/2.8L IS III USM + 2x', #PH (NC) + # 253.2 => 'Tamron SP 70-200mm f/2.8 Di VC USD G2 (A025) + 2x', #forum9367 + 254 => 'Canon EF 100mm f/2.8L Macro IS USM or Tamron Lens', #42 + 254.1 => 'Tamron SP 90mm f/2.8 Di VC USD 1:1 Macro (F017)', #PH + 255 => 'Sigma 24-105mm f/4 DG OS HSM | A or Other Lens', #50 255.1 => 'Sigma 180mm f/2.8 EX DG OS HSM APO Macro', #50 + 255.2 => 'Tamron SP 70-200mm f/2.8 Di VC USD', #exiv issue 1202 (A009) 368 => 'Sigma 14-24mm f/2.8 DG HSM | A or other Sigma Lens', #IB (A018) 368.1 => 'Sigma 20mm f/1.4 DG HSM | A', #50 (newer firmware) 368.2 => 'Sigma 50mm f/1.4 DG HSM | A', #50 368.3 => 'Sigma 40mm f/1.4 DG HSM | A', #IB (018) 368.4 => 'Sigma 60-600mm f/4.5-6.3 DG OS HSM | S', #IB (018) + 368.5 => 'Sigma 28mm f/1.4 DG HSM | A', #IB (A019) + 368.6 => 'Sigma 150-600mm f/5-6.3 DG OS HSM | S', #50 + 368.7 => 'Sigma 85mm f/1.4 DG HSM | A', #IB (016) + 368.8 => 'Sigma 105mm f/1.4 DG HSM', #IB (A018) + 368.9 => 'Sigma 14-24mm f/2.8 DG HSM', #IB (A018) + '368.10' => 'Sigma 35mm f/1.4 DG HSM | A', #PH (012) + '368.11' => 'Sigma 70mm f/2.8 DG Macro', #IB (A018) + '368.12' => 'Sigma 18-35mm f/1.8 DC HSM | A', #50 # Note: LensType 488 (0x1e8) is reported as 232 (0xe8) in 7D CameraSettings 488 => 'Canon EF-S 15-85mm f/3.5-5.6 IS USM', #PH 489 => 'Canon EF 70-300mm f/4-5.6L IS USM', #Gerald Kapounek @@ -451,24 +509,29 @@ $VERSION = '4.02'; 493.1 => 'Canon EF 24-105mm f/4L IS USM', #PH (should recheck this) 494 => 'Canon EF 600mm f/4L IS II USM', #PH 495 => 'Canon EF 24-70mm f/2.8L II USM or Sigma Lens', #PH - 495.1 => 'Sigma 24-70mm F2.8 DG OS HSM | A', #IB (017) + 495.1 => 'Sigma 24-70mm f/2.8 DG OS HSM | A', #IB (017) 496 => 'Canon EF 200-400mm f/4L IS USM', #PH 499 => 'Canon EF 200-400mm f/4L IS USM + 1.4x', #50 - 502 => 'Canon EF 28mm f/2.8 IS USM', #PH + 502 => 'Canon EF 28mm f/2.8 IS USM or Tamron Lens', #PH + 502.1 => 'Tamron 35mm f/1.8 Di VC USD (F012)', #forum9757 503 => 'Canon EF 24mm f/2.8 IS USM', #PH 504 => 'Canon EF 24-70mm f/4L IS USM', #PH 505 => 'Canon EF 35mm f/2 IS USM', #PH 506 => 'Canon EF 400mm f/4 DO IS II USM', #42 507 => 'Canon EF 16-35mm f/4L IS USM', #42 508 => 'Canon EF 11-24mm f/4L USM or Tamron Lens', #PH - 508.1 => 'Tamron 10-24mm f/3.5-4.5 Di II VC HLD', #PH (B023) + 508.1 => 'Tamron 10-24mm f/3.5-4.5 Di II VC HLD (B023)', #PH + 624 => 'Sigma 70-200mm f/2.8 DG OS HSM | S or other Sigma Lens', #IB (018) + 624.1 => 'Sigma 150-600mm f/5-6.3 | C', #ChrisSkopec 747 => 'Canon EF 100-400mm f/4.5-5.6L IS II USM or Tamron Lens', #JR 747.1 => 'Tamron SP 150-600mm f/5-6.3 Di VC USD G2', #50 748 => 'Canon EF 100-400mm f/4.5-5.6L IS II USM + 1.4x or Tamron Lens', #JR (1.4x Mk III) 748.1 => 'Tamron 100-400mm f/4.5-6.3 Di VC USD A035E + 1.4x', #IB 748.2 => 'Tamron 70-210mm f/4 Di VC USD (A034) + 2x', #IB 749 => 'Tamron 100-400mm f/4.5-6.3 Di VC USD A035E + 2x', #IB - 750 => 'Canon EF 35mm f/1.4L II USM', #42 + 750 => 'Canon EF 35mm f/1.4L II USM or Tamron Lens', #42 + 750.1 => 'Tamron SP 85mm f/1.8 Di VC USD (F016)', #Exiv2#1072 + 750.2 => 'Tamron SP 45mm f/1.8 Di VC USD (F013)', #PH 751 => 'Canon EF 16-35mm f/2.8L III USM', #42 752 => 'Canon EF 24-105mm f/4L IS II USM', #42 753 => 'Canon EF 85mm f/1.4L IS USM', #42 @@ -476,7 +539,7 @@ $VERSION = '4.02'; 757 => 'Canon EF 400mm f/2.8L IS III USM', #IB 758 => 'Canon EF 600mm f/4L IS III USM', #IB - 1136 => 'Sigma 24-70mm f/2.8 DG OS HSM | Art 017', #IB + 1136 => 'Sigma 24-70mm f/2.8 DG OS HSM | A', #IB (017) # (STM lenses - 0x10xx) 4142 => 'Canon EF-S 18-135mm f/3.5-5.6 IS STM', 4143 => 'Canon EF-M 18-55mm f/3.5-5.6 IS STM or Tamron Lens', @@ -493,9 +556,12 @@ $VERSION = '4.02'; 4154 => 'Canon EF-S 24mm f/2.8 STM', #IB 4155 => 'Canon EF-M 28mm f/3.5 Macro IS STM', #42 4156 => 'Canon EF 50mm f/1.8 STM', #42 - 4157 => 'Canon EF-M 18-150mm 1:3.5-6.3 IS STM', #42 + 4157 => 'Canon EF-M 18-150mm f/3.5-6.3 IS STM', #42 4158 => 'Canon EF-S 18-55mm f/4-5.6 IS STM', #PH + 4159 => 'Canon EF-M 32mm f/1.4 STM', #42 4160 => 'Canon EF-S 35mm f/2.8 Macro IS STM', #42 + 4208 => 'Sigma 56mm f/1.4 DC DN | C or other Sigma Lens', #forum10603 + 4208.1 => 'Sigma 30mm F1.4 DC DN | C', #git issue#83 (016) # (Nano USM lenses - 0x90xx) 36910 => 'Canon EF 70-300mm f/4-5.6 IS II USM', #42 36912 => 'Canon EF-S 18-135mm f/3.5-5.6 IS USM', #42 @@ -506,10 +572,50 @@ $VERSION = '4.02'; 61494 => 'Canon CN-E 85mm T1.3 L F', #PH 61495 => 'Canon CN-E 135mm T2.2 L F', #PH 61496 => 'Canon CN-E 35mm T1.5 L F', #PH - 61182 => 'Canon RF 35mm F1.8 Macro IS STM or other Canon RF Lens', #IB - 61182.1 => 'Canon RF 50mm F1.2 L USM', #IB - 61182.2 => 'Canon RF 24-105mm F4 L IS USM', #IB - 61182.3 => 'Canon RF 28-70mm F2 L USM', #IB +# +# see RFLensType tag for master list of 61182 RF lenses +# + 61182 => 'Canon RF 50mm F1.2L USM or other Canon RF Lens', + 61182.1 => 'Canon RF 24-105mm F4L IS USM', + 61182.2 => 'Canon RF 28-70mm F2L USM', + 61182.3 => 'Canon RF 35mm F1.8 MACRO IS STM', + 61182.4 => 'Canon RF 85mm F1.2L USM', + 61182.5 => 'Canon RF 85mm F1.2L USM DS', + 61182.6 => 'Canon RF 24-70mm F2.8L IS USM', + 61182.7 => 'Canon RF 15-35mm F2.8L IS USM', + 61182.8 => 'Canon RF 24-240mm F4-6.3 IS USM', + 61182.9 => 'Canon RF 70-200mm F2.8L IS USM', + '61182.10' => 'Canon RF 85mm F2 MACRO IS STM', + '61182.11' => 'Canon RF 600mm F11 IS STM', + '61182.12' => 'Canon RF 600mm F11 IS STM + RF1.4x', + '61182.13' => 'Canon RF 600mm F11 IS STM + RF2x', + '61182.14' => 'Canon RF 800mm F11 IS STM', + '61182.15' => 'Canon RF 800mm F11 IS STM + RF1.4x', + '61182.16' => 'Canon RF 800mm F11 IS STM + RF2x', + '61182.17' => 'Canon RF 24-105mm F4-7.1 IS STM', + '61182.18' => 'Canon RF 100-500mm F4.5-7.1L IS USM', + '61182.19' => 'Canon RF 100-500mm F4.5-7.1L IS USM + RF1.4x', + '61182.20' => 'Canon RF 100-500mm F4.5-7.1L IS USM + RF2x', + '61182.21' => 'Canon RF 70-200mm F4L IS USM', #42 + '61182.22' => 'Canon RF 100mm F2.8L MACRO IS USM', #42 + '61182.23' => 'Canon RF 50mm F1.8 STM', #42 + '61182.24' => 'Canon RF 14-35mm F4L IS USM', #IB + '61182.25' => 'Canon RF-S 18-45mm F4.5-6.3 IS STM', #42 + '61182.26' => 'Canon RF 100-400mm F5.6-8 IS USM', #42 + '61182.27' => 'Canon RF 100-400mm F5.6-8 IS USM + RF1.4x', #42 (NC) + '61182.28' => 'Canon RF 100-400mm F5.6-8 IS USM + RF2x', #42 (NC) + '61182.29' => 'Canon RF-S 18-150mm F3.5-6.3 IS STM', #42 + '61182.30' => 'Canon RF 24mm F1.8 MACRO IS STM', #42 + '61182.31' => 'Canon RF 16mm F2.8 STM', #42 + '61182.32' => 'Canon RF 400mm F2.8L IS USM', #IB + '61182.33' => 'Canon RF 400mm F2.8L IS USM + RF1.4x', #IB + '61182.34' => 'Canon RF 400mm F2.8L IS USM + RF2x', #IB + '61182.35' => 'Canon RF 600mm F4L IS USM', #GiaZopatti + '61182.36' => 'Canon RF 15-30mm F4.5-6.3 IS STM', #42 + # we need the RFLensType values for the following... + '61182.37' => 'Canon RF 800mm F5.6L IS USM', #PH (NC) + '61182.38' => 'Canon RF 1200mm F8L IS USM', #PH (NC) + '61182.39' => 'Canon RF 5.2mm F2.8L Dual Fisheye 3D VR', #PH (NC) 65535 => 'n/a', ); @@ -683,6 +789,7 @@ $VERSION = '4.02'; 0x3260000 => 'PowerShot A3400 IS', 0x3270000 => 'PowerShot A2400 IS', 0x3280000 => 'PowerShot A2300', + 0x3320000 => 'PowerShot S100V', #IB 0x3330000 => 'PowerShot G15', #25 0x3340000 => 'PowerShot SX50 HS', #25/forum8196 0x3350000 => 'PowerShot SX160 IS', @@ -741,7 +848,7 @@ $VERSION = '4.02'; 0x4020000 => 'PowerShot SX420 IS', 0x4030000 => 'PowerShot ELPH 190 IS / IXUS 180 / IXY 190', 0x4040000 => 'PowerShot G1', - 0x4040001 => 'IXY 180', # ?? (from Canon sample) + 0x4040001 => 'PowerShot ELPH 180 IS / IXUS 175 / IXY 180', #forum10402 0x4050000 => 'PowerShot SX720 HS', 0x4060000 => 'PowerShot SX620 HS', 0x4070000 => 'EOS M6', @@ -753,7 +860,11 @@ $VERSION = '4.02'; 0x4180000 => 'PowerShot G1 X Mark III', #IB 0x6040000 => 'PowerShot S100 / Digital IXUS / IXY Digital', 0x801 => 'PowerShot SX740 HS', + 0x804 => 'PowerShot G5 X Mark II', 0x805 => 'PowerShot SX70 HS', + 0x808 => 'PowerShot G7 X Mark III', + 0x811 => 'EOS M6 Mark II', #IB + 0x812 => 'EOS M200', #25 # (see http://cweb.canon.jp/e-support/faq/answer/digitalcamera/10447-1.html for PowerShot/IXUS/IXY names) @@ -835,7 +946,7 @@ $VERSION = '4.02'; 0x80000325 => 'EOS 70D', 0x80000326 => 'EOS Rebel T5i / 700D / Kiss X7i', 0x80000327 => 'EOS Rebel T5 / 1200D / Kiss X70 / Hi', - 0x80000328 => 'EOS-1D X MARK II', #42 + 0x80000328 => 'EOS-1D X Mark II', #42 0x80000331 => 'EOS M', 0x80000350 => 'EOS 80D', #42 0x80000355 => 'EOS M2', @@ -850,9 +961,23 @@ $VERSION = '4.02'; 0x80000406 => 'EOS 6D Mark II', #IB/42 0x80000408 => 'EOS 77D / 9000D', 0x80000417 => 'EOS Rebel SL2 / 200D / Kiss X9', #IB/42 + 0x80000421 => 'EOS R5', #PH 0x80000422 => 'EOS Rebel T100 / 4000D / 3000D', #IB (3000D in China; Kiss? - PH) - 0x80000424 => 'EOR R', #IB + 0x80000424 => 'EOS R', #IB + 0x80000428 => 'EOS-1D X Mark III', #IB 0x80000432 => 'EOS Rebel T7 / 2000D / 1500D / Kiss X90', #IB + 0x80000433 => 'EOS RP', + 0x80000435 => 'EOS Rebel T8i / 850D / X10i', #JR/PH + 0x80000436 => 'EOS SL3 / 250D / Kiss X10', #25 + 0x80000437 => 'EOS 90D', #IB + 0x80000450 => 'EOS R3', #42 + 0x80000453 => 'EOS R6', #PH + 0x80000464 => 'EOS R7', #42 + 0x80000465 => 'EOS R10', #42 + 0x80000467 => 'PowerShot ZOOM', + 0x80000468 => 'EOS M50 Mark II / Kiss M2', #IB + 0x80000520 => 'EOS D2000C', #IB + 0x80000560 => 'EOS D6000C', #PH (guess) ); my %canonQuality = ( @@ -863,8 +988,8 @@ my %canonQuality = ( 4 => 'RAW', 5 => 'Superfine', 7 => 'CRAW', #42 - 130 => 'Normal Movie', #22 - 131 => 'Movie (2)', #PH (7DmkII 1920x1080) + 130 => 'Light (RAW)', #github#119 + 131 => 'Standard (RAW)', #github#119 ); my %canonImageSize = ( -1 => 'n/a', @@ -911,7 +1036,7 @@ my %canonWhiteBalance = ( 20 => 'PC Set4', #PH 21 => 'PC Set5', #PH # 22 - Custom 2? - 23 => 'Auto (ambience priority)', #PH (5DS) + 23 => 'Auto (ambience priority)', #PH (5DS) (perhaps this needs re-thinking?: forum13295) # 30 - Click White Balance? # 31 - Shot Settings? # 137 - Tungsten? @@ -1520,7 +1645,10 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); ValueConv => 'unpack("H*", $val)', ValueConvInv => 'pack("H*", $val)', }, - # 0x29 - WBInfo (ref IB, offset 0x6 is int32u[4] WB_GRBGLevels as shot for PowerShot G9) + 0x29 => { #IB (G9) + Name => 'WBInfo', + SubDirectory => { TagTable => 'Image::ExifTool::Canon::WBInfo' }, + }, # 0x2d - changes with categories (ref 31) 0x2f => { #PH (G12) Name => 'FaceDetect3', @@ -1529,6 +1657,8 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); TagTable => 'Image::ExifTool::Canon::FaceDetect3', }, }, + # 0x32 - if length is 768, starting at offset 4 there are 6 RGGB 1/val int16 records: + # daylight,cloudy,tungsten,fluorescent,flash,kelvin (D30 2001, ref IB) 0x35 => { #PH Name => 'TimeInfo', SubDirectory => { @@ -1719,6 +1849,7 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); PrintConv => { 1 => 'sRGB', 2 => 'Adobe RGB', + 65535 => 'n/a', }, }, 0xb6 => { @@ -1796,11 +1927,21 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); Name => 'ColorData8', SubDirectory => { TagTable => 'Image::ExifTool::Canon::ColorData8' }, }, - { # (int16u[1820]) - M50, ref PH - Condition => '$count == 1820', + { # (int16u[1816|1820|1824]) - M50 (1820) ref PH, EOS R (1824), EOS RP, SX70 (1816) ref IB + Condition => '$count == 1816 or $count == 1820 or $count == 1824', Name => 'ColorData9', SubDirectory => { TagTable => 'Image::ExifTool::Canon::ColorData9' }, }, + { # (int16u[2024|3656]) - 1DXmkIII (2024) ref IB, R5/R6 (3656) ref PH + Condition => '$count == 2024 or $count == 3656', + Name => 'ColorData10', + SubDirectory => { TagTable => 'Image::ExifTool::Canon::ColorData10' }, + }, + { # (int16u[3973]) - R3 ref IB + Condition => '$count == 3973', + Name => 'ColorData11', + SubDirectory => { TagTable => 'Image::ExifTool::Canon::ColorData11' }, + }, { Name => 'ColorDataUnknown', SubDirectory => { TagTable => 'Image::ExifTool::Canon::ColorDataUnknown' }, @@ -1825,7 +1966,7 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); }, 0x4008 => { #53 Name => 'PictureStyleUserDef', # (BasePictStyleOfUser) - Format => 'int16u', + Writable => 'int16u', Count => 3, # UserDef1, UserDef2, UserDef3 PrintHex => 1, SeparateTable => 'PictureStyle', @@ -1833,7 +1974,7 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); }, 0x4009 => { #53 Name => 'PictureStylePC', # (BasePictStyleOfUser) - Format => 'int16u', + Writable => 'int16u', Count => 3, # PC1, PC2, PC3 PrintHex => 1, SeparateTable => 'PictureStyle', @@ -1930,6 +2071,13 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); TagTable => 'Image::ExifTool::Canon::HDRInfo', } }, + 0x4026 => { #github#119 + Name => 'LogInfo', + SubDirectory => { + Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)', + TagTable => 'Image::ExifTool::Canon::LogInfo', + } + }, 0x4028 => { #PH Name => 'AFConfig', # (AFTabInfo) SubDirectory => { @@ -1937,6 +2085,13 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); TagTable => 'Image::ExifTool::Canon::AFConfig', } }, + 0x403f => { #25 + Name => 'RawBurstModeRoll', + SubDirectory => { + Validate => 'Image::ExifTool::Canon::Validate($dirData,$subdirStart,$size)', + TagTable => 'Image::ExifTool::Canon::RawBurstInfo', + } + }, ); #.............................................................................. @@ -1975,7 +2130,7 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); 4 => { Name => 'CanonFlashMode', PrintConv => { - -1 => "n/a", # (PH, EOS M MOV video) + -1 => 'n/a', # (PH, EOS M MOV video) 0 => 'Off', 1 => 'Auto', 2 => 'On', @@ -1996,7 +2151,8 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); 4 => 'Continuous, Low', #PH 5 => 'Continuous, High', #PH 6 => 'Silent Single', #PH - # ref A: http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,5701.msg27843.html#msg27843 + 8 => 'Continuous, High+', #WolfgangGulcker + # ref A: https://exiftool.org/forum/index.php/topic,5701.msg27843.html#msg27843 9 => 'Single, Silent', #A 10 => 'Continuous, Silent', #A # 11 - seen for SX260 @@ -2016,6 +2172,7 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); 16 => 'Pan Focus', #PH # 137 - Single? 256 => 'AF + MF', #PH (NC, EOS M) + 257 => 'Live View', #forum12082 512 => 'Movie Snap Focus', #48 519 => 'Movie Servo AF', #PH (NC, EOS M) }, @@ -2036,6 +2193,8 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); 11 => 'CRM', #PH (C200 CRM) 12 => 'CR3', #PH (EOS R) 13 => 'CR3+JPEG', #PH (EOS R) + 14 => 'HIF', #PH (NC) + 15 => 'CR3+HIF', #PH (1DXmkIII) }, }, 10 => { @@ -2114,6 +2273,11 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); 60 => 'High-speed Burst HQ', #PH (C='High-speed Burst HQ', same as 59) 61 => 'Smooth Skin', #51 62 => 'Soft Focus', #PH (SX260,IXUS240) + 68 => 'Food', #PH (250D) + # 83 - seen for EOS M200 (ref PH) + 84 => 'HDR Art Standard', #PH (80D) + 85 => 'HDR Art Vivid', #PH (80D) + 93 => 'HDR Art Bold', #PH (80D) # 83 - seen for EOS M3 night shot (PH) 257 => 'Spotlight', #PH 258 => 'Night 2', #PH @@ -2214,6 +2378,7 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); 5 => 'Depth-of-field AE', 6 => 'M-Dep', #PH 7 => 'Bulb', #30 + 8 => 'Flexible-priority AE', #ArnoldVanOostrum }, }, 22 => { #4 @@ -4418,6 +4583,16 @@ my %ciMaxFocal = ( 2 => 'Rotate 270 CW', }, }, + 0x3a => { #IB + Name => 'CameraOrientation', + Condition => '$$self{Model} =~ /\b(1200D|REBEL T5|Kiss X70)\b/', + Notes => '1200D only', + PrintConv => { + 0 => 'Horizontal (normal)', + 1 => 'Rotate 90 CW', + 2 => 'Rotate 270 CW', + }, + }, 0x55 => { Name => 'FocusDistanceUpper', Condition => '$$self{Model} =~ /EOS 60D$/', @@ -4558,7 +4733,7 @@ my %ciMaxFocal = ( FIRST_ENTRY => 0, PRIORITY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, - NOTES => 'CameraInfo tags for the EOS 70D.', + NOTES => 'CameraInfo tags for the EOS 80D.', 0x03 => { %ciFNumber }, 0x04 => { %ciExposureTime }, 0x06 => { %ciISO }, @@ -5134,6 +5309,14 @@ my %ciMaxFocal = ( 0x06 => { %ciISO }, 0x1b => { %ciCameraTemperature }, # (700D + 0) 0x23 => { %ciFocalLength }, # (700D + 0) + 0x96 => { #IB (700D + 0x19) + Name => 'CameraOrientation', + PrintConv => { + 0 => 'Horizontal (normal)', + 1 => 'Rotate 90 CW', + 2 => 'Rotate 270 CW', + }, + }, 0xa5 => { # (700D + 0x19) Name => 'FocusDistanceUpper', %focusDistanceByteSwap, @@ -5565,6 +5748,13 @@ my %ciMaxFocal = ( ValueConv => 'unpack("H*",$val)', ValueConvInv => 'length($val) < 10 and $val = 0 x (10-length($val)) . $val; pack("H*",$val)', }, + 0x5c1 => { + Name => 'FirmwareVersion', + Format => 'string[6]', + Writable => 0, + Condition => '$$valPt =~ /^\d\.\d\.\d\0/', + Notes => 'M50', # (firmware 1.0.0) + }, ); # Picture Style information for various cameras (ref 48) @@ -6075,8 +6265,8 @@ my %ciMaxFocal = ( 8 => 'AF Point Expansion (4 point)', #46/PH/forum6237 9 => 'Spot AF', #46 10 => 'AF Point Expansion (8 point)', #forum6237 - 11 => 'Flexizone Multi', #PH (NC, EOS M, live view) - # 12 - also "Flexizone Multi"? (PH) + 11 => 'Flexizone Multi (49 point)', #PH (NC, EOS M, live view; 750D 49 points) + 12 => 'Flexizone Multi (9 point)', #PH (750D, 9 points) 13 => 'Flexizone Single', #PH (EOS M default, live view) 14 => 'Large Zone AF', #PH/forum6237 (7DmkII) }, @@ -6159,7 +6349,7 @@ my %ciMaxFocal = ( # DPP shows "On" for any value except 0xffff when bit 0x08 is set my ($val, $inv) = @_; if ($inv) { - $val =~ /(0x[0-9a-f]+)/i or $val =~ /(\d+)/; + $val =~ /(0x[0-9a-f]+)/i or $val =~ /(\d+)/ or return undef; return $1; } else { return sprintf("On (0x%.2x)",$val) if $val & 0x08; @@ -6346,6 +6536,25 @@ my %ciMaxFocal = ( 0x02 => 'FacesDetected', ); +# G9 white balance information (MakerNotes tag 0x29) (ref IB, changed ref forum13640) +%Image::ExifTool::Canon::WBInfo = ( + %binaryDataAttrs, + NOTES => 'WB tags for the Canon G9.', + FORMAT => 'int32u', + FIRST_ENTRY => 1, + GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + 0x02 => { Name => 'WB_GRBGLevelsAuto', Format => 'int32s[4]' }, + 0x0a => { Name => 'WB_GRBGLevelsDaylight', Format => 'int32s[4]' }, + 0x12 => { Name => 'WB_GRBGLevelsCloudy', Format => 'int32s[4]' }, + 0x1a => { Name => 'WB_GRBGLevelsTungsten', Format => 'int32s[4]' }, + 0x22 => { Name => 'WB_GRBGLevelsFluorescent', Format => 'int32s[4]' }, + 0x2a => { Name => 'WB_GRBGLevelsFluorHigh', Format => 'int32s[4]' }, + 0x32 => { Name => 'WB_GRBGLevelsFlash', Format => 'int32s[4]' }, + 0x3a => { Name => 'WB_GRBGLevelsUnderwater', Format => 'int32s[4]' }, + 0x42 => { Name => 'WB_GRBGLevelsCustom1', Format => 'int32s[4]' }, + 0x4a => { Name => 'WB_GRBGLevelsCustom2', Format => 'int32s[4]' }, +); + # yet more face detect information (MakerNotes tag 0x2f) - PH (G12) %Image::ExifTool::Canon::FaceDetect3 = ( %binaryDataAttrs, @@ -6558,11 +6767,66 @@ my %ciMaxFocal = ( PrintConvInv => '$val =~ s/ ?m$//; IsFloat($val) ? $val : 655.35', }, # 22 - values: 0, 1 - # 23 - values: 0, 21, 22 + 23 => { #JohnMoyer (forum12925) + Name => 'ShutterMode', + PrintConv => { + 0 => 'Mechanical', + 1 => 'Electronic First Curtain', + 2 => 'Electronic', + # 3 => ? + # 21 => ? + # 22 => ? + }, + }, 25 => { #PH Name => 'FlashExposureLock', PrintConv => \%offOn, }, + 0x3d => { #IB + Name => 'RFLensType', + Format => 'int16u', + PrintConv => { + 0 => 'n/a', + 257 => 'Canon RF 50mm F1.2L USM', + 258 => 'Canon RF 24-105mm F4L IS USM', + 259 => 'Canon RF 28-70mm F2L USM', + 260 => 'Canon RF 35mm F1.8 MACRO IS STM', + 261 => 'Canon RF 85mm F1.2L USM', + 262 => 'Canon RF 85mm F1.2L USM DS', + 263 => 'Canon RF 24-70mm F2.8L IS USM', + 264 => 'Canon RF 15-35mm F2.8L IS USM', + 265 => 'Canon RF 24-240mm F4-6.3 IS USM', + 266 => 'Canon RF 70-200mm F2.8L IS USM', + 267 => 'Canon RF 85mm F2 MACRO IS STM', + 268 => 'Canon RF 600mm F11 IS STM', + 269 => 'Canon RF 600mm F11 IS STM + RF1.4x', + 270 => 'Canon RF 600mm F11 IS STM + RF2x', + 271 => 'Canon RF 800mm F11 IS STM', + 272 => 'Canon RF 800mm F11 IS STM + RF1.4x', + 273 => 'Canon RF 800mm F11 IS STM + RF2x', + 274 => 'Canon RF 24-105mm F4-7.1 IS STM', + 275 => 'Canon RF 100-500mm F4.5-7.1L IS USM', + 276 => 'Canon RF 100-500mm F4.5-7.1L IS USM + RF1.4x', + 277 => 'Canon RF 100-500mm F4.5-7.1L IS USM + RF2x', + 278 => 'Canon RF 70-200mm F4L IS USM', #42 + 279 => 'Canon RF 100mm F2.8L MACRO IS USM', #42 + 280 => 'Canon RF 50mm F1.8 STM', #42 + 281 => 'Canon RF 14-35mm F4L IS USM', #42/IB + 282 => 'Canon RF-S 18-45mm F4.5-6.3 IS STM', #42 + 283 => 'Canon RF 100-400mm F5.6-8 IS USM', #42 + 284 => 'Canon RF 100-400mm F5.6-8 IS USM + RF1.4x', #42 (NC) + 285 => 'Canon RF 100-400mm F5.6-8 IS USM + RF2x', #42 (NC) + 286 => 'Canon RF-S 18-150mm F3.5-6.3 IS STM', #42 + 287 => 'Canon RF 24mm F1.8 MACRO IS STM', #42 + 288 => 'Canon RF 16mm F2.8 STM', #42 + 289 => 'Canon RF 400mm F2.8L IS USM', #IB + 290 => 'Canon RF 400mm F2.8L IS USM + RF1.4x', #IB + 291 => 'Canon RF 400mm F2.8L IS USM + RF2x', #IB + 292 => 'Canon RF 600mm F4L IS USM', #GiaZopatti + 302 => 'Canon RF 15-30mm F4.5-6.3 IS STM', #42 + # Note: add new RF lenses to %canonLensTypes with ID 61182 + }, + }, ); # Internal serial number information (MakerNotes tag 0x96) (ref PH) @@ -6602,6 +6866,9 @@ my %ciMaxFocal = ( 2 => '4:3', 7 => '16:9', 8 => '4:5', + 12 => '3:2 (APS-H crop)', #IB + 13 => '3:2 (APS-C crop)', #IB + 258 => '4:3 crop', #PH (NC) }, }, # (could use better names for these, or the Crop tags above, or both) @@ -6689,7 +6956,15 @@ my %ciMaxFocal = ( 17 => { Name => 'WB_RGGBLevelsTungsten', Format => 'int16s[4]' }, 21 => { Name => 'WB_RGGBLevelsFluorescent',Format => 'int16s[4]' }, 25 => { Name => 'WB_RGGBLevelsFlash', Format => 'int16s[4]' }, - 29 => { Name => 'WB_RGGBLevelsCustom', Format => 'int16s[4]' }, # (actually black levels for D60, ref IB) + 29 => [{ + Name => 'WB_RGGBLevelsCustom', + Notes => 'black levels for the D60', + Condition => '$$self{Model} !~ /EOS D60\b/', + Format => 'int16s[4]', + },{ # (black levels for D60, ref IB) + Name => 'BlackLevels', + Format => 'int16s[4]', + }], 33 => { Name => 'WB_RGGBLevelsKelvin', Format => 'int16s[4]' }, 37 => { Name => 'WB_RGGBBlackLevels', Format => 'int16s[4]' }, #IB ); @@ -7287,7 +7562,7 @@ my %ciMaxFocal = ( NOTES => q{ Camera color calibration data. For the 20D, 350D, 1DmkII and 1DSmkII the order of the coefficients is A, B, C, Temperature, but for newer models it - is B, C, A, Temperature. These tags are extracted only when the Unknown + is B, C, A, Temperature. These tags are extracted only when the L<Unknown|../ExifTool.html#Unknown> option is used. }, 0x00 => { Name => 'CameraColorCalibration01', %cameraColorCalibration }, @@ -7384,6 +7659,16 @@ my %ciMaxFocal = ( Condition => '$$self{ColorDataVersion} == -4', Format => 'int16s[4]', }, + 0x0569 => { #PH (NC) + Name => 'NormalWhiteLevel', + Condition => '$$self{ColorDataVersion} == -4', + Format => 'int16u', + }, + 0x056a => { #PH (NC) + Name => 'SpecularWhiteLevel', + Condition => '$$self{ColorDataVersion} == -4', + Format => 'int16u', + }, ); # Color data (MakerNotes tag 0x4001, count=1273|1275) (ref PH) @@ -7475,7 +7760,10 @@ my %ciMaxFocal = ( # Color data (MakerNotes tag 0x4001, count=1312,1313,1316) (ref PH) %Image::ExifTool::Canon::ColorData7 = ( %binaryDataAttrs, - NOTES => 'These tags are used by the EOS 1DX, 5DmkIII, 6D, 100D, 650D, 700D, M and 7DmkII.', + NOTES => q{ + These tags are used by the EOS 1DX, 5DmkIII, 6D, 7DmkII, 100D, 650D, 700D, + 8000D, M and M2. + }, FORMAT => 'int16s', FIRST_ENTRY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, @@ -7486,8 +7774,8 @@ my %ciMaxFocal = ( DataMember => 'ColorDataVersion', RawConv => '$$self{ColorDataVersion} = $val', PrintConv => { - 10 => '10 (1DX/5DmkIII/6D/70D/100D/650D/700D/M)', - 11 => '11 (7DmkII/750D/760D)', + 10 => '10 (1DX/5DmkIII/6D/70D/100D/650D/700D/M/M2)', + 11 => '11 (7DmkII/750D/760D/8000D)', }, }, # not really sure about the AsShot, Auto and Measured values any more - PH @@ -7622,6 +7910,10 @@ my %ciMaxFocal = ( # Color data (MakerNotes tag 0x4001, count=1560,etc) (ref IB) %Image::ExifTool::Canon::ColorData8 = ( %binaryDataAttrs, + NOTES => q{ + These tags are used by the EOS 1DXmkII, 5DS, 5DSR, 5DmkIV, 6DmkII, 77D, 80D, + 200D, 800D, 1300D, 2000D, 4000D and 9000D. + }, FORMAT => 'int16s', FIRST_ENTRY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, @@ -7632,10 +7924,10 @@ my %ciMaxFocal = ( DataMember => 'ColorDataVersion', RawConv => '$$self{ColorDataVersion} = $val', PrintConv => { - 12 => '12 (5DS/5DSR)', - 13 => '13 (80D)', #PH + 12 => '12 (1DXmkII/5DS/5DSR)', + 13 => '13 (80D/5DmkIV)', #PH 14 => '14 (1300D/2000D/4000D)', #IB - 15 => '15 (6DmkII/77D/200D/800D)', #IB + 15 => '15 (6DmkII/77D/200D/800D,9000D)', #IB }, }, 0x3f => { Name => 'WB_RGGBLevelsAsShot', Format => 'int16s[4]' }, @@ -7779,9 +8071,10 @@ my %ciMaxFocal = ( }, ); -# Color data (MakerNotes tag 0x4001, count=1820) (ref PH) +# Color data (MakerNotes tag 0x4001, count=1820,etc) (ref PH) %Image::ExifTool::Canon::ColorData9 = ( %binaryDataAttrs, + NOTES => 'These tags are used by the M6mkII, M50, M200, EOS R, RP, 90D, 250D and 850D', FORMAT => 'int16s', FIRST_ENTRY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, @@ -7793,6 +8086,9 @@ my %ciMaxFocal = ( RawConv => '$$self{ColorDataVersion} = $val', PrintConv => { 16 => '16 (M50)', + 17 => '17 (EOS R)', # (and PowerShot SX740HS) + 18 => '18 (EOS RP/250D)', # (and PowerShot SX70HS) + 19 => '19 (90D/850D/M6mkII/M200)',# (and PowerShot G7XmkIII) }, }, 0x47 => { Name => 'WB_RGGBLevelsAsShot', Format => 'int16s[4]' }, @@ -7882,7 +8178,6 @@ my %ciMaxFocal = ( 0x149 => { #IB Name => 'PerChannelBlackLevel', Format => 'int16u[4]', - Notes => '1300D', }, # 0x318 - PerChannelBlackLevel again (ref IB) 0x31c => { #IB @@ -7900,6 +8195,248 @@ my %ciMaxFocal = ( }, ); +# Color data (MakerNotes tag 0x4001, count=2024,3656) +# (same as ColorData9 but shifted up by 0x0e, ref PH) +%Image::ExifTool::Canon::ColorData10 = ( + %binaryDataAttrs, + NOTES => 'These tags are used by the R5, R5 and EOS 1DXmkIII.', + FORMAT => 'int16s', + FIRST_ENTRY => 0, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + DATAMEMBER => [ 0 ], + IS_SUBDIR => [ 0x118 ], + 0x00 => { + Name => 'ColorDataVersion', + DataMember => 'ColorDataVersion', + RawConv => '$$self{ColorDataVersion} = $val', + PrintConv => { + 32 => '32 (1DXmkIII)', #IB + 33 => '33 (R5/R6)', + }, + }, + 0x55 => { Name => 'WB_RGGBLevelsAsShot', Format => 'int16s[4]' }, + 0x59 => 'ColorTempAsShot', + 0x5a => { Name => 'WB_RGGBLevelsAuto', Format => 'int16s[4]' }, + 0x5e => 'ColorTempAuto', + 0x5f => { Name => 'WB_RGGBLevelsMeasured', Format => 'int16s[4]' }, + 0x63 => 'ColorTempMeasured', + 0x64 => { Name => 'WB_RGGBLevelsUnknown', Format => 'int16s[4]', Unknown => 1 }, + 0x68 => { Name => 'ColorTempUnknown', Unknown => 1 }, + 0x69 => { Name => 'WB_RGGBLevelsUnknown2', Format => 'int16s[4]', Unknown => 1 }, + 0x6d => { Name => 'ColorTempUnknown2', Unknown => 1 }, + 0x6e => { Name => 'WB_RGGBLevelsUnknown3', Format => 'int16s[4]', Unknown => 1 }, + 0x72 => { Name => 'ColorTempUnknown3', Unknown => 1 }, + 0x73 => { Name => 'WB_RGGBLevelsUnknown4', Format => 'int16s[4]', Unknown => 1 }, + 0x77 => { Name => 'ColorTempUnknown4', Unknown => 1 }, + 0x78 => { Name => 'WB_RGGBLevelsUnknown5', Format => 'int16s[4]', Unknown => 1 }, + 0x7c => { Name => 'ColorTempUnknown5', Unknown => 1 }, + 0x7d => { Name => 'WB_RGGBLevelsUnknown6', Format => 'int16s[4]', Unknown => 1 }, + 0x81 => { Name => 'ColorTempUnknown6', Unknown => 1 }, + 0x82 => { Name => 'WB_RGGBLevelsUnknown7', Format => 'int16s[4]', Unknown => 1 }, + 0x86 => { Name => 'ColorTempUnknown7', Unknown => 1 }, + 0x87 => { Name => 'WB_RGGBLevelsUnknown8', Format => 'int16s[4]', Unknown => 1 }, + 0x8b => { Name => 'ColorTempUnknown8', Unknown => 1 }, + 0x8c => { Name => 'WB_RGGBLevelsUnknown9', Format => 'int16s[4]', Unknown => 1 }, + 0x90 => { Name => 'ColorTempUnknown9', Unknown => 1 }, + 0x91 => { Name => 'WB_RGGBLevelsUnknown10', Format => 'int16s[4]', Unknown => 1 }, + 0x95 => { Name => 'ColorTempUnknown10', Unknown => 1 }, + 0x96 => { Name => 'WB_RGGBLevelsDaylight', Format => 'int16s[4]' }, + 0x9a => 'ColorTempDaylight', + 0x9b => { Name => 'WB_RGGBLevelsShade', Format => 'int16s[4]' }, + 0x9f => 'ColorTempShade', + 0xa0 => { Name => 'WB_RGGBLevelsCloudy', Format => 'int16s[4]' }, + 0xa4 => 'ColorTempCloudy', + 0xa5 => { Name => 'WB_RGGBLevelsTungsten', Format => 'int16s[4]' }, + 0xa9 => 'ColorTempTungsten', + 0xaa => { Name => 'WB_RGGBLevelsFluorescent',Format => 'int16s[4]' }, + 0xae => 'ColorTempFluorescent', + 0xaf => { Name => 'WB_RGGBLevelsKelvin', Format => 'int16s[4]' }, + 0xb3 => 'ColorTempKelvin', + 0xb4 => { Name => 'WB_RGGBLevelsFlash', Format => 'int16s[4]' }, + 0xb8 => 'ColorTempFlash', + 0xb9 => { Name => 'WB_RGGBLevelsUnknown11', Format => 'int16s[4]', Unknown => 1 }, + 0xbd => { Name => 'ColorTempUnknown11', Unknown => 1 }, + 0xbe => { Name => 'WB_RGGBLevelsUnknown12', Format => 'int16s[4]', Unknown => 1 }, + 0xc2 => { Name => 'ColorTempUnknown12', Unknown => 1 }, + 0xc3 => { Name => 'WB_RGGBLevelsUnknown13', Format => 'int16s[4]', Unknown => 1 }, + 0xc7 => { Name => 'ColorTempUnknown13', Unknown => 1 }, + 0xc8 => { Name => 'WB_RGGBLevelsUnknown14', Format => 'int16s[4]', Unknown => 1 }, + 0xcc => { Name => 'ColorTempUnknown14', Unknown => 1 }, + 0xcd => { Name => 'WB_RGGBLevelsUnknown15', Format => 'int16s[4]', Unknown => 1 }, + 0xd1 => { Name => 'ColorTempUnknown15', Unknown => 1 }, + 0xd2 => { Name => 'WB_RGGBLevelsUnknown16', Format => 'int16s[4]', Unknown => 1 }, + 0xd6 => { Name => 'ColorTempUnknown16', Unknown => 1 }, + 0xd7 => { Name => 'WB_RGGBLevelsUnknown17', Format => 'int16s[4]', Unknown => 1 }, + 0xdb => { Name => 'ColorTempUnknown17', Unknown => 1 }, + 0xdc => { Name => 'WB_RGGBLevelsUnknown18', Format => 'int16s[4]', Unknown => 1 }, + 0xe0 => { Name => 'ColorTempUnknown18', Unknown => 1 }, + 0xe1 => { Name => 'WB_RGGBLevelsUnknown19', Format => 'int16s[4]', Unknown => 1 }, + 0xe5 => { Name => 'ColorTempUnknown19', Unknown => 1 }, + 0xe6 => { Name => 'WB_RGGBLevelsUnknown20', Format => 'int16s[4]', Unknown => 1 }, + 0xea => { Name => 'ColorTempUnknown20', Unknown => 1 }, + 0xeb => { Name => 'WB_RGGBLevelsUnknown21', Format => 'int16s[4]', Unknown => 1 }, + 0xef => { Name => 'ColorTempUnknown21', Unknown => 1 }, + 0xf0 => { Name => 'WB_RGGBLevelsUnknown22', Format => 'int16s[4]', Unknown => 1 }, + 0xf4 => { Name => 'ColorTempUnknown22', Unknown => 1 }, + 0xf5 => { Name => 'WB_RGGBLevelsUnknown23', Format => 'int16s[4]', Unknown => 1 }, + 0xf9 => { Name => 'ColorTempUnknown23', Unknown => 1 }, + 0xfa => { Name => 'WB_RGGBLevelsUnknown24', Format => 'int16s[4]', Unknown => 1 }, + 0xfe => { Name => 'ColorTempUnknown24', Unknown => 1 }, + 0xff => { Name => 'WB_RGGBLevelsUnknown25', Format => 'int16s[4]', Unknown => 1 }, + 0x103=> { Name => 'ColorTempUnknown25', Unknown => 1 }, + 0x104=> { Name => 'WB_RGGBLevelsUnknown26', Format => 'int16s[4]', Unknown => 1 }, + 0x108=> { Name => 'ColorTempUnknown26', Unknown => 1 }, + 0x109=> { Name => 'WB_RGGBLevelsUnknown27', Format => 'int16s[4]', Unknown => 1 }, + 0x10d=> { Name => 'ColorTempUnknown27', Unknown => 1 }, + 0x10e=> { Name => 'WB_RGGBLevelsUnknown28', Format => 'int16s[4]', Unknown => 1 }, + 0x112=> { Name => 'ColorTempUnknown28', Unknown => 1 }, + 0x113=> { Name => 'WB_RGGBLevelsUnknown29', Format => 'int16s[4]', Unknown => 1 }, + 0x117=> { Name => 'ColorTempUnknown29', Unknown => 1 }, + 0x118 => { + Name => 'ColorCalib', + Format => 'undef[120]', + Unknown => 1, + SubDirectory => { TagTable => 'Image::ExifTool::Canon::ColorCalib' } + }, + 0x157 => { + Name => 'PerChannelBlackLevel', + Format => 'int16u[4]', + }, + # 0x326 - PerChannelBlackLevel again + 0x32a => { + Name => 'NormalWhiteLevel', + Format => 'int16u', + RawConv => '$val || undef', + }, + 0x32b => { + Name => 'SpecularWhiteLevel', + Format => 'int16u', + }, + 0x32c => { + Name => 'LinearityUpperMargin', + Format => 'int16u', + }, +); + +# Color data (MakerNotes tag 0x4001, count=3973, ref IB) +%Image::ExifTool::Canon::ColorData11 = ( + %binaryDataAttrs, + NOTES => 'These tags are used by the EOS R3', + FORMAT => 'int16s', + FIRST_ENTRY => 0, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + DATAMEMBER => [ 0 ], + IS_SUBDIR => [ 0x12c ], + 0x00 => { + Name => 'ColorDataVersion', + DataMember => 'ColorDataVersion', + RawConv => '$$self{ColorDataVersion} = $val', + PrintConv => { + 34 => '34 (R3)', #IB + }, + }, + 0x69 => { Name => 'WB_RGGBLevelsAsShot', Format => 'int16s[4]' }, + 0x6d => 'ColorTempAsShot', + 0x6e => { Name => 'WB_RGGBLevelsAuto', Format => 'int16s[4]' }, + 0x72 => 'ColorTempAuto', + 0x73 => { Name => 'WB_RGGBLevelsMeasured', Format => 'int16s[4]' }, + 0x77 => 'ColorTempMeasured', + 0x78 => { Name => 'WB_RGGBLevelsUnknown', Format => 'int16s[4]', Unknown => 1 }, + 0x7c => { Name => 'ColorTempUnknown', Unknown => 1 }, + 0x7d => { Name => 'WB_RGGBLevelsUnknown2', Format => 'int16s[4]', Unknown => 1 }, + 0x81 => { Name => 'ColorTempUnknown2', Unknown => 1 }, + 0x82 => { Name => 'WB_RGGBLevelsUnknown3', Format => 'int16s[4]', Unknown => 1 }, + 0x86 => { Name => 'ColorTempUnknown3', Unknown => 1 }, + 0x87 => { Name => 'WB_RGGBLevelsUnknown4', Format => 'int16s[4]', Unknown => 1 }, + 0x8b => { Name => 'ColorTempUnknown4', Unknown => 1 }, + 0x8c => { Name => 'WB_RGGBLevelsUnknown5', Format => 'int16s[4]', Unknown => 1 }, + 0x90 => { Name => 'ColorTempUnknown5', Unknown => 1 }, + 0x91 => { Name => 'WB_RGGBLevelsUnknown6', Format => 'int16s[4]', Unknown => 1 }, + 0x95 => { Name => 'ColorTempUnknown6', Unknown => 1 }, + 0x96 => { Name => 'WB_RGGBLevelsUnknown7', Format => 'int16s[4]', Unknown => 1 }, + 0x9a => { Name => 'ColorTempUnknown7', Unknown => 1 }, + 0x9b => { Name => 'WB_RGGBLevelsUnknown8', Format => 'int16s[4]', Unknown => 1 }, + 0x9f => { Name => 'ColorTempUnknown8', Unknown => 1 }, + 0xa0 => { Name => 'WB_RGGBLevelsUnknown9', Format => 'int16s[4]', Unknown => 1 }, + 0xa4 => { Name => 'ColorTempUnknown9', Unknown => 1 }, + 0xa5 => { Name => 'WB_RGGBLevelsUnknown10', Format => 'int16s[4]', Unknown => 1 }, + 0xa9 => { Name => 'ColorTempUnknown10', Unknown => 1 }, + 0xaa => { Name => 'WB_RGGBLevelsUnknown11', Format => 'int16s[4]', Unknown => 1 }, + 0xae => { Name => 'ColorTempUnknown11', Unknown => 1 }, + 0xaf => { Name => 'WB_RGGBLevelsUnknown11', Format => 'int16s[4]', Unknown => 1 }, + 0xb3 => { Name => 'ColorTempUnknown11', Unknown => 1 }, + 0xb4 => { Name => 'WB_RGGBLevelsUnknown12', Format => 'int16s[4]', Unknown => 1 }, + 0xb8 => { Name => 'ColorTempUnknown12', Unknown => 1 }, + 0xb9 => { Name => 'WB_RGGBLevelsUnknown13', Format => 'int16s[4]', Unknown => 1 }, + 0xbd => { Name => 'ColorTempUnknown13', Unknown => 1 }, + 0xbe => { Name => 'WB_RGGBLevelsUnknown14', Format => 'int16s[4]', Unknown => 1 }, + 0xc2 => { Name => 'ColorTempUnknown14', Unknown => 1 }, + 0xc3 => { Name => 'WB_RGGBLevelsUnknown15', Format => 'int16s[4]', Unknown => 1 }, + 0xc7 => { Name => 'ColorTempUnknown15', Unknown => 1 }, + 0xc8 => { Name => 'WB_RGGBLevelsUnknown16', Format => 'int16s[4]', Unknown => 1 }, + 0xcc => { Name => 'ColorTempUnknown16', Unknown => 1 }, + 0xcd => { Name => 'WB_RGGBLevelsDaylight', Format => 'int16s[4]' }, + 0xd1 => 'ColorTempDaylight', + 0xd2 => { Name => 'WB_RGGBLevelsShade', Format => 'int16s[4]' }, + 0xd6 => 'ColorTempShade', + 0xd7 => { Name => 'WB_RGGBLevelsCloudy', Format => 'int16s[4]' }, + 0xdb => 'ColorTempCloudy', + 0xdc => { Name => 'WB_RGGBLevelsTungsten', Format => 'int16s[4]' }, + 0xe0 => 'ColorTempTungsten', + 0xe1 => { Name => 'WB_RGGBLevelsFluorescent',Format => 'int16s[4]' }, + 0xe5 => 'ColorTempFluorescent', + 0xe6 => { Name => 'WB_RGGBLevelsKelvin', Format => 'int16s[4]' }, + 0xea => 'ColorTempKelvin', + 0xeb => { Name => 'WB_RGGBLevelsFlash', Format => 'int16s[4]' }, + 0xef => 'ColorTempFlash', + 0xf0 => { Name => 'WB_RGGBLevelsUnknown17', Format => 'int16s[4]', Unknown => 1 }, + 0xf4 => { Name => 'ColorTempUnknown17', Unknown => 1 }, + 0xf5 => { Name => 'WB_RGGBLevelsUnknown18', Format => 'int16s[4]', Unknown => 1 }, + 0xf9 => { Name => 'ColorTempUnknown18', Unknown => 1 }, + 0xfa => { Name => 'WB_RGGBLevelsUnknown19', Format => 'int16s[4]', Unknown => 1 }, + 0xfe => { Name => 'ColorTempUnknown19', Unknown => 1 }, + 0xff => { Name => 'WB_RGGBLevelsUnknown20', Format => 'int16s[4]', Unknown => 1 }, + 0x103 => { Name => 'ColorTempUnknown20', Unknown => 1 }, + 0x104 => { Name => 'WB_RGGBLevelsUnknown21', Format => 'int16s[4]', Unknown => 1 }, + 0x108 => { Name => 'ColorTempUnknown21', Unknown => 1 }, + 0x109 => { Name => 'WB_RGGBLevelsUnknown22', Format => 'int16s[4]', Unknown => 1 }, + 0x10d => { Name => 'ColorTempUnknown22', Unknown => 1 }, + 0x10e => { Name => 'WB_RGGBLevelsUnknown23', Format => 'int16s[4]', Unknown => 1 }, + 0x112 => { Name => 'ColorTempUnknown23', Unknown => 1 }, + 0x113 => { Name => 'WB_RGGBLevelsUnknown24', Format => 'int16s[4]', Unknown => 1 }, + 0x117 => { Name => 'ColorTempUnknown24', Unknown => 1 }, + 0x118 => { Name => 'WB_RGGBLevelsUnknown25', Format => 'int16s[4]', Unknown => 1 }, + 0x11c => { Name => 'ColorTempUnknown25', Unknown => 1 }, + 0x11d => { Name => 'WB_RGGBLevelsUnknown26', Format => 'int16s[4]', Unknown => 1 }, + 0x121 => { Name => 'ColorTempUnknown26', Unknown => 1 }, + 0x122 => { Name => 'WB_RGGBLevelsUnknown27', Format => 'int16s[4]', Unknown => 1 }, + 0x126 => { Name => 'ColorTempUnknown27', Unknown => 1 }, + 0x12c => { + Name => 'ColorCalib', + Format => 'undef[120]', + Unknown => 1, + SubDirectory => { TagTable => 'Image::ExifTool::Canon::ColorCalib' } + }, + 0x16b => { + Name => 'PerChannelBlackLevel', + Format => 'int16u[4]', + }, + # 0x27c - PerChannelBlackLevel again + 0x280 => { + Name => 'NormalWhiteLevel', + Format => 'int16u', + RawConv => '$val || undef', + }, + 0x281 => { + Name => 'SpecularWhiteLevel', + Format => 'int16u', + }, + 0x282 => { + Name => 'LinearityUpperMargin', + Format => 'int16u', + }, +); + # Unknown color data (MakerNotes tag 0x4001) %Image::ExifTool::Canon::ColorDataUnknown = ( PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, @@ -7971,6 +8508,10 @@ my %ciMaxFocal = ( Name => 'PeripheralLighting', PrintConv => \%offOn, }, + 3 => { + Name => 'DistortionCorrection', + PrintConv => \%offOn, + }, 4 => { Name => 'ChromaticAberrationCorr', PrintConv => \%offOn, @@ -7980,6 +8521,7 @@ my %ciMaxFocal = ( PrintConv => \%offOn, }, 6 => 'PeripheralLightingValue', + 9 => 'DistortionCorrectionValue', # 10 - flags? 11 => { Name => 'OriginalImageWidth', @@ -8015,6 +8557,10 @@ my %ciMaxFocal = ( Name => 'ChromaticAberrationSetting', PrintConv => \%offOn, }, + 7 => { + Name => 'DistortionCorrectionSetting', + PrintConv => \%offOn, + }, ); # Auto Lighting Optimizater information (MakerNotes tag 0x4018) (ref PH) @@ -8059,7 +8605,7 @@ my %ciMaxFocal = ( }, }, # 6 - related to ChromaticAberrationCorr - # 7 - related to DistortionCorrection + # 7 - related to DistortionCorrection (0=off, 1=On in a 5DmkIV sample) # 8 - related to PeripheralIlluminationCorr and ChromaticAberrationCorr ); @@ -8190,6 +8736,65 @@ my %filterConv = ( # 3 - maybe related to AutoImageAlign? ); +# More color information (MakerNotes tag 0x4026) (ref github issue #119) +%Image::ExifTool::Canon::LogInfo = ( + %binaryDataAttrs, + FORMAT => 'int32s', + FIRST_ENTRY => 1, + PRIORITY => 0, + 4 => { + Name => 'CompressionFormat', + PrintConv => { + 0 => 'Editing (ALL-I)', + 1 => 'Standard (IPB)', + 2 => 'Light (IPB)', + 3 => 'Motion JPEG', + 4 => 'RAW', # either Standard or Light, depending on Quality + }, + }, + 6 => { # 0 to 7 + Name => 'Sharpness', + RawConv => '$val == 0x7fffffff ? undef : $val', + }, + 7 => { # -4 to 4 + Name => 'Saturation', + RawConv => '$val == 0x7fffffff ? undef : $val', + %Image::ExifTool::Exif::printParameter, + }, + 8 => { # -4 to 4 + Name => 'ColorTone', + RawConv => '$val == 0x7fffffff ? undef : $val', + %Image::ExifTool::Exif::printParameter, + }, + 9 => { + Name => 'ColorSpace2', + RawConv => '$val == 0x7fffffff ? undef : $val', + PrintConv => { + 0 => 'BT.709', + 1 => 'BT.2020', + 2 => 'CinemaGamut', + }, + }, + 10 => { + Name => 'ColorMatrix', + RawConv => '$val == 0x7fffffff ? undef : $val', + PrintConv => { + 0 => 'EOS Original', + 1 => 'Neutral', + }, + }, + 11 => { + Name => 'CanonLogVersion', # (increases dynamic range of sensor data) + RawConv => '$val == 0x7fffffff ? undef : $val', + PrintConv => { + 0 => 'OFF', + 1 => 'CLogV1', + 2 => 'CLogV2', # (NC) + 3 => 'CLogV3', + }, + }, +); + # AF configuration info (MakerNotes tag 0x4028) (ref PH) %Image::ExifTool::Canon::AFConfig = ( %binaryDataAttrs, @@ -8341,9 +8946,20 @@ my %filterConv = ( }, ); +# RAW burst mode info (MakerNotes tag 0x403f) (ref 25) +%Image::ExifTool::Canon::RawBurstInfo = ( + %binaryDataAttrs, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + FORMAT => 'int32u', + FIRST_ENTRY => 1, + 1 => 'RawBurstImageNum', + 2 => 'RawBurstImageCount', +); + # Canon UUID atoms (ref PH, SX280) %Image::ExifTool::Canon::uuid = ( GROUPS => { 0 => 'MakerNotes', 1 => 'Canon', 2 => 'Video' }, + WRITE_PROC => 'Image::ExifTool::QuickTime::WriteQuickTime', NOTES => q{ Tags extracted from the uuid atom of MP4 videos from cameras such as the SX280, and CR3 images from cameras such as the EOS M50. @@ -8366,39 +8982,49 @@ my %filterConv = ( }, }, # CTBO - (CR3 files) int32u entry count N, N x (int32u index, int64u offset, int64u size) - # index 1=XMP, 2=PRVW, 3=mdat + # index: 1=XMP, 2=PRVW, 3=mdat, 4=?, 5=? + # --> ignored when reading, but offsets are updated when writing CMT1 => { # (CR3 files) Name => 'IFD0', + PreservePadding => 1, SubDirectory => { TagTable => 'Image::ExifTool::Exif::Main', ProcessProc => \&Image::ExifTool::ProcessTIFF, + WriteProc => \&Image::ExifTool::WriteTIFF, }, }, CMT2 => { # (CR3 files) Name => 'ExifIFD', + PreservePadding => 1, SubDirectory => { TagTable => 'Image::ExifTool::Exif::Main', ProcessProc => \&Image::ExifTool::ProcessTIFF, + WriteProc => \&Image::ExifTool::WriteTIFF, }, }, CMT3 => { # (CR3 files) Name => 'MakerNoteCanon', + PreservePadding => 1, SubDirectory => { TagTable => 'Image::ExifTool::Canon::Main', - ProcessProc => \&Image::ExifTool::ProcessTIFF, + ProcessProc => \&ProcessCMT3, + WriteProc => \&Image::ExifTool::WriteTIFF, }, }, CMT4 => { # (CR3 files) Name => 'GPSInfo', + PreservePadding => 1, SubDirectory => { TagTable => 'Image::ExifTool::GPS::Main', ProcessProc => \&Image::ExifTool::ProcessTIFF, + WriteProc => \&Image::ExifTool::WriteTIFF, DirName => 'GPS', }, }, THMB => { Name => 'ThumbnailImage', Groups => { 2 => 'Preview' }, + PreservePadding => 1, RawConv => 'substr($val, 16)', Binary => 1, }, @@ -8408,6 +9034,19 @@ my %filterConv = ( }, ); +# Canon top-level uuid atoms (ref PH, written by DPP4) +%Image::ExifTool::Canon::uuid2 = ( + WRITE_PROC => 'Image::ExifTool::QuickTime::WriteQuickTime', + CNOP => { + Name => 'CanonVRD', + PreservePadding => 1, + SubDirectory => { + TagTable => 'Image::ExifTool::CanonVRD::Main', + WriteProc => 'Image::ExifTool::CanonVRD::WriteCanonDR4', + }, + }, +); + %Image::ExifTool::Canon::UnknownIFD = ( GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, ); @@ -8418,10 +9057,30 @@ my %filterConv = ( # CCDT - int32u[3]: 0. 0, 1. decoder type?, 2. 0, 3. index ); +# 'CMP1' atom information (ref 54, CR3 files) +%Image::ExifTool::Canon::CMP1 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 0 => 'MakerNotes', 1 => 'Canon', 2 => 'Image' }, + FORMAT => 'int16u', + FIRST_ENTRY => 0, + PRIORITY => 0, + 8 => { Name => 'ImageWidth', Format => 'int32u' }, + 10 => { Name => 'ImageHeight', Format => 'int32u' }, + # (the rest of the documented tags don't seem to produced good values with my samples - PH) +); + # 'CDI1' atom information (ref PH, CR3 files) %Image::ExifTool::Canon::CDI1 = ( - GROUPS => { 0 => 'QuickTime', 1 => 'Canon', 2 => 'Image' }, - # IAD1 - 32/48 bytes + GROUPS => { 0 => 'MakerNotes', 1 => 'Canon', 2 => 'Image' }, + IAD1 => { Name => 'IAD1', SubDirectory => { TagTable => 'Image::ExifTool::Canon::IAD1' } }, +); + +# 'IAD1' atom information (ref 54, CR3 files) +%Image::ExifTool::Canon::IAD1 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 0 => 'MakerNotes', 1 => 'Canon', 2 => 'Image' }, + FORMAT => 'int16u', + FIRST_ENTRY => 0, ); # Canon Timed MetaData (ref PH, CR3 files) @@ -8429,7 +9088,7 @@ my %filterConv = ( GROUPS => { 0 => 'MakerNotes', 1 => 'Canon', 2 => 'Image' }, PROCESS_PROC => \&ProcessCTMD, NOTES => q{ - Canon Timed MetaData tags found in CR3 images. The ExtractEmbedded option + Canon Timed MetaData tags found in CR3 images. The L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> option is automatically applied when reading CR3 files to be able to extract this information. }, @@ -8525,9 +9184,12 @@ my %filterConv = ( %Image::ExifTool::Canon::CNTH = ( GROUPS => { 0 => 'MakerNotes', 1 => 'Canon', 2 => 'Video' }, + VARS => { ATOM_COUNT => 1 }, # only one contained atom + WRITABLE => 1, + WRITE_PROC => 'Image::ExifTool::QuickTime::WriteQuickTime', NOTES => q{ - Canon-specific QuickTime tags found in the CNTH atom of MOV videos from some - cameras such as the PowerShot S95. + Canon-specific QuickTime tags found in the CNTH atom of MOV/MP4 videos from + some cameras. }, CNDA => { Name => 'ThumbnailImage', @@ -8541,13 +9203,14 @@ my %filterConv = ( $$self{DOC_NUM} = 0; return \$val; }, + RawConvInv => '$val', }, ); # Canon CNOP atoms (ref PH) %Image::ExifTool::Canon::CNOP = ( GROUPS => { 0 => 'MakerNotes', 1 => 'Canon', 2 => 'Video' }, - # CNFB - 52 bytes (7DmkII,M50) + # CNFB - 52 bytes (7DmkII,M50,C200) # CNMI - 4 bytes: "0x20000001" (C200) # CNCM - 48 bytes: original file name in bytes 24-31 (C200) ); @@ -8735,8 +9398,9 @@ my %filterConv = ( # numbers from the previous image, so we need special logic # to handle the FileIndex wrap properly) $val[1] == 10000 and $val[1] = 1, ++$val[0]; - return sprintf("%.3d-%.4d",@val); + return sprintf("%.3d%.4d",@val); }, + PrintConv => '$_=$val;s/(\d+)(\d{4})/$1-$2/;$_', }, ); @@ -8848,8 +9512,9 @@ sub PrintLensID(@) push @likely, $tclens; if ($maxAperture) { # (not 100% sure that TC affects MaxAperture, but it should!) - next if $maxAperture < $sa * $tc - 0.15; - next if $maxAperture > $la * $tc + 0.15; + # (RF 24-105mm F4L IS USM shows a MaxAperture of 4.177) + next if $maxAperture < $sa * $tc - 0.18; + next if $maxAperture > $la * $tc + 0.18; } push @matches, $tclens; } @@ -8881,9 +9546,10 @@ sub PrintLensID(@) } @matches = @best if @best; } + @matches = @likely unless @matches; + @matches = @maybe unless @matches; + Image::ExifTool::Exif::MatchLensModel(\@matches, $lensModel); return join(' or ', @matches) if @matches; - return join(' or ', @likely) if @likely; - return join(' or ', @maybe) if @maybe; } elsif ($lensModel and $lensModel =~ /\d/) { # use lens model as written by the camera if ($printConv eq \%canonLensTypes) { @@ -9231,7 +9897,7 @@ sub PrintAFPoints1D($) $focusing = "$row$col" if $focus eq $focusPt; push @points, "$row$col" if shift @bits; } - $focusing or $focusing = ($focus eq 0xff) ? 'Auto' : sprintf('Unknown (0x%.2x)',$focus); + $focusing or $focusing = ($focus == 0xff) ? 'Auto' : sprintf('Unknown (0x%.2x)',$focus); return "$focusing (" . join(',',@points) . ')'; } @@ -9292,6 +9958,33 @@ sub CanonEvInv($) return $sign * ($val * 0x20 + $frac); } +#------------------------------------------------------------------------------ +# Read CMT3 maker notes from CR3 file +# Inputs: 0) ExifTool object reference, 1) dirInfo ref, 2) tag table ref +# Returns: data block (may be empty if no Exif data) or undef on error +sub ProcessCMT3($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + + # extract the static maker notes to copying to other file types if requested + # Note: this won't copy makernotes in the timed metadata since these are stored + # separately, but the only records they have that aren't in the static maker notes + # (for the M50) are: ColorData9, Flavor, CanonCameraInfoUnknown, + # VignettingCorrUnknown1, Canon_0x4033 and Canon_0x402e + if (($et->Options('MakerNotes') or $$et{REQ_TAG_LOOKUP}{makernotecanon}) and + $$dirInfo{DirLen} > 8) + { + my $dataPt = $$dirInfo{DataPt}; + # remove old (unused) trailer + $$dataPt =~ s/(II\x2a\0|MM\0\x2a)\0{4,10}$//; + # remove TIFF header and append as the Canon makernote trailer + # (so offsets will be interpreted correctly) + my $val = substr($$dataPt,8) . substr($$dataPt,0,8); + $et->FoundTag($Image::ExifTool::Canon::uuid{CMT3}, \$val); + } + return $et->ProcessTIFF($dirInfo, $tagTablePtr); +} + #------------------------------------------------------------------------------ # Process CTMD EXIF information # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref @@ -9466,7 +10159,7 @@ Canon maker notes in EXIF information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/CanonCustom.pm b/src/Image-ExifTool/lib/Image/ExifTool/CanonCustom.pm index bfee19a6..363235c2 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/CanonCustom.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/CanonCustom.pm @@ -19,7 +19,7 @@ use Image::ExifTool qw(:DataAccess); use Image::ExifTool::Canon; use Image::ExifTool::Exif; -$VERSION = '1.55'; +$VERSION = '1.58'; sub ProcessCanonCustom($$$); sub ProcessCanonCustom2($$$); @@ -1290,9 +1290,19 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); }, }, 0x0106 => [{ + Name => 'AEBShotCount', + Condition => '$$self{Model} =~ /\b90D\b/', + Notes => 'EOS 90D', # (and who knows what others?) + PrintConv => { + 2 => '2 shots', + 3 => '3 shots', + 5 => '5 shots', + 7 => '7 shots', + }, + },{ Name => 'AEBShotCount', Condition => '$count == 1', - Notes => 'one value for some models...', + Notes => 'other models storing a single value', PrintConv => { 0 => '3 shots', 1 => '2 shots', @@ -1302,7 +1312,7 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); },{ Name => 'AEBShotCount', Count => 2, - Notes => 'two values for others', + Notes => 'models storing two values', PrintConv => { '3 0' => '3 shots', '2 1' => '2 shots', @@ -1319,14 +1329,20 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); }, 0x0108 => { Name => 'SafetyShift', - Notes => 'value of 2 not used by 40D, 50D, 60D, 5DmkII and 7D', + Notes => 'value of 2 not used by some models', # eg. 40D, 50D, 60D, 5DmkII, 7D, 250D PrintConv => { 0 => 'Disable', 1 => 'Enable (Tv/Av)', 2 => 'Enable (ISO speed)', }, }, - 0x0109 => { + 0x0109 => [{ # (1DXmkIII) + Name => 'UsableShootingModes', + Condition => '$count == 1', + Count => 1, + PrintConv => 'sprintf("Flags 0x%x",$val)', + PrintConvInv => '$val=~/0x([\dA-F]+)/i ? hex($1) : undef', + },{ Name => 'UsableShootingModes', Count => 2, PrintConv => [ @@ -1337,10 +1353,16 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); undef, '$val=~/0x([\dA-F]+)/i ? hex($1) : undef', ], - }, - 0x010a => { + }], + 0x010a => [{ # (1DXmkIII) Name => 'UsableMeteringModes', - Count => 2, + Condition => '$count == 1', + Count => 1, + PrintConv => 'sprintf("Flags 0x%x",$val)', + PrintConvInv => '$val=~/0x([\dA-F]+)/i ? hex($1) : undef', + },{ + Name => 'UsableMeteringModes', + Count => 2, PrintConv => [ \%disableEnable, 'sprintf("Flags 0x%x",$val)', # (evaluative,partial,spot,center-weighted average) @@ -1349,7 +1371,7 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); undef, '$val=~/0x([\dA-F]+)/i ? hex($1) : undef', ], - }, + }], 0x010b => { Name => 'ExposureModeInManual', PrintConv => { @@ -1678,11 +1700,13 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); 0x040a => { # new for 5DmkIII Name => 'ViewfinderWarnings', PrintConv => { BITMASK => { #(NC) - 0 => 'Monochrome', # (have seen for: 5DmkII, 6D) - 1 => 'WB corrected', # (have seen for: 5DmkII, 6D) + 0 => 'Monochrome', # (have seen for: 5DmkII, 6D, 250D, 90D) + 1 => 'WB corrected', # (have seen for: 5DmkII, 6D, 90D) 2 => 'One-touch image quality', # (have seen for: 5DmkII; doesn't exist for 6D) 3 => 'ISO expansion', # (have seen for: 5DmkII) 4 => 'Spot metering', # (have seen for: 5DmkII, 6D) + 6 => 'Noise reduction', # (have seen for: 250D, 90D) + 7 => 'HDR', # (have seen for: 90D) }}, }, 0x040b => { # new for 5DmkIII @@ -1920,6 +1944,7 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); 1 => 'AF point button: Auto selection; Rear dial: Manual selection', }, }, + # (this is 2 values for 90D,M6mkII, seen: "1046 1046") ], 0x0510 => [ # new for 40D { @@ -1963,6 +1988,7 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); 1 => 'Enable', 2 => 'Register', 3 => 'Select AF-modes', + # also seen: 87 (90D), 1142 (RP) }, 'sprintf("Flags 0x%x",$val)', # (70D=Manual 1pt,Manual zone,Auto 19pt) ], @@ -2062,7 +2088,45 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); 2 => 'Enable: Down with Set', }, }, - 0x0610 => { + 0x0610 => [{ # (1DXmkIII) + Name => 'ContinuousShootingSpeed', + Condition => '$count == 6', + Count => 6, + PrintConv => [ + \%disableEnable, + '"Hi $val"', + '"Cont $val"', + '"Lo $val"', + '"Soft $val"', + '"Soft LS $val"', + ], + PrintConvInv => [ + undef, + '$val=~/(\d+)/ ? $1 : 0', + '$val=~/(\d+)/ ? $1 : 0', + '$val=~/(\d+)/ ? $1 : 0', + '$val=~/(\d+)/ ? $1 : 0', + '$val=~/(\d+)/ ? $1 : 0', + ], + },{ # (1DXmkIII firmware 1.3) + Name => 'ContinuousShootingSpeed', + Condition => '$count == 5', + Count => 5, + PrintConv => [ + '"Hi $val"', + '"Cont $val"', + '"Lo $val"', + '"Soft $val"', + '"Soft LS $val"', + ], + PrintConvInv => [ + '$val=~/(\d+)/ ? $1 : 0', + '$val=~/(\d+)/ ? $1 : 0', + '$val=~/(\d+)/ ? $1 : 0', + '$val=~/(\d+)/ ? $1 : 0', + '$val=~/(\d+)/ ? $1 : 0', + ], + },{ # others Name => 'ContinuousShootingSpeed', Count => 3, PrintConv => [ @@ -2075,7 +2139,7 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); '$val=~/(\d+)/ ? $1 : 0', '$val=~/(\d+)/ ? $1 : 0', ], - }, + }], 0x0611 => { Name => 'ContinuousShotLimit', Count => 2, @@ -2088,7 +2152,13 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); '$val=~/(\d+)/ ? $1 : 0', ], }, - 0x0612 => { # (1DX) + 0x0612 => [{ # (1DXmkIII) + Name => 'RestrictDriveModes', + Condition => '$count == 1', + Count => 1, + PrintConv => 'sprintf("Flags 0x%x",$val)', + PrintConvInv => '$val=~/0x([\dA-F]+)/i ? hex($1) : undef', + },{ # (1DX) Name => 'RestrictDriveModes', Count => 2, PrintConv => [ @@ -2099,7 +2169,7 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); undef, '$val=~/0x([\dA-F]+)/i ? hex($1) : undef', ], - }, + }], #### 4a) Operation 0x0701 => [ { @@ -2116,6 +2186,17 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); 3 => 'AE/AF, No AE lock', }, }, + { + Name => 'Shutter-AELock', + Condition => '$count == 2', + Notes => '250D', + PrintConv => { + '0 0' => 'AF/AE lock', + '1 0' => 'AE lock/AF', + '2 0' => 'AF/AF lock, No AE lock', + '3 0' => 'AE/AF, No AE lock', + }, + }, { Name => 'AFAndMeteringButtons', Condition => '$$self{Model} =~ /\b60D\b/', @@ -2233,6 +2314,13 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); 5 => 'Disabled', }, }, + { + Name => 'SetButtonWhenShooting', + Notes => '250D', + Condition => '$count == 2', + # (not sure how to decode this. seen: "37 0") + PrintConv => { }, + }, { Name => 'SetButtonWhenShooting', Notes => '1DmkIII and 1DmkIV', @@ -2436,7 +2524,21 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); }, }, ], - 0x080c => { + 0x080c => [{ # (1DXmkIII) + Name => 'TimerLength', + Condition => '$count == 3', + Count => 3, + PrintConv => [ + '"6 s: $val"', + '"16 s: $val"', + '"After release: $val"', + ], + PrintConvInv => [ + '$val=~/(\d+)$/ ? $1 : 0', + '$val=~/(\d+)$/ ? $1 : 0', + '$val=~/(\d+)$/ ? $1 : 0', + ], + },{ Name => 'TimerLength', Count => 4, PrintConv => [ @@ -2451,7 +2553,7 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); '$val=~/(\d+)$/ ? $1 : 0', '$val=~/(\d+)$/ ? $1 : 0', ], - }, + }], 0x080d => { Name => 'ShortReleaseTimeLag', PrintConv => \%disableEnable, @@ -2498,6 +2600,8 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); PrintConv => { 0 => 'Cancel selected', 1 => 'Erase selected', + 2 => 'Erase RAW selected', # (1DXmkIII) + 3 => 'Erase non-RAW selected', # (1DXmkIII) }, }, 0x0814 => { # (5DS) @@ -2508,6 +2612,10 @@ my %convPFn = ( PrintConv => \&ConvertPfn, PrintConvInv => \&ConvertPfnInv ); Name => 'AddIPTCInformation', PrintConv => \%disableEnable, }, + 0x0816 => { # (90D,RP) + Name => 'AudioCompression', + PrintConv => \%enableDisable, + } ); #------------------------------------------------------------------------------ @@ -2569,7 +2677,7 @@ sub ProcessCanonCustom2($$$) my $recPos = $pos; my $recEnd = $pos + $recLen - 8; if ($recEnd > $end) { - $et->Warn('Corrupted CanonCustom2 group'); + $et->Warn("Corrupted CanonCustom2 group $recNum"); return 0; } if ($verbose and not $write) { @@ -2579,8 +2687,17 @@ sub ProcessCanonCustom2($$$) for ($i=0; $recPos + 8 < $recEnd; ++$i, $recPos+=4*$num) { $tag = Get32u($dataPt, $recPos); $num = Get32u($dataPt, $recPos + 4); + my $nextRec = $recPos + 8 + $num * 4; + last if $nextRec > $recEnd; + # patch for EOS-1DXmkIII firmware 1.0.0 bug: + if ($tag == 0x70c and $num == 0x66 and $nextRec + 8 < $recEnd) { + my $tmp = Get32u($dataPt, $nextRec + 4); + if ($tmp == 0x70f) { + $et->Warn('Fixed incorrect CanonCustom tag 0x70c size', 1); + ++$num; # (count should be one greater) + } + } $recPos += 8; - last if $recPos + $num * 4 > $recEnd; my $val = ReadValue($dataPt, $recPos, 'int32s', $num, $num * 4); if ($write) { # write new value @@ -2612,6 +2729,9 @@ sub ProcessCanonCustom2($$$) } } } + if ($i != $recCount) { + $et->Warn('Missing '.($recCount-$i)." entries in CanonCustom2 group $recNum directory", 1); + } $pos = $recEnd; } if ($pos != $end) { @@ -2753,7 +2873,7 @@ Image::ExifTool to read this information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/CanonRaw.pm b/src/Image-ExifTool/lib/Image/ExifTool/CanonRaw.pm index c33d08b0..2ec6bead 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/CanonRaw.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/CanonRaw.pm @@ -683,7 +683,7 @@ sub ProcessCanonRaw($$$) my ($value, $delRawConv); if ($valueInDir) { # is the value data in the directory? # this type of tag stores the value in the 'size' and 'ptr' fields - $valueDataPos = $dirOffset + $pt + 4; + $valueDataPos = $dirOffset + $pt + 4; # (remember, +2 for the entry count) $size = 8; $value = substr($buff, $pt+2, $size); # set count to 1 by default for normal values in directory @@ -877,7 +877,7 @@ tags.) =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. @@ -892,7 +892,7 @@ under the same terms as Perl itself. =item L<http://xyrion.org/ciff/> -=item L<http://owl.phy.queensu.ca/~phil/exiftool/canon_raw.html> +=item L<https://exiftool.org/canon_raw.html> =back diff --git a/src/Image-ExifTool/lib/Image/ExifTool/CanonVRD.pm b/src/Image-ExifTool/lib/Image/ExifTool/CanonVRD.pm index 7794b649..7459f44e 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/CanonVRD.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/CanonVRD.pm @@ -13,7 +13,7 @@ # 2018/03/13 - PH Update to DPP 4.8.20 # # References: 1) Bogdan private communication (Canon DPP v3.4.1.1) -# 2) Gert Kello private communiation (DPP 3.8) +# 2) Gert Kello private communication (DPP 3.8) #------------------------------------------------------------------------------ package Image::ExifTool::CanonVRD; @@ -23,7 +23,7 @@ use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Canon; -$VERSION = '1.32'; +$VERSION = '1.34'; sub ProcessCanonVRD($$;$); sub WriteCanonVRD($$;$); @@ -150,8 +150,8 @@ my $blankFooter = "CANON OPTIONAL DATA\0" . ("\0" x 42) . "\xff\xd9"; },{ Name => 'IHL_EXIF', Notes => q{ - extracted as a block if the Unknown option is used, or processed as the - first sub-document with the ExtractEmbedded option + extracted as a block if the L<Unknown|../ExifTool.html#Unknown> option is used, or processed as the + first sub-document with the L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> option }, Binary => 1, Unknown => 1, @@ -1818,7 +1818,7 @@ sub ProcessDR4($$;$) if (not $format) { $val = unpack 'H*', substr($$dataPt, $off, $len); $format = 'undef'; - } elsif ($format eq 'double' and $len eq 8) { + } elsif ($format eq 'double' and $len == 8) { # avoid teeny weeny values $val = ReadValue($dataPt, $off, $format, undef, $len); $val = 0 if abs($val) < 1e-100; @@ -1954,6 +1954,28 @@ sub WriteCanonVRD($$;$) return $val; } +#------------------------------------------------------------------------------ +# Write DR4-type CanonVRD edit record +# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref +# Returns: VRD data block (may be empty if deleted, of undef on error) +sub WriteCanonDR4($$;$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + $et or return 1; # allow dummy access + my $nvHash = $et->GetNewValueHash($Image::ExifTool::Extra{CanonDR4}); + my $val = $et->GetNewValue($nvHash); + if (defined $val) { + return undef unless $et->IsOverwriting($nvHash, $val); + $et->VPrint(0, " Writing CanonDR4 as a block\n"); + ++$$et{CHANGED}; + return WrapDR4($val); + } + my $buff = ''; + $$dirInfo{OutFile} = \$buff; + return $buff if ProcessCanonVRD($et, $dirInfo, $tagTablePtr) > 0; + return undef; +} + #------------------------------------------------------------------------------ # Read/write CanonVRD information (from VRD file or VRD trailer) # Inputs: 0) ExifTool object reference, 1) dirInfo reference @@ -2015,7 +2037,7 @@ sub ProcessCanonVRD($$;$) # (so we must disable all Write() calls for this case) $dataPt = $outfile; } - if ($fromFile) { + if ($fromFile or $$dirInfo{DirStart}) { $dataPt = \$buff unless $dataPt; # read VRD data into memory if necessary unless ($raf->Read($$dataPt, $dirLen) == $dirLen) { @@ -2024,17 +2046,16 @@ sub ProcessCanonVRD($$;$) return 0; } } - # exit quickly if writing and no CanonVRD tags are being edited - if ($outfile and not exists $$et{EDIT_DIRS}{CanonVRD}) { - print $out "$$et{INDENT} [nothing changed]\n" if $verbose; - return 1 if $outfile eq $dataPt; - return Write($outfile, $$dataPt) ? 1 : -1; - } - my $vrdType = 'VRD'; if ($outfile) { $verbose and not $created and print $out " Rewriting CanonVRD trailer\n"; + # exit quickly if writing and no CanonVRD tags are being edited + unless (exists $$et{EDIT_DIRS}{CanonVRD}) { + print $out "$$et{INDENT} [nothing changed in CanonVRD]\n" if $verbose; + return 1 if $outfile eq $dataPt; + return Write($outfile, $$dataPt) ? 1 : -1; + } # delete CanonVRD information if specified my $doDel = $$et{DEL_GROUP}{CanonVRD}; unless ($doDel) { @@ -2112,7 +2133,7 @@ sub ProcessCanonVRD($$;$) $blockType = Get32u($dataPt, $pos); $blockLen = Get32u($dataPt, $pos + 4); } - $vrdType = 'DR4' if $blockType eq 0xffff00f7; + $vrdType = 'DR4' if $blockType == 0xffff00f7; $pos += 8; # move to start of block if ($pos + $blockLen > $end) { $et->Warn('Possibly corrupt CanonVRD block'); @@ -2242,7 +2263,7 @@ files, and as a trailer in JPEG, CRW, CR2 and TIFF images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/CaptureOne.pm b/src/Image-ExifTool/lib/Image/ExifTool/CaptureOne.pm index 85f4a392..cfd2f43f 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/CaptureOne.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/CaptureOne.pm @@ -221,7 +221,7 @@ settings files (COS). =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Casio.pm b/src/Image-ExifTool/lib/Image/ExifTool/Casio.pm index df1af014..73f66606 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Casio.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Casio.pm @@ -11,7 +11,7 @@ # 3) http://homepage3.nifty.com/kamisaka/makernote/makernote_casio.htm # 4) http://gvsoft.homedns.org/exif/makernote-casio-type1.html # 5) Robert Chi private communication (EX-F1) -# 6) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3701.html +# 6) https://exiftool.org/forum/index.php/topic,3701.html # JD) Jens Duttke private communication #------------------------------------------------------------------------------ @@ -2034,7 +2034,7 @@ Casio maker notes in EXIF information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Charset.pm b/src/Image-ExifTool/lib/Image/ExifTool/Charset.pm index 9486a45d..2e369abe 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Charset.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Charset.pm @@ -6,6 +6,8 @@ # Revisions: 2009/08/28 - P. Harvey created # 2010/01/20 - P. Harvey complete re-write # 2010/07/16 - P. Harvey added UTF-16 support +# +# Notes: Charset lookups are generated using my convertCharset script #------------------------------------------------------------------------------ package Image::ExifTool::Charset; @@ -59,6 +61,7 @@ my %unicode2byte = ( Latin2 => 0x101, DOSLatinUS => 0x101, DOSLatin1 => 0x101, + DOSCyrillic => 0x101, MacCroatian => 0x101, MacCyrillic => 0x101, MacGreek => 0x101, @@ -407,11 +410,11 @@ This module contains routines used by ExifTool to translate special character sets. Currently, the following character sets are supported: UTF8, UTF16, UCS2, UCS4, Arabic, Baltic, Cyrillic, Greek, Hebrew, JIS, - Latin, Latin2, DOSLatinUS, DOSLatin1, MacArabic, MacChineseCN, - MacChineseTW, MacCroatian, MacCyrillic, MacGreek, MacHebrew, MacIceland, - MacJapanese, MacKorean, MacLatin2, MacRSymbol, MacRoman, MacRomanian, - MacThai, MacTurkish, PDFDoc, RSymbol, ShiftJIS, Symbol, Thai, Turkish, - Vietnam + Latin, Latin2, DOSLatinUS, DOSLatin1, DOSCyrillic, MacArabic, + MacChineseCN, MacChineseTW, MacCroatian, MacCyrillic, MacGreek, MacHebrew, + MacIceland, MacJapanese, MacKorean, MacLatin2, MacRSymbol, MacRoman, + MacRomanian, MacThai, MacTurkish, PDFDoc, RSymbol, ShiftJIS, Symbol, Thai, + Turkish, Vietnam However, only some of these character sets are available to the user via ExifTool options -- the multi-byte character sets are used only internally @@ -419,7 +422,7 @@ when decoding certain types of information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Charset/DOSCyrillic.pm b/src/Image-ExifTool/lib/Image/ExifTool/Charset/DOSCyrillic.pm new file mode 100644 index 00000000..1ecc66ae --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/Charset/DOSCyrillic.pm @@ -0,0 +1,49 @@ +#------------------------------------------------------------------------------ +# File: DOSCyrillic.pm +# +# Description: cp866 to Unicode +# +# Revisions: 2020/03/23 - P. Harvey created +# +# References: 1) https://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP866.TXT +# +# Notes: The table omits 1-byte characters with the same values as Unicode +#------------------------------------------------------------------------------ +use strict; + +%Image::ExifTool::Charset::DOSCyrillic = ( + 0x80 => 0x0410, 0x81 => 0x0411, 0x82 => 0x0412, 0x83 => 0x0413, + 0x84 => 0x0414, 0x85 => 0x0415, 0x86 => 0x0416, 0x87 => 0x0417, + 0x88 => 0x0418, 0x89 => 0x0419, 0x8a => 0x041a, 0x8b => 0x041b, + 0x8c => 0x041c, 0x8d => 0x041d, 0x8e => 0x041e, 0x8f => 0x041f, + 0x90 => 0x0420, 0x91 => 0x0421, 0x92 => 0x0422, 0x93 => 0x0423, + 0x94 => 0x0424, 0x95 => 0x0425, 0x96 => 0x0426, 0x97 => 0x0427, + 0x98 => 0x0428, 0x99 => 0x0429, 0x9a => 0x042a, 0x9b => 0x042b, + 0x9c => 0x042c, 0x9d => 0x042d, 0x9e => 0x042e, 0x9f => 0x042f, + 0xa0 => 0x0430, 0xa1 => 0x0431, 0xa2 => 0x0432, 0xa3 => 0x0433, + 0xa4 => 0x0434, 0xa5 => 0x0435, 0xa6 => 0x0436, 0xa7 => 0x0437, + 0xa8 => 0x0438, 0xa9 => 0x0439, 0xaa => 0x043a, 0xab => 0x043b, + 0xac => 0x043c, 0xad => 0x043d, 0xae => 0x043e, 0xaf => 0x043f, + 0xb0 => 0x2591, 0xb1 => 0x2592, 0xb2 => 0x2593, 0xb3 => 0x2502, + 0xb4 => 0x2524, 0xb5 => 0x2561, 0xb6 => 0x2562, 0xb7 => 0x2556, + 0xb8 => 0x2555, 0xb9 => 0x2563, 0xba => 0x2551, 0xbb => 0x2557, + 0xbc => 0x255d, 0xbd => 0x255c, 0xbe => 0x255b, 0xbf => 0x2510, + 0xc0 => 0x2514, 0xc1 => 0x2534, 0xc2 => 0x252c, 0xc3 => 0x251c, + 0xc4 => 0x2500, 0xc5 => 0x253c, 0xc6 => 0x255e, 0xc7 => 0x255f, + 0xc8 => 0x255a, 0xc9 => 0x2554, 0xca => 0x2569, 0xcb => 0x2566, + 0xcc => 0x2560, 0xcd => 0x2550, 0xce => 0x256c, 0xcf => 0x2567, + 0xd0 => 0x2568, 0xd1 => 0x2564, 0xd2 => 0x2565, 0xd3 => 0x2559, + 0xd4 => 0x2558, 0xd5 => 0x2552, 0xd6 => 0x2553, 0xd7 => 0x256b, + 0xd8 => 0x256a, 0xd9 => 0x2518, 0xda => 0x250c, 0xdb => 0x2588, + 0xdc => 0x2584, 0xdd => 0x258c, 0xde => 0x2590, 0xdf => 0x2580, + 0xe0 => 0x0440, 0xe1 => 0x0441, 0xe2 => 0x0442, 0xe3 => 0x0443, + 0xe4 => 0x0444, 0xe5 => 0x0445, 0xe6 => 0x0446, 0xe7 => 0x0447, + 0xe8 => 0x0448, 0xe9 => 0x0449, 0xea => 0x044a, 0xeb => 0x044b, + 0xec => 0x044c, 0xed => 0x044d, 0xee => 0x044e, 0xef => 0x044f, + 0xf0 => 0x0401, 0xf1 => 0x0451, 0xf2 => 0x0404, 0xf3 => 0x0454, + 0xf4 => 0x0407, 0xf5 => 0x0457, 0xf6 => 0x040e, 0xf7 => 0x045e, + 0xf8 => 0x00b0, 0xf9 => 0x2219, 0xfa => 0x00b7, 0xfb => 0x221a, + 0xfc => 0x2116, 0xfd => 0x00a4, 0xfe => 0x25a0, 0xff => 0x00a0, +); + +1; # end diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Charset/DOSLatin1.pm b/src/Image-ExifTool/lib/Image/ExifTool/Charset/DOSLatin1.pm new file mode 100644 index 00000000..2e3fd15b --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/Charset/DOSLatin1.pm @@ -0,0 +1,49 @@ +#------------------------------------------------------------------------------ +# File: DOSLatin1.pm +# +# Description: cp850 to Unicode +# +# Revisions: 2017/10/31- P. Harvey created +# +# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP850.TXT +# +# Notes: The table omits 1-byte characters with the same values as Unicode +#------------------------------------------------------------------------------ +use strict; + +%Image::ExifTool::Charset::DOSLatin1 = ( + 0x80 => 0x00c7, 0x81 => 0x00fc, 0x82 => 0x00e9, 0x83 => 0x00e2, + 0x84 => 0x00e4, 0x85 => 0x00e0, 0x86 => 0x00e5, 0x87 => 0x00e7, + 0x88 => 0x00ea, 0x89 => 0x00eb, 0x8a => 0x00e8, 0x8b => 0x00ef, + 0x8c => 0x00ee, 0x8d => 0x00ec, 0x8e => 0x00c4, 0x8f => 0x00c5, + 0x90 => 0x00c9, 0x91 => 0x00e6, 0x92 => 0x00c6, 0x93 => 0x00f4, + 0x94 => 0x00f6, 0x95 => 0x00f2, 0x96 => 0x00fb, 0x97 => 0x00f9, + 0x98 => 0x00ff, 0x99 => 0x00d6, 0x9a => 0x00dc, 0x9b => 0x00f8, + 0x9c => 0x00a3, 0x9d => 0x00d8, 0x9e => 0x00d7, 0x9f => 0x0192, + 0xa0 => 0x00e1, 0xa1 => 0x00ed, 0xa2 => 0x00f3, 0xa3 => 0x00fa, + 0xa4 => 0x00f1, 0xa5 => 0x00d1, 0xa6 => 0x00aa, 0xa7 => 0x00ba, + 0xa8 => 0x00bf, 0xa9 => 0x00ae, 0xaa => 0x00ac, 0xab => 0x00bd, + 0xac => 0x00bc, 0xad => 0x00a1, 0xae => 0x00ab, 0xaf => 0x00bb, + 0xb0 => 0x2591, 0xb1 => 0x2592, 0xb2 => 0x2593, 0xb3 => 0x2502, + 0xb4 => 0x2524, 0xb5 => 0x00c1, 0xb6 => 0x00c2, 0xb7 => 0x00c0, + 0xb8 => 0x00a9, 0xb9 => 0x2563, 0xba => 0x2551, 0xbb => 0x2557, + 0xbc => 0x255d, 0xbd => 0x00a2, 0xbe => 0x00a5, 0xbf => 0x2510, + 0xc0 => 0x2514, 0xc1 => 0x2534, 0xc2 => 0x252c, 0xc3 => 0x251c, + 0xc4 => 0x2500, 0xc5 => 0x253c, 0xc6 => 0x00e3, 0xc7 => 0x00c3, + 0xc8 => 0x255a, 0xc9 => 0x2554, 0xca => 0x2569, 0xcb => 0x2566, + 0xcc => 0x2560, 0xcd => 0x2550, 0xce => 0x256c, 0xcf => 0x00a4, + 0xd0 => 0x00f0, 0xd1 => 0x00d0, 0xd2 => 0x00ca, 0xd3 => 0x00cb, + 0xd4 => 0x00c8, 0xd5 => 0x0131, 0xd6 => 0x00cd, 0xd7 => 0x00ce, + 0xd8 => 0x00cf, 0xd9 => 0x2518, 0xda => 0x250c, 0xdb => 0x2588, + 0xdc => 0x2584, 0xdd => 0x00a6, 0xde => 0x00cc, 0xdf => 0x2580, + 0xe0 => 0x00d3, 0xe1 => 0x00df, 0xe2 => 0x00d4, 0xe3 => 0x00d2, + 0xe4 => 0x00f5, 0xe5 => 0x00d5, 0xe6 => 0x00b5, 0xe7 => 0x00fe, + 0xe8 => 0x00de, 0xe9 => 0x00da, 0xea => 0x00db, 0xeb => 0x00d9, + 0xec => 0x00fd, 0xed => 0x00dd, 0xee => 0x00af, 0xef => 0x00b4, + 0xf0 => 0x00ad, 0xf1 => 0x00b1, 0xf2 => 0x2017, 0xf3 => 0x00be, + 0xf4 => 0x00b6, 0xf5 => 0x00a7, 0xf6 => 0x00f7, 0xf7 => 0x00b8, + 0xf8 => 0x00b0, 0xf9 => 0x00a8, 0xfa => 0x00b7, 0xfb => 0x00b9, + 0xfc => 0x00b3, 0xfd => 0x00b2, 0xfe => 0x25a0, 0xff => 0x00a0, +); + +1; # end diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Charset/DOSLatinUS.pm b/src/Image-ExifTool/lib/Image/ExifTool/Charset/DOSLatinUS.pm new file mode 100644 index 00000000..7f76823f --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/Charset/DOSLatinUS.pm @@ -0,0 +1,49 @@ +#------------------------------------------------------------------------------ +# File: DOSLatinUS.pm +# +# Description: cp437 to Unicode +# +# Revisions: 2017/10/31- P. Harvey created +# +# References: 1) http://unicode.org/Public/MAPPINGS/VENDORS/MICSFT/PC/CP437.TXT +# +# Notes: The table omits 1-byte characters with the same values as Unicode +#------------------------------------------------------------------------------ +use strict; + +%Image::ExifTool::Charset::DOSLatinUS = ( + 0x80 => 0x00c7, 0x81 => 0x00fc, 0x82 => 0x00e9, 0x83 => 0x00e2, + 0x84 => 0x00e4, 0x85 => 0x00e0, 0x86 => 0x00e5, 0x87 => 0x00e7, + 0x88 => 0x00ea, 0x89 => 0x00eb, 0x8a => 0x00e8, 0x8b => 0x00ef, + 0x8c => 0x00ee, 0x8d => 0x00ec, 0x8e => 0x00c4, 0x8f => 0x00c5, + 0x90 => 0x00c9, 0x91 => 0x00e6, 0x92 => 0x00c6, 0x93 => 0x00f4, + 0x94 => 0x00f6, 0x95 => 0x00f2, 0x96 => 0x00fb, 0x97 => 0x00f9, + 0x98 => 0x00ff, 0x99 => 0x00d6, 0x9a => 0x00dc, 0x9b => 0x00a2, + 0x9c => 0x00a3, 0x9d => 0x00a5, 0x9e => 0x20a7, 0x9f => 0x0192, + 0xa0 => 0x00e1, 0xa1 => 0x00ed, 0xa2 => 0x00f3, 0xa3 => 0x00fa, + 0xa4 => 0x00f1, 0xa5 => 0x00d1, 0xa6 => 0x00aa, 0xa7 => 0x00ba, + 0xa8 => 0x00bf, 0xa9 => 0x2310, 0xaa => 0x00ac, 0xab => 0x00bd, + 0xac => 0x00bc, 0xad => 0x00a1, 0xae => 0x00ab, 0xaf => 0x00bb, + 0xb0 => 0x2591, 0xb1 => 0x2592, 0xb2 => 0x2593, 0xb3 => 0x2502, + 0xb4 => 0x2524, 0xb5 => 0x2561, 0xb6 => 0x2562, 0xb7 => 0x2556, + 0xb8 => 0x2555, 0xb9 => 0x2563, 0xba => 0x2551, 0xbb => 0x2557, + 0xbc => 0x255d, 0xbd => 0x255c, 0xbe => 0x255b, 0xbf => 0x2510, + 0xc0 => 0x2514, 0xc1 => 0x2534, 0xc2 => 0x252c, 0xc3 => 0x251c, + 0xc4 => 0x2500, 0xc5 => 0x253c, 0xc6 => 0x255e, 0xc7 => 0x255f, + 0xc8 => 0x255a, 0xc9 => 0x2554, 0xca => 0x2569, 0xcb => 0x2566, + 0xcc => 0x2560, 0xcd => 0x2550, 0xce => 0x256c, 0xcf => 0x2567, + 0xd0 => 0x2568, 0xd1 => 0x2564, 0xd2 => 0x2565, 0xd3 => 0x2559, + 0xd4 => 0x2558, 0xd5 => 0x2552, 0xd6 => 0x2553, 0xd7 => 0x256b, + 0xd8 => 0x256a, 0xd9 => 0x2518, 0xda => 0x250c, 0xdb => 0x2588, + 0xdc => 0x2584, 0xdd => 0x258c, 0xde => 0x2590, 0xdf => 0x2580, + 0xe0 => 0x03b1, 0xe1 => 0x00df, 0xe2 => 0x0393, 0xe3 => 0x03c0, + 0xe4 => 0x03a3, 0xe5 => 0x03c3, 0xe6 => 0x00b5, 0xe7 => 0x03c4, + 0xe8 => 0x03a6, 0xe9 => 0x0398, 0xea => 0x03a9, 0xeb => 0x03b4, + 0xec => 0x221e, 0xed => 0x03c6, 0xee => 0x03b5, 0xef => 0x2229, + 0xf0 => 0x2261, 0xf1 => 0x00b1, 0xf2 => 0x2265, 0xf3 => 0x2264, + 0xf4 => 0x2320, 0xf5 => 0x2321, 0xf6 => 0x00f7, 0xf7 => 0x2248, + 0xf8 => 0x00b0, 0xf9 => 0x2219, 0xfa => 0x00b7, 0xfb => 0x221a, + 0xfc => 0x207f, 0xfd => 0x00b2, 0xfe => 0x25a0, 0xff => 0x00a0, +); + +1; # end diff --git a/src/Image-ExifTool/lib/Image/ExifTool/DICOM.pm b/src/Image-ExifTool/lib/Image/ExifTool/DICOM.pm index 2075cc73..e6984322 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/DICOM.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/DICOM.pm @@ -20,7 +20,7 @@ use strict; use vars qw($VERSION %uid); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.19'; +$VERSION = '1.22'; # DICOM VR (Value Representation) format conversions my %dicomFormat = ( @@ -3759,6 +3759,8 @@ sub ProcessDICOM($$) } my $val; my $format = $dicomFormat{$vr}; + # remove trailing space used to pad to an even number of characters + $buff =~ s/ $// unless $format or length($buff) & 0x01; if ($len > 1024) { # treat large data elements as binary data my $binData; @@ -3778,13 +3780,13 @@ sub ProcessDICOM($$) $format = 'string'; if ($vr eq 'DA') { # format date values - $val =~ s/^(\d{4})(\d{2})(\d{2})/$1:$2:$3/; + $val =~ s/^ *(\d{4})(\d{2})(\d{2})/$1:$2:$3/; } elsif ($vr eq 'TM') { # format time values - $val =~ s/^(\d{2})(\d{2})(\d{2}.*)/$1:$2:$3/; + $val =~ s/^ *(\d{2})(\d{2})(\d{2}[^ ]*)/$1:$2:$3/; } elsif ($vr eq 'DT') { # format date/time values - $val =~ s/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2}.*)/$1:$2:$3 $4:$5:$6/; + $val =~ s/^ *(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2}[^ ]*)/$1:$2:$3 $4:$5:$6/; } elsif ($vr eq 'AT' and $len == 4) { # convert attribute tag ID to hex format my ($g, $e) = (Get16u(\$buff,0), Get16u(\$buff,2)); @@ -3793,6 +3795,11 @@ sub ProcessDICOM($$) # add PrintConv to translate registered UID's $val =~ s/\0.*//s; # truncate at null $$tagInfo{PrintConv} = \%uid if $uid{$val} and $tagInfo; + } elsif ($vr =~ /^(AE|CS|DS|IS|LO|PN|SH)$/) { + $val =~ s/ +$//; # leading/trailing spaces not significant + $val =~ s/^ +//; + } elsif ($vr =~ /^(LT|ST|UT)$/) { + $val =~ s/ +$//; # trailing spaces not significant } } # save the group 2 end position and transfer syntax @@ -3846,7 +3853,7 @@ No translation of special characters sets is done. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/DJI.pm b/src/Image-ExifTool/lib/Image/ExifTool/DJI.pm new file mode 100644 index 00000000..4a2d8ae1 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/DJI.pm @@ -0,0 +1,223 @@ +#------------------------------------------------------------------------------ +# File: DJI.pm +# +# Description: DJI Phantom maker notes tags +# +# Revisions: 2016-07-25 - P. Harvey Created +# 2017-06-23 - PH Added XMP tags +#------------------------------------------------------------------------------ + +package Image::ExifTool::DJI; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); +use Image::ExifTool::Exif; +use Image::ExifTool::XMP; +use Image::ExifTool::GPS; + +$VERSION = '1.06'; + +sub ProcessDJIInfo($$$); + +my %convFloat2 = ( + PrintConv => 'sprintf("%+.2f", $val)', + PrintConvInv => '$val', +); + +# DJI maker notes (ref PH, mostly educated guesses based on DJI QuickTime::UserData tags) +%Image::ExifTool::DJI::Main = ( + WRITE_PROC => \&Image::ExifTool::Exif::WriteExif, + CHECK_PROC => \&Image::ExifTool::Exif::CheckExif, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + NOTES => q{ + This table lists tags found in the maker notes of images from some DJI + Phantom drones. + }, + 0x01 => { Name => 'Make', Writable => 'string' }, + # 0x02 - int8u[4]: "1 0 0 0", "1 1 0 0" + 0x03 => { Name => 'SpeedX', Writable => 'float', %convFloat2 }, # (guess) + 0x04 => { Name => 'SpeedY', Writable => 'float', %convFloat2 }, # (guess) + 0x05 => { Name => 'SpeedZ', Writable => 'float', %convFloat2 }, # (guess) + 0x06 => { Name => 'Pitch', Writable => 'float', %convFloat2 }, + 0x07 => { Name => 'Yaw', Writable => 'float', %convFloat2 }, + 0x08 => { Name => 'Roll', Writable => 'float', %convFloat2 }, + 0x09 => { Name => 'CameraPitch',Writable => 'float', %convFloat2 }, + 0x0a => { Name => 'CameraYaw', Writable => 'float', %convFloat2 }, + 0x0b => { Name => 'CameraRoll', Writable => 'float', %convFloat2 }, +); + +# DJI debug maker notes +%Image::ExifTool::DJI::Info = ( + PROCESS_PROC => \&ProcessDJIInfo, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + NOTES => 'Tags written by some DJI drones.', + VARS => { LONG_TAGS => 2 }, + ae_dbg_info => { Name => 'AEDebugInfo' }, + ae_histogram_info => { Name => 'AEHistogramInfo' }, + ae_local_histogram => { Name => 'AELocalHistogram' }, + ae_liveview_histogram_info => { Name => 'AELiveViewHistogramInfo' }, + ae_liveview_local_histogram => { Name => 'AELiveViewLocalHistogram' }, + awb_dbg_info => { Name => 'AWBDebugInfo' }, + af_dbg_info => { Name => 'AFDebugInfo' }, + hiso => { Name => 'Histogram' }, + xidiri => { Name => 'Xidiri' }, + 'GimbalDegree(Y,P,R)'=> { Name => 'GimbalDegree' }, + 'FlightDegree(Y,P,R)'=> { Name => 'FlightDegree' }, + adj_dbg_info => { Name => 'ADJDebugInfo' }, + sensor_id => { Name => 'SensorID' }, + 'FlightSpeed(X,Y,Z)' => { Name => 'FlightSpeed' }, + hyperlapse_dbg_info => { Name => 'HyperlapsDebugInfo' }, +); + +# thermal parameters in APP4 of DJI ZH20T images (ref forum11401) +%Image::ExifTool::DJI::ThermalParams = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 0 => 'APP4', 2 => 'Image' }, + NOTES => 'Thermal parameters extracted from APP4 of DJI RJPEG files from the ZH20T.', + # 0x00 - 0xaa551206 - temperature header magic number + 0x24 => { Name => 'K1', Format => 'float' }, + 0x28 => { Name => 'K2', Format => 'float' }, + 0x2c => { Name => 'K3', Format => 'float' }, + 0x30 => { Name => 'K4', Format => 'float' }, + 0x34 => { Name => 'KF', Format => 'float' }, + 0x38 => { Name => 'B1', Format => 'float' }, + 0x3c => { Name => 'B2', Format => 'float' }, + 0x44 => { Name => 'ObjectDistance', Format => 'int16u' }, + 0x46 => { Name => 'RelativeHumidity', Format => 'int16u' }, + 0x48 => { Name => 'Emissivity', Format => 'int16u' }, + 0x4a => { Name => 'Reflection', Format => 'int16u', }, + 0x4c => { Name => 'AmbientTemperature', Format => 'int16u' }, # (aka D1) + 0x50 => { Name => 'D2', Format => 'int32s' }, + 0x54 => { Name => 'KJ', Format => 'int16u' }, + 0x56 => { Name => 'DB', Format => 'int16u' }, + 0x58 => { Name => 'KK', Format => 'int16u' }, + # 0x500 - 0x55aa1206 - device header magic number + # (nothing yet decoded from device header) +); + +%Image::ExifTool::DJI::XMP = ( + %Image::ExifTool::XMP::xmpTableDefaults, + GROUPS => { 0 => 'XMP', 1 => 'XMP-drone-dji', 2 => 'Location' }, + NAMESPACE => 'drone-dji', + TABLE_DESC => 'XMP DJI', + VARS => { NO_ID => 1 }, + NOTES => 'XMP tags used by DJI for images from drones.', + AbsoluteAltitude => { Writable => 'real' }, + RelativeAltitude => { Writable => 'real' }, + GimbalRollDegree => { Writable => 'real' }, + GimbalYawDegree => { Writable => 'real' }, + GimbalPitchDegree => { Writable => 'real' }, + FlightRollDegree => { Writable => 'real' }, + FlightYawDegree => { Writable => 'real' }, + FlightPitchDegree => { Writable => 'real' }, + GpsLatitude => { + Name => 'GPSLatitude', + Writable => 'real', + Avoid => 1, + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lat")', + }, + GpsLongtitude => { # (sic) + Name => 'GPSLongtitude', + Writable => 'real', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")', + }, + GpsLongitude => { #PH (NC) + Name => 'GPSLongitude', + Writable => 'real', + Avoid => 1, + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")', + }, + FlightXSpeed => { Writable => 'real' }, + FlightYSpeed => { Writable => 'real' }, + FlightZSpeed => { Writable => 'real' }, + CamReverse => { }, # integer? + GimbalReverse => { }, # integer? + SelfData => { Groups => { 2 => 'Image' } }, + CalibratedFocalLength => { Writable => 'real', Groups => { 2 => 'Image' } }, + CalibratedOpticalCenterX => { Writable => 'real', Groups => { 2 => 'Image' } }, + CalibratedOpticalCenterY => { Writable => 'real', Groups => { 2 => 'Image' } }, + RtkFlag => { }, # integer? + RtkStdLon => { Writable => 'real' }, + RtkStdLat => { Writable => 'real' }, + RtkStdHgt => { Writable => 'real' }, + DewarpData => { Groups => { 2 => 'Image' } }, + DewarpFlag => { Groups => { 2 => 'Image' } }, # integer? + Latitude => { + Name => 'Latitude', + Writable => 'real', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lat")', + }, + Longitude => { + Name => 'Longitude', + Writable => 'real', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")', + }, +); + +#------------------------------------------------------------------------------ +# Process DJI infor (ref PH) +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub ProcessDJIInfo($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dirStart = $$dirInfo{DirStart} || 0; + my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $dirStart); + if ($dirStart) { + my $buff = substr($$dataPt, $dirStart, $dirLen); + $dataPt = \$buff; + } + while ($$dataPt =~ /\G\[(.*?)\](?=(\[|$))/sg) { + my ($tag, $val) = split /:/, $1, 2; + next unless defined $tag and defined $val; + if ($val =~ /^([\x20-\x7f]+)\0*$/) { + $val = $1; + } else { + my $buff = $val; + $val = \$buff; + } + if (not $$tagTbl{$tag} and $tag=~ /^[-_a-zA-Z0-9]+$/) { + my $name = $tag; + $name =~ s/_([a-z])/_\U$1/g; + AddTagToTable($tagTbl, $tag, { Name => Image::ExifTool::MakeTagName($name) }); + } + $et->HandleTag($tagTbl, $tag, $val); + } + return 1; +} + +__END__ + +=head1 NAME + +Image::ExifTool::DJI - DJI Phantom maker notes tags + +=head1 SYNOPSIS + +This module is loaded automatically by Image::ExifTool when required. + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to interpret +the maker notes in images from some DJI Phantom drones. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/DJI Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut diff --git a/src/Image-ExifTool/lib/Image/ExifTool/DNG.pm b/src/Image-ExifTool/lib/Image/ExifTool/DNG.pm index 07e057be..9c0babfe 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/DNG.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/DNG.pm @@ -616,7 +616,7 @@ sub ProcessAdobeIFD($$$) # parse the mutilated IFD. This is similar to a TIFF IFD, except: # - data follows directly after Count entry in IFD - # - byte order of IFD entires is always big-endian, but byte order of data changes + # - byte order of IFD entries is always big-endian, but byte order of data changes SetByteOrder('MM'); # IFD structure is always big-endian my $entries = Get16u($dataPt, $pos + 2); $et->VerboseDir($dirInfo, $entries); @@ -680,8 +680,14 @@ sub ProcessAdobeMakN($$$) my $dataPos = $$dirInfo{DataPos}; my $hdrLen = 6; - # hack for extra 12 bytes in MakN header of JPEG converted to DNG by Adobe Camera Raw - # (4 bytes "00 00 00 01" followed by 8 unknown bytes) + # 2018-09-27: hack for extra 12 bytes in MakN header of JPEG converted to DNG + # by Adobe Camera Raw (4 bytes "00 00 00 01" followed by 8 unknown bytes) + # - this is because CameraRaw copies the maker notes from the wrong location + # in a JPG image (off by 12 bytes presumably due to the JPEG headers) + # - this hack won't work in most cases because the extra bytes are not consistent + # since they are just the data that existed in the JPG before the maker notes + # - also, the last 12 bytes of the maker notes will be missing + # - 2022-04-26: this bug still exists in Camera Raw 14.3 $hdrLen += 12 if $len >= 18 and substr($$dataPt, $start+6, 4) eq "\0\0\0\x01"; my $dirStart = $start + $hdrLen; # pointer to maker note directory @@ -820,7 +826,7 @@ information in DNG (Digital Negative) images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/DPX.pm b/src/Image-ExifTool/lib/Image/ExifTool/DPX.pm index 0b59fa99..a10b9dcf 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/DPX.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/DPX.pm @@ -6,6 +6,7 @@ # Revisions: 2013-09-19 - P. Harvey created # # References: 1) http://www.cineon.com/ff_draft.php +# 2) Harry Mallon private communication #------------------------------------------------------------------------------ package Image::ExifTool::DPX; @@ -14,7 +15,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.03'; +$VERSION = '1.06'; # DPX tags %Image::ExifTool::DPX::Main = ( @@ -86,6 +87,56 @@ $VERSION = '1.03'; 156 => 'User-defined 8 component element', }, }, + 801 => { #2 + Name => 'TransferCharacteristic', + Format => 'int8u', + PrintConv => { + 0 => 'User-defined', + 1 => 'Printing density', + 2 => 'Linear', + 3 => 'Logarithmic', + 4 => 'Unspecified video', + 5 => 'SMPTE 274M', + 6 => 'ITU-R 704-4', + 7 => 'ITU-R 601-5 system B or G (625)', + 8 => 'ITU-R 601-5 system M (525)', + 9 => 'Composite video (NTSC)', + 10 => 'Composite video (PAL)', + 11 => 'Z (depth) - linear', + 12 => 'Z (depth) - homogeneous', + 13 => 'SMPTE ADX', + 14 => 'ITU-R 2020 NCL', + 15 => 'ITU-R 2020 CL', + 16 => 'IEC 61966-2-4 xvYCC', + 17 => 'ITU-R 2100 NCL/PQ', + 18 => 'ITU-R 2100 ICtCp/PQ', + 19 => 'ITU-R 2100 NCL/HLG', + 20 => 'ITU-R 2100 ICtCp/HLG', + 21 => 'RP 431-2:2011 Gama 2.6', + 22 => 'IEC 61966-2-1 sRGB', + }, + }, + 802 => { #2 + Name => 'ColorimetricSpecification', + Format => 'int8u', + PrintConv => { + 0 => 'User-defined', + 1 => 'Printing density', + 4 => 'Unspecified video', + 5 => 'SMPTE 274M', + 6 => 'ITU-R 704-4', + 7 => 'ITU-R 601-5 system B or G (625)', + 8 => 'ITU-R 601-5 system M (525)', + 9 => 'Composite video (NTSC)', + 10 => 'Composite video (PAL)', + 13 => 'SMPTE ADX', + 14 => 'ITU-R 2020', + 15 => 'P3D65', + 16 => 'P3DCI', + 17 => 'P3D60', + 18 => 'ACES', + }, + }, 803 => { Name => 'BitDepth', Format => 'int8u' }, 820 => { Name => 'ImageDescription', Format => 'string[32]' }, 892 => { Name => 'Image2Description', Format => 'string[32]', RawConv => '$val=~/[^\xff]/ ? $val : undef' }, @@ -105,10 +156,24 @@ $VERSION = '1.03'; 1532=> { Name => 'SourceCreateDate', Format => 'string[24]' }, 1556=> { Name => 'InputDeviceName', Format => 'string[32]' }, 1588=> { Name => 'InputDeviceSerialNumber', Format => 'string[32]' }, - # 1620=> { Name => 'AspectRatio', Format => 'int32u' }, - 1724 => { Name => 'FrameRate', Format => 'float' }, + # 1620 => { Name => 'Border', Format => 'int16u[4]' }, + 1628 => { + Name => 'AspectRatio', + Format => 'int32u[2]', + RawConv => '$val =~ /4294967295/ ? undef : $val', # ignore undefined values + PrintConv => q{ + return 'undef' if $val eq '0 0'; + return 'inf' if $val=~/ 0$/; + my @a=split(' ',$val); + return join(':', Rationalize($a[0]/$a[1])); + }, + }, + 1724 => { Name => 'OriginalFrameRate',Format => 'float' }, + 1728 => { Name => 'ShutterAngle', Format => 'float', RawConv => '($val =~ /\d/ and $val !~ /nan/i) ? $val : undef' }, #2 1732 => { Name => 'FrameID', Format => 'string[32]' }, 1764 => { Name => 'SlateInformation', Format => 'string[100]' }, + 1920 => { Name => 'TimeCode', Format => 'int32u' }, #2 + 1940 => { Name => 'FrameRate', Format => 'float', RawConv => '($val =~ /\d/ and $val !~ /nan/i) ? $val : undef' }, #2 1972 => { Name => 'Reserved5', Format => 'string[76]', Unknown => 1 }, 2048 => { Name => 'UserID', Format => 'string[32]' }, ); @@ -160,7 +225,7 @@ metadata from DPX (Digital Picture Exchange) images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/DV.pm b/src/Image-ExifTool/lib/Image/ExifTool/DV.pm index 03a6c483..55109a7d 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/DV.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/DV.pm @@ -15,7 +15,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.01'; +$VERSION = '1.02'; # DV profiles (ref 1) my @dvProfiles = ( @@ -24,7 +24,6 @@ my @dvProfiles = ( VideoSType => 0x0, FrameSize => 120000, VideoFormat => 'IEC 61834, SMPTE-314M - 525/60 (NTSC)', - VideoScanType => 'Progressive', Colorimetry => '4:1:1', FrameRate => 30000/1001, ImageHeight => 480, @@ -34,7 +33,6 @@ my @dvProfiles = ( VideoSType => 0x0, FrameSize => 144000, VideoFormat => 'IEC 61834 - 625/50 (PAL)', - VideoScanType => 'Progressive', Colorimetry => '4:2:0', FrameRate => 25/1, ImageHeight => 576, @@ -44,7 +42,6 @@ my @dvProfiles = ( VideoSType => 0x0, FrameSize => 144000, VideoFormat => 'SMPTE-314M - 625/50 (PAL)', - VideoScanType => 'Progressive', Colorimetry => '4:1:1', FrameRate => 25/1, ImageHeight => 576, @@ -54,7 +51,6 @@ my @dvProfiles = ( VideoSType => 0x4, FrameSize => 240000, VideoFormat => 'DVCPRO50: SMPTE-314M - 525/60 (NTSC) 50 Mbps', - VideoScanType => 'Progressive', Colorimetry => '4:2:2', FrameRate => 30000/1001, ImageHeight => 480, @@ -64,7 +60,6 @@ my @dvProfiles = ( VideoSType => 0x4, FrameSize => 288000, VideoFormat => 'DVCPRO50: SMPTE-314M - 625/50 (PAL) 50 Mbps', - VideoScanType => 'Progressive', Colorimetry => '4:2:2', FrameRate => 25/1, ImageHeight => 576, @@ -74,7 +69,6 @@ my @dvProfiles = ( VideoSType => 0x14, FrameSize => 480000, VideoFormat => 'DVCPRO HD: SMPTE-370M - 1080i60 100 Mbps', - VideoScanType => 'Interlaced', Colorimetry => '4:2:2', FrameRate => 30000/1001, ImageHeight => 1080, @@ -84,7 +78,6 @@ my @dvProfiles = ( VideoSType => 0x14, FrameSize => 576000, VideoFormat => 'DVCPRO HD: SMPTE-370M - 1080i50 100 Mbps', - VideoScanType => 'Interlaced', Colorimetry => '4:2:2', FrameRate => 25/1, ImageHeight => 1080, @@ -94,7 +87,6 @@ my @dvProfiles = ( VideoSType => 0x18, FrameSize => 240000, VideoFormat => 'DVCPRO HD: SMPTE-370M - 720p60 100 Mbps', - VideoScanType => 'Progressive', Colorimetry => '4:2:2', FrameRate => 60000/1001, ImageHeight => 720, @@ -104,7 +96,6 @@ my @dvProfiles = ( VideoSType => 0x18, FrameSize => 288000, VideoFormat => 'DVCPRO HD: SMPTE-370M - 720p50 100 Mbps', - VideoScanType => 'Progressive', Colorimetry => '4:2:2', FrameRate => 50/1, ImageHeight => 720, @@ -114,7 +105,6 @@ my @dvProfiles = ( VideoSType => 0x1, FrameSize => 144000, VideoFormat => 'IEC 61883-5 - 625/50 (PAL)', - VideoScanType => 'Progressive', Colorimetry => '4:2:0', FrameRate => 25/1, ImageHeight => 576, @@ -136,6 +126,7 @@ my @dvTags = ( VARS => { NO_ID => 1 }, NOTES => 'The following tags are extracted from DV videos.', DateTimeOriginal => { + Description => 'Date/Time Original', Groups => { 2 => 'Time' }, PrintConv => '$self->ConvertDateTime($val)', }, @@ -182,7 +173,7 @@ sub ProcessDV($$) $et->SetFileType(); my $pos = $start; - my $dsf = Get8u(\$buff, $pos + 3) & 0x80 >> 7; + my $dsf = (Get8u(\$buff, $pos + 3) & 0x80) >> 7; my $stype = Get8u(\$buff, $pos + 80*5 + 48 + 3) & 0x1f; # 576i50 25Mbps 4:1:1 is a special case @@ -207,7 +198,8 @@ sub ProcessDV($$) # read DVPack metadata from the VAUX DIF's to extract video tags delete $$profile{DateTimeOriginal}; delete $$profile{AspectRatio}; - my ($date, $time, $is16_9); + delete $$profile{VideoScanType}; + my ($date, $time, $is16_9, $interlace); for ($i=1; $i<6; ++$i) { $pos += 80; my $type = Get8u(\$buff, $pos); @@ -219,6 +211,7 @@ sub ProcessDV($$) my $apt = Get8u(\$buff, $start + 4) & 0x07; my $t = Get8u(\$buff, $p + 2); $is16_9 = (($t & 0x07) == 0x02 or (not $apt and ($t & 0x07) == 0x07)); + $interlace = Get8u(\$buff, $p + 3) & 0x10; # (ref 2) } elsif ($type == 0x62) { # date # mask off unused bits my @d = unpack('C*', substr($buff, $p + 1, 4)); @@ -244,7 +237,10 @@ sub ProcessDV($$) } if ($date and $time) { $$profile{DateTimeOriginal} = "$date $time"; - $$profile{AspectRatio} = $is16_9 ? '16:9' : '5:4' if defined $is16_9; + if (defined $is16_9) { + $$profile{AspectRatio} = $is16_9 ? '16:9' : '4:3'; + $$profile{VideoScanType} = $interlace ? 'Interlaced' : 'Progressive'; + } } # read audio tags if available @@ -295,7 +291,7 @@ information from DV (raw Digital Video) files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/DarwinCore.pm b/src/Image-ExifTool/lib/Image/ExifTool/DarwinCore.pm index e0aed749..4cc95c71 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/DarwinCore.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/DarwinCore.pm @@ -6,7 +6,7 @@ # Revisions: 2013-01-28 - P. Harvey Created # # References: 1) http://rs.tdwg.org/dwc/index.htm -# 2) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,4442.0/all.html +# 2) https://exiftool.org/forum/index.php/topic,4442.0/all.html #------------------------------------------------------------------------------ package Image::ExifTool::DarwinCore; @@ -15,7 +15,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool::XMP; -$VERSION = '1.02'; +$VERSION = '1.07'; my %dateTimeInfo = ( # NOTE: Do NOT put "Groups" here because Groups hash must not be common! @@ -28,7 +28,7 @@ my %dateTimeInfo = ( my %materialSample = ( STRUCT_NAME => 'DarwinCore MaterialSample', NAMESPACE => 'dwc', - materialSampleID => { }, + materialSampleID => { }, ); my %event = ( @@ -38,9 +38,28 @@ my %event = ( earliestDate => { %dateTimeInfo, Groups => { 2 => 'Time' } }, endDayOfYear => { Writable => 'integer', Groups => { 2 => 'Time' } }, eventDate => { %dateTimeInfo, Groups => { 2 => 'Time' } }, - eventID => { }, + eventID => { Avoid => 1, Notes => 'avoided in favor of XMP-iptcExt:EventID' }, eventRemarks => { Writable => 'lang-alt' }, - eventTime => { %dateTimeInfo, Groups => { 2 => 'Time' } }, + eventTime => { + Groups => { 2 => 'Time' }, + Writable => 'string', # (so we can format this ourself) + Shift => 'Time', + # (allow date/time or just time value) + ValueConv => 'Image::ExifTool::XMP::ConvertXMPDate($val)', + PrintConv => '$self->ConvertDateTime($val)', + ValueConvInv => 'Image::ExifTool::XMP::FormatXMPDate($val) or $val', + PrintConvInv => q{ + my $v = $self->InverseDateTime($val,undef,1); + undef $Image::ExifTool::evalWarning; + return $v if $v; + # allow time-only values by adding dummy date (thanks Herb) + my $v = $self->InverseDateTime("2000:01:01 $val",undef,1); + undef $Image::ExifTool::evalWarning; + return $v if $v and $v =~ s/.* //; # strip off dummy date + $Image::ExifTool::evalWarning = 'Invalid date/time or time-only value (use HH:MM:SS[.ss][+/-HH:MM|Z])'; + return undef; + }, + }, fieldNotes => { }, fieldNumber => { }, habitat => { }, @@ -119,6 +138,9 @@ my %event = ( identificationVerificationStatus => { }, identifiedBy => { }, typeStatus => { }, + # new, ref forum13707 + identifiedByID => { }, + verbatimIdentification => { }, }, }, LivingSpecimen => { Struct => \%materialSample }, @@ -170,6 +192,11 @@ my %event = ( recordNumber => { }, reproductiveCondition => { }, sex => { }, + # new, ref forum13707 + degreeOfEstablishment => { }, + georeferenceVerificationStatus => { }, + pathway => { }, + recordedByID => { }, }, }, OccurrenceOccurrenceDetails => { Name => 'OccurrenceDetails', Flat => 1 }, @@ -223,6 +250,7 @@ my %event = ( relationshipRemarks => { }, resourceID => { }, resourceRelationshipID => { }, + relationshipOfResourceID => { }, # new, ref forum13707 }, }, Taxon => { @@ -236,6 +264,7 @@ my %event = ( genus => { }, higherClassification => { }, infraspecificEpithet => { }, + cultivarEpithet => { }, # new, ref forum13707 kingdom => { }, nameAccordingTo => { }, nameAccordingToID => { }, @@ -319,6 +348,8 @@ my %event = ( verbatimLongitude => { }, verbatimSRS => { }, waterBody => { }, + # new, ref forum13707 + verticalDatum => { }, }, }, ); @@ -341,7 +372,7 @@ This file contains tag definitions for the Darwin Core XMP namespace. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/DjVu.pm b/src/Image-ExifTool/lib/Image/ExifTool/DjVu.pm index 13a2006e..2b0c03a7 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/DjVu.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/DjVu.pm @@ -18,7 +18,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.06'; +$VERSION = '1.07'; sub ParseAnt($); sub ProcessAnt($$$); @@ -227,16 +227,16 @@ Tok: for (;;) { last unless $tok =~ /(\\+)$/ and length($1) & 0x01; $tok .= '"'; # quote is part of the string } - # must protect unescaped "$" and "@" symbols, and "\" at end of string - $tok =~ s{\\(.)|([\$\@]|\\$)}{'\\'.($2 || $1)}sge; - # convert C escape sequences (allowed in quoted text) - $tok = eval qq{"$tok"}; + # convert C escape sequences, allowed in quoted text + # (note: this only converts a few of them!) + my %esc = ( a => "\a", b => "\b", f => "\f", n => "\n", + r => "\r", t => "\t", '"' => '"', '\\' => '\\' ); + $tok =~ s/\\(.)/$esc{$1}||'\\'.$1/egs; } else { # key name pos($$dataPt) = pos($$dataPt) - 1; # allow anything in key but whitespace, braces and double quotes # (this is one of those assumptions I mentioned) - $$dataPt =~ /([^\s()"]+)/sg; - $tok = $1; + $tok = $$dataPt =~ /([^\s()"]+)/sg ? $1 : undef; } push @toks, $tok if defined $tok; } @@ -353,7 +353,7 @@ Image::ExifTool::AIFF. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/EXE.pm b/src/Image-ExifTool/lib/Image/ExifTool/EXE.pm index cc899dba..a2e9173e 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/EXE.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/EXE.pm @@ -21,7 +21,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.15'; +$VERSION = '1.18'; sub ProcessPEResources($$); sub ProcessPEVersion($$); @@ -52,6 +52,10 @@ my %resourceType = ( ); my %languageCode = ( + Notes => q{ + See L<https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid> + for the full list of Microsoft language codes. + }, '0000' => 'Neutral', '007F' => 'Invariant', '0400' => 'Process default', @@ -397,7 +401,7 @@ my %languageCode = ( existing StringFileInfo tags even if not listed in this table. }, LanguageCode => { - Notes => 'extracted from the StringFileInfo value', + Notes => 'Windows code page; extracted from the StringFileInfo value', # ref http://techsupt.winbatch.com/TS/T000001050F49.html # (also see http://support.bigfix.com/fixlet/documents/WinInspectors-2006-08-10.pdf) # (also see ftp://ftp.dyu.edu.tw/pub/cpatch/faq/tech/tech_nlsnt.txt) @@ -1005,7 +1009,7 @@ sub ProcessPEDict($$) my $raf = $$dirInfo{RAF}; my $dataPt = $$dirInfo{DataPt}; my $dirLen = length($$dataPt); - my ($pos, @sections, %dirInfo); + my ($pos, @sections, %dirInfo, $rsrcFound); # loop through all sections for ($pos=0; $pos+40<=$dirLen; $pos+=40) { @@ -1015,14 +1019,16 @@ sub ProcessPEDict($$) my $offset = Get32u($dataPt, $pos + 20); # remember the section offsets for the VirtualAddress lookup later push @sections, { Base => $offset, Size => $size, VirtualAddress => $va }; - # save details of the first resource section + # save details of the first resource section (or .text if .rsrc not found, ref forum11465) + next unless ($name eq ".rsrc\0\0\0" and not $rsrcFound and defined($rsrcFound = 1)) or + ($name eq ".text\0\0\0" and not %dirInfo); %dirInfo = ( RAF => $raf, Base => $offset, DirStart => 0, # (relative to Base) DirLen => $size, Sections => \@sections, - ) if $name eq ".rsrc\0\0\0" and not %dirInfo; + ); } # process the first resource section ProcessPEResources($et, \%dirInfo) or return 0 if %dirInfo; @@ -1140,7 +1146,8 @@ sub ProcessEXE($$) my $fileSize = ($cp - ($cblp ? 1 : 0)) * 512 + $cblp; #(patch to accommodate observed 64-bit files) #return 0 if $fileSize < 0x40 or $fileSize < $lfarlc; - return 0 if $fileSize < 0x40; + #return 0 if $fileSize < 0x40; (changed to warning in ExifTool 12.08) + $et->Warn('Invalid file size in DOS header') if $fileSize < 0x40; # read the Windows NE, PE or LE (virtual device driver) header #if ($lfarlc == 0x40 and $fileSize > $lfanew + 2 and ... if ($raf->Seek($lfanew, 0) and $raf->Read($buff, 0x40) and $buff =~ /^(NE|PE|LE)/) { @@ -1226,6 +1233,14 @@ sub ProcessEXE($$) $tagTablePtr = GetTagTable('Image::ExifTool::EXE::MachO'); if ($1 eq "\xca\xfe\xba\xbe") { SetByteOrder('MM'); + my $ver = Get32u(\$buff, 4); + # Java bytecode .class files have the same magic number, so we need to look deeper + # (ref https://github.com/file/file/blob/master/magic/Magdir/cafebabe#L6-L15) + if ($ver > 30) { + # this is Java bytecode + $et->SetFileType('Java bytecode', 'application/java-byte-code', 'class'); + return 1; + } $et->SetFileType('Mach-O fat binary executable', undef, ''); return 1 if $fast3; my $count = Get32u(\$buff, 4); # get architecture count @@ -1362,7 +1377,7 @@ sub ProcessEXE($$) python => 'py', ruby => 'rb', php => 'php', - }->{$1}; + }->{$prog}; # use '.sh' for extension of all shell scripts $ext = $prog =~ /sh$/ ? 'sh' : '' unless defined $ext; } @@ -1391,7 +1406,7 @@ library files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Exif.pm b/src/Image-ExifTool/lib/Image/ExifTool/Exif.pm index a516f866..09bc1893 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Exif.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Exif.pm @@ -42,6 +42,7 @@ # 29) http://www.libtiff.org # 30) http://geotiff.maptools.org/spec/geotiffhome.html # 31) https://android.googlesource.com/platform/external/dng_sdk/+/refs/heads/master/source/dng_tag_codes.h +# 32) Jeffry Friedl private communication # IB) Iliah Borg private communication (LibRaw) # JD) Jens Duttke private communication #------------------------------------------------------------------------------ @@ -55,7 +56,7 @@ use vars qw($VERSION $AUTOLOAD @formatSize @formatName %formatNumber %intFormat use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::MakerNotes; -$VERSION = '4.07'; +$VERSION = '4.41'; sub ProcessExif($$$); sub WriteExif($$$); @@ -67,6 +68,7 @@ sub ValidateImageData($$$;$); sub ProcessTiffIFD($$$); sub PrintParameter($$$); sub GetOffList($$$$$); +sub PrintOpcode($$$); sub PrintLensInfo($); sub ConvertLensInfo($); @@ -262,6 +264,8 @@ sub BINARY_DATA_LIMIT { return 10 * 1024 * 1024; } 32845 => 'Pixar LogLuv', #3 32892 => 'Sequential Color Filter', #JR (Sony ARQ) 34892 => 'Linear Raw', #2 + 51177 => 'Depth Map', # (DNG 1.5) + 52527 => 'Semantic Mask', # (DNG 1.6) ); %orientation = ( @@ -276,7 +280,7 @@ sub BINARY_DATA_LIMIT { return 10 * 1024 * 1024; } ); %subfileType = ( - 0 => 'Full-resolution Image', + 0 => 'Full-resolution image', 1 => 'Reduced-resolution image', 2 => 'Single page of multi-page image', 3 => 'Single page of multi-page reduced-resolution image', @@ -284,14 +288,18 @@ sub BINARY_DATA_LIMIT { return 10 * 1024 * 1024; } 5 => 'Transparency mask of reduced-resolution image', 6 => 'Transparency mask of multi-page image', 7 => 'Transparency mask of reduced-resolution multi-page image', + 8 => 'Depth map', # (DNG 1.5) + 9 => 'Depth map of reduced-resolution image', # (DNG 1.5) + 16 => 'Enhanced image data', # (DNG 1.5) 0x10001 => 'Alternate reduced-resolution image', # (DNG 1.2) + 0x10004 => 'Semantic Mask', # (DNG 1.6) 0xffffffff => 'invalid', #(found in E5700 NEF's) BITMASK => { 0 => 'Reduced resolution', 1 => 'Single page', 2 => 'Transparency mask', - 3 => 'TIFF/IT final page', #20 - 4 => 'TIFF-FX mixed raster content', #20 + 3 => 'TIFF/IT final page', #20 (repurposed as DepthMap repurposes by DNG 1.5) + 4 => 'TIFF-FX mixed raster content', #20 (repurposed as EnhancedImageData by DNG 1.5) }, ); @@ -315,6 +323,7 @@ my %utf8StringConv = ( my %longBin = ( ValueConv => 'length($val) > 64 ? \$val : $val', ValueConvInv => '$val', + LongBinary => 1, # flag to avoid decoding values of a large array ); # PrintConv for SampleFormat (0x153) @@ -336,6 +345,34 @@ my %sampleFormat = ( 0x115 => 1, # SamplesPerPixel ); +# conversions for DNG OpcodeList tags +my %opcodeInfo = ( + Writable => 'undef', + WriteGroup => 'SubIFD', + Protected => 1, + Binary => 1, + ConvertBinary => 1, # needed because the ValueConv value is binary + PrintConvColumns => 2, + PrintConv => { + OTHER => \&PrintOpcode, + 1 => 'WarpRectilinear', + 2 => 'WarpFisheye', + 3 => 'FixVignetteRadial', + 4 => 'FixBadPixelsConstant', + 5 => 'FixBadPixelsList', + 6 => 'TrimBounds', + 7 => 'MapTable', + 8 => 'MapPolynomial', + 9 => 'GainMap', + 10 => 'DeltaPerRow', + 11 => 'DeltaPerColumn', + 12 => 'ScalePerRow', + 13 => 'ScalePerColumn', + 14 => 'WarpRectilinear2', # (DNG 1.6) + }, + PrintConvInv => undef, # (so the inverse conversion is not performed) +); + # main EXIF tag table %Image::ExifTool::Exif::Main = ( GROUPS => { 0 => 'EXIF', 1 => 'IFD0', 2 => 'Image'}, @@ -378,7 +415,14 @@ my %sampleFormat = ( WriteGroup => 'IFD0', # set priority directory if this is the full resolution image DataMember => 'SubfileType', - RawConv => '$self->SetPriorityDir() if $val eq "0"; $$self{SubfileType} = $val', + RawConv => q{ + if ($val == ($val & 0x02)) { + $self->SetPriorityDir() if $val == 0; + $$self{PageCount} = ($$self{PageCount} || 0) + 1; + $$self{MultiPage} = 1 if $val == 2 or $$self{PageCount} > 1; + } + $$self{SubfileType} = $val; + }, PrintConv => \%subfileType, }, 0xff => { @@ -388,7 +432,14 @@ my %sampleFormat = ( Writable => 'int16u', WriteGroup => 'IFD0', # set priority directory if this is the full resolution image - RawConv => '$self->SetPriorityDir() if $val eq "1"; $val', + RawConv => q{ + if ($val == 1 or $val == 3) { + $self->SetPriorityDir() if $val == 1; + $$self{PageCount} = ($$self{PageCount} || 0) + 1; + $$self{MultiPage} = 1 if $val == 3 or $$self{PageCount} > 1; + } + $val; + }, PrintConv => { 1 => 'Full-resolution image', 2 => 'Reduced-resolution image', @@ -404,7 +455,7 @@ my %sampleFormat = ( Writable => 'int32u', WriteGroup => 'IFD0', # Note: priority 0 tags automatically have their priority increased for the - # priority direcory (the directory with a SubfileType of "Full-resolution image") + # priority directory (the directory with a SubfileType of "Full-resolution image") Priority => 0, }, 0x101 => { @@ -530,7 +581,7 @@ my %sampleFormat = ( # (APP1 IFD2 is for Leica JPEG preview) Condition => q[ not ($$self{TIFF_TYPE} eq 'CR2' and $$self{DIR_NAME} eq 'IFD0') and - not ($$self{TIFF_TYPE} eq 'DNG' and $$self{Compression} eq '7' and $$self{SubfileType} ne '0') and + not ($$self{TIFF_TYPE} =~ /^(DNG|TIFF)$/ and $$self{Compression} eq '7' and $$self{SubfileType} ne '0') and not ($$self{TIFF_TYPE} eq 'APP1' and $$self{DIR_NAME} eq 'IFD2') ], Name => 'StripOffsets', @@ -616,7 +667,7 @@ my %sampleFormat = ( # (APP1 IFD2 is for Leica JPEG preview) Condition => q[ not ($$self{TIFF_TYPE} eq 'CR2' and $$self{DIR_NAME} eq 'IFD0') and - not ($$self{TIFF_TYPE} eq 'DNG' and $$self{Compression} eq '7' and $$self{SubfileType} ne '0') and + not ($$self{TIFF_TYPE} =~ /^(DNG|TIFF)$/ and $$self{Compression} eq '7' and $$self{SubfileType} ne '0') and not ($$self{TIFF_TYPE} eq 'APP1' and $$self{DIR_NAME} eq 'IFD2') ], Name => 'StripByteCounts', @@ -786,7 +837,8 @@ my %sampleFormat = ( Name => 'Software', Writable => 'string', WriteGroup => 'IFD0', - RawConv => '$val =~ s/\s+$//; $val', # trim trailing blanks + DataMember => 'Software', + RawConv => '$val =~ s/\s+$//; $$self{Software} = $val', # trim trailing blanks }, 0x132 => { Name => 'ModifyDate', @@ -820,6 +872,11 @@ my %sampleFormat = ( PrintConv => { 1 => 'None', 2 => 'Horizontal differencing', + 3 => 'Floating point', # (DNG 1.5) + 34892 => 'Horizontal difference X2', # (DNG 1.5) + 34893 => 'Horizontal difference X4', # (DNG 1.5) + 34894 => 'Floating point X2', # (DNG 1.5) + 34895 => 'Floating point X4', # (DNG 1.5) }, }, 0x13e => { @@ -1338,6 +1395,12 @@ my %sampleFormat = ( Count => 6, Priority => 0, }, + # 0x220 - int32u: 0 (IFD0, Xaiomi Redmi models) + # 0x221 - int32u: 0 (IFD0, Xaiomi Redmi models) + # 0x222 - int32u: 0 (IFD0, Xaiomi Redmi models) + # 0x223 - int32u: 0 (IFD0, Xaiomi Redmi models) + # 0x224 - int32u: 0,1 (IFD0, Xaiomi Redmi models) + # 0x225 - string: "" (IFD0, Xaiomi Redmi models) 0x22f => 'StripRowCounts', 0x2bc => { Name => 'ApplicationNotes', # (writable directory!) @@ -1407,6 +1470,7 @@ my %sampleFormat = ( 1 => 'Sony Uncompressed 12-bit RAW', #IB 2 => 'Sony Compressed RAW', # (lossy, ref IB) 3 => 'Sony Lossless Compressed RAW', #IB + 4 => 'Sony Lossless Compressed RAW 2', #JR (ILCE-1) }, }, # 0x7001 - int16u[1] (in SubIFD of Sony ARW images) - values: 0,1 @@ -1427,6 +1491,7 @@ my %sampleFormat = ( PrintConv => { 256 => 'Off', 257 => 'Auto', + 272 => 'Auto (ILCE-1)', #JR 511 => 'No correction params available', }, }, @@ -1479,6 +1544,22 @@ my %sampleFormat = ( WriteGroup => 'SubIFD', Count => 17, }, + 0x74c7 => { #IB (in ARW images from some Sony cameras) + Name => 'SonyCropTopLeft', + Writable => 'int32u', + WriteGroup => 'SubIFD', + Count => 2, + Permanent => 1, + Protected => 1, + }, + 0x74c8 => { #IB (in ARW images from some Sony cameras) + Name => 'SonyCropSize', + Writable => 'int32u', + WriteGroup => 'SubIFD', + Count => 2, + Permanent => 1, + Protected => 1, + }, 0x800d => 'ImageID', #10 0x80a3 => { Name => 'WangTag1', Binary => 1 }, #20 0x80a4 => { Name => 'WangAnnotation', Binary => 1 }, @@ -1542,19 +1623,6 @@ my %sampleFormat = ( Format => 'undef', Writable => 'string', WriteGroup => 'IFD0', - RawConvInv => '$val . "\0"', - PrintConvInv => sub { - my ($val, $self) = @_; - # encode if necessary (not automatic because Format is 'undef') - my $enc = $self->Options('CharsetEXIF'); - $val = $self->Encode($val,$enc) if $enc and $val !~ /\0/; - if ($val =~ /(.*?)\s*[\n\r]+\s*(.*)/s) { - return $1 unless length $2; - # photographer copyright set to ' ' if it doesn't exist, according to spec. - return((length($1) ? $1 : ' ') . "\0" . $2); - } - return $val; - }, Notes => q{ may contain copyright notices for photographer and editor, separated by a newline. As per the EXIF specification, the newline is replaced by a null @@ -1576,6 +1644,19 @@ my %sampleFormat = ( $val = $self->Decode($val,$enc) if $enc; return $val; }, + RawConvInv => '$val . "\0"', + PrintConvInv => sub { + my ($val, $self) = @_; + # encode if necessary (not automatic because Format is 'undef') + my $enc = $self->Options('CharsetEXIF'); + $val = $self->Encode($val,$enc) if $enc and $val !~ /\0/; + if ($val =~ /(.*?)\s*[\n\r]+\s*(.*)/s) { + return $1 unless length $2; + # photographer copyright set to ' ' if it doesn't exist, according to spec. + return((length($1) ? $1 : ' ') . "\0" . $2); + } + return $val; + }, }, 0x829a => { Name => 'ExposureTime', @@ -1600,7 +1681,12 @@ my %sampleFormat = ( 0x82aa => 'MDPrepDate', #3 0x82ab => 'MDPrepTime', #3 0x82ac => 'MDFileUnits', #3 - 0x830e => 'PixelScale', #30 + 0x830e => { #30 (GeoTiff) + Name => 'PixelScale', + Writable => 'double', + WriteGroup => 'IFD0', + Count => 3, + }, 0x8335 => 'AdventScale', #20 0x8336 => 'AdventRevision', #20 0x835c => 'UIC1Tag', #23 @@ -1627,11 +1713,19 @@ my %sampleFormat = ( }, 0x847e => 'IntergraphPacketData', #3 0x847f => 'IntergraphFlagRegisters', #3 - 0x8480 => 'IntergraphMatrix', #30 + 0x8480 => { #30 (GeoTiff, obsolete) + Name => 'IntergraphMatrix', + Writable => 'double', + WriteGroup => 'IFD0', + Count => -1, + }, 0x8481 => 'INGRReserved', #20 - 0x8482 => { #30 + 0x8482 => { #30 (GeoTiff) Name => 'ModelTiePoint', Groups => { 2 => 'Location' }, + Writable => 'double', + WriteGroup => 'IFD0', + Count => -1, }, 0x84e0 => 'Site', #9 0x84e1 => 'ColorSequence', #9 @@ -1694,9 +1788,12 @@ my %sampleFormat = ( }, 0x85b8 => 'PixelMagicJBIGOptions', #20 0x85d7 => 'JPLCartoIFD', #exifprobe (NC) - 0x85d8 => { #30 + 0x85d8 => { #30 (GeoTiff) Name => 'ModelTransform', Groups => { 2 => 'Location' }, + Writable => 'double', + WriteGroup => 'IFD0', + Count => 16, }, 0x8602 => { #16 Name => 'WB_GRGBLevels', @@ -1776,14 +1873,14 @@ my %sampleFormat = ( 0x87af => { #30 Name => 'GeoTiffDirectory', Format => 'undef', - Binary => 1, + Writable => 'int16u', Notes => q{ these "GeoTiff" tags may read and written as a block, but they aren't extracted unless specifically requested. Byte order changes are handled automatically when copying between TIFF images with different byte order }, - Writable => 'undef', WriteGroup => 'IFD0', + Binary => 1, RawConv => '$val . GetByteOrder()', # save byte order # swap byte order if necessary RawConvInv => q{ @@ -1798,9 +1895,9 @@ my %sampleFormat = ( 0x87b0 => { #30 Name => 'GeoTiffDoubleParams', Format => 'undef', - Binary => 1, - Writable => 'undef', + Writable => 'double', WriteGroup => 'IFD0', + Binary => 1, RawConv => '$val . GetByteOrder()', # save byte order # swap byte order if necessary RawConvInv => q{ @@ -1815,6 +1912,7 @@ my %sampleFormat = ( }, 0x87b1 => { #30 Name => 'GeoTiffAsciiParams', + Format => 'undef', Writable => 'string', WriteGroup => 'IFD0', Binary => 1, @@ -1926,6 +2024,7 @@ my %sampleFormat = ( 0x885d => 'FaxSubAddress', #9 0x885e => 'FaxRecvTime', #9 0x8871 => 'FedexEDR', #exifprobe (NC) + # 0x8889 - string: "portrait" (ExifIFD, Xiaomi POCO F1) 0x888a => { #PH Name => 'LeafSubIFD', Format => 'int32u', # Leaf incorrectly uses 'undef' format! @@ -1936,13 +2035,18 @@ my %sampleFormat = ( Start => '$val', }, }, + # 0x8891 - int16u: 35 (ExifIFD, Xiaomi POCO F1) + # 0x8894 - int16u: 0 (ExifIFD, Xiaomi POCO F1) + # 0x8895 - int16u: 0 (ExifIFD, Xiaomi POCO F1) + # 0x889a - int16u: 0 (ExifIFD, Xiaomi POCO F1) # 0x89ab - seen "11 100 130 16 0 0 0 0" in IFD0 of TIFF image from IR scanner (forum8470) 0x9000 => { Name => 'ExifVersion', Writable => 'undef', Mandatory => 1, RawConv => '$val=~s/\0+$//; $val', # (some idiots add null terminators) - PrintConvInv => '$val=~tr/.//d; $val=~/^\d{4}$/ ? $val : undef', + # (allow strings like "2.31" when writing) + PrintConvInv => '$val=~tr/.//d; $val=~/^\d{4}$/ ? $val : $val =~ /^\d{3}$/ ? "0$val" : undef', }, 0x9003 => { Name => 'DateTimeOriginal', @@ -2054,7 +2158,7 @@ my %sampleFormat = ( Notes => 'displayed in seconds, but stored as an APEX value', Format => 'rational64s', # Leica M8 patch (incorrectly written as rational64u) Writable => 'rational64s', - ValueConv => 'abs($val)<100 ? 2**(-$val) : 0', + ValueConv => 'IsFloat($val) && abs($val)<100 ? 2**(-$val) : 0', ValueConvInv => '$val>0 ? -log($val)/log(2) : -100', PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', @@ -2295,6 +2399,8 @@ my %sampleFormat = ( Name => 'CameraElevationAngle', Writable => 'rational64s', }, + # 0x9999 - string: camera settings (ExifIFD, Xiaomi POCO F1) + # 0x9aaa - int8u[2176]: ? (ExifIFD, Xiaomi POCO F1) 0x9c9b => { Name => 'XPTitle', Format => 'undef', @@ -2474,6 +2580,7 @@ my %sampleFormat = ( 5 => 'Color sequential area', 7 => 'Trilinear', 8 => 'Color sequential linear', + # 15 - used by DJI XT2 }, }, 0xa300 => { @@ -2491,7 +2598,7 @@ my %sampleFormat = ( 0xa301 => { Name => 'SceneType', Writable => 'undef', - ValueConvInv => 'chr($val)', + ValueConvInv => 'chr($val & 0xff)', PrintConv => { 1 => 'Directly photographed', }, @@ -2518,11 +2625,11 @@ my %sampleFormat = ( PrintConv => { 0 => 'Normal', 1 => 'Custom', - # 2 - also seen (Apple iOS) - 3 => 'HDR', # non-standard (Apple iOS) - # 4 - also seen (Apple iOS) - normal image from iOS Camera app (ref http://regex.info/blog/lightroom-goodies/metadata-presets) + 2 => 'HDR (no original saved)', #32 non-standard (Apple iOS) + 3 => 'HDR (original saved)', #32 non-standard (Apple iOS) + 4 => 'Original (for HDR)', #32 non-standard (Apple iOS) 6 => 'Panorama', # non-standard (Apple iOS, horizontal or vertical) - # 7 - also seen (Apple iOS) + 7 => 'Portrait HDR', #32 non-standard (Apple iOS) 8 => 'Portrait', # non-standard (Apple iOS, blurred background) # 9 - also seen (Apple iOS) (HDR Portrait?) }, @@ -2568,12 +2675,13 @@ my %sampleFormat = ( Name => 'SceneCaptureType', Groups => { 2 => 'Camera' }, Writable => 'int16u', + Notes => 'the value of 4 is non-standard, and used by some Samsung models', PrintConv => { 0 => 'Standard', 1 => 'Landscape', 2 => 'Portrait', 3 => 'Night', - # 4 - HDR (Samsung GT-I9300) + 4 => 'Other', # (non-standard Samsung, ref forum 5724) }, }, 0xa407 => { @@ -2665,15 +2773,85 @@ my %sampleFormat = ( 0xa433 => { Name => 'LensMake', Writable => 'string' }, #24 0xa434 => { Name => 'LensModel', Writable => 'string' }, #24 0xa435 => { Name => 'LensSerialNumber', Writable => 'string' }, #24 - 0xa480 => 'GDALMetadata', #3 - 0xa481 => 'GDALNoData', #3 - 0xa500 => { Name => 'Gamma', Writable => 'rational64u' }, + 0xa460 => { #Exif2.32 + Name => 'CompositeImage', + Writable => 'int16u', + PrintConv => { + 0 => 'Unknown', + 1 => 'Not a Composite Image', + 2 => 'General Composite Image', + 3 => 'Composite Image Captured While Shooting', + }, + }, + 0xa461 => { #Exif2.32 + Name => 'CompositeImageCount', + Notes => q{ + 2 values: 1. Number of source images, 2. Number of images used. Called + SourceImageNumberOfCompositeImage by the EXIF spec. + }, + Writable => 'int16u', + Count => 2, + }, + 0xa462 => { #Exif2.32 + Name => 'CompositeImageExposureTimes', + Notes => q{ + 11 or more values: 1. Total exposure time period, 2. Total exposure of all + source images, 3. Total exposure of all used images, 4. Max exposure time of + source images, 5. Max exposure time of used images, 6. Min exposure time of + source images, 7. Min exposure of used images, 8. Number of sequences, 9. + Number of source images in sequence. 10-N. Exposure times of each source + image. Called SourceExposureTimesOfCompositeImage by the EXIF spec. + }, + Writable => 'undef', + RawConv => sub { + my $val = shift; + my @v; + my $i = 0; + for (;;) { + if ($i == 56 or $i == 58) { + last if $i + 2 > length $val; + push @v, Get16u(\$val, $i); + $i += 2; + } else { + last if $i + 8 > length $val; + push @v, Image::ExifTool::GetRational64u(\$val, $i); + $i += 8; + } + } + return join ' ', @v; + }, + RawConvInv => sub { + my $val = shift; + my @v = split ' ', $val; + my $i; + for ($i=0; ; ++$i) { + last unless defined $v[$i]; + $v[$i] = ($i == 7 or $i == 8) ? Set16u($v[$i]) : Image::ExifTool::SetRational64u($v[$i]); + } + return join '', @v; + }, + PrintConv => sub { + my $val = shift; + my @v = split ' ', $val; + my $i; + for ($i=0; ; ++$i) { + last unless defined $v[$i]; + $v[$i] = PrintExposureTime($v[$i]) unless $i == 7 or $i == 8; + } + return join ' ', @v; + }, + PrintConvInv => '$val', + }, + 0xa480 => { Name => 'GDALMetadata', Writable => 'string', WriteGroup => 'IFD0' }, #3 + 0xa481 => { Name => 'GDALNoData', Writable => 'string', WriteGroup => 'IFD0' }, #3 + 0xa500 => { Name => 'Gamma', Writable => 'rational64u' }, 0xafc0 => 'ExpandSoftware', #JD (Opanda) 0xafc1 => 'ExpandLens', #JD (Opanda) 0xafc2 => 'ExpandFilm', #JD (Opanda) 0xafc3 => 'ExpandFilterLens', #JD (Opanda) 0xafc4 => 'ExpandScanner', #JD (Opanda) 0xafc5 => 'ExpandFlashLamp', #JD (Opanda) + 0xb4c3 => { Name => 'HasselbladRawImage', Format => 'undef', Binary => 1 }, #IB # # Windows Media Photo / HD Photo (WDP/HDP) tags # @@ -2836,6 +3014,16 @@ my %sampleFormat = ( }, PrintConvInv => '$val =~ /^PrintIM/ ? $val : undef', # quick validation }, + 0xc51b => { # (Hasselblad H3D) + Name => 'HasselbladExif', + Format => 'undef', + RawConv => q{ + $$self{DOC_NUM} = ++$$self{DOC_COUNT}; + $self->ExtractInfo(\$val, { ReEntry => 1 }); + $$self{DOC_NUM} = 0; + return undef; + }, + }, 0xc573 => { #PH Name => 'OriginalFileName', Notes => 'used by some obscure software', # (possibly Swizzy Photosmacker?) @@ -2867,12 +3055,12 @@ my %sampleFormat = ( }, }, # -# DNG tags 0xc6XX and 0xc7XX (ref 2 unless otherwise stated) +# DNG tags 0xc6XX, 0xc7XX and 0xcdXX (ref 2 unless otherwise stated) # 0xc612 => { Name => 'DNGVersion', Notes => q{ - tags 0xc612-0xc7b5 are defined by the DNG specification unless otherwise + tags 0xc612-0xcd3b are defined by the DNG specification unless otherwise noted. See L<https://helpx.adobe.com/photoshop/digital-negative.html> for the specification }, @@ -3130,7 +3318,7 @@ my %sampleFormat = ( Groups => { 1 => 'SR2' }, Flags => 'SubIFD', Format => 'int32u', - # some utilites have problems unless this is int8u format: + # some utilities have problems unless this is int8u format: # - Adobe Camera Raw 5.3 gives an error # - Apple Preview 10.5.8 gets the wrong white balance FixFormat => 'int8u', # (stupid Sony) @@ -3192,6 +3380,32 @@ my %sampleFormat = ( }, Format => 'undef', }, + { + # Ricoh models such as the GR III + Condition => '$$valPt =~ /^RICOH\0(II|MM)/', + Name => 'MakerNoteRicohPentax', + MakerNotes => 1, + Binary => 1, + WriteGroup => 'IFD0', # (for Validate) + SubDirectory => { + TagTable => 'Image::ExifTool::Pentax::Main', + Start => '$valuePtr + 8', + Base => '$start - 8', + ByteOrder => 'Unknown', + }, + Format => 'undef', + }, + # the DJI FC2103 writes some interesting stuff here (with sections labelled + # awb_dbg_info, ae_dbg_info, ae_histogram_info, af_dbg_info, hiso, xidiri) - PH + { + Name => 'MakerNoteDJIInfo', + Condition => '$$valPt =~ /^\[ae_dbg_info:/', + MakerNotes => 1, + Binary => 1, + WriteGroup => 'IFD0', # (for Validate) + SubDirectory => { TagTable => 'Image::ExifTool::DJI::Info' }, + Format => 'undef', + }, { Name => 'DNGPrivateData', Flags => [ 'Binary', 'Protected' ], @@ -3431,11 +3645,11 @@ my %sampleFormat = ( }, 0xc6fc => { Name => 'ProfileToneCurve', + %longBin, Writable => 'float', WriteGroup => 'IFD0', Count => -1, Protected => 1, - Binary => 1, }, 0xc6fd => { Name => 'ProfileEmbedPolicy', @@ -3560,47 +3774,15 @@ my %sampleFormat = ( }, 0xc726 => { Name => 'ProfileLookTableData', + %longBin, Writable => 'float', WriteGroup => 'IFD0', Count => -1, Protected => 1, - Binary => 1, - }, - 0xc740 => { # DNG 1.3 - Name => 'OpcodeList1', - Writable => 'undef', - WriteGroup => 'SubIFD', - Protected => 1, - Binary => 1, - # opcodes: - # 1 => 'WarpRectilinear', - # 2 => 'WarpFisheye', - # 3 => 'FixVignetteRadial', - # 4 => 'FixBadPixelsConstant', - # 5 => 'FixBadPixelsList', - # 6 => 'TrimBounds', - # 7 => 'MapTable', - # 8 => 'MapPolynomial', - # 9 => 'GainMap', - # 10 => 'DeltaPerRow', - # 11 => 'DeltaPerColumn', - # 12 => 'ScalePerRow', - # 13 => 'ScalePerColumn', - }, - 0xc741 => { # DNG 1.3 - Name => 'OpcodeList2', - Writable => 'undef', - WriteGroup => 'SubIFD', - Protected => 1, - Binary => 1, - }, - 0xc74e => { # DNG 1.3 - Name => 'OpcodeList3', - Writable => 'undef', - WriteGroup => 'SubIFD', - Protected => 1, - Binary => 1, }, + 0xc740 => { Name => 'OpcodeList1', %opcodeInfo }, # DNG 1.3 + 0xc741 => { Name => 'OpcodeList2', %opcodeInfo }, # DNG 1.3 + 0xc74e => { Name => 'OpcodeList3', %opcodeInfo }, # DNG 1.3 0xc761 => { # DNG 1.3 Name => 'NoiseProfile', Writable => 'double', @@ -3823,6 +4005,159 @@ my %sampleFormat = ( Count => 4, Protected => 1, }, + 0xc7d5 => { #PH (in SubIFD1 of Nikon Z6/Z7 NEF images) + Name => 'NikonNEFInfo', + Condition => '$$valPt =~ /^Nikon\0/', + SubDirectory => { + TagTable => 'Image::ExifTool::Nikon::NEFInfo', + Start => '$valuePtr + 18', + Base => '$start - 8', + ByteOrder => 'Unknown', + }, + }, + # 0xc7d6 - int8u: 1 (SubIFD1 of Nikon Z6/Z7 NEF) + 0xc7e9 => { # DNG 1.5 + Name => 'DepthFormat', + Writable => 'int16u', + Notes => 'tags 0xc7e9-0xc7ee added by DNG 1.5.0.0', + Protected => 1, + WriteGroup => 'IFD0', + PrintConv => { + 0 => 'Unknown', + 1 => 'Linear', + 2 => 'Inverse', + }, + }, + 0xc7ea => { # DNG 1.5 + Name => 'DepthNear', + Writable => 'rational64u', + Protected => 1, + WriteGroup => 'IFD0', + }, + 0xc7eb => { # DNG 1.5 + Name => 'DepthFar', + Writable => 'rational64u', + Protected => 1, + WriteGroup => 'IFD0', + }, + 0xc7ec => { # DNG 1.5 + Name => 'DepthUnits', + Writable => 'int16u', + Protected => 1, + WriteGroup => 'IFD0', + PrintConv => { + 0 => 'Unknown', + 1 => 'Meters', + }, + }, + 0xc7ed => { # DNG 1.5 + Name => 'DepthMeasureType', + Writable => 'int16u', + Protected => 1, + WriteGroup => 'IFD0', + PrintConv => { + 0 => 'Unknown', + 1 => 'Optical Axis', + 2 => 'Optical Ray', + }, + }, + 0xc7ee => { # DNG 1.5 + Name => 'EnhanceParams', + Writable => 'string', + Protected => 1, + WriteGroup => 'IFD0', + }, + 0xcd2d => { # DNG 1.6 + Name => 'ProfileGainTableMap', + Writable => 'undef', + WriteGroup => 'SubIFD', + Protected => 1, + Binary => 1, + }, + 0xcd2e => { # DNG 1.6 + Name => 'SemanticName', + # Writable => 'string', + WriteGroup => 'SubIFD' #? (NC) Semantic Mask IFD (only for Validate) + }, + 0xcd30 => { # DNG 1.6 + Name => 'SemanticInstanceIFD', + # Writable => 'string', + WriteGroup => 'SubIFD' #? (NC) Semantic Mask IFD (only for Validate) + }, + 0xcd31 => { # DNG 1.6 + Name => 'CalibrationIlluminant3', + Writable => 'int16u', + WriteGroup => 'IFD0', + Protected => 1, + SeparateTable => 'LightSource', + PrintConv => \%lightSource, + }, + 0xcd32 => { # DNG 1.6 + Name => 'CameraCalibration3', + Writable => 'rational64s', + WriteGroup => 'IFD0', + Count => -1, + Protected => 1, + }, + 0xcd33 => { # DNG 1.6 + Name => 'ColorMatrix3', + Writable => 'rational64s', + WriteGroup => 'IFD0', + Count => -1, + Protected => 1, + }, + 0xcd34 => { # DNG 1.6 + Name => 'ForwardMatrix3', + Writable => 'rational64s', + WriteGroup => 'IFD0', + Count => -1, + Protected => 1, + }, + 0xcd35 => { # DNG 1.6 + Name => 'IlluminantData1', + Writable => 'undef', + WriteGroup => 'IFD0', + Protected => 1, + }, + 0xcd36 => { # DNG 1.6 + Name => 'IlluminantData2', + Writable => 'undef', + WriteGroup => 'IFD0', + Protected => 1, + }, + 0xcd37 => { # DNG 1.6 + Name => 'IlluminantData3', + Writable => 'undef', + WriteGroup => 'IFD0', + Protected => 1, + }, + 0xcd38 => { # DNG 1.6 + Name => 'MaskSubArea', + # Writable => 'int32u', + WriteGroup => 'SubIFD', #? (NC) Semantic Mask IFD (only for Validate) + Count => 4, + }, + 0xcd39 => { # DNG 1.6 + Name => 'ProfileHueSatMapData3', + %longBin, + Writable => 'float', + WriteGroup => 'IFD0', + Count => -1, + Protected => 1, + }, + 0xcd3a => { # DNG 1.6 + Name => 'ReductionMatrix3', + Writable => 'rational64s', + WriteGroup => 'IFD0', + Count => -1, + Protected => 1, + }, + 0xcd3b => { # DNG 1.6 + Name => 'RGBTables', + Writable => 'undef', + WriteGroup => 'IFD0', + Protected => 1, + }, 0xea1c => { #13 Name => 'Padding', Binary => 1, @@ -3867,7 +4202,7 @@ my %sampleFormat = ( # tags in the range 0xfde8-0xfe58 have been observed in PS7 files # generated from RAW images. They are all strings with the - # tag name at the start of the string. To accomodate these types + # tag name at the start of the string. To accommodate these types # of tags, all tags with values above 0xf000 are handled specially # by ProcessExif(). 0xfde8 => { @@ -4012,8 +4347,8 @@ my %subSecConv = ( my $v; if (defined $val[1] and $val[1]=~/^(\d+)/) { my $subSec = $1; - # be careful here just in case the time already contains a timezone (contrary to spec) - undef $v unless ($v = $val[0]) =~ s/( \d{2}:\d{2}:\d{2})/$1\.$subSec/; + # be careful here just in case the time already contains sub-seconds or a timezone (contrary to spec) + undef $v unless ($v = $val[0]) =~ s/( \d{2}:\d{2}:\d{2})(?!\.\d+)/$1\.$subSec/; } if (defined $val[2] and $val[0]!~/[-+]/ and $val[2]=~/^([-+])(\d{1,2}):(\d{2})/) { $v = ($v || $val[0]) . sprintf('%s%.2d:%.2d', $1, $2, $3); @@ -4035,14 +4370,17 @@ my %subSecConv = ( Desire => { 2 => 'ExifImageWidth', 3 => 'ExifImageHeight', + 4 => 'RawImageCroppedSize', # (FujiFilm RAF images) }, # use ExifImageWidth/Height only for Canon and Phase One TIFF-base RAW images ValueConv => q{ - return "$val[2]x$val[3]" if $val[2] and $val[3] and + return $val[4] if $val[4]; + return "$val[2] $val[3]" if $val[2] and $val[3] and $$self{TIFF_TYPE} =~ /^(CR2|Canon 1D RAW|IIQ|EIP)$/; - return "$val[0]x$val[1]" if IsFloat($val[0]) and IsFloat($val[1]); + return "$val[0] $val[1]" if IsFloat($val[0]) and IsFloat($val[1]); return undef; }, + PrintConv => '$val =~ tr/ /x/; $val', }, Megapixels => { Require => 'ImageSize', @@ -4501,11 +4839,32 @@ my %subSecConv = ( }, GPSPosition => { Groups => { 2 => 'Location' }, + Writable => 1, + Protected => 1, + WriteAlso => { + GPSLatitude => '(defined $val and $val =~ /(.*?)( ?[NS])?,/) ? $1 : undef', + GPSLatitudeRef => '(defined $val and $val =~ /(-?)(.*?) ?([NS]?),/) ? ($3 || ($1 ? "S" : "N")) : undef', + GPSLongitude => '(defined $val and $val =~ /, ?(.*?)( ?[EW]?)$/) ? $1 : undef', + GPSLongitudeRef => '(defined $val and $val =~ /, ?(-?)(.*?) ?([EW]?)$/) ? ($3 || ($1 ? "W" : "E")) : undef', + }, + PrintConvInv => q{ + return undef unless $val =~ /(.*? ?[NS]?), ?(.*? ?[EW]?)$/; + my ($lat, $lon) = ($1, $2); + require Image::ExifTool::GPS; + $lat = Image::ExifTool::GPS::ToDegrees($lat, 1, "lat"); + $lon = Image::ExifTool::GPS::ToDegrees($lon, 1, "lon"); + return "$lat, $lon"; + }, Require => { 0 => 'GPSLatitude', 1 => 'GPSLongitude', }, Priority => 0, + Notes => q{ + when written, writes GPSLatitude, GPSLatitudeRef, GPSLongitude and + GPSLongitudeRef. This tag may be written using the same coordinate + format as provided by Google Maps when right-clicking on a location + }, ValueConv => '(length($val[0]) or length($val[1])) ? "$val[0] $val[1]" : undef', PrintConv => '"$prt[0], $prt[1]"', }, @@ -4522,7 +4881,9 @@ my %subSecConv = ( 7 => 'LensFocalRange', 8 => 'LensSpec', 9 => 'LensType2', - 10 => 'LensFocalLength', # (for Pentax to check for converter) + 10 => 'LensType3', + 11 => 'LensFocalLength', # (for Pentax to check for converter) + 12 => 'RFLensType', }, Notes => q{ attempt to identify the actual lens from all lenses with a given LensType. @@ -4540,20 +4901,56 @@ my %subSecConv = ( PrintConv => q{ my $pcv; # use LensType2 instead of LensType if available and valid (Sony E-mount lenses) - if ($val[9] and $val[9] & 0x8000) { + # (0x8000 or greater; 0 for several older/3rd-party E-mount lenses) + if (defined $val[9] and ($val[9] & 0x8000 or $val[9] == 0)) { $val[0] = $val[9]; $prt[0] = $prt[9]; + # Particularly GM lenses: often LensType2=0 but LensType3 is available and valid: use LensType3. + if ($val[9] == 0 and $val[10] & 0x8000) { + $val[0] = $val[10]; + $prt[0] = $prt[10]; + } $pcv = $$self{TAG_INFO}{LensType2}{PrintConv}; } + # use Canon RFLensType if available + if ($val[12]) { + $val[0] = $val[12]; + $prt[0] = $prt[12]; + $pcv = $$self{TAG_INFO}{RFLensType}{PrintConv}; + } my $lens = Image::ExifTool::Exif::PrintLensID($self, $prt[0], $pcv, $prt[8], @val); # check for use of lens converter (Pentax K-3) - if ($val[10] and $val[1] and $lens) { - my $conv = $val[1] / $val[10]; + if ($val[11] and $val[1] and $lens) { + my $conv = $val[1] / $val[11]; $lens .= sprintf(' + %.1fx converter', $conv) if $conv > 1.1; } return $lens; }, }, + 'LensID-2' => { + Name => 'LensID', + Groups => { 2 => 'Camera' }, + Desire => { + 0 => 'LensModel', + 1 => 'Lens', + 2 => 'XMP-aux:LensID', + 3 => 'Make', + }, + Inhibit => { + 4 => 'Composite:LensID', + }, + RawConv => q{ + return undef if defined $val[2] and defined $val[3]; + return $val if defined $val[0] and $val[0] =~ /(mm|\d\/F)/; + return $val if defined $val[1] and $val[1] =~ /(mm|\d\/F)/; + return undef; + }, + ValueConv => q{ + return $val[0] if defined $val[0] and $val[0] =~ /(mm|\d\/F)/; + return $val[1]; + }, + PrintConv => '$_=$val; s/(\d)\/F/$1mm F/; s/mmF/mm F/; s/(\d) mm/${1}mm/; s/ - /-/; $_', + }, ); # table for unknown IFD entries @@ -4762,7 +5159,7 @@ sub ConvertExifText($$;$$) $type = $1; $str = $et->Decode($str, 'JIS', 'Unknown'); } else { - $tag = $asciiFlex if $asciiFlex and $asciiFlex ne 1; + $tag = $asciiFlex if $asciiFlex and $asciiFlex ne '1'; $et->Warn('Invalid EXIF text encoding' . ($tag ? " for $tag" : '')); $str = $id . $str; } @@ -4875,6 +5272,7 @@ sub RedBlueBalance($@) sub PrintExposureTime($) { my $secs = shift; + return $secs unless Image::ExifTool::IsFloat($secs); if ($secs < 0.25001 and $secs > 0) { return sprintf("1/%d",int(0.5 + 1/$secs)); } @@ -4945,6 +5343,27 @@ sub PrintCFAPattern($) return $rtnVal . ']'; } +#------------------------------------------------------------------------------ +# Print Opcode List +# Inputs: 0) value, 1) flag for inverse conversion, 2) conversion hash reference +# Returns: converted value +sub PrintOpcode($$$) +{ + my ($val, $inv, $conv) = @_; + return undef if $inv; # (can't do inverse conversion) + return '' unless length $$val > 4; + my $num = unpack('N', $$val); + my $pos = 4; + my ($i, @ops); + for ($i=0; $i<$num; ++$i) { + $pos + 16 <= length $$val or push(@ops, '<err>'), last; + my ($op, $ver, $flags, $len) = unpack("x${pos}N4", $$val); + push @ops, $$conv{$op} || "[opcode $op]"; + $pos += 16 + $len; + } + return join ', ', @ops; +} + #------------------------------------------------------------------------------ # Print conversion for lens info # Inputs: 0) string of values (min focal, max focal, min F, max F) @@ -4992,12 +5411,44 @@ sub GetLensInfo($;$) return @a; } +#------------------------------------------------------------------------------ +# Match lens in list of possbilities based on value of LensModel +# Inputs: 0) reference to list of possible models, 1) LensModel string +# - updates list on return; guaranteed not to remove all list entries +sub MatchLensModel($$) +{ + my ($try, $lensModel) = @_; + if (@$try > 1 and $lensModel) { + my (@filt, $pat); + # filter by focal length + if ($lensModel =~ /((\d+-)?\d+mm)/) { + my $focal = $1; + @filt = grep /$focal/, @$try; + @$try = @filt if @filt and @filt < @$try; + } + # filter by aperture + if (@$try > 1 and $lensModel =~ m{(?:F/?|1:)(\d+(\.\d+)?)}i) { + my $fnum = $1; + @filt = grep m{(F/?|1:)$fnum(\b|[A-Z])}i, @$try; + @$try = @filt if @filt and @filt < @$try; + } + # filter by model version, and other lens parameters + foreach $pat ('I+', 'USM') { + next unless @$try > 1 and $lensModel =~ /\b($pat)\b/; + my $val = $1; + @filt = grep /\b$val\b/, @$try; + @$try = @filt if @filt and @filt < @$try; + } + } +} + #------------------------------------------------------------------------------ # Attempt to identify the specific lens if multiple lenses have the same LensType # Inputs: 0) ExifTool object ref, 1) LensType print value, 2) PrintConv hash ref, # 3) LensSpec print value, 4) LensType numerical value, 5) FocalLength, # 6) MaxAperture, 7) MaxApertureValue, 8) MinFocalLength, 9) MaxFocalLength, # 10) LensModel, 11) LensFocalRange, 12) LensSpec +my %sonyEtype; sub PrintLensID($$@) { my ($et, $lensTypePrt, $printConv, $lensSpecPrt, $lensType, $focalLength, @@ -5032,12 +5483,27 @@ sub PrintLensID($$@) ($shortFocal, $longFocal) = ($1, $2 || $1); } if ($$et{Make} eq 'SONY') { - # Patch for Metabones or other adapters on Sony E-mount cameras (ref Jos Roost) - # Metabones Canon EF to E-mount adapters add 0xef00, 0xbc00 or 0x7700 to the - # high byte for 2-byte Canon LensType values, so we need to adjust for these. - # Offset 0xef00 is also used by Sigma MC-11, Fotodiox and Viltrox EF-E adapters. - # Have to exclude A-mount Sigma Filtermatic with 'odd' LensType=0xff00. - if ($lensType != 0xffff and $lensType != 0xff00) { + if ($lensType eq 65535) { + # handle Sony E-type lenses when LensType2 isn't valid (NEX/ILCE models only) + if ($$et{Model} =~ /NEX|ILCE/) { + unless (%sonyEtype) { + my ($index, $i, %did, $lens); + require Image::ExifTool::Sony; + foreach (sort keys %Image::ExifTool::Sony::sonyLensTypes2) { + ($lens = $Image::ExifTool::Sony::sonyLensTypes2{$_}) =~ s/ or .*//; + next if $did{$lens}; + ($i, $index) = $index ? ("65535.$index", $index + 1) : (65535, 1); + $did{$sonyEtype{$i} = $lens} = 1; + } + } + $printConv = \%sonyEtype; + } + } elsif ($lensType != 0xff00) { + # Patch for Metabones or other adapters on Sony E-mount cameras (ref Jos Roost) + # Metabones Canon EF to E-mount adapters add 0xef00, 0xbc00 or 0x7700 to the + # high byte for 2-byte Canon LensType values, so we need to adjust for these. + # Offset 0xef00 is also used by Sigma MC-11, Fotodiox and Viltrox EF-E adapters. + # Have to exclude A-mount Sigma Filtermatic with 'odd' LensType=0xff00. require Image::ExifTool::Minolta; if ($Image::ExifTool::Minolta::metabonesID{$lensType & 0xff00}) { $lensType -= ($lensType >= 0xef00 ? 0xef00 : $lensType >= 0xbc00 ? 0xbc00 : 0x7700); @@ -5054,7 +5520,8 @@ sub PrintLensID($$@) $lensTypePrt = $$printConv{$lensType} if $$printConv{$lensType}; } } - } elsif ($shortFocal and $longFocal) { + # (Min/MaxFocalLength may report the current focal length for Tamron zoom lenses) + } elsif ($shortFocal and $longFocal and (not $lensModel or $lensModel !~ /^TAMRON.*-\d+mm/)) { # Canon (and some other makes) include makernote information # which allows better lens identification require Image::ExifTool::Canon; @@ -5090,7 +5557,7 @@ sub PrintLensID($$@) # excluding any part between () at the end, and preceded by a space (the space # ensures that e.g. Zeiss Loxia 21mm having LensSpec "E 21mm F2.8" will not be # identified as "Sony FE 21mm F2.8 (SEL28F20 + SEL075UWC)") - $lensSpecPrt and $lens =~ / \Q$lensSpecPrt\E( \(|$)/ and @best = ( $lens ), last; + $lensSpecPrt and $lens =~ / \Q$lensSpecPrt\E( \(| GM$|$)/ and @best = ( $lens ), last; # exactly-matching Sony lens should have been found above, so only add non-Sony lenses push @best, $lens unless $lens =~ /^Sony /; next; @@ -5150,9 +5617,12 @@ sub PrintLensID($$@) } return join(' or ', @user); } - # return the best match(es) from the possible lenses - return join(' or ', @best) if @best; - return join(' or ', @matches) if @matches; + # return the best match(es) from the possible lenses, after checking against LensModel + @best = @matches unless @best; + if (@best) { + MatchLensModel(\@best, $lensModel); + return join(' or ', @best); + } $lens = $$printConv{$lensType}; return $lensModel if $lensModel and $lens =~ / or /; # (eg. Sony NEX-5N) return $lens; @@ -5344,6 +5814,32 @@ sub ExtractImage($$$$) return $et->ValidateImage(\$image, $tag); } +#------------------------------------------------------------------------------ +# Utility routine to return tag ID string for warnings +# Inputs: 0) Tag ID, 1) [optional] TagInfo ref +# Returns: "tag 0xXXXX NAME" +sub TagName($;$) +{ + my ($tagID, $tagInfo) = @_; + my $tagName = $tagInfo ? ' '.$$tagInfo{Name} : ''; + return sprintf('tag 0x%.4x%s', $tagID, $tagName); +} + +#------------------------------------------------------------------------------ +# Get class name of next IFD offset for HtmlDump output +# Inputs: 0) ExifTool ref, 1) current class ID +# Returns: 0) new IFD offset name, 1) new class ID including "Offset_" for new offset +# 2) new "Offset_" ID +sub NextOffsetName($;$) +{ + my ($et, $id) = @_; + $$et{OffsetNum} = defined $$et{OffsetNum} ? $$et{OffsetNum} + 1 : 0; + my $offName = 'o' . $$et{OffsetNum}; + my $sid = "Offset_$offName"; + $id = (defined $id ? "$id " : '') . $sid; + return ($offName, $id, $sid); +} + #------------------------------------------------------------------------------ # Process EXIF directory # Inputs: 0) ExifTool object reference @@ -5364,9 +5860,10 @@ sub ProcessExif($$$) my $raf = $$dirInfo{RAF}; my $verbose = $et->Options('Verbose'); my $validate = $et->Options('Validate'); + my $saveFormat = $et->Options('SaveFormat'); my $htmlDump = $$et{HTML_DUMP}; my $success = 1; - my ($tagKey, $dirSize, $makerAddr, $strEnc, %offsetInfo); + my ($tagKey, $dirSize, $makerAddr, $strEnc, %offsetInfo, $offName, $nextOffName); my $inMakerNotes = $$tagTablePtr{GROUPS}{0} eq 'MakerNotes'; my $isExif = ($tagTablePtr eq \%Image::ExifTool::Exif::Main); @@ -5381,7 +5878,7 @@ sub ProcessExif($$$) unless ($path =~ /^(JPEG-APP1-IFD0|TIFF-IFD0|PSD-EXIFInfo-IFD0)$/) { if ($Image::ExifTool::MWG::strict) { $et->Warn("Ignored non-standard EXIF at $path"); - return 1; + return 0; } else { $et->Warn("Non-standard EXIF at $path", 1); } @@ -5424,10 +5921,6 @@ sub ProcessExif($$$) # also read next IFD pointer if available if ($raf->Read($buf2, $len+4) >= $len) { $buff .= $buf2; - # make copy of dirInfo since we're going to modify it - my %newDirInfo = %$dirInfo; - $dirInfo = \%newDirInfo; - # update directory parameters for the newly loaded IFD $dataPt = $$dirInfo{DataPt} = \$buff; $dataPos = $$dirInfo{DataPos} = $offset; $dataLen = $$dirInfo{DataLen} = length $buff; @@ -5437,11 +5930,16 @@ sub ProcessExif($$$) } } } - unless ($success) { - $et->Warn("Bad $dir directory"); - return 0; + if ($success) { + $numEntries = Get16u($dataPt, $dirStart); + } else { + $et->Warn("Bad $dir directory", $inMakerNotes); + return 0 unless $inMakerNotes and $dirLen >= 14 and $dirStart >= 0 and + $dirStart + $dirLen <= length($$dataPt); + $dirSize = $dirLen; + $numEntries = int(($dirSize - 2) / 12); # read what we can + Set16u($numEntries, $dataPt, $dirStart); } - $numEntries = Get16u($dataPt, $dirStart); $dirSize = 2 + 12 * $numEntries; $dirEnd = $dirStart + $dirSize; } @@ -5463,6 +5961,7 @@ sub ProcessExif($$$) } } if ($htmlDump) { + $offName = $$dirInfo{OffsetName}; my $longName = $dir eq 'MakerNotes' ? ($$dirInfo{Name} || $dir) : $dir; if (defined $makerAddr) { my $hdrLen = $dirStart + $dataPos + $base - $makerAddr; @@ -5470,14 +5969,17 @@ sub ProcessExif($$$) } unless ($$dirInfo{NoDumpEntryCount}) { $et->HDump($dirStart + $dataPos + $base, 2, "$longName entries", - "Entry count: $numEntries"); + "Entry count: $numEntries", undef, $offName); } my $tip; + my $id = $offName; if ($bytesFromEnd >= 4) { my $nxt = ($dir =~ /^(.*?)(\d+)$/) ? $1 . ($2 + 1) : 'Next IFD'; - $tip = sprintf("$nxt offset: 0x%.4x", Get32u($dataPt, $dirEnd)); + my $off = Get32u($dataPt, $dirEnd); + $tip = sprintf("$nxt offset: 0x%.4x", $off); + ($nextOffName, $id) = NextOffsetName($et, $offName) if $off; } - $et->HDump($dirEnd + $dataPos + $base, 4, "Next IFD", $tip, 0); + $et->HDump($dirEnd + $dataPos + $base, 4, "Next IFD", $tip, 0, $id); } # patch for Canon EOS 40D firmware 1.0.4 bug (incorrect directory counts) @@ -5487,7 +5989,7 @@ sub ProcessExif($$$) my $fmt = Get16u($dataPt, $entry + 2); if ($fmt < 1 or $fmt > 13) { $et->HDump($entry+$dataPos+$base,12,"[invalid IFD entry]", - "Bad format type: $fmt", 1); + "Bad format type: $fmt", 1, $offName); # adjust the number of directory entries --$numEntries; $dirEnd -= 12; @@ -5498,7 +6000,7 @@ sub ProcessExif($$$) $$et{Compression} = $$et{SubfileType} = ''; # loop through all entries in an EXIF directory (IFD) - my ($index, $valEnd, $offList, $offHash, $mapFmt); + my ($index, $valEnd, $offList, $offHash, $mapFmt, @valPos); $mapFmt = $$tagTablePtr{VARS}{MAP_FORMAT} if $$tagTablePtr{VARS}; my ($warnCount, $lastID) = (0, -1); @@ -5515,7 +6017,7 @@ sub ProcessExif($$$) $format = $$mapFmt{$format}; } else { $et->HDump($entry+$dataPos+$base,12,"[invalid IFD entry]", - "Bad format type: $format", 1); + "Bad format type: $format", 1, $offName); # warn unless the IFD was just padded with zeros if ($format or $validate) { $et->Warn("Bad format ($format) for $dir entry $index", $inMakerNotes); @@ -5532,7 +6034,9 @@ sub ProcessExif($$$) my $valueDataLen = $dataLen; my $valuePtr = $entry + 8; # pointer to value within $$dataPt my $tagInfo = $et->GetTagInfo($tagTablePtr, $tagID); - my ($origFormStr, $bad, $rational); + my ($origFormStr, $bad, $rational, $subOffName); + # save the EXIF format codes if requested + $$et{SaveFormat}{$saveFormat = $formatStr} = 1 if $saveFormat; # hack to patch incorrect count in Kodak SubIFD3 tags if ($count < 2 and ref $$tagTablePtr{$tagID} eq 'HASH' and $$tagTablePtr{$tagID}{FixCount}) { $offList or ($offList, $offHash) = GetOffList($dataPt, $dirStart, $dataPos, @@ -5549,24 +6053,30 @@ sub ProcessExif($$$) my $size = $count * $formatSize[$format]; my $readSize = $size; if ($size > 4) { - if ($size > 0x7fffffff) { - $et->Warn(sprintf("Invalid size (%u) for %s tag 0x%.4x", $size, $dir, $tagID), $inMakerNotes); + if ($size > 0x7fffffff and (not $tagInfo or not $$tagInfo{ReadFromRAF})) { + $et->Warn(sprintf("Invalid size (%u) for %s %s",$size,$dir,TagName($tagID,$tagInfo)), $inMakerNotes); ++$warnCount; next; } $valuePtr = Get32u($dataPt, $valuePtr); if ($validate and not $inMakerNotes) { - $et->Warn(sprintf('Odd offset for %s tag 0x%.4x', $dir, $tagID), 1) if $valuePtr & 0x01; + my $tagName = TagName($tagID, $tagInfo); + $et->Warn("Odd offset for $dir $tagName", 1) if $valuePtr & 0x01; if ($valuePtr < 8 || ($valuePtr + $size > length($$dataPt) and $valuePtr + $size > $$et{VALUE}{FileSize})) { - $et->Warn(sprintf("Invalid offset for %s tag 0x%.4x", $dir, $tagID)); + $et->Warn("Invalid offset for $dir $tagName"); ++$warnCount; next; } if ($valuePtr + $size > $dirStart + $dataPos and $valuePtr < $dirEnd + $dataPos + 4) { - $et->Warn(sprintf("Value for %s tag 0x%.4x overlaps IFD", $dir, $tagID)); + $et->Warn("Value for $dir $tagName overlaps IFD"); + } + foreach (@valPos) { + next if $$_[0] >= $valuePtr + $size or $$_[0] + $$_[1] <= $valuePtr; + $et->Warn("Value for $dir $tagName overlaps $$_[2]"); } + push @valPos, [ $valuePtr, $size, $tagName ]; } # fix valuePtr if necessary if ($$dirInfo{FixOffsets}) { @@ -5796,18 +6306,29 @@ sub ProcessExif($$$) unless ($bad) { # limit maximum length of data to reformat # (avoids long delays when processing some corrupted files) + my $warned; if ($count > 100000 and $formatStr !~ /^(undef|string|binary)$/) { my $tagName = $tagInfo ? $$tagInfo{Name} : sprintf('tag 0x%.4x', $tagID); - if ($tagName ne 'TransferFunction' or $count ne 196608) { + # (count of 196608 is typical for ColorMap) + if ($tagName ne 'TransferFunction' or $count != 196608) { my $minor = $count > 2000000 ? 0 : 2; - next if $et->Warn("Ignoring $dirName $tagName with excessive count", $minor); + if ($et->Warn("Ignoring $dirName $tagName with excessive count", $minor)) { + next unless $$et{OPTIONS}{HtmlDump}; + $warned = 1; + } } } - # convert according to specified format - $val = ReadValue($valueDataPt,$valuePtr,$formatStr,$count,$readSize,\$rational); - # re-code if necessary - if ($strEnc and $formatStr eq 'string' and defined $val) { - $val = $et->Decode($val, $strEnc); + if ($count > 500 and $formatStr !~ /^(undef|string|binary)$/ and + (not $tagInfo or $$tagInfo{LongBinary} or $warned) and not $$et{OPTIONS}{IgnoreMinorErrors}) + { + $et->WarnOnce('Not decoding some large array(s). Ignore minor errors to decode', 2) unless $warned; + next if $$et{TAGS_FROM_FILE}; # don't generate bogus value when copying tags + $val = "(large array of $count $formatStr values)"; + } else { + # convert according to specified format + $val = ReadValue($valueDataPt,$valuePtr,$formatStr,$count,$readSize,\$rational); + # re-code if necessary + $val = $et->Decode($val, $strEnc) if $strEnc and $formatStr eq 'string' and defined $val; } } @@ -5834,7 +6355,8 @@ sub ProcessExif($$$) "Format: $fstr\nSize: $size bytes\n"; if ($size > 4) { my $offPt = Get32u($dataPt,$entry+8); - my $actPt = $valuePtr + $valueDataPos + $base - ($$et{EXIF_POS} || 0); + # (test this with ../pics/{CanonEOS-1D_XMarkIII.hif,PanasonicDC-G9.rw2}) + my $actPt = $valuePtr + $valueDataPos + $base - ($$et{EXIF_POS} || 0) + ($$et{BASE_FUDGE} || 0); $tip .= sprintf("Value offset: 0x%.4x\n", $offPt); # highlight tag name (red for bad size) my $style = ($bad or not defined $tval) ? 'V' : 'H'; @@ -5844,6 +6366,9 @@ sub ProcessExif($$$) $tip .= sprintf("Offset base: ${sign}0x%.4x\n", abs($actPt - $offPt)); $style = 'F' if $style eq 'H'; # purple for different offsets } + if ($$et{EXIF_POS} and not $$et{BASE_FUDGE}) { + $tip .= sprintf("File offset: 0x%.4x\n", $actPt + $$et{EXIF_POS}) + } $colName = "<span class=$style>$tagName</span>"; $colName .= ' <span class=V>(odd)</span>' if $offPt & 0x01; } else { @@ -5862,7 +6387,7 @@ sub ProcessExif($$$) } elsif ($tagInfo and Image::ExifTool::IsInt($tval)) { if ($$tagInfo{IsOffset} or $$tagInfo{SubIFD}) { $tval = sprintf('0x%.4x', $tval); - my $actPt = $val + $base - ($$et{EXIF_POS} || 0); + my $actPt = $val + $base - ($$et{EXIF_POS} || 0) + ($$et{BASE_FUDGE} || 0); if ($actPt != $val) { $tval .= sprintf("\nActual offset: 0x%.4x", $actPt); my $sign = $actPt < $val ? '-' : ''; @@ -5874,7 +6399,10 @@ sub ProcessExif($$$) } } $tip .= "Value: $tval"; - $et->HDump($entry+$dataPos+$base, 12, "$dname $colName", $tip, 1); + my $id = $offName; + my $sid; + ($subOffName, $id, $sid) = NextOffsetName($et, $offName) if $tagInfo and $$tagInfo{SubIFD}; + $et->HDump($entry+$dataPos+$base, 12, "$dname $colName", $tip, 1, $id); next if $valueDataLen < 0; # don't process bad pointer entry if ($size > 4) { my $exifDumpPos = $valuePtr + $valueDataPos + $base; @@ -5887,7 +6415,7 @@ sub ProcessExif($$$) } } # add value data block (underlining maker notes data) - $et->HDump($exifDumpPos,$size,"$tagName value",'SAME', $flag); + $et->HDump($exifDumpPos,$size,"$tagName value",'SAME', $flag, $sid); } } else { if ($tagID <= $lastID and not $inMakerNotes) { @@ -6062,6 +6590,7 @@ sub ProcessExif($$$) TagInfo => $tagInfo, SubIFD => $$tagInfo{SubIFD}, Subdir => $subdir, + OffsetName => $subOffName, ); # (remember: some cameras incorrectly write maker notes in IFD0) if ($$tagInfo{MakerNotes}) { @@ -6085,7 +6614,7 @@ sub ProcessExif($$$) #### eval Validate ($val, $dirData, $subdirStart, $size) my $ok = 0; if (defined $$subdir{Validate} and not eval $$subdir{Validate}) { - $et->Warn("Invalid $tagStr data"); + $et->Warn("Invalid $tagStr data", $inMakerNotes); $invalid = 1; } else { if (not $subdirInfo{DirName} and $inMakerNotes) { @@ -6187,6 +6716,7 @@ sub ProcessExif($$$) $et->SetGroup($tagKey, $dirName) if $$tagTablePtr{SET_GROUP1}; # save original components of rational numbers (used when copying) $$et{RATIONAL}{$tagKey} = $rational if defined $rational; + $$et{TAG_EXTRA}{$tagKey}{G6} = $saveFormat if $saveFormat; } } @@ -6197,27 +6727,40 @@ sub ProcessExif($$$) # scan for subsequent IFD's if specified if ($$dirInfo{Multi} and $bytesFromEnd >= 4) { - my $offset = Get32u($dataPt, $dirEnd); - if ($offset) { - my $subdirStart = $offset - $dataPos; - # use same directory information for trailing directory, - # but change the start location (ProcessDirectory will - # test to make sure we don't reprocess the same dir twice) - my %newDirInfo = %$dirInfo; - $newDirInfo{DirStart} = $subdirStart; + # use same directory information for trailing directory, + # but change the start location (ProcessDirectory will + # test to make sure we don't reprocess the same dir twice) + my %newDirInfo = %$dirInfo; + $newDirInfo{Multi} = 0; # prevent recursion + $newDirInfo{OffsetName} = $nextOffName; + $$et{INDENT} =~ s/..$//; # keep indent the same + for (;;) { + my $offset = Get32u($dataPt, $dirEnd) or last; + $newDirInfo{DirStart} = $offset - $dataPos; # increment IFD number my $ifdNum = $newDirInfo{DirName} =~ s/(\d+)$// ? $1 : 0; $newDirInfo{DirName} .= $ifdNum + 1; # must validate SubIFD1 because the nextIFD pointer is invalid for some RAW formats if ($newDirInfo{DirName} ne 'SubIFD1' or ValidateIFD(\%newDirInfo)) { - $$et{INDENT} =~ s/..$//; # keep indent the same my $cur = pop @{$$et{PATH}}; $et->ProcessDirectory(\%newDirInfo, $tagTablePtr) or $success = 0; push @{$$et{PATH}}, $cur; + if ($success and $newDirInfo{BytesFromEnd} >= 4) { + $dataPt = $newDirInfo{DataPt}; + $dataPos = $newDirInfo{DataPos}; + $dirEnd = $newDirInfo{DirEnd}; + next; + } } elsif ($verbose or $$et{TIFF_TYPE} eq 'TIFF') { $et->Warn('Ignored bad IFD linked from SubIFD'); } + last; } + } elsif (defined $$dirInfo{Multi}) { + # return necessary parameters for parsing next IFD + $$dirInfo{DirEnd} = $dirEnd; + $$dirInfo{OffsetName} = $nextOffName; + $$dirInfo{BytesFromEnd} = $bytesFromEnd; } return $success; } @@ -6241,7 +6784,7 @@ EXIF and TIFF meta information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/FITS.pm b/src/Image-ExifTool/lib/Image/ExifTool/FITS.pm new file mode 100644 index 00000000..ca0bff30 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/FITS.pm @@ -0,0 +1,159 @@ +#------------------------------------------------------------------------------ +# File: FITS.pm +# +# Description: Read Flexible Image Transport System metadata +# +# Revisions: 2018/03/07 - P. Harvey Created +# +# References: 1) https://fits.gsfc.nasa.gov/fits_standard.html +#------------------------------------------------------------------------------ + +package Image::ExifTool::FITS; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.02'; + +# FITS tags (ref 1) +%Image::ExifTool::FITS::Main = ( + GROUPS => { 2 => 'Image' }, + NOTES => q{ + This table lists some standard Flexible Image Transport System (FITS) tags, + but ExifTool will extract any other tags found. See + L<https://fits.gsfc.nasa.gov/fits_standard.html> for the specification. + }, + TELESCOP => 'Telescope', + BACKGRND => 'Background', + INSTRUME => 'Instrument', + OBJECT => 'Object', + OBSERVER => 'Observer', + DATE => { Name => 'CreateDate', Groups => { 2 => 'Time' } }, + AUTHOR => { Name => 'Author', Groups => { 2 => 'Author' } }, + REFERENC => 'Reference', + 'DATE-OBS'=> { Name => 'ObservationDate', Groups => { 2 => 'Time' } }, + 'TIME-OBS'=> { Name => 'ObservationTime', Groups => { 2 => 'Time' } }, + 'DATE-END'=> { Name => 'ObservationDateEnd', Groups => { 2 => 'Time' } }, + 'TIME-END'=> { Name => 'ObservationTimeEnd', Groups => { 2 => 'Time' } }, + COMMENT => { Name => 'Comment', PrintConv => '$val =~ s/^ +//; $val', + Notes => 'leading spaces are removed if L<PrintConv|../ExifTool.html#PrintConv> is enabled' }, + HISTORY => { Name => 'History', PrintConv => '$val =~ s/^ +//; $val', + Notes => 'leading spaces are removed if L<PrintConv|../ExifTool.html#PrintConv> is enabled' }, +); + +#------------------------------------------------------------------------------ +# Read information in a FITS document +# Inputs: 0) ExifTool ref, 1) dirInfo ref +# Returns: 1 on success, 0 if this wasn't a valid FITS file +sub ProcessFITS($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my ($buff, $tag, $continue); + + return 0 unless $raf->Read($buff, 80) == 80 and $buff =~ /^SIMPLE = {20}T/; + $et->SetFileType(); + my $tagTablePtr = GetTagTable('Image::ExifTool::FITS::Main'); + + for (;;) { + $raf->Read($buff, 80) == 80 or $et->Warn('Truncated FITS header'), last; + my $key = substr($buff, 0, 8); + $key =~ s/ +$//; # remove trailing space from key + if ($key eq 'CONTINUE') { + defined $continue or $et->WarnOnce('Unexpected FITS CONTINUE keyword'), next; + } else { + if (defined $continue) { + # the previous value wasn't continued, so store with the trailing '&' + $et->HandleTag($tagTablePtr, $tag, $continue . '&'); + undef $continue; + } + last if $key eq 'END'; + # make sure the key is valid + $key =~ /^[-_A-Z0-9]*$/ or $et->Warn('Format error in FITS header'), last; + if ($key eq 'COMMENT' or $key eq 'HISTORY') { + my $val = substr($buff, 8); # comments start in column 9 + $val =~ s/ +$//; # remove trailing spaces + $et->HandleTag($tagTablePtr, $key, $val); + next; + } + # ignore other lines that aren't tags + next unless substr($buff,8,2) eq '= '; + # save tag name (avoiding potential conflict with ExifTool variables) + $tag = $Image::ExifTool::specialTags{$key} ? "_$key" : $key; + # add to tag table if necessary + unless ($$tagTablePtr{$tag}) { + my $name = ucfirst lc $tag; # make tag name lower case with leading capital + $name =~ s/_(.)/\U$1/g; # remove all '_' and capitalize subsequent letter + AddTagToTable($tagTablePtr, $tag, { Name => $name }); + } + } + my $val = substr($buff, 10); + # parse quoted values + if ($val =~ /^'(.*?)'(.*)/) { + ($val, $buff) = ($1, $2); + while ($buff =~ /^('.*?)'(.*)/) { # handle escaped quotes + $val .= $1; + $buff = $2; + } + $val =~ s/ +$//; # remove trailing spaces + if (defined $continue) { + $val = $continue . $val; + undef $continue; + } + # check for possible continuation, removing trailing '&' + $val =~ s/\&$// and $continue = $val, next; + } elsif (defined $continue) { + $et->WarnOnce('Invalid FITS CONTINUE value'); + next; + } else { + $val =~ s/ *(\/.*)?$//; # remove trailing spaces and comment + next unless length $val; # ignore undefined values + $val =~ s/^ +//; # remove leading spaces + # re-format floating-point values to use 'e' + $val =~ tr/DE/e/ if $val =~ /^[+-]?(?=\d|\.\d)\d*(\.\d*)?([ED]([+-]?\d+))?$/; + } + $et->HandleTag($tagTablePtr, $tag, $val); + } + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::FITS - Read Flexible Image Transport System metadata + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to read meta +information from FITS (Flexible Image Transport System) images. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<https://fits.gsfc.nasa.gov/fits_standard.html> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/FITS Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/FLAC.pm b/src/Image-ExifTool/lib/Image/ExifTool/FLAC.pm index a2d7675a..a9def18b 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/FLAC.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/FLAC.pm @@ -284,7 +284,7 @@ information from Free Lossless Audio Codec (FLAC) audio files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/FLIF.pm b/src/Image-ExifTool/lib/Image/ExifTool/FLIF.pm new file mode 100644 index 00000000..afbc10a9 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/FLIF.pm @@ -0,0 +1,353 @@ +#------------------------------------------------------------------------------ +# File: FLIF.pm +# +# Description: Read/write FLIF meta information +# +# Revisions: 2016/10/11 - P. Harvey Created +# 2016/10/14 - PH Added write support +# +# References: 1) http://flif.info/ +# 2) https://github.com/FLIF-hub/FLIF/blob/master/doc/metadata +#------------------------------------------------------------------------------ + +package Image::ExifTool::FLIF; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.02'; + +my %flifMap = ( + EXIF => 'FLIF', + XMP => 'FLIF', + ICC_Profile => 'FLIF', + IFD0 => 'EXIF', + IFD1 => 'IFD0', + ExifIFD => 'IFD0', + GPS => 'IFD0', + SubIFD => 'IFD0', + GlobParamIFD => 'IFD0', + PrintIM => 'IFD0', + InteropIFD => 'ExifIFD', + MakerNotes => 'ExifIFD', +); + +# FLIF tags +%Image::ExifTool::FLIF::Main = ( + GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' }, + VARS => { HEX_ID => 0 }, + NOTES => q{ + Information extracted from Free Lossless Image Format files. See + L<http://flif.info/> for more information. + }, +# +# header information +# + 0 => { + Name => 'ImageType', + PrintConv => { + '1' => 'Grayscale (non-interlaced)', + '3' => 'RGB (non-interlaced)', + '4' => 'RGBA (non-interlaced)', + 'A' => 'Grayscale (interlaced)', + 'C' => 'RGB (interlaced)', + 'D' => 'RGBA (interlaced)', + 'Q' => 'Grayscale Animation (non-interlaced)', + 'S' => 'RGB Animation (non-interlaced)', + 'T' => 'RGBA Animation (non-interlaced)', + 'a' => 'Grayscale Animation (interlaced)', + 'c' => 'RGB Animation (interlaced)', + 'd' => 'RGBA Animation (interlaced)', + }, + }, + 1 => { + Name => 'BitDepth', + PrintConv => { + '0' => 'Custom', + '1' => 8, + '2' => 16, + }, + }, + 2 => 'ImageWidth', + 3 => 'ImageHeight', + 4 => 'AnimationFrames', + 5 => { + Name => 'Encoding', + PrintConv => { + 0 => 'FLIF16', + }, + }, +# +# metadata chunks +# + iCCP => { + Name => 'ICC_Profile', + SubDirectory => { + TagTable => 'Image::ExifTool::ICC_Profile::Main', + }, + }, + eXif => { + Name => 'EXIF', + SubDirectory => { + TagTable => 'Image::ExifTool::Exif::Main', + ProcessProc => \&Image::ExifTool::ProcessTIFF, + WriteProc => \&Image::ExifTool::WriteTIFF, + Start => 6, # (skip "Exif\0\0" header) + Header => "Exif\0\0", + }, + }, + eXmp => { + Name => 'XMP', + SubDirectory => { + TagTable => 'Image::ExifTool::XMP::Main', + }, + }, + # tRko - list of truncation offsets + # \0 - FLIF16-format image data +); + +#------------------------------------------------------------------------------ +# Read variable-length FLIF integer +# Inputs: 0) raf reference, 1) number to add to returned value +# Returns: integer, or undef on EOF +sub GetVarInt($;$) +{ + my ($raf, $add) = @_; + my ($val, $buff); + for ($val=0; ; $val<<=7) { + $raf->Read($buff, 1) or return undef; + my $byte = ord($buff); + $val |= ($byte & 0x7f); + last unless $byte & 0x80; + } + return $val + ($add || 0); +} + +#------------------------------------------------------------------------------ +# Construct variable-length FLIF integer +# Inputs: 0) integer +# Returns: FLIF variable-length integer byte stream +sub SetVarInt($) +{ + my $val = shift; + my $buff = ''; + my $high = 0; + for (;;) { + $buff = chr(($val & 0x7f) | $high) . $buff; + last unless $val >>= 7; + $high = 0x80; + } + return $buff; +} + +#------------------------------------------------------------------------------ +# Read FLIF header +# Inputs: 0) RAF ref +# Returns: Scalar context: binary header block +# List context: header values (4 or 5 elements: type,depth,width,height[,frames]) +# or undef if this isn't a valid FLIF file header +sub ReadFLIFHeader($) +{ + my $raf = shift; + my ($buff, @vals); + + # verify this is a valid FLIF file + return () unless $raf->Read($buff, 6) == 6 and $buff =~ /^FLIF([0-\x6f])([0-2])/; + + # decode header information ("FLIF" chunk) + push @vals, $1, $2; # type, depth + push @vals, GetVarInt($raf,+1), GetVarInt($raf,+1); # width, height (+1 each) + push @vals, GetVarInt($raf,+2) if $vals[0] gt 'H'; # frames (+2) + + return () unless defined $vals[-1]; + return @vals if wantarray; # return the decoded header values + + # return the binary header block + my $hdrLen = $raf->Tell(); + return () unless $raf->Seek(0,0) and $raf->Read($buff, $hdrLen) == $hdrLen; + return $buff; +} + +#------------------------------------------------------------------------------ +# WriteFLIF : Write FLIF image +# Inputs: 0) ExifTool object reference, 1) dirInfo reference +# Returns: 1 on success, 0 if this wasn't a valid FLIF file, or -1 if +# an output file was specified and a write error occurred +sub WriteFLIF($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my ($buff, $soi, @addTags, %doneTag); + + # verify FLIF header and copy it to the output file + $buff = ReadFLIFHeader($raf) or return 0; + my $outfile = $$dirInfo{OutFile}; + Write($outfile, $buff) or return -1; + + $et->InitWriteDirs(\%flifMap); + my $tagTablePtr = GetTagTable('Image::ExifTool::FLIF::Main'); + + # loop through the FLIF chunks + for (;;) { + my ($tag, $size, $inflated); + # read new tag (or soi) unless we already hit the soi (start of image) + if (not defined $soi) { + $raf->Read($buff, 4) == 4 or $et->Error('Unexpected EOF'), last; + if ($buff lt ' ') { + $soi = $buff; # we have hit the start of image (no more metadata) + # make list of new tags to add + foreach $tag ('eXif', 'eXmp', 'iCCP') { + push @addTags, $tag if $$et{ADD_DIRS}{$$tagTablePtr{$tag}{Name}} and not $doneTag{$tag}; + } + } + } + if (not defined $soi) { + $tag = $buff; + $size = GetVarInt($raf); # read the data size + } elsif (@addTags) { + $tag = shift @addTags; + ($buff, $size) = ('', 0); # create metadata from scratch + } else { + # finish copying file (no more metadata to add) + Write($outfile, $soi) or return -1; + Write($outfile, $buff) or return -1 while $raf->Read($buff, 65536); + last; # all done! + } + my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); + if ($tagInfo and $$tagInfo{SubDirectory} and $$et{EDIT_DIRS}{$$tagInfo{Name}}) { + $doneTag{$tag} = 1; # prevent adding this back again later + unless (defined $soi) { + $raf->Read($buff, $size) == $size or $et->Error("Truncated FLIF $tag chunk"), last; + } + # rewrite the compressed data + if (eval { require IO::Uncompress::RawInflate } and eval { require IO::Compress::RawDeflate } ) { + if (length $buff == 0) { + $inflated = $buff; # (creating from scratch, so no need to inflate) + } elsif (not IO::Uncompress::RawInflate::rawinflate(\$buff => \$inflated)) { + $et->Error("Error inflating FLIF $tag chunk"), last; + } + my $subdir = $$tagInfo{SubDirectory}; + my %subdirInfo = ( + DirName => $$tagInfo{Name}, + DataPt => \$inflated, + DirStart => length($inflated) ? $$subdir{Start} : undef, + ReadOnly => 1, # (used only by WriteXMP) + ); + my $subTable = GetTagTable($$subdir{TagTable}); + $inflated = $et->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc}); + if (defined $inflated) { + next unless length $inflated; # (delete directory if length is zero) + $inflated = $$subdir{Header} . $inflated if $$subdir{Header}; # (add back header if necessary) + unless (IO::Compress::RawDeflate::rawdeflate(\$inflated => \$buff)) { + $et->Error("Error deflating FLIF $tag chunk"), last; + } + } + } else { + $et->WarnOnce('Install IO::Compress::RawDeflate to write FLIF metadata'); + } + Write($outfile, $tag, SetVarInt(length $buff), $buff) or return -1; + } elsif (not defined $soi) { + Write($outfile, $tag, SetVarInt($size)) or return -1; + Image::ExifTool::CopyBlock($raf, $outfile, $size) or return -1; + } + } + return 1; +} + +#------------------------------------------------------------------------------ +# Extract information from an FLIF file +# Inputs: 0) ExifTool object reference, 1) DirInfo reference +# Returns: 1 on success, 0 if this wasn't a valid FLIF file +sub ProcessFLIF($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my ($buff, $tag, $inflated); + + # verify this is a valid FLIF file and read the header + my @vals = ReadFLIFHeader($raf) or return 0; + + $et->SetFileType(); + my $tagTablePtr = GetTagTable('Image::ExifTool::FLIF::Main'); + my $verbose = $et->Options('Verbose'); + + # save the header information + $et->VPrint(0, "FLIF header:\n") if $verbose; + for ($tag=0; defined $vals[$tag]; ++$tag) { + $et->HandleTag($tagTablePtr, $tag, $vals[$tag]); + } + + # loop through the FLIF chunks + for (;;) { + $raf->Read($tag, 4) == 4 or $et->Warn('Unexpected EOF'), last; + my $byte = ord substr($tag, 0, 1); + # all done if we arrived at the image chunk + $byte < 32 and $et->HandleTag($tagTablePtr, 5, $byte), last; + my $size = GetVarInt($raf); + $et->VPrint(0, "FLIF $tag ($size bytes):\n") if $verbose; + if ($$tagTablePtr{$tag}) { + $raf->Read($buff, $size) == $size or $et->Warn("Truncated FLIF $tag chunk"), last; + $et->VerboseDump(\$buff, Addr => $raf->Tell() - $size) if $verbose > 2; + # inflate the compressed data + if (eval { require IO::Uncompress::RawInflate }) { + if (IO::Uncompress::RawInflate::rawinflate(\$buff => \$inflated)) { + $et->HandleTag($tagTablePtr, $tag, $inflated, + DataPt => \$inflated, + Size => length $inflated, + Extra => ' inflated', + ); + } else { + $et->Warn("Error inflating FLIF $tag chunk"); + } + } else { + $et->WarnOnce('Install IO::Uncompress::RawInflate to decode FLIF metadata'); + } + } else { + $raf->Seek($size, 1) or $et->Warn('Seek error'), last; + } + } + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::FLIF - Read/write FLIF meta information + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains routines required by Image::ExifTool to read and write +meta information in FLIF (Free Lossless Image Format) images. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<http://flif.info/> + +=item L<https://github.com/FLIF-hub/FLIF/blob/master/doc/metadata> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/FLIF Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/FLIR.pm b/src/Image-ExifTool/lib/Image/ExifTool/FLIR.pm index f238bb67..f2e32525 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/FLIR.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/FLIR.pm @@ -5,12 +5,12 @@ # # Revisions: 2013/03/28 - P. Harvey Created # -# References: 1) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,4898.0.html +# References: 1) https://exiftool.org/forum/index.php/topic,4898.0.html # 2) http://www.nuage.ch/site/flir-i7-some-analysis/ # 3) http://www.workswell.cz/manuals/flir/hardware/A3xx_and_A6xx_models/Streaming_format_ThermoVision.pdf # 4) http://support.flir.com/DocDownload/Assets/62/English/1557488%24A.pdf # 5) http://code.google.com/p/dvelib/source/browse/trunk/flirPublicFormat/fpfConverter/Fpfimg.h?spec=svn3&r=3 -# 6) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,5538.0.html +# 6) https://exiftool.org/forum/index.php/topic,5538.0.html # JD) Jens Duttke private communication # # Glossary: FLIR = Forward Looking Infra Red @@ -24,7 +24,7 @@ use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; use Image::ExifTool::GPS; -$VERSION = '1.17'; +$VERSION = '1.21'; sub ProcessFLIR($$;$); sub ProcessFLIRText($$$); @@ -64,7 +64,7 @@ my %float8g = ( Format => 'float', PrintConv => 'sprintf("%.8g",$val)' ); Name => 'ImageTemperatureMax', %temperatureInfo, Notes => q{ - these temperatures may be in Celcius, Kelvin or Fahrenheit, but there is no + these temperatures may be in Celsius, Kelvin or Fahrenheit, but there is no way to tell which }, }, @@ -99,7 +99,8 @@ my %float8g = ( Format => 'float', PrintConv => 'sprintf("%.8g",$val)' ); NOTES => q{ Information extracted from FLIR FFF images and the APP1 FLIR segment of JPEG images. These tags may also be extracted from the first frame of an FLIR - SEQ file. + SEQ file, or all frames if the ExtractEmbedded option is used. Setting + ExtractEmbedded to 2 also the raw thermal data from all frames. }, "_header" => { Name => 'FFFHeader', @@ -378,7 +379,7 @@ my %float8g = ( Format => 'float', PrintConv => 'sprintf("%.8g",$val)' ); NOTES => q{ FLIR camera information. The Planck tags are variables used in the temperature calculation. See - L<http://u88.n24.queensu.ca/exiftool/forum/index.php?topic=4898.msg23972#msg23972> + L<https://exiftool.org/forum/index.php?topic=4898.msg23972#msg23972> for details. }, 0x00 => { @@ -446,6 +447,8 @@ my %float8g = ( Format => 'float', PrintConv => 'sprintf("%.8g",$val)' ); 0x21c => { Name => 'FilterSerialNumber',Format => 'string[32]' }, 0x308 => { Name => 'PlanckO', Format => 'int32s' }, #1 0x30c => { Name => 'PlanckR2', %float8g }, #1 + 0x310 => { Name => 'RawValueRangeMin', Format => 'int16u', Groups => { 2 => 'Image' } }, #forum10060 + 0x312 => { Name => 'RawValueRangeMax', Format => 'int16u', Groups => { 2 => 'Image' } }, #forum10060 0x338 => { Name => 'RawValueMedian', Format => 'int16u', Groups => { 2 => 'Image' } }, 0x33c => { Name => 'RawValueRange', Format => 'int16u', Groups => { 2 => 'Image' } }, 0x384 => { @@ -689,7 +692,15 @@ my %float8g = ( Format => 'float', PrintConv => 'sprintf("%.8g",$val)' ); T => 'True North', }, }, - # 0x48 - int32u: seen 0,77 + 0x48 => { #PH (NC) + Name => 'GPSImgDirectionRef', + Format => 'string[2]', + RawConv => 'length($val) ? $val : undef', + PrintConv => { + M => 'Magnetic North', + T => 'True North', + }, + }, 0x4c => { Name => 'GPSSpeed', %float2f, @@ -700,7 +711,11 @@ my %float8g = ( Format => 'float', PrintConv => 'sprintf("%.8g",$val)' ); %float2f, RawConv => '$val < 0 ? undef : $val', }, - # 0x54 - float: seen 0,-1 + 0x54 => { + Name => 'GPSImgDirection', + %float2f, + RawConv => '$val < 0 ? undef : $val', + }, 0x58 => { Name => 'GPSMapDatum', Format => 'string[16]', @@ -713,7 +728,7 @@ my %float8g = ( Format => 'float', PrintConv => 'sprintf("%.8g",$val)' ); ); # humidity meter information -# (ref http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,5325.0.html) +# (ref https://exiftool.org/forum/index.php/topic,5325.0.html) # The %Image::ExifTool::UserDefined hash defines new tags to be added to existing tables. %Image::ExifTool::FLIR::MeterLink = ( GROUPS => { 0 => 'APP1', 2 => 'Image' }, @@ -752,7 +767,7 @@ my %float8g = ( Format => 'float', PrintConv => 'sprintf("%.8g",$val)' ); 96 => { Name => 'Reading1Value', Format => 'double', - # convert Kelvin -> Celcius and kg/kg -> g/kg + # convert Kelvin -> Celsius and kg/kg -> g/kg ValueConv => q{ return $val - 273.15 if $$self{Reading1Units} == 0x0d and $$self{Reading1Description} != 11; return $val *= 1000 if $$self{Reading1Units} == 0x24; @@ -792,7 +807,7 @@ my %float8g = ( Format => 'float', PrintConv => 'sprintf("%.8g",$val)' ); 196 => { Name => 'Reading2Value', Format => 'double', - # convert Kelvin -> Celcius and kg/kg -> g/kg + # convert Kelvin -> Celsius and kg/kg -> g/kg ValueConv => q{ return $val - 273.15 if $$self{Reading2Units} == 0x0d and $$self{Reading2Description} != 11; return $val *= 1000 if $$self{Reading2Units} == 0x24; @@ -831,7 +846,7 @@ my %float8g = ( Format => 'float', PrintConv => 'sprintf("%.8g",$val)' ); 296 => { Name => 'Reading3Value', Format => 'double', - # convert Kelvin -> Celcius and kg/kg -> g/kg + # convert Kelvin -> Celsius and kg/kg -> g/kg ValueConv => q{ return $val - 273.15 if $$self{Reading3Units} == 0x0d and $$self{Reading3Description} != 11; return $val *= 1000 if $$self{Reading3Units} == 0x24; @@ -871,7 +886,7 @@ my %float8g = ( Format => 'float', PrintConv => 'sprintf("%.8g",$val)' ); 396 => { Name => 'Reading4Value', Format => 'double', - # convert Kelvin -> Celcius and kg/kg -> g/kg + # convert Kelvin -> Celsius and kg/kg -> g/kg ValueConv => q{ return $val - 273.15 if $$self{Reading4Units} == 0x0d and $$self{Reading4Description} != 11; return $val *= 1000 if $$self{Reading4Units} == 0x24; @@ -1339,7 +1354,7 @@ sub GetImageType($$$) sub UnescapeFLIR($) { my $char = shift; - return $char unless length $char eq 4; # escaped ASCII char (eg. '\\') + return $char unless length $char == 4; # escaped ASCII char (eg. '\\') my $val = hex $char; return chr($val) if $val < 0x80; # simple ASCII return pack('C0U', $val) if $] >= 5.006001; @@ -1398,7 +1413,6 @@ sub ProcessMeasInfo($$$) my $dirStart = $$dirInfo{DirStart} || 0; my $dataPos = $$dirInfo{DataPos}; my $dirEnd = $dirStart + $$dirInfo{DirLen}; - my $verbose = $et->Options('Verbose'); my $pos = $dirStart + 12; return 0 if $pos > $dirEnd; @@ -1456,6 +1470,7 @@ sub ProcessFLIR($$;$) my $raf = $$dirInfo{RAF} || new File::RandomAccess($$dirInfo{DataPt}); my $verbose = $et->Options('Verbose'); my $out = $et->Options('TextOut'); + my $base = $raf->Tell(); my ($i, $hdr, $buff, $rec); # read and verify FFF header @@ -1484,15 +1499,18 @@ sub ProcessFLIR($$;$) my $ver = Get32u(\$hdr, 0x14); last if $ver >= 100 and $ver < 200; # (have seen 100 and 101 - PH) ToggleByteOrder(); - $i and $et->Warn("Unsupported FLIR $type version"), return 1; + next unless $i; + return 0 if $$et{DOC_NUM}; + $et->Warn("Unsupported FLIR $type version"); + return 1; } # read the FLIR record directory my $pos = Get32u(\$hdr, 0x18); my $num = Get32u(\$hdr, 0x1c); - unless ($raf->Seek($pos) and $raf->Read($buff, $num * 0x20) == $num * 0x20) { + unless ($raf->Seek($base+$pos) and $raf->Read($buff, $num * 0x20) == $num * 0x20) { $et->Warn('Truncated FLIR FFF directory'); - return 1; + return $$et{DOC_NUM} ? 0 : 1; } unless ($tagTablePtr) { @@ -1503,6 +1521,7 @@ sub ProcessFLIR($$;$) # process the header data $et->HandleTag($tagTablePtr, '_header', $hdr); + my $success = 1; my $oldIndent = $$et{INDENT}; $$et{INDENT} .= '| '; $et->VerboseDir($type, $num); @@ -1532,12 +1551,22 @@ sub ProcessFLIR($$;$) $verbose and printf $out "%s%d) FLIR Record 0x%.2x, offset 0x%.4x, length 0x%.4x\n", $$et{INDENT}, $i, $recType, $recPos, $recLen; - unless ($raf->Seek($recPos) and $raf->Read($rec, $recLen) == $recLen) { - $et->Warn('Invalid FLIR record'); + # skip RawData records for embedded documents + if ($recType == 1 and $$et{DOC_NUM} and $et->Options('ExtractEmbedded') < 2) { + $raf->Seek($base+$recPos+$recLen) or $success = 0, last; + next; + } + unless ($raf->Seek($base+$recPos) and $raf->Read($rec, $recLen) == $recLen) { + if ($$et{DOC_NUM}) { + $success = 0; # abort processing more documents + } else { + $et->Warn('Invalid FLIR record'); + } last; } if ($$tagTablePtr{$recType}) { $et->HandleTag($tagTablePtr, $recType, undef, + Base => $base, DataPt => \$rec, DataPos => $recPos, Start => 0, @@ -1549,7 +1578,17 @@ sub ProcessFLIR($$;$) } delete $$et{SET_GROUP0}; $$et{INDENT} = $oldIndent; - return 1; + + # extract information from subsequent frames in SEQ file if ExtractEmbedded is used + if ($$dirInfo{RAF} and $et->Options('ExtractEmbedded') and not $$et{DOC_NUM}) { + for (;;) { + $$et{DOC_NUM} = $$et{DOC_COUNT} + 1; + last unless ProcessFLIR($et, $dirInfo, $tagTablePtr); + # (DOC_COUNT will be incremented automatically if we extracted any tags) + } + delete $$et{DOC_NUM}; + } + return $success; } #------------------------------------------------------------------------------ @@ -1593,7 +1632,7 @@ Systems Inc. thermal image files (FFF, FPF and JPEG format). =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. @@ -1602,7 +1641,7 @@ under the same terms as Perl itself. =over 4 -=item L<http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,4898.0.html> +=item L<https://exiftool.org/forum/index.php/topic,4898.0.html> =item L<http://www.nuage.ch/site/flir-i7-some-analysis/> @@ -1612,7 +1651,7 @@ under the same terms as Perl itself. =item L<http://code.google.com/p/dvelib/source/browse/trunk/flirPublicFormat/fpfConverter/Fpfimg.h?spec=svn3&r=3> -=item L<http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,5538.0.html> +=item L<https://exiftool.org/forum/index.php/topic,5538.0.html> =back diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Fixup.pm b/src/Image-ExifTool/lib/Image/ExifTool/Fixup.pm index beb3e114..12b52d4e 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Fixup.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Fixup.pm @@ -354,7 +354,7 @@ linear list when ApplyFixups() is called. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Flash.pm b/src/Image-ExifTool/lib/Image/ExifTool/Flash.pm index de3f63f0..c91538ab 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Flash.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Flash.pm @@ -418,7 +418,7 @@ Record: for ($rec=0; ; ++$rec) { my $num = Get32u($dataPt, $pos); $$dirInfo{Pos} = $pos + 4; my ($i, @vals); - # add array index to compount tag name + # add array index to compound tag name my $structName = $$dirInfo{StructName}; for ($i=0; $i<$num; ++$i) { $$dirInfo{StructName} = $structName . $i if defined $structName; @@ -721,7 +721,7 @@ will add AMF3 support. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/FlashPix.pm b/src/Image-ExifTool/lib/Image/ExifTool/FlashPix.pm index 220decaa..bd1007f9 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/FlashPix.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/FlashPix.pm @@ -21,7 +21,7 @@ use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; use Image::ExifTool::ASF; # for GetGUID() -$VERSION = '1.36'; +$VERSION = '1.40'; sub ProcessFPX($$); sub ProcessFPXR($$$); @@ -125,7 +125,7 @@ my @dirEntryType = qw(INVALID STORAGE STREAM LOCKBYTES PROPERTY ROOT); # list of code pages used by Microsoft # (ref http://msdn.microsoft.com/en-us/library/dd317756(VS.85).aspx) my %codePage = ( - 037 => 'IBM EBCDIC US-Canada', + 37 => 'IBM EBCDIC US-Canada', 437 => 'DOS United States', 500 => 'IBM EBCDIC International', 708 => 'Arabic (ASMO 708)', @@ -298,6 +298,7 @@ my %fpxFileType = ( %Image::ExifTool::FlashPix::Main = ( PROCESS_PROC => \&ProcessFPXR, GROUPS => { 2 => 'Image' }, + VARS => { LONG_TAGS => 0 }, NOTES => q{ The FlashPix file format, introduced in 1996, was developed by Kodak, Hewlett-Packard and Microsoft. Internally the FPX file structure mimics @@ -313,7 +314,8 @@ my %fpxFileType = ( from DOC, PPT, XLS (Microsoft Word, PowerPoint and Excel) documents, VSD (Microsoft Visio) drawings, and FLA (Macromedia/Adobe Flash project) files since these are based on the same file format as FlashPix (the Windows - Compound Binary File format). See + Compound Binary File format). Note that ExifTool identifies any + unrecognized Windows Compound Binary file as a FlashPix (FPX) file. See L<http://graphcomp.com/info/specs/livepicture/fpx.pdf> for the FlashPix specification. }, @@ -466,6 +468,25 @@ my %fpxFileType = ( ByteOrder => 'BigEndian', }, }, + # recognize Autodesk Revit files by looking at BasicFileInfo + # (but don't yet support reading their metatdata) + BasicFileInfo => { + Name => 'BasicFileInfo', + Binary => 1, + RawConv => q{ + $val =~ tr/\0//d; # brute force conversion to ASCII + if ($val =~ /\.(rfa|rft|rte|rvt)/) { + $self->OverrideFileType(uc($1), "application/$1", $1); + } + return $val; + }, + }, + IeImg => { + Name => 'EmbeddedImage', + Notes => 'embedded images in Scene7 vignette VNT files', + Groups => { 2 => 'Preview' }, + Binary => 1, + }, ); # Summary Information properties @@ -1085,7 +1106,7 @@ my %fpxFileType = ( 0x0807 => 'German (Swiss)', 0x0408 => 'Greek', 0x0409 => 'English (US)', - 0x0809 => 'English (British)', + 0x0809 => 'English (British)', 0x0c09 => 'English (Australian)', 0x040a => 'Spanish (Castilian)', 0x080a => 'Spanish (Mexican)', @@ -1108,7 +1129,7 @@ my %fpxFileType = ( 0x0415 => 'Polish', 0x0416 => 'Portuguese (Brazilian)', 0x0816 => 'Portuguese', - 0x0417 => 'Rhaeto-Romanic', + 0x0417 => 'Rhaeto-Romanic', 0x0418 => 'Romanian', 0x0419 => 'Russian', 0x041a => 'Croato-Serbian (Latin)', @@ -1175,11 +1196,11 @@ my %fpxFileType = ( VARS => { NO_ID => 1 }, CommentBy => { Groups => { 2 => 'Author' }, - Notes => 'enable Duplicates option to extract all entries', + Notes => 'enable L<Duplicates|../ExifTool.html#Duplicates> option to extract all entries', }, LastSavedBy => { Groups => { 2 => 'Author' }, - Notes => 'enable Duplicates option to extract history of up to 10 entries', + Notes => 'enable L<Duplicates|../ExifTool.html#Duplicates> option to extract history of up to 10 entries', }, DOP => { SubDirectory => { TagTable => 'Image::ExifTool::FlashPix::DOP' } }, ModifyDate => { @@ -1368,29 +1389,48 @@ sub ReadFPXValue($$$$$;$$) my $flags = $type & 0xf000; if ($flags) { if ($flags == VT_VECTOR) { - $noPad = 1; # values don't seem to be padded inside vectors + $noPad = 1; # values sometimes aren't padded inside vectors!! my $size = $oleFormatSize{VT_VECTOR}; - last if $valPos + $size > $dirEnd; + if ($valPos + $size > $dirEnd) { + $et->WarnOnce('Incorrect FPX VT_VECTOR size'); + last; + } $count = Get32u($dataPt, $valPos); push @vals, '' if $count == 0; # allow zero-element vector $valPos += 4; } else { # can't yet handle this property flag + $et->WarnOnce('Unknown FPX property'); last; } } unless ($format =~ /^VT_/) { my $size = Image::ExifTool::FormatSize($format) * $count; - last if $valPos + $size > $dirEnd; + if ($valPos + $size > $dirEnd) { + $et->WarnOnce("Incorrect FPX $format size"); + last; + } @vals = ReadValue($dataPt, $valPos, $format, $count, $size); # update position to end of value plus padding $valPos += ($count * $size + 3) & 0xfffffffc; last; } my $size = $oleFormatSize{$format}; - my ($item, $val); + my ($item, $val, $len); for ($item=0; $item<$count; ++$item) { - last if $valPos + $size > $dirEnd; + if ($valPos + $size > $dirEnd) { + $et->WarnOnce("Truncated FPX $format value"); + last; + } + # sometimes VT_VECTOR items are padded to even 4-byte boundaries, and sometimes they aren't + if ($noPad and defined $len and $len & 0x03) { + my $pad = 4 - ($len & 0x03); + if ($valPos + $pad + $size <= $dirEnd) { + # skip padding if all zeros + $valPos += $pad if substr($$dataPt, $valPos, $pad) eq "\0" x $pad; + } + } + undef $len; if ($format eq 'VT_VARIANT') { my $subType = Get32u($dataPt, $valPos); $valPos += $size; @@ -1428,9 +1468,12 @@ sub ReadFPXValue($$$$$;$$) $val = ($val - 25569) * 24 * 3600 if $val != 0; $val = Image::ExifTool::ConvertUnixTime($val); } elsif ($format =~ /STR$/) { - my $len = Get32u($dataPt, $valPos); + $len = Get32u($dataPt, $valPos); $len *= 2 if $format eq 'VT_LPWSTR'; # convert to byte count - last if $valPos + $len + 4 > $dirEnd; + if ($valPos + $len + 4 > $dirEnd) { + $et->WarnOnce("Truncated $format value"); + last; + } $val = substr($$dataPt, $valPos + 4, $len); if ($format eq 'VT_LPWSTR') { # convert wide string from Unicode @@ -1439,7 +1482,7 @@ sub ReadFPXValue($$$$$;$$) my $charset = $Image::ExifTool::charsetName{"cp$codePage"}; if ($charset) { $val = $et->Decode($val, $charset); - } elsif ($codePage eq 1200) { # UTF-16, little endian + } elsif ($codePage == 1200) { # UTF-16, little endian $val = $et->Decode($val, 'UCS2', 'II'); } } @@ -1449,8 +1492,11 @@ sub ReadFPXValue($$$$$;$$) # on even 32-bit boundaries, but this isn't always the case) $valPos += $noPad ? $len : ($len + 3) & 0xfffffffc; } elsif ($format eq 'VT_BLOB' or $format eq 'VT_CF') { - my $len = Get32u($dataPt, $valPos); - last if $valPos + $len + 4 > $dirEnd; + my $len = Get32u($dataPt, $valPos); # (use local $len because we always expect padding) + if ($valPos + $len + 4 > $dirEnd) { + $et->WarnOnce("Truncated $format value"); + last; + } $val = substr($$dataPt, $valPos + 4, $len); # update position for data length plus padding # (does this padding disappear in arrays too?) @@ -1577,14 +1623,16 @@ sub ProcessDocumentTable($) my $key = 'TableOffsets' . ($i ? " ($i)" : ''); my $offsets = $$value{$key}; last unless defined $offsets; - my $doc = $$extra{$key}{G3} if $$extra{$key}; + my $doc; + $doc = $$extra{$key}{G3} if $$extra{$key}; $doc = '' unless $doc; # get DocFlags for this sub-document my ($docFlags, $docTable); for ($j=0; ; ++$j) { my $key = 'DocFlags' . ($j ? " ($j)" : ''); last unless defined $$value{$key}; - my $tmp = $$extra{$key}{G3} if $$extra{$key}; + my $tmp; + $tmp = $$extra{$key}{G3} if $$extra{$key}; $tmp = '' unless $tmp; if ($tmp eq $doc) { $docFlags = $$value{$key}; @@ -1597,7 +1645,8 @@ sub ProcessDocumentTable($) for ($j=0; ; ++$j) { my $key = $tag . ($j ? " ($j)" : ''); last unless defined $$value{$key}; - my $tmp = $$extra{$key}{G3} if $$extra{$key}; + my $tmp; + $tmp = $$extra{$key}{G3} if $$extra{$key}; $tmp = '' unless $tmp; if ($tmp eq $doc) { $docTable = \$$value{$key}; @@ -1642,14 +1691,14 @@ sub ProcessCommentBy($$$) my $pos = $$dirInfo{DirStart}; my $end = $$dirInfo{DirLen} + $pos; $et->VerboseDir($$dirInfo{DirName}); - while ($pos + 2 < $end) { - my $len = Get16u($dataPt, $pos); - $pos += 2; - last if $pos + $len * 2 > $end; - my $author = $et->Decode(substr($$dataPt, $pos, $len*2), 'UCS2'); - $pos += $len * 2; - $et->HandleTag($tagTablePtr, CommentBy => $author); - } + while ($pos + 2 < $end) { + my $len = Get16u($dataPt, $pos); + $pos += 2; + last if $pos + $len * 2 > $end; + my $author = $et->Decode(substr($$dataPt, $pos, $len*2), 'UCS2'); + $pos += $len * 2; + $et->HandleTag($tagTablePtr, CommentBy => $author); + } return 1; } @@ -1665,24 +1714,24 @@ sub ProcessLastSavedBy($$$) my $end = $$dirInfo{DirLen} + $pos; return 0 if $pos + 6 > $end; $et->VerboseDir($$dirInfo{DirName}); - my $num = Get16u($dataPt, $pos+2); - $pos += 6; - while ($num >= 2) { - last if $pos + 2 > $end; - my $len = Get16u($dataPt, $pos); - $pos += 2; - last if $pos + $len * 2 > $end; - my $author = $et->Decode(substr($$dataPt, $pos, $len*2), 'UCS2'); - $pos += $len * 2; - last if $pos + 2 > $end; - $len = Get16u($dataPt, $pos); - $pos += 2; - last if $pos + $len * 2 > $end; - my $path = $et->Decode(substr($$dataPt, $pos, $len*2), 'UCS2'); - $pos += $len * 2; - $et->HandleTag($tagTablePtr, LastSavedBy => "$author ($path)"); - $num -= 2; - } + my $num = Get16u($dataPt, $pos+2); + $pos += 6; + while ($num >= 2) { + last if $pos + 2 > $end; + my $len = Get16u($dataPt, $pos); + $pos += 2; + last if $pos + $len * 2 > $end; + my $author = $et->Decode(substr($$dataPt, $pos, $len*2), 'UCS2'); + $pos += $len * 2; + last if $pos + 2 > $end; + $len = Get16u($dataPt, $pos); + $pos += 2; + last if $pos + $len * 2 > $end; + my $path = $et->Decode(substr($$dataPt, $pos, $len*2), 'UCS2'); + $pos += $len * 2; + $et->HandleTag($tagTablePtr, LastSavedBy => "$author ($path)"); + $num -= 2; + } return 1; } @@ -1995,7 +2044,7 @@ sub ProcessFPXR($$$) $et->Warn("Unlisted FPXR segment (index $index)") if $index != 255; } - } elsif ($type ne 3) { # not a "Reserved" segment + } elsif ($type != 3) { # not a "Reserved" segment $et->Warn("Unknown FPXR segment (type $type)"); @@ -2213,14 +2262,15 @@ sub ProcessFPX($$) # remove instance number or class ID from tag if necessary $tagInfo = $et->GetTagInfo($tagTablePtr, $1) if ($tag =~ /(.*) \d{6}$/s and $$tagTablePtr{$1}) or - ($tag =~ /(.*)_[0-9a-f]{16}$/s and $$tagTablePtr{$1}); + ($tag =~ /(.*)_[0-9a-f]{16}$/s and $$tagTablePtr{$1}) or + ($tag =~ /(.*)_[0-9]{4}$/s and $$tagTablePtr{$1}); # IeImg instances } my $lSib = Get32u(\$dir, $pos + 0x44); # left sibling my $rSib = Get32u(\$dir, $pos + 0x48); # right sibling my $chld = Get32u(\$dir, $pos + 0x4c); # child directory - # save information about object hierachy + # save information about object hierarchy my ($obj, $sub); $obj = $hier{$index} or $obj = $hier{$index} = { }; $$obj{Left} = $lSib unless $lSib == FREE_SECT; @@ -2366,7 +2416,7 @@ JPEG images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Font.pm b/src/Image-ExifTool/lib/Image/ExifTool/Font.pm index aeeb1d09..58cdb1a6 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Font.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Font.pm @@ -19,7 +19,7 @@ use strict; use vars qw($VERSION %ttLang); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.08'; +$VERSION = '1.10'; sub ProcessOTF($$); @@ -80,7 +80,7 @@ my %ttCharset = ( %ttLang = ( # Macintosh language codes (also used by QuickTime.pm) # oddities: - # 49 - Cyrllic version 83 - Roman + # 49 - Cyrillic version 83 - Roman # 50 - Arabic version 84 - Arabic # 146 - with dot above Macintosh => { @@ -88,20 +88,20 @@ my %ttCharset = ( 1 => 'fr', 25 => 'pl', 49 => 'az', 73 => 'kn', 130 => 'ca', 2 => 'de', 26 => 'hu', 50 => 'az', 74 => 'ta', 131 => 'la', 3 => 'it', 27 => 'et', 51 => 'hy', 75 => 'te', 132 => 'qu', - 4 => 'nl', 28 => 'lv', 52 => 'ka', 76 => 'si', 133 => 'gn', + 4 => 'nl-NL', 28 => 'lv', 52 => 'ka', 76 => 'si', 133 => 'gn', 5 => 'sv', 29 => 'smi', 53 => 'ro', 77 => 'my', 134 => 'ay', 6 => 'es', 30 => 'fo', 54 => 'ky', 78 => 'km', 135 => 'tt', 7 => 'da', 31 => 'fa', 55 => 'tg', 79 => 'lo', 136 => 'ug', 8 => 'pt', 32 => 'ru', 56 => 'tk', 80 => 'vi', 137 => 'dz', 9 => 'no', 33 => 'zh-CN', 57 => 'mn-MN', 81 => 'id', 138 => 'jv', - 10 => 'he', 34 => 'nl', 58 => 'mn-CN', 82 => 'tl', 139 => 'su', + 10 => 'he', 34 => 'nl-BE', 58 => 'mn-CN', 82 => 'tl', 139 => 'su', 11 => 'ja', 35 => 'ga', 59 => 'ps', 83 => 'ms-MY', 140 => 'gl', 12 => 'ar', 36 => 'sq', 60 => 'ku', 84 => 'ms-BN', 141 => 'af', 13 => 'fi', 37 => 'ro', 61 => 'ks', 85 => 'am', 142 => 'br', - 14 => 'iu', 38 => 'cs', 62 => 'sd', 86 => 'ti', 144 => 'gd', - 15 => 'is', 39 => 'sk', 63 => 'bo', 87 => 'om', 145 => 'vg', + 14 => 'el', 38 => 'cs', 62 => 'sd', 86 => 'ti', 144 => 'gd', + 15 => 'is', 39 => 'sk', 63 => 'bo', 87 => 'om', 145 => 'gv', 16 => 'mt', 40 => 'sl', 64 => 'ne', 88 => 'so', 146 => 'ga', - 17 => 'tr', 41 => 'yi', 65 => 'sa', 89 => 'sw', 147 => 'rar', + 17 => 'tr', 41 => 'yi', 65 => 'sa', 89 => 'sw', 147 => 'to', 18 => 'hr', 42 => 'sr', 66 => 'mr', 90 => 'rw', 148 => 'el', 19 => 'zh-TW', 43 => 'mk', 67 => 'bn', 91 => 'rn', 149 => 'kl', 20 => 'ur', 44 => 'bg', 68 => 'as', 92 => 'ny', 150 => 'az', @@ -117,7 +117,7 @@ my %ttCharset = ( # 0x048c - no ISO equivalent # 0x081a/0x83c - sr-SP # 0x0c0a - modern? - # 0x2409 - Carribean country code not found in ISO 3166-1 + # 0x2409 - Caribbean country code not found in ISO 3166-1 Windows => { 0x0401 => 'ar-SA', 0x0438 => 'fo', 0x0481 => 'mi', 0x1409 => 'en-NZ', 0x0402 => 'bg', 0x0439 => 'hi', 0x0482 => 'oc', 0x140a => 'es-CR', @@ -589,6 +589,11 @@ sub ProcessFont($$) $et->HandleTag($tagTablePtr, 'postfont', $2); } $rtnVal = 1; + } elsif ($buff =~ /^(wOF[F2])/) { + my $type = $1 eq 'wOFF' ? 'woff' : 'woff2'; + $et->SetFileType(uc($type), "font/$type"); + # (don't yet extract metadata from these files) + $rtnVal = 1; } else { $rtnVal = 0; } @@ -611,11 +616,13 @@ This module is used by Image::ExifTool This module contains the routines required by Image::ExifTool to read meta information from various format font files. Currently recognized font file -types are OTF, TTF, TTC, DFONT, PFA, PFB, PFM, AFM, ACFM and AMFM. +types are OTF, TTF, TTC, DFONT, PFA, PFB, PFM, AFM, ACFM and AMFM. As well, +WOFF and WOFF2 font files are identified, but metadata is not currently +extracted from these formats. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/FotoStation.pm b/src/Image-ExifTool/lib/Image/ExifTool/FotoStation.pm index a959eabe..c1c0e523 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/FotoStation.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/FotoStation.pm @@ -243,7 +243,7 @@ write information from the FotoWare FotoStation trailer. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/FujiFilm.pm b/src/Image-ExifTool/lib/Image/ExifTool/FujiFilm.pm index 41210e7d..ba38cf93 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/FujiFilm.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/FujiFilm.pm @@ -4,7 +4,7 @@ # Description: Read/write FujiFilm maker notes and RAF images # # Revisions: 11/25/2003 - P. Harvey Created -# 11/14/2007 - PH Added abilty to write RAF images +# 11/14/2007 - PH Added ability to write RAF images # # References: 1) http://park2.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html # 2) http://homepage3.nifty.com/kamisaka/makernote/makernote_fuji.htm (2007/09/11) @@ -14,11 +14,12 @@ # 6) http://forums.dpreview.com/forums/readflat.asp?forum=1012&thread=31350384 # and http://forum.photome.de/viewtopic.php?f=2&t=353&p=742#p740 # 7) Kai Lappalainen private communication -# 8) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,5223.0.html +# 8) https://exiftool.org/forum/index.php/topic,5223.0.html # 9) Zilvinas Brobliauskas private communication # 10) Albert Shan private communication -# 11) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,8377.0.html -# 12) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,9607.0.html +# 11) https://exiftool.org/forum/index.php/topic,8377.0.html +# 12) https://exiftool.org/forum/index.php/topic,9607.0.html +# 13) https://exiftool.org/forum/index.php/topic=10481.0.html # IB) Iliah Borg private communication (LibRaw) # JD) Jens Duttke private communication #------------------------------------------------------------------------------ @@ -30,12 +31,13 @@ use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; -$VERSION = '1.63'; +$VERSION = '1.82'; sub ProcessFujiDir($$$); sub ProcessFaceRec($$$); # the following RAF version numbers have been tested for writing: +# (as of ExifTool 11.70, this lookup is no longer used if the version number is numerical) my %testedRAF = ( '0100' => 'E550, E900, F770, S5600, S6000fd, S6500fd, HS10/HS11, HS30, S200EXR, X100, XF1, X-Pro1, X-S1, XQ2 Ver1.00, X-T100, GFX 50R, XF10', '0101' => 'X-E1, X20 Ver1.01, X-T3', @@ -49,11 +51,14 @@ my %testedRAF = ( '0144' => 'X100T Ver1.44', '0159' => 'S2Pro Ver1.00', '0200' => 'X10 Ver2.00', + '0201' => 'X-H1 Ver2.01', '0212' => 'S3Pro Ver2.12', '0216' => 'S3Pro Ver2.16', # (NC) '0218' => 'S3Pro Ver2.18', + '0240' => 'X-E1 Ver2.40', '0264' => 'F700 Ver2.00', '0266' => 'S9500 Ver1.01', + '0261' => 'X-E1 Ver2.61', '0269' => 'S9500 Ver1.02', '0271' => 'S3Pro Ver2.71', # UV/IR model? '0300' => 'X-E2', @@ -83,22 +88,34 @@ my %faceCategories = ( Name => 'Version', Writable => 'undef', }, - 0x0010 => { #PH (how does this compare to actual serial number?) + 0x0010 => { #PH/IB Name => 'InternalSerialNumber', Writable => 'string', Notes => q{ - this number is unique, and contains the date of manufacture, but doesn't - necessarily correspond to the camera body number -- this needs to be checked + this number is unique for most models, and contains the camera model ID and + the date of manufacture }, # eg) "FPX20017035 592D31313034060427796060110384" # "FPX 20495643 592D313335310701318AD010110047" (F40fd) - # yymmdd + # HHHHHHHHHHHHyymmdd + # HHHHHHHHHHHH = camera body number in hex + # yymmdd = date of manufacture PrintConv => q{ - return $val unless $val=~/^(.*)(\d{2})(\d{2})(\d{2})(.{12})$/; - my $yr = $2 + ($2 < 70 ? 2000 : 1900); - return "$1 $yr:$3:$4 $5"; + if ($val =~ /^(.*?\s*)([0-9a-fA-F]*)(\d{2})(\d{2})(\d{2})(.{12})\s*\0*$/s + and $4 >= 1 and $4 <= 12 and $5 >= 1 and $5 <= 31) + { + my $yr = $3 + ($3 < 70 ? 2000 : 1900); + my $sn = pack 'H*', $2; + return "$1$sn $yr:$4:$5 $6"; + } else { + # handle a couple of models which use a slightly different format + $val =~ s/\b(592D(3[0-9])+)/pack("H*",$1).' '/e; + } + return $val; }, - PrintConvInv => '$_=$val; s/ (19|20)(\d{2}):(\d{2}):(\d{2}) /$2$3$4/; $_', + # (this inverse conversion doesn't work in all cases, so it is best to write + # the ValueConv value if an authentic internal serial number is required) + PrintConvInv => '$_=$val; s/(\S+) (19|20)(\d{2}):(\d{2}):(\d{2}) /unpack("H*",$1)."$3$4$5"/e; $_', }, 0x1000 => { Name => 'Quality', @@ -128,6 +145,8 @@ my %faceCategories = ( Writable => 'int16u', PrintConv => { 0x0 => 'Auto', + 0x1 => 'Auto (white priority)', #forum10890 + 0x2 => 'Auto (ambiance priority)', #forum10890 0x100 => 'Daylight', 0x200 => 'Cloudy', 0x300 => 'Daylight Fluorescent', @@ -248,10 +267,22 @@ my %faceCategories = ( 16 => 'Commander', 0x8000 => 'Not Attached', #10 (X-T2) (or external flash off) 0x8120 => 'TTL', #10 (X-T2) + 0x8320 => 'TTL Auto - Did not fire', 0x9840 => 'Manual', #10 (X-T2) + 0x9860 => 'Flash Commander', #13 0x9880 => 'Multi-flash', #10 (X-T2) 0xa920 => '1st Curtain (front)', #10 (EF-X500 flash) + 0xaa20 => 'TTL Slow - 1st Curtain (front)', #13 + 0xab20 => 'TTL Auto - 1st Curtain (front)', #13 + 0xad20 => 'TTL - Red-eye Flash - 1st Curtain (front)', #13 + 0xae20 => 'TTL Slow - Red-eye Flash - 1st Curtain (front)', #13 + 0xaf20 => 'TTL Auto - Red-eye Flash - 1st Curtain (front)', #13 0xc920 => '2nd Curtain (rear)', #10 + 0xca20 => 'TTL Slow - 2nd Curtain (rear)', #13 + 0xcb20 => 'TTL Auto - 2nd Curtain (rear)', #13 + 0xcd20 => 'TTL - Red-eye Flash - 2nd Curtain (rear)', #13 + 0xce20 => 'TTL Slow - Red-eye Flash - 2nd Curtain (rear)', #13 + 0xcf20 => 'TTL Auto - Red-eye Flash - 2nd Curtain (rear)', #13 0xe920 => 'High Speed Sync (HSS)', #10 }, }, @@ -273,6 +304,7 @@ my %faceCategories = ( PrintConv => { 0 => 'Auto', 1 => 'Manual', + 65535 => 'Movie', #forum10766 }, }, 0x1022 => { #8/forum6579 @@ -344,6 +376,7 @@ my %faceCategories = ( 0x1a => 'Portrait 2', #PH (NC, T500, maybe "Smile & Shoot"?) 0x1b => 'Dog Face Detection', #7 0x1c => 'Cat Face Detection', #7 + 0x30 => 'HDR', #forum10799 0x40 => 'Advanced Filter', 0x100 => 'Aperture-priority AE', 0x200 => 'Shutter speed priority AE', @@ -435,6 +468,17 @@ my %faceCategories = ( PrintConv => '$val > 0 ? "+$val" : $val', PrintConvInv => '$val + 0', }, + # 0x104b - BWAdjustment for Green->Magenta (forum10800) + 0x104d => { #forum9634 + Name => 'CropMode', + Writable => 'int16u', + PrintConv => { # (perhaps this is a bit mask?) + 0 => 'n/a', + 1 => 'Full-frame on GFX', #IB + 2 => 'Sports Finder Mode', # (mechanical shutter) + 4 => 'Electronic Shutter 1.25x Crop', # (continuous high) + }, + }, 0x1050 => { #forum6109 Name => 'ShutterType', Writable => 'int16u', @@ -445,6 +489,7 @@ my %faceCategories = ( 3 => 'Electronic Front Curtain', #10 }, }, + # 0x1100 - This may not work well for newer cameras (ref forum12682) 0x1100 => [{ Name => 'AutoBracketing', Condition => '$$self{Model} eq "X-T3"', @@ -463,6 +508,7 @@ my %faceCategories = ( 0 => 'Off', 1 => 'On', 2 => 'No flash & flash', #3 + 6 => 'Pixel Shift', #IB (GFX100S) }, }], 0x1101 => { @@ -473,10 +519,12 @@ my %faceCategories = ( Name => 'DriveSettings', SubDirectory => { TagTable => 'Image::ExifTool::FujiFilm::DriveSettings' }, }, + 0x1105 => { Name => 'PixelShiftShots', Writable => 'int16u' }, #IB + 0x1106 => { Name => 'PixelShiftOffset', Writable => 'rational64s', Count => 2 }, #IB # (0x1150-0x1152 exist only for Pro Low-light and Pro Focus PictureModes) - # 0x1150 - Pro Low-light - val=1; Pro Focus - val=2 (ref 7) - # 0x1151 - Pro Low-light - val=4 (number of pictures taken?); Pro Focus - val=2,3 (ref 7) - # 0x1152 - Pro Low-light - val=1,3,4 (stacked pictures used?); Pro Focus - val=1,2 (ref 7) + # 0x1150 - Pro Low-light - val=1; Pro Focus - val=2 (ref 7); HDR - val=128 (forum10799) + # 0x1151 - Pro Low-light - val=4 (number of pictures taken?); Pro Focus - val=2,3 (ref 7); HDR - val=3 (forum10799) + # 0x1152 - Pro Low-light - val=1,3,4 (stacked pictures used?); Pro Focus - val=1,2 (ref 7); HDR - val=3 (forum10799) 0x1153 => { #forum7668 Name => 'PanoramaAngle', Writable => 'int16u', @@ -577,6 +625,9 @@ my %faceCategories = ( 0x501 => 'Pro Neg. Hi', #PH (X-Pro1) 0x600 => 'Classic Chrome', #forum6109 0x700 => 'Eterna', #12 + 0x800 => 'Classic Negative', #forum10536 + 0x900 => 'Bleach Bypass', #forum10890 + 0xa00 => 'Nostalgic Neg', #forum12085 }, }, 0x1402 => { #2 @@ -584,7 +635,7 @@ my %faceCategories = ( Writable => 'int16u', PrintHex => 1, PrintConv => { - 0x000 => 'Auto (100-400%)', + 0x000 => 'Auto', 0x001 => 'Manual', #(ref http://forum.photome.de/viewtopic.php?f=2&t=353) 0x100 => 'Standard (100%)', 0x200 => 'Wide1 (230%)', @@ -595,6 +646,7 @@ my %faceCategories = ( 0x1403 => { #2 (only valid for manual DR, ref 6) Name => 'DevelopmentDynamicRange', Writable => 'int16u', + # (shows 200, 400 or 800 for HDR200,HDR400,HDR800, ref forum10799) }, 0x1404 => { #2 Name => 'MinFocalLength', @@ -614,13 +666,22 @@ my %faceCategories = ( }, # 0x1408 - values: '0100', 'S100', 'VQ10' # 0x1409 - values: same as 0x1408 - # 0x140a - values: 0, 1, 3, 5, 7 (bit 2=red-eye detection, ref 11) + # 0x140a - values: 0, 1, 3, 5, 7 (bit 2=red-eye detection, ref 11/13) 0x140b => { #6 Name => 'AutoDynamicRange', Writable => 'int16u', PrintConv => '"$val%"', PrintConvInv => '$val=~s/\s*\%$//; $val', }, + 0x104e => { #forum10800 (X-Pro3) + Name => 'ColorChromeFXBlue', + Writable => 'int32s', + PrintConv => { + 0 => 'Off', + 32 => 'Weak', # (NC) + 64 => 'Strong', + }, + }, 0x1422 => { #8 Name => 'ImageStabilization', Writable => 'int16u', @@ -628,7 +689,9 @@ my %faceCategories = ( PrintConv => [{ 0 => 'None', 1 => 'Optical', #PH - 2 => 'Sensor-shift', #PH + 2 => 'Sensor-shift', #PH (now IBIS/OIS, ref forum13708) + 3 => 'OIS Lens', #forum9815 (optical+sensor?) + 258 => 'IBIS/OIS + DIS', #forum13708 (digital on top of IBIS/OIS) 512 => 'Digital', #PH },{ 0 => 'Off', @@ -643,6 +706,8 @@ my %faceCategories = ( PrintConv => { 0 => 'Unrecognized', 0x100 => 'Portrait Image', + 0x103 => 'Night Portrait', #forum10651 + 0x105 => 'Backlit Portrait', #forum10651 0x200 => 'Landscape Image', 0x300 => 'Night Scene', 0x400 => 'Macro', @@ -677,7 +742,11 @@ my %faceCategories = ( 0x1444 => { #12 (X-T3, only exists if DRangePriority is 'Auto') Name => 'DRangePriorityAuto', Writable => 'int16u', - PrintConv => { 1 => 'Weak', 2 => 'Strong' }, + PrintConv => { + 1 => 'Weak', + 2 => 'Strong', + 3 => 'Plus', #forum10799 + }, }, 0x1445 => { #12 (X-T3, only exists if DRangePriority is 'Fixed') Name => 'DRangePriorityFixed', @@ -687,12 +756,43 @@ my %faceCategories = ( 0x1446 => { #12 Name => 'FlickerReduction', Writable => 'int32u', + # seen values: Off=0x0000, On=0x2100,0x3100 PrintConv => q{ - my $on = ((($val >> 12) & 0xff) == 3) ? 'On' : 'Off'; + my $on = ((($val >> 8) & 0x0f) == 1) ? 'On' : 'Off'; return sprintf('%s (0x%.4x)', $on, $val); }, PrintConvInv => '$val=~/(0x[0-9a-f]+)/i; hex $1', }, + 0x1447 => { Name => 'FirmwareVersion', Writable => 'string' }, + 0x1448 => { Name => 'FirmwareVersion2', Writable => 'string' }, + 0x3803 => { #forum10037 + Name => 'VideoRecordingMode', + Groups => { 2 => 'Video' }, + Writable => 'int32u', + PrintHex => 1, + PrintConv => { + 0x00 => 'Normal', + 0x10 => 'F-log', + 0x20 => 'HLG', + }, + }, + 0x3804 => { #forum10037 + Name => 'PeripheralLighting', + Groups => { 2 => 'Video' }, + Writable => 'int16u', + PrintConv => { 0 => 'Off', 1 => 'On' }, + }, + # 0x3805 - int16u: seen 1 + 0x3806 => { #forum10037 + Name => 'VideoCompression', + Groups => { 2 => 'Video' }, + Writable => 'int16u', + PrintConv => { + 1 => 'Log GOP', + 2 => 'All Intra', + }, + }, + # 0x3810 - int32u: related to video codec (ref forum10037) 0x3820 => { #PH (HS20EXR MOV) Name => 'FrameRate', Writable => 'int16u', @@ -708,6 +808,17 @@ my %faceCategories = ( Writable => 'int16u', Groups => { 2 => 'Video' }, }, + 0x3824 => { #forum10480 (X series) + Name => 'FullHDHighSpeedRec', + Writable => 'int32u', + Groups => { 2 => 'Video' }, + PrintConv => { 1 => 'Off', 2 => 'On' }, + }, + 0x4005 => { #forum9634 + Name => 'FaceElementSelected', # (could be face or eye) + Writable => 'int16u', + Count => 4, + }, 0x4100 => { #PH Name => 'FacesDetected', Writable => 'int16u', @@ -733,6 +844,24 @@ my %faceCategories = ( 1 => 'Face', 2 => 'Left Eye', 3 => 'Right Eye', + 7 => 'Body', + 8 => 'Head', + 11 => 'Bike', + 12 => 'Body of Car', + 13 => 'Front of Car', + 14 => 'Animal Body', + 15 => 'Animal Head', + 16 => 'Animal Face', + 17 => 'Animal Left Eye', + 18 => 'Animal Right Eye', + 19 => 'Bird Body', + 20 => 'Bird Head', + 21 => 'Bird Left Eye', + 22 => 'Bird Right Eye', + 23 => 'Aircraft Body', + 25 => 'Aircraft Cockpit', + 26 => 'Train Front', + 27 => 'Train Cockpit', },'REPEAT'], }, # 0x4202 int8u[-1] - number of cooredinates in each rectangle? (ref 11) @@ -811,14 +940,22 @@ my %faceCategories = ( WRITABLE => 1, 0.1 => { Name => 'FocusMode2', - Mask => 0x000000ff, + Mask => 0x0000000f, PrintConv => { - 0 => 'AF-M', - 1 => 'AF-S', - 2 => 'AF-C', + 0x0 => 'AF-M', + 0x1 => 'AF-S', + 0x2 => 'AF-C', }, }, 0.2 => { + Name => 'PreAF', + Mask => 0x00f0, + PrintConv => { + 0 => 'Off', + 1 => 'On', + }, + }, + 0.3 => { Name => 'AFAreaMode', Mask => 0x0f00, PrintConv => { @@ -827,7 +964,7 @@ my %faceCategories = ( 2 => 'Wide/Tracking', }, }, - 0.3 => { + 0.4 => { Name => 'AFAreaPointSize', Mask => 0xf000, PrintConv => { @@ -835,7 +972,7 @@ my %faceCategories = ( OTHER => sub { return $_[0] }, }, }, - 0.4 => { + 0.5 => { Name => 'AFAreaZoneSize', Mask => 0xf0000, PrintConv => { @@ -977,9 +1114,30 @@ my %faceCategories = ( Groups => { 1 => 'RAF2' }, # (so RAF2 shows up in family 1 list) Count => 2, Notes => 'including borders', - ValueConv => 'my @v=reverse split(" ",$val);"@v"', + ValueConv => 'my @v=reverse split(" ",$val);"@v"', # reverse to show width first + PrintConv => '$val=~tr/ /x/; $val', + }, + 0x110 => { + Name => 'RawImageCropTopLeft', + Format => 'int16u', + Count => 2, + Notes => 'top margin first, then left margin', + }, + 0x111 => { + Name => 'RawImageCroppedSize', + Format => 'int16u', + Count => 2, + Notes => 'including borders', + ValueConv => 'my @v=reverse split(" ",$val);"@v"', # reverse to show width first PrintConv => '$val=~tr/ /x/; $val', }, + 0x115 => { + Name => 'RawImageAspectRatio', + Format => 'int16u', + Count => 2, + ValueConv => 'my @v=reverse split(" ",$val);"@v"', # reverse to show width first + PrintConv => '$val=~tr/ /:/; $val', + }, 0x121 => [ { Name => 'RawImageSize', @@ -1367,9 +1525,10 @@ sub WriteRAF($$) return 1; } # check to make sure this version of RAF has been tested - unless ($testedRAF{$ver}) { - $et->Warn("RAF version $ver not yet tested", 1); - } + #(removed in ExifTool 11.70) + #unless ($testedRAF{$ver}) { + # $et->Warn("RAF version $ver not yet tested", 1); + #} # read the embedded JPEG unless ($raf->Seek($jpos, 0) and $raf->Read($jpeg, $jlen) == $jlen) { $et->Error('Error reading RAF meta information'); @@ -1532,7 +1691,7 @@ FujiFilm maker notes in EXIF information, and to read/write FujiFilm RAW =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/GE.pm b/src/Image-ExifTool/lib/Image/ExifTool/GE.pm index 9e8b7ab5..3977f51d 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/GE.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/GE.pm @@ -68,7 +68,7 @@ General Imaging maker notes. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/GIF.pm b/src/Image-ExifTool/lib/Image/ExifTool/GIF.pm index dda3d08d..a804795f 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/GIF.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/GIF.pm @@ -20,7 +20,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.16'; +$VERSION = '1.19'; # road map of directory locations in GIF images my %gifMap = ( @@ -42,7 +42,7 @@ my %gifMap = ( Comment => { # for documentation only -- flag as writable for the docs, but # it won't appear in the TagLookup because there is no WRITE_PROC - Writable => 1, + Writable => 2, }, Duration => { Notes => 'duration of a single animation iteration', @@ -54,6 +54,7 @@ my %gifMap = ( Extensions => { # (for documentation only) SubDirectory => { TagTable => 'Image::ExifTool::GIF::Extensions' }, }, + TransparentColor => { }, ); # GIF89a application extensions: @@ -67,12 +68,12 @@ my %gifMap = ( 'XMP Data/XMP' => { #2 Name => 'XMP', IncludeLengthBytes => 1, # length bytes are included in the data - Writable => 1, + Writable => 2, SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' }, }, 'ICCRGBG1/012' => { #4 Name => 'ICC_Profile', - Writable => 1, + Writable => 2, SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' }, }, 'MIDICTRL/Jon' => { #5 @@ -115,6 +116,11 @@ my %gifMap = ( ValueConv => '$val + 1', }, 5 => 'BackgroundColor', + 6 => { + Name => 'PixelAspectRatio', + RawConv => '$val ? $val : undef', + ValueConv => '($val + 15) / 64', + }, ); # GIF Netscape 2.0 animation extension (ref 3) @@ -466,10 +472,13 @@ Block: } elsif ($a == 0xf9 and $length == 4) { # graphic control extension last unless $raf->Read($buff, $length) == $length; - # sum the indivual delay times + # sum the individual delay times my $delay = Get16u(\$buff, 1); $delayTime += $delay; $verbose and printf $out "Graphic Control: delay=%.2f\n", $delay / 100; + # get transparent colour + my $bits = Get8u(\$buff, 0); + $et->HandleTag($tagTablePtr, 'TransparentColor', Get8u(\$buff,3)) if $bits & 0x01; $raf->Seek(-$length, 1) or last; } elsif ($a == 0x01 and $length == 12) { # plain text extension @@ -532,7 +541,7 @@ write GIF meta information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/GIMP.pm b/src/Image-ExifTool/lib/Image/ExifTool/GIMP.pm index bcba96b8..e3e7b2e0 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/GIMP.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/GIMP.pm @@ -228,7 +228,7 @@ sub ProcessXCF($$) # skip over precision for XCV version 4 or later $raf->Seek(4, 1) if $$et{XCFVersion} =~ /^v0*(\d+)/ and $1 >= 4; - + # loop through image properties for (;;) { $raf->Read($buff, 8) == 8 or last; @@ -270,7 +270,7 @@ GIMP software. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/GPS.pm b/src/Image-ExifTool/lib/Image/ExifTool/GPS.pm index a1c8131f..693964e8 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/GPS.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/GPS.pm @@ -12,13 +12,12 @@ use strict; use vars qw($VERSION); use Image::ExifTool::Exif; -$VERSION = '1.50'; +$VERSION = '1.54'; my %coordConv = ( ValueConv => 'Image::ExifTool::GPS::ToDegrees($val)', ValueConvInv => 'Image::ExifTool::GPS::ToDMS($self, $val)', PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1)', - PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val)', ); %Image::ExifTool::GPS::Main = ( @@ -41,7 +40,7 @@ my %coordConv = ( Notes => q{ tags 0x0001-0x0006 used for camera location according to MWG 2.0. ExifTool will also accept a number when writing GPSLatitudeRef, positive for north - latitudes or negative for south, or a string ending in N or S + latitudes or negative for south, or a string containing N, North, S or South }, Count => 2, PrintConv => { @@ -50,8 +49,8 @@ my %coordConv = ( OTHER => sub { my ($val, $inv) = @_; return undef unless $inv; - return uc $1 if $val =~ /\b([NS])$/i; - return $1 eq '-' ? 'S' : 'N' if $val =~ /^([-+]?)\d+(\.\d*)?$/; + return uc $2 if $val =~ /(^|[^A-Z])([NS])(orth|outh)?\b/i; + return $1 eq '-' ? 'S' : 'N' if $val =~ /([-+]?)\d+/; return undef; }, N => 'North', @@ -63,6 +62,7 @@ my %coordConv = ( Writable => 'rational64u', Count => 3, %coordConv, + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val,undef,"lat")', }, 0x0003 => { Name => 'GPSLongitudeRef', @@ -70,7 +70,7 @@ my %coordConv = ( Count => 2, Notes => q{ ExifTool will also accept a number when writing this tag, positive for east - longitudes or negative for west, or a string ending in E or W + longitudes or negative for west, or a string containing E, East, W or West }, PrintConv => { # extract E/W if written from Composite:GPSLongitude @@ -78,8 +78,8 @@ my %coordConv = ( OTHER => sub { my ($val, $inv) = @_; return undef unless $inv; - return uc $1 if $val =~ /\b([EW])$/i; - return $1 eq '-' ? 'W' : 'E' if $val =~ /^([-+]?)\d+(\.\d*)?$/; + return uc $2 if $val =~ /(^|[^A-Z])([EW])(ast|est)?\b/i; + return $1 eq '-' ? 'W' : 'E' if $val =~ /([-+]?)\d+/; return undef; }, E => 'East', @@ -91,18 +91,19 @@ my %coordConv = ( Writable => 'rational64u', Count => 3, %coordConv, + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val,undef,"lon")', }, 0x0005 => { Name => 'GPSAltitudeRef', Writable => 'int8u', Notes => q{ - ExifTool will also accept a signed number when writing this tag, beginning - with "+" for above sea level, or "-" for below + ExifTool will also accept number when writing this tag, with negative + numbers indicating below sea level }, PrintConv => { OTHER => sub { my ($val, $inv) = @_; - return undef unless $inv and $val =~ /^([-+])/; + return undef unless $inv and $val =~ /^([-+0-9])/; return($1 eq '-' ? 1 : 0); }, 0 => 'Above Sea Level', @@ -136,22 +137,26 @@ my %coordConv = ( my ($v, $et) = @_; $v = $et->TimeNow() if lc($v) eq 'now'; my @tz; - if ($v =~ s/([-+])(.*)//s) { # remove timezone + if ($v =~ s/([-+])(\d{1,2}):?(\d{2})\s*(DST)?$//i) { # remove timezone my $s = $1 eq '-' ? 1 : -1; # opposite sign to convert back to UTC my $t = $2; - @tz = ($s*$1, $s*$2) if $t =~ /^(\d{2}):?(\d{2})\s*$/; + @tz = ($s*$2, $s*$3); } - my @a = ($v =~ /((?=\d|\.\d)\d*(?:\.\d*)?)/g); - push @a, '00' while @a < 3; + # (note: we must allow '.' as a time separator, eg. '10.30.00', with is tricky due to decimal seconds) + # YYYYmmddHHMMSS[.ss] format + my @a = ($v =~ /^[^\d]*\d{4}[^\d]*\d{1,2}[^\d]*\d{1,2}[^\d]*(\d{1,2})[^\d]*(\d{2})[^\d]*(\d{2}(?:\.\d+)?)[^\d]*$/); + # HHMMSS[.ss] format + @a or @a = ($v =~ /^[^\d]*(\d{1,2})[^\d]*(\d{2})[^\d]*(\d{2}(?:\.\d+)?)[^\d]*$/); + @a or warn('Invalid time (use HH:MM:SS[.ss][+/-HH:MM|Z])'), return undef; if (@tz) { # adjust to UTC - $a[-2] += $tz[1]; - $a[-3] += $tz[0]; - while ($a[-2] >= 60) { $a[-2] -= 60; ++$a[-3] } - while ($a[-2] < 0) { $a[-2] += 60; --$a[-3] } - $a[-3] = ($a[-3] + 24) % 24; + $a[1] += $tz[1]; + $a[0] += $tz[0]; + while ($a[1] >= 60) { $a[1] -= 60; ++$a[0] } + while ($a[1] < 0) { $a[1] += 60; --$a[0] } + $a[0] = ($a[0] + 24) % 24; } - return "$a[-3]:$a[-2]:$a[-1]"; + return join(':', @a); }, }, 0x0008 => { @@ -238,6 +243,7 @@ my %coordConv = ( Writable => 'rational64u', Count => 3, %coordConv, + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val,undef,"lat")', }, 0x0015 => { Name => 'GPSDestLongitudeRef', @@ -250,6 +256,7 @@ my %coordConv = ( Writable => 'rational64u', Count => 3, %coordConv, + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val,undef,"lon")', }, 0x0017 => { Name => 'GPSDestBearingRef', @@ -353,21 +360,41 @@ my %coordConv = ( # which must therefore require this module as necessary GPSLatitude => { SubDoc => 1, # generate for all sub-documents + Writable => 1, + Avoid => 1, + Priority => 1, # (necessary because Avoid sets default Priority to 0) Require => { 0 => 'GPS:GPSLatitude', 1 => 'GPS:GPSLatitudeRef', }, + WriteAlso => { + 'GPS:GPSLatitude' => '$val', + 'GPS:GPSLatitudeRef' => '(defined $val and $val < 0) ? "S" : "N"', + }, ValueConv => '$val[1] =~ /^S/i ? -$val[0] : $val[0]', PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lat")', }, GPSLongitude => { SubDoc => 1, # generate for all sub-documents + Writable => 1, + Avoid => 1, + Priority => 1, + Require => { + 0 => 'GPS:GPSLongitude', + 1 => 'GPS:GPSLongitudeRef', + }, + WriteAlso => { + 'GPS:GPSLongitude' => '$val', + 'GPS:GPSLongitudeRef' => '(defined $val and $val < 0) ? "W" : "E"', + }, Require => { 0 => 'GPS:GPSLongitude', 1 => 'GPS:GPSLongitudeRef', }, ValueConv => '$val[1] =~ /^W/i ? -$val[0] : $val[0]', PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")', }, GPSAltitude => { SubDoc => [1,3], # generate for sub-documents if Desire 1 or 3 has a chance to exist @@ -383,11 +410,11 @@ my %coordConv = ( my $alt = $val[0]; $alt = $val[2] unless defined $alt; return undef unless defined $alt and IsFloat($alt); - return ($val[1] || $val[3]) ? -$alt : $alt; + return(($val[1] || $val[3]) ? -$alt : $alt); }, PrintConv => q{ $val = int($val * 10) / 10; - return ($val =~ s/^-// ? "$val m Below" : "$val m Above") . " Sea Level"; + return(($val =~ s/^-// ? "$val m Below" : "$val m Above") . " Sea Level"); }, }, GPSDestLatitude => { @@ -459,7 +486,7 @@ sub ToDMS($$;$$) unless (length $val) { # don't convert an empty value - return $val if $doPrintConv and $doPrintConv eq 1; # avoid hiding existing tag when extracting + return $val if $doPrintConv and $doPrintConv eq '1'; # avoid hiding existing tag when extracting return undef; # avoid writing empty value } if ($ref) { @@ -529,17 +556,26 @@ sub ToDMS($$;$$) #------------------------------------------------------------------------------ # Convert to decimal degrees # Inputs: 0) a string containing 1-3 decimal numbers and any amount of other garbage -# 1) true if value should be negative if coordinate ends in 'S' or 'W' -# Returns: Coordinate in degrees -sub ToDegrees($;$) +# 1) true if value should be negative if coordinate ends in 'S' or 'W', +# 2) 'lat' or 'lon' to extract lat or lon from GPSCoordinates string +# Returns: Coordinate in degrees, or '' on error +sub ToDegrees($;$$) { - my ($val, $doSign) = @_; + my ($val, $doSign, $coord) = @_; + return '' if $val =~ /\b(inf|undef)\b/; # ignore invalid values + # use only lat or lon part of combined GPSCoordinates inputs + if ($coord and ($coord eq 'lat' or $coord eq 'lon') and + # (two formatted coordinate values with cardinal directions, separated by a comma) + $val =~ /^(.*(?:N(?:orth)?|S(?:outh)?)),\s*(.*(?:E(?:ast)?|W(?:est)?))$/i) + { + $val = $coord eq 'lat' ? $1 : $2; + } # extract decimal or floating point values out of any other garbage my ($d, $m, $s) = ($val =~ /((?:[+-]?)(?=\d|\.\d)\d*(?:\.\d*)?(?:[Ee][+-]\d+)?)/g); return '' unless defined $d; my $deg = $d + (($m || 0) + ($s || 0)/60) / 60; # make negative if S or W coordinate - $deg = -$deg if $doSign ? $val =~ /[^A-Z](S|W)$/i : $deg < 0; + $deg = -$deg if $doSign ? $val =~ /[^A-Z](S(outh)?|W(est)?)\s*$/i : $deg < 0; return $deg; } @@ -563,7 +599,7 @@ GPS (Global Positioning System) meta information in EXIF data. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/GeoTiff.pm b/src/Image-ExifTool/lib/Image/ExifTool/GeoTiff.pm index 80aacc41..5582bf3b 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/GeoTiff.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/GeoTiff.pm @@ -573,6 +573,8 @@ my %epsg_vertcs = ( 3053 => 'Hjorsey 1955 Lambert', 3057 => 'ISN93 Lambert 1993', 3300 => 'Estonian Coordinate System of 1992', + 3786 => 'Popular Visualisation CRS / Mercator', #PH (NC) + 3857 => 'WGS 84 / Pseudo-Mercator', #PH (NC) 20137 => 'Adindan UTM zone 37N', 20138 => 'Adindan UTM zone 38N', 20248 => 'AGD66 AMG zone 48', @@ -603,7 +605,7 @@ my %epsg_vertcs = ( 20499 => 'Ain el Abd Bahrain Grid', 20538 => 'Afgooye UTM zone 38N', 20539 => 'Afgooye UTM zone 39N', - 20700 => 'Lisbon Portugese Grid', + 20700 => 'Lisbon Portuguese Grid', 20822 => 'Aratu UTM zone 22S', 20823 => 'Aratu UTM zone 23S', 20824 => 'Aratu UTM zone 24S', @@ -2240,7 +2242,7 @@ coordinates. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Geotag.pm b/src/Image-ExifTool/lib/Image/ExifTool/Geotag.pm index a0628def..7d95872d 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Geotag.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Geotag.pm @@ -11,6 +11,10 @@ # 2012/05/08 - PH Read Winplus Beacon .TXT files # 2015/05/30 - PH Read Bramor gEO log files # 2016/07/13 - PH Added ability to geotag date/time only +# 2019/07/02 - PH Added ability to read IMU CSV files +# 2019/11/10 - PH Also write pitch to CameraElevationAngle +# 2020/12/01 - PH Added ability to read DJI CSV log files +# 2022/06/21 - PH Added ability to read Google Takeout JSON files # # References: 1) http://www.topografix.com/GPX/1/1/ # 2) http://www.gpsinformation.org/dale/nmea.htm#GSA @@ -23,8 +27,9 @@ package Image::ExifTool::Geotag; use strict; use vars qw($VERSION); use Image::ExifTool qw(:Public); +use Image::ExifTool::GPS; -$VERSION = '1.56'; +$VERSION = '1.68'; sub JITTER() { return 2 } # maximum time jitter @@ -52,6 +57,7 @@ my %xmlTag = ( vdop => 'vdop', # GPX pdop => 'pdop', # GPX sat => 'nsats', # GPX + atemp => 'atemp', # GPX (Garmin 550t) when => 'time', # KML coordinates => 'coords', # KML coord => 'coords', # KML, as written by Google Location History @@ -77,6 +83,7 @@ my %fixInfoKeys = ( track => [ 'track', 'speed' ], alt => [ 'alt' ], orient => [ 'dir', 'pitch', 'roll' ], + atemp => [ 'atemp' ], ); my %isOrient = ( dir => 1, pitch => 1, roll => 1 ); # test for orientation key @@ -127,8 +134,8 @@ sub LoadTrackLog($$;$) local ($_, $/, *EXIFTOOL_TRKFILE); my ($et, $val) = @_; my ($raf, $from, $time, $isDate, $noDate, $noDateChanged, $lastDate, $dateFlarm); - my ($nmeaStart, $fixSecs, @fixTimes, $lastFix, %nmea); - my ($canCut, $cutPDOP, $cutHDOP, $cutSats, $e0, $e1, @tmp); + my ($nmeaStart, $fixSecs, @fixTimes, $lastFix, %nmea, @csvHeadings, $sortFixes); + my ($canCut, $cutPDOP, $cutHDOP, $cutSats, $e0, $e1, @tmp, $trackFile, $trackTime); unless (eval { require Time::Local }) { return 'Geotag feature requires Time::Local installed'; @@ -154,6 +161,7 @@ sub LoadTrackLog($$;$) } else { # $val is track file name if ($et->Open(\*EXIFTOOL_TRKFILE, $val)) { + $trackFile = $val; $raf = new File::RandomAccess(\*EXIFTOOL_TRKFILE); unless ($raf->Read($_, 256)) { close EXIFTOOL_TRKFILE; @@ -196,25 +204,28 @@ sub LoadTrackLog($$;$) my $skipped = 0; my $lastSecs = 0; my $fix = { }; + my $csvDelim = $et->Options('CSVDelim'); + $csvDelim = ',' unless defined $csvDelim; my (@saveFix, $timeSpan); for (;;) { $raf->ReadLine($_) or last; # determine file format if (not $format) { + s/^\xef\xbb\xbf//; # remove leading BOM if it exists if (/^<(\?xml|gpx)[\s>]/) { # look for XML or GPX header $format = 'XML'; # check for NMEA sentence # (must ONLY start with ones that have timestamps! eg. not GSA or PTNTHPR!) - } elsif (/^\$([A-Z]{2}(RMC|GGA|GLL|ZDA)|PMGNTRK),/) { + } elsif (/^.*\$([A-Z]{2}(RMC|GGA|GLL|ZDA)|PMGNTRK),/) { $format = 'NMEA'; - $nmeaStart = $2 || $1; # save type of first sentence + $nmeaStart = $2 || $1; # save type of first sentence } elsif (/^A(FLA|XSY|FIL)/) { # (don't set format yet because we want to read HFDTE first) $nmeaStart = 'B' ; next; - } elsif (/^HFDTE(\d{2})(\d{2})(\d{2})/) { + } elsif (/^HFDTE(?:DATE:)?(\d{2})(\d{2})(\d{2})/) { my $year = $3 + ($3 >= 70 ? 1900 : 2000); - $dateFlarm = Time::Local::timegm(0,0,0,$1,$2-1,$year-1900); + $dateFlarm = Time::Local::timegm(0,0,0,$1,$2-1,$year); $nmeaStart = 'B' ; $format = 'IGC'; next; @@ -225,6 +236,60 @@ sub LoadTrackLog($$;$) $format = 'Winplus'; } elsif (/^\s*\d+\s+.*\sypr\s*$/ and (@tmp=split) == 12) { $format = 'Bramor'; + } elsif (((/\b(GPS)?Date/i and /\b(GPS)?(Date)?Time/i) or /\bTime\(seconds\)/i) and /\Q$csvDelim/) { + chomp; + @csvHeadings = split /\Q$csvDelim/; + $format = 'CSV'; + # convert recognized headings to our parameter names + foreach (@csvHeadings) { + my $param; + s/^GPS ?//; # remove leading "GPS" to simplify regex patterns + if (/^Time ?\(seconds\)$/i) { # DJI + # DJI CSV log files have a column "Time(seconds)" which is seconds since + # the start of the flight. The date/time is obtained from the file name. + $param = 'runtime'; + if ($trackFile and $trackFile =~ /(\d{4})-(\d{2})-(\d{2})[^\/]+(\d{2})-(\d{2})-(\d{2})[^\/]*$/) { + $trackTime = Image::ExifTool::TimeLocal($6,$5,$4,$3,$2-1,$1); + my $utc = PrintFixTime($trackTime); + my $tzs = Image::ExifTool::TimeZoneString([$6,$5,$4,$3,$2-1,$1-1900],$trackTime); + $et->VPrint(2, " DJI start time: $utc (local timezone is $tzs)\n"); + } else { + return 'Error getting start time from file name for DJI CSV track file'; + } + } elsif (/^Date ?Time/i) { # ExifTool addition + $param = 'datetime'; + } elsif (/^Date/i) { + $param = 'date'; + } elsif (/^Time(?! ?\(text\))/i) { # (ignore DJI "Time(text)" column) + $param = 'time'; + } elsif (/^(Pos)?Lat/i) { + $param = 'lat'; + /ref$/i and $param .= 'ref'; + } elsif (/^(Pos)?Lon/i) { + $param = 'lon'; + /ref$/i and $param .= 'ref'; + } elsif (/^(Pos)?Alt/i) { + $param = 'alt'; + } elsif (/^(Angle)?(Heading|Track)/i) { + $param = 'track'; + } elsif (/^(Angle)?Pitch/i or /^Camera ?Elevation ?Angle/i) { + $param = 'pitch'; + } elsif (/^(Angle)?Roll/i) { + $param = 'roll'; + } + if ($param) { + $et->VPrint(2, "CSV column '${_}' is $param\n"); + $_ = $param; + } else { + $et->VPrint(2, "CSV column '${_}' ignored\n"); + $_ = ''; # ignore this column + } + } + next; + } elsif (/"(timelineObjects|placeVisit|activitySegment|latitudeE7)":/) { + # Google Takeout JSON format + $format = 'JSON'; + $sortFixes = 1; # (fixes are not all in order for this format) } else { # search only first 50 lines of file for a valid fix last if ++$skipped > 50; @@ -253,6 +318,8 @@ sub LoadTrackLog($$;$) # validate altitude undef $$fix{alt} if defined $$fix{alt} and $$fix{alt} !~ /^[+-]?\d+\.?\d*/; $$has{alt} = 1 if $$fix{alt}; # set "has altitude" flag if appropriate + } elsif ($tag eq 'atemp') { + $$has{atemp} = 1; } } } @@ -292,6 +359,8 @@ sub LoadTrackLog($$;$) # validate altitude undef $$fix{alt} if defined $$fix{alt} and $$fix{alt} !~ /^[+-]?\d+\.?\d*/; $$has{alt} = 1 if $$fix{alt}; # set "has altitude" flag if appropriate + } elsif ($tag eq 'atemp') { + $$has{atemp} = 1; } } } @@ -352,7 +421,7 @@ sub LoadTrackLog($$;$) /^TP,D,\s*([-+]?\d+\.\d*),\s*([-+]?\d+\.\d*),\s*(\d+)\/(\d+)\/(\d{4}),\s*(\d+):(\d+):(\d+)/ or next; $$fix{lat} = $1; $$fix{lon} = $2; - $time = Time::Local::timegm($8,$7,$6,$4,$3-1,$5-1900); + $time = Time::Local::timegm($8,$7,$6,$4,$3-1,$5); DoneFix: $isDate = 1; $$points{$time} = $fix; push @fixTimes, $time; @@ -372,17 +441,97 @@ DoneFix: $isDate = 1; next unless @d == 3 and @t == 3; @$fix{qw(lat lon alt track dir pitch roll)} = @parts[2,3,4,5,8,9,10]; # (add the seconds afterwards in case some models have decimal seconds) - $time = Time::Local::timegm(0,$t[1],$t[0],$d[0],$d[1]-1,$d[2]-1900) + $t[2]; + $time = Time::Local::timegm(0,$t[1],$t[0],$d[0],$d[1]-1,$d[2]) + $t[2]; # set necessary flags for extra available information @$has{qw(alt track orient)} = (1,1,1); goto DoneFix; # save this fix + } elsif ($format eq 'CSV') { + chomp; + my @vals = split /\Q$csvDelim/; +# +# CSV format output of GPS/IMU POS system +# Date* - date in DD/MM/YYYY format +# Time* - time in HH:MM:SS.SSS format +# [Pos]Lat* - latitude in decimal degrees +# [Pos]Lon* - longitude in decimal degrees +# [Pos]Alt* - altitude in m relative to sea level +# [Angle]Heading* - GPSTrack in degrees true +# [Angle]Pitch* - pitch angle in degrees +# [Angle]Roll* - roll angle in degrees +# (ExifTool enhancements allow for standard tag names or descriptions as the column headings, +# add support for time zones and flexible coordinates, and allow new DateTime and Shift columns) +# + my ($param, $date, $secs, %neg); + foreach $param (@csvHeadings) { + my $val = shift @vals; + last unless defined $val; + next unless $param; + if ($param eq 'datetime') { + local $SIG{'__WARN__'} = sub { }; + my $dateTime = $et->InverseDateTime($val); + if ($dateTime) { + $date = Image::ExifTool::GetUnixTime($val, 2); + $secs = 0; + } + } elsif ($param eq 'date') { + if ($val =~ m{^(\d{2})/(\d{2})/(\d{4})$}) { + $date = Time::Local::timegm(0,0,0,$1,$2-1,$3); + } elsif ($val =~ /(\d{4}).*?(\d{2}).*?(\d{2})/) { + $date = Time::Local::timegm(0,0,0,$3,$2-1,$1); + } + } elsif ($param eq 'time') { + if ($val =~ /^(\d{1,2}):(\d{2}):(\d{2}(\.\d+)?).*?(([-+])(\d{1,2}):?(\d{2}))?/) { + $secs = (($1 * 60) + $2) * 60 + $3; + # adjust for time zone if specified + $secs += ($7 * 60 + $8) * ($6 eq '-' ? 60 : -60) if $5; + } + } elsif ($param eq 'lat' or $param eq 'lon') { + $$fix{$param} = Image::ExifTool::GPS::ToDegrees($val, 1); + } elsif ($param eq 'latref') { + $neg{lat} = 1 if $val =~ /^S/i; + } elsif ($param eq 'lonref') { + $neg{lon} = 1 if $val =~ /^W/i; + } elsif ($param eq 'runtime') { + $date = $trackTime; + $secs = $val; + } else { + $$fix{$param} = $val; + } + } + # make coordinate negative according to reference direction if necessary + foreach $param (keys %neg) { + next unless defined $$fix{$param}; + $$fix{$param} = -abs($$fix{$param}); + } + if ($date and defined $secs and defined $$fix{lat} and defined $$fix{lon}) { + $time = $date + $secs; + $$has{alt} = 1 if defined $$fix{alt}; + $$has{track} = 1 if defined $$fix{track}; + $$has{orient} = 1 if defined $$fix{pitch}; + goto DoneFix; + } + next; + } elsif ($format eq 'JSON') { + # Google Takeout JSON format + if (/"(latitudeE7|longitudeE7|latE7|lngE7|timestamp)":\s*"?(.*?)"?,?\s*[\x0d\x0a]/) { + if ($1 eq 'timestamp') { + $time = GetTime($2); + goto DoneFix if $time and $$fix{lat} and $$fix{lon}; + } elsif ($1 eq 'latitudeE7' or $1 eq 'latE7') { + $$fix{lat} = $2 * 1e-7; + } else { + $$fix{lon} = $2 * 1e-7; + } + } + next; } my (%fix, $secs, $date, $nmea); if ($format eq 'NMEA') { # ignore unrecognized NMEA sentences # (first 2 characters: GP=GPS, GL=GLONASS, GA=Gallileo, GN=combined, BD=Beidou) - next unless /^\$([A-Z]{2}(RMC|GGA|GLL|GSA|ZDA)|PMGNTRK|PTNTHPR),/; - $nmea = $2 || $1; + next unless /^(.*)\$([A-Z]{2}(RMC|GGA|GLL|GSA|ZDA)|PMGNTRK|PTNTHPR),/; + $nmea = $3 || $2; + $_ = substr($_, length($1)) if length($1); } # # IGC (flarm) (ref 4) @@ -418,7 +567,7 @@ DoneFix: $isDate = 1; $fix{track} = $12 if length $12; my $year = $15 + ($15 >= 70 ? 1900 : 2000); $secs = (($1 * 60) + $2) * 60 + $3; - $date = Time::Local::timegm(0,0,0,$13,$14-1,$year-1900); + $date = Time::Local::timegm(0,0,0,$13,$14-1,$year); # # NMEA GGA sentence (no date) # @@ -461,7 +610,7 @@ DoneFix: $isDate = 1; # $GPZDA,hhmmss.ss,DD,MM,YYYY,tzh,tzm (hhmmss in UTC) /^\$[A-Z]{2}ZDA,(\d{2})(\d{2})(\d{2}(\.\d*)?),(\d+),(\d+),(\d+)/ or next; $secs = (($1 * 60) + $2) * 60 + $3; - $date = Time::Local::timegm(0,0,0,$5,$6-1,$7-1900); + $date = Time::Local::timegm(0,0,0,$5,$6-1,$7); # # Magellan eXplorist PMGNTRK (Proprietary MaGellaN TRacK) sentence (optional date) # @@ -477,7 +626,7 @@ DoneFix: $isDate = 1; next if $13 > 31 or $14 > 12 or $15 > 99; # validate day/month/year # optional date is available in PMGNTRK sentence my $year = $15 + ($15 >= 70 ? 1900 : 2000); - $date = Time::Local::timegm(0,0,0,$13,$14-1,$year-1900); + $date = Time::Local::timegm(0,0,0,$13,$14-1,$year); } # # Honeywell HMR3000 PTNTHPR (Heading Pitch Roll) sentence (no date) @@ -620,6 +769,8 @@ DoneFix: $isDate = 1; $numPoints -= $cutHDOP; $numPoints -= $cutSats; } + # sort fixes if necessary + @fixTimes = sort { $a <=> $b } @fixTimes if $sortFixes; # mark first fix of the track while (@fixTimes) { $fix = $$points{$fixTimes[0]} or shift(@fixTimes), next; @@ -666,7 +817,7 @@ sub GetTime($) { my $timeStr = shift; $timeStr =~ /^(\d{4})-(\d+)-(\d+)T(\d+):(\d+):(\d+)(\.\d+)?(.*)/ or return undef; - my $time = Time::Local::timegm($6,$5,$4,$3,$2-1,$1-1900); + my $time = Time::Local::timegm($6,$5,$4,$3,$2-1,$1); $time += $7 if $7; # add fractional seconds my $tz = $8; # adjust for time zone (otherwise assume UTC) @@ -831,7 +982,7 @@ sub SetGeoValues($$;$) last; } if ($tz) { - $time = Time::Local::timegm($sec,$min,$hr,$day,$mon-1,$year-1900); + $time = Time::Local::timegm($sec,$min,$hr,$day,$mon-1,$year); # use timezone from date/time value if ($tz ne 'Z') { my $tzmin = $t1 * 60 + $t2; @@ -839,7 +990,7 @@ sub SetGeoValues($$;$) } } else { # assume local timezone - $time = Image::ExifTool::TimeLocal($sec,$min,$hr,$day,$mon-1,$year-1900); + $time = Image::ExifTool::TimeLocal($sec,$min,$hr,$day,$mon-1,$year); } # add fractional seconds $time += $fs if $fs and $fs ne '.'; @@ -934,7 +1085,7 @@ sub SetGeoValues($$;$) # loop through available fix information categories # (pos, track, alt, orient) my ($category, $key); -Category: foreach $category (qw{pos track alt orient}) { +Category: foreach $category (qw{pos track alt orient atemp}) { next unless $$has{$category}; my ($f, $p0b, $p1b, $f0b); # loop through specific fix information keys @@ -1055,10 +1206,20 @@ Category: foreach $category (qw{pos track alt orient}) { } @r = $et->SetNewValue(GPSImgDirection => $$tFix{dir}, %opts); @r = $et->SetNewValue(GPSImgDirectionRef => (defined $$tFix{dir} ? 'T' : undef), %opts); + @r = $et->SetNewValue(CameraElevationAngle => $$tFix{pitch}, %opts); # Note: GPSPitch and GPSRoll are non-standard, and must be user-defined @r = $et->SetNewValue(GPSPitch => $$tFix{pitch}, %opts); @r = $et->SetNewValue(GPSRoll => $$tFix{roll}, %opts); } + if ($$has{atemp}) { + my $tFix = $fix; + if (not defined $$fix{atemp} and defined $iExt) { + # (not all fixes have atemp, so try interpolating specifically for this) + my $p = FindFix($et,'atemp',$times,$points,$iExt,$iDir,$geoMaxExtSecs); + $tFix = $p if $p; + } + @r = $et->SetNewValue(AmbientTemperature => $$tFix{atemp}, %opts); + } unless ($xmp) { my ($latRef, $lonRef); $latRef = ($$fix{lat} > 0 ? 'N' : 'S') if defined $$fix{lat}; @@ -1075,15 +1236,16 @@ Category: foreach $category (qw{pos track alt orient}) { @r = $et->SetNewValue(GPSDateTime => "$gpsDate $gpsTime", %opts); } } else { - my %opts; + my %opts = ( IgnorePermanent => 1 ); $opts{Replace} = 2 if defined $val; # remove existing new values $opts{Group} = $writeGroup if $writeGroup; # reset any GPS values we might have already set foreach (qw(GPSLatitude GPSLatitudeRef GPSLongitude GPSLongitudeRef GPSAltitude GPSAltitudeRef GPSDateStamp GPSTimeStamp GPSDateTime - GPSTrack GPSTrackRef GPSSpeed GPSSpeedRef - GPSImgDirection GPSImgDirectionRef GPSPitch GPSRoll)) + GPSTrack GPSTrackRef GPSSpeed GPSSpeedRef GPSImgDirection + GPSImgDirectionRef GPSPitch GPSRoll CameraElevationAngle + AmbientTemperature)) { my @r = $et->SetNewValue($_, undef, %opts); } @@ -1267,7 +1429,8 @@ This module is used by Image::ExifTool This module loads GPS track logs, interpolates to determine position based on time, and sets new GPS values for geotagging images. Currently supported formats are GPX, NMEA RMC/GGA/GLL, KML, IGC, Garmin XML and TCX, Magellan -PMGNTRK, Honeywell PTNTHPR, Winplus Beacon text, and Bramor gEO log files. +PMGNTRK, Honeywell PTNTHPR, Bramor gEO, Winplus Beacon text, Google Takeout +JSON, GPS/IMU CSV, DJI CSV, ExifTool CSV log files. Methods in this module should not be called directly. Instead, the Geotag feature is accessed by writing the values of the ExifTool Geotag, Geosync @@ -1276,12 +1439,12 @@ in the tag name documentation). =head1 NOTES -To take advantage of attitude information in the PTNTHPR NMEA sentence, two -user-defined tags, GPSPitch and GPSRoll, must be active. +To take advantage of attitude information in the PTNTHPR NMEA sentence, the +user-defined tag GPSRoll, must be active. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/GoPro.pm b/src/Image-ExifTool/lib/Image/ExifTool/GoPro.pm new file mode 100644 index 00000000..58df3d45 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/GoPro.pm @@ -0,0 +1,757 @@ +#------------------------------------------------------------------------------ +# File: GoPro.pm +# +# Description: Read information from GoPro videos +# +# Revisions: 2018/01/12 - P. Harvey Created +# +# References: 1) https://github.com/gopro/gpmf-parser +# 2) https://github.com/stilldavid/gopro-utils +#------------------------------------------------------------------------------ + +package Image::ExifTool::GoPro; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); +use Image::ExifTool::QuickTime; + +$VERSION = '1.07'; + +sub ProcessGoPro($$$); +sub ProcessString($$$); +sub ScaleValues($$); +sub AddUnits($$$); +sub ConvertSystemTime($$); + +# GoPro data types that have ExifTool equivalents (ref 1) +my %goProFmt = ( # format codes + # 0x00 - container (subdirectory) + 0x62 => 'int8s', # 'b' + 0x42 => 'int8u', # 'B' + 0x63 => 'string', # 'c' (possibly null terminated) + 0x73 => 'int16s', # 's' + 0x53 => 'int16u', # 'S' + 0x6c => 'int32s', # 'l' + 0x4c => 'int32u', # 'L' + 0x66 => 'float', # 'f' + 0x64 => 'double', # 'd' + 0x46 => 'undef', # 'F' (4-char ID) + 0x47 => 'undef', # 'G' (16-byte uuid) + 0x6a => 'int64s', # 'j' + 0x4a => 'int64u', # 'J' + 0x71 => 'fixed32s', # 'q' + 0x51 => 'fixed64s', # 'Q' + 0x55 => 'undef', # 'U' (16-byte date) + 0x3f => 'undef', # '?' (complex structure) +); + +# sizes of format codes if different than what FormatSize() would return +my %goProSize = ( + 0x46 => 4, + 0x47 => 16, + 0x55 => 16, +); + +# tagInfo elements to add units to PrintConv value +my %addUnits = ( + AddUnits => 1, + PrintConv => 'Image::ExifTool::GoPro::AddUnits($self, $val, $tag)', +); + +# Tags found in the GPMF box of Hero6 mp4 videos (ref PH), and +# the gpmd-format timed metadata of Hero5 and Hero6 videos (ref 1) +%Image::ExifTool::GoPro::GPMF = ( + PROCESS_PROC => \&ProcessGoPro, + GROUPS => { 2 => 'Camera' }, + NOTES => q{ + Tags extracted from the GPMF box of GoPro MP4 videos, the APP6 "GoPro" + segment of JPEG files, and from the "gpmd" timed metadata if the + L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> (-ee) option is enabled. Many more tags exist, but are + currently unknown and extracted only with the L<Unknown|../ExifTool.html#Unknown> (-u) option. Please + let me know if you discover the meaning of any of these unknown tags. See + L<https://github.com/gopro/gpmf-parser> for details about this format. + }, + ACCL => { #2 (gpmd) + Name => 'Accelerometer', + Notes => 'accelerator readings in m/s2', + Binary => 1, + }, + # ANGX (GPMF-GEOC) - seen -0.05 (fmt d, Max) + # ANGY (GPMF-GEOC) - seen 179.9 (fmt d, Max) + # ANGZ (GPMF-GEOC) - seen 0.152 (fmt d, Max) + ALLD => 'AutoLowLightDuration', #1 (gpmd) (untested) + # APTO (GPMF) - seen: 'RAW', 'DYNM' (fmt c) + ATTD => { #PH (Karma) + Name => 'Attitude', + # UNIT=s,rad,rad,rad,rad/s,rad/s,rad/s, + # TYPE=LffffffB + # SCAL=1000 1 1 1 1 1 1 1 + Binary => 1, + }, + ATTR => { #PH (Karma) + Name => 'AttitudeTarget', + # UNIT=s,rad,rad,rad, + # TYPE=Jffff + # SCAL=1000 1 1 1 1 + Binary => 1, + }, + AUDO => 'AudioSetting', #PH (GPMF - seen: 'WIND', fmt c) + # AUPT (GPMF) - seen: 'N','Y' (fmt c) + BPOS => { #PH (Karma) + Name => 'Controller', + Unknown => 1, + # UNIT=deg,deg,m,deg,deg,m,m,m + # TYPE=lllfffff + # SCAL=10000000 10000000 1000 1 1 1 1 1 + %addUnits, + }, + # BRID (GPMF) - seen: 0 (fmt B) + # BROD (GPMF) - seen: 'ASK','' (fmt c) + # CALH (GPMF-GEOC) - seen 3040 (fmt L, Max) + # CALW (GPMF-GEOC) - seen 4056 (fmt L, Max) + CASN => 'CameraSerialNumber', #PH (GPMF - seen: 'C3221324545448', fmt c) + # CINF (GPMF) - seen: 0x67376be7709bc8876a8baf3940908618, 0xe230988539b30cf5f016627ae8fc5395, + # 0x8bcbe424acc5b37d7d77001635198b3b (fmt B) (Camera INFormation?) + # CMOD (GPMF) - seen: 12,13,17 [12 360 video, 13 time-laps video, 17 JPEG] (fmt B) + # CRTX (GPMF-BACK/FRNT) - double[1] + # CRTY (GPMF-BACK/FRNT) - double[1] + CSEN => { #PH (Karma) + Name => 'CoyoteSense', + # UNIT=s,rad/s,rad/s,rad/s,g,g,g,,,, + # TYPE=LffffffLLLL + # SCAL=1000 1 1 1 1 1 1 1 1 1 1 + Binary => 1, + }, + CYTS => { #PH (Karma) + Name => 'CoyoteStatus', + # UNIT=s,,,,,rad,rad,rad,, + # TYPE=LLLLLfffBB + # SCAL=1000 1 1 1 1 1 1 1 1 1 + Binary => 1, + }, + DEVC => { #PH (gpmd,GPMF, fmt \0) + Name => 'DeviceContainer', + SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' }, + # (Max) DVID=1,DVNM='Global Settings',VERS,FMWR,LINF,CINF,CASN,MINF,MUID,CMOD,MTYP,OREN, + # DZOM,DZST,SMTR,PRTN,PTWB,PTSH,PTCL,EXPT,PIMX,PIMN,PTEV,RATE,SROT,ZFOV,VLTE,VLTA, + # EISE,EISA,AUPT,AUDO,BROD,BRID,PVUL,PRJT,SOFF + # (Max) DVID='GEOC',DVNM='Geometry Calibrations',SHFX,SHFY,SHFZ,ANGX,ANGY,ANGZ,CALW,CALH + # (Max) DVID='BACK',DVNM='Back Lens',KLNS,CTRX,CTRY,MFOV,SFTR + # (Max) DVID='FRNT',DVNM='Front Lens',KLNS,CTRX,CTRY,MFOV,SFTR + # (Max) DVID='HLMT',DVNM='Highlights' + }, + # DVID (GPMF) - DeviceID; seen: 1 (fmt L), HLMT (fmt F), GEOC (fmt F), 'BACK' (fmt F, Max) + DVID => { Name => 'DeviceID', Unknown => 1 }, #2 (gpmd) + # DVNM (GPMF) seen: 'Video Global Settings' (fmt c), 'Highlights' (fmt c), 'Geometry Calibrations' (Max) + # DVNM (gpmd) seen: 'Camera' (Hero5), 'Hero6 Black' (Hero6), 'GoPro Karma v1.0' (Karma) + DVNM => 'DeviceName', #PH (n/c) + DZOM => { #PH (GPMF - seen: 'Y', fmt c) + Name => 'DigitalZoom', + PrintConv => { N => 'No', Y => 'Yes' }, + }, + # DZST (GPMF) - seen: 0 (fmt L) (something to do with digital zoom maybe?) + EISA => { #PH (GPMF) - seen: 'Y','N','HS EIS','N/A' (fmt c) [N was for a time-lapse video] + Name => 'ElectronicImageStabilization', + }, + # EISE (GPMF) - seen: 'Y','N' (fmt c) + EMPT => { Name => 'Empty', Unknown => 1 }, #2 (gpmd) + ESCS => { #PH (Karma) + Name => 'EscapeStatus', + # UNIT=s,rpm,rpm,rpm,rpm,rpm,rpm,rpm,rpm,degC,degC,degC,degC,V,V,V,V,A,A,A,A,,,,,,,,, + # TYPE=JSSSSSSSSssssSSSSSSSSSSSSSSSSB + # (no SCAL!) + Unknown => 1, + %addUnits, + }, + # EXPT (GPMF) - seen: '', 'AUTO' (fmt c) + FACE => 'FaceDetected', #PH (gpmd) + FCNM => 'FaceNumbers', #PH (gpmd) (faces counted per frame, ref 1) + FMWR => 'FirmwareVersion', #PH (GPMF - seen: HD6.01.01.51.00, fmt c) + FWVS => 'OtherFirmware', #PH (NC) (gpmd - seen: '1.1.11.0', Karma) + GLPI => { #PH (gpmd, Karma) + Name => 'GPSPos', + # UNIT=s,deg,deg,m,m,m/s,m/s,m/s,deg + # TYPE=LllllsssS + # SCAL=1000 10000000 10000000 1000 1000 100 100 100 100 + RawConv => '$val', # necessary to use scaled value instead of raw data as subdir data + SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GLPI' }, + }, + GPRI => { #PH (gpmd, Karma) + Name => 'GPSRaw', + # UNIT=s,deg,deg,m,m,m,m/s,deg,, + # TYPE=JlllSSSSBB + # SCAL=1000000,10000000,10000000,1000,100,100,100,100,1,1 + Unknown => 1, + RawConv => '$val', # necessary to use scaled value instead of raw data as subdir data + SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPRI' }, + }, + GPS5 => { #2 (gpmd) + Name => 'GPSInfo', + # SCAL=10000000,10000000,1000,1000,100 + RawConv => '$val', # necessary to use scaled value instead of raw data as subdir data + SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPS5' }, + }, + GPSF => { #2 (gpmd) + Name => 'GPSMeasureMode', + PrintConv => { + 2 => '2-Dimensional Measurement', + 3 => '3-Dimensional Measurement', + }, + }, + GPSP => { #2 (gpmd) + Name => 'GPSHPositioningError', + Description => 'GPS Horizontal Positioning Error', + ValueConv => '$val / 100', # convert from cm to m + }, + GPSU => { #2 (gpmd) + Name => 'GPSDateTime', + Groups => { 2 => 'Time' }, + # (HERO5 writes this in 'c' format, HERO6 writes 'U') + ValueConv => '$val =~ s/^(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/20$1:$2:$3 $4:$5:/; $val', + PrintConv => '$self->ConvertDateTime($val)', + }, + GYRO => { #2 (gpmd) + Name => 'Gyroscope', + Notes => 'gyroscope readings in rad/s', + Binary => 1, + }, + # HFLG (APP6) - seen: 0 + ISOE => 'ISOSpeeds', #PH (gpmd) + ISOG => { #2 (gpmd) + Name => 'ImageSensorGain', + Binary => 1, + }, + KBAT => { #PH (gpmd) (Karma) + Name => 'BatteryStatus', + # UNIT=A,Ah,J,degC,V,V,V,V,s,%,,,,,% + # TYPE=lLlsSSSSSSSBBBb + # SCAL=1000,1000,0.00999999977648258,100,1000,1000,1000,1000,0.0166666675359011,1,1,1,1,1,1 + RawConv => '$val', # necessary to use scaled value instead of raw data as subdir data + SubDirectory => { TagTable => 'Image::ExifTool::GoPro::KBAT' }, + }, + # KLNS (GPMF-BACK/FRNT) - double[5] (fmt d, Max) + # LINF (GPMF) - seen: LAJ7061916601668,C3341326002180,C33632245450981 (fmt c) (Lens INFormation?) + LNED => { #PH (Karma) + Name => 'LocalPositionNED', + # UNIT=s,m,m,m,m/s,m/s,m/s + # TYPE=Lffffff + # SCAL=1000 1 1 1 1 1 1 + Binary => 1, + }, + MAGN => 'Magnetometer', #1 (gpmd) (units of uT) + # MFOV (GPMF-BACK/FRNT) - seen: 100 (fmt d, Max) + MINF => { #PH (GPMF - seen: HERO6 Black, fmt c) + Name => 'Model', + Groups => { 2 => 'Camera' }, + Description => 'Camera Model Name', + }, + # MTYP (GPMF) - seen: 0,1,5,11 [1 for time-lapse video, 5 for 360 video, 11 for JPEG] (fmt B) + # MUID (GPMF) - seen: 3882563431 2278071152 967805802 411471936 0 0 0 0 (fmt L) + OREN => { #PH (GPMF - seen: 'U', fmt c) + Name => 'AutoRotation', + PrintConv => { + U => 'Up', + D => 'Down', # (NC) + A => 'Auto', # (NC) + }, + }, + # (most of the "P" tags are ProTune settings - PH) + PHDR => 'HDRSetting', #PH (APP6 - seen: 0) + PIMN => 'AutoISOMin', #PH (GPMF - seen: 100, fmt L) + PIMX => 'AutoISOMax', #PH (GPMF - seen: 1600, fmt L) + # PRAW (APP6) - seen: 0, 'N', 'Y' (fmt c) + PRES => 'PhotoResolution', #PH (APP6 - seen: '12MP_W') + # PRJT (APP6) - seen: 'GPRO','EACO' (fmt F, Hero8, Max) + PRTN => { #PH (GPMF - seen: 'N', fmt c) + Name => 'ProTune', + PrintConv => { + N => 'Off', + Y => 'On', # (NC) + }, + }, + PTCL => 'ColorMode', #PH (GPMF - seen: 'GOPRO', fmt c' APP6: 'FLAT') + PTEV => 'ExposureCompensation', #PH (GPMF - seen: '0.0', fmt c) + PTSH => 'Sharpness', #PH (GPMF - seen: 'HIGH', fmt c) + PTWB => 'WhiteBalance', #PH (GPMF - seen: 'AUTO', fmt c) + # PVUL (APP6) - seen: 'F' (fmt c, Hero8, Max) + RATE => 'Rate', #PH (GPMF - seen: '0_5SEC', fmt c; APP6 - seen: '4_1SEC') + RMRK => { #2 (gpmd) + Name => 'Comments', + ValueConv => '$self->Decode($val, "Latin")', + }, + SCAL => { #2 (gpmd) scale factor for subsequent data + Name => 'ScaleFactor', + Unknown => 1, + }, + SCPR => { #PH (Karma) [stream was empty] + Name => 'ScaledPressure', + # UNIT=s,Pa,Pa,degC + # TYPE=Lffs + # SCAL=1000 0.00999999977648258 0.00999999977648258 100 + %addUnits, + }, + # SFTR (GPMF-BACK/FRNT) - seen 0.999,1.00004 (fmt d, Max) + # SHFX (GPMF-GEOC) - seen 22.92 (fmt d, Max) + # SHFY (GPMF-GEOC) - seen 0.123 (fmt d, Max) + # SHFZ (GPMF-GEOC) - seen 36.06 (fmt d, Max) + SHUT => { #2 (gpmd) + Name => 'ExposureTimes', + PrintConv => q{ + my @a = split ' ', $val; + $_ = Image::ExifTool::Exif::PrintExposureTime($_) foreach @a; + return join ' ', @a; + }, + }, + SIMU => { #PH (Karma) + Name => 'ScaledIMU', + # UNIT=s,g,g,g,rad/s,rad/s,rad/s,T,T,T + # TYPE=Lsssssssss + # SCAL=1000 1000 1000 1000 1000 1000 1000 1000 1000 1000 + %addUnits, + }, + SIUN => { #2 (gpmd - seen : 'm/s2','rad/s') + Name => 'SIUnits', + Unknown => 1, + ValueConv => '$self->Decode($val, "Latin")', + }, + # SMTR (GPMF) - seen: 'N' (fmt c) + # SOFF (APP6) - seen: 0 (fmt L, Hero8, Max) + # SROT (GPMF) - seen 20.60 (fmt f, Max) + STMP => { #1 (gpmd) + Name => 'TimeStamp', + ValueConv => '$val / 1e6', + }, + STRM => { #2 (gpmd,GPMF, fmt \0) + Name => 'NestedSignalStream', + SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' }, + }, + STNM => { #2 (gpmd) + Name => 'StreamName', + Unknown => 1, + ValueConv => '$self->Decode($val, "Latin")', + }, + SYST => { #PH (Karma) + Name => 'SystemTime', + # UNIT=s,s + # TYPE=JJ + # SCAL=1000000 1000 + # save system time calibrations for later + RawConv => q{ + my @v = split ' ', $val; + if (@v == 2) { + my $s = $$self{SystemTimeList}; + $s or $s = $$self{SystemTimeList} = [ ]; + push @$s, \@v; + } + return $val; + }, + }, + # TICK => { Name => 'InTime', Unknown => 1, ValueConv => '$val/1000' }, #1 (gpmd) + TMPC => { #2 (gpmd) + Name => 'CameraTemperature', + PrintConv => '"$val C"', + }, + # TOCK => { Name => 'OutTime', Unknown => 1, ValueConv => '$val/1000' }, #1 (gpmd) + TSMP => { Name => 'TotalSamples', Unknown => 1 }, #2 (gpmd) + TYPE => { Name => 'StructureType', Unknown => 1 }, #2 (gpmd,GPMF - eg 'LLLllfFff', fmt c) + UNIT => { #2 (gpmd) alternative units + Name => 'Units', + Unknown => 1, + ValueConv => '$self->Decode($val, "Latin")', + }, + VERS => { + Name => 'MetadataVersion', + PrintConv => '$val =~ tr/ /./; $val', + }, + VFOV => { #PH (GPMF - seen: 'W', fmt c) + Name => 'FieldOfView', + PrintConv => { + W => 'Wide', + S => 'Super View', # (NC, not seen) + L => 'Linear', # (NC, not seen) + }, + }, + # VLTA (GPMF) - seen: 78 ('N') (fmt B -- wrong format?) + VFRH => { #PH (Karma) + Name => 'VisualFlightRulesHUD', + BinaryData => 1, + # UNIT=m/s,m/s,m,m/s,deg,% + # TYPE=ffffsS + }, + # VLTE (GPMF) - seen: 'Y','N' (fmt c) + WBAL => 'ColorTemperatures', #PH (gpmd) + WRGB => { #PH (gpmd) + Name => 'WhiteBalanceRGB', + Binary => 1, + }, + # ZFOV (APP6,GPMF) - seen: 148.34, 0 (fmt f, Hero8, Max) + # the following ref forum12825 + MUID => { + Name => 'MediaUniqueID', + PrintConv => q{ + my @a = split ' ', $val; + $_ = sprintf('%.8x',$_) foreach @a; + return join('', @a); + }, + }, + EXPT => 'MaximumShutterAngle', + MTRX => 'AccelerometerMatrix', + ORIN => 'InputOrientation', + ORIO => 'OutputOrientation', + UNIF => 'InputUniformity', + SROT => 'SensorReadoutTime', +); + +# GoPro GPS5 tags (ref 2) (Hero5,Hero6) +%Image::ExifTool::GoPro::GPS5 = ( + PROCESS_PROC => \&ProcessString, + GROUPS => { 1 => 'GoPro', 2 => 'Location' }, + VARS => { HEX_ID => 0, ID_LABEL => 'Index' }, + 0 => { # (unit='deg') + Name => 'GPSLatitude', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + }, + 1 => { # (unit='deg') + Name => 'GPSLongitude', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + }, + 2 => { # (unit='m') + Name => 'GPSAltitude', + PrintConv => '"$val m"', + }, + 3 => 'GPSSpeed', # (unit='m/s') + 4 => 'GPSSpeed3D', # (unit='m/s') +); + +# GoPro GPRI tags (ref PH) (Karma) +%Image::ExifTool::GoPro::GPRI = ( + PROCESS_PROC => \&ProcessString, + GROUPS => { 1 => 'GoPro', 2 => 'Location' }, + VARS => { HEX_ID => 0, ID_LABEL => 'Index' }, + 0 => { # (unit='s') + Name => 'GPSDateTimeRaw', + Groups => { 2 => 'Time' }, + ValueConv => \&ConvertSystemTime, # convert to date/time based on SystemTime clock + PrintConv => '$self->ConvertDateTime($val)', + }, + 1 => { # (unit='deg') + Name => 'GPSLatitudeRaw', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + }, + 2 => { # (unit='deg') + Name => 'GPSLongitudeRaw', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + }, + 3 => { + Name => 'GPSAltitudeRaw', # (NC) + PrintConv => '"$val m"', + }, + # (unknown tags must be defined so that ProcessString() will iterate through all values) + 4 => { Name => 'GPRI_Unknown4', Unknown => 1, Hidden => 1, PrintConv => '"$val m"' }, + 5 => { Name => 'GPRI_Unknown5', Unknown => 1, Hidden => 1, PrintConv => '"$val m"' }, + 6 => 'GPSSpeedRaw', # (NC) # (unit='m/s' -- should convert to other units?) + 7 => 'GPSTrackRaw', # (NC) # (unit='deg') + 8 => { Name => 'GPRI_Unknown8', Unknown => 1, Hidden => 1 }, # (no units) + 9 => { Name => 'GPRI_Unknown9', Unknown => 1, Hidden => 1 }, # (no units) +); + +# GoPro GLPI tags (ref PH) (Karma) +%Image::ExifTool::GoPro::GLPI = ( + PROCESS_PROC => \&ProcessString, + GROUPS => { 1 => 'GoPro', 2 => 'Location' }, + VARS => { HEX_ID => 0, ID_LABEL => 'Index' }, + 0 => { # (unit='s') + Name => 'GPSDateTime', + Groups => { 2 => 'Time' }, + ValueConv => \&ConvertSystemTime, # convert to date/time based on SystemTime clock + PrintConv => '$self->ConvertDateTime($val)', + }, + 1 => { # (unit='deg') + Name => 'GPSLatitude', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + }, + 2 => { # (unit='deg') + Name => 'GPSLongitude', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + }, + 3 => { # (unit='m') + Name => 'GPSAltitude', # (NC) + PrintConv => '"$val m"', + }, + # (unknown tags must be defined so that ProcessString() will iterate through all values) + 4 => { Name => 'GLPI_Unknown4', Unknown => 1, Hidden => 1, PrintConv => '"$val m"' }, + 5 => { Name => 'GPSSpeedX', PrintConv => '"$val m/s"' }, # (NC) + 6 => { Name => 'GPSSpeedY', PrintConv => '"$val m/s"' }, # (NC) + 7 => { Name => 'GPSSpeedZ', PrintConv => '"$val m/s"' }, # (NC) + 8 => { Name => 'GPSTrack' }, # (unit='deg') +); + +# GoPro KBAT tags (ref PH) +%Image::ExifTool::GoPro::KBAT = ( + PROCESS_PROC => \&ProcessString, + GROUPS => { 1 => 'GoPro', 2 => 'Camera' }, + VARS => { HEX_ID => 0, ID_LABEL => 'Index' }, + NOTES => 'Battery status information found in GoPro Karma videos.', + 0 => { Name => 'BatteryCurrent', PrintConv => '"$val A"' }, + 1 => { Name => 'BatteryCapacity', PrintConv => '"$val Ah"' }, + 2 => { Name => 'KBAT_Unknown2', PrintConv => '"$val J"', Unknown => 1, Hidden => 1 }, + 3 => { Name => 'BatteryTemperature', PrintConv => '"$val C"' }, + 4 => { Name => 'BatteryVoltage1', PrintConv => '"$val V"' }, + 5 => { Name => 'BatteryVoltage2', PrintConv => '"$val V"' }, + 6 => { Name => 'BatteryVoltage3', PrintConv => '"$val V"' }, + 7 => { Name => 'BatteryVoltage4', PrintConv => '"$val V"' }, + 8 => { Name => 'BatteryTime', PrintConv => 'ConvertDuration(int($val + 0.5))' }, # (NC) + 9 => { Name => 'KBAT_Unknown9', PrintConv => '"$val %"', Unknown => 1, Hidden => 1, }, + 10 => { Name => 'KBAT_Unknown10', Unknown => 1, Hidden => 1 }, # (no units) + 11 => { Name => 'KBAT_Unknown11', Unknown => 1, Hidden => 1 }, # (no units) + 12 => { Name => 'KBAT_Unknown12', Unknown => 1, Hidden => 1 }, # (no units) + 13 => { Name => 'KBAT_Unknown13', Unknown => 1, Hidden => 1 }, # (no units) + 14 => { Name => 'BatteryLevel', PrintConv => '"$val %"' }, +); + +# GoPro fdsc tags written by the Hero5 and Hero6 (ref PH) +%Image::ExifTool::GoPro::fdsc = ( + GROUPS => { 2 => 'Camera' }, + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + NOTES => q{ + Tags extracted from the MP4 "fdsc" timed metadata when the L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> + (-ee) option is used. + }, + 0x08 => { Name => 'FirmwareVersion', Format => 'string[15]' }, + 0x17 => { Name => 'SerialNumber', Format => 'string[16]' }, + 0x57 => { Name => 'OtherSerialNumber', Format => 'string[15]' }, # (NC) + 0x66 => { + Name => 'Model', + Description => 'Camera Model Name', + Format => 'string[16]', + }, + # ... + # after this there are lots of interesting values also found in the GPMF box, + # but this block is lacking tag ID's and any directory structure, so the + # value offsets are therefore presumably firmware dependent :( +); + +#------------------------------------------------------------------------------ +# Convert system time to date/time string +# Inputs: 0) system time value, 1) ExifTool ref +# Returns: EXIF-format date/time string with milliseconds +sub ConvertSystemTime($$) +{ + my ($val, $et) = @_; + my $s = $$et{SystemTimeList} or return '<uncalibrated>'; + unless ($$et{SystemTimeListSorted}) { + $s = $$et{SystemTimeList} = [ sort { $$a[0] <=> $$b[0] } @$s ]; + $$et{SystemTimeListSorted} = 1; + } + my ($i, $j) = (0, $#$s); + # perform binary search to find this system time value + while ($j - $i > 1) { + my $t = int(($i + $j) / 2); + ($val < $$s[$t][0] ? $j : $i) = $t; + } + if ($i == $j or $$s[$j][0] == $$s[$i][0]) { + $val = $$s[$i][1]; + } else { + # interpolate between values + $val = $$s[$i][1] + ($$s[$j][1] - $$s[$i][1]) * ($val - $$s[$i][0]) / ($$s[$j][0] - $$s[$i][0]); + } + # (a bit tricky to remove fractional seconds then add them back again after + # the date/time conversion while avoiding round-off errors which could + # put the seconds out by 1...) + my ($t, $f) = ("$val" =~ /^(\d+)(\.\d+)/); + return Image::ExifTool::ConvertUnixTime($t, $$et{OPTIONS}{QuickTimeUTC}) . $f; +} + +#------------------------------------------------------------------------------ +# Scale values by last 'SCAL' constants +# Inputs: 0) value or list of values, 1) string of scale factors +# Returns: nothing, but updates values +sub ScaleValues($$) +{ + my ($val, $scl) = @_; + return unless $val and $scl; + my @scl = split ' ', $scl or return; + my @scaled; + my $v = (ref $val eq 'ARRAY') ? $val : [ $val ]; + foreach $val (@$v) { + my @a = split ' ', $val; + $a[$_] /= $scl[$_ % @scl] foreach 0..$#a; + push @scaled, join(' ', @a); + } + $_[0] = @scaled > 1 ? \@scaled : $scaled[0]; +} + +#------------------------------------------------------------------------------ +# Add units to values for human-readable output +# Inputs: 0) ExifTool ref, 1) value, 2) tag key +# Returns: converted value +sub AddUnits($$$) +{ + my ($et, $val, $tag) = @_; + if ($et and $$et{TAG_EXTRA}{$tag} and $$et{TAG_EXTRA}{$tag}{Units}) { + my $u = $$et{TAG_EXTRA}{$tag}{Units}; + $u = [ $u ] unless ref $u eq 'ARRAY'; + my @a = split ' ', $val; + if (@$u == @a) { + my $i; + for ($i=0; $i<@a; ++$i) { + $a[$i] .= ' ' . $$u[$i] if $$u[$i]; + } + $val = join ' ', @a; + } + } + return $val; +} + +#------------------------------------------------------------------------------ +# Process string of values (or array of strings) to extract as separate tags +# Inputs: 0) ExifTool object ref, 1) directory information ref, 2) tag table ref +# Returns: 1 on success +sub ProcessString($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + my $dataPt = $$dirInfo{DataPt}; + my @list = ref $$dataPt eq 'ARRAY' ? @{$$dataPt} : ( $$dataPt ); + my ($string, $val); + $et->VerboseDir('GoPro structure'); + foreach $string (@list) { + my @val = split ' ', $string; + my $i = 0; + foreach $val (@val) { + $et->HandleTag($tagTablePtr, $i, $val); + $$tagTablePtr{++$i} or $i = 0; + } + } + return 1; +} + +#------------------------------------------------------------------------------ +# Process GoPro metadata (gpmd samples, GPMF box, or APP6) (ref PH/1/2) +# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +# - with hack to check for encrypted text in gpmd data (Rove Stealth 4K) +sub ProcessGoPro($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $base = $$dirInfo{Base}; + my $pos = $$dirInfo{DirStart} || 0; + my $dirEnd = $pos + ($$dirInfo{DirLen} || (length($$dataPt) - $pos)); + my $verbose = $et->Options('Verbose'); + my $unknown = $verbose || $et->Options('Unknown'); + my ($size, $type, $unit, $scal, $setGroup0); + + $et->VerboseDir($$dirInfo{DirName} || 'GPMF', undef, $dirEnd-$pos) if $verbose; + if ($pos) { + my $parent = $$dirInfo{Parent}; + $setGroup0 = $$et{SET_GROUP0} = 'APP6' if $parent and $parent eq 'APP6'; + } else { + # set group0 to "QuickTime" unless group1 is being changed (to Track#) + $setGroup0 = $$et{SET_GROUP0} = 'QuickTime' unless $$et{SET_GROUP1}; + } + + for (; $pos+8<=$dirEnd; $pos+=($size+3)&0xfffffffc) { + my ($tag,$fmt,$len,$count) = unpack("x${pos}a4CCn", $$dataPt); + $size = $len * $count; + $pos += 8; + last if $pos + $size > $dirEnd; + my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); + last if $tag eq "\0\0\0\0"; # stop at null tag + next unless $size or $verbose; # don't save empty values unless verbose + my $format = $goProFmt{$fmt} || 'undef'; + my ($val, $i, $j, $p, @v); + if ($fmt == 0x3f and defined $type) { + # decode structure with format given by previous 'TYPE' + for ($i=0; $i<$count; ++$i) { + my (@s, $l); + for ($j=0, $p=0; $j<length($type); ++$j, $p+=$l) { + my $b = Get8u(\$type, $j); + my $f = $goProFmt{$b} or last; + $l = $goProSize{$b} || Image::ExifTool::FormatSize($f) or last; + last if $p + $l > $len; + my $s = ReadValue($dataPt, $pos+$i*$len+$p, $f, undef, $l); + last unless defined $s; + push @s, $s; + } + push @v, join ' ', @s if @s; + } + $val = @v > 1 ? \@v : $v[0]; + } elsif (($format eq 'undef' or $format eq 'string') and $count > 1 and $len > 1) { + # unpack multiple undef/string values as a list + my $a = $format eq 'undef' ? 'a' : 'A'; + $val = [ unpack("x${pos}".("$a$len" x $count), $$dataPt) ]; + } else { + $val = ReadValue($dataPt, $pos, $format, undef, $size); + } + # save TYPE, UNIT/SIUN and SCAL values for later + $type = $val if $tag eq 'TYPE'; + $unit = $val if $tag eq 'UNIT' or $tag eq 'SIUN'; + $scal = $val if $tag eq 'SCAL'; + + unless ($tagInfo) { + next unless $unknown; + my $name = Image::ExifTool::QuickTime::PrintableTagID($tag); + $tagInfo = { Name => "GoPro_$name", Description => "GoPro $name", Unknown => 1 }; + $$tagInfo{SubDirectory} = { TagTable => 'Image::ExifTool::GoPro::GPMF' } if not $fmt; + AddTagToTable($tagTablePtr, $tag, $tagInfo); + } + # apply scaling if available to last tag in this container + ScaleValues($val, $scal) if $scal and $tag ne 'SCAL' and $pos+$size+3>=$dirEnd; + my $key = $et->HandleTag($tagTablePtr, $tag, $val, + DataPt => $dataPt, + Base => $base, + Start => $pos, + Size => $size, + TagInfo => $tagInfo, + Format => $format, + Extra => $verbose ? ", type='".($fmt ? chr($fmt) : '\0')."' size=$len count=$count" : undef, + ); + # save units for adding in print conversion if specified + $$et{TAG_EXTRA}{$key}{Units} = $unit if $$tagInfo{AddUnits} and $key; + } + delete $$et{SET_GROUP0} if $setGroup0; + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::GoPro - Read information from GoPro videos + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to decode +metadata from GoPro MP4 videos. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<https://github.com/gopro/gpmf-parser> + +=item L<https://github.com/stilldavid/gopro-utils> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/GoPro Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/H264.pm b/src/Image-ExifTool/lib/Image/ExifTool/H264.pm index cbd2c5d7..89841b6d 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/H264.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/H264.pm @@ -64,7 +64,7 @@ my $parsePictureTiming; # flag to enable parsing of picture timing information ( Information (SEI). I<[Yes, this description is confusing, but nothing compared to the challenge of actually decoding the data!]> This information may exist at regular intervals through the entire video, but only the first - occurrence is extracted unless the ExtractEmbedded (-ee) option is used (in + occurrence is extracted unless the L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> (-ee) option is used (in which case subsequent occurrences are extracted as sub-documents). }, # (Note: all these are explained in IEC 61834-4, but it costs money so it is useless to me) @@ -89,7 +89,7 @@ my $parsePictureTiming; # flag to enable parsing of picture timing information ( Notes => 'hours:minutes:seconds:frames', ValueConv => 'sprintf("%.2x:%.2x:%.2x:%.2x",reverse unpack("C*",$val))', }, - # 0x14 - TitleBinaryGroup + # 0x14 - TitleBinaryGroup - val: 0x00000000,0x14200130 # 0x15 - TitleCassetteNo (ref 7) # 0x16-0x17 - TitleSoftID (ref 7) # (0x18,0x19 listed as TitleTextHeader/TitleText by ref 7) @@ -134,8 +134,8 @@ my $parsePictureTiming; # flag to enable parsing of picture timing information ( Name => 'Camera2', SubDirectory => { TagTable => 'Image::ExifTool::H264::Camera2' }, }, - # 0x73 Lens - val: 0x75ffffd3,0x0effffd3,0x59ffffd3,0x79ffffd3,0xffffffd3... - # 0x74 Gain + # 0x73 Lens - val: 0x04ffffd3,0x0effffd3,0x15ffffd3,0x41ffffd3,0x52ffffd3,0x59ffffd3,0x65ffffd3,0x71ffffd3,0x75ffffd3,0x79ffffd3,0x7fffffd3,0xffffffd3... + # 0x74 Gain - val: 0xb8ffff0f # 0x75 Pedestal # 0x76 Gamma # 0x77 Detail @@ -376,34 +376,49 @@ my $parsePictureTiming; # flag to enable parsing of picture timing information ( Notes => 'combined with tag 0xc8', }, # 0xc9-0xcf - GPSOption + # 0xc9 - val: 0x001d0203 + 0xca => { #PH (Sony DSC-HX7V) + Name => 'GPSDateStamp', + Format => 'string', + Groups => { 1 => 'GPS', 2 => 'Time' }, + Combine => 2, # the next 2 tags contain the rest of the string + Notes => 'combined with tags 0xcb and 0xcc', + ValueConv => 'Image::ExifTool::Exif::ExifDate($val)', + }, 0xe0 => { Name => 'MakeModel', SubDirectory => { TagTable => 'Image::ExifTool::H264::MakeModel' }, }, # 0xe1-0xef - MakerOption # 0xe1 - val: 0x01000670,0x01000678,0x06ffffff,0x01ffffff,0x01000020,0x01000400... - # 0xe2-0xe8 - val: 0x00000000 in many samples 0xe1 => { #6 Name => 'RecInfo', Condition => '$$self{Make} eq "Canon"', Notes => 'Canon only', SubDirectory => { TagTable => 'Image::ExifTool::H264::RecInfo' }, }, + # 0xe2-0xe8 - val: 0x00000000 in many samples + # 0xe2 - val: 0x00000000,0x01000000,0x01010000,0x8080900c,0x8080a074 + # 0xe3 - val: 0x00801f89,0x00801f8b,0x00c01f89,0xc9c01f80 0xe4 => { #PH Name => 'Model', Condition => '$$self{Make} eq "Sony"', # (possibly also Canon models?) Description => 'Camera Model Name', - Notes => 'Sony cameras only, combined with tags 0xe5 and 0xe6', + Notes => 'Sony only, combined with tags 0xe5 and 0xe6', Format => 'string', Combine => 2, # (not sure about 0xe6, but include it just in case) RawConv => '$val eq "" ? undef : $val', }, + # 0xeb - val: 0x008a0a00,0x0a300000,0x508a0a00,0x52880a00,0x528a0a00 + # 0xec - val: 0x0b700000 + # 0xed - val: 0x0ce0f819 0xee => { #6 (HFS200) Name => 'FrameInfo', Condition => '$$self{Make} eq "Canon"', Notes => 'Canon only', SubDirectory => { TagTable => 'Image::ExifTool::H264::FrameInfo' }, }, + # 0xef - val: 0x01c00000,0x0e00000c ); # ConsumerCamera1 information (ref PH) @@ -458,7 +473,7 @@ my $parsePictureTiming; # flag to enable parsing of picture timing information ( ValueConv => '$val == 0xff ? undef : $val', PrintConv => q{ my $foc = ($val & 0x7e) / (($val & 0x01) ? 40 : 400); - return ($val & 0x80 ? 'Manual' : 'Auto') . " ($foc)"; + return(($val & 0x80 ? 'Manual' : 'Auto') . " ($foc)"); }, }, ); @@ -890,7 +905,7 @@ sub ParsePictureTiming($$) #------------------------------------------------------------------------------ # Process H.264 Supplementary Enhancement Information (ref 1/PH) -# Inputs: 0) Exiftool ref, 1) dirInfo ref, 2) tag table ref +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref # Returns: 1 if we processed payload type 5 # Payload types: # 0 - buffer period @@ -1108,7 +1123,7 @@ information from H.264 video streams. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/HP.pm b/src/Image-ExifTool/lib/Image/ExifTool/HP.pm index ade99eee..c603df00 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/HP.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/HP.pm @@ -119,7 +119,7 @@ sub ProcessTDHD($$$); NOTES => q{ These tags are extracted from the APP6 "TDHD" segment of Photosmart R837 JPEG images. Many other unknown tags exist in is data, and can be seen with - the Unknown (-u) option. + the L<Unknown|../ExifTool.html#Unknown> (-u) option. }, # (all subdirectories except TDHD and LSLV are automatically recognized # by their "type" word of 0x10001) @@ -250,7 +250,7 @@ Hewlett-Packard maker notes. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/HTML.pm b/src/Image-ExifTool/lib/Image/ExifTool/HTML.pm index 695948f4..4af55d47 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/HTML.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/HTML.pm @@ -20,7 +20,7 @@ use Image::ExifTool::PostScript; use Image::ExifTool::XMP qw(EscapeXML UnescapeXML); require Exporter; -$VERSION = '1.15'; +$VERSION = '1.16'; @ISA = qw(Exporter); @EXPORT_OK = qw(EscapeHTML UnescapeHTML); @@ -363,11 +363,11 @@ sub EscapeChar($) #------------------------------------------------------------------------------ # Escape any special characters for HTML -# Inputs: 0) UTF-8 string to be escaped +# Inputs: 0) string to be escaped, 1) optional string encoding (default 'UTF8') # Returns: escaped string -sub EscapeHTML($) +sub EscapeHTML($;$) { - my $str = shift; + my ($str, $enc) = @_; # escape XML characters $str = EscapeXML($str); # escape other special characters if they exist @@ -382,19 +382,26 @@ sub EscapeHTML($) } # suppress warnings local $SIG{'__WARN__'} = sub { 1 }; - # escape any non-ascii characters for HTML - $str =~ s/([\xc2-\xf7][\x80-\xbf]+)/EscapeChar($1)/sge; + if ($enc and $enc ne 'UTF8') { + $str = Image::ExifTool::Decode(undef, $str, $enc, undef, 'UTF8'); + $str =~ s/([\xc2-\xf7][\x80-\xbf]+)/EscapeChar($1)/sge; + $str = Image::ExifTool::Decode(undef, $str, 'UTF8', undef, $enc); + } else { + # escape any non-ascii characters for HTML + $str =~ s/([\xc2-\xf7][\x80-\xbf]+)/EscapeChar($1)/sge; + } } return $str; } #------------------------------------------------------------------------------ # Unescape all HTML character references -# Inputs: 0) string to be unescaped +# Inputs: 0) string to be unescaped, 1) optional string encoding (default 'UTF8') # Returns: unescaped string -sub UnescapeHTML($) +sub UnescapeHTML($;$) { - return UnescapeXML(shift, \%entityNum); + my ($str, $enc) = @_; + return UnescapeXML($str, \%entityNum, $enc); } #------------------------------------------------------------------------------ @@ -548,7 +555,7 @@ meta information from HTML documents. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/HtmlDump.pm b/src/Image-ExifTool/lib/Image/ExifTool/HtmlDump.pm index 349f8f64..aee312b5 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/HtmlDump.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/HtmlDump.pm @@ -13,9 +13,9 @@ use vars qw($VERSION); use Image::ExifTool; # only for FinishTiffDump() use Image::ExifTool::HTML qw(EscapeHTML); -$VERSION = '1.34'; +$VERSION = '1.39'; -sub DumpTable($$$;$$$$$); +sub DumpTable($$$;$$$$$$); sub Open($$$;@); sub Write($@); @@ -32,6 +32,7 @@ _END_PART_1_ # Note: Don't change font-weight style because it can affect line height my $htmlHeader2 = <<_END_PART_2_; </title> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <style type="text/css"> <!-- /* character style ID's */ @@ -96,7 +97,8 @@ var YTOP = 20; // y offset when above cursor var safari1 = navigator.userAgent.indexOf("Safari/312.6") >= 0; var ie6 = navigator.userAgent.toLowerCase().indexOf('msie 6') >= 0; var mspan = new Array; -var hlist, tt, tb; +var clicked = 0; +var hlist, tt, tb, firstOutEvt, lastInEvt; function GetElementsByClass(classname, tagname) { var found = new Array(); @@ -111,10 +113,23 @@ function GetElementsByClass(classname, tagname) { } } } - delete list; return found; } +// click mouse +function doClick(e) +{ + if (!clicked) { + firstOutEvt = lastInEvt = undefined; + high(e, 2); + if (hlist) clicked = 1; + } else { + clicked = 0; + if (firstOutEvt) high(firstOutEvt, 0); + if (lastInEvt) high(lastInEvt, 1); + } +} + // move tooltip function move(e) { @@ -162,6 +177,12 @@ function move(e) // highlight/unhighlight text function high(e,on) { + if (on) { + lastInEvt = e; + } else { + if (!firstOutEvt) firstOutEvt = e; + } + if (clicked) return; var targ; if (e.target) targ = e.target; else if (e.srcElement) targ = e.srcElement; @@ -171,7 +192,9 @@ function high(e,on) { // un-highlight current objects if (hlist) { for (var i=0; i<hlist.length; ++i) { - hlist[i].style.background = 'transparent'; + for (var j=0; j<hlist[i].length; ++j) { + hlist[i][j].style.background = 'transparent'; + } } hlist = null; } @@ -190,20 +213,25 @@ function high(e,on) { } } // highlight anchor elements with the same name - hlist = document.getElementsByName(targ.name); + hlist = new Array; + hlist.push(document.getElementsByName(targ.name)); + // is this an IFD pointer? + var pos = targ.className.indexOf('Offset_'); + if (pos > 0) { + // add elements from this IFD to our highlight list + hlist.push(document.getElementsByClassName(targ.className.substr(pos+7))); + } // use class name to highlight span elements if necessary for (var i=0; i<mspan.length; ++i) { if (mspan[i] != targ.name) continue; - var slist = GetElementsByClass(targ.name, 'span'); - // add elements from hlist collection to our array - for (var j=0; j<hlist.length; ++j) { - slist[slist.length] = hlist[j]; - } - hlist = slist; + // add these span elements to our highlight list + hlist.push(GetElementsByClass(targ.name, 'span')); break; } - for (var j=0; j<hlist.length; ++j) { - hlist[j].style.background = '#ffcc99'; + for (var i=0; i<hlist.length; ++i) { + for (var j=0; j<hlist[i].length; ++j) { + hlist[i][j].style.background = on == 2 ? '#ffbbbb' : '#ffcc99'; + } } } } @@ -219,7 +247,7 @@ Enable JavaScript for active highlighting and information tool tips! <table class=dump cellspacing=0 cellpadding=2> <tr><td valign='top'><pre>]; -my $preMouse = q(<pre onmouseover="high(event,1)" onmouseout="high(event,0)" onmousemove="move(event)">); +my $preMouse = q(<pre onmouseover="high(event,1)" onmouseout="high(event,0)" onmousemove="move(event)" onmousedown="doClick(event)">); #------------------------------------------------------------------------------ # New - create new HtmlDump object @@ -236,7 +264,7 @@ sub new # Add information to dump # Inputs: 0) HTML dump hash ref, 1) absolute offset in file, 2) data size, # 3) comment string, 4) tool tip (or SAME to use previous tip), -# 5) bit flags (see below) +# 5) bit flags (see below), 6) IFD name # Bits: 0x01 - print at start of line # 0x02 - print red address # 0x04 - maker notes data ('M'-class span) @@ -244,9 +272,9 @@ sub new # 0x10 - allow double references # 0x100 - (reserved) # Notes: Block will be shown in 'unused' color if comment string begins with '[' -sub Add($$$$;$) +sub Add($$$$;$$) { - my ($self, $start, $size, $msg, $tip, $flag) = @_; + my ($self, $start, $size, $msg, $tip, $flag, $ifd) = @_; my $block = $$self{Block}; $$block{$start} or $$block{$start} = [ ]; my $htip; @@ -263,7 +291,7 @@ sub Add($$$$;$) $htip .= "<br>($size bytes)" unless $htip =~ /<br>Size:/; ++$self->{TipNum}; } - push @{$$block{$start}}, [ $size, $msg, $htip, $flag, $self->{TipNum} ]; + push @{$$block{$start}}, [ $size, $msg, $htip, $flag, $self->{TipNum}, $ifd ]; } #------------------------------------------------------------------------------ @@ -351,7 +379,7 @@ sub Print($$;$$$$$) } my $parms; foreach $parms (@$parmList) { - my ($len, $msg, $tip, $flag, $tipNum) = @$parms; + my ($len, $msg, $tip, $flag, $tipNum, $ifd) = @$parms; next unless $len > 0; $flag = 0 unless defined $flag; # generate same name for all blocks indexed by this tooltip @@ -367,8 +395,10 @@ sub Print($$;$$$$$) ++$index; } if ($flag & 0x14) { + my $class = $flag & 0x04 ? "$name M" : $name; + $class .= " $ifd" if $ifd; my %bkg = ( - Class => $flag & 0x04 ? "$name M" : $name, + Class => $class, Start => $start - $dataPos, End => $start - $dataPos + $len, ); @@ -428,7 +458,7 @@ sub Print($$;$$$$$) $flag |= 0x100 unless $flag & 0x01 or $nextFlag & 0x01; } $self->DumpTable($start-$dataPos, \$buff, $msg, $name, - $flag, $len, $pos-$dataPos); + $flag, $len, $pos-$dataPos, $ifd); undef $buff; $pos = $end if $pos < $end; } @@ -558,10 +588,10 @@ sub Open($$$;@) # Dump a block of data in HTML table form # Inputs: 0) HtmlDump object ref, 1) data position, 2) block pointer, # 3) message, 4) object name, 5) flag, 6) full block length (actual -# data may be shorter), 7) data end position -sub DumpTable($$$;$$$$$) +# data may be shorter), 7) data end position, 8) IFD name +sub DumpTable($$$;$$$$$$) { - my ($self, $pos, $blockPt, $msg, $name, $flag, $len, $endPos) = @_; + my ($self, $pos, $blockPt, $msg, $name, $flag, $len, $endPos, $ifd) = @_; $len = length $$blockPt unless defined $len; $endPos = 0 unless $endPos; my ($f0, $dblRef, $id); @@ -588,7 +618,8 @@ sub DumpTable($$$;$$$$$) } ++$id unless $dblRef; } - $name = "<a name=$name class=$id>"; + my $class = $ifd ? "'$id $ifd'" : $id; + $name = "<a name=$name class=$class>"; $msg and $msg = "$name$msg</a>"; } else { $name = ''; @@ -653,7 +684,8 @@ sub DumpTable($$$;$$$$$) if ($dblRef and $p >= $endPos) { $dblRef = 0; ++$id; - $name =~ s/class=\w\b/class=$id/; + my $class = $ifd ? "'$id $ifd'" : $id; + $name =~ s/class=\w\b/class=$class/; $f0 = ''; $self->Open('fgd', $f0, 0); } @@ -885,7 +917,7 @@ page. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/ICC_Profile.pm b/src/Image-ExifTool/lib/Image/ExifTool/ICC_Profile.pm index d3017c8c..4c806e5c 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/ICC_Profile.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/ICC_Profile.pm @@ -11,6 +11,7 @@ # 4) http://www.color.org/privatetag2007-01.pdf # 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 # # Notes: The ICC profile information is different: the format of each # tag is embedded in the information instead of in the directory @@ -24,7 +25,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.35'; +$VERSION = '1.40'; sub ProcessICC($$); sub ProcessICC_Profile($$$); @@ -52,6 +53,11 @@ my %profileClass = ( abst => 'Abstract Profile', nmcl => 'NamedColor Profile', nkpf => 'Nikon Input Device Profile (NON-STANDARD!)', # (written by Nikon utilities) + # additions in v5 (ref 7) + cenc => 'ColorEncodingSpace Profile', + 'mid '=> 'MultiplexIdentification Profile', + mlnk => 'MultiplexLink Profile', + mvis => 'MultiplexVisualization Profile', ); my %manuSig = ( #6 'NONE' => 'none', @@ -61,7 +67,7 @@ my %manuSig = ( #6 'AAMA' => 'Aamazing Technologies, Inc.', 'ACER' => 'Acer Peripherals', 'ACLT' => 'Acolyte Color Research', - 'ACTI' => 'Actix Sytems, Inc.', + 'ACTI' => 'Actix Systems, Inc.', 'ADAR' => 'Adara Technology, Inc.', 'ADBE' => 'Adobe Systems Inc.', 'ADI ' => 'ADI Systems, Inc.', @@ -516,11 +522,11 @@ my %manuSig = ( #6 prmg => 'Perceptual Reference Medium Gamut', }, }, - meta => { #5 (EVENTUALLY DECODE THIS ONCE WE HAVE A SAMPLE!!) + meta => { #5 Name => 'Metadata', SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Metadata', - Validate => '$type eq "meta"', + Validate => '$type eq "dict"', }, }, @@ -539,6 +545,90 @@ my %manuSig = ( #6 Binary => 1, # (NC) }, + # new tags in v5 (ref 7) + A2B3 => 'AToB3', + A2M0 => 'AToM0', + B2A3 => 'BToA3', + bcp0 => 'BRDFColorimetricParam0', + bcp1 => 'BRDFColorimetricParam1', + bcp2 => 'BRDFColorimetricParam2', + bcp3 => 'BRDFColorimetricParam3', + bsp0 => 'BRDFSpectralParam0', + bsp1 => 'BRDFSpectralParam1', + bsp2 => 'BRDFSpectralParam2', + bsp3 => 'BRDFSpectralParam3', + bAB0 => 'BRDFAToB0', + bAB1 => 'BRDFAToB1', + bAB2 => 'BRDFAToB2', + bAB3 => 'BRDFAToB3', + bBA0 => 'BRDFBToA0', + bBA1 => 'BRDFBToA1', + bBA2 => 'BRDFBToA2', + bBA3 => 'BRDFBToA3', + bBD0 => 'BRDFBToD0', + bBD1 => 'BRDFBToD1', + bBD2 => 'BRDFBToD2', + bBD3 => 'BRDFBToD3', + bDB0 => 'BRDFDToB0', + bDB1 => 'BRDFDToB1', + bDB2 => 'BRDFDToB2', + bDB3 => 'BRDFDToB3', + bMB0 => 'BRDFMToB0', + bMB1 => 'BRDFMToB1', + bMB2 => 'BRDFMToB2', + bMB3 => 'BRDFMToB3', + bMS0 => 'BRDFMToS0', + bMS1 => 'BRDFMToS1', + bMS2 => 'BRDFMToS2', + bMS3 => 'BRDFMToS3', + dAB0 => 'DirectionalAToB0', + dAB1 => 'DirectionalAToB1', + dAB2 => 'DirectionalAToB2', + dAB3 => 'DirectionalAToB3', + dBA0 => 'DirectionalBToA0', + dBA1 => 'DirectionalBToA1', + dBA2 => 'DirectionalBToA2', + dBA3 => 'DirectionalBToA3', + dBD0 => 'DirectionalBToD0', + dBD1 => 'DirectionalBToD1', + dBD2 => 'DirectionalBToD2', + dBD3 => 'DirectionalBToD3', + dDB0 => 'DirectionalDToB0', + dDB1 => 'DirectionalDToB1', + dDB2 => 'DirectionalDToB2', + dDB3 => 'DirectionalDToB3', + gdb0 => 'GamutBoundaryDescription0', + gdb1 => 'GamutBoundaryDescription1', + gdb2 => 'GamutBoundaryDescription2', + gdb3 => 'GamutBoundaryDescription3', + 'mdv '=> 'MultiplexDefaultValues', + mcta => 'MultiplexTypeArray', + minf => 'MeasurementInfo', + miin => 'MeasurementInputInfo', + M2A0 => 'MToA0', + M2B0 => 'MToB0', + M2B1 => 'MToB1', + M2B2 => 'MToB2', + M2B3 => 'MToB3', + M2S0 => 'MToS0', + M2S1 => 'MToS1', + M2S2 => 'MToS2', + M2S3 => 'MToS3', + cept => 'ColorEncodingParams', + csnm => 'ColorSpaceName', + cloo => 'ColorantOrderOut', + clio => 'ColorantInfoOut', + c2sp => 'CustomToStandardPcc', + 'CxF '=> 'CXF', + nmcl => 'NamedColor', + psin => 'ProfileSequenceInfo', + rfnm => 'ReferenceName', + svcn => 'SpectralViewingConditions', + swpt => 'SpectralWhitePoint', + s2cp => 'StandardToCustomPcc', + smap => 'SurfaceMap', + # smwp ? (seen in some v5 samples) + # 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 # a link so ExifTool can locate the header tags @@ -725,6 +815,7 @@ my %manuSig = ( #6 Name => 'ChromaticityColorant', Format => 'int16u', PrintConv => { + 0 => 'Unknown', 1 => 'ITU-R BT.709', 2 => 'SMPTE RP145-1994', 3 => 'EBU Tech.3213-E', @@ -801,6 +892,7 @@ my %manuSig = ( #6 ManufacturerName => { }, MediaColor => { }, MediaWeight => { }, + CreatorApp => { }, ); #------------------------------------------------------------------------------ @@ -850,7 +942,7 @@ sub FormatICCTag($$$) # dataType if ($type eq 'data' and $size >= 12) { my $form = Get32u($dataPt, $offset+8); - # format 0 is ASCII data + # format 0 is UTF-8 data $form == 0 and return substr($$dataPt, $offset+12, $size-12); # binary data and other data types treat as binary (ie. don't format) } @@ -910,7 +1002,7 @@ sub FormatICCTag($$$) } #------------------------------------------------------------------------------ -# Process ICC metadata record (ref 5) (UNTESTED!) +# Process ICC metadata record (ref 5) # Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref # Returns: 1 on success sub ProcessMetadata($$$) @@ -942,7 +1034,7 @@ sub ProcessMetadata($$$) my $namePtr = Get32u($dataPt, $entry); my $nameLen = Get32u($dataPt, $entry + 4); my $valuePtr = Get32u($dataPt, $entry + 8); - my $valueLen = Get32u($dataPt, $entry + 16); + my $valueLen = Get32u($dataPt, $entry + 12); next unless $namePtr and $valuePtr; # ignore if offsets are zero if ($namePtr < $minPtr or $namePtr + $nameLen > $dirLen or $valuePtr < $minPtr or $valuePtr + $valueLen > $dirLen) @@ -950,8 +1042,8 @@ sub ProcessMetadata($$$) $et->Warn('Corrupted ICC meta dictionary'); last; } - my $tag = substr($dataPt, $dirStart + $namePtr, $nameLen); - my $val = substr($dataPt, $dirStart + $valuePtr, $valueLen); + my $tag = substr($$dataPt, $dirStart + $namePtr, $nameLen); + my $val = substr($$dataPt, $dirStart + $valuePtr, $valueLen); $tag = $et->Decode($tag, 'UTF16', 'MM', 'UTF8'); $val = $et->Decode($val, 'UTF16', 'MM'); # generate tagInfo if it doesn't exist @@ -960,6 +1052,7 @@ sub ProcessMetadata($$$) $name =~ s/\s+(.)/\u$1/g; $name =~ tr/-_a-zA-Z0-9//dc; next unless length $name; + $et->VPrint(0, $$et{INDENT}, "[adding $tag]\n"); AddTagToTable($tagTablePtr, $tag, { Name => $name }); } $et->HandleTag($tagTablePtr, $tag, $val); @@ -1022,7 +1115,7 @@ sub ValidateICC($) $profileClass{substr($$valPtr, 12, 4)} or $err = 'profile class'; my $col = substr($$valPtr, 16, 4); # ColorSpaceData my $con = substr($$valPtr, 20, 4); # ConnectionSpace - my $match = '(XYZ |Lab |Luv |YCbr|Yxy |RGB |GRAY|HSV |HLS |CMYK|CMY |[2-9A-F]CLR)'; + my $match = '(XYZ |Lab |Luv |YCbr|Yxy |RGB |GRAY|HSV |HLS |CMYK|CMY |[2-9A-F]CLR|nc..|\0{4})'; $col =~ /$match/ or $err = 'color space'; $con =~ /$match/ or $err = 'connection space'; return $err ? "Invalid ICC profile (bad $err)" : undef; @@ -1134,7 +1227,7 @@ sub ProcessICC_Profile($$$) my $tagInfo = $et->GetTagInfo($tagTablePtr, $tagID); # unknown tags aren't generated automatically by GetTagInfo() # if the tagID's aren't numeric, so we must do this manually: - if (not $tagInfo and $$et{OPTIONS}{Unknown}) { + if (not $tagInfo and ($$et{OPTIONS}{Unknown} or $verbose)) { $tagInfo = { Unknown => 1 }; AddTagToTable($tagTablePtr, $tagID, $tagInfo); } @@ -1222,10 +1315,10 @@ sub ProcessICC_Profile($$$) DirName => $name, Parent => $$dirInfo{DirName}, ); - my $type = substr($$dataPt, $valuePtr, 4); + my $type = $fmt; #### eval Validate ($type) if (defined $$subdir{Validate} and not eval $$subdir{Validate}) { - $et->Warn("Invalid $name data"); + $et->Warn("Invalid ICC $name data"); } else { $et->ProcessDirectory(\%subdirInfo, $newTagTable, $$subdir{ProcessProc}); } @@ -1264,7 +1357,7 @@ data created on one device into another device's native color space. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. @@ -1277,6 +1370,8 @@ under the same terms as Perl itself. =item L<http://developer.apple.com/documentation/GraphicsImaging/Reference/ColorSync_Manager/ColorSync_Manager.pdf> +=item L<https://color.org/specification/ICC.2-2019.pdf> + =back =head1 SEE ALSO diff --git a/src/Image-ExifTool/lib/Image/ExifTool/ID3.pm b/src/Image-ExifTool/lib/Image/ExifTool/ID3.pm index 8c369044..5343cfd3 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/ID3.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/ID3.pm @@ -1,13 +1,15 @@ #------------------------------------------------------------------------------ # File: ID3.pm # -# Description: Read ID3 meta information +# Description: Read ID3 and Lyrics3 meta information # # Revisions: 09/12/2005 - P. Harvey Created +# 09/08/2020 - PH Added Lyrics3 support # -# References: 1) http://www.id3.org/ +# References: 1) http://www.id3.org/ (now https://id3.org) # 2) http://www.mp3-tech.org/ # 3) http://www.fortunecity.com/underworld/sonic/3/id3tag.html +# 4) https://id3.org/Lyrics3 #------------------------------------------------------------------------------ package Image::ExifTool::ID3; @@ -16,11 +18,12 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.51'; +$VERSION = '1.57'; sub ProcessID3v2($$$); sub ProcessPrivate($$$); sub ProcessSynText($$$); +sub ProcessID3Dir($$$); sub ConvertID3v1Text($$); sub ConvertTimeStamp($); @@ -67,14 +70,15 @@ my %dateTimeConv = ( # This table is just for documentation purposes %Image::ExifTool::ID3::Main = ( VARS => { NO_ID => 1 }, + PROCESS_PROC => \&ProcessID3Dir, # (used to process 'id3 ' chunk in WAV files) NOTES => q{ - ExifTool extracts ID3 information from MP3, MPEG, AIFF, OGG, FLAC, APE, MPC - and RealAudio files. ID3v2 tags which support multiple languages (eg. - Comment and Lyrics) are extracted by specifying the tag name, followed by a - dash ('-'), then a 3-character ISO 639-2 language code (eg. "Comment-spa"). - See L<http://www.id3.org/> for the official ID3 specification and - L<http://www.loc.gov/standards/iso639-2/php/code_list.php> for a list of ISO - 639-2 language codes. + ExifTool extracts ID3 and Lyrics3 information from MP3, MPEG, WAV, AIFF, + OGG, FLAC, APE, MPC and RealAudio files. ID3v2 tags which support multiple + languages (eg. Comment and Lyrics) are extracted by specifying the tag name, + followed by a dash ('-'), then a 3-character ISO 639-2 language code (eg. + "Comment-spa"). See L<https://id3.org/> for the official ID3 specification + and L<http://www.loc.gov/standards/iso639-2/php/code_list.php> for a list of + ISO 639-2 language codes. }, ID3v1 => { Name => 'ID3v1', @@ -98,6 +102,24 @@ my %dateTimeConv = ( }, ); +# Lyrics3 tags (ref 4) +%Image::ExifTool::ID3::Lyrics3 = ( + GROUPS => { 1 => 'Lyrics3', 2 => 'Audio' }, + NOTES => q{ + ExifTool extracts Lyrics3 version 1.00 and 2.00 tags from any file that + supports ID3. See L<https://id3.org/Lyrics3> for the specification. + }, + IND => 'Indications', + LYR => 'Lyrics', + INF => 'AdditionalInfo', + AUT => { Name => 'Author', Groups => { 2 => 'Author' } }, + EAL => 'ExtendedAlbumName', + EAR => 'ExtendedArtistName', + ETT => 'ExtendedTrackTitle', + IMG => 'AssociatedImageFile', + CRC => 'CRC', #PH +); + # Mapping for ID3v1 Genre numbers my %genre = ( 0 => 'Blues', @@ -613,6 +635,9 @@ my %id3v2_common = ( Name => 'OlympusDSS', SubDirectory => { TagTable => 'Image::ExifTool::Olympus::DSS' }, }, + GRP1 => 'Grouping', + MVNM => 'MovementName', # (NC) + MVIN => 'MovementNumber', # (NC) ); # Tags for ID3v2.3 (http://www.id3.org/id3v2.3.0) @@ -964,11 +989,20 @@ sub PrintGenre($) $genre{$1} or $genre{$1} = "Unknown ($1)"; } $val =~ s/\((\d+)\)/\($genre{$1}\)/g; - $val =~ s/(^|\/)(\d+)(?=\/|$)/$1$genre{$2}$3/g; + $val =~ s/(^|\/)(\d+)(?=\/|$)/$1$genre{$2}/g; $val =~ s/^\(([^)]+)\)\1?$/$1/; # clean up by removing brackets and duplicates return $val; } +#------------------------------------------------------------------------------ +# Get Genre ID +# Inputs: 0) Genre name +# Returns: genre ID number, or undef +sub GetGenreID($) +{ + return Image::ExifTool::ReverseLookup(shift, \%genre); +} + #------------------------------------------------------------------------------ # Decode ID3 string # Inputs: 0) ExifTool object reference @@ -1309,6 +1343,8 @@ sub ProcessID3v2($$$) } elsif ($$tagInfo{Format} or $$tagInfo{SubDirectory}) { $et->HandleTag($tagTablePtr, $id, undef, DataPt => \$val); next; + } elsif ($id eq 'GRP1' or $id eq 'MVNM' or $id eq 'MVIN') { + $val =~ s/(^\0+|\0+$)//g; # (PH guess) } elsif (not $$tagInfo{Binary}) { $et->Warn("Don't know how to handle $id frame"); next; @@ -1333,7 +1369,7 @@ sub ProcessID3v2($$$) # Inputs: 0) ExifTool object reference, 1) dirInfo reference # Returns: 1 on success, 0 if this file didn't contain ID3 information # - also processes audio data if any ID3 information was found -# - sets ExifTool DoneID3 to 1 when called, or to 2 if an ID3v1 trailer exists +# - sets ExifTool DoneID3 to 1 when called, or to trailer size if an ID3v1 trailer exists sub ProcessID3($$) { my ($et, $dirInfo) = @_; @@ -1412,8 +1448,9 @@ sub ProcessID3($$) # # read ID3v1 trailer if it exists # + my $trailSize = 0; if ($raf->Seek(-128, 2) and $raf->Read($tBuff, 128) == 128 and $tBuff =~ /^TAG/) { - $$et{DoneID3} = 2; # set to 2 as flag that trailer exists + $trailSize = 128; %id3Trailer = ( DataPt => \$tBuff, DataPos => $raf->Tell() - 128, @@ -1423,12 +1460,63 @@ sub ProcessID3($$) $id3Len += length($tBuff); $rtnVal = 1; # load 'Enhanced TAG' information if available - if ($raf->Seek(-355, 2) and $raf->Read($eBuff, 227) == 227 and $eBuff =~ /^TAG+/) { + my $eSize = 227; # size of ID3 Enhanced TAG info + if ($raf->Seek(-$trailSize - $eSize, 2) and $raf->Read($eBuff, $eSize) == $eSize and $eBuff =~ /^TAG+/) { $id3Trailer{EnhancedTAG} = \$eBuff; + $trailSize += $eSize; + } + $$et{DoneID3} = $trailSize; # save trailer size + } +# +# read Lyrics3 trailer if it exists +# + if ($raf->Seek(-$trailSize-15, 2) and $raf->Read($buff, 15) == 15 and $buff =~ /^(.{6})LYRICS(END|200)$/) { + my $ver = $2; # Lyrics3 version ('END' for version 1) + my $len = ($ver eq 'END') ? 5100 : $1 + 15; # max Lyrics3 length + my $tbl = GetTagTable('Image::ExifTool::ID3::Lyrics3'); + $len = $raf->Tell() if $len > $raf->Tell(); + if ($raf->Seek(-$len, 1) and $raf->Read($buff, $len) == $len and $buff =~ /LYRICSBEGIN/g) { + my $pos = pos($buff); + $$et{DoneID3} = $trailSize + $len - $pos + 11; # update trailer length + my $oldIndent = $$et{INDENT}; + $$et{INDENT} .= '| '; + if ($et->Options('Verbose')) { + $et->VPrint(0, "Lyrics3:\n"); + $et->VerboseDir('Lyrics3', undef, $len); + if ($pos > 11) { + $buff = substr($buff, $pos - 11); + $pos = 11; + } + $et->VerboseDump(\$buff); + } + if ($ver eq 'END') { + # Lyrics3 v1.00 + my $val = substr($buff, $pos, $len - $pos - 9); + $et->HandleTag($tbl, 'LYR', $et->Decode($val, 'Latin')); + } else { + # Lyrics3 v2.00 + for (;;) { + # (note: the size field is 5 digits,, not 6 as per the documentation) + last unless $buff =~ /\G(.{3})(\d{5})/g; + my ($tag, $size) = ($1, $2); + $pos += 8; + last if $pos + $size > length($buff); + unless ($$tbl{$tag}) { + AddTagToTable($tbl, $tag, { Name => Image::ExifTool::MakeTagName("Lyrics3_$tag") }); + } + $et->HandleTag($tbl, $tag, $et->Decode(substr($buff, $pos, $size), 'Latin')); + $pos += $size; + pos($buff) = $pos; + } + $pos == length($buff) - 15 or $et->Warn('Malformed Lyrics3 v2.00 block'); + } + $$et{INDENT} = $oldIndent; + } else { + $et->Warn('Error reading Lyrics3 trailer'); } } # -# process the the information +# process the information # if ($rtnVal) { # first process audio data if it exists @@ -1484,6 +1572,16 @@ sub ProcessID3($$) return $rtnVal; } +#------------------------------------------------------------------------------ +# Process ID3 directory +# Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) dummy tag table ref +sub ProcessID3Dir($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + $et->VerboseDir('ID3', undef, length ${$$dirInfo{DataPt}}); + return ProcessID3($et, $dirInfo); +} + #------------------------------------------------------------------------------ # Extract ID3 information from an MP3 audio file # Inputs: 0) ExifTool object reference, 1) dirInfo reference @@ -1554,7 +1652,7 @@ other types of audio files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. @@ -1563,12 +1661,14 @@ under the same terms as Perl itself. =over 4 -=item L<http://www.id3.org/> +=item L<https://id3.org/> =item L<http://www.mp3-tech.org/> =item L<http://www.fortunecity.com/underworld/sonic/3/id3tag.html> +=item L<https://id3.org/Lyrics3> + =back =head1 SEE ALSO diff --git a/src/Image-ExifTool/lib/Image/ExifTool/IPTC.pm b/src/Image-ExifTool/lib/Image/ExifTool/IPTC.pm index 76bbaa60..3cf723f9 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/IPTC.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/IPTC.pm @@ -15,7 +15,7 @@ use strict; use vars qw($VERSION $AUTOLOAD %iptcCharset); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.56'; +$VERSION = '1.57'; %iptcCharset = ( "\x1b%G" => 'UTF8', @@ -497,6 +497,7 @@ my %fileFormat = ( 103 => { Name => 'OriginalTransmissionReference', Format => 'string[0,32]', + Notes => 'now used as a job identifier', }, 105 => { Name => 'Headline', @@ -1050,6 +1051,7 @@ sub ProcessIPTC($$$) my $dirLen = $$dirInfo{DirLen} || 0; my $dirEnd = $pos + $dirLen; my $verbose = $et->Options('Verbose'); + my $validate = $et->Options('Validate'); my $success = 0; my ($lastRec, $recordPtr, $recordName); @@ -1153,6 +1155,9 @@ sub ProcessIPTC($$$) last; } if (not defined $lastRec or $lastRec != $rec) { + if ($validate and defined $lastRec and $rec < $lastRec) { + $et->Warn("IPTC doesn't conform to spec: Records out of sequence",1) + } my $tableInfo = $tagTablePtr->{$rec}; unless ($tableInfo) { $et->WarnOnce("Unrecognized IPTC record $rec (ignored)"); @@ -1183,9 +1188,26 @@ sub ProcessIPTC($$$) # (could use $$recordPtr{FORMAT} if no Format below, but don't do this to # be backward compatible with improperly written PhotoMechanic tags) $format = $$tagInfo{Format} if $tagInfo; - # use logic to determine format if not specified - unless ($format) { + if (not $format) { + # guess at "int" format if not specified $format = 'int' if $len <= 4 and $len != 3 and $val =~ /[\0-\x08]/; + } elsif ($validate) { + my ($fmt,$min,$max); + if ($format =~ /(.*)\[(\d+)(,(\d+))?\]/) { + $fmt = $1; + $min = $2; + $max = $4 || $2; + } else { + $fmt = $format; + $min = $max = 1; + } + my $siz = Image::ExifTool::FormatSize($fmt) || 1; + $min *= $siz; $max *= $siz; + if ($len < $min or $len > $max) { + my $should = ($min == $max) ? $min : ($len < $min ? "$min min" : "$max max"); + my $what = ($len < $siz * $min) ? 'short' : 'long'; + $et->Warn("IPTC $$tagInfo{Name} too $what ($len bytes; should be $should)", 1); + } } if ($format) { if ($format =~ /^int/) { @@ -1197,7 +1219,10 @@ sub ProcessIPTC($$$) } } } elsif ($format =~ /^string/) { - $val =~ s/\0+$//; # some braindead softwares add null terminators + # some braindead softwares add null terminators + if ($val =~ s/\0+$// and $validate) { + $et->Warn("IPTC $$tagInfo{Name} improperly terminated", 1); + } if ($rec == 1) { # handle CodedCharacterSet tag $xlat = HandleCodedCharset($et, $val) if $tag == 90; @@ -1207,9 +1232,11 @@ sub ProcessIPTC($$$) TranslateCodedString($et, \$val, \$xlat, 1); } } elsif ($format =~ /^digits/) { - $val =~ s/\0+$//; + if ($val =~ s/\0+$// and $validate) { + $et->Warn("IPTC $$tagInfo{Name} improperly terminated", 1); + } } elsif ($format !~ /^undef/) { - warn("Invalid IPTC format: $format"); + warn("Invalid IPTC format: $format"); # (this would be a programming error) } } $verbose and $et->VerboseInfo($tag, $tagInfo, @@ -1253,7 +1280,7 @@ image files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/ISO.pm b/src/Image-ExifTool/lib/Image/ExifTool/ISO.pm new file mode 100644 index 00000000..46317d43 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/ISO.pm @@ -0,0 +1,206 @@ +#------------------------------------------------------------------------------ +# File: ISO.pm +# +# Description: Read information from ISO 9660 disk images +# +# Revisions: 2016-04-07 - P. Harvey created +# +# References: 1) http://wiki.osdev.org/ISO_9660 +#------------------------------------------------------------------------------ + +package Image::ExifTool::ISO; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.01'; + +# trim trailing spaces and ignore tag if empty +my %rawStr = ( + RawConv => sub { + my $val = shift; + $val =~ s/ +$//; + return length($val) ? $val : undef; + }, +); + +# tag info for date/time tags +my %dateInfo = ( + Format => 'undef[17]', + Groups => { 2 => 'Time' }, + ValueConv => q{ + return undef if $val !~ /[^0\0 ]/; # ignore if empty + if ($val =~ s/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(.)/$1:$2:$3 $4:$5:$6.$7/s) { + $val .= TimeZoneString(unpack('c', $8) * 15); + } + return $val; + }, + PrintConv => '$self->ConvertDateTime($val)', +); + +# lookup for volume descriptor types +my %volumeDescriptorType = ( + 0 => 'Boot Record', + 1 => 'Primary Volume', + 2 => 'Supplementary Volume', + 3 => 'Volume Partition', + 255 => 'Terminator', +); + +# ISO tags +%Image::ExifTool::ISO::Main = ( + GROUPS => { 2 => 'Other' }, + NOTES => 'Tags extracted from ISO 9660 disk images.', + 0 => { + Name => 'BootRecord', + SubDirectory => { TagTable => 'Image::ExifTool::ISO::BootRecord' }, + }, + 1 => { + Name => 'PrimaryVolume', + SubDirectory => { TagTable => 'Image::ExifTool::ISO::PrimaryVolume' }, + }, +); + +%Image::ExifTool::ISO::BootRecord = ( + GROUPS => { 2 => 'Other' }, + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + # 0 => { Name => 'VolumeType', PrintConv => \%volumeDescriptorType }, # (0 for boot record) + # 1 => { Name => 'Identifier', Format => 'undef[5]' }, # (always "CD001") + # 6 => 'VolumeDesriptorVersion', # (always 1) + # always extract BootSystem, even if empty, as an indication that this is bootable + 7 => { Name => 'BootSystem', Format => 'string[32]', ValueConv => '$val=~s/ +$//; $val' }, + 39 => { Name => 'BootIdentifier', Format => 'string[32]', %rawStr }, +); + +%Image::ExifTool::ISO::PrimaryVolume = ( + GROUPS => { 2 => 'Other' }, + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + # 0 => { Name => 'VolumeType', PrintConv => \%volumeDescriptorType }, # (1 for primary volume) + # 1 => { Name => 'Identifier', Format => 'undef[5]' }, # (always "CD001") + # 6 => 'VolumeDesriptorVersion', # (always 1) + 8 => { Name => 'System', Format => 'string[32]', %rawStr }, + 40 => { Name => 'VolumeName', Format => 'string[32]', %rawStr }, + 80 => { Name => 'VolumeBlockCount', Format => 'int32u' }, + 120 => { Name => 'VolumeSetDiskCount', Format => 'int16u', Unknown => 1 }, + 124 => { Name => 'VolumeSetDiskNumber', Format => 'int16u', Unknown => 1 }, + 128 => { Name => 'VolumeBlockSize', Format => 'int16u' }, + 132 => { Name => 'PathTableSize', Format => 'int32u', Unknown => 1 }, + 140 => { Name => 'PathTableLocation', Format => 'int32u', Unknown => 1 }, + 174 => { + Name => 'RootDirectoryCreateDate', + Format => 'undef[7]', + Groups => { 2 => 'Time' }, + ValueConv => q{ + my @a = unpack('C6c', $val); + $a[0] += 1900; + $a[6] = TimeZoneString($a[6] * 15); + return sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2d%s', @a); + }, + PrintConv => '$self->ConvertDateTime($val)', + }, + 190 => { Name => 'VolumeSetName', Format => 'string[128]', %rawStr }, + 318 => { Name => 'Publisher', Format => 'string[128]', %rawStr }, + 446 => { Name => 'DataPreparer', Format => 'string[128]', %rawStr }, + 574 => { Name => 'Software', Format => 'string[128]', %rawStr }, + 702 => { Name => 'CopyrightFileName', Format => 'string[38]', %rawStr }, + 740 => { Name => 'AbstractFileName', Format => 'string[36]', %rawStr }, + 776 => { Name => 'BibligraphicFileName',Format => 'string[37]', %rawStr }, + 813 => { Name => 'VolumeCreateDate', %dateInfo }, + 830 => { Name => 'VolumeModifyDate', %dateInfo }, + 847 => { Name => 'VolumeExpirationDate',%dateInfo }, + 864 => { Name => 'VolumeEffectiveDate', %dateInfo }, + #881 => 'FileStructureVersion', # (always 1) +); + +# ISO Composite tags +%Image::ExifTool::ISO::Composite = ( + GROUPS => { 2 => 'Other' }, + VolumeSize => { + Require => { + 0 => 'ISO:VolumeBlockCount', + 1 => 'ISO:VolumeBlockSize', + }, + ValueConv => '$val[0] * $val[1]', + PrintConv => \&Image::ExifTool::ConvertFileSize, + }, +); + +# add our composite tags +Image::ExifTool::AddCompositeTags('Image::ExifTool::ISO'); + +#------------------------------------------------------------------------------ +# Extract information from an ISO 9660 disk image +# Inputs: 0) ExifTool object reference, 1) dirInfo reference +# Returns: 1 on success, 0 if this wasn't a valid ISO 9660 image +sub ProcessISO($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my ($buff, $tagTablePtr); + + # verify this is a valid ISO file + return 0 unless $raf->Seek(32768, 0); + + while ($raf->Read($buff, 2048) == 2048) { + last unless $buff =~ /^[\0-\x03\xff]CD001/; + unless ($tagTablePtr) { + $et->SetFileType(); # set the FileType tag + SetByteOrder('II'); # read little-endian values only + $tagTablePtr = GetTagTable('Image::ExifTool::ISO::Main'); + } + my $type = unpack('C', $buff); + $et->VPrint(0, "Volume descriptor type $type ($volumeDescriptorType{$type})\n"); + last if $type == 255; # stop at terminator + next unless $$tagTablePtr{$type}; + my $subTablePtr = GetTagTable($$tagTablePtr{$type}{SubDirectory}{TagTable}); + my %dirInfo = ( + DataPt => \$buff, + DataPos => $raf->Tell() - 2048, + DirStart => 0, + DirLen => length($buff), + ); + $et->ProcessDirectory(\%dirInfo, $subTablePtr); + } + return $tagTablePtr ? 1 : 0; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::ISO - Read information from ISO 9660 disk images + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to read +information from ISO 9660 disk images. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<http://wiki.osdev.org/ISO_9660> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/ISO Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/ITC.pm b/src/Image-ExifTool/lib/Image/ExifTool/ITC.pm index e877580e..33eda285 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/ITC.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/ITC.pm @@ -191,7 +191,7 @@ information (including artwork images) from iTunes Cover Flow files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Import.pm b/src/Image-ExifTool/lib/Image/ExifTool/Import.pm index 763c3058..9d642fbe 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Import.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Import.pm @@ -12,25 +12,26 @@ require Exporter; use vars qw($VERSION @ISA @EXPORT_OK); -$VERSION = '1.09'; +$VERSION = '1.10'; @ISA = qw(Exporter); @EXPORT_OK = qw(ReadCSV ReadJSON); sub ReadJSONObject($;$); -my %unescapeJSON = ( 't'=>"\t", 'n'=>"\n", 'r'=>"\r" ); +my %unescapeJSON = ( 't'=>"\t", 'n'=>"\n", 'r'=>"\r", 'b' => "\b", 'f' => "\f" ); my $charset; #------------------------------------------------------------------------------ # Read CSV file -# Inputs: 0) CSV file name, file ref or RAF ref, 1) database hash ref, 2) missing tag value +# Inputs: 0) CSV file name, file ref or RAF ref, 1) database hash ref, +# 2) missing tag value, 3) delimiter if other than ',' # Returns: undef on success, or error string # Notes: There are various flavours of CSV, but here we assume that only # double quotes are escaped, and they are escaped by doubling them -sub ReadCSV($$;$) +sub ReadCSV($$;$$) { local ($_, $/); - my ($file, $database, $missingValue) = @_; + my ($file, $database, $missingValue, $delim) = @_; my ($buff, @tags, $found, $err, $raf, $openedFile); if (UNIVERSAL::isa($file, 'File::RandomAccess')) { @@ -45,6 +46,7 @@ sub ReadCSV($$;$) $openedFile = 1; $raf = new File::RandomAccess(\*CSVFILE); } + $delim = ',' unless defined $delim; # set input record separator by first newline found in the file # (safe because first line should contain only tag names) while ($raf->Read($buff, 65536)) { @@ -53,18 +55,18 @@ sub ReadCSV($$;$) $raf->Seek(0,0); while ($raf->ReadLine($buff)) { my (@vals, $v, $i, %fileInfo); - my @toks = split ',', $buff; + my @toks = split /\Q$delim/, $buff; while (@toks) { ($v = shift @toks) =~ s/^ +//; # remove leading spaces if ($v =~ s/^"//) { # quoted value must end in an odd number of quotes while ($v !~ /("+)\s*$/ or not length($1) & 1) { if (@toks) { - $v .= ',' . shift @toks; + $v .= $delim . shift @toks; } else { # read another line from the file $raf->ReadLine($buff) or last; - @toks = split ',', $buff; + @toks = split /\Q$delim/, $buff; last unless @toks; $v .= shift @toks; } @@ -330,9 +332,10 @@ Read CSV or JSON file into a database hash. 2) Optional string used to represent an undefined (missing) tag value. (Used for deleting tags.) -3) [ReadJSON only] Optional character set for converting Unicode escape -sequences in strings. Defaults to "UTF8". See the ExifTool Charset option -for a list of valid settings. +3) For ReadCSV this gives the delimiter for CSV entries, with a default of +",". For ReadJSON this is the character set for converting Unicode escape +sequences in strings, with a default of "UTF8". See the ExifTool Charset +option for a list of valid character sets. =item Return Value: @@ -345,7 +348,7 @@ stored as hash lookups of tag name/value for each SourceFile. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/InDesign.pm b/src/Image-ExifTool/lib/Image/ExifTool/InDesign.pm index b18642b1..b15f43ce 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/InDesign.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/InDesign.pm @@ -258,7 +258,7 @@ them and the LargeFileSupport option is enabled. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/JPEG.pm b/src/Image-ExifTool/lib/Image/ExifTool/JPEG.pm index 8419370d..e1eea0d3 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/JPEG.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/JPEG.pm @@ -11,12 +11,12 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.26'; +$VERSION = '1.33'; sub ProcessOcad($$$); sub ProcessJPEG_HDR($$$); -# (this main JPEG table is for documentation purposes only) +# (most of the tags in this table are for documentation purposes only) %Image::ExifTool::JPEG::Main = ( NOTES => q{ This table lists information extracted by ExifTool from JPEG images. See @@ -63,6 +63,13 @@ sub ProcessJPEG_HDR($$$); Name => 'FLIR', Condition => '$$valPt =~ /^FLIR\0/', SubDirectory => { TagTable => 'Image::ExifTool::FLIR::FFF' }, + }, { + Name => 'RawThermalImage', # (from Parrot Bebop-Pro Thermal drone) + Condition => '$$valPt =~ /^PARROT\0(II\x2a\0|MM\0\x2a)/', + Groups => { 0 => 'APP1', 1 => 'Parrot', 2 => 'Preview' }, + Notes => 'thermal image from Parrot Bebop-Pro Thermal drone', + RawConv => 'substr($val, 7)', + Binary => 1, }], APP2 => [{ Name => 'ICC_Profile', @@ -89,6 +96,16 @@ sub ProcessJPEG_HDR($$$); Name => 'Stim', Condition => '$$valPt =~ /^Stim\0/', SubDirectory => { TagTable => 'Image::ExifTool::Stim::Main' }, + }, { + Name => 'JPS', + Condition => '$$valPt =~ /^_JPSJPS_/', + SubDirectory => { TagTable => 'Image::ExifTool::JPEG::JPS' }, + }, { + Name => 'ThermalData', # (written by DJI FLIR models) + Condition => '$$self{Make} eq "DJI"', + Notes => 'DJI raw thermal data', + Groups => { 0 => 'APP3', 1 => 'DJI', 2 => 'Image' }, + Binary => 1, }, { Name => 'PreviewImage', # (written by HP R837 and Samsung S1060) Condition => '$$valPt =~ /^\xff\xd8\xff\xdb/', @@ -102,6 +119,10 @@ sub ProcessJPEG_HDR($$$); Name => 'FPXR', # (non-standard location written by some HP models) Condition => '$$valPt =~ /^FPXR\0/', SubDirectory => { TagTable => 'Image::ExifTool::FlashPix::Main' }, + }, { + Name => 'ThermalParams', # (written by DJI FLIR models) + Condition => '$$self{Make} eq "DJI" and $$valPt =~ /^\xaa\x55\x12\x06/', + SubDirectory => { TagTable => 'Image::ExifTool::DJI::ThermalParams' }, }, { Name => 'PreviewImage', # (eg. Samsung S1060) Notes => 'continued from APP3', @@ -110,6 +131,16 @@ sub ProcessJPEG_HDR($$$); Name => 'RMETA', Condition => '$$valPt =~ /^RMETA\0/', SubDirectory => { TagTable => 'Image::ExifTool::Ricoh::RMETA' }, + }, { + Name => 'SamsungUniqueID', + Condition => '$$valPt =~ /ssuniqueid\0/', + SubDirectory => { TagTable => 'Image::ExifTool::Samsung::APP5' }, + }, { + Name => 'ThermalCalibration', # (written by DJI FLIR models) + Condition => '$$self{Make} eq "DJI"', + Notes => 'DJI thermal calibration data', + Groups => { 0 => 'APP5', 1 => 'DJI', 2 => 'Image' }, + Binary => 1, }, { Name => 'PreviewImage', # (eg. BenQ DC E1050) Notes => 'continued from APP4', @@ -130,11 +161,22 @@ sub ProcessJPEG_HDR($$$); Name => 'GoPro', Condition => '$$valPt =~ /^GoPro\0/', SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' }, + # also seen Motorola APP6 "MMIMETA\0", with sub-types: AL3A,ALED,MMI0,MOTD,QC3A + }, { + Name => 'DJI_DTAT', # (written by ZH20T) + Condition => '$$valPt =~ /^DTAT\0\0.\{/s', + Groups => { 0 => 'APP6', 1 => 'DJI' }, + Notes => 'DJI Thermal Analysis Tool record', + ValueConv => 'substr($val,7)', }], APP7 => [{ Name => 'Pentax', Condition => '$$valPt =~ /^PENTAX \0/', SubDirectory => { TagTable => 'Image::ExifTool::Pentax::Main' }, + }, { + Name => 'Huawei', + Condition => '$$valPt =~ /^HUAWEI\0\0/', + SubDirectory => { TagTable => 'Image::ExifTool::Unknown::Main' }, }, { Name => 'Qualcomm', Condition => '$$valPt =~ /^\x1aQualcomm Camera Attributes/', @@ -155,11 +197,15 @@ sub ProcessJPEG_HDR($$$); Condition => '$$valPt =~ /^UNICODE\0/', Notes => 'PhotoStudio Unicode comment', }, - APP11 => { + APP11 => [{ Name => 'JPEG-HDR', Condition => '$$valPt =~ /^HDR_RI /', SubDirectory => { TagTable => 'Image::ExifTool::JPEG::HDR' }, - }, + },{ + Name => 'JUMBF', + Condition => '$$valPt =~ /^JP/', + SubDirectory => { TagTable => 'Image::ExifTool::Jpeg2000::Main' }, + }], APP12 => [{ Name => 'PictureInfo', Condition => '$$valPt =~ /(\[picture info\]|Type=)/', @@ -181,7 +227,7 @@ sub ProcessJPEG_HDR($$$); APP14 => { Name => 'Adobe', Condition => '$$valPt =~ /^Adobe/', - Writable => 1, # (for docs only) + Writable => 2, # (for docs only) SubDirectory => { TagTable => 'Image::ExifTool::JPEG::Adobe' }, }, APP15 => { @@ -194,7 +240,7 @@ sub ProcessJPEG_HDR($$$); Name => 'Comment', # note: flag as writable for documentation, but it won't show up # in the TagLookup as writable because there is no WRITE_PROC - Writable => 1, + Writable => 2, }, SOF => { Name => 'StartOfFrame', @@ -231,11 +277,84 @@ sub ProcessJPEG_HDR($$$); Name => 'Samsung', Condition => '$$valPt =~ /QDIOBS$/', SubDirectory => { TagTable => 'Image::ExifTool::Samsung::Trailer' }, + }, { + Name => 'EmbeddedVideo', + Notes => 'extracted only when ExtractEmbedded option is used', + Condition => '$$valPt =~ /^.{4}ftyp/s', + }, { + Name => 'Insta360', + Condition => '$$valPt =~ /8db42d694ccc418790edff439fe026bf$/', + }, { + Name => 'NikonApp', + Condition => '$$valPt =~ m(\0{6}/NIKON APP$)', + Notes => 'contains editing information in XMP format', }, { Name => 'PreviewImage', Condition => '$$valPt =~ /^\xff\xd8\xff/', - Writable => 1, # (for docs only) + Writable => 2, # (for docs only) + }], +); + +# JPS APP3 segment (ref http://paulbourke.net/stereographics/stereoimage/) +%Image::ExifTool::JPEG::JPS = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 0 => 'APP3', 1 => 'JPS', 2 => 'Image' }, + NOTES => 'Tags found in JPEG Stereo (JPS) images.', + 0x0a => { + Name => 'JPSSeparation', + Format => 'int32u', # (just so we can look ahead to MediaType); + Notes => 'stereo only', + RawConv => q{ + $$self{MediaType} = $val & 0xff; + return undef unless $$self{MediaType} == 1; + return(($val >> 24) & 0xff); + }, + }, + 0x08 => { + Name => 'HdrLength', + Format => 'int16u', + Hidden => 1, + RawConv => '$$self{HdrLength} = $val; undef', + }, + 0x0b => { + Name => 'JPSFlags', + PrintConv => { BITMASK => { + 0 => 'Half height', + 1 => 'Half width', + 2 => 'Left field first', + }}, + }, + 0x0c => [{ + Name => 'JPSLayout', + Condition => '$$self{MediaType} == 0', + Notes => 'mono', + PrintConv => { + 0 => 'Both Eyes', + 1 => 'Left Eye', + 2 => 'Right Eye', + }, + },{ + Name => 'JPSLayout', + Condition => '$$self{MediaType} == 1', + Notes => 'stereo', + PrintConv => { + 1 => 'Interleaved', + 2 => 'Side By Side', + 3 => 'Over Under', + 4 => 'Anaglyph', + }, }], + 0x0d => { + Name => 'JPSType', + Hook => '$varSize += $$self{HdrLength} - 4', # comment starts after header block + PrintConv => { 0 => 'Mono', 1 => 'Stereo' }, + }, + # 0x0e - in16u comment length (ignored -- assume the remainder is all comment) + # (this is offset if we had a 4-byte JPS header block) + 0x10 => { + Name => 'JPSComment', + Format => 'string', + }, ); # EPPIM APP6 (Toshiba PrintIM) segment (ref PH, from PDR-M700 samples) @@ -248,6 +367,7 @@ sub ProcessJPEG_HDR($$$); 0xc4a5 => { Name => 'PrintIM', # must set Writable here so this tag will be saved with MakerNotes option + # (but it isn't actually writable because there is no WRITE_PROC) Writable => 'undef', Description => 'Print Image Matching', SubDirectory => { @@ -495,7 +615,7 @@ sub ProcessJPEG_HDR($$$); }, 2 => { Name => 'ImageFormat', - ValueConv => 'chr($val)', + ValueConv => 'chr($val & 0xff)', PrintConv => { B => 'IMode B' }, }, 3 => { @@ -598,7 +718,7 @@ segments are included in the Image::ExifTool module itself. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/JPEGDigest.pm b/src/Image-ExifTool/lib/Image/ExifTool/JPEGDigest.pm index 4b2171f8..759d2a39 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/JPEGDigest.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/JPEGDigest.pm @@ -283,7 +283,7 @@ my %PrintConv = ( #JD '42bfe52476bf07f1ed0e6451903cc9ee:111111' => 'Adobe Lightroom, Quality 85% - 92%', '4c3c425b4024b68c0de03904a825bc35:111111' => 'Adobe Lightroom, Quality 93% - 100%', - # Tested with Adobe Photoshop CS2 Version 9.0.2 (Win) - "Save as..." (RGB/CYMK) + # Tested with Adobe Photoshop CS2 Version 9.0.2 (Win) - "Save as..." (RGB/CMYK) '683506a889c78d9bc230a0c7ee5f62f3:221111' => 'Adobe Photoshop, Quality 0', 'bc490651af6592cd1dbbbc4fa2cfa1fb:221111' => 'Adobe Photoshop, Quality 1', 'ce4286d9f07999524c3c7472b065c5ab:221111' => 'Adobe Photoshop, Quality 2', @@ -2590,7 +2590,7 @@ estimated JPEG quality if requested. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/JSON.pm b/src/Image-ExifTool/lib/Image/ExifTool/JSON.pm new file mode 100644 index 00000000..daff8046 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/JSON.pm @@ -0,0 +1,190 @@ +#------------------------------------------------------------------------------ +# File: JSON.pm +# +# Description: Read JSON files +# +# Notes: Set ExifTool MissingTagValue to "null" to ignore JSON nulls +# +# Revisions: 2017/03/13 - P. Harvey Created +#------------------------------------------------------------------------------ + +package Image::ExifTool::JSON; +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); +use Image::ExifTool::Import; + +$VERSION = '1.05'; + +sub ProcessJSON($$); +sub ProcessTag($$$$%); + +%Image::ExifTool::JSON::Main = ( + GROUPS => { 0 => 'JSON', 1 => 'JSON', 2 => 'Other' }, + VARS => { NO_ID => 1 }, + PROCESS_PROC => \&ProcessJSON, + NOTES => q{ + Other than a few tags in the table below, JSON tags have not been + pre-defined. However, ExifTool will read any existing tags from basic + JSON-formatted files. + }, + # ON1 settings tags + ON1_SettingsData => { + RawConv => q{ + require Image::ExifTool::XMP; + $val = Image::ExifTool::XMP::DecodeBase64($val); + }, + SubDirectory => { TagTable => 'Image::ExifTool::PLIST::Main' }, + }, + ON1_SettingsMetadataCreated => { Groups => { 2 => 'Time' } }, + ON1_SettingsMetadataModified => { Groups => { 2 => 'Time' } }, + ON1_SettingsMetadataName => { }, + ON1_SettingsMetadataPluginID => { }, + ON1_SettingsMetadataTimestamp => { Groups => { 2 => 'Time' } }, + ON1_SettingsMetadataUsage => { }, + ON1_SettingsMetadataVisibleToUser=>{ }, +); + +#------------------------------------------------------------------------------ +# Store a tag value +# Inputs: 0) ExifTool ref, 1) tag table, 2) tag ID, 3) value, 4) tagInfo flags +sub FoundTag($$$$%) +{ + my ($et, $tagTablePtr, $tag, $val, %flags) = @_; + + # special case to reformat ON1 tag names + if ($tag =~ s/^settings\w{8}-\w{4}-\w{4}-\w{4}-\w{12}(Data|Metadata.+)$/ON1_Settings$1/) { + $et->OverrideFileType('ONP','application/on1') if $$et{FILE_TYPE} eq 'JSON'; + } + + # avoid conflict with special table entries + $tag .= '!' if $Image::ExifTool::specialTags{$tag}; + + AddTagToTable($tagTablePtr, $tag, { + Name => Image::ExifTool::MakeTagName($tag), + %flags, + Temporary => 1, + }) unless $$tagTablePtr{$tag}; + + $et->HandleTag($tagTablePtr, $tag, $val); +} + +#------------------------------------------------------------------------------ +# Process a JSON tag +# Inputs: 0) ExifTool ref, 1) tag table, 2) tag ID, 3) value, 4) tagInfo flags +# - expands structures into flattened tags as required +sub ProcessTag($$$$%) +{ + local $_; + my ($et, $tagTablePtr, $tag, $val, %flags) = @_; + + if (ref $val eq 'HASH') { + if ($et->Options('Struct')) { + FoundTag($et, $tagTablePtr, $tag, $val, %flags, Struct => 1); + return unless $et->Options('Struct') > 1; + } + # support hashes with ordered keys + my @keys = $$val{_ordered_keys_} ? @{$$val{_ordered_keys_}} : sort keys %$val; + foreach (@keys) { + my $tg = $tag . ((/^\d/ and $tag =~ /\d$/) ? '_' : '') . ucfirst; + $tg =~ s/([^a-zA-Z])([a-z])/$1\U$2/g; + ProcessTag($et, $tagTablePtr, $tg, $$val{$_}, %flags, Flat => 1); + } + } elsif (ref $val eq 'ARRAY') { + foreach (@$val) { + ProcessTag($et, $tagTablePtr, $tag, $_, %flags, List => 1); + } + } elsif (defined $val) { + FoundTag($et, $tagTablePtr, $tag, $val, %flags); + } +} + +#------------------------------------------------------------------------------ +# Extract meta information from a JSON file +# Inputs: 0) ExifTool object reference, 1) dirInfo reference +# Returns: 1 on success, 0 if this wasn't a recognized JSON file +sub ProcessJSON($$) +{ + local $_; + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my $structOpt = $et->Options('Struct'); + my (%database, $key, $tag, $dataPt); + + unless ($raf) { + $dataPt = $$dirInfo{DataPt}; + if ($$dirInfo{DirStart} or ($$dirInfo{DirLen} and $$dirInfo{DirLen} ne length($$dataPt))) { + my $buff = substr(${$$dirInfo{DataPt}}, $$dirInfo{DirStart}, $$dirInfo{DirLen}); + $dataPt = \$buff; + } + $raf = new File::RandomAccess($dataPt); + # extract as a block if requested + my $blockName = $$dirInfo{BlockInfo} ? $$dirInfo{BlockInfo}{Name} : ''; + my $blockExtract = $et->Options('BlockExtract'); + if ($blockName and ($blockExtract or $$et{REQ_TAG_LOOKUP}{lc $blockName} or + ($$et{TAGS_FROM_FILE} and not $$et{EXCL_TAG_LOOKUP}{lc $blockName}))) + { + $et->FoundTag($$dirInfo{BlockInfo}, $$dataPt); + return 1 if $blockExtract and $blockExtract > 1; + } + $et->VerboseDir('JSON'); + } + + # read information from JSON file into database structure + my $err = Image::ExifTool::Import::ReadJSON($raf, \%database, + $et->Options('MissingTagValue'), $et->Options('Charset')); + + return 0 if $err or not %database; + + $et->SetFileType() unless $dataPt; + + my $tagTablePtr = GetTagTable('Image::ExifTool::JSON::Main'); + + # remove any old tag definitions in case they change flags + foreach $key (TagTableKeys($tagTablePtr)) { + delete $$tagTablePtr{$key} if $$tagTablePtr{$key}{Temporary}; + } + + # extract tags from JSON database + foreach $key (sort keys %database) { + foreach $tag (sort keys %{$database{$key}}) { + my $val = $database{$key}{$tag}; + # (ignore SourceFile if generated automatically by ReadJSON) + next if $tag eq 'SourceFile' and defined $val and $val eq '*'; + ProcessTag($et, $tagTablePtr, $tag, $val); + } + } + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::JSON - Read JSON files + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool read +information from JSON files. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/JSON Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/JVC.pm b/src/Image-ExifTool/lib/Image/ExifTool/JVC.pm index db890f4a..53392241 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/JVC.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/JVC.pm @@ -117,7 +117,7 @@ notes. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Jpeg2000.pm b/src/Image-ExifTool/lib/Image/ExifTool/Jpeg2000.pm index 6c7fe2f2..76fb5ffe 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Jpeg2000.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Jpeg2000.pm @@ -16,9 +16,10 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.26'; +$VERSION = '1.32'; sub ProcessJpeg2000Box($$$); +sub ProcessJUMD($$$); my %resolutionUnit = ( -3 => 'km', @@ -41,8 +42,25 @@ my %jp2Map = ( 'UUID-IPTC' => 'JP2', 'UUID-EXIF' => 'JP2', 'UUID-XMP' => 'JP2', - # jp2h => 'JP2', (not yet functional) - # ICC_Profile => 'jp2h', (not yet functional) + jp2h => 'JP2', + colr => 'jp2h', + ICC_Profile => 'colr', + IFD1 => 'IFD0', + EXIF => 'IFD0', # to write EXIF as a block + ExifIFD => 'IFD0', + GPS => 'IFD0', + SubIFD => 'IFD0', + GlobParamIFD => 'IFD0', + PrintIM => 'IFD0', + InteropIFD => 'ExifIFD', + MakerNotes => 'ExifIFD', +); + +# map of where information is written in a JXL image +my %jxlMap = ( + IFD0 => 'Exif', + XMP => 'XML', + 'Exif' => 'JP2', IFD1 => 'IFD0', EXIF => 'IFD0', # to write EXIF as a block ExifIFD => 'IFD0', @@ -107,9 +125,13 @@ my %j2cMarker = ( WRITE_PROC => \&ProcessJpeg2000Box, PREFERRED => 1, # always add these tags when writing NOTES => q{ - The tags below are extracted from JPEG 2000 images, however ExifTool - currently writes only EXIF, IPTC and XMP tags in these images. + The tags below are found in JPEG 2000 images and the JUMBF metadata in JPEG + images, but not all of these are extracted. Note that ExifTool currently + writes only EXIF, IPTC and XMP tags in Jpeg2000 images. }, +# +# NOTE: ONLY TAGS WITH "Format" DEFINED ARE EXTRACTED! +# 'jP ' => 'JP2Signature', # (ref 1) "jP\x1a\x1a" => 'JP2Signature', # (ref 2) prfl => 'Profile', @@ -186,7 +208,11 @@ my %j2cMarker = ( comp => 'Composition', copt => 'CompositionOptions', inst => 'InstructionSet', - asoc => 'Association', + asoc => { + Name => 'Association', + SubDirectory => { }, + }, + # (Association box may contain any other sub-box) nlst => 'NumberList', bfil => 'BinaryFilter', drep => 'DesiredReproductions', @@ -195,13 +221,22 @@ my %j2cMarker = ( chck => 'DigitalSignature', mp7b => 'MPEG7Binary', free => 'Free', - jp2c => 'ContiguousCodestream', + jp2c => [{ + Name => 'ContiguousCodestream', + Condition => 'not $$self{jumd_level}', + },{ + Name => 'PreviewImage', + Groups => { 2 => 'Preview' }, + Format => 'undef', + Binary => 1, + }], jp2i => { Name => 'IntellectualProperty', SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' }, }, - 'xml '=> { + 'xml '=> [{ Name => 'XML', + Condition => 'not $$self{IsJXL}', Writable => 'undef', Flags => [ 'Binary', 'Protected', 'BlockExtract' ], List => 1, @@ -209,11 +244,18 @@ my %j2cMarker = ( by default, the XML data in this tag is parsed using the ExifTool XMP module to to allow individual tags to be accessed when reading, but it may also be extracted as a block via the "XML" tag, which is also how this tag is - written and copied. This is a List-type tag because multiple XML blocks may - exist + written and copied. It may also be extracted as a block by setting the API + BlockExtract option. This is a List-type tag because multiple XML blocks + may exist }, + # (note: extracting as a block was broken in 11.04, and finally fixed in 12.14) + SubDirectory => { TagTable => 'Image::ExifTool::XMP::XML' }, + },{ + Name => 'XMP', + Notes => 'used for XMP in JPEG XL files', + # NOTE: the hacked code relies on this being at index 1 of the tagInfo list! SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' }, - }, + }], uuid => [ { Name => 'UUID-EXIF', @@ -297,6 +339,22 @@ my %j2cMarker = ( Start => '$valuePtr + 16', }, }, + { + Name => 'UUID-Signature', # (seen in JUMB data of JPEG images) + # (may be able to remove this when JUMBF specification is finalized) + Condition => '$$valPt=~/^casg\x00\x11\x00\x10\x80\x00\x00\xaa\x00\x38\x9b\x71/', + Format => 'undef', + ValueConv => 'substr($val,16)', + }, + { + Name => 'UUID-C2PAClaimSignature', # (seen in incorrectly-formatted JUMB data of JPEG images) + # (may be able to remove this when JUMBF specification is finalized) + Condition => '$$valPt=~/^c2cs\x00\x11\x00\x10\x80\x00\x00\xaa\x00\x38\x9b\x71/', + SubDirectory => { + TagTable => 'Image::ExifTool::CBOR::Main', + Start => '$valuePtr + 16', + }, + }, { Name => 'UUID-Unknown', }, @@ -316,6 +374,73 @@ my %j2cMarker = ( Name => 'URL', Format => 'string', }, + # JUMBF boxes (ref https://github.com/thorfdbg/codestream-parser) + jumd => { + Name => 'JUMBFDescr', + SubDirectory => { TagTable => 'Image::ExifTool::Jpeg2000::JUMD' }, + }, + jumb => { + Name => 'JUMBFBox', + SubDirectory => { + TagTable => 'Image::ExifTool::Jpeg2000::Main', + ProcessProc => \&ProcessJUMB, + }, + }, + json => { + Name => 'JSONData', + Flags => [ 'Binary', 'Protected', 'BlockExtract' ], + Notes => q{ + by default, data in this tag is parsed using the ExifTool JSON module to to + allow individual tags to be accessed when reading, but it may also be + extracted as a block via the "JSONData" tag or by setting the API + BlockExtract option + }, + SubDirectory => { TagTable => 'Image::ExifTool::JSON::Main' }, + }, + cbor => { + Name => 'CBORData', + Flags => [ 'Binary', 'Protected' ], + SubDirectory => { TagTable => 'Image::ExifTool::CBOR::Main' }, + }, + bfdb => { # used in JUMBF (see # (used when tag is renamed according to JUMDLabel) + Name => 'BinaryDataType', + Notes => 'JUMBF, MIME type and optional file name', + Format => 'undef', + # (ignore "toggles" byte and just extract MIME type and file name) + ValueConv => '$_=substr($val,1); s/\0+$//; s/\0/, /; $_', + JUMBF_Suffix => 'Type', # (used when tag is renamed according to JUMDLabel) + }, + bidb => { # used in JUMBF + Name => 'BinaryData', + Notes => 'JUMBF', + Groups => { 2 => 'Preview' }, + Format => 'undef', + Binary => 1, + JUMBF_Suffix => 'Data', # (used when tag is renamed according to JUMDLabel) + }, +# +# stuff seen in JPEG XL images: +# + # jbrd - JPEG Bitstream Reconstruction Data (allows lossless conversion back to original JPG) + jxlc => { + Name => 'JXLCodestream', + Format => 'undef', + Notes => q{ + Codestream in JPEG XL image. Currently processed only to determine + ImageSize + }, + RawConv => 'Image::ExifTool::Jpeg2000::ProcessJXLCodestream($self,\$val); undef', + }, + Exif => { + Name => 'EXIF', + SubDirectory => { + TagTable => 'Image::ExifTool::Exif::Main', + ProcessProc => \&Image::ExifTool::ProcessTIFF, + WriteProc => \&Image::ExifTool::WriteTIFF, + DirName => 'EXIF', + Start => '$valuePtr + 4', + }, + }, ); %Image::ExifTool::Jpeg2000::ImageHeader = ( @@ -370,6 +495,7 @@ my %j2cMarker = ( 'jp2 ' => 'JPEG 2000 Image (.JP2)', # image/jp2 'jpm ' => 'JPEG 2000 Compound Image (.JPM)', # image/jpm 'jpx ' => 'JPEG 2000 with extensions (.JPX)', # image/jpx + 'jxl ' => 'JPEG XL Image (.JXL)', # image/jxl }, }, 1 => { @@ -435,11 +561,34 @@ my %j2cMarker = ( %Image::ExifTool::Jpeg2000::ColorSpec = ( PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + WRITE_PROC => \&Image::ExifTool::WriteBinaryData, # (we don't actually call this) GROUPS => { 2 => 'Image' }, FORMAT => 'int8s', + WRITABLE => 1, + # (Note: 'colr' is not a real group, but is used as a hack to write the + # necessary colr box. This hack necessitated another hack in TagInfoXML.pm + # to avoid reporting this fake group in the XML output) + WRITE_GROUP => 'colr', + DATAMEMBER => [ 0 ], + IS_SUBDIR => [ 3 ], + NOTES => q{ + The table below contains tags in the color specification (colr) box. This + box may be rewritten by writing either ICC_Profile, ColorSpace or + ColorSpecData. When writing, any existing colr boxes are replaced with the + newly created colr box. + + B<NOTE>: Care must be taken when writing this color specification because + writing a specification that is incompatible with the image data may make + the image undisplayable. + }, 0 => { Name => 'ColorSpecMethod', RawConv => '$$self{ColorSpecMethod} = $val', + Protected => 1, + Notes => q{ + default for writing is 2 when writing ICC_Profile, 1 when writing + ColorSpace, or 4 when writing ColorSpecData + }, PrintConv => { 1 => 'Enumerated', 2 => 'Restricted ICC', @@ -447,9 +596,15 @@ my %j2cMarker = ( 4 => 'Vendor Color', }, }, - 1 => 'ColorSpecPrecedence', + 1 => { + Name => 'ColorSpecPrecedence', + Notes => 'default for writing is 0', + Protected => 1, + }, 2 => { Name => 'ColorSpecApproximation', + Notes => 'default for writing is 0', + Protected => 1, PrintConv => { 0 => 'Not Specified', 1 => 'Accurate', @@ -474,6 +629,7 @@ my %j2cMarker = ( Name => 'ColorSpace', Condition => '$$self{ColorSpecMethod} == 1', Format => 'int32u', + Protected => 1, PrintConv => { # ref 15444-2 2002-05-15 0 => 'Bi-level', 1 => 'YCbCr(1)', @@ -503,11 +659,121 @@ my %j2cMarker = ( { Name => 'ColorSpecData', Format => 'undef[$size-3]', + Writable => 'undef', + Protected => 1, Binary => 1, }, ], ); +# JUMBF description box +%Image::ExifTool::Jpeg2000::JUMD = ( + PROCESS_PROC => \&ProcessJUMD, + GROUPS => { 0 => 'JUMBF', 1 => 'JUMBF', 2 => 'Image' }, + NOTES => 'Information extracted from the JUMBF description box.', + 'type' => { + Name => 'JUMDType', + ValueConv => 'unpack "H*", $val', + PrintConv => q{ + my @a = $val =~ /^(\w{8})(\w{4})(\w{4})(\w{16})$/; + return $val unless @a; + my $ascii = pack 'H*', $a[0]; + $a[0] = "($ascii)" if $ascii =~ /^[a-zA-Z0-9]{4}$/; + return join '-', @a; + }, + # seen: + # cacb/cast/caas/cacl/casg/json-00110010800000aa00389b71 + # 6579d6fbdba2446bb2ac1b82feeb89d1 - JPEG image + }, + 'label' => { Name => 'JUMDLabel' }, + 'toggles' => { + Name => 'JUMDToggles', + Unknown => 1, + PrintConv => { BITMASK => { + 0 => 'Requestable', + 1 => 'Label', + 2 => 'ID', + 3 => 'Signature', + }}, + }, + 'id' => { Name => 'JUMDID', Description => 'JUMD ID' }, + 'sig' => { Name => 'JUMDSignature', PrintConv => 'unpack "H*", $val' }, +); + +#------------------------------------------------------------------------------ +# Read JUMBF box to keep track of sub-document numbers +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub ProcessJUMB($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + if ($$et{jumd_level}) { + ++$$et{jumd_level}[-1]; # increment current sub-document number + } else { + $$et{jumd_level} = [ ++$$et{DOC_COUNT} ]; # new top-level sub-document + $$et{SET_GROUP0} = 'JUMBF'; + } + $$et{DOC_NUM} = join '-', @{$$et{jumd_level}}; + push @{$$et{jumd_level}}, 0; + ProcessJpeg2000Box($et, $dirInfo, $tagTablePtr); + delete $$et{DOC_NUM}; + delete $$et{JUMBFLabel}; + pop @{$$et{jumd_level}}; + if (@{$$et{jumd_level}} < 2) { + delete $$et{jumd_level}; + delete $$et{SET_GROUP0}; + } + return 1; +} + +#------------------------------------------------------------------------------ +# Read JUMBF description box (ref https://github.com/thorfdbg/codestream-parser) +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub ProcessJUMD($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $pos = $$dirInfo{DirStart}; + my $end = $pos + $$dirInfo{DirLen}; + $et->VerboseDir('JUMD', 0, $end-$pos); + delete $$et{JUMBFLabel}; + $$dirInfo{DirLen} < 17 and $et->Warn('Truncated JUMD directory'), return 0; + my $type = substr($$dataPt, $pos, 4); + $et->HandleTag($tagTablePtr, 'type', substr($$dataPt, $pos, 16)); + $pos += 16; + my $flags = Get8u($dataPt, $pos++); + $et->HandleTag($tagTablePtr, 'toggles', $flags); + if ($flags & 0x02) { # label exists? + pos($$dataPt) = $pos; + $$dataPt =~ /\0/g or $et->Warn('Missing JUMD label terminator'), return 0; + my $len = pos($$dataPt) - $pos; + my $name = substr($$dataPt, $pos, $len); + $et->HandleTag($tagTablePtr, 'label', $name); + $pos += $len; + if ($len) { + $name =~ s/[^-_a-zA-Z0-9]([a-z])/\U$1/g; # capitalize characters after illegal characters + $name =~ tr/-_a-zA-Z0-9//dc; # remove other illegal characters + $name =~ s/__/_/; # collapse double underlines + $name = ucfirst $name; # capitalize first letter + $name = "Tag$name" if length($name) < 2; # must at least 2 characters long + $$et{JUMBFLabel} = $name; + } + } + if ($flags & 0x04) { # ID exists? + $pos + 4 > $end and $et->Warn('Missing JUMD ID'), return 0; + $et->HandleTag($tagTablePtr, 'id', Get32u($dataPt, $pos)); + $pos += 4; + } + if ($flags & 0x08) { # signature exists? + $pos + 32 > $end and $et->Warn('Missing JUMD signature'), return 0; + $et->HandleTag($tagTablePtr, 'sig', substr($$dataPt, $pos, 32)); + $pos += 32; + } + $pos == $end or $et->Warn('Extra data in JUMD box'." $pos $end", 1); + return 1; +} + #------------------------------------------------------------------------------ # Create new JPEG 2000 boxes when writing # (Currently only supports adding top-level Writable JPEG2000 tags and certain UUID boxes) @@ -537,8 +803,29 @@ sub CreateNewBoxes($$) $et->VerboseValue("+ Jpeg2000:$$tagInfo{Name}", $val); } } - # add UUID boxes + # add UUID boxes (and/or JXL Exif/XML boxes) foreach $dirName (sort keys %$addDirs) { + # handle JPEG XL XMP and EXIF + if ($dirName eq 'XML' or $dirName eq 'Exif') { + my ($tag, $dir) = $dirName eq 'XML' ? ('xml ', 'XMP') : ('Exif', 'EXIF'); + my $tagInfo = $Image::ExifTool::Jpeg2000::Main{$tag}; + $tagInfo = $$tagInfo[1] if ref $tagInfo eq 'ARRAY'; # (hack for stupid JXL XMP) + my $subdir = $$tagInfo{SubDirectory}; + my $tagTable = GetTagTable($$subdir{TagTable}); + $tagTable = GetTagTable('Image::ExifTool::XMP::Main') if $dir eq 'XMP'; + my %dirInfo = ( + DirName => $dir, + Parent => 'JP2', + ); + my $newdir = $et->WriteDirectory(\%dirInfo, $tagTable, $$subdir{WriteProc}); + if (defined $newdir and length $newdir) { + # not sure why, but EXIF box is padded with leading 0's in my sample + my $pad = $dirName eq 'Exif' ? "\0\0\0\0" : ''; + my $boxhdr = pack('N', length($newdir) + length($pad) + 8) . $tag; + Write($outfile, $boxhdr, $pad, $newdir) or return 0; + next; + } + } next unless $uuid{$dirName}; my $tagInfo; foreach $tagInfo (@{$Image::ExifTool::Jpeg2000::Main{uuid}}) { @@ -563,6 +850,48 @@ sub CreateNewBoxes($$) return 1; } +#------------------------------------------------------------------------------ +# Create Color Specification Box +# Inputs: 0) ExifTool object ref, 1) Output file or scalar ref +# Returns: 1 on success +sub CreateColorSpec($$) +{ + my ($et, $outfile) = @_; + my $meth = $et->GetNewValue('Jpeg2000:ColorSpecMethod'); + my $prec = $et->GetNewValue('Jpeg2000:ColorSpecPrecedence') || 0; + my $approx = $et->GetNewValue('Jpeg2000:ColorSpecApproximation') || 0; + my $icc = $et->GetNewValue('ICC_Profile'); + my $space = $et->GetNewValue('Jpeg2000:ColorSpace'); + my $cdata = $et->GetNewValue('Jpeg2000:ColorSpecData'); + unless ($meth) { + if ($icc) { + $meth = 2; + } elsif (defined $space) { + $meth = 1; + } elsif (defined $cdata) { + $meth = 4; + } else { + $et->Warn('Color space not defined'), return 0; + } + } + if ($meth eq '1') { + defined $space or $et->Warn('Must specify ColorSpace'), return 0; + $cdata = pack('N', $space); + } elsif ($meth eq '2' or $meth eq '3') { + defined $icc or $et->Warn('Must specify ICC_Profile'), return 0; + $cdata = $icc; + } elsif ($meth eq '4') { + defined $cdata or $et->Warn('Must specify ColorSpecData'), return 0; + } else { + $et->Warn('Unknown ColorSpecMethod'), return 0; + } + my $boxhdr = pack('N', length($cdata) + 11) . 'colr'; + Write($outfile, $boxhdr, pack('CCC',$meth,$prec,$approx), $cdata) or return 0; + ++$$et{CHANGED}; + $et->VPrint(1, " + Jpeg2000:ColorSpec\n"); + return 1; +} + #------------------------------------------------------------------------------ # Process JPEG 2000 box # Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) Pointer to tag table @@ -580,7 +909,7 @@ sub ProcessJpeg2000Box($$$) my $raf = $$dirInfo{RAF}; my $outfile = $$dirInfo{OutFile}; my $dirEnd = $dirStart + $dirLen; - my ($err, $outBuff, $verbose); + my ($err, $outBuff, $verbose, $doColour); if ($outfile) { unless ($raf) { @@ -588,13 +917,19 @@ sub ProcessJpeg2000Box($$$) $outBuff = ''; $outfile = \$outBuff; } + # determine if we will be writing colr box + if ($$dirInfo{DirName} and $$dirInfo{DirName} eq 'JP2Header') { + $doColour = 2 if defined $et->GetNewValue('ColorSpecMethod') or $et->GetNewValue('ICC_Profile') or + defined $et->GetNewValue('ColorSpecPrecedence') or defined $et->GetNewValue('ColorSpace') or + defined $et->GetNewValue('ColorSpecApproximation') or defined $et->GetNewValue('ColorSpecData'); + } } else { # (must not set verbose flag when writing!) $verbose = $$et{OPTIONS}{Verbose}; $et->VerboseDir($$dirInfo{DirName}) if $verbose; } # loop through all contained boxes - my ($pos, $boxLen); + my ($pos, $boxLen, $lastBox); for ($pos=$dirStart; ; $pos+=$boxLen) { my ($boxID, $buff, $valuePtr); my $hdrLen = 8; # the box header length @@ -603,9 +938,7 @@ sub ProcessJpeg2000Box($$$) my $n = $raf->Read($buff,$hdrLen); unless ($n == $hdrLen) { $n and $err = '', last; - if ($outfile) { - CreateNewBoxes($et, $outfile) or $err = 1; - } + CreateNewBoxes($et, $outfile) or $err = 1 if $outfile; last; } $dataPt = \$buff; @@ -617,6 +950,17 @@ sub ProcessJpeg2000Box($$$) } $boxLen = unpack("x$pos N",$$dataPt); # (length includes header and data) $boxID = substr($$dataPt, $pos+4, 4); + # remove old colr boxes if necessary + if ($doColour and $boxID eq 'colr') { + if ($doColour == 1) { # did we successfully write the new colr box? + $et->VPrint(1," - Jpeg2000:ColorSpec\n"); + ++$$et{CHANGED}; + next; + } + $et->Warn('Out-of-order colr box encountered'); + undef $doColour; + } + $lastBox = $boxID; $pos += $hdrLen; # move to end of box header if ($boxLen == 1) { # box header contains an additional 8-byte integer for length @@ -710,6 +1054,14 @@ sub ProcessJpeg2000Box($$$) } } } + # create new tag for JUMBF data values with name corresponding to JUMBFLabel + if ($tagInfo and $$et{JUMBFLabel} and (not $$tagInfo{SubDirectory} or $$tagInfo{BlockExtract})) { + $tagInfo = { %$tagInfo, Name => $$et{JUMBFLabel} . ($$tagInfo{JUMBF_Suffix} || '') }; + delete $$tagInfo{Description}; + AddTagToTable($tagTablePtr, '_JUMBF_' . $$et{JUMBFLabel}, $tagInfo); + delete $$tagInfo{Protected}; # (must do this so -j -b returns JUMBF binary data) + $$tagInfo{TagID} = $boxID; + } if ($verbose) { $et->VerboseInfo($boxID, $tagInfo, Table => $tagTablePtr, @@ -747,8 +1099,10 @@ sub ProcessJpeg2000Box($$$) # remove this directory from our create list delete $$et{AddJp2Dirs}{$$tagInfo{Name}}; my $newdir; - # only edit writable UUID boxes - if ($uuid) { + # only edit writable UUID, Exif and jp2h boxes + if ($uuid or $boxID eq 'Exif' or ($boxID eq 'xml ' and $$et{IsJXL}) or + ($boxID eq 'jp2h' and $$et{EDIT_DIRS}{jp2h})) + { $newdir = $et->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc}); next if defined $newdir and not length $newdir; # next if deleting the box } elsif (defined $uuid) { @@ -760,6 +1114,11 @@ sub ProcessJpeg2000Box($$$) my $boxhdr = pack('N', length($newdir) + 8 + $prefixLen) . $boxID; $boxhdr .= substr($$dataPt, $valuePtr, $prefixLen) if $prefixLen; Write($outfile, $boxhdr, $newdir) or $err = 1; + # write new colr box immediately after ihdr + if ($doColour and $boxID eq 'ihdr') { + # (shouldn't be multiple ihdr boxes, but just in case, write only 1) + $doColour = $doColour==2 ? CreateColorSpec($et, $outfile) : 0; + } } else { # extract as a block if specified $subdirInfo{BlockInfo} = $tagInfo if $$tagInfo{BlockExtract}; @@ -798,6 +1157,68 @@ sub ProcessJpeg2000Box($$$) return 1; } +#------------------------------------------------------------------------------ +# Return bits from a bitstream object +# Inputs: 0) array ref, 1) number of bits +# Returns: specified number of bits as an integer, and shifts input bitstream +sub GetBits($$) +{ + my ($a, $n) = @_; + my $v = 0; + my $bit = 1; + my $i; + while ($n--) { + for ($i=0; $i<@$a; ++$i) { + # consume bits LSB first + my $set = $$a[$i] & 1; + $$a[$i] >>= 1; + if ($i) { + $$a[$i-1] |= 0x80 if $set; + } else { + $v |= $bit if $set; + $bit <<= 1; + } + } + } + return $v; +} + +#------------------------------------------------------------------------------ +# Extract parameters from JPEG XL codestream [unverified!] +# Inputs: 0) ExifTool ref, 1) codestream ref +# Returns: 1 +sub ProcessJXLCodestream($$) +{ + my ($et, $dataPt) = @_; + # add padding if necessary to avoid unpacking past end of data + if (length $$dataPt < 14) { + my $tmp = $$dataPt . ("\0" x 14); + $dataPt = \$tmp; + } + my @a = unpack 'x2C12', $$dataPt; + my ($x, $y); + my $small = GetBits(\@a, 1); + if ($small) { + $y = (GetBits(\@a, 5) + 1) * 8; + } else { + $y = GetBits(\@a, [9, 13, 18, 30]->[GetBits(\@a, 2)]) + 1; + } + my $ratio = GetBits(\@a, 3); + if ($ratio == 0) { + if ($small) { + $x = (GetBits(\@a, 5) + 1) * 8;; + } else { + $x = GetBits(\@a, [9, 13, 18, 30]->[GetBits(\@a, 2)]) + 1; + } + } else { + my $r = [[1,1],[12,10],[4,3],[3,2],[16,9],[5,4],[2,1]]->[$ratio-1]; + $x = int($y * $$r[0] / $$r[1]); + } + $et->FoundTag(ImageWidth => $x); + $et->FoundTag(ImageHeight => $y); + return 1; +} + #------------------------------------------------------------------------------ # Read/write meta information from a JPEG 2000 image # Inputs: 0) ExifTool object reference, 1) dirInfo reference @@ -812,8 +1233,9 @@ sub ProcessJP2($$) # check to be sure this is a valid JPG2000 file return 0 unless $raf->Read($hdr,12) == 12; - unless ($hdr eq "\x00\x00\x00\x0cjP \x0d\x0a\x87\x0a" or # (ref 1) - $hdr eq "\x00\x00\x00\x0cjP\x1a\x1a\x0d\x0a\x87\x0a") # (ref 2) + unless ($hdr eq "\0\0\0\x0cjP \x0d\x0a\x87\x0a" or # (ref 1) + $hdr eq "\0\0\0\x0cjP\x1a\x1a\x0d\x0a\x87\x0a" or # (ref 2) + $$et{IsJXL}) { return 0 unless $hdr =~ /^\xff\x4f\xff\x51\0/; # check for JP2 codestream format if ($outfile) { @@ -830,17 +1252,23 @@ sub ProcessJP2($$) } if ($outfile) { Write($outfile, $hdr) or return -1; - $et->InitWriteDirs(\%jp2Map); + if ($$et{IsJXL}) { + $et->InitWriteDirs(\%jxlMap); + $$et{AddJp2Tags} = { }; # (don't add JP2 tags in JXL files) + } else { + $et->InitWriteDirs(\%jp2Map); + $$et{AddJp2Tags} = $et->GetNewTagInfoHash(\%Image::ExifTool::Jpeg2000::Main); + } # save list of directories to create - my %addDirs = %{$$et{ADD_DIRS}}; + my %addDirs = %{$$et{ADD_DIRS}}; # (make a copy) $$et{AddJp2Dirs} = \%addDirs; - $$et{AddJp2Tags} = $et->GetNewTagInfoHash(\%Image::ExifTool::Jpeg2000::Main); } else { my ($buff, $fileType); # recognize JPX and JPM as unique types of JP2 if ($raf->Read($buff, 12) == 12 and $buff =~ /^.{4}ftyp(.{4})/s) { $fileType = 'JPX' if $1 eq 'jpx '; $fileType = 'JPM' if $1 eq 'jpm '; + $fileType = 'JXL' if $1 eq 'jxl '; } $raf->Seek(-length($buff), 1) if defined $buff; $et->SetFileType($fileType); @@ -855,6 +1283,59 @@ sub ProcessJP2($$) return $et->ProcessDirectory(\%dirInfo, $tagTablePtr); } +#------------------------------------------------------------------------------ +# Read meta information from a JPEG XL image +# Inputs: 0) ExifTool object reference, 1) dirInfo reference +# Returns: 1 on success, 0 if this wasn't a valid JPEG XL file, -1 on write error +sub ProcessJXL($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my $outfile = $$dirInfo{OutFile}; + my ($hdr, $buff); + + return 0 unless $raf->Read($hdr,12) == 12; + if ($hdr eq "\0\0\0\x0cJXL \x0d\x0a\x87\x0a") { + # JPEG XL in ISO BMFF container + $$et{IsJXL} = 1; + } elsif ($hdr =~ /^\xff\x0a/) { + # JPEG XL codestream + if ($outfile) { + if ($$et{OPTIONS}{IgnoreMinorErrors}) { + $et->Warn('Wrapped JXL codestream in ISO BMFF container'); + } else { + $et->Error('Will wrap JXL codestream in ISO BMFF container for writing',1); + return 0; + } + $$et{IsJXL} = 2; + my $buff = "\0\0\0\x0cJXL \x0d\x0a\x87\x0a\0\0\0\x14ftypjxl \0\0\0\0jxl "; + # add metadata to empty ISO BMFF container + $$dirInfo{RAF} = new File::RandomAccess(\$buff); + } else { + $et->SetFileType('JXL Codestream','image/jxl', 'jxl'); + return ProcessJXLCodestream($et, \$hdr); + } + } else { + return 0; + } + $raf->Seek(0,0) or $et->Error('Seek error'), return 0; + + my $success = ProcessJP2($et, $dirInfo); + + if ($outfile and $success > 0 and $$et{IsJXL} == 2) { + # attach the JXL codestream box to the ISO BMFF file + $raf->Seek(0,2) or return -1; + my $size = $raf->Tell(); + $raf->Seek(0,0) or return -1; + SetByteOrder('MM'); + Write($outfile, Set32u($size + 8), 'jxlc') or return -1; + while ($raf->Read($buff, 65536)) { + Write($outfile, $buff) or return -1; + } + } + return $success; +} + 1; # end __END__ @@ -874,7 +1355,7 @@ files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Kodak.pm b/src/Image-ExifTool/lib/Image/ExifTool/Kodak.pm index aa3ef8a2..18c5eb5c 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Kodak.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Kodak.pm @@ -25,7 +25,7 @@ use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; -$VERSION = '1.44'; +$VERSION = '1.47'; sub ProcessKodakIFD($$$); sub ProcessKodakText($$$); @@ -375,6 +375,8 @@ sub WriteKodakIFD($$$); %Image::ExifTool::Kodak::Type5 = ( GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + WRITE_PROC => \&Image::ExifTool::WriteBinaryData, + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, NOTES => q{ These tags are used by the CX4200, CX4210, CX4230, CX4300, CX4310, CX6200 and CX6230. @@ -442,6 +444,8 @@ sub WriteKodakIFD($$$); %Image::ExifTool::Kodak::Type6 = ( GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + WRITE_PROC => \&Image::ExifTool::WriteBinaryData, + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, NOTES => 'These tags are used by the DX3215 and DX3700.', WRITABLE => 1, FIRST_ENTRY => 0, @@ -784,6 +788,8 @@ sub WriteKodakIFD($$$); Name => 'PreviewImageSize', Writable => 'int16u', Count => 2, + PrintConv => '$val =~ tr/ /x/; $val', + PrintConvInv => '$val =~ tr/x/ /; $val', }, # 0x03 int32u - ranges from about 33940 to 40680 # 0x04 int32u - always 18493 @@ -2659,6 +2665,7 @@ my %sceneModeUsed = ( 'Image Number' => 'ImageNumber', 'ISO' => 'ISO', 'ISO Speed' => 'ISO', + 'Lens' => { Name => 'Lens', Priority => 0 }, 'Max Aperture' => { Name => 'MaxAperture', ValueConv => '$val=~s/^f//i; $val', @@ -3003,7 +3010,7 @@ my %sceneModeUsed = ( PROCESS_PROC => \&ProcessPose, NOTES => q{ Streamed orientation information from the PixPro 4KVR360, extracted as - sub-documents when the Duplicates option is used. + sub-documents when the L<Duplicates|../ExifTool.html#Duplicates> option is used. }, Accelerometer => { }, # up, back, left? units of g AngularVelocity => { } # left, up, ccw? units? @@ -3245,7 +3252,7 @@ interpret Kodak maker notes EXIF meta information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/KyoceraRaw.pm b/src/Image-ExifTool/lib/Image/ExifTool/KyoceraRaw.pm index b02fd9f0..f8d3cd7f 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/KyoceraRaw.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/KyoceraRaw.pm @@ -152,7 +152,7 @@ meta information from Kyocera Contax N Digital RAW images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/LIF.pm b/src/Image-ExifTool/lib/Image/ExifTool/LIF.pm new file mode 100644 index 00000000..3065c5cb --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/LIF.pm @@ -0,0 +1,153 @@ +#------------------------------------------------------------------------------ +# File: LIF.pm +# +# Description: Read LIF (Leica Image File) files +# +# Revisions: 2021-06-21 - P. Harvey Created +#------------------------------------------------------------------------------ + +package Image::ExifTool::LIF; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); +use Image::ExifTool::XMP; + +$VERSION = '1.00'; + +%Image::ExifTool::LIF::Main = ( + GROUPS => { 0 => 'XML', 1 => 'XML', 2 => 'Image' }, + PROCESS_PROC => \&Image::ExifTool::XMP::ProcessXMP, + VARS => { NO_ID => 1 }, + NOTES => q{ + Tags extracted from Leica Image Format (LIF) imaging files. As well as the + tags listed below, all available information is extracted from the + XML-format metadata in the LIF header. + }, + TimeStampList => { + Groups => { 2 => 'Time' }, + ValueConv => q{ + my $unixTimeZero = 134774 * 24 * 3600; + my @vals = split ' ', $val; + foreach (@vals) { + $_ = 1e-7 * hex($_); + # shift from Jan 1, 1601 to Jan 1, 1970 + $_ = Image::ExifTool::ConvertUnixTime($_ - $unixTimeZero); + } + return \@vals; + }, + }, +); + +#------------------------------------------------------------------------------ +# Shorten obscenely long LIF tag names +# Inputs: Tag name +# Returns: Shortened tag name +sub ShortenTagNames($) +{ + local $_; + $_ = shift; + s/DescriptionDimensionsDimensionDescription/Dimensions/; + s/DescriptionChannelsChannelDescription/Channel/; + s/ShutterListShutter/Shutter/; + s/SettingDefinition/Setting/; + s/AdditionalZPositionListAdditionalZPosition/AdditionalZPosition/; + s/LMSDataContainerHeader//g; + s/FilterWheelWheel/FilterWheel/; + s/FilterWheelFilter/FilterWheel/; + s/DetectorListDetector/Detector/; + s/OnlineDyeSeparationOnlineDyeSeparation/OnlineDyeSeparation/; + s/AotfListAotf/Aotf/; + s/SettingAotfLaserLineSetting/SettingAotfLaser/; + s/DataROISetROISet/DataROISet/; + s/AdditionalZPosition/AddZPos/; + s/FRAPplusBlock_FRAPBlock_FRAP_PrePost_Info/FRAP_/; + s/FRAPplusBlock_FRAPBlock_FRAP_(Master)?/FRAP_/; + s/LDM_Block_SequentialLDM_Block_Sequential_/LDM_/; + s/ATLConfocalSetting/ATLConfocal/; + s/LaserArrayLaser/Laser/; + s/LDM_Master/LDM_/; + s/(List)?ATLConfocal/ATL_/; + s/Separation/Sep/; + s/BleachPointsElement/BleachPoint/; + s/BeamPositionBeamPosition/BeamPosition/; + s/DataROISetPossible(ROI)?/DataROISet/; + s/RoiElementChildrenElementDataROISingle(Roi)?/Roi/; + s/InfoLaserLineSettingArrayLaserLineSetting/LastLineSetting/; + s/FilterWheelWheelNameFilterName/FilterWheelFilterName/; + s/LUT_ListLut/Lut/; + s/ROI_ListRoiRoidata/ROI_/; + s/LaserLineSettingArrayLaserLineSetting/LaserLineSetting/; + return $_; +} + +#------------------------------------------------------------------------------ +# Extract metadata from a LIF image +# Inputs: 0) ExifTool object reference, 1) dirInfo reference +# Returns: 1 on success, 0 if this wasn't a valid LIF file +sub ProcessLIF($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my $buff; + + # verify this is a valid LIF file + return 0 unless $raf->Read($buff, 15) == 15 and $buff =~ /^\x70\0{3}.{4}\x2a.{4}<\0/s; + + $et->SetFileType(); + SetByteOrder('II'); + + my $size = Get32u(\$buff, 4); # XML chunk size + my $len = Get32u(\$buff, 9) * 2; # XML data length + + $size < $len and $et->Error('Corrupted LIF XML block'), return 1; + $size > 100000000 and $et->Error('LIF XML block too large'), return 1; + + $raf->Seek(-2, 1) and $raf->Read($buff, $len) == $len or $et->Error('Truncated LIF XML block'), return 1; + + my $tagTablePtr = GetTagTable('Image::ExifTool::LIF::Main'); + + # convert from UCS2 to UTF8 + my $xml = Image::ExifTool::Decode($et, $buff, 'UCS2', 'II', 'UTF8'); + + my %dirInfo = ( DataPt => \$xml ); + + $$et{XmpIgnoreProps} = [ 'LMSDataContainerHeader', 'Element', 'Children', 'Data', 'Image', 'Attachment' ]; + $$et{ShortenXmpTags} = \&ShortenTagNames; + + $et->ProcessDirectory(\%dirInfo, $tagTablePtr); + + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::LIF - Read LIF meta information + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to read +metadata from Leica Image File (LIF) images. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/LIF Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/LNK.pm b/src/Image-ExifTool/lib/Image/ExifTool/LNK.pm index 2ddd497a..f66496a9 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/LNK.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/LNK.pm @@ -15,7 +15,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.07'; +$VERSION = '1.08'; sub ProcessItemID($$$); sub ProcessLinkInfo($$$); @@ -273,7 +273,9 @@ sub ProcessLinkInfo($$$); 6 => 'Ram Disk', }, }, - DriveSerialNumber => { }, + DriveSerialNumber => { + PrintConv => 'join("-", unpack("A4 A4", sprintf("%08X", $val)))', + }, VolumeLabel => { }, LocalBasePath => { }, CommonNetworkRelLink => { }, @@ -508,6 +510,7 @@ sub ProcessLinkInfo($$$) if ($off + 0x20 <= $dataLen) { # my $len = Get32u($dataPt, $off); $et->HandleTag($tagTablePtr, 'DriveType', undef, %opts, Start=>$off+4); + $et->HandleTag($tagTablePtr, 'DriveSerialNumber', undef, %opts, Start=>$off+8); $pos = Get32u($dataPt, $off + 0x0c); if ($pos == 0x14) { # use VolumeLabelOffsetUnicode instead @@ -699,7 +702,7 @@ information MS Shell Link (Windows shortcut) files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/cs.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/cs.pm index 7546dc9f..56fc3d1f 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/cs.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/cs.pm @@ -1570,7 +1570,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/de.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/de.pm index d6d434fb..d5f89f96 100755 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/de.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/de.pm @@ -11,7 +11,7 @@ package Image::ExifTool::Lang::de; use strict; use vars qw($VERSION); -$VERSION = '1.33'; +$VERSION = '1.36'; %Image::ExifTool::Lang::de::Translate = ( 'AEAperture' => 'AE-Blende', @@ -693,6 +693,7 @@ $VERSION = '1.33'; 'AFPointsInFocus' => { Description => 'AF-Punkte im Fokus', PrintConv => { + '(none)' => '(Keine)', 'All' => 'Alle', 'All 11 Points' => 'Alle 11 Punkte', 'Bottom' => 'Unten', @@ -992,7 +993,9 @@ $VERSION = '1.33'; }, }, 'AdvancedSceneMode' => { + Description => 'Erweiteter Szenenmodus', PrintConv => { + 'Off' => 'Aus', 'Creative Macro' => 'Makro kreativ', 'Flower' => 'Blumen', 'HDR B&W' => 'HDR Schwarz-Weiß', @@ -1182,6 +1185,7 @@ $VERSION = '1.33'; 'No flash & flash' => 'Kein Blitz & Blitz', 'Off' => 'Aus', 'On' => 'Ein', + 'Pre-shot' => 'Vorauslösung', 'WB' => 'Weißabgleich', 'WB2' => 'Weißabgleich 2', }, @@ -1675,7 +1679,7 @@ $VERSION = '1.33'; }, 'CanonImageType' => 'Canon-Bildtyp', 'CanonImageWidth' => 'Canon-Bildbreite', - 'CanonModelID' => 'Canon-Modell', + 'CanonModelID' => 'Canon-Modell ID', 'Caption' => 'Bildtext', 'Caption-Abstract' => 'Beschreibung/Zusammenfassung', 'CaptionWriter' => 'Bildtextautor', @@ -1700,7 +1704,7 @@ $VERSION = '1.33'; }, 'Category' => 'Kategorie', 'CenterAFArea' => { - Description => 'AF-Messfeldgröße', + Description => 'AF-Messfeld Mitte', PrintConv => { 'Normal Zone' => 'Normal', 'Wide Zone' => 'Groß', @@ -1714,7 +1718,7 @@ $VERSION = '1.33'; }, }, 'CenterWeightedAreaSize' => { - Description => 'Messfeldgröße', + Description => 'Messfeldgröße Mitte', PrintConv => { 'Average' => 'Durchschnitt', }, @@ -1789,9 +1793,9 @@ $VERSION = '1.33'; 'On' => 'Ein', }, }, - 'ColorAdjustment' => 'Farbkorrektur', + 'ColorAdjustment' => 'Farbeinstellung', 'ColorAdjustmentMode' => { - Description => 'Farbtonkorrektur Modus', + Description => 'Farbeinstellung Modus', PrintConv => { 'Off' => 'Aus', 'On' => 'Ein', @@ -1808,9 +1812,10 @@ $VERSION = '1.33'; 'On' => 'Ein', }, }, - 'ColorBalanceBlue' => 'Farbbalance Blau', - 'ColorBalanceGreen' => 'Farbbalance Grün', - 'ColorBalanceRed' => 'Farbbalance Rot', + 'ColorBalanceBlue' => 'Farbabgleich Blau', + 'ColorBalanceGreen' => 'Farbabgleich Grün', + 'ColorBalanceRed' => 'Farbangleich Rot', + 'ColorBalanceVersion' => 'Farbabgleich Version', 'ColorBitDepth' => 'Farbtiefe', 'ColorBoostType' => { PrintConv => { @@ -3209,7 +3214,8 @@ $VERSION = '1.33'; 'Night View/Portrait' => 'Abendszene/Porträt', 'Pet' => 'Haustiere', 'Portrait' => 'Porträt', - 'Program' => 'Programm', + 'Program' => 'Programmautomatik', + 'Program AE' => 'Programmautomatik', 'Program-shift' => 'Programm-Shift', 'Program-shift A' => 'Programmverschiebung A', 'Program-shift S' => 'Programmverschiebung S', @@ -3249,8 +3255,8 @@ $VERSION = '1.33'; 'Night view/portrait' => 'Abendszene/Porträt', 'Not Defined' => 'Nicht definiert', 'Portrait' => 'Porträt', - 'Program' => 'Programm', - 'Program AE' => 'Normal-Programm', + 'Program' => 'Programmautomatik', + 'Program AE' => 'Programmautomatik', 'Shutter Priority' => 'Verschlusspriorität', 'Shutter speed priority AE' => 'Verschlusspriorität', 'Sports' => 'Sport', @@ -3531,6 +3537,7 @@ $VERSION = '1.33'; 'F1/Studio Portrait' => 'F1/Studio-Porträt', 'F1a/Studio Portrait Enhanced Saturation' => 'F1a/Studio-Porträt Erweiterte Sättigung', 'F1b/Studio Portrait Smooth Skin Tone (ASTIA)' => 'F1b/Studio-Porträt Weiche Hauttöne', + 'F1b/Studio Portrait Smooth Skin Tone (Astia)' => 'F1b/Studio-Porträt Weiche Hauttöne', 'F1c/Studio Portrait Increased Sharpness' => 'F1c/Studio-Porträt Erhöhte Schärfe', 'F3/Studio Portrait Ex' => 'F3/Studio Porträt Ex', 'n/a' => '(nicht gesetzt)', @@ -3643,9 +3650,9 @@ $VERSION = '1.33'; 'On' => 'Ein', }, }, - 'FineTuneOptCenterWeighted' => 'Feinabst. der Bel.Messung Mittenbetonte Messung', - 'FineTuneOptMatrixMetering' => 'Feinabst. der Bel.Messung Matrixmessung', - 'FineTuneOptSpotMetering' => 'Feinabst. der Bel.Messung Spotmessung', + 'FineTuneOptCenterWeighted' => 'Feinabstimmung Mittenbetonte Messung', + 'FineTuneOptMatrixMetering' => 'Feinabstimmung Matrixmessung', + 'FineTuneOptSpotMetering' => 'Feinabstimmung Spotmessung', 'FirmwareRevision' => 'Firmware-Revision', 'FirmwareRevision2' => 'Firmware-Revision 2', 'FirmwareVersion' => 'Firmware-Version', @@ -5479,6 +5486,7 @@ $VERSION = '1.33'; 'ManufactureDate' => 'Herstellungsdatum', 'Marked' => 'Markiert', 'MasterDocumentID' => 'ID des Originaldokuments', + 'MatrixMetering' => 'Mehrfeldmessung', 'MaxAperture' => 'Größte Blende', 'MaxApertureAtCurrentFocal' => 'Größte Blende bei aktueller Brennweite', 'MaxApertureAtMaxFocal' => 'Größte Blende bei größter Brennweite', @@ -5505,6 +5513,7 @@ $VERSION = '1.33'; 'MeasurementObserver' => 'Messung nach', 'MediaBlackPoint' => 'Medium-Schwarzpunkt', 'MediaWhitePoint' => 'Medium-Weißpunkt', + 'Medium' => 'Mittelgroß', 'MenuButtonDisplayPosition' => { Description => 'Positionsanzeige Menuetaste', PrintConv => { @@ -5526,7 +5535,7 @@ $VERSION = '1.33'; Description => 'Belichtungsmessung', PrintConv => { 'Center-weighted' => 'Mittenbetont', - 'Matrix' => 'Matrixmessung', + 'Matrix' => 'Mehrfeldmessung', 'Spot' => 'Spotmessung', }, }, @@ -5590,7 +5599,7 @@ $VERSION = '1.33'; }, }, 'MinoltaMakerNote' => 'Minolta-Herstellerinformationen', - 'MinoltaModelID' => 'Minolta-Modell', + 'MinoltaModelID' => 'Minolta-Modell ID', 'MinoltaQuality' => { Description => 'Minolta-Bildqualität', PrintConv => { @@ -5620,6 +5629,7 @@ $VERSION = '1.33'; }, 'Model' => 'Kameramodell', 'Model2' => 'Kameramodell (2)', + 'ModelID' => 'Modell ID', 'ModelingFlash' => { Description => 'Einstelllicht', PrintConv => { @@ -6119,7 +6129,7 @@ $VERSION = '1.33'; 'Full' => 'Voll', }, }, - 'PentaxModelID' => 'Pentax-Modell', + 'PentaxModelID' => 'Pentax-Modell ID', 'PentaxVersion' => 'Pentax-Version', 'People' => 'Menschen', 'Permits' => { @@ -6296,7 +6306,7 @@ $VERSION = '1.33'; 'Pink' => 'Rosa', 'Portrait' => 'Porträt', 'Portrait 2' => 'Porträt 2', - 'Program' => 'Programm', + 'Program' => 'Programmautomatik', 'Program (HyP)' => 'Programmautomatik (Hyper-Programm)', 'Program AE' => 'Programmautomatik', 'Program Av Shift' => 'Av Shift-Belichtungsprogramm', @@ -6584,7 +6594,7 @@ $VERSION = '1.33'; 'Province-State' => 'Bundesland/Kanton', 'Publisher' => 'Herausgeber', 'Quality' => { - Description => 'Bildqualität', + Description => 'Qualität', PrintConv => { 'Best' => 'Optimal', 'Better' => 'Besser', @@ -6602,6 +6612,7 @@ $VERSION = '1.33'; 'n/a' => '(nicht gesetzt)', }, }, + 'Quality2' => 'Qualität 2', 'QualityMode' => { PrintConv => { 'Fine' => 'Fein', @@ -7119,7 +7130,7 @@ $VERSION = '1.33'; 'Off' => 'Aus', 'Pet' => 'Haustiere', 'Portrait' => 'Porträt', - 'Program' => 'Programm', + 'Program' => 'Programmautomatik', 'Self Portrait' => 'Selbstporträt', 'Self Portrait+Self Timer' => 'Selbstporträt+Selbstauslöser', 'Shutter Priority' => 'Verschlusspriorität', @@ -7151,7 +7162,7 @@ $VERSION = '1.33'; 'Night Landscape' => 'Landschaft bei Nacht', 'Night Portrait' => 'Nachtporträt', 'Portrait' => 'Porträt', - 'Program' => 'Programm', + 'Program' => 'Programmautomatik', 'Shutter Priority' => 'Verschlusspriorität', 'Snow' => 'Schnee', 'Sunset' => 'Sonnenuntergang', @@ -7494,7 +7505,7 @@ $VERSION = '1.33'; 'Night Scenery' => 'Nachtszene', 'Pet' => 'Haustiere', 'Portrait' => 'Porträt', - 'Program' => 'Programm', + 'Program' => 'Programmautomatik', 'Self Portrait' => 'Selbstportait', 'Shutter Priority' => 'Verschlusspriorität', 'Snow' => 'Schnee', @@ -7704,7 +7715,7 @@ $VERSION = '1.33'; Description => 'Unterdatei-Typ', PrintConv => { 'Alternate reduced-resolution image' => 'Alternatives Bild in reduzierter Auflösung', - 'Full-resolution Image' => 'Bild in voller Auflösung', + 'Full-resolution image' => 'Bild in voller Auflösung', 'Reduced-resolution image' => 'Bild in reduzierter Auflösung', 'Single page of multi-page image' => 'Einzelbild eines mehrseitigen Bildes', 'Single page of multi-page reduced-resolution image' => 'Einzelbild eines mehrseitigen Bildes in reduzierter Auflösung', @@ -8691,14 +8702,15 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 ACKNOWLEDGEMENTS -Thanks to Jens Duttke and Herbert Kauer for providing this translation. +Thanks to Jens Duttke, Herbert Kauer and Jobi for providing this +translation. =head1 SEE ALSO diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/en_ca.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/en_ca.pm index 6e3dbb6c..ce4bb91b 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/en_ca.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/en_ca.pm @@ -989,7 +989,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/en_gb.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/en_gb.pm index 6b07082b..f3674407 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/en_gb.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/en_gb.pm @@ -1032,7 +1032,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/es.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/es.pm index 7c57959b..10641b14 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/es.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/es.pm @@ -11,7 +11,7 @@ package Image::ExifTool::Lang::es; use strict; use vars qw($VERSION); -$VERSION = '1.15'; +$VERSION = '1.16'; %Image::ExifTool::Lang::es::Translate = ( 'AEAperture' => 'Aperture AE', @@ -176,6 +176,7 @@ $VERSION = '1.15'; 'ActionAdvised' => { Description => 'Acción Aconsejada', PrintConv => { + 'Object Append' => 'Añadir Objeto', 'Object Kill' => 'Destruir Objecto', 'Object Reference' => 'Referencia Objecto', 'Object Replace' => 'Reemplazar Objecto', @@ -870,6 +871,7 @@ $VERSION = '1.15'; }, }, 'ContrastSetting' => 'Ajustes de Contraste', + 'Copyright' => 'Copyright Perfil', 'CopyrightNotice' => 'Aviso Copyright', 'Country' => 'País', 'Country-PrimaryLocationCode' => 'Código País ISO', @@ -1300,7 +1302,7 @@ $VERSION = '1.15'; 'ExifImageHeight' => 'Alto Imagen', 'ExifImageWidth' => 'Ancho Imagen', 'ExifOffset' => 'Puntero Exif IFD', - 'ExifToolVersion' => 'Versión Exiftool', + 'ExifToolVersion' => 'Versión ExifTool', 'ExifVersion' => 'Versión Exif', 'ExpandFilm' => 'Película Expandida', 'ExpandFilterLens' => 'Filtro Objetivo Expandida', @@ -4003,7 +4005,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/fi.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/fi.pm index 0ef21068..5a35b1cb 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/fi.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/fi.pm @@ -11,7 +11,7 @@ package Image::ExifTool::Lang::fi; use strict; use vars qw($VERSION); -$VERSION = '1.02'; +$VERSION = '1.04'; %Image::ExifTool::Lang::fi::Translate = ( 'AEAperture' => 'AE-aukko', @@ -147,6 +147,7 @@ $VERSION = '1.02'; 'ActionAdvised' => { Description => 'Suositettava toiminto', PrintConv => { + 'Object Append' => 'Objektiliitäntä', 'Object Kill' => 'Objektin tuhonta', 'Object Reference' => 'Objektiviite', 'Object Replace' => 'Objektin korvaus', @@ -238,6 +239,7 @@ $VERSION = '1.02'; 'On' => 'Päällä', }, }, + 'AutoBracketingSet' => 'Haarukointisarja', 'AutoDistortionControl' => 'Automaattinen vääristymäkorjaus', 'AutoExposureBracketing' => 'Automaattinen valotuksen haarukointi', 'AutoFP' => 'Automaattinen FP', @@ -335,6 +337,7 @@ $VERSION = '1.02'; 'BurstMode' => { Description => 'Sarjatapa', PrintConv => { + 'Auto Exposure Bracketing (AEB)' => 'Ääretön', 'Infinite' => 'Ääretön', 'Off' => 'Pois', 'On' => 'Matala/korkea laatu', @@ -442,6 +445,7 @@ $VERSION = '1.02'; 'ColorBalanceBlue' => 'Väritasapaino sininen', 'ColorBalanceGreen' => 'Väritasapaino vihreä', 'ColorBalanceRed' => 'Väritasapaino punainen', + 'ColorBalanceVersion' => 'Väritasapainon versio', 'ColorBoostData' => 'Väritehostusdata', 'ColorBoostLevel' => 'Väritehostustaso', 'ColorBoostType' => 'Väritehostustyyppi', @@ -508,6 +512,7 @@ $VERSION = '1.02'; }, }, 'ColorMoireReduction' => 'Värimoareen vaimennus', + 'ColorMoireReductionMode' => 'Värimoareen vaimennustapa', 'ColorPalette' => 'Väripaletti', 'ColorProfile' => 'Väriprofiili', 'ColorRepresentation' => 'Väriesitys', @@ -665,6 +670,7 @@ $VERSION = '1.02'; 'DefaultCropOrigin' => 'Oletusrajauksen alkuperä', 'DefaultCropSize' => 'Oletusrajauskoko', 'DefaultScale' => 'Oletusasteikko', + 'DelayTime' => 'Viiveaika', 'DeletedImageCount' => 'Poistettujen kuvien määrä', 'Description' => 'Deskriptio', 'Destination' => 'Kohde', @@ -923,6 +929,7 @@ $VERSION = '1.02'; 'FileIndex' => 'Tiedostoindeksi', 'FileInfo' => 'Tiedostoinfot', 'FileInfoVersion' => 'Tiedostoinfojen versio', + 'FileName' => 'Tiedostonimi', 'FileNumber' => 'Tiedoston numero', 'FileNumberMemory' => 'Tiedostonumeromuisti', 'FileNumberSequence' => 'Tiedostojen numerojärjestys', @@ -946,9 +953,11 @@ $VERSION = '1.02'; 'Dynamic (B&W)' => 'Dynaaminen (M&V)', 'Dynamic (color)' => 'Dynaaminen (väri)', 'F0/Standard (PROVIA)' => 'F0/vakio', + 'F0/Standard (Provia)' => 'F0/vakio', 'F1/Studio Portrait' => 'F1/studiomuotokuva', 'F1a/Studio Portrait Enhanced Saturation' => 'F1a/studiomuotokuva laajennettu värikylläisyys', 'F1b/Studio Portrait Smooth Skin Tone (ASTIA)' => 'F1b/studiomuotokuva pehmeä ihonväri', + 'F1b/Studio Portrait Smooth Skin Tone (Astia)' => 'F1b/studiomuotokuva pehmeä ihonväri', 'F1c/Studio Portrait Increased Sharpness' => 'F1c/studiomuotokuva lisätty terävyys', 'F3/Studio Portrait Ex' => 'F3/studiomuotokuva Ex', 'Nature (color)' => 'Luonnollinen (väri)', @@ -1013,6 +1022,7 @@ $VERSION = '1.02'; 'FlashEnergy' => 'Salaman teho', 'FlashExposureBracketValue' => 'Salamavalotuksen haarukoinnin arvo', 'FlashExposureComp' => 'Salaman kirkkauden säätö', + 'FlashExposureComp2' => 'Salaman kirkkauden säätö 2', 'FlashFired' => { Description => 'Salama lauennut', PrintConv => { @@ -1105,6 +1115,7 @@ $VERSION = '1.02'; 'FocusArea' => 'Tarkennusalue', 'FocusAreaSelection' => 'Tarkennusalueen valinta', 'FocusContinuous' => 'Jatkuva tarkennus', + 'FocusDistance' => 'Tarkennusetäisyys', 'FocusDistanceLower' => 'Lähitarkennus', 'FocusDistanceUpper' => 'Kaukotarkennus', 'FocusMode' => { @@ -1605,6 +1616,7 @@ $VERSION = '1.02'; 'MaskedAreas' => 'Maskilliset alueet', 'MasterDocumentID' => 'Alkuperäisdokumentin ID', 'MasterGain' => 'Yleisvahvistus', + 'MatrixMetering' => 'Matriisimittaus', 'Matteing' => 'Mattaus', 'MaxAperture' => 'Suurin aukko', 'MaxApertureAtCurrentFocal' => 'Suurin aukko nykyisellä polttovälillä', @@ -1662,6 +1674,7 @@ $VERSION = '1.02'; 'Model' => 'Malli', 'Model2' => 'Kuvasyötelaitteen malli (2)', 'ModelAndVersion' => 'Malli ja versio', + 'ModelID' => 'Mallin ID', 'ModelTiePoint' => 'Sidospistemalli-tagi', 'ModelTransform' => 'Muuntomalli-tagi', 'ModelingFlash' => 'Mallinnussalama', @@ -2021,6 +2034,7 @@ $VERSION = '1.02'; 'n/a' => 'Ei asetettu', }, }, + 'Quality2' => 'Laatu 2', 'QualityMode' => { Description => 'Kuvalaatu', PrintConv => { @@ -2153,7 +2167,13 @@ $VERSION = '1.02'; }, }, 'ResolutionMode' => 'Resoluutiomuoto', - 'ResolutionUnit' => 'X- ja Y-resoluution yksikkö', + 'ResolutionUnit' => { + Description => 'X- ja Y-resoluution yksikkö', + PrintConv => { + 'None' => 'Ei mitään', + 'inches' => 'Tuuma', + }, + }, 'RetouchHistory' => 'Korjailuhistoria', 'ReverseIndicators' => 'Käänteiset ilmaisimet', 'RevisionNumber' => 'Revision numero', @@ -2218,6 +2238,10 @@ $VERSION = '1.02'; 'Saturation' => { Description => 'Värikylläisyys', PrintConv => { + '+1 (medium high)' => 'Korkeahko', + '+2 (high)' => 'Korkea', + '-1 (medium low)' => 'Matalahko', + '0 (normal)' => 'Vakio', 'Film Simulation' => 'Filminsimulaatio', 'High' => 'Korkea', 'Low' => 'Matala', @@ -2422,6 +2446,13 @@ $VERSION = '1.02'; 'Sharpness' => { Description => 'Terävyys', PrintConv => { + '+1 (medium hard)' => 'Kovahko', + '+2 (hard)' => 'Kova', + '+3 (very hard)' => 'Kova 2', + '-1 (medium soft)' => 'Pehmeähkö', + '-2 (soft)' => 'Pehmeä 2', + '-3 (very soft)' => 'Pehmeä', + '0 (normal)' => 'Vakio', 'Film Simulation' => 'Filminsimulaatio', 'Hard' => 'Kova', 'Hard2' => 'Kova 2', @@ -2473,6 +2504,7 @@ $VERSION = '1.02'; 'SpecialInstructions' => 'Ohjeet', 'SpecialMode' => 'Erikoistapa', 'SpectralSensitivity' => 'Spektraalinen herkkyys', + 'Sport' => 'Urheilu', 'SpotFocusPointX' => 'Pistetarkennuksen piste X', 'SpotFocusPointY' => 'Pistetarkennuksen piste Y', 'SpotMeteringMode' => 'Pistemittaustapa', @@ -2743,6 +2775,10 @@ $VERSION = '1.02'; 'Custom WB 4' => 'Mukautettu valkotasapaino 4', 'Custom WB 5400K' => 'Mukautettu valkotasapaino 5400 K', 'Custom WB 8000K' => 'Mukautettu valkotasapaino 8000 K', + 'One Touch WB 1' => 'Mukautettu valkotasapaino 1', + 'One Touch WB 2' => 'Mukautettu valkotasapaino 2', + 'One Touch WB 3' => 'Mukautettu valkotasapaino 3', + 'One Touch WB 4' => 'Mukautettu valkotasapaino 4', }, }, 'WhiteBalanceAdj' => 'Väritasapainon säätö', @@ -2801,7 +2837,13 @@ $VERSION = '1.02'; 'XPosition' => 'X-sijainti', 'XResolution' => 'Kuvan vaakaresoluutio', 'YCbCrCoefficients' => 'Väriavaruuden muunnon matriisikertoimet', - 'YCbCrPositioning' => 'Y:n ja C:n sijoitus', + 'YCbCrPositioning' => { + Description => 'Y:n ja C:n sijoitus', + PrintConv => { + 'Centered' => 'Keskitetty', + 'Co-sited' => 'Vierekkäin', + }, + }, 'YCbCrSubSampling' => 'Suhteen Y - C subsamplaus', 'YClipPathUnits' => 'Y-leikepolkuyksiköt', 'YPosition' => 'Y-sijainti', @@ -2836,7 +2878,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/fr.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/fr.pm index 6deeada7..12d1124b 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/fr.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/fr.pm @@ -11,7 +11,7 @@ package Image::ExifTool::Lang::fr; use strict; use vars qw($VERSION); -$VERSION = '1.32'; +$VERSION = '1.34'; %Image::ExifTool::Lang::fr::Translate = ( 'AEAperture' => 'Ouverture AE', @@ -372,6 +372,7 @@ $VERSION = '1.32'; 'ActionAdvised' => { Description => 'Action conseillée', PrintConv => { + 'Object Append' => 'Ajout d\'objet', 'Object Kill' => 'Destruction d\'objet', 'Object Reference' => 'Référence d\'objet', 'Object Replace' => 'Remplacement d\'objet', @@ -903,6 +904,7 @@ $VERSION = '1.32'; 'On' => 'Activé', }, }, + 'ColorBalanceVersion' => 'Version de la Balance des couleurs', 'ColorBooster' => { PrintConv => { 'Off' => 'Désactivé', @@ -4749,7 +4751,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/it.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/it.pm index e7026836..6d40317b 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/it.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/it.pm @@ -11,7 +11,7 @@ package Image::ExifTool::Lang::it; use strict; use vars qw($VERSION); -$VERSION = '1.13'; +$VERSION = '1.14'; %Image::ExifTool::Lang::it::Translate = ( 'A100DataOffset' => 'Offset dati A100', @@ -1249,6 +1249,7 @@ $VERSION = '1.13'; 'Off' => 'Spento', }, }, + 'ColorBalanceVersion' => 'Versione Bilanciamento Colore', 'ColorBooster' => { PrintConv => { 'Off' => 'Spento', @@ -2394,6 +2395,7 @@ $VERSION = '1.13'; PrintConv => { 'Aperture Priority' => 'Priorità diaframma', 'Aperture-priority AE' => 'Priorità diaframma', + 'Auto' => 'Esposizione automatica', 'Auto bracket' => 'A forcella automatica', 'Fireworks' => 'Fuochi artificiali', 'Landscape' => 'Orizzontale', @@ -4846,6 +4848,7 @@ $VERSION = '1.13'; }, }, 'ObjectTypeReference' => 'Riferimento Tipo Oggetto', + 'OffsetSchema' => 'Schema Offset', 'OldSubfileType' => { Description => 'Vecchio tipo sotto-file', PrintConv => { @@ -7057,7 +7060,7 @@ $VERSION = '1.13'; 'SubfileType' => { Description => 'Tipo sotto-file', PrintConv => { - 'Full-resolution Image' => 'Immagine con risoluzione originale', + 'Full-resolution image' => 'Immagine con risoluzione originale', 'Reduced-resolution image' => 'Immagine a risoluzione ridotta', 'Single page of multi-page image' => 'Singola pagina di un\'immagine multi-pagina', 'Single page of multi-page reduced-resolution image' => 'Singola pagina di un\'immagine multi-pagina a risoluzione ridotta', @@ -7711,9 +7714,9 @@ $VERSION = '1.13'; }, 'WBAdjLighting' => { PrintConv => { + 'Daylight (cloudy)' => 'Luce del giorno (2)', 'Daylight (direct sunlight)' => 'Luce del giorno (0)', 'Daylight (shade)' => 'Luce del giorno (1)', - 'Daylight (cloudy)' => 'Luce del giorno (2)', 'None' => 'Nessuno', }, }, @@ -7900,7 +7903,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/ja.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/ja.pm index 574fd6d4..9fb7d631 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/ja.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/ja.pm @@ -11,7 +11,7 @@ package Image::ExifTool::Lang::ja; use strict; use vars qw($VERSION); -$VERSION = '1.23'; +$VERSION = '1.25'; %Image::ExifTool::Lang::ja::Translate = ( 'AEAperture' => 'AE絞り', @@ -633,6 +633,7 @@ $VERSION = '1.23'; 'On' => 'オン', }, }, + 'AutoBracketingSet' => 'オートブラケット設定', 'AutoExposureBracketing' => { Description => 'フラッシュãƒã‚¤ã‚¢ã‚¹', PrintConv => { @@ -820,6 +821,7 @@ $VERSION = '1.23'; 'BurstMode' => { Description => 'ブラストモード', PrintConv => { + 'Auto Exposure Bracketing (AEB)' => 'ç„¡é™', 'Infinite' => 'ç„¡é™', 'Off' => 'オフ', 'On' => 'オン', @@ -2190,6 +2192,7 @@ $VERSION = '1.23'; 'FlashEnergy' => 'フラッシュ強度', 'FlashExposureBracketValue' => 'フラッシュ露出ブラケット値', 'FlashExposureComp' => 'フラッシュ露出補正', + 'FlashExposureComp2' => 'フラッシュ露出補正', 'FlashExposureCompSet' => 'ストロボ露出補正設定', 'FlashExposureLock' => { PrintConv => { @@ -3352,6 +3355,7 @@ $VERSION = '1.23'; 'MaskedAreas' => 'マスク領域', 'MasterDocumentID' => 'マスタ文書ID', 'MasterGain' => 'マスターゲイン', + 'MatrixMetering' => '分割測光', 'Matteing' => 'マッãƒãƒ³ã‚°', 'MaxAperture' => '最大絞り', 'MaxApertureAtCurrentFocal' => 'ç¾åœ¨ç„¦ç‚¹è·é›¢ã®æœ€å¤§çµžã‚Š', @@ -3472,6 +3476,7 @@ $VERSION = '1.23'; }, 'Model' => 'ç”»åƒå…¥åŠ›æ©Ÿå™¨ãƒ¢ãƒ‡ãƒ«', 'Model2' => 'ç”»åƒå…¥åŠ›æ©Ÿå™¨ãƒ¢ãƒ‡ãƒ«(2)', + 'ModelID' => 'モデルID', 'ModelTiePoint' => 'モデル拘æŸãƒã‚¤ãƒ³ãƒˆã‚¿ã‚°', 'ModelTransform' => 'モデル変化タグ', 'ModelingFlash' => { @@ -4215,6 +4220,7 @@ $VERSION = '1.23'; 'n/a' => '未設定', }, }, + 'Quality2' => 'å“質', 'QualityMode' => { Description => 'å“質モード', PrintConv => { @@ -4877,7 +4883,8 @@ $VERSION = '1.23'; 'Soft2' => 'ソフト2', 'n/a' => '該当無ã—', }, - }, 'SharpnessFactor' => 'シャープãƒã‚¹è¦å› ', + }, + 'SharpnessFactor' => 'シャープãƒã‚¹è¦å› ', 'SharpnessFaithful' => 'シャープãƒã‚¹å¿ å®Ÿè¨­å®š', 'SharpnessFrequency' => { PrintConv => { @@ -5061,6 +5068,7 @@ $VERSION = '1.23'; 'SpecialInstructions' => '手順', 'SpecialMode' => 'スペシャルモード', 'SpectralSensitivity' => 'スペクトル感度', + 'Sport' => 'スãƒãƒ¼ãƒ„', 'SpotFocusPointX' => 'スãƒãƒƒãƒˆãƒ•ã‚©ãƒ¼ã‚«ã‚¹ãƒã‚¤ãƒ³ãƒˆX', 'SpotFocusPointY' => 'スãƒãƒƒãƒˆãƒ•ã‚©ãƒ¼ã‚«ã‚¹ãƒã‚¤ãƒ³ãƒˆY', 'SpotMeterLinkToAFPoint' => { @@ -5693,6 +5701,10 @@ $VERSION = '1.23'; 'Custom WB 4' => 'カスタムホワイトãƒãƒ©ãƒ³ã‚¹4', 'Custom WB 5400K' => 'カスタムホワイトãƒãƒ©ãƒ³ã‚¹5400K', 'Custom WB 8000K' => 'カスタムホワイトãƒãƒ©ãƒ³ã‚¹8000K', + 'One Touch WB 1' => 'カスタムホワイトãƒãƒ©ãƒ³ã‚¹1', + 'One Touch WB 2' => 'カスタムホワイトãƒãƒ©ãƒ³ã‚¹2', + 'One Touch WB 3' => 'カスタムホワイトãƒãƒ©ãƒ³ã‚¹3', + 'One Touch WB 4' => 'カスタムホワイトãƒãƒ©ãƒ³ã‚¹4', }, }, 'WhiteBalanceAdj' => { @@ -5829,7 +5841,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/ko.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/ko.pm index f4ec5d01..e53aca7e 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/ko.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/ko.pm @@ -11,7 +11,7 @@ package Image::ExifTool::Lang::ko; use strict; use vars qw($VERSION); -$VERSION = '1.06'; +$VERSION = '1.07'; %Image::ExifTool::Lang::ko::Translate = ( 'AELock' => { @@ -256,6 +256,7 @@ $VERSION = '1.06'; 'Off' => '꺼ì§', }, }, + 'AutoBracketingSet' => 'ìžë™ 브ë¼ì¼€íŒ… 설정', 'AutoExposureBracketing' => { PrintConv => { 'Off' => '꺼ì§', @@ -429,6 +430,7 @@ $VERSION = '1.06'; 'On' => '켜ì§', }, }, + 'ColorBalanceVersion' => '컬러 밸런스 버전', 'ColorBooster' => { PrintConv => { 'Off' => '꺼ì§', @@ -1469,6 +1471,7 @@ $VERSION = '1.06'; 'MakerNotes' => '제조업체 ì •ë³´', 'ManualFlashOutput' => '내장 플래시 ìˆ˜ë™ ì¶œë ¥', 'ManualFocusDistance' => 'ìˆ˜ë™ ì´ˆì  ê±°ë¦¬', + 'MatrixMetering' => '멀티 패턴 측광', 'MaxAperture' => '최대 렌즈 조리개', 'MaxApertureAtMaxFocal' => '최대 ì´ˆì ê¸¸ì´ì—ì„œ 최대 조리개', 'MaxApertureAtMinFocal' => '최소 ì´ˆì ê¸¸ì´ì—ì„œ 최대 조리개', @@ -2313,7 +2316,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/nl.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/nl.pm index 4cf8b003..195c182b 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/nl.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/nl.pm @@ -11,7 +11,7 @@ package Image::ExifTool::Lang::nl; use strict; use vars qw($VERSION); -$VERSION = '1.11'; +$VERSION = '1.13'; %Image::ExifTool::Lang::nl::Translate = ( 'AEBAutoCancel' => { @@ -201,6 +201,7 @@ $VERSION = '1.11'; 'ActionAdvised' => { Description => 'Actie advies', PrintConv => { + 'Object Append' => 'Object toevoegen', 'Object Kill' => 'Object verwijderen', 'Object Reference' => 'Object referentie', 'Object Replace' => 'Object vervangen', @@ -335,6 +336,7 @@ $VERSION = '1.11'; 'Off' => 'Uit', }, }, + 'AutoBracketingSet' => 'Inst. voor auto bracketing', 'AutoExposureBracketing' => { PrintConv => { 'Off' => 'Uit', @@ -1500,97 +1502,98 @@ $VERSION = '1.11'; 'GIFVersion' => 'GIF versie', 'GPSAltitude' => 'Hoogte', 'GPSAltitudeRef' => { - Description => 'Hoogte referentie', + Description => 'GPS hoogte - referentie', PrintConv => { - 'Above Sea Level' => 'Zee spiegel', - 'Below Sea Level' => 'Zee spiegel referentie (negatieve waarde)', + 'Above Sea Level' => 'Boven zeeniveau', + 'Below Sea Level' => 'Onder zeeniveau', }, }, - 'GPSAreaInformation' => 'Naam van het GPS gebied', - 'GPSDOP' => 'Meet nauwkeurigheid', - 'GPSDateStamp' => 'GPS datum', - 'GPSDateTime' => 'GPS tijd (atoomklok)', - 'GPSDestBearing' => 'Motiefrichting', + 'GPSAreaInformation' => 'GPS naam van het gebied', + 'GPSDOP' => 'GPS meetnauwkeurigheid', + 'GPSDateStamp' => 'GPS UTC datum', + 'GPSDateTime' => 'GPS UTC datum en tijd', + 'GPSDestBearing' => 'GPS peiling van bestemming', 'GPSDestBearingRef' => { - Description => 'Referentie voor de motiefrichting', + Description => 'GPS peiling van bestemming - referentie', PrintConv => { - 'Magnetic North' => 'Magnetische uitrichting', - 'True North' => 'Geografische uitrichting', + 'Magnetic North' => 'Magnetische noorden', + 'True North' => 'Geografische noorden', }, }, - 'GPSDestDistance' => 'Afstand tot bestemming', + 'GPSDestDistance' => 'GPS afstand tot bestemming', 'GPSDestDistanceRef' => { - Description => 'Referentie voor de afstand tot de bestemming', + Description => 'GPS afstand tot bestemming - referentie', PrintConv => { - 'Miles' => 'Mijlen', - 'Nautical Miles' => 'Knopen', + 'Miles' => 'Engelse mijlen', + 'Nautical Miles' => 'Zeemijlen', }, }, - 'GPSDestLatitude' => 'Breedte van het doel', + 'GPSDestLatitude' => 'GPS breedtegraad van bestemming', 'GPSDestLatitudeRef' => { - Description => 'Referentie voor de breedte van het doel', + Description => 'GPS breedtegraad van bestemming - referentie', PrintConv => { - 'North' => 'Noordelijke breedte', - 'South' => 'Zuidelijke breedte', + 'North' => 'Noorderbreedte', + 'South' => 'Zuiderbreedte', }, }, - 'GPSDestLongitude' => 'Lengtegraad van het doel', + 'GPSDestLongitude' => 'GPS lengtegraad van bestemming', 'GPSDestLongitudeRef' => { - Description => 'Referentie voor de lengte van het doel', + Description => 'GPS lengtegraad van bestemming - referentie', PrintConv => { - 'East' => 'Oostelijke lengte', - 'West' => 'Westlijke lengte', + 'East' => 'Oosterlengte', + 'West' => 'Westerlengte', }, }, 'GPSDifferential' => { Description => 'GPS differentiaal correctie', PrintConv => { - 'Differential Corrected' => 'Differentiaal correctie toegepast', - 'No Correction' => 'Meting zonder differentiaal correctie', + 'Differential Corrected' => 'Met differentiaal correctie', + 'No Correction' => 'Zonder differentiaal correctie', }, }, - 'GPSImgDirection' => 'Richting van de afbeelding', + 'GPSImgDirection' => 'GPS peiling van de afbeelding', 'GPSImgDirectionRef' => { - Description => 'Referentie voor de uitrichting van de afbeelding', + Description => 'GPS peiling van de afbeelding - referentie', PrintConv => { - 'Magnetic North' => 'Magnetische uitrichting', - 'True North' => 'Geografische uitrichting', + 'Magnetic North' => 'Magnetische noorden', + 'True North' => 'Geografische noorden', }, }, - 'GPSInfo' => 'GPS Info IFD-wijzer', - 'GPSLatitude' => 'Breedte graad', + 'GPSInfo' => 'GPS Info', + 'GPSLatitude' => 'GPS breedtegraad', 'GPSLatitudeRef' => { - Description => 'Noord. of zuid. breedte', + Description => 'GPS breedtegraad - referentie', PrintConv => { - 'North' => 'Noordelijke breedte', - 'South' => 'Zuidlijke breedte', + 'North' => 'Noorderbreedte', + 'South' => 'Zuiderbreedte', }, }, - 'GPSLongitude' => 'Geografische lengte', + 'GPSLongitude' => 'GPS lengtegraad', 'GPSLongitudeRef' => { - Description => 'Oost. of west. lengte', + Description => 'GPS lengtegraad - referentie', PrintConv => { - 'East' => 'Oostlijke lengte', - 'West' => 'Westlijke lengte', + 'East' => 'Oosterlengte', + 'West' => 'Westerlengte', }, }, - 'GPSMapDatum' => 'Geodatische datum', + 'GPSMapDatum' => 'GPS geodetisch datum', 'GPSMeasureMode' => { - Description => 'GPS meet methode', + Description => 'GPS meetmethode', PrintConv => { - '2-D' => '2 dimensionale meting', - '2-Dimensional' => '2 dimensionale meting', - '2-Dimensional Measurement' => '2 dimensionale meting', - '3-D' => '3 dimensionale meting', - '3-Dimensional' => '3 dimensionale meting', - '3-Dimensional Measurement' => '3 dimensionale meting', + '2-D' => 'Tweedimensionale meting', + '2-Dimensional' => 'Tweedimensionale meting', + '2-Dimensional Measurement' => 'Tweedimensionale meting', + '3-D' => 'Driedimensionale meting', + '3-Dimensional' => 'Driedimensionale meting', + '3-Dimensional Measurement' => 'Driedimensionale meting', }, }, - 'GPSProcessingMethod' => 'Naam van de GPS verwerk methode', - 'GPSSatellites' => 'Voor de meting gebruikte satellieten', - 'GPSSpeed' => 'Snelheid van de GPS ontvanger', + 'GPSPosition' => 'GPS positie', + 'GPSProcessingMethod' => 'GPS verwerkingsmethode', + 'GPSSatellites' => 'GPS satellieten gebruikt voor de meting', + 'GPSSpeed' => 'GPS ontvanger bewegingssnelheid', 'GPSSpeedRef' => { - Description => 'Snelheids eenheid', + Description => 'GPS ontvanger bewegingssnelheid - referentie', PrintConv => { 'km/h' => 'Kilometer per uur', 'knots' => 'Knopen', @@ -1600,20 +1603,20 @@ $VERSION = '1.11'; 'GPSStatus' => { Description => 'GPS ontvanger status', PrintConv => { - 'Measurement Active' => 'Meting loopt', - 'Measurement Void' => 'Interoperabiliteit voor metingen', + 'Measurement Active' => 'Actuele meting beschikbaar', + 'Measurement Void' => 'Actuele meting niet beschikbaar', }, }, - 'GPSTimeStamp' => 'GPS tijd (atoomklok)', - 'GPSTrack' => 'Bewegingsrichting', + 'GPSTimeStamp' => 'GPS UTC tijd', + 'GPSTrack' => 'GPS ontvanger bewegingsrichting', 'GPSTrackRef' => { - Description => 'Referentie voor de bewegingsrichting', + Description => 'GPS ontvanger bewegingsrichting - referentie', PrintConv => { - 'Magnetic North' => 'Magnetische uitrichting', - 'True North' => 'Geographische uitrichting', + 'Magnetic North' => 'Magnetische noorden', + 'True North' => 'Geografische noorden', }, }, - 'GPSVersionID' => 'GPS tag versie', + 'GPSVersionID' => 'GPS versie ID', 'GainControl' => { Description => 'Belichtingsversterking', PrintConv => { @@ -1996,6 +1999,7 @@ $VERSION = '1.11'; }, }, 'MasterDocumentID' => 'ID van hoofddocument', + 'MatrixMetering' => 'Matrixmeting', 'MaxAperture' => 'Maximale lensopening', 'MaxApertureValue' => 'Grootste diafragma', 'MaxContinuousRelease' => 'Max. aant. continuopnamen', @@ -3058,9 +3062,9 @@ $VERSION = '1.11'; }, 'WBAdjLighting' => { PrintConv => { + 'Daylight (cloudy)' => 'Daglicht (2)', 'Daylight (direct sunlight)' => 'Daglicht (0)', 'Daylight (shade)' => 'Daglicht (1)', - 'Daylight (cloudy)' => 'Daglicht (2)', 'Flash' => 'Flits', 'None' => 'Geen', }, @@ -3204,7 +3208,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/pl.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/pl.pm index 0e59a51d..3ec0d6ab 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/pl.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/pl.pm @@ -11,7 +11,7 @@ package Image::ExifTool::Lang::pl; use strict; use vars qw($VERSION); -$VERSION = '1.10'; +$VERSION = '1.12'; %Image::ExifTool::Lang::pl::Translate = ( 'A100DataOffset' => 'PrzesuniÄ™cie danych A100', @@ -1064,7 +1064,7 @@ $VERSION = '1.10'; 'SubfileType' => { Description => 'Typ podsekcji', PrintConv => { - 'Full-resolution Image' => 'Obraz w peÅ‚nej rozdzielczoÅ›ci', + 'Full-resolution image' => 'Obraz w peÅ‚nej rozdzielczoÅ›ci', 'Reduced-resolution image' => 'Obraz o zredukowanej rozdzielczoÅ›ci', 'Single page of multi-page image' => 'Jedna strona obrazu wielostronicowego', 'Single page of multi-page reduced-resolution image' => 'Jedna strona obrazu wielostronicowego o zredukowanej rozdzielczoÅ›ci', @@ -1258,7 +1258,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/ru.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/ru.pm index ae4a8b33..bcf088f3 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/ru.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/ru.pm @@ -11,608 +11,4820 @@ package Image::ExifTool::Lang::ru; use strict; use vars qw($VERSION); -$VERSION = '1.04'; +$VERSION = '1.08'; %Image::ExifTool::Lang::ru::Translate = ( + 'A100DataOffset' => 'Смещение данных (Sony A100)', + 'ABDate' => 'AB – Дата', + 'ABLabel' => 'AB – Метка', + 'ABRelatedNames' => 'AB – Похожие имена', + 'AB_UID' => 'AB – Уникальный ID', + 'AFAdjustment' => 'Регулировка автофокуÑа', + 'AIBuildNumber' => 'AI – Ðомер Ñборки', + 'AIColorModel' => 'AI – Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ð¼Ð¾Ð´ÐµÐ»ÑŒ', + 'AIColorUsage' => 'AI – ИÑпользование цвета', + 'AICreatorVersion' => 'AI – ВерÑÐ¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ', + 'AIFileFormat' => 'AI – Формат файла', + 'AINumLayers' => 'AI – КоличеÑтво Ñлоёв', + 'AIRulerUnits' => { + Description => 'AI – Единицы линейки', + PrintConv => { + 'Centimeters' => 'Сантиметры', + 'Inches' => 'Дюймы', + 'Millimeters' => 'Милиметры', + 'Picas' => 'Пики', + 'Pixels' => 'ПикÑели', + 'Points' => 'Точки', + }, + }, + 'AITargetResolution' => 'AI – Целевое разрешение', + 'APEVersion' => 'ВерÑÐ¸Ñ APE', + 'ARMIdentifier' => 'Идентификатор ARM', + 'ARMVersion' => 'ВерÑÐ¸Ñ ARM', + 'ATSCContent' => { + Description => 'Контент ATSC', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'About' => 'Об', + 'AbsoluteAltitude' => 'ÐбÑÐ¾Ð»ÑŽÑ‚Ð½Ð°Ñ Ð²Ñ‹Ñота', + 'Abstract' => 'Краткое опиÑание', + 'AbstractFileName' => 'Файл Ñ Ð°Ð±Ñтрактной информацией', + 'Acceleration' => 'УÑкорение', + 'AccelerationVector' => 'Вектор уÑкорениÑ', + 'Accelerometer' => 'ÐкÑелерометр', + 'AccelerometerTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð°ÐºÑелерометра', + 'AccelerometerX' => 'ÐкÑелерометр – X', + 'AccelerometerY' => 'ÐкÑелерометр – Y', + 'AccelerometerZ' => 'ÐкÑелерометр – Z', + 'AccessDate' => 'Дата поÑледнего доÑтупа', + 'Acknowledged' => 'БлагодарноÑти', + 'Action' => 'ДейÑтвие', + 'ActionAdvised' => { + Description => 'Рекомендуемое дейÑтвие', + PrintConv => { + 'Object Append' => 'Добавить объект', + 'Object Kill' => 'Уничтожить объект', + 'Object Reference' => 'Сделать ÑÑылку на объект', + 'Object Replace' => 'Заменить объект', + }, + }, 'ActiveArea' => 'ÐÐºÑ‚Ð¸Ð²Ð½Ð°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ', + 'Actor' => 'Ðктёр', + 'Address' => 'ÐдреÑÑ', + 'AdoptedNeutral' => 'ПринÑтый как нейтральный', + 'Adult' => 'Ð”Ð»Ñ Ð²Ð·Ñ€Ð¾Ñлых', + 'AdultContentWarning' => { + Description => 'Предупреждение о Ñодержании Ð´Ð»Ñ Ð²Ð·Ñ€Ð¾Ñлых', + PrintConv => { + 'Adult Content Warning Required' => 'ТребуетÑÑ', + 'Not Required' => 'Ðе требуетÑÑ', + 'Unknown' => 'Ðе задано', + }, + }, + 'AdvancedSceneMode' => { + Description => 'РаÑширенный режим Ñцены', + PrintConv => { + 'Architecture' => 'Ðрхитектура', + 'Bleach Bypass' => 'Удержание Ñеребра', + 'Cinema' => 'Кино', + 'Color Select' => 'Выбранный цвет', + 'Creative Macro' => 'ТворчеÑкий макро', + 'Creative Night Scenery' => 'ТворчеÑкий ночной пейзаж', + 'Creative Portrait' => 'ТворчеÑкий портрет', + 'Creative Scenery' => 'ТворчеÑкий пейзаж', + 'Creative Sports' => 'ТворчеÑкий Ñпорт', + 'Cross Process' => 'КроÑÑпроцеÑÑ', + 'Dynamic Art' => 'Динамика', + 'Dynamic Monochrome' => 'Динамичное монохромное', + 'Elegant' => 'Элегантный', + 'Expressive' => 'Выразительный', + 'Fantasy' => 'ФÑнтези', + 'Flower' => 'Цветок', + 'HDR Art' => 'HDR', + 'HDR B&W' => 'Чёрно-Белый HDR', + 'Handheld Night Shot' => 'ÐÐ¾Ñ‡Ð½Ð°Ñ Ñъёмка Ñ Ñ€ÑƒÐºÐ¸', + 'High Dynamic' => 'Ð’Ñ‹ÑÐ¾ÐºÐ°Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸ÐºÐ°', + 'High Key' => 'Ð’ выÑоком ключе', + 'Illuminations' => 'Свеча', + 'Impressive Art' => 'ВпечатлÑющий', + 'Indoor Portrait' => 'Внутренний портрет', + 'Indoor Sports' => 'Спорт в помещении', + 'Low Key' => 'Ð’ низком ключе', + 'Miniature' => 'Миниатюра', + 'Monochrome' => 'Монохромный', + 'Nature' => 'Природа', + 'Objects' => 'Объекты', + 'Old Days' => 'Старые времена', + 'Outdoor Portrait' => 'Ðаружный портрет', + 'Outdoor Sports' => 'Спорт на открытом воздухе', + 'Pure' => 'ЧиÑтый', + 'Retro' => 'Ретро', + 'Rough Monochrome' => 'Грубый монохромный', + 'Sepia' => 'СепиÑ', + 'Silhouette' => 'СилуÑÑ‚', + 'Silky Monochrome' => 'ШелковиÑтый монохромный', + 'Soft' => 'ÐœÑгкий', + 'Star' => 'Звёзды', + 'Sunshine' => 'Солнечный Ñвет', + 'Toy Effect' => 'Эффект ломографии', + 'Toy Pop' => 'Ð›Ð¾Ð¼Ð¾Ð³Ñ€Ð°Ñ„Ð¸Ñ Ñ Ð²Ñ‹Ð´ÐµÐ»ÐµÐ½Ð¸ÐµÐ¼ цвета', + }, + }, + 'AdventRevision' => 'Проверка поÑвлениÑ', + 'AdventScale' => 'МаÑштаб поÑвлениÑ', + 'AffineA' => 'Ðфинное преобразование A', + 'AffineB' => 'Ðфинное преобразование B', + 'AffineC' => 'Ðфинное преобразование C', + 'AffineD' => 'Ðфинное преобразование D', + 'AffineTransformMat' => 'Матрица Ðфинного преобразованиÑ', + 'AffineX' => 'Ðфинное преобразование X', + 'AffineY' => 'Ðфинное преобразование Y', + 'AlarmUID' => 'Уникальный ID Ñигнала', 'Album' => 'Ðльбом', + 'AlbumArtist' => 'ИÑполнитель альбома', + 'AliasLayerMetadata' => 'ПÑевдоним метаданных ÑлоÑ', + 'Alignment' => 'Выравнивание', + 'AllColorFlatField1' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð¿Ð»Ð¾Ñкого Ð¿Ð¾Ð»Ñ â€“ Ð’Ñе цвета 1', + 'AllColorFlatField2' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð¿Ð»Ð¾Ñкого Ð¿Ð¾Ð»Ñ â€“ Ð’Ñе цвета 2', + 'AllColorFlatField3' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð¿Ð»Ð¾Ñкого Ð¿Ð¾Ð»Ñ â€“ Ð’Ñе цвета 3', + 'AllDayEvent' => 'Событие на веÑÑŒ день', + 'Alpha' => { + Description => 'Ðльфа-канал', + PrintConv => { + 'Alpha Exists (W color component)' => 'Ðльфа-канал приÑутÑтвует (цветной компонент W)', + 'Alpha Exists (color not premultiplied)' => 'Ðльфа-канал приÑутÑтвует (не предварительно умноженный цвет)', + 'Alpha Exists (color premultiplied)' => 'Ðльфа-канал приÑутÑтвует (предварительно умноженный цвет)', + 'No Alpha Plane' => 'Ðльфа-канал отÑутÑтвует', + }, + }, + 'AlphaByteCount' => 'Размер альфа-канала (байт)', + 'AlphaChannelsNames' => 'ÐÐ°Ð·Ð²Ð°Ð½Ð¸Ñ Ð°Ð»ÑŒÑ„Ð°-каналов', + 'AlphaDataDiscard' => { + Description => 'Отброшенные данные альфа-канала', + PrintConv => { + 'Flexbits Discarded' => 'Гибкие биты отброшены', + 'Full Resolution' => 'Полное разрешение', + 'HighPass Frequency Data Discarded' => 'Данные выÑоких чаÑтот отброшены', + 'Highpass and LowPass Frequency Data Discarded' => 'Данные выÑоких и низких чаÑтот отброшены', + }, + }, + 'AlphaIdentifiers' => 'Идентификаторы альфа-канала', + 'AlphaMask' => 'МаÑка Ðльфа-канала', + 'AlphaOffset' => 'Смещение альфа-канала', + 'AlternateDuotoneColors' => 'Ðльтернативные цвета Duotone', + 'AlternateSpotColors' => 'Ðльтернативные плашечные цвета', + 'AmbientInfrared' => 'Внешний инфракраÑный Ñвет', + 'AmbientLight' => 'Внешнее оÑвещение', + 'AmbientTemperature' => 'Температура окружающей Ñреды', + 'AmbientTemperatureFahrenheit' => 'Температура окружающей Ñреды по Фаренгейту', 'AnalogBalance' => 'Ðналоговый Ð±Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾', - 'AntiAliasStrength' => 'ОтноÑÐ¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ñила Ñглаживающего фильтра ÑенÑора', + 'AngleInfoRoll' => 'Угол Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ (крен)', + 'AngleInfoYaw' => 'Угол поворота (рыÑкание)', + 'AnimationControl' => 'Управление анимацией', + 'AnimationFrames' => 'Кадры анимации', + 'AnimationIterations' => 'Повторений анимации', + 'AnimationPlays' => 'Проигрывание анимации', + 'Anniversary' => 'Годовщина', + 'Annotation' => 'ÐннотациÑ', + 'AnnotationUsageRights' => 'Права на иÑпользование Ðннотации', + 'Annotations' => 'Ðннотации', + 'Announce' => 'Трекер', + 'AnnounceList1' => 'СпиÑок трекеров 1', + 'AntiAliasStrength' => 'Сила ÑглаживаниÑ', 'Aperture' => 'Диафрагма', 'ApertureValue' => 'Диафрагма', + 'AppleKeywords' => 'Apple – Ключевые Ñлова', + 'AppleMailDateReceived' => 'Apple Mail – Дата получениÑ', + 'AppleMailDateSent' => 'Apple Mail – Дата отправки', + 'AppleMailFlagged' => 'Apple Mail – Отмечено флажком', + 'AppleMailIsRemoteAttachment' => 'Apple Mail – Ðаличие удалённого вложениÑ', + 'AppleMailMessageID' => 'Apple Mail – ID ÑообщениÑ', + 'AppleMailPriority' => 'Apple Mail – Приоритет', + 'AppleMailRead' => 'Apple Mail – Прочитано', + 'AppleMailRepliedTo' => 'Apple Mail – Отвечено', + 'Application' => 'Приложение', + 'ApplicationData' => 'Данные об уÑтройÑтве', + 'ApplicationNotes' => 'ÐŸÑ€Ð¸Ð¼ÐµÑ‡Ð°Ð½Ð¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ', + 'ApplicationRecordVersion' => 'ВерÑÐ¸Ñ Application Record', + 'AppointmentSequence' => 'ПоÑледовательноÑÑ‚ÑŒ назначениÑ', + 'ApproximateFocusDistance' => 'Приблизительное раÑÑтоÑние фокуÑировки', + 'ArchivedFileName' => 'Ðазвание заархивированного файла', 'Artist' => 'ИÑполнитель', - 'AsShotICCProfile' => 'ICC профиль Ñнимка', + 'ArtistLen' => 'ИÑполнитель Len', + 'AsShotICCProfile' => 'ICC-профиль при Ñъёмке', 'AsShotNeutral' => 'Ðейтральный цвет при Ñъёмке', - 'AsShotPreProfileMatrix' => 'ÐŸÑ€ÐµÐ´Ð²Ð°Ñ€Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ñ†Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ð¼Ð°Ñ‚Ñ€Ð¸Ñ†Ð° Ñнимка', - 'AsShotProfileName' => 'Ð˜Ð¼Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ, аÑÑоциированного Ñо Ñнимком', - 'AsShotWhiteXY' => 'Ðейтральный цвет x,y', + 'AsShotPreProfileMatrix' => 'Предварительный профиль матрицы при Ñъёмке', + 'AsShotProfileName' => 'Ðазвание Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ Ð¿Ñ€Ð¸ Ñъёмке', + 'AsShotWhiteXY' => 'XY белого при Ñъёмке', + 'Ascender' => 'ÐадÑтрочный интервал', + 'Ascent' => 'ÐадÑтрочный интервал', + 'AspectRatio' => 'Соотношение Ñторон', + 'AssetID' => 'ID актива', + 'Association' => 'ÐÑÑоциациÑ', + 'AssumedDisplaySize' => 'Размер отображаемого ÑтереоизображениÑ', + 'AssumedDistanceView' => 'РаÑÑтоÑние от позиции проÑмотра до диÑплеÑ', + 'Attachment' => 'Вложение', + 'Attendee' => 'УчаÑтник', + 'Attitude' => 'Положение', + 'AttitudeTarget' => 'Целевое положение', + 'Audiences' => 'ÐудиториÑ', + 'AudioBitrate' => 'Битрейт аудио', + 'AudioBitsPerSample' => 'Ð‘Ð¸Ñ‚Ð¾Ð²Ð°Ñ Ð³Ð»ÑƒÐ±Ð¸Ð½Ð° аудио', + 'AudioBytes' => 'Ðудио байтов', + 'AudioChannels' => 'КоличеÑтво аудиоканалов', + 'AudioCodec' => 'Кодек аудио', + 'AudioCodecID' => 'ID аудиокодека', + 'AudioData' => 'Ðудиоданные', + 'AudioDuration' => 'ПродолжительноÑÑ‚ÑŒ аудио', + 'AudioEncoding' => { + Description => 'Кодирование звука', + PrintConv => { + 'Device-specific sound' => 'ЗавиÑÑщий от уÑтройÑтва звук', + 'G.711 A-law logarithmic PCM' => 'G.711 A-law логарифмичеÑкий PCM', + 'G.711 mu-law logarithmic PCM' => 'G.711 mu-law логарифмичеÑкий PCM', + 'Nellymoser 16kHz Mono' => 'Nellymoser 16 кГц, моно', + 'Nellymoser 8kHz Mono' => 'Nellymoser 8kHz, моно', + 'PCM-BE (uncompressed)' => 'PCM-BE (без ÑжатиÑ)', + 'PCM-LE (uncompressed)' => 'PCM-LE (без ÑжатиÑ)', + }, + }, + 'AudioFileSize' => 'Размер аудио файла', + 'AudioFormat' => 'Формат аудио', + 'AudioFrameSize' => 'Размер аудио фрейма', + 'AudioLayer' => 'Уровень аудио', + 'AudioMimeType' => 'MIME-тип аудио', + 'AudioMode' => 'Режим аудио', + 'AudioOutcue' => 'Заключительные Ñлова аудио', + 'AudioSampleRate' => 'ЧаÑтота диÑкретизации звука', + 'AudioSampleSize' => 'КоличеÑтво бит на канал', + 'AudioSamplingRate' => 'ЧаÑтота диÑкретизации', + 'AudioSamplingResolution' => 'РазрÑдноÑÑ‚ÑŒ аудио', + 'AudioSetting' => 'ÐаÑтройка звука', + 'AudioSize' => 'Размер аудиофайла', + 'AudioType' => { + Description => 'Тип аудио', + PrintConv => { + 'Mono Actuality' => 'Событие – Моно', + 'Mono Music' => 'Музыка – Моно', + 'Mono Question and Answer Session' => 'ВопроÑÑ‹ и ответы – Моно', + 'Mono Raw Sound' => 'ÐÐµÐ¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚Ð°Ð½Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ – Моно', + 'Mono Response to a Question' => 'Ответ на Ð²Ð¾Ð¿Ñ€Ð¾Ñ â€“ Моно', + 'Mono Scener' => 'ОбÑтоÑтельÑтва ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ â€“ Моно', + 'Mono Voicer' => 'ГолоÑÐ¾Ð²Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ – Моно', + 'Mono Wrap' => 'Итог ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ â€“ Моно', + 'Stereo Actuality' => 'Событие – Стерео', + 'Stereo Music' => 'Музыка – Стерео', + 'Stereo Question and Answer Session' => 'ВопроÑÑ‹ и ответы – Стерео', + 'Stereo Raw Sound' => 'ÐÐµÐ¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚Ð°Ð½Ð½Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ – Стерео', + 'Stereo Response to a Question' => 'Ответ на Ð²Ð¾Ð¿Ñ€Ð¾Ñ â€“ Стерео', + 'Stereo Scener' => 'ОбÑтоÑтельÑтва ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ â€“ Стерео', + 'Stereo Voicer' => 'ГолоÑÐ¾Ð²Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ – Стерео', + 'Stereo Wrap' => 'Итог ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ â€“ Стерео', + 'Text Only' => 'Только текÑÑ‚', + }, + }, + 'AuthenticationTime' => 'Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ – Ð’Ñ€ÐµÐ¼Ñ Ð°ÑƒÑ‚ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ð¸', + 'AuthenticationType' => 'Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ – Тип аутентификации', 'Author' => 'Ðвтор', + 'AuthorLen' => 'Ðвтор Len', 'AuthorsPosition' => 'ДолжноÑÑ‚ÑŒ автора', + 'AutoFocus' => { + Description => 'ÐвтофокуÑ', + PrintConv => { + 'Off' => 'Ðе включён', + 'On' => 'Включен', + }, + }, + 'AutoISOMax' => 'МакÑимально значение автоматичеÑкого ISO', + 'AutoISOMin' => 'Минимальное значение автоматичеÑкого ISO', + 'AutoLowLightDuration' => 'ÐвтоÑъёмка при низком оÑвещении – ПродолжительноÑÑ‚ÑŒ', + 'AutoRotation' => { + Description => 'ÐвтоматичеÑкий поворот', + PrintConv => { + 'Auto' => 'ÐвтоматичеÑки', + 'Down' => 'Вниз', + 'Up' => 'Вверх', + }, + }, + 'AutoSaveFilePath' => 'Путь к файлу автоÑохранениÑ', + 'AutoSaveFormat' => 'Формат автоÑохранениÑ', + 'AvgBitrate' => 'Средний битрейт', + 'AvgPacketSize' => 'Средний размер пакета', + 'AvgWidth' => 'СреднÑÑ ÑˆÐ¸Ñ€Ð¸Ð½Ð° глифа', + 'AxisDistanceX' => 'ДиÑÑ‚Ð°Ð½Ñ†Ð¸Ñ Ð¿Ð¾ оÑи X', + 'AxisDistanceY' => 'ДиÑÑ‚Ð°Ð½Ñ†Ð¸Ñ Ð¿Ð¾ оÑи Y', + 'AxisDistanceZ' => 'ДиÑÑ‚Ð°Ð½Ñ†Ð¸Ñ Ð¿Ð¾ оÑи Z', + 'BMPVersion' => { + Description => 'ВерÑÐ¸Ñ BMP', + PrintConv => { + 'AVI BMP structure?' => 'Структура AVI BMP?', + }, + }, + 'BWFilter' => 'Чёрно-Белый фильтр', + 'BW_HalftoningInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ тонировании – Чёрно-Белое', + 'BW_TransferFunc' => 'Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¿ÐµÑ€ÐµÐ½Ð¾Ñа – Чёрно-Белое', + 'Background' => 'Фон', + 'BackgroundColor' => 'Цвет фона', + 'BackgroundColorIndicator' => { + Description => 'Цвет фона', + PrintConv => { + 'Specified Background Color' => 'Указан', + 'Unspecified Background Color' => 'Ðе указан', + }, + }, + 'BackgroundColorValue' => 'Значение фонового цвета', + 'BackupTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ñ€ÐµÐ·ÐµÑ€Ð²Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ', + 'BadFaxLines' => 'КоличеÑтво битых Ñтрок', + 'BaseViewpointNum' => 'Ðомер базовой точки проÑмотра', 'BaselineExposure' => 'Ð‘Ð°Ð·Ð¾Ð²Ð°Ñ ÑкÑпозициÑ', - 'BaselineNoise' => 'Базовый шум', + 'BaselineExposureOffset' => 'Сдвиг базовой ÑкÑпозиции', + 'BaselineLength' => 'Длина базовой линии', + 'BaselineNoise' => 'Базовый уровень шума', 'BaselineSharpness' => 'Ð‘Ð°Ð·Ð¾Ð²Ð°Ñ Ñ‡Ñ‘Ñ‚ÐºÐ¾ÑÑ‚ÑŒ', + 'BatteryCapacity' => 'ÐмкоÑÑ‚ÑŒ аккумулÑтора', + 'BatteryCurrent' => 'Ток аккумулÑтора', + 'BatteryLevel' => 'Уровень зарÑда аккумулÑтора', + 'BatteryTemperature' => 'Температура аккумулÑтора', + 'BatteryTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ от аккумулÑтора', + 'BatteryType' => 'Тип аккумулÑтора', + 'BatteryVoltage' => 'ÐапрÑжение аккумулÑтора', + 'BatteryVoltage1' => 'ÐапрÑжение аккумулÑтора 1', + 'BatteryVoltage2' => 'ÐапрÑжение аккумулÑтора 2', + 'BatteryVoltage3' => 'ÐапрÑжение аккумулÑтора 3', + 'BatteryVoltage4' => 'ÐапрÑжение аккумулÑтора 4', + 'BatteryVoltageAvg' => 'ÐапрÑжение аккумулÑтора (Ñреднее)', 'BayerGreenSplit' => 'Разделение зелёных каналов в матрице Байера', - 'BestQualityScale' => 'МаÑштаб Ñ Ð½Ð°Ð¸Ð»ÑƒÑ‡ÑˆÐ¸Ð¼ качеÑтвом', + 'BayerPattern' => 'Фильтр Байера', + 'BestQualityScale' => 'Оптимальный маÑштаб', + 'BibligraphicFileName' => 'Файл Ñ Ð±Ð¸Ð±Ð»Ð¸Ð¾Ð³Ñ€Ð°Ñ„Ð¸Ñ‡ÐµÑкой информацией', + 'BinaryFilter' => 'Бинарный фильтр', + 'Birthday' => 'День рождениÑ', + 'BitDepth' => { + Description => 'Ð‘Ð¸Ñ‚Ð¾Ð²Ð°Ñ Ð³Ð»ÑƒÐ±Ð¸Ð½Ð°', + PrintConv => { + 'Custom' => 'Ð—Ð°Ð´Ð°Ð½Ð½Ð°Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»ÐµÐ¼', + }, + }, + 'Bitrate' => 'Битрейт', + 'BitsPerComponent' => 'КоличеÑтво бит на компонент', + 'BitsPerExtendedRunLength' => 'КоличеÑтво бит на раÑширенную длину Ñерий', + 'BitsPerPixel' => 'КоличеÑтво бит на пикÑель', + 'BitsPerRunLength' => 'КоличеÑтво бит на длину Ñерий', 'BitsPerSample' => 'КоличеÑтво бит на компонент', 'BlackLevel' => 'Уровень чёрного', - 'BlackLevelDeltaH' => 'Горизонтальное раÑпределение ÑƒÑ€Ð¾Ð²Ð½Ñ Ñ‡Ñ‘Ñ€Ð½Ð¾Ð³Ð¾', - 'BlackLevelDeltaV' => 'Вертикальное раÑпределение ÑƒÑ€Ð¾Ð²Ð½Ñ Ñ‡Ñ‘Ñ€Ð½Ð¾Ð³Ð¾', - 'BlackLevelRepeatDim' => 'Размер матрицы уровней чёрного', + 'BlackLevelBlue' => 'Уровень чёрного – Синий', + 'BlackLevelData' => 'Данные ÑƒÑ€Ð¾Ð²Ð½Ñ Ñ‡ÐµÑ€Ð½Ð¾Ð³Ð¾', + 'BlackLevelDeltaH' => 'Уровень чёрного – Дельта H', + 'BlackLevelDeltaV' => 'Уровень чёрного – Дельта V', + 'BlackLevelGreen' => 'Уровень чёрного – Зелёный', + 'BlackLevelRed' => 'Уровень чёрного – КраÑный', + 'BlackLevelRepeatDim' => 'Уровень чёрного – Размер шаблона повторений', + 'BlacksAdj' => 'Регулировка ÑƒÑ€Ð¾Ð²Ð½Ñ Ñ‡Ñ‘Ñ€Ð½Ð¾Ð³Ð¾', + 'BlockSizeMax' => 'МакÑимальный размер блока', + 'BlockSizeMin' => 'Минимальный размер блока', + 'BlocksPerFrame' => 'Блоков на кадр', + 'BlueBalance' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ñинего', + 'BlueEndpoint' => 'ÐšÐ¾Ð½ÐµÑ‡Ð½Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° Синего', + 'BlueMask' => 'МаÑка Синего', + 'BluePrimary' => 'ОÑновной Ñиний', + 'BlueX' => 'Синий по X', + 'BlueY' => 'Синий по Y', + 'BookName' => 'Ðазвание книги', + 'BookTitle' => 'Ðазвание книги', + 'BookType' => 'Тип книги', + 'BookVersion' => 'ВерÑÐ¸Ñ ÐºÐ½Ð¸Ð³Ð¸', + 'BootIdentifier' => 'Идентификатор загрузки', + 'BootLoaderVersion' => 'ВерÑÐ¸Ñ Ð·Ð°Ð³Ñ€ÑƒÐ·Ñ‡Ð¸ÐºÐ°', + 'BootSystem' => 'СиÑтема загрузки', + 'BorderColor' => 'Цвет границы', + 'BorderInformation' => 'Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ границе', + 'BoundingBox' => 'Габаритный прÑмоугольник', + 'Brain' => 'Модуль Brain', + 'BrandingImageID' => 'Бренд – ID изображениÑ', + 'BrandingName' => 'Бренд – Ðазвание', + 'BreakChar' => 'Символ определÑющий границы Ñлов', 'Brightness' => 'ЯркоÑÑ‚ÑŒ', + 'BrightnessAdj' => 'Регулировка ÑркоÑти', + 'BrightnessValue' => 'Значение ÑркоÑти', + 'BurstID' => 'ID Ñерии Ñнимков', + 'BurstPrimary' => 'Первый кадр Ñерии', + 'BurstUUID' => 'Уникальный ID Ð´Ð»Ñ Ñерии Ñнимков', + 'BusyStatus' => 'СоÑтоÑние занÑтоÑти', 'By-line' => 'Ðвтор', + 'By-lineTitle' => 'Титул автора', + 'ByteLength' => 'Длина в байтах', + 'ByteOrder' => { + Description => 'ПорÑдок байтов', + PrintConv => { + 'Big-endian' => 'ПорÑдок от Ñтаршего к младшему', + 'Little-endian' => 'ПорÑдок от младшего к Ñтаршему', + }, + }, + 'BytesPerLine' => 'КоличеÑтво байт на Ñтроку', + 'BytesPerMinute' => 'Байт в минуту', + 'CDDBDiscPlayTime' => 'CDDB – Ð’Ñ€ÐµÐ¼Ñ Ð²Ð¾ÑÐ¿Ñ€Ð¾Ð¸Ð·Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð´Ð¸Ñка', + 'CDDBDiscTracks' => 'CDDB – Треки на диÑке', + 'CDEType' => 'Тип CDE', 'CFALayout' => { - Description => 'Структура CFA', + Description => 'Макет CFA', + PrintConv => { + 'Even columns offset down 1/2 row' => 'Чётные Ñтолбцы Ñмещены вниз на 1/2 Ñтроки', + 'Even columns offset up 1/2 row' => 'Чётные Ñтолбцы Ñмещены вверх 1/2 Ñтроки', + 'Even rows offset down by 1/2 row, even columns offset left by 1/2 column' => 'Чётные Ñтроки Ñмещены вниз на 1/2 Ñтроки, чётные Ñтолбцы Ñмещены влево на 1/2 Ñтолбца', + 'Even rows offset down by 1/2 row, even columns offset right by 1/2 column' => 'Чётные Ñтроки Ñмещены вниз на 1/2 Ñтроки, чётные Ñтолбцы Ñмещены вправо на 1/2 Ñтолбца', + 'Even rows offset left 1/2 column' => 'Чётные Ñтроки Ñмещены влево на 1/2 Ñтолбца', + 'Even rows offset right 1/2 column' => 'Чётные Ñтроки Ñмещены вправо на 1/2 Ñтолбца', + 'Even rows offset up by 1/2 row, even columns offset left by 1/2 column' => 'Чётные Ñтроки Ñмещены вверх на 1/2 Ñтроки, чётные Ñтолбцы Ñмещены влево на 1/2 Ñтолбца', + 'Even rows offset up by 1/2 row, even columns offset right by 1/2 column' => 'Чётные Ñтроки Ñмещены вверх на 1/2 Ñтроки, чётные Ñтолбцы Ñмещены вправо на 1/2 Ñтолбца', + 'Rectangular' => 'ПрÑÐ¼Ð¾ÑƒÐ³Ð¾Ð»ÑŒÐ½Ð°Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½Ð¾Ð²ÐºÐ°', + }, + }, + 'CFAPattern' => { + Description => 'Шаблон CFA', + PrintConv => { + '[Blue,Green][Green,Red]' => '[Синий, Зелёный][Зелёный, КраÑный]', + '[Green,Blue][Red,Green]' => '[Зелёный, Синий][КраÑный, Зелёный]', + '[Green,Red][Blue,Green]' => '[Зелёный, КраÑный][Синий, Зелёный]', + '[Red,Green][Green,Blue]' => '[КраÑный, Зелёный][Зелёный, Синий]', + 'n/a' => 'Ðет данных', + }, + }, + 'CFAPattern2' => 'Шаблон CFA 2', + 'CFAPlaneColor' => 'Цветовые плоÑкоÑти CFA', + 'CFARepeatPatternDim' => 'Шаблон Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð¸Ñ CFA', + 'CIP3DataFile' => 'CIP3 – Файл данных', + 'CIP3Sheet' => 'CIP3 – ЛиÑÑ‚', + 'CIP3Side' => 'CIP3 – Сторона', + 'CMYKEquivalent' => 'Эквивалент CMYK', + 'CPUVersions' => 'ВерÑии CPU', + 'CR2CFAPattern' => { + Description => 'CR2 – Шаблон CFA', PrintConv => { - 'Even columns offset down 1/2 row' => 'Смещённое раÑположение A: чётные Ñтолбцы Ñмещены вниз на полпикÑела', - 'Even columns offset up 1/2 row' => 'Смещённое раÑположение B: чётные Ñтолбцы Ñмещены вверх на полпикÑела', - 'Even rows offset left 1/2 column' => 'Смещённое раÑположение D: чётные Ñтроки Ñмещены влево на полпикÑела', - 'Even rows offset right 1/2 column' => 'Смещённое раÑположение C: чётные Ñтроки Ñмещены вправо на полпикÑела', - 'Rectangular' => 'ПрÑмоугольное (или квадратное) раÑположение Ñлементов', + '[Blue,Green][Green,Red]' => '[Синий, Зеленый][Зеленый, КраÑный]', + '[Green,Blue][Red,Green]' => '[Зеленый, Синий][КраÑный, Зеленый]', + '[Green,Red][Blue,Green]' => '[Зеленый, КраÑный][Синий, Зеленый]', + '[Red,Green][Green,Blue]' => '[КраÑный, Зеленый][Зеленый, Синий]', }, }, - 'CFAPattern' => 'CFA карта', + 'CacheControl' => 'Контроль кешированиÑ', + 'CacheVersion' => 'ВерÑÐ¸Ñ ÐºÑша', + 'CalendarColor' => 'Цвет календарÑ', + 'CalendarDescription' => 'ОпиÑание календарÑ', + 'CalendarID' => 'ID календарÑ', + 'CalendarName' => 'Ðазвание календарÑ', + 'CalendarScale' => 'ÐšÐ°Ð»ÐµÐ½Ð´Ð°Ñ€Ð½Ð°Ñ ÑиÑтема', + 'CalibratedFocalLength' => 'Откалирброванное фокуÑное раÑÑтоÑние', + 'CalibratedOpticalCenterX' => 'Откалирброванный оптичеÑкий центр по X', + 'CalibratedOpticalCenterY' => 'Откалирброванный оптичеÑкий центр по Y', 'CalibrationIlluminant1' => { - Description => 'Калибровочный иллюминант â„–1', + Description => 'Калибровочное оÑвещение 1', PrintConv => { - 'Cloudy' => 'ОблачноÑÑ‚ÑŒ', - 'Cool White Fluorescent' => 'ФлуореÑцентный белый холодный (W 3800 - 4500K)', - 'Day White Fluorescent' => 'ФлуореÑцентный белый дневной', - 'Daylight' => 'Дневной Ñвет', - 'Daylight Fluorescent' => 'ФлуореÑцентный белый дневного Ñвета (D 5700 - 7100K)', - 'Fine Weather' => 'ЯÑÐ½Ð°Ñ Ð¿Ð¾Ð³Ð¾Ð´Ð°', - 'Flash' => 'Ð’Ñпышка', - 'Fluorescent' => 'ФлуореÑцентный', - 'ISO Studio Tungsten' => 'ISO Ð´Ð»Ñ Ñтудийных ламп накаливаниÑ', - 'Other' => 'другой иÑточник Ñвета', - 'Shade' => 'Тень', - 'Standard Light A' => 'Стандартный Ñвет A', - 'Standard Light B' => 'Стандартный Ñвет B', - 'Standard Light C' => 'Стандартный Ñвет C', - 'Tungsten (Incandescent)' => 'Лампа Ð½Ð°ÐºÐ°Ð»Ð¸Ð²Ð°Ð½Ð¸Ñ (Ñркий Ñвет)', - 'Unknown' => 'неизвеÑтно', - 'Warm White Fluorescent' => 'ФлуореÑцентный теплый белый (L 2600 - 3250K)', - 'White Fluorescent' => 'ФлуореÑцентный белый (WW 3250 - 3800K)', + 'Cloudy' => 'Облачно (6500 К)', + 'Cool White Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° – Холодный Ñвет (4150 К)', + 'D50' => 'D50 (5000 К)', + 'D55' => 'D55 (5500 К)', + 'D65' => 'D65 (6500 К)', + 'D75' => 'D75 (7500 К)', + 'Day White Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° – Дневной белый (5050 К)', + 'Daylight' => 'Дневной Ñвет (5500 К)', + 'Daylight Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° дневного Ñвета (6400 К)', + 'Fine Weather' => 'ЯÑÐ½Ð°Ñ Ð¿Ð¾Ð³Ð¾Ð´Ð° (5500 К)', + 'Flash' => 'Ð’Ñпышка (5500 К)', + 'Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° (4150 К)', + 'ISO Studio Tungsten' => 'Ð¡Ñ‚ÑƒÐ´Ð¸Ð¹Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° Ð½Ð°ÐºÐ°Ð»Ð¸Ð²Ð°Ð½Ð¸Ñ (3200 К)', + 'Other' => 'Другой иÑточник Ñвета', + 'Shade' => 'Тень (7500 К)', + 'Standard Light A' => 'Стандартное оÑвещение A (2850 К)', + 'Standard Light B' => 'Стандартное оÑвещение B (5500 К)', + 'Standard Light C' => 'Стандартное оÑвещение C (6500 К)', + 'Tungsten (Incandescent)' => 'Лампа Ð½Ð°ÐºÐ°Ð»Ð¸Ð²Ð°Ð½Ð¸Ñ (2850 К)', + 'Unknown' => 'ÐеизвеÑтно', + 'Warm White Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° – Тёплый Ñвет (2925 К)', + 'White Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° – Белый Ñвет (3525 К)', }, }, 'CalibrationIlluminant2' => { - Description => 'Калибровочный иллюминант â„–2', + Description => 'Калибровочное оÑвещение 2', PrintConv => { - 'Cloudy' => 'ОблачноÑÑ‚ÑŒ', - 'Cool White Fluorescent' => 'ФлуореÑцентный белый холодный (W 3800 - 4500K)', - 'Day White Fluorescent' => 'ФлуореÑцентный белый дневной', - 'Daylight' => 'Дневной Ñвет', - 'Daylight Fluorescent' => 'ФлуореÑцентный белый дневного Ñвета (D 5700 - 7100K)', - 'Fine Weather' => 'ЯÑÐ½Ð°Ñ Ð¿Ð¾Ð³Ð¾Ð´Ð°', - 'Flash' => 'Ð’Ñпышка', - 'Fluorescent' => 'ФлуореÑцентный', - 'ISO Studio Tungsten' => 'ISO Ð´Ð»Ñ Ñтудийных ламп накаливаниÑ', - 'Other' => 'другой иÑточник Ñвета', - 'Shade' => 'Тень', - 'Standard Light A' => 'Стандартный Ñвет A', - 'Standard Light B' => 'Стандартный Ñвет B', - 'Standard Light C' => 'Стандартный Ñвет C', - 'Tungsten (Incandescent)' => 'Лампа Ð½Ð°ÐºÐ°Ð»Ð¸Ð²Ð°Ð½Ð¸Ñ (Ñркий Ñвет)', - 'Unknown' => 'неизвеÑтно', - 'Warm White Fluorescent' => 'ФлуореÑцентный теплый белый (L 2600 - 3250K)', - 'White Fluorescent' => 'ФлуореÑцентный белый (WW 3250 - 3800K)', + 'Cloudy' => 'Облачно (6500 К)', + 'Cool White Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° – Холодный Ñвет (4150 К)', + 'D50' => 'D50 (5000 К)', + 'D55' => 'D55 (5500 К)', + 'D65' => 'D65 (6500 К)', + 'D75' => 'D75 (7500 К)', + 'Day White Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° – Дневной белый (5050 К)', + 'Daylight' => 'Дневной Ñвет (5500 К)', + 'Daylight Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° дневного Ñвета (6400 К)', + 'Fine Weather' => 'ЯÑÐ½Ð°Ñ Ð¿Ð¾Ð³Ð¾Ð´Ð° (5500 К)', + 'Flash' => 'Ð’Ñпышка (5500 К)', + 'Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° (4150 К)', + 'ISO Studio Tungsten' => 'Ð¡Ñ‚ÑƒÐ´Ð¸Ð¹Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° Ð½Ð°ÐºÐ°Ð»Ð¸Ð²Ð°Ð½Ð¸Ñ (3200 К)', + 'Other' => 'Другой иÑточник Ñвета', + 'Shade' => 'Тень (7500 К)', + 'Standard Light A' => 'Стандартное оÑвещение A (2850 К)', + 'Standard Light B' => 'Стандартное оÑвещение B (5500 К)', + 'Standard Light C' => 'Стандартное оÑвещение C (6500 К)', + 'Tungsten (Incandescent)' => 'Лампа Ð½Ð°ÐºÐ°Ð»Ð¸Ð²Ð°Ð½Ð¸Ñ (2850 К)', + 'Unknown' => 'ÐеизвеÑтное', + 'Warm White Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° – Тёплый Ñвет (2925 К)', + 'White Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° – Белый Ñвет (3525 К)', + }, + }, + 'CallForImage' => 'Звонок по изображению', + 'CamReverse' => 'Камера заднего вида', + 'CameraArrangementInterval' => 'Интервал раÑÐ¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ ÐºÐ°Ð¼ÐµÑ€Ñ‹', + 'CameraCalibration1' => 'ÐšÐ°Ð»Ð¸Ð±Ñ€Ð¾Ð²Ð¾Ñ‡Ð½Ð°Ñ Ð¼Ð°Ñ‚Ñ€Ð¸Ñ†Ð° фотокамеры 1', + 'CameraCalibration2' => 'ÐšÐ°Ð»Ð¸Ð±Ñ€Ð¾Ð²Ð¾Ñ‡Ð½Ð°Ñ Ð¼Ð°Ñ‚Ñ€Ð¸Ñ†Ð° фотокамеры 2', + 'CameraCalibrationSig' => 'Сигнатура калибровки камеры', + 'CameraDateTime' => 'Дата и Ð’Ñ€ÐµÐ¼Ñ ÐºÐ°Ð¼ÐµÑ€Ñ‹', + 'CameraElevationAngle' => 'Угол обзора камеры', + 'CameraFilename' => 'Ð˜Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð° Ñозданное камерой', + 'CameraID' => 'ID камеры', + 'CameraLabel' => 'Ðазвание камеры', + 'CameraMakeModel' => 'Модель камеры', + 'CameraModel' => 'Модель камеры', + 'CameraModelID' => 'ID модели камеры', + 'CameraOperator' => 'Кинооператор', + 'CameraOrientation' => { + Description => 'ÐžÑ€Ð¸ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ ÐºÐ°Ð¼ÐµÑ€Ñ‹', + PrintConv => { + 'Horizontal (normal)' => 'ГоризонтальнаÑ', + 'Rotate 180' => 'Поверот на 180°', + 'Rotate 270 CW' => 'Поворот на 270° по чаÑовой Ñтрелке', + 'Rotate 90 CW' => 'Поворот на 90° по чаÑовой Ñтрелке', }, }, - 'CameraCalibration1' => 'ÐšÐ°Ð»Ð¸Ð±Ñ€Ð¾Ð²Ð¾Ñ‡Ð½Ð°Ñ Ð¼Ð°Ñ‚Ñ€Ð¸Ñ†Ð° фотоаппарата â„–1', - 'CameraCalibration2' => 'ÐšÐ°Ð»Ð¸Ð±Ñ€Ð¾Ð²Ð¾Ñ‡Ð½Ð°Ñ Ð¼Ð°Ñ‚Ñ€Ð¸Ñ†Ð° фотоаппарата â„–2', - 'CameraCalibrationSig' => 'Сигнатура калибровки фотоаппарата', - 'CameraSerialNumber' => 'Серийный номер фотоаппарата', - 'Caption-Abstract' => 'ПодпиÑÑŒ', + 'CameraPitch' => 'Тангаж камеры (Ðаклон)', + 'CameraRoll' => 'Крен камеры (Вращение)', + 'CameraSerialNumber' => 'Серийный номер камеры', + 'CameraTemperature' => 'Температура камеры', + 'CameraType' => 'Тип камеры', + 'CameraYaw' => 'РыÑкание камеры (Поворот)', + 'CanSeekOnTime' => 'ВозможноÑÑ‚ÑŒ навигации по времени', + 'CanSeekToEnd' => 'ВозможноÑÑ‚ÑŒ перейти к концу', + 'CapHeight' => 'Ð’Ñ‹Ñота пропиÑных букв', + 'Caption' => 'Заголовок', + 'Caption-Abstract' => 'Подробное опиÑание', 'CaptionWriter' => 'Ðвтор подпиÑи', + 'CaptureSoftware' => 'ЗапиÑÑŒ изображений выполнен в', + 'CaptureXResolution' => 'Разрешение захвата по X', + 'CaptureXResolutionUnit' => { + Description => 'Единицы Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð·Ð°Ñ…Ð²Ð°Ñ‚Ð° по X', + PrintConv => { + '0.01 mm' => '0.01 мм', + '0.1 mm' => '0.1 мм', + '10 cm' => '10 Ñм', + '10 m' => '10 м', + '100 m' => '100 м', + 'cm' => 'Ñм', + 'km' => 'км', + 'm' => 'м', + 'mm' => 'мм', + 'um' => 'мкм', + }, + }, + 'CaptureYResolution' => 'Разрешение захвата по Y', + 'CaptureYResolutionUnit' => { + Description => 'Единицы Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð·Ð°Ñ…Ð²Ð°Ñ‚Ð° по Y', + PrintConv => { + '0.01 mm' => '0.01 мм', + '0.1 mm' => '0.1 мм', + '10 cm' => '10 Ñм', + '10 m' => '10 м', + '100 m' => '100 м', + 'cm' => 'Ñм', + 'km' => 'км', + 'm' => 'м', + 'mm' => 'мм', + 'um' => 'мкм', + }, + }, + 'CatalogSets' => 'Ðаборы каталога', 'Categories' => 'Категории', - 'Category' => 'Категории', + 'Category' => 'Группа', + 'CellLength' => 'Строк в матрице дизеринга или полутонированиÑ', + 'CellWidth' => 'Колонок в матрице дизеринга или полутонированиÑ', + 'ChannelMode' => { + Description => 'Режим канала', + PrintConv => { + 'Dual Channel' => 'Двухканальное', + 'Joint Stereo' => 'Объединённое Ñтерео', + 'Single Channel' => 'Моно', + 'Stereo' => 'Стерео', + }, + }, + 'ChannelUsage' => 'ИÑпользование канала', + 'Channels' => 'Каналов', + 'Chapter' => 'ЧаÑÑ‚ÑŒ', + 'ChapterCount' => 'КоличеÑтво глав', + 'ChapterName' => 'Ðазвание главы', + 'ChapterNumber' => 'Ðомер главы', + 'CharacterSet' => 'Ðабор Ñимволов', + 'Characters' => 'КоличеÑтво Ñимволов', + 'CharactersWithSpaces' => 'КоличеÑтво Ñимволов, Ð²ÐºÐ»ÑŽÑ‡Ð°Ñ Ð¿Ñ€Ð¾Ð±ÐµÐ»Ñ‹', 'ChromaBlurRadius' => 'Ð Ð°Ð´Ð¸ÑƒÑ ÑÐ³Ð»Ð°Ð¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð½Ð¾Ñти', - 'City' => 'Город', + 'ChromaticAberrationCorrParams' => 'Параметры коррекции хроматичеÑкой аберрации', + 'ChromaticAberrationCorrection' => { + Description => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ñ…Ñ€Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑкой аберрации', + PrintConv => { + 'Auto' => 'ÐвтоматичеÑкаÑ', + 'No correction params available' => 'ÐедоÑтупна', + 'Off' => 'Ðе включена', + 'On' => 'Включена', + }, + }, + 'Chromaticities' => 'ОÑновные цвета и Точка белого', + 'CircleOfConfusion' => 'Круг нерезкоÑти', + 'City' => 'Город проиÑÑ…Ð¾Ð¶Ð´ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ…', + 'Class' => 'КлаÑÑ', + 'Classification' => 'КлаÑÑификации', + 'ClassifyState' => 'КлаÑÐ¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ñтруктуры', + 'CleanFaxData' => { + Description => 'Ðаличие битых Ñтрок', + PrintConv => { + 'Clean' => 'Без битых Ñтрок', + 'Regenerated' => 'Битые Ñтроки воÑÑтановлены', + 'Unclean' => 'Битые Ñтроки не воÑÑтановлены', + }, + }, + 'ClipPath' => 'Обтравочный контур', + 'ClippingLimit' => 'ÐžÐ³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð½Ð° копирование', + 'ClippingPathName' => 'Ðазвание обтравочного контура', + 'CodePage' => { + Description => 'ÐšÐ¾Ð´Ð¾Ð²Ð°Ñ Ñтраница', + PrintConv => { + 'Windows Latin 1 (Western European)' => 'Windows Latin 1 (ЗападноевропейÑкаÑ)', + }, + }, + 'CodecFlavorID' => 'ID кодека Flavor', + 'CodedCharacterSet' => 'Кодовый набор Ñимволов', + 'CodedFrameSize' => 'Размер кодированного кадра', + 'CodestreamRegistration' => 'РегиÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ ÐºÐ¾Ð´Ð¾Ð²Ð¾Ð³Ð¾ потока', + 'CodingMethods' => { + Description => 'Метод ÑжатиÑ', + PrintConv => { + 'Baseline JPEG' => 'Базовое JPEG', + 'JBIG color' => 'Цветное JBIG', + 'Modified Huffman' => 'Одномерное – ÐœÐ¾Ð´Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð¥Ð°Ñ„Ñ„Ð¼Ð°Ð½Ð°', + 'Modified MR' => 'Двумерное – Modified Modified READ', + 'Modified Read' => 'Двумерное – Modified READ', + 'Unspecified compression' => 'ÐеизвеÑтное Ñжатие', + }, + }, + 'Collection' => 'КоллекциÑ', + 'CollectionName' => 'Ðазвание коллекции', + 'CollectionURI' => 'URI коллекции', + 'Collections' => 'Коллекции', + 'ColorAdjustmentMode' => { + Description => 'Режим регулировки цвета', + PrintConv => { + 'Off' => 'Ðе включён', + 'On' => 'Включен', + }, + }, + 'ColorCalibrationMatrix' => 'Матрица калибровки цвета', + 'ColorCharacterization' => 'Спецификации цвета', + 'ColorClass' => { + Description => 'Цветовой клаÑÑ', + PrintConv => { + '0 (None)' => '0 (Ðе указан)', + '1 (Winner)' => '1 (Лучшее)', + '2 (Winner alt)' => '2 (Лучшее Alt)', + '3 (Superior)' => '3 (Хорошее)', + '4 (Superior alt)' => '4 (Хорошее Alt)', + '5 (Typical)' => '5 (Обычноеl)', + '6 (Typical alt)' => '6 (Обычное Alt)', + '7 (Extras)' => '7 (ЭкÑтра)', + '8 (Trash)' => '8 (Хлам)', + }, + }, + 'ColorComponents' => 'Цветовых компонентов', + 'ColorCorrection' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð°', 'ColorEffect' => { PrintConv => { 'Sepia' => 'СепиÑ', }, }, 'ColorFilter' => 'Цветовой фильтр', - 'ColorMatrix1' => 'Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ð¼Ð°Ñ‚Ñ€Ð¸Ñ†Ð° â„–1', - 'ColorMatrix2' => 'Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ð¼Ð°Ñ‚Ñ€Ð¸Ñ†Ð° â„–2', + 'ColorGroup' => 'Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð°', + 'ColorHalftoningInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ тонировании – Цветное', + 'ColorMap' => 'Карта цветов', + 'ColorMatrix1' => 'Матрица Ð¿Ñ€ÐµÐ¾Ð±Ñ€Ð°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð¾Ð² 1', + 'ColorMatrix2' => 'Матрица Ð¿Ñ€ÐµÐ¾Ð±Ñ€Ð°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð¾Ð² 2', 'ColorMode' => { - Description => 'ТворчеÑкийСтиль', + Description => 'Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ð¼Ð¾Ð´ÐµÐ»ÑŒ', PrintConv => { 'Autumn Leaves' => 'ОÑенние лиÑÑ‚ÑŒÑ', - 'B&W' => 'Черно-белое', + 'B&W' => 'Чёрно-белое', + 'Bitmap' => 'МонохромнаÑ', + 'Black & White' => 'Чёрно-белый', 'Clear' => 'Прозрачный', + 'Color Palette' => 'Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ð¿Ð°Ð»Ð¸Ñ‚Ñ€Ð°', 'Deep' => 'Глубокий', + 'Duotone' => 'ДвуцветнаÑ', + 'Embed Adobe RGB' => 'Ð’Ñтроенный Adobe RGB', + 'Evening' => 'Вечер', + 'Grayscale' => 'Ð’ градациÑÑ… Ñерого', + 'Indexed' => 'ИндекÑированные цвета', + 'Indexed Color' => 'ИндекÑированный цвет', 'Landscape' => 'Пейзаж', 'Light' => 'Бледный', + 'Multichannel' => 'МногоканальнаÑ', + 'Natural' => 'Ðатуральный', + 'Natural color' => 'Ðатуральный цвет', + 'Natural sRGB' => 'Ðатуральный sRGB', + 'Natural+ sRGB' => 'Ðатуральный+ sRGB', 'Neutral' => 'Ðейтральный', + 'Night Portrait' => 'Ðочной портрет', + 'Night Scene' => 'ÐÐ¾Ñ‡Ð½Ð°Ñ Ñцена', 'Night View' => 'Ðочной вид', - 'Night View/Portrait' => 'Ðочной портрет', + 'Night View/Portrait' => 'Ðочной вид/портрет', 'Portrait' => 'Портрет', - 'Standard' => 'Стандартное', + 'RGB Color' => 'Цвет RGB', + 'Sepia' => 'СепиÑ', + 'Solarization' => 'СолÑризациÑ', + 'Standard' => 'Стандартный', 'Sunset' => 'Закат', 'Vivid' => 'Яркий цвет', + 'Vivid color' => 'Яркий цвет', + 'n/a' => 'Ðет данных', + }, + }, + 'ColorNoiseReduction' => 'Щумодав – Уменьшение цветных шумов', + 'ColorPalette' => 'Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ð¿Ð°Ð»Ð¸Ñ‚Ñ€Ð°', + 'ColorPlanes' => 'Цветовые плоÑкоÑти', + 'ColorPrimaries' => 'Праймериз цвета', + 'ColorRepresentation' => { + Description => 'Цветовое предÑтавление', + PrintConv => { + '3 Components, Frame Sequential in Multiple Objects' => '3 компонента. ПоÑледовательноÑÑ‚ÑŒ кадров в неÑкольких объектах', + '3 Components, Frame Sequential in One Object' => '3 компонента. ПоÑледовательноÑÑ‚ÑŒ кадров в одном объекте', + '3 Components, Line Sequential' => '3 компонента. ПоÑÐ»ÐµÐ´Ð¾Ð²Ð°Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ñтрока', + '3 Components, Pixel Sequential' => '3 компонента. ПоÑледовательноÑÑ‚ÑŒ пикÑелей', + '3 Components, Single Frame' => '3 компонента. Один кадр', + '3 Components, Special Interleaving' => '3 компонента. Специальное чередование', + '4 Components, Frame Sequential in Multiple Objects' => '4 компонента. ПоÑледовательноÑÑ‚ÑŒ кадров в неÑкольких объектах', + '4 Components, Frame Sequential in One Object' => '4 компонента. ПоÑледовательноÑÑ‚ÑŒ кадров в одном объекте', + '4 Components, Line Sequential' => '4 компонента. ПоÑÐ»ÐµÐ´Ð¾Ð²Ð°Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ñтрока', + '4 Components, Pixel Sequential' => '4 компонента. ПоÑледовательноÑÑ‚ÑŒ пикÑелей', + '4 Components, Single Frame' => '4 компонента. Один кадр', + '4 Components, Special Interleaving' => '4 компонента. Специальное чередование', + 'Monochrome, Single Frame' => 'Монохромное. Один кадр', + 'No Image, Single Frame' => 'Ðет изображениÑ. Один кадр', }, }, + 'ColorResolutionDepth' => 'Глубина цвета', + 'ColorResponseUnit' => 'Единицы цветовой чувÑтвительноÑти', + 'ColorSamplersResource' => 'РеÑÑƒÑ€Ñ Ð±Ñ€Ð°Ð·Ñ†Ð¾Ð² цвета', + 'ColorSamplersResource2' => 'РеÑÑƒÑ€Ñ Ð±Ñ€Ð°Ð·Ñ†Ð¾Ð² цвета 2', + 'ColorSequence' => 'ПоÑледовательноÑÑ‚ÑŒ цветов', 'ColorSpace' => { - Description => 'Данные о цветовой Ñреде', + Description => 'Цветовое проÑтранÑтво', + PrintConv => { + 'BT 2020 Constant Luminance' => 'ПоÑтоÑÐ½Ð½Ð°Ñ ÑркоÑÑ‚ÑŒ BT 2020', + 'Calibrated RGB' => 'Калиброванный RGB', + 'Device CMYK' => 'УÑтройÑтво CMYK', + 'Device RGB' => 'УÑтройÑтво RGB', + 'Embedded Color Profile' => 'Ð’Ñтроенный цветовой профиль', + 'Grayscale' => 'Оттенки Ñерого', + 'ICC Profile' => 'ICC-профиль', + 'Linked Color Profile' => 'СвÑзанный цветовой профиль', + 'Uncalibrated' => 'Ðекалиброванное', + 'Undefined' => 'Ðе определено', + 'Windows Color Space' => 'Цветовое проÑтранÑтво Windows', + }, + }, + 'ColorSpecApproximation' => { + Description => 'Ð¡Ð¿ÐµÑ†Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð° – ÐппрокÑимациÑ', + PrintConv => { + 'Accurate' => 'ТочнаÑ', + 'Exceptional Quality' => 'Лучшее качеÑтво', + 'Not Specified' => 'Ðе указана', + 'Poor Quality' => 'Ðизкое качеÑтво', + 'Reasonable Quality' => 'Приемлемое качеÑтво', + }, + }, + 'ColorSpecData' => 'Ð¡Ð¿ÐµÑ†Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð° – Данные', + 'ColorSpecMethod' => { + Description => 'Ð¡Ð¿ÐµÑ†Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð° – Метод', PrintConv => { - 'ICC Profile' => 'Профиль ICC', - 'Uncalibrated' => 'Ðе калиброванный', + 'Any ICC' => 'Любой ICC', + 'Enumerated' => 'ПеречиÑлимый', + 'Restricted ICC' => 'Ограниченный ICC', + 'Vendor Color' => 'Цвет поÑтавщика', }, }, + 'ColorSpecPrecedence' => 'Ð¡Ð¿ÐµÑ†Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð° – Precedence', + 'ColorTable' => 'Таблица цвета', 'ColorTemperature' => 'Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ñ‚ÐµÐ¼Ð¿ÐµÑ€Ð°Ñ‚ÑƒÑ€Ð°', + 'ColorTemperatureAdj' => 'Регулировка температуры цвета', + 'ColorTemperatures' => 'Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ñ‚ÐµÐ¼Ð¿ÐµÑ€Ð°Ñ‚ÑƒÑ€Ð°', + 'ColorTransferFuncs' => 'Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¿ÐµÑ€ÐµÐ½Ð¾Ñа – Цветное', + 'ColorType' => { + Description => 'Тип цвета', + PrintConv => { + 'Grayscale' => 'Ð“Ñ€Ð°Ð´Ð°Ñ†Ð¸Ñ Ñерого', + 'Grayscale with Alpha' => 'Ð“Ñ€Ð°Ð´Ð°Ñ†Ð¸Ñ Ñерого Ñ Ðльфа-каналом', + 'Palette' => 'Палитра', + 'RGB with Alpha' => 'RGB Ñ Ðльфа-каналом', + }, + }, 'ColorimetricReference' => 'КолориметричеÑкий Ñталон', + 'Colorimetry' => 'КолориметриÑ', + 'Colors' => 'Цвета', + 'Command' => 'Команда', + 'CommandLineArguments' => 'Ðргументы командной Ñтроки', 'Comment' => 'Комментарий', - 'ComponentsConfiguration' => 'Значение каждого компонента', - 'CompressedBitsPerPixel' => 'Режим ÑÐ¶Ð°Ñ‚Ð¸Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ', + 'CommentLen' => 'Комментарий Len', + 'CommentTime' => 'Ð’Ñ€ÐµÐ¼Ñ ÐºÐ¾Ð¼Ð¼ÐµÐ½Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ', + 'Comments' => 'Комментарии', + 'CommonNetworkRelLink' => 'ÐžÐ±Ñ‰Ð°Ñ Ñеть Rel Link', + 'CommonPathSuffix' => 'Ð¡ÑƒÑ„Ñ„Ð¸ÐºÑ Ð¾Ð±Ñ‰ÐµÐ³Ð¾ пути', + 'Company' => 'ОрганизациÑ', + 'CompatibleBrands' => 'СовмеÑтимые марки', + 'CompatibleFontName' => 'Ðазвание ÑовмеÑтимого шрифта', + 'ComponentDefinition' => 'Определение компонента', + 'ComponentMapping' => 'СопоÑтавление компонентов', + 'ComponentsConfiguration' => { + Description => 'ÐšÐ¾Ð½Ñ„Ð¸Ð³ÑƒÑ€Ð°Ñ†Ð¸Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÐµÐ½Ñ‚Ð¾Ð²', + PrintConv => { + 'Alpha (matte)' => 'Ðльфа-канал (маÑка)', + 'Alpha, B, G, R' => 'Ðльфа-канал, B, G, R', + 'Blue (B)' => 'Синий (B)', + 'Chrominance (Cb, Cr, subsampled by two)' => 'ЦветноÑÑ‚ÑŒ (Cb, Cr, ÑубдиÑÐºÑ€ÐµÑ‚Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° два)', + 'Composite video' => 'Композитное видео', + 'Depth (Z)' => 'Глубина (Z)', + 'Green (G)' => 'Зелёный (G)', + 'Luminance (Y)' => 'ЯркоÑÑ‚ÑŒ (Y)', + 'R, G, B, Alpha' => 'R, G, B, Ðльфа-канал', + 'Red (R)' => 'КраÑный (R)', + 'User-defined 2 component element' => '2-компонентный Ñлемент определÑемый пользователем', + 'User-defined 3 component element' => '3-компонентный Ñлемент определÑемый пользователем', + 'User-defined 4 component element' => '4-компонентный Ñлемент определÑемый пользователем', + 'User-defined 5 component element' => '5-компонентный Ñлемент определÑемый пользователем', + 'User-defined 6 component element' => '6-компонентный Ñлемент определÑемый пользователем', + 'User-defined 7 component element' => '7-компонентный Ñлемент определÑемый пользователем', + 'User-defined 8 component element' => '8-компонентный Ñлемент определÑемый пользователем', + 'User-defined single component' => 'Один компонент определÑемый пользователем', + }, + }, + 'Composer' => 'Композитор', + 'CompositeImage' => { + Description => 'СоÑтавное изображение', + PrintConv => { + 'Composite Image Captured While Shooting' => 'Полученное во Ð²Ñ€ÐµÐ¼Ñ Ñъёмки', + 'General Composite Image' => 'Созданное в редакторе', + 'Not a Composite Image' => 'Ðет', + 'Unknown' => 'ГеизвеÑтно', + }, + }, + 'CompositeImageCount' => 'СоÑтавное изображение – КоличеÑтво', + 'CompositeImageExposureTimes' => 'СоÑтавное изображение – Выдержка', + 'Composition' => 'КомпозициÑ', + 'CompositionOptions' => 'Варианты композиции', + 'Compressed' => { + Description => 'Сжатый', + PrintConv => { + 'False' => 'Ðет', + 'True' => 'Да', + }, + }, + 'CompressedBitsPerPixel' => 'Сжатых бит на пикÑель', + 'CompressedSize' => 'Сжатый размер', 'Compression' => { - Description => 'Схема ÑжатиÑ', + Description => 'Метод ÑжатиÑ', PrintConv => { + '4-Bit RLE' => '4-битное RLE', + '8-Bit RLE' => '8-битное RLE', + 'Bitfields' => 'Битовые полÑ', + 'Fractal' => 'Фрактальное', 'JPEG' => 'JPEG Ñжатие', - 'Uncompressed' => 'без ÑжатиÑ', + 'JPEG (old-style)' => 'JPEG (Ñтарый Ñтиль)', + 'Modified Huffman' => 'Модифицированное кодирование Хаффмана', + 'Modified Modified READ' => 'Modified Modified READ (MMR)', + 'Modified READ' => 'Modified READ (MR)', + 'None' => 'Без ÑжатиÑ', + 'RLE Encoding' => 'Кодирование RLE', + 'Uncompressed' => 'ÐеÑжатый', + 'ZIP with prediction' => 'ZIP Ñ Ð¿Ñ€ÐµÐ´Ñказанием', + 'ZIP without prediction' => 'ZIP без предÑказаниÑ', + }, + }, + 'CompressionFactor' => 'КоÑффициент ÑжатиÑ', + 'CompressionLevel' => 'Уровень ÑжатиÑ', + 'CompressionType' => 'Тип ÑжатиÑ', + 'CompressorName' => 'Ðазвание компреÑÑора', + 'ConditionalFEC' => 'КомпенÑÐ°Ñ†Ð¸Ñ ÑкÑпозиции при Ñъёмке Ñо вÑпышкой', + 'Confidence' => 'КонфидециальноÑÑ‚ÑŒ', + 'ConfidenceLevel' => 'Интервал раÑÐ¿Ð¾Ð·Ð½Ð°Ð²Ð°Ð½Ð¸Ñ Ð»Ð¸Ñ†Ð°', + 'ConfidenceMime' => 'MIME-тип конфидециального изображениÑ', + 'ConfirmedObjectSize' => 'Подтверждённый размер объекта', + 'ConsecutiveBadFaxLines' => 'КоличеÑтво поÑледовательных битых Ñтрок', + 'ConstrainedCropHeight' => 'ÐŸÑ€Ð¾Ð¿Ð¾Ñ€Ñ†Ð¸Ð¾Ð½Ð°Ð»ÑŒÐ½Ð°Ñ Ð¾Ð±Ñ€ÐµÐ·ÐºÐ° – Ð’Ñ‹Ñота', + 'ConstrainedCropWidth' => 'ÐŸÑ€Ð¾Ð¿Ð¾Ñ€Ñ†Ð¸Ð¾Ð½Ð°Ð»ÑŒÐ½Ð°Ñ Ð¾Ð±Ñ€ÐµÐ·ÐºÐ° – Ширина', + 'Contact' => 'Контакт', + 'ContainerVersion' => 'ВерÑÐ¸Ñ ÐºÐ¾Ð½Ñ‚ÐµÐ¹Ð½ÐµÑ€Ð°', + 'ContentDisposition' => 'РаÑпорÑжение Ñодержимым', + 'ContentIdentifier' => 'Идентификатор контента', + 'ContentLanguage' => 'Язык контента', + 'ContentLocationCode' => 'Контент – Код Ñтраны', + 'ContentLocationName' => 'Контент – Страна', + 'ContentProtected' => { + Description => 'Контент защищен', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'ContentProtectedPercent' => 'Контент защищен – Процент', + 'ContentRating' => { + Description => 'ВозраÑтной рейтинг контента', + PrintConv => { + 'Adult Supervision Recommended' => 'Под наблюдением взроÑлых', + 'Adults Only' => 'Только Ð´Ð»Ñ Ð²Ð·Ñ€Ð¾Ñлых', + 'All Ages' => 'Ð”Ð»Ñ Ð»ÑŽÐ±Ð¾Ð³Ð¾ возраÑта', + 'No Rating' => 'ВозраÑÑ‚Ð½Ð°Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð° не указана', + 'Older Children' => 'Старшим детÑм', + 'Older Teens' => 'Старшим подроÑткам', + 'Younger Teens' => 'Младшим подроÑткам', }, }, + 'ContentScriptType' => 'Язык Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñценариев', + 'ContentStyleType' => 'Язык таблицы Ñтилей', + 'ContentType' => 'MIME-тип документа', + 'ContiguousCodestream' => 'Смежный кодовый поток', 'Contrast' => { Description => 'КонтраÑтноÑÑ‚ÑŒ', PrintConv => { - 'High' => 'Резко', - 'Low' => 'ÐœÑгко', - 'Normal' => 'Стандарт', + 'High' => 'Ð’Ñ‹ÑокаÑ', + 'Low' => 'ÐизкаÑ', + 'Normal' => 'СтандартнаÑ', + }, + }, + 'ContrastAdj' => 'Регулировка контраÑта', + 'Contributor' => 'Соавтор', + 'Controller' => 'Контроллер', + 'ConvergenceAngle' => 'Угол ÑхождениÑ', + 'ConvergenceBaseImage' => { + Description => 'СходимоÑÑ‚ÑŒ базового изображениÑ', + PrintConv => { + 'Equivalent for Both Viewpoints' => 'Эквивалент Ð´Ð»Ñ Ð¾Ð±ÐµÐ¸Ñ… точек проÑмотра', + 'Left Viewpoint' => 'Ð›ÐµÐ²Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° проÑмотра', + 'Right Viewpoint' => 'ÐŸÑ€Ð°Ð²Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° проÑмотра', + }, + }, + 'ConvergenceDistance' => 'РаÑÑтоÑние ÑходимоÑти', + 'Converter' => 'Конвертер', + 'Copyright' => 'ÐвторÑкое право', + 'CopyrightFileName' => 'Ðазвание файла авторÑкого права', + 'CopyrightFlag' => { + Description => 'Флаг авторÑкого права', + PrintConv => { + 'False' => 'Ðет', + 'True' => 'ЕÑÑ‚ÑŒ', + }, + }, + 'CopyrightLen' => 'ÐвторÑкое право Len', + 'CopyrightNotice' => 'ÐвторÑкое право', + 'CopyrightOwner' => 'Правообладатель', + 'CopyrightOwnerID' => 'PLUS-ID правообладателÑ', + 'CopyrightOwnerImageID' => 'ID Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ñвоенный правообладателем', + 'CopyrightOwnerName' => 'Ð˜Ð¼Ñ Ð¿Ñ€Ð°Ð²Ð¾Ð¾Ð±Ð»Ð°Ð´Ð°Ñ‚ÐµÐ»Ñ', + 'CopyrightRegistrationNumber' => 'РегиÑтрационный номер авторÑкого права', + 'CopyrightStatus' => { + Description => 'Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ', + PrintConv => { + 'Protected' => 'Защищено', + 'Public Domain' => 'Ð’Ñеобщее доÑтоÑние', + 'Unknown' => 'Ðе указано', }, }, - 'Copyright' => 'Владелец копирайта', - 'CopyrightNotice' => 'Уведомление об авторÑких правах', + 'CountInfo' => 'Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ подщёте', 'Country' => 'Страна', + 'Country-PrimaryLocationCode' => 'Код Ñтраны', 'Country-PrimaryLocationName' => 'Страна', - 'CreateDate' => 'Дата ÑозданиÑ', + 'CountryCode' => 'Код Ñтраны', + 'CoverArt' => 'Обложка', + 'CoverArtMIMEType' => 'MIME тип обложки', + 'CoverArtType' => 'Тип обложки', + 'Coverage' => 'Охват', + 'CreateDate' => 'Дата оцифровки', + 'CreatedBy' => 'Создан', 'CreationDate' => 'Дата ÑозданиÑ', - 'Credit' => 'ФамилиÑ', - 'CurrentICCProfile' => 'Текущий ICC профиль', - 'CurrentPreProfileMatrix' => 'Ð¢ÐµÐºÑƒÑ‰Ð°Ñ Ð¿Ñ€ÐµÐ´Ð²Ð°Ñ€Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ñ†Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ð¼Ð°Ñ‚Ñ€Ð¸Ñ†Ð°', + 'CreationTime' => 'Ð’Ñ€ÐµÐ¼Ñ ÑозданиÑ', + 'CreativeStyleWasChanged' => { + Description => 'ТворчеÑкий Ñтиль был изменён', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'Creator' => 'Создатель', + 'CreatorAppID' => { + Description => 'ID Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñоздавшего файл', + PrintConv => { + 'Unknown' => 'ÐеизвеÑтное', + }, + }, + 'CreatorAppVersion' => 'ВерÑÐ¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ', + 'CreatorBuildNumber' => 'Приложение – Ðомер Ñборки', + 'CreatorBuildNumber2' => 'Приложение – Ðомер Ñборки 2', + 'CreatorMajorVersion' => 'Приложение – ÐœÐ°Ð¶Ð¾Ñ€Ð½Ð°Ñ Ð²ÐµÑ€ÑиÑ', + 'CreatorMinorVersion' => 'Приложение – ÐœÐ¸Ð½Ð¾Ñ€Ð½Ð°Ñ Ð²ÐµÑ€ÑиÑ', + 'CreatorOpenWithUIOptions' => 'Открыт Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°Ð¼Ð¸ пользовательÑкого интерфейÑа', + 'CreatorSoftware' => 'Создан в приложении', + 'CreatorTool' => 'Создано в', + 'CreatorVersion' => 'ВерÑÐ¸Ñ Ð¸Ñходного приложениÑ', + 'Credit' => 'ПоÑтавщик', + 'CreditLineRequired' => { + Description => 'Политика кредитованиÑ', + PrintConv => { + 'Credit Adjacent To Image' => 'Кредит Ñ€Ñдом Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸ÐµÐ¼', + 'Credit in Credits Area' => 'Кредит в облаÑти кредитов', + 'Credit on Image' => 'Кредит на изображение', + 'Not Required' => 'Кредит не требуетÑÑ', + }, + }, + 'CropArea' => 'ОблаÑÑ‚ÑŒ кадрированиÑ', + 'CropBottom' => 'Обрезка Ñнизу', + 'CropH' => 'Ð’Ñ‹Ñота кадрированиÑ', + 'CropLeft' => 'Обрезка Ñлева', + 'CropRight' => 'Обрезка Ñправа', + 'CropRotation' => 'Поворот рамки кадрированиÑ', + 'CropTop' => 'Обрезка Ñверху', + 'CropW' => 'Ширина кадрированиÑ', + 'CropX' => 'Координаты ÐºÐ°Ð´Ñ€Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾ оÑи X', + 'CropXCommonOffset' => { + Description => 'Обрезка по X – Общее Ñмещение', + PrintConv => { + 'Common Offset Setting' => 'ÐžÐ±Ñ‰Ð°Ñ Ð½Ð°Ñтройка ÑмещениÑ', + 'Individual Offset Setting' => 'Ð˜Ð½Ð´Ð¸Ð²Ð¸Ð´ÑƒÐ°Ð»ÑŒÐ½Ð°Ñ Ð½Ð°Ñтройка ÑмещениÑ', + }, + }, + 'CropXOffset' => 'Обрезка по X – Смещение', + 'CropXOffset2' => 'Обрезка по X – Смещение 2', + 'CropXSize' => 'Размер обрезки по X', + 'CropXViewpointNumber' => 'Обрезка по X – Ðомер точки проÑмотра', + 'CropXViewpointNumber2' => 'Обрезка по X – Ðомер точки проÑмотра 2', + 'CropY' => 'Координаты ÐºÐ°Ð´Ñ€Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾ оÑи Y', + 'CropYCommonOffset' => { + Description => 'Обрезка по Y – Общее Ñмещение', + PrintConv => { + 'Common Offset Setting' => 'ÐžÐ±Ñ‰Ð°Ñ Ð½Ð°Ñтройка ÑмещениÑ', + 'Individual Offset Setting' => 'Ð˜Ð½Ð´Ð¸Ð²Ð¸Ð´ÑƒÐ°Ð»ÑŒÐ½Ð°Ñ Ð½Ð°Ñтройка ÑмещениÑ', + }, + }, + 'CropYOffset' => 'Обрезка по Y – Смещение', + 'CropYOffset2' => 'Обрезка по Y – Смещение 2', + 'CropYSize' => 'Размер обрезки по Y', + 'CropYViewpointNumber' => 'Обрезка по Y – Ðомер точки проÑмотра', + 'CropYViewpointNumber2' => 'Обрезка по Y – Ðомер точки проÑмотра 2', + 'CroppedAreaImageHeightPixels' => 'ИÑÑ…Ð¾Ð´Ð½Ð°Ñ Ð²Ñ‹Ñота Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð² пикÑелÑÑ…', + 'CroppedAreaImageWidthPixels' => 'ИÑÑ…Ð¾Ð´Ð½Ð°Ñ ÑˆÐ¸Ñ€Ð¸Ð½Ð° Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð² пикÑелÑÑ…', + 'CroppedAreaLeftPixels' => 'ÐžÐ±Ñ€ÐµÐ·Ð°Ð½Ð½Ð°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ Ñлева в пикÑелÑÑ…', + 'CroppedAreaTopPixels' => 'ÐžÐ±Ñ€ÐµÐ·Ð°Ð½Ð½Ð°Ñ Ð¾Ð±Ð»Ð°ÑÑ‚ÑŒ Ñверху в пикÑелÑÑ…', + 'Cropping' => { + Description => 'Кадрирование', + PrintConv => { + 'Off' => 'Ðе включено', + 'On' => 'Включено', + }, + }, + 'Cross-Reference' => 'ПерекреÑÑ‚Ð½Ð°Ñ ÑÑылка', + 'CueSheet' => 'Файл разметки (Cue Sheet)', + 'CurrentICCProfile' => 'Текущий ICC-профиль', + 'CurrentIPTCDigest' => 'Хеш Ñумма текущего IPTC', + 'CurrentPreProfileMatrix' => 'Текущий предварительный профиль матрицы', + 'CurrentVersion' => 'Ð¢ÐµÐºÑƒÑ‰Ð°Ñ Ð²ÐµÑ€ÑиÑ', + 'CursorSize' => 'Размер курÑора', + 'Curve0x' => 'ÐšÑ€Ð¸Ð²Ð°Ñ 0x', + 'Curve0y' => 'ÐšÑ€Ð¸Ð²Ð°Ñ 0y', + 'Curve1x' => 'ÐšÑ€Ð¸Ð²Ð°Ñ 1x', + 'Curve1y' => 'ÐšÑ€Ð¸Ð²Ð°Ñ 1y', + 'Curve2x' => 'ÐšÑ€Ð¸Ð²Ð°Ñ 2x', + 'Curve2y' => 'ÐšÑ€Ð¸Ð²Ð°Ñ 2y', + 'Curve3x' => 'ÐšÑ€Ð¸Ð²Ð°Ñ 3x', + 'Curve3y' => 'ÐšÑ€Ð¸Ð²Ð°Ñ 3y', + 'Curve4x' => 'ÐšÑ€Ð¸Ð²Ð°Ñ 4x', + 'Curve4y' => 'ÐšÑ€Ð¸Ð²Ð°Ñ 4y', + 'Custom1' => 'Дополнительное поле 1', + 'Custom10' => 'Дополнительное поле 10', + 'Custom2' => 'Дополнительное поле 2', + 'Custom3' => 'Дополнительное поле 3', + 'Custom4' => 'Дополнительное поле 4', + 'Custom5' => 'Дополнительное поле 5', + 'Custom6' => 'Дополнительное поле 6', + 'Custom7' => 'Дополнительное поле 7', + 'Custom8' => 'Дополнительное поле 8', + 'Custom9' => 'Дополнительное поле 9', 'CustomRendered' => { - Description => 'Обработка Ñнимков по перÑональным наÑтройкам', + Description => 'ПользовательÑкий рендеринг', PrintConv => { - 'Custom' => '"ПроцеÑÑ, наÑтроенный пользователем"', - 'Normal' => 'Ðормальный процеÑÑ', + 'Custom' => 'ПользовательÑкий', + 'Normal' => 'Обычный', + 'Panorama' => 'Панорама', + 'Portrait' => 'Портрет', + }, + }, + 'D-RangeOptimizerHighlight' => 'ÐžÐ¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸Ñ‡ÐµÑкого диапазона – Света', + 'D-RangeOptimizerMode' => { + Description => 'ÐžÐ¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸Ñ‡ÐµÑкого диапазона – Режим', + PrintConv => { + 'Auto' => 'ÐвтоматичеÑкий', + 'Manual' => 'Ручной', + 'Off' => 'Ðе включён', }, }, + 'D-RangeOptimizerShadow' => 'ÐžÐ¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸Ñ‡ÐµÑкого диапазона – Тени', + 'D-RangeOptimizerValue' => 'ÐžÐ¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸Ñ‡ÐµÑкого диапазона – Значение', + 'DCContinent' => 'DC – Континент', + 'DCCoordinatePrecision' => 'DC – ТочноÑÑ‚ÑŒ координат', + 'DCCoordinateUncertaintyInMeters' => 'DC – ПогрешноÑÑ‚ÑŒ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¾Ñ€Ð´Ð¸Ð½Ð°Ñ‚ (м)', + 'DCCountry' => 'DC – Страна', + 'DCCountryCode' => 'DC – Код Ñтраны', + 'DCCounty' => 'DC – Район', + 'DCDecimalLatitude' => 'DC – ГеографичеÑÐºÐ°Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ð° меÑта находки', + 'DCDecimalLongitude' => 'DC – ГеографичеÑÐºÐ°Ñ Ð´Ð¾Ð»Ð³Ð¾Ñ‚Ð° меÑта находки', + 'DCEvent' => 'Событие/Явление', + 'DCFootprintSRS' => 'DC – Footprint SRS', + 'DCFootprintSpatialFit' => 'DC – Footprint Spatial Fit', + 'DCFootprintWKT' => 'DC – Footprint WKT', + 'DCGeodeticDatum' => 'DC – ГеографичеÑÐºÐ°Ñ ÑиÑтема координат', + 'DCGeoreferenceProtocol' => 'DC – ОпиÑание метода Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¾Ñ€Ð´Ð¸Ð½Ð°Ñ‚', + 'DCGeoreferenceRemarks' => 'DC – Комментарии к геопривÑзке', + 'DCGeoreferenceSources' => 'DC – ИÑточники геопривÑзки', + 'DCGeoreferenceVerificationStatus' => 'DC – Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€ÐºÐ¸ геопривÑзки', + 'DCGeoreferencedBy' => 'DC – Люди Ñоздавшие геопривÑзку', + 'DCGeoreferencedDate' => 'DC – Дата геопривÑзки', + 'DCHigherGeography' => 'DC – Крупные географичеÑкие объекты', + 'DCHigherGeographyID' => 'DC – ID географичеÑкого региона', + 'DCIsland' => 'DC – ОÑтров', + 'DCIslandGroup' => 'DC – Группа оÑтровов', + 'DCLocality' => 'DC – ОпиÑание меÑта находки', + 'DCLocationAccordingTo' => 'DC – ИÑточник данных о меÑтоположении', + 'DCLocationID' => 'DC – ID набора данных о меÑтоположении', + 'DCLocationRemarks' => 'DC – Комментарии к опиÑанию меÑтоположениÑ', + 'DCMaximumDepthInMeters' => 'DC – МакÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð³Ð»ÑƒÐ±Ð¸Ð½Ð° (м)', + 'DCMaximumDistanceAboveSurfaceInMeters' => 'DC – МакÑимальное диÑÑ‚Ð°Ð½Ñ†Ð¸Ñ Ð½Ð°Ð´ поверхноÑтью (м)', + 'DCMaximumElevationInMeters' => 'DC – МакÑимальное выÑота (м)', + 'DCMinimumDepthInMeters' => 'DC – ÐœÐ¸Ð½Ð¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð³Ð»ÑƒÐ±Ð¸Ð½Ð° (м)', + 'DCMinimumDistanceAboveSurfaceInMeters' => 'DC – Минимальное диÑÑ‚Ð°Ð½Ñ†Ð¸Ñ Ð½Ð°Ð´ поверхноÑтью (м)', + 'DCMinimumElevationInMeters' => 'DC – ÐœÐ¸Ð½Ð¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð²Ñ‹Ñота (м)', + 'DCMunicipality' => 'DC – Район', + 'DCPointRadiusSpatialFit' => 'DC – Point Radius Spatial Fit', + 'DCStateProvince' => 'DC – ОблаÑÑ‚ÑŒ', + 'DCTermsLocation' => 'DC – МеÑтоположение', + 'DCVerbatimCoordinateSystem' => 'DC – СиÑтема координат по первоиÑточнику', + 'DCVerbatimCoordinates' => 'DC – Координаты меÑта находки по первоиÑточнику', + 'DCVerbatimDepth' => 'DC – ОпиÑание глубины по первоиÑточнику', + 'DCVerbatimElevation' => 'DC – ОпиÑание выÑоты Ð¿Ð¾ первоиÑточнику', + 'DCVerbatimLatitude' => 'DC – Широта меÑÑ‚Ð¾Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾ первоиÑточнику', + 'DCVerbatimLocality' => 'DC – ОпиÑание меÑта по первоиÑточнику', + 'DCVerbatimLongitude' => 'DC – Долгота меÑÑ‚Ð¾Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾ первоиÑточнику', + 'DCVerbatimSRS' => 'DC – SRS по первоиÑточнику', + 'DCWaterBody' => 'DC – Водоём', + 'DNGAdobeData' => 'DNG – Данные Adobe', 'DNGBackwardVersion' => 'СовмеÑÑ‚Ð¸Ð¼Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ DNG', - 'DNGLensInfo' => 'Минимальное фокуÑное раÑÑтоÑние', + 'DNGLensInfo' => 'DNG – Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾Ð± объективе', + 'DNGPrivateData' => 'DNG – Данные производителÑ', 'DNGVersion' => 'ВерÑÐ¸Ñ DNG', + 'DOF' => 'Глубина резкоÑти', + 'DPP' => 'Digital Photo Professional (DPP)', + 'DPXFileSize' => 'Размер файла DPX', + 'DRMCommerceID' => 'DRM – КоммерчеÑкий ID', + 'DRMServerID' => 'DRM – ID Ñервера', + 'DRM_E-BookBaseID' => 'DRM – ID базы Ñлектронных книг', + 'DTVContent' => { + Description => 'Контент DTV', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'DataCompressionMethod' => 'Метод ÑÐ¶Ð°Ñ‚Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ…', + 'DataDump' => 'Вывод данных', + 'DataLocation' => { + Description => 'РаÑположение данных', + PrintConv => { + 'Downloaded Separately' => 'СкачиваетÑÑ Ð¾Ñ‚Ð´ÐµÐ»ÑŒÐ½Ð¾', + 'Local Music File' => 'Локальный музыкальный файл', + }, + }, + 'DataOffset' => 'Смещение данных', + 'DataOffsets' => 'Ð¡Ð¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ…', + 'DataPreparer' => 'Подготовка данных', + 'DataReference' => 'СÑылка на данные', + 'DataSign' => { + Description => 'ПодпиÑÑŒ данных', + PrintConv => { + 'Signed' => 'ПодпиÑан', + 'Unsigned' => 'ÐеподпиÑан', + }, + }, + 'DataSize' => 'Размер данных', + 'DataType' => { + Description => 'Тип данных', + PrintConv => { + 'Artwork' => 'Обложка', + }, + }, + 'DataWindow' => 'Окно данных', + 'DatabaseName' => 'Ðазвание базы данных', + 'Date' => 'Дата', + 'DateAcquired' => 'Дата приобретениÑ', 'DateCreated' => 'Дата ÑозданиÑ', - 'DateTimeOriginal' => 'ИÑÑ…Ð¾Ð´Ð½Ð°Ñ Ð´Ð°Ñ‚Ð° и времÑ', + 'DateIdentified' => 'Дата определениÑ', + 'DateSent' => 'Дата отправлениÑ', + 'DateTime' => 'Дата и времÑ', + 'DateTimeCompleted' => 'Дата завершениÑ', + 'DateTimeCreated' => 'Дата и Ð²Ñ€ÐµÐ¼Ñ ÑозданиÑ', + 'DateTimeDue' => 'Срок Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð·Ð°Ð´Ð°Ñ‡Ð¸', + 'DateTimeEnd' => 'Дата Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ ÑобытиÑ', + 'DateTimeOriginal' => 'Дата Ñъёмки', + 'DateTimeStamp' => 'Дата ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÑобытиÑ', + 'DateTimeStart' => 'Дата начала ÑобытиÑ', + 'DayOfWeek' => { + Description => 'День недели', + PrintConv => { + 'Friday' => 'ПÑтница', + 'Monday' => 'Понедельник', + 'Saturday' => 'Суббота', + 'Sunday' => 'ВоÑкреÑенье', + 'Thursday' => 'Четверг', + 'Tuesday' => 'Вторник', + 'Wednesday' => 'Среда', + }, + }, + 'Decode' => 'Декодирование', + 'DefaultAlarm' => 'Сигнал по-умолчанию', + 'DefaultBlackRender' => { + Description => 'Обработка чёрного по-умолчанию', + PrintConv => { + 'Auto' => 'ÐвтоматичеÑкаÑ', + 'None' => 'Ðе обрабатывать', + }, + }, + 'DefaultChar' => 'Символ замены', 'DefaultCropOrigin' => 'Положение обрезанного Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾-умолчанию', 'DefaultCropSize' => 'Размер обрезанного Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾-умолчанию', - 'DefaultScale' => 'Стандартный маÑштаб', - 'DeviceSettingDescription' => 'ОпиÑание наÑтроек уÑтройÑтва', - 'DigitalZoom' => 'Цифровой зум', - 'DigitalZoomRatio' => 'Показатель цифрового зума', - 'Directory' => '"Файл, размещение"', - 'DriveMode' => 'Режим ÑпуÑка', + 'DefaultImageColor' => 'Цвет Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾-умолчанию', + 'DefaultScale' => 'МаÑÑштаб по-умолчанию', + 'DefaultStyle' => 'Стиль по-умолчанию', + 'DefaultUserCrop' => 'ОблаÑÑ‚ÑŒ обрезки по-умолчанию', + 'DefineQuantizationTable' => 'Определение таблиц квантованиÑ', + 'Delay' => 'Задержка', + 'DelayTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð·Ð°Ð´ÐµÑ€Ð¶ÐºÐ¸', + 'DependentImage1EntryNumber' => 'ЗавиÑимое изображение 1 – Ðомер входа', + 'DependentImage2EntryNumber' => 'ЗавиÑимое изображение 2 – Ðомер входа', + 'Depth' => 'Глубина цвета', + 'DepthImage' => 'Глубина изображениÑ', + 'DepthMapTiff' => 'Карта глубины Tiff', + 'Descender' => 'ПодÑтрочный интервал', + 'Description' => 'ОпиÑание', + 'Designer' => 'Дизайнер', + 'DesignerURL' => 'URL дизайнера', + 'Destination' => 'Ðазначение', + 'DeviceID' => 'ID уÑтройÑтва', + 'DeviceName' => 'Ðазвание уÑтройÑтва', + 'DeviceSettingDescription' => 'ОпиÑание предуÑтановок камеры', + 'DewarpData' => 'КомпенÑÐ°Ñ†Ð¸Ñ Ð¾Ð¿Ñ‚Ð¸Ñ‡ÐµÑкого иÑÐºÐ°Ð¶ÐµÐ½Ð¸Ñ â€“ Данные', + 'DewarpFlag' => 'КомпенÑÐ°Ñ†Ð¸Ñ Ð¾Ð¿Ñ‚Ð¸Ñ‡ÐµÑкого иÑÐºÐ°Ð¶ÐµÐ½Ð¸Ñ â€“ Флаг', + 'DictionaryShortName' => 'Сокращенное название ÑловарÑ', + 'DigitalCreationDate' => 'Дата оцифровки файла', + 'DigitalCreationDateTime' => 'Дата и Ð²Ñ€ÐµÐ¼Ñ Ð¾Ñ†Ð¸Ñ„Ñ€Ð¾Ð²ÐºÐ¸ файла', + 'DigitalCreationTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð¾Ñ†Ð¸Ñ„Ñ€Ð¾Ð²ÐºÐ¸ файла', + 'DigitalSignature' => 'Ð¦Ð¸Ñ„Ñ€Ð¾Ð²Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ', + 'DigitalZoom' => { + Description => 'Цифровой зум', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'DigitalZoomOn' => { + Description => 'Цифровой зум', + PrintConv => { + 'Off' => 'Ðе включён', + 'On' => 'Включен', + }, + }, + 'DigitalZoomRatio' => 'КоÑффициент цифрового увеличениÑ', + 'Director' => 'Директор', + 'Directory' => 'Каталог', + 'DirectoryNumber' => 'Ðомер каталога', + 'DisallowCounterProposal' => 'Запретить вÑтречное предложение', + 'Disclaimer' => 'Отказ от ответÑтвенноÑти', + 'DisplayWindow' => 'Окно отображениÑ', + 'DisplayXResolution' => 'Разрешение Ñкрана по X', + 'DisplayXResolutionUnit' => { + Description => 'Единицы Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ñкрана по X', + PrintConv => { + '0.01 mm' => '0.01 мм', + '0.1 mm' => '0.1 мм', + '10 cm' => '10 Ñм', + '10 m' => '10 м', + '100 m' => '100 м', + 'cm' => 'Ñм', + 'km' => 'км', + 'm' => 'м', + 'mm' => 'мм', + 'um' => 'мкм', + }, + }, + 'DisplayYResolution' => 'Разрешение Ñкрана по Y', + 'DisplayYResolutionUnit' => { + Description => 'Единицы Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ñкрана по Y', + PrintConv => { + '0.01 mm' => '0.01 мм', + '0.1 mm' => '0.1 мм', + '10 cm' => '10 Ñм', + '10 m' => '10 м', + '100 m' => '100 м', + 'cm' => 'Ñм', + 'km' => 'км', + 'm' => 'м', + 'mm' => 'мм', + 'um' => 'мкм', + }, + }, + 'DisplayedUnitsX' => { + Description => 'Отображаемые единицы по X', + PrintConv => { + 'cm' => 'Сантиметры', + 'inches' => 'Дюймы', + }, + }, + 'DisplayedUnitsY' => { + Description => 'Отображаемые единицы по Y', + PrintConv => { + 'cm' => 'Сантиметры', + 'inches' => 'Дюймы', + }, + }, + 'Dispose' => 'Управление ÑлоÑми', + 'DistortionCompensation' => { + Description => 'КомпенÑÐ°Ñ†Ð¸Ñ Ð´Ð¸ÑторÑии', + PrintConv => { + 'Off' => 'Ðе включена', + 'On' => 'Включена', + 'n/a' => 'Ðет данных', + }, + }, + 'DistortionCorrParams' => 'Параметры коррекции диÑторÑии', + 'DistortionCorrection' => { + Description => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð´Ð¸ÑторÑии', + PrintConv => { + 'Auto' => 'ÐвтоматичеÑкаÑ', + 'Auto fixed by lens' => 'ÐвтоматичеÑÐºÐ°Ñ Ð¿Ð¾ объективу', + 'No correction params available' => 'Ðе доÑтупна', + 'Off' => 'Ðе включена', + }, + }, + 'DistortionCorrectionAlreadyApplied' => 'Применена ÐºÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð´Ð¸ÑторÑии', + 'Distribution' => 'ОпиÑание', + 'DittoKey' => { + Description => 'Ключь Ditto', + PrintConv => { + 'New' => 'Заново', + 'Same' => 'Так же', + }, + }, + 'DjVuVersion' => 'ВерÑÐ¸Ñ DjVu', + 'DoNotForwardMeeting' => 'Ðе передвигать вÑтречу', + 'DocClass' => 'СоÑтоÑние документа', + 'DocRights' => 'Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð°Ð²Ñ‚Ð¾Ñ€Ñкого права', + 'DocType' => 'Тип документа', + 'Document' => 'Документ', + 'DocumentAncestors' => 'Предки документа', + 'DocumentHistory' => 'ИÑÑ‚Ð¾Ñ€Ð¸Ñ Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°', + 'DocumentName' => 'Ðазвание документа', + 'DocumentNotes' => 'Комментарии к документу', + 'DocumentUsageRights' => 'Права на иÑпользование Документа', + 'DotRange' => 'Ð—Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ ÐºÐ¾Ð¼Ð¿Ð¾Ð½ÐµÐ½Ñ‚Ð° ÑоответÑтвующих точке', + 'DriveMode' => { + Description => 'Режим ÑпуÑка', + PrintConv => { + 'Continuous Shooting' => 'Ð¡ÐµÑ€Ð¸Ð¹Ð½Ð°Ñ Ñъёмка', + 'Self-timer Operation' => 'Съёмка Ñ Ð°Ð²Ñ‚Ð¾ÑпуÑком', + 'Single-frame Shooting' => 'ÐŸÐ¾ÐºÐ°Ð´Ñ€Ð¾Ð²Ð°Ñ Ñъёмка', + }, + }, + 'DriveSerialNumber' => 'Серийный номер привода', + 'DriveType' => { + Description => 'Тип накопителÑ', + PrintConv => { + 'Fixed Disk' => 'УÑтановленный диÑк', + 'Invalid Root Path' => 'Ðеверный корневой путь', + 'Ram Disk' => 'Ram диÑк', + 'Remote Drive' => 'Удаленный диÑк', + 'Removable Media' => 'Съемный диÑк', + 'Unknown' => 'ÐеизвеÑтный', + }, + }, + 'DuotoneHalftoningInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ тонировании – Двуцветное', + 'DuotoneImageInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ двухцветном изображении', + 'DuotoneTransferFuncs' => 'Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¿ÐµÑ€ÐµÐ½Ð¾Ñа – Двуцветное', + 'Duration' => 'ПродолжительноÑÑ‚ÑŒ', 'DynamicRangeOptimizer' => { - Description => 'Оптим.Д-диапаз.', - PrintConv => { - 'Advanced Auto' => 'Улучш.авто', - 'Advanced Lv1' => 'Улучш.уровень1', - 'Advanced Lv2' => 'Улучш.уровень2', - 'Advanced Lv3' => 'Улучш.уровень3', - 'Advanced Lv4' => 'Улучш.уровень4', - 'Advanced Lv5' => 'Улучш.уровень5', - 'Auto' => 'Ðвто', - 'Off' => 'Отключено', - 'Standard' => 'Стандартное', + Description => 'ÐžÐ¿Ñ‚Ð¸Ð¼Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð´Ð¸Ð½Ð°Ð¼Ð¸Ñ‡ÐµÑкого диапазона', + PrintConv => { + 'Advanced Auto' => 'РаÑширеннаÑ. ÐвтоматичеÑкаÑ', + 'Advanced Lv1' => 'РаÑширеннаÑ. Уровень 1', + 'Advanced Lv2' => 'РаÑширеннаÑ. Уровень 2', + 'Advanced Lv3' => 'РаÑширеннаÑ. Уровень 3', + 'Advanced Lv4' => 'РаÑширеннаÑ. Уровень 4', + 'Advanced Lv5' => 'РаÑширеннаÑ. Уровень 5', + 'Auto' => 'ÐвтоматичеÑкаÑ', + 'Off' => 'Ðе включена', + 'Standard' => 'СтандартнаÑ', + }, + }, + 'EPSOptions' => 'Параметры EPS', + 'EXRVersion' => 'ВерÑÐ¸Ñ EXR', + 'EarliestAgeOrLowestStage' => 'Самый ранний век/Ðизший ÑруÑ', + 'EarliestEonOrLowestEonothem' => 'Самый ранний Ñон/ÐÐ¸Ð·ÑˆÐ°Ñ Ñонотема', + 'EarliestEpochOrLowestSeries' => 'Ð¡Ð°Ð¼Ð°Ñ Ñ€Ð°Ð½Ð½ÑÑ Ñпоха/Ðизший отдел', + 'EarliestEraOrLowestErathem' => 'Ð¡Ð°Ð¼Ð°Ñ Ñ€Ð°Ð½Ð½ÑÑ Ñра/ÐÐ¸Ð·ÑˆÐ°Ñ Ñратема', + 'EarliestPeriodOrLowestSystem' => 'Самый ранний период/ÐÐ¸Ð·ÑˆÐ°Ñ ÑиÑтема', + 'EdgeNoiseReduction' => 'Щумоподавление – Уменьшение контурных шумов', + 'EditStatus' => 'Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ', + 'Edition' => 'Издание', + 'EditorialUpdate' => { + Description => 'Тип обновлениÑ', + PrintConv => { + 'Additional language' => 'Дополнительный Ñзык', + }, + }, + 'EffectiveBW' => 'Эффективный Чёрно-Белый', + 'EffectsVisible' => 'ВидимоÑÑ‚ÑŒ Ñффектов', + 'ElectronicImageStabilization' => 'Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ ÑÑ‚Ð°Ð±Ð¸Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ', + 'EmbeddedFileName' => 'Ðазвание вÑтроенного файла', + 'EmbeddedFileUsageRights' => 'Права на иÑпользование вÑтроенных файлов', + 'EmbeddedImage' => 'Ð’Ñтроенное изображение', + 'EmbeddedImageColorSpace' => 'Ð’Ñтроенное изображение – Цветовое проÑтранÑтво', + 'EmbeddedImageFilter' => 'Ð’Ñтроенное изображение – Фильтр', + 'EmbeddedImageHeight' => 'Ð’Ñтроенное изображение – Ð’Ñ‹Ñота', + 'EmbeddedImageWidth' => 'Ð’Ñтроенное изображение – Ширина', + 'EmbeddedJPG' => 'Ð’Ñтроенный JPG', + 'EmbeddedPNG' => 'Ð’Ñтроенный PNG', + 'EmbeddedVideo' => 'Ð’Ñтроенное видео', + 'EmbeddedXMPDigest' => 'Хеш-Ñумма вÑтроенного XMP', + 'Emphasis' => { + Description => 'Ðкцент', + PrintConv => { + 'None' => 'Ðет', + }, + }, + 'EncodeTime' => 'Ð’Ñ€ÐµÐ¼Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ', + 'EncodedBy' => 'Закодировал', + 'EncodedUsing' => 'Закодировано Ñ Ð¸Ñпользованием', + 'Encoder' => 'Кодер', + 'EncoderOptions' => 'ÐаÑтройки кодера', + 'EncoderVersion' => 'ВерÑÐ¸Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ñ‰Ð¸ÐºÐ°', + 'Encoding' => 'Кодирование', + 'EncodingProcess' => { + Description => 'ПроцеÑÑ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ', + PrintConv => { + 'Baseline DCT, Huffman coding' => 'Базовое DCT, кодирование Хаффмана', + 'Extended sequential DCT, Huffman coding' => 'РаÑширенное поÑледовательное DCT, кодирование Хаффмана', + 'Extended sequential DCT, arithmetic coding' => 'РаÑширенное поÑледовательное DCT, арифметичеÑкое кодирование', + 'Lossless, Differential Huffman coding' => 'Без потерь, дифференциальное кодирование Хаффмана', + 'Lossless, Huffman coding' => 'Без потерь, кодирование Хаффмана', + 'Lossless, arithmetic coding' => 'Без потерь, арифметичеÑкое кодирование', + 'Lossless, differential arithmetic coding' => 'Без потерь, дифференциальное арифметичеÑкое кодирование', + 'Progressive DCT, Huffman coding' => 'ПрогреÑÑивное DCT, кодирование Хаффмана', + 'Progressive DCT, arithmetic coding' => 'ПрогреÑÑивное DCT, арифметичеÑкое кодирование', + 'Progressive DCT, differential Huffman coding' => 'ПрогреÑÑивное DCT, дифференциальное кодирование Хаффмана', + 'Progressive DCT, differential arithmetic coding' => 'ПрогреÑÑивное DCT, дифференциальное арифметичеÑкое кодирование', + 'Sequential DCT, differential Huffman coding' => 'ПоÑледовательное DCT, Дифференциальное кодирование Хаффмана', + 'Sequential DCT, differential arithmetic coding' => 'ПоÑледовательное DCT, дифференциальное арифметичеÑкое кодирование', + }, + }, + 'EncodingScheme' => 'Схема кодированиÑ', + 'Encryption' => { + Description => 'Шифрование', + PrintConv => { + 'None' => 'Ðет', + 'Old Mobipocket' => 'Старый Mobipocket', }, }, - 'ExifImageHeight' => 'ДопуÑÑ‚Ð¸Ð¼Ð°Ñ Ð²Ñ‹Ñота Ñнимка', - 'ExifImageWidth' => 'ДопуÑÑ‚Ð¸Ð¼Ð°Ñ ÑˆÐ¸Ñ€Ð¸Ð½Ð° Ñнимка', - 'ExifOffset' => 'Exif IFD указатель', - 'ExifVersion' => 'Exif верÑиÑ', - 'ExposureCompensation' => '"ЭкÑпозициÑ, калибровка"', - 'ExposureIndex' => '"ЭкÑпозициÑ, показатель"', + 'EncryptionKey' => 'Ключ шифрованиÑ', + 'EndPoints' => 'Конечные точки', + 'EndTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ', + 'EndUser' => 'Конечный пользователь', + 'EndUserID' => 'PLUS-ID пользователÑ', + 'EndUserName' => 'Ð˜Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ', + 'EnvelopeNumber' => 'Ðомер конверта', + 'EnvelopePriority' => { + Description => 'Приоритет конверта', + PrintConv => { + '0 (reserved)' => '0 (Ð’ резерве)', + '1 (most urgent)' => '1 (Ðеотложное)', + '5 (normal urgency)' => '5 (Обычное)', + '8 (least urgent)' => '8 (Ðе Ñрочное)', + '9 (user-defined priority)' => '9 (ПользовательÑкий приоритет)', + }, + }, + 'EnvelopeRecordVersion' => 'ВерÑÐ¸Ñ Envelope Record', + 'EnvironmentMap' => { + Description => 'Карта окружениÑ', + PrintConv => { + 'Cube' => 'Куб', + 'Latitude/Longitude' => 'Широта/Долгота', + }, + }, + 'EquipmentInstitution' => 'Оборудование учреждениÑ', + 'EquipmentManufacturer' => 'Производитель оборудованиÑ', + 'Error' => 'Ошибка', + 'EscChar' => 'Escape-Ñимвол', + 'EscapeStatus' => 'Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð¿Ñ€Ð¾Ð±ÐµÐ³Ð°', + 'Event' => 'Событие', + 'EventDate' => 'Дата ÑобытиÑ', + 'EventDay' => 'День(и) ÑобытиÑ', + 'EventEarliestDate' => 'Дата начала ÑобытиÑ', + 'EventEndDayOfYear' => 'День года Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ ÑобытиÑ', + 'EventFieldNotes' => 'Полевые заметки о Ñобытии', + 'EventFieldNumber' => 'Ðомер полевых заметок о Ñобытии', + 'EventHabitat' => 'Ðреал ÑобытиÑ', + 'EventID' => 'ID ÑобытиÑ', + 'EventLatestDate' => 'Дата Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ ÑобытиÑ', + 'EventMonth' => 'МеÑÑц ÑобытиÑ', + 'EventNumber' => 'Ðомер ÑобытиÑ', + 'EventParentEventID' => 'ID оÑновного ÑобытиÑ', + 'EventRemarks' => 'Комментарии к Ñобытию', + 'EventSampleSizeUnit' => 'Событие – Единицы размера', + 'EventSampleSizeValue' => 'Событие – Размер образца', + 'EventSamplingEffort' => 'Событие – Затраченные уÑилиÑ', + 'EventSamplingProtocol' => 'Событие – Метод иÑÑледованиÑ', + 'EventStartDayOfYear' => 'День года начала ÑобытиÑ', + 'EventTime' => 'Ð’Ñ€ÐµÐ¼Ñ ÑобытиÑ', + 'EventVerbatimEventDate' => 'Дата ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð¿Ð¾ первоиÑточнику', + 'EventYear' => 'Год ÑобытиÑ', + 'ExceptionDateTimes' => 'Дата иÑключениÑ', + 'ExclusiveCoverage' => 'ЭкÑклюзивный репортаж', + 'ExcursionTolerance' => { + Description => 'Выход за пределы диапазона', + PrintConv => { + 'Allowed' => 'ДопуÑкаетÑÑ', + 'Not Allowed' => 'Ðе допуÑкаетÑÑ', + }, + }, + 'ExifByteOrder' => { + Description => 'Exif – ПорÑдок байтов', + PrintConv => { + 'Big-endian (Motorola, MM)' => 'ПорÑдок от Ñтаршего к младшему (Motorola, MM)', + 'Little-endian (Intel, II)' => 'ПорÑдок от младшего к Ñтаршему (Intel, II)', + }, + }, + 'ExifCameraInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ камере из Exif', + 'ExifImageHeight' => 'Exif – Ð’Ñ‹Ñота изображениÑ', + 'ExifImageWidth' => 'Exif – Ширина изображениÑ', + 'ExifInfo2' => 'Exif – Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ 2', + 'ExifOffset' => 'Смещение Exif Sub IFD', + 'ExifToolVersion' => 'ВерÑÐ¸Ñ ExifTool', + 'ExifUnicodeByteOrder' => { + Description => 'Exif – ПорÑдок байтов Unicode', + PrintConv => { + 'Big-endian (Motorola, MM)' => 'ПорÑдок от Ñтаршего к младшему (Motorola, MM)', + 'Little-endian (Intel, II)' => 'ПорÑдок от младшего к Ñтаршему (Intel, II)', + }, + }, + 'ExifVersion' => 'ВерÑÐ¸Ñ Exif', + 'ExpandFilm' => 'Expand – Плёнка', + 'ExpandFilterLens' => 'Expand – Фильтр объектива', + 'ExpandFlashLamp' => 'Expand – Ð’Ñпышка', + 'ExpandLens' => 'Expand – Объектив', + 'ExpandScanner' => 'Expand – Сканер', + 'ExpandSoftware' => 'Expand – Приложение', + 'ExpirationDate' => 'Дата иÑÑ‚ÐµÑ‡ÐµÐ½Ð¸Ñ Ñрока', + 'ExpirationSpan' => 'Срок дейÑÑ‚Ð²Ð¸Ñ Ð¸ÑтечениÑ', + 'ExpirationTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð¸ÑÑ‚ÐµÑ‡ÐµÐ½Ð¸Ñ Ñрока', + 'Expires' => 'Дата уÑÑ‚Ð°Ñ€ÐµÐ²Ð°Ð½Ð¸Ñ Ð´Ð¾ÐºÑƒÐ¼ÐµÐ½Ñ‚Ð°', + 'Exposure' => 'ЭкÑпозициÑ', + 'ExposureCompensation' => 'КомпенÑÐ°Ñ†Ð¸Ñ ÑкÑпозиции', + 'ExposureIndex' => 'Ð˜Ð½Ð´ÐµÐºÑ ÑкÑпозиции', + 'ExposureLockUsed' => 'ИÑпользование блокировки параметров ÑкÑпозиции', 'ExposureMode' => { - Description => '"ЭкÑпозициÑ, режим"', + Description => 'Режим ÑкÑпозиции', PrintConv => { 'Auto' => 'ÐвтоÑкÑпозициÑ', - 'Auto bracket' => 'ÐвтобрÑкетинг', + 'Auto bracket' => 'Ðвтобрекетинг', 'Manual' => 'Ð ÑƒÑ‡Ð½Ð°Ñ ÑкÑпозициÑ', }, }, 'ExposureProgram' => { - Description => 'ЭкÑÐ¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð½Ð°Ñ', + Description => 'Программа ÑкÑпозиции', PrintConv => { - 'Action (High speed)' => 'Экшен/боевик', - 'Aperture-priority AE' => 'Приоритет диафрагмы', - 'Bulb' => 'Лампа', - 'Creative (Slow speed)' => 'ТворчеÑÐºÐ°Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð°', + 'Action (High speed)' => 'Спорт', + 'Aperture-priority AE' => 'ÐвтоÑкÑÐ¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ñ Ð¿Ñ€Ð¸Ð¾Ñ€Ð¸Ñ‚ÐµÑ‚Ð¾Ð¼ Диафрагмы', + 'Bulb' => 'Выдержка от руки', + 'Creative (Slow speed)' => 'ТворчеÑкаÑ', 'Landscape' => 'Пейзаж', - 'Manual' => '"ЭкÑпозициÑ, ручнаÑ"', + 'Manual' => 'РучнаÑ', + 'Not Defined' => 'Ðе определена', 'Portrait' => 'Портрет', - 'Program AE' => 'ÐÐ¾Ñ€Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð°', - 'Shutter speed priority AE' => 'Приоритет выдержки', + 'Program AE' => 'ÐŸÑ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð½Ð°Ñ Ð°Ð²Ñ‚Ð¾ÑкÑпозициÑ', + 'Shutter speed priority AE' => 'ÐвтоÑкÑÐ¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ñ Ð¿Ñ€Ð¸Ð¾Ñ€Ð¸Ñ‚ÐµÑ‚Ð¾Ð¼ Выдержки', }, }, 'ExposureTime' => 'Выдержка', - 'FNumber' => 'Диафрагма', - 'FaceOrientation' => { + 'ExposureTimes' => 'Выдержка2', + 'ExtCache' => 'Ðазвание альтернативного кÑша', + 'ExtenderStatus' => { + Description => 'Ð¡Ñ‚Ð°Ñ‚ÑƒÑ ÑкÑтендера', + PrintConv => { + 'Attached' => 'Прикреплен', + 'Not attached' => 'Ðе прикреплен', + 'Removed' => 'Удалён', + }, + }, + 'ExternalLeading' => 'Внешний зазор', + 'ExtraFlags' => { + Description => 'Дополнительные флаги', + PrintConv => { + '(none)' => 'ОтÑутÑтвуют', + 'Fastest Algorithm' => 'БыÑтрый алгоритм', + 'Maximum Compression' => 'МакÑимальное Ñжатие', + }, + }, + 'ExtraSamples' => { + Description => 'ОпиÑание дополнительных компонентов', + PrintConv => { + 'Associated Alpha' => 'СвÑзаные альфа-данные', + 'Unassociated Alpha' => 'ÐеÑвÑзанные альфа-данные', + 'Unspecified' => 'Данные без указаниÑ', + }, + }, + 'FNumber' => 'Диафрагменное чиÑло', + 'FOV' => 'Поле зрениÑ', + 'FSType' => 'Тип Ð²Ð½ÐµÐ´Ñ€ÐµÐ½Ð¸Ñ ÑˆÑ€Ð¸Ñ„Ñ‚Ð° в документ', + 'FaceBalanceOrigI' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð»Ð¸Ñ†Ð° – ИÑходный I', + 'FaceBalanceOrigQ' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð»Ð¸Ñ†Ð° – ИÑходный Q', + 'FaceBalanceStrength' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð»Ð¸Ñ†Ð° – ИнтенÑивноÑÑ‚ÑŒ', + 'FaceBalanceWarmth' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð»Ð¸Ñ†Ð° – Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ñ‚ÐµÐ¼Ð¿ÐµÑ€Ð°Ñ‚ÑƒÑ€Ð°', + 'FaceDetected' => 'Обнаружение лица', + 'FaceID' => 'Идентификатор лица', + 'FaceNumbers' => 'КоличеÑтво лиц', + 'FaceOrientation' => { + PrintConv => { + 'Horizontal (normal)' => 'Положительное направление', + 'Rotate 180' => 'Поворот на 180°', + 'Rotate 270 CW' => 'Поворот на 270° по чаÑовой Ñтрелке', + 'Rotate 90 CW' => 'Поворот на 90° по чаÑовой Ñтрелке', + }, + }, + 'FacePosition' => 'Положение лица', + 'FacesDetected' => 'Обнаружены лица', + 'Far' => 'Дальнее значение карты глубины', + 'FastSeek' => { + Description => 'БыÑтрый поиÑк', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'FaxProfile' => { + Description => 'ФакÑ-профиль', + PrintConv => { + 'Extended B&W lossless, F' => 'РаÑширенный чёрно-белый без потерь, профиль F', + 'Lossless JBIG B&W, J' => 'JBIG чёрно-белый без потерь, профиль J', + 'Lossless color and grayscale, L' => 'Цветной и Ñ Ð¾Ñ‚Ñ‚ÐµÐ½ÐºÐ°Ð¼Ð¸ Ñерого без потерь, профиль L', + 'Lossy color and grayscale, C' => 'Цветной и Ñ Ð¾Ñ‚Ñ‚ÐµÐ½ÐºÐ°Ð¼Ð¸ Ñерого Ñ Ð¿Ð¾Ñ‚ÐµÑ€Ñми, профиль C', + 'Minimal B&W lossless, S' => 'Минимальный чёрно-белый без потерь, профиль S', + 'Mixed raster content, M' => 'Смешанное Ñодержимое раÑтра, профиль M', + 'Multi Profiles' => 'ÐеÑколько профилей', + 'Profile T' => 'Профиль T', + 'Unknown' => 'Ðе ÑоответÑтвует профилю факÑимильной ÑвÑзи', + }, + }, + 'FaxRecvParams' => 'Параметры Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ñ„Ð°ÐºÑов', + 'FaxRecvTime' => 'Требуемое Ð²Ñ€ÐµÐ¼Ñ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ñ„Ð°ÐºÑа', + 'FaxSubAddress' => 'ÐŸÐ¾Ð´Ð°Ð´Ñ€ÐµÑ Ñ„Ð°ÐºÑа', + 'FieldOfView' => { + Description => 'Угол обзора', + PrintConv => { + 'Linear' => 'Линейный', + 'Wide' => 'Широкий', + }, + }, + 'FieldPermissions' => { + Description => 'Ð Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° изменение Полей', + PrintConv => { + 'Allow changes to specified form fields' => 'Разрешить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² указанных полÑÑ… формы', + 'Disallow changes to all form fields' => 'Запретить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð²Ð¾ вÑех полÑÑ… формы', + 'Disallow changes to specified form fields' => 'Запретить Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð² указанных полÑÑ… формы', + }, + }, + 'File1Duration' => 'Файл 1 – ПродолжительноÑÑ‚ÑŒ', + 'File1Length' => 'Файл 1 – Размер', + 'File1MD5Sum' => 'Файл 1 – Сумма MD5', + 'File1Media' => 'Файл 1 – Медиа', + 'File1Path' => 'Файл 1 – Путь', + 'File1PathUTF-8' => 'Файл 1 – Путь в кодировке UTF-8', + 'FileAccessDate' => 'Дата поÑледнего доÑтупа к файлу', + 'FileAttributes' => { + Description => 'Ðтрибуты файла', + PrintConv => { + 'Archive' => 'Ðрхивный', + 'BSD Whiteout' => 'BSD – Скрытый', + 'Block' => 'Блок', + 'Character' => 'Символ', + 'Compressed' => 'Сжатый', + 'Device' => 'УÑтройÑтво', + 'Directory' => 'Каталог', + 'Encrypted' => 'Зашифрованный', + 'Encrypted?' => 'Зашифрованные?', + 'FIFO' => 'FIFO (именованный канал)', + 'Hidden' => 'Скрытый', + 'Mux Block' => 'Блок Mux', + 'Mux Character' => 'Символ Mux', + 'Normal' => 'Без атрибутов', + 'Not Content Indexed' => 'Ðе проиндекÑированный', + 'Not indexed' => 'Ðе индекÑированный', + 'Offline' => 'Ðвтономный', + 'Read Only' => 'Только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ', + 'Read-only' => 'Только Ð´Ð»Ñ Ñ‡Ñ‚ÐµÐ½Ð¸Ñ', + 'Regular' => 'Обычный', + 'Reparse Point' => 'Точки повторной обработки', + 'Reparse point' => 'Точки повторной обработки', + 'Set Group ID' => 'УÑтановка ID группы', + 'Set User ID' => 'УÑтановка ID пользователÑ', + 'Socket' => 'Сокет', + 'Solaris Door' => 'Дверь (в Solaris)', + 'Solaris Shadow Inode' => 'Теневой Ð¸Ð½Ð´ÐµÐºÑ Solaris', + 'Sparse' => 'Разрежённый', + 'Sparse File' => 'Разрежённый файл', + 'Symbolic Link' => 'СимволичеÑÐºÐ°Ñ ÑÑылка', + 'System' => 'СиÑтемный', + 'Temporary' => 'Временный', + 'Unknown' => 'ÐеизвеÑтный', + 'Volume' => 'Том', + 'Volume Label' => 'Метка тома', + 'VxFS Compressed' => 'Сжатый VxFS', + 'XENIX Named' => 'Именованный (в XENIX)', + }, + }, + 'FileBlockCount' => 'КоличеÑтво блоков в файле', + 'FileBlockSize' => 'Размер блока в файле', + 'FileCreateDate' => 'Дата ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð°', + 'FileDeviceID' => 'ID уÑтройÑтва файла', + 'FileDeviceNumber' => 'Ðомер уÑтройÑтва файла', + 'FileFormat' => { + Description => 'Формат файла', + PrintConv => { + 'AppleSingle (Apple Computer Inc)' => 'AppleSingle (Apple)', + 'Audio Interchange File Format AIFF (Apple Computer Inc)' => 'Ðудиофайл формата AIFF (Apple)', + 'Bit Mapped Graphics File [.BMP] (Microsoft)' => 'Битовый графичеÑкий файл [.BMP] (Microsoft)', + 'Compressed Binary File [.ZIP] (PKWare Inc)' => 'Сжатый двоичный файл [.ZIP] (ÐšÐ¾Ð¼Ð¿Ð°Ð½Ð¸Ñ PKWare)', + 'Digital Audio File [.WAV] (Microsoft & Creative Labs)' => 'Ðудиофайл формата [.WAV] (Microsoft и Creative Labs)', + 'Hypertext Markup Language [.HTML] (The Internet Society)' => 'Язык гипертекÑтовой разметки [.HTML] (The Internet Society)', + 'IPTC Unstructured Character Oriented File Format (UCOFF)' => 'ÐеÑтруктурированный Ñимвольно-ориентированный формат файла IPTC (UCOFF)', + 'IPTC7901 Recommended Message Format' => 'IPTC7901 Рекомендуемый формат ÑообщениÑ', + 'Illustrator (Adobe Graphics data)' => 'Illustrator (ГрафичеÑкие данные Adobe)', + 'JPEG File Interchange (JFIF)' => 'Формат обмена файлами Ñтандарта JPEG (JFIF)', + 'MPEG 2 Audio Layer 2 (Musicom), ISO/IEC' => 'Ðудио второго ÑƒÑ€Ð¾Ð²Ð½Ñ MPEG 2 (Musicom), ISO/IEC', + 'MPEG 2 Audio Layer 3, ISO/IEC' => 'Ðудио третьего ÑƒÑ€Ð¾Ð²Ð½Ñ MPEG 2 , ISO/IEC', + 'News Industry Text Format (NITF)' => 'ТекÑтовый формат новоÑтной индуÑтрии (NITF)', + 'No ObjectData' => 'Данные объекта отÑутÑтвуют', + 'PC DOS/Windows Executable Files [.COM][.EXE]' => 'ИÑполнÑемый файл PC DOS/Windows [.COM][.EXE]', + 'RIFF Wave (Microsoft Corporation)' => 'RIFF Wave (Microsoft)', + 'Ritzaus Bureau NITF version (RBNITF DTD)' => 'Ritzaus Bureau вариант NITF (RBNITF DTD)', + 'Tagged Image File Format (Adobe/Aldus Image data)' => 'Формат файла Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñ Ñ‚ÐµÐ³Ð°Ð¼Ð¸ (Adobe/Aldus данные изображениÑ)', + 'Tape Archive [.TAR]' => 'Формат файла архива [.TAR]', + 'Tidningarnas Telegrambyra NITF version (TTNITF DTD)' => 'Tidningarnas Telegrambyra вариант NITF (TTNITF DTD)', + 'United Press International ANPA 1312 variant' => 'United Press International – Вариант ANPA 1312', + 'United Press International Down-Load Message' => 'United Press International – Down-Load Message', + }, + }, + 'FileGroupID' => 'ID группы файла', + 'FileHardLinks' => 'ЖёÑткие ÑÑылки файла', + 'FileID' => 'ID файла', + 'FileInfoLen' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ файле – Len', + 'FileInfoLen2' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ файле – Len 2', + 'FileInfoVersion' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ файле – ВерÑиÑ', + 'FileInodeChangeDate' => 'Дата Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð²Ð¾Ð³Ð¾ индекÑа', + 'FileInodeNumber' => 'Ðомер индекÑа файла', + 'FileModifyDate' => 'Дата Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð°', + 'FileName' => 'Ðазвание файла', + 'FileNameAsDelivered' => 'Ðазвание предоÑтавленного файла', + 'FileNameLength' => 'Длина Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð°', + 'FileNumber' => 'Ðомер файла', + 'FilePath' => 'Путь к файлу', + 'FilePermissions' => 'Ð Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð°', + 'FileSequence' => 'ПоÑледовательноÑÑ‚ÑŒ файлов', + 'FileSize' => 'Размер файла', + 'FileSizeBytes' => 'Размер файла в байтах', + 'FileSource' => { + Description => 'ИÑточник файла', + PrintConv => { + 'Digital Camera' => 'Ð¦Ð¸Ñ„Ñ€Ð¾Ð²Ð°Ñ Ñ„Ð¾Ñ‚Ð¾ÐºÐ°Ð¼ÐµÑ€Ð°', + 'Film Scanner' => 'Плёночный Ñканер', + 'Reflection Print Scanner' => 'Планшетный Ñканер', + 'Sigma Digital Camera' => 'Ð¦Ð¸Ñ„Ñ€Ð¾Ð²Ð°Ñ Ñ„Ð¾Ñ‚Ð¾ÐºÐ°Ð¼ÐµÑ€Ð° Sigma', + }, + }, + 'FileType' => 'Тип файла', + 'FileTypeExtension' => 'РаÑширение файла', + 'FileUserID' => 'ID Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ñ„Ð°Ð¹Ð»Ð°', + 'FileVersion' => 'ВерÑÐ¸Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð°', + 'Filename' => 'Ðазвание файла', + 'Files' => 'Файлы', + 'FillAttributes' => 'Ðттрибуты заполнениÑ', + 'FillOrder' => { + Description => 'ПорÑдок битов в байте', + PrintConv => { + 'Normal' => 'Обычный', + 'Reversed' => 'Обратный', + }, + }, + 'Filter' => { + Description => 'Фильтр', + PrintConv => { + 'Adaptive' => 'Ðдаптивный', + }, + }, + 'FinalFrameBlocks' => 'Блоков в поÑледнем кадре', + 'Firmware' => 'Прошивка', + 'FirmwareDate' => 'Дата прошивки', + 'FirmwareID' => 'ID прошивки', + 'FirmwareVersion' => 'ВерÑÐ¸Ñ Ð¿Ñ€Ð¾ÑˆÐ¸Ð²ÐºÐ¸', + 'FirmwareVersions' => 'ВерÑÐ¸Ñ Ð¿Ñ€Ð¾ÑˆÐ¸Ð²ÐºÐ¸', + 'FirstChar' => 'Первый Ñимвол шрифта', + 'FirstPhotoDate' => 'Дата ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿ÐµÑ€Ð²Ð¾Ð³Ð¾ изображениÑ', + 'FirstPublicationDate' => 'Дата первой публикации изображениÑ', + 'FixtureIdentifier' => 'Узнаваемый идентификатор', + 'Flags' => { + Description => 'Флаги', + PrintConv => { + 'Allow Download' => 'Разрешить загрузку', + 'Allow Recording' => 'Разрешить запиÑÑŒ', + 'Animation' => 'ÐнимациÑ', + 'Comment' => 'Комментарий', + 'Description' => 'ОпиÑание', + 'Extension Present' => 'ÐаÑтоÑщее времÑ', + 'ExtraFields' => 'Дополнительное поле', + 'FileName' => 'Ðазвание файлов', + 'IDList' => 'СпиÑок ID', + 'IconFile' => 'Иконка файла', + 'Limited Range' => 'Ограниченный диапазон', + 'LinkInfo' => 'Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ ÑÑылке', + 'LinkToLink' => 'СÑылка на ÑÑылку', + 'Live' => 'Ð’ прÑмом Ñфире', + 'NoLinkInfo' => 'Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ ÑÑылке отÑутÑтвует', + 'NoLinkPathTracking' => 'ОтÑлеживание пути без ÑÑылки', + 'NoLinkTrack' => 'Без ÑÑылки на трек', + 'Perfect Play' => 'ВоÑпроизводить поÑле загрузки', + 'RelativePath' => 'ОтноÑительный путь', + 'RunAsUser' => 'ЗапуÑк от имени пользователÑ', + 'TargetMetadata' => 'Целевые метаданные', + 'Text' => 'ТекÑÑ‚', + 'Unicode' => 'Юникод', + 'WorkingDir' => 'Ð Ð°Ð±Ð¾Ñ‡Ð°Ñ Ð¿Ð°Ð¿ÐºÐ°', + }, + }, + 'Flash' => { + Description => 'СоÑтоÑние вÑпышки при Ñъёмке', + PrintConv => { + 'Auto, Did not fire' => 'ÐвтоматичеÑкий режим. Ð’Ñпышка не Ñработала', + 'Auto, Did not fire, Red-eye reduction' => 'ÐвтоматичеÑкий режим. Ð’Ñпышка не Ñработала. Включён режим ÑƒÐ¼ÐµÐ½ÑŒÑˆÐµÐ½Ð¸Ñ Ñффекта «краÑных глаз»', + 'Auto, Fired' => 'ÐвтоматичеÑкий режим. Ð’Ñпышка Ñработала', + 'Auto, Fired, Red-eye reduction' => 'ÐвтоматичеÑкий режим. Ð’Ñпышка Ñработала', + 'Auto, Fired, Red-eye reduction, Return detected' => 'ÐвтоматичеÑкий режим. Ð’Ñпышка Ñработала. Включён режим ÑƒÐ¼ÐµÐ½ÑŒÑˆÐµÐ½Ð¸Ñ Ñффекта «краÑных глаз». Отражённый Ñвет обнаружен', + 'Auto, Fired, Red-eye reduction, Return not detected' => 'ÐвтоматичеÑкий режим. Ð’Ñпышка Ñработала. Включён режим ÑƒÐ¼ÐµÐ½ÑŒÑˆÐµÐ½Ð¸Ñ Ñффекта «краÑных глаз». Отражённый Ñвет не обнаружен', + 'Auto, Fired, Return detected' => 'ÐвтоматичеÑкий режим. Ð’Ñпышка Ñработала. Отражённый Ñвет обнаружен', + 'Auto, Fired, Return not detected' => 'ÐвтоматичеÑкий режим. Ð’Ñпышка Ñработала. Отражённый Ñвет не обнаружен', + 'Did not fire' => 'Ð’Ñпышка не Ñработала', + 'Fired' => 'Ð’Ñпышка Ñработала', + 'Fired, Red-eye reduction' => 'Ð’Ñпышка Ñработала. Включён режим ÑƒÐ¼ÐµÐ½ÑŒÑˆÐµÐ½Ð¸Ñ Ñффекта «краÑных глаз»', + 'Fired, Red-eye reduction, Return detected' => 'Ð’Ñпышка Ñработала. Включён режим ÑƒÐ¼ÐµÐ½ÑŒÑˆÐµÐ½Ð¸Ñ Ñффекта «краÑных глаз». Отражённый Ñвет обнаружен', + 'Fired, Red-eye reduction, Return not detected' => 'Ð’Ñпышка Ñработала. Включён режим ÑƒÐ¼ÐµÐ½ÑŒÑˆÐµÐ½Ð¸Ñ Ñффекта «краÑных глаз». Отражённый Ñвет не обнаружен', + 'Fired, Return detected' => 'Ð’Ñпышка Ñработала. Отражённый Ñвет обнаружен', + 'Fired, Return not detected' => 'Ð’Ñпышка Ñработала. Отражённый Ñвет не обнаружен', + 'No Flash' => 'Без вÑпышки', + 'No flash function' => 'Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ñпышки не поддерживаетÑÑ', + 'Off' => 'Ðе включена', + 'Off, Did not fire' => 'Ðе включена. Ð’Ñпышка не Ñработала', + 'Off, Did not fire, Return not detected' => 'Ðе включена. Ð’Ñпышка не Ñработала. Отражённый Ñвет не обнаружен', + 'Off, No flash function' => 'Ðе включена. Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð²Ñпышки не поддерживаетÑÑ', + 'Off, Red-eye reduction' => 'Ðе включена. Включён режим ÑƒÐ¼ÐµÐ½ÑŒÑˆÐµÐ½Ð¸Ñ Ñффекта «краÑных глаз»', + 'On' => 'Включена', + 'On, Did not fire' => 'Принудительный режим. Ð’Ñпышка не Ñработала', + 'On, Fired' => 'Принудительный режим. Ð’Ñпышка Ñработала', + 'On, Red-eye reduction' => 'Принудительный режим. Включён режим ÑƒÐ¼ÐµÐ½ÑŒÑˆÐµÐ½Ð¸Ñ Ñффекта «краÑных глаз»', + 'On, Red-eye reduction, Return detected' => 'Принудительный режим. Включён режим ÑƒÐ¼ÐµÐ½ÑŒÑˆÐµÐ½Ð¸Ñ Ñффекта «краÑных глаз». Отражённый Ñвет обнаружен', + 'On, Red-eye reduction, Return not detected' => 'Принудительный режим. Включён режим ÑƒÐ¼ÐµÐ½ÑŒÑˆÐµÐ½Ð¸Ñ Ñффекта «краÑных глаз». Отражённый Ñвет не обнаружен', + 'On, Return detected' => 'Принудительный режим. Отражённый Ñвет обнаружен', + 'On, Return not detected' => 'Принудительный режим. Отражённый Ñвет не обнаружен', + }, + }, + 'FlashAttributes' => { + Description => 'Flash аттрибуты', + PrintConv => { + 'UseNetwork' => 'ИÑпользовать Ñеть', + }, + }, + 'FlashCompensation' => 'КомпенÑÐ°Ñ†Ð¸Ñ Ð²Ñпышки', + 'FlashEnergy' => 'МощноÑÑ‚ÑŒ вÑпышки', + 'FlashExposureComp' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð²Ñпышки', + 'FlashManufacturer' => 'Производитель вÑпышки', + 'FlashMode' => { + Description => 'Режим вÑпышки', + PrintConv => { + 'Auto' => 'ÐвтоматичеÑкий', + 'Disabled' => 'Ð’Ñпышка не включена', + 'Force' => 'Принудительный', + 'Red eye' => 'КраÑные глаза', + }, + }, + 'FlashModel' => 'Модель вÑпышки', + 'FlashType' => { + Description => 'Тип вÑпышки', + PrintConv => { + 'Built-In Flash' => 'Ð’ÑтроеннаÑ', + 'External' => 'ВнешнÑÑ', + }, + }, + 'FlashVersion' => 'ВерÑÐ¸Ñ Flash', + 'FlashpixVersion' => 'ВерÑÐ¸Ñ Flashpix', + 'FlickerReduce' => { + Description => 'Уменьшение мерцаниÑ', + PrintConv => { + 'Off' => 'Ðе включено', + 'On' => 'Включено', + }, + }, + 'FlightPitchDegree' => 'Тангаж полета (наклон)', + 'FlightRollDegree' => 'Крен полета (вращение)', + 'FlightXSpeed' => 'СкороÑÑ‚ÑŒ полёта по оÑи X', + 'FlightYSpeed' => 'СкороÑÑ‚ÑŒ полёта по оÑи Y', + 'FlightYawDegree' => 'РыÑкание полета (поворот)', + 'FlightZSpeed' => 'СкороÑÑ‚ÑŒ полёта по оÑи Z', + 'FocalDistance' => 'ФокуÑное раÑÑтоÑние', + 'FocalLength' => 'ФокуÑное раÑÑтоÑние', + 'FocalLength35efl' => 'ФокуÑное раÑÑтоÑние', + 'FocalLengthIn35mmFormat' => 'ФокуÑное раÑÑтоÑние Ð´Ð»Ñ 35-мм формата', + 'FocalPlaneResolutionUnit' => { + Description => 'Единицы Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð² фокальной плоÑкоÑти', + PrintConv => { + 'None' => 'Ðе указано', + 'cm' => 'Ñм', + 'inches' => 'дюймы', + 'mm' => 'мм', + 'um' => 'мкм', + }, + }, + 'FocalPlaneXResolution' => 'Разрешение в фокальной плоÑкоÑти по X', + 'FocalPlaneYResolution' => 'Разрешение в фокальной плоÑкоÑти по Y', + 'FocalPointX' => 'Точка фокуÑа по оÑи X', + 'FocalPointY' => 'Точка фокуÑа по оÑи Y', + 'FocusDistance' => 'ФокуÑное раÑÑтоÑние', + 'FocusDistance2' => 'ФокуÑное раÑÑтоÑние 2', + 'FocusMode' => 'Режим фокуÑировки', + 'FocusPos' => 'ÐŸÐ¾Ð·Ð¸Ñ†Ð¸Ñ Ñ„Ð¾ÐºÑƒÑа', + 'FontFamily' => { + Description => 'СемейÑтво шрифта', + PrintConv => { + 'Decorative' => 'Декоративный', + 'Don\'t Care' => 'Без разницы', + 'Modern' => 'Модерн', + 'Script' => 'Скрипт', + }, + }, + 'FontName' => 'Ðазвание шрифта', + 'FontSize' => 'Размер шрифта', + 'FontSubfamily' => 'Стиль шрифта', + 'FontSubfamilyID' => 'ID ÑÑ‚Ð¸Ð»Ñ ÑˆÑ€Ð¸Ñ„Ñ‚Ð°', + 'FontType' => 'Тип шрифта', + 'FontWeight' => 'Толщина шрифта', + 'Footnotes' => 'СноÑки', + 'For' => 'ДлÑ', + 'FormExtraUsageRights' => 'Права на иÑпользование Форм Extra', + 'FormFields' => 'ÐŸÐ¾Ð»Ñ Ñ„Ð¾Ñ€Ð¼', + 'FormUsageRights' => 'Права на иÑпользование Форм', + 'Format' => { + Description => 'Формат', + PrintConv => { + 'RangeInverse' => 'Диапазон инверÑии', + 'RangeLinear' => 'Диапазон линейноÑти', + }, + }, + 'FormatVersionTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð²ÐµÑ€Ñии формата', + 'FormattedName' => 'Отформатированное имÑ', + 'Formatter' => 'Форматировщик', + 'ForwardMatrix1' => 'ПрÑÐ¼Ð°Ñ Ð¼Ð°Ñ‚Ñ€Ð¸Ñ†Ð° 1', + 'ForwardMatrix2' => 'ПрÑÐ¼Ð°Ñ Ð¼Ð°Ñ‚Ñ€Ð¸Ñ†Ð° 2', + 'FossilSpecimen' => 'ИÑкопаемый образец', + 'FossilSpecimenMaterialSampleID' => 'ID материала иÑкопаемого образца', + 'FovCot' => 'Угол обзора и КотангенÑ', + 'FractalParameters' => 'Фрактальные параметры', + 'FragmentList' => 'СпиÑок фрагментов', + 'FragmentTable' => 'Таблица фрагментов', + 'FrameCount' => 'КоличеÑтво кадров', + 'FrameExposureTime' => 'Ð’Ñ€ÐµÐ¼Ñ ÑкÑпозиции кадра', + 'FrameID' => 'ID кадра', + 'FrameNum' => 'Ðомер кадра', + 'FrameRate' => 'ЧаÑтота кадров', + 'FrameSize' => 'Размер кадра', + 'FrameSizeMax' => 'МакÑимальный размер кадра', + 'FrameSizeMin' => 'Минимальный размер кадра', + 'FramesPerSecond' => 'Кадров в Ñекунду', + 'Free' => 'Свободный', + 'FreeBusyTime' => 'Свободное/ЗанÑтое времÑ', + 'FreeByteCounts' => 'КоличеÑтво байтов в Ñтроке неиÑпользуемых байтов', + 'FreeOffsets' => 'Смещение к Ñтроке неиÑпользуемых байтов', + 'FullName' => 'Полное название шрифта', + 'FullPanoHeightPixels' => 'ИÑÑ…Ð¾Ð´Ð½Ð°Ñ Ð¿Ð¾Ð»Ð½Ð°Ñ Ð²Ñ‹Ñота до обрезки изображениÑ', + 'FullPanoWidthPixels' => 'ИÑÑ…Ð¾Ð´Ð½Ð°Ñ Ð¿Ð¾Ð»Ð½Ð°Ñ ÑˆÐ¸Ñ€Ð¸Ð½Ð° до обрезки изображениÑ', + 'FullScreen' => 'ПолноÑкранный', + 'GDALMetadata' => 'GDAL – Метаданные', + 'GDALNoData' => 'GDAL – ПрозрачноÑÑ‚ÑŒ', + 'GEMake' => 'GE – Сделан', + 'GEModel' => 'GE – Модель', + 'GIFApplicationExtension' => 'РаÑширение GIF-приложениÑ', + 'GIFGraphicControlExtension' => 'РаÑширение ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð³Ñ€Ð°Ñ„Ð¸ÐºÐ¾Ð¹ GIF', + 'GIFPlainTextExtension' => 'РаÑширение обычного текÑта GIF', + 'GIFTFtpPriority' => 'Приоритет GIFT Ftp', + 'GIFVersion' => 'ВерÑÐ¸Ñ GIF', + 'GLPI_Unknown4' => 'GLPI – ÐеизвеÑтный 4', + 'GPRI_Unknown4' => 'GPRI – ÐеизвеÑтный – 4', + 'GPRI_Unknown5' => 'GPRI – ÐеизвеÑтный – 5', + 'GPRI_Unknown8' => 'GPRI – ÐеизвеÑтный – 8', + 'GPRI_Unknown9' => 'GPRI – ÐеизвеÑтный – 9', + 'GPSAltitude' => 'GPS – Ð’Ñ‹Ñота', + 'GPSAltitudeRaw' => 'GPS – Ð’Ñ‹Ñота – Raw', + 'GPSAltitudeRef' => { + Description => 'GPS – Ð˜Ð½Ð´ÐµÐºÑ Ð²Ñ‹Ñоты', + PrintConv => { + 'Above Sea Level' => 'Ðад уровнем морÑ', + 'Below Sea Level' => 'Ðиже ÑƒÑ€Ð¾Ð²Ð½Ñ Ð¼Ð¾Ñ€Ñ', + }, + }, + 'GPSAreaInformation' => 'GPS – Ðазвание облаÑти', + 'GPSDOP' => 'GPS – ТочноÑÑ‚ÑŒ измерениÑ', + 'GPSDateStamp' => 'GPS – Дата и времÑ', + 'GPSDateTime' => 'GPS – Дата/ВремÑ', + 'GPSDateTimeRaw' => 'GPS – Дата/Ð’Ñ€ÐµÐ¼Ñ â€“ Raw', + 'GPSDestBearing' => 'GPS – Пеленг объекта Ñъёмки', + 'GPSDestBearingRef' => { + Description => 'GPS – Ориентир пеленга объекта Ñъёмки', + PrintConv => { + 'Magnetic North' => 'Ðа магнитный Ñеверный полюÑ', + 'True North' => 'Ðа географичеÑкий Ñеверный полюÑ', + }, + }, + 'GPSDestDistance' => 'GPS – РаÑÑтоÑние до объекта Ñъёмки', + 'GPSDestDistanceRef' => { + Description => 'GPS – Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ñ€Ð°ÑÑтоÑниÑ', + PrintConv => { + 'Kilometers' => 'Километры', + 'Miles' => 'Мили', + 'Nautical Miles' => 'МорÑкие мили', + }, + }, + 'GPSDestLatitude' => 'GPS – Широта объекта Ñъёмки', + 'GPSDestLatitudeRef' => { + Description => 'GPS – Ð˜Ð½Ð´ÐµÐºÑ ÑˆÐ¸Ñ€Ð¾Ñ‚Ñ‹ объекта Ñъёмки', + PrintConv => { + 'North' => 'Ð¡ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ð°', + 'South' => 'Ð®Ð¶Ð½Ð°Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ð°', + }, + }, + 'GPSDestLongitude' => 'GPS – Долгота объекта Ñъёмки', + 'GPSDestLongitudeRef' => { + Description => 'GPS – Ð˜Ð½Ð´ÐµÐºÑ Ð´Ð¾Ð»Ð³Ð¾Ñ‚Ñ‹ объекта Ñъёмки', + PrintConv => { + 'East' => 'ВоÑÑ‚Ð¾Ñ‡Ð½Ð°Ñ Ð´Ð¾Ð»Ð³Ð¾Ñ‚Ð°', + 'West' => 'Ð—Ð°Ð¿Ð°Ð´Ð½Ð°Ñ Ð´Ð¾Ð»Ð³Ð¾Ñ‚Ð°', + }, + }, + 'GPSDifferential' => { + Description => 'GPS – Ð”Ð¸Ñ„Ñ„ÐµÑ€ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð°Ñ Ð¿Ð¾Ð¿Ñ€Ð°Ð²ÐºÐ°', + PrintConv => { + 'Differential Corrected' => 'Ð”Ð¸Ñ„Ñ„ÐµÑ€ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð°Ñ Ð¿Ð¾Ð¿Ñ€Ð°Ð²ÐºÐ° применена', + 'No Correction' => 'Измерение без дифференциальной поправки', + }, + }, + 'GPSHPositioningError' => 'GPS – Ошибка горизонтального позиционированиÑ', + 'GPSImgDirection' => 'GPS – ÐÐ°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ°Ð¼ÐµÑ€Ñ‹ при Ñъёмке', + 'GPSImgDirectionRef' => { + Description => 'GPS – Ориентир Ð½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ°Ð¼ÐµÑ€Ñ‹', + PrintConv => { + 'Magnetic North' => 'Ðа магнитный Ñеверный полюÑ', + 'True North' => 'Ðа географичеÑкий Ñеверный полюÑ', + }, + }, + 'GPSInfo' => 'IFD указатель информации GPS', + 'GPSLatitude' => 'GPS – Широта', + 'GPSLatitudeRaw' => 'GPS – Широта – Raw', + 'GPSLatitudeRef' => { + Description => 'GPS – Ð˜Ð½Ð´ÐµÐºÑ ÑˆÐ¸Ñ€Ð¾Ñ‚Ñ‹', + PrintConv => { + 'North' => 'Ð¡ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ð°', + 'South' => 'Ð®Ð¶Ð½Ð°Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ð°', + }, + }, + 'GPSLongitude' => 'GPS – Долгота', + 'GPSLongitudeRaw' => 'GPS – Долгота – Raw', + 'GPSLongitudeRef' => { + Description => 'GPS – Ð˜Ð½Ð´ÐµÐºÑ Ð´Ð¾Ð»Ð³Ð¾Ñ‚Ñ‹', + PrintConv => { + 'East' => 'ВоÑÑ‚Ð¾Ñ‡Ð½Ð°Ñ Ð´Ð¾Ð»Ð³Ð¾Ñ‚Ð°', + 'West' => 'Ð—Ð°Ð¿Ð°Ð´Ð½Ð°Ñ Ð´Ð¾Ð»Ð³Ð¾Ñ‚Ð°', + }, + }, + 'GPSLongtitude' => 'GPS – Долгота', + 'GPSMapDatum' => 'GPS – СиÑтема координат', + 'GPSMeasureMode' => { + Description => 'GPS – Режим Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ GPS', + PrintConv => { + '2-Dimensional Measurement' => '2-Ð¼ÐµÑ€Ð½Ð°Ñ Ð½Ð°Ð²Ð¸Ð³Ð°Ñ†Ð¸Ñ', + '3-Dimensional Measurement' => '3-Ð¼ÐµÑ€Ð½Ð°Ñ Ð½Ð°Ð²Ð¸Ð³Ð°Ñ†Ð¸Ñ', + }, + }, + 'GPSPosition' => 'GPS – МеÑтоположение', + 'GPSProcessingMethod' => 'GPS – Метод вычиÑÐ»ÐµÐ½Ð¸Ñ Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ', + 'GPSSatellites' => 'GPS – ИÑпользуемые Ñпутники', + 'GPSSpeed' => 'GPS – СкороÑÑ‚ÑŒ передвижениÑ', + 'GPSSpeed3D' => 'GPS – СкороÑÑ‚ÑŒ 3D', + 'GPSSpeedRaw' => 'GPS – ÑкороÑÑ‚ÑŒ – Raw', + 'GPSSpeedRef' => { + Description => 'GPS – Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ ÑкороÑти', + PrintConv => { + 'km/h' => 'Км/ч', + 'knots' => 'Узлы', + 'mph' => 'Миль/ч', + }, + }, + 'GPSSpeedX' => 'GPS – СкороÑÑ‚ÑŒ по X', + 'GPSSpeedY' => 'GPS – СкороÑÑ‚ÑŒ по Y', + 'GPSSpeedZ' => 'GPS – СкороÑÑ‚ÑŒ по Z', + 'GPSStatus' => { + Description => 'GPS – СоÑтоÑние приёмника во Ð²Ñ€ÐµÐ¼Ñ Ñъёмки', + PrintConv => { + 'Measurement Active' => 'Координаты актуальные', + 'Measurement Void' => 'Ðктуальных координат нету', + }, + }, + 'GPSTimeStamp' => 'GPS – Ð’Ñ€ÐµÐ¼Ñ Ð·Ð°Ð¿Ð¸Ñанных координат', + 'GPSTrack' => 'GPS – Трек', + 'GPSTrackRaw' => 'GPS – Трек – Raw', + 'GPSTrackRef' => { + Description => 'GPS – Ориентир направлениÑ', + PrintConv => { + 'Magnetic North' => 'Ðа магнитный Ñеверный полюÑ', + 'True North' => 'Ðа географичеÑкий Ñеверный полюÑ', + }, + }, + 'GPSVersionID' => 'GPS – ВерÑÐ¸Ñ Ñ‚ÐµÐ³Ð¾Ð²', + 'GainControl' => { + Description => 'Управление уÑилением', + PrintConv => { + 'High gain down' => 'С большим шагом вниз', + 'High gain up' => 'С большим шагом вверх', + 'Low gain down' => 'С малым шагом вниз', + 'Low gain up' => 'С малым шагом вверх', + 'None' => 'ОтÑутÑтвует', + }, + }, + 'Gamma' => 'Гамма', + 'GammaBlue' => 'Гамма Синего', + 'GammaCompensatedValue' => 'Значение гамма-компенÑации', + 'GammaGreen' => 'Гамма Зелёного', + 'GammaRed' => 'Гамма КраÑного', + 'Gapless' => { + Description => 'Без зазора', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'Gender' => 'Пол', + 'Generator' => 'Сгенерирован в', + 'GeneratorVersion' => 'ВерÑÐ¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ', + 'Genr' => 'Жанр', + 'Genre' => 'Жанр', + 'GeoTiffAsciiParams' => 'Geo Tiff – Параметры Ascii', + 'GeoTiffDirectory' => 'Geo Tiff – Каталог', + 'GeoTiffDoubleParams' => 'Geo Tiff – Параметры дублированиÑ', + 'Geolocation' => 'ГеолокациÑ', + 'GeologicalContext' => 'ГеологичеÑкий контекÑÑ‚', + 'GeologicalContextBed' => 'Ðазвание литоÑтратиграфичеÑкого ÑлоÑ', + 'GeologicalContextFormation' => 'Ðазвание литоÑтратиграфичеÑкой Ñвиты', + 'GeologicalContextGroup' => 'Ðазвание литоÑтратиграфичеÑкой Ñерии', + 'GeologicalContextID' => 'ID геологичеÑкого контекÑта', + 'GeologicalContextMember' => 'Ðазвание литоÑтратиграфичеÑкой пачки', + 'Geosync' => 'Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸ меÑтоположениÑ', + 'Geotag' => 'Журнал пройденного маршрута', + 'Geotime' => 'Дата/Ð’Ñ€ÐµÐ¼Ñ Ð¼ÐµÑтоположениÑ', + 'GimbalPitchDegree' => 'Тангаж шарнира (наклон)', + 'GimbalReverse' => 'Оборот шарнира', + 'GimbalRollDegree' => 'Крен шарнира (вращение)', + 'GimbalYawDegree' => 'РыÑкание шарнира (поворот)', + 'GlobalAltitude' => 'Ð“Ð»Ð¾Ð±Ð°Ð»ÑŒÐ½Ð°Ñ Ð²Ñ‹Ñота', + 'GlobalAngle' => 'Глобальный угол', + 'GoogleBot' => 'ПоиÑковый робот Google', + 'GooglePlusUploadCode' => 'Код загрузки Google Plus', + 'Gradation' => 'ВпечатлÑющ.режим', + 'GrayPoint' => 'Точка Ñерого', + 'GrayResponseCurve' => 'ОптичеÑÐºÐ°Ñ Ð¿Ð»Ð¾Ñ‚Ð½Ð¾ÑÑ‚ÑŒ Ñерого', + 'GrayResponseUnit' => 'Единицы плотноÑти Ñерого', + 'GreenEndpoint' => 'ÐšÐ¾Ð½ÐµÑ‡Ð½Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° Зелёного', + 'GreenMask' => 'МаÑка Зелёного', + 'GreenPrimary' => 'ОÑновной зелёный', + 'GreenX' => 'Зелёный по X', + 'GreenY' => 'Зелёный по Y', + 'GridGuidesInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ Ñетке и направлÑющих', + 'Gyroscope' => 'ГироÑкоп', + 'HCUsage' => 'Тип информации HC-файла', + 'HDContent' => { + Description => 'Контент HD', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'HDR' => { + Description => 'ÐвтоматичеÑкий HDR', + PrintConv => { + 'Off' => 'Ðе включён', + }, + }, + 'HDRImageType' => { + Description => 'Тип HDR изображениÑ', + PrintConv => { + 'HDR Image' => 'HDR изображение', + 'Original Image' => 'Оригинальное изображение', + }, + }, + 'HDRSetting' => 'Праметры HDR', + 'HDRToningInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ HDR-тонировании', + 'HTTPHostHeader' => 'Заголовок HTTP-хоÑта', + 'HalftoneHints' => 'Ð£ÐºÐ°Ð·Ð°Ð½Ð¸Ñ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‚Ð¾Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ', + 'HardLink' => 'ЖёÑÑ‚ÐºÐ°Ñ ÑÑылка', + 'HasAudio' => 'Имеет аудио', + 'HasColorMap' => { + Description => 'Имеет цветовую карту', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'HasCuePoints' => 'Имеет ключевые точки', + 'HasKeyFrames' => 'Имеет ключевые кадры', + 'HasMetadata' => 'Имеет метаданные', + 'HasRealMergedData' => { + Description => 'Имеет Ñовмещённые данные', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'HasVideo' => 'Имеет видео', + 'HasXFA' => { + Description => 'XFA', + PrintConv => { + 'No' => 'ОтÑутÑтвует', + 'Yes' => 'ЕÑÑ‚ÑŒ', + }, + }, + 'HeaderSize' => 'Размер заголовка', + 'HeaderVersion' => 'ВерÑÐ¸Ñ Ð·Ð°Ð³Ð¾Ð»Ð¾Ð²ÐºÐ¾Ð²', + 'Headline' => 'Заголовок', + 'HeightResolution' => 'Разрешение по выÑоте (PPI)', + 'HierarchicalKeywords' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов', + 'HierarchicalKeywords1' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 1', + 'HierarchicalKeywords1Applied' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 1 – Применена', + 'HierarchicalKeywords1Children' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 1 – ДочернÑÑ', + 'HierarchicalKeywords2' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 2', + 'HierarchicalKeywords2Applied' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 2 – Применена', + 'HierarchicalKeywords2Children' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 2 – ДочернÑÑ', + 'HierarchicalKeywords3' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 3', + 'HierarchicalKeywords3Applied' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 3 – Применена', + 'HierarchicalKeywords3Children' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 3 – ДочернÑÑ', + 'HierarchicalKeywords4' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 4', + 'HierarchicalKeywords4Applied' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 4 – Применена', + 'HierarchicalKeywords4Children' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 4 – ДочернÑÑ', + 'HierarchicalKeywords5' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 5', + 'HierarchicalKeywords5Applied' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 5 – Применена', + 'HierarchicalKeywords5Children' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 5 – ДочернÑÑ', + 'HierarchicalKeywords6' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 6', + 'HierarchicalKeywords6Applied' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… Ñлов 6 – Применена', + 'HierarchicalSubject' => 'Ð˜ÐµÑ€Ð°Ñ€Ñ…Ð¸Ñ Ñ‚ÐµÐ¼', + 'HighISOMultiplierBlue' => 'Множитель ISO – Синий', + 'HighISOMultiplierGreen' => 'Множитель ISO – Зелёный', + 'HighISOMultiplierRed' => 'Множитель ISO – КраÑный', + 'HighISONoiseReduction' => { + Description => 'Шумоподавление при выÑоком ISO', + PrintConv => { + 'Auto' => 'ÐвтоматичеÑкое', + 'High' => 'Сильное', + 'Low' => 'Слабое', + 'Normal' => 'Стандартное', + 'Off' => 'Ðе включено', + 'Standard' => 'Стандартное', + 'Strong' => 'Сильное', + }, + }, + 'HighestBiostratigraphicZone' => 'Ð’Ñ‹ÑÑˆÐ°Ñ Ð±Ð¸Ð¾ÑтратиграфичеÑÐºÐ°Ñ Ð·Ð¾Ð½Ð°', + 'HighlightColorDistortReduct' => { + Description => 'Уменьшение иÑкажений Ñветлых цветов', + PrintConv => { + 'Advanced' => 'РаÑширенный', + 'Standard' => 'Стандартный', + }, + }, + 'Highlights' => 'Света', + 'HighlightsAdj' => 'Регулировка Ñветов', + 'History' => 'ИÑториÑ', + 'HistoryBufferSize' => 'Размер буфера иÑтории', + 'HostComputer' => 'Компьютер/СиÑтема', + 'HotKey' => { + Description => 'ГорÑÑ‡Ð°Ñ ÐºÐ»Ð°Ð²Ð¸ÑˆÐ°', + PrintConv => { + '(none)' => 'ОтÑутÑтвует', + }, + }, + 'HowPublished' => 'Метод публикации', + 'Hue' => 'Оттенок', + 'HueAdj' => 'Регулировка оттенка', + 'HumanObservation' => 'Визуальное наблюдение', + 'HumanObservationDay' => 'День меÑÑца визуального наблюдениÑ', + 'HumanObservationEarliestDate' => 'Дата начала визуального наблюдениÑ', + 'HumanObservationEndDayOfYear' => 'День года Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ð²Ð¸Ð·ÑƒÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ наблюдениÑ', + 'HumanObservationEventDate' => 'Дата визуального наблюдениÑ', + 'HumanObservationEventID' => 'ID визуального наблюдениÑ', + 'HumanObservationEventRemarks' => 'Комментарии к визуальному наблюдению', + 'HumanObservationEventTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð²Ð¸Ð·ÑƒÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ наблюдениÑ', + 'HumanObservationFieldNotes' => 'Полевые заметки о визуальном наблюдении', + 'HumanObservationFieldNumber' => 'Ðомер полевых заметок о визуальном наблюдении', + 'HumanObservationHabitat' => 'Ðреал визуального наблюдениÑ', + 'HumanObservationLatestDate' => 'Дата Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ð²Ð¸Ð·ÑƒÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ наблюдениÑ', + 'HumanObservationMonth' => 'МеÑÑц визуального наблюдениÑ', + 'HumanObservationParentEventID' => 'ID оÑновного визуального наблюдениÑ', + 'HumanObservationSampleSizeUnit' => 'Визуальное наблюдение – Единицы размера', + 'HumanObservationSampleSizeValue' => 'Визуальное наблюдение – Размер образца', + 'HumanObservationSamplingEffort' => 'Визуальное наблюдение – Затраченные уÑилиÑ', + 'HumanObservationSamplingProtocol' => 'Визуальное наблюдение – Метод иÑÑледованиÑ', + 'HumanObservationStartDayOfYear' => 'День года начала визуального наблюдениÑ', + 'HumanObservationVerbatimEventDate' => 'Дата визуального Ð½Ð°Ð±Ð»ÑŽÐ´ÐµÐ½Ð¸Ñ Ð´Ð¾Ñловно', + 'HumanObservationYear' => 'Год визуального наблюдениÑ', + 'Humidity' => 'ВлажноÑÑ‚ÑŒ', + 'HyperfocalDistance' => 'Гиперфокальное раÑÑтоÑние', + 'HyperlinkBase' => 'База гиперÑÑылок', + 'ICCProfileName' => 'Ðазвание ICC-профилÑ', + 'ICC_Profile' => 'ICC-профиль', + 'ICC_Untagged' => 'ICC без метки', + 'ID3Size' => 'Размер блока данных ID3', + 'IDCCreativeStyle' => { + Description => 'IDC – ТворчеÑкий Ñтиль', + PrintConv => { + 'A100 Standard' => 'Стандарт A100', + 'Autumn Leaves' => 'ОÑенние лиÑÑ‚ÑŒÑ', + 'B&W' => 'Чёрно-Белое', + 'Camera Setting' => 'ÐаÑтройка камеры', + 'Clear' => 'ЧиÑтый', + 'Deep' => 'Глубокий', + 'Landscape' => 'Пейзаж', + 'Light' => 'Светлый', + 'Neutral' => 'Ðейтральный', + 'Night View' => 'Ðочной вид', + 'Portrait' => 'Портрет', + 'Real' => 'Реальный', + 'Sepia' => 'СепиÑ', + 'Standard' => 'Стандарт', + 'Sunset' => 'Закат', + 'Vivid' => 'Яркий', + }, + }, + 'IDCPreviewImage' => 'IDC – файл предпроÑмотра', + 'IDCPreviewLength' => 'IDC – Строк в файле предпроÑмотра', + 'IDCPreviewStart' => 'IDC – Ðачало файла предпроÑмотра', + 'IDsBaseValue' => 'ОÑновные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¸Ð½Ð´Ð¸ÐºÐ°Ñ‚Ð¾Ñ€Ð¾Ð²', + 'INGRReserved' => 'Intergraph – Резерв', + 'IPTCBitsPerSample' => 'IPTC – КоличеÑтво бит на компонент', + 'IPTCDigest' => 'Хеш IPTC', + 'IPTCImageHeight' => 'IPTC – Ð’Ñ‹Ñота изображениÑ', + 'IPTCImageRotation' => { + Description => 'IPTC – Вращение изображениÑ', + PrintConv => { + '0' => 'Ðе вращать', + '180' => 'Повернуть вправо на 180°', + '270' => 'Повернуть вправо на 270°', + '90' => 'Повернуть вправо на 90°', + }, + }, + 'IPTCImageWidth' => 'IPTC – Ширина изображениÑ', + 'IPTCPictureNumber' => 'IPTC – Ðомер изображениÑ', + 'IPTCPixelHeight' => 'IPTC – Ð’Ñ‹Ñота (в пикÑелÑÑ…)', + 'IPTCPixelWidth' => 'IPTC – Ширина (в пикÑелÑÑ…)', + 'ISOSetting' => { + Description => 'ISO2', + PrintConv => { + '200 (Zone Matching High)' => '200 (СоглаÑование зон. Ð’ выÑоком ключе)', + '80 (Zone Matching Low)' => '80 (СоглаÑование зон. Ð’ низком ключе)', + 'Auto' => 'ÐвтоматичеÑки', + }, + }, + 'ISOSpeed' => 'ЧувÑтвительноÑÑ‚ÑŒ ISO', + 'ISOSpeedLatitudeyyy' => 'ISO – ФотографичеÑÐºÐ°Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ð° yyy', + 'ISOSpeedLatitudezzz' => 'ISO – ФотографичеÑÐºÐ°Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ð° zzz', + 'ISOSpeeds' => 'ISO4', + 'ISRCNumber' => 'Ðомер ISRC', + 'IT8Header' => 'IT8-заголовок', + 'IconFileName' => 'Ðазвание файла значка', + 'IconIndex' => 'Ð˜Ð½Ð´ÐµÐºÑ Ð¸ÐºÐ¾Ð½ÐºÐ¸', + 'Identification' => 'Определение', + 'IdentificationID' => 'ID определениÑ', + 'IdentificationQualifier' => 'Уточнение к определению', + 'IdentificationReferences' => 'ИÑточники иÑпользованные Ð´Ð»Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ', + 'IdentificationRemarks' => 'Комментарии к определению', + 'IdentificationVerificationStatus' => 'Код Ð¿Ð¾Ð´Ñ‚Ð²ÐµÑ€Ð¶Ð´ÐµÐ½Ð¸Ñ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ', + 'IdentifiedBy' => 'Люди определившие образец', + 'Identifier' => 'Идентификатор', + 'Illumination' => { + Description => 'ПодÑветка', + PrintConv => { + 'Off' => 'Ðе включена', + 'On' => 'Включена', + }, + }, + 'Image2Description' => 'Изображение 2 – ОпиÑание', + 'Image3Description' => 'Изображение 3 – ОпиÑание', + 'Image4Description' => 'Изображение 4 – ОпиÑание', + 'Image5Description' => 'Изображение 5 – ОпиÑание', + 'Image6Description' => 'Изображение 6 – ОпиÑание', + 'Image7Description' => 'Изображение 7 – ОпиÑание', + 'Image8Description' => 'Изображение 8 – ОпиÑание', + 'Image::ExifTool::AIFF::Comment' => 'Комментарии AIFF', + 'Image::ExifTool::AIFF::Common' => 'Общее AIFF', + 'Image::ExifTool::AIFF::FormatVers' => 'ВерÑÐ¸Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð° AIFF', + 'Image::ExifTool::APE::NewHeader' => 'Ðовый заголовок APE', + 'Image::ExifTool::APE::OldHeader' => 'Старый заголовок APE', + 'Image::ExifTool::APP12::PictureInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ APP12', + 'Image::ExifTool::Apple::RunTime' => 'Apple – Ð’Ñ€ÐµÐ¼Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ', + 'Image::ExifTool::Audible::cvrx' => 'Обложка Audible', + 'Image::ExifTool::Audible::meta' => 'Метаданные Audible', + 'Image::ExifTool::BPG::Extensions' => 'РаÑÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ BPG', + 'Image::ExifTool::DjVu::Form' => 'Форма DjVu', + 'Image::ExifTool::DjVu::Info' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ DjVu', + 'Image::ExifTool::DjVu::Meta' => 'DjVu метаданные', + 'Image::ExifTool::FLAC::Picture' => 'Изображение FLAC', + 'Image::ExifTool::FLAC::StreamInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ потоке FLAC', + 'Image::ExifTool::Flash::Audio' => 'Flash аудио', + 'Image::ExifTool::Flash::Meta' => 'Flash метаданные', + 'Image::ExifTool::Flash::Video' => 'Flash видео', + 'Image::ExifTool::Font::Main' => 'Шрифт', + 'Image::ExifTool::Font::Name' => 'Ðазвание шрифта', + 'Image::ExifTool::Font::PFM' => 'Шрифт PFM', + 'Image::ExifTool::Font::PSInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ PostScript шрифте', + 'Image::ExifTool::FotoStation::SoftEdit' => 'FotoStation – Редактор', + 'Image::ExifTool::GE::Main' => 'General Imaging (GE)', + 'Image::ExifTool::GIF::Animation' => 'GIF анимациÑ', + 'Image::ExifTool::GIF::Extensions' => 'GIF РаÑширениÑ', + 'Image::ExifTool::GIF::MIDIControl' => 'GIF MIDIControl', + 'Image::ExifTool::GIF::Main' => 'GIF', + 'Image::ExifTool::GIF::Screen' => 'GIF Screen', + 'Image::ExifTool::GIMP::Header' => 'Заголовок GIMP', + 'Image::ExifTool::GIMP::Parasite' => 'GIMP – Паразитный Ñлемент', + 'Image::ExifTool::GIMP::Resolution' => 'GIMP – Разешение', + 'Image::ExifTool::HP::Type2' => 'HP – Тип 2', + 'Image::ExifTool::HP::Type4' => 'HP – Тип 4', + 'Image::ExifTool::HP::Type6' => 'HP – Тип 6', + 'Image::ExifTool::IPTC::ObjectData' => 'IPTC – Данные объекта', + 'Image::ExifTool::IPTC::PostObjectData' => 'IPTC – Данные Post объекта', + 'Image::ExifTool::IPTC::PreObjectData' => 'IPTC – Данные Pre объекта', + 'Image::ExifTool::ITC::Header' => 'Заголовок ITC', + 'Image::ExifTool::ITC::Item' => 'Элемент ITC', + 'Image::ExifTool::JFIF::Extension' => 'JFIF Дополнение', + 'Image::ExifTool::JVC::Text' => 'JVC – ТекÑÑ‚', + 'Image::ExifTool::Jpeg2000::ColorSpec' => 'Jpeg2000 – Ð¡Ð¿ÐµÑ†Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð°', + 'Image::ExifTool::Jpeg2000::DisplayResolution' => 'Jpeg2000 – Разрешение Ñкрана', + 'Image::ExifTool::Jpeg2000::FileType' => 'Jpeg2000 – Тип файла', + 'Image::ExifTool::Jpeg2000::ImageHeader' => 'Jpeg2000 – Заголовок изображениÑ', + 'Image::ExifTool::MPEG::Audio' => 'MPEG аудио', + 'Image::ExifTool::MPEG::Video' => 'MPEG видео', + 'Image::ExifTool::Microsoft::MP' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ Microsoft Photo', + 'Image::ExifTool::PDF::Encrypt' => 'PDF зашифрован', + 'Image::ExifTool::PDF::Info' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ PDF-файле', + 'Image::ExifTool::PDF::Pages' => 'Страниц в PDF', + 'Image::ExifTool::PDF::Root' => 'ОÑновные параметры PDF', + 'Image::ExifTool::PDF::Signature' => 'Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ PDF', + 'Image::ExifTool::PDF::TransformParams' => 'Параметры Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ PDF-файла', + 'Image::ExifTool::PNG::ImageHeader' => 'Заголовки PNG-изображениÑ', + 'Image::ExifTool::PNG::PrimaryChromaticities' => 'ОÑновные цвета PNG', + 'Image::ExifTool::PNG::StereoImage' => 'Стереоизображние PNG', + 'Image::ExifTool::PSP::Creator' => 'Создатель PSP', + 'Image::ExifTool::PSP::Image' => 'Изображение PSP', + 'Image::ExifTool::PhaseOne::SensorCalibration' => 'PhaseOne – ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ ÑенÑора', + 'Image::ExifTool::PhotoMechanic::SoftEdit' => 'PhotoMechanic', + 'Image::ExifTool::Photoshop::Header' => 'Заголовок Photoshop', + 'Image::ExifTool::Photoshop::JPEG_Quality' => 'КачеÑтво JPEG в Photoshop', + 'Image::ExifTool::Photoshop::Layers' => 'Слои Photoshop', + 'Image::ExifTool::Photoshop::PrintScaleInfo' => 'Photoshop – МаÑштабирование при печати', + 'Image::ExifTool::Photoshop::Resolution' => 'Photoshop – Разрешение', + 'Image::ExifTool::PrintIM::Main' => 'Print Image Matching (PrintIM)', + 'Image::ExifTool::RTF::Main' => 'RTF', + 'Image::ExifTool::Rawzor::Main' => 'Rawzor', + 'Image::ExifTool::Real::Metadata' => 'Метаданные Real', + 'Image::ExifTool::Real::Metafile' => 'Метафайл Real', + 'Image::ExifTool::Real::Properties' => 'СвойÑтва Real', + 'Image::ExifTool::Sanyo::Thumbnail' => 'Миниатюра Sanyo', + 'Image::ExifTool::Stim::CropX' => 'Stim – Обрезка по X', + 'Image::ExifTool::Stim::CropY' => 'Stim – Обрезка по Y', + 'Image::ExifTool::Theora::Identification' => 'Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Theora', + 'Image::ExifTool::Torrent::Files' => 'Торрент-файлы', + 'Image::ExifTool::Torrent::Info' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ торренте', + 'Image::ExifTool::Torrent::Main' => 'Торрент', + 'Image::ExifTool::Torrent::Profiles' => 'Торрент профили', + 'Image::ExifTool::Vorbis::Comments' => 'Комментарии Vorbis', + 'Image::ExifTool::Vorbis::Identification' => 'Идентификатор Vorbis', + 'Image::ExifTool::ZIP::GZIP' => 'ZIP GZIP', + 'Image::ExifTool::ZIP::Main' => 'ZIP', + 'Image::ExifTool::ZIP::RAR' => 'ZIP RAR', + 'ImageAlterationConstraints' => { + Description => 'Ограничение на редактирование', + PrintConv => { + 'No Colorization' => 'Ðе раÑкрашивать', + 'No Cropping' => 'Ðе кадрировать', + 'No De-Colorization' => 'Ðе обеÑцвечивать', + 'No Flipping' => 'Ðе отражать', + 'No Merging' => 'Ðе объединÑÑ‚ÑŒ', + 'No Retouching' => 'Ðе ретушировать', + }, + }, + 'ImageArrangement' => { + Description => 'РаÑположение Ñтереоизображений', + PrintConv => { + 'Cross View Alignment' => 'ПереÑечное раÑположение', + 'Parallel View Alignment' => 'Параллельное раÑположение', + }, + }, + 'ImageByteCount' => 'Размер Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (байт)', + 'ImageColorIndicator' => { + Description => 'Цвет переднего плана или прозрачноÑти', + PrintConv => { + 'Specified Image Color' => 'Указан', + 'Unspecified Image Color' => 'Ðе указан', + }, + }, + 'ImageColorValue' => 'Значение цвета переднего плана или прозрачноÑти', + 'ImageCreator' => 'Создатель изображеениÑ', + 'ImageCreatorID' => 'PLUS-ID ÑÐ¾Ð·Ð´Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ', + 'ImageCreatorImageID' => 'ID Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ñвоенный Ñоздателем', + 'ImageCreatorName' => 'Ð˜Ð¼Ñ ÑÐ¾Ð·Ð´Ð°Ñ‚ÐµÐ»Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ', + 'ImageData' => 'Данные изображениÑ', + 'ImageDataDiscard' => { + Description => 'Отброшенные данные изображениÑ', + PrintConv => { + 'Flexbits Discarded' => 'Гибкие биты отброшены', + 'Full Resolution' => 'Полное разрешение', + 'HighPass Frequency Data Discarded' => 'Данные выÑоких чаÑтот отброшены', + 'Highpass and LowPass Frequency Data Discarded' => 'Данные выÑоких и низких чаÑтот отброшены', + }, + }, + 'ImageDepth' => 'Глубина изображениÑ', + 'ImageDescription' => 'ОпиÑание изображениÑ', + 'ImageDuplicationConstraints' => { + Description => 'Ограничение на дублирование', + PrintConv => { + 'Duplication Only as Necessary Under License' => 'Дублировать только при необходимоÑти в ÑоответÑтвии Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¸ÐµÐ¹', + 'No Duplication' => 'Дублирование запрещено', + 'No Duplication Constraints' => 'ÐžÐ³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð½Ð° дублирование отÑутÑтвуют', + }, + }, + 'ImageElements' => 'Элементы изображениÑ', + 'ImageFileConstraints' => { + Description => 'ÐžÐ³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð½Ð° файл', + PrintConv => { + 'Maintain File Name' => 'ЗапрещаетÑÑ Ð¿ÐµÑ€ÐµÐ¸Ð¼ÐµÐ½Ð¾Ð²Ð°Ð½Ð¸Ðµ файла', + 'Maintain File Type' => 'ЗапрещаетÑÑ Ð¸Ð·Ð¼ÐµÐ½ÑÑ‚ÑŒ тип файла', + 'Maintain ID in File Name' => 'ЗапрещаетÑÑ Ð¸Ð·Ð¼ÐµÐ½ÑÑ‚ÑŒ ID в имени файла', + 'Maintain Metadata' => 'ЗапрещаетÑÑ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ðµ метаданных', + }, + }, + 'ImageFileFormatAsDelivered' => { + Description => 'ИÑходный формат файла', + PrintConv => { + 'Other' => 'Другой формат', + }, + }, + 'ImageFileName' => 'Ðазвание файла изображениÑ', + 'ImageFileSizeAsDelivered' => { + Description => 'ИÑходный размер файла', + PrintConv => { + 'Greater than 50 MB' => 'Более 50 МБ', + 'Up to 1 MB' => 'До 1 МБ', + 'Up to 10 MB' => 'До 10 МБ', + 'Up to 30 MB' => 'До 30 МБ', + 'Up to 50 MB' => 'До 50 МБ', + }, + }, + 'ImageFullHeight' => 'ÐŸÐ¾Ð»Ð½Ð°Ñ Ð²Ñ‹Ñота изображениÑ', + 'ImageFullWidth' => 'ÐŸÐ¾Ð»Ð½Ð°Ñ ÑˆÐ¸Ñ€Ð¸Ð½Ð° изображениÑ', + 'ImageHeight' => 'Ð’Ñ‹Ñота изображениÑ', + 'ImageHistory' => 'ИÑÑ‚Ð¾Ñ€Ð¸Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ', + 'ImageID' => 'ID изображениÑ', + 'ImageLayer' => 'Слой изображениÑ', + 'ImageLength' => 'Строк в изображении', + 'ImageLimitExposureBias' => 'Лимит поправки ÑкÑпозиции', + 'ImageMimeType' => 'MIME-тип изображениÑ', + 'ImageModulationExposureBias' => 'МодулÑÑ†Ð¸Ñ Ð¿Ð¾Ð¿Ñ€Ð°Ð²ÐºÐ¸ ÑкÑпозиции', + 'ImageNumber' => 'Ðомер изображениÑ', + 'ImageOffset' => 'Смещение изображениÑ', + 'ImageOrientation' => { + Description => 'ÐžÑ€Ð¸ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ', + PrintConv => { + 'Landscape' => 'ÐльбомнаÑ', + 'Portrait' => 'ПортретнаÑ', + 'Square' => 'КвадратнаÑ', + }, + }, + 'ImageRank' => 'Рейтинг изображениÑ', + 'ImageReadyDataSets' => 'Ðаборы данных', + 'ImageReadyVariables' => 'Переменные', + 'ImageReferencePoints' => 'Опорные точки изображениÑ', + 'ImageResolution' => 'Разрешение изображениÑ', + 'ImageRotation' => { + Description => 'Поворот/Ð ÐµÐ²ÐµÑ€Ñ Ñ‚Ð¾Ñ‡ÐµÐº проÑмотра изображениÑ', + PrintConv => { + 'None' => 'Ðет', + }, + }, + 'ImageSensorGain' => 'КоÑффициент уÑÐ¸Ð»ÐµÐ½Ð¸Ñ Ð´Ð°Ñ‚Ñ‡Ð¸ÐºÐ° изображениÑ', + 'ImageSize' => 'Размер изображениÑ', + 'ImageSourceData' => 'ИÑходные данные изображениÑ', + 'ImageStabilization' => { + PrintConv => { + 'CCD Shift' => 'ОптичеÑкий Ñтабилизатор', + 'High Sensitivity' => 'Движение объекта Ñъёмки', + 'Off' => 'Выкл', + 'Off (1)' => 'Выкл (1)', + }, + }, + 'ImageSupplier' => 'ПоÑтавщик изображениÑ', + 'ImageSupplierID' => 'PLUS-ID поÑтавщика изображениÑ', + 'ImageSupplierImageID' => 'ID Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ñвоенный поÑтавщиком', + 'ImageSupplierName' => 'Ð˜Ð¼Ñ Ð¿Ð¾Ñтавщика изображениÑ', + 'ImageToolbar' => 'Панель команд Ð´Ð»Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ', + 'ImageType' => { + Description => 'Тип изображениÑ', + PrintConv => { + 'Grayscale (interlaced)' => 'Ð“Ñ€Ð°Ð´Ð°Ñ†Ð¸Ñ Ñерого (череÑÑтрочнаÑ)', + 'Grayscale (non-interlaced)' => 'Ð“Ñ€Ð°Ð´Ð°Ñ†Ð¸Ñ Ñерого (без чередованиÑ)', + 'Grayscale Animation (interlaced)' => 'ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ Ð² градациÑÑ… Ñерого (череÑÑтрочнаÑ)', + 'Grayscale Animation (non-interlaced)' => 'ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ Ð² градациÑÑ… Ñерого (без чередованиÑ)', + 'Illustrated Image' => 'ГрафичеÑкое изображение', + 'Multimedia or Composited Image' => 'Мультимедийное или композитное изображение', + 'Other' => 'Другой тип', + 'Page' => 'Страница', + 'Photographic Image' => 'ФотографиÑ', + 'Preview' => 'ПредпроÑмотр', + 'RGB (interlaced)' => 'RGB (череÑÑтрочнаÑ)', + 'RGB (non-interlaced)' => 'RGB (без чередованиÑ)', + 'RGB Animation (interlaced)' => 'ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ RGB (череÑÑтрочнаÑ)', + 'RGB Animation (non-interlaced)' => 'ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ RGB (без чередованиÑ)', + 'RGBA (interlaced)' => 'RGBA (череÑÑтрочнаÑ)', + 'RGBA (non-interlaced)' => 'RGBA (без чередованиÑ)', + 'RGBA Animation (interlaced)' => 'ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ RGBA (череÑÑтрочнаÑ)', + 'RGBA Animation (non-interlaced)' => 'ÐÐ½Ð¸Ð¼Ð°Ñ†Ð¸Ñ RGBA (без чередованиÑ)', + 'Video' => 'Видео', + }, + }, + 'ImageUIDList' => 'СпиÑок уникальных ID изображений', + 'ImageUniqueID' => 'Уникальный ID изображениÑ', + 'ImageWidth' => 'Ширина изображениÑ', + 'Importance' => { + Description => 'ВажноÑÑ‚ÑŒ', + PrintConv => { + 'High' => 'Ð’Ñ‹ÑокаÑ', + 'Low' => 'ÐизкаÑ', + 'Normal' => 'ОбычнаÑ', + }, + }, + 'Imprint' => 'ИздательÑтво', + 'InclinationAngle' => 'Угол наклона', + 'InclinationCorrection' => { + Description => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð½Ð°ÐºÐ»Ð¾Ð½Ð°', + PrintConv => { + 'Off' => 'Ðе включена', + 'On' => 'Включена', + }, + }, + 'IncludedFileID' => 'ID вÑтроенного файла', + 'Index' => 'ИндекÑ', + 'IndexOffset' => 'Ð˜Ð½Ð´ÐµÐºÑ ÑмещениÑ', + 'Indexable' => { + Description => 'ИндекÑированный', + PrintConv => { + 'False' => 'Ðет', + 'True' => 'Да', + }, + }, + 'Indexed' => { + Description => 'ИндекÑированный', + PrintConv => { + 'Indexed' => 'Да', + 'Not indexed' => 'Ðет', + }, + }, + 'IndexedColorTableCount' => 'КоличеÑтво индекÑированных цветов', + 'InfraredIlluminator' => { + Description => 'ИнфракраÑÐ½Ð°Ñ Ð¿Ð¾Ð´Ñветка', + PrintConv => { + 'Off' => 'Ðе включена', + 'On' => 'Включена', + }, + }, + 'InitialCameraDolly' => 'ИÑходное положение вдоль линии взглÑда', + 'InitialDisplayEffect' => { + Description => 'Ðачальный Ñффект отображениÑ', + PrintConv => { + 'Off' => 'Ðе включён', + 'On' => 'Включен', + }, + }, + 'InitialHorizontalFOVDegrees' => 'ИÑходное горизонтальное поле Ð·Ñ€ÐµÐ½Ð¸Ñ (°)', + 'InitialViewHeadingDegrees' => 'КурÑовой угол Ð´Ð»Ñ Ð¸Ñходного предÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ (°)', + 'InitialViewPitchDegrees' => 'Угол продольного наклона Ð´Ð»Ñ Ð¸Ñходного предÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ (°)', + 'InitialViewRollDegrees' => 'Угол поперечного наклона Ð´Ð»Ñ Ð¸Ñходного предÑÑ‚Ð°Ð²Ð»ÐµÐ½Ð¸Ñ (°)', + 'InkNames' => 'ÐÐ°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ‡ÐµÑ€Ð½Ð¸Ð»', + 'InkSet' => { + Description => 'Ðабор чернил', + PrintConv => { + 'Not CMYK' => 'Ðе CMYK', + }, + }, + 'InputDeviceName' => 'Ðазвание уÑтройÑтва ввода', + 'InputDeviceSerialNumber' => 'Серийный номер уÑтройÑтва ввода', + 'InsertMode' => 'Режим вÑтавки', + 'InstanceType' => { + Description => 'Тип ÑобытиÑ', + PrintConv => { + 'Exception to Recurring Appointment' => 'ИÑключение Ð´Ð»Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€ÑющегоÑÑ ÑобытиÑ', + 'Non-recurring Appointment' => 'ÐеповторÑющиеÑÑ Ñобытие', + 'Recurring Appointment' => 'ПовторÑющиеÑÑ Ñобытие', + 'Single Instance of Recurring Appointment' => 'Событие Ñ ÐµÐ´Ð¸Ð½Ð¾ÐºÑ€Ð°Ñ‚Ð½Ñ‹Ð¼ повторением', + }, + }, + 'Institution' => 'ИнÑтитут', + 'InstructionSet' => 'Ðабор инÑтрукций', + 'Instructions' => 'ИнÑтрукции', + 'Instrument' => 'ИнÑтрумент', + 'IntendedBusyStatus' => 'Предполагаемый ÑÑ‚Ð°Ñ‚ÑƒÑ Ð·Ð°Ð½ÑтоÑти', + 'IntensityStereo' => 'ИнтенÑивное Ñтерео', + 'InterchangeColorSpace' => { + Description => 'Смена цветового проÑтранÑтва', + PrintConv => { + 'CMY (K) Device Dependent' => 'Ðппаратно-завиÑимый CMY (K)', + 'RGB Device Dependent' => 'Ðппаратно-завиÑимый RGB', + }, + }, + 'IntergraphFlagRegisters' => 'Intergraph – Флаг региÑтров', + 'IntergraphMatrix' => 'Intergraph – Матрица', + 'IntergraphPacketData' => 'Intergraph – Данные пакета', + 'Interlace' => { + Description => 'ЧереÑÑÑ‚Ñ€Ð¾Ñ‡Ð½Ð°Ñ Ñ€Ð°Ð·Ð²Ñ‘Ñ€Ñ‚ÐºÐ°', + PrintConv => { + 'Adam7 Interlace' => 'ЧереÑÑÑ‚Ñ€Ð¾Ñ‡Ð½Ð°Ñ Adam7', + 'Noninterlaced' => 'ПрогреÑÑивнаÑ', + }, + }, + 'InternalIDNumber' => 'Внутренний ID-номер', + 'InternalLeading' => 'Внутренний зазор', + 'InternalVersionNumber' => 'ВнутреннÑÑ Ð²ÐµÑ€ÑÐ¸Ñ Ñ„Ð°Ð¹Ð»Ð°', + 'InteropIndex' => { + Description => 'Ð˜Ð½Ð´ÐµÐºÑ Ñ„Ð°Ð¹Ð»Ð¾Ð²Ð¾Ð¹ ÑовмеÑтимоÑти', + PrintConv => { + 'R03 - DCF option file (Adobe RGB)' => 'R03 – Дополнительный файл DCF (Adobe RGB)', + 'R98 - DCF basic file (sRGB)' => 'R98 – ОÑновной файл DCF (sRGB)', + 'THM - DCF thumbnail file' => 'THM – Файл Ñ Ð¼Ð¸Ð½Ð¸Ð°Ñ‚ÑŽÑ€Ð°Ð¼Ð¸ DCF', + }, + }, + 'InteropOffset' => 'Тег взаимной ÑовмеÑтимоÑти', + 'InteropVersion' => 'ВерÑÐ¸Ñ Ñ„Ð°Ð¹Ð»Ð¾Ð²Ð¾Ð¹ ÑовмеÑтимоÑти', + 'IsBaseFont' => 'Базовый шрифт', + 'IsFixedPitch' => 'Моноширинный шрифт', + 'IsMergedHDR' => 'Объединённый HDR', + 'IsMergedPanorama' => 'ÐžÐ±ÑŠÐµÐ´Ð¸Ð½Ñ‘Ð½Ð½Ð°Ñ Ð¿Ð°Ð½Ð¾Ñ€Ð°Ð¼Ð°', + 'Italic' => 'КурÑив', + 'ItalicAngle' => 'Угол наклона шрифта', + 'ItemSubType' => 'Подтип Ñлемента', + 'Iterations' => 'Повторов', + 'JBIGOptions' => 'Параметры JBIG', + 'JFIFVersion' => 'ВерÑÐ¸Ñ JFIF', + 'JP2Signature' => 'JP2 ПодпиÑÑŒ', + 'JPEGACTables' => 'Таблицы JPEGAC', + 'JPEGDCTables' => 'Таблицы JPEGDC', + 'JPEGDigest' => 'JPEG – Хеш-Ñумма', + 'JPEGImageLength' => 'JPEG – Строк в изображении', + 'JPEGLosslessPredictors' => 'Ð—Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð¿Ñ€ÐµÐ´Ð¸ÐºÑ‚Ð¾Ñ€Ð° JPEG без потерь', + 'JPEGPointTransforms' => 'Преобразование точек JPEG', + 'JPEGProc' => { + Description => 'JPEG-Ñжатие в Ñтаром Ñтиле', + PrintConv => { + 'Baseline' => 'Базовое поÑледовательное', + 'Lossless' => 'Без потерь Ñ ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸ÐµÐ¼ Хаффмана', + }, + }, + 'JPEGQTables' => 'Таблицы JPEGQ', + 'JPEGQuality' => { + Description => 'КачеÑтво изображениÑ', + PrintConv => { + 'Extra Fine' => 'СверхвыÑокое', + 'Fine' => 'Ð’Ñ‹Ñокое', + 'Standard' => 'Стандартное качеÑтво', + }, + }, + 'JPEGQualityEstimate' => 'JPEG – Оценка качеÑтва', + 'JPEGRestartInterval' => 'Интервал перезапуÑка JPEG', + 'JPEGTables' => 'JPEG-таблицы', + 'JSONMetadata' => 'Метаданные JSON', + 'JobID' => 'ID заданиÑ', + 'JobTitle' => 'ДолжноÑÑ‚ÑŒ', + 'Journal' => 'Журнал', + 'JpgFromRaw' => 'Jpg-файл, вÑтроенный в Raw-файл', + 'JpgFromRawLength' => 'Строк в JPG-файле, вÑтроенного в RAW-файл', + 'JpgFromRawStart' => 'Смещение JPG-файла, вÑтроенного в RAW-файл', + 'JumpToXPEP' => 'Переход к XPEP', + 'KBAT_Unknown10' => 'KBAT – ÐеизвеÑтный 10', + 'KBAT_Unknown11' => 'KBAT – ÐеизвеÑтный 11', + 'KBAT_Unknown12' => 'KBAT – ÐеизвеÑтный 12', + 'KBAT_Unknown13' => 'KBAT – ÐеизвеÑтный 13', + 'KBAT_Unknown2' => 'KBAT – ÐеизвеÑтный 2', + 'KBAT_Unknown9' => 'KBAT – ÐеизвеÑтный 9', + 'KByteSize' => 'Общий размер в килобайтах', + 'KF8CoverURI' => 'KF8 – URI обложки', + 'Key' => 'Код', + 'KeyCode' => 'Код ключа', + 'KeyFramePositions' => 'Положение ключевых кадров', + 'KeyFramesTimes' => 'Ð’Ñ€ÐµÐ¼Ñ ÐºÐ»ÑŽÑ‡ÐµÐ²Ñ‹Ñ… кадров', + 'KeywordInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ ключевых Ñловах', + 'Keywords' => 'Ключевые Ñлова', + 'Label' => 'Метка', + 'LameBitrate' => 'Lame – Битрейт', + 'LameLowPassFilter' => 'Lame – Фильтр нижних чаÑтот', + 'LameMethod' => { + Description => 'Lame – Метод кодированиÑ', + PrintConv => { + 'ABR' => 'ABR – Средний битрейт', + 'ABR (2-pass)' => 'ABR – Средний битрейт (2 прохода)', + 'CBR' => 'CBR – ПоÑтоÑнный битрейт', + 'CBR (2-pass)' => 'CBR – ПоÑтоÑнный битрейт (2 прохода)', + 'VBR' => 'VBR – переменный битрейт', + 'VBR (new/mtrh)' => 'VBR – переменный битрейт (новый/mtrh)', + 'VBR (old/rh)' => 'VBR – переменный битрейт (Ñтарый/rh)', + }, + }, + 'LameQuality' => 'Lame – КачеÑтво', + 'LameStereoMode' => { + Description => 'Lame – Режим Ñтерео', + PrintConv => { + 'Auto' => 'ÐвтоматичеÑкий', + 'Dual Channels' => 'Двуканальный режим', + 'Forced Joint Stereo' => 'Принудительное объединённое Ñтерео', + 'Intensity Stereo' => 'ИнтенÑивное Ñтерео', + 'Joint Stereo' => 'Объединённое Ñтерео', + 'Mono' => 'Моно', + 'Stereo' => 'Стерео', + }, + }, + 'LameVBRQuality' => 'Lame – КачеÑтво переменного битрейта', + 'Language' => 'Язык', + 'LanguageIdentifier' => 'Идентификатор Ñзыка', + 'LargestValidInteriorRectHeight' => 'МакÑимально Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð°Ñ Ð²Ñ‹Ñота прÑмоугольника', + 'LargestValidInteriorRectLeft' => 'ОтÑтуп Ñлева Ð´Ð»Ñ Ð¼Ð°ÐºÑимально возможного прÑмоугольника', + 'LargestValidInteriorRectTop' => 'ОтÑтуп Ñверху Ð´Ð»Ñ Ð¼Ð°ÐºÑимально возможного прÑмоугольника', + 'LargestValidInteriorRectWidth' => 'МакÑимально Ð²Ð¾Ð·Ð¼Ð¾Ð¶Ð½Ð°Ñ ÑˆÐ¸Ñ€Ð¸Ð½Ð° прÑмоугольника', + 'LastAuthor' => 'ПоÑледнее редактирование Ñделал', + 'LastBackupDate' => 'Дата поÑледнего резервного копированиÑ', + 'LastChar' => 'ПоÑледний Ñимвол шрифта', + 'LastKeyFrameTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð¿Ð¾Ñледнего ключевого кадра', + 'LastKeywordIPTC' => 'ПоÑледнее ключевое Ñлово IPTC', + 'LastKeywordXMP' => 'ПоÑледнее ключевое Ñлово XMP', + 'LastModifiedBy' => 'ПоÑледнее изменение Ñделал', + 'LastPhotoDate' => 'Дата ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿Ð¾Ñледнего изображениÑ', + 'LastPrinted' => 'Дата поÑледней печати', + 'LastTimeStamp' => 'ПоÑледнÑÑ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð½Ð°ÌÑ Ð¼ÐµÑ‚ÐºÐ°', + 'LastUpdateTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð¿Ð¾Ñледнего обновлениÑ', + 'LateralChromaticAberrationCorrectionAlreadyApplied' => 'Применена ÐºÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ñ…Ñ€Ð¾Ð¼Ð°Ñ‚Ð¸Ñ‡ÐµÑкой аберрации', + 'LatestAgeOrHighestStage' => 'ПоÑледний век/Ð’Ñ‹Ñший ÑруÑ', + 'LatestEonOrHighestEonothem' => 'ПоÑледний Ñон/Ð’Ñ‹ÑÑˆÐ°Ñ Ñонотема', + 'LatestEpochOrHighestSeries' => 'ПоÑледнÑÑ Ñпоха/Ð’Ñ‹Ñший отдел', + 'LatestEraOrHighestErathem' => 'ПоÑледнÑÑ Ñра/Ð’Ñ‹ÑÑˆÐ°Ñ Ñратема', + 'LatestPeriodOrHighestSystem' => 'ПоÑледний период/Ð’Ñ‹ÑÑˆÐ°Ñ ÑиÑтема', + 'Latitude' => 'Широта', + 'LayerBlendModes' => { + Description => 'Режим Ð½Ð°Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ñлоёв', + PrintConv => { + 'Color' => 'ЦветноÑÑ‚ÑŒ', + 'Color Burn' => 'Затемнение оÑновы', + 'Color Dodge' => 'ОÑветление оÑновы', + 'Darken' => 'Затемнение', + 'Darker Color' => 'Темнее', + 'Difference' => 'Разница', + 'Dissolve' => 'Затухание', + 'Divide' => 'Разделить', + 'Exclusion' => 'ИÑключение', + 'Hard Light' => 'ЖёÑткий Ñвет', + 'Hard Mix' => 'ЖёÑткое Ñмешение', + 'Hue' => 'Цветовой тон', + 'Lighten' => 'Замена Ñветлым', + 'Lighter Color' => 'Светлее', + 'Linear Burn' => 'Линейный затемнитель', + 'Linear Dodge' => 'Линейный оÑветлитель', + 'Linear Light' => 'Линейный Ñвет', + 'Luminosity' => 'ЯркоÑÑ‚ÑŒ', + 'Multiply' => 'Умножение', + 'Normal' => 'Обычный', + 'Overlay' => 'Перекрытие', + 'Pass Through' => 'ПропуÑтить', + 'Pin Light' => 'Точечный Ñвет', + 'Saturation' => 'ÐаÑыщенноÑÑ‚ÑŒ', + 'Screen' => 'Экран', + 'Soft Light' => 'ÐœÑгкий Ñвет', + 'Subtract' => 'Вычитание', + 'Vivid Light' => 'Яркий Ñвет', + }, + }, + 'LayerComps' => 'Композиции Ñлоёв', + 'LayerCount' => 'КоличеÑтво Ñлоёв', + 'LayerGroupsEnabledID' => 'ID включенных групп Ñлоёв', + 'LayerIDs' => 'ID Ñлоёв', + 'LayerModifyDates' => 'Дата Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÑлоÑ', + 'LayerNames' => 'ÐÐ°Ð·Ð²Ð°Ð½Ð¸Ñ Ñлоёв', + 'LayerOpacities' => 'ÐепрозрачноÑÑ‚ÑŒ ÑлоÑ', + 'LayerRectangles' => 'ПрÑмоугольники ÑлоÑ', + 'LayerSelectionIDs' => 'Идентификаторы выборанного ÑлоÑ', + 'LayerUnicodeNames' => 'Юникодные Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñлоёв', + 'LayersGroupInfo' => 'Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ группе Ñлоёв', + 'Layout' => { + Description => 'Макет', + PrintConv => { + 'Scan Lines' => 'Линии ÑканированиÑ', + 'Tiles' => 'Тайлы', + }, + }, + 'LeftMargin' => 'ОтÑтуп Ñлева', + 'LegacyIPTCDigest' => 'Хеш-Ñумма прежней верÑии IPTC', + 'Length' => 'Общий размер в байтах', + 'Lens' => 'Объектив', + 'Lens35efl' => 'Объектив', + 'LensDistortInfo' => 'ДиÑторÑÐ¸Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð¸Ð²Ð°', + 'LensID' => 'ID объектива', + 'LensInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾Ð± объективе', + 'LensMake' => 'Производитель объектива', + 'LensManufacturer' => 'Производитель объектива', + 'LensModel' => 'Модель объектива', + 'LensNumber' => 'Серийный номер объектива', + 'LensSerialNumber' => 'Серийный номер объектива', + 'LensShading' => 'Виньетирование объектива', + 'LensSpec' => 'Параметры объектива', + 'LensTemperature' => 'Температура объектива', + 'LibraryID' => 'ID библиотеки', + 'License' => 'ЛицензиÑ', + 'LicenseEndDate' => 'Дата Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¸Ð¸', + 'LicenseID' => 'PLUS-ID лицензии', + 'LicenseInfoURL' => 'URL лицензии', + 'LicenseStartDate' => 'Дата вÑÑ‚ÑƒÐ¿Ð»ÐµÐ½Ð¸Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¸Ð¸ в Ñилу', + 'LicenseTransactionDate' => 'Дата лицензионной Ñделки', + 'Licensee' => 'Ð›Ð¸Ñ†ÐµÐ½Ð·Ð¸Ñ Ð¿Ñ€ÐµÐ´Ð¾Ñтавлена длÑ', + 'LicenseeID' => 'PLUS-ID лицензиата', + 'LicenseeImageID' => 'ID Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸Ñвоенный лицензиатом', + 'LicenseeImageNotes' => 'ÐŸÑ€Ð¸Ð¼ÐµÑ‡Ð°Ð½Ð¸Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¸Ð°Ñ‚Ð°', + 'LicenseeName' => 'Ð˜Ð¼Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¸Ð°Ñ‚Ð°', + 'LicenseeProjectReference' => 'Ðазвание проека приÑвоенное лицензиатом', + 'LicenseeTransactionID' => 'ID транзакции приÑвоенное лицензиатом', + 'Licensor' => 'Лицензор', + 'LicensorCity' => 'Город Ð¿Ñ€Ð¾Ð¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¾Ñ€Ð°', + 'LicensorCountry' => 'Страна Ð¿Ñ€Ð¾Ð¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¾Ñ€Ð°', + 'LicensorEmail' => 'ÐÐ´Ñ€ÐµÑ Ñлектронной почты лицензора', + 'LicensorExtendedAddress' => 'Дополнительные адреÑа Ñлектронной почты лицензора', + 'LicensorID' => 'PLUS-ID лицензора', + 'LicensorImageID' => 'ID Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð´Ð°Ð½Ð½Ð¾Ðµ лицензором', + 'LicensorName' => 'Ð˜Ð¼Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¾Ñ€Ð°', + 'LicensorNotes' => 'Коментарии лицензора', + 'LicensorPostalCode' => 'Почтовый Ð¸Ð½Ð´ÐµÐºÑ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¸Ð°Ñ€Ð°', + 'LicensorRegion' => 'ОблаÑÑ‚ÑŒ Ð¿Ñ€Ð¾Ð¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¾Ñ€Ð°', + 'LicensorStreetAddress' => 'Улица Ð¿Ñ€Ð¾Ð¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð»Ð¸Ñ†ÐµÐ½Ð·Ð¾Ñ€Ð°', + 'LicensorTelephone1' => 'Телефон 1 лицензора', + 'LicensorTelephone2' => 'Телефон 2 лицензора', + 'LicensorTelephoneType1' => { + Description => 'Тип телефона 1', + PrintConv => { + 'Cell' => 'Мобильный', + 'FAX' => 'ФÐКС', + 'Home' => 'Домашний', + 'Pager' => 'Пейджер', + 'Work' => 'Рабочий', + }, + }, + 'LicensorTelephoneType2' => { + Description => 'Тип телефона 2', + PrintConv => { + 'Cell' => 'Мобильный', + 'FAX' => 'ФÐКС', + 'Home' => 'Домашний', + 'Pager' => 'Пейджер', + 'Work' => 'Рабочий', + }, + }, + 'LicensorTransactionID' => 'ID транзакции приÑвоенный лицензором', + 'LicensorURL' => 'URL лицензора', + 'LightSource' => { + Description => 'Тип оÑвещениÑ', + PrintConv => { + 'Cloudy' => 'Облачно (6500 К)', + 'Cool White Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° – Холодный Ñвет (4150 К)', + 'Day White Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° – Дневной белый (5050 К)', + 'Daylight' => 'Дневной Ñвет (5500 К)', + 'Daylight Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° дневного Ñвета (6400 К)', + 'Fine Weather' => 'ЯÑÐ½Ð°Ñ Ð¿Ð¾Ð³Ð¾Ð´Ð° (5500 К)', + 'Flash' => 'Ð’Ñпышка (5500 К)', + 'Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° (4150 К)', + 'ISO Studio Tungsten' => 'ISO Ð´Ð»Ñ Ñтудийных ламп накаливаниÑ', + 'Other' => 'Другой иÑточник Ñвета', + 'Shade' => 'Тень (7500 К)', + 'Standard Light A' => 'Стандартный Ñвет A', + 'Standard Light B' => 'Стандартный Ñвет B', + 'Standard Light C' => 'Стандартный Ñвет C', + 'Tungsten (Incandescent)' => 'Лампа Ð½Ð°ÐºÐ°Ð»Ð¸Ð²Ð°Ð½Ð¸Ñ (2850 К)', + 'Unknown' => 'ÐеизвеÑтный', + 'Warm White Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° – Тёплый Ñвет (2925 К)', + 'White Fluorescent' => 'ФлуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð° – Белый Ñвет (3525 К)', + }, + }, + 'LightSourceSpecial' => { + Description => 'Специальный иÑточник Ñвета', + PrintConv => { + 'Off' => 'Ðе иÑпользовалÑÑ', + 'On' => 'ИÑпользовалÑÑ', + }, + }, + 'LightValue' => 'Световое чиÑло', + 'Lightness' => 'ОÑвещенноÑÑ‚ÑŒ', + 'LightroomWorkflow' => 'Рабочий процеÑÑ Lightroom', + 'LineOrder' => { + Description => 'ПорÑдок Ñтрок', + PrintConv => { + 'Decreasing Y' => 'По убыванию Y', + 'Increasing Y' => 'По возраÑтанию Y', + 'Random Y' => 'Случайный Y', + }, + }, + 'LinearResponseLimit' => 'Предел линейного отклика', + 'LinearityLimitBlue' => 'Предел линейноÑти – Синий', + 'LinearityLimitGreen' => 'Предел линейноÑти – Зелёный', + 'LinearityLimitRed' => 'Предел линейноÑти – КраÑный', + 'LinearizationCoefficients1' => 'КоÑффициенты линеаризации 1', + 'LinearizationCoefficients2' => 'КоÑффициенты линеаризации 2', + 'LinearizationTable' => 'Таблица линеаризации', + 'Linearized' => { + Description => 'ЛинеаризациÑ', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'Lines' => 'Строк', + 'LinkedProfileName' => 'Ðазвание ÑвÑзанного профилÑ', + 'LithostratigraphicTerms' => 'ЛитоÑтратиграфичеÑкие Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¾Ñ€Ð¾Ð´', + 'LivingSpecimen' => 'Живой образец', + 'LivingSpecimenMaterialSampleID' => 'Живой образец – ID образца материала', + 'LocalBasePath' => 'Локальный базовый путь', + 'LocalCaption' => 'ОпиÑание меÑта', + 'LocalDefaultAlarm' => 'Локальный Ñигнал по-умолчанию', + 'LocalPositionNED' => 'Ð›Ð¾ÐºÐ°Ð»ÑŒÐ½Ð°Ñ Ð¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ NED', + 'LocalizedCameraModel' => 'Локализованное название модели камеры', + 'Location' => 'МеÑтоположение', + 'Logo' => 'Логотип', + 'LongExposureNoiseReduction' => { + Description => 'Шумоподавление при длительной выдержке', + PrintConv => { + 'Auto' => 'ÐвтоматичеÑкое', + 'Off' => 'Ðе включено', + 'On' => 'Включено', + }, + }, + 'Longitude' => 'Долгота', + 'LookModTransform' => 'Преобразование вида ACES-ACES', + 'LookupTable' => 'Таблица подÑтановки', + 'LowestBiostratigraphicZone' => 'ÐÐ¸Ð·ÑˆÐ°Ñ Ð±Ð¸Ð¾ÑтратиграфичеÑÐºÐ°Ñ Ð·Ð¾Ð½Ð°', + 'MD5Signature' => 'MD5', + 'MD5Sum' => 'Сумма MD5', + 'MDColorTable' => 'MD – Таблица цветов', + 'MDFileTag' => 'MD – Формат иÑходных данных', + 'MDFileUnits' => 'MD – Единицы данных файла', + 'MDItemAccountHandles' => 'MD Item – ДеÑкрипторы аккаунта', + 'MDItemAccountIdentifier' => 'MD Item – Идентификатор аккаунта', + 'MDItemAcquisitionMake' => 'MD Item – Производитель уÑтройÑтва', + 'MDItemAcquisitionModel' => 'MD Item – Модель уÑтройÑтва', + 'MDItemAltitude' => 'MD Item – Ð’Ñ‹Ñота', + 'MDItemAperture' => 'MD Item – Диафрагма', + 'MDItemAudioBitRate' => 'MD Item – Битрейт аудио', + 'MDItemAudioChannelCount' => 'MD Item – КоличеÑтво аудиоканалов', + 'MDItemAuthorEmailAddresses' => 'MD Item – ÐÐ´Ñ€ÐµÑ Ñлектронной почты автора', + 'MDItemAuthors' => 'MD Item – Ðвторы', + 'MDItemBitsPerSample' => 'MD Item – КоличеÑтво бит на образец', + 'MDItemBundleIdentifier' => 'MD Item – Идентификатор комплекта', + 'MDItemCity' => 'MD Item – Город', + 'MDItemCodecs' => 'MD Item – Кодеки', + 'MDItemColorSpace' => 'MD Item – Цветовое проÑтранÑтво', + 'MDItemComment' => 'MD Item – Комментарий', + 'MDItemContentCreationDate' => 'MD Item – Дата ÑозданиÑ', + 'MDItemContentCreationDateRanking' => 'MD Item – Дата ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ â€“ Рейтинг', + 'MDItemContentCreationDate_Ranking' => 'MD Item – Дата ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ â€“ Рейтинг', + 'MDItemContentModificationDate' => 'MD Item – Дата редактированиÑ', + 'MDItemContentType' => 'MD Item – Тип контента', + 'MDItemContentTypeTree' => 'MD Item – Тип контента – Древо', + 'MDItemContributors' => 'MD Item – ВнеÑшие вклад', + 'MDItemCopyright' => 'MD Item – ÐвторÑкое право', + 'MDItemCountry' => 'MD Item – Страна', + 'MDItemCreator' => 'MD Item – Создано в', + 'MDItemDateAdded' => 'MD Item – Дата добавлениÑ', + 'MDItemDateAdded_Ranking' => 'MD Item – Дата Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ â€“ Рейтинг', + 'MDItemDescription' => 'MD Item – ОпиÑание', + 'MDItemDisplayName' => 'MD Item – Локализованное название файла', + 'MDItemDownloadedDate' => 'MD Item – Дата загрузки', + 'MDItemDurationSeconds' => 'MD Item – ПродолжительноÑÑ‚ÑŒ в Ñекундах', + 'MDItemEXIFGPSVersion' => 'MD Item – EXIF – ВерÑÐ¸Ñ GPS', + 'MDItemEXIFVersion' => 'MD Item – ВерÑÐ¸Ñ EXIF', + 'MDItemEmailConversationID' => 'MD Item – ID перепиÑки по Ñлектронной почте', + 'MDItemEncodingApplications' => 'MD Item – Кодировано в приложении', + 'MDItemExposureMode' => 'MD Item – Режим ÑкÑпозиции', + 'MDItemExposureProgram' => 'MD Item – Программа ÑкÑпозиции', + 'MDItemExposureTimeSeconds' => 'MD Item – Выдержка', + 'MDItemFNumber' => 'MD Item – Диафрагменное чиÑло', + 'MDItemFSContentChangeDate' => 'MD Item – FS – Дата редактированиÑ', + 'MDItemFSCreationDate' => 'MD Item – FS – Дата ÑозданиÑ', + 'MDItemFSCreatorCode' => 'MD Item – FS – Код программы, Ñоздавшей файл', + 'MDItemFSFinderFlags' => 'MD Item – FS – Ðтрибуты файла', + 'MDItemFSHasCustomIcon' => 'MD Item – FS – Ðаличие иконки файла', + 'MDItemFSInvisible' => 'MD Item – FS – Скрытый', + 'MDItemFSIsExtensionHidden' => 'MD Item – FS – РаÑширение файла Ñкрыто', + 'MDItemFSIsStationery' => 'MD Item – FS – Шаблон', + 'MDItemFSLabel' => { + Description => 'MD Item – FS – Ð¦Ð²ÐµÑ‚Ð½Ð°Ñ Ð¼ÐµÑ‚ÐºÐ° файла', + PrintConv => { + '0 (none)' => '0 (Без метки)', + '1 (Gray)' => '1 (СераÑ)', + '2 (Green)' => '2 (ЗелёнаÑ)', + '3 (Purple)' => '3 (ПурпурнаÑ)', + '4 (Blue)' => '4 (СинÑÑ)', + '5 (Yellow)' => '5 (ЖёлтаÑ)', + '6 (Red)' => '6 (КраÑнаÑ)', + '7 (Orange)' => '7 (ОранжеваÑ)', + }, + }, + 'MDItemFSName' => 'MD Item – FS – Ðазвание файла', + 'MDItemFSNodeCount' => 'MD Item – FS – КоличеÑтво файлов в каталоге', + 'MDItemFSOwnerGroupID' => 'MD Item – FS – ID группы владельца файла', + 'MDItemFSOwnerUserID' => 'MD Item – FS – ID Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Ð²Ð»Ð°Ð´ÐµÐ»ÑŒÑ†Ð° файла', + 'MDItemFSSize' => 'MD Item – FS – Размер файла', + 'MDItemFSTypeCode' => 'MD Item – FS – Код типа файла', + 'MDItemFinderComment' => 'MD Item – Комментарий к файлу', + 'MDItemFlashOnOff' => 'MD Item – Срабатывание вÑпышки', + 'MDItemFocalLength' => 'MD Item – ФокуÑное раÑÑтоÑние', + 'MDItemGPSDateStamp' => 'MD Item – GPS – Дата и Ð²Ñ€ÐµÐ¼Ñ Ð¼ÐµÑтоположениÑ', + 'MDItemGPSStatus' => 'MD Item – GPS – СоÑтоÑние приемника во Ð²Ñ€ÐµÐ¼Ñ Ñъёмки', + 'MDItemGPSTrack' => 'MD Item – GPS – Трек маршрута', + 'MDItemHasAlphaChannel' => 'MD Item – Ðаличие Ðльфа-канала', + 'MDItemISOSpeed' => 'MD Item – ISO', + 'MDItemIdentifier' => 'MD Item – Идентификатор', + 'MDItemImageDirection' => 'MD Item – ÐÐ°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ ÐºÐ°Ð¼ÐµÑ€Ñ‹ при Ñъёмке', + 'MDItemInterestingDateRanking' => 'MD Item – Дата интереÑных меÑÑ‚ – Рейтинг', + 'MDItemInterestingDate_Ranking' => 'MD Item – Дата интереÑных меÑÑ‚ – Рейтинг', + 'MDItemIsApplicationManaged' => 'MD Item – УправлÑетÑÑ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸ÐµÐ¼', + 'MDItemIsExistingThread' => 'MD Item – Цепочка Ñообщений', + 'MDItemIsLikelyJunk' => 'MD Item – Спам', + 'MDItemKeywords' => 'MD Item – Ключевые Ñлова', + 'MDItemKind' => 'MD Item – Тип файла', + 'MDItemLastUsedDate' => 'MD Item – Дата поÑледнего иÑпользованиÑ', + 'MDItemLastUsedDate_Ranking' => 'MD Item – Дата поÑледнего иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ â€“ Рейтинг', + 'MDItemLatitude' => 'MD Item – Широта', + 'MDItemLensModel' => 'MD Item – Модель объектива', + 'MDItemLogicalSize' => 'MD Item – ЛогичеÑкий размер', + 'MDItemLongitude' => 'MD Item – Долгота', + 'MDItemMailDateReceived_Ranking' => 'MD Item – Дата Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñ‡Ñ‚Ñ‹ – Рейтинг', + 'MDItemMailboxes' => 'MD Item – Почтовые Ñщики', + 'MDItemMediaTypes' => 'MD Item – Типы медиафайлов', + 'MDItemNumberOfPages' => 'MD Item – КоличеÑтво Ñтраниц', + 'MDItemOrientation' => 'MD Item – ОриентациÑ', + 'MDItemOriginApplicationIdentifier' => 'MD Item – Идентификатор приложениÑ', + 'MDItemOriginMessageID' => 'MD Item – ID ÑообщениÑ', + 'MDItemOriginSenderDisplayName' => 'MD Item – Ð˜Ð¼Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð¸Ñ‚ÐµÐ»Ñ', + 'MDItemOriginSenderHandle' => 'MD Item – ДеÑкриптор отправителÑ', + 'MDItemOriginSubject' => 'MD Item – Тема ÑообщениÑ', + 'MDItemPageHeight' => 'MD Item – Ð’Ñ‹Ñота Ñтраницы', + 'MDItemPageWidth' => 'MD Item – Ширина Ñтраницы', + 'MDItemPhysicalSize' => 'MD Item – ФизичеÑкий размер', + 'MDItemPixelCount' => 'MD Item – КоличеÑтво пикÑелей', + 'MDItemPixelHeight' => 'MD Item – Ð’Ñ‹Ñота в пикÑелÑÑ…', + 'MDItemPixelWidth' => 'MD Item – Ширина в пикÑелÑÑ…', + 'MDItemPrimaryRecipientEmailAddresses' => 'MD Item – ÐÐ´Ñ€ÐµÑ Ñлектронной почты оÑновного получателÑ', + 'MDItemProfileName' => 'MD Item – Ðазвание цветового профилÑ', + 'MDItemRecipients' => 'MD Item – Получатели', + 'MDItemRedEyeOnOff' => 'MD Item – Уменьшение Ñффекта "краÑных глаз"', + 'MDItemResolutionHeightDPI' => 'MD Item – Разрешение по выÑоте в DPI', + 'MDItemResolutionWidthDPI' => 'MD Item – Разрешение по ширине в DPI', + 'MDItemSecurityMethod' => 'MD Item – Метод шифрованиÑ', + 'MDItemSpeed' => 'MD Item – СкороÑÑ‚ÑŒ передвижениÑ', + 'MDItemStateOrProvince' => 'MD Item – ОблаÑÑ‚ÑŒ/Район', + 'MDItemStreamable' => 'MD Item – Потоковый', + 'MDItemSubject' => 'MD Item – Тема', + 'MDItemTimestamp' => 'MD Item – ВременнаÌÑ Ð¼ÐµÑ‚ÐºÐ°', + 'MDItemTitle' => 'MD Item – Ðазвание файла', + 'MDItemTotalBitRate' => 'MD Item – Общий битрейт', + 'MDItemUseCount' => 'MD Item – Счётчик иÑпользованиÑ', + 'MDItemUsedDates' => 'MD Item – ИÑпользуемые даты', + 'MDItemUserDownloadedDate' => 'MD Item – Пользователь – Дата загрузки', + 'MDItemUserDownloadedUserHandle' => 'MD Item – Пользователь – ДеÑкриптор загрузки пользователÑ', + 'MDItemUserSharedReceivedDate' => 'MD Item – User Shared Received Date', + 'MDItemUserSharedReceivedRecipient' => 'MD Item – User Shared Received Recipient', + 'MDItemUserSharedReceivedRecipientHandle' => 'MD Item – User Shared Received Recipient Handle', + 'MDItemUserSharedReceivedSender' => 'MD Item – User Shared Received Sender', + 'MDItemUserSharedReceivedSenderHandle' => 'MD Item – User Shared Received Sender Handle', + 'MDItemUserSharedReceivedTransport' => 'MD Item – ÐžÐ±Ñ‰Ð°Ñ Ð¿Ð°Ð¿ÐºÐ° Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ â€“ Received Transport', + 'MDItemUserTags' => 'MD Item – ПользовательÑкие теги', + 'MDItemVersion' => 'MD Item – ВерÑÐ¸Ñ Ñ„Ð°Ð¹Ð»Ð°', + 'MDItemVideoBitRate' => 'MD Item – Битрейт видео', + 'MDItemWhereFroms' => 'MD Item – ИÑточник файла', + 'MDItemWhiteBalance' => 'MD Item – Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾', + 'MDLabName' => 'MD – Создатель файла', + 'MDPrepDate' => 'MD – Дата ÑозданиÑ', + 'MDPrepTime' => 'MD – Ð’Ñ€ÐµÐ¼Ñ ÑозданиÑ', + 'MDSampleInfo' => 'MD – ОпиÑание файла', + 'MDScalePixel' => 'MD – Коефициент маÑÑˆÑ‚Ð°Ð±Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¿Ð¸ÐºÑелÑ', + 'MIDIControlVersion' => 'ВерÑÐ¸Ñ MIDI Control', + 'MIDISong' => 'MIDI композициÑ', + 'MIMEType' => 'MIME тип', + 'MOIVersion' => 'ВерÑÐ¸Ñ MOI', + 'MPEG7Binary' => 'Бинарный MPEG7', + 'MPEGAudioVersion' => 'ВерÑÐ¸Ñ MPEG аудио', + 'MPFVersion' => 'ВерÑÐ¸Ñ MPF', + 'MPImage' => 'Изображение MP', + 'MPImageFlags' => { + Description => 'MP изображение – Флаги', + PrintConv => { + 'Dependent child image' => 'ЗавиÑимое вложенное изображение', + 'Dependent parent image' => 'ЗавиÑимое родительÑкое изображение', + 'Representative image' => 'Репрезентативное изображение', + }, + }, + 'MPImageFormat' => 'MP изображение – Формат', + 'MPImageLength' => 'MP изображение – КоличеÑтво Ñтрок', + 'MPImageStart' => 'MP изображение – Ðачало', + 'MPImageType' => { + Description => 'MP изображение – Тип', + PrintConv => { + 'Baseline MP Primary Image' => 'Базовое первичное изображение MP', + 'Large Thumbnail (VGA equivalent)' => 'Большой ÑÑкиз (Ñквивалент VGA)', + 'Large Thumbnail (full HD equivalent)' => 'Большой ÑÑкиз (Ñквивалент Full HD)', + 'Multi-angle' => 'МногоракурÑное', + 'Multi-frame Disparity' => 'Многокадровое Ñмещённое (Disparity)', + 'Multi-frame Panorama' => 'ÐœÐ½Ð¾Ð³Ð¾ÐºÐ°Ð´Ñ€Ð¾Ð²Ð°Ñ Ð¿Ð°Ð½Ð¾Ñ€Ð°Ð¼Ð°', + 'Undefined' => 'Ðеопределённый', + }, + }, + 'MPIndividualNum' => 'Индивидуальный номер MP', + 'MSDocumentText' => 'MS – ТекÑтовый документ', + 'MSDocumentTextPosition' => 'MS – ТекÑтовый документ – ПозициÑ', + 'MSPropertySetStorage' => 'MS – Хранилище ÑвойÑтв', + 'MSStereo' => { + Description => 'MS Ñтерео', + PrintConv => { + 'Off' => 'Ðе включено', + 'On' => 'Включено', + }, + }, + 'MachineID' => 'ID машины', + 'MachineObservation' => 'Машинное наблюдение', + 'MachineObservationDay' => 'День меÑÑца машинного наблюдениÑ', + 'MachineObservationEarliestDate' => 'Дата начала машинного наблюдениÑ', + 'MachineObservationEndDayOfYear' => 'День года Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ð¼Ð°ÑˆÐ¸Ð½Ð½Ð¾Ð³Ð¾ наблюдениÑ', + 'MachineObservationEventDate' => 'Дата машинного наблюдениÑ', + 'MachineObservationEventID' => 'ID машинного наблюдениÑ', + 'MachineObservationEventRemarks' => 'Комментарии к машинному наблюдению', + 'MachineObservationEventTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð¼Ð°ÑˆÐ¸Ð½Ð½Ð¾Ð³Ð¾ наблюдениÑ', + 'MachineObservationFieldNotes' => 'Полевые заметки о машинном наблюдении', + 'MachineObservationFieldNumber' => 'Ðомер полевых заметок о машинном наблюдении', + 'MachineObservationHabitat' => 'Ðреал машинного наблюдениÑ', + 'MachineObservationLatestDate' => 'Дата Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ð¼Ð°ÑˆÐ¸Ð½Ð½Ð¾Ð³Ð¾ наблюдениÑ', + 'MachineObservationMonth' => 'МеÑÑц машинного наблюдениÑ', + 'MachineObservationParentEventID' => 'ID оÑновного машинного наблюдениÑ', + 'MachineObservationSampleSizeUnit' => 'Машинное наблюдение – Единицы размера', + 'MachineObservationSampleSizeValue' => 'Машинное наблюдение – Размер образца', + 'MachineObservationSamplingEffort' => 'Машинное наблюдение – Затраченные уÑилиÑ', + 'MachineObservationSamplingProtocol' => 'Машинное наблюдение – Метод иÑÑледованиÑ', + 'MachineObservationStartDayOfYear' => 'День года начала машинного наблюдениÑ', + 'MachineObservationVerbatimEventDate' => 'Дата машинного Ð½Ð°Ð±Ð»ÑŽÐ´ÐµÐ½Ð¸Ñ Ð´Ð¾Ñловно', + 'MachineObservationYear' => 'Год машинного наблюдениÑ', + 'MacintoshNSPrintInfo' => 'Macintosh NS – Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ печати', + 'MacintoshPrintInfo' => 'Macintosh – Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ печати', + 'Macro' => { + Description => 'Макро', + PrintConv => { + 'Macro' => 'Макро', + 'Manual' => 'Ручной', + 'Normal' => 'Обычный', + 'Off' => 'Выключен', + 'On' => 'Включен', + }, + }, + 'Magnetometer' => 'Магнитометр', + 'MajorBrand' => { + Description => 'ОÑÐ½Ð¾Ð²Ð½Ð°Ñ Ñ‚Ð¾Ñ€Ð³Ð¾Ð²Ð°Ñ Ð¼Ð°Ñ€ÐºÐ°', + PrintConv => { + 'JPEG 2000 Compound Image (.JPM)' => 'СоÑтавное изображение JPEG 2000 (.JPM)', + 'JPEG 2000 Image (.JP2)' => 'Изображение JPEG 2000 (.JP2)', + 'JPEG 2000 with extensions (.JPX)' => 'Улучшенный JPEG 2000 (.JPX)', + }, + }, + 'MajorVersion' => 'ÐœÐ°Ð¶Ð¾Ñ€Ð½Ð°Ñ Ð²ÐµÑ€ÑиÑ', + 'Make' => 'Производитель', + 'MakerNote' => 'Приватные данные DNG', + 'MakerNoteApple' => 'Комментарии Apple', + 'MakerNoteCanon' => 'Комментарии Canon', + 'MakerNoteCasio' => 'Комментарии Casio', + 'MakerNoteCasio2' => 'Комментарии Casio 2', + 'MakerNoteDJI' => 'Комментарии DJI', + 'MakerNoteFLIR' => 'Комментарии FLIR', + 'MakerNoteFujiFilm' => 'Комментарии Fuji Film', + 'MakerNoteGE' => 'Комментарии GE', + 'MakerNoteGE2' => 'Комментарии GE2', + 'MakerNoteHP' => 'Комментарии HP', + 'MakerNoteHP2' => 'Комментарии HP2', + 'MakerNoteHP4' => 'Комментарии HP4', + 'MakerNoteHP6' => 'Комментарии HP6', + 'MakerNoteHasselblad' => 'Комментарии Hasselblad', + 'MakerNoteISL' => 'Комментарии ISL', + 'MakerNoteJVC' => 'Комментарии JVC', + 'MakerNoteJVCText' => 'Комментарии JVC – ТекÑÑ‚', + 'MakerNoteKodak10' => 'Комментарии Kodak 10', + 'MakerNoteKodak11' => 'Комментарии Kodak 11', + 'MakerNoteKodak12' => 'Комментарии Kodak 12', + 'MakerNoteKodak1a' => 'Комментарии Kodak 1a', + 'MakerNoteKodak1b' => 'Комментарии Kodak 1b', + 'MakerNoteKodak2' => 'Комментарии Kodak 2', + 'MakerNoteKodak3' => 'Комментарии Kodak 3', + 'MakerNoteKodak4' => 'Комментарии Kodak 4', + 'MakerNoteKodak5' => 'Комментарии Kodak 5', + 'MakerNoteKodak6a' => 'Комментарии Kodak 6a', + 'MakerNoteKodak6b' => 'Комментарии Kodak 6b', + 'MakerNoteKodak7' => 'Комментарии Kodak 7', + 'MakerNoteKodak8a' => 'Комментарии Kodak 8a', + 'MakerNoteKodak8b' => 'Комментарии Kodak 8b', + 'MakerNoteKodak8c' => 'Комментарии Kodak 8c', + 'MakerNoteKodak9' => 'Комментарии Kodak 9', + 'MakerNoteKodakUnknown' => 'Комментарии Kodak – ÐеизвеÑтно', + 'MakerNoteKyocera' => 'Комментарии Kyocera', + 'MakerNoteLeica' => 'Комментарии Leica', + 'MakerNoteLeica10' => 'Комментарии Leica 10', + 'MakerNoteLeica2' => 'Комментарии Leica 2', + 'MakerNoteLeica3' => 'Комментарии Leica 3', + 'MakerNoteLeica4' => 'Комментарии Leica 4', + 'MakerNoteLeica5' => 'Комментарии Leica 5', + 'MakerNoteLeica6' => 'Комментарии Leica 6', + 'MakerNoteLeica7' => 'Комментарии Leica 7', + 'MakerNoteLeica8' => 'Комментарии Leica 8', + 'MakerNoteLeica9' => 'Комментарии Leica 9', + 'MakerNoteMinolta' => 'Комментарии Minolta', + 'MakerNoteMinolta2' => 'Комментарии Minolta 2', + 'MakerNoteMinolta3' => 'Комментарии Minolta 3', + 'MakerNoteMotorola' => 'Комментарии Motorola', + 'MakerNoteNikon' => 'Комментарии Nikon', + 'MakerNoteNikon2' => 'Комментарии Nikon 2', + 'MakerNoteNikon3' => 'Комментарии Nikon 3', + 'MakerNoteNintendo' => 'Комментарии Nintendo', + 'MakerNoteOffset' => 'Смещение заметки производителÑ', + 'MakerNoteOlympus' => 'Комментарии Olympus', + 'MakerNoteOlympus2' => 'Комментарии Olympus 2', + 'MakerNotePanasonic' => 'Комментарии Panasonic', + 'MakerNotePanasonic2' => 'Комментарии Panasonic 2', + 'MakerNotePanasonic3' => 'Комментарии Panasonic 3', + 'MakerNotePentax' => 'Комментарии Pentax', + 'MakerNotePentax2' => 'Комментарии Pentax 2', + 'MakerNotePentax3' => 'Комментарии Pentax 3', + 'MakerNotePentax4' => 'Комментарии Pentax 4', + 'MakerNotePentax5' => 'Комментарии Pentax 5', + 'MakerNotePentax6' => 'Комментарии Pentax 6', + 'MakerNotePhaseOne' => 'Комментарии Phase One', + 'MakerNoteReconyx' => 'Комментарии Reconyx', + 'MakerNoteReconyx2' => 'Комментарии Reconyx 2', + 'MakerNoteReconyx3' => 'Комментарии Reconyx 3', + 'MakerNoteRicoh' => 'Комментарии Ricoh', + 'MakerNoteRicoh2' => 'Комментарии Ricoh 2', + 'MakerNoteRicohPentax' => 'Комментарии Ricoh Pentax', + 'MakerNoteRicohText' => 'Комментарии Ricoh – ТекÑÑ‚', + 'MakerNoteSafety' => { + Description => 'ÐŸÑ€Ð¸Ð¼ÐµÑ‡Ð°Ð½Ð¸Ñ Ð±ÐµÐ·Ð¾Ð¿Ð°ÑноÑти', + PrintConv => { + 'Safe' => 'БезопаÑно', + 'Unsafe' => 'ÐебезопаÑно', + }, + }, + 'MakerNoteSamsung1a' => 'Комментарии Samsung 1a', + 'MakerNoteSamsung1b' => 'Комментарии Samsung 1b', + 'MakerNoteSamsung2' => 'Комментарии Samsung 2', + 'MakerNoteSanyo' => 'Комментарии Sanyo', + 'MakerNoteSanyoC4' => 'Комментарии Sanyo C4', + 'MakerNoteSanyoPatch' => 'Комментарии Sanyo Patch', + 'MakerNoteSigma' => 'Комментарии Sigma', + 'MakerNoteSigma3' => 'Комментарии Sigma 3', + 'MakerNoteSony' => 'Комментарии Sony', + 'MakerNoteSony2' => 'Комментарии Sony 2', + 'MakerNoteSony3' => 'Комментарии Sony 3', + 'MakerNoteSony4' => 'Комментарии Sony 4', + 'MakerNoteSony5' => 'Комментарии Sony 5', + 'MakerNoteSonyEricsson' => 'Комментарии Sony Ericsson', + 'MakerNoteSonySRF' => 'Комментарии Sony SRF', + 'MakerNoteUnknown' => 'Комментарии неизвеÑтного производителÑ', + 'MakerNoteUnknownBinary' => 'Комментарии неизвеÑтного Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»Ñ â€“ Бинарный', + 'MakerNoteUnknownText' => 'Комментарии неизвеÑтного Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»Ñ â€“ ТекÑтовый', + 'MakerNoteVersion' => 'Заметка Ð¿Ñ€Ð¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ‚ÐµÐ»Ñ â€“ ВерÑиÑ', + 'MakerNotes' => 'Данные производителей', + 'Manager' => 'Руководитель', + 'ManualFocusDistance' => 'РаÑÑтоÑние ручной фокуÑировки', + 'Manufacturer' => 'Разработчик', + 'MappingScheme' => 'Схема подÑтановки отÑутÑтвующего шрифта', + 'MarkerID' => 'ID маркера', + 'MaskedAreas' => 'МаÑкированные облаÑти', + 'MasterDocumentID' => 'ОÑновной ID документа', + 'MaterialSample' => 'Материал образца', + 'MaterialSampleID' => 'ID материала образца', + 'MatrixWorldToCamera' => 'Матрица мира на камеру', + 'MatrixWorldToScreen' => 'Матрица мира на Ñкран', + 'MattColor' => 'Matt цвет', + 'Matte' => 'Matte (МаÑка?)', + 'Matteing' => 'Матирование', + 'MaxAperture' => 'МакÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð´Ð¸Ð°Ñ„Ñ€Ð°Ð³Ð¼Ð° объектива', + 'MaxApertureValue' => 'МакÑимальное значение диафрагмы', + 'MaxBand' => 'МакÑимальный диапазон', + 'MaxBitrate' => 'МакÑимальный битрейт', + 'MaxPacketSize' => 'Размер макÑимального пакета', + 'MaxSampleValue' => 'МакÑимальное значение компонента', + 'MaxSubfileSize' => 'МакÑимальный размер подфайла', + 'MaxVal' => 'МакÑимальное значение пикÑелÑ', + 'MaxWidth' => 'МакÑÐ¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ ÑˆÐ¸Ñ€Ð¸Ð½Ð° глифа', + 'MaximumBitrate' => 'МакÑимальный битрейт', + 'MaximumDensityRange' => 'МакÑимальный диапазон плотноÑти', + 'MaximumObjectSize' => 'МакÑимальный размер объекта', + 'MeasureType' => { + Description => 'Тип Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ð³Ð»ÑƒÐ±Ð¸Ð½Ñ‹', + PrintConv => { + 'OpticalAxis' => 'ОптичеÑÐºÐ°Ñ Ð¾ÑÑŒ', + 'OpticalRay' => 'ОптичеÑкий луч', + }, + }, + 'MeasurementAccuracy' => 'ÐŸÐ¾Ñ‚ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð°Ñ Ð¿Ð¾Ð³Ñ€ÐµÑˆÐ½Ð¾ÑÑ‚ÑŒ измерениÑ', + 'MeasurementDeterminedBy' => 'Люди определившие значение измерениÑ', + 'MeasurementDeterminedDate' => 'Дата Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ', + 'MeasurementID' => 'ID измерениÑ', + 'MeasurementMethod' => 'Метод измерениÑ', + 'MeasurementOrFact' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾Ð± измерении', + 'MeasurementRemarks' => 'Заметки измерениÑ', + 'MeasurementScale' => 'Шкала измерений', + 'MeasurementType' => 'Тип измерениÑ', + 'MeasurementUnit' => 'Единицы измерениÑ', + 'MeasurementValue' => 'Значение измерениÑ', + 'MediaConstraints' => 'ÐžÐ³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð½Ð° медиареÑурÑÑ‹', + 'MediaData' => 'Медиа-данные', + 'MediaEventIdDate' => 'Дата ÑобытиÑ', + 'MediaIsDelay' => { + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'MediaIsFinale' => { + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'MediaIsLive' => { + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'MediaIsMovie' => { + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'MediaIsPremiere' => { + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'MediaIsRepeat' => { + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'MediaIsSAP' => { + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'MediaIsSport' => { + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'MediaIsStereo' => { + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'MediaIsSubtitled' => { + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'MediaIsTape' => { + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'MediaSummaryCode' => 'Сводный код медиареÑурÑов', + 'MeetingLocations' => 'МеÑто вÑтречи', + 'Megapixels' => 'МегапикÑелей', + 'MelodicPolyphony' => 'ПолифоничеÑÐºÐ°Ñ Ð¼ÐµÐ»Ð¾Ð´Ð¸Ñ', + 'Message' => 'Сообщение', + 'MetadataCreator' => 'Метаданные – Создатель', + 'MetadataDate' => 'Метаданные – Дата', + 'MeteringMode' => { + Description => 'ЭкÑпозамер', + PrintConv => { + 'Average' => 'УÑреднённый', + 'Center-weighted average' => 'Центрально-взвешенный', + 'Multi-segment' => 'Оценочный/Многозонный', + 'Multi-spot' => 'Многоточечный', + 'Other' => 'Другой', + 'Partial' => 'ЧаÑтичный', + 'Spot' => 'Точечный', + 'Unknown' => 'ÐеизвеÑтный', + }, + }, + 'Method' => 'Метод', + 'Micro1Version' => 'Micro 1 – ВерÑиÑ', + 'Micro2Version' => 'Micro 2 – ВерÑиÑ', + 'Mime' => 'MIME-тип', + 'MinApertureValue' => 'Минимальное чиÑло диафрагмы объектива', + 'MinSampleValue' => 'Минимальное значение компонента', + 'MinimumBitrate' => 'Минимальный битрейт', + 'MinimumVersion' => 'ÐœÐ¸Ð½Ð¸Ð¼Ð°Ð»ÑŒÐ½Ð°Ñ Ð²ÐµÑ€ÑиÑ', + 'MinorModelAgeDisclosure' => { + Description => 'ВозраÑÑ‚ Ñамой молодой модели на Ñнимке', + PrintConv => { + 'Age 14 or Under' => '14 лет и меньше', + 'Age 15' => '15 лет', + 'Age 16' => '16 лет', + 'Age 17' => '17 лет', + 'Age 18' => '18 лет', + 'Age 19' => '19 лет', + 'Age 20' => '20 лет', + 'Age 21' => '21 год', + 'Age 22' => '22 года', + 'Age 23' => '23 года', + 'Age 24' => '24 года', + 'Age 25 or Over' => '25 лет и выше', + 'Age Unknown' => 'ВозраÑÑ‚ неизвеÑтен', + }, + }, + 'MinorVersion' => 'ÐœÐ¸Ð½Ð¾Ñ€Ð½Ð°Ñ Ð²ÐµÑ€ÑиÑ', + 'MobiType' => { + Description => 'Тип Mobi', + PrintConv => { + 'Audio' => 'Ðудио', + 'KF8: generated by kindlegen2' => 'KF8: Ñгенерированный kindlegen 2', + 'Mobipocket Book' => 'Книга Mobipocket', + 'News' => 'ÐовоÑти', + 'News_Feed' => 'ÐовоÑÑ‚Ð½Ð°Ñ Ð»ÐµÐ½Ñ‚Ð°', + 'News_Magazine' => 'Журнал новоÑтей', + 'PalmDoc Book' => 'Книга PalmDoc', + 'mobipocket? generated by kindlegen1.2' => 'Mobipocket? Сгенерированный kindlegen 1.2', + }, + }, + 'MobiVersion' => 'ВерÑÐ¸Ñ Mobi', + 'ModDate' => 'Дата редактированиÑ', + 'ModeExtension' => { + Description => 'РаÑширение режима канала', + PrintConv => { + 'Bands 12-31' => 'ПолоÑÑ‹ 12-32', + 'Bands 16-31' => 'ПолоÑÑ‹ 16-31', + 'Bands 4-31' => 'ПолоÑÑ‹ 4-31', + 'Bands 8-31' => 'ПолоÑÑ‹ 8-31', + }, + }, + 'ModeNumber' => 'Режим Ñтандарта факÑ-профилÑ', + 'Model' => 'Модель камеры', + 'Model2' => 'Модель 2', + 'ModelReleaseID' => 'ID релиза модели', + 'ModelReleaseStatus' => { + Description => 'Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ñ€ÐµÐ»Ð¸Ð·Ð° модели', + PrintConv => { + 'Limited or Incomplete Model Releases' => 'Ограниченные или неполные верÑии моделей', + 'None' => 'Ðе обозначено', + 'Not Applicable' => 'Ðе дейÑтвующий', + 'Unlimited Model Releases' => 'Ðеограниченное количеÑтво релизов модели', + }, + }, + 'ModelTiePoint' => 'ПроÑтранÑÑ‚Ð²ÐµÐ½Ð½Ð°Ñ Ð¿Ñ€Ð¸Ð²Ñзка', + 'ModelTransform' => 'Модель преобразованиÑ', + 'ModificationNumber' => 'Ðомер модификации', + 'ModificationPermissions' => { + Description => 'Ð Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð° Редактирование', + PrintConv => { + 'Do not restrict applications to reader permissions' => 'Ðе ограничивать вÑем приложениÑм права на чтение', + 'Fill forms, Create page templates, Sign' => 'РазрешаетÑÑ: Заполнение форм, Создание шаблонов Ñтраниц, Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ', + 'Fill forms, Create page templates, Sign, Create/Delete/Edit annotations' => 'РазрешаетÑÑ: Заполнение форм, Создание шаблонов Ñтраниц, Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ, Создание/Удаление/Редактирование аннотаций', + 'No changes permitted' => 'Редактирование запрещено', + 'Restrict all applications to reader permissions' => 'Ограничивать вÑем приложениÑм права на чтение', + }, + }, + 'ModifyDate' => 'Дата редактированиÑ', + 'MoireFilter' => 'Фильтр муара', + 'Montage' => 'Монтаж', + 'Month' => 'МеÑÑц', + 'MoonPhase' => { + Description => 'Фаза луны', + PrintConv => { + 'First Quarter' => 'ÐŸÐµÑ€Ð²Ð°Ñ Ñ‡ÐµÑ‚Ð²ÐµÑ€Ñ‚ÑŒ', + 'Full' => 'Полнолуние', + 'Last Quarter' => 'ПоÑледнÑÑ Ñ‡ÐµÑ‚Ð²ÐµÑ€Ñ‚ÑŒ', + 'New' => 'Ðоволуние', + 'New Crescent' => 'ÐœÐ¾Ð»Ð¾Ð´Ð°Ñ Ð»ÑƒÐ½Ð°', + 'Old Crescent' => 'Ð¡Ñ‚Ð°Ñ€Ð°Ñ Ð»ÑƒÐ½Ð°', + 'Waning Gibbous' => 'Ð£Ð±Ñ‹Ð²Ð°ÑŽÑ‰Ð°Ñ Ð»ÑƒÐ½Ð°', + 'Waxing Gibbous' => 'РаÑÑ‚ÑƒÑ‰Ð°Ñ Ð»ÑƒÐ½Ð°', + }, + }, + 'MotionSensitivity' => 'Обнаружение движениÑ', + 'MultiFrameNoiseReduction' => { + Description => 'Многокадровое шумоподавление', + PrintConv => { + 'Off' => 'Ðе включено', + 'On' => 'Включено', + }, + }, + 'MultiProfiles' => { + Description => 'Мультипрофили', + PrintConv => { + 'JBIG2 Profile M' => 'JBIG2 профиль M', + 'N Layer Profile M' => 'N Ñлой Профиль M', + 'Profile C' => 'Профиль C', + 'Profile F' => 'Профиль F', + 'Profile J' => 'Профиль J', + 'Profile L' => 'Профиль L', + 'Profile M' => 'Профиль M', + 'Profile S' => 'Профиль S', + 'Profile T' => 'Профиль T', + 'Resolution/Image Width' => 'Разрешение/Ширина изображениÑ', + 'Shared Data' => 'Общие данные', + }, + }, + 'MultimediaType' => 'Тип мультимедиа', + 'Multishot' => { + Description => 'МультиÑъёмка', + PrintConv => { + 'Off' => 'Ðе включена', + 'Pixel Shift' => 'Сдвиг пикÑелей', + }, + }, + 'Name' => 'Ðазвание файла', + 'NameTableVersion' => 'Таблица имён – ВерÑиÑ', + 'NameUTF-8' => 'Ðазвание в кодировке UTF-8', + 'Narrator' => 'Ð˜Ð¼Ñ Ð´Ð¸ÐºÑ‚Ð¾Ñ€Ð°', + 'Near' => 'Ближайшее значение карты глубины', + 'NetName' => 'Сетевое имÑ', + 'NetProviderType' => 'Тип Ñетевого провайдера', + 'NewGUID' => 'Ðовый GUID', + 'NewRawImageDigest' => 'Хеш-Ñумма RAW-Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð² новом формате', + 'NewsPhotoVersion' => 'ВерÑÐ¸Ñ News Photo', + 'Nickname' => 'Прозвище', + 'NoMSSmartTags' => 'Смарт-теги MS отÑутÑтвуют', + 'Noise' => 'Уровень шума', + 'NoiseProfile' => 'Профиль – Уровень шума', + 'NoiseReduction' => 'Шумоподавление', + 'NoiseReductionApplied' => 'Применённое шумоподавление', + 'NoiseReductionMode' => { + Description => 'Режим шумоподавлениÑ', + PrintConv => { + 'Off' => 'Ðе включён', + 'On' => 'Включён', + }, + }, + 'NoiseReductionParams' => 'Параметры шумоподавлениÑ', + 'NoiseReductionValue' => 'Значение шумоподавлениÑ', + 'NominalBitrate' => 'Ðоминальный битрейт', + 'NominalVideoBitrate' => { + Description => 'Ðоминальный битрейт видео', + PrintConv => { + 'Unspecified' => 'Ðеопределённый', + }, + }, + 'Note' => 'Заметка', + 'Notes' => 'Комментарии', + 'Notice' => 'Заметка', + 'Now' => 'Текущие Дата и ВремÑ', + 'NumChannels' => 'КоличеÑтво каналов', + 'NumColors' => 'КоличеÑтво цветов', + 'NumFonts' => 'КоличеÑтво шрифтов в коллекции', + 'NumImportantColors' => 'КоличеÑтво важных цветов', + 'NumIndexEntries' => 'КоличеÑтво индекÑов', + 'NumPackets' => 'КоличеÑтво пакетов', + 'NumProperties' => 'КоличеÑтво ÑвойÑтв', + 'NumRules' => 'КоличеÑтво правил', + 'NumSampleFrames' => 'КоличеÑтво кадров', + 'NumSlices' => 'КоличеÑтво фрагментов', + 'NumStreams' => 'КоличеÑтво потоков', + 'Number' => 'Ðомер', + 'NumberList' => 'Ðумерованный ÑпиÑок', + 'NumberOfComponents' => 'КоличеÑтво компонентов', + 'NumberOfImages' => 'КоличеÑтво изображений', + 'NumberofInks' => 'КоличеÑтво чернил', + 'OPIProxy' => { + Description => 'ПодÑтановка изображениÑ', + PrintConv => { + 'Higher resolution image does not exist' => 'Изображение большего Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð¾Ñ‚ÑутÑтвует', + 'Higher resolution image exists' => 'ПриÑутÑтвует изображение Ñ Ð±Ð¾Ð»ÑŒÑˆÐ¸Ð¼ разрешением', + }, + }, + 'Object' => 'Объект', + 'ObjectAttributeReference' => 'СÑылка на атрибут объекта', + 'ObjectCycle' => { + Description => 'Суточный цикл', + PrintConv => { + 'Both Morning and Evening' => 'Утро и вечер', + 'Evening' => 'Вечер', + 'Morning' => 'Утро', + }, + }, + 'ObjectName' => 'Ðазвание объекта', + 'ObjectPreviewData' => 'ПредпроÑмотр объекта – Данные', + 'ObjectPreviewFileFormat' => { + Description => 'ПредпроÑмотр объекта – Формат файла', + PrintConv => { + 'AppleSingle (Apple Computer Inc)' => 'AppleSingle (Apple)', + 'Audio Interchange File Format AIFF (Apple Computer Inc)' => 'Ðудиофайл формата AIFF (Apple)', + 'Bit Mapped Graphics File [.BMP] (Microsoft)' => 'Битовый графичеÑкий файл [.BMP] (Microsoft)', + 'Compressed Binary File [.ZIP] (PKWare Inc)' => 'Сжатый двоичный файл [.ZIP] (ÐšÐ¾Ð¼Ð¿Ð°Ð½Ð¸Ñ PKWare)', + 'Digital Audio File [.WAV] (Microsoft & Creative Labs)' => 'Ðудиофайл формата [.WAV] (Microsoft и Creative Labs)', + 'Hypertext Markup Language [.HTML] (The Internet Society)' => 'Язык гипертекÑтовой разметки [.HTML] (The Internet Society)', + 'IPTC Unstructured Character Oriented File Format (UCOFF)' => 'ÐеÑтруктурированный Ñимвольно-ориентированный формат файла IPTC (UCOFF)', + 'IPTC7901 Recommended Message Format' => 'IPTC7901 Рекомендуемый формат ÑообщениÑ', + 'Illustrator (Adobe Graphics data)' => 'Illustrator (ГрафичеÑкие данные Adobe)', + 'JPEG File Interchange (JFIF)' => 'Формат обмена файлами Ñтандарта JPEG (JFIF)', + 'MPEG 2 Audio Layer 2 (Musicom), ISO/IEC' => 'Ðудио второго ÑƒÑ€Ð¾Ð²Ð½Ñ MPEG 2 (Musicom), ISO/IEC', + 'MPEG 2 Audio Layer 3, ISO/IEC' => 'Ðудио третьего ÑƒÑ€Ð¾Ð²Ð½Ñ MPEG 2 , ISO/IEC', + 'News Industry Text Format (NITF)' => 'ТекÑтовый формат новоÑтной индуÑтрии (NITF)', + 'No ObjectData' => 'Данные объекта отÑутÑтвуют', + 'PC DOS/Windows Executable Files [.COM][.EXE]' => 'ИÑполнÑемый файл PC DOS/Windows [.COM][.EXE]', + 'RIFF Wave (Microsoft Corporation)' => 'RIFF Wave (Microsoft)', + 'Ritzaus Bureau NITF version (RBNITF DTD)' => 'Ritzaus Bureau вариант NITF (RBNITF DTD)', + 'Tagged Image File Format (Adobe/Aldus Image data)' => 'Формат файла Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñ Ñ‚ÐµÐ³Ð°Ð¼Ð¸ (Adobe/Aldus данные изображениÑ)', + 'Tape Archive [.TAR]' => 'Формат файла архива [.TAR]', + 'Tidningarnas Telegrambyra NITF version (TTNITF DTD)' => 'Tidningarnas Telegrambyra вариант NITF (TTNITF DTD)', + 'United Press International ANPA 1312 variant' => 'United Press International – Вариант ANPA 1312', + 'United Press International Down-Load Message' => 'United Press International – Down-Load Message', + }, + }, + 'ObjectPreviewFileVersion' => 'ПредпроÑмотр объекта – ВерÑиÑ', + 'ObjectSizeAnnounced' => 'ЗаÑвленный размер объекта', + 'ObjectType' => 'Тип объекта', + 'ObjectTypeReference' => 'СÑылка на тип объекта', + 'ObservationDate' => 'Дата наблюдениÑ', + 'ObservationDateEnd' => 'Дата Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ð½Ð°Ð±Ð»ÑŽÐ´ÐµÐ½Ð¸Ñ', + 'ObservationTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð½Ð°Ð±Ð»ÑŽÐ´ÐµÐ½Ð¸Ñ', + 'ObservationTimeEnd' => 'Ð’Ñ€ÐµÐ¼Ñ Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ð½Ð°Ð±Ð»ÑŽÐ´ÐµÐ½Ð¸Ñ', + 'Observer' => 'Ðаблюдатель', + 'ObsoletePhotoshopTag1' => 'Photoshop – УÑтаревший тег 1', + 'ObsoletePhotoshopTag2' => 'Photoshop – УÑтаревший тег 2', + 'ObsoletePhotoshopTag3' => 'Photoshop – УÑтаревший тег 3', + 'Occurrence' => 'Ðаходка', + 'OccurrenceAssociatedMedia' => 'МедиареÑурÑÑ‹ ÑвÑзанные Ñ Ð½Ð°Ñ…Ð¾Ð´ÐºÐ¾Ð¹', + 'OccurrenceAssociatedOccurrences' => 'СвÑзанные находки', + 'OccurrenceAssociatedReferences' => 'СÑылки ÑвÑзанные Ñ Ð½Ð°Ñ…Ð¾Ð´ÐºÐ¾Ð¹', + 'OccurrenceAssociatedSequences' => 'ГенетичеÑкие поÑледовательноÑти ÑвÑзанные Ñ Ð½Ð°Ñ…Ð¾Ð´ÐºÐ¾Ð¹', + 'OccurrenceAssociatedTaxa' => 'ТакÑоны ÑвÑзанные Ñ Ð½Ð°Ñ…Ð¾Ð´ÐºÐ¾Ð¹', + 'OccurrenceBehavior' => 'ÐŸÐ¾Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾Ñоби во Ð²Ñ€ÐµÐ¼Ñ Ð½Ð°Ñ…Ð¾Ð´ÐºÐ¸', + 'OccurrenceCatalogNumber' => 'Ðомер набора данных', + 'OccurrenceDetails' => 'ПодробноÑти о находке', + 'OccurrenceDisposition' => 'СоÑтоÑние образца по отношению к коллекции', + 'OccurrenceEstablishmentMeans' => 'СпоÑоб оÑÐ½Ð¾Ð²Ð°Ð½Ð¸Ñ Ð½Ð° меÑтноÑти', + 'OccurrenceID' => 'ID находки', + 'OccurrenceIndividualCount' => 'КоличеÑтво найденных оÑобей', + 'OccurrenceIndividualID' => 'ID найденных оÑобей', + 'OccurrenceLifeStage' => 'Жизненные циклы найденных оÑобей', + 'OccurrenceOrganismQuantity' => 'ЧиÑло учётных единиц или обилие вида', + 'OccurrenceOrganismQuantityType' => 'Тип ÑиÑтемы количеÑтвенного определениÑ', + 'OccurrenceOtherCatalogNumbers' => 'Другие номера каталога Ð´Ð»Ñ Ð½Ð°Ñ…Ð¾Ð´ÐºÐ¸', + 'OccurrencePreparations' => 'Методы Ð¿Ñ€ÐµÐ¿Ð°Ñ€Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸ конÑÐµÑ€Ð²Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð±Ñ€Ð°Ð·Ñ†Ð°', + 'OccurrencePreviousIdentifications' => 'Предыдущие Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð½Ð°Ñ…Ð¾Ð´ÐºÐ¸', + 'OccurrenceRecordNumber' => 'Ðомер приÑвоенный объекту в момент находки', + 'OccurrenceRecordedBy' => 'Люди ответÑтвенные за запиÑÑŒ о находке', + 'OccurrenceRemarks' => 'Комментарии к находке', + 'OccurrenceReproductiveCondition' => 'Репродуктивное ÑоÑтоÑние оÑобей во Ð²Ñ€ÐµÐ¼Ñ Ð½Ð°Ñ…Ð¾Ð´ÐºÐ¸', + 'OccurrenceSex' => 'Пол найденных оÑобей', + 'OccurrenceStatus' => 'ПриÑутÑтвие вида в данной меÑтноÑти', + 'OceApplicationSelector' => 'Задатчик Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Oce', + 'OceIDNumber' => 'ID-номер Oce', + 'OceImageLogic' => 'Логика Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Oce', + 'OceScanjobDesc' => 'ОпиÑание Ð·Ð°Ð´Ð°Ð½Ð¸Ñ ÑÐºÐ°Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Oce', + 'OffsetSchema' => 'Схема ÑмещениÑ', + 'OffsetTime' => 'Смещение времени', + 'OffsetTimeDigitized' => 'Ð¡Ð¼ÐµÑ‰ÐµÐ½Ð¸Ñ Ð²Ñ€ÐµÐ¼ÐµÐ½Ð¸ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð°', + 'OffsetTimeOriginal' => 'Смещение времени Ñъёмки', + 'OldSubfileType' => { + Description => 'Тип подфайла (Ñтарый)', + PrintConv => { + 'Full-resolution image' => 'Изображение Ñ Ð¿Ð¾Ð»Ð½Ñ‹Ð¼ разрешением', + 'Reduced-resolution image' => 'Изображение Ñ Ð¿Ð¾Ð½Ð¸Ð¶ÐµÐ½Ð½Ñ‹Ð¼ разрешением', + 'Single page of multi-page image' => 'Одна Ñтраница из многоÑтраничного изображениÑ', + }, + }, + 'OnionSkins' => 'Обрамление Ñцены', + 'Opacity' => 'ÐепрозрачноÑÑ‚ÑŒ', + 'OpcodeList1' => 'СпиÑок кодов операций обработки изображений 1', + 'OpcodeList2' => 'СпиÑок кодов операций обработки изображений 2', + 'OpcodeList3' => 'СпиÑок кодов операций обработки изображений 3', + 'OperatingSystem' => { + Description => 'ÐžÐ¿ÐµÑ€Ð°Ñ†Ð¸Ð¾Ð½Ð½Ð°Ñ ÑиÑтема', + PrintConv => { + 'FAT filesystem (MS-DOS, OS/2, NT/Win32)' => 'Ð¤Ð°Ð¹Ð»Ð¾Ð²Ð°Ñ ÑиÑтема FAT (MS-DOS, OS/2, NT/Win32)', + 'HPFS filesystem (OS/2, NT)' => 'Ð¤Ð°Ð¹Ð»Ð¾Ð²Ð°Ñ ÑиÑтема HPFS (OS/2, NT)', + 'NTFS filesystem (NT)' => 'Ð¤Ð°Ð¹Ð»Ð¾Ð²Ð°Ñ ÑиÑтема NTFS (NT)', + 'VMS (or OpenVMS)' => 'VMS (или OpenVMS)', + 'Z-System' => 'Z/OS', + 'unknown' => 'ÐеизвеÑтнаÑ', + }, + }, + 'OpticalZoomOn' => { + Description => 'ОптичеÑкий зум', + PrintConv => { + 'Off' => 'Ðе включён', + 'On' => 'Включен', + }, + }, + 'Opto-ElectricConvFactor' => 'Фактор оптико-ÑлектричеÑкого преобразованиÑ', + 'Organism' => 'Организм', + 'OrganismAssociatedOccurrences' => 'СвÑзанные находки Ñ Ñтим организмом', + 'OrganismAssociatedOrganisms' => 'Другие организмы ÑвÑзанные Ñ Ñтим организмом', + 'OrganismID' => 'ID организма', + 'OrganismName' => 'Ðазвание приÑвоенное организму', + 'OrganismPreviousIdentifications' => 'Предыдущие Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð¸Ñ Ð¾Ñ€Ð³Ð°Ð½Ð¸Ð·Ð¼Ð°', + 'OrganismRemarks' => 'Комментарии к ÑкземплÑру организма', + 'OrganismScope' => 'Вид ÑкземплÑра организма', + 'Organization' => 'ОрганизациÑ', + 'Organizer' => 'Организатор', + 'Orientation' => { + Description => 'ОриентациÑ', + PrintConv => { + 'Horizontal (normal)' => 'ГоризонтальнаÑ', + 'Mirror horizontal' => 'Отражение по горизонтали', + 'Mirror horizontal and rotate 270 CW' => 'Отражение по горизонтали и поворот на 270° по чаÑовой Ñтрелке', + 'Mirror horizontal and rotate 90 CW' => 'Отражение по горизонтали и поворот на 90° по чаÑовой Ñтрелке', + 'Mirror vertical' => 'Отражение по вертикали', + 'Rotate 180' => 'Поворот на 180°', + 'Rotate 270 CW' => 'Поворот на 270° по чаÑовой Ñтрелке', + 'Rotate 90 CW' => 'Поворот на 90° по чаÑовой Ñтрелке', + }, + }, + 'OriginPathInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾Ð± иÑходном обтравочном контуре', + 'OriginalBestQualitySize' => 'Размер более качеÑтвенного изображениÑ', + 'OriginalCreateDateTime' => 'ИÑходные дата и Ð²Ñ€ÐµÐ¼Ñ ÑозданиÑ', + 'OriginalDecisionData' => 'Ð¦Ð¸Ñ„Ñ€Ð¾Ð²Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ оригинальноÑти Ñнимка (ODD)', + 'OriginalDefaultCropSize' => 'ИÑходный размер кадрированного изображениÑ', + 'OriginalDefaultFinalSize' => 'Полный размер иÑходного изображениÑ', + 'OriginalFileName' => 'ИÑходное название файла', + 'OriginalFileSize' => 'Размер иÑходного файла', + 'OriginalFileType' => 'Тип иÑходного файла', + 'OriginalFrameRate' => 'ИÑÑ…Ð¾Ð´Ð½Ð°Ñ Ñ‡Ð°Ñтота кадров', + 'OriginalImageHeight' => 'ИÑÑ…Ð¾Ð´Ð½Ð°Ñ Ð²Ñ‹Ñотаи зображениÑ', + 'OriginalImageWidth' => 'ИÑÑ…Ð¾Ð´Ð½Ð°Ñ ÑˆÐ¸Ñ€Ð¸Ð½Ð° изображениÑ', + 'OriginalMedia' => { + Description => 'Оригинальный ноÑитель', + PrintConv => { + 'False' => 'Ðет', + 'True' => 'Да', + }, + }, + 'OriginalRawFileData' => 'Данные иÑходного RAW-файла', + 'OriginalRawFileDigest' => 'Хеш-Ñумма иÑходного RAW-файла', + 'OriginalRawFileName' => 'Ðазвание иÑходного RAW-файла', + 'OriginalReleaseTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð° оригинала', + 'OriginalTransmissionReference' => 'ИÑÑ…Ð¾Ð´Ð½Ð°Ñ ÑÑылка на передачу', + 'OriginatingProgram' => 'Создано в риложении', + 'Originator' => 'Контент Ñоздан в', + 'OtherConditions' => 'Другие уÑловиÑ', + 'OtherConstraints' => 'Другие ограничениÑ', + 'OtherDate1' => 'Другое – Дата 1', + 'OtherDate2' => 'Другое – Дата 2', + 'OtherDate3' => 'Другое – Дата 3', + 'OtherFirmware' => 'Ð”Ñ€ÑƒÐ³Ð°Ñ Ð¿Ñ€Ð¾ÑˆÐ¸Ð²ÐºÐ°', + 'OtherImage' => 'Другое изображение', + 'OtherImageInfo' => 'Другие ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾Ð± изображении', + 'OtherImageLength' => 'Строк в файле предпроÑмотра', + 'OtherImageStart' => 'Смещение другого изображениÑ', + 'OtherLicenseDocuments' => 'Другие документы лицензии', + 'OtherLicenseInfo' => 'Дополнительные ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ лицензии', + 'OtherLicenseRequirements' => 'Другие лицензионные требованиÑ', + 'OtherSerialNumber' => 'Другой Серийный номер', + 'Owner' => 'Владелец', + 'OwnerAppointmentID' => 'ID владельца ÑобытиÑ', + 'OwnerID' => 'ID владельца', + 'OwnerName' => 'Ð˜Ð¼Ñ Ð²Ð»Ð°Ð´ÐµÐ»ÑŒÑ†Ð° камеры', + 'PDFVersion' => 'ВерÑÐ¸Ñ PDF', + 'PFMVersion' => 'ВерÑÐ¸Ñ PFM', + 'PGFVersion' => 'ВерÑÐ¸Ñ PGF', + 'PLUSVersion' => 'ВерÑÐ¸Ñ PLUS', + 'PMVersion' => 'ВерÑÐ¸Ñ PhotoMechanic', + 'PNGWarning' => 'Предупреждение PNG', + 'PStringCaption' => 'P – Строка заголовка', + 'PXC Viewer Info' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾Ñ‚ PDF-XChange Viewer', + 'Packets' => 'Пакетов', + 'PackingMethod' => { + Description => 'Метод ÑжатиÑ', + PrintConv => { + 'Best Compression' => 'МакÑимальный', + 'Fast' => 'БыÑтрый', + 'Fastest' => 'СкороÑтной', + 'Good Compression' => 'Хороший', + 'Normal' => 'Обычный', + 'Stored' => 'Без ÑжатиÑ', + }, + }, + 'Padding' => 'Внутренние отÑтупы', + 'Page' => 'Размер и раÑположение холÑта', + 'PageCount' => 'КоличеÑтво Ñтраниц', + 'PageEnter' => 'Эффект при заходе на Ñтраницу', + 'PageExit' => 'Эффект при уходе Ñо Ñтраницы', + 'PageFront' => 'КоличеÑтво фронтальных Ñтраниц', + 'PageLayout' => 'Макет Ñтраницы', + 'PageMode' => 'Режим Ñтраницы', + 'PageName' => 'Ðазвание Ñтраницы', + 'PageNormal' => 'КоличеÑтво обычных Ñтраниц', + 'PageNumber' => 'Ðомер Ñтраницы', + 'PageSpecial' => 'КоличеÑтво Ñпециальных Ñтраниц', + 'Pages' => 'Страниц', + 'Palette' => 'Палитра', + 'PaletteHistogram' => 'ГиÑтограмма палитры', + 'PalmFileType' => 'Тип файла Palm', + 'PanOrientation' => { + Description => 'ÐžÑ€Ð¸ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ Ð¿Ð°Ð½Ð¾Ñ€Ð°Ð¼Ñ‹', + PrintConv => { + 'Bottom to top' => 'Снизу вверх', + 'Clockwise' => 'По чаÑовой Ñтрелке', + 'Counter clockwise' => 'Против чаÑовой Ñтрелки', + 'Left to right' => 'Слева направо', + 'Right to left' => 'Справа налево', + 'Start at bottom left' => 'Ðачало внизу Ñлева', + 'Start at bottom right' => 'Ðачало внизу Ñправа', + 'Start at top left' => 'Ðачало Ñверху Ñлева', + 'Start at top right' => 'Ðачало Ñверху Ñправа', + 'Top to bottom' => 'Сверху вниз', + 'Zigzag (column start)' => 'Зигзаг (начало колонки)', + 'Zigzag (row start)' => 'Зигзаг (начало Ñтроки)', + '[unused]' => 'ÐеиÑпользуетÑÑ', + }, + }, + 'PanOverlapH' => 'Горизонтальное перекрытие панорамы', + 'PanOverlapV' => 'Вертикальное перекрытие панорамы', + 'PanasonicRawVersion' => 'Panasonic – ВерÑÐ¸Ñ RAW', + 'PanasonicTitle' => 'Panasonic – Ðазвание', + 'PanasonicTitle2' => 'Panasonic – Ðазвание 2', + 'PanoramicStitchCameraMotion' => { + Description => 'Метод ÑÑˆÐ¸Ð²Ð°Ð½Ð¸Ñ Ð¿Ð°Ð½Ð¾Ñ€Ð°Ð¼Ñ‹', + PrintConv => { + '3D Rotation' => '3D-вращение', + 'Affine' => 'Ðффинное преобразование', + 'Homography' => 'ГомографиÑ', + 'Rigid Scale' => 'ЖёÑÑ‚ÐºÐ°Ñ ÑˆÐºÐ°Ð»Ð°', + }, + }, + 'PanoramicStitchMapType' => { + Description => 'Тип карты', + PrintConv => { + 'Horizontal Cylindrical' => 'Ð“Ð¾Ñ€Ð¸Ð·Ð¾Ð½Ñ‚Ð°Ð»ÑŒÐ½Ð°Ñ Ñ†Ð¸Ð»Ð¸Ð½Ð´Ñ€Ð¸Ñ‡ÐµÑкаÑ', + 'Horizontal Spherical' => 'Ð“Ð¾Ñ€Ð¸Ð·Ð¾Ð½Ñ‚Ð°Ð»ÑŒÐ½Ð°Ñ ÑферичеÑкаÑ', + 'Perspective' => 'ПерÑпектива', + 'Vertical Cylindrical' => 'Ð’ÐµÑ€Ñ‚Ð¸ÐºÐ°Ð»ÑŒÐ½Ð°Ñ Ñ†Ð¸Ð»Ð¸Ð½Ð´Ñ€Ð¸Ñ‡ÐµÑкаÑ', + 'Vertical Spherical' => 'Ð’ÐµÑ€Ñ‚Ð¸ÐºÐ°Ð»ÑŒÐ½Ð°Ñ ÑферичеÑкаÑ', + }, + }, + 'PanoramicStitchPhi0' => 'Угол Phi 0', + 'PanoramicStitchPhi1' => 'Угол Phi 1', + 'PanoramicStitchTheta0' => 'Угол Theta 0', + 'PanoramicStitchTheta1' => 'Угол Theta 1', + 'Paragraphs' => 'Ðбзацев', + 'ParentMEID' => 'РодительÑкий MEID', + 'ParentMediaEventID' => 'ID ÑобытиÑ', + 'PathSelectionState' => 'СоÑтоÑние выбранного обтравочного контура', + 'PathTableLocation' => 'РаÑположение таблицы путей', + 'PathTableSize' => 'Размер таблицы путей', + 'PatientBirthDate' => 'Дата Ñ€Ð¾Ð¶Ð´ÐµÐ½Ð¸Ñ Ð¿Ð°Ñ†Ð¸ÐµÐ½Ñ‚Ð°', + 'PatientID' => 'ID пациента', + 'PatientName' => 'Ð˜Ð¼Ñ Ð¿Ð°Ñ†Ð¸ÐµÐ½Ñ‚Ð°', + 'PatientSex' => 'Пол пациента', + 'PeakSpectralSensitivity' => 'ÐŸÐ¸ÐºÐ¾Ð²Ð°Ñ ÑÐ¿ÐµÐºÑ‚Ñ€Ð°Ð»ÑŒÐ½Ð°Ñ Ñ‡ÑƒÐ²ÑтвительноÑÑ‚ÑŒ', + 'People' => 'Люди', + 'PercentComplete' => 'Процент завершениÑ', + 'PercussivePolyphony' => 'ПолифоничеÑÐºÐ°Ñ Ð¿ÐµÑ€ÐºÑƒÑÑиÑ', + 'Performer' => 'ИÑполнитель', + 'PeripheralIllumCentralRadius' => 'КомпенÑÐ°Ñ†Ð¸Ñ Ð¿Ð°Ñ€Ð°Ð·Ð¸Ñ‚Ð½Ð¾Ð³Ð¾ Ñигнала – Центральный радиуÑ', + 'PeripheralIllumCentralValue' => 'КомпенÑÐ°Ñ†Ð¸Ñ Ð¿Ð°Ñ€Ð°Ð·Ð¸Ñ‚Ð½Ð¾Ð³Ð¾ Ñигнала – Ð¦ÐµÐ½Ñ‚Ñ€Ð°Ð»ÑŒÐ½Ð°Ñ Ð½Ð°ÑыщенноÑÑ‚ÑŒ', + 'PeripheralIllumPeriphValue' => 'КомпенÑÐ°Ñ†Ð¸Ñ Ð¿Ð°Ñ€Ð°Ð·Ð¸Ñ‚Ð½Ð¾Ð³Ð¾ Ñигнала – ÐŸÐµÑ€Ð¸Ñ„ÐµÑ€Ð¸Ð¹Ð½Ð°Ñ Ð½Ð°ÑыщенноÑÑ‚ÑŒ', + 'Personality' => 'ЛичноÑти', + 'Photo' => 'ФотографиÑ', + 'PhotoResolution' => 'Разрешение Ñнимка', + 'PhotometricInterpretation' => { + Description => 'Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ð¼Ð¾Ð´ÐµÐ»ÑŒ', + PrintConv => { + 'BlackIsZero' => 'Чёрный равен нулю', + 'Color Filter Array' => 'МаÑÑив цветных фильтров (CFA)', + 'RGB Palette' => 'Палитра RGB', + 'Transparency Mask' => 'МаÑка прозрачноÑти', + 'WhiteIsZero' => 'Белый равен нулю', + }, + }, + 'Photoshop2ColorTable' => 'Photoshop 2 – Таблица цветов', + 'Photoshop2Info' => 'Photoshop 2 – СведениÑ', + 'PhotoshopBGRThumbnail' => 'Photoshop – BGR миниатюра', + 'PhotoshopFormat' => { + Description => 'Photoshop – Формат', + PrintConv => { + 'Optimized' => 'Оптимизированный', + 'Progressive' => 'ПрогреÑÑивный', + 'Standard' => 'Стандартный', + }, + }, + 'PhotoshopQuality' => 'Photoshop – КачеÑтво', + 'PhotoshopThumbnail' => 'Photoshop – Миниатюра', + 'PhysicalStreamNumberMap' => 'ФизичеÑкий поток – Number Map', + 'PhysicalStreamNumbers' => 'Ðомера физичеÑких потоков', + 'PhysicalStreams' => 'ФизичеÑких потоков', + 'PicsLabel' => 'Метка взроÑлоÑти контента', + 'PictInfo' => 'Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ð± изображении', + 'Picture' => 'Картина', + 'PictureBitsPerPixel' => 'КоличеÑтво бит на пикÑель картинки', + 'PictureDescription' => 'ОпиÑание изображениÑ', + 'PictureHeight' => 'Ð’Ñ‹Ñота картинки', + 'PictureIndexedColors' => 'ИндекÑированные цвета изображениÑ', + 'PictureLength' => 'Строк в картинке', + 'PictureMIMEType' => 'MIME тип изображениÑ', + 'PictureType' => { + Description => 'Тип изображениÑ', + PrintConv => { + '32x32 PNG Icon' => '32x32 иконка PNG', + 'Artist' => 'ИÑполнитель', + 'Back Cover' => 'ЗаднÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÐ°', + 'Band' => 'Группа', + 'Band Logo' => 'Логотип группы/иÑполнителÑ', + 'Bright(ly) Colored Fish' => 'Ярко Ð¾ÐºÑ€Ð°ÑˆÐµÐ½Ð½Ð°Ñ Ñ€Ñ‹Ð±Ð°', + 'Capture from Movie or Video' => 'Захват из фильма или видео', + 'Composer' => 'Композитор', + 'Conductor' => 'Дирижер', + 'Front Cover' => 'ПереднÑÑ Ð¾Ð±Ð»Ð¾Ð¶ÐºÐ°', + 'Illustration' => 'ИллюÑтрациÑ', + 'Lead Artist' => 'Ведущий ÐртиÑÑ‚/ИÑполнитель/СолиÑÑ‚', + 'Leaflet' => 'ЛиÑтовка', + 'Lyricist' => 'Ðвтор текÑта', + 'Media' => 'ÐоÑитель', + 'Other' => 'Другое', + 'Other Icon' => 'Ð”Ñ€ÑƒÐ³Ð°Ñ Ð¸ÐºÐ¾Ð½ÐºÐ°', + 'Performance' => 'ПредÑтавление', + 'Publisher Logo' => 'Логотип издателÑ/Ñтудии', + 'Recording Session' => 'ЗапиÑÑŒ ÑеÑÑии', + 'Recording Studio or Location' => 'Ð¡Ñ‚ÑƒÐ´Ð¸Ñ Ð·Ð²ÑƒÐºÐ¾Ð·Ð°Ð¿Ð¸Ñи или меÑтоположение', + }, + }, + 'PictureWidth' => 'Ширина картинки', + 'PieceLength' => 'Размер блока в байтах', + 'Pieces' => 'Блоков', + 'PipelineVersion' => 'ВерÑÐ¸Ñ Pipeline', + 'Pitch' => 'Тангаж (Ðаклон)', + 'PitchAndFamily' => 'Шаг и ÑемейÑтво шрифта', + 'PitchAngle' => 'Угол наклона (Тангаж)', + 'PixHeight' => 'Ð’Ñ‹Ñота в пикÑелÑÑ…', + 'PixWidth' => 'Ширина в пикÑелÑÑ…', + 'PixelAspectRatio' => 'Соотношение Ñторон пикÑелей', + 'PixelCalibration' => 'Калибровка по пикÑелÑм', + 'PixelFormat' => { + Description => 'Формат пикÑелÑ', + PrintConv => { + '112-bit 6 Channels Alpha' => '112-битный, 6 каналов, альфа-канал', + '112-bit 7 Channels' => '112-битный, 7 каналов', + '128-bit 7 Channels Alpha' => '128-битный, 7 каналов, альфа-канал', + '128-bit 8 Channels' => '128-битный, 8 каналов', + '128-bit PRGBA Float' => '128-битный, PRGBA Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой', + '128-bit RGB Float' => '128-битный, RGB Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой', + '128-bit RGBA Fixed Point' => '128-битный, RGBA Ñ Ñ„Ð¸ÐºÑированной точкой', + '128-bit RGBA Float' => '128-битный, RGBA Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой', + '144-bit 8 Channels Alpha' => '144-битный, 8 каналов, альфа-канал', + '16-bit BGR555' => '16-битный, BGR555', + '16-bit BGR565' => '16-битный, BGR565', + '16-bit Gray' => '16-битный, Серый', + '16-bit Gray Half' => '16-битный, половина Ñерого', + '24-bit 3 Channels' => '24-битный, 3 канала', + '24-bit BGR' => '24-битный, BGR', + '24-bit RGB' => '24-битный, RGB', + '32-bit 3 Channels Alpha' => '32-битный, 3 канала, альфа-канал', + '32-bit 4 Channels' => '32-битный, 4 канала', + '32-bit BGR' => '32-битный, BGR', + '32-bit BGR101010' => '32-битный, BGR101010', + '32-bit BGRA' => '32-битный, BGRA', + '32-bit CMYK' => '32-битный, CMYK', + '32-bit Gray Fixed Point' => '32-битный, Ñерый Ñ Ñ„Ð¸ÐºÑированной точкой', + '32-bit Gray Float' => '32-битный, Серый Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой', + '32-bit PBGRA' => '32-битный, PBGRA', + '32-bit RGBE' => '32-битный, RGBE', + '40-bit 4 Channels Alpha' => '40-битный, 4 канала, альфа-канал', + '40-bit 5 Channels' => '40-битный, 5 каналов', + '40-bit CMYK Alpha' => '40-битный, CMYK, альфа-канал', + '48-bit 3 Channels' => '48-битный, 3 канала', + '48-bit 5 Channels Alpha' => '48-битный, 5 каналов, альфа-канал', + '48-bit 6 Channels' => '48-битный, 6 каналов', + '48-bit RGB' => '48-битный, RGB', + '48-bit RGB Fixed Point' => '48-битный, RGB Ñ Ñ„Ð¸ÐºÑированной точкой', + '48-bit RGB Half' => '48-битный, RGB Half', + '4:2:0 (chroma at 0, 0.5)' => '4:2:0 (цветноÑÑ‚ÑŒ в 0, 0.5)', + '4:2:0 (chroma at 0.5, 0.5)' => '4:2:0 (цветноÑÑ‚ÑŒ в 0.5, 0.5)', + '4:2:2 (chroma at 0, 0)' => '4:2:2 (цветноÑÑ‚ÑŒ в 0, 0)', + '4:2:2 (chroma at 0.5, 0)' => '4:2:2 (цветноÑÑ‚ÑŒ в 0.5, 0)', + '56-bit 6 Channels Alpha' => '56-битный, 6 каналов, альфа-канал', + '56-bit 7 Channels' => '56-битный, 7 каналов', + '64-bit 3 Channels Alpha' => '64-битный, 3 канала, альфа-канал', + '64-bit 4 Channels' => '64-битный, 4 канала', + '64-bit 7 Channels Alpha' => '64-битный, 7 каналов, альфа-канал', + '64-bit 8 Channels' => '64-битный, 8 каналов', + '64-bit CMYK' => '64-битный, CMYK', + '64-bit PRGBA' => '64-битный, PRGBA', + '64-bit RGBA' => '64-битный, RGBA', + '64-bit RGBA Fixed Point' => '64-битный, RGBA Ñ Ñ„Ð¸ÐºÑированной точкой', + '64-bit RGBA Half' => '64-битный, RGBA Half', + '72-bit 8 Channels Alpha' => '72-битный, 8 каналов, альфа-канал', + '8-bit Gray' => '8-битный, Серый', + '80-bit 4 Channels Alpha' => '80-битный, 4 канала, альфа-канал', + '80-bit 5 Channels' => '80-битный, 5 канаов', + '80-bit CMYK Alpha' => '80-битный, CMYK, альфа-канал', + '96-bit 5 Channels Alpha' => '96-битный, 5 каналов, альфа-канал', + '96-bit 6 Channels' => '96-битный, 6 канаов', + '96-bit RGB Fixed Point' => '96-битный, RGB Ñ Ñ„Ð¸ÐºÑированной точкой', + 'Black & White' => 'Чёрно-белый', + 'Grayscale' => 'Оттенки Ñерого', + }, + }, + 'PixelIntensityRange' => 'Диапазон интенÑивноÑти пикÑелей (%)', + 'PixelMagicJBIGOptions' => 'Pixel Magic – Параметры JBIG', + 'PixelScale' => 'МаÑштаб пикÑелÑ', + 'PixelUnits' => { + Description => 'ПикÑельные единицы', + PrintConv => { + 'Unknown' => 'ÐеизвеÑтно', + 'meters' => 'Метры', + }, + }, + 'PixelsPerMeterX' => 'ПикÑелей на метр по X', + 'PixelsPerMeterY' => 'ПикÑелей на метр по Y', + 'PixelsPerUnitX' => 'ПикÑелей на единицу по X', + 'PixelsPerUnitY' => 'ПикÑелей на единицу по Y', + 'PlanarConfiguration' => { + Description => 'Принцип организации данных', + PrintConv => { + 'Chunky' => 'Ðепрерывный (RGBRGB)', + 'Planar' => 'По каналам (RRGGBB)', + }, + }, + 'Planes' => 'ПлоÑкоÑти', + 'PointSize' => 'Размер точки', + 'PopupFillAttributes' => 'Ðттрибуты Ð·Ð°Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ Ð²Ñплывающего окна', + 'PortraitVersion' => 'ÐŸÐ¾Ñ€Ñ‚Ñ€ÐµÑ‚Ð½Ð°Ñ Ð¾Ñ€Ð¸ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ', + 'PoseHeadingDegrees' => 'Ðаправление по компаÑу Ð´Ð»Ñ Ñ†ÐµÐ½Ñ‚Ñ€Ð° Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (°)', + 'PosePitchDegrees' => 'Продольный наклон Ð´Ð»Ñ Ñ†ÐµÐ½Ñ‚Ñ€Ð° Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (°)', + 'PoseRollDegrees' => 'Поперечный наклон Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ (°)', + 'PostScriptFontName' => 'PostScript название шрифта', + 'Pragma' => 'Контроль кÑшированиÑ', + 'Predictor' => { + Description => 'Предиктор', + PrintConv => { + 'Horizontal differencing' => 'Горизонтальное дифференцирование', + 'None' => 'Ðе иÑпользовалÑÑ', + }, + }, + 'PreferredFamily' => 'Предпочитаемое ÑемейÑтво шрифта', + 'PreferredSubfamily' => 'Предпочитаемый Ñтиль шрифта', + 'Prefs' => 'ÐаÑтройки', + 'PreservedSpecimen' => 'Сохраненный образец', + 'PreservedSpecimenMaterialSampleID' => 'ID материала Ñохранённого образца', + 'PresetWhiteBalance' => { + Description => 'ПредуÑтановка баланÑа белого', + PrintConv => { + 'Auto' => 'ÐвтоматичеÑкий', + 'Camera Setting' => 'ÐаÑтройка камеры', + 'Cloudy' => 'Облачно', + 'Color Temperature' => 'Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ñ‚ÐµÐ¼Ð¿ÐµÑ€Ð°Ñ‚ÑƒÑ€Ð°', + 'Cool White Fluorescent' => 'Холодный белый (флуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð°)', + 'Day Light Fluorescent' => 'Дневной Ñвет (флуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð°)', + 'Day White Fluorescent' => 'Дневной белый (флуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð°)', + 'Daylight' => 'Дневной Ñвет', + 'Flash' => 'Ð’Ñпышка', + 'Shade' => 'Тень', + 'Specify Gray Point' => 'Ð£ÐºÐ°Ð·Ð°Ð½Ð½Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° Ñерого', + 'Tungsten' => 'Лампа накаливаниÑ', + 'Warm White Fluorescent' => 'Тёплый белый (флуореÑÑ†ÐµÐ½Ñ‚Ð½Ð°Ñ Ð»Ð°Ð¼Ð¿Ð°)', + }, + }, + 'PresetWhiteBalanceAdj' => 'ПредуÑтановка баланÑа белого', + 'Pressure' => 'Давление', + 'Preview' => 'ПредпроÑмотр', + 'PreviewApplicationName' => 'Файл предпроÑмотра – Ðазвание приложениÑ', + 'PreviewApplicationVersion' => 'Файл предпроÑмотра – ВерÑÐ¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ', + 'PreviewColorSpace' => { + Description => 'Файл предпроÑмотра – Цветовое проÑтранÑтво', + PrintConv => { + 'Unknown' => 'ÐеизвеÑтно', + }, + }, + 'PreviewCropBottom' => 'ПредпроÑмотр – Обрезка Ñнизу', + 'PreviewCropLeft' => 'ПредпроÑмотр – Обрезка Ñлева', + 'PreviewCropRight' => 'ПредпроÑмотр – Обрезка Ñправа', + 'PreviewCropTop' => 'ПредпроÑмотр – Обрезка Ñверху', + 'PreviewDateTime' => 'Файл предпроÑмотра – Дата и ВремÑ', + 'PreviewImage' => 'Файл предпроÑмотра', + 'PreviewImageLength' => 'Строк в файле предпроÑмотра', + 'PreviewImageSize' => 'Размер файла предпроÑмотра', + 'PreviewImageStart' => 'Смещение файла предпроÑмотра', + 'PreviewPDF' => 'Файл предпроÑмотра PDF', + 'PreviewPNG' => 'Файл предпроÑмотра PNG', + 'PreviewSettingsDigest' => 'Файл предпроÑмотра – Идентификатор параметров преобразованиÑ', + 'PreviewSettingsName' => 'Файл предпроÑмотра – Ðазвание параметров преобразованиÑ', + 'PreviewTIFF' => 'Файл предпроÑмотра TIFF', + 'PreviewWMF' => 'Файл предпроÑмотра WMF', + 'PrimaryChromaticities' => 'ЦветноÑÑ‚ÑŒ оÑновных цветов', + 'PrimaryFTP' => 'ОÑновной FTP', + 'PrintFlags' => 'Флаги печати', + 'PrintFlagsInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ флагах печати', + 'PrintIMVersion' => 'ВерÑÐ¸Ñ PrintIM', + 'PrintInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ печати', + 'PrintInfo2' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ печати 2', + 'PrintPosition' => 'Положение при печати', + 'PrintScale' => 'МаÑштаб при печати', + 'PrintStyle' => { + Description => 'Стиль печати', + PrintConv => { + 'Centered' => 'По центру', + 'Size to Fit' => 'Подогнать под формат лиÑта', + 'User Defined' => 'Определённый пользователем', + }, + }, + 'Priority' => 'Приоритет', + 'Private' => 'ЧаÑтный', + 'PrivateRTKInfo' => 'ЧаÑÑ‚Ð½Ð°Ñ Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾ RTK', + 'ProTune' => { + PrintConv => { + 'Off' => 'Ðе включён', + 'On' => 'Включен', + }, + }, + 'ProcessingSoftware' => 'Редактировано в приложении', + 'ProcessingTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸', + 'ProdNotes' => 'КоличеÑтво заметок производителÑ', + 'ProducedDate' => 'Дата производÑтва', + 'Producer' => 'Производитель', + 'ProductID' => 'ID продукта', + 'ProductOrServiceConstraints' => 'ÐžÐ³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð½Ð° продукты или уÑлуги', + 'Profile' => 'Профиль', + 'Profile1AudioCodec' => 'Профиль 1 – Кодек аудио', + 'Profile1Height' => 'Профиль 1 – Ð’Ñ‹Ñота', + 'Profile1VideoCodec' => 'Профиль 1 – Кодек видео', + 'Profile1Width' => 'Профиль 1 – Ширина', + 'ProfileCalibrationSig' => 'Сигнатура калибровки профилÑ', + 'ProfileCopyright' => 'ÐвторÑкое право профилÑ', + 'ProfileDataOffset' => 'Смещение данных профилÑ', + 'ProfileEmbedPolicy' => { + Description => 'Политика Ð²Ð½ÐµÐ´Ñ€ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ', PrintConv => { - 'Horizontal (normal)' => 'Положительное направление', - 'Rotate 180' => 'Поворот на 180°', - 'Rotate 270 CW' => 'Поворот на 270° по чаÑовой Ñтрелке', - 'Rotate 90 CW' => 'Поворот на 90° по чаÑовой Ñтрелке', + 'Allow Copying' => 'Разрешено копирование', + 'Embed if Used' => 'Внедрить еÑли иÑпользуетÑÑ', + 'Never Embed' => 'Ðикогда не внедрÑÑ‚ÑŒ', + 'No Restrictions' => 'Без ограничений', }, }, - 'FileFormat' => 'Формат', - 'FileModifyDate' => 'Дата обновлениÑ', - 'FileName' => 'Ð˜Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°', - 'FileSize' => 'Размер файла', - 'FileSource' => { - Description => 'ИÑточник файла', + 'ProfileHueSatMapData1' => 'Профиль – Карта оттенков/наÑыщенноÑти – Данные 1', + 'ProfileHueSatMapData2' => 'Профиль – Карта оттенков/наÑыщенноÑти – Данные 2', + 'ProfileHueSatMapDims' => 'Профиль – Карта оттенков/наÑыщенноÑти – Затемнение', + 'ProfileHueSatMapEncoding' => { + Description => 'Профиль – Карта оттенков/наÑыщенноÑти – Кодирование', PrintConv => { - 'Digital Camera' => 'DSC', - 'Film Scanner' => 'Сканнер проÑвечивающего типа', - 'Reflection Print Scanner' => 'Сканнер отражающего типа', + 'Linear' => 'Линейное', }, }, - 'FileType' => 'Тип файла', - 'Filename' => 'Ð˜Ð¼Ñ Ñ„Ð°Ð¹Ð»Ð°', - 'Flash' => { - Description => 'Ð’Ñпышка', + 'ProfileLookTableData' => 'Профиль – Таблица подÑтановки – Данные', + 'ProfileLookTableDims' => 'Профиль – Таблица подÑтановки – Затемнение', + 'ProfileLookTableEncoding' => { + Description => 'Профиль – Таблица подÑтановки – Кодирование', PrintConv => { - 'Auto, Fired' => 'Вкл. (автоматичеÑÐºÐ°Ñ Ð²Ñпышка)', - 'Auto, Fired, Red-eye reduction' => '"Вкл. (автоматичеÑÐºÐ°Ñ Ð²Ñпышка, Ñнижение Ñффекта «краÑных глаз»)"', - 'Auto, Fired, Red-eye reduction, Return detected' => '"Вкл. (автоматичеÑÐºÐ°Ñ Ð²Ñпышка, Ñнижение Ñффекта «краÑных глаз», региÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð°Ð¶ÐµÐ½Ð½Ð¾Ð³Ð¾ луча)"', - 'Auto, Fired, Return detected' => '"Вкл. (автоматичеÑÐºÐ°Ñ Ð²Ñпышка, региÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð°Ð¶ÐµÐ½Ð½Ð¾Ð³Ð¾ луча)"', - 'Did not fire' => 'Ð’Ñпышка не Ñработала', - 'Fired' => 'Ð’Ñпышка Ñработала', - 'Fired, Red-eye reduction' => 'Вкл. (Ñнижение Ñффекта «краÑных глаз»)', - 'Fired, Red-eye reduction, Return detected' => '"Вкл. (Ñнижение Ñффекта «краÑных глаз», региÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð°Ð¶ÐµÐ½Ð½Ð¾Ð³Ð¾ луча)"', - 'Fired, Return detected' => 'Вкл. (региÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð°Ð¶ÐµÐ½Ð½Ð¾Ð³Ð¾ луча)', - 'No Flash' => 'Ðет функции вÑпышки', - 'On, Fired' => 'Вкл. (принудительнаÑ)', - 'On, Red-eye reduction' => '"Вкл. (принудительнаÑ, Ñнижение Ñффекта «краÑных глаз»)"', - 'On, Red-eye reduction, Return detected' => '"Вкл. (принудительнаÑ, Ñнижение Ñффекта «краÑных глаз», региÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð°Ð¶ÐµÐ½Ð½Ð¾Ð³Ð¾ луча)"', - 'On, Return detected' => '"Вкл. (принудительнаÑ, региÑÑ‚Ñ€Ð°Ñ†Ð¸Ñ Ð¾Ñ‚Ñ€Ð°Ð¶ÐµÐ½Ð½Ð¾Ð³Ð¾ луча)"', + 'Linear' => 'Линейное', }, }, - 'FlashEnergy' => 'МощноÑÑ‚ÑŒ вÑпышки', - 'FlashExposureComp' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð²Ñпышки', - 'FlashpixVersion' => 'ÐŸÐ¾Ð´Ð´ÐµÑ€Ð¶Ð¸Ð²Ð°ÐµÐ¼Ð°Ñ Ð²ÐµÑ€ÑÐ¸Ñ Flashpix', - 'FocalLength' => 'ФокуÑное раÑÑтоÑние', - 'FocalLength35efl' => 'ФокуÑное раÑÑтоÑние (приведено к 35 мм)', - 'FocalLengthIn35mmFormat' => 'ФокуÑное раÑÑтоÑние Ð´Ð»Ñ 35-мм фотопленки', - 'FocalPlaneResolutionUnit' => { - Description => 'Элемент Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð² фокальной плоÑкоÑти', + 'ProfileName' => 'Ðазвание профилÑ', + 'ProfileSize' => 'Размер профилÑ', + 'ProfileToneCurve' => 'Профиль – Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ', + 'ProfileType' => { + Description => 'Тип профилÑ', PrintConv => { - 'inches' => 'дюйм', + 'Unspecified' => 'Ðе указан', }, }, - 'FocalPlaneXResolution' => 'Разрешение в фокальной плоÑкоÑти по X', - 'FocalPlaneYResolution' => 'Разрешение в фокальной плоÑкоÑти по Y', - 'FocusMode' => 'ФокуÑировка', - 'ForwardMatrix1' => 'ПрÑÐ¼Ð°Ñ Ð¼Ð°Ñ‚Ñ€Ð¸Ñ†Ð° â„–1', - 'ForwardMatrix2' => 'ПрÑÐ¼Ð°Ñ Ð¼Ð°Ñ‚Ñ€Ð¸Ñ†Ð° â„–2', - 'FrameRate' => 'ПлотноÑÑ‚ÑŒ кадров', - 'FrameSize' => '"Кадр, размер"', - 'GPSAltitude' => 'Ð’Ñ‹Ñота', - 'GPSAltitudeRef' => { - Description => 'Определение по выÑоте', - PrintConv => { - 'Above Sea Level' => 'Уровень морÑ', - 'Below Sea Level' => 'Опорное значение ÑƒÑ€Ð¾Ð²Ð½Ñ Ð¼Ð¾Ñ€Ñ (негативное значение)', - }, - }, - 'GPSAreaInformation' => 'Ðазвание облаÑти GPS', - 'GPSDOP' => 'ТочноÑÑ‚ÑŒ измерениÑ', - 'GPSDateStamp' => 'Дата GPS', - 'GPSDestBearing' => 'Ðзимут пункта назначениÑ', - 'GPSDestBearingRef' => 'ÐžÐ¿Ð¾Ñ€Ð½Ð°Ñ Ð²ÐµÐ»Ð¸Ñ‡Ð¸Ð½Ð° Ð´Ð»Ñ Ð°Ð·Ð¸Ð¼ÑƒÑ‚Ð° пункта назначениÑ', - 'GPSDestDistance' => 'РаÑÑтоÑние до пункта назначениÑ', - 'GPSDestDistanceRef' => 'ÐžÐ¿Ð¾Ñ€Ð½Ð°Ñ Ð²ÐµÐ»Ð¸Ñ‡Ð¸Ð½Ð° раÑÑтоÑÐ½Ð¸Ñ Ð´Ð¾ пункта назначениÑ', - 'GPSDestLatitude' => 'Широта пункта назначениÑ', - 'GPSDestLatitudeRef' => 'ÐžÐ¿Ð¾Ñ€Ð½Ð°Ñ Ð²ÐµÐ»Ð¸Ñ‡Ð¸Ð½Ð° Ð´Ð»Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ñ‹ пункта назначениÑ', - 'GPSDestLongitude' => 'Долгота пункта назначениÑ', - 'GPSDestLongitudeRef' => 'ÐžÐ¿Ð¾Ñ€Ð½Ð°Ñ Ð²ÐµÐ»Ð¸Ñ‡Ð¸Ð½Ð° Ð´Ð»Ñ Ð´Ð¾Ð»Ð³Ð¾Ñ‚Ñ‹ пункта назначениÑ', - 'GPSDifferential' => { - Description => 'Ð”Ð¸Ñ„Ñ„ÐµÑ€ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð°Ñ ÐºÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ GPS', + 'ProgID' => 'ID приложениÑ', + 'ProgramID' => 'ID программы', + 'ProgramMode' => { + Description => 'Режим программы', PrintConv => { - 'Differential Corrected' => 'Ð”Ð¸Ñ„Ñ„ÐµÑ€ÐµÐ½Ñ†Ð¸Ð°Ð»ÑŒÐ½Ð°Ñ ÐºÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð¿Ñ€Ð¸Ð¼ÐµÐ½ÐµÐ½Ð°', - 'No Correction' => 'Измерение без дифференциальной коррекции', + 'Night Portrait' => 'Ðочной портрет', + 'None' => 'ОтÑутÑтвует', + 'Portrait' => 'Портрет', + 'Sports' => 'Спорт', + 'Sunset' => 'Закат', + 'Text' => 'ТекÑÑ‚', }, }, - 'GPSImgDirection' => 'Ðаправление изображениÑ', - 'GPSImgDirectionRef' => 'ÐžÐ¿Ð¾Ñ€Ð½Ð°Ñ Ð²ÐµÐ»Ð¸Ñ‡Ð¸Ð½Ð° Ð´Ð»Ñ Ð½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ', - 'GPSInfo' => 'IFD указатель информации GPS', - 'GPSLatitude' => 'Широта', - 'GPSLatitudeRef' => { - Description => 'Ð¡ÐµÐ²ÐµÑ€Ð½Ð°Ñ Ð¸Ð»Ð¸ ÑŽÐ¶Ð½Ð°Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ð°', + 'ProgramVersion' => 'ВерÑÐ¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ', + 'ProgressiveScans' => { + Description => 'ПрогреÑÑивное Ñканирование', PrintConv => { - 'North' => 'Ð¡ÐµÐ²ÐµÑ€Ð½Ð°Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ð°', - 'South' => 'Ð®Ð¶Ð½Ð°Ñ ÑˆÐ¸Ñ€Ð¾Ñ‚Ð°', + '3 Scans' => '3 прохода', + '4 Scans' => '4 прохода', + '5 Scans' => '5 проходов', }, }, - 'GPSLongitude' => 'Долгота', - 'GPSLongitudeRef' => { - Description => 'ВоÑÑ‚Ð¾Ñ‡Ð½Ð°Ñ Ð¸Ð»Ð¸ Ð·Ð°Ð¿Ð°Ð´Ð½Ð°Ñ Ð´Ð¾Ð»Ð³Ð¾Ñ‚Ð°', + 'Project' => 'Проект', + 'ProjectionType' => 'Тип проекции', + 'PropertyReleaseID' => 'ID ÑвойÑтв релиза', + 'PropertyReleaseStatus' => { + Description => 'Ð¡Ñ‚Ð°Ñ‚ÑƒÑ ÑвойÑтв релиза', PrintConv => { - 'East' => 'ВоÑÑ‚Ð¾Ñ‡Ð½Ð°Ñ Ð´Ð¾Ð»Ð³Ð¾Ñ‚Ð°', - 'West' => 'Ð—Ð°Ð¿Ð°Ð´Ð½Ð°Ñ Ð´Ð¾Ð»Ð³Ð¾Ñ‚Ð°', + 'Limited or Incomplete Property Releases' => 'Ограниченные или неполные релизы', + 'None' => 'Ðе обозначено', + 'Not Applicable' => 'Ðе иÑпользуетÑÑ', + 'Unlimited Property Releases' => 'Ðеограниченные релизы ÑвойÑтв', }, }, - 'GPSMapDatum' => 'ИÑпользованы данные геодезичеÑких иÑÑледований', - 'GPSMeasureMode' => { - Description => 'Режим Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ GPS', + 'Protect' => 'Защита', + 'Provider' => 'ПоÑтавщик', + 'ProviderCopyright' => 'ПоÑтавщик – ÐвторÑкое право', + 'ProviderRating' => 'Провайдер – Рейтинг', + 'Province-State' => 'ОблаÑÑ‚ÑŒ/район', + 'PublishDate' => 'Дата публикации', + 'PublishDateStart' => 'Дата начала публикации', + 'Publisher' => 'Издатель', + 'PublisherLimit' => 'ÐžÐ³Ñ€Ð°Ð½Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð¸Ð·Ð´Ð°Ñ‚ÐµÐ»Ñ', + 'PxShiftPeriphEdgeNR' => { PrintConv => { - '3-Dimensional Measurement' => '3-мерное измерение', + 'Off' => 'Ðе включён', + 'On' => 'Включен', }, }, - 'GPSProcessingMethod' => 'Ðазвание метода обработки GPS', - 'GPSSatellites' => '"Спутники GPS, иÑпользуемые Ð´Ð»Ñ Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ"', - 'GPSSpeed' => 'СкороÑÑ‚ÑŒ GPS-уÑтройÑтва', - 'GPSSpeedRef' => { - Description => 'СкороÑтной Ñлемент', + 'PyramidLevels' => 'Уровни пирамиды', + 'Quality' => { + Description => 'КачеÑтво', PrintConv => { - 'km/h' => 'Километры в чаÑ', - 'knots' => 'Узлы', - 'mph' => 'Мили в чаÑ', + '2 (Telephone)' => '2 (Телефон)', + '3 (Thumb)' => '3 (ЭÑкиз)', + '4 (Radio)' => '4 (Радио)', + '5 (Standard)' => '5 (Стандартное)', + '6 (Xtreme)' => '6 (ЭкÑтремальное)', + '7 (Insane)' => '7 (СумаÑшедшее)', + '8 (BrainDead)' => '8 (Полный улёт)', + 'Compressed RAW' => 'cRAW', + 'Compressed RAW + JPEG' => 'cRAW+JPEG', + 'Extra Fine' => 'СверхвыÑокое', + 'Fine' => 'Ð’Ñ‹Ñокое', + 'Low' => 'Ðизкое качеÑтво', + 'Normal' => 'Стандартное качеÑтво', + 'RAW + JPEG' => 'RAW+JPEG', + 'Standard' => 'Стандартное', + 'Unstable/Experimental' => 'ÐеÑтабильное/ЭкÑпериментальное', }, }, - 'GPSStatus' => { - Description => 'СоÑтоÑние GPS-уÑтройÑтва', + 'QuantizationMethod' => { + Description => 'Метод квантованиÑ', PrintConv => { - 'Measurement Active' => 'ПроизводитÑÑ Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ðµ', - 'Measurement Void' => 'Ð’Ð·Ð°Ð¸Ð¼Ð½Ð°Ñ ÑовмеÑтимоÑÑ‚ÑŒ измерений', + 'Color Space Specific' => 'Специфичное цветовое проÑтранÑтво', + 'Compression Method Specific' => 'Специфичный метод ÑжатиÑ', + 'Gamma Compensated' => 'КомпенÑÐ°Ñ†Ð¸Ñ Ð³Ð°Ð¼Ð¼Ñ‹', + 'Linear Density' => 'Ð›Ð¸Ð½ÐµÐ¹Ð½Ð°Ñ Ð¿Ð»Ð¾Ñ‚Ð½Ð¾ÑÑ‚ÑŒ', + 'Linear Reflectance/Transmittance' => 'Линейное Отражение/ПропуÑкание', }, }, - 'GPSTimeStamp' => 'GPS-Ð²Ñ€ÐµÐ¼Ñ (атомные чаÑÑ‹)', - 'GPSTrack' => 'Ðаправление движениÑ', - 'GPSTrackRef' => { - Description => 'ÐžÐ¿Ð¾Ñ€Ð½Ð°Ñ Ð²ÐµÐ»Ð¸Ñ‡Ð¸Ð½Ð° Ð½Ð°Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð´Ð²Ð¸Ð¶ÐµÐ½Ð¸Ñ', + 'QuickEdit' => 'БыÑтрое редактирование', + 'QuickMaskInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ быÑтрой маÑке', + 'QuickShot' => { + Description => 'БыÑтрый Ñнимок', PrintConv => { - 'Magnetic North' => 'Ðаправление магнитной Ñтрелки', - 'True North' => 'ИÑтинное направление', + 'Off' => 'Ðе включён', + 'On' => 'Включен', }, }, - 'GPSVersionID' => 'ВерÑÐ¸Ñ GPS-Ñ‚Ñга', - 'GainControl' => { - Description => 'Управление шагом', + 'RAFVersion' => 'ВерÑÐ¸Ñ RAF', + 'RGBCurves' => 'Кривые RGB', + 'ROIDescription' => 'ОпиÑание ROI', + 'RPP' => 'Raw Photo Processor (RPP)', + 'RasterPadding' => { + Description => 'РаÑтровое заполнение', PrintConv => { - 'High gain down' => 'С большим шагом вниз', - 'High gain up' => 'С большим шагом вверх', - 'Low gain down' => 'С малым шагом вниз', - 'Low gain up' => 'С малым шагом вверх', - 'None' => 'Ðет', + 'Byte' => 'Байт', + 'Long Sector' => 'Длинный Ñектор', + 'Long Word' => 'Длинное Ñлово', + 'Sector' => 'Сектор', + 'Word' => 'Слово', }, }, - 'Gamma' => 'Гамма', - 'Gradation' => 'ВпечатлÑющ.режим', - 'HDR' => { - Description => 'Ðвто HDR', + 'RasterizedCaption' => 'РаÑтрированное опиÑание', + 'Rate' => 'Темп', + 'Rating' => 'Рейтинг', + 'RatingPercent' => 'Рейтинг (%)', + 'RawCropBottom' => 'Raw – Обрезка Ñнизу', + 'RawCropLeft' => 'Raw – Обрезка Ñлева', + 'RawCropRight' => 'Raw – Обрезка Ñправа', + 'RawCropTop' => 'Raw – Обрезка Ñверху', + 'RawData' => 'Raw-данные', + 'RawDataLength' => 'Строк в Raw-данных', + 'RawDataOffset' => 'Смещение RAW-данных', + 'RawDataUniqueID' => 'Уникальный ID RAW-данных', + 'RawDepth' => 'Глубина Raw-изображениÑ', + 'RawFile' => 'RAW-файл', + 'RawFormat' => 'RAW-формат', + 'RawImageDigest' => 'Хеш-Ñумма RAW-изображениÑ', + 'RawImageMode' => 'Режим Raw-изображениÑ', + 'RawImageSegmentation' => 'Ð¡ÐµÐ³Ð¼ÐµÐ½Ñ‚Ð°Ñ†Ð¸Ñ RAW-изображениÑ', + 'RawToPreviewGain' => 'КоÑффициент ÑƒÐ²ÐµÐ»Ð¸Ñ‡ÐµÐ½Ð¸Ñ Ð¼ÐµÐ¶Ð´Ñƒ Raw и файлом предпроÑмотра', + 'Rawrppused' => 'ИÑпользовалÑÑ RPP', + 'RawzorCreatorVersion' => 'ВерÑÐ¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ', + 'RawzorRequiredVersion' => 'Ð¢Ñ€ÐµÐ±ÑƒÐµÐ¼Ð°Ñ Ð²ÐµÑ€ÑиÑ', + 'ReaderName' => 'Ðазвание проÑмотрщика', + 'ReaderRequirements' => 'Ð¢Ñ€ÐµÐ±Ð¾Ð²Ð°Ð½Ð¸Ñ Ðº ридеру', + 'RecEngineer' => 'Инженер', + 'RecLocation' => 'ЛокациÑ', + 'RecommendedExposureIndex' => 'Рекомендуемый Ð¸Ð½Ð´ÐµÐºÑ ÑкÑпозиции', + 'Record' => 'ЗапиÑÑŒ', + 'RecordBasisOfRecord' => 'ОÑнование запиÑи', + 'RecordCollectionCode' => 'Код/Ðазвание коллекции запиÑи', + 'RecordCollectionID' => 'ID коллекции запиÑи', + 'RecordDataGeneralizations' => 'Обобщение данных запиÑи', + 'RecordDatasetID' => 'ID базы данных запиÑи', + 'RecordDatasetName' => 'Ðазвание базы данных запиÑи', + 'RecordDynamicProperties' => 'ДинамичеÑкие ÑвойÑтва запиÑи', + 'RecordInformationWithheld' => 'Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ñ‚ÑутÑÑ‚Ð²ÑƒÑŽÑ‰Ð°Ñ Ð² запиÑи', + 'RecordInstitutionCode' => 'ÐžÑ€Ð³Ð°Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¾Ð±Ñ€Ð°Ð·Ñ†Ð° или информации', + 'RecordInstitutionID' => 'ID организации Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¾Ð±Ñ€Ð°Ð·Ñ†Ð° или информации', + 'RecordMode' => 'Режим запиÑи', + 'RecordOwnerInstitutionCode' => 'ОрганизациÑ-владелец образца или информации', + 'RecordShutterRelease' => { + Description => 'СпуÑк затвора при запиÑи', PrintConv => { - 'Off' => 'Отключено', + 'Press start, press stop' => 'Ðажать «Старт», нажать «Стоп»', + 'Record while down' => 'ЗапиÑÑŒ пока нажата кнопка', }, }, - 'Headline' => 'Заголовок', - 'HighISONoiseReduction' => { - Description => 'NR выÑокого ISO', + 'RecurrenceDateTimes' => 'Дата/Ð’Ñ€ÐµÐ¼Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€ÐµÐ½Ð¸Ñ ÑобытиÑ', + 'RecurrenceID' => 'ID повторÑющегоÑÑ ÑобытиÑ', + 'RecurrenceRule' => 'Правило повторениÑ', + 'RedBalance' => 'Ð‘Ð°Ð»Ð°Ð½Ñ ÐºÑ€Ð°Ñного', + 'RedBlueFlatField' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð¿Ð»Ð¾Ñкого Ð¿Ð¾Ð»Ñ â€“ КраÑный и Синий', + 'RedEndpoint' => 'ÐšÐ¾Ð½ÐµÑ‡Ð½Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° КраÑного', + 'RedEyeReduction' => { + Description => 'Уменьшение Ñффекта краÑных глаз', PrintConv => { - 'Auto' => 'Ðвто', - 'High' => 'Hi', - 'Low' => 'Lo', - 'Normal' => 'ÐормальнаÑ', - 'Off' => 'Отключено', + 'Off' => 'Ðе включено', + 'On' => 'Включено', }, }, - 'Hue' => 'Оттенок', - 'ISO' => 'Значение ISO', - 'ImageHeight' => 'Ð’Ñ‹Ñота Ñнимка', - 'ImageSize' => '"Снимок, размер"', - 'ImageStabilization' => { + 'RedMask' => 'МаÑка КраÑного', + 'RedPrimary' => 'ОÑновной краÑный', + 'RedX' => 'КраÑный по X', + 'RedY' => 'КраÑный по Y', + 'RedcodeVersion' => 'ВерÑÐ¸Ñ Redcode', + 'ReductionMatrix1' => 'Матрица редукции 1', + 'ReductionMatrix2' => 'Матрица редукции 2', + 'ReelName' => 'Ðазвание ноÑÐ¸Ñ‚ÐµÐ»Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸', + 'ReelNumber' => 'Ðомер запиÑи', + 'ReelTimecode' => 'Таймкод запиÑи', + 'Reference' => 'СÑылка', + 'ReferenceBlackWhite' => 'ИÑходные Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ñ‡Ñ‘Ñ€Ð½Ð¾Ð³Ð¾ и белого', + 'ReferenceDate' => 'Дата предыдущего конверта', + 'ReferenceNumber' => 'Ðомер предыдущего конверта', + 'ReferenceService' => 'СÑылка на предыдущий конверт', + 'Refresh' => 'Задержка Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñтраницы', + 'RegionAppliedToDimensions' => 'Размеры Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ которых применÑлÑÑ Ñ€ÐµÐ³Ð¸Ð¾Ð½', + 'RegionAppliedToDimensionsH' => 'Ð’Ñ‹Ñота Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ которой применÑÐ»Ñ Ñ€ÐµÐ³Ð¸Ð¾Ð½', + 'RegionAppliedToDimensionsUnit' => 'Единицы размеров изображениÑ', + 'RegionAppliedToDimensionsW' => 'Ширина Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¸ которой применÑÐ»Ñ Ñ€ÐµÐ³Ð¸Ð¾Ð½', + 'RegionArea' => 'ОблаÑÑ‚ÑŒ региона', + 'RegionAreaD' => 'Диаметр круглой облаÑти', + 'RegionAreaH' => 'Ð’Ñ‹Ñота прÑмоугольной облаÑи', + 'RegionAreaUnit' => 'Единицы Ð¸Ð·Ð¼ÐµÑ€ÐµÐ½Ð¸Ñ Ð¾Ð±Ð»Ð°Ñти', + 'RegionAreaW' => 'Ширина прÑмоугольной облаÑти', + 'RegionAreaX' => 'Координаты центра облаÑти по X', + 'RegionAreaY' => 'Координаты центра облаÑти по Y', + 'RegionBarCodeValue' => 'Значение штрихкода региона', + 'RegionConstraints' => 'Региональные ограничениÑ', + 'RegionDescription' => 'ОпиÑание региона', + 'RegionExtensions' => 'Дополнительное ÑвойÑтво региона', + 'RegionFocusUsage' => { + Description => 'ИÑпользование фокуÑа', PrintConv => { - 'CCD Shift' => 'ОптичеÑкий Ñтабилизатор', - 'High Sensitivity' => 'Движение объекта Ñъёмки', - 'Off' => 'Выкл', - 'Off (1)' => 'Выкл (1)', + 'Evaluated, Not Used' => 'УчитывалÑÑ, но не иÑпользовалÑÑ', + 'Evaluated, Used' => 'УчитывалÑÑ Ð¸ иÑпользовалÑÑ', + 'Not Evaluated, Not Used' => 'Ðе учитывалÑÑ Ð¸ не иÑпользовалÑÑ', }, }, - 'ImageUniqueID' => 'Уникальный ID-код Ñнимка', - 'ImageWidth' => 'Ширина Ñнимка', - 'Index' => 'ИндекÑ', - 'Instructions' => 'ИнÑтрукции', - 'InteropIndex' => 'Ð˜Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð²Ð·Ð°Ð¸Ð¼Ð½Ð¾Ð¹ ÑовмеÑтимоÑти', - 'InteropOffset' => 'ТÑг взаимной ÑовмеÑтимоÑти', - 'InteropVersion' => 'ВерÑÐ¸Ñ Ð²Ð·Ð°Ð¸Ð¼Ð½Ð¾Ð¹ ÑовмеÑтимоÑти', - 'JPEGQuality' => { - Description => 'КачеÑтво изображениÑ', + 'RegionInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾Ð± регионе', + 'RegionInfoDateRegionsValid' => 'Дата ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ð¿Ð¾Ñледнего региона', + 'RegionInfoMP' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ регионе в Microsoft Photo', + 'RegionInfoRegions' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ регионах', + 'RegionList' => 'СпиÑок Ñтруктуры регионов', + 'RegionName' => 'Ðазвание региона', + 'RegionPersonDisplayName' => 'Ð˜Ð¼Ñ Ñ‡ÐµÐ»Ð¾Ð²ÐµÐºÐ° отмеченное регионом', + 'RegionPersonEmailDigest' => 'Хеш-Ñумма Ñлектронной почты Windows Live пользователÑ', + 'RegionPersonLiveIdCID' => 'ID Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ Windows Live CID', + 'RegionPersonSourceID' => 'ИÑходный ID пользователÑ', + 'RegionRectangle' => 'ПрÑмоугольник региона', + 'RegionRotation' => 'Вращение региона', + 'RegionSeeAlso' => 'Смотрите также', + 'RegionType' => { + Description => 'Тип региона', PrintConv => { - 'Extra Fine' => 'СверхвыÑокое', - 'Fine' => 'Ð’Ñ‹Ñокое', - 'Standard' => 'Стандартное качеÑтво', + 'BarCode' => 'Штрихкод', + 'Face' => 'Лицо', + 'Focus' => 'ФокуÑ', + 'Pet' => 'Животное', }, }, - 'Keywords' => 'Ключевые Ñлова', - 'Lens' => 'Объектив', - 'LensInfo' => 'Ð˜Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð¾Ð± объективе', - 'LightSource' => { - Description => 'ИÑточник Ñвета', + 'RegionXformTackPoint' => 'Точки-модификаторы облаÑти Ð¿Ñ€ÐµÐ¾Ð±Ñ€Ð°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ Xform', + 'RelatedImageFileFormat' => 'Формат файла ÑвÑзанного изображениÑ', + 'RelatedImageHeight' => 'Ð’Ñ‹Ñота ÑвÑзанного изображениÑ', + 'RelatedImageWidth' => 'Ширина ÑвÑзанного изображениÑ', + 'RelatedResourceID' => 'ID ÑвÑзанного реÑурÑа', + 'RelatedSoundFile' => 'СвÑзанный аудиофайл', + 'RelatedTo' => 'ОтноÑитÑÑ Ðº', + 'Relation' => 'СÑылка на ÑвÑзанный реÑурÑ', + 'RelationshipAccordingTo' => 'СвÑзь между реÑурÑами Ñоздал', + 'RelationshipEstablishedDate' => 'Дата ÑвÑзи между реÑурÑами', + 'RelationshipOfResource' => 'СвÑзь реÑурÑов', + 'RelationshipRemarks' => 'Комментарии к ÑвÑзи реÑурÑов', + 'RelativeAltitude' => 'ОтноÑÐ¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ð²Ñ‹Ñота', + 'RelativePath' => 'ОтноÑительный путь', + 'ReleaseDate' => 'Дата публикации', + 'ReleaseTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð¿ÑƒÐ±Ð»Ð¸ÐºÐ°Ñ†Ð¸Ð¸', + 'RemoveHistoryDuplicates' => 'Удалить иÑторию дубликатов', + 'RenderingIntent' => { + Description => 'Методы цветового преобразованиÑ', PrintConv => { - 'Cloudy' => 'ОблачноÑÑ‚ÑŒ', - 'Cool White Fluorescent' => 'ФлуореÑцентный белый холодный (W 3800 - 4500K)', - 'Day White Fluorescent' => 'ФлуореÑцентный белый дневной', - 'Daylight' => 'Дневной Ñвет', - 'Daylight Fluorescent' => 'ФлуореÑцентный белый дневного Ñвета (D 5700 - 7100K)', - 'Fine Weather' => 'ЯÑÐ½Ð°Ñ Ð¿Ð¾Ð³Ð¾Ð´Ð°', - 'Flash' => 'Ð’Ñпышка', - 'Fluorescent' => 'ФлуореÑцентный', - 'ISO Studio Tungsten' => 'ISO Ð´Ð»Ñ Ñтудийных ламп накаливаниÑ', - 'Other' => 'другой иÑточник Ñвета', - 'Shade' => 'Тень', - 'Standard Light A' => 'Стандартный Ñвет A', - 'Standard Light B' => 'Стандартный Ñвет B', - 'Standard Light C' => 'Стандартный Ñвет C', - 'Tungsten (Incandescent)' => 'Лампа Ð½Ð°ÐºÐ°Ð»Ð¸Ð²Ð°Ð½Ð¸Ñ (Ñркий Ñвет)', - 'Unknown' => 'неизвеÑтно', - 'Warm White Fluorescent' => 'ФлуореÑцентный теплый белый (L 2600 - 3250K)', - 'White Fluorescent' => 'ФлуореÑцентный белый (WW 3250 - 3800K)', + 'Absolute Colorimetric (LCS_GM_ABS_COLORIMETRIC)' => 'ÐбÑолютный колориметричеÑкий (LCS_GM_ABS_COLORIMETRIC)', + 'Graphic (LCS_GM_BUSINESS)' => 'По наÑыщенноÑти (LCS_GM_BUSINESS)', + 'Picture (LCS_GM_IMAGES)' => 'Перцепционный (LCS_GM_IMAGES)', + 'Proof (LCS_GM_GRAPHICS)' => 'ОтноÑительный колориметричеÑкий (LCS_GM_GRAPHICS)', }, }, - 'Lightness' => 'ОÑвещенноÑÑ‚ÑŒ', - 'LinearResponseLimit' => 'Предел линейного отклика', - 'LinearizationTable' => 'Таблица линеаризации', - 'LocalizedCameraModel' => 'Локализованное название фотоаппарата', - 'Location' => 'МеÑто Ñъемки', - 'LongExposureNoiseReduction' => { - Description => 'NR долгой ÑкÑп.', + 'RenderingTransform' => 'Преобразование цвета', + 'RentalExpirationDate' => 'Дата Ð¾ÐºÐ¾Ð½Ñ‡Ð°Ð½Ð¸Ñ Ð°Ñ€ÐµÐ½Ð´Ñ‹', + 'RentalFlag' => 'Флаг аренды', + 'Repeat' => 'КоличеÑтво повторов', + 'ReplayGainAlbumGain' => 'Replay Gain – ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð³Ñ€Ð¾Ð¼ÐºÐ¾Ñти альбома', + 'ReplayGainAlbumPeak' => 'Replay Gain – Пиковый уровень альбома', + 'ReplayGainTrackGain' => 'Replay Gain – ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð³Ñ€Ð¾Ð¼ÐºÐ¾Ñти трека', + 'ReplayGainTrackPeak' => 'Replay Gain – Пиковый уровень трека', + 'ReplyTo' => 'E-Mail вебмаÑтера', + 'RepresentativeDisparityFar' => 'Ð ÐµÐ¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ‚Ð¸Ð²Ð½Ð°Ñ Ð½ÐµÑоглаÑованноÑÑ‚ÑŒ – Вдали', + 'RepresentativeDisparityNear' => 'Ð ÐµÐ¿Ñ€ÐµÐ·ÐµÐ½Ñ‚Ð°Ñ‚Ð¸Ð²Ð½Ð°Ñ Ð½ÐµÑоглаÑованноÑÑ‚ÑŒ – РÑдом', + 'RepresentativeImage' => { + Description => 'Репрезентативное изображение', PrintConv => { - 'Off' => 'Отключено', - 'On' => 'Включено', + 'Left Viewpoint' => 'Ð›ÐµÐ²Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° проÑмотра', + 'Right Viewpoint' => 'ÐŸÑ€Ð°Ð²Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° проÑмотра', }, }, - 'Make' => 'Изготовитель', - 'MakerNote' => 'Приватные данные DNG', - 'MakerNoteSafety' => { - Description => 'БезопаÑноÑÑ‚ÑŒ «примечаний производителÑ»', + 'RequestID' => 'ID запрÑа', + 'RequestStatus' => 'Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ð·Ð°Ð¿Ñ€Ð¾Ñа', + 'Resaved' => { + Description => 'Повторное Ñохранение', PrintConv => { - 'Safe' => 'БезопаÑно', - 'Unsafe' => 'ÐебезопаÑно', + 'No' => 'Ðет', + 'Yes' => 'Да', }, }, - 'MakerNotes' => 'Данные производителей', - 'MaskedAreas' => 'Ðеактивные облаÑти', - 'MaxAperture' => 'МакÑ. диафрагма объектива', - 'MeteringMode' => { - Description => 'ЭкÑпозамер', + 'Reserved5' => 'Зарезервировано 5', + 'Resolution' => 'Разрешение изображениÑ', + 'ResolutionUnit' => { + Description => 'Единицы Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð¿Ð¾ X и Y', PrintConv => { - 'Average' => 'Средний', - 'Center-weighted average' => 'Центрально-взвешенный Ñредний', - 'Multi-segment' => 'Узор', - 'Multi-spot' => 'Многозональный', - 'Other' => 'Другое', - 'Partial' => 'ЧаÑтичный', - 'Spot' => 'Точечный', - 'Unknown' => 'неизвеÑтно', + 'None' => 'Ðе указаны', + 'cm' => 'Ñм', + 'inches' => 'дюймы', }, }, - 'Model' => 'Камера', - 'ModifyDate' => '"Файл, изменить дату и времÑ"', - 'MultiFrameNoiseReduction' => { - Description => 'Многокадр. шумоподавл.', + 'ResourceCount' => 'КоличеÑтво реÑурÑов', + 'ResourceForkSize' => 'Размер Ñ€Ð°Ð·Ð²ÐµÑ‚Ð²Ð»ÐµÐ½Ð¸Ñ Ñ€ÐµÑурÑа', + 'ResourceID' => 'ID реÑурÑа', + 'ResourceRelationship' => 'СвÑзи реÑурÑов', + 'ResourceRelationshipID' => 'ID ÑвÑзи между реÑурÑами', + 'ResourceType' => 'Тип реÑурÑа', + 'Resources' => 'РеÑурÑÑ‹', + 'RetailPrice' => 'Ð Ð¾Ð·Ð½Ð¸Ñ‡Ð½Ð°Ñ Ñ†ÐµÐ½Ð°', + 'RetailPriceCurrency' => 'Валюта розничной цены', + 'Reuse' => { + Description => 'Повторное иÑпользование', PrintConv => { - 'Off' => 'Отключено', - 'On' => 'Включено', + 'Not Applicable' => 'Запрещено', + 'Repeat Use' => 'Разрешено', }, }, - 'NoiseReduction' => 'Шумоподавление', - 'NoiseReductionApplied' => 'Применённое шумоподавление', - 'Opto-ElectricConvFactor' => 'Фактор оптико-ÑлектричеÑкого преобразованиÑ', - 'Orientation' => { - Description => 'ОриентациÑ', + 'Review' => 'Обзор', + 'Revision' => 'Дата Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ vCard', + 'RevisionDate' => 'Дата ревизии', + 'RevisionNumber' => 'КоличеÑтво редакций файла', + 'RevisitAfter' => 'Повторно поÑетить через', + 'RicohPitch' => 'Ricoh – Тангаж (Ðаклон)', + 'RicohRoll' => 'Ricoh – Крен (Вращение)', + 'RightAlbedo' => 'Правильное ÑтереоÑкопичеÑкое изображение', + 'Rights' => 'Права', + 'Robots' => 'Политика обработки Ñтраницы роботами', + 'Roll' => 'Крен (Вращение)', + 'RollAngle' => 'Угол Ð²Ñ€Ð°Ñ‰ÐµÐ½Ð¸Ñ (Крен)', + 'RootDirectoryCreateDate' => 'Дата ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ ÐºÐ¾Ñ€Ð½ÐµÐ²Ð¾Ð³Ð¾ каталога', + 'Rotation' => 'Вращение', + 'RoundTripVersion' => 'ВерÑÐ¸Ñ Round Trip', + 'Routing' => 'Роутинг', + 'RoutingDestinations' => 'Ðазначение маршрутизации', + 'RoutingExclusions' => 'ИÑÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð¼Ð°Ñ€ÑˆÑ€ÑƒÑ‚Ð¸Ð·Ð°Ñ†Ð¸Ð¸', + 'RowInterleaveFactor' => 'КоÑффициент Ñ‡ÐµÑ€ÐµÐ´Ð¾Ð²Ð°Ð½Ð¸Ñ Ñтрок', + 'RowsPerStrip' => 'КоличеÑтво Ñтрок на полоÑу', + 'RtkFlag' => 'Rtk – Флаг', + 'RtkStdHgt' => 'Rtk – Стандартное отклонение выÑоты', + 'RtkStdLat' => 'Rtk – Стандартное отклонение широты', + 'RtkStdLon' => 'Rtk – Стандартное отклонение долготы', + 'RunTimeEpoch' => 'Ð’Ñ€ÐµÐ¼Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ â€“ Ðомер Ñпохи', + 'RunTimeFlags' => { + Description => 'Ð’Ñ€ÐµÐ¼Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ â€“ Флаги', PrintConv => { - 'Horizontal (normal)' => 'Положительное направление', - 'Rotate 180' => 'Поворот на 180°', - 'Rotate 270 CW' => 'Поворот на 270° по чаÑовой Ñтрелке', - 'Rotate 90 CW' => 'Поворот на 90° по чаÑовой Ñтрелке', + 'Has been rounded' => 'Округленное времÑ', + 'Indefinite' => 'Ðеопределённое времÑ', + 'Negative infinity' => 'ÐœÐ¸Ð½ÑƒÑ Ð±ÐµÑконечноÑÑ‚ÑŒ', + 'Positive infinity' => 'ÐŸÐ»ÑŽÑ Ð±ÐµÑконечноÑÑ‚ÑŒ', + 'Valid' => 'ДейÑтвительное времÑ', }, }, - 'OriginalRawFileData' => 'ИÑходные данные raw-файла', - 'OriginalRawFileDigest' => 'Сигнатура иÑходного Raw-файла', - 'OriginalRawFileName' => 'ИÑходное Ð¸Ð¼Ñ Raw-файла', - 'PhotometricInterpretation' => 'СоÑтав пикÑела', - 'PlanarConfiguration' => { - Description => 'ÐžÑ€Ð³Ð°Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð´Ð°Ð½Ð½Ñ‹Ñ… изображениÑ', + 'RunTimeScale' => 'Ð’Ñ€ÐµÐ¼Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ â€“ Шкала времени', + 'RunTimeSincePowerUp' => 'Ð’Ñ€ÐµÐ¼Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ Ñ Ð¼Ð¾Ð¼ÐµÐ½Ñ‚Ð° включениÑ', + 'RunTimeValue' => 'Ð’Ñ€ÐµÐ¼Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ â€“ Значение', + 'RunWindow' => { + Description => 'ЗапуÑтить окно', PrintConv => { - 'Chunky' => 'крупный формат', - 'Planar' => 'планарный формат', + 'Hide' => 'Скрытый', + 'Minimized' => 'Минимизировать', + 'Normal' => 'Обычный', + 'Restore' => 'ВоÑÑтановить', + 'Show' => 'Показывать', + 'Show Default' => 'Отображать по-умолчанию', + 'Show Maximized' => 'Отображать развёрнутым', + 'Show Minimized' => 'Отображать Ñвернутым', + 'Show Minimized No Activate' => 'Отображать Ñвернутым и не активвным', + 'Show No Activate' => 'Отображать', }, }, - 'PreviewApplicationName' => 'Ð˜Ð¼Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€ÐµÐ´Ð¿Ñ€Ð¾Ñмотра', - 'PreviewApplicationVersion' => 'ВерÑÐ¸Ñ Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ñ€ÐµÐ´Ð¿Ñ€Ð¾Ñмотра', - 'PreviewColorSpace' => { - Description => 'Цветовое проÑтранÑтво предпроÑмотра', + 'SEMInfo' => 'SEM – ОпиÑание', + 'SIUnits' => 'Единицы SI', + 'SMaxSampleValue' => 'МакÑимальное значение компонента', + 'SMinSampleValue' => 'Минимальное значение компонента', + 'SRGBRendering' => { + Description => 'SRGB-рендеринг', PrintConv => { - 'Unknown' => 'ÐеизвеÑтно', + 'Absolute Colorimetric' => 'ÐбÑолютно колориметричеÑкий', + 'Perceptual' => 'Перцепционный', + 'Relative Colorimetric' => 'ОтноÑительно колориметричеÑкий', + 'Saturation' => 'ÐаÑыщенный', }, }, - 'PreviewDateTime' => 'Дата и Ð²Ñ€ÐµÐ¼Ñ Ð¿Ñ€ÐµÐ´Ð¿Ñ€Ð¾Ñмотра', - 'PreviewSettingsDigest' => 'Сигнатура наÑтроек предпроÑмотра', - 'PreviewSettingsName' => 'Ðазвание наÑтроек предпроÑмотра', - 'PrimaryChromaticities' => 'ТональноÑÑ‚ÑŒ оÑновных цветов', - 'ProfileCalibrationSig' => 'Сигнатура калибровки профилÑ', - 'ProfileCopyright' => 'ÐвторÑкие права профилÑ', - 'ProfileEmbedPolicy' => { - Description => 'Политика Ð²Ð½ÐµÐ´Ñ€ÐµÐ½Ð¸Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ', + 'SRawType' => 'Тип SRaw', + 'SampleFlag' => 'Флаг образца', + 'SampleFormat' => { + Description => 'Формат компонента', PrintConv => { - 'Allow Copying' => 'Разрешено копирование', - 'Embed if Used' => 'Внедрить еÑли иÑпользован', - 'Never Embed' => 'Ðикогда не внедрÑÑ‚ÑŒ', - 'No Restrictions' => 'Ðет ограничений', + 'Complex float' => 'КомплекÑные данные Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой IEEE', + 'Complex int' => 'КомплекÑные целые данные', + 'Float' => 'Данные Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой IEEE', + 'Signed' => 'ЦелочиÑленные данные Ñо знаком', + 'Undefined' => 'Ðеопределенный формат данных', + 'Unsigned' => 'Беззнаковые целочиÑленные данные', }, }, - 'ProfileHueSatMapData1' => 'Даные Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¾Ñ‚Ñ‚ÐµÐ½ÐºÐ°/наÑыщенноÑти â„–1', - 'ProfileHueSatMapData2' => 'Даные Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¾Ñ‚Ñ‚ÐµÐ½ÐºÐ°/наÑыщенноÑти â„–2', - 'ProfileHueSatMapDims' => 'КоличеÑтво образцов оттенков', - 'ProfileLookTableData' => 'Данные таблицы проÑмотра', - 'ProfileLookTableDims' => 'КоличеÑтво образцов оттенков', - 'ProfileName' => 'Ð˜Ð¼Ñ Ð¿Ñ€Ð¾Ñ„Ð¸Ð»Ñ', - 'ProfileToneCurve' => 'ÐšÑ€Ð¸Ð²Ð°Ñ ÑрокÑти профилÑ', - 'Province-State' => 'ОблаÑÑ‚ÑŒ/район', - 'Quality' => { - Description => 'КачеÑтво изображениÑ', + 'SampleRate' => 'ЧаÑтота диÑкретизации', + 'SampleRate2' => 'ЧаÑтота диÑкретизации 2', + 'SampleSize' => 'Размер', + 'SampleStructure' => { + Description => 'Структура компонента', PrintConv => { - 'Compressed RAW' => 'cRAW', - 'Compressed RAW + JPEG' => 'cRAW+JPEG', - 'Extra Fine' => 'СверхвыÑокое', - 'Fine' => 'Ð’Ñ‹Ñокое', - 'Low' => 'Ðизкое качеÑтво', - 'Normal' => 'Стандартное качеÑтво', - 'RAW + JPEG' => 'RAW+JPEG', - 'Standard' => 'Стандартное', + 'CompressionDependent' => 'ЗавиÑÐ¸Ð¼Ð°Ñ Ð¾Ñ‚ ÑжатиÑ', + 'Orthogonal4-2-2Sampling' => 'ÐžÑ€Ñ‚Ð¾Ð³Ð¾Ð½Ð°Ð»ÑŒÐ½Ð°Ñ Ñ Ñ‡Ð°Ñтотами диÑкретизации в Ñоотношении 4: 2: 2: (4)', + 'OrthogonalConstangSampling' => 'ÐžÑ€Ñ‚Ð¾Ð³Ð¾Ð½Ð°Ð»ÑŒÐ½Ð°Ñ Ñ Ñ‚ÐµÐ¼Ð¸ же отноÑительными чаÑтотами диÑкретизации в каждом компоненте', }, }, - 'RawDataUniqueID' => 'Уникальный идентификатор файла', - 'RawImageDigest' => 'Сигнатура RAW-файла', - 'RecordMode' => 'Режим запиÑи', - 'ReductionMatrix1' => 'Матрица редукции â„–1', - 'ReductionMatrix2' => 'Матрица редукции 2', - 'ReferenceBlackWhite' => 'Пара опорных значений черного и белого', - 'RelatedImageFileFormat' => 'Формат файла ÑвÑзанного Ñнимка', - 'RelatedImageHeight' => 'Длина ÑвÑзанного Ñнимка', - 'RelatedImageWidth' => 'Ширина ÑвÑзанного Ñнимка', - 'RelatedSoundFile' => 'СвÑзанный аудио-файл', - 'ResolutionUnit' => { - Description => 'Элемент Ñ€Ð°Ð·Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð¿Ð¾ X и Y', + 'SampleText' => 'Пример текÑта', + 'SamplesPerPixel' => 'КоличеÑтво компонентов на пикÑель', + 'SamsungRawByteOrder' => 'Samsung RAW – ПорÑдок байтов', + 'SamsungRawPointersLength' => 'Samsung RAW – Длина указателей', + 'SamsungRawPointersOffset' => 'Samsung RAW – Смещение указателей', + 'SamsungRawUnknown' => 'Samsung RAW – ÐеизвеÑтно', + 'SanyoQuality' => { + Description => 'Sanyo – КачеÑтво', PrintConv => { - 'cm' => 'Ñантиметры', - 'inches' => 'дюймы', + 'Fine/High' => 'Хорошее/Ð’Ñ‹Ñокое', + 'Fine/Low' => 'Хорошее/Ðизкое', + 'Fine/Medium' => 'Хорошее/Среднее', + 'Fine/Medium High' => 'Хорошее/Выше Ñреднего', + 'Fine/Medium Low' => 'Хорошее/Ðиже Ñреднего', + 'Fine/Super High' => 'Хорошее/Лучшее', + 'Fine/Very High' => 'Хорошее/Очень выÑокое', + 'Fine/Very Low' => 'Хорошее/Очень низкое', + 'Normal/High' => 'Ðормальное/Ð’Ñ‹Ñокое', + 'Normal/Low' => 'Ðормальное/Ðизкое', + 'Normal/Medium' => 'Ðормальное/Среднее', + 'Normal/Medium High' => 'Ðормальное/Выше Ñреднего', + 'Normal/Medium Low' => 'Ðормальное/Ðиже Ñреднего', + 'Normal/Super High' => 'Ðормальное/Лучшее', + 'Normal/Very High' => 'Ðормальное/Очень выÑокое', + 'Normal/Very Low' => 'Ðормальное/Очень низкое', + 'Super Fine/High' => 'Лучшее/Ð’Ñ‹Ñокое', + 'Super Fine/Low' => 'Лучшее/Ðизкое', + 'Super Fine/Medium' => 'Лучшее/Среднее', + 'Super Fine/Medium High' => 'Лучшее/Выше Ñреднего', + 'Super Fine/Medium Low' => 'Лучшее/Ðиже Ñреднего', + 'Super Fine/Super High' => 'Лучшее/Лучшее', + 'Super Fine/Very High' => 'Лучшее/Очень выÑокое', + 'Super Fine/Very Low' => 'Лучшее/Очень низкое', }, }, - 'RowInterleaveFactor' => 'Ширина Ñ‡ÐµÑ€ÐµÐ´Ð¾Ð²Ð°Ð½Ð¸Ñ Ñтрок', - 'RowsPerStrip' => 'ЧиÑло Ñ€Ñдов в полоÑе', - 'SamplesPerPixel' => 'КоличеÑтво компонентов', + 'SanyoThumbnail' => 'Sanyo – Миниатюра', 'Saturation' => { Description => 'ÐаÑыщенноÑÑ‚ÑŒ', PrintConv => { - 'High' => 'Ð’Ñ‹ÑÐ¾ÐºÐ°Ñ Ð½Ð°ÑыщенноÑÑ‚ÑŒ', - 'Low' => 'ÐÐ¸Ð·ÐºÐ°Ñ Ð½Ð°ÑыщенноÑÑ‚ÑŒ', - 'Normal' => 'Стандартный', + 'High' => 'Ð’Ñ‹ÑокаÑ', + 'Low' => 'ÐизкаÑ', + 'Normal' => 'СтандартнаÑ', }, }, + 'SaturationAdj' => 'Регулировка наÑыщенноÑти', + 'ScaleFactor' => 'КоÑффициент маÑштабированиÑ', + 'ScaleFactor35efl' => 'КоÑффициент маÑÑˆÑ‚Ð°Ð±Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ðº 35-мм формату', + 'ScaledIMU' => 'МаÑштабируемый IMU', + 'ScaledPressure' => 'ВычиÑленное давление', + 'ScalingFactor' => 'КоÑффициент маÑштабированиÑ', + 'ScanningDirection' => { + Description => 'Ðаправление ÑканированиÑ', + PrintConv => { + 'Bottom-Top, L-R' => 'Снизу вверх, Ñлева направо', + 'Bottom-Top, R-L' => 'Снизу вверх, Ñправа налево', + 'L-R, Bottom-Top' => 'Слева направо, Ñнизу вверх', + 'L-R, Top-Bottom' => 'Слева направо, Ñверху вниз', + 'R-L, Bottom-Top' => 'Справа налево, Ñнизу вверх', + 'R-L, Top-Bottom' => 'Справа налево, Ñверху вниз', + 'Top-Bottom, L-R' => 'Сверху вниз, Ñлева направо', + 'Top-Bottom, R-L' => 'Сверху вниз, Ñправа налево', + }, + }, + 'Scene' => 'Ðомер изображениÑ', 'SceneCaptureType' => { - Description => 'Ð¡ÑŽÐ¶ÐµÑ‚Ð½Ð°Ñ Ð¿Ñ€Ð¾Ð³Ñ€Ð°Ð¼Ð¼Ð°', + Description => 'Тип Ñнимаемой Ñцены', PrintConv => { 'Landscape' => 'Пейзаж', - 'Night' => 'ÐÐ¾Ñ‡Ð½Ð°Ñ Ñъемка', + 'Night' => 'ÐÐ¾Ñ‡Ð½Ð°Ñ Ñъёмка', + 'Other' => 'Другой', 'Portrait' => 'Портрет', - 'Standard' => 'Стандартный', + 'Standard' => 'Стандартный режим', }, }, 'SceneMode' => { Description => 'Выбор Ñцены', PrintConv => { '3D Sweep Panorama' => '3D', - 'Anti Motion Blur' => 'УÑÑ‚Ñ€. размыт. движ.', + 'Anti Motion Blur' => 'УÑтранение ÑмазываниÑ', 'Auto' => 'Ðвто', - 'Cont. Priority AE' => 'Ðепрер. приор. ÐЭ', - 'Handheld Night Shot' => 'ÐÐ¾Ñ‡Ð½Ð°Ñ Ñъемка Ñ Ñ€ÑƒÐº', + 'Cont. Priority AE' => 'ÐвтоÑкÑÐ¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ñ Ð¿Ñ€Ð¸Ð¾Ñ€Ð¸Ñ‚ÐµÑ‚Ð¾Ð¼ Ñерийной Ñъёмки', + 'Handheld Night Shot' => 'ÐÐ¾Ñ‡Ð½Ð°Ñ Ñъёмка Ñ Ñ€ÑƒÐº', 'Landscape' => 'Пейзаж', 'Macro' => 'МакроÑъёмка', 'Night Portrait' => 'Ðочной портрет', @@ -624,75 +4836,742 @@ $VERSION = '1.04'; 'Sweep Panorama' => 'Панорамный обзор', }, }, + 'SceneSelect' => { + Description => 'Выбор Ñцены', + PrintConv => { + 'Lamp' => 'Лампа', + 'Night' => 'Ðочь', + 'Off' => 'Ðе задейÑтвован', + 'Sport' => 'Спорт', + 'User 1' => 'ПользовательÑÐºÐ°Ñ 1', + 'User 2' => 'ПользовательÑÐºÐ°Ñ 2', + }, + }, 'SceneType' => { - Description => 'Тип Ñюжета', + Description => 'Тип Ñцены', + PrintConv => { + 'Directly photographed' => 'Сфотографировано цифровой камерой', + }, + }, + 'School' => 'Школа', + 'ScreenBufferSize' => 'Размер буфера Ñкрана', + 'ScreenHeight' => 'Ð’Ñ‹Ñота Ñкрана', + 'ScreenWidth' => 'Ширина Ñкрана', + 'ScreenWindowCenter' => 'Окно по центру Ñкрана', + 'ScreenWindowWidth' => 'Окно по ширине Ñкрана', + 'SecondaryFTP' => 'Дополнительный FTP', + 'SecurityClassification' => { + Description => 'КлаÑÑÐ¸Ñ„Ð¸ÐºÐ°Ñ†Ð¸Ñ Ð±ÐµÐ·Ð¾Ð¿Ð°ÑноÑти', + PrintConv => { + 'Confidential' => 'Личное', + 'Restricted' => 'Ð”Ð»Ñ ÑƒÐ·ÐºÐ¾Ð³Ð¾ круга', + 'Secret' => 'Секретно', + 'Top Secret' => 'Совершенно Ñекретно', + 'Unclassified' => 'Без клаÑÑификации', + }, + }, + 'SeekTable' => 'Таблица поиÑка', + 'SelfData' => 'СобÑтвенные данные', + 'SelfTimer' => { + Description => 'Режим автоÑпуÑка затвора', PrintConv => { - 'Directly photographed' => 'ÐепоÑредÑтвенно полученный Ñнимок', + 'Off' => 'Ðе задейÑтвован', + 'On' => 'Включен', }, }, + 'SelfTimerMode' => 'Режим таймера ÑпуÑка затвора', 'SensingMethod' => { - Description => 'Метод региÑтрации', + Description => 'Тип датчика', + PrintConv => { + 'Color sequential area' => 'Цветной поÑледовательный ÑенÑор', + 'Color sequential linear' => 'Цветной поÑледовательный линейный ÑенÑор', + 'Monochrome area' => 'Монохромный ÑенÑор', + 'Monochrome linear' => 'Монохромный линейный ÑенÑор', + 'Not defined' => 'Ðе опредеен', + 'One-chip color area' => 'Одночиповый цветной ÑенÑор', + 'Three-chip color area' => 'Трехчиповый цветной ÑенÑор', + 'Trilinear' => 'Трехлинейный цветной ÑенÑор', + 'Two-chip color area' => 'Двухчиповый цветной ÑенÑор', + }, + }, + 'SensitivityType' => { + Description => 'Тип чувÑтвительноÑти', + PrintConv => { + 'ISO Speed' => 'ЧувÑтвительноÑÑ‚ÑŒ ISO', + 'Recommended Exposure Index' => 'Рекомендуемый Ð¸Ð½Ð´ÐµÐºÑ ÑкÑпозиции', + 'Recommended Exposure Index and ISO Speed' => 'Рекомендуемый Ð¸Ð½Ð´ÐµÐºÑ ÑкÑпозиции и ISO', + 'Standard Output Sensitivity' => 'Ð¡Ñ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð°Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð½Ð°Ñ Ñ‡ÑƒÐ²ÑтвительноÑÑ‚ÑŒ', + 'Standard Output Sensitivity and ISO Speed' => 'Ð¡Ñ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð°Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð½Ð°Ñ Ñ‡ÑƒÐ²ÑтвительноÑÑ‚ÑŒ и ISO', + 'Standard Output Sensitivity and Recommended Exposure Index' => 'Ð¡Ñ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð°Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð½Ð°Ñ Ñ‡ÑƒÐ²ÑтвительноÑÑ‚ÑŒ и рекомендуемый Ð¸Ð½Ð´ÐµÐºÑ ÑкÑпозиции', + 'Standard Output Sensitivity, Recommended Exposure Index and ISO Speed' => 'Ð¡Ñ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð°Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð½Ð°Ñ Ñ‡ÑƒÐ²ÑтвительноÑÑ‚ÑŒ и рекомендуемый Ð¸Ð½Ð´ÐµÐºÑ ÑкÑпозиции и ISO', + 'Unknown' => 'ÐеизвеÑтно', + }, + }, + 'Sensor' => 'СенÑор', + 'SensorBottomBorder' => 'ÐижнÑÑ Ð³Ñ€Ð°Ð½Ð¸Ñ†Ð° ÑенÑора', + 'SensorCalibration_0x0404' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ ÑенÑора 0x0404', + 'SensorCalibration_0x0405' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ ÑенÑора 0x0405', + 'SensorCalibration_0x0406' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ ÑенÑора 0x0406', + 'SensorCalibration_0x0408' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ ÑенÑора 0x0408', + 'SensorCalibration_0x040f' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ ÑенÑора 0x040f', + 'SensorCalibration_0x0413' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ ÑенÑора 0x0413', + 'SensorCalibration_0x0414' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ ÑенÑора 0x0414', + 'SensorCalibration_0x0418' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ ÑенÑора 0x0418', + 'SensorCalibration_0x041c' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ ÑенÑора 0x041c', + 'SensorCalibration_0x041e' => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ ÑенÑора 0x041e', + 'SensorDefects' => 'Дефекты ÑенÑора', + 'SensorHeight' => 'Ð’Ñ‹Ñота ÑенÑора', + 'SensorLeftBorder' => 'Ð›ÐµÐ²Ð°Ñ Ð³Ñ€Ð°Ð½Ð¸Ñ†Ð° ÑенÑора', + 'SensorLeftMargin' => 'Матрица – ОтÑтуп Ñлева', + 'SensorRightBorder' => 'ÐŸÑ€Ð°Ð²Ð°Ñ Ð³Ñ€Ð°Ð½Ð¸Ñ†Ð° ÑенÑора', + 'SensorSerialNumber' => 'Серийный номер ÑенÑора', + 'SensorTemperature' => 'Датчик температуры', + 'SensorTemperature2' => 'Датчик температуры 2', + 'SensorTopBorder' => 'ВерхнÑÑ Ð³Ñ€Ð°Ð½Ð¸Ñ†Ð° ÑенÑора', + 'SensorTopMargin' => 'Матрица – ОтÑтуп Ñправа', + 'SensorWidth' => 'Ширина ÑенÑора', + 'Sequence' => 'ПоÑледовательноÑÑ‚ÑŒ', + 'SequenceNumber' => 'ПорÑдковый номер', + 'SequenceShotInterval' => { + Description => 'Интервал поÑледовательных Ñнимков', + PrintConv => { + '10 frames/s' => '10 кадров/Ñ', + '15 frames/s' => '15 кадров/Ñ', + '20 frames/s' => '20 кадров/Ñ', + '5 frames/s' => '5 кадров/Ñ', + }, + }, + 'SequentialShot' => { + Description => 'ПоÑледовательноÑÑ‚ÑŒ Ñнимков', PrintConv => { - 'Color sequential area' => 'ПоÑледовательный ÑенÑор цветовой облаÑти', - 'Color sequential linear' => 'ПоÑледовательный линейный цветовой ÑенÑор', - 'One-chip color area' => 'ОднопроцеÑÑорный ÑенÑор цветовой облаÑти', - 'Three-chip color area' => 'ТрехпроцеÑÑорный ÑенÑор цветовой облаÑти', - 'Trilinear' => 'Трехлинейный цветовой ÑенÑор', - 'Two-chip color area' => 'ДвухпроцеÑÑорный ÑенÑор цветовой облаÑти', + 'Adjust Exposure' => 'По Ñдвигу ÑкÑпозиции', + 'Best' => 'Лучший Ñнимок', + 'None' => 'Ðет', + 'Standard' => 'СтандартнаÑ', }, }, - 'SerialNumber' => 'ID-код фотокамеры', + 'SerialNumber' => 'Серийный номер камеры', + 'Series' => 'СериÑ', + 'SeriesDateTime' => 'Дата Ñерии', + 'SeriesDescription' => 'ОпиÑание Ñрии', + 'SeriesModality' => 'МодальноÑÑ‚ÑŒ Ñерии', + 'SeriesNumber' => 'Ðомер Ñерии', + 'ServiceID' => 'ID ÑервиÑа', + 'ServiceIdentifier' => 'Идентификатор поÑтавщика и продукта', + 'SetCookie' => 'ÐаÑтройки cookie', 'ShadingCompensation' => 'УÑтранение теней', 'ShadowScale' => 'Диапазон теней', + 'Shadows' => 'Тени', + 'ShadowsAdj' => 'Регулировка теней', + 'SharedData' => 'Общие данные', 'Sharpness' => { Description => 'РезкоÑÑ‚ÑŒ', PrintConv => { - 'Hard' => 'Резкий', - 'Normal' => 'Стандартный', - 'Soft' => 'ÐœÑгкий', + 'Hard' => 'СильнаÑ', + 'Normal' => 'СтандартнаÑ', + 'Soft' => 'СлабаÑ', + }, + }, + 'SharpnessAdj' => 'Регулировка резкоÑтти', + 'SharpnessOvershoot' => 'РезкоÑÑ‚ÑŒ – Положительное отклонение', + 'SharpnessThreshold' => 'РезкоÑÑ‚ÑŒ – Порог', + 'SharpnessUndershoot' => 'РезкоÑÑ‚ÑŒ – Отрицательное отклонение', + 'ShootingCount' => 'КоличеÑтво Ñнимков Ñ Ð¾Ð±ÐµÐ¸Ñ… точек проÑмотра', + 'ShootingMode' => 'Режим Ñъёмки', + 'ShortDocumentID' => 'Краткий ID документа', + 'ShutterCurtainHack' => { + Description => 'Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ ÑˆÑ‚Ð¾Ñ€ÐºÐ¸ затвора', + PrintConv => { + '1st-curtain sync' => 'Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ð¾ 1-й шторке', + '2nd-curtain sync' => 'Ð¡Ð¸Ð½Ñ…Ñ€Ð¾Ð½Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¿Ð¾ 2-й шторке', + }, + }, + 'ShutterSpeed' => 'СкороÑÑ‚ÑŒ ÑÑ€Ð°Ð±Ð°Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð·Ð°Ñ‚Ð²Ð¾Ñ€Ð°', + 'ShutterSpeedValue' => 'СкороÑÑ‚ÑŒ ÑÑ€Ð°Ð±Ð°Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ð·Ð°Ñ‚Ð²Ð¾Ñ€Ð°', + 'Sidebars' => 'КоличеÑтво боковых панелей', + 'SidecarForExtension' => 'РаÑширение файла', + 'Signature' => 'ПодпиÑÑŒ', + 'SignatureUsageRights' => 'Права на иÑпользование ПодпиÑи', + 'SignerContactInfo' => 'Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ – ÐšÐ¾Ð½Ñ‚Ð°ÐºÑ‚Ð½Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ', + 'SignificantBits' => 'Старшие биты', + 'SigningAuthority' => 'Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ – Орган', + 'SigningDate' => 'Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ – Дата подпиÑи', + 'SigningLocation' => 'Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ – МеÑтоположение', + 'SigningReason' => 'Ð­Ð»ÐµÐºÑ‚Ñ€Ð¾Ð½Ð½Ð°Ñ Ð¿Ð¾Ð´Ð¿Ð¸ÑÑŒ – Причина подпиÑаниÑ', + 'SimilarityIndex' => 'Ð˜Ð½Ð´ÐµÐºÑ ÑходÑтва', + 'Site' => 'Сайт', + 'SiteEnter' => 'Эффект при заходе на Ñайт', + 'SiteExit' => 'Эффект при уходе Ñ Ñайта', + 'SizeMode' => { + Description => 'Режим размера', + PrintConv => { + 'Size Known' => 'Размер извеÑтный', + 'Size Not Known' => 'Размер не извеÑтен', + }, + }, + 'SlateInformation' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ Slate', + 'SlicesGroupName' => 'Ðазвание группы фрагментов', + 'Smoothness' => 'Сглаживание', + 'Snapshots' => 'Скриншоты', + 'SocTemperature' => 'Температура на чипе (Soc)', + 'SocialProfile' => 'Социальный профиль', + 'Software' => { + Description => 'Приложение', + PrintConv => { + 'PC Paintbrush 2.8 (with palette)' => 'PC Paintbrush 2.8 (Ñ Ð¿Ð°Ð»Ð¸Ñ‚Ñ€Ð¾Ð¹)', + 'PC Paintbrush 2.8 (without palette)' => 'PC Paintbrush 2.8 (без палитры)', + 'PC Paintbrush for Windows' => 'PC Paintbrush Ð´Ð»Ñ Windows', + }, + }, + 'SoftwareVersion' => 'ВерÑÐ¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ', + 'SonyCropSize' => 'Sony – Размер рамки кадрированиÑ', + 'SonyCropTopLeft' => 'Sony – Верхний левый угол рамки кадрированиÑ', + 'SonyRawFileType' => { + Description => 'Sony – Тип RAW-файла', + PrintConv => { + 'Sony Compressed RAW' => 'Sony – Ñжатый RAW', + 'Sony Lossless Compressed RAW' => 'Sony – Ñжатый без потерь RAW', + 'Sony Uncompressed 12-bit RAW' => 'Sony – 12-битный неÑжатый RAW', + 'Sony Uncompressed 14-bit RAW' => 'Sony – 14-битный неÑжатый RAW', }, }, - 'ShootingMode' => 'Режим Ñъемки', - 'ShutterSpeed' => 'Выдержка', - 'ShutterSpeedValue' => 'Выдержка', - 'Software' => 'Ð˜Ð¼Ñ Ð¸ верÑÐ¸Ñ ÐŸÐž', + 'SonyToneCurve' => 'Sony – Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ', + 'Sound' => 'ЗвукозапиÑÑŒ', 'Source' => 'ИÑточник', - 'SpatialFrequencyResponse' => 'ПроÑтранÑÑ‚Ð²ÐµÐ½Ð½Ð°Ñ Ñ‡Ð°ÑÑ‚Ð¾Ñ‚Ð½Ð°Ñ Ñ…Ð°Ñ€Ð°ÐºÑ‚ÐµÑ€Ð¸Ñтика', + 'SourceCount' => 'КоличеÑтво иÑпользованых камер', + 'SourceCreateDate' => 'ИÑÑ…Ð¾Ð´Ð½Ð°Ñ Ð´Ð°Ñ‚Ð° ÑозданиÑ', + 'SourceData' => 'ИÑходные данные', + 'SourceDate' => 'Дата публикации', + 'SourceEdition' => 'Печатное издание', + 'SourceFileName' => 'Ðазвание иÑходного файла', + 'SourcePhotosCount' => 'КоличеÑтво иÑходных изображений', + 'SourcePublisher' => 'ИздательÑтво', + 'SourceRights' => 'Права печатного изданиÑ', + 'SourceTitle' => 'Ðазвание издательÑтва', + 'SpatialFrequencyResponse' => 'Отклик проÑтранÑтвенной чаÑтоты', + 'SpatialResolution' => 'ПроÑтранÑтвенное разрешение', + 'SpecialInstructions' => 'Специальные указаниÑ', + 'SpecialMode' => 'Специальный режим', + 'SpecialTypeID' => 'ID Ñпециального типа', 'SpectralSensitivity' => 'Ð¡Ð¿ÐµÐºÑ‚Ñ€Ð°Ð»ÑŒÐ½Ð°Ñ Ñ‡ÑƒÐ²ÑтвительноÑÑ‚ÑŒ', + 'SpeedX' => 'СкороÑÑ‚ÑŒ по оÑи X', + 'SpeedY' => 'СкороÑÑ‚ÑŒ по оÑи Y', + 'SpeedZ' => 'СкороÑÑ‚ÑŒ по оÑи Z', + 'Spherical' => 'СферичеÑкое видео', + 'SplitColumn' => 'Ð Ð°Ð·Ð´ÐµÐ»ÐµÐ½Ð½Ð°Ñ ÐºÐ¾Ð»Ð¾Ð½ÐºÐ°', + 'SpotHalftone' => 'Точка полутона', + 'StandardOutputSensitivity' => 'Ð¡Ñ‚Ð°Ð½Ð´Ð°Ñ€Ñ‚Ð½Ð°Ñ Ð²Ñ‹Ñ…Ð¾Ð´Ð½Ð°Ñ Ñ‡ÑƒÐ²ÑтвительноÑÑ‚ÑŒ', + 'StartEdgeCode' => 'Edge код Ñтарта', + 'StartReading' => 'Ðачало чтениÑ', + 'StartTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð½Ð°Ñ‡Ð°Ð»Ð°', + 'StartTimecode' => 'Таймкод Ñтарта', 'State' => 'ОблаÑÑ‚ÑŒ', - 'StripByteCounts' => 'Байт на Ñжатую полоÑу', - 'StripOffsets' => 'РаÑположение данных изображениÑ', - 'SubSecTime' => '"Дата и времÑ, Ñуб-Ñекунды"', - 'SubSecTimeDigitized' => '"Дата и Ð²Ñ€ÐµÐ¼Ñ Ñ†Ð¸Ñ„Ñ€Ð¾Ð²Ð¾Ðµ, Ñуб-Ñекунды"', - 'SubSecTimeOriginal' => '"Дата и Ð²Ñ€ÐµÐ¼Ñ Ð¸Ñходное, Ñуб-Ñекунды"', - 'SubTileBlockSize' => 'Размер блока в тайле', + 'Status' => 'СтатуÑ', + 'Stereo' => 'Стерео', + 'StereoMode' => 'Режим Ñтерео', + 'StimVersion' => 'ВерÑÐ¸Ñ Stim', + 'Stitched' => 'Ð¡ÑˆÐ¸Ñ‚Ð°Ñ Ð²Ð¸Ð´ÐµÐ¾Ð¿Ð°Ð½Ð¾Ñ€Ð°Ð¼Ð°', + 'StitchingSoftware' => 'Сшито в программе', + 'StoNits' => 'ОÑвещенноÑÑ‚ÑŒ (коÑффициент переÑчета кд/м2)', + 'StorageFormatDate' => 'ПамÑÑ‚ÑŒ – Дата форматированиÑ', + 'StorageFormatTime' => 'ПамÑÑ‚ÑŒ – Ð’Ñ€ÐµÐ¼Ñ Ñ„Ð¾Ñ€Ð¼Ð°Ñ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ', + 'StorageMethod' => 'СпоÑоб хранениÑ', + 'StorageModel' => 'ПамÑÑ‚ÑŒ – Модель', + 'StorageSerialNumber' => 'ПамÑÑ‚ÑŒ – Серийный номер', + 'StorageType' => 'ПамÑÑ‚ÑŒ – Тип', + 'StreamAvgBitrate' => 'Средний битрейт потока', + 'StreamAvgPacketSize' => 'Размер Ñреднего битрейта потока', + 'StreamDuration' => 'ПродолжительноÑÑ‚ÑŒ потока', + 'StreamMaxBitrate' => 'МакÑимальный битрейт потока', + 'StreamMaxPacketSize' => 'Размер макÑимального битрейта потока', + 'StreamMimeLen' => 'Mime потока Len', + 'StreamMimeType' => 'Mime-тип потока', + 'StreamName' => 'Ðазвание потока', + 'StreamNameLen' => 'Ðазвание потока Len', + 'StreamNumber' => 'Ðомер потока', + 'StreamPreroll' => 'Предварительный проÑмотр потока', + 'StreamStartTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ð½Ð°Ñ‡Ð°Ð»Ð° потока', + 'StreamType' => 'Тип потока', + 'Strikeout' => 'Перечёркнутый', + 'StripByteCounts' => 'КоличеÑтво байт на полоÑу', + 'StripOffsets' => 'Смещение Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ полоÑÑ‹ изображениÑ', + 'StripRowCounts' => 'КоличеÑтво полоÑ', + 'StrobeTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ñтроба', + 'StructureType' => 'Тип конÑтрукции', + 'StudyDateTime' => 'Дата обÑледованиÑ', + 'StudyDescription' => 'ОпиÑание обÑледованиÑ', + 'StudyID' => 'ID иÑÑледованиÑ', + 'StudyPhysician' => 'Врач проводивший обÑледование', + 'Sub-location' => 'МеÑтоположение в городе', + 'SubFile' => 'Подфайл', + 'SubPacketH' => 'Субпакет H', + 'SubPacketSize' => 'Размер Ñубпакета', + 'SubSecCreateDate' => 'Дата, Ð²Ñ€ÐµÐ¼Ñ Ð¸ милиÑекунды ÑозданиÑ', + 'SubSecDateTimeOriginal' => 'ИÑходные дата, Ð²Ñ€ÐµÐ¼Ñ Ð¸ милиÑекунды ÑозданиÑ', + 'SubSecModifyDate' => 'Дата, Ð²Ñ€ÐµÐ¼Ñ Ð¸ милиÑекунды редактированиÑ', + 'SubSecTime' => 'Ð’Ñ€ÐµÐ¼Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð² милиÑекундах', + 'SubSecTimeDigitized' => 'Ð’Ñ€ÐµÐ¼Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð° в милиÑекундах', + 'SubSecTimeOriginal' => 'Ð’Ñ€ÐµÐ¼Ñ Ñъёмки в милиÑекундах', + 'SubTileBlockSize' => 'Размер блока подзаголовка', + 'SubfileType' => { + Description => 'Тип подфайла', + PrintConv => { + 'Alternate reduced-resolution image' => 'Ðльтернативное изображение Ñ Ð¿Ð¾Ð½Ð¸Ð¶ÐµÐ½Ð½Ñ‹Ð¼ разрешением', + 'Color IW44' => 'Цветной IW44', + 'Full-resolution image' => 'Изображение Ñ Ð¿Ð¾Ð»Ð½Ñ‹Ð¼ разрешением', + 'Grayscale IW44' => 'Ð“Ñ€Ð°Ð´Ð°Ñ†Ð¸Ñ Ñерого IW44', + 'Multi-page document' => 'МногоÑтраничный документ', + 'Reduced-resolution image' => 'Изображение Ñ Ð¿Ð¾Ð½Ð¸Ð¶ÐµÐ½Ð½Ñ‹Ð¼ разрешением', + 'Shared component' => 'Общий компонент', + 'Single page of multi-page image' => 'Одна Ñтраница из многоÑтраничного изображениÑ', + 'Single page of multi-page reduced-resolution image' => 'Одна Ñтраница из многоÑтраничного Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñ Ð¿Ð¾Ð½Ð¸Ð¶ÐµÐ½Ð½Ñ‹Ð¼ разрешением', + 'Single-page image' => 'ОдноÑтраничное изображение', + 'TIFF-FX mixed raster content' => 'Смешанное раÑтровое Ñодержимое TIFF-FX', + 'TIFF/IT final page' => 'ПоÑледнÑÑ Ñтраница TIFF/IT', + 'Thumbnail image' => 'Миниатюра', + 'Transparency mask' => 'МаÑка прозрачноÑти изображениÑ', + 'Transparency mask of multi-page image' => 'МаÑка прозрачноÑти многоÑтраничного изображениÑ', + 'Transparency mask of reduced-resolution image' => 'МаÑка прозрачноÑти Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñ Ð¿Ð¾Ð½Ð¸Ð¶ÐµÐ½Ð½Ñ‹Ð¼ разрешением', + 'Transparency mask of reduced-resolution multi-page image' => 'МаÑка прозрачноÑти многоÑтраничного Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ñ Ð¿Ð¾Ð½Ð¸Ð¶ÐµÐ½Ð½Ñ‹Ð¼ разрешением', + 'invalid' => 'Ðекорректный', + }, + }, + 'Subject' => 'Тема', 'SubjectArea' => 'ОблаÑÑ‚ÑŒ объекта', - 'SubjectDistance' => 'РаÑÑтоÑние до объекта', + 'SubjectCode' => 'Предметный код', + 'SubjectDistance' => 'ДиÑÑ‚Ð°Ð½Ñ†Ð¸Ñ Ðº фокуÑируемому объекту', 'SubjectDistanceRange' => { - Description => 'Диапазон раÑÑтоÑний до объекта', + Description => 'РаÑÑтоÑние до Ñнимаемого объекта', PrintConv => { - 'Close' => 'Крупный план', - 'Distant' => 'Удаленный план', - 'Macro' => 'Макро', + 'Close' => 'Съёмка Ñ Ð±Ð»Ð¸Ð·ÐºÐ¾Ð³Ð¾ раÑÑтоÑниÑ', + 'Distant' => 'Съёмка Ñ Ð´Ð°Ð»ÑŒÐ½ÐµÐ³Ð¾ раÑÑтоÑниÑ', + 'Macro' => 'Макро Ñъёмка', + 'Unknown' => 'ÐеизвеÑтно', }, }, 'SubjectLocation' => 'РаÑположение объекта', + 'SubjectPixelHeight' => 'Ð’Ñ‹Ñота объекта в пикÑелÑÑ…', + 'SubjectPixelWidth' => 'Ширина объекта в пикÑелÑÑ…', + 'SubjectReference' => 'СÑылка на предмет', + 'SubjectUnits' => { + Description => 'Единицы объекта', + PrintConv => { + 'meters' => 'Метры', + 'radians' => 'Радианы', + }, + }, + 'Subtitle' => 'Субтитры', + 'SubtitleDescription' => 'Субтитры – ОпиÑание', + 'SuggestedPalette' => 'Ð ÐµÐºÐ¾Ð¼ÐµÐ½Ð´Ð¾Ð²Ð°Ð½Ð½Ð°Ñ Ð¿Ð°Ð»Ð¸Ñ‚Ñ€Ð°', + 'Summary' => 'Резюме', 'SupplementalCategories' => 'Дополнительные категории', - 'ThumbnailImage' => 'Пиктограмма', - 'ThumbnailImageSize' => 'Размер пиктограмм', - 'Title' => 'Заголовок', + 'SupplementalType' => { + Description => 'Тип дополнениÑ', + PrintConv => { + 'Logo' => 'Логотип', + 'Main Image' => 'ОÑновное изображение', + 'Rasterized Caption' => 'РаÑтрированный заголовок', + 'Reduced Resolution Image' => 'Изображение Ñ Ð¿Ð¾Ð½Ð¸Ð¶ÐµÐ½Ð½Ñ‹Ð¼ разрешением', + }, + }, + 'SymLink' => 'СимволичеÑÐºÐ°Ñ ÑÑылка', + 'System' => 'СиÑтема', + 'SystemTime' => 'СиÑтемное времÑ', + 'T4Options' => { + Description => 'Параметры ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ T4', + PrintConv => { + '2-Dimensional encoding' => 'Двумерное кодирование', + 'Fill bits added' => 'Добавление заполнÑющих битов', + 'Uncompressed' => 'Без ÑжатиÑ', + }, + }, + 'T6Options' => { + Description => 'Параметры ÐºÐ¾Ð´Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ T6', + PrintConv => { + 'Uncompressed' => 'Без ÑжатиÑ', + }, + }, + 'T82Options' => 'Параметры T82', + 'T88Options' => 'Параметры T88', + 'TIFF-EPStandardID' => 'ID Ñтандарта TIFF-EP', + 'TIFFPreview' => 'ПредпроÑмотр TIFF', + 'TIFF_FXExtensions' => { + Description => 'Ð Ð°Ð·ÑˆÐ¸Ñ€ÐµÐ½Ð¸Ñ TIFF_FX', + PrintConv => { + 'JBIG2 Profile M' => 'JBIG2 профиль M', + 'N Layer Profile M' => 'N Ñлой Профиль M', + 'Resolution/Image Width' => 'Разрешение/Ширина изображениÑ', + 'Shared Data' => 'Общие данные', + }, + }, + 'TOCItems' => 'КоличеÑтво точек навигации', + 'TStop' => 'Ð˜Ð½Ð´ÐµÐºÑ ÑветопропуÑÐºÐ°Ð½Ð¸Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð¸Ð²Ð° (T-Stop)', + 'Tagged' => { + Description => 'Тегированный', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'TaggedPDF' => { + Description => 'Тегированный PDF', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'Take' => 'Дубль', + 'Tamper-proofKeys' => 'Ключи от взлома', + 'TargetAudiences' => 'Ð¦ÐµÐ»ÐµÐ²Ð°Ñ Ð°ÑƒÐ´Ð¸Ñ‚Ð¾Ñ€Ð¸Ñ', + 'TargetFileDOSName' => 'DOS название целевого файла', + 'TargetFileSize' => 'Размер целевого файла', + 'TargetLayerID' => 'ID целевого ÑлоÑ', + 'TargetPrinter' => 'Среда печати', + 'Tattoo' => 'Татуировка', + 'Taxon' => 'ТакÑон', + 'TaxonAcceptedNameUsage' => 'ОбщепринÑтое название такÑона', + 'TaxonAcceptedNameUsageID' => 'ID общепринÑтого Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð°ÐºÑона', + 'TaxonClass' => 'КлаÑÑ Ñ‚Ð°ÐºÑона', + 'TaxonConceptID' => 'ID такÑономичеÑкой концепции', + 'TaxonFamily' => 'СемейÑтво такÑона', + 'TaxonGenus' => 'Род такÑона', + 'TaxonHigherClassification' => 'ТакÑоны рангом выше', + 'TaxonID' => 'ID такÑона', + 'TaxonInfraspecificEpithet' => 'Ðизший внутривидовой Ñпитет', + 'TaxonKingdom' => 'ЦарÑтво такÑона', + 'TaxonNameAccordingTo' => 'ИÑточник опиÑÐ°Ð½Ð¸Ñ Ð³Ñ€Ð°Ð½Ð¸Ñ† такÑона', + 'TaxonNameAccordingToID' => 'ID иÑточника опиÑÐ°Ð½Ð¸Ñ Ð³Ñ€Ð°Ð½Ð¸Ñ† такÑона', + 'TaxonNamePublishedIn' => 'Ðазвание такÑона впервые опубликовано в', + 'TaxonNamePublishedInID' => 'ID первой публикации Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð°ÐºÑона', + 'TaxonNamePublishedInYear' => 'Год первой публикации Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð°ÐºÑона', + 'TaxonNomenclaturalCode' => 'Код номенклатуры такÑона', + 'TaxonNomenclaturalStatus' => 'Ðоменклатурный ÑÑ‚Ð°Ñ‚ÑƒÑ Ñ‚Ð°ÐºÑона', + 'TaxonOrder' => 'ПорÑдок такÑона', + 'TaxonOriginalNameUsage' => 'ПервоиÑточник Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð°ÐºÑона', + 'TaxonOriginalNameUsageID' => 'ID первоиÑточника Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð°ÐºÑона', + 'TaxonParentNameUsage' => 'РодительÑкий такÑон', + 'TaxonParentNameUsageID' => 'ID родительÑкого такÑона', + 'TaxonPhylum' => 'Тип такÑона', + 'TaxonRank' => 'Ранг такÑона', + 'TaxonRemarks' => 'Комментарии к такÑону', + 'TaxonScientificName' => 'Ðаучное название такÑона', + 'TaxonScientificNameAuthorship' => 'Ðвтор научного Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð°ÐºÑона', + 'TaxonScientificNameID' => 'ID научного Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð°ÐºÑона', + 'TaxonSpecificEpithet' => 'Видовой Ñпитет такÑона', + 'TaxonSubgenus' => 'Подрод такÑона', + 'TaxonTaxonomicStatus' => 'Ð¡Ñ‚Ð°Ñ‚ÑƒÑ Ñ‚Ð°ÐºÑона', + 'TaxonVerbatimTaxonRank' => 'Ранг такÑона по первоиÑточнику', + 'TaxonVernacularName' => 'Ðародное название такÑона', + 'Telephone' => 'Ðомер телефона', + 'Telescope' => 'ТелеÑкоп', + 'Template' => 'Шаблон', + 'TermsAndConditionsText' => 'ТекÑÑ‚ лицензионного ÑоглашениÑ', + 'TermsAndConditionsURL' => 'СÑылка на лицензионное Ñоглашение', + 'TestName' => 'ТеÑтовое название файла', + 'Text' => 'ТекÑÑ‚', + 'TextLayerName' => 'ÐÐ°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ‚ÐµÐºÑтовых Ñлоёв', + 'TextLayerText' => 'ТекÑÑ‚ текÑтового ÑлоÑ', + 'TextLayers' => 'ТекÑтовые Ñлои', + 'TextToSpeech' => { + Description => 'ТекÑÑ‚ в речь', + PrintConv => { + 'Disabled' => 'Ðе включеён', + 'Enabled' => 'Включен', + }, + }, + 'TextureFormat' => 'Формат текÑтуры', + 'TheoraVersion' => 'ВерÑÐ¸Ñ Theora', + 'Thresholding' => { + Description => 'ÐŸÐ¾Ñ€Ð¾Ð³Ð¾Ð²Ð°Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ°', + PrintConv => { + 'No dithering or halftoning' => 'Дизеринг или полутонирование не применÑлоÑÑŒ', + 'Ordered dither or halftone' => 'Заказной дизеринг или полутонирование', + 'Randomized dither' => 'Случайный дизеринг', + }, + }, + 'ThumbnailBPG' => 'Миниатюра BPG', + 'ThumbnailHeight' => 'Ð’Ñ‹Ñота миниатюры', + 'ThumbnailImage' => 'Миниатюра изображениÑ', + 'ThumbnailImageSize' => 'Размер миниатюри', + 'ThumbnailLength' => 'Строк в миниатюре', + 'ThumbnailOffset' => 'Смещение миниатюры', + 'ThumbnailTIFF' => 'TIFF миниатюра', + 'ThumbnailWidth' => 'Ширина миниатюры', + 'TileByteCounts' => 'КоличеÑтво байт в тайле', + 'TileDepth' => 'Глубина тайла', + 'TileLength' => 'Строк в тайле', + 'TileOffsets' => 'Смещение тайла', + 'TileWidth' => 'Колонок в тайле', + 'Tiles' => 'Тайлы', + 'Time' => 'ВремÑ', + 'TimeCode' => 'Код времени', + 'TimeCodes' => 'Таймкоды', + 'TimeCreated' => 'Ð’Ñ€ÐµÐ¼Ñ ÑозданиÑ', + 'TimeSent' => 'Ð’Ñ€ÐµÐ¼Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ', + 'TimeShot' => 'Ð’Ñ€ÐµÐ¼Ñ Ñъёмки', + 'TimeStamp' => 'ВременнаÌÑ Ð¼ÐµÑ‚ÐºÐ°', + 'TimeTransparency' => 'ПрозрачноÑÑ‚ÑŒ времени', + 'TimeZone' => 'ЧаÑовой поÑÑ', + 'TimeZone2' => 'ЧаÑовой поÑÑ 2', + 'TimeZoneOffset' => 'Смещение чаÑового поÑÑа', + 'TimeZoneURL' => 'URL ЧаÑового поÑÑа', + 'TimelineInfo' => 'Ð¡Ð²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ шкале времени', + 'TimezoneID' => 'ID чаÑового поÑÑа', + 'TimezoneName' => 'Ðазвание чаÑового поÑÑа', + 'TimezoneOffsetFrom' => 'Смещение чаÑового поÑÑа Ñ', + 'TimezoneOffsetTo' => 'Смещение чаÑового поÑÑа к', + 'Title' => 'Ðазвание', + 'TitleLen' => 'Ðазвание Len', + 'ToneCurveBlueX' => 'Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ â€“ Синий X', + 'ToneCurveBlueY' => 'Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ â€“ Синий Y', + 'ToneCurveBrightnessX' => 'Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ â€“ ЯркоÑÑ‚ÑŒ X', + 'ToneCurveBrightnessY' => 'Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ â€“ ЯркоÑÑ‚ÑŒ Y', + 'ToneCurveGreenX' => 'Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ â€“ Зелёный X', + 'ToneCurveGreenY' => 'Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ â€“ Зелёный Y', + 'ToneCurveRedX' => 'Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ â€“ КраÑный X', + 'ToneCurveRedY' => 'Ð¢Ð¾Ð½Ð¾Ð²Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ â€“ КраÑный Y', + 'ToolName' => 'Приложение', + 'ToolVersion' => 'ВерÑÐ¸Ñ Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ', + 'TopMargin' => 'ОтÑтуп Ñверху', + 'TotalBitrate' => 'Общий битрейт', + 'TotalDataRate' => 'ÐžÐ±Ñ‰Ð°Ñ ÑкороÑÑ‚ÑŒ передачи данных', + 'TotalDuration' => 'ÐžÐ±Ñ‰Ð°Ñ Ð¿Ñ€Ð¾Ð´Ð¾Ð»Ð¶Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð¾ÑÑ‚ÑŒ', + 'TotalEditTime' => 'Общее Ð²Ñ€ÐµÐ¼Ñ Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ', + 'TotalFrames' => 'Ð’Ñего кадров', + 'TotalSamples' => 'Ð’Ñего образцов', + 'Track' => 'Трек', + 'TrackCategory' => 'ÐšÐ°Ñ‚ÐµÐ³Ð¾Ñ€Ð¸Ñ Ñ‚Ñ€ÐµÐºÐ°', + 'TrackComments' => 'Комментарии к треку', + 'TrackID' => 'ID трека', + 'TrackLyrics' => 'ТекÑÑ‚ пеÑни', + 'TrackNumber' => 'Ðомер трека', + 'Trademark' => 'Ð¢Ð¾Ñ€Ð³Ð¾Ð²Ð°Ñ Ð¼Ð°Ñ€ÐºÐ°', 'TransferFunction' => 'Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ Ð¿ÐµÑ€ÐµÐ½Ð¾Ñа', + 'TransferRange' => 'Диапазон функции переноÑа', + 'Transformation' => { + Description => 'ТранÑформациÑ', + PrintConv => { + 'Horizontal (normal)' => 'Горизонтально', + 'Mirror horizontal' => 'Отразить по горизонтали', + 'Mirror horizontal and rotate 270 CW' => 'Отражение по горизонтали и поворот на 270° по чаÑовой Ñтрелке', + 'Mirror horizontal and rotate 90 CW' => 'Отражение по горизонтали и поворот на 90° по чаÑовой Ñтрелке', + 'Mirror vertical' => 'Отразить по вертикали', + 'Rotate 180' => 'Повернуть на 180°', + 'Rotate 270 CW' => 'Поворот на 270° по чаÑовой Ñтрелке', + 'Rotate 90 CW' => 'Поворот на 90° по чаÑовой Ñтрелке', + }, + }, 'TransmissionReference' => 'СÑылка на иÑточник', - 'UniqueCameraModel' => 'Ð£Ð½Ð¸ÐºÐ°Ð»ÑŒÐ½Ð°Ñ Ð¼Ð¾Ð´ÐµÐ»ÑŒ фотоаппарата', - 'Urgency' => 'ПриоритетноÑÑ‚ÑŒ', + 'Transparency' => 'ПрозрачноÑÑ‚ÑŒ', + 'TransparencyIndicator' => 'Ðаличие прозрачноÑти', + 'TransparentIndex' => 'Ð˜Ð½Ð´ÐµÐºÑ Ð¿Ñ€Ð¾Ð·Ñ€Ð°Ñ‡Ð½Ð¾Ñти', + 'TrapIndicator' => 'Применен ли треппинг к файлу', + 'Trapped' => 'Треппинг', + 'Trigger' => 'Ð’Ñ€ÐµÐ¼Ñ ÑÑ€Ð°Ð±Ð°Ñ‚Ñ‹Ð²Ð°Ð½Ð¸Ñ Ñигнала', + 'TriggerMode' => { + Description => 'Режим триггера', + PrintConv => { + 'CodeLoc Not Entered' => 'Код блокировки не задан', + 'External Sensor' => 'Внешний датчик', + 'Motion Detection' => 'Обнаружение движениÑ', + 'Point and Shoot' => 'Ðаведи и Ñнимай', + 'Time Lapse' => 'ТаймлапÑ', + }, + }, + 'Type' => 'Тип', + 'TypeStatus' => 'СпиÑок номенклатурных типов', + 'UIC1Tag' => 'UIC – Тег 1', + 'UIC2Tag' => 'UIC – Тег 2', + 'UIC3Tag' => 'UIC – Тег 3', + 'UIC4Tag' => 'UIC – Тег 4', + 'UID' => 'Уникальный ID', + 'URLList1' => 'СпиÑок URL 1', + 'URL_List' => 'СпиÑок URL', + 'USPTOOriginalContentType' => { + Description => 'USPTO – ИÑходный тип контента', + PrintConv => { + 'Color' => 'Цвет', + 'Grayscale' => 'Оттенки Ñерого', + 'Text or Drawing' => 'ТекÑÑ‚ или риÑунок', + }, + }, + 'UUID-Unknown' => 'ÐеизвеÑтный UUID', + 'UUIDList' => 'СпиÑок UUID', + 'Uncompressed' => { + Description => 'Ðе Ñжато', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'UncompressedSize' => 'ÐеÑжатый размер', + 'UncompressedTextLength' => 'Длина неÑжатого текÑта', + 'Underline' => 'Подчёркнутый', + 'UnderlinePosition' => 'ÐŸÐ¾Ð·Ð¸Ñ†Ð¸Ñ Ð¿Ð¾Ð´Ñ‡Ñ‘Ñ€ÐºÐ¸Ð²Ð°Ð½Ð¸Ñ', + 'UnderlineThickness' => 'Толщина подчёркиваниÑ', + 'UnicodeAlphaNames' => 'Юникодное название альфа-канала', + 'UniqueCameraModel' => 'Уникальное название модели камеры', + 'UniqueDocumentID' => 'Уникальный ID документа', + 'UniqueObjectName' => 'Уникальное название объекта', + 'Units' => { + Description => 'Единицы измерениÑ', + PrintConv => { + 'Inches' => 'Дюймы', + 'Picas' => 'Пики', + 'Points' => 'Точки', + 'mm' => 'Милиметры', + }, + }, + 'Unknown' => 'ÐеизвеÑтный', + 'UnknownDate' => 'ÐеизвеÑÑ‚Ð½Ð°Ñ Ð´Ð°Ñ‚Ð°', + 'UpdatedTitle' => 'Обновленное название', + 'Urgency' => { + Description => 'Приоритет обработки', + PrintConv => { + '0 (reserved)' => '0 (Зарезервированно)', + '1 (most urgent)' => '1 (Срочно)', + '5 (normal urgency)' => '5 (Обычный)', + '8 (least urgent)' => '8 (Ðе Ñрочно)', + '9 (user-defined priority)' => '9 (ПользовательÑкий приоритет)', + }, + }, + 'UsageRightsMessage' => 'Сообщение о правах иÑпользованиÑ', + 'UsePanoramaViewer' => 'ИÑпользовать проÑмотрщик панорам', + 'UserAccess' => { + Description => 'РазрешаетÑÑ', + PrintConv => { + 'Annotate' => 'Ðннотирование', + 'Assemble' => 'Сборка', + 'Copy' => 'Копирование', + 'Extract' => 'Извлечение', + 'Fill forms' => 'Заполнение форм', + 'Modify' => 'Редактирование', + 'Print' => 'Печать', + 'Print high-res' => 'Печать в выÑоком разрешении', + }, + }, 'UserComment' => 'Комментарии пользователÑ', + 'UserFields' => 'Дополнительное поле', + 'UserID' => 'ID пользователÑ', + 'UserLabel' => 'Ярлык пользователÑ', + 'VBRBytes' => 'Переменный битрейт – Бит', + 'VBRFrames' => 'Переменный битрейт – КоличеÑтво фреймов', + 'VBRScale' => 'Переменный битрейт – Шкала', + 'VCalendarVersion' => 'ВерÑÐ¸Ñ VCalendar', + 'VCardVersion' => 'ВерÑÐ¸Ñ VCard', + 'Vary' => 'Ðльтернативный HTTP-заголовок', + 'Vendor' => 'ПоÑтавщик', + 'VendorURL' => 'URL поÑтавщика', + 'Version' => 'ВерÑиÑ', + 'Version2' => 'ВерÑÐ¸Ñ 2', + 'VersionCreateDate' => 'ВерÑÐ¸Ñ â€“ Дата ÑозданиÑ', + 'VersionModifyDate' => 'ВерÑÐ¸Ñ â€“ Дата редактированиÑ', + 'VersionYear' => 'Год Ñтандарта факÑ-профилÑ', + 'VerticalDivergence' => 'Угол вертикального раÑхождениÑ', + 'Vibrance' => 'КраÑочноÑÑ‚ÑŒ', + 'VideoBitrate' => 'Битрейт видео', + 'VideoClosedCaptioning' => { + Description => 'Видео Ñ Ñубтитрами', + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'VideoCodecID' => 'ID видеокодека', + 'VideoEncoding' => 'Видеокодирование', + 'VideoFormat' => 'Формат видео', + 'VideoMode' => 'Режим видео', + 'VideoQuality' => 'КачеÑтво видео', + 'VideoScanType' => 'Тип ÑÐºÐ°Ð½Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð²Ð¸Ð´ÐµÐ¾', + 'VideoSize' => 'Размер видео', + 'View' => 'ПроÑмотр', + 'ViewType' => { + Description => 'Тип проÑмотра', + PrintConv => { + 'No Pop-up Effect' => 'Без вÑплывающего Ñффекта', + 'Pop-up Effect' => 'С вÑплывающим Ñффектом', + }, + }, + 'Viewfinder' => 'ВидоиÑкатель', + 'VignetteCorrectionAlreadyApplied' => 'Применена ÐºÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð²Ð¸Ð½ÑŒÐµÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ', + 'VignettingCorrParams' => 'Параметры коррекции виньетированиÑ', + 'VignettingCorrection' => { + Description => 'ÐšÐ¾Ñ€Ñ€ÐµÐºÑ†Ð¸Ñ Ð²Ð¸Ð½ÑŒÐµÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ', + PrintConv => { + 'Auto' => 'ÐвтоматичеÑкаÑ', + 'No correction params available' => 'ÐедоÑтупна', + 'Off' => 'Ðе включена', + }, + }, + 'VirtualImageHeight' => 'Ð’Ñ‹Ñота виртуального изображениÑ', + 'VirtualImageWidth' => 'Ширина виртуального изображениÑ', + 'VirtualPageUnits' => 'Единицы виртуальной Ñтраницы', + 'VisualFlightRulesHUD' => 'Визуальные правила полетов HUD', + 'VoiceMemo' => { + Description => 'ГолоÑовые заметки', + PrintConv => { + 'Off' => 'Ðе включено', + 'On' => 'Включено', + }, + }, + 'Volume' => 'Том', + 'VolumeBlockCount' => 'КоличеÑтво блоков в томе', + 'VolumeBlockSize' => 'Размер блока в томе', + 'VolumeCreateDate' => 'Дата ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñ‚Ð¾Ð¼Ð°', + 'VolumeEffectiveDate' => 'Дата начала иÑÐ¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð¾Ð¼Ð°', + 'VolumeExpirationDate' => 'Дата уÑÑ‚Ð°Ñ€ÐµÐ²Ð°Ð½Ð¸Ñ Ñ‚Ð¾Ð¼Ð°', + 'VolumeID' => 'ID тома', + 'VolumeLabel' => 'Метка тома', + 'VolumeModifyDate' => 'Дата Ñ€ÐµÐ´Ð°ÐºÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ‚Ð¾Ð¼Ð°', + 'VolumeName' => 'Ðазвание тома', + 'VolumeSetDiskCount' => 'КоличеÑтво диÑков в наборе томов', + 'VolumeSetDiskNumber' => 'Ðомер диÑка в наборе томов', + 'VolumeSetName' => 'Ðазвание набора томов', + 'VolumeSize' => 'Размер тома', + 'VorbisVersion' => 'ВерÑÐ¸Ñ Vorbis', + 'WBBlueLevel' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð‘ÐµÐ»Ð¾Ð³Ð¾ – Уровень Ñинего', + 'WBGreenLevel' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð‘ÐµÐ»Ð¾Ð³Ð¾ – Уровень зелёного', + 'WBMode' => 'Режим баланÑа белого', + 'WBRedLevel' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð‘ÐµÐ»Ð¾Ð³Ð¾ – Уровень краÑного', + 'WBScale' => 'Чёрно-Белое – Шкала', + 'WB_GBRGLevels' => 'Чёрно-Белое – Уровни GBRG', + 'WB_GRGBLevels' => 'Уровни WB_GRGB', + 'WB_RBLevelsCloudy' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ – Уровни RB – Облачно', + 'WB_RBLevelsCoolWhiteF' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ – Уровни RB – Холодный белый F', + 'WB_RBLevelsDayWhiteF' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ – Уровни RB – Дневной белый F', + 'WB_RBLevelsDaylight' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ – Уровни RB – Дневной Ñвет', + 'WB_RBLevelsDaylightF' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ – Уровни RB – Дневной Ñвет F', + 'WB_RBLevelsFlash' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ – Уровни RB – Ð’Ñпышка', + 'WB_RBLevelsShade' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ – Уровни RB – Тень', + 'WB_RBLevelsTungsten' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ – Уровни RB – Лампа накаливаниÑ', + 'WB_RBLevelsUnknown' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ – Уровни RB – ÐеизвеÑтный иÑточник Ñвета', + 'WB_RBLevelsWhiteF' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ – Уровни RB – Белый', + 'WB_RGBLevels' => 'Уровни WB RGB', + 'WB_RGGBLevels' => 'Чёрно-Белое – Уровни RGGB', + 'WWSFamilyName' => 'Ðазвание ÑемейÑтва WWS', + 'WWSSubfamilyName' => 'Ðазвание ÑÑ‚Ð¸Ð»Ñ WWS', + 'WangAnnotation' => 'Wang Imaging – ÐннотациÑ', + 'WangTag1' => 'Wang Imaging – Тег 1', + 'WangTag3' => 'Wang Imaging – Тег 3', + 'WangTag4' => 'Wang Imaging – Тег 4', + 'Warning' => 'Уведомление', + 'WarpQuadrilateral' => 'Ð”ÐµÑ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ñ‡ÐµÑ‚Ñ‹Ñ€Ñ‘Ñ…ÑƒÐ³Ð¾Ð»ÑŒÐ½Ð¸ÐºÐ°', + 'Watched' => { + PrintConv => { + 'No' => 'Ðет', + 'Yes' => 'Да', + }, + }, + 'WaterDepth' => 'Глубина воды', + 'Watermark' => 'ВодÑной знак', + 'Weight' => 'Толщина шрифта', 'WhiteBalance' => { Description => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾', PrintConv => { - 'Auto' => 'ÐвтоматичеÑкий Ð±Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾', + 'Auto' => 'ÐвтоматичеÑкий', 'Black & White' => 'Монохром', 'Cloudy' => 'ОблачноÑÑ‚ÑŒ', - 'Color Temperature/Color Filter' => 'Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ñ‚ÐµÐ¼Ð¿ÐµÑ€Ð°Ñ‚ÑƒÑ€Ð° / Цветовой фильтр', + 'Color Temperature/Color Filter' => 'Ð¦Ð²ÐµÑ‚Ð¾Ð²Ð°Ñ Ñ‚ÐµÐ¼Ð¿ÐµÑ€Ð°Ñ‚ÑƒÑ€Ð°/Цветовой фильтр', 'Cool White Fluorescent' => 'ФлуореÑцентный белый холодный', 'Custom' => 'Пользователь', 'Custom 1' => 'ПЕРСОÐÐЛЬÐЫЙ 1', @@ -704,7 +5583,7 @@ $VERSION = '1.04'; 'Daylight Fluorescent' => 'ФлуореÑцентный дневной', 'Flash' => 'Ð’Ñпышка', 'Fluorescent' => 'ФлуореÑцентный', - 'Manual' => 'Ð ÑƒÑ‡Ð½Ð°Ñ Ð½Ð°Ñтройка баланÑа белого', + 'Manual' => 'Ручной', 'Shade' => 'Тень', 'Tungsten' => 'Лампа накаливаниÑ', 'Unknown' => 'неизвеÑтно', @@ -712,31 +5591,120 @@ $VERSION = '1.04'; 'White Fluorescent' => 'ФлуореÑцентный белый', }, }, + 'WhiteBalance0' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ 0', + 'WhiteBalance1' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ 1', + 'WhiteBalance2' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ 2', + 'WhiteBalanceRGB' => 'Ð‘Ð°Ð»Ð°Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾ RGB', 'WhiteLevel' => 'Уровень белого', + 'WhiteLuminance' => 'ЯркоÑÑ‚ÑŒ белого', 'WhitePoint' => 'ЦветноÑÑ‚ÑŒ белой точки', - 'Writer-Editor' => 'Ðвтор подпиÑи', - 'YCbCrCoefficients' => 'Матричные коÑффициенты Ð¿Ñ€ÐµÐ¾Ð±Ñ€Ð°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ Ñ†Ð²ÐµÑ‚Ð¾Ð²Ð¾Ð¹ Ñреды', + 'WhitePointX' => 'Ð‘ÐµÐ»Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° по X', + 'WhitePointY' => 'Ð‘ÐµÐ»Ð°Ñ Ñ‚Ð¾Ñ‡ÐºÐ° по Y', + 'WhitesAdj' => 'Регулировка ÑƒÑ€Ð¾Ð²Ð½Ñ Ð±ÐµÐ»Ð¾Ð³Ð¾', + 'WideRange' => { + Description => 'Широкий диапазон', + PrintConv => { + 'Off' => 'Ðе включён', + 'On' => 'Включен', + }, + }, + 'WidthBytes' => 'Ширина в байтах', + 'WidthResolution' => 'Разрешение по ширине (PPI)', + 'WindowOrigin' => 'Ðачало координат окна', + 'WindowOriginAuto' => 'Ðачало координат окна – ÐвтоматичеÑки', + 'WindowSize' => 'Размер окна', + 'WindowTarget' => 'Целевое окно', + 'Words' => 'Слов', + 'WorkflowURL' => 'URL рабочего процеÑÑа', + 'WorkingDirectory' => 'Рабочий каталог', + 'WorkingPath' => 'Рабочий контур', + 'WorldToCamera' => 'Мир на камеру', + 'WorldToNDC' => 'Мир на NDC', + 'WrapModes' => 'Режим обёртываниÑ', + 'Writer-Editor' => 'ПиÑатель/Редактор', + 'WriterName' => 'Ðазвание редактора', + 'XAttrAppleMailDateReceived' => 'X Attr – Почта Apple – Дата получениÑ', + 'XAttrAppleMailDateSent' => 'X Attr – Почта Apple – Дата отправки', + 'XAttrAppleMailIsRemoteAttachment' => 'X Attr – Почта Apple – Ðаличие удалённого вложениÑ', + 'XAttrFinderInfo' => 'X Attr – СвойÑтва файла', + 'XAttrLastUsedDate' => 'X Attr – Дата поÑледнего иÑпользованиÑ', + 'XAttrMDItemDownloadedDate' => 'X Attr – MD Item – Дата загрузки', + 'XAttrMDItemFinderComment' => 'X Attr – MD Item – Комментарий к файлу', + 'XAttrMDItemWhereFroms' => 'X Attr – MD Item – ИÑточник файла', + 'XAttrMDLabel' => 'X Attr – MD – Ð¦Ð²ÐµÑ‚Ð½Ð°Ñ Ð¼ÐµÑ‚ÐºÐ° файла', + 'XAttrQuarantine' => 'X Attr – Карантинный', + 'XAttrResourceFork' => 'X Attr – Вилка реÑурÑов', + 'XCFVersion' => 'ВерÑÐ¸Ñ XCF', + 'XClipPathUnits' => 'Единицы обтравочного контура по X', + 'XHeight' => 'Ð’Ñ‹Ñота Ñтрочных букв', + 'XMLData' => 'Данные XML', + 'XOffset' => 'Смещение по X', + 'XPAuthor' => 'XP – Ðвтор', + 'XPComment' => 'XP – Комментарии', + 'XPKeywords' => 'XP – Ключевые Ñлова', + 'XPSubject' => 'XP – Тема', + 'XPTitle' => 'XP – Ðазвание', + 'XPosition' => 'Положение Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾ X', + 'XResolution' => 'Разрешение по X', + 'XYResolution' => 'Разрешение по X и Y', + 'YCbCrCoefficients' => 'КоÑффициенты Ð¿Ñ€ÐµÐ¾Ð±Ñ€Ð°Ð·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸Ð· RGB в Y Cb Cr', 'YCbCrPositioning' => { - Description => 'ÐŸÐ¾Ð·Ð¸Ñ†Ð¸Ñ Ð¿Ð¾ Y и C', + Description => 'Положение точки, определÑющей цвет в Y Cb Cr', PrintConv => { - 'Centered' => 'центрованный', - 'Co-sited' => 'Ñовпадающий по меÑту', + 'Centered' => 'Центрованный', + 'Co-sited' => 'СовмеÑтимый', }, }, - 'YCbCrSubSampling' => 'КоÑффициент ÑубдиÑкретизации Y и C', + 'YCbCrSubSampling' => 'КоÑффициент ÑубдиÑкретизации Y Cb Cr', + 'YClipPathUnits' => 'Единицы обтравочного контура по Y', + 'YLevel' => 'Уровень – Y', + 'YOffset' => 'Смещение по Y', + 'YPosition' => 'Положение Ð¸Ð·Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾ Y', + 'YResolution' => 'Разрешение по Y', + 'YTarget' => 'Цель – Y', + 'Yaw' => 'РыÑкание (Поворот)', + 'YawAngle' => 'Угол поворота (РыÑкание)', + 'Year' => 'Год', + 'ZipBitFlag' => 'Zip – Битовый флаг', + 'ZipCRC' => 'Zip – CRC', + 'ZipCompressedSize' => 'Zip – Сжатый размер', + 'ZipCompression' => { + Description => 'Zip – Сжатие', + PrintConv => { + 'Enhanced Deflate using Deflate64(tm)' => 'Улучшенный Deflate Ñ Ð¸Ñпользованием Deflate64(tm)', + 'IBM LZ77 z Architecture (PFS)' => 'IBM LZ77 z/Architecture (PFS)', + 'IBM TERSE (new)' => 'IBM TERSE (новый)', + 'Imploded (old IBM TERSE)' => 'Imploded (Ñтарый IBM TERSE)', + 'None' => 'Без ÑжатиÑ', + 'PPMd version I, Rev 1' => 'PPMd верÑÐ¸Ñ I, Ð ÐµÐ²Ð¸Ð·Ð¸Ñ 1', + 'Reduced with compression factor 1' => 'Сжатый Ñ ÐºÐ¾Ñффициентом ÑÐ¶Ð°Ñ‚Ð¸Ñ 1', + 'Reduced with compression factor 2' => 'Сжатый Ñ ÐºÐ¾Ñффициентом ÑÐ¶Ð°Ñ‚Ð¸Ñ 2', + 'Reduced with compression factor 3' => 'Сжатый Ñ ÐºÐ¾Ñффициентом ÑÐ¶Ð°Ñ‚Ð¸Ñ 3', + 'Reduced with compression factor 4' => 'Сжатый Ñ ÐºÐ¾Ñффициентом ÑÐ¶Ð°Ñ‚Ð¸Ñ 4', + 'WavPack compressed' => 'WavPack', + }, + }, + 'ZipFileName' => 'Zip – Ðазвание файла', + 'ZipFileNameLength' => 'Zip – Длина Ð½Ð°Ð·Ð²Ð°Ð½Ð¸Ñ Ñ„Ð°Ð¹Ð»Ð°', + 'ZipModifyDate' => 'Zip – Дата редактированиÑ', + 'ZipRequiredVersion' => 'Zip – Ð¢Ñ€ÐµÐ±ÑƒÐµÐ¼Ð°Ñ Ð²ÐµÑ€ÑиÑ', + 'ZipUncompressedSize' => 'Zip – ÐеÑжатый размер', 'ZoneMatching' => { - Description => 'СоответÑтвие облаÑтей', + Description => 'СоглаÑование зон', PrintConv => { - 'High Key' => 'Hi', - 'ISO Setting Used' => 'Отключено', - 'Low Key' => 'Lo', + 'High Key' => 'Ð’ выÑоком ключе', + 'ISO Setting Used' => 'ИÑпользуютÑÑ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ñ‹ ISO', + 'Low Key' => 'Ð’ низком ключе', }, }, + 'Zoom' => 'Зум', + 'ZoomPos' => 'ÐŸÐ¾Ð·Ð¸Ñ†Ð¸Ñ Ð·ÑƒÐ¼Ð°', + 'ZoomedPreviewImage' => 'Увеличенный предпроÑмотр изображениÑ', + 'iTunesMediaType' => 'Тип iTunes медиа', ); 1; # end - __END__ =head1 NAME @@ -750,15 +5718,15 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 ACKNOWLEDGEMENTS -Thanks to Jens Duttke, Sergey Shemetov, Dmitry Yerokhin and Anton Sukhinov -for providing this translation. +Thanks to Jens Duttke, Sergey Shemetov, Dmitry Yerokhin, Anton Sukhinov and +Alexander for providing this translation. =head1 SEE ALSO diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/sv.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/sv.pm index 9c1250fb..76f4a093 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/sv.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/sv.pm @@ -620,7 +620,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/tr.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/tr.pm index c6665f2c..b997a683 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/tr.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/tr.pm @@ -11,7 +11,7 @@ package Image::ExifTool::Lang::tr; use strict; use vars qw($VERSION); -$VERSION = '1.04'; +$VERSION = '1.05'; %Image::ExifTool::Lang::tr::Translate = ( 'Album' => 'Albüm', @@ -499,6 +499,7 @@ $VERSION = '1.04'; }, 'WhitePoint' => 'Beya nokta kromatik', 'Writer-Editor' => 'Açıklama Yazarı', + 'XResolution' => 'X çözünürlüğü', 'YCbCrCoefficients' => 'Renk alanı transformasyon matriks katsayısı', 'YCbCrPositioning' => { Description => 'Y ve C konumlama', @@ -508,6 +509,7 @@ $VERSION = '1.04'; }, }, 'YCbCrSubSampling' => 'Y den C\'ye alt örnekleme oranı', + 'YResolution' => 'Y çözünürlüğü', ); 1; # end @@ -526,7 +528,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/zh_cn.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/zh_cn.pm index 9cc9c27a..e0f42fab 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/zh_cn.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/zh_cn.pm @@ -1313,7 +1313,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lang/zh_tw.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lang/zh_tw.pm index 1df5e0f8..d214535e 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lang/zh_tw.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lang/zh_tw.pm @@ -784,7 +784,7 @@ and values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Leaf.pm b/src/Image-ExifTool/lib/Image/ExifTool/Leaf.pm index 81a5c5fe..8df1fbab 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Leaf.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Leaf.pm @@ -504,7 +504,7 @@ Capture. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Lytro.pm b/src/Image-ExifTool/lib/Image/ExifTool/Lytro.pm index bd8d8fd7..d4a1ae11 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Lytro.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Lytro.pm @@ -50,6 +50,7 @@ sub ExtractTags($$$); DevicesAccelerometerSampleArrayZ => { Name => 'AccelerometerZ'}, DevicesClockZuluTime => { Name => 'DateTimeOriginal', + Description => 'Date/Time Original', Groups => { 2 => 'Time' }, ValueConv => 'require Image::ExifTool::XMP; Image::ExifTool::XMP::ConvertXMPDate($val)', PrintConv => '$self->ConvertDateTime($val)', @@ -191,7 +192,7 @@ from Lytro Light Field Picture (LFP) files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/M2TS.pm b/src/Image-ExifTool/lib/Image/ExifTool/M2TS.pm index fba525bf..86c7273b 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/M2TS.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/M2TS.pm @@ -31,7 +31,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.15'; +$VERSION = '1.21'; # program map table "stream_type" lookup (ref 6/1) my %streamType = ( @@ -57,7 +57,8 @@ my %streamType = ( 0x13 => 'ISO 14496-1 SL-packetized', 0x14 => 'ISO 13818-6 Synchronized Download Protocol', # 0x15-0x7F => 'ISO 13818-1 Reserved', - 0x1b => 'H.264 Video', + 0x1b => 'H.264 (AVC) Video', + 0x24 => 'H.265 (HEVC) Video', #PH 0x80 => 'DigiCipher II Video', 0x81 => 'A52/AC-3 Audio', 0x82 => 'HDMV DTS Audio', @@ -67,6 +68,7 @@ my %streamType = ( 0x86 => 'DTS-HD Audio', 0x87 => 'E-AC-3 Audio', 0x8a => 'DTS Audio', + 0x90 => 'PGS Audio', #https://www.avsforum.com/threads/bass-eq-for-filtered-movies.2995212/page-399 0x91 => 'A52b/AC-3 Audio', 0x92 => 'DVD_SPU vls Subtitle', 0x94 => 'SDDS Audio', @@ -111,6 +113,8 @@ my %noSyntax = ( 0xff => 1, # program_stream_directory ); +my $knotsToKph = 1.852; # knots --> km/h + # information extracted from the MPEG-2 transport stream %Image::ExifTool::M2TS::Main = ( GROUPS => { 2 => 'Video' }, @@ -262,7 +266,7 @@ sub ParseAC3Descriptor($$) #------------------------------------------------------------------------------ # Parse PID stream data -# Inputs: 0) Exiftool ref, 1) PID number, 2) PID type, 3) PID name, 4) data ref +# Inputs: 0) ExifTool ref, 1) PID number, 2) PID type, 3) PID name, 4) data ref # Returns: 0=stream parsed OK, # 1=stream parsed but we want to parse more of these, # -1=can't parse yet because we don't know the type @@ -299,6 +303,116 @@ sub ParsePID($$$$$) } elsif ($type == 0x81 or $type == 0x87 or $type == 0x91) { # AC-3 audio ParseAC3Audio($et, $dataPt); + } elsif ($type < 0) { + if ($$dataPt =~ /^(.{164})?(.{24})A[NS][EW]/s) { + # (Blueskysea B4K, Novatek NT96670) + # 0000: 01 00 ff 00 30 31 32 33 34 35 37 38 61 62 63 64 [....01234578abcd] + # 0010: 65 66 67 0a 00 00 00 00 00 00 00 00 00 00 00 00 [efg.............] + # 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0040: 00 00 00 00 30 31 32 33 34 35 37 38 71 77 65 72 [....01234578qwer] + # 0050: 74 79 75 69 6f 70 0a 00 00 00 00 00 00 00 00 00 [tyuiop..........] + # 0060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0080: 00 00 00 00 63 38 61 61 32 35 63 66 34 35 65 65 [....c8aa25cf45ee] + # 0090: 61 39 65 32 34 34 32 66 61 65 62 35 65 30 39 39 [a9e2442faeb5e099] + # 00a0: 30 37 64 34 15 00 00 00 10 00 00 00 1b 00 00 00 [07d4............] + # 00b0: 15 00 00 00 01 00 00 00 09 00 00 00 41 4e 57 00 [............ANW.] + # 00c0: 82 9a 57 45 98 b2 00 46 66 66 e4 41 d7 e3 14 43 [..WE...Fff.A...C] + # 00d0: 01 00 02 00 03 00 04 00 05 00 06 00 [............] + # (Viofo A119V3) + # 0000: 08 00 00 00 07 00 00 00 18 00 00 00 15 00 00 00 [................] + # 0010: 03 00 00 00 0b 00 00 00 41 4e 45 00 01 f2 ac 45 [........ANE....E] + # 0020: 2d 7f 6e 45 b8 1e 97 41 d7 23 46 43 00 00 00 00 [-.nE...A.#FC....] + # pad with dummy header and parse with existing FreeGPS code (minimum 92 bytes) + my $dat = ("\0" x 16) . substr($$dataPt, length($1 || '')) . ("\0" x 20); + my $tbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); + Image::ExifTool::QuickTime::ProcessFreeGPS($et, { DataPt => \$dat }, $tbl); + $more = 1; + } elsif ($$dataPt =~ /^A([NS])([EW])\0/s) { + # INNOVV TS video (same format is INNOVV MP4) + SetByteOrder('II'); + my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); + while ($$dataPt =~ /(A[NS][EW]\0.{28})/g) { + my $dat = $1; + my $lat = abs(GetFloat(\$dat, 4)); # (abs just to be safe) + my $lon = abs(GetFloat(\$dat, 8)); # (abs just to be safe) + my $spd = GetFloat(\$dat, 12) * $knotsToKph; + my $trk = GetFloat(\$dat, 16); + my @acc = unpack('x20V3', $dat); + map { $_ = $_ - 4294967296 if $_ >= 0x80000000 } @acc; + Image::ExifTool::QuickTime::ConvertLatLon($lat, $lon); + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + $et->HandleTag($tagTbl, GPSLatitude => abs($lat) * (substr($dat,1,1) eq 'S' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSLongitude => abs($lon) * (substr($dat,2,1) eq 'W' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSSpeed => $spd); + $et->HandleTag($tagTbl, GPSSpeedRef => 'K'); + $et->HandleTag($tagTbl, GPSTrack => $trk); + $et->HandleTag($tagTbl, GPSTrackRef => 'T'); + $et->HandleTag($tagTbl, Accelerometer => "@acc"); + } + SetByteOrder('MM'); + $more = 1; + } elsif ($$dataPt =~ /^\$(GPSINFO|GSNRINFO),/) { + # $GPSINFO,0x0004,2021.08.09 13:27:36,2341.54561,12031.70135,8.0,51,153,0,0,\x0d + # $GSNRINFO,0.01,0.04,0.25\0 + $$dataPt =~ tr/\x0d/\x0a/; + $$dataPt =~ tr/\0//d; + my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); + my @lines = split /\x0a/, $$dataPt; + my ($line, $lastTime); + foreach $line (@lines) { + if ($line =~ /^\$GPSINFO/) { + my @a = split /,/, $lines[0]; + next unless @a > 7; + # ignore duplicate fixes + next if $lastTime and $a[2] eq $lastTime; + $lastTime = $a[2]; + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + $a[2] =~ tr/./:/; + # (untested, and probably doesn't work for S/W hemispheres) + my ($lat, $lon) = @a[3,4]; + Image::ExifTool::QuickTime::ConvertLatLon($lat, $lon); + # $a[0] - flags? values: '0x0001','0x0004','0x0008','0x0010' + $et->HandleTag($tagTbl, GPSDateTime => $a[2]); + $et->HandleTag($tagTbl, GPSLatitude => $lat); + $et->HandleTag($tagTbl, GPSLongitude => $lon); + $et->HandleTag($tagTbl, GPSSpeed => $a[5]); + $et->HandleTag($tagTbl, GPSSpeedRef => 'K'); + # $a[6] - values: 48-60 + $et->HandleTag($tagTbl, GPSTrack => $a[7]); + $et->HandleTag($tagTbl, GPSTrackRef => 'T'); + # #a[8,9] - always 0 + } elsif ($line =~ /^\$GSNRINFO/) { + my @a = split /,/, $line; + shift @a; + $et->HandleTag($tagTbl, Accelerometer => "@a"); + } + } + $more = 1; + } elsif ($$dataPt =~ /^.{44}A\0{3}.{4}([NS])\0{3}.{4}([EW])\0{3}/s and length($$dataPt) >= 84) { + #forum11320 + SetByteOrder('II'); + my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); + my $lat = abs(GetFloat($dataPt, 48)); # (abs just to be safe) + my $lon = abs(GetFloat($dataPt, 56)); # (abs just to be safe) + my $spd = GetFloat($dataPt, 64); + my $trk = GetFloat($dataPt, 68); + $et->WarnOnce('GPSLatitude/Longitude encryption is not yet known, so these will be wrong'); + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + my @date = unpack('x32V3x28V3', $$dataPt); + $date[3] += 2000; + $et->HandleTag($tagTbl, GPSDateTime => sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2d', @date[3..5,0..2])); + $et->HandleTag($tagTbl, GPSLatitude => abs($lat) * ($1 eq 'S' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSLongitude => abs($lon) * ($2 eq 'W' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSSpeed => $spd); + $et->HandleTag($tagTbl, GPSSpeedRef => 'K'); + $et->HandleTag($tagTbl, GPSTrack => $trk); + $et->HandleTag($tagTbl, GPSTrackRef => 'T'); + SetByteOrder('MM'); + $more = 1; + } + delete $$et{DOC_NUM}; } return $more; } @@ -313,7 +427,7 @@ sub ProcessM2TS($$) my $raf = $$dirInfo{RAF}; my ($buff, $pLen, $upkPrefix, $j, $fileType, $eof); my (%pmt, %pidType, %data, %sectLen); - my ($startTime, $endTime, $backScan, $maxBack); + my ($startTime, $endTime, $fwdTime, $backScan, $maxBack); my $verbose = $et->Options('Verbose'); my $out = $et->Options('TextOut'); @@ -330,7 +444,7 @@ sub ProcessM2TS($$) $upkPrefix = 'x4N'; } my $prePos = $pLen - 188; # byte position of packet prefix - my $readSize = 64 * $pLen; # read 64 packets at once + my $readSize = 64 * $pLen; # size of our read buffer $raf->Seek(0,0); # rewind to start $raf->Read($buff, $readSize) >= $pLen * 4 or return 0; # require at least 4 packets # validate the sync byte in the next 3 packets @@ -350,40 +464,74 @@ sub ProcessM2TS($$) ); my %didPID = ( 1 => 0, 2 => 0, 0x1fff => 0 ); my %needPID = ( 0 => 1 ); # lookup for stream PID's that we still need to parse + # PID's that may contain GPS info + my %gpsPID = ( + 0x0300 => 1, # Novatek INNOVV + 0x01e4 => 1, # vsys a6l dashcam + ); my $pEnd = 0; - my $i = 0; + + # scan entire file for GPS programs if ExtractEmbedded option is 3 or higher + # (some dashcams write these programs but don't include it in the PMT) + if (($et->Options('ExtractEmbedded') || 0) > 2) { + foreach (keys %gpsPID) { + $needPID{$_} = 1; + $pidType{$_} = -1; + $pidName{$_} ='unregistered dashcam GPS'; + } + } # parse packets from MPEG-2 Transport Stream for (;;) { unless (%needPID) { last unless defined $startTime; - # seek backwards to find last PCR - if (defined $backScan) { - last if defined $endTime; - $backScan -= $pLen; - last if $backScan < $maxBack; - } else { + # reconfigure to seek backwards for last PCR + unless (defined $backScan) { + my $saveTime = $endTime; undef $endTime; last if $et->Options('FastScan'); - $verbose and print "[Starting backscan for last PCR]\n"; - # calculate position of last complete packet - my $fwdPos = $raf->Tell(); + $verbose and print $out "[Starting backscan for last PCR]\n"; + # remember how far we got when reading forward through the file + my $fwdPos = $raf->Tell() - length($buff) + $pEnd; + # determine the position of the last packet relative to the EOF $raf->Seek(0, 2) or last; my $fsize = $raf->Tell(); - my $nPack = int($fsize / $pLen); - $backScan = ($nPack - 1) * $pLen - $fsize; + $backScan = int($fsize / $pLen) * $pLen - $fsize; # set limit on how far back we will go $maxBack = $fwdPos - $fsize; - $maxBack = -256000 if $maxBack < -256000; + # scan back a maximum of 512k (have seen last PCR at -276k) + my $nMax = int(512000 / $pLen); # max packets to backscan + if ($nMax < int(-$maxBack / $pLen)) { + $maxBack = $backScan - $nMax * $pLen; + } else { + # use this time if none found in all remaining packets + $fwdTime = $saveTime; + } + $pEnd = 0; } - $raf->Seek($backScan, 2) or last; } - my $pos = $pEnd; + my $pos; # read more if necessary - if ($pos + $pLen > length $buff) { - $raf->Read($buff, $readSize) >= $pLen or $eof = 1, last; - $pos = $pEnd = 0; + if (defined $backScan) { + last if defined $endTime; + $pos = $pEnd = $pEnd - 2 * $pLen; # step back to previous packet + if ($pos < 0) { + # read another buffer from end of file + last if $backScan <= $maxBack; + my $buffLen = $backScan - $maxBack; + $buffLen = $readSize if $buffLen > $readSize; + $backScan -= $buffLen; + $raf->Seek($backScan, 2) or last; + $raf->Read($buff, $buffLen) == $buffLen or last; + $pos = $pEnd = $buffLen - $pLen; + } + } else { + $pos = $pEnd; + if ($pos + $pLen > length $buff) { + $raf->Read($buff, $readSize) >= $pLen or $eof = 1, last; + $pos = $pEnd = 0; + } } $pEnd += $pLen; # decode the packet prefix @@ -391,7 +539,7 @@ sub ProcessM2TS($$) my $prefix = unpack("x${pos}N", $buff); # (use unpack instead of Get32u for speed) # validate sync byte unless (($prefix & 0xff000000) == 0x47000000) { - $et->Warn('Synchronization error') unless defined $backScan; + $et->Warn('M2TS synchronization error') unless defined $backScan; last; } # my $transport_error_indicator = $prefix & 0x00800000; @@ -402,12 +550,11 @@ sub ProcessM2TS($$) my $adaptation_field_exists = $prefix & 0x00000020; my $payload_data_exists = $prefix & 0x00000010; # my $continuity_counter = $prefix & 0x0000000f; - if ($verbose > 1) { + my $i = ($raf->Tell() - length($buff) + $pEnd) / $pLen - 1; print $out "Transport packet $i:\n"; - ++$i; $et->VerboseDump(\$buff, Len => $pLen, Addr => $i * $pLen, Start => $pos - $prePos); - my $str = $pidName{$pid} ? " ($pidName{$pid})" : ''; + my $str = $pidName{$pid} ? " ($pidName{$pid})" : ' <not in Program Map Table!>'; printf $out " Timecode: 0x%.4x\n", Get32u(\$buff, $pos - $prePos) if $pLen == 192; printf $out " Packet ID: 0x%.4x$str\n", $pid; printf $out " Start Flag: %s\n", $payload_unit_start_indicator ? 'Yes' : 'No'; @@ -620,7 +767,11 @@ sub ProcessM2TS($$) } $data{$pid} = substr($buff, $pos, $pEnd-$pos); } else { - next unless defined $data{$pid}; + unless (defined $data{$pid}) { + # (vsys a6l dashcam GPS record doesn't have a start indicator) + next unless $gpsPID{$pid}; + $data{$pid} = ''; + } # accumulate data for each elementary stream $data{$pid} .= substr($buff, $pos, $pEnd-$pos); } @@ -646,7 +797,8 @@ sub ProcessM2TS($$) } # calculate Duration if available - if (defined $startTime and defined $endTime and $startTime != $endTime) { + $endTime = $fwdTime unless defined $endTime; + if (defined $startTime and defined $endTime) { $endTime += 0x80000000 * 1200 if $startTime > $endTime; # handle 33-bit wrap $et->HandleTag($tagTablePtr, 'Duration', $endTime - $startTime); } @@ -694,7 +846,7 @@ video. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MIE.pm b/src/Image-ExifTool/lib/Image/ExifTool/MIE.pm index c6e72042..00901cba 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/MIE.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/MIE.pm @@ -14,7 +14,7 @@ use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; use Image::ExifTool::GPS; -$VERSION = '1.47'; +$VERSION = '1.49'; sub ProcessMIE($$); sub ProcessMIEGroup($$$); @@ -152,11 +152,11 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); (eg. C<55(mi/h)>). If no units are specified, the default units are written. - 4) ExifTool writes compressed metadata to MIE files if the Compress (-z) + 4) ExifTool writes compressed metadata to MIE files if the L<Compress|../ExifTool.html#Compress> (-z) option is used and Compress::Zlib is available. - See L<http://owl.phy.queensu.ca/~phil/exiftool/MIE1.1-20070121.pdf> for the - official MIE specification. + See L<https://exiftool.org/MIE1.1-20070121.pdf> for the official MIE + specification. }, '0Type' => { Name => 'SubfileType', @@ -393,7 +393,7 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)', ValueConvInv => 'Image::ExifTool::GPS::ToDMS($self, $val, 0)', PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', - PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1)', + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lat")', }, Longitude => { Name => 'GPSLongitude', @@ -406,7 +406,7 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)', ValueConvInv => 'Image::ExifTool::GPS::ToDMS($self, $val, 0)', PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', - PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1)', + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")', }, MeasureMode => { Name => 'GPSMeasureMode', @@ -1001,10 +1001,10 @@ sub WriteMIEGroup($$$) } } # don't rewrite free bytes or information in deleted groups - if ($format eq 0x80 or ($delGroup and $tagLen and ($format & 0xf0) != 0x10)) { + if ($format == 0x80 or ($delGroup and $tagLen and ($format & 0xf0) != 0x10)) { $raf->Seek($valLen, 1) or $msg = 'Seek error', last; if ($verbose > 1) { - my $free = ($format eq 0x80) ? ' free' : ''; + my $free = ($format == 0x80) ? ' free' : ''; print $out " - $grp1:$tag ($valLen$free bytes)\n"; } ++$$et{CHANGED} if $delGroup; @@ -1023,6 +1023,7 @@ sub WriteMIEGroup($$$) # we are writing the new tag now my ($newVal, $writable, $oldVal, $newFormat, $compress); my $newTag = shift @editTags; + length($newTag) > 255 and $et->Warn('Tag name too long'), next; # (just to be safe) my $newInfo = $$editDirs{$newTag}; if ($newInfo) { # create the new subdirectory or rewrite existing non-MIE directory @@ -1242,8 +1243,7 @@ sub WriteMIEGroup($$$) # write new value if creating, or if List and list existed, or # if tag was previously deleted next unless $$nvHash{IsCreating} or - (($newTag eq $lastTag and ($$newInfo{List} or $deletedTag eq $lastTag) - and not $$nvHash{EditOnly})); + ($newTag eq $lastTag and ($$newInfo{List} or $deletedTag eq $lastTag)); } # get the new value to write (undef to delete) push @newVals, $et->GetNewValue($nvHash); @@ -1340,7 +1340,7 @@ sub WriteMIEGroup($$$) $extLen = Set32u($len); $len = 254; } else { - $et->Warn("Can't write $newTag (DataLength > 2GB not yet suppported)"); + $et->Warn("Can't write $newTag (DataLength > 2GB not yet supported)"); last; # don't write this tag } # write this element (with leading MIE group element if not done already) @@ -2545,7 +2545,7 @@ tag name. For example: =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. The MIE format itself is also @@ -2555,7 +2555,7 @@ copyright Phil Harvey, and is covered by the same free-use license. =over 4 -=item L<http://owl.phy.queensu.ca/~phil/exiftool/MIE1.1-20070121.pdf> +=item L<https://exiftool.org/MIE1.1-20070121.pdf> =back diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MIEUnits.pod b/src/Image-ExifTool/lib/Image/ExifTool/MIEUnits.pod index 7cdfbfca..3484f6ce 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/MIEUnits.pod +++ b/src/Image-ExifTool/lib/Image/ExifTool/MIEUnits.pod @@ -356,7 +356,7 @@ A few examples of combined units strings: =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MIFF.pm b/src/Image-ExifTool/lib/Image/ExifTool/MIFF.pm index a6cfe2c1..316c57b0 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/MIFF.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/MIFF.pm @@ -255,7 +255,7 @@ This module contains routines required by Image::ExifTool to read MIFF =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MNG.pm b/src/Image-ExifTool/lib/Image/ExifTool/MNG.pm index 2f1d819a..f7a2b37c 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/MNG.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/MNG.pm @@ -661,7 +661,7 @@ This module contains definitions required by Image::ExifTool to read MNG =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MOI.pm b/src/Image-ExifTool/lib/Image/ExifTool/MOI.pm new file mode 100644 index 00000000..260c4533 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/MOI.pm @@ -0,0 +1,159 @@ +#------------------------------------------------------------------------------ +# File: MOI.pm +# +# Description: Read MOI meta information +# +# Revisions: 2014/12/15 - P. Harvey Created +# +# References: 1) https://en.wikipedia.org/wiki/MOI_(file_format) +#------------------------------------------------------------------------------ + +package Image::ExifTool::MOI; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.02'; + +# MOI tags (ref 1) +%Image::ExifTool::MOI::Main = ( + GROUPS => { 2 => 'Video' }, + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + NOTES => q{ + MOI files store information about associated MOD or TOD files, and are + written by some JVC, Canon and Panasonic camcorders. + }, + 0x00 => { Name => 'MOIVersion', Format => 'string[2]' }, + # 0x02 => { Name => 'MOIFileSize', Format => 'int32u' }, + 0x06 => { + Name => 'DateTimeOriginal', + Description => 'Date/Time Original', + Format => 'undef[8]', + Groups => { 2 => 'Time' }, + ValueConv => sub { + my $val = shift; + return undef unless length($val) >= 8; + my @v = unpack('nCCCCn', $val); + $v[5] /= 1000; + return sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%06.3f', @v); + }, + PrintConv => '$self->ConvertDateTime($val)', + }, + 0x0e => { + Name => 'Duration', + Format => 'int32u', + ValueConv => '$val / 1000', + PrintConv => 'ConvertDuration($val)', + }, + 0x80 => { + Name => 'AspectRatio', + Format => 'int8u', + PrintConv => q{ + my $lo = ($val & 0x0f); + my $hi = ($val >> 4); + my $aspect; + if ($lo < 2) { + $aspect = '4:3'; + } elsif ($lo == 4 or $lo == 5) { + $aspect = '16:9'; + } else { + $aspect = 'Unknown'; + } + if ($hi == 4) { + $aspect .= ' NTSC'; + } elsif ($hi == 5) { + $aspect .= ' PAL'; + } + return $aspect; + }, + }, + 0x84 => { + Name => 'AudioCodec', + Format => 'int16u', + Groups => { 2 => 'Audio' }, + PrintHex => 1, + PrintConv => { + 0x00c1 => 'AC3', + 0x4001 => 'MPEG', + }, + }, + 0x86 => { + Name => 'AudioBitrate', + Format => 'int8u', + Groups => { 2 => 'Audio' }, + ValueConv => '$val * 16000 + 48000', + PrintConv => 'ConvertBitrate($val)', + }, + 0xda => { + Name => 'VideoBitrate', + Format => 'int16u', + PrintHex => 1, + ValueConv => { + 0x5896 => '8500000', + 0x813d => '5500000', + }, + PrintConv => 'ConvertBitrate($val)', + }, +); + +#------------------------------------------------------------------------------ +# Validate and extract metadata from MOI file +# Inputs: 0) ExifTool ref, 1) dirInfo ref +# Returns: 1 on success, 0 if this wasn't a valid MOI file +sub ProcessMOI($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my $buff; + # read enough to allow skipping over run-in if it exists + $raf->Read($buff, 256) == 256 and $buff =~ /^V6/ or return 0; + if (defined $$et{VALUE}{FileSize}) { + my $size = unpack('x2N', $buff); + $size == $$et{VALUE}{FileSize} or return 0; + } + $et->SetFileType(); + SetByteOrder('MM'); + my $tagTablePtr = GetTagTable('Image::ExifTool::MOI::Main'); + return $et->ProcessBinaryData({ DataPt => \$buff }, $tagTablePtr); +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::MOI - Read MOI meta information + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to read meta +information from MOI files. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<https://en.wikipedia.org/wiki/MOI_(file_format)> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/MOI Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MPC.pm b/src/Image-ExifTool/lib/Image/ExifTool/MPC.pm index 1576fc9c..daeaecab 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/MPC.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/MPC.pm @@ -134,7 +134,7 @@ information from Musepack (MPC) audio files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MPEG.pm b/src/Image-ExifTool/lib/Image/ExifTool/MPEG.pm index c9acb2bc..3e209e17 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/MPEG.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/MPEG.pm @@ -704,7 +704,7 @@ based on unofficial sources which may be incomplete, inaccurate or outdated. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MPF.pm b/src/Image-ExifTool/lib/Image/ExifTool/MPF.pm index a6b5bd06..50d36aed 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/MPF.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/MPF.pm @@ -28,8 +28,8 @@ sub ProcessMPImageList($$$); from this segment is stored as a JPEG trailer. The MPF tags are not writable, however the MPF segment may be deleted as a group (with "MPF:All") but then the JPEG trailer should also be deleted (with "Trailer:All"). See - L<http://www.cipa.jp/std/documents/e/DC-007_E.pdf> for the official - specification. + L<https://web.archive.org/web/20190713230858/http://www.cipa.jp/std/documents/e/DC-007_E.pdf> + for the official specification. }, 0xb000 => 'MPFVersion', 0xb001 => 'NumberOfImages', @@ -97,7 +97,7 @@ sub ProcessMPImageList($$$); NOTES => q{ The first MPF "Large Thumbnail" image is extracted as PreviewImage, and the rest of the embedded MPF images are extracted as MPImage#. The - ExtractEmbedded (-ee) option may be used to extract information from these + L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> (-ee) option may be used to extract information from these embedded images. }, 0.1 => { @@ -163,7 +163,7 @@ sub ProcessMPImageList($$$); }, Notes => q{ the first MPF "Large Thumbnail" is extracted as PreviewImage, and the rest - of the embedded MPF images are extracted as MPImage#. The ExtractEmbedded + of the embedded MPF images are extracted as MPImage#. The L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> option may be used to extract information from these embedded images. }, # extract all MPF images (not just one) @@ -266,7 +266,7 @@ Format (MPF) information from JPEG images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MRC.pm b/src/Image-ExifTool/lib/Image/ExifTool/MRC.pm new file mode 100644 index 00000000..8fde7430 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/MRC.pm @@ -0,0 +1,341 @@ +#------------------------------------------------------------------------------ +# File: MRC.pm +# +# Description: Read MRC (Medical Research Council) image files +# +# Revisions: 2021-04-21 - P. Harvey Created +# +# References: 1) https://www.ccpem.ac.uk/mrc_format/mrc2014.php +# 2) http://legacy.ccp4.ac.uk/html/library.html +# 3) https://github.com/ccpem/mrcfile/blob/master/mrcfile/dtypes.py +# +# Notes: The header is basically identical to the older CCP4 file format +#------------------------------------------------------------------------------ + +package Image::ExifTool::MRC; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.00'; + +my %bool = ( + Format => 'int8u', + PrintConv => { 0 => 'No', 1 => 'Yes' } +); + +%Image::ExifTool::MRC::Main = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' }, + VARS => { NO_LOOKUP => 1 }, # omit tags from lookup + FORMAT => 'int32u', + NOTES => q{ + Tags extracted from Medical Research Council (MRC) format imaging files. + See L<https://www.ccpem.ac.uk/mrc_format/mrc2014.php> for the specification. + }, + 0 => 'ImageWidth', + 1 => 'ImageHeight', + 2 => { + Name => 'ImageDepth', + Notes => q{ + number of sections. Use ExtractEmbedded option to extract metadata for all + sections + }, + RawConv => '$$self{ImageDepth} = $val', + }, + 3 => { + Name => 'ImageMode', + PrintConv => { + 0 => '8-bit signed integer', + 1 => '16-bit signed integer', + 2 => '32-bit signed real', + 3 => 'complex 16-bit integer', + 4 => 'complex 32-bit real', + 6 => '16-bit unsigned integer', + }, + }, + 4 => { Name => 'StartPoint', Format => 'int32u[3]' }, + 7 => { Name => 'GridSize', Format => 'int32u[3]' }, + 10 => { Name => 'CellWidth', Format => 'float', Notes => 'cell size in angstroms' }, + 11 => { Name => 'CellHeight',Format => 'float' }, + 12 => { Name => 'CellDepth', Format => 'float' }, + 13 => { Name => 'CellAlpha', Format => 'float' }, + 14 => { Name => 'CellBeta', Format => 'float' }, + 15 => { Name => 'CellGamma', Format => 'float' }, + 16 => { Name => 'ImageWidthAxis', PrintConv => { 1 => 'X', 2 => 'Y', 3 => 'Z' } }, + 17 => { Name => 'ImageHeightAxis', PrintConv => { 1 => 'X', 2 => 'Y', 3 => 'Z' } }, + 18 => { Name => 'ImageDepthAxis', PrintConv => { 1 => 'X', 2 => 'Y', 3 => 'Z' } }, + 19 => { Name => 'DensityMin', Format => 'float' }, + 20 => { Name => 'DensityMax', Format => 'float' }, + 21 => { Name => 'DensityMean',Format => 'float' }, + 22 => 'SpaceGroupNumber', + 23 => { Name => 'ExtendedHeaderSize', RawConv => '$$self{ExtendedHeaderSize} = $val' }, + 26 => { Name => 'ExtendedHeaderType', Format => 'string[4]', RawConv => '$$self{ExtendedHeaderType} = $val' }, + 27 => 'MRCVersion', + 49 => { Name => 'Origin', Format => 'float[3]' }, + 53 => { Name => 'MachineStamp', Format => 'int8u[4]', PrintConv => 'sprintf("0x%.2x 0x%.2x 0x%.2x 0x%.2x",split " ", $val)' }, + 54 => { Name => 'RMSDeviation', Format => 'float' }, + 55 => { Name => 'NumberOfLabels', RawConv => '$$self{NLab} = $val' }, + 56 => { Name => 'Label0', Format => 'string[80]', Condition => '$$self{NLab} > 0' }, + 76 => { Name => 'Label1', Format => 'string[80]', Condition => '$$self{NLab} > 1' }, + 96 => { Name => 'Label2', Format => 'string[80]', Condition => '$$self{NLab} > 2' }, + 116 => { Name => 'Label3', Format => 'string[80]', Condition => '$$self{NLab} > 3' }, + 136 => { Name => 'Label4', Format => 'string[80]', Condition => '$$self{NLab} > 4' }, + 156 => { Name => 'Label5', Format => 'string[80]', Condition => '$$self{NLab} > 5' }, + 176 => { Name => 'Label6', Format => 'string[80]', Condition => '$$self{NLab} > 6' }, + 196 => { Name => 'Label7', Format => 'string[80]', Condition => '$$self{NLab} > 7' }, + 216 => { Name => 'Label8', Format => 'string[80]', Condition => '$$self{NLab} > 8' }, + 236 => { Name => 'Label9', Format => 'string[80]', Condition => '$$self{NLab} > 9' }, +); + +%Image::ExifTool::MRC::FEI12 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' }, + VARS => { NO_LOOKUP => 1 }, # omit tags from lookup (way too many!) + NOTES => 'Tags extracted from FEI1 and FEI2 extended headers.', + 0 => { Name => 'MetadataSize', Format => 'int32u', RawConv => '$$self{MetadataSize} = $val' }, + 4 => { Name => 'MetadataVersion', Format => 'int32u' }, + 8 => { + Name => 'Bitmask1', + Format => 'int32u', + RawConv => '$$self{BitM} = $val', + PrintConv => 'sprintf("0x%.8x", $val)', + }, + 12 => { + Name => 'TimeStamp', + Format => 'double', + Condition => '$$self{BitM} & 0x01', + Groups => { 2 => 'Time'}, + # shift from days since Dec 30, 1899 to Unix epoch of Jan 1, 1970 + # (my sample looks like local time, although it should be UTC) + ValueConv => 'ConvertUnixTime(($val-25569)*24*3600)', + PrintConv => '$self->ConvertDateTime($val)', + }, + 20 => { Name => 'MicroscopeType', Format => 'string[16]', Condition => '$$self{BitM} & 0x02' }, + 36 => { Name => 'MicroscopeID', Format => 'string[16]', Condition => '$$self{BitM} & 0x04' }, + 52 => { Name => 'Application', Format => 'string[16]', Condition => '$$self{BitM} & 0x08' }, + 68 => { Name => 'AppVersion', Format => 'string[16]', Condition => '$$self{BitM} & 0x10' }, + 84 => { Name => 'HighTension', Format => 'double', Condition => '$$self{BitM} & 0x20', Notes => 'volts' }, + 92 => { Name => 'Dose', Format => 'double', Condition => '$$self{BitM} & 0x40', Notes => 'electrons/m2' }, + 100 => { Name => 'AlphaTilt', Format => 'double', Condition => '$$self{BitM} & 0x80' }, + 108 => { Name => 'BetaTilt', Format => 'double', Condition => '$$self{BitM} & 0x100' }, + 116 => { Name => 'XStage', Format => 'double', Condition => '$$self{BitM} & 0x200' }, + 124 => { Name => 'YStage', Format => 'double', Condition => '$$self{BitM} & 0x400' }, + 132 => { Name => 'ZStage', Format => 'double', Condition => '$$self{BitM} & 0x800' }, + 140 => { Name => 'TiltAxisAngle', Format => 'double', Condition => '$$self{BitM} & 0x1000' }, + 148 => { Name => 'DualAxisRot', Format => 'double', Condition => '$$self{BitM} & 0x2000' }, + 156 => { Name => 'PixelSizeX', Format => 'double', Condition => '$$self{BitM} & 0x4000' }, + 164 => { Name => 'PixelSizeY', Format => 'double', Condition => '$$self{BitM} & 0x8000' }, + 220 => { Name => 'Defocus', Format => 'double', Condition => '$$self{BitM} & 0x400000' }, + 228 => { Name => 'STEMDefocus', Format => 'double', Condition => '$$self{BitM} & 0x800000' }, + 236 => { Name => 'AppliedDefocus', Format => 'double', Condition => '$$self{BitM} & 0x1000000' }, + 244 => { Name => 'InstrumentMode', Format => 'int32u', Condition => '$$self{BitM} & 0x2000000', PrintConv => { 1 => 'TEM', 2 => 'STEM' } }, + 248 => { Name => 'ProjectionMode', Format => 'int32u', Condition => '$$self{BitM} & 0x4000000', PrintConv => { 1 => 'Diffraction', 2 => 'Imaging' } }, + 252 => { Name => 'ObjectiveLens', Format => 'string[16]', Condition => '$$self{BitM} & 0x8000000' }, + 268 => { Name => 'HighMagnificationMode', Format => 'string[16]', Condition => '$$self{BitM} & 0x10000000' }, + 284 => { Name => 'ProbeMode', Format => 'int32u', Condition => '$$self{BitM} & 0x20000000', PrintConv => { 1 => 'Nano', 2 => 'Micro' } }, + 288 => { Name => 'EFTEMOn', %bool, Condition => '$$self{BitM} & 0x40000000' }, + 289 => { Name => 'Magnification', Format => 'double', Condition => '$$self{BitM} & 0x80000000' }, + 297 => { + Name => 'Bitmask2', + Format => 'int32u', + RawConv => '$$self{BitM} = $val', + PrintConv => 'sprintf("0x%.8x", $val)', + }, + 301 => { Name => 'CameraLength', Format => 'double', Condition => '$$self{BitM} & 0x01' }, + 309 => { Name => 'SpotIndex', Format => 'int32u', Condition => '$$self{BitM} & 0x02' }, + 313 => { Name => 'IlluminationArea',Format => 'double', Condition => '$$self{BitM} & 0x04' }, + 321 => { Name => 'Intensity', Format => 'double', Condition => '$$self{BitM} & 0x08' }, + 329 => { Name => 'ConvergenceAngle',Format => 'double', Condition => '$$self{BitM} & 0x10' }, + 337 => { Name => 'IlluminationMode',Format => 'string[16]', Condition => '$$self{BitM} & 0x20' }, + 353 => { Name => 'WideConvergenceAngleRange', %bool, Condition => '$$self{BitM} & 0x40' }, + 354 => { Name => 'SlitInserted', %bool, Condition => '$$self{BitM} & 0x80' }, + 355 => { Name => 'SlitWidth', Format => 'double', Condition => '$$self{BitM} & 0x100' }, + 363 => { Name => 'AccelVoltOffset', Format => 'double', Condition => '$$self{BitM} & 0x200' }, + 371 => { Name => 'DriftTubeVolt', Format => 'double', Condition => '$$self{BitM} & 0x400' }, + 379 => { Name => 'EnergyShift', Format => 'double', Condition => '$$self{BitM} & 0x800' }, + 387 => { Name => 'ShiftOffsetX', Format => 'double', Condition => '$$self{BitM} & 0x1000' }, + 395 => { Name => 'ShiftOffsetY', Format => 'double', Condition => '$$self{BitM} & 0x2000' }, + 403 => { Name => 'ShiftX', Format => 'double', Condition => '$$self{BitM} & 0x4000' }, + 411 => { Name => 'ShiftY', Format => 'double', Condition => '$$self{BitM} & 0x8000' }, + 419 => { Name => 'IntegrationTime', Format => 'double', Condition => '$$self{BitM} & 0x10000' }, + 427 => { Name => 'BinningWidth', Format => 'int32u', Condition => '$$self{BitM} & 0x20000' }, + 431 => { Name => 'BinningHeight', Format => 'int32u', Condition => '$$self{BitM} & 0x40000' }, + 435 => { Name => 'CameraName', Format => 'string[16]', Condition => '$$self{BitM} & 0x80000' }, + 451 => { Name => 'ReadoutAreaLeft', Format => 'int32u', Condition => '$$self{BitM} & 0x100000' }, + 455 => { Name => 'ReadoutAreaTop', Format => 'int32u', Condition => '$$self{BitM} & 0x200000' }, + 459 => { Name => 'ReadoutAreaRight',Format => 'int32u', Condition => '$$self{BitM} & 0x400000' }, + 463 => { Name => 'ReadoutAreaBottom',Format=> 'int32u', Condition => '$$self{BitM} & 0x800000' }, + 467 => { Name => 'CetaNoiseReduct', %bool, Condition => '$$self{BitM} & 0x1000000' }, + 468 => { Name => 'CetaFramesSummed',Format => 'int32u', Condition => '$$self{BitM} & 0x2000000' }, + 472 => { Name => 'DirectDetElectronCounting', %bool, Condition => '$$self{BitM} & 0x4000000' }, + 473 => { Name => 'DirectDetAlignFrames', %bool, Condition => '$$self{BitM} & 0x8000000' }, + 490 => { + Name => 'Bitmask3', + Format => 'int32u', + RawConv => '$$self{BitM} = $val', + PrintConv => 'sprintf("0x%.8x", $val)', + }, + 518 => { Name => 'PhasePlate', %bool, Condition => '$$self{BitM} & 0x40' }, + 519 => { Name => 'STEMDetectorName',Format => 'string[16]', Condition => '$$self{BitM} & 0x80' }, + 535 => { Name => 'Gain', Format => 'double', Condition => '$$self{BitM} & 0x100' }, + 543 => { Name => 'Offset', Format => 'double', Condition => '$$self{BitM} & 0x200' }, + 571 => { Name => 'DwellTime', Format => 'double', Condition => '$$self{BitM} & 0x8000' }, + 579 => { Name => 'FrameTime', Format => 'double', Condition => '$$self{BitM} & 0x10000' }, + 587 => { Name => 'ScanSizeLeft', Format => 'int32u', Condition => '$$self{BitM} & 0x20000' }, + 591 => { Name => 'ScanSizeTop', Format => 'int32u', Condition => '$$self{BitM} & 0x40000' }, + 595 => { Name => 'ScanSizeRight', Format => 'int32u', Condition => '$$self{BitM} & 0x80000' }, + 599 => { Name => 'ScanSizeBottom', Format => 'int32u', Condition => '$$self{BitM} & 0x100000' }, + 603 => { Name => 'FullScanFOV_X', Format => 'double', Condition => '$$self{BitM} & 0x200000' }, + 611 => { Name => 'FullScanFOV_Y', Format => 'double', Condition => '$$self{BitM} & 0x400000' }, + 619 => { Name => 'Element', Format => 'string[16]', Condition => '$$self{BitM} & 0x800000' }, + 635 => { Name => 'EnergyIntervalLower', Format => 'double', Condition => '$$self{BitM} & 0x1000000' }, + 643 => { Name => 'EnergyIntervalHigher',Format => 'double', Condition => '$$self{BitM} & 0x2000000' }, + 651 => { Name => 'Method', Format=> 'int32u', Condition => '$$self{BitM} & 0x4000000' }, + 655 => { Name => 'IsDoseFraction', %bool, Condition => '$$self{BitM} & 0x8000000' }, + 656 => { Name => 'FractionNumber', Format => 'int32u', Condition => '$$self{BitM} & 0x10000000' }, + 660 => { Name => 'StartFrame', Format => 'int32u', Condition => '$$self{BitM} & 0x20000000' }, + 664 => { Name => 'EndFrame', Format => 'int32u', Condition => '$$self{BitM} & 0x40000000' }, + 668 => { Name =>'InputStackFilename',Format=> 'string[80]', Condition => '$$self{BitM} & 0x80000000' }, + 748 => { + Name => 'Bitmask4', + Format => 'int32u', + RawConv => '$$self{BitM} = $val', + PrintConv => 'sprintf("0x%.8x", $val)', + }, + 752 => { Name => 'AlphaTiltMin', Format => 'double', Condition => '$$self{BitM} & 0x01' }, + 760 => { Name => 'AlphaTiltMax', Format => 'double', Condition => '$$self{BitM} & 0x02' }, +# +# FEI2 header starts here +# + 768 => { Name => 'ScanRotation', Format => 'double', Condition => '$$self{BitM} & 0x04' }, + 776 => { Name => 'DiffractionPatternRotation',Format=>'double', Condition => '$$self{BitM} & 0x08' }, + 784 => { Name => 'ImageRotation', Format => 'double', Condition => '$$self{BitM} & 0x10' }, + 792 => { Name => 'ScanModeEnumeration',Format => 'int32u', Condition => '$$self{BitM} & 0x20', PrintConv => { 0 => 'Other', 1 => 'Raster', 2 => 'Serpentine' } }, + 796 => { + Name => 'AcquisitionTimeStamp', + Format => 'int64u', + Condition => '$$self{BitM} & 0x40', + Groups => { 2 => 'Time' }, + # microseconds since 1970 UTC + ValueConv => 'ConvertUnixTime($val / 1e6, 1, 6)', + PrintConv => '$self->ConvertDateTime($val)', + }, + 804 => { Name => 'DetectorCommercialName', Format => 'string[16]', Condition => '$$self{BitM} & 0x80' }, + 820 => { Name => 'StartTiltAngle', Format => 'double', Condition => '$$self{BitM} & 0x100' }, + 828 => { Name => 'EndTiltAngle', Format => 'double', Condition => '$$self{BitM} & 0x200' }, + 836 => { Name => 'TiltPerImage', Format => 'double', Condition => '$$self{BitM} & 0x400' }, + 844 => { Name => 'TitlSpeed', Format => 'double', Condition => '$$self{BitM} & 0x800' }, + 852 => { Name => 'BeamCenterX', Format => 'int32u', Condition => '$$self{BitM} & 0x1000' }, + 856 => { Name => 'BeamCenterY', Format => 'int32u', Condition => '$$self{BitM} & 0x2000' }, + 860 => { + Name => 'CFEGFlashTimeStamp', + Format => 'int64u', + Condition => '$$self{BitM} & 0x4000', + Groups => { 2 => 'Time' }, + ValueConv => 'ConvertUnixTime($val / 1e6, 1, 6)', + PrintConv => '$self->ConvertDateTime($val)', + }, + 868 => { Name => 'PhasePlatePosition',Format => 'int32u', Condition => '$$self{BitM} & 0x8000' }, + 872 => { Name => 'ObjectiveAperture', Format=>'string[16]',Condition => '$$self{BitM} & 0x10000' }, +); + +#------------------------------------------------------------------------------ +# Extract metadata from a MRC image +# Inputs: 0) ExifTool object reference, 1) dirInfo reference +# Returns: 1 on success, 0 if this wasn't a valid MRC file +sub ProcessMRC($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my ($buff, $tagTablePtr, $i); + + # verify this is a valid MRC file + return 0 unless $raf->Read($buff, 1024) == 1024; + # validate axes, "MAP" file type and machine stamp + return 0 unless $buff =~ /^.{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/s; + + $et->SetFileType(); + SetByteOrder('II'); + my %dirInfo = ( + DataPt => \$buff, + DirStart => 0, + DirLen => length($buff), + ); + $tagTablePtr = GetTagTable('Image::ExifTool::MRC::Main'); + $et->ProcessDirectory(\%dirInfo, $tagTablePtr); + + # (I don't have any samples with extended headers for testing, so these are not yet decoded) + if ($$et{ExtendedHeaderSize} and $$et{ExtendedHeaderType} =~ /^FEI[12]/) { + unless ($raf->Read($buff,4)==4 and $raf->Seek(-4,1)) { # read metadata size + $et->Warn('Error reading extended header'); + return 1; + } + my $size = Get32u(\$buff, 0); + if ($size * $$et{ImageDepth} > $$et{ExtendedHeaderSize}) { + $et->Warn('Corrupted extended header'); + return 1; + } + $dirInfo{DirLen} = $size; + $tagTablePtr = GetTagTable('Image::ExifTool::MRC::FEI12'); + for ($i=0; ;) { + $dirInfo{DataPos} = $raf->Tell(); + $raf->Read($buff, $size) == $size or $et->Warn("Error reading extended header $i"), last; + $et->ProcessDirectory(\%dirInfo, $tagTablePtr); + last if ++$i >= $$et{ImageDepth}; + unless ($$et{OPTIONS}{ExtractEmbedded}) { + $et->Warn('Use the ExtractEmbedded option to read metadata for all frames',3); + last; + } + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + } + delete $$et{DOC_NUM}; + } + + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::MRC - Read MRC meta information + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to read +metadata from Medical Research Council (MRC) images. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<https://www.ccpem.ac.uk/mrc_format/mrc2014.php> + +=item L<http://legacy.ccp4.ac.uk/html/library.html> + +=item L<https://github.com/ccpem/mrcfile/blob/master/mrcfile/dtypes.py> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/MRC Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MWG.pm b/src/Image-ExifTool/lib/Image/ExifTool/MWG.pm index d63fe225..3d7be229 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/MWG.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/MWG.pm @@ -16,7 +16,7 @@ use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; use Image::ExifTool::XMP; -$VERSION = '1.22'; +$VERSION = '1.24'; sub RecoverTruncatedIPTC($$$); sub ListToString($); @@ -29,6 +29,7 @@ my $mwgLoaded; # flag set if we alreaded Load()ed the MWG tags %Image::ExifTool::MWG::Composite = ( GROUPS => { 0 => 'Composite', 1 => 'MWG', 2 => 'Image' }, VARS => { NO_ID => 1 }, + WRITE_PROC => \&Image::ExifTool::DummyWriteProc, NOTES => q{ The table below lists special Composite tags which are used to access other tags based on the MWG 2.0 recommendations. These tags are only accessible @@ -59,7 +60,7 @@ my $mwgLoaded; # flag set if we alreaded Load()ed the MWG tags string values be stored as UTF-8. To honour this, the exiftool application sets the default internal EXIF string encoding to "UTF8" when the MWG module is loaded, but via the API this must be done manually by setting the - CharsetEXIF option. + L<CharsetEXIF|../ExifTool.html#CharsetEXIF> option. A complication of the MWG specification is that although the MWG:Creator property may consist of multiple values, the associated EXIF tag @@ -116,7 +117,7 @@ my $mwgLoaded; # flag set if we alreaded Load()ed the MWG tags DateTimeOriginal => { Description => 'Date/Time Original', Groups => { 2 => 'Time' }, - Notes => '"creation date of the intellectual content being shown" - MWG', + Notes => '"specifies when a photo was taken" - MWG', Writable => 1, Shift => 0, # don't shift this tag Desire => { @@ -158,7 +159,7 @@ my $mwgLoaded; # flag set if we alreaded Load()ed the MWG tags }, CreateDate => { Groups => { 2 => 'Time' }, - Notes => '"creation date of the digital representation" - MWG', + Notes => '"specifies when an image was digitized" - MWG', Writable => 1, Shift => 0, # don't shift this tag Desire => { @@ -196,7 +197,7 @@ my $mwgLoaded; # flag set if we alreaded Load()ed the MWG tags }, ModifyDate => { Groups => { 2 => 'Time' }, - Notes => '"modification date of the digital image file" - MWG', + Notes => '"specifies when a file was modified by the user" - MWG', Writable => 1, Shift => 0, # don't shift this tag Desire => { @@ -459,7 +460,8 @@ my %sKeywordStruct; NOTES => q{ Image region metadata defined by the MWG 2.0 specification. These tags may be accessed without the need to load the MWG Composite tags above. See - L<http://www.metadataworkinggroup.org/> for the official specification. + L<https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf> + for the official specification. }, Regions => { Name => 'RegionInfo', @@ -487,8 +489,9 @@ my %sKeywordStruct; Hierarchical keywords metadata defined by the MWG 2.0 specification. ExifTool unrolls keyword structures to an arbitrary depth of 6 to allow individual levels to be accessed with different tag names, and to avoid - infinite recursion. See L<http://www.metadataworkinggroup.org/> for the - official specification. + infinite recursion. See + L<https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf> + for the official specification. }, # arbitrarily define only the first 6 levels of the keyword hierarchy Keywords => { @@ -526,7 +529,8 @@ my %sKeywordStruct; NAMESPACE => 'mwg-coll', NOTES => q{ Collections metadata defined by the MWG 2.0 specification. See - L<http://www.metadataworkinggroup.org/> for the official specification. + L<https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf> + for the official specification. }, Collections => { FlatName => '', @@ -625,6 +629,14 @@ sub OverwriteStringList($$$$) local $_; my ($et, $nvHash, $val, $newValuePt) = @_; my (@new, $delIndex); + my $writeMode = $et->Options('WriteMode'); + if ($writeMode ne 'wcg') { + if (defined $val) { + $writeMode =~ /w/i or return 0; + } else { + $writeMode =~ /c/i or return 0; + } + } if ($$nvHash{DelValue} and defined $val) { # preserve specified old values my $old = StringToList($val, $et); @@ -744,7 +756,7 @@ must be loaded explicitly as described above. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MXF.pm b/src/Image-ExifTool/lib/Image/ExifTool/MXF.pm index 45d30b3b..84d67a05 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/MXF.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/MXF.pm @@ -1066,7 +1066,7 @@ my %componentDataDef = ( '060e2b34.0101.0102.04010503.08000000' => { Name => 'Palette', Type => 'DataValue', Unknown => 1 }, '060e2b34.0101.0102.04010503.09000000' => { Name => 'PaletteLayout', Type => 'RGBALayout', Unknown => 1 }, '060e2b34.0101.0102.04010503.0a000000' => { Name => 'ComponentDepth', Format => 'int32u' }, - '060e2b34.0101.0102.04010601.00000000' => { Name => 'VideoCodingSchemeID', Type => 'AUID', Unknown => 1 }, + '060e2b34.0101.0102.04010601.00000000' => { Name => 'VideoCodingSchemeID', Type => 'AUID' }, '060e2b34.0101.0102.04010802.03000000' => { Name => 'RoundedCaptureFilmFrameRate', Format => 'int32u' }, '060e2b34.0101.0102.04020301.02000000' => { Name => 'AudioAverageBitrate', Format => 'float', PrintConv => 'ConvertBitrate($val)', Groups => { 2 => 'Audio' } }, '060e2b34.0101.0102.04020301.03000000' => { Name => 'AudioFixedBitrateFlag', Type => 'Boolean', Groups => { 2 => 'Audio' } }, @@ -2987,7 +2987,7 @@ information from MXF (Material Exchange Format) files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MacOS.pm b/src/Image-ExifTool/lib/Image/ExifTool/MacOS.pm new file mode 100644 index 00000000..7803f334 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/MacOS.pm @@ -0,0 +1,735 @@ +#------------------------------------------------------------------------------ +# File: MacOS.pm +# +# Description: Read/write MacOS system tags +# +# Revisions: 2017/03/01 - P. Harvey Created +# 2020/10/13 - PH Added ability to read MacOS "._" files +#------------------------------------------------------------------------------ + +package Image::ExifTool::MacOS; +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.12'; + +sub MDItemLocalTime($); +sub ProcessATTR($$$); + +my %mdDateInfo = ( + ValueConv => \&MDItemLocalTime, + PrintConv => '$self->ConvertDateTime($val)', +); + +# Information decoded from Mac OS sidecar files +%Image::ExifTool::MacOS::Main = ( + GROUPS => { 0 => 'File', 1 => 'MacOS' }, + NOTES => q{ + Note that on some filesystems, MacOS creates sidecar files with names that + begin with "._". ExifTool will read these files if specified, and extract + the information listed in the following table without the need for extra + options, but these files are not writable directly. + }, + 2 => { + Name => 'RSRC', + SubDirectory => { TagTable => 'Image::ExifTool::RSRC::Main' }, + }, + 9 => { + Name => 'ATTR', + SubDirectory => { + TagTable => 'Image::ExifTool::MacOS::XAttr', + ProcessProc => \&ProcessATTR, + }, + }, +); + +# "mdls" tags (ref PH) +%Image::ExifTool::MacOS::MDItem = ( + WRITE_PROC => \&Image::ExifTool::DummyWriteProc, + VARS => { NO_ID => 1 }, + GROUPS => { 0 => 'File', 1 => 'MacOS', 2 => 'Other' }, + NOTES => q{ + MDItem tags are extracted using the "mdls" utility. They are extracted if + any "MDItem*" tag or the MacOS group is specifically requested, or by + setting the API L<MDItemTags|../ExifTool.html#MDItemTags> option to 1 or the API L<RequestAll|../ExifTool.html#RequestAll> option to 2 or + higher. Note that these tags do not necessarily reflect the current + metadata of a file -- it may take some time for the MacOS mdworker daemon to + index the file after a metadata change. + }, + MDItemFinderComment => { + Writable => 1, + WritePseudo => 1, + Protected => 1, # (all writable pseudo tags must be protected) + }, + MDItemFSLabel => { + Writable => 1, + WritePseudo => 1, + Protected => 1, # (all writable pseudo tags must be protected) + WriteCheck => '$val =~ /^[0-7]$/ ? undef : "Not an integer in the range 0-7"', + PrintConv => { + 0 => '0 (none)', + 1 => '1 (Gray)', + 2 => '2 (Green)', + 3 => '3 (Purple)', + 4 => '4 (Blue)', + 5 => '5 (Yellow)', + 6 => '6 (Red)', + 7 => '7 (Orange)', + }, + }, + MDItemFSCreationDate => { + Writable => 1, + WritePseudo => 1, + DelCheck => q{"Can't delete"}, + Protected => 1, # (all writable pseudo tags must be protected) + Shift => 'Time', # (but not supported yet) + Notes => q{ + file creation date. Requires "setfile" for writing. Note that when + reading, it may take a few seconds after writing a file before this value + reflects the change. However, L<FileCreateDate|Extra.html> is updated immediately + }, + Groups => { 2 => 'Time' }, + ValueConv => \&MDItemLocalTime, + ValueConvInv => '$val', + PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val)', + }, + MDItemAcquisitionMake => { Groups => { 2 => 'Camera' } }, + MDItemAcquisitionModel => { Groups => { 2 => 'Camera' } }, + MDItemAltitude => { Groups => { 2 => 'Location' } }, + MDItemAperture => { Groups => { 2 => 'Camera' } }, + MDItemAudioBitRate => { Groups => { 2 => 'Audio' } }, + MDItemAudioChannelCount => { Groups => { 2 => 'Audio' } }, + MDItemAuthors => { Groups => { 2 => 'Author' } }, + MDItemBitsPerSample => { Groups => { 2 => 'Image' } }, + MDItemCity => { Groups => { 2 => 'Location' } }, + MDItemCodecs => { }, + MDItemColorSpace => { Groups => { 2 => 'Image' } }, + MDItemComment => { }, + MDItemContentCreationDate => { Groups => { 2 => 'Time' }, %mdDateInfo }, + MDItemContentCreationDateRanking => { Groups => { 2 => 'Time' }, %mdDateInfo }, + MDItemContentModificationDate => { Groups => { 2 => 'Time' }, %mdDateInfo }, + MDItemContentType => { }, + MDItemContentTypeTree => { }, + MDItemContributors => { }, + MDItemCopyright => { Groups => { 2 => 'Author' } }, + MDItemCountry => { Groups => { 2 => 'Location' } }, + MDItemCreator => { Groups => { 2 => 'Document' } }, + MDItemDateAdded => { Groups => { 2 => 'Time' }, %mdDateInfo }, + MDItemDescription => { }, + MDItemDisplayName => { }, + MDItemDownloadedDate => { Groups => { 2 => 'Time' }, %mdDateInfo }, + MDItemDurationSeconds => { PrintConv => 'ConvertDuration($val)' }, + MDItemEncodingApplications => { }, + MDItemEXIFGPSVersion => { Groups => { 2 => 'Location' }, Description => 'MD Item EXIF GPS Version' }, + MDItemEXIFVersion => { }, + MDItemExposureMode => { Groups => { 2 => 'Camera' } }, + MDItemExposureProgram => { Groups => { 2 => 'Camera' } }, + MDItemExposureTimeSeconds => { Groups => { 2 => 'Camera' } }, + MDItemFlashOnOff => { Groups => { 2 => 'Camera' } }, + MDItemFNumber => { Groups => { 2 => 'Camera' } }, + MDItemFocalLength => { Groups => { 2 => 'Camera' } }, + MDItemFSContentChangeDate => { Groups => { 2 => 'Time' }, %mdDateInfo }, + MDItemFSCreatorCode => { Groups => { 2 => 'Author' } }, + MDItemFSFinderFlags => { }, + MDItemFSHasCustomIcon => { }, + MDItemFSInvisible => { }, + MDItemFSIsExtensionHidden => { }, + MDItemFSIsStationery => { }, + MDItemFSName => { }, + MDItemFSNodeCount => { }, + MDItemFSOwnerGroupID => { }, + MDItemFSOwnerUserID => { }, + MDItemFSSize => { }, + MDItemFSTypeCode => { }, + MDItemGPSDateStamp => { Groups => { 2 => 'Time' } }, + MDItemGPSStatus => { Groups => { 2 => 'Location' } }, + MDItemGPSTrack => { Groups => { 2 => 'Location' } }, + MDItemHasAlphaChannel => { Groups => { 2 => 'Image' } }, + MDItemImageDirection => { Groups => { 2 => 'Location' } }, + MDItemInterestingDateRanking => { Groups => { 2 => 'Time' }, %mdDateInfo }, + MDItemISOSpeed => { Groups => { 2 => 'Camera' } }, + MDItemKeywords => { }, + MDItemKind => { }, + MDItemLastUsedDate => { Groups => { 2 => 'Time' }, %mdDateInfo }, + MDItemLastUsedDate_Ranking => { }, + MDItemLatitude => { Groups => { 2 => 'Location' } }, + MDItemLensModel => { }, + MDItemLogicalSize => { }, + MDItemLongitude => { Groups => { 2 => 'Location' } }, + MDItemMediaTypes => { }, + MDItemNumberOfPages => { }, + MDItemOrientation => { Groups => { 2 => 'Image' } }, + MDItemOriginApplicationIdentifier => { }, + MDItemOriginMessageID => { }, + MDItemOriginSenderDisplayName => { }, + MDItemOriginSenderHandle => { }, + MDItemOriginSubject => { }, + MDItemPageHeight => { Groups => { 2 => 'Image' } }, + MDItemPageWidth => { Groups => { 2 => 'Image' } }, + MDItemPhysicalSize => { Groups => { 2 => 'Image' } }, + MDItemPixelCount => { Groups => { 2 => 'Image' } }, + MDItemPixelHeight => { Groups => { 2 => 'Image' } }, + MDItemPixelWidth => { Groups => { 2 => 'Image' } }, + MDItemProfileName => { Groups => { 2 => 'Image' } }, + MDItemRedEyeOnOff => { Groups => { 2 => 'Camera' } }, + MDItemResolutionHeightDPI => { Groups => { 2 => 'Image' } }, + MDItemResolutionWidthDPI => { Groups => { 2 => 'Image' } }, + MDItemSecurityMethod => { }, + MDItemSpeed => { Groups => { 2 => 'Location' } }, + MDItemStateOrProvince => { Groups => { 2 => 'Location' } }, + MDItemStreamable => { }, + MDItemTimestamp => { Groups => { 2 => 'Time' } }, # (time only) + MDItemTitle => { }, + MDItemTotalBitRate => { }, + MDItemUseCount => { }, + MDItemUsedDates => { Groups => { 2 => 'Time' }, %mdDateInfo }, + MDItemUserDownloadedDate => { Groups => { 2 => 'Time' }, %mdDateInfo }, + MDItemUserDownloadedUserHandle=> { }, + MDItemUserSharedReceivedDate => { }, + MDItemUserSharedReceivedRecipient => { }, + MDItemUserSharedReceivedRecipientHandle => { }, + MDItemUserSharedReceivedSender=> { }, + MDItemUserSharedReceivedSenderHandle => { }, + MDItemUserSharedReceivedTransport => { }, + MDItemUserTags => { + List => 1, + Writable => 1, + WritePseudo => 1, + Protected => 1, # (all writable pseudo tags must be protected) + Notes => q{ + requires "tag" utility for writing -- install with "brew install tag". Note + that user tags may not contain a comma, and that duplicate user tags will + not be written + }, + }, + MDItemVersion => { }, + MDItemVideoBitRate => { Groups => { 2 => 'Video' } }, + MDItemWhereFroms => { }, + MDItemWhiteBalance => { Groups => { 2 => 'Image' } }, + # tags used by Apple Mail on .emlx files + com_apple_mail_dateReceived => { Name => 'AppleMailDateReceived', Groups => { 2 => 'Time' }, %mdDateInfo }, + com_apple_mail_dateSent => { Name => 'AppleMailDateSent', Groups => { 2 => 'Time' }, %mdDateInfo }, + com_apple_mail_flagged => { Name => 'AppleMailFlagged' }, + com_apple_mail_messageID => { Name => 'AppleMailMessageID' }, + com_apple_mail_priority => { Name => 'AppleMailPriority' }, + com_apple_mail_read => { Name => 'AppleMailRead' }, + com_apple_mail_repliedTo => { Name => 'AppleMailRepliedTo' }, + com_apple_mail_isRemoteAttachment => { Name => 'AppleMailIsRemoteAttachment' }, + MDItemAccountHandles => { }, + MDItemAccountIdentifier => { }, + MDItemAuthorEmailAddresses => { }, + MDItemBundleIdentifier => { }, + MDItemContentCreationDate_Ranking=>{Groups=> { 2 => 'Time' }, %mdDateInfo }, + MDItemDateAdded_Ranking => { Groups => { 2 => 'Time' }, %mdDateInfo }, + MDItemEmailConversationID => { }, + MDItemIdentifier => { }, + MDItemInterestingDate_Ranking => { Groups => { 2 => 'Time' }, %mdDateInfo }, + MDItemIsApplicationManaged => { }, + MDItemIsExistingThread => { }, + MDItemIsLikelyJunk => { }, + MDItemMailboxes => { }, + MDItemMailDateReceived_Ranking=> { Groups => { 2 => 'Time' }, %mdDateInfo }, + MDItemPrimaryRecipientEmailAddresses => { }, + MDItemRecipients => { }, + MDItemSubject => { }, +); + +# "xattr" tags +%Image::ExifTool::MacOS::XAttr = ( + WRITE_PROC => \&Image::ExifTool::DummyWriteProc, + GROUPS => { 0 => 'File', 1 => 'MacOS', 2 => 'Other' }, + VARS => { NO_ID => 1 }, # (id's are too long) + NOTES => q{ + XAttr tags are extracted using the "xattr" utility. They are extracted if + any "XAttr*" tag or the MacOS group is specifically requested, or by setting + the API L<XAttrTags|../ExifTool.html#XAttrTags> option to 1 or the API L<RequestAll|../ExifTool.html#RequestAll> option to 2 or higher. + And they are extracted by default from MacOS "._" files when reading + these files directly. + }, + 'com.apple.FinderInfo' => { + Name => 'XAttrFinderInfo', + ConvertBinary => 1, + # ref https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-9A581/Finder.h + ValueConv => q{ + my @a = unpack('a4a4n3x10nx2N', $$val); + tr/\0//d, $_="'${_}'" foreach @a[0,1]; + return "@a"; + }, + PrintConv => q{ + $val =~ s/^('.*?') ('.*?') //s or return $val; + my ($type, $creator) = ($1, $2); + my ($flags, $y, $x, $exFlags, $putAway) = split ' ', $val; + my $label = ($flags >> 1) & 0x07; + my $flags = DecodeBits((($exFlags<<16) | $flags) & 0xfff1, { + 0 => 'OnDesk', + 6 => 'Shared', + 7 => 'HasNoInits', + 8 => 'Inited', + 10 => 'CustomIcon', + 11 => 'Stationery', + 12 => 'NameLocked', + 13 => 'HasBundle', + 14 => 'Invisible', + 15 => 'Alias', + # extended flags + 22 => 'HasRoutingInfo', + 23 => 'ObjectBusy', + 24 => 'CustomBadge', + 31 => 'ExtendedFlagsValid', + }); + my $str = "Type=$type Creator=$creator Flags=$flags Label=$label Pos=($x,$y)"; + $str .= " Putaway=$putAway" if $putAway; + return $str; + }, + }, + 'com.apple.quarantine' => { + Name => 'XAttrQuarantine', + Writable => 1, + WritePseudo => 1, + WriteCheck => '"May only delete this tag"', + Protected => 1, + Notes => q{ + quarantine information for files downloaded from the internet. May only be + deleted when writing + }, + # ($a[1] is the time when the quarantine tag was set) + PrintConv => q{ + my @a = split /;/, $val; + $a[0] = 'Flags=' . $a[0]; + $a[1] = 'set at ' . ConvertUnixTime(hex $a[1]); + $a[2] = 'by ' . $a[2]; + return join ' ', @a; + }, + PrintConvInv => '$val', + }, + 'com.apple.metadata:com_apple_mail_dateReceived' => { + Name => 'XAttrAppleMailDateReceived', + Groups => { 2 => 'Time' }, + }, + 'com.apple.metadata:com_apple_mail_dateSent' => { + Name => 'XAttrAppleMailDateSent', + Groups => { 2 => 'Time' }, + }, + 'com.apple.metadata:com_apple_mail_isRemoteAttachment' => { + Name => 'XAttrAppleMailIsRemoteAttachment', + }, + 'com.apple.metadata:kMDItemDownloadedDate' => { + Name => 'XAttrMDItemDownloadedDate', + Groups => { 2 => 'Time' }, + }, + 'com.apple.metadata:kMDItemFinderComment' => { Name => 'XAttrMDItemFinderComment' }, + 'com.apple.metadata:kMDItemWhereFroms' => { Name => 'XAttrMDItemWhereFroms' }, + 'com.apple.metadata:kMDLabel' => { Name => 'XAttrMDLabel', Binary => 1 }, + 'com.apple.ResourceFork' => { Name => 'XAttrResourceFork', Binary => 1 }, + 'com.apple.lastuseddate#PS' => { + Name => 'XAttrLastUsedDate', + Groups => { 2 => 'Time' }, + # (first 4 bytes are date/time. Not sure what remaining 12 bytes are for) + RawConv => 'ConvertUnixTime(unpack("V",$$val))', + PrintConv => '$self->ConvertDateTime($val)', + }, +); + +#------------------------------------------------------------------------------ +# Convert OS MDItem time string to standard EXIF-formatted local time +# Inputs: 0) time string (eg. "2017-02-21 17:21:43 +0000") +# Returns: EXIF-formatted local time string with timezone +sub MDItemLocalTime($) +{ + my $val = shift; + $val =~ tr/-/:/; + $val =~ s/ ?([-+]\d{2}):?(\d{2})/$1:$2/; + # convert from UTC to local time + if ($val =~ /\+00:00$/) { + my $time = Image::ExifTool::GetUnixTime($val); + $val = Image::ExifTool::ConvertUnixTime($time, 1) if $time; + } + return $val; +} + +#------------------------------------------------------------------------------ +# Set MacOS MDItem and XAttr tags from new tag values +# Inputs: 0) ExifTool ref, 1) file name, 2) list of tags to set +# Returns: 1=something was set OK, 0=didn't try, -1=error (and warning set) +# Notes: There may be errors even if 1 is returned +sub SetMacOSTags($$$) +{ + my ($et, $file, $setTags) = @_; + my $result = 0; + my $tag; + + foreach $tag (@$setTags) { + my ($nvHash, $f, $v, $attr, $cmd, $err, $silentErr); + my $val = $et->GetNewValue($tag, \$nvHash); + next unless $nvHash; + my $overwrite = $et->IsOverwriting($nvHash); + unless ($$nvHash{TagInfo}{List}) { + next unless $overwrite; + if ($overwrite < 0) { + my $operation = $$nvHash{Shift} ? 'Shifting' : 'Conditional replacement'; + $et->Warn("$operation of MacOS $tag not yet supported"); + next; + } + } + if ($tag eq 'MDItemFSCreationDate' or $tag eq 'FileCreateDate') { + ($f = $file) =~ s/'/'\\''/g; + # convert to local time if value has a time zone + if ($val =~ /[-+Z]/) { + my $time = Image::ExifTool::GetUnixTime($val, 1); + $val = Image::ExifTool::ConvertUnixTime($time, 1) if $time; + } + $val =~ s{(\d{4}):(\d{2}):(\d{2})}{$2/$3/$1}; # reformat for setfile + $cmd = "/usr/bin/setfile -d '${val}' '${f}'"; + } elsif ($tag eq 'MDItemUserTags') { + # (tested with "tag" version 0.9.0) + ($f = $file) =~ s/'/'\\''/g; + my @vals = $et->GetNewValue($nvHash); + if ($overwrite < 0 and @{$$nvHash{DelValue}}) { + # delete specified tags + my @dels = @{$$nvHash{DelValue}}; + s/'/'\\''/g foreach @dels; + my $del = join ',', @dels; + $err = system "/usr/local/bin/tag -r '${del}' '${f}'>/dev/null 2>&1"; + unless ($err) { + $et->VerboseValue("- $tag", $del); + $result = 1; + undef $err if @vals; # more to do if there are tags to add + } + } + unless (defined $err) { + # add new tags, or overwrite or delete existing tags + s/'/'\\''/g foreach @vals; + my $opt = $overwrite > 0 ? '-s' : '-a'; + $val = @vals ? join(',', @vals) : ''; + $cmd = "/usr/local/bin/tag $opt '${val}' '${f}'"; + $et->VPrint(1," - $tag = (all)\n") if $overwrite > 0; + undef $val if $val eq ''; + } + } elsif ($tag eq 'XAttrQuarantine') { + ($f = $file) =~ s/'/'\\''/g; + $cmd = "/usr/bin/xattr -d com.apple.quarantine '${f}'"; + $silentErr = 256; # (will get this error if attribute doesn't exist) + } else { + ($f = $file) =~ s/(["\\])/\\$1/g; # escape necessary characters for script + $f =~ s/'/'"'"'/g; + if ($tag eq 'MDItemFinderComment') { + # (write finder comment using osascript instead of xattr + # because it is more work to construct the necessary bplist) + $val = '' unless defined $val; # set to empty string instead of deleting + $v = $et->Encode($val, 'UTF8'); + $v =~ s/(["\\])/\\$1/g; + $v =~ s/'/'"'"'/g; + $attr = 'comment'; + } else { # $tag eq 'MDItemFSLabel' + $v = $val ? 8 - $val : 0; # convert from label to label index (0 for no label) + $attr = 'label index'; + } + $cmd = qq(/usr/bin/osascript -e 'set fp to POSIX file "$f" as alias' -e \\ + 'tell application "Finder" to set $attr of file fp to "$v"'); + } + if (defined $cmd) { + $err = system $cmd . '>/dev/null 2>&1'; # (pipe all output to /dev/null) + } + if (not $err) { + $et->VerboseValue("+ $tag", $val) if defined $val; + $result = 1; + } elsif (not $silentErr or $err != $silentErr) { + $cmd =~ s/ .*//s; + $et->Warn(qq{Error $err running "$cmd" to set $tag}); + $result = -1 unless $result; + } + } + return $result; +} + +#------------------------------------------------------------------------------ +# Extract MacOS metadata item tags +# Inputs: 0) ExifTool object ref, 1) file name +sub ExtractMDItemTags($$) +{ + local $_; + my ($et, $file) = @_; + my ($fn, $tag, $val, $tmp); + + ($fn = $file) =~ s/([`"\$\\])/\\$1/g; # escape necessary characters + $et->VPrint(0, '(running mdls)'); + my @mdls = `/usr/bin/mdls "$fn" 2> /dev/null`; # get MacOS metadata + if ($? or not @mdls) { + $et->Warn('Error running "mdls" to extract MDItem tags'); + return; + } + my $tagTablePtr = GetTagTable('Image::ExifTool::MacOS::MDItem'); + $$et{INDENT} .= '| '; + $et->VerboseDir('MDItem'); + foreach (@mdls) { + chomp; + if (ref $val ne 'ARRAY') { + s/^k?(\w+)\s*= // or next; + $tag = $1; + $_ eq '(' and $val = [ ], next; # (start of a list) + $_ = '' if $_ eq '(null)'; + s/^"// and s/"$//; # remove quotes if they exist + $val = $_; + } elsif ($_ eq ')') { # (end of a list) + $_ = $$val[0]; + next unless defined $_; + } else { + # add item to list + s/^ //; # remove leading spaces + s/,$//; # remove trailing comma + $_ = '' if $_ eq '(null)'; + s/^"// and s/"$//; # remove quotes if they exist + s/\\"/"/g; # un-escape quotes + $_ = $et->Decode($_, 'UTF8'); + push @$val, $_; + next; + } + # add to Extra tags if not done already + unless ($$tagTablePtr{$tag}) { + # check for a date/time format + my %tagInfo; + %tagInfo = ( + Groups => { 2 => 'Time' }, + ValueConv => \&MDItemLocalTime, + PrintConv => '$self->ConvertDateTime($val)', + ) if /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/; + # change tags like "com_apple_mail_xxx" to "AppleMailXxx" + ($tmp = $tag) =~ s/^com_//; # remove leading "com_" + $tmp =~ s/_([a-z])/\u$1/g; # use CamelCase + $tagInfo{Name} = Image::ExifTool::MakeTagName($tmp); + $tagInfo{List} = 1 if ref $val eq 'ARRAY'; + $tagInfo{Groups}{2} = 'Audio' if $tag =~ /Audio/; + $tagInfo{Groups}{2} = 'Author' if $tag =~ /(Copyright|Author)/; + $et->VPrint(0, " [adding $tag]\n"); + AddTagToTable($tagTablePtr, $tag, \%tagInfo); + } + $val = $et->Decode($val, 'UTF8') unless ref $val; + $et->HandleTag($tagTablePtr, $tag, $val); + undef $val; + } + $$et{INDENT} =~ s/\| $//; +} + + +#------------------------------------------------------------------------------ +# Read MacOS XAttr value +# Inputs: 0) ExifTool object ref, 1) file name +sub ReadXAttrValue($$$$) +{ + my ($et, $tagTablePtr, $tag, $val) = @_; + # add to our table if necessary + unless ($$tagTablePtr{$tag}) { + my $name; + # generate tag name from attribute name + if ($tag =~ /^com\.apple\.(.*)$/) { + ($name = $1) =~ s/^metadata:_?k//; + $name =~ s/^metadata:(com_)?//; + } else { + $name = $tag; + } + $name =~ s/[.:_]([a-z])/\U$1/g; + $name = 'XAttr' . ucfirst $name; + my %tagInfo = ( Name => $name ); + $tagInfo{Groups} = { 2 => 'Time' } if $tag=~/Date$/; + $et->VPrint(0, " [adding $tag]\n"); + AddTagToTable($tagTablePtr, $tag, \%tagInfo); + } + if ($val =~ /^bplist0/) { + my %dirInfo = ( DataPt => \$val ); + require Image::ExifTool::PLIST; + if (Image::ExifTool::PLIST::ProcessBinaryPLIST($et, \%dirInfo, $tagTablePtr)) { + return undef if ref $dirInfo{Value} eq 'HASH'; + $val = $dirInfo{Value} + } else { + $et->Warn("Error decoding $$tagTablePtr{$tag}{Name}"); + return undef; + } + } + if (not ref $val and ($val =~ /\0/ or length($val) > 200) or $tag eq 'XAttrMDLabel') { + my $buff = $val; + $val = \$buff; + } + return $val; +} + +#------------------------------------------------------------------------------ +# Read MacOS extended attribute tags using 'xattr' utility +# Inputs: 0) ExifTool object ref, 1) file name +sub ExtractXAttrTags($$) +{ + local $_; + my ($et, $file) = @_; + my ($fn, $tag, $val, $warn); + + ($fn = $file) =~ s/([`"\$\\])/\\$1/g; # escape necessary characters + $et->VPrint(0, '(running xattr)'); + my @xattr = `/usr/bin/xattr -lx "$fn" 2> /dev/null`; # get MacOS extended attributes + if ($? or not @xattr) { + $? and $et->Warn('Error running "xattr" to extract XAttr tags'); + return; + } + my $tagTablePtr = GetTagTable('Image::ExifTool::MacOS::XAttr'); + $$et{INDENT} .= '| '; + $et->VerboseDir('XAttr'); + push @xattr, ''; # (for a list terminator) + foreach (@xattr) { + chomp; + if (s/^[\dA-Fa-f]{8}//) { + $tag or $warn = 1, next; + s/\|.*//; + tr/ //d; + (/[^\dA-Fa-f]/ or length($_) & 1) and $warn = 2, next; + $val = '' unless defined $val; + $val .= pack('H*', $_); + next; + } elsif ($tag and defined $val) { + $val = ReadXAttrValue($et, $tagTablePtr, $tag, $val); + $et->HandleTag($tagTablePtr, $tag, $val) if defined $val; + undef $tag; + undef $val; + } + next unless length; + s/:$// or $warn = 3, next; # attribute name must have trailing ":" + defined $val and $warn = 4, undef $val; + # remove random ID after kMDLabel in tag ID + ($tag = $_) =~ s/^com.apple.metadata:kMDLabel_.*/com.apple.metadata:kMDLabel/s; + } + $warn and $et->Warn(qq{Error $warn parsing "xattr" output}); + $$et{INDENT} =~ s/\| $//; +} + +#------------------------------------------------------------------------------ +# Extract MacOS file creation date/time +# Inputs: 0) ExifTool object ref, 1) file name +sub GetFileCreateDate($$) +{ + local $_; + my ($et, $file) = @_; + my ($fn, $tag, $val, $tmp); + + ($fn = $file) =~ s/([`"\$\\])/\\$1/g; # escape necessary characters + $et->VPrint(0, '(running stat)'); + my $time = `/usr/bin/stat -f '%SB' -t '%Y:%m:%d %H:%M:%S%z' "$fn" 2> /dev/null`; + if ($? or not $time or $time !~ s/([-+]\d{2})(\d{2})\s*$/$1:$2/) { + $et->Warn('Error running "stat" to extract FileCreateDate'); + return; + } + $$et{SET_GROUP1} = 'MacOS'; + $et->FoundTag(FileCreateDate => $time); + delete $$et{SET_GROUP1}; +} + +#------------------------------------------------------------------------------ +# Read ATTR metadata from "._" file +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Return: 1 on success +# (ref https://www.swiftforensics.com/2018/11/the-dot-underscore-file-format.html) +sub ProcessATTR($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dataPos = $$dirInfo{DataPos}; + my $dataLen = length $$dataPt; + + $dataLen >= 58 and $$dataPt =~ /^.{34}ATTR/s or $et->Warn('Invalid ATTR header'), return 0; + my $entries = Get32u($dataPt, 66); + $et->VerboseDir('ATTR', $entries); + # (Note: The RAF is not in $dirInfo because it would break RSRC reading -- + # the RSCR block uses relative offsets, while the ATTR block uses absolute! grrr!) + my $raf = $$et{RAF}; + my $pos = 70; # first entry is after ATTR header + my $i; + for ($i=0; $i<$entries; ++$i) { + $pos + 12 > $dataLen and $et->Warn('Truncated ATTR entry'), last; + my $off = Get32u($dataPt, $pos); + my $len = Get32u($dataPt, $pos + 4); + my $n = Get8u($dataPt, $pos + 10); # number of characters in tag name + $pos + 11 + $n > $dataLen and $et->Warn('Truncated ATTR name'), last; + $off -= $dataPos; # convert to relative offset (grrr!) + $off < 0 or $off > $dataLen and $et->Warn('Invalid ATTR offset'), last; + my $tag = substr($$dataPt, $pos + 11, $n); + $tag =~ s/\0+$//; # remove null terminator + # remove random ID after kMDLabel in tag ID + $tag =~ s/^com.apple.metadata:kMDLabel_.*/com.apple.metadata:kMDLabel/s; + $off + $len > $dataLen and $et->Warn('Truncated ATTR value'), last; + my $val = ReadXAttrValue($et, $tagTablePtr, $tag, substr($$dataPt, $off, $len)); + $et->HandleTag($tagTablePtr, $tag, $val, + DataPt => $dataPt, + DataPos => $dataPos, + Start => $off, + Size => $len, + ) if defined $val; + $pos += (11 + $n + 3) & -4; # step to next entry (on even 4-byte boundary) + } + return 1; +} + +#------------------------------------------------------------------------------ +# Read information from a MacOS "._" sidecar file +# Inputs: 0) ExifTool ref, 1) dirInfo ref +# Returns: 1 on success, 0 if this wasn't a valid "._" file +# (ref https://www.swiftforensics.com/2018/11/the-dot-underscore-file-format.html) +sub ProcessMacOS($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my ($hdr, $buff, $i); + + return 0 unless $raf->Read($hdr, 26) == 26 and $hdr =~ /^\0\x05\x16\x07\0(.)\0\0Mac OS X /s; + my $ver = ord $1; + # (extension may be anything, so just echo back the incoming file extension if it exists) + $et->SetFileType(undef, undef, $$et{FILE_EXT}); + $ver == 2 or $et->Warn("Unsupported file version $ver"), return 1; + SetByteOrder('MM'); + my $tagTablePtr = GetTagTable('Image::ExifTool::MacOS::Main'); + my $entries = Get16u(\$hdr, 0x18); + $et->VerboseDir('MacOS', $entries); + $raf->Read($hdr, $entries * 12) == $entries * 12 or $et->Warn('Truncated header'), return 1; + for ($i=0; $i<$entries; ++$i) { + my $pos = $i * 12; + my $tag = Get32u(\$hdr, $pos); + my $off = Get32u(\$hdr, $pos + 4); + my $len = Get32u(\$hdr, $pos + 8); + $len > 100000000 and $et->Warn('Record size too large'), last; + $raf->Seek($off,0) and $raf->Read($buff,$len) == $len or $et->Warn('Truncated record'), last; + $et->HandleTag($tagTablePtr, $tag, undef, DataPt => \$buff, DataPos => $off, Index => $i); + } + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::MacOS - Read/write MacOS system tags + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to extract +MDItem* and XAttr* tags on MacOS systems using the "mdls" and "xattr" +utilities respectively. It also reads metadata directly from the MacOS "_." +sidecar files that are used on some filesystems to store file attributes. +Writable tags use "xattr", "setfile" or "osascript" for writing. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/MacOS Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MakerNotes.pm b/src/Image-ExifTool/lib/Image/ExifTool/MakerNotes.pm index 96d02bf6..b00081b1 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/MakerNotes.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/MakerNotes.pm @@ -21,7 +21,7 @@ sub ProcessKodakPatch($$$); sub WriteUnknownOrPreview($$$); sub FixLeicaBase($$;$); -$VERSION = '2.06'; +$VERSION = '2.11'; my $debug; # set to 1 to enable debugging code @@ -32,7 +32,7 @@ my $debug; # set to 1 to enable debugging code # write maker notes into a file with different byte ordering! # - Put these in alphabetical order to make TagNames documentation nicer. @Image::ExifTool::MakerNotes::Main = ( - # decide which MakerNotes to use (based on camera make/model) + # decide which MakerNotes to use (based on makernote header and camera make/model) { Name => 'MakerNoteApple', Condition => '$$valPt =~ /^Apple iOS\0/', @@ -89,6 +89,11 @@ my $debug; # set to 1 to enable debugging code FixBase => 1, # necessary for AVI and MOV videos }, }, + { + Name => 'MakerNoteDJIInfo', + Condition => '$$valPt =~ /^\[ae_dbg_info:/', + SubDirectory => { TagTable => 'Image::ExifTool::DJI::Info' }, + }, { Name => 'MakerNoteDJI', Condition => '$$self{Make} eq "DJI" and $$valPt !~ /^...\@AMBA/s', @@ -160,6 +165,10 @@ my $debug; # set to 1 to enable debugging code Start => '$valuePtr', Base => 0, # (avoids warnings since maker notes are not self-contained) }, + # 0x0011 - sensor code (ref IB) + # 0x0012 - camera model id? + # 0x0015 - camera model name + # 0x0016 - coating code (ref IB) }, # (the GE X5 has really messed up EXIF-like maker notes starting with # "GENIC\x0c\0" --> currently not decoded) @@ -566,6 +575,17 @@ my $debug; # set to 1 to enable debugging code ByteOrder => 'Unknown', }, }, + { + Name => 'MakerNoteOlympus3', + # new Olympus maker notes start with "OLYMPUS\0" + Condition => '$$valPt =~ /^OM SYSTEM\0/', + SubDirectory => { + TagTable => 'Image::ExifTool::Olympus::Main', + Start => '$valuePtr + 16', + Base => '$start - 16', + ByteOrder => 'Unknown', + }, + }, { Name => 'MakerNoteLeica', # (starts with "LEICA\0\0\0") @@ -687,7 +707,15 @@ my $debug; # set to 1 to enable debugging code SubDirectory => { TagTable => 'Image::ExifTool::Panasonic::Leica9', Start => '$valuePtr + 8', - Base => '$start - 8', + ByteOrder => 'Unknown', + }, + }, + { + Name => 'MakerNoteLeica10', # used by the D-Lux7 + Condition => '$$valPt =~ /^LEICA CAMERA AG\0/', + SubDirectory => { + TagTable => 'Image::ExifTool::Panasonic::Main', + Start => '$valuePtr + 18', ByteOrder => 'Unknown', }, }, @@ -832,6 +860,25 @@ my $debug; # set to 1 to enable debugging code ByteOrder => 'Little-endian', }, }, + { + Name => 'MakerNoteReconyx3', + Condition => '$$valPt =~ /^RECONYXH2\0/', + SubDirectory => { + TagTable => 'Image::ExifTool::Reconyx::Type3', + ByteOrder => 'Little-endian', + }, + }, + { + Name => 'MakerNoteRicohPentax', + # used by cameras such as the Ricoh GR III + Condition => '$$valPt=~/^RICOH\0(II|MM)/', + SubDirectory => { + TagTable => 'Image::ExifTool::Pentax::Main', + Start => '$valuePtr + 8', + Base => '$start - 8', + ByteOrder => 'Unknown', + }, + }, { Name => 'MakerNoteRicoh', # (my test R50 image starts with " \x02\x01" - PH) @@ -891,9 +938,9 @@ my $debug; # set to 1 to enable debugging code }, { Name => 'MakerNoteSamsung2', - # Samsung EXIF-format maker notes + # Samsung EXIF-format maker notes ( Condition => q{ - $$self{Make} eq 'SAMSUNG' and ($$self{TIFF_TYPE} eq 'SRW' or + uc $$self{Make} eq 'SAMSUNG' and ($$self{TIFF_TYPE} eq 'SRW' or $$valPt=~/^(\0.\0\x01\0\x07\0{3}\x04|.\0\x01\0\x07\0\x04\0{3})0100/s) }, SubDirectory => { @@ -942,8 +989,12 @@ my $debug; # set to 1 to enable debugging code }, { Name => 'MakerNoteSigma', - # (starts with "SIGMA\0") - Condition => '$$self{Make}=~/^(SIGMA|FOVEON)/', + Condition => q{ + return undef unless $$self{Make}=~/^(SIGMA|FOVEON)/; + # save version number in "MakerNoteSigmaVer" member variable + $$self{MakerNoteSigmaVer} = $$valPt=~/^SIGMA\0\0\0\0(.)/ ? ord($1) : -1; + return 1; + }, SubDirectory => { TagTable => 'Image::ExifTool::Sigma::Main', Validate => '$val =~ /^(SIGMA|FOVEON)/', @@ -1777,7 +1828,7 @@ maker notes in EXIF information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Matroska.pm b/src/Image-ExifTool/lib/Image/ExifTool/Matroska.pm index 8f8cd76d..5227691b 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Matroska.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Matroska.pm @@ -14,7 +14,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.09'; +$VERSION = '1.12'; my %noYes = ( 0 => 'No', 1 => 'Yes' ); @@ -27,8 +27,10 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); NOTES => q{ The following tags are extracted from Matroska multimedia container files. This container format is used by file types such as MKA, MKV, MKS and WEBM. - For speed, ExifTool extracts tags only up to the first Cluster unless the - Verbose (-v) or Unknown = 2 (-U) option is used. See + For speed, by default ExifTool extracts tags only up to the first Cluster. + However, the L<Verbose|../ExifTool.html#Verbose> (-v) and L<Unknown|../ExifTool.html#Unknown> = 2 (-U) options force processing of + Cluster data, and the L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> (-ee) option skips over Clusters to + read subsequent tags. See L<http://www.matroska.org/technical/specs/index.html> for the official Matroska specification. }, @@ -221,6 +223,8 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); }, 0x2e => { Name => 'TrackEntry', + # reset TrackType member at the start of each track + Condition => 'delete $$self{TrackType}; 1', SubDirectory => { TagTable => 'Image::ExifTool::Matroska::Main' }, }, 0x57 => { Name => 'TrackNumber', Format => 'unsigned' }, @@ -267,10 +271,11 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); } ], 0x3314f => { Name => 'TrackTimecodeScale',Format => 'float' }, - 0x137f => { Name => 'TrackOffset', Format => 'signed', Unknown => 1 }, + 0x137f => { Name => 'TrackOffset', Format => 'signed', Unknown => 1 }, 0x15ee => { Name => 'MaxBlockAdditionID',Format => 'unsigned', Unknown => 1 }, - 0x136e => { Name => 'TrackName', Format => 'utf8' }, - 0x2b59c => { Name => 'TrackLanguage', Format => 'string' }, + 0x136e => { Name => 'TrackName', Format => 'utf8' }, + 0x2b59c => { Name => 'TrackLanguage', Format => 'string' }, + 0x2b59d => { Name => 'TrackLanguageIETF', Format => 'string' }, 0x06 => [ { Name => 'VideoCodecID', @@ -662,6 +667,7 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); 3 => 'Mesh', }, }, + # ProjectionPrivate in the spec 0x7672 => [{ Name => 'EquirectangularProj', Condition => '$$self{ProjectionType} == 1', @@ -670,10 +676,13 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); Name => 'CubemapProj', Condition => '$$self{ProjectionType} == 2', SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::cbmp' }, + },{ # (don't decode 3 because it is a PITA) + Name => 'ProjectionPrivate', + Binary => 1, }], - 0x7673 => { Name => 'ProjectionPosYaw', Format => 'float' }, - 0x7674 => { Name => 'ProjectionPosPitch', Format => 'float' }, - 0x7675 => { Name => 'ProjectionPosRoll', Format => 'float' }, + 0x7673 => { Name => 'ProjectionPoseYaw', Format => 'float' }, + 0x7674 => { Name => 'ProjectionPosePitch', Format => 'float' }, + 0x7675 => { Name => 'ProjectionPoseRoll', Format => 'float' }, ); #------------------------------------------------------------------------------ @@ -737,7 +746,8 @@ sub ProcessMKV($$) # set flag to process entire file (otherwise we stop at the first Cluster) my $verbose = $et->Options('Verbose'); - my $processAll = ($verbose or $et->Options('Unknown') > 1); + my $processAll = ($verbose or $et->Options('Unknown') > 1) ? 2 : 0; + ++$processAll if $et->Options('ExtractEmbedded'); $$et{TrackTypes} = \%trackTypes; # store Track types reference my $oldIndent = $$et{INDENT}; my $chapterNum = 0; @@ -780,16 +790,20 @@ sub ProcessMKV($$) my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); # just fall through into the contained EBML elements if ($tagInfo and $$tagInfo{SubDirectory}) { - # stop processing at first cluster unless we are in verbose mode - last if $$tagInfo{Name} eq 'Cluster' and not $processAll; - $$et{INDENT} .= '| '; - $et->VerboseDir($$tagTablePtr{$tag}{Name}, undef, $size); - push @dirEnd, [ $pos + $dataPos + $size, $$tagInfo{Name} ]; - if ($$tagInfo{Name} eq 'ChapterAtom') { - $$et{SET_GROUP1} = 'Chapter' . (++$chapterNum); - $trackIndent = $$et{INDENT}; + # stop processing at first cluster unless we are using -v -U or -ee + if ($$tagInfo{Name} eq 'Cluster' and $processAll < 2) { + last unless $processAll; + undef $tagInfo; # just skip the Cluster when -ee is used + } else { + $$et{INDENT} .= '| '; + $et->VerboseDir($$tagTablePtr{$tag}{Name}, undef, $size); + push @dirEnd, [ $pos + $dataPos + $size, $$tagInfo{Name} ]; + if ($$tagInfo{Name} eq 'ChapterAtom') { + $$et{SET_GROUP1} = 'Chapter' . (++$chapterNum); + $trackIndent = $$et{INDENT}; + } + next; } - next; } last if $unknownSize; if ($pos + $size > $dataLen) { @@ -798,7 +812,7 @@ sub ProcessMKV($$) # just skip unknown and large data blocks if (not $tagInfo or $more > 10000000) { # don't try to skip very large blocks unless LargeFileSupport is enabled - last if $more > 0x80000000 and not $et->Options('LargeFileSupport'); + last if $more >= 0x80000000 and not $et->Options('LargeFileSupport'); $raf->Seek($more, 1) or last; $buff = ''; $dataPos += $dataLen + $more; @@ -912,7 +926,7 @@ information from Matroska multimedia files (MKA, MKV, MKS and WEBM). =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Microsoft.pm b/src/Image-ExifTool/lib/Image/ExifTool/Microsoft.pm index 7ae6167f..e0ecdb52 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Microsoft.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Microsoft.pm @@ -5,6 +5,7 @@ # # Revisions: 2010/10/01 - P. Harvey Created # 2011/10/05 - PH Added ProcessXtra() +# 2021/02/23 - PH Added abiltity to write Xtra tags # # References: 1) http://research.microsoft.com/en-us/um/redmond/groups/ivm/hdview/hdmetadataspec.htm #------------------------------------------------------------------------------ @@ -16,9 +17,11 @@ use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::XMP; -$VERSION = '1.20'; +$VERSION = '1.23'; sub ProcessXtra($$$); +sub WriteXtra($$$); +sub CheckXtra($$$); # tags written by Microsoft HDView (ref 1) %Image::ExifTool::Microsoft::Stitch = ( @@ -152,7 +155,7 @@ my %sRegions = ( Rectangle => { }, PersonDisplayName => { }, PersonEmailDigest => { }, - PersonLiveIdCID => { }, # (see http://130.15.24.88/exiftool/forum/index.php?topic=4274.msg20368#msg20368) + PersonLiveIdCID => { }, # (see https://exiftool.org/forum/index.php?topic=4274.msg20368#msg20368) PersonSourceID => { }, ); %Image::ExifTool::Microsoft::MP = ( @@ -196,11 +199,20 @@ my %sRegions = ( # and Image::ExifTool::WTV::Metadata %Image::ExifTool::Microsoft::Xtra = ( PROCESS_PROC => \&ProcessXtra, + WRITE_PROC => \&WriteXtra, + CHECK_PROC => \&CheckXtra, + WRITE_GROUP => 'Microsoft', + AVOID => 1, GROUPS => { 0 => 'QuickTime', 2 => 'Video' }, VARS => { NO_ID => 1 }, NOTES => q{ - Tags extracted from the Microsoft "Xtra" atom of QuickTime videos. Tag ID's - are not shown because some are unruly GUID's. + Tags found in the Microsoft "Xtra" atom of QuickTime videos. Tag ID's are + not shown because some are unruly GUID's. Currently most of these tags are + not writable because the Microsoft documentation is poor and samples were + not available, but more tags may be made writable in the future if samples + are provided. Note that writable tags in this table are are flagged to + "Avoid", which means that other more common tags will be written instead if + possible unless the Microsoft group is specified explicitly. }, Abstract => { }, AcquisitionTime => { Groups => { 2 => 'Time' } }, @@ -327,30 +339,34 @@ my %sRegions = ( UserServiceRating => { }, VideoBitrate => { }, VideoFormat => { }, - 'WM/AlbumArtist' => 'AlbumArtist', - 'WM/AlbumCoverURL' => 'AlbumCoverURL', - 'WM/AlbumTitle' => 'AlbumTitle', + 'WM/AlbumArtist' => { Name => 'AlbumArtist', Writable => 'Unicode' }, # (NC) + 'WM/AlbumCoverURL' => { Name => 'AlbumCoverURL', Writable => 'Unicode' }, # (NC) + 'WM/AlbumTitle' => { Name => 'AlbumTitle', Writable => 'Unicode' }, # (NC) 'WM/BeatsPerMinute' => 'BeatsPerMinute', - 'WM/Category' => 'Category', - 'WM/Composer' => 'Composer', - 'WM/Conductor' => 'Conductor', - 'WM/ContentDistributor' => 'ContentDistributor', + 'WM/Category' => { Name => 'Category', Writable => 'Unicode', List => 1 }, + 'WM/Composer' => { Name => 'Composer', Writable => 'Unicode' }, # (NC) + 'WM/Conductor' => { Name => 'Conductor', Writable => 'Unicode', List => 1 }, + 'WM/ContentDistributor' => { Name => 'ContentDistributor', Writable => 'Unicode' }, 'WM/ContentDistributorType' => 'ContentDistributorType', 'WM/ContentGroupDescription'=> 'ContentGroupDescription', - 'WM/Director' => 'Director', + 'WM/Director' => { Name => 'Director', Writable => 'Unicode', List => 1 }, 'WM/EncodingTime' => { Name => 'EncodingTime', Groups => { 2 => 'Time' }, + Shift => 'Time', + Writable => 'date', PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val)', }, 'WM/Genre' => 'Genre', 'WM/GenreID' => 'GenreID', - 'WM/InitialKey' => 'InitialKey', + 'WM/InitialKey' => { Name => 'InitialKey', Writable => 'Unicode' }, 'WM/Language' => 'Language', 'WM/Lyrics' => 'Lyrics', 'WM/MCDI' => 'MCDI', 'WM/MediaClassPrimaryID' => { Name => 'MediaClassPrimaryID', + Writable => 'GUID', PrintConv => { #http://msdn.microsoft.com/en-us/library/windows/desktop/dd757960(v=vs.85).aspx 'D1607DBC-E323-4BE2-86A1-48A42A28441E' => 'Music', 'DB9830BD-3AB3-4FAB-8A37-1A995F7FF74B' => 'Video', @@ -360,6 +376,7 @@ my %sRegions = ( }, 'WM/MediaClassSecondaryID' => { Name => 'MediaClassSecondaryID', + Writable => 'GUID', PrintConv => { #http://msdn.microsoft.com/en-us/library/windows/desktop/dd757960(v=vs.85).aspx 'E0236BEB-C281-4EDE-A36D-7AF76A3D45B5' => 'Audio Book', '3A172A13-2BD9-4831-835B-114F6A95943F' => 'Spoken Word', @@ -385,22 +402,22 @@ my %sRegions = ( }, 'WM/MediaOriginalChannel' => 'MediaOriginalChannel', 'WM/MediaStationName' => 'MediaStationName', - 'WM/Mood' => 'Mood', - 'WM/OriginalAlbumTitle' => 'OriginalAlbumTitle', - 'WM/OriginalArtist' => 'OriginalArtist', - 'WM/OriginalLyricist' => 'OriginalLyricist', - 'WM/ParentalRating' => 'ParentalRating', + 'WM/Mood' => { Name => 'Mood', Writable => 'Unicode' }, + 'WM/OriginalAlbumTitle' => { Name => 'OriginalAlbumTitle', Writable => 'Unicode' }, # (NC) + 'WM/OriginalArtist' => { Name => 'OriginalArtist', Writable => 'Unicode' }, # (NC) + 'WM/OriginalLyricist' => { Name => 'OriginalLyricist', Writable => 'Unicode' }, # (NC) + 'WM/ParentalRating' => { Name => 'ParentalRating', Writable => 'Unicode' }, 'WM/PartOfSet' => 'PartOfSet', - 'WM/Period' => 'Period', - 'WM/Producer' => 'Producer', + 'WM/Period' => { Name => 'Period', Writable => 'Unicode' }, + 'WM/Producer' => { Name => 'Producer', Writable => 'Unicode', List => 1 }, 'WM/ProtectionType' => 'ProtectionType', - 'WM/Provider' => 'Provider', + 'WM/Provider' => { Name => 'Provider', Writable => 'Unicode' }, # (NC) 'WM/ProviderRating' => 'ProviderRating', 'WM/ProviderStyle' => 'ProviderStyle', - 'WM/Publisher' => 'Publisher', - 'WM/SharedUserRating' => 'SharedUserRating', + 'WM/Publisher' => { Name => 'Publisher', Writable => 'Unicode' }, # (multiple entries separated by semicolon) + 'WM/SharedUserRating' => { Name => 'SharedUserRating', Writable => 'int64u' }, 'WM/SubscriptionContentID' => 'SubscriptionContentID', - 'WM/SubTitle' => 'Subtitle', + 'WM/SubTitle' => { Name => 'Subtitle', Writable => 'Unicode' }, 'WM/SubTitleDescription' => 'SubtitleDescription', 'WM/TrackNumber' => 'TrackNumber', 'WM/UniqueFileIdentifier' => 'UniqueFileIdentifier', @@ -412,8 +429,11 @@ my %sRegions = ( 'WM/WMContentID' => 'WMContentID', 'WM/WMShadowFileSourceDRMType' => 'WMShadowFileSourceDRMType', 'WM/WMShadowFileSourceFileType' => 'WMShadowFileSourceFileType', - 'WM/Writer' => 'Writer', - 'WM/Year' => { Name => 'Year', Groups => { 2 => 'Time' } }, + 'WM/Writer' => { Name => 'Writer', Groups => { 2 => 'Author' }, Writable => 'Unicode' }, # (NC) + 'WM/Year' => { Name => 'Year', Groups => { 2 => 'Time' } }, + 'WM/PromotionURL' => { Name => 'PromotionURL',Writable => 'Unicode' }, + 'WM/AuthorURL' => { Name => 'AuthorURL', Groups => { 2 => 'Author' }, Writable => 'Unicode' }, + 'WM/EncodedBy', => { Name => 'EncodedBy', Writable => 'Unicode' }, # I can't find documentation for the following tags in videos, # but the tag ID's correspond to Microsoft property GUID+ID's @@ -422,9 +442,12 @@ my %sRegions = ( # http://multi-rename-script.googlecode.com/svn-history/r4/trunk/plugins/ShellDetails/ShellDetails.ini # I have observed only 1 so far: '{2CBAA8F5-D81F-47CA-B17A-F8D822300131} 100' => { - Name => 'DateAcquired', + Name => 'DateAcquired', # (seems to be when videos are downloaded from the camera) Groups => { 2 => 'Time' }, + Shift => 'Time', + Writable => 'vt_filetime', PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val,undef)', }, # the following have not yet been observed... '{B725F130-47EF-101A-A5F1-02608C9EEBAC} 10' => 'Name', @@ -764,6 +787,245 @@ my %sRegions = ( '{64440491-4C8B-11D1-8B70-080036B11A03} 43' => 'TotalBitrate', ); +#------------------------------------------------------------------------------ +# check new value for Xtra tag +# Inputs: 0) ExifTool object ref, 1) tagInfo hash ref, 2) raw value ref +# Returns: error string, or undef on success +sub CheckXtra($$$) +{ + my ($et, $tagInfo, $valPt) = @_; + my $format = $$tagInfo{Writable}; + return 'Unknown format' unless $format; + if ($format =~ /^int/) { + return 'Not an integer' unless Image::ExifTool::IsInt($$valPt); + } elsif ($format ne 'Unicode') { + my @vals = ($$valPt); + return 'Invalid format' unless WriteXtraValue($et, $tagInfo, \@vals); + } + return undef; +} + +#------------------------------------------------------------------------------ +# Decode value(s) in Microsoft Xtra tag +# Inputs: 0) ExifTool object ref, 1) value data +# Returns: Scalar context: decoded value, List context: 0) decoded value, 1) format string +sub ReadXtraValue($$) +{ + my ($et, $data) = @_; + my ($format, $i, @vals); + + return undef if length($data) < 10; + + # (version flags according to the reference, but looks more like a count - PH) + my $count = Get32u(\$data, 0); + # point to start of first value (after 4-byte count, 4-byte length and 2-byte type) + my $valPos = 10; + for ($i=0; ;) { + # (stored value includes size of $valLen and $valType, so subtract 6) + my $valLen = Get32u(\$data, $valPos - 6) - 6; + last if $valPos + $valLen > length($data); + my $valType = Get16u(\$data, $valPos - 2); + my $val = substr($data, $valPos, $valLen); + # Note: all dumb Microsoft values are little-endian inside a big-endian-format file + SetByteOrder('II'); + if ($valType == 8) { + $format = 'Unicode'; + $val = $et->Decode($val, 'UCS2'); + } elsif ($valType == 19 and $valLen == 8) { + $format = 'int64u'; + $val = Get64u(\$val, 0); + } elsif ($valType == 21 and $valLen == 8) { + $format = 'date'; + $val = Get64u(\$val, 0); + # convert time from 100 ns intervals since Jan 1, 1601 + $val = $val * 1e-7 - 11644473600 if $val; + # (the Nikon S100 uses UTC timezone, same as ASF - PH) + $val = Image::ExifTool::ConvertUnixTime($val, 1); + } elsif ($valType == 72 and $valLen == 16) { + $format = 'GUID'; + $val = uc unpack('H*',pack('NnnNN',unpack('VvvNN',$val))); + $val =~ s/(.{8})(.{4})(.{4})(.{4})/$1-$2-$3-$4-/; + } elsif ($valType == 65 and $valLen > 4) { #PH (empirical) + $format = 'variant'; + require Image::ExifTool::FlashPix; + my $vPos = 0; # (necessary because ReadFPXValue updates this) + # read entry as a VT_VARIANT (use FlashPix module for this) + $val = Image::ExifTool::FlashPix::ReadFPXValue($et, \$val, $vPos, + Image::ExifTool::FlashPix::VT_VARIANT(), $valLen, 1); + } else { + $format = "Unknown($valType)"; + } + SetByteOrder('MM'); # back to native QuickTime byte ordering + push @vals, $val; + last if ++$i >= $count; + $valPos += $valLen + 6; # step to next value + last if $valPos > length($data); + } + return wantarray ? (\@vals, $format) : \@vals; +} + +#------------------------------------------------------------------------------ +# Write a Microsoft Xtra value +# Inputs: 0) ExifTool object ref, 1) tagInfo ref, 2) reference to list of values +# Returns: new value binary data (or empty string) +sub WriteXtraValue($$$) +{ + my ($et, $tagInfo, $vals) = @_; + my $format = $$tagInfo{Writable}; + my $buff = ''; + my $count = 0; + my $val; + foreach $val (@$vals) { + SetByteOrder('II'); + my ($type, $dat); + if ($format eq 'Unicode') { + $dat = $et->Encode($val,'UCS2','II') . "\0\0"; # (must be null terminated) + $type = 8; + } elsif ($format eq 'int64u') { + if (Image::ExifTool::IsInt($val)) { + $dat = Set64u($val); + $type = 19; + } + } elsif ($format eq 'date') { + $dat = Image::ExifTool::GetUnixTime($val, 1); # (convert to UTC, NC) + if ($dat) { + # 100ns intervals since Jan 1, 1601 + $dat = Set64u(($dat + 11644473600) * 1e7); + $type = 21; + } + } elsif ($format eq 'vt_filetime') { # 'date' value inside a VT_VARIANT + $dat = Image::ExifTool::GetUnixTime($val); # (leave as local time, NC) + if ($dat) { + # 100ns intervals since Jan 1, 1601 + $dat = Set32u(64) . Set64u(($dat + 11644473600) * 1e7); + $type = 65; + } + } elsif ($format eq 'GUID') { + ($dat = $val) =~ tr/-//d; + if (length($dat) == 32) { + $dat = pack('VvvNN',unpack('NnnNN',pack('H*', $dat))); + $type = 72; + } + } else { + $et->WarnOnce("Error converting value for Microsoft:$$tagInfo{Name}"); + } + SetByteOrder('MM'); + if (defined $type) { + ++$count; + $buff .= Set32u(length($dat)+6) . Set16u($type) . $dat; + } + } + return $count ? Set32u($count) . $buff : ''; +} + +#------------------------------------------------------------------------------ +# Add new values to list +# Inputs: 0) ExifTool ref, 1) new value list ref, 2) nvHash ref +# Returns: true if something was added +sub AddNewValues($$$) +{ + my ($et, $vals, $nvHash) = @_; + my @newVals = $et->GetNewValue($nvHash) or return undef; + if ($$et{OPTIONS}{Verbose} > 1) { + $et->VPrint(1, " + Microsoft:$$nvHash{TagInfo}{Name} = $_\n") foreach @newVals; + } + push @$vals, @newVals; + return 1; +} + +#------------------------------------------------------------------------------ +# Write tags to a Microsoft Xtra MP4 atom +# Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref +# Returns: Microsoft Xtra data block (may be empty if no Xtra data) or undef on error +sub WriteXtra($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + $et or return 1; # allow dummy access + + my $delGroup = ($$et{DEL_GROUP} and $$et{DEL_GROUP}{Microsoft}); + my $newTags = $et->GetNewTagInfoHash($tagTablePtr); + + return undef unless $delGroup or %$newTags; # don't rewrite if nothing to do + + my $dataPt = $$dirInfo{DataPt}; + my $dataLen = length $$dataPt; + my $newData = ''; + my $pos = 0; + my ($err, %done, $changed, $tag); + + if ($delGroup) { + $changed = 1 if $dataLen; + my $empty = ''; + $dataPt = $empty; + $dataLen = 0; + } + for (;;) { + last if $pos + 4 > $dataLen; + my $size = Get32u($dataPt, $pos); # (includes $size word) + ($size < 8 or $pos + $size > $dataLen) and $err=1, last; + my $tagLen = Get32u($dataPt, $pos + 4); + $tagLen + 18 > $size and $err=1, last; + $tag = substr($$dataPt, $pos + 8, $tagLen); + my @newVals; + while ($$newTags{$tag}) { + my $nvHash = $et->GetNewValueHash($$newTags{$tag}); + $$nvHash{CreateOnly} and delete($$newTags{$tag}), last; # don't edit this tag + my $valPos = $pos + 8 + $tagLen; + my $valLen = $size - 8 - $tagLen; + my $val = ReadXtraValue($et, substr($$dataPt, $valPos, $valLen)); + foreach $val (@$val) { + my $overwrite = $et->IsOverwriting($nvHash, $val); + $overwrite or push(@newVals, $val), next; + $et->VPrint(1, " - Microsoft:$$newTags{$tag}{Name} = $val\n"); + next if $done{$tag}; + $done{$tag} = 1; + AddNewValues($et, \@newVals, $nvHash); + } + # add to the end of the list if this was a List-type tag and we didn't delete anything + if (not $done{$tag} and $$newTags{$tag}{List}) { + AddNewValues($et, \@newVals, $nvHash) or last; + $done{$tag} = 1; + } + last; # (it was a cheap goto) + } + if ($done{$tag}) { + $changed = 1; + # write changed values + my $buff = WriteXtraValue($et, $$newTags{$tag}, \@newVals); + if (length $buff) { + $newData .= Set32u(8+length($tag)+length($buff)) . Set32u(length($tag)) . $tag . $buff; + } + } else { + # nothing changed; just copy over + $newData .= substr($$dataPt, $pos, $size); + } + $pos += $size; # step to next entry + } + if ($err) { + $et->Warn('Microsoft Xtra format error'); + return undef; + } + # add any new tags + foreach $tag (sort keys %$newTags) { + next if $done{$tag}; + my $nvHash = $et->GetNewValueHash($$newTags{$tag}); + next unless $$nvHash{IsCreating} and not $$nvHash{EditOnly}; + my @newVals; + AddNewValues($et, \@newVals, $nvHash) or next; + my $buff = WriteXtraValue($et, $$newTags{$tag}, \@newVals); + if (length $buff) { + $newData .= Set32u(8+length($tag)+length($buff)) . Set32u(length($tag)) . $tag . $buff; + $changed = 1; + } + } + if ($changed) { + ++$$et{CHANGED}; + } else { + undef $newData; + } + return $newData; +} + #------------------------------------------------------------------------------ # Extract information from Xtra MP4 atom # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref @@ -783,61 +1045,13 @@ sub ProcessXtra($$$) last if $size < 8 or $pos + $size > $dataLen; my $tagLen = Get32u($dataPt, $pos + 4); last if $tagLen + 18 > $size; - my $tag = substr($$dataPt, $pos + 8, $tagLen); - # (version flags according to the reference, but looks more like a count - PH) - my $count = Get32u($dataPt, $pos + $tagLen + 8); - my ($i, $valPos, $valLen, $valType, $val, $format, @vals); - # point to start of first value (after 4-byte length and 2-byte type) - $valPos = $pos + $tagLen + 18; - for ($i=0; ;) { - # (stored value includes size of $valLen and $valType, so subtract 6) - $valLen = Get32u($dataPt, $valPos - 6) - 6; - my $more = $pos + $size - $valPos - $valLen; - last if $more < 0; - $valType = Get16u($dataPt, $valPos - 2); - $val = substr($$dataPt, $valPos, $valLen); - # Note: all dumb Microsoft values are little-endian inside a big-endian-format file - SetByteOrder('II'); - if ($valType == 8) { - $format = 'Unicode'; - $val = $et->Decode($val, 'UCS2'); - } elsif ($valType == 19 and $valLen == 8) { - $format = 'int64u'; - $val = Get64u(\$val, 0); - } elsif ($valType == 21 and $valLen == 8) { - $format = 'date'; - $val = Get64u(\$val, 0); - # convert time from 100 ns intervals since Jan 1, 1601 - $val = $val * 1e-7 - 11644473600 if $val; - # (the Nikon S100 uses UTC timezone, same as ASF - PH) - $val = Image::ExifTool::ConvertUnixTime($val) . 'Z'; - } elsif ($valType == 72 and $valLen == 16) { - $format = 'GUID'; - $val = uc unpack('H*',pack('NnnNN',unpack('VvvNN',$val))); - $val =~ s/(.{8})(.{4})(.{4})(.{4})/$1-$2-$3-$4-/; - } elsif ($valType == 65 && $valLen > 4) { #PH (empirical) - $format = 'variant'; - require Image::ExifTool::FlashPix; - my $vPos = $valPos; # (necessary because ReadFPXValue updates this) - # read entry as a VT_VARIANT (use FlashPix module for this) - $val = Image::ExifTool::FlashPix::ReadFPXValue($et, $dataPt, $vPos, - Image::ExifTool::FlashPix::VT_VARIANT(), $valPos+$valLen, 1); - } else { - $format = "Unknown($valType)"; - } - SetByteOrder('MM'); # back to native QuickTime byte ordering - last if ++$i >= $count or $more < 6; - push @vals, $val; - undef $val; - $valPos += $valLen + 6; # step to next value - } - if (@vals) { - push @vals, $val if defined $val; - $val = \@vals; - $valPos = $pos + $tagLen + 18; - $valLen = $size - 18 - $tagLen; - } + my $valLen = $size - 8 - $tagLen; if ($tagLen > 0 and $valLen > 0) { + my $tag = substr($$dataPt, $pos + 8, $tagLen); + my $valPos = $pos + 8 + $tagLen; + my ($val, $format) = ReadXtraValue($et, substr($$dataPt, $valPos, $valLen)); + last unless defined $val; + $val = $$val[0] if @$val == 1; my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); unless ($tagInfo) { # generate tag information for unrecognized tags @@ -850,6 +1064,7 @@ sub ProcessXtra($$$) $et->VPrint(0, $$et{INDENT}, "[adding Microsoft:$tag]\n"); } } + my $count = ref $val ? scalar @$val : 1; $et->HandleTag($tagTablePtr, $tag, $val, TagInfo => $tagInfo, DataPt => $dataPt, @@ -857,7 +1072,7 @@ sub ProcessXtra($$$) Start => $valPos, Size => $valLen, Format => $format, - Extra => " count=$count type=$valType", + Extra => " count=$count", ); } $pos += $size; # step to next entry @@ -880,11 +1095,12 @@ This module is used by Image::ExifTool =head1 DESCRIPTION This module contains definitions required by Image::ExifTool to interpret -Microsoft-specific EXIF and XMP tags. +Microsoft-specific EXIF and XMP tags, and routines to read/write Microsoft +Xtra tags in videos. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Minolta.pm b/src/Image-ExifTool/lib/Image/ExifTool/Minolta.pm index 4115c21e..c9925202 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Minolta.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Minolta.pm @@ -31,10 +31,10 @@ # 22) http://www.mi-fo.de/forum/index.php?act=attach&type=post&id=6024 # 23) Marcin Krol private communication # 24) http://cpanforum.com/threads/12291 -# 26) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3521.0.html -# 27) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3833.0.html +# 26) https://exiftool.org/forum/index.php/topic,3521.0.html +# 27) https://exiftool.org/forum/index.php/topic,3833.0.html # 28) Michael Reitinger private communication (RX100) -# 29) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,4086.0.html +# 29) https://exiftool.org/forum/index.php/topic,4086.0.html # IB) Iliah Borg private communication (LibRaw) # JD) Jens Duttke private communication # JR) Jos Roost private communication @@ -49,7 +49,7 @@ use vars qw($VERSION %minoltaLensTypes %minoltaTeleconverters %minoltaColorMode use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; -$VERSION = '2.66'; +$VERSION = '2.87'; # Full list of product codes for Sony-compatible Minolta lenses # (ref http://www.kb.sony.com/selfservice/documentLink.do?externalId=C1000570) @@ -236,12 +236,13 @@ $VERSION = '2.66'; 24 => 'Minolta/Sony AF 24-105mm F3.5-4.5 (D) or Sigma or Tamron Lens', # 24 => 'Sony 24-105mm F3.5-4.5 (SAL24105)', (ref JR) 24.1 => 'Sigma 18-50mm F2.8', - 24.2 => 'Sigma 17-70mm F2.8-4.5 (D)', + 24.2 => 'Sigma 17-70mm F2.8-4.5 DC Macro', # (changed "(D)" to "DC Macro", ref JR) 24.3 => 'Sigma 20-40mm F2.8 EX DG Aspherical IF', #JD/22 24.4 => 'Sigma 18-200mm F3.5-6.3 DC', #22 24.5 => 'Sigma DC 18-125mm F4-5,6 D', #exiv2 0.23 # 24.6 => 'Tamron SP AF 28-75mm F2.8 XR Di (IF) Macro', #JD 24.6 => 'Tamron SP AF 28-75mm F2.8 XR Di LD Aspherical [IF] Macro', #NJ (Model A09) + 24.7 => 'Sigma 15-30mm F3.5-4.5 EX DG Aspherical', #JR 25 => 'Minolta AF 100-300mm F4.5-5.6 APO (D) or Sigma Lens', 25.1 => 'Sigma 100-300mm F4 EX (APO (D) or D IF)', #JD 25.2 => 'Sigma 70mm F2.8 EX DG Macro', #JD @@ -250,6 +251,7 @@ $VERSION = '2.66'; 25.5 => 'Sigma 24mm F1.8 EX DG ASP Macro', #Florian Knorn # 25 - also seen for an "old Sigma 50mm Macro" (forum2833) 27 => 'Minolta AF 85mm F1.4 G (D)', # added (D) (ref 13) + # 27 => 'Venus Optics Laowa 105mm F2 STF', #IB (NC) 28 => 'Minolta/Sony AF 100mm F2.8 Macro (D) or Tamron Lens', # 28 => 'Sony 100mm F2.8 Macro (SAL100M28)', (ref 18/JR) 28.1 => 'Tamron SP AF 90mm F2.8 Di Macro', #JD (Model 272E) @@ -287,12 +289,14 @@ $VERSION = '2.66'; 45 => 'Carl Zeiss Planar T* 85mm F1.4 ZA (SAL85F14Z)', #JR 46 => 'Carl Zeiss Vario-Sonnar T* DT 16-80mm F3.5-4.5 ZA (SAL1680Z)', #JR 47 => 'Carl Zeiss Sonnar T* 135mm F1.8 ZA (SAL135F18Z)', #JR - 48 => 'Carl Zeiss Vario-Sonnar T* 24-70mm F2.8 ZA SSM (SAL2470Z) or ZA SSM II', #11/JR + 48 => 'Carl Zeiss Vario-Sonnar T* 24-70mm F2.8 ZA SSM (SAL2470Z) or Other Lens', #11/JR 48.1 => 'Carl Zeiss Vario-Sonnar T* 24-70mm F2.8 ZA SSM II (SAL2470Z2)', #JR + 48.2 => 'Tamron SP 24-70mm F2.8 Di USD', #IB (A007) (also with id 204) 49 => 'Sony DT 55-200mm F4-5.6 (SAL55200)', #JD/JR 50 => 'Sony DT 18-250mm F3.5-6.3 (SAL18250)', #11/JR 51 => 'Sony DT 16-105mm F3.5-5.6 (SAL16105)', #11/JR #51.1 => 'Sony AF DT 55-200mm F4-5.5', #11 (anomaly? - PH) + # LensType 52 also seen for Fringer Contax_N to E-mount adapter Ver.31 and Ver.21 (ref JR) 52 => 'Sony 70-300mm F4.5-5.6 G SSM (SAL70300G) or G SSM II or Tamron Lens', #JD 52.1 => 'Sony 70-300mm F4.5-5.6 G SSM II (SAL70300G2)', #JR 52.2 => 'Tamron SP 70-300mm F4-5.6 Di USD', #JR,NJ (Model A005) @@ -303,7 +307,7 @@ $VERSION = '2.66'; 55.1 => 'Sony DT 18-55mm F3.5-5.6 SAM II (SAL18552)', #JR 56 => 'Sony DT 55-200mm F4-5.6 SAM (SAL55200-2)', #22/JR 57 => 'Sony DT 50mm F1.8 SAM (SAL50F18) or Tamron Lens or Commlite CM-EF-NEX adapter', #22/JR - 57.1 => 'Tamron SP AF 60mm F2 Di II LD [IF] Macro 1:1', # (Model G005) (ref http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3858.0.html) + 57.1 => 'Tamron SP AF 60mm F2 Di II LD [IF] Macro 1:1', # (Model G005) (ref https://exiftool.org/forum/index.php/topic,3858.0.html) 57.2 => 'Tamron 18-270mm F3.5-6.3 Di II PZD', #27 (Model B008) # (note: the Commlite CM-EF-NEX adapter also appears to give LensType 57, ref JR) 58 => 'Sony DT 30mm F2.8 Macro SAM (SAL30M28)', #22/JR @@ -324,35 +328,35 @@ $VERSION = '2.66'; # was 128.1 => 'Tamron 18-200mm F3.5-6.3', 128.2 => 'Tamron AF 28-300mm F3.5-6.3 XR Di LD Aspherical [IF] Macro', #JR (Model A061) # was 128.2 => 'Tamron 28-300mm F3.5-6.3', - 128.3 => 'Tamron 80-300mm F3.5-6.3', - 128.4 => 'Tamron AF 28-200mm F3.8-5.6 XR Di Aspherical [IF] Macro', #JD (Model A031) + # (removed -- probably never existed, ref IB) 'Tamron 80-300mm F3.5-6.3', + 128.3 => 'Tamron AF 28-200mm F3.8-5.6 XR Di Aspherical [IF] Macro', #JD (Model A031) # also Tamron AF 28-200mm F3.8-5.6 Aspherical', #IB (Model 71D) # and 'Tamron AF 28-200mm F3.8-5.6 LD Aspherical [IF] Super', #IB (Model 171D) - 128.5 => 'Tamron SP AF 17-35mm F2.8-4 Di LD Aspherical IF', #JD (Model A05) - 128.6 => 'Sigma AF 50-150mm F2.8 EX DC APO HSM II', #JD - 128.7 => 'Sigma 10-20mm F3.5 EX DC HSM', #11 (Model 202-205) - 128.8 => 'Sigma 70-200mm F2.8 II EX DG APO MACRO HSM', #24 - 128.9 => 'Sigma 10mm F2.8 EX DC HSM Fisheye', #Florian Knorn + 128.4 => 'Tamron SP AF 17-35mm F2.8-4 Di LD Aspherical IF', #JD (Model A05) + 128.5 => 'Sigma AF 50-150mm F2.8 EX DC APO HSM II', #JD + 128.6 => 'Sigma 10-20mm F3.5 EX DC HSM', #11 (Model 202-205) + 128.7 => 'Sigma 70-200mm F2.8 II EX DG APO MACRO HSM', #24 + 128.8 => 'Sigma 10mm F2.8 EX DC HSM Fisheye', #Florian Knorn # (yes, '128.10'. My condolences to typed languages that use this database - PH) - '128.10' => 'Sigma 50mm F1.4 EX DG HSM', #Florian Knorn (Model A014, ref IB) - '128.11' => 'Sigma 85mm F1.4 EX DG HSM', #27 - '128.12' => 'Sigma 24-70mm F2.8 IF EX DG HSM', #27 - '128.13' => 'Sigma 18-250mm F3.5-6.3 DC OS HSM', #27 - '128.14' => 'Sigma 17-50mm F2.8 EX DC HSM', #Exiv2 - '128.15' => 'Sigma 17-70mm F2.8-4 DC Macro HSM', #JR (OS Model C013, ref IB) - '128.16' => 'Sigma 150mm F2.8 EX DG OS HSM APO Macro', #Marcus Holland-Moritz - '128.17' => 'Sigma 150-500mm F5-6.3 APO DG OS HSM', #IB - '128.18' => 'Tamron AF 28-105mm F4-5.6 [IF]', #IB (Model 179D) - '128.19' => 'Sigma 35mm F1.4 DG HSM', #JR - '128.20' => 'Sigma 18-35mm F1.8 DC HSM', #JR (Model A013, ref IB) - '128.21' => 'Sigma 50-500mm F4.5-6.3 APO DG OS HSM', #JR - '128.22' => 'Sigma 24-105mm F4 DG HSM | A', #JR (013) - '128.23' => 'Sigma 30mm F1.4', #IB - '128.24' => 'Sigma 35mm F1.4 DG HSM | A', #IB/JR (012) - '128.25' => 'Sigma 105mm F2.8 EX DG OS HSM Macro', #IB - '128.26' => 'Sigma 180mm F2.8 EX DG OS HSM APO Macro', #IB - '128.27' => 'Sigma 18-300mm F3.5-6.3 DC Macro HSM | C', #IB/JR (014) - '128.28' => 'Sigma 18-50mm F2.8-4.5 DC HSM', #IB + 128.9 => 'Sigma 50mm F1.4 EX DG HSM', #Florian Knorn (Model A014, ref IB) + '128.10' => 'Sigma 85mm F1.4 EX DG HSM', #27 + '128.11' => 'Sigma 24-70mm F2.8 IF EX DG HSM', #27 + '128.12' => 'Sigma 18-250mm F3.5-6.3 DC OS HSM', #27 + '128.13' => 'Sigma 17-50mm F2.8 EX DC HSM', #Exiv2 + '128.14' => 'Sigma 17-70mm F2.8-4 DC Macro HSM', # (no OS for Sony mount, ref JR) (also C013 Model, ref IB) + '128.15' => 'Sigma 150mm F2.8 EX DG OS HSM APO Macro', #Marcus Holland-Moritz + '128.16' => 'Sigma 150-500mm F5-6.3 APO DG OS HSM', #IB + '128.17' => 'Tamron AF 28-105mm F4-5.6 [IF]', #IB (Model 179D) + '128.18' => 'Sigma 35mm F1.4 DG HSM', #JR + '128.19' => 'Sigma 18-35mm F1.8 DC HSM', #JR (Model A013, ref IB) + '128.20' => 'Sigma 50-500mm F4.5-6.3 APO DG OS HSM', #JR + '128.21' => 'Sigma 24-105mm F4 DG HSM | A', #JR (013) + '128.22' => 'Sigma 30mm F1.4', #IB + '128.23' => 'Sigma 35mm F1.4 DG HSM | A', #IB/JR (012) + '128.24' => 'Sigma 105mm F2.8 EX DG OS HSM Macro', #IB + '128.25' => 'Sigma 180mm F2.8 EX DG OS HSM APO Macro', #IB + '128.26' => 'Sigma 18-300mm F3.5-6.3 DC Macro HSM | C', #IB/JR (014) + '128.27' => 'Sigma 18-50mm F2.8-4.5 DC HSM', #IB 129 => 'Tamron Lens (129)', 129.1 => 'Tamron 200-400mm F5.6 LD', #12 (LD ref 23) 129.2 => 'Tamron 70-300mm F4-5.6 LD', #12 @@ -362,12 +366,14 @@ $VERSION = '2.66'; 137 => 'Cosina 70-210mm F2.8-4 AF', #11 138 => 'Soligor 19-35mm F3.5-4.5', #11 139 => 'Tokina AF 28-300mm F4-6.3', #IB - 142 => 'Voigtlander 70-300mm F4.5-5.6', #JD + # (the following Cosina 70-300mm lens was also marketed as a Phoenix, Vivitar Series 1, and + # some sort of 3rd-party marketing as a Voightlander 70-300mm F4.5-5.6 SKOPAR AF, ref IB) + 142 => 'Cosina AF 70-300mm F4.5-5.6 MC', #IB (was 'Voigtlander 70-300mm F4.5-5.6', #JD) 146 => 'Voigtlander Macro APO-Lanthar 125mm F2.5 SL', #JD 194 => 'Tamron SP AF 17-50mm F2.8 XR Di II LD Aspherical [IF]', #23 (Model A16) 202 => 'Tamron SP AF 70-200mm F2.8 Di LD [IF] Macro', #JR (Model A001) (see also 255.7) 203 => 'Tamron SP 70-200mm F2.8 Di USD', #JR (Model A009) - 204 => 'Tamron SP 24-70mm F2.8 Di USD', #JR (Model A007) + 204 => 'Tamron SP 24-70mm F2.8 Di USD', #JR (Model A007) (also with id 48) 212 => 'Tamron 28-300mm F3.5-6.3 Di PZD', #JR (Model A010) 213 => 'Tamron 16-300mm F3.5-6.3 Di II PZD Macro', #JR (Model B016) 214 => 'Tamron SP 150-600mm F5-6.3 Di USD', #JR (Model A011) @@ -409,10 +415,11 @@ $VERSION = '2.66'; 25521.7 => 'Angenieux AF 28-70mm F2.6', #JD 25521.8 => 'Tokina AT-X 17 AF 17mm F3.5', #27 25521.9 => 'Tokina 20-35mm F3.5-4.5 II AF', #IB - 25531 => 'Minolta AF 28-135mm F4-4.5 or Sigma Lens', + 25531 => 'Minolta AF 28-135mm F4-4.5 or Other Lens', 25531.1 => 'Sigma ZOOM-alpha 35-135mm F3.5-4.5', #16 25531.2 => 'Sigma 28-105mm F2.8-4 Aspherical', #JD 25531.3 => 'Sigma 28-105mm F4-5.6 UC', #JR + 25531.4 => 'Tokina AT-X 242 AF 24-200mm F3.5-5.6', #IB 25541 => 'Minolta AF 35-105mm F3.5-4.5', #13 25551 => 'Minolta AF 70-210mm F4 Macro or Sigma Lens', 25551.1 => 'Sigma 70-210mm F4-5.6 APO', #7 @@ -431,7 +438,7 @@ $VERSION = '2.66'; 25611.5 => 'Tokina AT-X AF 300mm F4', #JD 25611.6 => 'Tokina AT-X AF 400mm F5.6 SD', #22 25611.7 => 'Tokina AF 730 II 75-300mm F4.5-5.6', #JD - 25611.8 => 'Sigma 800mm F5.6 APO', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3472.0.html + 25611.8 => 'Sigma 800mm F5.6 APO', #https://exiftool.org/forum/index.php/topic,3472.0.html 25611.9 => 'Sigma AF 400mm F5.6 APO Macro', #27 '25611.10' => 'Sigma 1000mm F8 APO', #JR 25621 => 'Minolta AF 50mm F1.4 [New]', # original and New, not Sony (ref 13/18) @@ -444,7 +451,7 @@ $VERSION = '2.66'; 25641.1 => 'Sigma 50mm F2.8 EX Macro', #11 25651 => 'Minolta AF 600mm F4 APO', # ("APO" added - ref JR) 25661 => 'Minolta AF 24mm F2.8 or Sigma Lens', - 25661.1 => 'Sigma 17-35mm F2.8-4 EX Aspherical', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3789.msg17679.html#msg17679 + 25661.1 => 'Sigma 17-35mm F2.8-4 EX Aspherical', #https://exiftool.org/forum/index.php/topic,3789.msg17679.html#msg17679 25721 => 'Minolta/Sony AF 500mm F8 Reflex', # 25721 => 'Sony 500mm F8 Reflex (SAL500F80)', (ref JR) 25781 => 'Minolta/Sony AF 16mm F2.8 Fisheye or Sigma Lens', # Sony added (ref 13/18) @@ -454,12 +461,12 @@ $VERSION = '2.66'; 25781.3 => 'Sigma 15mm F2.8 Fisheye', #JD (writes 16mm to EXIF) 25791 => 'Minolta/Sony AF 20mm F2.8 or Tokina Lens', # Sony added (ref 11) # 25791 => 'Sony 20mm F2.8 (SAL20F28)', (ref JR) - 25791.1 => 'Tokina AT-X Pro DX 11-16mm F2.8', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3593.0.html + 25791.1 => 'Tokina AT-X Pro DX 11-16mm F2.8', #https://exiftool.org/forum/index.php/topic,3593.0.html 25811 => 'Minolta AF 100mm F2.8 Macro [New] or Sigma or Tamron Lens', # not Sony (ref 13/18) 25811.1 => 'Sigma AF 90mm F2.8 Macro', #JD 25811.2 => 'Sigma AF 105mm F2.8 EX [DG] Macro', #JD 25811.3 => 'Sigma 180mm F5.6 Macro', - 25811.4 => 'Sigma 180mm F3.5 EX DG Macro', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3789.msg17679.html#msg17679 + 25811.4 => 'Sigma 180mm F3.5 EX DG Macro', #https://exiftool.org/forum/index.php/topic,3789.msg17679.html#msg17679 25811.5 => 'Tamron 90mm F2.8 Macro', 25851 => 'Beroflex 35-135mm F3.5-4.5', #16 25858 => 'Minolta AF 35-105mm F3.5-4.5 New or Tamron Lens', @@ -499,7 +506,7 @@ $VERSION = '2.66'; 26241 => 'Minolta AF 35-80mm F4-5.6 Power Zoom', 26281 => 'Minolta AF 80-200mm F2.8 HS-APO G', #11 ("HS-APO" added, white, probably same as 1, non-HS is 25891 - ref JR) 26291 => 'Minolta AF 85mm F1.4 New', - 26311 => 'Minolta/Sony AF 100-300mm F4.5-5.6 APO', #11 + 26311 => 'Minolta AF 100-300mm F4.5-5.6 APO', #11 (does not exist? https://www.dyxum.com/dforum/lens-data-requested_topic23435_page2.html) 26321 => 'Minolta AF 24-50mm F4 New', 26381 => 'Minolta AF 50mm F2.8 Macro New', 26391 => 'Minolta AF 100mm F2.8 Macro', @@ -514,6 +521,7 @@ $VERSION = '2.66'; # - this is the base to which the Canon LensType is added 30464 => 'Metabones Canon EF Speed Booster', #Metabones (to this, add Canon LensType) 45671 => 'Tokina 70-210mm F4-5.6', #22 + 45681 => 'Tokina AF 35-200mm F4-5.6 Zoom SD', #IB (model 352) 45701 => 'Tamron AF 35-135mm F3.5-4.5', #IB (model 40d) 45711 => 'Vivitar 70-210mm F4.5-5.6', #IB 45741 => '2x Teleconverter or Tamron or Tokina Lens', #18 @@ -538,108 +546,13 @@ $VERSION = '2.66'; 65280 => 'Sigma 16mm F2.8 Filtermatic Fisheye', #IB # all M42-type lenses give a value of 65535 (and FocalLength=0, FNumber=1) 65535 => 'E-Mount, T-Mount, Other Lens or no lens', #JD/JR -# -# Sony E-type lenses (NOTE: these should be kept in sync with %sonyLensTypes2 of Sony.pm) -# - 65535.1 => 'Sony E 16mm F2.8', #PH (32784 - SEL16F28) - 65535.2 => 'Sony E 18-55mm F3.5-5.6 OSS', #PH (32785 - SEL1855) - 65535.3 => 'Sony E 55-210mm F4.5-6.3 OSS', #PH (32786 - SEL55210) - 65535.4 => 'Sony E 18-200mm F3.5-6.3 OSS', #PH (32787 - SEL18200) - 65535.5 => 'Sony E 30mm F3.5 Macro', #JR (32788 - SEL30M35) - 65535.6 => 'Sony E 24mm F1.8 ZA', #PH (32789 - SEL24F18Z) - 65535.7 => 'Sony E 50mm F1.8 OSS', #PH (32790 - SEL50F18) - 65535.8 => 'Sony E 16-70mm F4 ZA OSS', #JR (32791 - SEL1670Z) - 65535.9 => 'Sony E 10-18mm F4 OSS', #PH (32792 - SEL1018) - '65535.10' => 'Sony E PZ 16-50mm F3.5-5.6 OSS', #PH (32793 - SELP1650) - '65535.11' => 'Sony FE 35mm F2.8 ZA', #JR (32794 - SEL35F28Z) - '65535.12' => 'Sony FE 24-70mm F4 ZA OSS', #JR (32795 - SEL2470Z) - '65535.13' => 'Sony FE 85mm F1.8', #JR (32796 - SEL85F18) - '65535.14' => 'Sony E 18-200mm F3.5-6.3 OSS LE', #JR (32797 or 0 - SEL18200LE) - '65535.15' => 'Sony E 20mm F2.8', #PH (32798 - SEL20F28) - '65535.16' => 'Sony E 35mm F1.8 OSS', #JR (32799 - SEL35F18) - '65535.17' => 'Sony E PZ 18-105mm F4 G OSS', #JR (32800 - SELP18105G) - '65535.18' => 'Sony FE 12-24mm F4 G', #JR (32801 - SEL1224G) - '65535.19' => 'Sony FE 90mm F2.8 Macro G OSS', #JR (32802 - SEL90M28G) - '65535.20' => 'Sony E 18-50mm F4-5.6', #JR (32803 - SEL1850) - '65535.21' => 'Sony FE 24mm F1.4 GM', #IB (32804 - SEL24F14GM) - '65535.22' => 'Sony FE 24-105mm F4 G OSS', #IB (32805 - SEL24105G) - '65535.23' => 'Sony E PZ 18-200mm F3.5-6.3 OSS', #JR (32807 - SELP18200) - '65535.24' => 'Sony FE 55mm F1.8 ZA', #JR (32808 - SEL55F18Z) - '65535.25' => 'Sony FE 70-200mm F4 G OSS', #JR (32810 - SEL70200G) - '65535.26' => 'Sony FE 16-35mm F4 ZA OSS', #JR (32811 - SEL1635Z) - '65535.27' => 'Sony FE 50mm F2.8 Macro', #JR (32812 - SEL50M28) - '65535.28' => 'Sony FE 28-70mm F3.5-5.6 OSS', #JR (32813 - SEL2870) - '65535.29' => 'Sony FE 35mm F1.4 ZA', #JR (32814 - SEL35F14Z) - '65535.30' => 'Sony FE 24-240mm F3.5-6.3 OSS', #JR (32815 - SEL24240) - '65535.31' => 'Sony FE 28mm F2', #JR (32816 - SEL28F20) - '65535.32' => 'Sony FE PZ 28-135mm F4 G OSS', #JR (32817 - SELP28135G) - '65535.33' => 'Sony FE 100mm F2.8 STF GM OSS', #JR (32819 - SEL100F28GM, uses 33076 when set to 0.57m - 1.0m range) - '65535.34' => 'Sony E PZ 18-110mm F4 G OSS', #JR (32820 - SELP18110G) - '65535.35' => 'Sony FE 24-70mm F2.8 GM', #JR (32821 - SEL2470GM) - '65535.36' => 'Sony FE 50mm F1.4 ZA', #JR (32822 - SEL50F14Z) - '65535.37' => 'Sony FE 85mm F1.4 GM', #JR (32823 - SEL85F14GM) - '65535.38' => 'Sony FE 50mm F1.8', #JR (32824 - SEL50F18F with trailing "F" as compared to 32790) - '65535.39' => 'Sony FE 21mm F2.8 (SEL28F20 + SEL075UWC)', #JR (32826 - SEL28F20 + SEL075UWC Ultra-wide converter) - '65535.40' => 'Sony FE 16mm F3.5 Fisheye (SEL28F20 + SEL057FEC)', #JR (32827 - SEL28F20 + SEL057FEC Fisheye converter) - '65535.41' => 'Sony FE 70-300mm F4.5-5.6 G OSS', #JR (32828 - SEL70300G) - '65535.42' => 'Sony FE 100-400mm F4.5-5.6 GM OSS', #JR (32829 - SEL100400GM) - '65535.43' => 'Sony FE 70-200mm F2.8 GM OSS', #JR (32830 - SEL70200GM) - '65535.44' => 'Sony FE 16-35mm F2.8 GM', #JR (32831 - SEL1635GM) - '65535.45' => 'Sony FE 400mm F2.8 GM OSS', #IB (32848 - SEL400F28GM) - '65535.46' => 'Sony E 18-135mm F3.5-5.6 OSS', #JR (32849 - SEL18135) - '65535.47' => 'Sony FE 70-200mm F2.8 GM OSS + 1.4X Teleconverter', #JR (33072 - SEL70200GM + SEL14TC) - '65535.48' => 'Sony FE 70-200mm F2.8 GM OSS + 2X Teleconverter', #JR (33073 - SEL70200GM + SEL20TC) - '65535.49' => 'Sony FE 100-400mm F4.5-5.6 GM OSS + 1.4X Teleconverter', #JR (33077 - SEL100400GM + SEL14TC) - '65535.50' => 'Sony FE 100-400mm F4.5-5.6 GM OSS + 2X Teleconverter', #JR (33078 - SEL100400GM + SEL20TC) - '65535.51' => 'Sony FE 400mm F2.8 GM OSS + 1.4X Teleconverter', #IB (33079 - SEL400F28GM + SEL14TC) - '65535.52' => 'Sony FE 400mm F2.8 GM OSS + 2X Teleconverter', #JR (33080 - SEL400F28GM + SEL20TC) -# -# 3rd party E lenses -# - '65535.53' => 'Samyang AF 50mm F1.4 FE', #JR (32789) - '65535.54' => 'Samyang AF 14mm F2.8 FE', #JR (32790 and 51505) - '65535.55' => 'Samyang AF 24mm F2.8', #JR (32794) - '65535.56' => 'Samyang AF 35mm F2.8 FE', #PH (51505) - '65535.57' => 'Samyang AF 35mm F1.4', #IB (51507) - '65535.58' => 'Sigma 19mm F2.8 [EX] DN', #JR (0) - '65535.59' => 'Sigma 30mm F2.8 [EX] DN', #JR (0) - '65535.60' => 'Sigma 60mm F2.8 DN', #JR (0) - '65535.61' => 'Sigma 30mm F1.4 DC DN | C', #IB (50480) (016) - '65535.62' => 'Sigma 85mm F1.4 DG HSM | A', #JR (50499) (018) - '65535.63' => 'Sigma 16mm F1.4 DC DN | C', #JR (50503) (017) - '65535.64' => 'Sigma 70mm F2.8 DG MACRO | A', #JR (50513) (018) - '65535.65' => 'Tamron 18-200mm F3.5-6.3 Di III VC', #JR (0 - Model B011) - '65535.66' => 'Tamron 28-75mm F2.8 Di III RXD', #JR (49457 - Model A036) - '65535.67' => 'Tokina Firin 20mm F2 FE MF', #JR (0) - '65535.68' => 'Voigtlander SUPER WIDE-HELIAR 15mm F4.5 III', #JR (50992) - '65535.69' => 'Voigtlander HELIAR-HYPER WIDE 10mm F5.6', #IB (50993) - '65535.70' => 'Voigtlander ULTRA WIDE-HELIAR 12mm F5.6 III', #IB (50994) - '65535.71' => 'Voigtlander MACRO APO-LANTHAR 65mm F2 Aspherical', #JR (50995) - '65535.72' => 'Voigtlander NOKTON 40mm F1.2 Aspherical', #JR (50996) - '65535.73' => 'Voigtlander NOKTON classic 35mm F1.4', #JR (50997) - '65535.74' => 'Zeiss Touit 12mm F2.8', #JR (49201 or 0) - '65535.75' => 'Zeiss Touit 32mm F1.8', #JR (49202 or 0) - '65535.76' => 'Zeiss Touit 50mm F2.8 Macro', #JR (49203 or 0) - '65535.77' => 'Zeiss Batis 25mm F2', #JR (49216) - '65535.78' => 'Zeiss Batis 85mm F1.8', #JR (49217) - '65535.79' => 'Zeiss Batis 18mm F2.8', #IB (49218) - '65535.80' => 'Zeiss Batis 135mm F2.8', #IB (49219) - '65535.81' => 'Zeiss Batis 40mm F2 CF', #JR (49220) - '65535.82' => 'Zeiss Loxia 50mm F2', #JR (49232 or 0) - '65535.83' => 'Zeiss Loxia 35mm F2', #JR (49233 or 0) - '65535.84' => 'Zeiss Loxia 21mm F2.8', #JR (49234) - '65535.85' => 'Zeiss Loxia 85mm F2.4', #JR (49235) - '65535.86' => 'Zeiss Loxia 25mm F2.4', #JR (49236) -# -# other lenses -# - '65535.87' => 'Arax MC 35mm F2.8 Tilt+Shift', #JD - '65535.88' => 'Arax MC 80mm F2.8 Tilt+Shift', #JD - '65535.89' => 'Zenitar MF 16mm F2.8 Fisheye M42', #JD - '65535.90' => 'Samyang 500mm Mirror F8.0', #19 - '65535.91' => 'Pentacon Auto 135mm F2.8', #19 - '65535.92' => 'Pentacon Auto 29mm F2.8', #19 - '65535.93' => 'Helios 44-2 58mm F2.0', #19 + '65535.1' => 'Arax MC 35mm F2.8 Tilt+Shift', #JD + '65535.2' => 'Arax MC 80mm F2.8 Tilt+Shift', #JD + '65535.3' => 'Zenitar MF 16mm F2.8 Fisheye M42', #JD + '65535.4' => 'Samyang 500mm Mirror F8.0', #19 + '65535.5' => 'Pentacon Auto 135mm F2.8', #19 + '65535.6' => 'Pentacon Auto 29mm F2.8', #19 + '65535.7' => 'Helios 44-2 58mm F2.0', #19 ); %minoltaTeleconverters = ( @@ -689,13 +602,18 @@ $VERSION = '2.66'; 15 => 'Light', #JR (NC) 16 => 'Autumn Leaves', #JR (NC) 17 => 'Sepia', #JR + 18 => 'FL', #JR (7SM3) + 19 => 'Vivid 2', #JR (7SM3) + 20 => 'IN', #JR (7SM3) + 21 => 'SH', #JR (7SM3) 100 => 'Neutral', #JD 101 => 'Clear', #JD 102 => 'Deep', #JD 103 => 'Light', #JD 104 => 'Night View', #JD 105 => 'Autumn Leaves', #JD - 0xffffffff => 'n/a', #PH + 255 => 'Off', #JR (new for ILCE-7SM3, July 2020) + 0xffffffff => 'n/a', #PH ); %minoltaSceneMode = ( @@ -1925,7 +1843,7 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); }, ); -# Image stabilization inforamtion used by the Sony DSLR-A100 (ref 20) +# Image stabilization information used by the Sony DSLR-A100 (ref 20) %Image::ExifTool::Minolta::ISInfoA100 = ( PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, WRITE_PROC => \&Image::ExifTool::WriteBinaryData, @@ -2774,7 +2692,7 @@ my %offOn = ( 0 => 'Off', 1 => 'On' ); PrintConv => 'int($val + 0.5)', PrintConvInv => '$val', }, - 0x49bb => { # (http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3688.0.html) + 0x49bb => { # (https://exiftool.org/forum/index.php/topic,3688.0.html) # if this value is the 35mm equivalent magnification, then the formula could # be (1.5 * 2**($val/16-5)+1) * FocalLength, but this tends to underestimate # distance by about 18% (ref 20) (255=inf) @@ -2974,7 +2892,7 @@ sub ConvertWhiteBalance($) my $printConv = $minoltaWhiteBalance{$val}; unless (defined $printConv) { if ($val & 0xffff0000) { - # the A2 values can be shifted by += 3 settings, where + # the A2 values can be shifted by +- 3 settings, where # each setting adds or subtracts 0x0010000 (ref 2) my $type = ($val & 0xff000000) + 0x800000; if ($minoltaWhiteBalance{$type}) { @@ -3010,7 +2928,7 @@ and write Minolta RAW (MRW) images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/MinoltaRaw.pm b/src/Image-ExifTool/lib/Image/ExifTool/MinoltaRaw.pm index 32d4b0c8..0610448c 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/MinoltaRaw.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/MinoltaRaw.pm @@ -17,7 +17,7 @@ use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Minolta; -$VERSION = '1.15'; +$VERSION = '1.16'; sub ProcessMRW($$;$); sub WriteMRW($$;$); @@ -59,10 +59,12 @@ sub WriteMRW($$;$); CHECK_PROC => \&Image::ExifTool::CheckBinaryData, WRITABLE => 1, GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + DATAMEMBER => [ 0 ], FIRST_ENTRY => 0, 0 => { Name => 'FirmwareID', Format => 'string[8]', + RawConv => '$$self{MinoltaPRD} = 1 if $$self{FILE_TYPE} eq "MRW"; $val', # used in decoding RIF info }, 8 => { Name => 'SensorHeight', @@ -214,38 +216,37 @@ sub WriteMRW($$;$); PrintConv => \%Image::ExifTool::Minolta::sonyColorMode, }, ], - # NOTE: some of these WB_RBLevels may apply to other models too... + # NOTE: WB_RBLevels up to Custom also apply to Minolta models which write PRD info (ref IB) 8 => { #3 Name => 'WB_RBLevelsTungsten', - Condition => '$$self{Model} eq "DSLR-A100"', + Condition => '$$self{Model} eq "DSLR-A100" or $$self{MinoltaPRD}', Format => 'int16u[2]', Notes => 'these WB_RBLevels currently decoded only for the Sony A100', }, 12 => { #3 Name => 'WB_RBLevelsDaylight', - Condition => '$$self{Model} eq "DSLR-A100"', + Condition => '$$self{Model} eq "DSLR-A100" or $$self{MinoltaPRD}', Format => 'int16u[2]', }, 16 => { #3 Name => 'WB_RBLevelsCloudy', - Condition => '$$self{Model} eq "DSLR-A100"', + Condition => '$$self{Model} eq "DSLR-A100" or $$self{MinoltaPRD}', Format => 'int16u[2]', }, 20 => { #3 Name => 'WB_RBLevelsCoolWhiteF', - Condition => '$$self{Model} eq "DSLR-A100"', + Condition => '$$self{Model} eq "DSLR-A100" or $$self{MinoltaPRD}', Format => 'int16u[2]', }, 24 => { #3 Name => 'WB_RBLevelsFlash', - Condition => '$$self{Model} eq "DSLR-A100"', + Condition => '$$self{Model} eq "DSLR-A100" or $$self{MinoltaPRD}', Format => 'int16u[2]', }, 28 => { #3 - Name => 'WB_RBLevelsUnknown', - Condition => '$$self{Model} eq "DSLR-A100"', + Name => 'WB_RBLevelsCustom', #IB + Condition => '$$self{Model} eq "DSLR-A100" or $$self{MinoltaPRD}', Format => 'int16u[2]', - Unknown => 1, }, 32 => { #3 Name => 'WB_RBLevelsShade', @@ -511,7 +512,7 @@ write Konica-Minolta RAW (MRW) images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Motorola.pm b/src/Image-ExifTool/lib/Image/ExifTool/Motorola.pm new file mode 100644 index 00000000..5b6786aa --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/Motorola.pm @@ -0,0 +1,178 @@ +#------------------------------------------------------------------------------ +# File: Motorola.pm +# +# Description: Read Motorola meta information +# +# Revisions: 2015/10/29 - P. Harvey Created +# +# References: 1) Neal Krawetz private communication +#------------------------------------------------------------------------------ + +package Image::ExifTool::Motorola; + +use strict; +use vars qw($VERSION); +use Image::ExifTool::Exif; + +$VERSION = '1.02'; + +# Motorola makernotes tags (ref PH) +%Image::ExifTool::Motorola::Main = ( + WRITE_PROC => \&Image::ExifTool::Exif::WriteExif, + CHECK_PROC => \&Image::ExifTool::Exif::CheckExif, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + WRITABLE => 1, + # 0x54e0 - int8u: 1 + # 0x54f0 - float + 0x5500 => { Name => 'BuildNumber', Writable => 'string' }, #1 (eg. 'MPJ24.139-23.4') + 0x5501 => { Name => 'SerialNumber', Writable => 'string' }, #1 (eg. 'ZY2238TJ4V') + # 0x5502 - int8u + # 0x5503 - int8u + # 0x5510 - int8u: 0,1 + # 0x5511 - int32u (3 of these tags for some cameras) + # 0x5512 - int32u + # 0x5520 - int16s + # 0x5530 - string: 'continuous-picture','auto','continuous-video' + # 0x5540 - int8u: 95 + # 0x5550 - int8u: 85,90 + # 0x5560 - string: 'auto' + # 0x5570 - string: 'auto','auto-hdr' + # 0x5580 - int32s: 9000,14949,15000,24000 + # 0x5590 - int32s: 30000 + # 0x55a0 - int32s: 960,1280,1440 + # 0x55b0 - int32s: 720,960,1080 + # 0x55c0 - int32s: 30 + # 0x55d0 - string: 'yuv420sp' + # 0x55e0-0x55e9 - int16u + # 0x55f0 - int8u: 10 + # 0x55f1 - int8u: 13 + # 0x55f2-0x55f5 - int16u[130] + # 0x5600 - int8u: 0,16 + # 0x5601 - int16u[16] + # 0x5602 - int32u[3,50] + # 0x5603 - int32u: 0 + # 0x6400 - string: 'AUTO','ON','OFF' + # 0x6401 - string: 'HDR' + # 0x6410 - string: 'NO','YES' + # 0x6420 - int32s for some models: 0 (only exists in HDR images?) + 0x6420 => { #forum13731 + Condition => '$format eq "string"', + Name => 'CustomRendered', + Writable => 'string', + }, + # 0x6430 - float + # 0x6431 - int8u: 0,1 + # 0x6432 - int8u: 0,79,100 + # 0x6433 - int8u: 0,1 + # 0x6434 - int8u: 0,65,100 + # 0x6435 - int8u: 1,6,24 + # 0x6436 - int8u: 55,60 + # 0x6437 - int8u: 30,35,40 + # 0x6438 - int8u: 24,40 + # 0x6439 - int8u: 15,50 + # 0x643a - int8u: 0,20 + # 0x643b - string: '2,8,-4','2,10,-4','' + # 0x643c - int32s + # 0x643d - float + # 0x6440 - int8u[N]: 0's and 1's + # 0x6441 - int8u[N] + # 0x6442,0x6443 - int8u[N]: 0's and 1's + # 0x644d - string: 'YES' + # 0x644f - float + # 0x6450 - float + # 0x6451 - float: 0.699999988079071 + # 0x6452 - int8u: 1 + # 0x6470 - string: 'AUTO' + # 0x6471 - int8u: 1 + # 0x6473 - int8u: 24 + # 0x6474 - int8u: 10 + # 0x6475 - int32u[24] + # 0x6476 - int32u: 2 + # 0x6490 - int8u: 0 + # 0x64c0 - int32s: 0,2 + # 0x64c1 - int32u: 1,4,64 + # 0x64c2,0x64c3 - int32s + # 0x64c4 - int32s + # 0x64c5 - int32u + 0x64d0 => { Name => 'DriveMode', Writable => 'string' }, #forum13731 + # 0x6500 - int8u: 1 + # 0x6501 - string: 'Luma-Chroma Plane','Chroma only' or int8u: 0 + # 0x6502 - string: 'Luma-Chroma Plane','Chroma only','' or int8u: 1,255 + # 0x6504 - int32s + # 0x6530-0x6535 - int32s + # 0x6600-0x6605 - int8u + # 0x6606 - string: 'D50','TL84','5000' - illuminant? color temperature? + # 0x6607 - string: 'D50g','D65','3000' - illuminant? color temperature? + # 0x6608 - string: 'A' + # 0x6609-0x660e - float + # 0x660f - int12u + # 0x6612-0x661b - int16u + # 0x661d - int16u + # 0x661e-0x6635 - float + # 0x6637 - int8u[212] + # 0x6640,0x6641 - int8u + # 0x6642-0x6649 - int16u + # 0x664e - in8u + # 0x664f-0x6652 - int16u + # 0x6653 - string: 'QC','AL' + # 0x6654-0x6656 - int16u + # 0x665d - int8u: 0 + 0x665e => { Name => 'Sensor', Writable => 'string' }, # (eg. 'BACK,IMX230') + # 0x6700 - string: eg. 'eac040d0','333e1721','001b7b3a','000000000005040f' + # 0x6701 - string: eg. '14048001',940140230','940140190' + # 0x6702 - string: '0L','1L','0S','3S','32','33,'42' + # 0x6703 - string: 'PR','SEG','LIG','LI','SHV','SH','SO' + # 0x6704 - string: 'DO','GX1','GZ0','GZ1','GX2','VI','VI1','VI2','GU','' + 0x6705 => { Name => 'ManufactureDate', Writable => 'string' }, # (NC, eg. '03Jun2015') + # 0x6706 - string: eg. '30454e4e','42%','01%','01','1','904c2ca2' + # 0x6707 - string: eg. '1','25a2ca16','002371e1','69' + # 0x6708-0x670c - string or int16u (string may be firmware revision) + # 0x6800 - int32u: 1,2 + # 0x6801,0x6802 - float + # 0x6803 - int16u + # 0x6804,0x6805 - float + # 0x6806 - int16u,int32s + # 0x6807 - int32s,int32u[3] + # 0x6808 - int32u,int32u[3] + # 0x6809,0x680a - float[3] + # 0x680d - int8u: 0 + # 0x680e - float: 0 + # 0x7000 - int8u: 0,2 + # 0x7001,0x7002 - int16s + # 0x7003-0x7005 - int16u + # 0x7100 - string: '0-7' + # 0x7101 - string: '4-7','0-7' + # 0x7102 - string: '0-3','' + # 0x7103,0x7104 - string: comma-separated lists of numbers +); + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::Motorola - Read Motorola meta information + +=head1 SYNOPSIS + +This module is loaded automatically by Image::ExifTool when required. + +=head1 DESCRIPTION + +This module contains the definitions to read meta information from Motorola +cell phone images. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/Motorola Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Nikon.pm b/src/Image-ExifTool/lib/Image/ExifTool/Nikon.pm index 2dc334e0..b3377724 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Nikon.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Nikon.pm @@ -41,11 +41,14 @@ # 27) Jens Kriese private communication # 28) Warren Hatch private communication (D3v2.00 with SB-800 and SB-900) # 29) Anonymous contribution 2011/05/25 (D700, D7000) -# 30) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3833.30.html +# 30) https://exiftool.org/forum/index.php/topic,3833.30.html # 31) Michael Relt private communication -# 32) Stefan http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,4494.0.html +# 32) Stefan https://exiftool.org/forum/index.php/topic,4494.0.html # 34) Stewart Bennett private communication (D4S, D810) # 35) David Puschel private communication +# 36) Hayo Baann (forum10207) +# 37) Tom Lachecki, private communication +# 38) https://github.com/exiftool/exiftool/pull/40 (and forum10893) # IB) Iliah Borg private communication (LibRaw) # JD) Jens Duttke private communication # NJ) Niels Kristian Bech Jensen private communication @@ -58,8 +61,9 @@ use vars qw($VERSION %nikonLensIDs %nikonTextEncoding); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; use Image::ExifTool::GPS; +use Image::ExifTool::XMP; -$VERSION = '3.54'; +$VERSION = '4.09'; sub LensIDConv($$$); sub ProcessNikonAVI($$$); @@ -78,11 +82,9 @@ sub GetAFPointGrid($$;$); The Nikon LensID is constructed as a Composite tag from the raw hex values of 8 other tags: LensIDNumber, LensFStops, MinFocalLength, MaxFocalLength, MaxApertureAtMinFocal, MaxApertureAtMaxFocal, MCUVersion and LensType, in - that order. (source: - L<http://www.rottmerhusen.com/objektives/lensid/thirdparty.html>.) Multiple - lenses with the same LensID are differentiated by decimal values in the list - below. The user-defined "Lenses" list may be used to specify the lens for - ExifTool to choose in these cases (see the + that order. Multiple lenses with the same LensID are differentiated by + decimal values in the list below. The user-defined "Lenses" list may be + used to specify the lens for ExifTool to choose in these cases (see the L<sample config file|../config.html> for details). }, OTHER => \&LensIDConv, @@ -271,13 +273,14 @@ sub GetAFPointGrid($$;$); '9F 58 44 44 14 14 A1 06' => 'AF-S DX Nikkor 35mm f/1.8G', #27 'A0 54 50 50 0C 0C A2 06' => 'AF-S Nikkor 50mm f/1.4G', 'A1 40 18 37 2C 34 A3 06' => 'AF-S DX Nikkor 10-24mm f/3.5-4.5G ED', + 'A1 40 2D 53 2C 3C CB 86' => 'AF-P DX Nikkor 18-55mm f/3.5-5.6G', #30 'A2 48 5C 80 24 24 A4 0E' => 'AF-S Nikkor 70-200mm f/2.8G ED VR II', 'A3 3C 29 44 30 30 A5 0E' => 'AF-S Nikkor 16-35mm f/4G ED VR', 'A4 54 37 37 0C 0C A6 06' => 'AF-S Nikkor 24mm f/1.4G ED', 'A5 40 3C 8E 2C 3C A7 0E' => 'AF-S Nikkor 28-300mm f/3.5-5.6G ED VR', 'A6 48 8E 8E 24 24 A8 0E' => 'AF-S Nikkor 300mm f/2.8G IF-ED VR II', 'A7 4B 62 62 2C 2C A9 0E' => 'AF-S DX Micro Nikkor 85mm f/3.5G ED VR', - 'A8 48 80 98 30 30 AA 0E' => 'AF-S Zoom-Nikkor 200-400mm f/4G IF-ED VR II', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3218.msg15495.html#msg15495 + 'A8 48 80 98 30 30 AA 0E' => 'AF-S Zoom-Nikkor 200-400mm f/4G IF-ED VR II', #https://exiftool.org/forum/index.php/topic,3218.msg15495.html#msg15495 'A9 54 80 80 18 18 AB 0E' => 'AF-S Nikkor 200mm f/2G ED VR II', 'AA 3C 37 6E 30 30 AC 0E' => 'AF-S Nikkor 24-120mm f/4G ED VR', 'AC 38 53 8E 34 3C AE 0E' => 'AF-S DX Nikkor 55-300mm f/4.5-5.6G ED VR', @@ -296,6 +299,7 @@ sub GetAFPointGrid($$;$); 'B8 40 2D 44 2C 34 BA 06' => 'AF-S Nikkor 18-35mm f/3.5-4.5G ED', 'A0 40 2D 74 2C 3C BB 0E' => 'AF-S DX Nikkor 18-140mm f/3.5-5.6G ED VR', #PH 'A1 54 55 55 0C 0C BC 06' => 'AF-S Nikkor 58mm f/1.4G', #IB + 'A1 48 6E 8E 24 24 DB 4E' => 'AF-S Nikkor 120-300mm f/2.8E FL ED SR VR', #28 'A2 40 2D 53 2C 3C BD 0E' => 'AF-S DX Nikkor 18-55mm f/3.5-5.6G VR II', 'A4 40 2D 8E 2C 40 BF 0E' => 'AF-S DX Nikkor 18-300mm f/3.5-6.3G ED VR', 'A5 4C 44 44 14 14 C0 06' => 'AF-S Nikkor 35mm f/1.8G ED', #35 ("ED" ref 11) @@ -315,6 +319,7 @@ sub GetAFPointGrid($$;$); 'A0 40 2D 53 2C 3C CA 8E' => 'AF-P DX Nikkor 18-55mm f/3.5-5.6G', #Yang You pvt communication 'A0 40 2D 53 2C 3C CA 0E' => 'AF-P DX Nikkor 18-55mm f/3.5-5.6G VR', #PH 'AF 4C 37 37 14 14 CC 06' => 'AF-S Nikkor 24mm f/1.8G ED', #IB + 'A2 38 5C 8E 34 40 CD 86' => 'AF-P DX Nikkor 70-300mm f/4.5-6.3G VR', #PH 'A3 38 5C 8E 34 40 CE 8E' => 'AF-P DX Nikkor 70-300mm f/4.5-6.3G ED VR', 'A3 38 5C 8E 34 40 CE 0E' => 'AF-P DX Nikkor 70-300mm f/4.5-6.3G ED', 'A4 48 5C 80 24 24 CF 4E' => 'AF-S Nikkor 70-200mm f/2.8E FL ED VR', @@ -333,6 +338,7 @@ sub GetAFPointGrid($$;$); 'AA 48 88 A4 3C 3C D5 0E' => 'AF-S Nikkor 180-400mm f/4E TC1.4 FL ED VR + 1.4x TC', 'AB 44 5C 8E 34 3C D6 CE' => 'AF-P Nikkor 70-300mm f/4.5-5.6E ED VR', 'AB 44 5C 8E 34 3C D6 0E' => 'AF-P Nikkor 70-300mm f/4.5-5.6E ED VR', + 'AB 44 5C 8E 34 3C D6 4E' => 'AF-P Nikkor 70-300mm f/4.5-5.6E ED VR', #IB 'AC 54 3C 3C 0C 0C D7 46' => 'AF-S Nikkor 28mm f/1.4E ED', 'AC 54 3C 3C 0C 0C D7 06' => 'AF-S Nikkor 28mm f/1.4E ED', 'AD 3C A0 A0 3C 3C D8 0E' => 'AF-S Nikkor 500mm f/5.6E PF ED VR', @@ -345,6 +351,7 @@ sub GetAFPointGrid($$;$); 'FE 47 00 00 24 24 4B 06' => 'Sigma 4.5mm F2.8 EX DC HSM Circular Fisheye', #JD '26 48 11 11 30 30 1C 02' => 'Sigma 8mm F4 EX Circular Fisheye', '79 40 11 11 2C 2C 1C 06' => 'Sigma 8mm F3.5 EX Circular Fisheye', #JD + 'DB 40 11 11 2C 2C 1C 06' => 'Sigma 8mm F3.5 EX DG Circular Fisheye', #30 'DC 48 19 19 24 24 4B 06' => 'Sigma 10mm F2.8 EX DC HSM Fisheye', 'C2 4C 24 24 14 14 4B 06' => 'Sigma 14mm F1.8 DG HSM | A', #IB '48 48 24 24 24 24 4B 02' => 'Sigma 14mm F2.8 EX Aspherical HSM', @@ -362,12 +369,13 @@ sub GetAFPointGrid($$;$); '91 54 44 44 0C 0C 4B 06' => 'Sigma 35mm F1.4 DG HSM', #30 'DE 54 50 50 0C 0C 4B 06' => 'Sigma 50mm F1.4 EX DG HSM', '88 54 50 50 0C 0C 4B 06' => 'Sigma 50mm F1.4 DG HSM | A', - '02 48 50 50 24 24 02 00' => 'Sigma Macro 50mm F2.8', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,4027.0.html + '02 48 50 50 24 24 02 00' => 'Sigma Macro 50mm F2.8', #https://exiftool.org/forum/index.php/topic,4027.0.html '32 54 50 50 24 24 35 02' => 'Sigma Macro 50mm F2.8 EX DG', - 'E3 54 50 50 24 24 35 02' => 'Sigma Macro 50mm F2.8 EX DG', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3215.0.html + 'E3 54 50 50 24 24 35 02' => 'Sigma Macro 50mm F2.8 EX DG', #https://exiftool.org/forum/index.php/topic,3215.0.html '79 48 5C 5C 24 24 1C 06' => 'Sigma Macro 70mm F2.8 EX DG', #JD '9B 54 62 62 0C 0C 4B 06' => 'Sigma 85mm F1.4 EX DG HSM', 'C8 54 62 62 0C 0C 4B 46' => 'Sigma 85mm F1.4 DG HSM | A', #JamiBradley + 'C8 54 62 62 0C 0C 4B 06' => 'Sigma 85mm F1.4 DG HSM | A', #KennethCochran '02 48 65 65 24 24 02 00' => 'Sigma Macro 90mm F2.8', '32 54 6A 6A 24 24 35 02.2' => 'Sigma Macro 105mm F2.8 EX DG', #JD 'E5 54 6A 6A 24 24 35 02' => 'Sigma Macro 105mm F2.8 EX DG', @@ -377,6 +385,7 @@ sub GetAFPointGrid($$;$); '99 48 76 76 24 24 4B 0E' => 'Sigma APO Macro 150mm F2.8 EX DG OS HSM', #(Christian Hesse) '48 4C 7C 7C 2C 2C 4B 02' => 'Sigma APO Macro 180mm F3.5 EX DG HSM', '48 4C 7D 7D 2C 2C 4B 02' => 'Sigma APO Macro 180mm F3.5 EX DG HSM', + 'F4 4C 7C 7C 2C 2C 4B 02' => 'Sigma APO Macro 180mm F3.5 EX DG HSM', #Bruno '94 48 7C 7C 24 24 4B 0E' => 'Sigma APO Macro 180mm F2.8 EX DG OS HSM', #MichaelTapes (HSM from ref 8) '48 54 8E 8E 24 24 4B 02' => 'Sigma APO 300mm F2.8 EX DG HSM', 'FB 54 8E 8E 24 24 4B 02' => 'Sigma APO 300mm F2.8 EX DG HSM', #26 @@ -396,6 +405,7 @@ sub GetAFPointGrid($$;$); '48 38 1F 37 34 3C 4B 06' => 'Sigma 12-24mm F4.5-5.6 EX DG Aspherical HSM', 'F0 38 1F 37 34 3C 4B 06' => 'Sigma 12-24mm F4.5-5.6 EX DG Aspherical HSM', '96 38 1F 37 34 3C 4B 06' => 'Sigma 12-24mm F4.5-5.6 II DG HSM', #Jurgen Sahlberg + 'CA 3C 1F 37 30 30 4B 46' => 'Sigma 12-24mm F4 DG HSM | A', #github issue#101 'C1 48 24 37 24 24 4B 46' => 'Sigma 14-24mm F2.8 DG HSM | A', #30 '26 40 27 3F 2C 34 1C 02' => 'Sigma 15-30mm F3.5-4.5 EX DG Aspherical DF', '48 48 2B 44 24 30 4B 06' => 'Sigma 17-35mm F2.8-4 EX DG Aspherical HSM', @@ -406,7 +416,7 @@ sub GetAFPointGrid($$;$); '7A 48 2B 5C 24 34 4B 06' => 'Sigma 17-70mm F2.8-4.5 DC Macro Asp. IF HSM', '7F 48 2B 5C 24 34 1C 06' => 'Sigma 17-70mm F2.8-4.5 DC Macro Asp. IF', '8E 3C 2B 5C 24 30 4B 0E' => 'Sigma 17-70mm F2.8-4 DC Macro OS HSM | C', - 'A0 48 2A 5C 24 30 4B 0E' => 'Sigma 17-70mm F2.8-4 DC Macro OS HSM', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,5170.0.html + 'A0 48 2A 5C 24 30 4B 0E' => 'Sigma 17-70mm F2.8-4 DC Macro OS HSM', #https://exiftool.org/forum/index.php/topic,5170.0.html '8B 4C 2D 44 14 14 4B 06' => 'Sigma 18-35mm F1.8 DC HSM', #30/NJ '26 40 2D 44 2B 34 1C 02' => 'Sigma 18-35mm F3.5-4.5 Aspherical', '26 48 2D 50 24 24 1C 06' => 'Sigma 18-50mm F2.8 EX DC', @@ -423,9 +433,11 @@ sub GetAFPointGrid($$;$); '7A 40 2D 80 2C 40 4B 0E' => 'Sigma 18-200mm F3.5-6.3 DC OS HSM', 'ED 40 2D 80 2C 40 4B 0E' => 'Sigma 18-200mm F3.5-6.3 DC OS HSM', #JD '90 40 2D 80 2C 40 4B 0E' => 'Sigma 18-200mm F3.5-6.3 II DC OS HSM', #JohnHelour + '89 30 2D 80 2C 40 4B 0E' => 'Sigma 18-200mm F3.5-6.3 DC Macro OS HS | C', #JoeSchonberg 'A5 40 2D 88 2C 40 4B 0E' => 'Sigma 18-250mm F3.5-6.3 DC OS HSM', # LensFStops varies with FocalLength for this lens (ref 2): '92 2C 2D 88 2C 40 4B 0E' => 'Sigma 18-250mm F3.5-6.3 DC Macro OS HSM', #2 + '87 2C 2D 8E 2C 40 4B 0E' => 'Sigma 18-300mm F3.5-6.3 DC Macro HSM', #30 # '92 2C 2D 88 2C 40 4B 0E' (250mm) # '92 2B 2D 88 2C 40 4B 0E' (210mm) # '92 2C 2D 88 2C 40 4B 0E' (185mm) @@ -442,6 +454,7 @@ sub GetAFPointGrid($$;$); # '92 3E 2D 88 2C 40 4B 0E' (22mm) # '92 40 2D 88 2C 40 4B 0E' (18mm) '26 48 31 49 24 24 1C 02' => 'Sigma 20-40mm F2.8', + '7B 48 37 44 18 18 4B 06' => 'Sigma 24-35mm F2.0 DG HSM | A', #30 '02 3A 37 50 31 3D 02 00' => 'Sigma 24-50mm F4-5.6 UC', '26 48 37 56 24 24 1C 02' => 'Sigma 24-60mm F2.8 EX DG', 'B6 48 37 56 24 24 1C 02' => 'Sigma 24-60mm F2.8 EX DG', @@ -467,7 +480,7 @@ sub GetAFPointGrid($$;$); '26 40 3C 80 2B 3C 1C 02' => 'Sigma 28-200mm F3.5-5.6 Compact Aspherical Hyperzoom Macro', '26 3D 3C 80 2F 3D 1C 02' => 'Sigma 28-300mm F3.8-5.6 Aspherical', '26 41 3C 8E 2C 40 1C 02' => 'Sigma 28-300mm F3.5-6.3 DG Macro', - 'E6 41 3C 8E 2C 40 1C 02' => 'Sigma 28-300mm F3.5-6.3 DG Macro', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3301.0.html + 'E6 41 3C 8E 2C 40 1C 02' => 'Sigma 28-300mm F3.5-6.3 DG Macro', #https://exiftool.org/forum/index.php/topic,3301.0.html '26 40 3C 8E 2C 40 1C 02' => 'Sigma 28-300mm F3.5-6.3 Macro', '02 3B 44 61 30 3D 02 00' => 'Sigma 35-80mm F4-5.6', '02 40 44 73 2B 36 02 00' => 'Sigma 35-135mm F3.5-4.5 a', @@ -483,9 +496,11 @@ sub GetAFPointGrid($$;$); '7A 48 5C 80 24 24 4B 06' => 'Sigma 70-200mm F2.8 EX APO DG Macro HSM II', 'EE 48 5C 80 24 24 4B 06' => 'Sigma 70-200mm F2.8 EX APO DG Macro HSM II', #JD '9C 48 5C 80 24 24 4B 0E' => 'Sigma 70-200mm F2.8 EX DG OS HSM', #Rolando Ruzic + 'BB 48 5C 80 24 24 4B 4E' => 'Sigma 70-200mm F2.8 DG OS HSM | S', #forum13207 '02 46 5C 82 25 25 02 00' => 'Sigma 70-210mm F2.8 APO', #JD '02 40 5C 82 2C 35 02 00' => 'Sigma APO 70-210mm F3.5-4.5', '26 3C 5C 82 30 3C 1C 02' => 'Sigma 70-210mm F4-5.6 UC-II', + '02 3B 5C 82 30 3C 02 00' => 'Sigma Zoom-K 70-210mm F4-5.6', #30 '26 3C 5C 8E 30 3C 1C 02' => 'Sigma 70-300mm F4-5.6 DG Macro', '56 3C 5C 8E 30 3C 1C 02' => 'Sigma 70-300mm F4-5.6 APO Macro Super II', 'E0 3C 5C 8E 30 3C 4B 06' => 'Sigma 70-300mm F4-5.6 APO DG Macro HSM', #22 @@ -496,9 +511,10 @@ sub GetAFPointGrid($$;$); '77 44 60 98 34 3C 7B 0E' => 'Sigma 80-400mm F4.5-5.6 APO DG D OS', '48 48 68 8E 30 30 4B 02' => 'Sigma APO 100-300mm F4 EX IF HSM', 'F3 48 68 8E 30 30 4B 02' => 'Sigma APO 100-300mm F4 EX IF HSM', + '26 45 68 8E 34 42 1C 02' => 'Sigma 100-300mm F4.5-6.7 DL', #30 '48 54 6F 8E 24 24 4B 02' => 'Sigma APO 120-300mm F2.8 EX DG HSM', '7A 54 6E 8E 24 24 4B 02' => 'Sigma APO 120-300mm F2.8 EX DG HSM', - 'FA 54 6E 8E 24 24 4B 02' => 'Sigma APO 120-300mm F2.8 EX DG HSM', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,2787.0.html + 'FA 54 6E 8E 24 24 4B 02' => 'Sigma APO 120-300mm F2.8 EX DG HSM', #https://exiftool.org/forum/index.php/topic,2787.0.html 'CF 38 6E 98 34 3C 4B 0E' => 'Sigma APO 120-400mm F4.5-5.6 DG OS HSM', 'C3 34 68 98 38 40 4B 4E' => 'Sigma 100-400mm F5-6.3 DG OS HSM | C', #JR (017) '8D 48 6E 8E 24 24 4B 0E' => 'Sigma 120-300mm F2.8 DG OS HSM Sports', @@ -506,14 +522,18 @@ sub GetAFPointGrid($$;$); 'CE 34 76 A0 38 40 4B 0E' => 'Sigma 150-500mm F5-6.3 DG OS APO HSM', #JD '81 34 76 A6 38 40 4B 0E' => 'Sigma 150-600mm F5-6.3 DG OS HSM | S', #Jaap Voets '82 34 76 A6 38 40 4B 0E' => 'Sigma 150-600mm F5-6.3 DG OS HSM | C', + 'C4 4C 73 73 14 14 4B 46' => 'Sigma 135mm F1.8 DG HSM | A', #forum3833 '26 40 7B A0 34 40 1C 02' => 'Sigma APO 170-500mm F5-6.3 Aspherical RF', 'A7 49 80 A0 24 24 4B 06' => 'Sigma APO 200-500mm F2.8 EX DG', '48 3C 8E B0 3C 3C 4B 02' => 'Sigma APO 300-800mm F5.6 EX DG HSM', + 'D2 3C 8E B0 3C 3C 4B 02' => 'Sigma APO 300-800mm F5.6 EX DG HSM', #forum10942 # '00 47 25 25 24 24 00 02' => 'Tamron SP AF 14mm f/2.8 Aspherical (IF) (69E)', + 'C8 54 44 44 0D 0D DF 46' => 'Tamron SP 35mm f/1.4 Di USD (F045)', #IB 'E8 4C 44 44 14 14 DF 0E' => 'Tamron SP 35mm f/1.8 Di VC USD (F012)', #35 'E7 4C 4C 4C 14 14 DF 0E' => 'Tamron SP 45mm f/1.8 Di VC USD (F013)', 'F4 54 56 56 18 18 84 06' => 'Tamron SP AF 60mm f/2.0 Di II Macro 1:1 (G005)', #24 + 'E5 4C 62 62 14 14 C9 4E' => 'Tamron SP 85mm f/1.8 Di VC USD (F016)', #30 '1E 5D 64 64 20 20 13 00' => 'Tamron SP AF 90mm f/2.5 (52E)', '20 5A 64 64 20 20 14 00' => 'Tamron SP AF 90mm f/2.5 Macro (152E)', '22 53 64 64 24 24 E0 02' => 'Tamron SP AF 90mm f/2.8 Macro 1:1 (72E)', @@ -525,29 +545,33 @@ sub GetAFPointGrid($$;$); '00 4C 7C 7C 2C 2C 00 02' => 'Tamron SP AF 180mm f/3.5 Di Model (B01)', '21 56 8E 8E 24 24 14 00' => 'Tamron SP AF 300mm f/2.8 LD-IF (60E)', '27 54 8E 8E 24 24 1D 02' => 'Tamron SP AF 300mm f/2.8 LD-IF (360E)', - 'E1 40 19 36 2C 35 DF 4E' => 'Tamron 10-24mm F/3.5-4.5 Di II VC HLD (B023)', + 'E1 40 19 36 2C 35 DF 4E' => 'Tamron 10-24mm f/3.5-4.5 Di II VC HLD (B023)', 'F6 3F 18 37 2C 34 84 06' => 'Tamron SP AF 10-24mm f/3.5-4.5 Di II LD Aspherical (IF) (B001)', 'F6 3F 18 37 2C 34 DF 06' => 'Tamron SP AF 10-24mm f/3.5-4.5 Di II LD Aspherical (IF) (B001)', #30 '00 36 1C 2D 34 3C 00 06' => 'Tamron SP AF 11-18mm f/4.5-5.6 Di II LD Aspherical (IF) (A13)', 'E9 48 27 3E 24 24 DF 0E' => 'Tamron SP 15-30mm f/2.8 Di VC USD (A012)', #IB - 'EA 40 29 8E 2C 40 DF 0E' => 'Tamron AF 16-300mm f/3.5-6.3 Di II VC PZD (B016)', + 'CA 48 27 3E 24 24 DF 4E' => 'Tamron SP 15-30mm f/2.8 Di VC USD G2 (A041)', #IB + 'EA 40 29 8E 2C 40 DF 0E' => 'Tamron 16-300mm f/3.5-6.3 Di II VC PZD (B016)', # (removed AF designation, ref 37) '07 46 2B 44 24 30 03 02' => 'Tamron SP AF 17-35mm f/2.8-4 Di LD Aspherical (IF) (A05)', + 'CB 3C 2B 44 24 31 DF 46' => 'Tamron 17-35mm f/2.8-4 Di OSD (A037)', #IB '00 53 2B 50 24 24 00 06' => 'Tamron SP AF 17-50mm f/2.8 XR Di II LD Aspherical (IF) (A16)', #PH + '7C 54 2B 50 24 24 00 06' => 'Tamron SP AF 17-50mm f/2.8 XR Di II LD Aspherical (IF) (A16)', #PH (https://github.com/Exiv2/exiv2/issues/1155) '00 54 2B 50 24 24 00 06' => 'Tamron SP AF 17-50mm f/2.8 XR Di II LD Aspherical (IF) (A16NII)', - 'FB 54 2B 50 24 24 84 06' => 'Tamron SP AF 17-50mm f/2.8 XR Di II LD Aspherical (IF) (A16NII)', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3787.0.html + 'FB 54 2B 50 24 24 84 06' => 'Tamron SP AF 17-50mm f/2.8 XR Di II LD Aspherical (IF) (A16NII)', #https://exiftool.org/forum/index.php/topic,3787.0.html 'F3 54 2B 50 24 24 84 0E' => 'Tamron SP AF 17-50mm f/2.8 XR Di II VC LD Aspherical (IF) (B005)', '00 3F 2D 80 2B 40 00 06' => 'Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical (IF) (A14)', '00 3F 2D 80 2C 40 00 06' => 'Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical (IF) Macro (A14)', + 'EC 3E 3C 8E 2C 40 DF 0E' => 'Tamron 28-300mm f/3.5-6.3 Di VC PZD A010', #30 '00 40 2D 80 2C 40 00 06' => 'Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical (IF) Macro (A14NII)', #NJ 'FC 40 2D 80 2C 40 DF 06' => 'Tamron AF 18-200mm f/3.5-6.3 XR Di II LD Aspherical (IF) Macro (A14NII)', #PH (NC) - 'E6 40 2D 80 2C 40 DF 0E' => 'Tamron AF 18-200mm f/3.5-6.3 Di II VC (B018)', #Tanel + 'E6 40 2D 80 2C 40 DF 0E' => 'Tamron 18-200mm f/3.5-6.3 Di II VC (B018)', #Tanel (removed AF designation, ref 37) '00 40 2D 88 2C 40 62 06' => 'Tamron AF 18-250mm f/3.5-6.3 Di II LD Aspherical (IF) Macro (A18)', '00 40 2D 88 2C 40 00 06' => 'Tamron AF 18-250mm f/3.5-6.3 Di II LD Aspherical (IF) Macro (A18NII)', #JD 'F5 40 2C 8A 2C 40 40 0E' => 'Tamron AF 18-270mm f/3.5-6.3 Di II VC LD Aspherical (IF) Macro (B003)', 'F0 3F 2D 8A 2C 40 DF 0E' => 'Tamron AF 18-270mm f/3.5-6.3 Di II VC PZD (B008)', - 'E0 40 2D 98 2C 41 DF 4E' => 'Tamron AF 18-400mm f/3.5-6.3 Di II VC HLD (B028)', + 'E0 40 2D 98 2C 41 DF 4E' => 'Tamron 18-400mm f/3.5-6.3 Di II VC HLD (B028)', # (removed AF designation, ref 37) '07 40 2F 44 2C 34 03 02' => 'Tamron AF 19-35mm f/3.5-4.5 (A10)', - '07 40 30 45 2D 35 03 02' => 'Tamron AF 19-35mm f/3.5-4.5 (A10)', + '07 40 30 45 2D 35 03 02.1' => 'Tamron AF 19-35mm f/3.5-4.5 (A10)', '00 49 30 48 22 2B 00 02' => 'Tamron SP AF 20-40mm f/2.7-3.5 (166D)', '0E 4A 31 48 23 2D 0E 02' => 'Tamron SP AF 20-40mm f/2.7-3.5 (166D)', 'FE 48 37 5C 24 24 DF 0E' => 'Tamron SP 24-70mm f/2.8 Di VC USD (A007)', #24 @@ -566,6 +590,7 @@ sub GetAFPointGrid($$;$); '4D 41 3C 8E 2B 40 62 02' => 'Tamron AF 28-300mm f/3.5-6.3 XR Di LD Aspherical (IF) (A061)', '4D 41 3C 8E 2C 40 62 02' => 'Tamron AF 28-300mm f/3.5-6.3 XR LD Aspherical (IF) (185D)', 'F9 40 3C 8E 2C 40 40 0E' => 'Tamron AF 28-300mm f/3.5-6.3 XR Di VC LD Aspherical (IF) Macro (A20)', + 'C9 3C 44 76 25 31 DF 4E' => 'Tamron 35-150mm f/2.8-4 Di VC OSD (A043)', #30 '00 47 53 80 30 3C 00 06' => 'Tamron AF 55-200mm f/4-5.6 Di II LD (A15)', 'F7 53 5C 80 24 24 84 06' => 'Tamron SP AF 70-200mm f/2.8 Di LD (IF) Macro (A001)', 'FE 53 5C 80 24 24 84 06' => 'Tamron SP AF 70-200mm f/2.8 Di LD (IF) Macro (A001)', @@ -577,8 +602,11 @@ sub GetAFPointGrid($$;$); '69 47 5C 8E 30 3C 00 02' => 'Tamron AF 70-300mm f/4-5.6 Di LD Macro 1:2 (A17N)', '00 48 5C 8E 30 3C 00 06' => 'Tamron AF 70-300mm f/4-5.6 Di LD Macro 1:2 (A17NII)', #JD 'F1 47 5C 8E 30 3C DF 0E' => 'Tamron SP 70-300mm f/4-5.6 Di VC USD (A005)', + 'CF 47 5C 8E 31 3D DF 0E' => 'Tamron SP 70-300mm f/4-5.6 Di VC USD (A030)', #forum9773 + 'CC 44 68 98 34 41 DF 0E' => 'Tamron 100-400mm f/4.5-6.3 Di VC USD', #30 'EB 40 76 A6 38 40 DF 0E' => 'Tamron SP AF 150-600mm f/5-6.3 VC USD (A011)', 'E3 40 76 A6 38 40 DF 4E' => 'Tamron SP 150-600mm f/5-6.3 Di VC USD G2', #30 + 'E3 40 76 A6 38 40 DF 0E' => 'Tamron SP 150-600mm f/5-6.3 Di VC USD G2 (A022)', #forum3833 '20 3C 80 98 3D 3D 1E 02' => 'Tamron AF 200-400mm f/5.6 LD IF (75D)', '00 3E 80 A0 38 3F 00 02' => 'Tamron SP AF 200-500mm f/5-6.3 Di LD (IF) (A08)', '00 3F 80 A0 38 3F 00 02' => 'Tamron SP AF 200-500mm f/5-6.3 Di (A08)', @@ -592,7 +620,9 @@ sub GetAFPointGrid($$;$); '00 40 18 2B 2C 34 00 06' => 'Tokina AT-X 107 AF DX Fisheye (AF 10-17mm f/3.5-4.5)', '00 48 1C 29 24 24 00 06' => 'Tokina AT-X 116 PRO DX (AF 11-16mm f/2.8)', '7A 48 1C 29 24 24 7E 06' => 'Tokina AT-X 116 PRO DX II (AF 11-16mm f/2.8)', + '80 48 1C 29 24 24 7A 06' => 'Tokina atx-i 11-16mm F2.8 CF', #exiv2 issue 1078 '7A 48 1C 30 24 24 7E 06' => 'Tokina AT-X 11-20 F2.8 PRO DX (AF 11-20mm f/2.8)', + '8B 48 1C 30 24 24 85 06' => 'Tokina AT-X 11-20 F2.8 PRO DX (AF 11-20mm f/2.8)', #forum12687 '00 3C 1F 37 30 30 00 06' => 'Tokina AT-X 124 AF PRO DX (AF 12-24mm f/4)', '7A 3C 1F 37 30 30 7E 06.2' => 'Tokina AT-X 124 AF PRO DX II (AF 12-24mm f/4)', '7A 3C 1F 3C 30 30 7E 06' => 'Tokina AT-X 12-28 PRO DX (AF 12-28mm f/4)', @@ -621,6 +651,7 @@ sub GetAFPointGrid($$;$); '24 44 60 98 34 3C 1A 02' => 'Tokina AT-X 840 AF-II (AF 80-400mm f/4.5-5.6)', '00 44 60 98 34 3C 00 02' => 'Tokina AT-X 840 D (AF 80-400mm f/4.5-5.6)', '14 48 68 8E 30 30 0B 00' => 'Tokina AT-X 340 AF (AF 100-300mm f/4)', + '8C 48 29 3C 24 24 86 06' => 'Tokina opera 16-28mm F2.8 FF', #30 # '06 3F 68 68 2C 2C 06 00' => 'Cosina AF 100mm F3.5 Macro', '07 36 3D 5F 2C 3C 03 00' => 'Cosina AF Zoom 28-80mm F3.5-5.6 MC Macro', @@ -636,8 +667,11 @@ sub GetAFPointGrid($$;$); '00 54 48 48 18 18 00 00' => 'Voigtlander Ultron 40mm F2 SLII Aspherical', '00 54 55 55 0C 0C 00 00' => 'Voigtlander Nokton 58mm F1.4 SLII', '00 40 64 64 2C 2C 00 00' => 'Voigtlander APO-Lanthar 90mm F3.5 SLII Close Focus', + '07 40 30 45 2D 35 03 02.2' => 'Voigtlander Ultragon 19-35mm F3.5-4.5 VMV', #NJ + '71 48 64 64 24 24 00 00' => 'Voigtlander APO-Skopar 90mm F2.8 SL IIs', #30 # '00 40 2D 2D 2C 2C 00 00' => 'Carl Zeiss Distagon T* 3.5/18 ZF.2', + '00 48 27 27 24 24 00 00' => 'Carl Zeiss Distagon T* 2.8/15 ZF.2', #MykytaKozlov '00 48 32 32 24 24 00 00' => 'Carl Zeiss Distagon T* 2.8/21 ZF.2', '00 54 38 38 18 18 00 00' => 'Carl Zeiss Distagon T* 2/25 ZF.2', '00 54 3C 3C 18 18 00 00' => 'Carl Zeiss Distagon T* 2/28 ZF.2', @@ -650,6 +684,7 @@ sub GetAFPointGrid($$;$); '00 54 72 72 18 18 00 00' => 'Carl Zeiss Apo Sonnar T* 2/135 ZF.2', '00 54 53 53 0C 0C 00 00' => 'Zeiss Otus 1.4/55', #IB '01 54 62 62 0C 0C 00 00' => 'Zeiss Otus 1.4/85', + '03 54 68 68 0C 0C 00 00' => 'Zeiss Otus 1.4/100', #IB '52 54 44 44 18 18 00 00' => 'Zeiss Milvus 35mm f/2', '53 54 50 50 0C 0C 00 00' => 'Zeiss Milvus 50mm f/1.4', #IB '54 54 50 50 18 18 00 00' => 'Zeiss Milvus 50mm f/2 Macro', @@ -664,14 +699,16 @@ sub GetAFPointGrid($$;$); '4A 40 11 11 2C 0C 4D 02' => 'Samyang 8mm f/3.5 Fish-Eye CS', '4A 48 24 24 24 0C 4D 02.1' => 'Samyang 10mm f/2.8 ED AS NCS CS', '4A 48 1E 1E 24 0C 4D 02' => 'Samyang 12mm f/2.8 ED AS NCS Fish-Eye', #Jurgen Sahlberg - '4A 48 24 24 24 0C 4D 02.2' => 'Samyang AE 14mm f/2.8 ED AS IF UMC', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3150.0.html + '4A 48 24 24 24 0C 4D 02.2' => 'Samyang AE 14mm f/2.8 ED AS IF UMC', #https://exiftool.org/forum/index.php/topic,3150.0.html '4A 4C 24 24 1E 6C 4D 06' => 'Samyang 14mm f/2.4 Premium', '4A 54 29 29 18 0C 4D 02' => 'Samyang 16mm f/2.0 ED AS UMC CS', #Jon Bloom (by email) '4A 60 36 36 0C 0C 4D 02' => 'Samyang 24mm f/1.4 ED AS UMC', '4A 60 44 44 0C 0C 4D 02' => 'Samyang 35mm f/1.4 AS UMC', - '4A 60 62 62 0C 0C 4D 02' => 'Samyang AE 85mm f/1.4 AS IF UMC', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,2888.0.html + '4A 60 62 62 0C 0C 4D 02' => 'Samyang AE 85mm f/1.4 AS IF UMC', #https://exiftool.org/forum/index.php/topic,2888.0.html # '9A 4C 50 50 14 14 9C 06' => 'Yongnuo YN50mm F1.8N', + '9F 48 48 48 24 24 A1 06' => 'Yongnuo YN40mm F2.8N', #30 + '9F 54 68 68 18 18 A2 06' => 'Yongnuo YN100mm F2N', #30 # '02 40 44 5C 2C 34 02 00' => 'Exakta AF 35-70mm 1:3.5-4.5 MC', # @@ -693,6 +730,10 @@ sub GetAFPointGrid($$;$); '00 48 80 80 30 30 00 00' => 'Nikkor 200mm f/4 AiS', '00 40 11 11 2C 2C 00 00' => 'Samyang 8mm f/3.5 Fish-Eye', '00 58 64 64 20 20 00 00' => 'Soligor C/D Macro MC 90mm f/2.5', + '4A 58 30 30 14 0C 4D 02' => 'Rokinon 20mm f/1.8 ED AS UMC', #30 +# + 'A0 56 44 44 14 14 A2 06' => 'Sony FE 35mm F1.8', #IB (Techart adapter) + 'A0 37 5C 8E 34 3C A2 06' => 'Sony FE 70-300mm F4.5-5.6 G OSS', #IB (Techart adapter) ); # text encoding used in LocationInfo (ref PH) @@ -718,8 +759,9 @@ my %flashFirmware = ( '4 4' => '4.04 (SB-400)', '5 1' => '5.01 (SB-900)', '5 2' => '5.02 (SB-900)', - '6 1' => '6.01 (SB-700)', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,5034.0.html + '6 1' => '6.01 (SB-700)', #https://exiftool.org/forum/index.php/topic,5034.0.html '7 1' => '7.01 (SB-910)', #PH + '14 3' => '14.03 (SB-5000)', #28 OTHER => sub { my ($val, $inv) = @_; return sprintf('%d.%.2d (Unknown model)', split(' ', $val)) unless $inv; @@ -776,6 +818,124 @@ my %flashControlMode = ( 0x07 => 'Repeating Flash', ); +my %activeDLightingZ7 = ( + 0 => 'Off', + 2 => 'Low', + 3 => 'Normal', + 4 => 'High', + 5 => 'Extra High', +); + +my %flashControlModeZ7 = ( + 0 => 'TTL', + 1 => 'Auto External Flash', + 2 => 'GN (distance priority)', + 3 => 'Manual', + 4 => 'Repeating Flash', +); + +my %flashRemoteControlZ7 = ( + 0 => 'Group', + 1 => 'Quick Wireless', + 2 => 'Remote Repeating', +); + +my %flashWirelessOptionZ7 = ( + 0 => 'Off', + 1 => 'Optical AWL', + 2 => 'Optical/Radio AWL', + 3 => 'Radio AWL', +); + +my %focusModeZ7 = ( + 0 => 'Manual', + 1 => 'AF-S', + 2 => 'AF-C', + 4 => 'AF-F', # full frame +); + +my %infoZSeries = ( + Condition => '$$self{Model} =~ /^NIKON Z (5|50|6|6_2|7|7_2|fc|9)\b/i', + Notes => 'Z Series cameras thru Decemeber 2021', +); +my %iSOAutoHiLimitZ7 = ( + 0 => 'ISO 64', + 1 => 'ISO 80', + 2 => 'ISO 100', + 3 => 'ISO 125', + 4 => 'ISO 160', + 5 => 'ISO 200', + 6 => 'ISO 250', + 7 => 'ISO 320', + 8 => 'ISO 400', + 9 => 'ISO 500', + 10 => 'ISO 640', + 11 => 'ISO 800', + 12 => 'ISO 1000', + 13 => 'ISO 1250', + 14 => 'ISO 1600', + 15 => 'ISO 2000', + 16 => 'ISO 2500', + 17 => 'ISO 3200', + 18 => 'ISO 4000', + 19 => 'ISO 5000', + 20 => 'ISO 6400', + 21 => 'ISO 8000', + 22 => 'ISO 10000', + 23 => 'ISO 12800', + 24 => 'ISO 16000', + 25 => 'ISO 20000', + 26 => 'ISO 25600', + 27 => 'ISO Hi 0.3', + 28 => 'ISO Hi 0.7', + 29 => 'ISO Hi 1.0', + 32 => 'ISO Hi 2.0', +); + +my %meteringModeZ7 = ( + 0 => 'Matrix', + 1 => 'Center', + 2 => 'Spot', + 3 => 'Highlight' +); + +my %movieFrameRateZ7 = ( + 0 => '120p', + 1 => '100p', + 2 => '60p', + 3 => '50p', + 4 => '30p', + 5 => '25p', + 6 => '24p', +); + +my %offLowNormalHighZ7 = ( + 0 => 'Off', + 1 => 'Low', + 2 => 'Normal', + 3 => 'High', +); + +my %movieFrameSizeZ9 = ( + 1 => '1920x1080', + 2 => '3840x2160', + 3 => '7680x4320', +); + +my %subjectDetectionZ9 = ( + 0 => 'Off', + 1 => 'Auto', + 2 => 'People', + 3 => 'Animals', + 4 => 'Vehicles', +); + +my %vRModeZ9 = ( + 0 => 'Off', + 1 => 'Normal', + 2 => 'Sport', +); + my %retouchValues = ( #PH 0 => 'None', 3 => 'B & W', @@ -860,6 +1020,38 @@ my %afPoints39 = ( 10 => 'E3', 20 => 'B9', 30 => 'D4', ); +# AF point indices for models with 105 focus points, eg. D6 (ref 28) +# - 7 rows (A-G) with 15 columns (1-15), center is D8 +my %afPoints105 = ( + 1 => 'D8', 28 => 'G7', 55 => 'F13', 82 => 'E4', + 2 => 'C8', 29 => 'D6', 56 => 'G13', 83 => 'F4', + 3 => 'B8', 30 => 'C6', 57 => 'D14', 84 => 'G4', + 4 => 'A8', 31 => 'B6', 58 => 'C14', 85 => 'D3', + 5 => 'E8', 32 => 'A6', 59 => 'B14', 86 => 'C3', + 6 => 'F8', 33 => 'E6', 60 => 'A14', 87 => 'B3', + 7 => 'G8', 34 => 'F6', 61 => 'E14', 88 => 'A3', + 8 => 'D9', 35 => 'G6', 62 => 'F14', 89 => 'E3', + 9 => 'C9', 36 => 'D11', 63 => 'G14', 90 => 'F3', + 10 => 'B9', 37 => 'C11', 64 => 'D15', 91 => 'G3', + 11 => 'A9', 38 => 'B11', 65 => 'C15', 92 => 'D2', + 12 => 'E9', 39 => 'A11', 66 => 'B15', 93 => 'C2', + 13 => 'F9', 40 => 'E11', 67 => 'A15', 94 => 'B2', + 14 => 'G9', 41 => 'F11', 68 => 'E15', 95 => 'A2', + 15 => 'D10', 42 => 'G11', 69 => 'F15', 96 => 'E2', + 16 => 'C10', 43 => 'D12', 70 => 'G15', 97 => 'F2', + 17 => 'B10', 44 => 'C12', 71 => 'D5', 98 => 'G2', + 18 => 'A10', 45 => 'B12', 72 => 'C5', 99 => 'D1', + 19 => 'E10', 46 => 'A12', 73 => 'B5', 100 => 'C1', + 20 => 'F10', 47 => 'E12', 74 => 'A5', 101 => 'B1', + 21 => 'G10', 48 => 'F12', 75 => 'E5', 102 => 'A1', + 22 => 'D7', 49 => 'G12', 76 => 'F5', 103 => 'E1', + 23 => 'C7', 50 => 'D13', 77 => 'G5', 104 => 'F1', + 24 => 'B7', 51 => 'C13', 78 => 'D4', 105 => 'G1', + 25 => 'A7', 52 => 'B13', 79 => 'C4', + 26 => 'E7', 53 => 'A13', 80 => 'B4', + 27 => 'F7', 54 => 'E13', 81 => 'A4', +); + # AF point indices for models with 135 focus points, eg. 1J1 (ref PH) # - 9 rows (A-I) with 15 columns (1-15), center is E8 # - odd columns, columns 2 and 14, and the remaining corner points are @@ -931,16 +1123,58 @@ my %afPoints153 = ( 31 => 'B8', 62 => 'H13', 93 => 'C17', 124 => 'G4', ); +# AF point indices for models with 81 focus points, eg. Z6/Z7/Z50 (ref 38) +# - 9 rows (A-I) with 9 columns (1-9), center is E5 +# NOTE: the AF points start 2 bytes into the data, so the map starts +# at 17 instead of 1 +# +# 7 6 5 4 3 2 1 0 +# 00 : [H5][G5][F5][A5][B5][C5][D5][E5] +# 01 : [G6][F6][A6][B6][C6][D6][E6][I5] +# 02 : [F4][A4][B4][C4][D4][E4][I6][H6] +# 03 : [A7][B7][C7][D7][E7][I4][H4][G4] +# 04 : [B3][C3][D3][E3][I7][H7][G7][F7] +# 05 : [C8][D8][E8][I3][H3][G3][F3][A3] +# 06 : [D2][E2][I8][H8][G8][F8][A8][B8] +# 07 : [E9][I2][H2][G2][F2][A2][B2][C2] +# 08 : [I9][H9][G9][F9][A9][B9][C9][D9] +# 09 : [H1][G1][F1][A1][B1][C1][D1][E1] +# 0a : [ ][ ][ ][ ][ ][ ][ ][I1] +my %afPoints81 = ( + 17 => 'E5', 34 => 'I6', 51 => 'H7', 68 => 'G8', 85 => 'F9', + 18 => 'D5', 35 => 'E4', 52 => 'I7', 69 => 'H8', 86 => 'G9', + 19 => 'C5', 36 => 'D4', 53 => 'E3', 70 => 'I8', 87 => 'H9', + 20 => 'B5', 37 => 'C4', 54 => 'D3', 71 => 'E2', 88 => 'I9', + 21 => 'A5', 38 => 'B4', 55 => 'C3', 72 => 'D2', 89 => 'E1', + 22 => 'F5', 39 => 'A4', 56 => 'B3', 73 => 'C2', 90 => 'D1', + 23 => 'G5', 40 => 'F4', 57 => 'A3', 74 => 'B2', 91 => 'C1', + 24 => 'H5', 41 => 'G4', 58 => 'F3', 75 => 'A2', 92 => 'B1', + 25 => 'I5', 42 => 'H4', 59 => 'G3', 76 => 'F2', 93 => 'A1', + 26 => 'E6', 43 => 'I4', 60 => 'H3', 77 => 'G2', 94 => 'F1', + 27 => 'D6', 44 => 'E7', 61 => 'I3', 78 => 'H2', 95 => 'G1', + 28 => 'C6', 45 => 'D7', 62 => 'E8', 79 => 'I2', 96 => 'H1', + 29 => 'B6', 46 => 'C7', 63 => 'D8', 80 => 'E9', 97 => 'I1', + 30 => 'A6', 47 => 'B7', 64 => 'C8', 81 => 'D9', + 31 => 'F6', 48 => 'A7', 65 => 'B8', 82 => 'C9', + 32 => 'G6', 49 => 'F7', 66 => 'A8', 83 => 'B9', + 33 => 'H6', 50 => 'G7', 67 => 'F8', 84 => 'A9', +); + my %cropHiSpeed = ( #IB 0 => 'Off', 1 => '1.3x Crop', # (1.3x Crop, Large) - 2 => 'DX Crop', + 2 => 'DX Crop', # (1.5x) 3 => '5:4 Crop', - 4 => '3:2 Crop', + 4 => '3:2 Crop', # (1.2x, ref 36) 6 => '16:9 Crop', + 8 => '2.7x Crop', #36 (D4/D500) 9 => 'DX Movie Crop', # (DX during movie recording, Large) + 10 => '1.3x Movie Crop', #36 (D4/D500) 11 => 'FX Uncropped', 12 => 'DX Uncropped', + 13 => '2.8x Movie Crop', #28 (D5/D6) 5584/1936 + 14 => '1.4x Movie Crop', #28 (D5/D6) 5584/3856 + 15 => '1.5x Movie Crop', #36 (D4/D500) 5600/3872 17 => '1:1 Crop', OTHER => sub { my ($val, $inv, $conv) = @_; @@ -952,7 +1186,31 @@ my %cropHiSpeed = ( #IB }, ); +my %flashGroupOptionsMode = ( + 0 => 'TTL', + 1 => 'Manual', + 2 => 'Auto', + 3 => 'Off', +); + +my %nefCompression = ( #28 relocated to MakerNotes_0x51 at offset x'0a (Z9) + 1 => 'Lossy (type 1)', # (older models) + 2 => 'Uncompressed', #JD - D100 (even though TIFF compression is set!) + 3 => 'Lossless', + 4 => 'Lossy (type 2)', + 5 => 'Striped packed 12 bits', #IB + 6 => 'Uncompressed (reduced to 12 bit)', #IB + 7 => 'Unpacked 12 bits', #IB (padded to 16) + 8 => 'Small', #IB + 9 => 'Packed 12 bits', #IB (2 pixels in 3 bytes) + 10 => 'Packed 14 bits', #28 (4 pixels in 7 bytes, eg. D6 uncompressed 14 bit) + 13 => 'High Efficiency', #28 + 14 => 'High Efficiency*', #28 +); + +my %noYes = ( 0 => 'No' , 1 => 'Yes', ); my %offOn = ( 0 => 'Off', 1 => 'On' ); +my %onOff = ( 0 => 'On', 1 => 'Off' ); # common attributes for writable BinaryData directories my %binaryDataAttrs = ( @@ -963,6 +1221,30 @@ my %binaryDataAttrs = ( FIRST_ENTRY => 0, ); +my %base64bin = ( ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)' ); +my %base64int32u = ( ValueConv => 'my $val=Image::ExifTool::XMP::DecodeBase64($val); unpack("V",$$val)' ); +my %base64bytes = ( ValueConv => 'my $val=Image::ExifTool::XMP::DecodeBase64($val); join(".",unpack("C*",$$val))' ); +my %base64double = ( + ValueConv => q{ + my $val=Image::ExifTool::XMP::DecodeBase64($val); + my $saveOrder = GetByteOrder(); + SetByteOrder('II'); + $val = GetDouble($val,0); + SetByteOrder($saveOrder); + return $val; + }, +); +my %base64coord = ( + ValueConv => q{ + my $val=Image::ExifTool::XMP::DecodeBase64($val); + my $saveOrder = GetByteOrder(); + SetByteOrder('II'); + $val = GetDouble($val,0) + GetDouble($val,8)/60 + GetDouble($val,16)/3600; + SetByteOrder($saveOrder); + return $val; + }, + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1)', +); # Nikon maker note tags %Image::ExifTool::Nikon::Main = ( PROCESS_PROC => \&Image::ExifTool::Nikon::ProcessNikon, @@ -1002,7 +1284,12 @@ my %binaryDataAttrs = ( 0x0004 => { Name => 'Quality', Writable => 'string' }, 0x0005 => { Name => 'WhiteBalance', Writable => 'string' }, 0x0006 => { Name => 'Sharpness', Writable => 'string' }, - 0x0007 => { Name => 'FocusMode', Writable => 'string' }, + 0x0007 => { + Name => 'FocusMode', + DataMember => 'FocusMode', + Writable => 'string', + RawConv => '$$self{FocusMode} = $val', + }, # FlashSetting (better named FlashSyncMode, ref 28) values: # "Normal", "Slow", "Rear Slow", "RED-EYE", "RED-EYE SLOW" 0x0008 => { Name => 'FlashSetting', Writable => 'string' }, @@ -1225,18 +1512,32 @@ my %binaryDataAttrs = ( }, 0x0023 => [ { #PH (D300, but also found in D3,D3S,D3X,D90,D300S,D700,D3000,D5000) - Condition => '$$valPt =~ /^01/', Name => 'PictureControlData', + Condition => '$$valPt =~ /^01/', Writable => 'undef', Permanent => 0, Flags => [ 'Binary', 'Protected' ], SubDirectory => { TagTable => 'Image::ExifTool::Nikon::PictureControl' }, },{ #28 Name => 'PictureControlData', + Condition => '$$valPt =~ /^02/', Writable => 'undef', Permanent => 0, Flags => [ 'Binary', 'Protected' ], SubDirectory => { TagTable => 'Image::ExifTool::Nikon::PictureControl2' }, + },{ + Name => 'PictureControlData', + Condition => '$$valPt =~ /^03/', + Writable => 'undef', + Permanent => 0, + Flags => [ 'Binary', 'Protected' ], + SubDirectory => { TagTable => 'Image::ExifTool::Nikon::PictureControl3' }, + },{ + Name => 'PictureControlData', + Writable => 'undef', + Permanent => 0, + Flags => [ 'Binary', 'Protected' ], + SubDirectory => { TagTable => 'Image::ExifTool::Nikon::PictureControlUnknown' }, }, ], 0x0024 => { #JD @@ -1284,7 +1585,19 @@ my %binaryDataAttrs = ( ByteOrder => 'BigEndian', #(NC) }, }, - # 0x0034 - Nikon 1 models only, values: 0,16,33 + 0x0034 => { #forum9646 + Name => 'ShutterMode', + Writable => 'int16u', + PrintConv => { + 0 => 'Mechanical', + 16 => 'Electronic', + # 33 => ? seen for 1J2 + 48 => 'Electronic Front Curtain', + 64 => 'Electronic (Movie)', #JanSkoda (Z6II) + 80 => 'Auto (Mechanical)', #JanSkoda (Z6II) + 81 => 'Auto (Electronic Front Curtain)', #JanSkoda (Z6II) + }, + }, 0x0035 => { #32 Name => 'HDRInfo', SubDirectory => { TagTable => 'Image::ExifTool::Nikon::HDRInfo' }, @@ -1303,10 +1616,46 @@ my %binaryDataAttrs = ( Count => 4, # (may need to divide by 4 for some images, eg. D3300/D5300, 12 bit - ref IB) }, + 0x003e => { #28 + Name => 'ImageSizeRAW', + PrintConv => { + 1 => 'Large', + 2 => 'Medium', + 3 => 'Small', + }, + }, + 0x003f => { #https://github.com/darktable-org/darktable/issues/12282 + Name => 'WhiteBalanceFineTune', + Writable => 'rational64s', + Count => 2, + }, + 0x0045 => { #IB + Name => 'CropArea', + Notes => 'left, top, width, height', + Writable => 'int16u', + Count => 4, + }, + 0x004e => { #28 + Name => 'NikonSettings', + Writable => 'undef', + Permanent => 0, + Flags => [ 'Binary', 'Protected' ], + SubDirectory => { TagTable => 'Image::ExifTool::NikonSettings::Main' }, + }, 0x004f => { #IB (D850) Name => 'ColorTemperatureAuto', Writable => 'int16u', }, + 0x0051 => { #28 (Z9) + Name => 'MakerNotes0x51', + Writable => 'undef', + Hidden => 1, + Permanent => 0, + Flags => [ 'Binary', 'Protected' ], + SubDirectory => { TagTable => 'Image::ExifTool::Nikon::MakerNotes0x51' }, + }, + #0x0053 #28 possibly a secondary DistortionControl block (in addition to DistortInfo)? Certainly offset 0x04 within block contains tag AutoDistortionControl for Z72 and D6 (1=>On; 2=> Off) + #0x005e #28 possibly DiffractionCompensation block? Certainly offset 0x04 within block contains tag DiffractionCompensation 0x0080 => { Name => 'ImageAdjustment', Writable => 'string' }, 0x0081 => { Name => 'ToneComp', Writable => 'string' }, #2 0x0082 => { Name => 'AuxiliaryLens', Writable => 'string' }, @@ -1314,25 +1663,36 @@ my %binaryDataAttrs = ( Name => 'LensType', Writable => 'int8u', # credit to Tom Christiansen (ref 7) for figuring this out... + # (note that older models don't seem to set bits 4-7 (0xf0), so the + # LensType may be different with different models, ref Kenneth Cochran) PrintConv => q[$_ = $val ? Image::ExifTool::DecodeBits($val, { 0 => 'MF', 1 => 'D', 2 => 'G', 3 => 'VR', - # bit 4 set for Nikon 1 lenses - PH - # bit 5 set for FT-1 adapter? - PH - # bit 6 set for FL lenses? - PH + 4 => '1', #PH + 5 => 'FT-1', #PH/IB + 6 => 'E', #PH (electromagnetic aperture mechanism) + 7 => 'AF-P', #PH/IB }) : 'AF'; # remove commas and change "D G" to just "G" - s/,//g; s/\bD G\b/G/; $_ + s/,//g; s/\bD G\b/G/; + s/ E\b// and s/^(G )?/E /; # put "E" at the start instead of "G" + s/ 1// and $_ = "1 $_"; # put "1" at start + s/FT-1 // and $_ .= ' FT-1'; # put "FT-1" at end + return $_; ], PrintConvInv => q[ my $bits = 0; - $bits |= 0x01 if $val =~ /\bMF\b/i; - $bits |= 0x02 if $val =~ /\bD\b/i; - $bits |= 0x06 if $val =~ /\bG\b/i; - $bits |= 0x08 if $val =~ /\bVR\b/i; + $bits |= 0x01 if $val =~ /\bMF\b/i; # bit 0 + $bits |= 0x02 if $val =~ /\bD\b/i; # bit 1 + $bits |= 0x06 if $val =~ /\bG\b/i; # bits 1 and 2 + $bits |= 0x08 if $val =~ /\bVR\b/i; # bit 3 + $bits |= 0x10 if $val =~ /\b1\b/; # bit 4 + $bits |= 0x20 if $val =~ /\bFT-1/i; # bit 5 + $bits |= 0x80 if $val =~ /\bAF-P/i; # bit 7 (not used by all models) + $bits |= 0x46 if $val =~ /\bE\b/i; # bits 1, 2 and 6 return $bits; ], }, @@ -1362,6 +1722,7 @@ my %binaryDataAttrs = ( 7 => 'Fired, External', #14 8 => 'Fired, Commander Mode', 9 => 'Fired, TTL Mode', + 18 => 'LED Light', #G.F. (movie LED light) }, }, 0x0088 => [ @@ -1441,7 +1802,7 @@ my %binaryDataAttrs = ( 0x008c => { Name => 'ContrastCurve', #JD Writable => 'undef', - Flags => [ 'Binary', 'Protected' ], + Flags => [ 'Binary', 'Protected', 'Drop' ], # (drop because not found in Nikon JPEG's) }, # ColorHue: MODE1/MODE1a=sRGB, MODE2=Adobe RGB, MODE3a=more saturated sRGB # --> should really be called ColorSpace or ColorMode, but that would conflict with other tags @@ -1596,10 +1957,8 @@ my %binaryDataAttrs = ( SubDirectory => { TagTable => 'Image::ExifTool::Nikon::ShotInfoD850', DecryptStart => 4, - # initially only decrypt enough to extract CustomSettingsOffset - DecryptLen => 0x58, - # then decrypt through to the end of the custom settings - DecryptMore => 'Get32u(\$data, 0x58) + 90 + 4', + DecryptLen => 0x2efb + 12, + DecryptMore => 'Get32u(\$data, 0xa0) + 12', ByteOrder => 'LittleEndian', }, }, @@ -1673,7 +2032,7 @@ my %binaryDataAttrs = ( TagTable => 'Image::ExifTool::Nikon::ShotInfoD500', DecryptStart => 4, DecryptLen => 0x2c24 + 12, - DecryptMore => 'Get32u(\$data, 0xa0) + 12', + DecryptMore => 'Get32u(\$data, 0xa8) + 0x2ea5 - 0x2c90', ByteOrder => 'LittleEndian', }, }, @@ -1684,7 +2043,17 @@ my %binaryDataAttrs = ( TagTable => 'Image::ExifTool::Nikon::ShotInfoD500', DecryptStart => 4, DecryptLen => 0x2cb2 + 4, - DecryptMore => 'Get32u(\$data, 0xa0) + 12', + DecryptMore => 'Get32u(\$data, 0xa8) + 0x2ea5 - 0x2c90', + ByteOrder => 'LittleEndian', + }, + }, + { # (D6 firmware version 1.00, ref 28) + Condition => '$$valPt =~ /^0246/', + Name => 'ShotInfoD6', + SubDirectory => { + TagTable => 'Image::ExifTool::Nikon::ShotInfoD6', + DecryptStart => 4, + DecryptLen => 0xc292 + 720, # thru decoded parts of Offset 32 ByteOrder => 'LittleEndian', }, }, @@ -1698,9 +2067,31 @@ my %binaryDataAttrs = ( ByteOrder => 'BigEndian', }, }, - # 0227 - D7100 - { - Condition => '$$valPt =~ /^02/', + { # (Z6_2 firmware version 1.00 and Z7II firmware versions 1.00 & 1.01, ref 28) + # 0800=Z6/Z7 0801=Z50 0802=Z5 0803=Z6II/Z7II 0804=Zfc + Condition => '$$valPt =~ /^080[01234]/', + Name => 'ShotInfoZ7II', + SubDirectory => { + TagTable => 'Image::ExifTool::Nikon::ShotInfoZ7II', + DecryptStart => 4, + # TODO: eventually set the length dynamically according to actual offsets! + DecryptLen => 0xd04e + 860, # thru decoded MenuSettingsZ7II + ByteOrder => 'LittleEndian', + }, + }, + { # (Z9 firmware version 1.00 ref 28) + Condition => '$$valPt =~ /^0805/', + Name => 'ShotInfoZ9', + SubDirectory => { + TagTable => 'Image::ExifTool::Nikon::ShotInfoZ9', + DecryptStart => 4, + # TODO: eventually set the length dynamically according to actual offsets! + DecryptLen => 0xec4b + 1907, # decoded thru end of Offset26 + ByteOrder => 'LittleEndian', + }, + }, + { # D7100=0227 + Condition => '$$valPt =~ /^0[28]/', Name => 'ShotInfo02xx', SubDirectory => { TagTable => 'Image::ExifTool::Nikon::ShotInfo', @@ -1728,19 +2119,10 @@ my %binaryDataAttrs = ( 0x0093 => { #21 Name => 'NEFCompression', Writable => 'int16u', - PrintConv => { - 1 => 'Lossy (type 1)', # (older models) - 2 => 'Uncompressed', #JD - D100 (even though TIFF compression is set!) - 3 => 'Lossless', - 4 => 'Lossy (type 2)', - 5 => 'Striped packed 12 bits', #IB - 6 => 'Uncompressed (reduced to 12 bit)', #IB - 7 => 'Unpacked 12 bits', #IB (padded to 16) - 8 => 'Small', #IB - 9 => 'Packed 12 bits', #IB (2 pixels in 3 bytes) - }, + SeparateTable => 'NEFCompression', + PrintConv => \%nefCompression, }, - 0x0094 => { Name => 'Saturation', Writable => 'int16s' }, + 0x0094 => { Name => 'SaturationAdj', Writable => 'int16s' }, 0x0095 => { Name => 'NoiseReduction', Writable => 'string' }, # ("Off" or "FPNR"=long exposure NR) 0x0096 => { Name => 'NEFLinearizationTable', # same table as DNG LinearizationTable (ref JD) @@ -1835,7 +2217,7 @@ my %binaryDataAttrs = ( DirOffset => 10, }, }, - { # (D3100=0215,D7000/D5100=0216,D4/D800/D3200=0217) + { # (D3100=0215,D7000/D5100=0216,D4/D600/D800/D800E/D3200=0217) Condition => '$$valPt =~ /^021[567]/', Name => 'ColorBalance0215', SubDirectory => { @@ -1857,9 +2239,9 @@ my %binaryDataAttrs = ( DecryptLen => 10, # (arbitrary) }, }, - { # (1J1/1J2/1V1=0400, 1V2=0401, 1J3/1S1=0402, 1AW1=0403) + { # (1J1/1J2/1V1=0400, 1V2=0401, 1J3/1S1=0402, 1AW1=0403, Z6/Z7=0800) Name => 'ColorBalanceUnknown04', - Condition => '$$valPt =~ /^04/', + Condition => '$$valPt =~ /^0[48]/', SubDirectory => { TagTable => 'Image::ExifTool::Nikon::ColorBalanceUnknown', ProcessProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, @@ -1909,7 +2291,7 @@ my %binaryDataAttrs = ( }, }, { - Condition => '$$valPt =~ /^0400/', # 1J1, 1V1 + Condition => '$$valPt =~ /^040[01]/', # 0=1J1/1V1, 1=1J2 Name => 'LensData0400', SubDirectory => { TagTable => 'Image::ExifTool::Nikon::LensData0400', @@ -1918,10 +2300,44 @@ my %binaryDataAttrs = ( DecryptStart => 4, }, }, - { # (1J1/1V1=0400) + { + Condition => '$$valPt =~ /^0402/', # 1J3/1S1/1V2 + Name => 'LensData0402', + SubDirectory => { + TagTable => 'Image::ExifTool::Nikon::LensData0402', + ProcessProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + WriteProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + DecryptStart => 4, + }, + }, + { + Condition => '$$valPt =~ /^0403/', # 1J4,1J5 + Name => 'LensData0403', + SubDirectory => { + TagTable => 'Image::ExifTool::Nikon::LensData0403', + ProcessProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + WriteProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + DecryptStart => 4, + }, + }, + { + Condition => '$$valPt =~ /^080[012]/', # Z6/Z7/Z9 + Name => 'LensData0800', + SubDirectory => { + TagTable => 'Image::ExifTool::Nikon::LensData0800', + ProcessProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + WriteProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + DecryptStart => 4, + ByteOrder => 'LittleEndian', + }, + }, + { Name => 'LensDataUnknown', SubDirectory => { TagTable => 'Image::ExifTool::Nikon::LensDataUnknown', + ProcessProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + WriteProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + DecryptStart => 4, }, }, ], @@ -1949,6 +2365,17 @@ my %binaryDataAttrs = ( Name => 'SceneAssist', Writable => 'string', }, + 0x009d => { #NealKrawetz + Name => 'DateStampMode', + Writable => 'int16u', + Notes => 'feature to imprint date/time on image', + PrintConv => { #PH + 0 => 'Off', + 1 => 'Date & Time', + 2 => 'Date', + 3 => 'Date Counter', # (NC) (D3500) + }, + }, 0x009e => { #JD Name => 'RetouchHistory', Writable => 'int16u', @@ -2027,6 +2454,11 @@ my %binaryDataAttrs = ( Name => 'FlashInfo0107', # (0107 for D4S/D750/D810/D5500/D7200, 0108 for D5/D500/D3400) Condition => '$$valPt =~ /^010[78]/', SubDirectory => { TagTable => 'Image::ExifTool::Nikon::FlashInfo0107' }, + }, + { + Name => 'FlashInfo0300', # (Z7II) + Condition => '$$valPt =~ /^030[01]/', + SubDirectory => { TagTable => 'Image::ExifTool::Nikon::FlashInfo0300' }, }, { Name => 'FlashInfoUnknown', @@ -2098,11 +2530,15 @@ my %binaryDataAttrs = ( PrintConv => '$self->ConvertDateTime($val)', PrintConvInv => '$self->InverseDateTime($val,0)', }, - 0x00b7 => { #JD + 0x00b7 => [{ + Name => 'AFInfo2', + Condition => '$$self{Model} =~ /^NIKON Z 9\b/i', #AFInfo2Version 0400 + SubDirectory => { TagTable => 'Image::ExifTool::Nikon::AFInfo2V0400' }, + },{ #JD Name => 'AFInfo2', # (this structure may be byte swapped when rewritten by CaptureNX) SubDirectory => { TagTable => 'Image::ExifTool::Nikon::AFInfo2' }, - }, + }], 0x00b8 => [{ #PH Name => 'FileInfo', # unfortunately, some newer models write this as little-endian @@ -2151,6 +2587,10 @@ my %binaryDataAttrs = ( Flags => [ 'Binary', 'Protected' ], SubDirectory => { TagTable => 'Image::ExifTool::Nikon::PictureControl' }, }, + 0x00bf => { + Name => 'SilentPhotography', + PrintConv => \%offOn, + }, 0x00c3 => { Name => 'BarometerInfo', SubDirectory => { @@ -2189,11 +2629,14 @@ my %binaryDataAttrs = ( 0x0e09 => { #12 Name => 'NikonCaptureVersion', Writable => 'string', - PrintConv => undef, + Permanent => 0, + PrintConv => undef, # (avoid applying default print conversion to string) }, # 0x0e0e is in D70 Nikon Capture files (not out-of-the-camera D70 files) - PH 0x0e0e => { #PH Name => 'NikonCaptureOffsets', + Writable => 'undef', + Permanent => 0, SubDirectory => { TagTable => 'Image::ExifTool::Nikon::CaptureOffsets', Validate => '$val =~ /^0100/', @@ -2209,11 +2652,11 @@ my %binaryDataAttrs = ( Start => '$val', }, }, - 0x0e13 => [{ # PH/http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,2737.0.html + 0x0e13 => [{ # PH/https://exiftool.org/forum/index.php/topic,2737.0.html Name => 'NikonCaptureEditVersions', Condition => '$self->Options("ExtractEmbedded")', Notes => q{ - the ExtractEmbedded option may be used to decode settings from the stored + the L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> option may be used to decode settings from the stored edit versions, otherwise this is extracted as a binary data block }, Writable => 'undef', @@ -2356,14 +2799,23 @@ my %binaryDataAttrs = ( }, }, # 5 - values: 0, 1 (VR On), 2 (VR Off) - 6 => { + 6 => [{ + Name => 'VRMode', + PrintConv => { + 0 => 'Off', + 1 => 'Sport', + 3 => 'Normal', + }, + %infoZSeries + },{ Name => 'VRMode', PrintConv => { 0 => 'Normal', - # 1 - seen this for 1V1 - PH + 1 => 'On (1)', #PH (NC) 2 => 'Active', # (1J1) + 3 => 'Sport', #PH (Z7) }, - }, + }], # 7 - values: 0, 1 ); @@ -2640,23 +3092,6 @@ my %binaryDataAttrs = ( PrintConv => 'Image::ExifTool::Nikon::PrintPC($val)', PrintConvInv => 'Image::ExifTool::Nikon::PrintPCInv($val)', }, - 48 => { #21 - Name => 'PictureControlAdjust', - PrintConv => { - 0 => 'Default Settings', - 1 => 'Quick Adjust', - 2 => 'Full Control', - }, - }, - 49 => { - Name => 'PictureControlQuickAdjust', - # settings: -2 to +2 (n/a for Neutral and Monochrome modes) - DelValue => 0xff, - ValueConv => '$val - 0x80', - ValueConvInv => '$val + 0x80', - PrintConv => 'Image::ExifTool::Nikon::PrintPC($val)', - PrintConvInv => 'Image::ExifTool::Nikon::PrintPCInv($val)', - }, 51 => { Name => 'Sharpness', DelValue => 0xff, @@ -2719,7 +3154,7 @@ my %binaryDataAttrs = ( 0xff => 'n/a', }, }, - 64 => { + 64 => { Name => 'ToningEffect', # settings: B&W,Sepia,Cyanotype,Red,Yellow,Green,Blue-Green,Blue, # Purple-Blue,Red-Purple (n/a for color modes) @@ -2751,76 +3186,226 @@ my %binaryDataAttrs = ( }, ); -# World Time information - JD (D300) -%Image::ExifTool::Nikon::WorldTime = ( +# Picture Control information V3 (ref PH, Z7) +%Image::ExifTool::Nikon::PictureControl3 = ( %binaryDataAttrs, - GROUPS => { 0 => 'MakerNotes', 2 => 'Time' }, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + # NOTE: Must set ByteOrder in SubDirectory if any multi-byte integer tags added 0 => { - Name => 'TimeZone', - Format => 'int16s', - PrintConv => q{ - my $sign = $val < 0 ? '-' : '+'; - my $h = int(abs($val) / 60); - sprintf("%s%.2d:%.2d", $sign, $h, abs($val)-60*$h); - }, - PrintConvInv => q{ - $val =~ /([-+]?)(\d+):(\d+)/ or return undef; - return $1 . ($2 * 60 + $3); - }, + Name => 'PictureControlVersion', + Format => 'undef[4]', + Writable => 0, }, - 2 => { - Name => 'DaylightSavings', - PrintConv => { 0 => 'No', 1 => 'Yes' }, + 8 => { + Name => 'PictureControlName', + Format => 'string[20]', + # make lower case with a leading capital for each word + PrintConv => \&FormatString, + PrintConvInv => 'uc($val)', }, - 3 => { - Name => 'DateDisplayFormat', + # 48 - looks like PictureControl2 byte 45 + 28 => { + Name => 'PictureControlBase', + Format => 'string[20]', + PrintConv => \&FormatString, + PrintConvInv => 'uc($val)', + }, + 54 => { # (NC) + Name => 'PictureControlAdjust', PrintConv => { - 0 => 'Y/M/D', - 1 => 'M/D/Y', - 2 => 'D/M/Y', + 0 => 'Default Settings', + 1 => 'Quick Adjust', + 2 => 'Full Control', }, }, -); - -# ISO information - PH (D300) -%Image::ExifTool::Nikon::ISOInfo = ( - %binaryDataAttrs, - GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, - 0 => { - Name => 'ISO', - Notes => 'val = 100 * 2**(raw/12-5)', - Priority => 0, # because people like to see rounded-off values if they exist - ValueConv => '100*exp(($val/12-5)*log(2))', - ValueConvInv => '(log($val/100)/log(2)+5)*12', - PrintConv => 'int($val + 0.5)', - PrintConvInv => '$val', + 55 => { # (NC) + Name => 'PictureControlQuickAdjust', + DelValue => 0xff, + ValueConv => '$val - 0x80', + ValueConvInv => '$val + 0x80', + PrintConv => 'Image::ExifTool::Nikon::PrintPC($val)', + PrintConvInv => 'Image::ExifTool::Nikon::PrintPCInv($val)', }, - # 1 - 0x01 - # 2 - 0x0c (probably the ISO divisor above) - # 3 - 0x00 - 4 => { - Name => 'ISOExpansion', - Format => 'int16u', - PrintHex => 1, - PrintConvColumns => 2, - PrintConv => { - 0x000 => 'Off', - 0x101 => 'Hi 0.3', - 0x102 => 'Hi 0.5', - 0x103 => 'Hi 0.7', - 0x104 => 'Hi 1.0', - 0x105 => 'Hi 1.3', # (Hi 1.3-1.7 may be possible with future models) - 0x106 => 'Hi 1.5', - 0x107 => 'Hi 1.7', - 0x108 => 'Hi 2.0', #(NC) - D3 should have this mode - 0x109 => 'Hi 2.3', #IB - 0x10a => 'Hi 2.5', #IB - 0x10b => 'Hi 2.7', #IB - 0x10c => 'Hi 3.0', #IB - 0x10d => 'Hi 3.3', #IB - 0x10e => 'Hi 3.5', #IB - 0x10f => 'Hi 3.7', #IB - 0x110 => 'Hi 4.0', #IB + 57 => { + Name => 'Sharpness', + DelValue => 0xff, + ValueConv => '$val - 0x80', + ValueConvInv => '$val + 0x80', + PrintConv => 'Image::ExifTool::Nikon::PrintPC($val,"None","%.2f",4)', + PrintConvInv => 'Image::ExifTool::Nikon::PrintPCInv($val,4)', + }, + 59 => { + Name => 'MidRangeSharpness', + DelValue => 0xff, + ValueConv => '$val - 0x80', + ValueConvInv => '$val + 0x80', + PrintConv => 'Image::ExifTool::Nikon::PrintPC($val,"None","%.2f",4)', + PrintConvInv => 'Image::ExifTool::Nikon::PrintPCInv($val,4)', + }, + 61 => { + Name => 'Clarity', + DelValue => 0xff, + ValueConv => '$val - 0x80', + ValueConvInv => '$val + 0x80', + PrintConv => 'Image::ExifTool::Nikon::PrintPC($val,"None","%.2f",4)', + PrintConvInv => 'Image::ExifTool::Nikon::PrintPCInv2($val,4)', + }, + 63 => { + Name => 'Contrast', + DelValue => 0xff, + ValueConv => '$val - 0x80', + ValueConvInv => '$val + 0x80', + PrintConv => 'Image::ExifTool::Nikon::PrintPC($val,"None","%.2f",4)', + PrintConvInv => 'Image::ExifTool::Nikon::PrintPCInv($val,4)', + }, + 65 => { #21 + Name => 'Brightness', + ValueConv => '$val - 0x80', + ValueConvInv => '$val + 0x80', + PrintConv => 'Image::ExifTool::Nikon::PrintPC($val,undef,"%.2f",4)', + PrintConvInv => 'Image::ExifTool::Nikon::PrintPCInv($val,4)', + }, + 67 => { + Name => 'Saturation', + DelValue => 0xff, + ValueConv => '$val - 0x80', + ValueConvInv => '$val + 0x80', + PrintConv => 'Image::ExifTool::Nikon::PrintPC($val,"None","%.2f",4)', + PrintConvInv => 'Image::ExifTool::Nikon::PrintPCInv($val,4)', + }, + 69 => { + Name => 'Hue', + DelValue => 0xff, + ValueConv => '$val - 0x80', + ValueConvInv => '$val + 0x80', + PrintConv => 'Image::ExifTool::Nikon::PrintPC($val,"None","%.2f",4)', + PrintConvInv => 'Image::ExifTool::Nikon::PrintPCInv($val)', + }, + 71 => { # (NC) + Name => 'FilterEffect', + DelValue => 0xff, + PrintHex => 1, + PrintConv => { + 0x80 => 'Off', + 0x81 => 'Yellow', + 0x82 => 'Orange', + 0x83 => 'Red', + 0x84 => 'Green', + 0xff => 'n/a', + }, + }, + 72 => { # (NC) + Name => 'ToningEffect', + DelValue => 0xff, + PrintHex => 1, + PrintConvColumns => 2, + PrintConv => { + 0x80 => 'B&W', + 0x81 => 'Sepia', + 0x82 => 'Cyanotype', + 0x83 => 'Red', + 0x84 => 'Yellow', + 0x85 => 'Green', + 0x86 => 'Blue-green', + 0x87 => 'Blue', + 0x88 => 'Purple-blue', + 0x89 => 'Red-purple', + 0xff => 'n/a', + }, + }, + 73 => { # (NC) + Name => 'ToningSaturation', + DelValue => 0xff, + ValueConv => '$val - 0x80', + ValueConvInv => '$val + 0x80', + PrintConv => 'Image::ExifTool::Nikon::PrintPC($val,"None","%.2f",4)', + PrintConvInv => 'Image::ExifTool::Nikon::PrintPCInv($val,4)', + + }, +); + +# Unknown Picture Control information +%Image::ExifTool::Nikon::PictureControlUnknown = ( + %binaryDataAttrs, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + # NOTE: Must set ByteOrder in SubDirectory if any multi-byte integer tags added + 0 => { + Name => 'PictureControlVersion', + Format => 'undef[4]', + Writable => 0, + }, +); + +# World Time information - JD (D300) +%Image::ExifTool::Nikon::WorldTime = ( + %binaryDataAttrs, + GROUPS => { 0 => 'MakerNotes', 2 => 'Time' }, + 0 => { + Name => 'TimeZone', + Format => 'int16s', + PrintConv => q{ + my $sign = $val < 0 ? '-' : '+'; + my $h = int(abs($val) / 60); + sprintf("%s%.2d:%.2d", $sign, $h, abs($val)-60*$h); + }, + PrintConvInv => q{ + $val =~ /([-+]?)(\d+):(\d+)/ or return undef; + return $1 . ($2 * 60 + $3); + }, + }, + 2 => { + Name => 'DaylightSavings', + PrintConv => { 0 => 'No', 1 => 'Yes' }, + }, + 3 => { + Name => 'DateDisplayFormat', + PrintConv => { + 0 => 'Y/M/D', + 1 => 'M/D/Y', + 2 => 'D/M/Y', + }, + }, +); + +# ISO information - PH (D300) +%Image::ExifTool::Nikon::ISOInfo = ( + %binaryDataAttrs, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + 0 => { + Name => 'ISO', + Notes => 'val = 100 * 2**(raw/12-5)', + Priority => 0, # because people like to see rounded-off values if they exist + ValueConv => '100*exp(($val/12-5)*log(2))', + ValueConvInv => '(log($val/100)/log(2)+5)*12', + PrintConv => 'int($val + 0.5)', + PrintConvInv => '$val', + }, + # 1 - 0x01 + # 2 - 0x0c (probably the ISO divisor above) + # 3 - 0x00 + 4 => { + Name => 'ISOExpansion', + Format => 'int16u', + PrintHex => 1, + PrintConvColumns => 2, + PrintConv => { + 0x000 => 'Off', + 0x101 => 'Hi 0.3', + 0x102 => 'Hi 0.5', + 0x103 => 'Hi 0.7', + 0x104 => 'Hi 1.0', + 0x105 => 'Hi 1.3', # (Hi 1.3-1.7 may be possible with future models) + 0x106 => 'Hi 1.5', + 0x107 => 'Hi 1.7', + 0x108 => 'Hi 2.0', #(NC) - D3 should have this mode + 0x109 => 'Hi 2.3', #IB + 0x10a => 'Hi 2.5', #IB + 0x10b => 'Hi 2.7', #IB + 0x10c => 'Hi 3.0', #IB + 0x10d => 'Hi 3.3', #IB + 0x10e => 'Hi 3.5', #IB + 0x10f => 'Hi 3.7', #IB + 0x110 => 'Hi 4.0', #IB 0x111 => 'Hi 4.3', #IB 0x112 => 'Hi 4.5', #IB 0x113 => 'Hi 4.7', #IB @@ -2992,7 +3577,10 @@ my %binaryDataAttrs = ( 4 => { #PH Name => 'ContrastDetectAF', RawConv => '$$self{ContrastDetectAF} = $val', - PrintConv => \%offOn, + PrintConv => { + %offOn, + 2 => 'On (2)', #PH (Z7) + }, Notes => 'this is Off for the hybrid AF used in Nikon 1 models', }, 5 => [ @@ -3019,12 +3607,18 @@ my %binaryDataAttrs = ( 15 => 'Dynamic Area (72 points)', #PH 16 => 'Group Area (HL)', #28 17 => 'Group Area (VL)', #28 + 18 => 'Dynamic Area (49 points)', #28 128 => 'Single', #PH (1J1,1J2,1J3,1J4,1S1,1S2,1V2,1V3) 129 => 'Auto (41 points)', #PH (1J1,1J2,1J3,1J4,1S1,1S2,1V1,1V2,1V3,AW1) 130 => 'Subject Tracking (41 points)', #PH (1J1,1J4,1J3) 131 => 'Face Priority (41 points)', #PH (1J1,1J3,1S1,1V2,AW1) # 134 - seen for 1V1[PhaseDetectAF=0] (PH) # 135 - seen for 1J2[PhaseDetectAF=4] (PH) + 192 => 'Pinpoint', #PH (NC) + 193 => 'Single', #PH (NC) + 195 => 'Wide (S)', #PH (NC) + 196 => 'Wide (L)', #PH (NC) + 197 => 'Auto', #PH (NC) }, }, { #PH (D3/D90/D5000) @@ -3043,6 +3637,22 @@ my %binaryDataAttrs = ( 129 => 'Auto (41 points)', #PH (NC) 130 => 'Subject Tracking (41 points)', #PH (NC) 131 => 'Face Priority (41 points)', #PH (NC) + 192 => 'Pinpoint', #PH (Z7) + 193 => 'Single', #PH (Z7) + 194 => 'Dynamic', #PH (Z7) + 195 => 'Wide (S)', #PH (Z7) + 196 => 'Wide (L)', #PH (Z7) + 197 => 'Auto', #PH (Z7) + 198 => 'Auto (People)', #28 (Z7) #if no faces are detected, will record as 'Auto'. Camera setting recorded in AFAreaMode field in the MakerNotes area + 199 => 'Auto (Animal)', #28 (Z7) #if no animals are detected, will record as 'Auto'. Camera setting recorded in AFAreaMode field in the MakerNotes area + 200 => 'Normal-area AF', #28 (D6) + 201 => 'Wide-area AF', #28 (D6) + 202 => 'Face-priority AF', #28 (D6) + 203 => 'Subject-tracking AF', #28 (D6) + 204 => 'Dynamic Area (S)', #28 (Z9) + 205 => 'Dynamic Area (M)', #28 (Z9) + 206 => 'Dynamic Area (L)', #28 (Z9) + 207 => '3D-tracking', #28 (Z9) }, }, ], @@ -3060,12 +3670,15 @@ my %binaryDataAttrs = ( 5 => 'On (5)', #PH (1S2[128/129], 1J4/1V3[129]) 6 => 'On (105-point)', #PH (1J4/1V3[128/130]) 7 => 'On (153-point)', #PH (D5/D500/D850) + 8 => 'On (81-point)', #38 + 9 => 'On (105-point)', #28 (D6) }, }, 7 => [ { #PH/JD Name => 'PrimaryAFPoint', - Condition => '$$self{PhaseDetectAF} < 2', + # PrimaryAFPoint may only be valid for PhaseDetect - certainly true on the D6, possibly other bodies? (ref 28) + Condition => '$$self{PhaseDetectAF} < 2 and $$self{AFInfo2Version} ne "0301"', Notes => q{ models with 51-point AF -- 5 rows (A-E) and 11 columns (1-11): D3, D3S, D3X, D4, D4S, D300, D300S, D700, D800, D800e and D810 @@ -3171,6 +3784,22 @@ my %binaryDataAttrs = ( 1 => 'E9 (Center)', }, }, + { #PH (Z7) (NC) + Name => 'PrimaryAFPoint', + Condition => '$$self{PhaseDetectAF} == 8 and $$self{AFInfo2Version} =~ /^03/', + Notes => q{ + Nikon models with 493-point AF -- 17 rows (A-Q) and 29 columns (1-29), I15 + at the center + }, + PrintConv => { + 0 => '(none)', + 246 => 'I15 (Center)', + OTHER => sub { + my ($val, $inv) = @_; + return GetAFPointGrid($val, 29, $inv); + }, + }, + }, { Name => 'PrimaryAFPoint', Condition => '$$self{AFInfo2Version} eq "0100"', @@ -3184,7 +3813,7 @@ my %binaryDataAttrs = ( 8 => [ { #JD/PH Name => 'AFPointsUsed', - Condition => '$$self{PhaseDetectAF} < 2', + Condition => '$$self{PhaseDetectAF} < 2 and $$self{AFInfo2Version} ne "0301"', Notes => q{ models with 51-point AF -- 5 rows: A1-9, B1-11, C1-11, D1-11, E1-9. Center point is C6 @@ -3253,7 +3882,7 @@ my %binaryDataAttrs = ( Name => 'AFPointsUsed', Condition => '$$self{PhaseDetectAF} == 5', Notes => q{ - newer models with 135-point AF -- 9 rows (B-J) and 15 colums (1-15). Center + newer models with 135-point AF -- 9 rows (B-J) and 15 columns (1-15). Center point is F8 }, Format => 'undef[21]', @@ -3288,8 +3917,23 @@ my %binaryDataAttrs = ( PrintConv => sub { PrintAFPoints(shift, \%afPoints153); }, PrintConvInv => sub { PrintAFPointsInv(shift, \%afPoints153); }, }, - { + { #38 (Z6/Z7/Z50) Name => 'AFPointsUsed', + Condition => '$$self{PhaseDetectAF} == 8 and $$self{Model} =~ /^NIKON Z/', + Notes => q{ + models with 81-selectable point AF -- 9 rows (A-I) and 9 columns (1-9) for + phase detect AF points. Center point is E5 + }, + Format => 'undef[13]', + ValueConv => 'join(" ", unpack("H2"x13, $val))', + ValueConvInv => '$val=~tr/ //d; pack("H*",$val)', + PrintConv => sub { PrintAFPoints(shift, \%afPoints81); }, + PrintConvInv => sub { PrintAFPointsInv(shift, \%afPoints81); }, + }, + { #PH + Name => 'AFPointsUsed', + # version 301 uses a separate field at offset 0x0a for this tag (ref 28) + Condition => '$$self{AFInfo2Version} ne "0301"', Format => 'undef[7]', ValueConv => 'join(" ", unpack("H2"x7, $val))', ValueConvInv => '$val=~tr/ //d; pack("H*",$val)', @@ -3297,6 +3941,19 @@ my %binaryDataAttrs = ( PrintConvInv => '$val=~s/Unknown \\((.*)\\)/$1/; $val', }, ], + 0x0a => { #28 (D6) in any of the 3 Group modes on the D6, the points specify the outer boundaries of the focus point area; otherwise the tag value is consistent with other Nikon bodies + Name => 'AFPointsUsed', + Condition => '$$self{AFInfo2Version} eq "0301" and $$self{PhaseDetectAF} == 9', + Notes => q{ + models with 105-point AF -- 7 rows (A-G) and 15 columns (1-15). Center + point is D8 + }, + Format => 'undef[14]', + ValueConv => 'join(" ", unpack("H2"x14, $val))', + ValueConvInv => '$val=~tr/ //d; pack("H*",$val)', + PrintConv => sub { PrintAFPoints(shift, \%afPoints105); }, + PrintConvInv => sub { PrintAFPointsInv(shift, \%afPoints105); }, + }, 0x10 => { #PH (D90 and D5000) Name => 'AFImageWidth', Condition => '$$self{AFInfo2Version} eq "0100"', @@ -3339,60 +3996,171 @@ my %binaryDataAttrs = ( Format => 'int16u', RawConv => '$val ? $val : undef', }, - 0x1c => { #PH - Name => 'ContrastDetectAFInFocus', - Condition => '$$self{AFInfo2Version} eq "0100"', - PrintConv => { 0 => 'No', 1 => 'Yes' }, - }, - # 0x1d - always zero (with or without live view) - 0x44 => [ - { - Name => 'PrimaryAFPoint', - Condition => '$$self{PhaseDetectAF} == 7 and $$self{AFInfo2Version} eq "0101"', - PrintConvColumns => 5, - PrintConv => { - 0 => '(none)', - %afPoints153, - 1 => 'E9 (Center)', - }, - }, - { - Name => 'PrimaryAFPoint', - Condition => '$$self{AFInfo2Version} eq "0101"', - Notes => 'future models?...', - PrintConv => { - 0 => '(none)', - 1 => 'Center', - }, + 0x1c => [ + { #PH + Name => 'ContrastDetectAFInFocus', + Condition => '$$self{AFInfo2Version} eq "0100"', + PrintConv => { 0 => 'No', 1 => 'Yes' }, + },{ #PH (D500, see forum11190) + Name => 'AFPointsSelected', + Condition => '$$self{AFInfo2Version} eq "0101" and $$self{PhaseDetectAF} == 7', + Format => 'undef[20]', + ValueConv => 'join(" ", unpack("H2"x20, $val))', + ValueConvInv => '$val=~tr/ //d; pack("H*",$val)', + PrintConv => sub { PrintAFPoints(shift, \%afPoints153); }, + PrintConvInv => sub { PrintAFPointsInv(shift, \%afPoints153); }, }, ], - 0x46 => { + # 0x1d - always zero (with or without live view) + 0x2a => { #PH (Z7) Name => 'AFImageWidth', - Condition => '$$self{ContrastDetectAF} == 1 and $$self{AFInfo2Version} eq "0101"', + Condition => '$$self{AFInfo2Version} =~ /^03/', Format => 'int16u', RawConv => '$val ? $val : undef', - Notes => 'this and the following tags are valid only for contrast-detect AF', }, - 0x48 => { + 0x2c => { #PH (Z7) Name => 'AFImageHeight', - Condition => '$$self{ContrastDetectAF} == 1 and $$self{AFInfo2Version} eq "0101"', + Condition => '$$self{AFInfo2Version} =~ /^03/', Format => 'int16u', RawConv => '$val ? $val : undef', }, - 0x4a => { + 0x2e => { #PH (Z7) Name => 'AFAreaXPosition', - Condition => '$$self{ContrastDetectAF} == 1 and $$self{AFInfo2Version} eq "0101"', - Notes => 'center of AF area in AFImage coordinates', + Condition => q{ + $$self{ContrastDetectAF} == 2 and $$self{AFInfo2Version} =~ /^03/ or + $$self{ContrastDetectAF} == 1 and $$self{AFInfo2Version} =~ /^0301/ + }, Format => 'int16u', - RawConv => '$val ? $val : undef', }, - 0x4c => { - Name => 'AFAreaYPosition', - Condition => '$$self{ContrastDetectAF} == 1 and $$self{AFInfo2Version} eq "0101"', + 0x2f => { #28 (Z7) Still photography range 1-17 for the 493 point Z7 (arranged in a 29x17 grid. Center at x=16, y=10). + Name => 'AFFocusPointXPosition', + Condition => q{ + $$self{ContrastDetectAF} == 2 and $$self{AFInfo2Version} =~ /^03/ or + $$self{ContrastDetectAF} == 1 and $$self{AFInfo2Version} =~ /^0301/ + }, + PrintConv => sub { my ($val) = @_; PrintAFPointsLeftRight($val, 29 ); }, + }, + 0x30 => [ + { #PH (Z7) + Name => 'AFAreaYPosition', + Condition => q{ + $$self{ContrastDetectAF} == 2 and $$self{AFInfo2Version} =~ /^03/ or + $$self{ContrastDetectAF} == 1 and $$self{AFInfo2Version} =~ /^0301/ + }, + Format => 'int16u', + },{ #PH (D500, see forum11190) + Name => 'AFPointsInFocus', + Condition => '$$self{AFInfo2Version} eq "0101" and $$self{PhaseDetectAF} == 7', + Notes => 'AF points in focus at the time time image was captured', + Format => 'undef[20]', + ValueConv => 'join(" ", unpack("H2"x20, $val))', + ValueConvInv => '$val=~tr/ //d; pack("H*",$val)', + PrintConv => sub { PrintAFPoints(shift, \%afPoints153); }, + PrintConvInv => sub { PrintAFPointsInv(shift, \%afPoints153); }, + }, + ], + 0x31 => { #28 (Z7) + Name => 'AFFocusPointYPosition', + Condition => q{ + $$self{ContrastDetectAF} == 2 and $$self{AFInfo2Version} =~ /^03/ or + $$self{ContrastDetectAF} == 1 and $$self{AFInfo2Version} =~ /^0301/ + }, + PrintConv => sub { my ($val) = @_; PrintAFPointsUpDown($val, 17 ); }, + }, + 0x32 => { #PH (Z7) + Name => 'AFAreaWidth', + Condition => '$$self{AFInfo2Version} =~ /^03/', Format => 'int16u', RawConv => '$val ? $val : undef', }, - 0x4e => { + 0x34 => { #PH (Z7) + Name => 'AFAreaHeight', + Condition => '$$self{AFInfo2Version} =~ /^03/', + Format => 'int16u', + RawConv => '$val ? $val : undef', + }, + 0x38 => { #28 + Name => 'PrimaryAFPoint', + Condition => '$$self{PhaseDetectAF} == 9 and $$self{AFInfo2Version} =~ /^03/', + Notes => q{ + Nikon models with 105-point AF -- 7 rows (A-G) and 15 columns (1-15): D6 + }, + PrintConvColumns => 5, + PrintConv => { + 0 => '(none)', + %afPoints105, + 1 => 'D8 (Center)', + }, + }, + 0x44 => [ + { + Name => 'PrimaryAFPoint', + Condition => '$$self{PhaseDetectAF} == 7 and $$self{AFInfo2Version} eq "0101"', + PrintConvColumns => 5, + PrintConv => { + 0 => '(none)', + %afPoints153, + 1 => 'E9 (Center)', + }, + }, + { #PH + Name => 'PrimaryAFPoint', + Notes => 'D3500', + Condition => '$$self{PhaseDetectAF} == 2 and $$self{AFInfo2Version} eq "0101"', + PrintConvColumns => 2, + PrintConv => { + 0 => '(none)', + 1 => 'Center', + 2 => 'Top', + 3 => 'Bottom', + 4 => 'Mid-left', + 5 => 'Upper-left', + 6 => 'Lower-left', + 7 => 'Far Left', + 8 => 'Mid-right', + 9 => 'Upper-right', + 10 => 'Lower-right', + 11 => 'Far Right', + }, + }, + { + Name => 'PrimaryAFPoint', + Condition => '$$self{AFInfo2Version} eq "0101"', + Notes => 'future models?...', + Priority => 0, + PrintConv => { + 0 => '(none)', + 1 => 'Center', + }, + }, + ], + 0x46 => { + Name => 'AFImageWidth', + Condition => '$$self{ContrastDetectAF} == 1 and $$self{AFInfo2Version} eq "0101"', + Format => 'int16u', + RawConv => '$val ? $val : undef', + Notes => 'this and the following tags are valid only for contrast-detect AF', + }, + 0x48 => { + Name => 'AFImageHeight', + Condition => '$$self{ContrastDetectAF} == 1 and $$self{AFInfo2Version} eq "0101"', + Format => 'int16u', + RawConv => '$val ? $val : undef', + }, + 0x4a => { + Name => 'AFAreaXPosition', + Condition => '$$self{ContrastDetectAF} == 1 and $$self{AFInfo2Version} eq "0101"', + Notes => 'center of AF area in AFImage coordinates', + Format => 'int16u', + RawConv => '$val ? $val : undef', + }, + 0x4c => { + Name => 'AFAreaYPosition', + Condition => '$$self{ContrastDetectAF} == 1 and $$self{AFInfo2Version} eq "0101"', + Format => 'int16u', + RawConv => '$val ? $val : undef', + }, + 0x4e => { Name => 'AFAreaWidth', Condition => '$$self{ContrastDetectAF} == 1 and $$self{AFInfo2Version} eq "0101"', Format => 'int16u', @@ -3412,6 +4180,55 @@ my %binaryDataAttrs = ( }, ); +%Image::ExifTool::Nikon::AFInfo2V0400 = ( #V0400 related fields begin at x'3c' ( Z9) + %binaryDataAttrs, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + DATAMEMBER => [ 0 ], + 0 => { + Name => 'AFInfo2Version', + Format => 'undef[4]', + Writable => 0, + RawConv => '$$self{AFInfo2Version} = $val', + }, + 0x3e => { + Name => 'AFImageWidth', + Format => 'int16u', + }, + 0x40 => { + Name => 'AFImageHeight', + Format => 'int16u', + }, + 0x43 => { + Name => 'FocusPositionHorizontal', + Notes => q{ + the focus points form a 29x17 grid, but the X,Y coordinate values run from 1,1 + to 30,19. The horizontal coordinate 11R (5) and the vertical coordinates 6U + (4) and 2D (12) are not used for some reason + }, + # 493 focus points for Z9 fall in a 30x19 grid + # (the 11R (5) position is not used, for a total of 29 columns, ref AlbertShan email) + PrintConv => sub { my ($val) = @_; PrintAFPointsLeftRight($val, 29); }, + }, + 0x45 => { + Name => 'FocusPositionVertical', + # (the 6U (4) and 2D (12) are not used, for a total of 17 rows, ref AlbertShan email) + PrintConv => sub { my ($val) = @_; PrintAFPointsUpDown($val, 17); }, + }, + 0x46 => { + Name => 'AFAreaWidth', + Format => 'int16u', + Notes => 'size of AF area in AFImage pixels', + RawConv => '$val ? $val : undef', + }, + 0x48 => { + Name => 'AFAreaHeight', + Format => 'int16u', + RawConv => '$val ? $val : undef', + } + # AFFocusResult is the result of the last AF operation and not necessarily an indication of the state of the of the capture (e.g., the subject may have moved or the image re-framed) + #0x4a => { Name => 'AFFocusResult',PrintConv => {0=> "No Focus", 1=>"Focus"} }, #new tag created because Z9 uses a hybrid contrast/phase AF (closest former tag was ContrastDetectAFInFocus). +); + # Nikon AF fine-tune information (ref 28) %Image::ExifTool::Nikon::AFTune = ( %binaryDataAttrs, @@ -3423,6 +4240,7 @@ my %binaryDataAttrs = ( # (don't know what the difference between 1 and 2 is) 1 => 'On (1)', 2 => 'On (2)', + 3 => 'On (Zoom)', #28 }, }, 1 => { @@ -3432,6 +4250,7 @@ my %binaryDataAttrs = ( PrintConvInv => '$val eq "n/a" ? 255 : $val', }, 2 => { + # when AFFineTune = 3 (indicating a zoom lens), this Tag stores the tuning adjustment for the wide end of the zoom range (ref 28) Name => 'AFFineTuneAdj', Priority => 0, # so other value takes priority if it exists Notes => 'may only be valid for saved lenses', @@ -3439,6 +4258,14 @@ my %binaryDataAttrs = ( PrintConv => '$val > 0 ? "+$val" : $val', PrintConvInv => '$val', }, + 3 => { + Name => 'AFFineTuneAdjTele', + # should probably insert a Condition that restricts this to AFFineTune = 3 (ref 28) + Notes => 'only valid for zoom lenses (ie, AFTune=3)', + Format => 'int8s', + PrintConv => '$val > 0 ? "+$val" : $val', + PrintConvInv => '$val', + }, ); # Nikon NEF processing information (ref forum6281) @@ -3509,6 +4336,8 @@ my %binaryDataAttrs = ( %Image::ExifTool::Nikon::CaptureOffsets = ( PROCESS_PROC => \&ProcessNikonCaptureOffsets, GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + # (note that these are duplicates of offsets in the normal TIFF structure, + # and that these offsets are not updated when ExifTool rewrites the file) 1 => 'IFD0_Offset', 2 => 'PreviewIFD_Offset', 3 => 'SubIFD_Offset', @@ -3994,7 +4823,7 @@ my %nikonFocalConversions = ( %Image::ExifTool::Nikon::LensData0400 = ( %binaryDataAttrs, GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, - NOTES => 'Tags extracted from the encrypted lens data of Nikon 1 models.', + NOTES => 'Tags extracted from the encrypted lens data of the Nikon 1J1/1V1/1J2.', 0x00 => { Name => 'LensDataVersion', Format => 'string[4]', @@ -4006,6 +4835,244 @@ my %nikonFocalConversions = ( }, ); +# Nikon lens data version 0402 (note: needs decrypting) (ref PH) +%Image::ExifTool::Nikon::LensData0402 = ( + %binaryDataAttrs, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + NOTES => 'Tags extracted from the encrypted lens data of the Nikon 1J3/1S1/1V2.', + 0x00 => { + Name => 'LensDataVersion', + Format => 'string[4]', + Writable => 0, + }, + 0x18b => { #PH + Name => 'LensModel', + Format => 'string[64]', + }, +); + +# Nikon lens data version 0403 (note: needs decrypting) (ref PH) +%Image::ExifTool::Nikon::LensData0403 = ( + %binaryDataAttrs, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + NOTES => 'Tags extracted from the encrypted lens data of the Nikon 1J4/1J5.', + 0x00 => { + Name => 'LensDataVersion', + Format => 'string[4]', + Writable => 0, + }, + 0x2ac => { #PH + Name => 'LensModel', + Format => 'string[64]', + }, +); + +# Nikon Z lens data (note: needs decrypting) (ref PH, based on LensData0204) +%Image::ExifTool::Nikon::LensData0800 = ( + %binaryDataAttrs, + NOTES => 'Tags found in the encrypted LensData from cameras such as the Z6 and Z7.', + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + DATAMEMBER => [ 0x03, 0x2f, 0x35, 0x4c, 0x56 ], + 0x00 => { + Name => 'LensDataVersion', + Format => 'string[4]', + Writable => 0, + }, + 0x03 => { # look forward to see if new old data exists... + Name => 'OldLensData', + Format => 'undef[17]', + RawConv => '$$self{OldLensData} = 1 unless $val =~ /^.\0+$/s; undef', + Hidden => 1, + }, + 0x04 => { + Name => 'ExitPupilPosition', + Condition => '$$self{OldLensData}', + ValueConv => '$val ? 2048 / $val : $val', + ValueConvInv => '$val ? 2048 / $val : $val', + PrintConv => 'sprintf("%.1f mm",$val)', + PrintConvInv => '$val=~s/\s*mm$//; $val', + }, + 0x05 => { + Name => 'AFAperture', + Condition => '$$self{OldLensData}', + %nikonApertureConversions, + }, + # --> another extra byte at position 0x08 in this version of LensData (PH) + #0x09 => { + # Name => 'FocusPosition', #28 - this appears to be copied from an older version of LensData and is no longer valid. Text with Z9 and Z7_2 with a variety of lenses + # Condition => '$$self{OldLensData}', + # PrintConv => 'sprintf("0x%02x", $val)', + # PrintConvInv => '$val', + #}, + 0x0b => { + Notes => 'this focus distance is approximate, and not very accurate for some lenses', + Name => 'FocusDistance', + Condition => '$$self{OldLensData}', + ValueConv => '0.01 * 10**($val/40)', # in m + ValueConvInv => '$val>0 ? 40*log($val*100)/log(10) : 0', + PrintConv => '$val ? sprintf("%.2f m",$val) : "inf"', + PrintConvInv => '$val eq "inf" ? 0 : $val =~ s/\s*m$//, $val', + }, + 0x0c => { + Name => 'FocalLength', + Condition => '$$self{OldLensData}', + Priority => 0, + %nikonFocalConversions, + }, + 0x0d => { + Name => 'LensIDNumber', + Condition => '$$self{OldLensData}', + Notes => 'see LensID values below', + }, + 0x0e => { + Name => 'LensFStops', + Condition => '$$self{OldLensData}', + ValueConv => '$val / 12', + ValueConvInv => '$val * 12', + PrintConv => 'sprintf("%.2f", $val)', + PrintConvInv => '$val', + }, + 0x0f => { + Name => 'MinFocalLength', + Condition => '$$self{OldLensData}', + %nikonFocalConversions, + }, + 0x10 => { + Name => 'MaxFocalLength', + Condition => '$$self{OldLensData}', + %nikonFocalConversions, + }, + 0x11 => { + Name => 'MaxApertureAtMinFocal', + Condition => '$$self{OldLensData}', + %nikonApertureConversions, + }, + 0x12 => { + Name => 'MaxApertureAtMaxFocal', + Condition => '$$self{OldLensData}', + %nikonApertureConversions, + }, + 0x13 => { + Name => 'MCUVersion', + Condition => '$$self{OldLensData}', + }, + 0x14 => { + Name => 'EffectiveMaxAperture', + Condition => '$$self{OldLensData}', + %nikonApertureConversions, + }, +# +# ---- new LensData tags used by Nikkor Z cameras (ref PH/28). ---- +# (some fields are strictly for Z-series lenses, others apply to legacy F-mount as well, ref 28) +# + 0x2f => { # look forward to see if new lens data exists... + Name => 'NewLensData', + Format => 'undef[17]', + RawConv => '$$self{NewLensData} = 1 unless $val =~ /^.\0+$/s; undef', + Hidden => 1, + }, + 0x30 => { #PH + Name => 'LensID', + Condition => '$$self{NewLensData}', + Notes => 'tags from here onward used for Nikkor Z lenses only', + Format => 'int16u', + PrintConv => { + 1 => 'Nikkor Z 24-70mm f/4 S', + 2 => 'Nikkor Z 14-30mm f/4 S', + 4 => 'Nikkor Z 35mm f/1.8 S', + 8 => 'Nikkor Z 58mm f/0.95 S Noct', #IB + 9 => 'Nikkor Z 50mm f/1.8 S', + 11 => 'Nikkor Z DX 16-50mm f/3.5-6.3 VR', + 12 => 'Nikkor Z DX 50-250mm f/4.5-6.3 VR', + 13 => 'Nikkor Z 24-70mm f/2.8 S', + 14 => 'Nikkor Z 85mm f/1.8 S', + 15 => 'Nikkor Z 24mm f/1.8 S', #IB + 16 => 'Nikkor Z 70-200mm f/2.8 VR S', #IB + 17 => 'Nikkor Z 20mm f/1.8 S', #IB + 18 => 'Nikkor Z 24-200mm f/4-6.3 VR', #IB + 21 => 'Nikkor Z 50mm f/1.2 S', #IB + 22 => 'Nikkor Z 24-50mm f/4-6.3', #IB + 23 => 'Nikkor Z 14-24mm f/2.8 S', #IB + 24 => 'Nikkor Z MC 105mm f/2.8 VR S', #IB + 27 => 'Nikkor Z MC 50mm f/2.8', #IB + 28 => 'Nikkor Z 100-400mm f/4.5-5.6 VR S', #28 + 29 => 'Nikkor Z 28mm f/2.8', #IB + 30 => 'Nikkor Z 400mm f/2.8 TC VR S', #28 + 31 => 'Nikkor Z 24-120 f/4', #28 + 32 => 'Nikkor Z 800mm f/6.3 VR S', #28 + }, + }, + 0x35 => { #28 + Name => 'LensMountType', + RawConv => '$$self{LensMountType} = $val', # 0=> DSLR lens via FTZ style adapter; 1=> Native Z lens; + Format => 'int8u', + Unknown => 1, + PrintConv => { + 0 => 'F-mount Lens', + 1 => 'Z-mount Lens', + }, + }, + 0x36 => { #PH + Name => 'MaxAperture', + Condition => '$$self{NewLensData}', + Format => 'int16u', + Priority => 0, + ValueConv => '2**($val/384-1)', + ValueConvInv => '384*(log($val)/log(2)+1)', + PrintConv => 'sprintf("%.1f",$val)', + PrintConvInv => '$val', + }, + 0x38 => { #PH + Name => 'FNumber', + Condition => '$$self{NewLensData}', + Format => 'int16u', + Priority => 0, + ValueConv => '2**($val/384-1)', + ValueConvInv => '384*(log($val)/log(2)+1)', + PrintConv => 'sprintf("%.1f",$val)', + PrintConvInv => '$val', + }, + 0x3c => { #PH + Name => 'FocalLength', + Condition => '$$self{NewLensData}', + Format => 'int16u', + Priority => 0, + PrintConv => '"$val mm"', + PrintConvInv => '$val=~s/\s*mm$//;$val', + }, + 0x4c => { #28 + Name => 'FocusDistanceRangeWidth', #reflects the number of discrete absolute lens positions that are mapped to the reported FocusDistance. Will be 1 near CFD reflecting very narrow focus distance bands (i.e., quite accurate). Near Infinity will be something like 32. Note: 0 at infinity. + Format => 'int8u', + Condition => '$$self{NewLensData} and $$self{LensMountType} == 1', + RawConv => '$$self{FocusDistanceRangeWidth} = $val', + Unknown => 1, + }, + 0x4e => { #28 + Name => 'FocusDistance', + Format => 'int16u', + Condition => '$$self{NewLensData} and $$self{LensMountType} == 1', + RawConv => '$val = $val/256', # 1st byte is the fractional component. This byte was not previously considered in the legacy calculation (which only used the 2nd byte). When 2nd byte < 80; distance is < 1 meter + ValueConv => '0.01 * 10**($val/40)', # in m + ValueConvInv => '$val>0 ? 40*log($val*100)/log(10) : 0', + PrintConv => q{ + $$self{FocusDistanceRangeWidth} == 0 ? "Inf" : $val < 1 ? $val < 0.35 ? sprintf("%.4f m", $val): sprintf("%.3f m", $val): sprintf("%.2f m", $val), #distances less than 35mm are quite accurate with increasingly less precision past 1m + }, + }, + 0x56 => { #28 + Name => 'LensDriveEnd', # byte contains: 1 at CFD/MOD; 2 at Infinity; 0 otherwise + Condition => '$$self{NewLensData} and $$self{LensMountType} == 1', + Format => 'int8u', + RawConv => 'unless ($$self{FocusDistanceRangeWidth} == 0 ) { if ($val == 0 ) {$$self{LensDriveEnd} = "No"} else { $$self{LensDriveEnd} = "CFD"}; } else{ $$self{LensDriveEnd} = "Inf"}', + Unknown => 1, + }, + 0x5a => { #28 + Name => 'LensPositionAbsolute', # <=0 at infinity. Typical value at CFD might be 58000. Only valid for Z-mount lenses. + Condition => '$$self{NewLensData} and $$self{LensMountType} == 1', + Format => 'int32s', + Unknown => 1, + }, +); + # Unknown Nikon lens data (note: data may need decrypting after byte 4) %Image::ExifTool::Nikon::LensDataUnknown = ( PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, @@ -4095,6 +5162,7 @@ my %nikonFocalConversions = ( 1 => 'On', }, }, + # 0xac - int16u[600] TiffMeteringImage1: 30x20 image (ShotInfoVersion 0800, ref JR) 0x157 => { #JD Name => 'ShutterCount', Condition => '$$self{ShotInfoVersion} eq "0205"', @@ -4125,6 +5193,14 @@ my %nikonFocalConversions = ( Priority => 0, }, # note: DecryptLen currently set to 0x251 + + # 0x55c - int16u[2400] TiffMeteringImage2: 60x40 image (ShotInfoVersion 0800, ref JR) + # 0x181c - int16u[1200] TiffMeteringImage?: 60x20 image for some NEF's (ShotInfoVersion 0800, ref JR) + # 0x217c - int16u[2400] TiffMeteringImage3: 60x40 image (ShotInfoVersion 0800, ref JR) + # 0x3d9c - int16u[2400] TiffMeteringImage4: 60x40 image (ShotInfoVersion 0800, ref JR) + # 0x59c0 - TiffMeteringImageWidth (ShotInfoVersion 0800, ref JR) + # 0x59c2 - TiffMeteringImageHeight (ShotInfoVersion 0800, ref JR) + # 0x59c4 - int16u[1800] TiffMeteringImage5: 30x20 RGB image (ShotInfoVersion 0800, ref JR) ); # shot information for D40 and D40X (encrypted) - ref PH @@ -5176,8 +6252,8 @@ my %nikonFocalConversions = ( WRITE_PROC => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, CHECK_PROC => \&Image::ExifTool::CheckBinaryData, VARS => { ID_LABEL => 'Index' }, - DATAMEMBER => [ 0x04, 0x10, 0x14, 0x2c, 0x50, 0x58, 0xa0, 0xb0, - 0x07b0, 0x086c, 0x0e7c, 0x0eea, 0x2c23 ], + DATAMEMBER => [ 0x04, 0x10, 0x14, 0x2c, 0x50, 0x58, 0xa0, 0xa8, 0xb0, + 0x07b0, 0x086c, 0x0e7c, 0x0eea, 0x2c23, 0x2c8f ], IS_SUBDIR => [ 0x0eeb ], WRITABLE => 1, FIRST_ENTRY => 0, @@ -5200,42 +6276,56 @@ my %nikonFocalConversions = ( DataMember => 'RotationInfoOffset', Format => 'int32u', Writable => 0, - RawConv => '$$self{RotationInfoOffset} = $val || 0x10000000; $val', # (ignore if 0) + Hidden => 1, + RawConv => '$$self{RotationInfoOffset} = $val || 0x10000000; undef', # (ignore if 0) }, 0x14 => { Name => 'JPGInfoOffset', DataMember => 'JPGInfoOffset', Format => 'int32u', Writable => 0, - RawConv => '$$self{JPGInfoOffset} = $val || 0x10000000; $val', # (ignore if 0) + Hidden => 1, + RawConv => '$$self{JPGInfoOffset} = $val || 0x10000000; undef', # (ignore if 0) }, 0x2c => { Name => 'BracketingInfoOffset', DataMember => 'BracketingInfoOffset', Format => 'int32u', Writable => 0, - RawConv => '$$self{BracketingInfoOffset} = $val || 0x10000000; $val', # (ignore if 0) + Hidden => 1, + RawConv => '$$self{BracketingInfoOffset} = $val || 0x10000000; undef', # (ignore if 0) }, 0x50 => { Name => 'ShootingMenuOffset', DataMember => 'ShootingMenuOffset', Format => 'int32u', Writable => 0, - RawConv => '$$self{ShootingMenuOffset} = $val || 0x10000000; $val', # (ignore if 0) + Hidden => 1, + RawConv => '$$self{ShootingMenuOffset} = $val || 0x10000000; undef', # (ignore if 0) }, 0x58 => { Name => 'CustomSettingsOffset', DataMember => 'CustomSettingsOffset', Format => 'int32u', Writable => 0, - RawConv => '$$self{CustomSettingsOffset} = $val || 0x10000000; $val', # (ignore if 0) + Hidden => 1, + RawConv => '$$self{CustomSettingsOffset} = $val || 0x10000000; undef', # (ignore if 0) }, 0xa0 => { Name => 'OrientationOffset', DataMember => 'OrientationOffset', Format => 'int32u', Writable => 0, - RawConv => '$$self{OrientationOffset} = $val || 0x10000000; $val', # (ignore if 0) + Hidden => 1, + RawConv => '$$self{OrientationOffset} = $val || 0x10000000; undef', # (ignore if 0) + }, + 0xa8 => { + Name => 'OtherOffset', + DataMember => 'OtherOffset', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{OtherOffset} = $val || 0x10000000; undef', # (ignore if 0) }, # # Tag ID's below are the offsets for a D500 JPEG image, but these offsets change @@ -5259,6 +6349,18 @@ my %nikonFocalConversions = ( 3 => 'Rotate 180', }, }, + 0x0d0 => { + Name => 'Interval', + # prior version of the d% firmware do not support this tag, nor does the D500 (at least thru firmware 1.3) + Condition => '$$self{Model} eq "NIKON D5" and $$self{FirmwareVersion} ge "1.40"', + PrintConv => '$val > 0 ? sprintf("%.0f", $val) : ""', + }, + 0x0d4 => { + Name => 'IntervalFrame', + # prior version of the d% firmware do not support this tag, nor does the D500 (at least thru firmware 1.3) + Condition => '$$self{Model} eq "NIKON D5" and $$self{FirmwareVersion} ge "1.40"', + PrintConv => '$val > 0 ? sprintf("%.0f", $val) : ""', + }, 0x05e2 => { Name => 'FlickerReductionIndicator', Mask => 0x01, @@ -5626,9 +6728,15 @@ my %nikonFocalConversions = ( PrintConv => 'sprintf("%.1f", $val)', PrintConvInv => '$val', }, - # note: DecryptLen currently set to OrientationOffset + 12 - - # (not sure about how this moves around) +### 0x2c90 - OtherInfo start (D500 firmware 1.20d) + 0x2c8f => { + Name => 'Hook7', + Hidden => 1, + RawConv => 'undef', + # account for variable location of OtherInfo data + Hook => '$varSize = $$self{OtherOffset} - 0x2c90', + }, + # (needs testing) #0x2cb2 => { # Name => 'ExtendedPhotoShootingBanks', # Mask => 0x01, @@ -5637,10 +6745,10 @@ my %nikonFocalConversions = ( # 1 => 'Off', # }, #}, - # don't decode this because it is duplicate information and moves around with firmware versions + # (may not be reliable and is found elsewhere) #0x2ea2 => { # Name => 'Rotation', - # Condition => '$$self{Model} =~ /\bD500\b/ and $$self{FirmwareVersion} =~ /^1.1/', + # Condition => '$$self{Model} =~ /\bD500\b/', # Notes => 'D500 firmware 1.1x', # Mask => 0x30, # PrintConv => { @@ -5650,7 +6758,275 @@ my %nikonFocalConversions = ( # 3 => 'Rotate 180', # }, #}, + 0x2ea4 => { #PH + Name => 'NikonMeteringMode', + Condition => '$$self{Model} =~ /\bD500\b/', # (didn't seem to work for D5, but I need more samples) + Notes => 'D500 only', + Mask => 0x03, + PrintConv => { + 0 => 'Matrix', + 1 => 'Center', + 2 => 'Spot', + 3 => 'Highlight' + }, + }, + # note: DecryptLen currently set to OtherOffset + 0x2ea5 - 0x2c90 +); + +# shot information for the D6 firmware 1.00 (encrypted) - ref 28 +%Image::ExifTool::Nikon::ShotInfoD6 = ( + PROCESS_PROC => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + WRITE_PROC => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, + VARS => { ID_LABEL => 'Index' }, + DATAMEMBER => [ 0x30, 0x60, 0x9c, 0xa4, 0x75e7, 0x760c, 0x7610, 0xc219, 0xc292, 0xc40e, 0xc412, 0xc4a6, 0xc4be ], + WRITABLE => 1, + FIRST_ENTRY => 0, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + NOTES => 'These tags are extracted from encrypted data in images from the D6.', + 0x00 => { + Name => 'ShotInfoVersion', + Format => 'string[4]', + Writable => 0, + }, + 0x04 => { + Name => 'FirmwareVersion', + Format => 'string[8]', + Writable => 0, + }, + 0x24 => { + Name => 'NumberOffsets', # (number of entries in offset table. offsets are from start of ShotInfo data) + DataMember => 'NumberOffsets', + Format => 'int32u', + Writable => 0, + Hidden => 1, + }, + 0x30 => { + Name => 'Offset3', + DataMember => 'Offset3', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{Offset3} = $val || 0x10000000; undef', # (ignore if 0) + }, + 0x60 => { + Name => 'Offset15', + DataMember => 'Offset15', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{Offset15} = $val || 0x10000000; undef', # (ignore if 0) + }, + 0x9c => { + Name => 'OrientationOffset', + DataMember => 'OrientationOffset', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{OrientationOffset} = $val || 0x10000000; undef', # (ignore if 0) + }, + 0xa4 => { + Name => 'Offset32', + DataMember => 'Offset32', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{Offset32} = $val || 0x10000000; undef', # (ignore if 0) + }, + ### 0x75e8 - Offset3 info start (D6 firmware 1.33) + 0x75e7 => { + Name => 'Hook1', + Hidden => 1, + RawConv => 'undef', + # account for variable location of Offset5 data + Hook => '$varSize = $$self{Offset3} - 0x75e8', + }, + 0x760c => { + Name => 'IntervalShooting', + RawConv => '$$self{IntervalShooting} = $val', + Format => 'int16u', + PrintConv => q{ + return 'Off' if $val == 0 ; + my $i = sprintf("Interval %.0f of %.0f",$val, $$self{IntervalShootingIntervals}); #something like "Interval 1 of 3" + my $f = $$self{IntervalShootingShotsPerInterval} > 1 ? sprintf(" Frame %.0f of %.0f",$$self{IntervalFrame}, $$self{IntervalShootingShotsPerInterval}): '' ; #something like "Frame 1 of 3" or blank + return "On: $i$f" + #$val == 0 ? 'Off' : sprintf("On: Interval %.0f of %.0f Frame %.0f of %.0f",$val, $$self{IntervalShootingIntervals}, $$self{IntervalFrame}, $$self{IntervalShootingShotsPerInterval}), + }, + }, + 0x7610 => { + Name => 'IntervalFrame', + RawConv => '$$self{IntervalFrame} = $val', + Condition => '$$self{IntervalShooting} > 0', + Format => 'int16u', + Hidden => 1, + }, +### 0xc21a - OrientationInfo start (D6 firmware 1.00) (0xc952 for firmware 1.33) + 0xc219 => { + Name => 'Hook2', + Hidden => 1, + RawConv => 'undef', + # account for variable location of OrientationInfo data + Hook => '$varSize = $$self{OrientationOffset} - 0xc21a', + }, + 0xc21a => { + Name => 'RollAngle', + Format => 'fixed32u', + Notes => 'converted to degrees of clockwise camera roll', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + 0xc21e => { + Name => 'PitchAngle', + Format => 'fixed32u', + Notes => 'converted to degrees of upward camera tilt', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + 0xc222 => { + Name => 'YawAngle', + Format => 'fixed32u', + Notes => 'the camera yaw angle when shooting in portrait orientation', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + ### 0xc9c6 - Offset32 start (D6 firmware 1.33) + 0xc292 => { + Name => 'Hook3', + Hidden => 1, + RawConv => 'undef', + # account for variable location of data + Hook => '$varSize = $$self{Offset32} - 0xc292', + }, + 0xc40e => { + Name => 'Intervals', + Format => 'int32u', + RawConv => '$$self{IntervalShootingIntervals} = $val', + Condition => '$$self{IntervalShooting} > 0', + }, + 0xc412 => { + Name => 'ShotsPerInterval', + Format => 'int32u', + RawConv => '$$self{IntervalShootingShotsPerInterval} = $val', + Condition => '$$self{IntervalShooting} > 0', + }, + 0xc416 => { + Name => 'IntervalExposureSmoothing', + Condition => '$$self{IntervalShooting} > 0', + Format => 'int8u', + PrintConv => \%offOn, + }, + 0xc418 => { + Name => 'IntervalPriority', + Condition => '$$self{IntervalShooting} > 0', + Format => 'int8u', + PrintConv => \%offOn, + }, + 0xc43a => { + Name => 'FocusShiftNumberShots', + }, + 0xc43e => { + Name => 'FocusShiftStepWidth', + }, + 0xc442 => { + Name => 'FocusShiftInterval', + PrintConv => '$val == 1? "1 Second" : sprintf("%.0f Seconds",$val)', + }, + 0xc446 => { + Name => 'FocusShiftExposureLock', + PrintConv => \%offOn, + }, + #0xc49c => HighISONoiseReduction + 0xc4a0 => { + Name => 'DiffractionCompensation', + Format => 'int8u', + PrintConv => \%offOn, + }, + #0xc4a1 => {Name => 'FlickerReductionShooting',}, #redundant with tag in NikonSettings + 0xc4a6 => { + Name => 'FlashControlMode', #this and nearby tag values for flash may be set from either the Photo Shooting Menu or using the Flash unit menu + RawConv => '$$self{FlashControlMode} = $val', + PrintConv => { + 0 => 'TTL', + 1 => 'Auto External Flash', + 2 => 'GN (distance priority)', + 3 => 'Manual', + 4 => 'Repeating Flash', + }, + }, + 0xc4ac => { + Name => 'FlashGNDistance', + Condition => '$$self{FlashControlMode} == 2', + Unknown => 1, + ValueConv => '$val + 3', + PrintConv => \%flashGNDistance, + }, + 0xc4b0 => { + Name => 'FlashOutput', #range[0,24] with 0=>Full; 1=>50%; then decreasing flash power in 1/3 stops to 0.39% (1/256 full power). #also found in FlashInfoUnknown at offset 0x0a (with different mappings) + Condition => '$$self{FlashControlMode} >= 3', + Unknown => 1, + ValueConv => '2 ** (-$val/3)', + ValueConvInv => '$val>0 ? -3*log($val)/log(2) : 0', + PrintConv => '$val>0.99 ? "Full" : sprintf("%.1f%%",$val*100)', + PrintConvInv => '$val=~/(\d+)/ ? $1/100 : 1', + }, + 0xc4ba => { + Name => 'FlashRemoteControl', + Unknown => 1, + PrintConv => { + 0 => 'Group', + 1 => 'Quick Wireless', + 2 => 'Remote Repeating', + }, + }, + 0xc4be => { + Name => 'FlashMasterControlMode', #tag name chosen for compatibility with those found in FlashInfo0102 & FlashInfo0103 + RawConv => '$$self{FlashGroupOptionsMasterMode} = $val', + PrintConv => \%flashGroupOptionsMode, + }, + 0xc4c0 => { + Name => 'FlashMasterCompensation', + Unknown => 1, + Format => 'int8s', + Condition => '$$self{FlashGroupOptionsMasterMode} != 3', #other than 'Off' + ValueConv => '$val/6', + ValueConvInv => '6 * $val', + PrintConv => '$val ? sprintf("%+.1f",$val) : 0', + PrintConvInv => '$val', + }, + 0xc4c4 => { + Name => 'FlashMasterOutput', + Unknown => 1, + Condition => '$$self{FlashGroupOptionsMasterMode} == 1', #only for Mode=M + ValueConv => '2 ** (-$val/3)', + ValueConvInv => '$val>0 ? -3*log($val)/log(2) : 0', + PrintConv => '$val>0.99 ? "Full" : sprintf("%.1f%%",$val*100)', + PrintConvInv => '$val=~/(\d+)/ ? $1/100 : 1', + }, + 0xc4c6 => { + Name => 'FlashWirelessOption', + Unknown => 1, + PrintConv => { + 0 => 'Optical AWL', + 1 => 'Off', + }, + }, + 0xc55c => { + Name => 'MovieType', + Unknown => 1, + PrintConv => { + 0 => 'MOV', + 1 => 'MP4', + }, + }, + # note: DecryptLen currently set to 0xc9c6 + 720 ); + # shot information for the D610 firmware 1.00 (encrypted) - ref PH %Image::ExifTool::Nikon::ShotInfoD610 = ( PROCESS_PROC => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, @@ -5688,12 +7064,16 @@ my %nikonFocalConversions = ( WRITE_PROC => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, CHECK_PROC => \&Image::ExifTool::CheckBinaryData, VARS => { ID_LABEL => 'Index' }, - DATAMEMBER => [ 0x04, 0x24, 0x40, 0x84, 0x01d0, 0x175e, 0x185d ], + DATAMEMBER => [ 0x04, 0x24, 0x38, 0x40, 0x84, 0x01d0, 0x175e, 0x185d, 0x18ab ], IS_SUBDIR => [ 0x18ab ], WRITABLE => 1, FIRST_ENTRY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, - NOTES => 'These tags are extracted from encrypted data in images from the D810.', + NOTES => q{ + These tags are extracted from encrypted data in images from the D810. Note + that the indices listed below are for firmware version 1.0, but they may be + different for other firmware versions. + }, 0x00 => { Name => 'ShotInfoVersion', Format => 'string[4]', @@ -5713,21 +7093,32 @@ my %nikonFocalConversions = ( DataMember => 'BracketingOffset', Format => 'int32u', Writable => 0, - RawConv => '$$self{BracketingOffset} = $val', + Hidden => 1, + RawConv => '$$self{BracketingOffset} = $val || 0x10000000; undef', + }, + 0x38 => { + Name => 'ISOAutoOffset', + DataMember => 'ISOAutoOffset', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{ISOAutoOffset} = $val || 0x10000000; undef', }, 0x40 => { Name => 'CustomSettingsOffset', # (relative offset from start of ShotInfo data) DataMember => 'CustomSettingsOffset', Format => 'int32u', Writable => 0, - RawConv => '$$self{CustomSettingsOffset} = $val', + Hidden => 1, + RawConv => '$$self{CustomSettingsOffset} = $val || 0x10000000; undef', }, 0x84 => { Name => 'OrientationOffset', DataMember => 'OrientationOffset', Format => 'int32u', Writable => 0, - RawConv => '$$self{OrientationOffset} = $val', + Hidden => 1, + RawConv => '$$self{OrientationOffset} = $val || 0x10000000; undef', }, 0x01d0 => { Name => 'SecondarySlotFunction', @@ -5840,7 +7231,7 @@ my %nikonFocalConversions = ( }, }, 0x175e => { - Name => 'D810MeteringMode', + Name => 'NikonMeteringMode', Mask => 0x03, PrintConv => { 0 => 'Matrix', @@ -5848,15 +7239,7 @@ my %nikonFocalConversions = ( 2 => 'Spot', 3 => 'Highlight' }, - Hook => '$varSize = $$self{CustomSettingsOffset} - 0x18ab', - }, - 0x18ab => { # (actual offset adjusted by Hook above) - Name => 'CustomSettingsD810', - Notes => 'actual offset determined by CustomSettingsOffset', - Format => 'undef[53]', - SubDirectory => { - TagTable => 'Image::ExifTool::NikonCustom::SettingsD810', - }, + Hook => '$varSize = $$self{ISOAutoOffset} - 0x1858', }, 0x185c => { Name => 'ISOAutoShutterTime', @@ -5905,7 +7288,6 @@ my %nikonFocalConversions = ( Name => 'ISOAutoHiLimit', Mask => 0xff, PrintHex => 1, - Hook => '$varSize = $$self{OrientationOffset} - 0x36f4', PrintConv => { 0x24 => 'ISO 200', 0x26 => 'ISO 250', @@ -5949,6 +7331,15 @@ my %nikonFocalConversions = ( 0x6c => 'ISO Hi 4.0', 0x72 => 'ISO Hi 5.0', }, + Hook => '$varSize = $$self{CustomSettingsOffset} - 0x18ab', + }, + 0x18ab => { # (actual offset adjusted by Hook above) + Name => 'CustomSettingsD810', + Format => 'undef[53]', + SubDirectory => { + TagTable => 'Image::ExifTool::NikonCustom::SettingsD810', + }, + Hook => '$varSize = $$self{OrientationOffset} - 0x36f4', }, 0x36f4 => { Name => 'RollAngle', @@ -5999,7 +7390,7 @@ my %nikonFocalConversions = ( WRITE_PROC => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, CHECK_PROC => \&Image::ExifTool::CheckBinaryData, VARS => { ID_LABEL => 'Index' }, - DATAMEMBER => [ 0x04, 0x58, 0x0fbf ], + DATAMEMBER => [ 0x04, 0x58, 0xa0, 0x0fbf, 0x2efa ], IS_SUBDIR => [ 0x1038 ], WRITABLE => 1, FIRST_ENTRY => 0, @@ -6022,7 +7413,16 @@ my %nikonFocalConversions = ( DataMember => 'CustomSettingsOffset', Format => 'int32u', Writable => 0, - RawConv => '$$self{CustomSettingsOffset} = $val', + Hidden => 1, + RawConv => '$$self{CustomSettingsOffset} = $val || 0x10000000; undef', + }, + 0xa0 => { + Name => 'OrientationOffset', + DataMember => 'OrientationOffset', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{OrientationOffset} = $val || 0x10000000; undef', }, 0x0791 => { Name => 'PhotoShootingMenuBankImageArea', @@ -6063,7 +7463,42 @@ my %nikonFocalConversions = ( TagTable => 'Image::ExifTool::NikonCustom::SettingsD850', }, }, - # note: DecryptLen currently set to 94 bytes after CustomSettingsOffset +### 0x2efb - OrientationInfo start (D850 firmware 1.01a) + 0x2efa => { + Name => 'Hook1', + Hidden => 1, + RawConv => 'undef', + # account for variable location of OrientationInfo data + Hook => '$varSize = $$self{OrientationOffset} - 0x2efb', + }, + 0x2efb => { #28 + Name => 'RollAngle', + Format => 'fixed32u', + Notes => 'converted to degrees of clockwise camera roll', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + 0x2eff => { #28 + Name => 'PitchAngle', + Format => 'fixed32u', + Notes => 'converted to degrees of upward camera tilt', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + 0x2f03 => { #28 + Name => 'YawAngle', + Format => 'fixed32u', + Notes => 'the camera yaw angle when shooting in portrait orientation', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + # note: DecryptLen currently set to 0x2f07 ); # shot information for the D4 firmware 1.00g (ref PH) %Image::ExifTool::Nikon::ShotInfoD4 = ( @@ -6108,9 +7543,7 @@ my %nikonFocalConversions = ( WRITABLE => 1, FIRST_ENTRY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, - NOTES => q{ - These tags are extracted from encrypted data in images from the D4S. - }, + NOTES => 'These tags are extracted from encrypted data in images from the D4S.', 0x00 => { Name => 'ShotInfoVersion', Format => 'string[4]', @@ -6360,7 +7793,7 @@ my %nikonFocalConversions = ( Format => 'undef[56]', SubDirectory => { TagTable => 'Image::ExifTool::NikonCustom::SettingsD4' }, }, -# 0x1978 => { #this decode works, but involves more bits than should be necessary +# 0x1978 => { # this decode works, but involves more bits than should be necessary # Name => 'ShutterTrigger', # Mask => 0xff, # PrintConv => { @@ -6378,35 +7811,1357 @@ my %nikonFocalConversions = ( PrintConv => 'sprintf("%.1f", $val)', PrintConvInv => '$val', }, - 0x350f => { - Name => 'PitchAngle', - Format => 'fixed32u', - Notes => 'converted to degrees of upward camera tilt', - ValueConv => '$val <= 180 ? $val : $val - 360', - ValueConvInv => '$val >= 0 ? $val : $val + 360', - PrintConv => 'sprintf("%.1f", $val)', - PrintConvInv => '$val', + 0x350f => { + Name => 'PitchAngle', + Format => 'fixed32u', + Notes => 'converted to degrees of upward camera tilt', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + 0x3513 => { + Name => 'YawAngle', + Format => 'fixed32u', + Notes => 'the camera yaw angle when shooting in portrait orientation', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + 0x3693 => { + Name => 'Rotation', + Mask => 0x30, + PrintConv => { + 0 => 'Horizontal', + 1 => 'Rotate 270 CW', + 2 => 'Rotate 90 CW', + 3 => 'Rotate 180', + }, + }, + # note: DecryptLen currently set to 0x3697 +); + +# shot information for the Z7II firmware 1.00 (encrypted) - ref 28 +%Image::ExifTool::Nikon::ShotInfoZ7II = ( + PROCESS_PROC => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + WRITE_PROC => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, + VARS => { ID_LABEL => 'Index' }, + DATAMEMBER => [ 0x04, 0x30, 0x38, 0x98, 0xa0, 0x75e7, 0x760c, + 0x7610, 0x7eff, 0xce31, 0xcea5, 0xceb6, 0xceb7 ], + IS_SUBDIR => [ 0xceb8 ], + WRITABLE => 1, + FIRST_ENTRY => 0, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + NOTES => 'These tags are extracted from encrypted data in images from the Z7II.', + 0x00 => { + Name => 'ShotInfoVersion', + Format => 'string[4]', + Writable => 0, + }, + 0x04 => { + Name => 'FirmwareVersion', + DataMember => 'FirmwareVersion', + Format => 'string[8]', + Writable => 0, + RawConv => '$$self{FirmwareVersion} = $val', + }, + 0x0e => { + Name => 'FirmwareVersion2', + Format => 'string[8]', + Writable => 0, + Hidden => 1, + }, + 0x18 => { + Name => 'FirmwareVersion3', + Format => 'string[8]', + Writable => 0, + Hidden => 1, + }, + 0x24 => { + Name => 'NumberOffsets', # number of entries in offset table. offsets are from start of ShotInfo data. + DataMember => 'NumberOffsets', + Format => 'int32u', + Writable => 0, + Hidden => 1, + }, + 0x30 => { + Name => 'Offset3', + DataMember => 'Offset3', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{Offset3} = $val || 0x10000000; undef', # (ignore if 0) + }, + 0x38 => { + Name => 'Offset5', + DataMember => 'Offset5', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{Offset5} = $val || 0x10000000; undef', # (ignore if 0) + }, + 0x98 => { + Name => 'OrientationOffset', + DataMember => 'OrientationOffset', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{OrientationOffset} = $val || 0x10000000; undef', # (ignore if 0) + }, + 0xa0 => { + Name => 'Offset31', + DataMember => 'Offset31', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{Offset31} = $val || 0x10000000; undef', # (ignore if 0) + }, + ### 0x75e8 - Offset3 info start (Z7II firmware 1.30) + 0x75e7 => { + Name => 'Hook1', + Hidden => 1, + RawConv => 'undef', + # account for variable location of Offset3 data + Hook => '$varSize = $$self{Offset3} - 0x75e8', + }, + 0x760c => { + Name => 'IntervalShooting', + RawConv => '$$self{IntervalShooting} = $val', + Format => 'int16u', + PrintConv => q{ + return 'Off' if $val == 0 ; + my $i = sprintf("Interval %.0f of %.0f",$val, $$self{IntervalShootingIntervals}); # something like "Interval 1 of 3" + my $f = $$self{IntervalShootingShotsPerInterval} > 1 ? sprintf(" Frame %.0f of %.0f",$$self{IntervalFrame}, $$self{IntervalShootingShotsPerInterval}): '' ; # something like "Frame 1 of 3" or blank + return "On: $i$f" + #$val == 0 ? 'Off' : sprintf("On: Interval %.0f of %.0f Frame %.0f of %.0f",$val, $$self{IntervalShootingIntervals}, $$self{IntervalFrame}, $$self{IntervalShootingShotsPerInterval}), + }, + }, + 0x7610 => { + Name => 'IntervalFrame', + RawConv => '$$self{IntervalFrame} = $val', + Condition => '$$self{IntervalShooting} > 0', + Format => 'int16u', + Hidden => 1, + }, + ### 0x7f00 - Offset5 info start (Z7II firmware 1.30) + 0x7eff => { + Name => 'Hook2', + Hidden => 1, + RawConv => 'undef', + # account for variable location of Offset5 data + Hook => '$varSize = $$self{Offset5} - 0x7f00', + }, + 0x7fa0 => { #28 + Name => 'PortraitImpressionBalance', # will be 0 for firmware 1.21 and earlier; firmware 1.30 onward: will be set by Photo Shooting Menu entry Portrait Impression Balance + # offset5+160; 128 is neutral; >128 increases Yellow; <128 increases Magenta; increments of 4 result from 1 full unit adjustment on the camera + # offset5+161 128 is neutral; >128 increases Brightness; <128 decreases Brightness + # with firmware 1.30 when 'Off' is selected in the Shooting menu, offsets 160 & 161 will contain 255. Selecting Mode 1,2, or 3 will populate offsets 160 & 161 with values in the range [116,141] + Format => 'int8u[2]', + Condition => '$$self{FirmwareVersion} ge "01.30"', + PrintConv => q{ + return 'Off' if $val eq '0 0' or $val eq '255 255'; + my @v = split ' ', $val; + my $brightness = $v[1]==128 ? 'Brightness: Neutral' : sprintf('Brightness: %+.1f',($v[1]-128)/4); + my $color = $v[0]==128 ? 'Color: Neutral' : sprintf('%s: %.1f', $v[0]>128 ? 'Yellow' : 'Magenta', abs($v[0]-128)/4); + # will return something like: 'Magenta: 1.0 Brightness: Neutral' + return "$color $brightness" + }, + }, + ### 0xce32 - OrientationInfo start (Z7II firmware 1.00) + 0xce31 => { + Name => 'Hook3', + Hidden => 1, + RawConv => 'undef', + # account for variable location of OrientationInfo data + Hook => '$varSize = $$self{OrientationOffset} - 0xce32', + }, + + 0xce32 => { + Name => 'RollAngle', + Format => 'fixed32u', + Notes => 'converted to degrees of clockwise camera roll', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + 0xce36 => { + Name => 'PitchAngle', + Format => 'fixed32u', + Notes => 'converted to degrees of upward camera tilt', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + 0xce3a => { + Name => 'YawAngle', + Format => 'fixed32u', + Notes => 'the camera yaw angle when shooting in portrait orientation', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + 0xcea5 => { + Name => 'Hook4', + Hidden => 1, + RawConv => 'undef', + # account for variable location of Offset31 data + Hook => '$varSize = $$self{Offset31} - 0xcea6', + }, + ### 0xcea6 - Offset31 info start (Z7II firmware 1.30) + 0xceb6 => { + Name => 'MenuSettingsZ7IIOffset', + # offset to MenuSettingsZ7II is relative to start of Offset31 block + RawConv => '$$self{MenuSettingsZ7IIOffset} = ($val || 0x10000000) + $$self{Offset31}; undef', # (ignore if 0) + }, + 0xceb7 => { + Name => 'Hook5', + Hidden => 1, + RawConv => 'undef', + # account for variable location of Offset5 data + Hook => '$varSize = $$self{MenuSettingsZ7IIOffset} - 0xceb8', + }, + 0xceb8 => { # (this is 0xd04e for the Z50) + Name => 'MenuSettingsZ7II', + Format => 'undef[860]', + SubDirectory => { + TagTable => 'Image::ExifTool::Nikon::MenuSettingsZ7II', + }, + } + # note: DecryptLen currently set to 0xd04e + 860 (offset for Z50 is 0xd04e) +); + +# shot information for the Z9 firmware 1.00 (encrypted) - ref 28 +%Image::ExifTool::Nikon::ShotInfoZ9 = ( + PROCESS_PROC => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + WRITE_PROC => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, + VARS => { ID_LABEL => 'Index' }, + DATAMEMBER => [ 0x04, 0x30, 0x38, 0x84, 0x8c, 0x6c6f, 0x6c98, + 0x6c9a, 0x7717, 0x7844, 0xeaea, 0xeb6f, 0xeb70 ], + IS_SUBDIR => [ 0xec4b ], + WRITABLE => 1, + FIRST_ENTRY => 0, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + NOTES => 'These tags are extracted from encrypted data in images from the Z9.', + 0x00 => { + Name => 'ShotInfoVersion', + Format => 'string[4]', + Writable => 0, + }, + 0x04 => { + Name => 'FirmwareVersion', + DataMember => 'FirmwareVersion', + Format => 'string[8]', + Writable => 0, + RawConv => '$$self{FirmwareVersion} = $val', + }, + 0x0e => { + Name => 'FirmwareVersion2', + Format => 'string[8]', + Writable => 0, + Hidden => 1, + }, + 0x18 => { + Name => 'FirmwareVersion3', + Format => 'string[8]', + Writable => 0, + Hidden => 1, + }, + 0x24 => { + Name => 'NumberOffsets', # number of entries in offset table. offsets are from start of ShotInfo data. + DataMember => 'NumberOffsets', + Format => 'int32u', + Writable => 0, + Hidden => 1, + }, + 0x30 => { + Name => 'Offset3', #offset3 - length 2528 (Z9 firmware 1.0) + DataMember => 'Offset3', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{Offset3} = $val || 0x10000000; undef', # (ignore if 0) + }, + 0x38 => { + Name => 'Offset5', #offset5 - length 2488 (Z9 firmware 1.0) + DataMember => 'Offset5', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{Offset5} = $val || 0x10000000; undef', # (ignore if 0) + }, + 0x84 => { + Name => 'OrientationOffset', #offset24 - length 108 (Z9 firmware 1.0) + DataMember => 'OrientationOffset', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{OrientationOffset} = $val || 0x10000000; undef', # (ignore if 0) + }, + 0x8c => { + Name => 'Offset26', #offset26 - length 1895 (Z9 firmware 1.0) + DataMember => 'Offset26', + Format => 'int32u', + Writable => 0, + Hidden => 1, + RawConv => '$$self{Offset26} = $val || 0x10000000; undef', # (ignore if 0) + }, + ### 0x6c70 - Offset3 info start (Z9 firmware 1.00) + 0x6c6f => { + Name => 'Offset3Hook', + Hidden => 1, + RawConv => 'undef', + # account for variable location of Offset3 data + Hook => '$varSize = $$self{Offset3} - 0x6c70', + }, + 0x6c98 => { + Name => 'IntervalShooting', + RawConv => '$$self{IntervalShooting} = $val', + Format => 'int16u', + PrintConv => q{ + return 'Off' if $val == 0 ; + my $i = sprintf("Interval %.0f of %.0f",$val, $$self{IntervalShootingIntervals}); # something like "Interval 1 of 3" + my $f = $$self{IntervalShootingShotsPerInterval} > 1 ? sprintf(" Frame %.0f of %.0f",$$self{IntervalFrame}, $$self{IntervalShootingShotsPerInterval}): '' ; # something like "Frame 1 of 3" or blank + return "On: $i$f" + #$val == 0 ? 'Off' : sprintf("On: Interval %.0f of %.0f Frame %.0f of %.0f",$val, $$self{IntervalShootingIntervals}, $$self{IntervalFrame}, $$self{IntervalShootingShotsPerInterval}), + }, + }, + 0x6c9a => { + Name => 'IntervalFrame', + RawConv => '$$self{IntervalFrame} = $val', + Condition => '$$self{IntervalShooting} > 0', + Format => 'int16u', + Hidden => 1, + }, + ### 0x7718 - Offset5 info start (Z9 firmware 1.00) + 0x7717 => { + Name => 'Offsset5Hook', + Hidden => 1, + RawConv => 'undef', + # account for variable location of Offset5 data + Hook => '$varSize = $$self{Offset5} - 0x7718', + }, + 0x7844 => { + Name => 'FocusShiftShooting', + RawConv => '$$self{FocusShiftShooting} = $val', + PrintConv => q{ + return 'Off' if $val == 0 ; + my $i = sprintf("Frame %.0f of %.0f",$val, $$self{FocusShiftNumberShots}); # something like Frame 1 of 100" + return "On: $i" + }, + }, + ### 0xeaeb - OrientationInfo start (Z9 firmware 1.00) + 0xeaea => { + Name => 'OrientationHook', + Hidden => 1, + RawConv => 'undef', + # account for variable location of OrientationInfo data + Hook => '$varSize = $$self{OrientationOffset} - 0xeaeb', + }, + 0xeaeb => { + Name => 'RollAngle', + Format => 'fixed32u', + Notes => 'converted to degrees of clockwise camera roll', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + 0xeaef => { + Name => 'PitchAngle', + Format => 'fixed32u', + Notes => 'converted to degrees of upward camera tilt', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + 0xeaf3 => { + Name => 'YawAngle', + Format => 'fixed32u', + Notes => 'the camera yaw angle when shooting in portrait orientation', + ValueConv => '$val <= 180 ? $val : $val - 360', + ValueConvInv => '$val >= 0 ? $val : $val + 360', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + ### 0xeb5f - Offset26 info start (Z9 firmware 1.00) + 0xeb6f => { + Name => 'MenuSettingsZ9Offset', + Writable => 0, + Hidden => 1, + # offset to MenuSettingsZ9 is relative to start of Offset26 block + RawConv => '$$self{MenuSettingsZ9Offset} = ($val || 0x10000000) + $$self{Offset26}; undef', # (ignore if 0) + }, + 0xeb70 => { + Name => 'Hook5', + Hidden => 1, + RawConv => 'undef', + # account for variable location of menu settings data + Hook => '$varSize = $$self{MenuSettingsZ9Offset} - 0xec4b', + }, + 0xec4b => { + Name => 'MenuSettingsZ9', + Format => 'undef[1646]', + SubDirectory => { + TagTable => 'Image::ExifTool::Nikon::MenuSettingsZ9', + }, + }, + # note: DecryptLen currently set to 0xec4b + 1646 +); + +%Image::ExifTool::Nikon::MenuSettingsZ7II = ( + %binaryDataAttrs, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + DATAMEMBER => [ 176, 180, 328, 352, 858 ], + NOTES => 'These tags are used by the Z5, Z6, Z7, Z6II, Z7II, Z50 and Zfc.', + 160 => { + Name => 'IntervalDurationHours', + Format => 'int32u', + #Condition => '$$self{IntervalShooting} > 0', + }, + 164 => { + Name => 'IntervalDurationMinutes', + Format => 'int32u', + #Condition => '$$self{IntervalShooting} > 0', + }, + 168 => { + Name => 'IntervalDurationSeconds', + Format => 'int32u', + #Condition => '$$self{IntervalShooting} > 0', + }, + 176 => { + Name => 'Intervals', + Format => 'int32u', + RawConv => '$$self{IntervalShootingIntervals} = $val', + #Condition => '$$self{IntervalShooting} > 0', + }, + 180 => { + Name => 'ShotsPerInterval', + Format => 'int32u', + RawConv => '$$self{IntervalShootingShotsPerInterval} = $val', + #Condition => '$$self{IntervalShooting} > 0', + }, + 184 => { + Name => 'IntervalExposureSmoothing', + #Condition => '$$self{IntervalShooting} > 0', + Format => 'int8u', + PrintConv => \%offOn, + }, + 186 => { + Name => 'IntervalPriority', + #Condition => '$$self{IntervalShooting} > 0', + Format => 'int8u', + PrintConv => \%offOn, + }, + 220 => { + Name => 'FocusShiftNumberShots', + }, + 224 => { + Name => 'FocusShiftStepWidth', + }, + 228 => { + Name => 'FocusShiftInterval', + PrintConv => '$val == 1? "1 Second" : sprintf("%.0f Seconds",$val)', + }, + 232 => { + Name => 'FocusShiftExposureLock', + PrintConv => \%offOn, + }, + #304 => White Balance - Kelvin Temp + #312 => ColorSpace + #314 => ActiveD-Lighting + #318 => HighISONoiseReduction + 322 => { + Name => 'DiffractionCompensation', + Format => 'int8u', + PrintConv => \%offOn, + }, + 323 => { + Name => 'AutoDistortionControl', + Format => 'int8u', + PrintConv => \%offOn, + }, + #324 => {Name => 'FlickerReductionShooting',}, # redundant with tag in NikonSettings + 326 => { + Name => 'NikonMeteringMode', + Unknown => 1, + PrintConv => { + 0 => 'Matrix', + 1 => 'Center', + 2 => 'Spot', + 3 => 'Highlight' + }, + }, + 326 => { Name => 'NikonMeteringMode', PrintConv => \%meteringModeZ7}, + 328 => { + Name => 'FlashControlMode', # this and nearby tag values for flash may be set from either the Photo Shooting Menu or using the Flash unit menu + RawConv => '$$self{FlashControlMode} = $val', + PrintConv => \%flashControlModeZ7, + }, + 334 => { + Name => 'FlashGNDistance', + Condition => '$$self{FlashControlMode} == 2', + Unknown => 1, + ValueConv => '$val + 3', + PrintConv => \%flashGNDistance, + }, + 338 => { + Name => 'FlashOutput', # range[0,24] with 0=>Full; 1=>50%; then decreasing flash power in 1/3 stops to 0.39% (1/256 full power). also found in FlashInfoUnknown at offset 0x0a (with different mappings) + Condition => '$$self{FlashControlMode} >= 3', + Unknown => 1, + ValueConv => '2 ** (-$val/3)', + ValueConvInv => '$val>0 ? -3*log($val)/log(2) : 0', + PrintConv => '$val>0.99 ? "Full" : sprintf("%.1f%%",$val*100)', + PrintConvInv => '$val=~/(\d+)/ ? $1/100 : 1', + }, + 346 => { Name => 'FlashWirelessOption', PrintConv => \%flashWirelessOptionZ7, Unknown => 1}, + 348 => { Name => 'FlashRemoteControl', PrintConv => \%flashRemoteControlZ7, Unknown => 1}, + 352 => { + Name => 'FlashMasterControlMode', # tag name chosen for compatibility with those found in FlashInfo0102 & FlashInfo0103 + RawConv => '$$self{FlashGroupOptionsMasterMode} = $val', + PrintConv => \%flashGroupOptionsMode, + }, + 354 => { + Name => 'FlashMasterCompensation', + Format => 'int8s', + Condition => '$$self{FlashGroupOptionsMasterMode} != 3', # other than 'Off' + Unknown => 1, + ValueConv => '$val/6', + ValueConvInv => '6 * $val', + PrintConv => '$val ? sprintf("%+.1f",$val) : 0', + PrintConvInv => '$val', + }, + 358 => { + Name => 'FlashMasterOutput', + Unknown => 1, + Condition => '$$self{FlashGroupOptionsMasterMode} == 1', # only for Mode=M + ValueConv => '2 ** (-$val/3)', + ValueConvInv => '$val>0 ? -3*log($val)/log(2) : 0', + PrintConv => '$val>0.99 ? "Full" : sprintf("%.1f%%",$val*100)', + PrintConvInv => '$val=~/(\d+)/ ? $1/100 : 1', + }, + #360 => {Name => 'FlashGroupAControlMode', }, # commented out to reduce output volume - mapping follows FlashMasterControlMode with FlashGroupACompensation at 362 and FlashGroupAOutput at 368 + #368 => {Name => 'FlashGroupBControlMode', }, # commented out to reduce output volume - mapping follows FlashMasterControlMode with FlashGroupBCompensation at 370 and FlashGroupBOutput at 374 + #376 => {Name => 'FlashGroupCControlMode', }, # commented out to reduce output volume - mapping follows FlashMasterControlMode with FlashGroupCCompensation at 378 and FlashGroupCOutput at 382 + #384 => {Name => 'FlashGroupDControlMode', }, # commented out to reduce output volume - mapping follows FlashMasterControlMode with FlashGroupDCompensation at 386 and FlashGroupDOutput at 390 + #392 => {Name => 'FlashGroupEControlMode', }, # commented out to reduce output volume - mapping follows FlashMasterControlMode with FlashGroupECompensation at 394 and FlashGroupEOutput at 398 + #400 => {Name => 'FlashGroupFControlMode', }, # commented out to reduce output volume - mapping follows FlashMasterControlMode with FlashGroupFCompensation at 402 and FlashGroupFOutput at 406 + #434 => FocusMode + #436 => AFAreaMode + #438 => VibrationReduction + #442 => BracketSet + #444 => BracketProgram + #446 => BracketIncrement + #463 => SilentPhotography + 502 => { Name => 'MovieFrameSize', PrintConv => \%movieFrameSizeZ9, Unknown => 1}, + 504 => { Name => 'MovieFrameRate', PrintConv => \%movieFrameRateZ7, Unknown => 1}, + 506 => { + Name => 'MovieSlowMotion', + Unknown => 1, + PrintConv => { + 0 => 'Off', + 1 => 'On (4x)', # 120p recording with playback @ 30p [1920 x 1080; 30p x 4] or 100p recording with playback @ 25p [1920 x 1080; 25p x 4] + 2 => 'On (5x)', # 120p recording with playback @ 24p [1920 x 1080; 20p x 5] + }, + }, + 510 => { + Name => 'MovieType', + Unknown => 1, + PrintConv => { + 0 => 'MOV', + 1 => 'MP4', + }, + }, + #512 => MovieISOAutoHiLimit + 516 => { + Name => 'MovieISOAutoManualMode', + Condition => '$$self{Model} =~ /^NIKON 7/', #ISO ranges vary by model. These mappings are for the Z7 and Z7II + Format => 'int16u', + Unknown => 1, + ValueConv => '($val-104)/8', + ValueConvInv => '8 * ($val + 104)', + PrintConv => \%iSOAutoHiLimitZ7, + }, + #520 => MovieWhiteBalanceSameAsPhoto + 568 => { Name => 'MovieActiveD-Lighting', PrintConv => \%activeDLightingZ7, Unknown => 1}, + 572 => { Name => 'MovieHighISONoiseReduction', PrintConv => \%offLowNormalHighZ7, Unknown => 1}, + 574 => { Name => 'MovieVignetteControl', PrintConv => \%offLowNormalHighZ7, Unknown => 1}, + 576 => { + Name => 'MovieVignetteControlSameAsPhoto', + Unknown => 1, + PrintConv => \%noYes + }, + 577 => { + Name => 'MovieDiffractionCompensation', + Unknown => 1, + PrintConv => \%offOn + }, + 578 => { + Name => 'MovieAutoDistortionControl', + Unknown => 1, + PrintConv => \%offOn + }, + 584 => { Name => 'MovieFocusMode', PrintConv => \%focusModeZ7, Unknown => 1}, + #586 => MovieAFAreaMode + 590 => { + Name => 'MovieVibrationReduction', + Unknown => 1, + PrintConv => { + 0 => 'Off', + 1 => 'On (Normal)', + 2 => 'On (Sport)', + }, + }, + 591 => { + Name => 'MovieVibrationReductionSameAsPhoto', + Unknown => 1, + PrintConv => \%noYes + }, + #848 => HDMIOutputResolution + #850 => HDMIOutputRange + #854 => HDMIExternalRecorder + #856 => HDMIBitDepth + 858 => { + Name => 'HDMIOutputN-Log', # one of the choices under SettingsMenu/HDMI/Advanced. Curiously,the HDR/HLC output option which is controlled by the same sub-menu is decoded thru NikonSettings + Condition => '$$self{HDMIBitDepth} and $$self{HDMIBitDepth} == 2', # only for 10 bit + RawConv => '$$self{HDMIOutputNLog} = $val', + Unknown => 1, + PrintConv => \%offOn, + }, + #859 => HDMIViewAssist +); + +%Image::ExifTool::Nikon::MenuSettingsZ9 = ( + %binaryDataAttrs, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + DATAMEMBER => [ 140, 188, 192, 232, 424, 534 ], + IS_SUBDIR => [ 799 ], + NOTES => 'These tags are used by the Z9.', + #90 ISO + 140 => { + Name => 'MultipleExposureMode', + RawConv => '$$self{MultipleExposureMode} = $val', + PrintConv => { + 0 => 'Off', + 1 => 'On (Series)', + 2 => 'On', + }, + }, + 142 => {Name => 'MultiExposureShots', Condition => '$$self{MultipleExposureMode} != 0' }, #range 2-9 + 188 => { + Name => 'Intervals', + Format => 'int32u', + RawConv => '$$self{IntervalShootingIntervals} = $val', + Condition => '$$self{IntervalShooting} > 0', + }, + 192 => { + Name => 'ShotsPerInterval', + Format => 'int32u', + RawConv => '$$self{IntervalShootingShotsPerInterval} = $val', + Condition => '$$self{IntervalShooting} > 0', + }, + #220 NEFCompression 0=> 'Lossless' 1=> 'High Efficiency*' 4=> 'High Efficientcy' + 232 => { + Name => 'FocusShiftNumberShots', #1-300 + RawConv => '$$self{FocusShiftNumberShots} = $val', + Condition => '$$self{FocusShiftShooting} > 0', + }, + 236 => { + Name => 'FocusShiftStepWidth', #1(Narrow) to 10 (Wide) + Condition => '$$self{FocusShiftShooting} > 0', + }, + 240 => { + Name => 'FocusShiftInterval', + Condition => '$$self{FocusShiftShooting} > 0', + PrintConv => '$val == 1? "1 Second" : sprintf("%.0f Seconds",$val)', + }, + 244 => { + Name => 'FocusShiftExposureLock', + Unknown => 1, + PrintConv => \%offOn, + Condition => '$$self{FocusShiftShooting} > 0', + }, + 274 => { + Name => 'PhotoShootingMenuBank', + PrintConv => { + 0 => 'A', + 1 => 'B', + 2 => 'C', + 3 => 'D', + }, + }, + 276 => { Name => 'ExtendedMenuBanks', PrintConv => \%offOn, }, #single tag from both Photo & Video menus + 308 => { + Name => 'PhotoShootingMenuBankImageArea', + PrintConv => { + 0 => 'FX', + 1 => 'DX', + 4 => '16:9', + 8 => '1:1', + }, + }, + #310 ImageQuality + 322 => { Name => 'AutoISO', PrintConv => \%offOn, }, + 324 => { + Name => 'ISOAutoHiLimit', + Format => 'int16u', + Unknown => 1, + ValueConv => '($val-104)/8', + ValueConvInv => '8 * ($val + 104)', + PrintConv => \%iSOAutoHiLimitZ7, + }, + 326 => { + Name => 'ISOAutoFlashLimit', + Format => 'int16u', + Unknown => 1, + ValueConv => '($val-104)/8', + ValueConvInv => '8 * ($val + 104)', + PrintConv => \%iSOAutoHiLimitZ7, + }, + #332 ISOAutoShutterTime - Auto setting 0=> 'Auto (Slowest)', 1 => 'Auto (Slower)', 2=> 'Auto', 3=> 'Auto (Faster)', 4=> 'Auto (Fastest)' + 334 => { + Name => 'ISOAutoShutterTime', #shutter speed is 2 ** (-$val/24) + ValueConv => '$val / 8', + Format => 'int16s', + PrintConv => { + -15 => 'Auto', #z9 firmware 1.00 maps both 'Auto' and '30 s' to -15 + -12 => '15 s', + -9 => '8 s', + -6 => '4 s', + -3 => '2 s', + 0 => '1 s', + 1 => '1/1.3 s', + 2 => '1/1.6 s', + 3 => '1/2 s', + 4 => '1/2.5 s', + 5 => '1/3 s', + 6 => '1/4 s', + 7 => '1/5 s', + 8 => '1/6 s', + 9 => '1/8 s', + 10 => '1/10 s', + 11 => '1/13 s', + 12 => '1/15 s', + 13 => '1/20 s', + 14 => '1/25 s', + 15 => '1/30 s', + 16 => '1/40 s', + 17 => '1/50 s', + 18 => '1/60 s', + 19 => '1/80 s', + 20 => '1/100 s', + 21 => '1/120 s', + 22 => '1/160 s', + 23 => '1/200 s', + 24 => '1/250 s', + 25 => '1/320 s', + 26 => '1/400 s', + 27 => '1/500 s', + 28 => '1/640 s', + 29 => '1/800 s', + 30 => '1/1000 s', + 31 => '1/1250 s', + 32 => '1/1600 s', + 33 => '1/2000 s', + 34 => '1/2500 s', + 35 => '1/3200 s', + 36 => '1/4000 s', + 37 => '1/5000 s', + 37.5 => '1/6000 s', + 38 => '1/6400 s', + 39 => '1/8000 s', + 40 => '1/10000 s', + 40.5 => '1/12000 s', + 41 => '1/13000 s', + 42 => '1/16000 s', + }, + }, + #336 WhiteBalance + #406 PictureControl + #408 ColorSpace + #410 ActiveD-Lighting + #412 => { Name => 'NoiseReduction', PrintConv => \%offOn }, #Long Exposure Noise Reduction + #414 HighISONoiseReduction + #414 VignetteControl + 416 => { Name => 'MovieVignetteControl', PrintConv => \%offLowNormalHighZ7, Unknown => 1}, + 418 => { Name => 'DiffractionCompensation', PrintConv => \%offOn }, #value can be set from both the Photo Shoot Menu and the Video Shooting Menu + #419 AutoDistortionControl #value can be set from both the Photo Shoot Menu and the Video Shooting Menu + 420 => { Name => 'FlickerReductionShooting', PrintConv => \%offOn }, + #422 MeteringMode + 424 => { + Name => 'FlashControlMode', # this and nearby tag values for flash may be set from either the Photo Shooting Menu or using the Flash unit menu + RawConv => '$$self{FlashControlMode} = $val', + PrintConv => \%flashControlModeZ7, + }, + 426 => { + Name => 'FlashMasterCompensation', + Format => 'int8s', + Unknown => 1, + ValueConv => '$val/6', + ValueConvInv => '6 * $val', + PrintConv => '$val ? sprintf("%+.1f",$val) : 0', + PrintConvInv => '$val', + }, + 430 => { + Name => 'FlashGNDistance', + Condition => '$$self{FlashControlMode} == 2', + Unknown => 1, + ValueConv => '$val + 3', + PrintConv => \%flashGNDistance, + }, + 434 => { + Name => 'FlashOutput', # range[0,24] with 0=>Full; 1=>50%; then decreasing flash power in 1/3 stops to 0.39% (1/256 full power). also found in FlashInfoUnknown at offset 0x0a (with different mappings) + Condition => '$$self{FlashControlMode} >= 3', + Unknown => 1, + ValueConv => '2 ** (-$val/3)', + ValueConvInv => '$val>0 ? -3*log($val)/log(2) : 0', + PrintConv => '$val>0.99 ? "Full" : sprintf("%.1f%%",$val*100)', + PrintConvInv => '$val=~/(\d+)/ ? $1/100 : 1', + }, + #442 flash wirelss control 0=> 'Off' 1=> 'CMD' + 444 => { Name => 'FlashRemoteControl', PrintConv => \%flashRemoteControlZ7, Unknown => 1}, + 456 => { Name => 'FlashWirelessOption', PrintConv => \%flashWirelessOptionZ7, Unknown => 1}, + #526 FocusMode + 528 => { + Name => 'AFAreaMode', + PrintConv => { + 1 => 'Single', + 2 => 'Dynamic', + 3 => 'Wide (S)', + 4 => 'Wide (L)', + 5 => '3D', + 6 => 'Auto', + 12 => 'Wide (C1)', + 13 => 'Wide (C2)', + }, + }, + 530 => { Name => 'VRMode', PrintConv => \%vRModeZ9}, + 534 => { + Name => 'BracketSet', + RawConv => '$$self{BracketSet} = $val', + PrintConv => { + 0 => 'AE/Flash', + 1 => 'AE', + 2 => 'Flash', + 3 => 'White Balance', + 4 => 'Active-D Lighting', + }, + }, + 536 => { + Name => 'BracketProgram', + Condition => '$$self{BracketSet} < 3', + Notes => 'AE and/or Flash Bracketing', + PrintConv => { + 0 => 'Disabled', + 2 => '2F', + 3 => '3F', + 4 => '4F', + 5 => '5F', + 7 => '7F', + 9 => '9F', + }, + }, + 538 => { + Name => 'BracketIncrement', + Condition => '$$self{BracketSet} < 3', + Notes => 'AE and/or Flash Bracketing', + PrintConv => { + 0 => '0.3', + #1 => '0.5', + 2 => '0.7', + 3 => '1.0', + 4 => '2.0', + 5 => '3.0', + }, + }, + #544 BracketProgram for ADL + 556 => { + Name => 'SecondarySlotFunction', + PrintConv => { + 0 => 'Overflow', + 1 => 'Backup', + 2 => 'NEF Primary + JPG Secondary', + 3 => 'JPG Primary + JPG Secondary', + }, + }, + 572 => { Name => 'DXCropAlert', PrintConv => \%offOn, }, + 574 => { Name => 'SubjectDetection', PrintConv => \%subjectDetectionZ9}, + 604 => { + Name => 'MovieImageArea', + Unknown => 1, + Mask => 0x01, #without the mask 4 => 'FX' 5 => DX only the 2nd Z-series field encountered with a mask. + PrintConv => { + 0 => 'FX', + 1 => 'DX', + }, + }, + 614 => { + Name => 'MovieType', + Unknown => 1, + PrintConv => { + 1 => 'H.265 8-bit (MP4)', + 2 => 'H.265 8-bit (MOV)', + 3 => 'H.265 10-bit (MOV)', + 4 => 'ProRes 422 HQ 10-bit (MOV)', + 5 => 'ProRes RAW HQ 12-bit (MOV)', + 6 => 'NRAW 12-bit (NEV)' + }, + }, + 616 => { + Name => 'MovieISOAutoHiLimit', + Format => 'int16u', + Unknown => 1, + ValueConv => '($val-104)/8', + ValueConvInv => '8 * ($val + 104)', + PrintConv => \%iSOAutoHiLimitZ7, + }, + 618 => { Name => 'MovieISOAutoControlManualMode', PrintConv => \%offOn, Unknown => 1}, + 620 => { + Name => 'MovieISOAutoManualMode', + Format => 'int16u', + Unknown => 1, + ValueConv => '($val-104)/8', + ValueConvInv => '8 * ($val + 104)', + PrintConv => \%iSOAutoHiLimitZ7, + }, + 696 => { Name => 'MovieActiveD-Lighting', PrintConv => \%activeDLightingZ7, Unknown => 1}, + 698 => { Name => 'MovieHighISONoiseReduction', PrintConv => \%offLowNormalHighZ7, Unknown => 1}, + 704 => { + Name => 'MovieFlickerReduction', + PrintConv => { + 0 => 'Auto', + 1 => '50Hz', + 2 => '60Hz', + }, + }, + 706 => { Name => 'MovieMeteringMode', PrintConv => \%meteringModeZ7, , Unknown => 1}, + 708 => { Name => 'MovieFocusMode', PrintConv => \%focusModeZ7, Unknown => 1}, + 710 => { + Name => 'MovieAFAreaMode', + PrintConv => { + 1 => 'Single', + 3 => 'Wide (S)', + 4 => 'Wide (L)', + 6 => 'Auto', + 11 => 'Subject Tracking', + }, + }, + 712 => { Name => 'MovieVRMode', PrintConv => \%vRModeZ9, Unknown => 1}, + 716 => { Name => 'MovieElectronicVR', PrintConv => \%offOn, Unknown => 1 }, #distinct from MoveieVRMode + 718 => { Name => 'MovieSoundRecording', PrintConv => { 0 => 'Off', 1 => 'On', 2 => 'On' }, Unknown => 1 }, #not sure why the unusal mapping with 2 => 'On' + 720 => { Name => 'MicrophoneSensitivity', Unknown => 1}, #1-20 + 722 => { Name => 'MicrophoneAttenuator', PrintConv => \%offOn, Unknown => 1 }, #distinct from MoveieVRMode + 724 => { Name => 'MicrophoneFrequencyResponse', PrintConv => { 0 => 'Wide Range', 1 => 'Vocal Range' }, Unknown => 1 }, + 726 => { Name => 'WindNoiseReduction', PrintConv => \%offOn, Unknown => 1 }, + 748 => { + Name => 'MovieToneMap', + Unknown => 1, + PrintConv => { + 0 => 'SDR', + 1 => 'HLG', + 2 => 'N-Log', + }, + }, + 754 => { Name => 'MovieFrameSize', PrintConv => \%movieFrameSizeZ9, Unknown => 1}, + 756 => { Name => 'MovieFrameRate', PrintConv => \%movieFrameRateZ7, Unknown => 1}, + 762 => { Name => 'MicrophoneJackPower', PrintConv => \%offOn, Unknown => 1 }, + 763 => { Name => 'MovieDXCropAlert', PrintConv => \%offOn, Unknown => 1 }, + 764 => { Name => 'MovieSubjectDetection', PrintConv => \%subjectDetectionZ9, Unknown => 1}, + 799 => { + Name => 'CustomSettingsZ9', + Format => 'undef[608]', + SubDirectory => { TagTable => 'Image::ExifTool::NikonCustom::SettingsZ9' }, + }, + 1426 => { + Name => 'Language', + Unknown => 1, + PrintConv => { + 4 => 'English', + 5 => 'Spanish', + 7 => 'French', + }, + }, + 1428 => { + Name => 'TimeZone', + PrintConv => { + 5 => '+09:00 (Tokyo)', + 6 => '+08:00 (Beijing, Honk Kong, Sinapore)', + 10 => '+05:45 (Kathmandu)', + 11 => '+05:30 (New Dehli)', + 12 => '+05:00 (Islamabad)', + 13 => '+04:30 (Kabul)', + 14 => '+04:00 (Abu Dhabi)', + 15 => '+03:30 (Tehran)', + 16 => '+03:00 (Moscow, Nairobi)', + 17 => '+02:00 (Athens, Helsinki)', + 18 => '+01:00 (Madrid, Paris, Berlin)', + 19 => '+00:00 (London)', + 20 => '-01:00 (Azores)', + 21 => '-02:00 (Fernando de Noronha)', + 22 => '-03:00 (Buenos Aires, Sao Paulo)', + 23 => '-03:30 (Newfoundland)', + 24 => '-04:00 (Manaus, Caracas)', + 25 => '-05:00 (New York, Toronto, Lima)', + 26 => '-06:00 (Chicago, Mexico City)', + 27 => '-07:00 (Denver)', + 28 => '-08:00 (Los Angeles, Vancouver)', + 29 => '-09:00 (Anchorage)', + 30 => '-10:00 (Hawaii)', + }, + }, + 1434 => {Name => 'MonitorBrightness', ValueConv => '$val - 5', Unknown => 1}, # settings: -5 to +5 + 1456 => { Name => 'AFFineTune', PrintConv => \%offOn, Unknown => 1 }, + 1552 => { + Name => 'HDMIOutputResolution', + PrintConv => { + 0 => 'Auto', + 1 => '4320p', + 2 => '2160p', + 3 => '1080p', + #4 => '1080i', + 5 => '720p', + #6 => '576p', + #7 => '480p', + }, + }, + 1565 => { Name => 'SetClockFromLocationData', PrintConv => \%offOn, Unknown => 1 }, + 1572 => { Name => 'AirplaneMode', PrintConv => \%offOn, Unknown => 1 }, + 1573 => { Name => 'EmptySlotRelease', PrintConv => { 0 => 'Disable Release', 1 => 'Enable Release' }, Unknown => 1 }, + 1608 => { Name => 'EnergySavingMode', PrintConv =>\%offOn, Unknown => 1 }, + 1632 => { Name => 'RecordLocationData', PrintConv => \%offOn, Unknown => 1 }, + 1636 => { Name => 'USBPowerDelivery', PrintConv => \%offOn, Unknown => 1 }, + 1645 => { Name => 'SensorShield', PrintConv => { 0 => 'Stays Open', 1 => 'Closes' }, Unknown => 1 }, +); + +# Flash information (ref JD) +%Image::ExifTool::Nikon::FlashInfo0100 = ( + %binaryDataAttrs, + DATAMEMBER => [ 9.2, 15, 16 ], + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + NOTES => q{ + These tags are used by the D2H, D2Hs, D2X, D2Xs, D50, D70, D70s, D80 and + D200. + }, + # NOTE: Must set ByteOrder in SubDirectory if any multi-byte integer tags added + 0 => { + Name => 'FlashInfoVersion', + Format => 'string[4]', + Writable => 0, + }, + 4 => { #PH + Name => 'FlashSource', + PrintConv => { + 0 => 'None', + 1 => 'External', + 2 => 'Internal', + }, + }, + # 5 - values: 46,48,50,54,78 + 6 => { + Format => 'int8u[2]', + Name => 'ExternalFlashFirmware', + SeparateTable => 'FlashFirmware', + PrintConv => \%flashFirmware, + }, + 8 => { + Name => 'ExternalFlashFlags', + PrintConv => { 0 => '(none)', + BITMASK => { + 0 => 'Fired', #28 + 2 => 'Bounce Flash', #PH + 4 => 'Wide Flash Adapter', + 5 => 'Dome Diffuser', #28 + }, + }, + }, + 9.1 => { + Name => 'FlashCommanderMode', + Mask => 0x80, + PrintConv => { 0 => 'Off', 1 => 'On' }, + }, + 9.2 => { + Name => 'FlashControlMode', + Mask => 0x7f, + DataMember => 'FlashControlMode', + RawConv => '$$self{FlashControlMode} = $val', + PrintConv => \%flashControlMode, + SeparateTable => 'FlashControlMode', + }, + 10 => [ + { + Name => 'FlashOutput', + Condition => '$$self{FlashControlMode} >= 0x06', + ValueConv => '2 ** (-$val/6)', + ValueConvInv => '$val>0 ? -6*log($val)/log(2) : 0', + PrintConv => '$val>0.99 ? "Full" : sprintf("%.0f%%",$val*100)', + PrintConvInv => '$val=~/(\d+)/ ? $1/100 : 1', + }, + { + Name => 'FlashCompensation', + Format => 'int8s', + Priority => 0, + ValueConv => '-$val/6', + ValueConvInv => '-6 * $val', + PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)', + PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', + }, + ], + 11 => { + Name => 'FlashFocalLength', + RawConv => '$val ? $val : undef', + PrintConv => '"$val mm"', + PrintConvInv => '$val=~/(\d+)/; $1 || 0', + }, + 12 => { + Name => 'RepeatingFlashRate', + RawConv => '$val ? $val : undef', + PrintConv => '"$val Hz"', + PrintConvInv => '$val=~/(\d+)/; $1 || 0', + }, + 13 => { + Name => 'RepeatingFlashCount', + RawConv => '$val ? $val : undef', + }, + 14 => { #PH + Name => 'FlashGNDistance', + SeparateTable => 1, + PrintConv => \%flashGNDistance, + }, + 15 => { + Name => 'FlashGroupAControlMode', + Mask => 0x0f, + DataMember => 'FlashGroupAControlMode', + RawConv => '$$self{FlashGroupAControlMode} = $val', + PrintConv => \%flashControlMode, + SeparateTable => 'FlashControlMode', + }, + 16 => { + Name => 'FlashGroupBControlMode', + Mask => 0x0f, + DataMember => 'FlashGroupBControlMode', + RawConv => '$$self{FlashGroupBControlMode} = $val', + PrintConv => \%flashControlMode, + SeparateTable => 'FlashControlMode', + }, + 17 => [ + { + Name => 'FlashGroupAOutput', + Condition => '$$self{FlashGroupAControlMode} >= 0x06', + ValueConv => '2 ** (-$val/6)', + ValueConvInv => '$val>0 ? -6*log($val)/log(2) : 0', + PrintConv => '$val>0.99 ? "Full" : sprintf("%.0f%%",$val*100)', + PrintConvInv => '$val=~/(\d+)/ ? $1/100 : 1', + }, + { + Name => 'FlashGroupACompensation', + Format => 'int8s', + ValueConv => '-$val/6', + ValueConvInv => '-6 * $val', + PrintConv => '$val ? sprintf("%+.1f",$val) : 0', + PrintConvInv => '$val', + }, + ], + 18 => [ + { + Name => 'FlashGroupBOutput', + Condition => '$$self{FlashGroupBControlMode} >= 0x06', + ValueConv => '2 ** (-$val/6)', + ValueConvInv => '$val>0 ? -6*log($val)/log(2) : 0', + PrintConv => '$val>0.99 ? "Full" : sprintf("%.0f%%",$val*100)', + PrintConvInv => '$val=~/(\d+)/ ? $1/100 : 1', + }, + { + Name => 'FlashGroupBCompensation', + Format => 'int8s', + ValueConv => '-$val/6', + ValueConvInv => '-6 * $val', + PrintConv => '$val ? sprintf("%+.1f",$val) : 0', + PrintConvInv => '$val', + }, + ], +); + +# Flash information for D40, D40x, D3 and D300 (ref JD) +%Image::ExifTool::Nikon::FlashInfo0102 = ( + %binaryDataAttrs, + DATAMEMBER => [ 9.2, 16.1, 17.1, 17.2 ], + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + NOTES => q{ + These tags are used by the D3 (firmware 1.x), D40, D40X, D60 and D300 + (firmware 1.00). + }, + # NOTE: Must set ByteOrder in SubDirectory if any multi-byte integer tags added + 0 => { + Name => 'FlashInfoVersion', + Format => 'string[4]', + Writable => 0, + }, + 4 => { #PH + Name => 'FlashSource', + PrintConv => { + 0 => 'None', + 1 => 'External', + 2 => 'Internal', + }, + }, + # 5 - values: 46,48,50,54,78 + 6 => { + Format => 'int8u[2]', + Name => 'ExternalFlashFirmware', + SeparateTable => 'FlashFirmware', + PrintConv => \%flashFirmware, + }, + 8 => { + Name => 'ExternalFlashFlags', + PrintConv => { BITMASK => { + 0 => 'Fired', #28 + 2 => 'Bounce Flash', #PH + 4 => 'Wide Flash Adapter', + 5 => 'Dome Diffuser', #28 + }}, + }, + 9.1 => { + Name => 'FlashCommanderMode', + Mask => 0x80, + PrintConv => { 0 => 'Off', 1 => 'On' }, + }, + 9.2 => { + Name => 'FlashControlMode', + Mask => 0x7f, + DataMember => 'FlashControlMode', + RawConv => '$$self{FlashControlMode} = $val', + PrintConv => \%flashControlMode, + SeparateTable => 'FlashControlMode', + }, + 10 => [ + { + Name => 'FlashOutput', + Condition => '$$self{FlashControlMode} >= 0x06', + ValueConv => '2 ** (-$val/6)', + ValueConvInv => '$val>0 ? -6*log($val)/log(2) : 0', + PrintConv => '$val>0.99 ? "Full" : sprintf("%.0f%%",$val*100)', + PrintConvInv => '$val=~/(\d+)/ ? $1/100 : 1', + }, + { + Name => 'FlashCompensation', + # this is the compensation from the camera (0x0012) for "Built-in" FlashType, or + # the compensation from the external unit (0x0017) for "Optional" FlashType - PH + Format => 'int8s', + Priority => 0, + ValueConv => '-$val/6', + ValueConvInv => '-6 * $val', + PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)', + PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', + }, + ], + 12 => { + Name => 'FlashFocalLength', + RawConv => '$val ? $val : undef', + PrintConv => '"$val mm"', + PrintConvInv => '$val=~/(\d+)/; $1 || 0', + }, + 13 => { + Name => 'RepeatingFlashRate', + RawConv => '$val ? $val : undef', + PrintConv => '"$val Hz"', + PrintConvInv => '$val=~/(\d+)/; $1 || 0', + }, + 14 => { + Name => 'RepeatingFlashCount', + RawConv => '$val ? $val : undef', + }, + 15 => { #PH + Name => 'FlashGNDistance', + SeparateTable => 1, + PrintConv => \%flashGNDistance, + }, + 16.1 => { + Name => 'FlashGroupAControlMode', + Mask => 0x0f, + Notes => 'note: group A tags may apply to the built-in flash settings for some models', + DataMember => 'FlashGroupAControlMode', + RawConv => '$$self{FlashGroupAControlMode} = $val', + PrintConv => \%flashControlMode, + SeparateTable => 'FlashControlMode', }, - 0x3513 => { - Name => 'YawAngle', - Format => 'fixed32u', - Notes => 'the camera yaw angle when shooting in portrait orientation', - ValueConv => '$val <= 180 ? $val : $val - 360', - ValueConvInv => '$val >= 0 ? $val : $val + 360', - PrintConv => 'sprintf("%.1f", $val)', - PrintConvInv => '$val', + 17.1 => { + Name => 'FlashGroupBControlMode', + Mask => 0xf0, + Notes => 'note: group B tags may apply to group A settings for some models', + DataMember => 'FlashGroupBControlMode', + RawConv => '$$self{FlashGroupBControlMode} = $val', + PrintConv => \%flashControlMode, + SeparateTable => 'FlashControlMode', }, - 0x3693 => { - Name => 'Rotation', - Mask => 0x30, - PrintConv => { - 0 => 'Horizontal', - 1 => 'Rotate 270 CW', - 2 => 'Rotate 90 CW', - 3 => 'Rotate 180', - }, + 17.2 => { #PH + Name => 'FlashGroupCControlMode', + Mask => 0x0f, + Notes => 'note: group C tags may apply to group B settings for some models', + DataMember => 'FlashGroupCControlMode', + RawConv => '$$self{FlashGroupCControlMode} = $val', + PrintConv => \%flashControlMode, + SeparateTable => 'FlashControlMode', }, - # note: DecryptLen currently set to 0x3697 + 18 => [ + { + Name => 'FlashGroupAOutput', + Condition => '$$self{FlashGroupAControlMode} >= 0x06', + ValueConv => '2 ** (-$val/6)', + ValueConvInv => '$val>0 ? -6*log($val)/log(2) : 0', + PrintConv => '$val>0.99 ? "Full" : sprintf("%.0f%%",$val*100)', + PrintConvInv => '$val=~/(\d+)/ ? $1/100 : 1', + }, + { + Name => 'FlashGroupACompensation', + Format => 'int8s', + ValueConv => '-$val/6', + ValueConvInv => '-6 * $val', + PrintConv => '$val ? sprintf("%+.1f",$val) : 0', + PrintConvInv => '$val', + }, + ], + 19 => [ + { + Name => 'FlashGroupBOutput', + Condition => '$$self{FlashGroupBControlMode} >= 0x60', + ValueConv => '2 ** (-$val/6)', + ValueConvInv => '$val>0 ? -6*log($val)/log(2) : 0', + PrintConv => '$val>0.99 ? "Full" : sprintf("%.0f%%",$val*100)', + PrintConvInv => '$val=~/(\d+)/ ? $1/100 : 1', + }, + { + Name => 'FlashGroupBCompensation', + Format => 'int8s', + ValueConv => '-$val/6', + ValueConvInv => '-6 * $val', + PrintConv => '$val ? sprintf("%+.1f",$val) : 0', + PrintConvInv => '$val', + }, + ], + 20 => [ #PH + { + Name => 'FlashGroupCOutput', + Condition => '$$self{FlashGroupCControlMode} >= 0x06', + ValueConv => '2 ** (-$val/6)', + ValueConvInv => '$val>0 ? -6*log($val)/log(2) : 0', + PrintConv => '$val>0.99 ? "Full" : sprintf("%.0f%%",$val*100)', + PrintConvInv => '$val=~/(\d+)/ ? $1/100 : 1', + }, + { + Name => 'FlashGroupCCompensation', + Format => 'int8s', + ValueConv => '-$val/6', + ValueConvInv => '-6 * $val', + PrintConv => '$val ? sprintf("%+.1f",$val) : 0', + PrintConvInv => '$val', + }, + ], ); # Flash information (ref JD) @@ -7303,6 +10058,42 @@ my %nikonFocalConversions = ( ], ); +# Flash information for the Z7II (ref 28) +# (likey similar to FlashInfo010 and FlashInfo0108 with addition of support for radio controlled units such as the SB-5000? +%Image::ExifTool::Nikon::FlashInfo0300 = ( + %binaryDataAttrs, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + 0 => { + Name => 'FlashInfoVersion', + Format => 'string[4]', + Writable => 0, + }, + 4 => { + Name => 'FlashSource', + PrintConv => { + 0 => 'None', + 1 => 'External', + 2 => 'Internal', + }, + }, + 6 => { + Format => 'int8u[2]', + Name => 'ExternalFlashFirmware', + SeparateTable => 'FlashFirmware', + PrintConv => \%flashFirmware, + }, + 10 => { + Name => 'FlashCompensation', + # this is the compensation from the camera (0x0012) for "Built-in" FlashType, or + # the compensation from the external unit (0x0017) for "Optional" FlashType - PH + Format => 'int8s', + Priority => 0, + ValueConv => '-$val/6', + ValueConvInv => '-6 * $val', + PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)', + PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', + }, +); # Unknown Flash information %Image::ExifTool::Nikon::FlashInfoUnknown = ( %binaryDataAttrs, @@ -7426,6 +10217,43 @@ my %nikonFocalConversions = ( }, ); +# MakerNotes0x51 - compression info for Z9 +%Image::ExifTool::Nikon::MakerNotes0x51 = ( + %binaryDataAttrs, + DATAMEMBER => [ 0 ], + GROUPS => { 0 => 'MakerNotes' }, + 0 => { + Name => 'FirmwareVersion', + Format => 'string[8]', + Writable => 0, + RawConv => '$$self{FirmwareVersion} = $val', + }, + 10 => { + Name => 'NEFCompression', + Writable => 'int16u', + SeparateTable => 'NEFCompression', + PrintConv => \%nefCompression, + }, +); + +# extra info found in IFD0 of NEF files (ref PH, Z6/Z7) +%Image::ExifTool::Nikon::NEFInfo = ( + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + NOTES => q{ + As-yet unknown information found in SubIFD1 tag 0xc7d5 of NEF images from + cameras such as the Z6 and Z7, and NRW images from some Coolpix cameras. + }, + # 0x01 - undef[12] + # 0x02 - undef[148] + # 0x03 - undef[284] + # 0x04 - undef[148,212] + # 0x05 - undef[84] (barrel distortion params at offsets 0x14,0x1c,0x24, ref 28) + # 0x06 - undef[116] (vignette correction params at offsets 0x24,0x34,0x44, ref 28) + # 0x07 - undef[104] + # 0x08 - undef[24] + # 0x09 - undef[36] +); + # tags in Nikon QuickTime videos (PH - observations with Coolpix S3) # (similar information in Kodak,Minolta,Nikon,Olympus,Pentax and Sanyo videos) %Image::ExifTool::Nikon::MOV = ( @@ -8012,18 +10840,32 @@ my %nikonFocalConversions = ( }, 0x2000023 => [ { #PH (D300, but also found in D3,D3S,D3X,D90,D300S,D700,D3000,D5000) - Condition => '$$valPt =~ /^01/', Name => 'PictureControlData', + Condition => '$$valPt =~ /^01/', Writable => 'undef', Permanent => 0, Flags => [ 'Binary', 'Protected' ], SubDirectory => { TagTable => 'Image::ExifTool::Nikon::PictureControl' }, },{ #28 Name => 'PictureControlData', + Condition => '$$valPt =~ /^02/', Writable => 'undef', Permanent => 0, Flags => [ 'Binary', 'Protected' ], SubDirectory => { TagTable => 'Image::ExifTool::Nikon::PictureControl2' }, + },{ + Name => 'PictureControlData', + Condition => '$$valPt =~ /^03/', + Writable => 'undef', + Permanent => 0, + Flags => [ 'Binary', 'Protected' ], + SubDirectory => { TagTable => 'Image::ExifTool::Nikon::PictureControl3' }, + },{ + Name => 'PictureControlData', + Writable => 'undef', + Permanent => 0, + Flags => [ 'Binary', 'Protected' ], + SubDirectory => { TagTable => 'Image::ExifTool::Nikon::PictureControlUnknown' }, }, ], 0x2000024 => { @@ -8072,9 +10914,16 @@ my %nikonFocalConversions = ( 1 => 'D', 2 => 'G', 3 => 'VR', + 4 => '1', #PH + # bit 5 set for FT-1 adapter? - PH + 6 => 'E', #PH (electromagnetic aperture mechanism) + # bit 7 set for AF-P lenses? - PH }) : 'AF'; # remove commas and change "D G" to just "G" - s/,//g; s/\bD G\b/G/; $_ + s/,//g; s/\bD G\b/G/; + s/ E\b// and s/^(G )?/E /; # put "E" at the start instead of "G" + s/ 1// and $_ = "1 $_"; # put "1" at start + return $_; ], }, 0x2000084 => { @@ -8092,6 +10941,7 @@ my %nikonFocalConversions = ( 7 => 'Fired, External', #14 8 => 'Fired, Commander Mode', 9 => 'Fired, TTL Mode', + 18 => 'LED Light', #G.F. (movie LED light) }, }, 0x2000098 => [ @@ -8130,7 +10980,7 @@ my %nikonFocalConversions = ( }, }, { - Condition => '$$valPt =~ /^0400/', # 1J1, 1V1 + Condition => '$$valPt =~ /^040[01]/', # 0=1J1/1V1, 1=1J2 Name => 'LensData0400', SubDirectory => { TagTable => 'Image::ExifTool::Nikon::LensData0400', @@ -8139,10 +10989,45 @@ my %nikonFocalConversions = ( DecryptStart => 4, }, }, - { # (1J1/1V1=0400) + { + Condition => '$$valPt =~ /^0402/', # 1J3/1S1/1V2 + Name => 'LensData0402', + SubDirectory => { + TagTable => 'Image::ExifTool::Nikon::LensData0402', + ProcessProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + WriteProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + DecryptStart => 4, + }, + }, + { + Condition => '$$valPt =~ /^0403/', # 1J4,1J5 + Name => 'LensData0403', + SubDirectory => { + TagTable => 'Image::ExifTool::Nikon::LensData0403', + ProcessProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + WriteProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + DecryptStart => 4, + }, + }, + { + Condition => '$$valPt =~ /^080[012]/', # Z6/Z7/Z9 + Name => 'LensData0800', + SubDirectory => { + TagTable => 'Image::ExifTool::Nikon::LensData0800', + ProcessProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + WriteProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + DecryptStart => 4, + ByteOrder => 'LittleEndian', + # 0x5a0c - NikonMeteringMode for some Z6 ver1.00 samples (ref PH) + }, + }, + { Name => 'LensDataUnknown', SubDirectory => { TagTable => 'Image::ExifTool::Nikon::LensDataUnknown', + ProcessProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + WriteProc => \&Image::ExifTool::Nikon::ProcessNikonEncrypted, + DecryptStart => 4, }, }, ], @@ -8210,6 +11095,103 @@ my %nikonFocalConversions = ( }, ); +# Nikon XMP tags written in NKSC metadata +%Image::ExifTool::Nikon::ast = ( + GROUPS => { 0 => 'XMP', 1 => 'XMP-ast', 2 => 'Image' }, + PROCESS_PROC => \&Image::ExifTool::XMP::ProcessXMP, + NAMESPACE => 'ast', + VARS => { NO_ID => 1 }, + NOTES => 'Tags used by Nikon NX Studio in Nikon NKSC sidecar files and trailers.', + about => { }, + version => { }, + XMLPackets => { + SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' }, + Encoding => 'Base64', + Binary => 1, + }, + IPTC => { + SubDirectory => { TagTable => 'Image::ExifTool::IPTC::Main' }, + Encoding => 'Base64', + Binary => 1, + }, + GPSVersionID => { Groups => { 2 => 'Location' }, %base64bytes }, + GPSLatitudeRef => { + Groups => { 2 => 'Location' }, + %base64int32u, + PrintConv => { 0 => 'North', 1 => 'South' }, #PH (NC) + }, + GPSLatitude => { Groups => { 2 => 'Location' }, %base64coord }, + GPSLongitudeRef => { + Groups => { 2 => 'Location' }, + %base64int32u, + PrintConv => { 2 => 'East', 3 => 'West' }, #PH (NC) + }, + GPSLongitude => { Groups => { 2 => 'Location' }, %base64coord }, + GPSAltitudeRef => { + Groups => { 2 => 'Location' }, + %base64bytes, + PrintConv => { + 0 => 'Above Sea Level', + 1 => 'Below Sea Level', + }, + }, + GPSAltitude => { + Groups => { 2 => 'Location' }, + %base64double, + PrintConv => '"$val m"', + }, + GPSMapDatum => { Groups => { 2 => 'Location' } }, + GPSImgDirection => { + Groups => { 2 => 'Location' }, + %base64double, + PrintConv => 'sprintf("%.2f", $val)', + }, + GPSImgDirectionRef => { + Groups => { 2 => 'Location' }, + PrintConv => { + M => 'Magnetic North', + T => 'True North', + }, + }, +); +%Image::ExifTool::Nikon::sdc = ( + GROUPS => { 0 => 'XMP', 1 => 'XMP-sdc', 2 => 'Image' }, + PROCESS_PROC => \&Image::ExifTool::XMP::ProcessXMP, + NAMESPACE => 'sdc', + VARS => { NO_ID => 1 }, + about => { }, + version => { }, + appversion => { Name => 'AppVersion' }, + appname => { Name => 'AppName' }, +); +%Image::ExifTool::Nikon::nine = ( + GROUPS => { 0 => 'XMP', 1 => 'XMP-nine', 2 => 'Image' }, + PROCESS_PROC => \&Image::ExifTool::XMP::ProcessXMP, + NAMESPACE => 'nine', + VARS => { NO_ID => 1 }, + about => { }, + version => { }, + Label => { }, + Rating => { }, + Trim => { %base64bin }, + NineEdits => { + SubDirectory => { + TagTable => 'Image::ExifTool::Nikon::NineEdits', + IgnoreProp => { userData => 1 }, # remove "UserData" from already overly long tag names + }, + Binary => 1, + }, +); +%Image::ExifTool::Nikon::NineEdits = ( + GROUPS => { 0 => 'XML', 1 => 'NineEdits', 2 => 'Image' }, + PROCESS_PROC => \&Image::ExifTool::XMP::ProcessXMP, + VARS => { NO_ID => 1 }, + NOTES => 'XML-based tags used to store editing information.', + filterParametersBinary => { %base64bin }, + filterParametersExportExportData => { %base64bin }, + filterParametersCustomCustomData => { %base64bin }, +); + # Nikon composite tags %Image::ExifTool::Nikon::Composite = ( GROUPS => { 2 => 'Camera' }, @@ -8338,7 +11320,7 @@ sub GetAFPointGrid($$;$) return undef unless $val =~ /^([A-J])(\d+)$/i; return (ord(uc($1))-65) * $ncol + $2 - 1; } else { - my $row = int(($val + 0.5) / $ncol); + my $row = int(($val + 0.5) / $ncol) & 0xff; my $col = $val - $ncol * $row + 1; return chr(65+$row) . $col; } @@ -8386,6 +11368,32 @@ sub PrintAFPointsGridInv($$$) return join(" ", unpack("H2"x$size, pack('C*', @dat))); } +#------------------------------------------------------------------------------ +# Print conversion for relative Left/Right AF points (ref 28) +# Inputs: 0) column, 1) number of columns +# Returns: AF point data as a string (e.g. '2L of Center' or 'C' or '3R of Center') +sub PrintAFPointsLeftRight($$) +{ + my ($col, $ncol) = @_; + my $center = 1 + ($ncol + 1)/2; + return 'C' if $col == $center; + return sprintf('%d', $center - $col) . 'L of Center' if $col < $center; + return sprintf('%d', $col - $center) . 'R of Center' if $col > $center; +} + +#------------------------------------------------------------------------------ +# Print conversion for relative Up/Down AF points (ref 28) +# Inputs: 0) row, 1) number of rows +# Returns: AF point data as a string (e.g. '2U from Center' or 'C' or '3D from Center') +sub PrintAFPointsUpDown($$) +{ + my ($row, $nrow) = @_; + my $center = 1 + ($nrow + 1)/2; + return 'C' if $row == $center; + return sprintf('%d', $center - $row) . 'U from Center' if $row < $center; + return sprintf('%d', $row - $center) . 'D from Center' if $row > $center; +} + #------------------------------------------------------------------------------ # Print PictureControl value # Inputs: 0) value (with 0x80 subtracted), @@ -8439,20 +11447,26 @@ sub LensIDConv($$$) return join(' or ', @user) if @user; return join(' or ', @vals); } - # Sigma has been changing the LensID on some new lenses + # Sigma has been changing the LensIDNumber on some new lenses # and with some Sigma lenses the LensFStops changes! (argh!) + # Also, older cameras my not set bits 4-7 of LensType my $pat = $val; - $pat =~ s/^\w+ \w+/.. ../; + $pat =~ s/^\w+ \w+/.. ../; # ignore LensIDNumber and LensFStops + $pat =~ s/\w(\w)$/.$1/; # ignore bits 4-7 of LensType my @ids = sort grep /^$pat$/, keys %$conv; if (@ids) { # first try different LensFStops (2nd value) ($pat = $val) =~ s/ \w+/ ../; my @good = grep /^$pat$/, @ids; return $$conv{$good[0]} if @good; - # then try different LensType (1st value) + # then try different LensIDNumber (1st value) ($pat = $val) =~ s/^\w+/../; @good = grep /^$pat$/, @ids; return "Unknown ($val) $$conv{$good[0]} ?" if @good; + # older cameras may not set bits 4-7 of LensType + ($pat = $val) =~ s/\w(\w)$/.$1/; + @good = grep /^$pat$/, @ids; + return "Unknown ($val) $$conv{$good[0]} ?" if @good; } return undef; } @@ -8571,6 +11585,72 @@ sub SerialKey($$) return 0x60; # D200 (ref 10), D40X (ref PH), etc } +#------------------------------------------------------------------------------ +# Extract information from "NIKON APP" trailer (ref PH) +# Inputs: 0) ExifTool ref, 1) Optional dirInfo ref for returning trailer info +# Returns: true on success +sub ProcessNikonApp($;$) +{ + local $_; + my ($et, $dirInfo) = @_; + my $raf = $$et{RAF}; + my $offset = $dirInfo ? $$dirInfo{Offset} || 0 : 0; + my $buff; + + return 0 unless $raf->Seek(-20-$offset, 2) and $raf->Read($buff, 20) == 20 and + substr($buff,-16) eq "\0\0\0\0\0\0/NIKON APP"; # check magic number + + my $verbose = $et->Options('Verbose'); + my $fileEnd = $raf->Tell(); + my $trailerLen = unpack('N', $buff); + $trailerLen > $fileEnd and $et->Warn('Bad NikonApp trailer size'), return 0; + if ($dirInfo) { + $$dirInfo{DirLen} = $trailerLen if $dirInfo; + $$dirInfo{DataPos} = $fileEnd - $trailerLen; + if ($$dirInfo{OutFile}) { + if ($$et{DEL_GROUP}{NikonApp}) { + ++$$et{CHANGED}; + # just copy the trailer when writing + } elsif ($trailerLen > $fileEnd or not $raf->Seek($$dirInfo{DataPos}, 0) or + $raf->Read(${$$dirInfo{OutFile}}, $trailerLen) != $trailerLen) + { + return 0; + } else { + return 1; + } + } + $et->DumpTrailer($dirInfo) if $verbose or $$et{HTML_DUMP}; + } + unless ($trailerLen >= 0x40 and $raf->Seek($fileEnd - $trailerLen, 0) and + $raf->Read($buff, 0x40) == 0x40 and $buff =~ m(NIKON APP\0)) + { + $et->Warn('Error reading NikonApp trailer'); + return 0; + } + $$et{SET_GROUP0} = 'NikonApp'; + while ($raf->Read($buff, 8) == 8) { + my ($id, $len) = unpack('N2', $buff); + if ($len & 0x80000000) { + $et->Warn('Invalid NikonApp record length'); + last; + } + last if $id == 0 and $len == 0; + unless ($raf->Read($buff, $len) == $len) { + $et->Warn('Truncated NikonApp record'); + last; + } + if ($id == 1) { + require Image::ExifTool::XMP; + Image::ExifTool::XMP::ProcessXMP($et, { DataPt => \$buff }); + } else { # (haven't seen any other types of records) + $et->Warn("Unknown NikonApp record $id"); + last; + } + } + delete $$et{SET_GROUP0}; + return 1; +} + #------------------------------------------------------------------------------ # Read Nikon NCTG tags in MOV videos # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref @@ -8580,35 +11660,47 @@ sub ProcessNikonMOV($$$) my ($et, $dirInfo, $tagTablePtr) = @_; my $dataPt = $$dirInfo{DataPt}; my $dataPos = $$dirInfo{DataPos}; - my $pos = $$dirInfo{DirStart}; - my $end = $pos + $$dirInfo{DirLen}; + my %needTags = ( 0x110a431 => 0, 0x20000a7 => undef ); # needed for decryption $et->VerboseDir($$dirInfo{DirName}, 0, $$dirInfo{DirLen}); - while ($pos + 8 < $end) { - my $tag = Get32u($dataPt, $pos); - my $fmt = Get16u($dataPt, $pos + 4); # (same format code as EXIF) - my $count = Get16u($dataPt, $pos + 6); - $pos += 8; - my $fmtStr = $Image::ExifTool::Exif::formatName[$fmt]; - unless ($fmtStr) { - $et->Warn(sprintf("Unknown format ($fmt) for $$dirInfo{DirName} tag 0x%x",$tag)); - last; - } - my $size = $count * $Image::ExifTool::Exif::formatSize[$fmt]; - if ($pos + $size > $end) { - $et->Warn(sprintf("Truncated data for $$dirInfo{DirName} tag 0x%x",$tag)); - last; + my $pass; + # do two passes so we can pre-scan for necessary decryption keys + for ($pass=0; $pass<2; ++$pass) { + my $pos = $$dirInfo{DirStart}; + my $end = $pos + $$dirInfo{DirLen}; + while ($pos + 8 < $end) { + my $tag = Get32u($dataPt, $pos); + my $fmt = Get16u($dataPt, $pos + 4); # (same format code as EXIF) + my $count = Get16u($dataPt, $pos + 6); + $pos += 8; + my $fmtStr = $Image::ExifTool::Exif::formatName[$fmt]; + unless ($fmtStr) { + $et->Warn(sprintf("Unknown format ($fmt) for $$dirInfo{DirName} tag 0x%x",$tag)) if $pass; + last; + } + my $size = $count * $Image::ExifTool::Exif::formatSize[$fmt]; + if ($pos + $size > $end) { + $et->Warn(sprintf("Truncated data for $$dirInfo{DirName} tag 0x%x",$tag)) if $pass; + last; + } + if ($pass) { + my $rational; + my $val = ReadValue($dataPt, $pos, $fmtStr, $count, $size, \$rational); + my $key = $et->HandleTag($tagTablePtr, $tag, $val, + DataPt => $dataPt, + DataPos => $dataPos, + Format => $fmtStr, + Start => $pos, + Size => $size, + Base => $$dirInfo{Base}, + ); + $$et{RATIONAL}{$key} = $rational if $rational and $key; + } elsif (exists $needTags{$tag}) { + $needTags{$tag} = ReadValue($dataPt, $pos, $fmtStr, $count, $size); + $$et{NikonSerialKey} = SerialKey($et, $needTags{0x110a431}); + $$et{NikonCountKey} = $needTags{0x20000a7}; + } + $pos += $size; # is this padded to an even offset???? } - my $rational; - my $val = ReadValue($dataPt, $pos, $fmtStr, $count, $size, \$rational); - my $key = $et->HandleTag($tagTablePtr, $tag, $val, - DataPt => $dataPt, - DataPos => $dataPos, - Format => $fmtStr, - Start => $pos, - Size => $size, - ); - $$et{RATIONAL}{$key} = $rational if $rational and $key; - $pos += $size; # is this padded to an even offset???? } return 1; } @@ -8773,12 +11865,10 @@ sub PrescanExif($$$) $dataLen = length $data; $dirStart = 0; } - # loop through necessary IFD entries - my ($lastTag) = sort { $b <=> $a } keys %$tagHash; # (reverse sort) + # loop through Nikon MakerNote IFD entries for ($index=0; $index<$numEntries; ++$index) { my $entry = $dirStart + 2 + 12 * $index; my $tagID = Get16u($dataPt, $entry); - last if $tagID > $lastTag; # (assuming tags are in order) next unless exists $$tagHash{$tagID}; # only extract required tags my $format = Get16u($dataPt, $entry+2); next if $format < 1 or $format > 13; @@ -8902,7 +11992,7 @@ Nikon maker notes in EXIF information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/NikonCapture.pm b/src/Image-ExifTool/lib/Image/ExifTool/NikonCapture.pm index 9f20dbfd..e02b7a8f 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/NikonCapture.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/NikonCapture.pm @@ -918,7 +918,7 @@ the maker notes of NEF images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/NikonCustom.pm b/src/Image-ExifTool/lib/Image/ExifTool/NikonCustom.pm index cfe18f4e..6f96b448 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/NikonCustom.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/NikonCustom.pm @@ -5,7 +5,7 @@ # # Revisions: 2009/11/25 - P. Harvey Created # -# References: 1) Warren Hatch private communication (D3 with SB-800 and SB-900) +# References: 1) Warren Hatch private communication (D3 and Z9 with SB-800 and SB-900) # 2) Anonymous contribution 2011/05/25 (D700, D7000) # JD) Jens Duttke private communication #------------------------------------------------------------------------------ @@ -15,8 +15,125 @@ package Image::ExifTool::NikonCustom; use strict; use vars qw($VERSION); -$VERSION = '1.17'; +$VERSION = '1.20'; +my %buttonsZ9= ( + 0 => 'None', + 1 => 'Preview', + 3 => 'FV Lock', + 4 => 'AE/AF Lock', + 5 => 'AE Lock Only', + 6 => 'AE Lock (reset on release)', + 7 => 'AE Lock (hold)', + 8 => 'AF Lock Only', + 9 => 'AF-On', + 10 => 'Flash Disable/Enable', + 11 => 'Bracketing Burst', + 12 => '+NEF(RAW)', + 18 => 'Virtual Horizon', + 19 => 'Synchronized Release', + 20 => 'My Menu', + 21 => 'My Menu Top Item', + 22 => 'Playback', + 23 => 'Rating', + 24 => 'Protect', + 25 => 'Zoom', + 26 => 'Focus Peaking', + 28 => 'Image Area', + 30 => 'Non-CPU Lens', + 31 => 'Active-D Lighting', + 33 => '1 Stop Speed/Aperture', + 35 => 'Metering', + 36 => 'Auto Bracketing', + 37 => 'Multiple Exposure', + 38 => 'HDR Overlay', + 39 => 'Picture Control', + 40 => 'Quality', + 41 => 'Focus Mode/AF AreaMode', + 42 => 'Select Center Focus Point', + 44 => 'Record Movie', + 47 => 'Choose Folder', + 48 => 'Power Aperture (Open)', + 49 => 'Power Aperture (Close)', + 52 => 'Microphone Sensitivity', + 57 => 'Preset Focus Point', + 58 => 'AE/AWB Lock (hold)', + 59 => 'AF-AreaMode', + 60 => 'AF-AreaMode + AF-On', + 61 => 'Recall Shooting Functions', + 64 => 'Filtered Playback', + 65 => 'Same as AF-On', + 66 => 'Voice Memo', + 70 => 'Photo Shooting Bank', + 73 => 'Exposure Compensation', + 76 => 'Silent Mode', + 78 => 'LiveView Information', + 79 => 'AWB Lock (hold)', + 80 => 'Grid Display', + 81 => 'Starlight View', + 82 => 'Select To Send (PC)', + 83 => 'Select To Send (FTP)', + 85 => 'Control Lock', + 86 => 'Save Focus Position', + 87 => 'Recall Focus Position', + 88 => 'Recall Shooting Functions (Hold)', +); +my %dialsZ9 = ( + 0 => '1 Frame', + 1 => '10 Frames', + 2 => '50 Frames', + 3 => 'Folder', + 4 => 'Protect', + 5 => 'Photos Only', + 6 => 'Videos Only', + 7 => 'Rating', + 8 => 'Page', +); +my %evfGridsZ9 = ( + 0 => '3x3', + 1 => '4x4', + 2 => '2.35:1', + 3 => '1.85:1', + 4 => '5:4', + 5 => '4:3', + 6 => '1:1', + 7 => '16:9', + 8 => '90%', +); +my %flicksZ9 = ( + 0 => 'Rating', + 1 => 'Select To Send (PC)', + 2 => 'Select To Send (FTP)', + 3 => 'Protect', + 4 => 'Voice Memo', + 5 => 'None', +); +my %focusModeRestrictionsZ9 = ( + 0 => 'AF-S', + 1 => 'AF-C', + 2 => 'Full-time AF', + 3 => 'Manual', + 4 => 'No Restrictions', +); +my %powerOffDelayTimesZ9 = ( + 0 => '2 s', + 1 => '4 s', + 3 => '10 s', + 4 => '20 s', + 5 => '30 s', + 6 => '1 min', + 7 => '5 min', + 8 => '10 min', + 11 => '30 min', + 12 => 'No Limit', +); +my %thirdHalfFull = ( + 0 => '1/3 EV', + 1 => '1/2 EV', + 2 => '1 EV', +); + +my %limitNolimit = ( 0 => 'Limit', 1 => 'No Limit' ); my %offOn = ( 0 => 'Off', 1 => 'On' ); my %onOff = ( 0 => 'On', 1 => 'Off' ); my %noYes = ( 0 => 'No', 1 => 'Yes' ); @@ -3083,7 +3200,7 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); 3 => 'D', }, }, - 1.1 => { #CSa1 + 1.1 => { # CSa1 Name => 'AF-CPrioritySelection', Mask => 0xc0, PrintConv => { @@ -3093,7 +3210,15 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); 3 => 'Focus + Release', }, }, - 1.2 => { # CSa6 + 1.2 => { # CSa2 + Name => 'AF-SPrioritySelection', + Mask => 0x20, + PrintConv => { + 0 => 'Focus', + 1 => 'Release', + }, + }, + 1.3 => { # CSa6 Name => 'NumberOfFocusPoints', Mask => 0x10, PrintConv => { @@ -3101,7 +3226,7 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); 1 => '15 Points', }, }, - 1.3 => { # CSa4 + 1.4 => { # CSa4 Name => 'Three-DTrackingFaceDetection', Mask => 0x08, PrintConv => { @@ -3109,14 +3234,6 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); 1 => 'On', }, }, - 1.4 => { # CSa2 - Name => 'AF-SPrioritySelection', - Mask => 0x20, - PrintConv => { - 0 => 'Focus', - 1 => 'Release', - }, - }, 1.5 => { # CSa3-a Name => 'BlockShotAFResponse', Mask => 0x07, @@ -3358,6 +3475,8 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); 47 => 'AF-Area Mode + AF-On (Auto Area AF)', 49 => 'Sync Release (Master Only)', 50 => 'Sync Release (Remote Only)', + 58 => 'AF-Area Mode + AF-On (Group Area AF - HL)', + 59 => 'AF-Area Mode + AF-On (Group Area AF - VL)', }, }, 15.1 => { # CSf1-a @@ -3401,6 +3520,8 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); 47 => 'AF-Area Mode + AF-On (Auto Area AF)', 49 => 'Sync Release (Master Only)', 50 => 'Sync Release (Remote Only)', + 58 => 'AF-Area Mode + AF-On (Group Area AF - HL)', + 59 => 'AF-Area Mode + AF-On (Group Area AF - VL)', }, }, 16.1 => { # CSf1-p @@ -4150,7 +4271,7 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); 3 => 'D', }, }, - 1.1 => { #CSa1 + 1.1 => { # CSa1 Name => 'AF-CPrioritySelection', Mask => 0xc0, PrintConv => { @@ -4160,7 +4281,15 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); 3 => 'Focus + Release', }, }, - 1.2 => { # CSa6 + 1.2 => { # CSa2 + Name => 'AF-SPrioritySelection', + Mask => 0x20, + PrintConv => { + 0 => 'Focus', + 1 => 'Release', + }, + }, + 1.3 => { # CSa6 Name => 'NumberOfFocusPoints', Mask => 0x10, PrintConv => { @@ -4168,19 +4297,11 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); 1 => '15 Points', }, }, - 1.3 => { # CSa4 + 1.4 => { # CSa4 Name => 'Three-DTrackingFaceDetection', Mask => 0x08, PrintConv => \%offOn, }, - 1.4 => { # CSa2 - Name => 'AF-SPrioritySelection', - Mask => 0x20, - PrintConv => { - 0 => 'Focus', - 1 => 'Release', - }, - }, 1.5 => { # CSa3-a Name => 'BlockShotAFResponse', Mask => 0x07, @@ -6950,8 +7071,8 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); }, }, 49.1 => { # CSa9 - Name => 'LimitAFAreaModeSelection', #note that 'Dynamic area (9 points)' can be selected from the camera menu but the setting is not writen to the EXIF data. - Mask => 0x7e, #...This AF Mode was addded to the D5 firmware several months after the camera's initial release which may help explain the inconsistency. + Name => 'LimitAFAreaModeSelection', #note that 'Dynamic area (9 points)' can be selected from the camera menu but the setting is not written to the EXIF data. + Mask => 0x7e, #...This AF Mode was added to the D5 firmware several months after the camera's initial release which may help explain the inconsistency. PrintConv => { 0 => 'No Restrictions', BITMASK => { @@ -9512,6 +9633,405 @@ my %noYes = ( 0 => 'No', 1 => 'Yes' ); }, ); +# Z9 custom settings (ref 1) #base at offset26 + 1035 (firmware 1.0.0) +%Image::ExifTool::NikonCustom::SettingsZ9 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + WRITE_PROC => \&Image::ExifTool::WriteBinaryData, + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, + DATAMEMBER => [ 185, 529 ], + WRITABLE => 1, + FIRST_ENTRY => 0, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + NOTES => 'Custom settings for the Z9.', + 1 => { + Name => 'CustomSettingsBank', + PrintConv => { + 0 => 'A', + 1 => 'B', + 2 => 'C', + 3 => 'D', + }, + }, + 3 => { # CSa1 + Name => 'AF-CPrioritySelection', + PrintConv => { + 0 => 'Release', + 1 => 'Release + Focus', + 3 => 'Focus', + }, + }, + 5 => { Name => 'AF-SPrioritySelection', PrintConv => {0 => 'Release',1 => 'Focus'}}, #CSa2 + 7 => { # CSa3-a #when AFAreaMode is 3D-tracking, blocked shot response will be 3, regardless of this setting + Name => 'BlockShotAFResponse', + PrintConv => { + 1 => '1 (Quick)', + 2 => '2', + 3 => '3 (Normal)', + 4 => '4', + 5 => '5 (Delayed)', + }, + }, + 11 => {Name => 'AFPointSel',PrintConv => { 0 => 'Use All',1 => 'Use Half' }}, # CSa4 + 13 => { # CSa5 + Name => 'StoreByOrientation', + PrintConv => { + 0 => 'Off', + 1 => 'Focus Point', + 2 => 'Focus Point and AF-area mode', + }, + }, + 15 => { Name => 'AFActivation', PrintConv => {0 => 'AF-On Only', 1 => 'Shutter/AF-On'}}, # CSa6-a + 16 => { Name => 'AF-OnOutOfFocusRelease', PrintConv => {0 => 'Disable', 1 => 'Enable'}, Unknown => 1}, # CSa6-b + 17 => { Name => 'LimitAF-AreaModeSelPinpoint', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa8 + 19 => { Name => 'LimitAF-AreaModeSelWideAF_S', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa8 + 20 => { Name => 'LimitAF-AreaModeSelWideAF_L', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa8 + 21 => { Name => 'LimitAFAreaModeSelAuto', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa8 #left out hypen to retain compatibility with tag name in NikonSettings + 22 => { Name => 'FocusPointWrap', PrintConv => { 0 => 'No Wrap', 1 => 'Wrap' }, Unknown => 1 }, # CSa10 + 23 => { Name => 'ManualFocusPointIllumination', PrintConv => {0 => 'On During Focus Point Selection Only', 1 => 'On', }, Unknown => 1 }, # CSa11a + 24 => { Name => 'DynamicAreaAFAssist', PrintConv => { 0 => 'Focus Point Only',1 => 'Focus and Surrounding Points',}, Unknown => 1 }, # CSa11b + 25 => { Name => 'AF-AssistIlluminator', PrintConv => \%offOn }, # CSa12 + 26 => { Name => 'ManualFocusRingInAFMode', PrintConv => \%offOn }, # CSa14 + 27 => { Name => 'ExposureControlStepSize', PrintConv => \%thirdHalfFull }, # CSb2 + 29 => { # CSb3 + Name => 'EasyExposureCompensation', + PrintConv => { + 0 => 'Off', + 1 => 'On', + 2 => 'On (auto reset)', + }, + }, + 31 => { # CSb5 + Name => 'CenterWeightedAreaSize', + PrintConv => { + 0 => '8 mm', + 1 => '12 mm', + 4 => 'Average', + }, + }, + 33 => { # CSb6-a + Name => 'FineTuneOptMatrixMetering', + Format => 'int8s', + ValueConv => '$val / 6', + ValueConvInv => 'int($val*6)', + PrintConv => '$val ? sprintf("%+.2f", $val) : 0', + PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', + }, + 35 => { # CSb6-b + Name => 'FineTuneOptCenterWeighted', + Format => 'int8s', + ValueConv => '$val / 6', + ValueConvInv => 'int($val*6)', + PrintConv => '$val ? sprintf("%+.2f", $val) : 0', + PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', + }, + 37 => { # CSb6-c + Name => 'FineTuneOptSpotMetering', + Format => 'int8s', + ValueConv => '$val / 6', + ValueConvInv => 'int($val*6)', + PrintConv => '$val ? sprintf("%+.2f", $val) : 0', + PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', + }, + 39 => { # CSb6-d + Name => 'FineTuneOptHighlightWeighted', + Format => 'int8s', + ValueConv => '$val / 6', + ValueConvInv => 'int($val*6)', + PrintConv => '$val ? sprintf("%+.2f", $val) : 0', + PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', + }, + 41 => { # CSc1 + Name => 'ShutterReleaseButtonAE-L', + PrintConv => { + 0 => 'Off', + 1 => 'On (Half Press)', + 2 => 'On (Burst Mode)', + }, + }, + 43 => { # CSc3-a + Name => 'SelfTimerTime', + PrintConv => { + 0 => '2 s', + 1 => '5 s', + 2 => '10 s', + 3 => '20 s', + }, + }, + 45 => { Name => 'SelfTimerShotCount', }, # CSc3-b 1-9 + 49 => { # CSc3-c + Name => 'SelfTimerShotInterval', + PrintConv => { + 0 => '0.5 s', + 1 => '1 s', + 2 => '2 s', + 3 => '3 s', + }, + }, + 51 => { Name => 'PlaybackMonitorOffTime', PrintConv => \%powerOffDelayTimesZ9 }, # CSc4-a + 53 => { Name => 'MenuMonitorOffTime', PrintConv => \%powerOffDelayTimesZ9 }, # CSc4-b + 55 => { Name => 'ShootingInfoMonitorOffTime',PrintConv => \%powerOffDelayTimesZ9 }, # CSc4-c + 57 => { Name => 'ImageReviewMonitorOffTime', PrintConv => \%powerOffDelayTimesZ9 }, # CSc4-d + 59 => { Name => 'CLModeShootingSpeed', ValueConv => '$val + 1', ValueConvInv => '$val - 1', PrintConv => '"$val fps"', PrintConvInv => '$val=~s/\s*fps//i; $val' }, # CSd1b + 61 => { # CSd2 # values: 1-200 & 'No Limit' + Name => 'MaxContinuousRelease', + Format => 'int16s', + ValueConv => '($val = -1 ? \'No Limit\' : $val ) ', + }, + 65 => { Name => 'SyncReleaseMode', PrintConv => { 0 => 'No Sync', 1 => 'Sync' }, Unknown => 1 }, # CSd4 + 69 => { Name => 'LimitSelectableImageAreaDX', PrintConv => \%limitNolimit, Unknown => 1 }, # CSd6-1 + 70 => { Name => 'LimitSelectableImageArea1To1', PrintConv => \%limitNolimit, Unknown => 1 }, # CSd6-2 + 71 => { Name => 'LimitSelectableImageArea16To9', PrintConv => \%limitNolimit, Unknown => 1 }, # CSd6-3 + 72 => { Name => 'FileNumberSequence', PrintConv => \%offOn }, # CSd7 + 73 => { #CSa13b + Name => 'FocusPeakingLevel', + Unknown => 1, + PrintConv => { + 0 => 'High Sensitivity', + 1 => 'Standard Sensitivity', + 2 => 'Low Sensitivity', + }, + }, + 75 => { #CSa13c + Name => 'FocusPeakingHighlightColor', + Unknown => 1, + PrintConv => { + 0 => 'Red', + 1 => 'Yellow', + 2 => 'Blue', + 3 => 'White', + }, + }, + 81 => { Name => 'ContinuousModeDisplay', PrintConv => \%offOn }, # CSd12 + 83 => { # CSe1-a Previous cameras reported this with HighSpeedSync indicator appended as '(Auto FP)'. Z9 separated the 2 fields. + Name => 'FlashSyncSpeed', + ValueConv => '($val-144)/8', + PrintConv => { + 0 => '1/60 s', + 1 => '1/80 s', + 2 => '1/100 s', + 3 => '1/125 s', + 4 => '1/160 s', + 5 => '1/200 s', + 6 => '1/250 s', + }, + }, + 85 => { Name => 'HighSpeedSync', PrintConv => \%offOn }, # CSe1-b + 87 => { # CSe2 + Name => 'FlashShutterSpeed', + ValueConv => 'my $t = ($val - 16) % 24; $t ? $val / 24 : 2 + ($val - 16) / 24', #unusual decode perhaps due to need to accomodate 4 new values? + PrintConv => { + 0 => '1 s', + 1 => '1/2 s', + 2 => '1/4 s', + 3 => '1/8 s', + 4 => '1/15 s', + 5 => '1/30 s', + 6 => '1/60 s', + 7 => '30 s', + 8 => '15 s', + 9 => '8 s', + 10 => '4 s', + 11 => '2 s', + }, + }, + 89 => { Name => 'FlashExposureCompArea', PrintConv => { 0 => 'Entire Frame', 1 => 'Background Only' } }, # CSe3 + 91 => { Name => 'AutoFlashISOSensitivity', PrintConv => { 0 => 'Subject and Background',1 => 'Subject Only'} }, # CSe4 + 93 => { Name => 'ModelingFlash', PrintConv => \%offOn }, # CSe5 + 95 => { # CSe6 + Name => 'AutoBracketModeM', + PrintConv => { + 0 => 'Flash/Speed', + 1 => 'Flash/Speed/Aperture', + 2 => 'Flash/Aperture', + 3 => 'Flash Only', + 4 => 'Flash/ISO', + }, + }, + 97 => { Name => 'AutoBracketOrder', PrintConv => { 0 => '0,-,+',1 => '-,0,+' } }, # CSe7 + 99 => { Name => 'Func1Button', PrintConv => \%buttonsZ9}, # CSf2-a + #101 Func1Button submenu: Preview 0 => 'Press To Recall', 1=> 'Hold To Recall' # CSf2-a + #103 Func1Button submenu: AreaMode 0-7 => S, Dyn-S, Dyn-M, Dyn-L, Wide-S, Wide-L, 3D, Auto; 11=>n/a # CSf2-a + #105 Func1Button submenu: AreaMode+AF-On 0-7 => S, Dyn-S, Dyn-M, Dyn-L, Wide-S, Wide-L, 3D, Auto; 11=>n/a # CSf2-a + #109 Func1Button submenu: SynchronizedRelease 1=>'Master', 2=>'Remote' # CSf2-a + #111 Func1Button submenu: Zoom 0=>'Zoom (Low)', 2=>'Zoom (1:1)', 2=>'Zoom (High)' # CSf2-a + #113 Func1Button & Func1ButtonPlayback submenu: Rating # CSf2-a & CSf3a 0=>'Candidate For Deletion' 6=>''None' + 115 => { Name => 'Func2Button', PrintConv => \%buttonsZ9}, # CSf2-b + #117 Func2Button submenu: Preview 0 => 'Press To Recall', 1=> 'Hold To Recall' # CSf2-b + #119 Func2Button submenu: AreaMode 0-7 => S, Dyn-S, Dyn-M, Dyn-L, Wide-S, Wide-L, 3D, Auto; 11=>n/a # CSf2-b + #121 Func2Button submenu: AreaMode+AF-On 0-7 => S, Dyn-S, Dyn-M, Dyn-L, Wide-S, Wide-L, 3D, Auto; 11=>n/a # CSf2-b + #125 Func2Button submenu: SynchronizedRelease 1=>'Master', 2=>'Remote' # CSf2-b + #127 Func2Button submenu: Zoom 0=>'Zoom (Low)', 2=>'Zoom (1:1)', 2=>'Zoom (High)' # CSf2-b + #129 Func2Button & Func2ButtonPlayback submenu: Rating # CSf2-b & CSf3b 0=>'Candidate For Deletion' 6=>''None' + 131 => { Name => 'AFOnButton', PrintConv => \%buttonsZ9}, # CSf2-c + 143 => { Name => 'SubSelector', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf2-g + 155 => { Name => 'AssignMovieRecordButton', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf2-m + 159 => { Name => 'LensFunc1Button', PrintConv => \%buttonsZ9}, # CSf2-o + 167 => { Name => 'LensFunc2Button', PrintConv => \%buttonsZ9}, # CSf2-p + 173 => { # CSf2-q + Name => 'LensControlRing', + PrintConv => { + 0 => 'None (Disabled)', + 1 => 'Focus (M/A)', + 2 => 'ISO Sensitivity', + 3 => 'Exposure Compensation', + 4 => 'Aperture', + }, + }, + 175 => { Name => 'MultiSelectorShootMode', PrintConv => \%buttonsZ9}, # CSf2-h called the OK button in camera, tag name retained for compatibility + 179 => { Name => 'MultiSelectorPlaybackMode', PrintConv => \%buttonsZ9}, # CSf3f + 183 => { Name => 'ShutterSpeedLock', PrintConv => \%offOn }, # CSf4-a + 184 => { Name => 'ApertureLock', PrintConv => \%offOn }, # CSf4-b + 185 => { # CSf5-a Previous cameras reported this tag as part of CmdDialsReverseRotation. Blend with CSf5-b separate settings together to match extant tag name and values + Name => 'CmdDialsReverseRotExposureComp', + RawConv => '$$self{CmdDialsReverseRotExposureComp} = $val', + Hidden => 1, + }, + 186 => [{ # CSf5-a (continued from above) + Name => 'CmdDialsReverseRotation', + Condition => '$$self{CmdDialsReverseRotExposureComp} == 0', + PrintConv => { + 0 => 'No', + 1 => 'Shutter Speed & Aperture', + }, + },{ + Name => 'CmdDialsReverseRotation', + PrintConv => { + 0 => 'Exposure Compensation', + 1 => 'Exposure Compensation, Shutter Speed & Aperture', + }, + }], + 191 => { Name => 'UseDialWithoutHold', PrintConv => \%offOn, Unknown => 1 }, # CSf6 + 193 => { Name => 'ReverseIndicators', PrintConv => { 0 => '+ 0 -', 1 => '- 0 +' }, Unknown => 1 }, # CSf7 + 195 => { Name => 'MovieFunc1Button', PrintConv => \%buttonsZ9}, # CSg2-a + 203 => { Name => 'MovieAF-OnButton', PrintConv => \%buttonsZ9}, # CSg2-f + 217 => { Name => 'MovieMultiSelector', PrintConv => \%buttonsZ9, Unknown => 1}, # CSg2-h + 221 => { Name => 'MovieAFSpeed', ValueConv => '$val - 5', ValueConvInv => '$val + 6' }, # CSg6-a + 223 => { Name => 'MovieAFSpeedApply', rintConv => {0 => 'Always', 1 => 'Only During Recording'},}, # CSg6-b + 225 => { # CSg7 + Name => 'MovieAFTrackingSensitivity', + PrintConv => { + 0 => '1 (High)', + 1 => '2', + 2 => '3', + 3 => '4 (Normal)', + 4 => '5', + 5 => '6', + 6 => '7 (Low)', + }, + }, + 257 => { Name => 'LCDIllumination', PrintConv => \%offOn, Unknown => 1 }, # CSd11 + 258 => { Name => 'ExtendedShutterSpeeds', PrintConv => \%offOn }, # CSd5 + 259 => { Name => 'SubjectMotion', PrintConv => {0 => 'Erratic', 1 => 'Steady'} }, # CSa3-b + 261 => { Name => 'FocusPointPersistence', PrintConv => {0 => 'Auto', 1 => 'Off'} }, # CSa7 + 263 => { Name => 'AutoFocusModeRestrictions', PrintConv => \%focusModeRestrictionsZ9, Unknown => 1}, # CSa9 + 267 => { Name => 'CHModeShootingSpeed', ValueConv => '$val + 1', ValueConvInv => '$val - 1', PrintConv => '"$val fps"', PrintConvInv => '$val=~s/\s*fps//i; $val' }, # CSd1a + 269.1 => { Name => 'LimitReleaseModeSelCL', Mask => 0x02, PrintConv => \%limitNolimit, Unknown => 1 }, # CSd3-a + 269.2 => { Name => 'LimitReleaseModeSelCH', Mask => 0x04, PrintConv => \%limitNolimit, Unknown => 1 }, # CSd3-b + 269.3 => { Name => 'LimitReleaseModeSelC30', Mask => 0x10, PrintConv => \%limitNolimit, Unknown => 1 }, # CSd3-e + 269.4 => { Name => 'LimitReleaseModeSelC120', Mask => 0x40, PrintConv => \%limitNolimit, Unknown => 1 }, # CSd3-c + 269.5 => { Name => 'LimitReleaseModeSelSelf', Mask => 0x80, PrintConv => \%limitNolimit, Unknown => 1 }, # CSd3-d + 273 => { Name => 'FlashBurstPriority', PrintConv => { 0 => 'Frame Rate',1 => 'Exposure'}, Unknown => 1 }, # CSe8 + 277 => { Name => 'VerticalFuncButton', PrintConv => \%buttonsZ9}, # CSf2-c + 281 => { Name => 'Func3Button', PrintConv => \%buttonsZ9}, # CSf2-c + 285 => { Name => 'VerticalAFOnButton', PrintConv => \%buttonsZ9}, # CSf2-l + 293 => { Name => 'VerticalMultiSelectorPlaybackMode', PrintConv => { 0 => 'Image Scroll L/R', 1 => 'Image Scroll Up/Down' }, Unknown => 1}, # CSf3-j + 295 => { Name => 'MovieFunc3Button', PrintConv => \%buttonsZ9}, # CSg2-c + 335 => { Name => 'LimitAF-AreaModeSelDynamic_S', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa8 + 336 => { Name => 'LimitAF-AreaModeSelDynamic_M', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa8 + 337 => { Name => 'LimitAF-AreaModeSelDynamic_L', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa8 + 339 => { Name => 'LimitAF-AreaModeSel3DTracking', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa8 + 341 => { Name => 'PlaybackFlickUp', PrintConv => \%flicksZ9, Unknown => 1}, # CSf11-a + 345 => { Name => 'PlaybackFlickDown', PrintConv => \%flicksZ9, Unknown => 1}, # CSf11-b + 349 => { Name => 'ISOStepSize', PrintConv => \%thirdHalfFull }, # CSb1 + 355 => { Name => 'ReverseFocusRing', PrintConv => { 0 => 'Not Reversed', 1 => 'Reversed' } }, # CSf8 + 356 => { Name => 'EVFImageFrame', PrintConv => \%offOn, Unknown => 1 }, # CSd14 + 357 => { Name => 'EVFGrid', PrintConv => \%evfGridsZ9, Unknown => 1 }, # CSd15 + 359 => { Name => 'VirtualHorizonStyle', PrintConv => {0 => 'Type A (Cockpit)', 1 => 'Type B (Sides)' }, Unknown => 1}, #CSd16 + 373 => { Name => 'Func4Button', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf2-e + 379 => { Name => 'AudioButton', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf2-i + 381 => { Name => 'QualityButton', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf2-j + 399 => { Name => 'VerticalMultiSelector', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf2-k + 421 => { Name => 'Func1ButtonPlaybackMode', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf3-a + 423 => { Name => 'Func2ButtonPlaybackMode', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf3-b + 425 => { Name => 'Func3ButtonPlaybackMode', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf3-c + 431 => { Name => 'Func4ButtonPlaybackMode', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf3-e + 437 => { Name => 'MovieRecordButtonPlaybackMode', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf3-m + 439 => { Name => 'VerticalFuncButtonPlaybackMode', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf3-d + 441 => { Name => 'AudioButtonPlaybackMode', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf3-g + 447 => { Name => 'QualityButtonPlaybackMode', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf3-h + 467 => { Name => 'FocusPointLock', PrintConv => \%offOn, Unknown => 1}, # CSf4-c + 453 => { Name => 'WhiteBalanceButtonPlaybackMode', PrintConv => \%buttonsZ9, Unknown => 1}, # CSf3-i + 459 => { Name => 'CommandDialPlaybackMode', PrintConv => \%dialsZ9, Unknown => 1}, # CSf3-k + 463 => { Name => 'SubCommandDialPlaybackMode', PrintConv => \%dialsZ9, Unknown => 1}, # CSf3-l + 469 => { Name => 'ControlRingResponse', PrintConv => { 0 => 'High', 1 => 'Low' } }, # CSf10 + 481 => { Name => 'VerticalMovieFuncButton', PrintConv => \%buttonsZ9, Unknown => 1}, # CSg2-d + 505 => { Name => 'VerticalMovieAFOnButton', PrintConv => \%buttonsZ9, Unknown => 1}, # CSg2-l + 515 => { Name => 'MovieAFAreaMode', PrintConv => \%buttonsZ9, Unknown => 1}, # CSg2-e + #521 => { Name => 'MovieLimitAF-AreaModeSelWideAF_S', PrintConv => \%limitNolimit, Unknown => 1 }, # CSg4-a + #522 => { Name => 'MovieLimitAF-AreaModeSelWideAF_W', PrintConv => \%limitNolimit, Unknown => 1 }, # CSg4-b + #523 => { Name => 'MovieLimitAF-AreaModeSelSubjectTrack', PrintConv => \%limitNolimit, Unknown => 1 }, # CSg4-c + #524 => { Name => 'MovieLimitAFAreaModeSelAuto', PrintConv => \%limitNolimit, Unknown => 1 }, # CSg4-d + #525 => { Name => 'MovieAutoFocusModeRestrictions', PrintConv => \%focusModeRestrictionsZ9, Unknown => 1}, # CSa9 + 527 => { Name => 'HDMIViewAssist', PrintConv => \%offOn, Unknown => 1 }, # CSg8 + 529 => { # CSg9-a + Name => 'ZebraPatternToneRange', + Unknown => 1, + RawConv => '$$self{ZebraPatternToneRange} = $val', + PrintConv => { + 0 => 'Off', + 1 => 'Highlights', + 2 => 'Midtones', + }, + }, + 531 => { Name => 'MovieZebraPattern', Condition => '$$self{ZebraPatternToneRange} and $$self{ZebraPatternToneRange} != 0', PrintConv => {0 => 'Pattern 1', 1 => 'Pattern 2'}, Unknown => 1}, # CSg9-b + 533 => { Name => 'MovieHighlightDisplayThreshold', Condition => '$$self{ZebraPatternToneRange} and $$self{ZebraPatternToneRange} == 1', Unknown => 1 }, # CSg9-c 120-25 when highlights are the selected tone range + 535 => { Name => 'MovieMidtoneDisplayValue', Condition => '$$self{ZebraPatternToneRange} and $$self{ZebraPatternToneRange} == 2', Unknown => 1 }, # CSg9-d1 when midtones are the selected tone range + 537 => { Name => 'MovieMidtoneDisplayRange', Condition => '$$self{ZebraPatternToneRange} and $$self{ZebraPatternToneRange} == 2', PrintConv => '"+/-$val"', Unknown => 1 }, # CSg9-d1 when midtones are the selected tone range + #539 CS g-10 LimitZebraPatternToneRange 0=>'No Restrictions', 1=> 'Highlights', 2=> 'Midtones' + 541 => { Name => 'MovieEVFGrid', PrintConv => \%evfGridsZ9, Unknown => 1 }, # CSg11 + 549 => { Name => 'MovieShutterSpeedLock', PrintConv => \%offOn, Unknown => 1}, # CSg4-a + 550 => { Name => 'MovieFocusPointLock', PrintConv => \%offOn, Unknown => 1}, # CSf4-c + 563 => { Name => 'MatrixMetering', PrintConv => { 0 => 'Face Detection Off', 1 => 'Face Detection On' }, Unknown => 1 }, # CSb4 + 564 => { Name => 'AF-CFocusDisplay', PrintConv => \%offOn }, # CSa11c + 565 => { Name => 'FocusPeakingDisplay', PrintConv => \%offOn, Unknown => 1}, # CSa13a + 567 => { # CSb7 + Name => 'KeepExposure', + PrintConv => { + 0 => 'Off', + 1 => 'Shutter Speed', + 2 => 'ISO', + }, + }, + #569 CDd8 (adjust viewfinder/monitor hue, brightness and/or white balance settings) 0=>'No adjustment', 1=>'Adjust'. Related ontrols & adjustments stored in following dozen bytes or so. + 585 => { Name => 'StarlightView', PrintConv => \%offOn, Unknown => 1 }, # CSd9 + 587 => { # CSd10-a + Name => 'EVFWarmDisplayMode', + Unknown => 1, + PrintConv => { + 0 => 'Off', + 1 => 'Mode 1', + 2 => 'Mode 2', + }, + }, + 589 => { # CSd10-b values in range -3 to +3 + Name => 'EVFWarmDisplayBrightness', + Format => 'int8s', + Unknown => 1, + }, + 591 => { #CSd13 + Name => 'EVFReleaseIndicator', + Unknown => 1, + PrintConv => { + 0 => 'Off', + 1 => 'Type A (Dark)', + 2 => 'Type B (Border)', + 3 => 'Type C (Sides)', + }, + }, + 601 => { Name => 'MovieApertureLock', PrintConv => \%offOn, Unknown => 1 }, # CSg4-b + 607 => { Name => 'FlickAdvanceDirection', PrintConv => { 0 => 'Left to Right', 1 => 'Right to Left' }, Unknown => 1 }, # CSf11-c +); + 1; # end __END__ @@ -9534,16 +10054,16 @@ this information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 ACKNOWLEDGEMENTS -Thanks to Jens Duttke and Warren Hatch for their help decoding the D300 and -D3 custom settings. And thanks to the customer service personnel at Best -Buy for not bugging me while I spent lots of time playing with their +Thanks to Jens Duttke and Warren Hatch for their help decoding the D300, D3 +and Z9 custom settings. And thanks to the customer service personnel at +Best Buy for not bugging me while I spent lots of time playing with their cameras. =head1 SEE ALSO diff --git a/src/Image-ExifTool/lib/Image/ExifTool/NikonSettings.pm b/src/Image-ExifTool/lib/Image/ExifTool/NikonSettings.pm new file mode 100644 index 00000000..8621a9cc --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/NikonSettings.pm @@ -0,0 +1,2093 @@ +#------------------------------------------------------------------------------ +# File: NikonSettings.pm +# +# Description: Read Nikon user settings +# +# Revisions: 2021/01/08 - Warren Hatch Created +# 2021/01/12 - PH Created ProcessNikonSettings() to extract tags +# by ID instead of using fixed offsets +# +# References: 1) Warren Hatch private communication (D6 and Z7_2) +# +#------------------------------------------------------------------------------ + +package Image::ExifTool::NikonSettings; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.07'; + +sub ProcessNikonSettings($$$); + +my %enableDisable = ( 1 => 'Enable', 2 => 'Disable' ); + +my %funcButtonZ7m2 = ( + 1 => 'AF-On', + 2 => 'AF Lock Only', + 3 => 'AE Lock (hold)', + 4 => 'AE Lock (reset on release)', + 5 => 'AE Lock Only', + 6 => 'AE/AF Lock', + 7 => 'FV Lock', + 8 => 'Flash Disable/Enable', + 9 => 'Preview', + 10 => 'Matrix Metering', + 11 => 'Center-weighted Metering', + 12 => 'Spot Metering', + 13 => 'Highlight-weighted Metering', + 14 => 'Bracketing Burst', + 15 => 'Synchronized Release (Master)', + 16 => 'Synchronized Release (Remote)', # no settings map to 17 or 18 + 19 => '+NEF(RAW)', + 20 => 'Subject Tracking', + 21 => 'Silent Photography', + 22 => 'LiveView Info Display On/Off', + 23 => 'Grid Display', + 24 => 'Zoom (Low)', + 25 => 'Zoom (1:1)', + 26 => 'Zoom (High)', + 27 => 'My Menu', + 28 => 'My Menu Top Item', + 29 => 'Playback', + 30 => 'Protect', + 31 => 'Image Area', + 32 => 'Image Quality', + 33 => 'White Balance', + 34 => 'Picture Control', + 35 => 'Active-D Lighting', + 36 => 'Metering', + 37 => 'Flash Mode', + 38 => 'Focus Mode', + 39 => 'Auto Bracketing', + 40 => 'Multiple Exposure', + 41 => 'HDR', + 42 => 'Exposure Delay Mode', + 43 => 'Shutter/Aperture Lock', + 44 => 'Focus Peaking', + 45 => 'Rating 0', + 46 => 'Rating 5', + 47 => 'Rating 4', + 48 => 'Rating 3', + 49 => 'Rating 2', + 50 => 'Rating 1', # no settings map to x'51 (possibly intended for 'Candidate for Delection' + 52 => 'Non-CPU Lens', + 52 => 'None', +); + +my %flickUpDownD6 = ( + 1 => 'Rating', + 2 => 'Select To Send', + 3 => 'Protect', + 4 => 'Voice Memo', + 5 => 'None', +); + +my %flickUpDownRatingD6 = ( + 1 => 'Rating 5', + 2 => 'Rating 4', + 3 => 'Rating 3', + 4 => 'Rating 2', + 5 => 'Rating 1', + 6 => 'Candidate for Deletion', +); + +my %groupAreaCustom = ( + 1 => '1x7', + 2 => '1x5', + 3 => '3x7', + 4 => '3x5', + 5 => '3x3', + 6 => '5x7', + 7 => '5x5', + 8 => '5x3', + 9 => '5x1', + 10 => '7x7', + 11 => '7x5', + 12 => '7x3', + 13 => '7x1', + 14 => '11x3', + 15 => '11x1', + 16 => '15x3', + 17 => '15x1', +); + +my %iSOAutoHiLimitD6 = ( + 1 => 'ISO 200', + 2 => 'ISO 250', + 3 => 'ISO 280', + 4 => 'ISO 320', + 5 => 'ISO 400', + 6 => 'ISO 500', + 7 => 'ISO 560', + 8 => 'ISO 640', + 9 => 'ISO 800', + 10 => 'ISO 1000', + 11 => 'ISO 1100', + 12 => 'ISO 1250', + 13 => 'ISO 1600', + 14 => 'ISO 2000', + 15 => 'ISO 2200', + 16 => 'ISO 2500', + 17 => 'ISO 3200', + 18 => 'ISO 4000', + 19 => 'ISO 4500', + 20 => 'ISO 5000', + 21 => 'ISO 6400', + 22 => 'ISO 8000', + 23 => 'ISO 9000', + 24 => 'ISO 10000', + 25 => 'ISO 12800', + 26 => 'ISO 16000', + 27 => 'ISO 18000', + 28 => 'ISO 20000', + 29 => 'ISO 25600', + 30 => 'ISO 32000', + 31 => 'ISO 36000', + 32 => 'ISO 40000', + 33 => 'ISO 51200', + 34 => 'ISO 64000', + 35 => 'ISO 72000', + 36 => 'ISO 81200', + 37 => 'ISO 102400', + 38 => 'ISO Hi 0.3', + 39 => 'ISO Hi 0.5', + 40 => 'ISO Hi 0.7', + 41 => 'ISO Hi 1.0', + 42 => 'ISO Hi 2.0', + 43 => 'ISO Hi 3.0', + 44 => 'ISO Hi 4.0', + 45 => 'ISO Hi 5.0', +); + +my %iSOAutoHiLimitZ7 = ( + 1 => 'ISO 100', + 2 => 'ISO 125', + 4 => 'ISO 160', + 5 => 'ISO 200', + 6 => 'ISO 250', + 8 => 'ISO 320', + 9 => 'ISO 400', + 10 => 'ISO 500', + 12 => 'ISO 640', + 13 => 'ISO 800', + 14 => 'ISO 1000', + 16 => 'ISO 1250', + 17 => 'ISO 1600', + 18 => 'ISO 2000', + 20 => 'ISO 2500', + 21 => 'ISO 3200', + 22 => 'ISO 4000', + 24 => 'ISO 5000', + 25 => 'ISO 6400', + 26 => 'ISO 8000', + 28 => 'ISO 10000', + 29 => 'ISO 12800', + 30 => 'ISO 16000', + 32 => 'ISO 20000', + 33 => 'ISO 25600', + 38 => 'ISO Hi 0.3', + 39 => 'ISO Hi 0.5', + 40 => 'ISO Hi 0.7', + 41 => 'ISO Hi 1.0', + 42 => 'ISO Hi 2.0', +); + +my %lensFuncButtonZ7m2 = ( + 1 => 'AF-On', + 2 => 'AF Lock Only', + 3 => 'AE Lock (hold)', + 4 => 'AE Lock (reset on release)', + 5 => 'AE Lock Only', + 6 => 'AE/AF Lock', + 7 => 'FV Lock', + 8 => 'Flash Disable/Enable', + 9 => 'Preview', + 10 => 'Matrix Metering', + 11 => 'Center-weighted Metering', + 12 => 'Spot Metering', + 13 => 'Highlight-weighted Metering', + 14 => 'Bracketing Burst', + 15 => 'Synchronized Release (Master)', + 16 => 'Synchronized Release (Remote)', # no settings map to 17 or 18 (Z7II fw 1.01) + 19 => '+NEF(RAW)', + 20 => 'Subject Tracking', + 21 => 'Grid Display', + 22 => 'Zoom (Low)', + 23 => 'Zoom (1:1)', + 24 => 'Zoom (High)', + 25 => 'My Menu', + 26 => 'My Menu Top Item', + 27 => 'Playback', + 28 => 'None', +); + +my %limitNolimit = ( 1 => 'Limit', 2 => 'No Limit' ); + +my %limtReleaseModeSel = ( + 0 => 'No Limit', # not sure why 0 and 2 both map to 'No Limit', but they do + 1 => 'Limit', + 2 => 'No Limit', +); + +my %menuBank = ( + 1 => 'A', + 2 => 'B', + 3 => 'C', + 4 => 'D', +); + +my %noYes = ( 1 => 'No', 2 => 'Yes' ); +my %offOn = ( 1 => 'Off', 2 => 'On' ); +my %onOff = ( 1 => 'On', 2 => 'Off' ); + +my %previewButtonD6 = ( + 1 => 'Preset Focus Point - Press To Recall', + 2 => 'Preset Focus Point - Hold To Recall', + 3 => 'AF-AreaMode S', + 4 => 'AF-AreaMode D9', + 5 => 'AF-AreaMode D25', + 6 => 'AF-AreaMode D49', + 7 => 'AF-AreaMode D105', + 8 => 'AF-AreaMode 3D', + 9 => 'AF-AreaMode Group', + 10 => 'AF-AreaMode Group C1', + 11 => 'AF-AreaMode Group C2', + 12 => 'AF-AreaMode Auto Area', + 13 => 'AF-AreaMode + AF-On S', + 14 => 'AF-AreaMode + AF-On D9', + 15 => 'AF-AreaMode + AF-On D25', + 16 => 'AF-AreaMode + AF-On D49', + 17 => 'AF-AreaMode + AF-On D105', + 18 => 'AF-AreaMode + AF-On 3D', + 19 => 'AF-AreaMode + AF-On Group', + 20 => 'AF-AreaMode + AF-On Group C1', + 21 => 'AF-AreaMode + AF-On Group C2', + 22 => 'AF-AreaMode + AF-On Auto Area', + 23 => 'AF-On', + 24 => 'AF Lock Only', + 25 => 'AE Lock (hold)', + 26 => 'AE/WB Lock (hold)', + 27 => 'AE Lock (reset on release)', + 28 => 'AE Lock Only', + 29 => 'AE/AF Lock', + 30 => 'FV Lock', + 31 => 'Flash Disable/Enable', + 32 => 'Preview', + 33 => 'Recall Shooting Functions', + 34 => 'Bracketing Burst', + 35 => 'Synchronized Release (Master)', + 36 => 'Synchronized Release (Remote)', # no settings map to 37 or 38 + 39 => '+NEF(RAW)', + 40 => 'Grid Display', + 41 => 'Virtual Horizon', + 42 => 'Voice Memo', + 43 => 'Wired LAN', + 44 => 'My Menu', + 45 => 'My Menu Top Item', + 46 => 'Playback', + 47 => 'Filtered Playback', + 48 => 'Photo Shooting Bank', + 49 => 'AF Mode/AF Area Mode', + 50 => 'Image Area', + 51 => 'Active-D Lighting', + 52 => 'Exposure Delay Mode', + 53 => 'Shutter/Aperture Lock', + 54 => '1 Stop Speed/Aperture', + 55 => 'Non-CPU Lens', + 56 => 'None', +); + +my %releaseFocus = ( + 1 => 'Release', + 2 => 'Focus', +); + +my %tagMultiSelector = ( + 1 => 'Restart Standby Timer', + 2 => 'Do Nothing', +); + +my %tagSecondarySlotFunction = ( + 1 => 'Overflow', + 2 => 'Backup', + 3 => 'NEF Primary + JPG Secondary', + 4 => 'JPG Primary + JPG Secondary', +); + +my %tagSubSelector = ( + 1 => 'Same as MultiSelector', + 2 => 'Focus Point Selection', +); + +my %thirdHalfFull = ( + 1 => '1/3 EV', + 2 => '1/2 EV', + 3 => '1 EV', +); + +my %times4s10s20s1m5m20m = ( + 1 => '4 s', + 2 => '10 s', + 3 => '20 s', + 4 => '1 min', + 5 => '5 min', + 6 => '10 min', +); + +my %yesNo = ( 1 => 'Yes', 2 => 'No' ); + +my %infoD6 = ( + Condition => '$$self{Model} =~ /^NIKON D6\b/i', + Notes => 'D6', +); + +my %infoZ7 = ( + Condition => '$$self{Model} =~ /^NIKON Z (7|7_2)\b/i', + Notes => 'Z7 and Z7_2', +); + +my %infoZSeries = ( + Condition => '$$self{Model} =~ /^NIKON Z (5|50|6|6_2|7|7_2|fc)\b/i', + Notes => 'Z Series cameras thru November 2021', +); + +# Nikon Settings tags (ref 1, tag ID's ref PH) +%Image::ExifTool::NikonSettings::Main = ( + PROCESS_PROC => \&ProcessNikonSettings, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + NOTES => q{ + User settings for newer Nikon models. A number of the tags are marked as + Unknown only to reduce the volume of the normal output. + }, + 0x001 => [{ + Name => 'ISOAutoHiLimit', + PrintConv => \%iSOAutoHiLimitD6, + %infoD6, + },{ + Name => 'ISOAutoHiLimit', + PrintConv => \%iSOAutoHiLimitZ7, + %infoZ7, + }], + 0x002 => [{ + Name => 'ISOAutoFlashLimit', + PrintConv => { + 1 => 'Same As Without Flash', + 2 => 'ISO 200', + 3 => 'ISO 250', + 5 => 'ISO 320', + 6 => 'ISO 400', + 7 => 'ISO 500', + 9 => 'ISO 640', + 10 => 'ISO 800', + 11 => 'ISO 1000', + 13 => 'ISO 1250', + 14 => 'ISO 1600', + 15 => 'ISO 2000', + 17 => 'ISO 2500', + 18 => 'ISO 3200', + 19 => 'ISO 4000', + 21 => 'ISO 5000', + 22 => 'ISO 6400', + 23 => 'ISO 8000', + 25 => 'ISO 10000', + 26 => 'ISO 12800', + 27 => 'ISO 16000', + 29 => 'ISO 20000', + 30 => 'ISO 25600', + 31 => 'ISO 32000', + 33 => 'ISO 40000', + 34 => 'ISO 51200', + 35 => 'ISO 64000', + 36 => 'ISO 72000', + 37 => 'ISO 81200', + 38 => 'ISO 102400', + 39 => 'ISO Hi 0.3', + 40 => 'ISO Hi 0.5', + 41 => 'ISO Hi 0.7', + 42 => 'ISO Hi 1.0', + 43 => 'ISO Hi 2.0', + 44 => 'ISO Hi 3.0', + 45 => 'ISO Hi 4.0', + 46 => 'ISO Hi 5.0', + }, + %infoD6, + },{ + Name => 'ISOAutoFlashLimit', + PrintConv => { + 1 => 'Same As Without Flash', + 2 => 'ISO 100', + 3 => 'ISO 125', + 5 => 'ISO 160', + 6 => 'ISO 200', + 7 => 'ISO 250', + 9 => 'ISO 320', + 10 => 'ISO 400', + 11 => 'ISO 500', + 13 => 'ISO 640', + 14 => 'ISO 800', + 15 => 'ISO 1000', + 17 => 'ISO 1250', + 18 => 'ISO 1600', + 19 => 'ISO 2000', + 21 => 'ISO 2500', + 22 => 'ISO 3200', + 23 => 'ISO 4000', + 25 => 'ISO 5000', + 26 => 'ISO 6400', + 27 => 'ISO 8000', + 29 => 'ISO 10000', + 30 => 'ISO 12800', + 31 => 'ISO 16000', + 33 => 'ISO 20000', + 34 => 'ISO 25600', + 39 => 'ISO Hi 0.3', + 40 => 'ISO Hi 0.5', + 41 => 'ISO Hi 0.7', + 42 => 'ISO Hi 1.0', + 43 => 'ISO Hi 2.0', + }, + %infoZ7, + }], + 0x003 => { # (D6/Z7_2) + Name => 'ISOAutoShutterTime', + PrintConv => { + 1 => 'Auto (Slowest)', + 2 => 'Auto (Slower)', + 3 => 'Auto', + 4 => 'Auto (Faster)', + 5 => 'Auto (Fastest)', + 6 => '1/4000 s', + 7 => '1/3200 s', + 8 => '1/2500 s', + 9 => '1/2000 s', + 10 => '1/1600 s', + 11 => '1/1250 s', + 12 => '1/1000 s', + 13 => '1/800 s', + 14 => '1/640 s', + 15 => '1/500 s', + 16 => '1/400 s', + 17 => '1/320 s', + 18 => '1/250 s', + 19 => '1/200 s', + 20 => '1/160 s', + 21 => '1/125 s', + 22 => '1/100 s', + 23 => '1/80 s', + 24 => '1/60 s', + 25 => '1/50 s', + 26 => '1/40 s', + 27 => '1/30 s', + 28 => '1/25 s', + 29 => '1/20 s', + 30 => '1/15 s', + 31 => '1/13 s', + 32 => '1/10 s', + 33 => '1/8 s', + 34 => '1/6 s', + 35 => '1/5 s', + 36 => '1/4 s', + 37 => '1/3 s', + 38 => '1/2.5 s', + 39 => '1/2 s', + 40 => '1/1.6 s', + 41 => '1/1.3 s', + 42 => '1 s', + 43 => '1.3 s', + 44 => '1.6 s', + 45 => '2 s', + 46 => '2.5 s', + 47 => '3 s', + 48 => '4 s', + 49 => '5 s', + 50 => '6 s', + 51 => '8 s', + 52 => '10 s', + 53 => '13 s', + 54 => '15 s', + 55 => '20 s', + 56 => '25 s', + 57 => '30 s', + }, + }, + 0x00b => { Name => 'FlickerReductionShooting', PrintConv => \%enableDisable }, # (D6/Z7_2) + 0x00c => { Name => 'FlickerReductionIndicator',PrintConv => \%enableDisable }, # (D6) + 0x00d => [{ + Name => 'MovieISOAutoHiLimit', + PrintConv => \%iSOAutoHiLimitD6, + %infoD6, + },{ + Name => 'MovieISOAutoHiLimit', + PrintConv => { + 1 => 'ISO 200', + 2 => 'ISO 250', + 4 => 'ISO 320', + 5 => 'ISO 400', + 6 => 'ISO 500', + 8 => 'ISO 640', + 9 => 'ISO 800', + 10 => 'ISO 1000', + 12 => 'ISO 1250', + 13 => 'ISO 1600', + 14 => 'ISO 2000', + 16 => 'ISO 2500', + 17 => 'ISO 3200', + 18 => 'ISO 4000', + 20 => 'ISO 5000', + 21 => 'ISO 6400', + 22 => 'ISO 8000', + 24 => 'ISO 10000', + 25 => 'ISO 12800', + 26 => 'ISO 16000', + 28 => 'ISO 20000', + 29 => 'ISO 25600', + 34 => 'ISO Hi 0.3', + 35 => 'ISO Hi 0.5', + 36 => 'ISO Hi 0.7', + 37 => 'ISO Hi 1.0', + 38 => 'ISO Hi 2.0', + }, + %infoZ7, + }], + 0x00e => { Name => 'MovieISOAutoControlManualMode',PrintConv => \%onOff }, # (D6/Z7_2) + 0x00f => { Name => 'MovieWhiteBalanceSameAsPhoto', PrintConv => \%yesNo }, # (D6/Z7_2) + 0x01d => [{ # CSa1 (D6) + Name => 'AF-CPrioritySel', + PrintConv => { # valid for cameras with 4 options for CS1, otherwise 1=Release, 2=Focus + 1 => 'Release', + 2 => 'Release + Focus', + 3 => 'Focus + Release', + 4 => 'Focus', + }, + %infoD6, + },{ # CSa1 (Z7_2) + Name => 'AF-CPrioritySel', + PrintConv => \%releaseFocus, + %infoZSeries, + }], + 0x01e => { Name => 'AF-SPrioritySel', PrintConv => \%releaseFocus }, # CSa2 (D6), CSa2 (Z7_2) + 0x020 => [{ # CSa4 (D6) + Name => 'AFPointSel', + PrintConv => { + 1 => '105 Points', + 2 => '27 Points', + 3 => '15 Points', + }, + %infoD6, + },{ # CSa4 (Z7_2) + Name => 'AFPointSel', + PrintConv => { 1 => 'Use All', 2 => 'Use Half' }, + %infoZSeries, + }], + 0x022 => { Name => 'AFActivation', PrintConv => { 1 => 'Shutter/AF-On', 2 => 'AF-On Only' } }, # CSa6-a (D6/Z7_2) (missing enable/disable out of focus release) # (D6) + 0x023 => { Name => 'FocusPointWrap', PrintConv => { 1 => 'Wrap', 2 => 'No Wrap' } }, # CSa16 (D6), CSa8 (Z7_2) + 0x025 => { # CSa17-a (D6), CSa9-a (Z7_2) + Name => 'ManualFocusPointIllumination', + PrintConv => { + 1 => 'On', + 2 => 'On During Focus Point Selection Only', + }, + }, + 0x026 => { Name => 'AF-AssistIlluminator', PrintConv => \%onOff }, # CSa11 (Z7_2) + 0x027 => { Name => 'ManualFocusRingInAFMode', PrintConv => \%onOff }, # CSa12 (D6,Z7_2) capability documented in manual, but visibility (& ability to test) requires a compatible lens + 0x029 => { Name => 'ISOStepSize', PrintConv => \%thirdHalfFull }, # CSb1 (D6) + 0x02a => { Name => 'ExposureControlStepSize', PrintConv => \%thirdHalfFull }, # CSb2 (D6), CSb1 (Z7_2) + 0x02b => { # CSb4 (D6), CSb2 (Z7_2) + Name => 'EasyExposureCompensation', + PrintConv => { + 1 => 'On (auto reset)', + 2 => 'On', + 3 => 'Off', + }, + }, + 0x02c => { Name => 'MatrixMetering', PrintConv => { 1 => 'Face Detection On', 2 => 'Face Detection Off' } }, # CSb5 (D6) + 0x02d => [{ # CSb6 (D6) + Name => 'CenterWeightedAreaSize', + PrintConv => { + 1 => '8 mm', + 2 => '12 mm', + 3 => '15 mm', + 4 => '20 mm', + 5 => 'Average', + }, + %infoD6 + },{ # CSb3 (Z7_2) + Name => 'CenterWeightedAreaSize', + PrintConv => { 1 => '12 mm', 2 => 'Average' }, + %infoZSeries, + }], + 0x02f => { # CSb7-a (D6), CSb4-a (Z7_2) + Name => 'FineTuneOptMatrixMetering', + ValueConv => '($val - 7) / 6', + ValueConvInv => 'int($val*6+7)', + PrintConv => '$val ? sprintf("%+.2f", $val) : 0', + PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', + }, + 0x030 => { # CSb7-b (D6), CSb4-b (Z7_2) + Name => 'FineTuneOptCenterWeighted', + ValueConv => '($val - 7) / 6', + ValueConvInv => 'int($val*6+7)', + PrintConv => '$val ? sprintf("%+.2f", $val) : 0', + PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', + }, + 0x031 => { # CSb7-c (D6), CSb4-c (Z7_2) + Name => 'FineTuneOptSpotMetering', + ValueConv => '($val - 7) / 6', + ValueConvInv => 'int($val*6+7)', + PrintConv => '$val ? sprintf("%+.2f", $val) : 0', + PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', + }, + 0x032 => { # CSb7-d (D6), CSb4-d (Z7_2) + Name => 'FineTuneOptHighlightWeighted', + ValueConv => '($val - 7) / 6', + ValueConvInv => 'int($val*6+7)', + PrintConv => '$val ? sprintf("%+.2f", $val) : 0', + PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', + }, + 0x033 => { # CSc1 (D6), CSc1 (Z7_2) + Name => 'ShutterReleaseButtonAE-L', + PrintConv => { + 1 => 'On (Half Press)', + 2 => 'On (Burst Mode)', + 3 => 'Off', + }, + }, + 0x034 => [{ # CSc2 (D6) + Name => 'StandbyMonitorOffTime', + PrintConv => { + 1 => '4 s', + 2 => '6 s', + 3 => '10 s', + 4 => '30 s', + 5 => '1 min', + 6 => '5 min', + 7 => '10 min', + 8 => '30 min', + 9 => 'No Limit', + }, + %infoD6, + },{ # CSc4-d (Z7_2) + Name => 'StandbyMonitorOffTime', + PrintConv => { + 1 => '10 s', + 2 => '20 s', + 3 => '30 s', + 4 => '1 min', + 5 => '5 min', + 6 => '10 min', + 7 => '30 min', + 8 => 'No Limit', + }, + %infoZSeries, + }], + 0x035 => { # CSc3-a (D6), CSc2-a (Z7_2) + Name => 'SelfTimerTime', + PrintConv => { + 1 => '2 s', + 2 => '5 s', + 3 => '10 s', + 4 => '20 s', + }, + }, + 0x036 => { Name => 'SelfTimerShotCount', ValueConv => '10 - $val', ValueConvInv => '10 + $val' }, # CSc3-b (D6), CSc2-b (Z7_2) + 0x037 => { # CSc3-c (D6), CSc2-c (Z7_2) + Name => 'SelfTimerShotInterval', + PrintConv => { + 1 => '0.5 s', + 2 => '1 s', + 3 => '2 s', + 4 => '3 s', + }, + }, + 0x038 => { Name => 'PlaybackMonitorOffTime', PrintConv => \%times4s10s20s1m5m20m }, # CSc4-a (D6), CSc3-a (Z7_2) + 0x039 => { Name => 'MenuMonitorOffTime', PrintConv => \%times4s10s20s1m5m20m }, # CSc4-b (D6), CSc3-b (Z7_2) + 0x03a => { Name => 'ShootingInfoMonitorOffTime',PrintConv => \%times4s10s20s1m5m20m }, # CSc4-c (D6) + 0x03b => { # CSc4-d (D6), CSc3-c (Z7_2) + Name => 'ImageReviewMonitorOffTime', + PrintConv => { + 1 => '2 s', + 2 => '4 s', + 3 => '10 s', + 4 => '20 s', + 5 => '1 min', + 6 => '5 min', + 7 => '10 min', + }, + }, + 0x03c => { # CSc4-e (D6) + Name => 'LiveViewMonitorOffTime', + PrintConv => { + 1 => '5 min', + 2 => '10 min', + 3 => '15 min', + 4 => '20 min', + 5 => '30 min', + 6 => 'No Limit', + }, + }, + 0x03e => { Name => 'CLModeShootingSpeed', ValueConv => '6 - $val', ValueConvInv => '6 + $val', PrintConv => '"$val fps"', PrintConvInv => '$val=~s/\s*fps//i; $val' }, # CSd1 (Z7_2) + 0x03f => { Name => 'MaxContinuousRelease' }, # CSd2 # values: 1-200 # (D6/Z7_2) + 0x040 => { # CSd5 (D6), CSd4 (Z7_2) + Name => 'ExposureDelayMode', + PrintConv => { + 1 => '3 s', + 2 => '2 s', + 3 => '1 s', + 4 => '0.5 s', + 5 => '0.2 s', + 6 => 'Off', + }, + }, + 0x041 => { Name => 'ElectronicFront-CurtainShutter',PrintConv => \%onOff }, # CSd6 (D6) + 0x042 => { Name => 'FileNumberSequence', PrintConv => \%onOff }, # CSd9 (D6), CSd8 (Z7_2) + 0x043 => { Name => 'FramingGridDisplay', PrintConv => \%onOff }, # CSd11 (D6), CSd10 (Z7_2), new tag with implementation of NikonSettings # (Z7_2) + 0x045 => { Name => 'LCDIllumination', PrintConv => \%onOff }, # CSd13 (D6) + 0x046 => { Name => 'OpticalVR', PrintConv => \%onOff }, # CSd15 (D6) + 0x047 => [{ # CSe1 (D6) + Name => 'FlashSyncSpeed', + PrintConv => { + 1 => '1/250 s (auto FP)', + 2 => '1/250 s', + 3 => '1/200 s', + 4 => '1/160 s', + 5 => '1/125 s', + 6 => '1/100 s', + 7 => '1/80 s', + 8 => '1/60 s', + }, + %infoD6, + },{ # CSe1 (Z7_2) + Name => 'FlashSyncSpeed', + PrintConv => { + 1 => '1/200 s (auto FP)', + 2 => '1/200 s', + 3 => '1/160 s', + 4 => '1/125 s', + 5 => '1/100 s', + 6 => '1/80 s', + 7 => '1/60 s', + }, + %infoZSeries, + }], + 0x048 => { # CSe2 (D6/Z7_2) + Name => 'FlashShutterSpeed', + PrintConv => { + 1 => '1/60 s', + 2 => '1/30 s', + 3 => '1/15 s', + 4 => '1/8 s', + 5 => '1/4 s', + 6 => '1/2 s', + 7 => '1 s', + 8 => '2 s', + }, + }, + 0x049 => { Name => 'FlashExposureCompArea', PrintConv => { 1 => 'Entire Frame', 2 => 'Background Only' } }, # CSe3 (D6/Z7_2) + 0x04a => { # CSe4 (D6/Z7_2) + Name => 'AutoFlashISOSensitivity', + PrintConv => { + 1 => 'Subject and Background', + 2 => 'Subject Only', + }, + }, + 0x051 => { # CSf3-l (D6) + Name => 'AssignBktButton', + PrintConv => { + 1 => 'Auto Bracketing', + 2 => 'Multiple Exposure', + 3 => 'HDR (high dynamic range)', + 4 => 'None', + }, + }, + 0x052 => [{ # CSf3-m (D6) + Name => 'AssignMovieRecordButton', + PrintConv => { + 1 => 'Voice Memo', + 2 => 'Photo Shooting Bank', + 3 => 'Exposure Mode', + 4 => 'AF Mode/AF Area Mode', + 5 => 'Image Area', + 6 => 'Shutter/Aperture Lock', + 7 => 'None', + }, + %infoD6, + },{ # CSf2-f (Z7_2) + Name => 'AssignMovieRecordButton', + PrintConv => { + 1 => 'AE Lock (hold)', + 2 => 'AE Lock (reset on release)', + 3 => 'Preview', + 4 => '+NEF(RAW)', + 5 => 'LiveView Info Display On/Off', + 6 => 'Grid Display', + 7 => 'Zoom (Low)', + 8 => 'Zoom (1:1)', + 9 => 'Zoom (High)', + 10 => 'My Menu', + 11 => 'My Menu Top Item', + 12 => 'Image Area', + 13 => 'Image Quality', + 14 => 'White Balance', + 15 => 'Picture Control', + 16 => 'Active-D Lighting', + 17 => 'Metering', + 18 => 'Flash Mode', + 19 => 'Focus Mode', + 20 => 'Auto Bracketing', + 21 => 'Multiple Exposure', + 22 => 'HDR', + 23 => 'Exposure Delay Mode', + 24 => 'Shutter/Aperture Lock', + 25 => 'Non-CPU Lens', + 26 => 'None', + }, + %infoZSeries, + }], + 0x053 => [{ # CSf4-a (D6) + Name => 'MultiSelectorShootMode', + PrintConv => { + 1 => 'Select Center Focus Point', + 2 => 'Preset Focus Point - Press To Recall', + 3 => 'Preset Focus Point - Hold To Recall', + 4 => 'None', + }, + %infoD6, + },{ # CSf3-a (Z7_2) also called the OK button on this camera + Name => 'MultiSelectorShootMode', + PrintConv => { + 1 => 'Select Center Focus Point', + 2 => 'Zoom (Low)', + 3 => 'Zoom (1:1)', + 4 => 'Zoom (High)', + 5 => 'None', + }, + %infoZSeries, + }], + 0x054 => [{ # CSf4-c (D6) + Name => 'MultiSelectorPlaybackMode', + PrintConv => { + 1 => 'Filtered Playback', + 2 => 'View Histograms', + 3 => 'Zoom (Low)', + 4 => 'Zoom (1:1)', + 5 => 'Zoom (High)', + 6 => 'Choose Folder', + }, + %infoD6, + },{ # CSf3-b (Z7_2) # these decodes are correct. However, a new camera (or one following a 'reset all settings') will report Zoom (Low), despite the camera exhibiting the expected behavior (Zoom 1:1). Any change to CSf3-b corrects the reporting. + Name => 'MultiSelectorPlaybackMode', + PrintConv => { + 1 => 'Thumbnail On/Off', + 2 => 'View Histograms', + 3 => 'Zoom (Low)', + 4 => 'Zoom (1:1)', + 5 => 'Zoom (High)', + 6 => 'Choose Folder', + }, + %infoZSeries, + }], + 0x056 => { # CSf4-b (D6) + Name => 'MultiSelectorLiveView', + PrintConv => { + 1 => 'Select Center Focus Point', + 2 => 'Zoom (Low)', + 3 => 'Zoom (1:1)', + 4 => 'Zoom (High)', + 5 => 'None', + }, + }, + 0x058 => { # CSf6-a-1 and CSf6-a-2 (D6), CSf5-a-1 and CSf5-a-2 (Z7_2), Previous cameras reported these 2 in a single tag (CmdDialsReverseRotation). Blend the separate settings together to match extant tag name and values + Name => 'CmdDialsReverseRotExposureComp', + RawConv => '$$self{CmdDialsReverseRotExposureComp} = $val', + Unknown => 1, + }, + 0x059 => { # CSf6-b-1 and CSf6-b-2 (D6), CSf5-b-1 and CSf5-b-2 (Z7_2), Previous cameras reported these 2 in a single tag (CmdDialsChangeMainSub). Blend the separate settings together to match extant tag name and values + Name => 'CmdDialsChangeMainSubExposure', + RawConv => '$$self{CmdDialsChangeMainSubExposure} = $val', + Unknown => 1, + }, + 0x05a => [{ # CSf6-b-1 and CSf6-b-2 (D6), CSf5-b-1 and CSf5-b-2 (Z7_2), (continued from above) + Name => 'CmdDialsChangeMainSub', + Condition => '$$self{CmdDialsChangeMainSubExposure} and $$self{CmdDialsChangeMainSubExposure} == 1', + PrintConv => { + 1 => 'Autofocus On, Exposure On', + 2 => 'Autofocus Off, Exposure On', + }, + },{ + Name => 'CmdDialsChangeMainSub', + Condition => '$$self{CmdDialsChangeMainSubExposure} and $$self{CmdDialsChangeMainSubExposure} == 2', + PrintConv => { + 1 => 'Autofocus On, Exposure On (Mode A)', + 2 => 'Autofocus Off, Exposure On (Mode A)', + }, + },{ + Name => 'CmdDialsChangeMainSub', + PrintConv => { + 1 => 'Autofocus On, Exposure Off', + 2 => 'Autofocus Off, Exposure Off', + }, + }], + 0x05b => { Name => 'CmdDialsMenuAndPlayback', PrintConv => { 1 => 'On', 2 => 'On (Image Review Excluded)', 3 => 'Off' } }, # CSf5-c (D6), CSf5-c (Z7_2) + 0x05c => { # CSf6-d (D6), CSf5-d (Z7_2) + Name => 'SubDialFrameAdvance', + PrintConv => { + 1 => '10 Frames', + 2 => '50 Frames', + 3 => 'Rating', + 4 => 'Protect', + 5 => 'Stills Only', + 6 => 'Movies Only', + 7 => 'Folder', + }, + }, + 0x05d => { Name => 'ReleaseButtonToUseDial', PrintConv => \%yesNo }, # CSf8 (D6), CSf6 (Z7_2) + 0x05e => { Name => 'ReverseIndicators', PrintConv => { 1 => '+ 0 -', 2 => '- 0 +' } }, # CSf9 (D6), CSf7 (Z7_2) + 0x062 => { # CSg2-f (D6), CSg2-e (Z7_2) + Name => 'MovieShutterButton', + PrintConv => { + 1 => 'Take Photo', + 2 => 'Record Movie', + }, + }, + 0x063 => { # Settings menu # (D6,Z7_2) + Name => 'Language', + PrintConv => { + 5 => 'English', + 6 => 'Spanish', + 8 => 'French', + 15 => 'Portuguese (Br)', + }, + }, + 0x06c => [{ + Name => 'ShootingInfoDisplay', + PrintConv => { + 1 => 'Auto', + 2 => 'Manual (dark on light)', + 3 => 'Manual (light on dark)', + }, + %infoD6, + },{ + Name => 'ShootingInfoDisplay', + PrintConv => { + 1 => 'Manual (dark on light)', + 2 => 'Manual (light on dark)', + }, + %infoZSeries, + }], + 0x074 => { Name => 'FlickAdvanceDirection', PrintConv => { 1 => 'Right to Left', 2 => 'Left to Right' } }, # CSf12-3 (D6) + 0x075 => { # Settings menu # (D6,Z7_2) + Name => 'HDMIOutputResolution', + PrintConv => { + 1 => 'Auto', + 2 => '2160p', + 3 => '1080p', + 4 => '1080i', + 5 => '720p', + 6 => '576p', + 7 => '480p', + }, + }, + 0x077 => { # Settings menu # (D6,Z7_2) + Name => 'HDMIOutputRange', + PrintConv => { + 1 => 'Auto', + 2 => 'Limit', + 3 => 'Full', + }, + }, + 0x080 => [{ + Name => 'RemoteFuncButton', + PrintConv => { + 1 => 'AF-On', + 2 => 'AF Lock Only', + 3 => 'AE Lock (reset on release)', + 4 => 'AE Lock Only', + 5 => 'AE/AF Lock', + 6 => 'FV Lock', + 7 => 'Flash Disable/Enable', + 8 => 'Preview', + 9 => '+NEF(RAW)', + 10 => 'LiveView Info Display On/Off', + 11 => 'Recall Shooting Functions', + 12 => 'None', + }, + %infoD6, + },{ + Name => 'RemoteFuncButton', + PrintConv => { + 1 => 'AF-On', + 2 => 'AF Lock Only', + 3 => 'AE Lock (reset on release)', + 4 => 'AE Lock Only', + 5 => 'AE/AF Lock', + 6 => 'FV Lock', + 7 => 'Flash Disable/Enable', + 8 => 'Preview', + 9 => '+NEF(RAW)', + 10 => 'None', + 11 => 'LiveView Info Display On/Off', + }, + %infoZSeries, + }], + 0x08b => [{ # CSf6-a-1 and CSf6-a-2 (D6), CSf5-a-1 and CSf5-a-2 (Z7_2), (continued from above) + Name => 'CmdDialsReverseRotation', + Condition => '$$self{CmdDialsReverseRotExposureComp} and $$self{CmdDialsReverseRotExposureComp} == 1', + PrintConv => { + 1 => 'No', + 2 => 'Shutter Speed & Aperture', + }, + },{ + Name => 'CmdDialsReverseRotation', + PrintConv => { + 1 => 'Exposure Compensation', + 2 => 'Exposure Compensation, Shutter Speed & Aperture', + }, + }], + 0x08d => { # CSd10-b (D6), CSd11-b (Z7_2) + Name => 'FocusPeakingHighlightColor', + PrintConv => { + 1 => 'Red', + 2 => 'Yellow', + 3 => 'Blue', + 4 => 'White', + }, + }, + 0x08e => { Name => 'ContinuousModeDisplay', PrintConv => \%onOff }, # CSd14 (D6), CSd12 (Z7_2) + 0x08f => { Name => 'ShutterSpeedLock', PrintConv => \%onOff }, # CSf54-a (D6), CSf4-a (Z7_2) + 0x090 => { Name => 'ApertureLock', PrintConv => \%onOff }, # CSf5-b (D6), CSf4-b (Z7_2 could not select) + 0x091 => { # CSg4-b (D6), CSg6-b (Z7_2) + Name => 'MovieHighlightDisplayThreshold', + PrintConv => { + 1 => '255', + 2 => '248', + 3 => '235', + 4 => '224', + 5 => '213', + 6 => '202', + 7 => '191', + 8 => '180', + }, + }, + 0x092 => { Name => 'HDMIExternalRecorder', PrintConv => \%onOff }, # Settings Menu/HDMI/Advanced entry (D6 & Z7_2) + 0x093 => { # CSa3-a (D6), CSa3 (Z7_2) + Name => 'BlockShotAFResponse', + PrintConv => { + 1 => '1 (Quick)', + 2 => '2', + 3 => '3 (Normal)', + 4 => '4', + 5 => '5 (Delay)', + }, + }, + 0x094 => { Name => 'SubjectMotion', PrintConv => { 1 => 'Erratic', 2 => 'Steady' } }, # CSa3-b (D6) + 0x095 => { Name => 'Three-DTrackingFaceDetection', PrintConv => \%onOff }, # CSa8 (D6) + 0x097 => [{ # CSa5 (D6) + Name => 'StoreByOrientation', + PrintConv => { + 1 => 'Focus Point', + 2 => 'Focus Point and AF-area mode', + 3 => 'Off', + }, + %infoD6, + },{ # CSa5 (Z7_2) + Name => 'StoreByOrientation', + PrintConv => { + 1 => 'Focus Point', + 2 => 'Off', + }, + %infoZSeries, + }], + 0x099 => { Name => 'DynamicAreaAFAssist',PrintConv => \%onOff }, # CSa17-c (D6), CSa9-b (Z7_2) + 0x09a => { Name => 'ExposureCompStepSize', PrintConv => \%thirdHalfFull }, # CSb3 (D6) + 0x09b => { Name => 'SyncReleaseMode', PrintConv => { 1 => 'Sync', 2 => 'No Sync' } }, # CSd4 (D6), CSd3 (Z7_2) + 0x09c => { Name => 'ModelingFlash', PrintConv => \%onOff }, # CSe6 (D6), CSe5 (Z7_2) + 0x09d => { # CSe7 (D6), CSe6 (Z7_2) + Name => 'AutoBracketModeM', + PrintConv => { + 1 => 'Flash/Speed', + 2 => 'Flash/Speed/Aperture', + 3 => 'Flash/Aperture', + 4 => 'Flash Only', + }, + }, + 0x09e => { Name => 'PreviewButton', PrintConv => \%previewButtonD6 }, # CSf3-a (D6) + 0x0a0 => [{ # CSf3-b (D6) + Name => 'Func1Button', + PrintConv => \%previewButtonD6, + %infoD6, + },{ # CSf2-a (Z7_2) + Name => 'Func1Button', + PrintConv => \%funcButtonZ7m2, + %infoZSeries, + }], + 0x0a2 => [{ # CSf3-c (D6) + Name => 'Func2Button', + PrintConv => \%previewButtonD6, + %infoD6, + },{ # CSf2-b (Z7_2) + Name => 'Func2Button', + PrintConv => \%funcButtonZ7m2, + %infoZSeries, + }], + 0x0a3 => [{ # CSf3-f (D6) + Name => 'AF-OnButton', + PrintConv => { + 1 => 'AF-AreaMode S', + 2 => 'AF-AreaMode D9', + 3 => 'AF-AreaMode D25', + 4 => 'AF-AreaMode D49', + 5 => 'AF-AreaMode D105', + 6 => 'AF-AreaMode 3D', + 7 => 'AF-AreaMode Group', + 8 => 'AF-AreaMode Group C1', + 9 => 'AF-AreaMode Group C2', + 10 => 'AF-AreaMode Auto Area', + 11 => 'AF-AreaMode + AF-On S', + 12 => 'AF-AreaMode + AF-On D9', + 13 => 'AF-AreaMode + AF-On D25', + 14 => 'AF-AreaMode + AF-On D49', + 15 => 'AF-AreaMode + AF-On D105', + 16 => 'AF-AreaMode + AF-On 3D', + 17 => 'AF-AreaMode + AF-On Group', + 18 => 'AF-AreaMode + AF-On Group C1', + 19 => 'AF-AreaMode + AF-On Group C2', + 20 => 'AF-AreaMode + AF-On Auto Area', + 21 => 'AF-On', + 22 => 'AF Lock Only', + 23 => 'AE Lock (hold)', + 24 => 'AE/WB Lock (hold)', + 25 => 'AE Lock (reset on release)', + 26 => 'AE Lock Only', + 27 => 'AE/AF Lock', + 28 => 'Recall Shooting Functions', + 29 => 'None', + }, + %infoD6, + },{ # CSf2-c (Z7_2) + Name => 'AF-OnButton', + PrintConv => { + 1 => 'Center Focus Point', + 2 => 'AF-On', + 3 => 'AF Lock Only', + 4 => 'AE Lock (hold)', + 5 => 'AE Lock (reset on release)', + 6 => 'AE Lock Only', + 7 => 'AE/AF Lock', + 8 => 'LiveView Info Display On/Off', + 9 => 'Zoom (Low)', + 10 => 'Zoom (1:1)', + 11 => 'Zoom (High)', + 12 => 'None' + }, + %infoZSeries, + }], + 0x0a4 => { Name => 'SubSelector', PrintConv => \%tagSubSelector }, # CSf3-g-1 # (D6), CSf2-d-1 # (Z7_2) + 0x0a5 => [{ # CSf3-h (D6) + Name => 'SubSelectorCenter', + PrintConv => { + 1 => 'Preset Focus Point - Press To Recall', + 2 => 'Preset Focus Point - Hold To Recall', + 3 => 'Center Focus Point', + 4 => 'AF-AreaMode S', + 5 => 'AF-AreaMode D9', + 6 => 'AF-AreaMode D25', + 7 => 'AF-AreaMode D49', + 8 => 'AF-AreaMode D105', + 9 => 'AF-AreaMode 3D', + 10 => 'AF-AreaMode Group', + 11 => 'AF-AreaMode Group C1', + 12 => 'AF-AreaMode Group C2', + 13 => 'AF-AreaMode Auto Area', + 14 => 'AF-AreaMode + AF-On S', + 15 => 'AF-AreaMode + AF-On D9', + 16 => 'AF-AreaMode + AF-On D25', + 17 => 'AF-AreaMode + AF-On D49', + 18 => 'AF-AreaMode + AF-On D105', + 19 => 'AF-AreaMode + AF-On 3D', + 20 => 'AF-AreaMode + AF-On Group', + 21 => 'AF-AreaMode + AF-On Group C1', + 22 => 'AF-AreaMode + AF-On Group C2', + 23 => 'AF-AreaMode + AF-On Auto Area', + 24 => 'AF-On', + 25 => 'AF Lock Only', + 26 => 'AE Lock (hold)', + 27 => 'AE/WB Lock (hold)', + 28 => 'AE Lock (reset on release)', + 29 => 'AE Lock Only', + 30 => 'AE/AF Lock', + 31 => 'FV Lock', + 32 => 'Flash Disable/Enable', + 33 => 'Preview', + 34 => 'Recall Shooting Functions', + 35 => 'Bracketing Burst', + 36 => 'Synchronized Release (Master)', + 37 => 'Synchronized Release (Remote)', + 38 => 'None', + }, + %infoD6, + },{ # CSf2-e (Z7_2) + Name => 'SubSelectorCenter', + PrintConv => { + 1 => 'Center Focus Point', + 2 => 'AF-On', + 3 => 'AF Lock Only', + 4 => 'AE Lock (hold)', + 5 => 'AE Lock (reset on release)', + 6 => 'AE Lock Only', + 7 => 'AE/AF Lock', + 8 => 'FV Lock', + 9 => 'Flash Disable/Enable', + 10 => 'Preview', + 11 => 'Matrix Metering', + 12 => 'Center-weighted Metering', + 13 => 'Spot Metering', + 14 => 'Highlight-weighted Metering', + 15 => 'Bracketing Burst', + 16 => 'Synchronized Release (Master)', + 17 => 'Synchronized Release (Remote)', + 20 => '+NEF(RAW)', + 21 => 'LiveView Info Display On/Off', + 22 => 'Grid Display', + 23 => 'Image Area', + 24 => 'Non-CPU Lens', + 25 => 'None', + }, + %infoZSeries, + }], + 0x0a7 => [{ # CSf3-n (D6) + Name => 'LensFunc1Button', + PrintConv => { + 1 => 'Preset Focus Point - Press To Recall', + 2 => 'Preset Focus Point - Hold To Recall', + 3 => 'AF-AreaMode S', + 4 => 'AF-AreaMode D9', + 5 => 'AF-AreaMode D25', + 6 => 'AF-AreaMode D49', + 7 => 'AF-AreaMode D105', + 8 => 'AF-AreaMode 3D', + 9 => 'AF-AreaMode Group', + 10 => 'AF-AreaMode Group C1', + 11 => 'AF-AreaMode Group C2', + 12 => 'AF-AreaMode Auto Area', + 13 => 'AF-AreaMode + AF-On S', + 14 => 'AF-AreaMode + AF-On D9', + 15 => 'AF-AreaMode + AF-On D25', + 16 => 'AF-AreaMode + AF-On D49', + 17 => 'AF-AreaMode + AF-On D105', + 18 => 'AF-AreaMode + AF-On 3D', + 19 => 'AF-AreaMode + AF-On Group', + 20 => 'AF-AreaMode + AF-On Group C1', + 21 => 'AF-AreaMode + AF-On Group C2', + 22 => 'AF-AreaMode + AF-On Auto Area', + 23 => 'AF-On', + 24 => 'AF Lock Only', + 25 => 'AE Lock Only', + 26 => 'AE/AF Lock', + 27 => 'Flash Disable/Enable', + 28 => 'Recall Shooting Functions', + 29 => 'Synchronized Release (Master)', + 30 => 'Synchronized Release (Remote)', + }, + %infoD6, + },{ # CSf2-g (Z7_2) + Name => 'LensFunc1Button', + PrintConv => \%lensFuncButtonZ7m2, + %infoZSeries, + }], + 0x0a8 => { Name => 'CmdDialsApertureSetting', PrintConv => { 1 => 'Sub-command Dial', 2 => 'Aperture Ring' } }, # CSf6-c (D6) + 0x0a9 => { Name => 'MultiSelector', PrintConv => \%tagMultiSelector }, # CSf7 (D6) + 0x0aa => { # CSf10 (D6) + Name => 'LiveViewButtonOptions', + PrintConv => { + 1 => 'Enable', + 2 => 'Enable (Standby Timer Active)', + 3 => 'Disable', + }, + }, + 0x0ab => { # CSf11 (D6) + Name => 'LightSwitch', + PrintConv => { + 1 => 'LCD Backlight', + 2 => 'LCD Backlight and Shooting Information', + }, + }, + 0x0b1 => [{ # CSg2-a (D6) + Name => 'MoviePreviewButton', + PrintConv => { + 1 => 'Power Aperture (Open)', + 2 => 'Exposure Compensation', + 3 => 'Grid Display', + 4 => 'Zoom (Low)', + 5 => 'Zoom (1:1)', + 6 => 'Zoom (High)', + 7 => 'Image Area', + 8 => 'Microphone Sensitivity', + 9 => 'None', + }, + %infoD6, + },{ # CSg2-a (Z7_2) + Name => 'MovieFunc1Button', + PrintConv => { + 1 => 'Power Aperture (Open)', + 2 => 'Exposure Compensation', + 3 => 'Subject Tracking', + 4 => 'LiveView Info Display On/Off', + 5 => 'Grid Display', + 6 => 'Zoom (Low)', + 7 => 'Zoom (1:1)', + 8 => 'Zoom (High)', + 9 => 'Protect', + 10 => 'Image Area', + 11 => 'White Balance', + 12 => 'Picture Control', + 13 => 'Active-D Lighting', + 14 => 'Metering', + 15 => 'Focus Mode', + 16 => 'Microphone Sensitivity', + 17 => 'Focus Peaking', + 18 => 'Rating (None)', + 19 => 'Rating (5)', + 20 => 'Rating (4)', + 21 => 'Rating (3)', + 22 => 'Rating (2)', + 23 => 'Rating (1)', # no mapping for 24 on the Z7_2. Possibly intended for Rating = 'Candidate for Deletion'? + 25 => 'None', + }, + %infoZSeries, + }], + 0x0b3 => [{ # CSg2-b (D6) + Name => 'MovieFunc1Button', + PrintConv => { + 1 => 'Power Aperture (Close)', + 2 => 'Exposure Compensation', + 3 => 'Grid Display', + 4 => 'Zoom (Low)', + 5 => 'Zoom (1:1)', + 6 => 'Zoom (High)', + 7 => 'Image Area', + 8 => 'Microphone Sensitivity', + 9 => 'None', + }, + %infoD6, + },{ # CSg2-b (Z7_2) + Name => 'MovieFunc2Button', + PrintConv => { # TODO: simplify Func1 and Func2 movies buttons - identical except for the 1st entry + 1 => 'Power Aperture (Close)', + 2 => 'Exposure Compensation', + 3 => 'Subject Tracking', + 4 => 'LiveView Info Display On/Off', + 5 => 'Grid Display', + 6 => 'Zoom (Low)', + 7 => 'Zoom (1:1)', + 8 => 'Zoom (High)', + 9 => 'Protect', + 10 => 'Image Area', + 11 => 'White Balance', + 12 => 'Picture Control', + 13 => 'Active-D Lighting', + 14 => 'Metering', + 15 => 'Focus Mode', + 16 => 'Microphone Sensitivity', + 17 => 'Focus Peaking', + 18 => 'Rating (None)', + 19 => 'Rating (5)', + 20 => 'Rating (4)', + 21 => 'Rating (3)', + 22 => 'Rating (2)', + 23 => 'Rating (1)', # no mapping for 24 on the Z7_2. Possibly intended for Rating = 'Candidate for Deletion'? + 25 => 'None', + }, + %infoZSeries, + }], + 0x0b5 => { # CSg2-c (D6) + Name => 'MovieFunc2Button', + PrintConv => { + 1 => 'Grid Display', + 2 => 'Zoom (Low)', + 3 => 'Zoom (1:1)', + 4 => 'Zoom (High)', + 5 => 'Image Area', + 6 => 'Microphone Sensitivity', + 7 => 'None', + }, + }, + 0x0b6 => [{ # CSg2-e (D6) + Name => 'AssignMovieSubselector', + PrintConv => { + 1 => 'Center Focus Point', + 2 => 'AF Lock Only', + 3 => 'AE Lock (hold)', + 4 => 'AE/WB Lock (hold)', + 5 => 'AE Lock Only', + 6 => 'AE/AF Lock', + 7 => 'Zoom (Low)', + 8 => 'Zoom (1:1)', + 9 => 'Zoom (High)', + 10 => 'Record Movie', + 11 => 'None', + }, + %infoD6, + },{ # CSg2-d (Z7_2) + Name => 'AssignMovieSubselector', + PrintConv => { + 1 => 'Center Focus Point', + 2 => 'AF Lock Only', + 3 => 'AE Lock (hold)', + 4 => 'AE Lock Only', + 5 => 'AE/AF Lock', + 6 => 'LiveView Info Display On/Off', + 7 => 'Grid Display', + 8 => 'Zoom (Low)', + 9 => 'Zoom (1:1)', + 10 => 'Zoom (High)', + 11 => 'Record Movie', + 12 => 'Image Area', + 13 => 'None', + }, + %infoZSeries, + }], + 0x0b8 => { Name => 'LimitAFAreaModeSelD9', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa14-a (D6) + 0x0b9 => { Name => 'LimitAFAreaModeSelD25', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa14-b (D6) + 0x0bc => { Name => 'LimitAFAreaModeSel3D', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa14-e (D6) + 0x0bd => { Name => 'LimitAFAreaModeSelGroup', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa14-f (D6) + 0x0be => { Name => 'LimitAFAreaModeSelAuto', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa14-i (D6), CSa7-g (Z7_2) + # 0x0bf => { Name => 'LimitSelectableImageArea30x20', PrintConv => \%limitNolimit }, # CSd8-1 (D6) further investigation & testing of CSd8-1 and CSd8-2 required. The other CSd8 tags are fine. + # 0x0c0 => { Name => 'LimitSelectableImageAreaDX', PrintConv => \%limitNolimit }, # CSd8-2 (D6) further investigation & testing of CSd8-1 and CSd8-2 required. The other CSd8 tags are fine. + 0x0c1 => { Name => 'LimitSelectableImageArea5To4', PrintConv => \%limitNolimit, Unknown => 1 }, # CSd8-3 (D6) + 0x0c2 => { Name => 'LimitSelectableImageArea1To1', PrintConv => \%limitNolimit, Unknown => 1 }, # CSd8-4 (D6) + # 0x0d3 => CSf3-g-2 (D6), CSf2-d-2 (Z7_2) SelectorPlaybackRole 'Scroll' and 'Display Next/Previous' (skipped to reduce volume of output) + 0x0d4 => { Name => 'PhotoShootingMenuBank', PrintConv => \%menuBank }, # (D6) + 0x0d5 => { Name => 'CustomSettingsBank', PrintConv => \%menuBank }, # (D6) + 0x0d6 => { Name => 'LimitAF-AreaModeSelPinpoint', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa7-a (Z7_2) + 0x0d7 => { Name => 'LimitAF-AreaModeSelDynamic', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa7-b (Z7_2) + 0x0d8 => { Name => 'LimitAF-AreaModeSelWideAF_S', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa7-c (Z7_2) + 0x0d9 => { Name => 'LimitAF-AreaModeSelWideAF_L', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa7-d (Z7_2) + 0x0da => { Name => 'LowLightAF', PrintConv => \%onOff }, # CSa10 (Z7_2) + 0x0db => { Name => 'LimitSelectableImageAreaDX', PrintConv => \%limitNolimit, Unknown => 1 }, # CSd7-a (Z7_2) + 0x0dc => { Name => 'LimitSelectableImageArea5To4', PrintConv => \%limitNolimit, Unknown => 1 }, # CSd7-b (Z7_2) + 0x0dd => { Name => 'LimitSelectableImageArea1To1', PrintConv => \%limitNolimit, Unknown => 1 }, # CSd7-c (Z7_2) + 0x0de => { Name => 'LimitSelectableImageArea16To9', PrintConv => \%limitNolimit, Unknown => 1 }, # CSd7-d (Z7_2) + 0x0df => { Name => 'ApplySettingsToLiveView', PrintConv => \%onOff }, # CSd9 # new tag with Z7_2 # (Z7_2) + 0x0e0 => { # CSd10-a (D6), CSd11-a (Z7_2) + Name => 'FocusPeakingLevel', + PrintConv => { + 1 => 'High Sensitivity', + 2 => 'Standard Sensitivity', + 3 => 'Low Sensitivity', + 4 => 'Off', + }, + }, + 0x0ea => { # CSf2-i #option for 'Focus (M/A)' is documented, but not available from camera menu + Name => 'LensControlRing', + PrintConv => { + 1 => 'Aperture', + 2 => 'Exposure Compensation', + 3 => 'ISO Sensitivity', + 4 => 'None (Disabled)', + }, + }, + # 0x0eb MovieLensControlRing ? # (Z7_2) + # 0x0ec # (Z7_2) + 0x0ed => [{ # CSg3 (D6) + Name => 'MovieMultiSelector', + PrintConv => { + 1 => 'Center Focus Point', + 2 => 'Zoom (Low)', + 3 => 'Zoom (1:1)', + 4 => 'Zoom (High)', + 5 => 'Record Movie', + 6 => 'None', + }, + %infoD6, + },{ # labels Ok button on camera # (Z7_2) + Name => 'MovieMultiSelector', + PrintConv => { # Z7 has codes for both OK and MultiSelector - although only the OK value can be changed. [The multiselector served as the OK button on these cameras]. + 1 => 'Center Focus Point', + 2 => 'Zoom (Low)', + 3 => 'Zoom (1:1)', + 4 => 'Zoom (High)', + 5 => 'Record Movie', + 6 => 'None', + }, + }], + 0x0ee => { Name => 'MovieAFSpeed', ValueConv => '$val - 6', ValueConvInv => '$val + 6' }, # CSg4-a (Z7_2) + 0x0ef => { # CSg4-b (Z7_2) + Name => 'MovieAFSpeedApply', + PrintConv => { + 1 => 'Always', + 2 => 'Only During Recording', + }, + }, + 0x0f0 => { # CSg5 (Z7_2) + Name => 'MovieAFTrackingSensitivity', + PrintConv => { + 1 => '1 (High)', + 2 => '2', + 3 => '3', + 4 => '4 (Normal)', + 5 => '5', + 6 => '6', + 7 => '7 (Low)', + }, + }, + 0x0f1 => { # CSg4-a (D6), CSg6-a (Z7_2) + Name => 'MovieHighlightDisplayPattern', + PrintConv => { + 1 => 'Pattern 1', + 2 => 'Pattern 2', + 3 => 'Off', + }, + }, + 0x0f2 => { Name => 'SubDialFrameAdvanceRating5', PrintConv => \%noYes, Unknown => 1 }, # (D6,Z7_2) + 0x0f3 => { Name => 'SubDialFrameAdvanceRating4', PrintConv => \%noYes, Unknown => 1 }, # (D6,Z7_2) + 0x0f4 => { Name => 'SubDialFrameAdvanceRating3', PrintConv => \%noYes, Unknown => 1 }, # (D6,Z7_2) + 0x0f5 => { Name => 'SubDialFrameAdvanceRating2', PrintConv => \%noYes, Unknown => 1 }, # (D6,Z7_2) + 0x0f6 => { Name => 'SubDialFrameAdvanceRating1', PrintConv => \%noYes, Unknown => 1 }, # (D6,Z7_2) + 0x0f7 => { Name => 'SubDialFrameAdvanceRating0', PrintConv => \%noYes, Unknown => 1 }, # (D6,Z7_2) + # 0x0f8 ?? looks like it should be part of the above, but nothing seems to cause the value to change. Possibly intended for Rating='Candidate for Deletion' # (D6) + 0x0f9 => { # CSg2-c (Z7_2) + Name => 'MovieAF-OnButton', + PrintConv => { + 1 => 'Center Focus Point', + 2 => 'AF-On', + 3 => 'AF Lock Only', + 4 => 'AE Lock (hold)', + 5 => 'AE Lock Only', + 6 => 'AE/AF Lock', + 7 => 'LiveView Info Display On/Off', + 8 => 'Zoom (Low)', + 9 => 'Zoom (1:1)', + 10 => 'Zoom (High)', + 11 => 'Record Movie', + 12 => 'None', + }, + }, + 0x0fb => { Name => 'SecondarySlotFunction', PrintConv => \%tagSecondarySlotFunction }, # tag name selected to maintain compatibility with older cameras # (Z7_2) + 0x0fb => { Name => 'SecondarySlotFunction', PrintConv => \%tagSecondarySlotFunction }, # (D6) + 0x0fc => { Name => 'SilentPhotography', PrintConv => \%onOff }, # (D6,Z7_2) # tag is associated with Silent LiveView Photography (as distinguisehed from Silent Interval or Silent Focus Shift) + 0x0fd => { Name => 'ExtendedShutterSpeeds', PrintConv => \%onOff }, # CSd7 (D6), CSd6 (Z7_2) + 0x102 => { # (Z7_2) + Name => 'HDMIBitDepth', + RawConv => '$$self{HDMIBitDepth} = $val', + PrintConv => { + 1 => '8 Bit', + 2 => '10 Bit', + #5 => 'Auto', #observed on the Z50 - needs confirmation + }, + }, + 0x103 => { # (Z7_2) + Name => 'HDMIOutputHDR', + Condition => '$$self{HDMIBitDepth} == 2', # HDR(HLC) output option only available only for 10 bit + RawConv => '$$self{HDMIOutputHDR} = $val', + PrintConv => { + 2 => 'On', # unusual decode perhaps due to sharing sub-menu with tag HDMIOutputN-Log? + 3 => 'Off', + }, + }, + 0x104 => { # valid for 10 bit with either N-Log or HDR/HLG selected CSg5 (Z7_2) + Name => 'HDMIViewAssist', + Condition => '$$self{HDMIBitDepth} == 2', + PrintConv => \%onOff + }, + 0x109 => { # (D6,Z7_2) + Name => 'BracketSet', + RawConv => '$$self{BracketSet} = $val', + PrintConv => { + 1 => 'AE/Flash', + 2 => 'AE', + 3 => 'Flash', + 4 => 'White Balance', + 5 => 'Active-D Lighting', + }, + }, + 0x10a => [{ # (D6/Z7_2) + Name => 'BracketProgram', + Condition => '$$self{BracketSet} < 4', + Notes => 'AE and/or Flash Bracketing', + RawConv => '$$self{BracketProgram} = $val', + PrintConv => { + 15 => '+3F', + 16 => '-3F', + 17 => '+2F', + 18 => '-2F', + 19 => 'Disabled', + 20 => '3F', + 21 => '5F', + 22 => '7F', + 23 => '9F', + }, + },{ + Name => 'BracketProgram', + Condition => '$$self{BracketSet} and $$self{BracketSet} == 4', + Notes => 'White Balance Bracketing', + RawConv => '$$self{BracketProgram} = $val', + PrintConv => { + 1 => 'B3F', + 2 => 'A3F', + 3 => 'B2F', + 4 => 'A2F', + 5 => 'Disabled', + 6 => '3F', + 7 => '5F', + 8 => '7F', + 9 => '9F', + 19 => 'N/A' # observed when shooting other than JPG + }, + },{ + Name => 'BracketProgram', + Condition => '$$self{BracketSet} and $$self{BracketSet} == 5', + Notes => 'Active-D Bracketing', + RawConv => '$$self{BracketProgram} = $val', + Mask => 0x0f, + PrintConv => { + 10 => 'Disabled', + 11 => '2 Exposures', + 12 => '3 Exposures', + 13 => '4 Exposures', + 14 => '5 Exposures', + }, + }], + 0x10b => [{ # (D6/Z7_2) + Name => 'BracketIncrement', + Condition => '$$self{BracketSet} < 4 and $$self{BracketProgram} ne 19', + Notes => 'AE and/or Flash Bracketing enabled', + PrintConv => { + 0x01 => '0.3', + 0x03 => '0.5', + 0x04 => '1.0', + 0x05 => '2.0', + 0x06 => '3.0', + }, + },{ + Name => 'BracketIncrement', + Condition => '$$self{BracketSet} == 4 and $$self{BracketProgram} ne 5', + Notes => 'White Balance Bracketing enabled', + PrintConv => '$val-6', # TODO: qualify amber/blue direction of increment (eg, '1A' vs.'1B' vs '1A,1B') + }], + 0x10c => { # (D6/Z7_2) + Name => 'BracketIncrement', + Condition => '$$self{BracketSet} == 5 and $$self{BracketProgram} ne 10', + Notes => 'Active-D Bracketing enabled', + PrintConv => { + 0 => 'Off', + 1 => 'Off, Low', + 2 => 'Off, Normal', + 3 => 'Off, High', + 4 => 'Off, Extra High', + 5 => 'Off, Auto', + 6 => 'Off, Low, Normal', + 7 => 'Off, Low, Normal, High', + 8 => 'Off, Low, Normal, High, Extra High', + }, + }, + 0x10e => { # (D6/Z7_2) + Name => 'MonitorBrightness', + # settings: -5 to +5 + ValueConv => '$val - 6', + }, + 0x116 => { Name => 'GroupAreaC1', PrintConv =>\%groupAreaCustom }, # CSa10-a (new with D6) # (D6) + 0x117 => { Name => 'AutoAreaAFStartingPoint', PrintConv => \%enableDisable }, # CSa12 (D6) + 0x118 => { Name => 'FocusPointPersistence', PrintConv => { 1 => 'Auto', 2 => 'Off' } }, # CSa13 (new with D6) # (D6) + 0x119 => { Name => 'LimitAFAreaModeSelD49', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa14-c (D6) + 0x11a => { Name => 'LimitAFAreaModeSelD105', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa14-d (D6) + 0x11b => { Name => 'LimitAFAreaModeSelGroupC1', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa14-g (D6) + 0x11c => { Name => 'LimitAFAreaModeSelGroupC2', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa14-h (D6) + 0x11d => { # CSa15 (D6) + Name => 'AutoFocusModeRestrictions', + PrintConv => { + 1 => 'AF-S', + 2 => 'AF-C', + 3 => 'No Limit', + }, + }, + 0x11e => { # CSa17-b (D6) + Name => 'FocusPointBrightness', + PrintConv => { + 1 => 'Extra High', + 2 => 'High', + 3 => 'Normal', + 4 => 'Low', + }, + }, + 0x11f => { Name => 'CHModeShootingSpeed', ValueConv => '15 - $val', ValueConvInv => '15 + $val', PrintConv => '"$val fps"', PrintConvInv => '$val=~s/\s*fps//i; $val' }, # CSd1-a (D6) + 0x120 => { Name => 'CLModeShootingSpeed', ValueConv => '11 - $val', ValueConvInv => '11 + $val', PrintConv => '"$val fps"', PrintConvInv => '$val=~s/\s*fps//i; $val' }, # CSd1-b (D6) + 0x121 => { # CSd1-c (new with D6) + Name => 'QuietShutterShootingSpeed', + PrintConv => { + 1 => 'Single', + 2 => '5 fps', + 3 => '4 fps', + 4 => '3 fps', + 5 => '2 fps', + 6 => '1 fps', + }, + }, + 0x122 => { Name => 'LimitReleaseModeSelCL', PrintConv => \%limtReleaseModeSel, Unknown => 1 }, # CSd3-a (D6) + 0x123 => { Name => 'LimitReleaseModeSelCH', PrintConv => \%limtReleaseModeSel, Unknown => 1 }, # CSd3-b (D6) + 0x124 => { Name => 'LimitReleaseModeSelQ', PrintConv => \%limtReleaseModeSel, Unknown => 1 }, # CSd3-c (D6) + 0x125 => { Name => 'LimitReleaseModeSelTimer', PrintConv => \%limtReleaseModeSel, Unknown => 1 }, # CSd3-d (D6) + 0x126 => { Name => 'LimitReleaseModeSelMirror-Up', PrintConv => \%limtReleaseModeSel, Unknown => 1 }, # CSd3-e (D6) + 0x127 => { Name => 'LimitSelectableImageArea16To9', PrintConv => \%limitNolimit, Unknown => 1 }, # CSd8-5 (D6) + 0x128 => { Name => 'RearControPanelDisplay', PrintConv => { 1 => 'Release Mode', 2 => 'Frame Count' } }, # CSd12 # new tag with D6 # (D6) + 0x129 => { Name => 'FlashBurstPriority', PrintConv => { 1 => 'Frame Rate', 2 => 'Exposure' } }, # CSE5 # new tag with D6 # (D6) + 0x12a => { Name => 'RecallShootFuncExposureMode', PrintConv => \%offOn }, # (D6) + 0x12b => { Name => 'RecallShootFuncShutterSpeed', PrintConv => \%offOn }, # (D6) + 0x12c => { Name => 'RecallShootFuncAperture', PrintConv => \%offOn }, # (D6) + 0x12d => { Name => 'RecallShootFuncExposureComp', PrintConv => \%offOn }, # (D6) + 0x12e => { Name => 'RecallShootFuncISO', PrintConv => \%offOn }, # (D6) + 0x12f => { Name => 'RecallShootFuncMeteringMode', PrintConv => \%offOn }, # (D6) + 0x130 => { Name => 'RecallShootFuncWhiteBalance', PrintConv => \%offOn }, # (D6) + 0x131 => { Name => 'RecallShootFuncAFAreaMode', PrintConv => \%offOn }, # (D6) + 0x132 => { Name => 'RecallShootFuncFocusTracking', PrintConv => \%offOn }, # (D6) + 0x133 => { Name => 'RecallShootFuncAF-On', PrintConv => \%offOn }, # (D6) + 0x134 => { # CSf3-d (D6) + Name => 'VerticalFuncButton', + PrintConv => { + 1 => 'Preset Focus Point', + 2 => 'AE Lock (hold)', + 3 => 'AE/WB Lock (hold)', + 4 => 'AE Lock (reset on release)', + 5 => 'FV Lock', + 6 => 'Preview', + 7 => '+NEF(RAW)', + 8 => 'Grid Display', + 9 => 'Virtual Horizon', + 10 => 'Voice Memo', + 11 => 'Playback', + 12 => 'Filtered Playback', + 13 => 'Photo Shooting Bank', + 14 => 'Exposure Mode', + 15 => 'Exposure Comp', + 16 => 'AF Mode/AF Area Mode', + 17 => 'Image Area', + 18 => 'ISO', + 19 => 'Active-D Lighting', + 20 => 'Metering', + 21 => 'Exposure Delay Mode', + 22 => 'Shutter/Aperture Lock', + 23 => '1 Stop Speed/Aperture', + 24 => 'Rating 0', + 25 => 'Rating 5', + 26 => 'Rating 4', + 27 => 'Rating 3', + 28 => 'Rating 2', + 29 => 'Rating 1', + 30 => 'Candidate For Deletion', + 31 => 'Non-CPU Lens', + 32 => 'None', + }, + }, + 0x135 => { # CSf3-e (D6) + Name => 'Func3Button', + PrintConv => { + 1 => 'Voice Memo', + 2 => 'Select To Send', + 3 => 'Wired LAN', + 4 => 'My Menu', + 5 => 'My Menu Top Item', + 6 => 'Filtered Playback', + 7 => 'Rating 0', + 8 => 'Rating 5', + 9 => 'Rating 4', + 10 => 'Rating 3', + 11 => 'Rating 2', + 12 => 'Rating 1', + 13 => 'Candidate For Deletion', + 14 => 'None', + }, + }, + 0x136 => { # CSf3-i (D6) + Name => 'VerticalAF-OnButton', + PrintConv => { + 1 => 'AF-AreaMode S', + 2 => 'AF-AreaMode D9', + 3 => 'AF-AreaMode D25', + 4 => 'AF-AreaMode D49', + 5 => 'AF-AreaMode D105', + 6 => 'AF-AreaMode 3D', + 7 => 'AF-AreaMode Group', + 8 => 'AF-AreaMode Group C1', + 9 => 'AF-AreaMode Group C2', + 10 => 'AF-AreaMode Auto Area', + 11 => 'AF-AreaMode + AF-On S', + 12 => 'AF-AreaMode + AF-On D9', + 13 => 'AF-AreaMode + AF-On D25', + 14 => 'AF-AreaMode + AF-On D49', + 15 => 'AF-AreaMode + AF-On D105', + 16 => 'AF-AreaMode + AF-On 3D', + 17 => 'AF-AreaMode + AF-On Group', + 18 => 'AF-AreaMode + AF-On Group C1', + 19 => 'AF-AreaMode + AF-On Group C2', + 20 => 'AF-AreaMode + AF-On Auto Area', + 21 => 'Same as AF-On', + 22 => 'AF-On', + 23 => 'AF Lock Only', + 24 => 'AE Lock (hold)', + 25 => 'AE/WB Lock (hold)', + 26 => 'AE Lock (reset on release)', + 27 => 'AE Lock Only', + 28 => 'AE/AF Lock', + 29 => 'Recall Shooting Functions', + 30 => 'None', + }, + }, + 0x137 => { Name => 'VerticalMultiSelector', PrintConv => \%tagSubSelector }, # CSf3-j-1 # (D6) + 0x138 => { # CSf3-k (D6) + Name => 'MeteringButton', + PrintConv => { + 1 => 'Photo Shooting Bank', + 2 => 'Image Area', + 3 => 'Active-D Lighting', + 4 => 'Metering', + 5 => 'Exposure Delay Mode', + 6 => 'Shutter/Aperture Lock', + 7 => '1 Stop Speed/Aperture', + 8 => 'Non-CPU Lens', + 9 => 'None', + }, + }, + 0x139 => { Name => 'PlaybackFlickUp', RawConv => '$$self{PlaybackFlickUp} = $val', PrintConv => \%flickUpDownD6 }, # CSf12-1-a # (D6) + 0x13a => { Name => 'PlaybackFlickUpRating', Condition => '$$self{PlaybackFlickUp} and $$self{PlaybackFlickUp} == 1', Notes => 'Meaningful only when PlaybackFlickUp is Rating', PrintConv => \%flickUpDownRatingD6 }, # CSf12-1-b # (D6) + 0x13b => { Name => 'PlaybackFlickDown', RawConv => '$$self{PlaybackFlickDown} = $val', PrintConv => \%flickUpDownD6 }, # CSf12-2-a # (D6) + 0x13c => { Name => 'PlaybackFlickDownRating', Condition => '$$self{PlaybackFlickDown} and $$self{PlaybackFlickDown} == 1', Notes => 'Meaningful only when PlaybackFlickDown is Rating', PrintConv => \%flickUpDownRatingD6 }, # CSf12-2-b # (D6) + 0x13d => { # CSg2-d (D6) + Name => 'MovieFunc3Button', + PrintConv => { + 1 => 'Record Movie', + 2 => 'My Menu', + 3 => 'My Menu Top Item', + 4 => 'None', + }, + }, + 0x150 => { # CSd5 (Z7_2) new with Z series + Name => 'ShutterType', + PrintConv => { + 1 => 'Auto', + 2 => 'Mechanical', + 3 => 'Electronic', + }, + }, + 0x151 => { Name => 'LensFunc2Button', PrintConv => \%lensFuncButtonZ7m2 }, # CSf2-h (Z7_2) + #0x153 => { Name => 'ViewfinderBrightness', } #(Z7_2) # commented out to reduce output volume. Range [-5,+5]. PrintConv matches MonitorBrightness. + 0x158 => { Name => 'USBPowerDelivery', PrintConv => \%enableDisable }, # (Z7_2) + 0x159 => { Name => 'EnergySavingMode', PrintConv =>\%onOff }, # (Z7_2) + 0x15c => { Name => 'BracketingBurstOptions',PrintConv => \%enableDisable }, # CSe9 (D6) + # 0x15d => CSf3-j-2 (D6) 'Same as Multi-Selector with Info(U/D) & Playback(R/L)' and 'Same as Multi-Selector with Info(R/L) & Playback(U/D)' (skipped to reduce volume of output) + 0x15e => { Name => 'PrimarySlot', PrintConv => { 1 => 'CFexpress/XQD Card', 2 => 'SD Card' } }, # (Z7_2) + 0x15f => { Name => 'ReverseFocusRing', PrintConv => { 1 => 'Not Reversed', 2 => 'Reversed' } }, # CSf8 (Z7_2) + 0x160 => { # CSf9-a (Z7_2) + Name => 'VerticalFuncButton', + PrintConv => { + 1 => 'AE Lock (hold)', + 2 => 'AE Lock (reset on release)', + 3 => 'FV Lock', + 4 => 'Preview', + 5 => '+NEF(RAW)', + 6 => 'Subject Tracking', + 7 => 'Silent Photography', + 8 => 'LiveView Info Display On/Off', + 9 => 'Playback', + 10 => 'Image Area', + 11 => 'Metering', + 12 => 'Flash Mode', + 13 => 'Focus Mode', + 14 => 'Exposure Delay Mode', + 15 => 'Shutter/Aperture Lock', + 16 => 'Exposure Compensation', + 17 => 'ISO Sensitivity', + 18 => 'None', + }, + }, + 0x161 => { # CSf9-b (Z7_2) + Name => 'VerticalAFOnButton', + PrintConv => { + 1 => 'Same as AF-On Button', + 2 => 'Select Center Focus Point', + 3 => 'AF-On', + 4 => 'AF Lock Only', + 5 => 'AE Lock (hold)', + 6 => 'AE Lock (reset on release)', + 7 => 'AE Lock Only', + 8 => 'AE/AF Lock', + 9 => 'LiveView Info Display On/Off', + 10 => 'Zoom (Low)', + 11 => 'Zoom (1:1)', + 12 => 'Zoom (High)', + 13 => 'None', + }, + }, + 0x162 => { Name => 'VerticalMultiSelector', PrintConv => \%tagSubSelector }, # CSf9-c (Z7_2) + # 0x163 => CSf9-c-2 (Z7_2) 'Same as Multi-Selector with Info(U/D) & Playback(R/L)' and 'Same as Multi-Selector with Info(R/L) & Playback(U/D)' (skipped to reduce volume of output) + 0x164 => { # CSg7-a (Z7_2) + Name => 'VerticalMovieFuncButton', + PrintConv => { + 1 => 'LiveView Info Display On/Off', + 2 => 'Record Movie', + 3 => 'Exposure Compensation', + 4 => 'ISO', + 5 => 'None', + }, + }, + 0x165 => { # CSg7-b (Z7_2) + Name => 'VerticalMovieAFOnButton', + PrintConv => { + 1 => 'Same as AF-On', + 2 => 'Center Focus Point', + 3 => 'AF-On', + 4 => 'AF Lock Only', + 5 => 'AE Lock (hold)', + 6 => 'AE Lock Only', + 7 => 'AE/AF Lock', + 8 => 'LiveView Info Display On/Off', + 9 => 'Zoom (Low)', + 10 => 'Zoom (1:1)', + 11 => 'Zoom (High)', + 12 => 'Record Movie', + 13 => 'None', + }, + }, + #0x168 => { Name => 'ControlPanelBrightness', # (Z7_2) #commented to reduce output volume + 0x169 => { Name => 'LimitAF-AreaModeSelAutoPeople', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa7-h (Z7_2) + 0x16a => { Name => 'LimitAF-AreaModeSelAutoAnimals', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa7-h (Z7_2) + 0x16b => { Name => 'LimitAF-AreaModeSelWideLPeople', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa7-e (Z7_2) + 0x16c => { Name => 'LimitAF-AreaModeSelWideLAnimals', PrintConv => \%limitNolimit, Unknown => 1 }, # CSa7-f (Z7_2) + 0x16d => { Name => 'SaveFocus', PrintConv => \%onOff }, # (Z7_2) + 0x16e => { # (Z7_2) + Name => 'AFAreaMode', + RawConv => '$$self{AFAreaMode} = $val', + PrintConv => { + 2 => 'Single-point', + 3 => 'Dynamic-area', + 4 => 'Wide (S)', + 5 => 'Wide (L)', + 6 => 'Wide (L-people)', + 7 => 'Wide (L-animals)', + 8 => 'Auto', + 9 => 'Auto (People)', + 10 => 'Auto (Animals)', + }, + }, + 0x16f => { # (Z7_2) + Name => 'MovieAFAreaMode', + PrintConv => { + 1 => 'Single-point', + 2 => 'Wide (S)', + 3 => 'Wide (L)', + 4 => 'Wide (L-people)', + 5 => 'Wide (L-animals)', + 6 => 'Auto', + 7 => 'Auto (People)', + 8 => 'Auto (Animals)', + }, + }, + 0x170 => { Name => 'PreferSubSelectorCenter', PrintConv => \%offOn }, # CSf13 (D6 firmware v1.2.0) + 0x171 => { # CSb8 (D6 firmware v1.3.0) + Name => 'KeepExposureWithTeleconverter', + PrintConv => { + 1 => 'Off', + 2 => 'Shutter Speed', + 3 => 'ISO', + }, + }, + 0x174 => { # CSa17-d (D6 firmware v1.2.0) + Name => 'FocusPointSelectionSpeed', + PrintConv => { + 1 => 'Normal', + 2 => 'High', + 3 => 'Very High', + }, + }, +); + +#------------------------------------------------------------------------------ +# Process NikonSettings directory (ref PH) +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub ProcessNikonSettings($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + + # NikonSettings directory has a 24-byte header: + # 0x00 - undef[4]: '0100' + # 0x04 - int32u: 1 (D-models), 2 (Z-models) + # 0x08 - undef[4]: '0100' + # 0x0c - int32u: 1 (Z7), 2 (D850), 3 (D780,Z50), 4 (D6,Z5), 5(Z7m2) + # 0x10 - undef[4]: firmware version (eg. '0110' for firmware 1.10) + # 0x14 - int32u: number of entries in directory + + return 0 if $$dirInfo{DirLen} < 24; # sanity check + + my $dataPt = $$dirInfo{DataPt}; + my $start = $$dirInfo{DirStart}; + my $num = Get32u($dataPt, $start + 0x14); + + $et->VerboseDir('NikonSettings', $num); + + my $n = int(($$dirInfo{DirLen} - 0x18) / 8); + if ($n < $num) { + $et->Warn('Missing '.($num-$n).' NikonSettings entries', 1); + $num = $n; + } elsif ($n > $num) { + $et->Warn('Unused space in NikonSettings directory', 1); + } + my $i; + for ($i=0; $i<$num; ++$i) { + my $entry = $start + 0x18 + $i * 8; + my $tag = Get16u($dataPt, $entry); + my $fmt = Get16u($dataPt, $entry + 2); + my $val = Get32u($dataPt, $entry + 4); + # abort if the tag has a format that we haven't yet seen + # (assuming this is a size/format code. So far we have only seen 0x400) + $fmt == 0x400 or $et->Warn(sprintf('Unknown format 0x%x for NikonSettings tag 0x%.4x',$fmt,$tag)), last; + $et->HandleTag($tagTablePtr, $tag, $val, + DataPt => $dataPt, + DataPos => $$dirInfo{DataPos}, + Base => $$dirInfo{Base}, + Start => $entry + 4, + Size => 4, + Format => 'int32u', + Index => $i, + ); + } + return 1; +} + + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::NikonSettings - Read Nikon user settings + +=head1 SYNOPSIS + +This module is loaded automatically by Image::ExifTool when required. + +=head1 DESCRIPTION + +This module contains the definitions necessary to read the user settings for +Nikon cameras such as the D6 and Z7mk2. + + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 ACKNOWLEDGEMENTS + +Thanks to Warren Hatch for his work decoding settings for the D6 and Z7mkII, +and for providing the original source code for this module. + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/Nikon Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Nintendo.pm b/src/Image-ExifTool/lib/Image/ExifTool/Nintendo.pm index 636ef6c4..5665859e 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Nintendo.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Nintendo.pm @@ -107,7 +107,7 @@ interpret Nintendo maker notes EXIF meta information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/OOXML.pm b/src/Image-ExifTool/lib/Image/ExifTool/OOXML.pm index 03daed03..e135dc59 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/OOXML.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/OOXML.pm @@ -14,13 +14,14 @@ use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::XMP; use Image::ExifTool::ZIP; -$VERSION = '1.07'; +$VERSION = '1.08'; # test for recognized OOXML document extensions my %isOOXML = ( DOCX => 1, DOCM => 1, DOTX => 1, DOTM => 1, POTX => 1, POTM => 1, + PPAX => 1, PPAM => 1, PPSX => 1, PPSM => 1, PPTX => 1, PPTM => 1, THMX => 1, XLAM => 1, @@ -394,7 +395,7 @@ archives of XML files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Ogg.pm b/src/Image-ExifTool/lib/Image/ExifTool/Ogg.pm index 75d36fd5..7b92185f 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Ogg.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Ogg.pm @@ -214,7 +214,7 @@ information from Ogg bitstream container files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Olympus.pm b/src/Image-ExifTool/lib/Image/ExifTool/Olympus.pm index 3c997349..3bcf3701 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Olympus.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Olympus.pm @@ -9,8 +9,8 @@ # References: 1) http://park2.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html # 2) http://www.cybercom.net/~dcoffin/dcraw/ # 3) http://www.ozhiker.com/electronics/pjmt/jpeg_info/olympus_mn.html -# 4) Markku HŠnninen private communication (tests with E-1) -# 5) RŽmi Guyomarch from http://forums.dpreview.com/forums/read.asp?forum=1022&message=12790396 +# 4) Markku Hanninen private communication (tests with E-1) +# 5) Remi Guyomarch from http://forums.dpreview.com/forums/read.asp?forum=1022&message=12790396 # 6) Frank Ledwon private communication (tests with E/C-series cameras) # 7) Michael Meissner private communication # 8) Shingo Noguchi, PhotoXP (http://www.daifukuya.com/photoxp/) @@ -21,12 +21,13 @@ # 13) Chris Shaw private communication (E-3) # 14) Viktor Lushnikov private communication (E-400) # 15) Yrjo Rauste private communication (E-30) -# 16) Godfrey DiGiorgi private communcation (E-P1) + http://forums.dpreview.com/forums/read.asp?message=33187567 +# 16) Godfrey DiGiorgi private communication (E-P1) + http://forums.dpreview.com/forums/read.asp?message=33187567 # 17) Martin Hibers private communication # 18) Tomasz Kawecki private communication # 19) Brad Grier private communication # 22) Herbert Kauer private communication # 23) Daniel Pollock private communication (PEN-F) +# 24) Sebastian private communication (E-M1 Mark III) # IB) Iliah Borg private communication (LibRaw) # NJ) Niels Kristian Bech Jensen private communication #------------------------------------------------------------------------------ @@ -39,7 +40,7 @@ use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; use Image::ExifTool::APP12; -$VERSION = '2.54'; +$VERSION = '2.78'; sub PrintLensInfo($$$); @@ -106,9 +107,14 @@ my %olympusLensTypes = ( '0 30 10' => 'Olympus M.Zuiko Digital ED 45mm F1.2 Pro', #IB '0 31 00' => 'Olympus Zuiko Digital ED 12-60mm F2.8-4.0 SWD', #7 '0 32 00' => 'Olympus Zuiko Digital ED 14-35mm F2.0 SWD', #PH + '0 32 10' => 'Olympus M.Zuiko Digital ED 12-200mm F3.5-6.3', #IB '0 33 00' => 'Olympus Zuiko Digital 25mm F2.8', #PH + '0 33 10' => 'Olympus M.Zuiko Digital 150-400mm F4.5 TC1.25x IS Pro', #IB '0 34 00' => 'Olympus Zuiko Digital ED 9-18mm F4.0-5.6', #7 + '0 34 10' => 'Olympus M.Zuiko Digital ED 12-45mm F4.0 Pro', #IB '0 35 00' => 'Olympus Zuiko Digital 14-54mm F2.8-3.5 II', #PH + '0 35 10' => 'Olympus M.Zuiko 100-400mm F5.0-6.3', #IB + '0 36 10' => 'Olympus M.Zuiko Digital ED 8-25mm F4 Pro', #IB # Sigma lenses '1 01 00' => 'Sigma 18-50mm F3.5-5.6 DC', #8 '1 01 10' => 'Sigma 30mm F2.8 EX DN', #NJ @@ -168,10 +174,24 @@ my %olympusLensTypes = ( '2 26 10' => 'Lumix G 25mm F1.7 Asph.', #NJ '2 27 10' => 'Leica DG Vario-Elmar 100-400mm F4.0-6.3 Asph. Power OIS', #NJ '2 28 10' => 'Lumix G Vario 12-60mm F3.5-5.6 Asph. Power OIS', #NJ + '2 29 10' => 'Leica DG Summilux 12mm F1.4 Asph.', #IB + '2 30 10' => 'Leica DG Vario-Elmarit 12-60mm F2.8-4 Asph. Power OIS', #IB + '2 31 10' => 'Lumix G Vario 45-200mm F4.0-5.6 II', #forum3833 + '2 32 10' => 'Lumix G Vario 100-300mm F4.0-5.6 II', #PH + '2 33 10' => 'Lumix G X Vario 12-35mm F2.8 II Asph. Power OIS', #IB + '2 34 10' => 'Lumix G Vario 35-100mm F2.8 II', #forum3833 + '2 35 10' => 'Leica DG Vario-Elmarit 8-18mm F2.8-4 Asph.', #IB + '2 36 10' => 'Leica DG Elmarit 200mm F2.8 Power OIS', #IB + '2 37 10' => 'Leica DG Vario-Elmarit 50-200mm F2.8-4 Asph. Power OIS', #IB + '2 38 10' => 'Leica DG Vario-Summilux 10-25mm F1.7 Asph.', #IB + '2 40 10' => 'Leica DG Vario-Summilux 25-50mm F1.7 Asph.', #IB (H-X2550) '3 01 00' => 'Leica D Vario Elmarit 14-50mm F2.8-3.5 Asph.', #11 '3 02 00' => 'Leica D Summilux 25mm F1.4 Asph.', #11 # Tamron lenses '5 01 10' => 'Tamron 14-150mm F3.5-5.8 Di III', #NJ (model C001) + # '65535 07 40' - Seen for LUMIX S 16-35/F4 on Panasonic DC-S1H (ref PH) + # Other makes + '24 01 10' => 'Venus Optics Laowa 50mm F2.8 2x Macro', #DonKomarechka ); # lookup for Olympus camera types (ref PH) @@ -363,6 +383,7 @@ my %olympusCameraTypes = ( D4587 => 'TG-860', D4591 => 'TG-870', D4593 => 'TG-5', #IB + D4603 => 'TG-6', #IB D4809 => 'C2500L', D4842 => 'E-10', D4856 => 'C-1', @@ -406,6 +427,12 @@ my %olympusCameraTypes = ( S0067 => 'E-M1MarkII', S0068 => 'E-M10MarkIII', S0076 => 'E-PL9', #IB + S0080 => 'E-M1X', #IB + S0085 => 'E-PL10', #IB + S0089 => 'E-M5MarkIII', + S0092 => 'E-M1MarkIII', #IB + S0093 => 'E-P7', #IB + S0095 => 'OM-1', #IB SR45 => 'D220', SR55 => 'D320L', SR83 => 'D340L', @@ -730,8 +757,8 @@ my %indexInfo = ( Name => 'CameraID', Format => 'string', # this really should have been a string }, - 0x020b => { Name => 'EpsonImageWidth', Writable => 'int16u' }, #PH - 0x020c => { Name => 'EpsonImageHeight', Writable => 'int16u' }, #PH + 0x020b => { Name => 'EpsonImageWidth', Writable => 'int32u' }, #PH + 0x020c => { Name => 'EpsonImageHeight', Writable => 'int32u' }, #PH 0x020d => { Name => 'EpsonSoftware', Writable => 'string' }, #PH 0x0280 => { #PH %Image::ExifTool::previewImageTagInfo, @@ -754,9 +781,17 @@ my %indexInfo = ( 0x0303 => { Name => 'WhiteBalanceBracket', Writable => 'int16u' }, #11 0x0304 => { Name => 'WhiteBalanceBias', Writable => 'int16u' }, #11 # 0x0305 => 'PrintMatching', ? #11 + 0x0400 => { #IB + Name => 'SensorArea', + Condition => '$$self{TIFF_TYPE} eq "ERF"', + Writable => 'undef', + Format => 'int16u', + Count => 4, + Notes => 'found in Epson ERF images', + }, 0x0401 => { #IB Name => 'BlackLevel', - Condition => '$format eq "int32u" and $count == 4', + Condition => '$$self{TIFF_TYPE} eq "ERF"', Writable => 'int32u', Count => 4, Notes => 'found in Epson ERF images', @@ -819,6 +854,7 @@ my %indexInfo = ( TagTable => 'Image::ExifTool::PrintIM::Main', }, }, + # 0x0e80 - undef[256] - offset 0x30: uint16[2] WB_RGBLevels = val[0]*561,65536,val[1]*431 (ref IB) 0x0f00 => { Name => 'DataDump', Writable => 0, @@ -1054,6 +1090,7 @@ my %indexInfo = ( 0x1035 => { #6 Name => 'PreviewImageValid', Writable => 'int32u', + DelValue => 0, PrintConv => { 0 => 'No', 1 => 'Yes' }, }, 0x1036 => { #6 @@ -1576,14 +1613,14 @@ my %indexInfo = ( Writable => 'int8u', Count => 6, Notes => q{ - 6 numbers: 0. Make, 1. Unknown, 2. Model, 3. Sub-model, 4-5. Unknown. Only + 6 numbers: 1. Make, 2. Unknown, 3. Model, 4. Sub-model, 5-6. Unknown. Only the Make, Model and Sub-model are used to identify the lens type }, SeparateTable => 'LensType', # Have seen these values for the unknown numbers: - # 1: 0 - # 4: 0, 2(Olympus lenses for which I have also seen 0 for this number) - # 5: 0, 16(new Lumix lenses) + # 2: 0 + # 5: 0, 2(Olympus lenses for which I have also seen 0 for this number) + # 6: 0, 16(new Lumix lenses) ValueConv => 'my @a=split(" ",$val); sprintf("%x %.2x %.2x",@a[0,2,3])', # set unknown values to zero when writing ValueConvInv => 'my @a=split(" ",$val); hex($a[0])." 0 ".hex($a[1])." ".hex($a[2])." 0 0"', @@ -1648,7 +1685,7 @@ my %indexInfo = ( Writable => 'int8u', Count => 6, Notes => q{ - 6 numbers: 0. Make, 1. Unknown, 2. Model, 3. Sub-model, 4-5. Unknown. Only + 6 numbers: 1. Make, 2. Unknown, 3. Model, 4. Sub-model, 5-6. Unknown. Only the Make and Model are used to identify the extender }, ValueConv => 'my @a=split(" ",$val); sprintf("%x %.2x",@a[0,2])', @@ -1680,6 +1717,7 @@ my %indexInfo = ( 0 => 'None', 2 => 'Simple E-System', 3 => 'E-System', + 4 => 'E-System (body powered)', #forum9740 }, }, 0x1001 => { #6 @@ -1697,6 +1735,8 @@ my %indexInfo = ( 7 => 'FL-36R', #11 9 => 'FL-14', #11 11 => 'FL-600R', #11 + 13 => 'FL-LM3', #forum9740 + 15 => 'FL-900R', #7 }, }, 0x1002 => { #6 @@ -1806,6 +1846,7 @@ my %indexInfo = ( 6 => 'Imager AF', 7 => 'Live View Magnification Frame', 8 => 'AF sensor', + 9 => 'Starry Sky AF', #24 }, }], }, @@ -1863,9 +1904,30 @@ my %indexInfo = ( }, 0x307 => { #15 Name => 'AFFineTuneAdj', - Format => 'int16s', + Writable => 'int16s', Count => 3, # not sure what the 3 values mean }, + 0x308 => { #forum11578 + Name => 'FocusBracketStepSize', + Writable => 'int8u', + }, + 0x309 => { #forum13341 + Name => 'AISubjectTrackingMode', + Writable => 'int16u', + ValueConv => '($val >> 8) . " " . ($val & 0xff)', + ValueConvInv => 'my @a = split " ", $val; $val = $a[0]*256 + $a[1]', + PrintConv => [{ + 0 => 'Off', + 1 => 'Motorsports', + 2 => 'Airplanes', + 3 => 'Trains', + 4 => 'Birds', + 5 => 'Dogs & Cats', + },{ + 0 => 'Object Not Found', + 1 => 'Object Found', + }], + }, 0x400 => { #6 Name => 'FlashMode', Writable => 'int16u', @@ -2090,6 +2152,11 @@ my %indexInfo = ( 67 => 'Soft Background Shot', #11 142 => 'Hand-held Starlight', #PH (SH-21) 154 => 'HDR', #PH (XZ-2) + 197 => 'Panning', #forum11631 (EM5iii) + 203 => 'Light Trails', #forum11631 (EM5iii) + 204 => 'Backlight HDR', #forum11631 (EM5iii) + 205 => 'Silent', #forum11631 (EM5iii) + 206 => 'Multi Focus Shot', #forum11631 (EM5iii) }, }, 0x50a => { #PH/4/6 @@ -2448,7 +2515,7 @@ my %indexInfo = ( 3 => 'Bottom to Top', 4 => 'Top to Bottom', ); - return ($a{$a} || "Unknown ($a)") . ', Shot ' . $b; + return(($a{$a} || "Unknown ($a)") . ', Shot ' . $b); }, }, 0x603 => { #PH/4 @@ -2481,10 +2548,38 @@ my %indexInfo = ( Count => 2, PrintConv => { '0 0' => 'No', + '1 *' => 'Live Composite (* images)', #24 + '4 *' => 'Live Time/Bulb (* images)', #24 + '3 2' => 'ND2 (1EV)', #IB + '3 4' => 'ND4 (2EV)', #IB + '3 8' => 'ND8 (3EV)', #IB + '3 16' => 'ND16 (4EV)', #IB + '3 32' => 'ND32 (5EV)', #IB + '3 64' => 'ND64 (6EV)', #forum13341 '5 4' => 'HDR1', #forum8906 '6 4' => 'HDR2', #forum8906 - #'8 8' - seen this for the E-M1mkII - '9 8' => 'Focus-stacked (8 images)', + '8 8' => 'Tripod high resolution', #IB + '9 *' => 'Focus-stacked (* images)', #IB (* = 2-15) + '11 12' => 'Hand-held high resolution (11 12)', #forum13341 (OM-1) + '11 16' => 'Hand-held high resolution (11 16)', #IB (perhaps '11 15' would be possible, ref 24) + OTHER => sub { + my ($val, $inv, $conv) = @_; + if ($inv) { + $val = lc $val; + return undef unless $val =~ s/(\d+) images/\* images/; + my $num = $1; + foreach (keys %$conv) { + next unless $val eq lc $$conv{$_}; + ($val = $_) =~ s/\*/$num/ or return undef; + return $val; + } + } else { + return "Unknown ($_[0])" unless $val =~ s/ (\d+)/ \*/ and $$conv{$val}; + my $num = $1; + ($val = $$conv{$val}) =~ s/\*/$num/; + return $val; + } + }, }, }, 0x900 => { #11 @@ -2845,6 +2940,7 @@ my %indexInfo = ( Count => 2, PrintConv => [{ 0 => 'Off', + 1 => 'Live Composite', #github issue#61 2 => 'On (2 frames)', 3 => 'On (3 frames)', }], @@ -3161,7 +3257,7 @@ my %indexInfo = ( Writable => 'int16s', RawConv => '($val and $val ne "-32768") ? $val : undef', # ignore 0 and -32768 # ValueConv => '-2*(($val/135)**2)+55', #11 - ValueConv => '84 - 3 * $val / 26', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,5423.0.html + ValueConv => '84 - 3 * $val / 26', #https://exiftool.org/forum/index.php/topic,5423.0.html ValueConvInv => 'int((84 - $val) * 26 / 3 + 0.5)', PrintConv => 'sprintf("%.1f C",$val)', PrintConvInv => '$val=~s/ ?C$//; $val', @@ -3354,7 +3450,7 @@ my %indexInfo = ( 0x2a => { Name => 'FNumber', Format => 'rational64u', - PrintConv => 'sprintf("%.1f",$val)', + PrintConv => 'Image::ExifTool::Exif::PrintFNumber($val)', }, 0x32 => { #(NC) Name => 'ExposureCompensation', @@ -3400,7 +3496,7 @@ my %indexInfo = ( 0x3a => { Name => 'FNumber', Format => 'rational64u', - PrintConv => 'sprintf("%.1f",$val)', + PrintConv => 'Image::ExifTool::Exif::PrintFNumber($val)', }, 0x42 => { #(NC) Name => 'ExposureCompensation', @@ -3451,7 +3547,7 @@ my %indexInfo = ( 0x28 => { Name => 'FNumber', Format => 'rational64u', - PrintConv => 'sprintf("%.1f",$val)', + PrintConv => 'Image::ExifTool::Exif::PrintFNumber($val)', }, 0x30 => { #(NC) Name => 'ExposureCompensation', @@ -3533,6 +3629,10 @@ my %indexInfo = ( Format => 'string[24]', Groups => { 2 => 'Time' }, }, + 0x17f => { + Name => 'LensModel', + Format => 'string[32]' + }, ); # yet a different "thmb" atom format (PH, E-M5) @@ -3664,10 +3764,11 @@ my %indexInfo = ( 0x5a => { Name => 'FNumber', Format => 'rational64u', - PrintConv => 'sprintf("%.1f",$val)', + PrintConv => 'Image::ExifTool::Exif::PrintFNumber($val)', }, 0x7f => { Name => 'DateTimeOriginal', #(NC) + Description => 'Date/Time Original', Format => 'string[24]', Groups => { 2 => 'Time' }, PrintConv => '$self->ConvertDateTime($val)', @@ -3708,7 +3809,7 @@ my %indexInfo = ( 0x5e => { Name => 'FNumber', Format => 'rational64u', - PrintConv => 'sprintf("%.1f",$val)', + PrintConv => 'Image::ExifTool::Exif::PrintFNumber($val)', }, 0x83 => { Name => 'DateTime1', @@ -3871,6 +3972,17 @@ my %indexInfo = ( Image::ExifTool::Exif::ExtractImage($self,$val[0],$val[1],"ZoomedPreviewImage"); }, }, + # this is actually for PanasonicRaw tags, but it uses the lens lookup here + LensType => { + Require => { + 0 => 'LensTypeMake', + 1 => 'LensTypeModel', + }, + Notes => 'based on tags found in some Panasonic RW2 images', + SeparateTable => 'Olympus LensType', + ValueConv => '"$val[0] $val[1]"', + PrintConv => \%olympusLensTypes, + }, ); # add our composite tags @@ -3898,7 +4010,7 @@ sub ExtenderStatus($$$) $lensType =~ / F(\d+(\.\d+)?)/ or return 1; # If the maximum aperture at the maximum focal length is greater than the # known max/max aperture of the lens, then the extender must be attached - return ($maxAperture - $1 > 0.2) ? 1 : 2; + return(($maxAperture - $1 > 0.2) ? 1 : 2); } #------------------------------------------------------------------------------ @@ -3979,7 +4091,7 @@ Olympus or Epson maker notes in EXIF information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/OpenEXR.pm b/src/Image-ExifTool/lib/Image/ExifTool/OpenEXR.pm index cf1d67b5..3971a136 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/OpenEXR.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/OpenEXR.pm @@ -15,7 +15,7 @@ use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::GPS; -$VERSION = '1.02'; +$VERSION = '1.03'; # supported EXR value format types (other types are extracted as undef binary data) my %formatType = ( @@ -62,7 +62,7 @@ my %formatType = ( Groups => { 2 => 'Location' }, PrintConv => q{ $val = int($val * 10) / 10; - return ($val =~ s/^-// ? "$val m Below" : "$val m Above") . " Sea Level"; + return(($val =~ s/^-// ? "$val m Below" : "$val m Above") . " Sea Level"); }, }, aperture => { PrintConv => 'sprintf("%.1f",$val)' }, @@ -70,6 +70,7 @@ my %formatType = ( chromaticities => { }, capDate => { Name => 'DateTimeOriginal', + Description => 'Date/Time Original', Groups => { 2 => 'Time' }, PrintConv => '$self->ConvertDateTime($val)', }, @@ -158,7 +159,7 @@ sub ProcessEXR($$) my $raf = $$dirInfo{RAF}; my $verbose = $et->Options('Verbose'); my $binary = $et->Options('Binary') || $verbose; - my ($buff, $buf2, $dim); + my ($buff, $dim); # verify this is a valid RIFF file return 0 unless $raf->Read($buff, 8) == 8; @@ -171,12 +172,13 @@ sub ProcessEXR($$) my $ver = unpack('x4V', $buff); $et->HandleTag($tagTablePtr, '_ver', $ver & 0xff); $et->HandleTag($tagTablePtr, '_lay', $ver & 0x200); + my $maxLen = ($ver & 0x400) ? 255 : 31; # extract attributes for (;;) { $raf->Read($buff, 68) or last; last if $buff =~ /^\0/; - unless ($buff =~ /^([^\0]{1,31})\0([^\0]{1,31})\0(.{4})/sg) { + unless ($buff =~ /^([^\0]{1,$maxLen})\0([^\0]{1,$maxLen})\0(.{4})/sg) { $et->Warn('EXR format error'); last; } @@ -188,6 +190,7 @@ sub ProcessEXR($$) my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); unless ($tagInfo) { my $name = ucfirst $tag; + $name =~ s/([^a-zA-Z])([a-z])/$1\U$2/g; # capitalize first letter of each word $name =~ tr/-_a-zA-Z0-9//dc; if (length $name <= 1) { if (length $name) { @@ -196,7 +199,7 @@ sub ProcessEXR($$) $name = 'Invalid'; } } - $tagInfo = { Name => $name, WasAdded => 1 }; + $tagInfo = { Name => $name }; AddTagToTable($tagTablePtr, $tag, $tagInfo); $et->VPrint(0, $$et{INDENT}, "[adding $tag]\n"); } @@ -301,7 +304,7 @@ information from OpenEXR images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Opus.pm b/src/Image-ExifTool/lib/Image/ExifTool/Opus.pm new file mode 100644 index 00000000..2c157e9c --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/Opus.pm @@ -0,0 +1,98 @@ +#------------------------------------------------------------------------------ +# File: Opus.pm +# +# Description: Read Ogg Opus audio meta information +# +# Revisions: 2016/07/14 - P. Harvey Created +# +# References: 1) https://www.opus-codec.org/docs/ +# 2) https://wiki.xiph.org/OggOpus +# 3) https://tools.ietf.org/pdf/rfc7845.pdf +#------------------------------------------------------------------------------ + +package Image::ExifTool::Opus; + +use strict; +use vars qw($VERSION); + +$VERSION = '1.00'; + +# Opus metadata types +%Image::ExifTool::Opus::Main = ( + NOTES => q{ + Information extracted from Ogg Opus files. See + L<https://www.opus-codec.org/docs/> for the specification. + }, + 'OpusHead' => { + Name => 'Header', + SubDirectory => { TagTable => 'Image::ExifTool::Opus::Header' }, + }, + 'OpusTags' => { + Name => 'Comments', + SubDirectory => { TagTable => 'Image::ExifTool::Vorbis::Comments' }, + }, +); + +%Image::ExifTool::Opus::Header = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Audio' }, + 0 => 'OpusVersion', + 1 => 'AudioChannels', + # 2 => 'PreSkip' (int16u) + 4 => { + Name => 'SampleRate', + Format => 'int32u', + }, + 8 => { + Name => 'OutputGain', + Format => 'int16u', + ValueConv => '10 ** ($val/5120)', + }, +); + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::Opus - Read Ogg Opus audio meta information + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to extract meta +information from Ogg Opus audio files. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<https://www.opus-codec.org/docs/> + +=item L<https://wiki.xiph.org/OggOpus> + +=item L<https://tools.ietf.org/pdf/rfc7845.pdf> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/Opus Tags>, +L<Image::ExifTool::TagNames/Ogg Tags>, +L<Image::ExifTool::TagNames/Vorbis Tags>, +L<Image::ExifTool::TagNames/FLAC Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Other.pm b/src/Image-ExifTool/lib/Image/ExifTool/Other.pm new file mode 100644 index 00000000..133aac08 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/Other.pm @@ -0,0 +1,93 @@ +#------------------------------------------------------------------------------ +# File: Other.pm +# +# Description: Read meta information from other uncommon formats +# +# Revisions: 2021/07/16 - P. Harvey Created +# +# References: 1) PFM - http://www.pauldebevec.com/Research/HDR/PFM/ +#------------------------------------------------------------------------------ + +package Image::ExifTool::Other; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); +use Image::ExifTool::Exif; + +$VERSION = '1.00'; + +# Other info +%Image::ExifTool::Other::PFM = ( + GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' }, + VARS => { NO_ID => 1 }, + NOTES => q{ + Tags extracted from Portable FloatMap images. See + L<http://www.pauldebevec.com/Research/HDR/PFM/> for the specification. + }, + ColorSpace => { PrintConv => { PF => 'RGB', 'Pf' => 'Monochrome'} }, + ImageWidth => { }, + ImageHeight => { }, + ByteOrder => { PrintConv => '$val > 0 ? "Big-endian" : "Little-endian"' }, +); + +#------------------------------------------------------------------------------ +# Extract information from a Portable FloatMap image +# Inputs: 0) ExifTool object reference, 1) dirInfo reference +# Returns: 1 on success, 0 if this wasn't a valid PFM file +sub ProcessPFM2($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my $buff; + return 0 unless $raf->Read($buff, 256) and $buff =~ /^(P[Ff])\x0a(\d+) (\d+)\x0a([-+0-9.]+)\x0a/; + $et->SetFileType('PFM', 'image/x-pfm'); + my $tagTablePtr = GetTagTable('Image::ExifTool::Other::PFM'); + $et->HandleTag($tagTablePtr, ColorSpace => $1); + $et->HandleTag($tagTablePtr, ImageWidth => $2); + $et->HandleTag($tagTablePtr, ImageHeight => $3); + $et->HandleTag($tagTablePtr, ByteOrder => $4); + # hack to set proper file description (extension is the same for Printer Font Metrics files) + $Image::ExifTool::static_vars{OverrideFileDescription}{PFM} = 'Portable FloatMap', + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::Other - Read meta information from other uncommon formats + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains routines required by Image::ExifTool to extract +information from Portable FloatMap (PFM) images. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item PFM L<http://www.pauldebevec.com/Research/HDR/PFM/> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/Other Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PCX.pm b/src/Image-ExifTool/lib/Image/ExifTool/PCX.pm new file mode 100644 index 00000000..d54d871d --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/PCX.pm @@ -0,0 +1,138 @@ +#------------------------------------------------------------------------------ +# File: PCX.pm +# +# Description: Read metadata from PC Paintbrush files +# +# Revisions: 2018/12/12 - P. Harvey Created +# +# References: 1) http://qzx.com/pc-gpe/pcx.txt +# 2) https://www.fileformat.info/format/pcx/corion.htm +#------------------------------------------------------------------------------ + +package Image::ExifTool::PCX; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.00'; + +# PCX info +%Image::ExifTool::PCX::Main = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' }, + NOTES => 'Tags extracted from PC Paintbrush images.', + DATAMEMBER => [ 0x04, 0x05 ], + 0x00 => { + Name => 'Manufacturer', + PrintConv => { 10 => 'ZSoft' }, + }, + 0x01 => { + Name => 'Software', + PrintConv => { + 0 => 'PC Paintbrush 2.5', + 2 => 'PC Paintbrush 2.8 (with palette)', + 3 => 'PC Paintbrush 2.8 (without palette)', + 4 => 'PC Paintbrush for Windows', + 5 => 'PC Paintbrush 3.0+', + }, + }, + 0x02 => { Name => 'Encoding', PrintConv => { 1 => 'RLE' } }, + 0x03 => 'BitsPerPixel', + 0x04 => { + Name => 'LeftMargin', + Format => 'int16u', + RawConv => '$$self{LeftMargin} = $val', + }, + 0x06 => { + Name => 'TopMargin', + Format => 'int16u', + RawConv => '$$self{TopMargin} = $val', + }, + 0x08 => { + Name => 'ImageWidth', + Format => 'int16u', + Notes => 'adjusted for LeftMargin', + ValueConv => '$val - $$self{LeftMargin} + 1', + }, + 0x0a => { + Name => 'ImageHeight', + Format => 'int16u', + Notes => 'adjusted for TopMargin', + ValueConv => '$val - $$self{TopMargin} + 1', + }, + 0x0c => 'XResolution', + 0x0e => 'YResolution', + 0x41 => 'ColorPlanes', + 0x42 => { Name => 'BytesPerLine', Format => 'int16u' }, + 0x44 => { + Name => 'ColorMode', + PrintConv => { + 0 => 'n/a', + 1 => 'Color Palette', + 2 => 'Grayscale', + }, + }, + 0x46 => { Name => 'ScreenWidth', Format => 'int16u', RawConv => '$val or undef' }, + 0x48 => { Name => 'ScreenHeight', Format => 'int16u', RawConv => '$val or undef' }, +); + +#------------------------------------------------------------------------------ +# Extract information from a PCX image +# Inputs: 0) ExifTool object reference, 1) dirInfo reference +# Returns: 1 on success, 0 if this wasn't a valid PCX file +sub ProcessPCX($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my $buff; + return 0 unless $raf->Read($buff, 0x50) == 0x50 and + $buff =~ /^\x0a[\0-\x05]\x01[\x01\x02\x04\x08].{64}[\0-\x02]/s; + SetByteOrder('II'); + $et->SetFileType(); + my %dirInfo = ( DirName => 'PCX', DataPt => \$buff ); + my $tagTablePtr = GetTagTable('Image::ExifTool::PCX::Main'); + return $et->ProcessBinaryData(\%dirInfo, $tagTablePtr); +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::PCX - Read metadata from PC Paintbrush files + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains routines required by Image::ExifTool to extract +information from PC Paintbrush (PCX) files. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<http://qzx.com/pc-gpe/pcx.txt> + +=item L<https://www.fileformat.info/format/pcx/corion.htm> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/PCX Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PDF.pm b/src/Image-ExifTool/lib/Image/ExifTool/PDF.pm index 2dd97200..1e580c1e 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/PDF.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/PDF.pm @@ -21,7 +21,7 @@ use vars qw($VERSION $AUTOLOAD $lastFetched); use Image::ExifTool qw(:DataAccess :Utils); require Exporter; -$VERSION = '1.46'; +$VERSION = '1.55'; sub FetchObject($$$$); sub ExtractObject($$;$$); @@ -95,7 +95,7 @@ my %supportedFilter = ( WRITABLE => 'string', # set PRIORITY to 0 so most recent Info dictionary takes precedence # (Acrobat Pro bug? doesn't use same object/generation number for - # new Info dictionary when doing incrmental update) + # new Info dictionary when doing incremental update) PRIORITY => 0, NOTES => q{ As well as the tags listed below, the PDF specification allows for @@ -271,9 +271,21 @@ my %supportedFilter = ( %Image::ExifTool::PDF::ColorSpace = ( DefaultRGB => { SubDirectory => { TagTable => 'Image::ExifTool::PDF::DefaultRGB' }, + ConvertToDict => 1, # (not seen yet, but just in case) + }, + DefaultCMYK => { + SubDirectory => { TagTable => 'Image::ExifTool::PDF::DefaultRGB' }, + # hack: this is stored as an array instead of a dictionary in my + # sample, so convert to a dictionary to extract the ICCBased element + ConvertToDict => 1, }, Cs1 => { - SubDirectory => { TagTable => 'Image::ExifTool::PDF::Cs1' }, + SubDirectory => { TagTable => 'Image::ExifTool::PDF::DefaultRGB' }, + ConvertToDict => 1, # (just in case) + }, + CS0 => { + SubDirectory => { TagTable => 'Image::ExifTool::PDF::DefaultRGB' }, + ConvertToDict => 1, # (just in case) }, ); @@ -284,14 +296,7 @@ my %supportedFilter = ( }, ); -# tags in PDF Cs1 dictionary -%Image::ExifTool::PDF::Cs1 = ( - _stream => { - SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' }, - }, -); - -# tags in PDF ICCBased dictionary +# tags in PDF ICCBased, Cs1 and CS0 dictionaries %Image::ExifTool::PDF::ICCBased = ( _stream => { SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main' }, @@ -303,7 +308,7 @@ my %supportedFilter = ( EXTRACT_UNKNOWN => 0, # extract known but numbered tags (Im1, Im2, etc) Im => { Notes => q{ - the ExtractEmbedded option enables information to be extracted from these + the L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> option enables information to be extracted from these embedded images }, SubDirectory => { TagTable => 'Image::ExifTool::PDF::Im' }, @@ -313,7 +318,7 @@ my %supportedFilter = ( # tags in PDF Im# dictionary %Image::ExifTool::PDF::Im = ( NOTES => q{ - Information extracted from embedded images with the ExtractEmbedded option. + Information extracted from embedded images with the L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> option. The EmbeddedImage and its metadata are extracted only for JPEG and Jpeg2000 image formats. }, @@ -337,7 +342,7 @@ my %supportedFilter = ( EXTRACT_UNKNOWN => 0, # extract known but numbered tags (MC0, MC1, etc) MC => { Notes => q{ - the ExtractEmbedded option enables information to be extracted from these + the L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> option enables information to be extracted from these embedded metadata dictionaries }, SubDirectory => { TagTable => 'Image::ExifTool::PDF::MC' }, @@ -397,7 +402,7 @@ my %supportedFilter = ( }, AIPrivateData => { Notes => q{ - the ExtractEmbedded option enables information to be extracted from embedded + the L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> option enables information to be extracted from embedded PostScript documents in the AIPrivateData# and AIPDFPrivateData# streams }, JoinStreams => 1, # join streams from numbered tags and process as one @@ -684,6 +689,44 @@ sub LocateObject($$) return $offset; } +#------------------------------------------------------------------------------ +# Check that the correct object is located at the specified file offset +# Inputs: 0) ExifTool ref, 1) object name, 2) object reference string, 3) file offset +# Returns: first non-blank line at start of object, or undef on error +sub CheckObject($$$$) +{ + my ($et, $tag, $ref, $offset) = @_; + my ($data, $obj, $dat, $pat); + + my $raf = $$et{RAF}; + $raf->Seek($offset+$$et{PDFBase}, 0) or $et->Warn("Bad $tag offset"), return undef; + # verify that we are reading the expected object + ($obj = $ref) =~ s/R/obj/; + for (;;) { + $raf->ReadLine($data) or $et->Warn("Error reading $tag data"), return undef; + last if $data =~ s/^$obj//; + next if $data =~ /^\s+$/; # keep reading if this was a blank line + # handle cases where other whitespace characters are used in the object ID string + while ($data =~ /^\d+(\s+\d+)?\s*$/) { + $raf->ReadLine($dat); + $data .= $dat; + } + ($pat = $obj) =~ s/ /\\s+/g; + unless ($data =~ s/$pat//) { + $tag = ucfirst $tag; + $et->Warn("$tag object ($obj) not found at offset $offset"); + return undef; + } + last; + } + # read the first line of data from the object (ignoring blank lines and comments) + for (;;) { + last if $data =~ /\S/ and $data !~ /^\s*%/; + $raf->ReadLine($data) or $et->Warn("Error reading $tag data"), return undef; + } + return $data; +} + #------------------------------------------------------------------------------ # Fetch indirect object from file (from inside a stream if required) # Inputs: 0) ExifTool object reference, 1) object reference string, @@ -737,7 +780,7 @@ sub FetchObject($$$$) return undef; } # extract the object at the specified index in the stream - # (offsets in table are in sequential order, so we can subract from + # (offsets in table are in sequential order, so we can subtract from # the next offset to get the object length) $offset = $$table[$i + 1]; my $len = ($$table[$i + 3] || length($$obj{_stream})) - $offset; @@ -746,21 +789,11 @@ sub FetchObject($$$$) undef $lastFetched if $cryptStream; return ExtractObject($et, \$data); } - my $raf = $$et{RAF}; - $raf->Seek($offset+$$et{PDFBase}, 0) or $et->Warn("Bad $tag offset"), return undef; - # verify that we are reading the expected object - $raf->ReadLine($data) or $et->Warn("Error reading $tag data"), return undef; - ($obj = $ref) =~ s/R/obj/; - unless ($data =~ s/^$obj//) { - $et->Warn("$tag object ($obj) not found at $offset"); - return undef; - } - # read the first line of data for the object (skipping comments if necessary) - for (;;) { - last if $data =~ /\S/ and $data !~ /^\s*%/; - $raf->ReadLine($data) or $et->Warn("Error reading $tag data"), return undef; - } - return ExtractObject($et, \$data, $raf, $xref); + # load the start of the object + $data = CheckObject($et, $tag, $ref, $offset); + return undef unless defined $data; + + return ExtractObject($et, \$data, $$et{RAF}, $xref); } #------------------------------------------------------------------------------ @@ -948,22 +981,11 @@ sub ExtractObject($$;$$) # get the location of the object specifying the length # (compressed objects are not allowed) my $offset = LocateObject($xref, $length) or return $dict; - $offset or $et->Warn('Bad Length object'), return $dict; - $raf->Seek($offset+$$et{PDFBase}, 0) or $et->Warn('Bad Length offset'), return $dict; - # verify that we are reading the expected object - $raf->ReadLine($data) or $et->Warn('Error reading Length data'), return $dict; - $length =~ s/R/obj/; - unless ($data =~ /^$length\s+(\d+)?/) { - $et->Warn("Length object ($length) not found at $offset"); - return $dict; - } - if (defined $1) { - $length = $1; - } else { - $raf->ReadLine($data) or $et->Warn('Error reading stream Length'), return $dict; - $data =~ /^\s*(\d+)/ or $et->Warn('Stream length not found'), return $dict; - $length = $1; - } + $offset or $et->Warn('Bad stream Length object'), return $dict; + $data = CheckObject($et, 'stream Length', $length, $offset); + defined $data or return $dict; + $data =~ /^\s*(\d+)/ or $et->Warn('Stream Length not found'), return $dict; + $length = $1; $raf->Seek($oldpos, 0); # restore position to start of stream } # extract the trailing stream data @@ -1869,7 +1891,15 @@ sub ProcessDict($$$$;$$) # process the subdirectory my @subDicts; if (ref $val eq 'ARRAY') { - @subDicts = @{$val}; + # hack to convert array to dictionary if necessary + if ($$tagInfo{ConvertToDict} and @$val == 2 and not ref $$val[0]) { + my $tg = $$val[0]; + $tg =~ s(^/)(); # remove name + my %dict = ( _tags => [ $tg ], $tg => $$val[1] ); + @subDicts = ( \%dict ); + } else { + @subDicts = @{$val}; + } } else { @subDicts = ( $val ); } @@ -1957,16 +1987,17 @@ sub ProcessDict($$$$;$$) } else { $val = ReadPDFValue($val); } - # convert from UTF-16 (big endian) to UTF-8 or Latin if necessary - # unless this is binary data (hex-encoded strings would not have been converted) if (ref $val) { if (ref $val eq 'ARRAY') { + delete $$et{LIST_TAGS}{$tagInfo} if $$tagInfo{List}; my $v; foreach $v (@$val) { $et->FoundTag($tagInfo, $v); } } } elsif (defined $val) { + # convert from UTF-16 (big endian) to UTF-8 or Latin if necessary + # unless this is binary data (hex-encoded strings would not have been converted) my $format = $$tagInfo{Format} || $$tagInfo{Writable} || 'string'; $val = ConvertPDFDate($val) if $format eq 'date'; if (not $$tagInfo{Binary} and $val =~ /[\x18-\x1f\x80-\xff]/) { @@ -2089,7 +2120,7 @@ sub ReadPDF($$) $$et{PDFBase} = length $1 and $et->Warn('PDF header is not at start of file',1); $pdfVer = $2; $et->SetFileType(); # set the FileType tag - $et->Warn("May not be able to read a PDF version $pdfVer file") if $pdfVer >= 2.0; + $et->Warn("The PDF $pdfVer specification is held hostage by the ISO") if $pdfVer >= 2.0; # store PDFVersion tag my $tagTablePtr = GetTagTable('Image::ExifTool::PDF::Root'); $et->HandleTag($tagTablePtr, 'Version', $pdfVer); @@ -2132,6 +2163,7 @@ sub ReadPDF($$) # set input record separator local $/ = $ws =~ /(\x0d\x0a|\x0d|\x0a)/ ? $1 : "\x0a"; my (%xref, @mainDicts, %loaded, $mainFree); + my ($xrefSize, $mainDictSize) = (0, 0); # initialize variables to capture when rewriting if ($capture) { $capture->{startxref} = $xr; @@ -2174,6 +2206,10 @@ XRef: $raf->Read($buff, 20) == 20 or return -6; $buff =~ /^\s*(\d{10}) (\d{5}) (f|n)/s or return -4; my $num = $start + $i; + $xrefSize = $num if $num > $xrefSize; + # locate object to generate entry from stream if necessary + # (must do this before we test $xref{$num}) + LocateAnyObject(\%xref, $num) if $xref{dicts}; # save offset for newest copy of all objects # (or next object number for free objects) unless (defined $xref{$num}) { @@ -2207,6 +2243,8 @@ XRef: $et->Warn('Error loading secondary dictionary'); next; } + # keep track of total trailer dictionary Size + $mainDictSize = $$mainDict{Size} if $$mainDict{Size} and $$mainDict{Size} > $mainDictSize; if ($loadXRefStream) { # decode and save our XRef stream from PDF-1.5 file # (but parse it later as required to save time) @@ -2238,6 +2276,7 @@ XRef: # load XRef stream in hybrid file if it exists push @xrefOffsets, $$mainDict{XRefStm}, 'XRefStm' if $$mainDict{XRefStm}; $encrypt = $$mainDict{Encrypt} if $$mainDict{Encrypt}; + undef $encrypt if $encrypt and $encrypt eq 'null'; # (have seen "null") if ($$mainDict{ID} and ref $$mainDict{ID} eq 'ARRAY') { $id = ReadPDFValue($mainDict->{ID}->[0]); } @@ -2245,6 +2284,10 @@ XRef: # load previous xref table if it exists push @xrefOffsets, $$mainDict{Prev}, 'Prev' if $$mainDict{Prev}; } + if ($xrefSize > $mainDictSize) { + my $str = "Objects in xref table ($xrefSize) exceed trailer dictionary Size ($mainDictSize)"; + $capture ? $et->Error($str) : $et->Warn($str); + } # # extract encryption information if necessary # @@ -2346,7 +2389,7 @@ including AESV2 (AES-128) and AESV3 (AES-256). =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PGF.pm b/src/Image-ExifTool/lib/Image/ExifTool/PGF.pm index 8c525378..15fbf89c 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/PGF.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/PGF.pm @@ -119,7 +119,7 @@ information from Progressive Graphics File (PGF) images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PICT.pm b/src/Image-ExifTool/lib/Image/ExifTool/PICT.pm index 776883d8..5dcde5db 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/PICT.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/PICT.pm @@ -1095,13 +1095,13 @@ sub ProcessPICT($$) @hdr = unpack('x2n5', $buff); $op = pop @hdr; # check for PICT version 1 format - if ($op eq 0x1101) { + if ($op == 0x1101) { $vers = 1; undef $extended; last; } # check for PICT version 2 format - if ($op eq 0x0011) { + if ($op == 0x0011) { $raf->Read($buff, 28) == 28 or return 0; if ($buff =~ /^\x02\xff\x0c\x00\xff\xff/) { $vers = 2; @@ -1174,7 +1174,7 @@ sub ProcessPICT($$) } last unless $tagInfo; } - if ($op eq 0xff) { + if ($op == 0xff) { $verbose and print $out "End of picture\n"; $success = 1; last; @@ -1236,7 +1236,7 @@ Verbose or the Unknown option. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PLIST.pm b/src/Image-ExifTool/lib/Image/ExifTool/PLIST.pm index 53dfcfe8..32d8801e 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/PLIST.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/PLIST.pm @@ -438,7 +438,7 @@ This module decodes both the binary and XML-based PLIST format. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PLUS.pm b/src/Image-ExifTool/lib/Image/ExifTool/PLUS.pm new file mode 100644 index 00000000..c9844fa5 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/PLUS.pm @@ -0,0 +1,2607 @@ +#------------------------------------------------------------------------------ +# File: PLUS.pm +# +# Description: PLUS (Picture Licensing Universal System) tags +# +# Revisions: 2016/05/18 - P. Harvey Created +# +# References: 1) http://www.useplus.com/useplus/standards.asp +#------------------------------------------------------------------------------ + +package Image::ExifTool::PLUS; + +use strict; +use vars qw($VERSION); +use Image::ExifTool::XMP; + +$VERSION = '1.00'; + +sub ValidateMediaSummary($); + +#------------------------------------------------------------------------------ +# PLUS (Picture Licensing Universal System) + +# PLUS vocabulary conversions +my %plusVocab = ( + ValueConv => '$val =~ s{http://ns.useplus.org/ldf/vocab/}{}; $val', + ValueConvInv => '"http://ns.useplus.org/ldf/vocab/$val"', +); + +# PLUS License Data Format 1.2.1 structures +# (this seems crazy to me -- why did they define different ID/Name structures +# for each field rather than just re-using the same structure?) +my %plusLicensee = ( + STRUCT_NAME => 'Licensee', + NAMESPACE => 'plus', + # all "rdf:type" properties removed in version 1.2.1 + # (idiots. Why did they put them there in the first place? -- it required + # a special patch for ExifTool to support these, and now they are gone!) + # TYPE => 'plus:LicenseeDetail', (removed in 1.2.1) + LicenseeID => { }, + LicenseeName=> { }, +); +my %plusEndUser = ( + STRUCT_NAME => 'EndUser', + NAMESPACE => 'plus', + # TYPE => 'plus:EndUserDetail', (removed in 1.2.1) + EndUserID => { }, + EndUserName => { }, +); +my %plusLicensor = ( + STRUCT_NAME => 'Licensor', + NAMESPACE => 'plus', + # TYPE => 'plus:LicensorDetail', (removed in 1.2.1) + LicensorID => { }, + LicensorName => { }, + LicensorStreetAddress => { }, + LicensorExtendedAddress => { }, + LicensorCity => { }, + LicensorRegion => { }, + LicensorPostalCode => { }, + LicensorCountry => { }, + LicensorTelephoneType1 => { + %plusVocab, + PrintConv => { + 'work' => 'Work', + 'cell' => 'Cell', + 'fax' => 'FAX', + 'home' => 'Home', + 'pager' => 'Pager', + }, + }, + LicensorTelephone1 => { }, + LicensorTelephoneType2 => { + %plusVocab, + PrintConv => { + 'work' => 'Work', + 'cell' => 'Cell', + 'fax' => 'FAX', + 'home' => 'Home', + 'pager' => 'Pager', + }, + }, + LicensorTelephone2 => { }, + LicensorEmail => { }, + LicensorURL => { }, +); +my %plusCopyrightOwner = ( + STRUCT_NAME => 'CopyrightOwner', + NAMESPACE => 'plus', + # TYPE => 'plus:CopyrightOwnerDetail', (removed in 1.2.1) + CopyrightOwnerID => { }, + CopyrightOwnerName => { }, +); +my %plusImageCreator = ( + STRUCT_NAME => 'ImageCreator', + NAMESPACE => 'plus', + # TYPE => 'plus:ImageCreatorDetail', (removed in 1.2.1) + ImageCreatorID => { }, + ImageCreatorName => { }, +); +my %plusImageSupplier = ( + STRUCT_NAME => 'ImageSupplier', + NAMESPACE => 'plus', + # TYPE => 'plus:ImageSupplierDetail', (removed in 1.2.1) + ImageSupplierID => { }, + ImageSupplierName => { }, +); + +# Media Matrix 1.1.1 decoding +my %mediaMatrix = ( + Notes => q{ + The lookup below is used to add human-readable descriptions to Media Matrix + ID's in PLUS Media Summary Codes. + }, + OTHER => sub { + my ($val, $inv, $conv) = @_; + $val = uc $val; # convert to upper case + if ($inv) { + # prepare MediaSummaryCode for writing + $val =~ s/\(.*?\)//sg; # remove descriptions + $val =~ s/^\s*?PLUS\s+(V[0-9]+)\s+(U[0-9]+)\s*;/|PLUS|$1|$2|/s; # reformat header + $val =~ tr/;/|/; # use "|" as separator instead of ";" + $val =~ tr/0-9A-Z|//dc; # remove extraneous characters + $val .= '|' unless $val =~ /\|$/; # add terminating "|" + ValidateMediaSummary($val) or return undef; + } elsif ($val =~ /^\|PLUS\|(.*?)\|(.*?)\|(.*)/s) { + # add human-readable descriptions + my ($ver,$num,$code) = ($1,$2,$3); + $ver .= " (LDF Version $1.$2)" if $ver =~ /V0*(\d+)(\d{2})$/; + $num .= " ($1 Media Usages:)" if $num =~ /U0*(\d+)/; + $code =~ tr/0-9A-Z|//dc; # remove extraneous characters + $val = "PLUS $ver $num"; + while ($code =~ /(\d[A-Z]{3})/g) { + my $mmid = $1; + if (defined $$conv{$mmid}) { + $val .= " $mmid ($$conv{$mmid})"; + } elsif ($mmid =~ /^1I([A-Z])([A-Z])/) { # decode Usage Item count + my $n = (ord($1)-65) * 26 + ord($2)-65 + 1; + # (add a separator before each new Media Usage Code) + $val .= "; $mmid ($n Usage Items:)"; + } elsif ($mmid =~ /^1UN([A-Z])/) { # decode Usage Number + $val .= " (Usage Number $1)"; + } else { + $val .= " $mmid"; + } + } + } + return $val; + }, + # 1 - Usage + '1IAA' => '1 Usage Item:', + '1IAB' => '2 Usage Items:', + '1IAC' => '3 Usage Items:', + '1IAD' => '4 Usage Items:', + '1IAE' => '5 Usage Items:', + # ... + '1UNA' => 'Usage Number A', + '1UNB' => 'Usage Number B', + '1UNC' => 'Usage Number C', + '1UND' => 'Usage Number D', + '1UNE' => 'Usage Number E', + # ... + # 2 - Media + '2BOB' => 'Advertising|Periodicals|Magazine, Consumer|Printed', + '2ACE' => 'Advertising|Periodicals|Magazine, Consumer|Internet Website', + '2GEN' => 'Advertising|Periodicals|Magazine, Consumer|Internet Downloadable File', + '2ADS' => 'Advertising|Periodicals|Magazine, Consumer|Internet Email', + '2GIB' => 'Advertising|Periodicals|Magazine, Consumer|All Internet Distribution Formats', + '2GHI' => 'Advertising|Periodicals|Magazine, Consumer|Recordable Media', + '2GEY' => 'Advertising|Periodicals|Magazine, Consumer|All Electronic Distribution Formats', + '2HAT' => 'Advertising|Periodicals|Magazine, Trade|Printed', + '2HAG' => 'Advertising|Periodicals|Magazine, Trade|Internet Website', + '2HAE' => 'Advertising|Periodicals|Magazine, Trade|Internet Downloadable File', + '2AFT' => 'Advertising|Periodicals|Magazine, Trade|Internet Email', + '2HAJ' => 'Advertising|Periodicals|Magazine, Trade|All Internet Distribution Formats', + '2AGE' => 'Advertising|Periodicals|Magazine, Trade|Recordable Media', + '2HAH' => 'Advertising|Periodicals|Magazine, Trade|All Electronic Distribution Formats', + '2JAR' => 'Advertising|Periodicals|Magazine, Corporate|Printed', + '2GIN' => 'Advertising|Periodicals|Magazine, Corporate|Internet Website', + '2GIE' => 'Advertising|Periodicals|Magazine, Corporate|Internet Downloadable File', + '2AGO' => 'Advertising|Periodicals|Magazine, Corporate|Internet Email', + '2GNU' => 'Advertising|Periodicals|Magazine, Corporate|All Internet Distribution Formats', + '2GIP' => 'Advertising|Periodicals|Magazine, Corporate|Recordable Media', + '2GIT' => 'Advertising|Periodicals|Magazine, Corporate|All Electronic Distribution Formats', + '2DEB' => 'Advertising|Periodicals|Magazine, Education|Printed', + '2GUM' => 'Advertising|Periodicals|Magazine, Education|Internet Website', + '2GUL' => 'Advertising|Periodicals|Magazine, Education|Internet Downloadable File', + '2AHA' => 'Advertising|Periodicals|Magazine, Education|Internet Email', + '2GYP' => 'Advertising|Periodicals|Magazine, Education|All Internet Distribution Formats', + '2GUV' => 'Advertising|Periodicals|Magazine, Education|Recordable Media', + '2GUY' => 'Advertising|Periodicals|Magazine, Education|All Electronic Distribution Formats', + '2CUS' => 'Advertising|Periodicals|Magazine, Custom Published|Printed', + '2GOR' => 'Advertising|Periodicals|Magazine, Custom Published|Internet Website', + '2GOS' => 'Advertising|Periodicals|Magazine, Custom Published|Internet Downloadable File', + '2AIL' => 'Advertising|Periodicals|Magazine, Custom Published|Internet Email', + '2GOX' => 'Advertising|Periodicals|Magazine, Custom Published|All Internet Distribution Formats', + '2ALP' => 'Advertising|Periodicals|Magazine, Custom Published|Recordable Media', + '2AMI' => 'Advertising|Periodicals|Magazine, Custom Published|All Electronic Distribution Formats', + '2BEN' => 'Advertising|Periodicals|Magazine, Advertorial|Printed', + '2BAP' => 'Advertising|Periodicals|Magazine, Advertorial|Internet Website', + '2BAM' => 'Advertising|Periodicals|Magazine, Advertorial|Internet Downloadable File', + '2BOP' => 'Advertising|Periodicals|Magazine, Advertorial|Internet Email', + '2GOB' => 'Advertising|Periodicals|Magazine, Advertorial|All Internet Distribution Formats', + '2DUH' => 'Advertising|Periodicals|Magazine, Advertorial|All Electronic Distribution Formats', + '2DUP' => 'Advertising|Periodicals|Magazine Reprints, All Types|Printed', + '2HAS' => 'Advertising|Periodicals|Magazine Reprints, All Types|Internet Website', + '2HAP' => 'Advertising|Periodicals|Magazine Reprints, All Types|Internet Downloadable File', + '2AMP' => 'Advertising|Periodicals|Magazine Reprints, All Types|Internet Email', + '2HEH' => 'Advertising|Periodicals|Magazine Reprints, All Types|All Internet Distribution Formats', + '2HAW' => 'Advertising|Periodicals|Magazine Reprints, All Types|Recordable Media', + '2HAY' => 'Advertising|Periodicals|Magazine Reprints, All Types|All Electronic Distribution Formats', + '2MOO' => 'Advertising|Periodicals|Magazine, All Types|Printed', + '2ANA' => 'Advertising|Periodicals|Magazine, All Types|Internet Website', + '2GOO' => 'Advertising|Periodicals|Magazine, All Types|Recordable Media', + '2ANY' => 'Advertising|Periodicals|Magazine, All Types|Internet Downloadable File', + '2APE' => 'Advertising|Periodicals|Magazine, All Types|Internet Email', + '2APT' => 'Advertising|Periodicals|Magazine, All Types|All Internet Distribution Formats', + '2ARK' => 'Advertising|Periodicals|Magazine, All Types|All Electronic Distribution Formats', + '2KEG' => 'Advertising|Periodicals|Newspaper, Weekly Supplement|Printed', + '2HOB' => 'Advertising|Periodicals|Newspaper, Weekly Supplement|Internet Website', + '2HOD' => 'Advertising|Periodicals|Newspaper, Weekly Supplement|Internet Downloadable File', + '2ARM' => 'Advertising|Periodicals|Newspaper, Weekly Supplement|Internet Email', + '2HMM' => 'Advertising|Periodicals|Newspaper, Weekly Supplement|All Internet Distribution Formats', + '2HOE' => 'Advertising|Periodicals|Newspaper, Weekly Supplement|Recordable Media', + '2HIS' => 'Advertising|Periodicals|Newspaper, Weekly Supplement|All Electronic Distribution Formats', + '2KEN' => 'Advertising|Periodicals|Newspaper, Tabloid|Printed', + '2HOY' => 'Advertising|Periodicals|Newspaper, Tabloid|Internet Website', + '2HUH' => 'Advertising|Periodicals|Newspaper, Tabloid|All Internet Distribution Formats', + '2ASH' => 'Advertising|Periodicals|Newspaper, Tabloid|Internet Downloadable File', + '2BAY' => 'Advertising|Periodicals|Newspaper, Tabloid|Internet Email', + '2HUE' => 'Advertising|Periodicals|Newspaper, Tabloid|Recordable Media', + '2HOW' => 'Advertising|Periodicals|Newspaper, Tabloid|All Electronic Distribution Formats', + '2NEW' => 'Advertising|Periodicals|Newspaper, All Types|Printed', + '2HID' => 'Advertising|Periodicals|Newspaper, All Types|Internet Website', + '2HIE' => 'Advertising|Periodicals|Newspaper, All Types|Internet Downloadable File', + '2BED' => 'Advertising|Periodicals|Newspaper, All Types|Internet Email', + '2HIC' => 'Advertising|Periodicals|Newspaper, All Types|All Internet Distribution Formats', + '2HIM' => 'Advertising|Periodicals|Newspaper, All Types|Recordable Media', + '2HEY' => 'Advertising|Periodicals|Newspaper, All Types|All Electronic Distribution Formats', + '2JAY' => 'Advertising|Periodicals|Newsletter, All Types|Printed', + '2HES' => 'Advertising|Periodicals|Newsletter, All Types|Internet Website', + '2HEP' => 'Advertising|Periodicals|Newsletter, All Types|Internet Downloadable File', + '2HEW' => 'Advertising|Periodicals|Newsletter, All Types|All Internet Distribution Formats', + '2BID' => 'Advertising|Periodicals|Newsletter, All Types|Internet Email', + '2HET' => 'Advertising|Periodicals|Newsletter, All Types|Recordable Media', + '2HEN' => 'Advertising|Periodicals|Newsletter, All Types|All Electronic Distribution Formats', + '2BAH' => 'Advertising|Periodicals|Quarterly Report|Printed', + '2HUT' => 'Advertising|Periodicals|Quarterly Report|Internet Website', + '2HUP' => 'Advertising|Periodicals|Quarterly Report|Internet Downloadable File', + '2BAL' => 'Advertising|Periodicals|Quarterly Report|Internet Email', + '2JEE' => 'Advertising|Periodicals|Quarterly Report|All Internet Distribution Formats', + '2HYP' => 'Advertising|Periodicals|Quarterly Report|Recordable Media', + '2JAG' => 'Advertising|Periodicals|Quarterly Report|All Electronic Distribution Formats', + '2ANN' => 'Advertising|Periodicals|Annual Report|Printed', + '2FON' => 'Advertising|Periodicals|Annual Report|Internet Website', + '2FOH' => 'Advertising|Periodicals|Annual Report|Internet Downloadable File', + '2FOP' => 'Advertising|Periodicals|Annual Report|Internet Email', + '2FOY' => 'Advertising|Periodicals|Annual Report|All Internet Distribution Formats', + '2BAS' => 'Advertising|Periodicals|Annual Report|Recordable Media', + '2FOU' => 'Advertising|Periodicals|Annual Report|All Electronic Distribution Formats', + '2KIP' => 'Advertising|Periodicals|Program Advertising|Printed', + '2DEE' => 'Advertising|Periodicals|Wrapper|Printed', + '2FUD' => 'Advertising|Periodicals|Cover Wrap|Printed', + '2FUB' => 'Advertising|Periodicals|Belly Band|Printed', + '2BAT' => 'Advertising|Periodicals|Free Standing Insert, All Insert Types|Printed', + '2HIP' => 'Advertising|Periodicals|Free Standing Insert, Advertorial Insert|Printed', + '2BAG' => 'Advertising|Periodicals|All Periodical Types|Printed', + '2FIZ' => 'Advertising|Periodicals|All Periodical Types|Internet Website', + '2BOD' => 'Advertising|Periodicals|All Periodical Types|Internet Downloadable File', + '2BOW' => 'Advertising|Periodicals|All Periodical Types|Internet Email', + '2FOB' => 'Advertising|Periodicals|All Periodical Types|All Internet Distribution Formats', + '2FIR' => 'Advertising|Periodicals|All Periodical Types|Recordable Media', + '2FLU' => 'Advertising|Periodicals|All Periodical Types|All Electronic Distribution Formats', + '2EDH' => 'Advertising|Marketing Materials|Artist\'s Reference, All Types|Printed', + '2ECU' => 'Advertising|Marketing Materials|Artist\'s Reference, All Types|All Internet Distribution Formats', + '2DOT' => 'Advertising|Marketing Materials|Artist\'s Reference, All Types|All Electronic Distribution Formats', + '2MMA' => 'Advertising|Marketing Materials|Bill Insert|Printed', + '2MMB' => 'Advertising|Marketing Materials|Blow In Card|Printed', + '2MMC' => 'Advertising|Marketing Materials|Bound-in Insert|Printed', + '2MMD' => 'Advertising|Marketing Materials|Broadside|Printed', + '2EGG' => 'Advertising|Marketing Materials|Brochure|Printed', + '2EFF' => 'Advertising|Marketing Materials|Brochure|Internet Downloadable File', + '2EFS' => 'Advertising|Marketing Materials|Brochure|Internet Email', + '2EFT' => 'Advertising|Marketing Materials|Brochure|Recordable Media', + '2MME' => 'Advertising|Marketing Materials|Buckslip|Printed', + '2MMF' => 'Advertising|Marketing Materials|Business Card|Printed', + '2MMG' => 'Advertising|Marketing Materials|Business Envelope|Printed', + '2BIZ' => 'Advertising|Marketing Materials|Card, Business Greeting Card|Printed', + '2MMI' => 'Advertising|Marketing Materials|Business Invitation|Printed', + '2MMJ' => 'Advertising|Marketing Materials|Business Reply Card|Printed', + '2MMK' => 'Advertising|Marketing Materials|Business Reply Envelope|Printed', + '2MML' => 'Advertising|Marketing Materials|Business Stationery|Printed', + '2FIG' => 'Advertising|Marketing Materials|Catalog|Printed', + '2ELL' => 'Advertising|Marketing Materials|Catalog|Internet Downloadable File', + '2ELS' => 'Advertising|Marketing Materials|Catalog|Internet Email', + '2ELF' => 'Advertising|Marketing Materials|Catalog|Recordable Media', + '2EDU' => 'Advertising|Marketing Materials|CD ROM|Recordable Media', + '2MMM' => 'Advertising|Marketing Materials|Compliment Slip|Printed', + '2MMN' => 'Advertising|Marketing Materials|Coupon|Printed', + '2EGO' => 'Advertising|Marketing Materials|Coupon|Internet Downloadable File', + '2ENG' => 'Advertising|Marketing Materials|Coupon|Internet Email', + '2ENS' => 'Advertising|Marketing Materials|Coupon|Recordable Media', + '2MMP' => 'Advertising|Marketing Materials|Coupon Packs|Printed', + '2DVA' => 'Advertising|Marketing Materials|DVD|Recordable Media', + '2MMQ' => 'Advertising|Marketing Materials|Flyaway Card|Printed', + '2FLY' => 'Advertising|Marketing Materials|Flyer|Printed', + '2MMR' => 'Advertising|Marketing Materials|Leaflet|Printed', + '2MMS' => 'Advertising|Marketing Materials|Magalog|Printed', + '2END' => 'Advertising|Marketing Materials|Magalog|Internet Downloadable File', + '2EON' => 'Advertising|Marketing Materials|Magalog|Internet Email', + '2FAX' => 'Advertising|Marketing Materials|Magalog|Recordable Media', + '2MMT' => 'Advertising|Marketing Materials|One Sheet|Printed', + '2MMU' => 'Advertising|Marketing Materials|Onsert|Printed', + '2MMV' => 'Advertising|Marketing Materials|Polybag|Printed', + '2BUN' => 'Advertising|Marketing Materials|Promo Card|Printed', + '2MMW' => 'Advertising|Marketing Materials|Promotional Calendar, One Page|Printed', + '2FAS' => 'Advertising|Marketing Materials|Promotional Calendar, One Page|Internet Downloadable File', + '2FAY' => 'Advertising|Marketing Materials|Promotional Calendar, One Page|Internet Email', + '2GUT' => 'Advertising|Marketing Materials|Promotional Calendar, One Page|Recordable Media', + '2EWE' => 'Advertising|Marketing Materials|Promotional Calendar, One Page|All Electronic Distribution Formats', + '2YAM' => 'Advertising|Marketing Materials|Promotional Calendar, Multi-Page|Printed', + '2ESS' => 'Advertising|Marketing Materials|Promotional Calendar, Multi-Page|Internet Downloadable File', + '2ETA' => 'Advertising|Marketing Materials|Promotional Calendar, Multi-Page|Internet Email', + '2HAD' => 'Advertising|Marketing Materials|Promotional Calendar, Multi-Page|Recordable Media', + '2FET' => 'Advertising|Marketing Materials|Promotional E-card|Internet Email', + '2FEU' => 'Advertising|Marketing Materials|Promotional E-card|All Internet Distribution Formats', + '2FEH' => 'Advertising|Marketing Materials|Promotional E-card|Recordable Media', + '2FEN' => 'Advertising|Marketing Materials|Promotional E-card|Internet Downloadable File', + '2MMX' => 'Advertising|Marketing Materials|Promotional Envelope|Printed', + '2NUT' => 'Advertising|Marketing Materials|Promotional Postcard|Printed', + '2KAF' => 'Advertising|Marketing Materials|Public Relations, Press Kit|Printed', + '2JUT' => 'Advertising|Marketing Materials|Public Relations, Press Kit|Internet Website', + '2JUN' => 'Advertising|Marketing Materials|Public Relations, Press Kit|Internet Downloadable File', + '2JUS' => 'Advertising|Marketing Materials|Public Relations, Press Kit|Internet Email', + '2JOW' => 'Advertising|Marketing Materials|Public Relations, Press Kit|All Internet Distribution Formats', + '2JOB' => 'Advertising|Marketing Materials|Public Relations, Press Kit|Recordable Media', + '2JOE' => 'Advertising|Marketing Materials|Public Relations, Press Kit|All Electronic Distribution Formats', + '2KAB' => 'Advertising|Marketing Materials|Public Relations, Press Kit|Television Broadcast', + '2KEX' => 'Advertising|Marketing Materials|Public Relations, Press Release|Printed', + '2KEA' => 'Advertising|Marketing Materials|Public Relations, Press Release|Internet Website', + '2KAT' => 'Advertising|Marketing Materials|Public Relations, Press Release|Internet Downloadable File', + '2KAY' => 'Advertising|Marketing Materials|Public Relations, Press Release|Internet Email', + '2KAS' => 'Advertising|Marketing Materials|Public Relations, Press Release|Recordable Media', + '2KID' => 'Advertising|Marketing Materials|Public Relations, Press Release|All Electronic Distribution Formats', + '2KEF' => 'Advertising|Marketing Materials|Public Relations, Press Release|Television Broadcast', + '2JIB' => 'Advertising|Marketing Materials|Public Relations, All Types|Printed', + '2MMY' => 'Advertising|Marketing Materials|Sales Kit|Printed', + '2MMZ' => 'Advertising|Marketing Materials|Self Mailer|Printed', + '2JAM' => 'Advertising|Marketing Materials|All Marketing Material Types|Printed', + '2HAM' => 'Advertising|Marketing Materials|All Marketing Material Types|Internet Downloadable File', + '2DYE' => 'Advertising|Marketing Materials|All Marketing Material Types|Internet Email', + '2DUO' => 'Advertising|Marketing Materials|All Marketing Material Types|Recordable Media', + '2BEG' => 'Advertising|Book|Retail Book, Directory|Printed', + '2EAC' => 'Advertising|Book|Retail Book, Directory|E-Book in Internet Website', + '2EAD' => 'Advertising|Book|Retail Book, Directory|E-Book in Internet Downloadable File', + '2EAE' => 'Advertising|Book|Retail Book, Directory|All E-Book Internet Distribution Formats', + '2EAF' => 'Advertising|Book|Retail Book, Directory|E-Book on Recordable Media', + '2EAG' => 'Advertising|Book|Retail Book, Directory|All E-Book Distribution Formats', + '2ELM' => 'Advertising|Book|Textbook, All Types|Printed', + '2EAH' => 'Advertising|Book|Textbook, All Types|E-Book in Internet Website', + '2EAJ' => 'Advertising|Book|Textbook, All Types|E-Book in Internet Downloadable File', + '2EAK' => 'Advertising|Book|Textbook, All Types|All E-Book Internet Distribution Formats', + '2EAL' => 'Advertising|Book|Textbook, All Types|E-Book on Recordable Media', + '2EAM' => 'Advertising|Book|Textbook, All Types|All E-Book Distribution Formats', + '2HOG' => 'Advertising|Book|All Book Types|Printed', + '2EAN' => 'Advertising|Book|All Book Types|All E-Book Internet Distribution Formats', + '2EAP' => 'Advertising|Book|All Book Types|All E-Book Distribution Formats', + '2HEM' => 'Advertising|Display|Billboard, Bulletin|Printed', + '2BUR' => 'Advertising|Display|Billboard, Bulletin|Electronic Display', + '2DAG' => 'Advertising|Display|Billboard, Spectacular|Printed', + '2DAD' => 'Advertising|Display|Billboard, Spectacular|Electronic Display', + '2DAK' => 'Advertising|Display|Billboard, Wallscape|Printed', + '2DAH' => 'Advertising|Display|Billboard, Wallscape|Electronic Display', + '2DAB' => 'Advertising|Display|Billboard, Rotating Billboard|Printed', + '2BLD' => 'Advertising|Display|Billboard, Building Wrap|Printed', + '2BYS' => 'Advertising|Display|Billboard, Mobile Billboard|Printed', + '2BYE' => 'Advertising|Display|Billboard, Mobile Billboard|Electronic Display', + '2BIL' => 'Advertising|Display|Billboard, All Types|Printed', + '2BUD' => 'Advertising|Display|Billboard, All Types|Electronic Display', + '2BRR' => 'Advertising|Display|Banner, Backdrop|Printed', + '2BUB' => 'Advertising|Display|Banner, Background|Printed', + '2BRA' => 'Advertising|Display|Banner, Airborne Display|Printed', + '2BRO' => 'Advertising|Display|Banner, All Types|Printed', + '2BAN' => 'Advertising|Display|Banner, All Types|Electronic Display', + '2CAR' => 'Advertising|Display|Shopping Cart|Printed', + '2CRT' => 'Advertising|Display|Shopping Cart|Electronic Display', + '2FAD' => 'Advertising|Display|Poster, Movie Poster|Printed', + '2HON' => 'Advertising|Display|Poster, Movie Poster|Electronic Display', + '2DIB' => 'Advertising|Display|Poster, Door Side Poster|Printed', + '2DEY' => 'Advertising|Display|Poster, Door Side Poster|Electronic Display', + '2DEV' => 'Advertising|Display|Poster, Corporate Poster|Printed', + '2DEN' => 'Advertising|Display|Poster, Corporate Poster|Electronic Display', + '2ELE' => 'Advertising|Display|Poster, Elevator Advertising|Printed', + '2DID' => 'Advertising|Display|Poster, Elevator Advertising|Electronic Display', + '2DRY' => 'Advertising|Display|Poster, Restroom Poster|Printed', + '2WET' => 'Advertising|Display|Poster, Restroom Poster|Electronic Display', + '2DEL' => 'Advertising|Display|Poster, Backlit Print|Printed', + '2DEX' => 'Advertising|Display|Poster, Display Chrome|Printed', + '2FAT' => 'Advertising|Display|Poster, All Types|Printed', + '2DAW' => 'Advertising|Display|Poster, All Types|Electronic Display', + '2MOB' => 'Advertising|Display|Store Display, In-Store Poster|Printed', + '2DIT' => 'Advertising|Display|Store Display, In-Store Poster|Electronic Display', + '2FOG' => 'Advertising|Display|Store Display, All Display Types|Printed', + '2DIN' => 'Advertising|Display|Store Display, All Display Types|Electronic Display', + '2HOT' => 'Advertising|Display|Terminal Advertising, Airport Display|Printed', + '2JOU' => 'Advertising|Display|Terminal Advertising, Airport Display|Electronic Display', + '2DOM' => 'Advertising|Display|Terminal Advertising, Bus Stop Advertising|Printed', + '2DOL' => 'Advertising|Display|Terminal Advertising, Bus Stop Advertising|Electronic Display', + '2DOR' => 'Advertising|Display|Terminal Advertising, Ferry Terminal Advertising|Printed', + '2DON' => 'Advertising|Display|Terminal Advertising, Ferry Terminal Advertising|Electronic Display', + '2TAN' => 'Advertising|Display|Terminal Advertising, Shelter Advertising|Printed', + '2DOS' => 'Advertising|Display|Terminal Advertising, Shelter Advertising|Electronic Display', + '2DUB' => 'Advertising|Display|Terminal Advertising, Station Poster|Printed', + '2DOW' => 'Advertising|Display|Terminal Advertising, Station Poster|Electronic Display', + '2DUG' => 'Advertising|Display|Terminal Advertising, Subway Terminal Advertising|Printed', + '2DUE' => 'Advertising|Display|Terminal Advertising, Subway Terminal Advertising|Electronic Display', + '2DUN' => 'Advertising|Display|Terminal Advertising, Train Terminal Advertising|Printed', + '2DUI' => 'Advertising|Display|Terminal Advertising, Train Terminal Advertising|Electronic Display', + '2JOY' => 'Advertising|Display|Terminal Advertising, All Types|Printed', + '2DOE' => 'Advertising|Display|Terminal Advertising, All Types|Electronic Display', + '2TAX' => 'Advertising|Display|Transit Advertising, Taxi Advertising|Printed', + '2BUS' => 'Advertising|Display|Transit Advertising, Bus Panel|Printed', + '2TRC' => 'Advertising|Display|Transit Advertising, Bus Panel|Electronic Display', + '2TRE' => 'Advertising|Display|Transit Advertising, Bus Poster|Printed', + '2BPE' => 'Advertising|Display|Transit Advertising, Bus Poster|Electronic Display', + '2TRG' => 'Advertising|Display|Transit Advertising, Bus Rear Display|Printed', + '2TRF' => 'Advertising|Display|Transit Advertising, Bus Rear Display|Electronic Display', + '2TRN' => 'Advertising|Display|Transit Advertising, Bus Wrap|Printed', + '2TRM' => 'Advertising|Display|Transit Advertising, Bus Wrap|Electronic Display', + '2TRJ' => 'Advertising|Display|Transit Advertising, Subway Advertising|Printed', + '2TRI' => 'Advertising|Display|Transit Advertising, Subway Advertising|Electronic Display', + '2TRL' => 'Advertising|Display|Transit Advertising, Train Advertising|Printed', + '2TRK' => 'Advertising|Display|Transit Advertising, Train Advertising|Electronic Display', + '2TRQ' => 'Advertising|Display|Transit Advertising, Commercial Vehicles|Printed', + '2TRR' => 'Advertising|Display|Transit Advertising, Commercial Vehicles|Electronic Display', + '2FER' => 'Advertising|Display|Transit Advertising, Ferry Advertising|Printed', + '2TRH' => 'Advertising|Display|Transit Advertising, Ferry Advertising|Electronic Display', + '2TRA' => 'Advertising|Display|Transit Advertising, All Types|Printed', + '2TRB' => 'Advertising|Display|Transit Advertising, All Types|Electronic Display', + '2DAM' => 'Advertising|Display|Event, Stadium Advertising|Printed', + '2DAL' => 'Advertising|Display|Event, Stadium Advertising|Electronic Display', + '2DIS' => 'Advertising|Display|Event, Trade Show Display|Printed', + '2DAP' => 'Advertising|Display|Event, Trade Show Display|Electronic Display', + '2BIG' => 'Advertising|Display|All Display Types|Printed', + '2BOG' => 'Advertising|Display|All Display Types|Electronic Display', + '2BOY' => 'Advertising|Art|Art Display, Display Print|Printed', + '2ART' => 'Advertising|Art|Art Display, All Art Types|Printed', + '2BEL' => 'Advertising|Art|Art Display, All Art Types|Internet Website', + '2BEY' => 'Advertising|Art|Art Display, All Art Types|All Internet Distribution Formats', + '2BOS' => 'Advertising|Art|Art Display, All Art Types|Electronic Display', + '2BIS' => 'Advertising|Art|Art Display, All Art Types|All Electronic Distribution Formats', + '2ADH' => 'Advertising|Point of Purchase|Adhesive Tag|Printed', + '2BOT' => 'Advertising|Point of Purchase|Bottlenecker|Printed', + '2CAS' => 'Advertising|Point of Purchase|Case Card|Printed', + '2COU' => 'Advertising|Point of Purchase|Counter Card|Printed', + '2BUY' => 'Advertising|Point of Purchase|Floor Graphic|Printed', + '2TAG' => 'Advertising|Point of Purchase|Hang Tag|Printed', + '2GYM' => 'Advertising|Point of Purchase|Kiosk, Interactive Kiosk|Printed', + '2GUN' => 'Advertising|Point of Purchase|Kiosk, Interactive Kiosk|Electronic Display', + '2JUG' => 'Advertising|Point of Purchase|Kiosk, Telephone Kiosk|Printed', + '2FIN' => 'Advertising|Point of Purchase|Kiosk, All Types|Printed', + '2KIO' => 'Advertising|Point of Purchase|Kiosk, All Types|Electronic Display', + '2MEN' => 'Advertising|Point of Purchase|Menu|Printed', + '2TAL' => 'Advertising|Point of Purchase|Shelf Talker|Printed', + '2TIN' => 'Advertising|Point of Purchase|Slip Case|Printed', + '2WAX' => 'Advertising|Point of Purchase|Table Tent|Printed', + '2BIN' => 'Advertising|Point of Purchase|All Point of Purchase Types|Printed', + '2BIB' => 'Advertising|Point of Purchase|All Point of Purchase Types|Electronic Display', + '2BAR' => 'Advertising|Point of Purchase|All Point of Purchase Types|All Electronic Distribution Formats', + '2MAR' => 'Advertising|Website|Web Page, Design Element|Internet Website', + '2MAX' => 'Advertising|Website|Web Page, Design Element|All Internet Distribution Formats', + '2MAS' => 'Advertising|Website|Web Page, Design Element|Recordable Media', + '2MAW' => 'Advertising|Website|Web Page, Design Element|All Electronic Distribution Formats', + '2MED' => 'Advertising|Website|Web Page, Web Banner Ad|Internet Website', + '2MEW' => 'Advertising|Website|Web Page, Web Banner Ad|All Internet Distribution Formats', + '2MEG' => 'Advertising|Website|Web Page, Web Banner Ad|Recordable Media', + '2MEM' => 'Advertising|Website|Web Page, Web Banner Ad|All Electronic Distribution Formats', + '2JWL' => 'Advertising|Website|Web Page, Web Interstitial Ad|Internet Website', + '2MIG' => 'Advertising|Website|Web Page, Web Interstitial Ad|All Internet Distribution Formats', + '2MIB' => 'Advertising|Website|Web Page, Web Interstitial Ad|Recordable Media', + '2MID' => 'Advertising|Website|Web Page, Web Interstitial Ad|All Electronic Distribution Formats', + '2WEB' => 'Advertising|Website|Web Page, All Types|Internet Website', + '2KUE' => 'Advertising|Website|Web Page, All Types|All Internet Distribution Formats', + '2MAC' => 'Advertising|Website|Web Page, All Types|Recordable Media', + '2MAE' => 'Advertising|Website|Web Page, All Types|All Electronic Distribution Formats', + '2MIL' => 'Advertising|Website|Webcast, All Types|Internet Website', + '2EMA' => 'Advertising|Email|All Email Types|Internet Email', + '2ZUS' => 'Advertising|Mobile|All Mobile Types|Mobile', + '2FUR' => 'Advertising|Live Presentation|Sales Presentation|Projected Display', + '2EYE' => 'Advertising|Live Presentation|Panel Presentation|Projected Display', + '2TOE' => 'Advertising|Live Presentation|Trade Show Presentation|Projected Display', + '2JAW' => 'Advertising|Live Presentation|Stage Performance|Projected Display', + '2EAR' => 'Advertising|Live Presentation|All Live Presentation Types|All Electronic Distribution Formats', + '2FID' => 'Advertising|Merchandise|Apparel, T-Shirts|Printed or Woven', + '2FEZ' => 'Advertising|Merchandise|Apparel, General Apparel|Printed or Woven', + '2FIE' => 'Advertising|Merchandise|Folder|Printed', + '2AAY' => 'Advertising|All Media Types|Promotional Reproduction of Licensed Usage in Context|All Distribution Formats', + '2AAA' => 'Advertising|All Media Types|All Formats|All Distribution Formats', + '2GEM' => 'Editorial|Periodicals|Magazine, Consumer|Printed', + '2GDW' => 'Editorial|Periodicals|Magazine, Consumer|Internet Website', + '2GDY' => 'Editorial|Periodicals|Magazine, Consumer|Internet Downloadable File', + '2KIN' => 'Editorial|Periodicals|Magazine, Consumer|Internet Email', + '2GEA' => 'Editorial|Periodicals|Magazine, Consumer|All Internet Distribution Formats', + '2GDV' => 'Editorial|Periodicals|Magazine, Consumer|Recordable Media', + '2GDZ' => 'Editorial|Periodicals|Magazine, Consumer|All Electronic Distribution Formats', + '2MOM' => 'Editorial|Periodicals|Magazine, Trade|Printed', + '2MOW' => 'Editorial|Periodicals|Magazine, Trade|Internet Website', + '2MUT' => 'Editorial|Periodicals|Magazine, Trade|Internet Downloadable File', + '2NAB' => 'Editorial|Periodicals|Magazine, Trade|Internet Email', + '2NAG' => 'Editorial|Periodicals|Magazine, Trade|All Internet Distribution Formats', + '2GFD' => 'Editorial|Periodicals|Magazine, Trade|Recordable Media', + '2NOB' => 'Editorial|Periodicals|Magazine, Trade|All Electronic Distribution Formats', + '2MAY' => 'Editorial|Periodicals|Magazine, Education|Printed', + '2GEP' => 'Editorial|Periodicals|Magazine, Education|Internet Website', + '2GEQ' => 'Editorial|Periodicals|Magazine, Education|Internet Downloadable File', + '2NOW' => 'Editorial|Periodicals|Magazine, Education|Internet Email', + '2GES' => 'Editorial|Periodicals|Magazine, Education|All Internet Distribution Formats', + '2GEK' => 'Editorial|Periodicals|Magazine, Education|Recordable Media', + '2GER' => 'Editorial|Periodicals|Magazine, Education|All Electronic Distribution Formats', + '2MOP' => 'Editorial|Periodicals|Magazine, Custom Published|Printed', + '2GEF' => 'Editorial|Periodicals|Magazine, Custom Published|Internet Website', + '2GEG' => 'Editorial|Periodicals|Magazine, Custom Published|Internet Downloadable File', + '2NUN' => 'Editorial|Periodicals|Magazine, Custom Published|Internet Email', + '2GEI' => 'Editorial|Periodicals|Magazine, Custom Published|All Internet Distribution Formats', + '2GEC' => 'Editorial|Periodicals|Magazine, Custom Published|Recordable Media', + '2GEH' => 'Editorial|Periodicals|Magazine, Custom Published|All Electronic Distribution Formats', + '2MEL' => 'Editorial|Periodicals|Magazine, Partworks|Printed', + '2GEV' => 'Editorial|Periodicals|Magazine, Partworks|Internet Website', + '2GEW' => 'Editorial|Periodicals|Magazine, Partworks|Internet Downloadable File', + '2TAB' => 'Editorial|Periodicals|Magazine, Partworks|Internet Email', + '2GFB' => 'Editorial|Periodicals|Magazine, Partworks|All Internet Distribution Formats', + '2GEZ' => 'Editorial|Periodicals|Magazine, Partworks|Recordable Media', + '2GFA' => 'Editorial|Periodicals|Magazine, Partworks|All Electronic Distribution Formats', + '2WIG' => 'Editorial|Periodicals|Scholarly Journal|Printed', + '2GGF' => 'Editorial|Periodicals|Scholarly Journal|Internet Website', + '2GGG' => 'Editorial|Periodicals|Scholarly Journal|Internet Downloadable File', + '2TAD' => 'Editorial|Periodicals|Scholarly Journal|Internet Email', + '2GGI' => 'Editorial|Periodicals|Scholarly Journal|All Internet Distribution Formats', + '2GGD' => 'Editorial|Periodicals|Scholarly Journal|Recordable Media', + '2GGH' => 'Editorial|Periodicals|Scholarly Journal|All Electronic Distribution Formats', + '2MAG' => 'Editorial|Periodicals|Magazine, All Types|Printed', + '2GDP' => 'Editorial|Periodicals|Magazine, All Types|Internet Website', + '2GDM' => 'Editorial|Periodicals|Magazine, All Types|Internet Downloadable File', + '2GDQ' => 'Editorial|Periodicals|Magazine, All Types|Internet Email', + '2GDT' => 'Editorial|Periodicals|Magazine, All Types|All Internet Distribution Formats', + '2GDR' => 'Editorial|Periodicals|Magazine, All Types|Recordable Media', + '2GDS' => 'Editorial|Periodicals|Magazine, All Types|All Electronic Distribution Formats', + '2JET' => 'Editorial|Periodicals|Newspaper, All Types|Printed', + '2GFN' => 'Editorial|Periodicals|Newspaper, All Types|Internet Website', + '2GFP' => 'Editorial|Periodicals|Newspaper, All Types|Internet Downloadable File', + '2TAJ' => 'Editorial|Periodicals|Newspaper, All Types|Internet Email', + '2GFR' => 'Editorial|Periodicals|Newspaper, All Types|All Internet Distribution Formats', + '2GFM' => 'Editorial|Periodicals|Newspaper, All Types|Recordable Media', + '2GFQ' => 'Editorial|Periodicals|Newspaper, All Types|All Electronic Distribution Formats', + '2TUB' => 'Editorial|Periodicals|Newspaper, Weekly Supplement|Printed', + '2GFW' => 'Editorial|Periodicals|Newspaper, Weekly Supplement|Internet Website', + '2GFY' => 'Editorial|Periodicals|Newspaper, Weekly Supplement|Internet Downloadable File', + '2TAO' => 'Editorial|Periodicals|Newspaper, Weekly Supplement|Internet Email', + '2GFV' => 'Editorial|Periodicals|Newspaper, Weekly Supplement|All Internet Distribution Formats', + '2GFS' => 'Editorial|Periodicals|Newspaper, Weekly Supplement|Recordable Media', + '2GFU' => 'Editorial|Periodicals|Newspaper, Weekly Supplement|All Electronic Distribution Formats', + '2FAN' => 'Editorial|Periodicals|Newspaper, Tabloid|Printed', + '2TEX' => 'Editorial|Periodicals|Newspaper, Tabloid|Internet Website', + '2GGA' => 'Editorial|Periodicals|Newspaper, Tabloid|Internet Downloadable File', + '2TIP' => 'Editorial|Periodicals|Newspaper, Tabloid|Internet Email', + '2TON' => 'Editorial|Periodicals|Newspaper, Tabloid|All Internet Distribution Formats', + '2TIE' => 'Editorial|Periodicals|Newspaper, Tabloid|Recordable Media', + '2TOT' => 'Editorial|Periodicals|Newspaper, Tabloid|All Electronic Distribution Formats', + '2TOM' => 'Editorial|Periodicals|Newsletter|Printed', + '2GFH' => 'Editorial|Periodicals|Newsletter|Internet Website', + '2GFI' => 'Editorial|Periodicals|Newsletter|Internet Downloadable File', + '2NEL' => 'Editorial|Periodicals|Newsletter|Internet Email', + '2GFK' => 'Editorial|Periodicals|Newsletter|All Internet Distribution Formats', + '2GFG' => 'Editorial|Periodicals|Newsletter|Recordable Media', + '2GFJ' => 'Editorial|Periodicals|Newsletter|All Electronic Distribution Formats', + '2BUG' => 'Editorial|Book|Retail Book, Children\'s Book|Printed', + '2EPC' => 'Editorial|Book|Retail Book, Children\'s Book|E-Book in Internet Website', + '2EBE' => 'Editorial|Book|Retail Book, Children\'s Book|E-Book in Internet Downloadable File', + '2EGB' => 'Editorial|Book|Retail Book, Children\'s Book|E-Book in Internet Email', + '2EKB' => 'Editorial|Book|Retail Book, Children\'s Book|All E-Book Internet Distribution Formats', + '2ERB' => 'Editorial|Book|Retail Book, Children\'s Book|E-Book on Recordable Media', + '2EGC' => 'Editorial|Book|Retail Book, Children\'s Book|All E-Book Distribution Formats', + '2TAE' => 'Editorial|Book|Retail Book, Coffee Table Book|Printed', + '2TAV' => 'Editorial|Book|Retail Book, Concept Book|Printed', + '2EPD' => 'Editorial|Book|Retail Book, Concept Book|E-Book in Internet Website', + '2EBF' => 'Editorial|Book|Retail Book, Concept Book|E-Book in Internet Downloadable File', + '2EGD' => 'Editorial|Book|Retail Book, Concept Book|E-Book in Internet Email', + '2EKC' => 'Editorial|Book|Retail Book, Concept Book|All E-Book Internet Distribution Formats', + '2ERC' => 'Editorial|Book|Retail Book, Concept Book|E-Book on Recordable Media', + '2EGE' => 'Editorial|Book|Retail Book, Concept Book|All E-Book Distribution Formats', + '2DIR' => 'Editorial|Book|Retail Book, Directory|Printed', + '2EPE' => 'Editorial|Book|Retail Book, Directory|E-Book in Internet Website', + '2EBG' => 'Editorial|Book|Retail Book, Directory|E-Book in Internet Downloadable File', + '2ERD' => 'Editorial|Book|Retail Book, Directory|E-Book on Recordable Media', + '2YEA' => 'Editorial|Book|Retail Book, Directory|All Electronic Distribution Formats', + '2EAB' => 'Editorial|Book|Retail Book, Directory|All E-Book Distribution Formats', + '2HAN' => 'Editorial|Book|Retail Book, Handbook|Printed', + '2EPF' => 'Editorial|Book|Retail Book, Handbook|E-Book in Internet Website', + '2EBH' => 'Editorial|Book|Retail Book, Handbook|E-Book in Internet Downloadable File', + '2EGH' => 'Editorial|Book|Retail Book, Handbook|E-Book in Internet Email', + '2EKD' => 'Editorial|Book|Retail Book, Handbook|All E-Book Internet Distribution Formats', + '2ERF' => 'Editorial|Book|Retail Book, Handbook|E-Book on Recordable Media', + '2EGJ' => 'Editorial|Book|Retail Book, Handbook|All E-Book Distribution Formats', + '2HIL' => 'Editorial|Book|Retail Book, Hi-lo Book|Printed', + '2EPG' => 'Editorial|Book|Retail Book, Hi-lo Book|E-Book in Internet Website', + '2EBI' => 'Editorial|Book|Retail Book, Hi-lo Book|E-Book in Internet Downloadable File', + '2EGK' => 'Editorial|Book|Retail Book, Hi-lo Book|E-Book in Internet Email', + '2EKE' => 'Editorial|Book|Retail Book, Hi-lo Book|All E-Book Internet Distribution Formats', + '2ERG' => 'Editorial|Book|Retail Book, Hi-lo Book|E-Book on Recordable Media', + '2EGL' => 'Editorial|Book|Retail Book, Hi-lo Book|All E-Book Distribution Formats', + '2WAB' => 'Editorial|Book|Retail Book, Illustrated Book|Printed', + '2EPH' => 'Editorial|Book|Retail Book, Illustrated Book|E-Book in Internet Website', + '2EBJ' => 'Editorial|Book|Retail Book, Illustrated Book|E-Book in Internet Downloadable File', + '2EGM' => 'Editorial|Book|Retail Book, Illustrated Book|E-Book in Internet Email', + '2EKF' => 'Editorial|Book|Retail Book, Illustrated Book|All E-Book Internet Distribution Formats', + '2ERH' => 'Editorial|Book|Retail Book, Illustrated Book|E-Book on Recordable Media', + '2EGN' => 'Editorial|Book|Retail Book, Illustrated Book|All E-Book Distribution Formats', + '2WHA' => 'Editorial|Book|Retail Book, Illustrated Guide|Printed', + '2EPJ' => 'Editorial|Book|Retail Book, Illustrated Guide|E-Book in Internet Website', + '2EBL' => 'Editorial|Book|Retail Book, Illustrated Guide|E-Book in Internet Downloadable File', + '2EGP' => 'Editorial|Book|Retail Book, Illustrated Guide|E-Book in Internet Email', + '2EKG' => 'Editorial|Book|Retail Book, Illustrated Guide|All E-Book Internet Distribution Formats', + '2ERI' => 'Editorial|Book|Retail Book, Illustrated Guide|E-Book on Recordable Media', + '2EGQ' => 'Editorial|Book|Retail Book, Illustrated Guide|All E-Book Distribution Formats', + '2EGR' => 'Editorial|Book|Retail Book, Illustrated Guide|All E-Book Distribution Formats', + '2MAN' => 'Editorial|Book|Retail Book, Manual|Printed', + '2EPK' => 'Editorial|Book|Retail Book, Manual|E-Book in Internet Website', + '2EBM' => 'Editorial|Book|Retail Book, Manual|E-Book in Internet Downloadable File', + '2EGS' => 'Editorial|Book|Retail Book, Manual|E-Book in Internet Email', + '2EKH' => 'Editorial|Book|Retail Book, Manual|All E-Book Internet Distribution Formats', + '2ERJ' => 'Editorial|Book|Retail Book, Manual|E-Book on Recordable Media', + '2EGT' => 'Editorial|Book|Retail Book, Manual|All E-Book Distribution Formats', + '2YAP' => 'Editorial|Book|Retail Book, Novelty Book|Printed', + '2EPL' => 'Editorial|Book|Retail Book, Novelty Book|E-Book in Internet Website', + '2EBN' => 'Editorial|Book|Retail Book, Novelty Book|E-Book in Internet Downloadable File', + '2EGV' => 'Editorial|Book|Retail Book, Novelty Book|E-Book in Internet Email', + '2EKJ' => 'Editorial|Book|Retail Book, Novelty Book|All E-Book Internet Distribution Formats', + '2ERK' => 'Editorial|Book|Retail Book, Novelty Book|E-Book on Recordable Media', + '2EGW' => 'Editorial|Book|Retail Book, Novelty Book|All E-Book Distribution Formats', + '2YEN' => 'Editorial|Book|Retail Book, Postcard Book|Printed', + '2EPM' => 'Editorial|Book|Retail Book, Postcard Book|E-Book in Internet Website', + '2EBP' => 'Editorial|Book|Retail Book, Postcard Book|E-Book in Internet Downloadable File', + '2EGY' => 'Editorial|Book|Retail Book, Postcard Book|E-Book in Internet Email', + '2EKK' => 'Editorial|Book|Retail Book, Postcard Book|All E-Book Internet Distribution Formats', + '2ERL' => 'Editorial|Book|Retail Book, Postcard Book|E-Book on Recordable Media', + '2EGZ' => 'Editorial|Book|Retail Book, Postcard Book|All E-Book Distribution Formats', + '2YOK' => 'Editorial|Book|Retail Book, Young Adult Book|Printed', + '2EPN' => 'Editorial|Book|Retail Book, Young Adult Book|E-Book in Internet Website', + '2EBQ' => 'Editorial|Book|Retail Book, Young Adult Book|E-Book in Internet Downloadable File', + '2EJB' => 'Editorial|Book|Retail Book, Young Adult Book|E-Book in Internet Email', + '2EKL' => 'Editorial|Book|Retail Book, Young Adult Book|All E-Book Internet Distribution Formats', + '2ERM' => 'Editorial|Book|Retail Book, Young Adult Book|E-Book on Recordable Media', + '2EJC' => 'Editorial|Book|Retail Book, Young Adult Book|All E-Book Distribution Formats', + '2BOO' => 'Editorial|Book|Retail Book, All Types|Printed', + '2EPB' => 'Editorial|Book|Retail Book, All Types|E-Book in Internet Website', + '2EBC' => 'Editorial|Book|Retail Book, All Types|E-Book in Internet Downloadable File', + '2EJD' => 'Editorial|Book|Retail Book, All Types|E-Book in Internet Email', + '2EKM' => 'Editorial|Book|Retail Book, All Types|All E-Book Internet Distribution Formats', + '2ERN' => 'Editorial|Book|Retail Book, All Types|E-Book on Recordable Media', + '2EJE' => 'Editorial|Book|Retail Book, All Types|All E-Book Distribution Formats', + '2EEL' => 'Editorial|Book|Textbook, Compendium|Printed', + '2EPQ' => 'Editorial|Book|Textbook, Compendium|E-Book in Internet Website', + '2EBS' => 'Editorial|Book|Textbook, Compendium|E-Book in Internet Downloadable File', + '2EJF' => 'Editorial|Book|Textbook, Compendium|E-Book in Internet Email', + '2EKN' => 'Editorial|Book|Textbook, Compendium|All E-Book Internet Distribution Formats', + '2ERP' => 'Editorial|Book|Textbook, Compendium|E-Book on Recordable Media', + '2EJJ' => 'Editorial|Book|Textbook, Compendium|All E-Book Distribution Formats', + '2EMU' => 'Editorial|Book|Textbook, Course Pack|Printed', + '2GBN' => 'Editorial|Book|Textbook, Course Pack|Internet Website', + '2GBM' => 'Editorial|Book|Textbook, Course Pack|Internet Downloadable File', + '2ZOO' => 'Editorial|Book|Textbook, Course Pack|Internet Email', + '2GBQ' => 'Editorial|Book|Textbook, Course Pack|All Internet Distribution Formats', + '2ZOA' => 'Editorial|Book|Textbook, Course Pack|Recordable Media', + '2GBP' => 'Editorial|Book|Textbook, Course Pack|All Distribution Formats', + '2BEE' => 'Editorial|Book|Textbook, Middle Reader|Printed', + '2EPR' => 'Editorial|Book|Textbook, Middle Reader|E-Book in Internet Website', + '2EBT' => 'Editorial|Book|Textbook, Middle Reader|E-Book in Internet Downloadable File', + '2EJK' => 'Editorial|Book|Textbook, Middle Reader|E-Book in Internet Email', + '2EKP' => 'Editorial|Book|Textbook, Middle Reader|All E-Book Internet Distribution Formats', + '2ERQ' => 'Editorial|Book|Textbook, Middle Reader|E-Book on Recordable Media', + '2EJL' => 'Editorial|Book|Textbook, Middle Reader|All E-Book Distribution Formats', + '2BOA' => 'Editorial|Book|Textbook, Student Edition|Printed', + '2EPS' => 'Editorial|Book|Textbook, Student Edition|E-Book in Internet Website', + '2EBV' => 'Editorial|Book|Textbook, Student Edition|E-Book in Internet Downloadable File', + '2EJM' => 'Editorial|Book|Textbook, Student Edition|E-Book in Internet Email', + '2EKQ' => 'Editorial|Book|Textbook, Student Edition|All E-Book Internet Distribution Formats', + '2ERS' => 'Editorial|Book|Textbook, Student Edition|E-Book on Recordable Media', + '2EJN' => 'Editorial|Book|Textbook, Student Edition|All E-Book Distribution Formats', + '2FOX' => 'Editorial|Book|Textbook, All Types|Printed', + '2EPP' => 'Editorial|Book|Textbook, All Types|E-Book in Internet Website', + '2EBR' => 'Editorial|Book|Textbook, All Types|E-Book in Internet Downloadable File', + '2EGA' => 'Editorial|Book|Textbook, All Types|E-Book in Internet Email', + '2EKR' => 'Editorial|Book|Textbook, All Types|All E-Book Internet Distribution Formats', + '2ERT' => 'Editorial|Book|Textbook, All Types|E-Book on Recordable Media', + '2EJP' => 'Editorial|Book|Textbook, All Types|All E-Book Distribution Formats', + '2GBZ' => 'Editorial|Book|Textbook Ancillary Materials, Educational Film Set|Projected Display', + '2YET' => 'Editorial|Book|Textbook Ancillary Materials, Packaging For Recordable Media|Printed', + '2YUM' => 'Editorial|Book|Textbook Ancillary Materials, Lab Manual|Printed', + '2EPZ' => 'Editorial|Book|Textbook Ancillary Materials, Lab Manual|E-Book in Internet Website', + '2EBA' => 'Editorial|Book|Textbook Ancillary Materials, Lab Manual|E-Book in Internet Downloadable File', + '2EJQ' => 'Editorial|Book|Textbook Ancillary Materials, Lab Manual|E-Book in Internet Email', + '2EKS' => 'Editorial|Book|Textbook Ancillary Materials, Lab Manual|All E-Book Internet Distribution Formats', + '2ERU' => 'Editorial|Book|Textbook Ancillary Materials, Lab Manual|E-Book on Recordable Media', + '2EJR' => 'Editorial|Book|Textbook Ancillary Materials, Lab Manual|All E-Book Distribution Formats', + '2YAK' => 'Editorial|Book|Textbook Ancillary Materials, Teachers\' Edition|Printed', + '2EPT' => 'Editorial|Book|Textbook Ancillary Materials, Teachers\' Edition|E-Book in Internet Website', + '2EBW' => 'Editorial|Book|Textbook Ancillary Materials, Teachers\' Edition|E-Book in Internet Downloadable File', + '2EJS' => 'Editorial|Book|Textbook Ancillary Materials, Teachers\' Edition|E-Book in Internet Email', + '2EKT' => 'Editorial|Book|Textbook Ancillary Materials, Teachers\' Edition|All E-Book Internet Distribution Formats', + '2ERV' => 'Editorial|Book|Textbook Ancillary Materials, Teachers\' Edition|E-Book on Recordable Media', + '2EJT' => 'Editorial|Book|Textbook Ancillary Materials, Teachers\' Edition|All E-Book Distribution Formats', + '2ZOT' => 'Editorial|Book|Textbook Ancillary Materials, Teacher\'s Manual|Printed', + '2EPW' => 'Editorial|Book|Textbook Ancillary Materials, Teacher\'s Manual|E-Book in Internet Website', + '2EBD' => 'Editorial|Book|Textbook Ancillary Materials, Teacher\'s Manual|E-Book in Internet Downloadable File', + '2EJV' => 'Editorial|Book|Textbook Ancillary Materials, Teacher\'s Manual|E-Book in Internet Email', + '2EKU' => 'Editorial|Book|Textbook Ancillary Materials, Teacher\'s Manual|All E-Book Internet Distribution Formats', + '2ERW' => 'Editorial|Book|Textbook Ancillary Materials, Teacher\'s Manual|E-Book on Recordable Media', + '2EJW' => 'Editorial|Book|Textbook Ancillary Materials, Teacher\'s Manual|All E-Book Distribution Formats', + '2GEE' => 'Editorial|Book|Textbook Ancillary Materials, Workbook|Printed', + '2EPY' => 'Editorial|Book|Textbook Ancillary Materials, Workbook|E-Book in Internet Website', + '2EBB' => 'Editorial|Book|Textbook Ancillary Materials, Workbook|E-Book in Internet Downloadable File', + '2EJY' => 'Editorial|Book|Textbook Ancillary Materials, Workbook|E-Book in Internet Email', + '2EKV' => 'Editorial|Book|Textbook Ancillary Materials, Workbook|All E-Book Internet Distribution Formats', + '2ERY' => 'Editorial|Book|Textbook Ancillary Materials, Workbook|E-Book on Recordable Media', + '2EJZ' => 'Editorial|Book|Textbook Ancillary Materials, Workbook|All E-Book Distribution Formats', + '2ELK' => 'Editorial|Book|Textbook Ancillary Materials, All Ancillary Types|Printed', + '2GBY' => 'Editorial|Book|Textbook Ancillary Materials, All Ancillary Types|All Internet Distribution Formats', + '2GBW' => 'Editorial|Book|Textbook Ancillary Materials, All Ancillary Types|All Distribution Formats', + '2NAY' => 'Editorial|Book|Reference Book, Encyclopedia|Printed', + '2EAQ' => 'Editorial|Book|Reference Book, Encyclopedia|E-Book in Internet Website', + '2EMB' => 'Editorial|Book|Reference Book, Encyclopedia|E-Book in Internet Downloadable File', + '2EMC' => 'Editorial|Book|Reference Book, Encyclopedia|All E-Book Internet Distribution Formats', + '2EMD' => 'Editorial|Book|Reference Book, Encyclopedia|E-Book on Recordable Media', + '2NAH' => 'Editorial|Book|Reference Book, Encyclopedia|All Electronic Distribution Formats', + '2NIP' => 'Editorial|Book|Reference Book, Telephone Book|Printed', + '2EMF' => 'Editorial|Book|Reference Book, Telephone Book|E-Book in Internet Website', + '2EMG' => 'Editorial|Book|Reference Book, Telephone Book|E-Book in Internet Downloadable File', + '2EMH' => 'Editorial|Book|Reference Book, Telephone Book|All E-Book Internet Distribution Formats', + '2EMI' => 'Editorial|Book|Reference Book, Telephone Book|E-Book on Recordable Media', + '2EMJ' => 'Editorial|Book|Reference Book, Telephone Book|All E-Book Distribution Formats', + '2DOG' => 'Editorial|Book|Reference Book, All Types|Printed', + '2EMK' => 'Editorial|Book|Reference Book, All Types|E-Book in Internet Website', + '2EML' => 'Editorial|Book|Reference Book, All Types|E-Book in Internet Downloadable File', + '2EMM' => 'Editorial|Book|Reference Book, All Types|All E-Book Internet Distribution Formats', + '2EMN' => 'Editorial|Book|Reference Book, All Types|E-Book on Recordable Media', + '2EMP' => 'Editorial|Book|Reference Book, All Types|All E-Book Distribution Formats', + '2DEW' => 'Editorial|Book|Trade Book, All Types|Printed', + '2EPV' => 'Editorial|Book|Trade Book, All Types|E-Book in Internet Website', + '2EMQ' => 'Editorial|Book|Trade Book, All Types|E-Book in Internet Downloadable File', + '2EMR' => 'Editorial|Book|Trade Book, All Types|E-Book in Internet Email', + '2EMS' => 'Editorial|Book|Trade Book, All Types|All E-Book Internet Distribution Formats', + '2ERA' => 'Editorial|Book|Trade Book, All Types|E-Book on Recordable Media', + '2EMT' => 'Editorial|Book|Trade Book, All Types|All E-Book Distribution Formats', + '2MOG' => 'Editorial|Book|All Book Types|Printed', + '2EPA' => 'Editorial|Book|All Book Types|E-Book in Internet Website', + '2EBK' => 'Editorial|Book|All Book Types|E-Book in Internet Downloadable File', + '2EJU' => 'Editorial|Book|All Book Types|E-Book in Internet Email', + '2EKA' => 'Editorial|Book|All Book Types|All E-Book Internet Distribution Formats', + '2ERZ' => 'Editorial|Book|All Book Types|E-Book on Recordable Media', + '2EJA' => 'Editorial|Book|All Book Types|All E-Book Distribution Formats', + '2MOR' => 'Editorial|Book|Artist\'s Reference, All Types|Printed', + '2EKW' => 'Editorial|Book|Artist\'s Reference, All Types|All E-Book Internet Distribution Formats', + '2EMV' => 'Editorial|Book|Artist\'s Reference, All Types|All E-Book Distribution Formats', + '2GAL' => 'Editorial|Display|Gallery Exhibition|Printed', + '2GDJ' => 'Editorial|Display|Gallery Exhibition|Electronic Display', + '2MUS' => 'Editorial|Display|Museum Display|Printed', + '2GDK' => 'Editorial|Display|Museum Display|Electronic Display', + '2EAU' => 'Editorial|Display|Poster, Educational Poster|Printed', + '2GHG' => 'Editorial|Website|Web Page, Body Content|Internet Website', + '2GHK' => 'Editorial|Website|Web Page, Body Content|All Internet Distribution Formats', + '2GHH' => 'Editorial|Website|Web Page, Body Content|Recordable Media', + '2GHJ' => 'Editorial|Website|Web Page, Body Content|All Electronic Distribution Formats', + '2GHB' => 'Editorial|Website|Web Page, All Types|Internet Website', + '2GHF' => 'Editorial|Website|Web Page, All Types|All Internet Distribution Formats', + '2GHC' => 'Editorial|Website|Web Page, All Types|Recordable Media', + '2GHD' => 'Editorial|Website|Web Page, All Types|All Electronic Distribution Formats', + '2GHA' => 'Editorial|Website|Webcast, All Types|Internet Website', + '2ZAG' => 'Editorial|Mobile|All Mobile Types|Mobile', + '2GGM' => 'Editorial|Merchandise|CD ROM|Recordable Media', + '2DVE' => 'Editorial|Merchandise|DVD|Recordable Media', + '2AAE' => 'Editorial|All Media Types|All Formats|All Distribution Formats', + '2ZIG' => 'Products|Mobile|Wallpaper|Mobile', + '2ZIP' => 'Products|Mobile|Game, All Types|Mobile', + '2ZAP' => 'Products|Mobile|Entertainment Programming|Mobile', + '2ZEN' => 'Products|Mobile|Computer Software|Mobile', + '2ZAM' => 'Products|Mobile|All Mobile Types|Mobile', + '2ADD' => 'Products|Merchandise|Address Book|Printed', + '2ANT' => 'Products|Merchandise|Anthology|Printed', + '2APP' => 'Products|Merchandise|Apparel, General Apparel|Printed or Woven', + '2TST' => 'Products|Merchandise|Apparel, T-Shirts|Printed or Woven', + '2BIO' => 'Products|Merchandise|Birthday Book|Printed', + '2BLA' => 'Products|Merchandise|Blank Note Book|Printed', + '2ATM' => 'Products|Merchandise|Card, ATM Card|Printed', + '2BNK' => 'Products|Merchandise|Card, Bank Card|Printed', + '2CRE' => 'Products|Merchandise|Card, Credit Card|Printed', + '2BIT' => 'Products|Merchandise|Card, Debit Card|Printed', + '2GFT' => 'Products|Merchandise|Card, Gift Card|Printed', + '2GRE' => 'Products|Merchandise|Card, Greeting Card|Printed', + '2HER' => 'Products|Merchandise|Card, Hero Card|Printed', + '2CRD' => 'Products|Merchandise|Card, Other Card|Printed', + '2ATT' => 'Products|Merchandise|Card, Phone Card|Printed', + '2CDR' => 'Products|Merchandise|CD ROM|Recordable Media', + '2CHK' => 'Products|Merchandise|Check|Printed', + '2BAK' => 'Products|Merchandise|Computer Software|Internet Downloadable File', + '2BAU' => 'Products|Merchandise|Computer Software|Internet Email', + '2BAV' => 'Products|Merchandise|Computer Software|All Internet Distribution Formats', + '2BAJ' => 'Products|Merchandise|Computer Software|Recordable Media', + '2WAR' => 'Products|Merchandise|Computer Software|All Electronic Distribution Formats', + '2GIG' => 'Products|Merchandise|Datebook|Printed', + '2DIA' => 'Products|Merchandise|Diary|Printed', + '2BAZ' => 'Products|Merchandise|Diary|Internet Downloadable File', + '2BBA' => 'Products|Merchandise|Diary|Internet Email', + '2BAW' => 'Products|Merchandise|Diary|Recordable Media', + '2HUB' => 'Products|Merchandise|Double Postcard|Printed', + '2DVD' => 'Products|Merchandise|DVD|Recordable Media', + '2EAT' => 'Products|Merchandise|Edible Media|Printed', + '2FOL' => 'Products|Merchandise|Folder|Printed', + '2GAB' => 'Products|Merchandise|Game, Computer Game|Internet Downloadable File', + '2GAH' => 'Products|Merchandise|Game, Computer Game|Internet Email', + '2GAE' => 'Products|Merchandise|Game, Computer Game|All Internet Distribution Formats', + '2GAG' => 'Products|Merchandise|Game, Computer Game|Recordable Media', + '2GAN' => 'Products|Merchandise|Game, Computer Game|All Electronic Distribution Formats', + '2GAP' => 'Products|Merchandise|Game, All Types|Printed', + '2GAT' => 'Products|Merchandise|Game, All Types|Internet Downloadable File', + '2GAS' => 'Products|Merchandise|Game, All Types|Internet Email', + '2GAD' => 'Products|Merchandise|Game, All Types|All Internet Distribution Formats', + '2GAR' => 'Products|Merchandise|Game, All Types|Recordable Media', + '2GAM' => 'Products|Merchandise|Game, All Types|All Electronic Distribution Formats', + '2BOX' => 'Products|Merchandise|Gift Box|Printed', + '2GIF' => 'Products|Merchandise|Gift Certificate|Printed', + '2WRP' => 'Products|Merchandise|Gift Wrap|Printed', + '2JIG' => 'Products|Merchandise|Jigsaw Puzzle|Printed', + '2JIN' => 'Products|Merchandise|Jigsaw Puzzle|Internet Downloadable File', + '2JIL' => 'Products|Merchandise|Jigsaw Puzzle|Recordable Media', + '2JRN' => 'Products|Merchandise|Journal|Printed', + '2MAP' => 'Products|Merchandise|Map|Printed', + '2MAD' => 'Products|Merchandise|Map|Internet Downloadable File', + '2MET' => 'Products|Merchandise|Map|Internet Email', + '2MIM' => 'Products|Merchandise|Map|All Internet Distribution Formats', + '2MIR' => 'Products|Merchandise|Map|Recordable Media', + '2MAB' => 'Products|Merchandise|Map|All Electronic Distribution Formats', + '2MOU' => 'Products|Merchandise|Mouse Pad|Printed', + '2MUG' => 'Products|Merchandise|Mugs|Printed', + '2NOV' => 'Products|Merchandise|Novelty Products|Printed', + '2MCH' => 'Products|Merchandise|Other Merchandise|Printed', + '2ALB' => 'Products|Merchandise|Photo Album|Printed', + '2MAT' => 'Products|Merchandise|Placemat|Printed', + '2MRP' => 'Products|Merchandise|Plates|Printed', + '2TOP' => 'Products|Merchandise|Poster, Retail Poster|Printed', + '2FUN' => 'Products|Merchandise|Playing Cards|Printed', + '2CLO' => 'Products|Merchandise|Retail Calendar, One Page|Printed', + '2CAL' => 'Products|Merchandise|Retail Calendar, Multi-Page|Printed', + '2BCJ' => 'Products|Merchandise|Retail Calendar, Multi-Page|Internet Downloadable File', + '2BCI' => 'Products|Merchandise|Retail Calendar, Multi-Page|Internet Email', + '2BCH' => 'Products|Merchandise|Retail Calendar, Multi-Page|All Internet Distribution Formats', + '2BCF' => 'Products|Merchandise|Retail Calendar, Multi-Page|Recordable Media', + '2BCG' => 'Products|Merchandise|Retail Calendar, Multi-Page|All Electronic Distribution Formats', + '2FAR' => 'Products|Merchandise|Retail Postcard|Printed', + '2FIB' => 'Products|Merchandise|Screen Saver|Internet Downloadable File', + '2GEL' => 'Products|Merchandise|Screen Saver|Internet Email', + '2TOD' => 'Products|Merchandise|Screen Saver|All Internet Distribution Formats', + '2WRY' => 'Products|Merchandise|Screen Saver|Recordable Media', + '2HEX' => 'Products|Merchandise|Screen Saver|All Electronic Distribution Formats', + '2KEP' => 'Products|Merchandise|Souvenir|Printed', + '2WEE' => 'Products|Merchandise|Stamp|Printed', + '2WIT' => 'Products|Merchandise|Stationery|Printed', + '2TIC' => 'Products|Merchandise|Sticker|Printed', + '2FEM' => 'Products|Merchandise|Textiles|Printed or Woven', + '2TKT' => 'Products|Merchandise|Ticket|Printed', + '2TOY' => 'Products|Merchandise|Toy|Printed', + '2TRD' => 'Products|Merchandise|Trading Cards|Printed', + '2TUA' => 'Products|Merchandise|Virtual Reality|Recordable Media', + '2WAL' => 'Products|Merchandise|Wallpaper|Printed', + '2MER' => 'Products|Merchandise|All Merchandise Types|Printed', + '2BAB' => 'Products|Art|Artist\'s Reference, Tattoo|Printed', + '2DVL' => 'Products|Product Packaging|Packaging For Recordable Media, Liner Notes|Printed', + '2DVP' => 'Products|Product Packaging|Packaging For Recordable Media, All Packaging Types|Printed', + '2FRA' => 'Products|Product Packaging|Picture Frame Insert|Printed', + '2EVE' => 'Products|Product Packaging|Retail Packaging, All Packaging Types|Printed', + '2WHO' => 'Products|Product Packaging|Wholesale Packaging, All Packaging Types|Printed', + '2DAY' => 'Products|Product Packaging|All Product Packaging Types|Printed', + '2AAP' => 'Products|All Media Types|All Formats|All Distribution Formats', + '2TUX' => 'Internal Company Use|Periodicals|Magazine, Custom Published|Printed', + '2BIC' => 'Internal Company Use|Periodicals|Magazine, Custom Published|Intranet and Extranet Website', + '2BIF' => 'Internal Company Use|Periodicals|Magazine, Custom Published|Intranet and Extranet Downloadable File', + '2FOE' => 'Internal Company Use|Periodicals|Magazine, Custom Published|Internet Email', + '2BII' => 'Internal Company Use|Periodicals|Magazine, Custom Published|All Intranet and Extranet Distribution Formats', + '2BIA' => 'Internal Company Use|Periodicals|Magazine, Custom Published|Recordable Media', + '2BIH' => 'Internal Company Use|Periodicals|Magazine, Custom Published|All Electronic Distribution Formats', + '2FRO' => 'Internal Company Use|Comp Use|All Comp Types|Printed', + '2FPO' => 'Internal Company Use|Comp Use|All Comp Types|All Electronic Distribution Formats', + '2GED' => 'Internal Company Use|Internal Review|All Review Types|Printed', + '2GID' => 'Internal Company Use|Internal Review|All Review Types|All Electronic Distribution Formats', + '2GOA' => 'Internal Company Use|Promotional Materials|Corporate Brochure|Printed', + '2BHH' => 'Internal Company Use|Promotional Materials|Corporate Brochure|Intranet and Extranet Downloadable File', + '2BHI' => 'Internal Company Use|Promotional Materials|Corporate Brochure|Intranet and Extranet Email', + '2BHG' => 'Internal Company Use|Promotional Materials|Corporate Brochure|Recordable Media', + '2BHN' => 'Internal Company Use|Promotional Materials|Corporate Calendar|Printed', + '2BHL' => 'Internal Company Use|Promotional Materials|Corporate Calendar|Intranet and Extranet Downloadable File', + '2BHM' => 'Internal Company Use|Promotional Materials|Corporate Calendar|Intranet and Extranet Email', + '2BHK' => 'Internal Company Use|Promotional Materials|Corporate Calendar|Recordable Media', + '2BHY' => 'Internal Company Use|Promotional Materials|Corporate Folder|Printed', + '2BHQ' => 'Internal Company Use|Promotional Materials|Card, Corporate Card|Printed', + '2BHT' => 'Internal Company Use|Promotional Materials|Card, Corporate Card|Intranet and Extranet Downloadable File', + '2BHU' => 'Internal Company Use|Promotional Materials|Card, Corporate Card|Intranet and Extranet Email', + '2BHS' => 'Internal Company Use|Promotional Materials|Card, Corporate Card|Recordable Media', + '2BHZ' => 'Internal Company Use|Promotional Materials|CD ROM|Recordable Media', + '2DVI' => 'Internal Company Use|Promotional Materials|DVD|Recordable Media', + '2BHV' => 'Internal Company Use|Promotional Materials|Sales Kit|All Electronic Distribution Formats', + '2BHW' => 'Internal Company Use|Promotional Materials|Training Materials|Printed', + '2BJN' => 'Internal Company Use|Website|Web Page, Content Body|Intranet and Extranet Website', + '2FAB' => 'Internal Company Use|Website|Web Page, Content Body|Recordable Media', + '2FAC' => 'Internal Company Use|Website|Web Page, Content Body|All Electronic Distribution Formats', + '2FAH' => 'Internal Company Use|Website|Web Page, Design Element|Intranet and Extranet Website', + '2FAI' => 'Internal Company Use|Website|Web Page, Design Element|Recordable Media', + '2FAJ' => 'Internal Company Use|Website|Web Page, Design Element|All Electronic Distribution Formats', + '2NET' => 'Internal Company Use|Website|Web Page, All Types|Intranet and Extranet Website', + '2BJL' => 'Internal Company Use|Website|Web Page, All Types|Recordable Media', + '2BJK' => 'Internal Company Use|Website|Web Page, All Types|All Electronic Distribution Formats', + '2BJH' => 'Internal Company Use|Website|Webcast, All Types|Intranet and Extranet Website', + '2WAN' => 'Internal Company Use|Website|All Website Types|Intranet and Extranet Website', + '2BHD' => 'Internal Company Use|Email|All Email Types|Intranet and Extranet Email', + '2ZUM' => 'Internal Company Use|Mobile|All Mobile Types|Mobile', + '2BHF' => 'Internal Company Use|Live Presentation|Internal Presentation|Projected Display', + '2BHB' => 'Internal Company Use|Art|Art Display, Display Print|Printed', + '2GOY' => 'Internal Company Use|Art|Art Display, All Art Types|Printed', + '2HAO' => 'Internal Company Use|Art|Art Display, All Art Types|Electronic Display', + '2AAI' => 'Internal Company Use|All Media Types|All Formats|All Distribution Formats', + '2TVC' => 'Motion Picture & TV|Television Programming|Commercial|Television Broadcast', + '2TEB' => 'Motion Picture & TV|Television Programming|Commercial|Internet Downloadable File', + '2TEC' => 'Motion Picture & TV|Television Programming|Commercial|All Internet Distribution Formats', + '2TEG' => 'Motion Picture & TV|Television Programming|Commercial|Recordable Media', + '2TVD' => 'Motion Picture & TV|Television Programming|Commercial|All Electronic Distribution Formats', + '2TVE' => 'Motion Picture & TV|Television Programming|Infomercial|Television Broadcast', + '2TEH' => 'Motion Picture & TV|Television Programming|Infomercial|Internet Downloadable File', + '2TEJ' => 'Motion Picture & TV|Television Programming|Infomercial|All Internet Distribution Formats', + '2TEK' => 'Motion Picture & TV|Television Programming|Infomercial|Recordable Media', + '2TVF' => 'Motion Picture & TV|Television Programming|Infomercial|All Electronic Distribution Formats', + '2TVG' => 'Motion Picture & TV|Television Programming|On-Air Promotion|Television Broadcast', + '2TEL' => 'Motion Picture & TV|Television Programming|On-Air Promotion|Internet Downloadable File', + '2TEM' => 'Motion Picture & TV|Television Programming|On-Air Promotion|All Internet Distribution Formats', + '2TEP' => 'Motion Picture & TV|Television Programming|On-Air Promotion|Recordable Media', + '2TVH' => 'Motion Picture & TV|Television Programming|On-Air Promotion|All Electronic Distribution Formats', + '2TVI' => 'Motion Picture & TV|Television Programming|Documentary Program|Television Broadcast', + '2TER' => 'Motion Picture & TV|Television Programming|Documentary Program|Internet Downloadable File', + '2TES' => 'Motion Picture & TV|Television Programming|Documentary Program|All Internet Distribution Formats', + '2TET' => 'Motion Picture & TV|Television Programming|Documentary Program|Recordable Media', + '2TVJ' => 'Motion Picture & TV|Television Programming|Documentary Program|All Electronic Distribution Formats', + '2TVA' => 'Motion Picture & TV|Television Programming|All Television Advertising Types|Television Broadcast', + '2TEA' => 'Motion Picture & TV|Television Programming|All Television Advertising Types|Internet Downloadable File', + '2TEQ' => 'Motion Picture & TV|Television Programming|All Television Advertising Types|All Internet Distribution Formats', + '2TED' => 'Motion Picture & TV|Television Programming|All Television Advertising Types|Recordable Media', + '2TVB' => 'Motion Picture & TV|Television Programming|All Television Advertising Types|All Electronic Distribution Formats', + '2TVK' => 'Motion Picture & TV|Television Programming|Educational Program|Television Broadcast', + '2TEU' => 'Motion Picture & TV|Television Programming|Educational Program|Internet Downloadable File', + '2TEV' => 'Motion Picture & TV|Television Programming|Educational Program|All Internet Distribution Formats', + '2TEW' => 'Motion Picture & TV|Television Programming|Educational Program|Recordable Media', + '2TVL' => 'Motion Picture & TV|Television Programming|Educational Program|All Electronic Distribution Formats', + '2TVM' => 'Motion Picture & TV|Television Programming|Entertainment Program|Television Broadcast', + '2TEY' => 'Motion Picture & TV|Television Programming|Entertainment Program|Internet Downloadable File', + '2TEZ' => 'Motion Picture & TV|Television Programming|Entertainment Program|All Internet Distribution Formats', + '2TLA' => 'Motion Picture & TV|Television Programming|Entertainment Program|Recordable Media', + '2TVN' => 'Motion Picture & TV|Television Programming|Entertainment Program|All Electronic Distribution Formats', + '2TVY' => 'Motion Picture & TV|Television Programming|Made For TV Movie|Television Broadcast', + '2TLC' => 'Motion Picture & TV|Television Programming|Made For TV Movie|Internet Downloadable File', + '2TLB' => 'Motion Picture & TV|Television Programming|Made For TV Movie|All Internet Distribution Formats', + '2TLD' => 'Motion Picture & TV|Television Programming|Made For TV Movie|Recordable Media', + '2TVP' => 'Motion Picture & TV|Television Programming|Made For TV Movie|All Electronic Distribution Formats', + '2TEF' => 'Motion Picture & TV|Television Programming|News Program, Flash|Television Broadcast', + '2TVS' => 'Motion Picture & TV|Television Programming|News Program|Television Broadcast', + '2TLE' => 'Motion Picture & TV|Television Programming|News Program|Internet Downloadable File', + '2TLF' => 'Motion Picture & TV|Television Programming|News Program|All Internet Distribution Formats', + '2TLG' => 'Motion Picture & TV|Television Programming|News Program|Recordable Media', + '2TVT' => 'Motion Picture & TV|Television Programming|News Program|All Electronic Distribution Formats', + '2TLH' => 'Motion Picture & TV|Television Programming|Non Broadcast Pilot|Recordable Media', + '2TLJ' => 'Motion Picture & TV|Television Programming|Non Broadcast Pilot|Projected Display', + '2TVU' => 'Motion Picture & TV|Television Programming|Non-Profit Program|Television Broadcast', + '2TLK' => 'Motion Picture & TV|Television Programming|Non-Profit Program|Internet Downloadable File', + '2TLL' => 'Motion Picture & TV|Television Programming|Non-Profit Program|All Internet Distribution Formats', + '2TLM' => 'Motion Picture & TV|Television Programming|Non-Profit Program|Recordable Media', + '2TVV' => 'Motion Picture & TV|Television Programming|Non-Profit Program|All Electronic Distribution Formats', + '2TLR' => 'Motion Picture & TV|Television Programming|Prop|Television Broadcast', + '2TLN' => 'Motion Picture & TV|Television Programming|Prop|Internet Downloadable File', + '2TLP' => 'Motion Picture & TV|Television Programming|Prop|All Internet Distribution Formats', + '2TLQ' => 'Motion Picture & TV|Television Programming|Prop|Recordable Media', + '2TVW' => 'Motion Picture & TV|Television Programming|Prop|All Electronic Distribution Formats', + '2TLV' => 'Motion Picture & TV|Television Programming|Set Decor|Television Broadcast', + '2TLS' => 'Motion Picture & TV|Television Programming|Set Decor|Internet Downloadable File', + '2TLT' => 'Motion Picture & TV|Television Programming|Set Decor|All Internet Distribution Formats', + '2TLU' => 'Motion Picture & TV|Television Programming|Set Decor|Recordable Media', + '2TVQ' => 'Motion Picture & TV|Television Programming|Set Decor|All Electronic Distribution Formats', + '2KOA' => 'Motion Picture & TV|Television Programming|Artist\'s Reference, All Types|Projected Display', + '2KOB' => 'Motion Picture & TV|Television Programming|Artist\'s Reference, All Types|Internet Downloadable File', + '2KOI' => 'Motion Picture & TV|Television Programming|Artist\'s Reference, All Types|All Internet Distribution Formats', + '2KOP' => 'Motion Picture & TV|Television Programming|Artist\'s Reference, All Types|Recordable Media', + '2KOR' => 'Motion Picture & TV|Television Programming|Artist\'s Reference, All Types|All Electronic Distribution Formats', + '2KOS' => 'Motion Picture & TV|Television Programming|Artist\'s Reference, All Types|Television Broadcast', + '2TEE' => 'Motion Picture & TV|Television Programming|All Editorial Television Types|Television Broadcast', + '2TLW' => 'Motion Picture & TV|Television Programming|All Editorial Television Types|Internet Downloadable File', + '2TLY' => 'Motion Picture & TV|Television Programming|All Editorial Television Types|All Internet Distribution Formats', + '2TLZ' => 'Motion Picture & TV|Television Programming|All Editorial Television Types|Recordable Media', + '2TVZ' => 'Motion Picture & TV|Television Programming|All Editorial Television Types|All Electronic Distribution Formats', + '2JOT' => 'Motion Picture & TV|Motion Picture|In Theater Commercial|Projected Display', + '2ATE' => 'Motion Picture & TV|Motion Picture|Movie Trailer|Projected Display', + '2MPP' => 'Motion Picture & TV|Motion Picture|Movie Trailer|Internet Downloadable File', + '2BET' => 'Motion Picture & TV|Motion Picture|Movie Trailer|All Internet Distribution Formats', + '2DIG' => 'Motion Picture & TV|Motion Picture|Movie Trailer|Recordable Media', + '2AID' => 'Motion Picture & TV|Motion Picture|Movie Trailer|All Electronic Distribution Formats', + '2MPF' => 'Motion Picture & TV|Motion Picture|Movie Trailer|Television Broadcast', + '2JOG' => 'Motion Picture & TV|Motion Picture|Documentary Film|Projected Display', + '2MPM' => 'Motion Picture & TV|Motion Picture|Documentary Film|Internet Downloadable File', + '2TUG' => 'Motion Picture & TV|Motion Picture|Documentary Film|All Internet Distribution Formats', + '2TRY' => 'Motion Picture & TV|Motion Picture|Documentary Film|Recordable Media', + '2DOC' => 'Motion Picture & TV|Motion Picture|Documentary Film|All Electronic Distribution Formats', + '2MPD' => 'Motion Picture & TV|Motion Picture|Documentary Film|Television Broadcast', + '2FEA' => 'Motion Picture & TV|Motion Picture|Feature Film|Projected Display', + '2MPN' => 'Motion Picture & TV|Motion Picture|Feature Film|Internet Downloadable File', + '2WAG' => 'Motion Picture & TV|Motion Picture|Feature Film|All Internet Distribution Formats', + '2WIN' => 'Motion Picture & TV|Motion Picture|Feature Film|Recordable Media', + '2FIL' => 'Motion Picture & TV|Motion Picture|Feature Film|All Electronic Distribution Formats', + '2MPE' => 'Motion Picture & TV|Motion Picture|Feature Film|Television Broadcast', + '2WIZ' => 'Motion Picture & TV|Motion Picture|Short Film|Projected Display', + '2MPS' => 'Motion Picture & TV|Motion Picture|Short Film|Internet Downloadable File', + '2ASK' => 'Motion Picture & TV|Motion Picture|Short Film|All Internet Distribution Formats', + '2AIM' => 'Motion Picture & TV|Motion Picture|Short Film|Recordable Media', + '2FIT' => 'Motion Picture & TV|Motion Picture|Short Film|All Electronic Distribution Formats', + '2MPI' => 'Motion Picture & TV|Motion Picture|Short Film|Television Broadcast', + '2MPG' => 'Motion Picture & TV|Motion Picture|Prop|Television Broadcast', + '2HOP' => 'Motion Picture & TV|Motion Picture|Prop|Projected Display', + '2MPQ' => 'Motion Picture & TV|Motion Picture|Prop|Internet Downloadable File', + '2HIT' => 'Motion Picture & TV|Motion Picture|Prop|All Internet Distribution Formats', + '2FRY' => 'Motion Picture & TV|Motion Picture|Prop|Recordable Media', + '2EFX' => 'Motion Picture & TV|Motion Picture|Prop|All Electronic Distribution Formats', + '2MPH' => 'Motion Picture & TV|Motion Picture|Set Decor|Television Broadcast', + '2MPR' => 'Motion Picture & TV|Motion Picture|Set Decor|Internet Downloadable File', + '2JAB' => 'Motion Picture & TV|Motion Picture|Set Decor|All Internet Distribution Formats', + '2HUG' => 'Motion Picture & TV|Motion Picture|Set Decor|Recordable Media', + '2HUM' => 'Motion Picture & TV|Motion Picture|Set Decor|All Electronic Distribution Formats', + '2ARC' => 'Motion Picture & TV|Motion Picture|Set Decor|Projected Display', + '2TAP' => 'Motion Picture & TV|Motion Picture|Artist\'s Reference, All Types|Projected Display', + '2MPL' => 'Motion Picture & TV|Motion Picture|Artist\'s Reference, All Types|Internet Downloadable File', + '2NOD' => 'Motion Picture & TV|Motion Picture|Artist\'s Reference, All Types|All Internet Distribution Formats', + '2MIX' => 'Motion Picture & TV|Motion Picture|Artist\'s Reference, All Types|Recordable Media', + '2NAP' => 'Motion Picture & TV|Motion Picture|Artist\'s Reference, All Types|All Electronic Distribution Formats', + '2MPC' => 'Motion Picture & TV|Motion Picture|Artist\'s Reference, All Types|Television Broadcast', + '2FIX' => 'Motion Picture & TV|Motion Picture|All Motion Picture Types|Projected Display', + '2MPJ' => 'Motion Picture & TV|Motion Picture|All Motion Picture Types|Internet Downloadable File', + '2DIP' => 'Motion Picture & TV|Motion Picture|All Motion Picture Types|All Internet Distribution Formats', + '2MOV' => 'Motion Picture & TV|Motion Picture|All Motion Picture Types|Recordable Media', + '2MPA' => 'Motion Picture & TV|Motion Picture|All Motion Picture Types|Television Broadcast', + '2ACT' => 'Motion Picture & TV|Motion Picture|All Motion Picture Types|All Electronic Distribution Formats', + '2MPB' => 'Motion Picture & TV|Music Video|All Music Video Types|Television Broadcast', + '2MPK' => 'Motion Picture & TV|Music Video|All Music Video Types|Internet Downloadable File', + '2BER' => 'Motion Picture & TV|Music Video|All Music Video Types|Recordable Media', + '2BES' => 'Motion Picture & TV|Music Video|All Music Video Types|All Internet Distribution Formats', + '2TVR' => 'Motion Picture & TV|Music Video|All Music Video Types|All Electronic Distribution Formats', + '2AAM' => 'Motion Picture & TV|All Media Types|All Formats|All Distribution Formats', + '2WED' => 'Personal Use|Personal Review|All Review Types|Printed', + '2DIM' => 'Personal Use|Personal Review|All Review Types|All Electronic Distribution Formats', + '2BFR' => 'Personal Use|Website|Web Page, All Types|Internet Website', + '2BFU' => 'Personal Use|Website|Web Page, All Types|All Internet Distribution Formats', + '2BFS' => 'Personal Use|Website|Web Page, All Types|Recordable Media', + '2BFT' => 'Personal Use|Website|Web Page, All Types|All Electronic Distribution Formats', + '2ZIT' => 'Personal Use|Mobile|Wallpaper|Mobile', + '2ZOB' => 'Personal Use|Mobile|All Mobile Types|Mobile', + '2BFN' => 'Personal Use|Art|Art Display, Display Print|Printed', + '2KIT' => 'Personal Use|Art|Art Display, All Art Types|Printed', + '2BFJ' => 'Personal Use|Art|Art Display, All Art Types|Internet Website', + '2BFI' => 'Personal Use|Art|Art Display, All Art Types|All Internet Distribution Formats', + '2BFK' => 'Personal Use|Art|Art Display, All Art Types|Electronic Display', + '2BFH' => 'Personal Use|Art|Art Display, All Art Types|All Electronic Distribution Formats', + '2TAT' => 'Personal Use|Art|Artist\'s Reference, Tattoo|Printed', + '2BFP' => 'Personal Use|Art|Study Print, Educational|Printed', + '2AAU' => 'Personal Use|All Media Types|All Formats|All Distribution Formats', + '2AAB' => 'All Categories|Book|All Book Types|All Distribution Formats', + '2AAD' => 'All Categories|Display|All Display Types|All Distribution Formats', + '2AAT' => 'All Categories|Marketing Materials|All Marketing Material Types|All Distribution Formats', + '2AAH' => 'All Categories|Merchandise|All Merchandise Types|All Distribution Formats', + '2AAL' => 'All Categories|Mobile|All Mobile Types|All Distribution Formats', + '2AAX' => 'All Categories|Motion Picture|All Motion Picture Types|All Distribution Formats', + '2AAV' => 'All Categories|Music Video|All Music Video Types|All Distribution Formats', + '2AAC' => 'All Categories|Periodicals|All Periodical Types|All Distribution Formats', + '2AAR' => 'All Categories|Point of Purchase|All Point Of Purchase Types|All Distribution Formats', + '2AAG' => 'All Categories|Product Packaging|All Product Packaging Types|All Distribution Formats', + '2AAN' => 'All Categories|Television Programming|All Television Programming Types|All Distribution Formats', + '2BAA' => 'All Categories|Website|All Web Page Types|All Distribution Formats', + '2ALL' => 'All Categories|All Media Types|All Formats|All Distribution Formats', + '2UNL' => 'Unlicensed|Not Applicable|Not Applicable|Not Applicable', + # 3P - Placement + '3PAA' => 'Any Placements on All Pages', + '3PXX' => 'Not Applicable or None', + '3PUL' => 'Any Placements', + '3PNQ' => 'Single Placement in Content Body', + '3PPU' => 'Single Placement on Title Page', + '3PQT' => 'Single Placement on Table Of Contents', + '3PQA' => 'Single Placement as Frontispiece', + '3PQI' => 'Single Placement on Preface', + '3PPW' => 'Single Placement as Forward', + '3PSA' => 'Single Placement as Front Matter', + '3PNI' => 'Single Placement as Chapter Opener', + '3PQN' => 'Single Placement as Vignette', + '3PRT' => 'Single Placement on Pop Up', + '3PNZ' => 'Single Placement in Bibliography', + '3PQZ' => 'Single Placement on Index', + '3PQG' => 'Single Placement on Any Interior Page', + '3PSR' => 'Single Placement on Inside Cover', + '3PQE' => 'Single Placement on Spine', + '3PSL' => 'Single Placement on Flap', + '3PSP' => 'Single Placement on Back Cover', + '3PNN' => 'Single Placement on Front Cover', + '3PTL' => 'Single Placement on Front Cover And Back Cover', + '3PPA' => 'Single Placement on Dust Jacket', + '3PTD' => 'Single Placements on Interior, Covers and Jacket', + '3PRY' => 'Multiple Placements in Content Body', + '3PRL' => 'Multiple Placements on Any Interior Pages', + '3PSU' => 'Multiple Placements on Inside Cover', + '3PQS' => 'Multiple Placements on Back Cover', + '3PRZ' => 'Multiple Placements on Front Cover', + '3PTM' => 'Multiple Placements on Front Cover And Back Cover', + '3PTC' => 'Multiple Placements on Dust Jacket', + '3PTE' => 'Multiple Placements on Interior, Covers and Jacket', + '3PST' => 'Single Placement on Any Interior Page', + '3PPK' => 'Single Placement on Inside Cover', + '3PNR' => 'Single Placement on Back Cover', + '3PRB' => 'Single Placement on Front Cover', + '3PUD' => 'Single Placement on Back Cover Or Interior Page', + '3PTB' => 'Single Placement on Front Cover And Interior Page', + '3PUF' => 'Single Placement on Front Cover Or Back Cover', + '3PNF' => 'Single Placement on Front Cover And Back Cover', + '3PTP' => 'Single Placement on Any Cover And Interior Page', + '3PQW' => 'Multiple Placements on Any Interior Pages', + '3PNY' => 'Multiple Placements on Inside Cover', + '3PNC' => 'Multiple Placements on Back Cover', + '3PPV' => 'Multiple Placements on Front Cover', + '3PRG' => 'Multiple Placements on Front Cover And Back Cover', + '3PTN' => 'Multiple Placements on Any Covers And Interior Pages', + '3PQX' => 'Single Placement on Any Interior Page', + '3PTF' => 'Single Placement on Section Opener Page', + '3PNT' => 'Single Placement on Front Page', + '3PTH' => 'Single Placement on Section Opener and Front Page', + '3PSY' => 'Multiple Placements on Any Interior Pages', + '3PTG' => 'Multiple Placements on Section Opener Page', + '3PTI' => 'Multiple Placements on Section Opener and Front Page', + '3PPM' => 'Multiple Placements on Any Pages', + '3PQJ' => 'Single Placement on Wrap Around Cover', + '3PQB' => 'Multiple Placements on Wrap Around Cover', + '3PRS' => 'Single Placement in Content Body', + '3PRI' => 'Single Placement as Colophon', + '3PRC' => 'Single Placement on Table Of Contents', + '3PQQ' => 'Single Placement as Unit Opener', + '3PND' => 'Single Placement as Chapter Opener', + '3PQF' => 'Single Placements in Bibliography', + '3PRN' => 'Single Placement on Any Interior Page', + '3PQH' => 'Single Placement on Back Cover', + '3PSJ' => 'Single Placement on Front Cover', + '3PTJ' => 'Single Placement on Any Covers And Interior Pages', + '3PRD' => 'Multiple Placements in Content Body', + '3PSM' => 'Multiple Placements on Any Interior Pages', + '3PSN' => 'Multiple Placements on Back Cover', + '3PPF' => 'Multiple Placements on Front Cover', + '3PTK' => 'Multiple Placements on Any Covers And Interior Pages', + '3PNE' => 'Single Placement on Front Side', + '3PQC' => 'Single Placement on Back Side', + '3PPL' => 'Single Placement on Both Sides', + '3PNV' => 'Multiple Placements on Front Side', + '3PSB' => 'Multiple Placements on Back Side', + '3PQK' => 'Multiple Placements on Both Sides', + '3PTA' => 'Single Placement on One Side', + '3PNB' => 'Multiple Placements on One Side', + '3PRQ' => 'Single Placement on Screen', + '3PSD' => 'Multiple Placements on Screen', + '3PPH' => 'Single Placement on Inside', + '3PSQ' => 'Single Placement on Back Side', + '3PRU' => 'Single Placement on Front Side', + '3PNP' => 'Single Placement on Both Sides', + '3PRK' => 'Multiple Placements on Inside', + '3PQM' => 'Multiple Placements on Back Side', + '3PNK' => 'Multiple Placements on Front Side', + '3PRV' => 'Multiple Placements on Both Sides', + '3PRH' => 'Single Placement on Any Interior Page', + '3PSH' => 'Single Placement on Back Cover', + '3PQY' => 'Single Placement on Front Cover', + '3PRM' => 'Single Placement on Front Cover And Back Cover', + '3PTQ' => 'Single Placement on Any Covers And Interior Pages', + '3PRF' => 'Multiple Placements on Any Interior Pages', + '3PSF' => 'Multiple Placements on Back Cover', + '3PRJ' => 'Multiple Placements on Front Cover', + '3PPP' => 'Multiple Placements on Front Cover And Interior Pages', + '3PSS' => 'Multiple Placements on Front Cover And Back Cover', + '3PTR' => 'Multiple Placements on Any Covers And Interior Pages', + '3PSW' => 'Single Placement on Item', + '3PNL' => 'Multiple Placements on Item', + '3PPX' => 'Single Placement on Packaging Exterior|Front', + '3PUJ' => 'Single Placement on Packaging Exterior|Back or Side', + '3PPD' => 'Single Placement in Packaging Interior', + '3PSI' => 'Multiple Placements on Packaging Exterior|Front', + '3PUH' => 'Multiple Placements on Packaging Exterior|Back or Side', + '3PPC' => 'Multiple Placements in Packaging Interior', + '3PTS' => 'Single Placement Anywhere On Packaging', + '3PTT' => 'Multiple Placements Anywhere On Packaging', + '3PNW' => 'Single Placement in Body Of Program', + '3PQU' => 'Single Placement in Closing Sequence', + '3PRR' => 'Single Placement in Title Sequence', + '3PTV' => 'Single Placement in Any Part', + '3PPZ' => 'Multiple Placements in Body Of Program', + '3PPN' => 'Multiple Placements in Closing Sequence', + '3PSV' => 'Multiple Placements in Title Sequence', + '3PTU' => 'Multiple Placements in Any Part', + '3PRP' => 'Single Placement in Body Of Advertisement', + '3PPJ' => 'Multiple Placements in Body Of Advertisement', + '3PPR' => 'Single Placement in Any Part', + '3PRW' => 'Multiple Placements in Any Part', + '3PQD' => 'Single Placement on Secondary Page', + '3PQP' => 'Single Placement on Pop Up', + '3PPS' => 'Single Placement on Landing Page', + '3PPG' => 'Single Placement on Splash Page', + '3PPY' => 'Single Placement on Home Page', + '3PTY' => 'Single Placement on Home Page And Secondary Pages', + '3PTW' => 'Single Placement on Any Pages', + '3PSZ' => 'Multiple Placements on Secondary Pages', + '3PNJ' => 'Multiple Placements on Pop Ups', + '3PPI' => 'Multiple Placements on Landing Pages', + '3PNS' => 'Multiple Placements on Splash Pages', + '3PNU' => 'Multiple Placements on Home Page', + '3PPQ' => 'Multiple Placements on Home Page And Secondary Pages', + '3PTZ' => 'Multiple Placements on Any Pages', + '3PPE' => 'Single Placement as Flash', + '3PNM' => 'Single Placement in Body Of Program', + '3PPB' => 'Single Placement in Closing Sequence', + '3PSC' => 'Single Placement in Title Sequence', + '3PUC' => 'Single Placement in Any Part', + '3PNX' => 'Multiple Placements as Flash', + '3PNH' => 'Multiple Placements in Body Of Program', + '3PQL' => 'Multiple Placements in Closing Sequence', + '3PSK' => 'Multiple Placements in Title Sequence', + '3PUB' => 'Multiple Placements in Any Part', + # 4S - Size + '4SAA' => 'Any Size Image|Any Size Media', + '4SXX' => 'Not Applicable or None', + '4SUL' => 'Any Sizes', + '4SJA' => 'Up To 1/16 Page|Any Size Page', + '4SBN' => 'Up To 1/8 Page Image|Any Size Page', + '4SJB' => 'Up To 1/4 Page Image|Any Size Page', + '4SEU' => 'Up To 1/3 Page Image|Any Size Page', + '4SEJ' => 'Up To 1/2 Page Image|Any Size Page', + '4SMG' => 'Up To 3/4 Page Image|Any Size Page', + '4SAG' => 'Up To Full Page Image|Any Size Page', + '4SFI' => 'Up To 2 Page Image|Any Size Pages', + '4SJZ' => 'Up To 3 Page Image|Any Size Pages', + '4SFG' => 'Up To 4 Page Image|Any Size Pages', + '4SBP' => 'Any Size Image|Any Size Page', + '4SGF' => 'Up To 1/4 Page Image|Up To 1/4 Page Ad', + '4SCH' => 'Up To 1/4 Page Image|Up To 1/2 Page Ad', + '4SIY' => 'Up To 1/4 Page Image|Up To Full Page Ad', + '4SCV' => 'Up To 1/2 Page Image|Up To 1/2 Page Ad', + '4SLY' => 'Up To 1/2 Page Image|Up To Full Page Ad', + '4SBU' => 'Up To 1/2 Page Image|Up To 2 Page Ad', + '4SCP' => 'Up To Full Page Image|Up To Full Page Ad', + '4SGL' => 'Up To Full Page Image|Up To 2 Page Ad', + '4SGM' => 'Up To Full Page Image|Any Size Ad', + '4SMB' => 'Up To 2 Page Image|Up To 2 Page Ad', + '4SFR' => 'Up To 2 Page Image|Any Size Ad', + '4SKP' => 'Any Size Image|Any Size Ad', + '4SBK' => 'Up To 1/16 Page Image|Any Size Page', + '4SJS' => 'Up To 1/8 Page Image|Any Size Page', + '4SLV' => 'Up To 1/4 Page Image|Any Size Page', + '4SGW' => 'Up To 1/2 Page Image|Any Size Page', + '4SKD' => 'Up To Full Page Image|Any Size Page', + '4SFJ' => 'Up To 2 Page Image|Any Size Pages', + '4SLA' => 'Any Size Image|Any Size Pages', + '4SKE' => 'Up To 1/8 Page Image|Any Size Page', + '4SAK' => 'Up To 1/4 Page Image|Any Size Page', + '4SLD' => 'Up To 1/2 Page Image|Any Size Page', + '4SJV' => 'Up To Full Page Image|Any Size Page', + '4SJU' => 'Up To 2 Page Image|Any Size Pages', + '4SIW' => 'Any Size Image|Any Size Pages', + '4SAL' => 'Up To 1/4 Area Image|Up To Full Area Media', + '4SJM' => 'Up To 1/2 Area Image|Up To Full Area Media', + '4SKZ' => 'Up To Full Area Image|Up To Full Area Media', + '4SCN' => 'Up To 1/8 Page Image|Up To Full Page Media', + '4SLW' => 'Up To 1/4 Page Image|Up To Full Page Media', + '4SIZ' => 'Up To 1/2 Page Image|Up To Full Page Media', + '4SAC' => 'Up To Full Page Image|Up To Full Page Media', + '4SFX' => 'Up To 8 x 10 Inch Image|Any Size Media', + '4SFP' => 'Up To 11 x 14 Inch Image|Any Size Media', + '4SMV' => 'Any Size Image|Any Size Media', + '4SJD' => 'Up To 21 x 30 cm Image|Any Size Media', + '4SFQ' => 'Up To 30 x 42 cm Image|Any Size Media', + '4SJK' => 'Any Size Image|Up To Full Card', + '4SEQ' => 'Up To 5 x 5 Inch Image|Up To 40 x 40 Inch Media', + '4SIV' => 'Up To 10 x 10 Inch Image|Up To 40 x 40 Inch Media', + '4SCE' => 'Up To 20 x 20 Inch Image|Up To 40 x 40 Inch Media', + '4SDP' => 'Up To 30x 30 Inch Image|Up To 40 x 40 Inch Media', + '4SCT' => 'Up To 40 x 40 Inch Image|Up To 40 x 40 Inch Media', + '4SBJ' => 'Up To 20 x 20 cm Image|Up To 100 x 100 cm Media', + '4SKI' => 'Up To 30 x 30 cm Image|Up To 100 x 100 cm Media', + '4SJW' => 'Up To 40 x 40 cm Image|Up To 100 x 100 cm Media', + '4SCB' => 'Up To 50 x 50 cm Image|Up To 100 x 100 cm Media', + '4SAT' => 'Up To 75 x 75 cm Image|Up To 100 x 100 cm Media', + '4SCI' => 'Up To 100 x 100 cm Image|Up To 100 x 100 cm Media', + '4SGP' => 'Any Size Image|Any Size Media', + '4SIX' => 'Up To 1/4 Area Image|Up To 11 x 36 Foot Display', + '4SHA' => 'Up To 1/4 Area Image|Up To 10 x 40 Foot Display', + '4SGU' => 'Up To 1/4 Area Image|Up To 14 x 48 Foot Display', + '4SAJ' => 'Up To 1/2 Area Image|Up To 11 x 36 Foot Display', + '4SDX' => 'Up To 1/2 Area Image|Up To 10 x 40 Foot Display', + '4SCR' => 'Up To 1/2 Area Image|Up To 14 x 48 Foot Display', + '4SFM' => 'Up To Full Area Image|Up To 11 x 36 Foot Display', + '4SKV' => 'Up To Full Area Image|Up To 10 x 40 Foot Display', + '4SGE' => 'Up To Full Area Image|Up To 14 x 48 Foot Display', + '4SMW' => 'Up To Full Area Image|Any Size Display', + '4SJI' => 'Up To 1/4 Area Image|Up To 4 x 8 Foot Media', + '4SBI' => 'Up To 1/4 Area Image|Up To 10 x 8 Foot Media', + '4SIM' => 'Up To 1/4 Area Image|Up To 12 x 24 Foot Media', + '4SFF' => 'Up To 1/4 Area Image|Any Size Media', + '4SAX' => 'Up To 1/2 Area Image|Up To 4 x 8 Foot Media', + '4SLI' => 'Up To 1/2 Area Image|Up To 10 x 8 Foot Media', + '4SLS' => 'Up To 1/2 Area Image|Up To 12 x 24 Foot Media', + '4SMK' => 'Up To 1/2 Area Image|Any Size Media', + '4SLG' => 'Up To Full Area Image|Up To 4 x 8 Foot Media', + '4SAN' => 'Up To Full Area Image|Up To 10 x 8 Foot Media', + '4SDI' => 'Up To Full Area Image|Up To 12 x 24 Foot Media', + '4SML' => 'Up To Full Area Image|Any Size Media', + '4SKF' => 'Up To 1/4 Area Image|Up To 672 Square Foot Display', + '4SKR' => 'Up To 1/4 Area Image|Up To 1,200 Square Foot Display', + '4SLK' => 'Up To 1/4 Area Image|Up To 2,400 Square Foot Display', + '4SJQ' => 'Up To 1/4 Area Image|Up To 4,800 Square Foot Display', + '4SEY' => 'Up To 1/4 Area Image|Up To 10,000 Square Foot Display', + '4SFE' => 'Up To 1/4 Area Image|Any Size Display', + '4SKS' => 'Up To 1/2 Area Image|Up To 672 Square Foot Display', + '4SGS' => 'Up To 1/2 Area Image|Up To 1,200 Square Foot Display', + '4SMA' => 'Up To 1/2 Area Image|Up To 2,400 Square Foot Display', + '4SAF' => 'Up To 1/2 Area Image|Up To 4,800 Square Foot Display', + '4SAW' => 'Up To 1/2 Area Image|Up To 10,000 Square Foot Display', + '4SAQ' => 'Up To 1/2 Area Image|Any Size Display', + '4SLN' => 'Up To Full Area Image|Up To 672 Square Foot Display', + '4SDS' => 'Up To Full Area Image|Up To 1,200 Square Foot Display', + '4SIT' => 'Up To Full Area Image|Up To 2,400 Square Foot Display', + '4SGX' => 'Up To Full Area Image|Up To 4,800 Square Foot Display', + '4SBD' => 'Up To Full Area Image|Up To 10,000 Square Foot Display', + '4SBF' => 'Up To Full Area Image|Any Size Display', + '4SDD' => 'Up To 1/4 Area Image|Up To 4 Sheet Display', + '4SBC' => 'Up To 1/4 Area Image|Up To 8 Sheet Display', + '4SLJ' => 'Up To 1/4 Area Image|Up To 12 Sheet Display', + '4SAD' => 'Up To 1/4 Area Image|Up To 16 Sheet Display', + '4SEA' => 'Up To 1/4 Area Image|Up To 30 Sheet Display', + '4SCD' => 'Up To 1/4 Area Image|Up To 48 Sheet Display', + '4SKX' => 'Up To 1/4 Area Image|Up To 96 Sheet Display', + '4SMN' => 'Up To 1/4 Area Image|Any Size Display', + '4SDU' => 'Up To 1/2 Area Image|Up To 4 Sheet Display', + '4SBL' => 'Up To 1/2 Area Image|Up To 8 Sheet Display', + '4SER' => 'Up To 1/2 Area Image|Up To 12 Sheet Display', + '4SEN' => 'Up To 1/2 Area Image|Up To 16 Sheet Display', + '4SLP' => 'Up To 1/2 Area Image|Up To 30 Sheet Display', + '4SGQ' => 'Up To 1/2 Area Image|Up To 48 Sheet Display', + '4SDF' => 'Up To 1/2 Area Image|Up To 96 Sheet Display', + '4SMP' => 'Up To 1/2 Area Image|Any Size Display', + '4SFL' => 'Up To Full Area Image|Up To 4 Sheet Display', + '4SFS' => 'Up To Full Area Image|Up To 8 Sheet Display', + '4SIF' => 'Up To Full Area Image|Up To 12 Sheet Display', + '4SIS' => 'Up To Full Area Image|Up To 16 Sheet Display', + '4SFD' => 'Up To Full Area Image|Up To 30 Sheet Display', + '4SFU' => 'Up To Full Area Image|Up To 48 Sheet Display', + '4SDK' => 'Up To Full Area Image|Up To 96 Sheet Display', + '4SMQ' => 'Up To Full Area Image|Any Size Display', + '4SKA' => 'Up To 1/4 Area Image|Up To 20 x 30 Inch Media', + '4SIK' => 'Up To 1/4 Area Image|Up To 24 x 36 Inch Media', + '4SFK' => 'Up To 1/4 Area Image|Up To 30 x 40 Inch Media', + '4SDV' => 'Up To 1/4 Area Image|Up To 40 x 60 Inch Media', + '4SMX' => 'Up To 1/4 Area Image|Any Size Media', + '4SEF' => 'Up To 1/4 Area Image|Up To A1 Media', + '4SCJ' => 'Up To 1/4 Area Image|Up To B1 Media', + '4SJG' => 'Up To 1/4 Area Image|Up To A0 Media', + '4SIP' => 'Up To 1/4 Area Image|Up To B0 Media', + '4SKU' => 'Up To 1/2 Area Image|Up To 20 x 30 Inch Media', + '4SAS' => 'Up To 1/2 Area Image|Up To 24 x 36 Inch Media', + '4SGB' => 'Up To 1/2 Area Image|Up To 30 x 40 Inch Media', + '4SBQ' => 'Up To 1/2 Area Image|Up To 40 x 60 Inch Media', + '4SMY' => 'Up To 1/2 Area Image|Any Size Media', + '4SKJ' => 'Up To 1/2 Area Image|Up To A1 Media', + '4SAM' => 'Up To 1/2 Area Image|Up To B1 Media', + '4SDZ' => 'Up To 1/2 Area Image|Up To A0 Media', + '4SGT' => 'Up To 1/2 Area Image|Up To B0 Media', + '4SKN' => 'Up To Full Area Image|Up To 20 x 30 Inch Media', + '4SIQ' => 'Up To Full Area Image|Up To 24 x 36 Inch Media', + '4SLT' => 'Up To Full Area Image|Up To 30 x 40 Inch Media', + '4SDN' => 'Up To Full Area Image|Up To 40 x 60 Inch Media', + '4SMZ' => 'Up To Full Area Image|Any Size Media', + '4SBH' => 'Up To Full Area Image|Up To A1 Media', + '4SLU' => 'Up To Full Area Image|Up To B1 Media', + '4SEL' => 'Up To Full Area Image|Up To A0 Media', + '4SBM' => 'Up To Full Area Image|Up To B0 Media', + '4SIH' => 'Up To 1/4 Area Image|Up To 24 x 30 Inch Display', + '4SKW' => 'Up To 1/4 Area Image|Up To 30 x 40 Inch Display', + '4SDM' => 'Up To 1/4 Area Image|Up To 27 x 85 Inch Display', + '4SJP' => 'Up To 1/4 Area Image|Up To 60 x 40 Inch Display', + '4SIB' => 'Up To 1/4 Area Image|Up To 69 x 48 Inch Display', + '4SDH' => 'Up To 1/4 Area Image|Up To 27 x 141 Inch Display', + '4SJL' => 'Up To 1/4 Area Image|Up To 30 x 240 Inch Display', + '4SLQ' => 'Up To 1/4 Area Image|Up To B1 Display', + '4SLL' => 'Up To 1/4 Area Image|Up To A0 Display', + '4SEI' => 'Up To 1/4 Area Image|Up To B0 Display', + '4SBA' => 'Up To 1/2 Area Image|Up To 24 x 30 Inch Display', + '4SCL' => 'Up To 1/2 Area Image|Up To 30 x 40 Inch Display', + '4SIC' => 'Up To 1/2 Area Image|Up To 27 x 85 Inch Display', + '4SBY' => 'Up To 1/2 Area Image|Up To 60 x 40 Inch Display', + '4SFZ' => 'Up To 1/2 Area Image|Up To 27 x 141 Inch Display', + '4SAU' => 'Up To 1/2 Area Image|Up To 26 x 241 Inch Display', + '4SBR' => 'Up To 1/2 Area Image|Up To 30 x 240 Inch Display', + '4SCC' => 'Up To 1/2 Area Image|Up To B1 Display', + '4SAB' => 'Up To 1/2 Area Image|Up To A0 Display', + '4SLX' => 'Up To 1/2 Area Image|Up To B0 Display', + '4SGI' => 'Up To Full Area Image|Up To 24 x 30 Inch Display', + '4SBT' => 'Up To Full Area Image|Up To 30 x 40 Inch Display', + '4SGK' => 'Up To Full Area Image|Up To 27 x 85 Inch Display', + '4SIL' => 'Up To Full Area Image|Up To 60 x 40 Inch Display', + '4SAH' => 'Up To Full Area Image|Up To 69 x 48 Inch Display', + '4SGA' => 'Up To Full Area Image|Up To 27 x 141 Inch Display', + '4SDR' => 'Up To Full Area Image|Up To 26 x 241 Inch Display', + '4SID' => 'Up To Full Area Image|Up To 30 x 240 Inch Display', + '4SCX' => 'Up To Full Area Image|Any Size Display', + '4SGR' => 'Up To Full Area Image|Up To B1 Display', + '4SEC' => 'Up To Full Area Image|Up To A0 Display', + '4SET' => 'Up To Full Area Image|Up To B0 Display', + '4SKT' => 'Up To 1/4 Area Image|Up To 43 x 62 Inch Display', + '4SEW' => 'Up To 1/4 Area Image|Up To 48 x 71 Inch Display', + '4SEH' => 'Up To 1/4 Area Image|Up To 43 x 126 Inch Display', + '4SBS' => 'Up To 1/4 Area Image|Up To 83 x 135 Inch Display', + '4SMR' => 'Up To 1/4 Area Image|Any Size Display', + '4SJX' => 'Up To 1/4 Area Image|Up To B0 Display', + '4SAY' => 'Up To 1/2 Area Image|Up To 43 x 62 Inch Display', + '4SKY' => 'Up To 1/2 Area Image|Up To 48 x 71 Inch Display', + '4SBV' => 'Up To 1/2 Area Image|Up To 43 x 126 Inch Display', + '4SEP' => 'Up To 1/2 Area Image|Up To 83 x 135 Inch Display', + '4SNG' => 'Up To 1/2 Area Image|Any Size Display', + '4SAZ' => 'Up To 1/2 Area Image|Up To B0 Display', + '4SDW' => 'Up To Full Area Image|Up To 43 x 62 Inch Display', + '4SFW' => 'Up To Full Area Image|Up To 48 x 71 Inch Display', + '4SGN' => 'Up To Full Area Image|Up To 43 x 126 Inch Display', + '4SBX' => 'Up To Full Area Image|Up To 83 x 135 Inch Display', + '4SNO' => 'Up To Full Area Image|Any Size Display', + '4SKK' => 'Up To Full Area Image|Up To B0 Display', + '4SAP' => 'Up To 1/4 Screen Image|Up To 32 Inch Screen', + '4SEK' => 'Up To 1/4 Screen Image|Up To 63 Inch Screen', + '4SLZ' => 'Up To 1/4 Screen Image|Up To 10 Diagonal Foot Screen', + '4SIE' => 'Up To 1/4 Screen Image|Up To 30 Diagonal Foot Screen', + '4SEM' => 'Up To 1/4 Screen Image|Up To 100 Diagonal Foot Screen', + '4SGJ' => 'Up To 1/2 Screen Image|Up To 32 Inch Screen', + '4SBE' => 'Up To 1/2 Screen Image|Up To 63 Inch Screen', + '4SIJ' => 'Up To 1/2 Screen Image|Up To 10 Diagonal Foot Screen', + '4SGY' => 'Up To 1/2 Screen Image|Up To 30 Diagonal Foot Screen', + '4SDQ' => 'Up To 1/2 Screen Image|Up To 100 Diagonal Foot Screen', + '4SBZ' => 'Up To Full Screen Image|Up To 32 Inch Screen', + '4SJF' => 'Up To Full Screen Image|Up To 63 Inch Screen', + '4SLE' => 'Up To Full Screen Image|Up To 10 Diagonal Foot Screen', + '4SJY' => 'Up To Full Screen Image|Up To 30 Diagonal Foot Screen', + '4SKC' => 'Up To Full Screen Image|Up To 100 Diagonal Foot Screen', + '4SDL' => 'Up To Full Screen Image|Any Size Screen', + '4SFA' => 'Up To 1/4 Area Image|Any Size Item', + '4SCG' => 'Up To 1/2 Area Image|Any Size Item', + '4SLR' => 'Up To Full Area Image|Any Size Item', + '4SGZ' => 'Up To 3 x 4.5 Inch Image|Any Size Media', + '4SFH' => 'Up To 5 x 7 Inch Image|Any Size Media', + '4SCU' => 'Up To 6 x 9 Inch Image|Any Size Media', + '4SLF' => 'Up To 8 x 10 Inch Image|Any Size Media', + '4SAV' => 'Up To 8 x 12 Inch Image|Any Size Media', + '4SKB' => 'Up To 11 x 14 Inch Image|Any Size Media', + '4SAE' => 'Up To 14 x 20 Inch Image|Any Size Media', + '4SEZ' => 'Up To 16 x 20 Inch Image|Any Size Media', + '4SDB' => 'Up To 20 x 24 Inch Image|Any Size Media', + '4SDG' => 'Up To 24 x 30 Inch Image|Any Size Media', + '4SDE' => 'Up To 30 x 40 Inch Image|Any Size Media', + '4SJE' => 'Up To 38 x 50 Inch Image|Any Size Media', + '4SCM' => 'Up To 40 x 60 Inch Image|Any Size Media', + '4SIN' => 'Any Size Image|Any Size Media', + '4SDA' => 'Up To 11 x 15 cm Image|Any Size Media', + '4SME' => 'Up To 13 x 18 cm Image|Any Size Media', + '4SFC' => 'Up To 15 x 21 cm Image|Any Size Media', + '4SIG' => 'Up To 18 x 25 cm Image|Any Size Media', + '4SEV' => 'Up To 21 x 30 cm Image|Any Size Media', + '4SJJ' => 'Up To 25 x 36 cm Image|Any Size Media', + '4SMD' => 'Up To 25 x 36 cm Image|Any Size Media', + '4SLH' => 'Up To 30 x 42 cm Image|Any Size Media', + '4SEE' => 'Up To 42 x 60 cm Image|Any Size Media', + '4SDC' => 'Up To 50 x 71 cm Image|Any Size Media', + '4SDY' => 'Up To 60 x 85 cm Image|Any Size Media', + '4SCQ' => 'Up To 70 x 100 cm Image|Any Size Media', + '4SMF' => 'Up To 85 x 119 cm Image|Any Size Media', + '4SJC' => 'Up To 100 x 142 cm Image|Any Size Media', + '4SFN' => 'Up To 1/4 Area Image|Up To 25 x 13 Inch Media', + '4SLC' => 'Up To 1/4 Area Image|Up To 50 x 24 Inch Media', + '4SIR' => 'Up To 1/4 Area Image|Up To 26 x 53 Inch Media', + '4SDT' => 'Up To 1/4 Area Image|Up To 46 x 60 Inch Media', + '4SFB' => 'Up To 1/4 Area Image|Up To 138 x 53 Inch Media', + '4SGV' => 'Up To 1/2 Area Image|Up To 25 x 13 Inch Media', + '4SJR' => 'Up To 1/2 Area Image|Up To 50 x 24 Inch Media', + '4SKL' => 'Up To 1/2 Area Image|Up To 26 x 53 Inch Media', + '4SEX' => 'Up To 1/2 Area Image|Up To 46 x 60 Inch Media', + '4SBW' => 'Up To 1/2 Area Image|Up To 138 x 53 Inch Media', + '4SJN' => 'Up To Full Area Image|Up To 25 x 13 Inch Media', + '4SKH' => 'Up To Full Area Image|Up To 50 x 24 Inch Media', + '4SKM' => 'Up To Full Area Image|Up To 26 x 53 Inch Media', + '4SGG' => 'Up To Full Area Image|Up To 46 x 60 Inch Media', + '4SDJ' => 'Up To Full Area Image|Up To 138 x 53 Inch Media', + '4SCZ' => 'Up To 1/4 Screen Image|Up To 15 Inch Screen', + '4SCS' => 'Up To 1/4 Screen Image|Up To 21 Inch Screen', + '4SMS' => 'Up To 1/4 Screen Image|Any Size Screen', + '4SED' => 'Up To 1/2 Screen Image|Up To 15 Inch Screen', + '4SFV' => 'Up To 1/2 Screen Image|Up To 21 Inch Screen', + '4SMT' => 'Up To 1/2 Screen Image|Any Size Screen', + '4SCY' => 'Up To Full Screen Image|Up To 15 Inch Screen', + '4SEB' => 'Up To Full Screen Image|Up To 21 Inch Screen', + '4SMU' => 'Up To Full Screen Image|Any Size Screen', + '4SGH' => 'Up To 1/4 Screen Image|Any Size Screen', + '4SGC' => 'Up To 1/2 Screen Image|Any Size Screen', + '4SES' => 'Up To Full Screen Image|Any Size Screen', + '4SKQ' => 'Up To 1/4 Area Image|Up To 180 x 150 Pixels Ad', + '4SCA' => 'Up To 1/4 Area Image|Up To 468 x 60 Pixels Ad', + '4SCK' => 'Up To 1/4 Area Image|Up To 728 x 90 Pixels Ad', + '4SCF' => 'Up To 1/4 Area Image|Up To 300 x 600 Pixels Ad', + '4SIU' => 'Up To 1/4 Area Image|Up To Full Screen Ad', + '4SAI' => 'Up To 1/2 Area Image|Up To 180 x 150 Pixels Ad', + '4SII' => 'Up To 1/2 Area Image|Up To 468 x 60 Pixels Ad', + '4SCW' => 'Up To 1/2 Area Image|Up To 728 x 90 Pixels Ad', + '4SLM' => 'Up To 1/2 Area Image|Up To 300 x 600 Pixels Ad', + '4SFT' => 'Up To 1/2 Area Image|Up To Full Screen Ad', + '4SJT' => 'Up To Full Area Image|Up To 180 x 150 Pixels Ad', + '4SGD' => 'Up To Full Area Image|Up To 468 x 60 Pixels Ad', + '4SAR' => 'Up To Full Area Image|Up To 728 x 90 Pixels Ad', + '4SEG' => 'Up To Full Area Image|Up To 300 x 600 Pixels Ad', + '4SBG' => 'Any Size Image|Up To Full Screen Ad', + '4SMH' => 'Up To 150 x 150 Pixels Image|Any Size Screen', + '4SMJ' => 'Up To 300 x 600 Pixels Image|Any Size Screen', + '4SKG' => 'Any Size Image|Any Size Screen', + # 5V - Version + '5VAA' => 'All Versions', + '5VXX' => 'Not Applicable or None', + '5VUL' => 'Any Versions', + '5VVM' => 'Single Print Version', + '5VVB' => 'Multiple Print Versions', + '5VUP' => 'Single Version', + '5VUY' => 'Multiple Versions', + '5VVC' => 'Single Paperback Edition', + '5VUK' => 'Single Hardcover Edition', + '5VVH' => 'Single Edition in All Binding Formats', + '5VVK' => 'Multiple Paperback Editions', + '5VUU' => 'Multiple Hardcover Editions', + '5VVL' => 'Multiple Editions in All Binding Formats', + '5VUZ' => 'Single Issue', + '5VVJ' => 'Multiple Issues', + '5VUG' => 'Single Edition', + '5VVG' => 'Multiple Editions', + # 6Q - Quantity + '6QAA' => 'Any Quantity', + '6QXX' => 'Not Applicable or None', + '6QUL' => 'Any Quantity', + '6QAU' => 'One|Print Run', + '6QDA' => 'Up To 10|Print Run', + '6QEY' => 'Up To 100|Print Run', + '6QBA' => 'Up To 1,000|Print Run', + '6QCW' => 'Up To 5,000|Print Run', + '6QEC' => 'Up To 10,000|Print Run', + '6QFD' => 'Up To 25,000|Print Run', + '6QBH' => 'Up To 40,000|Print Run', + '6QFR' => 'Up To 50,000|Print Run', + '6QDQ' => 'Up To 100,000|Print Run', + '6QBG' => 'Up To 250,000|Print Run', + '6QEN' => 'Up To 500,000|Print Run', + '6QDL' => 'Any Quantity Of|Print Run', + '6QBU' => 'One|Copy', + '6QDR' => 'Up To 10|Total Circulation', + '6QFU' => 'Up To 25|Total Circulation', + '6QFV' => 'Up To 50|Total Circulation', + '6QEJ' => 'Up To 100|Total Circulation', + '6QFW' => 'Up To 250|Total Circulation', + '6QFY' => 'Up To 500|Total Circulation', + '6QCD' => 'Up To 1,000|Total Circulation', + '6QFZ' => 'Up To 2,500|Total Circulation', + '6QAT' => 'Up To 5,000|Total Circulation', + '6QBB' => 'Up To 10,000|Total Circulation', + '6QFS' => 'Up To 25,000|Total Circulation', + '6QAN' => 'Up To 50,000|Total Circulation', + '6QCS' => 'Up To 100,000|Total Circulation', + '6QDT' => 'Up To 250,000|Total Circulation', + '6QCI' => 'Up To 500,000|Total Circulation', + '6QCN' => 'Up To 1 Million|Total Circulation', + '6QCK' => 'Up To 2 Million|Total Circulation', + '6QCL' => 'Up To 3 Million|Total Circulation', + '6QAV' => 'Up To 5 Million|Total Circulation', + '6QDK' => 'Up To 10 Million|Total Circulation', + '6QGB' => 'Up To 25 Million|Total Circulation', + '6QGC' => 'Up To 50 Million|Total Circulation', + '6QEV' => 'Any Quantity Of|Circulation', + '6QFI' => 'One|Reprint', + '6QDG' => 'Up To 10|Reprints', + '6QCB' => 'Up To 100|Reprints', + '6QAY' => 'Up To 1,000|Reprints', + '6QBF' => 'Up To 10,000|Reprints', + '6QCU' => 'Any Quantity Of|Reprints', + '6QEH' => 'One|Print Run', + '6QDH' => 'Up To 10|Print Run', + '6QAZ' => 'Up To 100|Print Run', + '6QFB' => 'Up To 1,000|Print Run', + '6QAQ' => 'Up To 5,000|Print Run', + '6QEG' => 'Up To 10,000|Print Run', + '6QBV' => 'Up To 25,000|Print Run', + '6QCG' => 'Up To 50,000|Print Run', + '6QAH' => 'Up To 100,000|Print Run', + '6QDE' => 'Up To 250,000|Print Run', + '6QDJ' => 'Up To 500,000|Print Run', + '6QCZ' => 'Up To 1 Million|Print Run', + '6QCT' => 'Up To 2 Million|Print Run', + '6QAR' => 'Up To 3 Million|Print Run', + '6QDC' => 'Up To 5 Million|Print Run', + '6QDU' => 'Up To 10 Million|Print Run', + '6QEU' => 'Any Quantity Of|Print Run', + '6QFT' => 'One|Copy', + '6QDI' => 'One|Display', + '6QDY' => 'Up To 5|Displays', + '6QFJ' => 'Up To 10|Displays', + '6QEL' => 'Up To 25|Displays', + '6QBD' => 'Up To 50|Displays', + '6QAE' => 'Up To 100|Displays', + '6QCE' => 'Up To 250|Displays', + '6QAP' => 'Up To 500|Displays', + '6QBY' => 'Up To 1,000|Displays', + '6QBC' => 'Up To 2,500|Displays', + '6QET' => 'Up To 5,000|Displays', + '6QFF' => 'Up To 10,000|Displays', + '6QDS' => 'Up To 25,000|Displays', + '6QES' => 'Up To 50,000|Displays', + '6QDZ' => 'Up To 100,000|Displays', + '6QBW' => 'Up To 250,000|Displays', + '6QAX' => 'Up To 500,000|Displays', + '6QDB' => 'Up To 1 Million|Displays', + '6QEK' => 'Up To 2 Million|Displays', + '6QFA' => 'Up To 3 Million|Displays', + '6QCJ' => 'Up To 5 Million|Displays', + '6QFQ' => 'Any Quantity Of|Displays', + '6QCX' => 'One|Display', + '6QBP' => 'Up To 5|Displays', + '6QAL' => 'Up To 10|Displays', + '6QDX' => 'Up To 25|Displays', + '6QEM' => 'Up To 50|Displays', + '6QEA' => 'Up To 100|Displays', + '6QFG' => 'Up To 250|Displays', + '6QAG' => 'Up To 500|Displays', + '6QEI' => 'Any Quantity Of|Displays', + '6QEP' => 'One|Copy', + '6QEX' => 'Two|Copies', + '6QCF' => 'Three|Copies', + '6QBK' => 'Four|Copies', + '6QBL' => 'Five|Copies', + '6QCP' => 'Up To 10|Copies', + '6QDV' => 'Up To 50|Copies', + '6QCM' => 'Up To 100|Copies', + '6QAI' => 'Up To 500|Copies', + '6QAS' => 'Up To 1,000|Copies', + '6QDW' => 'Up To 5,000|Copies', + '6QCQ' => 'Up To 10,000|Copies', + '6QAM' => 'Any Quantity Of|Copies', + '6QBE' => 'One|Copy', + '6QFC' => 'Up To 5|Copies', + '6QEB' => 'Up To 10|Copies', + '6QGD' => 'Up To 25|Copies', + '6QGE' => 'Up To 50|Copies', + '6QCR' => 'Up To 100|Copies', + '6QCA' => 'Up To 250|Copies', + '6QBS' => 'Up To 500|Copies', + '6QDF' => 'Up To 1,000|Copies', + '6QEW' => 'Up To 2,500|Copies', + '6QFE' => 'Up To 5,000|Copies', + '6QEE' => 'Up To 10,000|Copies', + '6QBT' => 'Up To 25,000|Copies', + '6QDP' => 'Up To 50,000|Copies', + '6QDN' => 'Up To 100,000|Copies', + '6QFN' => 'Any Quantity Of|Copies', + '6QFH' => 'Up To 10,000|Viewers', + '6QCV' => 'Up To 100,000|Viewers', + '6QBN' => 'Up To 1 Million|Viewers', + '6QFP' => 'Up To 10 Million|Viewers', + '6QBI' => 'Up To 100 Million|Viewers', + '6QBQ' => 'Any Quantity Of|Viewers', + '6QAB' => 'Up To 10,000|Impressions', + '6QBR' => 'Up To 100,000|Impressions', + '6QCY' => 'Up To 1 Million|Impressions', + '6QBM' => 'Up To 10 Million|Impressions', + '6QFM' => 'Any Quantity Of|Impressions', + '6QDD' => 'Up To 100|Viewers', + '6QEQ' => 'Up To 1,000|Viewers', + '6QEZ' => 'Up To 10,000|Viewers', + '6QBZ' => 'Up To 100,000|Viewers', + '6QCC' => 'Any Quantity Of|Viewers', + '6QCH' => 'One|Copy', + '6QAW' => 'Up To 5|Copies', + '6QAK' => 'Up To 10|Copies', + '6QFL' => 'Up To 100|Copies', + '6QAC' => 'Up To 1,000|Copies', + '6QAD' => 'Up To 10,000|Copies', + '6QEF' => 'Up To 25,000|Copies', + '6QAF' => 'Up To 50,000|Copies', + '6QED' => 'Up To 100,000|Copies', + '6QFK' => 'Up To 250,000|Copies', + '6QDM' => 'Up To 500,000|Copies', + '6QBX' => 'Up To 1 Million|Copies', + '6QER' => 'Any Quantity Of|Copies', + # 7D - Duration + '7DAA' => 'In Perpetuity', + '7DXX' => 'Not Applicable or None', + '7DUL' => 'Any Durations', + '7DUT' => 'Up To 10 Years', + '7DUS' => 'Up To 6 Months', + '7DUV' => 'Up To 6 Months', + '7DUW' => 'Up To 1 Year', + '7DUY' => 'Up To 3 Years', + '7DUZ' => 'Up To 5 Years', + '7DUQ' => 'Up To 10 Years', + '7DXC' => 'Up To 1 Day', + '7DXL' => 'Up To 1 Week', + '7DXH' => 'Life Of Publication', + '7DYF' => 'Up To 1 Day', + '7DWL' => 'Up To 1 Week', + '7DYJ' => 'Up To 2 Weeks', + '7DXF' => 'Up To 1 Month', + '7DZF' => 'Up To 2 Months', + '7DWC' => 'Up To 3 Months', + '7DWW' => 'Up To 6 Months', + '7DZA' => 'Up To 1 Year', + '7DZP' => 'Up To 2 Years', + '7DZJ' => 'Up To 3 Years', + '7DZK' => 'Up To 5 Years', + '7DZL' => 'Up To 10 Years', + '7DWS' => 'Life Of Publication', + '7DXZ' => 'Up To 3 Months', + '7DXW' => 'Up To 6 Months', + '7DXD' => 'Up To 1 Year', + '7DYS' => 'Life Of Publication', + '7DYM' => 'Up To 1 Year', + '7DWE' => 'Up To 2 Years', + '7DYL' => 'Up To 3 Years', + '7DWV' => 'Up To 5 Years', + '7DWB' => 'Up To 7 Years', + '7DYY' => 'Up To 10 Years', + '7DWG' => 'Up To 15 Years', + '7DXA' => 'Full Term Of Copyright', + '7DXT' => 'Up To 1 Day', + '7DXB' => 'Up To 1 Week', + '7DYI' => 'Up To 1 Month', + '7DWI' => 'Up To 1 Year', + '7DZM' => 'Up To 2 Years', + '7DZN' => 'Up To 3 Years', + '7DYV' => 'Life Of Event', + '7DXQ' => 'Up To 1 Year', + '7DZH' => 'Up To 2 Years', + '7DXP' => 'Up To 3 Years', + '7DYD' => 'Up To 5 Years', + '7DWU' => 'Up To 7 Years', + '7DXG' => 'Up To 10 Years', + '7DXV' => 'Up To 15 Years', + '7DWR' => 'In Perpetuity', + '7DXM' => 'Up To 1 Year', + '7DWK' => 'Up To 2 Years', + '7DXS' => 'In Perpetuity', + '7DYG' => 'Up To 1 Day', + '7DZD' => 'Up To 1 Week', + '7DWP' => 'Up To 13 Weeks', + '7DYT' => 'Up To 26 Weeks', + '7DWT' => 'Up To 52 Weeks', + '7DYA' => 'Up To 5 Years', + '7DXR' => 'Up To 10 Years', + '7DXI' => 'In Perpetuity', + '7DYW' => 'Up To 1 Day', + '7DYP' => 'Up To 1 Week', + '7DWJ' => 'Up To 1 Month', + '7DYE' => 'Up To 3 Months', + '7DYX' => 'Up To 6 Months', + '7DXE' => 'Up To 1 Year', + '7DWZ' => 'Up To 2 Years', + '7DZB' => 'Up To 3 Years', + '7DYN' => 'Up To 5 Years', + '7DYC' => 'Up To 10 Years', + '7DXY' => 'Up To 15 Years', + '7DWM' => 'In Perpetuity', + '7DYZ' => 'Up To 1 Day', + '7DXK' => 'Up To 1 Month', + '7DWY' => 'Up To 3 Months', + '7DYB' => 'Up To 6 Months', + '7DZG' => 'Up To 1 Year', + '7DYK' => 'Up To 2 Years', + '7DYQ' => 'In Perpetuity', + # 8R - Region + '8RAA' => 'Worldwide', + '8RXX' => 'Not Applicable or None', + '8RUL' => 'Any Regions', + '8RWA' => 'Broad International Region|Worldwide Excluding Northern America', + '8RWB' => 'Broad International Region|Worldwide Excluding USA', + '8RWC' => 'Broad International Region|Worldwide Excluding USA and Europe', + '8RWD' => 'Broad International Region|Worldwide Excluding Europe', + '8RWE' => 'Broad International Region|Worldwide Excluding USA and UK', + '8RWF' => 'Broad International Region|Worldwide Excluding UK', + '8RWG' => 'Broad International Region|All English Speaking Countries', + '8RWH' => 'Broad International Region|All English Speaking Countries Excluding USA', + '8RAH' => 'Broad International Region|All Spanish Speaking Countries', + '8RWI' => 'Broad International Region|All Spanish Speaking Countries Excluding USA', + '8RFY' => 'Broad International Region|All Americas', + '8REK' => 'Broad International Region|Europe, Middle East and Africa', + '8RWJ' => 'Broad International Region|USA, Canada and Mexico', + '8RQV' => 'Northern America|One Minor City, Up To 250,000 Population', + '8RQT' => 'Northern America|One Major City, Over 250,000 Population', + '8RQU' => 'Northern America|One Metropolitan Area, Adjoining Cities', + '8RRJ' => 'Northern America|One State Or Province', + '8RYK' => 'Northern America|Up To 3 States Or Provinces', + '8RCD' => 'Northern America|Up To 5 States Or Provinces', + '8RGJ' => 'Northern America|All Northern American Countries', + '8RCE' => 'Northern America|USA and Canada', + '8RHQ' => 'Northern America|USA', + '8RCA' => 'Northern America|Canada', + '8RHJ' => 'Northern America|USA-Central', + '8RHP' => 'Northern America|USA-Midwest', + '8RHR' => 'Northern America|USA-Northeast', + '8RHS' => 'Northern America|USA-Pacific Northwest', + '8RHW' => 'Northern America|USA-Southeast', + '8RHX' => 'Northern America|USA-Southwest', + '8RIA' => 'Northern America|USA-West', + '8RHY' => 'Northern America|USA-Minor Outlying Islands', + '8RUK' => 'Northern America|USA-All Territories, Protectorates, Dependencies, Outposts', + '8RBK' => 'Northern America|Canada-British Columbia', + '8RUM' => 'Northern America|Canada-Prairies', + '8RUN' => 'Northern America|Canada-Atlantic Provinces', + '8RCJ' => 'Northern America|Canada-Ontario', + '8RUP' => 'Northern America|Canada-Quebec', + '8RUQ' => 'Northern America|Canada-Northern Territories', + '8RBM' => 'Northern America|Bermuda', + '8RGL' => 'Northern America|Greenland', + '8RPM' => 'Northern America|Saint Pierre and Miquelon', + '8RQL' => 'Europe|One Minor City, Up To 250,000 Population', + '8RQJ' => 'Europe|One Major City, Over 250,000 Population', + '8RQK' => 'Europe|One Metropolitan Area, Adjoining Cities', + '8RRF' => 'Europe|One State Or Province', + '8RYF' => 'Europe|Up To 3 States Or Provinces', + '8RYG' => 'Europe|Up To 5 States Or Provinces', + '8RDU' => 'Europe|All Europe', + '8REL' => 'Europe|All European Union Countries', + '8REI' => 'Europe|All United Kingdom', + '8REJ' => 'Europe|All Western Europe', + '8RED' => 'Europe|All Northern Europe', + '8REB' => 'Europe|All European Mediterranean Countries', + '8REA' => 'Europe|All Eastern Europe', + '8RDW' => 'Europe|All Baltic States', + '8RDX' => 'Europe|All Benelux', + '8RDY' => 'Europe|All Caucasian States', + '8REF' => 'Europe|All Scandinavia', + '8RAX' => 'Europe|Aland Islands', + '8RAL' => 'Europe|Albania', + '8RAD' => 'Europe|Andorra', + '8RAM' => 'Europe|Armenia', + '8RAT' => 'Europe|Austria', + '8RAZ' => 'Europe|Azerbaijan', + '8RBY' => 'Europe|Belarus', + '8RBE' => 'Europe|Belgium', + '8RBA' => 'Europe|Bosnia and Herzegovina', + '8RBG' => 'Europe|Bulgaria', + '8RDR' => 'Europe|Croatia', + '8RCY' => 'Europe|Cyprus', + '8RCZ' => 'Europe|Czech Republic', + '8RDK' => 'Europe|Denmark', + '8REM' => 'Europe|England', + '8REE' => 'Europe|Estonia', + '8RDS' => 'Europe|Faeroe Islands', + '8RFI' => 'Europe|Finland', + '8RFR' => 'Europe|France', + '8RGE' => 'Europe|Georgia', + '8RDE' => 'Europe|Germany', + '8RGI' => 'Europe|Gibraltar', + '8RGR' => 'Europe|Greece', + '8RGG' => 'Europe|Guernsey', + '8RHU' => 'Europe|Hungary', + '8RIS' => 'Europe|Iceland', + '8RIE' => 'Europe|Ireland', + '8RIM' => 'Europe|Isle Of Man', + '8RIT' => 'Europe|Italy', + '8RJE' => 'Europe|Jersey', + '8RLV' => 'Europe|Latvia', + '8RLI' => 'Europe|Liechtenstein', + '8RLT' => 'Europe|Lithuania', + '8RLU' => 'Europe|Luxembourg', + '8RMK' => 'Europe|Macedonia', + '8RMT' => 'Europe|Malta', + '8RMD' => 'Europe|Moldova', + '8RMC' => 'Europe|Monaco', + '8RNL' => 'Europe|Netherlands', + '8RUH' => 'Europe|Northern Ireland', + '8RNO' => 'Europe|Norway', + '8RPL' => 'Europe|Poland', + '8RPT' => 'Europe|Portugal', + '8RRO' => 'Europe|Romania', + '8RRU' => 'Europe|Russian Federation', + '8RSM' => 'Europe|San Marino', + '8REN' => 'Europe|Scotland', + '8RCS' => 'Europe|Serbia and Montenegro', + '8RSK' => 'Europe|Slovakia', + '8RSI' => 'Europe|Slovenia', + '8RES' => 'Europe|Spain', + '8RSE' => 'Europe|Sweden', + '8RCH' => 'Europe|Switzerland', + '8RUA' => 'Europe|Ukraine', + '8RUI' => 'Europe|Wales', + '8RDT' => 'Europe|Vatican City State', + '8RQF' => 'Asia|One Minor City, Up To 250,000 Population', + '8RQD' => 'Asia|One Major City, Over 250,000 Population', + '8RQE' => 'Asia|One Metropolitan Area, Adjoining Cities', + '8RRC' => 'Asia|One State Or Province', + '8RAV' => 'Asia|Up To 3 States Or Provinces', + '8RYD' => 'Asia|Up To 5 States Or Provinces', + '8RDB' => 'Asia|All Asia', + '8RDC' => 'Asia|All Central Asia', + '8RCP' => 'Asia|All Eastern Asia', + '8RDG' => 'Asia|All Southern Asia', + '8RDH' => 'Asia|All Southeastern Asia', + '8RBD' => 'Asia|Bangladesh', + '8RBT' => 'Asia|Bhutan', + '8RBN' => 'Asia|Brunei Darussalam', + '8RKH' => 'Asia|Cambodia', + '8RCN' => 'Asia|All China', + '8RUB' => 'Asia|China-East', + '8RAY' => 'Asia|China-Northeast', + '8RUC' => 'Asia|China-North', + '8RUD' => 'Asia|China-South Central', + '8RUF' => 'Asia|China-Southwest', + '8RHK' => 'Asia|Hong Kong', + '8RIN' => 'Asia|India', + '8RID' => 'Asia|Indonesia', + '8RJP' => 'Asia|Japan', + '8RKZ' => 'Asia|Kazakhstan', + '8RKP' => 'Asia|North Korea', + '8RKR' => 'Asia|South Korea', + '8RKG' => 'Asia|Kyrgyzstan', + '8RLA' => 'Asia|Laos', + '8RMO' => 'Asia|Macao', + '8RMY' => 'Asia|Malaysia', + '8RMV' => 'Asia|Maldives', + '8RMN' => 'Asia|Mongolia', + '8RMM' => 'Asia|Myanmar', + '8RNP' => 'Asia|Nepal', + '8RPK' => 'Asia|Pakistan', + '8RPH' => 'Asia|Philippines', + '8RSG' => 'Asia|Singapore', + '8RTW' => 'Asia|Taiwan', + '8RTJ' => 'Asia|Tajikistan', + '8RTH' => 'Asia|Thailand', + '8RDA' => 'Asia|Tibet', + '8RTL' => 'Asia|Timor-Leste', + '8RTM' => 'Asia|Turkmenistan', + '8RUZ' => 'Asia|Uzbekistan', + '8RVN' => 'Asia|Viet Nam', + '8RQO' => 'Latin America and Caribbean|One Minor City, Up To 250,000 Population', + '8RQM' => 'Latin America and Caribbean|One Major City, Over 250,000 Population', + '8RQN' => 'Latin America and Caribbean|One Metropolitan Area, Adjoining Cities', + '8RRG' => 'Latin America and Caribbean|One State Or Province', + '8RYH' => 'Latin America and Caribbean|Up To 3 States Or Provinces', + '8RYI' => 'Latin America and Caribbean|Up To 5 States Or Provinces', + '8RAC' => 'Latin America and Caribbean|All Latin America and Caribbean', + '8RUJ' => 'Latin America and Caribbean|All Latin America', + '8RFZ' => 'Latin America and Caribbean|All Caribbean', + '8RFS' => 'Latin America and Caribbean|All South America', + '8RGC' => 'Latin America and Caribbean|All Central America', + '8RFT' => 'Latin America and Caribbean|All Andean Countries', + '8RFU' => 'Latin America and Caribbean|All Southern Cone', + '8RFV' => 'Latin America and Caribbean|All Amazonia', + '8RAI' => 'Latin America and Caribbean|Anguilla', + '8RAG' => 'Latin America and Caribbean|Antigua and Barbuda', + '8RAR' => 'Latin America and Caribbean|Argentina', + '8RAW' => 'Latin America and Caribbean|Aruba', + '8RBS' => 'Latin America and Caribbean|Bahamas', + '8RBB' => 'Latin America and Caribbean|Barbados', + '8RBZ' => 'Latin America and Caribbean|Belize', + '8RGZ' => 'Latin America and Caribbean|Bequia', + '8RBO' => 'Latin America and Caribbean|Bolivia', + '8RHA' => 'Latin America and Caribbean|Bonaire', + '8RBR' => 'Latin America and Caribbean|Brazil', + '8RHB' => 'Latin America and Caribbean|British Virgin Islands', + '8RKY' => 'Latin America and Caribbean|Cayman Islands', + '8RCL' => 'Latin America and Caribbean|Chile', + '8RCO' => 'Latin America and Caribbean|Colombia', + '8RCR' => 'Latin America and Caribbean|Costa Rica', + '8RCU' => 'Latin America and Caribbean|Cuba', + '8RHC' => 'Latin America and Caribbean|Curacao', + '8RDM' => 'Latin America and Caribbean|Dominica', + '8RDO' => 'Latin America and Caribbean|Dominican Republic', + '8REC' => 'Latin America and Caribbean|Ecuador', + '8RSV' => 'Latin America and Caribbean|El Salvador', + '8RFK' => 'Latin America and Caribbean|Falkland Islands, Malvinas', + '8RGF' => 'Latin America and Caribbean|French Guiana', + '8RGD' => 'Latin America and Caribbean|Grenada', + '8RGP' => 'Latin America and Caribbean|Guadeloupe', + '8RGT' => 'Latin America and Caribbean|Guatemala', + '8RGY' => 'Latin America and Caribbean|Guyana', + '8RHT' => 'Latin America and Caribbean|Haiti', + '8RHN' => 'Latin America and Caribbean|Honduras', + '8RJM' => 'Latin America and Caribbean|Jamaica', + '8RMQ' => 'Latin America and Caribbean|Martinique', + '8RMX' => 'Latin America and Caribbean|Mexico', + '8RMS' => 'Latin America and Caribbean|Montserrat', + '8RAN' => 'Latin America and Caribbean|Netherlands Antilles', + '8RNI' => 'Latin America and Caribbean|Nicaragua', + '8RPA' => 'Latin America and Caribbean|Panama', + '8RPY' => 'Latin America and Caribbean|Paraguay', + '8RFQ' => 'Latin America and Caribbean|Patagonia', + '8RPE' => 'Latin America and Caribbean|Peru', + '8RPR' => 'Latin America and Caribbean|Puerto Rico', + '8RHD' => 'Latin America and Caribbean|Saba', + '8RHE' => 'Latin America and Caribbean|Saint Barthelemy', + '8RHF' => 'Latin America and Caribbean|Saint Eustatius', + '8RKN' => 'Latin America and Caribbean|Saint Kitts and Nevis', + '8RLC' => 'Latin America and Caribbean|Saint Lucia', + '8RHG' => 'Latin America and Caribbean|Saint Martin', + '8RVC' => 'Latin America and Caribbean|Saint Vincent and The Grenadines', + '8RSR' => 'Latin America and Caribbean|Suriname', + '8RTT' => 'Latin America and Caribbean|Trinidad and Tobago', + '8RTC' => 'Latin America and Caribbean|Turks and Caicos Islands', + '8RHH' => 'Latin America and Caribbean|U.S. Virgin Islands', + '8RUY' => 'Latin America and Caribbean|Uruguay', + '8RVE' => 'Latin America and Caribbean|Venezuela', + '8RQZ' => 'Oceania|One Minor City, Up To 250,000 Population', + '8RQW' => 'Oceania|One Major City, Over 250,000 Population', + '8RQY' => 'Oceania|One Metropolitan Area, Adjoining Cities', + '8RRK' => 'Oceania|One State Or Province', + '8RYL' => 'Oceania|Up To 3 States Or Provinces', + '8RYM' => 'Oceania|Up To 5 States Or Provinces', + '8RCT' => 'Oceania|All Oceania', + '8RUR' => 'Oceania|All Australia and New Zealand', + '8RUS' => 'Oceania|All Oceania excluding Australia and New Zealand', + '8RAU' => 'Oceania|Australia', + '8RAS' => 'Oceania|American Samoa', + '8RCX' => 'Oceania|Christmas Island', + '8RCC' => 'Oceania|Cocos, Keeling Islands', + '8RKM' => 'Oceania|Comoros', + '8RCK' => 'Oceania|Cook Islands', + '8RFJ' => 'Oceania|Fiji', + '8RPF' => 'Oceania|French Polynesia', + '8RGU' => 'Oceania|Guam', + '8RKI' => 'Oceania|Kiribati', + '8RMG' => 'Oceania|Madagascar', + '8RMH' => 'Oceania|Marshall Islands', + '8RMU' => 'Oceania|Mauritius', + '8RFM' => 'Oceania|Micronesia', + '8RFF' => 'Oceania|Midway Islands', + '8RNR' => 'Oceania|Nauru', + '8RNC' => 'Oceania|New Caledonia', + '8RNZ' => 'Oceania|New Zealand', + '8RNU' => 'Oceania|Niue', + '8RNF' => 'Oceania|Norfolk Island', + '8RMP' => 'Oceania|Northern Mariana Islands', + '8RPW' => 'Oceania|Palau', + '8RPG' => 'Oceania|Papua New Guinea', + '8RPN' => 'Oceania|Pitcairn Islands', + '8RFH' => 'Oceania|Rapa Nui, Easter Island', + '8RWS' => 'Oceania|Samoa', + '8RSC' => 'Oceania|Seychelles', + '8RSB' => 'Oceania|Solomon Islands', + '8RLK' => 'Oceania|Sri Lanka', + '8RFL' => 'Oceania|Tahiti', + '8RTK' => 'Oceania|Tokelau', + '8RTO' => 'Oceania|Tonga', + '8RTV' => 'Oceania|Tuvalu', + '8RVU' => 'Oceania|Vanuatu', + '8RFP' => 'Oceania|Wallis and Futuna', + '8RQS' => 'Middle East|One Minor City, Up To 250,000 Population', + '8RQP' => 'Middle East|One Major City, Over 250,000 Population', + '8RQR' => 'Middle East|One Metropolitan Area, Adjoining Cities', + '8RRH' => 'Middle East|One State Or Province', + '8RYJ' => 'Middle East|Up To 3 States Or Provinces', + '8RBX' => 'Middle East|Up To 5 States Or Provinces', + '8REX' => 'Middle East|All Middle East', + '8REY' => 'Middle East|All Middle Eastern Gulf States', + '8RIB' => 'Middle East|All Middle Eastern Mediterranean Countries', + '8RAF' => 'Middle East|Afghanistan', + '8RBH' => 'Middle East|Bahrain', + '8RIR' => 'Middle East|Iran', + '8RIQ' => 'Middle East|Iraq', + '8RIL' => 'Middle East|Israel', + '8RJO' => 'Middle East|Jordan', + '8RKW' => 'Middle East|Kuwait', + '8RLB' => 'Middle East|Lebanon', + '8ROM' => 'Middle East|Oman', + '8REV' => 'Middle East|Palestinian Authority', + '8RQA' => 'Middle East|Qatar', + '8RSA' => 'Middle East|Saudi Arabia', + '8RSY' => 'Middle East|Syria', + '8RTR' => 'Middle East|Turkey', + '8RAE' => 'Middle East|United Arab Emirates', + '8RYE' => 'Middle East|Yemen', + '8RQC' => 'Africa|One Minor City, Up To 250,000 Population', + '8RQX' => 'Africa|One Major City, Over 250,000 Population', + '8RQB' => 'Africa|One Metropolitan Area, Adjoining Cities', + '8RRB' => 'Africa|One State Or Province', + '8RYB' => 'Africa|Up To 3 States Or Provinces', + '8RYC' => 'Africa|Up To 5 States Or Provinces', + '8RAJ' => 'Africa|All Africa', + '8RAK' => 'Africa|All African Mediterranean Countries', + '8RAP' => 'Africa|All Central Africa', + '8RAQ' => 'Africa|All Eastern Africa', + '8RBC' => 'Africa|All Southern Africa', + '8RBL' => 'Africa|All Western Africa', + '8RDZ' => 'Africa|Algeria', + '8RAO' => 'Africa|Angola', + '8RBP' => 'Africa|Ascension Island', + '8RBJ' => 'Africa|Benin', + '8RBW' => 'Africa|Botswana', + '8RBF' => 'Africa|Burkina Faso', + '8RBI' => 'Africa|Burundi', + '8RCM' => 'Africa|Cameroon', + '8RCV' => 'Africa|Cape Verde', + '8RCF' => 'Africa|Central African Republic', + '8RTD' => 'Africa|Chad', + '8RCG' => 'Africa|Congo', + '8RCI' => 'Africa|Cote D\'Ivoire', + '8RDJ' => 'Africa|Djibouti', + '8REG' => 'Africa|Egypt', + '8RGQ' => 'Africa|Equatorial Guinea', + '8RER' => 'Africa|Eritrea', + '8RET' => 'Africa|Ethiopia', + '8RGA' => 'Africa|Gabon', + '8RGM' => 'Africa|Gambia', + '8RGH' => 'Africa|Ghana', + '8RGN' => 'Africa|Guinea', + '8RGW' => 'Africa|Guinea-Bissau', + '8RKE' => 'Africa|Kenya', + '8RLS' => 'Africa|Lesotho', + '8RLR' => 'Africa|Liberia', + '8RLY' => 'Africa|Libyan Arab Jamahiriya', + '8RMW' => 'Africa|Malawi', + '8RML' => 'Africa|Mali', + '8RMR' => 'Africa|Mauritania', + '8RYT' => 'Africa|Mayotte', + '8RMA' => 'Africa|Morocco', + '8RMZ' => 'Africa|Mozambique', + '8RNA' => 'Africa|Namibia', + '8RNE' => 'Africa|Niger', + '8RNG' => 'Africa|Nigeria', + '8RRE' => 'Africa|Reunion', + '8RRW' => 'Africa|Rwanda', + '8RSH' => 'Africa|Saint Helena', + '8RST' => 'Africa|Sao Tome and Principe', + '8RSN' => 'Africa|Senegal', + '8RSL' => 'Africa|Sierra Leone', + '8RSO' => 'Africa|Somalia', + '8RZA' => 'Africa|South Africa', + '8RSD' => 'Africa|Sudan', + '8RSZ' => 'Africa|Swaziland', + '8RTZ' => 'Africa|Tanzania, United Republic Of', + '8RTG' => 'Africa|Togo', + '8RTN' => 'Africa|Tunisia', + '8RUG' => 'Africa|Uganda', + '8REH' => 'Africa|Western Sahara', + '8RZM' => 'Africa|Zambia', + '8RZW' => 'Africa|Zimbabwe', + '8RBQ' => 'Other Regions|Antarctica', + '8RCB' => 'Other Regions|All Arctic and Arctic Ocean Islands', + '8RFB' => 'Other Regions|All Northern Atlantic Ocean Islands', + '8RFW' => 'Other Regions|All Southern Atlantic Ocean Islands', + '8RFX' => 'Other Regions|All Southern Indian Ocean Islands', + '8REU' => 'Other Regions|All French Southern Territories', + '8RDQ' => 'Other Regions|All British Indian Ocean Territories', + # 8L - Language + '8LAA' => 'All Languages', + '8LXX' => 'Not Applicable or None', + '8LUL' => 'Any Languages', + '8LOL' => 'Any One Language', + '8LEN' => 'English', + '8LAF' => 'Afrikaans', + '8LAR' => 'Arabic', + '8LBO' => 'Bosnian', + '8LBU' => 'Bulgarian', + '8LCA' => 'Chinese-Cantonese', + '8LCH' => 'Chinese-Mandarin', + '8LCP' => 'Chinese-Other', + '8LCR' => 'Croatian', + '8LCZ' => 'Czech', + '8LDA' => 'Danish', + '8LDU' => 'Dutch', + '8LES' => 'Estonian', + '8LFI' => 'Finnish', + '8LFR' => 'French', + '8LGE' => 'German', + '8LGR' => 'Greek', + '8LHE' => 'Hebrew', + '8LHI' => 'Hindi', + '8LHU' => 'Hungarian', + '8LIC' => 'Icelandic', + '8LIN' => 'Indonesian', + '8LIG' => 'Irish Gaelic', + '8LIT' => 'Italian', + '8LJA' => 'Japanese', + '8LKO' => 'Korean', + '8LLA' => 'Latvian', + '8LMG' => 'Mongolian', + '8LNO' => 'Norwegian', + '8LPO' => 'Polish', + '8LPR' => 'Portuguese', + '8LRO' => 'Romanian', + '8LRU' => 'Russian', + '8LSG' => 'Scottish Gaelic', + '8LSE' => 'Serbian', + '8LSI' => 'Sindhi', + '8LSV' => 'Slovakian', + '8LSL' => 'Slovenian', + '8LSP' => 'Spanish', + '8LSH' => 'Swahili', + '8LSZ' => 'Swazi', + '8LSW' => 'Swedish', + '8LTA' => 'Tagalog', + '8LTH' => 'Thai', + '8LTU' => 'Turkish', + '8LUR' => 'Ukrainian', + '8LYI' => 'Yiddish', + '8LOT' => 'Other Language', + # 8I - Industry + '8IAA' => 'All Industries', + '8IXX' => 'Not Applicable or None', + '8IUL' => 'Any Industries', + '8IAD' => 'Advertising and Marketing', + '8IAG' => 'Agriculture, Farming and Horticulture', + '8IAT' => 'Airline Transportation', + '8IAL' => 'Alcohol', + '8IAR' => 'Architecture and Engineering', + '8IAE' => 'Arts and Entertainment', + '8IAU' => 'Automotive', + '8IAV' => 'Aviation', + '8IBA' => 'Baby and Childcare', + '8IBE' => 'Beauty and Personal Care', + '8IBI' => 'Biotechnology', + '8IBR' => 'Broadcast Media', + '8ICO' => 'Business Consulting and Services', + '8ICH' => 'Chemicals', + '8ICE' => 'Communications Equipment and Services', + '8IHS' => 'Computer Hardware, Software and Peripherals', + '8ICC' => 'Construction and Contracting', + '8IAP' => 'Consumer Appliances and Electronics', + '8ICG' => 'Counseling', + '8IEC' => 'Ecology, Environmental and Conservation', + '8IED' => 'Education', + '8IEM' => 'Employment Training and Recruitment', + '8IEN' => 'Energy, Utilities and Fuel', + '8IEV' => 'Events and Conventions', + '8IFA' => 'Fashion', + '8IFI' => 'Financial Services and Banking', + '8IFB' => 'Food and Beverage Processing', + '8IFL' => 'Food and Beverage Retail', + '8IFS' => 'Food Services', + '8IFO' => 'Forestry and Wood Products', + '8IFR' => 'Freight and Warehousing', + '8IFU' => 'Furniture', + '8IGA' => 'Games, Toys and Hobbies', + '8IGI' => 'Gaming Industry', + '8IGL' => 'Gardening and Landscaping', + '8IGO' => 'Government and Politics', + '8IGR' => 'Graphic Design', + '8IGC' => 'Greeting Card', + '8IHI' => 'Heavy Industry', + '8IHO' => 'Home Improvement', + '8IHH' => 'Hotels and Hospitality', + '8IHA' => 'Household Appliances', + '8IHC' => 'Household Cleaning Products', + '8IIM' => 'Industry and Manufacturing', + '8IIT' => 'Information Technologies', + '8IIN' => 'Insurance', + '8IIS' => 'Internet Services', + '8ILS' => 'Legal Services', + '8IME' => 'Medical and Healthcare', + '8IMS' => 'Microelectronics and Semiconductors', + '8IMW' => 'Military and Weapons', + '8IMM' => 'Mining and Metals', + '8IMU' => 'Music', + '8INP' => 'Not For Profit, Social, Charitable', + '8IOP' => 'Office Products', + '8IOG' => 'Oil and Gas', + '8IOI' => 'Other Industry', + '8IPO' => 'Personal Use Only', + '8IPP' => 'Pet Products and Services', + '8IPS' => 'Pharmaceuticals and Supplements', + '8IPT' => 'Printing and Reprographics', + '8IPR' => 'Public Relations', + '8IPM' => 'Publishing Media', + '8IRE' => 'Real Estate', + '8IRR' => 'Religion and Religious Services', + '8ISM' => 'Retail Sales and Marketing', + '8IRM' => 'Retail Merchandise', + '8ISS' => 'Safety and Security', + '8ISC' => 'Sciences', + '8ISH' => 'Shipping', + '8ISO' => 'Software', + '8ISF' => 'Sports, Fitness and Recreation', + '8ITE' => 'Telecommunications', + '8ITX' => 'Textiles and Apparel', + '8ITB' => 'Tobacco', + '8ITR' => 'Travel and Tourism', + # 9E - Exclusivity + '9EXX' => 'Not Applicable or None', + '9ENE' => 'Non-Exclusive', + '9EXC' => 'All Exclusive', + '9EIN' => 'Exclusivity For Industry', + '9EME' => 'Exclusivity For Media', + '9ELA' => 'Exclusivity For Language', + '9ERE' => 'Exclusivity For Region' +); + +# PLUS License Data Format 1.2.0 (plus) (ref 1) +%Image::ExifTool::PLUS::XMP = ( + %Image::ExifTool::XMP::xmpTableDefaults, + GROUPS => { 0 => 'XMP', 1 => 'XMP-plus', 2 => 'Author' }, + NAMESPACE => 'plus', + NOTES => q{ + PLUS (Picture Licensing Universal System) License Data Format 1.2.1 XMP + tags. Note that all controlled-vocabulary tags in this table (ie. tags with + a fixed set of values) have raw values which begin with + "http://ns.useplus.org/ldf/vocab/", but to reduce clutter this prefix has + been removed from the values shown below. See L<http://ns.useplus.org/> for + the complete specification. + }, + Version => { Name => 'PLUSVersion' }, + Licensee => { + FlatName => '', + Struct => \%plusLicensee, + List => 'Seq', + }, + EndUser => { + FlatName => '', + Struct => \%plusEndUser, + List => 'Seq', + }, + Licensor => { + FlatName => '', + Struct => \%plusLicensor, + List => 'Seq', + }, + LicensorNotes => { Writable => 'lang-alt' }, + MediaSummaryCode => { + SeparateTable => 'MediaMatrix', + PrintConv => \%mediaMatrix, + }, + LicenseStartDate => { %Image::ExifTool::XMP::dateTimeInfo, Groups => { 2 => 'Time'} }, + LicenseEndDate => { %Image::ExifTool::XMP::dateTimeInfo, Groups => { 2 => 'Time'} }, + MediaConstraints => { Writable => 'lang-alt' }, + RegionConstraints => { Writable => 'lang-alt' }, + ProductOrServiceConstraints => { Writable => 'lang-alt' }, + ImageFileConstraints => { + List => 'Bag', + %plusVocab, + PrintConv => { + 'IF-MFN' => 'Maintain File Name', + 'IF-MID' => 'Maintain ID in File Name', + 'IF-MMD' => 'Maintain Metadata', + 'IF-MFT' => 'Maintain File Type', + }, + }, + ImageAlterationConstraints => { + List => 'Bag', + %plusVocab, + PrintConv => { + 'AL-CRP' => 'No Cropping', + 'AL-FLP' => 'No Flipping', + 'AL-RET' => 'No Retouching', + 'AL-CLR' => 'No Colorization', + 'AL-DCL' => 'No De-Colorization', + 'AL-MRG' => 'No Merging', + }, + }, + ImageDuplicationConstraints => { + %plusVocab, + PrintConv => { + 'DP-NDC' => 'No Duplication Constraints', + 'DP-LIC' => 'Duplication Only as Necessary Under License', + 'DP-NOD' => 'No Duplication', + }, + }, + ModelReleaseStatus => { + %plusVocab, + PrintConv => { + 'MR-NON' => 'None', + 'MR-NAP' => 'Not Applicable', + 'MR-UMR' => 'Unlimited Model Releases', + 'MR-LMR' => 'Limited or Incomplete Model Releases', + }, + }, + ModelReleaseID => { List => 'Bag' }, + MinorModelAgeDisclosure => { + %plusVocab, + PrintConv => { + 'AG-UNK' => 'Age Unknown', + 'AG-A25' => 'Age 25 or Over', + 'AG-A24' => 'Age 24', + 'AG-A23' => 'Age 23', + 'AG-A22' => 'Age 22', + 'AG-A21' => 'Age 21', + 'AG-A20' => 'Age 20', + 'AG-A19' => 'Age 19', + 'AG-A18' => 'Age 18', + 'AG-A17' => 'Age 17', + 'AG-A16' => 'Age 16', + 'AG-A15' => 'Age 15', + 'AG-U14' => 'Age 14 or Under', + }, + }, + PropertyReleaseStatus => { + %plusVocab, + PrintConv => { + 'PR-NON' => 'None', + 'PR-NAP' => 'Not Applicable', + 'PR-UPR' => 'Unlimited Property Releases', + 'PR-LPR' => 'Limited or Incomplete Property Releases', + }, + }, + PropertyReleaseID => { List => 'Bag' }, + OtherConstraints => { Writable => 'lang-alt' }, + CreditLineRequired => { + %plusVocab, + PrintConv => { + 'CR-NRQ' => 'Not Required', + 'CR-COI' => 'Credit on Image', + 'CR-CAI' => 'Credit Adjacent To Image', + 'CR-CCA' => 'Credit in Credits Area', + }, + }, + AdultContentWarning => { + %plusVocab, + PrintConv => { + 'CW-NRQ' => 'Not Required', + 'CW-AWR' => 'Adult Content Warning Required', + 'CW-UNK' => 'Unknown', + }, + }, + OtherLicenseRequirements => { Writable => 'lang-alt' }, + TermsAndConditionsText => { Writable => 'lang-alt' }, + TermsAndConditionsURL => { }, + OtherConditions => { Writable => 'lang-alt' }, + ImageType => { + %plusVocab, + PrintConv => { + 'TY-PHO' => 'Photographic Image', + 'TY-ILL' => 'Illustrated Image', + 'TY-MCI' => 'Multimedia or Composited Image', + 'TY-VID' => 'Video', + 'TY-OTR' => 'Other', + }, + }, + LicensorImageID => { }, + FileNameAsDelivered => { }, + ImageFileFormatAsDelivered => { + %plusVocab, + PrintConv => { + 'FF-JPG' => 'JPEG Interchange Formats (JPG, JIF, JFIF)', + 'FF-TIF' => 'Tagged Image File Format (TIFF)', + 'FF-GIF' => 'Graphics Interchange Format (GIF)', + 'FF-RAW' => 'Proprietary RAW Image Format', + 'FF-DNG' => 'Digital Negative (DNG)', + 'FF-EPS' => 'Encapsulated PostScript (EPS)', + 'FF-BMP' => 'Windows Bitmap (BMP)', + 'FF-PSD' => 'Photoshop Document (PSD)', + 'FF-PIC' => 'Macintosh Picture (PICT)', + 'FF-PNG' => 'Portable Network Graphics (PNG)', + 'FF-WMP' => 'Windows Media Photo (HD Photo)', + 'FF-OTR' => 'Other', + }, + }, + ImageFileSizeAsDelivered => { + %plusVocab, + PrintConv => { + 'SZ-U01' => 'Up to 1 MB', + 'SZ-U10' => 'Up to 10 MB', + 'SZ-U30' => 'Up to 30 MB', + 'SZ-U50' => 'Up to 50 MB', + 'SZ-G50' => 'Greater than 50 MB', + }, + }, + CopyrightStatus => { + %plusVocab, + PrintConv => { + 'CS-PRO' => 'Protected', + 'CS-PUB' => 'Public Domain', + 'CS-UNK' => 'Unknown', + }, + }, + CopyrightRegistrationNumber => { }, + FirstPublicationDate => { %Image::ExifTool::XMP::dateTimeInfo, Groups => { 2 => 'Time'} }, + CopyrightOwner => { + FlatName => '', + Struct => \%plusCopyrightOwner, + List => 'Seq', + }, + CopyrightOwnerImageID => { }, + ImageCreator => { + FlatName => '', + Struct => \%plusImageCreator, + List => 'Seq', + }, + ImageCreatorImageID => { }, + ImageSupplier => { + FlatName => '', + Struct => \%plusImageSupplier, + List => 'Seq', + }, + ImageSupplierImageID => { }, + LicenseeImageID => { }, + LicenseeImageNotes => { Writable => 'lang-alt' }, + OtherImageInfo => { Writable => 'lang-alt' }, + LicenseID => { }, + LicensorTransactionID => { List => 'Bag' }, + LicenseeTransactionID => { List => 'Bag' }, + LicenseeProjectReference=> { List => 'Bag' }, + LicenseTransactionDate => { %Image::ExifTool::XMP::dateTimeInfo, Groups => { 2 => 'Time'} }, + Reuse => { + %plusVocab, + PrintConv => { + 'RE-REU' => 'Repeat Use', + 'RE-NAP' => 'Not Applicable', + }, + }, + OtherLicenseDocuments => { List => 'Bag' }, + OtherLicenseInfo => { Writable => 'lang-alt' }, + # Note: these are Bag's of lang-alt lists -- a nested list tag! + Custom1 => { List => 'Bag', Writable => 'lang-alt' }, + Custom2 => { List => 'Bag', Writable => 'lang-alt' }, + Custom3 => { List => 'Bag', Writable => 'lang-alt' }, + Custom4 => { List => 'Bag', Writable => 'lang-alt' }, + Custom5 => { List => 'Bag', Writable => 'lang-alt' }, + Custom6 => { List => 'Bag', Writable => 'lang-alt' }, + Custom7 => { List => 'Bag', Writable => 'lang-alt' }, + Custom8 => { List => 'Bag', Writable => 'lang-alt' }, + Custom9 => { List => 'Bag', Writable => 'lang-alt' }, + Custom10 => { List => 'Bag', Writable => 'lang-alt' }, +); + +#------------------------------------------------------------------------------ +# Validate Media Summary Code +# Inputs: 0) Media Usage Code +# Returns: true if OK, false on severe error +# - issues warning for detected format problems +# - repairs some repairable problems +sub ValidateMediaSummary($) +{ + my $val = shift; + + my @a = split /\|/, $val; + @a >= 4 and $a[0] eq '' or warn("Not a valid Media Summary Code\n"), return 0; + $a[1] eq 'PLUS' or warn("Unrecognized Media Usage standard\n"), return 0; + $a[2] =~ /^V(\d+)/ or warn("Unrecognized Media Usage version\n"); + $a[3] =~ /^U(\d+)/ or warn("Invalid Media Usage count\n"), return 0; + my $numUsages = $1; + my ($i, $j); + unless ($numUsages == @a - 4) { + warn("Fixed incorrect number of Media Usages\n"); + $numUsages = @a - 4; + $a[3] = sprintf('U%.3d', $numUsages); + } + for ($i=1; $i<=$numUsages; ++$i) { + my $usage = $a[$i + 3]; + $usage =~ /^1I([A-Z])([A-Z])/ or warn("Missing Media Usage $i item count\n"), return 0; + length($usage) % 4 and warn("Incorrect Media Usage $i length\n"), return 0; + my $numItems = (ord($1)-65) * 26 + ord($2)-65 + 1; + unless (length($usage) == 4 * ($numItems + 1)) { + $numItems = length($usage) / 4 - 1; + warn("Fixed incorrect Media Usage $i item count\n"); + $a[$i+3] = '1I' . chr(65 + int($numItems / 26)) . chr($numItems % 26) . substr($usage, 4); + } + for ($j=1; $j<=$numItems; ++$j) { + my $item = substr($usage, $j*4, 4); + $item =~ /^\d[A-Z]{3}$/ or warn(qq(Invalid item "$item" for Media Usage $i\n)), return 0; + } + } + $_[0] = join('|', @a) . '|' if $Image::ExifTool::evalWarning; + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::PLUS - PLUS (Picture Licensing Universal System) tags + +=head1 DESCRIPTION + +Definitions for PLUS (Picture Licensing Universal System) tags. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<http://www.useplus.com/useplus/standards.asp> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/PLUS Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PNG.pm b/src/Image-ExifTool/lib/Image/ExifTool/PNG.pm index c25962ce..6bcaeee7 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/PNG.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/PNG.pm @@ -19,6 +19,15 @@ # decompress then decode the ASCII/hex profile information before # you can edit it, then you have to ASCII/hex-encode, recompress # and calculate a CRC before you can write it out again. gaaaak. +# +# Although XMP is allowed after the IDAT chunk according to the +# PNG specifiction, some apps (Apple Spotlight and Preview for +# OS X 10.8.5 and Adobe Photoshop CC 14.0) ignore it unless it +# comes before IDAT. As of version 11.58, ExifTool uses a 2-pass +# writing algorithm to allow it to be compatible with XMP after +# IDAT while writing it before IDAT. (PNG and EXIF are still +# written after IDAT.) As of version 11.63, this strategy is +# applied to all text chunks (tEXt, zTXt and iTXt). #------------------------------------------------------------------------------ package Image::ExifTool::PNG; @@ -27,7 +36,7 @@ use strict; use vars qw($VERSION $AUTOLOAD %stdCase); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.46'; +$VERSION = '1.60'; sub ProcessPNG_tEXt($$$); sub ProcessPNG_iTXt($$$); @@ -78,6 +87,14 @@ my %pngMap = ( # color type of current image $Image::ExifTool::PNG::colorType = -1; +# data and text chunk types +my %isDatChunk = ( IDAT => 1, JDAT => 1, JDAA => 1 ); +my %isTxtChunk = ( tEXt => 1, zTXt => 1, iTXt => 1, eXIf => 1 ); + +# chunks that we shouldn't move other chunks across (ref 3) +my %noLeapFrog = ( SAVE => 1, SEEK => 1, IHDR => 1, JHDR => 1, IEND => 1, MEND => 1, + DHDR => 1, BASI => 1, CLON => 1, PAST => 1, SHOW => 1, MAGN => 1 ); + # PNG chunks %Image::ExifTool::PNG::Main = ( WRITE_PROC => \&Image::ExifTool::DummyWriteProc, @@ -93,6 +110,19 @@ $Image::ExifTool::PNG::colorType = -1; it is specifically deleted with C<-Trailer:All=>. When reading, a minor warning is issued if this trailer exists, and ExifTool will attempt to parse this data as additional PNG chunks. + + Also according to the PNG specification, there is no restriction on the + location of text-type chunks (tEXt, zTXt and iTXt). However, certain + utilities (including some Apple and Adobe utilities) won't read the XMP iTXt + chunk if it comes after the IDAT chunk, and at least one utility won't read + other text chunks here. For this reason, when writing, ExifTool 11.63 and + later create new text chunks (including XMP) before IDAT, and move existing + text chunks to before IDAT. + + The PNG format contains CRC checksums that are validated when reading with + either the L<Verbose|../ExifTool.html#Verbose> or L<Validate|../ExifTool.html#Validate> option. When writing, these checksums are + validated by default, but the L<FastScan|../ExifTool.html#FastScan> option may be used to bypass this + check if speed is more of a concern. }, bKGD => { Name => 'BackgroundColor', @@ -112,11 +142,14 @@ $Image::ExifTool::PNG::colorType = -1; }, gAMA => { Name => 'Gamma', + Writable => 1, + Protected => 1, Notes => q{ ExifTool reports the gamma for decoding the image, which is consistent with the EXIF convention, but is the inverse of the stored encoding gamma }, ValueConv => 'my $a=unpack("N",$val);$a ? int(1e9/$a+0.5)/1e4 : $val', + ValueConvInv => 'pack("N", int(1e5/$val+0.5))', }, gIFg => { Name => 'GIFGraphicControlExtension', @@ -136,7 +169,10 @@ $Image::ExifTool::PNG::colorType = -1; }, iCCP => { Name => 'ICC_Profile', - Notes => 'this is where ExifTool will write a new ICC_Profile', + Notes => q{ + this is where ExifTool will write a new ICC_Profile. When creating a new + ICC_Profile, the SRGBRendering tag should be deleted if it exists + }, SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main', ProcessProc => \&ProcessPNG_Compressed, @@ -144,7 +180,12 @@ $Image::ExifTool::PNG::colorType = -1; }, 'iCCP-name' => { Name => 'ProfileName', - Notes => 'not a real tag ID, this tag represents the iCCP profile name', + Writable => 1, + FakeTag => 1, # (not a real PNG tag, so don't try to write it) + Notes => q{ + not a real tag ID, this tag represents the iCCP profile name, and may only + be written when the ICC_Profile is written + }, }, # IDAT # IEND @@ -197,7 +238,11 @@ $Image::ExifTool::PNG::colorType = -1; }, sRGB => { Name => 'SRGBRendering', + Writable => 1, + Protected => 1, + Notes => 'this chunk should not be present if an iCCP chunk exists', ValueConv => 'unpack("C",$val)', + ValueConvInv => 'pack("C",$val)', PrintConv => { 0 => 'Perceptual', 1 => 'Relative Colorimetric', @@ -229,6 +274,7 @@ $Image::ExifTool::PNG::colorType = -1; }, tRNS => { Name => 'Transparency', + # may have as many entries as the PLTE table, but who wants to see all that? ValueConv => q{ return \$val if length($val) > 6; join(" ",unpack($Image::ExifTool::PNG::colorType == 3 ? "C*" : "n*", $val)); @@ -281,6 +327,18 @@ $Image::ExifTool::PNG::colorType = -1; }, # fcTL - animation frame control for each frame # fdAT - animation data for each frame + iDOT => { # (ref NealKrawetz) + Name => 'AppleDataOffsets', + Binary => 1, + # Apple offsets into data relative to start of iDOT chunk: + # int32u Divisor [only ever seen 2] + # int32u Unknown [always 0] + # int32u TotalDividedHeight [image height from IDHR/Divisor] + # int32u Size [always 40 / 0x28; size of this chunk] + # int32u DividedHeight1 + # int32u DividedHeight2 + # int32u IDAT_Offset2 [location of IDAT with start of DividedHeight2 segment] + }, ); # PNG IHDR chunk @@ -351,14 +409,17 @@ $Image::ExifTool::PNG::colorType = -1; 0 => { Name => 'PixelsPerUnitX', Format => 'int32u', + Notes => 'default 2834', }, 4 => { Name => 'PixelsPerUnitY', Format => 'int32u', + Notes => 'default 2834', }, 8 => { Name => 'PixelUnits', PrintConv => { 0 => 'Unknown', 1 => 'meters' }, + Notes => 'default meters', }, ); @@ -427,12 +488,14 @@ my %unreg = ( Notes => 'unregistered' ); These tags may be stored as tEXt, zTXt or iTXt chunks in the PNG image. By default ExifTool writes new string-value tags as as uncompressed tEXt, or - compressed zTXt if the Compress (-z) option is used and Compress::Zlib is + compressed zTXt if the L<Compress|../ExifTool.html#Compress> (-z) option is used and Compress::Zlib is available. Alternate language tags and values containing special characters (unless the Latin character set is used) are written as iTXt, and compressed - if the Compress option is used and Compress::Zlib is available. Raw profile + if the L<Compress|../ExifTool.html#Compress> option is used and Compress::Zlib is available. Raw profile information is always created as compressed zTXt if Compress::Zlib is available, or tEXt otherwise. Standard XMP is written as uncompressed iTXt. + User-defined tags may set an 'iTXt' flag in the tag definition to be written + only as iTXt. Alternate languages are accessed by suffixing the tag name with a '-', followed by an RFC 3066 language code (eg. "PNG:Comment-fr", or @@ -502,9 +565,7 @@ my %unreg = ( Notes => 'unregistered' ); XMP specification, and is where ExifTool will add a new XMP chunk if the image didn't already contain XMP }, - SubDirectory => { - TagTable => 'Image::ExifTool::XMP::Main', - }, + SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' }, }, 'Raw profile type APP1' => [ { @@ -588,7 +649,7 @@ my %unreg = ( Notes => 'unregistered' ); GROUPS => { 2 => 'Image' }, FORMAT => 'int32u', NOTES => q{ - Tags found in the Animation Conrol chunk. See + Tags found in the Animation Control chunk. See L<https://wiki.mozilla.org/APNG_Specification> for details. }, 0 => { @@ -792,7 +853,7 @@ sub FoundPNG($$$$;$$$$) my $processed; if ($$tagInfo{SubDirectory}) { if ($$et{OPTIONS}{Validate} and $$tagInfo{NonStandard}) { - $et->Warn("Non-standard $$tagInfo{NonStandard} in PNG $tag chunk", 1); + $et->WarnOnce("Non-standard $$tagInfo{NonStandard} in PNG $tag chunk", 1); } my $subdir = $$tagInfo{SubDirectory}; my $dirName = $$subdir{DirName} || $tagName; @@ -830,23 +891,11 @@ sub FoundPNG($$$$;$$$$) return 1 unless $$et{EDIT_DIRS}{$dirName}; $$outBuff = $et->WriteDirectory(\%subdirInfo, $subTable); if ($tagName eq 'XMP' and $$outBuff) { - if ($$et{FoundIDAT} and $$et{DEL_GROUP}{XMP}) { - $et->VPrint(0,' Deleting XMP'); - $$outBuff = ''; - } else { - # make sure the XMP is marked as read-only - Image::ExifTool::XMP::ValidateXMP($outBuff,'r'); - } + # make sure the XMP is marked as read-only + Image::ExifTool::XMP::ValidateXMP($outBuff,'r'); } DoneDir($et, $dirName, $outBuff, $$tagInfo{NonStandard}); } else { - # issue warning for standard XMP after IDAT (PNGEarlyXMP option) - if ($tagName eq 'XMP' and not $$tagInfo{NonStandard} and - $$et{FoundIDAT} and $$et{FoundIDAT} == 2) - { - $et->Warn('XMP found after PNG IDAT'); - $$et{FoundIDAT} = 1; - } $processed = $et->ProcessDirectory(\%subdirInfo, $subTable, $processProc); } $compressed = 1; # pretend this is compressed since it is binary data @@ -872,9 +921,7 @@ sub FoundPNG($$$$;$$$$) { # write new value for this tag if necessary my $newVal; - if ($$et{DEL_GROUP}{PNG} or $$et{PNGDoneTag}{$tag} or - $$et{PNGDoneTag}{ucfirst $tag}) - { + if ($$et{DEL_GROUP}{PNG}){ # remove this tag now, but keep in ADD_PNG list to add back later $isOverwriting = 1; } else { @@ -946,7 +993,7 @@ sub FoundPNG($$$$;$$$$) $$tagInfo{LangCode} = $lang if $lang; # make unknown profiles binary data type $$tagInfo{Binary} = 1 if $tag =~ /^Raw profile type /; - $verbose and $et->VPrint(0, " | [adding $tag]\n"); + $verbose and $et->VPrint(0, " [adding $tag]\n"); AddTagToTable($tagTablePtr, $tag, $tagInfo); } # @@ -1055,7 +1102,7 @@ sub ProcessProfile($$$) $$outBuff = $et->WriteDirectory(\%dirInfo, $tagTablePtr, \&Image::ExifTool::WriteTIFF); $$outBuff = $Image::ExifTool::exifAPP1hdr . $$outBuff if $$outBuff; - DoneDir($et, 'IFD0', $outBuff); + DoneDir($et, 'IFD0', $outBuff, $$tagInfo{NonStandard}); } else { $processed = $et->ProcessTIFF(\%dirInfo); } @@ -1069,7 +1116,7 @@ sub ProcessProfile($$$) return 1 unless $$editDirs{XMP}; $$outBuff = $et->WriteDirectory(\%dirInfo, $tagTablePtr); $$outBuff and $$outBuff = $Image::ExifTool::xmpAPP1hdr . $$outBuff; - DoneDir($et, 'XMP', $outBuff, 1); + DoneDir($et, 'XMP', $outBuff, $$tagInfo{NonStandard}); } else { $processed = $et->ProcessDirectory(\%dirInfo, $tagTablePtr); } @@ -1085,7 +1132,7 @@ sub ProcessProfile($$$) } $$outBuff = $et->WriteDirectory(\%dirInfo, $tagTablePtr, \&Image::ExifTool::WriteTIFF); - DoneDir($et, 'IFD0', $outBuff); + DoneDir($et, 'IFD0', $outBuff, $$tagInfo{NonStandard}); } else { $processed = $et->ProcessTIFF(\%dirInfo); } @@ -1127,11 +1174,16 @@ sub ProcessPNG_Compressed($$$) if ($tagInfo and $$tagInfo{Name} eq 'ICC_Profile') { $et->VerboseDir('iCCP'); $tagTablePtr = \%Image::ExifTool::PNG::Main; - if (length($tag) and not $outBuff) { - FoundPNG($et, $tagTablePtr, 'iCCP-name', $tag); - } + FoundPNG($et, $tagTablePtr, 'iCCP-name', $tag) if length($tag) and not $outBuff; $success = FoundPNG($et, $tagTablePtr, 'iCCP', $val, $compressed, $outBuff); - $$outBuff = $hdr . $$outBuff if $outBuff and $$outBuff; + if ($outBuff and $$outBuff) { + my $profileName = $et->GetNewValue($Image::ExifTool::PNG::Main{'iCCP-name'}); + if (defined $profileName) { + $hdr = $profileName . substr($hdr, length $tag); + $et->VerboseValue("+ PNG:ProfileName", $profileName); + } + $$outBuff = $hdr . $$outBuff; + } } else { $success = FoundPNG($et, $tagTablePtr, $tag, $val, $compressed, $outBuff, 'Latin'); } @@ -1148,6 +1200,7 @@ sub ProcessPNG_tEXt($$$) my ($et, $dirInfo, $tagTablePtr) = @_; my ($tag, $val) = split /\0/, ${$$dirInfo{DataPt}}, 2; my $outBuff = $$dirInfo{OutBuff}; + $$et{INDENT} = substr($$et{INDENT}, 0, -2) if $$et{OPTIONS}{Verbose}; return FoundPNG($et, $tagTablePtr, $tag, $val, undef, $outBuff, 'Latin'); } @@ -1166,6 +1219,7 @@ sub ProcessPNG_iTXt($$$) # set compressed flag so we will decompress it in FoundPNG() $compressed and $compressed = 2 + $meth; my $outBuff = $$dirInfo{OutBuff}; + $$et{INDENT} = substr($$et{INDENT}, 0, -2) if $$et{OPTIONS}{Verbose}; return FoundPNG($et, $tagTablePtr, $tag, $val, $compressed, $outBuff, 'UTF8', $lang); } @@ -1234,14 +1288,13 @@ sub ProcessPNG($$) my $datChunk = ''; my $datCount = 0; my $datBytes = 0; - my ($sig, $err); + my $fastScan = $et->Options('FastScan'); + my ($n, $sig, $err, $hbuf, $dbuf, $cbuf); + my ($wasHdr, $wasEnd, $wasDat, $doTxt, @txtOffset); # check to be sure this is a valid PNG/MNG/JNG image return 0 unless $raf->Read($sig,8) == 8 and $pngLookup{$sig}; - $$raf{NoBuffer} = 1 if $et->Options('FastScan'); # disable buffering in FastScan mode - - my $earlyXMP = $et->Options('PNGEarlyXMP'); if ($outfile) { delete $$et{TextChunkType}; Write($outfile, $sig) or $err = 1 if $outfile; @@ -1249,16 +1302,11 @@ sub ProcessPNG($$) $$et{ADD_PNG} = $et->GetNewTagInfoHash( \%Image::ExifTool::PNG::Main, \%Image::ExifTool::PNG::TextualData); - # NOTE: PNGDoneTag and PNGDoneDir are used to keep track of metadata added - # before the PNG IEND chunk is encountered. Currently this is implemented - # only for XMP (written before IDAT with the PNGEarlyXMP option), but - # may be implemented in the future for other types - PH - $$et{PNGDoneTag} = { }; - $$et{PNGDoneDir} = { }; # initialize with same directories, with PNG tags taking priority $et->InitWriteDirs(\%pngMap,'PNG'); - # write XMP before IDAT if we would delete it later anyway - $earlyXMP = 1 if $$et{DEL_GROUP}{XMP}; + } else { + # disable buffering in FastScan mode + $$raf{NoBuffer} = 1 if $fastScan; } my ($fileType, $hdrChunk, $endChunk) = @{$pngLookup{$sig}}; $et->SetFileType($fileType); # set the FileType tag @@ -1269,13 +1317,37 @@ sub ProcessPNG($$) $mngTablePtr = GetTagTable('Image::ExifTool::MNG::Main'); } my $verbose = $et->Options('Verbose'); + my $validate = $et->Options('Validate'); my $out = $et->Options('TextOut'); - my ($hbuf, $dbuf, $cbuf, $wasHdr, $wasEnd); + + # scan ahead to find offsets of all text chunks after IDAT + if ($outfile) { + while ($raf->Read($hbuf,8) == 8) { + my ($len, $chunk) = unpack('Na4',$hbuf); + last if $len > 0x7fffffff; + if ($wasDat) { + last if $noLeapFrog{$chunk}; # (don't move text across these chunks) + push @txtOffset, $raf->Tell() - 8 if $isTxtChunk{$chunk}; + } elsif ($isDatChunk{$chunk}) { + $wasDat = $chunk; + } + $raf->Seek($len + 4, 1) or last; # skip chunk data + } + $raf->Seek(8,0) or $et->Error('Error seeking in file'), return -1; + undef $wasDat; + } # process the PNG/MNG/JNG chunks undef $noCompressLib; for (;;) { - my $n = $raf->Read($hbuf,8); + if ($doTxt) { + # read text chunks that were found after IDAT so we can write them before + $raf->Seek(shift(@txtOffset), 0) or $et->Error('Seek error'), last; + # (this is the IDAT offset if @txtOffset is now empty) + undef $doTxt unless @txtOffset; + } + $n = $raf->Read($hbuf,8); # read chunk header + if ($wasEnd) { last unless $n; # stop now if normal end of PNG $et->WarnOnce("Trailer data after $fileType $endChunk chunk", 1); @@ -1291,31 +1363,52 @@ sub ProcessPNG($$) last; } if ($verbose) { + print $out " Moving $chunk from after IDAT ($len bytes)\n" if $doTxt; # don't dump image data chunks in verbose mode (only give count instead) if ($datCount and $chunk ne $datChunk) { my $s = $datCount > 1 ? 's' : ''; print $out "$fileType $datChunk ($datCount chunk$s, total $datBytes bytes)\n"; $datCount = $datBytes = 0; - $datChunk = ''; } - if ($chunk =~ /^(IDAT|JDAT|JDAA)$/) { - $datChunk = $chunk; - $datCount++; - $datBytes += $len; + } + unless ($wasHdr) { + if ($chunk eq $hdrChunk) { + $wasHdr = 1; + } elsif ($hdrChunk eq 'IHDR' and $chunk eq 'CgBI') { + $et->Warn('Non-standard PNG image (Apple iPhone format)'); + } else { + $et->WarnOnce("$fileType image did not start with $hdrChunk"); } } + if ($outfile and ($isDatChunk{$chunk} or $chunk eq $endChunk) and @txtOffset) { + # continue processing here after we move the text chunks from after IDAT + push @txtOffset, $raf->Tell() - 8; + $doTxt = 1; # process text chunks now + next; + } + if ($isDatChunk{$chunk}) { + if ($fastScan and $fastScan >= 2) { + $et->VPrint(0,"End processing at $chunk chunk due to FastScan=$fastScan setting"); + last; + } + $datChunk = $chunk; + $datCount++; + $datBytes += $len; + $wasDat = $chunk; + } else { + $datChunk = ''; + } if ($outfile) { - if ($chunk eq $endChunk) { - # add any new chunks immediately before the IEND/MEND chunk - AddChunks($et, $outfile) or $err = 1; - } elsif ($chunk eq 'PLTE' or $chunk eq 'IDAT') { - if ($chunk eq 'IDAT') { - # add XMP before IDAT if specified - AddChunks($et, $outfile, 'XMP') or $err = 1 if $earlyXMP; - # pHYs comes before IDAT - AddChunks($et, $outfile, 'PNG-pHYs') or $err = 1; - } - # iCCP chunk must come before PLTE and IDAT + # add text chunks (including XMP) before any data chunk end chunk + if ($datChunk or $chunk eq $endChunk) { + # write iCCP chunk now if requested because AddChunks will try + # to add it as a text profile chunk if this isn't successful + # (ie. if Compress::Zlib wasn't available) + Add_iCCP($et, $outfile); + AddChunks($et, $outfile) or $err = 1; # add all text chunks + AddChunks($et, $outfile, 'IFD0') or $err = 1; # and eXIf chunk + } elsif ($chunk eq 'PLTE') { + # iCCP chunk must come before PLTE (and IDAT, handled above) # (ignore errors -- will add later as text profile if this fails) Add_iCCP($et, $outfile); } @@ -1350,47 +1443,73 @@ sub ProcessPNG($$) } next; } - # set FoundIDAT flag: 1=after IDAT, 2=after IDAT and warn about late XMP - $$et{FoundIDAT} = $earlyXMP ? 2 : 1 if $chunk eq 'IDAT'; + if ($datChunk) { + my $chunkSizeLimit = 10000000; # largest chunk to read into memory + if ($outfile) { + # avoid loading very large data chunks into memory + if ($len > $chunkSizeLimit) { + Write($outfile, $hbuf) or $err = 1; + Image::ExifTool::CopyBlock($raf, $outfile, $len+4) or $et->Error("Error copying $datChunk"); + next; + } + # skip over data chunks if possible/necessary + } elsif (not $validate or $len > $chunkSizeLimit) { + $raf->Seek($len + 4, 1) or $et->Warn('Seek error'), last; + next; + } + } elsif ($wasDat and $isTxtChunk{$chunk}) { + my $msg; + if (not $outfile) { + $msg = 'may be ignored by some readers'; + } elsif (defined $doTxt) { # $doTxt == 0 if we crossed a noLeapFrog chunk + $msg = "can't be moved"; # (but could be deleted then added back again) + } else { + $msg = 'fixed'; + } + $et->WarnOnce("Text/EXIF chunk(s) found after $$et{FileType} $wasDat ($msg)", 1); + } # read chunk data and CRC unless ($raf->Read($dbuf,$len)==$len and $raf->Read($cbuf, 4)==4) { $et->Warn("Corrupted $fileType image") unless $wasEnd; last; } - unless ($wasHdr) { - if ($chunk eq $hdrChunk) { - $wasHdr = 1; - } elsif ($hdrChunk eq 'IHDR' and $chunk eq 'CgBI') { - $et->Warn('Non-standard PNG image (Apple iPhone format)'); - } else { - $et->Warn("$fileType image did not start with $hdrChunk"); - last; - } - } - if ($verbose) { + if ($verbose or $validate or ($outfile and not $fastScan)) { # check CRC when in verbose mode (since we don't care about speed) my $crc = CalculateCRC(\$hbuf, undef, 4); $crc = CalculateCRC(\$dbuf, $crc); - $crc == unpack('N',$cbuf) or $et->Warn("Bad CRC for $chunk chunk") unless $wasEnd; + unless ($crc == unpack('N',$cbuf)) { + my $msg = "Bad CRC for $chunk chunk"; + $outfile ? $et->Error($msg, 1) : $et->Warn($msg); + } if ($datChunk) { Write($outfile, $hbuf, $dbuf, $cbuf) or $err = 1 if $outfile; next; } - print $out "$fileType $chunk ($len bytes):\n"; - $et->VerboseDump(\$dbuf, Addr => $raf->Tell() - $len - 4) if $verbose > 2; + # just skip over any text chunk found after IDAT + if ($outfile and $wasDat) { + if ($isTxtChunk{$chunk} and not defined $doTxt) { + ++$$et{CHANGED} if $$et{FORCE_WRITE}{PNG}; + print $out " Deleting $chunk that was moved ($len bytes)\n" if $verbose; + next; + } + # done moving text if we hit one of these chunks + $doTxt = 0 if $noLeapFrog{$chunk}; + } + if ($verbose) { + print $out "$fileType $chunk ($len bytes):\n"; + $et->VerboseDump(\$dbuf, Addr => $raf->Tell() - $len - 4) if $verbose > 2; + } } - # translate case of chunk name if necessary - if (not $$tagTablePtr{$chunk}) { + # translate case of chunk names that have changed since the first implementation + if (not $$tagTablePtr{$chunk} and $stdCase{lc $chunk}) { my $stdChunk = $stdCase{lc $chunk}; - if ($stdChunk) { - if ($outfile and ($$et{EDIT_DIRS}{IFD0} or $stdChunk !~ /^[ez]xif$/i)) { - $et->Warn("Changed $chunk chunk to $stdChunk", 1); - ++$$et{CHANGED}; - } else { - $et->Warn("$chunk chunk should be $stdChunk", 1); - } - $chunk = $stdCase{lc $chunk}; + if ($outfile and ($$et{EDIT_DIRS}{IFD0} or $stdChunk !~ /^[ez]xif$/i)) { + $et->Warn("Changed $chunk chunk to $stdChunk", 1); + ++$$et{CHANGED}; + } else { + $et->Warn("$chunk chunk should be $stdChunk", 1); } + $chunk = $stdCase{lc $chunk}; } # only extract information from chunks in our tables my ($theBuff, $outBuff); @@ -1442,7 +1561,7 @@ and JNG (JPEG Network Graphics) images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PPM.pm b/src/Image-ExifTool/lib/Image/ExifTool/PPM.pm index 5ae32d11..ae7d2906 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/PPM.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/PPM.pm @@ -16,7 +16,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.09'; +$VERSION = '1.10'; #------------------------------------------------------------------------------ # Read or write information in a PPM/PGM/PBM image @@ -48,19 +48,19 @@ sub ProcessPPM($$) # note: may contain comments starting with '#' if ($buff =~ /\G#/gc) { # must read more if we are in the middle of a comment - next unless $buff =~ /\G ?(.*\n(#.*\n)*)\s*/g; + next unless $buff =~ /\G ?(.*[\n\r]+(#.*[\n\r]+)*)\s*/g; $info{Comment} = $1; next if $buff =~ /\G#/gc; } else { delete $info{Comment}; } - next unless $buff =~ /\G(\S+)\s+(\S+)\s/g; + next unless $buff =~ /\G(\S+)\s+(\S+)\s+/g; $info{ImageWidth} = $1; $info{ImageHeight} = $2; $type = [qw{PPM PBM PGM}]->[$num % 3]; last if $type eq 'PBM'; # (no MaxVal for PBM images) if ($buff =~ /\G\s*#/gc) { - next unless $buff =~ /\G ?(.*\n(#.*\n)*)\s*/g; + next unless $buff =~ /\G ?(.*[\n\r]+(#.*[\n\r]+)*)\s*/g; $info{Comment} = '' unless exists $info{Comment}; $info{Comment} .= $1; next if $buff =~ /\G#/gc; @@ -76,7 +76,7 @@ sub ProcessPPM($$) } if (defined $info{Comment}) { $info{Comment} =~ s/^# ?//mg; # remove "# " at the start of each line - $info{Comment} =~ s/\n$//; # remove trailing newline + $info{Comment} =~ s/[\n\r]+$//; # remove trailing newline } $et->SetFileType($type); my $len = pos($buff); @@ -143,7 +143,7 @@ BitMap) images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PSP.pm b/src/Image-ExifTool/lib/Image/ExifTool/PSP.pm index b139a9b3..2083fde7 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/PSP.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/PSP.pm @@ -284,7 +284,7 @@ information from Paint Shop Pro images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Palm.pm b/src/Image-ExifTool/lib/Image/ExifTool/Palm.pm index 97026e88..9f8b1dd8 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Palm.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Palm.pm @@ -379,7 +379,7 @@ KF7 and KF8 books (AZW and AZW3). =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Panasonic.pm b/src/Image-ExifTool/lib/Image/ExifTool/Panasonic.pm index 125b840f..b992f379 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Panasonic.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Panasonic.pm @@ -20,11 +20,13 @@ # 14) Carl Bretteville private communication (M9) # 15) Zdenek Mihula private communication (TZ8) # 16) Olaf Ulrich private communication -# 17) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,4922.0.html +# 17) https://exiftool.org/forum/index.php/topic,4922.0.html # 18) Thomas Modes private communication (G6) -# 19) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,5533.0.html +# 19) https://exiftool.org/forum/index.php/topic,5533.0.html # 20) Bernd-Michael Kemper private communication (DMC-GX80/85) # 21) Klaus Homeister forum post +# 22) Daniel Beichl private communication (G9) +# 23) Tim Gray private communication (M10 Monochrom) # JD) Jens Duttke private communication (TZ3,FZ30,FZ50) #------------------------------------------------------------------------------ @@ -35,7 +37,7 @@ use vars qw($VERSION %leicaLensTypes); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; -$VERSION = '2.03'; +$VERSION = '2.17'; sub ProcessLeicaLEIC($$$); sub WhiteBalanceConv($;$$); @@ -107,7 +109,8 @@ sub WhiteBalanceConv($;$$); 39 => 'Macro-Elmar-M 90mm f/4', # 11633/11634 '39 0' => 'Tele-Elmar-M 135mm f/4 (II)',# 11861 40 => 'Macro-Adapter M', # 14409 - '41 3' => 'Apo-Summicron-M 50mm f/2 Asph', #16 + 41 => 'Apo-Summicron-M 50mm f/2 ASPH.', #IB + '41 3' => 'Apo-Summicron-M 50mm f/2 ASPH.', #16 42 => 'Tri-Elmar-M 28-35-50mm f/4 ASPH.',# 11625 '42 1' => 'Tri-Elmar-M 28-35-50mm f/4 ASPH. (at 28mm)', '42 2' => 'Tri-Elmar-M 28-35-50mm f/4 ASPH. (at 35mm)', @@ -122,8 +125,9 @@ sub WhiteBalanceConv($;$$); 50 => 'Elmar-M 24mm f/3.8 ASPH.', # ? (ref 11) 51 => 'Super-Elmar-M 21mm f/3.4 Asph', # ? (ref 16, frameSelectorBits=1) '51 2' => 'Super-Elmar-M 14mm f/3.8 Asph', # ? (ref 16) - 52 => 'Super-Elmar-M 18mm f/3.8 ASPH.', # ? (ref PH/11) - '53 2' => 'Apo-Telyt-M 135mm f/3.4', #16 + 52 => 'Apo-Telyt-M 18mm f/3.8 ASPH.', # ? (ref PH/11) + 53 => 'Apo-Telyt-M 135mm f/3.4', #IB + '53 2' => 'Apo-Telyt-M 135mm f/3.4', #16 '53 3' => 'Apo-Summicron-M 50mm f/2 (VI)', #LR 58 => 'Noctilux-M 75mm f/1.25 ASPH.', # ? (ref IB) ); @@ -250,11 +254,12 @@ my %shootingMode = ( 83 => 'Clear Night Portrait', #18 84 => 'Soft Image of a Flower', #18 85 => 'Appetizing Food', #18 - 86 => 'Cute Desert', #18 + 86 => 'Cute Dessert', #18 87 => 'Freeze Animal Motion', #18 88 => 'Clear Sports Shot', #18 89 => 'Monochrome', #18 90 => 'Creative Control', #18 + 92 => 'Handheld Night Shot', #forum11523 ); %Image::ExifTool::Panasonic::Main = ( @@ -312,6 +317,7 @@ my %shootingMode = ( 14 => 'Manual 3', #forum9296 15 => 'Manual 4', #forum9296 # also seen 18,26 (forum9296) + 19 => 'Auto (cool)', #PH (Leica C-Lux) }, }, 0x07 => { @@ -348,6 +354,7 @@ my %shootingMode = ( '0 16' => '3-area (high speed)', # (FZ8) '0 23' => '23-area', #PH (FZ47,NC) '0 49' => '49-area', #20 + '0 225' => '225-area', #22 '1 0' => 'Spot Focusing', # (FZ8) '1 1' => '5-area', # (FZ8) '16' => 'Normal?', # (only mode for DMC-LC20) @@ -360,7 +367,10 @@ my %shootingMode = ( '32 2' => '3-area (center)?', # (DMC-L1 guess) '32 3' => '3-area (right)?', # (DMC-L1 guess) '64 0' => 'Face Detect', - '128 0' => 'Spot Focusing 2', #18 + '64 1' => 'Face Detect (animal detect on)', #forum11194 + '64 2' => 'Face Detect (animal detect off)', #forum11194 + '128 0' => 'Pinpoint focus', #18/forum11194 + '240 0' => 'Tracking', #22 }, }, ], @@ -368,14 +378,17 @@ my %shootingMode = ( Name => 'ImageStabilization', Writable => 'int16u', PrintConv => { - 2 => 'On, Mode 1', + 2 => 'On, Optical', 3 => 'Off', 4 => 'On, Mode 2', - 5 => 'Panning', #18 + 5 => 'On, Optical Panning', #18 # GF1 also has a "Mode 3" - PH - 6 => 'On, Mode 3', #PH (GX7, sensor shift?) + 6 => 'On, Body-only', #PH (GX7, sensor shift?) + 7 => 'On, Body-only Panning', #forum11194 9 => 'Dual IS', #20 + 10 => 'Dual IS Panning', #forum11194 11 => 'Dual2 IS', #forum9298 + 12 => 'Dual2 IS Panning', #forum11194 }, }, 0x1c => { @@ -436,7 +449,7 @@ my %shootingMode = ( same as the number printed on the camera body }, PrintConv => q{ - return $val unless $val=~/^([A-Z]\d{2})(\d{2})(\d{2})(\d{2})(\d{4})/; + return $val unless $val=~/^([A-Z][0-9A-Z]{2})(\d{2})(\d{2})(\d{2})(\d{4})/; my $yr = $2 + ($2 < 70 ? 2000 : 1900); return "($1) $yr:$3:$4 no. $5"; }, @@ -446,7 +459,15 @@ my %shootingMode = ( Name => 'PanasonicExifVersion', Writable => 'undef', }, - # 0x27 - values: 0 (LZ6,FX10K) + 0x27 => { + Name => 'VideoFrameRate', + Writable => 'int16u', + Notes => 'only valid for older models', + PrintConv => { + OTHER => sub { shift }, + 0 => 'n/a', + }, + }, 0x28 => { Name => 'ColorEffect', Writable => 'int16u', @@ -508,9 +529,11 @@ my %shootingMode = ( 0 => 'Off', 1 => 'On', #PH (TZ5) [was "Low/High Quality" from ref 4] 2 => 'Auto Exposure Bracketing (AEB)', #17 + 3 => 'Focus Bracketing', #forum11194 4 => 'Unlimited', #PH (TZ5) 8 => 'White Balance Bracketing', #18 17 => 'On (with flash)', #forum5597 + 18 => 'Aperture Bracketing', #forum11194 }, }, 0x2b => { #4 @@ -535,13 +558,15 @@ my %shootingMode = ( # 0x03 - observed with LZ6 and TZ5 in Fireworks mode # and GX7 in Fantasy/Retro/OldDays/HighKey - PH # 0x04 - observed in MP4 movie with GM1 (EXIF and 0x39 Contrast "Normal") - PH - # 0x05 - observed with FX01, FX40 and FP8 (EXIF contrast "Normal") - PH + 0x05 => 'Normal 2', #forum1194 0x06 => 'Medium Low', #PH (FZ18) 0x07 => 'Medium High', #PH (FZ18) # 0x08 - GX7 in DynamicMonochrome mode 0x0d => 'High Dynamic', #PH (FZ47 in ?) # 0x13 - seen for LX100 (PH) - # 0x18 - seen for FZ2500 (PH) + 0x18 => 'Dynamic Range (film-like)', #forum11194 + 0x2e => 'Match Filter Effects Toy', #forum11194 + 0x37 => 'Match Photo Style L. Monochrome', #forum11194 # DMC-LC1 values: 0x100 => 'Low', 0x110 => 'Normal', @@ -633,19 +658,27 @@ my %shootingMode = ( 2 => 'High (+1)', 3 => 'Lowest (-2)', #JD 4 => 'Highest (+2)', #JD - # 65531 - seen for LX100/FZ2500 "NR1" test shots at imaging-resource (PH) - # 0 - seen for FZ2500 "NR6D" test shots (PH) + 5 => '+5', #PH (NC) + 6 => '+6', # (NC) seen for DC-S1/S1R (IB) + 65531 => '-5', # LX100/FZ2500 "NR1" test shots at imaging-resource (PH) + 65532 => '-4', + 65533 => '-3', + 65534 => '-2', + 65535 => '-1', }, }, 0x2e => { #4 Name => 'SelfTimer', Writable => 'int16u', PrintConv => { + 0 => 'Off (0)', #forum11529 1 => 'Off', 2 => '10 s', 3 => '2 s', 4 => '10 s / 3 pictures', #17 - # 258 - seen for FZ2500,TZ90 (PH) + 258 => '2 s after shutter pressed', #forum11194 + 266 => '10 s after shutter pressed', #forum11194 + 778 => '3 photos after 10 s', #forum11194 }, }, # 0x2f - values: 1 (LZ6,FX10K) @@ -713,7 +746,20 @@ my %shootingMode = ( PrintConvInv => '$val =~ /(\d+)/ ? $1 : $val', }, # 0x37 - values: 0,1,2 (LZ6, 0 for movie preview); 257 (FX10K); 0,256 (TZ5, 0 for movie preview) - # 0x38 - values: 0,1,2 (LZ6, same as 0x37); 1,2 (FX10K); 0,256 (TZ5, 0 for movie preview) + # --> may indicate battery power (forum11388) + 0x38 => { #forum11388 + Name => 'BatteryLevel', + Writable => 'int16u', + PrintConv => { + 1 => 'Full', + 2 => 'Medium', + 3 => 'Low', + 4 => 'Near Empty', + 7 => 'Near Full', + 8 => 'Medium Low', + 256 => 'n/a', + }, + }, 0x39 => { #7 (L1/L10) Name => 'Contrast', Format => 'int16s', @@ -748,6 +794,7 @@ my %shootingMode = ( Name => 'AdvancedSceneType', Writable => 'int16u', Notes => 'used together with SceneMode to derive Composite AdvancedSceneMode', + # see forum11194 for more info }, 0x3e => { #PH (TZ5/FS7) # (tags 0x3b, 0x3e, 0x8008 and 0x8009 have the same values in all my samples - PH) @@ -840,7 +887,7 @@ my %shootingMode = ( }, }, 0x49 => { #19 - Name => 'LongExposureNoiseReduction', + Name => 'LongExposureNoiseReduction', # (indicates availability, forum11194) Writable => 'int16u', PrintConv => { 1 => 'Off', @@ -1079,6 +1126,10 @@ my %shootingMode = ( 4 => 'Monochrome', 5 => 'Scenery', 6 => 'Portrait', + 8 => 'Cinelike D', #forum11194 + 9 => 'Cinelike V', #forum11194 + 11 => 'L. Monochrome', #forum11194 + 15 => 'L. Monochrome D', #forum11194 }, }, 0x8a => { #18 @@ -1141,7 +1192,7 @@ my %shootingMode = ( ValueConv => '-$val / 10', ValueConvInv => '-$val * 10', }, - 0x92 => { #21 (forum9453) + 0x92 => { #21 (forum9453) (more to decode in forum11194) Name => 'WBShiftCreativeControl', Writable => 'int8u', Format => 'int8s', @@ -1169,6 +1220,7 @@ my %shootingMode = ( 0 => 'Off', 1 => 'Time Lapse', 2 => 'Stop-motion Animation', + 3 => 'Focus Bracketing', #forum11194 }, }, 0x9d => { #18 @@ -1198,6 +1250,36 @@ my %shootingMode = ( }, }, # 0xa0 - undef[32]: AWB gains and black levels (ref forum9303) + 0xa1 => { #forum11194 + Name => 'FilterEffect', + Writable => 'rational64u', + Format => 'int32u', + PrintConv => { + '0 0' => 'Expressive', + # '0 1' => have seen this for XS1 (PH) + '0 2' => 'Retro', + '0 4' => 'High Key', + '0 8' => 'Sepia', + '0 16' => 'High Dynamic', + '0 32' => 'Miniature Effect', + '0 256' => 'Low Key', + '0 512' => 'Toy Effect', + '0 1024' => 'Dynamic Monochrome', + '0 2048' => 'Soft Focus', + '0 4096' => 'Impressive Art', + '0 8192' => 'Cross Process', + '0 16384' => 'One Point Color', + '0 32768' => 'Star Filter', + '0 524288' => 'Old Days', + '0 1048576' => 'Sunshine', + '0 2097152' => 'Bleach Bypass', + '0 4194304' => 'Toy Pop', + '0 8388608' => 'Fantasy', + '0 33554432' => 'Monochrome', + '0 67108864' => 'Rough Monochrome', + '0 134217728' => 'Silky Monochrome', + }, + }, 0xa3 => { #18 Name => 'ClearRetouchValue', Writable => 'rational64u', @@ -1217,9 +1299,15 @@ my %shootingMode = ( Writable => 'int16u', PrintConv => { 0 => 'Off', 1 => 'On' }, }, + 0xac => { #forum11194 + Name => 'MonochromeFilterEffect', + Writable => 'int16u', + PrintConv => { 0 => 'Off', 1 => 'Yellow', 2 => 'Orange', 3 => 'Red', 4 => 'Green' }, + }, 0xad => { #forum9360 Name => 'HighlightShadow', Writable => 'int16u', + Format => 'int16s', #forum11194 Count => 2, }, 0xaf => { #PH (is this in UTC maybe? -- sometimes different time zone other times) @@ -1230,6 +1318,11 @@ my %shootingMode = ( PrintConv => '$self->ConvertDateTime($val)', PrintConvInv => '$self->InverseDateTime($val)', }, + 0xb3 => { #forum11194 + Name => 'VideoBurstResolution', + Writable => 'int16u', + PrintConv => { 1 => 'Off or 4K', 4 => '6K' }, + }, 0xb4 => { #forum9429 Name => 'MultiExposure', Writable => 'int16u', @@ -1251,6 +1344,10 @@ my %shootingMode = ( 0x28 => '4K Burst (Start/Stop)', 0x48 => '4K Pre-burst', 0x108 => 'Loop Recording', + 0x810 => '6K Burst', + 0x820 => '6K Burst (Start/Stop)', + 0x408 => 'Focus Stacking', #forum11563 + 0x1001 => 'High Resolution Mode', }, }, 0xbc => { #forum9282 @@ -1258,6 +1355,86 @@ my %shootingMode = ( Writable => 'int16u', PrintConv => { 0 => 'Off', 1 => 'Auto' }, }, + 0xbd => { #forum11194 + Name => 'FocusBracket', + Notes => 'positive is further, negative is closer', + Writable => 'int16u', + Format => 'int16s', + }, + 0xbe => { #forum11194 + Name => 'LongExposureNRUsed', + Writable => 'int16u', + PrintConv => { 0 => 'No', 1 => 'Yes' }, + }, + 0xbf => { #forum11194 + Name => 'PostFocusMerging', + Format => 'int32u', + Count => 2, + PrintConv => { '0 0' => 'Post Focus Auto Merging or None' }, + }, + 0xc1 => { #forum11194 + Name => 'VideoPreburst', + Writable => 'int16u', + PrintConv => { 0 => 'No', 1 => '4K or 6K' }, + }, + 0xca => { #forum11459 + Name => 'SensorType', + Writable => 'int16u', + PrintConv => { + 0 => 'Multi-aspect', + 1 => 'Standard', + }, + }, + # Note: LensTypeMake and LensTypeModel are combined into a Composite LensType tag + # defined in Olympus.pm which has the same values as Olympus:LensType + 0xc4 => { #PH + Name => 'LensTypeMake', + Condition => '$format eq "int16u" and $$valPt ne "\xff\xff"', # (ignore make 65535 for now) + Writable => 'int16u', + }, + 0xc5 => { #PH + Name => 'LensTypeModel', + Condition => '$format eq "int16u"', + Writable => 'int16u', + RawConv => q{ + return undef unless $val; + require Image::ExifTool::Olympus; # (to load Composite LensID) + return $val; + }, + ValueConv => '$_=sprintf("%.4x",$val); s/(..)(..)/$2 $1/; $_', + ValueConvInv => '$val =~ s/(..) (..)/$2$1/; hex($val)', + }, + 0xd1 => { #PH + Name => 'ISO', + RawConv => '$val > 0xfffffff0 ? undef : $val', + Writable => 'int32u', + }, + 0xd2 => { #forum11194 + Name => 'MonochromeGrainEffect', + Writable => 'int16u', + PrintConv => { + 0 => 'Off', + 1 => 'Low', + 2 => 'Standard', + 3 => 'High', + }, + }, + 0xd6 => { #PH (DC-S1) + Name => 'NoiseReductionStrength', + Writable => 'rational64s', + }, + 0xe4 => { #IB + Name => 'LensTypeModel', + Condition => '$format eq "int16u"', + Writable => 'int16u', + RawConv => q{ + return undef unless $val; + require Image::ExifTool::Olympus; # (to load Composite LensID) + return $val; + }, + ValueConv => '$_=sprintf("%.4x",$val); s/(..)(..)/$2 $1/; $_', + ValueConvInv => '$val =~ s/(..) (..)/$2$1/; hex($val)', + }, 0x0e00 => { Name => 'PrintIM', Description => 'Print Image Matching', @@ -1885,7 +2062,7 @@ my %shootingMode = ( Writable => 'int32u', }, 0x311 => { - Name => 'ExternalSensorBrightnessValue', + Name => 'ExternalSensorBrightnessValue', Condition => '$$self{Model} =~ /Typ 006/', Notes => 'Leica S only', Format => 'rational64s', # (may be incorrectly unsigned in JPEG images) @@ -1928,7 +2105,7 @@ my %shootingMode = ( WRITE_PROC => \&Image::ExifTool::Exif::WriteExif, CHECK_PROC => \&Image::ExifTool::Exif::CheckExif, GROUPS => { 0 => 'MakerNotes', 1 => 'Leica', 2 => 'Camera' }, - NOTES => 'This information is written by the Leica S (Typ 007).', + NOTES => 'This information is written by the Leica S (Typ 007) and M10 models.', 0x304 => { Name => 'FocusDistance', Notes => 'focus distance in mm for most models, but cm for others', @@ -1949,6 +2126,40 @@ my %shootingMode = ( PrintConvInv => '$val', }, # 0x340 - ImageUniqueID + 0x34c => { #23 + Name => 'UserProfile', + Writable => 'string', + }, + # 0x357 int32u - 0=DNG, 3162=JPG (ref 23) + 0x359 => { #23 + Name => 'ISOSelected', + Writable => 'int32s', + PrintConv => { + 0 => 'Auto', + OTHER => sub { return shift; }, + }, + }, + 0x35a => { #23 + Name => 'FNumber', + Writable => 'int32s', + ValueConv => '$val / 1000', + ValueConvInv => '$val * 1000', + PrintConv => 'sprintf("%.1f", $val)', + PrintConvInv => '$val', + }, + 0x035b => { #IB + Name => 'CorrelatedColorTemp', # (in Kelvin) + Writable => 'int16u', + }, + 0x035c => { #IB + Name => 'ColorTint', # (same units as Adobe is using) + Writable => 'int16s', + }, + 0x035d => { #IB + Name => 'WhitePoint', # (x/y) + Writable => 'rational64u', + Count => 2, + }, ); # Type 2 tags (ref PH) @@ -2261,6 +2472,15 @@ my %shootingMode = ( Start => 12, }, }, + 0x200080 => { # (GH6) + Name => 'ExifData', + Condition => '$$valPt =~ /^\xff\xd8\xff\xe1..Exif\0\0/s', + SubDirectory => { + TagTable => 'Image::ExifTool::Exif::Main', + ProcessProc => \&Image::ExifTool::ProcessTIFF, + Start => 12, + }, + }, ); # Panasonic Composite tags @@ -2285,7 +2505,8 @@ my %shootingMode = ( # AdvancedSceneType=5 for automatic mode iA (ref 19) if ($prt) { return $prt if $v[1] == 1; - return "$prt (intelligent auto)" if $v[1] == 5; + return "$prt (intelligent auto)" if $v[1] == 5; #forum11523 + return "$prt (intelligent auto plus)" if $v[1] == 7; #forum11523 return "$prt ($v[1])"; } return "Unknown ($val)"; @@ -2308,10 +2529,19 @@ my %shootingMode = ( '9 3' => 'Objects', #(FZ28) '9 4' => 'Creative Macro', #(FZ28) #'9 5' - ? (GF3) + '18 1' => 'High Sensitivity', #forum11523 (TZ5) + '20 1' => 'Fireworks', #forum11523 (TZ5) '21 2' => 'Illuminations', #(FZ28) '21 4' => 'Creative Night Scenery', #(FZ28) #'21 5' - ? (LX3) + '26 1' => 'High-speed Burst (shot 1)', #forum11523 (TZ5) + '27 1' => 'High-speed Burst (shot 2)', #forum11523 (TZ5) + '29 1' => 'Snow', #forum11523 (TZ5) + '30 1' => 'Starry Sky', #forum11523 (TZ5) + '31 1' => 'Beach', #forum11523 (TZ5) + '36 1' => 'High-speed Burst (shot 3)', #forum11523 (TZ5) #'37 5' - ? (various) + '39 1' => 'Aerial Photo / Underwater / Multi-aspect', #forum11523 (TZ5) '45 2' => 'Cinema', #(GF2) '45 7' => 'Expressive', #(GF1,GF2) '45 8' => 'Retro', #(GF1,GF2) @@ -2428,7 +2658,7 @@ sub ProcessLeicaLEIC($$$) #------------------------------------------------------------------------------ # Process MakerNote trailer written by Leica S2 # Inputs: 0) ExifTool object ref, 1) new absolute position of Leica trailer when writing -# Returns: On success: 1 when reading, directory data when writing; othewise undef +# Returns: On success: 1 when reading, directory data when writing; otherwise undef # Notes: # - may be called twice for a file if the first call doesn't succeed # - must leave RAF position unchanged @@ -2616,7 +2846,7 @@ Panasonic and Leica maker notes in EXIF information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PanasonicRaw.pm b/src/Image-ExifTool/lib/Image/ExifTool/PanasonicRaw.pm index 4cb1c954..fef741be 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/PanasonicRaw.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/PanasonicRaw.pm @@ -6,7 +6,7 @@ # Revisions: 2009/03/24 - P. Harvey Created # 2009/05/12 - PH Added RWL file type (same format as RW2) # -# References: 1) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,1542.0.html +# References: 1) https://exiftool.org/forum/index.php/topic,1542.0.html # 2) http://www.cybercom.net/~dcoffin/dcraw/ # 3) http://syscall.eu/#pana # 4) Klaus Homeister private communication @@ -21,7 +21,7 @@ use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; -$VERSION = '1.23'; +$VERSION = '1.26'; sub ProcessJpgFromRaw($$$); sub WriteJpgFromRaw($$$); @@ -187,10 +187,13 @@ my %panasonicWhiteBalance = ( #forum9396 Protected => 1, # 2 - RAW DMC-FZ8/FZ18 # 3 - RAW DMC-L10 - # 4 - RW2 for most other models, including G9 normal resolution and YUNEEC CGO4 + # 4 - RW2 for most other models, including G9 in "pixel shift off" mode and YUNEEC CGO4 # (must add 15 to black levels for RawFormat == 4) - # 5 - RW2 DC-GH5s and G9 HiRes - # missing - DMC-LX1/FZ30/FZ50/L1/LX1/LX2 + # 5 - RW2 DC-GH5s; G9 in "pixel shift on" mode + # 6 - RW2 DC-S1, DC-S1r in "pixel shift off" mode + # 7 - RW2 DC-S1r (and probably DC-S1, have no raw samples) in "pixel shift on" mode + # not used - DMC-LX1/FZ30/FZ50/L1/LX1/LX2 + # (modes 5 and 7 are lossless) }, 0x2e => { #JD Name => 'JpgFromRaw', # (writable directory!) @@ -215,6 +218,7 @@ my %panasonicWhiteBalance = ( #forum9396 0x30 => { Name => 'CropLeft', Writable => 'int16u' }, 0x31 => { Name => 'CropBottom', Writable => 'int16u' }, 0x32 => { Name => 'CropRight', Writable => 'int16u' }, + # 0x44 - may contain another pointer to the raw data starting at byte 2 in this data (DC-GH6) 0x10f => { Name => 'Make', Groups => { 2 => 'Camera' }, @@ -271,6 +275,7 @@ my %panasonicWhiteBalance = ( #forum9396 0x11c => { #forum9373 Name => 'Gamma', Writable => 'int16u', + # unfortunately it seems that the scaling factor varies with model... ValueConv => '$val / ($val >= 1024 ? 1024 : ($val >= 256 ? 256 : 100))', ValueConvInv => 'int($val * 256 + 0.5)', }, @@ -496,21 +501,77 @@ my %panasonicWhiteBalance = ( #forum9396 Writable => 'int32u', PrintConv => { 0 => 'No', 1 => 'Yes' }, }, - # 1201 - LensStyle? ref forum9394 + # Note: LensTypeMake and LensTypeModel are combined into a Composite LensType tag + # defined in Olympus.pm which has the same values as Olympus:LensType + 0x1201 => { #IB + Name => 'LensTypeMake', + Condition => '$format eq "int16u"', + Writable => 'int16u', + # when format is int16u, these values have been observed: + # 0 - Olympus or unknown lens + # 2 - Leica or Lumix lens + # when format is int32u (S models), these values have been observed (ref IB): + # 256 - Leica lens + # 257 - Lumix lens + # 258 - ? (seen once) + }, + 0x1202 => { #IB + Name => 'LensTypeModel', + Condition => '$format eq "int16u"', + Writable => 'int16u', + RawConv => q{ + return undef unless $val; + require Image::ExifTool::Olympus; # (to load Composite LensID) + return $val; + }, + ValueConv => '$_=sprintf("%.4x",$val); s/(..)(..)/$2 $1/; $_', + ValueConvInv => '$val =~ s/(..) (..)/$2$1/; hex($val)', + }, 0x1203 => { #4 Name => 'FocalLengthIn35mmFormat', Writable => 'int16u', PrintConv => '"$val mm"', PrintConvInv => '$val=~s/\s*mm$//;$val', }, + # 0x1300 - incident light value? (ref forum11395) + 0x1301 => { #forum11395 + Name => 'ApertureValue', + Writable => 'int16s', + Priority => 0, + ValueConv => '2 ** ($val / 512)', + ValueConvInv => '$val>0 ? 512*log($val)/log(2) : 0', + PrintConv => 'sprintf("%.1f",$val)', + PrintConvInv => '$val', + }, + 0x1302 => { #forum11395 + Name => 'ShutterSpeedValue', + Writable => 'int16s', + Priority => 0, + ValueConv => 'abs($val/256)<100 ? 2**(-$val/256) : 0', + ValueConvInv => '$val>0 ? -256*log($val)/log(2) : -25600', + PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', + PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', + }, + 0x1303 => { #forum11395 + Name => 'SensitivityValue', + Writable => 'int16s', + ValueConv => '$val / 256', + ValueConvInv => 'int($val * 256)', + }, 0x1305 => { #forum9384 Name => 'HighISOMode', Writable => 'int16u', RawConv => '$val || undef', PrintConv => { 1 => 'On', 2 => 'Off' }, }, + # 0x1306 EV for some models like the GX8 (forum11395) # 0x140b - scaled overall black level? (ref forum9281) # 0x1411 - scaled black level per channel difference (ref forum9281) + 0x1412 => { #forum11397 + Name => 'FacesDetected', + Writable => 'int8u', + PrintConv => { 0 => 'No', 1 => 'Yes' }, + }, # 0x2000 - WB tungsten=3, daylight=4 (ref forum9467) # 0x2009 - scaled black level per channel (ref forum9281) # 0x3000-0x310b - red/blue balances * 1024 (ref forum9467) @@ -572,6 +633,8 @@ my %panasonicWhiteBalance = ( #forum9396 Writable => 'int8u', PrintConv => \%Image::ExifTool::Exif::orientation, }, + # 0x3504 = Tag 0x1301+0x1302-0x1303 (Bv = Av+Tv-Sv) (forum11395) + # 0x3505 - same as 0x1300 (forum11395) 0x3600 => { #forum9396 Name => 'WhiteBalanceDetected', Writable => 'int8u', @@ -675,6 +738,7 @@ sub WriteDistortionInfo($$$) # 2 - value count # 3 - reference to list of original offset values # 4 - IFD format number +# 5 - (pointer to StripOffsets value added by this PatchRawDataOffset routine) sub PatchRawDataOffset($$$) { my ($offsetInfo, $raf, $ifd) = @_; @@ -683,15 +747,26 @@ sub PatchRawDataOffset($$$) my $rawDataOffset = $$offsetInfo{0x118}; my $err; $err = 1 unless $ifd == 0; - $err = 1 unless $stripOffsets and $stripByteCounts and $$stripOffsets[2] == 1; - if ($rawDataOffset) { + if ($stripOffsets or $stripByteCounts) { + $err = 1 unless $stripOffsets and $stripByteCounts and $$stripOffsets[2] == 1; + } else { + # the DC-GH6 and DC-GH5M2 write RawDataOffset with no Strip tags, so we need + # to create fake StripByteCounts information for copying the data + # (disable this until SilkyPix and Adobe utilities can deal with a variable + # RawDataOffset, see https://exiftool.org/forum/index.php?topic=13861.0 -- + # so these files will continue to give a "No size tag" error when writing) + # $stripByteCounts = $$offsetInfo{0x117} = [ $PanasonicRaw::Main{0x117}, 0, 1, [ 0 ], 4 ]; + } + if ($rawDataOffset and not $err) { $err = 1 unless $$rawDataOffset[2] == 1; - $err = 1 unless $$stripOffsets[3][0] == 0xffffffff or $$stripByteCounts[3][0] == 0; + if ($stripOffsets) { + $err = 1 unless $$stripOffsets[3][0] == 0xffffffff or $$stripByteCounts[3][0] == 0; + } } $err and return 'Unsupported Panasonic/Leica RAW variant'; if ($rawDataOffset) { # update StripOffsets along with this tag if it contains a reasonable value - unless ($$stripOffsets[3][0] == 0xffffffff) { + if ($stripOffsets and $$stripOffsets[3][0] != 0xffffffff) { # save pointer to StripOffsets value for updating later push @$rawDataOffset, $$stripOffsets[1]; } @@ -790,7 +865,10 @@ sub ProcessJpgFromRaw($$$) $out = $et->Options('TextOut'); print $out '--- DOC1:JpgFromRaw ',('-'x56),"\n"; } + # fudge HtmlDump base offsets to show as a stand-alone JPEG + $$et{BASE_FUDGE} = $$et{BASE}; my $rtnVal = $et->ProcessJPEG(\%dirInfo); + $$et{BASE_FUDGE} = 0; # restore necessary variables for continued RW2/RWL processing $$et{BASE} = 0; $$et{FILE_TYPE} = 'TIFF'; @@ -823,7 +901,7 @@ write meta information in Panasonic/Leica RAW, RW2 and RWL images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Parrot.pm b/src/Image-ExifTool/lib/Image/ExifTool/Parrot.pm new file mode 100644 index 00000000..555eab48 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/Parrot.pm @@ -0,0 +1,846 @@ +#------------------------------------------------------------------------------ +# File: Parrot.pm +# +# Description: Read timed metadata from Parrot drone videos +# +# Revisions: 2019-10-23 - P. Harvey Created +# +# References: 1) https://developer.parrot.com/docs/pdraw/metadata.html +# --> changed to https://developer.parrot.com/docs/pdraw/video-metadata.html +#------------------------------------------------------------------------------ + +package Image::ExifTool::Parrot; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.02'; + +sub Process_mett($$$); + +# tags found in Parrot 'mett' timed metadata (ref 1) +%Image::ExifTool::Parrot::mett = ( + PROCESS_PROC => \&Process_mett, + # put the 'P' records first in the documentation + VARS => { + SORT_PROC => sub { my ($a,$b)=@_; $a=~s/P/A/; $b=~s/P/A/; $a cmp $b }, + LONG_TAGS => 1 + }, + NOTES => q{ + Streaming metadata found in Parrot drone videos. See + L<https://developer.parrot.com/docs/pdraw/metadata.html> for the + specification. + }, + P1 => { + Name => 'ParrotV1', + SubDirectory => { TagTable => 'Image::ExifTool::Parrot::V1' }, + }, + P2 => { + Name => 'ParrotV2', + SubDirectory => { TagTable => 'Image::ExifTool::Parrot::V2' }, + }, + P3 => { + Name => 'ParrotV3', + SubDirectory => { TagTable => 'Image::ExifTool::Parrot::V3' }, + }, + E1 => { + Name => 'ParrotTimeStamp', + SubDirectory => { TagTable => 'Image::ExifTool::Parrot::TimeStamp' }, + }, + E2 => { + Name => 'ParrotFollowMe', + SubDirectory => { TagTable => 'Image::ExifTool::Parrot::FollowMe' }, + }, + E3 => { + Name => 'ParrotAutomation', + SubDirectory => { TagTable => 'Image::ExifTool::Parrot::Automation' }, + }, + # timed metadata written by ARCore (see forum13653) + 'application/arcore-accel' => { + Name => 'ARCoreAccel', + SubDirectory => { TagTable => 'Image::ExifTool::Parrot::ARCoreAccel', ByteOrder => 'II' }, + }, + 'application/arcore-gyro' => { + Name => 'ARCoreGyro', + SubDirectory => { TagTable => 'Image::ExifTool::Parrot::ARCoreGyro', ByteOrder => 'II' }, + }, + 'application/arcore-video-0' => { + Name => 'ARCoreVideo', + SubDirectory => { TagTable => 'Image::ExifTool::Parrot::ARCoreVideo', ByteOrder => 'II' }, + }, + 'application/arcore-custom-event' => { + Name => 'ARCoreCustom', + SubDirectory => { TagTable => 'Image::ExifTool::Parrot::ARCoreCustom', ByteOrder => 'II' }, + }, +); + +# tags found in the Parrot 'mett' V1 timed metadata (ref 1) [untested] +%Image::ExifTool::Parrot::V1 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + NOTES => 'Parrot version 1 streaming metadata.', + GROUPS => { 2 => 'Location' }, + 4 => { + Name => 'DroneYaw', + Format => 'int16s', + ValueConv => '$val / 0x1000 * 180 / 3.14159', # convert from rad to deg + }, + 6 => { + Name => 'DronePitch', + Format => 'int16s', + ValueConv => '$val / 0x1000 * 180 / 3.14159', + }, + 8 => { + Name => 'DroneRoll', + Format => 'int16s', + ValueConv => '$val / 0x1000 * 180 / 3.14159', + }, + 10 => { + Name => 'CameraPan', + Format => 'int16s', + ValueConv => '$val / 0x1000 * 180 / 3.14159', + }, + 12 => { + Name => 'CameraTilt', + Format => 'int16s', + ValueConv => '$val / 0x1000 * 180 / 3.14159', + }, + 14 => { + Name => 'FrameView', # (W,X,Y,Z) + Format => 'int16s[4]', + ValueConv => 'my @a = split " ",$val; $_ /= 0x1000 foreach @a; "@a"', + }, + 22 => { + Name => 'ExposureTime', + Groups => { 2 => 'Camera' }, + Format => 'int16s', + ValueConv => '$val / 0x100 / 1000', + PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', + }, + 24 => { + Name => 'ISO', + Groups => { 2 => 'Camera' }, + Format => 'int16s', + }, + 26 => { + Name => 'WifiRSSI', + Groups => { 2 => 'Device' }, + Format => 'int8s', + PrintConv => '"$val dBm"', + }, + 27 => { + Name => 'Battery', + Groups => { 2 => 'Device' }, + PrintConv => '"$val %"', + }, + 28 => { + Name => 'GPSLatitude', + Format => 'int32s', + ValueConv => '$val / 0x100000', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + }, + 32 => { + Name => 'GPSLongitude', + Format => 'int32s', + ValueConv => '$val / 0x100000', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + }, + 36 => { + Name => 'GPSAltitude', + Format => 'int32s', + Mask => 0xffffff00, + ValueConv => '$val / 0x100', + PrintConv => 'sprintf("%.3f m", $val)', + }, + 36.1 => { + Name => 'GPSSatellites', # (SV count) + Format => 'int32s', + Mask => 0xff, + }, + 40 => { + Name => 'AltitudeFromTakeOff', + Format => 'int32s', + ValueConv => '$val / 0x10000', + PrintConv => 'sprintf("%.3f m", $val)', + }, + 44 => { + Name => 'DistanceFromHome', + Format => 'int32u', + ValueConv => '$val / 0x10000', + }, + 48 => { + Name => 'SpeedX', + Format => 'int16s', + ValueConv => '$val / 0x100', + }, + 50 => { + Name => 'SpeedY', + Format => 'int16s', + ValueConv => '$val / 0x100', + }, + 52 => { + Name => 'SpeedZ', + Format => 'int16s', + ValueConv => '$val / 0x100', + }, + 54 => { + Name => 'Binning', + Groups => { 2 => 'Device' }, + Mask => 0x80, + }, + 54.1 => { + Name => 'FlyingState', + Groups => { 2 => 'Device' }, + Mask => 0x7f, + PrintConv => { + 0 => 'Landed', + 1 => 'Taking Off', + 2 => 'Hovering', + 3 => 'Flying', + 4 => 'Landing', + 5 => 'Emergency', + }, + }, + 55 => { + Name => 'Animation', + Groups => { 2 => 'Device' }, + Mask => 0x80, + }, + 55.1 => { + Name => 'PilotingMode', + Groups => { 2 => 'Device' }, + Mask => 0x7f, + PrintConv => { + 0 => 'Manual', + 1 => 'Return Home', + 2 => 'Flight Plan', + 3 => 'Follow Me', + }, + }, +); + +# tags found in the Parrot 'mett' V2 timed metadata (ref 1) [untested] +%Image::ExifTool::Parrot::V2 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + Groups => { 2 => 'Location' }, + NOTES => 'Parrot version 2 basic streaming metadata.', + 4 => { + Name => 'Elevation', + Notes => 'estimated distance from ground', + Format => 'int32s', + ValueConv => '$val / 0x10000', + PrintConv => 'sprintf("%.3f m", $val)', + }, + 8 => { + Name => 'GPSLatitude', + Format => 'int32s', + ValueConv => '$val / 0x400000', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + }, + 12 => { + Name => 'GPSLongitude', + Format => 'int32s', + ValueConv => '$val / 0x400000', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + }, + 16 => { + Name => 'GPSAltitude', + Format => 'int32s', + Mask => 0xffffff00, + ValueConv => '$val / 0x100', + PrintConv => 'sprintf("%.3f m", $val)', + }, + 16.1 => { + Name => 'GPSSatellites', # (SV count) + Format => 'int32s', + Mask => 0xff, + }, + 20 => { + Name => 'GPSVelocityNorth', # (m/s) + Format => 'int16s', + ValueConv => '$val / 0x100', + }, + 22 => { + Name => 'GPSVelocityEast', # (m/s) + Format => 'int16s', + ValueConv => '$val / 0x100', + }, + 24 => { + Name => 'GPSVelocityDown', # (m/s) + Format => 'int16s', + ValueConv => '$val / 0x100', + }, + 26 => { + Name => 'AirSpeed', # (m/s) + Format => 'int16s', + RawConv => '$val < 0 ? undef : $val', + ValueConv => '$val / 0x100', + }, + 28 => { + Name => 'DroneQuaternion', # (W,X,Y,Z) + Format => 'int16s[4]', + ValueConv => 'my @a = split " ",$val; $_ /= 0x4000 foreach @a; "@a"', + }, + 36 => { + Name => 'FrameView', # (W,X,Y,Z) + Format => 'int16s[4]', + ValueConv => 'my @a = split " ",$val; $_ /= 0x4000 foreach @a; "@a"', + }, + 44 => { + Name => 'CameraPan', + Format => 'int16s', + ValueConv => '$val / 0x1000 * 180 / 3.14159', # convert from rad to deg + }, + 46 => { + Name => 'CameraTilt', + Format => 'int16s', + ValueConv => '$val / 0x1000 * 180 / 3.14159', + }, + 48 => { + Name => 'ExposureTime', + Groups => { 2 => 'Camera' }, + Format => 'int16u', + ValueConv => '$val / 0x100 / 1000', + PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', + }, + 50 => { + Name => 'ISO', + Groups => { 2 => 'Camera' }, + Format => 'int16u', + }, + 52 => { + Name => 'Binning', + Groups => { 2 => 'Device' }, + Mask => 0x80, + }, + 52.1 => { + Name => 'FlyingState', + Groups => { 2 => 'Device' }, + Mask => 0x7f, + PrintConv => { + 0 => 'Landed', + 1 => 'Taking Off', + 2 => 'Hovering', + 3 => 'Flying', + 4 => 'Landing', + 5 => 'Emergency', + 6 => 'User Takeoff', + 7 => 'Motor Ramping', + 8 => 'Emergency Landing', + }, + }, + 53 => { + Name => 'Animation', + Groups => { 2 => 'Device' }, + Mask => 0x80, + }, + 53.1 => { + Name => 'PilotingMode', + Groups => { 2 => 'Device' }, + Mask => 0x7f, + PrintConv => { + 0 => 'Manual', + 1 => 'Return Home', + 2 => 'Flight Plan', + 3 => 'Follow Me / Tracking', # (same as 'Tracking') + 4 => 'Magic Carpet', + 5 => 'Move To', + }, + }, + 54 => { + Name => 'WifiRSSI', + Groups => { 2 => 'Device' }, + Format => 'int8s', + PrintConv => '"$val dBm"', + }, + 55 => { + Name => 'Battery', + Groups => { 2 => 'Device' }, + PrintConv => '"$val %"', + }, +); + +# tags found in the Parrot 'mett' V3 timed metadata (ref 1) +%Image::ExifTool::Parrot::V3 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + NOTES => 'Parrot version 3 basic streaming metadata.', + 4 => { + Name => 'Elevation', + Notes => 'estimated distance from ground', + Format => 'int32s', + ValueConv => '$val / 0x10000', + PrintConv => 'sprintf("%.3f m", $val)', + }, + 8 => { + Name => 'GPSLatitude', + Format => 'int32s', + ValueConv => '$val / 0x400000', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + }, + 12 => { + Name => 'GPSLongitude', + Format => 'int32s', + ValueConv => '$val / 0x400000', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + }, + 16 => { + Name => 'GPSAltitude', + Format => 'int32s', + Mask => 0xffffff00, + ValueConv => '$val / 0x100', + PrintConv => 'sprintf("%.3f m", $val)', + }, + 16.1 => { + Name => 'GPSSatellites', # (SV count) + Format => 'int32s', + Mask => 0xff, + }, + 20 => { + Name => 'GPSVelocityNorth', # (m/s) + Format => 'int16s', + ValueConv => '$val / 0x100', + }, + 22 => { + Name => 'GPSVelocityEast', # (m/s) + Format => 'int16s', + ValueConv => '$val / 0x100', + }, + 24 => { + Name => 'GPSVelocityDown', # (m/s) + Format => 'int16s', + ValueConv => '$val / 0x100', + }, + 26 => { + Name => 'AirSpeed', # (m/s) + Format => 'int16s', + RawConv => '$val < 0 ? undef : $val', + ValueConv => '$val / 0x100', + }, + 28 => { + Name => 'DroneQuaternion', # (W,X,Y,Z) + Format => 'int16s[4]', + ValueConv => 'my @a = split " ",$val; $_ /= 0x4000 foreach @a; "@a"', + }, + 36 => { + Name => 'FrameBaseView', # (W,X,Y,Z without pan/tilt) + Format => 'int16s[4]', + ValueConv => 'my @a = split " ",$val; $_ /= 0x4000 foreach @a; "@a"', + }, + 44 => { + Name => 'FrameView', # (W,X,Y,Z) + Format => 'int16s[4]', + ValueConv => 'my @a = split " ",$val; $_ /= 0x4000 foreach @a; "@a"', + }, + 52 => { + Name => 'ExposureTime', + Groups => { 2 => 'Camera' }, + Format => 'int16u', + ValueConv => '$val / 0x100 / 1000', + PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', + }, + 54 => { + Name => 'ISO', + Groups => { 2 => 'Camera' }, + Format => 'int16u', + }, + 56 => { + Name => 'RedBalance', + Groups => { 2 => 'Camera' }, + Format => 'int16u', + ValueConv => '$val / 0x4000', + }, + 58 => { + Name => 'BlueBalance', + Groups => { 2 => 'Camera' }, + Format => 'int16u', + ValueConv => '$val / 0x4000', + }, + 60 => { + Name => 'FOV', # (degrees) + Description => 'Field Of View', + Notes => 'horizontal and vertical field of view in degrees', + Groups => { 2 => 'Image' }, + Format => 'int16u[2]', + ValueConv => 'my @a = split " ",$val; $_ /= 0x100 foreach @a; "@a"', + }, + 64 => { + Name => 'LinkGoodput', + Groups => { 2 => 'Device' }, + Format => 'int32u', + Mask => 0xffffff00, + PrintConv => '"$val kbit/s"', + }, + 64.1 => { + Name => 'LinkQuality', + Groups => { 2 => 'Device' }, + Format => 'int32u', + Notes => '0-5', + Mask => 0xff, + }, + 68 => { + Name => 'WifiRSSI', + Groups => { 2 => 'Device' }, + Format => 'int8s', + PrintConv => '"$val dBm"', + }, + 69 => { + Name => 'Battery', + Groups => { 2 => 'Device' }, + PrintConv => '"$val %"', + }, + 70 => { + Name => 'Binning', + Groups => { 2 => 'Device' }, + Mask => 0x80, + }, + 70.1 => { + Name => 'FlyingState', + Groups => { 2 => 'Device' }, + Mask => 0x7f, + PrintConv => { + 0 => 'Landed', + 1 => 'Taking Off', + 2 => 'Hovering', + 3 => 'Flying', + 4 => 'Landing', + 5 => 'Emergency', + 6 => 'User Takeoff', + 7 => 'Motor Ramping', + 8 => 'Emergency Landing', + }, + }, + 71 => { + Name => 'Animation', + Groups => { 2 => 'Device' }, + Mask => 0x80, + }, + 71.1 => { + Name => 'PilotingMode', + Groups => { 2 => 'Device' }, + Mask => 0x7f, + PrintConv => { + 0 => 'Manual', + 1 => 'Return Home', + 2 => 'Flight Plan', + 3 => 'Follow Me / Tracking', # (same as 'Tracking') + 4 => 'Magic Carpet', + 5 => 'Move To', + }, + }, +); + +# tags found in the Parrot 'mett' E1 timestamp timed metadata (ref 1) +%Image::ExifTool::Parrot::TimeStamp = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + NOTES => 'Parrot streaming metadata timestamp extension.', + GROUPS => { 2 => 'Time' }, + 4 => { + Name => 'TimeStamp', + Format => 'int64u', + ValueConv => '$val / 1e6', + }, +); + +# tags found in the Parrot 'mett' E2 follow-me timed metadata (ref 1) [untested] +%Image::ExifTool::Parrot::FollowMe = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + NOTES => 'Parrot streaming metadata follow-me extension.', + 4 => { + Name => 'GPSTargetLatitude', + Format => 'int32s', + ValueConv => '$val / 0x400000', + }, + 8 => { + Name => 'GPSTargetLongitude', + Format => 'int32s', + ValueConv => '$val / 0x400000', + }, + 12 => { + Name => 'GPSTargetAltitude', + Format => 'int32s', + ValueConv => '$val / 0x10000', + }, + 16 => { + Name => 'Follow-meMode', + Groups => { 2 => 'Device' }, + PrintConv => { BITMASK => { + 0 => 'Follow-me enabled', + 1 => 'Follow-me', # (0=Look-at-me! auggh. see AutomationFlags below) + 2 => 'Angle locked', + }}, + }, + 17 => { + Name => 'Follow-meAnimation', + Groups => { 2 => 'Device' }, + PrintConv => { + 0 => 'None', + 1 => 'Orbit', + 2 => 'Boomerang', + 3 => 'Parabola', + 4 => 'Zenith', + }, + }, +); + +# tags found in the Parrot 'mett' E3 automation timed metadata (ref 1) +%Image::ExifTool::Parrot::Automation = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + NOTES => 'Parrot streaming metadata automation extension.', + 4 => { + Name => 'GPSFramingLatitude', + Format => 'int32s', + ValueConv => '$val / 0x400000', + }, + 8 => { + Name => 'GPSFramingLongitude', + Format => 'int32s', + ValueConv => '$val / 0x400000', + }, + 12 => { + Name => 'GPSFramingAltitude', + Format => 'int32s', + ValueConv => '$val / 0x10000', + }, + 16 => { + Name => 'GPSDestLatitude', + Format => 'int32s', + ValueConv => '$val / 0x400000', + }, + 20 => { + Name => 'GPSDestLongitude', + Format => 'int32s', + ValueConv => '$val / 0x400000', + }, + 24 => { + Name => 'GPSDestAltitude', + Format => 'int32s', + ValueConv => '$val / 0x10000', + }, + 28 => { + Name => 'AutomationAnimation', + Groups => { 2 => 'Device' }, + PrintConv => { + 0 => 'None', + 1 => 'Orbit', + 2 => 'Boomerang', + 3 => 'Parabola', + 4 => 'Dolly Slide', + 5 => 'Dolly Zoom', + 6 => 'Reveal Vertical', + 7 => 'Reveal Horizontal', + 8 => 'Candle', + 9 => 'Flip Front', + 10 => 'Flip Back', + 11 => 'Flip Left', + 12 => 'Flip Right', + 13 => 'Twist Up', + 14 => 'Position Twist Up', + }, + }, + 29 => { + Name => 'AutomationFlags', + Groups => { 2 => 'Device' }, + PrintConv => { BITMASK => { + 0 => 'Follow-me enabled', + 1 => 'Look-at-me enabled', # (really? opposite sense to Follow-meMode above!) + 2 => 'Angle locked', + }}, + }, +); + +# ARCore Accel data (ref PH) +%Image::ExifTool::Parrot::ARCoreAccel = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + NOTES => 'ARCore accelerometer data.', + FIRST_ENTRY => 0, + # 00-04: always 10 34 16 1 29 + 4 => { + Name => 'AccelerometerUnknown', + Format => 'undef[16]', + Unknown => 1, + ValueConv => 'join " ", unpack("Cx4Cx4Cx4C", $val)', + }, + 5 => { # (NC) + Name => 'Accelerometer', + Format => 'undef[14]', + RawConv => 'GetFloat(\$val,0) . " " . GetFloat(\$val,5) . " " . GetFloat(\$val,10)', + }, + # 05-08: float Accelerometer X + # 09: 37 + # 10-13: float Accelerometer Y + # 14: 45 + # 15-18: float Accelerometer Z + # 19: 48 + # 20-24: 128-255 + # 25: 246 then 247 + # 26: 188 + # 27: 2 + # 28: 56 + # 29-32: 128-255 + # 33: increments slowly (about once every 56 samples or so) +); + +# ARCore Gyro data (ref PH) +%Image::ExifTool::Parrot::ARCoreGyro = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + NOTES => 'ARCore accelerometer data.', + FIRST_ENTRY => 0, + # 00-04: always 10 34 16 3 29 + 4 => { + Name => 'GyroscopeUnknown', + Format => 'undef[16]', + Unknown => 1, # always "29 37 45 48" in my sample, just like AccelerometerUnknown + ValueConv => 'join " ", unpack("Cx4Cx4Cx4C", $val)', + }, + 5 => { # (NC) + Name => 'Gyroscope', + Format => 'undef[14]', + RawConv => 'GetFloat(\$val,0) . " " . GetFloat(\$val,5) . " " . GetFloat(\$val,10)', + }, +); + +%Image::ExifTool::Parrot::ARCoreVideo = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + FIRST_ENTRY => 0, +); + +%Image::ExifTool::Parrot::ARCoreCustom = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + FIRST_ENTRY => 0, +); + +%Image::ExifTool::Parrot::Composite = ( + GPSDateTime => { + Description => 'GPS Date/Time', + Groups => { 2 => 'Time' }, + SubDoc => 1, + Require => { + 0 => 'Parrot:GPSLatitude', # (avoids creating this tag for other videos) + 1 => 'Main:CreateDate', + 2 => 'SampleTime', + }, + ValueConv => q{ + my $time = $val[1]; + my $diff = $val[2]; + # handle time zone and shift to UTC + if ($time =~ s/([-+])(\d{1,2}):?(\d{2})$//) { + my $secs = (($2 * 60) + $3) * 60; + $secs *= -1 if $1 eq '+'; + $diff += $secs; + } elsif ($time !~ s/Z$//) { + # shift from local time + $diff += GetUnixTime($time, 1) - GetUnixTime($time); + } + my $sign = ($diff =~ s/^-// ? '-' : ''); + $time .= '.000'; # add decimal seconds + ShiftTime($time, "${sign}0:0:$diff"); + return $time . 'Z'; + }, + PrintConv => '$self->ConvertDateTime($val)', + }, +); + +# add our composite tags +Image::ExifTool::AddCompositeTags('Image::ExifTool::Parrot'); + + +#------------------------------------------------------------------------------ +# Parse Parrot 'mett' timed metadata +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +# (this metadata design is really stupid -- you need to know the size of the base structures) +sub Process_mett($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dataPos = $$dirInfo{DataPos}; + my $dirEnd = length $$dataPt; + my $pos = $$dirInfo{DirStart} || 0; + my $metaType = $$et{MetaType} || ''; + + $et->VerboseDir('Parrot mett', undef, $dirEnd); + + if ($$tagTbl{$metaType}) { + $et->HandleTag($tagTbl, $metaType, undef, + DataPt => $dataPt, + DataPos => $dataPos, + Base => $$dirInfo{Base}, + ); + return 1; + } + while ($pos + 4 < $dirEnd) { + my ($id, $nwords) = unpack("x${pos}a2n", $$dataPt); + my $size; + if ($id !~ /^[EP]\d/) { + # no ID so this should be a 60-byte V1 recording record, otherwise give up + last unless $dirEnd == 60; + $id = 'P1'; # generate a fake ID + # ignore the first 4 of the record so the fields will align with + # the other V1 records (unfortunately, this means that we won't + # decode the V1 recording frame timestamp, but oh well) + $pos += 4; + $size = $dirEnd - $pos; + # must override size for P3 and P3 records since it includes the extensions (augh!) + } elsif ($id eq 'P2') { + $size = 56; + } elsif ($id eq 'P3') { + $size = 72; + } else { + $size = $nwords * 4 + 4; + } + last if $pos + $size > $dirEnd; + $et->HandleTag($tagTbl, $id, undef, + DataPt => $dataPt, + DataPos => $dataPos, + Base => $$dirInfo{Base}, + Start => $pos, + Size => $size, + ); + $pos += $size; + } + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::Parrot - Read timed metadata from Parrot drone videos + +=head1 SYNOPSIS + +This module is loaded automatically by Image::ExifTool when required. + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to interpret +timed metadata from the 'mett' frame found in Parrot drone MP4 videos. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<https://developer.parrot.com/docs/pdraw/metadata.html> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/Parrot Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Pentax.pm b/src/Image-ExifTool/lib/Image/ExifTool/Pentax.pm index b98f94c5..9b74ea49 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Pentax.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Pentax.pm @@ -37,11 +37,11 @@ # 22) Bozi (K10D, http://www.cpanforum.com/posts/8480) # 23) Akos Szalkai (https://rt.cpan.org/Ticket/Display.html?id=43743) # 24) Albert Bogner private communication -# 26) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3444.0.html -# 27) http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3833.0.html -# 28) Klaus Homeister http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,4803.0.html +# 26) https://exiftool.org/forum/index.php/topic,3444.0.html +# 27) https://exiftool.org/forum/index.php/topic,3833.0.html +# 28) Klaus Homeister https://exiftool.org/forum/index.php/topic,4803.0.html # 29) Louis Granboulan private communication (K-5II) -# 30) http://u88.n24.queensu.ca/exiftool/forum/index.php?topic=5433 +# 30) https://exiftool.org/forum/index.php?topic=5433 # 31) Andras Salamon private communication (K-70) # IB) Iliah Borg private communication (LibRaw) # JD) Jens Duttke private communication @@ -58,7 +58,7 @@ use Image::ExifTool::Exif; use Image::ExifTool::GPS; use Image::ExifTool::HP; -$VERSION = '3.24'; +$VERSION = '3.40'; sub CryptShutterCount($$); sub PrintFilter($$$); @@ -146,7 +146,7 @@ sub DecodeAFPoints($$$$;$); '3 44.3' => 'Sigma 17-70mm F2.8-4.5 DC Macro', #(Bart Hickman) '3 44.4' => 'Sigma 18-50mm F3.5-5.6 DC', #4 '3 44.5' => 'Sigma 17-35mm F2.8-4 EX DG', #29 - '3 44.6' => 'Tamron 35-90mm F4 AF', #12 + '3 44.6' => 'Tamron 35-90mm F4-5.6 AF', #12 (added "-5.6", ref IB) '3 44.7' => 'Sigma AF 18-35mm F3.5-4.5 Aspherical', #29 '3 46' => 'Sigma or Samsung Lens (3 46)', '3 46.1' => 'Sigma APO 70-200mm F2.8 EX', @@ -171,13 +171,14 @@ sub DecodeAFPoints($$$$;$); '3 255.4' => 'Sigma DF EX Aspherical 28-70mm F2.8', #12 '3 255.5' => 'Sigma AF Tele 400mm F5.6 Multi-coated', #JD '3 255.6' => 'Sigma 24-60mm F2.8 EX DG', #PH - '3 255.7' => 'Sigma 70-300mm F4-5.6 Macro', #JD + '3 255.7' => 'Sigma 70-300mm F4-5.6 Macro', #JD (also DG Macro, ref 27) '3 255.8' => 'Sigma 55-200mm F4-5.6 DC', #JD '3 255.9' => 'Sigma 18-50mm F2.8 EX DC', #JD (also Macro version - PH) '4 1' => 'smc PENTAX-FA SOFT 28mm F2.8', '4 2' => 'smc PENTAX-FA 80-320mm F4.5-5.6', '4 3' => 'smc PENTAX-FA 43mm F1.9 Limited', '4 6' => 'smc PENTAX-FA 35-80mm F4-5.6', + '4 8' => 'Irix 150mm F2.8 Macro', #exiv2 issue 1084 '4 9' => 'Irix 11mm F4 Firefly', #27 '4 10' => 'Irix 15mm F2.4', #27 '4 12' => 'smc PENTAX-FA 50mm F1.4', #17 @@ -304,8 +305,9 @@ sub DecodeAFPoints($$$$;$); '7 243' => 'smc PENTAX-DA 70mm F2.4 Limited', #PH '7 244' => 'smc PENTAX-DA 21mm F3.2 AL Limited', #16 '8 0' => 'Sigma 50-150mm F2.8 II APO EX DC HSM', #forum2997 - '8 3' => 'Sigma AF 18-125mm F3.5-5.6 DC', #29 + '8 3' => 'Sigma 18-125mm F3.8-5.6 DC HSM', #forum10167 '8 4' => 'Sigma 50mm F1.4 EX DG HSM', #Artur private communication + '8 6' => 'Sigma 4.5mm F2.8 EX DC Fisheye', #IB '8 7' => 'Sigma 24-70mm F2.8 IF EX DG HSM', #Exiv2 '8 8' => 'Sigma 18-250mm F3.5-6.3 DC OS HSM', #27 '8 11' => 'Sigma 10-20mm F3.5 EX DC HSM', #27 @@ -316,9 +318,11 @@ sub DecodeAFPoints($$$$;$); '8 16' => 'Sigma 70-200mm F2.8 EX DG Macro HSM II', #26 '8 17' => 'Sigma 50-500mm F4.5-6.3 DG OS HSM', #(Heike Herrmann) (also APO, ref 26) '8 18' => 'Sigma 8-16mm F4.5-5.6 DC HSM', #forum2998 + '8 20' => 'Sigma 18-50mm F2.8-4.5 DC HSM', #IB '8 21' => 'Sigma 17-50mm F2.8 EX DC OS HSM', #26 '8 22' => 'Sigma 85mm F1.4 EX DG HSM', #26 '8 23' => 'Sigma 70-200mm F2.8 APO EX DG OS HSM', #27 + '8 24' => 'Sigma 17-70mm F2.8-4 DC Macro OS HSM', #27 '8 25' => 'Sigma 17-50mm F2.8 EX DC HSM', #Exiv2 '8 27' => 'Sigma 18-200mm F3.5-6.3 II DC HSM', #27 '8 28' => 'Sigma 18-250mm F3.5-6.3 DC Macro HSM', #27 @@ -334,6 +338,11 @@ sub DecodeAFPoints($$$$;$); '8 62' => 'HD PENTAX-D FA 24-70mm F2.8 ED SDM WR', #PH '8 63' => 'HD PENTAX-D FA 15-30mm F2.8 ED SDM WR', #PH '8 64' => 'HD PENTAX-D FA* 50mm F1.4 SDM AW', #27 + '8 65' => 'HD PENTAX-D FA 70-210mm F4 ED SDM WR', #PH + '8 66' => 'HD PENTAX-D FA 85mm F1.4 ED SDM AW', #James O'Neill + '8 67' => 'HD PENTAX-D FA 21mm F2.4 ED Limited DC WR', #ChristianShulz + '8 195' => 'HD PENTAX DA* 16-50mm F2.8 ED PLM AW', #27 + '8 196' => 'HD PENTAX-DA* 11-18mm F2.8 ED DC AW', #29 '8 197' => 'HD PENTAX-DA 55-300mm F4.5-6.3 ED PLM WR RE', #29 '8 198' => 'smc PENTAX-DA L 18-50mm F4-5.6 DC WR RE', #29 '8 199' => 'HD PENTAX-DA 18-50mm F4-5.6 DC WR RE', #29 @@ -394,6 +403,10 @@ sub DecodeAFPoints($$$$;$); '21 7' => '07 Mount Shield 11.5mm F9', #PH (NC) '21 8' => '08 Wide Zoom 3.8-5.9mm F3.7-4', #PH (NC) '21 233' => 'Adapter Q for K-mount Lens', #29 +# +# Ricoh lenses +# + '31 1' => 'GR Lens', #PH (GR III 28mm F2.8) ); # Pentax model ID codes - PH @@ -533,9 +546,12 @@ my %pentaxModelID = ( 0x13092 => 'K-1', #IB (Ricoh) 0x1309c => 'K-3 II', #29 (Ricoh) 0x131f0 => 'WG-M2', # (Ricoh) + 0x1320e => 'GR III', # (Ricoh) 0x13222 => 'K-70', #29 (Ricoh) 0x1322c => 'KP', #29 (Ricoh) 0x13240 => 'K-1 Mark II', # (Ricoh) + 0x13254 => 'K-3 Mark III', #IB (Ricoh) + 0x13290 => 'WG-70', # (Ricoh) ); # Pentax city codes - (PH, Optio WP) @@ -1118,6 +1134,8 @@ my %binaryDataAttrs = ( 3 => 'Manual', 4 => 'Super Macro', #JD 5 => 'Pan Focus', + # 8 - seen for Ricoh GR III + # 9 - seen for Ricoh GR III 16 => 'AF-S (Focus-priority)', #17 17 => 'AF-C (Focus-priority)', #17 18 => 'AF-A (Focus-priority)', #PH (educated guess) @@ -1128,6 +1146,8 @@ my %binaryDataAttrs = ( 273 => 'AF-C (Release-priority)', #PH (K-5,K-3) 274 => 'AF-A (Release-priority)', #PH (K-3) 288 => 'Contrast-detect (Release-priority)', #PH (K-01) + # 32777 (0x8009) - seen for Ricoh GR III + # 32779 (0x800b) - seen for Ricoh GR III }, },{ Name => 'FocusMode', @@ -1552,12 +1572,27 @@ my %binaryDataAttrs = ( 'Saturation', 'Sharpness', 'Contrast', 'Hue' or 'HighLowKey' followed by '+1', '+2' or '+3' for step size }, - # 1=.3ev, 2=.7, 3=1.0, ... 10=.5ev, 11=1.5, ... - ValueConv => [ '$val<10 ? $val/3 : $val-9.5' ], - ValueConvInv => [ 'abs($val-int($val)-.5)>0.05 ? int($val*3+0.5) : int($val+10)' ], + # 1=.3ev, 2=.7, 3=1.0 ... 10=.5, 11=1.5, ... 4096=0, 4097=0.5 ... 8192=0, 8193=0.3 + # (models like K-1 and K-5 use 0x1000 and 0x2000 to indicate 1/2 and 1/3 EV step + # size -- convert this as a fraction so we can recognize this format when writing) + ValueConv => [ q{ + return $val / 3 if $val < 10; + return $val - 9.5 if $val < 20; + return ($val - 0x1000) . '/2' if $val & 0x1000; + return ($val - 0x2000) . '/3' if $val & 0x2000; + return $val; # (shouldn't happen) + }], + ValueConvInv => [ q{ + if ($val =~ s{/(\d+)$}{}) { + return $val + 0x1000 if $1 == 2; + return $val + 0x2000 if $1 == 3; + return undef; + } + return abs($val-int($val)-.5)>0.05 ? int($val*3+0.5) : int($val+10); + }], PrintConv => sub { my @v = split(' ', shift); - $v[0] = sprintf('%.1f', $v[0]) if $v[0]; + $v[0] = sprintf('%.1f', $v[0]) if $v[0] and $v[0]!~m{/}; if ($v[1]) { my %s = (1=>'WB-BA',2=>'WB-GM',3=>'Saturation',4=>'Sharpness', 5=>'Contrast',6=>'Hue',7=>'HighLowKey'); @@ -2103,6 +2138,8 @@ my %binaryDataAttrs = ( 9 => 'Radiant', # (Q) 10 => 'Cross Processing', #31 (K-70) 11 => 'Flat', #31 (K-70) + # 256 - seen for GR III + # 262 - seen for GR III }, }, 0x0050 => { #PH @@ -2187,6 +2224,8 @@ my %binaryDataAttrs = ( 16 => '16 (K-1)', #PH 17 => '17 (K-70)', #29 18 => '18 (KP)', #PH + 19 => '19 (GR III)', #PH + 20 => '20 (K-3III)', #PH }, }, 0x0067 => { #PH (K-5) @@ -2418,6 +2457,8 @@ my %binaryDataAttrs = ( '1 0' => 'Slow', '2 0' => 'Standard', '3 0' => 'Fast', + # '1 108' - seen for GR III + # '3 84' - seen for K-3III }, }, 0x007b => { #PH (K-5) @@ -2519,10 +2560,24 @@ my %binaryDataAttrs = ( }, # 0x0086 - int8u: 0, 111[Sport,Pet] (Q) - related to Tracking FocusMode? # 0x0087 - int8u: 0 (Q) + 0x0087 => { #PH + Name => 'ShutterType', + Writable => 'int8u', + PrintConv => { + 0 => 'Normal', # ('Mechanical' if the camera has a mechanical shutter) + 1 => 'Electronic', # (KP) + }, + }, 0x0088 => { #PH Name => 'NeutralDensityFilter', Writable => 'int8u', - PrintConv => { 0 => 'Off', 1 => 'On' }, + Count => -1, + PrintConv => { + 0 => 'Off', + 1 => 'On', + '0 2' => 'Off (0 2)', #PH (NC, GR III) + '1 2' => 'On (1 2)', #PH (NC, GR III) + }, }, 0x008b => { #PH (LS465) Name => 'ISO', @@ -2547,8 +2602,9 @@ my %binaryDataAttrs = ( }, }, }, - 0x0095 => { #31 + 0x0095 => [{ #31 Name => 'SkinToneCorrection', + Condition => '$count == 2', Writable => 'int8s', Count => 2, PrintConv => { @@ -2556,7 +2612,15 @@ my %binaryDataAttrs = ( '1 1' => 'On (type 1)', '1 2' => 'On (type 2)', }, - }, + },{ + Name => 'SkinToneCorrection', + Condition => '$count == 3', + Writable => 'int8s', + Count => 3, + PrintConv => { + '0 0 0' => 'Off', + }, + }], 0x0096 => { #31 Name => 'ClarityControl', Writable => 'int8s', @@ -2660,7 +2724,7 @@ my %binaryDataAttrs = ( SubDirectory => { TagTable => 'Image::ExifTool::Pentax::LensInfo' }, },{ Name => 'LensInfo', - Condition => '$count != 90 and $count != 91 and $count != 80 and $count != 128', + Condition => '$count != 90 and $count != 91 and $count != 80 and $count != 128 and $count != 168', SubDirectory => { TagTable => 'Image::ExifTool::Pentax::LensInfo2' }, },{ Name => 'LensInfo', # 645D @@ -2675,6 +2739,7 @@ my %binaryDataAttrs = ( Condition => '$count == 80 or $count == 128', SubDirectory => { TagTable => 'Image::ExifTool::Pentax::LensInfo5' }, } + # ($count == 168 - Ricoh GR III) ], 0x0208 => [ #PH { @@ -2791,8 +2856,18 @@ my %binaryDataAttrs = ( # High: 0000000238c0e960fde0f9203140f5a0fce0f1e031403f00e600fb00f7803760f120fc60ef403460 # Very High:000000023d20e520fdc0f7203420f4c0fb60ee6036404400e120fae0f5403aa0f020fac0eb403a00 }, - # 0x021c - undef[18] (K-5) - # 0x021d - undef[18] (K-5) + 0x021c => { #IB + Name => 'ColorMatrixA2', + Format => 'int16s', + Writable => 'undef', + Count => 9, + }, + 0x021d => { #IB + Name => 'ColorMatrixB2', + Format => 'int16s', + Writable => 'undef', + Count => 9, + }, # 0x021e - undef[8] (K-5, Q) 0x021f => { #JD Name => 'AFInfo', @@ -2809,7 +2884,7 @@ my %binaryDataAttrs = ( Name => 'HuffmanTable', Flags => [ 'Unknown', 'Binary' ], Writable => 0, - Notes => 'found in K10D, K20D and K2000D PEF images', + Notes => 'found in K10D, K20D and K2000 PEF images', }, 0x0221 => { #28 Name => 'KelvinWB', @@ -2844,13 +2919,20 @@ my %binaryDataAttrs = ( Writable => 'string', Notes => 'left blank by some cameras', }, - 0x022a => { #PH (K-5) + 0x022a => [{ #PH (RICOH models (GR III)) + Name => 'FilterInfo', + Condition => '$$self{Make} =~ /^RICOH/', + SubDirectory => { + TagTable => 'Image::ExifTool::Pentax::FilterInfo', + ByteOrder => 'LittleEndian', + }, + },{ #PH (K-5) Name => 'FilterInfo', SubDirectory => { TagTable => 'Image::ExifTool::Pentax::FilterInfo', ByteOrder => 'BigEndian', }, - }, + }], 0x022b => { #PH (K-5) Name => 'LevelInfo', SubDirectory => { TagTable => 'Image::ExifTool::Pentax::LevelInfo' }, @@ -3313,7 +3395,7 @@ my %binaryDataAttrs = ( 8 => { Name => 'ExposureBracketStepSize', # This is set even when Exposure Bracket is Off (and the K10D - # displays Ò---Ó as the step size when you press the EB button) - DaveN + # displays "---" as the step size when you press the EB button) - DaveN # because the last value is remembered and if you turn Exposure Bracket # on the step size goes back to what it was before. PrintConv => { @@ -4269,15 +4351,15 @@ my %binaryDataAttrs = ( Name => 'LC3', %lensCode, }, - 5 => { # LC4 = abberation correction, near distance data + 5 => { # LC4 = aberration correction, near distance data Name => 'LC4', %lensCode, }, - 6 => { # LC5 = light color abberation correction data + 6 => { # LC5 = light color aberration correction data Name => 'LC5', %lensCode, }, - 7 => { # LC6 = open abberation data + 7 => { # LC6 = open aberration data Name => 'LC6', %lensCode, }, @@ -4556,6 +4638,7 @@ my %binaryDataAttrs = ( # *istDS and K100D, but I'm not sure what this means - PH # I've also seen: 0x42 (K2000), 0xf2 (K-7,K-r,K-5), 0x12,0x22 (K-x) - PH PrintConv => { + 1 => 'Camera Battery', #PH (NC, GR III) 2 => 'Body Battery', 3 => 'Grip Battery', 4 => 'External Power Supply', #PH @@ -5251,7 +5334,7 @@ my %binaryDataAttrs = ( NOTES => q{ The parameters associated with each type of digital filter are unique, and these settings are also extracted with the DigitalFilter tag. Information - is not extracted for filters that are "Off" unless the Unknown option is + is not extracted for filters that are "Off" unless the L<Unknown|../ExifTool.html#Unknown> option is used. }, 0 => { @@ -5298,6 +5381,7 @@ my %binaryDataAttrs = ( Mask => 0x0f, PrintHex => 0, PrintConv => { + 0 => 'n/a', #PH (NC, GR III) 1 => 'Horizontal (normal)', 2 => 'Rotate 180', 3 => 'Rotate 90 CW', @@ -6231,7 +6315,7 @@ tags, and everyone who helped contribute to the LensType values. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PhaseOne.pm b/src/Image-ExifTool/lib/Image/ExifTool/PhaseOne.pm index 8b1cd8ad..23c2eb8c 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/PhaseOne.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/PhaseOne.pm @@ -15,7 +15,7 @@ use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; -$VERSION = '1.05'; +$VERSION = '1.07'; sub WritePhaseOne($$$); sub ProcessPhaseOne($$$); @@ -73,10 +73,11 @@ my @formatName = ( undef, 'string', 'int16s', undef, 'int32s' ); PrintConv => { #PH 1 => 'RAW 1', #? (encrypted) 2 => 'RAW 2', #? (encrypted) - 3 => 'IIQ L', + 3 => 'IIQ L', # (now "L14", ref IB) # 4? 5 => 'IIQ S', - 6 => 'IIQ Sv2', + 6 => 'IIQ Sv2', # (now "S14" for "IIQ 14 Smart" and "IIQ 14 Sensor+", ref IB) + 8 => 'IIQ L16', #IB ("IIQ 16 Extended" and "IIQ 16 Large") }, }, 0x010f => { @@ -260,6 +261,7 @@ my @formatName = ( undef, 'string', 'int16s', undef, 'int32s' ); CHECK_PROC => \&Image::ExifTool::Exif::CheckExif, GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, TAG_PREFIX => 'SensorCalibration', + WRITE_GROUP => 'PhaseOne', VARS => { ENTRY_SIZE => 12 }, # (entries do not contain a format field) 0x0400 => { Name => 'SensorDefects', @@ -435,7 +437,7 @@ sub WritePhaseOne($$$) # nothing to do if we aren't changing any PhaseOne tags my $newTags = $et->GetNewTagInfoHash($tagTablePtr); - return undef unless %$newTags or $$et{DropTags}; + return undef unless %$newTags or $$et{DropTags} or $$et{EDIT_DIRS}{PhaseOne}; my $dataPt = $$dirInfo{DataPt}; my $dataPos = $$dirInfo{DataPos} || 0; @@ -710,7 +712,7 @@ One maker notes. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PhotoCD.pm b/src/Image-ExifTool/lib/Image/ExifTool/PhotoCD.pm index 6a2d9916..441a328a 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/PhotoCD.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/PhotoCD.pm @@ -13,9 +13,8 @@ package Image::ExifTool::PhotoCD; use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -use Image::ExifTool::Exif; # (for Composite:ImageSize) -$VERSION = '1.02'; +$VERSION = '1.03'; sub ProcessExtData($$$); @@ -485,7 +484,7 @@ information from Kodak Photo CD Image Pac (PCD) files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PhotoMechanic.pm b/src/Image-ExifTool/lib/Image/ExifTool/PhotoMechanic.pm index 83de14b5..34dc6107 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/PhotoMechanic.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/PhotoMechanic.pm @@ -15,7 +15,7 @@ use Image::ExifTool::Exif; use Image::ExifTool::IPTC; use Image::ExifTool::XMP; -$VERSION = '1.05'; +$VERSION = '1.06'; sub ProcessPhotoMechanic($$); @@ -200,7 +200,7 @@ sub ProcessPhotoMechanic($$) if (defined $newBuff) { $newPt = \$newBuff; # write out the modified trailer my $pad = 0x800 - length($newBuff); - if ($pad > 0 and not $et->Options('Compact')) { + if ($pad > 0 and not $$et{OPTIONS}{Compact}{NoPadding}) { # pad out to 2kB like PhotoMechanic does $newBuff .= "\0" x $pad; } @@ -236,7 +236,7 @@ write information written by the Camera Bits Photo Mechanic software. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Photoshop.pm b/src/Image-ExifTool/lib/Image/ExifTool/Photoshop.pm index 5d93c4fb..8efac9d8 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Photoshop.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Photoshop.pm @@ -28,7 +28,7 @@ use strict; use vars qw($VERSION $AUTOLOAD $iptcDigestInfo); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.62'; +$VERSION = '1.65'; sub ProcessPhotoshop($$$); sub WritePhotoshop($$$); @@ -248,11 +248,12 @@ my %unicodeString = ( Protected => 1, Notes => q{ this tag indicates provides a way for XMP-aware applications to indicate - that the XMP is synchronized with the IPTC. When writing, special values of - "new" and "old" represent the digests of the IPTC from the edited and - original files respectively, and are undefined if the IPTC does not exist in - the respective file. Set this to "new" as an indication that the XMP is - synchronized with the IPTC + that the XMP is synchronized with the IPTC. The MWG recommendation is to + ignore the XMP if IPTCDigest exists and doesn't match the CurrentIPTCDigest. + When writing, special values of "new" and "old" represent the digests of the + IPTC from the edited and original files respectively, and are undefined if + the IPTC does not exist in the respective file. Set this to "new" as an + indication that the XMP is synchronized with the IPTC }, # also note the 'new' feature requires that the IPTC comes before this tag is written ValueConv => 'unpack("H*", $val)', @@ -545,7 +546,7 @@ my %unicodeString = ( PrintConv => 'sprintf("%d%%",$val)', }, # tags extracted from additional layer information (tag ID's are real) - # - must be able to accomodate a blank entry to preserve the list ordering + # - must be able to accommodate a blank entry to preserve the list ordering luni => { Name => 'LayerUnicodeNames', List => 1, @@ -675,9 +676,18 @@ sub ProcessLayersAndMask($$$) # check for Lr16 block if layers length is 0 (ref https://forums.adobe.com/thread/1540914) if ($len == 0 and $num == 0) { $raf->Read($data,10) == 10 or return 0; - if ($data =~/^..8BIMLr16/s) { + if ($data =~ /^..8BIMLr16/s) { $raf->Read($data, $psiz+2) == $psiz+2 or return 0; $len = $psb ? Get64u(\$data, 0) : Get32u(\$data, 0); + } elsif ($data =~ /^..8BIMMt16/s) { # (have seen Mt16 before Lr16, ref PH) + $raf->Read($data, $psiz) == $psiz or return 0; + $raf->Read($data, 8) == 8 or return 0; + if ($data eq '8BIMLr16') { + $raf->Read($data, $psiz+2) == $psiz+2 or return 0; + $len = $psb ? Get64u(\$data, 0) : Get32u(\$data, 0); + } else { + $raf->Seek(-18-$psiz, 1) or return 0; + } } else { $raf->Seek(-10, 1) or return 0; } @@ -819,7 +829,7 @@ sub ProcessDocumentData($$$) my $raf = $$dirInfo{RAF}; my $dirLen = $$dirInfo{DirLen}; my $pos = 36; # length of header - my $buff; + my ($buff, $n, $err); $et->VerboseDir('Photoshop Document Data', undef, $dirLen); unless ($raf) { @@ -838,27 +848,26 @@ sub ProcessDocumentData($$$) } my $psb = ($1 eq 'V0002'); my %dinfo = ( DataPt => \$buff ); - my ($n, $setOrder); $$et{IsPSB} = $psb; # set PSB flag (needed when handling Layers directory) while ($pos + 12 <= $dirLen) { - $raf->Read($buff, 8) == 8 or last; + $raf->Read($buff, 8) == 8 or $err = 'Error reading document data', last; # set byte order according to byte order of first signature SetByteOrder($buff =~ /^(8BIM|8B64)/ ? 'MM' : 'II') if $pos == 36; $buff = pack 'N*', unpack 'V*', $buff if GetByteOrder() eq 'II'; my $sig = substr($buff, 0, 4); - last unless $sig eq '8BIM' or $sig eq '8B64'; # verify signature + $sig eq '8BIM' or $sig eq '8B64' or $err = 'Bad photoshop resource', last; # verify signature my $tag = substr($buff, 4, 4); if ($psb and $tag =~ /^(LMsk|Lr16|Lr32|Layr|Mt16|Mt32|Mtrn|Alph|FMsk|lnk2|FEid|FXid|PxSD)$/) { - last if $pos + 16 > $dirLen; - $raf->Read($buff, 8) == 8 or last; + $pos + 16 > $dirLen and $err = 'Short PSB resource', last; + $raf->Read($buff, 8) == 8 or $err = 'Error reading PSB resource', last; $n = Get64u(\$buff, 0); $pos += 4; } else { - $raf->Read($buff, 4) == 4 or last; + $raf->Read($buff, 4) == 4 or $err = 'Error reading PSD resource', last; $n = Get32u(\$buff, 0); } $pos += 12; - last if $pos + $n > $dirLen; + $pos + $n > $dirLen and $err = 'Truncated photoshop resource', last; my $pad = (4 - ($n & 3)) & 3; # number of padding bytes my $tagInfo = $$tagTablePtr{$tag}; if ($tagInfo or $verbose) { @@ -866,20 +875,21 @@ sub ProcessDocumentData($$$) my $fpos = $raf->Tell() + $n + $pad; my $subTable = GetTagTable($$tagInfo{SubDirectory}{TagTable}); $et->ProcessDirectory({ RAF => $raf, DirLen => $n }, $subTable); - $raf->Seek($fpos, 0) or last; + $raf->Seek($fpos, 0) or $err = 'Seek error', last; } else { $dinfo{DataPos} = $raf->Tell(); $dinfo{Start} = 0; $dinfo{Size} = $n; - $raf->Read($buff, $n) == $n or last; + $raf->Read($buff, $n) == $n or $err = 'Error reading photoshop resource', last; $et->HandleTag($tagTablePtr, $tag, undef, %dinfo); - $raf->Seek($pad, 1) or last; + $raf->Seek($pad, 1) or $err = 'Seek error', last; } } else { - $raf->Seek($n + $pad, 1) or last; + $raf->Seek($n + $pad, 1) or $err = 'Seek error', last; } $pos += $n + $pad; # step to start of next structure } + $err and $et->Warn($err); return 1; } @@ -911,6 +921,9 @@ sub ProcessPhotoshop($$$) } } } + if ($$et{FILE_TYPE} eq 'JPEG' and $$dirInfo{Parent} ne 'APP13') { + $$et{LOW_PRIORITY_DIR}{'*'} = 1; # lower priority of all these tags + } SetByteOrder('MM'); # Photoshop is always big-endian $verbose and $et->VerboseDir('Photoshop', 0, $$dirInfo{DirLen}); @@ -970,11 +983,19 @@ sub ProcessPhotoshop($$$) DataPos => $$dirInfo{DataPos}, Size => $size, Start => $pos, + Base => $$dirInfo{Base}, Parent => $$dirInfo{DirName}, ); $size += 1 if $size & 0x01; # size is padded to an even # bytes $pos += $size; } + # warn about incorrect IPTCDigest + if ($$et{VALUE}{IPTCDigest} and $$et{VALUE}{CurrentIPTCDigest} and + $$et{VALUE}{IPTCDigest} ne $$et{VALUE}{CurrentIPTCDigest}) + { + $et->WarnOnce('IPTCDigest is not current. XMP may be out of sync'); + } + delete $$et{LOW_PRIORITY_DIR}{'*'}; return $success; } @@ -1123,7 +1144,7 @@ be preserved when copying Photoshop information via user-defined tags. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PostScript.pm b/src/Image-ExifTool/lib/Image/ExifTool/PostScript.pm index 65481b8f..47ce58ec 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/PostScript.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/PostScript.pm @@ -16,7 +16,7 @@ use strict; use vars qw($VERSION $AUTOLOAD); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.43'; +$VERSION = '1.44'; sub WritePS($$); sub ProcessPS($$;$); @@ -89,12 +89,12 @@ sub ProcessPS($$;$); SubDirectory => { TagTable => 'Image::ExifTool::PostScript::Main', }, - Notes => 'extracted with ExtractEmbedded option', + Notes => 'extracted with L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> option', }, EmbeddedFileName => { Notes => q{ not a real tag ID, but the file name from a BeginDocument statement. - Extracted with document metadata when ExtractEmbedded option is used + Extracted with document metadata when L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> option is used }, }, # AI metadata (most with a single leading '%') @@ -208,9 +208,9 @@ sub GetInputRecordSeparator($) $a = pos($data), pos($data) = 0 if $data =~ /\x0a/g; $d = pos($data) if $data =~ /\x0d/g; my $diff = $a - $d; - if ($diff eq 1) { + if ($diff == 1) { $sep = "\x0d\x0a"; - } elsif ($diff eq -1) { + } elsif ($diff == -1) { $sep = "\x0a\x0d"; } elsif ($diff > 0) { $sep = "\x0d"; @@ -221,6 +221,97 @@ sub GetInputRecordSeparator($) return $sep; } +#------------------------------------------------------------------------------ +# Split into lines ending in any CR, LF or CR+LF combination +# (this is annoying, and could be avoided if EPS files didn't mix linefeeds!) +# Inputs: 0) data pointer, 1) reference to lines array +# Notes: Fills @$lines with lines from splitting $$dataPt +sub SplitLine($$) +{ + my ($dataPt, $lines) = @_; + for (;;) { + my $endl; + # find the position of the first LF (\x0a) + $endl = pos($$dataPt), pos($$dataPt) = 0 if $$dataPt =~ /\x0a/g; + if ($$dataPt =~ /\x0d/g) { # find the first CR (\x0d) + if (defined $endl) { + # (remember, CR+LF is a DOS newline...) + $endl = pos($$dataPt) if pos($$dataPt) < $endl - 1; + } else { + $endl = pos($$dataPt); + } + } elsif (not defined $endl) { + push @$lines, $$dataPt; + last; + } + if (length $$dataPt == $endl) { + push @$lines, $$dataPt; + last; + } else { + # continue to split into separate lines + push @$lines, substr($$dataPt, 0, $endl); + $$dataPt = substr($$dataPt, $endl); + } + } +} + +#------------------------------------------------------------------------------ +# check to be sure we haven't read past end of PS data in DOS-style file +# Inputs: 0) RAF ref (with PSEnd member), 1) data ref +# - modifies data and sets RAF to EOF if end of PS is reached +sub CheckPSEnd($$) +{ + my ($raf, $dataPt) = @_; + my $pos = $raf->Tell(); + if ($pos >= $$raf{PSEnd}) { + $raf->Seek(0, 2); # seek to end of file so we can't read any more + $$dataPt = substr($$dataPt, 0, length($$dataPt) - $pos + $$raf{PSEnd}) if $pos > $$raf{PSEnd}; + } +} + +#------------------------------------------------------------------------------ +# Read next line from EPS file +# Inputs: 0) RAF ref (with PSEnd member if Postscript ends before end of file) +# 1) array of lines from file +# Returns: true on success +sub GetNextLine($$) +{ + my ($raf, $lines) = @_; + my ($data, $changedNL); + my $altnl = ($/ eq "\x0d") ? "\x0a" : "\x0d"; + for (;;) { + $raf->ReadLine($data) or last; + $$raf{PSEnd} and CheckPSEnd($raf, \$data); + # split line if it contains other newline sequences + if ($data =~ /$altnl/) { + if (length($data) > 500000 and IsPC()) { + # patch for Windows memory problem + unless ($changedNL) { + $changedNL = $/; + $/ = $altnl; + $altnl = $changedNL; + $raf->Seek(-length($data), 1); + next; + } + } else { + # split into separate lines + # push @$lines, split /$altnl/, $data, -1; + # if (@$lines == 2 and $$lines[1] eq $/) { + # # handle case of DOS newline data inside file using Unix newlines + # $$lines[0] .= pop @$lines; + # } + # split into separate lines if necessary + SplitLine(\$data, $lines); + } + } else { + push @$lines, $data; + } + $/ = $changedNL if $changedNL; + return 1; + } + return 0; +} + #------------------------------------------------------------------------------ # Decode comment from PostScript file # Inputs: 0) comment string, 1) RAF ref, 2) reference to lines array @@ -233,22 +324,7 @@ sub DecodeComment($$$;$) $val =~ s/\x0d*\x0a*$//; # remove trailing CR, LF or CR/LF # check for continuation comments for (;;) { - unless (@$lines) { - my $buff; - $raf->ReadLine($buff) or last; - my $altnl = $/ eq "\x0d" ? "\x0a" : "\x0d"; - if ($buff =~ /$altnl/) { - chomp $buff if $/ eq "\x0d\x0a"; # remove DOS newline before splitting - # split into separate lines - @$lines = split /$altnl/, $buff, -1; - # handle case of DOS newline data inside file using Unix newlines - @$lines = ( $$lines[0] . $$lines[1] ) if @$lines == 2 and $$lines[1] eq $/; - # add back trailing DOS newline if necessary - @$lines ? @$lines[-1] .= $/ : push @$lines, $/ if $/ eq "\x0d\x0a"; - } else { - push @$lines, $buff; - } - } + @$lines or GetNextLine($raf, $lines) or last; last unless $$lines[0] =~ /^%%\+/; # is the next line a continuation? $$dataPt .= $$lines[0] if $dataPt; # add to data if necessary $$lines[0] =~ s/\x0d*\x0a*$//; # remove trailing CR, LF or CR/LF @@ -371,11 +447,13 @@ sub ProcessPS($$;$) # - save DOS header then seek ahead and check PS header $raf->Read($dos, 26) == 26 or return 0; SetByteOrder('II'); - unless ($raf->Seek(Get32u(\$dos, 0), 0) and + my $psStart = Get32u(\$dos, 0); + unless ($raf->Seek($psStart, 0) and $raf->Read($data, 4) == 4 and $data eq '%!PS') { return PSErr($et, 'invalid header'); } + $$raf{PSEnd} = $psStart + Get32u(\$dos, 4); # set end of PostScript data in RAF } else { # check for PostScript font file (PFA or PFB) my $d2; @@ -487,7 +565,7 @@ sub ProcessPS($$;$) if ($mode) { if (not $endToken) { $buff .= $data; - next unless $data =~ m{<\?xpacket end=.(w|r).\?>($/|$)}; + next unless $data =~ m{<\?xpacket end=.(w|r).\?>(\n|\r|$)}; } elsif ($data !~ /^$endToken/i) { if ($mode eq 'XMP') { $buff .= $data; @@ -565,7 +643,7 @@ sub ProcessPS($$;$) $buff = $data; undef $endToken; # no end token (just look for xpacket end) # XMP could be contained in a single line (if newlines are different) - next unless $data =~ m{<\?xpacket end=.(w|r).\?>($/|$)}; + next unless $data =~ m{<\?xpacket end=.(w|r).\?>(\n|\r|$)}; } elsif ($data =~ /^%%?(\w+): ?(.*)/s and $$tagTablePtr{$1}) { my ($tag, $val) = ($1, $2); # only allow 'ImageData' and AI tags to have single leading '%' @@ -699,7 +777,7 @@ This code reads meta information from EPS (Encapsulated PostScript), PS =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/PrintIM.pm b/src/Image-ExifTool/lib/Image/ExifTool/PrintIM.pm index 79cf88cb..e44d47da 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/PrintIM.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/PrintIM.pm @@ -112,7 +112,7 @@ Print Image Matching meta information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Qualcomm.pm b/src/Image-ExifTool/lib/Image/ExifTool/Qualcomm.pm index 12438dc6..ed64e157 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Qualcomm.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Qualcomm.pm @@ -1331,7 +1331,7 @@ information from the APP7 Qualcomm segment in JPEG images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/QuickTime.pm b/src/Image-ExifTool/lib/Image/ExifTool/QuickTime.pm index 4573a72d..78e6d62f 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/QuickTime.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/QuickTime.pm @@ -32,17 +32,22 @@ # 20) https://developer.apple.com/legacy/library/documentation/quicktime/reference/QT7-1_Update_Reference/QT7-1_Update_Reference.pdf # 21) Francois Bonzon private communication # 22) https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/Metadata/Metadata.html +# 23) http://atomicparsley.sourceforge.net/mpeg-4files.html +# 24) https://github.com/sergiomb2/libmp4v2/wiki/iTunesMetadata +# 25) https://cconcolato.github.io/mp4ra/atoms.html +# 26) https://github.com/SamsungVR/android_upload_sdk/blob/master/SDKLib/src/main/java/com/samsung/msca/samsungvr/sdk/UserVideo.java +# 27) https://exiftool.org/forum/index.php?topic=11517.0 #------------------------------------------------------------------------------ package Image::ExifTool::QuickTime; use strict; -use vars qw($VERSION $AUTOLOAD); +use vars qw($VERSION $AUTOLOAD %stringEncoding); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; use Image::ExifTool::GPS; -$VERSION = '2.20'; +$VERSION = '2.76'; sub ProcessMOV($$;$); sub ProcessKeys($$$); @@ -52,19 +57,35 @@ sub ProcessEncodingParams($$$); sub ProcessSampleDesc($$$); sub ProcessHybrid($$$); sub ProcessRights($$$); -sub Process_mebx($$$); # (in QuickTimeStream.pl) +# ++vvvvvvvvvvvv++ (in QuickTimeStream.pl) +sub Process_mebx($$$); +sub Process_3gf($$$); +sub Process_gps0($$$); +sub Process_gsen($$$); +sub ProcessRIFFTrailer($$$); +sub ProcessTTAD($$$); +sub ProcessNMEA($$$); +sub ProcessGPSLog($$$); +sub SaveMetaKeys($$$); +# ++^^^^^^^^^^^^++ sub ParseItemLocation($$); +sub ParseContentDescribes($$); sub ParseItemInfoEntry($$); sub ParseItemPropAssoc($$); sub FixWrongFormat($); sub GetMatrixStructure($$); sub ConvertISO6709($); +sub ConvInvISO6709($); sub ConvertChapterList($); sub PrintChapter($); sub PrintGPSCoordinates($); -sub UnpackLang($); +sub PrintInvGPSCoordinates($); +sub UnpackLang($;$); +sub WriteKeys($$$); sub WriteQuickTime($$$); sub WriteMOV($$); +sub GetLangInfo($$); +sub CheckQTValue($$$); # MIME types for all entries in the ftypLookup with file extensions # (defaults to 'video/mp4' if not found in this lookup) @@ -86,7 +107,10 @@ my %mimeLookup = ( MQV => 'video/quicktime', HEIC => 'image/heic', HEVC => 'image/heic-sequence', + HEICS=> 'image/heic-sequence', HEIF => 'image/heif', + HEIFS=> 'image/heif-sequence', + AVIF => 'image/avif', #PH (NC) CRX => 'video/x-canon-crx', # (will get overridden) ); @@ -137,8 +161,15 @@ my %ftypLookup = ( 'F4P ' => 'Protected Video for Adobe Flash Player 9+ (.F4P)', # video/mp4 'F4V ' => 'Video for Adobe Flash Player 9+ (.F4V)', # video/mp4 'isc2' => 'ISMACryp 2.0 Encrypted File', # ?/enc-isoff-generic - 'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]', # video/mp4 - 'isom' => 'MP4 Base Media v1 [IS0 14496-12:2003]', # video/mp4 + 'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]', # video/mp4 (or audio) + 'iso3' => 'MP4 Base Media v3', # video/mp4 (or audio) + 'iso4' => 'MP4 Base Media v4', # video/mp4 (or audio) + 'iso5' => 'MP4 Base Media v5', # video/mp4 (or audio) + 'iso6' => 'MP4 Base Media v6', # video/mp4 (or audio) + 'iso7' => 'MP4 Base Media v7', # video/mp4 (or audio) + 'iso8' => 'MP4 Base Media v8', # video/mp4 (or audio) + 'iso9' => 'MP4 Base Media v9', # video/mp4 (or audio) + 'isom' => 'MP4 Base Media v1 [IS0 14496-12:2003]', # video/mp4 (or audio) 'JP2 ' => 'JPEG 2000 Image (.JP2) [ISO 15444-1 ?]', # image/jp2 'JP20' => 'Unknown, from GPAC samples (prob non-existent)', 'jpm ' => 'JPEG 2000 Compound Image (.JPM) [ISO 15444-6]', # image/jpm @@ -186,27 +217,46 @@ my %ftypLookup = ( 'hevc' => 'High Efficiency Image Format HEVC sequence (.HEICS)', # image/heic-sequence 'mif1' => 'High Efficiency Image Format still image (.HEIF)', # image/heif 'msf1' => 'High Efficiency Image Format sequence (.HEIFS)', # image/heif-sequence + 'heix' => 'High Efficiency Image Format still image (.HEIF)', # image/heif (ref PH, Canon 1DXmkIII) + 'avif' => 'AV1 Image File Format (.AVIF)', # image/avif 'crx ' => 'Canon Raw (.CRX)', #PH (CR3 or CRM; use Canon CompressorVersion to decide) ); -# information for time/date-based tags (time zero is Jan 1, 1904) +# information for int32u date/time tags (time zero is Jan 1, 1904) my %timeInfo = ( Notes => 'converted from UTC to local time if the QuickTimeUTC option is set', - # It is not uncommon for brain-dead software to use the wrong time zero, - # so assume a time zero of Jan 1, 1970 if the date is before this - RawConv => q{ - my $offset = (66 * 365 + 17) * 24 * 3600; - return $val - $offset if $val >= $offset or $$self{OPTIONS}{QuickTimeUTC}; - $self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1) if $val; - return $val; - }, Shift => 'Time', Writable => 1, Permanent => 1, DelValue => 0, + # It is not uncommon for brain-dead software to use the wrong time zero, it should be + # Jan 1, 1904, so assume a time zero of Jan 1, 1970 if the date is before this # Note: This value will be in UTC if generated by a system that is aware of the time zone - ValueConv => 'ConvertUnixTime($val, $self->Options("QuickTimeUTC"))', - ValueConvInv => 'GetUnixTime($val, $self->Options("QuickTimeUTC")) + (66 * 365 + 17) * 24 * 3600', + # (also note: this code is duplicated for the CreateDate tag) + RawConv => q{ + my $offset = (66 * 365 + 17) * 24 * 3600; + return $val - $offset if $val >= $offset or $$self{OPTIONS}{QuickTimeUTC}; + if ($val and not $$self{IsWriting}) { + $self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1); + } + return $val; + }, + RawConvInv => q{ + if ($$self{FileType} eq 'CR3' and not $self->Options('QuickTimeUTC')) { + # convert to UTC + my $offset = (66 * 365 + 17) * 24 * 3600; + $val = ConvertUnixTime($val - $offset); + $val = GetUnixTime($val, 1) + $offset; + } + return $val; + }, + # (all CR3 files store UTC times - PH) + ValueConv => 'ConvertUnixTime($val, $self->Options("QuickTimeUTC") || $$self{FileType} eq "CR3")', + ValueConvInv => q{ + $val = GetUnixTime($val, $self->Options("QuickTimeUTC")); + return undef unless defined $val; + return $val + (66 * 365 + 17) * 24 * 3600; + }, PrintConv => '$self->ConvertDateTime($val)', PrintConvInv => '$self->InverseDateTime($val)', # (can't put Groups here because they aren't constant!) @@ -221,17 +271,15 @@ my %unknownInfo = ( Unknown => 1, ValueConv => '$val =~ /^([\x20-\x7e]*)\0*$/ ? $1 : \$val', ); + +# multi-language text with 6-byte header +my %langText = ( IText => 6 ); + # parsing for most of the 3gp udta language text boxes -my %langText = ( - RawConv => sub { - my ($val, $self) = @_; - return '<err>' unless length $val >= 6; - my $lang = UnpackLang(Get16u(\$val, 4)); - $lang = $lang ? "($lang) " : ''; - $val = substr($val, 6); # isolate string - $val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/; - return $lang . $val; - }, +my %langText3gp = ( + Notes => 'used in 3gp videos', + Avoid => 1, + IText => 6, ); # 4-character Vendor ID codes (ref PH) @@ -258,7 +306,7 @@ my %vendorID = ( ); # QuickTime data atom encodings for string types (ref 12) -my %stringEncoding = ( +%stringEncoding = ( 1 => 'UTF8', 2 => 'UTF16', 3 => 'ShiftJIS', @@ -372,21 +420,39 @@ my %channelLabel = ( # properties which don't get inherited from the parent my %dontInherit = ( ispe => 1, # size of parent may be different + hvcC => 1, # (likely redundant) ); +# tags that may be duplicated and directories that may contain duplicate tags +# (used only to avoid warnings when Validate-ing) +my %dupTagOK = ( mdat => 1, trak => 1, free => 1, infe => 1, sgpd => 1, dimg => 1, CCDT => 1, + sbgp => 1, csgm => 1, uuid => 1, cdsc => 1, maxr => 1, '----' => 1 ); +my %dupDirOK = ( ipco => 1, '----' => 1 ); + # the usual atoms required to decode timed metadata with the ExtractEmbedded option -my %eeStd = ( stco => 1, co64 => 1, stsz => 1, stz2 => 1, stsc => 1, stts => 1 ); +my %eeStd = ( stco => 'stbl', co64 => 'stbl', stsz => 'stbl', stz2 => 'stbl', + stsc => 'stbl', stts => 'stbl' ); -# boxes for the various handler types that we want to save when ExtractEmbedded is enabled +# boxes and their containers for the various handler types that we want to save +# when the ExtractEmbedded is enabled (currently only the 'gps ' container name is +# used, but others have been checked against all available sample files and may be +# useful in the future if the names are used for different boxes on other locations) my %eeBox = ( # (note: vide is only processed if specific atoms exist in the VideoSampleDesc) - vide => { %eeStd, JPEG => 1 }, # (add avcC to parse H264 stream) + vide => { %eeStd, + JPEG => 'stsd', + }, text => { %eeStd }, meta => { %eeStd }, sbtl => { %eeStd }, data => { %eeStd }, camm => { %eeStd }, # (Insta360) - '' => { 'gps ' => 1 }, # (no handler -- top level box) + ctbx => { %eeStd }, # (GM cars) + '' => { 'gps ' => 'moov', 'GPS ' => 'main' }, # (no handler -- in top level 'moov' box, and main) +); +# boxes to save when ExtractEmbedded is set to 2 or higher +my %eeBox2 = ( + vide => { avcC => 'stsd' }, # (parses H264 video stream) ); # QuickTime atoms @@ -394,31 +460,6 @@ my %eeBox = ( PROCESS_PROC => \&ProcessMOV, WRITE_PROC => \&WriteQuickTime, # (only needs to be defined for directories to process when writing) GROUPS => { 2 => 'Video' }, - NOTES => q{ - The QuickTime format is used for many different types of audio, video and - image files (most notably, MOV/MP4 videos and HEIC/CR3 images). Exiftool - extracts standard meta information a variety of audio, video and image - parameters, as well as proprietary information written by many camera - models. Tags with a question mark after their name are not extracted unless - the Unknown option is set. - - ExifTool currently has a very limited ability to write metadata in - QuickTime-format videos. It can edit/create/delete any XMP tags, but may - only be used to edit certain date/time tags and the video orientation in - native QuickTime metadata. - - According to the specification, many QuickTime date/time tags should be - stored as UTC. Unfortunately, digital cameras often store local time values - instead (presumably because they don't know the time zone). For this - reason, by default ExifTool does not assume a time zone for these values. - However, if the QuickTimeUTC API option is set, then ExifTool will assume - these values are properly stored as UTC, and will convert them to local time - when extracting. - - See - L<http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html> - for the official specification. - }, meta => { # 'meta' is found here in my Sony ILCE-7S MP4 sample - PH Name => 'Meta', SubDirectory => { @@ -426,12 +467,32 @@ my %eeBox = ( Start => 4, # skip 4-byte version number header }, }, + meco => { #ISO14496-12:2015 + Name => 'OtherMeta', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' }, + }, free => [ { Name => 'KodakFree', # (found in Kodak M5370 MP4 videos) Condition => '$$valPt =~ /^\0\0\0.Seri/s', SubDirectory => { TagTable => 'Image::ExifTool::Kodak::Free' }, + },{ + Name => 'Pittasoft', + # (Pittasoft Blackview dashcam MP4 videos) + Condition => '$$valPt =~ /^\0\0..(cprt|sttm|ptnm|ptrh|thum|gps |3gf )/s', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Pittasoft' }, + },{ + Name => 'ThumbnailImage', + # (DJI Zenmuse XT2 thermal camera) + Groups => { 2 => 'Preview' }, + Condition => '$$valPt =~ /^.{4}mdat\xff\xd8\xff/s', + RawConv => q{ + my $len = unpack('N', $val); + return undef if $len <= 8 or $len > length($val); + return substr($val, 8, $len-8); + }, + Binary => 1, },{ Unknown => 1, Binary => 1, @@ -449,6 +510,17 @@ my %eeBox = ( Condition => '$$valPt =~ /^\0.{3}(CNDB|CNCV|CNMN|CNFV|CNTH|CNDM)/s', SubDirectory => { TagTable => 'Image::ExifTool::Canon::Skip' }, }, + { + Name => 'PreviewImage', # (found in DuDuBell M1 dashcam MOV files) + Groups => { 2 => 'Preview' }, + Condition => '$$valPt =~ /^.{12}\xff\xd8\xff/', + Binary => 1, + RawConv => q{ + my $len = Get32u(\$val, 8); + return undef unless length($val) >= $len + 12; + return substr($val, 12, $len); + }, + }, { Name => 'Skip', Unknown => 1, Binary => 1 }, ], wide => { Unknown => 1, Binary => 1 }, @@ -481,21 +553,27 @@ my %eeBox = ( }, # mfra - movie fragment random access: contains tfra (track fragment random access), and # mfro (movie fragment random access offset) (ref 5) - mdat => { Name => 'MovieData', Unknown => 1, Binary => 1 }, + mdat => { Name => 'MediaData', Unknown => 1, Binary => 1 }, 'mdat-size' => { - Name => 'MovieDataSize', + Name => 'MediaDataSize', + RawConv => '$$self{MediaDataSize} = $val', Notes => q{ not a real tag ID, this tag represents the size of the 'mdat' data in bytes and is used in the AvgBitrate calculation }, }, - 'mdat-offset' => 'MovieDataOffset', + 'mdat-offset' => { + Name => 'MediaDataOffset', + RawConv => '$$self{MediaDataOffset} = $val', + }, junk => { Unknown => 1, Binary => 1 }, #8 uuid => [ { #9 (MP4 files) Name => 'XMP', # *** this is where ExifTool writes XMP in MP4 videos (as per XMP spec) *** Condition => '$$valPt=~/^\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac/', + WriteGroup => 'XMP', # (write main XMP tags here) + PreservePadding => 1, SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main', Start => 16, @@ -519,10 +597,43 @@ my %eeBox = ( }, # "\x98\x7f\xa3\xdf\x2a\x85\x43\xc0\x8f\x8f\xd9\x7c\x47\x1e\x8e\xea" - unknown data in Flip videos { #PH (Canon CR3) - Name => 'UUID-Preview', - Condition => '$$valPt=~/^\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16/', + Name => 'UUID-Canon2', + WriteLast => 1, # MUST come after mdat or DPP will drop mdat when writing! + Condition => '$$valPt=~/^\x21\x0f\x16\x87\x91\x49\x11\xe4\x81\x11\x00\x24\x21\x31\xfc\xe4/', + SubDirectory => { + TagTable => 'Image::ExifTool::Canon::uuid2', + Start => 16, + }, + }, + { # (ref https://github.com/JamesHeinrich/getID3/blob/master/getid3/module.audio-video.quicktime.php) + Name => 'SensorData', # sensor data for the 360Fly + Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/ and $$self{OPTIONS}{ExtractEmbedded}', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Tags360Fly' }, + }, + { + Name => 'SensorData', + Condition => '$$valPt=~/^\xef\xe1\x58\x9a\xbb\x77\x49\xef\x80\x95\x27\x75\x9e\xb1\xdc\x6f/', + Notes => 'raw 360Fly sensor data without ExtractEmbedded option', + RawConv => q{ + $self->WarnOnce('Use the ExtractEmbedded option to decode timed SensorData',3); + return \$val; + }, + }, + { #PH (Canon CR3) Name => 'PreviewImage', + Condition => '$$valPt=~/^\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16/', Groups => { 2 => 'Preview' }, + PreservePadding => 1, + # 0x00 - undef[16]: UUID + # 0x10 - int32u[2]: "0 1" (version and/or item count?) + # 0x18 - int32u: PRVW atom size + # 0x20 - int32u: 'PRVW' + # 0x30 - int32u: 0 + # 0x34 - int16u: 1 + # 0x36 - int16u: image width + # 0x38 - int16u: image height + # 0x3a - int16u: 1 + # 0x3c - int32u: preview length RawConv => '$val = substr($val, 0x30); $self->ValidateImage(\$val, $tag)', }, { #8 @@ -543,6 +654,11 @@ my %eeBox = ( Groups => { 2 => 'Preview' }, Binary => 1, }, + 'thm ' => { #PH (70mai A800) + Name => 'ThumbnailImage', + Groups => { 2 => 'Preview' }, + Binary => 1, + }, ardt => { #PH Name => 'ARDroneFile', ValueConv => 'length($val) > 4 ? substr($val,4) : $val', # remove length @@ -588,9 +704,58 @@ my %eeBox = ( udat => { #PH (GPS NMEA-format log written by Datakam Player software) Name => 'GPSLog', Binary => 1, # (actually ASCII, but very lengthy) + Notes => 'parsed to extract GPS separately when ExtractEmbedded is used', + RawConv => q{ + $val =~ s/\0+$//; # remove trailing nulls + if (length $val and $$self{OPTIONS}{ExtractEmbedded}) { + my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); + Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl); + } + return $val; + }, }, # meta - proprietary XML information written by some Flip cameras - PH # beam - 16 bytes found in an iPhone video + IDIT => { #PH (written by DuDuBell M1, VSYS M6L dashcams) + Name => 'DateTimeOriginal', + Description => 'Date/Time Original', + Groups => { 2 => 'Time' }, + Format => 'string', # (removes trailing "\0") + Shift => 'Time', + Writable => 1, + Permanent => 1, + DelValue => '0000-00-00T00:00:00+0000', + ValueConv => '$val=~tr/-/:/; $val', + ValueConvInv => '$val=~s/(\d+):(\d+):/$1-$2-/; $val', + PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) + }, + gps0 => { #PH (DuDuBell M1, VSYS M6L) + Name => 'GPSTrack', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::Stream', + ProcessProc => \&Process_gps0, + }, + }, + gsen => { #PH (DuDuBell M1, VSYS M6L) + Name => 'GSensor', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::Stream', + ProcessProc => \&Process_gsen, + }, + }, + # gpsa - seen hex "01 20 00 00" (DuDuBell M1, VSYS M6L) + # gsea - 20 bytes hex "05 00's..." (DuDuBell M1) "05 08 02 01 ..." (VSYS M6L) + 'GPS ' => { # GPS data written by 70mai dashcam (parsed in QuickTimeStream.pl) + Name => 'GPSDataList2', + Unknown => 1, + Binary => 1, + }, + sefd => { + Name => 'SamsungTrailer', + SubDirectory => { TagTable => 'Image::ExifTool::Samsung::Trailer' }, + }, + # 'samn'? - seen in Vantrue N2S sample video ); # MPEG-4 'ftyp' atom @@ -685,8 +850,8 @@ my %eeBox = ( # v216 => "Uncompressed Y'CbCr, 10, 12, 14, or 16-bit 4:2:2", # v410 => "Uncompressed Y'CbCr, 10-bit 4:4:4", # v210 => "Uncompressed Y'CbCr, 10-bit 4:2:2", +# hvc1 => 'HEVC', #PH # }, - # (HEVC-encoded videos have a CompressorID of 'hvc1') }, 10 => { Name => 'VendorID', @@ -736,7 +901,7 @@ my %eeBox = ( }, colr => { Name => 'ColorRepresentation', - ValueConv => 'join(" ", substr($val,0,4), unpack("x4n*",$val))', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ColorRep' }, }, pasp => { Name => 'PixelAspectRatio', @@ -766,9 +931,10 @@ my %eeBox = ( # mjqt - default quantization table for MJPEG # mjht - default Huffman table for MJPEG # csgm ? (seen in hevc video) - # CMP1 - 52 bytes (Canon CR3) - # JPEG - 4 bytes all 0 (Canon CR3) - # free - (Canon CR3) + CMP1 => { # Canon CR3 + Name => 'CMP1', + SubDirectory => { TagTable => 'Image::ExifTool::Canon::CMP1' }, + }, CDI1 => { # Canon CR3 Name => 'CDI1', SubDirectory => { @@ -776,6 +942,8 @@ my %eeBox = ( Start => 4, }, }, + # JPEG - 4 bytes all 0 (Canon CR3) + # free - (Canon CR3) # # spherical video v2 stuff (untested) # @@ -883,7 +1051,7 @@ my %eeBox = ( %Image::ExifTool::QuickTime::CleanAperture = ( PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, GROUPS => { 2 => 'Video' }, - FORMAT => 'rational64u', + FORMAT => 'rational64s', 0 => 'CleanApertureWidth', 1 => 'CleanApertureHeight', 2 => 'CleanApertureOffsetX', @@ -922,6 +1090,7 @@ my %eeBox = ( }, trak => { Name => 'Track', + CanCreate => 0, # don't create this atom SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Track' }, }, udta => { @@ -971,6 +1140,10 @@ my %eeBox = ( Unknown => 1, Binary => 1, }, + meco => { #ISO14496-12:2015 + Name => 'OtherMeta', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' }, + }, # prfl - Profile (ref 12) # clip - clipping --> contains crgn (clip region) (ref 12) # mvex - movie extends --> contains mehd (movie extends header), trex (track extends) (ref 14) @@ -982,11 +1155,26 @@ my %eeBox = ( PROCESS_PROC => \&ProcessMOV, WRITE_PROC => \&WriteQuickTime, GROUPS => { 2 => 'Video' }, - # mfhd - movie fragment header + mfhd => { + Name => 'MovieFragmentHeader', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MovieFragHdr' }, + }, traf => { Name => 'TrackFragment', SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TrackFragment' }, }, + meta => { #ISO14496-12:2015 + Name => 'Meta', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, + }, +); + +# (ref CFFMediaFormat-2_1.pdf) +%Image::ExifTool::QuickTime::MovieFragHdr = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Video' }, + FORMAT => 'int32u', + 1 => 'MovieFragmentSequence', ); # (ref CFFMediaFormat-2_1.pdf) @@ -994,6 +1182,10 @@ my %eeBox = ( PROCESS_PROC => \&ProcessMOV, WRITE_PROC => \&WriteQuickTime, GROUPS => { 2 => 'Video' }, + meta => { #ISO14496-12:2015 + Name => 'Meta', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, + }, # tfhd - track fragment header # edts - edits --> contains elst (edit list) (ref PH) # tfdt - track fragment base media decode time @@ -1025,6 +1217,15 @@ my %eeBox = ( Name => 'CreateDate', Groups => { 2 => 'Time' }, %timeInfo, + RawConv => q{ + my $offset = (66 * 365 + 17) * 24 * 3600; + if ($val >= $offset or $$self{OPTIONS}{QuickTimeUTC}) { + $val -= $offset; + } elsif ($val and not $$self{IsWriting}) { + $self->WarnOnce('Patched incorrect time zero for QuickTime date/time tag',1); + } + return $$self{CreateDate} = $val; + }, # this is int64u if MovieHeaderVersion == 1 (ref 13) Hook => '$$self{MovieHeaderVersion} and $format = "int64u", $varSize += 4', }, @@ -1115,11 +1316,12 @@ my %eeBox = ( { #https://github.com/google/spatial-media/blob/master/docs/spherical-video-rfc.md Name => 'SphericalVideoXML', Condition => '$$valPt=~/^\xff\xcc\x82\x63\xf8\x55\x4a\x93\x88\x14\x58\x7a\x02\x52\x1f\xdd/', - Flags => [ 'Binary', 'BlockExtract' ], - Writable => 0, + WriteGroup => 'GSpherical', # write only GSpherical XMP tags here + HandlerType => 'vide', # only write in video tracks SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main', Start => 16, + WriteProc => 'Image::ExifTool::XMP::WriteGSpherical', }, }, { @@ -1127,6 +1329,10 @@ my %eeBox = ( %unknownInfo, }, ], + meco => { #ISO14492-12:2015 pg 83 + Name => 'OtherMeta', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::OtherMeta' }, + }, # edts - edits --> contains elst (edit list) # clip - clipping --> contains crgn (clip region) # matt - track matt --> contains kmat (compressed matt) @@ -1199,6 +1405,7 @@ my %eeBox = ( Format => 'fixed32s[9]', Notes => 'writable for the video track via the Composite Rotation tag', Writable => 1, + Protected => 1, Permanent => 1, # only set rotation if image size is non-zero RawConvInv => \&GetMatrixStructure, @@ -1230,17 +1437,30 @@ my %eeBox = ( %Image::ExifTool::QuickTime::UserData = ( PROCESS_PROC => \&ProcessMOV, WRITE_PROC => \&WriteQuickTime, - GROUPS => { 2 => 'Video' }, + CHECK_PROC => \&CheckQTValue, + GROUPS => { 1 => 'UserData', 2 => 'Video' }, + WRITABLE => 1, + PREFERRED => 1, # (preferred over Keys tags when writing) + FORMAT => 'string', + WRITE_GROUP => 'UserData', + LANG_INFO => \&GetLangInfo, NOTES => q{ Tag ID's beginning with the copyright symbol (hex 0xa9) are multi-language - text. Alternate language tags are accessed by adding a dash followed by the - language/country code to the tag name. ExifTool will extract any - multi-language user data tags found, even if they don't exist in this table. + text. Alternate language tags are accessed by adding a dash followed by a + 3-character ISO 639-2 language code to the tag name. ExifTool will extract + any multi-language user data tags found, even if they aren't in this table. + Note when creating new tags, + L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> tags are + preferred over these, so to create the tag when a same-named ItemList tag + exists, either "UserData" must be specified (eg. C<-UserData:Artist=Monet> + on the command line), or the PREFERRED level must be changed via + L<the config file|../config.html#PREF>. }, "\xa9cpy" => { Name => 'Copyright', Groups => { 2 => 'Author' } }, "\xa9day" => { Name => 'ContentCreateDate', Groups => { 2 => 'Time' }, + Shift => 'Time', # handle values in the form "2010-02-12T13:27:14-0800" (written by Apple iPhone) ValueConv => q{ require Image::ExifTool::XMP; @@ -1248,7 +1468,14 @@ my %eeBox = ( $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary return $val; }, + ValueConvInv => q{ + require Image::ExifTool::XMP; + my $tmp = Image::ExifTool::XMP::FormatXMPDate($val); + ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon + return $val; + }, PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) }, "\xa9ART" => 'Artist', #PH (iTunes 8.0.2) "\xa9alb" => 'Album', #PH (iTunes 8.0.2) @@ -1285,7 +1512,6 @@ my %eeBox = ( "\xa9prf" => 'Performers', "\xa9prk" => 'PerformerKeywords', #12 "\xa9prl" => 'PerformerURL', - "\xa9dir" => 'Director', #12 "\xa9req" => 'Requirements', "\xa9snk" => 'SubtitleKeywords', #12 "\xa9snm" => 'Subtitle', #12 @@ -1295,12 +1521,14 @@ my %eeBox = ( "\xa9swr" => 'SoftwareVersion', #12 "\xa9too" => 'Encoder', #PH (NC) "\xa9trk" => 'Track', #PH (NC) - "\xa9wrt" => 'Composer', + "\xa9wrt" => { Name => 'Composer', Avoid => 1 }, # ("\xa9com" is preferred in UserData) "\xa9xyz" => { #PH (iPhone 3GS) Name => 'GPSCoordinates', Groups => { 2 => 'Location' }, ValueConv => \&ConvertISO6709, + ValueConvInv => \&ConvInvISO6709, PrintConv => \&PrintGPSCoordinates, + PrintConvInv => \&PrintInvGPSCoordinates, }, # \xa9 tags written by DJI Phantom 3: (ref PH) "\xa9xsp" => 'SpeedX', #PH (guess) @@ -1317,7 +1545,12 @@ my %eeBox = ( "\xa9dji" => { Name => 'UserData_dji', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 }, "\xa9res" => { Name => 'UserData_res', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 }, "\xa9uid" => { Name => 'UserData_uid', Format => 'undef', Binary => 1, Unknown => 1, Hidden => 1 }, - "\xa9mdl" => { Name => 'Model', Format => 'string', Notes => 'non-standard-format DJI tag' }, + "\xa9mdl" => { + Name => 'Model', + Notes => 'non-standard-format DJI tag', + Format => 'string', + Avoid => 1, + }, # end DJI tags name => 'Name', WLOC => { @@ -1362,52 +1595,50 @@ my %eeBox = ( hinv => 'HintVersion', #PH (guess) XMP_ => { #PH (Adobe CS3 Bridge) Name => 'XMP', + WriteGroup => 'XMP', # (write main tags here) # *** this is where ExifTool writes XMP in MOV videos (as per XMP spec) *** SubDirectory => { TagTable => 'Image::ExifTool::XMP::Main' }, }, # the following are 3gp tags, references: # http://atomicparsley.sourceforge.net # http://www.3gpp.org/ftp/tsg_sa/WG4_CODEC/TSGS4_25/Docs/ - cprt => { Name => 'Copyright', %langText, Groups => { 2 => 'Author' } }, - auth => { Name => 'Author', %langText, Groups => { 2 => 'Author' } }, - titl => { Name => 'Title', %langText }, - dscp => { Name => 'Description',%langText }, - perf => { Name => 'Performer', %langText }, - gnre => { Name => 'Genre', %langText }, - albm => { Name => 'Album', %langText }, - coll => { Name => 'CollectionName', %langText }, #17 + # (note that all %langText3gp tags are Avoid => 1) + cprt => { Name => 'Copyright', %langText3gp, Groups => { 2 => 'Author' } }, + auth => { Name => 'Author', %langText3gp, Groups => { 2 => 'Author' } }, + titl => { Name => 'Title', %langText3gp }, + dscp => { Name => 'Description',%langText3gp }, + perf => { Name => 'Performer', %langText3gp }, + gnre => { Name => 'Genre', %langText3gp }, + albm => { Name => 'Album', %langText3gp }, + coll => { Name => 'CollectionName', %langText3gp }, #17 rtng => { Name => 'Rating', + Writable => 'undef', + Avoid => 1, # (4-byte flags, 4-char entity, 4-char criteria, 2-byte lang, string) - RawConv => q{ - return '<err>' unless length $val >= 14; - my $str = 'Entity=' . substr($val,4,4) . ' Criteria=' . substr($val,8,4); - $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters - my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 12)); - $lang = $lang ? "($lang) " : ''; - $val = substr($val, 14); - $val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/; - return $lang . $str . ' ' . $val; - }, + IText => 14, # (14 bytes before string) + Notes => 'string in the form "Entity=XXXX Criteria=XXXX XXXXX", used in 3gp videos', + ValueConv => '$val=~s/^(.{4})(.{4})/Entity=$1 Criteria=$2 /i; $val', + ValueConvInv => '$val=~s/Entity=(.{4}) Criteria=(.{4}) ?/$1$2/i; $val', }, clsf => { Name => 'Classification', + Writable => 'undef', + Avoid => 1, # (4-byte flags, 4-char entity, 2-byte index, 2-byte lang, string) - RawConv => q{ - return '<err>' unless length $val >= 12; - my $str = 'Entity=' . substr($val,4,4) . ' Index=' . Get16u(\$val,8); - $str =~ tr/\0-\x1f\x7f-\xff//d; # remove unprintable characters - my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 10)); - $lang = $lang ? "($lang) " : ''; - $val = substr($val, 12); - $val = $self->Decode($val, 'UCS2') if $val =~ /^\xfe\xff/; - return $lang . $str . ' ' . $val; - }, + IText => 12, + Notes => 'string in the form "Entity=XXXX Index=### XXXXX", used in 3gp videos', + ValueConv => '$val=~s/^(.{4})(.{2})/"Entity=$1 Index=".unpack("n",$2)." "/ie; $val', + ValueConvInv => '$val=~s/Entity=(.{4}) Index=(\d+) ?/$1.pack("n",$2)/ie; $val', }, kywd => { Name => 'Keywords', - # (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings) + # (4 byte flags, 2-byte lang, 1-byte count, count x pascal strings, ref 17) + # (but I have also seen a simple string written by iPhone, so don't make writable yet) + Notes => "not writable because Apple doesn't follow the 3gp specification", RawConv => q{ + my $sep = $self->Options('ListSep'); + return join($sep, split /\0+/, $val) unless $val =~ /^\0/; # (iPhone) return '<err>' unless length $val >= 7; my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4)); $lang = $lang ? "($lang) " : ''; @@ -1423,27 +1654,30 @@ my %eeBox = ( push @vals, $v; $pos += $len; } - my $sep = $self->Options('ListSep'); return $lang . join($sep, @vals); }, }, loci => { Name => 'LocationInformation', Groups => { 2 => 'Location' }, + Writable => 'undef', + IText => 6, + Avoid => 1, + NoDecode => 1, # (we'll decode the data ourself) + Notes => q{ + string in the form "XXXXX Role=XXX Lat=XXX Lon=XXX Alt=XXX Body=XXX + Notes=XXX", used in 3gp videos + }, # (4-byte flags, 2-byte lang, location string, 1-byte role, 4-byte fixed longitude, # 4-byte fixed latitude, 4-byte fixed altitude, body string, notes string) RawConv => q{ - return '<err>' unless length $val >= 6; - my $lang = Image::ExifTool::QuickTime::UnpackLang(Get16u(\$val, 4)); - $lang = $lang ? "($lang) " : ''; - $val = substr($val, 6); my $str; if ($val =~ /^\xfe\xff/) { $val =~ s/^(\xfe\xff(.{2})*?)\0\0//s or return '<err>'; $str = $self->Decode($1, 'UCS2'); } else { $val =~ s/^(.*?)\0//s or return '<err>'; - $str = $1; + $str = $self->Decode($1, 'UTF8'); } $str = '(none)' unless length $str; return '<err>' if length $val < 13; @@ -1458,30 +1692,55 @@ my %eeBox = ( if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) { $str .= ' Body=' . $self->Decode($1, 'UCS2'); } elsif ($val =~ s/^(.*?)\0//s) { - $str .= " Body=$1"; + $str .= ' Body=' . $self->Decode($1, 'UTF8'); } if ($val =~ s/^(\xfe\xff(.{2})*?)\0\0//s) { $str .= ' Notes=' . $self->Decode($1, 'UCS2'); } elsif ($val =~ s/^(.*?)\0//s) { - $str .= " Notes=$1"; + $str .= ' Notes=' . $self->Decode($1, 'UTF8'); } - return $lang . $str; + return $str; + }, + RawConvInv => q{ + my ($role, $lat, $lon, $alt, $body, $note); + $lat = $1 if $val =~ s/ Lat=([-+]?[.\d]+)//i; + $lon = $1 if $val =~ s/ Lon=([-+]?[.\d]+)//i; + $alt = $1 if $val =~ s/ Alt=([-+]?[.\d]+)//i; + $note = $val =~ s/ Notes=(.*)//i ? $1 : ''; + $body = $val =~ s/ Body=(.*)//i ? $1 : ''; + $role = $val =~ s/ Role=(.*)//i ? $1 : ''; + $val = '' if $val eq '(none)'; + $role = {shooting=>0,real=>1,fictional=>2}->{lc $role} || 0; + return $self->Encode($val, 'UTF8') . "\0" . Set8u($role) . + SetFixed32s(defined $lon ? $lon : 999) . + SetFixed32s(defined $lat ? $lat : 999) . + SetFixed32s(defined $alt ? $alt : 0) . + $self->Encode($body) . "\0" . + $self->Encode($note) . "\0"; }, }, yrrc => { Name => 'Year', + Writable => 'undef', Groups => { 2 => 'Time' }, - RawConv => 'length($val) >= 6 ? Get16u(\$val,4) : "<err>"', + Avoid => 1, + Notes => 'used in 3gp videos', + ValueConv => 'length($val) >= 6 ? unpack("x4n",$val) : "<err>"', + ValueConvInv => 'pack("Nn",0,$val)', }, urat => { #17 Name => 'UserRating', - RawConv => q{ + Writable => 'undef', + Notes => 'used in 3gp videos', + Avoid => 1, + ValueConv => q{ return '<err>' unless length $val >= 8; - return Get8u(\$val, 7); + unpack('x7C', $val); }, + ValueConvInv => 'pack("N2",0,$val)', }, # tsel - TrackSelection (ref 17) - # Apple tags (ref 16) + # Apple tags (ref 16[dead] -- see ref 25 instead) angl => { Name => 'CameraAngle', Format => 'string' }, # (NC) clfn => { Name => 'ClipFileName', Format => 'string' }, # (NC) clid => { Name => 'ClipID', Format => 'string' }, # (NC) @@ -1489,27 +1748,43 @@ my %eeBox = ( cmnm => { # (NC) Name => 'Model', Description => 'Camera Model Name', + Avoid => 1, Format => 'string', # (necessary to remove the trailing NULL) }, - date => { # (NC) + date => { Name => 'DateTimeOriginal', + Description => 'Date/Time Original', Groups => { 2 => 'Time' }, + Notes => q{ + Apple Photos has been reported to show a crazy date/time for some MP4 files + containing this tag, but perhaps only if it is missing a time zone + }, #forum10690/11125 + Shift => 'Time', ValueConv => q{ require Image::ExifTool::XMP; $val = Image::ExifTool::XMP::ConvertXMPDate($val); $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary return $val; }, + ValueConvInv => q{ + require Image::ExifTool::XMP; + $val = Image::ExifTool::XMP::FormatXMPDate($val); + $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon + return $val; + }, PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) }, manu => { # (SX280) Name => 'Make', + Avoid => 1, # (with Canon there are 6 unknown bytes before the model: "\0\0\0\0\x15\xc7") RawConv => '$val=~s/^\0{4}..//s; $val=~s/\0.*//; $val', }, modl => { # (Samsung GT-S8530, Canon SX280) Name => 'Model', Description => 'Camera Model Name', + Avoid => 1, # (with Canon there are 6 unknown bytes before the model: "\0\0\0\0\x15\xc7") RawConv => '$val=~s/^\0{4}..//s; $val=~s/\0.*//; $val', }, @@ -1523,7 +1798,7 @@ my %eeBox = ( Name => 'TrackType', # set flag to process this as international text # even though the tag ID doesn't start with 0xa9 - IText => 1, + IText => 4, # IText with 4-byte header }, chpl => { # (Nero chapter list) Name => 'ChapterList', @@ -1661,6 +1936,7 @@ my %eeBox = ( CNMN => { Name => 'Model', #PH (EOS 550D) Description => 'Camera Model Name', + Avoid => 1, Format => 'string', # (necessary to remove the trailing NULL) }, CNFV => { Name => 'FirmwareVersion', Format => 'string' }, #PH (EOS 550D) @@ -1704,19 +1980,39 @@ my %eeBox = ( ByteOrder => 'LittleEndian', }, }, + # ---- Garmin ---- (ref PH) + uuid => [{ + Name => 'GarminSoftware', # (NC) + Condition => '$$valPt =~ /^VIRBactioncamera/', + RawConv => 'substr($val, 16)', + RawConvInv => '"VIRBactioncamera$val"', + },{ + # have seen "28 f3 11 e2 b7 91 4f 6f 94 e2 4f 5d ea cb 3c 01" for RicohThetaZ1 accelerometer RADT data (not yet decoded) + Name => 'UUID-Unknown', + Writable => 0, + %unknownInfo, + }], + pmcc => { + Name => 'GarminSettings', + ValueConv => 'substr($val, 4)', + ValueConvInv => '"\0\0\0\x01$val"', + }, + # hmtp - "\0\0\0\x01" followed by 408 bytes of zero + # vrin - "\0\0\0\x01" followed by 8 bytes of zero # ---- GoPro ---- (ref PH) GoPr => 'GoProType', # (Hero3+) - FIRM => 'FirmwareVersion', # (Hero4) + FIRM => { Name => 'FirmwareVersion', Avoid => 1 }, # (Hero4) LENS => 'LensSerialNumber', # (Hero4) CAME => { # (Hero4) Name => 'SerialNumberHash', Description => 'Camera Serial Number Hash', ValueConv => 'unpack("H*",$val)', + ValueConvInv => 'pack("H*",$val)', }, # SETT? 12 bytes (Hero4) # MUID? 32 bytes (Hero4, starts with serial number hash) # HMMT? 404 bytes (Hero4, all zero) - # BCID? 26 bytes (Hero5, all zero) + # BCID? 26 bytes (Hero5, all zero), 36 bytes GoPro Max # GUMI? 16 bytes (Hero5) "FOV\0" => 'FieldOfView', #forum8938 (Hero2) seen: "Wide" GPMF => { @@ -1726,6 +2022,7 @@ my %eeBox = ( # free (all zero) "\xa9TSC" => 'StartTimeScale', # (Hero6) "\xa9TSZ" => 'StartTimeSampleSize', # (Hero6) + "\xa9TIM" => 'StartTimecode', #PH (NC) # --- HTC ---- htcb => { Name => 'HTCBinary', @@ -1736,10 +2033,10 @@ my %eeBox = ( Name => 'KodakDcMD', SubDirectory => { TagTable => 'Image::ExifTool::Kodak::DcMD' }, }, - SNum => { Name => 'SerialNumber', Groups => { 2 => 'Camera' } }, - ptch => { Name => 'Pitch', Format => 'rational64s' }, # Units?? - _yaw => { Name => 'Yaw', Format => 'rational64s' }, # Units?? - roll => { Name => 'Roll', Format => 'rational64s' }, # Units?? + SNum => { Name => 'SerialNumber', Avoid => 1, Groups => { 2 => 'Camera' } }, + ptch => { Name => 'Pitch', Format => 'rational64s', Avoid => 1 }, # Units?? + _yaw => { Name => 'Yaw', Format => 'rational64s', Avoid => 1 }, # Units?? + roll => { Name => 'Roll', Format => 'rational64s', Avoid => 1 }, # Units?? _cx_ => { Name => 'CX', Format => 'rational64s', Unknown => 1 }, _cy_ => { Name => 'CY', Format => 'rational64s', Unknown => 1 }, rads => { Name => 'Rads', Format => 'rational64s', Unknown => 1 }, @@ -1772,7 +2069,11 @@ my %eeBox = ( # ---- Microsoft ---- Xtra => { #PH (microsoft) Name => 'MicrosoftXtra', - SubDirectory => { TagTable => 'Image::ExifTool::Microsoft::Xtra' }, + WriteGroup => 'Microsoft', + SubDirectory => { + DirName => 'Microsoft', + TagTable => 'Image::ExifTool::Microsoft::Xtra', + }, }, # ---- Minolta ---- MMA0 => { #PH (DiMage 7Hi) @@ -1821,7 +2122,7 @@ my %eeBox = ( SubDirectory => { TagTable => 'Image::ExifTool::Olympus::thmb' }, },{ #17 (format is in bytes 3-7) Name => 'ThumbnailImage', - Condition => '$$valPt =~ /^.{8}\xff\xd8\xff\xdb/s', + Condition => '$$valPt =~ /^.{8}\xff\xd8\xff[\xdb\xe0]/s', Groups => { 2 => 'Preview' }, RawConv => 'substr($val, 8)', Binary => 1, @@ -1885,6 +2186,63 @@ my %eeBox = ( ProcessProc => \&Image::ExifTool::ProcessTIFF, # (because ProcessMOV is default) }, }, + '@mak' => { Name => 'Make', Avoid => 1 }, + '@mod' => { Name => 'Model', Avoid => 1 }, + '@swr' => { Name => 'SoftwareVersion', Avoid => 1 }, + '@day' => { + Name => 'ContentCreateDate', + Notes => q{ + some stupid Ricoh programmer used the '@' symbol instead of the copyright + symbol in these tag ID's for the Ricoh Theta Z1 and maybe other models + }, + Groups => { 2 => 'Time' }, + Shift => 'Time', + Avoid => 1, + # handle values in the form "2010-02-12T13:27:14-0800" + ValueConv => q{ + require Image::ExifTool::XMP; + $val = Image::ExifTool::XMP::ConvertXMPDate($val); + $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary + return $val; + }, + ValueConvInv => q{ + require Image::ExifTool::XMP; + my $tmp = Image::ExifTool::XMP::FormatXMPDate($val); + ($val = $tmp) =~ s/([-+]\d{2}):(\d{2})$/$1$2/ if defined $tmp; # remove time zone colon + return $val; + }, + PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) + }, + '@xyz' => { #PH (iPhone 3GS) + Name => 'GPSCoordinates', + Groups => { 2 => 'Location' }, + Avoid => 1, + ValueConv => \&ConvertISO6709, + ValueConvInv => \&ConvInvISO6709, + PrintConv => \&PrintGPSCoordinates, + PrintConvInv => \&PrintInvGPSCoordinates, + }, + # RDT1 - pairs of int32u_BE, starting at byte 8: "458275 471846" + # RDT2 - pairs of int32u_BE, starting at byte 8: "472276 468526" + # RDT3 - pairs of int32u_BE, starting at byte 8: "876603 482191" + # RDT4 - pairs of int32u_BE, starting at byte 8: "1955 484612" + # RDT6 - empty + # RDT7 - empty + # RDT8 - empty + # RDT9 - only 16-byte header? + # the boxes below all have a similar header (little-endian): + # 0 int32u - number of records + # 4 ? - "1e 00" + # 6 int16u - record length in bytes + # 8 ? - "23 01 00 00 00 00 00 00" + # 16 - start of records (each record ends in an int64u timestamp "ts" in ns) + # RDTA - float[4],ts: "-0.31289672 -0.2245330 11.303817 0 775.780" + # RDTB - float[4],ts: "-0.04841613 -0.2166595 0.0724792 0 775.780" + # RDTC - float[4],ts: "27.60925 -27.10037 -13.27285 0 775.829" + # RDTD - int16s[3],ts: "353 -914 16354 0 775.829" + # RDTG - ts: "775.825" + # RDTI - float[4],ts: "0.00165951 0.005770059 0.06838259 0.1744695 775.862" # ---- Samsung ---- vndr => 'Vendor', #PH (Samsung PL70) SDLN => 'PlayMode', #PH (NC, Samsung ST80 "SEQ_PLAY") @@ -1909,8 +2267,38 @@ my %eeBox = ( # @etc - 4 bytes all zero (Samsung WB30F) # saut - 4 bytes all zero (Samsung SM-N900T) # smrd - string "TRUEBLUE" (Samsung SM-C101) + # ---- TomTom Bandit Action Cam ---- + TTMD => { + Name => 'TomTomMetaData', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::TomTom' }, + }, + # ---- Samsung Gear 360 ---- + vrot => { + Name => 'AccelerometerData', + Notes => q{ + accelerometer readings for each frame of the video, expressed as sets of + yaw, pitch and roll angles in degrees + }, + Format => 'rational64s', + ValueConv => '$val =~ s/^-?\d+ //; \$val', # (ignore leading version/size words) + }, + # m360 - 8 bytes "0 0 0 0 0 0 0 1" + # opax - 164 bytes unknown (center and affine arrays? ref 26) + # opai - 32 bytes (maybe contains a serial number starting at byte 16? - PH) (rgb gains, degamma, gamma? ref 26) + # intv - 16 bytes all zero + # ---- Xaiomi ---- + mcvr => { + Name => 'PreviewImage', + Groups => { 2 => 'Preview' }, + Binary => 1, + }, # ---- Unknown ---- # CDET - 128 bytes (unknown origin) + # mtyp - 4 bytes all zero (some drone video) + # kgrf - 8 bytes all zero ? (in udta inside trak atom) + # kgcg - 128 bytes 0's and 1's + # kgsi - 4 bytes "00 00 00 80" + # FIEL - 18 bytes "FIEL\0\x01\0\0\0..." # # other 3rd-party tags # (ref http://code.google.com/p/mp4parser/source/browse/trunk/isoparser/src/main/resources/isoparser-default.properties?r=814) @@ -1943,6 +2331,26 @@ my %eeBox = ( # 4 - values: 12 ); +# TomTom Bandit Action Cam metadata (ref PH) +%Image::ExifTool::QuickTime::TomTom = ( + PROCESS_PROC => \&ProcessMOV, + GROUPS => { 2 => 'Video' }, + NOTES => 'Tags found in TomTom Bandit Action Cam MP4 videos.', + TTAD => { + Name => 'TomTomAD', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::Stream', + ProcessProc => \&Image::ExifTool::QuickTime::ProcessTTAD, + }, + }, + TTHL => { Name => 'TomTomHL', Binary => 1, Unknown => 1 }, # (mostly zeros) + # (TTID values are different for each video) + TTID => { Name => 'TomTomID', ValueConv => 'unpack("x4H*",$val)' }, + TTVI => { Name => 'TomTomVI', Format => 'int32u', Unknown => 1 }, # seen: "0 1 61 508 508" + # TTVD seen: "normal 720p 60fps 60fps 16/9 wide 1x" + TTVD => { Name => 'TomTomVD', ValueConv => 'my @a = ($val =~ /[\x20-\x7f]+/g); "@a"' }, +); + # User-specific media data atoms (ref 11) %Image::ExifTool::QuickTime::UserMedia = ( PROCESS_PROC => \&ProcessMOV, @@ -1955,16 +2363,22 @@ my %eeBox = ( # User-specific media data atoms (ref 11) %Image::ExifTool::QuickTime::MetaData = ( - PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessMetaData, + PROCESS_PROC => \&ProcessMetaData, GROUPS => { 2 => 'Video' }, TAG_PREFIX => 'MetaData', 0x01 => 'Title', 0x03 => { Name => 'ProductionDate', Groups => { 2 => 'Time' }, + Shift => 'Time', + Writable => 1, + Permanent => 1, + DelValue => '0000/00/00 00:00:00', # translate from format "YYYY/mm/dd HH:MM:SS" ValueConv => '$val=~tr{/}{:}; $val', + ValueConvInv => '$val=~s[^(\d{4}):(\d{2}):][$1/$2/]; $val', PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val)', }, 0x04 => 'Software', 0x05 => 'Product', @@ -1980,15 +2394,31 @@ my %eeBox = ( 0x0b => { Name => 'TimeZone', Groups => { 2 => 'Time' }, + Writable => 1, + Permanent => 1, + DelValue => 0, RawConv => 'Get16s(\$val,0)', + RawConvInv => 'Set16s($val)', PrintConv => 'TimeZoneString($val)', + PrintConvInv => q{ + return undef unless $val =~ /^([-+])(\d{1,2}):?(\d{2})$/' + my $tzmin = $2 * 60 + $3; + $tzmin = -$tzmin if $1 eq '-'; + return $tzmin; + } }, 0x0c => { Name => 'ModifyDate', Groups => { 2 => 'Time' }, + Shift => 'Time', + Writable => 1, + Permanent => 1, + DelValue => '0000/00/00 00:00:00', # translate from format "YYYY/mm/dd HH:MM:SS" ValueConv => '$val=~tr{/}{:}; $val', + ValueConvInv => '$val=~s[^(\d{4}):(\d{2}):][$1/$2/]; $val', PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val)', }, ); @@ -1997,7 +2427,7 @@ my %eeBox = ( PROCESS_PROC => \&ProcessMOV, GROUPS => { 2 => 'Video' }, dcom => 'Compression', - # cmvd - compressed movie data + # cmvd - compressed moov atom data ); # Profile atoms (ref 11) @@ -2140,7 +2570,8 @@ my %eeBox = ( # meta atoms %Image::ExifTool::QuickTime::Meta = ( PROCESS_PROC => \&ProcessMOV, - GROUPS => { 2 => 'Video' }, + WRITE_PROC => \&WriteQuickTime, + GROUPS => { 1 => 'Meta', 2 => 'Video' }, ilst => { Name => 'ItemList', SubDirectory => { @@ -2154,8 +2585,8 @@ my %eeBox = ( SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Handler' }, }, dinf => { - Name => 'DataInformation', - Flags => ['Binary','Unknown'], + Name => 'DataInfo', # (don't change this name -- used to recognize directory when writing) + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DataInfo' }, }, ipmc => { Name => 'IPMPControl', @@ -2164,6 +2595,7 @@ my %eeBox = ( iloc => { Name => 'ItemLocation', RawConv => \&ParseItemLocation, + WriteHook => \&ParseItemLocation, Notes => 'parsed, but not extracted as a tag', }, ipro => { @@ -2172,7 +2604,7 @@ my %eeBox = ( }, iinf => [{ Name => 'ItemInformation', - Condition => '$$valPt =~ /^\0/', # (version 0?) + Condition => '$$valPt =~ /^\0/', # (check for version 0) SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ItemInfo', Start => 6, # (4-byte version/flags + 2-byte count) @@ -2186,7 +2618,7 @@ my %eeBox = ( }], 'xml ' => { Name => 'XML', - Flags => [ 'Binary', 'Protected', 'BlockExtract' ], + Flags => [ 'Binary', 'Protected' ], SubDirectory => { TagTable => 'Image::ExifTool::XMP::XML', IgnoreProp => { NonRealTimeMeta => 1 }, # ignore container for Sony 'nrtm' @@ -2204,9 +2636,11 @@ my %eeBox = ( Name => 'PrimaryItemReference', Condition => '$$valPt =~ /^\0/', # (version 0?) RawConv => '$$self{PrimaryItem} = unpack("x4n",$val)', + WriteHook => sub { my ($val,$et) = @_; $$et{PrimaryItem} = unpack("x4n",$val); }, },{ Name => 'PrimaryItemReference', RawConv => '$$self{PrimaryItem} = unpack("x4N",$val)', + WriteHook => sub { my ($val,$et) = @_; $$et{PrimaryItem} = unpack("x4N",$val); }, }], free => { #PH Name => 'Free', @@ -2225,11 +2659,54 @@ my %eeBox = ( Start => 4, }, }, - # idat + idat => { + Name => 'MetaImageSize', #PH (NC) + Format => 'int16u', + # (don't know what the first two numbers are for) + PrintConv => '$val =~ s/^(\d+) (\d+) (\d+) (\d+)/${3}x$4/; $val', + }, + uuid => [ + { #PH (Canon R5/R6 HIF) + Name => 'MetaVersion', # (NC) + Condition => '$$valPt=~/^\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48/', + RawConv => 'substr($val, 0x14)', + }, + { + Name => 'UUID-Unknown', + %unknownInfo, + }, + ], +); + +# additional metadata container (ref ISO14496-12:2015) +%Image::ExifTool::QuickTime::OtherMeta = ( + PROCESS_PROC => \&ProcessMOV, + WRITE_PROC => \&WriteQuickTime, + GROUPS => { 2 => 'Video' }, + mere => { + Name => 'MetaRelation', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::MetaRelation' }, + }, + meta => { + Name => 'Meta', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Meta' }, + }, +); + +# metabox relation (ref ISO14496-12:2015) +%Image::ExifTool::QuickTime::MetaRelation = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Video' }, + FORMAT => 'int32u', + # 0 => 'MetaRelationVersion', + # 1 => 'FirstMetaboxHandlerType', + # 2 => 'FirstMetaboxHandlerType', + # 3 => { Name => 'MetaboxRelation', Format => 'int8u' }, ); %Image::ExifTool::QuickTime::ItemProp = ( PROCESS_PROC => \&ProcessMOV, + WRITE_PROC => \&WriteQuickTime, GROUPS => { 2 => 'Image' }, ipco => { Name => 'ItemPropertyContainer', @@ -2238,29 +2715,36 @@ my %eeBox = ( ipma => { Name => 'ItemPropertyAssociation', RawConv => \&ParseItemPropAssoc, + WriteHook => \&ParseItemPropAssoc, Notes => 'parsed, but not extracted as a tag', }, ); %Image::ExifTool::QuickTime::ItemPropCont = ( PROCESS_PROC => \&ProcessMOV, + WRITE_PROC => \&WriteQuickTime, + PERMANENT => 1, # (can't be deleted) GROUPS => { 2 => 'Image' }, VARS => { START_INDEX => 1 }, # show verbose indices starting at 1 colr => [{ Name => 'ICC_Profile', Condition => '$$valPt =~ /^(prof|rICC)/', + Permanent => 0, # (in QuickTime, this writes a zero-length box instead of deleting) SubDirectory => { TagTable => 'Image::ExifTool::ICC_Profile::Main', Start => 4, }, },{ - Name => 'Unknown_colr', - Flags => ['Binary','Unknown','Hidden'], + Name => 'ColorRepresentation', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::ColorRep' }, }], irot => { Name => 'Rotation', Format => 'int8u', + Writable => 'int8u', + Protected => 1, ValueConv => '$val * 90', + ValueConvInv => 'int($val / 90 + 0.5)', }, ispe => { Name => 'ImageSpatialExtent', @@ -2289,6 +2773,8 @@ my %eeBox = ( pasp => { Name => 'PixelAspectRatio', Format => 'int32u', + Writable => 'int32u', + Protected => 1, }, rloc => { Name => 'RelativeLocation', @@ -2297,45 +2783,301 @@ my %eeBox = ( }, clap => { Name => 'CleanAperture', - Format => 'rational64u', + Format => 'rational64s', Notes => '4 numbers: width, height, left and top', }, hvcC => { Name => 'HEVCConfiguration', - Flags => ['Binary','Unknown'], + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::HEVCConfig' }, + }, + av1C => { + Name => 'AV1Configuration', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::AV1Config' }, + }, +); + +# ref https://aomediacodec.github.io/av1-spec/av1-spec.pdf +%Image::ExifTool::QuickTime::ColorRep = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Video' }, + FIRST_ENTRY => 0, + 0 => { Name => 'ColorProfiles', Format => 'undef[4]' }, + 4 => { + Name => 'ColorPrimaries', + Format => 'int16u', + 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 1921 XYZ)', + 11 => 'SMPTE RP 431-2', + 12 => 'SMPTE EG 432-1', + 22 => 'EBU Tech. 3213-E', + }, + }, + 6 => { + Name => 'TransferCharacteristics', + Format => 'int16u', + PrintConv => { + 0 => 'For future use (0)', + 1 => 'BT.709', + 2 => 'Unspecified', + 3 => 'For future use (3)', + 4 => 'BT.470 System M (historical)', + 5 => 'BT.470 System B, G (historical)', + 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', + }, + }, + 8 => { + Name => 'MatrixCoefficients', + Format => 'int16u', + 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', + }, + }, +); + +# HEVC configuration (ref https://github.com/MPEGGroup/isobmff/blob/master/IsoLib/libisomediafile/src/HEVCConfigAtom.c) +%Image::ExifTool::QuickTime::HEVCConfig = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Video' }, + FIRST_ENTRY => 0, + 0 => 'HEVCConfigurationVersion', + 1 => { + Name => 'GeneralProfileSpace', + Mask => 0xc0, + PrintConv => { 0 => 'Conforming' }, + }, + 1.1 => { + Name => 'GeneralTierFlag', + Mask => 0x20, + PrintConv => { + 0 => 'Main Tier', + 1 => 'High Tier', + }, + }, + 1.2 => { + Name => 'GeneralProfileIDC', + Mask => 0x1f, + PrintConv => { + 0 => 'No Profile', + 1 => 'Main', + 2 => 'Main 10', + 3 => 'Main Still Picture', + 4 => 'Format Range Extensions', + 5 => 'High Throughput', + 6 => 'Multiview Main', + 7 => 'Scalable Main', + 8 => '3D Main', + 9 => 'Screen Content Coding Extensions', + 10 => 'Scalable Format Range Extensions', + 11 => 'High Throughput Screen Content Coding Extensions', + }, + }, + 2 => { + Name => 'GenProfileCompatibilityFlags', + Format => 'int32u', + PrintConv => { BITMASK => { + 31 => 'No Profile', # (bit 0 in stream) + 30 => 'Main', # (bit 1 in stream) + 29 => 'Main 10', # (bit 2 in stream) + 28 => 'Main Still Picture', # (bit 3 in stream) + 27 => 'Format Range Extensions',# (...) + 26 => 'High Throughput', + 25 => 'Multiview Main', + 24 => 'Scalable Main', + 23 => '3D Main', + 22 => 'Screen Content Coding Extensions', + 21 => 'Scalable Format Range Extensions', + 20 => 'High Throughput Screen Content Coding Extensions', + }}, + }, + 6 => { + Name => 'ConstraintIndicatorFlags', + Format => 'int8u[6]', + }, + 12 => { + Name => 'GeneralLevelIDC', + PrintConv => 'sprintf("%d (level %.1f)", $val, $val/30)', + }, + 13 => { + Name => 'MinSpatialSegmentationIDC', + Format => 'int16u', + Mask => 0x0fff, + }, + 15 => { + Name => 'ParallelismType', + Mask => 0x03, + }, + 16 => { + Name => 'ChromaFormat', + Mask => 0x03, + PrintConv => { + 0 => 'Monochrome', + 1 => '4:2:0', + 2 => '4:2:2', + 3 => '4:4:4', + }, + }, + 17 => { + Name => 'BitDepthLuma', + Mask => 0x07, + ValueConv => '$val + 8', + }, + 18 => { + Name => 'BitDepthChroma', + Mask => 0x07, + ValueConv => '$val + 8', + }, + 19 => { + Name => 'AverageFrameRate', + Format => 'int16u', + ValueConv => '$val / 256', + }, + 21 => { + Name => 'ConstantFrameRate', + Mask => 0xc0, + PrintConv => { + 0 => 'Unknown', + 1 => 'Constant Frame Rate', + 2 => 'Each Temporal Layer is Constant Frame Rate', + }, + }, + 21.1 => { + Name => 'NumTemporalLayers', + Mask => 0x38, + }, + 21.2 => { + Name => 'TemporalIDNested', + Mask => 0x04, + PrintConv => { 0 => 'No', 1 => 'Yes' }, + }, + #21.3 => { + # Name => 'NALUnitLengthSize', + # Mask => 0x03, + # ValueConv => '$val + 1', + # PrintConv => { 1 => '8-bit', 2 => '16-bit', 4 => '32-bit' }, + #}, + #22 => 'NumberOfNALUnitArrays', + # (don't decode the NAL unit arrays) +); + +# HEVC configuration (ref https://aomediacodec.github.io/av1-isobmff/#av1codecconfigurationbox) +%Image::ExifTool::QuickTime::AV1Config = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Video' }, + FIRST_ENTRY => 0, + 0 => { + Name => 'AV1ConfigurationVersion', + Mask => 0x7f, + }, + 1.0 => { + Name => 'SeqProfile', + Mask => 0xe0, + Unknown => 1, + }, + 1.1 => { + Name => 'SeqLevelIdx0', + Mask => 0x1f, + Unknown => 1, + }, + 2.0 => { + Name => 'SeqTier0', + Mask => 0x80, + Unknown => 1, + }, + 2.1 => { + Name => 'HighBitDepth', + Mask => 0x40, + Unknown => 1, + }, + 2.2 => { + Name => 'TwelveBit', + Mask => 0x20, + Unknown => 1, + }, + 2.3 => { + Name => 'ChromaFormat', # (Monochrome+SubSamplingX+SubSamplingY) + Notes => 'bits: 0x04 = Monochrome, 0x02 = SubSamplingX, 0x01 = SubSamplingY', + Mask => 0x1c, + PrintConv => { + 0x00 => 'YUV 4:4:4', + 0x02 => 'YUV 4:2:2', + 0x03 => 'YUV 4:2:0', + 0x07 => 'Monochrome 4:0:0', + }, + }, + 2.4 => { + Name => 'ChromaSamplePosition', + Mask => 0x03, + PrintConv => { + 0 => 'Unknown', + 1 => 'Vertical', + 2 => 'Colocated', + 3 => '(reserved)', + }, + }, + 3 => { + Name => 'InitialDelaySamples', + RawConv => '$val & 0x10 ? undef : ($val & 0x0f) + 1', + Unknown => 1, }, ); %Image::ExifTool::QuickTime::ItemRef = ( PROCESS_PROC => \&ProcessMOV, + WRITE_PROC => \&WriteQuickTime, GROUPS => { 2 => 'Image' }, # (Note: ExifTool's ItemRefVersion may be used to test the iref version number) - # dimg - DerivedImage - # thmb - Thumbnail - # auxl - AuxiliaryImage + NOTES => q{ + The Item reference entries listed in the table below contain information about + 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' }, + thmb => { Name => 'ThumbnailRef', RawConv => 'undef' }, + auxl => { Name => 'AuxiliaryImageRef', RawConv => 'undef' }, cdsc => { Name => 'ContentDescribes', - Notes => 'parsed, but not extracted as a tag', - RawConv => sub { - my ($val, $et) = @_; - my ($id, $count, @to); - if ($$et{ItemRefVersion}) { - return undef if length $val < 10; - ($id, $count, @to) = unpack('NnN*', $val); - } else { - return undef if length $val < 6; - ($id, $count, @to) = unpack('nnn*', $val); - } - # add all referenced item ID's to a "RefersTo" lookup - $$et{ItemInfo}{$id}{RefersTo}{$_} = 1 foreach @to; - $et->VPrint(1, "$$et{INDENT} Item $id describes: @to\n"); - return undef; - }, + RawConv => \&ParseContentDescribes, + WriteHook => \&ParseContentDescribes, }, ); %Image::ExifTool::QuickTime::ItemInfo = ( PROCESS_PROC => \&ProcessMOV, + WRITE_PROC => \&WriteQuickTime, GROUPS => { 2 => 'Image' }, # avc1 - AVC image # hvc1 - HEVC image @@ -2345,6 +3087,7 @@ my %eeBox = ( infe => { Name => 'ItemInfoEntry', RawConv => \&ParseItemInfoEntry, + WriteHook => \&ParseItemInfoEntry, Notes => 'parsed, but not extracted as a tag', }, ); @@ -2401,20 +3144,37 @@ my %eeBox = ( # -> these atoms are unique, and contain one or more 'data' atoms %Image::ExifTool::QuickTime::ItemList = ( PROCESS_PROC => \&ProcessMOV, - GROUPS => { 2 => 'Audio' }, + WRITE_PROC => \&WriteQuickTime, + CHECK_PROC => \&CheckQTValue, + WRITABLE => 1, + PREFERRED => 2, # (preferred over UserData and Keys tags when writing) + FORMAT => 'string', + GROUPS => { 1 => 'ItemList', 2 => 'Audio' }, + WRITE_GROUP => 'ItemList', + LANG_INFO => \&GetLangInfo, NOTES => q{ - As well as these tags, the "mdta" handler uses numerical tag ID's which are - added dynamically to this table after processing the Meta Keys information. + This is the preferred location for creating new QuickTime tags. Tags in + this table support alternate languages which are accessed by adding a + 3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2 + country code to the tag name (eg. "ItemList:Title-fra" or + "ItemList::Title-fra-FR"). When creating a new Meta box to contain the + ItemList directory, by default ExifTool adds an 'mdir' (Metadata) Handler + box because Apple software may ignore ItemList tags otherwise, but the API + L<QuickTimeHandler|../ExifTool.html#QuickTimeHandler> option may be set to 0 to avoid this. }, # in this table, binary 1 and 2-byte "data"-type tags are interpreted as - # int8u and int16u. Multi-byte binary "data" tags are extracted as binary data + # int8u and int16u. Multi-byte binary "data" tags are extracted as binary data. + # (Note that the Preferred property is set to 0 for some tags to prevent them + # from being created when a same-named tag already exists in the table) "\xa9ART" => 'Artist', "\xa9alb" => 'Album', + "\xa9aut" => { Name => 'Author', Avoid => 1, Groups => { 2 => 'Author' } }, #forum10091 ('auth' is preferred) "\xa9cmt" => 'Comment', - "\xa9com" => 'Composer', + "\xa9com" => { Name => 'Composer', Avoid => 1, }, # ("\xa9wrt" is preferred in ItemList) "\xa9day" => { Name => 'ContentCreateDate', Groups => { 2 => 'Time' }, + Shift => 'Time', # handle values in the form "2010-02-12T13:27:14-0800" ValueConv => q{ require Image::ExifTool::XMP; @@ -2422,7 +3182,14 @@ my %eeBox = ( $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary return $val; }, + ValueConvInv => q{ + require Image::ExifTool::XMP; + $val = Image::ExifTool::XMP::FormatXMPDate($val); + $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon + return $val; + }, PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) }, "\xa9des" => 'Description', #4 "\xa9enc" => 'EncodedBy', #10 @@ -2430,10 +3197,25 @@ my %eeBox = ( "\xa9grp" => 'Grouping', "\xa9lyr" => 'Lyrics', "\xa9nam" => 'Title', - # "\xa9st3" ? #10 "\xa9too" => 'Encoder', "\xa9trk" => 'Track', "\xa9wrt" => 'Composer', +# +# the following tags written by AtomicParsley 0.9.6 +# (ref https://exiftool.org/forum/index.php?topic=11455.0) +# + "\xa9st3" => 'Subtitle', + "\xa9con" => 'Conductor', + "\xa9sol" => 'Soloist', + "\xa9arg" => 'Arranger', + "\xa9ope" => 'OriginalArtist', + "\xa9dir" => 'Director', + "\xa9ard" => 'ArtDirector', + "\xa9sne" => 'SoundEngineer', + "\xa9prd" => 'Producer', + "\xa9xpd" => 'ExecutiveProducer', + sdes => 'StoreDescription', +# '----' => { Name => 'iTunesInfo', SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::iTunesInfo' }, @@ -2442,15 +3224,29 @@ my %eeBox = ( covr => { Name => 'CoverArt', Groups => { 2 => 'Preview' } }, cpil => { #10 Name => 'Compilation', + Format => 'int8u', #27 (ref 23 contradicts what AtomicParsley actually writes, which is int8s) + Writable => 'int8s', PrintConv => { 0 => 'No', 1 => 'Yes' }, }, disk => { Name => 'DiskNumber', Format => 'undef', # (necessary to prevent decoding as string!) - ValueConv => 'length($val) >= 6 ? join(" of ",unpack("x2nn",$val)) : \$val', + ValueConv => q{ + return \$val unless length($val) >= 6; + my @a = unpack 'x2nn', $val; + return $a[1] ? join(' of ', @a) : $a[0]; + }, + ValueConvInv => q{ + my @a = $val =~ /\d+/g; + return undef if @a == 0 or @a > 2; + push @a, 0 if @a == 1; + return pack('n3', 0, @a); + }, }, pgap => { #10 Name => 'PlayGap', + Format => 'int8u', #23 + Writable => 'int8s', #27 PrintConv => { 0 => 'Insert Gap', 1 => 'No Gap', @@ -2458,12 +3254,26 @@ my %eeBox = ( }, tmpo => { Name => 'BeatsPerMinute', - Format => 'int16u', # marked as boolean but really int16u in my sample + # marked as boolean but really int16u in my sample + # (but written as int16s by iTunes and AtomicParsley, ref forum11506) + Format => 'int16u', + Writable => 'int16s', }, trkn => { Name => 'TrackNumber', Format => 'undef', # (necessary to prevent decoding as string!) - ValueConv => 'length($val) >= 6 ? join(" of ",unpack("x2nn",$val)) : \$val', + ValueConv => q{ + return \$val unless length($val) >= 6; + my @a = unpack 'x2nn', $val; + return $a[1] ? join(' of ', @a) : $a[0]; + }, + # (see forum11501 for discussion about the format used) + ValueConvInv => q{ + my @a = $val =~ /\d+/g; + return undef if @a == 0 or @a > 2; + push @a, 0 if @a == 1; + return pack('n4', 0, @a, 0); + }, }, # # Note: it is possible that the tags below are not being decoded properly @@ -2471,40 +3281,59 @@ my %eeBox = ( # akID => { #10 Name => 'AppleStoreAccountType', + Format => 'int8u', #24 + Writable => 'int8s', #27 PrintConv => { 0 => 'iTunes', 1 => 'AOL', }, }, - albm => 'Album', #(ffmpeg source) + albm => { Name => 'Album', Avoid => 1 }, #(ffmpeg source) apID => 'AppleStoreAccount', atID => { #10 (or TV series) Name => 'AlbumTitleID', Format => 'int32u', + Writable => 'int32s', #27 }, auth => { Name => 'Author', Groups => { 2 => 'Author' } }, catg => 'Category', #7 cnID => { #10 Name => 'AppleStoreCatalogID', Format => 'int32u', + Writable => 'int32s', #27 }, cprt => { Name => 'Copyright', Groups => { 2 => 'Author' } }, - dscp => 'Description', - desc => 'Description', #7 + dscp => { Name => 'Description', Avoid => 1 }, + desc => { Name => 'Description', Avoid => 1 }, #7 gnre => { #10 Name => 'Genre', + Avoid => 1, + # (Note: see https://exiftool.org/forum/index.php?topic=11537.0) + Format => 'undef', + ValueConv => 'unpack("n",$val)', + ValueConvInv => '$val =~ /^\d+$/ ? pack("n",$val) : undef', PrintConv => q{ return $val unless $val =~ /^\d+$/; require Image::ExifTool::ID3; Image::ExifTool::ID3::PrintGenre($val - 1); # note the "- 1" }, + PrintConvInv => q{ + return $val if $val =~ /^[0-9]+$/; + require Image::ExifTool::ID3; + my $id = Image::ExifTool::ID3::GetGenreID($val); + return unless defined $id and $id =~ /^\d+$/; + return $id + 1; + }, }, egid => 'EpisodeGlobalUniqueID', #7 geID => { #10 Name => 'GenreID', Format => 'int32u', + Writable => 'int32s', #27 SeparateTable => 1, - PrintConv => { #21 (based on https://affiliate.itunes.apple.com/resources/documentation/genre-mapping/) + # the following lookup is based on http://itunes.apple.com/WebObjects/MZStoreServices.woa/ws/genres + # (see scripts/parse_genre to parse genre JSON file from above) + PrintConv => { #21/PH 2 => 'Music|Blues', 3 => 'Music|Comedy', 4 => "Music|Children's Music", @@ -2550,6 +3379,17 @@ my %eeBox = ( 53 => 'Music|Instrumental', 74 => 'Audiobooks|News', 75 => 'Audiobooks|Programs & Performances', + 500 => 'Fitness Music', + 501 => 'Fitness Music|Pop', + 502 => 'Fitness Music|Dance', + 503 => 'Fitness Music|Hip-Hop', + 504 => 'Fitness Music|Rock', + 505 => 'Fitness Music|Alt/Indie', + 506 => 'Fitness Music|Latino', + 507 => 'Fitness Music|Country', + 508 => 'Fitness Music|World', + 509 => 'Fitness Music|New Age', + 510 => 'Fitness Music|Classical', 1001 => 'Music|Alternative|College Rock', 1002 => 'Music|Alternative|Goth Rock', 1003 => 'Music|Alternative|Grunge', @@ -2665,12 +3505,12 @@ my %eeBox = ( 1116 => 'Music|Latino|Contemporary Latin', 1117 => 'Music|Latino|Pop Latino', 1118 => 'Music|Latino|Raices', # (Ra&iacute;ces) - 1119 => 'Music|Latino|Latin Urban', + 1119 => 'Music|Latino|Urbano latino', 1120 => 'Music|Latino|Baladas y Boleros', 1121 => 'Music|Latino|Rock y Alternativo', 1122 => 'Music|Brazilian', 1123 => 'Music|Latino|Musica Mexicana', # (M&uacute;sica Mexicana) - 1124 => 'Music|Latino|Salsa y Tropical', + 1124 => 'Music|Latino|Musica tropical', # (M&uacute;sica tropical) 1125 => 'Music|New Age|Environmental', 1126 => 'Music|New Age|Healing', 1127 => 'Music|New Age|Meditation', @@ -2721,8 +3561,8 @@ my %eeBox = ( 1174 => 'Music|Vocal|Traditional Pop', 1175 => 'Music|Jazz|Vocal Jazz', 1176 => 'Music|Vocal|Vocal Pop', - 1177 => 'Music|World|Afro-Beat', - 1178 => 'Music|World|Afro-Pop', + 1177 => 'Music|African|Afro-Beat', + 1178 => 'Music|African|Afro-Pop', 1179 => 'Music|World|Cajun', 1180 => 'Music|World|Celtic', 1181 => 'Music|World|Celtic Folk', @@ -2747,7 +3587,7 @@ my %eeBox = ( 1200 => 'Music|World|Australia', 1201 => 'Music|World|Japan', 1202 => 'Music|World|France', - 1203 => 'Music|World|Africa', + 1203 => 'Music|African', 1204 => 'Music|World|Asia', 1205 => 'Music|World|Europe', 1206 => 'Music|World|South Africa', @@ -2800,24 +3640,24 @@ my %eeBox = ( 1261 => 'Music|Vocal|Trot', 1262 => 'Music|Indian', 1263 => 'Music|Indian|Bollywood', - 1264 => 'Music|Indian|Tamil', - 1265 => 'Music|Indian|Telugu', + 1264 => 'Music|Indian|Regional Indian|Tamil', + 1265 => 'Music|Indian|Regional Indian|Telugu', 1266 => 'Music|Indian|Regional Indian', 1267 => 'Music|Indian|Devotional & Spiritual', 1268 => 'Music|Indian|Sufi', 1269 => 'Music|Indian|Indian Classical', - 1270 => 'Music|World|Russian Chanson', + 1270 => 'Music|Russian|Russian Chanson', 1271 => 'Music|World|Dini', - 1272 => 'Music|World|Halk', - 1273 => 'Music|World|Sanat', + 1272 => 'Music|Turkish|Halk', + 1273 => 'Music|Turkish|Sanat', 1274 => 'Music|World|Dangdut', 1275 => 'Music|World|Indonesian Religious', 1276 => 'Music|World|Calypso', 1277 => 'Music|World|Soca', 1278 => 'Music|Indian|Ghazals', 1279 => 'Music|Indian|Indian Folk', - 1280 => 'Music|World|Arabesque', - 1281 => 'Music|World|Afrikaans', + 1280 => 'Music|Turkish|Arabesque', + 1281 => 'Music|African|Afrikaans', 1282 => 'Music|World|Farsi', 1283 => 'Music|World|Israeli', 1284 => 'Music|Arabic|Khaleeji', @@ -2834,8 +3674,8 @@ my %eeBox = ( 1296 => 'Music|World|Tango', 1297 => 'Music|World|Fado', 1298 => 'Music|World|Iberia', - 1299 => 'Music|World|Russian', - 1300 => 'Music|World|Turkish', + 1299 => 'Music|Russian', + 1300 => 'Music|Turkish', 1301 => 'Podcasts|Arts', 1302 => 'Podcasts|Society & Culture|Personal Journals', 1303 => 'Podcasts|Comedy', @@ -2904,6 +3744,90 @@ my %eeBox = ( 1479 => 'Podcasts|Science & Medicine|Social Sciences', 1480 => 'Podcasts|Technology|Software How-To', 1481 => 'Podcasts|Health|Alternative Health', + 1482 => 'Podcasts|Arts|Books', + 1483 => 'Podcasts|Fiction', + 1484 => 'Podcasts|Fiction|Drama', + 1485 => 'Podcasts|Fiction|Science Fiction', + 1486 => 'Podcasts|Fiction|Comedy Fiction', + 1487 => 'Podcasts|History', + 1488 => 'Podcasts|True Crime', + 1489 => 'Podcasts|News', + 1490 => 'Podcasts|News|Business News', + 1491 => 'Podcasts|Business|Management', + 1492 => 'Podcasts|Business|Marketing', + 1493 => 'Podcasts|Business|Entrepreneurship', + 1494 => 'Podcasts|Business|Non-Profit', + 1495 => 'Podcasts|Comedy|Improv', + 1496 => 'Podcasts|Comedy|Comedy Interviews', + 1497 => 'Podcasts|Comedy|Stand-Up', + 1498 => 'Podcasts|Education|Language Learning', + 1499 => 'Podcasts|Education|How To', + 1500 => 'Podcasts|Education|Self-Improvement', + 1501 => 'Podcasts|Education|Courses', + 1502 => 'Podcasts|Leisure', + 1503 => 'Podcasts|Leisure|Automotive', + 1504 => 'Podcasts|Leisure|Aviation', + 1505 => 'Podcasts|Leisure|Hobbies', + 1506 => 'Podcasts|Leisure|Crafts', + 1507 => 'Podcasts|Leisure|Games', + 1508 => 'Podcasts|Leisure|Home & Garden', + 1509 => 'Podcasts|Leisure|Video Games', + 1510 => 'Podcasts|Leisure|Animation & Manga', + 1511 => 'Podcasts|Government', + 1512 => 'Podcasts|Health & Fitness', + 1513 => 'Podcasts|Health & Fitness|Alternative Health', + 1514 => 'Podcasts|Health & Fitness|Fitness', + 1515 => 'Podcasts|Health & Fitness|Nutrition', + 1516 => 'Podcasts|Health & Fitness|Sexuality', + 1517 => 'Podcasts|Health & Fitness|Mental Health', + 1518 => 'Podcasts|Health & Fitness|Medicine', + 1519 => 'Podcasts|Kids & Family|Education for Kids', + 1520 => 'Podcasts|Kids & Family|Stories for Kids', + 1521 => 'Podcasts|Kids & Family|Parenting', + 1522 => 'Podcasts|Kids & Family|Pets & Animals', + 1523 => 'Podcasts|Music|Music Commentary', + 1524 => 'Podcasts|Music|Music History', + 1525 => 'Podcasts|Music|Music Interviews', + 1526 => 'Podcasts|News|Daily News', + 1527 => 'Podcasts|News|Politics', + 1528 => 'Podcasts|News|Tech News', + 1529 => 'Podcasts|News|Sports News', + 1530 => 'Podcasts|News|News Commentary', + 1531 => 'Podcasts|News|Entertainment News', + 1532 => 'Podcasts|Religion & Spirituality|Religion', + 1533 => 'Podcasts|Science', + 1534 => 'Podcasts|Science|Natural Sciences', + 1535 => 'Podcasts|Science|Social Sciences', + 1536 => 'Podcasts|Science|Mathematics', + 1537 => 'Podcasts|Science|Nature', + 1538 => 'Podcasts|Science|Astronomy', + 1539 => 'Podcasts|Science|Chemistry', + 1540 => 'Podcasts|Science|Earth Sciences', + 1541 => 'Podcasts|Science|Life Sciences', + 1542 => 'Podcasts|Science|Physics', + 1543 => 'Podcasts|Society & Culture|Documentary', + 1544 => 'Podcasts|Society & Culture|Relationships', + 1545 => 'Podcasts|Sports', + 1546 => 'Podcasts|Sports|Soccer', + 1547 => 'Podcasts|Sports|Football', + 1548 => 'Podcasts|Sports|Basketball', + 1549 => 'Podcasts|Sports|Baseball', + 1550 => 'Podcasts|Sports|Hockey', + 1551 => 'Podcasts|Sports|Running', + 1552 => 'Podcasts|Sports|Rugby', + 1553 => 'Podcasts|Sports|Golf', + 1554 => 'Podcasts|Sports|Cricket', + 1555 => 'Podcasts|Sports|Wrestling', + 1556 => 'Podcasts|Sports|Tennis', + 1557 => 'Podcasts|Sports|Volleyball', + 1558 => 'Podcasts|Sports|Swimming', + 1559 => 'Podcasts|Sports|Wilderness', + 1560 => 'Podcasts|Sports|Fantasy Sports', + 1561 => 'Podcasts|TV & Film|TV Reviews', + 1562 => 'Podcasts|TV & Film|After Shows', + 1563 => 'Podcasts|TV & Film|Film Reviews', + 1564 => 'Podcasts|TV & Film|Film History', + 1565 => 'Podcasts|TV & Film|Film Interviews', 1602 => 'Music Videos|Blues', 1603 => 'Music Videos|Comedy', 1604 => "Music Videos|Children's Music", @@ -2990,16 +3914,16 @@ my %eeBox = ( 1689 => 'Music Videos|Spoken Word', 1690 => 'Music Videos|Indian', 1691 => 'Music Videos|Indian|Bollywood', - 1692 => 'Music Videos|Indian|Tamil', - 1693 => 'Music Videos|Indian|Telugu', + 1692 => 'Music Videos|Indian|Regional Indian|Tamil', + 1693 => 'Music Videos|Indian|Regional Indian|Telugu', 1694 => 'Music Videos|Indian|Regional Indian', 1695 => 'Music Videos|Indian|Devotional & Spiritual', 1696 => 'Music Videos|Indian|Sufi', 1697 => 'Music Videos|Indian|Indian Classical', - 1698 => 'Music Videos|World|Russian Chanson', + 1698 => 'Music Videos|Russian|Russian Chanson', 1699 => 'Music Videos|World|Dini', - 1700 => 'Music Videos|World|Halk', - 1701 => 'Music Videos|World|Sanat', + 1700 => 'Music Videos|Turkish|Halk', + 1701 => 'Music Videos|Turkish|Sanat', 1702 => 'Music Videos|World|Dangdut', 1703 => 'Music Videos|World|Indonesian Religious', 1704 => 'Music Videos|Indian|Indian Pop', @@ -3007,8 +3931,8 @@ my %eeBox = ( 1706 => 'Music Videos|World|Soca', 1707 => 'Music Videos|Indian|Ghazals', 1708 => 'Music Videos|Indian|Indian Folk', - 1709 => 'Music Videos|World|Arabesque', - 1710 => 'Music Videos|World|Afrikaans', + 1709 => 'Music Videos|Turkish|Arabesque', + 1710 => 'Music Videos|African|Afrikaans', 1711 => 'Music Videos|World|Farsi', 1712 => 'Music Videos|World|Israeli', 1713 => 'Music Videos|Arabic', @@ -3026,8 +3950,8 @@ my %eeBox = ( 1726 => 'Music Videos|World|Tango', 1727 => 'Music Videos|World|Fado', 1728 => 'Music Videos|World|Iberia', - 1729 => 'Music Videos|World|Russian', - 1730 => 'Music Videos|World|Turkish', + 1729 => 'Music Videos|Russian', + 1730 => 'Music Videos|Turkish', 1731 => 'Music Videos|Alternative|College Rock', 1732 => 'Music Videos|Alternative|Goth Rock', 1733 => 'Music Videos|Alternative|Grunge', @@ -3200,9 +4124,9 @@ my %eeBox = ( 1901 => 'Music Videos|Vocal|Traditional Pop', 1902 => 'Music Videos|Jazz|Vocal Jazz', 1903 => 'Music Videos|Vocal|Vocal Pop', - 1904 => 'Music Videos|World|Africa', - 1905 => 'Music Videos|World|Afro-Beat', - 1906 => 'Music Videos|World|Afro-Pop', + 1904 => 'Music Videos|African', + 1905 => 'Music Videos|African|Afro-Beat', + 1906 => 'Music Videos|African|Afro-Pop', 1907 => 'Music Videos|World|Asia', 1908 => 'Music Videos|World|Australia', 1909 => 'Music Videos|World|Cajun', @@ -3245,12 +4169,94 @@ my %eeBox = ( 1948 => 'Music Videos|New Age|Yoga', 1949 => 'Music Videos|Pop|Tribute', 1950 => 'Music Videos|Pop|Shows', + 1951 => 'Music Videos|Cuban', + 1952 => 'Music Videos|Cuban|Mambo', + 1953 => 'Music Videos|Cuban|Chachacha', + 1954 => 'Music Videos|Cuban|Guajira', + 1955 => 'Music Videos|Cuban|Son', + 1956 => 'Music Videos|Cuban|Bolero', + 1957 => 'Music Videos|Cuban|Guaracha', + 1958 => 'Music Videos|Cuban|Timba', + 1959 => 'Music Videos|Soundtrack|Video Game', + 1960 => 'Music Videos|Indian|Regional Indian|Punjabi|Punjabi Pop', + 1961 => 'Music Videos|Indian|Regional Indian|Bengali|Rabindra Sangeet', + 1962 => 'Music Videos|Indian|Regional Indian|Malayalam', + 1963 => 'Music Videos|Indian|Regional Indian|Kannada', + 1964 => 'Music Videos|Indian|Regional Indian|Marathi', + 1965 => 'Music Videos|Indian|Regional Indian|Gujarati', + 1966 => 'Music Videos|Indian|Regional Indian|Assamese', + 1967 => 'Music Videos|Indian|Regional Indian|Bhojpuri', + 1968 => 'Music Videos|Indian|Regional Indian|Haryanvi', + 1969 => 'Music Videos|Indian|Regional Indian|Odia', + 1970 => 'Music Videos|Indian|Regional Indian|Rajasthani', + 1971 => 'Music Videos|Indian|Regional Indian|Urdu', + 1972 => 'Music Videos|Indian|Regional Indian|Punjabi', + 1973 => 'Music Videos|Indian|Regional Indian|Bengali', + 1974 => 'Music Videos|Indian|Indian Classical|Carnatic Classical', + 1975 => 'Music Videos|Indian|Indian Classical|Hindustani Classical', + 1976 => 'Music Videos|African|Afro House', + 1977 => 'Music Videos|African|Afro Soul', + 1978 => 'Music Videos|African|Afrobeats', + 1979 => 'Music Videos|African|Benga', + 1980 => 'Music Videos|African|Bongo-Flava', + 1981 => 'Music Videos|African|Coupe-Decale', + 1982 => 'Music Videos|African|Gqom', + 1983 => 'Music Videos|African|Highlife', + 1984 => 'Music Videos|African|Kuduro', + 1985 => 'Music Videos|African|Kizomba', + 1986 => 'Music Videos|African|Kwaito', + 1987 => 'Music Videos|African|Mbalax', + 1988 => 'Music Videos|African|Ndombolo', + 1989 => 'Music Videos|African|Shangaan Electro', + 1990 => 'Music Videos|African|Soukous', + 1991 => 'Music Videos|African|Taarab', + 1992 => 'Music Videos|African|Zouglou', + 1993 => 'Music Videos|Turkish|Ozgun', + 1994 => 'Music Videos|Turkish|Fantezi', + 1995 => 'Music Videos|Turkish|Religious', + 1996 => 'Music Videos|Pop|Turkish Pop', + 1997 => 'Music Videos|Rock|Turkish Rock', + 1998 => 'Music Videos|Alternative|Turkish Alternative', + 1999 => 'Music Videos|Hip-Hop/Rap|Turkish Hip-Hop/Rap', + 2000 => 'Music Videos|African|Maskandi', + 2001 => 'Music Videos|Russian|Russian Romance', + 2002 => 'Music Videos|Russian|Russian Bard', + 2003 => 'Music Videos|Russian|Russian Pop', + 2004 => 'Music Videos|Russian|Russian Rock', + 2005 => 'Music Videos|Russian|Russian Hip-Hop', + 2006 => 'Music Videos|Arabic|Levant', + 2007 => 'Music Videos|Arabic|Levant|Dabke', + 2008 => 'Music Videos|Arabic|Maghreb Rai', + 2009 => 'Music Videos|Arabic|Khaleeji|Khaleeji Jalsat', + 2010 => 'Music Videos|Arabic|Khaleeji|Khaleeji Shailat', + 2011 => 'Music Videos|Tarab', + 2012 => 'Music Videos|Tarab|Iraqi Tarab', + 2013 => 'Music Videos|Tarab|Egyptian Tarab', + 2014 => 'Music Videos|Tarab|Khaleeji Tarab', + 2015 => 'Music Videos|Pop|Levant Pop', + 2016 => 'Music Videos|Pop|Iraqi Pop', + 2017 => 'Music Videos|Pop|Egyptian Pop', + 2018 => 'Music Videos|Pop|Maghreb Pop', + 2019 => 'Music Videos|Pop|Khaleeji Pop', + 2020 => 'Music Videos|Hip-Hop/Rap|Levant Hip-Hop', + 2021 => 'Music Videos|Hip-Hop/Rap|Egyptian Hip-Hop', + 2022 => 'Music Videos|Hip-Hop/Rap|Maghreb Hip-Hop', + 2023 => 'Music Videos|Hip-Hop/Rap|Khaleeji Hip-Hop', + 2024 => 'Music Videos|Alternative|Indie Levant', + 2025 => 'Music Videos|Alternative|Indie Egyptian', + 2026 => 'Music Videos|Alternative|Indie Maghreb', + 2027 => 'Music Videos|Electronic|Levant Electronic', + 2028 => "Music Videos|Electronic|Electro-Cha'abi", + 2029 => 'Music Videos|Electronic|Maghreb Electronic', + 2030 => 'Music Videos|Folk|Iraqi Folk', + 2031 => 'Music Videos|Folk|Khaleeji Folk', + 2032 => 'Music Videos|Dance|Maghreb Dance', 4000 => 'TV Shows|Comedy', 4001 => 'TV Shows|Drama', 4002 => 'TV Shows|Animation', 4003 => 'TV Shows|Action & Adventure', - 4004 => 'TV Shows|Classic', - 4005 => 'TV Shows|Kids', + 4004 => 'TV Shows|Classics', + 4005 => 'TV Shows|Kids & Family', 4006 => 'TV Shows|Nonfiction', 4007 => 'TV Shows|Reality TV', 4008 => 'TV Shows|Sci-Fi & Fantasy', @@ -3316,9 +4322,11 @@ my %eeBox = ( 6023 => 'App Store|Food & Drink', 6024 => 'App Store|Shopping', 6025 => 'App Store|Stickers', + 6026 => 'App Store|Developer Tools', + 6027 => 'App Store|Graphics & Design', 7001 => 'App Store|Games|Action', 7002 => 'App Store|Games|Adventure', - 7003 => 'App Store|Games|Arcade', + 7003 => 'App Store|Games|Casual', 7004 => 'App Store|Games|Board', 7005 => 'App Store|Games|Card', 7006 => 'App Store|Games|Casino', @@ -3510,8 +4518,8 @@ my %eeBox = ( 8193 => 'Tones|Ringtones|Indian|Indian Pop', 8194 => 'Tones|Ringtones|Indian|Regional Indian', 8195 => 'Tones|Ringtones|Indian|Sufi', - 8196 => 'Tones|Ringtones|Indian|Tamil', - 8197 => 'Tones|Ringtones|Indian|Telugu', + 8196 => 'Tones|Ringtones|Indian|Regional Indian|Tamil', + 8197 => 'Tones|Ringtones|Indian|Regional Indian|Telugu', 8198 => 'Tones|Ringtones|Instrumental', 8199 => 'Tones|Ringtones|Jazz|Avant-Garde Jazz', 8201 => 'Tones|Ringtones|Jazz|Big Band', @@ -3617,11 +4625,11 @@ my %eeBox = ( 8301 => 'Tones|Ringtones|Vocal|Trot', 8302 => 'Tones|Ringtones|Jazz|Vocal Jazz', 8303 => 'Tones|Ringtones|Vocal|Vocal Pop', - 8304 => 'Tones|Ringtones|World|Africa', - 8305 => 'Tones|Ringtones|World|Afrikaans', - 8306 => 'Tones|Ringtones|World|Afro-Beat', - 8307 => 'Tones|Ringtones|World|Afro-Pop', - 8308 => 'Tones|Ringtones|World|Arabesque', + 8304 => 'Tones|Ringtones|African', + 8305 => 'Tones|Ringtones|African|Afrikaans', + 8306 => 'Tones|Ringtones|African|Afro-Beat', + 8307 => 'Tones|Ringtones|African|Afro-Pop', + 8308 => 'Tones|Ringtones|Turkish|Arabesque', 8309 => 'Tones|Ringtones|World|Asia', 8310 => 'Tones|Ringtones|World|Australia', 8311 => 'Tones|Ringtones|World|Cajun', @@ -3637,7 +4645,7 @@ my %eeBox = ( 8321 => 'Tones|Ringtones|World|Farsi', 8322 => 'Tones|Ringtones|World|Flamenco', 8323 => 'Tones|Ringtones|World|France', - 8324 => 'Tones|Ringtones|World|Halk', + 8324 => 'Tones|Ringtones|Turkish|Halk', 8325 => 'Tones|Ringtones|World|Hawaii', 8326 => 'Tones|Ringtones|World|Iberia', 8327 => 'Tones|Ringtones|World|Indonesian Religious', @@ -3646,15 +4654,15 @@ my %eeBox = ( 8330 => 'Tones|Ringtones|World|Klezmer', 8331 => 'Tones|Ringtones|World|North America', 8332 => 'Tones|Ringtones|World|Polka', - 8333 => 'Tones|Ringtones|World|Russian', - 8334 => 'Tones|Ringtones|World|Russian Chanson', - 8335 => 'Tones|Ringtones|World|Sanat', + 8333 => 'Tones|Ringtones|Russian', + 8334 => 'Tones|Ringtones|Russian|Russian Chanson', + 8335 => 'Tones|Ringtones|Turkish|Sanat', 8336 => 'Tones|Ringtones|World|Soca', 8337 => 'Tones|Ringtones|World|South Africa', 8338 => 'Tones|Ringtones|World|South America', 8339 => 'Tones|Ringtones|World|Tango', 8340 => 'Tones|Ringtones|World|Traditional Celtic', - 8341 => 'Tones|Ringtones|World|Turkish', + 8341 => 'Tones|Ringtones|Turkish', 8342 => 'Tones|Ringtones|World|Worldbeat', 8343 => 'Tones|Ringtones|World|Zydeco', 8345 => 'Tones|Ringtones|Classical|Art Song', @@ -3680,6 +4688,88 @@ my %eeBox = ( 8365 => 'Tones|Ringtones|New Age|Yoga', 8366 => 'Tones|Ringtones|Pop|Tribute', 8367 => 'Tones|Ringtones|Pop|Shows', + 8368 => 'Tones|Ringtones|Cuban', + 8369 => 'Tones|Ringtones|Cuban|Mambo', + 8370 => 'Tones|Ringtones|Cuban|Chachacha', + 8371 => 'Tones|Ringtones|Cuban|Guajira', + 8372 => 'Tones|Ringtones|Cuban|Son', + 8373 => 'Tones|Ringtones|Cuban|Bolero', + 8374 => 'Tones|Ringtones|Cuban|Guaracha', + 8375 => 'Tones|Ringtones|Cuban|Timba', + 8376 => 'Tones|Ringtones|Soundtrack|Video Game', + 8377 => 'Tones|Ringtones|Indian|Regional Indian|Punjabi|Punjabi Pop', + 8378 => 'Tones|Ringtones|Indian|Regional Indian|Bengali|Rabindra Sangeet', + 8379 => 'Tones|Ringtones|Indian|Regional Indian|Malayalam', + 8380 => 'Tones|Ringtones|Indian|Regional Indian|Kannada', + 8381 => 'Tones|Ringtones|Indian|Regional Indian|Marathi', + 8382 => 'Tones|Ringtones|Indian|Regional Indian|Gujarati', + 8383 => 'Tones|Ringtones|Indian|Regional Indian|Assamese', + 8384 => 'Tones|Ringtones|Indian|Regional Indian|Bhojpuri', + 8385 => 'Tones|Ringtones|Indian|Regional Indian|Haryanvi', + 8386 => 'Tones|Ringtones|Indian|Regional Indian|Odia', + 8387 => 'Tones|Ringtones|Indian|Regional Indian|Rajasthani', + 8388 => 'Tones|Ringtones|Indian|Regional Indian|Urdu', + 8389 => 'Tones|Ringtones|Indian|Regional Indian|Punjabi', + 8390 => 'Tones|Ringtones|Indian|Regional Indian|Bengali', + 8391 => 'Tones|Ringtones|Indian|Indian Classical|Carnatic Classical', + 8392 => 'Tones|Ringtones|Indian|Indian Classical|Hindustani Classical', + 8393 => 'Tones|Ringtones|African|Afro House', + 8394 => 'Tones|Ringtones|African|Afro Soul', + 8395 => 'Tones|Ringtones|African|Afrobeats', + 8396 => 'Tones|Ringtones|African|Benga', + 8397 => 'Tones|Ringtones|African|Bongo-Flava', + 8398 => 'Tones|Ringtones|African|Coupe-Decale', + 8399 => 'Tones|Ringtones|African|Gqom', + 8400 => 'Tones|Ringtones|African|Highlife', + 8401 => 'Tones|Ringtones|African|Kuduro', + 8402 => 'Tones|Ringtones|African|Kizomba', + 8403 => 'Tones|Ringtones|African|Kwaito', + 8404 => 'Tones|Ringtones|African|Mbalax', + 8405 => 'Tones|Ringtones|African|Ndombolo', + 8406 => 'Tones|Ringtones|African|Shangaan Electro', + 8407 => 'Tones|Ringtones|African|Soukous', + 8408 => 'Tones|Ringtones|African|Taarab', + 8409 => 'Tones|Ringtones|African|Zouglou', + 8410 => 'Tones|Ringtones|Turkish|Ozgun', + 8411 => 'Tones|Ringtones|Turkish|Fantezi', + 8412 => 'Tones|Ringtones|Turkish|Religious', + 8413 => 'Tones|Ringtones|Pop|Turkish Pop', + 8414 => 'Tones|Ringtones|Rock|Turkish Rock', + 8415 => 'Tones|Ringtones|Alternative|Turkish Alternative', + 8416 => 'Tones|Ringtones|Hip-Hop/Rap|Turkish Hip-Hop/Rap', + 8417 => 'Tones|Ringtones|African|Maskandi', + 8418 => 'Tones|Ringtones|Russian|Russian Romance', + 8419 => 'Tones|Ringtones|Russian|Russian Bard', + 8420 => 'Tones|Ringtones|Russian|Russian Pop', + 8421 => 'Tones|Ringtones|Russian|Russian Rock', + 8422 => 'Tones|Ringtones|Russian|Russian Hip-Hop', + 8423 => 'Tones|Ringtones|Arabic|Levant', + 8424 => 'Tones|Ringtones|Arabic|Levant|Dabke', + 8425 => 'Tones|Ringtones|Arabic|Maghreb Rai', + 8426 => 'Tones|Ringtones|Arabic|Khaleeji|Khaleeji Jalsat', + 8427 => 'Tones|Ringtones|Arabic|Khaleeji|Khaleeji Shailat', + 8428 => 'Tones|Ringtones|Tarab', + 8429 => 'Tones|Ringtones|Tarab|Iraqi Tarab', + 8430 => 'Tones|Ringtones|Tarab|Egyptian Tarab', + 8431 => 'Tones|Ringtones|Tarab|Khaleeji Tarab', + 8432 => 'Tones|Ringtones|Pop|Levant Pop', + 8433 => 'Tones|Ringtones|Pop|Iraqi Pop', + 8434 => 'Tones|Ringtones|Pop|Egyptian Pop', + 8435 => 'Tones|Ringtones|Pop|Maghreb Pop', + 8436 => 'Tones|Ringtones|Pop|Khaleeji Pop', + 8437 => 'Tones|Ringtones|Hip-Hop/Rap|Levant Hip-Hop', + 8438 => 'Tones|Ringtones|Hip-Hop/Rap|Egyptian Hip-Hop', + 8439 => 'Tones|Ringtones|Hip-Hop/Rap|Maghreb Hip-Hop', + 8440 => 'Tones|Ringtones|Hip-Hop/Rap|Khaleeji Hip-Hop', + 8441 => 'Tones|Ringtones|Alternative|Indie Levant', + 8442 => 'Tones|Ringtones|Alternative|Indie Egyptian', + 8443 => 'Tones|Ringtones|Alternative|Indie Maghreb', + 8444 => 'Tones|Ringtones|Electronic|Levant Electronic', + 8445 => "Tones|Ringtones|Electronic|Electro-Cha'abi", + 8446 => 'Tones|Ringtones|Electronic|Maghreb Electronic', + 8447 => 'Tones|Ringtones|Folk|Iraqi Folk', + 8448 => 'Tones|Ringtones|Folk|Khaleeji Folk', + 8449 => 'Tones|Ringtones|Dance|Maghreb Dance', 9002 => 'Books|Nonfiction', 9003 => 'Books|Romance', 9004 => 'Books|Travel & Adventure', @@ -3693,7 +4783,7 @@ my %eeBox = ( 9019 => 'Books|Science & Nature', 9020 => 'Books|Sci-Fi & Fantasy', 9024 => 'Books|Lifestyle & Home', - 9025 => 'Books|Health, Mind & Body', + 9025 => 'Books|Self-Development', 9026 => 'Books|Comics & Graphic Novels', 9027 => 'Books|Computers & Internet', 9028 => 'Books|Cookbooks, Food & Wine', @@ -3707,7 +4797,7 @@ my %eeBox = ( 10001 => 'Books|Lifestyle & Home|Antiques & Collectibles', 10002 => 'Books|Arts & Entertainment|Art & Architecture', 10003 => 'Books|Religion & Spirituality|Bibles', - 10004 => 'Books|Health, Mind & Body|Spirituality', + 10004 => 'Books|Self-Development|Spirituality', 10005 => 'Books|Business & Personal Finance|Industries & Professions', 10006 => 'Books|Business & Personal Finance|Marketing & Sales', 10007 => 'Books|Business & Personal Finance|Small Business & Entrepreneurship', @@ -3772,7 +4862,7 @@ my %eeBox = ( 10066 => 'Books|Reference|Foreign Languages', 10067 => 'Books|Arts & Entertainment|Games', 10068 => 'Books|Lifestyle & Home|Gardening', - 10069 => 'Books|Health, Mind & Body|Health & Fitness', + 10069 => 'Books|Self-Development|Health & Fitness', 10070 => 'Books|History|Africa', 10071 => 'Books|History|Americas', 10072 => 'Books|History|Ancient', @@ -3797,7 +4887,7 @@ my %eeBox = ( 10091 => 'Books|Nonfiction|Philosophy', 10092 => 'Books|Arts & Entertainment|Photography', 10093 => 'Books|Fiction & Literature|Poetry', - 10094 => 'Books|Health, Mind & Body|Psychology', + 10094 => 'Books|Self-Development|Psychology', 10095 => 'Books|Reference|Almanacs & Yearbooks', 10096 => 'Books|Reference|Atlases & Maps', 10097 => 'Books|Reference|Catalogs & Directories', @@ -3822,7 +4912,7 @@ my %eeBox = ( 10116 => 'Books|Science & Nature|Life Sciences', 10117 => 'Books|Science & Nature|Physics', 10118 => 'Books|Science & Nature|Reference', - 10119 => 'Books|Health, Mind & Body|Self-Improvement', + 10119 => 'Books|Self-Development|Self-Improvement', 10120 => 'Books|Nonfiction|Social Science', 10121 => 'Books|Sports & Outdoors|Baseball', 10122 => 'Books|Sports & Outdoors|Basketball', @@ -3912,7 +5002,7 @@ my %eeBox = ( 11059 => 'Books|Sports & Outdoors|Motor Sports', 11060 => 'Books|Sports & Outdoors|Rugby', 11061 => 'Books|Sports & Outdoors|Running', - 11062 => 'Books|Health, Mind & Body|Diet & Nutrition', + 11062 => 'Books|Self-Development|Diet & Nutrition', 11063 => 'Books|Science & Nature|Agriculture', 11064 => 'Books|Science & Nature|Atmosphere', 11065 => 'Books|Science & Nature|Biology', @@ -4156,6 +5246,8 @@ my %eeBox = ( 11339 => 'Books|Comics & Graphic Novels|Manga|Girls', 11340 => 'Books|Comics & Graphic Novels|Manga|Women', 11341 => 'Books|Comics & Graphic Novels|Manga|Other', + 11342 => 'Books|Comics & Graphic Novels|Manga|Yaoi', + 11343 => 'Books|Comics & Graphic Novels|Manga|Comic Essays', 12001 => 'Mac App Store|Business', 12002 => 'Mac App Store|Developer Tools', 12003 => 'Mac App Store|Education', @@ -4179,7 +5271,7 @@ my %eeBox = ( 12022 => 'Mac App Store|Graphics & Design', 12201 => 'Mac App Store|Games|Action', 12202 => 'Mac App Store|Games|Adventure', - 12203 => 'Mac App Store|Games|Arcade', + 12203 => 'Mac App Store|Games|Casual', 12204 => 'Mac App Store|Games|Board', 12205 => 'Mac App Store|Games|Card', 12206 => 'Mac App Store|Games|Casino', @@ -4576,15 +5668,97 @@ my %eeBox = ( 100021 => 'Music|New Age|Yoga', 100022 => 'Music|Pop|Tribute', 100023 => 'Music|Pop|Shows', + 100024 => 'Music|Cuban', + 100025 => 'Music|Cuban|Mambo', + 100026 => 'Music|Cuban|Chachacha', + 100027 => 'Music|Cuban|Guajira', + 100028 => 'Music|Cuban|Son', + 100029 => 'Music|Cuban|Bolero', + 100030 => 'Music|Cuban|Guaracha', + 100031 => 'Music|Cuban|Timba', + 100032 => 'Music|Soundtrack|Video Game', + 100033 => 'Music|Indian|Regional Indian|Punjabi|Punjabi Pop', + 100034 => 'Music|Indian|Regional Indian|Bengali|Rabindra Sangeet', + 100035 => 'Music|Indian|Regional Indian|Malayalam', + 100036 => 'Music|Indian|Regional Indian|Kannada', + 100037 => 'Music|Indian|Regional Indian|Marathi', + 100038 => 'Music|Indian|Regional Indian|Gujarati', + 100039 => 'Music|Indian|Regional Indian|Assamese', + 100040 => 'Music|Indian|Regional Indian|Bhojpuri', + 100041 => 'Music|Indian|Regional Indian|Haryanvi', + 100042 => 'Music|Indian|Regional Indian|Odia', + 100043 => 'Music|Indian|Regional Indian|Rajasthani', + 100044 => 'Music|Indian|Regional Indian|Urdu', + 100045 => 'Music|Indian|Regional Indian|Punjabi', + 100046 => 'Music|Indian|Regional Indian|Bengali', + 100047 => 'Music|Indian|Indian Classical|Carnatic Classical', + 100048 => 'Music|Indian|Indian Classical|Hindustani Classical', + 100049 => 'Music|African|Afro House', + 100050 => 'Music|African|Afro Soul', + 100051 => 'Music|African|Afrobeats', + 100052 => 'Music|African|Benga', + 100053 => 'Music|African|Bongo-Flava', + 100054 => 'Music|African|Coupe-Decale', + 100055 => 'Music|African|Gqom', + 100056 => 'Music|African|Highlife', + 100057 => 'Music|African|Kuduro', + 100058 => 'Music|African|Kizomba', + 100059 => 'Music|African|Kwaito', + 100060 => 'Music|African|Mbalax', + 100061 => 'Music|African|Ndombolo', + 100062 => 'Music|African|Shangaan Electro', + 100063 => 'Music|African|Soukous', + 100064 => 'Music|African|Taarab', + 100065 => 'Music|African|Zouglou', + 100066 => 'Music|Turkish|Ozgun', + 100067 => 'Music|Turkish|Fantezi', + 100068 => 'Music|Turkish|Religious', + 100069 => 'Music|Pop|Turkish Pop', + 100070 => 'Music|Rock|Turkish Rock', + 100071 => 'Music|Alternative|Turkish Alternative', + 100072 => 'Music|Hip-Hop/Rap|Turkish Hip-Hop/Rap', + 100073 => 'Music|African|Maskandi', + 100074 => 'Music|Russian|Russian Romance', + 100075 => 'Music|Russian|Russian Bard', + 100076 => 'Music|Russian|Russian Pop', + 100077 => 'Music|Russian|Russian Rock', + 100078 => 'Music|Russian|Russian Hip-Hop', + 100079 => 'Music|Arabic|Levant', + 100080 => 'Music|Arabic|Levant|Dabke', + 100081 => 'Music|Arabic|Maghreb Rai', + 100082 => 'Music|Arabic|Khaleeji|Khaleeji Jalsat', + 100083 => 'Music|Arabic|Khaleeji|Khaleeji Shailat', + 100084 => 'Music|Tarab', + 100085 => 'Music|Tarab|Iraqi Tarab', + 100086 => 'Music|Tarab|Egyptian Tarab', + 100087 => 'Music|Tarab|Khaleeji Tarab', + 100088 => 'Music|Pop|Levant Pop', + 100089 => 'Music|Pop|Iraqi Pop', + 100090 => 'Music|Pop|Egyptian Pop', + 100091 => 'Music|Pop|Maghreb Pop', + 100092 => 'Music|Pop|Khaleeji Pop', + 100093 => 'Music|Hip-Hop/Rap|Levant Hip-Hop', + 100094 => 'Music|Hip-Hop/Rap|Egyptian Hip-Hop', + 100095 => 'Music|Hip-Hop/Rap|Maghreb Hip-Hop', + 100096 => 'Music|Hip-Hop/Rap|Khaleeji Hip-Hop', + 100097 => 'Music|Alternative|Indie Levant', + 100098 => 'Music|Alternative|Indie Egyptian', + 100099 => 'Music|Alternative|Indie Maghreb', + 100100 => 'Music|Electronic|Levant Electronic', + 100101 => "Music|Electronic|Electro-Cha'abi", + 100102 => 'Music|Electronic|Maghreb Electronic', + 100103 => 'Music|Folk|Iraqi Folk', + 100104 => 'Music|Folk|Khaleeji Folk', + 100105 => 'Music|Dance|Maghreb Dance', 40000000 => 'iTunes U', - 40000001 => 'iTunes U|Business', - 40000002 => 'iTunes U|Business|Economics', - 40000003 => 'iTunes U|Business|Finance', - 40000004 => 'iTunes U|Business|Hospitality', - 40000005 => 'iTunes U|Business|Management', - 40000006 => 'iTunes U|Business|Marketing', - 40000007 => 'iTunes U|Business|Personal Finance', - 40000008 => 'iTunes U|Business|Real Estate', + 40000001 => 'iTunes U|Business & Economics', + 40000002 => 'iTunes U|Business & Economics|Economics', + 40000003 => 'iTunes U|Business & Economics|Finance', + 40000004 => 'iTunes U|Business & Economics|Hospitality', + 40000005 => 'iTunes U|Business & Economics|Management', + 40000006 => 'iTunes U|Business & Economics|Marketing', + 40000007 => 'iTunes U|Business & Economics|Personal Finance', + 40000008 => 'iTunes U|Business & Economics|Real Estate', 40000009 => 'iTunes U|Engineering', 40000010 => 'iTunes U|Engineering|Chemical & Petroleum Engineering', 40000011 => 'iTunes U|Engineering|Civil Engineering', @@ -4592,15 +5766,15 @@ my %eeBox = ( 40000013 => 'iTunes U|Engineering|Electrical Engineering', 40000014 => 'iTunes U|Engineering|Environmental Engineering', 40000015 => 'iTunes U|Engineering|Mechanical Engineering', - 40000016 => 'iTunes U|Art & Architecture', - 40000017 => 'iTunes U|Art & Architecture|Architecture', - 40000019 => 'iTunes U|Art & Architecture|Art History', - 40000020 => 'iTunes U|Art & Architecture|Dance', - 40000021 => 'iTunes U|Art & Architecture|Film', - 40000022 => 'iTunes U|Art & Architecture|Design', - 40000023 => 'iTunes U|Art & Architecture|Interior Design', - 40000024 => 'iTunes U|Art & Architecture|Music', - 40000025 => 'iTunes U|Art & Architecture|Theater', + 40000016 => 'iTunes U|Music, Art, & Design', + 40000017 => 'iTunes U|Music, Art, & Design|Architecture', + 40000019 => 'iTunes U|Music, Art, & Design|Art History', + 40000020 => 'iTunes U|Music, Art, & Design|Dance', + 40000021 => 'iTunes U|Music, Art, & Design|Film', + 40000022 => 'iTunes U|Music, Art, & Design|Design', + 40000023 => 'iTunes U|Music, Art, & Design|Interior Design', + 40000024 => 'iTunes U|Music, Art, & Design|Music', + 40000025 => 'iTunes U|Music, Art, & Design|Theater', 40000026 => 'iTunes U|Health & Medicine', 40000027 => 'iTunes U|Health & Medicine|Anatomy & Physiology', 40000028 => 'iTunes U|Health & Medicine|Behavioral Science', @@ -4627,26 +5801,26 @@ my %eeBox = ( 40000049 => 'iTunes U|History|Middle Eastern History', 40000050 => 'iTunes U|History|North American History', 40000051 => 'iTunes U|History|South American History', - 40000053 => 'iTunes U|Communications & Media', + 40000053 => 'iTunes U|Communications & Journalism', 40000054 => 'iTunes U|Philosophy', 40000055 => 'iTunes U|Religion & Spirituality', - 40000056 => 'iTunes U|Language', - 40000057 => 'iTunes U|Language|African Languages', - 40000058 => 'iTunes U|Language|Ancient Languages', - 40000061 => 'iTunes U|Language|English', - 40000063 => 'iTunes U|Language|French', - 40000064 => 'iTunes U|Language|German', - 40000065 => 'iTunes U|Language|Italian', - 40000066 => 'iTunes U|Language|Linguistics', - 40000068 => 'iTunes U|Language|Spanish', - 40000069 => 'iTunes U|Language|Speech Pathology', - 40000070 => 'iTunes U|Literature', - 40000071 => 'iTunes U|Literature|Anthologies', - 40000072 => 'iTunes U|Literature|Biography', - 40000073 => 'iTunes U|Literature|Classics', - 40000074 => 'iTunes U|Literature|Literary Criticism', - 40000075 => 'iTunes U|Literature|Fiction', - 40000076 => 'iTunes U|Literature|Poetry', + 40000056 => 'iTunes U|Languages', + 40000057 => 'iTunes U|Languages|African Languages', + 40000058 => 'iTunes U|Languages|Ancient Languages', + 40000061 => 'iTunes U|Languages|English', + 40000063 => 'iTunes U|Languages|French', + 40000064 => 'iTunes U|Languages|German', + 40000065 => 'iTunes U|Languages|Italian', + 40000066 => 'iTunes U|Languages|Linguistics', + 40000068 => 'iTunes U|Languages|Spanish', + 40000069 => 'iTunes U|Languages|Speech Pathology', + 40000070 => 'iTunes U|Writing & Literature', + 40000071 => 'iTunes U|Writing & Literature|Anthologies', + 40000072 => 'iTunes U|Writing & Literature|Biography', + 40000073 => 'iTunes U|Writing & Literature|Classics', + 40000074 => 'iTunes U|Writing & Literature|Literary Criticism', + 40000075 => 'iTunes U|Writing & Literature|Fiction', + 40000076 => 'iTunes U|Writing & Literature|Poetry', 40000077 => 'iTunes U|Mathematics', 40000078 => 'iTunes U|Mathematics|Advanced Mathematics', 40000079 => 'iTunes U|Mathematics|Algebra', @@ -4664,13 +5838,13 @@ my %eeBox = ( 40000091 => 'iTunes U|Science|Geography', 40000092 => 'iTunes U|Science|Geology', 40000093 => 'iTunes U|Science|Physics', - 40000094 => 'iTunes U|Psychology & Social Science', + 40000094 => 'iTunes U|Social Science', 40000095 => 'iTunes U|Law & Politics|Law', 40000096 => 'iTunes U|Law & Politics|Political Science', 40000097 => 'iTunes U|Law & Politics|Public Administration', - 40000098 => 'iTunes U|Psychology & Social Science|Psychology', - 40000099 => 'iTunes U|Psychology & Social Science|Social Welfare', - 40000100 => 'iTunes U|Psychology & Social Science|Sociology', + 40000098 => 'iTunes U|Social Science|Psychology', + 40000099 => 'iTunes U|Social Science|Social Welfare', + 40000100 => 'iTunes U|Social Science|Sociology', 40000101 => 'iTunes U|Society', 40000103 => 'iTunes U|Society|Asia Pacific Studies', 40000104 => 'iTunes U|Society|European Studies', @@ -4685,36 +5859,36 @@ my %eeBox = ( 40000113 => 'iTunes U|Teaching & Learning|Learning Resources', 40000114 => 'iTunes U|Teaching & Learning|Psychology & Research', 40000115 => 'iTunes U|Teaching & Learning|Special Education', - 40000116 => 'iTunes U|Art & Architecture|Culinary Arts', - 40000117 => 'iTunes U|Art & Architecture|Fashion', - 40000118 => 'iTunes U|Art & Architecture|Media Arts', - 40000119 => 'iTunes U|Art & Architecture|Photography', - 40000120 => 'iTunes U|Art & Architecture|Visual Art', - 40000121 => 'iTunes U|Business|Entrepreneurship', - 40000122 => 'iTunes U|Communications & Media|Broadcasting', - 40000123 => 'iTunes U|Communications & Media|Digital Media', - 40000124 => 'iTunes U|Communications & Media|Journalism', - 40000125 => 'iTunes U|Communications & Media|Photojournalism', - 40000126 => 'iTunes U|Communications & Media|Print', - 40000127 => 'iTunes U|Communications & Media|Speech', - 40000128 => 'iTunes U|Communications & Media|Writing', + 40000116 => 'iTunes U|Music, Art, & Design|Culinary Arts', + 40000117 => 'iTunes U|Music, Art, & Design|Fashion', + 40000118 => 'iTunes U|Music, Art, & Design|Media Arts', + 40000119 => 'iTunes U|Music, Art, & Design|Photography', + 40000120 => 'iTunes U|Music, Art, & Design|Visual Art', + 40000121 => 'iTunes U|Business & Economics|Entrepreneurship', + 40000122 => 'iTunes U|Communications & Journalism|Broadcasting', + 40000123 => 'iTunes U|Communications & Journalism|Digital Media', + 40000124 => 'iTunes U|Communications & Journalism|Journalism', + 40000125 => 'iTunes U|Communications & Journalism|Photojournalism', + 40000126 => 'iTunes U|Communications & Journalism|Print', + 40000127 => 'iTunes U|Communications & Journalism|Speech', + 40000128 => 'iTunes U|Communications & Journalism|Writing', 40000129 => 'iTunes U|Health & Medicine|Nursing', - 40000130 => 'iTunes U|Language|Arabic', - 40000131 => 'iTunes U|Language|Chinese', - 40000132 => 'iTunes U|Language|Hebrew', - 40000133 => 'iTunes U|Language|Hindi', - 40000134 => 'iTunes U|Language|Indigenous Languages', - 40000135 => 'iTunes U|Language|Japanese', - 40000136 => 'iTunes U|Language|Korean', - 40000137 => 'iTunes U|Language|Other Languages', - 40000138 => 'iTunes U|Language|Portuguese', - 40000139 => 'iTunes U|Language|Russian', + 40000130 => 'iTunes U|Languages|Arabic', + 40000131 => 'iTunes U|Languages|Chinese', + 40000132 => 'iTunes U|Languages|Hebrew', + 40000133 => 'iTunes U|Languages|Hindi', + 40000134 => 'iTunes U|Languages|Indigenous Languages', + 40000135 => 'iTunes U|Languages|Japanese', + 40000136 => 'iTunes U|Languages|Korean', + 40000137 => 'iTunes U|Languages|Other Languages', + 40000138 => 'iTunes U|Languages|Portuguese', + 40000139 => 'iTunes U|Languages|Russian', 40000140 => 'iTunes U|Law & Politics', 40000141 => 'iTunes U|Law & Politics|Foreign Policy & International Relations', 40000142 => 'iTunes U|Law & Politics|Local Governments', 40000143 => 'iTunes U|Law & Politics|National Governments', 40000144 => 'iTunes U|Law & Politics|World Affairs', - 40000145 => 'iTunes U|Literature|Comparative Literature', + 40000145 => 'iTunes U|Writing & Literature|Comparative Literature', 40000146 => 'iTunes U|Philosophy|Aesthetics', 40000147 => 'iTunes U|Philosophy|Epistemology', 40000148 => 'iTunes U|Philosophy|Ethics', @@ -4723,8 +5897,8 @@ my %eeBox = ( 40000151 => 'iTunes U|Philosophy|Logic', 40000152 => 'iTunes U|Philosophy|Philosophy of Language', 40000153 => 'iTunes U|Philosophy|Philosophy of Religion', - 40000154 => 'iTunes U|Psychology & Social Science|Archaeology', - 40000155 => 'iTunes U|Psychology & Social Science|Anthropology', + 40000154 => 'iTunes U|Social Science|Archaeology', + 40000155 => 'iTunes U|Social Science|Anthropology', 40000156 => 'iTunes U|Religion & Spirituality|Buddhism', 40000157 => 'iTunes U|Religion & Spirituality|Christianity', 40000158 => 'iTunes U|Religion & Spirituality|Comparative Religion', @@ -4742,20 +5916,20 @@ my %eeBox = ( 40000170 => 'iTunes U|Society|Sexuality Studies', 40000171 => 'iTunes U|Teaching & Learning|Educational Technology', 40000172 => 'iTunes U|Teaching & Learning|Information/Library Science', - 40000173 => 'iTunes U|Language|Dutch', - 40000174 => 'iTunes U|Language|Luxembourgish', - 40000175 => 'iTunes U|Language|Swedish', - 40000176 => 'iTunes U|Language|Norwegian', - 40000177 => 'iTunes U|Language|Finnish', - 40000178 => 'iTunes U|Language|Danish', - 40000179 => 'iTunes U|Language|Polish', - 40000180 => 'iTunes U|Language|Turkish', - 40000181 => 'iTunes U|Language|Flemish', + 40000173 => 'iTunes U|Languages|Dutch', + 40000174 => 'iTunes U|Languages|Luxembourgish', + 40000175 => 'iTunes U|Languages|Swedish', + 40000176 => 'iTunes U|Languages|Norwegian', + 40000177 => 'iTunes U|Languages|Finnish', + 40000178 => 'iTunes U|Languages|Danish', + 40000179 => 'iTunes U|Languages|Polish', + 40000180 => 'iTunes U|Languages|Turkish', + 40000181 => 'iTunes U|Languages|Flemish', 50000024 => 'Audiobooks', 50000040 => 'Audiobooks|Fiction', 50000041 => 'Audiobooks|Arts & Entertainment', - 50000042 => 'Audiobooks|Biography & Memoir', - 50000043 => 'Audiobooks|Business', + 50000042 => 'Audiobooks|Biographies & Memoirs', + 50000043 => 'Audiobooks|Business & Personal Finance', 50000044 => 'Audiobooks|Kids & Young Adults', 50000045 => 'Audiobooks|Classics', 50000046 => 'Audiobooks|Comedy', @@ -4763,13 +5937,13 @@ my %eeBox = ( 50000048 => 'Audiobooks|Speakers & Storytellers', 50000049 => 'Audiobooks|History', 50000050 => 'Audiobooks|Languages', - 50000051 => 'Audiobooks|Mystery', + 50000051 => 'Audiobooks|Mysteries & Thrillers', 50000052 => 'Audiobooks|Nonfiction', 50000053 => 'Audiobooks|Religion & Spirituality', - 50000054 => 'Audiobooks|Science', + 50000054 => 'Audiobooks|Science & Nature', 50000055 => 'Audiobooks|Sci Fi & Fantasy', - 50000056 => 'Audiobooks|Self Development', - 50000057 => 'Audiobooks|Sports', + 50000056 => 'Audiobooks|Self-Development', + 50000057 => 'Audiobooks|Sports & Outdoors', 50000058 => 'Audiobooks|Technology', 50000059 => 'Audiobooks|Travel & Adventure', 50000061 => 'Music|Spoken Word', @@ -4800,28 +5974,37 @@ my %eeBox = ( 50000089 => 'Books|Comics & Graphic Novels|Manga|Horror', 50000090 => 'Books|Comics & Graphic Novels|Comics', 50000091 => 'Books|Romance|Multicultural', + 50000092 => 'Audiobooks|Erotica', + 50000093 => 'Audiobooks|Light Novels', }, }, - grup => 'Grouping', #10 + grup => { Name => 'Grouping', Avoid => 1 }, #10 hdvd => { #10 Name => 'HDVideo', + Format => 'int8u', #24 + Writable => 'int8s', #27 PrintConv => { 0 => 'No', 1 => 'Yes' }, }, keyw => 'Keyword', #7 ldes => 'LongDescription', #10 pcst => { #7 Name => 'Podcast', + Format => 'int8u', #23 + Writable => 'int8s', #27 PrintConv => { 0 => 'No', 1 => 'Yes' }, }, perf => 'Performer', plID => { #10 (or TV season) Name => 'PlayListID', Format => 'int8u', # actually int64u, but split it up + Writable => 'int32s', #27 }, purd => 'PurchaseDate', #7 purl => 'PodcastURL', #7 rtng => { #10 Name => 'Rating', + Format => 'int8u', #23 + Writable => 'int8s', #27 PrintConv => { 0 => 'none', 1 => 'Explicit', @@ -4832,6 +6015,7 @@ my %eeBox = ( sfID => { #10 Name => 'AppleStoreCountry', Format => 'int32u', + Writable => 'int32s', #27 SeparateTable => 1, PrintConv => { #21 143441 => 'United States', # US @@ -4999,6 +6183,8 @@ my %eeBox = ( sosn => 'SortShow', #10 stik => { #10 Name => 'MediaType', + Format => 'int8u', #23 + Writable => 'int8s', #27 PrintConvColumns => 2, PrintConv => { #(http://weblog.xanga.com/gryphondwb/615474010/iphone-ringtones---what-did-itunes-741-really-do.html) 0 => 'Movie (old)', #forum9059 (was Movie) @@ -5015,11 +6201,12 @@ my %eeBox = ( }, }, rate => 'RatingPercent', #PH - titl => 'Title', + titl => { Name => 'Title', Avoid => 1 }, tven => 'TVEpisodeID', #7 tves => { #7/10 Name => 'TVEpisode', Format => 'int32u', + Writable => 'int32s', #27 }, tvnn => 'TVNetworkName', #7 tvsh => 'TVShow', #10 @@ -5030,6 +6217,8 @@ my %eeBox = ( yrrc => 'Year', #(ffmpeg source) itnu => { #PH (iTunes 10.5) Name => 'iTunesU', + Format => 'int8u', #27 + Writable => 'int8s', #27 Description => 'iTunes U', PrintConv => { 0 => 'No', 1 => 'Yes' }, }, @@ -5039,10 +6228,24 @@ my %eeBox = ( gspu => { Name => 'GooglePingURL', Format => 'string' }, gssd => { Name => 'GoogleSourceData', Format => 'string' }, gsst => { Name => 'GoogleStartTime', Format => 'string' }, - gstd => { Name => 'GoogleTrackDuration',Format => 'string', ValueConv => '$val / 1000', PrintConv => 'ConvertDuration($val)' }, + gstd => { + Name => 'GoogleTrackDuration', + Format => 'string', + ValueConv => '$val / 1000', + ValueConvInv => '$val * 1000', + PrintConv => 'ConvertDuration($val)', + PrintConvInv => q{ + $val =~ s/ s$//; + my @a = split /(:| days )/, $val; + my $sign = ($val =~ s/^-//) ? -1 : 1; + $a[0] += shift(@a) * 24 if @a == 4; + $a[0] += shift(@a) * 60 while @a > 1; + return $a[0] * $sign; + }, + }, # atoms observed in AAX audiobooks (ref PH) - "\xa9cpy" => { Name => 'Copyright', Groups => { 2 => 'Author' } }, + "\xa9cpy" => { Name => 'Copyright', Avoid => 1, Groups => { 2 => 'Author' } }, "\xa9pub" => 'Publisher', "\xa9nrt" => 'Narrator', '@pti' => 'ParentTitle', # (guess -- same as "\xa9nam") @@ -5057,6 +6260,35 @@ my %eeBox = ( GUID => 'GUID', AACR => { Name => 'Unknown_AACR', Unknown => 1 }, # eg: "CR!1T1H1QH6WX7T714G2BMFX3E9MC4S" # ausr - 30 bytes (User Alias?) + "\xa9xyz" => { #PH (written by Google Photos) + Name => 'GPSCoordinates', + Groups => { 2 => 'Location' }, + ValueConv => \&ConvertISO6709, + ValueConvInv => \&ConvInvISO6709, + PrintConv => \&PrintGPSCoordinates, + PrintConvInv => \&PrintInvGPSCoordinates, + }, + # the following tags written by iTunes 12.5.1.21 + # (ref https://www.ventismedia.com/mantis/view.php?id=14963 + # https://community.mp3tag.de/t/x-mp4-new-tag-problems/19488) + "\xa9wrk" => 'Work', #PH + "\xa9mvn" => 'MovementName', #PH + "\xa9mvi" => { #PH + Name => 'MovementNumber', + Format => 'int16u', #27 + Writable => 'int16s', #27 + }, + "\xa9mvc" => { #PH + Name => 'MovementCount', + Format => 'int16u', #27 + Writable => 'int16s', #27 + }, + shwm => { #PH + Name => 'ShowMovement', + Format => 'int8u', #27 + Writable => 'int8s', #27 + PrintConv => { 0 => 'No', 1 => 'Yes' }, + }, ); # tag decoded from timed face records @@ -5086,12 +6318,29 @@ my %eeBox = ( # item list keys (ref PH) %Image::ExifTool::QuickTime::Keys = ( - PROCESS_PROC => \&Image::ExifTool::QuickTime::ProcessKeys, - VARS => { LONG_TAGS => 3 }, + PROCESS_PROC => \&ProcessKeys, + WRITE_PROC => \&WriteKeys, + CHECK_PROC => \&CheckQTValue, + VARS => { LONG_TAGS => 7 }, + WRITABLE => 1, + # (not PREFERRED when writing) + GROUPS => { 1 => 'Keys' }, + WRITE_GROUP => 'Keys', + LANG_INFO => \&GetLangInfo, NOTES => q{ - This directory contains a list of key names which are used to decode - ItemList tags written by the "mdta" handler. The prefix of - "com.apple.quicktime." has been removed from all TagID's below. + This directory contains a list of key names which are used to decode tags + written by the "mdta" handler. Also in this table are a few tags found in + timed metadata that are not yet writable by ExifTool. The prefix of + "com.apple.quicktime." has been removed from the TagID's below. These tags + support alternate languages in the same way as the + L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> tags. Note + that by default, + L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> and + L<UserData|Image::ExifTool::TagNames/QuickTime UserData Tags> tags are + preferred when writing, so to create a tag when a same-named tag exists in + either of these tables, either the "Keys" location must be specified (eg. + C<-Keys:Author=Phil> on the command line), or the PREFERRED level must be + changed via L<the config file|../config.html#PREF>. }, version => 'Version', album => 'Album', @@ -5103,16 +6352,25 @@ my %eeBox = ( creationdate=> { Name => 'CreationDate', Groups => { 2 => 'Time' }, + Shift => 'Time', ValueConv => q{ require Image::ExifTool::XMP; $val = Image::ExifTool::XMP::ConvertXMPDate($val,1); $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary return $val; }, + ValueConvInv => q{ + require Image::ExifTool::XMP; + $val = Image::ExifTool::XMP::FormatXMPDate($val); + $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon + return $val; + }, PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) }, description => { }, director => { }, + displayname => { Name => 'DisplayName' }, title => { }, #22 genre => { }, information => { }, @@ -5127,13 +6385,21 @@ my %eeBox = ( 'camera.framereadouttimeinmicroseconds' => { # (iPhone 4) Name => 'FrameReadoutTime', ValueConv => '$val * 1e-6', + ValueConvInv => 'int($val * 1e6 + 0.5)', PrintConv => '$val * 1e6 . " microseconds"', + PrintConvInv => '$val =~ s/ .*//; $val * 1e-6', }, 'location.ISO6709' => { Name => 'GPSCoordinates', Groups => { 2 => 'Location' }, + Notes => q{ + Google Photos may ignore this if the coorinates have more than 5 digits + after the decimal + }, ValueConv => \&ConvertISO6709, + ValueConvInv => \&ConvInvISO6709, PrintConv => \&PrintGPSCoordinates, + PrintConvInv => \&PrintInvGPSCoordinates, }, 'location.name' => { Name => 'LocationName', Groups => { 2 => 'Location' } }, 'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } }, @@ -5150,24 +6416,37 @@ my %eeBox = ( 'location.date' => { Name => 'LocationDate', Groups => { 2 => 'Time' }, + Shift => 'Time', ValueConv => q{ require Image::ExifTool::XMP; $val = Image::ExifTool::XMP::ConvertXMPDate($val); $val =~ s/([-+]\d{2})(\d{2})$/$1:$2/; # add colon to timezone if necessary return $val; }, + ValueConvInv => q{ + require Image::ExifTool::XMP; + $val = Image::ExifTool::XMP::FormatXMPDate($val); + $val =~ s/([-+]\d{2}):(\d{2})$/$1$2/; # remove time zone colon + return $val; + }, PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val,1)', # (add time zone if it didn't exist) }, + 'location.accuracy.horizontal' => { Name => 'LocationAccuracyHorizontal' }, + 'live-photo.auto' => { Name => 'LivePhotoAuto', Writable => 'int8u' }, + 'live-photo.vitality-score' => { Name => 'LivePhotoVitalityScore', Writable => 'float' }, + 'live-photo.vitality-scoring-version' => { Name => 'LivePhotoVitalityScoringVersion', Writable => 'int64s' }, + 'apple.photos.variation-identifier' => { Name => 'ApplePhotosVariationIdentifier', Writable => 'int64s' }, 'direction.facing' => { Name => 'CameraDirection', Groups => { 2 => 'Location' } }, - 'direction.motion' => { Name => 'CameraMotion', Groups => { 2 => 'Location' } }, - 'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } }, + 'direction.motion' => { Name => 'CameraMotion', Groups => { 2 => 'Location' } }, + 'location.body' => { Name => 'LocationBody', Groups => { 2 => 'Location' } }, 'player.version' => 'PlayerVersion', 'player.movie.visual.brightness'=> 'Brightness', 'player.movie.visual.color' => 'Color', 'player.movie.visual.tint' => 'Tint', 'player.movie.visual.contrast' => 'Contrast', 'player.movie.audio.gain' => 'AudioGain', - 'player.movie.audio.treble' => 'Trebel', + 'player.movie.audio.treble' => 'Treble', 'player.movie.audio.bass' => 'Bass', 'player.movie.audio.balance' => 'Balance', 'player.movie.audio.pitchshift' => 'PitchShift', @@ -5180,38 +6459,93 @@ my %eeBox = ( 'collection.user' => 'UserCollection', #22 'Encoded_With' => 'EncodedWith', # -# seen in timed metadata (mebx), and added dynamically via SaveMetaKeys() (ref PH): +# the following tags aren't in the com.apple.quicktime namespace: +# + 'com.apple.photos.captureMode' => 'CaptureMode', + 'com.android.version' => 'AndroidVersion', +# +# also seen +# + # com.divergentmedia.clipwrap.model ('NEX-FS700EK') + # com.divergentmedia.clipwrap.model1 ('49') + # com.divergentmedia.clipwrap.model2 ('0') + # com.divergentmedia.clipwrap.manufacturer ('Sony') + # com.divergentmedia.clipwrap.originalDateTime ('2013/2/6 10:30:40+0200') +# +# seen in timed metadata (mebx), and added dynamically to the table via SaveMetaKeys() +# NOTE: these tags are not writable! (timed metadata cannot yet be written) # # (mdta)com.apple.quicktime.video-orientation (dtyp=66, int16s) - 'video-orientation' => 'VideoOrientation', + 'video-orientation' => { + Name => 'VideoOrientation', + Writable => 0, + PrintConv => \%Image::ExifTool::Exif::orientation, #PH (NC) + }, + # (mdta)com.apple.quicktime.live-photo-info (dtyp=com.apple.quicktime.com.apple.quicktime.live-photo-info) + 'live-photo-info' => { + Name => 'LivePhotoInfo', + Writable => 0, + # not sure what these values mean, but unpack them anyway - PH + # (ignore the fact that the "f" and "l" unpacks won't work on a big-endian machine) + ValueConv => 'join " ",unpack "VfVVf6c4lCCcclf4Vvv", $val', + }, + # (mdta)com.apple.quicktime.still-image-time (dtyp=65, int8s) + 'still-image-time' => { # (found in live photo) + Name => 'StillImageTime', + Writable => 0, + Notes => q{ + this tag always has a value of -1; the time of the still image is obtained + from the associated SampleTime + }, + }, # (mdta)com.apple.quicktime.detected-face (dtyp='com.apple.quicktime.detected-face') 'detected-face' => { Name => 'FaceInfo', + Writable => 0, SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::FaceInfo' }, }, - # ---- detected-face fields ---- + # ---- detected-face fields ( ---- # --> back here after a round trip through FaceInfo -> FaceRec -> FaceItem # (fiel)com.apple.quicktime.detected-face.bounds (dtyp=80, float[8]) 'detected-face.bounds' => { Name => 'DetectedFaceBounds', + Writable => 0, # round to a reasonable number of decimal places PrintConv => 'my @a=split " ",$val;$_=int($_*1e6+.5)/1e6 foreach @a;join " ",@a', + PrintConvInv => '$val', }, # (fiel)com.apple.quicktime.detected-face.face-id (dtyp=77, int32u) - 'detected-face.face-id' => 'DetectedFaceID', + 'detected-face.face-id' => { Name => 'DetectedFaceID', Writable => 0 }, # (fiel)com.apple.quicktime.detected-face.roll-angle (dtyp=23, float) - 'detected-face.roll-angle' => 'DetectedFaceRollAngle', + 'detected-face.roll-angle' => { Name => 'DetectedFaceRollAngle', Writable => 0 }, # (fiel)com.apple.quicktime.detected-face.yaw-angle (dtyp=23, float) - 'detected-face.yaw-angle' => 'DetectedFaceYawAngle', + 'detected-face.yaw-angle' => { Name => 'DetectedFaceYawAngle', Writable => 0 }, +# +# seen in Apple ProRes RAW file +# + # (mdta)com.apple.proapps.manufacturer (eg. "Sony") + # (mdta)com.apple.proapps.exif.{Exif}.FNumber (float, eg. 1.0) + # (mdta)org.smpte.rdd18.lens.irisfnumber (eg. "F1.0") + # (mdta)com.apple.proapps.exif.{Exif}.ShutterSpeedValue (float, eg. 1.006) + # (mdta)org.smpte.rdd18.camera.shutterspeed_angle (eg. "179.2deg") + # (mdta)org.smpte.rdd18.camera.neutraldensityfilterwheelsetting (eg. "ND1") + # (mdta)org.smpte.rdd18.camera.whitebalance (eg. "4300K") + # (mdta)com.apple.proapps.exif.{Exif}.ExposureIndex (float, eg. 4000) + # (mdta)org.smpte.rdd18.camera.isosensitivity (eg. "4000") + # (mdta)com.apple.proapps.image.{TIFF}.Make (eg. "Atmos") + # (mdta)com.apple.proapps.image.{TIFF}.Model (eg. "ShogunInferno") + # (mdta)com.apple.proapps.image.{TIFF}.Software (eg. "9.0") ); # iTunes info ('----') atoms %Image::ExifTool::QuickTime::iTunesInfo = ( PROCESS_PROC => \&ProcessMOV, - GROUPS => { 2 => 'Audio' }, + GROUPS => { 1 => 'iTunes', 2 => 'Audio' }, + VARS => { LONG_TAGS => 0 }, # (hack for discrepancy in the way long tags are counted in BuildTagLookup) NOTES => q{ ExifTool will extract any iTunesInfo tags that exist, even if they are not - defined in this table. + defined in this table. These tags belong to the family 1 "iTunes" group, + and are not currently writable. }, # 'mean'/'name'/'data' atoms form a triplet, but unfortunately # I haven't been able to find any documentation on this. @@ -5272,9 +6606,45 @@ my %eeBox = ( SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::EncodingParams' }, }, # also heard about 'iTunPGAP', but I haven't seen a sample - DISCNUMBER => 'DiscNumber', #PH - TRACKNUMBER => 'TrackNumber', #PH - popularimeter => 'Popularimeter', #PH + # all tags below were added based on samples I have seen - PH + DISCNUMBER => 'DiscNumber', + TRACKNUMBER => 'TrackNumber', + ARTISTS => 'Artists', + CATALOGNUMBER => 'CatalogNumber', + RATING => 'Rating', + MEDIA => 'Media', + SCRIPT => 'Script', # character set? (seen 'Latn') + BARCODE => 'Barcode', + LABEL => 'Label', + MOOD => 'Mood', + popularimeter => 'Popularimeter', + 'Dynamic Range (DR)'=> 'DynamicRange', + initialkey => 'InitialKey', + originalyear => 'OriginalYear', + originaldate => 'OriginalDate', + '~length' => 'Length', # play length? (ie. duration?) + replaygain_track_gain=>'ReplayTrackGain', + replaygain_track_peak=>'ReplayTrackPeak', + 'Volume Level (ReplayGain)'=> 'ReplayVolumeLevel', + 'Dynamic Range (R128)'=> 'DynamicRangeR128', + 'Volume Level (R128)' => 'VolumeLevelR128', + 'Peak Level (Sample)' => 'PeakLevelSample', + 'Peak Level (R128)' => 'PeakLevelR128', + # also seen (many from forum12777): + # 'MusicBrainz Album Release Country' + # 'MusicBrainz Album Type' + # 'MusicBrainz Album Status' + # 'MusicBrainz Track Id' + # 'MusicBrainz Release Track Id' + # 'MusicBrainz Album Id' + # 'MusicBrainz Album Artist Id' + # 'MusicBrainz Artist Id' + # 'Acoustid Id' (sic) + # 'Tool Version' + # 'Tool Name' + # 'ISRC' + # 'HDCD' + # 'Waveform' ); # iTunes audio encoding parameters @@ -5489,7 +6859,7 @@ my %eeBox = ( Format => 'int16u', RawConv => '$val ? $val : undef', # allow both Macintosh (for MOV files) and ISO (for MP4 files) language codes - ValueConv => '$val < 0x400 ? $val : pack "C*", map { (($val>>$_)&0x1f)+0x60 } 10, 5, 0', + ValueConv => '($val < 0x400 or $val == 0x7fff) ? $val : pack "C*", map { (($val>>$_)&0x1f)+0x60 } 10, 5, 0', PrintConv => q{ return $val unless $val =~ /^\d+$/; require Image::ExifTool::Font; @@ -5521,7 +6891,7 @@ my %eeBox = ( Flags => ['Binary','Unknown'], }, dinf => { - Name => 'DataInfo', + Name => 'DataInfo', # (don't change this name -- used to recognize directory when writing) SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::DataInfo' }, }, gmhd => { @@ -5683,6 +7053,12 @@ my %eeBox = ( sgpd => { Name => 'SampleGroupDescription', Flags => ['Binary','Unknown'], + # bytes 4-7 give grouping type (ref ISO/IEC 14496-15:2014) + # tsas - temporal sublayer sample + # stsa - step-wise temporal layer access + # avss - AVC sample + # tscl - temporal layer scalability + # sync - sync sample }, subs => { Name => 'Sub-sampleInformation', @@ -5718,6 +7094,8 @@ my %eeBox = ( $self->OverrideFileType('M4P') if $val eq 'drms' and $$self{VALUE}{FileType} eq 'M4A'; return $val; }, + # see this link for print conversions (not complete): + # https://github.com/yannickcr/brooser/blob/master/php/librairies/getid3/module.audio-video.quicktime.php }, 20 => { #PH Name => 'AudioVendorID', @@ -5735,7 +7113,7 @@ my %eeBox = ( # # AudioFormat Offset Child atoms # ----------- ------ ---------------- -# mp4a 52 * wave, chan, esds +# mp4a 52 * wave, chan, esds, SA3D(Insta360 spherical video params?,also GoPro Max) # in24 52 wave, chan # "ms\0\x11" 52 wave # sowt 52 chan @@ -5772,6 +7150,7 @@ my %eeBox = ( # alac - 28 bytes # adrm - AAX DRM atom? 148 bytes # aabd - AAX unknown 17kB (contains 'aavd' strings) + # SA3D - written by Garmin VIRB360 ); # AMR decode config box (ref 3) @@ -5802,13 +7181,28 @@ my %eeBox = ( Name => 'SchemeInfo', SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::SchemeInfo' }, }, + enda => { + Name => 'Endianness', + Format => 'int16u', + PrintConv => { + 0 => 'Big-endian (Motorola, MM)', + 1 => 'Little-endian (Intel, II)', + }, + }, # skcr - # enda ); %Image::ExifTool::QuickTime::Wave = ( PROCESS_PROC => \&ProcessMOV, frma => 'PurchaseFileFormat', + enda => { + Name => 'Endianness', + Format => 'int16u', + PrintConv => { + 0 => 'Big-endian (Motorola, MM)', + 1 => 'Little-endian (Intel, II)', + }, + }, # "ms\0\x11" - 20 bytes ); @@ -6198,6 +7592,12 @@ my %eeBox = ( Format => 'undef[4]', RawConv => '$$self{MetaFormat} = $val', }, + 8 => { # starts at 8 for MetaFormat eq 'camm', and 17 for 'mett' + Name => 'MetaType', + Format => 'undef[$size-8]', + # may start at various locations! + RawConv => '$$self{MetaType} = ($val=~/(application[^\0]+)/ ? $1 : undef)', + }, # # Observed offsets for child atoms of various MetaFormat types: # @@ -6242,11 +7642,27 @@ my %eeBox = ( # data - - # ftab => { Name => 'FontTable', Format => 'undef', ValueConv => 'substr($val, 5)' }, + name => { Name => 'OtherName', Format => 'undef', ValueConv => 'substr($val, 4)' }, + # mrlh = GM header? + # mrlv = GM data + # mrld = GM data (448-byte records): + # 0 - int32u count + # 4 - int32u ? (related to units) 0=none,1=m/km,2=L,3=kph,4=C,7=deg,8=rpm,9=kPa,10=G,11=V,15=Nm,16=% + # 8 - int32u ? (0,1,3,4,5) + # 12 - string[64] units + # 76 - int32u ? (1,3,7,15) + # 80 - int32u 0 + # 84 - undef[4] ? + # 88 - int16u[6] ? + # 100 - undef[32] ? + # 132 - string[64] measurement name + # 196 - string[64] measurement name ); # MP4 data information box (ref 5) %Image::ExifTool::QuickTime::DataInfo = ( PROCESS_PROC => \&ProcessMOV, + WRITE_PROC => \&WriteQuickTime, # (necessary to parse dref even though we don't change it) NOTES => 'MP4 data information box.', dref => { Name => 'DataRef', @@ -6347,6 +7763,7 @@ my %eeBox = ( # MP4 data reference box (ref 5) %Image::ExifTool::QuickTime::DataRef = ( PROCESS_PROC => \&ProcessMOV, + WRITE_PROC => \&WriteQuickTime, # (necessary to parse dref even though we don't change it) NOTES => 'MP4 data reference box.', 'url ' => { Name => 'URL', @@ -6392,7 +7809,11 @@ my %eeBox = ( 8 => { Name => 'HandlerType', Format => 'undef[4]', - RawConv => '$$self{HandlerType} = $val unless $val eq "alis" or $val eq "url "; $val', + RawConv => q{ + $$self{HandlerType} = $val unless $val eq 'alis' or $val eq 'url '; + $$self{HasHandler}{$val} = 1; # remember all our handlers + return $val; + }, PrintConvColumns => 2, PrintConv => { alis => 'Alias Data', #PH @@ -6418,6 +7839,8 @@ my %eeBox = ( pict => 'Picture', # (HEIC images) camm => 'Camera Metadata', # (Insta360 MP4) psmd => 'Panasonic Static Metadata', #PH (Leica C-Lux CAM-DC25) + data => 'Data', #PH (GPS and G-sensor data from DataKam) + sbtl => 'Subtitle', #PH (TomTom Bandit Action Cam) }, }, 12 => { #PH @@ -6461,6 +7884,66 @@ my %eeBox = ( }, ); +# atoms in Pittasoft "free" atom +%Image::ExifTool::QuickTime::Pittasoft = ( + PROCESS_PROC => \&ProcessMOV, + NOTES => 'Tags found in Pittasoft Blackvue dashcam "free" data.', + cprt => 'Copyright', + thum => { + Name => 'PreviewImage', + Groups => { 2 => 'Preview' }, + Binary => 1, + RawConv => q{ + return undef unless length $val > 4; + my $len = unpack('N', $val); + return undef unless length $val >= 4 + $len; + return substr($val, 4, $len); + }, + }, + ptnm => { + Name => 'OriginalFileName', + ValueConv => 'substr($val, 4, -1)', + }, + ptrh => { + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Pittasoft' }, + # contains these atoms: + # ptvi - 27 bytes: '..avc1...' + # ptso - 16 bytes: '..mp4a...' + }, + 'gps ' => { + Name => 'GPSLog', + Binary => 1, # (ASCII NMEA track log with leading timestamps) + Notes => 'parsed to extract GPS separately when ExtractEmbedded is used', + RawConv => q{ + $val =~ s/\0+$//; # remove trailing nulls + if (length $val and $$self{OPTIONS}{ExtractEmbedded}) { + my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); + Image::ExifTool::QuickTime::ProcessGPSLog($self, { DataPt => \$val }, $tagTbl); + } + return $val; + }, + }, + '3gf ' => { + Name => 'AccelData', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::Stream', + ProcessProc => \&Process_3gf, + }, + }, + sttm => { + Name => 'StartTime', + Format => 'int64u', + Groups => { 2 => 'Time' }, + RawConv => '$$self{StartTime} = $val', + # (ms since Jan 1, 1970, in local time zone - PH) + ValueConv => q{ + my $secs = int($val / 1000); + return ConvertUnixTime($secs) . sprintf(".%03d",$val - $secs * 1000); + }, + PrintConv => '$self->ConvertDateTime($val)', + }, +); + # QuickTime composite tags %Image::ExifTool::QuickTime::Composite = ( GROUPS => { 2 => 'Video' }, @@ -6474,6 +7957,7 @@ my %eeBox = ( 1 => 'QuickTime:HandlerType', }, Writable => 1, + Protected => 1, WriteAlso => { MatrixStructure => 'Image::ExifTool::QuickTime::GetRotationMatrix($val)', }, @@ -6483,13 +7967,13 @@ my %eeBox = ( AvgBitrate => { Priority => 0, # let QuickTime::AvgBitrate take priority Require => { - 0 => 'QuickTime::MovieDataSize', + 0 => 'QuickTime::MediaDataSize', 1 => 'QuickTime::Duration', }, RawConv => q{ return undef unless $val[1]; $val[1] /= $$self{TimeScale} if $$self{TimeScale}; - my $key = 'MovieDataSize'; + my $key = 'MediaDataSize'; my $size = $val[0]; for (;;) { $key = $self->NextTagKey($key) or last; @@ -6582,6 +8066,7 @@ Image::ExifTool::AddCompositeTags('Image::ExifTool::QuickTime'); # sub AUTOLOAD { + # (Note: no need to autoload routines in QuickTimeStream that use Stream table) if ($AUTOLOAD eq 'Image::ExifTool::QuickTime::Process_mebx') { require 'Image/ExifTool/QuickTimeStream.pl'; no strict 'refs'; @@ -6709,7 +8194,7 @@ sub FixWrongFormat($) #------------------------------------------------------------------------------ # Convert ISO 6709 string to standard lag/lon format # Inputs: 0) ISO 6709 string (lat, lon, and optional alt) -# Returns: position in decimal degress with altitude if available +# Returns: position in decimal degrees with altitude if available # Notes: Wikipedia indicates altitude may be in feet -- how is this specified? sub ConvertISO6709($) { @@ -6802,18 +8287,18 @@ sub PrintGPSCoordinates($) #------------------------------------------------------------------------------ # Unpack packed ISO 639/T language code -# Inputs: 0) packed language code (or undef) -# Returns: language code, or undef for default language, or 'err' for format error -sub UnpackLang($) +# Inputs: 0) packed language code (or undef/0), 1) true to not treat 'und' and 'eng' as default +# Returns: language code, or undef/0 for default language, or 'err' for format error +sub UnpackLang($;$) { - my $lang = shift; + my ($lang, $noDef) = @_; if ($lang) { # language code is packed in 5-bit characters - $lang = pack "C*", map { (($lang>>$_)&0x1f)+0x60 } 10, 5, 0; + $lang = pack 'C*', map { (($lang>>$_)&0x1f)+0x60 } 10, 5, 0; # validate language code if ($lang =~ /^[a-z]+$/) { # treat 'eng' or 'und' as the default language - undef $lang if $lang eq 'und' or $lang eq 'eng'; + undef $lang if ($lang eq 'und' or $lang eq 'eng') and not $noDef; } else { $lang = 'err'; # invalid language code } @@ -6821,6 +8306,30 @@ sub UnpackLang($) return $lang; } +#------------------------------------------------------------------------------ +# Get language code string given QuickTime language and country codes +# Inputs: 0) numerical language code, 1) numerical country code, 2) no defaults +# Returns: language code string (ie. "fra-FR") or undef for default language +sub GetLangCode($;$$) +{ + my ($lang, $ctry, $noDef) = @_; + # ignore country ('ctry') and language lists ('lang') for now + undef $ctry if $ctry and $ctry <= 255; + undef $lang if $lang and $lang <= 255; + $lang = UnpackLang($lang, $noDef); + # add country code if specified + if ($ctry) { + $ctry = unpack('a2',pack('n',$ctry)); # unpack as ISO 3166-1 + # treat 'ZZ' like a default country (see ref 12) + undef $ctry if $ctry eq 'ZZ'; + if ($ctry and $ctry =~ /^[A-Z]{2}$/) { + $lang or $lang = 'und'; + $lang .= "-$ctry"; + } + } + return $lang; +} + #------------------------------------------------------------------------------ # Get langInfo hash and save details about alt-lang tags # Inputs: 0) ExifTool ref, 1) tagInfo hash ref, 2) locale code @@ -6878,15 +8387,20 @@ sub GetString($$) #------------------------------------------------------------------------------ # Get a printable version of the tag ID -# Inputs: 0) tag ID, 1) Flag: 1=print as 4- or 8-digit hex value if necessary +# Inputs: 0) tag ID, 1) Flag: 0x01 - print as 4- or 8-digit hex value if necessary +# 0x02 - put leading backslash before escaped character # Returns: Printable tag ID sub PrintableTagID($;$) { my $tag = $_[0]; my $n = ($tag =~ s/([\x00-\x1f\x7f-\xff])/'x'.unpack('H*',$1)/eg); - if ($n > 2 and $_[1]) { - $tag = '0x' . unpack('H8', $_[0]); - $tag =~ s/^0x0000/0x/; + if ($n and $_[1]) { + if ($n > 2 and $_[1] & 0x01) { + $tag = '0x' . unpack('H8', $_[0]); + $tag =~ s/^0x0000/0x/; + } elsif ($_[1] & 0x02) { + ($tag = $_[0]) =~ s/([\x00-\x1f\x7f-\xff])/'\\x'.unpack('H*',$1)/eg; + } } return $tag; } @@ -6899,7 +8413,12 @@ sub PrintableTagID($;$) # ConstructionMethod - offset type: 0=file, 1=idat, 2=item # DataReferenceIndex - 0 for "this file", otherwise index in dref box # BaseOffset - base for file offsets -# Extents - list of index,offset,length details for data in file +# Extents - list of details for data in file: +# 0) index (extent_index) +# 1) offset (extent_offset) +# 2) length (extent_length) +# 3) nlen (length_size) +# 4) lenPt (pointer to length word) # infe: # ProtectionIndex - index if item is protected (0 for unprotected) # Name - item name @@ -6918,12 +8437,14 @@ sub PrintableTagID($;$) # Parse item location (iloc) box (ref ISO 14496-12:2015 pg.79) # Inputs: 0) iloc data, 1) ExifTool ref # Returns: undef, and fills in ExifTool ItemInfo hash +# Notes: see also Handle_iloc() in WriteQuickTime.pl sub ParseItemLocation($$) { my ($val, $et) = @_; my ($i, $j, $num, $pos, $id); my ($extent_index, $extent_offset, $extent_length); + my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose'); my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { }); my $len = length $val; return undef if $len < 8; @@ -6971,7 +8492,11 @@ sub ParseItemLocation($$) $extent_offset = GetVarInt(\$val, $pos, $noff); $extent_length = GetVarInt(\$val, $pos, $nlen); return undef unless defined $extent_length; - push @extents, [ $extent_index, $extent_offset, $extent_length ]; + $et->VPrint(1, "$$et{INDENT} Item $id: const_meth=", + defined $$items{$id}{ConstructionMethod} ? $$items{$id}{ConstructionMethod} : '', + sprintf(" base=0x%x offset=0x%x len=0x%x\n", $$items{$id}{BaseOffset}, + $extent_offset, $extent_length)) if $verbose; + push @extents, [ $extent_index, $extent_offset, $extent_length, $nlen, $pos-$nlen ]; } # save item location information keyed on 1-based item ID: $$items{$id}{Extents} = \@extents; @@ -6979,6 +8504,33 @@ sub ParseItemLocation($$) return undef; } +#------------------------------------------------------------------------------ +# Parse content describes entry (cdsc) box +# Inputs: 0) cdsc data, 1) ExifTool ref +# Returns: undef, and fills in ExifTool ItemInfo hash +sub ParseContentDescribes($$) +{ + my ($val, $et) = @_; + my ($id, $count, @to); + if ($$et{ItemRefVersion}) { + return undef if length $val < 10; + ($id, $count, @to) = unpack('NnN*', $val); + } else { + return undef if length $val < 6; + ($id, $count, @to) = unpack('nnn*', $val); + } + if ($count > @to) { + my $str = 'Missing values in ContentDescribes box'; + $$et{IsWriting} ? $et->Error($str) : $et->Warn($str); + } elsif ($count < @to) { + $et->Warn('Ignored extra values in ContentDescribes box', 1); + @to = $count; + } + # add all referenced item ID's to a "RefersTo" lookup + $$et{ItemInfo}{$id}{RefersTo}{$_} = 1 foreach @to; + return undef; +} + #------------------------------------------------------------------------------ # Parse item information entry (infe) box (ref ISO 14496-12:2015 pg.82) # Inputs: 0) infe data, 1) ExifTool ref @@ -6988,7 +8540,7 @@ sub ParseItemInfoEntry($$) my ($val, $et) = @_; my $id; - my $verbose = $et->Options('Verbose'); + my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose'); my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { }); my $len = length $val; return undef if $len < 4; @@ -7032,15 +8584,14 @@ sub ParseItemInfoEntry($$) #------------------------------------------------------------------------------ # Parse item property association (ipma) box (ref https://github.com/gpac/gpac/blob/master/src/isomedia/iff.c) -# Inputs: 0) infe data, 1) ExifTool ref +# Inputs: 0) ipma data, 1) ExifTool ref # Returns: undef, and fills in ExifTool ItemInfo hash -# Note: this information is currently not used by ExifTool (must figure out how to do this) sub ParseItemPropAssoc($$) { my ($val, $et) = @_; my ($i, $j, $id); - my $verbose = $et->Options('Verbose'); + my $verbose = $$et{IsWriting} ? 0 : $et->Options('Verbose'); my $items = $$et{ItemInfo} || ($$et{ItemInfo} = { }); my $len = length $val; return undef if $len < 8; @@ -7086,40 +8637,76 @@ sub ParseItemPropAssoc($$) #------------------------------------------------------------------------------ # Process item information now -# Inputs: 0) ExifTool ref, 1) RAF ref -sub HandleItemInfo($$) +# Inputs: 0) ExifTool ref +sub HandleItemInfo($) { - my ($et, $raf) = @_; + my $et = shift; + my $raf = $$et{RAF}; my $items = $$et{ItemInfo}; + my $verbose = $et->Options('Verbose'); my $buff; # extract information from EXIF/XMP metadata items if ($items and $raf) { + push @{$$et{PATH}}, 'ItemInformation'; my $curPos = $raf->Tell(); my $primary = $$et{PrimaryItem}; my $id; + $et->VerboseDir('Processing items from ItemInformation', scalar(keys %$items)); foreach $id (sort { $a <=> $b } keys %$items) { my $item = $$items{$id}; my $type = $$item{ContentType} || $$item{Type} || next; - unless ($type eq 'Exif') { - next unless $type eq 'application/rdf+xml'; - $type = 'XMP'; - } - if ($$item{ContentEncoding}) { - $et->WarnOnce("Can't currently decode encoded $type metadata"); - next; + if ($verbose) { + # add up total length of this item for the verbose output + my $len = 0; + if ($$item{Extents} and @{$$item{Extents}}) { + $len += $$_[2] foreach @{$$item{Extents}}; + } + $et->VPrint(0, "$$et{INDENT}Item $id) '${type}' ($len bytes)\n"); } - if ($$item{ProtectionIndex}) { - $et->WarnOnce("Can't currently decode protected $type metadata"); - next; + # get ExifTool name for this item + my $name = { Exif => 'EXIF', 'application/rdf+xml' => 'XMP' }->{$type} || ''; + my ($warn, $extent); + $warn = "Can't currently decode encoded $type metadata" if $$item{ContentEncoding}; + $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}; + $et->WarnOnce($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) { + $warn = "No Extents for $type item"; + $et->WarnOnce($warn) if $name; } - if ($$item{ConstructionMethod}) { - $et->WarnOnce("Can't currently extract $type with construction method $$item{ConstructionMethod}"); + if ($warn) { + $et->VPrint(0, "$$et{INDENT} [not extracted] ($warn)\n") if $verbose > 2; next; } - next if $$item{DataReferenceIndex}; # (can only extract information from "this file") - my ($extent, $proc); my $base = $$item{BaseOffset} || 0; + if ($verbose > 2) { + # do verbose hex dump + my $len = 0; + undef $buff; + my $val = ''; + my $maxLen = $verbose > 3 ? 2048 : 96; + foreach $extent (@{$$item{Extents}}) { + my $n = $$extent[2]; + my $more = $maxLen - $len; + if ($more > 0 and $n) { + $more = $n if $more > $n; + $val .= $buff if defined $buff; + $raf->Seek($$extent[1] + $base, 0) or last; + $raf->Read($buff, $more) or last; + } + $len += $n; + } + if (defined $buff) { + $buff = $val . $buff if length $val; + $et->VerboseDump(\$buff, DataPos => $$item{Extents}[0][1] + $base); + my $snip = $len - length $buff; + $et->VPrint(0, "$$et{INDENT} [snip $snip bytes]\n") if $snip; + } + } + next unless $name; + # assemble the data for this item undef $buff; my $val = ''; foreach $extent (@{$$item{Extents}}) { @@ -7129,15 +8716,43 @@ sub HandleItemInfo($$) } next unless defined $buff; $buff = $val . $buff if length $val; - my $start = $type eq 'Exif' ? 10 : 0; # skip count and "Exif\0\0" header + next unless length $buff; # ignore empty directories + my ($start, $subTable, $proc); my $pos = $$item{Extents}[0][1] + $base; + if ($name eq 'EXIF' and length $buff >= 4) { + if ($buff =~ /^(MM\0\x2a|II\x2a\0)/) { + $et->Warn('Missing Exif header'); + $start = 0; + } elsif ($buff =~ /^Exif\0\0/) { + # (haven't seen this yet, but it is just a matter of time + # until someone screws it up like this) + $et->Warn('Missing Exif header size'); + $start = 6; + } else { + my $n = unpack('N', $buff); + $start = 4 + $n; # skip "Exif\0\0" header if it exists + if ($start > length($buff)) { + $et->Warn('Invalid EXIF header'); + next; + } + if ($$et{HTML_DUMP}) { + $et->HDump($pos, 4, 'Exif header length', "Value: $n"); + $et->HDump($pos+4, $start-4, 'Exif header') if $n; + } + } + $subTable = GetTagTable('Image::ExifTool::Exif::Main'); + $proc = \&Image::ExifTool::ProcessTIFF; + } else { + $start = 0; + $subTable = GetTagTable('Image::ExifTool::XMP::Main'); + } my %dirInfo = ( DataPt => \$buff, DataLen => length $buff, DirStart => $start, DirLen => length($buff) - $start, DataPos => $pos, - Base => $pos, # (needed for IsOffset tags in binary data) + Base => $pos + $start, # (needed for HtmlDump and IsOffset tags in binary data) ); # handle processing of metadata for sub-documents if (defined $primary and $$item{RefersTo} and not $$item{RefersTo}{$primary}) { @@ -7147,12 +8762,11 @@ sub HandleItemInfo($$) my ($lowest) = sort { $a <=> $b } keys %{$$item{RefersTo}}; $$items{$lowest}{DocNum} = $$et{DOC_NUM}; } - my $subTable = GetTagTable('Image::ExifTool::' . $type . '::Main'); - $proc = \&Image::ExifTool::ProcessTIFF if $type eq 'Exif'; $et->ProcessDirectory(\%dirInfo, $subTable, $proc); delete $$et{DOC_NUM}; } $raf->Seek($curPos, 0); # seek back to original position + pop @{$$et{PATH}}; } # process the item properties now that we should know their associations and document numbers if ($$et{ItemPropertyContainer}) { @@ -7166,6 +8780,36 @@ sub HandleItemInfo($$) delete $$et{ItemInfo}; } +#------------------------------------------------------------------------------ +# Warn if ExtractEmbedded option isn't used +# Inputs: 0) ExifTool ref +sub EEWarn($) +{ + my $et = shift; + $et->WarnOnce('The ExtractEmbedded option may find more tags in the media data',3); +} + +#------------------------------------------------------------------------------ +# Get quicktime format from flags word +# Inputs: 0) quicktime atom flags, 1) data length +# Returns: ExifTool format string +sub QuickTimeFormat($$) +{ + my ($flags, $len) = @_; + my $format; + if ($flags == 0x15 or $flags == 0x16) { + $format = { 1=>'int8', 2=>'int16', 4=>'int32', 8=>'int64' }->{$len}; + $format .= $flags == 0x15 ? 's' : 'u' if $format; + } elsif ($flags == 0x17) { + $format = 'float'; + } elsif ($flags == 0x18) { + $format = 'double'; + } elsif ($flags == 0x00) { + $format = { 1=>'int8u', 2=>'int16u' }->{$len}; + } + return $format; +} + #------------------------------------------------------------------------------ # Process MPEG-4 MTDT atom (ref 11) # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref @@ -7231,18 +8875,22 @@ sub ProcessSampleDesc($$$) my $dirLen = $$dirInfo{DirLen} || (length($$dataPt) - $pos); return 0 if $pos + 8 > $dirLen; - my $num = Get32u($dataPt, 4); # get number of sample descriptions in table + my $num = Get32u($dataPt, 4); # get number of sample entries in table $pos += 8; - my $i; - for ($i=0; $i<$num; ++$i) { # loop through sample descriptions - last if $pos + 8 > $dirLen; + my ($i, $err); + for ($i=0; $i<$num; ++$i) { # loop through sample entries + $pos + 8 > $dirLen and $err = 1, last; my $size = Get32u($dataPt, $pos); - last if $pos + $size > $dirLen; + $pos + $size > $dirLen and $err = 1, last; $$dirInfo{DirStart} = $pos; $$dirInfo{DirLen} = $size; ProcessHybrid($et, $dirInfo, $tagTablePtr); $pos += $size; } + if ($err and $$et{HandlerType}) { + my $grp = $$et{SET_GROUP1} || $$dirInfo{Parent} || 'unknown'; + $et->Warn("Truncated $$et{HandlerType} sample table for $grp"); + } return 1; } @@ -7349,7 +8997,7 @@ sub ProcessEncodingParams($$$) } #------------------------------------------------------------------------------ -# Process Meta keys and add tags to the ItemList table ('mdta' handler) (ref PH) +# Read Meta Keys and add tags to ItemList table ('mdta' handler) (ref PH) # Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref # Returns: 1 on success sub ProcessKeys($$$) @@ -7365,9 +9013,9 @@ sub ProcessKeys($$$) } my $pos = 8; my $index = 1; - ++$$et{KeyCount}; # increment key count for this directory - my $infoTable = GetTagTable('Image::ExifTool::QuickTime::ItemList'); - my $userTable = GetTagTable('Image::ExifTool::QuickTime::UserData'); + ++$$et{KeysCount}; # increment key count for this directory + my $itemList = GetTagTable('Image::ExifTool::QuickTime::ItemList'); + my $userData = GetTagTable('Image::ExifTool::QuickTime::UserData'); while ($pos < $dirLen - 4) { my $len = unpack("x${pos}N", $$dataPt); last if $len < 8 or $pos + $len > $dirLen; @@ -7375,54 +9023,72 @@ sub ProcessKeys($$$) my $ns = substr($$dataPt, $pos + 4, 4); my $tag = substr($$dataPt, $pos + 8, $len - 8); $tag =~ s/\0.*//s; # truncate at null - if ($ns eq 'mdta') { - $tag =~ s/^com\.apple\.quicktime\.//; # remove common apple quicktime domain - } + my $full = $tag; + $tag =~ s/^com\.(apple\.quicktime\.)?// if $ns eq 'mdta'; # remove apple quicktime domain $tag = "Tag_$ns" unless $tag; - # (I have some samples where the tag is a reversed ItemList or UserData tag ID) - my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); - unless ($tagInfo) { - $tagInfo = $et->GetTagInfo($infoTable, $tag); - unless ($tagInfo) { - $tagInfo = $et->GetTagInfo($userTable, $tag); - if (not $tagInfo and $tag =~ /^\w{3}\xa9$/) { - $tag = pack('N', unpack('V', $tag)); - $tagInfo = $et->GetTagInfo($infoTable, $tag); - $tagInfo or $tagInfo = $et->GetTagInfo($userTable, $tag); - } + my $short = $tag; + my $tagInfo; + for (;;) { + $tagInfo = $et->GetTagInfo($tagTablePtr, $tag) and last; + # also try ItemList and UserData tables + $tagInfo = $et->GetTagInfo($itemList, $tag) and last; + $tagInfo = $et->GetTagInfo($userData, $tag) and last; + # (I have some samples where the tag is a reversed ItemList or UserData tag ID) + if ($tag =~ /^\w{3}\xa9$/) { + $tag = pack('N', unpack('V', $tag)); + $tagInfo = $et->GetTagInfo($itemList, $tag) and last; + $tagInfo = $et->GetTagInfo($userData, $tag); + last; } + if ($tag eq $full) { + $tag = $short; + last; + } + $tag = $full; } my ($newInfo, $msg); if ($tagInfo) { + # copy tag information into new Keys tag $newInfo = { Name => $$tagInfo{Name}, Format => $$tagInfo{Format}, ValueConv => $$tagInfo{ValueConv}, + ValueConvInv => $$tagInfo{ValueConvInv}, PrintConv => $$tagInfo{PrintConv}, + PrintConvInv => $$tagInfo{PrintConvInv}, + Writable => defined $$tagInfo{Writable} ? $$tagInfo{Writable} : 1, + SubDirectory => $$tagInfo{SubDirectory}, }; my $groups = $$tagInfo{Groups}; - $$newInfo{Groups} = { %$groups } if $groups; - } elsif ($tag =~ /^[-\w.]+$/) { + $$newInfo{Groups} = $groups ? { %$groups } : { }; + $$newInfo{Groups}{$_} or $$newInfo{Groups}{$_} = $$tagTablePtr{GROUPS}{$_} foreach 0..2; + $$newInfo{Groups}{1} = 'Keys'; + } elsif ($tag =~ /^[-\w. ]+$/ or $tag =~ /\w{4}/) { # create info for tags with reasonable id's - my $name = $tag; - $name =~ s/\.(.)/\U$1/g; - $newInfo = { Name => ucfirst($name) }; + my $name = ucfirst $tag; + $name =~ tr/-0-9a-zA-Z_. //dc; + $name =~ s/[. ]+(.?)/\U$1/g; + $name =~ s/_([a-z])/_\U$1/g; + $name =~ s/([a-z])_([A-Z])/$1$2/g; + $name = "Tag_$name" if length $name < 2; + $newInfo = { Name => $name, Groups => { 1 => 'Keys' } }; $msg = ' (Unknown)'; } # substitute this tag in the ItemList table with the given index - my $id = $$et{KeyCount} . '.' . $index; - if (ref $$infoTable{$id} eq 'HASH') { + my $id = $$et{KeysCount} . '.' . $index; + if (ref $$itemList{$id} eq 'HASH') { # delete other languages too if they exist - my $oldInfo = $$infoTable{$id}; + my $oldInfo = $$itemList{$id}; if ($$oldInfo{OtherLang}) { - delete $$infoTable{$_} foreach @{$$oldInfo{OtherLang}}; + delete $$itemList{$_} foreach @{$$oldInfo{OtherLang}}; } - delete $$infoTable{$id}; + delete $$itemList{$id}; } if ($newInfo) { + $$newInfo{KeysID} = $tag; # save original ID for use in family 7 group name + AddTagToTable($itemList, $id, $newInfo); $msg or $msg = ''; - AddTagToTable($infoTable, $id, $newInfo); - $out and print $out "$$et{INDENT}Added ItemList Tag $id = $tag$msg\n"; + $out and print $out "$$et{INDENT}Added ItemList Tag $id = ($ns) $tag$msg\n"; } $pos += $len; ++$index; @@ -7453,17 +9119,19 @@ sub ProcessMOV($$;$) my $raf = $$dirInfo{RAF}; my $dataPt = $$dirInfo{DataPt}; my $verbose = $et->Options('Verbose'); + my $validate = $$et{OPTIONS}{Validate}; my $dataPos = $$dirInfo{Base} || 0; + my $dirID = $$dirInfo{DirID} || ''; my $charsetQuickTime = $et->Options('CharsetQuickTime'); my ($buff, $tag, $size, $track, $isUserData, %triplet, $doDefaultLang, $index); - my ($dirEnd, $ee, $unkOpt, %saveOptions); + my ($dirEnd, $unkOpt, %saveOptions, $atomCount); my $topLevel = not $$et{InQuickTime}; $$et{InQuickTime} = 1; $$et{HandlerType} = $$et{MetaFormat} = '' unless defined $$et{HandlerType}; - unless (defined $$et{KeyCount}) { - $$et{KeyCount} = 0; # initialize ItemList key directory count + unless (defined $$et{KeysCount}) { + $$et{KeysCount} = 0; # initialize ItemList key directory count $doDefaultLang = 1; # flag to generate default language tags } # more convenient to package data as a RandomAccess file @@ -7496,6 +9164,7 @@ sub ProcessMOV($$;$) if ($raf->Read($buff, $size-8) == $size-8) { $raf->Seek(-($size-8), 1); my $type = substr($buff, 0, 4); + $$et{save_ftyp} = $type; # see if we know the extension for this file type if ($ftypLookup{$type} and $ftypLookup{$type} =~ /\(\.(\w+)/) { $fileType = $1; @@ -7520,14 +9189,18 @@ sub ProcessMOV($$;$) } $$raf{NoBuffer} = 1 if $et->Options('FastScan'); # disable buffering in FastScan mode - if ($$et{OPTIONS}{ExtractEmbedded}) { - $ee = 1; + my $ee = $$et{OPTIONS}{ExtractEmbedded}; + if ($ee) { $unkOpt = $$et{OPTIONS}{Unknown}; require 'Image/ExifTool/QuickTimeStream.pl'; } - $index = $$tagTablePtr{VARS}{START_INDEX} if $$tagTablePtr{VARS}; + if ($$tagTablePtr{VARS}) { + $index = $$tagTablePtr{VARS}{START_INDEX}; + $atomCount = $$tagTablePtr{VARS}{ATOM_COUNT}; + } for (;;) { my ($eeTag, $ignore); + last if defined $atomCount and --$atomCount < 0; if ($size < 8) { if ($size == 0) { if ($dataPt) { @@ -7538,14 +9211,20 @@ sub ProcessMOV($$;$) my $str = $$dirInfo{DirName} . ' with ' . ($raf->Tell() - $pos) . ' bytes'; $et->VPrint(0,"$$et{INDENT}\[Terminator found in $str remaining]"); } else { - $tag = PrintableTagID($tag); - $et->VPrint(0,"$$et{INDENT}Tag '${tag}' extends to end of file"); + my $t = PrintableTagID($tag,2); + $et->VPrint(0,"$$et{INDENT}Tag '${t}' extends to end of file"); + if ($$tagTablePtr{"$tag-size"}) { + my $pos = $raf->Tell(); + $raf->Seek(0, 2); + $et->HandleTag($tagTablePtr, "$tag-size", $raf->Tell() - $pos); + $et->HandleTag($tagTablePtr, "$tag-offset", $pos) if $$tagTablePtr{"$tag-offset"}; + } } last; } $size == 1 or $et->Warn('Invalid atom size'), last; # read extended atom size - $raf->Read($buff, 8) == 8 or last; + $raf->Read($buff, 8) == 8 or $et->Warn('Truncated atom header'), last; $dataPos += 8; my ($hi, $lo) = unpack('NN', $buff); if ($hi or $lo > 0x7fffffff) { @@ -7562,6 +9241,18 @@ sub ProcessMOV($$;$) } else { $size -= 8; } + if ($validate) { + $$et{ValidatePath} or $$et{ValidatePath} = { }; + my $path = join('-', @{$$et{PATH}}, $tag); + $path =~ s/-Track-/-$$et{SET_GROUP1}-/ if $$et{SET_GROUP1}; + if ($$et{ValidatePath}{$path} and not $dupTagOK{$tag} and not $dupDirOK{$dirID}) { + my $i = Get32u(\$tag,0); + my $str = $i < 255 ? "index $i" : "tag '" . PrintableTagID($tag,2) . "'"; + $et->WarnOnce("Duplicate $str at " . join('-', @{$$et{PATH}})); + $$et{ValidatePath} = { } if $path eq 'MOV-moov'; # avoid warnings for all contained dups + } + $$et{ValidatePath}{$path} = 1; + } if ($isUserData and $$et{SET_GROUP1}) { my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); # add track name to UserData tags inside tracks @@ -7580,11 +9271,17 @@ sub ProcessMOV($$;$) my $handlerType = $$et{HandlerType}; if ($eeBox{$handlerType} and $eeBox{$handlerType}{$tag}) { if ($ee) { - $eeTag = 1; - $$et{OPTIONS}{Unknown} = 1; # temporarily enable "Unknown" option + # (there is another 'gps ' box with a track log that doesn't contain offsets) + if ($tag ne 'gps ' or $eeBox{$handlerType}{$tag} eq $dirID) { + $eeTag = 1; + $$et{OPTIONS}{Unknown} = 1; # temporarily enable "Unknown" option + } } elsif ($handlerType ne 'vide' and not $$et{OPTIONS}{Validate}) { - $et->WarnOnce('The ExtractEmbedded option may find more tags in the movie data',3); + EEWarn($et); } + } elsif ($ee and $ee > 1 and $eeBox2{$handlerType} and $eeBox2{$handlerType}{$tag}) { + $eeTag = 1; + $$et{OPTIONS}{Unknown} = 1; } my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); @@ -7592,7 +9289,7 @@ sub ProcessMOV($$;$) # allow numerical tag ID's unless ($tagInfo) { - my $id = $$et{KeyCount} . '.' . unpack('N', $tag); + my $id = $$et{KeysCount} . '.' . unpack('N', $tag); if ($$tagTablePtr{$id}) { $tagInfo = $et->GetTagInfo($tagTablePtr, $id); $tag = $id; @@ -7624,9 +9321,21 @@ sub ProcessMOV($$;$) } # load values only if associated with a tag (or verbose) and not too big if ($size > 0x2000000) { # start to get worried above 32 MB + # check for RIFF trailer (written by Auto-Vox dashcam) + if ($buff =~ /^(gpsa|gps0|gsen|gsea)...\0/s) { # (yet seen only gpsa as first record) + $et->VPrint(0, "Found RIFF trailer"); + if ($et->Options('ExtractEmbedded')) { + $raf->Seek(-8, 1) or last; # seek back to start of trailer + my $tbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); + ProcessRIFFTrailer($et, { RAF => $raf }, $tbl); + } else { + EEWarn($et); + } + last; + } $ignore = 1; if ($tagInfo and not $$tagInfo{Unknown} and not $eeTag) { - my $t = PrintableTagID($tag); + my $t = PrintableTagID($tag,2); if ($size > 0x8000000) { $et->Warn("Skipping '${t}' atom > 128 MB", 1); } else { @@ -7638,7 +9347,7 @@ sub ProcessMOV($$;$) # set document number for this item property if necessary if ($$et{IsItemProperty}) { my $items = $$et{ItemInfo}; - my ($id, $prop, $mainItem, $docNum, $lowest); + my ($id, $prop, $docNum, $lowest); my $primary = $$et{PrimaryItem} || 0; ItemID: foreach $id (keys %$items) { next unless $$items{$id}{Association}; @@ -7655,7 +9364,7 @@ ItemID: foreach $id (keys %$items) { last ItemID; } elsif ($$item{DocNum}) { # this property is already associated with an item that has - # an ExifTool document number, so use the lowest assocated DocNum + # an ExifTool document number, so use the lowest associated DocNum $docNum = $$item{DocNum} if not defined $docNum or $docNum > $$item{DocNum}; } elsif (not defined $lowest or $lowest > $id) { # keep track of the lowest associated item ID @@ -7674,7 +9383,8 @@ ItemID: foreach $id (keys %$items) { my $val; my $missing = $size - $raf->Read($val, $size); if ($missing) { - $et->Warn("Truncated '${tag}' data (missing $missing bytes)"); + my $t = PrintableTagID($tag,2); + $et->Warn("Truncated '${t}' data (missing $missing bytes)"); last; } # use value to get tag info if necessary @@ -7693,6 +9403,24 @@ ItemID: foreach $id (keys %$items) { Format => $tagInfo ? $$tagInfo{Format} : undef, Index => $index, ); + # print iref item ID numbers + if ($dirID eq 'iref') { + my ($id, $count, @to, $i); + if ($$et{ItemRefVersion}) { + ($id, $count, @to) = unpack('NnN*', $val) if length $val >= 10; + } else { + ($id, $count, @to) = unpack('nnn*', $val) if length $val >= 6; + } + defined $id or $id = '<err>', $count = 0; + $id .= " (wrong count: $count)" if $count != @to; + # convert sequential numbers to a range + for ($i=1; $i<@to; ) { + $to[$i-1] =~ /(\d+)$/ and $to[$i] == $1 + 1 or ++$i, next; + $to[$i-1] =~ s/(-.*)?$/-$to[$i]/; + splice @to, $i, 1; + } + $et->VPrint(1, "$$et{INDENT} Item $id refers to: ",join(',',@to),"\n"); + } } # extract metadata from stream if ExtractEmbedded option is enabled if ($eeTag) { @@ -7717,6 +9445,7 @@ ItemID: foreach $id (keys %$items) { Name => $name, Description => $desc, }; + $et->VPrint(0, $$et{INDENT}, "[adding QuickTime:$name]\n"); AddTagToTable($tagTablePtr, $tag, $tagInfo); } # ignore 8-byte header @@ -7728,9 +9457,9 @@ ItemID: foreach $id (keys %$items) { $val = \$buff; } } - undef %triplet; + $$tagInfo{List} = 1; # (allow any of these tags to have multiple data elements) + $et->VerboseInfo($tag, $tagInfo, Value => $val) if $verbose; } else { - undef %triplet if $tag eq 'mean'; $triplet{$tag} = substr($val,4) if length($val) > 4; undef $tagInfo; # don't store this tag } @@ -7750,6 +9479,7 @@ ItemID: foreach $id (keys %$items) { DirStart => $start, DirLen => $size - $start, DirName => $$subdir{DirName} || $$tagInfo{Name}, + DirID => $tag, HasData => $$subdir{HasData}, Multi => $$subdir{Multi}, IgnoreProp => $$subdir{IgnoreProp}, # (XML hack) @@ -7761,7 +9491,9 @@ ItemID: foreach $id (keys %$items) { SetByteOrder('II'); } my $oldGroup1 = $$et{SET_GROUP1}; - if ($$tagInfo{Name} eq 'Track') { + if ($$tagInfo{SubDirectory} and $$tagInfo{SubDirectory}{TagTable} and + $$tagInfo{SubDirectory}{TagTable} eq 'Image::ExifTool::QuickTime::Track') + { $track or $track = 0; $$et{SET_GROUP1} = 'Track' . (++$track); } @@ -7786,10 +9518,6 @@ ItemID: foreach $id (keys %$items) { } $$et{SET_GROUP1} = $oldGroup1; SetByteOrder('MM'); - if ($tag eq 'meta') { - # handle metadata now if we just processed the 'meta' box - HandleItemInfo($et, $raf) if $tag eq 'meta'; - } } elsif ($hasData) { # handle atoms containing 'data' tags # (currently ignore contained atoms: 'itif', 'name', etc.) @@ -7797,8 +9525,8 @@ ItemID: foreach $id (keys %$items) { for (;;) { last if $pos + 16 > $size; my ($len, $type, $flags, $ctry, $lang) = unpack("x${pos}Na4Nnn", $val); - last if $pos + $len > $size; - my $value; + last if $pos + $len > $size or not $len; + my ($value, $langInfo, $oldDir); my $format = $$tagInfo{Format}; if ($type eq 'data' and $len >= 16) { $pos += 16; @@ -7816,21 +9544,11 @@ ItemID: foreach $id (keys %$items) { $value =~ s/\0$// unless $$tagInfo{Binary}; } else { if (not $format) { - if ($flags == 0x15 or $flags == 0x16) { - $format = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len}; - $format .= $flags == 0x15 ? 's' : 'u' if $format; - } elsif ($flags == 0x17) { - $format = 'float'; - } elsif ($flags == 0x18) { - $format = 'double'; - } elsif ($flags == 0x00) { - # read 1 and 2-byte binary as integers - if ($len == 1) { - $format = 'int8u', - } elsif ($len == 2) { - $format = 'int16u', - } - } + $format = QuickTimeFormat($flags, $len); + } elsif ($format =~ /^int\d+([us])$/) { + # adjust integer to available length (but not int64) + my $fmt = { 1=>'int8', 2=>'int16', 4=>'int32' }->{$len}; + $format = $fmt . $1 if defined $fmt; } if ($format) { $value = ReadValue(\$value, 0, $format, $$tagInfo{Count}, $len); @@ -7841,25 +9559,11 @@ ItemID: foreach $id (keys %$items) { } } } - my $langInfo; if ($ctry or $lang) { - # ignore country ('ctry') and language lists ('lang') for now - undef $ctry if $ctry and $ctry <= 255; - undef $lang if $lang and $lang <= 255; - $lang = UnpackLang($lang); - # add country code if specified - if ($ctry) { - $ctry = unpack('a2',pack('n',$ctry)); # unpack as ISO 3166-1 - # treat 'ZZ' like a default country (see ref 12) - undef $ctry if $ctry eq 'ZZ'; - if ($ctry and $ctry =~ /^[A-Z]{2}$/) { - $lang or $lang = 'und'; - $lang .= "-$ctry"; - } - } - if ($lang) { + my $langCode = GetLangCode($lang, $ctry); + if ($langCode) { # get tagInfo for other language - $langInfo = GetLangInfoQT($et, $tagInfo, $lang); + $langInfo = GetLangInfoQT($et, $tagInfo, $langCode); # save other language tag ID's so we can delete later if necessary if ($langInfo) { $$tagInfo{OtherLang} or $$tagInfo{OtherLang} = [ ]; @@ -7876,9 +9580,16 @@ ItemID: foreach $id (keys %$items) { Size => $len, Format => $format, Index => $index, - Extra => sprintf(", Type='${type}', Flags=0x%x",$flags) + Extra => sprintf(", Type='${type}', Flags=0x%x, Lang=0x%.4x",$flags,$lang), ) if $verbose; + # use "Keys" in path instead of ItemList if this was defined by a Keys tag + my $isKey = $$tagInfo{Groups} && $$tagInfo{Groups}{1} && $$tagInfo{Groups}{1} eq 'Keys'; + if ($isKey) { + $oldDir = $$et{PATH}[-1]; + $$et{PATH}[-1] = 'Keys'; + } $et->FoundTag($langInfo, $value) if defined $value; + $$et{PATH}[-1] = $oldDir if $isKey; $pos += $len; } } elsif ($tag =~ /^\xa9/ or $$tagInfo{IText}) { @@ -7889,38 +9600,61 @@ ItemID: foreach $id (keys %$items) { $pos = $size; } for (;;) { - last if $pos + 4 > $size; - my ($len, $lang) = unpack("x${pos}nn", $val); - $pos += 4; - # according to the QuickTime spec (ref 12), $len should include - # 4 bytes for length and type words, but nobody (including - # Apple, Pentax and Kodak) seems to add these in, so try - # to allow for either - if ($pos + $len > $size) { - $len -= 4; - last if $pos + $len > $size or $len < 0; + my ($len, $lang); + if ($$tagInfo{IText} and $$tagInfo{IText} >= 6) { + last if $pos + $$tagInfo{IText} > $size; + $pos += $$tagInfo{IText} - 2; + $lang = unpack("x${pos}n", $val); + $pos += 2; + $len = $size - $pos; + } else { + last if $pos + 4 > $size; + ($len, $lang) = unpack("x${pos}nn", $val); + $pos += 4; + # according to the QuickTime spec (ref 12), $len should include + # 4 bytes for length and type words, but nobody (including + # Apple, Pentax and Kodak) seems to add these in, so try + # to allow for either + if ($pos + $len > $size) { + $len -= 4; + last if $pos + $len > $size or $len < 0; + } } # ignore any empty entries (or null padding) after the first next if not $len and $pos; my $str = substr($val, $pos, $len); - my $langInfo; - if ($lang < 0x400) { + my ($langInfo, $enc); + if (($lang < 0x400 or $lang == 0x7fff) and $str !~ /^\xfe\xff/) { # this is a Macintosh language code # a language code of 0 is Macintosh english, so treat as default if ($lang) { - # use Font.pm to look up language string - require Image::ExifTool::Font; - $lang = $Image::ExifTool::Font::ttLang{Macintosh}{$lang}; + if ($lang == 0x7fff) { + # technically, ISO 639-2 doesn't have a 2-character + # equivalent for 'und', but use 'un' anyway + $lang = 'un'; + } else { + # use Font.pm to look up language string + require Image::ExifTool::Font; + $lang = $Image::ExifTool::Font::ttLang{Macintosh}{$lang}; + } } # the spec says only "Macintosh text encoding", but # allow this to be configured by the user - $str = $et->Decode($str, $charsetQuickTime); + $enc = $charsetQuickTime; } else { # convert language code to ASCII (ignore read-only bit) $lang = UnpackLang($lang); # may be either UTF-8 or UTF-16BE - my $enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8'; + $enc = $str=~s/^\xfe\xff// ? 'UTF16' : 'UTF8'; + } + unless ($$tagInfo{NoDecode}) { $str = $et->Decode($str, $enc); + $str =~ s/\0+$//; # remove any trailing nulls (eg. 3gp tags) + } + if ($$tagInfo{IText} and $$tagInfo{IText} > 6) { + my $n = $$tagInfo{IText} - 6; + # add back extra bytes (eg. 'rtng' box) + $str = substr($val, $pos-$n-2, $n) . $str; } $langInfo = GetLangInfoQT($et, $tagInfo, $lang) if $lang; $et->FoundTag($langInfo || $tagInfo, $str); @@ -7959,7 +9693,11 @@ ItemID: foreach $id (keys %$items) { Size => $size, Extra => sprintf(' at offset 0x%.4x', $raf->Tell()), ) if $verbose; - $raf->Seek($size, 1) or $et->Warn("Truncated '${tag}' data"), last; + if ($size and (not $raf->Seek($size-1, 1) or $raf->Read($buff, 1) != 1)) { + my $t = PrintableTagID($tag,2); + $et->Warn("Truncated '${t}' data"); + last; + } } $dataPos += $size + 8; # point to start of next atom data last if $dirEnd and $dataPos >= $dirEnd; # (note: ignores last value if 0 bytes) @@ -7967,6 +9705,13 @@ ItemID: foreach $id (keys %$items) { ($size, $tag) = unpack('Na4', $buff); ++$index if defined $index; } + # tweak file type based on track content ("iso*" and "dash" ftyp only) + if ($topLevel and $$et{VALUE}{FileType} and $$et{VALUE}{FileType} eq 'MP4' and + $$et{save_ftyp} and $$et{HasHandler} and $$et{save_ftyp} =~ /^(iso|dash)/ and + $$et{HasHandler}{soun} and not $$et{HasHandler}{vide}) + { + $et->OverrideFileType('M4A', 'audio/mp4'); + } # fill in missing defaults for alternate language tags # (the first language is taken as the default) if ($doDefaultLang and $$et{QTLang}) { @@ -7986,10 +9731,11 @@ QTLang: foreach $tag (@{$$et{QTLang}}) { } delete $$et{QTLang}; } - if ($topLevel) { - HandleItemInfo($et, $raf); # process our item information - ScanMovieData($et) if $ee; # brute force scan for metadata embedded in movie data - } + # process item information now that we are done processing its 'meta' container + HandleItemInfo($et) if $topLevel or $dirID eq 'meta'; + + ScanMediaData($et) if $ee and $topLevel; # brute force scan for metadata embedded in media data + # restore any changed options $et->Options($_ => $saveOptions{$_}) foreach keys %saveOptions; return 1; @@ -8025,7 +9771,7 @@ information from QuickTime and MP4 video, M4A audio, and HEIC image files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/QuickTimeStream.pl b/src/Image-ExifTool/lib/Image/ExifTool/QuickTimeStream.pl new file mode 100644 index 00000000..614841b1 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/QuickTimeStream.pl @@ -0,0 +1,2934 @@ +#------------------------------------------------------------------------------ +# File: QuickTimeStream.pl +# +# Description: Extract embedded information from QuickTime media data +# +# Revisions: 2018-01-03 - P. Harvey Created +# +# References: 1) https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-SW130 +# 2) http://sergei.nz/files/nvtk_mp42gpx.py +# 3) https://forum.flitsservice.nl/dashcam-info/dod-ls460w-gps-data-uit-mov-bestand-lezen-t87926.html +# 4) https://developers.google.com/streetview/publish/camm-spec +# 5) https://sergei.nz/extracting-gps-data-from-viofo-a119-and-other-novatek-powered-cameras/ +# 6) Thomas Allen https://github.com/exiftool/exiftool/pull/62 +#------------------------------------------------------------------------------ +package Image::ExifTool::QuickTime; + +use strict; + +use Image::ExifTool qw(:DataAccess :Utils); +use Image::ExifTool::QuickTime; + +sub Process_tx3g($$$); +sub Process_marl($$$); +sub Process_mebx($$$); +sub ProcessFreeGPS($$$); +sub ProcessFreeGPS2($$$); +sub Process360Fly($$$); +sub ProcessFMAS($$$); + +# QuickTime data types that have ExifTool equivalents +# (ref https://developer.apple.com/library/content/documentation/QuickTime/QTFF/Metadata/Metadata.html#//apple_ref/doc/uid/TP40000939-CH1-SW35) +my %qtFmt = ( + 0 => 'undef', + 1 => 'string', # (UTF-8) + # 2 - UTF-16 + # 3 - shift-JIS + # 4 - UTF-8 sort + # 5 - UTF-16 sort + # 13 - JPEG image + # 14 - PNG image + # 21 - signed integer (1,2,3 or 4 bytes) + # 22 - unsigned integer (1,2,3 or 4 bytes) + 23 => 'float', + 24 => 'double', + # 27 - BMP image + # 28 - QuickTime atom + 65 => 'int8s', + 66 => 'int16s', + 67 => 'int32s', + 70 => 'float', # float[2] x,y + 71 => 'float', # float[2] width,height + 72 => 'float', # float[4] x,y,width,height + 74 => 'int64s', + 75 => 'int8u', + 76 => 'int16u', + 77 => 'int32u', + 78 => 'int64u', + 79 => 'float', # float[9] transform matrix + 80 => 'float', # float[8] face coordinates +); + +# maximums for validating H,M,S,d,m,Y from "freeGPS " metadata +my @dateMax = ( 24, 59, 59, 2200, 12, 31 ); + +# typical (minimum?) size of freeGPS block +my $gpsBlockSize = 0x8000; + +# conversion factors +my $knotsToKph = 1.852; # knots --> km/h +my $mpsToKph = 3.6; # m/s --> km/h +my $mphToKph = 1.60934; # mph --> km/h + +# handler types to process based on MetaFormat/OtherFormat +my %processByMetaFormat = ( + meta => 1, # ('CTMD' in CR3 images, 'priv' unknown in DJI video) + data => 1, # ('RVMI') + sbtl => 1, # (subtitle; 'tx3g' in Yuneec drone videos) + ctbx => 1, # ('marl' in GM videos) +); + +# data lengths for each INSV record type +my %insvDataLen = ( + 0x300 => 0, # accelerometer (could be either 20 or 56 bytes) + 0x400 => 16, # exposure (ref 6) + 0x600 => 8, # timestamps (ref 6) + 0x700 => 53, # GPS +); + +# limit the default amount of data we read for some record types +# (to avoid running out of memory) +my %insvLimit = ( + 0x300 => [ 'accelerometer', 20000 ], # maximum of 20000 accelerometer records +); + +# tags extracted from various QuickTime data streams +%Image::ExifTool::QuickTime::Stream = ( + GROUPS => { 2 => 'Location' }, + NOTES => q{ + The tags below are extracted from timed metadata in QuickTime and other + formats of video files when the ExtractEmbedded option is used. Although + most of these tags are combined into the single table below, ExifTool + currently reads 59 different formats of timed GPS metadata from video files. + }, + VARS => { NO_ID => 1 }, + GPSLatitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', RawConv => '$$self{FoundGPSLatitude} = 1; $val' }, + GPSLongitude => { PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")' }, + GPSAltitude => { PrintConv => '(sprintf("%.4f", $val) + 0) . " m"' }, # round to 4 decimals + GPSSpeed => { PrintConv => 'sprintf("%.4f", $val) + 0', Notes => 'in km/h unless GPSSpeedRef says otherwise' }, + GPSSpeedRef => { PrintConv => { K => 'km/h', M => 'mph', N => 'knots' } }, + GPSTrack => { PrintConv => 'sprintf("%.4f", $val) + 0', Notes => 'relative to true north unless GPSTrackRef says otherwise' }, + GPSTrackRef => { PrintConv => { M => 'Magnetic North', T => 'True North' } }, + GPSDateTime => { + Groups => { 2 => 'Time' }, + Description => 'GPS Date/Time', + RawConv => '$$self{FoundGPSDateTime} = 1; $val', + PrintConv => '$self->ConvertDateTime($val)', + }, + GPSTimeStamp => { PrintConv => 'Image::ExifTool::GPS::PrintTimeStamp($val)', Groups => { 2 => 'Time' } }, + GPSSatellites=> { }, + GPSDOP => { Description => 'GPS Dilution Of Precision' }, + Distance => { PrintConv => '"$val m"' }, + VerticalSpeed=> { PrintConv => '"$val m/s"' }, + FNumber => { PrintConv => 'Image::ExifTool::Exif::PrintFNumber($val)', Groups => { 2 => 'Camera' } }, + ExposureTime => { PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', Groups => { 2 => 'Camera' } }, + ExposureCompensation => { PrintConv => 'Image::ExifTool::Exif::PrintFraction($val)', Groups => { 2 => 'Camera' } }, + ISO => { Groups => { 2 => 'Camera' } }, + CameraDateTime=>{ PrintConv => '$self->ConvertDateTime($val)', Groups => { 2 => 'Time' } }, + VideoTimeStamp => { Groups => { 2 => 'Video' } }, + Accelerometer=> { Notes => '3-axis acceleration in units of g' }, + AccelerometerData => { }, + AngularVelocity => { }, + GSensor => { }, + Car => { }, + RawGSensor => { + # (same as GSensor, but offset by some unknown value) + ValueConv => 'my @a=split " ",$val; $_/=1000 foreach @a; "@a"', + }, + Text => { Groups => { 2 => 'Other' } }, + TimeCode => { Groups => { 2 => 'Video' } }, + FrameNumber => { Groups => { 2 => 'Video' } }, + SampleTime => { Groups => { 2 => 'Video' }, PrintConv => 'ConvertDuration($val)', Notes => 'sample decoding time' }, + SampleDuration=>{ Groups => { 2 => 'Video' }, PrintConv => 'ConvertDuration($val)' }, + UserLabel => { Groups => { 2 => 'Other' } }, + KiloCalories => { Groups => { 2 => 'Other' } }, + SampleDateTime => { + Groups => { 2 => 'Time' }, + ValueConv => q{ + my $str = ConvertUnixTime($val); + my $frac = $val - int($val); + if ($frac != 0) { + $frac = sprintf('%.6f', $frac); + $frac =~ s/^0//; + $frac =~ s/0+$//; + $str .= $frac; + } + return $str; + }, + PrintConv => '$self->ConvertDateTime($val)', + }, +# +# timed metadata decoded based on MetaFormat (format of 'meta' or 'data' sample description) +# [or HandlerType, or specific 'vide' type if specified] +# + mebx => { + Name => 'mebx', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::Keys', + ProcessProc => \&Process_mebx, + }, + }, + gpmd => [{ + Name => 'gpmd_Kingslim', # Kingslim D4 dashcam + Condition => '$$valPt =~ /^.{21}\0\0\0A[NS][EW]/s', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::Stream', + ProcessProc => \&ProcessFreeGPS, + }, + },{ + Name => 'gpmd_Rove', # Rove Stealth 4K encrypted text + Condition => '$$valPt =~ /^\0\0\xf2\xe1\xf0\xeeTT/', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::Stream', + ProcessProc => \&Process_text, + }, + },{ + Name => 'gpmd_FMAS', # Vantrue N2S binary format + Condition => '$$valPt =~ /^FMAS\0\0\0\0/', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::Stream', + ProcessProc => \&ProcessFMAS, + }, + },{ + Name => 'gpmd_GoPro', + SubDirectory => { TagTable => 'Image::ExifTool::GoPro::GPMF' }, + }], + fdsc => { + Name => 'fdsc', + Condition => '$$valPt =~ /^GPRO/', + # (other types of "fdsc" samples aren't yet parsed: /^GP\x00/ and /^GP\x04/) + SubDirectory => { TagTable => 'Image::ExifTool::GoPro::fdsc' }, + }, + rtmd => { + Name => 'rtmd', + SubDirectory => { TagTable => 'Image::ExifTool::Sony::rtmd' }, + }, + marl => { + Name => 'marl', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::marl' }, + }, + CTMD => { # (Canon Timed MetaData) + Name => 'CTMD', + SubDirectory => { TagTable => 'Image::ExifTool::Canon::CTMD' }, + }, + tx3g => { + Name => 'tx3g', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::tx3g' }, + }, + RVMI => [{ # data "OtherFormat" written by unknown software + Name => 'RVMI_gReV', + Condition => '$$valPt =~ /^gReV/', # GPS data + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::RVMI_gReV', + ByteOrder => 'Little-endian', + }, + },{ + Name => 'RVMI_sReV', + Condition => '$$valPt =~ /^sReV/', # sensor data + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::RVMI_sReV', + ByteOrder => 'Little-endian', + }, + # (there is also "tReV" data that hasn't been decoded yet) + }], + camm => [{ + Name => 'camm0', + # (according to the spec. the first 2 bytes are reserved and should be zero, + # but I have a sample where these bytes are non-zero, so allow anything here) + Condition => '$$valPt =~ /^..\0\0/s', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::camm0', + ByteOrder => 'Little-Endian', + }, + },{ + Name => 'camm1', + Condition => '$$valPt =~ /^..\x01\0/s', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::camm1', + ByteOrder => 'Little-Endian', + }, + },{ # (written by Insta360) - [HandlerType, not MetaFormat] + Name => 'camm2', + Condition => '$$valPt =~ /^..\x02\0/s', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::camm2', + ByteOrder => 'Little-Endian', + }, + },{ + Name => 'camm3', + Condition => '$$valPt =~ /^..\x03\0/s', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::camm3', + ByteOrder => 'Little-Endian', + }, + },{ + Name => 'camm4', + Condition => '$$valPt =~ /^..\x04\0/s', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::camm4', + ByteOrder => 'Little-Endian', + }, + },{ + Name => 'camm5', + Condition => '$$valPt =~ /^..\x05\0/s', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::camm5', + ByteOrder => 'Little-Endian', + }, + },{ + Name => 'camm6', + Condition => '$$valPt =~ /^..\x06\0/s', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::camm6', + ByteOrder => 'Little-Endian', + }, + },{ + Name => 'camm7', + Condition => '$$valPt =~ /^..\x07\0/s', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::camm7', + ByteOrder => 'Little-Endian', + }, + }], + mett => { # Parrot drones + Name => 'mett', + SubDirectory => { TagTable => 'Image::ExifTool::Parrot::mett' }, + }, + JPEG => { # (in CR3 images) - [vide HandlerType with JPEG in SampleDescription, not MetaFormat] + Name => 'JpgFromRaw', + Groups => { 2 => 'Preview' }, + RawConv => '$self->ValidateImage(\$val,$tag)', + }, + text => { # (TomTom Bandit MP4) - [sbtl HandlerType with 'text' in SampleDescription] + Name => 'PreviewInfo', + Condition => 'length $$valPt > 12 and Get32u($valPt,4) == length($$valPt) and $$valPt =~ /^.{8}\xff\xd8\xff/s', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::PreviewInfo' }, + }, + INSV => { + Groups => { 0 => 'Trailer', 1 => 'Insta360' }, # (so these groups will appear in the -listg options) + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::INSV_MakerNotes' }, + }, + Unknown00 => { Unknown => 1 }, + Unknown01 => { Unknown => 1 }, + Unknown02 => { Unknown => 1 }, + Unknown03 => { Unknown => 1 }, +); + +# tags found in 'camm' type 0 timed metadata (ref 4) +%Image::ExifTool::QuickTime::camm0 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + FIRST_ENTRY => 0, + NOTES => q{ + The camm0 through camm7 tables define tags extracted from the Google Street + View Camera Motion Metadata of MP4 videos. See + L<https://developers.google.com/streetview/publish/camm-spec> for the + specification. + }, + 4 => { + Name => 'AngleAxis', + Notes => 'angle axis orientation in radians in local coordinate system', + Format => 'float[3]', + }, +); + +# tags found in 'camm' type 1 timed metadata (ref 4) +%Image::ExifTool::QuickTime::camm1 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Camera' }, + FIRST_ENTRY => 0, + 4 => { + Name => 'PixelExposureTime', + Format => 'int32s', + ValueConv => '$val * 1e-9', + PrintConv => 'sprintf("%.4g ms", $val * 1000)', + }, + 8 => { + Name => 'RollingShutterSkewTime', + Format => 'int32s', + ValueConv => '$val * 1e-9', + PrintConv => 'sprintf("%.4g ms", $val * 1000)', + }, +); + +# tags found in 'camm' type 2 timed metadata (ref PH, Insta360Pro) +%Image::ExifTool::QuickTime::camm2 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + FIRST_ENTRY => 0, + 4 => { + Name => 'AngularVelocity', + Notes => 'gyro angular velocity about X, Y and Z axes in rad/s', + Format => 'float[3]', + }, +); + +# tags found in 'camm' type 3 timed metadata (ref PH, Insta360Pro) +%Image::ExifTool::QuickTime::camm3 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + FIRST_ENTRY => 0, + 4 => { + Name => 'Acceleration', + Notes => 'acceleration in the X, Y and Z directions in m/s^2', + Format => 'float[3]', + }, +); + +# tags found in 'camm' type 4 timed metadata (ref 4) +%Image::ExifTool::QuickTime::camm4 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + FIRST_ENTRY => 0, + 4 => { + Name => 'Position', + Notes => 'X, Y, Z position in local coordinate system', + Format => 'float[3]', + }, +); + +# tags found in 'camm' type 5 timed metadata (ref 4) +%Image::ExifTool::QuickTime::camm5 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + FIRST_ENTRY => 0, + 4 => { + Name => 'GPSLatitude', + Format => 'double', + RawConv => '$$self{FoundGPSLatitude} = 1; $val', + ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + }, + 12 => { + Name => 'GPSLongitude', + Format => 'double', + ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + }, + 20 => { + Name => 'GPSAltitude', + Format => 'double', + PrintConv => '$_ = sprintf("%.6f", $val); s/\.?0+$//; "$_ m"', + }, +); + +# tags found in 'camm' type 6 timed metadata (ref PH/4, Insta360) +%Image::ExifTool::QuickTime::camm6 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + FIRST_ENTRY => 0, + 0x04 => { + Name => 'GPSDateTime', + Description => 'GPS Date/Time', + Groups => { 2 => 'Time' }, + Format => 'double', + RawConv => '$$self{FoundGPSDateTime} = 1; $val', + # by the specification, this should use the GPS epoch of Jan 6, 1980, + # but I have samples which use the Unix epoch of Jan 1, 1970, so convert + # to the Unix Epoch only if it doesn't match the CreateDate within 5 years + ValueConv => q{ + my $offset = 315964800; + if ($$self{CreateDate} and $$self{CreateDate} - $val > 24 * 3600 * 365 * 5) { + $val += $offset; + } + my $str = ConvertUnixTime($val); + my $frac = $val - int($val); + if ($frac != 0) { + $frac = sprintf('%.6f', $frac); + $frac =~ s/^0//; + $frac =~ s/0+$//; + $str .= $frac; + } + return $str . 'Z'; + }, + PrintConv => '$self->ConvertDateTime($val)', + }, + 0x0c => { + Name => 'GPSMeasureMode', + Format => 'int32u', + PrintConv => { + 0 => 'No Measurement', + 2 => '2-Dimensional Measurement', + 3 => '3-Dimensional Measurement', + }, + }, + 0x10 => { + Name => 'GPSLatitude', + Format => 'double', + RawConv => '$$self{FoundGPSLatitude} = 1; $val', + ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + }, + 0x18 => { + Name => 'GPSLongitude', + Format => 'double', + ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + }, + 0x20 => { + Name => 'GPSAltitude', + Format => 'float', + PrintConv => '$_ = sprintf("%.3f", $val); s/\.?0+$//; "$_ m"', + }, + 0x24 => { Name => 'GPSHorizontalAccuracy', Format => 'float', Notes => 'metres' }, + 0x28 => { Name => 'GPSVerticalAccuracy', Format => 'float' }, + 0x2c => { Name => 'GPSVelocityEast', Format => 'float', Notes => 'm/s' }, + 0x30 => { Name => 'GPSVelocityNorth', Format => 'float' }, + 0x34 => { Name => 'GPSVelocityUp', Format => 'float' }, + 0x38 => { Name => 'GPSSpeedAccuracy', Format => 'float' }, +); + +# tags found in 'camm' type 7 timed metadata (ref 4) +%Image::ExifTool::QuickTime::camm7 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + FIRST_ENTRY => 0, + 4 => { + Name => 'MagneticField', + Format => 'float[3]', + Notes => 'microtesla', + }, +); + +# preview image stored by TomTom Bandit ActionCam +%Image::ExifTool::QuickTime::PreviewInfo = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + FIRST_ENTRY => 0, + NOTES => 'Preview stored by TomTom Bandit ActionCam.', + 8 => { + Name => 'PreviewImage', + Groups => { 2 => 'Preview' }, + Binary => 1, + Format => 'undef[$size-8]', + }, +); + +# tags found in 'RVMI' 'gReV' timed metadata (ref PH) +%Image::ExifTool::QuickTime::RVMI_gReV = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + FIRST_ENTRY => 0, + NOTES => 'GPS information extracted from the RVMI box of MOV videos.', + 4 => { + Name => 'GPSLatitude', + Format => 'int32s', + RawConv => '$$self{FoundGPSLatitude} = 1; $val', + ValueConv => 'Image::ExifTool::GPS::ToDegrees($val/1e6, 1)', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + }, + 8 => { + Name => 'GPSLongitude', + Format => 'int32s', + ValueConv => 'Image::ExifTool::GPS::ToDegrees($val/1e6, 1)', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + }, + # 12 - int32s: space for altitude? (always zero in my sample) + 16 => { + Name => 'GPSSpeed', # km/h + Format => 'int16s', + ValueConv => '$val / 10', + }, + 18 => { + Name => 'GPSTrack', + Format => 'int16u', + ValueConv => '$val * 2', + }, +); + +# tags found in 'RVMI' 'sReV' timed metadata (ref PH) +%Image::ExifTool::QuickTime::RVMI_sReV = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + FIRST_ENTRY => 0, + NOTES => q{ + G-sensor information extracted from the RVMI box of MOV videos. + }, + 4 => { + Name => 'GSensor', + Format => 'int16s[3]', # X Y Z + ValueConv => 'my @a=split " ",$val; $_/=1000 foreach @a; "@a"', + }, +); + +# tags found in 'tx3g' sbtl timed metadata (ref PH) +%Image::ExifTool::QuickTime::tx3g = ( + PROCESS_PROC => \&Process_tx3g, + GROUPS => { 2 => 'Location' }, + FIRST_ENTRY => 0, + NOTES => q{ + Tags extracted from the tx3g sbtl timed metadata of Yuneec drones, and + subtitle text in some other videos. + }, + Lat => { + Name => 'GPSLatitude', + RawConv => '$$self{FoundGPSLatitude} = 1; $val', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + }, + Lon => { + Name => 'GPSLongitude', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + }, + Alt => { + Name => 'GPSAltitude', + ValueConv => '$val =~ s/\s*m$//; $val', # remove " m" + PrintConv => '"$val m"', # add it back again + }, + Yaw => 'Yaw', + Pitch => 'Pitch', + Roll => 'Roll', + GimYaw => 'GimbalYaw', + GimPitch => 'GimbalPitch', + GimRoll => 'GimbalRoll', + DateTime => { # for date/time-format subtitle text + Groups => { 2 => 'Time' }, + PrintConv => '$self->ConvertDateTime($val)', + }, + Text => { Groups => { 2 => 'Other' } }, +); + +%Image::ExifTool::QuickTime::INSV_MakerNotes = ( + GROUPS => { 1 => 'MakerNotes', 2 => 'Camera' }, + 0x0a => 'SerialNumber', + 0x12 => 'Model', + 0x1a => 'Firmware', + 0x2a => { + Name => 'Parameters', + ValueConv => '$val =~ tr/_/ /; $val', + }, +); + +%Image::ExifTool::QuickTime::Tags360Fly = ( + PROCESS_PROC => \&Process360Fly, + NOTES => 'Timed metadata found in MP4 videos from the 360Fly.', + 1 => { + Name => 'Accel360Fly', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Accel360Fly' }, + }, + 2 => { + Name => 'Gyro360Fly', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Gyro360Fly' }, + }, + 3 => { + Name => 'Mag360Fly', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Mag360Fly' }, + }, + 5 => { + Name => 'GPS360Fly', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::GPS360Fly' }, + }, + 6 => { + Name => 'Rot360Fly', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Rot360Fly' }, + }, + 250 => { + Name => 'Fusion360Fly', + SubDirectory => { TagTable => 'Image::ExifTool::QuickTime::Fusion360Fly' }, + }, +); + +%Image::ExifTool::QuickTime::Accel360Fly = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + 1 => { Name => 'AccelMode', Unknown => 1 }, # (always 2 in my sample) + 2 => { + Name => 'SampleTime', + Groups => { 2 => 'Video' }, + Format => 'int64u', + ValueConv => '$val / 1e6', + PrintConv => 'ConvertDuration($val)', + }, + 10 => { Name => 'AccelYPR', Format => 'float[3]' }, +); + +%Image::ExifTool::QuickTime::Gyro360Fly = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + 1 => { Name => 'GyroMode', Unknown => 1 }, # (always 1 in my sample) + 2 => { + Name => 'SampleTime', + Groups => { 2 => 'Video' }, + Format => 'int64u', + ValueConv => '$val / 1e6', + PrintConv => 'ConvertDuration($val)', + }, + 10 => { Name => 'GyroYPR', Format => 'float[3]' }, +); + +%Image::ExifTool::QuickTime::Mag360Fly = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + 1 => { Name => 'MagMode', Unknown => 1 }, # (always 1 in my sample) + 2 => { + Name => 'SampleTime', + Groups => { 2 => 'Video' }, + Format => 'int64u', + ValueConv => '$val / 1e6', + PrintConv => 'ConvertDuration($val)', + }, + 10 => { Name => 'MagnetometerXYZ', Format => 'float[3]' }, +); + +%Image::ExifTool::QuickTime::GPS360Fly = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + 1 => { Name => 'GPSMode', Unknown => 1 }, # (always 16 in my sample) + 2 => { + Name => 'SampleTime', + Groups => { 2 => 'Video' }, + Format => 'int64u', + ValueConv => '$val / 1e6', + PrintConv => 'ConvertDuration($val)', + }, + 10 => { Name => 'GPSLatitude', Format => 'float', PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")' }, + 14 => { Name => 'GPSLongitude', Format => 'float', PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")' }, + 18 => { Name => 'GPSAltitude', Format => 'float', PrintConv => '"$val m"' }, # (questionable accuracy) + 22 => { + Name => 'GPSSpeed', + Notes => 'converted to km/hr', + Format => 'int16u', + ValueConv => '$val * 0.036', + PrintConv => 'sprintf("%.1f",$val)', + }, + 24 => { Name => 'GPSTrack', Format => 'int16u', ValueConv => '$val / 100' }, + 26 => { Name => 'Acceleration', Format => 'int16u', ValueConv => '$val / 1000' }, +); + +%Image::ExifTool::QuickTime::Rot360Fly = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + 1 => { Name => 'RotMode', Unknown => 1 }, # (always 1 in my sample) + 2 => { + Name => 'SampleTime', + Groups => { 2 => 'Video' }, + Format => 'int64u', + ValueConv => '$val / 1e6', + PrintConv => 'ConvertDuration($val)', + }, + 10 => { Name => 'RotationXYZ', Format => 'float[3]' }, +); + +%Image::ExifTool::QuickTime::Fusion360Fly = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + 1 => { Name => 'FusionMode', Unknown => 1 }, # (always 0 in my sample) + 2 => { + Name => 'SampleTime', + Groups => { 2 => 'Video' }, + Format => 'int64u', + ValueConv => '$val / 1e6', + PrintConv => 'ConvertDuration($val)', + }, + 10 => { Name => 'FusionYPR', Format => 'float[3]' }, +); + +# tags found in 'marl' ctbx timed metadata (ref PH) +%Image::ExifTool::QuickTime::marl = ( + PROCESS_PROC => \&Process_marl, + GROUPS => { 2 => 'Other' }, + NOTES => 'Tags extracted from the marl ctbx timed metadata of GM cars.', +); + +#------------------------------------------------------------------------------ +# Save information from keys in OtherSampleDesc directory for processing timed metadata +# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +# (ref "Timed Metadata Media" here: +# https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html) +sub SaveMetaKeys($$$) +{ + local $_; + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dirLen = length $$dataPt; + return 0 unless $dirLen > 8; + my $pos = 0; + my $verbose = $$et{OPTIONS}{Verbose}; + my $oldIndent = $$et{INDENT}; + my $ee = $$et{ee}; + $ee or $ee = $$et{ee} = { }; + + $verbose and $et->VerboseDir($$dirInfo{DirName}, undef, $dirLen); + + # loop through metadata key table + while ($pos + 8 < $dirLen) { + my $size = Get32u($dataPt, $pos); + my $id = substr($$dataPt, $pos+4, 4); + my $end = $pos + $size; + $end = $dirLen if $end > $dirLen; + $pos += 8; + my ($tagID, $format, $pid); + if ($verbose) { + $pid = PrintableTagID($id,1); + $et->VPrint(0, "$oldIndent+ [Metadata Key entry, Local ID=$pid, $size bytes]\n"); + $$et{INDENT} .= '| '; + } + + while ($pos + 4 < $end) { + my $len = unpack("x${pos}N", $$dataPt); + last if $len < 8 or $pos + $len > $end; + my $tag = substr($$dataPt, $pos + 4, 4); + $pos += 8; $len -= 8; + my $val = substr($$dataPt, $pos, $len); + $pos += $len; + my $str; + if ($tag eq 'keyd') { + ($tagID = $val) =~ s/^(mdta|fiel)com\.apple\.quicktime\.//; + $tagID = "Tag_$val" unless $tagID; + ($str = $val) =~ s/(.{4})/$1 / if $verbose; + } elsif ($tag eq 'dtyp') { + next if length $val < 4; + if (length $val >= 4) { + my $ns = unpack('N', $val); + if ($ns == 0) { + length $val >= 8 or $et->Warn('Short dtyp data'), next; + $str = unpack('x4N',$val); + $format = $qtFmt{$str} || 'undef'; + } elsif ($ns == 1) { + $str = substr($val, 4); + $format = 'undef'; + } else { + $format = 'undef'; + } + $str .= " ($format)" if $verbose and defined $str; + } + } + if ($verbose > 1) { + if (defined $str) { + $str =~ tr/\x00-\x1f\x7f-\xff/./; + $str = " = $str"; + } else { + $str = ''; + } + $et->VPrint(1, $$et{INDENT}."- Tag '".PrintableTagID($tag,2)."' ($len bytes)$str\n"); + $et->VerboseDump(\$val); + } + } + if (defined $tagID and defined $format) { + if ($verbose) { + my $t2 = PrintableTagID($tagID); + $et->VPrint(0, "$$et{INDENT}Added Local ID $pid = $t2 ($format)\n"); + } + $$ee{'keys'}{$id} = { TagID => $tagID, Format => $format }; + } + $$et{INDENT} = $oldIndent; + } + return 1; +} + +#------------------------------------------------------------------------------ +# We found some tags for this sample, so set document number and save timing information +# Inputs: 0) ExifTool ref, 1) tag table ref, 2) sample time, 3) sample duration +sub FoundSomething($$;$$) +{ + my ($et, $tagTbl, $time, $dur) = @_; + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + $et->HandleTag($tagTbl, SampleTime => $time) if defined $time; + $et->HandleTag($tagTbl, SampleDuration => $dur) if defined $dur; +} + +#------------------------------------------------------------------------------ +# Approximate GPSDateTime value from sample time and CreateDate +# Inputs: 0) ExifTool ref, 1) tag table ptr, 2) sample time (s) +# 3) true if CreateDate is at end of video +# Notes: Uses ExifTool CreateDateAtEnd as flag to subtract video duration +sub SetGPSDateTime($$$) +{ + my ($et, $tagTbl, $sampleTime) = @_; + my $value = $$et{VALUE}; + if (defined $sampleTime and $$value{CreateDate}) { + $sampleTime += $$value{CreateDate}; # adjust sample time to seconds since the epoch + if ($$et{CreateDateAtEnd}) { # adjust if CreateDate is at end of video + return unless $$value{TimeScale} and $$value{Duration}; + $sampleTime -= $$value{Duration} / $$value{TimeScale}; + $et->WarnOnce('Approximating GPSDateTime as CreateDate - Duration + SampleTime', 1); + } else { + $et->WarnOnce('Approximating GPSDateTime as CreateDate + SampleTime', 1); + } + unless ($et->Options('QuickTimeUTC')) { + my $tzOff = $$et{tzOff}; # use previously calculated offset + unless (defined $tzOff) { + # adjust to UTC, assuming time is local + my @tm = localtime $$value{CreateDate}; + my @gm = gmtime $$value{CreateDate}; + $tzOff = $$et{tzOff} = Image::ExifTool::GetTimeZone(\@tm, \@gm) * 60; + } + $sampleTime -= $tzOff; # shift from local time to UTC + } + $et->HandleTag($tagTbl, GPSDateTime => Image::ExifTool::ConvertUnixTime($sampleTime,0,3) . 'Z'); + } +} + +#------------------------------------------------------------------------------ +# Handle tags that we found in the subtitle 'text' +# Inputs: 0) ExifTool ref, 1) tag table ref, 2) hash of tag names/values +sub HandleTextTags($$$) +{ + my ($et, $tagTbl, $tags) = @_; + my $tag; + delete $$tags{done}; + delete $$tags{GPSTimeStamp} if $$tags{GPSDateTime}; + foreach $tag (sort keys %$tags) { + $et->HandleTag($tagTbl, $tag => $$tags{$tag}); + } + $$et{UnknownTextCount} = 0; + undef %$tags; # clear the hash +} + +#------------------------------------------------------------------------------ +# Process subtitle 'text' +# Inputs: 0) ExifTool ref, 1) data ref or dirInfo ref, 2) tag table ref +sub Process_text($$$) +{ + my ($et, $dataPt, $tagTbl) = @_; + my %tags; + + return if $$et{NoMoreTextDecoding}; + + if (ref $dataPt eq 'HASH') { + my $dirName = $$dataPt{DirName}; + $dataPt = $$dataPt{DataPt}; + $et->VerboseDir($dirName, undef, length($$dataPt)); + } + + while ($$dataPt =~ /\$(\w+)([^\$]*)/g) { + my ($tag, $dat) = ($1, $2); + if ($tag =~ /^[A-Z]{2}RMC$/ and $dat =~ /^,(\d{2})(\d{2})(\d+(?:\.\d*)),A?,(\d*?)(\d{1,2}\.\d+),([NS]),(\d*?)(\d{1,2}\.\d+),([EW]),(\d*\.?\d*),(\d*\.?\d*),(\d{2})(\d{2})(\d+)/) { + my $time = "$1:$2:$3"; + if ($$et{LastTime}) { + if ($$et{LastTime} eq $time) { + $$et{DOC_NUM} = $$et{LastDoc}; + } elsif (%tags) { + HandleTextTags($et, $tagTbl, \%tags); + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + } + } + $$et{LastTime} = $time; + $$et{LastDoc} = $$et{DOC_NUM}; + my $year = $14 + ($14 >= 70 ? 1900 : 2000); + my $dateTime = sprintf('%.4d:%.2d:%.2d %sZ', $year, $13, $12, $time); + $tags{GPSDateTime} = $dateTime; + $tags{GPSLatitude} = (($4 || 0) + $5/60) * ($6 eq 'N' ? 1 : -1); + $tags{GPSLongitude} = (($7 || 0) + $8/60) * ($9 eq 'E' ? 1 : -1); + $tags{GPSSpeed} = $10 * $knotsToKph if length $10; + $tags{GPSTrack} = $11 if length $11; + } elsif ($tag =~ /^[A-Z]{2}GGA$/ and $dat =~ /^,(\d{2})(\d{2})(\d+(?:\.\d*)?),(\d*?)(\d{1,2}\.\d+),([NS]),(\d*?)(\d{1,2}\.\d+),([EW]),[1-6]?,(\d+)?,(\.\d+|\d+\.?\d*)?,(-?\d+\.?\d*)?,M?/s) { + my $time = "$1:$2:$3"; + if ($$et{LastTime}) { + if ($$et{LastTime} eq $time) { + $$et{DOC_NUM} = $$et{LastDoc}; + } elsif (%tags) { + HandleTextTags($et, $tagTbl, \%tags); + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + } + } + $$et{LastTime} = $time; + $$et{LastDoc} = $$et{DOC_NUM}; + $tags{GPSTimeStamp} = $time; + $tags{GPSLatitude} = (($4 || 0) + $5/60) * ($6 eq 'N' ? 1 : -1); + $tags{GPSLongitude} = (($7 || 0) + $8/60) * ($9 eq 'E' ? 1 : -1); + $tags{GPSSatellites} = $10 if defined $10; + $tags{GPSDOP} = $11 if defined $11; + $tags{GPSAltitude} = $12 if defined $12; + } elsif ($tag eq 'BEGINGSENSOR' and $dat =~ /^:([-+]\d+\.\d+):([-+]\d+\.\d+):([-+]\d+\.\d+)/) { + $tags{Accelerometer} = "$1 $2 $3"; + } elsif ($tag eq 'TIME' and $dat =~ /^:(\d+)/) { + $tags{TimeCode} = $1 / ($$et{MediaTS} || 1); + } elsif ($tag eq 'BEGIN') { + $tags{Text} = $dat if length $dat; + $tags{done} = 1; + } elsif ($tag ne 'END') { + $tags{Text} = "\$$tag$dat"; + } + } + %tags and HandleTextTags($et, $tagTbl, \%tags), return; + + # check for enciphered binary GPS data + # BlueSkySea: + # 0000: 00 00 aa aa aa aa 54 54 98 9a 9b 93 9a 92 98 9a [......TT........] + # 0010: 9a 9d 9f 9b 9f 9d aa aa aa aa aa aa aa aa aa aa [................] + # 0020: aa aa aa aa aa a9 e4 9e 92 9f 9b 9f 92 9d 99 ef [................] + # 0030: 9a 9a 98 9b 93 9d 9d 9c 93 aa aa aa aa aa 9a 99 [................] + # 0040: 9b aa aa aa aa aa aa aa aa aa aa aa aa aa aa aa [................] + # [...] + # decrypted: + # 0000: aa aa 00 00 00 00 fe fe 32 30 31 39 30 38 32 30 [........20190820] + # 0010: 30 37 35 31 35 37 00 00 00 00 00 00 00 00 00 00 [075157..........] + # 0020: 00 00 00 00 00 03 4e 34 38 35 31 35 38 37 33 45 [......N48515873E] + # 0030: 30 30 32 31 39 37 37 36 39 00 00 00 00 00 30 33 [002197769.....03] + # 0040: 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [1...............] + # [...] + # Ambarella A12: + # 0000: 00 00 f2 e1 f0 ee 54 54 98 9a 9b 93 9b 9b 9b 9c [......TT........] + # 0010: 9b 9a 9a 93 9a 9b a6 9a 9b 9b 93 9b 9a 9b 9c 9a [................] + # 0020: 9d 9a 92 9f 93 a9 e4 9f 9f 9e 9f 9b 9b 9c 9d ef [................] + # 0030: 9a 99 9d 9e 99 9a 9a 9e 9b 81 9a 9b 9f 9d 9a 9a [................] + # 0040: 9a 87 9a 9a 9a 87 9a 98 99 87 9a 9a 99 87 9a 9a [................] + # [...] + # decrypted: + # 0000: aa aa 58 4b 5a 44 fe fe 32 30 31 39 31 31 31 36 [..XKZD..20191116] + # 0010: 31 30 30 39 30 31 0c 30 31 31 39 31 30 31 36 30 [100901.011910160] + # 0020: 37 30 38 35 39 03 4e 35 35 34 35 31 31 36 37 45 [70859.N55451167E] + # 0030: 30 33 37 34 33 30 30 34 31 2b 30 31 35 37 30 30 [037430041+015700] + # 0040: 30 2d 30 30 30 2d 30 32 33 2d 30 30 33 2d 30 30 [0-000-023-003-00] + # [...] + # 0100: aa 55 57 ed ed 45 58 54 44 00 01 30 30 30 30 31 [.UW..EXTD..00001] + # 0110: 31 30 38 30 30 30 58 00 58 00 58 00 58 00 58 00 [108000X.X.X.X.X.] + # 0120: 58 00 58 00 58 00 58 00 00 00 00 00 00 00 00 00 [X.X.X.X.........] + # 0130: 00 00 00 00 00 00 00 [.......] + if ($$dataPt =~ /^\0\0(..\xaa\xaa|\xf2\xe1\xf0\xee)/s and length $$dataPt >= 282) { + my $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 8, 14))); + if ($val =~ /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/) { + $tags{GPSDateTime} = "$1:$2:$3 $4:$5:$6"; + $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 38, 9))); + if ($val =~ /^([NS])(\d{2})(\d+$)$/) { + $tags{GPSLatitude} = ($2 + $3 / 600000) * ($1 eq 'S' ? -1 : 1); + } + $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 47, 10))); + if ($val =~ /^([EW])(\d{3})(\d+$)$/) { + $tags{GPSLongitude} = ($2 + $3 / 600000) * ($1 eq 'W' ? -1 : 1); + } + $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0x39, 5))); + $tags{GPSAltitude} = $val + 0 if $val =~ /^[-+]\d+$/; + $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0x3e, 3))); + $tags{GPSSpeed} = $val + 0 if $val =~ /^\d+$/; + if ($$dataPt =~ /^\0\0..\xaa\xaa/s) { # (BlueSkySea) + $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0xad, 12))); + # the first X,Y,Z accelerometer readings from the AccelerometerData + if ($val =~ /^([-+]\d{3})([-+]\d{3})([-+]\d{3})$/) { + $tags{Accelerometer} = "$1 $2 $3"; + $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0xba, 96))); + my $order = GetByteOrder(); + SetByteOrder('II'); + $val = ReadValue(\$val, 0, 'float'); + SetByteOrder($order); + $tags{AccelerometerData} = $val; + } + } else { # (Ambarella) + my @acc; + $val = pack('C*', map { $_ ^ 0xaa } unpack('C*', substr($$dataPt, 0x41, 195))); + push @acc, $1, $2, $3 while $val =~ /\G([-+]\d{3})([-+]\d{3})([-+]\d{3})/g; + $tags{Accelerometer} = "@acc" if @acc; + } + } + %tags and HandleTextTags($et, $tagTbl, \%tags), return; + } + + # check for DJI telemetry data, eg: + # "F/3.5, SS 1000, ISO 100, EV 0, GPS (8.6499, 53.1665, 18), D 24.26m, + # H 6.00m, H.S 2.10m/s, V.S 0.00m/s \n" + if ($$dataPt =~ /GPS \(([-+]?\d*\.\d+),\s*([-+]?\d*\.\d+)/) { + $$et{CreateDateAtEnd} = 1; # set flag indicating the file creation date is at the end + $tags{GPSLatitude} = $2; + $tags{GPSLongitude} = $1; + $tags{GPSAltitude} = $1 if $$dataPt =~ /,\s*H\s+([-+]?\d+\.?\d*)m/; + $tags{GPSSpeed} = $1 * $mpsToKph if $$dataPt =~ /,\s*H.S\s+([-+]?\d+\.?\d*)/; + $tags{Distance} = $1 * $mpsToKph if $$dataPt =~ /,\s*D\s+(\d+\.?\d*)m/; + $tags{VerticalSpeed} = $1 if $$dataPt =~ /,\s*V.S\s+([-+]?\d+\.?\d*)/; + $tags{FNumber} = $1 if $$dataPt =~ /\bF\/(\d+\.?\d*)/; + $tags{ExposureTime} = 1 / $1 if $$dataPt =~ /\bSS\s+(\d+\.?\d*)/; + $tags{ExposureCompensation} = ($1 / ($2 || 1)) if $$dataPt =~ /\bEV\s+([-+]?\d+\.?\d*)(\/\d+)?/; + $tags{ISO} = $1 if $$dataPt =~ /\bISO\s+(\d+\.?\d*)/; + HandleTextTags($et, $tagTbl, \%tags); + return; + } + + # check for Mini 0806 dashcam GPS, eg: + # "A,270519,201555.000,3356.8925,N,08420.2071,W,000.0,331.0M,+01.84,-09.80,-00.61;\n" + if ($$dataPt =~ /^A,(\d{2})(\d{2})(\d{2}),(\d{2})(\d{2})(\d{2}(\.\d+)?)/) { + $tags{GPSDateTime} = "20$3:$2:$1 $4:$5:$6Z"; + if ($$dataPt =~ /^A,.*?,.*?,(\d{2})(\d+\.\d+),([NS])/) { + $tags{GPSLatitude} = ($1 + $2/60) * ($3 eq 'S' ? -1 : 1); + } + if ($$dataPt =~ /^A,.*?,.*?,.*?,.*?,(\d{3})(\d+\.\d+),([EW])/) { + $tags{GPSLongitude} = ($1 + $2/60) * ($3 eq 'W' ? -1 : 1); + } + my @a = split ',', $$dataPt; + $tags{GPSAltitude} = $a[8] if $a[8] and $a[8] =~ s/M$//; + $tags{GPSSpeed} = $a[7] if $a[7] and $a[7] =~ /^\d+\.\d+$/; # (NC) + $tags{Accelerometer} = "$a[9] $a[10] $a[11]" if $a[11] and $a[11] =~ s/;\s*$//; + HandleTextTags($et, $tagTbl, \%tags); + return; + } + + # check for Roadhawk dashcam text + # ".;;;;D?JL;6+;;;D;R?;4;;;;DBB;;O;;;=D;L;;HO71G>F;-?=J-F:FNJJ;DPP-JF3F;;PL=DBRLBF0F;=?DNF-RD-PF;N;?=JF;;?D=F:*6F~" + # decoded: + # "X0000.2340Y-000.0720Z0000.9900G0001.0400$GPRMC,082138,A,5330.6683,N,00641.9749,W,012.5,87.86,050213,002.1,A" + # (note: "002.1" is magnetic variation and is not decoded; it should have ",E" or ",W" afterward for direction) + if ($$dataPt =~ /\*[0-9A-F]{2}~$/) { + # (ref https://reverseengineering.stackexchange.com/questions/11582/how-to-reverse-engineer-dash-cam-metadata) + my @decode = unpack 'C*', '-I8XQWRVNZOYPUTA0B1C2SJ9K.L,M$D3E4F5G6H7'; + my @chars = unpack 'C*', substr($$dataPt, 0, -4); + foreach (@chars) { + my $n = $_ - 43; + $_ = $decode[$n] if $n >= 0 and defined $decode[$n]; + } + my $buff = pack 'C*', @chars; + if ($buff =~ /X(.*?)Y(.*?)Z(.*?)G(.*?)\$/) { + # yup. the decoding worked out + $tags{Accelerometer} = "$1 $2 $3 $4"; + $$dataPt = $buff; # (process GPRMC below) + } + } + + # check for Thinkware format (and other NMEA RMC), eg: + # "gsensori,4,512,-67,-12,100;GNRMC,161313.00,A,4529.87489,N,07337.01215,W,6.225,35.34,310819,,,A*52..; + # CAR,0,0,0,0.0,0,0,0,0,0,0,0,0" + if ($$dataPt =~ /[A-Z]{2}RMC,(\d{2})(\d{2})(\d+(\.\d*)?),A?,(\d*?)(\d{1,2}\.\d+),([NS]),(\d*?)(\d{1,2}\.\d+),([EW]),(\d*\.?\d*),(\d*\.?\d*),(\d{2})(\d{2})(\d+)/ and + # do some basic sanity checks on the date + $13 <= 31 and $14 <= 12 and $15 <= 99) + { + my $year = $15 + ($15 >= 70 ? 1900 : 2000); + $tags{GPSDateTime} = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ', $year, $14, $13, $1, $2, $3); + $tags{GPSLatitude} = (($5 || 0) + $6/60) * ($7 eq 'N' ? 1 : -1); + $tags{GPSLongitude} = (($8 || 0) + $9/60) * ($10 eq 'E' ? 1 : -1); + $tags{GPSSpeed} = $11 * $knotsToKph if length $11; + $tags{GPSTrack} = $12 if length $12; + } + $tags{GSensor} = $1 if $$dataPt =~ /\bgsensori,(.*?)(;|$)/; + $tags{Car} = $1 if $$dataPt =~ /\bCAR,(.*?)(;|$)/; + + if (%tags) { + HandleTextTags($et, $tagTbl, \%tags); + } else { + $$et{UnknownTextCount} = ($$et{UnknownTextCount} || 0) + 1; + # give up trying to decode useful information if we haven't found anything for a while + $$et{NoMoreTextDecoding} = 1 if $$et{UnknownTextCount} > 100; + } +} + +#------------------------------------------------------------------------------ +# Extract embedded metadata from media samples +# Inputs: 0) ExifTool ref +# Notes: Also accesses ExifTool RAF*, SET_GROUP1, HandlerType, MetaFormat, +# ee*, and avcC elements (* = must exist) +sub ProcessSamples($) +{ + my $et = shift; + my ($raf, $ee) = @$et{qw(RAF ee)}; + my ($i, $buff, $pos, $hdrLen, $hdrFmt, @time, @dur, $oldIndent); + + return unless $ee; + delete $$et{ee}; # use only once + + # only process specific types of video streams + my $type = $$et{HandlerType} || ''; + if ($type eq 'vide') { + if ($$ee{avcC}) { $type = 'avcC' } + elsif ($$ee{JPEG}) { $type = 'JPEG' } + else { return } + } + + my ($start, $size) = @$ee{qw(start size)}; +# +# determine sample start offsets from chunk offsets (stco) and sample-to-chunk table (stsc), +# and sample time/duration from time-to-sample (stts) +# + unless ($start and $size) { + return unless $size; + my ($stco, $stsc, $stts) = @$ee{qw(stco stsc stts)}; + return unless $stco and $stsc and @$stsc; + $start = [ ]; + my ($nextChunk, $iChunk) = (0, 1); + my ($chunkStart, $startChunk, $samplesPerChunk, $descIdx, $timeCount, $timeDelta, $time); + if ($stts and @$stts > 1) { + $time = 0; + $timeCount = shift @$stts; + $timeDelta = shift @$stts; + } + my $ts = $$et{MediaTS} || 1; + foreach $chunkStart (@$stco) { + if ($iChunk >= $nextChunk and @$stsc) { + ($startChunk, $samplesPerChunk, $descIdx) = @{shift @$stsc}; + $nextChunk = $$stsc[0][0] if @$stsc; + } + @$size < @$start + $samplesPerChunk and $et->WarnOnce('Sample size error'), last; + my $sampleStart = $chunkStart; +Sample: for ($i=0; ; ) { + push @$start, $sampleStart; + if (defined $time) { + until ($timeCount) { + if (@$stts < 2) { + undef $time; + last Sample; + } + $timeCount = shift @$stts; + $timeDelta = shift @$stts; + } + push @time, $time / $ts; + push @dur, $timeDelta / $ts; + $time += $timeDelta; + --$timeCount; + } + # (eventually should use the description indices: $descIdx) + last if ++$i >= $samplesPerChunk; + $sampleStart += $$size[$#$start]; + } + ++$iChunk; + } + @$start == @$size or $et->WarnOnce('Incorrect sample start/size count'), return; + } +# +# extract and parse the sample data +# + my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); + my $verbose = $et->Options('Verbose'); + my $metaFormat = $$et{MetaFormat} || ''; + my $tell = $raf->Tell(); + + if ($verbose) { + $et->VPrint(0, "---- Extract Embedded ----\n"); + $oldIndent = $$et{INDENT}; + $$et{INDENT} = ''; + } + # get required information from avcC box if parsing video data + if ($type eq 'avcC') { + $hdrLen = (Get8u(\$$ee{avcC}, 4) & 0x03) + 1; + $hdrFmt = ($hdrLen == 4 ? 'N' : $hdrLen == 2 ? 'n' : 'C'); + require Image::ExifTool::H264; + } + # loop through all samples + for ($i=0; $i<@$start and $i<@$size; ++$i) { + + # initialize our flags for setting GPSDateTime + delete $$et{FoundGPSLatitude}; + delete $$et{FoundGPSDateTime}; + + # read the sample data + my $size = $$size[$i]; + next unless $raf->Seek($$start[$i], 0) and $raf->Read($buff, $size) == $size; + + if ($type eq 'avcC') { + next if length($buff) <= $hdrLen; + # scan through all NAL units and send them to ParseH264Video() + for ($pos=0; ; ) { + my $len = unpack("x$pos$hdrFmt", $buff); + last if $pos + $hdrLen + $len > length($buff); + my $tmp = "\0\0\0\x01" . substr($buff, $pos+$hdrLen, $len); + Image::ExifTool::H264::ParseH264Video($et, \$tmp); + $pos += $hdrLen + $len; + last if $pos + $hdrLen >= length($buff); + } + if ($$et{GotNAL06}) { + my $eeOpt = $et->Options('ExtractEmbedded'); + last unless $eeOpt and $eeOpt > 2; + } + next; + } + if ($verbose > 1) { + my $hdr = $$et{SET_GROUP1} ? "$$et{SET_GROUP1} Type='${type}' Format='${metaFormat}'" : "Type='${type}'"; + $et->VPrint(1, "${hdr}, Sample ".($i+1).' of '.scalar(@$start)." ($size bytes)\n"); + $et->VerboseDump(\$buff, Addr => $$start[$i]); + } + if ($type eq 'text' or + # (PNDM is normally 'text', but was sbtl/tx3g in concatenated Garmin sample output_3videos.mp4) + ($type eq 'sbtl' and $metaFormat eq 'tx3g' and $buff =~ /^..PNDM/s)) + { + + FoundSomething($et, $tagTbl, $time[$i], $dur[$i]); + unless ($buff =~ /^\$BEGIN/) { + # remove ending "encd" box if it exists + $buff =~ s/\0\0\0\x0cencd\0\0\x01\0$// and $size -= 12; + # cameras such as the CanonPowerShotN100 store ASCII time codes with a + # leading 2-byte integer giving the length of the string + # (and chapter names start with a 2-byte integer too) + if ($size >= 2 and unpack('n',$buff) == $size - 2) { + next if $size == 2; + $buff = substr($buff,2); + } + my $val; + # check for encrypted GPS text as written by E-PRANCE B47FS camera + if ($buff =~ /^\0/ and $buff =~ /\x0a$/ and length($buff) > 5) { + # decode simple ASCII difference cipher, + # based on known value of 4th-last char = '*' + my $dif = ord('*') - ord(substr($buff, -4, 1)); + my $tmp = pack 'C*',map { $_=($_+$dif)&0xff } unpack 'C*',substr $buff,1,-1; + if ($verbose > 2) { + $et->VPrint(0, "[decrypted text]\n"); + $et->VerboseDump(\$tmp); + } + if ($tmp =~ /^(.*?)(\$[A-Z]{2}RMC.*)/s) { + ($val, $buff) = ($1, $2); + $val =~ tr/\t/ /; + $et->HandleTag($tagTbl, RawGSensor => $val) if length $val; + } + } elsif ($buff =~ /^(\0.{3})?PNDM/s) { + # Garmin Dashcam format (actually binary, not text) + my $n = $1 ? 4 : 0; # skip leading 4-byte size word if it exists + next if length($buff) < 20 + $n; + $et->HandleTag($tagTbl, GPSLatitude => Get32s(\$buff, 12+$n) * 180/0x80000000); + $et->HandleTag($tagTbl, GPSLongitude => Get32s(\$buff, 16+$n) * 180/0x80000000); + $et->HandleTag($tagTbl, GPSSpeed => Get16u(\$buff, 8+$n) * $mphToKph); + SetGPSDateTime($et, $tagTbl, $time[$i]); + next; # all done (don't store/process as text) + } + unless (defined $val) { + $et->HandleTag($tagTbl, Text => $buff); # just store any other text + } + } + Process_text($et, \$buff, $tagTbl); + + } elsif ($processByMetaFormat{$type}) { + + if ($$tagTbl{$metaFormat}) { + my $tagInfo = $et->GetTagInfo($tagTbl, $metaFormat, \$buff); + if ($tagInfo) { + FoundSomething($et, $tagTbl, $time[$i], $dur[$i]); + $$et{ee} = $ee; # need ee information for 'keys' + $et->HandleTag($tagTbl, $metaFormat, undef, + DataPt => \$buff, + DataPos => 0, + Base => $$start[$i], # (Base must be set for CR3 files) + TagInfo => $tagInfo, + ); + delete $$et{ee}; + } elsif ($metaFormat eq 'camm' and $buff =~ /^X/) { + # seen 'camm' metadata in this format (X/Y/Z acceleration and G force? + GPRMC + ?) + # "X0000.0000Y0000.0000Z0000.0000G0000.0000$GPRMC,000125,V,,,,,000.0,,280908,002.1,N*71~, 794021 \x0a" + FoundSomething($et, $tagTbl, $time[$i], $dur[$i]); + $et->HandleTag($tagTbl, Accelerometer => "$1 $2 $3 $4") if $buff =~ /X(.*?)Y(.*?)Z(.*?)G(.*?)\$/; + Process_text($et, \$buff, $tagTbl); + } + } elsif ($verbose) { + $et->VPrint(0, "Unknown $type format ($metaFormat)"); + } + + } elsif ($type eq 'gps ') { # (ie. GPSDataList tag) + + if ($buff =~ /^....freeGPS /s) { + # decode "freeGPS " data (Novatek) + ProcessFreeGPS($et, { + DataPt => \$buff, + DataPos => $$start[$i], + SampleTime => $time[$i], + SampleDuration => $dur[$i], + }, $tagTbl) ; + } + + } elsif ($$tagTbl{$type}) { + + my $tagInfo = $et->GetTagInfo($tagTbl, $type, \$buff); + if ($tagInfo) { + FoundSomething($et, $tagTbl, $time[$i], $dur[$i]); + $et->HandleTag($tagTbl, $type, undef, + DataPt => \$buff, + DataPos => 0, + Base => $$start[$i], # (Base must be set for CR3 files) + TagInfo => $tagInfo, + ); + } + } + # generate approximate GPSDateTime if necessary + SetGPSDateTime($et, $tagTbl, $time[$i]) if $$et{FoundGPSLatitude} and not $$et{FoundGPSDateTime}; + } + if ($verbose) { + $$et{INDENT} = $oldIndent; + $et->VPrint(0, "--------------------------\n"); + } + # clean up + $raf->Seek($tell, 0); # restore original file position + $$et{DOC_NUM} = 0; + $$et{HandlerType} = $$et{HanderDesc} = ''; +} + +#------------------------------------------------------------------------------ +# Convert latitude/longitude from DDDMM.MMMM format to decimal degrees +# Inputs: 0) latitude, 1) longitude +# Returns: lat/lon are changed in place +# (note: this method works fine for negative coordinates) +sub ConvertLatLon($$) +{ + my $deg = int($_[0] / 100); # latitude + $_[0] = $deg + ($_[0] - $deg * 100) / 60; + $deg = int($_[1] / 100); # longitude + $_[1] = $deg + ($_[1] - $deg * 100) / 60; +} + +#------------------------------------------------------------------------------ +# Process "freeGPS " data blocks referenced by a 'gps ' (GPSDataList) atom +# Inputs: 0) ExifTool ref, 1) dirInfo ref {DataPt,SampleTime,SampleDuration}, 2) tagTable ref +# Returns: 1 on success (or 0 on unrecognized or "measurement-void" GPS data) +# Notes: +# - also see ProcessFreeGPS2() below for processing of other types of freeGPS blocks +sub ProcessFreeGPS($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dirLen = length $$dataPt; + my ($yr, $mon, $day, $hr, $min, $sec, $stat, $lbl, $ddd); + my ($lat, $latRef, $lon, $lonRef, $spd, $trk, $alt, @acc, @xtra); + + return 0 if $dirLen < 92; + + if (substr($$dataPt,18,8) eq "\xaa\xaa\xf2\xe1\xf0\xee\x54\x54") { + + # (this is very similar to the encrypted text format) + # decode encrypted ASCII-based GPS (DashCam Azdome GS63H, ref 5) + # header looks like this in my sample: + # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 05 01 00 00 [....freeGPS ....] + # 0010: 01 03 aa aa f2 e1 f0 ee 54 54 98 9a 9b 92 9a 93 [........TT......] + # 0020: 98 9e 98 98 9e 93 98 92 a6 9f 9f 9c 9d ed fa 8a [................] + # decrypted (from byte 18): + # 0000: 00 00 58 4b 5a 44 fe fe 32 30 31 38 30 39 32 34 [..XKZD..20180924] + # 0010: 32 32 34 39 32 38 0c 35 35 36 37 47 50 20 20 20 [224928.5567GP ] + # 0020: 00 00 00 00 00 03 4e 34 30 34 36 34 33 35 30 57 [......N40464350W] + # 0030: 30 30 37 30 34 30 33 30 38 30 30 30 30 30 30 30 [0070403080000000] + # 0040: 37 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [7...............] + # [...] + # 00a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 2b 30 39 [.............+09] + # 00b0: 33 2d 30 30 33 2d 30 30 35 00 00 00 00 00 00 00 [3-003-005.......] + # header looks like this for EEEkit gps: + # 0000: 00 00 04 00 66 72 65 65 47 50 53 20 f0 03 00 00 [....freeGPS ....] + # 0010: 01 03 aa aa f2 e1 f0 ee 54 54 98 9a 98 9a 9a 9f [........TT......] + # 0020: 9b 93 9b 9c 98 99 99 9f a6 9a 9a 98 9a 9a 9f 9b [................] + # 0030: 93 9b 9c 98 99 99 9c a9 e4 99 9d 9e 9f 98 9e 9b [................] + # 0040: 9c fd 9b 98 98 98 9f 9f 9a 9a 93 81 9a 9b 9d 9f [................] + # decrypted (from byte 18): + # 0000: 00 00 58 4b 5a 44 fe fe 32 30 32 30 30 35 31 39 [..XKZD..20200519] + # 0010: 31 36 32 33 33 35 0c 30 30 32 30 30 35 31 39 31 [162335.002005191] + # 0020: 36 32 33 33 36 03 4e 33 37 34 35 32 34 31 36 57 [62336.N37452416W] + # 0030: 31 32 32 32 35 35 30 30 39 2b 30 31 37 35 30 31 [122255009+017501] + # 0040: 31 2b 30 31 34 2b 30 30 32 2b 30 32 36 2b 30 31 [1+014+002+026+01] + my $n = $dirLen - 18; + $n = 0x101 if $n > 0x101; + my $buf2 = pack 'C*', map { $_ ^ 0xaa } unpack 'C*', substr($$dataPt,18,$n); + if ($et->Options('Verbose') > 1) { + $et->VPrint(1, '[decrypted freeGPS data]'); + $et->VerboseDump(\$buf2); + } + # (extract longitude as 9 digits, not 8, ref PH) + return 0 unless $buf2 =~ /^.{8}(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2}).(.{15})([NS])(\d{8})([EW])(\d{9})(\d{8})?/s; + ($yr,$mon,$day,$hr,$min,$sec,$lbl,$latRef,$lat,$lonRef,$lon,$spd) = ($1,$2,$3,$4,$5,$6,$7,$8,$9/1e4,$10,$11/1e4,$12); + if (defined $spd) { # (Azdome) + $spd += 0; # remove leading 0's + } elsif ($buf2 =~ /^.{57}([-+]\d{4})(\d{3})/s) { # (EEEkit) + # $alt = $1 + 0; (doesn't look right for my sample, but the Ambarella A12 text has this) + $spd = $2 + 0; + } + $lbl =~ s/\0.*//s; $lbl =~ s/\s+$//; # truncate at null and remove trailing spaces + push @xtra, UserLabel => $lbl if length $lbl; + # extract accelerometer data (ref PH) + if ($buf2 =~ /^.{65}(([-+]\d{3})([-+]\d{3})([-+]\d{3})([-+]\d{3})*)/s) { + $_ = $1; + @acc = ($2/100, $3/100, $4/100); + s/([-+])/ $1/g; s/^ //; + push @xtra, AccelerometerData => $_; + } elsif ($buf2 =~ /^.{173}([-+]\d{3})([-+]\d{3})([-+]\d{3})/s) { # (Azdome) + @acc = ($1/100, $2/100, $3/100); + } + + } elsif ($$dataPt =~ /^.{52}(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/s) { + + # decode NMEA-format GPS data (NextBase 512GW dashcam, ref PH) + # header looks like this in my sample: + # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 40 01 00 00 [....freeGPS @...] + # 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + push @xtra, CameraDateTime => "$1:$2:$3 $4:$5:$6"; + if ($$dataPt =~ /\$[A-Z]{2}RMC,(\d{2})(\d{2})(\d+(\.\d*)?),A?,(\d+\.\d+),([NS]),(\d+\.\d+),([EW]),(\d*\.?\d*),(\d*\.?\d*),(\d{2})(\d{2})(\d+)/s) { + ($lat,$latRef,$lon,$lonRef) = ($5,$6,$7,$8); + $yr = $13 + ($13 >= 70 ? 1900 : 2000); + ($mon,$day,$hr,$min,$sec) = ($12,$11,$1,$2,$3); + $spd = $9 * $knotsToKph if length $9; + $trk = $10 if length $10; + } + if ($$dataPt =~ /\$[A-Z]{2}GGA,(\d{2})(\d{2})(\d+(\.\d*)?),(\d+\.\d+),([NS]),(\d+\.\d+),([EW]),[1-6]?,(\d+)?,(\.\d+|\d+\.?\d*)?,(-?\d+\.?\d*)?,M?/s) { + ($hr,$min,$sec,$lat,$latRef,$lon,$lonRef) = ($1,$2,$3,$5,$6,$7,$8) unless defined $yr; + $alt = $11; + unshift @xtra, GPSSatellites => $9; + unshift @xtra, GPSDOP => $10; + } + if (defined $lat) { + # extract accelerometer readings if GPS was valid + @acc = unpack('x68V3', $$dataPt); + # change to signed integer and divide by 256 + map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 256 } @acc; + } + + } elsif ($$dataPt =~ /^.{37}\0\0\0A([NS])([EW])/s) { + + # decode freeGPS from ViofoA119v3 dashcam (similar to Novatek GPS format) + # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 03 00 00 [..@.freeGPS ....] + # 0010: 05 00 00 00 2f 00 00 00 03 00 00 00 13 00 00 00 [..../...........] + # 0020: 09 00 00 00 1b 00 00 00 41 4e 57 00 25 d1 99 45 [........ANW.%..E] + # 0030: f1 47 40 46 66 66 d2 41 85 eb 83 41 00 00 00 00 [.G@Fff.A...A....] + ($latRef, $lonRef) = ($1, $2); + ($hr,$min,$sec,$yr,$mon,$day) = unpack('x16V6', $$dataPt); + $yr += 2000; + SetByteOrder('II'); + $lat = GetFloat($dataPt, 0x2c); + $lon = GetFloat($dataPt, 0x30); + $spd = GetFloat($dataPt, 0x34) * $knotsToKph; # (convert knots to km/h) + $trk = GetFloat($dataPt, 0x38); + SetByteOrder('MM'); + + } elsif ($$dataPt =~ /^.{21}\0\0\0A([NS])([EW])/s) { + + # also decode 'gpmd' chunk from Kingslim D4 dashcam videos + # 0000: 0a 00 00 00 0b 00 00 00 07 00 00 00 e5 07 00 00 [................] + # 0010: 06 00 00 00 03 00 00 00 41 4e 57 31 91 52 83 45 [........ANW1.R.E] + # 0020: 15 70 fe c5 29 5c c3 41 ae c7 af 42 00 00 d1 be [.p..)\.A...B....] + # 0030: 00 00 80 3b 00 00 2c 3e 00 00 00 00 00 00 00 00 [...;..,>........] + # 0040: 00 00 00 00 00 00 00 00 00 00 00 00 26 26 26 26 [............&&&&] + # 0050: 4c 49 47 4f 47 50 53 49 4e 46 4f 00 00 00 00 05 [LIGOGPSINFO.....] + # 0060: 01 00 00 00 23 23 23 23 75 00 00 00 c0 22 20 20 [....####u...." ] + # 0070: 20 f0 12 10 12 21 e5 0e 10 12 2f 90 10 13 01 f2 [ ....!..../.....] + ($latRef, $lonRef) = ($1, $2); + ($hr,$min,$sec,$yr,$mon,$day) = unpack("V6", $$dataPt); + SetByteOrder('II'); + # lat/lon aren't decoded properly, but spd,trk,acc are + $lat = GetFloat($dataPt, 0x1c); + $lon = GetFloat($dataPt, 0x20); + $et->VPrint(0, sprintf("Raw lat/lon = %.9f %.9f\n", $lat, $lon)); + $et->WarnOnce('GPSLatitude/Longitude encryption is not yet known, so these will be wrong'); + $lat = abs $lat; + $lon = abs $lon; + $spd = GetFloat($dataPt, 0x24) * $knotsToKph; # (convert knots to km/h) + $trk = GetFloat($dataPt, 0x28); + $acc[0] = GetFloat($dataPt, 0x2c); + $acc[1] = GetFloat($dataPt, 0x30); + $acc[2] = GetFloat($dataPt, 0x34); + SetByteOrder('MM'); + + } elsif ($$dataPt =~ /^.{60}A\0{3}.{4}([NS])\0{3}.{4}([EW])\0{3}/s) { + + # decode freeGPS from Akaso dashcam + # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 60 00 00 00 [....freeGPS `...] + # 0010: 78 2e 78 78 00 00 00 00 00 00 00 00 00 00 00 00 [x.xx............] + # 0020: 30 30 30 30 30 00 00 00 00 00 00 00 00 00 00 00 [00000...........] + # 0030: 12 00 00 00 2f 00 00 00 19 00 00 00 41 00 00 00 [..../.......A...] + # 0040: 13 b3 ca 44 4e 00 00 00 29 92 fb 45 45 00 00 00 [...DN...)..EE...] + # 0050: d9 ee b4 41 ec d1 d3 42 e4 07 00 00 01 00 00 00 [...A...B........] + # 0060: 0c 00 00 00 01 00 00 00 05 00 00 00 00 00 00 00 [................] + ($latRef, $lonRef) = ($1, $2); + ($hr, $min, $sec, $yr, $mon, $day) = unpack('x48V3x28V3', $$dataPt); + SetByteOrder('II'); + $lat = GetFloat($dataPt, 0x40); + $lon = GetFloat($dataPt, 0x48); + $spd = GetFloat($dataPt, 0x50); + $trk = GetFloat($dataPt, 0x54) + 180; # (why is this off by 180?) + $trk -= 360 if $trk >= 360; + SetByteOrder('MM'); + + } elsif ($$dataPt =~ /^.{60}4W`b]S</s and length($$dataPt) >= 140) { + + # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 01 00 00 [..@.freeGPS ....] + # 0010: 5a 58 53 42 4e 58 59 53 00 00 00 00 00 00 00 00 [ZXSBNXYS........] + # 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0030: 00 00 00 00 00 00 00 00 00 00 00 00 34 57 60 62 [............4W`b] + # 0040: 5d 53 3c 41 44 45 41 41 42 3e 40 40 3c 51 3c 45 []S<ADEAAB>@@<Q<E] + # 0050: 41 40 43 3e 41 47 49 48 44 3c 5e 3c 40 41 46 43 [A@C>AGIHD<^<@AFC] + # 0060: 42 3e 49 49 40 42 45 3c 55 3c 45 47 3e 45 43 41 [B>II@BE<U<EG>ECA] + # decipher $GPRMC by subtracting 16 from each character value + $_ = pack 'C*', map { $_>=16 and $_-=16 } unpack('x60C80', $$dataPt); + return 0 unless /[A-Z]{2}RMC,(\d{2})(\d{2})(\d+(\.\d*)?),A?,(\d*?\d{1,2}\.\d+),([NS]),(\d*?\d{1,2}\.\d+),([EW]),(\d*\.?\d*),(\d*\.?\d*),(\d{2})(\d{2})(\d+)/; + ($yr,$mon,$day,$hr,$min,$sec,$lat,$latRef,$lon,$lonRef) = ($13,$12,$11,$1,$2,$3,$5,$6,$7,$8); + $yr += ($yr >= 70 ? 1900 : 2000); + $spd = $9 * $knotsToKph if length $9; + $trk = $10 if length $10; + + } elsif ($$dataPt =~ /^.{64}[\x01-\x0c]\0{3}[\x01-\x1f]\0{3}A[NS][EW]\0{5}/s) { + + # Akaso V1 dascham + # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 00 00 00 [....freeGPS x...] + # 0010: 59 6e 64 41 6b 61 73 6f 43 61 72 00 00 00 00 00 [YndAkasoCar.....] + # 0020: 30 30 30 30 30 00 00 00 00 00 00 00 00 00 00 00 [00000...........] + # 0030: 0e 00 00 00 27 00 00 00 2c 00 00 00 e3 07 00 00 [....'...,.......] + # 0040: 05 00 00 00 1d 00 00 00 41 4e 45 00 00 00 00 00 [........ANE.....] + # 0050: f1 4e 3e 3d 90 df ca 40 e3 50 bf 0b 0b 31 a0 40 [.N>=...@.P...1.@] + # 0060: 4b dc c8 41 9a 79 a7 43 34 58 43 31 4f 37 31 35 [K..A.y.C4XC1O715] + # 0070: 35 31 32 36 36 35 37 35 59 4e 44 53 0d e7 cc f9 [51266575YNDS....] + # 0080: 00 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 [................] + # Redtiger F7N dashcam + # 0000: 00 00 40 00 66 72 65 65 47 50 53 20 f0 01 00 00 [..@.freeGPS ....] + # 0010: 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0020: 01 00 00 00 b0 56 50 01 7b 18 68 45 17 02 3f 46 [.....VP.{.hE..?F] + # 0030: 13 00 00 00 01 00 00 00 06 00 00 00 15 00 00 00 [................] + # 0040: 0c 00 00 00 1c 00 00 00 41 4e 57 00 00 00 00 00 [........ANW.....] + # 0050: 80 d4 26 4e 36 11 b5 40 74 b5 15 7b cd 7b f3 40 [..&N6..@t..{.{.@] + # 0060: 0a d7 a3 3d cd 4c 4e 43 38 34 37 41 45 48 31 36 [...=.LNC847AEH16] + # 0070: 33 36 30 38 32 34 35 37 59 53 4b 4a 01 00 00 00 [36082457YSKJ....] + # 0080: ec ff ff ff 00 00 00 00 0e 00 00 00 01 00 00 00 [................] + # 0090: 0a 00 00 00 e5 07 00 00 0c 00 00 00 1c 00 00 00 [................] + ($hr,$min,$sec,$yr,$mon,$day,$stat,$latRef,$lonRef) = + unpack('x48V6a1a1a1x1', $$dataPt); + # ignore invalid fixes + return 0 unless $stat eq 'A' and ($latRef eq 'N' or $latRef eq 'S') and + ($lonRef eq 'E' or $lonRef eq 'W'); + + $et->WarnOnce('GPSLatitude/Longitude encryption is not yet known, so these will be wrong'); + # (see https://exiftool.org/forum/index.php?topic=11320.0) + + SetByteOrder('II'); + + $spd = GetFloat($dataPt, 0x60); + $trk = GetFloat($dataPt, 0x64) + 180; # (why is this off by 180?) + $lat = GetDouble($dataPt, 0x50); # latitude is here, but encrypted somehow + $lon = GetDouble($dataPt, 0x58); # longitude is here, but encrypted somehow + $ddd = 1; # don't convert until we know what the format is + + SetByteOrder('MM'); + #my $serialNum = substr($$dataPt, 0x68, 20); + + } elsif ($$dataPt =~ /^.{12}\xac\0\0\0.{44}(.{72})/s) { + + # EACHPAI dash cam + # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 ac 00 00 00 [....freeGPS ....] + # 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0030: 00 00 00 00 00 00 00 00 00 00 00 00 34 57 60 62 [............4W`b] + # 0040: 5d 53 3c 41 47 45 45 42 42 3e 40 40 40 3c 51 3c []S<AGEEBB>@@@<Q<] + # 0050: 44 42 44 40 3e 48 46 43 45 3c 5e 3c 40 48 43 41 [DBD@>HFCE<^<@HCA] + # 0060: 42 3e 46 42 47 48 3c 67 3c 40 3e 40 42 3c 43 3e [B>FBGH<g<@>@B<C>] + # 0070: 43 41 3c 40 42 40 46 42 40 3c 3c 3c 51 3a 47 46 [CA<@B@FB@<<<Q:GF] + # 0080: 00 2a 36 35 00 00 00 00 00 00 00 00 00 00 00 00 [.*65............] + + $et->WarnOnce("Can't yet decrypt EACHPAI timed GPS", 1); + # (see https://exiftool.org/forum/index.php?topic=5095.msg61266#msg61266) + return 1; + + my $time = pack 'C*', map { $_ ^= 0 } unpack 'C*', $1; + # bytes 7-12 are the timestamp in ASCII HHMMSS after xor-ing with 0x70 + substr($time,7,6) = pack 'C*', map { $_ ^= 0x70 } unpack 'C*', substr($time,7,6); + # (other values are currently unknown) + + } elsif ($$dataPt =~ /^.{64}A([NS])([EW])\0/s) { + + # Vantrue S1 dashcam + # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 00 00 00 [....freeGPS x...] + # 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0030: 68 6f 72 73 6f 6e 74 65 63 68 00 00 00 00 00 00 [horsontech......] + # 0040: 41 4e 45 00 15 00 00 00 07 00 00 00 02 00 00 00 [ANE.............] + # 0050: 03 00 00 00 35 00 00 00 05 00 00 00 4f 74 4c 44 [....5.......OtLD] + # 0060: e2 77 a0 45 89 c1 98 42 71 bd ac 42 02 ab 0d 43 [.w.E...Bq..B...C] + # 0070: 05 00 00 00 7f 00 00 00 07 01 00 00 00 00 00 00 [................] + ($latRef, $lonRef) = ($1, $2); + ($yr,$mon,$day,$hr,$min,$sec,@acc) = unpack('x68V6x20V3', $$dataPt); + return 0 unless $mon>=1 and $mon<=12 and $day>=1 and $day<=31; + $yr += 2000 if $yr < 2000; + # (not sure about acc scaling) + map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 1000 } @acc; + SetByteOrder('II'); + $lon = GetFloat($dataPt, 0x5c); + $lat = GetFloat($dataPt, 0x60); + $spd = GetFloat($dataPt, 0x64) * $knotsToKph; + $trk = GetFloat($dataPt, 0x68); + $alt = GetFloat($dataPt, 0x6c); + SetByteOrder('MM'); + + } else { + + # decode binary GPS format (Viofo A119S, ref 2) + # header looks like this in my sample: + # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 4c 00 00 00 [....freeGPS L...] + # 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0030: 10 00 00 00 2d 00 00 00 14 00 00 00 11 00 00 00 [....-...........] + # 0040: 0c 00 00 00 1f 00 00 00 41 4e 45 00 5d 9a a9 45 [........ANE.]..E] + # 0050: ab 1e e5 44 ec 51 f0 40 b8 5e a5 43 00 00 00 00 [...D.Q.@.^.C....] + # (records are same structure as Type 3 Novatek GPS in ProcessFreeGPS2() below) + ($hr,$min,$sec,$yr,$mon,$day,$stat,$latRef,$lonRef,$lat,$lon,$spd,$trk) = + unpack('x48V6a1a1a1x1V4', $$dataPt); + # ignore invalid fixes + return 0 unless $stat eq 'A' and ($latRef eq 'N' or $latRef eq 'S') and + ($lonRef eq 'E' or $lonRef eq 'W'); + ($lat,$lon,$spd,$trk) = unpack 'f*', pack 'L*', $lat, $lon, $spd, $trk; + # lat/lon also stored as doubles by Transcend Driver Pro 230 (ref PH) + SetByteOrder('II'); + my ($lat2, $lon2, $alt2) = ( + GetDouble($dataPt, 0x70), + GetDouble($dataPt, 0x80), + # GetDouble($dataPt, 0x98), # (don't know what this is) + GetDouble($dataPt,0xa0), + # GetDouble($dataPt,0xa8)) # (don't know what this is) + ); + if (abs($lat2-$lat) < 0.001 and abs($lon2-$lon) < 0.001) { + $lat = $lat2; + $lon = $lon2; + $alt = $alt2; + } + SetByteOrder('MM'); + $yr += 2000 if $yr < 2000; + $spd *= $knotsToKph; # convert speed to km/h + # ($trk is not confirmed; may be GPSImageDirection, ref PH) + } +# +# save tag values extracted by above code +# + FoundSomething($et, $tagTbl, $$dirInfo{SampleTime}, $$dirInfo{SampleDuration}); + # lat/long are in DDDMM.MMMM format + ConvertLatLon($lat, $lon) unless $ddd; + $sec = '0' . $sec unless $sec =~ /^\d{2}/; # pad integer part of seconds to 2 digits + if (defined $yr) { + my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%sZ',$yr,$mon,$day,$hr,$min,$sec); + $et->HandleTag($tagTbl, GPSDateTime => $time); + } elsif (defined $hr) { + my $time = sprintf('%.2d:%.2d:%sZ',$hr,$min,$sec); + $et->HandleTag($tagTbl, GPSTimeStamp => $time); + } + $et->HandleTag($tagTbl, GPSLatitude => $lat * ($latRef eq 'S' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSLongitude => $lon * ($lonRef eq 'W' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSAltitude => $alt) if defined $alt; + $et->HandleTag($tagTbl, GPSSpeed => $spd) if defined $spd; + $et->HandleTag($tagTbl, GPSTrack => $trk) if defined $trk; + while (@xtra) { + my $tag = shift @xtra; + $et->HandleTag($tagTbl, $tag => shift @xtra); + } + $et->HandleTag($tagTbl, Accelerometer => \@acc) if @acc; + return 1; +} + +#------------------------------------------------------------------------------ +# Process "freeGPS " data blocks _not_ referenced by a 'gps ' atom +# Inputs: 0) ExifTool ref, 1) dirInfo ref {DataPt,DataPos,DirLen}, 2) tagTable ref +# Returns: 1 on success +# Notes: +# - also see ProcessFreeGPS() above +sub ProcessFreeGPS2($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dirLen = $$dirInfo{DirLen}; + my ($yr, $mon, $day, $hr, $min, $sec, $pos, @acc); + my ($lat, $latRef, $lon, $lonRef, $spd, $trk, $alt, $ddd, $unk); + + return 0 if $dirLen < 82; # minimum size of block with a single GPS record + + if (substr($$dataPt,0x45,3) eq 'ATC') { + + # header looks like this: (sample 1) + # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 38 06 00 00 [....freeGPS 8...] + # 0010: 49 51 53 32 30 31 33 30 33 30 36 42 00 00 00 00 [IQS20130306B....] + # 0020: 4d 61 79 20 31 35 20 32 30 31 35 2c 20 31 39 3a [May 15 2015, 19:] + # (sample 2) + # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 4c 06 00 00 [....freeGPS L...] + # 0010: 32 30 31 33 30 33 31 38 2e 30 31 00 00 00 00 00 [20130318.01.....] + # 0020: 4d 61 72 20 31 38 20 32 30 31 33 2c 20 31 34 3a [Mar 18 2013, 14:] + + my ($recPos, $lastRecPos, $foundNew); + my $verbose = $et->Options('Verbose'); + my $dataPos = $$dirInfo{DataPos}; + my $then = $$et{FreeGPS2}{Then}; + $then or $then = $$et{FreeGPS2}{Then} = [ (0) x 6 ]; + # Loop through records in the ATC-type GPS block until we find the most recent. + # If we have already found one, then we only need to check the first record + # (in case the buffer wrapped around), and the record after the position of + # the last record we found, because the others will be old. Odd, but this + # is the way it is done... I have only seen one new 52-byte record in the + # entire 32 kB block, but the entire device ring buffer (containing 30 + # entries in my samples) is stored every time. The code below allows for + # the possibility of missing blocks and multiple new records in a single + # block, but I have never seen this. Note that there may be some earlier + # GPS records at the end of the first block that we will miss decoding, but + # these should (I believe) be before the start of the video +ATCRec: for ($recPos = 0x30; $recPos + 52 < $dirLen; $recPos += 52) { + + my $a = substr($$dataPt, $recPos, 52); # isolate a single record + # decrypt record + my @a = unpack('C*', $a); + my ($key1, $key2) = @a[0x14, 0x1c]; + $a[$_] ^= $key1 foreach 0x00..0x14, 0x18..0x1b; + $a[$_] ^= $key2 foreach 0x1c, 0x20..0x32; + my $b = pack 'C*', @a; + # unpack and validate date/time + my @now = unpack 'x13C3x28vC2', $b; # (H-1,M,S,Y,m,d) + $now[0] = ($now[0] + 1) & 0xff; # increment hour + my $i; + for ($i=0; $i<@dateMax; ++$i) { + next if $now[$i] <= $dateMax[$i]; + $et->WarnOnce('Invalid GPS date/time'); + next ATCRec; # ignore this record + } + # look for next ATC record in temporal sequence + foreach $i (3..5, 0..2) { + if ($now[$i] < $$then[$i]) { + last ATCRec if $foundNew; + last; + } + next if $now[$i] == $$then[$i]; + # we found a more recent record -- extract it and remember its location + if ($verbose) { + $et->VPrint(2, " + [encrypted GPS record]\n"); + $et->VerboseDump(\$a, DataPos => $dataPos + $recPos); + $et->VPrint(2, " + [decrypted GPS record]\n"); + $et->VerboseDump(\$b); + #my @v = unpack 'H8VVC4V!CA3V!CA3VvvV!vCCCCH4', $b; + #$et->VPrint(2, " + [unpacked: @v]\n"); + # values unpacked above (ref PH): + # 0) 0x00 4 bytes - byte 0=1, 1=counts to 255, 2=record index, 3=0 (ref 3) + # 1) 0x04 4 bytes - int32u: bits 0-4=day, 5-8=mon, 9-19=year (ref 3) + # 2) 0x08 4 bytes - int32u: bits 0-5=sec, 6-11=min, 12-16=hour (ref 3) + # 3) 0x0c 1 byte - seen values of 0,1,2 - GPS status maybe? + # 4) 0x0d 1 byte - hour minus 1 + # 5) 0x0e 1 byte - minute + # 6) 0x0f 1 byte - second + # 7) 0x10 4 bytes - int32s latitude * 1e7 + # 8) 0x14 1 byte - always 0 (used for decryption) + # 9) 0x15 3 bytes - always "ATC" + # 10) 0x18 4 bytes - int32s longitude * 1e7 + # 11) 0x1c 1 byte - always 0 (used for decryption) + # 12) 0x1d 3 bytes - always "001" + # 13) 0x20 4 bytes - int32s speed * 100 (m/s) + # 14) 0x24 2 bytes - int16u heading * 100 (-180 to 180 deg) + # 15) 0x26 2 bytes - always zero + # 16) 0x28 4 bytes - int32s altitude * 1000 (ref 3) + # 17) 0x2c 2 bytes - int16u year + # 18) 0x2e 1 byte - month + # 19) 0x2f 1 byte - day + # 20) 0x30 1 byte - unknown + # 21) 0x31 1 byte - always zero + # 22) 0x32 2 bytes - checksum ? + } + @$then = @now; + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + $trk = Get16s(\$b, 0x24) / 100; + $trk += 360 if $trk < 0; + my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ', @now[3..5, 0..2]); + $et->HandleTag($tagTbl, GPSDateTime => $time); + $et->HandleTag($tagTbl, GPSLatitude => Get32s(\$b, 0x10) / 1e7); + $et->HandleTag($tagTbl, GPSLongitude => Get32s(\$b, 0x18) / 1e7); + $et->HandleTag($tagTbl, GPSSpeed => Get32s(\$b, 0x20) / 100 * $mpsToKph); + $et->HandleTag($tagTbl, GPSTrack => $trk); + $et->HandleTag($tagTbl, GPSAltitude => Get32s(\$b, 0x28) / 1000); + $lastRecPos = $recPos; + $foundNew = 1; + # don't skip to location of previous recent record in ring buffer + # since we found a more recent record here + delete $$et{FreeGPS2}{RecentRecPos}; + last; + } + # skip older records + my $recentRecPos = $$et{FreeGPS2}{RecentRecPos}; + $recPos = $recentRecPos if $recentRecPos and $recPos < $recentRecPos; + } + # save position of most recent record (needed when parsing the next freeGPS block) + $$et{FreeGPS2}{RecentRecPos} = $lastRecPos; + return 1; + + } elsif ($$dataPt =~ /^.{60}A\0.{10}([NS])\0.{14}([EW])\0/s) { + + # header looks like this in my sample: + # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 08 01 00 00 [....freeGPS ....] + # 0010: 32 30 31 33 30 38 31 35 2e 30 31 00 00 00 00 00 [20130815.01.....] + # 0020: 4a 75 6e 20 31 30 20 32 30 31 37 2c 20 31 34 3a [Jun 10 2017, 14:] + + # Type 2 (ref PH): + # 0x30 - int32u hour + # 0x34 - int32u minute + # 0x38 - int32u second + # 0x3c - int32u GPS status ('A' or 'V') + # 0x40 - double latitude (DDMM.MMMMMM) + # 0x48 - int32u latitude ref ('N' or 'S') + # 0x50 - double longitude (DDMM.MMMMMM) + # 0x58 - int32u longitude ref ('E' or 'W') + # 0x60 - double speed (knots) + # 0x68 - double heading (deg) + # 0x70 - int32u year - 2000 + # 0x74 - int32u month + # 0x78 - int32u day + # 0x7c - int32s[3] accelerometer * 1000 + ($latRef, $lonRef) = ($1, $2); + ($hr,$min,$sec,$yr,$mon,$day,@acc) = unpack('x48V3x52V6', $$dataPt); + map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 1000 } @acc; + $lat = GetDouble($dataPt, 0x40); + $lon = GetDouble($dataPt, 0x50); + $spd = GetDouble($dataPt, 0x60) * $knotsToKph; + $trk = GetDouble($dataPt, 0x68); + + } elsif ($$dataPt =~ /^.{72}A([NS])([EW])/s) { + + # Type 3 (Novatek GPS, ref 2): (in case it wasn't decoded via 'gps ' atom) + # 0x30 - int32u hour + # 0x34 - int32u minute + # 0x38 - int32u second + # 0x3c - int32u year - 2000 + # 0x40 - int32u month + # 0x44 - int32u day + # 0x48 - int8u GPS status ('A' or 'V') + # 0x49 - int8u latitude ref ('N' or 'S') + # 0x4a - int8u longitude ref ('E' or 'W') + # 0x4b - 0 + # 0x4c - float latitude (DDMM.MMMMMM) + # 0x50 - float longitude (DDMM.MMMMMM) + # 0x54 - float speed (knots) + # 0x58 - float heading (deg) + # Type 3b, same as above for 0x30-0x4a (ref PH) + # 0x4c - int32s latitude (decimal degrees * 1e7) + # 0x50 - int32s longitude (decimal degrees * 1e7) + # 0x54 - int32s speed (m/s * 100) + # 0x58 - float altitude (m * 1000, NC) + ($latRef, $lonRef) = ($1, $2); + ($hr,$min,$sec,$yr,$mon,$day) = unpack('x48V6', $$dataPt); + if (substr($$dataPt, 16, 3) eq 'IQS') { + # Type 3b (ref PH) + # header looks like this in my sample: + # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 4c 00 00 00 [....freeGPS L...] + # 0010: 49 51 53 5f 41 37 5f 32 30 31 35 30 34 31 37 00 [IQS_A7_20150417.] + # 0020: 4d 61 72 20 32 39 20 32 30 31 37 2c 20 31 36 3a [Mar 29 2017, 16:] + $ddd = 1; + $lat = abs Get32s($dataPt, 0x4c) / 1e7; + $lon = abs Get32s($dataPt, 0x50) / 1e7; + $spd = Get32s($dataPt, 0x54) / 100 * $mpsToKph; + $alt = GetFloat($dataPt, 0x58) / 1000; # (NC) + } else { + # Type 3 (ref 2) + # (no sample with this format) + $lat = GetFloat($dataPt, 0x4c); + $lon = GetFloat($dataPt, 0x50); + $spd = GetFloat($dataPt, 0x54) * $knotsToKph; + $trk = GetFloat($dataPt, 0x58); + } + + } elsif ($$dataPt =~ /^.{60}A\0.{6}([NS])\0.{6}([EW])\0/s and $dirLen >= 112) { + + # header looks like this in my sample (unknown dashcam, "Anticlock 2 2020_1125_1455_007.MOV"): + # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 68 00 00 00 [....freeGPS h...] + # 0010: 32 30 31 33 30 33 32 35 41 00 00 00 00 00 00 00 [20130325A.......] + # 0020: 41 70 72 20 20 36 20 32 30 31 36 2c 20 31 36 3a [Apr 6 2016, 16:] + # 0030: 0e 00 00 00 38 00 00 00 22 00 00 00 41 00 00 00 [....8..."...A...] + # 0040: 8a 63 24 45 53 00 00 00 9f e6 42 45 45 00 00 00 [.c$ES.....BEE...] + # 0050: 59 c0 04 3f 52 b8 42 41 14 00 00 00 0b 00 00 00 [Y..?R.BA........] + # 0060: 19 00 00 00 06 00 00 00 05 00 00 00 f6 ff ff ff [................] + # 0070: 03 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 [................] + ($latRef, $lonRef) = ($1, $2); + ($hr,$min,$sec,$yr,$mon,$day,@acc) = unpack('x48V3x28V6',$$dataPt); + map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 1000 } @acc; # (NC) + $lat = GetFloat($dataPt, 0x40); + $lon = GetFloat($dataPt, 0x48); + $spd = GetFloat($dataPt, 0x50); + $trk = GetFloat($dataPt, 0x54); + + } elsif ($$dataPt =~ /^.{16}A([NS])([EW])\0/s) { + + # INNOVV MP4 video (same format as INNOVV TS) + while ($$dataPt =~ /(A[NS][EW]\0.{28})/g) { + my $dat = $1; + $lat = abs(GetFloat(\$dat, 4)); # (abs just to be safe) + $lon = abs(GetFloat(\$dat, 8)); # (abs just to be safe) + $spd = GetFloat(\$dat, 12) * $knotsToKph; + $trk = GetFloat(\$dat, 16); + @acc = unpack('x20V3', $dat); + map { $_ = $_ - 4294967296 if $_ >= 0x80000000 } @acc; + ConvertLatLon($lat, $lon); + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + $et->HandleTag($tagTbl, GPSLatitude => $lat * (substr($dat,1,1) eq 'S' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSLongitude => $lon * (substr($dat,2,1) eq 'W' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSSpeed => $spd); + $et->HandleTag($tagTbl, GPSTrack => $trk); + $et->HandleTag($tagTbl, Accelerometer => "@acc"); + } + return 1; + + } else { + + # (look for binary GPS as stored by NextBase 512G, ref PH) + # header looks like this in my sample: + # 0000: 00 00 80 00 66 72 65 65 47 50 53 20 78 01 00 00 [....freeGPS x...] + # 0010: 78 2e 78 78 00 00 00 00 00 00 00 00 00 00 00 00 [x.xx............] + # 0020: 30 30 30 30 30 00 00 00 00 00 00 00 00 00 00 00 [00000...........] + + # followed by a number of 32-byte records in this format (big endian!): + # 0x30 - int16u unknown (seen: 0x24 0x53 = "$S") + # 0x32 - int16u speed (m/s * 100) + # 0x34 - int16s heading (deg * 100) (or GPSImgDirection?) + # 0x36 - int16u year + # 0x38 - int8u month + # 0x39 - int8u day + # 0x3a - int8u hour + # 0x3b - int8u min + # 0x3c - int16u sec * 10 + # 0x3e - int8u unknown (seen: 2) + # 0x3f - int32s latitude (decimal degrees * 1e7) + # 0x43 - int32s longitude (decimal degrees * 1e7) + # 0x47 - int8u unknown (seen: 16) + # 0x48-0x4f - all zero + for ($pos=0x32; ; ) { + ($spd,$trk,$yr,$mon,$day,$hr,$min,$sec,$unk,$lat,$lon) = unpack "x${pos}nnnCCCCnCNN", $$dataPt; + # validate record using date/time + last if $yr < 2000 or $yr > 2200 or + $mon < 1 or $mon > 12 or + $day < 1 or $day > 31 or + $hr > 59 or $min > 59 or $sec > 600; + # change lat/lon to signed integer and divide by 1e7 + map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 1e7 } $lat, $lon; + $trk -= 0x10000 if $trk >= 0x8000; # make it signed + $trk /= 100; + $trk += 360 if $trk < 0; + my $time = sprintf("%.4d:%.2d:%.2d %.2d:%.2d:%04.1fZ", $yr, $mon, $day, $hr, $min, $sec/10); + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + $et->HandleTag($tagTbl, GPSDateTime => $time); + $et->HandleTag($tagTbl, GPSLatitude => $lat); + $et->HandleTag($tagTbl, GPSLongitude => $lon); + $et->HandleTag($tagTbl, GPSSpeed => $spd / 100 * $mpsToKph); + $et->HandleTag($tagTbl, GPSTrack => $trk); + last if $pos += 0x20 > length($$dataPt) - 0x1e; + } + return $$et{DOC_NUM} ? 1 : 0; # return 0 if nothing extracted + } +# +# save tag values extracted by above code +# + return 0 if $mon < 1 or $mon > 12; # quick sanity check + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + $yr += 2000 if $yr < 2000; + my $time = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ', $yr, $mon, $day, $hr, $min, $sec); + # convert from DDMM.MMMMMM to DD.DDDDDD format if necessary + ConvertLatLon($lat, $lon) unless $ddd; + $et->HandleTag($tagTbl, GPSDateTime => $time); + $et->HandleTag($tagTbl, GPSLatitude => $lat * ($latRef eq 'S' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSLongitude => $lon * ($lonRef eq 'W' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSSpeed => $spd) if defined $spd; # (now in km/h) + $et->HandleTag($tagTbl, GPSTrack => $trk) if defined $trk; + if (defined $alt) { + $et->HandleTag($tagTbl, GPSAltitude => $alt); + } + $et->HandleTag($tagTbl, Accelerometer => "@acc") if @acc; + return 1; +} + + +#------------------------------------------------------------------------------ +# Extract embedded information referenced from a track +# Inputs: 0) ExifTool ref, 1) tag name, 2) data ref +sub ParseTag($$$) +{ + local $_; + my ($et, $tag, $dataPt) = @_; + my $dataLen = length $$dataPt; + + if ($tag eq 'stsz' or $tag eq 'stz2' and $dataLen > 12) { + # read the sample sizes + my ($sz, $num) = unpack('x4N2', $$dataPt); + my $size = $$et{ee}{size} = [ ]; + if ($tag eq 'stsz') { + if ($sz == 0) { + @$size = ReadValue($dataPt, 12, 'int32u', $num, $dataLen-12); + } else { + @$size = ($sz) x $num; + } + } else { + $sz &= 0xff; + if ($sz == 4) { + my @tmp = ReadValue($dataPt, 12, 'int8u', int(($num+1)/2), $dataLen-12); + foreach (@tmp) { + push @$size, $_ >> 4; + push @$size, $_ & 0xff; + } + } elsif ($sz == 8 || $sz == 16) { + @$size = ReadValue($dataPt, 12, "int${sz}u", $num, $dataLen-12); + } + } + } elsif ($tag eq 'stco' or $tag eq 'co64' and $dataLen > 8) { + # read the chunk offsets + my $num = unpack('x4N', $$dataPt); + my $stco = $$et{ee}{stco} = [ ]; + @$stco = ReadValue($dataPt, 8, $tag eq 'stco' ? 'int32u' : 'int64u', $num, $dataLen-8); + } elsif ($tag eq 'stsc' and $dataLen > 8) { + # read the sample-to-chunk box + my $num = unpack('x4N', $$dataPt); + if ($dataLen >= 8 + $num * 12) { + my ($i, @stsc); + for ($i=0; $i<$num; ++$i) { + # list of (first-chunk, samples-per-chunk, sample-description-index) + push @stsc, [ unpack('x'.(8+$i*12).'N3', $$dataPt) ]; + } + $$et{ee}{stsc} = \@stsc; + } + } elsif ($tag eq 'stts' and $dataLen > 8) { + # read the time-to-sample box + my $num = unpack('x4N', $$dataPt); + if ($dataLen >= 8 + $num * 8) { + $$et{ee}{stts} = [ unpack('x8N'.($num*2), $$dataPt) ]; + } + } elsif ($tag eq 'avcC') { + # read the AVC compressor configuration + $$et{ee}{avcC} = $$dataPt if $dataLen >= 7; # (minimum length is 7) + } elsif ($tag eq 'JPEG') { + $$et{ee}{JPEG} = $$dataPt; + } elsif ($tag eq 'gps ' and $dataLen > 8) { + # decode Novatek 'gps ' box (ref 2) + my $num = Get32u($dataPt, 4); + $num = int(($dataLen - 8) / 8) if $num * 8 + 8 > $dataLen; + my $start = $$et{ee}{start} = [ ]; + my $size = $$et{ee}{size} = [ ]; + my $i; + for ($i=0; $i<$num; ++$i) { + push @$start, Get32u($dataPt, 8 + $i * 8); + push @$size, Get32u($dataPt, 12 + $i * 8); + } + $$et{HandlerType} = $tag; # fake handler type + ProcessSamples($et); # we have all we need to process sample data now + } elsif ($tag eq 'GPS ') { + my $pos = 0; + my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); + SetByteOrder('II'); + while ($pos + 36 < $dataLen) { + my $dat = substr($$dataPt, $pos, 36); + last if $dat eq "\x0" x 36; + my @a = unpack 'VVVVaVaV', $dat; + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + # 0=1, 1=1, 2=secs, 3=? + SetGPSDateTime($et, $tagTbl, $a[2]); + my $lat = $a[5] / 1e3; + my $lon = $a[7] / 1e3; + ConvertLatLon($lat, $lon); + $lat = -abs($lat) if $a[4] eq 'S'; + $lon = -abs($lon) if $a[6] eq 'W'; + $et->HandleTag($tagTbl, GPSLatitude => $lat); + $et->HandleTag($tagTbl, GPSLongitude => $lon); + $et->HandleTag($tagTbl, GPSSpeed => $a[3] / 1e3); + $pos += 36; + } + SetByteOrder('MM'); + delete $$et{DOC_NUM}; + } +} + +#------------------------------------------------------------------------------ +# Process Yuneec 'tx3g' sbtl metadata (ref PH) +# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub Process_tx3g($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + my $dataPt = $$dirInfo{DataPt}; + return 0 if length $$dataPt < 2; + pos($$dataPt) = 2; # skip 2-byte length word + $et->VerboseDir('tx3g', undef, length($$dataPt)-2); + $et->HandleTag($tagTablePtr, 'Text', substr($$dataPt, 2)); + if ($$dataPt =~ /^..\w{3} (\d{4})-(\d{2})-(\d{2}) (\d{2}:\d{2}:\d{2}) ?([-+])(\d{2}):?(\d{2})$/s) { + $et->HandleTag($tagTablePtr, 'DateTime', "$1:$2:$3 $4$5$6:$7"); + } else { + $et->HandleTag($tagTablePtr, $1, $2) while $$dataPt =~ /(\w+):([^:]*[^:\s])(\s|$)/sg; + } + return 1; +} + +#------------------------------------------------------------------------------ +# Process GM 'marl' ctbx metadata (ref PH) +# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub Process_marl($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + my $dataPt = $$dirInfo{DataPt}; + return 0 if length $$dataPt < 2; + + # 8-byte records: + # byte 0 seems to be tag ID (0=timestamp in sec * 1e7) + # bytes 1-3 seem to be 24-bit signed integer (unknown meaning) + # bytes 4-7 are an int32u value, usually a multiple of 10000 + + $et->WarnOnce("Can't yet decode timed GM data", 1); + # (see https://exiftool.org/forum/index.php?topic=11335.msg61393#msg61393) + return 1; +} + +#------------------------------------------------------------------------------ +# Process QuickTime 'mebx' timed metadata +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +# - uses tag ID keys stored in the ExifTool ee data member by a previous call to SaveMetaKeys +sub Process_mebx($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $ee = $$et{ee} or return 0; + return 0 unless $$ee{'keys'}; + my $dataPt = $$dirInfo{DataPt}; + + # parse using information from 'keys' table (eg. Apple iPhone7+ hevc 'Core Media Data Handler') + $et->VerboseDir('mebx', undef, length $$dataPt); + my ($pos, $len); + for ($pos=0; $pos+8<length($$dataPt); $pos+=$len) { + $len = Get32u($dataPt, $pos); + last if $len < 8 or $pos + $len > length $$dataPt; + my $id = substr($$dataPt, $pos+4, 4); + my $info = $$ee{'keys'}{$id}; + if ($info) { + my $tag = $$info{TagID}; + unless ($$tagTbl{$tag}) { + next unless $tag =~ /^[-\w.]+$/; + # create info for tags with reasonable id's + my $name = $tag; + $name =~ s/[-.](.)/\U$1/g; + AddTagToTable($tagTbl, $tag, { Name => ucfirst($name) }); + } + my $val = ReadValue($dataPt, $pos+8, $$info{Format}, undef, $len-8); + $et->HandleTag($tagTbl, $tag, $val, + DataPt => $dataPt, + Base => $$dirInfo{Base}, + Start => $pos + 8, + Size => $len - 8, + ); + } else { + $et->WarnOnce('No key information for mebx ID ' . PrintableTagID($id,1)); + } + } + return 1; +} + +#------------------------------------------------------------------------------ +# Process QuickTime '3gf' timed metadata (ref PH, Pittasoft Blackvue dashcam) +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub Process_3gf($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dirLen = $$dirInfo{DirLen}; + my $recLen = 10; # 10-byte record length + $et->VerboseDir('3gf', undef, $dirLen); + if ($dirLen > $recLen and not $et->Options('ExtractEmbedded')) { + $dirLen = $recLen; + EEWarn($et); + } + my $pos; + for ($pos=0; $pos+$recLen<=$dirLen; $pos+=$recLen) { + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + my $tc = Get32u($dataPt, $pos); + last if $tc == 0xffffffff; + my ($x, $y, $z) = (Get16s($dataPt, $pos+4)/10, Get16s($dataPt, $pos+6)/10, Get16s($dataPt, $pos+8)/10); + $et->HandleTag($tagTbl, TimeCode => $tc / 1000); + $et->HandleTag($tagTbl, Accelerometer => "$x $y $z"); + } + delete $$et{DOC_NUM}; + return 1; +} + +#------------------------------------------------------------------------------ +# Process DuDuBell M1 dashcam / VSYS M6L 'gps0' atom (ref PH) +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub Process_gps0($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dirLen = $$dirInfo{DirLen}; + my $recLen = 32; # 32-byte record length + $et->VerboseDir('gps0', undef, $dirLen); + SetByteOrder('II'); + if ($dirLen > $recLen and not $et->Options('ExtractEmbedded')) { + $dirLen = $recLen; + EEWarn($et); + } + my $pos; + for ($pos=0; $pos+$recLen<=$dirLen; $pos+=$recLen) { + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + # lat/long are in DDDMM.MMMM format + my $lat = GetDouble($dataPt, $pos); + my $lon = GetDouble($dataPt, $pos+8); + next if abs($lat) > 9000 or abs($lon) > 18000; + ConvertLatLon($lat, $lon); + my @a = unpack('C*', substr($$dataPt, $pos+22, 6)); # unpack date/time + $a[0] += 2000; + $et->HandleTag($tagTbl, GPSDateTime => sprintf("%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ", @a)); + $et->HandleTag($tagTbl, GPSLatitude => $lat); + $et->HandleTag($tagTbl, GPSLongitude => $lon); + $et->HandleTag($tagTbl, GPSSpeed => Get16u($dataPt, $pos+0x14)); + $et->HandleTag($tagTbl, GPSTrack => Get8u($dataPt, $pos+0x1c) * 2); # (NC) + $et->HandleTag($tagTbl, GPSAltitude => Get32s($dataPt, $pos + 0x10)); + # yet to be decoded: + # 0x1d - int8u[3] seen: "1 1 0" + } + delete $$et{DOC_NUM}; + SetByteOrder('MM'); + return 1; +} + +#------------------------------------------------------------------------------ +# Process DuDuBell M1 dashcam / VSYS M6L 'gsen' atom (ref PH) +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub Process_gsen($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dirLen = $$dirInfo{DirLen}; + my $recLen = 3; # 3-byte record length + $et->VerboseDir('gsen', undef, $dirLen); + if ($dirLen > $recLen and not $et->Options('ExtractEmbedded')) { + $dirLen = $recLen; + EEWarn($et); + } + my $pos; + for ($pos=0; $pos+$recLen<=$dirLen; $pos+=$recLen) { + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + my @acc = map { $_ /= 16 } unpack "x${pos}c3", $$dataPt; + $et->HandleTag($tagTbl, Accelerometer => "@acc"); + # (there are no associated timestamps, but these are sampled at 5 Hz in my test video) + } + delete $$et{DOC_NUM}; + return 1; +} + +#------------------------------------------------------------------------------ +# Process RIFF-format trailer written by Auto-Vox dashcam (ref PH) +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +# Note: This trailer is basically RIFF chunks added to a QuickTime-format file (augh!), +# but there are differences in the record formats so we can't just call +# ProcessRIFF to process the gps0 and gsen atoms using the routines above +sub ProcessRIFFTrailer($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $raf = $$dirInfo{RAF}; + my $verbose = $et->Options('Verbose'); + my ($buff, $pos); + SetByteOrder('II'); + for (;;) { + last unless $raf->Read($buff, 8) == 8; + my ($tag, $len) = unpack('a4V', $buff); + last if $tag eq "\0\0\0\0"; + unless ($tag =~ /^[\w ]{4}/ and $len < 0x2000000) { + $et->Warn('Bad RIFF trailer'); + last; + } + $raf->Read($buff, $len) == $len or $et->Warn("Truncated $tag record in RIFF trailer"), last; + if ($verbose) { + $et->VPrint(0, " - RIFF trailer '${tag}' ($len bytes)\n"); + $et->VerboseDump(\$buff, Addr => $raf->Tell() - $len) if $verbose > 2; + $$et{INDENT} .= '| '; + $et->VerboseDir($tag, undef, $len) if $tag =~ /^(gps0|gsen)$/; + } + if ($tag eq 'gps0') { + # (similar to record decoded in Process_gps0, but with some differences) + # 0000: 41 49 54 47 74 46 94 f6 c6 c5 b4 40 34 a2 b4 37 [AITGtF.....@4..7] + # 0010: f8 7b 8a 40 ff ff 00 00 38 00 77 0a 1a 0c 12 28 [.{.@....8.w....(] + # 0020: 8d 01 02 40 29 07 00 00 [...@)...] + # 0x00 - undef[4] 'AITG' + # 0x04 - double latitude (always positive) + # 0x0c - double longitude (always positive) + # 0x14 - ? seen hex "ff ff 00 00" (altitude in Process_gps0 record below) + # 0x18 - int16u speed in knots (different than km/hr in Process_gps0) + # 0x1a - int8u[6] yr-1900,mon,day,hr,min,sec (different than -2000 in Process_gps0) + # 0x20 - int8u direction in degrees / 2 + # 0x21 - int8u guessing that this is 1=N, 2=S - PH + # 0x22 - int8u guessing that this is 1=E, 2=W - PH + # 0x23 - ? seen hex "40" + # 0x24 - in32u time since start of video (ms) + my $recLen = 0x28; + for ($pos=0; $pos+$recLen<$len; $pos+=$recLen) { + substr($buff, $pos, 4) eq 'AITG' or $et->Warn('Unrecognized gps0 record'), last; + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + # lat/long are in DDDMM.MMMM format + my $lat = GetDouble(\$buff, $pos+4); + my $lon = GetDouble(\$buff, $pos+12); + $et->Warn('Bad gps0 record') and last if abs($lat) > 9000 or abs($lon) > 18000; + ConvertLatLon($lat, $lon); + $lat = -$lat if Get8u(\$buff, $pos+0x21) == 2; # wild guess + $lon = -$lon if Get8u(\$buff, $pos+0x22) == 2; # wild guess + my @a = unpack('C*', substr($buff, $pos+26, 6)); # unpack date/time + $a[0] += 1900; # (different than Proces_gps0) + $et->HandleTag($tagTbl, SampleTime => Get32u(\$buff, $pos + 0x24) / 1000); + $et->HandleTag($tagTbl, GPSDateTime => sprintf("%.4d:%.2d:%.2d %.2d:%.2d:%.2dZ", @a)); + $et->HandleTag($tagTbl, GPSLatitude => $lat); + $et->HandleTag($tagTbl, GPSLongitude => $lon); + $et->HandleTag($tagTbl, GPSSpeed => Get16u(\$buff, $pos+0x18) * $knotsToKph); + $et->HandleTag($tagTbl, GPSTrack => Get8u(\$buff, $pos+0x20) * 2); + } + } elsif ($tag eq 'gsen') { + # (similar to record decoded in Process_gsen) + # 0000: 41 49 54 53 1a 0d 05 ff c8 00 00 00 [AITS........] + # 0x00 - undef[4] 'AITS' + # 0x04 - int8s[3] accelerometer readings + # 0x07 - ? seen hex "ff" + # 0x08 - in32u time since start of video (ms) + my $recLen = 0x0c; + for ($pos=0; $pos+$recLen<$len; $pos+=$recLen) { + substr($buff, $pos, 4) eq 'AITS' or $et->Warn('Unrecognized gsen record'), last; + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + my @acc = map { $_ /= 24 } unpack('x'.($pos+4).'c3', $buff); + $et->HandleTag($tagTbl, SampleTime => Get32u(\$buff, $pos + 8) / 1000); + # 0=+Up, 1=+Right, 3=+Forward (calibration of 24 counts/g is a wild guess - PH) + $et->HandleTag($tagTbl, Accelerometer => "@acc"); + } + } + # also seen, but not decoded: + # gpsa (8 bytes): hex "01 20 00 00 08 03 02 08 " + # gsea (20 bytes): all zeros + $$et{INDENT} = substr($$et{INDENT}, 0, -2) if $verbose; + } + delete $$et{DOC_NUM}; + SetByteOrder('MM'); + return 1; +} + +#------------------------------------------------------------------------------ +# Process 'gps ' atom containing NMEA from Pittasoft Blackvue dashcam (ref PH) +# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub ProcessNMEA($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + my ($rtnVal, %fix); + # parse only RMC and GGA sentence [with leading timecode] for now + for (;;) { + my ($tc, $type, $tim); + if ($$dataPt =~ /(?:\[(\d+)\])?\$[A-Z]{2}(RMC|GGA),(\d{2}\d{2}\d+(\.\d*)?),/g) { + ($tc, $type, $tim) = ($1, $2, $3); + } + # write out last fix now if complete + # (use the GPS timestamps because they may be different for the same timecode) + if ($fix{tim} and (not $tim or $fix{tim} != $tim)) { + if ($fix{dat} and defined $fix{lat} and defined $fix{lon}) { + my $sampleTime; + $sampleTime = ($fix{tc} - $$et{StartTime}) / 1000 if $fix{tc} and $$et{StartTime}; + FoundSomething($et, $tagTbl, $sampleTime); + $et->HandleTag($tagTbl, GPSDateTime => $fix{dat}); + $et->HandleTag($tagTbl, GPSLatitude => $fix{lat}); + $et->HandleTag($tagTbl, GPSLongitude => $fix{lon}); + $et->HandleTag($tagTbl, GPSSpeed => $fix{spd} * $knotsToKph) if defined $fix{spd}; + $et->HandleTag($tagTbl, GPSTrack => $fix{trk}) if defined $fix{trk}; + $et->HandleTag($tagTbl, GPSAltitude => $fix{alt}) if defined $fix{alt}; + $et->HandleTag($tagTbl, GPSSatellites=> $fix{nsats}+0) if defined $fix{nsats}; + $et->HandleTag($tagTbl, GPSDOP => $fix{hdop}) if defined $fix{hdop}; + } + undef %fix; + } + $fix{tim} = $tim or last; + my $pos = pos($$dataPt); + pos($$dataPt) = $pos - length($tim) - 1; # rewind to re-parse time + # (parsing of NMEA strings copied from Geotag.pm) + if ($type eq 'RMC' and + $$dataPt =~ /\G(\d{2})(\d{2})(\d+(\.\d*)?),A?,(\d*?)(\d{1,2}\.\d+),([NS]),(\d*?)(\d{1,2}\.\d+),([EW]),(\d*\.?\d*),(\d*\.?\d*),(\d{2})(\d{2})(\d+)/g) + { + my $year = $15 + ($15 >= 70 ? 1900 : 2000); + $fix{tc} = $tc; # use timecode of RMC sentence + $fix{dat} = sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%sZ',$year,$14,$13,$1,$2,$3); + $fix{lat} = (($5 || 0) + $6/60) * ($7 eq 'N' ? 1 : -1); + $fix{lon} = (($8 || 0) + $9/60) * ($10 eq 'E' ? 1 : -1); + $fix{spd} = $11 if length $11; + $fix{trk} = $12 if length $12; + } elsif ($type eq 'GGA' and + $$dataPt =~ /\G(\d{2})(\d{2})(\d+(\.\d*)?),(\d*?)(\d{1,2}\.\d+),([NS]),(\d*?)(\d{1,2}\.\d+),([EW]),[1-6]?,(\d+)?,(\.\d+|\d+\.?\d*)?,(-?\d+\.?\d*)?,M?/g) + { + $fix{lat} = (($5 || 0) + $6/60) * ($7 eq 'N' ? 1 : -1); + $fix{lon} = (($8 || 0) + $9/60) * ($10 eq 'E' ? 1 : -1); + @fix{qw(nsats hdop alt)} = ($11,$12,$13); + } else { + pos($$dataPt) = $pos; # continue searching from our last match + } + } + delete $$et{DOC_NUM}; + return $rtnVal; +} + +#------------------------------------------------------------------------------ +# Process 'gps ' or 'udat' atom possibly containing NMEA (ref PH) +# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub ProcessGPSLog($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + my ($rtnVal, @a); + + # try NMEA format first + return 1 if ProcessNMEA($et,$dirInfo,$tagTbl); + + # DENVER ACG-8050WMK2 format looks like this: + # 210318073213[1][N][52200970][E][006362321][+00152][100][00140][C000000]+000+000+000+000+000+000+000+000+000+000+000+000+000+000+000+000+000+000 + # YYMMDDHHMMSS A? NS lat EW lon alt kph dir kCal accel + while ($$dataPt =~ /\b(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\[1\]\[([NS])\]\[(\d{8})\]\[([EW])\]\[(\d{9})\]\[([-+]?\d*)\]\[(\d*)\]\[(\d*)\]\[C?(\d*)\](([-+]\d{3})+)/g) { + my $lat = substr( $8,0,2) + substr( $8,2) / 600000; + my $lon = substr($10,0,3) + substr($10,3) / 600000; + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + $et->HandleTag($tagTbl, GPSDateTime => "20$1:$2:$3 $4:$5:$6Z"); + $et->HandleTag($tagTbl, GPSLatitude => $lat * ($7 eq 'S' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSLongitude => $lon * ($9 eq 'W' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSAltitude => $11 / 10) if length $11; + $et->HandleTag($tagTbl, GPSSpeed => $12 + 0) if length $12; + $et->HandleTag($tagTbl, GPSTrack => $13 + 0) if length $13; + $et->HandleTag($tagTbl, KiloCalories => $14 / 10) if length $14; + $et->HandleTag($tagTbl, Accelerometer=> $15) if length $15; + $rtnVal = 1; + } + delete $$et{DOC_NUM}; + return $rtnVal; +} + +#------------------------------------------------------------------------------ +# Process TomTom Bandit Action Cam TTAD atom (ref PH) +# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +my %ttLen = ( # lengths of known TomTom records + 0 => 12, # angular velocity (NC) + 1 => 4, # ? + 2 => 12, # ? + 3 => 12, # accelerometer (NC) + # (haven't seen a record 4 yet) + 5 => 92, # GPS + 0xff => 4, # timecode +); +sub ProcessTTAD($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dirLen = $$dirInfo{DirLen}; + my $pos = 76; + + return 0 if $dirLen < $pos; + + $et->VerboseDir('TTAD', undef, $dirLen); + SetByteOrder('II'); + + my $eeOpt = $et->Options('ExtractEmbedded'); + my $unknown = $et->Options('Unknown'); + my $found = 0; + my $sampleTime = 0; + my $resync = 1; + my $skipped = 0; + my $warned; + + while ($pos < $dirLen) { + # get next record type + my $type = Get8u($dataPt, $pos++); + # resync if necessary by skipping data until next timecode record + if ($resync and $type != 0xff) { + ++$skipped > 0x100 and $et->Warn('Unrecognized or bad TTAD data', 1), last; + next; + } + unless ($ttLen{$type}) { + # skip unknown records + $et->Warn("Unknown TTAD record type $type",1) unless $warned; + $resync = $warned = 1; + ++$skipped; + next; + } + last if $pos + $ttLen{$type} > $dirLen; + if ($type == 0xff) { # timecode? + my $tm = Get32u($dataPt, $pos); + # validate timecode if skipping unknown data + if ($resync) { + if ($tm < $sampleTime or $tm > $sampleTime + 250) { + ++$skipped; + next; + } + undef $resync; + $skipped = 0; + } + $pos += $ttLen{$type}; + $sampleTime = $tm; + next; + } + unless ($eeOpt) { + # only extract one of each type without -ee option + $found & (1 << $type) and $pos += $ttLen{$type}, next; + $found |= (1 << $type); + } + if ($type == 0 or $type == 3) { + # (these are both just educated guesses - PH) + FoundSomething($et, $tagTbl, $sampleTime / 1000); + my @a = map { Get32s($dataPt,$pos+4*$_) / 1000 } 0..2; + $et->HandleTag($tagTbl, ($type ? 'Accelerometer' : 'AngularVelocity') => "@a"); + } elsif ($type == 5) { + # example records unpacked with 'dVddddVddddv*' + # datetime ? spd ele lat lon ? trk ? ? ? ? ? ? ? ? ? + # 2019:03:05 07:52:58.999Z 3 0.02 242 48.0254203 7.8497567 0 45.69 13.34 17.218 17.218 0 0 0 32760 5 0 + # 2019:03:05 07:52:59.999Z 3 0.14 242 48.0254203 7.8497567 0 45.7 12.96 15.662 15.662 0 0 0 32760 5 0 + # 2019:03:05 07:53:00.999Z 3 0.67 243.78 48.0254584 7.8497907 0 50.93 9.16 10.84 10.84 0 0 0 32760 5 0 + # (I think "5" may be the number of satellites. seen: 5,6,7 - PH) + FoundSomething($et, $tagTbl, $sampleTime / 1000); + my $t = GetDouble($dataPt, $pos); + $et->HandleTag($tagTbl, GPSDateTime => Image::ExifTool::ConvertUnixTime($t,undef,3).'Z'); + $et->HandleTag($tagTbl, GPSLatitude => GetDouble($dataPt, $pos+0x1c)); + $et->HandleTag($tagTbl, GPSLongitude => GetDouble($dataPt, $pos+0x24)); + $et->HandleTag($tagTbl, GPSAltitude => GetDouble($dataPt, $pos+0x14)); + $et->HandleTag($tagTbl, GPSSpeed => GetDouble($dataPt, $pos+0x0c) * $mpsToKph); + $et->HandleTag($tagTbl, GPSTrack => GetDouble($dataPt, $pos+0x30)); + if ($unknown) { + my @a = map { GetDouble($dataPt, $pos+0x38+8*$_) } 0..2; + $et->HandleTag($tagTbl, Unknown03 => "@a"); + } + } elsif ($type < 3) { + # as yet unknown: + # 1 - int32s[1]? (values around 98k) + # 2 - int32s[3] (values like "806 8124 4323" -- probably something * 1000 again) + if ($unknown) { + FoundSomething($et, $tagTbl, $sampleTime / 1000); + my $n = $type == 1 ? 0 : 2; + my @a = map { Get32s($dataPt,$pos+4*$_) } 0..$n; + $et->HandleTag($tagTbl, "Unknown0$type" => "@a"); + } + } else { + $et->WarnOnce("Unknown TTAD record type $type",1); + } + # without -ee, stop after we find types 0,3,5 (ie. bitmask 0x29) + $eeOpt or ($found & 0x29) != 0x29 or EEWarn($et), last; + $pos += $ttLen{$type}; + } + SetByteOrder('MM'); + delete $$et{DOC_NUM}; + return 1; +} + +#------------------------------------------------------------------------------ +# Extract information from Insta360 trailer (INSV and INSP files) (ref PH) +# Inputs: 0) ExifTool ref, 1) Optional dirInfo ref for returning trailer info +# Returns: true on success +sub ProcessInsta360($;$) +{ + local $_; + my ($et, $dirInfo) = @_; + my $raf = $$et{RAF}; + my $offset = $dirInfo ? $$dirInfo{Offset} || 0 : 0; + my $buff; + + return 0 unless $raf->Seek(-78-$offset, 2) and $raf->Read($buff, 78) == 78 and + substr($buff,-32) eq "8db42d694ccc418790edff439fe026bf"; # check magic number + + my $verbose = $et->Options('Verbose'); + my $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); + my $fileEnd = $raf->Tell(); + my $trailerLen = unpack('x38V', $buff); + $trailerLen > $fileEnd and $et->Warn('Bad Insta360 trailer size'), return 0; + if ($dirInfo) { + $$dirInfo{DirLen} = $trailerLen; + $$dirInfo{DataPos} = $fileEnd - $trailerLen; + if ($$dirInfo{OutFile}) { + if ($$et{DEL_GROUP}{Insta360}) { + ++$$et{CHANGED}; + # just copy the trailer when writing + } elsif ($trailerLen > $fileEnd or not $raf->Seek($$dirInfo{DataPos}, 0) or + $raf->Read(${$$dirInfo{OutFile}}, $trailerLen) != $trailerLen) + { + return 0; + } else { + return 1; + } + } + $et->DumpTrailer($dirInfo) if $verbose or $$et{HTML_DUMP}; + } + unless ($et->Options('ExtractEmbedded')) { + # can arrive here when reading Insta360 trailer on JPEG image (INSP file) + $et->WarnOnce('Use ExtractEmbedded option to extract timed metadata from Insta360 trailer',3); + return 1; + } + + my $unknown = $et->Options('Unknown'); + # position relative to end of trailer (avoids using large offsets for files > 2 GB) + my $epos = -78-$offset; + my ($i, $p); + $$et{SET_GROUP0} = 'Trailer'; + $$et{SET_GROUP1} = 'Insta360'; + SetByteOrder('II'); + # loop through all records in the trailer, from last to first + for (;;) { + my ($id, $len) = unpack('vV', $buff); + ($epos -= $len) + $trailerLen < 0 and last; + $raf->Seek($epos, 2) or last; + my $dlen = $insvDataLen{$id}; + if ($verbose) { + $et->VPrint(0, sprintf("Insta360 Record 0x%x (offset 0x%x, %d bytes):\n", $id, $fileEnd + $epos, $len)); + } + # there are 2 types of record 0x300: + # 1. 56 byte records + # 0000: 4a f7 02 00 00 00 00 00 00 00 00 00 00 1e e7 3f [J..............?] + # 0010: 00 00 00 00 00 b2 ef bf 00 00 00 00 00 70 c1 bf [.............p..] + # 0020: 00 00 00 e0 91 5c 8c bf 00 00 00 20 8f ff 87 bf [.....\..... ....] + # 0030: 00 00 00 00 88 7f c9 bf + # 2. 20 byte records + # 0000: c1 d8 d9 0b 00 00 00 00 f5 83 14 80 df 7f fe 7f [................] + # 0010: fe 7f 01 80 + if ($id == 0x300) { + if ($len % 20 and not $len % 56) { + $dlen = 56; + } elsif ($len % 56 and not $len % 20) { + $dlen = 20; + } else { + if ($raf->Read($buff, 20) == 20) { + if (substr($buff, 16, 3) eq "\0\0\0") { + $dlen = 56; + } else { + $dlen = 20; + } + } + $raf->Seek($epos, 2) or last; + } + } + # limit the number of records we read if necessary + if ($dlen and $insvLimit{$id} and $len > $insvLimit{$id}[1] * $dlen and + $et->Warn("Insta360 $insvLimit{$id}[0] data is huge. Processing only the first $insvLimit{$id}[1] records",2)) + { + $len = $insvLimit{$id}[1] * $dlen; + } + $raf->Read($buff, $len) == $len or last; + $et->VerboseDump(\$buff) if $verbose > 2; + if ($dlen) { + if ($len % $dlen) { + $et->Warn(sprintf('Unexpected Insta360 record 0x%x length',$id)); + } elsif ($id == 0x300) { + for ($p=0; $p<$len; $p+=$dlen) { + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + my @a; + if ($dlen == 56) { + @a = map { GetDouble(\$buff, $p + 8 * $_) } 1..6; + } else { + @a = unpack("x${p}x8v6", $buff); + map { $_ = ($_ - 0x8000) / 1000 } @a; + } + $et->HandleTag($tagTbl, TimeCode => sprintf('%.3f', Get64u(\$buff, $p) / 1000)); + $et->HandleTag($tagTbl, Accelerometer => "@a[0..2]"); # (NC) + $et->HandleTag($tagTbl, AngularVelocity => "@a[3..5]"); # (NC) + } + } elsif ($id == 0x400) { + for ($p=0; $p<$len; $p+=$dlen) { + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + $et->HandleTag($tagTbl, TimeCode => sprintf('%.3f', Get64u(\$buff, $p) / 1000)); + $et->HandleTag($tagTbl, ExposureTime => GetDouble(\$buff, $p + 8)); #6 + } + } elsif ($id == 0x600) { #6 + for ($p=0; $p<$len; $p+=$dlen) { + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + $et->HandleTag($tagTbl, VideoTimeStamp => sprintf('%.3f', Get64u(\$buff, $p) / 1000)); + } + } elsif ($id == 0x700) { + for ($p=0; $p<$len; $p+=$dlen) { + my $tmp = substr($buff, $p, $dlen); + my @a = unpack('VVvaa8aa8aa8a8a8', $tmp); + next unless $a[3] eq 'A'; # (ignore void fixes) + unless (($a[5] eq 'N' or $a[5] eq 'S') and # (quick validation) + ($a[7] eq 'E' or $a[7] eq 'W' or + # (odd, but I've seen "O" instead of "W". Perhaps + # when the language is french? ie. "Ouest"?) + $a[7] eq 'O')) + { + $et->Warn('Unrecognized INSV GPS format'); + last; + } + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + $a[$_] = GetDouble(\$a[$_], 0) foreach 4,6,8,9,10; + $a[4] = -abs($a[4]) if $a[5] eq 'S'; # (abs just in case it was already signed) + $a[6] = -abs($a[6]) if $a[7] ne 'E'; + $et->HandleTag($tagTbl, GPSDateTime => Image::ExifTool::ConvertUnixTime($a[0]) . 'Z'); + $et->HandleTag($tagTbl, GPSLatitude => $a[4]); + $et->HandleTag($tagTbl, GPSLongitude => $a[6]); + $et->HandleTag($tagTbl, GPSSpeed => $a[8] * $mpsToKph); + $et->HandleTag($tagTbl, GPSTrack => $a[9]); + $et->HandleTag($tagTbl, GPSAltitude => $a[10]); + $et->HandleTag($tagTbl, Unknown02 => "@a[1,2]") if $unknown; # millisecond counter (https://exiftool.org/forum/index.php?topic=9884.msg65143#msg65143) + } + } + } elsif ($id == 0x101) { + my $tagTablePtr = GetTagTable('Image::ExifTool::QuickTime::INSV_MakerNotes'); + for ($i=0, $p=0; $i<4; ++$i) { + last if $p + 2 > $len; + my ($t, $n) = unpack("x${p}CC", $buff); + last if $p + 2 + $n > $len; + my $val = substr($buff, $p+2, $n); + $et->HandleTag($tagTablePtr, $t, $val); + $p += 2 + $n; + } + } + ($epos -= 6) + $trailerLen < 0 and last; # step back to previous record + $raf->Seek($epos, 2) or last; + $raf->Read($buff, 6) == 6 or last; + } + $$et{DOC_NUM} = 0; + SetByteOrder('MM'); + delete $$et{SET_GROUP0}; + delete $$et{SET_GROUP1}; + return 1; +} + +#------------------------------------------------------------------------------ +# Process 360Fly 'uuid' atom containing sensor data +# (ref https://github.com/JamesHeinrich/getID3/blob/master/getid3/module.audio-video.quicktime.php) +# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub Process360Fly($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dataLen = length $$dataPt; + my $pos = 16; + my $lastTime = -1; + my $streamTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); + while ($pos + 32 <= $dataLen) { + my $type = ord substr $$dataPt, $pos, 1; + my $time = Get64u($dataPt, $pos + 2); # (only valid for some types) + if ($$tagTbl{$type}) { + if ($time != $lastTime) { + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + $lastTime = $time; + } + } + $et->HandleTag($tagTbl, $type, undef, DataPt => $dataPt, Start => $pos, Size => 32); + # synthesize GPSDateTime from the timestamp for GPS records + SetGPSDateTime($et, $streamTbl, $time / 1e6) if $type == 5; + $pos += 32; + } + delete $$et{DOC_NUM}; + return 1; +} + +#------------------------------------------------------------------------------ +# Process GPS from Vantrue N2S dashcam +# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub ProcessFMAS($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + return 0 unless $$dataPt =~ /^FMAS\0\0\0\0.{72}SAMM.{36}A/s and length($$dataPt) >= 160; + $et->VerboseDir('FMAS', undef, length($$dataPt)); + # 0000: 46 4d 41 53 00 00 00 00 00 00 00 00 00 00 00 00 [FMAS............] + # 0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [................] + # 0030: 02 08 01 08 06 08 02 04 07 02 06 00 00 00 00 00 [................] + # 0040: 00 00 00 00 00 00 00 00 4f 46 4e 49 4d 4d 41 53 [........OFNIMMAS] + # 0050: 53 41 4d 4d 01 00 00 00 00 00 00 00 00 00 00 00 [SAMM............] + # 0060: e5 07 09 18 08 00 22 00 02 00 00 00 a1 82 8a bf [......".........] + # 0070: 89 23 8e bd 0b 2c 30 bc 41 57 4e 51 16 00 a1 01 [.#...,0.AWNQ....] + # 0080: 29 26 27 0c 4b 00 49 00 00 00 00 00 00 00 00 00 [)&'.K.I.........] + # 0090: 00 00 00 00 00 00 00 00 00 52 00 00 00 00 00 00 [.........R......] + my @a = unpack('x96vCCCCCCx16AAACCCvCCvvv',$$dataPt); + SetByteOrder('II'); + my $acc = ReadValue($dataPt, 0x6c, 'float', 3); # (looks like Z comes first in my sample) + my $lon = $a[10] + ($a[11] + $a[13]/6000) / 60; # (why zero byte at $a[12]?) + my $lat = $a[14] + ($a[15] + $a[16]/6000) / 60; + $et->HandleTag($tagTbl, GPSDateTime => sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2d', @a[0..5])); + $et->HandleTag($tagTbl, GPSLatitude => $lat * ($a[9] eq 'S' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSLongitude => $lon * ($a[8] eq 'W' ? -1 : 1)); + $et->HandleTag($tagTbl, GPSSpeed => $a[17] * $mphToKph); # convert mph -> kph + $et->HandleTag($tagTbl, GPSTrack => $a[18]); + $et->HandleTag($tagTbl, Accelerometer=> $acc); + SetByteOrder('MM'); + return 1; +} + +#------------------------------------------------------------------------------ +# Scan media data for "freeGPS" metadata if not found already (ref PH) +# Inputs: 0) ExifTool ref +sub ScanMediaData($) +{ + my $et = shift; + my $raf = $$et{RAF} or return; + my ($tagTbl, $oldByteOrder, $verbose, $buff, $dataLen); + my ($pos, $buf2) = (0, ''); + + # don't rescan for freeGPS if we already found embedded metadata + my $dataPos = $$et{MediaDataOffset}; + if ($dataPos and not $$et{DOC_COUNT}) { + $dataLen = $$et{MediaDataSize}; + if ($dataLen) { + if ($raf->Seek($dataPos, 0)) { + $$et{FreeGPS2} = { }; # initialize variable space for FreeGPS2() + } else { + undef $dataLen; + } + } + } + + # loop through 'mdat' media data looking for GPS information + while ($dataLen) { + last if $pos + $gpsBlockSize > $dataLen; + last unless $raf->Read($buff, $gpsBlockSize); + $buff = $buf2 . $buff if length $buf2; + last if length $buff < $gpsBlockSize; + # look for "freeGPS " block + # (found on an absolute 0x8000-byte boundary in all of my samples, + # but allow for any alignment when searching) + if ($buff !~ /\0..\0freeGPS /sg) { # (seen ".." = "\0\x80","\x01\0") + $buf2 = substr($buff,-12); + $pos += length($buff)-12; + # in all of my samples the first freeGPS block is within 2 MB of the start + # of the mdat, so limit the scan to the first 20 MB to be fast and safe + next if $tagTbl or $pos < 20e6; + last; + } elsif (not $tagTbl) { + # initialize variables for extracting metadata from this block + $tagTbl = GetTagTable('Image::ExifTool::QuickTime::Stream'); + $verbose = $$et{OPTIONS}{Verbose}; + $oldByteOrder = GetByteOrder(); + SetByteOrder('II'); + $et->VPrint(0, "---- Extract Embedded ----\n"); + $$et{INDENT} .= '| '; + } + if (pos($buff) > 12) { + $pos += pos($buff) - 12; + $buff = substr($buff, pos($buff) - 12); + } + # make sure we have the full freeGPS record + my $len = unpack('N', $buff); + if ($len < 12) { + $len = 12; + } else { + my $more = $len - length($buff); + if ($more > 0) { + last unless $raf->Read($buf2, $more) == $more; + $buff .= $buf2; + } + if ($verbose) { + $et->VerboseDir('GPS', undef, $len); + $et->VerboseDump(\$buff, DataPos => $pos + $dataPos); + } + my $dirInfo = { DataPt => \$buff, DataPos => $pos + $dataPos, DirLen => $len }; + ProcessFreeGPS2($et, $dirInfo, $tagTbl); + } + $pos += $len; + $buf2 = substr($buff, $len); + } + if ($tagTbl) { + $$et{DOC_NUM} = 0; # reset DOC_NUM after extracting embedded metadata + $et->VPrint(0, "--------------------------\n"); + SetByteOrder($oldByteOrder); + $$et{INDENT} = substr $$et{INDENT}, 0, -2; + } + # process Insta360 trailer if it exists + ProcessInsta360($et); +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::QuickTime - Extract embedded information from media data + +=head1 SYNOPSIS + +These routines are autoloaded by Image::ExifTool::QuickTime. + +=head1 DESCRIPTION + +This file contains routines used by Image::ExifTool to extract embedded +information like GPS tracks from MOV, MP4 and INSV media data. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item Lhttps://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFChap3/qtff3.html#//apple_ref/doc/uid/TP40000939-CH205-SW130> + +=item L<http://sergei.nz/files/nvtk_mp42gpx.py> + +=item L<https://forum.flitsservice.nl/dashcam-info/dod-ls460w-gps-data-uit-mov-bestand-lezen-t87926.html> + +=item L<https://developers.google.com/streetview/publish/camm-spec> + +=item L<https://sergei.nz/extracting-gps-data-from-viofo-a119-and-other-novatek-powered-cameras/> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::QuickTime(3pm)|Image::ExifTool::QuickTime>, +L<Image::ExifTool::TagNames/QuickTime Stream Tags>, +L<Image::ExifTool::TagNames/GoPro GPMF Tags>, +L<Image::ExifTool::TagNames/Sony rtmd Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/README b/src/Image-ExifTool/lib/Image/ExifTool/README index 8f9b4441..1b989059 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/README +++ b/src/Image-ExifTool/lib/Image/ExifTool/README @@ -14,13 +14,14 @@ the binary data block (floating point IDs allow multiple tags for the same offset, with the integer part being used for the offset). The corresponding hash value provides information about the tag (explained later). -Twenty-six special keys (TABLE_NAME, SHORT_NAME, PROCESS_PROC, WRITE_PROC, -CHECK_PROC, GROUPS, FORMAT, FIRST_ENTRY, TAG_PREFIX, PRINT_CONV, WRITABLE, -TABLE_DESC, NOTES, IS_OFFSET, IS_SUBDIR, EXTRACT_UNKNOWN, NAMESPACE, PREFERRED, -SRC_TABLE, PRIORITY, AVOID, WRITE_GROUP, LANG_INFO, VARS, DATAMEMBER and -SET_GROUP1) are used to provide additional information about a table. The -special keys have names that are all capitalized to avoid possible conflicts -with tag keys. Below is an explanation of the meaning of each special key: +Twenty-eight special keys (TABLE_NAME, SHORT_NAME, PROCESS_PROC, WRITE_PROC, +CHECK_PROC, INIT_TABLE, GROUPS, FORMAT, FIRST_ENTRY, TAG_PREFIX, PRINT_CONV, +WRITABLE, TABLE_DESC, NOTES, IS_OFFSET, IS_SUBDIR, EXTRACT_UNKNOWN, NAMESPACE, +PREFERRED, PERMANENT, SRC_TABLE, PRIORITY, AVOID, WRITE_GROUP, LANG_INFO, VARS, +DATAMEMBER and SET_GROUP1) are used to provide additional information about a +table. The special keys have names that are all capitalized to avoid possible +conflicts with tag keys. Below is an explanation of the meaning of each special +key: TABLE_NAME : Name of this table (set automatically by GetTagTable()). @@ -52,18 +53,23 @@ with tag keys. Below is an explanation of the meaning of each special key: FixOffsets - Evaluated for each value pointer to patch maker note offsets LastIFD - Used by WriteExif() to return offset of last IFD written ImageData - Used by WriteExif() to avoid buffering large image data blocks + NoRefTest - Flag to bypass "referenced by previous directory" test - WRITE_PROC : Reference to a function to write all new tags for this directory. - The write proc returns the new directory data or undefined on error. It takes - the same arguments as the process proc above except that the second argument + WRITE_PROC : Function reference or name for writing this directory. The + function returns the new directory data or undefined on error. It takes the + same arguments as the process proc above except that the second argument (reference to directory information hash) is optional, and if specified gives information about the source directory for tags to be copied to the output. CHECK_PROC : Reference to a function which validates Raw values for writing. - The function takes three arguments: 0) ExifTool object reference, 1) tagInfo - reference, 2) value reference, and returns undefined (and possibly modifies - the input value) if successful, or an error message if there was a format - problem. May set ExifTool CHECK_WARN datamember for success with a warning. + The function takes 3-4 arguments: 0) ExifTool object reference, 1) tagInfo + reference, 2) value reference, and 3) [optional] conversion type. It returns + undefined (and possibly modifies the input value) if successful, or an error + message if there was a format problem. May set ExifTool CHECK_WARN datamember + for success with a warning. + + INIT_TABLE : Routine called to do any necessary initialization before the + first time the table is loaded. Argument is a reference to the table. GROUPS : A hash lookup for the default group names for all entries in this table. If not specified, the default Group 0 and 1 names will be set @@ -169,10 +175,13 @@ with tag keys. Below is an explanation of the meaning of each special key: PREFERRED : Set to true if the tags in this table should always be added when writing information. Overrides the order specified by SetNewGroups(). When - this feature is used, it may also be desireable to specify a preferred group + this feature is used, it may also be desirable to specify a preferred group when calling InitWriteDirs() to write these tags; this avoids creating other directories for tags which are already being creating in the preferred group. + PERMANENT : Tags in this table are Permanent, and can't be deleted. Maker + notes tags are Permanent by default, without the need to set this property. + SRC_TABLE : Used internally to store the source table name of a user-defined tag table so the appropriate module can be loaded as required. @@ -194,13 +203,16 @@ with tag keys. Below is an explanation of the meaning of each special key: ID_LABEL Label to use instead of "Tag ID" for column heading in tag name documentation. When this is set, numerical TagID's are - not converted to hexadecimal notation. Unless otherwise set, + not converted to hexadecimal notation. Unless otherwise set, an ID_LABEL of "Index" is assumed for tables which use ProcessBinaryData. NO_ID Avoid printing "Tag ID" column in tag name documentation. - HEX_ID Print tag ID in hexadecimal (with 4 hex digits or more). + HEX_ID Print tag ID in hexadecimal (with 4 hex digits or more). Set + to 0 for string ID's that look like hex numbers to prevent + them from being converted when importing an XML file for + language translations in BuildLangModules(). NO_LOOKUP Do not add tags to TagLookup.pm lookup tables. @@ -230,6 +242,10 @@ with tag keys. Below is an explanation of the meaning of each special key: START_INDEX [QuickTime tables only] Initial index for indices shown in Verbose output. Indices are not show otherwise. + ATOM_COUNT [QuickTime tables only] Maximum number of atoms contained in + within this atom. Currently used only for Canon CNTH atom, + which contains garbage after the first contained atom. + DATAMEMBER : BinaryData tables only. A reference to a list of sorted tag ID's which must be extracted as data members when writing. Must also list "var_" format tags and tags with Hook so offsets are properly calculated if the table @@ -245,7 +261,7 @@ describing this tag, or 3) a reference to a list of hashes which contain Condition expressions allowing the appropriate hash to be selected to suit the conditions. The following is a description of possible hash entries. All entries are optional, except for the tag Name which is required if the tag ID is -numerical. +numerical, and generated automatically otherwise. Name : The tag name. Tag names need not be unique. If they aren't unique, then duplicate tags will hide the values of previous @@ -349,6 +365,9 @@ numerical. 'DataTag' - associated tag name containing data for offset or byte count tags. + 'DelGroup' - set if deleting this tag is the same as deleting + the group of the same name. + 'Drop' - [IFD-format and PhaseOne makernote tags only] set to 1 for tags that should be excluded when rebuilding maker notes when copying all tags. Set to a number larger than 1 to drop @@ -369,11 +388,16 @@ numerical. 'Flattened' - [reserved] used internally to mark Struct tags which have been processed to generate flattened equivalents. - 'GotGroups' - [reserved] flag used internally to indicate that - the Groups hash has been initialized for this tag. + 'NotFlat' - [XMP tags only] Flag indicates that this tag ID + does not represent a flattened tag. Used to avoid a conflict + if the tag ID would be the same as a generated ID for a + flattened tag. The result is that the flattened tag will not + be accessible. 'Hidden' - set to hide tag from the TagName documentation. - Also suppresses verbose output of a BinaryData tag. + Also suppresses verbose output of a BinaryData tag. The + RawConv of a Hidden tag should return undef so the tag value + is not seen by the user. 'IsComposite' - flag set for Composite tags @@ -386,6 +410,9 @@ numerical. to be evaluated. Expression may access $val and $et, and is evaluated only when reading. + 'iTXt' - [PNG TextualData tags only] flag to write tag as PNG + iTXt chunk even if it contains no special characters. + 'List' - flag indicating that duplicate entries of this tag are allowed, and will be accumulated in a list. Note that for XMP information, 3 different types of lists are supported and @@ -425,6 +452,10 @@ numerical. may be written if the tag already exists. By default, all MakerNotes tags are permanent unless otherwise specified. + 'PreservePadding' - [QuickTime only] flag to preserve the + original size of the QuickTime atom by padding with nulls when + writing with the QuickTimePad option. + 'PrintHex' - specifies that unknown PrintConv values should be printed in hex (eg. 'Unknown (0x1)'). Also causes numerical tag values to be printed in hex in the HTML tag name @@ -449,15 +480,15 @@ numerical. tags in IFD1 of JPEG images which default to priority 0. 'Protected' - bit mask to protect tags from writing: - Bit 0x01 indicates an 'unsafe' tag, which is not set via + Bit 0x01 indicates an 'Unsafe' tag, which is not set via SetNewValuesFromFile() unless specified explicitly. - Bit 0x02 indicates a 'protected' tag, which should not be set + Bit 0x02 indicates a 'Protected' tag, which should not be set directly by the user. 'PutFirst' - [EXIF only] flag to place this value before IFD0 when writing (ie. immediately after TIFF header). Only used - for main IFD's (IFD0, IFD1, etc) and IFD's where SubIFD flag - is set to 2 (currently only ExifIFD). + for values in main IFD's (IFD0, IFD1, etc) and IFD's where + SubIFD flag is set to 2 (currently only ExifIFD). 'RawJoin' - [List tags only] Joins raw List-type tag values into a single string with a space separator, allowing @@ -502,7 +533,8 @@ numerical. SubIFD's where the PutFirst flag is valid. 'Unknown' - this is an unknown tag (only extracted when the - Unknown option is set). + Unknown option is set). This is set to 2 for Unknown tags in + binary tables (extracted when Unknown is 2). 'WriteNothing' - flag indicating that nothing is actually written when this tag is set. It is a fake writable tag that @@ -543,6 +575,10 @@ numerical. if a Warning may be issued) because ValueConv is more efficient since it is only executed if the tag value is requested, while RawConv is executed for all extracted tags. + Note that a tag is still writable if it has a RawConv without + a RawConvInv (with the exception of QuickTime ItemList and + UserData tags, which specifically require this), but this is + not true for ValueConv/PrintConv. ValueConv : Used to convert the Raw value to a useable form. May be a hash reference to act as a lookup table, a scalar which is @@ -551,53 +587,53 @@ numerical. split at whitespace into a list of items and each item is converted by the associated entry in the ValueConv list. A special value of 'REPEAT' may be used to repeat the previous - conversion for all remaning elements). If a hash reference is - used and the Raw value doesn't appear as one of the keys, then - the converted value is set to "Unknown (X)", where X is the - Raw value (unless either of the special keys exist: 'BITMASK', - a reference to a hash used to decode individual value bits; or - 'OTHER', a reference to a subroutine used to convert unknown - values. The OTHER subroutine takes 3 arguments: the value, a - flag which is set for the inverse conversion, and a reference - to the PrintConv hash, and returns the converted value or - undef on error -- it may call warn() to return an error - message. The lookup hash may also contain a 'Notes' entry - which is used for documentation if the SeparateTable flag is - set). In an expression, $self is a reference to the current - ExifTool object, $val is the Raw value, and $tag is the tag - key. The subroutine takes 2 arguments: the Raw value and a - reference to the current ExifTool object. The advanced - formatting expression (if any) may be accessed via the - ExifTool "FMT_EXPR" member variable. The expression or - subroutine is evaluated if and when the tag value is requested - (ie. only after all extraction is complete), so if necessary - at this time the values of all other tags are available via - calls to $self->GetValue("Tag","Raw"). (Note: In theory, - types other than "Raw" may be accessed, but they are slower - and may lead to cyclical dependencies so they should be - avoided). When evaluated, the expression or subroutine - returns a scalar for the converted value, a SCALAR reference - to a binary data value (see the 'Binary' flag), or an ARRAY - reference for a list of values. The return value should - always be defined -- use RawConv instead to return undef if it - is necessary to test the value for validity, otherwise an - undef tag may hide a previously defined value when the - Duplicates option is not enabled. If this isn't possible (as - with Composite tags where the converted values of the source - tags are needed), set the Priority to 0 to avoid taking - priority over a valid tag. If ValueConv is not specified, the - Raw value is not converted. Composite tags which Require or - Desire other tags may access the ValueConv, PrintConv and Raw - values of these tags through the elements of the @val, @prt - and @raw lists respectively (only if there was no RawConv or - it returned a hash reference). For these tags, $val may be - used in an expression to represent $val[0], and the first - argument passed for a code reference is a reference to @val. - Note: Warnings issued by these conversions are intercepted by - ExifTool and saved as Warning tags, but since ValueConv and - PrintConv conversions are done on demand, the warnings may be - generated after the list of extracted tags is returned, so may - easily be missed. + conversion for all remaining elements). If a hash reference + is used and the Raw value doesn't appear as one of the keys, + then the converted value is set to "Unknown (X)", where X is + the Raw value (unless either of the special keys exist: + 'BITMASK', a reference to a hash used to decode individual + value bits; or 'OTHER', a reference to a subroutine used to + convert unknown values. The OTHER subroutine takes 3 + arguments: the value, a flag which is set for the inverse + conversion, and a reference to the PrintConv hash, and returns + the converted value or undef on error -- it may call warn() to + return an error message. The lookup hash may also contain a + 'Notes' entry which is used for documentation if the + SeparateTable flag is set). In an expression, $self is a + reference to the current ExifTool object, $val is the Raw + value, and $tag is the tag key. The subroutine takes 2 + arguments: the Raw value and a reference to the current + ExifTool object. The advanced formatting expression (if any) + may be accessed via the ExifTool "FMT_EXPR" member variable. + The expression or subroutine is evaluated if and when the tag + value is requested (ie. only after all extraction is + complete), so if necessary at this time the values of all + other tags are available via calls to + $self->GetValue("Tag","Raw"). (Note: In theory, types other + than "Raw" may be accessed, but they are slower and may lead + to cyclical dependencies so they should be avoided). When + evaluated, the expression or subroutine returns a scalar for + the converted value, a SCALAR reference to a binary data value + (see the 'Binary' flag), or an ARRAY reference for a list of + values. The return value should always be defined -- use + RawConv instead to return undef if it is necessary to test the + value for validity, otherwise an undef tag may hide a + previously defined value when the Duplicates option is not + enabled. If this isn't possible (as with Composite tags where + the converted values of the source tags are needed), set the + Priority to 0 to avoid taking priority over a valid tag. If + ValueConv is not specified, the Raw value is not converted. + Composite tags which Require or Desire other tags may access + the ValueConv, PrintConv and Raw values of these tags through + the elements of the @val, @prt and @raw lists respectively + (only if there was no RawConv or it returned a hash + reference). For these tags, $val may be used in an expression + to represent $val[0], and the first argument passed for a code + reference is a reference to @val. Note: Warnings issued by + these conversions are intercepted by ExifTool and saved as + Warning tags, but since ValueConv and PrintConv conversions + are done on demand, the warnings may be generated after the + list of extracted tags is returned, so may easily be missed. PrintConv : This entry is similar to ValueConv above, except that it is used to further convert the tag value to a human readable @@ -674,8 +710,8 @@ numerical. BitShift : [Mask tags only] Bit shift for Mask-ed values. If not specified, set to the number of trailing bits in the Mask. - When reading, the value is shifted by this number of bits - after the Mask is applied. + When reading, the value is shifted right by this number of + bits after the Mask is applied. Condition : If given, specifies scalar which is evaluated as a Perl expression at extraction time to decide whether the tag is @@ -711,9 +747,10 @@ numerical. they are used as indices into the common @val, @prt and @raw lists), and together the keys must be sequential starting from 0. A special feature allows a scalar tag name to be used - instead of the hash reference when only the 0th tag is - defined. For example, the following two definitions are - equivalent: + instead of the hash reference, in which case the next + available index will be used (avoiding collisions with Desire + and Inhibit hash entries). For example, the following two + definitions are equivalent: Require => { 0 => 'XMP:Title' }, Require => 'XMP:Title', @@ -724,11 +761,15 @@ numerical. may be undefined for Desire'd tags. If no tags are Require'd, at least one of the Desire'd tags must exist for the Composite tag to be generated. If there are no Require'd or Desire'd - tags, then the Composite tag is always generated. + tags, then the Composite tag is always generated. A scalar + Desire tag name is given the next available index (after + scalar Require tags are allocated). Inhibit : [Composite tags only] Similar to the Require and Desire hashes, except that the Composite tag is NOT built if any of - the Inhibit tags exist. + the Inhibit tags exist. A scalar tag name is given the next + available index (after scalar Require and Desire tags are + allocated). Shift : [Writable tags only] Specifies type of shift to apply if this value may be shifted. Set to 'Time' for shifting date/time @@ -736,40 +777,45 @@ numerical. conditionally deleted. Writable : Indicates this tag can be written (or not written if Writable - is set to zero), and for EXIF-type tables gives format for - writing. Writable may be set to 1 for MakerNotes information - because the existing format is always used, however providing - a format is desireable because it is used in validating the - value. For EXIF tables, the Writable flag may be different - than the Format flag, in which case Format is used for - converting the binary value and Writable specifies the format - code written to the EXIF IFD. For SubDirectories in EXIF - information, this flag is only defined if the SubDirectory is - writable as a block, or if the SubDirectory can not be edited - (in which case Writable is set to 0). If non-zero, the - SubDirectory is also extracted as a block, so the Binary and - Protected flags should usually set as well. There is - currently no way to specify a write format for a SubDirectory - that is not writable as a block (the default is 'int32u' for - IFD-type SubDirectories, and 'undef' for all others). + is set to zero), and for EXIF and QuickTime tables gives + format for writing. Writable may be set to 1 for MakerNotes + information because the existing format is always used, + however providing a format is desirable because it is used in + validating the value. Set to 2 for tag to show "yes" in the + Writable column of the tag name documentation even when there + is no WRITE_PROC defined (eg. if it is written via an Extra + tag). For EXIF and QuickTime tables, the Writable flag may be + different than the Format flag, in which case Format is used + for converting the binary value and Writable specifies the + format code written to the EXIF IFD. For SubDirectories in + EXIF information, this flag is only defined if the + SubDirectory is writable as a block, or if the SubDirectory + can not be edited (in which case Writable is set to 0). If + non-zero, the SubDirectory is also extracted as a block, so + the Binary and Protected flags should usually set as well. + There is currently no way to specify a write format for a + SubDirectory that is not writable as a block (the default is + 'int32u' for IFD-type SubDirectories, and 'undef' for all + others). WriteAlso : Used for writable tag to specify other tags to write when this tag is written. The value is a hash reference. The hash keys are the names of the tags to write, and the values are evaluated to obtain the ValueConv values of each tag (or undef - to delete the tag). In the eval, $val is the Raw value of the - parent tag (which may be undef if the tag is being deleted, - and should not be modified because it will affect subsequent - WriteAlso tags), and the %opts hash may be accessed to modify - SetNewValue options for each tag. By default, Type is set to - "ValueConv" and the Protected option has bit 0x02 set to allow - writing of Protected tags that aren't directly writable. The - AddValue, DelValue, Shift and Replace options from the parent - tag are also defined, but no other options are set by default. - Previous new values of WriteAlso tags have already been - removed prior to the eval if the Replace option was used for - the parent tag. If an empty warning is issued ("\n"), the - target tag is not written and no error is reported. + to delete the tag). In the eval, $val is the new Raw value of + the parent tag (which may be undef if the tag is being + deleted, and should not be modified because it will affect + subsequent WriteAlso tags), and the %opts hash may be accessed + to modify SetNewValue options for each tag. By default, Type + is set to "ValueConv" and the Protected option has bit 0x02 + set to allow writing of Protected tags that aren't directly + writable. The AddValue, DelValue, Shift and Replace options + from the parent tag are also defined, but no other options are + set by default. Previous new values of WriteAlso tags have + already been removed prior to the eval if the Replace option + was used for the parent tag. If an empty warning is issued + ("\n"), the target tag is not written and no error is + reported. WriteCheck : If given, specifies a scalar which is evaluated as a Perl expression for a one-time validatation the Raw value being @@ -780,6 +826,9 @@ numerical. string is empty, the tag is not written and no warnings are issued, but WriteAlso is still evaluated if it exists. + WriteHook : [QuickTime only] Routine to call with these arguments when tag + is encountered during writing: 0) tag value, 1) ExifTool ref. + WriteOnly : Flag set if tag is write-only. Used for documentation only. DelCheck : Similar to WriteCheck, but called when the tag is deleted. The @@ -813,6 +862,8 @@ numerical. 0) ExifTool object ref, 1) new value hash ref, 2) old value, 3) new value reference. + Preferred : This tag is always preferred when writing. + Override : [User-defined Composite tags only] Flag to specify that the new tag definition should override the definition of existing Composite tags with the same name. Default is 1 unless @@ -874,13 +925,15 @@ numerical. Hook : [BinaryData tags only] Expression to be evaluated when extracting tag to allow dynamic Format, etc for BinaryData - tags. May access $self, and $size (the full size of the - binary data block), and assign a new value to $format to - dynamically set the tag format, and/or increment $varSize to - add a byte offset to subsequent tags. $varSize may be set to - a large number to effectively abort processing of the - directory after this tag. Must have corresponding DATAMEMBER - entry in writable tables. Must not have Unknown set. + tags. May access $self, $size (the full size of the binary + data record), $dataPt (reference to the data block), and $pos + (position of this tag in the data block), and assign a new + value to $format to dynamically set the tag format, and/or + increment $varSize to add a byte offset to subsequent tags. + $varSize may be set to a large number to effectively abort + processing of the directory after this tag. Must have + corresponding DATAMEMBER entry in writable tables. Must not + have Unknown set. LargeTag : [BinaryData tags only] Flag to indicate that the data for this tag is large, and that it shouldn't be stored in the %val @@ -925,6 +978,9 @@ numerical. alternate language tags (eg. 'fr'). Only used with formats which support alternate languages (eg. XMP, MIE, etc). + AddedUnknown : [reserved] Used internally to mark Unknown tags that were + added to the table at run time. + SubDirectory { If it exists, this specifies the start of a new subdirectory. It contains a collection of variables which specify the type and location of the subdirectory. Note that ValueConv and @@ -978,7 +1034,7 @@ numerical. The following variables may be used in the expression: $val (value of the tag), $dirData (reference to directory data), $subdirStart (offset to subdirectory start) and $size (size of - subdirectory). Returns true if subirectory is valid. + subdirectory). Returns true if subdirectory is valid. ProcessProc: If given, specifies processing procedure used to decode this subdirectory data. This overrides the default procedure @@ -1045,7 +1101,7 @@ The contained structure field information hashes are similar to tag information hashes, except that only the following elements are used: Raw/Value/PrintConv (and their inverses), TagID (optional), Groups, List, - Writable, Struct, Namespace, LangCode, PropertyPath, Notes. + Writable, Struct, Namespace, FlatName, LangCode, PropertyPath, Notes. But note that for PropertyPath, only the element of the path corresponding to the specific field is stored (including any necessary list properties). The @@ -1057,7 +1113,7 @@ flattened tags are allowed, and are used when it is necessary to change the Name or Description of a flattened tag. The flattened tag information hash entries are copied from the corresponding structure field definitions, even for pre-defined flattened tags. The exception is that the List property is -generated automatically unless explicity set to 0 in a pre-defined flattened +generated automatically unless explicitly set to 0 in a pre-defined flattened tag. -------------------------------------------------------------------------------- diff --git a/src/Image-ExifTool/lib/Image/ExifTool/RIFF.pm b/src/Image-ExifTool/lib/Image/ExifTool/RIFF.pm index b37e0831..f561cfba 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/RIFF.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/RIFF.pm @@ -21,6 +21,7 @@ # 13) http://tech.ebu.ch/docs/tech/tech3285.pdf # 14) https://developers.google.com/speed/webp/docs/riff_container # 15) https://tech.ebu.ch/docs/tech/tech3306-2009.pdf +# 16) https://sites.google.com/site/musicgapi/technical-documents/wav-file-format #------------------------------------------------------------------------------ package Image::ExifTool::RIFF; @@ -29,11 +30,12 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.51'; +$VERSION = '1.59'; sub ConvertTimecode($); sub ProcessSGLT($$$); sub ProcessSLLT($$$); +sub ProcessLucas($$$); # recognized RIFF variants my %riffType = ( @@ -142,7 +144,7 @@ my %code2charset = ( 0x64 => 'APICOM G.726 ADPCM', 0x65 => 'APICOM G.722 ADPCM', 0x66 => 'Microsoft DSAT', #6 - 0x67 => 'Micorsoft DSAT DISPLAY', #6 + 0x67 => 'Microsoft DSAT DISPLAY', #6 0x69 => 'Voxware Byte Aligned', #7 0x70 => 'Voxware AC8', #7 0x71 => 'Voxware AC10', #7 @@ -339,7 +341,7 @@ my %code2charset = ( these files, information is extracted from subsequent RIFF chunks as sub-documents, but the Duration is calculated for the full video. }, - # (not 100% sure that the concatination technique mentioned above is valid - PH) + # (not 100% sure that the concatenation technique mentioned above is valid - PH) 'fmt ' => { Name => 'AudioFormat', SubDirectory => { TagTable => 'Image::ExifTool::RIFF::AudioFormat' }, @@ -353,9 +355,35 @@ my %code2charset = ( SubDirectory => { TagTable => 'Image::ExifTool::RIFF::DS64' }, }, list => 'ListType', #15 - labl => { #15 - Name => 'Label', - SubDirectory => { TagTable => 'Image::ExifTool::RIFF::Label' }, + labl => { #16 (in 'adtl' chunk) + Name => 'CuePointLabel', + Priority => 0, # (so they are stored in sequence) + ValueConv => 'my $str=substr($val,4); $str=~s/\0+$//; unpack("V",$val) . " " . $str', + }, + note => { #16 (in 'adtl' chunk) + Name => 'CuePointNote', + Priority => 0, # (so they are stored in sequence) + ValueConv => 'my $str=substr($val,4); $str=~s/\0+$//; unpack("V",$val) . " " . $str', + }, + ltxt => { #16 (in 'adtl' chunk) + Name => 'LabeledText', + Notes => 'CuePointID Length Purpose Country Language Dialect Codepage Text', + Priority => 0, # (so they are stored in sequence) + ValueConv => q{ + my @a = unpack('VVa4vvvv', $val); + $a[2] = "'$a[2]'"; + my $txt = substr($val, 18); + $txt =~ s/\0+$//; # remove null terminator + return join(' ', @a, $txt); + }, + }, + smpl => { #16 + Name => 'Sampler', + SubDirectory => { TagTable => 'Image::ExifTool::RIFF::Sampler' }, + }, + inst => { #16 + Name => 'Instrument', + SubDirectory => { TagTable => 'Image::ExifTool::RIFF::Instrument' }, }, LIST_INFO => { Name => 'Info', @@ -395,6 +423,10 @@ my %code2charset = ( ProcessProc => \&Image::ExifTool::RIFF::ProcessChunks, }, }, + LIST_adtl => { #PH (ref 16, forum12387) + Name => 'AssociatedDataList', + SubDirectory => { TagTable => 'Image::ExifTool::RIFF::Main' }, + }, # seen LIST_JUNK JUNK => [ { @@ -433,6 +465,14 @@ my %code2charset = ( Condition => '$$valPt =~ /^PENTDigital Camera/', SubDirectory => { TagTable => 'Image::ExifTool::Pentax::Junk2' }, }, + { + Name => 'LucasJunk', # (Lucas LK-7900 Ace) + Condition => '$$valPt =~ /^0G(DA|PS)/', + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::Stream', + ProcessProc => \&ProcessLucas, + }, + }, { Name => 'TextJunk', # try to interpret unknown junk as an ASCII string @@ -457,10 +497,15 @@ my %code2charset = ( Name => 'NumberOfSamples', RawConv => 'Get32u(\$val, 0)', }, - 'cue ' => { + 'cue '=> { Name => 'CuePoints', Binary => 1, + Notes => q{ + config_files/cutepointlist.config from full distribution will decode this + and generate a list of cue points with labels + }, }, + plst => { Name => 'Playlist', Binary => 1 }, #16 afsp => { }, IDIT => { Name => 'DateTimeOriginal', @@ -473,17 +518,42 @@ my %code2charset = ( Name => 'CharacterSet', SubDirectory => { TagTable => 'Image::ExifTool::RIFF::CSET' }, }, + # tx_ tags are generated based on the Codec used for the txts stream + tx_USER => { + Name => 'UserText', + SubDirectory => { TagTable => 'Image::ExifTool::RIFF::UserText' }, + }, + tx_Unknown => { # (untested) + Name => 'Text', + Notes => 'streamed text, extracted when the ExtractEmbedded option is used', + }, + 'id3 ' => { + Name => 'ID3', + SubDirectory => { TagTable => 'Image::ExifTool::ID3::Main' }, + }, # # WebP-specific tags # - EXIF => { # (WebP) + EXIF => [{ # (WebP) Name => 'EXIF', + Condition => '$$valPt =~ /^(II\x2a\0|MM\0\x2a)/', Notes => 'WebP files', SubDirectory => { TagTable => 'Image::ExifTool::Exif::Main', ProcessProc => \&Image::ExifTool::ProcessTIFF, }, - }, + },{ # (WebP) - have also seen with "Exif\0\0" header - PH + Name => 'EXIF', + Condition => '$$valPt =~ /^Exif\0\0(II\x2a\0|MM\0\x2a)/', + SubDirectory => { + TagTable => 'Image::ExifTool::Exif::Main', + ProcessProc => \&Image::ExifTool::ProcessTIFF, + Start => 6, + }, + },{ + Name => 'UnknownEXIF', + Binary => 1, + }], 'XMP ' => { #14 (WebP) Name => 'XMP', Notes => 'WebP files', @@ -534,6 +604,38 @@ my %code2charset = ( ProcessProc => \&ProcessSLLT, }, }, + iXML => { #PH + SubDirectory => { TagTable => 'Image::ExifTool::XMP::XML' }, + }, + aXML => { #PH + SubDirectory => { TagTable => 'Image::ExifTool::XMP::XML' }, + }, +# +# tags found in an AlphaImagingTech AVI video - PH +# + LIST_INF0 => { # ('0' instead of 'O' -- odd) + Name => 'Info', + SubDirectory => { TagTable => 'Image::ExifTool::RIFF::Info' }, + }, + gps0 => { + Name => 'GPSTrack', + SetGroups => 'RIFF', # (moves "QuickTime" tags to the "RIFF" group) + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::Stream', + # (don't use code ref here or get "Prototype mismatch" warning with some Perl versions) + ProcessProc => 'Image::ExifTool::QuickTime::Process_gps0', + }, + }, + gsen => { + Name => 'GSensor', + SetGroups => 'RIFF', # (moves "QuickTime" tags to the "RIFF" group) + SubDirectory => { + TagTable => 'Image::ExifTool::QuickTime::Stream', + ProcessProc => 'Image::ExifTool::QuickTime::Process_gsen', + }, + }, + # gpsa - seen hex "01 20 00 00", same as QuickTime + # gsea - 16 bytes hex "04 08 02 00 20 02 00 00 1f 03 00 00 01 00 00 00" ); # the maker notes used by some digital cameras @@ -605,7 +707,11 @@ my %code2charset = ( Name => 'BWFVersion', Format => 'int16u', }, - # 348 - int8u[64] - SMPTE 330M UMID (Unique Material Identifier) + 348 => { + Name => 'BWF_UMID', + Format => 'undef[64]', + ValueConv => '$_=unpack("H*",$val); s/0{64}$//; uc $_', + }, # 412 - int8u[190] - reserved 602 => { Name => 'CodingHistory', @@ -638,16 +744,52 @@ my %code2charset = ( # very unlikely, support for these is not yet implemented) ); -# cue point labels (ref 15) -%Image::ExifTool::RIFF::Label = ( +# Sampler chunk (ref 16) +%Image::ExifTool::RIFF::Sampler = ( PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, GROUPS => { 2 => 'Audio' }, FORMAT => 'int32u', - 0 => 'LabelID', - 1 => { - Name => 'LabelText', - Format => 'string[$size-4]', + 0 => 'Manufacturer', + 1 => 'Product', + 2 => 'SamplePeriod', + 3 => 'MIDIUnityNote', + 4 => 'MIDIPitchFraction', + 5 => { + Name => 'SMPTEFormat', + PrintConv => { + 0 => 'none', + 24 => '24 fps', + 25 => '25 fps', + 29 => '29 fps', + 30 => '30 fps', + }, + }, + 6 => { + Name => 'SMPTEOffset', + Notes => 'HH:MM:SS:FF', + ValueConv => q{ + my $str = sprintf('%.8x', $val); + $str =~ s/(..)(..)(..)(..)/$1:$2:$3:$4/; + return $str; + }, }, + 7 => 'NumSampleLoops', + 8 => 'SamplerDataLen', + 9 => { Name => 'SamplerData', Format => 'undef[$size-40]', Binary => 1 }, +); + +# Instrument chunk (ref 16) +%Image::ExifTool::RIFF::Instrument = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Audio' }, + FORMAT => 'int8s', + 0 => 'UnshiftedNote', + 1 => 'FineTune', + 2 => 'Gain', + 3 => 'LowNote', + 4 => 'HighNote', + 5 => 'LowVelocity', + 6 => 'HighVelocity', ); # Sub chunks of INFO LIST chunk @@ -680,6 +822,7 @@ my %code2charset = ( ILGT => 'Lightness', IMED => 'Medium', INAM => 'Title', + ITRK => 'TrackNumber', IPLT => 'NumColors', IPRD => 'Product', ISBJ => 'Subject', @@ -878,7 +1021,7 @@ my %code2charset = ( # RIFF character set chunk %Image::ExifTool::RIFF::CSET = ( - PROCESS_PROC => \&Image::ExifTool::RIFF::ProcessBinaryData, + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, GROUPS => { 2 => 'Other' }, FORMAT => 'int16u', 0 => { @@ -938,6 +1081,12 @@ my %code2charset = ( Condition => '$$self{RIFFStreamType} eq "vids"', SubDirectory => { TagTable => 'Image::ExifTool::BMP::Main' }, }, + { + Name => 'TextFormat', + Condition => '$$self{RIFFStreamType} eq "txts"', + Hidden => 1, + RawConv => '$self->Options("ExtractEmbedded") or $self->WarnOnce("Use ExtractEmbedded option to extract timed text",3); undef', + }, ], ); @@ -968,7 +1117,7 @@ my %code2charset = ( 0 => { Name => 'StreamType', Format => 'string[4]', - RawConv => '$$self{RIFFStreamType} = $val', + RawConv => '$$self{RIFFStreamNum} = ($$self{RIFFStreamNum} || 0) + 1; $$self{RIFFStreamType} = $val', PrintConv => { auds => 'Audio', mids => 'MIDI', @@ -981,16 +1130,19 @@ my %code2charset = ( { Name => 'AudioCodec', Condition => '$$self{RIFFStreamType} eq "auds"', + RawConv => '$$self{RIFFStreamCodec}[$$self{RIFFStreamNum}-1] = $val', Format => 'string[4]', }, { Name => 'VideoCodec', Condition => '$$self{RIFFStreamType} eq "vids"', + RawConv => '$$self{RIFFStreamCodec}[$$self{RIFFStreamNum}-1] = $val', Format => 'string[4]', }, { Name => 'Codec', Format => 'string[4]', + RawConv => '$$self{RIFFStreamCodec}[$$self{RIFFStreamNum}-1] = $val', }, ], # 2 => 'StreamFlags', @@ -1186,6 +1338,55 @@ my %code2charset = ( }, ); +# streamed USER txts written by Momento M6 dashcam (ref PH) +%Image::ExifTool::RIFF::UserText = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 2 => 'Location' }, + NOTES => q{ + Tags decoded from the USER-format txts stream written by Momento M6 dashcam. + Extracted only if the ExtractEmbedded option is used. + }, + # (little-endian) + # 0 - int32u: 32 + # 4 - int32u: sample number (starting from unknown offset) + # 8 - int8u[4]: "w x y z" ? (w 0=front cam, 1=rear cam, z mostly 5-8) + # 12 - int8u[4]: "0 x 1 0" ? (x incrementing once per second) + # 16 - int8u[4]: "0 32 0 x" ? + # 20 - int32u: 100-150(mostly), 250-300(once per second) + # 24 - int8u[4]: "0 x y 0" ? + 28 => { Name => 'GPSAltitude', Format => 'int32u', ValueConv => '$val / 10' }, # (NC) + # 32 - int32u: 0(mostly), 23(once per second) + # 36 - int32u: 0 + 40 => { Name => 'Accelerometer', Format => 'float[3]' }, + # 52 - int32u: 1 + 56 => { Name => 'GPSSpeed', Format => 'float' }, # km/h + 60 => { + Name => 'GPSLatitude', + Format => 'float', + # Note: these values are unsigned and I don't know where the hemisphere is stored, + # but my only sample is from the U.S., so assume a positive latitude (for now) + ValueConv => 'my $deg = int($val / 100); $deg + ($val - $deg * 100) / 60', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + }, + 64 => { + Name => 'GPSLongitude', + Format => 'float', + # Note: these values are unsigned and I don't know where the hemisphere is stored, + # but my only sample is from the U.S., so assume a negative longitude (for now) + ValueConv => 'my $deg = int($val / 100); -($deg + ($val - $deg * 100) / 60)', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + }, + 68 => { + Name => 'GPSDateTime', + Description => 'GPS Date/Time', + Groups => { 2 => 'Time' }, + Format => 'int32u', + ValueConv => 'ConvertUnixTime($val)', + # (likely local time, but clock seemed off by 3 hours in my sample) + PrintConv => '$self->ConvertDateTime($val)', + }, +); + # WebP alpha info (ref 14) %Image::ExifTool::RIFF::ALPH = ( PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, @@ -1248,7 +1449,7 @@ my %code2charset = ( # (can't calculate duration like this for compressed audio types) RawConv => q{ return undef if $$self{VALUE}{FileType} =~ /^(LA|OFR|PAC|WV)$/; - return ($val[0] and not ($val[2] or $val[3])) ? $val[1] / $val[0] : undef; + return(($val[0] and not ($val[2] or $val[3])) ? $val[1] / $val[0] : undef); }, PrintConv => 'ConvertDuration($val)', }, @@ -1320,7 +1521,8 @@ sub CalcDuration($@) # FujiFilm REAL 3D AVI's), but the video stream information isn't reliable for # some cameras (eg. Olympus FE models), so use the video stream information # only if the RIFF header duration is 2 to 3 times longer - my $dur1 = $val[1] / $val[0] if $val[0]; + my $dur1; + $dur1 = $val[1] / $val[0] if $val[0]; if ($val[2] and $val[3]) { my $dur2 = $val[3] / $val[2]; my $rat = $dur1 / $dur2; @@ -1431,8 +1633,7 @@ sub MakeTagInfo($$) #------------------------------------------------------------------------------ # Process RIFF chunks -# Inputs: 0) ExifTool object reference, 1) directory information reference -# 2) tag table reference +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref # Returns: 1 on success sub ProcessChunks($$$) { @@ -1585,6 +1786,105 @@ sub ProcessSLLT($$$) return 1; } +#------------------------------------------------------------------------------ +# Process Lucas streaming GPS information (Lucas LK-7900 Ace) (ref PH) +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Returns: 1 on success +sub ProcessLucas($$$) +{ + my ($et, $dirInfo, $tagTbl) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $dataLen = length $$dataPt; + + unless ($et->Options('ExtractEmbedded')) { + $et->Warn('Use ExtractEmbedded option to extract timed GPS', 3); + return 1; + } + my %recLen = ( # record lengths (not including 4-byte ID) + '0GDA' => 24, + '0GPS' => 48, + ); + my ($date,$time,$lat,$lon,$alt,$spd,$sat,$dop,$ew,$ns); + $$et{SET_GROUP0} = $$et{SET_GROUP1} = 'RIFF'; + while ($$dataPt =~ /(0GDA|0GPS)/g) { + my ($rec, $pos) = ($1, pos $$dataPt); + $pos + $recLen{$rec} > $dataLen and $et->Warn("Truncated $1 record"), last; + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + # records start with int64u sample date/time in ms since 1970 + $et->HandleTag($tagTbl, SampleDateTime => Get64u($dataPt, $pos) / 1000); + if ($rec eq '0GPS') { + my $len = Get32u($dataPt, $pos+8); + my $endPos = $pos + $recLen{$rec} + $len; + $endPos > $dataLen and $et->Warn('Truncated 0GPS record'), last; + my $buff = substr($$dataPt, $pos+$recLen{$rec}, $len); + while ($buff =~ /\$(GC|GA),(\d+),/g) { + my $p = pos $buff; + $time = $2; + if ($1 eq 'GC') { + # time date dist ? sat dop alt A + # $GC,052350,180914,0000955,1,08,1.1,0017,,A*45\x0d\x0a\0 + if ($buff =~ /\G(\d+),\d*,\d*,(\d+),([-\d.]+),(\d+),\d*,A/g) { + ($date,$sat,$dop,$alt) = ($1,$2,$3,$4); + } + } else { + # time A lat lon spd N W + # $GA,052351,A,0949.6626,07635.4439,049,N,E,*4C\x0d\x0a\0 + if ($buff =~ /\GA,([\d.]+),([\d.]+),(\d+),([NS]),([EW])/g) { + ($lat,$lon,$spd,$ns,$ew) = ($1,$2,$3,$4,$5,$6); + # lat/long are in DDDMM.MMMM format + my $deg = int($lat / 100); + $lat = $deg + ($lat - $deg * 100) / 60; + $deg = int($lon / 100); + $lon = $deg + ($lon - $deg * 100) / 60; + $lat *= -1 if $ns eq 'S'; + $lon *= -1 if $ew eq 'W'; + } + } + # look ahead to next NMEA-like sentence, and store the fix + # now only if the next sentence is not at the same time + if ($buff !~ /\$(GC|GA),$time,/g) { + pos($$dataPt) = $endPos; + if ($$dataPt !~ /\$(GC|GA),(\d+)/ or $1 ne $time) { + $time =~ s/(\d{2})(\d{2})(\d{2})/$1:$2:$3Z/; + if ($date) { + $date =~ s/(\d{2})(\d{2})(\d{2})/20$3:$2:$1/; + $et->HandleTag($tagTbl, GPSDateTime => "$date $time"); + } else { + $et->HandleTag($tagTbl, GPSTimeStamp => $time); + } + if (defined $lat) { + $et->HandleTag($tagTbl, GPSLatitude => $lat); + $et->HandleTag($tagTbl, GPSLongitude => $lon); + $et->HandleTag($tagTbl, GPSSpeed => $spd); + } + if (defined $alt) { + $et->HandleTag($tagTbl, GPSAltitude => $alt); + $et->HandleTag($tagTbl, GPSSatellites => $sat); + $et->HandleTag($tagTbl, GPSDOP => $dop); + } + undef $lat; + undef $alt; + } + } + pos($buff) = $p; + } + $pos += $len; + } else { # this is an accelerometer (0GDA) record + # record has 4 more int32s values (the last is always 57 or 58 -- + # maybe related to sample time in ms? -- not extracted) + my @acc = unpack('x'.($pos+8).'V3', $$dataPt); + # change to signed integer and divide by 256 + map { $_ = $_ - 4294967296 if $_ >= 0x80000000; $_ /= 256 } @acc; + $et->HandleTag($tagTbl, Accelerometer => "@acc"); + } + pos($$dataPt) = $pos + $recLen{$rec}; + } + delete $$et{SET_GROUP0}; + delete $$et{SET_GROUP1}; + $$et{DOC_NUM} = 0; + return 1; +} + #------------------------------------------------------------------------------ # Extract information from a RIFF file # Inputs: 0) ExifTool object reference, 1) DirInfo reference @@ -1596,6 +1896,7 @@ sub ProcessRIFF($$) my ($buff, $buf2, $type, $mime, $err, $rf64); my $verbose = $et->Options('Verbose'); my $unknown = $et->Options('Unknown'); + my $ee = $et->Options('ExtractEmbedded'); # verify this is a valid RIFF file return 0 unless $raf->Read($buff, 12) == 12; @@ -1613,7 +1914,8 @@ sub ProcessRIFF($$) $mime = $riffMimeType{$type} if $type; $et->SetFileType($type, $mime); $$et{VALUE}{FileType} .= ' (RF64)' if $rf64; - $$et{RIFFStreamType} = ''; # initialize stream type + $$et{RIFFStreamType} = ''; # initialize stream type + $$et{RIFFStreamCodec} = []; # initialize codec array SetByteOrder('II'); my $tagTbl = GetTagTable('Image::ExifTool::RIFF::Main'); my $pos = 12; @@ -1652,17 +1954,28 @@ sub ProcessRIFF($$) # stop when we hit the audio data or AVI index or AVI movie data # --> no more because Adobe Bridge stores XMP after this!! # (so now we only do this on the FastScan option) - if (($tag eq 'data' or $tag eq 'idx1' or $tag eq 'LIST_movi') and - $et->Options('FastScan')) + if ($et->Options('FastScan') and ($tag eq 'data' or $tag eq 'idx1' or + ($tag eq 'LIST_movi' and not $ee))) { $et->VPrint(0, "(end of parsing)\n"); last; } # RIFF chunks are padded to an even number of bytes my $len2 = $len + ($len & 0x01); - if ($$tagTbl{$tag} or (($verbose or $unknown) and $tag !~ /^(data|idx1|LIST_movi|RIFF)$/)) { + # change name of stream txts data depending on the Codec + if ($ee and $tag =~ /^(\d{2})tx$/) { + $tag = 'tx_' . ($$et{RIFFStreamCodec}[$1] || 'Unknown'); + $tag = "tx_Unknown" unless defined $$tagTbl{$tag}; + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; + } + my $tagInfo = $$tagTbl{$tag}; + if ($tagInfo or (($verbose or $unknown) and $tag !~ /^(data|idx1|LIST_movi|RIFF|\d{2}(db|dc|wb))$/)) { $raf->Read($buff, $len2) == $len2 or $err=1, last; - MakeTagInfo($tagTbl, $tag) if not $$tagTbl{$tag} and ($verbose or $unknown); + my $setGroups; + if ($tagInfo and ref $tagInfo eq 'HASH' and $$tagInfo{SetGroups}) { + $setGroups = $$et{SET_GROUP0} = $$et{SET_GROUP1} = $$tagInfo{SetGroups}; + } + MakeTagInfo($tagTbl, $tag) if not $tagInfo and ($verbose or $unknown); $et->HandleTag($tagTbl, $tag, $buff, DataPt => \$buff, DataPos => 0, # (relative to Base) @@ -1670,11 +1983,18 @@ sub ProcessRIFF($$) Size => $len2, Base => $pos, ); + if ($setGroups) { + delete $$et{SET_GROUP0}; + delete $$et{SET_GROUP1}; + } + delete $$et{DOC_NUM} if $ee; } elsif ($tag eq 'RIFF') { # don't read into RIFF chunk (eg. concatenated video file) $raf->Read($buff, 4) == 4 or $err=1, last; # extract information from remaining file as an embedded file $$et{DOC_NUM} = ++$$et{DOC_COUNT} + } elsif ($tag eq 'LIST_movi' and $ee) { + next; # parse into movi chunk } else { if ($len > 0x7fffffff and not $et->Options('LargeFileSupport')) { $et->Warn("Stopped parsing at large $tag chunk (LargeFileSupport not set)"); @@ -1709,7 +2029,7 @@ including AVI videos, WAV audio files and WEBP images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/RSRC.pm b/src/Image-ExifTool/lib/Image/ExifTool/RSRC.pm index 61216997..26e75ab6 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/RSRC.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/RSRC.pm @@ -14,19 +14,22 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.08'; +$VERSION = '1.09'; + +sub ProcessRSRC($$); # Information decoded from Mac OS resources %Image::ExifTool::RSRC::Main = ( GROUPS => { 2 => 'Document' }, + PROCESS_PROC => \&ProcessRSRC, NOTES => q{ - Tags extracted from Mac OS resource files and DFONT files. These tags may - also be extracted from the resource fork of any file in OS X, either by - adding "/..namedfork/rsrc" to the filename to process the resource fork - alone, or by using the ExtractEmbedded (-ee) option to process the resource - fork as a sub-document of the main file. When writing, ExifTool preserves - the Mac OS resource fork by default, but it may deleted with C<-rsrc:all=> - on the command line. + Tags extracted from Mac OS resource files, DFONT files and "._" sidecar + files. These tags may also be extracted from the resource fork of any file + in OS X, either by adding "/..namedfork/rsrc" to the filename to process the + resource fork alone, or by using the L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> (-ee) option to process + the resource fork as a sub-document of the main file. When writing, + ExifTool preserves the Mac OS resource fork by default, but it may deleted + with C<-rsrc:all=> on the command line. }, '8BIM' => { Name => 'PhotoshopInfo', @@ -66,6 +69,9 @@ sub ProcessRSRC($$) my $raf = $$dirInfo{RAF}; my ($hdr, $map, $buff, $i, $j); + # allow access with data reference + $raf or $raf = new File::RandomAccess($$dirInfo{DataPt}); + # attempt to validate the format as thoroughly as practical return 0 unless $raf->Read($hdr, 30) == 30; my ($datOff, $mapOff, $datLen, $mapLen) = unpack('N*', $hdr); @@ -81,7 +87,7 @@ sub ProcessRSRC($$) SetByteOrder('MM'); my $typeOff = Get16u(\$map, 24); my $nameOff = Get16u(\$map, 26); - my $numTypes = Get16u(\$map, 28); + my $numTypes = (Get16u(\$map, 28) + 1) & 0xffff; # validate offsets in the resource map return 0 if $typeOff < 28 or $nameOff < 30; @@ -89,10 +95,10 @@ sub ProcessRSRC($$) $et->SetFileType('RSRC') unless $$et{IN_RESOURCE}; my $verbose = $et->Options('Verbose'); my $tagTablePtr = GetTagTable('Image::ExifTool::RSRC::Main'); - $et->VerboseDir('RSRC', $numTypes+1); + $et->VerboseDir('RSRC', $numTypes); # parse resource type list - for ($i=0; $i<=$numTypes; ++$i) { + for ($i=0; $i<$numTypes; ++$i) { my $off = $typeOff + 2 + 8 * $i; # offset of entry in type list last if $off + 8 > $mapLen; my $resType = substr($map,$off,4); # resource type @@ -219,7 +225,7 @@ resource files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/RTF.pm b/src/Image-ExifTool/lib/Image/ExifTool/RTF.pm index 81f177bb..1b33e3aa 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/RTF.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/RTF.pm @@ -15,7 +15,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.03'; +$VERSION = '1.04'; sub ProcessUserProps($$$); @@ -153,7 +153,7 @@ sub UnescapeRTF($$$) $val =~ tr/\n\r//d; # ignore CR's and LF's return $val; } - # CR/LF is signficant if it terminates a control sequence (so change these to a space) + # CR/LF is significant if it terminates a control sequence (so change these to a space) # (was $val =~ s/(^|[^\\])((?:\\\\)*)(\\[a-zA-Z]+(?:-?\d+)?)[\n\r]/$1$2$3 /g;) $val =~ s/\\(?:([a-zA-Z]+(?:-?\d+)?)[\n\r]|(.))/'\\'.($1 ? "$1 " : $2)/sge; # protect the newline control sequence by converting to a \par command @@ -181,12 +181,17 @@ sub UnescapeRTF($$$) if ($1 eq 'uc') { # \ucN $skip = $2; } elsif ($1 eq 'u') { # \uN - require Image::ExifTool::Charset; - $rtnVal .= Image::ExifTool::Charset::Recompose($et, [$2]); - if ($skip) { - # must skip the specified number of characters - # (not simple because RTF control words count as a single character) - last unless $val =~ /\G([^\\]|\\([a-zA-Z]+)(-?\d+)? ?|\\'.{2}|\\.){$skip}/g; + if ($2 < 0) { + $et->WarnOnce('Invalid Unicode character(s) in text'); + $rtnVal .= '?'; + } else { + require Image::ExifTool::Charset; + $rtnVal .= Image::ExifTool::Charset::Recompose($et, [$2]); + if ($skip) { + # must skip the specified number of characters + # (not simple because RTF control words count as a single character) + last unless $val =~ /\G([^\\]|\\([a-zA-Z]+)(-?\d+)? ?|\\'.{2}|\\.){$skip}/g; + } } } elsif ($rtfEntity{$1}) { require Image::ExifTool::Charset; @@ -361,7 +366,7 @@ information from RTF (Rich Text Format) documents. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Radiance.pm b/src/Image-ExifTool/lib/Image/ExifTool/Radiance.pm index 6dd8611b..5d315ab3 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Radiance.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Radiance.pm @@ -15,7 +15,7 @@ use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.01'; +$VERSION = '1.02'; # Radiance tags %Image::ExifTool::Radiance::Main = ( @@ -42,6 +42,7 @@ $VERSION = '1.01'; }, }, _command => 'Command', + _comment => 'Comment', software => 'Software', view => 'View', 'format' => 'Format', # <-- this is the one that caused the conflict when uppercase @@ -74,8 +75,12 @@ sub ProcessHDR($$) while ($raf->ReadLine($buff)) { chomp $buff; last unless length($buff) > 0 and length($buff) < 4096; + if ($buff =~ s/^#\s*//) { + $et->HandleTag($tagTablePtr, '_comment', $buff) if length $buff; + next; + } unless ($buff =~ /^(.*)?\s*=\s*(.*)/) { - $et->HandleTag($tagTablePtr, '_command', $buff); + $et->HandleTag($tagTablePtr, '_command', $buff) if length $buff; next; } # use lower-case tag names to avoid conflicts with reserved tag table entries @@ -120,7 +125,7 @@ images are a type of high dynamic-range image. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Rawzor.pm b/src/Image-ExifTool/lib/Image/ExifTool/Rawzor.pm index cf537db2..c9e61102 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Rawzor.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Rawzor.pm @@ -168,7 +168,7 @@ information from Rawzor compressed images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Real.pm b/src/Image-ExifTool/lib/Image/ExifTool/Real.pm index 4b1c58f4..203f6c1b 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Real.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Real.pm @@ -715,7 +715,7 @@ little-endian, but the Real format is big-endian. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Reconyx.pm b/src/Image-ExifTool/lib/Image/ExifTool/Reconyx.pm index 2b7b62b7..8b41fcee 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Reconyx.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Reconyx.pm @@ -7,6 +7,7 @@ # # References: 1) RCNX_MN10.pdf (courtesy of Reconyx Inc.) # 2) ultrafire_makernote.pdf (courtesy of Reconyx Inc.) +# 3) Reconyx private communication #------------------------------------------------------------------------------ package Image::ExifTool::Reconyx; @@ -14,7 +15,7 @@ package Image::ExifTool::Reconyx; use strict; use vars qw($VERSION); -$VERSION = '1.05'; +$VERSION = '1.06'; # info for Type2 version tags my %versionInfo = ( @@ -287,6 +288,132 @@ my %versionInfo = ( }, ); +# maker notes for Reconyx HF2 PRO cameras (ref 3) +%Image::ExifTool::Reconyx::Type3 = ( + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + WRITE_PROC => \&Image::ExifTool::WriteBinaryData, + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, + TAG_PREFIX => 'Reconyx', + WRITABLE => 1, + FIRST_ENTRY => 0, + NOTES => 'Tags extracted from models such as the HF2 PRO.', + # 0x0a => { Name => 'StructureVersion', Format => 'int16u' }, + # 0x0c => { Name => 'ParentFileSize', Format => 'int32u' }, + 0x10 => { Name => 'FileNumber', Format => 'int16u' }, + 0x12 => { Name => 'DirectoryNumber', Format => 'int16u' }, + # 0x14 => { Name => 'DirCreateDate', Format => 'int16u' }, + # 0x16 => { Name => 'DirCreateTime', Format => 'int16u' }, + # 0x18 - int16[8] SDCardLabel + # 0x28 => { Name => 'MakerNoteVersion', Format => 'int16u' }, + 0x2a => { + Name => 'FirmwareVersion', + Format => 'int16u[3]', + ValueConv => 'my @a = split " ",$val; sprintf("%d.%d%c",@a)', + ValueConvInv => '$val=~/(\d+)\.(\d+)([a-zA-Z])/ ? "$1 $2 ".ord($3) : undef', + }, + 0x30 => { + Name => 'FirmwareDate', + Format => 'int16u[2]', + ValueConv => 'my ($y,$d) = split " ", $val; sprintf("%.4x:%.2x:%.2x",$y,$d>>8,$d&0xff)', + ValueConvInv => 'my @a=split ":", $val; hex($a[0])." ".hex($a[1].$a[2])', + }, + 0x34 => { + Name => 'TriggerMode', #PH (NC) (called EventType in the Reconyx code) + Format => 'string[2]', + PrintConv => { + M => 'Motion Detection', # (seen this one only) + T => 'Time Lapse', # (NC) + P => 'Point and Shoot', # (NC) + }, + }, + 0x36 => { + Name => 'Sequence', + Format => 'int16u[2]', + PrintConv => '$val =~ s/ / of /; $val', + PrintConvInv => 'join(" ", $val=~/\d+/g)', + }, + 0x3a => { + Name => 'EventNumber', + Format => 'int16u[2]', + ValueConv => 'my @a=split " ",$val;($a[0]<<16)+$a[1]', + ValueConvInv => '($val >> 16) . " " . ($val & 0xffff)', + }, + 0x3e => { + Name => 'DateTimeOriginal', + Description => 'Date/Time Original', + Format => 'int16u[6]', + Groups => { 2 => 'Time' }, + Priority => 0, # (not as reliable as EXIF) + Shift => 'Time', + ValueConv => q{ + my @a = split ' ', $val; + sprintf('%.4d:%.2d:%.2d %.2d:%.2d:%.2d', reverse @a); + }, + ValueConvInv => q{ + my @a = ($val =~ /\d+/g); + return undef unless @a >= 6; + join ' ', @a[6,5,4,3,2,1,0]; + }, + PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val)', + }, + 0x4a => { #2 + Name => 'DayOfWeek', + Groups => { 2 => 'Time' }, + Format => 'int16u', + PrintConv => { + 0 => 'Sunday', + 1 => 'Monday', + 2 => 'Tuesday', + 3 => 'Wednesday', + 4 => 'Thursday', + 5 => 'Friday', + 6 => 'Saturday', + }, + }, + 0x4c => { + Name => 'MoonPhase', + Groups => { 2 => 'Time' }, + Format => 'int16u', + PrintConv => { + 0 => 'New', + 1 => 'New Crescent', + 2 => 'First Quarter', + 3 => 'Waxing Gibbous', + 4 => 'Full', + 5 => 'Waning Gibbous', + 6 => 'Last Quarter', + 7 => 'Old Crescent', + }, + }, + 0x4e => { + Name => 'AmbientTemperatureFahrenheit', + Format => 'int16s', + PrintConv => '"$val F"', + PrintConvInv => '$val=~/(-?\d+)/ ? $1 : $val', + }, + 0x50 => { + Name => 'AmbientTemperature', + Format => 'int16s', + PrintConv => '"$val C"', + PrintConvInv => '$val=~/(-?\d+)/ ? $1 : $val', + }, + 0x52 => { Name => 'Contrast', Format => 'int16u' }, + 0x54 => { Name => 'Brightness', Format => 'int16u' }, + 0x56 => { Name => 'Sharpness', Format => 'int16u' }, + 0x58 => { Name => 'Saturation', Format => 'int16u' }, + 0x5a => { Name => 'Flash', Format => 'int16u', PrintConv => { 0 => 'Off', 1 => 'On' } }, + 0x5c => { Name => 'AmbientInfrared', Format => 'int16u' }, + 0x5e => { Name => 'AmbientLight', Format => 'int16u' }, + 0x60 => { Name => 'MotionSensitivity', Format => 'int16u' }, + 0x62 => { Name => 'BatteryVoltage', Format => 'int16u' }, + 0x64 => { Name => 'BatteryVoltageAvg', Format => 'int16u' }, + 0x66 => { Name => 'BatteryType', Format => 'int16u' }, + 0x68 => { Name => 'UserLabel', Format => 'string[22]' }, + 0x7e => { Name => 'SerialNumber', Format => 'unicode[15]' }, +); + __END__ =head1 NAME @@ -304,7 +431,7 @@ maker notes in images from Reconyx cameras. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Red.pm b/src/Image-ExifTool/lib/Image/ExifTool/Red.pm new file mode 100644 index 00000000..23b4ba89 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/Red.pm @@ -0,0 +1,325 @@ +#------------------------------------------------------------------------------ +# File: Red.pm +# +# Description: Read Redcode R3D video files +# +# Revisions: 2018-01-25 - P. Harvey Created +# +# References: 1) http://www.wikiwand.com/en/REDCODE +#------------------------------------------------------------------------------ + +package Image::ExifTool::Red; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.01'; + +sub ProcessR3D($$); + +# RED format codes (ref PH) +my %redFormat = ( + 0 => 'int8u', + 1 => 'string', + 2 => 'float', + 3 => 'int8u', # (how is this different than 0?) + 4 => 'int16u', + 5 => 'int8s', # (not sure about this) + 6 => 'int32s', + 7 => 'undef', # (mixed-format structure?) + 8 => 'int32u', # (NC) + 9 => 'undef', # ? (seen 256 bytes, all zero) +); + +# error strings +my $errTrunc = 'Truncated R3D file'; + +# RED directory tags (ref PH) +%Image::ExifTool::Red::Main = ( + GROUPS => { 2 => 'Camera' }, + NOTES => 'Tags extracted from Redcode R3D video files.', + VARS => { ALPHA_FIRST => 1 }, + + RED1 => { Name => 'Red1Header', SubDirectory => { TagTable => 'Image::ExifTool::Red::RED1' } }, + RED2 => { Name => 'Red2Header', SubDirectory => { TagTable => 'Image::ExifTool::Red::RED2' } }, + + # (upper 4 bits of tag ID are the format code) + # ---- format 1 ---- + 0x1000 => 'StartEdgeCode', #1 + 0x1001 => { Name => 'StartTimecode', Groups => { 2 => 'Time' } }, #1 + 0x1002 => { #1 + Name => 'OtherDate1', + Groups => { 2 => 'Time' }, + # format is "YYYY_MM_DD[_TZ?]" + ValueConv => '$val =~ s/(\d{4})_(\d{2})_/$1:$2:/; $val =~ tr/_/ /; $val', + }, + 0x1003 => { #1 + Name => 'OtherDate2', + Groups => { 2 => 'Time' }, + ValueConv => '$val =~ s/(\d{4})_(\d{2})_/$1:$2:/; $val =~ tr/_/ /; $val', + }, + 0x1004 => { #1 + Name => 'OtherDate3', + Groups => { 2 => 'Time' }, + ValueConv => '$val =~ s/(\d{4})_(\d{2})_/$1:$2:/; $val =~ tr/_/ /; $val', + }, + 0x1005 => { #1 + Name => 'DateTimeOriginal', + Description => 'Date/Time Original', + Groups => { 2 => 'Time' }, + ValueConv => '$val =~ s/(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})/$1:$2:$3 $4:$5:/; $val', + PrintConv => '$self->ConvertDateTime($val)', + }, + 0x1006 => 'SerialNumber', #1 + 0x1019 => 'CameraType', #1 + 0x101a => { Name => 'ReelNumber', Groups => { 2 => 'Video' } }, #1 + 0x101b => { Name => 'Take', Groups => { 2 => 'Video' } }, + 0x1023 => { #1 + Name => 'DateCreated', + Groups => { 2 => 'Time' }, + ValueConv => '$val =~ s/(\d{4})(\d{2})/$1:$2:/; $val', + }, + 0x1024 => { #1 + Name => 'TimeCreated', + Groups => { 2 => 'Time' }, + ValueConv => '$val =~ s/(\d{2})(\d{2})/$1:$2:/; $val', + }, + 0x1025 => 'FirmwareVersion', #1 + 0x1029 => { Name => 'ReelTimecode', Groups => { 2 => 'Time' } }, #1 + 0x102a => 'StorageType', #1 + 0x1030 => { #1 + Name => 'StorageFormatDate', + Groups => { 2 => 'Time' }, + ValueConv => '$val =~ s/(\d{4})(\d{2})/$1:$2:/; $val', + }, + 0x1031 => { #1 + Name => 'StorageFormatTime', + Groups => { 2 => 'Time' }, + ValueConv => '$val =~ s/(\d{2})(\d{2})/$1:$2:/; $val', + }, + 0x1032 => 'StorageSerialNumber', #1 + 0x1033 => 'StorageModel', #1 + 0x1036 => 'AspectRatio', #1 + # 0x1041 - seen 'NA' + 0x1042 => 'Revision', # ? (seen "TODO, rev EPIC-1.0" and "MYSTERIUM X, rev EPIC-1.0") + # 0x1051 - seen 'C', 'L' + 0x1056 => 'OriginalFileName', + 0x106e => 'LensMake', + 0x106f => 'LensNumber', # (last 2 hex digits are LensType) + 0x1070 => 'LensModel', + 0x1071 => { + Name => 'Model', + Description => 'Camera Model Name', + }, + 0x107c => { Name => 'CameraOperator', Groups => { 2 => 'Author' } }, + 0x1086 => { + Name => 'VideoFormat', + Groups => { 2 => 'Video' }, + }, + 0x1096 => 'Filter', # optical low-pass filter + 0x10a0 => 'Brain', + 0x10a1 => 'Sensor', + # ---- format 2 ---- + 0x200d => 'ColorTemperature', + # 0x200e - (sometimes this is frame rate) + # 0x2015 - seen '1 1 1' (RGBGain or RGBGamma?) + 0x204b => 'RGBCurves', # (blackx/y,toex/y,midx/y,kneex/y,whitex/y) + 0x2066 => { + Name => 'OriginalFrameRate', + Groups => { 2 => 'Video' }, + PrintConv => 'int($val * 1000 + 0.5) / 1000', + }, + # ---- format 4 ---- + 0x4037 => { Name => 'CropArea' }, # (NC) + 0x403b => 'ISO', + # 0x404e - related to CropArea (or "0 0 0 0") + 0x406a => { Name => 'FNumber', ValueConv => '$val / 10' }, + 0x406b => 'FocalLength', + # 0x4084 - related to ISO? + # 0x4087 - related to ISO? + # ---- format 6 ---- + 0x606c => { Name => 'FocusDistance', ValueConv => '$val/1000', PrintConv => '"$val m"' }, +); + +# RED1 file header (ref PH) +%Image::ExifTool::Red::RED1 = ( + GROUPS => { 2 => 'Video' }, + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + NOTES => 'Redcode version 1 header.', + # 0x00 - int32u: length of header + # 0x04 - string: "RED1" + # 0x0a - string: "R1" + 0x07 => { Name => 'RedcodeVersion', Format => 'string[1]' }, #1 + # 0x0e - looks funny; my sample has a value of 43392 here + # 0x0e => { Name => 'AudioSampleRate', Format => 'int16u' }, #1 + 0x36 => { Name => 'ImageWidth', Format => 'int16u' }, #1 + 0x3a => { Name => 'ImageHeight', Format => 'int16u' }, #PH (ref 1 gave 0x3c) + 0x3e => { #PH (ref 1 gave 0x42 for denom) + Name => 'FrameRate', + Format => 'rational32u', + PrintConv => 'int($val * 1000 + 0.5) / 1000', + }, + 0x43 => { Name => 'OriginalFileName', Format => 'string[32]' }, #1 +); + +# RED2 file header (ref PH) +%Image::ExifTool::Red::RED2 = ( + GROUPS => { 2 => 'Video' }, + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + NOTES => 'Redcode version 2 header.', + # 0x00 - int32u: length of header + # 0x04 - string: "RED2" + 0x07 => { Name => 'RedcodeVersion', Format => 'string[1]' }, + # 0x08 - seen 0x05 + # 0x09 - seen 0x0d,0x0f,0x10 + # 0x0a - string: "R2" + # 0x0c - seen 0x04,0x05,0x07,0x08,0x0b,0x0c + # 0x0d - seen 0x01,0x08 (and 0x09 in block 1) + # 0x0e - int16u: seen 3072 + # 0x10 - looks like some sort of 32-byte hash or something (same in other blocks) + # 0x30-0x3f - mostly 0x00's with a couple of 0x01's + # 0x40 - int8u: count of 0x18-byte "rdi" records + # 0x41-0x43 - seen "\0\0\x01" + # ---- rdi record: (0x18 bytes long) ---- + # 0x44 - string: "rdi#" (where number is index of "rdi" record, starting at \x01) + 0x4c => { Name => 'ImageWidth', Format => 'int32u' }, + 0x50 => { Name => 'ImageHeight', Format => 'int32u' }, + # 0x54 - seen 0x11,0x13,0x15 (and 0x03 in "rdi\x02" record) + # 0x55 - seen 0x02 + 0x56 => { + Name => 'FrameRate', + Format => 'int16u[3]', + ValueConv => 'my @a = split " ",$val; ($a[1] * 0x10000 + $a[2]) / $a[0]', + PrintConv => 'int($val * 1000 + 0.5) / 1000', + }, + # (immediately following last "rdi" record is a + # Red directory beginning with int16u size) +); + +#------------------------------------------------------------------------------ +# Process metadata from a Redcode R3D video (ref PH) +# Inputs: 0) ExifTool object reference, 1) dirInfo reference +# Returns: 1 on success, 0 if this wasn't a valid R3D file +sub ProcessR3D($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my ($buff, $buf2, $pos, $dirLen, $dirEnd); + my $verbose = $et->Options('Verbose'); + + # R3D file structure: + # - each block starts with int32u block size followed by 4-byte block type + # - first block type is either "RED1" (version 1) or "RED2" (version 2) + # - blocks begin on even 0x1000 byte boundaries for version 2 files + + # validate the file header + return 0 unless $raf->Read($buff, 8) == 8 and $buff =~ /^\0\0..RED(1|2)/s; + my $ver = $1; + my $size = unpack('N', $buff); + return 0 if $size < 8; + + $et->SetFileType(); + SetByteOrder('MM'); + my $tagTablePtr = GetTagTable('Image::ExifTool::Red::Main'); + my $dataPos = 0; + + # read the first block of the file + $raf->Read($buf2, $size - 8) == $size - 8 or return $et->Warn($errTrunc); + $buff .= $buf2; + + # extract tags from the header + $et->HandleTag($tagTablePtr, "RED$ver", undef, DataPt => \$buff); + + # read the second block from a version 1 file because + # the first block doesn't contain a Red directory + if ($ver eq '1') { + # (read more than we need) + $raf->Read($buff, 0x10000) or return $et->Warn($errTrunc); + $dataPos += $size; + $pos = 0x22; # directory starts at offset 0x22 + } else { + # calculate position of Red directory start + length($buff) < 0x41 and return $et->Warn($errTrunc); + my $n = Get8u(\$buff, 0x40); # number of "rdi" records + $pos = 0x44 + $n * 0x18; + } + if ($pos + 8 > length $buff) { + $dirLen = 0; # find directory the hard way + } else { + $dirLen = Get16u(\$buff, $pos); # get length of Red directory + $pos += 2; # skip length word + } + # do sanity check on the directory size (in case our assumptions were wrong) + if ($dirLen < 300 or $dirLen >= 2048 or $pos + $dirLen > length $buff) { + # tag 0x1000 with length 0x000f should be near the directory start + $buff =~ /\0\x0f\x10\0/g or return $et->Warn("Can't find Red directory"); + $pos = pos($buff) - 4; + $dirEnd = length $buff; + undef $dirLen; + $et->Warn('This R3D file is different. Please submit a sample for testing'); + } else { + $dirEnd = $pos + $dirLen; + } + $$et{INDENT} .= '| ', $et->VerboseDir('Red', undef, $dirLen) if $verbose; + + # process the first Red directory + while ($pos + 4 <= $dirEnd) { + my $len = Get16u(\$buff, $pos); + last if $len < 4 or $pos + $len > $dirEnd; + my $tag = Get16u(\$buff, $pos + 2); + my $fmt = $redFormat{$tag >> 12}; # format is top 4 bits of tag ID (ref PH) + $fmt or $dirLen && $et->Warn('Unknown format code'), last; + $et->HandleTag($tagTablePtr, $tag, undef, + DataPt => \$buff, + DataPos => $dataPos, + Start => $pos + 4, + Size => $len - 4, + Format => $fmt, + ); + $pos += $len; + } + $$et{INDENT} = substr($$et{INDENT}, 0, -2) if $verbose; + + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::Red - Read Redcode R3D video files + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains routines required by Image::ExifTool to read metadata +from Redcode R3D version 1 and 2 video files. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<http://www.wikiwand.com/en/REDCODE> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/Red Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Ricoh.pm b/src/Image-ExifTool/lib/Image/ExifTool/Ricoh.pm index 7807b25a..816b8643 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Ricoh.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Ricoh.pm @@ -19,7 +19,7 @@ use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; -$VERSION = '1.33'; +$VERSION = '1.35'; sub ProcessRicohText($$$); sub ProcessRicohRMETA($$$); @@ -330,9 +330,13 @@ my %ricohLensIDs = ( }, }, 0x1018 => { #3 - Name => 'CropMode35mm', + Name => 'CropMode', Writable => 'int16u', - PrintConv => { 0 => 'Off', 1 => 'On' }, + PrintConv => { + 0 => 'Off', + 1 => 'On (35mm)', + 2 => 'On (47mm)', #IB + }, }, 0x1019 => { #3 Name => 'NDFilter', @@ -871,6 +875,7 @@ my %ricohLensIDs = ( Name => 'SoundFile', Notes => 'audio data recorded in JPEG images by the G700SE', }, + _barcode => { Name => 'Barcodes', List => 1 }, ); # information stored in Ricoh AVI images (ref PH) @@ -1000,6 +1005,23 @@ sub ProcessRicohRMETA($$$) # (but it looks like the int16u at $dirStart+6 is the next block number # if the data is continued, or 0 for the last block) $dirLen < 14 and $et->Warn('Short Ricoh RMETA block', 1), return 0; + if ($$dataPt =~ /^.{20}BARCODE/s) { + my $val = substr($$dataPt, 20); + $val =~ s/\0.*//s; + $val =~ s/^BARCODE\w+,\d{2},//; + my @codes; + for (;;) { + $val =~ s/(\d+),// and length $val >= $1 or last; + push @codes, substr($val, 0, $1); + last unless length $val > $1; + $val = substr($val, $1+1); + } + $et->HandleTag($tagTablePtr, '_barcode', \@codes) if @codes; + return 1; + } elsif ($$dataPt =~ /^.{18}ASCII/s) { + # (ignore barcode tag names for now) + return 1; + } my $audioLen = Get16u($dataPt, $dirStart+12); $audioLen + 14 > $dirLen and $et->Warn('Truncated Ricoh RMETA audio data', 1), return 0; my $buff = substr($$dataPt, $dirStart + 14, $audioLen); @@ -1121,7 +1143,7 @@ interpret Ricoh maker notes EXIF meta information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Samsung.pm b/src/Image-ExifTool/lib/Image/ExifTool/Samsung.pm index caeb8521..856d2193 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Samsung.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Samsung.pm @@ -11,7 +11,7 @@ # 4) Jaroslav Stepanek via rt.cpan.org # 5) Nick Livchits private communication # 6) Sreerag Raghavan private communication (SM-C200) -# IB) Iliah Borg private communcation (LibRaw) +# IB) Iliah Borg private communication (LibRaw) # NJ) Niels Kristian Bech Jensen private communication #------------------------------------------------------------------------------ @@ -22,11 +22,13 @@ use vars qw($VERSION %samsungLensTypes); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; -$VERSION = '1.43'; +$VERSION = '1.52'; sub WriteSTMN($$$); sub ProcessINFO($$$); +sub ProcessSamsungMeta($$$); sub ProcessSamsungIFD($$$); +sub ProcessSamsung($$$); # Samsung LensType lookup %samsungLensTypes = ( @@ -111,7 +113,7 @@ my %formatMinMax = ( This is a standard-format IFD found in the maker notes of some Samsung models, except that the entry count is a 4-byte integer and the offsets are relative to the end of the IFD. Currently, no tags in this IFD are known, - so the Unknown (-u) or Verbose (-v) option must be used to see this + so the L<Unknown|../ExifTool.html#Unknown> (-u) or L<Verbose|../ExifTool.html#Verbose> (-v) option must be used to see this information. }, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, @@ -234,6 +236,7 @@ my %formatMinMax = ( 0x500103c => 'WB600 / VLUU WB600 / WB610', 0x500133e => 'WB150 / WB150F / WB152 / WB152F / WB151', 0x5a0000f => 'WB5000 / HZ25W', + 0x5a0001e => 'WB5500 / VLUU WB5500 / HZ50W', 0x6001036 => 'EX1', 0x700131c => 'VLUU SH100, SH100', 0x27127002 => 'SMX-C20N', @@ -451,6 +454,8 @@ my %formatMinMax = ( 0xa018 => { #1 Name => 'ExposureTime', Writable => 'rational64u', + ValueConv => '$val=~s/ .*//; $val', # some models write 2 values here + ValueConvInv => '$val', PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', PrintConvInv => '$val', }, @@ -458,6 +463,8 @@ my %formatMinMax = ( Name => 'FNumber', Priority => 0, Writable => 'rational64u', + ValueConv => '$val=~s/ .*//; $val', # some models write 2 values here + ValueConvInv => '$val', PrintConv => 'sprintf("%.1f",$val)', PrintConvInv => '$val', }, @@ -924,17 +931,45 @@ my %formatMinMax = ( 4 => { Name => 'ThumbnailOffset', IsOffset => 1 }, ); +# information extracted from "ssuniqueid\0" APP5 (ref PH) +%Image::ExifTool::Samsung::APP5 = ( + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + ssuniqueid => { + Name => 'UniqueID', + # 32 bytes - some sort of serial number? + ValueConv => 'unpack("H*",$val)', + }, +); + # information extracted from Samsung trailer (ie. Samsung SM-T805 "Sound & Shot" JPEG) (ref PH) %Image::ExifTool::Samsung::Trailer = ( GROUPS => { 0 => 'MakerNotes', 2 => 'Other' }, - VARS => { NO_ID => 1 }, + VARS => { NO_ID => 1, HEX_ID => 0 }, + PROCESS_PROC => \&ProcessSamsung, + PRIORITY => 0, # (first one takes priority so DepthMapWidth/Height match first DepthMapData) NOTES => q{ Tags extracted from the trailer of JPEG images written when using certain features (such as "Sound & Shot" or "Shot & More") from Samsung models such - as the Galaxy S4 and Tab S. - }, - '0x0001-name' => 'EmbeddedImageName', # ("DualShot_1","DualShot_2") - '0x0001' => { Name => 'EmbeddedImage', Groups => { 2 => 'Preview' }, Binary => 1 }, + as the Galaxy S4 and Tab S, and from the 'sefd' atom in HEIC images from the + Samsung S10+. + }, + '0x0001-name' => { + Name => 'EmbeddedImageName', # ("DualShot_1","DualShot_2") + RawConv => '$$self{EmbeddedImageName} = $val', + }, + '0x0001' => [ + { + Name => 'EmbeddedImage', + Condition => '$$self{EmbeddedImageName} eq "DualShot_1"', + Groups => { 2 => 'Preview' }, + Binary => 1, + }, + { + Name => 'EmbeddedImage2', + Groups => { 2 => 'Preview' }, + Binary => 1, + }, + ], '0x0100-name' => 'EmbeddedAudioFileName', # ("SoundShot_000") '0x0100' => { Name => 'EmbeddedAudioFile', Groups => { 2 => 'Audio' }, Binary => 1 }, '0x0201-name' => 'SurroundShotVideoName', # ("Interactive_Panorama_000") @@ -948,6 +983,8 @@ my %formatMinMax = ( # 0x08e0-name - seen 'Panorama_Shot_Info' # 0x08e0 - string, seen 'PanoramaShot' # 0x08e1-name - seen 'Motion_Panorama_Info' + # 0x0910-name - seen 'Front_Cam_Selfie_Info' + # 0x0910 - string, seen 'Front_Cam_Selfie_Info' # 0x09e0-name - seen 'Burst_Shot_Info' # 0x09e0 - string, seen '489489125' # 0x0a01-name - seen 'Image_UTC_Data' @@ -962,28 +999,342 @@ my %formatMinMax = ( '0x0a30-name' => 'EmbeddedVideoType', # ("MotionPhoto_Data") '0x0a30' => { Name => 'EmbeddedVideoFile', Groups => { 2 => 'Video' }, Binary => 1 }, #forum7161 # 0x0aa1-name - seen 'MCC_Data' - # 0x0aa1 - seen '234','222' - '0x0ab1-name' => 'DepthMapName', # seen 'DualShot_DepthMap_1' (SM-N950U) - '0x0ab1' => { Name => 'DepthMapData', Binary => 1 }, + # 0x0aa1 - seen '204','222','234','302','429' + '0x0aa1' => { + Name => 'MCCData', + Groups => { 2 => 'Location' }, + PrintConv => { + 202 => 'Greece', + 204 => 'Netherlands', + 206 => 'Belgium', + 208 => 'France', + 212 => 'Monaco', + 213 => 'Andorra', + 214 => 'Spain', + 216 => 'Hungary', + 218 => 'Bosnia & Herzegov.', + 219 => 'Croatia', + 220 => 'Serbia', + 221 => 'Kosovo', + 222 => 'Italy', + 226 => 'Romania', + 228 => 'Switzerland', + 230 => 'Czech Rep.', + 231 => 'Slovakia', + 232 => 'Austria', + 234 => 'United Kingdom', + 235 => 'United Kingdom', + 238 => 'Denmark', + 240 => 'Sweden', + 242 => 'Norway', + 244 => 'Finland', + 246 => 'Lithuania', + 247 => 'Latvia', + 248 => 'Estonia', + 250 => 'Russian Federation', + 255 => 'Ukraine', + 257 => 'Belarus', + 259 => 'Moldova', + 260 => 'Poland', + 262 => 'Germany', + 266 => 'Gibraltar', + 268 => 'Portugal', + 270 => 'Luxembourg', + 272 => 'Ireland', + 274 => 'Iceland', + 276 => 'Albania', + 278 => 'Malta', + 280 => 'Cyprus', + 282 => 'Georgia', + 283 => 'Armenia', + 284 => 'Bulgaria', + 286 => 'Turkey', + 288 => 'Faroe Islands', + 289 => 'Abkhazia', + 290 => 'Greenland', + 292 => 'San Marino', + 293 => 'Slovenia', + 294 => 'Macedonia', + 295 => 'Liechtenstein', + 297 => 'Montenegro', + 302 => 'Canada', + 308 => 'St. Pierre & Miquelon', + 310 => 'United States / Guam', + 311 => 'United States / Guam', + 312 => 'United States', + 316 => 'United States', + 330 => 'Puerto Rico', + 334 => 'Mexico', + 338 => 'Jamaica', + 340 => 'French Guiana / Guadeloupe / Martinique', + 342 => 'Barbados', + 344 => 'Antigua and Barbuda', + 346 => 'Cayman Islands', + 348 => 'British Virgin Islands', + 350 => 'Bermuda', + 352 => 'Grenada', + 354 => 'Montserrat', + 356 => 'Saint Kitts and Nevis', + 358 => 'Saint Lucia', + 360 => 'St. Vincent & Gren.', + 362 => 'Bonaire, Sint Eustatius and Saba / Curacao / Netherlands Antilles', + 363 => 'Aruba', + 364 => 'Bahamas', + 365 => 'Anguilla', + 366 => 'Dominica', + 368 => 'Cuba', + 370 => 'Dominican Republic', + 372 => 'Haiti', + 374 => 'Trinidad and Tobago', + 376 => 'Turks and Caicos Islands / US Virgin Islands', + 400 => 'Azerbaijan', + 401 => 'Kazakhstan', + 402 => 'Bhutan', + 404 => 'India', + 405 => 'India', + 410 => 'Pakistan', + 412 => 'Afghanistan', + 413 => 'Sri Lanka', + 414 => 'Myanmar (Burma)', + 415 => 'Lebanon', + 416 => 'Jordan', + 417 => 'Syrian Arab Republic', + 418 => 'Iraq', + 419 => 'Kuwait', + 420 => 'Saudi Arabia', + 421 => 'Yemen', + 422 => 'Oman', + 424 => 'United Arab Emirates', + 425 => 'Israel / Palestinian Territory', + 426 => 'Bahrain', + 427 => 'Qatar', + 428 => 'Mongolia', + 429 => 'Nepal', + 430 => 'United Arab Emirates', + 431 => 'United Arab Emirates', + 432 => 'Iran', + 434 => 'Uzbekistan', + 436 => 'Tajikistan', + 437 => 'Kyrgyzstan', + 438 => 'Turkmenistan', + 440 => 'Japan', + 441 => 'Japan', + 450 => 'South Korea', + 452 => 'Viet Nam', + 454 => 'Hongkong, China', + 455 => 'Macao, China', + 456 => 'Cambodia', + 457 => 'Laos P.D.R.', + 460 => 'China', + 466 => 'Taiwan', + 467 => 'North Korea', + 470 => 'Bangladesh', + 472 => 'Maldives', + 502 => 'Malaysia', + 505 => 'Australia', + 510 => 'Indonesia', + 514 => 'Timor-Leste', + 515 => 'Philippines', + 520 => 'Thailand', + 525 => 'Singapore', + 528 => 'Brunei Darussalam', + 530 => 'New Zealand', + 537 => 'Papua New Guinea', + 539 => 'Tonga', + 540 => 'Solomon Islands', + 541 => 'Vanuatu', + 542 => 'Fiji', + 544 => 'American Samoa', + 545 => 'Kiribati', + 546 => 'New Caledonia', + 547 => 'French Polynesia', + 548 => 'Cook Islands', + 549 => 'Samoa', + 550 => 'Micronesia', + 552 => 'Palau', + 553 => 'Tuvalu', + 555 => 'Niue', + 602 => 'Egypt', + 603 => 'Algeria', + 604 => 'Morocco', + 605 => 'Tunisia', + 606 => 'Libya', + 607 => 'Gambia', + 608 => 'Senegal', + 609 => 'Mauritania', + 610 => 'Mali', + 611 => 'Guinea', + 612 => 'Ivory Coast', + 613 => 'Burkina Faso', + 614 => 'Niger', + 615 => 'Togo', + 616 => 'Benin', + 617 => 'Mauritius', + 618 => 'Liberia', + 619 => 'Sierra Leone', + 620 => 'Ghana', + 621 => 'Nigeria', + 622 => 'Chad', + 623 => 'Central African Rep.', + 624 => 'Cameroon', + 625 => 'Cape Verde', + 626 => 'Sao Tome & Principe', + 627 => 'Equatorial Guinea', + 628 => 'Gabon', + 629 => 'Congo, Republic', + 630 => 'Congo, Dem. Rep.', + 631 => 'Angola', + 632 => 'Guinea-Bissau', + 633 => 'Seychelles', + 634 => 'Sudan', + 635 => 'Rwanda', + 636 => 'Ethiopia', + 637 => 'Somalia', + 638 => 'Djibouti', + 639 => 'Kenya', + 640 => 'Tanzania', + 641 => 'Uganda', + 642 => 'Burundi', + 643 => 'Mozambique', + 645 => 'Zambia', + 646 => 'Madagascar', + 647 => 'Reunion', + 648 => 'Zimbabwe', + 649 => 'Namibia', + 650 => 'Malawi', + 651 => 'Lesotho', + 652 => 'Botswana', + 653 => 'Swaziland', + 654 => 'Comoros', + 655 => 'South Africa', + 657 => 'Eritrea', + 659 => 'South Sudan', + 702 => 'Belize', + 704 => 'Guatemala', + 706 => 'El Salvador', + 708 => 'Honduras', + 710 => 'Nicaragua', + 712 => 'Costa Rica', + 714 => 'Panama', + 716 => 'Peru', + 722 => 'Argentina Republic', + 724 => 'Brazil', + 730 => 'Chile', + 732 => 'Colombia', + 734 => 'Venezuela', + 736 => 'Bolivia', + 738 => 'Guyana', + 740 => 'Ecuador', + 744 => 'Paraguay', + 746 => 'Suriname', + 748 => 'Uruguay', + 750 => 'Falkland Islands (Malvinas)', + 901 => 'International Networks / Satellite Networks', + }, + }, + # 0x0ab0-name - seen 'DualShot_Meta_Info' + '0x0ab1-name' => { + Name => 'DepthMapName', + # seen 'DualShot_DepthMap_1' (SM-N950U), DualShot_DepthMap_5 (SM-G998W) + RawConv => '$$self{DepthMapName} = $val', + }, + '0x0ab1' => [ + { + Name => 'DepthMapData', + Condition => '$$self{DepthMapName} eq "DualShot_DepthMap_1"', + Binary => 1, + },{ + Name => 'DepthMapData2', + Binary => 1, + }, + ], # 0x0ab3-name - seen 'DualShot_Extra_Info' (SM-N950U) '0x0ab3' => { # (SM-N950U) - Name => 'DualShotInfo', - SubDirectory => { TagTable => 'Image::ExifTool::Samsung::DualShotInfo' }, + Name => 'DualShotExtra', + SubDirectory => { TagTable => 'Image::ExifTool::Samsung::DualShotExtra' }, }, # 0x0ac0-name - seen 'ZoomInOut_Info' (SM-N950U) # 0x0ac0 - 2048 bytes of interesting stuff including firmware version? (SM-N950U) + '0x0b40' => { # (SM-N975X front camera) + Name => 'SingleShotMeta', + SubDirectory => { TagTable => 'Image::ExifTool::Samsung::SingleShotMeta' }, + }, + # 0x0b41-name - seen 'SingeShot_DepthMap_1' (Yes, "Singe") (SM-N975X front camera) + '0x0b41' => { Name => 'SingleShotDepthMap', Binary => 1 }, # 0xa050-name - seen 'Jpeg360_2D_Info' (Samsung Gear 360) # 0xa050 - seen 'Jpeg3602D' (Samsung Gear 360) ); # DualShot Extra Info (ref PH) -%Image::ExifTool::Samsung::DualShotInfo = ( +%Image::ExifTool::Samsung::DualShotExtra = ( PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, FIRST_ENTRY => 0, FORMAT => 'int32u', - 9 => 'DepthMapWidth', - 10 => 'DepthMapHeight', + # This is a pain, but the DepthMapWidth/Height move around in this record. + # In all of my samples so far, the bytes "01 00 ff ff" precede these tags. + # I have seen this byte sequence at offsets 32, 60, 64 and 68, so look for + # it in bytes 32-95, and use its location to adjust the tag positions + 8 => { + Name => 'DualShotDummy', + Format => 'undef[64]', + Hidden => 1, + Hook => q{ + if ($size >= 96) { + my $tmp = substr($$dataPt, $pos, 64); + # (have seen 0x01,0x03 and 0x07) + if ($tmp =~ /[\x01-\x09]\0\xff\xff/g and not pos($tmp) % 4) { + $$self{DepthMapTagPos} = pos($tmp); + $varSize += $$self{DepthMapTagPos} - 32; + } + } + }, + RawConv => 'undef', # not a real tag + }, + 16 => { + Name => 'DepthMapWidth', + Condition => '$$self{DepthMapTagPos}', + Notes => 'index varies depending on model', + }, + 17 => { + Name => 'DepthMapHeight', + Condition => '$$self{DepthMapTagPos}', + Notes => 'index varies depending on model', + }, +); + +# SingleShot Meta Info (ref PH) (SM-N975X front camera) +%Image::ExifTool::Samsung::SingleShotMeta = ( + PROCESS_PROC => \&ProcessSamsungMeta, + GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + inputWidth => { }, + inputHeight => { }, + outputWidth => { }, + outputHeight => { }, + segWidth => { }, + segHeight => { }, + depthSWWidth => { }, + depthSWHeight => { }, + depthHWWidth => { }, + depthHWHeight => { }, + flipStatus => { }, + lensFacing => { }, + deviceOrientation => { }, + objectOrientation => { }, + isArtBokeh => { }, + beautyRetouchLevel => { }, + beautyColorLevel => { }, + effectType => { }, + effectStrength => { }, + blurStrength => { }, + spinStrength => { }, + zoomStrength => { }, + colorpopStrength => { }, + monoStrength => { }, + sidelightStrength => { }, + vintageStrength => { }, + bokehShape => { }, + perfMode => { }, ); # Samsung composite tags @@ -1012,7 +1363,19 @@ my %formatMinMax = ( my $tiff = MakeTiffHeader($val[1],$val[2],1,8) . ${$val[0]}; return \$tiff; }, - } + }, + SingleShotDepthMapTiff => { + Require => { + 0 => 'SingleShotDepthMap', + 1 => 'SegWidth', + 2 => 'SegHeight', + }, + ValueConv => q{ + return undef unless length ${$val[0]} == $val[1] * $val[2]; + my $tiff = MakeTiffHeader($val[1],$val[2],1,8) . ${$val[0]}; + return \$tiff; + }, + }, ); # add our composite tags @@ -1081,6 +1444,54 @@ sub ProcessINFO($$$) return 1; } +#------------------------------------------------------------------------------ +# Read Samsung Meta Info from trailer +# Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref +# Returns: true on success +sub ProcessSamsungMeta($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + my $dirName = $$dirInfo{DirName}; + my $dataPt = $$dirInfo{DataPt}; + my $pos = $$dirInfo{DirStart}; + my $end = $$dirInfo{DirLen} + $pos; + unless ($pos + 8 <= $end and substr($$dataPt, $pos, 4) eq 'DOFS') { + $et->Warn("Unrecognized $dirName data"); + return 0; + } + my $ver = Get32u($dataPt, $pos + 4); + if ($ver == 3) { + unless ($pos + 18 <= $end and Get32u($dataPt, $pos + 12) == $$dirInfo{DirLen}) { + $et->Warn("Unrecognized $dirName version $ver data"); + return 0; + } + my $num = Get16u($dataPt, $pos + 16); + $et->VerboseDir("$dirName version $ver", $num); + $pos += 18; + my ($i, $val); + for ($i=0; $i<$num; ++$i) { + last if $pos + 2 > $end; + my ($x, $n) = unpack("x${pos}CC", $$dataPt); + $pos += 2; + last if $pos + $n + 2 > $end; + my $tag = substr($$dataPt, $pos, $n); + my $len = Get16u($dataPt, $pos + $n); + $pos += $n + 2; + last if $pos + $len > $end; + if ($len == 4) { + $val = Get32u($dataPt, $pos); + } else { + my $tmp = substr($$dataPt, $pos, $len); + $val = \$pos; + } + $et->HandleTag($tagTablePtr, $tag, $val); + $pos += $len; + } + $et->Warn("Unexpected end of $dirName version $ver $i $num data") if $i < $num; + } + return 1; +} + #------------------------------------------------------------------------------ # Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref # Returns: true on success @@ -1131,6 +1542,10 @@ sub ProcessSamsung($$$) my $unknown = $et->Options('Unknown'); my ($buff, $buf2, $index, $offsetPos, $audioNOff, $audioSize); + unless ($raf) { + $raf = new File::RandomAccess($$dirInfo{DataPt}); + $et->VerboseDir('SamsungTrailer'); + } return 0 unless $raf->Seek(-6-$offset, 2) and $raf->Read($buff, 6) == 6 and ($buff eq 'QDIOBS' or $buff eq "\0\0SEFT"); my $endPos = $raf->Tell(); @@ -1185,7 +1600,7 @@ SamBlock: # save trailer position and length my $dataPos = $$dirInfo{DataPos} = $dirPos - $firstBlock; my $dirLen = $$dirInfo{DirLen} = $endPos - $dataPos; - if (($verbose or $$et{HTML_DUMP}) and not $outfile) { + if (($verbose or $$et{HTML_DUMP}) and not $outfile and $$dirInfo{RAF}) { $et->DumpTrailer($dirInfo); return 1 if $$et{HTML_DUMP}; } @@ -1305,7 +1720,7 @@ Samsung maker notes in EXIF information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Sanyo.pm b/src/Image-ExifTool/lib/Image/ExifTool/Sanyo.pm index 68fad062..67722f78 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Sanyo.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Sanyo.pm @@ -419,7 +419,7 @@ Sanyo maker notes in EXIF information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Scalado.pm b/src/Image-ExifTool/lib/Image/ExifTool/Scalado.pm index 43583278..333b9639 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Scalado.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Scalado.pm @@ -128,7 +128,7 @@ metadata from the JPEG APP4 SCALADO segment. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Shift.pl b/src/Image-ExifTool/lib/Image/ExifTool/Shift.pl index fc2ccf00..6f761efa 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Shift.pl +++ b/src/Image-ExifTool/lib/Image/ExifTool/Shift.pl @@ -4,13 +4,14 @@ # Description: ExifTool time shifting routines # # Revisions: 10/28/2005 - P. Harvey Created +# 03/13/2019 - PH Added single-argument form of ShiftTime() #------------------------------------------------------------------------------ package Image::ExifTool; use strict; -sub ShiftTime($$;$$); +sub ShiftTime($;$$$); #------------------------------------------------------------------------------ # apply shift to value in new value hash @@ -280,21 +281,31 @@ ($$$;$) # Inputs: 0) date/time string, 1) shift string, 2) shift direction (+1 or -1), # or 0 or undef to take shift direction from sign of shift, # 3) reference to ShiftOffset hash (with Date, DateTime, Time, Timezone keys) +# or 0) shift string (and operates on $_) # Returns: error string or undef on success and date/time string is updated -sub ShiftTime($$;$$) +sub ShiftTime($;$$$) { - local $_; - my ($val, $shift, $dir, $shiftOffset) = @_; + my ($val, $shift, $dir, $shiftOffset); my (@time, @shift, @toTime, $mode, $needShiftOffset, $dec); + + if (@_ == 1) { # single argument form of ShiftTime()? + $val = $_; + $shift = $_[0]; + } else { + ($val, $shift, $dir, $shiftOffset) = @_; + } $dir or $dir = ($shift =~ s/^(\+|-)// and $1 eq '-') ? -1 : 1; # # figure out what we are dealing with (time, date or date/time) # SplitTime($val, \@time) or return "Invalid time string ($val)"; if (defined $time[0]) { + return "Can't shift from year 0000" if $time[0] eq '0000'; $mode = defined $time[3] ? 'DateTime' : 'Date'; } elsif (defined $time[3]) { $mode = 'Time'; + } else { + $mode = ''; } # get number of digits after the seconds decimal point if (defined $time[5] and $time[5] =~ /\.(\d+)/) { @@ -418,7 +429,7 @@ ($$;$$) # # insert shifted time components back into original string # - my ($i, $err); + my $i; for ($i=0; $i<@toTime; ++$i) { next unless defined $time[$i] and defined $toTime[$i]; my ($v, $d, $s); @@ -447,13 +458,15 @@ ($$;$$) my $sig = $len - length $s; my $dec = $d ? length($d) - 1 : 0; my $newNum = sprintf($dec ? "$s%0$sig.${dec}f" : "$s%0${sig}d", $nv); - length($newNum) != $len and $err = 1; substr($val, $pos - $len, $len) = $newNum; - pos($val) = $pos; + pos($val) = $pos + length($newNum) - $len; } - $err and return "Error packing shifted time ($val)"; - $_[0] = $val; # return shifted value - return undef; # success! + if (@_ == 1) { + $_ = $val; # set $_ to the returned value + } else { + $_[0] = $val; # return shifted value + } + return undef; # success! } @@ -494,6 +507,10 @@ =head2 ShiftTime B<ShiftTime>, and used in subsequent calls to shift date/time values by the same relative amount (see L</TRICKY> section below). +or + +0) Shift string (and $_ contains the input date/time string). + =item Return value: Error string, or undef on success and the input date/time string is shifted @@ -615,7 +632,7 @@ =head1 BUGS =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Shortcuts.pm b/src/Image-ExifTool/lib/Image/ExifTool/Shortcuts.pm index b251b864..b0ae8569 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Shortcuts.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Shortcuts.pm @@ -19,7 +19,7 @@ package Image::ExifTool::Shortcuts; use strict; use vars qw($VERSION); -$VERSION = '1.60'; +$VERSION = '1.67'; # this is a special table used to define command-line shortcuts # (documentation Notes may be added for these via %shortcutNotes in BuildTagLookup.pm) @@ -118,6 +118,7 @@ $VERSION = '1.60'; 'MakerNoteCasio', 'MakerNoteCasio2', 'MakerNoteDJI', + 'MakerNoteDJIInfo', 'MakerNoteFLIR', 'MakerNoteFujiFilm', 'MakerNoteGE', @@ -158,6 +159,7 @@ $VERSION = '1.60'; 'MakerNoteNintendo', 'MakerNoteOlympus', 'MakerNoteOlympus2', + 'MakerNoteOlympus3', 'MakerNoteLeica', 'MakerNoteLeica2', 'MakerNoteLeica3', @@ -167,6 +169,7 @@ $VERSION = '1.60'; 'MakerNoteLeica7', 'MakerNoteLeica8', 'MakerNoteLeica9', + 'MakerNoteLeica10', 'MakerNotePanasonic', 'MakerNotePanasonic2', 'MakerNotePanasonic3', @@ -179,8 +182,10 @@ $VERSION = '1.60'; 'MakerNotePhaseOne', 'MakerNoteReconyx', 'MakerNoteReconyx2', + 'MakerNoteReconyx3', 'MakerNoteRicoh', 'MakerNoteRicoh2', + 'MakerNoteRicohPentax', 'MakerNoteRicohText', 'MakerNoteSamsung1a', 'MakerNoteSamsung1b', @@ -262,6 +267,15 @@ $VERSION = '1.60'; 'XMP', 'ZoomedPreviewImage', ], + 'ls-l' => [ + 'FilePermissions', + 'FileHardLinks', + 'FileUserID', + 'FileGroupID', + 'FileSize#', + 'FileModifyDate', + 'FileName', + ], ); #------------------------------------------------------------------------------ @@ -329,7 +343,7 @@ name prefix. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Sigma.pm b/src/Image-ExifTool/lib/Image/ExifTool/Sigma.pm index 68fb70ad..d0a3bf1a 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Sigma.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Sigma.pm @@ -19,7 +19,7 @@ use strict; use vars qw($VERSION %sigmaLensTypes); use Image::ExifTool::Exif; -$VERSION = '1.24'; +$VERSION = '1.31'; # sigma LensType lookup (ref IB) %sigmaLensTypes = ( @@ -88,7 +88,9 @@ $VERSION = '1.24'; 0x256 => 'Sigma 105mm F2.8 EX Macro', 0x257 => 'Sigma 105mm F2.8 EX DG Macro', 0x258 => 'Sigma 105mm F2.8 EX DG OS HSM Macro', + 0x259 => 'Sigma 105mm F1.4 DG HSM | A', #IB (A018) 0x270 => 'Sigma 70mm F2.8 EX DG Macro', #NJ (SD1) + 0x271 => 'Sigma 70mm F2.8 DG Macro | A', #IB (A018) 0x300 => 'Sigma 30mm F1.4 EX DC HSM', 0x301 => 'Sigma 30mm F1.4 DC HSM | A', 0x302 => 'Sigma 30mm F1.4 DC DN | C', #JR (DN lenses are only for Sony E or MFT mount) @@ -116,6 +118,8 @@ $VERSION = '1.24'; 0x484 => 'Sigma 8mm F4 EX DG Circular Fisheye', 0x485 => 'Sigma 8mm F3.5 EX DG Circular Fisheye', 0x486 => 'Sigma 4.5mm F2.8 EX DC HSM Circular Fisheye', + 0x504 => 'Sigma 70-300mm F4-5.6 Macro Super', #IB + 0x505 => 'Sigma APO 70-300mm F4-5.6 Macro Super', #IB 0x506 => 'Sigma 70-300mm F4-5.6 APO Macro Super II', 0x507 => 'Sigma 70-300mm F4-5.6 DL Macro Super II', 0x508 => 'Sigma 70-300mm F4-5.6 DG APO Macro', @@ -128,6 +132,7 @@ $VERSION = '1.24'; 0x521 => 'Sigma 18-50mm F3.5-5.6 DC Macro', 0x527 => 'Sigma 100-300mm F4 EX IF HSM', 0x529 => 'Sigma 120-300mm F2.8 EX HSM IF APO', + 0x545 => 'Sigma 28-70mm F2.8 EX ASP DF', #IB 0x547 => 'Sigma 24-60mm F2.8 EX DG', 0x548 => 'Sigma 24-70mm F2.8 EX DG Macro', 0x549 => 'Sigma 28-70mm F2.8 EX DG', @@ -150,6 +155,7 @@ $VERSION = '1.24'; 0x597 => 'Sigma 200-500mm F2.8 APO EX DG', 0x5A8 => 'Sigma 70-300mm F4-5.6 APO DG Macro (Motorized)', 0x5A9 => 'Sigma 70-300mm F4-5.6 DG Macro (Motorized)', + 0x605 => 'Sigma 24-70mm F3.5-5.6 ASP HF', #IB 0x633 => 'Sigma 28-70mm F2.8-4 HS', 0x634 => 'Sigma 28-70mm F2.8-4 DG', 0x635 => 'Sigma 24-105mm F4 DG OS HSM | A', @@ -175,6 +181,7 @@ $VERSION = '1.24'; 0x727 => 'Sigma 135-400mm F4.5-5.6 DG ASP APO', 0x728 => 'Sigma 120-400mm F4.5-5.6 DG APO OS HSM', 0x729 => 'Sigma 100-400mm F5-6.3 DG OS HSM | C', #JR (017) + 0x730 => 'Sigma 60-600mm F4.5-6.3 DG OS HSM | S', #IB (S018) 0x733 => 'Sigma 170-500mm F5-6.3 ASP APO', 0x734 => 'Sigma 170-500mm F5-6.3 DG ASP APO', 0x735 => 'Sigma 50-500mm F4-6.3 EX RF HSM APO', @@ -185,8 +192,10 @@ $VERSION = '1.24'; 0x745 => 'Sigma 150-600mm F5-6.3 DG OS HSM | C', 0x777 => 'Sigma 18-200mm F3.5-6.3 DC', 0x77D => 'Sigma 18-200mm F3.5-6.3 DC (Motorized)', + 0x785 => 'Sigma 28-200mm F3.5-5.6 DL ASP IF HZM Macro', #IB 0x787 => 'Sigma 28-200mm F3.5-5.6 Compact ASP HZ Macro', 0x789 => 'Sigma 18-125mm F3.5-5.6 DC', + 0x790 => 'Sigma 28-300mm F3.5-6.3 DL ASP IF HZM', #IB 0x793 => 'Sigma 28-300mm F3.5-6.3 Macro', 0x794 => 'Sigma 28-200mm F3.5-5.6 DG Compact ASP HZ Macro', 0x795 => 'Sigma 28-300mm F3.5-6.3 DG Macro', @@ -216,6 +225,12 @@ $VERSION = '1.24'; 0x1007 => 'Sigma 30mm F2.8', #PH (DP2 Quattro kit) 0x1008 => 'Sigma 50mm F2.8 Macro', #NJ (DP3 Quattro kit) 0x1009 => 'Sigma 14mm F4', #NJ (DP0 Quattro kit) + # L-mount lenses?: + 0x6001 => 'Sigma 150-600mm F5-6.3 DG OS HSM | S', #PH (NC, fp) + 0x6003 => 'Sigma 45mm F2.8 DG DN | C', #PH (NC, fp) + 0x6006 => 'Sigma 50mm F1.4 DG HSM | A', #IB (014) + 0x8005 => 'Sigma 35mm F1.4 DG HSM | A', #PH (012) + 0x8009 => 'Sigma 18-35mm F1.8 DC HSM | A', #PH 0x8900 => 'Sigma 70-300mm F4-5.6 DG OS', #PH (SD15) 0xA100 => 'Sigma 24-70mm F2.8 DG Macro', #PH (SD15) # 'FFFF' - seen this for a 28-70mm F2.8 lens - PH @@ -420,13 +435,15 @@ $VERSION = '1.24'; 0x001c => [ #PH { Name => 'PreviewImageSize', - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => q{ PreviewImageStart for the SD1 and Merrill/Quattro models, and PreviewImageSize for others }, Writable => 'int16u', Count => 2, + PrintConv => '$val =~ tr/ /x/; $val', + PrintConvInv => '$val =~ tr/x/ /; $val', },{ Name => 'PreviewImageStart', Condition => '$format eq "int32u"', @@ -441,7 +458,7 @@ $VERSION = '1.24'; 0x001d => [ #PH { Name => 'MakerNoteVersion', - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => q{ PreviewImageLength for the SD1 and Merrill/Quattro models, and MakerNoteVersion for others @@ -460,15 +477,17 @@ $VERSION = '1.24'; # 0x001e - int16u: 0, 4, 13 - flash mode for other models? 0x001e => { #PH Name => 'PreviewImageSize', - Condition => '$$self{Model} =~ /^(SIGMA (DP\d (Merrill|Quattro))|sd Quattro)$/i', + Condition => '$$self{MakerNoteSigmaVer} >= 3', Notes => 'only valid for some models', Writable => 'int16u', Count => 2, + PrintConv => '$val =~ tr/ /x/; $val', + PrintConvInv => '$val =~ tr/x/ /; $val', }, 0x001f => [ #PH { Name => 'AFPoint', # (NC -- invalid for SD9,SD14?) - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => q{ MakerNoteVersion for the SD1 and Merrill/Quattro models, and AFPoint for others @@ -483,38 +502,47 @@ $VERSION = '1.24'; # 0x0021 - string: " " for most models, or int8u[2]: '3 3' for the DP3 Merrill 0x0022 => { #PH (NC) Name => 'FileFormat', - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => 'models other than the SD1 and Merrill/Quattro models', # values: "JPG", "JPG-S", "JPG-P", "X3F", "X3F-S" }, # 0x0023 - string: "", 10, 83, 131, 145, 150, 152, 169 0x0024 => { # (invalid for SD9,SD14?) Name => 'Calibration', - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => 'models other than the SD1 and Merrill/Quattro models', }, # 0x0025 - string: "", "0.70", "0.90" # 0x0026-2b - int32u: 0 0x0026 => { #PH (NC) Name => 'FileFormat', - Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', - Notes => 'SD1 and Merrill/Quattro models only', + Condition => '$$self{MakerNoteSigmaVer} >= 3', + Notes => 'some newer models only', + # (also Sigma fp) }, - 0x0027 => { #PH + 0x0027 => [{ #PH Name => 'LensType', - Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', - Notes => 'SD1 and Merrill/Quattro models only', + Condition => '$$self{MakerNoteSigmaVer} >= 3 and $format eq "string"', + Notes => 'some newer models only', ValueConv => '$val =~ /^[0-9a-f]+$/i ? hex($val) : $val', # (truncate decimal part and convert hex) ValueConvInv => '$val=~s/\.\d+$//;$val=~/^0x/ and $val=hex($val);IsInt($val) ? sprintf("%x",$val) : $val', SeparateTable => 'LensType', PrintHex => 1, PrintConv => \%sigmaLensTypes, - }, + },{ #PH + Name => 'LensType', + Condition => '$$self{MakerNoteSigmaVer} >= 3', + Notes => 'some other models like the fp', + Writable => 'int16u', + SeparateTable => 'LensType', + PrintHex => 1, + PrintConv => \%sigmaLensTypes, + }], 0x002a => { #PH Name => 'LensFocalRange', - Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', - Notes => 'SD1 and Merrill/Quattro models only', + Condition => '$$self{MakerNoteSigmaVer} >= 3', + Notes => 'some newer models only', Writable => 'rational64u', Count => 2, PrintConv => '$val=~s/ / to /; $val', @@ -524,13 +552,14 @@ $VERSION = '1.24'; Name => 'LensMaxApertureRange', # for most models this gives the max aperture at the long/short focal lengths, # but for some models this gives the min/max aperture - Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', - Notes => 'SD1 and Merrill/Quattro models only', + Condition => '$$self{MakerNoteSigmaVer} >= 3', + Notes => 'some newer models only', Writable => 'rational64u', Count => 2, PrintConv => '$val=~s/ / to /; $val', PrintConvInv => '$val=~s/to /; $val', }, + # 0x002c is rational64u for some models, with a value that may be related to FNumber - PH 0x002c => { #PH Name => 'ColorMode', Condition => '$format eq "int32u"', @@ -555,7 +584,7 @@ $VERSION = '1.24'; 0x0030 => [ #PH { Name => 'LensApertureRange', - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => q{ Calibration for the SD1 and Merrill/Quattro models, and LensApertureRange for others. Note that LensApertureRange changes with focal length, and some @@ -567,7 +596,7 @@ $VERSION = '1.24'; ], 0x0031 => { #PH Name => 'FNumber', - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => 'models other than the SD1 and Merrill/Quattro models', Writable => 'rational64u', PrintConv => 'sprintf("%.1f",$val)', @@ -576,7 +605,7 @@ $VERSION = '1.24'; }, 0x0032 => { #PH Name => 'ExposureTime', - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => 'models other than the SD1 and Merrill/Quattro models', Writable => 'rational64u', PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', @@ -585,9 +614,8 @@ $VERSION = '1.24'; }, 0x0033 => { #PH Name => 'ExposureTime2', - Condition => '$$self{Model} !~ / (SD1|SD9|SD15|Merrill|Quattro)$/', + Condition => '$$self{Model} !~ / (SD1|SD9|SD15|Merrill|Quattro|fp)$/', Notes => 'models other than the SD1, SD9, SD15 and Merrill/Quattro models', - Writable => 'string', ValueConv => '$val * 1e-6', ValueConvInv => 'int($val * 1e6 + 0.5)', PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', @@ -595,14 +623,14 @@ $VERSION = '1.24'; }, 0x0034 => { #PH Name => 'BurstShot', - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => 'models other than the SD1 and Merrill/Quattro models', Writable => 'int32u', }, # 0x0034 - int32u: 0,1,2,3 or 4 0x0035 => { #PH Name => 'ExposureCompensation', - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => 'models other than the SD1 and Merrill/Quattro models', Writable => 'rational64s', # add a '+' sign to positive values @@ -613,7 +641,7 @@ $VERSION = '1.24'; # 0x0037-38 - string: "" 0x0039 => { #PH (invalid for SD9, SD14?) Name => 'SensorTemperature', - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => 'models other than the SD1 and Merrill/Quattro models', # (string format) PrintConv => 'IsInt($val) ? "$val C" : $val', @@ -621,19 +649,19 @@ $VERSION = '1.24'; }, 0x003a => { #PH Name => 'FlashExposureComp', - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => 'models other than the SD1 and Merrill/Quattro models', Writable => 'rational64s', }, 0x003b => { #PH (how is this different from other Firmware?) Name => 'Firmware', - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => 'models other than the SD1 and Merrill/Quattro models', Priority => 0, }, 0x003c => { #PH Name => 'WhiteBalance', - Condition => '$$self{Model} !~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', + Condition => '$$self{MakerNoteSigmaVer} < 3', Notes => 'models other than the SD1 and Merrill/Quattro models', Priority => 0, }, @@ -643,13 +671,13 @@ $VERSION = '1.24'; }, 0x0048 => { #PH Name => 'LensApertureRange', - Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', - Notes => 'SD1 and Merrill/Quattro models only', + Condition => '$$self{MakerNoteSigmaVer} >= 3', + Notes => 'some newer models only', }, 0x0049 => { #PH Name => 'FNumber', - Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', - Notes => 'SD1 and Merrill/Quattro models only', + Condition => '$$self{MakerNoteSigmaVer} >= 3', + Notes => 'some newer models only', Writable => 'rational64u', PrintConv => 'sprintf("%.1f",$val)', PrintConvInv => '$val', @@ -657,8 +685,8 @@ $VERSION = '1.24'; }, 0x004a => { #PH Name => 'ExposureTime', - Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', - Notes => 'SD1 and Merrill/Quattro models only', + Condition => '$$self{MakerNoteSigmaVer} >= 3', + Notes => 'some newer models only', Writable => 'rational64u', PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', PrintConvInv => '$val', @@ -667,15 +695,13 @@ $VERSION = '1.24'; 0x004b => [{ #PH Name => 'ExposureTime2', Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d Merrill)$/', - Notes => 'SD1 and Merrill/Quattro models only', - Writable => 'string', + Notes => 'SD1 and DP Merrill models only', PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', PrintConvInv => 'Image::ExifTool::Exif::ConvertFraction($val)', - },{ + },{ #PH Name => 'ExposureTime2', Condition => '$$self{Model} =~ /^SIGMA dp\d Quattro$/i', - Notes => 'SD1 and Merrill/Quattro models only', - Writable => 'string', + Notes => 'DP Quattro models only', ValueConv => '$val / 1000000', ValueConvInv => '$val * 1000000', PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', @@ -683,8 +709,8 @@ $VERSION = '1.24'; }], 0x004d => { #PH Name => 'ExposureCompensation', - Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', - Notes => 'SD1 and Merrill/Quattro models only', + Condition => '$$self{MakerNoteSigmaVer} >= 3', + Notes => 'some newer models only', Writable => 'rational64s', # add a '+' sign to positive values PrintConv => '$val and $val =~ s/^(\d)/\+$1/; $val', @@ -693,45 +719,105 @@ $VERSION = '1.24'; # 0x0054 - string: "F20","F23" 0x0055 => { #PH Name => 'SensorTemperature', - Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', - Notes => 'SD1 and Merrill/Quattro models only', + Condition => '$$self{MakerNoteSigmaVer} >= 3', + Notes => 'some newer models only', # (string format) PrintConv => 'IsInt($val) ? "$val C" : $val', PrintConvInv => '$val=~s/ ?C$//; $val', }, 0x0056 => { #PH (NC) Name => 'FlashExposureComp', - Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', - Notes => 'SD1 and Merrill/Quattro models only', + Condition => '$$self{MakerNoteSigmaVer} >= 3', + Notes => 'some newer models only', Writable => 'rational64s', }, 0x0057 => { #PH (how is this different from other Firmware?) - Name => 'Firmware', - Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', - Notes => 'SD1 and Merrill/Quattro models only', + Name => 'Firmware2', + Condition => '$format eq "string"', + Notes => 'some newer models only', Priority => 0, }, 0x0058 => { #PH Name => 'WhiteBalance', - Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', - Notes => 'SD1 and Merrill/Quattro models only', + Condition => '$$self{MakerNoteSigmaVer} >= 3', + Notes => 'some newer models only', Priority => 0, }, 0x0059 => { #PH Name => 'DigitalFilter', - Condition => '$$self{Model} =~ /^SIGMA (SD1( Merrill)?|DP\d (Merrill|Quattro))$/i', - Notes => 'SD1 and Merrill/Quattro models only', - # seen: Standard, Landscape,Monochrome,Neutral,Portrait,Sepia,Vivid + Condition => '$$self{MakerNoteSigmaVer} >= 3', + Notes => 'some newer models only', + # seen: Standard,Landscape,Monochrome,Neutral,Portrait,Sepia,Vivid }, # 0x005a/b/c - rational64s: 0/10 for the SD1 - 0x0084 => { #PH + 0x0084 => { #PH (Quattro models and fp) Name => 'Model', Description => 'Camera Model Name', - Writable => 'string', }, # 0x0085 + 0x0086 => { #PH (Quattro models) + Name => 'ISO', + Writable => 'int16u', + }, + 0x0087 => 'ResolutionMode', #PH (Quattro models) + 0x0088 => 'WhiteBalance', #PH (Quattro models) + 0x008c => 'Firmware', #PH (Quattro models) + 0x011f => { #IB (FP DNG images) + Name => 'CameraCalibration', + Writable => 'float', + Count => 9, + }, + 0x0120 => { #IB (FP DNG images) + Name => 'WBSettings', + SubDirectory => { TagTable => 'Image::ExifTool::Sigma::WBSettings' }, + }, + 0x0121 => { #IB (FP DNG images) + Name => 'WBSettings2', + SubDirectory => { TagTable => 'Image::ExifTool::Sigma::WBSettings2' }, + }, ); +# WB settings (ref IB) +%Image::ExifTool::Sigma::WBSettings = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + WRITE_PROC => \&Image::ExifTool::WriteBinaryData, + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, + WRITABLE => 1, + FORMAT => 'float', + GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + 0 => { Name => 'WB_RGBLevelsAuto', Format => 'float[3]' }, + 3 => { Name => 'WB_RGBLevelsDaylight', Format => 'float[3]' }, + 6 => { Name => 'WB_RGBLevelsShade', Format => 'float[3]' }, + 9 => { Name => 'WB_RGBLevelsOvercast', Format => 'float[3]' }, + 12 => { Name => 'WB_RGBLevelsIncandescent', Format => 'float[3]' }, + 15 => { Name => 'WB_RGBLevelsFluorescent', Format => 'float[3]' }, + 18 => { Name => 'WB_RGBLevelsFlash', Format => 'float[3]' }, + 21 => { Name => 'WB_RGBLevelsCustom1', Format => 'float[3]' }, + 24 => { Name => 'WB_RGBLevelsCustom2', Format => 'float[3]' }, + 27 => { Name => 'WB_RGBLevelsCustom3', Format => 'float[3]' }, +); + +# WB settings (ref IB) +%Image::ExifTool::Sigma::WBSettings2 = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + WRITE_PROC => \&Image::ExifTool::WriteBinaryData, + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, + WRITABLE => 1, + FORMAT => 'float', + GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + 0 => { Name => 'WB_RGBLevelsUnknown0', Unknown => 1, Format => 'float[3]' }, + 3 => { Name => 'WB_RGBLevelsUnknown1', Unknown => 1, Format => 'float[3]' }, + 6 => { Name => 'WB_RGBLevelsUnknown2', Unknown => 1, Format => 'float[3]' }, + 9 => { Name => 'WB_RGBLevelsUnknown3', Unknown => 1, Format => 'float[3]' }, + 12 => { Name => 'WB_RGBLevelsUnknown4', Unknown => 1, Format => 'float[3]' }, + 15 => { Name => 'WB_RGBLevelsUnknown5', Unknown => 1, Format => 'float[3]' }, + 18 => { Name => 'WB_RGBLevelsUnknown6', Unknown => 1, Format => 'float[3]' }, + 21 => { Name => 'WB_RGBLevelsUnknown7', Unknown => 1, Format => 'float[3]' }, + 24 => { Name => 'WB_RGBLevelsUnknown8', Unknown => 1, Format => 'float[3]' }, + 27 => { Name => 'WB_RGBLevelsUnknown9', Unknown => 1, Format => 'float[3]' }, +); + + 1; # end __END__ @@ -751,7 +837,7 @@ Sigma and Foveon maker notes in EXIF information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/SigmaRaw.pm b/src/Image-ExifTool/lib/Image/ExifTool/SigmaRaw.pm index acecf892..46a694eb 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/SigmaRaw.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/SigmaRaw.pm @@ -16,7 +16,7 @@ use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Sigma; -$VERSION = '1.26'; +$VERSION = '1.27'; sub ProcessX3FHeader($$$); sub ProcessX3FDirectory($$$); @@ -427,36 +427,43 @@ sub WriteX3F($$) $len -= 28; # only rewrite full-sized JpgFromRaw (version 2.0, type 2, format 18) - if ($buff =~ /^SECi\0\0\x02\0\x02\0\0\0\x12\0\0\0/ and - $$et{ImageWidth} == unpack('x16V', $buff)) - { + if ($buff =~ /^SECi\0\0\x02\0\x02\0\0\0\x12\0\0\0/) { $raf->Read($buff, $len) == $len or return 'Error reading JpgFromRaw'; - # use same write directories as JPEG - $et->InitWriteDirs('JPEG'); - # rewrite the embedded JPEG in memory - my $newData; - my %jpegInfo = ( - Parent => 'X3F', - RAF => new File::RandomAccess(\$buff), - OutFile => \$newData, - ); - $$et{FILE_TYPE} = 'JPEG'; - my $success = $et->WriteJPEG(\%jpegInfo); - $$et{FILE_TYPE} = 'X3F'; - SetByteOrder('II'); - return 'Error writing X3F JpgFromRaw' unless $success and $newData; - return -1 if $success < 0; - # write new data if anything changed, otherwise copy old image - my $outPt = $$et{CHANGED} ? \$newData : \$buff; - Write($outfile, $$outPt) or return -1; - # set $len to the total subsection data length - $len = length($$outPt) + 28; - $didContain = 1; + if ($buff =~ /^\xff\xd8\xff\xe1/) { # does this preview contain EXIF? + # use same write directories as JPEG + $et->InitWriteDirs('JPEG'); + # make sure we don't add APP0 JFIF because it would mess up our preview identification + delete $$et{ADD_DIRS}{APP0}; + delete $$et{ADD_DIRS}{JFIF}; + # rewrite the embedded JPEG in memory + my $newData; + my %jpegInfo = ( + Parent => 'X3F', + RAF => new File::RandomAccess(\$buff), + OutFile => \$newData, + ); + $$et{FILE_TYPE} = 'JPEG'; + my $success = $et->WriteJPEG(\%jpegInfo); + $$et{FILE_TYPE} = 'X3F'; + SetByteOrder('II'); + return 'Error writing X3F JpgFromRaw' unless $success and $newData; + return -1 if $success < 0; + # (this shouldn't happen unless someone tries to delete the EXIF...) + return 'EXIF segment must come first in X3F JpgFromRaw' unless $newData =~ /^\xff\xd8\xff\xe1/; + # write new data if anything changed, otherwise copy old image + my $outPt = $$et{CHANGED} ? \$newData : \$buff; + Write($outfile, $$outPt) or return -1; + # set $len to the total subsection data length + $len = length($$outPt); + $didContain = 1; + } else { + Write($outfile, $buff) or return -1; + } } else { # copy original image data Image::ExifTool::CopyBlock($raf, $outfile, $len) or return 'Corrupted X3F image'; - $len += 28; } + $len += 28; # add back header length } else { # copy data for this subsection Image::ExifTool::CopyBlock($raf, $outfile, $len) or return 'Corrupted X3F directory'; @@ -516,16 +523,18 @@ sub ProcessX3FDirectory($$$) $raf->Read($buff, 28) == 28 or return 'Error reading PreviewImage header'; # ignore all image data but JPEG compressed (version 2.0, type 2, format 18) next unless $buff =~ /^SECi\0\0\x02\0\x02\0\0\0\x12\0\0\0/; - # check preview image size and extract full-sized preview as JpgFromRaw - if ($$et{ImageWidth} == unpack('x16V', $buff)) { + $offset += 28; + $len -= 28; + $raf->Read($buff, $len) == $len or return "Error reading PreviewImage data"; + # check fore EXIF segment, and extract this image as the JpgFromRaw + if ($buff =~ /^\xff\xd8\xff\xe1/) { $$et{IsJpgFromRaw} = 1; $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); delete $$et{IsJpgFromRaw}; } - $offset += 28; - $len -= 28; + } else { + $raf->Read($buff, $len) == $len or return "Error reading $$tagInfo{Name} data"; } - $raf->Read($buff, $len) == $len or return "Error reading $$tagInfo{Name} data"; my $subdir = $$tagInfo{SubDirectory}; if ($subdir) { my %dirInfo = ( DataPt => \$buff ); @@ -591,8 +600,6 @@ sub ProcessX3F($$) $buff .= $buf2; } my ($widPos, $hdrType) = $ver < 4 ? (28, 'Header') : (40, 'Header4'); - # extract ImageWidth for later - $$et{ImageWidth} = Get32u(\$buff, $widPos); # process header information my $tagTablePtr = GetTagTable('Image::ExifTool::SigmaRaw::Main'); unless ($outfile) { @@ -643,7 +650,7 @@ Sigma and Foveon X3F images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Sony.pm b/src/Image-ExifTool/lib/Image/ExifTool/Sony.pm index b592e902..523315bc 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Sony.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Sony.pm @@ -22,17 +22,19 @@ # IB) Iliah Borg private communication (LibRaw) # JD) Jens Duttke private communication # JR) Jos Roost private communication +# +# NC = Not Confirmed #------------------------------------------------------------------------------ package Image::ExifTool::Sony; use strict; -use vars qw($VERSION %sonyLensTypes); +use vars qw($VERSION %sonyLensTypes %sonyLensTypes2); use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::Exif; use Image::ExifTool::Minolta; -$VERSION = '2.93'; +$VERSION = '3.52'; sub ProcessSRF($$$); sub ProcessSR2($$$); @@ -52,36 +54,53 @@ sub PrintInvLensSpec($;$$); # Sony E-mount lenses # (NOTE: these should be kept in sync with the 65535 entries in %minoltaLensTypes) -my %sonyLensTypes2 = ( - Notes => 'Lens type numbers for Sony E-mount lenses used by NEX models.', +%sonyLensTypes2 = ( + Notes => 'Lens type numbers for Sony E-mount lenses used by NEX/ILCE models.', 0 => 'Unknown E-mount lens or other lens', + 0.1 => 'Sigma 19mm F2.8 [EX] DN', + 0.2 => 'Sigma 30mm F2.8 [EX] DN', + 0.3 => 'Sigma 60mm F2.8 DN', + 0.4 => 'Sony E 18-200mm F3.5-6.3 OSS LE', # (firmware Ver.01) + 0.5 => 'Tamron 18-200mm F3.5-6.3 Di III VC', # (Model B011) + 0.6 => 'Tokina FiRIN 20mm F2 FE AF', # (firmware Ver.00) samples from Tokina, May 2018 + 0.7 => 'Tokina FiRIN 20mm F2 FE MF', # samples from Tokina, 16-12-2016, DC-watch 01-02-2017 + 0.8 => 'Zeiss Touit 12mm F2.8', # (firmware Ver.00) + 0.9 => 'Zeiss Touit 32mm F1.8', # (firmware Ver.00) + '0.10' => 'Zeiss Touit 50mm F2.8 Macro', # (firmware Ver.00) + '0.11' => 'Zeiss Loxia 50mm F2', # (firmware Ver.01) + '0.12' => 'Zeiss Loxia 35mm F2', # (firmware Ver.01) 1 => 'Sony LA-EA1 or Sigma MC-11 Adapter', # MC-11 with not-supported lenses 2 => 'Sony LA-EA2 Adapter', - 3 => 'Sony LA-EA3 Adapter', #(NC) ILCE-7 image with A-mount lens, but also has 0x940e 2nd byte=2 - 6 => 'Sony LA-EA4 Adapter', #(NC) ILCE-7R image with A-mount lens and having phase-detect info blocks in 0x940e AFInfo - # 27 => Venus Optics Laowa 12mm f2.8 Zero-D or 105mm f2 (T3.2) Smooth Trans Focus (ref IB) + 3 => 'Sony LA-EA3 Adapter', + 6 => 'Sony LA-EA4 Adapter', + 7 => 'Sony LA-EA5 Adapter', #JR + # 27 => Venus Optics Laowa 12mm f2.8 Zero-D or 105mm f2 (T3.2) Smooth Trans Focus (ref IB) 44 => 'Metabones Canon EF Smart Adapter', #JR 78 => 'Metabones Canon EF Smart Adapter Mark III or Other Adapter', #PH/JR (also Mark IV, Fotodiox and Viltrox) + 184 => 'Metabones Canon EF Speed Booster Ultra', #JR ('Green' mode, LensMount reported as A-mount) 234 => 'Metabones Canon EF Smart Adapter Mark IV', #JR (LensMount reported as A-mount) 239 => 'Metabones Canon EF Speed Booster', #JR + 24593 => 'LA-EA4r MonsterAdapter', # Sony VX product code: (http://www.mi-fo.de/forum/index.php?s=7df1c8d3b1cd675f2abf4f4442e19cf2&showtopic=35035&view=findpost&p=303746) 32784 => 'Sony E 16mm F2.8', # VX9100 32785 => 'Sony E 18-55mm F3.5-5.6 OSS', # VX9101 32786 => 'Sony E 55-210mm F4.5-6.3 OSS', # VX9102 32787 => 'Sony E 18-200mm F3.5-6.3 OSS', # VX9103 32788 => 'Sony E 30mm F3.5 Macro', # VX9104 - 32789 => 'Sony E 24mm F1.8 ZA or Samyang AF 50mm F1.4 FE', # VX9105 - 32789.1 => 'Samyang AF 50mm F1.4 FE', - 32790 => 'Sony E 50mm F1.8 OSS or Samyang AF 14mm F2.8 FE', # VX9106 - 32790.1 => 'Samyang AF 14mm F2.8 FE', + 32789 => 'Sony E 24mm F1.8 ZA or Samyang AF 50mm F1.4', # VX9105 + 32789.1 => 'Samyang AF 50mm F1.4', + 32790 => 'Sony E 50mm F1.8 OSS or Samyang AF 14mm F2.8', # VX9106 + 32790.1 => 'Samyang AF 14mm F2.8', 32791 => 'Sony E 16-70mm F4 ZA OSS', # VX9107 32792 => 'Sony E 10-18mm F4 OSS', # VX9108 32793 => 'Sony E PZ 16-50mm F3.5-5.6 OSS', # VX9109 - 32794 => 'Sony FE 35mm F2.8 ZA or Samyang AF 24mm F2.8 FE', # VX9110 - 32794.1 => 'Samyang AF 24mm F2.8 FE', #JR + 32794 => 'Sony FE 35mm F2.8 ZA or Samyang Lens', # VX9110 + 32794.1 => 'Samyang AF 24mm F2.8', #JR + 32794.2 => 'Samyang AF 35mm F2.8', #IB (also 51505) 32795 => 'Sony FE 24-70mm F4 ZA OSS', # VX9111 - 32796 => 'Sony FE 85mm F1.8', #JR - 32797 => 'Sony E 18-200mm F3.5-6.3 OSS LE', # VX9113 + 32796 => 'Sony FE 85mm F1.8 or Viltrox PFU RBMH 85mm F1.8', #JR + 32796.1 => 'Viltrox PFU RBMH 85mm F1.8', #JR (MF) + 32797 => 'Sony E 18-200mm F3.5-6.3 OSS LE', # VX9113 (firmware Ver.02) 32798 => 'Sony E 20mm F2.8', # VX9114 32799 => 'Sony E 35mm F1.8 OSS', # VX9115 32800 => 'Sony E PZ 18-105mm F4 G OSS', #JR # VX9116 @@ -107,7 +126,8 @@ my %sonyLensTypes2 = ( 32820 => 'Sony E PZ 18-110mm F4 G OSS', #JR 32821 => 'Sony FE 24-70mm F2.8 GM', #JR/IB 32822 => 'Sony FE 50mm F1.4 ZA', #JR - 32823 => 'Sony FE 85mm F1.4 GM', #JR/IB + 32823 => 'Sony FE 85mm F1.4 GM or Samyang AF 85mm F1.4', #JR/IB + 32823.1 => 'Samyang AF 85mm F1.4', #IB 32824 => 'Sony FE 50mm F1.8', #JR (Sony code 'SEL50F18F' with trailing "F" as compared to 'SEL50F18' for 32790) 32826 => 'Sony FE 21mm F2.8 (SEL28F20 + SEL075UWC)', #JR # (+ Ultra-wide converter) @@ -118,8 +138,31 @@ my %sonyLensTypes2 = ( 32831 => 'Sony FE 16-35mm F2.8 GM', #JR 32848 => 'Sony FE 400mm F2.8 GM OSS', #IB 32849 => 'Sony E 18-135mm F3.5-5.6 OSS', #JR + 32850 => 'Sony FE 135mm F1.8 GM', #IB + 32851 => 'Sony FE 200-600mm F5.6-6.3 G OSS', #IB + 32852 => 'Sony FE 600mm F4 GM OSS', #IB + 32853 => 'Sony E 16-55mm F2.8 G', #IB/JR + 32854 => 'Sony E 70-350mm F4.5-6.3 G OSS', #IB/JR + 32855 => 'Sony FE C 16-35mm T3.1 G', #JR (SELC1635G) (max aperture is 2.8) + 32858 => 'Sony FE 35mm F1.8', #JR/IB + 32859 => 'Sony FE 20mm F1.8 G', #IB/JR + 32860 => 'Sony FE 12-24mm F2.8 GM', #JR/IB + 32862 => 'Sony FE 50mm F1.2 GM', #IB/JR + 32863 => 'Sony FE 14mm F1.8 GM', #IB + 32864 => 'Sony FE 28-60mm F4-5.6', #JR + 32865 => 'Sony FE 35mm F1.4 GM', #IB/JR + 32866 => 'Sony FE 24mm F2.8 G', #IB + 32867 => 'Sony FE 40mm F2.5 G', #IB + 32868 => 'Sony FE 50mm F2.5 G', #IB + 32871 => 'Sony FE PZ 16-35mm F4 G', #JR + 32873 => 'Sony E PZ 10-20mm F4 G', #JR + 32874 => 'Sony FE 70-200mm F2.8 GM OSS II', #IB + 32875 => 'Sony FE 24-70mm F2.8 GM II', #JR + 32876 => 'Sony E 11mm F1.8', #JR + 32877 => 'Sony E 15mm F1.4 G', #JR # (comment this out so LensID will report the LensModel, which is more useful) + # 32952 => 'Metabones Canon EF Speed Booster Ultra', #JR (corresponds to 184, but 'Advanced' mode, LensMount reported as E-mount) # 33002 => 'Metabones Canon EF Smart Adapter with Ver.5x', #PH/JR (corresponds to 234, but LensMount reported as E-mount) 33072 => 'Sony FE 70-200mm F2.8 GM OSS + 1.4X Teleconverter', #JR @@ -129,6 +172,10 @@ my %sonyLensTypes2 = ( 33078 => 'Sony FE 100-400mm F4.5-5.6 GM OSS + 2X Teleconverter', #JR 33079 => 'Sony FE 400mm F2.8 GM OSS + 1.4X Teleconverter', #IB 33080 => 'Sony FE 400mm F2.8 GM OSS + 2X Teleconverter', #JR + 33081 => 'Sony FE 200-600mm F5.6-6.3 G OSS + 1.4X Teleconverter', #JR + 33082 => 'Sony FE 200-600mm F5.6-6.3 G OSS + 2X Teleconverter', #JR + 33083 => 'Sony FE 600mm F4 GM OSS + 1.4X Teleconverter', #JR (NC) + 33084 => 'Sony FE 600mm F4 GM OSS + 2X Teleconverter', #JR 49201 => 'Zeiss Touit 12mm F2.8', #JR (lens firmware Ver.02) 49202 => 'Zeiss Touit 32mm F1.8', #JR (lens firmware Ver.02) @@ -145,15 +192,36 @@ my %sonyLensTypes2 = ( 49236 => 'Zeiss Loxia 25mm F2.4', #JR 49457 => 'Tamron 28-75mm F2.8 Di III RXD', #JR (Model A036) + 49458 => 'Tamron 17-28mm F2.8 Di III RXD', #JR (Model A046) + 49459 => 'Tamron 35mm F2.8 Di III OSD M1:2', #IB (Model F053) + 49460 => 'Tamron 24mm F2.8 Di III OSD M1:2', #JR (Model F051) + 49461 => 'Tamron 20mm F2.8 Di III OSD M1:2', #JR (Model F050) + 49462 => 'Tamron 70-180mm F2.8 Di III VXD', #JR (Model A056) + 49463 => 'Tamron 28-200mm F2.8-5.6 Di III RXD', #JR (Model A071) + 49464 => 'Tamron 70-300mm F4.5-6.3 Di III RXD', #JR (Model A047) + 49465 => 'Tamron 17-70mm F2.8 Di III-A VC RXD', #JR (Model B070) + 49466 => 'Tamron 150-500mm F5-6.7 Di III VC VXD', #JR (Model A057) + 49467 => 'Tamron 11-20mm F2.8 Di III-A RXD', #JR (Model B060) + 49468 => 'Tamron 18-300mm F3.5-6.3 Di III-A VC VXD', #JR (Model B061) + 49469 => 'Tamron 35-150mm F2-F2.8 Di III VXD', #JR (Model A058) + 49470 => 'Tamron 28-75mm F2.8 Di III VXD G2', #JR (Model A063) + 49471 => 'Tamron 50-400mm F4.5-6.3 Di III VC VXD', #JR (Model A067) + + 49473 => 'Tokina atx-m 85mm F1.8 FE or Viltrox lens', #JR + 49473.1 => 'Viltrox 23mm F1.4 E', #JR + 49473.2 => 'Viltrox 56mm F1.4 E', #JR + 49712 => 'Tokina FiRIN 20mm F2 FE AF', # (firmware Ver.01) + 49713 => 'Tokina FiRIN 100mm F2.8 FE MACRO', # (firmware Ver.01) 50480 => 'Sigma 30mm F1.4 DC DN | C', #IB/JR (016) - 50481 => 'Sigma 50mm F1.4 DG HSM | A + MC-11', #JR (014) + 50481 => 'Sigma 50mm F1.4 DG HSM | A', #JR (014 + MC-11 or 018) 50482 => 'Sigma 18-300mm F3.5-6.3 DC MACRO OS HSM | C + MC-11', #JR (014) 50483 => 'Sigma 18-35mm F1.8 DC HSM | A + MC-11', #JR (013) 50484 => 'Sigma 24-35mm F2 DG HSM | A + MC-11', #JR (015) + 50485 => 'Sigma 24mm F1.4 DG HSM | A + MC-11', #JR (015) 50486 => 'Sigma 150-600mm F5-6.3 DG OS HSM | C + MC-11', #JR (015) 50487 => 'Sigma 20mm F1.4 DG HSM | A + MC-11', #JR (015) - 50488 => 'Sigma 35mm F1.4 DG HSM | A + MC-11', #JR (012) + 50488 => 'Sigma 35mm F1.4 DG HSM | A', #JR (012 + MC-11 or 018) 50489 => 'Sigma 150-600mm F5-6.3 DG OS HSM | S + MC-11', #JR (014) 50490 => 'Sigma 120-300mm F2.8 DG OS HSM | S + MC-11', #JR (013) 50492 => 'Sigma 24-105mm F4 DG OS HSM | A + MC-11', #JR (013) @@ -162,7 +230,28 @@ my %sonyLensTypes2 = ( 50499 => 'Sigma 85mm F1.4 DG HSM | A', #JR (018) 50501 => 'Sigma 100-400mm F5-6.3 DG OS HSM | C + MC-11', #JR (017) 50503 => 'Sigma 16mm F1.4 DC DN | C', #JR (017) + 50507 => 'Sigma 105mm F1.4 DG HSM | A', #IB (018) + 50508 => 'Sigma 56mm F1.4 DC DN | C', #JR (018) + 50512 => 'Sigma 70-200mm F2.8 DG OS HSM | S + MC-11', #IB (018) (JR added "+ MC-11") 50513 => 'Sigma 70mm F2.8 DG MACRO | A', #JR (018) + 50514 => 'Sigma 45mm F2.8 DG DN | C', #IB/JR (019) + 50515 => 'Sigma 35mm F1.2 DG DN | A', #IB/JR (019) + 50516 => 'Sigma 14-24mm F2.8 DG DN | A', #IB/JR (019) + 50517 => 'Sigma 24-70mm F2.8 DG DN | A', #JR (019) + 50518 => 'Sigma 100-400mm F5-6.3 DG DN OS | C', #JR (020) + 50521 => 'Sigma 85mm F1.4 DG DN | A', #JR (020) + 50522 => 'Sigma 105mm F2.8 DG DN MACRO | A', #JR (020) + 50523 => 'Sigma 65mm F2 DG DN | C', #IB (020) + 50524 => 'Sigma 35mm F2 DG DN | C', #IB (020) + 50525 => 'Sigma 24mm F3.5 DG DN | C', #JR (021) + 50526 => 'Sigma 28-70mm F2.8 DG DN | C', #JR (021) + 50527 => 'Sigma 150-600mm F5-6.3 DG DN OS | S', #JR (021) + 50528 => 'Sigma 35mm F1.4 DG DN | A', #IB/JR (021) + 50529 => 'Sigma 90mm F2.8 DG DN | C', #JR (021) + 50530 => 'Sigma 24mm F2 DG DN | C', #JR (021) + 50531 => 'Sigma 18-50mm F2.8 DC DN | C', #IB/JR (021) + 50532 => 'Sigma 20mm F2 DG DN | C', #JR (022) + 50533 => 'Sigma 16-28mm F2.8 DG DN | C', #JR (022) 50992 => 'Voigtlander SUPER WIDE-HELIAR 15mm F4.5 III', #JR 50993 => 'Voigtlander HELIAR-HYPER WIDE 10mm F5.6', #IB @@ -170,15 +259,34 @@ my %sonyLensTypes2 = ( 50995 => 'Voigtlander MACRO APO-LANTHAR 65mm F2 Aspherical', #JR 50996 => 'Voigtlander NOKTON 40mm F1.2 Aspherical', #JR 50997 => 'Voigtlander NOKTON classic 35mm F1.4', #JR + 50998 => 'Voigtlander MACRO APO-LANTHAR 110mm F2.5', #JR + 50999 => 'Voigtlander COLOR-SKOPAR 21mm F3.5 Aspherical', #IB + 51000 => 'Voigtlander NOKTON 50mm F1.2 Aspherical', #JR + 51001 => 'Voigtlander NOKTON 21mm F1.4 Aspherical', #JR + 51002 => 'Voigtlander APO-LANTHAR 50mm F2 Aspherical', #JR + 51003 => 'Voigtlander NOKTON 35mm F1.2 Aspherical SE', #JR + 51006 => 'Voigtlander APO-LANTHAR 35mm F2 Aspherical', #JR # lenses listed in the Sigma MC-11 list, but not yet seen: # 504xx => 'Sigma 18-200mm F3.5-6.3 DC MACRO OS HSM | C + MC-11', # (014) - # 504xx => 'Sigma 24mm F1.4 DG HSM | A + MC-11', # (015) # 504xx => 'Sigma 30mm F1.4 DC HSM | A + MC-11', # (013) - 51505 => 'Samyang AF 14mm F2.8 FE or Samyang AF 35mm F2.8 FE', #forum3833 - 51505.1 => 'Samyang AF 35mm F2.8 FE', #PH + # Note: For Samyang lenses, the "FE" designation isn't written to + # EXIF:LensModel, so it isn't included in these strings either - JR/PH + 51504 => 'Samyang AF 50mm F1.4', #IB + 51505 => 'Samyang AF 14mm F2.8 or Samyang AF 35mm F2.8', #forum3833 + 51505.1 => 'Samyang AF 35mm F2.8', #PH (also 32794) 51507 => 'Samyang AF 35mm F1.4', #IB + 51508 => 'Samyang AF 45mm F1.8', + 51510 => 'Samyang AF 18mm F2.8 or Samyang AF 35mm F1.8', #JR + 51510.1 => 'Samyang AF 35mm F1.8', #JR + 51512 => 'Samyang AF 75mm F1.8', #IB/JR + 51513 => 'Samyang AF 35mm F1.8', #JR + 51514 => 'Samyang AF 24mm F1.8', #IB + 51515 => 'Samyang AF 12mm F2.0', #JR + 51516 => 'Samyang AF 24-70mm F2.8', #JR + 51517 => 'Samyang AF 50mm F1.4 II', #JR + 51518 => 'Samyang AF 135mm F1.8', #JR ); # ExposureProgram values (ref PH, mainly decoded from A200) @@ -553,9 +661,10 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); 3 => 'Standard', 4 => 'Economy', 5 => 'Extra Fine', - 6 => 'RAW + JPEG', + 6 => 'RAW + JPEG/HEIF', 7 => 'Compressed RAW', 8 => 'Compressed RAW + JPEG', + 9 => 'Light', #JR 0xffffffff => 'n/a', #PH (SLT-A57 panorama) }, }, @@ -897,8 +1006,9 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # unknown offsets or values for DSC-TX20/TX55/WX30 # unknown offsets or values for DSC-HX60V/HX350/HX400V/QX10/QX30/QX100/RX10/RX100M2/RX100M3/WX220/WX350, # ILCA-68/77M2, ILCE-5000/5100/6000/7/7M2/7R/7S/QX1, Stellar2, Lusso - # unknown offsets or values for DSC-HX90V/RX0/RX1RM2/RX10M2/RX10M3/RX100M4/RX100M5/WX500, ILCE-6300/6500/7RM2/7SM2, ILCA-99M2 - # unknown offsets or values for ILCE-7M3/7RM3/9, DSC-RX10M4/RX100M6/RX100M5A + # unknown offsets or values for DSC-HX80/HX90V/RX0/RX1RM2/RX10M2/RX10M3/RX100M4/RX100M5/WX500, ILCE-6300/6500/7RM2/7SM2, ILCA-99M2 + # unknown offsets or values for ILCE-6100/6400/6600/7C/7M3/7RM3/7RM4/9/9M2, DSC-RX0M2/RX10M4/RX100M6/RX100M5A/RX100M7/HX99 + # July 2020: ILCE-7SM3 doesn't write this tag anymore { Name => 'Tag2010a', # ad Condition => '$$self{Model} =~ /^NEX-5N$/', @@ -935,11 +1045,11 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag2010g' }, },{ Name => 'Tag2010h', # ? - Condition => '$$self{Model} =~ /^(DSC-(RX0|RX1RM2|RX10M2|RX10M3|RX100M4|RX100M5|HX90V?|WX500)|ILCE-(6300|6500|7RM2|7SM2)|ILCA-99M2)\b/', + Condition => '$$self{Model} =~ /^(DSC-(RX0|RX1RM2|RX10M2|RX10M3|RX100M4|RX100M5|HX80|HX90V?|WX500)|ILCE-(6300|6500|7RM2|7SM2)|ILCA-99M2)\b/', SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag2010h' }, },{ Name => 'Tag2010i', # ? - Condition => '$$self{Model} =~ /^(ILCE-(7M3|7RM3|9)|DSC-(RX10M4|RX100M6|RX100M5A))\b/', + Condition => '$$self{Model} =~ /^(ILCE-(6100|6400|6600|7C|7M3|7RM3A?|7RM4A?|9|9M2)|DSC-(RX10M4|RX100M6|RX100M5A|RX100M7|HX99|RX0M2)|ZV-(1|E10))\b/', SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag2010i' }, },{ Name => 'Tag_0x2010', @@ -997,6 +1107,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); 1 => 'Flash Fired', 2 => 'External Flash Fired', 3 => 'Wireless Controlled Flash Fired', # (NC) seen for ILCE-9 and ILCE-7M3 images + # 5 => 'External Flash ???', # seen for ILCE-7RM4 }, }, # 0x2018 - something with external flash: seen 1 only when 0x2017 = 2 @@ -1014,7 +1125,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # FocusMode for SLT/HV/ILCA and NEX/ILCE; doesn't seem to apply to DSC models (always 0) # from 2018: at least DSC-RX10M4 and RX100M6 also use this tag Name => 'FocusMode', - Condition => '($$self{Model} !~ /^DSC-/) or ($$self{Model} =~ /^DSC-(RX10M4|RX100M6|RX100M5A)/)', + Condition => '($$self{Model} !~ /^DSC-/) or ($$self{Model} =~ /^DSC-(RX10M4|RX100M6|RX100M7|RX100M5A|HX99|RX0M2)/)', Writable => 'int8u', Priority => 0, PrintConv => { @@ -1046,7 +1157,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); }, },{ Name => 'AFAreaModeSetting', - Condition => '$$self{Model} =~ /^(NEX-|ILCE-|DSC-(RX10M4|RX100M6|RX100M5A))/', + Condition => '$$self{Model} =~ /^(NEX-|ILCE-|ILME-|DSC-(RX10M4|RX100M6|RX100M7|RX100M5A|HX99|RX0M2))/', Notes => 'NEX, ILCE and some DSC models', RawConv => '$$self{AFAreaILCE} = $val', DataMember => 'AFAreaILCE', @@ -1082,7 +1193,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # observed values in range (0 0) to (640 480), with center (320 240) often seen # for NEX-5R/6, positions appear to be in an 11x9 grid Name => 'FlexibleSpotPosition', - Condition => '$$self{Model} =~ /^(NEX-|ILCE-|DSC-(RX10M4|RX100M6|RX100M5A))/', + Condition => '$$self{Model} =~ /^(NEX-|ILCE-|ILME-|DSC-(RX10M4|RX100M6|RX100M7|RX100M5A|HX99|RX0M2))/', Writable => 'int16u', Count => 2, Notes => q{ @@ -1097,7 +1208,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # doesn't seem to apply to DSC models (always 0) Name => 'AFPointSelected', Condition => q{ - ($$self{Model} =~ /^(SLT-|HV)/) or ($$self{Model} =~ /^ILCE-/ and + ($$self{Model} =~ /^(SLT-|HV)/) or ($$self{Model} =~ /^(ILCE-|ILME-)/ and defined $$self{AFAreaILCE} and $$self{AFAreaILCE} == 4) }, Notes => 'SLT models or ILCE with LA-EA2/EA4', @@ -1175,7 +1286,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); Name => 'AFPointSelected', # non-zero only when AFAreaMode is 'Zone', and 'Expanded-Flexible-Spot' for ILCE-6300/7RM2/7SM2 # each Zone has 3x3 AF Areas --> 9 positions within 5x5 total Contrast AF Areas - Condition => '$$self{Model} =~ /^(NEX-|ILCE-)/', + Condition => '$$self{Model} =~ /^(NEX-|ILCE-|ILME-)/', Notes => 'NEX and ILCE models', Writable => 'int8u', PrintConv => { @@ -1242,7 +1353,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # from 2018: at least DSC-RX10M4 and RX100M6 also use this tag 0x2021 => { #JR Name => 'AFTracking', - Condition => '($$self{Model} !~ /^DSC-/) or ($$self{Model} =~ /^DSC-(RX10M4|RX100M6|RX100M5A)/)', + Condition => '($$self{Model} !~ /^DSC-/) or ($$self{Model} =~ /^DSC-(RX10M4|RX100M6|RX100M7|RX100M5A|HX99|RX0M2)/)', Writable => 'int8u', PrintConv => { 0 => 'Off', @@ -1323,6 +1434,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); '1 0' => 'Off', '1 1' => 'Standard', '1 2' => 'High', + '65535 65535' => 'n/a', # ILCE-7SM3 }, }, 0x2029 => { # uncompressed 14-bit RAW file type setting introduced 2015 @@ -1331,6 +1443,8 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); PrintConv => { 0 => 'Compressed RAW', 1 => 'Uncompressed RAW', + 2 => 'Lossless Compressed RAW', #JR (NC) seen for ILCE-1 + 65535 => 'n/a', # seen for ILCE-7SM3 JPEG-only }, }, # 0x202a - first seen for ILCE-6300: 66 bytes @@ -1366,7 +1480,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); }, }, 0x202d => { #JR first seen for ILCA-99M2, ILCE-6500, DSC-RX100M5 - Name => 'ExposureStandardAdjustment', # (NC) + Name => 'ExposureStandardAdjustment', Writable => 'rational64s', PrintConv => '$val ? sprintf("%+.1f",$val) : 0', PrintConvInv => '$val', @@ -1377,13 +1491,15 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); Count => 2, PrintConv => { '0 0' => 'n/a', - '0 1' => 'Standard JPEG', - '0 2' => 'Fine JPEG', - '0 3' => 'Extra Fine JPEG', + '0 1' => 'Standard', + '0 2' => 'Fine', + '0 3' => 'Extra Fine', + '0 4' => 'Light', #JR '1 0' => 'RAW', - '1 1' => 'RAW + Standard JPEG', - '1 2' => 'RAW + Fine JPEG', - '1 3' => 'RAW + Extra Fine JPEG', + '1 1' => 'RAW + Standard', + '1 2' => 'RAW + Fine', + '1 3' => 'RAW + Extra Fine', + '1 4' => 'RAW + Light', #JR }, }, 0x202f => { #JR (ILCE-7RM3) @@ -1393,8 +1509,9 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # first 4 bytes: GroupID, read as int32u # the ID displayed by Sony ImageDataConverter appears to be based on the lower 22 bits: # 5 bits, 5 bits, 6 bits, 6 bits - # last 2 bytes: ShotNumber: (1 4) to (4 4) are the 4 source images, - # (0 4) is combined "PixelShifted" image + # last 2 bytes: ShotNumber: (1 4) to (4 4) and (1 16) to (16 16) are the 4 or 16 source images, + # (0 4) is the combined image for 4-shot PixelShift mode + # (0 16) is the combined image for 16-shot PixelShift mode (ILCE-7RM4) RawConv => q{ my ($a,$b,$c) = (Get32u(\$val,0), Get8u(\$val,4), Get8u(\$val,5)); sprintf("%.2d%.2d%.2d%.2d %d %d 0x%x",($a>>17)&0x1f,($a>>12)&0x1f,($a>>6)&0x3f,$a&0x3f,$b,$c,$a>>22); @@ -1403,31 +1520,83 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); my ($a,$b,$c,$d) = split ' ', $val; my @a = $a =~ /../g; return undef unless @a == 4; - return Set32u((hex($d)<<22) | ($a[0]<<17) | ($a[1]<<12) | ($a[2]<<6) | $a[3]) . chr($b) . chr($c); + return Set32u((hex($d)<<22) | ($a[0]<<17) | ($a[1]<<12) | ($a[2]<<6) | $a[3]) . chr($b & 0xff) . chr($c & 0xff); }, PrintConv => { '00000000 0 0 0x0' => 'n/a', OTHER => sub { my ($val, $inv) = @_; if ($inv) { - $val =~ s{Composed}{Shot 0/4}i; + $val =~ s{Composed (\d+)-shot}{Shot 0/$1}i; $val =~ s{^(?:Group)?\s*(\d+)[, ]+(?:Shot\s*)?(\d+)[/ ](\d+)\s*\(?(\w+)\)?}{$1 $2 $3 $4}i or return undef; } else { $val =~ s{(\d+) (\d+) (\d+) (\w+)}{Group $1, Shot $2/$3 ($4)} or return undef; - $val =~ s{Shot\s*0+/0*4\b}{Composed}i; + $val =~ s{Shot 0+/0*(\d+)\b}{Composed $1-shot}i; } return $val; }, }, }, - 0x2031 => { #JR (new for ILCE-9 v2.00) + 0x2031 => { #JR (only for ILCE-9 v2.00; ILCE-9 v2.10 and higher have "option" to write into EXIF tag 0xa431 ) Name => 'SerialNumber', Writable => 'string', - ValueConv => '$val=~s/(\d{2})(\d{2})(\d{2})(\d{2})/$4$3$2$1/; $val=~s/^0//; $val', # (NC) + ValueConv => '$val=~s/(\d{2})(\d{2})(\d{2})(\d{2})/$4$3$2$1/; $val=~s/^0//; $val', ValueConvInv => '$val="0$val" if length($val)==7; $val=~s/(\d{2})(\d{2})(\d{2})(\d{2})/$4$3$2$1/; $val', PrintConv => 'sprintf("%.8d",$val)', PrintConvInv => '$val', }, +# 0x2032 - 0x2039: from July 2020 for ILCE-7SM3, ILCE-1, ILME-FX3 and newer + 0x2032 => { + Name => 'Shadows', + Writable => 'int32s', + PrintConv => '$val > 0 ? "+$val" : $val', + PrintConvInv => '$val', + }, + 0x2033 => { + Name => 'Highlights', + Writable => 'int32s', + PrintConv => '$val > 0 ? "+$val" : $val', + PrintConvInv => '$val', + }, + 0x2034 => { + Name => 'Fade', + Writable => 'int32s', + PrintConv => '$val > 0 ? "+$val" : $val', + PrintConvInv => '$val', + }, + 0x2035 => { + Name => 'SharpnessRange', + Writable => 'int32s', + PrintConv => '$val > 0 ? "+$val" : $val', + PrintConvInv => '$val', + }, + 0x2036 => { + Name => 'Clarity', + Writable => 'int32s', + PrintConv => '$val > 0 ? "+$val" : $val', + PrintConvInv => '$val', + }, + 0x2037 => { + Name => 'FocusFrameSize', + Format => 'int16u', + Count => '3', + Notes => 'width and height of FocusFrame, centered on FocusLocation', + PrintConv => q{ + my @a = split ' ', $val; + return $a[2] ? sprintf('%3dx%3d', $a[0], $a[1]) : 'n/a'; + }, + PrintConvInv => '$val =~ /(\d+)x(\d+)/ ? "$1 $2 257" : "0 0 0"', + }, + 0x2039 => { #JR + Name => 'JPEG-HEIFSwitch', # (name used in camera menus) + Writable => 'int16u', + PrintConv => { + 0 => 'JPEG', + 1 => 'HEIF', + 65535 => 'n/a', + }, + }, +# 0x203a - 0x2041: first seen October 2021 for ILCE-7M4 0x3000 => { Name => 'ShotInfo', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ShotInfo' }, @@ -1456,18 +1625,25 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # from mid-2015: ILCE-7RM2/7SM2/6300 and newer models use different offsets { Name => 'Tag9050a', - Condition => '$$self{Model} !~ /^(DSC-|Stellar|ILCE-(6300|6500|7M3|7RM2|7RM3|7SM2|9)|ILCA-99M2)/', + Condition => '$$self{Model} !~ /^(DSC-|Stellar|ILCE-(1|6100|6300|6400|6500|6600|7C|7M3|7M4|7RM2|7RM3A?|7RM4A?|7SM2|7SM3|9|9M2)|ILCA-99M2|ILME-FX3|ZV-)/', SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag9050a', ByteOrder => 'LittleEndian', }, },{ Name => 'Tag9050b', - Condition => '$$self{Model} =~ /^(ILCE-(6300|6500|7M3|7RM2|7RM3|7SM2|9)|ILCA-99M2)/', + Condition => '$$self{Model} =~ /^(ILCE-(6100|6300|6400|6500|6600|7C|7M3|7RM2|7RM3A?|7RM4A?|7SM2|9|9M2)|ILCA-99M2|ZV-E10)/', SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag9050b', ByteOrder => 'LittleEndian', }, + },{ + Name => 'Tag9050c', + Condition => '$$self{Model} =~ /^(ILCE-(1|7M4|7SM3)|ILME-FX3)/', + SubDirectory => { + TagTable => 'Image::ExifTool::Sony::Tag9050c', + ByteOrder => 'LittleEndian', + }, },{ Name => 'Sony_0x9050', %unknownCipherData, @@ -1480,9 +1656,11 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # 0x0c (e) for ILCE-3000/3500, NEX-3N, SLT-A58, DSC-HX50V/HX300/RX100M2/TX30/WX60/WX80/WX200/WX300, DSC-QX10/QX100 # 0xd0 (e) H90, W650, W690: tag9400 decoding appears not valid/different # 0x23 (e) for DSC-RX10/HX60V/HX350/HX400V/WX220/WX350, ILCE-7/7R/5000/6000, ILCA-68/77M2 - # 0x24 (e) for ILCA-99M2,ILCE-5100/6300/6500/7M2/7RM2/7S/7SM2/QX1, DSC-HX90V/QX30/RX0/RX100M3/RX100M4/RX100M5/RX10M2/RX10M3/RX1RM2/WX500 - # 0x26 (e) for ILCE-7M3/7RM3/9, DSC-RX10M4/RX100M6 - # first byte decoded: 40, 204, 202, 27, 58, 62, 48, 215 respectively + # 0x24 (e) for ILCA-99M2,ILCE-5100/6300/6500/7M2/7RM2/7S/7SM2/QX1, DSC-HX80/HX90V/QX30/RX0/RX100M3/RX100M4/RX100M5/RX10M2/RX10M3/RX1RM2/WX500 + # 0x26 (e) for ILCE-6100/6400/6600/7M3/7RM3/9, DSC-RX0M2/RX10M4/RX100M5A/RX100M6/HX99 + # 0x28 (e) for ILCE-7RM4/9M2, DSC-RX100M7, ZV-1/E10 + # 0x31 (e) for ILCE-1/7SM3, ILME-FX3 + # first byte decoded: 40, 204, 202, 27, 58, 62, 48, 215, 28, 106 respectively { Name => 'Tag9400a', Condition => q{ @@ -1496,15 +1674,15 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag9400b' }, },{ Name => 'Tag9400c', - Condition => '$$valPt =~ /^[\x23\x24\x26]/', + Condition => '$$valPt =~ /^[\x23\x24\x26\x28\x31]/', SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag9400c' }, },{ Name => 'Sony_0x9400', %unknownCipherData, }], 0x9401 => { - Name => 'Sony_0x9401', - %unknownCipherData, + Name => 'Tag9401', + SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag9401' }, # notes for data in this block (ref PH/JR): # 0x02-0x03 appear to have some relation to start-offset of data... # 0x00 - 0x03 Metering @@ -1527,7 +1705,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # 33 41 0d 0e 0x09d7 (k) DSC-RX1, DSC-RX1R # 38 00 32 0e 0x09fc (l) SLT-A58, ILCE-3000/3500, NEX-3N, DSC-HX300/HX50V/WX200/WX300/WX60/WX80/TX30 # 3a 10 3a 0e 0x0a01 (m) DSC-QX10/QX100 - # 3a 20 47 0e 0x0a01 (m) DSC-RX100M2, + # 3a 20 47 0e 0x0a01 (m) DSC-RX100M2 # 43 00 66 0e 0x0a1b (n) ILCE-7/7R v0.xx/v1.00/v1.01, ILCE-5000, DSC-RX10 # 43 10 66 0e 0x0a1b (n) ILCE-7/7R v1.02/v1.10 # 43 30 6c 0e 0x0a1b (n) ILCE-7/7R v1.20-v3.20 @@ -1536,10 +1714,10 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # 44 20 a2 0e 0x0a39 (o) ILCE-6000 v2.00-v3.20 # 49 00 b0 0e 0x0a3b (p) ILCA-68 v1.00, ILCA-77M2 V1.00/v1.01/v2.00 (also DSC-RX100M3 samples from sony.net) # 4a 00 b3 0e 0x0a3d (q) ILCE-7S v1.00, ILCE-5100 v1.00/v1.10, ILCE-QX1, DSC-QX30/RX100M3 - # 4a 20 b9 0e 0x0a3d (q) ILCE-7S v1.20-v3.10 + # 4a 20 b9 0e 0x0a3d (q) ILCE-7S v1.20-v3.20 # 4e 10 d0 0e 0x0a5a (r) ILCE-7M2 v1.00/v1.10 # 4e 30 d6 0e 0x0a5a (r) ILCE-7M2 v1.20-v4.00 - # 5a 00 14 0f 0x0a85 (s) DSC-HX90V/WX500 + # 5a 00 14 0f 0x0a85 (s) DSC-HX80/HX90V/WX500 # 5d 00 56 0f 0x0ac7 (t) DSC-RX10M2/RX100M4, ILCE-7RM2/7SM2 v1.00-v2.20 (also DSC-RX1RM2 samples from Sony) # 5d 1d 58 0f 0x0ac7 (t) ILCE-7RM2 v3.00-v4.00 # 5d 1e 57 0f 0x0ac7 (t) DSC-RX1RM2 v1.00 @@ -1547,10 +1725,17 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # 5d 20 58 0f 0x0ac7 (t) ILCE-6300 v1.00/v1.10 # 5e 00 56 0f 0x0ac7 (t) DSC-RX10M3 v1.00 # 64 00 a8 0f 0x0b15 (u) DSC-RX100M5 v1.00 - # 67 00 f9 0f 0x0b66 (v) ILCA-99M2 v1.00, ILCE-6500 v1.00/v1.03, DSC-RX0 v1.00 - # 7c 00 fe 0f 0x0adb (w) ILCE-9 v0.01/v1.00/v1.01/v1.10/v2.00 + # 67 00 f9 0f 0x0b66 (v) ILCA-99M2 v1.00, ILCE-6500 v1.00-v1.05, DSC-RX0 v1.00 + # 7c 00 fe 0f 0x0adb (w) ILCE-9 v0.01-v2.00 + # 7d 00 fe 0f 0x0adb (w) ILCE-9 v2.10-v4.10 # 7f 00 fa 0f 0x0add (x) DSC-RX10M4 v1.00 - # 80 00 fa 0f 0x0add (x) ILCE-7M3 v1.00, ILCE-7RM3 v0.01/v1.00/v1.01 + # 80 00 fa 0f 0x0add (x) ILCE-7M3/7RM3 v1.00-v3.01 + # 82 00 fc 0f 0x0ad9 (y) DSC-RX100M5A v1.00, DSC-RX100M6 v1.00 + # 90 00 fe 0f 0x098f? (z) DSC-HX99 v1.00 + # 92 10 ff 0f 0x0990 (za) ILCE-6100/6400/6600 v1.00 + # 94 00 ce 0b 0x0879 (zb) ILCE-9 v5.00-v6.00, DSC-RX0M2 + # 98 00 db 0c 0x088a (zc) ILCE-7RM4 v1.00 + # 9a 00 e3 0c 0x088a (zc) DSC-RX100M7 v1.00, ILCE-9M2 v1.00 # # 0x0004 - (RX100: 0 or 1. subsequent data valid only if 1 - PH) # 0x0007 => { @@ -1583,11 +1768,13 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # 0x15 0x01 for a few ILCE-7/7R ... # 0x14 0x01 ILCE-6000, DSC-HX60V/HX350/HX400V/WX220/WX350 # 0x17 0x01 ILCE-7S/7M2/5100/QX1, DSC-QX30/RX100M3 - # 0x19 0x01 DSC-HX90V/RX1RM2/RX10M2/RX100M4/WX500, ILCE-6300/7RM2/7SM2 + # 0x19 0x01 DSC-HX80/HX90V/RX1RM2/RX10M2/RX100M4/WX500, ILCE-6300/7RM2/7SM2 # 0x1a 0x01 DSC-RX0/RX10M3/RX100M5, ILCE-6500 # 0x1c 0x01 ILCE-9 # 0x1d 0x01 DSC-RX10M4 - # 0x1e 0x01 ILCE-7M3/7RM3, DSC-RX100M6 + # 0x1e 0x01 ILCE-7M3/7RM3, DSC-RX100M5A/RX100M6 + # 0x1f 0x01 DSC-HX99 + # 0x20 0x01 ILCE-6100/6400/6600/7RM4/9M2, ILCE-9 v5.00-v6.00, DSC-RX0M2/RX100M7 # var var SLT-A58/A99V, HV, ILCA-68/77M2/99M2 # only valid when first byte 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x17, 0x19, 0x1a, 0x1c (enciphered 0x8a, 0x70, 0xb6, 0x69, 0x88, 0x20, 0x30, 0xd7, 0xbb, 0x92, 0x28) # Condition => '$$self{DoubleCipher} ? $$valPt =~ /^[\x7e\x46\x1d\x18\x3a\x95\x24\x26\xd6]\x01/ : $$valPt =~ /^[\x8a\x70\xb6\x69\x88\x20\x30\xd7\xbb\x92\x28]\x01/', @@ -1610,8 +1797,9 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # 12 0 8 2 2 SLT-A58, NEX-3N, ILCE-3000/3500, DSC-HX300/HX50V/WX60/WX80/WX300/TX30... # 13 0 9 2 2 DSC-QX10/QX100/RX100M2 # 15 0 35 2 2 ILCA-68/77M2, ILCE-5000/5100/6000/7/7R/7S/7M2/QX1, DSC-HX60V/HX350/HX400V/QX30/RX10/RX100M3/WX220/WX350 - # 16 0 85 2 2 DSC-HX90V/WX500 - # 17 0 232 1 2 DSC-RX0/RX1RM2/RX10M2/RX10M3/RX10M4/RX100M4/RX100M5/RX100M6, ILCE-6300/6500/7M3/7RM2/7RM3/7SM2/9, ILCA-99M2 + # 16 0 85 2 2 DSC-HX80/HX90V/WX500 + # 17 0 232 1 2 DSC-RX0/RX0M2/RX1RM2/RX10M2/RX10M3/RX10M4/RX100M4/RX100M5/RX100M5A/RX100M6/RX100M7/HX99, ILCE-6100/6300/6400/6500/6600/7C/7M3/7RM2/7RM3/7RM4/7SM2/9/9M2, ILCA-99M2, ZV-1 + # 18 0 20 0 164 ILCE-7SM3 # other values for Panorama images and several other models 0x9404 => [{ Name => 'Tag9404a', @@ -1642,10 +1830,11 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); # 137 var (0xb3 = 179 var enc.) ILCA-68/77M2, DSC-RX100M3 - appears to go with 136 # 138 var (0x7e = 126 var enc.) ILCE-7S/5100/QX1, DSC-QX30 - appears to go with 136 # 139 var (0x9a = 154 var enc.) ILCE-7M2 - # 142 var (0x25 = 37 var enc.) DSC-HX90V/RX1RM2/RX10M2/RX10M3/RX100M4/WX500, ILCE-6300/7RM2/7SM2 + # 142 var (0x25 = 37 var enc.) DSC-HX80/HX90V/RX1RM2/RX10M2/RX10M3/RX100M4/WX500, ILCE-6300/7RM2/7SM2 # 144 var (0xe1 = 225 var enc.) DSC-RX100M5 # 145 var (0x76 = 118 var enc.) ILCA-99M2, ILCE-6500, DSC-RX0 - # 163 var (0x8b = 139 var enc.) ILCE-7M3/7RM3/9, DSC-RX10M4/RX100M6 + # 163 var (0x8b = 139 var enc.) ILCE-6100/6400/6600/7C/7M3/7RM3/7RM4/9/9M2, DSC-RX0M2/RX10M4/RX100M5A/RX100M6/RX100M7/HX99, ZV-1/E10 + # July 2020: ILCE-7SM3 doesn't write this tag anymore, but writes 0x9416 0x9405 => [{ Name => 'Tag9405a', # first byte must be 0x1b or 0x40 or 0x7d @@ -1662,9 +1851,10 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); }], 0x9406 => [{ Name => 'Tag9406', - # - first byte must be 0x01 or 0x02 (enciphered 0x01 or 0x08), or 0x03 (enc. 0x1b) for ILCE-6300/7RM2/7SM2, and + # - first byte must be 0x01 or 0x02 (enciphered 0x01 or 0x08), + # or 0x03 (enc. 0x1b) for ILCE-6100/6300/6400/6500/6600/7M3/7RM2/7RM3/7RM4/7SM2/9/9M2, and ILCA-99M2 # third byte must be 0x02 or 0x03 (enciphered 0x08 or 0x1b) - ref JR - # (applies to most SLT and NEX models, but no DSC models) + # (applies to most SLT/ILCA and NEX/ILCE models, but no DSC models) Condition => '$$valPt =~ /^[\x01\x08\x1b].[\x08\x1b]/s', SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag9406' }, },{ @@ -1697,7 +1887,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); }, 0x940c => [{ Name => 'Tag940c', - Condition => '$$self{Model} =~ /^(NEX-|ILCE-|Lunar)\b/', + Condition => '$$self{Model} =~ /^(NEX-|ILCE-|ILME-|Lunar|ZV-E10)\b/', SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag940c' }, },{ Name => 'Sony_0x940c', @@ -1731,6 +1921,10 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); %unknownCipherData, # 0x02 - int32u?: 1,3,5,7,9 (A77) }, + 0x9416 => { # replaces 0x9405 for the Sony ILCE-7SM3, from July 2020 + Name => 'Sony_0x9416', + SubDirectory => { TagTable => 'Image::ExifTool::Sony::Tag9416' }, + }, 0xb000 => { #8 Name => 'FileFormat', Writable => 'int8u', @@ -1752,6 +1946,8 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); '3 3 1 0' => 'ARW 2.3.1', #PH/JR (DSC-RX1R/RX100M2/Stellar2) '3 3 2 0' => 'ARW 2.3.2', #JR (DSC-RX1RM2,ILCE-7SM2 - support for uncompressed 14-bit RAW) '3 3 3 0' => 'ARW 2.3.3', #JR (ILCE-9) + '3 3 5 0' => 'ARW 2.3.5', #JR (DSC-HX99) + '4 0 0 0' => 'ARW 4.0', # (ILCE-7SM3) # what about cRAW images? }, }, @@ -1761,7 +1957,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); Writable => 'int16u', PrintConvColumns => 2, PrintConv => { - 0 => 'DSC-HX80', #PH + #0 => 'DSC-HX80', #PH (and several other DSC models) 2 => 'DSC-R1', 256 => 'DSLR-A100', 257 => 'DSLR-A900', @@ -1769,13 +1965,13 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); 259 => 'DSLR-A200', 260 => 'DSLR-A350', 261 => 'DSLR-A300', - 262 => 'DSLR-A900 (APS-C mode)', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3994.0.html + 262 => 'DSLR-A900 (APS-C mode)', #https://exiftool.org/forum/index.php/topic,3994.0.html 263 => 'DSLR-A380/A390', #PH (A390) 264 => 'DSLR-A330', 265 => 'DSLR-A230', 266 => 'DSLR-A290', #PH 269 => 'DSLR-A850', - 270 => 'DSLR-A850 (APS-C mode)', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3994.0.html + 270 => 'DSLR-A850 (APS-C mode)', #https://exiftool.org/forum/index.php/topic,3994.0.html 273 => 'DSLR-A550', 274 => 'DSLR-A500', #PH 275 => 'DSLR-A450', #http://dev.exiv2.org/issues/show/0000611 @@ -1784,7 +1980,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); 280 => 'SLT-A33', #PH 281 => 'SLT-A55 / SLT-A55V', #PH (A55 NC) 282 => 'DSLR-A560', #PH - 283 => 'DSLR-A580', #http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,2881.0.html + 283 => 'DSLR-A580', #https://exiftool.org/forum/index.php/topic,2881.0.html 284 => 'NEX-C3', #PH 285 => 'SLT-A35', #JR 286 => 'SLT-A65 / SLT-A65V', #PH @@ -1836,11 +2032,28 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); 364 => 'DSC-RX0', #PH 365 => 'DSC-RX10M4', #JR 366 => 'DSC-RX100M6', #IB + 367 => 'DSC-HX99', #IB 369 => 'DSC-RX100M5A', #JR + 371 => 'ILCE-6400', #IB + 372 => 'DSC-RX0M2', #JR + 374 => 'DSC-RX100M7', #IB + 375 => 'ILCE-7RM4', #IB + 376 => 'ILCE-9M2', #JR + 378 => 'ILCE-6600', #IB/JR + 379 => 'ILCE-6100', #IB/JR + 380 => 'ZV-1', #JR + 381 => 'ILCE-7C', #JR + 382 => 'ZV-E10', #JR + 383 => 'ILCE-7SM3', + 384 => 'ILCE-1', #PH + 385 => 'ILME-FX3', #JR + 386 => 'ILCE-7RM3A', #JR + 387 => 'ILCE-7RM4A', #forum12542 + 388 => 'ILCE-7M4', #IB/JR }, }, 0xb020 => { #2 - Name => 'CreativeStyle', + Name => 'CreativeStyle', # (called CreativeLook by the 7SM3, ref JR) Writable => 'string', # (all of these values have been observed, ref JR and PH) # - this PrintConv is included to make these strings consistent with @@ -1864,6 +2077,12 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); Light => 'Light', Autumnleaves=> 'Autumn Leaves', Sepia => 'Sepia', + # new for the ILCE-7SM3 (ref JR) + VV2 => 'Vivid 2', # (NC) + FL => 'FL', # "moody finish with sharp contrast and calm coloring as well as the impressive sky and colors of the greens" + IN => 'IN', # "matte textures by suppressing the contrast and saturation" + SH => 'SH', # "bright, transparent, soft, and vivid mood" + # (...also Custom Look 1-6, but don't konw the values) }, }, 0xb021 => { #2 @@ -2134,6 +2353,7 @@ my %hidUnk = ( Hidden => 1, Unknown => 1 ); 4 => '+4/3', #JR (NC) 5 => '+5/3', #JR (NC) 6 => '+6/3', #JR + 9 => '+9/3', #JR 128 => 'n/a', #JR (HX9V) 32767 => 'High', }, @@ -5420,7 +5640,7 @@ my %faceInfo = ( PrintConv => { 191 => 'On (191)', # seen a few times with moving subject, continuous drive, bracketing 207 => 'On (207)', # seen once with RemoteCommander - 210 => 'On (210)', # seen a few times with continous drive + 210 => 'On (210)', # seen a few times with continuous drive 213 => 'On', 246 => 'Off', }, @@ -5745,7 +5965,7 @@ my %releaseMode2 = ( #JR 15 => 'Continuous - High Resolution Sweep Panorama', #JR (HX50V) 16 => 'Continuous - 3D Image', # (HX9V) 17 => 'Continuous - Burst 2', # (WX7 - PH) (#JR 9400-SequenceLength=10 shots) - # 18 - seen for several ILCE-7S v2.00 iAuto+ single-shot images ... + 18 => 'Normal - iAuto+', # seen for several ILCE-3500/6000/6500/7S iAuto+ single-shot images ... 19 => 'Continuous - Speed/Advance Priority', #PH/JR (RX100) 20 => 'Continuous - Multi Frame NR', 23 => 'Single-frame - Exposure Bracketing', # (seen for ILCE-7 series) @@ -5786,6 +6006,7 @@ my %releaseMode2010 = ( 4 => 'Continuous - Burst', # seen for DSC-WX500 with burst of 10 shots 5 => 'Continuous - Speed/Advance Priority', 6 => 'Normal - Self-timer', # seen for ILCE-6300/6500/9, ILCA-99M2 + 9 => 'Single Burst Shooting', # first seen for DSC-RX100M7 }, ); my %selfTimer2010 = ( @@ -5938,8 +6159,58 @@ my %pictureProfile2010 = ( 29 => 'Gamma ITU709 (800%)', 31 => 'Gamma S-Log3 (PP8 or PP9)', #14 33 => 'Gamma HLG2 (PP10)', #14 + 34 => 'Gamma HLG3', #IB + 37 => 'FL', + 38 => 'VV2', + 39 => 'IN', + 40 => 'SH', }, ); +my %isoSetting2010 = ( + 0 => 'Auto', + 5 => 25, + 7 => 40, + 8 => 50, + 9 => 64, + 10 => 80, + 11 => 100, + 12 => 125, + 13 => 160, + 14 => 200, + 15 => 250, + 16 => 320, + 17 => 400, + 18 => 500, + 19 => 640, + 20 => 800, + 21 => 1000, + 22 => 1250, + 23 => 1600, + 24 => 2000, + 25 => 2500, + 26 => 3200, + 27 => 4000, + 28 => 5000, + 29 => 6400, + 30 => 8000, + 31 => 10000, + 32 => 12800, + 33 => 16000, + 34 => 20000, + 35 => 25600, + 36 => 32000, + 37 => 40000, + 38 => 51200, + 39 => 64000, + 40 => 80000, + 41 => 102400, + 42 => 128000, + 43 => 160000, + 44 => 204800, + 45 => 256000, + 46 => 320000, + 47 => 409600, +); %Image::ExifTool::Sony::Tag2010a = ( #JR PROCESS_PROC => \&ProcessEnciphered, @@ -5951,6 +6222,7 @@ my %pictureProfile2010 = ( FIRST_ENTRY => 0, PRIORITY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + IS_SUBDIR => [ 0x04b0 ], 0x04b0 => { Name => 'MeterInfo', Format => 'int32u[486]', @@ -5987,6 +6259,7 @@ my %pictureProfile2010 = ( FIRST_ENTRY => 0, PRIORITY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + IS_SUBDIR => [ 0x04b4 ], 0x0000 => { %sequenceImageNumber }, #PH 0x0004 => { %sequenceFileNumber }, #PH 0x0008 => { %releaseMode2, Format => 'int32u' }, @@ -6054,6 +6327,7 @@ my %pictureProfile2010 = ( FIRST_ENTRY => 0, PRIORITY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + IS_SUBDIR => [ 0x0490 ], 0x0000 => { %sequenceImageNumber }, #PH 0x0004 => { %sequenceFileNumber }, #PH 0x0008 => { %releaseMode2, Format => 'int32u' }, @@ -6122,6 +6396,7 @@ my %pictureProfile2010 = ( FIRST_ENTRY => 0, PRIORITY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + IS_SUBDIR => [ 0x050c ], 0x0000 => { %sequenceImageNumber }, #PH 0x0004 => { %sequenceFileNumber }, #PH 0x0008 => { %releaseMode2, Format => 'int32u' }, @@ -6176,14 +6451,16 @@ my %pictureProfile2010 = ( CHECK_PROC => \&Image::ExifTool::CheckBinaryData, FORMAT => 'int8u', NOTES => q{ - Valid for SLT-A58/A99, ILCE-3000/3500, NEX-3N/5R/5T/6/VG30E/VG900, DSC-RX100, - DSC-RX1/RX1R. Also valid for DSC-HX300/HX50V/TX30/WX60/WX200/WX300, but not - for panorama images. + Valid for SLT-A58/A99, ILCE-3000/3500, NEX-3N/5R/5T/6/VG30E/VG900, + DSC-RX100, DSC-RX1/RX1R. Also valid for DSC-HX300/HX50V/TX30/WX60/WX200/ + WX300, but not for panorama images. }, WRITABLE => 1, FIRST_ENTRY => 0, PRIORITY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + DATAMEMBER => [ 0x1892 ], + IS_SUBDIR => [ 0x04b8 ], 0x0000 => { %sequenceImageNumber }, #PH 0x0004 => { %sequenceFileNumber }, #PH 0x0008 => { %releaseMode2, Format => 'int32u' }, @@ -6286,7 +6563,9 @@ my %pictureProfile2010 = ( Condition => '$$self{Model} !~ /^(DSC-|Stellar)/', Format => 'int16s[16]', }, - # 0x1890 - same as 0x1892, but has value 3 for 50mm F1.4 ZA, DT 18-135mm and for 70-400mm G II: meaning ?? + # 0x1890 - same as 0x1892, but has value 3 for SAL18135, SAL50F14Z, SAL55300, SAL70200G2, SAL70300G2, SAL70400G2 + # Presumably, these are the A-mount lenses "compatible with software updates" as referred to in the ILCA-99M2 manual. + # Indeed, SAL70400G2 on ILCA-77M2 gives Version: "Lens: Ver.01" 0x1891 => { Name => 'LensFormat', Condition => '$$self{Model} !~ /^(DSC-|Stellar)/', @@ -6348,6 +6627,7 @@ my %pictureProfile2010 = ( FIRST_ENTRY => 0, PRIORITY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + IS_SUBDIR => [ 0x01e0 ], 0x0004 => { %releaseMode2, Format => 'int32u' }, # NOT at offset 0x08 ! #0x002e => { Name => 'SonyImageWidth3', Format => 'int16u' }, #0x0042 => { Name => 'SonyImageWidth3', Format => 'int16u' }, @@ -6427,6 +6707,8 @@ my %pictureProfile2010 = ( FIRST_ENTRY => 0, PRIORITY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + DATAMEMBER => [ 0x18be ], + IS_SUBDIR => [ 0x0388 ], 0x0004 => { %releaseMode2, Format => 'int32u' }, # NOT at offset 0x08 ! 0x0050 => { %dynamicRangeOptimizer2010 }, 0x020c => { %releaseMode2010 }, @@ -6489,7 +6771,7 @@ my %pictureProfile2010 = ( Condition => '$$self{Model} !~ /^DSC-/', Format => 'int16s[16]', }, - # 0x18bc - same as 0x18be, but has value 3 for 50mm F1.4 ZA, DT 18-135mm and for 70-400mm G II: meaning ?? + # 0x18bc - same as 0x18be, but has value 3 for SAL18135, SAL50F14Z, SAL55300, SAL70200G2, SAL70300G2, SAL70400G2 0x18bd => { Name => 'LensFormat', Condition => '$$self{Model} !~ /^DSC-/', @@ -6547,13 +6829,15 @@ my %pictureProfile2010 = ( CHECK_PROC => \&Image::ExifTool::CheckBinaryData, FORMAT => 'int8u', NOTES => q{ - Valid for DSC-HX90V/RX0/RX1RM2/RX10M2/RX10M3/RX100M4/RX100M5/WX500, + Valid for DSC-HX80/HX90V/RX0/RX1RM2/RX10M2/RX10M3/RX100M4/RX100M5/WX500, ILCE-6300/6500/7RM2/7SM2, ILCA-99M2. }, WRITABLE => 1, FIRST_ENTRY => 0, PRIORITY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + DATAMEMBER => [ 0x18ee ], + IS_SUBDIR => [ 0x0388, 0x0398 ], 0x0004 => { %releaseMode2, Format => 'int32u' }, 0x0050 => { %dynamicRangeOptimizer2010 }, 0x020c => { %releaseMode2010 }, @@ -6624,7 +6908,7 @@ my %pictureProfile2010 = ( Condition => '$$self{Model} !~ /^DSC-/', Format => 'int16s[16]', }, - # 0x18ec - same as 0x18ee, but has value 3 for LensType>=65, except SAL300F28G2 + # 0x18ec - same as 0x18ee, but has value 3 for SAL18135, SAL50F14Z, SAL55300, SAL70200G2, SAL70300G2, SAL70400G2 0x18ed => { Name => 'LensFormat', Condition => '$$self{Model} !~ /^DSC-/', @@ -6682,12 +6966,15 @@ my %pictureProfile2010 = ( CHECK_PROC => \&Image::ExifTool::CheckBinaryData, FORMAT => 'int8u', NOTES => q{ - Valid for ILCE-7M3/7RM3/9, DSC-RX10M4/RX100M6/RX100M5A. + Valid for ILCE-6100/6400/6600/7C/7M3/7RM3/7RM4/9/9M2, DSC-RX0M2/RX10M4/RX100M6/ + RX100M5A/RX100M7/HX99. }, WRITABLE => 1, FIRST_ENTRY => 0, PRIORITY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + DATAMEMBER => [ 0x17f2 ], + IS_SUBDIR => [ 0x036d ], 0x0004 => { %releaseMode2, Format => 'int32u' }, 0x004e => { %dynamicRangeOptimizer2010 }, 0x0204 => { %releaseMode2010 }, @@ -6750,7 +7037,7 @@ my %pictureProfile2010 = ( Condition => '$$self{Model} !~ /^DSC-/', Format => 'int16s[16]', }, - # 0x17f0 - same as 0x17f2, but has value 3 for LensType>=65, except SAL300F28G2 + # 0x17f0 - same as 0x17f2, but has value 3 for SAL18135, SAL50F14Z, SAL55300, SAL70200G2, SAL70300G2, SAL70400G2 0x17f1 => { Name => 'LensFormat', Condition => '$$self{Model} !~ /^DSC-/', @@ -6982,8 +7269,8 @@ my %pictureProfile2010 = ( }, WRITABLE => 1, FIRST_ENTRY => 0, - DATAMEMBER => [ 0x0105 ], GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + DATAMEMBER => [ 0x0031, 0x0105 ], NOTES => q{ Data for tags 0x9050, 0x94xx and 0x2010 is encrypted by a simple substitution cipher, but the deciphered values are listed below. @@ -7010,6 +7297,17 @@ my %pictureProfile2010 = ( # appears to be difference between used FNumber and MaxAperture, 256 being +1 APEX or stop # however, not always valid e.g. bracketing, Shutter-prio e.a. # difference between 0x0002 and 0x0004 mostly 0.0, 0.1 or 0.2 stops. + 0x0020 => { + Name => 'Shutter', + Format => 'int16u[3]', + PrintConv => { + '0 0 0' => 'Silent / Electronic (0 0 0)', + OTHER => sub { + my ($val, $inv) = @_; + return $inv ? ($val=~/\((.*?)\)/ ? $1 : undef) : "Mechanical ($val)"; + }, + }, + }, 0x0031 => { #JR Name => 'FlashStatus', RawConv => '$$self{FlashFired} = $val', @@ -7024,7 +7322,7 @@ my %pictureProfile2010 = ( }, }, 0x0032 => { #13 - Name => 'ImageCount', + Name => 'ShutterCount', # this seems to be valid for the A7R,A37,A57,A65,A77,A99,A99V and possibly the # NEX-5N/7. For the A99V it is definitely more than 16 bits, but it wraps at # 65536 for the A7R. @@ -7059,9 +7357,9 @@ my %pictureProfile2010 = ( # e.g for SAL70400G2: 9 5 5 64 69 74 79 84 89 94 98 104 255 105 89 80 # where 9 means 9 focal lengths: 64 ... 104, # corresponding to 70-400mm via FocalLength = 4.375*2**($val/16) -# 0x004c, 0x0051: E-Mount: ImageCount and dateTime +# 0x004c, 0x0051: E-Mount: ShutterCount and dateTime 0x004c => { # only ILCE-7/7R/7S/7M2/5000/5100/6000/QX1 - but appears not valid when flash is used ... - Name => 'ImageCount2', + Name => 'ShutterCount2', Condition => '($$self{Model} =~ /^(ILCE-(7(R|S|M2)?|[56]000|5100|QX1))\b/) and (($$self{FlashFired} & 0x01) != 1)', Format => 'int32u', RawConv => '$val & 0x00ffffff', @@ -7104,7 +7402,7 @@ my %pictureProfile2010 = ( PrintConv => 'unpack "H*", pack "C*", split " ", $val', PrintConvInv => 'join " ", unpack "C*", pack "H*", $val', }, - # 0x0104 - same as 0x0105, but has value 3 for 50mm F1.4 ZA, DT 18-135mm and for 70-400mm G II: meaning ?? + # 0x0104 - same as 0x0105, but has value 3 for SAL18135, SAL50F14Z, SAL55300, SAL70200G2, SAL70300G2, SAL70400G2 0x0105 => { Name => 'LensMount', DataMember => 'LensMount', @@ -7145,6 +7443,14 @@ my %pictureProfile2010 = ( Name => 'DistortionCorrParamsPresent', PrintConv => { 0 => 'No', 1 => 'Yes'}, }, + 0x0114 => { + Name => 'APS-CSizeCapture', + Condition => '$$self{Model} =~ /^(SLT-A99|HV|ILCE-7)/', + PrintConv => { + 0 => 'Off', + 1 => 'On', + }, + }, # 0x0115 and 0x0116, or 0x0116 and 0x0117: # give the same info as the first and last bytes of LensSpec, # but also for older Sony and Minolta lenses where all LensSpec bytes are 0. @@ -7178,27 +7484,27 @@ my %pictureProfile2010 = ( # 0x012d => {Name=>'LensType',Format=>'int16u',Condition =>'$$self{Model}=~/^(SLT-A(37|57|65|77)V?|Lunar|NEX-(F3|5N|7|VG20E))/'}, # 0x012e => {Name=>'LensType',Format=>'int16u',Condition =>'$$self{Model}=~/^(SLT-A(58|99V?)|HV|ILCA-(68|77M2)|NEX-(3N|5R|5T|6|VG30E|VG900)|ILCE-(3000|3500|5000|5100|6000|7|7R|7S|7M2|QX1))/'}, -# ImageCount3 = ImageCount for SLT-A58, ILCE, ILCA, NEX-3N -# ImageCount-1 for SLT-A37,A57,A65,A77,A99, NEX-F3,5N,5R,5T,6,7, sometimes 0 -# ImageCount-2 for NEX-VG, and often 0; "ImageCount-2" also seen on a few A99V images -# The offset for ImageCount3 changes with firmware version for the ILCE-7/7R/7S/7M2, so don't decode it for now: +# ShutterCount3 = ShutterCount for SLT-A58, ILCE, ILCA, NEX-3N +# ShutterCount-1 for SLT-A37,A57,A65,A77,A99, NEX-F3,5N,5R,5T,6,7, sometimes 0 +# ShutterCount-2 for NEX-VG, and often 0; "ShutterCount-2" also seen on a few A99V images +# The offset for ShutterCount3 changes with firmware version for the ILCE-7/7R/7S/7M2, so don't decode it for now: # ILCE-7M2/7S: 0x01a0 (firmware 1.0x, 1.1x), 0x01b6 (firmware 1.20, 1.21, 2.00) # ILCE-7/7R: 0x01aa (firmware 1.0x, 1.1x), 0x01c0 (firmware 1.20, 1.21, 2.00) # Similarly for ILCE-6000 v2.00: 0x01aa --> 0x01c0: removed from 0x01aa 0x01a0 => { - Name => 'ImageCount3', + Name => 'ShutterCount3', Format => 'int32u', RawConv => '$val == 0 ? undef : $val', Condition => '$$self{Model} =~ /^(ILCE-(5100|QX1)|ILCA-(68|77M2))/', }, 0x01aa => { - Name => 'ImageCount3', + Name => 'ShutterCount3', Format => 'int32u', RawConv => '$val == 0 ? undef : $val', Condition => '$$self{Model} =~ /^(SLT-A(58|99V?)|HV|NEX-(3N|5R|5T|6|VG900|VG30E)|ILCE-([35]000|3500))\b/', }, 0x01bd => { - Name => 'ImageCount3', + Name => 'ShutterCount3', Format => 'int32u', RawConv => '$val == 0 ? undef : $val', Condition => '$$self{Model} =~ /^(SLT-A(37|57|65|77)V?|Lunar|NEX-(F3|5N|7|VG20E))/', @@ -7240,11 +7546,14 @@ my %pictureProfile2010 = ( WRITE_PROC => \&WriteEnciphered, CHECK_PROC => \&Image::ExifTool::CheckBinaryData, FORMAT => 'int8u', - NOTES => 'Valid from July 2015 for ILCE-6300/6500/7M3/7RM2/7RM3/7SM2/9, ILCA-99M2.', + NOTES => q{ + Valid from July 2015 for ILCE-6100/6300/6400/6500/6600/7C/7M3/7RM2/7RM3/7RM4/ + 7SM2/9/9M2, ILCA-99M2. + }, WRITABLE => 1, FIRST_ENTRY => 0, - DATAMEMBER => [ 0x0105 ], GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + DATAMEMBER => [ 0x0039, 0x0105 ], 0x0000 => { Condition => '$$self{Model} =~ /^(ILCA-)/', Name => 'SonyMaxAperture', # (at current focal length) @@ -7263,6 +7572,25 @@ my %pictureProfile2010 = ( PrintConv => 'sprintf("%.0f",$val)', PrintConvInv => '$val', }, + 0x0026 => { + Name => 'Shutter', + Format => 'int16u[3]', + PrintConv => { + '0 0 0' => 'Silent / Electronic (0 0 0)', + OTHER => sub { + my ($val, $inv) = @_; + return $inv ? ($val=~/\((.*?)\)/ ? $1 : undef) : "Mechanical ($val)"; + }, + }, + }, + #0x002c => { + # Name => 'Shutter', + # Condition => '$$self{Model} !~ /^(ILCE-6400)/ and $$self{Software} !~ /^ILCE-9 v5.0/', + # PrintConv => { + # 0 => 'Silent / Electronic', + # 56 => 'Mechanical', + # }, + #}, 0x0039 => { Name => 'FlashStatus', RawConv => '$$self{FlashFired} = $val', @@ -7274,10 +7602,11 @@ my %pictureProfile2010 = ( 66 => 'Built-in Flash Inhibited', # seen for panorama, HDR, burst mode 128 => 'External Flash present', # seen for NEX-5N/5T 129 => 'External Flash Fired', # seen for SLT-A99V, ILCE-7R, NEX-5N/5R +# 131 => 'External Flash ???', # seen for ILCE-7RM4 }, }, 0x003a => { - Name => 'ImageCount', + Name => 'ShutterCount', # or "ShutterCount"? : number of shutter actuations, does not increase during Silent Shooting, # at least for ILCE-7RM2 Format => 'int32u', @@ -7304,36 +7633,52 @@ my %pictureProfile2010 = ( Name => 'ReleaseMode2', %releaseMode2, }, +# March 2019: ILCE-9 with v5.0x firmware follows ILCE-6400 in many tags ... + 0x0050 => { + Name => 'ShutterCount2', + Condition => '(($$self{FlashFired} & 0x01) != 1) and ($$self{Model} =~ /^(ILCE-(6100|6400|6600|7C|7RM4A?|9M2)|ZV-E10)/ or $$self{Software} =~ /^ILCE-9 (v5.0|v6.0)/)', + Format => 'int32u', + RawConv => '$val & 0x00ffffff', + }, 0x0052 => { - Name => 'ImageCount2', - Condition => '(($$self{FlashFired} & 0x01) != 1) and ($$self{Model} =~ /^(ILCE-(7M3|7RM3))/)', + Name => 'ShutterCount2', + Condition => '(($$self{FlashFired} & 0x01) != 1) and ($$self{Model} =~ /^(ILCE-(7M3|7RM3A?))/)', Format => 'int32u', RawConv => '$val & 0x00ffffff', - PrintConv => 'sprintf("%6d",$val)', }, # 0x0058 - 0x0067: A-Mount: 16 values, only non-zero data for lenses giving "A-mount (3)" in 0x0104 below. # e.g for SAL70400G2: 9 5 5 64 69 74 79 84 89 94 98 104 255 105 89 80 # where 9 means 9 focal lengths: 64 ... 104, # corresponding to 70-400mm via FocalLength = 4.375*2**($val/16) -# 0x0058, 0x0061: E-Mount: ImageCount and dateTime +# 0x0058, 0x0061: E-Mount: ShutterCount and dateTime 0x0058 => { # appears not valid when flash is used ... not for ILCA-99M2 - Name => 'ImageCount2', - Condition => '(($$self{FlashFired} & 0x01) != 1) and ($$self{Model} !~ /^(ILCA-99M2|ILCE-(7M3|7RM3))/)', + Name => 'ShutterCount2', + Condition => '(($$self{FlashFired} & 0x01) != 1) and ($$self{Model} !~ /^(ILCA-99M2|ILCE-(6100|6400|6600|7C|7M3|7RM3A?|7RM4A?|9M2)|ZV-E10)/) and $$self{Software} !~ /^ILCE-9 (v5.0|v6.0)/', Format => 'int32u', RawConv => '$val & 0x00ffffff', }, 0x0061 => { # only minutes-seconds, not for ILCA-99M2, ILCE-9 Name => 'SonyTimeMinSec', - Condition => '$$self{Model} !~ /^(ILCA-99M2|ILCE-(7M3|7RM3|9))/', + Condition => '$$self{Model} !~ /^(ILCA-99M2|ILCE-(6100|6400|6600|7C|7M3|7RM3A?|7RM4A?|9|9M2)|ZV-E10)/', Format => 'undef[2]', ValueConv => q{ my @v = unpack('C*', $val); return sprintf("%.2d:%.2d", @v) }, }, + 0x006b => { + Name => 'ReleaseMode2', + Condition => '$$self{Model} =~ /^(ILCE-(6100|6400|6600|7C|7RM4A?|9M2)|ZV-E10)/ or $$self{Software} =~ /^ILCE-9 (v5.0|v6.0)/', + %releaseMode2, + }, + 0x006d => { + Name => 'ReleaseMode2', + Condition => '$$self{Model} =~ /^(ILCE-(7M3|7RM3A?))/', + %releaseMode2, + }, 0x0073 => { Name => 'ReleaseMode2', - Condition => '$$self{Model} !~ /^(ILCE-(7M3|7RM3))/', + Condition => '$$self{Model} !~ /^(ILCE-(6100|6400|6600|7C|7M3|7RM3A?|7RM4A?|9M2)|ZV-E10)/ and $$self{Software} !~ /^ILCE-9 (v5.0|v6.0)/', %releaseMode2, }, 0x0088 => { @@ -7344,7 +7689,7 @@ my %pictureProfile2010 = ( ##### same offsets for lens info tags - # 0x0104 - same as 0x0105, but has value 3 for 50mm F1.4 ZA, DT 18-135mm and for 70-400mm G II: meaning ?? + # 0x0104 - same as 0x0105, but has value 3 for SAL18135, SAL50F14Z, SAL55300, SAL70200G2, SAL70300G2, SAL70400G2 0x0105 => { Name => 'LensMount', DataMember => 'LensMount', @@ -7385,6 +7730,14 @@ my %pictureProfile2010 = ( Name => 'DistortionCorrParamsPresent', PrintConv => { 0 => 'No', 1 => 'Yes'}, }, + 0x0114 => { + Name => 'APS-CSizeCapture', + Condition => '$$self{Model} =~ /^(ILCE-7|ILCE-9|ILCA-99)/', + PrintConv => { + 0 => 'Off', + 1 => 'On', + }, + }, # 0x0116 and 0x0117: # give the same info as the first and last bytes of LensSpec, # but also for older Sony and Minolta lenses where all LensSpec bytes are 0. @@ -7403,23 +7756,65 @@ my %pictureProfile2010 = ( # tags becoming model- and/or firmware-dependent from here. # 0x019f => { - Name => 'ImageCount3', - Condition => '$$self{Model} =~ /^(ILCE-(7M3|7RM3|9))/', + Name => 'ShutterCount3', + Condition => '$$self{Model} =~ /^(ILCE-(6100|6400|6600|7C|7M3|7RM3A?|7RM4A?|9|9M2)|ZV-E10)\b/', Format => 'int32u', RawConv => '$val == 0 ? undef : $val', }, 0x01cb => { - Name => 'ImageCount3', + Name => 'ShutterCount3', Condition => '$$self{Model} =~ /^(ILCE-(7RM2|7SM2))/', Format => 'int32u', RawConv => '$val == 0 ? undef : $val', }, 0x01cd => { - Name => 'ImageCount3', + Name => 'ShutterCount3', Condition => '$$self{Model} =~ /^(ILCE-(6300|6500)|ILCA-99M2)/', Format => 'int32u', RawConv => '$val == 0 ? undef : $val', }, + 0x01eb => { + Name => 'APS-CSizeCapture', + Condition => '$$self{Model} =~ /^ILCE-(7RM4A?|7C|9M2)|ZV-E10/ or $$self{Software} =~ /^ILCE-9 (v5.0|v6.0)/', + PrintConv => { + 0 => 'Off', + 1 => 'On', + }, + }, + 0x01ed => { + Name => 'LensSpecFeatures', + Condition => '$$self{Model} =~ /^ILCE-(7RM4A?|7C|9M2)|ZV-E10/ or $$self{Software} =~ /^ILCE-9 (v5.0|v6.0)/', + Priority => 0, + Format => 'undef[2]', + ValueConv => 'join " ", unpack "H2H2", $val', + ValueConvInv => sub { + my @a = split(" ", shift); + return @a == 2 ? pack 'CC', hex($a[0]), hex($a[1]) : undef; + }, + PrintConv => \&PrintLensSpec, + PrintConvInv => 'Image::ExifTool::Sony::PrintInvLensSpec($val, $self, 1)', + }, + 0x01ee => { + Name => 'APS-CSizeCapture', + Condition => '$$self{Model} =~ /^(ILCE-(7M3|7RM3A?|9))\b/ and $$self{Software} !~ /^ILCE-9 (v5.0|v6.0)/', + PrintConv => { + 0 => 'Off', + 1 => 'On', + }, + }, + 0x01f0 => { + Name => 'LensSpecFeatures', + Condition => '$$self{Model} =~ /^(ILCE-(6100|6400|6600|7M3|7RM3A?|9))\b/ and $$self{Software} !~ /^ILCE-9 (v5.0|v6.0)/', + Priority => 0, + Format => 'undef[2]', + ValueConv => 'join " ", unpack "H2H2", $val', + ValueConvInv => sub { + my @a = split(" ", shift); + return @a == 2 ? pack 'CC', hex($a[0]), hex($a[1]) : undef; + }, + PrintConv => \&PrintLensSpec, + PrintConvInv => 'Image::ExifTool::Sony::PrintInvLensSpec($val, $self, 1)', + }, # the following tags are commented out because they can cause problems for the # Composite LensID of non-electronic lenses (even if Priority is set to 0) # 0x020d => { @@ -7441,7 +7836,15 @@ my %pictureProfile2010 = ( # Condition => '$$self{Model} =~ /^(ILCE-(6300|6500)|ILCA-99M2)/', # Format=>'int16u', # }, - 0x021c => { + 0x021a => { + Name => 'APS-CSizeCapture', + Condition => '$$self{Model} =~ /^(ILCE-(7RM2|7SM2))/', + PrintConv => { + 0 => 'Off', + 1 => 'On', + }, + }, + 0x021c => [{ Name => 'LensSpecFeatures', Condition => '$$self{Model} =~ /^(ILCE-(7RM2|7SM2))/', Priority => 0, @@ -7453,7 +7856,14 @@ my %pictureProfile2010 = ( }, PrintConv => \&PrintLensSpec, PrintConvInv => 'Image::ExifTool::Sony::PrintInvLensSpec($val, $self, 1)', - }, + },{ + Name => 'APS-CSizeCapture', + Condition => '$$self{Model} =~ /^(ILCA-99M2)/', + PrintConv => { + 0 => 'Off', + 1 => 'On', + }, + }], 0x021e => { Name => 'LensSpecFeatures', Condition => '$$self{Model} =~ /^(ILCE-(6300|6500)|ILCA-99M2)/', @@ -7469,6 +7879,111 @@ my %pictureProfile2010 = ( }, ); +%Image::ExifTool::Sony::Tag9050c = ( #JR + PROCESS_PROC => \&ProcessEnciphered, + WRITE_PROC => \&WriteEnciphered, + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, + FORMAT => 'int8u', + NOTES => q{ + Valid from July 2020 for ILCE-1/7SM3, ILME-FX3. + }, + WRITABLE => 1, + FIRST_ENTRY => 0, + GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + DATAMEMBER => [ 0x0039 ], + 0x0026 => { + Name => 'Shutter', + Format => 'int16u[3]', + PrintConv => { + '0 0 0' => 'Silent / Electronic (0 0 0)', + OTHER => sub { + my ($val, $inv) = @_; + return $inv ? ($val=~/\((.*?)\)/ ? $1 : undef) : "Mechanical ($val)"; + }, + }, + }, + 0x0039 => { + Name => 'FlashStatus', + RawConv => '$$self{FlashFired} = $val', + PrintConv => { + 0 => 'No Flash present', + 2 => 'Flash Inhibited', # seen for ILCE-7/7R continuous, panorama, HDR mode + 64 => 'Built-in Flash present', + 65 => 'Built-in Flash Fired', + 66 => 'Built-in Flash Inhibited', # seen for panorama, HDR, burst mode + 128 => 'External Flash present', # seen for NEX-5N/5T + 129 => 'External Flash Fired', # seen for SLT-A99V, ILCE-7R, NEX-5N/5R + }, + }, + 0x003a => { + Name => 'ShutterCount', + # or "ShutterCount"? : number of shutter actuations, does not increase during Silent Shooting, + # at least for ILCE-7RM2 + Format => 'int32u', + Notes => 'total number of image exposures made by the camera', + RawConv => '$val & 0x00ffffff', + PrintConv => 'sprintf("%6d",$val)', + }, + 0x0046 => { # appr. same value as Exif ExposureTime, but longer in HDR-modes + Name => 'SonyExposureTime', + Format => 'int16u', + ValueConv => '$val ? 2 ** (16 - $val/256) : 0', + ValueConvInv => '$val ? int((16 - log($val) / log(2)) * 256 + 0.5) : 0', + PrintConv => '$val ? Image::ExifTool::Exif::PrintExposureTime($val) : "Bulb"', + PrintConvInv => 'lc($val) eq "bulb" ? 0 : Image::ExifTool::Exif::ConvertFraction($val)', + }, + 0x0048 => { + Name => 'SonyFNumber', + Format => 'int16u', + ValueConv => '2 ** (($val/256 - 16) / 2)', + ValueConvInv => '(log($val)*2/log(2)+16)*256', + PrintConv => 'sprintf("%.1f",$val)', + PrintConvInv => '$val', + }, + 0x004b => { + Name => 'ReleaseMode2', + %releaseMode2, + }, + 0x0050 => { + Name => 'ShutterCount2', + Condition => '($$self{FlashFired} & 0x01) != 1', + Format => 'int32u', + RawConv => '$val & 0x00ffffff', + }, + 0x0066 => { # appr. same value as Exif ExposureTime, but not valid in HDR-modes + Name => 'SonyExposureTime', + Format => 'int16u', + ValueConv => '$val ? 2 ** (16 - $val/256) : 0', + ValueConvInv => '$val ? int((16 - log($val) / log(2)) * 256 + 0.5) : 0', + PrintConv => '$val ? Image::ExifTool::Exif::PrintExposureTime($val) : "Bulb"', + PrintConvInv => 'lc($val) eq "bulb" ? 0 : Image::ExifTool::Exif::ConvertFraction($val)', + }, + 0x0068 => { # appr. same value as Exif ExposureTime, but not valid in HDR-modes + Name => 'SonyFNumber', + Format => 'int16u', + ValueConv => '2 ** (($val/256 - 16) / 2)', + ValueConvInv => '(log($val)*2/log(2)+16)*256', + PrintConv => 'sprintf("%.1f",$val)', + PrintConvInv => '$val', + }, + 0x006b => { + Name => 'ReleaseMode2', + %releaseMode2, + }, + 0x0088 => { + Name => 'InternalSerialNumber', #(NC) + Condition => '$$self{Model} =~ /^(ILCE-(7M4|7SM3)|ILME-FX3)/', + Format => 'int8u[6]', + PrintConv => 'unpack "H*", pack "C*", split " ", $val', + }, + 0x008a => { + Name => 'InternalSerialNumber', #(NC) + Condition => '$$self{Model} =~ /^(ILCE-1)/', + Format => 'int8u[6]', + PrintConv => 'unpack "H*", pack "C*", split " ", $val', + }, +); + %Image::ExifTool::Sony::Tag9400a = ( #JR PROCESS_PROC => \&ProcessEnciphered, WRITE_PROC => \&WriteEnciphered, @@ -7636,21 +8151,20 @@ my %pictureProfile2010 = ( FORMAT => 'int8u', WRITABLE => 1, NOTES => q{ - Valid for DSC-HX60V/HX90V/HX350/HX400V/QX30/RX0/RX1RM2/RX10/RX10M2/RX10M3/ - RX10M4/RX100M3/RX100M4/RX100M5/RX100M6/WX220/WX350/WX500, ILCE-7/7R/7S/ - 7M2/7M3/7RM2/7RM3/7SM2/9/5000/5100/6000/6300/6500/QX1, ILCA-68/77M2/99M2. + Valid for DSC-HX60V/HX80/HX90V/HX99/HX350/HX400V/QX30/RX0/RX1RM2/RX10/ + RX10M2/RX10M3/RX10M4/RX100M3/RX100M4/RX100M5/RX100M5A/RX100M6/RX100M7/WX220/ + WX350/WX500, ILCE-1/7/7C/7R/7S/7M2/7M3/7RM2/7RM3/7RM4/7SM2/7SM3/9/9M2/5000/ + 5100/6000/6100/6300/6400/6500/6600/QX1, ILCA-68/77M2/99M2. }, FIRST_ENTRY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, 0x0009 => { %releaseMode2 }, - 0x000a => [{ - Condition => '$$self{Model} =~ /^(ILCE-(7M3|7RM3|9)|DSC-(RX10M4|RX100M6|RX100M5A))\b/', - Name => 'ShotNumberSincePowerUp', - Format => 'int8u', - },{ + 0x000a => { Name => 'ShotNumberSincePowerUp', + Condition => '$$self{Model} =~ /^(ILCA-(68|77M2|99M2)|ILCE-(5000|5100|6000|6300|6500|7|7M2|7R|7RM2|7S|7SM2|QX1)|DSC-(HX350|HX400V|HX60V|HX80|HX90|HX90V|QX30|RX0|RX1RM2|RX10|RX10M2|RX10M3|RX100M3|RX100M4|RX100M5|WX220|WX350|WX500))\b/', + Notes => 'valid only for some models', Format => 'int32u', - }], + }, 0x0012 => { %sequenceImageNumber }, 0x0016 => { Name => 'SequenceLength', @@ -7662,9 +8176,11 @@ my %pictureProfile2010 = ( 4 => '4 shots', 5 => '5 shots', 6 => '6 shots', + 7 => '7 shots', # DSC-RX100M7 Single Burst Shooting 9 => '9 shots', # ILCE-7RM2 9-shot bracketing 10 => '10 shots', 12 => '12 shots', # ILCA-77M2 12-shot MFNR-mode + 16 => '16 shots', # ILCE-7RM4 16-shot PixelShift 100 => 'Continuous - iSweep Panorama', 200 => 'Continuous - Sweep Panorama', }, @@ -7678,6 +8194,7 @@ my %pictureProfile2010 = ( 2 => '2 files', 3 => '3 files', 5 => '5 files', + 7 => '7 files', # DSC-RX100M7 Single Burst Shooting 9 => '9 files', # ILCE-7RM2 9-shot bracketing 10 => '10 files', # seen for DSC-WX500 with burst of 10 shots }, @@ -7691,27 +8208,76 @@ my %pictureProfile2010 = ( 8 => 'Rotate 270 CW', }, }, - 0x002a => { + 0x002a => [{ Name => 'Quality2', + Condition => '$$self{Model} !~ /^(ILCE-(1|7M4|7SM3)|ILME-FX3)\b/', PrintConv => { 0 => 'JPEG', 1 => 'RAW', 2 => 'RAW + JPEG', 3 => 'JPEG + MPO', # 3D images }, - }, + },{ + Name => 'Quality2', + Condition => '$$self{Model} =~ /^(ILCE-(1|7M4|7SM3)|ILME-FX3)\b/', + PrintConv => { + 1 => 'JPEG', + 2 => 'RAW', + 3 => 'RAW + JPEG', + 4 => 'HEIF', + 6 => 'RAW + HEIF', + }, + }], 0x0047 => { Name => 'SonyImageHeight', + Condition => '$$self{Model} !~ /^(ILCE-(1|7M4|7SM3)|ILME-FX3)\b/', Format => 'int16u', PrintConv => '$val > 0 ? 8*$val : "n.a."', }, 0x0053 => { Name => 'ModelReleaseYear', + Condition => '$$self{Model} !~ /^(ILCE-(1|7M4|7SM3)|ILME-FX3)\b/', Format => 'int8u', PrintConv => 'sprintf("20%.2d", $val)', }, ); +%Image::ExifTool::Sony::Tag9401 = ( # JR + PROCESS_PROC => \&ProcessEnciphered, + WRITE_PROC => \&WriteEnciphered, + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, + FORMAT => 'int8u', + WRITABLE => 1, + FIRST_ENTRY => 0, + GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + DATAMEMBER => [ 0 ], + IS_SUBDIR => [ 0x0498, 0x049d, 0x04a1, 0x04a2, 0x059d, 0x0634, 0x0636, 0x064c, 0x0653, 0x0678, 0x06b8, 0x06de, 0x06e7 ], + 0x0000 => { Name => 'Ver9401', Hidden => 1, RawConv => '$$self{Ver9401} = $val; $$self{OPTIONS}{Unknown}<2 ? undef : $val' }, + + 0x0498 => { Name => 'ISOInfo', Condition => '$$self{Ver9401} == 148', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } }, + 0x049d => { Name => 'ISOInfo', Condition => '$$self{Ver9401} == 167', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } }, + 0x04a1 => { Name => 'ISOInfo', Condition => '$$self{Ver9401} =~ /^(160|164)/', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } }, + 0x04a2 => { Name => 'ISOInfo', Condition => '$$self{Ver9401} =~ /^(152|154|155)/', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } }, + 0x059d => { Name => 'ISOInfo', Condition => '$$self{Ver9401} =~ /^(144|146)/', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } }, + 0x0634 => { Name => 'ISOInfo', Condition => '$$self{Ver9401} == 68', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } }, + 0x0636 => { Name => 'ISOInfo', Condition => '$$self{Ver9401} =~ /^(73|74)/', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } }, + 0x064c => { Name => 'ISOInfo', Condition => '$$self{Ver9401} == 78', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } }, + 0x0653 => { Name => 'ISOInfo', Condition => '$$self{Ver9401} == 90', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } }, + 0x0678 => { Name => 'ISOInfo', Condition => '$$self{Ver9401} =~ /^(93|94)/', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } }, + 0x06b8 => { Name => 'ISOInfo', Condition => '$$self{Ver9401} =~ /^(100|103)/', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } }, + 0x06de => { Name => 'ISOInfo', Condition => '$$self{Ver9401} =~ /^(124|125)/', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } }, + 0x06e7 => { Name => 'ISOInfo', Condition => '$$self{Ver9401} =~ /^(127|128|130)/', Format => 'int8u[5]', SubDirectory => { TagTable => 'Image::ExifTool::Sony::ISOInfo' } }, +); + +%Image::ExifTool::Sony::ISOInfo = ( # JR + FORMAT => 'int8u', + %binaryDataAttrs, + GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, + 0x0000 => { Name => 'ISOSetting', ValueConv => \%isoSetting2010 }, + 0x0002 => { Name => 'ISOAutoMin', ValueConv => \%isoSetting2010 }, + 0x0004 => { Name => 'ISOAutoMax', ValueConv => \%isoSetting2010 }, +); + # PH (RX100) %Image::ExifTool::Sony::Tag9402 = ( PROCESS_PROC => \&ProcessEnciphered, @@ -7761,6 +8327,8 @@ my %pictureProfile2010 = ( 12 => 'Expanded Flexible Spot', #JR (HX90V, ILCE-7 series) 14 => 'Tracking', 15 => 'Face Tracking', + 20 => 'Animal Eye Tracking', +# 21 => '???', # (ILCE-7SM3) 255 => 'Manual', }, }, @@ -7826,8 +8394,8 @@ my %pictureProfile2010 = ( GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, DATAMEMBER => [ 0x04 ], 0x04 => { - # seen values 0,2,3,18,32,49,50,83,148 - # CameraTemperature is valid for all values except 0,148 + # seen values 0,2,3,18,19,32,49,50,83,130,132,148,213,229,255 + # CameraTemperature is valid for all values above except ==0 and >=130 Name => 'TempTest2', DataMember => 'TempTest2', Hidden => 1, @@ -7911,8 +8479,8 @@ my %pictureProfile2010 = ( WRITABLE => 1, FIRST_ENTRY => 0, PRIORITY => 0, - DATAMEMBER => [ 0x0604 ], GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + DATAMEMBER => [ 0x0604 ], NOTES => 'Valid for SLT, NEX, ILCE-3000/3500 and several DSC models.', 0x0600 => { Name => 'DistortionCorrParamsPresent', @@ -7926,7 +8494,7 @@ my %pictureProfile2010 = ( 1 => 'Applied', }, }, - # 0x0602 - same as 0x0604, but has value 3 for 50mm F1.4 ZA, DT 18-135mm and for 70-400mm G II: meaning ?? + # 0x0602 - same as 0x0604, but has value 3 for SAL18135, SAL50F14Z, SAL55300, SAL70200G2, SAL70300G2, SAL70400G2 0x0603 => { Name => 'LensFormat', Condition => '$$self{Model} !~ /^(DSC-|Stellar)/', @@ -7989,12 +8557,13 @@ my %pictureProfile2010 = ( WRITABLE => 1, FIRST_ENTRY => 0, PRIORITY => 0, - DATAMEMBER => [ 0x005e ], GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + DATAMEMBER => [ 0x005e ], NOTES => q{ - Valid for DSC-HX60V/HX350/HX400V/QX30/RX0/RX10/RX10M2/RX10M3/RX10M4/ - RX100M3/RX100M4/RX100M5/RX100M6/WX220/WX350, ILCE-7/7M2/7M3/7R/7RM2/ - 7S/7SM2/9/5000/5100/6000/6300/6500/QX1, ILCA-68/77M2/99M2. + Valid for DSC-HX60V/HX80/HX90V/HX99/HX350/HX400V/QX30/RX0/RX10/RX10M2/ + RX10M3/RX10M4/RX100M3/RX100M4/RX100M5/RX100M5A/RX100M6/RX100M7/WX220/WX350, + ILCE-7/7M2/7M3/7R/7RM2/7RM3/7RM4/7S/7SM2/9/9M2/5000/5100/6000/6100/6300/ + 6400/6500/6600/QX1, ILCA-68/77M2/99M2. }, 0x0004 => { Name => 'SonyISO', @@ -8031,7 +8600,7 @@ my %pictureProfile2010 = ( # also often deviating results for Sony FE 90mm F2.8 Macro G OSS ... Name => 'SonyFNumber', Format => 'int16u', - Condition => '$$self{Model} !~ /^DSC-/', + Condition => '$$self{Model} !~ /^(DSC-|ZV-)/', ValueConv => '2 ** (($val/256 - 16) / 2)', ValueConvInv => '(log($val)*2/log(2)+16)*256', PrintConv => 'sprintf("%.1f",$val)', @@ -8104,7 +8673,7 @@ my %pictureProfile2010 = ( 1 => 'Applied', }, }, - # 0x005c - same as 0x005e, but has value 3 for 50mm F1.4 ZA, DT 18-135mm and for 70-400mm G II: meaning ?? + # 0x005c - same as 0x005e, but has value 3 for SAL18135, SAL50F14Z, SAL55300, SAL70200G2, SAL70300G2, SAL70400G2 0x005d => { Name => 'LensFormat', Condition => '$$self{Model} !~ /^DSC-/', @@ -8147,7 +8716,7 @@ my %pictureProfile2010 = ( }, 0x0342 => { Name => 'LensZoomPosition', - Condition => '$$self{Model} !~ /^(ILCA-|ILCE-(7RM2|7M3|7RM3|7SM2|6500|9)|DSC-(HX90V|RX0|RX10M2|RX10M3|RX10M4|RX100M4|RX100M5|RX100M6|WX500))/', + Condition => '$$self{Model} !~ /^(ILCA-|ILCE-(7RM2|7M3|7RM3A?|7RM4A?|7SM2|6100|6300|6400|6500|6600|7C|9|9M2)|DSC-(HX80|HX90V|HX99|RX0|RX10M2|RX10M3|RX10M4|RX100M4|RX100M5|RX100M5A|RX100M6|RX100M7|WX500)|ZV-)/', Format => 'int16u', PrintConv => 'sprintf("%.0f%%",$val/10.24)', PrintConvInv => '$val=~s/ ?%$//; $val * 10.24', @@ -8157,6 +8726,13 @@ my %pictureProfile2010 = ( Condition => '$$self{Model} =~ /^(ILCA-(68|77M2)|ILCE-(5000|5100|6000|7|7R|7S|QX1)|Lusso)\b/', Format => 'int16s[16]', }, + 0x034e => { + Name => 'LensZoomPosition', + Condition => '$$self{Model} =~ /^(DSC-(RX100M5|RX100M5A|RX100M6|RX100M7|RX10M4|HX99)|ILCE-(6100|6400|6600|7C|7M3|7RM3A?|7RM4A?|9M2)|ZV-E10)/', + Format => 'int16u', + PrintConv => 'sprintf("%.0f%%",$val/10.24)', + PrintConvInv => '$val=~s/ ?%$//; $val * 10.24', + }, 0x0350 => { Name => 'VignettingCorrParams', Condition => '$$self{Model} =~ /^(ILCE-7M2)/', @@ -8164,12 +8740,12 @@ my %pictureProfile2010 = ( }, 0x035c => { Name => 'VignettingCorrParams', - Condition => '$$self{Model} =~ /^(ILCA-99M2|ILCE-(6500|7M3|7RM3|9))/', + Condition => '$$self{Model} =~ /^(ILCA-99M2|ILCE-(6100|6400|6500|6600|7C|7M3|7RM3A?|7RM4A?|9|9M2)|ZV-E10)/', Format => 'int16s[16]', }, 0x035a => { Name => 'LensZoomPosition', - Condition => '$$self{Model} =~ /^(ILCE-(7RM2|7SM2)|DSC-(HX90V|RX10M2|RX10M3|RX100M4|WX500))/', + Condition => '$$self{Model} =~ /^(ILCE-(7RM2|7SM2)|DSC-(HX80|HX90V|RX10M2|RX10M3|RX100M4|WX500))/', Format => 'int16u', PrintConv => 'sprintf("%.0f%%",$val/10.24)', PrintConvInv => '$val=~s/ ?%$//; $val * 10.24', @@ -8201,7 +8777,7 @@ my %pictureProfile2010 = ( }, 0x03b8 => { Name => 'ChromaticAberrationCorrParams', - Condition => '$$self{Model} =~ /^(ILCE-(7M3|7RM3|9))/', + Condition => '$$self{Model} =~ /^(ILCE-(6100|6400|6600|7C|7M3|7RM3A?|7RM4A?|9|9M2)|ZV-E10)/', Format => 'int16s[32]', }, ); @@ -8217,7 +8793,7 @@ my %pictureProfile2010 = ( GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, # 0x0000: 1 for SLT-A37/A57/A65/A77, NEX-5N/7/F3/VG20 # 2 for SLT-A58/99V, NEX-3N/5R/5T/6/VG30/VG900, ILCA-68/77M2, ILCE-3000/3500/7/7M2/7R/7S/5000/6000 -# 3 for ILCA-99M2, ILCE-6300/6500/7M3/7RM2/7RM3/7SM2/9 +# 3 for ILCA-99M2, ILCE-6100/6300/6400/6500/6600/7M3/7RM2/7RM3/7RM4/7SM2/9/9M2 # 0x0001+0x0002: Int16u, seen 580 - 770: similar to "BatteryUnknown" ?? # 0x0005: int8u, seen 73 - 117: maybe Fahrenheit? Higher than "AmbientTemperature", but same trend. 0x0005 => { @@ -8230,7 +8806,7 @@ my %pictureProfile2010 = ( # 0x0006: usually 0, seen non-zero values only for SLT-A99V, ILCA-77M2/99M2 and ILCE-7/7R/7RM2/9: BatteryLevel Grip ? 0x0006 => { Name => 'BatteryLevelGrip1', - Condition => '$$valPt !~ /^\x00/', # only valid when not 0 + RawConv => '$val ? $val : undef', # only valid when not 0 PrintConv => '"$val%"', PrintConvInv => '$val=~s/\s*\%//; $val', }, @@ -8245,7 +8821,8 @@ my %pictureProfile2010 = ( # but ILCE-7/7R with grip can have max 2, and as all ILCE-7/7R samples give >100 values, exclude... 0x0008 => { Name => 'BatteryLevelGrip2', - Condition => '$$valPt !~ /^[\x00\xff]/ and $$self{Model} !~ /^(ILCE-(7|7R)|Lusso)$/', # only when not 0 or 255 and not for ILCE-7/7R + Condition => '$$self{Model} !~ /^(ILCE-(7|7R)|Lusso)$/', # not valid for ILCE-7/7R + RawConv => '($val and $val != 255) ? $val : undef', # not valid if 0 or 255 PrintConv => '"$val%"', PrintConvInv => '$val=~s/\s*\%//; $val', }, @@ -8273,12 +8850,13 @@ my %pictureProfile2010 = ( PrintConv => { # verified for A77 firmware 1.03 and 1.07 and A99 firmware 1.00, # but there were inconsistencies with my A77 firmware 1.04 samples - PH - 0 => '(none)', + 0 => '(none)', # ILCA-68/77M2/99M2 always give this 0x00007801 => 'Center Zone', 0x0001821c => 'Right Zone', 0x000605c0 => 'Left Zone', - 0x7fffffff => '(all)', - # 0xffffffff - 'n/a' - RX1 and NEX models always give this + 0x0003ffff => '(all LA-EA4)', # for LA-EA4: 18 bits + 0x7fffffff => '(all)', # also for LA-EA2 + 0xffffffff => 'n/a', # DSC and ILCE/NEX models always give this, except when using LA-EA2 or LA-EA4 # (on Wide AFAreaMode, outer focus points are dropped # at progressively higher digital zoom ratios, ref JR) BITMASK => { @@ -8319,7 +8897,7 @@ my %pictureProfile2010 = ( FIRST_ENTRY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, DATAMEMBER => [ 0x0008 ], - NOTES => 'NEX and ILCE models only.', + NOTES => 'E-mount cameras only.', # 0x0001 - 0 for all NEX and ILCE-3000/3500, 20 for all other ILCE (17 for ILCE samples from Sony.net) # 0x0008 - LensMount, but different values from Tag9405-0x0105 and Tag9050-0x0604. @@ -8359,10 +8937,11 @@ my %pictureProfile2010 = ( # 1.30: NEX-5T v1.00, NEX-6 v1.02/v1.03, NEX-7 v1.03 # 1.31: ILCE-7/7R v0.95/v1.00/v1.01, ILCE-5000 # 1.40: ILCE-7/7R v1.02/v1.10, ILCE-7S v1.00, ILCE-6000 v1.00/v1.10, ILCE-5100/QX1 - # 1.50: ILCE-7/7R/7S v1.20-v3.20, ILCE-7M2 v1.00-v4.00, ILCE-7RM2 v1.00-v3.00, ILCE-7SM2 v1.00-v2.10, + # 1.50: ILCE-7/7R/7S v1.20-v3.20, ILCE-7M2, ILCE-7RM2 v1.00-v3.00, ILCE-7SM2 v1.00-v2.20, # ILCE-6000 v1.20-v3.20 # 1.60: ILCE-6300/6500, ILCE-7RM2 v3.05-v4.00 - # 1.70: ILCE-7M3/7RM3/9 + # 1.70: ILCE-7M3/7RM3, ILCE-9 v1.00-v4.10 + # 1.80: ILCE-6100/6400/6600/7RM4/9M2, ILCE-9 v5.00-v6.00 }, 0x000d => { Name => 'LensE-mountVersion', @@ -8384,11 +8963,14 @@ my %pictureProfile2010 = ( # 1.40: SEL1635Z, SEL24240, SEL35F14Z, SELP28135G, Zeiss Loxia 35mm/50mm Ver.01, Zeiss Touit Ver.02 # 1.41: SELP18105G Ver.02 # 1.50: SEL28F20, SEL90M28G, Zeiss Batis 18mm/25mm/85mm/135mm, Zeiss Loxia 21mm, Zeiss Loxia 35mm/50mm Ver.02, - # Tokina Firin 20mm - # 1.60: SEL1224G, SEL1635GM, SELP18110G, SEL18135, SEL2470GM, SEL24105G, SEL50F14Z, SEL50F18F, SEL50M28, SEL70200GM, - # SEL70300G, SEL85F14GM, SEL85F18, SEL100F28GM, SEL100400GM, Sigma 30mm F1.4 DC DN, Sigma MC-11, - # Samyang AF 14mm/50mm, Voigtlander 15mm, Sigma 16mm F1.4 DC DN - # 1.70: LA-EA3 Ver.02, Samyang AF 35mm, Tamron 28-75mm, Voigtlander 10mm/12mm/40mm/65mm, Zeiss Loxia 25mm/85mm + # Tokina FiRIN 20mm + # 1.60: SEL1224G, SEL1635GM, SEL1655G, SELP18110G, SEL18135, SEL2470GM, SEL24105G, SEL35F18F, SEL50F14Z, SEL50F18F, + # SEL50M28, SEL70200GM, SEL70300G, SEL70350G, SEL85F14GM, SEL85F18, SEL100F28GM, SEL100400GM, SEL135F18GM, + # SEL200600G, SEL600F40GM, Sigma 16F14DCDN/30F14DCDN/35F12DGDN/45F28DGDN, Sigma MC-11, Samyang AF 14mm/50mm, + # Voigtlander 15mm, Viltrox 85mm MF + # 1.70: LA-EA3 Ver.02, Samyang AF 24mm/35mm/85mm, Tamron 17-28mm, 28-75mm, Tokina FiRIN 20mm AF Ver.01, Tokina FiRIN 100mm Macro, + # Voigtlander 10mm/12mm/40mm/65mm, Zeiss Loxia 25mm/85mm, Sigma 14-24mm + # 1.80: Voigtlander 21mm }, # 0x0014 and 0x0015: change together: LensFirmwareVersion # 0x0015 as 2-digit hex matches known firmware versions of Sony lenses and Metabones adapters, @@ -8409,7 +8991,7 @@ my %pictureProfile2010 = ( ); -# AFInfo (SLT models only) (ref PH, decoded mainly from A77) +# AFInfo 0x940e (SLT models only) (ref PH, decoded mainly from A77) %Image::ExifTool::Sony::AFInfo = ( PROCESS_PROC => \&ProcessEnciphered, WRITE_PROC => \&WriteEnciphered, @@ -8420,7 +9002,7 @@ my %pictureProfile2010 = ( PRIORITY => 0, GROUPS => { 0 => 'MakerNotes', 2 => 'Camera' }, DATAMEMBER => [ 0x02 ], - IS_SUBDIR => [ 0x11 ], + IS_SUBDIR => [ 0x11, 0x7d ], NOTES => 'These tags are currently extracted for SLT models only.', # first 4 bytes (deciphered) (ref JR): # 0 1 1 0 for A37, A57, A58 @@ -8430,7 +9012,9 @@ my %pictureProfile2010 = ( # 1 1 3 0 for ILCA-68/77M2/99M2 # 0 0 0 0 for NEX and ILCE-3000/3500, also seen for SLT/ILCA with non-AF lens # 1 0 0 0 for ILCE-5000/5100/6000/7/7M2/7R/7S/QX1 - # 6 0 0 0 for ILCE-6300/6500/7M3/7RM2/7RM3/7SM2/9 + # 6 0 0 0 for ILCE-6100/6300/6400/6500/6600/7C/7M3/7RM2/7RM3/7RM4/7SM2/9/9M2 + # 9 . . . for ILCE-7SM3 + # 11 . . . for ILCE-1 # 0 2 0 0 for NEX/ILCE with LA-EA2/EA4 Phase-AF adapter # 2 0 0 0 seen for a few NEX-5N images # 2 2 0 0 seen for a few NEX-5N/7 images with LA-EA2 adapter @@ -8723,11 +9307,12 @@ my %pictureProfile2010 = ( # other NEX/ILCE: 74 blocks of 164 bytes # 0x1a06 onwards - first seen for ILCE-7RM2: appears to be some kind of metering image - 0x1a06 => { Name => 'TiffMeteringImageWidth', Condition => '$$self{Model} =~ /^(ILCE-(6300|6500|7M3|7RM2|7RM3|7SM2|9))\b/' }, - 0x1a07 => { Name => 'TiffMeteringImageHeight', Condition => '$$self{Model} =~ /^(ILCE-(6300|6500|7M3|7RM2|7RM3|7SM2|9))\b/' }, + # but not valid anymore for ILCE-6400, ILCE-9 v5.0x + 0x1a06 => { Name => 'TiffMeteringImageWidth', Condition => '$$self{Model} =~ /^(ILCE-(6300|6500|7M3|7RM2|7RM3A?|7SM2|9))\b/ and $$self{Software} !~ /^ILCE-9 (v5.0|v6.0)/' }, + 0x1a07 => { Name => 'TiffMeteringImageHeight', Condition => '$$self{Model} =~ /^(ILCE-(6300|6500|7M3|7RM2|7RM3A?|7SM2|9))\b/ and $$self{Software} !~ /^ILCE-9 (v5.0|v6.0)/' }, 0x1a08 => { # (2640 bytes: 1 set of 44x30 int16u values) Name => 'TiffMeteringImage', - Condition => '$$self{Model} =~ /^(ILCE-(6300|6500|7M3|7RM2|7RM3|7SM2|9))\b/', + Condition => '$$self{Model} =~ /^(ILCE-(6300|6500|7M3|7RM2|7RM3A?|7SM2|9))\b/ and $$self{Software} !~ /^ILCE-9 (v5.0|v6.0)/', Format => 'undef[2640]', Notes => q{ 13(?)-bit intensity data from 1320 (1200) metering segments, extracted as a @@ -8933,6 +9518,159 @@ my %pictureProfile2010 = ( 0xbc => { Name => 'AFStatus_94_E6_Center_F2-8', %Image::ExifTool::Minolta::afStatusInfo }, ); +# tag 0x9416 decoding (ref JR) +%Image::ExifTool::Sony::Tag9416 = ( + PROCESS_PROC => \&ProcessEnciphered, + WRITE_PROC => \&WriteEnciphered, + CHECK_PROC => \&Image::ExifTool::CheckBinaryData, + FORMAT => 'int8u', + NOTES => 'Valid for the ILCE-1/7M4/7SM3, ILME-FX3.', + FIRST_ENTRY => 0, + GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, + 0x0000 => { Name => 'Tag9416_0000', PrintConv => 'sprintf("%3d",$val)', RawConv => '$$self{TagVersion} = $val' }, + 0x0004 => { + Name => 'SonyISO', + Format => 'int16u', + ValueConv => '100 * 2**(16 - $val/256)', + ValueConvInv => '256 * (16 - log($val/100)/log(2))', + PrintConv => 'sprintf("%.0f",$val)', + PrintConvInv => '$val', + }, + 0x0006 => { %gain2010 }, + 0x000a => { # appr. same value as Exif ExposureTime, but shorter in HDR-modes + Name => 'SonyExposureTime2', + Format => 'int16u', + ValueConv => '$val ? 2 ** (16 - $val/256) : 0', + ValueConvInv => '$val ? int((16 - log($val) / log(2)) * 256 + 0.5) : 0', + PrintConv => '$val ? Image::ExifTool::Exif::PrintExposureTime($val) : "Bulb"', + PrintConvInv => 'lc($val) eq "bulb" ? 0 : Image::ExifTool::Exif::ConvertFraction($val)', + }, + 0x000c => { + Name => 'ExposureTime', + Format => 'rational32u', + PrintConv => '$val ? Image::ExifTool::Exif::PrintExposureTime($val) : "Bulb"', # (Bulb NC) + PrintConvInv => 'lc($val) eq "bulb" ? 0 : $val', + }, + 0x0010 => { # but sometimes deviating results + Name => 'SonyFNumber2', + Format => 'int16u', + ValueConv => '2 ** (($val/256 - 16) / 2)', + ValueConvInv => '(log($val)*2/log(2)+16)*256', + PrintConv => 'sprintf("%.1f",$val)', + PrintConvInv => '$val', + }, + 0x0012 => { + Name => 'SonyMaxApertureValue', # (at current focal length) + Format => 'int16u', + ValueConv => '2 ** (($val/256 - 16) / 2)', + ValueConvInv => '(log($val)*2/log(2)+16)*256', + PrintConv => 'sprintf("%.1f",$val)', + PrintConvInv => '$val', + }, + 0x001d => { %sequenceImageNumber }, + 0x0035 => { + Name => 'ExposureProgram', + Priority => 0, + SeparateTable => 'ExposureProgram3', + PrintConv => \%sonyExposureProgram3, + }, + 0x0048 => { + Name => 'LensMount', + Condition => '$$self{Model} !~ /^(DSC-)/', + PrintConv => { + 0 => 'Unknown', + 1 => 'A-mount', + 2 => 'E-mount', + 3 => 'A-mount (3)', + }, + }, + 0x0049 => { + Name => 'LensFormat', + Condition => '$$self{Model} !~ /^(DSC-)/', + PrintConv => { + 0 => 'Unknown', + 1 => 'APS-C', + 2 => 'Full-frame', + }, + }, + 0x004a => { + Name => 'LensMount', + DataMember => 'LensMount', + RawConv => '$$self{LensMount} = $val; $$self{Model} =~ /^(DSC-)/ ? undef : $val', + PrintConv => { + 0 => 'Unknown', + 1 => 'A-mount', + 2 => 'E-mount', + }, + }, + 0x004b => { + Name => 'LensType2', + Condition => '$$self{LensMount} == 2', + Format => 'int16u', + SeparateTable => 'LensType2', + PrintConv => \%sonyLensTypes2, + }, + 0x004d => { + Name => 'LensType', + Condition => '$$self{LensMount} == 1', + Priority => 0, #PH (just to be safe) + Format => 'int16u', #PH + SeparateTable => 1, + ValueConvInv => '($val & 0xff00) == 0x8000 ? 0 : int($val)', + PrintConv => \%sonyLensTypes, + }, + 0x004f => { + Name => 'DistortionCorrParams', + Format => 'int16s[16]', + }, + 0x0070 => { %pictureProfile2010 }, #IB + 0x0071 => { + Name => 'FocalLength', + Format => 'int16u', + ValueConv => '$val / 10', + ValueConvInv => '$val * 10', + PrintConv => 'sprintf("%.1f mm",$val)', + PrintConvInv => '$val =~ s/ ?mm//; $val', + }, + 0x0073 => { + Name => 'MinFocalLength', + Format => 'int16u', + ValueConv => '$val / 10', + ValueConvInv => '$val * 10', + PrintConv => 'sprintf("%.1f mm",$val)', + PrintConvInv => '$val =~ s/ ?mm//; $val', + }, + 0x0075 => { # may give 0 for fixed focal length lenses + Name => 'MaxFocalLength', + Format => 'int16u', + RawConv => '$val || undef', + ValueConv => '$val / 10', + ValueConvInv => '$val * 10', + PrintConv => 'sprintf("%.1f mm",$val)', + PrintConvInv => '$val =~ s/ ?mm//; $val', + }, + 0x088f => { + Name => 'VignettingCorrParams', + Condition => '$$self{Model} !~ /^(ILCE-7M4)/', + Format => 'int16s[16]', + }, + 0x0891 => { + Name => 'VignettingCorrParams', + Condition => '$$self{Model} =~ /^(ILCE-7M4)/', + Format => 'int16s[16]', + }, + 0x0914 => { + Name => 'ChromaticAberrationCorrParams', + Condition => '$$self{Model} !~ /^(ILCE-7M4)/', + Format => 'int16s[32]', + }, + 0x0916 => { + Name => 'ChromaticAberrationCorrParams', + Condition => '$$self{Model} =~ /^(ILCE-7M4)/', + Format => 'int16s[32]', + }, +); + %Image::ExifTool::Sony::FaceInfo1 = ( %binaryDataAttrs, GROUPS => { 0 => 'MakerNotes', 2 => 'Image' }, @@ -9206,20 +9944,22 @@ my %pictureProfile2010 = ( WRITE_PROC => \&Image::ExifTool::Exif::WriteExif, CHECK_PROC => \&Image::ExifTool::Exif::CheckExif, GROUPS => { 0 => 'MakerNotes', 1 => 'SR2SubIFD', 2 => 'Camera' }, + WRITE_GROUP => 'SR2SubIFD', + PERMANENT => 1, SET_GROUP1 => 1, # set group1 name to directory name for all tags in table NOTES => 'Tags in the encrypted SR2SubIFD', - 0x7300 => 'BlackLevel', #IB (R1) - 0x7302 => 'WB_GRBGLevelsAuto', #IB (R1) - 0x7303 => 'WB_GRBGLevels', #1 (R1 "as shot", ref IB) - 0x7310 => 'BlackLevel', #IB (divide by 4) - 0x7312 => 'WB_RGGBLevelsAuto', #IB - 0x7313 => 'WB_RGGBLevels', #6 - 0x7480 => 'WB_RGBLevelsDaylight', #IB (R1) - 0x7481 => 'WB_RGBLevelsCloudy', #IB (R1) - 0x7482 => 'WB_RGBLevelsTungsten', #IB (R1) - 0x7483 => 'WB_RGBLevelsFlash', #IB (R1) - 0x7484 => 'WB_RGBLevels4500K', #IB (R1) - 0x7486 => 'WB_RGBLevelsFluorescent', #IB (R1) + 0x7300 => { Name => 'BlackLevel', Writable => 'int16u', Count => 4, Protected => 1 }, + 0x7302 => { Name => 'WB_GRBGLevelsAuto', Writable => 'int16s', Count => 4, Protected => 1 }, #IB (R1) + 0x7303 => { Name => 'WB_GRBGLevels', Writable => 'int16s', Count => 4, Protected => 1 }, #1 (R1 "as shot", ref IB) + 0x7310 => { Name => 'BlackLevel', Writable => 'int16u', Count => 4, Protected => 1 }, #IB (divide by 4) + 0x7312 => { Name => 'WB_RGGBLevelsAuto', Writable => 'int16s', Count => 4, Protected => 1 }, #IB + 0x7313 => { Name => 'WB_RGGBLevels', Writable => 'int16s', Count => 4, Protected => 1 }, #6 + 0x7480 => { Name => 'WB_RGBLevelsDaylight', Writable => 'int16s', Count => 4, Protected => 1 }, #IB (R1) + 0x7481 => { Name => 'WB_RGBLevelsCloudy', Writable => 'int16s', Count => 4, Protected => 1 }, #IB (R1) + 0x7482 => { Name => 'WB_RGBLevelsTungsten', Writable => 'int16s', Count => 4, Protected => 1 }, #IB (R1) + 0x7483 => { Name => 'WB_RGBLevelsFlash', Writable => 'int16s', Count => 4, Protected => 1 }, #IB (R1) + 0x7484 => { Name => 'WB_RGBLevels4500K', Writable => 'int16s', Count => 4, Protected => 1 }, #IB (R1) + 0x7486 => { Name => 'WB_RGBLevelsFluorescent', Writable => 'int16s', Count => 4, Protected => 1 }, #IB (R1) 0x74a0 => 'MaxApertureAtMaxFocal', #PH 0x74a1 => 'MaxApertureAtMinFocal', #PH 0x74a2 => { #IB (R1) @@ -9241,21 +9981,21 @@ my %pictureProfile2010 = ( }, }, 0x7800 => 'ColorMatrix', #IB (divide by 1024) - 0x7820 => 'WB_RGBLevelsDaylight', #6 (or 5300K, ref IB) - 0x7821 => 'WB_RGBLevelsCloudy', #6 (or 6100K, ref IB) - 0x7822 => 'WB_RGBLevelsTungsten', #6 - 0x7823 => 'WB_RGBLevelsFlash', #IB - 0x7824 => 'WB_RGBLevels4500K', #IB - 0x7825 => 'WB_RGBLevelsShade', #6 (or 7500K, ref IB) - 0x7826 => 'WB_RGBLevelsFluorescent', #6 (~4000K) - 0x7827 => 'WB_RGBLevelsFluorescentP1', #IB (~5000K) - 0x7828 => 'WB_RGBLevelsFluorescentP2', #IB (~6500K) (was Flash, ref 6) - 0x7829 => 'WB_RGBLevelsFluorescentM1', #IB (~3500K) - 0x782a => 'WB_RGBLevels8500K', #IB - 0x782b => 'WB_RGBLevels6000K', #IB - 0x782c => 'WB_RGBLevels3200K', #IB - 0x782d => 'WB_RGBLevels2500K', #IB - 0x787f => 'WhiteLevel', #IB (divide by 4) + 0x7820 => { Name => 'WB_RGBLevelsDaylight', Writable => 'int16s', Count => 3, Protected => 1 }, #6 (or 5300K, ref IB) + 0x7821 => { Name => 'WB_RGBLevelsCloudy', Writable => 'int16s', Count => 3, Protected => 1 }, #6 (or 6100K, ref IB) + 0x7822 => { Name => 'WB_RGBLevelsTungsten', Writable => 'int16s', Count => 3, Protected => 1 }, #6 + 0x7823 => { Name => 'WB_RGBLevelsFlash', Writable => 'int16s', Count => 3, Protected => 1 }, #IB + 0x7824 => { Name => 'WB_RGBLevels4500K', Writable => 'int16s', Count => 3, Protected => 1 }, #IB + 0x7825 => { Name => 'WB_RGBLevelsShade', Writable => 'int16s', Count => 3, Protected => 1 }, #6 (or 7500K, ref IB) + 0x7826 => { Name => 'WB_RGBLevelsFluorescent', Writable => 'int16s', Count => 3, Protected => 1 }, #6 (~4000K) + 0x7827 => { Name => 'WB_RGBLevelsFluorescentP1', Writable => 'int16s', Count => 3, Protected => 1 }, #IB (~5000K) + 0x7828 => { Name => 'WB_RGBLevelsFluorescentP2', Writable => 'int16s', Count => 3, Protected => 1 }, #IB (~6500K) (was Flash, ref 6) + 0x7829 => { Name => 'WB_RGBLevelsFluorescentM1', Writable => 'int16s', Count => 3, Protected => 1 }, #IB (~3500K) + 0x782a => { Name => 'WB_RGBLevels8500K', Writable => 'int16s', Count => 3, Protected => 1 }, #IB + 0x782b => { Name => 'WB_RGBLevels6000K', Writable => 'int16s', Count => 3, Protected => 1 }, #IB + 0x782c => { Name => 'WB_RGBLevels3200K', Writable => 'int16s', Count => 3, Protected => 1 }, #IB + 0x782d => { Name => 'WB_RGBLevels2500K', Writable => 'int16s', Count => 3, Protected => 1 }, #IB + 0x787f => { Name => 'WhiteLevel', Writable => 'int16u', Count => 3, Protected => 1 }, #IB (divide by 4) 0x797d => 'VignettingCorrParams', #forum7640 0x7980 => 'ChromaticAberrationCorrParams', #forum6509 (Sony A7 ARW) 0x7982 => 'DistortionCorrParams', #forum6509 (Sony A7 ARW) @@ -9307,7 +10047,7 @@ my %pictureProfile2010 = ( ValueConv => 'length($val) > 12 ? substr($val,0,12) : $val', }, # 'EvA:' - exposure compensation * 10 (ref JR) - # for documentation only -- this IFD is handled manually + # IFD: for documentation only -- this IFD is handled manually IFD => { Name => 'PIC_IFD', SubDirectory => { TagTable => 'Image::ExifTool::Sony::Main' }, @@ -9417,7 +10157,7 @@ my %pictureProfile2010 = ( GROUPS => { 2 => 'Video' }, NOTES => q{ These tags are extracted from the 'rtmd' timed metadata of MP4 videos from - some models when the ExtractEmbedded option is used. + some models when the L<ExtractEmbedded|../ExifTool.html#ExtractEmbedded> option is used. }, # 0x060e - 16 bytes starting with 0x060e2b340253 (fake tag ID - comes before 0x8300 container) 0x060e => { Name => 'Sony_rtmd_0x060e', Format => 'int8u', %hidUnk }, @@ -9425,22 +10165,132 @@ my %pictureProfile2010 = ( 0x3210 => { Name => 'Sony_rtmd_0x3210', Format => 'int8u', %hidUnk }, 0x3219 => { Name => 'Sony_rtmd_0x3219', Format => 'int8u', %hidUnk }, 0x321a => { Name => 'Sony_rtmd_0x321a', Format => 'int8u', %hidUnk }, - 0x8000 => { Name => 'Sony_rtmd_0x8000', Format => 'int16u', %hidUnk }, + 0x8000 => { #forum12218 + Name => 'FNumber', + Format => 'int16u', + ValueConv => '2 ** (8-$val/8192)', + PrintConv => 'Image::ExifTool::Exif::PrintFNumber($val)', + }, 0x8001 => { Name => 'Sony_rtmd_0x8001', Format => 'int16u', %hidUnk }, + 0x8004 => { Name => 'Sony_rtmd_0x8004', Format => 'int16u', %hidUnk }, + 0x8005 => { Name => 'Sony_rtmd_0x8005', Format => 'int16u', %hidUnk }, + 0x800a => { Name => 'Sony_rtmd_0x800a', Format => 'int16u', %hidUnk }, + 0x800b => { Name => 'Sony_rtmd_0x800b', Format => 'int16u', %hidUnk }, # 0x8100 - 16 bytes starting with 0x060e2b340401 0x8100 => { Name => 'Sony_rtmd_0x8100', Format => 'int8u', %hidUnk }, 0x8101 => { Name => 'Sony_rtmd_0x8101', Format => 'int8u', %hidUnk }, # seen: 0,1 - 0x8109 => { Name => 'Sony_rtmd_0x8109', Format => 'int32u', %hidUnk }, # seen: "1 50" - 0x810a => { Name => 'Sony_rtmd_0x810a', Format => 'int16u', %hidUnk }, # seen: 0 - 0x810b => { Name => 'Sony_rtmd_0x810b', Format => 'int16u', %hidUnk }, # seen: 100 - 0x810c => { Name => 'Sony_rtmd_0x810c', Format => 'int16u', %hidUnk }, # seen: 100 - 0x810d => { Name => 'Sony_rtmd_0x810d', Format => 'int8u', %hidUnk }, # seen: 1 + 0x8104 => { Name => 'Sony_rtmd_0x8104', Format => 'int16u', %hidUnk }, # seen: 35616 + 0x8105 => { Name => 'Sony_rtmd_0x8105', Format => 'int16u', %hidUnk }, # seen: 20092 + 0x8106 => { Name => 'Sony_rtmd_0x8106', Format => 'int32u', %hidUnk }, # seen: "25 1","24000 1001" frame rate? + 0x8109 => { #forum12218 + Name => 'ExposureTime', + Format => 'rational64u', + PrintConv => 'Image::ExifTool::Exif::PrintExposureTime($val)', + }, + 0x810a => { #PH (NC, based on samples from forum12218) + Name => 'MasterGainAdjustment', + Format => 'int16u', + ValueConv => '$val / 100', + PrintConv => 'sprintf("%.2f dB", $val)', + }, + 0x810b => { Name => 'ISO', Format => 'int16u' }, #forum12218 + 0x810c => { #PH (NC, based on samples from forum12218) + Name => 'ElectricalExtenderMagnification', + Format => 'int16u', + }, + 0x810d => { Name => 'Sony_rtmd_0x810d', Format => 'int8u', %hidUnk }, # seen: 0,1 + 0x8115 => { Name => 'Sony_rtmd_0x8115', Format => 'int16u', %hidUnk }, # seen: 100 # 0x8300 - container for other tags in this format + 0x8500 => { + Name => 'GPSVersionID', + Groups => { 2 => 'Location' }, + Format => 'int8u', + PrintConv => '$val =~ tr/ /./; $val', + }, + 0x8501 => { + Name => 'GPSLatitudeRef', + Groups => { 2 => 'Location' }, + Format => 'string', + PrintConv => { + N => 'North', + S => 'South', + }, + }, + 0x8502 => { + Name => 'GPSLatitude', + Groups => { 2 => 'Location' }, + Format => 'rational64u', + ValueConv => 'require Image::ExifTool::GPS;Image::ExifTool::GPS::ToDegrees($val)', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1)', + }, + 0x8503 => { + Name => 'GPSLongitudeRef', + Groups => { 2 => 'Location' }, + Format => 'string', + PrintConv => { + E => 'East', + W => 'West', + }, + }, + 0x8504 => { + Name => 'GPSLongitude', + Groups => { 2 => 'Location' }, + Format => 'rational64u', + ValueConv => 'require Image::ExifTool::GPS;Image::ExifTool::GPS::ToDegrees($val)', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1)', + }, + 0x8507 => { + Name => 'GPSTimeStamp', + Groups => { 2 => 'Time' }, + Format => 'rational64u', + ValueConv => 'require Image::ExifTool::GPS;Image::ExifTool::GPS::ConvertTimeStamp($val)', + PrintConv => 'Image::ExifTool::GPS::PrintTimeStamp($val)', + }, + 0x8509 => { + Name => 'GPSStatus', + Groups => { 2 => 'Location' }, + Format => 'string', + PrintConv => { + A => 'Measurement Active', + V => 'Measurement Void', + }, + }, + 0x850a => { + Name => 'GPSMeasureMode', + Groups => { 2 => 'Location' }, + Format => 'string', + PrintConv => { + 2 => '2-Dimensional Measurement', + 3 => '3-Dimensional Measurement', + }, + }, + 0x8512 => { + Name => 'GPSMapDatum', + Groups => { 2 => 'Location' }, + Format => 'string', + }, + 0x851d => { + Name => 'GPSDateStamp', + Groups => { 2 => 'Time' }, + Format => 'string', + ValueConv => 'Image::ExifTool::Exif::ExifDate($val)', + }, 0xe000 => { Name => 'Sony_rtmd_0xe000', Format => 'int8u', %hidUnk }, # (16 bytes) 0xe300 => { Name => 'Sony_rtmd_0xe300', Format => 'int8u', %hidUnk }, # seen: 0,1 - 0xe301 => { Name => 'Sony_rtmd_0xe301', Format => 'int32u', %hidUnk }, # seen: 100 + 0xe301 => { Name => 'Sony_rtmd_0xe301', Format => 'int32u', %hidUnk }, # seen: 100,1600,12800 0xe302 => { Name => 'Sony_rtmd_0xe302', Format => 'int8u', %hidUnk }, # seen: 1 - 0xe303 => { Name => 'Sony_rtmd_0xe303', Format => 'int8u', %hidUnk }, # seen: 255 + 0xe303 => { #forum12218 + Name => 'WhiteBalance', + Format => 'int8u', + PrintConv => { + 1 => 'Incandescent', + 2 => 'Fluorescent', + 4 => 'Daylight', + 5 => 'Cloudy', + 6 => 'Custom', # ("Shade" uses this value too) + 255 => 'Preset', + }, + }, 0xe304 => { Name => 'DateTime', Groups => { 2 => 'Time' }, @@ -9448,6 +10298,21 @@ my %pictureProfile2010 = ( ValueConv => 'my @a=unpack("x1H4H2H2H2H2H2",$val); "$a[0]:$a[1]:$a[2] $a[3]:$a[4]:$a[5]"', PrintConv => '$self->ConvertDateTime($val)', }, + 0xe435 => { Name => 'Sony_rtmd_0xe435', Format => 'int32u', %hidUnk }, # seen: 2000 + 0xe437 => { Name => 'Sony_rtmd_0xe437', Format => 'int32s', %hidUnk }, # seen: -3800 to -3400 + 0xe43b => { + Name => 'PitchRollYaw', + Format => 'int16s', + RawConv => 'substr($val, 8)', + }, + 0xe445 => { Name => 'Sony_rtmd_0xe445', Format => 'int32u', %hidUnk }, # seen: 2000 + 0xe44b => { + Name => 'Accelerometer', # (NC) + Format => 'int16s', + RawConv => 'substr($val, 8)', + }, + # f010 - 2048 bytes + # f020 - 543 bytes ); # Composite Sony tags @@ -9466,7 +10331,7 @@ my %pictureProfile2010 = ( # For DSLR-A550 and newer, NEX/ILCE/SLT/ILCA (only A65V/A77V are missing ...): # seen FocusPosition2 with values from 80 - 255 (and 21 for Touit 12mm...) # Formula from minolta.pm (WBInfoA100 - 0x49bb) gives mostly correct/acceptable distance indications. - # (http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3688.0.html) + # (https://exiftool.org/forum/index.php/topic,3688.0.html) # if this value is the 35mm equivalent magnification, then the formula could # be (1.5 * 2**($val/16-5)+1) * FocalLength, but this tends to underestimate # distance by about 18% (ref 20) (255=inf) @@ -9482,6 +10347,37 @@ my %pictureProfile2010 = ( }, PrintConv => '$val eq "inf" ? $val : sprintf("%.2f m",$val)', }, + GPSDateTime => { + Description => 'GPS Date/Time', + Groups => { 2 => 'Time' }, + SubDoc => 1, # generate for all sub-documents + Require => { + 0 => 'Sony:GPSDateStamp', + 1 => 'Sony:GPSTimeStamp', + }, + ValueConv => '"$val[0] $val[1]Z"', + PrintConv => '$self->ConvertDateTime($val)', + }, + GPSLatitude => { + SubDoc => 1, # generate for all sub-documents + Groups => { 2 => 'Location' }, + Require => { + 0 => 'Sony:GPSLatitude', + 1 => 'Sony:GPSLatitudeRef', + }, + ValueConv => '$val[1] =~ /^S/i ? -$val[0] : $val[0]', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', + }, + GPSLongitude => { + SubDoc => 1, # generate for all sub-documents + Groups => { 2 => 'Location' }, + Require => { + 0 => 'Sony:GPSLongitude', + 1 => 'Sony:GPSLongitudeRef', + }, + ValueConv => '$val[1] =~ /^W/i ? -$val[0] : $val[0]', + PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', + }, ); # add our composite tags @@ -9980,7 +10876,7 @@ sub Decrypt($$$$) } #------------------------------------------------------------------------------ -# Decipher/encipher Sony tag 0x94xx data (ref PH) +# Decipher/encipher Sony tag 0x2010, 0x900b, 0x9050 and 0x940x data (ref PH) # Inputs: 0) data reference, 1) true to encipher the data sub Decipher($;$) { @@ -10402,7 +11298,7 @@ Minolta. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/SonyIDC.pm b/src/Image-ExifTool/lib/Image/ExifTool/SonyIDC.pm index c512fb45..33f51522 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/SonyIDC.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/SonyIDC.pm @@ -379,7 +379,7 @@ write Sony Image Data Converter version 3.0 metadata in ARW images. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Stim.pm b/src/Image-ExifTool/lib/Image/ExifTool/Stim.pm index 3c82e49d..d51a2811 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Stim.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Stim.pm @@ -21,8 +21,8 @@ $VERSION = '1.01'; NOTES => q{ These tags are part of the CIPA Stereo Still Image specification, and are found in the APP3 "Stim" segment of JPEG images. See - L<http://www.cipa.jp/std/documents/e/DC-006_E.pdf> for the - official specification. + L<https://web.archive.org/web/20190718152459/http://www.cipa.jp/std/documents/e/DC-006_E.pdf> + for the official specification. }, 0 => 'StimVersion', 1 => { @@ -174,7 +174,7 @@ information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/TagInfoXML.pm b/src/Image-ExifTool/lib/Image/ExifTool/TagInfoXML.pm index 6a6c10d9..fbbacb7b 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/TagInfoXML.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/TagInfoXML.pm @@ -15,7 +15,7 @@ use vars qw($VERSION @ISA $makeMissing); use Image::ExifTool qw(:Utils :Vars); use Image::ExifTool::XMP; -$VERSION = '1.30'; +$VERSION = '1.32'; @ISA = qw(Exporter); # set this to a language code to generate Lang module with 'MISSING' entries @@ -28,7 +28,7 @@ sub NumbersFirst; # names for acknowledgements in the POD documentation my %credits = ( cs => 'Jens Duttke and Petr MichE<aacute>lek', - de => 'Jens Duttke and Herbert Kauer', + de => 'Jens Duttke, Herbert Kauer and Jobi', es => 'Jens Duttke, Santiago del BrE<iacute>o GonzE<aacute>lez and Emilio Sancha', fi => 'Jens Duttke and Jarkko ME<auml>kineva', fr => 'Jens Duttke, Bernard Guillotin, Jean Glasser, Jean Piquemal, Harry Nizard and Alphonse Philippe', @@ -37,7 +37,7 @@ my %credits = ( ko => 'Jens Duttke and Jeong Beom Kim', nl => 'Jens Duttke, Peter Moonen, Herman Beld and Peter van der Laan', pl => 'Jens Duttke, Przemyslaw Sulek and Kacper Perschke', - ru => 'Jens Duttke, Sergey Shemetov, Dmitry Yerokhin and Anton Sukhinov', + ru => 'Jens Duttke, Sergey Shemetov, Dmitry Yerokhin, Anton Sukhinov and Alexander', sv => 'Jens Duttke and BjE<ouml>rn SE<ouml>derstrE<ouml>m', 'tr' => 'Jens Duttke, Hasan Yildirim and Cihan Ulusoy', zh_cn => 'Jens Duttke and Haibing Zhong', @@ -58,6 +58,12 @@ my %translateLang = ( my $numbersFirst = 1; # set to -1 to sort numbers last, or 2 to put negative numbers last my $caseInsensitive; # used internally by sort routine +# write groups that don't represent real family 1 group names +my %fakeWriteGroup = ( + Comment => 1, # (JPEG Comment) + colr => 1, # (Jpeg2000 'colr' box) +); + #------------------------------------------------------------------------------ # Utility to print tag information database as an XML list # Inputs: 0) output file name (undef to send to console), @@ -67,9 +73,9 @@ sub Write(;$$%) { local ($_, *PTIFILE); my ($file, $group, %opts) = @_; - my @groups = split ':', $group if $group; my $et = new Image::ExifTool; - my ($fp, $tableName, %langInfo, @langs, $defaultLang); + my ($fp, $tableName, %langInfo, @langs, $defaultLang, @groups); + @groups = split ':', $group if $group; Image::ExifTool::LoadAllTables(); # first load all our tables unless ($opts{NoDesc}) { @@ -164,6 +170,7 @@ PTILoop: for ($index=0; $index<@infoArray; ++$index) { $format = 'struct' if $$tagInfo{Struct}; if (defined $format) { $format =~ s/\[.*\$.*\]//; # remove expressions from format + $format = 'undef' if $format eq '2'; # (special case) } elsif ($isBinary) { $format = 'int8u'; } else { @@ -177,9 +184,8 @@ PTILoop: for ($index=0; $index<@infoArray; ++$index) { } my @groups = $et->GetGroup($tagInfo); my $writeGroup = $$tagInfo{WriteGroup} || $$table{WRITE_GROUP}; - if ($writeGroup and $writeGroup ne 'Comment') { - $groups[1] = $writeGroup; # use common write group for group 1 - } + # use common write group for group 1 (unless fake) + $groups[1] = $writeGroup if $writeGroup and not $fakeWriteGroup{$writeGroup}; # add group names if different from table defaults my $grp = ''; for ($fam=0; $fam<3; ++$fam) { @@ -366,7 +372,12 @@ sub BuildLangModules($;$) $id = Image::ExifTool::XMP::FullUnescapeXML($1); $name = $2; $index = $4; - $id = hex($id) if $id =~ /^0x[\da-fA-F]+$/; # convert hex ID's + # convert hex ID's unless HEX_ID is 0 (for string ID's that look like hex) + if ($id =~ /^0x[\da-fA-F]+$/ and (not defined $$table{VARS} or + not defined $$table{VARS}{HEX_ID} or $$table{VARS}{HEX_ID})) + { + $id = hex($id); + } next; } if ($tok eq 'values') { @@ -619,7 +630,6 @@ HEADER 1; # end - __END__ ~head1 NAME @@ -633,7 +643,7 @@ and values. ~head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. @@ -817,7 +827,7 @@ Number of modules updated, or negative on error. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/TagLookup.pm b/src/Image-ExifTool/lib/Image/ExifTool/TagLookup.pm index c29fcdf7..9baaba1e 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/TagLookup.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/TagLookup.pm @@ -17,7 +17,7 @@ require Exporter; use vars qw($VERSION @ISA @EXPORT_OK); use Image::ExifTool qw(:Utils); -$VERSION = '1.16'; +$VERSION = '1.18'; @ISA = qw(Exporter); @EXPORT_OK = qw(FindTagInfo TagExists); @@ -38,6 +38,7 @@ my @tableList = ( 'Image::ExifTool::Canon::AFMicroAdj', 'Image::ExifTool::Canon::Ambience', 'Image::ExifTool::Canon::AspectInfo', + 'Image::ExifTool::Canon::CNTH', 'Image::ExifTool::Canon::CameraInfo1000D', 'Image::ExifTool::Canon::CameraInfo1D', 'Image::ExifTool::Canon::CameraInfo1DX', @@ -72,6 +73,8 @@ my @tableList = ( 'Image::ExifTool::Canon::ColorCoefs', 'Image::ExifTool::Canon::ColorCoefs2', 'Image::ExifTool::Canon::ColorData1', + 'Image::ExifTool::Canon::ColorData10', + 'Image::ExifTool::Canon::ColorData11', 'Image::ExifTool::Canon::ColorData2', 'Image::ExifTool::Canon::ColorData3', 'Image::ExifTool::Canon::ColorData4', @@ -92,6 +95,7 @@ my @tableList = ( 'Image::ExifTool::Canon::HDRInfo', 'Image::ExifTool::Canon::LensInfo', 'Image::ExifTool::Canon::LightingOpt', + 'Image::ExifTool::Canon::LogInfo', 'Image::ExifTool::Canon::Main', 'Image::ExifTool::Canon::MeasuredColor', 'Image::ExifTool::Canon::ModifiedInfo', @@ -103,11 +107,13 @@ my @tableList = ( 'Image::ExifTool::Canon::Panorama', 'Image::ExifTool::Canon::PreviewImageInfo', 'Image::ExifTool::Canon::Processing', + 'Image::ExifTool::Canon::RawBurstInfo', 'Image::ExifTool::Canon::SerialInfo', 'Image::ExifTool::Canon::ShotInfo', 'Image::ExifTool::Canon::TimeInfo', 'Image::ExifTool::Canon::VignettingCorr', 'Image::ExifTool::Canon::VignettingCorr2', + 'Image::ExifTool::Canon::WBInfo', 'Image::ExifTool::CanonCustom::Functions10D', 'Image::ExifTool::CanonCustom::Functions1D', 'Image::ExifTool::CanonCustom::Functions2', @@ -161,6 +167,7 @@ my @tableList = ( 'Image::ExifTool::IPTC::EnvelopeRecord', 'Image::ExifTool::IPTC::NewsPhoto', 'Image::ExifTool::JFIF::Main', + 'Image::ExifTool::Jpeg2000::ColorSpec', 'Image::ExifTool::Jpeg2000::Main', 'Image::ExifTool::Kodak::CameraInfo', 'Image::ExifTool::Kodak::IFD', @@ -176,6 +183,8 @@ my @tableList = ( 'Image::ExifTool::Kodak::Type2', 'Image::ExifTool::Kodak::Type3', 'Image::ExifTool::Kodak::Type4', + 'Image::ExifTool::Kodak::Type5', + 'Image::ExifTool::Kodak::Type6', 'Image::ExifTool::Kodak::Type7', 'Image::ExifTool::Kodak::Type9', 'Image::ExifTool::MIE::Audio', @@ -202,6 +211,7 @@ my @tableList = ( 'Image::ExifTool::Microsoft::MP1', 'Image::ExifTool::Microsoft::Stitch', 'Image::ExifTool::Microsoft::XMP', + 'Image::ExifTool::Microsoft::Xtra', 'Image::ExifTool::Minolta::CameraInfoA100', 'Image::ExifTool::Minolta::CameraSettings', 'Image::ExifTool::Minolta::CameraSettings5D', @@ -216,6 +226,7 @@ my @tableList = ( 'Image::ExifTool::Motorola::Main', 'Image::ExifTool::Nikon::AFInfo', 'Image::ExifTool::Nikon::AFInfo2', + 'Image::ExifTool::Nikon::AFInfo2V0400', 'Image::ExifTool::Nikon::AFTune', 'Image::ExifTool::Nikon::BarometerInfo', 'Image::ExifTool::Nikon::CaptureOutput', @@ -235,6 +246,7 @@ my @tableList = ( 'Image::ExifTool::Nikon::FlashInfo0103', 'Image::ExifTool::Nikon::FlashInfo0106', 'Image::ExifTool::Nikon::FlashInfo0107', + 'Image::ExifTool::Nikon::FlashInfo0300', 'Image::ExifTool::Nikon::GEM', 'Image::ExifTool::Nikon::HDRInfo', 'Image::ExifTool::Nikon::ISOInfo', @@ -242,11 +254,18 @@ my @tableList = ( 'Image::ExifTool::Nikon::LensData01', 'Image::ExifTool::Nikon::LensData0204', 'Image::ExifTool::Nikon::LensData0400', + 'Image::ExifTool::Nikon::LensData0402', + 'Image::ExifTool::Nikon::LensData0403', + 'Image::ExifTool::Nikon::LensData0800', 'Image::ExifTool::Nikon::LocationInfo', 'Image::ExifTool::Nikon::Main', + 'Image::ExifTool::Nikon::MakerNotes0x51', + 'Image::ExifTool::Nikon::MenuSettingsZ7II', + 'Image::ExifTool::Nikon::MenuSettingsZ9', 'Image::ExifTool::Nikon::MultiExposure', 'Image::ExifTool::Nikon::PictureControl', 'Image::ExifTool::Nikon::PictureControl2', + 'Image::ExifTool::Nikon::PictureControl3', 'Image::ExifTool::Nikon::PreviewIFD', 'Image::ExifTool::Nikon::ROC', 'Image::ExifTool::Nikon::RetouchInfo', @@ -265,6 +284,7 @@ my @tableList = ( 'Image::ExifTool::Nikon::ShotInfoD5000', 'Image::ExifTool::Nikon::ShotInfoD5100', 'Image::ExifTool::Nikon::ShotInfoD5200', + 'Image::ExifTool::Nikon::ShotInfoD6', 'Image::ExifTool::Nikon::ShotInfoD700', 'Image::ExifTool::Nikon::ShotInfoD7000', 'Image::ExifTool::Nikon::ShotInfoD80', @@ -272,6 +292,8 @@ my @tableList = ( 'Image::ExifTool::Nikon::ShotInfoD810', 'Image::ExifTool::Nikon::ShotInfoD850', 'Image::ExifTool::Nikon::ShotInfoD90', + 'Image::ExifTool::Nikon::ShotInfoZ7II', + 'Image::ExifTool::Nikon::ShotInfoZ9', 'Image::ExifTool::Nikon::Type2', 'Image::ExifTool::Nikon::VRInfo', 'Image::ExifTool::Nikon::WorldTime', @@ -305,6 +327,7 @@ my @tableList = ( 'Image::ExifTool::NikonCustom::SettingsD810', 'Image::ExifTool::NikonCustom::SettingsD850', 'Image::ExifTool::NikonCustom::SettingsD90', + 'Image::ExifTool::NikonCustom::SettingsZ9', 'Image::ExifTool::Nintendo::CameraInfo', 'Image::ExifTool::Olympus::CameraSettings', 'Image::ExifTool::Olympus::Equipment', @@ -381,12 +404,18 @@ my @tableList = ( 'Image::ExifTool::Photoshop::Main', 'Image::ExifTool::Photoshop::Resolution', 'Image::ExifTool::PostScript::Main', + 'Image::ExifTool::QuickTime::ItemList', + 'Image::ExifTool::QuickTime::ItemPropCont', + 'Image::ExifTool::QuickTime::Keys', + 'Image::ExifTool::QuickTime::Main', 'Image::ExifTool::QuickTime::MediaHeader', 'Image::ExifTool::QuickTime::MovieHeader', 'Image::ExifTool::QuickTime::Preview', 'Image::ExifTool::QuickTime::TrackHeader', + 'Image::ExifTool::QuickTime::UserData', 'Image::ExifTool::Reconyx::Main', 'Image::ExifTool::Reconyx::Type2', + 'Image::ExifTool::Reconyx::Type3', 'Image::ExifTool::Ricoh::FaceInfo', 'Image::ExifTool::Ricoh::FirmwareInfo', 'Image::ExifTool::Ricoh::ImageInfo', @@ -401,6 +430,8 @@ my @tableList = ( 'Image::ExifTool::Sanyo::FaceInfo', 'Image::ExifTool::Sanyo::Main', 'Image::ExifTool::Sigma::Main', + 'Image::ExifTool::Sigma::WBSettings', + 'Image::ExifTool::Sigma::WBSettings2', 'Image::ExifTool::Sony::AFInfo', 'Image::ExifTool::Sony::AFStatus15', 'Image::ExifTool::Sony::AFStatus19', @@ -420,6 +451,7 @@ my @tableList = ( 'Image::ExifTool::Sony::FaceInfo2', 'Image::ExifTool::Sony::FaceInfoA', 'Image::ExifTool::Sony::FocusInfo', + 'Image::ExifTool::Sony::ISOInfo', 'Image::ExifTool::Sony::Main', 'Image::ExifTool::Sony::MeterInfo', 'Image::ExifTool::Sony::MeterInfo9', @@ -427,6 +459,7 @@ my @tableList = ( 'Image::ExifTool::Sony::MoreInfo0401', 'Image::ExifTool::Sony::MoreSettings', 'Image::ExifTool::Sony::Panorama', + 'Image::ExifTool::Sony::SR2SubIFD', 'Image::ExifTool::Sony::ShotInfo', 'Image::ExifTool::Sony::Tag2010a', 'Image::ExifTool::Sony::Tag2010b', @@ -440,6 +473,7 @@ my @tableList = ( 'Image::ExifTool::Sony::Tag202a', 'Image::ExifTool::Sony::Tag9050a', 'Image::ExifTool::Sony::Tag9050b', + 'Image::ExifTool::Sony::Tag9050c', 'Image::ExifTool::Sony::Tag9400a', 'Image::ExifTool::Sony::Tag9400b', 'Image::ExifTool::Sony::Tag9400c', @@ -456,8 +490,11 @@ my @tableList = ( 'Image::ExifTool::SonyIDC::Main', 'Image::ExifTool::XMP::Album', 'Image::ExifTool::XMP::DICOM', + 'Image::ExifTool::XMP::Device', 'Image::ExifTool::XMP::ExpressionMedia', 'Image::ExifTool::XMP::GAudio', + 'Image::ExifTool::XMP::GCamera', + 'Image::ExifTool::XMP::GCreations', 'Image::ExifTool::XMP::GDepth', 'Image::ExifTool::XMP::GFocus', 'Image::ExifTool::XMP::GImage', @@ -473,6 +510,7 @@ my @tableList = ( 'Image::ExifTool::XMP::aux', 'Image::ExifTool::XMP::cc', 'Image::ExifTool::XMP::cell', + 'Image::ExifTool::XMP::crd', 'Image::ExifTool::XMP::creatorAtom', 'Image::ExifTool::XMP::crs', 'Image::ExifTool::XMP::dc', @@ -508,5350 +546,6575 @@ my @tableList = ( # lookup for all writable tags my %tagLookup = ( - 'aberrationcorrectiondistance' => { 103 => 0x69 }, - 'about' => { 460 => 'about' }, - 'aboutcvterm' => { 452 => 'AboutCvTerm' }, - 'aboutcvtermcvid' => { 452 => [\'AboutCvTerm','AboutCvTermCvId'] }, - 'aboutcvtermid' => { 452 => [\'AboutCvTerm','AboutCvTermCvTermId'] }, - 'aboutcvtermname' => { 452 => [\'AboutCvTerm','AboutCvTermCvTermName'] }, - 'aboutcvtermrefinedabout' => { 452 => [\'AboutCvTerm','AboutCvTermCvTermRefinedAbout'] }, - 'absolutealtitude' => { 110 => 'AbsoluteAltitude' }, - 'abspeakaudiofilepath' => { 466 => 'absPeakAudioFilePath' }, - 'academicfield' => { 456 => 'academicField' }, - 'acceleration' => { 113 => 0x9404, 447 => 'Acceleration' }, - 'accelerationtracking' => { 78 => 0x518 }, + 'aberrationcorrectiondistance' => { 109 => 0x69 }, + 'about' => { 498 => 'about' }, + 'aboutcvterm' => { 490 => 'AboutCvTerm' }, + 'aboutcvtermcvid' => { 490 => [\'AboutCvTerm','AboutCvTermCvId'] }, + 'aboutcvtermid' => { 490 => [\'AboutCvTerm','AboutCvTermCvTermId'] }, + 'aboutcvtermname' => { 490 => [\'AboutCvTerm','AboutCvTermCvTermName'] }, + 'aboutcvtermrefinedabout' => { 490 => [\'AboutCvTerm','AboutCvTermCvTermRefinedAbout'] }, + 'absolutealtitude' => { 116 => 'AbsoluteAltitude' }, + 'abspeakaudiofilepath' => { 504 => 'absPeakAudioFilePath' }, + 'academicfield' => { 494 => 'academicField' }, + 'acceleration' => { 119 => 0x9404, 485 => 'Acceleration' }, + 'accelerationtracking' => { 84 => 0x518 }, 'accelerationvector' => { 1 => 0x8 }, - 'accelerometer' => { 361 => 0x3 }, - 'accelerometerx' => { 297 => 0x8d }, - 'accelerometery' => { 297 => 0x8e }, - 'accelerometerz' => { 297 => 0x8c }, - 'accessoryserialnumber' => { 297 => 0x54 }, - 'accessorytype' => { 297 => 0x53 }, - 'actionadvised' => { 125 => 0x2a }, - 'activearea' => { 113 => 0xc68d }, - 'actived-lighting' => { 211 => 0x22, 248 => 0x24 }, - 'actived-lightingmode' => { 248 => 0x25 }, - 'adaptervoltage' => { 131 => 0x407 }, - 'addaspectratioinfo' => { 78 => 0x80e }, - 'addiptcinformation' => { 78 => 0x815 }, - 'additionalmodelinformation' => { 452 => 'AddlModelInfo' }, - 'addoriginaldecisiondata' => { 78 => 0x80f, 79 => 0x11, 80 => 0x13, 83 => 0x14 }, - 'address' => { 152 => 'Address' }, - 'adjustmentmode' => { 368 => 0x15 }, - 'adlbracketingstep' => { 229 => 0x883 }, - 'adlbracketingtype' => { 229 => 0x884 }, - 'adobe' => { 114 => 'Adobe' }, - 'adultcontentwarning' => { 284 => 'AdultContentWarning', 459 => 'adultContentWarning' }, - 'advancedfilter' => { 121 => 0x1201 }, - 'advancedraw' => { 250 => 0x76a43203 }, - 'advancedscenetype' => { 297 => 0x3d }, - 'advisory' => { 464 => 'Advisory' }, - 'ae_iso' => { 305 => 0x2, 306 => 0x4, 307 => 0x12 }, - 'aeaperture' => { 305 => 0x1, 306 => 0x3, 307 => 0x11 }, - 'aeaperturesteps' => { 305 => 0x8, 306 => 0xb }, - 'aebautocancel' => { 78 => 0x104 }, - 'aebbracketvalue' => { 72 => 0x11 }, - 'aebracketingsteps' => { 228 => 0x174c, 229 => 0x87b, 237 => 0x1756 }, - 'aebsequence' => { 78 => 0x105 }, - 'aebsequenceautocancel' => { 76 => 0x9, 77 => 0x9, 79 => 0x8, 80 => 0x9, 83 => 0x9, 84 => 0x7 }, - 'aebshotcount' => { 78 => 0x106 }, - 'aebxv' => { 305 => 0x4, 306 => 0x6 }, - 'aeerror' => { 306 => 0x8 }, - 'aeexposuretime' => { 305 => 0x0, 306 => 0x2, 307 => 0x10 }, - 'aelbutton' => { 174 => 0x45 }, - 'aelexposureindicator' => { 174 => 0x51 }, - 'aelock' => { 174 => 0x5b, 259 => '4.2', 268 => '4.2', 274 => 0x201, 332 => 0x48, 376 => 0x40, 377 => 0x40, 378 => [0x86,0x286] }, - 'aelockbutton' => { 257 => '16.1', 259 => '4.1', 262 => '15.1', 263 => '16.1', 264 => '16.1', 266 => '30.1', 267 => '16.1', 268 => '4.1', 270 => '17.1', 272 => '17.1' }, - 'aelockbuttonplusdials' => { 257 => '16.2', 266 => '32.1', 270 => '44.1' }, - 'aelockformb-d80' => { 272 => '3.1' }, - 'aelockmetermodeafterfocus' => { 78 => 0x114 }, - 'aemaxaperture' => { 305 => 0x9, 306 => 0x10, 307 => 0x1c }, - 'aemaxaperture2' => { 305 => 0xa, 306 => 0x11, 307 => 0x1d }, - 'aemeteringmode' => { 305 => 0xc }, - 'aemeteringmode2' => { 305 => '13.1' }, - 'aemeteringsegments' => { 177 => 0x628, 332 => 0x209 }, - 'aemicroadjustment' => { 78 => 0x110 }, - 'aeminaperture' => { 305 => 0xb, 306 => 0x12, 307 => 0x1e }, - 'aeminexposuretime' => { 305 => 0x5, 306 => 0x13, 307 => 0x1f }, - 'aeprogrammode' => { 305 => 0x6 }, - 'aeprojectlink' => { 441 => 'aeProjectLink' }, - 'aeprojectlinkcompositionid' => { 441 => [\'aeProjectLink','aeProjectLinkCompositionID'] }, - 'aeprojectlinkfullpath' => { 441 => [\'aeProjectLink','aeProjectLinkFullPath'] }, - 'aeprojectlinkrenderoutputmoduleindex' => { 441 => [\'aeProjectLink','aeProjectLinkRenderOutputModuleIndex'] }, - 'aeprojectlinkrenderqueueitemid' => { 441 => [\'aeProjectLink','aeProjectLinkRenderQueueItemID'] }, - 'aeprojectlinkrendertimestamp' => { 441 => [\'aeProjectLink','aeProjectLinkRenderTimeStamp'] }, - 'aesetting' => { 33 => 0x21 }, - 'aewhitebalance' => { 305 => 0xd }, - 'aexv' => { 305 => 0x3, 306 => 0x5 }, - 'af-cpriority' => { 122 => '0.2' }, - 'af-cpriorityselection' => { 257 => '1.1', 258 => '1.1', 260 => '1.1', 261 => '1.1', 263 => '0.1', 264 => '0.1', 265 => '0.1', 266 => '1.1', 267 => '0.1', 270 => '1.1', 271 => '1.1' }, - 'af-csetting' => { 118 => 0x0 }, - 'af-cspeedtrackingsensitivity' => { 118 => '0.2' }, - 'af-ctrackingsensitivity' => { 118 => '0.1' }, - 'af-czoneareaswitching' => { 118 => '0.3' }, - 'af-onbutton' => { 260 => '70.1', 261 => '70.1', 271 => '70.1' }, - 'af-onformb-d10' => { 257 => '3.3', 266 => '3.2' }, - 'af-onformb-d11' => { 267 => '2.2' }, - 'af-onformb-d12' => { 270 => '50.1' }, - 'af-spriority' => { 122 => '0.1' }, - 'af-spriorityselection' => { 257 => '1.2', 258 => '1.2', 260 => '1.4', 261 => '1.4', 265 => '0.2', 266 => '1.2', 267 => '0.2', 270 => '1.2', 271 => '1.2' }, + 'accelerometer' => { 390 => 0x3 }, + 'accelerometerdata' => { 380 => 'vrot' }, + 'accelerometerx' => { 320 => 0x8d }, + 'accelerometery' => { 320 => 0x8e }, + 'accelerometerz' => { 320 => 0x8c }, + 'accessoryserialnumber' => { 320 => 0x54 }, + 'accessorytype' => { 320 => 0x53 }, + 'actionadvised' => { 131 => 0x2a }, + 'activearea' => { 119 => 0xc68d }, + 'actived-lighting' => { 226 => 0x22, 270 => 0x24 }, + 'actived-lightingmode' => { 270 => 0x25 }, + 'adaptervoltage' => { 138 => 0x407 }, + 'addaspectratioinfo' => { 84 => 0x80e }, + 'addiptcinformation' => { 84 => 0x815 }, + 'additionalmodelinformation' => { 490 => 'AddlModelInfo' }, + 'addoriginaldecisiondata' => { 84 => 0x80f, 85 => 0x11, 86 => 0x13, 89 => 0x14 }, + 'address' => { 161 => 'Address' }, + 'adjustmentmode' => { 397 => 0x15 }, + 'adlbracketingstep' => { 248 => 0x883 }, + 'adlbracketingtype' => { 248 => 0x884 }, + 'adobe' => { 120 => 'Adobe' }, + 'adultcontentwarning' => { 307 => 'AdultContentWarning', 497 => 'adultContentWarning' }, + 'advancedfilter' => { 127 => 0x1201 }, + 'advancedraw' => { 272 => 0x76a43203 }, + 'advancedscenetype' => { 320 => 0x3d }, + 'advisory' => { 502 => 'Advisory' }, + 'ae_iso' => { 328 => 0x2, 329 => 0x4, 330 => 0x12 }, + 'aeaperture' => { 328 => 0x1, 329 => 0x3, 330 => 0x11 }, + 'aeaperturesteps' => { 328 => 0x8, 329 => 0xb }, + 'aebautocancel' => { 84 => 0x104 }, + 'aebbracketvalue' => { 77 => 0x11 }, + 'aebracketingsteps' => { 247 => 0x174c, 248 => 0x87b, 257 => 0x1756 }, + 'aebsequence' => { 84 => 0x105 }, + 'aebsequenceautocancel' => { 82 => 0x9, 83 => 0x9, 85 => 0x8, 86 => 0x9, 89 => 0x9, 90 => 0x7 }, + 'aebshotcount' => { 84 => 0x106 }, + 'aebxv' => { 328 => 0x4, 329 => 0x6 }, + 'aeerror' => { 329 => 0x8 }, + 'aeexposuretime' => { 328 => 0x0, 329 => 0x2, 330 => 0x10 }, + 'aelbutton' => { 184 => 0x45 }, + 'aelexposureindicator' => { 184 => 0x51 }, + 'aelock' => { 184 => 0x5b, 281 => '4.2', 290 => '4.2', 297 => 0x201, 355 => 0x48, 407 => 0x40, 408 => 0x40, 409 => [0x86,0x286] }, + 'aelockbutton' => { 279 => '16.1', 281 => '4.1', 284 => '15.1', 285 => '16.1', 286 => '16.1', 288 => '30.1', 289 => '16.1', 290 => '4.1', 292 => '17.1', 294 => '17.1' }, + 'aelockbuttonplusdials' => { 279 => '16.2', 288 => '32.1', 292 => '44.1' }, + 'aelockformb-d80' => { 294 => '3.1' }, + 'aelockmetermodeafterfocus' => { 84 => 0x114 }, + 'aemaxaperture' => { 328 => 0x9, 329 => 0x10, 330 => 0x1c }, + 'aemaxaperture2' => { 328 => 0xa, 329 => 0x11, 330 => 0x1d }, + 'aemeteringmode' => { 328 => 0xc }, + 'aemeteringmode2' => { 328 => '13.1' }, + 'aemeteringsegments' => { 187 => 0x628, 355 => 0x209 }, + 'aemicroadjustment' => { 84 => 0x110 }, + 'aeminaperture' => { 328 => 0xb, 329 => 0x12, 330 => 0x1e }, + 'aeminexposuretime' => { 328 => 0x5, 329 => 0x13, 330 => 0x1f }, + 'aeprogrammode' => { 328 => 0x6 }, + 'aeprojectlink' => { 479 => 'aeProjectLink' }, + 'aeprojectlinkcompositionid' => { 479 => [\'aeProjectLink','aeProjectLinkCompositionID'] }, + 'aeprojectlinkfullpath' => { 479 => [\'aeProjectLink','aeProjectLinkFullPath'] }, + 'aeprojectlinkrenderoutputmoduleindex' => { 479 => [\'aeProjectLink','aeProjectLinkRenderOutputModuleIndex'] }, + 'aeprojectlinkrenderqueueitemid' => { 479 => [\'aeProjectLink','aeProjectLinkRenderQueueItemID'] }, + 'aeprojectlinkrendertimestamp' => { 479 => [\'aeProjectLink','aeProjectLinkRenderTimeStamp'] }, + 'aesetting' => { 34 => 0x21 }, + 'aewhitebalance' => { 328 => 0xd }, + 'aexv' => { 328 => 0x3, 329 => 0x5 }, + 'af-assistilluminator' => { 295 => 0x19 }, + 'af-cfocusdisplay' => { 295 => 0x234 }, + 'af-cpriority' => { 128 => '0.2' }, + 'af-cpriorityselection' => { 279 => '1.1', 280 => '1.1', 282 => '1.1', 283 => '1.1', 285 => '0.1', 286 => '0.1', 287 => '0.1', 288 => '1.1', 289 => '0.1', 292 => '1.1', 293 => '1.1', 295 => 0x3 }, + 'af-csetting' => { 124 => 0x0 }, + 'af-cspeedtrackingsensitivity' => { 124 => '0.2' }, + 'af-ctrackingsensitivity' => { 124 => '0.1' }, + 'af-czoneareaswitching' => { 124 => '0.3' }, + 'af-onbutton' => { 282 => '70.1', 283 => '70.1', 293 => '70.1' }, + 'af-onformb-d10' => { 279 => '3.3', 288 => '3.2' }, + 'af-onformb-d11' => { 289 => '2.2' }, + 'af-onformb-d12' => { 292 => '50.1' }, + 'af-onoutoffocusrelease' => { 295 => 0x10 }, + 'af-spriority' => { 128 => '0.1' }, + 'af-spriorityselection' => { 279 => '1.2', 280 => '1.2', 282 => '1.2', 283 => '1.2', 287 => '0.2', 288 => '1.2', 289 => '0.2', 292 => '1.2', 293 => '1.2', 295 => 0x5 }, 'afacceldeceltracking' => { 2 => 0x3 }, - 'afactivation' => { 257 => '2.1', 258 => '2.1', 260 => '78.3', 261 => '78.3', 266 => '2.1', 270 => '2.1', 271 => '78.3' }, - 'afadjustment' => { 332 => 0x72, 341 => 0x267 }, - 'afandmeteringbuttons' => { 78 => 0x701 }, - 'afaperture' => { 207 => 0x5, 208 => 0x5 }, - 'afareaheight' => { 183 => [0x1a,0x50] }, - 'afareaillumination' => { 174 => 0x4b, 268 => '15.3' }, - 'afareamode' => { 120 => '0.2', 170 => 0x33, 174 => 0xe, 182 => 0x0, 183 => 0x5, 297 => 0xf, 358 => 0x1205, 369 => [0xa,0x3a], 376 => 0x11, 377 => 0x10, 378 => 0x24, 388 => 0xb043, 411 => 0x17 }, - 'afareamodesetting' => { 259 => '11.1', 262 => '0.1', 268 => '16.1', 272 => '2.1', 388 => 0x201c }, - 'afareapointsize' => { 120 => '0.3' }, - 'afareas' => { 274 => 0x304 }, + 'afactivation' => { 279 => '2.1', 280 => '2.1', 282 => '78.3', 283 => '78.3', 288 => '2.1', 292 => '2.1', 293 => '78.3', 295 => 0xf }, + 'afadjustment' => { 355 => 0x72, 364 => 0x267 }, + 'afandmeteringbuttons' => { 84 => 0x701 }, + 'afaperture' => { 219 => 0x5, 220 => 0x5, 224 => 0x5 }, + 'afareaheight' => { 193 => [0x1a,0x34,0x50], 194 => 0x48 }, + 'afareaillumination' => { 184 => 0x4b, 290 => '15.3' }, + 'afareamode' => { 126 => '0.3', 180 => 0x33, 184 => 0xe, 192 => 0x0, 193 => 0x5, 229 => 0x210, 320 => 0xf, 387 => 0x1205, 400 => [0xa,0x3a], 407 => 0x11, 408 => 0x10, 409 => 0x24, 420 => 0xb043, 445 => 0x17 }, + 'afareamodesetting' => { 281 => '11.1', 284 => '0.1', 290 => '16.1', 294 => '2.1', 420 => 0x201c }, + 'afareapointsize' => { 126 => '0.4' }, + 'afareas' => { 297 => 0x304 }, 'afareaselectionmethod' => { 2 => 0xd }, - 'afareaselectmethod' => { 78 => 0x51b }, - 'afareawidth' => { 183 => [0x18,0x4e] }, - 'afareaxposition' => { 183 => [0x14,0x4a], 358 => 0x1203 }, - 'afareaxposition1' => { 358 => 0x1201 }, - 'afareayposition' => { 183 => [0x16,0x4c], 358 => 0x1204 }, - 'afareayposition1' => { 358 => 0x1202 }, - 'afareazonesize' => { 120 => '0.4' }, - 'afassist' => { 76 => 0x5, 84 => 0x5, 174 => 0x48, 257 => '2.5', 259 => '0.2', 262 => '0.2', 263 => '1.1', 264 => '1.1', 265 => '1.3', 266 => '2.4', 267 => '1.3', 268 => '0.2', 270 => '2.4', 272 => '2.3' }, - 'afassistbeam' => { 2 => 0x8, 78 => 0x50e, 79 => 0x4, 80 => 0x5, 81 => 0x4, 82 => 0x4, 83 => 0x5 }, - 'afassistlamp' => { 297 => 0x31 }, - 'afbuttonpressed' => { 378 => [0x83,0x283] }, + 'afareaselectmethod' => { 84 => 0x51b }, + 'afareawidth' => { 193 => [0x18,0x32,0x4e], 194 => 0x46 }, + 'afareaxposition' => { 193 => [0x14,0x2e,0x4a], 387 => 0x1203 }, + 'afareaxposition1' => { 387 => 0x1201 }, + 'afareayposition' => { 193 => [0x16,0x30,0x4c], 387 => 0x1204 }, + 'afareayposition1' => { 387 => 0x1202 }, + 'afareazonesize' => { 126 => '0.5' }, + 'afassist' => { 82 => 0x5, 90 => 0x5, 184 => 0x48, 279 => '2.5', 281 => '0.2', 284 => '0.2', 285 => '1.1', 286 => '1.1', 287 => '1.3', 288 => '2.4', 289 => '1.3', 290 => '0.2', 292 => '2.4', 294 => '2.3' }, + 'afassistbeam' => { 2 => 0x8, 84 => 0x50e, 85 => 0x4, 86 => 0x5, 87 => 0x4, 88 => 0x4, 89 => 0x5 }, + 'afassistlamp' => { 320 => 0x31 }, + 'afbuttonpressed' => { 409 => [0x83,0x283] }, 'afconfigtool' => { 2 => 0x1 }, - 'afdefocus' => { 308 => 0x6 }, - 'afduringliveview' => { 78 => 0x511 }, - 'affinea' => { 435 => 'AffineA' }, - 'affineb' => { 435 => 'AffineB' }, - 'affinec' => { 435 => 'AffineC' }, - 'affined' => { 435 => 'AffineD' }, - 'affinetune' => { 184 => 0x0, 274 => 0x306 }, - 'affinetuneadj' => { 184 => 0x2, 221 => 0x2d1, 222 => 0x2dc, 274 => 0x307 }, - 'affinetuneindex' => { 184 => 0x1 }, - 'affinex' => { 435 => 'AffineX' }, - 'affiney' => { 435 => 'AffineY' }, - 'afhold' => { 308 => 0x1fd }, - 'afilluminator' => { 376 => 0x29, 388 => 0xb044 }, - 'afimageheight' => { 183 => [0x12,0x48] }, - 'afimagewidth' => { 183 => [0x10,0x46] }, - 'afintegrationtime' => { 308 => 0x7 }, - 'afmicroadj' => { 369 => [0x17d,0x50] }, - 'afmicroadjmode' => { 3 => 0x1, 373 => 0x131 }, - 'afmicroadjregisteredlenses' => { 373 => '305.1' }, - 'afmicroadjustment' => { 78 => 0x507 }, - 'afmicroadjvalue' => { 3 => 0x2, 373 => 0x130 }, - 'afmode' => { 107 => 0x3009, 121 => 0x1022, 170 => 0x16, 368 => 0x5 }, - 'afmoderestrictions' => { 258 => '50.3', 260 => '48.3', 261 => '48.3', 270 => '48.3', 271 => '48.3' }, - 'afonaelockbuttonswitch' => { 78 => 0x702 }, - 'afonbutton' => { 257 => '3.1', 258 => '47.1' }, - 'afpoint' => { 33 => 0x13, 106 => 0x18, 170 => 0x15, 182 => 0x1, 277 => 0x308, 368 => 0x1f, 369 => [0x37,0x7], 373 => 0x19, 374 => 0x18, 375 => [0x18,0x20] }, - 'afpointactivationarea' => { 77 => 0x11, 83 => 0x11 }, - 'afpointareaexpansion' => { 78 => 0x508 }, - 'afpointatshutterrelease' => { 369 => [0x39,0x9] }, - 'afpointautoselection' => { 78 => 0x50b }, - 'afpointbrightness' => { 78 => 0x50d, 257 => '2.4', 258 => '46.5', 260 => '2.2', 261 => '2.2', 270 => '2.3', 271 => '2.2' }, - 'afpointdisplayduringfocus' => { 2 => 0x10, 78 => 0x50c }, - 'afpointillumination' => { 77 => 0xa, 257 => '2.3', 258 => '46.2', 260 => '47.2', 261 => '47.2', 265 => '1.2', 266 => '2.3', 267 => '1.2', 270 => '47.2', 271 => '47.2', 272 => '2.4' }, - 'afpointinfocus' => { 369 => [0x38,0x8] }, - 'afpointmode' => { 313 => 0x3 }, - 'afpointposition' => { 107 => 0x2021, 297 => 0x4d }, - 'afpointregistration' => { 76 => 0x7 }, - 'afpoints' => { 173 => 0x10 }, - 'afpointselected' => { 174 => 0xd, 274 => 0x305, 332 => 0xe, 373 => 0x15, 374 => 0x14, 375 => [0x14,0x1c], 388 => 0x201e }, - 'afpointselected2' => { 313 => 0x4 }, - 'afpointselection' => { 77 => 0xb, 257 => '1.3', 258 => '1.3', 266 => '1.3', 270 => '1.3', 271 => '1.3' }, - 'afpointselectionmethod' => { 78 => 0x50f, 79 => 0xc, 80 => 0xd, 83 => 0xd }, - 'afpointsetting' => { 376 => 0x12, 377 => 0x11 }, - 'afpointsinfocus' => { 72 => 0xe, 182 => 0x2, 308 => 0xb, 309 => 0x4, 332 => [0xf,0x3c] }, - 'afpointsinfocus5d' => { 18 => 0x38 }, - 'afpointspotmetering' => { 77 => 0xd }, - 'afpointsselected' => { 309 => '4.1', 419 => 0x4 }, - 'afpointsspecial' => { 309 => '4.2' }, - 'afpointsunknown1' => { 308 => 0x0 }, - 'afpointsunknown2' => { 308 => 0x2 }, - 'afpointsused' => { 183 => 0x8, 369 => [0x10,0x16e] }, + 'afdefocus' => { 331 => 0x6 }, + 'afduringliveview' => { 84 => 0x511 }, + 'affinea' => { 472 => 'AffineA' }, + 'affineb' => { 472 => 'AffineB' }, + 'affinec' => { 472 => 'AffineC' }, + 'affined' => { 472 => 'AffineD' }, + 'affinetune' => { 195 => 0x0, 229 => 0x5b0, 297 => 0x306 }, + 'affinetuneadj' => { 195 => 0x2, 240 => 0x2d1, 241 => 0x2dc, 297 => 0x307 }, + 'affinetuneadjtele' => { 195 => 0x3 }, + 'affinetuneindex' => { 195 => 0x1 }, + 'affinex' => { 472 => 'AffineX' }, + 'affiney' => { 472 => 'AffineY' }, + 'affocuspointxposition' => { 193 => 0x2f }, + 'affocuspointyposition' => { 193 => 0x31 }, + 'afhold' => { 331 => 0x1fd }, + 'afilluminator' => { 407 => 0x29, 420 => 0xb044 }, + 'afimageheight' => { 193 => [0x12,0x2c,0x48], 194 => 0x40 }, + 'afimagewidth' => { 193 => [0x10,0x2a,0x46], 194 => 0x3e }, + 'afintegrationtime' => { 331 => 0x7 }, + 'afmicroadj' => { 400 => [0x17d,0x50] }, + 'afmicroadjmode' => { 3 => 0x1, 404 => 0x131 }, + 'afmicroadjregisteredlenses' => { 404 => '305.1' }, + 'afmicroadjustment' => { 84 => 0x507 }, + 'afmicroadjvalue' => { 3 => 0x2, 404 => 0x130 }, + 'afmode' => { 113 => 0x3009, 127 => 0x1022, 180 => 0x16, 397 => 0x5 }, + 'afmoderestrictions' => { 280 => '50.3', 282 => '48.3', 283 => '48.3', 292 => '48.3', 293 => '48.3' }, + 'afonaelockbuttonswitch' => { 84 => 0x702 }, + 'afonbutton' => { 279 => '3.1', 280 => '47.1', 295 => 0x83 }, + 'afpoint' => { 34 => 0x13, 112 => 0x18, 180 => 0x15, 192 => 0x1, 300 => 0x308, 397 => 0x1f, 400 => [0x37,0x7], 404 => 0x19, 405 => 0x18, 406 => [0x18,0x20] }, + 'afpointactivationarea' => { 83 => 0x11, 89 => 0x11 }, + 'afpointareaexpansion' => { 84 => 0x508 }, + 'afpointatshutterrelease' => { 400 => [0x39,0x9] }, + 'afpointautoselection' => { 84 => 0x50b }, + 'afpointbrightness' => { 84 => 0x50d, 279 => '2.4', 280 => '46.5', 282 => '2.2', 283 => '2.2', 292 => '2.3', 293 => '2.2' }, + 'afpointdisplayduringfocus' => { 2 => 0x10, 84 => 0x50c }, + 'afpointillumination' => { 83 => 0xa, 279 => '2.3', 280 => '46.2', 282 => '47.2', 283 => '47.2', 287 => '1.2', 288 => '2.3', 289 => '1.2', 292 => '47.2', 293 => '47.2', 294 => '2.4' }, + 'afpointinfocus' => { 400 => [0x38,0x8] }, + 'afpointmode' => { 336 => 0x3 }, + 'afpointposition' => { 113 => 0x2021, 320 => 0x4d }, + 'afpointregistration' => { 82 => 0x7 }, + 'afpoints' => { 183 => 0x10 }, + 'afpointsel' => { 295 => 0xb }, + 'afpointselected' => { 184 => 0xd, 297 => 0x305, 355 => 0xe, 404 => 0x15, 405 => 0x14, 406 => [0x14,0x1c], 420 => 0x201e }, + 'afpointselected2' => { 336 => 0x4 }, + 'afpointselection' => { 83 => 0xb, 279 => '1.3', 280 => '1.3', 288 => '1.3', 292 => '1.3', 293 => '1.3' }, + 'afpointselectionmethod' => { 84 => 0x50f, 85 => 0xc, 86 => 0xd, 89 => 0xd }, + 'afpointsetting' => { 407 => 0x12, 408 => 0x11 }, + 'afpointsinfocus' => { 77 => 0xe, 192 => 0x2, 193 => 0x30, 331 => 0xb, 332 => 0x4, 355 => [0xf,0x3c] }, + 'afpointsinfocus5d' => { 19 => 0x38 }, + 'afpointspotmetering' => { 83 => 0xd }, + 'afpointsselected' => { 193 => 0x1c, 332 => '4.1', 453 => 0x4 }, + 'afpointsspecial' => { 332 => '4.2' }, + 'afpointsunknown1' => { 331 => 0x0 }, + 'afpointsunknown2' => { 331 => 0x2 }, + 'afpointsused' => { 193 => [0xa,0x8], 400 => [0x10,0x16e] }, 'afpointswitching' => { 2 => 0x4 }, - 'afpredictor' => { 308 => 0x4 }, - 'afresponse' => { 211 => 0xad }, - 'afresult' => { 279 => 0x1038 }, - 'afsearch' => { 274 => 0x303 }, - 'afsensoractive' => { 170 => 0x1 }, - 'afstatus' => { 358 => 0x1200 }, - 'afstatus_00_b4' => { 372 => 0x0 }, - 'afstatus_01_c4' => { 372 => 0x2 }, - 'afstatus_02_d4' => { 372 => 0x4 }, - 'afstatus_03_e4' => { 372 => 0x6 }, - 'afstatus_04_f4' => { 372 => 0x8 }, - 'afstatus_05_g4' => { 372 => 0xa }, - 'afstatus_06_h4' => { 372 => 0xc }, - 'afstatus_07_b3' => { 372 => 0xe }, - 'afstatus_08_c3' => { 372 => 0x10 }, - 'afstatus_09_d3' => { 372 => 0x12 }, - 'afstatus_10_e3' => { 372 => 0x14 }, - 'afstatus_11_f3' => { 372 => 0x16 }, - 'afstatus_12_g3' => { 372 => 0x18 }, - 'afstatus_13_h3' => { 372 => 0x1a }, - 'afstatus_14_b2' => { 372 => 0x1c }, - 'afstatus_15_c2' => { 372 => 0x1e }, - 'afstatus_16_d2' => { 372 => 0x20 }, - 'afstatus_17_e2' => { 372 => 0x22 }, - 'afstatus_18_f2' => { 372 => 0x24 }, - 'afstatus_19_g2' => { 372 => 0x26 }, - 'afstatus_20_h2' => { 372 => 0x28 }, - 'afstatus_21_c1' => { 372 => 0x2a }, - 'afstatus_22_d1' => { 372 => 0x2c }, - 'afstatus_23_e1' => { 372 => 0x2e }, - 'afstatus_24_f1' => { 372 => 0x30 }, - 'afstatus_25_g1' => { 372 => 0x32 }, - 'afstatus_26_a7_vertical' => { 372 => 0x34 }, - 'afstatus_27_a6_vertical' => { 372 => 0x36 }, - 'afstatus_28_a5_vertical' => { 372 => 0x38 }, - 'afstatus_29_c7_vertical' => { 372 => 0x3a }, - 'afstatus_30_c6_vertical' => { 372 => 0x3c }, - 'afstatus_31_c5_vertical' => { 372 => 0x3e }, - 'afstatus_32_e7_vertical' => { 372 => 0x40 }, - 'afstatus_33_e6_center_vertical' => { 372 => 0x42 }, - 'afstatus_34_e5_vertical' => { 372 => 0x44 }, - 'afstatus_35_g7_vertical' => { 372 => 0x46 }, - 'afstatus_36_g6_vertical' => { 372 => 0x48 }, - 'afstatus_37_g5_vertical' => { 372 => 0x4a }, - 'afstatus_38_i7_vertical' => { 372 => 0x4c }, - 'afstatus_39_i6_vertical' => { 372 => 0x4e }, - 'afstatus_40_i5_vertical' => { 372 => 0x50 }, - 'afstatus_41_a7' => { 372 => 0x52 }, - 'afstatus_42_b7' => { 372 => 0x54 }, - 'afstatus_43_c7' => { 372 => 0x56 }, - 'afstatus_44_d7' => { 372 => 0x58 }, - 'afstatus_45_e7' => { 372 => 0x5a }, - 'afstatus_46_f7' => { 372 => 0x5c }, - 'afstatus_47_g7' => { 372 => 0x5e }, - 'afstatus_48_h7' => { 372 => 0x60 }, - 'afstatus_49_i7' => { 372 => 0x62 }, - 'afstatus_50_a6' => { 372 => 0x64 }, - 'afstatus_51_b6' => { 372 => 0x66 }, - 'afstatus_52_c6' => { 372 => 0x68 }, - 'afstatus_53_d6' => { 372 => 0x6a }, - 'afstatus_54_e6_center' => { 372 => 0x6c }, - 'afstatus_55_f6' => { 372 => 0x6e }, - 'afstatus_56_g6' => { 372 => 0x70 }, - 'afstatus_57_h6' => { 372 => 0x72 }, - 'afstatus_58_i6' => { 372 => 0x74 }, - 'afstatus_59_a5' => { 372 => 0x76 }, - 'afstatus_60_b5' => { 372 => 0x78 }, - 'afstatus_61_c5' => { 372 => 0x7a }, - 'afstatus_62_d5' => { 372 => 0x7c }, - 'afstatus_63_e5' => { 372 => 0x7e }, - 'afstatus_64_f5' => { 372 => 0x80 }, - 'afstatus_65_g5' => { 372 => 0x82 }, - 'afstatus_66_h5' => { 372 => 0x84 }, - 'afstatus_67_i5' => { 372 => 0x86 }, - 'afstatus_68_c11' => { 372 => 0x88 }, - 'afstatus_69_d11' => { 372 => 0x8a }, - 'afstatus_70_e11' => { 372 => 0x8c }, - 'afstatus_71_f11' => { 372 => 0x8e }, - 'afstatus_72_g11' => { 372 => 0x90 }, - 'afstatus_73_b10' => { 372 => 0x92 }, - 'afstatus_74_c10' => { 372 => 0x94 }, - 'afstatus_75_d10' => { 372 => 0x96 }, - 'afstatus_76_e10' => { 372 => 0x98 }, - 'afstatus_77_f10' => { 372 => 0x9a }, - 'afstatus_78_g10' => { 372 => 0x9c }, - 'afstatus_79_h10' => { 372 => 0x9e }, - 'afstatus_80_b9' => { 372 => 0xa0 }, - 'afstatus_81_c9' => { 372 => 0xa2 }, - 'afstatus_82_d9' => { 372 => 0xa4 }, - 'afstatus_83_e9' => { 372 => 0xa6 }, - 'afstatus_84_f9' => { 372 => 0xa8 }, - 'afstatus_85_g9' => { 372 => 0xaa }, - 'afstatus_86_h9' => { 372 => 0xac }, - 'afstatus_87_b8' => { 372 => 0xae }, - 'afstatus_88_c8' => { 372 => 0xb0 }, - 'afstatus_89_d8' => { 372 => 0xb2 }, - 'afstatus_90_e8' => { 372 => 0xb4 }, - 'afstatus_91_f8' => { 372 => 0xb6 }, - 'afstatus_92_g8' => { 372 => 0xb8 }, - 'afstatus_93_h8' => { 372 => 0xba }, - 'afstatus_94_e6_center_f2-8' => { 372 => 0xbc }, - 'afstatusactivesensor' => { 170 => 0x2, 369 => [0x4,0x3b], 373 => 0x1e, 374 => 0x1b, 375 => [0x1b,0x21] }, - 'afstatusbottom' => { 170 => 0x8, 373 => 0x2a, 374 => 0x21, 375 => 0x21 }, - 'afstatusbottom-left' => { 170 => 0x12, 374 => 0x2b, 375 => 0x2b }, - 'afstatusbottom-right' => { 170 => 0x6, 374 => 0x1f, 375 => 0x1f }, - 'afstatusbottomassist-left' => { 373 => 0x28 }, - 'afstatusbottomassist-right' => { 373 => 0x2c }, - 'afstatusbottomhorizontal' => { 370 => 0x10, 371 => 0x1c }, - 'afstatusbottomvertical' => { 370 => 0x16, 371 => 0x26 }, - 'afstatuscenter-10' => { 373 => 0x34 }, - 'afstatuscenter-11' => { 373 => 0x36 }, - 'afstatuscenter-12' => { 373 => 0x38 }, - 'afstatuscenter-14' => { 373 => 0x3c }, - 'afstatuscenter-7' => { 373 => 0x2e }, - 'afstatuscenter-9' => { 373 => 0x32 }, - 'afstatuscenter-horizontal' => { 373 => 0x30 }, - 'afstatuscenter-vertical' => { 373 => 0x3a }, - 'afstatuscenterf2-8' => { 373 => 0x4c }, - 'afstatuscenterhorizontal' => { 170 => 0x2f, 370 => 0xc, 371 => 0x18, 374 => 0x2f, 375 => 0x2f }, - 'afstatuscentervertical' => { 170 => 0xc, 370 => 0x14, 371 => 0x22, 374 => 0x25, 375 => 0x25 }, - 'afstatusfarleft' => { 370 => 0x6, 373 => 0x26 }, - 'afstatusfarlefthorizontal' => { 371 => 0x4 }, - 'afstatusfarleftvertical' => { 371 => 0x12 }, - 'afstatusfarright' => { 370 => 0x18, 373 => 0x44 }, - 'afstatusfarrighthorizontal' => { 371 => 0x2c }, - 'afstatusfarrightvertical' => { 371 => 0x34 }, - 'afstatusleft' => { 170 => 0x2d, 370 => 0x2, 373 => 0x22, 374 => 0x2d, 375 => 0x2d }, - 'afstatuslefthorizontal' => { 371 => 0x6 }, - 'afstatusleftvertical' => { 371 => 0xe }, - 'afstatuslower-left' => { 370 => 0x4, 373 => 0x24 }, - 'afstatuslower-lefthorizontal' => { 371 => 0xa }, - 'afstatuslower-leftvertical' => { 371 => 0x10 }, - 'afstatuslower-middle' => { 370 => 0x22, 371 => 0x24 }, - 'afstatuslower-right' => { 370 => 0x1e, 373 => 0x4a }, - 'afstatuslower-righthorizontal' => { 371 => 0x32 }, - 'afstatuslower-rightvertical' => { 371 => 0x3a }, - 'afstatuslowerfarleft' => { 371 => 0x8 }, - 'afstatuslowerfarright' => { 371 => 0x30 }, - 'afstatusmiddlehorizontal' => { 170 => 0xa, 374 => 0x23, 375 => 0x23 }, - 'afstatusnearleft' => { 370 => 0xe, 371 => 0x1a }, - 'afstatusnearright' => { 370 => 0xa, 371 => 0x16 }, - 'afstatusright' => { 170 => 0x31, 370 => 0x1c, 373 => 0x48, 374 => 0x31, 375 => 0x31 }, - 'afstatusrighthorizontal' => { 371 => 0x2e }, - 'afstatusrightvertical' => { 371 => 0x38 }, - 'afstatustop' => { 170 => 0xe, 373 => 0x40, 374 => 0x27, 375 => 0x27 }, - 'afstatustop-left' => { 170 => 0x10, 374 => 0x29, 375 => 0x29 }, - 'afstatustop-right' => { 170 => 0x4, 374 => 0x1d, 375 => 0x1d }, - 'afstatustopassist-left' => { 373 => 0x3e }, - 'afstatustopassist-right' => { 373 => 0x42 }, - 'afstatustophorizontal' => { 370 => 0x8, 371 => 0x14 }, - 'afstatustopvertical' => { 370 => 0x12, 371 => 0x1e }, - 'afstatusupper-left' => { 370 => 0x0, 373 => 0x20 }, - 'afstatusupper-lefthorizontal' => { 371 => 0x2 }, - 'afstatusupper-leftvertical' => { 371 => 0xc }, - 'afstatusupper-middle' => { 370 => 0x20, 371 => 0x20 }, - 'afstatusupper-right' => { 370 => 0x1a, 373 => 0x46 }, - 'afstatusupper-righthorizontal' => { 371 => 0x2a }, - 'afstatusupper-rightvertical' => { 371 => 0x36 }, - 'afstatusupperfarleft' => { 371 => 0x0 }, - 'afstatusupperfarright' => { 371 => 0x28 }, + 'afpredictor' => { 331 => 0x4 }, + 'afresponse' => { 226 => 0xad }, + 'afresult' => { 302 => 0x1038 }, + 'afsearch' => { 297 => 0x303 }, + 'afsensoractive' => { 180 => 0x1 }, + 'afstatus' => { 387 => 0x1200 }, + 'afstatus_00_b4' => { 403 => 0x0 }, + 'afstatus_01_c4' => { 403 => 0x2 }, + 'afstatus_02_d4' => { 403 => 0x4 }, + 'afstatus_03_e4' => { 403 => 0x6 }, + 'afstatus_04_f4' => { 403 => 0x8 }, + 'afstatus_05_g4' => { 403 => 0xa }, + 'afstatus_06_h4' => { 403 => 0xc }, + 'afstatus_07_b3' => { 403 => 0xe }, + 'afstatus_08_c3' => { 403 => 0x10 }, + 'afstatus_09_d3' => { 403 => 0x12 }, + 'afstatus_10_e3' => { 403 => 0x14 }, + 'afstatus_11_f3' => { 403 => 0x16 }, + 'afstatus_12_g3' => { 403 => 0x18 }, + 'afstatus_13_h3' => { 403 => 0x1a }, + 'afstatus_14_b2' => { 403 => 0x1c }, + 'afstatus_15_c2' => { 403 => 0x1e }, + 'afstatus_16_d2' => { 403 => 0x20 }, + 'afstatus_17_e2' => { 403 => 0x22 }, + 'afstatus_18_f2' => { 403 => 0x24 }, + 'afstatus_19_g2' => { 403 => 0x26 }, + 'afstatus_20_h2' => { 403 => 0x28 }, + 'afstatus_21_c1' => { 403 => 0x2a }, + 'afstatus_22_d1' => { 403 => 0x2c }, + 'afstatus_23_e1' => { 403 => 0x2e }, + 'afstatus_24_f1' => { 403 => 0x30 }, + 'afstatus_25_g1' => { 403 => 0x32 }, + 'afstatus_26_a7_vertical' => { 403 => 0x34 }, + 'afstatus_27_a6_vertical' => { 403 => 0x36 }, + 'afstatus_28_a5_vertical' => { 403 => 0x38 }, + 'afstatus_29_c7_vertical' => { 403 => 0x3a }, + 'afstatus_30_c6_vertical' => { 403 => 0x3c }, + 'afstatus_31_c5_vertical' => { 403 => 0x3e }, + 'afstatus_32_e7_vertical' => { 403 => 0x40 }, + 'afstatus_33_e6_center_vertical' => { 403 => 0x42 }, + 'afstatus_34_e5_vertical' => { 403 => 0x44 }, + 'afstatus_35_g7_vertical' => { 403 => 0x46 }, + 'afstatus_36_g6_vertical' => { 403 => 0x48 }, + 'afstatus_37_g5_vertical' => { 403 => 0x4a }, + 'afstatus_38_i7_vertical' => { 403 => 0x4c }, + 'afstatus_39_i6_vertical' => { 403 => 0x4e }, + 'afstatus_40_i5_vertical' => { 403 => 0x50 }, + 'afstatus_41_a7' => { 403 => 0x52 }, + 'afstatus_42_b7' => { 403 => 0x54 }, + 'afstatus_43_c7' => { 403 => 0x56 }, + 'afstatus_44_d7' => { 403 => 0x58 }, + 'afstatus_45_e7' => { 403 => 0x5a }, + 'afstatus_46_f7' => { 403 => 0x5c }, + 'afstatus_47_g7' => { 403 => 0x5e }, + 'afstatus_48_h7' => { 403 => 0x60 }, + 'afstatus_49_i7' => { 403 => 0x62 }, + 'afstatus_50_a6' => { 403 => 0x64 }, + 'afstatus_51_b6' => { 403 => 0x66 }, + 'afstatus_52_c6' => { 403 => 0x68 }, + 'afstatus_53_d6' => { 403 => 0x6a }, + 'afstatus_54_e6_center' => { 403 => 0x6c }, + 'afstatus_55_f6' => { 403 => 0x6e }, + 'afstatus_56_g6' => { 403 => 0x70 }, + 'afstatus_57_h6' => { 403 => 0x72 }, + 'afstatus_58_i6' => { 403 => 0x74 }, + 'afstatus_59_a5' => { 403 => 0x76 }, + 'afstatus_60_b5' => { 403 => 0x78 }, + 'afstatus_61_c5' => { 403 => 0x7a }, + 'afstatus_62_d5' => { 403 => 0x7c }, + 'afstatus_63_e5' => { 403 => 0x7e }, + 'afstatus_64_f5' => { 403 => 0x80 }, + 'afstatus_65_g5' => { 403 => 0x82 }, + 'afstatus_66_h5' => { 403 => 0x84 }, + 'afstatus_67_i5' => { 403 => 0x86 }, + 'afstatus_68_c11' => { 403 => 0x88 }, + 'afstatus_69_d11' => { 403 => 0x8a }, + 'afstatus_70_e11' => { 403 => 0x8c }, + 'afstatus_71_f11' => { 403 => 0x8e }, + 'afstatus_72_g11' => { 403 => 0x90 }, + 'afstatus_73_b10' => { 403 => 0x92 }, + 'afstatus_74_c10' => { 403 => 0x94 }, + 'afstatus_75_d10' => { 403 => 0x96 }, + 'afstatus_76_e10' => { 403 => 0x98 }, + 'afstatus_77_f10' => { 403 => 0x9a }, + 'afstatus_78_g10' => { 403 => 0x9c }, + 'afstatus_79_h10' => { 403 => 0x9e }, + 'afstatus_80_b9' => { 403 => 0xa0 }, + 'afstatus_81_c9' => { 403 => 0xa2 }, + 'afstatus_82_d9' => { 403 => 0xa4 }, + 'afstatus_83_e9' => { 403 => 0xa6 }, + 'afstatus_84_f9' => { 403 => 0xa8 }, + 'afstatus_85_g9' => { 403 => 0xaa }, + 'afstatus_86_h9' => { 403 => 0xac }, + 'afstatus_87_b8' => { 403 => 0xae }, + 'afstatus_88_c8' => { 403 => 0xb0 }, + 'afstatus_89_d8' => { 403 => 0xb2 }, + 'afstatus_90_e8' => { 403 => 0xb4 }, + 'afstatus_91_f8' => { 403 => 0xb6 }, + 'afstatus_92_g8' => { 403 => 0xb8 }, + 'afstatus_93_h8' => { 403 => 0xba }, + 'afstatus_94_e6_center_f2-8' => { 403 => 0xbc }, + 'afstatusactivesensor' => { 180 => 0x2, 400 => [0x4,0x3b], 404 => 0x1e, 405 => 0x1b, 406 => [0x1b,0x21] }, + 'afstatusbottom' => { 180 => 0x8, 404 => 0x2a, 405 => 0x21, 406 => 0x21 }, + 'afstatusbottom-left' => { 180 => 0x12, 405 => 0x2b, 406 => 0x2b }, + 'afstatusbottom-right' => { 180 => 0x6, 405 => 0x1f, 406 => 0x1f }, + 'afstatusbottomassist-left' => { 404 => 0x28 }, + 'afstatusbottomassist-right' => { 404 => 0x2c }, + 'afstatusbottomhorizontal' => { 401 => 0x10, 402 => 0x1c }, + 'afstatusbottomvertical' => { 401 => 0x16, 402 => 0x26 }, + 'afstatuscenter-10' => { 404 => 0x34 }, + 'afstatuscenter-11' => { 404 => 0x36 }, + 'afstatuscenter-12' => { 404 => 0x38 }, + 'afstatuscenter-14' => { 404 => 0x3c }, + 'afstatuscenter-7' => { 404 => 0x2e }, + 'afstatuscenter-9' => { 404 => 0x32 }, + 'afstatuscenter-horizontal' => { 404 => 0x30 }, + 'afstatuscenter-vertical' => { 404 => 0x3a }, + 'afstatuscenterf2-8' => { 404 => 0x4c }, + 'afstatuscenterhorizontal' => { 180 => 0x2f, 401 => 0xc, 402 => 0x18, 405 => 0x2f, 406 => 0x2f }, + 'afstatuscentervertical' => { 180 => 0xc, 401 => 0x14, 402 => 0x22, 405 => 0x25, 406 => 0x25 }, + 'afstatusfarleft' => { 401 => 0x6, 404 => 0x26 }, + 'afstatusfarlefthorizontal' => { 402 => 0x4 }, + 'afstatusfarleftvertical' => { 402 => 0x12 }, + 'afstatusfarright' => { 401 => 0x18, 404 => 0x44 }, + 'afstatusfarrighthorizontal' => { 402 => 0x2c }, + 'afstatusfarrightvertical' => { 402 => 0x34 }, + 'afstatusleft' => { 180 => 0x2d, 401 => 0x2, 404 => 0x22, 405 => 0x2d, 406 => 0x2d }, + 'afstatuslefthorizontal' => { 402 => 0x6 }, + 'afstatusleftvertical' => { 402 => 0xe }, + 'afstatuslower-left' => { 401 => 0x4, 404 => 0x24 }, + 'afstatuslower-lefthorizontal' => { 402 => 0xa }, + 'afstatuslower-leftvertical' => { 402 => 0x10 }, + 'afstatuslower-middle' => { 401 => 0x22, 402 => 0x24 }, + 'afstatuslower-right' => { 401 => 0x1e, 404 => 0x4a }, + 'afstatuslower-righthorizontal' => { 402 => 0x32 }, + 'afstatuslower-rightvertical' => { 402 => 0x3a }, + 'afstatuslowerfarleft' => { 402 => 0x8 }, + 'afstatuslowerfarright' => { 402 => 0x30 }, + 'afstatusmiddlehorizontal' => { 180 => 0xa, 405 => 0x23, 406 => 0x23 }, + 'afstatusnearleft' => { 401 => 0xe, 402 => 0x1a }, + 'afstatusnearright' => { 401 => 0xa, 402 => 0x16 }, + 'afstatusright' => { 180 => 0x31, 401 => 0x1c, 404 => 0x48, 405 => 0x31, 406 => 0x31 }, + 'afstatusrighthorizontal' => { 402 => 0x2e }, + 'afstatusrightvertical' => { 402 => 0x38 }, + 'afstatustop' => { 180 => 0xe, 404 => 0x40, 405 => 0x27, 406 => 0x27 }, + 'afstatustop-left' => { 180 => 0x10, 405 => 0x29, 406 => 0x29 }, + 'afstatustop-right' => { 180 => 0x4, 405 => 0x1d, 406 => 0x1d }, + 'afstatustopassist-left' => { 404 => 0x3e }, + 'afstatustopassist-right' => { 404 => 0x42 }, + 'afstatustophorizontal' => { 401 => 0x8, 402 => 0x14 }, + 'afstatustopvertical' => { 401 => 0x12, 402 => 0x1e }, + 'afstatusupper-left' => { 401 => 0x0, 404 => 0x20 }, + 'afstatusupper-lefthorizontal' => { 402 => 0x2 }, + 'afstatusupper-leftvertical' => { 402 => 0xc }, + 'afstatusupper-middle' => { 401 => 0x20, 402 => 0x20 }, + 'afstatusupper-right' => { 401 => 0x1a, 404 => 0x46 }, + 'afstatusupper-righthorizontal' => { 402 => 0x2a }, + 'afstatusupper-rightvertical' => { 402 => 0x36 }, + 'afstatusupperfarleft' => { 402 => 0x0 }, + 'afstatusupperfarright' => { 402 => 0x28 }, 'afstatusviewfinder' => { 2 => 0x12 }, - 'aftracking' => { 388 => 0x2021 }, + 'aftracking' => { 420 => 0x2021 }, 'aftrackingsensitivity' => { 2 => 0x2 }, - 'aftype' => { 369 => 0x2 }, - 'afwithshutter' => { 376 => 0x2a }, - 'aggregateissuenumber' => { 456 => 'aggregateIssueNumber' }, - 'aggregationtype' => { 456 => 'aggregationType' }, - 'agreement' => { 459 => 'agreement' }, - 'ah2greeninterpolationthreshold' => { 131 => 0xe4e }, - 'aiservocontinuousshooting' => { 77 => 0x15 }, + 'aftype' => { 400 => 0x2 }, + 'afwithshutter' => { 407 => 0x2a }, + 'aggregateissuenumber' => { 494 => 'aggregateIssueNumber' }, + 'aggregationtype' => { 494 => 'aggregationType' }, + 'agreement' => { 497 => 'agreement' }, + 'ah2greeninterpolationthreshold' => { 138 => 0xe4e }, + 'airplanemode' => { 229 => 0x624 }, + 'aiservocontinuousshooting' => { 83 => 0x15 }, 'aiservofirstimage' => { 2 => 0x5 }, - 'aiservofirstimagepriority' => { 78 => 0x519 }, - 'aiservoimagepriority' => { 78 => 0x503 }, + 'aiservofirstimagepriority' => { 84 => 0x519 }, + 'aiservoimagepriority' => { 84 => 0x503 }, 'aiservosecondimage' => { 2 => 0x6 }, - 'aiservosecondimagepriority' => { 78 => 0x51a }, - 'aiservotrackingmethod' => { 78 => 0x504 }, - 'aiservotrackingsensitivity' => { 77 => 0x14, 78 => 0x502 }, - 'album' => { 466 => 'album' }, - 'alreadyapplied' => { 442 => 'AlreadyApplied' }, - 'alternatetitle' => { 456 => 'alternateTitle' }, - 'alternatetitlea-lang' => { 456 => [\'alternateTitle','alternateTitleA-lang'] }, - 'alternatetitlea-platform' => { 456 => [\'alternateTitle','alternateTitleA-platform'] }, - 'alternatetitletext' => { 456 => [\'alternateTitle','alternateTitleText'] }, - 'altitude' => { 185 => 0x6 }, - 'alttapename' => { 466 => 'altTapeName' }, - 'alttimecode' => { 466 => 'altTimecode' }, - 'alttimecodetimeformat' => { 466 => [\'altTimecode','altTimecodeTimeFormat'] }, - 'alttimecodetimevalue' => { 466 => [\'altTimecode','altTimecodeTimeValue'] }, - 'alttimecodevalue' => { 466 => [\'altTimecode','altTimecodeValue'] }, + 'aiservosecondimagepriority' => { 84 => 0x51a }, + 'aiservotrackingmethod' => { 84 => 0x504 }, + 'aiservotrackingsensitivity' => { 83 => 0x14, 84 => 0x502 }, + 'aisubjecttrackingmode' => { 297 => 0x309 }, + 'album' => { 372 => ['albm',"\xa9alb"], 374 => 'album', 380 => ['albm',"\xa9alb"], 504 => 'album' }, + 'albumartist' => { 179 => 'WM/AlbumArtist', 372 => 'aART', 380 => 'albr' }, + 'albumcoverurl' => { 179 => 'WM/AlbumCoverURL' }, + 'albumtitle' => { 179 => 'WM/AlbumTitle' }, + 'albumtitleid' => { 372 => 'atID' }, + 'alreadyapplied' => { 478 => 'AlreadyApplied', 480 => 'AlreadyApplied' }, + 'alternatetitle' => { 494 => 'alternateTitle' }, + 'alternatetitlea-lang' => { 494 => [\'alternateTitle','alternateTitleA-lang'] }, + 'alternatetitlea-platform' => { 494 => [\'alternateTitle','alternateTitleA-platform'] }, + 'alternatetitletext' => { 494 => [\'alternateTitle','alternateTitleText'] }, + 'altitude' => { 196 => 0x6 }, + 'alttapename' => { 504 => 'altTapeName' }, + 'alttextaccessibility' => { 489 => 'AltTextAccessibility' }, + 'alttimecode' => { 504 => 'altTimecode' }, + 'alttimecodetimeformat' => { 504 => [\'altTimecode','altTimecodeTimeFormat'] }, + 'alttimecodetimevalue' => { 504 => [\'altTimecode','altTimecodeTimeValue'] }, + 'alttimecodevalue' => { 504 => [\'altTimecode','altTimecodeValue'] }, 'ambienceselection' => { 4 => 0x1 }, - 'ambienttemperature' => { 113 => 0x9400, 353 => 0x14, 354 => 0x46, 411 => 0x4, 447 => 'Temperature' }, - 'ambienttemperaturefahrenheit' => { 353 => 0x13, 354 => 0x44 }, - 'analogbalance' => { 113 => 0xc627 }, - 'analogcaptureiso' => { 131 => 0x89e }, - 'analogisotable' => { 131 => 0x89d }, - 'angleadj' => { 97 => 0x10003, 103 => 0x8b }, - 'angleinforoll' => { 437 => 'AngleInfoRoll' }, - 'angleinfoyaw' => { 437 => 'AngleInfoYaw' }, - 'anti-blur' => { 388 => 0xb04b }, - 'antialiasstrength' => { 113 => 0xc632 }, - 'aperturelock' => { 258 => '38.2', 260 => '38.2', 261 => '38.2', 270 => '38.2', 271 => '38.2' }, - 'aperturerange' => { 78 => 0x10d }, - 'apertureringuse' => { 313 => '1.4' }, - 'aperturesetting' => { 174 => 0x7, 376 => 0x30, 377 => 0x29, 378 => 0x1 }, - 'aperturevalue' => { 87 => 0x2, 113 => 0x9202, 279 => 0x1002, 341 => 0x401, 446 => 'ApertureValue' }, - 'applekeywords' => { 283 => 'AAPL:Keywords' }, - 'applicationkeystring' => { 131 => 0x400 }, - 'applicationnotes' => { 113 => 0x2bc, 302 => 0x2bc }, - 'applicationrecordversion' => { 125 => 0x0 }, - 'applyshootingmeteringmode' => { 78 => 0x10e }, - 'approved' => { 448 => 'Approved' }, - 'approvedby' => { 448 => 'ApprovedBy' }, - 'approximatefnumber' => { 292 => 0x313, 299 => 0x3406 }, - 'approximatefocusdistance' => { 438 => 'ApproximateFocusDistance' }, - 'appversion' => { 450 => 'AppVersion' }, - 'aquahsl' => { 97 => 0x20914 }, - 'armidentifier' => { 126 => 0x78 }, - 'armversion' => { 126 => 0x7a }, - 'artfilter' => { 274 => 0x529 }, - 'artfiltereffect' => { 274 => 0x52f }, - 'artist' => { 113 => 0x13b, 287 => 'Artist', 332 => 0x22e, 462 => 'Artist', 466 => 'artist' }, - 'artmode' => { 107 => 0x301b }, - 'artmodeparameters' => { 107 => 0x310b }, - 'artworkcircadatecreated' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOCircaDateCreated'] }, - 'artworkcontentdescription' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOContentDescription'] }, - 'artworkcontributiondescription' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOContributionDescription'] }, - 'artworkcopyrightnotice' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOCopyrightNotice'] }, - 'artworkcopyrightownerid' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOCurrentCopyrightOwnerId'] }, - 'artworkcopyrightownername' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOCurrentCopyrightOwnerName'] }, - 'artworkcreator' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOCreator'] }, - 'artworkcreatorid' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOCreatorId'] }, - 'artworkdatecreated' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAODateCreated'] }, - 'artworklicensorid' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOCurrentLicensorId'] }, - 'artworklicensorname' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOCurrentLicensorName'] }, - 'artworkorobject' => { 452 => 'ArtworkOrObject' }, - 'artworkphysicaldescription' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOPhysicalDescription'] }, - 'artworksource' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOSource'] }, - 'artworksourceinventoryno' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOSourceInvNo'] }, - 'artworksourceinvurl' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOSourceInvURL'] }, - 'artworkstyleperiod' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOStylePeriod'] }, - 'artworktitle' => { 452 => [\'ArtworkOrObject','ArtworkOrObjectAOTitle'] }, - 'aspectframe' => { 278 => 0x1113 }, - 'aspectratio' => { 5 => 0x0, 278 => 0x1112, 332 => 0x80, 376 => 0x55, 377 => 0x55, 378 => 0xa }, - 'assetid' => { 431 => 'AssetID' }, - 'asshoticcprofile' => { 113 => 0xc68f }, - 'asshotneutral' => { 113 => 0xc628 }, - 'asshotpreprofilematrix' => { 113 => 0xc690 }, - 'asshotprofilename' => { 113 => 0xc6f6 }, - 'asshotwhitexy' => { 113 => 0xc629 }, - 'assignbktbutton' => { 257 => '4.2', 258 => '16.1', 260 => '16.1', 261 => '16.1', 270 => '16.1', 271 => '16.1' }, - 'assignfuncbutton' => { 78 => 0x70b }, - 'assignmb-d17af-onbutton' => { 261 => '79.1' }, - 'assignmb-d17funcbutton' => { 261 => '67.1' }, - 'assignmb-d17funcbuttonplusdials' => { 261 => '68.1' }, - 'assignmb-d18af-onbutton' => { 271 => '79.1' }, - 'assignmb-d18funcbutton' => { 271 => '67.1' }, - 'assignmb-d18funcbuttonplusdials' => { 271 => '68.1' }, - 'assignmoviefunc1buttonplusdials' => { 260 => '75.1', 261 => '75.1', 271 => '75.1' }, - 'assignmoviefunc2button' => { 260 => '82.1', 261 => '82.1', 271 => '82.1' }, - 'assignmoviepreviewbuttonplusdials' => { 260 => '75.2', 261 => '75.2', 271 => '75.2' }, - 'assignmovierecordbutton' => { 258 => '43.2', 270 => '45.1' }, - 'assignmovierecordbuttonplusdials' => { 260 => '45.1', 261 => '45.1', 271 => '45.1' }, - 'assignmoviesubselector' => { 260 => '74.1', 261 => '74.1', 271 => '74.1' }, - 'assignmoviesubselectorplusdials' => { 260 => '76.1', 261 => '76.1', 271 => '76.1' }, - 'assignremotefnbutton' => { 258 => '54.1', 270 => '51.1' }, - 'assistbuttonfunction' => { 76 => 0xd }, - 'atcaptureusercrop' => { 131 => 0x943 }, - 'attributionname' => { 439 => 'attributionName' }, - 'attributionurl' => { 439 => 'attributionURL' }, - 'audio' => { 297 => 0x20 }, - 'audiobitrate' => { 63 => 0x6c, 452 => 'audioBitRate' }, - 'audiobitratemode' => { 452 => 'audioBitRateMode' }, - 'audiobitspersample' => { 452 => 'audioBitsPerSample' }, - 'audiochannelcount' => { 452 => 'audioChannelCount' }, - 'audiochannels' => { 63 => 0x70 }, - 'audiochanneltype' => { 466 => 'audioChannelType' }, - 'audiocompression' => { 146 => 'Compression' }, - 'audiocompressor' => { 466 => 'audioCompressor' }, - 'audiodata' => { 425 => 'Data' }, - 'audioduration' => { 125 => 0x99 }, - 'audiomimetype' => { 425 => 'Mime' }, - 'audiomoddate' => { 466 => 'audioModDate' }, - 'audiooutcue' => { 125 => 0x9a }, - 'audiosamplerate' => { 63 => 0x6e, 466 => 'audioSampleRate' }, - 'audiosampletype' => { 466 => 'audioSampleType' }, - 'audiosamplingrate' => { 125 => 0x97 }, - 'audiosamplingresolution' => { 125 => 0x98 }, - 'audiotype' => { 125 => 0x96 }, - 'author' => { 148 => 'Author', 283 => 'Author', 287 => 'Author', 348 => 'Author', 436 => 'author', 453 => 'Author', 464 => 'Author' }, - 'authorsposition' => { 454 => 'AuthorsPosition' }, - 'autoafpointcolortracking' => { 78 => 0x51c }, + 'ambientinfrared' => { 383 => 0x5c }, + 'ambientlight' => { 383 => 0x5e }, + 'ambienttemperature' => { 119 => 0x9400, 381 => 0x14, 382 => 0x46, 383 => 0x50, 445 => 0x4, 485 => 'Temperature' }, + 'ambienttemperaturefahrenheit' => { 381 => 0x13, 382 => 0x44, 383 => 0x4e }, + 'analogbalance' => { 119 => 0xc627 }, + 'analogcaptureiso' => { 138 => 0x89e }, + 'analogisotable' => { 138 => 0x89d }, + 'androidversion' => { 374 => 'com.android.version' }, + 'angleadj' => { 103 => 0x10003, 109 => 0x8b }, + 'angleinforoll' => { 474 => 'AngleInfoRoll' }, + 'angleinfoyaw' => { 474 => 'AngleInfoYaw' }, + 'anti-blur' => { 420 => 0xb04b }, + 'antialiasstrength' => { 119 => 0xc632 }, + 'aperturelock' => { 280 => '38.2', 282 => '38.2', 283 => '38.2', 292 => '38.2', 293 => '38.2', 295 => 0xb8 }, + 'aperturemode' => { 380 => 'apmd' }, + 'aperturerange' => { 84 => 0x10d }, + 'apertureringuse' => { 336 => '1.4' }, + 'aperturesetting' => { 184 => 0x7, 407 => 0x30, 408 => 0x29, 409 => 0x1 }, + 'aperturevalue' => { 93 => 0x2, 119 => 0x9202, 302 => 0x1002, 364 => 0x401, 484 => 'ApertureValue' }, + 'appinfo' => { 458 => 'AppInfo' }, + 'appinfoapplication' => { 458 => [\'AppInfo','AppInfoApplication'] }, + 'appinfoitemuri' => { 458 => [\'AppInfo','AppInfoItemURI'] }, + 'appinfoversion' => { 458 => [\'AppInfo','AppInfoVersion'] }, + 'applekeywords' => { 306 => 'AAPL:Keywords' }, + 'applephotosvariationidentifier' => { 374 => 'apple.photos.variation-identifier' }, + 'applestoreaccount' => { 372 => 'apID' }, + 'applestoreaccounttype' => { 372 => 'akID' }, + 'applestorecatalogid' => { 372 => 'cnID' }, + 'applestorecountry' => { 372 => 'sfID' }, + 'applicationkeystring' => { 138 => 0x400 }, + 'applicationnotes' => { 119 => 0x2bc, 325 => 0x2bc }, + 'applicationrecordversion' => { 131 => 0x0 }, + 'applyshootingmeteringmode' => { 84 => 0x10e }, + 'approved' => { 486 => 'Approved' }, + 'approvedby' => { 486 => 'ApprovedBy' }, + 'approximatefnumber' => { 315 => 0x313, 322 => 0x3406 }, + 'approximatefocusdistance' => { 475 => 'ApproximateFocusDistance' }, + 'appversion' => { 488 => 'AppVersion' }, + 'aps-csizecapture' => { 439 => 0x114, 440 => [0x114,0x1eb,0x1ee,0x21a,0x21c] }, + 'aquahsl' => { 103 => 0x20914 }, + 'armidentifier' => { 132 => 0x78 }, + 'armversion' => { 132 => 0x7a }, + 'arranger' => { 372 => "\xa9arg", 380 => "\xa9arg" }, + 'arrangerkeywords' => { 380 => "\xa9ark" }, + 'artdirector' => { 372 => "\xa9ard" }, + 'artfilter' => { 297 => 0x529 }, + 'artfiltereffect' => { 297 => 0x52f }, + 'artist' => { 119 => 0x13b, 310 => 'Artist', 355 => 0x22e, 372 => "\xa9ART", 374 => 'artist', 380 => "\xa9ART", 500 => 'Artist', 504 => 'artist' }, + 'artmode' => { 113 => 0x301b }, + 'artmodeparameters' => { 113 => 0x310b }, + 'artwork' => { 374 => 'artwork' }, + 'artworkcircadatecreated' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOCircaDateCreated'] }, + 'artworkcontentdescription' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOContentDescription'] }, + 'artworkcontributiondescription' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOContributionDescription'] }, + 'artworkcopyrightnotice' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOCopyrightNotice'] }, + 'artworkcopyrightownerid' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOCurrentCopyrightOwnerId'] }, + 'artworkcopyrightownername' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOCurrentCopyrightOwnerName'] }, + 'artworkcreator' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOCreator'] }, + 'artworkcreatorid' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOCreatorId'] }, + 'artworkdatecreated' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAODateCreated'] }, + 'artworklicensorid' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOCurrentLicensorId'] }, + 'artworklicensorname' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOCurrentLicensorName'] }, + 'artworkorobject' => { 490 => 'ArtworkOrObject' }, + 'artworkphysicaldescription' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOPhysicalDescription'] }, + 'artworksource' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOSource'] }, + 'artworksourceinventoryno' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOSourceInvNo'] }, + 'artworksourceinvurl' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOSourceInvURL'] }, + 'artworkstyleperiod' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOStylePeriod'] }, + 'artworktitle' => { 490 => [\'ArtworkOrObject','ArtworkOrObjectAOTitle'] }, + 'aspectframe' => { 301 => 0x1113 }, + 'aspectratio' => { 5 => 0x0, 301 => 0x1112, 355 => 0x80, 407 => 0x55, 408 => 0x55, 409 => 0xa }, + 'assetid' => { 468 => 'AssetID' }, + 'asshoticcprofile' => { 119 => 0xc68f }, + 'asshotneutral' => { 119 => 0xc628 }, + 'asshotpreprofilematrix' => { 119 => 0xc690 }, + 'asshotprofilename' => { 119 => 0xc6f6 }, + 'asshotwhitexy' => { 119 => 0xc629 }, + 'assignbktbutton' => { 279 => '4.2', 280 => '16.1', 282 => '16.1', 283 => '16.1', 292 => '16.1', 293 => '16.1' }, + 'assignfuncbutton' => { 84 => 0x70b }, + 'assignmb-d17af-onbutton' => { 283 => '79.1' }, + 'assignmb-d17funcbutton' => { 283 => '67.1' }, + 'assignmb-d17funcbuttonplusdials' => { 283 => '68.1' }, + 'assignmb-d18af-onbutton' => { 293 => '79.1' }, + 'assignmb-d18funcbutton' => { 293 => '67.1' }, + 'assignmb-d18funcbuttonplusdials' => { 293 => '68.1' }, + 'assignmoviefunc1buttonplusdials' => { 282 => '75.1', 283 => '75.1', 293 => '75.1' }, + 'assignmoviefunc2button' => { 282 => '82.1', 283 => '82.1', 293 => '82.1' }, + 'assignmoviepreviewbuttonplusdials' => { 282 => '75.2', 283 => '75.2', 293 => '75.2' }, + 'assignmovierecordbutton' => { 280 => '43.2', 292 => '45.1', 295 => 0x9b }, + 'assignmovierecordbuttonplusdials' => { 282 => '45.1', 283 => '45.1', 293 => '45.1' }, + 'assignmoviesubselector' => { 282 => '74.1', 283 => '74.1', 293 => '74.1' }, + 'assignmoviesubselectorplusdials' => { 282 => '76.1', 283 => '76.1', 293 => '76.1' }, + 'assignremotefnbutton' => { 280 => '54.1', 292 => '51.1' }, + 'assistbuttonfunction' => { 82 => 0xd }, + 'atcaptureusercrop' => { 138 => 0x943 }, + 'attributionname' => { 476 => 'attributionName' }, + 'attributionurl' => { 476 => 'attributionURL' }, + 'audio' => { 320 => 0x20 }, + 'audiobitrate' => { 67 => 0x6c, 490 => 'audioBitRate' }, + 'audiobitratemode' => { 490 => 'audioBitRateMode' }, + 'audiobitspersample' => { 490 => 'audioBitsPerSample' }, + 'audiobutton' => { 295 => 0x17b }, + 'audiobuttonplaybackmode' => { 295 => 0x1b9 }, + 'audiochannelcount' => { 490 => 'audioChannelCount' }, + 'audiochannels' => { 67 => 0x70 }, + 'audiochanneltype' => { 504 => 'audioChannelType' }, + 'audiocompression' => { 84 => 0x816, 155 => 'Compression' }, + 'audiocompressor' => { 504 => 'audioCompressor' }, + 'audiodata' => { 460 => 'Data' }, + 'audioduration' => { 131 => 0x99 }, + 'audiogain' => { 374 => 'player.movie.audio.gain' }, + 'audiomimetype' => { 460 => 'Mime' }, + 'audiomoddate' => { 504 => 'audioModDate' }, + 'audiooutcue' => { 131 => 0x9a }, + 'audiosamplerate' => { 67 => 0x6e, 504 => 'audioSampleRate' }, + 'audiosampletype' => { 504 => 'audioSampleType' }, + 'audiosamplingrate' => { 131 => 0x97 }, + 'audiosamplingresolution' => { 131 => 0x98 }, + 'audiotype' => { 131 => 0x96 }, + 'author' => { 157 => 'Author', 306 => 'Author', 310 => 'Author', 371 => 'Author', 372 => ['auth',"\xa9aut"], 374 => 'author', 380 => 'auth', 473 => 'author', 491 => 'Author', 502 => 'Author' }, + 'authorsposition' => { 492 => 'AuthorsPosition' }, + 'authorurl' => { 179 => 'WM/AuthorURL' }, + 'autoafpointcolortracking' => { 84 => 0x51c }, 'autoafpointseleositraf' => { 2 => 0xa }, - 'autoaperture' => { 323 => '0.1' }, - 'autobracket' => { 368 => 0x19 }, - 'autobracketing' => { 121 => 0x1100, 332 => 0x18, 358 => 0x1007 }, - 'autobracketingmode' => { 269 => '12.3' }, - 'autobracketingset' => { 269 => '12.1' }, - 'autobracketmodem' => { 257 => '21.2', 258 => '13.3', 260 => '13.2', 261 => '13.2', 266 => '26.2', 270 => '13.3', 271 => '13.2' }, - 'autobracketorder' => { 174 => 0x43, 257 => '21.3', 258 => '13.2', 260 => '13.1', 261 => '13.1', 266 => '26.3', 267 => '12.2', 268 => '2.2', 269 => '12.2', 270 => '13.2', 271 => '13.1', 272 => '13.2' }, - 'autobracketset' => { 257 => '21.1', 258 => '13.1', 262 => '11.1', 263 => '12.1', 264 => '12.1', 266 => '26.1', 267 => '12.1', 268 => '2.1', 270 => '13.1', 272 => '13.1' }, - 'autobrightness' => { 442 => 'AutoBrightness' }, - 'autocontrast' => { 442 => 'AutoContrast' }, - 'autodistortioncontrol' => { 195 => 0x4 }, - 'autodynamicrange' => { 121 => 0x140b }, - 'autoexposure' => { 442 => 'AutoExposure' }, - 'autoexposurebracketing' => { 72 => 0x10 }, - 'autoflashisosensitivity' => { 260 => '38.5', 261 => '38.5', 271 => '38.5' }, - 'autofocus' => { 277 => 0x209 }, - 'autofp' => { 268 => '7.3', 272 => '31.4' }, - 'autoiso' => { 72 => 0x1, 107 => 0x3008, 259 => '1.1', 268 => '1.1' }, - 'autoisomax' => { 259 => '1.2', 268 => '1.2' }, - 'autoisominshutterspeed' => { 259 => '1.3', 268 => '1.3' }, - 'autolateralca' => { 442 => 'AutoLateralCA' }, - 'autolightingoptimizer' => { 15 => 0xbe, 16 => 0xbf, 19 => 0xbf, 59 => 0x2, 78 => 0x204, 97 => 0x20500, 103 => 0x6f }, - 'autolightingoptimizeron' => { 97 => '0x20500.0', 103 => 0x6e }, - 'autoportraitframed' => { 388 => 0x2016 }, - 'autoredeye' => { 250 => 0xfe28a44f }, - 'autorotate' => { 72 => 0x1b }, - 'autoshadows' => { 442 => 'AutoShadows' }, - 'autowhiteversion' => { 442 => 'AutoWhiteVersion' }, - 'auxiliarylens' => { 211 => 0x82 }, - 'avaperturesetting' => { 313 => 0x13 }, - 'averageblacklevel' => { 42 => 0xe7, 44 => 0xfb, 45 => 0x114, 46 => 0x146 }, - 'averagelv' => { 177 => 0x38 }, - 'avsettingwithoutlens' => { 78 => 0x707 }, - 'azimuth' => { 156 => 'Azimuth' }, - 'babyage' => { 297 => [0x8010,0x33] }, - 'babyname' => { 297 => 0x66 }, - 'backgroundalpha' => { 461 => 'bgalpha' }, - 'baseexposurecompensation' => { 313 => 0x15 }, - 'baseiso' => { 72 => 0x2, 91 => 0x101c, 131 => 0x903, 299 => 0x312a, 417 => 0x6 }, - 'baseisodaylight' => { 131 => 0x910 }, - 'baseisoflash' => { 131 => 0x913 }, - 'baseisofluorescent' => { 131 => 0x912 }, - 'baseisotungsten' => { 131 => 0x911 }, - 'baselineexposure' => { 113 => 0xc62a }, - 'baselineexposureoffset' => { 113 => 0xc7a5 }, - 'baselinenoise' => { 113 => 0xc62b }, - 'baselinesharpness' => { 113 => 0xc62c }, - 'baseurl' => { 464 => 'BaseURL' }, - 'batterylevel' => { 376 => 0x51, 380 => 0xc, 381 => 0x4, 382 => 0x4, 418 => 0x7 }, - 'batterylevelgrip1' => { 418 => 0x6 }, - 'batterylevelgrip2' => { 418 => 0x8 }, - 'batteryorder' => { 257 => '12.5', 266 => '13.2', 267 => '2.1', 270 => '3.1' }, - 'batterystate' => { 174 => 0x60, 376 => 0x50, 382 => 0x14 }, - 'batterytemperature' => { 380 => 0x1, 382 => 0x2, 418 => 0x5 }, - 'batterytype' => { 60 => 0x38 }, - 'batteryunknown' => { 380 => 0x2, 382 => 0x0 }, - 'batteryvoltage' => { 131 => 0x408, 353 => 0x2a, 354 => 0x49, 380 => 0x8 }, - 'batteryvoltage1' => { 382 => 0x6 }, - 'batteryvoltage2' => { 382 => 0x8 }, - 'bayergreensplit' => { 113 => 0xc62d }, - 'bayerpattern' => { 130 => 0xf902, 178 => 0x17 }, - 'beatspliceparams' => { 466 => 'beatSpliceParams' }, - 'beatspliceparamsriseindecibel' => { 466 => [\'beatSpliceParams','beatSpliceParamsRiseInDecibel'] }, - 'beatspliceparamsriseintimeduration' => { 466 => [\'beatSpliceParams','beatSpliceParamsRiseInTimeDuration'] }, - 'beatspliceparamsriseintimedurationscale' => { 466 => [\'beatSpliceParams','beatSpliceParamsRiseInTimeDurationScale'] }, - 'beatspliceparamsriseintimedurationvalue' => { 466 => [\'beatSpliceParams','beatSpliceParamsRiseInTimeDurationValue'] }, - 'beatspliceparamsusefilebeatsmarker' => { 466 => [\'beatSpliceParams','beatSpliceParamsUseFileBeatsMarker'] }, - 'beep' => { 257 => '13.1', 258 => '5.4', 259 => '0.1', 262 => '2.1', 263 => '3.1', 264 => '3.1', 266 => '10.1', 268 => '0.1', 270 => '5.5', 272 => '4.1' }, - 'beeppitch' => { 267 => '3.1' }, - 'beepvolume' => { 267 => '4.5' }, - 'bestqualityscale' => { 113 => 0xc65c }, - 'bestshotmode' => { 107 => 0x3007 }, - 'bitdepth' => { 153 => 'BitDepth', 178 => 0x11, 218 => 0x41 }, - 'bitspercomponent' => { 127 => 0x87 }, - 'bitspersample' => { 113 => 0x102, 302 => 0xa, 462 => 'BitsPerSample' }, - 'blackacquirerows' => { 131 => 0x18ba }, - 'blacklevel' => { 113 => 0xc61a, 193 => 0x20, 211 => 0x3d, 279 => [0x401,0x1012], 341 => 0x21d }, - 'blacklevel2' => { 278 => 0x600, 282 => 0x600 }, - 'blacklevelblue' => { 302 => 0x1e }, - 'blacklevelbottom' => { 131 => 0x3f0 }, - 'blackleveldata' => { 341 => 0x223 }, - 'blackleveldeltah' => { 113 => 0xc61b }, - 'blackleveldeltav' => { 113 => 0xc61c }, - 'blacklevelgreen' => { 302 => 0x1d }, - 'blacklevelred' => { 302 => 0x1c }, - 'blacklevelrepeatdim' => { 113 => 0xc619 }, - 'blacklevelrough' => { 131 => 0x40e }, - 'blacklevelroughafter' => { 131 => 0x416 }, - 'blackleveltop' => { 131 => 0x3ef }, - 'blackpoint' => { 332 => 0x200 }, - 'blacks2012' => { 442 => 'Blacks2012' }, - 'blacksadj' => { 421 => 0x9018 }, - 'bleachbypasstoning' => { 332 => 0x7f }, - 'blockshotafresponse' => { 260 => '1.5', 261 => '1.5', 271 => '1.5' }, - 'blogtitle' => { 456 => 'blogTitle' }, - 'blogurl' => { 456 => 'blogURL' }, - 'bluebalance' => { 279 => 0x1018, 302 => 0x12, 332 => 0x1b }, - 'bluecurvelimits' => { 102 => 0x1fe }, - 'bluecurvepoints' => { 101 => 0x79, 102 => 0x1d4 }, - 'bluehsl' => { 97 => 0x20915 }, - 'bluehue' => { 442 => 'BlueHue' }, - 'bluesaturation' => { 442 => 'BlueSaturation' }, - 'bluratinfinity' => { 427 => 'BlurAtInfinity' }, - 'blurcontrol' => { 332 => 0x82 }, - 'blurwarning' => { 121 => 0x1300 }, - 'bodybatteryadload' => { 311 => 0x3 }, - 'bodybatteryadnoload' => { 311 => 0x2 }, - 'bodybatterystate' => { 311 => '1.1' }, - 'bodybatteryvoltage1' => { 311 => 0x2 }, - 'bodybatteryvoltage2' => { 311 => 0x4 }, - 'bodybatteryvoltage3' => { 311 => 0x6 }, - 'bodybatteryvoltage4' => { 311 => 0x8 }, - 'bodyfirmware' => { 359 => 0x0 }, - 'bodyfirmwareversion' => { 275 => 0x104, 276 => 0x100, 279 => 0x104 }, - 'bodyserialnumber' => { 359 => 0x10 }, - 'bookedition' => { 456 => 'bookEdition' }, - 'bootloaderversion' => { 354 => 0x26 }, - 'bracketmode' => { 54 => 0x3 }, - 'bracketsequence' => { 107 => 0x301d }, - 'bracketsettings' => { 297 => 0x45 }, - 'bracketshotnumber' => { 54 => 0x5, 313 => 0x9, 387 => 0x2b }, - 'bracketshotnumber2' => { 387 => 0x2d }, - 'bracketstep' => { 171 => 0xe }, - 'bracketvalue' => { 54 => 0x4 }, - 'brightness' => { 113 => 0xfe53, 147 => 'Brightness', 167 => 'Brightness', 171 => 0x2c, 213 => 0x34, 214 => 0x39, 353 => 0x25, 376 => 0x22, 388 => 0x2007, 442 => 'Brightness' }, - 'brightnessadj' => { 102 => 0x114, 243 => 0x0, 253 => 0x2d, 421 => 0x8018 }, - 'brightnessvalue' => { 113 => 0x9203, 177 => [0x691,0x49c3], 279 => 0x1003, 393 => 0x1e, 396 => 0x1140, 397 => 0x1140, 398 => 0x111c, 399 => 0x1198, 400 => 0x1174, 401 => 0x102c, 402 => 0x224, 403 => 0x224, 404 => 0x219, 446 => 'BrightnessValue' }, - 'bulbduration' => { 72 => 0x18 }, - 'burstcount' => { 131 => 0x40d }, - 'burstmode' => { 133 => 0xa, 297 => 0x2a }, - 'burstmode2' => { 133 => 0x18 }, - 'burstshot' => { 368 => 0x34 }, - 'burstspeed' => { 297 => 0x77 }, + 'autoaperture' => { 346 => '0.1' }, + 'autobracket' => { 397 => 0x19 }, + 'autobracketing' => { 127 => 0x1100, 355 => 0x18, 387 => 0x1007 }, + 'autobracketingmode' => { 291 => '12.3' }, + 'autobracketingset' => { 291 => '12.1' }, + 'autobracketmodem' => { 279 => '21.2', 280 => '13.3', 282 => '13.2', 283 => '13.2', 288 => '26.2', 292 => '13.3', 293 => '13.2', 295 => 0x5f }, + 'autobracketorder' => { 184 => 0x43, 279 => '21.3', 280 => '13.2', 282 => '13.1', 283 => '13.1', 288 => '26.3', 289 => '12.2', 290 => '2.2', 291 => '12.2', 292 => '13.2', 293 => '13.1', 294 => '13.2', 295 => 0x61 }, + 'autobracketset' => { 279 => '21.1', 280 => '13.1', 284 => '11.1', 285 => '12.1', 286 => '12.1', 288 => '26.1', 289 => '12.1', 290 => '2.1', 292 => '13.1', 294 => '13.1' }, + 'autobrightness' => { 478 => 'AutoBrightness', 480 => 'AutoBrightness' }, + 'autocontrast' => { 478 => 'AutoContrast', 480 => 'AutoContrast' }, + 'autodistortioncontrol' => { 206 => 0x4, 228 => 0x143 }, + 'autodynamicrange' => { 127 => 0x140b }, + 'autoexposure' => { 478 => 'AutoExposure', 480 => 'AutoExposure' }, + 'autoexposurebracketing' => { 77 => 0x10 }, + 'autoflashisosensitivity' => { 282 => '38.5', 283 => '38.5', 293 => '38.5', 295 => 0x5b }, + 'autofocus' => { 300 => 0x209 }, + 'autofocusmoderestrictions' => { 295 => 0x107 }, + 'autofp' => { 290 => '7.3', 294 => '31.4' }, + 'autoiso' => { 77 => 0x1, 113 => 0x3008, 229 => 0x142, 281 => '1.1', 290 => '1.1' }, + 'autoisomax' => { 281 => '1.2', 290 => '1.2' }, + 'autoisominshutterspeed' => { 281 => '1.3', 290 => '1.3' }, + 'autolateralca' => { 478 => 'AutoLateralCA', 480 => 'AutoLateralCA' }, + 'autolightingoptimizer' => { 16 => 0xbe, 17 => 0xbf, 20 => 0xbf, 62 => 0x2, 84 => 0x204, 103 => 0x20500, 109 => 0x6f }, + 'autolightingoptimizeron' => { 103 => '0x20500.0', 109 => 0x6e }, + 'autoportraitframed' => { 420 => 0x2016 }, + 'autoredeye' => { 272 => 0xfe28a44f }, + 'autorotate' => { 77 => 0x1b }, + 'autoshadows' => { 478 => 'AutoShadows', 480 => 'AutoShadows' }, + 'autotone' => { 478 => 'AutoTone', 480 => 'AutoTone' }, + 'autotonedigest' => { 478 => 'AutoToneDigest', 480 => 'AutoToneDigest' }, + 'autotonedigestnosat' => { 478 => 'AutoToneDigestNoSat', 480 => 'AutoToneDigestNoSat' }, + 'autowhiteversion' => { 478 => 'AutoWhiteVersion', 480 => 'AutoWhiteVersion' }, + 'auxiliarylens' => { 226 => 0x82 }, + 'avaperturesetting' => { 336 => 0x13 }, + 'averageblacklevel' => { 45 => 0xe7, 47 => 0xfb, 48 => 0x114, 49 => 0x146 }, + 'averagelv' => { 187 => 0x38 }, + 'avsettingwithoutlens' => { 84 => 0x707 }, + 'azimuth' => { 165 => 'Azimuth' }, + 'babyage' => { 320 => [0x8010,0x33] }, + 'babyname' => { 320 => 0x66 }, + 'backgroundalpha' => { 499 => 'bgalpha' }, + 'balance' => { 374 => 'player.movie.audio.balance' }, + 'baseexposurecompensation' => { 336 => 0x15 }, + 'baseiso' => { 77 => 0x2, 97 => 0x101c, 138 => 0x903, 322 => 0x312a, 451 => 0x6 }, + 'baseisodaylight' => { 138 => 0x910 }, + 'baseisoflash' => { 138 => 0x913 }, + 'baseisofluorescent' => { 138 => 0x912 }, + 'baseisotungsten' => { 138 => 0x911 }, + 'baselineexposure' => { 119 => 0xc62a }, + 'baselineexposureoffset' => { 119 => 0xc7a5 }, + 'baselinenoise' => { 119 => 0xc62b }, + 'baselinesharpness' => { 119 => 0xc62c }, + 'baseurl' => { 502 => 'BaseURL' }, + 'bass' => { 374 => 'player.movie.audio.bass' }, + 'batterylevel' => { 320 => 0x38, 407 => 0x51, 411 => 0xc, 412 => 0x4, 413 => 0x4, 452 => 0x7 }, + 'batterylevelgrip1' => { 452 => 0x6 }, + 'batterylevelgrip2' => { 452 => 0x8 }, + 'batteryorder' => { 279 => '12.5', 288 => '13.2', 289 => '2.1', 292 => '3.1' }, + 'batterystate' => { 184 => 0x60, 407 => 0x50, 413 => 0x14 }, + 'batterytemperature' => { 411 => 0x1, 413 => 0x2, 452 => 0x5 }, + 'batterytype' => { 64 => 0x38, 383 => 0x66 }, + 'batteryunknown' => { 411 => 0x2, 413 => 0x0 }, + 'batteryvoltage' => { 138 => 0x408, 381 => 0x2a, 382 => 0x49, 383 => 0x62, 411 => 0x8 }, + 'batteryvoltage1' => { 413 => 0x6 }, + 'batteryvoltage2' => { 413 => 0x8 }, + 'batteryvoltageavg' => { 383 => 0x64 }, + 'bayergreensplit' => { 119 => 0xc62d }, + 'bayerpattern' => { 137 => 0xf902, 188 => 0x17 }, + 'beatsperminute' => { 372 => 'tmpo' }, + 'beatspliceparams' => { 504 => 'beatSpliceParams' }, + 'beatspliceparamsriseindecibel' => { 504 => [\'beatSpliceParams','beatSpliceParamsRiseInDecibel'] }, + 'beatspliceparamsriseintimeduration' => { 504 => [\'beatSpliceParams','beatSpliceParamsRiseInTimeDuration'] }, + 'beatspliceparamsriseintimedurationscale' => { 504 => [\'beatSpliceParams','beatSpliceParamsRiseInTimeDurationScale'] }, + 'beatspliceparamsriseintimedurationvalue' => { 504 => [\'beatSpliceParams','beatSpliceParamsRiseInTimeDurationValue'] }, + 'beatspliceparamsusefilebeatsmarker' => { 504 => [\'beatSpliceParams','beatSpliceParamsUseFileBeatsMarker'] }, + 'beep' => { 279 => '13.1', 280 => '5.4', 281 => '0.1', 284 => '2.1', 285 => '3.1', 286 => '3.1', 288 => '10.1', 290 => '0.1', 292 => '5.5', 294 => '4.1' }, + 'beeppitch' => { 289 => '3.1' }, + 'beepvolume' => { 289 => '4.5' }, + 'bestqualityscale' => { 119 => 0xc65c }, + 'bestshotmode' => { 113 => 0x3007 }, + 'bitdepth' => { 162 => 'BitDepth', 188 => 0x11, 237 => 0x41 }, + 'bitspercomponent' => { 133 => 0x87 }, + 'bitspersample' => { 119 => 0x102, 325 => 0xa, 500 => 'BitsPerSample' }, + 'blackacquirerows' => { 138 => 0x18ba }, + 'blacklevel' => { 119 => 0xc61a, 204 => 0x20, 226 => 0x3d, 302 => [0x401,0x1012], 364 => 0x21d, 427 => [0x7300,0x7310] }, + 'blacklevel2' => { 301 => 0x600, 305 => 0x600 }, + 'blacklevelblue' => { 325 => 0x1e }, + 'blacklevelbottom' => { 138 => 0x3f0 }, + 'blackleveldata' => { 364 => 0x223 }, + 'blackleveldeltah' => { 119 => 0xc61b }, + 'blackleveldeltav' => { 119 => 0xc61c }, + 'blacklevelgreen' => { 325 => 0x1d }, + 'blacklevelred' => { 325 => 0x1c }, + 'blacklevelrepeatdim' => { 119 => 0xc619 }, + 'blacklevelrough' => { 138 => 0x40e }, + 'blacklevelroughafter' => { 138 => 0x416 }, + 'blacklevels' => { 35 => 0x1d }, + 'blackleveltop' => { 138 => 0x3ef }, + 'blackpoint' => { 355 => 0x200 }, + 'blacks2012' => { 478 => 'Blacks2012', 480 => 'Blacks2012' }, + 'blacksadj' => { 455 => 0x9018 }, + 'bleachbypasstoning' => { 355 => 0x7f }, + 'blockshotafresponse' => { 282 => '1.5', 283 => '1.5', 293 => '1.5', 295 => 0x7 }, + 'blogtitle' => { 494 => 'blogTitle' }, + 'blogurl' => { 494 => 'blogURL' }, + 'bluebalance' => { 302 => 0x1018, 325 => 0x12, 355 => 0x1b }, + 'bluecurvelimits' => { 108 => 0x1fe }, + 'bluecurvepoints' => { 107 => 0x79, 108 => 0x1d4 }, + 'bluehsl' => { 103 => 0x20915 }, + 'bluehue' => { 478 => 'BlueHue', 480 => 'BlueHue' }, + 'bluesaturation' => { 478 => 'BlueSaturation', 480 => 'BlueSaturation' }, + 'bluratinfinity' => { 464 => 'BlurAtInfinity' }, + 'blurcontrol' => { 355 => 0x82 }, + 'blurwarning' => { 127 => 0x1300 }, + 'bodybatteryadload' => { 334 => 0x3 }, + 'bodybatteryadnoload' => { 334 => 0x2 }, + 'bodybatterystate' => { 334 => '1.1' }, + 'bodybatteryvoltage1' => { 334 => 0x2 }, + 'bodybatteryvoltage2' => { 334 => 0x4 }, + 'bodybatteryvoltage3' => { 334 => 0x6 }, + 'bodybatteryvoltage4' => { 334 => 0x8 }, + 'bodyfirmware' => { 388 => 0x0 }, + 'bodyfirmwareversion' => { 298 => 0x104, 299 => 0x100, 302 => 0x104 }, + 'bodyserialnumber' => { 388 => 0x10 }, + 'bookedition' => { 494 => 'bookEdition' }, + 'bootloaderversion' => { 382 => 0x26 }, + 'bracketincrement' => { 229 => 0x21a }, + 'bracketmode' => { 57 => 0x3 }, + 'bracketprogram' => { 229 => 0x218 }, + 'bracketsequence' => { 113 => 0x301d }, + 'bracketset' => { 229 => 0x216 }, + 'bracketsettings' => { 320 => 0x45 }, + 'bracketshotnumber' => { 57 => 0x5, 336 => 0x9, 418 => 0x2b }, + 'bracketshotnumber2' => { 418 => 0x2d }, + 'bracketstep' => { 181 => 0xe }, + 'bracketvalue' => { 57 => 0x4 }, + 'brightness' => { 119 => 0xfe53, 156 => 'Brightness', 176 => 'Brightness', 181 => 0x2c, 231 => 0x34, 232 => 0x39, 233 => 0x41, 374 => 'player.movie.visual.brightness', 381 => 0x25, 383 => 0x54, 407 => 0x22, 420 => 0x2007, 478 => 'Brightness', 480 => 'Brightness' }, + 'brightnessadj' => { 108 => 0x114, 265 => 0x0, 275 => 0x2d, 455 => 0x8018 }, + 'brightnessvalue' => { 119 => 0x9203, 187 => [0x691,0x49c3], 302 => 0x1003, 425 => 0x1e, 429 => 0x1140, 430 => 0x1140, 431 => 0x111c, 432 => 0x1198, 433 => 0x1174, 434 => 0x102c, 435 => 0x224, 436 => 0x224, 437 => 0x219, 484 => 'BrightnessValue' }, + 'buildnumber' => { 191 => 0x5500 }, + 'bulbduration' => { 77 => 0x18 }, + 'burstcount' => { 138 => 0x40d }, + 'burstid' => { 461 => 'BurstID' }, + 'burstmode' => { 140 => 0xa, 320 => 0x2a }, + 'burstmode2' => { 140 => 0x18 }, + 'burstprimary' => { 461 => 'BurstPrimary' }, + 'burstshot' => { 397 => 0x34 }, + 'burstspeed' => { 320 => 0x77 }, 'burstuuid' => { 1 => 0xb }, - 'buttonfunctioncontroloff' => { 78 => 0x70a }, - 'bwadjustment' => { 121 => 0x1049 }, - 'bwfilter' => { 171 => 0x2a, 179 => 0x39 }, - 'bwmode' => { 279 => 0x203 }, - 'by-line' => { 125 => 0x50 }, - 'by-linetitle' => { 125 => 0x55 }, - 'bytecount' => { 456 => 'byteCount' }, - 'c14configuration' => { 131 => 0x1964 }, - 'cacheversion' => { 113 => 0xc7aa }, - 'calibration' => { 368 => [0x24,0x30] }, - 'calibrationhistory' => { 131 => 0x9c9 }, - 'calibrationilluminant1' => { 113 => 0xc65a }, - 'calibrationilluminant2' => { 113 => 0xc65b }, - 'calibrationversion' => { 131 => 0x9c6 }, - 'callforimage' => { 431 => 'CallForImage' }, - 'cameraangle' => { 466 => 'cameraAngle' }, - 'cameracalibration1' => { 113 => 0xc623 }, - 'cameracalibration2' => { 113 => 0xc624 }, - 'cameracalibrationsig' => { 113 => 0xc6f3 }, - 'cameracolorcalibration01' => { 35 => 0x0, 36 => 0x0 }, - 'cameracolorcalibration02' => { 35 => 0x4, 36 => 0x5 }, - 'cameracolorcalibration03' => { 35 => 0x8, 36 => 0xa }, - 'cameracolorcalibration04' => { 35 => 0xc, 36 => 0xf }, - 'cameracolorcalibration05' => { 35 => 0x10, 36 => 0x14 }, - 'cameracolorcalibration06' => { 35 => 0x14, 36 => 0x19 }, - 'cameracolorcalibration07' => { 35 => 0x18, 36 => 0x1e }, - 'cameracolorcalibration08' => { 35 => 0x1c, 36 => 0x23 }, - 'cameracolorcalibration09' => { 35 => 0x20, 36 => 0x28 }, - 'cameracolorcalibration10' => { 35 => 0x24, 36 => 0x2d }, - 'cameracolorcalibration11' => { 35 => 0x28, 36 => 0x32 }, - 'cameracolorcalibration12' => { 35 => 0x2c, 36 => 0x37 }, - 'cameracolorcalibration13' => { 35 => 0x30, 36 => 0x3c }, - 'cameracolorcalibration14' => { 35 => 0x34, 36 => 0x41 }, - 'cameracolorcalibration15' => { 35 => 0x38, 36 => 0x46 }, - 'camerae-mountversion' => { 420 => 0xb }, - 'cameraelevationangle' => { 113 => 0x9405, 447 => 'CameraElevationAngle' }, - 'camerafilename' => { 431 => 'CameraFilename' }, - 'cameraid' => { 279 => 0x209, 367 => 0x209 }, - 'cameraiso' => { 33 => 0x10 }, - 'cameralabel' => { 113 => 0xc7a1, 466 => 'cameraLabel' }, - 'cameramakemodel' => { 431 => 'CameraMakeModel' }, - 'cameramodel' => { 341 => 0x410, 466 => 'cameraModel' }, - 'cameramodelid' => { 167 => 'CameraModelID' }, - 'cameramove' => { 466 => 'cameraMove' }, - 'cameraorientation' => { 6 => 0x30, 8 => 0x7d, 10 => 0x30, 12 => 0x35, 13 => 0x30, 14 => 0x30, 15 => 0x31, 16 => 0x31, 17 => 0x35, 18 => 0x27, 19 => 0x31, 20 => 0x7d, 21 => 0x38, 22 => 0x36, 23 => 0x7d, 24 => 0x83, 25 => 0x84, 27 => 0x35, 28 => 0x96, 297 => 0x8f, 336 => 0x1, 341 => 0x100, 382 => [0x16,0x18], 408 => 0x28, 409 => 0x24, 410 => 0x29 }, - 'cameraowner' => { 134 => 0xc353 }, - 'cameraparameters' => { 279 => 0x2050 }, - 'camerapicturestyle' => { 27 => 0xaf }, - 'camerapitch' => { 109 => 0x9 }, - 'cameraprofile' => { 442 => 'CameraProfile' }, - 'cameraprofiledigest' => { 442 => 'CameraProfileDigest' }, - 'camerarawcolortone' => { 103 => 0xe1 }, - 'camerarawcontrast' => { 103 => 0xe3 }, - 'camerarawhighlightpoint' => { 103 => 0xe6 }, - 'camerarawlinear' => { 103 => 0xe4 }, - 'camerarawoutputhighlightpoint' => { 103 => 0xe8 }, - 'camerarawoutputshadowpoint' => { 103 => 0xe9 }, - 'camerarawsaturation' => { 103 => 0xe2 }, - 'camerarawshadowpoint' => { 103 => 0xe7 }, - 'camerarawsharpness' => { 103 => 0xe5 }, - 'cameraroll' => { 109 => 0xb }, - 'cameraserialnumber' => { 113 => 0xc62f, 169 => 'CameraSerialNumber', 431 => 'CameraSerialNumber' }, - 'camerasettingsversion' => { 274 => 0x0 }, - 'cameratemperature' => { 6 => 0x18, 8 => 0x1b, 10 => 0x18, 12 => 0x19, 13 => 0x18, 14 => 0x18, 15 => 0x19, 16 => 0x19, 17 => 0x19, 18 => 0x17, 19 => 0x19, 20 => 0x1b, 21 => 0x19, 22 => 0x19, 23 => 0x1b, 24 => 0x1b, 25 => 0x1b, 26 => 0x1b, 27 => 0x19, 28 => 0x1b, 29 => [0x87,0x91], 30 => [0x99,0x9f,0xa4,0xa8,0x105], 32 => ['-3',0x64,0x47,0x53,0x5b,0x5c], 72 => 0xc, 131 => 0x406, 278 => 0x1306, 292 => 0x320, 299 => 0x3402, 332 => 0x47, 365 => 0x43, 412 => 0x5 }, - 'cameratemperature4' => { 337 => 0x14 }, - 'cameratemperature5' => { 337 => 0x16 }, - 'cameratemperaturerangemax' => { 115 => 0x5 }, - 'cameratemperaturerangemin' => { 115 => 0x6 }, - 'cameratype' => { 72 => 0x1a, 279 => 0x207 }, - 'cameratype2' => { 275 => 0x100 }, - 'camerayaw' => { 109 => 0xa }, - 'canondr4' => { 114 => 'CanonDR4' }, - 'canonexposuremode' => { 33 => 0x14 }, - 'canonfiledescription' => { 91 => 0x805 }, - 'canonfilelength' => { 60 => 0xe }, - 'canonfirmwareversion' => { 60 => 0x7, 91 => 0x80b }, - 'canonflashinfo' => { 91 => 0x1028 }, - 'canonflashmode' => { 33 => 0x4 }, - 'canonimagesize' => { 9 => 0x39, 33 => 0xa }, - 'canonimagetype' => { 60 => 0x6, 91 => 0x815 }, - 'canonmodelid' => { 60 => 0x10, 91 => 0x1834 }, - 'canonvrd' => { 114 => 'CanonVRD' }, - 'caption' => { 436 => 'caption' }, - 'caption-abstract' => { 125 => 0x78 }, - 'captionsauthornames' => { 445 => 'CaptionsAuthorNames' }, - 'captionsdatetimestamps' => { 445 => 'CaptionsDateTimeStamps' }, - 'captionwriter' => { 454 => 'CaptionWriter' }, - 'captureframerate' => { 107 => 0x4001 }, - 'captureheightnormal' => { 131 => 0x1839 }, - 'capturelook' => { 131 => 0xc48 }, - 'capturesoftware' => { 429 => 'CaptureSoftware' }, - 'capturewidthnormal' => { 131 => 0x1838 }, - 'capturewidthtest' => { 131 => 0x1842 }, - 'cardshutterlock' => { 174 => 0x49 }, - 'casioimagesize' => { 107 => 0x9 }, - 'catalogsets' => { 125 => 0xff, 424 => 'CatalogSets', 434 => 'CatalogSets' }, - 'categories' => { 60 => 0x23, 436 => 'categories' }, - 'category' => { 125 => 0xf, 273 => 0x30, 454 => 'Category' }, - 'cbcrgain' => { 365 => 0xa036 }, - 'cbcrgaindefault' => { 365 => 0xa035 }, - 'cbcrmatrix' => { 365 => 0xa034 }, - 'cbcrmatrixdefault' => { 365 => 0xa033 }, - 'ccdboardversion' => { 292 => 0x331 }, - 'ccdscanmode' => { 279 => 0x1039 }, - 'ccdsensitivity' => { 240 => 0x6 }, - 'ccdversion' => { 292 => 0x330 }, - 'cellglobalid' => { 440 => 'cgi' }, - 'celllength' => { 113 => 0x109 }, - 'cellr' => { 440 => 'r' }, - 'celltowerid' => { 440 => 'cellid' }, - 'cellwidth' => { 113 => 0x108 }, - 'centerafarea' => { 268 => '15.1' }, - 'centerfocuspoint' => { 272 => '2.2' }, - 'centerpixel' => { 131 => 0x40c }, - 'centerweightedareasize' => { 257 => '7.1', 258 => '8.1', 260 => '8.1', 261 => '8.1', 265 => '7.1', 266 => '5.1', 267 => '7.1', 268 => '6.3', 270 => '8.1', 271 => '8.1', 272 => '8.1' }, - 'certificate' => { 470 => 'Certificate' }, - 'cfainterpolationalgorithm' => { 131 => 0xe60 }, - 'cfainterpolationmetric' => { 131 => 0xe61 }, - 'cfaoffsetcols' => { 131 => 0xc71 }, - 'cfaoffsetrows' => { 131 => 0xc6f }, - 'cfapattern' => { 113 => 0xa302, 302 => 0x9, 446 => 'CFAPattern' }, - 'cfapattern2' => { 113 => 0x828e }, - 'cfapatterncolumns' => { 446 => [\'CFAPattern','CFAPatternColumns'] }, - 'cfapatternrows' => { 446 => [\'CFAPattern','CFAPatternRows'] }, - 'cfapatternvalues' => { 446 => [\'CFAPattern','CFAPatternValues'] }, - 'cfarepeatpatterndim' => { 113 => 0x828d }, - 'cfazipperfixthreshold' => { 131 => 0xe62 }, - 'channel' => { 456 => 'channel' }, - 'channela-lang' => { 456 => [\'channel','channelA-lang'] }, - 'channelchannel' => { 456 => [\'channel','channelChannel'] }, - 'channels' => { 146 => 'Channels' }, - 'channelsubchannel1' => { 456 => [\'channel','channelSubchannel1'] }, - 'channelsubchannel2' => { 456 => [\'channel','channelSubchannel2'] }, - 'channelsubchannel3' => { 456 => [\'channel','channelSubchannel3'] }, - 'channelsubchannel4' => { 456 => [\'channel','channelSubchannel4'] }, - 'checkmark' => { 97 => 0x10101, 102 => 0x26a }, - 'checkmark2' => { 103 => 0x8e }, - 'childfontfiles' => { 471 => [\'Fonts','FontsChildFontFiles'] }, - 'chmodeshootingspeed' => { 257 => '10.3', 258 => '11.2' }, - 'chromablurradius' => { 113 => 0xc631 }, - 'chromanoisecolorspace' => { 131 => 0xe6d }, - 'chromanoiseedgemapthresh' => { 131 => 0xe6c }, - 'chromanoisehighfthresh' => { 131 => 0xe6a }, - 'chromanoiselowfthresh' => { 131 => 0xe6b }, - 'chromaticaberration' => { 97 => 0x20703, 103 => 0x66, 365 => 0xa051 }, - 'chromaticaberrationb' => { 442 => 'ChromaticAberrationB' }, - 'chromaticaberrationblue' => { 97 => 0x20708, 103 => 0x6b }, - 'chromaticaberrationcorr' => { 74 => [0x4,0x5] }, - 'chromaticaberrationcorrection' => { 113 => 0x7034, 322 => 0x1, 421 => 0x900d }, - 'chromaticaberrationcorrparams' => { 113 => 0x7035, 416 => 0x66a, 417 => [0x37c,0x384,0x39c,0x3b0,0x3b8] }, - 'chromaticaberrationon' => { 97 => '0x20703.0', 103 => 0x62 }, - 'chromaticaberrationr' => { 442 => 'ChromaticAberrationR' }, - 'chromaticaberrationred' => { 97 => 0x20707, 103 => 0x6a }, - 'chromaticaberrationsetting' => { 75 => 0x6 }, - 'chrominancenoisereduction' => { 97 => 0x20601, 103 => 0x5e, 368 => 0x1a }, - 'chrominancenr_tiff_jpeg' => { 103 => 0x60 }, - 'circadatecreated' => { 452 => 'CircaDateCreated' }, - 'circgradbasedcorractive' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionActive'] }, - 'circgradbasedcorramount' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionAmount'] }, - 'circgradbasedcorrbrightness' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalBrightness'] }, - 'circgradbasedcorrclarity' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalClarity'] }, - 'circgradbasedcorrclarity2012' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalClarity2012'] }, - 'circgradbasedcorrcontrast' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalContrast'] }, - 'circgradbasedcorrcontrast2012' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalContrast2012'] }, - 'circgradbasedcorrdefringe' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalDefringe'] }, - 'circgradbasedcorrexposure' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalExposure'] }, - 'circgradbasedcorrexposure2012' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalExposure2012'] }, - 'circgradbasedcorrhighlights2012' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalHighlights2012'] }, - 'circgradbasedcorrhue' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalToningHue'] }, - 'circgradbasedcorrluminancenoise' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalLuminanceNoise'] }, - 'circgradbasedcorrmaskalpha' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksAlpha'] }, - 'circgradbasedcorrmaskangle' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksAngle'] }, - 'circgradbasedcorrmaskbottom' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksBottom'] }, - 'circgradbasedcorrmaskcentervalue' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCenterValue'] }, - 'circgradbasedcorrmaskcenterweight' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCenterWeight'] }, - 'circgradbasedcorrmaskdabs' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksDabs'] }, - 'circgradbasedcorrmaskfeather' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFeather'] }, - 'circgradbasedcorrmaskflipped' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFlipped'] }, - 'circgradbasedcorrmaskflow' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFlow'] }, - 'circgradbasedcorrmaskfullx' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFullX'] }, - 'circgradbasedcorrmaskfully' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFullY'] }, - 'circgradbasedcorrmaskleft' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksLeft'] }, - 'circgradbasedcorrmaskmidpoint' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMidpoint'] }, - 'circgradbasedcorrmaskperimetervalue' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksPerimeterValue'] }, - 'circgradbasedcorrmaskradius' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksRadius'] }, - 'circgradbasedcorrmaskright' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksRight'] }, - 'circgradbasedcorrmaskroundness' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksRoundness'] }, - 'circgradbasedcorrmasks' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasks'] }, - 'circgradbasedcorrmasksizex' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksSizeX'] }, - 'circgradbasedcorrmasksizey' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksSizeY'] }, - 'circgradbasedcorrmasktop' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksTop'] }, - 'circgradbasedcorrmaskvalue' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskValue'] }, - 'circgradbasedcorrmaskversion' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksVersion'] }, - 'circgradbasedcorrmaskwhat' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksWhat'] }, - 'circgradbasedcorrmaskx' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksX'] }, - 'circgradbasedcorrmasky' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksY'] }, - 'circgradbasedcorrmaskzerox' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksZeroX'] }, - 'circgradbasedcorrmaskzeroy' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksZeroY'] }, - 'circgradbasedcorrmoire' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalMoire'] }, - 'circgradbasedcorrsaturation' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalSaturation','CircularGradientBasedCorrectionsLocalToningSaturation'] }, - 'circgradbasedcorrshadows2012' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalShadows2012'] }, - 'circgradbasedcorrsharpness' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalSharpness'] }, - 'circgradbasedcorrtemperature' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalTemperature'] }, - 'circgradbasedcorrtint' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalTint'] }, - 'circgradbasedcorrwhat' => { 442 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsWhat'] }, - 'circulargradientbasedcorrections' => { 442 => 'CircularGradientBasedCorrections' }, - 'city' => { 125 => 0x5a, 152 => 'City', 297 => 0x6d, 454 => 'City' }, - 'city2' => { 297 => 0x80 }, - 'clarity' => { 214 => 0x35, 442 => 'Clarity' }, - 'clarity2012' => { 442 => 'Clarity2012' }, - 'claritycontrol' => { 332 => 0x96 }, - 'classifystate' => { 125 => 0xe1 }, - 'clearretouch' => { 297 => 0x7c }, - 'clearretouchvalue' => { 297 => 0xa3 }, - 'client' => { 466 => 'client' }, - 'clientname' => { 448 => 'ClientName' }, - 'clmodeshootingspeed' => { 257 => '10.2', 258 => '11.3', 260 => '11.2', 261 => '11.2', 266 => '11.2', 267 => '10.2', 270 => '11.2', 271 => '11.2', 272 => '11.1' }, - 'cmcontrast' => { 282 => 0x2022 }, - 'cmexposurecompensation' => { 282 => 0x2000 }, - 'cmhue' => { 282 => 0x2021 }, - 'cmsaturation' => { 282 => 0x2020 }, - 'cmsharpness' => { 282 => 0x2023 }, - 'cmwhitebalance' => { 282 => 0x2001 }, - 'cmwhitebalancecomp' => { 282 => 0x2002 }, - 'cmwhitebalancegraypoint' => { 282 => 0x2010 }, - 'codec' => { 160 => 'Codec' }, - 'codedcharacterset' => { 126 => 0x5a }, - 'collection' => { 287 => 'Collection' }, - 'collectionname' => { 161 => [\'Collections','CollectionsCollectionName'] }, - 'collections' => { 161 => 'Collections', 436 => 'collections' }, - 'collectionuri' => { 161 => [\'Collections','CollectionsCollectionURI'] }, - 'color' => { 455 => 'color' }, - 'coloraberrationcontrol' => { 250 => 0xc89224b }, - 'coloradjustment' => { 368 => 0x14 }, - 'coloradjustmentmode' => { 367 => 0x210 }, - 'coloranta' => { 471 => [\'Colorants','ColorantsA'] }, - 'colorantb' => { 471 => [\'Colorants','ColorantsB'] }, - 'colorantblack' => { 471 => [\'Colorants','ColorantsBlack'] }, - 'colorantblue' => { 471 => [\'Colorants','ColorantsBlue'] }, - 'colorantcyan' => { 471 => [\'Colorants','ColorantsCyan'] }, - 'colorantgray' => { 471 => [\'Colorants','ColorantsGray'] }, - 'colorantgreen' => { 471 => [\'Colorants','ColorantsGreen'] }, - 'colorantl' => { 471 => [\'Colorants','ColorantsL'] }, - 'colorantmagenta' => { 471 => [\'Colorants','ColorantsMagenta'] }, - 'colorantmode' => { 471 => [\'Colorants','ColorantsMode'] }, - 'colorantred' => { 471 => [\'Colorants','ColorantsRed'] }, - 'colorants' => { 471 => 'Colorants' }, - 'colorantswatchname' => { 471 => [\'Colorants','ColorantsSwatchName'] }, - 'coloranttint' => { 471 => [\'Colorants','ColorantsTint'] }, - 'coloranttype' => { 471 => [\'Colorants','ColorantsType'] }, - 'colorantyellow' => { 471 => [\'Colorants','ColorantsYellow'] }, - 'colorbalance' => { 147 => 'ColorBalance' }, - 'colorbalanceadj' => { 250 => 0x76a43202 }, - 'colorbalanceblue' => { 171 => 0x1e }, - 'colorbalancegreen' => { 171 => 0x1d }, - 'colorbalancered' => { 171 => 0x1c }, - 'colorbalanceversion' => { 192 => 0x4, 193 => 0x4, 194 => 0x0 }, - 'colorblur' => { 103 => 0x65 }, - 'colorbluron' => { 97 => 0x20704 }, - 'colorbooster' => { 250 => 0x5f0e7d23 }, - 'colorboostlevel' => { 244 => 0x1 }, - 'colorboosttype' => { 244 => 0x0 }, - 'colorchromeeffect' => { 121 => 0x1048 }, - 'colorclass' => { 343 => 0xde, 344 => 'ColorClass' }, - 'colorcompensationfilter' => { 174 => [0x3a,0x5f], 176 => 0x111, 388 => 0xb022 }, - 'colorcompensationfiltercustom' => { 376 => 0xd, 377 => 0xc }, - 'colorcompensationfilterset' => { 376 => 0x8, 377 => 0x7, 378 => 0x18, 393 => 0xf }, - 'colorcontrol' => { 279 => 0x102b }, - 'colorcorrection' => { 421 => 0x8015 }, - 'colorcreatoreffect' => { 274 => 0x532 }, - 'colordataversion' => { 41 => 0x0, 42 => 0x0, 43 => 0x0, 44 => 0x0, 45 => 0x0, 46 => 0x0, 47 => 0x0 }, - 'coloreffect' => { 297 => 0x28 }, - 'colorfilter' => { 106 => 0x17, 107 => 0x3017, 171 => 0x29, 179 => [0x38,0x4d,0x4f], 339 => 0x17 }, - 'colorgain' => { 218 => 0x51 }, - 'colorhue' => { 97 => 0x20900, 211 => 0x8d }, - 'colorimetricreference' => { 113 => 0xc6bf }, - 'colorlabel' => { 445 => 'ColorLabel' }, - 'colormatrix' => { 278 => 0x200, 279 => 0x1011, 365 => 0xa030 }, - 'colormatrix1' => { 113 => 0xc621, 341 => 0x106 }, - 'colormatrix2' => { 113 => 0xc622, 282 => 0x200, 341 => 0x226 }, - 'colormatrixa' => { 332 => 0x203 }, - 'colormatrixadobergb' => { 365 => 0xa032 }, - 'colormatrixb' => { 332 => 0x204 }, - 'colormatrixnumber' => { 279 => 0x1019 }, - 'colormatrixsrgb' => { 365 => 0xa031 }, - 'colormode' => { 107 => 0x3015, 121 => 0x1210, 133 => 0x66, 171 => 0x28, 174 => 0x16, 176 => 0x101, 177 => 0x36, 179 => 0x7, 211 => 0x3, 240 => 0x4, 297 => 0x32, 368 => 0x2c, 388 => 0xb029, 454 => 'ColorMode' }, - 'colormoirereduction' => { 97 => 0x20670, 251 => 0x15 }, - 'colormoirereductionmode' => { 251 => 0x5 }, - 'colormoirereductionon' => { 97 => '0x20670.0' }, - 'colornoisereduction' => { 421 => 0x8029, 442 => 'ColorNoiseReduction' }, - 'colornoisereductiondetail' => { 442 => 'ColorNoiseReductionDetail' }, - 'colornoisereductionintensity' => { 251 => 0x18 }, - 'colornoisereductionsharpness' => { 251 => 0x1c }, - 'colornoisereductionsmoothness' => { 442 => 'ColorNoiseReductionSmoothness' }, - 'colorplanes' => { 117 => 0x2 }, - 'colorprofile' => { 171 => 0x33 }, - 'colorprofilesettings' => { 274 => 0x539 }, - 'colorrepresentation' => { 127 => 0x3c }, - 'colorsaturationadj' => { 97 => 0x20305 }, - 'colorsequence' => { 127 => 0x41 }, - 'colorspace' => { 48 => 0x3, 60 => 0xb4, 91 => 0x10b4, 113 => 0xa001, 153 => 'ColorSpace', 172 => 0x2f, 173 => 0x25, 174 => 0x17, 211 => 0x1e, 274 => 0x507, 332 => 0x37, 365 => 0xa011, 368 => 0xb, 376 => 0x1b, 377 => 0x83, 378 => 0xe, 393 => 0x6, 446 => 'ColorSpace' }, - 'colortempasshot' => { 37 => 0x4, 38 => 0x7, 39 => 0x1d, 40 => 0x26, 41 => 0x43, 44 => 0x43, 45 => 0x43, 46 => 0x43, 47 => 0x4b }, - 'colortempauto' => { 37 => 0x9, 38 => 0xf, 39 => 0x22, 40 => 0x1c, 41 => 0x48, 44 => 0x48, 45 => 0x48, 46 => 0x48, 47 => 0x50 }, - 'colortempcloudy' => { 37 => 0x22, 38 => 0x37, 39 => 0x31, 40 => 0x35, 41 => 0x5c, 44 => 0x75, 45 => 0x8e, 46 => 0x93, 47 => 0x96, 332 => 0x55 }, - 'colortempcustom' => { 41 => 0x84 }, - 'colortempcustom1' => { 39 => 0x45 }, - 'colortempcustom2' => { 39 => 0x4a }, - 'colortempdaylight' => { 37 => 0x18, 38 => 0x27, 39 => 0x27, 40 => 0x2b, 41 => 0x52, 44 => 0x6b, 45 => 0x84, 46 => 0x89, 47 => 0x8c, 332 => 0x53 }, - 'colortemperature' => { 6 => 0x73, 7 => [0x48,0x4e], 8 => 0xc0, 9 => 0x37, 10 => 0x62, 11 => 0x37, 12 => 0x7c, 13 => 0x73, 14 => 0x73, 15 => 0x77, 16 => 0x73, 17 => 0x7c, 18 => 0x58, 19 => 0x73, 20 => 0xc0, 21 => 0x7f, 22 => 0x7d, 23 => 0xc0, 24 => 0xc6, 25 => 0xc7, 26 => 0x135, 27 => 0x7b, 28 => 0x13a, 60 => 0xae, 70 => 0x9, 91 => 0x10ae, 121 => 0x1005, 131 => 0x846, 147 => 'ColorTemperature', 172 => [0x6e,0x49], 173 => 0x3f, 174 => [0x39,0x5e], 176 => 0x10b, 179 => [0x3c,0x4c,0x4e], 292 => 0x321, 332 => 0x50, 358 => 0x1308, 388 => 0xb021, 442 => 'Temperature' }, - 'colortemperatureadj' => { 421 => 0x8013 }, - 'colortemperatureauto' => { 211 => 0x4f }, - 'colortemperaturebg' => { 279 => 0x1013 }, - 'colortemperaturecustom' => { 376 => 0xc, 377 => 0xb }, - 'colortemperaturerg' => { 279 => 0x1014 }, - 'colortemperatureset' => { 376 => 0x7, 377 => 0x6 }, - 'colortemperaturesetting' => { 174 => 0x25, 378 => 0x17, 393 => 0xe }, - 'colortempflash' => { 37 => 0x36, 38 => 0x57, 39 => 0x40, 40 => 0x49, 41 => 0x70, 44 => 0x89, 45 => 0xa2, 46 => 0xa7, 47 => 0xaa, 332 => 0x5a }, - 'colortempflashdata' => { 41 => 0x24a }, - 'colortempfluorescent' => { 37 => 0x2c, 38 => 0x47, 39 => 0x3b, 40 => 0x3f, 41 => 0x66, 44 => 0x7f, 45 => 0x98, 46 => 0x9d, 47 => 0xa0 }, - 'colortempfluorescentd' => { 332 => 0x57 }, - 'colortempfluorescentn' => { 332 => 0x58 }, - 'colortempfluorescentw' => { 332 => 0x59 }, - 'colortempkelvin' => { 37 => 0x31, 38 => 0x4f, 40 => 0x44, 41 => 0x6b, 44 => 0x84, 45 => 0x9d, 46 => 0xa2, 47 => 0xa5, 297 => 0x44, 358 => 0x1307 }, - 'colortempmeasured' => { 37 => 0xe, 38 => 0x17, 41 => 0x4d, 44 => 0x4d, 45 => 0x4d, 46 => 0x4d, 47 => 0x55 }, - 'colortemppc1' => { 40 => 0x94, 41 => 0x75 }, - 'colortemppc2' => { 40 => 0x99, 41 => 0x7a }, - 'colortemppc3' => { 40 => 0x9e, 41 => 0x7f }, - 'colortempshade' => { 37 => 0x1d, 38 => 0x2f, 39 => 0x2c, 40 => 0x30, 41 => 0x57, 44 => 0x70, 45 => 0x89, 46 => 0x8e, 47 => 0x91, 332 => 0x54 }, - 'colortemptungsten' => { 37 => 0x27, 38 => 0x3f, 39 => 0x36, 40 => 0x3a, 41 => 0x61, 44 => 0x7a, 45 => 0x93, 46 => 0x98, 47 => 0x9b, 332 => 0x56 }, - 'colortempunknown' => { 37 => 0x13, 38 => 0x1f, 40 => 0x21, 44 => 0x52, 45 => 0x52, 46 => 0x52, 47 => 0x5a }, - 'colortempunknown10' => { 37 => 0x63, 38 => 0x9f, 40 => 0x76, 44 => 0xa2, 45 => 0x7f, 46 => 0x7f, 47 => 0x87 }, - 'colortempunknown11' => { 37 => 0x68, 38 => 0xa7, 40 => 0x7b, 44 => 0xa7, 45 => 0xa7, 46 => 0x84, 47 => 0xaf }, - 'colortempunknown12' => { 37 => 0x6d, 38 => 0xaf, 40 => 0x80, 44 => 0xac, 45 => 0xac, 46 => 0xac, 47 => 0xb4 }, - 'colortempunknown13' => { 37 => 0x72, 38 => 0xb7, 40 => 0x85, 44 => 0xb1, 45 => 0xb1, 46 => 0xb1, 47 => 0xb9 }, - 'colortempunknown14' => { 40 => 0x8a, 44 => 0xb6, 45 => 0xb6, 46 => 0xb6, 47 => 0xbe }, - 'colortempunknown15' => { 40 => 0x8f, 44 => 0xbb, 45 => 0xbb, 46 => 0xbb, 47 => 0xc3 }, - 'colortempunknown16' => { 40 => 0xa3, 45 => 0xc0, 46 => 0xc0, 47 => 0xc8 }, - 'colortempunknown17' => { 45 => 0xc5, 46 => 0xc5, 47 => 0xcd }, - 'colortempunknown18' => { 45 => 0xca, 46 => 0xca, 47 => 0xd2 }, - 'colortempunknown19' => { 45 => 0xcf, 46 => 0xcf, 47 => 0xd7 }, - 'colortempunknown2' => { 37 => 0x3b, 38 => 0x5f, 40 => 0x4e, 44 => 0x57, 45 => 0x57, 46 => 0x57, 47 => 0x5f }, - 'colortempunknown20' => { 45 => 0xd4, 46 => 0xd4, 47 => 0xdc }, - 'colortempunknown21' => { 46 => 0xd9, 47 => 0xe1 }, - 'colortempunknown22' => { 46 => 0xde, 47 => 0xe6 }, - 'colortempunknown23' => { 46 => 0xe3, 47 => 0xeb }, - 'colortempunknown24' => { 46 => 0xe8, 47 => 0xf0 }, - 'colortempunknown25' => { 46 => 0xed, 47 => 0xf5 }, - 'colortempunknown26' => { 46 => 0xf2, 47 => 0xfa }, - 'colortempunknown27' => { 46 => 0xf7, 47 => 0xff }, - 'colortempunknown28' => { 46 => 0xfc, 47 => 0x104 }, - 'colortempunknown29' => { 46 => 0x101, 47 => 0x109 }, - 'colortempunknown3' => { 37 => 0x40, 38 => 0x67, 40 => 0x53, 44 => 0x5c, 45 => 0x5c, 46 => 0x5c, 47 => 0x64 }, - 'colortempunknown30' => { 46 => 0x106 }, - 'colortempunknown4' => { 37 => 0x45, 38 => 0x6f, 40 => 0x58, 44 => 0x61, 45 => 0x61, 46 => 0x61, 47 => 0x69 }, - 'colortempunknown5' => { 37 => 0x4a, 38 => 0x77, 40 => 0x5d, 44 => 0x66, 45 => 0x66, 46 => 0x66, 47 => 0x6e }, - 'colortempunknown6' => { 37 => 0x4f, 38 => 0x7f, 40 => 0x62, 44 => 0x8e, 45 => 0x6b, 46 => 0x6b, 47 => 0x73 }, - 'colortempunknown7' => { 37 => 0x54, 38 => 0x87, 40 => 0x67, 44 => 0x93, 45 => 0x70, 46 => 0x70, 47 => 0x78 }, - 'colortempunknown8' => { 37 => 0x59, 38 => 0x8f, 40 => 0x6c, 44 => 0x98, 45 => 0x75, 46 => 0x75, 47 => 0x7d }, - 'colortempunknown9' => { 37 => 0x5e, 38 => 0x97, 40 => 0x71, 44 => 0x9d, 45 => 0x7a, 46 => 0x7a, 47 => 0x82 }, - 'colortone' => { 9 => 0x6f, 11 => 0x77, 33 => 0x2a, 48 => 0x2 }, - 'colortoneadj' => { 97 => 0x20304, 102 => 0x11e }, - 'colortoneauto' => { 67 => 0x9c }, - 'colortonefaithful' => { 18 => 0x107, 66 => 0x6c, 67 => 0x6c }, - 'colortonelandscape' => { 18 => 0x105, 66 => 0x3c, 67 => 0x3c }, - 'colortonemonochrome' => { 66 => 0x84, 67 => 0x84 }, - 'colortoneneutral' => { 18 => 0x106, 66 => 0x54, 67 => 0x54 }, - 'colortoneportrait' => { 18 => 0x104, 66 => 0x24, 67 => 0x24 }, - 'colortonestandard' => { 18 => 0x103, 66 => 0xc, 67 => 0xc }, - 'colortoneuserdef1' => { 18 => 0x109, 66 => 0x9c, 67 => 0xb4 }, - 'colortoneuserdef2' => { 18 => 0x10a, 66 => 0xb4, 67 => 0xcc }, - 'colortoneuserdef3' => { 18 => 0x10b, 66 => 0xcc, 67 => 0xe4 }, - 'comlenblksize' => { 131 => 0xfde8 }, - 'commanddials' => { 268 => '5.1' }, - 'commanddialsaperturesetting' => { 257 => '17.3', 258 => '18.3', 260 => '18.3', 261 => '18.3', 266 => '33.3', 267 => '17.3', 270 => '18.3', 271 => '18.3' }, - 'commanddialschangemainsub' => { 257 => '17.2', 258 => '18.1', 260 => '18.1', 261 => '18.1', 266 => '33.2', 267 => '17.2', 270 => '18.1', 271 => '18.1' }, - 'commanddialsmenuandplayback' => { 257 => '17.4', 258 => '18.2', 260 => '18.2', 261 => '18.2', 266 => '33.4', 267 => '17.4', 270 => '18.2', 271 => '18.2' }, - 'commanddialsreverserotation' => { 257 => '17.1', 258 => '6.4', 260 => '6.2', 261 => '6.2', 262 => '16.2', 263 => '17.2', 266 => '33.1', 267 => '17.1', 270 => '6.2', 271 => '6.2', 272 => '18.1' }, - 'commanderchannel' => { 268 => '10.2', 269 => '25.2' }, - 'commandergroupa_ttl-aacomp' => { 268 => '13.1', 269 => '31.1' }, - 'commandergroupa_ttlcomp' => { 272 => '32.1' }, - 'commandergroupamanualoutput' => { 268 => '13.2', 269 => '28.2' }, - 'commandergroupamode' => { 268 => '11.2', 269 => '28.1' }, - 'commandergroupb_ttl-aacomp' => { 268 => '14.1', 269 => '32.1' }, - 'commandergroupb_ttlcomp' => { 272 => '33.1' }, - 'commandergroupbmanualoutput' => { 268 => '14.2', 269 => '29.2' }, - 'commandergroupbmode' => { 268 => '11.3', 269 => '29.1' }, - 'commanderinternalflash' => { 268 => '11.1', 269 => '27.1' }, - 'commanderinternalmanualoutput' => { 268 => '12.2', 269 => '27.2' }, - 'commanderinternalttlchannel' => { 266 => '18.2' }, - 'commanderinternalttlcomp' => { 268 => '12.1', 269 => '30.2', 272 => '31.2' }, - 'commanderinternalttlcompbuiltin' => { 266 => '20.1', 267 => '26.1' }, - 'commanderinternalttlcompgroupa' => { 266 => '21.1', 267 => '27.1' }, - 'commanderinternalttlcompgroupb' => { 266 => '22.1', 267 => '28.1' }, - 'comment' => { 0 => 0x2, 114 => 'Comment', 148 => 'Comment', 287 => 'Comment' }, - 'compass' => { 361 => 0x4 }, - 'complianceprofile' => { 456 => 'complianceProfile' }, - 'componentsconfiguration' => { 113 => 0x9101, 153 => 'Components', 446 => 'ComponentsConfiguration' }, - 'componentversion' => { 91 => 0x80c }, - 'composer' => { 466 => 'composer' }, - 'composition' => { 431 => 'Composition' }, - 'compositionadjust' => { 331 => '0.1' }, - 'compositionadjustrotation' => { 331 => 0x7 }, - 'compositionadjustx' => { 331 => 0x5 }, - 'compositionadjusty' => { 331 => 0x6 }, - 'compressedbitsperpixel' => { 113 => 0x9102, 446 => 'CompressedBitsPerPixel' }, - 'compressedimagesize' => { 176 => 0x40, 279 => 0x40 }, - 'compression' => { 113 => 0x103, 302 => 0xb, 462 => 'Compression' }, - 'compressionfactor' => { 274 => 0x50d }, - 'compressionratio' => { 153 => 'Compression', 279 => 0x1034 }, - 'condadobvfactor' => { 131 => 0xf3e }, - 'condadodaybvthresh' => { 131 => 0xf3c }, - 'condadodayoffsets' => { 131 => 0xf42 }, - 'condadofluoffsets' => { 131 => 0xf44 }, - 'condadofluthresh' => { 131 => 0xf41 }, - 'condadoillfactor' => { 131 => 0xf3f }, - 'condadoneurange' => { 131 => 0xf3d }, - 'condadotunoffsets' => { 131 => 0xf43 }, - 'condadotunthresh' => { 131 => 0xf40 }, - 'confidence' => { 426 => 'Confidence' }, - 'confidencelevel' => { 437 => 'ConfidenceLevel' }, - 'confidencemime' => { 426 => 'ConfidenceMime' }, - 'constrainedcropheight' => { 102 => 0x266, 343 => 0xd6 }, - 'constrainedcropwidth' => { 102 => 0x262, 343 => 0xd5 }, - 'contact' => { 125 => 0x76 }, - 'contactinfo' => { 455 => 'contactInfo' }, - 'containerformat' => { 452 => 'ContainerFormat' }, - 'containerformatidentifier' => { 452 => [\'ContainerFormat','ContainerFormatIdentifier'] }, - 'containerformatname' => { 452 => [\'ContainerFormat','ContainerFormatName'] }, - 'contentidentifier' => { 1 => 0x11 }, - 'contentlocationcode' => { 125 => 0x1a }, - 'contentlocationname' => { 125 => 0x1b }, - 'contenttype' => { 456 => 'contentType' }, - 'continuousbracketing' => { 174 => 0x20 }, - 'continuousdrive' => { 33 => 0x5 }, - 'continuousmodeliveview' => { 271 => '77.2' }, - 'continuousshootingspeed' => { 78 => 0x610 }, - 'continuousshotlimit' => { 78 => 0x611 }, - 'contrast' => { 9 => 0x73, 11 => 0x75, 33 => 0xd, 106 => 0xc, 107 => [0x3012,0x20], 113 => [0xa408,0xfe54], 121 => [0x1004,0x1006], 147 => 'Contrast', 167 => 'Contrast', 171 => 0x20, 172 => 0x31, 173 => 0x27, 174 => 0x19, 179 => 0x2, 213 => 0x33, 214 => 0x37, 279 => 0x1029, 297 => 0x39, 299 => 0x300a, 332 => 0x20, 339 => 0xc, 353 => 0x24, 358 => 0x1012, 368 => 0xd, 376 => 0x1d, 377 => 0x1a, 388 => 0x2004, 442 => 'Contrast', 446 => 'Contrast' }, - 'contrast2012' => { 442 => 'Contrast2012' }, - 'contrastadj' => { 97 => 0x20303, 102 => 0x115, 253 => 0x2c, 421 => 0x8017 }, - 'contrastauto' => { 67 => 0x90 }, - 'contrastcurve' => { 211 => 0x8c }, - 'contrastdetectaf' => { 183 => 0x4 }, - 'contrastdetectafarea' => { 332 => 0x231 }, - 'contrastdetectafinfocus' => { 183 => [0x1c,0x52] }, - 'contrastfaithful' => { 18 => 0xec, 66 => 0x60, 67 => 0x60 }, - 'contrasthighlight' => { 332 => 0x6d }, - 'contrasthighlightshadowadj' => { 332 => 0x6f }, - 'contrastlandscape' => { 18 => 0xea, 66 => 0x30, 67 => 0x30 }, - 'contrastmode' => { 297 => 0x2c }, - 'contrastmonochrome' => { 18 => 0xed, 66 => 0x78, 67 => 0x78 }, - 'contrastneutral' => { 18 => 0xeb, 66 => 0x48, 67 => 0x48 }, - 'contrastportrait' => { 18 => 0xe9, 66 => 0x18, 67 => 0x18 }, - 'contrastsetting' => { 274 => 0x505, 282 => 0x1012, 378 => 0x10, 393 => 0x8 }, - 'contrastshadow' => { 332 => 0x6e }, - 'contraststandard' => { 18 => 0xe8, 66 => 0x0, 67 => 0x0 }, - 'contrastuserdef1' => { 18 => 0xee, 66 => 0x90, 67 => 0xa8 }, - 'contrastuserdef2' => { 18 => 0xef, 66 => 0xa8, 67 => 0xc0 }, - 'contrastuserdef3' => { 18 => 0xf0, 66 => 0xc0, 67 => 0xd8 }, - 'contributedmedia' => { 466 => 'contributedMedia' }, - 'contributedmediaduration' => { 466 => [\'contributedMedia','contributedMediaDuration'] }, - 'contributedmediadurationscale' => { 466 => [\'contributedMedia','contributedMediaDurationScale'] }, - 'contributedmediadurationvalue' => { 466 => [\'contributedMedia','contributedMediaDurationValue'] }, - 'contributedmediamanaged' => { 466 => [\'contributedMedia','contributedMediaManaged'] }, - 'contributedmediapath' => { 466 => [\'contributedMedia','contributedMediaPath'] }, - 'contributedmediastarttime' => { 466 => [\'contributedMedia','contributedMediaStartTime'] }, - 'contributedmediastarttimescale' => { 466 => [\'contributedMedia','contributedMediaStartTimeScale'] }, - 'contributedmediastarttimevalue' => { 466 => [\'contributedMedia','contributedMediaStartTimeValue'] }, - 'contributedmediatrack' => { 466 => [\'contributedMedia','contributedMediaTrack'] }, - 'contributedmediawebstatement' => { 466 => [\'contributedMedia','contributedMediaWebStatement'] }, - 'contributor' => { 443 => 'contributor', 452 => 'Contributor' }, - 'contributoridentifier' => { 452 => [\'Contributor','ContributorIdentifier'] }, - 'contributorname' => { 452 => [\'Contributor','ContributorName'] }, - 'contributorrole' => { 452 => [\'Contributor','ContributorRole'] }, - 'contributors' => { 148 => 'Contributors' }, - 'controldialset' => { 174 => 0x46 }, - 'controlledvocabularyterm' => { 452 => 'CVterm' }, - 'controllerboardversion' => { 292 => 0x332 }, - 'controlmode' => { 72 => 0x12 }, - 'controlringrotation' => { 78 => 0x712 }, - 'conversionlens' => { 275 => 0x403, 297 => 0x35 }, - 'converter' => { 113 => 0xfe4d, 240 => 0xb, 442 => 'Converter' }, - 'converttograyscale' => { 442 => 'ConvertToGrayscale' }, - 'cookingequipment' => { 458 => 'cookingEquipment' }, - 'cookingmethod' => { 458 => 'cookingMethod' }, - 'copyright' => { 0 => 0x3, 113 => 0x8298, 148 => 'Copyright', 287 => 'Copyright', 332 => 0x22f, 348 => 'Copyright', 453 => 'Copyright', 459 => 'copyright', 462 => 'Copyright', 466 => 'copyright' }, - 'copyrightflag' => { 346 => 0x40a }, - 'copyrightnotice' => { 125 => 0x74 }, - 'copyrightowner' => { 284 => 'CopyrightOwner' }, - 'copyrightownerid' => { 284 => [\'CopyrightOwner','CopyrightOwnerCopyrightOwnerID'] }, - 'copyrightownerimageid' => { 284 => 'CopyrightOwnerImageID' }, - 'copyrightownername' => { 284 => [\'CopyrightOwner','CopyrightOwnerCopyrightOwnerName'] }, - 'copyrightregistrationnumber' => { 284 => 'CopyrightRegistrationNumber' }, - 'copyrightstatus' => { 284 => 'CopyrightStatus' }, - 'copyrightyear' => { 452 => 'CopyrightYear', 456 => 'copyrightYear' }, - 'coringfilter' => { 278 => 0x310, 279 => 0x102d, 282 => 0x310 }, - 'coringvalues' => { 278 => 0x311, 282 => 0x311 }, - 'corporateentity' => { 456 => 'corporateEntity' }, - 'country' => { 152 => 'Country', 297 => 0x69, 454 => 'Country' }, - 'country-primarylocationcode' => { 125 => 0x64 }, - 'country-primarylocationname' => { 125 => 0x65 }, - 'countrycode' => { 210 => 0x5, 344 => 'CountryCode', 451 => 'CountryCode' }, - 'course' => { 458 => 'course' }, - 'coverage' => { 443 => 'coverage' }, - 'coverdate' => { 456 => 'coverDate' }, - 'coverdisplaydate' => { 456 => 'coverDisplayDate' }, - 'cpufirmwareversion' => { 332 => 0x28 }, - 'crc32' => { 444 => 'crc32' }, - 'createdate' => { 113 => 0x9004, 148 => 'CreateDate', 283 => 'CreationDate', 287 => 'create-date', 348 => 'CreationDate', 350 => 0x1, 464 => 'CreateDate' }, - 'creationdate' => { 453 => 'CreationDate', 456 => 'creationDate' }, - 'creationtime' => { 287 => 'Creation Time' }, - 'creativestyle' => { 376 => 0x1a, 377 => 0x18, 387 => 0x41, 388 => 0xb020, 417 => 0x4a }, - 'creativestylesetting' => { 378 => 0xf, 393 => 0x7 }, - 'creativestylewaschanged' => { 421 => 0x8001 }, - 'creator' => { 283 => 'Creator', 348 => 'Creator', 443 => 'creator', 452 => 'Creator', 453 => 'Creator' }, - 'creatoraddress' => { 451 => [\'CreatorContactInfo','CreatorContactInfoCiAdrExtadr'] }, - 'creatorappid' => { 169 => 'CreatorAppId' }, - 'creatorcity' => { 451 => [\'CreatorContactInfo','CreatorContactInfoCiAdrCity'] }, - 'creatorcontactinfo' => { 451 => 'CreatorContactInfo' }, - 'creatorcountry' => { 451 => [\'CreatorContactInfo','CreatorContactInfoCiAdrCtry'] }, - 'creatoridentifier' => { 452 => [\'Creator','CreatorIdentifier'] }, - 'creatorname' => { 452 => [\'Creator','CreatorName'] }, - 'creatoropenwithuioptions' => { 169 => 'CreatorOpenWithUIOptions' }, - 'creatorpostalcode' => { 451 => [\'CreatorContactInfo','CreatorContactInfoCiAdrPcode'] }, - 'creatorregion' => { 451 => [\'CreatorContactInfo','CreatorContactInfoCiAdrRegion'] }, - 'creatorrole' => { 452 => [\'Creator','CreatorRole'] }, - 'creatortool' => { 464 => 'CreatorTool' }, - 'creatorworkemail' => { 451 => [\'CreatorContactInfo','CreatorContactInfoCiEmailWork'] }, - 'creatorworktelephone' => { 451 => [\'CreatorContactInfo','CreatorContactInfoCiTelWork'] }, - 'creatorworkurl' => { 451 => [\'CreatorContactInfo','CreatorContactInfoCiUrlWork'] }, - 'credit' => { 125 => 0x6e, 454 => 'Credit' }, - 'creditline' => { 459 => 'creditLine' }, - 'creditlinereq' => { 469 => 'CreditLineReq' }, - 'creditlinerequired' => { 284 => 'CreditLineRequired' }, - 'cropactive' => { 95 => 0x0, 102 => 0x244 }, - 'cropangle' => { 442 => 'CropAngle' }, - 'croparea' => { 421 => 0x9011 }, - 'cropaspectratio' => { 97 => 0x30101, 102 => 0x260 }, - 'cropaspectratiocustom' => { 97 => 0x30102 }, - 'cropbottom' => { 117 => 0x9, 245 => 0x36, 302 => 0x31, 343 => 0xdc, 442 => 'CropBottom' }, - 'cropbottommargin' => { 50 => 0x3 }, - 'cropcircleactive' => { 103 => 0xd6 }, - 'cropcircleradius' => { 103 => 0xd9 }, - 'cropcirclex' => { 103 => 0xd7 }, - 'cropcircley' => { 103 => 0xd8 }, - 'cropconstraintowarp' => { 442 => 'CropConstrainToWarp' }, - 'croph' => { 435 => 'CropH' }, - 'cropheight' => { 95 => 0x6, 102 => 0x24c, 278 => 0x615, 282 => 0x615, 442 => 'CropHeight' }, - 'crophispeed' => { 211 => 0x1b }, - 'cropleft' => { 102 => 0x246, 117 => 0x6, 245 => 0x1e, 278 => 0x612, 282 => 0x612, 302 => 0x30, 343 => 0xd9, 442 => 'CropLeft' }, - 'cropleftmargin' => { 50 => 0x0 }, - 'cropmode35mm' => { 358 => 0x1018 }, - 'croporiginalheight' => { 95 => 0xb }, - 'croporiginalwidth' => { 95 => 0xa }, - 'cropoutputheight' => { 245 => 0xce }, - 'cropoutputheightinches' => { 245 => 0x96 }, - 'cropoutputpixels' => { 245 => 0xd6 }, - 'cropoutputresolution' => { 245 => 0xb6 }, - 'cropoutputscale' => { 245 => 0xbe }, - 'cropoutputwidth' => { 245 => 0xc6 }, - 'cropoutputwidthinches' => { 245 => 0x8e }, - 'croppedareaimageheightpixels' => { 429 => 'CroppedAreaImageHeightPixels', 430 => 'CroppedAreaImageHeightPixels' }, - 'croppedareaimagewidthpixels' => { 429 => 'CroppedAreaImageWidthPixels', 430 => 'CroppedAreaImageWidthPixels' }, - 'croppedarealeftpixels' => { 429 => 'CroppedAreaLeftPixels', 430 => 'CroppedAreaLeftPixels' }, - 'croppedareatoppixels' => { 429 => 'CroppedAreaTopPixels', 430 => 'CroppedAreaTopPixels' }, - 'croppedimageheight' => { 5 => 0x2, 358 => 0x1604 }, + 'buttonfunctioncontroloff' => { 84 => 0x70a }, + 'bwadjustment' => { 127 => 0x1049 }, + 'bwfilter' => { 181 => 0x2a, 189 => 0x39 }, + 'bwmode' => { 302 => 0x203 }, + 'by-line' => { 131 => 0x50 }, + 'by-linetitle' => { 131 => 0x55 }, + 'bytecount' => { 494 => 'byteCount' }, + 'c14configuration' => { 138 => 0x1964 }, + 'cacheversion' => { 119 => 0xc7aa }, + 'calibratedfocallength' => { 116 => 'CalibratedFocalLength' }, + 'calibratedopticalcenterx' => { 116 => 'CalibratedOpticalCenterX' }, + 'calibratedopticalcentery' => { 116 => 'CalibratedOpticalCenterY' }, + 'calibration' => { 397 => [0x24,0x30] }, + 'calibrationhistory' => { 138 => 0x9c9 }, + 'calibrationilluminant1' => { 119 => 0xc65a }, + 'calibrationilluminant2' => { 119 => 0xc65b }, + 'calibrationilluminant3' => { 119 => 0xcd31 }, + 'calibrationversion' => { 138 => 0x9c6 }, + 'callforimage' => { 468 => 'CallForImage' }, + 'camera' => { 458 => [\'Cameras','CamerasCamera'] }, + 'cameraangle' => { 380 => 'angl', 504 => 'cameraAngle' }, + 'cameraappinfo' => { 458 => [\'Cameras','CamerasCameraAppInfo'] }, + 'cameraappinfoapplication' => { 458 => [\'Cameras','CamerasCameraAppInfoApplication'] }, + 'cameraappinfoitemuri' => { 458 => [\'Cameras','CamerasCameraAppInfoItemURI'] }, + 'cameraappinfoversion' => { 458 => [\'Cameras','CamerasCameraAppInfoVersion'] }, + 'cameraburstid' => { 462 => 'CameraBurstID' }, + 'cameracalibration' => { 397 => 0x11f }, + 'cameracalibration1' => { 119 => 0xc623 }, + 'cameracalibration2' => { 119 => 0xc624 }, + 'cameracalibration3' => { 119 => 0xcd32 }, + 'cameracalibrationsig' => { 119 => 0xc6f3 }, + 'cameracolorcalibration01' => { 36 => 0x0, 37 => 0x0 }, + 'cameracolorcalibration02' => { 36 => 0x4, 37 => 0x5 }, + 'cameracolorcalibration03' => { 36 => 0x8, 37 => 0xa }, + 'cameracolorcalibration04' => { 36 => 0xc, 37 => 0xf }, + 'cameracolorcalibration05' => { 36 => 0x10, 37 => 0x14 }, + 'cameracolorcalibration06' => { 36 => 0x14, 37 => 0x19 }, + 'cameracolorcalibration07' => { 36 => 0x18, 37 => 0x1e }, + 'cameracolorcalibration08' => { 36 => 0x1c, 37 => 0x23 }, + 'cameracolorcalibration09' => { 36 => 0x20, 37 => 0x28 }, + 'cameracolorcalibration10' => { 36 => 0x24, 37 => 0x2d }, + 'cameracolorcalibration11' => { 36 => 0x28, 37 => 0x32 }, + 'cameracolorcalibration12' => { 36 => 0x2c, 37 => 0x37 }, + 'cameracolorcalibration13' => { 36 => 0x30, 37 => 0x3c }, + 'cameracolorcalibration14' => { 36 => 0x34, 37 => 0x41 }, + 'cameracolorcalibration15' => { 36 => 0x38, 37 => 0x46 }, + 'cameradepthmap' => { 458 => [\'Cameras','CamerasCameraDepthMap'] }, + 'cameradepthmapconfidenceuri' => { 458 => [\'Cameras','CamerasCameraDepthMapConfidenceURI'] }, + 'cameradepthmapdepthuri' => { 458 => [\'Cameras','CamerasCameraDepthMapDepthURI'] }, + 'cameradepthmapfar' => { 458 => [\'Cameras','CamerasCameraDepthMapFar'] }, + 'cameradepthmapfocaltable' => { 458 => [\'Cameras','CamerasCameraDepthMapFocalTable'] }, + 'cameradepthmapfocaltableentrycount' => { 458 => [\'Cameras','CamerasCameraDepthMapFocalTableEntryCount'] }, + 'cameradepthmapformat' => { 458 => [\'Cameras','CamerasCameraDepthMapFormat'] }, + 'cameradepthmapitemsemantic' => { 458 => [\'Cameras','CamerasCameraDepthMapItemSemantic'] }, + 'cameradepthmapmeasuretype' => { 458 => [\'Cameras','CamerasCameraDepthMapMeasureType'] }, + 'cameradepthmapnear' => { 458 => [\'Cameras','CamerasCameraDepthMapNear'] }, + 'cameradepthmapsoftware' => { 458 => [\'Cameras','CamerasCameraDepthMapSoftware'] }, + 'cameradepthmapunits' => { 458 => [\'Cameras','CamerasCameraDepthMapUnits'] }, + 'cameradirection' => { 374 => 'direction.facing' }, + 'camerae-mountversion' => { 454 => 0xb }, + 'cameraelevationangle' => { 119 => 0x9405, 485 => 'CameraElevationAngle' }, + 'camerafilename' => { 468 => 'CameraFilename' }, + 'cameraid' => { 302 => 0x209, 380 => 'cmid', 396 => 0x209 }, + 'cameraidentifier' => { 374 => 'camera.identifier' }, + 'cameraimage' => { 458 => [\'Cameras','CamerasCameraImage'] }, + 'cameraimageitemsemantic' => { 458 => [\'Cameras','CamerasCameraImageItemSemantic'] }, + 'cameraimageitemuri' => { 458 => [\'Cameras','CamerasCameraImageItemURI'] }, + 'cameraimagingmodel' => { 458 => [\'Cameras','CamerasCameraImagingModel'] }, + 'cameraimagingmodeldistortion' => { 458 => [\'Cameras','CamerasCameraImagingModelDistortion'] }, + 'cameraimagingmodeldistortioncount' => { 458 => [\'Cameras','CamerasCameraImagingModelDistortionCount'] }, + 'cameraimagingmodelfocallengthx' => { 458 => [\'Cameras','CamerasCameraImagingModelFocalLengthX'] }, + 'cameraimagingmodelfocallengthy' => { 458 => [\'Cameras','CamerasCameraImagingModelFocalLengthY'] }, + 'cameraimagingmodelimageheight' => { 458 => [\'Cameras','CamerasCameraImagingModelImageHeight'] }, + 'cameraimagingmodelimagewidth' => { 458 => [\'Cameras','CamerasCameraImagingModelImageWidth'] }, + 'cameraimagingmodelpixelaspectratio' => { 458 => [\'Cameras','CamerasCameraImagingModelPixelAspectRatio'] }, + 'cameraimagingmodelprincipalpointx' => { 458 => [\'Cameras','CamerasCameraImagingModelPrincipalPointX'] }, + 'cameraimagingmodelprincipalpointy' => { 458 => [\'Cameras','CamerasCameraImagingModelPrincipalPointY'] }, + 'cameraimagingmodelskew' => { 458 => [\'Cameras','CamerasCameraImagingModelSkew'] }, + 'cameraiso' => { 34 => 0x10 }, + 'cameralabel' => { 119 => 0xc7a1, 504 => 'cameraLabel' }, + 'cameralightestimate' => { 458 => [\'Cameras','CamerasCameraLightEstimate'] }, + 'cameralightestimatecolorcorrectionb' => { 458 => [\'Cameras','CamerasCameraLightEstimateColorCorrectionB'] }, + 'cameralightestimatecolorcorrectiong' => { 458 => [\'Cameras','CamerasCameraLightEstimateColorCorrectionG'] }, + 'cameralightestimatecolorcorrectionr' => { 458 => [\'Cameras','CamerasCameraLightEstimateColorCorrectionR'] }, + 'cameralightestimatepixelintensity' => { 458 => [\'Cameras','CamerasCameraLightEstimatePixelIntensity'] }, + 'cameramakemodel' => { 468 => 'CameraMakeModel' }, + 'cameramodel' => { 364 => 0x410, 504 => 'cameraModel' }, + 'cameramodelid' => { 176 => 'CameraModelID' }, + 'cameramodelrestriction' => { 478 => 'CameraModelRestriction', 480 => 'CameraModelRestriction' }, + 'cameramotion' => { 374 => 'direction.motion' }, + 'cameramove' => { 504 => 'cameraMove' }, + 'cameraorientation' => { 7 => 0x30, 9 => 0x7d, 11 => 0x30, 13 => 0x35, 14 => 0x30, 15 => 0x30, 16 => 0x31, 17 => 0x31, 18 => 0x35, 19 => 0x27, 20 => 0x31, 21 => 0x7d, 22 => 0x38, 23 => [0x36,0x3a], 24 => 0x7d, 25 => 0x83, 26 => 0x84, 27 => 0x96, 28 => 0x35, 29 => 0x96, 320 => 0x8f, 359 => 0x1, 364 => 0x100, 413 => [0x16,0x18], 442 => 0x28, 443 => 0x24, 444 => 0x29 }, + 'cameraowner' => { 141 => 0xc353 }, + 'cameraparameters' => { 302 => 0x2050 }, + 'camerapicturestyle' => { 28 => 0xaf }, + 'camerapitch' => { 115 => 0x9, 380 => "\xa9gpt" }, + 'camerapointcloud' => { 458 => [\'Cameras','CamerasCameraPointCloud'] }, + 'camerapointcloudmetric' => { 458 => [\'Cameras','CamerasCameraPointCloudMetric'] }, + 'camerapointcloudpointcloud' => { 458 => [\'Cameras','CamerasCameraPointCloudPointCloud'] }, + 'camerapointcloudpoints' => { 458 => [\'Cameras','CamerasCameraPointCloudPoints'] }, + 'camerapose' => { 458 => [\'Cameras','CamerasCameraPose'] }, + 'cameraposepositionx' => { 458 => [\'Cameras','CamerasCameraPosePositionX'] }, + 'cameraposepositiony' => { 458 => [\'Cameras','CamerasCameraPosePositionY'] }, + 'cameraposepositionz' => { 458 => [\'Cameras','CamerasCameraPosePositionZ'] }, + 'cameraposerotationw' => { 458 => [\'Cameras','CamerasCameraPoseRotationW'] }, + 'cameraposerotationx' => { 458 => [\'Cameras','CamerasCameraPoseRotationX'] }, + 'cameraposerotationy' => { 458 => [\'Cameras','CamerasCameraPoseRotationY'] }, + 'cameraposerotationz' => { 458 => [\'Cameras','CamerasCameraPoseRotationZ'] }, + 'cameraposetimestamp' => { 458 => [\'Cameras','CamerasCameraPoseTimestamp'] }, + 'cameraprofile' => { 478 => 'CameraProfile', 480 => 'CameraProfile' }, + 'cameraprofiledigest' => { 478 => 'CameraProfileDigest', 480 => 'CameraProfileDigest' }, + 'camerarawcolortone' => { 109 => 0xe1 }, + 'camerarawcontrast' => { 109 => 0xe3 }, + 'camerarawhighlightpoint' => { 109 => 0xe6 }, + 'camerarawlinear' => { 109 => 0xe4 }, + 'camerarawoutputhighlightpoint' => { 109 => 0xe8 }, + 'camerarawoutputshadowpoint' => { 109 => 0xe9 }, + 'camerarawsaturation' => { 109 => 0xe2 }, + 'camerarawshadowpoint' => { 109 => 0xe7 }, + 'camerarawsharpness' => { 109 => 0xe5 }, + 'cameraroll' => { 115 => 0xb, 380 => "\xa9grl" }, + 'cameras' => { 458 => 'Cameras' }, + 'cameraserialnumber' => { 119 => 0xc62f, 178 => 'CameraSerialNumber', 468 => 'CameraSerialNumber' }, + 'camerasettingsversion' => { 297 => 0x0 }, + 'cameratemperature' => { 7 => 0x18, 9 => 0x1b, 11 => 0x18, 13 => 0x19, 14 => 0x18, 15 => 0x18, 16 => 0x19, 17 => 0x19, 18 => 0x19, 19 => 0x17, 20 => 0x19, 21 => 0x1b, 22 => 0x19, 23 => 0x19, 24 => 0x1b, 25 => 0x1b, 26 => 0x1b, 27 => 0x1b, 28 => 0x19, 29 => 0x1b, 30 => [0x87,0x91], 31 => [0x99,0x9f,0xa4,0xa8,0x105], 33 => ['-3',0x64,0x47,0x53,0x5b,0x5c], 77 => 0xc, 138 => 0x406, 301 => 0x1306, 315 => 0x320, 322 => 0x3402, 355 => 0x47, 394 => 0x43, 446 => 0x5 }, + 'cameratemperature4' => { 360 => 0x14 }, + 'cameratemperature5' => { 360 => 0x16 }, + 'cameratemperaturerangemax' => { 121 => 0x5 }, + 'cameratemperaturerangemin' => { 121 => 0x6 }, + 'cameratrait' => { 458 => [\'Cameras','CamerasCameraTrait'] }, + 'cameratype' => { 77 => 0x1a, 302 => 0x207 }, + 'cameratype2' => { 298 => 0x100 }, + 'cameravendorinfo' => { 458 => [\'Cameras','CamerasCameraVendorInfo'] }, + 'cameravendorinfomanufacturer' => { 458 => [\'Cameras','CamerasCameraVendorInfoManufacturer'] }, + 'cameravendorinfomodel' => { 458 => [\'Cameras','CamerasCameraVendorInfoModel'] }, + 'cameravendorinfonotes' => { 458 => [\'Cameras','CamerasCameraVendorInfoNotes'] }, + 'camerayaw' => { 115 => 0xa, 380 => "\xa9gyw" }, + 'camreverse' => { 116 => 'CamReverse' }, + 'canondr4' => { 120 => 'CanonDR4' }, + 'canonexposuremode' => { 34 => 0x14 }, + 'canonfiledescription' => { 97 => 0x805 }, + 'canonfilelength' => { 64 => 0xe }, + 'canonfirmwareversion' => { 64 => 0x7, 97 => 0x80b }, + 'canonflashinfo' => { 97 => 0x1028 }, + 'canonflashmode' => { 34 => 0x4 }, + 'canonimagesize' => { 10 => 0x39, 34 => 0xa }, + 'canonimagetype' => { 64 => 0x6, 97 => 0x815 }, + 'canonlogversion' => { 63 => 0xb }, + 'canonmodelid' => { 64 => 0x10, 97 => 0x1834 }, + 'canonvrd' => { 120 => 'CanonVRD' }, + 'caption' => { 473 => 'caption' }, + 'caption-abstract' => { 131 => 0x78 }, + 'captionsauthornames' => { 483 => 'CaptionsAuthorNames' }, + 'captionsdatetimestamps' => { 483 => 'CaptionsDateTimeStamps' }, + 'captionwriter' => { 492 => 'CaptionWriter' }, + 'captureframerate' => { 113 => 0x4001 }, + 'captureheightnormal' => { 138 => 0x1839 }, + 'capturelook' => { 138 => 0xc48 }, + 'capturemode' => { 374 => 'com.apple.photos.captureMode' }, + 'capturesoftware' => { 466 => 'CaptureSoftware' }, + 'capturewidthnormal' => { 138 => 0x1838 }, + 'capturewidthtest' => { 138 => 0x1842 }, + 'cardshutterlock' => { 184 => 0x49 }, + 'casioimagesize' => { 113 => 0x9 }, + 'catalogsets' => { 131 => 0xff, 459 => 'CatalogSets', 471 => 'CatalogSets' }, + 'categories' => { 64 => 0x23, 473 => 'categories' }, + 'category' => { 131 => 0xf, 179 => 'WM/Category', 296 => 0x30, 372 => 'catg', 492 => 'Category' }, + 'cbcrgain' => { 394 => 0xa036 }, + 'cbcrgaindefault' => { 394 => 0xa035 }, + 'cbcrmatrix' => { 394 => 0xa034 }, + 'cbcrmatrixdefault' => { 394 => 0xa033 }, + 'ccdboardversion' => { 315 => 0x331 }, + 'ccdscanmode' => { 302 => 0x1039 }, + 'ccdsensitivity' => { 262 => 0x6 }, + 'ccdversion' => { 315 => 0x330 }, + 'cellglobalid' => { 477 => 'cgi' }, + 'celllength' => { 119 => 0x109 }, + 'cellr' => { 477 => 'r' }, + 'celltowerid' => { 477 => 'cellid' }, + 'cellwidth' => { 119 => 0x108 }, + 'centerafarea' => { 290 => '15.1' }, + 'centerfocuspoint' => { 294 => '2.2' }, + 'centerpixel' => { 138 => 0x40c }, + 'centerweightedareasize' => { 279 => '7.1', 280 => '8.1', 282 => '8.1', 283 => '8.1', 287 => '7.1', 288 => '5.1', 289 => '7.1', 290 => '6.3', 292 => '8.1', 293 => '8.1', 294 => '8.1', 295 => 0x1f }, + 'certificate' => { 508 => 'Certificate' }, + 'cfainterpolationalgorithm' => { 138 => 0xe60 }, + 'cfainterpolationmetric' => { 138 => 0xe61 }, + 'cfaoffsetcols' => { 138 => 0xc71 }, + 'cfaoffsetrows' => { 138 => 0xc6f }, + 'cfapattern' => { 119 => 0xa302, 325 => 0x9, 484 => 'CFAPattern' }, + 'cfapattern2' => { 119 => 0x828e }, + 'cfapatterncolumns' => { 484 => [\'CFAPattern','CFAPatternColumns'] }, + 'cfapatternrows' => { 484 => [\'CFAPattern','CFAPatternRows'] }, + 'cfapatternvalues' => { 484 => [\'CFAPattern','CFAPatternValues'] }, + 'cfarepeatpatterndim' => { 119 => 0x828d }, + 'cfazipperfixthreshold' => { 138 => 0xe62 }, + 'channel' => { 494 => 'channel' }, + 'channela-lang' => { 494 => [\'channel','channelA-lang'] }, + 'channelchannel' => { 494 => [\'channel','channelChannel'] }, + 'channels' => { 155 => 'Channels' }, + 'channelsubchannel1' => { 494 => [\'channel','channelSubchannel1'] }, + 'channelsubchannel2' => { 494 => [\'channel','channelSubchannel2'] }, + 'channelsubchannel3' => { 494 => [\'channel','channelSubchannel3'] }, + 'channelsubchannel4' => { 494 => [\'channel','channelSubchannel4'] }, + 'chapterlist' => { 380 => 'chpl' }, + 'checkmark' => { 103 => 0x10101, 108 => 0x26a }, + 'checkmark2' => { 109 => 0x8e }, + 'childfontfiles' => { 509 => [\'Fonts','FontsChildFontFiles'] }, + 'chmodeshootingspeed' => { 279 => '10.3', 280 => '11.2', 295 => 0x10b }, + 'chromablurradius' => { 119 => 0xc631 }, + 'chromanoisecolorspace' => { 138 => 0xe6d }, + 'chromanoiseedgemapthresh' => { 138 => 0xe6c }, + 'chromanoisehighfthresh' => { 138 => 0xe6a }, + 'chromanoiselowfthresh' => { 138 => 0xe6b }, + 'chromaticaberration' => { 103 => 0x20703, 109 => 0x66, 394 => 0xa051 }, + 'chromaticaberrationb' => { 478 => 'ChromaticAberrationB', 480 => 'ChromaticAberrationB' }, + 'chromaticaberrationblue' => { 103 => 0x20708, 109 => 0x6b }, + 'chromaticaberrationcorr' => { 79 => [0x4,0x5] }, + 'chromaticaberrationcorrection' => { 119 => 0x7034, 345 => 0x1, 455 => 0x900d }, + 'chromaticaberrationcorrparams' => { 119 => 0x7035, 450 => 0x66a, 451 => [0x37c,0x384,0x39c,0x3b0,0x3b8] }, + 'chromaticaberrationon' => { 103 => '0x20703.0', 109 => 0x62 }, + 'chromaticaberrationr' => { 478 => 'ChromaticAberrationR', 480 => 'ChromaticAberrationR' }, + 'chromaticaberrationred' => { 103 => 0x20707, 109 => 0x6a }, + 'chromaticaberrationsetting' => { 80 => 0x6 }, + 'chrominancenoisereduction' => { 103 => 0x20601, 109 => 0x5e, 397 => 0x1a }, + 'chrominancenr_tiff_jpeg' => { 109 => 0x60 }, + 'circadatecreated' => { 490 => 'CircaDateCreated' }, + 'circgradbasedcorractive' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionActive'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionActive'] }, + 'circgradbasedcorramount' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionAmount'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionAmount'] }, + 'circgradbasedcorrblacks2012' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalBlacks2012'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalBlacks2012'] }, + 'circgradbasedcorrbrightness' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalBrightness'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalBrightness'] }, + 'circgradbasedcorrclarity' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalClarity'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalClarity'] }, + 'circgradbasedcorrclarity2012' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalClarity2012'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalClarity2012'] }, + 'circgradbasedcorrcontrast' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalContrast'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalContrast'] }, + 'circgradbasedcorrcontrast2012' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalContrast2012'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalContrast2012'] }, + 'circgradbasedcorrcorrectionname' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionName'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionName'] }, + 'circgradbasedcorrcorrectionsyncid' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionSyncID'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionSyncID'] }, + 'circgradbasedcorrdefringe' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalDefringe'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalDefringe'] }, + 'circgradbasedcorrdehaze' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalDehaze'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalDehaze'] }, + 'circgradbasedcorrexposure' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalExposure'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalExposure'] }, + 'circgradbasedcorrexposure2012' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalExposure2012'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalExposure2012'] }, + 'circgradbasedcorrhighlights2012' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalHighlights2012'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalHighlights2012'] }, + 'circgradbasedcorrhue' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalHue'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalHue'] }, + 'circgradbasedcorrluminancenoise' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalLuminanceNoise'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalLuminanceNoise'] }, + 'circgradbasedcorrmaskalpha' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksAlpha'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksAlpha'] }, + 'circgradbasedcorrmaskangle' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksAngle'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksAngle'] }, + 'circgradbasedcorrmaskbottom' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksBottom'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksBottom'] }, + 'circgradbasedcorrmaskcentervalue' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCenterValue'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCenterValue'] }, + 'circgradbasedcorrmaskcenterweight' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCenterWeight'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCenterWeight'] }, + 'circgradbasedcorrmaskdabs' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksDabs'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksDabs'] }, + 'circgradbasedcorrmaskfeather' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFeather'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFeather'] }, + 'circgradbasedcorrmaskflipped' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFlipped'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFlipped'] }, + 'circgradbasedcorrmaskflow' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFlow'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFlow'] }, + 'circgradbasedcorrmaskfullx' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFullX'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFullX'] }, + 'circgradbasedcorrmaskfully' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFullY'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksFullY'] }, + 'circgradbasedcorrmaskinputdigest' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksInputDigest'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksInputDigest'] }, + 'circgradbasedcorrmaskleft' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksLeft'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksLeft'] }, + 'circgradbasedcorrmaskmaskactive' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskActive'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskActive'] }, + 'circgradbasedcorrmaskmaskblendmode' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskBlendMode'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskBlendMode'] }, + 'circgradbasedcorrmaskmaskdigest' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskDigest'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskDigest'] }, + 'circgradbasedcorrmaskmaskinverted' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskInverted'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskInverted'] }, + 'circgradbasedcorrmaskmaskname' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskName'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskName'] }, + 'circgradbasedcorrmaskmasks' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasks'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasks'] }, + 'circgradbasedcorrmaskmasksalpha' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksAlpha'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksAlpha'] }, + 'circgradbasedcorrmaskmasksangle' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksAngle'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksAngle'] }, + 'circgradbasedcorrmaskmasksbottom' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksBottom'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksBottom'] }, + 'circgradbasedcorrmaskmaskscentervalue' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksCenterValue'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksCenterValue'] }, + 'circgradbasedcorrmaskmaskscenterweight' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksCenterWeight'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksCenterWeight'] }, + 'circgradbasedcorrmaskmasksdabs' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksDabs'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksDabs'] }, + 'circgradbasedcorrmaskmasksfeather' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksFeather'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksFeather'] }, + 'circgradbasedcorrmaskmasksflipped' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksFlipped'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksFlipped'] }, + 'circgradbasedcorrmaskmasksflow' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksFlow'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksFlow'] }, + 'circgradbasedcorrmaskmasksfullx' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksFullX'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksFullX'] }, + 'circgradbasedcorrmaskmasksfully' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksFullY'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksFullY'] }, + 'circgradbasedcorrmaskmasksinputdigest' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksInputDigest'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksInputDigest'] }, + 'circgradbasedcorrmaskmasksleft' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksLeft'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksLeft'] }, + 'circgradbasedcorrmaskmasksmaskactive' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskActive'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskActive'] }, + 'circgradbasedcorrmaskmasksmaskblendmode' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskBlendMode'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskBlendMode'] }, + 'circgradbasedcorrmaskmasksmaskdigest' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskDigest'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskDigest'] }, + 'circgradbasedcorrmaskmasksmaskinverted' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskInverted'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskInverted'] }, + 'circgradbasedcorrmaskmasksmaskname' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskName'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskName'] }, + 'circgradbasedcorrmaskmasksmasksubtype' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskSubType'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskSubType'] }, + 'circgradbasedcorrmaskmasksmasksyncid' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskSyncID'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskSyncID'] }, + 'circgradbasedcorrmaskmasksmaskversion' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskVersion'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskVersion'] }, + 'circgradbasedcorrmaskmasksmidpoint' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMidpoint'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMidpoint'] }, + 'circgradbasedcorrmaskmasksorigin' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksOrigin'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksOrigin'] }, + 'circgradbasedcorrmaskmasksperimetervalue' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksPerimeterValue'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksPerimeterValue'] }, + 'circgradbasedcorrmaskmasksradius' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksRadius'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksRadius'] }, + 'circgradbasedcorrmaskmasksreferencepoint' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksReferencePoint'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksReferencePoint'] }, + 'circgradbasedcorrmaskmasksright' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksRight'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksRight'] }, + 'circgradbasedcorrmaskmasksroundness' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksRoundness'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksRoundness'] }, + 'circgradbasedcorrmaskmaskssizex' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksSizeX'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksSizeX'] }, + 'circgradbasedcorrmaskmaskssizey' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksSizeY'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksSizeY'] }, + 'circgradbasedcorrmaskmaskstop' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksTop'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksTop'] }, + 'circgradbasedcorrmaskmasksubtype' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskSubType'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskSubType'] }, + 'circgradbasedcorrmaskmasksvalue' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskValue'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksMaskValue'] }, + 'circgradbasedcorrmaskmasksversion' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksVersion'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksVersion'] }, + 'circgradbasedcorrmaskmaskswhat' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksWhat'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksWhat'] }, + 'circgradbasedcorrmaskmaskswholeimagearea' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksWholeImageArea'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksWholeImageArea'] }, + 'circgradbasedcorrmaskmasksx' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksX'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksX'] }, + 'circgradbasedcorrmaskmasksy' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksY'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksY'] }, + 'circgradbasedcorrmaskmasksyncid' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskSyncID'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskSyncID'] }, + 'circgradbasedcorrmaskmaskszerox' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksZeroX'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksZeroX'] }, + 'circgradbasedcorrmaskmaskszeroy' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksZeroY'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMasksZeroY'] }, + 'circgradbasedcorrmaskmaskversion' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskVersion'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskVersion'] }, + 'circgradbasedcorrmaskmidpoint' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMidpoint'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMidpoint'] }, + 'circgradbasedcorrmaskorigin' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksOrigin'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksOrigin'] }, + 'circgradbasedcorrmaskperimetervalue' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksPerimeterValue'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksPerimeterValue'] }, + 'circgradbasedcorrmaskradius' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksRadius'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksRadius'] }, + 'circgradbasedcorrmaskrange' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMask'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMask'] }, + 'circgradbasedcorrmaskrangeareamodels' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModels'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModels'] }, + 'circgradbasedcorrmaskrangeareamodelscolorsampleinfo' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'] }, + 'circgradbasedcorrmaskrangeareamodelscomponents' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsAreaComponents'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsAreaComponents'] }, + 'circgradbasedcorrmaskrangecoloramount' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskColorAmount'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskColorAmount'] }, + 'circgradbasedcorrmaskrangedepthfeather' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthFeather'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthFeather'] }, + 'circgradbasedcorrmaskrangedepthmax' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMax'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMax'] }, + 'circgradbasedcorrmaskrangedepthmin' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMin'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMin'] }, + 'circgradbasedcorrmaskrangeinvert' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskInvert'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskInvert'] }, + 'circgradbasedcorrmaskrangelumfeather' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumFeather'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumFeather'] }, + 'circgradbasedcorrmaskrangeluminancedepthsampleinfo' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLuminanceDepthSampleInfo'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLuminanceDepthSampleInfo'] }, + 'circgradbasedcorrmaskrangelummax' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMax'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMax'] }, + 'circgradbasedcorrmaskrangelummin' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMin'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMin'] }, + 'circgradbasedcorrmaskrangelumrange' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumRange'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumRange'] }, + 'circgradbasedcorrmaskrangesampletype' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskSampleType'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskSampleType'] }, + 'circgradbasedcorrmaskrangetype' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskType'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskType'] }, + 'circgradbasedcorrmaskrangeversion' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskVersion'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskVersion'] }, + 'circgradbasedcorrmaskreferencepoint' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksReferencePoint'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksReferencePoint'] }, + 'circgradbasedcorrmaskright' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksRight'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksRight'] }, + 'circgradbasedcorrmaskroundness' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksRoundness'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksRoundness'] }, + 'circgradbasedcorrmasks' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasks'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasks'] }, + 'circgradbasedcorrmasksizex' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksSizeX'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksSizeX'] }, + 'circgradbasedcorrmasksizey' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksSizeY'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksSizeY'] }, + 'circgradbasedcorrmasktop' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksTop'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksTop'] }, + 'circgradbasedcorrmaskvalue' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskValue'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksMaskValue'] }, + 'circgradbasedcorrmaskversion' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksVersion'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksVersion'] }, + 'circgradbasedcorrmaskwhat' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksWhat'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksWhat'] }, + 'circgradbasedcorrmaskwholeimagearea' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksWholeImageArea'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksWholeImageArea'] }, + 'circgradbasedcorrmaskx' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksX'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksX'] }, + 'circgradbasedcorrmasky' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksY'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksY'] }, + 'circgradbasedcorrmaskzerox' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksZeroX'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksZeroX'] }, + 'circgradbasedcorrmaskzeroy' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksZeroY'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionMasksZeroY'] }, + 'circgradbasedcorrmoire' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalMoire'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalMoire'] }, + 'circgradbasedcorrrangemask' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMask'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMask'] }, + 'circgradbasedcorrrangemaskareamodels' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskAreaModels'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskAreaModels'] }, + 'circgradbasedcorrrangemaskareamodelscolorsampleinfo' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'] }, + 'circgradbasedcorrrangemaskareamodelscomponents' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskAreaModelsAreaComponents'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskAreaModelsAreaComponents'] }, + 'circgradbasedcorrrangemaskcoloramount' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskColorAmount'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskColorAmount'] }, + 'circgradbasedcorrrangemaskdepthfeather' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskDepthFeather'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskDepthFeather'] }, + 'circgradbasedcorrrangemaskdepthmax' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskDepthMax'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskDepthMax'] }, + 'circgradbasedcorrrangemaskdepthmin' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskDepthMin'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskDepthMin'] }, + 'circgradbasedcorrrangemaskinvert' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskInvert'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskInvert'] }, + 'circgradbasedcorrrangemasklumfeather' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskLumFeather'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskLumFeather'] }, + 'circgradbasedcorrrangemaskluminancedepthsampleinfo' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskLuminanceDepthSampleInfo'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskLuminanceDepthSampleInfo'] }, + 'circgradbasedcorrrangemasklummax' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskLumMax'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskLumMax'] }, + 'circgradbasedcorrrangemasklummin' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskLumMin'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskLumMin'] }, + 'circgradbasedcorrrangemasklumrange' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskLumRange'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskLumRange'] }, + 'circgradbasedcorrrangemasksampletype' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskSampleType'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskSampleType'] }, + 'circgradbasedcorrrangemasktype' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskType'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskType'] }, + 'circgradbasedcorrrangemaskversion' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskVersion'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsCorrectionRangeMaskVersion'] }, + 'circgradbasedcorrsaturation' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalSaturation'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalSaturation'] }, + 'circgradbasedcorrshadows2012' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalShadows2012'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalShadows2012'] }, + 'circgradbasedcorrsharpness' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalSharpness'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalSharpness'] }, + 'circgradbasedcorrtemperature' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalTemperature'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalTemperature'] }, + 'circgradbasedcorrtexture' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalTexture'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalTexture'] }, + 'circgradbasedcorrtint' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalTint'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalTint'] }, + 'circgradbasedcorrtoninghue' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalToningHue'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalToningHue'] }, + 'circgradbasedcorrtoningsaturation' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalToningSaturation'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalToningSaturation'] }, + 'circgradbasedcorrwhat' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsWhat'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsWhat'] }, + 'circgradbasedcorrwhites2012' => { 478 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalWhites2012'], 480 => [\'CircularGradientBasedCorrections','CircularGradientBasedCorrectionsLocalWhites2012'] }, + 'circulargradientbasedcorrections' => { 478 => 'CircularGradientBasedCorrections', 480 => 'CircularGradientBasedCorrections' }, + 'city' => { 131 => 0x5a, 161 => 'City', 320 => 0x6d, 492 => 'City' }, + 'city2' => { 320 => 0x80 }, + 'clarity' => { 232 => 0x35, 233 => 0x3d, 420 => 0x2036, 478 => 'Clarity', 480 => 'Clarity' }, + 'clarity2012' => { 478 => 'Clarity2012', 480 => 'Clarity2012' }, + 'claritycontrol' => { 355 => 0x96 }, + 'classification' => { 380 => 'clsf' }, + 'classifystate' => { 131 => 0xe1 }, + 'clearretouch' => { 320 => 0x7c }, + 'clearretouchvalue' => { 320 => 0xa3 }, + 'client' => { 504 => 'client' }, + 'clientname' => { 486 => 'ClientName' }, + 'clipboardaspectratio' => { 478 => 'ClipboardAspectRatio', 480 => 'ClipboardAspectRatio' }, + 'clipboardorientation' => { 478 => 'ClipboardOrientation', 480 => 'ClipboardOrientation' }, + 'clipfilename' => { 380 => 'clfn' }, + 'clipid' => { 380 => 'clid' }, + 'clmodeshootingspeed' => { 279 => '10.2', 280 => '11.3', 282 => '11.2', 283 => '11.2', 288 => '11.2', 289 => '10.2', 292 => '11.2', 293 => '11.2', 294 => '11.1', 295 => 0x3b }, + 'cluster' => { 478 => 'Cluster', 480 => 'Cluster' }, + 'cmcontrast' => { 305 => 0x2022 }, + 'cmddialsreverserotation' => { 295 => 0xba }, + 'cmexposurecompensation' => { 305 => 0x2000 }, + 'cmhue' => { 305 => 0x2021 }, + 'cmsaturation' => { 305 => 0x2020 }, + 'cmsharpness' => { 305 => 0x2023 }, + 'cmwhitebalance' => { 305 => 0x2001 }, + 'cmwhitebalancecomp' => { 305 => 0x2002 }, + 'cmwhitebalancegraypoint' => { 305 => 0x2010 }, + 'codec' => { 169 => 'Codec' }, + 'codedcharacterset' => { 132 => 0x5a }, + 'codeversion' => { 380 => 'cver' }, + 'collection' => { 310 => 'Collection' }, + 'collectionname' => { 170 => [\'Collections','CollectionsCollectionName'], 380 => 'coll' }, + 'collections' => { 170 => 'Collections', 473 => 'collections' }, + 'collectionuri' => { 170 => [\'Collections','CollectionsCollectionURI'] }, + 'color' => { 374 => 'player.movie.visual.color', 493 => 'color' }, + 'coloraberrationcontrol' => { 272 => 0xc89224b }, + 'coloradjustment' => { 397 => 0x14 }, + 'coloradjustmentmode' => { 396 => 0x210 }, + 'coloranta' => { 509 => [\'Colorants','ColorantsA'] }, + 'colorantb' => { 509 => [\'Colorants','ColorantsB'] }, + 'colorantblack' => { 509 => [\'Colorants','ColorantsBlack'] }, + 'colorantblue' => { 509 => [\'Colorants','ColorantsBlue'] }, + 'colorantcyan' => { 509 => [\'Colorants','ColorantsCyan'] }, + 'colorantgray' => { 509 => [\'Colorants','ColorantsGray'] }, + 'colorantgreen' => { 509 => [\'Colorants','ColorantsGreen'] }, + 'colorantl' => { 509 => [\'Colorants','ColorantsL'] }, + 'colorantmagenta' => { 509 => [\'Colorants','ColorantsMagenta'] }, + 'colorantmode' => { 509 => [\'Colorants','ColorantsMode'] }, + 'colorantred' => { 509 => [\'Colorants','ColorantsRed'] }, + 'colorants' => { 509 => 'Colorants' }, + 'colorantswatchname' => { 509 => [\'Colorants','ColorantsSwatchName'] }, + 'coloranttint' => { 509 => [\'Colorants','ColorantsTint'] }, + 'coloranttype' => { 509 => [\'Colorants','ColorantsType'] }, + 'colorantyellow' => { 509 => [\'Colorants','ColorantsYellow'] }, + 'colorbalance' => { 156 => 'ColorBalance' }, + 'colorbalanceadj' => { 272 => 0x76a43202 }, + 'colorbalanceblue' => { 181 => 0x1e }, + 'colorbalancegreen' => { 181 => 0x1d }, + 'colorbalancered' => { 181 => 0x1c }, + 'colorbalanceversion' => { 203 => 0x4, 204 => 0x4, 205 => 0x0 }, + 'colorblur' => { 109 => 0x65 }, + 'colorbluron' => { 103 => 0x20704 }, + 'colorbooster' => { 272 => 0x5f0e7d23 }, + 'colorboostlevel' => { 266 => 0x1 }, + 'colorboosttype' => { 266 => 0x0 }, + 'colorchromeeffect' => { 127 => 0x1048 }, + 'colorchromefxblue' => { 127 => 0x104e }, + 'colorclass' => { 366 => 0xde, 367 => 'ColorClass' }, + 'colorcompensationfilter' => { 184 => [0x3a,0x5f], 186 => 0x111, 420 => 0xb022 }, + 'colorcompensationfiltercustom' => { 407 => 0xd, 408 => 0xc }, + 'colorcompensationfilterset' => { 407 => 0x8, 408 => 0x7, 409 => 0x18, 425 => 0xf }, + 'colorcontrol' => { 302 => 0x102b }, + 'colorcorrection' => { 455 => 0x8015 }, + 'colorcreatoreffect' => { 297 => 0x532 }, + 'colordataversion' => { 41 => 0x0, 42 => 0x0, 44 => 0x0, 45 => 0x0, 46 => 0x0, 47 => 0x0, 48 => 0x0, 49 => 0x0, 50 => 0x0 }, + 'coloreffect' => { 320 => 0x28 }, + 'colorfilter' => { 112 => 0x17, 113 => 0x3017, 181 => 0x29, 189 => [0x38,0x4d,0x4f], 362 => 0x17 }, + 'colorgain' => { 237 => 0x51 }, + 'colorgradeblending' => { 478 => 'ColorGradeBlending', 480 => 'ColorGradeBlending' }, + 'colorgradeglobalhue' => { 478 => 'ColorGradeGlobalHue', 480 => 'ColorGradeGlobalHue' }, + 'colorgradegloballum' => { 478 => 'ColorGradeGlobalLum', 480 => 'ColorGradeGlobalLum' }, + 'colorgradeglobalsat' => { 478 => 'ColorGradeGlobalSat', 480 => 'ColorGradeGlobalSat' }, + 'colorgradehighlightlum' => { 478 => 'ColorGradeHighlightLum', 480 => 'ColorGradeHighlightLum' }, + 'colorgrademidtonehue' => { 478 => 'ColorGradeMidtoneHue', 480 => 'ColorGradeMidtoneHue' }, + 'colorgrademidtonelum' => { 478 => 'ColorGradeMidtoneLum', 480 => 'ColorGradeMidtoneLum' }, + 'colorgrademidtonesat' => { 478 => 'ColorGradeMidtoneSat', 480 => 'ColorGradeMidtoneSat' }, + 'colorgradeshadowlum' => { 478 => 'ColorGradeShadowLum', 480 => 'ColorGradeShadowLum' }, + 'colorhue' => { 103 => 0x20900, 226 => 0x8d }, + 'colorimetricreference' => { 119 => 0xc6bf }, + 'colorlabel' => { 483 => 'ColorLabel' }, + 'colormatrix' => { 63 => 0xa, 301 => 0x200, 302 => 0x1011, 394 => 0xa030 }, + 'colormatrix1' => { 119 => 0xc621, 364 => 0x106 }, + 'colormatrix2' => { 119 => 0xc622, 305 => 0x200, 364 => 0x226 }, + 'colormatrix3' => { 119 => 0xcd33 }, + 'colormatrixa' => { 355 => 0x203 }, + 'colormatrixa2' => { 355 => 0x21c }, + 'colormatrixadobergb' => { 394 => 0xa032 }, + 'colormatrixb' => { 355 => 0x204 }, + 'colormatrixb2' => { 355 => 0x21d }, + 'colormatrixnumber' => { 302 => 0x1019 }, + 'colormatrixsrgb' => { 394 => 0xa031 }, + 'colormode' => { 113 => 0x3015, 127 => 0x1210, 140 => 0x66, 181 => 0x28, 184 => 0x16, 186 => 0x101, 187 => 0x36, 189 => 0x7, 226 => 0x3, 262 => 0x4, 320 => 0x32, 397 => 0x2c, 420 => 0xb029, 492 => 'ColorMode' }, + 'colormoirereduction' => { 103 => 0x20670, 273 => 0x15 }, + 'colormoirereductionmode' => { 273 => 0x5 }, + 'colormoirereductionon' => { 103 => '0x20670.0' }, + 'colornoisereduction' => { 455 => 0x8029, 478 => 'ColorNoiseReduction', 480 => 'ColorNoiseReduction' }, + 'colornoisereductiondetail' => { 478 => 'ColorNoiseReductionDetail', 480 => 'ColorNoiseReductionDetail' }, + 'colornoisereductionintensity' => { 273 => 0x18 }, + 'colornoisereductionsharpness' => { 273 => 0x1c }, + 'colornoisereductionsmoothness' => { 478 => 'ColorNoiseReductionSmoothness', 480 => 'ColorNoiseReductionSmoothness' }, + 'colorplanes' => { 123 => 0x2 }, + 'colorprofile' => { 181 => 0x33 }, + 'colorprofilesettings' => { 297 => 0x539 }, + 'colorrepresentation' => { 133 => 0x3c }, + 'colorsaturationadj' => { 103 => 0x20305 }, + 'colorsequence' => { 133 => 0x41 }, + 'colorspace' => { 51 => 0x3, 64 => 0xb4, 97 => 0x10b4, 119 => 0xa001, 135 => 0x3, 162 => 'ColorSpace', 182 => 0x2f, 183 => 0x25, 184 => 0x17, 226 => 0x1e, 297 => 0x507, 355 => 0x37, 394 => 0xa011, 397 => 0xb, 407 => 0x1b, 408 => 0x83, 409 => 0xe, 425 => 0x6, 484 => 'ColorSpace' }, + 'colorspace2' => { 63 => 0x9 }, + 'colorspecapproximation' => { 135 => 0x2 }, + 'colorspecdata' => { 135 => 0x3 }, + 'colorspecmethod' => { 135 => 0x0 }, + 'colorspecprecedence' => { 135 => 0x1 }, + 'colortempasshot' => { 38 => 0x4, 39 => 0x7, 40 => 0x1d, 41 => 0x59, 42 => 0x6d, 43 => 0x26, 44 => 0x43, 47 => 0x43, 48 => 0x43, 49 => 0x43, 50 => 0x4b }, + 'colortempauto' => { 38 => 0x9, 39 => 0xf, 40 => 0x22, 41 => 0x5e, 42 => 0x72, 43 => 0x1c, 44 => 0x48, 47 => 0x48, 48 => 0x48, 49 => 0x48, 50 => 0x50 }, + 'colortempcloudy' => { 38 => 0x22, 39 => 0x37, 40 => 0x31, 41 => 0xa4, 42 => 0xdb, 43 => 0x35, 44 => 0x5c, 47 => 0x75, 48 => 0x8e, 49 => 0x93, 50 => 0x96, 355 => 0x55 }, + 'colortempcustom' => { 44 => 0x84 }, + 'colortempcustom1' => { 40 => 0x45 }, + 'colortempcustom2' => { 40 => 0x4a }, + 'colortempdaylight' => { 38 => 0x18, 39 => 0x27, 40 => 0x27, 41 => 0x9a, 42 => 0xd1, 43 => 0x2b, 44 => 0x52, 47 => 0x6b, 48 => 0x84, 49 => 0x89, 50 => 0x8c, 355 => 0x53 }, + 'colortemperature' => { 7 => 0x73, 8 => [0x48,0x4e], 9 => 0xc0, 10 => 0x37, 11 => 0x62, 12 => 0x37, 13 => 0x7c, 14 => 0x73, 15 => 0x73, 16 => 0x77, 17 => 0x73, 18 => 0x7c, 19 => 0x58, 20 => 0x73, 21 => 0xc0, 22 => 0x7f, 23 => 0x7d, 24 => 0xc0, 25 => 0xc6, 26 => 0xc7, 27 => 0x135, 28 => 0x7b, 29 => 0x13a, 64 => 0xae, 74 => 0x9, 97 => 0x10ae, 127 => 0x1005, 138 => 0x846, 156 => 'ColorTemperature', 182 => [0x6e,0x49], 183 => 0x3f, 184 => [0x39,0x5e], 186 => 0x10b, 189 => [0x3c,0x4c,0x4e], 315 => 0x321, 355 => 0x50, 387 => 0x1308, 420 => 0xb021, 478 => 'Temperature', 480 => 'Temperature' }, + 'colortemperatureadj' => { 455 => 0x8013 }, + 'colortemperatureauto' => { 226 => 0x4f }, + 'colortemperaturebg' => { 302 => 0x1013 }, + 'colortemperaturecustom' => { 407 => 0xc, 408 => 0xb }, + 'colortemperaturerg' => { 302 => 0x1014 }, + 'colortemperatureset' => { 407 => 0x7, 408 => 0x6 }, + 'colortemperaturesetting' => { 184 => 0x25, 409 => 0x17, 425 => 0xe }, + 'colortempflash' => { 38 => 0x36, 39 => 0x57, 40 => 0x40, 41 => 0xb8, 42 => 0xef, 43 => 0x49, 44 => 0x70, 47 => 0x89, 48 => 0xa2, 49 => 0xa7, 50 => 0xaa, 355 => 0x5a }, + 'colortempflashdata' => { 44 => 0x24a }, + 'colortempfluorescent' => { 38 => 0x2c, 39 => 0x47, 40 => 0x3b, 41 => 0xae, 42 => 0xe5, 43 => 0x3f, 44 => 0x66, 47 => 0x7f, 48 => 0x98, 49 => 0x9d, 50 => 0xa0 }, + 'colortempfluorescentd' => { 355 => 0x57 }, + 'colortempfluorescentn' => { 355 => 0x58 }, + 'colortempfluorescentw' => { 355 => 0x59 }, + 'colortempkelvin' => { 38 => 0x31, 39 => 0x4f, 41 => 0xb3, 42 => 0xea, 43 => 0x44, 44 => 0x6b, 47 => 0x84, 48 => 0x9d, 49 => 0xa2, 50 => 0xa5, 320 => 0x44, 387 => 0x1307 }, + 'colortempmeasured' => { 38 => 0xe, 39 => 0x17, 41 => 0x63, 42 => 0x77, 44 => 0x4d, 47 => 0x4d, 48 => 0x4d, 49 => 0x4d, 50 => 0x55 }, + 'colortemppc1' => { 43 => 0x94, 44 => 0x75 }, + 'colortemppc2' => { 43 => 0x99, 44 => 0x7a }, + 'colortemppc3' => { 43 => 0x9e, 44 => 0x7f }, + 'colortempshade' => { 38 => 0x1d, 39 => 0x2f, 40 => 0x2c, 41 => 0x9f, 42 => 0xd6, 43 => 0x30, 44 => 0x57, 47 => 0x70, 48 => 0x89, 49 => 0x8e, 50 => 0x91, 355 => 0x54 }, + 'colortemptungsten' => { 38 => 0x27, 39 => 0x3f, 40 => 0x36, 41 => 0xa9, 42 => 0xe0, 43 => 0x3a, 44 => 0x61, 47 => 0x7a, 48 => 0x93, 49 => 0x98, 50 => 0x9b, 355 => 0x56 }, + 'colortempunknown' => { 38 => 0x13, 39 => 0x1f, 41 => 0x68, 42 => 0x7c, 43 => 0x21, 47 => 0x52, 48 => 0x52, 49 => 0x52, 50 => 0x5a }, + 'colortempunknown10' => { 38 => 0x63, 39 => 0x9f, 41 => 0x95, 42 => 0xa9, 43 => 0x76, 47 => 0xa2, 48 => 0x7f, 49 => 0x7f, 50 => 0x87 }, + 'colortempunknown11' => { 38 => 0x68, 39 => 0xa7, 41 => 0xbd, 42 => [0xae,0xb3], 43 => 0x7b, 47 => 0xa7, 48 => 0xa7, 49 => 0x84, 50 => 0xaf }, + 'colortempunknown12' => { 38 => 0x6d, 39 => 0xaf, 41 => 0xc2, 42 => 0xb8, 43 => 0x80, 47 => 0xac, 48 => 0xac, 49 => 0xac, 50 => 0xb4 }, + 'colortempunknown13' => { 38 => 0x72, 39 => 0xb7, 41 => 0xc7, 42 => 0xbd, 43 => 0x85, 47 => 0xb1, 48 => 0xb1, 49 => 0xb1, 50 => 0xb9 }, + 'colortempunknown14' => { 41 => 0xcc, 42 => 0xc2, 43 => 0x8a, 47 => 0xb6, 48 => 0xb6, 49 => 0xb6, 50 => 0xbe }, + 'colortempunknown15' => { 41 => 0xd1, 42 => 0xc7, 43 => 0x8f, 47 => 0xbb, 48 => 0xbb, 49 => 0xbb, 50 => 0xc3 }, + 'colortempunknown16' => { 41 => 0xd6, 42 => 0xcc, 43 => 0xa3, 48 => 0xc0, 49 => 0xc0, 50 => 0xc8 }, + 'colortempunknown17' => { 41 => 0xdb, 42 => 0xf4, 48 => 0xc5, 49 => 0xc5, 50 => 0xcd }, + 'colortempunknown18' => { 41 => 0xe0, 42 => 0xf9, 48 => 0xca, 49 => 0xca, 50 => 0xd2 }, + 'colortempunknown19' => { 41 => 0xe5, 42 => 0xfe, 48 => 0xcf, 49 => 0xcf, 50 => 0xd7 }, + 'colortempunknown2' => { 38 => 0x3b, 39 => 0x5f, 41 => 0x6d, 42 => 0x81, 43 => 0x4e, 47 => 0x57, 48 => 0x57, 49 => 0x57, 50 => 0x5f }, + 'colortempunknown20' => { 41 => 0xea, 42 => 0x103, 48 => 0xd4, 49 => 0xd4, 50 => 0xdc }, + 'colortempunknown21' => { 41 => 0xef, 42 => 0x108, 49 => 0xd9, 50 => 0xe1 }, + 'colortempunknown22' => { 41 => 0xf4, 42 => 0x10d, 49 => 0xde, 50 => 0xe6 }, + 'colortempunknown23' => { 41 => 0xf9, 42 => 0x112, 49 => 0xe3, 50 => 0xeb }, + 'colortempunknown24' => { 41 => 0xfe, 42 => 0x117, 49 => 0xe8, 50 => 0xf0 }, + 'colortempunknown25' => { 41 => 0x103, 42 => 0x11c, 49 => 0xed, 50 => 0xf5 }, + 'colortempunknown26' => { 41 => 0x108, 42 => 0x121, 49 => 0xf2, 50 => 0xfa }, + 'colortempunknown27' => { 41 => 0x10d, 42 => 0x126, 49 => 0xf7, 50 => 0xff }, + 'colortempunknown28' => { 41 => 0x112, 49 => 0xfc, 50 => 0x104 }, + 'colortempunknown29' => { 41 => 0x117, 49 => 0x101, 50 => 0x109 }, + 'colortempunknown3' => { 38 => 0x40, 39 => 0x67, 41 => 0x72, 42 => 0x86, 43 => 0x53, 47 => 0x5c, 48 => 0x5c, 49 => 0x5c, 50 => 0x64 }, + 'colortempunknown30' => { 49 => 0x106 }, + 'colortempunknown4' => { 38 => 0x45, 39 => 0x6f, 41 => 0x77, 42 => 0x8b, 43 => 0x58, 47 => 0x61, 48 => 0x61, 49 => 0x61, 50 => 0x69 }, + 'colortempunknown5' => { 38 => 0x4a, 39 => 0x77, 41 => 0x7c, 42 => 0x90, 43 => 0x5d, 47 => 0x66, 48 => 0x66, 49 => 0x66, 50 => 0x6e }, + 'colortempunknown6' => { 38 => 0x4f, 39 => 0x7f, 41 => 0x81, 42 => 0x95, 43 => 0x62, 47 => 0x8e, 48 => 0x6b, 49 => 0x6b, 50 => 0x73 }, + 'colortempunknown7' => { 38 => 0x54, 39 => 0x87, 41 => 0x86, 42 => 0x9a, 43 => 0x67, 47 => 0x93, 48 => 0x70, 49 => 0x70, 50 => 0x78 }, + 'colortempunknown8' => { 38 => 0x59, 39 => 0x8f, 41 => 0x8b, 42 => 0x9f, 43 => 0x6c, 47 => 0x98, 48 => 0x75, 49 => 0x75, 50 => 0x7d }, + 'colortempunknown9' => { 38 => 0x5e, 39 => 0x97, 41 => 0x90, 42 => 0xa4, 43 => 0x71, 47 => 0x9d, 48 => 0x7a, 49 => 0x7a, 50 => 0x82 }, + 'colortint' => { 319 => 0x35c }, + 'colortone' => { 10 => 0x6f, 12 => 0x77, 34 => 0x2a, 51 => 0x2, 63 => 0x8 }, + 'colortoneadj' => { 103 => 0x20304, 108 => 0x11e }, + 'colortoneauto' => { 71 => 0x9c }, + 'colortonefaithful' => { 19 => 0x107, 70 => 0x6c, 71 => 0x6c }, + 'colortonelandscape' => { 19 => 0x105, 70 => 0x3c, 71 => 0x3c }, + 'colortonemonochrome' => { 70 => 0x84, 71 => 0x84 }, + 'colortoneneutral' => { 19 => 0x106, 70 => 0x54, 71 => 0x54 }, + 'colortoneportrait' => { 19 => 0x104, 70 => 0x24, 71 => 0x24 }, + 'colortonestandard' => { 19 => 0x103, 70 => 0xc, 71 => 0xc }, + 'colortoneuserdef1' => { 19 => 0x109, 70 => 0x9c, 71 => 0xb4 }, + 'colortoneuserdef2' => { 19 => 0x10a, 70 => 0xb4, 71 => 0xcc }, + 'colortoneuserdef3' => { 19 => 0x10b, 70 => 0xcc, 71 => 0xe4 }, + 'comlenblksize' => { 138 => 0xfde8 }, + 'commanddialplaybackmode' => { 295 => 0x1cb }, + 'commanddials' => { 290 => '5.1' }, + 'commanddialsaperturesetting' => { 279 => '17.3', 280 => '18.3', 282 => '18.3', 283 => '18.3', 288 => '33.3', 289 => '17.3', 292 => '18.3', 293 => '18.3' }, + 'commanddialschangemainsub' => { 279 => '17.2', 280 => '18.1', 282 => '18.1', 283 => '18.1', 288 => '33.2', 289 => '17.2', 292 => '18.1', 293 => '18.1' }, + 'commanddialsmenuandplayback' => { 279 => '17.4', 280 => '18.2', 282 => '18.2', 283 => '18.2', 288 => '33.4', 289 => '17.4', 292 => '18.2', 293 => '18.2' }, + 'commanddialsreverserotation' => { 279 => '17.1', 280 => '6.4', 282 => '6.2', 283 => '6.2', 284 => '16.2', 285 => '17.2', 288 => '33.1', 289 => '17.1', 292 => '6.2', 293 => '6.2', 294 => '18.1' }, + 'commanderchannel' => { 290 => '10.2', 291 => '25.2' }, + 'commandergroupa_ttl-aacomp' => { 290 => '13.1', 291 => '31.1' }, + 'commandergroupa_ttlcomp' => { 294 => '32.1' }, + 'commandergroupamanualoutput' => { 290 => '13.2', 291 => '28.2' }, + 'commandergroupamode' => { 290 => '11.2', 291 => '28.1' }, + 'commandergroupb_ttl-aacomp' => { 290 => '14.1', 291 => '32.1' }, + 'commandergroupb_ttlcomp' => { 294 => '33.1' }, + 'commandergroupbmanualoutput' => { 290 => '14.2', 291 => '29.2' }, + 'commandergroupbmode' => { 290 => '11.3', 291 => '29.1' }, + 'commanderinternalflash' => { 290 => '11.1', 291 => '27.1' }, + 'commanderinternalmanualoutput' => { 290 => '12.2', 291 => '27.2' }, + 'commanderinternalttlchannel' => { 288 => '18.2' }, + 'commanderinternalttlcomp' => { 290 => '12.1', 291 => '30.2', 294 => '31.2' }, + 'commanderinternalttlcompbuiltin' => { 288 => '20.1', 289 => '26.1' }, + 'commanderinternalttlcompgroupa' => { 288 => '21.1', 289 => '27.1' }, + 'commanderinternalttlcompgroupb' => { 288 => '22.1', 289 => '28.1' }, + 'comment' => { 0 => 0x2, 120 => 'Comment', 157 => 'Comment', 310 => 'Comment', 372 => "\xa9cmt", 374 => 'comment', 380 => "\xa9cmt" }, + 'compass' => { 390 => 0x4 }, + 'compatibleversion' => { 478 => 'CompatibleVersion', 480 => 'CompatibleVersion' }, + 'compilation' => { 372 => 'cpil' }, + 'compimageimagespersequence' => { 485 => [\'CompositeImageExposureTimes','CompositeImageExposureTimesNumberOfImagesInSequences'] }, + 'compimagemaxexposureall' => { 485 => [\'CompositeImageExposureTimes','CompositeImageExposureTimesMaxExposureTimesOfAll'] }, + 'compimagemaxexposureused' => { 485 => [\'CompositeImageExposureTimes','CompositeImageExposureTimesMaxExposureTimesOfUsed'] }, + 'compimageminexposureall' => { 485 => [\'CompositeImageExposureTimes','CompositeImageExposureTimesMinExposureTimesOfAll'] }, + 'compimageminexposureused' => { 485 => [\'CompositeImageExposureTimes','CompositeImageExposureTimesMinExposureTimesOfUsed'] }, + 'compimagenumsequences' => { 485 => [\'CompositeImageExposureTimes','CompositeImageExposureTimesNumberOfSequences'] }, + 'compimagesumexposureall' => { 485 => [\'CompositeImageExposureTimes','CompositeImageExposureTimesSumOfExposureTimesOfAll'] }, + 'compimagesumexposureused' => { 485 => [\'CompositeImageExposureTimes','CompositeImageExposureTimesSumOfExposureTimesOfUsed'] }, + 'compimagetotalexposureperiod' => { 485 => [\'CompositeImageExposureTimes','CompositeImageExposureTimesTotalExposurePeriod'] }, + 'compimagevalues' => { 485 => [\'CompositeImageExposureTimes','CompositeImageExposureTimesValues'] }, + 'complianceprofile' => { 494 => 'complianceProfile' }, + 'componentsconfiguration' => { 119 => 0x9101, 162 => 'Components', 484 => 'ComponentsConfiguration' }, + 'componentversion' => { 97 => 0x80c }, + 'composer' => { 179 => 'WM/Composer', 372 => ["\xa9com","\xa9wrt"], 380 => ["\xa9com","\xa9wrt"], 504 => 'composer' }, + 'composerkeywords' => { 380 => "\xa9cok" }, + 'compositeimage' => { 119 => 0xa460, 485 => 'CompositeImage' }, + 'compositeimagecount' => { 119 => 0xa461, 485 => 'CompositeImageCount' }, + 'compositeimageexposuretimes' => { 119 => 0xa462, 485 => 'CompositeImageExposureTimes' }, + 'composition' => { 468 => 'Composition' }, + 'compositionadjust' => { 354 => '0.1' }, + 'compositionadjustrotation' => { 354 => 0x7 }, + 'compositionadjustx' => { 354 => 0x5 }, + 'compositionadjusty' => { 354 => 0x6 }, + 'compressedbitsperpixel' => { 119 => 0x9102, 484 => 'CompressedBitsPerPixel' }, + 'compressedimagesize' => { 186 => 0x40, 302 => 0x40 }, + 'compression' => { 119 => 0x103, 325 => 0xb, 500 => 'Compression' }, + 'compressionfactor' => { 297 => 0x50d }, + 'compressionformat' => { 63 => 0x4 }, + 'compressionratio' => { 162 => 'Compression', 302 => 0x1034 }, + 'compressorversion' => { 380 => 'CNCV' }, + 'condadobvfactor' => { 138 => 0xf3e }, + 'condadodaybvthresh' => { 138 => 0xf3c }, + 'condadodayoffsets' => { 138 => 0xf42 }, + 'condadofluoffsets' => { 138 => 0xf44 }, + 'condadofluthresh' => { 138 => 0xf41 }, + 'condadoillfactor' => { 138 => 0xf3f }, + 'condadoneurange' => { 138 => 0xf3d }, + 'condadotunoffsets' => { 138 => 0xf43 }, + 'condadotunthresh' => { 138 => 0xf40 }, + 'conductor' => { 179 => 'WM/Conductor', 372 => "\xa9con" }, + 'confidence' => { 463 => 'Confidence' }, + 'confidencelevel' => { 474 => 'ConfidenceLevel' }, + 'confidencemime' => { 463 => 'ConfidenceMime' }, + 'constrainedcropheight' => { 108 => 0x266, 366 => 0xd6 }, + 'constrainedcropwidth' => { 108 => 0x262, 366 => 0xd5 }, + 'contact' => { 131 => 0x76 }, + 'contactinfo' => { 478 => 'ContactInfo', 480 => 'ContactInfo', 493 => 'contactInfo' }, + 'container' => { 458 => 'Container' }, + 'containerdirectory' => { 458 => [\'Container','ContainerDirectory'] }, + 'containerdirectoryitem' => { 458 => [\'Container','ContainerDirectoryItem'] }, + 'containerdirectoryitemdatauri' => { 458 => [\'Container','ContainerDirectoryItemDataURI'] }, + 'containerdirectoryitemlength' => { 458 => [\'Container','ContainerDirectoryItemLength'] }, + 'containerdirectoryitemmime' => { 458 => [\'Container','ContainerDirectoryItemMime'] }, + 'containerdirectoryitempadding' => { 458 => [\'Container','ContainerDirectoryItemPadding'] }, + 'containerformat' => { 490 => 'ContainerFormat' }, + 'containerformatidentifier' => { 490 => [\'ContainerFormat','ContainerFormatIdentifier'] }, + 'containerformatname' => { 490 => [\'ContainerFormat','ContainerFormatName'] }, + 'contentcreatedate' => { 372 => "\xa9day", 380 => ['@day',"\xa9day"] }, + 'contentdistributor' => { 179 => 'WM/ContentDistributor' }, + 'contentdistributorid' => { 380 => 'cdis' }, + 'contentid' => { 380 => 'ccid' }, + 'contentlocationcode' => { 131 => 0x1a }, + 'contentlocationname' => { 131 => 0x1b }, + 'contenttype' => { 494 => 'contentType' }, + 'continuousbracketing' => { 184 => 0x20 }, + 'continuousdrive' => { 34 => 0x5 }, + 'continuousmodedisplay' => { 295 => 0x51 }, + 'continuousmodeliveview' => { 293 => '77.2' }, + 'continuousshootingspeed' => { 84 => 0x610 }, + 'continuousshotlimit' => { 84 => 0x611 }, + 'contrast' => { 10 => 0x73, 12 => 0x75, 34 => 0xd, 112 => 0xc, 113 => [0x3012,0x20], 119 => [0xa408,0xfe54], 127 => [0x1004,0x1006], 156 => 'Contrast', 176 => 'Contrast', 181 => 0x20, 182 => 0x31, 183 => 0x27, 184 => 0x19, 189 => 0x2, 231 => 0x33, 232 => 0x37, 233 => 0x3f, 302 => 0x1029, 320 => 0x39, 322 => 0x300a, 355 => 0x20, 362 => 0xc, 374 => 'player.movie.visual.contrast', 381 => 0x24, 383 => 0x52, 387 => 0x1012, 397 => 0xd, 407 => 0x1d, 408 => 0x1a, 420 => 0x2004, 478 => 'Contrast', 480 => 'Contrast', 484 => 'Contrast' }, + 'contrast2012' => { 478 => 'Contrast2012', 480 => 'Contrast2012' }, + 'contrastadj' => { 103 => 0x20303, 108 => 0x115, 275 => 0x2c, 455 => 0x8017 }, + 'contrastauto' => { 71 => 0x90 }, + 'contrastcurve' => { 226 => 0x8c }, + 'contrastdetectaf' => { 193 => 0x4 }, + 'contrastdetectafarea' => { 355 => 0x231 }, + 'contrastdetectafinfocus' => { 193 => [0x1c,0x52] }, + 'contrastfaithful' => { 19 => 0xec, 70 => 0x60, 71 => 0x60 }, + 'contrasthighlight' => { 355 => 0x6d }, + 'contrasthighlightshadowadj' => { 355 => 0x6f }, + 'contrastlandscape' => { 19 => 0xea, 70 => 0x30, 71 => 0x30 }, + 'contrastmode' => { 320 => 0x2c }, + 'contrastmonochrome' => { 19 => 0xed, 70 => 0x78, 71 => 0x78 }, + 'contrastneutral' => { 19 => 0xeb, 70 => 0x48, 71 => 0x48 }, + 'contrastportrait' => { 19 => 0xe9, 70 => 0x18, 71 => 0x18 }, + 'contrastsetting' => { 297 => 0x505, 305 => 0x1012, 409 => 0x10, 425 => 0x8 }, + 'contrastshadow' => { 355 => 0x6e }, + 'contraststandard' => { 19 => 0xe8, 70 => 0x0, 71 => 0x0 }, + 'contrastuserdef1' => { 19 => 0xee, 70 => 0x90, 71 => 0xa8 }, + 'contrastuserdef2' => { 19 => 0xef, 70 => 0xa8, 71 => 0xc0 }, + 'contrastuserdef3' => { 19 => 0xf0, 70 => 0xc0, 71 => 0xd8 }, + 'contributedmedia' => { 504 => 'contributedMedia' }, + 'contributedmediaduration' => { 504 => [\'contributedMedia','contributedMediaDuration'] }, + 'contributedmediadurationscale' => { 504 => [\'contributedMedia','contributedMediaDurationScale'] }, + 'contributedmediadurationvalue' => { 504 => [\'contributedMedia','contributedMediaDurationValue'] }, + 'contributedmediamanaged' => { 504 => [\'contributedMedia','contributedMediaManaged'] }, + 'contributedmediapath' => { 504 => [\'contributedMedia','contributedMediaPath'] }, + 'contributedmediastarttime' => { 504 => [\'contributedMedia','contributedMediaStartTime'] }, + 'contributedmediastarttimescale' => { 504 => [\'contributedMedia','contributedMediaStartTimeScale'] }, + 'contributedmediastarttimevalue' => { 504 => [\'contributedMedia','contributedMediaStartTimeValue'] }, + 'contributedmediatrack' => { 504 => [\'contributedMedia','contributedMediaTrack'] }, + 'contributedmediawebstatement' => { 504 => [\'contributedMedia','contributedMediaWebStatement'] }, + 'contributor' => { 481 => 'contributor', 490 => 'Contributor' }, + 'contributoridentifier' => { 490 => [\'Contributor','ContributorIdentifier'] }, + 'contributorname' => { 490 => [\'Contributor','ContributorName'] }, + 'contributorrole' => { 490 => [\'Contributor','ContributorRole'] }, + 'contributors' => { 157 => 'Contributors' }, + 'controldialset' => { 184 => 0x46 }, + 'controlledvocabularyterm' => { 490 => 'CVterm' }, + 'controllerboardversion' => { 315 => 0x332 }, + 'controlmode' => { 77 => 0x12 }, + 'controlringresponse' => { 295 => 0x1d5 }, + 'controlringrotation' => { 84 => 0x712 }, + 'conversionlens' => { 298 => 0x403, 320 => 0x35 }, + 'converter' => { 119 => 0xfe4d, 262 => 0xb, 478 => 'Converter', 480 => 'Converter' }, + 'converttograyscale' => { 478 => 'ConvertToGrayscale', 480 => 'ConvertToGrayscale' }, + 'cookingequipment' => { 496 => 'cookingEquipment' }, + 'cookingmethod' => { 496 => 'cookingMethod' }, + 'copyright' => { 0 => 0x3, 119 => 0x8298, 157 => 'Copyright', 310 => 'Copyright', 355 => 0x22f, 371 => 'Copyright', 372 => ['cprt',"\xa9cpy"], 374 => 'copyright', 380 => ['cprt',"\xa9cpy"], 478 => 'Copyright', 480 => 'Copyright', 491 => 'Copyright', 497 => 'copyright', 500 => 'Copyright', 504 => 'copyright' }, + 'copyrightflag' => { 369 => 0x40a }, + 'copyrightnotice' => { 131 => 0x74 }, + 'copyrightowner' => { 307 => 'CopyrightOwner' }, + 'copyrightownerid' => { 307 => [\'CopyrightOwner','CopyrightOwnerCopyrightOwnerID'] }, + 'copyrightownerimageid' => { 307 => 'CopyrightOwnerImageID' }, + 'copyrightownername' => { 307 => [\'CopyrightOwner','CopyrightOwnerCopyrightOwnerName'] }, + 'copyrightregistrationnumber' => { 307 => 'CopyrightRegistrationNumber' }, + 'copyrightstatus' => { 307 => 'CopyrightStatus' }, + 'copyrightyear' => { 490 => 'CopyrightYear', 494 => 'copyrightYear' }, + 'coringfilter' => { 301 => 0x310, 302 => 0x102d, 305 => 0x310 }, + 'coringvalues' => { 301 => 0x311, 305 => 0x311 }, + 'corporateentity' => { 494 => 'corporateEntity' }, + 'correlatedcolortemp' => { 319 => 0x35b }, + 'country' => { 161 => 'Country', 320 => 0x69, 492 => 'Country' }, + 'country-primarylocationcode' => { 131 => 0x64 }, + 'country-primarylocationname' => { 131 => 0x65 }, + 'countrycode' => { 225 => 0x5, 367 => 'CountryCode', 489 => 'CountryCode' }, + 'course' => { 496 => 'course' }, + 'coverage' => { 481 => 'coverage' }, + 'coverart' => { 372 => 'covr' }, + 'coverdate' => { 494 => 'coverDate' }, + 'coverdisplaydate' => { 494 => 'coverDisplayDate' }, + 'coveruri' => { 380 => 'cvru' }, + 'cpufirmwareversion' => { 355 => 0x28 }, + 'crc32' => { 482 => 'crc32' }, + 'createdate' => { 119 => 0x9004, 157 => 'CreateDate', 306 => 'CreationDate', 310 => 'create-date', 371 => 'CreationDate', 377 => 0x1, 502 => 'CreateDate' }, + 'creationdate' => { 374 => 'creationdate', 491 => 'CreationDate', 494 => 'creationDate' }, + 'creationtime' => { 310 => 'Creation Time' }, + 'creativestyle' => { 407 => 0x1a, 408 => 0x18, 418 => 0x41, 420 => 0xb020, 451 => 0x4a }, + 'creativestylesetting' => { 409 => 0xf, 425 => 0x7 }, + 'creativestylewaschanged' => { 455 => 0x8001 }, + 'creator' => { 306 => 'Creator', 371 => 'Creator', 481 => 'creator', 490 => 'Creator', 491 => 'Creator' }, + 'creatoraddress' => { 489 => [\'CreatorContactInfo','CreatorContactInfoCiAdrExtadr'] }, + 'creatorappid' => { 178 => 'CreatorAppId' }, + 'creatorcity' => { 489 => [\'CreatorContactInfo','CreatorContactInfoCiAdrCity'] }, + 'creatorcontactinfo' => { 489 => 'CreatorContactInfo' }, + 'creatorcountry' => { 489 => [\'CreatorContactInfo','CreatorContactInfoCiAdrCtry'] }, + 'creatoridentifier' => { 490 => [\'Creator','CreatorIdentifier'] }, + 'creatorname' => { 490 => [\'Creator','CreatorName'] }, + 'creatoropenwithuioptions' => { 178 => 'CreatorOpenWithUIOptions' }, + 'creatorpostalcode' => { 489 => [\'CreatorContactInfo','CreatorContactInfoCiAdrPcode'] }, + 'creatorregion' => { 489 => [\'CreatorContactInfo','CreatorContactInfoCiAdrRegion'] }, + 'creatorrole' => { 490 => [\'Creator','CreatorRole'] }, + 'creatortool' => { 502 => 'CreatorTool' }, + 'creatorworkemail' => { 489 => [\'CreatorContactInfo','CreatorContactInfoCiEmailWork'] }, + 'creatorworktelephone' => { 489 => [\'CreatorContactInfo','CreatorContactInfoCiTelWork'] }, + 'creatorworkurl' => { 489 => [\'CreatorContactInfo','CreatorContactInfoCiUrlWork'] }, + 'credit' => { 131 => 0x6e, 492 => 'Credit' }, + 'creditline' => { 497 => 'creditLine' }, + 'creditlinereq' => { 507 => 'CreditLineReq' }, + 'creditlinerequired' => { 307 => 'CreditLineRequired' }, + 'cropactive' => { 101 => 0x0, 108 => 0x244 }, + 'cropangle' => { 478 => 'CropAngle', 480 => 'CropAngle' }, + 'croparea' => { 226 => 0x45, 455 => 0x9011 }, + 'cropaspectratio' => { 103 => 0x30101, 108 => 0x260 }, + 'cropaspectratiocustom' => { 103 => 0x30102 }, + 'cropbottom' => { 123 => 0x9, 267 => 0x36, 325 => 0x31, 366 => 0xdc, 478 => 'CropBottom', 480 => 'CropBottom' }, + 'cropbottommargin' => { 53 => 0x3 }, + 'cropcircleactive' => { 109 => 0xd6 }, + 'cropcircleradius' => { 109 => 0xd9 }, + 'cropcirclex' => { 109 => 0xd7 }, + 'cropcircley' => { 109 => 0xd8 }, + 'cropconstraintowarp' => { 478 => 'CropConstrainToWarp', 480 => 'CropConstrainToWarp' }, + 'croph' => { 472 => 'CropH' }, + 'cropheight' => { 101 => 0x6, 108 => 0x24c, 301 => 0x615, 305 => 0x615, 478 => 'CropHeight', 480 => 'CropHeight' }, + 'crophispeed' => { 226 => 0x1b }, + 'cropleft' => { 108 => 0x246, 123 => 0x6, 267 => 0x1e, 301 => 0x612, 305 => 0x612, 325 => 0x30, 366 => 0xd9, 478 => 'CropLeft', 480 => 'CropLeft' }, + 'cropleftmargin' => { 53 => 0x0 }, + 'cropmode' => { 127 => 0x104d, 387 => 0x1018 }, + 'croporiginalheight' => { 101 => 0xb }, + 'croporiginalwidth' => { 101 => 0xa }, + 'cropoutputheight' => { 267 => 0xce }, + 'cropoutputheightinches' => { 267 => 0x96 }, + 'cropoutputpixels' => { 267 => 0xd6 }, + 'cropoutputresolution' => { 267 => 0xb6 }, + 'cropoutputscale' => { 267 => 0xbe }, + 'cropoutputwidth' => { 267 => 0xc6 }, + 'cropoutputwidthinches' => { 267 => 0x8e }, + 'croppedareaimageheightpixels' => { 466 => 'CroppedAreaImageHeightPixels', 467 => 'CroppedAreaImageHeightPixels' }, + 'croppedareaimagewidthpixels' => { 466 => 'CroppedAreaImageWidthPixels', 467 => 'CroppedAreaImageWidthPixels' }, + 'croppedarealeftpixels' => { 466 => 'CroppedAreaLeftPixels', 467 => 'CroppedAreaLeftPixels' }, + 'croppedareatoppixels' => { 466 => 'CroppedAreaTopPixels', 467 => 'CroppedAreaTopPixels' }, + 'croppedimageheight' => { 5 => 0x2, 387 => 0x1604 }, 'croppedimageleft' => { 5 => 0x3 }, 'croppedimagetop' => { 5 => 0x4 }, - 'croppedimagewidth' => { 5 => 0x1, 358 => 0x1603 }, - 'cropping' => { 421 => 0x9010 }, - 'cropright' => { 117 => 0x8, 245 => 0x2e, 302 => 0x32, 343 => 0xdb, 442 => 'CropRight' }, - 'croprightmargin' => { 50 => 0x1 }, - 'croprotatedoriginalheight' => { 95 => 0x2 }, - 'croprotatedoriginalwidth' => { 95 => 0x1 }, - 'croprotation' => { 95 => 0x8, 117 => 0xb }, - 'cropscaledresolution' => { 245 => 0x9e }, - 'cropsourceresolution' => { 245 => 0xae }, - 'croptop' => { 102 => 0x248, 117 => 0x7, 245 => 0x26, 278 => 0x613, 282 => 0x613, 302 => 0x2f, 343 => 0xda, 442 => 'CropTop' }, - 'croptopmargin' => { 50 => 0x2 }, - 'cropunit' => { 442 => 'CropUnit' }, - 'cropunits' => { 442 => 'CropUnits' }, - 'cropw' => { 435 => 'CropW' }, - 'cropwidth' => { 95 => 0x5, 102 => 0x24a, 278 => 0x614, 282 => 0x614, 442 => 'CropWidth' }, - 'cropx' => { 95 => 0x3, 435 => 'CropX' }, - 'cropy' => { 95 => 0x4, 435 => 'CropY' }, - 'crossprocess' => { 332 => 0x7b }, - 'crossprocessparams' => { 332 => 0x235 }, - 'cuisine' => { 458 => 'cuisine' }, - 'currenticcprofile' => { 113 => 0xc691 }, - 'currentpreprofilematrix' => { 113 => 0xc692 }, - 'currentversion' => { 421 => 0xd000 }, - 'curve0x' => { 435 => 'Curve0x' }, - 'curve0y' => { 435 => 'Curve0y' }, - 'curve1x' => { 435 => 'Curve1x' }, - 'curve1y' => { 435 => 'Curve1y' }, - 'curve2x' => { 435 => 'Curve2x' }, - 'curve2y' => { 435 => 'Curve2y' }, - 'curve3x' => { 435 => 'Curve3x' }, - 'curve3y' => { 435 => 'Curve3y' }, - 'curve4x' => { 435 => 'Curve4x' }, - 'curve4y' => { 435 => 'Curve4y' }, - 'curves' => { 250 => 0x76a43201 }, - 'custom1' => { 284 => 'Custom1' }, - 'custom10' => { 284 => 'Custom10' }, - 'custom2' => { 284 => 'Custom2' }, - 'custom3' => { 284 => 'Custom3' }, - 'custom4' => { 284 => 'Custom4' }, - 'custom5' => { 284 => 'Custom5' }, - 'custom6' => { 284 => 'Custom6' }, - 'custom7' => { 284 => 'Custom7' }, - 'custom8' => { 284 => 'Custom8' }, - 'custom9' => { 284 => 'Custom9' }, - 'customcolortone' => { 103 => 0x4c }, - 'customcontrast' => { 103 => 0x4e }, - 'customcontrols' => { 78 => 0x70c }, - 'customdefaultunsharpfineness' => { 103 => 0xbe }, - 'customdefaultunsharpstrength' => { 103 => 0xbc }, - 'customdefaultunsharpthreshold' => { 103 => 0xc0 }, - 'customilluminant' => { 131 => 0x405 }, - 'customizedials' => { 78 => 0x715 }, - 'customlinear' => { 103 => 0x4f }, - 'customoutputhighlightpoint' => { 103 => 0x53 }, - 'customoutputshadowpoint' => { 103 => 0x54 }, - 'custompicturestyle' => { 97 => 0x10021 }, - 'custompicturestyledata' => { 97 => 0xf0500 }, - 'custompicturestylefilename' => { 60 => 0x4010 }, - 'customrawhighlight' => { 103 => 0x7c }, - 'customrawhighlightpoint' => { 103 => 0x51 }, - 'customrawshadow' => { 103 => 0x85 }, - 'customrawshadowpoint' => { 103 => 0x52 }, - 'customrendered' => { 113 => 0xa401, 446 => 'CustomRendered' }, - 'customsaturation' => { 103 => 0x4d, 274 => 0x503 }, - 'customsettingsalldefault' => { 257 => '0.2', 266 => '0.2' }, - 'customsettingsbank' => { 257 => '0.1', 258 => '0.1', 260 => '0.1', 261 => '0.1', 266 => '0.1', 270 => '0.2', 271 => '0.2' }, - 'customsharpness' => { 103 => 0x50 }, - 'customunsharpmaskfineness' => { 103 => 0xb8 }, - 'customunsharpmaskstrength' => { 103 => 0xb6 }, - 'customunsharpmaskthreshold' => { 103 => 0xba }, - 'customwb_rblevels' => { 393 => 0x1a }, - 'customwb_rgblevels' => { 377 => 0x8, 378 => 0x19 }, - 'customwbbluelevel' => { 174 => 0x36 }, - 'customwberror' => { 174 => 0x37 }, - 'customwbgreenlevel' => { 174 => 0x35 }, - 'customwbredlevel' => { 174 => 0x34 }, - 'customwbsetting' => { 174 => 0x26 }, - 'd-lightinghq' => { 250 => 0x2175eb78 }, - 'd-lightinghqcolorboost' => { 246 => 0x2 }, - 'd-lightinghqhighlight' => { 246 => 0x1 }, - 'd-lightinghqselected' => { 250 => 0x6a6e36b6 }, - 'd-lightinghqshadow' => { 246 => 0x0 }, - 'd-lightinghs' => { 250 => 0xce5554aa }, - 'd-lightinghsadjustment' => { 247 => 0x0 }, - 'd-lightinghscolorboost' => { 247 => 0x1 }, - 'd-rangeoptimizerhighlight' => { 421 => 0x8024 }, - 'd-rangeoptimizermode' => { 421 => 0x8022 }, - 'd-rangeoptimizershadow' => { 421 => 0x802d }, - 'd-rangeoptimizervalue' => { 421 => 0x8023 }, - 'd810meteringmode' => { 237 => 0x175e }, - 'darkblacksegrows' => { 131 => 0x18d8 }, - 'darkfocusenvironment' => { 297 => 0x8003 }, - 'darkframecountfactor' => { 131 => 0xc85 }, - 'darkframelongexposure' => { 131 => 0xc84 }, - 'darkframeshortexposure' => { 131 => 0xc83 }, - 'darkpedestal' => { 131 => 0xc7f }, - 'data' => { 426 => 'Data' }, - 'datacompressionmethod' => { 127 => 0x6e }, - 'dataimprint' => { 171 => 0x34 }, - 'dataonscreen' => { 452 => 'DataOnScreen' }, - 'dataonscreenregion' => { 452 => [\'DataOnScreen','DataOnScreenRegion'] }, - 'dataonscreenregiond' => { 452 => [\'DataOnScreen','DataOnScreenRegionD'] }, - 'dataonscreenregionh' => { 452 => [\'DataOnScreen','DataOnScreenRegionH'] }, - 'dataonscreenregiontext' => { 452 => [\'DataOnScreen','DataOnScreenRegionText'] }, - 'dataonscreenregionunit' => { 452 => [\'DataOnScreen','DataOnScreenRegionUnit'] }, - 'dataonscreenregionw' => { 452 => [\'DataOnScreen','DataOnScreenRegionW'] }, - 'dataonscreenregionx' => { 452 => [\'DataOnScreen','DataOnScreenRegionX'] }, - 'dataonscreenregiony' => { 452 => [\'DataOnScreen','DataOnScreenRegionY'] }, - 'datascaling' => { 332 => 0x3d }, - 'date' => { 332 => 0x6, 443 => 'date' }, - 'dateacquired' => { 169 => 'DateAcquired' }, - 'datecreated' => { 125 => 0x37, 454 => 'DateCreated' }, - 'datedisplayformat' => { 242 => 0x3 }, - 'dateidentified' => { 112 => [\'Identification','IdentificationDateIdentified'] }, - 'dateimprint' => { 262 => '4.2' }, - 'daterecieved' => { 456 => 'dateRecieved' }, - 'datesent' => { 126 => 0x46 }, - 'datestampmode' => { 60 => 0x1c }, - 'datetime' => { 436 => 'datetime', 462 => 'DateTime' }, - 'datetimedigitized' => { 446 => 'DateTimeDigitized' }, - 'datetimeoriginal' => { 94 => 0x0, 113 => 0x9003, 145 => 0x14, 148 => 'OriginalDate', 353 => 0xb, 354 => 0x3b, 446 => 'DateTimeOriginal' }, - 'datetimestamp' => { 133 => 0x64 }, - 'datetimeutc' => { 274 => 0x908 }, - 'daylightsavings' => { 73 => 0x3, 242 => 0x2 }, - 'dayofweek' => { 354 => 0x42 }, - 'dccontinent' => { 112 => [\'dctermsLocation','dctermsLocationContinent'] }, - 'dccoordinateprecision' => { 112 => [\'dctermsLocation','dctermsLocationCoordinatePrecision'] }, - 'dccoordinateuncertaintyinmeters' => { 112 => [\'dctermsLocation','dctermsLocationCoordinateUncertaintyInMeters'] }, - 'dccountry' => { 112 => [\'dctermsLocation','dctermsLocationCountry'] }, - 'dccountrycode' => { 112 => [\'dctermsLocation','dctermsLocationCountryCode'] }, - 'dccounty' => { 112 => [\'dctermsLocation','dctermsLocationCounty'] }, - 'dcdecimallatitude' => { 112 => [\'dctermsLocation','dctermsLocationDecimalLatitude'] }, - 'dcdecimallongitude' => { 112 => [\'dctermsLocation','dctermsLocationDecimalLongitude'] }, - 'dcevent' => { 112 => 'Event' }, - 'dcfootprintspatialfit' => { 112 => [\'dctermsLocation','dctermsLocationFootprintSpatialFit'] }, - 'dcfootprintsrs' => { 112 => [\'dctermsLocation','dctermsLocationFootprintSRS'] }, - 'dcfootprintwkt' => { 112 => [\'dctermsLocation','dctermsLocationFootprintWKT'] }, - 'dcgeodeticdatum' => { 112 => [\'dctermsLocation','dctermsLocationGeodeticDatum'] }, - 'dcgeoreferencedby' => { 112 => [\'dctermsLocation','dctermsLocationGeoreferencedBy'] }, - 'dcgeoreferenceddate' => { 112 => [\'dctermsLocation','dctermsLocationGeoreferencedDate'] }, - 'dcgeoreferenceprotocol' => { 112 => [\'dctermsLocation','dctermsLocationGeoreferenceProtocol'] }, - 'dcgeoreferenceremarks' => { 112 => [\'dctermsLocation','dctermsLocationGeoreferenceRemarks'] }, - 'dcgeoreferencesources' => { 112 => [\'dctermsLocation','dctermsLocationGeoreferenceSources'] }, - 'dcgeoreferenceverificationstatus' => { 112 => [\'dctermsLocation','dctermsLocationGeoreferenceVerificationStatus'] }, - 'dchighergeography' => { 112 => [\'dctermsLocation','dctermsLocationHigherGeography'] }, - 'dchighergeographyid' => { 112 => [\'dctermsLocation','dctermsLocationHigherGeographyID'] }, - 'dcisland' => { 112 => [\'dctermsLocation','dctermsLocationIsland'] }, - 'dcislandgroup' => { 112 => [\'dctermsLocation','dctermsLocationIslandGroup'] }, - 'dclocality' => { 112 => [\'dctermsLocation','dctermsLocationLocality'] }, - 'dclocationaccordingto' => { 112 => [\'dctermsLocation','dctermsLocationLocationAccordingTo'] }, - 'dclocationid' => { 112 => [\'dctermsLocation','dctermsLocationLocationID'] }, - 'dclocationremarks' => { 112 => [\'dctermsLocation','dctermsLocationLocationRemarks'] }, - 'dcmaximumdepthinmeters' => { 112 => [\'dctermsLocation','dctermsLocationMaximumDepthInMeters'] }, - 'dcmaximumdistanceabovesurfaceinmeters' => { 112 => [\'dctermsLocation','dctermsLocationMaximumDistanceAboveSurfaceInMeters'] }, - 'dcmaximumelevationinmeters' => { 112 => [\'dctermsLocation','dctermsLocationMaximumElevationInMeters'] }, - 'dcminimumdepthinmeters' => { 112 => [\'dctermsLocation','dctermsLocationMinimumDepthInMeters'] }, - 'dcminimumdistanceabovesurfaceinmeters' => { 112 => [\'dctermsLocation','dctermsLocationMinimumDistanceAboveSurfaceInMeters'] }, - 'dcminimumelevationinmeters' => { 112 => [\'dctermsLocation','dctermsLocationMinimumElevationInMeters'] }, - 'dcmunicipality' => { 112 => [\'dctermsLocation','dctermsLocationMunicipality'] }, - 'dcpointradiusspatialfit' => { 112 => [\'dctermsLocation','dctermsLocationPointRadiusSpatialFit'] }, - 'dcstateprovince' => { 112 => [\'dctermsLocation','dctermsLocationStateProvince'] }, - 'dctermslocation' => { 112 => 'dctermsLocation' }, - 'dcverbatimcoordinates' => { 112 => [\'dctermsLocation','dctermsLocationVerbatimCoordinates'] }, - 'dcverbatimcoordinatesystem' => { 112 => [\'dctermsLocation','dctermsLocationVerbatimCoordinateSystem'] }, - 'dcverbatimdepth' => { 112 => [\'dctermsLocation','dctermsLocationVerbatimDepth'] }, - 'dcverbatimelevation' => { 112 => [\'dctermsLocation','dctermsLocationVerbatimElevation'] }, - 'dcverbatimlatitude' => { 112 => [\'dctermsLocation','dctermsLocationVerbatimLatitude'] }, - 'dcverbatimlocality' => { 112 => [\'dctermsLocation','dctermsLocationVerbatimLocality'] }, - 'dcverbatimlongitude' => { 112 => [\'dctermsLocation','dctermsLocationVerbatimLongitude'] }, - 'dcverbatimsrs' => { 112 => [\'dctermsLocation','dctermsLocationVerbatimSRS'] }, - 'dcwaterbody' => { 112 => [\'dctermsLocation','dctermsLocationWaterBody'] }, - 'declination' => { 156 => 'Declination' }, - 'decposition' => { 171 => 0x32 }, - 'defaultautogray' => { 442 => 'DefaultAutoGray' }, - 'defaultautotone' => { 442 => 'DefaultAutoTone' }, - 'defaultblackrender' => { 113 => 0xc7a6 }, - 'defaultcroporigin' => { 113 => 0xc61f }, - 'defaultcropsize' => { 113 => 0xc620 }, - 'defaulteraseoption' => { 78 => 0x813 }, - 'defaultscale' => { 113 => 0xc61e }, - 'defaultsspecifictoiso' => { 442 => 'DefaultsSpecificToISO' }, - 'defaultsspecifictoserial' => { 442 => 'DefaultsSpecificToSerial' }, - 'defaultusercrop' => { 113 => 0xc7b5 }, - 'defectisocode' => { 131 => 0x90f }, - 'defringe' => { 442 => 'Defringe' }, - 'defringegreenamount' => { 442 => 'DefringeGreenAmount' }, - 'defringegreenhuehi' => { 442 => 'DefringeGreenHueHi' }, - 'defringegreenhuelo' => { 442 => 'DefringeGreenHueLo' }, - 'defringepurpleamount' => { 442 => 'DefringePurpleAmount' }, - 'defringepurplehuehi' => { 442 => 'DefringePurpleHueHi' }, - 'defringepurplehuelo' => { 442 => 'DefringePurpleHueLo' }, - 'dehaze' => { 442 => 'Dehaze' }, - 'deletedimagecount' => { 211 => 0xa6, 219 => 0x6e }, - 'deprecatedon' => { 439 => 'deprecatedOn' }, - 'derivedfrom' => { 467 => 'DerivedFrom' }, - 'derivedfromalternatepaths' => { 467 => [\'DerivedFrom','DerivedFromAlternatePaths'] }, - 'derivedfromdocumentid' => { 467 => [\'DerivedFrom','DerivedFromDocumentID'] }, - 'derivedfromfilepath' => { 467 => [\'DerivedFrom','DerivedFromFilePath'] }, - 'derivedfromfrompart' => { 467 => [\'DerivedFrom','DerivedFromFromPart'] }, - 'derivedfrominstanceid' => { 467 => [\'DerivedFrom','DerivedFromInstanceID'] }, - 'derivedfromlastmodifydate' => { 467 => [\'DerivedFrom','DerivedFromLastModifyDate'] }, - 'derivedfromlasturl' => { 467 => [\'DerivedFrom','DerivedFromLastURL'] }, - 'derivedfromlinkcategory' => { 467 => [\'DerivedFrom','DerivedFromLinkCategory'] }, - 'derivedfromlinkform' => { 467 => [\'DerivedFrom','DerivedFromLinkForm'] }, - 'derivedfrommanager' => { 467 => [\'DerivedFrom','DerivedFromManager'] }, - 'derivedfrommanagervariant' => { 467 => [\'DerivedFrom','DerivedFromManagerVariant'] }, - 'derivedfrommanageto' => { 467 => [\'DerivedFrom','DerivedFromManageTo'] }, - 'derivedfrommanageui' => { 467 => [\'DerivedFrom','DerivedFromManageUI'] }, - 'derivedfrommaskmarkers' => { 467 => [\'DerivedFrom','DerivedFromMaskMarkers'] }, - 'derivedfromoriginaldocumentid' => { 467 => [\'DerivedFrom','DerivedFromOriginalDocumentID'] }, - 'derivedfrompartmapping' => { 467 => [\'DerivedFrom','DerivedFromPartMapping'] }, - 'derivedfromplacedresolutionunit' => { 467 => [\'DerivedFrom','DerivedFromPlacedResolutionUnit'] }, - 'derivedfromplacedxresolution' => { 467 => [\'DerivedFrom','DerivedFromPlacedXResolution'] }, - 'derivedfromplacedyresolution' => { 467 => [\'DerivedFrom','DerivedFromPlacedYResolution'] }, - 'derivedfromrenditionclass' => { 467 => [\'DerivedFrom','DerivedFromRenditionClass'] }, - 'derivedfromrenditionparams' => { 467 => [\'DerivedFrom','DerivedFromRenditionParams'] }, - 'derivedfromtopart' => { 467 => [\'DerivedFrom','DerivedFromToPart'] }, - 'derivedfromversionid' => { 467 => [\'DerivedFrom','DerivedFromVersionID'] }, - 'description' => { 287 => 'Description', 443 => 'description', 464 => 'Description' }, - 'destination' => { 126 => 0x5 }, - 'destinationcity' => { 332 => 0x24, 338 => 0x3 }, - 'destinationcitycode' => { 339 => 0x1001 }, - 'destinationdst' => { 332 => 0x26, 338 => '0.3' }, - 'developmentdynamicrange' => { 121 => 0x1403 }, - 'deviantmatrixcustom' => { 131 => 0x7de }, - 'deviantmatrixdaylight' => { 131 => 0x7da }, - 'deviantmatrixflash' => { 131 => 0x7dd }, - 'deviantmatrixfluorescent' => { 131 => 0x7dc }, - 'deviantmatrixtungsten' => { 131 => 0x7db }, - 'deviantwhitecustom' => { 131 => 0x842 }, - 'deviantwhitedaylight' => { 131 => 0x83e }, - 'deviantwhiteflash' => { 131 => 0x841 }, - 'deviantwhitefluorescent' => { 131 => 0x840 }, - 'deviantwhitetungsten' => { 131 => 0x83f }, - 'device' => { 456 => 'device' }, - 'devicesettingdescription' => { 446 => 'DeviceSettingDescription' }, - 'devicesettingdescriptioncolumns' => { 446 => [\'DeviceSettingDescription','DeviceSettingDescriptionColumns'] }, - 'devicesettingdescriptionrows' => { 446 => [\'DeviceSettingDescription','DeviceSettingDescriptionRows'] }, - 'devicesettingdescriptionsettings' => { 446 => [\'DeviceSettingDescription','DeviceSettingDescriptionSettings'] }, - 'devicetype' => { 365 => 0x2 }, - 'dialdirectiontvav' => { 78 => 0x706 }, - 'dietaryneeds' => { 458 => 'dietaryNeeds' }, - 'diffractioncorrection' => { 297 => 0xbc, 322 => 0x3 }, - 'diffractioncorrectionon' => { 97 => 0x2070b }, - 'digitalcreationdate' => { 125 => 0x3e }, - 'digitalcreationtime' => { 125 => 0x3f }, - 'digitaldeehighlightadj' => { 218 => 0x202 }, - 'digitaldeeshadowadj' => { 218 => 0x200 }, - 'digitaldeethreshold' => { 218 => 0x201 }, - 'digitalfilter' => { 368 => 0x59 }, - 'digitalfilter01' => { 319 => 0x5 }, - 'digitalfilter02' => { 319 => 0x16 }, - 'digitalfilter03' => { 319 => 0x27 }, - 'digitalfilter04' => { 319 => 0x38 }, - 'digitalfilter05' => { 319 => 0x49 }, - 'digitalfilter06' => { 319 => 0x5a }, - 'digitalfilter07' => { 319 => 0x6b }, - 'digitalfilter08' => { 319 => 0x7c }, - 'digitalfilter09' => { 319 => 0x8d }, - 'digitalfilter10' => { 319 => 0x9e }, - 'digitalfilter11' => { 319 => 0xaf }, - 'digitalfilter12' => { 319 => 0xc0 }, - 'digitalfilter13' => { 319 => 0xd1 }, - 'digitalfilter14' => { 319 => 0xe2 }, - 'digitalfilter15' => { 319 => 0xf3 }, - 'digitalfilter16' => { 319 => 0x104 }, - 'digitalfilter17' => { 319 => 0x115 }, - 'digitalfilter18' => { 319 => 0x126 }, - 'digitalfilter19' => { 319 => 0x137 }, - 'digitalfilter20' => { 319 => 0x148 }, - 'digitalgain' => { 70 => 0xb }, - 'digitalgem' => { 203 => 0x0 }, - 'digitalice' => { 218 => 0x100 }, - 'digitalimageguid' => { 452 => 'DigImageGUID' }, - 'digitalroc' => { 216 => 0x0 }, - 'digitalsourcefiletype' => { 452 => 'DigitalSourcefileType' }, - 'digitalsourcetype' => { 452 => 'DigitalSourceType' }, - 'digitalzoom' => { 33 => 0xc, 106 => 0xa, 121 => 0x1044, 133 => 0x68, 147 => 'DigitalZoom', 171 => 0xc, 211 => 0x86, 240 => 0xa, 279 => 0x204, 332 => 0x1e, 339 => 0xa, 367 => 0x204, 408 => 0x12, 409 => 0x12 }, - 'digitalzoomon' => { 367 => 0x21b }, - 'digitalzoomratio' => { 113 => 0xa404, 398 => 0x200, 400 => 0x21c, 446 => 'DigitalZoomRatio' }, - 'director' => { 466 => 'director' }, - 'directorphotography' => { 466 => 'directorPhotography' }, - 'directory' => { 114 => 'Directory' }, - 'directoryindex' => { 6 => 0x137, 8 => 0x2dc, 10 => 0x17e, 12 => 0x238, 13 => 0x13f, 14 => 0x133, 15 => 0x1df, 16 => 0x1a7, 17 => 0x1f0, 18 => 0xcc, 19 => 0x1c7, 20 => 0x298, 21 => 0x1e7, 22 => 0x1e5, 23 => [0x27c,0x280], 24 => 0x2b6, 25 => 0x2bf, 27 => 0x1f7, 28 => 0x4ba }, - 'directoryindex2' => { 20 => 0x29c }, - 'directorynumber' => { 197 => 0x3 }, - 'disclaimer' => { 287 => 'Disclaimer' }, - 'discnumber' => { 466 => 'discNumber' }, - 'dishtype' => { 458 => 'dishType' }, - 'displayallafpoints' => { 78 => 0x514 }, - 'displayaperture' => { 33 => 0x23 }, - 'displayedunitsx' => { 347 => 0x2 }, - 'displayedunitsy' => { 347 => 0x6 }, - 'displayname' => { 455 => 'displayName' }, - 'distance1' => { 133 => 0x28 }, - 'distance2' => { 133 => 0x2c }, - 'distance3' => { 133 => 0x30 }, - 'distance4' => { 133 => 0x34 }, - 'distortion' => { 365 => 0xa050 }, - 'distortioncompensation' => { 421 => 0x8040 }, - 'distortioncontrol' => { 219 => 0x10 }, - 'distortioncorrection' => { 97 => 0x20705, 103 => 0x67, 113 => 0x7036, 274 => 0x50b, 301 => '7.1', 322 => 0x0, 416 => 0x601, 417 => 0x5b }, - 'distortioncorrection2' => { 278 => 0x1011 }, - 'distortioncorrectionalreadyapplied' => { 438 => 'DistortionCorrectionAlreadyApplied' }, - 'distortioncorrectionon' => { 97 => '0x20705.0', 103 => 0x63 }, - 'distortioncorrectionsetting' => { 388 => 0x2013 }, - 'distortioncorrparams' => { 113 => 0x7037, 397 => 0x1a23, 400 => 0x1870, 402 => 0x189c, 403 => 0x18cc, 404 => 0x17d0, 416 => 0x6ca, 417 => 0x64 }, - 'distortioncorrparamsnumber' => { 400 => 0x1899, 402 => 0x18c5, 403 => 0x18f5, 404 => 0x17f9 }, - 'distortioncorrparamspresent' => { 400 => 0x1898, 402 => 0x18c4, 403 => 0x18f4, 404 => 0x17f8, 406 => 0x10b, 407 => 0x10b, 416 => 0x600, 417 => 0x5a }, - 'distortioneffect' => { 97 => 0x20709 }, - 'distortionn' => { 301 => 0xc }, - 'distortionparam02' => { 301 => 0x2 }, - 'distortionparam04' => { 301 => 0x4 }, - 'distortionparam08' => { 301 => 0x8 }, - 'distortionparam09' => { 301 => 0x9 }, - 'distortionparam11' => { 301 => 0xb }, - 'distortionscale' => { 301 => 0x5 }, - 'distributor' => { 456 => 'distributor' }, - 'distributorproductid' => { 455 => 'distributorProductID' }, - 'dloon' => { 97 => '0x20706.0', 103 => 0xdc }, - 'dlosetting' => { 97 => 0x20706, 103 => 0xdd }, - 'dlosettingapplied' => { 96 => 0x4 }, - 'dloshootingdistance' => { 103 => 0xde }, - 'dloversion' => { 96 => 0x5 }, - 'dmcomment' => { 466 => 'comment' }, - 'dmdithermatrix' => { 131 => 0xc7a }, - 'dmdithermatrixheight' => { 131 => 0xc7c }, - 'dmdithermatrixwidth' => { 131 => 0xc7b }, - 'dngadobedata' => { 113 => 0xc634 }, - 'dngbackwardversion' => { 113 => 0xc613 }, - 'dngignoresidecars' => { 442 => 'DNGIgnoreSidecars' }, - 'dnglensinfo' => { 113 => 0xc630 }, - 'dngprivatedata' => { 113 => 0xc634 }, - 'dngversion' => { 113 => 0xc612 }, - 'document' => { 287 => 'Document' }, - 'documentancestors' => { 454 => 'DocumentAncestors' }, - 'documenthistory' => { 125 => 0xe7 }, - 'documentid' => { 467 => 'DocumentID' }, - 'documentname' => { 113 => 0x10d }, - 'documentnotes' => { 125 => 0xe6 }, - 'doi' => { 456 => 'doi' }, - 'dopesheet' => { 452 => 'Dopesheet' }, - 'dopesheetlink' => { 452 => 'DopesheetLink' }, - 'dopesheetlinklink' => { 452 => [\'DopesheetLink','DopesheetLinkLink'] }, - 'dopesheetlinklinkqualifier' => { 452 => [\'DopesheetLink','DopesheetLinkLinkQualifier'] }, - 'doublingmicrovolts' => { 131 => 0xc82 }, - 'dpp' => { 436 => 'dpp' }, - 'dr4cameramodel' => { 98 => 0x3 }, - 'drangepriority' => { 121 => 0x1443 }, - 'drangepriorityauto' => { 121 => 0x1444 }, - 'drangepriorityfixed' => { 121 => 0x1445 }, - 'drivemode' => { 107 => 0x3103, 119 => '0.1', 171 => 0x6, 174 => 0x1e, 177 => 0xe, 274 => 0x600, 332 => 0x34, 358 => 0x1002, 368 => 0x3, 376 => 0x4, 377 => 0x7e, 378 => 0x34 }, - 'drivemode2' => { 174 => 0xa, 313 => 0x7, 387 => 0xe, 393 => 0x1 }, - 'drivemodesetting' => { 378 => 0x4 }, - 'drivespeed' => { 119 => '0.2' }, - 'dspfirmwareversion' => { 332 => 0x27 }, - 'duration' => { 63 => 0x6a, 146 => 'Duration', 160 => 'Duration', 458 => 'duration', 466 => 'duration' }, - 'durationscale' => { 466 => [\'duration','durationScale'] }, - 'durationvalue' => { 466 => [\'duration','durationValue'] }, - 'dustremovaldata' => { 60 => 0x97 }, - 'dynamicafarea' => { 257 => '1.4', 266 => '1.4' }, - 'dynamicareaafdisplay' => { 258 => '46.1', 260 => '47.1', 261 => '47.1', 270 => '47.1', 271 => '47.1' }, - 'dynamicrange' => { 121 => 0x1400 }, - 'dynamicrangeexpansion' => { 332 => 0x69, 358 => 0x100e }, - 'dynamicrangemax' => { 102 => 0x7c }, - 'dynamicrangemin' => { 102 => 0x7a }, - 'dynamicrangeoptimizer' => { 174 => 0x15, 388 => [0xb025,0xb04f], 396 => 0x1144, 397 => [0x1144,0x324], 398 => [0x1120,0x300], 399 => [0x119c,0x37c], 400 => [0x1178,0x328], 401 => [0x1030,0x50], 402 => [0x228,0x50], 403 => [0x228,0x50], 404 => [0x21b,0x4e] }, - 'dynamicrangeoptimizerbracket' => { 387 => 0x2e }, - 'dynamicrangeoptimizerlevel' => { 376 => 0x19, 377 => 0x17, 378 => 0xd, 387 => 0x79, 393 => 0x5 }, - 'dynamicrangeoptimizermode' => { 177 => 0x15, 376 => 0x18, 377 => 0x16, 387 => [0x77,0x15] }, - 'dynamicrangeoptimizersetting' => { 174 => 0x27, 378 => 0xc, 393 => 0x4 }, - 'dynamicrangesetting' => { 121 => 0x1402 }, - 'e-dialinprogram' => { 313 => '1.3' }, - 'earliestageorloweststage' => { 112 => [\'GeologicalContext','GeologicalContextEarliestAgeOrLowestStage'] }, - 'earliesteonorlowesteonothem' => { 112 => [\'GeologicalContext','GeologicalContextEarliestEonOrLowestEonothem'] }, - 'earliestepochorlowestseries' => { 112 => [\'GeologicalContext','GeologicalContextEarliestEpochOrLowestSeries'] }, - 'earliesteraorlowesterathem' => { 112 => [\'GeologicalContext','GeologicalContextEarliestEraOrLowestErathem'] }, - 'earliestperiodorlowestsystem' => { 112 => [\'GeologicalContext','GeologicalContextEarliestPeriodOrLowestSystem'] }, - 'easyexposurecomp' => { 272 => '6.1' }, - 'easyexposurecompensation' => { 257 => '6.4', 258 => '6.5', 260 => '6.3', 261 => '6.3', 265 => '5.1', 266 => '4.4', 267 => '5.2', 270 => '6.3', 271 => '6.3' }, - 'easymode' => { 33 => 0xb }, - 'edgemapslope' => { 131 => 0x930 }, - 'edgemapx1' => { 131 => 0x931 }, - 'edgemapx2' => { 131 => 0x932 }, - 'edgemapx3' => { 131 => 0x934 }, - 'edgemapx4' => { 131 => 0x935 }, - 'edgenoisereduction' => { 251 => 0x4, 421 => 0x8028 }, - 'edition' => { 456 => 'edition' }, - 'editorialupdate' => { 125 => 0x8 }, - 'editstatus' => { 125 => 0x7, 344 => 'EditStatus', 436 => 'EditStatus' }, - 'editversionname' => { 250 => 0x3d136244 }, - 'effectivelv' => { 332 => 0x2d }, - 'effectivemaxaperture' => { 207 => 0x12, 208 => 0x13 }, - 'eissn' => { 456 => 'eIssn' }, - 'electricalblackcolumns' => { 131 => 0x1810 }, - 'electronicfront-curtainshutter' => { 260 => '5.2', 261 => '5.2', 270 => '5.3', 271 => '5.2' }, - 'electronicfrontcurtainshutter' => { 388 => 0x201a }, - 'elevation' => { 156 => 'Elevation' }, - 'email' => { 148 => 'EMail' }, - 'embargodate' => { 459 => 'embargoDate' }, - 'embdencrightsexpr' => { 452 => 'EmbdEncRightsExpr' }, - 'embeddedencodedrightsexpr' => { 452 => [\'EmbdEncRightsExpr','EmbdEncRightsExprEncRightsExpr'] }, - 'embeddedencodedrightsexprlangid' => { 452 => [\'EmbdEncRightsExpr','EmbdEncRightsExprRightsExprLangId'] }, - 'embeddedencodedrightsexprtype' => { 452 => [\'EmbdEncRightsExpr','EmbdEncRightsExprRightsExprEncType'] }, - 'embeddedxmpdigest' => { 454 => 'EmbeddedXMPDigest' }, - 'emissivity' => { 115 => 0x3 }, - 'enablechromanoisereduction' => { 131 => 0xe6e }, - 'enablesharpening' => { 131 => 0x92e }, - 'encryptionkey' => { 365 => 0xa020 }, - 'endingpage' => { 456 => 'endingPage' }, - 'enduser' => { 284 => 'EndUser' }, - 'enduserid' => { 284 => [\'EndUser','EndUserEndUserID'] }, - 'endusername' => { 284 => [\'EndUser','EndUserEndUserName'] }, - 'engineer' => { 466 => 'engineer' }, - 'enhancedarktones' => { 243 => 0x8 }, - 'enhancement' => { 106 => 0x16, 107 => 0x3016 }, - 'enhancer' => { 278 => 0x300 }, - 'enhancervalues' => { 278 => 0x301 }, - 'envelopenumber' => { 126 => 0x28 }, - 'envelopepriority' => { 126 => 0x3c }, - 'enveloperecordversion' => { 126 => 0x0 }, - 'episode' => { 452 => 'Episode' }, - 'episodeidentifier' => { 452 => [\'Episode','EpisodeIdentifier'] }, - 'episodename' => { 452 => [\'Episode','EpisodeName'] }, - 'episodenumber' => { 452 => [\'Episode','EpisodeNumber'] }, - 'epsonimageheight' => { 279 => 0x20c }, - 'epsonimagewidth' => { 279 => 0x20b }, - 'epsonsoftware' => { 279 => 0x20d }, - 'equipmentinstitution' => { 423 => 'EquipmentInstitution' }, - 'equipmentmanufacturer' => { 423 => 'EquipmentManufacturer' }, - 'equipmentversion' => { 275 => 0x0 }, - 'ettlii' => { 78 => 0x304, 79 => 0xd, 80 => 0xe, 81 => 0x7, 82 => 0x7, 83 => 0xe }, - 'event' => { 424 => 'Event', 434 => 'Event', 452 => 'Event', 456 => 'event' }, - 'eventalias' => { 455 => 'eventAlias' }, - 'eventdate' => { 112 => [\'Event','EventEventDate'] }, - 'eventday' => { 112 => [\'Event','EventDay'] }, - 'eventearliestdate' => { 112 => [\'Event','EventEarliestDate'] }, - 'eventend' => { 455 => 'eventEnd' }, - 'eventenddayofyear' => { 112 => [\'Event','EventEndDayOfYear'] }, - 'eventfieldnotes' => { 112 => [\'Event','EventFieldNotes'] }, - 'eventfieldnumber' => { 112 => [\'Event','EventFieldNumber'] }, - 'eventhabitat' => { 112 => [\'Event','EventHabitat'] }, - 'eventid' => { 112 => [\'Event','EventEventID'] }, - 'eventlatestdate' => { 112 => [\'Event','EventLatestDate'] }, - 'eventmonth' => { 112 => [\'Event','EventMonth'] }, - 'eventnumber' => { 353 => 0x9, 354 => 0x37 }, - 'eventparenteventid' => { 112 => [\'Event','EventParentEventID'] }, - 'eventremarks' => { 112 => [\'Event','EventEventRemarks'] }, - 'eventsamplesizeunit' => { 112 => [\'Event','EventSampleSizeUnit'] }, - 'eventsamplesizevalue' => { 112 => [\'Event','EventSampleSizeValue'] }, - 'eventsamplingeffort' => { 112 => [\'Event','EventSamplingEffort'] }, - 'eventsamplingprotocol' => { 112 => [\'Event','EventSamplingProtocol'] }, - 'eventstart' => { 455 => 'eventStart' }, - 'eventstartdayofyear' => { 112 => [\'Event','EventStartDayOfYear'] }, - 'eventsubtype' => { 455 => 'eventSubtype' }, - 'eventtime' => { 112 => [\'Event','EventEventTime'] }, - 'eventtype' => { 455 => 'eventType' }, - 'eventverbatimeventdate' => { 112 => [\'Event','EventVerbatimEventDate'] }, - 'eventyear' => { 112 => [\'Event','EventYear'] }, - 'evsteps' => { 313 => '1.2', 315 => 0x0 }, - 'evstepsize' => { 262 => '5.1', 263 => '6.1', 264 => '6.1', 268 => '0.7' }, - 'exclusivecoverage' => { 431 => 'ExclusiveCoverage' }, - 'exclusivityenddate' => { 459 => 'exclusivityEndDate' }, - 'excursiontolerance' => { 127 => 0x82 }, - 'exif' => { 114 => 'EXIF' }, - 'exifbyteorder' => { 114 => 'ExifByteOrder' }, - 'exifcamerainfo' => { 125 => 0xe8 }, - 'exifimageheight' => { 113 => 0xa003, 446 => 'PixelYDimension' }, - 'exifimagewidth' => { 113 => 0xa002, 446 => 'PixelXDimension' }, - 'exifunicodebyteorder' => { 114 => 'ExifUnicodeByteOrder' }, - 'exifversion' => { 113 => 0x9000, 446 => 'ExifVersion' }, - 'exitpupilposition' => { 207 => 0x4, 208 => 0x4 }, - 'expirationdate' => { 125 => 0x25, 459 => 'expirationDate' }, - 'expirationtime' => { 125 => 0x26 }, - 'exposure' => { 113 => 0xfe51, 442 => 'Exposure' }, - 'exposure2012' => { 442 => 'Exposure2012' }, - 'exposureadj' => { 248 => 0x0 }, - 'exposureadj2' => { 248 => 0x12 }, - 'exposureadjust' => { 368 => 0xc }, - 'exposurebracketingindicatorlast' => { 174 => 0x52 }, - 'exposurebracketshotnumber' => { 177 => 0x2d, 387 => 0x2f }, - 'exposurebracketstepsize' => { 313 => 0x8 }, - 'exposurebracketvalue' => { 211 => 0x19 }, - 'exposurecompautocancel' => { 78 => 0x113 }, - 'exposurecompensation' => { 72 => 0x6, 87 => 0x0, 113 => 0x9204, 133 => 0x24, 147 => 'ExposureComp', 167 => 'ExposureCompensation', 171 => 0xd, 172 => 0x53, 173 => 0x1e, 177 => 0x49c0, 279 => 0x1006, 332 => 0x16, 341 => 0x402, 365 => 0xa013, 368 => [0xc,0x35,0x4d], 396 => 0x114c, 397 => 0x114c, 398 => 0x1128, 400 => 0x1180, 401 => 0x1038, 402 => 0x230, 403 => 0x230, 404 => 0x223, 446 => 'ExposureBiasValue' }, - 'exposurecompensation2' => { 393 => [0x24,0x26,0x2a] }, - 'exposurecompensationmode' => { 174 => 0x47, 177 => 0x2a }, - 'exposurecompensationset' => { 376 => 0x3, 377 => 0x3, 378 => 0x3, 393 => 0x1e }, - 'exposurecompensationsetting' => { 174 => 0x1 }, - 'exposurecompstepsize' => { 257 => '6.3', 258 => '7.3', 260 => '7.3', 261 => '7.3', 266 => '4.3', 270 => '7.3', 271 => '7.3' }, - 'exposurecontrolstep' => { 265 => '6.1', 267 => '6.1' }, - 'exposurecontrolstepsize' => { 257 => '6.2', 258 => '7.1', 260 => '7.1', 261 => '7.1', 266 => '4.2', 270 => '7.1', 271 => '7.1', 272 => '7.1' }, - 'exposurecount' => { 121 => 0x1032 }, - 'exposuredelaymode' => { 257 => '10.1', 258 => '11.1', 260 => '11.1', 261 => '11.1', 262 => '9.1', 263 => '10.1', 264 => '10.1', 266 => '10.4', 267 => '10.1', 268 => '6.4', 270 => '11.1', 271 => '11.1', 272 => '11.2' }, - 'exposuredifference' => { 211 => 0xe }, - 'exposuregaincustom' => { 131 => 0x89c }, - 'exposuregaindaylight' => { 131 => 0x898 }, - 'exposuregainflash' => { 131 => 0x89b }, - 'exposuregainfluorescent' => { 131 => 0x89a }, - 'exposuregaintungsten' => { 131 => 0x899 }, - 'exposureindex' => { 113 => 0xa215, 446 => 'ExposureIndex' }, - 'exposureindicator' => { 174 => 0x50 }, - 'exposurelevelincrements' => { 76 => 0x6, 77 => 0x6, 78 => 0x101, 79 => 0x5, 80 => 0x6, 81 => 0x5, 82 => 0x5, 83 => 0x6, 84 => 0x4, 376 => 0x58, 377 => 0x58 }, - 'exposurelockused' => { 429 => 'ExposureLockUsed' }, - 'exposuremode' => { 113 => 0xa402, 147 => 'ExposureMode', 171 => 0x1, 172 => 0xa, 173 => 0x0, 174 => 0x0, 177 => 0x34, 274 => 0x200, 294 => 0x40d, 368 => 0x8, 388 => 0xb041, 446 => 'ExposureMode' }, - 'exposuremodeinmanual' => { 78 => 0x10b }, - 'exposureprogram' => { 113 => 0x8822, 358 => 0x1001, 369 => [0x17e,0x43], 376 => 0x3c, 377 => 0x3c, 378 => 0x5, 382 => 0x14, 387 => 0x3f, 393 => 0x2, 396 => 0x1175, 397 => 0x1179, 398 => 0x1155, 399 => 0x11d1, 400 => 0x11ad, 401 => 0x1065, 402 => 0x25d, 403 => 0x25d, 404 => 0x24c, 413 => 0xb, 414 => 0xc, 415 => 0xb, 417 => 0x48, 446 => 'ExposureProgram' }, - 'exposureshift' => { 274 => 0x203 }, - 'exposurestandardadjustment' => { 388 => 0x202d }, - 'exposuretime' => { 6 => 0x4, 7 => 0x4, 8 => 0x4, 9 => 0x4, 10 => 0x4, 11 => 0x4, 12 => 0x4, 13 => 0x4, 14 => 0x4, 15 => 0x4, 16 => 0x4, 17 => 0x4, 18 => 0x4, 19 => 0x4, 20 => 0x4, 21 => 0x4, 22 => 0x4, 23 => 0x4, 24 => 0x4, 25 => 0x4, 26 => 0x4, 27 => 0x4, 28 => 0x4, 29 => 0x6, 30 => 0x7, 72 => 0x16, 113 => 0x829a, 130 => 0xfd05, 133 => 0x20, 135 => 0xfa24, 137 => 0xf104, 140 => 0x12, 142 => 0x38, 145 => 0x10, 147 => 'ExposureTime', 171 => 0x9, 172 => 0x35, 173 => 0x48, 174 => 0x8, 177 => 0x49b8, 332 => 0x12, 365 => 0xa018, 368 => [0x32,0x4a], 376 => 0x0, 377 => 0x0, 393 => [0x21,0x23,0x27], 417 => 0x10, 446 => 'ExposureTime' }, - 'exposuretime2' => { 368 => [0x33,0x4b] }, - 'exposuretuning' => { 211 => 0x1c }, - 'exposurevalue' => { 131 => 0x3 }, - 'exposurewarning' => { 121 => 0x1302 }, - 'exrauto' => { 121 => 0x1033 }, - 'exrmode' => { 121 => 0x1034 }, - 'extendedwbdetect' => { 274 => 0x902 }, - 'extender' => { 275 => 0x301 }, - 'extenderfirmwareversion' => { 275 => 0x304 }, - 'extendermagnification' => { 149 => 'Magnification' }, - 'extendermake' => { 149 => 'Make' }, - 'extendermodel' => { 149 => 'Model', 275 => 0x303 }, - 'extenderserialnumber' => { 149 => 'SerialNumber', 275 => 0x302 }, - 'extenderstatus' => { 330 => 0x3 }, - 'externalflash' => { 277 => 0x1201 }, - 'externalflashae1' => { 279 => 0x101f }, - 'externalflashae1_0' => { 279 => 0x101b }, - 'externalflashae2' => { 279 => 0x1020 }, - 'externalflashae2_0' => { 279 => 0x101c }, - 'externalflashbounce' => { 277 => 0x1204, 279 => 0x1026, 320 => 0x1a }, - 'externalflashcompensation' => { 200 => 0x1b }, - 'externalflashexposurecomp' => { 211 => 0x17, 320 => 0x19 }, - 'externalflashfirmware' => { 198 => 0x6, 199 => 0x6, 200 => 0x6, 201 => 0x6, 202 => 0x6 }, - 'externalflashflags' => { 198 => 0x8, 199 => 0x8, 200 => 0x8, 201 => 0x8 }, - 'externalflashguidenumber' => { 277 => 0x1203, 320 => '24.1' }, - 'externalflashgvalue' => { 279 => 0x1025 }, - 'externalflashmode' => { 279 => 0x1028, 320 => 0x2 }, - 'externalflashreadystate' => { 202 => '9.1' }, - 'externalflashstatus' => { 202 => '8.2' }, - 'externalflashzoom' => { 277 => 0x1205, 279 => 0x1027 }, - 'externalflashzoomoverride' => { 202 => '8.1' }, - 'externalmetadatalink' => { 452 => 'ExternalMetadataLink' }, - 'externalsensorbrightnessvalue' => { 292 => 0x311, 295 => 0x311, 296 => 0x311, 299 => 0x3408 }, - 'extrainfoversion' => { 380 => 0x1a }, - 'eyestartaf' => { 174 => 0x40 }, - 'fac100per' => { 131 => 0xe94 }, - 'fac170per' => { 131 => 0xe93 }, - 'fac18per' => { 131 => 0xe92 }, - 'face10position' => { 104 => 0x3f4, 105 => 0x1ec, 196 => 0x28, 317 => 0x12 }, - 'face10size' => { 318 => 0x12 }, - 'face11position' => { 196 => 0x2c, 317 => 0x14 }, - 'face11size' => { 318 => 0x14 }, - 'face12position' => { 196 => 0x30, 317 => 0x16 }, - 'face12size' => { 318 => 0x16 }, - 'face13position' => { 317 => 0x18 }, - 'face13size' => { 318 => 0x18 }, - 'face14position' => { 317 => 0x1a }, - 'face14size' => { 318 => 0x1a }, - 'face15position' => { 317 => 0x1c }, - 'face15size' => { 318 => 0x1c }, - 'face16position' => { 317 => 0x1e }, - 'face16size' => { 318 => 0x1e }, - 'face17position' => { 317 => 0x20 }, - 'face17size' => { 318 => 0x20 }, - 'face18position' => { 317 => 0x22 }, - 'face18size' => { 318 => 0x22 }, - 'face19position' => { 317 => 0x24 }, - 'face19size' => { 318 => 0x24 }, - 'face1position' => { 51 => 0x8, 104 => 0xd, 105 => 0x18, 196 => 0x4, 289 => 0x1, 317 => 0x0, 355 => 0xbc, 383 => 0x1, 384 => 0x0, 385 => 0x0, 386 => 0x5b }, - 'face1size' => { 318 => 0x0 }, - 'face20position' => { 317 => 0x26 }, - 'face20size' => { 318 => 0x26 }, - 'face21position' => { 317 => 0x28 }, - 'face21size' => { 318 => 0x28 }, - 'face22position' => { 317 => 0x2a }, - 'face22size' => { 318 => 0x2a }, - 'face23position' => { 317 => 0x2c }, - 'face23size' => { 318 => 0x2c }, - 'face24position' => { 317 => 0x2e }, - 'face24size' => { 318 => 0x2e }, - 'face25position' => { 317 => 0x30 }, - 'face25size' => { 318 => 0x30 }, - 'face26position' => { 317 => 0x32 }, - 'face26size' => { 318 => 0x32 }, - 'face27position' => { 317 => 0x34 }, - 'face27size' => { 318 => 0x34 }, - 'face28position' => { 317 => 0x36 }, - 'face28size' => { 318 => 0x36 }, - 'face29position' => { 317 => 0x38 }, - 'face29size' => { 318 => 0x38 }, - 'face2position' => { 51 => 0xa, 104 => 0x7c, 105 => 0x4c, 196 => 0x8, 289 => 0x5, 317 => 0x2, 355 => 0xc8, 383 => 0x6, 384 => 0x20, 385 => 0x25, 386 => 0x65 }, - 'face2size' => { 318 => 0x2 }, - 'face30position' => { 317 => 0x3a }, - 'face30size' => { 318 => 0x3a }, - 'face31position' => { 317 => 0x3c }, - 'face31size' => { 318 => 0x3c }, - 'face32position' => { 317 => 0x3e }, - 'face32size' => { 318 => 0x3e }, - 'face3position' => { 51 => 0xc, 104 => 0xeb, 105 => 0x80, 196 => 0xc, 289 => 0x9, 317 => 0x4, 355 => 0xd4, 383 => 0xb, 384 => 0x40, 385 => 0x4a, 386 => 0x6f }, - 'face3size' => { 318 => 0x4 }, - 'face4position' => { 51 => 0xe, 104 => 0x15a, 105 => 0xb4, 196 => 0x10, 289 => 0xd, 317 => 0x6, 355 => 0xe0, 383 => 0x10, 384 => 0x60, 385 => 0x6f, 386 => 0x79 }, - 'face4size' => { 318 => 0x6 }, - 'face5position' => { 51 => 0x10, 104 => 0x1c9, 105 => 0xe8, 196 => 0x14, 289 => 0x11, 317 => 0x8, 355 => 0xec, 383 => 0x15, 384 => 0x80, 385 => 0x94 }, - 'face5size' => { 318 => 0x8 }, - 'face6position' => { 51 => 0x12, 104 => 0x238, 105 => 0x11c, 196 => 0x18, 317 => 0xa, 355 => 0xf8, 383 => 0x1a, 384 => 0xa0, 385 => 0xb9 }, - 'face6size' => { 318 => 0xa }, - 'face7position' => { 51 => 0x14, 104 => 0x2a7, 105 => 0x150, 196 => 0x1c, 317 => 0xc, 355 => 0x104, 383 => 0x1f, 384 => 0xc0, 385 => 0xde }, - 'face7size' => { 318 => 0xc }, - 'face8position' => { 51 => 0x16, 104 => 0x316, 105 => 0x184, 196 => 0x20, 317 => 0xe, 355 => 0x110, 383 => 0x24, 384 => 0xe0, 385 => 0x103 }, - 'face8size' => { 318 => 0xe }, - 'face9position' => { 51 => 0x18, 104 => 0x385, 105 => 0x1b8, 196 => 0x24, 317 => 0x10 }, - 'face9size' => { 318 => 0x10 }, - 'facebalanceorigi' => { 435 => 'FaceBalanceOrigI' }, - 'facebalanceorigq' => { 435 => 'FaceBalanceOrigQ' }, - 'facebalancestrength' => { 435 => 'FaceBalanceStrength' }, - 'facebalancewarmth' => { 435 => 'FaceBalanceWarmth' }, - 'facedetect' => { 332 => 0x76, 365 => 0x100 }, - 'facedetectarea' => { 278 => 0x1201 }, - 'facedetectframecrop' => { 278 => 0x1207 }, - 'facedetectframesize' => { 51 => 0x3, 104 => 0x1, 105 => 0x4, 196 => 0x1, 278 => 0x1203, 332 => 0x77, 355 => 0xb6 }, - 'facedetection' => { 378 => 0x30, 393 => 0x19 }, - 'faceelementpositions' => { 121 => 0x4203 }, - 'faceelementtypes' => { 121 => 0x4201 }, - 'faceid' => { 437 => 'FaceID' }, - 'faceinfounknown' => { 107 => 0x2089 }, - 'facename' => { 365 => 0x123 }, - 'faceorientation' => { 105 => 0x8 }, - 'faceposition' => { 316 => 0x2, 366 => 0x4 }, - 'facepositions' => { 121 => 0x4103 }, - 'facerecognition' => { 365 => 0x120 }, - 'facesdetected' => { 51 => 0x2, 52 => 0x2, 53 => 0x3, 104 => 0x0, 105 => 0x2, 107 => 0x211c, 121 => 0x4100, 196 => 0x3, 278 => 0x1200, 297 => 0x3f, 316 => 0x0, 355 => 0xb5, 366 => 0x0, 383 => 0x0, 386 => 0x3, 395 => 0x30 }, - 'facesrecognized' => { 290 => 0x0 }, - 'facewidth' => { 52 => 0x1 }, - 'faithfuloutputhighlightpoint' => { 103 => 0x38 }, - 'faithfuloutputshadowpoint' => { 103 => 0x39 }, - 'faithfulrawcolortone' => { 103 => 0x31 }, - 'faithfulrawcontrast' => { 103 => 0x33 }, - 'faithfulrawhighlight' => { 103 => 0x79 }, - 'faithfulrawhighlightpoint' => { 103 => 0x36 }, - 'faithfulrawlinear' => { 103 => 0x34 }, - 'faithfulrawsaturation' => { 103 => 0x32 }, - 'faithfulrawshadow' => { 103 => 0x82 }, - 'faithfulrawshadowpoint' => { 103 => 0x37 }, - 'faithfulrawsharpness' => { 103 => 0x35 }, - 'faithfulunsharpmaskfineness' => { 103 => 0xac }, - 'faithfulunsharpmaskstrength' => { 103 => 0xaa }, - 'faithfulunsharpmaskthreshold' => { 103 => 0xae }, - 'far' => { 426 => 'Far' }, - 'fastresetlinetime' => { 131 => 0x1860 }, - 'feedidentifier' => { 452 => 'FeedIdentifier' }, - 'femicroadjustment' => { 78 => 0x111 }, - 'ffid' => { 444 => 'ffid' }, - 'field' => { 455 => 'field' }, - 'fieldcount' => { 279 => 0x103f }, - 'fifoenonepixeldelay' => { 131 => 0x1901 }, - 'filecreatedate' => { 114 => 'FileCreateDate' }, - 'filedatarate' => { 466 => 'fileDataRate' }, - 'fileformat' => { 89 => 0x0, 126 => 0x14, 368 => [0x22,0x26], 388 => 0xb000 }, - 'filegroupid' => { 114 => 'FileGroupID' }, - 'fileindex' => { 6 => 0x143, 8 => 0x2d0, 10 => 0x172, 12 => 0x22c, 13 => 0x133, 14 => 0x13f, 15 => 0x1d3, 16 => 0x19b, 17 => 0x1e4, 18 => 0xd0, 19 => 0x1bb, 20 => 0x28c, 21 => 0x1db, 22 => 0x1d9, 23 => [0x270,0x274], 24 => 0x2aa, 25 => 0x2b3, 27 => 0x1eb, 28 => 0x4ae, 298 => 0x0 }, - 'fileindex2' => { 20 => 0x290 }, - 'filemodifydate' => { 114 => 'FileModifyDate' }, - 'filename' => { 114 => 'FileName' }, - 'filenameasdelivered' => { 284 => 'FileNameAsDelivered' }, - 'filenumber' => { 54 => 0x1, 60 => 0x8, 91 => 0x1817, 108 => 'FileNumber', 197 => 0x4 }, - 'filenumbermemory' => { 171 => 0x1a }, - 'filenumbersequence' => { 257 => '12.2', 262 => '3.1', 263 => '4.1', 264 => '4.1', 266 => '11.1', 267 => '4.3', 272 => '5.2' }, - 'filepermissions' => { 114 => 'FilePermissions' }, - 'filesource' => { 113 => 0xa300, 121 => 0x8000, 446 => 'FileSource' }, - 'fileuserid' => { 114 => 'FileUserID' }, - 'fileversion' => { 126 => 0x16 }, - 'fillflashautoreduction' => { 76 => 0xe, 77 => 0xe, 84 => 0xa }, - 'filllight' => { 442 => 'FillLight' }, - 'fillorder' => { 113 => 0x10a }, - 'filmgraineffect' => { 274 => 0x538 }, - 'filmmode' => { 121 => 0x1401, 294 => 0x412, 297 => 0x42 }, - 'filmtype' => { 218 => 0x2 }, - 'filtereffect' => { 54 => 0xe, 213 => 0x37, 214 => 0x3f }, - 'filtereffectauto' => { 67 => 0xa0 }, - 'filtereffectfaithful' => { 66 => 0x70, 67 => 0x70 }, - 'filtereffectlandscape' => { 66 => 0x40, 67 => 0x40 }, - 'filtereffectmonochrome' => { 18 => 0xff, 66 => 0x88, 67 => 0x88 }, - 'filtereffectneutral' => { 66 => 0x58, 67 => 0x58 }, - 'filtereffectportrait' => { 66 => 0x28, 67 => 0x28 }, - 'filtereffectstandard' => { 66 => 0x10, 67 => 0x10 }, - 'filtereffectuserdef1' => { 66 => 0xa0, 67 => 0xb8 }, - 'filtereffectuserdef2' => { 66 => 0xb8, 67 => 0xd0 }, - 'filtereffectuserdef3' => { 66 => 0xd0, 67 => 0xe8 }, - 'finderdisplayduringexposure' => { 77 => 0x1 }, - 'finesharpness' => { 332 => 0x70 }, - 'finetuneoptcenterweighted' => { 257 => '7.2', 258 => '9.1', 260 => '9.1', 261 => '9.1', 265 => '8.1', 270 => '9.1', 271 => '9.1', 272 => '9.1' }, - 'finetuneopthighlightweighted' => { 260 => '46.1', 261 => '46.1', 270 => '46.1', 271 => '46.1' }, - 'finetuneoptmatrixmetering' => { 257 => '8.1', 258 => '8.2', 260 => '8.2', 261 => '8.2', 265 => '7.2', 266 => '6.1', 270 => '8.2', 271 => '8.2', 272 => '8.2' }, - 'finetuneoptspotmetering' => { 257 => '8.2', 258 => '9.2', 260 => '9.2', 261 => '9.2', 265 => '8.2', 266 => '6.2', 270 => '9.2', 271 => '9.2', 272 => '9.2' }, - 'finishexposure' => { 131 => 0xdbd }, - 'finishfiletype' => { 131 => 0xdb8 }, - 'finishlook' => { 131 => 0xdbc }, - 'finishnoise' => { 131 => 0xdba }, - 'finishresolution' => { 131 => 0xdb9 }, - 'finishsharpening' => { 131 => 0xdbb }, - 'firmware' => { 279 => 0x405, 368 => [0x17,0x3b,0x57], 438 => 'Firmware' }, - 'firmwaredate' => { 106 => 0x15, 107 => 0x2001, 353 => 0x4 }, - 'firmwareid' => { 178 => 0x0 }, - 'firmwarename' => { 365 => 0xa001 }, - 'firmwarerevision' => { 18 => 0xa4, 60 => 0x1e, 356 => 0x0 }, - 'firmwarerevision2' => { 356 => 0xc }, - 'firmwareversion' => { 6 => 0x10b, 10 => 0x136, 13 => 0xff, 14 => 0x107, 131 => [0x415,0xce5], 145 => 0x57, 147 => 'FirmwareVersion', 295 => 0x320, 297 => 0x2, 299 => 0x3109, 332 => 0x230, 354 => 0x18, 358 => 0x2 }, - 'firmwareversions' => { 341 => 0x301 }, - 'firstphotodate' => { 429 => 'FirstPhotoDate' }, - 'firstpublicationdate' => { 284 => 'FirstPublicationDate' }, - 'fixtureidentifier' => { 125 => 0x16, 436 => 'FixtureIdentifier' }, - 'flash' => { 108 => 'Flash', 113 => 0x9209, 172 => 0x1f, 173 => 0x15, 446 => 'Flash' }, - 'flashaction' => { 376 => 0x3e, 377 => 0x3e, 388 => 0x2017, 393 => [0x2a,0x2c,0x30] }, - 'flashaction2' => { 376 => 0x4c, 377 => 0x4c, 393 => 0x77 }, - 'flashactionexternal' => { 393 => [0x78,0x7c] }, - 'flashactivity' => { 33 => 0x1c }, - 'flashbatterylevel' => { 41 => 0x249 }, - 'flashbias' => { 297 => 0x24 }, - 'flashbits' => { 33 => 0x1d }, - 'flashbuttonfunction' => { 78 => 0x70e }, - 'flashchargelevel' => { 279 => 0x1010 }, - 'flashcolorfilter' => { 200 => 0x10, 201 => 0x10 }, - 'flashcommandermode' => { 198 => '9.1', 199 => '9.1', 200 => '9.1', 201 => '9.1' }, - 'flashcompensation' => { 131 => 0x3f3, 198 => 0xa, 199 => 0xa, 200 => 0xa, 201 => 0x27, 202 => 0xa, 438 => 'FlashCompensation' }, - 'flashcontrol' => { 376 => 0x23, 377 => 0x1f, 378 => 0x21 }, - 'flashcontrolbuilt-in' => { 266 => '16.1', 267 => '23.1', 269 => '23.1', 270 => '24.1' }, - 'flashcontrolmode' => { 198 => '9.2', 199 => '9.2', 200 => '9.2', 201 => '9.2', 274 => 0x404 }, - 'flashcurtain' => { 297 => 0x48 }, - 'flashdefault' => { 174 => 0x42 }, - 'flashdevice' => { 279 => 0x1005 }, - 'flashdistance' => { 107 => 0x2034 }, - 'flashenergy' => { 113 => 0xa20b, 446 => 'FlashEnergy' }, - 'flashexposurebracketvalue' => { 211 => 0x18 }, - 'flashexposurecomp' => { 72 => 0xf, 121 => 0x1011, 150 => 'ExposureComp', 171 => 0x23, 176 => 0x104, 177 => 0x49c1, 211 => 0x12, 274 => 0x401, 279 => 0x1023, 332 => 0x4d, 358 => 0x100b, 368 => [0x3a,0x56], 388 => 0x104 }, - 'flashexposurecomp2' => { 236 => 0x4d2 }, - 'flashexposurecomp3' => { 200 => 0x1d }, - 'flashexposurecomp4' => { 200 => 0x27 }, - 'flashexposurecomparea' => { 258 => '38.4', 260 => '38.4', 261 => '38.4', 270 => '38.4', 271 => '38.4' }, - 'flashexposurecompset' => { 174 => 0x10, 305 => 0xe, 376 => 0x14, 377 => 0x12, 378 => 0x23, 393 => 0x1f }, - 'flashexposurecompset2' => { 393 => [0x26,0x2c] }, - 'flashexposureindicator' => { 174 => 0x54 }, - 'flashexposureindicatorlast' => { 174 => 0x56 }, - 'flashexposureindicatornext' => { 174 => 0x55 }, - 'flashexposurelock' => { 54 => 0x19 }, - 'flashfired' => { 133 => 0x5d, 150 => 'Fired', 171 => 0x14, 235 => '590.3', 446 => [\'Flash','FlashFired'] }, - 'flashfiring' => { 78 => 0x306, 79 => 0x6, 80 => 0x7, 83 => 0x7 }, - 'flashfirmwareversion' => { 275 => 0x1002 }, - 'flashfocallength' => { 198 => 0xb, 199 => 0xc, 200 => 0xc, 201 => 0xc, 202 => 0xc }, - 'flashfunction' => { 177 => 0x31, 446 => [\'Flash','FlashFunction'] }, - 'flashgndistance' => { 198 => 0xe, 199 => 0xf, 200 => 0xf, 201 => 0xf, 202 => 0xf }, - 'flashgroupacompensation' => { 198 => 0x11, 199 => 0x12, 200 => 0x13, 201 => 0x28, 202 => 0x28 }, - 'flashgroupacontrolmode' => { 198 => 0xf, 199 => '16.1', 200 => '17.1', 201 => '17.1', 202 => '17.1' }, - 'flashgroupaoutput' => { 198 => 0x11, 199 => 0x12, 200 => 0x13, 201 => 0x28, 202 => 0x28 }, - 'flashgroupbcompensation' => { 198 => 0x12, 199 => 0x13, 200 => 0x14, 201 => 0x29, 202 => 0x29 }, - 'flashgroupbcontrolmode' => { 198 => 0x10, 199 => '17.1', 200 => '18.1', 201 => '18.1', 202 => '18.1' }, - 'flashgroupboutput' => { 198 => 0x12, 199 => 0x13, 200 => 0x14, 201 => 0x29, 202 => 0x29 }, - 'flashgroupccompensation' => { 199 => 0x14, 200 => 0x15, 201 => 0x2a, 202 => 0x2a }, - 'flashgroupccontrolmode' => { 199 => '17.2', 200 => '18.2', 201 => '18.2', 202 => '18.2' }, - 'flashgroupcoutput' => { 199 => 0x14, 200 => 0x15, 201 => 0x2a, 202 => 0x2a }, - 'flashguidenumber' => { 72 => 0xd, 88 => 0x0, 150 => 'GuideNumber' }, - 'flashintensity' => { 106 => [0x19,0x5], 274 => 0x405 }, - 'flashlevel' => { 259 => 0x9, 388 => 0xb048 }, - 'flashmake' => { 150 => 'Make' }, - 'flashmanufacturer' => { 169 => 'FlashManufacturer' }, - 'flashmetering' => { 171 => 0x3f, 174 => 0x1c }, - 'flashmeteringmode' => { 6 => 0x15, 12 => 0x15, 13 => 0x15, 14 => 0x15, 15 => 0x15, 16 => 0x15, 17 => 0x15, 19 => 0x15, 21 => 0x15, 27 => 0x15 }, - 'flashmeteringsegments' => { 332 => 0x20a }, - 'flashmode' => { 106 => 0x4, 131 => 0x3f2, 133 => 0x5c, 150 => 'Mode', 171 => 0x2, 172 => 0x20, 173 => 0x16, 174 => 0xf, 211 => 0x87, 274 => 0x400, 279 => 0x1004, 332 => 0xc, 339 => 0x4, 357 => 0x20, 358 => 0x100a, 367 => 0x225, 376 => 0x13, 377 => 0x7f, 378 => 0x20, 393 => 0x10, 396 => 0x1138, 397 => 0x1138, 398 => 0x1114, 399 => 0x1190, 400 => 0x116c, 401 => 0x1024, 402 => 0x21c, 403 => 0x21c, 404 => 0x211, 446 => [\'Flash','FlashMode'] }, - 'flashmodel' => { 150 => 'Model', 169 => 'FlashModel', 275 => 0x1001 }, - 'flashoptions' => { 313 => 0x2 }, - 'flashoptions2' => { 313 => 0x10 }, - 'flashoutput' => { 41 => 0x248, 72 => 0x21, 198 => 0xa, 199 => 0xa, 200 => 0xa, 201 => 0x27 }, - 'flashpixversion' => { 113 => 0xa000, 446 => 'FlashpixVersion' }, - 'flashredeyemode' => { 446 => [\'Flash','FlashRedEyeMode'] }, - 'flashremotecontrol' => { 274 => 0x403 }, - 'flashreturn' => { 446 => [\'Flash','FlashReturn'] }, - 'flashserialnumber' => { 150 => 'SerialNumber', 275 => 0x1003 }, - 'flashsetting' => { 211 => 0x8 }, - 'flashshutterspeed' => { 257 => '20.2', 258 => '23.2', 260 => '23.2', 261 => '23.2', 266 => '15.2', 267 => '22.2', 268 => '7.2', 269 => '22.2', 270 => '23.2', 271 => '23.2', 272 => '23.1' }, - 'flashsource' => { 198 => 0x4, 199 => 0x4, 200 => 0x4, 201 => 0x4, 202 => 0x4 }, - 'flashstatus' => { 320 => 0x0, 393 => [0x82,0x86], 406 => 0x31, 407 => 0x39 }, - 'flashstatusbuilt-in' => { 378 => [0x87,0x287] }, - 'flashstatusexternal' => { 378 => [0x88,0x288] }, - 'flashsyncspeed' => { 257 => '20.1', 258 => '23.1', 260 => '23.1', 261 => '23.1', 266 => '15.1', 267 => '22.1', 269 => '22.1', 270 => '23.1', 271 => '23.1' }, - 'flashsyncspeedav' => { 76 => 0x3, 78 => 0x10f, 79 => 0x2, 80 => 0x3, 81 => 0x2, 82 => 0x2, 83 => 0x3, 84 => 0x6 }, - 'flashthreshold' => { 88 => 0x1 }, - 'flashtype' => { 150 => 'Type', 174 => 0x59, 211 => 0x9, 275 => 0x1000 }, - 'flashwarning' => { 267 => '30.1', 268 => '7.1', 272 => '31.1', 297 => 0x62 }, - 'flexiblespotposition' => { 388 => 0x201d }, - 'flickerreduce' => { 367 => 0x218 }, - 'flickerreduction' => { 121 => 0x1446, 229 => 0xe84 }, - 'flickerreductionindicator' => { 229 => 0x5e2 }, - 'flightpitchdegree' => { 110 => 'FlightPitchDegree' }, - 'flightrolldegree' => { 110 => 'FlightRollDegree' }, - 'flightyawdegree' => { 110 => 'FlightYawDegree' }, - 'fliphorizontal' => { 250 => 0x76a43206 }, - 'fnumber' => { 6 => 0x3, 8 => 0x3, 10 => 0x3, 12 => 0x3, 13 => 0x3, 14 => 0x3, 15 => 0x3, 16 => 0x3, 17 => 0x3, 18 => 0x3, 19 => 0x3, 20 => 0x3, 21 => 0x3, 22 => 0x3, 23 => 0x3, 24 => 0x3, 25 => 0x3, 26 => 0x3, 27 => 0x3, 28 => 0x3, 29 => 0x5, 30 => 0x6, 72 => 0x15, 113 => 0x829d, 130 => 0xfd04, 133 => 0x1e, 135 => 0xfa23, 137 => 0xf103, 140 => 0x13, 142 => 0x3c, 145 => 0xc, 154 => 'FNumber', 171 => 0xa, 172 => 0x36, 173 => 0x47, 174 => 0x9, 177 => 0x49c7, 332 => 0x13, 365 => 0xa019, 368 => [0x31,0x49], 376 => 0x1, 377 => 0x1, 393 => [0x20,0x22,0x26], 446 => 'FNumber' }, - 'focaldistance' => { 427 => 'FocalDistance' }, - 'focallength' => { 6 => 0x1d, 7 => 0xa, 8 => 0x23, 9 => 0x9, 10 => 0x1d, 11 => 0x9, 12 => 0x1e, 13 => 0x1d, 14 => 0x1d, 15 => 0x1e, 16 => 0x1e, 17 => 0x1e, 18 => 0x28, 19 => 0x1e, 20 => 0x23, 21 => 0x1e, 22 => 0x1e, 23 => 0x23, 24 => 0x23, 25 => 0x23, 26 => 0x23, 27 => 0x1e, 28 => 0x23, 56 => 0x1, 107 => 0x1d, 113 => 0x920a, 140 => 0x1d, 154 => 'FocalLength', 171 => 0x12, 207 => 0xa, 208 => 0xb, 291 => 0x1, 332 => 0x1d, 341 => 0x403, 358 => 0x1500, 375 => 0xe, 400 => 0x1278, 401 => 0x1134, 402 => 0x32c, 403 => 0x32c, 404 => 0x30a, 446 => 'FocalLength' }, - 'focallength2' => { 393 => [0x23,0x25,0x29] }, - 'focallengthin35mmformat' => { 113 => 0xa405, 365 => 0xa01a, 446 => 'FocalLengthIn35mmFilm' }, - 'focallengthtelezoom' => { 375 => 0x10 }, - 'focalplaneafpointarea' => { 405 => 0x2 }, - 'focalplaneafpointlocation1' => { 405 => 0x6 }, - 'focalplaneafpointlocation10' => { 405 => 0x2a }, - 'focalplaneafpointlocation11' => { 405 => 0x2e }, - 'focalplaneafpointlocation12' => { 405 => 0x32 }, - 'focalplaneafpointlocation13' => { 405 => 0x36 }, - 'focalplaneafpointlocation14' => { 405 => 0x3a }, - 'focalplaneafpointlocation15' => { 405 => 0x3e }, - 'focalplaneafpointlocation2' => { 405 => 0xa }, - 'focalplaneafpointlocation3' => { 405 => 0xe }, - 'focalplaneafpointlocation4' => { 405 => 0x12 }, - 'focalplaneafpointlocation5' => { 405 => 0x16 }, - 'focalplaneafpointlocation6' => { 405 => 0x1a }, - 'focalplaneafpointlocation7' => { 405 => 0x1e }, - 'focalplaneafpointlocation8' => { 405 => 0x22 }, - 'focalplaneafpointlocation9' => { 405 => 0x26 }, - 'focalplaneafpointsused' => { 405 => 0x1 }, - 'focalplanediagonal' => { 275 => 0x103, 279 => 0x205 }, - 'focalplaneresolutionunit' => { 113 => 0xa210, 446 => 'FocalPlaneResolutionUnit' }, - 'focalplanexresolution' => { 113 => 0xa20e, 446 => 'FocalPlaneXResolution' }, - 'focalplanexsize' => { 56 => 0x2 }, - 'focalplanexunknown' => { 56 => 0x2 }, - 'focalplaneyresolution' => { 113 => 0xa20f, 446 => 'FocalPlaneYResolution' }, - 'focalplaneysize' => { 56 => 0x3 }, - 'focalplaneyunknown' => { 56 => 0x3 }, - 'focalpointx' => { 427 => 'FocalPointX' }, - 'focalpointy' => { 427 => 'FocalPointY' }, - 'focaltype' => { 9 => 0x2d, 56 => 0x0 }, - 'focalunits' => { 33 => 0x19 }, - 'focus' => { 240 => 0x8 }, - 'focusarea' => { 171 => 0x31 }, - 'focusareaselection' => { 268 => '15.2' }, - 'focuscontinuous' => { 33 => 0x20 }, - 'focusdisplayaiservoandmf' => { 78 => 0x515 }, - 'focusdistance' => { 154 => 'FocusDistance', 171 => 0x13, 177 => 0x49bb, 207 => 0x9, 208 => 0xa, 277 => 0x305, 291 => 0x0, 295 => 0x304, 296 => 0x304 }, - 'focusdistancelower' => { 6 => 0x45, 8 => 0x8e, 10 => 0x45, 12 => 0x56, 13 => 0x45, 14 => 0x45, 15 => 0x52, 16 => 0x52, 17 => 0x56, 19 => 0x52, 20 => 0x8e, 21 => 0x59, 22 => 0x57, 23 => 0x8e, 24 => 0x94, 25 => 0x95, 26 => 0xa7, 27 => 0x56, 28 => 0xa7, 54 => 0x15, 72 => 0x14 }, - 'focusdistanceupper' => { 6 => 0x43, 8 => 0x8c, 10 => 0x43, 12 => 0x54, 13 => 0x43, 14 => 0x43, 15 => 0x50, 16 => 0x50, 17 => 0x54, 19 => 0x50, 20 => 0x8c, 21 => 0x57, 22 => 0x55, 23 => 0x8c, 24 => 0x92, 25 => 0x93, 26 => 0xa5, 27 => 0x54, 28 => 0xa5, 54 => 0x14, 72 => 0x13 }, - 'focusholdbutton' => { 174 => 0x44 }, - 'focusinfoversion' => { 277 => 0x0 }, - 'focusingscreen' => { 77 => 0x0, 78 => 0x80b, 83 => 0x0 }, - 'focuslocation' => { 388 => 0x2027 }, - 'focuslocked' => { 170 => 0x14 }, - 'focusmode' => { 33 => 0x7, 106 => 0x3, 107 => [0x3003,0xd], 121 => 0x1021, 131 => 0x3f5, 133 => 0x38, 147 => 'FocusMode', 171 => 0x30, 173 => 0xe, 174 => 0xc, 211 => 0x7, 274 => 0x301, 279 => 0x100b, 297 => 0x7, 332 => 0xd, 339 => 0x3, 358 => 0x1006, 369 => [0xb,0x5], 375 => [0x15,0x1d], 376 => 0x4d, 377 => 0x4d, 388 => [0xb042,0xb04e,0x201b], 393 => 0x13, 411 => 0x16 }, - 'focusmode2' => { 120 => '0.1', 313 => '3.1', 393 => [0x2c,0x2e,0x32] }, - 'focusmodesetting' => { 259 => '10.1', 373 => 0x14, 374 => 0x15, 376 => 0x10, 377 => 0xf, 378 => 0x6 }, - 'focusmodeswitch' => { 174 => 0x58, 376 => 0x2e }, - 'focuspixel' => { 121 => 0x1023 }, - 'focuspointwrap' => { 257 => '2.2', 258 => '2.2', 260 => '2.1', 261 => '2.1', 265 => '1.1', 266 => '2.2', 267 => '1.1', 270 => '2.2', 271 => '2.1', 272 => '2.5' }, - 'focusposition' => { 207 => 0x8, 208 => 0x8, 332 => 0x10, 387 => 0x9bb }, - 'focusposition2' => { 393 => [0x29,0x2b,0x2f], 411 => 0x2d, 414 => 0x20 }, - 'focusprocess' => { 274 => 0x302 }, - 'focusrange' => { 33 => 0x12, 279 => 0x100a }, - 'focusrangeindex' => { 323 => '3.1' }, - 'focusringrotation' => { 78 => 0x713 }, - 'focussetting' => { 368 => 0x6 }, - 'focusstatus' => { 375 => 0x19, 376 => 0x53, 377 => 0x53 }, - 'focusstepcount' => { 277 => 0x301, 279 => 0x100e }, - 'focusstepinfinity' => { 277 => 0x303, 279 => 0x103b }, - 'focusstepnear' => { 277 => 0x304, 279 => 0x103c }, - 'focustrackinglockon' => { 257 => ['1.5','4.1'], 258 => '1.4', 265 => '0.4', 266 => '3.1', 267 => '0.4', 270 => '1.4' }, - 'focuswarning' => { 121 => 0x1301 }, - 'foldername' => { 171 => 0x27 }, - 'foldernumber' => { 376 => 0x9a, 378 => [0x402,0x114,0x316] }, - 'fontcomposite' => { 471 => [\'Fonts','FontsComposite'] }, - 'fontface' => { 471 => [\'Fonts','FontsFontFace'] }, - 'fontfamily' => { 471 => [\'Fonts','FontsFontFamily'] }, - 'fontfilename' => { 471 => [\'Fonts','FontsFontFileName'] }, - 'fontname' => { 471 => [\'Fonts','FontsFontName'] }, - 'fonts' => { 471 => 'Fonts' }, - 'fonttype' => { 471 => [\'Fonts','FontsFontType'] }, - 'fontversion' => { 471 => [\'Fonts','FontsVersionString'] }, - 'for' => { 348 => 'For' }, - 'forcewrite' => { 114 => 'ForceWrite' }, - 'format' => { 426 => 'Format', 443 => 'format', 464 => 'Format' }, - 'forwardlock' => { 461 => 'forwardlock' }, - 'forwardmatrix1' => { 113 => 0xc714 }, - 'forwardmatrix2' => { 113 => 0xc715 }, - 'fossilspecimen' => { 112 => 'FossilSpecimen' }, - 'fossilspecimenmaterialsampleid' => { 112 => [\'FossilSpecimen','FossilSpecimenMaterialSampleID'] }, - 'framecount' => { 63 => [0x2,0x4] }, - 'frameheight' => { 121 => 0x3822 }, - 'framenum' => { 343 => 0xd7 }, - 'framenumber' => { 121 => 0x8003, 177 => 0x3c, 332 => 0x29 }, - 'framerate' => { 63 => [0x1,0x6], 113 => 0xc764, 121 => 0x3820 }, - 'framewidth' => { 121 => 0x3821 }, - 'framing' => { 455 => 'framing' }, - 'freebytes' => { 91 => 0x1 }, - 'freememorycardimages' => { 172 => [0x37,0x54], 173 => [0x2d,0x4a], 174 => 0x32 }, - 'fujiflashmode' => { 121 => 0x1010 }, - 'fullimagesize' => { 388 => 0xb02b }, - 'fullpanoheightpixels' => { 429 => 'FullPanoHeightPixels', 430 => 'FullPanoHeightPixels' }, - 'fullpanowidthpixels' => { 429 => 'FullPanoWidthPixels', 430 => 'FullPanoWidthPixels' }, - 'fullpresssnap' => { 358 => 0x100d }, - 'fullsizeimage' => { 153 => 'data' }, - 'fullsizeimagename' => { 153 => '1Name' }, - 'fullsizeimagetype' => { 153 => '0Type' }, - 'func1button' => { 260 => '14.1', 261 => '14.1', 271 => '14.1' }, - 'func1buttonplusdials' => { 260 => '42.1', 261 => '42.1', 271 => '42.1' }, - 'func2button' => { 260 => '80.1', 261 => '80.1', 271 => '80.1' }, - 'func2buttonplusdials' => { 260 => '81.1' }, - 'func3button' => { 260 => '83.1' }, - 'funcbutton' => { 257 => ['14.1','15.1'], 258 => '14.1', 266 => '28.1', 267 => '13.1', 270 => '14.1', 272 => '14.1' }, - 'funcbuttonplusdials' => { 257 => ['14.2','15.2'], 258 => '14.2', 266 => '31.1', 270 => '42.1' }, - 'functionbutton' => { 264 => '13.1', 268 => '5.2' }, - 'gainbase' => { 278 => 0x610 }, - 'gaincontrol' => { 113 => 0xa407, 446 => 'GainControl' }, - 'gamma' => { 113 => 0xa500, 131 => 0x8fe, 302 => 0x11c, 447 => 'Gamma' }, - 'gammablackpoint' => { 99 => 0xc }, - 'gammacolortone' => { 99 => 0x3 }, - 'gammacompensatedvalue' => { 127 => 0x91 }, - 'gammacontrast' => { 99 => 0x2 }, - 'gammacurveoutputrange' => { 99 => 0xf }, - 'gammahighlight' => { 99 => 0xa }, - 'gammalinear' => { 97 => 0x20200 }, - 'gammamidpoint' => { 99 => 0xe }, - 'gammasaturation' => { 99 => 0x4 }, - 'gammashadow' => { 99 => 0x9 }, - 'gammasharpnessstrength' => { 99 => 0x8 }, - 'gammaunsharpmaskfineness' => { 99 => 0x6 }, - 'gammaunsharpmaskstrength' => { 99 => 0x5 }, - 'gammaunsharpmaskthreshold' => { 99 => 0x7 }, - 'gammawhitepoint' => { 99 => 0xd }, - 'geimagesize' => { 121 => 0x1304 }, - 'gemake' => { 123 => 0x300 }, - 'gemodel' => { 123 => 0x207 }, - 'genre' => { 452 => 'Genre', 456 => 'genre', 466 => 'genre' }, - 'genrecvid' => { 452 => [\'Genre','GenreCvId'] }, - 'genrecvtermid' => { 452 => [\'Genre','GenreCvTermId'] }, - 'genrecvtermname' => { 452 => [\'Genre','GenreCvTermName'] }, - 'genrecvtermrefinedabout' => { 452 => [\'Genre','GenreCvTermRefinedAbout'] }, - 'geography' => { 457 => 'geography' }, - 'geologicalcontext' => { 112 => 'GeologicalContext' }, - 'geologicalcontextbed' => { 112 => [\'GeologicalContext','GeologicalContextBed'] }, - 'geologicalcontextformation' => { 112 => [\'GeologicalContext','GeologicalContextFormation'] }, - 'geologicalcontextgroup' => { 112 => [\'GeologicalContext','GeologicalContextGroup'] }, - 'geologicalcontextid' => { 112 => [\'GeologicalContext','GeologicalContextGeologicalContextID'] }, - 'geologicalcontextmember' => { 112 => [\'GeologicalContext','GeologicalContextMember'] }, - 'geosync' => { 114 => 'Geosync' }, - 'geotag' => { 114 => 'Geotag' }, - 'geotiffasciiparams' => { 113 => 0x87b1 }, - 'geotiffdirectory' => { 113 => 0x87af }, - 'geotiffdoubleparams' => { 113 => 0x87b0 }, - 'geotime' => { 114 => 'Geotime' }, - 'giftftppriority' => { 431 => 'GIFTFtpPriority' }, - 'gimbalpitchdegree' => { 110 => 'GimbalPitchDegree' }, - 'gimbalrolldegree' => { 110 => 'GimbalRollDegree' }, - 'gimbalyawdegree' => { 110 => 'GimbalYawDegree' }, - 'globalaltitude' => { 346 => 0x419 }, - 'globalangle' => { 346 => 0x40d }, - 'good' => { 466 => 'good' }, - 'googleplusuploadcode' => { 113 => 0x9009 }, - 'gpsaltitude' => { 124 => 0x6, 151 => 'Altitude', 446 => 'GPSAltitude' }, - 'gpsaltituderef' => { 124 => 0x5, 446 => 'GPSAltitudeRef' }, - 'gpsareainformation' => { 124 => 0x1c, 446 => 'GPSAreaInformation' }, - 'gpsdatestamp' => { 124 => 0x1d }, - 'gpsdatetime' => { 151 => 'DateTime', 446 => 'GPSTimeStamp' }, - 'gpsdestbearing' => { 124 => 0x18, 151 => 'Bearing', 446 => 'GPSDestBearing' }, - 'gpsdestbearingref' => { 124 => 0x17, 446 => 'GPSDestBearingRef' }, - 'gpsdestdistance' => { 124 => 0x1a, 151 => 'Distance', 446 => 'GPSDestDistance' }, - 'gpsdestdistanceref' => { 124 => 0x19, 446 => 'GPSDestDistanceRef' }, - 'gpsdestlatitude' => { 124 => 0x14, 446 => 'GPSDestLatitude' }, - 'gpsdestlatituderef' => { 124 => 0x13 }, - 'gpsdestlongitude' => { 124 => 0x16, 446 => 'GPSDestLongitude' }, - 'gpsdestlongituderef' => { 124 => 0x15 }, - 'gpsdifferential' => { 124 => 0x1e, 151 => 'Differential', 446 => 'GPSDifferential' }, - 'gpsdop' => { 124 => 0xb, 446 => 'GPSDOP' }, - 'gpshpositioningerror' => { 124 => 0x1f, 446 => 'GPSHPositioningError' }, - 'gpsimgdirection' => { 124 => 0x11, 446 => 'GPSImgDirection' }, - 'gpsimgdirectionref' => { 124 => 0x10, 446 => 'GPSImgDirectionRef' }, - 'gpslatitude' => { 124 => 0x2, 151 => 'Latitude', 446 => 'GPSLatitude' }, - 'gpslatituderef' => { 124 => 0x1 }, - 'gpslongitude' => { 124 => 0x4, 151 => 'Longitude', 446 => 'GPSLongitude' }, - 'gpslongituderef' => { 124 => 0x3 }, - 'gpsmapdatum' => { 124 => 0x12, 151 => 'Datum', 446 => 'GPSMapDatum' }, - 'gpsmeasuremode' => { 124 => 0xa, 151 => 'MeasureMode', 446 => 'GPSMeasureMode' }, - 'gpsprocessingmethod' => { 124 => 0x1b, 446 => 'GPSProcessingMethod' }, - 'gpssatellites' => { 124 => 0x8, 151 => 'Satellites', 446 => 'GPSSatellites' }, - 'gpsspeed' => { 124 => 0xd, 151 => 'Speed', 446 => 'GPSSpeed' }, - 'gpsspeedref' => { 124 => 0xc, 446 => 'GPSSpeedRef' }, - 'gpsstatus' => { 124 => 0x9, 446 => 'GPSStatus' }, - 'gpsstring' => { 131 => 0x402 }, - 'gpstimestamp' => { 124 => 0x7 }, - 'gpstrack' => { 124 => 0xf, 151 => 'Heading', 446 => 'GPSTrack' }, - 'gpstrackref' => { 124 => 0xe, 446 => 'GPSTrackRef' }, - 'gpsversionid' => { 124 => 0x0, 446 => 'GPSVersionID' }, - 'gradation' => { 274 => 0x50f }, - 'gradientbasedcorractive' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionActive'] }, - 'gradientbasedcorramount' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionAmount'] }, - 'gradientbasedcorrbrightness' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalBrightness'] }, - 'gradientbasedcorrclarity' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalClarity'] }, - 'gradientbasedcorrclarity2012' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalClarity2012'] }, - 'gradientbasedcorrcontrast' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalContrast'] }, - 'gradientbasedcorrcontrast2012' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalContrast2012'] }, - 'gradientbasedcorrdefringe' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalDefringe'] }, - 'gradientbasedcorrections' => { 442 => 'GradientBasedCorrections' }, - 'gradientbasedcorrexposure' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalExposure'] }, - 'gradientbasedcorrexposure2012' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalExposure2012'] }, - 'gradientbasedcorrhighlights2012' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalHighlights2012'] }, - 'gradientbasedcorrhue' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalToningHue'] }, - 'gradientbasedcorrluminancenoise' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalLuminanceNoise'] }, - 'gradientbasedcorrmaskalpha' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksAlpha'] }, - 'gradientbasedcorrmaskangle' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksAngle'] }, - 'gradientbasedcorrmaskbottom' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksBottom'] }, - 'gradientbasedcorrmaskcentervalue' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCenterValue'] }, - 'gradientbasedcorrmaskcenterweight' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCenterWeight'] }, - 'gradientbasedcorrmaskdabs' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksDabs'] }, - 'gradientbasedcorrmaskfeather' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFeather'] }, - 'gradientbasedcorrmaskflipped' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFlipped'] }, - 'gradientbasedcorrmaskflow' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFlow'] }, - 'gradientbasedcorrmaskfullx' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFullX'] }, - 'gradientbasedcorrmaskfully' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFullY'] }, - 'gradientbasedcorrmaskleft' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksLeft'] }, - 'gradientbasedcorrmaskmidpoint' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMidpoint'] }, - 'gradientbasedcorrmaskperimetervalue' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksPerimeterValue'] }, - 'gradientbasedcorrmaskradius' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksRadius'] }, - 'gradientbasedcorrmaskright' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksRight'] }, - 'gradientbasedcorrmaskroundness' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksRoundness'] }, - 'gradientbasedcorrmasks' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasks'] }, - 'gradientbasedcorrmasksizex' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksSizeX'] }, - 'gradientbasedcorrmasksizey' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksSizeY'] }, - 'gradientbasedcorrmasktop' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksTop'] }, - 'gradientbasedcorrmaskvalue' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskValue'] }, - 'gradientbasedcorrmaskversion' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksVersion'] }, - 'gradientbasedcorrmaskwhat' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksWhat'] }, - 'gradientbasedcorrmaskx' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksX'] }, - 'gradientbasedcorrmasky' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksY'] }, - 'gradientbasedcorrmaskzerox' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksZeroX'] }, - 'gradientbasedcorrmaskzeroy' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksZeroY'] }, - 'gradientbasedcorrmoire' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalMoire'] }, - 'gradientbasedcorrsaturation' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalSaturation','GradientBasedCorrectionsLocalToningSaturation'] }, - 'gradientbasedcorrshadows2012' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalShadows2012'] }, - 'gradientbasedcorrsharpness' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalSharpness'] }, - 'gradientbasedcorrtemperature' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalTemperature'] }, - 'gradientbasedcorrtint' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalTint'] }, - 'gradientbasedcorrwhat' => { 442 => [\'GradientBasedCorrections','GradientBasedCorrectionsWhat'] }, - 'grainamount' => { 442 => 'GrainAmount' }, - 'graineffect' => { 121 => 0x1047 }, - 'grainfrequency' => { 442 => 'GrainFrequency' }, - 'grainsize' => { 442 => 'GrainSize' }, - 'graymixeraqua' => { 442 => 'GrayMixerAqua' }, - 'graymixerblue' => { 442 => 'GrayMixerBlue' }, - 'graymixergreen' => { 442 => 'GrayMixerGreen' }, - 'graymixermagenta' => { 442 => 'GrayMixerMagenta' }, - 'graymixerorange' => { 442 => 'GrayMixerOrange' }, - 'graymixerpurple' => { 442 => 'GrayMixerPurple' }, - 'graymixerred' => { 442 => 'GrayMixerRed' }, - 'graymixeryellow' => { 442 => 'GrayMixerYellow' }, - 'graypoint' => { 421 => 0x8021 }, - 'grayresponseunit' => { 113 => 0x122 }, - 'greencurvelimits' => { 102 => 0x1c4 }, - 'greencurvepoints' => { 101 => 0x53, 102 => 0x19a }, - 'greenhsl' => { 97 => 0x20913 }, - 'greenhue' => { 442 => 'GreenHue' }, - 'greensaturation' => { 442 => 'GreenSaturation' }, - 'griddisplay' => { 257 => '13.3', 258 => '4.3', 260 => '4.2', 261 => '4.2', 262 => '2.2', 266 => '10.5', 267 => '3.4', 268 => '6.1', 270 => '4.4', 271 => '4.2', 272 => '4.2' }, - 'gripbatteryadload' => { 311 => 0x5 }, - 'gripbatteryadnoload' => { 311 => 0x4 }, - 'gripbatterystate' => { 311 => '1.2' }, - 'groupareaafillumination' => { 258 => '46.4', 261 => '47.4', 270 => '47.4' }, - 'h2resetblackpixels' => { 131 => 0x18a6 }, - 'h3resetblackcolumns' => { 131 => 0x18ce }, - 'h3resetblackpixels' => { 131 => 0x18b0 }, - 'halftonehints' => { 113 => 0x141 }, - 'hardlink' => { 114 => 'HardLink' }, - 'hasalternative' => { 456 => 'hasAlternative' }, - 'hascorrection' => { 456 => 'hasCorrection' }, - 'hascorrectiona-lang' => { 456 => [\'hasCorrection','hasCorrectionA-lang'] }, - 'hascorrectiona-platform' => { 456 => [\'hasCorrection','hasCorrectionA-platform'] }, - 'hascorrectiontext' => { 456 => [\'hasCorrection','hasCorrectionText'] }, - 'hascrop' => { 442 => 'HasCrop' }, - 'hasextendedxmp' => { 468 => 'HasExtendedXMP' }, - 'hassettings' => { 442 => 'HasSettings' }, - 'hastranslation' => { 456 => 'hasTranslation' }, - 'hasvisibleoverprint' => { 471 => 'HasVisibleOverprint' }, - 'hasvisibletransparency' => { 471 => 'HasVisibleTransparency' }, - 'hdr' => { 57 => 0x1, 204 => 0x4, 297 => 0x9e, 332 => 0x85, 388 => 0x200a }, - 'hdreffect' => { 57 => 0x2 }, + 'croppedimagewidth' => { 5 => 0x1, 387 => 0x1603 }, + 'cropping' => { 455 => 0x9010 }, + 'cropright' => { 123 => 0x8, 267 => 0x2e, 325 => 0x32, 366 => 0xdb, 478 => 'CropRight', 480 => 'CropRight' }, + 'croprightmargin' => { 53 => 0x1 }, + 'croprotatedoriginalheight' => { 101 => 0x2 }, + 'croprotatedoriginalwidth' => { 101 => 0x1 }, + 'croprotation' => { 101 => 0x8, 123 => 0xb }, + 'cropscaledresolution' => { 267 => 0x9e }, + 'cropsourceresolution' => { 267 => 0xae }, + 'croptop' => { 108 => 0x248, 123 => 0x7, 267 => 0x26, 301 => 0x613, 305 => 0x613, 325 => 0x2f, 366 => 0xda, 478 => 'CropTop', 480 => 'CropTop' }, + 'croptopmargin' => { 53 => 0x2 }, + 'cropunit' => { 478 => 'CropUnit', 480 => 'CropUnit' }, + 'cropunits' => { 478 => 'CropUnits', 480 => 'CropUnits' }, + 'cropw' => { 472 => 'CropW' }, + 'cropwidth' => { 101 => 0x5, 108 => 0x24a, 301 => 0x614, 305 => 0x614, 478 => 'CropWidth', 480 => 'CropWidth' }, + 'cropx' => { 101 => 0x3, 472 => 'CropX' }, + 'cropy' => { 101 => 0x4, 472 => 'CropY' }, + 'crossprocess' => { 355 => 0x7b }, + 'crossprocessparams' => { 355 => 0x235 }, + 'cuisine' => { 496 => 'cuisine' }, + 'currenticcprofile' => { 119 => 0xc691 }, + 'currentpreprofilematrix' => { 119 => 0xc692 }, + 'currentversion' => { 455 => 0xd000 }, + 'curve0x' => { 472 => 'Curve0x' }, + 'curve0y' => { 472 => 'Curve0y' }, + 'curve1x' => { 472 => 'Curve1x' }, + 'curve1y' => { 472 => 'Curve1y' }, + 'curve2x' => { 472 => 'Curve2x' }, + 'curve2y' => { 472 => 'Curve2y' }, + 'curve3x' => { 472 => 'Curve3x' }, + 'curve3y' => { 472 => 'Curve3y' }, + 'curve4x' => { 472 => 'Curve4x' }, + 'curve4y' => { 472 => 'Curve4y' }, + 'curves' => { 272 => 0x76a43201 }, + 'custom1' => { 307 => 'Custom1' }, + 'custom10' => { 307 => 'Custom10' }, + 'custom2' => { 307 => 'Custom2' }, + 'custom3' => { 307 => 'Custom3' }, + 'custom4' => { 307 => 'Custom4' }, + 'custom5' => { 307 => 'Custom5' }, + 'custom6' => { 307 => 'Custom6' }, + 'custom7' => { 307 => 'Custom7' }, + 'custom8' => { 307 => 'Custom8' }, + 'custom9' => { 307 => 'Custom9' }, + 'customcolortone' => { 109 => 0x4c }, + 'customcontrast' => { 109 => 0x4e }, + 'customcontrols' => { 84 => 0x70c }, + 'customdefaultunsharpfineness' => { 109 => 0xbe }, + 'customdefaultunsharpstrength' => { 109 => 0xbc }, + 'customdefaultunsharpthreshold' => { 109 => 0xc0 }, + 'customilluminant' => { 138 => 0x405 }, + 'customizedials' => { 84 => 0x715 }, + 'customlinear' => { 109 => 0x4f }, + 'customoutputhighlightpoint' => { 109 => 0x53 }, + 'customoutputshadowpoint' => { 109 => 0x54 }, + 'custompicturestyle' => { 103 => 0x10021 }, + 'custompicturestyledata' => { 103 => 0xf0500 }, + 'custompicturestylefilename' => { 64 => 0x4010 }, + 'customrawhighlight' => { 109 => 0x7c }, + 'customrawhighlightpoint' => { 109 => 0x51 }, + 'customrawshadow' => { 109 => 0x85 }, + 'customrawshadowpoint' => { 109 => 0x52 }, + 'customrendered' => { 119 => 0xa401, 191 => 0x6420, 484 => 'CustomRendered' }, + 'customsaturation' => { 109 => 0x4d, 297 => 0x503 }, + 'customsettingsalldefault' => { 279 => '0.2', 288 => '0.2' }, + 'customsettingsbank' => { 279 => '0.1', 280 => '0.1', 282 => '0.1', 283 => '0.1', 288 => '0.1', 292 => '0.2', 293 => '0.2', 295 => 0x1 }, + 'customsharpness' => { 109 => 0x50 }, + 'customunsharpmaskfineness' => { 109 => 0xb8 }, + 'customunsharpmaskstrength' => { 109 => 0xb6 }, + 'customunsharpmaskthreshold' => { 109 => 0xba }, + 'customwb_rblevels' => { 425 => 0x1a }, + 'customwb_rgblevels' => { 408 => 0x8, 409 => 0x19 }, + 'customwbbluelevel' => { 184 => 0x36 }, + 'customwberror' => { 184 => 0x37 }, + 'customwbgreenlevel' => { 184 => 0x35 }, + 'customwbredlevel' => { 184 => 0x34 }, + 'customwbsetting' => { 184 => 0x26 }, + 'cx' => { 380 => '_cx_' }, + 'cy' => { 380 => '_cy_' }, + 'd-lightinghq' => { 272 => 0x2175eb78 }, + 'd-lightinghqcolorboost' => { 268 => 0x2 }, + 'd-lightinghqhighlight' => { 268 => 0x1 }, + 'd-lightinghqselected' => { 272 => 0x6a6e36b6 }, + 'd-lightinghqshadow' => { 268 => 0x0 }, + 'd-lightinghs' => { 272 => 0xce5554aa }, + 'd-lightinghsadjustment' => { 269 => 0x0 }, + 'd-lightinghscolorboost' => { 269 => 0x1 }, + 'd-rangeoptimizerhighlight' => { 455 => 0x8024 }, + 'd-rangeoptimizermode' => { 455 => 0x8022 }, + 'd-rangeoptimizershadow' => { 455 => 0x802d }, + 'd-rangeoptimizervalue' => { 455 => 0x8023 }, + 'darkblacksegrows' => { 138 => 0x18d8 }, + 'darkfocusenvironment' => { 320 => 0x8003 }, + 'darkframecountfactor' => { 138 => 0xc85 }, + 'darkframelongexposure' => { 138 => 0xc84 }, + 'darkframeshortexposure' => { 138 => 0xc83 }, + 'darkpedestal' => { 138 => 0xc7f }, + 'datacompressionmethod' => { 133 => 0x6e }, + 'dataimprint' => { 181 => 0x34 }, + 'dataonscreen' => { 490 => 'DataOnScreen' }, + 'dataonscreenregion' => { 490 => [\'DataOnScreen','DataOnScreenRegion'] }, + 'dataonscreenregiond' => { 490 => [\'DataOnScreen','DataOnScreenRegionD'] }, + 'dataonscreenregionh' => { 490 => [\'DataOnScreen','DataOnScreenRegionH'] }, + 'dataonscreenregiontext' => { 490 => [\'DataOnScreen','DataOnScreenRegionText'] }, + 'dataonscreenregionunit' => { 490 => [\'DataOnScreen','DataOnScreenRegionUnit'] }, + 'dataonscreenregionw' => { 490 => [\'DataOnScreen','DataOnScreenRegionW'] }, + 'dataonscreenregionx' => { 490 => [\'DataOnScreen','DataOnScreenRegionX'] }, + 'dataonscreenregiony' => { 490 => [\'DataOnScreen','DataOnScreenRegionY'] }, + 'datascaling' => { 355 => 0x3d }, + 'date' => { 355 => 0x6, 481 => 'date' }, + 'dateacquired' => { 178 => 'DateAcquired', 179 => '{2CBAA8F5-D81F-47CA-B17A-F8D822300131} 100' }, + 'datecreated' => { 131 => 0x37, 492 => 'DateCreated' }, + 'datedisplayformat' => { 264 => 0x3 }, + 'dateidentified' => { 118 => [\'Identification','IdentificationDateIdentified'] }, + 'dateimprint' => { 284 => '4.2' }, + 'daterecieved' => { 494 => 'dateRecieved' }, + 'datesent' => { 132 => 0x46 }, + 'datestampmode' => { 64 => 0x1c, 226 => 0x9d }, + 'datetime' => { 473 => 'datetime', 500 => 'DateTime' }, + 'datetimedigitized' => { 484 => 'DateTimeDigitized' }, + 'datetimeoriginal' => { 100 => 0x0, 119 => 0x9003, 154 => 0x14, 157 => 'OriginalDate', 375 => 'IDIT', 380 => 'date', 381 => 0xb, 382 => 0x3b, 383 => 0x3e, 484 => 'DateTimeOriginal' }, + 'datetimestamp' => { 140 => 0x64 }, + 'datetimeutc' => { 297 => 0x908 }, + 'daylightsavings' => { 78 => 0x3, 264 => 0x2 }, + 'dayofweek' => { 382 => 0x42, 383 => 0x4a }, + 'dccontinent' => { 118 => [\'dctermsLocation','dctermsLocationContinent'] }, + 'dccoordinateprecision' => { 118 => [\'dctermsLocation','dctermsLocationCoordinatePrecision'] }, + 'dccoordinateuncertaintyinmeters' => { 118 => [\'dctermsLocation','dctermsLocationCoordinateUncertaintyInMeters'] }, + 'dccountry' => { 118 => [\'dctermsLocation','dctermsLocationCountry'] }, + 'dccountrycode' => { 118 => [\'dctermsLocation','dctermsLocationCountryCode'] }, + 'dccounty' => { 118 => [\'dctermsLocation','dctermsLocationCounty'] }, + 'dcdecimallatitude' => { 118 => [\'dctermsLocation','dctermsLocationDecimalLatitude'] }, + 'dcdecimallongitude' => { 118 => [\'dctermsLocation','dctermsLocationDecimalLongitude'] }, + 'dcevent' => { 118 => 'Event' }, + 'dcfootprintspatialfit' => { 118 => [\'dctermsLocation','dctermsLocationFootprintSpatialFit'] }, + 'dcfootprintsrs' => { 118 => [\'dctermsLocation','dctermsLocationFootprintSRS'] }, + 'dcfootprintwkt' => { 118 => [\'dctermsLocation','dctermsLocationFootprintWKT'] }, + 'dcgeodeticdatum' => { 118 => [\'dctermsLocation','dctermsLocationGeodeticDatum'] }, + 'dcgeoreferencedby' => { 118 => [\'dctermsLocation','dctermsLocationGeoreferencedBy'] }, + 'dcgeoreferenceddate' => { 118 => [\'dctermsLocation','dctermsLocationGeoreferencedDate'] }, + 'dcgeoreferenceprotocol' => { 118 => [\'dctermsLocation','dctermsLocationGeoreferenceProtocol'] }, + 'dcgeoreferenceremarks' => { 118 => [\'dctermsLocation','dctermsLocationGeoreferenceRemarks'] }, + 'dcgeoreferencesources' => { 118 => [\'dctermsLocation','dctermsLocationGeoreferenceSources'] }, + 'dcgeoreferenceverificationstatus' => { 118 => [\'dctermsLocation','dctermsLocationGeoreferenceVerificationStatus'] }, + 'dchighergeography' => { 118 => [\'dctermsLocation','dctermsLocationHigherGeography'] }, + 'dchighergeographyid' => { 118 => [\'dctermsLocation','dctermsLocationHigherGeographyID'] }, + 'dcisland' => { 118 => [\'dctermsLocation','dctermsLocationIsland'] }, + 'dcislandgroup' => { 118 => [\'dctermsLocation','dctermsLocationIslandGroup'] }, + 'dclocality' => { 118 => [\'dctermsLocation','dctermsLocationLocality'] }, + 'dclocationaccordingto' => { 118 => [\'dctermsLocation','dctermsLocationLocationAccordingTo'] }, + 'dclocationid' => { 118 => [\'dctermsLocation','dctermsLocationLocationID'] }, + 'dclocationremarks' => { 118 => [\'dctermsLocation','dctermsLocationLocationRemarks'] }, + 'dcmaximumdepthinmeters' => { 118 => [\'dctermsLocation','dctermsLocationMaximumDepthInMeters'] }, + 'dcmaximumdistanceabovesurfaceinmeters' => { 118 => [\'dctermsLocation','dctermsLocationMaximumDistanceAboveSurfaceInMeters'] }, + 'dcmaximumelevationinmeters' => { 118 => [\'dctermsLocation','dctermsLocationMaximumElevationInMeters'] }, + 'dcminimumdepthinmeters' => { 118 => [\'dctermsLocation','dctermsLocationMinimumDepthInMeters'] }, + 'dcminimumdistanceabovesurfaceinmeters' => { 118 => [\'dctermsLocation','dctermsLocationMinimumDistanceAboveSurfaceInMeters'] }, + 'dcminimumelevationinmeters' => { 118 => [\'dctermsLocation','dctermsLocationMinimumElevationInMeters'] }, + 'dcmunicipality' => { 118 => [\'dctermsLocation','dctermsLocationMunicipality'] }, + 'dcpointradiusspatialfit' => { 118 => [\'dctermsLocation','dctermsLocationPointRadiusSpatialFit'] }, + 'dcstateprovince' => { 118 => [\'dctermsLocation','dctermsLocationStateProvince'] }, + 'dctermslocation' => { 118 => 'dctermsLocation' }, + 'dcverbatimcoordinates' => { 118 => [\'dctermsLocation','dctermsLocationVerbatimCoordinates'] }, + 'dcverbatimcoordinatesystem' => { 118 => [\'dctermsLocation','dctermsLocationVerbatimCoordinateSystem'] }, + 'dcverbatimdepth' => { 118 => [\'dctermsLocation','dctermsLocationVerbatimDepth'] }, + 'dcverbatimelevation' => { 118 => [\'dctermsLocation','dctermsLocationVerbatimElevation'] }, + 'dcverbatimlatitude' => { 118 => [\'dctermsLocation','dctermsLocationVerbatimLatitude'] }, + 'dcverbatimlocality' => { 118 => [\'dctermsLocation','dctermsLocationVerbatimLocality'] }, + 'dcverbatimlongitude' => { 118 => [\'dctermsLocation','dctermsLocationVerbatimLongitude'] }, + 'dcverbatimsrs' => { 118 => [\'dctermsLocation','dctermsLocationVerbatimSRS'] }, + 'dcverticaldatum' => { 118 => [\'dctermsLocation','dctermsLocationVerticalDatum'] }, + 'dcwaterbody' => { 118 => [\'dctermsLocation','dctermsLocationWaterBody'] }, + 'declination' => { 165 => 'Declination' }, + 'decposition' => { 181 => 0x32 }, + 'defaultautogray' => { 478 => 'DefaultAutoGray', 480 => 'DefaultAutoGray' }, + 'defaultautotone' => { 478 => 'DefaultAutoTone', 480 => 'DefaultAutoTone' }, + 'defaultblackrender' => { 119 => 0xc7a6 }, + 'defaultcroporigin' => { 119 => 0xc61f }, + 'defaultcropsize' => { 119 => 0xc620 }, + 'defaulteraseoption' => { 84 => 0x813 }, + 'defaultscale' => { 119 => 0xc61e }, + 'defaultsspecifictoiso' => { 478 => 'DefaultsSpecificToISO', 480 => 'DefaultsSpecificToISO' }, + 'defaultsspecifictoserial' => { 478 => 'DefaultsSpecificToSerial', 480 => 'DefaultsSpecificToSerial' }, + 'defaultusercrop' => { 119 => 0xc7b5 }, + 'defectisocode' => { 138 => 0x90f }, + 'defringe' => { 478 => 'Defringe', 480 => 'Defringe' }, + 'defringegreenamount' => { 478 => 'DefringeGreenAmount', 480 => 'DefringeGreenAmount' }, + 'defringegreenhuehi' => { 478 => 'DefringeGreenHueHi', 480 => 'DefringeGreenHueHi' }, + 'defringegreenhuelo' => { 478 => 'DefringeGreenHueLo', 480 => 'DefringeGreenHueLo' }, + 'defringepurpleamount' => { 478 => 'DefringePurpleAmount', 480 => 'DefringePurpleAmount' }, + 'defringepurplehuehi' => { 478 => 'DefringePurpleHueHi', 480 => 'DefringePurpleHueHi' }, + 'defringepurplehuelo' => { 478 => 'DefringePurpleHueLo', 480 => 'DefringePurpleHueLo' }, + 'dehaze' => { 478 => 'Dehaze', 480 => 'Dehaze' }, + 'deletedimagecount' => { 226 => 0xa6, 238 => 0x6e }, + 'deprecatedon' => { 476 => 'deprecatedOn' }, + 'depthfar' => { 119 => 0xc7eb }, + 'depthformat' => { 119 => 0xc7e9 }, + 'depthimage' => { 463 => 'Data' }, + 'depthmeasuretype' => { 119 => 0xc7ed }, + 'depthnear' => { 119 => 0xc7ea }, + 'depthunits' => { 119 => 0xc7ec }, + 'derivedfrom' => { 505 => 'DerivedFrom' }, + 'derivedfromalternatepaths' => { 505 => [\'DerivedFrom','DerivedFromAlternatePaths'] }, + 'derivedfromdocumentid' => { 505 => [\'DerivedFrom','DerivedFromDocumentID'] }, + 'derivedfromfilepath' => { 505 => [\'DerivedFrom','DerivedFromFilePath'] }, + 'derivedfromfrompart' => { 505 => [\'DerivedFrom','DerivedFromFromPart'] }, + 'derivedfrominstanceid' => { 505 => [\'DerivedFrom','DerivedFromInstanceID'] }, + 'derivedfromlastmodifydate' => { 505 => [\'DerivedFrom','DerivedFromLastModifyDate'] }, + 'derivedfromlasturl' => { 505 => [\'DerivedFrom','DerivedFromLastURL'] }, + 'derivedfromlinkcategory' => { 505 => [\'DerivedFrom','DerivedFromLinkCategory'] }, + 'derivedfromlinkform' => { 505 => [\'DerivedFrom','DerivedFromLinkForm'] }, + 'derivedfrommanager' => { 505 => [\'DerivedFrom','DerivedFromManager'] }, + 'derivedfrommanagervariant' => { 505 => [\'DerivedFrom','DerivedFromManagerVariant'] }, + 'derivedfrommanageto' => { 505 => [\'DerivedFrom','DerivedFromManageTo'] }, + 'derivedfrommanageui' => { 505 => [\'DerivedFrom','DerivedFromManageUI'] }, + 'derivedfrommaskmarkers' => { 505 => [\'DerivedFrom','DerivedFromMaskMarkers'] }, + 'derivedfromoriginaldocumentid' => { 505 => [\'DerivedFrom','DerivedFromOriginalDocumentID'] }, + 'derivedfrompartmapping' => { 505 => [\'DerivedFrom','DerivedFromPartMapping'] }, + 'derivedfromplacedresolutionunit' => { 505 => [\'DerivedFrom','DerivedFromPlacedResolutionUnit'] }, + 'derivedfromplacedxresolution' => { 505 => [\'DerivedFrom','DerivedFromPlacedXResolution'] }, + 'derivedfromplacedyresolution' => { 505 => [\'DerivedFrom','DerivedFromPlacedYResolution'] }, + 'derivedfromrenditionclass' => { 505 => [\'DerivedFrom','DerivedFromRenditionClass'] }, + 'derivedfromrenditionparams' => { 505 => [\'DerivedFrom','DerivedFromRenditionParams'] }, + 'derivedfromtopart' => { 505 => [\'DerivedFrom','DerivedFromToPart'] }, + 'derivedfromversionid' => { 505 => [\'DerivedFrom','DerivedFromVersionID'] }, + 'description' => { 310 => 'Description', 372 => ['desc','dscp',"\xa9des"], 374 => 'description', 380 => 'dscp', 478 => 'Description', 480 => 'Description', 481 => 'description', 502 => 'Description' }, + 'destination' => { 132 => 0x5 }, + 'destinationcity' => { 355 => 0x24, 361 => 0x3 }, + 'destinationcitycode' => { 362 => 0x1001 }, + 'destinationdst' => { 355 => 0x26, 361 => '0.3' }, + 'developmentdynamicrange' => { 127 => 0x1403 }, + 'deviantmatrixcustom' => { 138 => 0x7de }, + 'deviantmatrixdaylight' => { 138 => 0x7da }, + 'deviantmatrixflash' => { 138 => 0x7dd }, + 'deviantmatrixfluorescent' => { 138 => 0x7dc }, + 'deviantmatrixtungsten' => { 138 => 0x7db }, + 'deviantwhitecustom' => { 138 => 0x842 }, + 'deviantwhitedaylight' => { 138 => 0x83e }, + 'deviantwhiteflash' => { 138 => 0x841 }, + 'deviantwhitefluorescent' => { 138 => 0x840 }, + 'deviantwhitetungsten' => { 138 => 0x83f }, + 'device' => { 494 => 'device' }, + 'devicesettingdescription' => { 484 => 'DeviceSettingDescription' }, + 'devicesettingdescriptioncolumns' => { 484 => [\'DeviceSettingDescription','DeviceSettingDescriptionColumns'] }, + 'devicesettingdescriptionrows' => { 484 => [\'DeviceSettingDescription','DeviceSettingDescriptionRows'] }, + 'devicesettingdescriptionsettings' => { 484 => [\'DeviceSettingDescription','DeviceSettingDescriptionSettings'] }, + 'devicetype' => { 394 => 0x2 }, + 'dewarpdata' => { 116 => 'DewarpData' }, + 'dewarpflag' => { 116 => 'DewarpFlag' }, + 'dialdirectiontvav' => { 84 => 0x706 }, + 'dietaryneeds' => { 496 => 'dietaryNeeds' }, + 'diffractioncompensation' => { 228 => 0x142, 229 => 0x1a2, 252 => 0xc4a0 }, + 'diffractioncorrection' => { 320 => 0xbc, 345 => 0x3 }, + 'diffractioncorrectionon' => { 103 => 0x2070b }, + 'digitalcreationdate' => { 131 => 0x3e }, + 'digitalcreationtime' => { 131 => 0x3f }, + 'digitaldeehighlightadj' => { 237 => 0x202 }, + 'digitaldeeshadowadj' => { 237 => 0x200 }, + 'digitaldeethreshold' => { 237 => 0x201 }, + 'digitalfilter' => { 397 => 0x59 }, + 'digitalfilter01' => { 342 => 0x5 }, + 'digitalfilter02' => { 342 => 0x16 }, + 'digitalfilter03' => { 342 => 0x27 }, + 'digitalfilter04' => { 342 => 0x38 }, + 'digitalfilter05' => { 342 => 0x49 }, + 'digitalfilter06' => { 342 => 0x5a }, + 'digitalfilter07' => { 342 => 0x6b }, + 'digitalfilter08' => { 342 => 0x7c }, + 'digitalfilter09' => { 342 => 0x8d }, + 'digitalfilter10' => { 342 => 0x9e }, + 'digitalfilter11' => { 342 => 0xaf }, + 'digitalfilter12' => { 342 => 0xc0 }, + 'digitalfilter13' => { 342 => 0xd1 }, + 'digitalfilter14' => { 342 => 0xe2 }, + 'digitalfilter15' => { 342 => 0xf3 }, + 'digitalfilter16' => { 342 => 0x104 }, + 'digitalfilter17' => { 342 => 0x115 }, + 'digitalfilter18' => { 342 => 0x126 }, + 'digitalfilter19' => { 342 => 0x137 }, + 'digitalfilter20' => { 342 => 0x148 }, + 'digitalgain' => { 74 => 0xb }, + 'digitalgem' => { 215 => 0x0 }, + 'digitalice' => { 237 => 0x100 }, + 'digitalimageguid' => { 490 => 'DigImageGUID' }, + 'digitalroc' => { 235 => 0x0 }, + 'digitalsourcefiletype' => { 490 => 'DigitalSourcefileType' }, + 'digitalsourcetype' => { 490 => 'DigitalSourceType' }, + 'digitalzoom' => { 34 => 0xc, 112 => 0xa, 127 => 0x1044, 140 => 0x68, 151 => 0x22, 152 => 0x1e, 156 => 'DigitalZoom', 181 => 0xc, 226 => 0x86, 262 => 0xa, 302 => 0x204, 355 => 0x1e, 362 => 0xa, 396 => 0x204, 442 => 0x12, 443 => 0x12 }, + 'digitalzoomon' => { 396 => 0x21b }, + 'digitalzoomratio' => { 119 => 0xa404, 431 => 0x200, 433 => 0x21c, 484 => 'DigitalZoomRatio' }, + 'director' => { 179 => 'WM/Director', 372 => "\xa9dir", 374 => 'director', 380 => "\xa9dir", 504 => 'director' }, + 'directorphotography' => { 504 => 'directorPhotography' }, + 'directory' => { 120 => 'Directory' }, + 'directoryindex' => { 7 => 0x137, 9 => 0x2dc, 11 => 0x17e, 13 => 0x238, 14 => 0x13f, 15 => 0x133, 16 => 0x1df, 17 => 0x1a7, 18 => 0x1f0, 19 => 0xcc, 20 => 0x1c7, 21 => 0x298, 22 => 0x1e7, 23 => 0x1e5, 24 => [0x27c,0x280], 25 => 0x2b6, 26 => 0x2bf, 28 => 0x1f7, 29 => 0x4ba }, + 'directoryindex2' => { 21 => 0x29c }, + 'directorynumber' => { 208 => 0x3, 383 => 0x12 }, + 'disableautocreation' => { 461 => 'DisableAutoCreation' }, + 'disclaimer' => { 310 => 'Disclaimer' }, + 'discnumber' => { 504 => 'discNumber' }, + 'dishtype' => { 496 => 'dishType' }, + 'disknumber' => { 372 => 'disk' }, + 'displayallafpoints' => { 84 => 0x514 }, + 'displayaperture' => { 34 => 0x23 }, + 'displayedunitsx' => { 370 => 0x2 }, + 'displayedunitsy' => { 370 => 0x6 }, + 'displayname' => { 374 => 'displayname', 493 => 'displayName' }, + 'distance1' => { 140 => 0x28 }, + 'distance2' => { 140 => 0x2c }, + 'distance3' => { 140 => 0x30 }, + 'distance4' => { 140 => 0x34 }, + 'distortion' => { 394 => 0xa050 }, + 'distortioncompensation' => { 455 => 0x8040 }, + 'distortioncontrol' => { 238 => 0x10 }, + 'distortioncorrection' => { 79 => 0x3, 103 => 0x20705, 109 => 0x67, 119 => 0x7036, 297 => 0x50b, 324 => '7.1', 345 => 0x0, 450 => 0x601, 451 => 0x5b }, + 'distortioncorrection2' => { 301 => 0x1011 }, + 'distortioncorrectionalreadyapplied' => { 475 => 'DistortionCorrectionAlreadyApplied' }, + 'distortioncorrectionon' => { 103 => '0x20705.0', 109 => 0x63 }, + 'distortioncorrectionsetting' => { 80 => 0x7, 420 => 0x2013 }, + 'distortioncorrectionvalue' => { 79 => 0x9 }, + 'distortioncorrparams' => { 119 => 0x7037, 430 => 0x1a23, 433 => 0x1870, 435 => 0x189c, 436 => 0x18cc, 437 => 0x17d0, 450 => 0x6ca, 451 => 0x64 }, + 'distortioncorrparamsnumber' => { 433 => 0x1899, 435 => 0x18c5, 436 => 0x18f5, 437 => 0x17f9 }, + 'distortioncorrparamspresent' => { 433 => 0x1898, 435 => 0x18c4, 436 => 0x18f4, 437 => 0x17f8, 439 => 0x10b, 440 => 0x10b, 450 => 0x600, 451 => 0x5a }, + 'distortioneffect' => { 103 => 0x20709 }, + 'distortionn' => { 324 => 0xc }, + 'distortionparam02' => { 324 => 0x2 }, + 'distortionparam04' => { 324 => 0x4 }, + 'distortionparam08' => { 324 => 0x8 }, + 'distortionparam09' => { 324 => 0x9 }, + 'distortionparam11' => { 324 => 0xb }, + 'distortionscale' => { 324 => 0x5 }, + 'distributor' => { 494 => 'distributor' }, + 'distributorproductid' => { 493 => 'distributorProductID' }, + 'dloon' => { 103 => '0x20706.0', 109 => 0xdc }, + 'dlosetting' => { 103 => 0x20706, 109 => 0xdd }, + 'dlosettingapplied' => { 102 => 0x4 }, + 'dloshootingdistance' => { 109 => 0xde }, + 'dloversion' => { 102 => 0x5 }, + 'dmcomment' => { 504 => 'comment' }, + 'dmdithermatrix' => { 138 => 0xc7a }, + 'dmdithermatrixheight' => { 138 => 0xc7c }, + 'dmdithermatrixwidth' => { 138 => 0xc7b }, + 'dngadobedata' => { 119 => 0xc634 }, + 'dngbackwardversion' => { 119 => 0xc613 }, + 'dngignoresidecars' => { 478 => 'DNGIgnoreSidecars', 480 => 'DNGIgnoreSidecars' }, + 'dnglensinfo' => { 119 => 0xc630 }, + 'dngprivatedata' => { 119 => 0xc634 }, + 'dngversion' => { 119 => 0xc612 }, + 'document' => { 310 => 'Document' }, + 'documentancestors' => { 492 => 'DocumentAncestors' }, + 'documenthistory' => { 131 => 0xe7 }, + 'documentid' => { 505 => 'DocumentID' }, + 'documentname' => { 119 => 0x10d }, + 'documentnotes' => { 131 => 0xe6 }, + 'doi' => { 494 => 'doi' }, + 'dopesheet' => { 490 => 'Dopesheet' }, + 'dopesheetlink' => { 490 => 'DopesheetLink' }, + 'dopesheetlinklink' => { 490 => [\'DopesheetLink','DopesheetLinkLink'] }, + 'dopesheetlinklinkqualifier' => { 490 => [\'DopesheetLink','DopesheetLinkLinkQualifier'] }, + 'doublingmicrovolts' => { 138 => 0xc82 }, + 'dpp' => { 473 => 'dpp' }, + 'dr4cameramodel' => { 104 => 0x3 }, + 'drangepriority' => { 127 => 0x1443 }, + 'drangepriorityauto' => { 127 => 0x1444 }, + 'drangepriorityfixed' => { 127 => 0x1445 }, + 'drivemode' => { 113 => 0x3103, 125 => '0.1', 181 => 0x6, 184 => 0x1e, 187 => 0xe, 191 => 0x64d0, 297 => 0x600, 355 => 0x34, 387 => 0x1002, 397 => 0x3, 407 => 0x4, 408 => 0x7e, 409 => 0x34 }, + 'drivemode2' => { 184 => 0xa, 336 => 0x7, 418 => 0xe, 425 => 0x1 }, + 'drivemodesetting' => { 409 => 0x4 }, + 'drivespeed' => { 125 => '0.2' }, + 'dspfirmwareversion' => { 355 => 0x27 }, + 'duration' => { 67 => 0x6a, 155 => 'Duration', 169 => 'Duration', 496 => 'duration', 504 => 'duration' }, + 'durationscale' => { 504 => [\'duration','durationScale'] }, + 'durationvalue' => { 504 => [\'duration','durationValue'] }, + 'dustremovaldata' => { 64 => 0x97 }, + 'dxcropalert' => { 229 => 0x23c }, + 'dynamicafarea' => { 279 => '1.4', 288 => '1.4' }, + 'dynamicareaafassist' => { 295 => 0x18 }, + 'dynamicareaafdisplay' => { 280 => '46.1', 282 => '47.1', 283 => '47.1', 292 => '47.1', 293 => '47.1' }, + 'dynamicrange' => { 127 => 0x1400 }, + 'dynamicrangeexpansion' => { 355 => 0x69, 387 => 0x100e }, + 'dynamicrangemax' => { 108 => 0x7c }, + 'dynamicrangemin' => { 108 => 0x7a }, + 'dynamicrangeoptimizer' => { 184 => 0x15, 420 => [0xb025,0xb04f], 429 => 0x1144, 430 => [0x1144,0x324], 431 => [0x1120,0x300], 432 => [0x119c,0x37c], 433 => [0x1178,0x328], 434 => [0x1030,0x50], 435 => [0x228,0x50], 436 => [0x228,0x50], 437 => [0x21b,0x4e] }, + 'dynamicrangeoptimizerbracket' => { 418 => 0x2e }, + 'dynamicrangeoptimizerlevel' => { 407 => 0x19, 408 => 0x17, 409 => 0xd, 418 => 0x79, 425 => 0x5 }, + 'dynamicrangeoptimizermode' => { 187 => 0x15, 407 => 0x18, 408 => 0x16, 418 => [0x77,0x15] }, + 'dynamicrangeoptimizersetting' => { 184 => 0x27, 409 => 0xc, 425 => 0x4 }, + 'dynamicrangesetting' => { 127 => 0x1402 }, + 'e-dialinprogram' => { 336 => '1.3' }, + 'earliestageorloweststage' => { 118 => [\'GeologicalContext','GeologicalContextEarliestAgeOrLowestStage'] }, + 'earliesteonorlowesteonothem' => { 118 => [\'GeologicalContext','GeologicalContextEarliestEonOrLowestEonothem'] }, + 'earliestepochorlowestseries' => { 118 => [\'GeologicalContext','GeologicalContextEarliestEpochOrLowestSeries'] }, + 'earliesteraorlowesterathem' => { 118 => [\'GeologicalContext','GeologicalContextEarliestEraOrLowestErathem'] }, + 'earliestperiodorlowestsystem' => { 118 => [\'GeologicalContext','GeologicalContextEarliestPeriodOrLowestSystem'] }, + 'earthpos' => { 458 => 'EarthPos' }, + 'earthposaltitude' => { 458 => [\'EarthPos','EarthPosAltitude'] }, + 'earthposlatitude' => { 458 => [\'EarthPos','EarthPosLatitude'] }, + 'earthposlongitude' => { 458 => [\'EarthPos','EarthPosLongitude'] }, + 'earthposrotationw' => { 458 => [\'EarthPos','EarthPosRotationW'] }, + 'earthposrotationx' => { 458 => [\'EarthPos','EarthPosRotationX'] }, + 'earthposrotationy' => { 458 => [\'EarthPos','EarthPosRotationY'] }, + 'earthposrotationz' => { 458 => [\'EarthPos','EarthPosRotationZ'] }, + 'earthpostimestamp' => { 458 => [\'EarthPos','EarthPosTimestamp'] }, + 'easyexposurecomp' => { 294 => '6.1' }, + 'easyexposurecompensation' => { 279 => '6.4', 280 => '6.5', 282 => '6.3', 283 => '6.3', 287 => '5.1', 288 => '4.4', 289 => '5.2', 292 => '6.3', 293 => '6.3', 295 => 0x1d }, + 'easymode' => { 34 => 0xb }, + 'edgemapslope' => { 138 => 0x930 }, + 'edgemapx1' => { 138 => 0x931 }, + 'edgemapx2' => { 138 => 0x932 }, + 'edgemapx3' => { 138 => 0x934 }, + 'edgemapx4' => { 138 => 0x935 }, + 'edgenoisereduction' => { 273 => 0x4, 455 => 0x8028 }, + 'edit1' => { 380 => "\xa9ed1" }, + 'edit2' => { 380 => "\xa9ed2" }, + 'edit3' => { 380 => "\xa9ed3" }, + 'edit4' => { 380 => "\xa9ed4" }, + 'edit5' => { 380 => "\xa9ed5" }, + 'edit6' => { 380 => "\xa9ed6" }, + 'edit7' => { 380 => "\xa9ed7" }, + 'edit8' => { 380 => "\xa9ed8" }, + 'edit9' => { 380 => "\xa9ed9" }, + 'edition' => { 494 => 'edition' }, + 'editorialupdate' => { 131 => 0x8 }, + 'editstatus' => { 131 => 0x7, 367 => 'EditStatus', 473 => 'EditStatus' }, + 'editversionname' => { 272 => 0x3d136244 }, + 'effectivelv' => { 355 => 0x2d }, + 'effectivemaxaperture' => { 219 => 0x12, 220 => 0x13, 224 => 0x14 }, + 'eissn' => { 494 => 'eIssn' }, + 'electricalblackcolumns' => { 138 => 0x1810 }, + 'electronicfront-curtainshutter' => { 282 => '5.2', 283 => '5.2', 292 => '5.3', 293 => '5.2' }, + 'electronicfrontcurtainshutter' => { 420 => 0x201a }, + 'elevation' => { 165 => 'Elevation' }, + 'email' => { 157 => 'EMail' }, + 'embargodate' => { 497 => 'embargoDate' }, + 'embdencrightsexpr' => { 490 => 'EmbdEncRightsExpr' }, + 'embeddedencodedrightsexpr' => { 490 => [\'EmbdEncRightsExpr','EmbdEncRightsExprEncRightsExpr'] }, + 'embeddedencodedrightsexprlangid' => { 490 => [\'EmbdEncRightsExpr','EmbdEncRightsExprRightsExprLangId'] }, + 'embeddedencodedrightsexprtype' => { 490 => [\'EmbdEncRightsExpr','EmbdEncRightsExprRightsExprEncType'] }, + 'embeddedxmpdigest' => { 492 => 'EmbeddedXMPDigest' }, + 'emissivity' => { 121 => 0x3 }, + 'emptyslotrelease' => { 229 => 0x625 }, + 'enablechromanoisereduction' => { 138 => 0xe6e }, + 'enablesharpening' => { 138 => 0x92e }, + 'encodedby' => { 179 => 'WM/EncodedBy', 372 => "\xa9enc" }, + 'encodedwith' => { 374 => 'Encoded_With' }, + 'encoder' => { 372 => "\xa9too", 380 => "\xa9too" }, + 'encoderid' => { 380 => "\xa9enc" }, + 'encodingtime' => { 179 => 'WM/EncodingTime' }, + 'encryptionkey' => { 394 => 0xa020 }, + 'endingpage' => { 494 => 'endingPage' }, + 'enduser' => { 307 => 'EndUser' }, + 'enduserid' => { 307 => [\'EndUser','EndUserEndUserID'] }, + 'endusername' => { 307 => [\'EndUser','EndUserEndUserName'] }, + 'energysavingmode' => { 229 => 0x648 }, + 'engineer' => { 504 => 'engineer' }, + 'enhancedarktones' => { 265 => 0x8 }, + 'enhancement' => { 112 => 0x16, 113 => 0x3016 }, + 'enhanceparams' => { 119 => 0xc7ee }, + 'enhancer' => { 301 => 0x300 }, + 'enhancervalues' => { 301 => 0x301 }, + 'envelopenumber' => { 132 => 0x28 }, + 'envelopepriority' => { 132 => 0x3c }, + 'enveloperecordversion' => { 132 => 0x0 }, + 'episode' => { 490 => 'Episode' }, + 'episodeglobaluniqueid' => { 372 => 'egid' }, + 'episodeidentifier' => { 490 => [\'Episode','EpisodeIdentifier'] }, + 'episodename' => { 490 => [\'Episode','EpisodeName'] }, + 'episodenumber' => { 490 => [\'Episode','EpisodeNumber'] }, + 'epsonimageheight' => { 302 => 0x20c }, + 'epsonimagewidth' => { 302 => 0x20b }, + 'epsonsoftware' => { 302 => 0x20d }, + 'equipmentinstitution' => { 457 => 'EquipmentInstitution' }, + 'equipmentmanufacturer' => { 457 => 'EquipmentManufacturer' }, + 'equipmentversion' => { 298 => 0x0 }, + 'ettlii' => { 84 => 0x304, 85 => 0xd, 86 => 0xe, 87 => 0x7, 88 => 0x7, 89 => 0xe }, + 'event' => { 459 => 'Event', 471 => 'Event', 490 => 'Event', 494 => 'event' }, + 'eventalias' => { 493 => 'eventAlias' }, + 'eventdate' => { 118 => [\'Event','EventEventDate'] }, + 'eventday' => { 118 => [\'Event','EventDay'] }, + 'eventearliestdate' => { 118 => [\'Event','EventEarliestDate'] }, + 'eventend' => { 493 => 'eventEnd' }, + 'eventenddayofyear' => { 118 => [\'Event','EventEndDayOfYear'] }, + 'eventfieldnotes' => { 118 => [\'Event','EventFieldNotes'] }, + 'eventfieldnumber' => { 118 => [\'Event','EventFieldNumber'] }, + 'eventhabitat' => { 118 => [\'Event','EventHabitat'] }, + 'eventid' => { 118 => [\'Event','EventEventID'], 490 => 'EventId' }, + 'eventlatestdate' => { 118 => [\'Event','EventLatestDate'] }, + 'eventmonth' => { 118 => [\'Event','EventMonth'] }, + 'eventnumber' => { 381 => 0x9, 382 => 0x37, 383 => 0x3a }, + 'eventparenteventid' => { 118 => [\'Event','EventParentEventID'] }, + 'eventremarks' => { 118 => [\'Event','EventEventRemarks'] }, + 'eventsamplesizeunit' => { 118 => [\'Event','EventSampleSizeUnit'] }, + 'eventsamplesizevalue' => { 118 => [\'Event','EventSampleSizeValue'] }, + 'eventsamplingeffort' => { 118 => [\'Event','EventSamplingEffort'] }, + 'eventsamplingprotocol' => { 118 => [\'Event','EventSamplingProtocol'] }, + 'eventstart' => { 493 => 'eventStart' }, + 'eventstartdayofyear' => { 118 => [\'Event','EventStartDayOfYear'] }, + 'eventsubtype' => { 493 => 'eventSubtype' }, + 'eventtime' => { 118 => [\'Event','EventEventTime'] }, + 'eventtype' => { 493 => 'eventType' }, + 'eventverbatimeventdate' => { 118 => [\'Event','EventVerbatimEventDate'] }, + 'eventyear' => { 118 => [\'Event','EventYear'] }, + 'evfgrid' => { 295 => 0x165 }, + 'evfimageframe' => { 295 => 0x164 }, + 'evfreleaseindicator' => { 295 => 0x24f }, + 'evfwarmdisplaybrightness' => { 295 => 0x24d }, + 'evfwarmdisplaymode' => { 295 => 0x24b }, + 'evsteps' => { 336 => '1.2', 338 => 0x0 }, + 'evstepsize' => { 284 => '5.1', 285 => '6.1', 286 => '6.1', 290 => '0.7' }, + 'exclusivecoverage' => { 468 => 'ExclusiveCoverage' }, + 'exclusivityenddate' => { 497 => 'exclusivityEndDate' }, + 'excursiontolerance' => { 133 => 0x82 }, + 'executiveproducer' => { 372 => "\xa9xpd" }, + 'exif' => { 120 => 'EXIF' }, + 'exifbyteorder' => { 120 => 'ExifByteOrder' }, + 'exifcamerainfo' => { 131 => 0xe8 }, + 'exifimageheight' => { 119 => 0xa003, 484 => 'PixelYDimension' }, + 'exifimagewidth' => { 119 => 0xa002, 484 => 'PixelXDimension' }, + 'exifunicodebyteorder' => { 120 => 'ExifUnicodeByteOrder' }, + 'exifversion' => { 119 => 0x9000, 484 => 'ExifVersion' }, + 'exitpupilposition' => { 219 => 0x4, 220 => 0x4, 224 => 0x4 }, + 'expirationdate' => { 131 => 0x25, 497 => 'expirationDate' }, + 'expirationtime' => { 131 => 0x26 }, + 'exposure' => { 119 => 0xfe51, 478 => 'Exposure', 480 => 'Exposure' }, + 'exposure2012' => { 478 => 'Exposure2012', 480 => 'Exposure2012' }, + 'exposureadj' => { 270 => 0x0 }, + 'exposureadj2' => { 270 => 0x12 }, + 'exposureadjust' => { 397 => 0xc }, + 'exposurebracketingindicatorlast' => { 184 => 0x52 }, + 'exposurebracketshotnumber' => { 187 => 0x2d, 418 => 0x2f }, + 'exposurebracketstepsize' => { 336 => 0x8 }, + 'exposurebracketvalue' => { 226 => 0x19 }, + 'exposurecompautocancel' => { 84 => 0x113 }, + 'exposurecompensation' => { 77 => 0x6, 93 => 0x0, 119 => 0x9204, 140 => 0x24, 156 => 'ExposureComp', 176 => 'ExposureCompensation', 181 => 0xd, 182 => 0x53, 183 => 0x1e, 187 => 0x49c0, 302 => 0x1006, 355 => 0x16, 364 => 0x402, 394 => 0xa013, 397 => [0xc,0x35,0x4d], 429 => 0x114c, 430 => 0x114c, 431 => 0x1128, 433 => 0x1180, 434 => 0x1038, 435 => 0x230, 436 => 0x230, 437 => 0x223, 484 => 'ExposureBiasValue' }, + 'exposurecompensation2' => { 425 => [0x24,0x26,0x2a] }, + 'exposurecompensationmode' => { 184 => 0x47, 187 => 0x2a }, + 'exposurecompensationset' => { 407 => 0x3, 408 => 0x3, 409 => 0x3, 425 => 0x1e }, + 'exposurecompensationsetting' => { 184 => 0x1 }, + 'exposurecompstepsize' => { 279 => '6.3', 280 => '7.3', 282 => '7.3', 283 => '7.3', 288 => '4.3', 292 => '7.3', 293 => '7.3' }, + 'exposurecontrolstep' => { 287 => '6.1', 289 => '6.1' }, + 'exposurecontrolstepsize' => { 279 => '6.2', 280 => '7.1', 282 => '7.1', 283 => '7.1', 288 => '4.2', 292 => '7.1', 293 => '7.1', 294 => '7.1', 295 => 0x1b }, + 'exposurecount' => { 127 => 0x1032 }, + 'exposuredelaymode' => { 279 => '10.1', 280 => '11.1', 282 => '11.1', 283 => '11.1', 284 => '9.1', 285 => '10.1', 286 => '10.1', 288 => '10.4', 289 => '10.1', 290 => '6.4', 292 => '11.1', 293 => '11.1', 294 => '11.2' }, + 'exposuredifference' => { 226 => 0xe }, + 'exposuregaincustom' => { 138 => 0x89c }, + 'exposuregaindaylight' => { 138 => 0x898 }, + 'exposuregainflash' => { 138 => 0x89b }, + 'exposuregainfluorescent' => { 138 => 0x89a }, + 'exposuregaintungsten' => { 138 => 0x899 }, + 'exposureindex' => { 119 => 0xa215, 484 => 'ExposureIndex' }, + 'exposureindicator' => { 184 => 0x50 }, + 'exposurelevelincrements' => { 82 => 0x6, 83 => 0x6, 84 => 0x101, 85 => 0x5, 86 => 0x6, 87 => 0x5, 88 => 0x5, 89 => 0x6, 90 => 0x4, 407 => 0x58, 408 => 0x58 }, + 'exposurelockused' => { 466 => 'ExposureLockUsed' }, + 'exposuremode' => { 119 => 0xa402, 156 => 'ExposureMode', 181 => 0x1, 182 => 0xa, 183 => 0x0, 184 => 0x0, 187 => 0x34, 297 => 0x200, 317 => 0x40d, 397 => 0x8, 420 => 0xb041, 484 => 'ExposureMode' }, + 'exposuremodeinmanual' => { 84 => 0x10b }, + 'exposureprogram' => { 119 => 0x8822, 387 => 0x1001, 400 => [0x17e,0x43], 407 => 0x3c, 408 => 0x3c, 409 => 0x5, 413 => 0x14, 418 => 0x3f, 425 => 0x2, 429 => 0x1175, 430 => 0x1179, 431 => 0x1155, 432 => 0x11d1, 433 => 0x11ad, 434 => 0x1065, 435 => 0x25d, 436 => 0x25d, 437 => 0x24c, 447 => 0xb, 448 => 0xc, 449 => 0xb, 451 => 0x48, 484 => 'ExposureProgram' }, + 'exposureshift' => { 297 => 0x203 }, + 'exposurestandardadjustment' => { 420 => 0x202d }, + 'exposuretime' => { 7 => 0x4, 8 => 0x4, 9 => 0x4, 10 => 0x4, 11 => 0x4, 12 => 0x4, 13 => 0x4, 14 => 0x4, 15 => 0x4, 16 => 0x4, 17 => 0x4, 18 => 0x4, 19 => 0x4, 20 => 0x4, 21 => 0x4, 22 => 0x4, 23 => 0x4, 24 => 0x4, 25 => 0x4, 26 => 0x4, 27 => 0x4, 28 => 0x4, 29 => 0x4, 30 => 0x6, 31 => 0x7, 77 => 0x16, 119 => 0x829a, 137 => 0xfd05, 140 => 0x20, 142 => 0xfa24, 144 => 0xf104, 147 => 0x12, 149 => 0x38, 151 => 0x14, 152 => 0x10, 154 => 0x10, 156 => 'ExposureTime', 181 => 0x9, 182 => 0x35, 183 => 0x48, 184 => 0x8, 187 => 0x49b8, 355 => 0x12, 394 => 0xa018, 397 => [0x32,0x4a], 407 => 0x0, 408 => 0x0, 425 => [0x21,0x23,0x27], 451 => 0x10, 484 => 'ExposureTime' }, + 'exposuretime2' => { 397 => [0x33,0x4b] }, + 'exposuretuning' => { 226 => 0x1c }, + 'exposurevalue' => { 138 => 0x3 }, + 'exposurewarning' => { 127 => 0x1302 }, + 'exrauto' => { 127 => 0x1033 }, + 'exrmode' => { 127 => 0x1034 }, + 'extdescraccessibility' => { 489 => 'ExtDescrAccessibility' }, + 'extendedmenubanks' => { 229 => 0x114 }, + 'extendedshutterspeeds' => { 295 => 0x102 }, + 'extendedwbdetect' => { 297 => 0x902 }, + 'extender' => { 298 => 0x301 }, + 'extenderfirmwareversion' => { 298 => 0x304 }, + 'extendermagnification' => { 158 => 'Magnification' }, + 'extendermake' => { 158 => 'Make' }, + 'extendermodel' => { 158 => 'Model', 298 => 0x303 }, + 'extenderserialnumber' => { 158 => 'SerialNumber', 298 => 0x302 }, + 'extenderstatus' => { 353 => 0x3 }, + 'externalflash' => { 300 => 0x1201 }, + 'externalflashae1' => { 302 => 0x101f }, + 'externalflashae1_0' => { 302 => 0x101b }, + 'externalflashae2' => { 302 => 0x1020 }, + 'externalflashae2_0' => { 302 => 0x101c }, + 'externalflashbounce' => { 300 => 0x1204, 302 => 0x1026, 343 => 0x1a }, + 'externalflashcompensation' => { 211 => 0x1b }, + 'externalflashexposurecomp' => { 226 => 0x17, 343 => 0x19 }, + 'externalflashfirmware' => { 209 => 0x6, 210 => 0x6, 211 => 0x6, 212 => 0x6, 213 => 0x6, 214 => 0x6 }, + 'externalflashflags' => { 209 => 0x8, 210 => 0x8, 211 => 0x8, 212 => 0x8 }, + 'externalflashguidenumber' => { 300 => 0x1203, 343 => '24.1' }, + 'externalflashgvalue' => { 302 => 0x1025 }, + 'externalflashmode' => { 302 => 0x1028, 343 => 0x2 }, + 'externalflashreadystate' => { 213 => '9.1' }, + 'externalflashstatus' => { 213 => '8.2' }, + 'externalflashzoom' => { 300 => 0x1205, 302 => 0x1027 }, + 'externalflashzoomoverride' => { 213 => '8.1' }, + 'externalmetadatalink' => { 490 => 'ExternalMetadataLink' }, + 'externalsensorbrightnessvalue' => { 315 => 0x311, 318 => 0x311, 319 => 0x311, 322 => 0x3408 }, + 'extrainfoversion' => { 411 => 0x1a }, + 'eyestartaf' => { 184 => 0x40 }, + 'fac100per' => { 138 => 0xe94 }, + 'fac170per' => { 138 => 0xe93 }, + 'fac18per' => { 138 => 0xe92 }, + 'face10position' => { 110 => 0x3f4, 111 => 0x1ec, 207 => 0x28, 340 => 0x12 }, + 'face10size' => { 341 => 0x12 }, + 'face11position' => { 207 => 0x2c, 340 => 0x14 }, + 'face11size' => { 341 => 0x14 }, + 'face12position' => { 207 => 0x30, 340 => 0x16 }, + 'face12size' => { 341 => 0x16 }, + 'face13position' => { 340 => 0x18 }, + 'face13size' => { 341 => 0x18 }, + 'face14position' => { 340 => 0x1a }, + 'face14size' => { 341 => 0x1a }, + 'face15position' => { 340 => 0x1c }, + 'face15size' => { 341 => 0x1c }, + 'face16position' => { 340 => 0x1e }, + 'face16size' => { 341 => 0x1e }, + 'face17position' => { 340 => 0x20 }, + 'face17size' => { 341 => 0x20 }, + 'face18position' => { 340 => 0x22 }, + 'face18size' => { 341 => 0x22 }, + 'face19position' => { 340 => 0x24 }, + 'face19size' => { 341 => 0x24 }, + 'face1position' => { 54 => 0x8, 110 => 0xd, 111 => 0x18, 207 => 0x4, 312 => 0x1, 340 => 0x0, 384 => 0xbc, 414 => 0x1, 415 => 0x0, 416 => 0x0, 417 => 0x5b }, + 'face1size' => { 341 => 0x0 }, + 'face20position' => { 340 => 0x26 }, + 'face20size' => { 341 => 0x26 }, + 'face21position' => { 340 => 0x28 }, + 'face21size' => { 341 => 0x28 }, + 'face22position' => { 340 => 0x2a }, + 'face22size' => { 341 => 0x2a }, + 'face23position' => { 340 => 0x2c }, + 'face23size' => { 341 => 0x2c }, + 'face24position' => { 340 => 0x2e }, + 'face24size' => { 341 => 0x2e }, + 'face25position' => { 340 => 0x30 }, + 'face25size' => { 341 => 0x30 }, + 'face26position' => { 340 => 0x32 }, + 'face26size' => { 341 => 0x32 }, + 'face27position' => { 340 => 0x34 }, + 'face27size' => { 341 => 0x34 }, + 'face28position' => { 340 => 0x36 }, + 'face28size' => { 341 => 0x36 }, + 'face29position' => { 340 => 0x38 }, + 'face29size' => { 341 => 0x38 }, + 'face2position' => { 54 => 0xa, 110 => 0x7c, 111 => 0x4c, 207 => 0x8, 312 => 0x5, 340 => 0x2, 384 => 0xc8, 414 => 0x6, 415 => 0x20, 416 => 0x25, 417 => 0x65 }, + 'face2size' => { 341 => 0x2 }, + 'face30position' => { 340 => 0x3a }, + 'face30size' => { 341 => 0x3a }, + 'face31position' => { 340 => 0x3c }, + 'face31size' => { 341 => 0x3c }, + 'face32position' => { 340 => 0x3e }, + 'face32size' => { 341 => 0x3e }, + 'face3position' => { 54 => 0xc, 110 => 0xeb, 111 => 0x80, 207 => 0xc, 312 => 0x9, 340 => 0x4, 384 => 0xd4, 414 => 0xb, 415 => 0x40, 416 => 0x4a, 417 => 0x6f }, + 'face3size' => { 341 => 0x4 }, + 'face4position' => { 54 => 0xe, 110 => 0x15a, 111 => 0xb4, 207 => 0x10, 312 => 0xd, 340 => 0x6, 384 => 0xe0, 414 => 0x10, 415 => 0x60, 416 => 0x6f, 417 => 0x79 }, + 'face4size' => { 341 => 0x6 }, + 'face5position' => { 54 => 0x10, 110 => 0x1c9, 111 => 0xe8, 207 => 0x14, 312 => 0x11, 340 => 0x8, 384 => 0xec, 414 => 0x15, 415 => 0x80, 416 => 0x94 }, + 'face5size' => { 341 => 0x8 }, + 'face6position' => { 54 => 0x12, 110 => 0x238, 111 => 0x11c, 207 => 0x18, 340 => 0xa, 384 => 0xf8, 414 => 0x1a, 415 => 0xa0, 416 => 0xb9 }, + 'face6size' => { 341 => 0xa }, + 'face7position' => { 54 => 0x14, 110 => 0x2a7, 111 => 0x150, 207 => 0x1c, 340 => 0xc, 384 => 0x104, 414 => 0x1f, 415 => 0xc0, 416 => 0xde }, + 'face7size' => { 341 => 0xc }, + 'face8position' => { 54 => 0x16, 110 => 0x316, 111 => 0x184, 207 => 0x20, 340 => 0xe, 384 => 0x110, 414 => 0x24, 415 => 0xe0, 416 => 0x103 }, + 'face8size' => { 341 => 0xe }, + 'face9position' => { 54 => 0x18, 110 => 0x385, 111 => 0x1b8, 207 => 0x24, 340 => 0x10 }, + 'face9size' => { 341 => 0x10 }, + 'facebalanceorigi' => { 472 => 'FaceBalanceOrigI' }, + 'facebalanceorigq' => { 472 => 'FaceBalanceOrigQ' }, + 'facebalancestrength' => { 472 => 'FaceBalanceStrength' }, + 'facebalancewarmth' => { 472 => 'FaceBalanceWarmth' }, + 'facedetect' => { 355 => 0x76, 394 => 0x100 }, + 'facedetectarea' => { 301 => 0x1201 }, + 'facedetectframecrop' => { 301 => 0x1207 }, + 'facedetectframesize' => { 54 => 0x3, 110 => 0x1, 111 => 0x4, 207 => 0x1, 301 => 0x1203, 355 => 0x77, 384 => 0xb6 }, + 'facedetection' => { 409 => 0x30, 425 => 0x19 }, + 'faceelementpositions' => { 127 => 0x4203 }, + 'faceelementselected' => { 127 => 0x4005 }, + 'faceelementtypes' => { 127 => 0x4201 }, + 'faceid' => { 474 => 'FaceID' }, + 'faceinfounknown' => { 113 => 0x2089 }, + 'facename' => { 394 => 0x123 }, + 'faceorientation' => { 111 => 0x8 }, + 'faceposition' => { 339 => 0x2, 395 => 0x4 }, + 'facepositions' => { 127 => 0x4103 }, + 'facerecognition' => { 394 => 0x120 }, + 'facesdetected' => { 54 => 0x2, 55 => 0x2, 56 => 0x3, 110 => 0x0, 111 => 0x2, 113 => 0x211c, 127 => 0x4100, 207 => 0x3, 301 => 0x1200, 320 => 0x3f, 339 => 0x0, 384 => 0xb5, 395 => 0x0, 414 => 0x0, 417 => 0x3, 428 => 0x30 }, + 'facesrecognized' => { 313 => 0x0 }, + 'facewidth' => { 55 => 0x1 }, + 'fade' => { 420 => 0x2034 }, + 'faithfuloutputhighlightpoint' => { 109 => 0x38 }, + 'faithfuloutputshadowpoint' => { 109 => 0x39 }, + 'faithfulrawcolortone' => { 109 => 0x31 }, + 'faithfulrawcontrast' => { 109 => 0x33 }, + 'faithfulrawhighlight' => { 109 => 0x79 }, + 'faithfulrawhighlightpoint' => { 109 => 0x36 }, + 'faithfulrawlinear' => { 109 => 0x34 }, + 'faithfulrawsaturation' => { 109 => 0x32 }, + 'faithfulrawshadow' => { 109 => 0x82 }, + 'faithfulrawshadowpoint' => { 109 => 0x37 }, + 'faithfulrawsharpness' => { 109 => 0x35 }, + 'faithfulunsharpmaskfineness' => { 109 => 0xac }, + 'faithfulunsharpmaskstrength' => { 109 => 0xaa }, + 'faithfulunsharpmaskthreshold' => { 109 => 0xae }, + 'far' => { 463 => 'Far' }, + 'fastresetlinetime' => { 138 => 0x1860 }, + 'feedidentifier' => { 490 => 'FeedIdentifier' }, + 'femicroadjustment' => { 84 => 0x111 }, + 'ffid' => { 482 => 'ffid' }, + 'field' => { 493 => 'field' }, + 'fieldcount' => { 302 => 0x103f }, + 'fieldofview' => { 380 => "FOV\x00" }, + 'fifoenonepixeldelay' => { 138 => 0x1901 }, + 'filecreatedate' => { 120 => 'FileCreateDate' }, + 'filedatarate' => { 504 => 'fileDataRate' }, + 'fileformat' => { 95 => 0x0, 132 => 0x14, 397 => [0x22,0x26], 420 => 0xb000 }, + 'filegroupid' => { 120 => 'FileGroupID' }, + 'fileindex' => { 7 => 0x143, 9 => 0x2d0, 11 => 0x172, 13 => 0x22c, 14 => 0x133, 15 => 0x13f, 16 => 0x1d3, 17 => 0x19b, 18 => 0x1e4, 19 => 0xd0, 20 => 0x1bb, 21 => 0x28c, 22 => 0x1db, 23 => 0x1d9, 24 => [0x270,0x274], 25 => 0x2aa, 26 => 0x2b3, 28 => 0x1eb, 29 => 0x4ae, 321 => 0x0 }, + 'fileindex2' => { 21 => 0x290 }, + 'filemodifydate' => { 120 => 'FileModifyDate' }, + 'filename' => { 120 => 'FileName' }, + 'filenameasdelivered' => { 307 => 'FileNameAsDelivered' }, + 'filenumber' => { 57 => 0x1, 64 => 0x8, 97 => 0x1817, 114 => 'Canon-FileNumber', 208 => 0x4, 383 => 0x10 }, + 'filenumbermemory' => { 181 => 0x1a }, + 'filenumbersequence' => { 279 => '12.2', 284 => '3.1', 285 => '4.1', 286 => '4.1', 288 => '11.1', 289 => '4.3', 294 => '5.2', 295 => 0x48 }, + 'filepermissions' => { 120 => 'FilePermissions' }, + 'filesource' => { 119 => 0xa300, 127 => 0x8000, 484 => 'FileSource' }, + 'fileuserid' => { 120 => 'FileUserID' }, + 'fileversion' => { 132 => 0x16 }, + 'fillflashautoreduction' => { 82 => 0xe, 83 => 0xe, 90 => 0xa }, + 'filllight' => { 478 => 'FillLight', 480 => 'FillLight' }, + 'fillorder' => { 119 => 0x10a }, + 'filmgraineffect' => { 297 => 0x538 }, + 'filmmode' => { 127 => 0x1401, 317 => 0x412, 320 => 0x42 }, + 'filmtype' => { 237 => 0x2 }, + 'filtereffect' => { 57 => 0xe, 231 => 0x37, 232 => 0x3f, 233 => 0x47, 320 => 0xa1 }, + 'filtereffectauto' => { 71 => 0xa0 }, + 'filtereffectfaithful' => { 70 => 0x70, 71 => 0x70 }, + 'filtereffectlandscape' => { 70 => 0x40, 71 => 0x40 }, + 'filtereffectmonochrome' => { 19 => 0xff, 70 => 0x88, 71 => 0x88 }, + 'filtereffectneutral' => { 70 => 0x58, 71 => 0x58 }, + 'filtereffectportrait' => { 70 => 0x28, 71 => 0x28 }, + 'filtereffectstandard' => { 70 => 0x10, 71 => 0x10 }, + 'filtereffectuserdef1' => { 70 => 0xa0, 71 => 0xb8 }, + 'filtereffectuserdef2' => { 70 => 0xb8, 71 => 0xd0 }, + 'filtereffectuserdef3' => { 70 => 0xd0, 71 => 0xe8 }, + 'finderdisplayduringexposure' => { 83 => 0x1 }, + 'finesharpness' => { 355 => 0x70 }, + 'finetuneoptcenterweighted' => { 279 => '7.2', 280 => '9.1', 282 => '9.1', 283 => '9.1', 287 => '8.1', 292 => '9.1', 293 => '9.1', 294 => '9.1', 295 => 0x23 }, + 'finetuneopthighlightweighted' => { 282 => '46.1', 283 => '46.1', 292 => '46.1', 293 => '46.1', 295 => 0x27 }, + 'finetuneoptmatrixmetering' => { 279 => '8.1', 280 => '8.2', 282 => '8.2', 283 => '8.2', 287 => '7.2', 288 => '6.1', 292 => '8.2', 293 => '8.2', 294 => '8.2', 295 => 0x21 }, + 'finetuneoptspotmetering' => { 279 => '8.2', 280 => '9.2', 282 => '9.2', 283 => '9.2', 287 => '8.2', 288 => '6.2', 292 => '9.2', 293 => '9.2', 294 => '9.2', 295 => 0x25 }, + 'finishexposure' => { 138 => 0xdbd }, + 'finishfiletype' => { 138 => 0xdb8 }, + 'finishlook' => { 138 => 0xdbc }, + 'finishnoise' => { 138 => 0xdba }, + 'finishresolution' => { 138 => 0xdb9 }, + 'finishsharpening' => { 138 => 0xdbb }, + 'firmware' => { 302 => 0x405, 397 => [0x8c,0x17,0x3b], 475 => 'Firmware' }, + 'firmware2' => { 397 => 0x57 }, + 'firmwaredate' => { 112 => 0x15, 113 => 0x2001, 381 => 0x4, 383 => 0x30 }, + 'firmwareid' => { 188 => 0x0 }, + 'firmwarename' => { 394 => 0xa001 }, + 'firmwarerevision' => { 19 => 0xa4, 64 => 0x1e, 385 => 0x0 }, + 'firmwarerevision2' => { 385 => 0xc }, + 'firmwareversion' => { 7 => 0x10b, 11 => 0x136, 14 => 0xff, 15 => 0x107, 127 => 0x1447, 138 => [0x415,0xce5], 154 => 0x57, 156 => 'FirmwareVersion', 318 => 0x320, 320 => 0x2, 322 => 0x3109, 355 => 0x230, 380 => ['CNFV','FIRM'], 382 => 0x18, 383 => 0x2a, 387 => 0x2 }, + 'firmwareversion2' => { 127 => 0x1448 }, + 'firmwareversions' => { 364 => 0x301 }, + 'firstphotodate' => { 466 => 'FirstPhotoDate' }, + 'firstpublicationdate' => { 307 => 'FirstPublicationDate' }, + 'fixtureidentifier' => { 131 => 0x16, 473 => 'FixtureIdentifier' }, + 'flash' => { 114 => 'XMP-Flash', 119 => 0x9209, 152 => 0x22, 182 => 0x1f, 183 => 0x15, 383 => 0x5a, 484 => 'Flash' }, + 'flashaction' => { 407 => 0x3e, 408 => 0x3e, 420 => 0x2017, 425 => [0x2a,0x2c,0x30] }, + 'flashaction2' => { 407 => 0x4c, 408 => 0x4c, 425 => 0x77 }, + 'flashactionexternal' => { 425 => [0x78,0x7c] }, + 'flashactivity' => { 34 => 0x1c }, + 'flashbatterylevel' => { 44 => 0x249 }, + 'flashbias' => { 320 => 0x24 }, + 'flashbits' => { 34 => 0x1d }, + 'flashburstpriority' => { 295 => 0x111 }, + 'flashbuttonfunction' => { 84 => 0x70e }, + 'flashchargelevel' => { 302 => 0x1010 }, + 'flashcolorfilter' => { 211 => 0x10, 212 => 0x10 }, + 'flashcommandermode' => { 209 => '9.1', 210 => '9.1', 211 => '9.1', 212 => '9.1' }, + 'flashcompensation' => { 138 => 0x3f3, 209 => 0xa, 210 => 0xa, 211 => 0xa, 212 => 0x27, 213 => 0xa, 214 => 0xa, 475 => 'FlashCompensation' }, + 'flashcontrol' => { 407 => 0x23, 408 => 0x1f, 409 => 0x21 }, + 'flashcontrolbuilt-in' => { 288 => '16.1', 289 => '23.1', 291 => '23.1', 292 => '24.1' }, + 'flashcontrolmode' => { 209 => '9.2', 210 => '9.2', 211 => '9.2', 212 => '9.2', 228 => 0x148, 229 => 0x1a8, 252 => 0xc4a6, 297 => 0x404 }, + 'flashcurtain' => { 320 => 0x48 }, + 'flashdefault' => { 184 => 0x42 }, + 'flashdevice' => { 302 => 0x1005 }, + 'flashdistance' => { 113 => 0x2034 }, + 'flashenergy' => { 119 => 0xa20b, 484 => 'FlashEnergy' }, + 'flashexposurebracketvalue' => { 226 => 0x18 }, + 'flashexposurecomp' => { 77 => 0xf, 127 => 0x1011, 159 => 'ExposureComp', 181 => 0x23, 186 => 0x104, 187 => 0x49c1, 226 => 0x12, 297 => 0x401, 302 => 0x1023, 355 => 0x4d, 387 => 0x100b, 397 => [0x3a,0x56], 420 => 0x104 }, + 'flashexposurecomp2' => { 256 => 0x4d2 }, + 'flashexposurecomp3' => { 211 => 0x1d }, + 'flashexposurecomp4' => { 211 => 0x27 }, + 'flashexposurecomparea' => { 280 => '38.4', 282 => '38.4', 283 => '38.4', 292 => '38.4', 293 => '38.4', 295 => 0x59 }, + 'flashexposurecompset' => { 184 => 0x10, 328 => 0xe, 407 => 0x14, 408 => 0x12, 409 => 0x23, 425 => 0x1f }, + 'flashexposurecompset2' => { 425 => [0x26,0x2c] }, + 'flashexposureindicator' => { 184 => 0x54 }, + 'flashexposureindicatorlast' => { 184 => 0x56 }, + 'flashexposureindicatornext' => { 184 => 0x55 }, + 'flashexposurelock' => { 57 => 0x19 }, + 'flashfired' => { 140 => 0x5d, 159 => 'Fired', 181 => 0x14, 255 => '590.3', 484 => [\'Flash','FlashFired'] }, + 'flashfiring' => { 84 => 0x306, 85 => 0x6, 86 => 0x7, 89 => 0x7 }, + 'flashfirmwareversion' => { 298 => 0x1002 }, + 'flashfocallength' => { 209 => 0xb, 210 => 0xc, 211 => 0xc, 212 => 0xc, 213 => 0xc }, + 'flashfunction' => { 187 => 0x31, 484 => [\'Flash','FlashFunction'] }, + 'flashgndistance' => { 209 => 0xe, 210 => 0xf, 211 => 0xf, 212 => 0xf, 213 => 0xf, 228 => 0x14e, 229 => 0x1ae, 252 => 0xc4ac }, + 'flashgroupacompensation' => { 209 => 0x11, 210 => 0x12, 211 => 0x13, 212 => 0x28, 213 => 0x28 }, + 'flashgroupacontrolmode' => { 209 => 0xf, 210 => '16.1', 211 => '17.1', 212 => '17.1', 213 => '17.1' }, + 'flashgroupaoutput' => { 209 => 0x11, 210 => 0x12, 211 => 0x13, 212 => 0x28, 213 => 0x28 }, + 'flashgroupbcompensation' => { 209 => 0x12, 210 => 0x13, 211 => 0x14, 212 => 0x29, 213 => 0x29 }, + 'flashgroupbcontrolmode' => { 209 => 0x10, 210 => '17.1', 211 => '18.1', 212 => '18.1', 213 => '18.1' }, + 'flashgroupboutput' => { 209 => 0x12, 210 => 0x13, 211 => 0x14, 212 => 0x29, 213 => 0x29 }, + 'flashgroupccompensation' => { 210 => 0x14, 211 => 0x15, 212 => 0x2a, 213 => 0x2a }, + 'flashgroupccontrolmode' => { 210 => '17.2', 211 => '18.2', 212 => '18.2', 213 => '18.2' }, + 'flashgroupcoutput' => { 210 => 0x14, 211 => 0x15, 212 => 0x2a, 213 => 0x2a }, + 'flashguidenumber' => { 77 => 0xd, 94 => 0x0, 159 => 'GuideNumber' }, + 'flashintensity' => { 112 => [0x19,0x5], 297 => 0x405 }, + 'flashlevel' => { 281 => 0x9, 420 => 0xb048 }, + 'flashmake' => { 159 => 'Make' }, + 'flashmanufacturer' => { 178 => 'FlashManufacturer' }, + 'flashmastercompensation' => { 228 => 0x162, 229 => 0x1aa, 252 => 0xc4c0 }, + 'flashmastercontrolmode' => { 228 => 0x160, 252 => 0xc4be }, + 'flashmasteroutput' => { 228 => 0x166, 252 => 0xc4c4 }, + 'flashmetering' => { 181 => 0x3f, 184 => 0x1c }, + 'flashmeteringmode' => { 7 => 0x15, 13 => 0x15, 14 => 0x15, 15 => 0x15, 16 => 0x15, 17 => 0x15, 18 => 0x15, 20 => 0x15, 22 => 0x15, 28 => 0x15 }, + 'flashmeteringsegments' => { 355 => 0x20a }, + 'flashmode' => { 112 => 0x4, 138 => 0x3f2, 140 => 0x5c, 151 => 0x27, 159 => 'Mode', 181 => 0x2, 182 => 0x20, 183 => 0x16, 184 => 0xf, 226 => 0x87, 297 => 0x400, 302 => 0x1004, 355 => 0xc, 362 => 0x4, 386 => 0x20, 387 => 0x100a, 396 => 0x225, 407 => 0x13, 408 => 0x7f, 409 => 0x20, 425 => 0x10, 429 => 0x1138, 430 => 0x1138, 431 => 0x1114, 432 => 0x1190, 433 => 0x116c, 434 => 0x1024, 435 => 0x21c, 436 => 0x21c, 437 => 0x211, 484 => [\'Flash','FlashMode'] }, + 'flashmodel' => { 159 => 'Model', 178 => 'FlashModel', 298 => 0x1001 }, + 'flashoptions' => { 336 => 0x2 }, + 'flashoptions2' => { 336 => 0x10 }, + 'flashoutput' => { 44 => 0x248, 77 => 0x21, 209 => 0xa, 210 => 0xa, 211 => 0xa, 212 => 0x27, 228 => 0x152, 229 => 0x1b2, 252 => 0xc4b0 }, + 'flashpixversion' => { 119 => 0xa000, 484 => 'FlashpixVersion' }, + 'flashredeyemode' => { 484 => [\'Flash','FlashRedEyeMode'] }, + 'flashremotecontrol' => { 228 => 0x15c, 229 => 0x1bc, 252 => 0xc4ba, 297 => 0x403 }, + 'flashreturn' => { 484 => [\'Flash','FlashReturn'] }, + 'flashserialnumber' => { 159 => 'SerialNumber', 298 => 0x1003 }, + 'flashsetting' => { 226 => 0x8 }, + 'flashshutterspeed' => { 279 => '20.2', 280 => '23.2', 282 => '23.2', 283 => '23.2', 288 => '15.2', 289 => '22.2', 290 => '7.2', 291 => '22.2', 292 => '23.2', 293 => '23.2', 294 => '23.1', 295 => 0x57 }, + 'flashsource' => { 209 => 0x4, 210 => 0x4, 211 => 0x4, 212 => 0x4, 213 => 0x4, 214 => 0x4 }, + 'flashstatus' => { 343 => 0x0, 425 => [0x82,0x86], 439 => 0x31, 440 => 0x39, 441 => 0x39 }, + 'flashstatusbuilt-in' => { 409 => [0x87,0x287] }, + 'flashstatusexternal' => { 409 => [0x88,0x288] }, + 'flashsyncspeed' => { 279 => '20.1', 280 => '23.1', 282 => '23.1', 283 => '23.1', 288 => '15.1', 289 => '22.1', 291 => '22.1', 292 => '23.1', 293 => '23.1', 295 => 0x53 }, + 'flashsyncspeedav' => { 82 => 0x3, 84 => 0x10f, 85 => 0x2, 86 => 0x3, 87 => 0x2, 88 => 0x2, 89 => 0x3, 90 => 0x6 }, + 'flashthreshold' => { 94 => 0x1 }, + 'flashtype' => { 159 => 'Type', 184 => 0x59, 226 => 0x9, 298 => 0x1000 }, + 'flashwarning' => { 289 => '30.1', 290 => '7.1', 294 => '31.1', 320 => 0x62 }, + 'flashwirelessoption' => { 228 => 0x15a, 229 => 0x1c8, 252 => 0xc4c6 }, + 'flexiblespotposition' => { 420 => 0x201d }, + 'flickadvancedirection' => { 295 => 0x25f }, + 'flickerreduce' => { 396 => 0x218 }, + 'flickerreduction' => { 127 => 0x1446, 248 => 0xe84 }, + 'flickerreductionindicator' => { 248 => 0x5e2 }, + 'flickerreductionshooting' => { 229 => 0x1a4 }, + 'flightpitchdegree' => { 116 => 'FlightPitchDegree' }, + 'flightrolldegree' => { 116 => 'FlightRollDegree' }, + 'flightxspeed' => { 116 => 'FlightXSpeed' }, + 'flightyawdegree' => { 116 => 'FlightYawDegree' }, + 'flightyspeed' => { 116 => 'FlightYSpeed' }, + 'flightzspeed' => { 116 => 'FlightZSpeed' }, + 'fliphorizontal' => { 272 => 0x76a43206 }, + 'fnumber' => { 7 => 0x3, 9 => 0x3, 11 => 0x3, 13 => 0x3, 14 => 0x3, 15 => 0x3, 16 => 0x3, 17 => 0x3, 18 => 0x3, 19 => 0x3, 20 => 0x3, 21 => 0x3, 22 => 0x3, 23 => 0x3, 24 => 0x3, 25 => 0x3, 26 => 0x3, 27 => 0x3, 28 => 0x3, 29 => 0x3, 30 => 0x5, 31 => 0x6, 77 => 0x15, 119 => 0x829d, 137 => 0xfd04, 140 => 0x1e, 142 => 0xfa23, 144 => 0xf103, 147 => 0x13, 149 => 0x3c, 151 => 0x1c, 152 => 0x18, 154 => 0xc, 163 => 'FNumber', 181 => 0xa, 182 => 0x36, 183 => 0x47, 184 => 0x9, 187 => 0x49c7, 224 => 0x38, 319 => 0x35a, 355 => 0x13, 394 => 0xa019, 397 => [0x31,0x49], 407 => 0x1, 408 => 0x1, 425 => [0x20,0x22,0x26], 484 => 'FNumber' }, + 'focaldistance' => { 464 => 'FocalDistance' }, + 'focallength' => { 7 => 0x1d, 8 => 0xa, 9 => 0x23, 10 => 0x9, 11 => 0x1d, 12 => 0x9, 13 => 0x1e, 14 => 0x1d, 15 => 0x1d, 16 => 0x1e, 17 => 0x1e, 18 => 0x1e, 19 => 0x28, 20 => 0x1e, 21 => 0x23, 22 => 0x1e, 23 => 0x1e, 24 => 0x23, 25 => 0x23, 26 => 0x23, 27 => 0x23, 28 => 0x1e, 29 => 0x23, 59 => 0x1, 113 => 0x1d, 119 => 0x920a, 147 => 0x1d, 163 => 'FocalLength', 181 => 0x12, 219 => 0xa, 220 => 0xb, 224 => [0xc,0x3c], 314 => 0x1, 355 => 0x1d, 364 => 0x403, 387 => 0x1500, 406 => 0xe, 433 => 0x1278, 434 => 0x1134, 435 => 0x32c, 436 => 0x32c, 437 => 0x30a, 484 => 'FocalLength' }, + 'focallength2' => { 425 => [0x23,0x25,0x29] }, + 'focallengthin35mmformat' => { 119 => 0xa405, 394 => 0xa01a, 484 => 'FocalLengthIn35mmFilm' }, + 'focallengthtelezoom' => { 406 => 0x10 }, + 'focalplaneafpointarea' => { 438 => 0x2 }, + 'focalplaneafpointlocation1' => { 438 => 0x6 }, + 'focalplaneafpointlocation10' => { 438 => 0x2a }, + 'focalplaneafpointlocation11' => { 438 => 0x2e }, + 'focalplaneafpointlocation12' => { 438 => 0x32 }, + 'focalplaneafpointlocation13' => { 438 => 0x36 }, + 'focalplaneafpointlocation14' => { 438 => 0x3a }, + 'focalplaneafpointlocation15' => { 438 => 0x3e }, + 'focalplaneafpointlocation2' => { 438 => 0xa }, + 'focalplaneafpointlocation3' => { 438 => 0xe }, + 'focalplaneafpointlocation4' => { 438 => 0x12 }, + 'focalplaneafpointlocation5' => { 438 => 0x16 }, + 'focalplaneafpointlocation6' => { 438 => 0x1a }, + 'focalplaneafpointlocation7' => { 438 => 0x1e }, + 'focalplaneafpointlocation8' => { 438 => 0x22 }, + 'focalplaneafpointlocation9' => { 438 => 0x26 }, + 'focalplaneafpointsused' => { 438 => 0x1 }, + 'focalplanediagonal' => { 298 => 0x103, 302 => 0x205 }, + 'focalplaneresolutionunit' => { 119 => 0xa210, 484 => 'FocalPlaneResolutionUnit' }, + 'focalplanexresolution' => { 119 => 0xa20e, 484 => 'FocalPlaneXResolution' }, + 'focalplanexsize' => { 59 => 0x2 }, + 'focalplanexunknown' => { 59 => 0x2 }, + 'focalplaneyresolution' => { 119 => 0xa20f, 484 => 'FocalPlaneYResolution' }, + 'focalplaneysize' => { 59 => 0x3 }, + 'focalplaneyunknown' => { 59 => 0x3 }, + 'focalpointx' => { 464 => 'FocalPointX' }, + 'focalpointy' => { 464 => 'FocalPointY' }, + 'focaltype' => { 10 => 0x2d, 59 => 0x0 }, + 'focalunits' => { 34 => 0x19 }, + 'focus' => { 262 => 0x8 }, + 'focusarea' => { 181 => 0x31 }, + 'focusareaselection' => { 290 => '15.2' }, + 'focusbracket' => { 320 => 0xbd }, + 'focusbracketstepsize' => { 297 => 0x308 }, + 'focuscontinuous' => { 34 => 0x20 }, + 'focusdisplayaiservoandmf' => { 84 => 0x515 }, + 'focusdistance' => { 163 => 'FocusDistance', 181 => 0x13, 187 => 0x49bb, 219 => 0x9, 220 => 0xa, 224 => [0xb,0x4e], 300 => 0x305, 314 => 0x0, 318 => 0x304, 319 => 0x304 }, + 'focusdistancelower' => { 7 => 0x45, 9 => 0x8e, 11 => 0x45, 13 => 0x56, 14 => 0x45, 15 => 0x45, 16 => 0x52, 17 => 0x52, 18 => 0x56, 20 => 0x52, 21 => 0x8e, 22 => 0x59, 23 => 0x57, 24 => 0x8e, 25 => 0x94, 26 => 0x95, 27 => 0xa7, 28 => 0x56, 29 => 0xa7, 57 => 0x15, 77 => 0x14 }, + 'focusdistancerange' => { 1 => 0xc }, + 'focusdistancerangewidth' => { 224 => 0x4c }, + 'focusdistanceupper' => { 7 => 0x43, 9 => 0x8c, 11 => 0x43, 13 => 0x54, 14 => 0x43, 15 => 0x43, 16 => 0x50, 17 => 0x50, 18 => 0x54, 20 => 0x50, 21 => 0x8c, 22 => 0x57, 23 => 0x55, 24 => 0x8c, 25 => 0x92, 26 => 0x93, 27 => 0xa5, 28 => 0x54, 29 => 0xa5, 57 => 0x14, 77 => 0x13 }, + 'focusholdbutton' => { 184 => 0x44 }, + 'focusinfoversion' => { 300 => 0x0 }, + 'focusingscreen' => { 83 => 0x0, 84 => 0x80b, 89 => 0x0 }, + 'focuslocation' => { 420 => 0x2027 }, + 'focuslocked' => { 180 => 0x14 }, + 'focusmode' => { 34 => 0x7, 112 => 0x3, 113 => [0x3003,0xd], 127 => 0x1021, 138 => 0x3f5, 140 => 0x38, 156 => 'FocusMode', 181 => 0x30, 183 => 0xe, 184 => 0xc, 226 => 0x7, 297 => 0x301, 302 => 0x100b, 320 => 0x7, 355 => 0xd, 362 => 0x3, 387 => 0x1006, 400 => [0xb,0x5], 406 => [0x15,0x1d], 407 => 0x4d, 408 => 0x4d, 420 => [0xb042,0xb04e,0x201b], 425 => 0x13, 445 => 0x16 }, + 'focusmode2' => { 126 => '0.1', 336 => '3.1', 425 => [0x2c,0x2e,0x32] }, + 'focusmodesetting' => { 281 => '10.1', 404 => 0x14, 405 => 0x15, 407 => 0x10, 408 => 0xf, 409 => 0x6 }, + 'focusmodeswitch' => { 184 => 0x58, 407 => 0x2e }, + 'focuspeakingdisplay' => { 295 => 0x235 }, + 'focuspeakinghighlightcolor' => { 295 => 0x4b }, + 'focuspeakinglevel' => { 295 => 0x49 }, + 'focuspixel' => { 127 => 0x1023 }, + 'focuspointlock' => { 295 => 0x1d3 }, + 'focuspointpersistence' => { 295 => 0x105 }, + 'focuspointwrap' => { 279 => '2.2', 280 => '2.2', 282 => '2.1', 283 => '2.1', 287 => '1.1', 288 => '2.2', 289 => '1.1', 292 => '2.2', 293 => '2.1', 294 => '2.5', 295 => 0x16 }, + 'focusposition' => { 219 => 0x8, 220 => 0x8, 355 => 0x10, 418 => 0x9bb }, + 'focusposition2' => { 425 => [0x29,0x2b,0x2f], 445 => 0x2d, 448 => 0x20 }, + 'focuspositionhorizontal' => { 194 => 0x43 }, + 'focuspositionvertical' => { 194 => 0x45 }, + 'focusprocess' => { 297 => 0x302 }, + 'focusrange' => { 34 => 0x12, 302 => 0x100a }, + 'focusrangeindex' => { 346 => '3.1' }, + 'focusringrotation' => { 84 => 0x713 }, + 'focussetting' => { 397 => 0x6 }, + 'focusshiftexposurelock' => { 228 => 0xe8, 229 => 0xf4, 252 => 0xc446 }, + 'focusshiftinterval' => { 228 => 0xe4, 229 => 0xf0, 252 => 0xc442 }, + 'focusshiftnumbershots' => { 228 => 0xdc, 229 => 0xe8, 252 => 0xc43a }, + 'focusshiftshooting' => { 261 => 0x7844 }, + 'focusshiftstepwidth' => { 228 => 0xe0, 229 => 0xec, 252 => 0xc43e }, + 'focusstatus' => { 406 => 0x19, 407 => 0x53, 408 => 0x53 }, + 'focusstepcount' => { 300 => 0x301, 302 => 0x100e }, + 'focusstepinfinity' => { 300 => 0x303, 302 => 0x103b }, + 'focusstepnear' => { 300 => 0x304, 302 => 0x103c }, + 'focustrackinglockon' => { 279 => ['1.5','4.1'], 280 => '1.4', 287 => '0.4', 288 => '3.1', 289 => '0.4', 292 => '1.4' }, + 'focuswarning' => { 127 => 0x1301 }, + 'foldername' => { 181 => 0x27 }, + 'foldernumber' => { 407 => 0x9a, 409 => [0x402,0x114,0x316] }, + 'fontcomposite' => { 509 => [\'Fonts','FontsComposite'] }, + 'fontface' => { 509 => [\'Fonts','FontsFontFace'] }, + 'fontfamily' => { 509 => [\'Fonts','FontsFontFamily'] }, + 'fontfilename' => { 509 => [\'Fonts','FontsFontFileName'] }, + 'fontname' => { 509 => [\'Fonts','FontsFontName'] }, + 'fonts' => { 509 => 'Fonts' }, + 'fonttype' => { 509 => [\'Fonts','FontsFontType'] }, + 'fontversion' => { 509 => [\'Fonts','FontsVersionString'] }, + 'for' => { 371 => 'For' }, + 'forcewrite' => { 120 => 'ForceWrite' }, + 'format' => { 380 => "\xa9fmt", 463 => 'Format', 481 => 'format', 502 => 'Format' }, + 'forwardlock' => { 499 => 'forwardlock' }, + 'forwardmatrix1' => { 119 => 0xc714 }, + 'forwardmatrix2' => { 119 => 0xc715 }, + 'forwardmatrix3' => { 119 => 0xcd34 }, + 'fossilspecimen' => { 118 => 'FossilSpecimen' }, + 'fossilspecimenmaterialsampleid' => { 118 => [\'FossilSpecimen','FossilSpecimenMaterialSampleID'] }, + 'framecount' => { 67 => [0x2,0x4] }, + 'frameheight' => { 127 => 0x3822 }, + 'framenum' => { 366 => 0xd7 }, + 'framenumber' => { 127 => 0x8003, 187 => 0x3c, 355 => 0x29 }, + 'framerate' => { 67 => [0x1,0x6], 119 => 0xc764, 127 => 0x3820 }, + 'framereadouttime' => { 374 => 'camera.framereadouttimeinmicroseconds' }, + 'framewidth' => { 127 => 0x3821 }, + 'framing' => { 493 => 'framing' }, + 'freebytes' => { 97 => 0x1 }, + 'freememorycardimages' => { 182 => [0x37,0x54], 183 => [0x2d,0x4a], 184 => 0x32 }, + 'fujiflashmode' => { 127 => 0x1010 }, + 'fullhdhighspeedrec' => { 127 => 0x3824 }, + 'fullimagesize' => { 420 => 0xb02b }, + 'fullpanoheightpixels' => { 466 => 'FullPanoHeightPixels', 467 => 'FullPanoHeightPixels' }, + 'fullpanowidthpixels' => { 466 => 'FullPanoWidthPixels', 467 => 'FullPanoWidthPixels' }, + 'fullpresssnap' => { 387 => 0x100d }, + 'fullsizeimage' => { 162 => 'data' }, + 'fullsizeimagename' => { 162 => '1Name' }, + 'fullsizeimagetype' => { 162 => '0Type' }, + 'func1button' => { 282 => '14.1', 283 => '14.1', 293 => '14.1', 295 => 0x63 }, + 'func1buttonplaybackmode' => { 295 => 0x1a5 }, + 'func1buttonplusdials' => { 282 => '42.1', 283 => '42.1', 293 => '42.1' }, + 'func2button' => { 282 => '80.1', 283 => '80.1', 293 => '80.1', 295 => 0x73 }, + 'func2buttonplaybackmode' => { 295 => 0x1a7 }, + 'func2buttonplusdials' => { 282 => '81.1' }, + 'func3button' => { 282 => '83.1', 295 => 0x119 }, + 'func3buttonplaybackmode' => { 295 => 0x1a9 }, + 'func4button' => { 295 => 0x175 }, + 'func4buttonplaybackmode' => { 295 => 0x1af }, + 'funcbutton' => { 279 => ['14.1','15.1'], 280 => '14.1', 288 => '28.1', 289 => '13.1', 292 => '14.1', 294 => '14.1' }, + 'funcbuttonplusdials' => { 279 => ['14.2','15.2'], 280 => '14.2', 288 => '31.1', 292 => '42.1' }, + 'functionbutton' => { 286 => '13.1', 290 => '5.2' }, + 'gainbase' => { 301 => 0x610 }, + 'gaincontrol' => { 119 => 0xa407, 484 => 'GainControl' }, + 'gamma' => { 119 => 0xa500, 138 => 0x8fe, 308 => 'gAMA', 325 => 0x11c, 485 => 'Gamma' }, + 'gammablackpoint' => { 105 => 0xc }, + 'gammacolortone' => { 105 => 0x3 }, + 'gammacompensatedvalue' => { 133 => 0x91 }, + 'gammacontrast' => { 105 => 0x2 }, + 'gammacurveoutputrange' => { 105 => 0xf }, + 'gammahighlight' => { 105 => 0xa }, + 'gammalinear' => { 103 => 0x20200 }, + 'gammamidpoint' => { 105 => 0xe }, + 'gammasaturation' => { 105 => 0x4 }, + 'gammashadow' => { 105 => 0x9 }, + 'gammasharpnessstrength' => { 105 => 0x8 }, + 'gammaunsharpmaskfineness' => { 105 => 0x6 }, + 'gammaunsharpmaskstrength' => { 105 => 0x5 }, + 'gammaunsharpmaskthreshold' => { 105 => 0x7 }, + 'gammawhitepoint' => { 105 => 0xd }, + 'garminsettings' => { 380 => 'pmcc' }, + 'garminsoftware' => { 380 => 'uuid' }, + 'gdalmetadata' => { 119 => 0xa480 }, + 'gdalnodata' => { 119 => 0xa481 }, + 'geimagesize' => { 127 => 0x1304 }, + 'gemake' => { 129 => 0x300 }, + 'gemodel' => { 129 => 0x207 }, + 'genre' => { 372 => ['gnre',"\xa9gen"], 374 => 'genre', 380 => ['gnre',"\xa9gen"], 490 => 'Genre', 494 => 'genre', 504 => 'genre' }, + 'genrecvid' => { 490 => [\'Genre','GenreCvId'] }, + 'genrecvtermid' => { 490 => [\'Genre','GenreCvTermId'] }, + 'genrecvtermname' => { 490 => [\'Genre','GenreCvTermName'] }, + 'genrecvtermrefinedabout' => { 490 => [\'Genre','GenreCvTermRefinedAbout'] }, + 'genreid' => { 372 => 'geID' }, + 'geography' => { 495 => 'geography' }, + 'geologicalcontext' => { 118 => 'GeologicalContext' }, + 'geologicalcontextbed' => { 118 => [\'GeologicalContext','GeologicalContextBed'] }, + 'geologicalcontextformation' => { 118 => [\'GeologicalContext','GeologicalContextFormation'] }, + 'geologicalcontextgroup' => { 118 => [\'GeologicalContext','GeologicalContextGroup'] }, + 'geologicalcontextid' => { 118 => [\'GeologicalContext','GeologicalContextGeologicalContextID'] }, + 'geologicalcontextmember' => { 118 => [\'GeologicalContext','GeologicalContextMember'] }, + 'geosync' => { 120 => 'Geosync' }, + 'geotag' => { 120 => 'Geotag' }, + 'geotiffasciiparams' => { 119 => 0x87b1 }, + 'geotiffdirectory' => { 119 => 0x87af }, + 'geotiffdoubleparams' => { 119 => 0x87b0 }, + 'geotime' => { 120 => 'Geotime' }, + 'giftftppriority' => { 468 => 'GIFTFtpPriority' }, + 'gimbalpitchdegree' => { 116 => 'GimbalPitchDegree' }, + 'gimbalreverse' => { 116 => 'GimbalReverse' }, + 'gimbalrolldegree' => { 116 => 'GimbalRollDegree' }, + 'gimbalyawdegree' => { 116 => 'GimbalYawDegree' }, + 'globalaltitude' => { 369 => 0x419 }, + 'globalangle' => { 369 => 0x40d }, + 'good' => { 504 => 'good' }, + 'googlehostheader' => { 372 => 'gshh' }, + 'googlepingmessage' => { 372 => 'gspm' }, + 'googlepingurl' => { 372 => 'gspu' }, + 'googleplusuploadcode' => { 119 => 0x9009 }, + 'googlesourcedata' => { 372 => 'gssd' }, + 'googlestarttime' => { 372 => 'gsst' }, + 'googletrackduration' => { 372 => 'gstd' }, + 'goprotype' => { 380 => 'GoPr' }, + 'gpsaltitude' => { 130 => 0x6, 160 => 'Altitude', 484 => 'GPSAltitude' }, + 'gpsaltituderef' => { 130 => 0x5, 484 => 'GPSAltitudeRef' }, + 'gpsareainformation' => { 130 => 0x1c, 484 => 'GPSAreaInformation' }, + 'gpscoordinates' => { 372 => "\xa9xyz", 374 => 'location.ISO6709', 380 => ['@xyz',"\xa9xyz"] }, + 'gpsdatestamp' => { 130 => 0x1d }, + 'gpsdatetime' => { 160 => 'DateTime', 484 => 'GPSTimeStamp' }, + 'gpsdestbearing' => { 130 => 0x18, 160 => 'Bearing', 484 => 'GPSDestBearing' }, + 'gpsdestbearingref' => { 130 => 0x17, 484 => 'GPSDestBearingRef' }, + 'gpsdestdistance' => { 130 => 0x1a, 160 => 'Distance', 484 => 'GPSDestDistance' }, + 'gpsdestdistanceref' => { 130 => 0x19, 484 => 'GPSDestDistanceRef' }, + 'gpsdestlatitude' => { 130 => 0x14, 484 => 'GPSDestLatitude' }, + 'gpsdestlatituderef' => { 130 => 0x13 }, + 'gpsdestlongitude' => { 130 => 0x16, 484 => 'GPSDestLongitude' }, + 'gpsdestlongituderef' => { 130 => 0x15 }, + 'gpsdifferential' => { 130 => 0x1e, 160 => 'Differential', 484 => 'GPSDifferential' }, + 'gpsdop' => { 130 => 0xb, 484 => 'GPSDOP' }, + 'gpshpositioningerror' => { 130 => 0x1f, 484 => 'GPSHPositioningError' }, + 'gpsimgdirection' => { 130 => 0x11, 484 => 'GPSImgDirection' }, + 'gpsimgdirectionref' => { 130 => 0x10, 484 => 'GPSImgDirectionRef' }, + 'gpslatitude' => { 114 => 'GPS-GPSLatitude', 116 => 'GpsLatitude', 130 => 0x2, 160 => 'Latitude', 484 => 'GPSLatitude' }, + 'gpslatituderef' => { 130 => 0x1 }, + 'gpslongitude' => { 114 => 'GPS-GPSLongitude', 116 => 'GpsLongitude', 130 => 0x4, 160 => 'Longitude', 484 => 'GPSLongitude' }, + 'gpslongituderef' => { 130 => 0x3 }, + 'gpslongtitude' => { 116 => 'GpsLongtitude' }, + 'gpsmapdatum' => { 130 => 0x12, 160 => 'Datum', 484 => 'GPSMapDatum' }, + 'gpsmeasuremode' => { 130 => 0xa, 160 => 'MeasureMode', 484 => 'GPSMeasureMode' }, + 'gpsposition' => { 114 => 'Exif-GPSPosition' }, + 'gpsprocessingmethod' => { 130 => 0x1b, 484 => 'GPSProcessingMethod' }, + 'gpssatellites' => { 130 => 0x8, 160 => 'Satellites', 484 => 'GPSSatellites' }, + 'gpsspeed' => { 130 => 0xd, 160 => 'Speed', 484 => 'GPSSpeed' }, + 'gpsspeedref' => { 130 => 0xc, 484 => 'GPSSpeedRef' }, + 'gpsstatus' => { 130 => 0x9, 484 => 'GPSStatus' }, + 'gpsstring' => { 138 => 0x402 }, + 'gpstimestamp' => { 130 => 0x7 }, + 'gpstrack' => { 130 => 0xf, 160 => 'Heading', 484 => 'GPSTrack' }, + 'gpstrackref' => { 130 => 0xe, 484 => 'GPSTrackRef' }, + 'gpsversionid' => { 130 => 0x0, 484 => 'GPSVersionID' }, + 'gradation' => { 297 => 0x50f }, + 'gradientbasedcorractive' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionActive'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionActive'] }, + 'gradientbasedcorramount' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionAmount'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionAmount'] }, + 'gradientbasedcorrblacks2012' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalBlacks2012'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalBlacks2012'] }, + 'gradientbasedcorrbrightness' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalBrightness'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalBrightness'] }, + 'gradientbasedcorrclarity' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalClarity'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalClarity'] }, + 'gradientbasedcorrclarity2012' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalClarity2012'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalClarity2012'] }, + 'gradientbasedcorrcontrast' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalContrast'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalContrast'] }, + 'gradientbasedcorrcontrast2012' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalContrast2012'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalContrast2012'] }, + 'gradientbasedcorrcorrectionname' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionName'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionName'] }, + 'gradientbasedcorrcorrectionsyncid' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionSyncID'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionSyncID'] }, + 'gradientbasedcorrdefringe' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalDefringe'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalDefringe'] }, + 'gradientbasedcorrdehaze' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalDehaze'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalDehaze'] }, + 'gradientbasedcorrections' => { 478 => 'GradientBasedCorrections', 480 => 'GradientBasedCorrections' }, + 'gradientbasedcorrexposure' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalExposure'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalExposure'] }, + 'gradientbasedcorrexposure2012' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalExposure2012'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalExposure2012'] }, + 'gradientbasedcorrhighlights2012' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalHighlights2012'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalHighlights2012'] }, + 'gradientbasedcorrhue' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalHue'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalHue'] }, + 'gradientbasedcorrluminancenoise' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalLuminanceNoise'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalLuminanceNoise'] }, + 'gradientbasedcorrmaskalpha' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksAlpha'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksAlpha'] }, + 'gradientbasedcorrmaskangle' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksAngle'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksAngle'] }, + 'gradientbasedcorrmaskbottom' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksBottom'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksBottom'] }, + 'gradientbasedcorrmaskcentervalue' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCenterValue'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCenterValue'] }, + 'gradientbasedcorrmaskcenterweight' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCenterWeight'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCenterWeight'] }, + 'gradientbasedcorrmaskdabs' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksDabs'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksDabs'] }, + 'gradientbasedcorrmaskfeather' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFeather'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFeather'] }, + 'gradientbasedcorrmaskflipped' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFlipped'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFlipped'] }, + 'gradientbasedcorrmaskflow' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFlow'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFlow'] }, + 'gradientbasedcorrmaskfullx' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFullX'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFullX'] }, + 'gradientbasedcorrmaskfully' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFullY'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksFullY'] }, + 'gradientbasedcorrmaskinputdigest' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksInputDigest'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksInputDigest'] }, + 'gradientbasedcorrmaskleft' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksLeft'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksLeft'] }, + 'gradientbasedcorrmaskmaskactive' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskActive'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskActive'] }, + 'gradientbasedcorrmaskmaskblendmode' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskBlendMode'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskBlendMode'] }, + 'gradientbasedcorrmaskmaskdigest' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskDigest'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskDigest'] }, + 'gradientbasedcorrmaskmaskinverted' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskInverted'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskInverted'] }, + 'gradientbasedcorrmaskmaskname' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskName'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskName'] }, + 'gradientbasedcorrmaskmasks' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasks'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasks'] }, + 'gradientbasedcorrmaskmasksalpha' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksAlpha'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksAlpha'] }, + 'gradientbasedcorrmaskmasksangle' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksAngle'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksAngle'] }, + 'gradientbasedcorrmaskmasksbottom' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksBottom'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksBottom'] }, + 'gradientbasedcorrmaskmaskscentervalue' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksCenterValue'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksCenterValue'] }, + 'gradientbasedcorrmaskmaskscenterweight' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksCenterWeight'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksCenterWeight'] }, + 'gradientbasedcorrmaskmasksdabs' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksDabs'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksDabs'] }, + 'gradientbasedcorrmaskmasksfeather' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksFeather'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksFeather'] }, + 'gradientbasedcorrmaskmasksflipped' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksFlipped'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksFlipped'] }, + 'gradientbasedcorrmaskmasksflow' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksFlow'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksFlow'] }, + 'gradientbasedcorrmaskmasksfullx' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksFullX'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksFullX'] }, + 'gradientbasedcorrmaskmasksfully' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksFullY'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksFullY'] }, + 'gradientbasedcorrmaskmasksinputdigest' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksInputDigest'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksInputDigest'] }, + 'gradientbasedcorrmaskmasksleft' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksLeft'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksLeft'] }, + 'gradientbasedcorrmaskmasksmaskactive' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskActive'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskActive'] }, + 'gradientbasedcorrmaskmasksmaskblendmode' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskBlendMode'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskBlendMode'] }, + 'gradientbasedcorrmaskmasksmaskdigest' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskDigest'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskDigest'] }, + 'gradientbasedcorrmaskmasksmaskinverted' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskInverted'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskInverted'] }, + 'gradientbasedcorrmaskmasksmaskname' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskName'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskName'] }, + 'gradientbasedcorrmaskmasksmasksubtype' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskSubType'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskSubType'] }, + 'gradientbasedcorrmaskmasksmasksyncid' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskSyncID'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskSyncID'] }, + 'gradientbasedcorrmaskmasksmaskversion' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskVersion'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskVersion'] }, + 'gradientbasedcorrmaskmasksmidpoint' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMidpoint'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMidpoint'] }, + 'gradientbasedcorrmaskmasksorigin' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksOrigin'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksOrigin'] }, + 'gradientbasedcorrmaskmasksperimetervalue' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksPerimeterValue'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksPerimeterValue'] }, + 'gradientbasedcorrmaskmasksradius' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksRadius'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksRadius'] }, + 'gradientbasedcorrmaskmasksreferencepoint' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksReferencePoint'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksReferencePoint'] }, + 'gradientbasedcorrmaskmasksright' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksRight'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksRight'] }, + 'gradientbasedcorrmaskmasksroundness' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksRoundness'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksRoundness'] }, + 'gradientbasedcorrmaskmaskssizex' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksSizeX'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksSizeX'] }, + 'gradientbasedcorrmaskmaskssizey' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksSizeY'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksSizeY'] }, + 'gradientbasedcorrmaskmaskstop' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksTop'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksTop'] }, + 'gradientbasedcorrmaskmasksubtype' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskSubType'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskSubType'] }, + 'gradientbasedcorrmaskmasksvalue' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskValue'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksMaskValue'] }, + 'gradientbasedcorrmaskmasksversion' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksVersion'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksVersion'] }, + 'gradientbasedcorrmaskmaskswhat' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksWhat'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksWhat'] }, + 'gradientbasedcorrmaskmaskswholeimagearea' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksWholeImageArea'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksWholeImageArea'] }, + 'gradientbasedcorrmaskmasksx' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksX'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksX'] }, + 'gradientbasedcorrmaskmasksy' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksY'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksY'] }, + 'gradientbasedcorrmaskmasksyncid' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskSyncID'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskSyncID'] }, + 'gradientbasedcorrmaskmaskszerox' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksZeroX'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksZeroX'] }, + 'gradientbasedcorrmaskmaskszeroy' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksZeroY'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMasksZeroY'] }, + 'gradientbasedcorrmaskmaskversion' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskVersion'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskVersion'] }, + 'gradientbasedcorrmaskmidpoint' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMidpoint'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMidpoint'] }, + 'gradientbasedcorrmaskorigin' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksOrigin'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksOrigin'] }, + 'gradientbasedcorrmaskperimetervalue' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksPerimeterValue'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksPerimeterValue'] }, + 'gradientbasedcorrmaskradius' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksRadius'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksRadius'] }, + 'gradientbasedcorrmaskrange' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMask'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMask'] }, + 'gradientbasedcorrmaskrangeareamodels' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModels'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModels'] }, + 'gradientbasedcorrmaskrangeareamodelscolorsampleinfo' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'] }, + 'gradientbasedcorrmaskrangeareamodelscomponents' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsAreaComponents'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsAreaComponents'] }, + 'gradientbasedcorrmaskrangecoloramount' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskColorAmount'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskColorAmount'] }, + 'gradientbasedcorrmaskrangedepthfeather' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthFeather'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthFeather'] }, + 'gradientbasedcorrmaskrangedepthmax' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMax'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMax'] }, + 'gradientbasedcorrmaskrangedepthmin' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMin'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMin'] }, + 'gradientbasedcorrmaskrangeinvert' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskInvert'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskInvert'] }, + 'gradientbasedcorrmaskrangelumfeather' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumFeather'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumFeather'] }, + 'gradientbasedcorrmaskrangeluminancedepthsampleinfo' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLuminanceDepthSampleInfo'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLuminanceDepthSampleInfo'] }, + 'gradientbasedcorrmaskrangelummax' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMax'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMax'] }, + 'gradientbasedcorrmaskrangelummin' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMin'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMin'] }, + 'gradientbasedcorrmaskrangelumrange' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumRange'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumRange'] }, + 'gradientbasedcorrmaskrangesampletype' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskSampleType'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskSampleType'] }, + 'gradientbasedcorrmaskrangetype' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskType'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskType'] }, + 'gradientbasedcorrmaskrangeversion' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskVersion'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksCorrectionRangeMaskVersion'] }, + 'gradientbasedcorrmaskreferencepoint' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksReferencePoint'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksReferencePoint'] }, + 'gradientbasedcorrmaskright' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksRight'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksRight'] }, + 'gradientbasedcorrmaskroundness' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksRoundness'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksRoundness'] }, + 'gradientbasedcorrmasks' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasks'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasks'] }, + 'gradientbasedcorrmasksizex' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksSizeX'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksSizeX'] }, + 'gradientbasedcorrmasksizey' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksSizeY'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksSizeY'] }, + 'gradientbasedcorrmasktop' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksTop'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksTop'] }, + 'gradientbasedcorrmaskvalue' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskValue'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksMaskValue'] }, + 'gradientbasedcorrmaskversion' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksVersion'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksVersion'] }, + 'gradientbasedcorrmaskwhat' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksWhat'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksWhat'] }, + 'gradientbasedcorrmaskwholeimagearea' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksWholeImageArea'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksWholeImageArea'] }, + 'gradientbasedcorrmaskx' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksX'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksX'] }, + 'gradientbasedcorrmasky' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksY'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksY'] }, + 'gradientbasedcorrmaskzerox' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksZeroX'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksZeroX'] }, + 'gradientbasedcorrmaskzeroy' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksZeroY'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionMasksZeroY'] }, + 'gradientbasedcorrmoire' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalMoire'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalMoire'] }, + 'gradientbasedcorrrangemask' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMask'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMask'] }, + 'gradientbasedcorrrangemaskareamodels' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskAreaModels'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskAreaModels'] }, + 'gradientbasedcorrrangemaskareamodelscolorsampleinfo' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'] }, + 'gradientbasedcorrrangemaskareamodelscomponents' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskAreaModelsAreaComponents'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskAreaModelsAreaComponents'] }, + 'gradientbasedcorrrangemaskcoloramount' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskColorAmount'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskColorAmount'] }, + 'gradientbasedcorrrangemaskdepthfeather' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskDepthFeather'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskDepthFeather'] }, + 'gradientbasedcorrrangemaskdepthmax' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskDepthMax'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskDepthMax'] }, + 'gradientbasedcorrrangemaskdepthmin' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskDepthMin'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskDepthMin'] }, + 'gradientbasedcorrrangemaskinvert' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskInvert'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskInvert'] }, + 'gradientbasedcorrrangemasklumfeather' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskLumFeather'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskLumFeather'] }, + 'gradientbasedcorrrangemaskluminancedepthsampleinfo' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskLuminanceDepthSampleInfo'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskLuminanceDepthSampleInfo'] }, + 'gradientbasedcorrrangemasklummax' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskLumMax'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskLumMax'] }, + 'gradientbasedcorrrangemasklummin' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskLumMin'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskLumMin'] }, + 'gradientbasedcorrrangemasklumrange' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskLumRange'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskLumRange'] }, + 'gradientbasedcorrrangemasksampletype' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskSampleType'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskSampleType'] }, + 'gradientbasedcorrrangemasktype' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskType'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskType'] }, + 'gradientbasedcorrrangemaskversion' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskVersion'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsCorrectionRangeMaskVersion'] }, + 'gradientbasedcorrsaturation' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalSaturation'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalSaturation'] }, + 'gradientbasedcorrshadows2012' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalShadows2012'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalShadows2012'] }, + 'gradientbasedcorrsharpness' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalSharpness'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalSharpness'] }, + 'gradientbasedcorrtemperature' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalTemperature'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalTemperature'] }, + 'gradientbasedcorrtexture' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalTexture'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalTexture'] }, + 'gradientbasedcorrtint' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalTint'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalTint'] }, + 'gradientbasedcorrtoninghue' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalToningHue'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalToningHue'] }, + 'gradientbasedcorrtoningsaturation' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalToningSaturation'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalToningSaturation'] }, + 'gradientbasedcorrwhat' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsWhat'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsWhat'] }, + 'gradientbasedcorrwhites2012' => { 478 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalWhites2012'], 480 => [\'GradientBasedCorrections','GradientBasedCorrectionsLocalWhites2012'] }, + 'grainamount' => { 478 => 'GrainAmount', 480 => 'GrainAmount' }, + 'graineffect' => { 127 => 0x1047 }, + 'grainfrequency' => { 478 => 'GrainFrequency', 480 => 'GrainFrequency' }, + 'grainseed' => { 478 => 'GrainSeed', 480 => 'GrainSeed' }, + 'grainsize' => { 478 => 'GrainSize', 480 => 'GrainSize' }, + 'graymixeraqua' => { 478 => 'GrayMixerAqua', 480 => 'GrayMixerAqua' }, + 'graymixerblue' => { 478 => 'GrayMixerBlue', 480 => 'GrayMixerBlue' }, + 'graymixergreen' => { 478 => 'GrayMixerGreen', 480 => 'GrayMixerGreen' }, + 'graymixermagenta' => { 478 => 'GrayMixerMagenta', 480 => 'GrayMixerMagenta' }, + 'graymixerorange' => { 478 => 'GrayMixerOrange', 480 => 'GrayMixerOrange' }, + 'graymixerpurple' => { 478 => 'GrayMixerPurple', 480 => 'GrayMixerPurple' }, + 'graymixerred' => { 478 => 'GrayMixerRed', 480 => 'GrayMixerRed' }, + 'graymixeryellow' => { 478 => 'GrayMixerYellow', 480 => 'GrayMixerYellow' }, + 'graypoint' => { 455 => 0x8021 }, + 'grayresponseunit' => { 119 => 0x122 }, + 'greencurvelimits' => { 108 => 0x1c4 }, + 'greencurvepoints' => { 107 => 0x53, 108 => 0x19a }, + 'greenhsl' => { 103 => 0x20913 }, + 'greenhue' => { 478 => 'GreenHue', 480 => 'GreenHue' }, + 'greensaturation' => { 478 => 'GreenSaturation', 480 => 'GreenSaturation' }, + 'griddisplay' => { 279 => '13.3', 280 => '4.3', 282 => '4.2', 283 => '4.2', 284 => '2.2', 288 => '10.5', 289 => '3.4', 290 => '6.1', 292 => '4.4', 293 => '4.2', 294 => '4.2' }, + 'gripbatteryadload' => { 334 => 0x5 }, + 'gripbatteryadnoload' => { 334 => 0x4 }, + 'gripbatterystate' => { 334 => '1.2' }, + 'group' => { 478 => 'Group', 480 => 'Group' }, + 'groupareaafillumination' => { 280 => '46.4', 283 => '47.4', 292 => '47.4' }, + 'grouping' => { 372 => ['grup',"\xa9grp"], 380 => "\xa9grp" }, + 'guid' => { 372 => 'GUID' }, + 'h2resetblackpixels' => { 138 => 0x18a6 }, + 'h3resetblackcolumns' => { 138 => 0x18ce }, + 'h3resetblackpixels' => { 138 => 0x18b0 }, + 'halftonehints' => { 119 => 0x141 }, + 'hardlink' => { 120 => 'HardLink' }, + 'hasalternative' => { 494 => 'hasAlternative' }, + 'hascorrection' => { 494 => 'hasCorrection' }, + 'hascorrectiona-lang' => { 494 => [\'hasCorrection','hasCorrectionA-lang'] }, + 'hascorrectiona-platform' => { 494 => [\'hasCorrection','hasCorrectionA-platform'] }, + 'hascorrectiontext' => { 494 => [\'hasCorrection','hasCorrectionText'] }, + 'hascrop' => { 478 => 'HasCrop', 480 => 'HasCrop' }, + 'hasextendedxmp' => { 506 => 'HasExtendedXMP' }, + 'hassettings' => { 478 => 'HasSettings', 480 => 'HasSettings' }, + 'hastranslation' => { 494 => 'hasTranslation' }, + 'hasvisibleoverprint' => { 509 => 'HasVisibleOverprint' }, + 'hasvisibletransparency' => { 509 => 'HasVisibleTransparency' }, + 'hdmioutputn-log' => { 228 => 0x35a }, + 'hdmioutputresolution' => { 229 => 0x610 }, + 'hdmiviewassist' => { 295 => 0x20f }, + 'hdr' => { 60 => 0x1, 216 => 0x4, 320 => 0x9e, 355 => 0x85, 420 => 0x200a }, + 'hdreffect' => { 60 => 0x2 }, 'hdrimagetype' => { 1 => 0xa }, - 'hdrinfoversion' => { 204 => 0x0 }, - 'hdrlevel' => { 204 => 0x5, 378 => 0x2e, 393 => 0x17 }, - 'hdrlevel2' => { 204 => 0x7 }, - 'hdrsetting' => { 378 => 0x2d, 393 => 0x16, 396 => 0x1148, 397 => 0x1148, 398 => 0x1124, 399 => 0x11a0, 400 => 0x117c, 401 => 0x1034, 402 => 0x22c, 403 => 0x22c, 404 => 0x21f }, - 'hdrshot' => { 297 => 0x76 }, - 'hdrsmoothing' => { 204 => 0x6 }, - 'headline' => { 125 => 0x69, 452 => 'Headline', 454 => 'Headline' }, - 'hierarchicalkeywords' => { 162 => [\'Keywords','KeywordsHierarchy'] }, - 'hierarchicalkeywords1' => { 162 => [\'Keywords','KeywordsHierarchyKeyword'] }, - 'hierarchicalkeywords1applied' => { 162 => [\'Keywords','KeywordsHierarchyApplied'] }, - 'hierarchicalkeywords1children' => { 162 => [\'Keywords','KeywordsHierarchyChildren'] }, - 'hierarchicalkeywords2' => { 162 => [\'Keywords','KeywordsHierarchyChildrenKeyword'] }, - 'hierarchicalkeywords2applied' => { 162 => [\'Keywords','KeywordsHierarchyChildrenApplied'] }, - 'hierarchicalkeywords2children' => { 162 => [\'Keywords','KeywordsHierarchyChildrenChildren'] }, - 'hierarchicalkeywords3' => { 162 => [\'Keywords','KeywordsHierarchyChildrenChildrenKeyword'] }, - 'hierarchicalkeywords3applied' => { 162 => [\'Keywords','KeywordsHierarchyChildrenChildrenApplied'] }, - 'hierarchicalkeywords3children' => { 162 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildren'] }, - 'hierarchicalkeywords4' => { 162 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenKeyword'] }, - 'hierarchicalkeywords4applied' => { 162 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenApplied'] }, - 'hierarchicalkeywords4children' => { 162 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenChildren'] }, - 'hierarchicalkeywords5' => { 162 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenChildrenKeyword'] }, - 'hierarchicalkeywords5applied' => { 162 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenChildrenApplied'] }, - 'hierarchicalkeywords5children' => { 162 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenChildrenChildren'] }, - 'hierarchicalkeywords6' => { 162 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenChildrenChildrenKeyword'] }, - 'hierarchicalkeywords6applied' => { 162 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenChildrenChildrenApplied'] }, - 'hierarchicalsubject' => { 433 => 'hierarchicalSubject' }, - 'highestbiostratigraphiczone' => { 112 => [\'GeologicalContext','GeologicalContextHighestBiostratigraphicZone'] }, - 'highisomultiplierblue' => { 302 => 0x1a }, - 'highisomultipliergreen' => { 302 => 0x19 }, - 'highisomultiplierred' => { 302 => 0x18 }, - 'highisonoisereduction' => { 15 => 0xbc, 16 => 0xbd, 19 => 0xbd, 27 => 0xc9, 59 => 0x5, 78 => 0x202, 211 => 0xb1, 332 => 0x71, 376 => 0x2c, 377 => 0x26, 378 => 0x26, 388 => 0x2009, 393 => 0x12, 417 => 0x42 }, - 'highisonoisereduction2' => { 388 => 0xb050 }, - 'highlight' => { 368 => 0xf }, - 'highlightadj' => { 97 => 0x2030c }, - 'highlightcolordistortreduct' => { 421 => 0x8026 }, - 'highlightlinearitylimit' => { 365 => 0xa025 }, - 'highlightprotection' => { 249 => 0x6 }, - 'highlightrecovery' => { 442 => 'HighlightRecovery' }, - 'highlights' => { 435 => 'Highlights' }, - 'highlights2012' => { 442 => 'Highlights2012' }, - 'highlightsadj' => { 421 => 0x9019 }, - 'highlightshadow' => { 297 => 0xad }, - 'highlighttone' => { 121 => 0x1041 }, - 'highlighttonepriority' => { 12 => 0x7, 15 => 0x7, 16 => 0x7, 17 => 0x7, 19 => 0x7, 21 => 0x7, 27 => 0x7, 59 => 0x3, 78 => 0x203 }, - 'highlightwarning' => { 297 => 0x8002 }, - 'highlowkeyadj' => { 332 => 0x6c }, - 'highspeedsync' => { 174 => 0x5, 376 => 0x2, 377 => 0x2 }, - 'histogramxml' => { 250 => 0x83a1a25 }, - 'history' => { 454 => 'History', 467 => 'History' }, - 'historyaction' => { 467 => [\'History','HistoryAction'] }, - 'historychanged' => { 467 => [\'History','HistoryChanged'] }, - 'historyinstanceid' => { 467 => [\'History','HistoryInstanceID'] }, - 'historyparameters' => { 467 => [\'History','HistoryParameters'] }, - 'historysoftwareagent' => { 467 => [\'History','HistorySoftwareAgent'] }, - 'historywhen' => { 467 => [\'History','HistoryWhen'] }, - 'holefilldarkdeltathreshold' => { 131 => 0xc88 }, - 'holefilldeltathreshold' => { 131 => 0xc7e }, - 'hometowncity' => { 107 => 0x3006, 332 => 0x23, 338 => 0x2 }, - 'hometowncitycode' => { 339 => 0x1000 }, - 'hometowndst' => { 332 => 0x25, 338 => '0.2' }, - 'hostcomputer' => { 113 => 0x13c }, - 'hostsoftwarerendering' => { 131 => 0xce7 }, - 'hue' => { 179 => 0x3b, 214 => 0x3d, 332 => 0x67 }, - 'hueadj' => { 253 => 0x2f, 421 => 0x8019 }, - 'hueadjust' => { 358 => 0x1016 }, - 'hueadjustment' => { 172 => 0x4a, 173 => 0x40, 211 => 0x92, 213 => 0x36 }, - 'hueadjustmentaqua' => { 442 => 'HueAdjustmentAqua' }, - 'hueadjustmentblue' => { 442 => 'HueAdjustmentBlue' }, - 'hueadjustmentgreen' => { 442 => 'HueAdjustmentGreen' }, - 'hueadjustmentmagenta' => { 442 => 'HueAdjustmentMagenta' }, - 'hueadjustmentorange' => { 442 => 'HueAdjustmentOrange' }, - 'hueadjustmentpurple' => { 442 => 'HueAdjustmentPurple' }, - 'hueadjustmentred' => { 442 => 'HueAdjustmentRed' }, - 'hueadjustmentyellow' => { 442 => 'HueAdjustmentYellow' }, - 'huesetting' => { 282 => 0x1011 }, - 'humanobservation' => { 112 => 'HumanObservation' }, - 'humanobservationday' => { 112 => [\'HumanObservation','HumanObservationDay'] }, - 'humanobservationearliestdate' => { 112 => [\'HumanObservation','HumanObservationEarliestDate'] }, - 'humanobservationenddayofyear' => { 112 => [\'HumanObservation','HumanObservationEndDayOfYear'] }, - 'humanobservationeventdate' => { 112 => [\'HumanObservation','HumanObservationEventDate'] }, - 'humanobservationeventid' => { 112 => [\'HumanObservation','HumanObservationEventID'] }, - 'humanobservationeventremarks' => { 112 => [\'HumanObservation','HumanObservationEventRemarks'] }, - 'humanobservationeventtime' => { 112 => [\'HumanObservation','HumanObservationEventTime'] }, - 'humanobservationfieldnotes' => { 112 => [\'HumanObservation','HumanObservationFieldNotes'] }, - 'humanobservationfieldnumber' => { 112 => [\'HumanObservation','HumanObservationFieldNumber'] }, - 'humanobservationhabitat' => { 112 => [\'HumanObservation','HumanObservationHabitat'] }, - 'humanobservationlatestdate' => { 112 => [\'HumanObservation','HumanObservationLatestDate'] }, - 'humanobservationmonth' => { 112 => [\'HumanObservation','HumanObservationMonth'] }, - 'humanobservationparenteventid' => { 112 => [\'HumanObservation','HumanObservationParentEventID'] }, - 'humanobservationsamplesizeunit' => { 112 => [\'HumanObservation','HumanObservationSampleSizeUnit'] }, - 'humanobservationsamplesizevalue' => { 112 => [\'HumanObservation','HumanObservationSampleSizeValue'] }, - 'humanobservationsamplingeffort' => { 112 => [\'HumanObservation','HumanObservationSamplingEffort'] }, - 'humanobservationsamplingprotocol' => { 112 => [\'HumanObservation','HumanObservationSamplingProtocol'] }, - 'humanobservationstartdayofyear' => { 112 => [\'HumanObservation','HumanObservationStartDayOfYear'] }, - 'humanobservationverbatimeventdate' => { 112 => [\'HumanObservation','HumanObservationVerbatimEventDate'] }, - 'humanobservationyear' => { 112 => [\'HumanObservation','HumanObservationYear'] }, - 'humidity' => { 113 => 0x9401, 447 => 'Humidity' }, - 'icc_profile' => { 114 => 'ICC_Profile' }, - 'iccprofilename' => { 454 => 'ICCProfile' }, - 'idccreativestyle' => { 421 => 0x8000 }, - 'idcpreviewlength' => { 421 => 0x202 }, - 'idcpreviewstart' => { 421 => 0x201 }, - 'identification' => { 112 => 'Identification' }, - 'identificationid' => { 112 => [\'Identification','IdentificationIdentificationID'] }, - 'identificationqualifier' => { 112 => [\'Identification','IdentificationIdentificationQualifier'] }, - 'identificationreferences' => { 112 => [\'Identification','IdentificationIdentificationReferences'] }, - 'identificationremarks' => { 112 => [\'Identification','IdentificationIdentificationRemarks'] }, - 'identificationverificationstatus' => { 112 => [\'Identification','IdentificationIdentificationVerificationStatus'] }, - 'identifiedby' => { 112 => [\'Identification','IdentificationIdentifiedBy'] }, - 'identifier' => { 443 => 'identifier', 464 => 'Identifier' }, - 'ifcameramodel' => { 131 => 0x9c8 }, - 'illumination' => { 268 => '0.5', 354 => 0x48 }, - 'imageabsolutex' => { 131 => 0x3fe }, - 'imageabsolutey' => { 131 => 0x3ff }, - 'imageadjustment' => { 211 => 0x80, 240 => 0x5 }, - 'imagealterationconstraints' => { 284 => 'ImageAlterationConstraints' }, - 'imagearea' => { 223 => 0x10, 226 => 0x10 }, - 'imageareaoffset' => { 332 => 0x38 }, - 'imageauthentication' => { 211 => 0x20 }, - 'imageboundary' => { 211 => 0x16 }, - 'imagecount' => { 121 => 0x1438, 211 => 0xa5, 391 => 0x11b, 406 => 0x32, 407 => 0x3a }, - 'imagecount2' => { 406 => 0x4c, 407 => [0x52,0x58] }, - 'imagecount3' => { 406 => [0x1a0,0x1aa,0x1bd], 407 => [0x19f,0x1cb,0x1cd] }, - 'imagecreator' => { 284 => 'ImageCreator' }, - 'imagecreatorid' => { 284 => [\'ImageCreator','ImageCreatorImageCreatorID'] }, - 'imagecreatorimageid' => { 284 => 'ImageCreatorImageID' }, - 'imagecreatorname' => { 284 => [\'ImageCreator','ImageCreatorImageCreatorName'] }, - 'imagecropx' => { 131 => 0x41f }, - 'imagecropy' => { 131 => 0x420 }, - 'imagedata' => { 428 => 'Data' }, - 'imagedatasize' => { 211 => 0xa2 }, - 'imagedescription' => { 113 => 0x10e, 462 => 'ImageDescription' }, - 'imageduplicationconstraints' => { 284 => 'ImageDuplicationConstraints' }, - 'imagedustoff' => { 250 => 0xfe443a45 }, - 'imageeditcount' => { 332 => 0x41 }, - 'imageediting' => { 332 => 0x32 }, - 'imageeffects' => { 358 => 0x1010 }, - 'imagefileconstraints' => { 284 => 'ImageFileConstraints' }, - 'imagefileformatasdelivered' => { 284 => 'ImageFileFormatAsDelivered' }, - 'imagefilesizeasdelivered' => { 284 => 'ImageFileSizeAsDelivered' }, - 'imagegeneration' => { 121 => 0x1436 }, - 'imageheight' => { 113 => 0x101, 178 => 0xc, 341 => 0x10d, 426 => 'ImageHeight', 462 => 'ImageLength' }, - 'imagehistory' => { 113 => 0x9213, 445 => 'ImageHistory' }, - 'imageidnumber' => { 292 => 0x340 }, - 'imagemimetype' => { 428 => 'Mime' }, - 'imagenumber' => { 113 => 0x9211, 147 => 'ImageNumber', 172 => 0xae, 173 => 0x5e, 341 => 0x113, 376 => 0x9b, 378 => [0x400,'276.1',0x314], 438 => 'ImageNumber' }, - 'imagenumber2' => { 173 => 0x62 }, - 'imageoptimization' => { 211 => 0xa9 }, - 'imageorientation' => { 125 => 0x83 }, - 'imageprocessing' => { 211 => 0x1a }, - 'imageprocessingfiledatecreated' => { 131 => 0xc81 }, - 'imageprocessingfiletagsversionnumber' => { 131 => 0xc80 }, - 'imageprocessingversion' => { 278 => 0x0 }, - 'imagequality' => { 147 => 'ImageQuality', 225 => '723.2', 226 => '732.2', 235 => '708.1', 297 => 0x1 }, - 'imagequality2' => { 274 => 0x603 }, - 'imagerank' => { 431 => 'ImageRank' }, - 'imagerbiassettlingdelaymsec' => { 131 => 0x600 }, - 'imagerboardversion' => { 131 => 0x439 }, - 'imagercols' => { 131 => 0x17d4 }, - 'imageref' => { 450 => 'ImageRef' }, - 'imageresolution' => { 131 => 0x944 }, - 'imageresolutionjpg' => { 131 => 0x945 }, - 'imagereview' => { 259 => '0.4', 268 => '0.4' }, - 'imagereviewmonitorofftime' => { 258 => '21.1', 260 => '21.1', 261 => '21.1', 265 => '20.1', 270 => '21.1', 271 => '21.1' }, - 'imagereviewtime' => { 257 => '25.1', 259 => '2.1', 262 => '19.1', 263 => '20.1', 264 => '20.1', 266 => '9.2', 267 => '20.1', 272 => '21.2' }, - 'imagerfiledatecreated' => { 131 => 0x9c5 }, - 'imagerfileproductionlevel' => { 131 => 0x9c4 }, - 'imagerfiletagsversionstandard' => { 131 => 0x9c7 }, - 'imagerpowerondelaymsec' => { 131 => 0x5fd }, - 'imagerrows' => { 131 => 0x17de }, - 'imagesegmentlines' => { 131 => 0x184d }, - 'imagesegmentstartline' => { 131 => 0x184c }, - 'imagesize' => { 153 => 'ImageSize' }, - 'imagesizerestriction' => { 459 => 'imageSizeRestriction' }, - 'imagesourcedata' => { 113 => 0x935c }, - 'imagespace' => { 131 => 0x909 }, - 'imagestabilization' => { 33 => 0x22, 107 => 0x3020, 121 => 0x1422, 147 => 'ImageStabilization', 172 => 0xbd, 173 => 0x71, 174 => 0x57, 175 => 0x0, 176 => [0x18,0x107,0x113], 177 => 0x49c2, 211 => 0xac, 274 => 0x604, 277 => 0x1600, 297 => 0x1a, 381 => 0x12, 382 => 0x11, 388 => 0xb026 }, - 'imagestabilization2' => { 380 => 0xa }, - 'imagestabilizationsetting' => { 177 => 0x14, 376 => 0x3d, 377 => 0x3d, 387 => 0x14 }, - 'imagestyle' => { 376 => 0x2d, 377 => 0x27 }, - 'imagesupplier' => { 284 => 'ImageSupplier' }, - 'imagesupplierid' => { 284 => [\'ImageSupplier','ImageSupplierImageSupplierID'] }, - 'imagesupplierimageid' => { 284 => 'ImageSupplierImageID' }, - 'imagesuppliername' => { 284 => [\'ImageSupplier','ImageSupplierImageSupplierName'] }, - 'imagetemperaturemax' => { 115 => 0x1 }, - 'imagetemperaturemin' => { 115 => 0x2 }, - 'imagetone' => { 332 => 0x4f }, - 'imagetype' => { 125 => 0x82, 284 => 'ImageType' }, - 'imageuniqueid' => { 1 => 0x15, 60 => 0x28, 113 => 0xa420, 445 => 'ImageUniqueID', 446 => 'ImageUniqueID' }, - 'imagewidth' => { 113 => 0x100, 178 => 0xe, 341 => 0x10c, 426 => 'ImageWidth', 462 => 'ImageWidth' }, - 'inclinationangle' => { 421 => 0x900f }, - 'inclinationcorrection' => { 421 => 0x900e }, - 'incrementaltemperature' => { 442 => 'IncrementalTemperature' }, - 'incrementaltint' => { 442 => 'IncrementalTint' }, - 'industry' => { 456 => 'industry', 457 => 'industry' }, - 'infobuttonwhenshooting' => { 78 => 0x409 }, - 'infraredilluminator' => { 353 => 0x28 }, - 'ingredientexclusion' => { 458 => 'ingredientExclusion' }, - 'ingredients' => { 467 => 'Ingredients' }, - 'ingredientsalternatepaths' => { 467 => [\'Ingredients','IngredientsAlternatePaths'] }, - 'ingredientsdocumentid' => { 467 => [\'Ingredients','IngredientsDocumentID'] }, - 'ingredientsfilepath' => { 467 => [\'Ingredients','IngredientsFilePath'] }, - 'ingredientsfrompart' => { 467 => [\'Ingredients','IngredientsFromPart'] }, - 'ingredientsinstanceid' => { 467 => [\'Ingredients','IngredientsInstanceID'] }, - 'ingredientslastmodifydate' => { 467 => [\'Ingredients','IngredientsLastModifyDate'] }, - 'ingredientslasturl' => { 467 => [\'Ingredients','IngredientsLastURL'] }, - 'ingredientslinkcategory' => { 467 => [\'Ingredients','IngredientsLinkCategory'] }, - 'ingredientslinkform' => { 467 => [\'Ingredients','IngredientsLinkForm'] }, - 'ingredientsmanager' => { 467 => [\'Ingredients','IngredientsManager'] }, - 'ingredientsmanagervariant' => { 467 => [\'Ingredients','IngredientsManagerVariant'] }, - 'ingredientsmanageto' => { 467 => [\'Ingredients','IngredientsManageTo'] }, - 'ingredientsmanageui' => { 467 => [\'Ingredients','IngredientsManageUI'] }, - 'ingredientsmaskmarkers' => { 467 => [\'Ingredients','IngredientsMaskMarkers'] }, - 'ingredientsoriginaldocumentid' => { 467 => [\'Ingredients','IngredientsOriginalDocumentID'] }, - 'ingredientspartmapping' => { 467 => [\'Ingredients','IngredientsPartMapping'] }, - 'ingredientsplacedresolutionunit' => { 467 => [\'Ingredients','IngredientsPlacedResolutionUnit'] }, - 'ingredientsplacedxresolution' => { 467 => [\'Ingredients','IngredientsPlacedXResolution'] }, - 'ingredientsplacedyresolution' => { 467 => [\'Ingredients','IngredientsPlacedYResolution'] }, - 'ingredientsrenditionclass' => { 467 => [\'Ingredients','IngredientsRenditionClass'] }, - 'ingredientsrenditionparams' => { 467 => [\'Ingredients','IngredientsRenditionParams'] }, - 'ingredientstopart' => { 467 => [\'Ingredients','IngredientsToPart'] }, - 'ingredientsversionid' => { 467 => [\'Ingredients','IngredientsVersionID'] }, - 'initialafpointaiservoaf' => { 78 => 0x51e }, + 'hdrinfoversion' => { 216 => 0x0 }, + 'hdrlevel' => { 216 => 0x5, 409 => 0x2e, 425 => 0x17 }, + 'hdrlevel2' => { 216 => 0x7 }, + 'hdrpmakernote' => { 461 => 'hdrp_makernote' }, + 'hdrsetting' => { 409 => 0x2d, 425 => 0x16, 429 => 0x1148, 430 => 0x1148, 431 => 0x1124, 432 => 0x11a0, 433 => 0x117c, 434 => 0x1034, 435 => 0x22c, 436 => 0x22c, 437 => 0x21f }, + 'hdrshot' => { 320 => 0x76 }, + 'hdrsmoothing' => { 216 => 0x6 }, + 'hdvideo' => { 372 => 'hdvd' }, + 'headline' => { 131 => 0x69, 490 => 'Headline', 492 => 'Headline' }, + 'hierarchicalkeywords' => { 171 => [\'Keywords','KeywordsHierarchy'] }, + 'hierarchicalkeywords1' => { 171 => [\'Keywords','KeywordsHierarchyKeyword'] }, + 'hierarchicalkeywords1applied' => { 171 => [\'Keywords','KeywordsHierarchyApplied'] }, + 'hierarchicalkeywords1children' => { 171 => [\'Keywords','KeywordsHierarchyChildren'] }, + 'hierarchicalkeywords2' => { 171 => [\'Keywords','KeywordsHierarchyChildrenKeyword'] }, + 'hierarchicalkeywords2applied' => { 171 => [\'Keywords','KeywordsHierarchyChildrenApplied'] }, + 'hierarchicalkeywords2children' => { 171 => [\'Keywords','KeywordsHierarchyChildrenChildren'] }, + 'hierarchicalkeywords3' => { 171 => [\'Keywords','KeywordsHierarchyChildrenChildrenKeyword'] }, + 'hierarchicalkeywords3applied' => { 171 => [\'Keywords','KeywordsHierarchyChildrenChildrenApplied'] }, + 'hierarchicalkeywords3children' => { 171 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildren'] }, + 'hierarchicalkeywords4' => { 171 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenKeyword'] }, + 'hierarchicalkeywords4applied' => { 171 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenApplied'] }, + 'hierarchicalkeywords4children' => { 171 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenChildren'] }, + 'hierarchicalkeywords5' => { 171 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenChildrenKeyword'] }, + 'hierarchicalkeywords5applied' => { 171 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenChildrenApplied'] }, + 'hierarchicalkeywords5children' => { 171 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenChildrenChildren'] }, + 'hierarchicalkeywords6' => { 171 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenChildrenChildrenKeyword'] }, + 'hierarchicalkeywords6applied' => { 171 => [\'Keywords','KeywordsHierarchyChildrenChildrenChildrenChildrenChildrenApplied'] }, + 'hierarchicalsubject' => { 470 => 'hierarchicalSubject' }, + 'highestbiostratigraphiczone' => { 118 => [\'GeologicalContext','GeologicalContextHighestBiostratigraphicZone'] }, + 'highisomultiplierblue' => { 325 => 0x1a }, + 'highisomultipliergreen' => { 325 => 0x19 }, + 'highisomultiplierred' => { 325 => 0x18 }, + 'highisonoisereduction' => { 16 => 0xbc, 17 => 0xbd, 20 => 0xbd, 28 => 0xc9, 62 => 0x5, 84 => 0x202, 226 => 0xb1, 355 => 0x71, 407 => 0x2c, 408 => 0x26, 409 => 0x26, 420 => 0x2009, 425 => 0x12, 451 => 0x42 }, + 'highisonoisereduction2' => { 420 => 0xb050 }, + 'highlight' => { 397 => 0xf }, + 'highlight2012' => { 478 => 'Highlight2012', 480 => 'Highlight2012' }, + 'highlightadj' => { 103 => 0x2030c }, + 'highlightcolordistortreduct' => { 455 => 0x8026 }, + 'highlightlinearitylimit' => { 394 => 0xa025 }, + 'highlightprotection' => { 271 => 0x6 }, + 'highlightrecovery' => { 478 => 'HighlightRecovery', 480 => 'HighlightRecovery' }, + 'highlights' => { 420 => 0x2033, 472 => 'Highlights' }, + 'highlights2012' => { 478 => 'Highlights2012', 480 => 'Highlights2012' }, + 'highlightsadj' => { 455 => 0x9019 }, + 'highlightshadow' => { 320 => 0xad }, + 'highlighttone' => { 127 => 0x1041 }, + 'highlighttonepriority' => { 13 => 0x7, 16 => 0x7, 17 => 0x7, 18 => 0x7, 20 => 0x7, 22 => 0x7, 28 => 0x7, 62 => 0x3, 84 => 0x203 }, + 'highlightwarning' => { 320 => 0x8002 }, + 'highlowkeyadj' => { 355 => 0x6c }, + 'highspeedsync' => { 184 => 0x5, 295 => 0x55, 407 => 0x2, 408 => 0x2 }, + 'hintversion' => { 380 => 'hinv' }, + 'histogramxml' => { 272 => 0x83a1a25 }, + 'history' => { 492 => 'History', 505 => 'History' }, + 'historyaction' => { 505 => [\'History','HistoryAction'] }, + 'historychanged' => { 505 => [\'History','HistoryChanged'] }, + 'historyinstanceid' => { 505 => [\'History','HistoryInstanceID'] }, + 'historyparameters' => { 505 => [\'History','HistoryParameters'] }, + 'historysoftwareagent' => { 505 => [\'History','HistorySoftwareAgent'] }, + 'historywhen' => { 505 => [\'History','HistoryWhen'] }, + 'holefilldarkdeltathreshold' => { 138 => 0xc88 }, + 'holefilldeltathreshold' => { 138 => 0xc7e }, + 'hometowncity' => { 113 => 0x3006, 355 => 0x23, 361 => 0x2 }, + 'hometowncitycode' => { 362 => 0x1000 }, + 'hometowndst' => { 355 => 0x25, 361 => '0.2' }, + 'hostcomputer' => { 119 => 0x13c }, + 'hostsoftwarerendering' => { 138 => 0xce7 }, + 'hue' => { 189 => 0x3b, 232 => 0x3d, 233 => 0x45, 355 => 0x67 }, + 'hueadj' => { 275 => 0x2f, 455 => 0x8019 }, + 'hueadjust' => { 387 => 0x1016 }, + 'hueadjustment' => { 182 => 0x4a, 183 => 0x40, 226 => 0x92, 231 => 0x36 }, + 'hueadjustmentaqua' => { 478 => 'HueAdjustmentAqua', 480 => 'HueAdjustmentAqua' }, + 'hueadjustmentblue' => { 478 => 'HueAdjustmentBlue', 480 => 'HueAdjustmentBlue' }, + 'hueadjustmentgreen' => { 478 => 'HueAdjustmentGreen', 480 => 'HueAdjustmentGreen' }, + 'hueadjustmentmagenta' => { 478 => 'HueAdjustmentMagenta', 480 => 'HueAdjustmentMagenta' }, + 'hueadjustmentorange' => { 478 => 'HueAdjustmentOrange', 480 => 'HueAdjustmentOrange' }, + 'hueadjustmentpurple' => { 478 => 'HueAdjustmentPurple', 480 => 'HueAdjustmentPurple' }, + 'hueadjustmentred' => { 478 => 'HueAdjustmentRed', 480 => 'HueAdjustmentRed' }, + 'hueadjustmentyellow' => { 478 => 'HueAdjustmentYellow', 480 => 'HueAdjustmentYellow' }, + 'huesetting' => { 305 => 0x1011 }, + 'humanobservation' => { 118 => 'HumanObservation' }, + 'humanobservationday' => { 118 => [\'HumanObservation','HumanObservationDay'] }, + 'humanobservationearliestdate' => { 118 => [\'HumanObservation','HumanObservationEarliestDate'] }, + 'humanobservationenddayofyear' => { 118 => [\'HumanObservation','HumanObservationEndDayOfYear'] }, + 'humanobservationeventdate' => { 118 => [\'HumanObservation','HumanObservationEventDate'] }, + 'humanobservationeventid' => { 118 => [\'HumanObservation','HumanObservationEventID'] }, + 'humanobservationeventremarks' => { 118 => [\'HumanObservation','HumanObservationEventRemarks'] }, + 'humanobservationeventtime' => { 118 => [\'HumanObservation','HumanObservationEventTime'] }, + 'humanobservationfieldnotes' => { 118 => [\'HumanObservation','HumanObservationFieldNotes'] }, + 'humanobservationfieldnumber' => { 118 => [\'HumanObservation','HumanObservationFieldNumber'] }, + 'humanobservationhabitat' => { 118 => [\'HumanObservation','HumanObservationHabitat'] }, + 'humanobservationlatestdate' => { 118 => [\'HumanObservation','HumanObservationLatestDate'] }, + 'humanobservationmonth' => { 118 => [\'HumanObservation','HumanObservationMonth'] }, + 'humanobservationparenteventid' => { 118 => [\'HumanObservation','HumanObservationParentEventID'] }, + 'humanobservationsamplesizeunit' => { 118 => [\'HumanObservation','HumanObservationSampleSizeUnit'] }, + 'humanobservationsamplesizevalue' => { 118 => [\'HumanObservation','HumanObservationSampleSizeValue'] }, + 'humanobservationsamplingeffort' => { 118 => [\'HumanObservation','HumanObservationSamplingEffort'] }, + 'humanobservationsamplingprotocol' => { 118 => [\'HumanObservation','HumanObservationSamplingProtocol'] }, + 'humanobservationstartdayofyear' => { 118 => [\'HumanObservation','HumanObservationStartDayOfYear'] }, + 'humanobservationverbatimeventdate' => { 118 => [\'HumanObservation','HumanObservationVerbatimEventDate'] }, + 'humanobservationyear' => { 118 => [\'HumanObservation','HumanObservationYear'] }, + 'humidity' => { 119 => 0x9401, 485 => 'Humidity' }, + 'icc_profile' => { 120 => 'ICC_Profile' }, + 'iccprofilename' => { 492 => 'ICCProfile' }, + 'iconuri' => { 380 => 'icnu' }, + 'idccreativestyle' => { 455 => 0x8000 }, + 'idcpreviewlength' => { 455 => 0x202 }, + 'idcpreviewstart' => { 455 => 0x201 }, + 'identification' => { 118 => 'Identification' }, + 'identificationid' => { 118 => [\'Identification','IdentificationIdentificationID'] }, + 'identificationqualifier' => { 118 => [\'Identification','IdentificationIdentificationQualifier'] }, + 'identificationreferences' => { 118 => [\'Identification','IdentificationIdentificationReferences'] }, + 'identificationremarks' => { 118 => [\'Identification','IdentificationIdentificationRemarks'] }, + 'identificationverificationstatus' => { 118 => [\'Identification','IdentificationIdentificationVerificationStatus'] }, + 'identifiedby' => { 118 => [\'Identification','IdentificationIdentifiedBy'] }, + 'identifiedbyid' => { 118 => [\'Identification','IdentificationIdentifiedByID'] }, + 'identifier' => { 481 => 'identifier', 502 => 'Identifier' }, + 'ifcameramodel' => { 138 => 0x9c8 }, + 'illuminantdata1' => { 119 => 0xcd35 }, + 'illuminantdata2' => { 119 => 0xcd36 }, + 'illuminantdata3' => { 119 => 0xcd37 }, + 'illumination' => { 290 => '0.5', 382 => 0x48 }, + 'imageabsolutex' => { 138 => 0x3fe }, + 'imageabsolutey' => { 138 => 0x3ff }, + 'imageadjustment' => { 226 => 0x80, 262 => 0x5 }, + 'imagealterationconstraints' => { 307 => 'ImageAlterationConstraints' }, + 'imagearea' => { 242 => 0x10, 245 => 0x10 }, + 'imageareaoffset' => { 355 => 0x38 }, + 'imageauthentication' => { 226 => 0x20 }, + 'imageboundary' => { 226 => 0x16 }, + 'imagecount' => { 127 => 0x1438, 226 => 0xa5, 423 => 0x11b }, + 'imagecreator' => { 307 => 'ImageCreator' }, + 'imagecreatorid' => { 307 => [\'ImageCreator','ImageCreatorImageCreatorID'] }, + 'imagecreatorimageid' => { 307 => 'ImageCreatorImageID' }, + 'imagecreatorname' => { 307 => [\'ImageCreator','ImageCreatorImageCreatorName'] }, + 'imagecropx' => { 138 => 0x41f }, + 'imagecropy' => { 138 => 0x420 }, + 'imagedata' => { 465 => 'Data' }, + 'imagedatasize' => { 226 => 0xa2 }, + 'imagedescription' => { 119 => 0x10e, 500 => 'ImageDescription' }, + 'imageduplicationconstraints' => { 307 => 'ImageDuplicationConstraints' }, + 'imagedustoff' => { 272 => 0xfe443a45 }, + 'imageeditcount' => { 355 => 0x41 }, + 'imageediting' => { 355 => 0x32 }, + 'imageeffects' => { 387 => 0x1010 }, + 'imagefileconstraints' => { 307 => 'ImageFileConstraints' }, + 'imagefileformatasdelivered' => { 307 => 'ImageFileFormatAsDelivered' }, + 'imagefilesizeasdelivered' => { 307 => 'ImageFileSizeAsDelivered' }, + 'imagegeneration' => { 127 => 0x1436 }, + 'imageheight' => { 119 => 0x101, 188 => 0xc, 364 => 0x10d, 463 => 'ImageHeight', 500 => 'ImageLength' }, + 'imagehistory' => { 119 => 0x9213, 483 => 'ImageHistory' }, + 'imageidnumber' => { 315 => 0x340 }, + 'imagemimetype' => { 465 => 'Mime' }, + 'imagenumber' => { 119 => 0x9211, 156 => 'ImageNumber', 182 => 0xae, 183 => 0x5e, 364 => 0x113, 407 => 0x9b, 409 => [0x400,'276.1',0x314], 475 => 'ImageNumber' }, + 'imagenumber2' => { 183 => 0x62 }, + 'imageoptimization' => { 226 => 0xa9 }, + 'imageorientation' => { 131 => 0x83 }, + 'imageprocessing' => { 226 => 0x1a }, + 'imageprocessingfiledatecreated' => { 138 => 0xc81 }, + 'imageprocessingfiletagsversionnumber' => { 138 => 0xc80 }, + 'imageprocessingversion' => { 301 => 0x0 }, + 'imagequality' => { 156 => 'ImageQuality', 244 => '723.2', 245 => '732.2', 255 => '708.1', 320 => 0x1 }, + 'imagequality2' => { 297 => 0x603 }, + 'imagerank' => { 468 => 'ImageRank' }, + 'imagerbiassettlingdelaymsec' => { 138 => 0x600 }, + 'imagerboardversion' => { 138 => 0x439 }, + 'imagercols' => { 138 => 0x17d4 }, + 'imageref' => { 488 => 'ImageRef' }, + 'imageregion' => { 490 => 'ImageRegion' }, + 'imageregionboundary' => { 490 => [\'ImageRegion','ImageRegionRegionBoundary'] }, + 'imageregionboundaryh' => { 490 => [\'ImageRegion','ImageRegionRegionBoundaryRbH'] }, + 'imageregionboundaryrx' => { 490 => [\'ImageRegion','ImageRegionRegionBoundaryRbRx'] }, + 'imageregionboundaryshape' => { 490 => [\'ImageRegion','ImageRegionRegionBoundaryRbShape'] }, + 'imageregionboundaryunit' => { 490 => [\'ImageRegion','ImageRegionRegionBoundaryRbUnit'] }, + 'imageregionboundaryvertices' => { 490 => [\'ImageRegion','ImageRegionRegionBoundaryRbVertices'] }, + 'imageregionboundaryverticesx' => { 490 => [\'ImageRegion','ImageRegionRegionBoundaryRbVerticesRbX'] }, + 'imageregionboundaryverticesy' => { 490 => [\'ImageRegion','ImageRegionRegionBoundaryRbVerticesRbY'] }, + 'imageregionboundaryw' => { 490 => [\'ImageRegion','ImageRegionRegionBoundaryRbW'] }, + 'imageregionboundaryx' => { 490 => [\'ImageRegion','ImageRegionRegionBoundaryRbX'] }, + 'imageregionboundaryy' => { 490 => [\'ImageRegion','ImageRegionRegionBoundaryRbY'] }, + 'imageregionctype' => { 490 => [\'ImageRegion','ImageRegionRCtype'] }, + 'imageregionctypeidentifier' => { 490 => [\'ImageRegion','ImageRegionRCtypeIdentifier'] }, + 'imageregionctypename' => { 490 => [\'ImageRegion','ImageRegionRCtypeName'] }, + 'imageregionid' => { 490 => [\'ImageRegion','ImageRegionRId'] }, + 'imageregionname' => { 490 => [\'ImageRegion','ImageRegionName'] }, + 'imageregionrole' => { 490 => [\'ImageRegion','ImageRegionRRole'] }, + 'imageregionroleidentifier' => { 490 => [\'ImageRegion','ImageRegionRRoleIdentifier'] }, + 'imageregionrolename' => { 490 => [\'ImageRegion','ImageRegionRRoleName'] }, + 'imageresolution' => { 138 => 0x944 }, + 'imageresolutionjpg' => { 138 => 0x945 }, + 'imagereview' => { 281 => '0.4', 290 => '0.4' }, + 'imagereviewmonitorofftime' => { 280 => '21.1', 282 => '21.1', 283 => '21.1', 287 => '20.1', 292 => '21.1', 293 => '21.1', 295 => 0x39 }, + 'imagereviewtime' => { 279 => '25.1', 281 => '2.1', 284 => '19.1', 285 => '20.1', 286 => '20.1', 288 => '9.2', 289 => '20.1', 294 => '21.2' }, + 'imagerfiledatecreated' => { 138 => 0x9c5 }, + 'imagerfileproductionlevel' => { 138 => 0x9c4 }, + 'imagerfiletagsversionstandard' => { 138 => 0x9c7 }, + 'imagerotated' => { 151 => 0x2a }, + 'imagerpowerondelaymsec' => { 138 => 0x5fd }, + 'imagerrows' => { 138 => 0x17de }, + 'imagesegmentlines' => { 138 => 0x184d }, + 'imagesegmentstartline' => { 138 => 0x184c }, + 'imagesize' => { 162 => 'ImageSize' }, + 'imagesizeraw' => { 226 => 0x3e }, + 'imagesizerestriction' => { 497 => 'imageSizeRestriction' }, + 'imagesourcedata' => { 119 => 0x935c }, + 'imagespace' => { 138 => 0x909 }, + 'imagestabilization' => { 34 => 0x22, 113 => 0x3020, 127 => 0x1422, 156 => 'ImageStabilization', 182 => 0xbd, 183 => 0x71, 184 => 0x57, 185 => 0x0, 186 => [0x18,0x107,0x113], 187 => 0x49c2, 226 => 0xac, 297 => 0x604, 300 => 0x1600, 320 => 0x1a, 412 => 0x12, 413 => 0x11, 420 => 0xb026 }, + 'imagestabilization2' => { 411 => 0xa }, + 'imagestabilizationsetting' => { 187 => 0x14, 407 => 0x3d, 408 => 0x3d, 418 => 0x14 }, + 'imagestyle' => { 407 => 0x2d, 408 => 0x27 }, + 'imagesupplier' => { 307 => 'ImageSupplier' }, + 'imagesupplierid' => { 307 => [\'ImageSupplier','ImageSupplierImageSupplierID'] }, + 'imagesupplierimageid' => { 307 => 'ImageSupplierImageID' }, + 'imagesuppliername' => { 307 => [\'ImageSupplier','ImageSupplierImageSupplierName'] }, + 'imagetemperaturemax' => { 121 => 0x1 }, + 'imagetemperaturemin' => { 121 => 0x2 }, + 'imagetone' => { 355 => 0x4f }, + 'imagetype' => { 131 => 0x82, 307 => 'ImageType' }, + 'imageuniqueid' => { 1 => 0x15, 64 => 0x28, 119 => 0xa420, 483 => 'ImageUniqueID', 484 => 'ImageUniqueID' }, + 'imagewidth' => { 119 => 0x100, 188 => 0xe, 364 => 0x10c, 463 => 'ImageWidth', 500 => 'ImageWidth' }, + 'inclinationangle' => { 455 => 0x900f }, + 'inclinationcorrection' => { 455 => 0x900e }, + 'incrementaltemperature' => { 478 => 'IncrementalTemperature', 480 => 'IncrementalTemperature' }, + 'incrementaltint' => { 478 => 'IncrementalTint', 480 => 'IncrementalTint' }, + 'industry' => { 494 => 'industry', 495 => 'industry' }, + 'infobuttonwhenshooting' => { 84 => 0x409 }, + 'information' => { 374 => 'information', 380 => "\xa9inf" }, + 'infourl' => { 380 => 'infu' }, + 'infraredilluminator' => { 381 => 0x28 }, + 'ingredientexclusion' => { 496 => 'ingredientExclusion' }, + 'ingredients' => { 505 => 'Ingredients' }, + 'ingredientsalternatepaths' => { 505 => [\'Ingredients','IngredientsAlternatePaths'] }, + 'ingredientsdocumentid' => { 505 => [\'Ingredients','IngredientsDocumentID'] }, + 'ingredientsfilepath' => { 505 => [\'Ingredients','IngredientsFilePath'] }, + 'ingredientsfrompart' => { 505 => [\'Ingredients','IngredientsFromPart'] }, + 'ingredientsinstanceid' => { 505 => [\'Ingredients','IngredientsInstanceID'] }, + 'ingredientslastmodifydate' => { 505 => [\'Ingredients','IngredientsLastModifyDate'] }, + 'ingredientslasturl' => { 505 => [\'Ingredients','IngredientsLastURL'] }, + 'ingredientslinkcategory' => { 505 => [\'Ingredients','IngredientsLinkCategory'] }, + 'ingredientslinkform' => { 505 => [\'Ingredients','IngredientsLinkForm'] }, + 'ingredientsmanager' => { 505 => [\'Ingredients','IngredientsManager'] }, + 'ingredientsmanagervariant' => { 505 => [\'Ingredients','IngredientsManagerVariant'] }, + 'ingredientsmanageto' => { 505 => [\'Ingredients','IngredientsManageTo'] }, + 'ingredientsmanageui' => { 505 => [\'Ingredients','IngredientsManageUI'] }, + 'ingredientsmaskmarkers' => { 505 => [\'Ingredients','IngredientsMaskMarkers'] }, + 'ingredientsoriginaldocumentid' => { 505 => [\'Ingredients','IngredientsOriginalDocumentID'] }, + 'ingredientspartmapping' => { 505 => [\'Ingredients','IngredientsPartMapping'] }, + 'ingredientsplacedresolutionunit' => { 505 => [\'Ingredients','IngredientsPlacedResolutionUnit'] }, + 'ingredientsplacedxresolution' => { 505 => [\'Ingredients','IngredientsPlacedXResolution'] }, + 'ingredientsplacedyresolution' => { 505 => [\'Ingredients','IngredientsPlacedYResolution'] }, + 'ingredientsrenditionclass' => { 505 => [\'Ingredients','IngredientsRenditionClass'] }, + 'ingredientsrenditionparams' => { 505 => [\'Ingredients','IngredientsRenditionParams'] }, + 'ingredientstopart' => { 505 => [\'Ingredients','IngredientsToPart'] }, + 'ingredientsversionid' => { 505 => [\'Ingredients','IngredientsVersionID'] }, + 'initialafpointaiservoaf' => { 84 => 0x51e }, 'initialafpointinservo' => { 2 => 0x13 }, - 'initialcameradolly' => { 429 => 'InitialCameraDolly' }, - 'initialhorizontalfovdegrees' => { 429 => 'InitialHorizontalFOVDegrees' }, - 'initialviewheadingdegrees' => { 429 => 'InitialViewHeadingDegrees', 430 => 'InitialViewHeadingDegrees' }, - 'initialviewpitchdegrees' => { 429 => 'InitialViewPitchDegrees', 430 => 'InitialViewPitchDegrees' }, - 'initialviewrolldegrees' => { 429 => 'InitialViewRollDegrees', 430 => 'InitialViewRollDegrees' }, - 'initialzoomliveview' => { 257 => '4.4' }, - 'initialzoomsetting' => { 257 => '9.3', 266 => '27.3' }, - 'inkset' => { 113 => 0x14c }, - 'inputprofile' => { 131 => 0x1389 }, - 'instanceid' => { 467 => 'InstanceID' }, - 'instantplaybacksetup' => { 174 => 0x3e }, - 'instantplaybacktime' => { 174 => 0x3d }, - 'instructions' => { 454 => 'Instructions' }, - 'instrument' => { 466 => 'instrument' }, - 'integrationtime' => { 131 => 0x423 }, - 'intellectualgenre' => { 451 => 'IntellectualGenre' }, - 'intelligentauto' => { 388 => 0xb052, 413 => 0xd, 414 => 0xe, 415 => 0xd }, - 'intelligentcontrast' => { 49 => 0x4 }, - 'intelligentd-range' => { 297 => 0x79 }, - 'intelligentexposure' => { 297 => 0x5d }, - 'intelligentresolution' => { 297 => 0x70 }, - 'interchangecolorspace' => { 127 => 0x40 }, - 'internalflash' => { 171 => 0x2b, 257 => '23.1', 259 => '8.1', 262 => '22.1', 264 => '23.1', 268 => '8.1', 272 => '24.1', 277 => 0x1208 }, - 'internalflashae1' => { 279 => 0x1021 }, - 'internalflashae1_0' => { 279 => 0x101d }, - 'internalflashae2' => { 279 => 0x1022 }, - 'internalflashae2_0' => { 279 => 0x101e }, - 'internalflashmode' => { 320 => 0x1 }, - 'internalflashstrength' => { 320 => 0x3 }, - 'internalflashtable' => { 279 => 0x1024 }, - 'internallensserialnumber' => { 365 => 0xa005 }, - 'internalndfilter' => { 297 => 0x9d }, - 'internalserialnumber' => { 60 => 0x96, 71 => 0x9, 121 => 0x10, 177 => 0x49dc, 273 => 0x18, 275 => 0x102, 294 => 0x500, 297 => 0x25, 312 => 0x4, 358 => 0x5, 406 => [0x7c,0xf0], 407 => 0x88 }, - 'interopindex' => { 113 => 0x1, 447 => 'InteroperabilityIndex' }, - 'interopversion' => { 113 => 0x2 }, - 'intervallength' => { 171 => 0x10 }, - 'intervalmode' => { 171 => 0x26 }, - 'intervalnumber' => { 171 => 0x11 }, - 'intervalshooting' => { 332 => 0x92 }, - 'introtime' => { 466 => 'introTime' }, - 'introtimescale' => { 466 => [\'introTime','introTimeScale'] }, - 'introtimevalue' => { 466 => [\'introTime','introTimeValue'] }, - 'ipaversion' => { 131 => 0xdae }, - 'ipfcameramodel' => { 131 => 0xe4d }, - 'iptc' => { 114 => 'IPTC' }, - 'iptc-naa' => { 113 => 0x83bb, 302 => 0x83bb }, - 'iptcbitspersample' => { 127 => 0x56 }, - 'iptcdigest' => { 346 => 0x425 }, - 'iptcimageheight' => { 127 => 0x1e }, - 'iptcimagerotation' => { 127 => 0x66 }, - 'iptcimagewidth' => { 127 => 0x14 }, - 'iptclastedited' => { 452 => 'IptcLastEdited' }, - 'iptcpicturenumber' => { 127 => 0xa }, - 'iptcpixelheight' => { 127 => 0x32 }, - 'iptcpixelwidth' => { 127 => 0x28 }, - 'isalternativeof' => { 456 => 'isAlternativeOf' }, - 'isbn' => { 456 => 'isbn' }, - 'iscorrectionof' => { 456 => 'isCorrectionOf' }, - 'iscustompicturestyle' => { 103 => 0x3 }, - 'ismergedhdr' => { 438 => 'IsMergedHDR' }, - 'ismergedpanorama' => { 438 => 'IsMergedPanorama' }, - 'iso' => { 6 => 0x6, 8 => 0x6, 9 => 0x75, 10 => 0x6, 11 => 0x79, 12 => 0x6, 13 => 0x6, 14 => 0x6, 15 => 0x6, 16 => 0x6, 17 => 0x6, 18 => 0x6, 19 => 0x6, 20 => 0x6, 21 => 0x6, 22 => 0x6, 23 => 0x6, 24 => 0x6, 25 => 0x6, 26 => 0x6, 27 => 0x6, 28 => 0x6, 29 => 0x0, 30 => 0x1, 106 => 0x14, 107 => [0x3014,0x14], 113 => 0x8827, 130 => 0xfd06, 131 => 0x1784, 133 => 0x60, 135 => [0xfa2e,0xfa46], 136 => [0x27,0x28], 137 => 0xf105, 140 => 0x14, 142 => 0x4e, 145 => 0x34, 147 => 'ISO', 171 => 0x8, 177 => 0x49ba, 205 => 0x0, 211 => 0x2, 302 => 0x17, 332 => [0x8b,0x14], 339 => 0x14, 341 => 0x105, 365 => 0xa014, 387 => 0x6f, 393 => [0x1f,0x21,0x25], 446 => 'ISOSpeedRatings' }, - 'iso2' => { 205 => 0x6, 220 => 0x265, 221 => 0x25c, 222 => 0x265, 223 => 0x221, 224 => 0x25d, 225 => 0x256, 226 => 0x25d, 230 => 0x2b5, 233 => 0x265, 239 => 0x2b5 }, - 'isoauto' => { 313 => '14.4' }, - 'isoautohilimit' => { 228 => 0x18eb, 229 => 0xe82, 237 => 0x185d }, - 'isoautoparameters' => { 332 => 0x7a }, - 'isoautoshuttertime' => { 228 => 0x18ea, 229 => 0xe81, 237 => 0x185c }, - 'isocalibrationgain' => { 131 => 0x89f }, - 'isodisplay' => { 260 => '4.1', 261 => '4.1', 262 => '2.3', 263 => '3.3', 264 => '3.3', 267 => '3.3', 270 => '4.3', 271 => '4.1', 272 => '4.3' }, - 'isoexpansion' => { 78 => 0x103, 79 => 0x7, 80 => 0x8, 83 => 0x8, 205 => 0x4 }, - 'isoexpansion2' => { 205 => 0xa }, - 'isofloor' => { 313 => 0x6 }, - 'isoselection' => { 211 => 0xf }, - 'isosensitivitystep' => { 265 => '6.2', 267 => '6.2' }, - 'isosetting' => { 133 => 0x5e, 147 => 'ISOSetting', 171 => 0x24, 172 => 0x26, 173 => 0x1c, 174 => 0x13, 179 => 0x6, 211 => 0x13, 313 => '17.3', 357 => 0x27, 376 => 0x16, 377 => 0x14, 378 => 0x2, 387 => 0x6d }, - 'isospeed' => { 113 => 0x8833, 447 => 'ISOSpeed' }, - 'isospeedexpansion' => { 77 => 0x3 }, - 'isospeedincrements' => { 78 => 0x102 }, - 'isospeedlatitudeyyy' => { 113 => 0x8834, 447 => 'ISOSpeedLatitudeyyy' }, - 'isospeedlatitudezzz' => { 113 => 0x8835, 447 => 'ISOSpeedLatitudezzz' }, - 'isospeedrange' => { 78 => 0x103 }, - 'isostepsize' => { 257 => '6.1', 258 => '7.2', 260 => '7.2', 261 => '7.2', 266 => '4.1', 270 => '7.2', 271 => '7.2' }, - 'isovalue' => { 279 => 0x1001 }, - 'issn' => { 456 => 'issn' }, - 'issueidentifier' => { 456 => 'issueIdentifier' }, - 'issuename' => { 456 => 'issueName' }, - 'issueteaser' => { 456 => 'issueTeaser' }, - 'issuetype' => { 456 => 'issueType' }, - 'istranslationof' => { 456 => 'isTranslationOf' }, - 'itemsubtype' => { 169 => 'ItemSubType' }, - 'jobid' => { 125 => 0xb8 }, - 'jobname' => { 448 => 'JobName' }, - 'jobref' => { 465 => 'JobRef' }, - 'jobrefid' => { 465 => [\'JobRef','JobRefId'] }, - 'jobrefname' => { 465 => [\'JobRef','JobRefName'] }, - 'jobrefurl' => { 465 => [\'JobRef','JobRefUrl'] }, - 'jobstatus' => { 448 => 'JobStatus' }, - 'jpeghandling' => { 442 => 'JPEGHandling' }, - 'jpegquality' => { 9 => 0x66, 297 => 0x43, 299 => 0x3034, 388 => 0xb047 }, - 'jpegsize' => { 299 => 0x303a }, - 'jpgcompression' => { 229 => 0x7d4 }, - 'jpgfromraw' => { 91 => 0x2007, 108 => 'JpgFromRaw', 302 => 0x2e }, - 'jpgfromrawlength' => { 113 => [0x117,0x202] }, - 'jpgfromrawstart' => { 113 => [0x111,0x201] }, - 'jpgrecordedpixels' => { 313 => '14.1' }, - 'jurisdiction' => { 439 => 'jurisdiction' }, - 'kelvinwb_01' => { 321 => 0x5 }, - 'kelvinwb_02' => { 321 => 0x9 }, - 'kelvinwb_03' => { 321 => 0xd }, - 'kelvinwb_04' => { 321 => 0x11 }, - 'kelvinwb_05' => { 321 => 0x15 }, - 'kelvinwb_06' => { 321 => 0x19 }, - 'kelvinwb_07' => { 321 => 0x1d }, - 'kelvinwb_08' => { 321 => 0x21 }, - 'kelvinwb_09' => { 321 => 0x25 }, - 'kelvinwb_10' => { 321 => 0x29 }, - 'kelvinwb_11' => { 321 => 0x2d }, - 'kelvinwb_12' => { 321 => 0x31 }, - 'kelvinwb_13' => { 321 => 0x35 }, - 'kelvinwb_14' => { 321 => 0x39 }, - 'kelvinwb_15' => { 321 => 0x3d }, - 'kelvinwb_16' => { 321 => 0x41 }, - 'kelvinwb_daylight' => { 321 => 0x1 }, - 'kerneldenominators' => { 131 => 0x933 }, - 'key' => { 466 => 'key' }, - 'keystonecompensation' => { 278 => 0x1900 }, - 'keystonedirection' => { 278 => 0x1901 }, - 'keystonevalue' => { 278 => 0x1906 }, - 'keyword' => { 456 => 'keyword' }, - 'keywordinfo' => { 162 => 'Keywords' }, - 'keywords' => { 125 => 0x19, 148 => 'Keywords', 283 => 'Keywords', 348 => 'Keywords', 436 => 'keywords', 453 => 'Keywords', 464 => 'Keywords' }, - 'killdate' => { 456 => 'killDate' }, - 'killdatea-platform' => { 456 => [\'killDate','killDateA-platform'] }, - 'killdatedate' => { 456 => [\'killDate','killDateDate'] }, - 'kodakimageheight' => { 130 => 0xf908, 133 => 0xe, 135 => [0xfa1e,0xfa52], 141 => 0x70 }, - 'kodakimagewidth' => { 130 => 0xf907, 133 => 0xc, 135 => [0xfa1d,0xfa51], 141 => 0x6c }, - 'kodakinfotype' => { 130 => 0xfa00 }, - 'kodaklook' => { 131 => 0xe4c }, - 'kodaklookprofile' => { 131 => 0x138a }, - 'kodakmaker' => { 141 => 0x8 }, - 'kodakmodel' => { 133 => 0x0, 141 => 0x28 }, - 'kodaktag' => { 131 => 0x3ea }, - 'kodakversion' => { 131 => 0x0 }, - 'label' => { 287 => 'Label', 464 => 'Label' }, - 'labelname1' => { 450 => [\'TagStructure','TagStructureLabelName'] }, - 'labelname2' => { 450 => [\'TagStructure','TagStructureSubLabelsLabelName'] }, - 'labelname3' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsLabelName'] }, - 'labelname4' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsLabelName'] }, - 'labelname5' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsLabelName'] }, - 'labelname6' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsSubLabelsLabelName'] }, - 'landmark' => { 297 => 0x6f }, - 'landscapeoutputhighlightpoint' => { 103 => 0x26 }, - 'landscapeoutputshadowpoint' => { 103 => 0x27 }, - 'landscaperawcolortone' => { 103 => 0x1f }, - 'landscaperawcontrast' => { 103 => 0x21 }, - 'landscaperawhighlight' => { 103 => 0x77 }, - 'landscaperawhighlightpoint' => { 103 => 0x24 }, - 'landscaperawlinear' => { 103 => 0x22 }, - 'landscaperawsaturation' => { 103 => 0x20 }, - 'landscaperawshadow' => { 103 => 0x80 }, - 'landscaperawshadowpoint' => { 103 => 0x25 }, - 'landscaperawsharpness' => { 103 => 0x23 }, - 'landscapeunsharpmaskfineness' => { 103 => 0xa0 }, - 'landscapeunsharpmaskstrength' => { 103 => 0x9e }, - 'landscapeunsharpmaskthreshold' => { 103 => 0xa2 }, - 'language' => { 443 => 'language' }, - 'languageidentifier' => { 125 => 0x87 }, - 'largestvalidinteriorrectheight' => { 429 => 'LargestValidInteriorRectHeight' }, - 'largestvalidinteriorrectleft' => { 429 => 'LargestValidInteriorRectLeft' }, - 'largestvalidinteriorrecttop' => { 429 => 'LargestValidInteriorRectTop' }, - 'largestvalidinteriorrectwidth' => { 429 => 'LargestValidInteriorRectWidth' }, - 'lastfilenumber' => { 171 => 0x1b }, - 'lastkeywordiptc' => { 169 => 'LastKeywordIPTC' }, - 'lastkeywordxmp' => { 169 => 'LastKeywordXMP' }, - 'lastphotodate' => { 429 => 'LastPhotoDate' }, - 'lasturl' => { 467 => 'LastURL' }, - 'lateralchromaticaberration' => { 388 => 0x2012 }, - 'lateralchromaticaberrationcorrectionalreadyapplied' => { 438 => 'LateralChromaticAberrationCorrectionAlreadyApplied' }, - 'latestageorhigheststage' => { 112 => [\'GeologicalContext','GeologicalContextLatestAgeOrHighestStage'] }, - 'latesteonorhighesteonothem' => { 112 => [\'GeologicalContext','GeologicalContextLatestEonOrHighestEonothem'] }, - 'latestepochorhighestseries' => { 112 => [\'GeologicalContext','GeologicalContextLatestEpochOrHighestSeries'] }, - 'latesteraorhighesterathem' => { 112 => [\'GeologicalContext','GeologicalContextLatestEraOrHighestErathem'] }, - 'latestperiodorhighestsystem' => { 112 => [\'GeologicalContext','GeologicalContextLatestPeriodOrHighestSystem'] }, - 'lc1' => { 323 => 0x2 }, - 'lc10' => { 323 => 0xb }, - 'lc11' => { 323 => 0xc }, - 'lc12' => { 323 => 0xd }, - 'lc14' => { 323 => 0xf }, - 'lc15' => { 323 => 0x10 }, - 'lc3' => { 323 => 0x4 }, - 'lc4' => { 323 => 0x5 }, - 'lc5' => { 323 => 0x6 }, - 'lc6' => { 323 => 0x7 }, - 'lc7' => { 323 => 0x8 }, - 'lc8' => { 323 => 0x9 }, - 'lcddisplayatpoweron' => { 78 => 0x811, 82 => 0xa }, - 'lcddisplayreturntoshoot' => { 83 => 0x12 }, - 'lcdillumination' => { 257 => '17.5', 258 => '5.2', 260 => '5.1', 261 => '5.1', 266 => '10.3', 267 => '4.2', 270 => '5.2', 271 => '5.1', 272 => '5.4' }, - 'lcdilluminationduringbulb' => { 78 => 0x408 }, - 'lcdmatrix' => { 131 => 0xe74 }, - 'lcdmatrixchickfix' => { 131 => 0xe75 }, - 'lcdmatrixmarvin' => { 131 => 0xe76 }, - 'lcdpanels' => { 77 => 0x8 }, - 'lcheditor' => { 250 => 0x8ae85e }, - 'legacyiptcdigest' => { 454 => 'LegacyIPTCDigest' }, - 'legalcode' => { 439 => 'legalcode' }, - 'lens' => { 113 => 0xfdea, 211 => 0x84, 438 => 'Lens' }, - 'lensafstopbutton' => { 76 => 0x11, 77 => 0x13, 78 => 0x506, 79 => 0x10, 80 => 0x12, 83 => 0x13, 84 => 0x9 }, - 'lensaperturerange' => { 368 => [0x30,0x48] }, - 'lenscorrectionsettings' => { 445 => 'LensCorrectionSettings' }, - 'lensdistortinfo' => { 438 => 'LensDistortInfo' }, - 'lensdistortionparams' => { 279 => 0x206 }, - 'lensdrivenoaf' => { 78 => 0x505 }, + 'initialcameradolly' => { 466 => 'InitialCameraDolly' }, + 'initialhorizontalfovdegrees' => { 466 => 'InitialHorizontalFOVDegrees' }, + 'initialkey' => { 179 => 'WM/InitialKey' }, + 'initialverticalfovdegrees' => { 466 => 'InitialVerticalFOVDegrees' }, + 'initialviewheadingdegrees' => { 466 => 'InitialViewHeadingDegrees', 467 => 'InitialViewHeadingDegrees' }, + 'initialviewpitchdegrees' => { 466 => 'InitialViewPitchDegrees', 467 => 'InitialViewPitchDegrees' }, + 'initialviewrolldegrees' => { 466 => 'InitialViewRollDegrees', 467 => 'InitialViewRollDegrees' }, + 'initialzoomliveview' => { 279 => '4.4' }, + 'initialzoomsetting' => { 279 => '9.3', 288 => '27.3' }, + 'inkset' => { 119 => 0x14c }, + 'inputprofile' => { 138 => 0x1389 }, + 'instanceid' => { 505 => 'InstanceID' }, + 'instantplaybacksetup' => { 184 => 0x3e }, + 'instantplaybacktime' => { 184 => 0x3d }, + 'instructions' => { 492 => 'Instructions' }, + 'instrument' => { 504 => 'instrument' }, + 'integrationtime' => { 138 => 0x423 }, + 'intellectualgenre' => { 489 => 'IntellectualGenre' }, + 'intelligentauto' => { 420 => 0xb052, 447 => 0xd, 448 => 0xe, 449 => 0xd }, + 'intelligentcontrast' => { 52 => 0x4 }, + 'intelligentd-range' => { 320 => 0x79 }, + 'intelligentexposure' => { 320 => 0x5d }, + 'intelligentresolution' => { 320 => 0x70 }, + 'interchangecolorspace' => { 133 => 0x40 }, + 'intergraphmatrix' => { 119 => 0x8480 }, + 'internalflash' => { 181 => 0x2b, 279 => '23.1', 281 => '8.1', 284 => '22.1', 286 => '23.1', 290 => '8.1', 294 => '24.1', 300 => 0x1208 }, + 'internalflashae1' => { 302 => 0x1021 }, + 'internalflashae1_0' => { 302 => 0x101d }, + 'internalflashae2' => { 302 => 0x1022 }, + 'internalflashae2_0' => { 302 => 0x101e }, + 'internalflashmode' => { 343 => 0x1 }, + 'internalflashstrength' => { 343 => 0x3 }, + 'internalflashtable' => { 302 => 0x1024 }, + 'internallensserialnumber' => { 394 => 0xa005 }, + 'internalndfilter' => { 320 => 0x9d }, + 'internalserialnumber' => { 64 => 0x96, 76 => 0x9, 127 => 0x10, 187 => 0x49dc, 296 => 0x18, 298 => 0x102, 317 => 0x500, 320 => 0x25, 335 => 0x4, 387 => 0x5, 439 => [0x7c,0xf0], 440 => 0x88, 441 => [0x88,0x8a] }, + 'interopindex' => { 119 => 0x1, 485 => 'InteroperabilityIndex' }, + 'interopversion' => { 119 => 0x2 }, + 'interval' => { 248 => 0xd0 }, + 'intervaldurationhours' => { 228 => 0xa0 }, + 'intervaldurationminutes' => { 228 => 0xa4 }, + 'intervaldurationseconds' => { 228 => 0xa8 }, + 'intervalexposuresmoothing' => { 228 => 0xb8, 252 => 0xc416 }, + 'intervalframe' => { 248 => 0xd4 }, + 'intervallength' => { 181 => 0x10 }, + 'intervalmode' => { 181 => 0x26 }, + 'intervalnumber' => { 181 => 0x11 }, + 'intervalpriority' => { 228 => 0xba, 252 => 0xc418 }, + 'intervals' => { 228 => 0xb0, 229 => 0xbc, 252 => 0xc40e }, + 'intervalshooting' => { 252 => 0x760c, 260 => 0x760c, 261 => 0x6c98, 355 => 0x92 }, + 'introtime' => { 504 => 'introTime' }, + 'introtimescale' => { 504 => [\'introTime','introTimeScale'] }, + 'introtimevalue' => { 504 => [\'introTime','introTimeValue'] }, + 'ipaversion' => { 138 => 0xdae }, + 'ipfcameramodel' => { 138 => 0xe4d }, + 'iptc' => { 120 => 'IPTC' }, + 'iptc-naa' => { 119 => 0x83bb, 325 => 0x83bb }, + 'iptcbitspersample' => { 133 => 0x56 }, + 'iptcdigest' => { 369 => 0x425 }, + 'iptcimageheight' => { 133 => 0x1e }, + 'iptcimagerotation' => { 133 => 0x66 }, + 'iptcimagewidth' => { 133 => 0x14 }, + 'iptclastedited' => { 490 => 'IptcLastEdited' }, + 'iptcpicturenumber' => { 133 => 0xa }, + 'iptcpixelheight' => { 133 => 0x32 }, + 'iptcpixelwidth' => { 133 => 0x28 }, + 'isalternativeof' => { 494 => 'isAlternativeOf' }, + 'isbn' => { 494 => 'isbn' }, + 'iscorrectionof' => { 494 => 'isCorrectionOf' }, + 'iscustompicturestyle' => { 109 => 0x3 }, + 'ismergedhdr' => { 475 => 'IsMergedHDR' }, + 'ismergedpanorama' => { 475 => 'IsMergedPanorama' }, + 'iso' => { 7 => 0x6, 9 => 0x6, 10 => 0x75, 11 => 0x6, 12 => 0x79, 13 => 0x6, 14 => 0x6, 15 => 0x6, 16 => 0x6, 17 => 0x6, 18 => 0x6, 19 => 0x6, 20 => 0x6, 21 => 0x6, 22 => 0x6, 23 => 0x6, 24 => 0x6, 25 => 0x6, 26 => 0x6, 27 => 0x6, 28 => 0x6, 29 => 0x6, 30 => 0x0, 31 => 0x1, 112 => 0x14, 113 => [0x3014,0x14], 119 => 0x8827, 137 => 0xfd06, 138 => 0x1784, 140 => 0x60, 142 => [0xfa2e,0xfa46], 143 => [0x27,0x28], 144 => 0xf105, 147 => 0x14, 149 => 0x4e, 151 => 0x1e, 152 => 0x1a, 154 => 0x34, 156 => 'ISO', 181 => 0x8, 187 => 0x49ba, 217 => 0x0, 226 => 0x2, 320 => 0xd1, 325 => 0x17, 355 => [0x8b,0x14], 362 => 0x14, 364 => 0x105, 394 => 0xa014, 397 => 0x86, 418 => 0x6f, 425 => [0x1f,0x21,0x25], 484 => 'ISOSpeedRatings' }, + 'iso2' => { 217 => 0x6, 239 => 0x265, 240 => 0x25c, 241 => 0x265, 242 => 0x221, 243 => 0x25d, 244 => 0x256, 245 => 0x25d, 249 => 0x2b5, 253 => 0x265, 259 => 0x2b5 }, + 'isoauto' => { 336 => '14.4' }, + 'isoautoflashlimit' => { 229 => 0x146 }, + 'isoautohilimit' => { 229 => 0x144, 247 => 0x18eb, 248 => 0xe82, 257 => 0x185d }, + 'isoautomax' => { 419 => 0x4 }, + 'isoautomin' => { 419 => 0x2 }, + 'isoautoparameters' => { 355 => 0x7a }, + 'isoautoshuttertime' => { 229 => 0x14e, 247 => 0x18ea, 248 => 0xe81, 257 => 0x185c }, + 'isocalibrationgain' => { 138 => 0x89f }, + 'isodisplay' => { 282 => '4.1', 283 => '4.1', 284 => '2.3', 285 => '3.3', 286 => '3.3', 289 => '3.3', 292 => '4.3', 293 => '4.1', 294 => '4.3' }, + 'isoexpansion' => { 84 => 0x103, 85 => 0x7, 86 => 0x8, 89 => 0x8, 217 => 0x4 }, + 'isoexpansion2' => { 217 => 0xa }, + 'isofloor' => { 336 => 0x6 }, + 'isoselected' => { 319 => 0x359 }, + 'isoselection' => { 226 => 0xf }, + 'isosensitivitystep' => { 287 => '6.2', 289 => '6.2' }, + 'isosetting' => { 140 => 0x5e, 152 => 0x14, 156 => 'ISOSetting', 181 => 0x24, 182 => 0x26, 183 => 0x1c, 184 => 0x13, 189 => 0x6, 226 => 0x13, 336 => '17.3', 386 => 0x27, 407 => 0x16, 408 => 0x14, 409 => 0x2, 418 => 0x6d, 419 => 0x0 }, + 'isospeed' => { 119 => 0x8833, 485 => 'ISOSpeed' }, + 'isospeedexpansion' => { 83 => 0x3 }, + 'isospeedincrements' => { 84 => 0x102 }, + 'isospeedlatitudeyyy' => { 119 => 0x8834, 485 => 'ISOSpeedLatitudeyyy' }, + 'isospeedlatitudezzz' => { 119 => 0x8835, 485 => 'ISOSpeedLatitudezzz' }, + 'isospeedrange' => { 84 => 0x103 }, + 'isostepsize' => { 279 => '6.1', 280 => '7.2', 282 => '7.2', 283 => '7.2', 288 => '4.1', 292 => '7.2', 293 => '7.2', 295 => 0x15d }, + 'isovalue' => { 302 => 0x1001 }, + 'isrccode' => { 380 => "\xa9isr" }, + 'issn' => { 494 => 'issn' }, + 'issueidentifier' => { 494 => 'issueIdentifier' }, + 'issuename' => { 494 => 'issueName' }, + 'issueteaser' => { 494 => 'issueTeaser' }, + 'issuetype' => { 494 => 'issueType' }, + 'istranslationof' => { 494 => 'isTranslationOf' }, + 'itemsubtype' => { 178 => 'ItemSubType' }, + 'itunesu' => { 372 => 'itnu' }, + 'jobid' => { 131 => 0xb8 }, + 'jobname' => { 486 => 'JobName' }, + 'jobref' => { 503 => 'JobRef' }, + 'jobrefid' => { 503 => [\'JobRef','JobRefId'] }, + 'jobrefname' => { 503 => [\'JobRef','JobRefName'] }, + 'jobrefurl' => { 503 => [\'JobRef','JobRefUrl'] }, + 'jobstatus' => { 486 => 'JobStatus' }, + 'jpeg-heifswitch' => { 420 => 0x2039 }, + 'jpeghandling' => { 478 => 'JPEGHandling', 480 => 'JPEGHandling' }, + 'jpegquality' => { 10 => 0x66, 320 => 0x43, 322 => 0x3034, 420 => 0xb047 }, + 'jpegsize' => { 322 => 0x303a }, + 'jpgcompression' => { 248 => 0x7d4 }, + 'jpgfromraw' => { 97 => 0x2007, 114 => 'Exif-JpgFromRaw', 325 => 0x2e }, + 'jpgfromrawlength' => { 119 => [0x117,0x202] }, + 'jpgfromrawstart' => { 119 => [0x111,0x201] }, + 'jpgrecordedpixels' => { 336 => '14.1' }, + 'jurisdiction' => { 476 => 'jurisdiction' }, + 'keepexposure' => { 295 => 0x237 }, + 'kelvinwb_01' => { 344 => 0x5 }, + 'kelvinwb_02' => { 344 => 0x9 }, + 'kelvinwb_03' => { 344 => 0xd }, + 'kelvinwb_04' => { 344 => 0x11 }, + 'kelvinwb_05' => { 344 => 0x15 }, + 'kelvinwb_06' => { 344 => 0x19 }, + 'kelvinwb_07' => { 344 => 0x1d }, + 'kelvinwb_08' => { 344 => 0x21 }, + 'kelvinwb_09' => { 344 => 0x25 }, + 'kelvinwb_10' => { 344 => 0x29 }, + 'kelvinwb_11' => { 344 => 0x2d }, + 'kelvinwb_12' => { 344 => 0x31 }, + 'kelvinwb_13' => { 344 => 0x35 }, + 'kelvinwb_14' => { 344 => 0x39 }, + 'kelvinwb_15' => { 344 => 0x3d }, + 'kelvinwb_16' => { 344 => 0x41 }, + 'kelvinwb_daylight' => { 344 => 0x1 }, + 'kerneldenominators' => { 138 => 0x933 }, + 'key' => { 504 => 'key' }, + 'keystonecompensation' => { 301 => 0x1900 }, + 'keystonedirection' => { 301 => 0x1901 }, + 'keystonevalue' => { 301 => 0x1906 }, + 'keyword' => { 372 => 'keyw', 494 => 'keyword' }, + 'keywordinfo' => { 171 => 'Keywords' }, + 'keywords' => { 131 => 0x19, 157 => 'Keywords', 306 => 'Keywords', 371 => 'Keywords', 374 => 'keywords', 473 => 'keywords', 491 => 'Keywords', 502 => 'Keywords' }, + 'killdate' => { 494 => 'killDate' }, + 'killdatea-platform' => { 494 => [\'killDate','killDateA-platform'] }, + 'killdatedate' => { 494 => [\'killDate','killDateDate'] }, + 'kodakimageheight' => { 137 => 0xf908, 140 => 0xe, 142 => [0xfa1e,0xfa52], 148 => 0x70 }, + 'kodakimagewidth' => { 137 => 0xf907, 140 => 0xc, 142 => [0xfa1d,0xfa51], 148 => 0x6c }, + 'kodakinfotype' => { 137 => 0xfa00 }, + 'kodaklook' => { 138 => 0xe4c }, + 'kodaklookprofile' => { 138 => 0x138a }, + 'kodakmaker' => { 148 => 0x8 }, + 'kodakmodel' => { 140 => 0x0, 148 => 0x28 }, + 'kodaktag' => { 138 => 0x3ea }, + 'kodakversion' => { 138 => 0x0 }, + 'label' => { 310 => 'Label', 502 => 'Label' }, + 'labelname1' => { 488 => [\'TagStructure','TagStructureLabelName'] }, + 'labelname2' => { 488 => [\'TagStructure','TagStructureSubLabelsLabelName'] }, + 'labelname3' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsLabelName'] }, + 'labelname4' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsLabelName'] }, + 'labelname5' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsLabelName'] }, + 'labelname6' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsSubLabelsLabelName'] }, + 'landmark' => { 320 => 0x6f }, + 'landscapeoutputhighlightpoint' => { 109 => 0x26 }, + 'landscapeoutputshadowpoint' => { 109 => 0x27 }, + 'landscaperawcolortone' => { 109 => 0x1f }, + 'landscaperawcontrast' => { 109 => 0x21 }, + 'landscaperawhighlight' => { 109 => 0x77 }, + 'landscaperawhighlightpoint' => { 109 => 0x24 }, + 'landscaperawlinear' => { 109 => 0x22 }, + 'landscaperawsaturation' => { 109 => 0x20 }, + 'landscaperawshadow' => { 109 => 0x80 }, + 'landscaperawshadowpoint' => { 109 => 0x25 }, + 'landscaperawsharpness' => { 109 => 0x23 }, + 'landscapeunsharpmaskfineness' => { 109 => 0xa0 }, + 'landscapeunsharpmaskstrength' => { 109 => 0x9e }, + 'landscapeunsharpmaskthreshold' => { 109 => 0xa2 }, + 'language' => { 229 => 0x592, 481 => 'language' }, + 'languageidentifier' => { 131 => 0x87 }, + 'largestvalidinteriorrectheight' => { 466 => 'LargestValidInteriorRectHeight' }, + 'largestvalidinteriorrectleft' => { 466 => 'LargestValidInteriorRectLeft' }, + 'largestvalidinteriorrecttop' => { 466 => 'LargestValidInteriorRectTop' }, + 'largestvalidinteriorrectwidth' => { 466 => 'LargestValidInteriorRectWidth' }, + 'lastfilenumber' => { 181 => 0x1b }, + 'lastkeywordiptc' => { 178 => 'LastKeywordIPTC' }, + 'lastkeywordxmp' => { 178 => 'LastKeywordXMP' }, + 'lastphotodate' => { 466 => 'LastPhotoDate' }, + 'lasturl' => { 505 => 'LastURL' }, + 'lateralchromaticaberration' => { 420 => 0x2012 }, + 'lateralchromaticaberrationcorrectionalreadyapplied' => { 475 => 'LateralChromaticAberrationCorrectionAlreadyApplied' }, + 'latestageorhigheststage' => { 118 => [\'GeologicalContext','GeologicalContextLatestAgeOrHighestStage'] }, + 'latesteonorhighesteonothem' => { 118 => [\'GeologicalContext','GeologicalContextLatestEonOrHighestEonothem'] }, + 'latestepochorhighestseries' => { 118 => [\'GeologicalContext','GeologicalContextLatestEpochOrHighestSeries'] }, + 'latesteraorhighesterathem' => { 118 => [\'GeologicalContext','GeologicalContextLatestEraOrHighestErathem'] }, + 'latestperiodorhighestsystem' => { 118 => [\'GeologicalContext','GeologicalContextLatestPeriodOrHighestSystem'] }, + 'latitude' => { 116 => 'Latitude' }, + 'lc1' => { 346 => 0x2 }, + 'lc10' => { 346 => 0xb }, + 'lc11' => { 346 => 0xc }, + 'lc12' => { 346 => 0xd }, + 'lc14' => { 346 => 0xf }, + 'lc15' => { 346 => 0x10 }, + 'lc3' => { 346 => 0x4 }, + 'lc4' => { 346 => 0x5 }, + 'lc5' => { 346 => 0x6 }, + 'lc6' => { 346 => 0x7 }, + 'lc7' => { 346 => 0x8 }, + 'lc8' => { 346 => 0x9 }, + 'lcddisplayatpoweron' => { 84 => 0x811, 88 => 0xa }, + 'lcddisplayreturntoshoot' => { 89 => 0x12 }, + 'lcdillumination' => { 279 => '17.5', 280 => '5.2', 282 => '5.1', 283 => '5.1', 288 => '10.3', 289 => '4.2', 292 => '5.2', 293 => '5.1', 294 => '5.4', 295 => 0x101 }, + 'lcdilluminationduringbulb' => { 84 => 0x408 }, + 'lcdmatrix' => { 138 => 0xe74 }, + 'lcdmatrixchickfix' => { 138 => 0xe75 }, + 'lcdmatrixmarvin' => { 138 => 0xe76 }, + 'lcdpanels' => { 83 => 0x8 }, + 'lcheditor' => { 272 => 0x8ae85e }, + 'legacyiptcdigest' => { 492 => 'LegacyIPTCDigest' }, + 'legalcode' => { 476 => 'legalcode' }, + 'lens' => { 119 => 0xfdea, 226 => 0x84, 475 => 'Lens' }, + 'lensafstopbutton' => { 82 => 0x11, 83 => 0x13, 84 => 0x506, 85 => 0x10, 86 => 0x12, 89 => 0x13, 90 => 0x9 }, + 'lensaperturerange' => { 397 => [0x30,0x48] }, + 'lenscontrolring' => { 295 => 0xad }, + 'lenscorrectionsettings' => { 483 => 'LensCorrectionSettings' }, + 'lensdistortinfo' => { 475 => 'LensDistortInfo' }, + 'lensdistortionparams' => { 302 => 0x206 }, + 'lensdriveend' => { 224 => 0x56 }, + 'lensdrivenoaf' => { 84 => 0x505 }, 'lensdrivewhenafimpossible' => { 2 => 0xb }, - 'lense-mountversion' => { 378 => 0x3f0, 420 => 0xd }, - 'lensfirmware' => { 359 => 0x20, 365 => 0xa004 }, - 'lensfirmwareversion' => { 275 => 0x204, 297 => 0x60, 378 => 0x3f3, 420 => 0x14 }, - 'lensfocallength' => { 97 => 0xf0512, 323 => 0x9 }, - 'lensfocalrange' => { 368 => [0xa,0x2a] }, - 'lensfocusfunctionbuttons' => { 258 => '55.1', 260 => '52.1', 261 => '52.1', 270 => '52.1', 271 => '52.1' }, - 'lensformat' => { 400 => 0x1891, 402 => 0x18bd, 403 => 0x18ed, 404 => 0x17f1, 406 => 0x106, 407 => 0x106, 416 => 0x603, 417 => 0x5d }, - 'lensfstops' => { 206 => 0x7, 207 => 0xc, 208 => 0xd, 211 => 0x8b, 323 => '0.3' }, - 'lensid' => { 438 => 'LensID' }, - 'lensidnumber' => { 206 => 0x6, 207 => 0xb, 208 => 0xc }, - 'lensinfo' => { 113 => 0xa432, 329 => 0x2a, 438 => 'LensInfo', 447 => 'LensSpecification' }, - 'lenskind' => { 323 => 0x1 }, - 'lensmake' => { 113 => 0xa433, 154 => 'Make', 447 => 'LensMake' }, - 'lensmanualdistortionamount' => { 442 => 'LensManualDistortionAmount' }, - 'lensmanufacturer' => { 169 => 'LensManufacturer' }, - 'lensmaxaperturerange' => { 368 => 0x2b }, - 'lensmodel' => { 6 => 0x937, 13 => 0x92b, 14 => 0x933, 60 => 0x95, 113 => 0xa434, 154 => 'Model', 169 => 'LensModel', 209 => 0x18a, 275 => 0x203, 329 => 0xc, 341 => 0x412, 447 => 'LensModel' }, - 'lensmodulationoptimizer' => { 121 => 0x1045 }, - 'lensmount' => { 378 => 0x99, 400 => 0x1892, 402 => 0x18be, 403 => 0x18ee, 404 => 0x17f2, 406 => 0x105, 407 => 0x105, 416 => 0x604, 417 => 0x5e }, - 'lensmount2' => { 420 => 0x8 }, - 'lensprofilechromaticaberrationscale' => { 442 => 'LensProfileChromaticAberrationScale' }, - 'lensprofiledigest' => { 442 => 'LensProfileDigest' }, - 'lensprofiledistortionscale' => { 442 => 'LensProfileDistortionScale' }, - 'lensprofileenable' => { 442 => 'LensProfileEnable' }, - 'lensprofilefilename' => { 442 => 'LensProfileFilename' }, - 'lensprofilematchkeycameramodelname' => { 442 => 'LensProfileMatchKeyCameraModelName' }, - 'lensprofilematchkeyexifmake' => { 442 => 'LensProfileMatchKeyExifMake' }, - 'lensprofilematchkeyexifmodel' => { 442 => 'LensProfileMatchKeyExifModel' }, - 'lensprofilematchkeyisraw' => { 442 => 'LensProfileMatchKeyIsRaw' }, - 'lensprofilematchkeylensid' => { 442 => 'LensProfileMatchKeyLensID' }, - 'lensprofilematchkeylensinfo' => { 442 => 'LensProfileMatchKeyLensInfo' }, - 'lensprofilematchkeylensname' => { 442 => 'LensProfileMatchKeyLensName' }, - 'lensprofilematchkeysensorformatfactor' => { 442 => 'LensProfileMatchKeySensorFormatFactor' }, - 'lensprofilename' => { 442 => 'LensProfileName' }, - 'lensprofilesetup' => { 442 => 'LensProfileSetup' }, - 'lensprofilevignettingscale' => { 442 => 'LensProfileVignettingScale' }, - 'lensproperties' => { 275 => 0x20b }, - 'lensserialnumber' => { 20 => 0x164, 31 => 0x16b, 58 => 0x0, 113 => 0xa435, 154 => 'SerialNumber', 275 => 0x202, 295 => 0x321, 297 => 0x52, 359 => 0x30, 438 => 'LensSerialNumber', 447 => 'LensSerialNumber' }, - 'lensshutterlock' => { 174 => 0x4a }, - 'lensspec' => { 373 => 0x0, 374 => 0x0, 375 => 0x0, 388 => 0xb02a }, - 'lensspecfeatures' => { 406 => [0x115,0x116], 407 => [0x116,0x21c,0x21e] }, - 'lenstemperature' => { 279 => 0x1008 }, - 'lenstype' => { 6 => 0xe2, 7 => 0xd, 8 => 0x1a7, 9 => 0xc, 10 => 0x111, 11 => 0xc, 12 => 0x14f, 13 => 0xd6, 14 => 0xde, 15 => 0xf6, 16 => 0xea, 17 => 0xff, 18 => [0xc,0x97], 19 => 0xe6, 20 => 0x153, 21 => 0xea, 22 => 0xe8, 23 => 0x127, 24 => 0x161, 25 => 0x166, 26 => 0x184, 27 => 0x112, 28 => 0x189, 33 => 0x16, 176 => 0x10c, 177 => 0x49bd, 211 => 0x83, 275 => 0x201, 288 => 0x16, 292 => 0x310, 294 => 0x303, 295 => 0x303, 297 => 0x51, 299 => 0x3405, 324 => 0x0, 325 => 0x0, 326 => 0x1, 327 => 0x1, 328 => 0x1, 330 => 0x0, 365 => 0xa003, 368 => 0x27, 388 => 0xb027, 400 => 0x1896, 402 => 0x18c2, 403 => 0x18f2, 404 => 0x17f6, 406 => 0x109, 407 => 0x109, 416 => 0x608, 417 => 0x62 }, - 'lenstype2' => { 378 => 0x3f7, 400 => 0x1893, 402 => 0x18bf, 403 => 0x18ef, 404 => 0x17f3, 406 => 0x107, 407 => 0x107, 416 => 0x605, 417 => 0x60 }, - 'lenstype3' => { 420 => 0x9 }, - 'lenszoomposition' => { 413 => 0x19, 414 => 0x1e, 417 => [0x342,0x35a] }, - 'levelindicator' => { 305 => 0x15 }, - 'levelorientation' => { 331 => 0x0 }, - 'license' => { 439 => 'license' }, - 'licensee' => { 284 => 'Licensee' }, - 'licenseeid' => { 284 => [\'Licensee','LicenseeLicenseeID'] }, - 'licenseeimageid' => { 284 => 'LicenseeImageID' }, - 'licenseeimagenotes' => { 284 => 'LicenseeImageNotes' }, - 'licenseename' => { 284 => [\'Licensee','LicenseeLicenseeName'] }, - 'licenseenddate' => { 284 => 'LicenseEndDate' }, - 'licenseeprojectreference' => { 284 => 'LicenseeProjectReference' }, - 'licenseetransactionid' => { 284 => 'LicenseeTransactionID' }, - 'licenseid' => { 284 => 'LicenseID' }, - 'licensestartdate' => { 284 => 'LicenseStartDate' }, - 'licensetransactiondate' => { 284 => 'LicenseTransactionDate' }, - 'licensetype' => { 444 => 'licensetype' }, - 'licensor' => { 284 => 'Licensor' }, - 'licensorcity' => { 284 => [\'Licensor','LicensorLicensorCity'] }, - 'licensorcountry' => { 284 => [\'Licensor','LicensorLicensorCountry'] }, - 'licensoremail' => { 284 => [\'Licensor','LicensorLicensorEmail'] }, - 'licensorextendedaddress' => { 284 => [\'Licensor','LicensorLicensorExtendedAddress'] }, - 'licensorid' => { 284 => [\'Licensor','LicensorLicensorID'] }, - 'licensorimageid' => { 284 => 'LicensorImageID' }, - 'licensorname' => { 284 => [\'Licensor','LicensorLicensorName'] }, - 'licensornotes' => { 284 => 'LicensorNotes' }, - 'licensorpostalcode' => { 284 => [\'Licensor','LicensorLicensorPostalCode'] }, - 'licensorregion' => { 284 => [\'Licensor','LicensorLicensorRegion'] }, - 'licensorstreetaddress' => { 284 => [\'Licensor','LicensorLicensorStreetAddress'] }, - 'licensortelephone1' => { 284 => [\'Licensor','LicensorLicensorTelephone1'] }, - 'licensortelephone2' => { 284 => [\'Licensor','LicensorLicensorTelephone2'] }, - 'licensortelephonetype1' => { 284 => [\'Licensor','LicensorLicensorTelephoneType1'] }, - 'licensortelephonetype2' => { 284 => [\'Licensor','LicensorLicensorTelephoneType2'] }, - 'licensortransactionid' => { 284 => 'LicensorTransactionID' }, - 'licensorurl' => { 284 => [\'Licensor','LicensorLicensorURL'] }, - 'lightcondition' => { 279 => 0x1009 }, - 'lightingmode' => { 107 => 0x302a }, - 'lightreading' => { 332 => 0x15 }, - 'lightsource' => { 113 => 0x9208, 211 => 0x90, 282 => 0x1000, 446 => 'LightSource' }, - 'lightsourcespecial' => { 367 => 0x21d }, - 'lightswitch' => { 270 => '0.1', 272 => '0.1' }, - 'lightvaluecenter' => { 279 => 0x103d }, - 'lightvalueperiphery' => { 279 => 0x103e }, - 'limitafareamodeselection' => { 258 => '51.1', 260 => '49.1', 261 => '49.1', 270 => '49.1', 271 => '49.1' }, - 'linearitylimitblue' => { 302 => 0x10 }, - 'linearitylimitgreen' => { 302 => 0xf }, - 'linearitylimitred' => { 302 => 0xe }, - 'linearityuppermargin' => { 42 => [0x2ba,0x2d1,0x2d5], 44 => 0x1e5, 45 => [0x1fe,0x2de], 46 => [0x232,0x310], 47 => 0x31e }, - 'linearizationtable' => { 113 => 0xc618 }, - 'linearresponselimit' => { 113 => 0xc62e }, - 'link' => { 456 => 'link' }, - 'linkaetoafpoint' => { 313 => '14.2' }, - 'linkedencodedrightsexpr' => { 452 => [\'LinkedEncRightsExpr','LinkedEncRightsExprLinkedRightsExpr'] }, - 'linkedencodedrightsexprlangid' => { 452 => [\'LinkedEncRightsExpr','LinkedEncRightsExprRightsExprLangId'] }, - 'linkedencodedrightsexprtype' => { 452 => [\'LinkedEncRightsExpr','LinkedEncRightsExprRightsExprEncType'] }, - 'linkedencrightsexpr' => { 452 => 'LinkedEncRightsExpr' }, - 'linlogcoring' => { 131 => 0x904 }, - 'lithostratigraphicterms' => { 112 => [\'GeologicalContext','GeologicalContextLithostratigraphicTerms'] }, - 'liveviewaf' => { 262 => '32.1', 272 => '34.1' }, - 'liveviewafareamode' => { 267 => '34.1' }, - 'liveviewafmethod' => { 393 => 0x20 }, - 'liveviewafmode' => { 267 => '34.2' }, - 'liveviewafsetting' => { 378 => 0x36 }, - 'liveviewbuttonoptions' => { 258 => '50.2', 260 => '48.2', 261 => '48.2', 270 => '48.2', 271 => '48.2' }, - 'liveviewexposuresimulation' => { 78 => 0x810 }, - 'liveviewfocusmode' => { 378 => [0x8b,0x28b] }, - 'liveviewmetering' => { 378 => [0x84,0x284] }, - 'liveviewmonitorofftime' => { 258 => '21.2', 260 => '21.2', 261 => '21.2', 263 => '20.2', 264 => '20.2', 265 => '20.2', 267 => '20.2', 270 => '21.2', 271 => '21.2' }, - 'liveviewshooting' => { 54 => 0x13 }, - 'livingspecimen' => { 112 => 'LivingSpecimen' }, - 'livingspecimenmaterialsampleid' => { 112 => [\'LivingSpecimen','LivingSpecimenMaterialSampleID'] }, - 'localcaption' => { 125 => 0x79 }, - 'localizedcameramodel' => { 113 => 0xc615 }, - 'locallocationname' => { 365 => 0x30 }, - 'location' => { 210 => 0x9, 297 => 0x67, 434 => 'Location', 451 => 'Location', 455 => 'location', 456 => 'location' }, - 'locationareacode' => { 440 => 'lac' }, - 'locationcreated' => { 452 => 'LocationCreated' }, - 'locationcreatedcity' => { 452 => [\'LocationCreated','LocationCreatedCity'] }, - 'locationcreatedcountrycode' => { 452 => [\'LocationCreated','LocationCreatedCountryCode'] }, - 'locationcreatedcountryname' => { 452 => [\'LocationCreated','LocationCreatedCountryName'] }, - 'locationcreatedgpsaltitude' => { 452 => [\'LocationCreated','LocationCreatedGPSAltitude'] }, - 'locationcreatedgpslatitude' => { 452 => [\'LocationCreated','LocationCreatedGPSLatitude'] }, - 'locationcreatedgpslongitude' => { 452 => [\'LocationCreated','LocationCreatedGPSLongitude'] }, - 'locationcreatedidentifier' => { 452 => [\'LocationCreated','LocationCreatedIdentifier'] }, - 'locationcreatedlocationid' => { 452 => [\'LocationCreated','LocationCreatedLocationId'] }, - 'locationcreatedlocationname' => { 452 => [\'LocationCreated','LocationCreatedLocationName'] }, - 'locationcreatedprovincestate' => { 452 => [\'LocationCreated','LocationCreatedProvinceState'] }, - 'locationcreatedsublocation' => { 452 => [\'LocationCreated','LocationCreatedSublocation'] }, - 'locationcreatedworldregion' => { 452 => [\'LocationCreated','LocationCreatedWorldRegion'] }, - 'locationinfoversion' => { 210 => 0x0 }, - 'locationname' => { 365 => 0x31 }, - 'locationshown' => { 452 => 'LocationShown' }, - 'locationshowncity' => { 452 => [\'LocationShown','LocationShownCity'] }, - 'locationshowncountrycode' => { 452 => [\'LocationShown','LocationShownCountryCode'] }, - 'locationshowncountryname' => { 452 => [\'LocationShown','LocationShownCountryName'] }, - 'locationshowngpsaltitude' => { 452 => [\'LocationShown','LocationShownGPSAltitude'] }, - 'locationshowngpslatitude' => { 452 => [\'LocationShown','LocationShownGPSLatitude'] }, - 'locationshowngpslongitude' => { 452 => [\'LocationShown','LocationShownGPSLongitude'] }, - 'locationshownidentifier' => { 452 => [\'LocationShown','LocationShownIdentifier'] }, - 'locationshownlocationid' => { 452 => [\'LocationShown','LocationShownLocationId'] }, - 'locationshownlocationname' => { 452 => [\'LocationShown','LocationShownLocationName'] }, - 'locationshownprovincestate' => { 452 => [\'LocationShown','LocationShownProvinceState'] }, - 'locationshownsublocation' => { 452 => [\'LocationShown','LocationShownSublocation'] }, - 'locationshownworldregion' => { 452 => [\'LocationShown','LocationShownWorldRegion'] }, - 'lockmicrophonebutton' => { 78 => 0x709 }, - 'logcomment' => { 466 => 'logComment' }, - 'logscale' => { 131 => 0x902 }, - 'longexposurenoisereduction' => { 59 => 0x4, 78 => 0x201, 79 => 0x1, 80 => 0x2, 81 => 0x1, 82 => 0x1, 83 => 0x2, 84 => 0x1, 297 => 0x49, 376 => 0x2b, 377 => 0x25, 378 => 0x25, 388 => 0x2008, 393 => 0x11, 417 => 0x44 }, - 'longexposurenoisereduction2' => { 54 => 0x8 }, - 'loop' => { 466 => 'loop' }, - 'lowestbiostratigraphiczone' => { 112 => [\'GeologicalContext','GeologicalContextLowestBiostratigraphicZone'] }, - 'luminanceadjustmentaqua' => { 442 => 'LuminanceAdjustmentAqua' }, - 'luminanceadjustmentblue' => { 442 => 'LuminanceAdjustmentBlue' }, - 'luminanceadjustmentgreen' => { 442 => 'LuminanceAdjustmentGreen' }, - 'luminanceadjustmentmagenta' => { 442 => 'LuminanceAdjustmentMagenta' }, - 'luminanceadjustmentorange' => { 442 => 'LuminanceAdjustmentOrange' }, - 'luminanceadjustmentpurple' => { 442 => 'LuminanceAdjustmentPurple' }, - 'luminanceadjustmentred' => { 442 => 'LuminanceAdjustmentRed' }, - 'luminanceadjustmentyellow' => { 442 => 'LuminanceAdjustmentYellow' }, - 'luminancecurvelimits' => { 102 => 0x150 }, - 'luminancecurvepoints' => { 102 => 0x126 }, - 'luminancenoisereduction' => { 97 => 0x20600, 103 => 0x5f, 368 => 0x1b }, - 'luminancenoisereductioncontrast' => { 442 => 'LuminanceNoiseReductionContrast' }, - 'luminancenoisereductiondetail' => { 442 => 'LuminanceNoiseReductionDetail' }, - 'luminancenr_tiff_jpeg' => { 103 => 0x6d }, - 'luminancesmoothing' => { 442 => 'LuminanceSmoothing' }, - 'lvshootingareadisplay' => { 78 => [0x40b,0x40c] }, - 'lyrics' => { 466 => 'lyrics' }, - 'm16cversion' => { 292 => 0x333 }, - 'macatom' => { 441 => 'macAtom' }, - 'macatomapplicationcode' => { 441 => [\'macAtom','macAtomApplicationCode'] }, - 'macatominvocationappleevent' => { 441 => [\'macAtom','macAtomInvocationAppleEvent'] }, - 'macatomposixprojectpath' => { 441 => [\'macAtom','macAtomPosixProjectPath'] }, - 'machineobservation' => { 112 => 'MachineObservation' }, - 'machineobservationday' => { 112 => [\'MachineObservation','MachineObservationDay'] }, - 'machineobservationearliestdate' => { 112 => [\'MachineObservation','MachineObservationEarliestDate'] }, - 'machineobservationenddayofyear' => { 112 => [\'MachineObservation','MachineObservationEndDayOfYear'] }, - 'machineobservationeventdate' => { 112 => [\'MachineObservation','MachineObservationEventDate'] }, - 'machineobservationeventid' => { 112 => [\'MachineObservation','MachineObservationEventID'] }, - 'machineobservationeventremarks' => { 112 => [\'MachineObservation','MachineObservationEventRemarks'] }, - 'machineobservationeventtime' => { 112 => [\'MachineObservation','MachineObservationEventTime'] }, - 'machineobservationfieldnotes' => { 112 => [\'MachineObservation','MachineObservationFieldNotes'] }, - 'machineobservationfieldnumber' => { 112 => [\'MachineObservation','MachineObservationFieldNumber'] }, - 'machineobservationhabitat' => { 112 => [\'MachineObservation','MachineObservationHabitat'] }, - 'machineobservationlatestdate' => { 112 => [\'MachineObservation','MachineObservationLatestDate'] }, - 'machineobservationmonth' => { 112 => [\'MachineObservation','MachineObservationMonth'] }, - 'machineobservationparenteventid' => { 112 => [\'MachineObservation','MachineObservationParentEventID'] }, - 'machineobservationsamplesizeunit' => { 112 => [\'MachineObservation','MachineObservationSampleSizeUnit'] }, - 'machineobservationsamplesizevalue' => { 112 => [\'MachineObservation','MachineObservationSampleSizeValue'] }, - 'machineobservationsamplingeffort' => { 112 => [\'MachineObservation','MachineObservationSamplingEffort'] }, - 'machineobservationsamplingprotocol' => { 112 => [\'MachineObservation','MachineObservationSamplingProtocol'] }, - 'machineobservationstartdayofyear' => { 112 => [\'MachineObservation','MachineObservationStartDayOfYear'] }, - 'machineobservationverbatimeventdate' => { 112 => [\'MachineObservation','MachineObservationVerbatimEventDate'] }, - 'machineobservationyear' => { 112 => [\'MachineObservation','MachineObservationYear'] }, - 'macro' => { 121 => 0x1020, 123 => 0x202, 279 => 0x202, 357 => 0x21, 367 => 0x202, 388 => 0xb040 }, - 'macroled' => { 277 => 0x120a }, - 'macromagnification' => { 6 => 0x1b, 10 => 0x1b, 13 => 0x1b, 14 => 0x1b, 18 => 0x1b, 19 => 0x1b, 54 => 0x10 }, - 'macromode' => { 33 => 0x1, 171 => 0xb, 274 => 0x300, 297 => 0x1c, 358 => 0x1009 }, - 'magentahsl' => { 97 => 0x20917 }, - 'magicfilter' => { 274 => 0x52c }, - 'magnifiedview' => { 80 => 0x11, 82 => 0x9 }, - 'mainboardversion' => { 131 => 0x438 }, - 'maindialexposurecomp' => { 268 => '0.6' }, - 'mainingredient' => { 458 => 'mainIngredient' }, - 'majorversion' => { 432 => 'MajorVersion' }, - 'make' => { 92 => 0x0, 109 => 0x1, 113 => 0x10f, 147 => 'Make', 287 => 'Make', 302 => 0x10f, 455 => 'make', 462 => 'Make' }, - 'makernote' => { 446 => 'MakerNote' }, - 'makernoteapple' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotecanon' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotecasio' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotecasio2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotedji' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteflir' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotefujifilm' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotege' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotege2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotehasselblad' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotehp' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotehp2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotehp4' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotehp6' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteisl' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotejvc' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotejvctext' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak10' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak11' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak12' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak1a' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak1b' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak3' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak4' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak5' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak6a' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak6b' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak7' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak8a' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak8b' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak8c' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodak9' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekodakunknown' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotekyocera' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteleica' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteleica2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteleica3' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteleica4' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteleica5' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteleica6' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteleica7' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteleica8' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteleica9' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteminolta' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteminolta2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteminolta3' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotemotorola' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotenikon' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotenikon2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotenikon3' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotenintendo' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteoffset' => { 367 => 0xff }, - 'makernoteolympus' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteolympus2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotepanasonic' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotepanasonic2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotepanasonic3' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotepentax' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotepentax2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotepentax3' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotepentax4' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotepentax5' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotepentax6' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotephaseone' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotereconyx' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotereconyx2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotericoh' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotericoh2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotericohtext' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesafety' => { 113 => 0xc635 }, - 'makernotesamsung1a' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesamsung1b' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesamsung2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesanyo' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesanyoc4' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesanyopatch' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesigma' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesony' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesony2' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesony3' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesony4' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesony5' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesonyericsson' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotesonysrf' => { 111 => 'MakN', 113 => 0x927c }, - 'makernotetype' => { 358 => 0x1 }, - 'makernoteunknown' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteunknownbinary' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteunknowntext' => { 111 => 'MakN', 113 => 0x927c }, - 'makernoteversion' => { 176 => 0x0, 211 => 0x1, 279 => 0x0, 297 => 0x8000, 362 => 0x0, 365 => 0x1, 368 => [0x1d,0x1f], 379 => 0x2000 }, - 'managedfrom' => { 467 => 'ManagedFrom' }, - 'managedfromalternatepaths' => { 467 => [\'ManagedFrom','ManagedFromAlternatePaths'] }, - 'managedfromdocumentid' => { 467 => [\'ManagedFrom','ManagedFromDocumentID'] }, - 'managedfromfilepath' => { 467 => [\'ManagedFrom','ManagedFromFilePath'] }, - 'managedfromfrompart' => { 467 => [\'ManagedFrom','ManagedFromFromPart'] }, - 'managedfrominstanceid' => { 467 => [\'ManagedFrom','ManagedFromInstanceID'] }, - 'managedfromlastmodifydate' => { 467 => [\'ManagedFrom','ManagedFromLastModifyDate'] }, - 'managedfromlasturl' => { 467 => [\'ManagedFrom','ManagedFromLastURL'] }, - 'managedfromlinkcategory' => { 467 => [\'ManagedFrom','ManagedFromLinkCategory'] }, - 'managedfromlinkform' => { 467 => [\'ManagedFrom','ManagedFromLinkForm'] }, - 'managedfrommanager' => { 467 => [\'ManagedFrom','ManagedFromManager'] }, - 'managedfrommanagervariant' => { 467 => [\'ManagedFrom','ManagedFromManagerVariant'] }, - 'managedfrommanageto' => { 467 => [\'ManagedFrom','ManagedFromManageTo'] }, - 'managedfrommanageui' => { 467 => [\'ManagedFrom','ManagedFromManageUI'] }, - 'managedfrommaskmarkers' => { 467 => [\'ManagedFrom','ManagedFromMaskMarkers'] }, - 'managedfromoriginaldocumentid' => { 467 => [\'ManagedFrom','ManagedFromOriginalDocumentID'] }, - 'managedfrompartmapping' => { 467 => [\'ManagedFrom','ManagedFromPartMapping'] }, - 'managedfromplacedresolutionunit' => { 467 => [\'ManagedFrom','ManagedFromPlacedResolutionUnit'] }, - 'managedfromplacedxresolution' => { 467 => [\'ManagedFrom','ManagedFromPlacedXResolution'] }, - 'managedfromplacedyresolution' => { 467 => [\'ManagedFrom','ManagedFromPlacedYResolution'] }, - 'managedfromrenditionclass' => { 467 => [\'ManagedFrom','ManagedFromRenditionClass'] }, - 'managedfromrenditionparams' => { 467 => [\'ManagedFrom','ManagedFromRenditionParams'] }, - 'managedfromtopart' => { 467 => [\'ManagedFrom','ManagedFromToPart'] }, - 'managedfromversionid' => { 467 => [\'ManagedFrom','ManagedFromVersionID'] }, - 'manager' => { 467 => 'Manager' }, - 'managervariant' => { 467 => 'ManagerVariant' }, - 'manageto' => { 467 => 'ManageTo' }, - 'manageui' => { 467 => 'ManageUI' }, - 'manifest' => { 467 => 'Manifest' }, - 'manifestlinkform' => { 467 => [\'Manifest','ManifestLinkForm'] }, - 'manifestplacedresolutionunit' => { 467 => [\'Manifest','ManifestPlacedResolutionUnit'] }, - 'manifestplacedxresolution' => { 467 => [\'Manifest','ManifestPlacedXResolution'] }, - 'manifestplacedyresolution' => { 467 => [\'Manifest','ManifestPlacedYResolution'] }, - 'manifestreference' => { 467 => [\'Manifest','ManifestReference'] }, - 'manifestreferencealternatepaths' => { 467 => [\'Manifest','ManifestReferenceAlternatePaths'] }, - 'manifestreferencedocumentid' => { 467 => [\'Manifest','ManifestReferenceDocumentID'] }, - 'manifestreferencefilepath' => { 467 => [\'Manifest','ManifestReferenceFilePath'] }, - 'manifestreferencefrompart' => { 467 => [\'Manifest','ManifestReferenceFromPart'] }, - 'manifestreferenceinstanceid' => { 467 => [\'Manifest','ManifestReferenceInstanceID'] }, - 'manifestreferencelastmodifydate' => { 467 => [\'Manifest','ManifestReferenceLastModifyDate'] }, - 'manifestreferencelasturl' => { 467 => [\'Manifest','ManifestReferenceLastURL'] }, - 'manifestreferencelinkcategory' => { 467 => [\'Manifest','ManifestReferenceLinkCategory'] }, - 'manifestreferencelinkform' => { 467 => [\'Manifest','ManifestReferenceLinkForm'] }, - 'manifestreferencemanager' => { 467 => [\'Manifest','ManifestReferenceManager'] }, - 'manifestreferencemanagervariant' => { 467 => [\'Manifest','ManifestReferenceManagerVariant'] }, - 'manifestreferencemanageto' => { 467 => [\'Manifest','ManifestReferenceManageTo'] }, - 'manifestreferencemanageui' => { 467 => [\'Manifest','ManifestReferenceManageUI'] }, - 'manifestreferencemaskmarkers' => { 467 => [\'Manifest','ManifestReferenceMaskMarkers'] }, - 'manifestreferenceoriginaldocumentid' => { 467 => [\'Manifest','ManifestReferenceOriginalDocumentID'] }, - 'manifestreferencepartmapping' => { 467 => [\'Manifest','ManifestReferencePartMapping'] }, - 'manifestreferenceplacedresolutionunit' => { 467 => [\'Manifest','ManifestReferencePlacedResolutionUnit'] }, - 'manifestreferenceplacedxresolution' => { 467 => [\'Manifest','ManifestReferencePlacedXResolution'] }, - 'manifestreferenceplacedyresolution' => { 467 => [\'Manifest','ManifestReferencePlacedYResolution'] }, - 'manifestreferencerenditionclass' => { 467 => [\'Manifest','ManifestReferenceRenditionClass'] }, - 'manifestreferencerenditionparams' => { 467 => [\'Manifest','ManifestReferenceRenditionParams'] }, - 'manifestreferencetopart' => { 467 => [\'Manifest','ManifestReferenceToPart'] }, - 'manifestreferenceversionid' => { 467 => [\'Manifest','ManifestReferenceVersionID'] }, - 'manometerpressure' => { 274 => 0x900, 297 => 0x86 }, - 'manometerreading' => { 274 => 0x901 }, - 'manualafpointselectpattern' => { 78 => 0x513 }, + 'lense-mountversion' => { 409 => 0x3f0, 454 => 0xd }, + 'lensfirmware' => { 388 => 0x20, 394 => 0xa004 }, + 'lensfirmwareversion' => { 298 => 0x204, 320 => 0x60, 409 => 0x3f3, 454 => 0x14 }, + 'lensfocallength' => { 103 => 0xf0512, 346 => 0x9 }, + 'lensfocalrange' => { 397 => [0xa,0x2a] }, + 'lensfocusfunctionbuttons' => { 280 => '55.1', 282 => '52.1', 283 => '52.1', 292 => '52.1', 293 => '52.1' }, + 'lensformat' => { 433 => 0x1891, 435 => 0x18bd, 436 => 0x18ed, 437 => 0x17f1, 439 => 0x106, 440 => 0x106, 450 => 0x603, 451 => 0x5d }, + 'lensfstops' => { 218 => 0x7, 219 => 0xc, 220 => 0xd, 224 => 0xe, 226 => 0x8b, 346 => '0.3' }, + 'lensfunc1button' => { 295 => 0x9f }, + 'lensfunc2button' => { 295 => 0xa7 }, + 'lensid' => { 224 => 0x30, 475 => 'LensID' }, + 'lensidnumber' => { 218 => 0x6, 219 => 0xb, 220 => 0xc, 224 => 0xd }, + 'lensinfo' => { 119 => 0xa432, 352 => 0x2a, 475 => 'LensInfo', 485 => 'LensSpecification' }, + 'lenskind' => { 346 => 0x1 }, + 'lensmake' => { 119 => 0xa433, 163 => 'Make', 485 => 'LensMake' }, + 'lensmanualdistortionamount' => { 478 => 'LensManualDistortionAmount', 480 => 'LensManualDistortionAmount' }, + 'lensmanufacturer' => { 178 => 'LensManufacturer' }, + 'lensmaxaperturerange' => { 397 => 0x2b }, + 'lensmodel' => { 7 => 0x937, 14 => 0x92b, 15 => 0x933, 64 => 0x95, 119 => 0xa434, 163 => 'Model', 178 => 'LensModel', 221 => 0x18a, 222 => 0x18b, 223 => 0x2ac, 298 => 0x203, 352 => 0xc, 364 => 0x412, 485 => 'LensModel' }, + 'lensmodulationoptimizer' => { 127 => 0x1045 }, + 'lensmount' => { 409 => 0x99, 433 => 0x1892, 435 => 0x18be, 436 => 0x18ee, 437 => 0x17f2, 439 => 0x105, 440 => 0x105, 450 => 0x604, 451 => 0x5e }, + 'lensmount2' => { 454 => 0x8 }, + 'lensmounttype' => { 224 => 0x35 }, + 'lenspositionabsolute' => { 224 => 0x5a }, + 'lensprofilechromaticaberrationscale' => { 478 => 'LensProfileChromaticAberrationScale', 480 => 'LensProfileChromaticAberrationScale' }, + 'lensprofiledigest' => { 478 => 'LensProfileDigest', 480 => 'LensProfileDigest' }, + 'lensprofiledistortionscale' => { 478 => 'LensProfileDistortionScale', 480 => 'LensProfileDistortionScale' }, + 'lensprofileenable' => { 478 => 'LensProfileEnable', 480 => 'LensProfileEnable' }, + 'lensprofilefilename' => { 478 => 'LensProfileFilename', 480 => 'LensProfileFilename' }, + 'lensprofileisembedded' => { 478 => 'LensProfileIsEmbedded', 480 => 'LensProfileIsEmbedded' }, + 'lensprofilematchkeycameramodelname' => { 478 => 'LensProfileMatchKeyCameraModelName', 480 => 'LensProfileMatchKeyCameraModelName' }, + 'lensprofilematchkeyexifmake' => { 478 => 'LensProfileMatchKeyExifMake', 480 => 'LensProfileMatchKeyExifMake' }, + 'lensprofilematchkeyexifmodel' => { 478 => 'LensProfileMatchKeyExifModel', 480 => 'LensProfileMatchKeyExifModel' }, + 'lensprofilematchkeyisraw' => { 478 => 'LensProfileMatchKeyIsRaw', 480 => 'LensProfileMatchKeyIsRaw' }, + 'lensprofilematchkeylensid' => { 478 => 'LensProfileMatchKeyLensID', 480 => 'LensProfileMatchKeyLensID' }, + 'lensprofilematchkeylensinfo' => { 478 => 'LensProfileMatchKeyLensInfo', 480 => 'LensProfileMatchKeyLensInfo' }, + 'lensprofilematchkeylensname' => { 478 => 'LensProfileMatchKeyLensName', 480 => 'LensProfileMatchKeyLensName' }, + 'lensprofilematchkeysensorformatfactor' => { 478 => 'LensProfileMatchKeySensorFormatFactor', 480 => 'LensProfileMatchKeySensorFormatFactor' }, + 'lensprofilename' => { 478 => 'LensProfileName', 480 => 'LensProfileName' }, + 'lensprofilesetup' => { 478 => 'LensProfileSetup', 480 => 'LensProfileSetup' }, + 'lensprofilevignettingscale' => { 478 => 'LensProfileVignettingScale', 480 => 'LensProfileVignettingScale' }, + 'lensproperties' => { 298 => 0x20b }, + 'lensserialnumber' => { 21 => 0x164, 32 => 0x16b, 61 => 0x0, 119 => 0xa435, 163 => 'SerialNumber', 298 => 0x202, 318 => 0x321, 320 => 0x52, 380 => 'LENS', 388 => 0x30, 475 => 'LensSerialNumber', 485 => 'LensSerialNumber' }, + 'lensshutterlock' => { 184 => 0x4a }, + 'lensspec' => { 404 => 0x0, 405 => 0x0, 406 => 0x0, 420 => 0xb02a }, + 'lensspecfeatures' => { 439 => [0x115,0x116], 440 => [0x116,0x1ed,0x1f0,0x21c,0x21e] }, + 'lenstemperature' => { 302 => 0x1008 }, + 'lenstype' => { 7 => 0xe2, 8 => 0xd, 9 => 0x1a7, 10 => 0xc, 11 => 0x111, 12 => 0xc, 13 => 0x14f, 14 => 0xd6, 15 => 0xde, 16 => 0xf6, 17 => 0xea, 18 => 0xff, 19 => [0xc,0x97], 20 => 0xe6, 21 => 0x153, 22 => 0xea, 23 => 0xe8, 24 => 0x127, 25 => 0x161, 26 => 0x166, 27 => 0x184, 28 => 0x112, 29 => 0x189, 34 => 0x16, 186 => 0x10c, 187 => 0x49bd, 226 => 0x83, 298 => 0x201, 311 => 0x16, 315 => 0x310, 317 => 0x303, 318 => 0x303, 320 => 0x51, 322 => 0x3405, 347 => 0x0, 348 => 0x0, 349 => 0x1, 350 => 0x1, 351 => 0x1, 353 => 0x0, 394 => 0xa003, 397 => 0x27, 420 => 0xb027, 433 => 0x1896, 435 => 0x18c2, 436 => 0x18f2, 437 => 0x17f6, 439 => 0x109, 440 => 0x109, 450 => 0x608, 451 => 0x62 }, + 'lenstype2' => { 409 => 0x3f7, 433 => 0x1893, 435 => 0x18bf, 436 => 0x18ef, 437 => 0x17f3, 439 => 0x107, 440 => 0x107, 450 => 0x605, 451 => 0x60 }, + 'lenstype3' => { 454 => 0x9 }, + 'lenstypemake' => { 320 => 0xc4 }, + 'lenstypemodel' => { 320 => [0xc5,0xe4] }, + 'lenszoomposition' => { 447 => 0x19, 448 => 0x1e, 451 => [0x342,0x34e,0x35a] }, + 'levelindicator' => { 328 => 0x15 }, + 'levelmeter' => { 380 => ['Lvlm','lvlm'] }, + 'levelorientation' => { 354 => 0x0 }, + 'license' => { 476 => 'license' }, + 'licensee' => { 307 => 'Licensee' }, + 'licenseeid' => { 307 => [\'Licensee','LicenseeLicenseeID'] }, + 'licenseeimageid' => { 307 => 'LicenseeImageID' }, + 'licenseeimagenotes' => { 307 => 'LicenseeImageNotes' }, + 'licenseename' => { 307 => [\'Licensee','LicenseeLicenseeName'] }, + 'licenseenddate' => { 307 => 'LicenseEndDate' }, + 'licenseeprojectreference' => { 307 => 'LicenseeProjectReference' }, + 'licenseetransactionid' => { 307 => 'LicenseeTransactionID' }, + 'licenseid' => { 307 => 'LicenseID' }, + 'licensestartdate' => { 307 => 'LicenseStartDate' }, + 'licensetransactiondate' => { 307 => 'LicenseTransactionDate' }, + 'licensetype' => { 482 => 'licensetype' }, + 'licensor' => { 307 => 'Licensor' }, + 'licensorcity' => { 307 => [\'Licensor','LicensorLicensorCity'] }, + 'licensorcountry' => { 307 => [\'Licensor','LicensorLicensorCountry'] }, + 'licensoremail' => { 307 => [\'Licensor','LicensorLicensorEmail'] }, + 'licensorextendedaddress' => { 307 => [\'Licensor','LicensorLicensorExtendedAddress'] }, + 'licensorid' => { 307 => [\'Licensor','LicensorLicensorID'] }, + 'licensorimageid' => { 307 => 'LicensorImageID' }, + 'licensorname' => { 307 => [\'Licensor','LicensorLicensorName'] }, + 'licensornotes' => { 307 => 'LicensorNotes' }, + 'licensorpostalcode' => { 307 => [\'Licensor','LicensorLicensorPostalCode'] }, + 'licensorregion' => { 307 => [\'Licensor','LicensorLicensorRegion'] }, + 'licensorstreetaddress' => { 307 => [\'Licensor','LicensorLicensorStreetAddress'] }, + 'licensortelephone1' => { 307 => [\'Licensor','LicensorLicensorTelephone1'] }, + 'licensortelephone2' => { 307 => [\'Licensor','LicensorLicensorTelephone2'] }, + 'licensortelephonetype1' => { 307 => [\'Licensor','LicensorLicensorTelephoneType1'] }, + 'licensortelephonetype2' => { 307 => [\'Licensor','LicensorLicensorTelephoneType2'] }, + 'licensortransactionid' => { 307 => 'LicensorTransactionID' }, + 'licensorurl' => { 307 => [\'Licensor','LicensorLicensorURL'] }, + 'lightcondition' => { 302 => 0x1009 }, + 'lightingmode' => { 113 => 0x302a }, + 'lightreading' => { 355 => 0x15 }, + 'lightsource' => { 119 => 0x9208, 226 => 0x90, 305 => 0x1000, 484 => 'LightSource' }, + 'lightsourcespecial' => { 396 => 0x21d }, + 'lightswitch' => { 292 => '0.1', 294 => '0.1' }, + 'lightvaluecenter' => { 302 => 0x103d }, + 'lightvalueperiphery' => { 302 => 0x103e }, + 'limitaf-areamodesel3dtracking' => { 295 => 0x153 }, + 'limitaf-areamodeseldynamic_l' => { 295 => 0x151 }, + 'limitaf-areamodeseldynamic_m' => { 295 => 0x150 }, + 'limitaf-areamodeseldynamic_s' => { 295 => 0x14f }, + 'limitaf-areamodeselpinpoint' => { 295 => 0x11 }, + 'limitaf-areamodeselwideaf_l' => { 295 => 0x14 }, + 'limitaf-areamodeselwideaf_s' => { 295 => 0x13 }, + 'limitafareamodeselauto' => { 295 => 0x15 }, + 'limitafareamodeselection' => { 280 => '51.1', 282 => '49.1', 283 => '49.1', 292 => '49.1', 293 => '49.1' }, + 'limitreleasemodeselc120' => { 295 => '269.4' }, + 'limitreleasemodeselc30' => { 295 => '269.3' }, + 'limitreleasemodeselch' => { 295 => '269.2' }, + 'limitreleasemodeselcl' => { 295 => '269.1' }, + 'limitreleasemodeselself' => { 295 => '269.5' }, + 'limitselectableimagearea16to9' => { 295 => 0x47 }, + 'limitselectableimagearea1to1' => { 295 => 0x46 }, + 'limitselectableimageareadx' => { 295 => 0x45 }, + 'linearitylimitblue' => { 325 => 0x10 }, + 'linearitylimitgreen' => { 325 => 0xf }, + 'linearitylimitred' => { 325 => 0xe }, + 'linearityuppermargin' => { 41 => 0x32c, 42 => 0x282, 45 => [0x2ba,0x2d1,0x2d5], 47 => 0x1e5, 48 => [0x1fe,0x2de], 49 => [0x232,0x310], 50 => 0x31e }, + 'linearizationtable' => { 119 => 0xc618 }, + 'linearresponselimit' => { 119 => 0xc62e }, + 'link' => { 494 => 'link' }, + 'linkaetoafpoint' => { 336 => '14.2' }, + 'linkedencodedrightsexpr' => { 490 => [\'LinkedEncRightsExpr','LinkedEncRightsExprLinkedRightsExpr'] }, + 'linkedencodedrightsexprlangid' => { 490 => [\'LinkedEncRightsExpr','LinkedEncRightsExprRightsExprLangId'] }, + 'linkedencodedrightsexprtype' => { 490 => [\'LinkedEncRightsExpr','LinkedEncRightsExprRightsExprEncType'] }, + 'linkedencrightsexpr' => { 490 => 'LinkedEncRightsExpr' }, + 'linlogcoring' => { 138 => 0x904 }, + 'lithostratigraphicterms' => { 118 => [\'GeologicalContext','GeologicalContextLithostratigraphicTerms'] }, + 'livephotoauto' => { 374 => 'live-photo.auto' }, + 'livephotovitalityscore' => { 374 => 'live-photo.vitality-score' }, + 'livephotovitalityscoringversion' => { 374 => 'live-photo.vitality-scoring-version' }, + 'liveviewaf' => { 284 => '32.1', 294 => '34.1' }, + 'liveviewafareamode' => { 289 => '34.1' }, + 'liveviewafmethod' => { 425 => 0x20 }, + 'liveviewafmode' => { 289 => '34.2' }, + 'liveviewafsetting' => { 409 => 0x36 }, + 'liveviewbuttonoptions' => { 280 => '50.2', 282 => '48.2', 283 => '48.2', 292 => '48.2', 293 => '48.2' }, + 'liveviewexposuresimulation' => { 84 => 0x810 }, + 'liveviewfocusmode' => { 409 => [0x8b,0x28b] }, + 'liveviewmetering' => { 409 => [0x84,0x284] }, + 'liveviewmonitorofftime' => { 280 => '21.2', 282 => '21.2', 283 => '21.2', 285 => '20.2', 286 => '20.2', 287 => '20.2', 289 => '20.2', 292 => '21.2', 293 => '21.2' }, + 'liveviewshooting' => { 57 => 0x13 }, + 'livingspecimen' => { 118 => 'LivingSpecimen' }, + 'livingspecimenmaterialsampleid' => { 118 => [\'LivingSpecimen','LivingSpecimenMaterialSampleID'] }, + 'localcaption' => { 131 => 0x79 }, + 'localizedcameramodel' => { 119 => 0xc615 }, + 'locallocationname' => { 394 => 0x30 }, + 'location' => { 225 => 0x9, 320 => 0x67, 471 => 'Location', 489 => 'Location', 493 => 'location', 494 => 'location' }, + 'locationaccuracyhorizontal' => { 374 => 'location.accuracy.horizontal' }, + 'locationareacode' => { 477 => 'lac' }, + 'locationbody' => { 374 => 'location.body' }, + 'locationcreated' => { 490 => 'LocationCreated' }, + 'locationcreatedcity' => { 490 => [\'LocationCreated','LocationCreatedCity'] }, + 'locationcreatedcountrycode' => { 490 => [\'LocationCreated','LocationCreatedCountryCode'] }, + 'locationcreatedcountryname' => { 490 => [\'LocationCreated','LocationCreatedCountryName'] }, + 'locationcreatedgpsaltitude' => { 490 => [\'LocationCreated','LocationCreatedGPSAltitude'] }, + 'locationcreatedgpslatitude' => { 490 => [\'LocationCreated','LocationCreatedGPSLatitude'] }, + 'locationcreatedgpslongitude' => { 490 => [\'LocationCreated','LocationCreatedGPSLongitude'] }, + 'locationcreatedidentifier' => { 490 => [\'LocationCreated','LocationCreatedIdentifier'] }, + 'locationcreatedlocationid' => { 490 => [\'LocationCreated','LocationCreatedLocationId'] }, + 'locationcreatedlocationname' => { 490 => [\'LocationCreated','LocationCreatedLocationName'] }, + 'locationcreatedprovincestate' => { 490 => [\'LocationCreated','LocationCreatedProvinceState'] }, + 'locationcreatedsublocation' => { 490 => [\'LocationCreated','LocationCreatedSublocation'] }, + 'locationcreatedworldregion' => { 490 => [\'LocationCreated','LocationCreatedWorldRegion'] }, + 'locationdate' => { 374 => 'location.date' }, + 'locationinformation' => { 380 => 'loci' }, + 'locationinfoversion' => { 225 => 0x0 }, + 'locationname' => { 374 => 'location.name', 394 => 0x31 }, + 'locationnote' => { 374 => 'location.note' }, + 'locationrole' => { 374 => 'location.role' }, + 'locationshown' => { 490 => 'LocationShown' }, + 'locationshowncity' => { 490 => [\'LocationShown','LocationShownCity'] }, + 'locationshowncountrycode' => { 490 => [\'LocationShown','LocationShownCountryCode'] }, + 'locationshowncountryname' => { 490 => [\'LocationShown','LocationShownCountryName'] }, + 'locationshowngpsaltitude' => { 490 => [\'LocationShown','LocationShownGPSAltitude'] }, + 'locationshowngpslatitude' => { 490 => [\'LocationShown','LocationShownGPSLatitude'] }, + 'locationshowngpslongitude' => { 490 => [\'LocationShown','LocationShownGPSLongitude'] }, + 'locationshownidentifier' => { 490 => [\'LocationShown','LocationShownIdentifier'] }, + 'locationshownlocationid' => { 490 => [\'LocationShown','LocationShownLocationId'] }, + 'locationshownlocationname' => { 490 => [\'LocationShown','LocationShownLocationName'] }, + 'locationshownprovincestate' => { 490 => [\'LocationShown','LocationShownProvinceState'] }, + 'locationshownsublocation' => { 490 => [\'LocationShown','LocationShownSublocation'] }, + 'locationshownworldregion' => { 490 => [\'LocationShown','LocationShownWorldRegion'] }, + 'lockmicrophonebutton' => { 84 => 0x709 }, + 'logcomment' => { 504 => 'logComment' }, + 'logscale' => { 138 => 0x902 }, + 'longdescription' => { 372 => 'ldes' }, + 'longexposurenoisereduction' => { 62 => 0x4, 84 => 0x201, 85 => 0x1, 86 => 0x2, 87 => 0x1, 88 => 0x1, 89 => 0x2, 90 => 0x1, 320 => 0x49, 407 => 0x2b, 408 => 0x25, 409 => 0x25, 420 => 0x2008, 425 => 0x11, 451 => 0x44 }, + 'longexposurenoisereduction2' => { 57 => 0x8 }, + 'longexposurenrused' => { 320 => 0xbe }, + 'longitude' => { 116 => 'Longitude' }, + 'look' => { 478 => 'Look', 480 => 'Look' }, + 'lookamount' => { 478 => [\'Look','LookAmount'], 480 => [\'Look','LookAmount'] }, + 'lookcluster' => { 478 => [\'Look','LookCluster'], 480 => [\'Look','LookCluster'] }, + 'lookcopyright' => { 478 => [\'Look','LookCopyright'], 480 => [\'Look','LookCopyright'] }, + 'lookgroup' => { 478 => [\'Look','LookGroup'], 480 => [\'Look','LookGroup'] }, + 'lookname' => { 478 => 'LookName', 480 => 'LookName' }, + 'lookparameters' => { 478 => [\'Look','LookParameters'], 480 => [\'Look','LookParameters'] }, + 'lookparameterscameraprofile' => { 478 => [\'Look','LookParametersCameraProfile'], 480 => [\'Look','LookParametersCameraProfile'] }, + 'lookparametersclarity2012' => { 478 => [\'Look','LookParametersClarity2012'], 480 => [\'Look','LookParametersClarity2012'] }, + 'lookparametersconverttograyscale' => { 478 => [\'Look','LookParametersConvertToGrayscale'], 480 => [\'Look','LookParametersConvertToGrayscale'] }, + 'lookparameterslooktable' => { 478 => [\'Look','LookParametersLookTable'], 480 => [\'Look','LookParametersLookTable'] }, + 'lookparametersprocessversion' => { 478 => [\'Look','LookParametersProcessVersion'], 480 => [\'Look','LookParametersProcessVersion'] }, + 'lookparameterstonecurvepv2012' => { 478 => [\'Look','LookParametersToneCurvePV2012'], 480 => [\'Look','LookParametersToneCurvePV2012'] }, + 'lookparameterstonecurvepv2012blue' => { 478 => [\'Look','LookParametersToneCurvePV2012Blue'], 480 => [\'Look','LookParametersToneCurvePV2012Blue'] }, + 'lookparameterstonecurvepv2012green' => { 478 => [\'Look','LookParametersToneCurvePV2012Green'], 480 => [\'Look','LookParametersToneCurvePV2012Green'] }, + 'lookparameterstonecurvepv2012red' => { 478 => [\'Look','LookParametersToneCurvePV2012Red'], 480 => [\'Look','LookParametersToneCurvePV2012Red'] }, + 'lookparametersversion' => { 478 => [\'Look','LookParametersVersion'], 480 => [\'Look','LookParametersVersion'] }, + 'looksupportsamount' => { 478 => [\'Look','LookSupportsAmount'], 480 => [\'Look','LookSupportsAmount'] }, + 'looksupportsmonochrome' => { 478 => [\'Look','LookSupportsMonochrome'], 480 => [\'Look','LookSupportsMonochrome'] }, + 'looksupportsoutputreferred' => { 478 => [\'Look','LookSupportsOutputReferred'], 480 => [\'Look','LookSupportsOutputReferred'] }, + 'lookuuid' => { 478 => [\'Look','LookUUID'], 480 => [\'Look','LookUUID'] }, + 'loop' => { 504 => 'loop' }, + 'loopstyle' => { 380 => 'LOOP' }, + 'lowestbiostratigraphiczone' => { 118 => [\'GeologicalContext','GeologicalContextLowestBiostratigraphicZone'] }, + 'luminanceadjustmentaqua' => { 478 => 'LuminanceAdjustmentAqua', 480 => 'LuminanceAdjustmentAqua' }, + 'luminanceadjustmentblue' => { 478 => 'LuminanceAdjustmentBlue', 480 => 'LuminanceAdjustmentBlue' }, + 'luminanceadjustmentgreen' => { 478 => 'LuminanceAdjustmentGreen', 480 => 'LuminanceAdjustmentGreen' }, + 'luminanceadjustmentmagenta' => { 478 => 'LuminanceAdjustmentMagenta', 480 => 'LuminanceAdjustmentMagenta' }, + 'luminanceadjustmentorange' => { 478 => 'LuminanceAdjustmentOrange', 480 => 'LuminanceAdjustmentOrange' }, + 'luminanceadjustmentpurple' => { 478 => 'LuminanceAdjustmentPurple', 480 => 'LuminanceAdjustmentPurple' }, + 'luminanceadjustmentred' => { 478 => 'LuminanceAdjustmentRed', 480 => 'LuminanceAdjustmentRed' }, + 'luminanceadjustmentyellow' => { 478 => 'LuminanceAdjustmentYellow', 480 => 'LuminanceAdjustmentYellow' }, + 'luminancecurvelimits' => { 108 => 0x150 }, + 'luminancecurvepoints' => { 108 => 0x126 }, + 'luminancenoisereduction' => { 103 => 0x20600, 109 => 0x5f, 397 => 0x1b }, + 'luminancenoisereductioncontrast' => { 478 => 'LuminanceNoiseReductionContrast', 480 => 'LuminanceNoiseReductionContrast' }, + 'luminancenoisereductiondetail' => { 478 => 'LuminanceNoiseReductionDetail', 480 => 'LuminanceNoiseReductionDetail' }, + 'luminancenr_tiff_jpeg' => { 109 => 0x6d }, + 'luminancesmoothing' => { 478 => 'LuminanceSmoothing', 480 => 'LuminanceSmoothing' }, + 'lvshootingareadisplay' => { 84 => [0x40b,0x40c] }, + 'lyrics' => { 372 => "\xa9lyr", 380 => "\xa9lyr", 504 => 'lyrics' }, + 'lyricsuri' => { 380 => 'lrcu' }, + 'm16cversion' => { 315 => 0x333 }, + 'macatom' => { 479 => 'macAtom' }, + 'macatomapplicationcode' => { 479 => [\'macAtom','macAtomApplicationCode'] }, + 'macatominvocationappleevent' => { 479 => [\'macAtom','macAtomInvocationAppleEvent'] }, + 'macatomposixprojectpath' => { 479 => [\'macAtom','macAtomPosixProjectPath'] }, + 'machineobservation' => { 118 => 'MachineObservation' }, + 'machineobservationday' => { 118 => [\'MachineObservation','MachineObservationDay'] }, + 'machineobservationearliestdate' => { 118 => [\'MachineObservation','MachineObservationEarliestDate'] }, + 'machineobservationenddayofyear' => { 118 => [\'MachineObservation','MachineObservationEndDayOfYear'] }, + 'machineobservationeventdate' => { 118 => [\'MachineObservation','MachineObservationEventDate'] }, + 'machineobservationeventid' => { 118 => [\'MachineObservation','MachineObservationEventID'] }, + 'machineobservationeventremarks' => { 118 => [\'MachineObservation','MachineObservationEventRemarks'] }, + 'machineobservationeventtime' => { 118 => [\'MachineObservation','MachineObservationEventTime'] }, + 'machineobservationfieldnotes' => { 118 => [\'MachineObservation','MachineObservationFieldNotes'] }, + 'machineobservationfieldnumber' => { 118 => [\'MachineObservation','MachineObservationFieldNumber'] }, + 'machineobservationhabitat' => { 118 => [\'MachineObservation','MachineObservationHabitat'] }, + 'machineobservationlatestdate' => { 118 => [\'MachineObservation','MachineObservationLatestDate'] }, + 'machineobservationmonth' => { 118 => [\'MachineObservation','MachineObservationMonth'] }, + 'machineobservationparenteventid' => { 118 => [\'MachineObservation','MachineObservationParentEventID'] }, + 'machineobservationsamplesizeunit' => { 118 => [\'MachineObservation','MachineObservationSampleSizeUnit'] }, + 'machineobservationsamplesizevalue' => { 118 => [\'MachineObservation','MachineObservationSampleSizeValue'] }, + 'machineobservationsamplingeffort' => { 118 => [\'MachineObservation','MachineObservationSamplingEffort'] }, + 'machineobservationsamplingprotocol' => { 118 => [\'MachineObservation','MachineObservationSamplingProtocol'] }, + 'machineobservationstartdayofyear' => { 118 => [\'MachineObservation','MachineObservationStartDayOfYear'] }, + 'machineobservationverbatimeventdate' => { 118 => [\'MachineObservation','MachineObservationVerbatimEventDate'] }, + 'machineobservationyear' => { 118 => [\'MachineObservation','MachineObservationYear'] }, + 'macro' => { 127 => 0x1020, 129 => 0x202, 151 => 0x2b, 302 => 0x202, 386 => 0x21, 396 => 0x202, 420 => 0xb040 }, + 'macroled' => { 300 => 0x120a }, + 'macromagnification' => { 7 => 0x1b, 11 => 0x1b, 14 => 0x1b, 15 => 0x1b, 19 => 0x1b, 20 => 0x1b, 57 => 0x10 }, + 'macromode' => { 34 => 0x1, 181 => 0xb, 297 => 0x300, 320 => 0x1c, 387 => 0x1009 }, + 'magentahsl' => { 103 => 0x20917 }, + 'magicfilter' => { 297 => 0x52c }, + 'magnifiedview' => { 86 => 0x11, 88 => 0x9 }, + 'mainboardversion' => { 138 => 0x438 }, + 'maindialexposurecomp' => { 290 => '0.6' }, + 'mainingredient' => { 496 => 'mainIngredient' }, + 'majorversion' => { 469 => 'MajorVersion' }, + 'make' => { 98 => 0x0, 115 => 0x1, 119 => 0x10f, 156 => 'Make', 310 => 'Make', 325 => 0x10f, 374 => 'make', 380 => ['@mak',"\xa9mak"], 493 => 'make', 500 => 'Make' }, + 'makernote' => { 484 => 'MakerNote' }, + 'makernoteapple' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotecanon' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotecasio' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotecasio2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotedji' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotedjiinfo' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteflir' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotefujifilm' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotege' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotege2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotehasselblad' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotehp' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotehp2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotehp4' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotehp6' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteisl' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotejvc' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotejvctext' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak10' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak11' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak12' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak1a' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak1b' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak3' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak4' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak5' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak6a' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak6b' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak7' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak8a' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak8b' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak8c' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodak9' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekodakunknown' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotekyocera' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteleica' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteleica10' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteleica2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteleica3' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteleica4' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteleica5' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteleica6' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteleica7' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteleica8' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteleica9' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteminolta' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteminolta2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteminolta3' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotemotorola' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotenikon' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotenikon2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotenikon3' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotenintendo' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteoffset' => { 396 => 0xff }, + 'makernoteolympus' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteolympus2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteolympus3' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotepanasonic' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotepanasonic2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotepanasonic3' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotepentax' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotepentax2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotepentax3' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotepentax4' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotepentax5' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotepentax6' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotepentaxunknown' => { 380 => 'PXMN' }, + 'makernotephaseone' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotereconyx' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotereconyx2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotereconyx3' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotericoh' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotericoh2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotericohpentax' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotericohtext' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesafety' => { 119 => 0xc635 }, + 'makernotesamsung1a' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesamsung1b' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesamsung2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesanyo' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesanyoc4' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesanyopatch' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesigma' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesony' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesony2' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesony3' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesony4' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesony5' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesonyericsson' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotesonysrf' => { 117 => 'MakN', 119 => 0x927c }, + 'makernotetype' => { 387 => 0x1 }, + 'makernoteunknown' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteunknownbinary' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteunknowntext' => { 117 => 'MakN', 119 => 0x927c }, + 'makernoteversion' => { 186 => 0x0, 226 => 0x1, 302 => 0x0, 320 => 0x8000, 391 => 0x0, 394 => 0x1, 397 => [0x1d,0x1f], 410 => 0x2000 }, + 'makerurl' => { 380 => "\xa9mal" }, + 'managedfrom' => { 505 => 'ManagedFrom' }, + 'managedfromalternatepaths' => { 505 => [\'ManagedFrom','ManagedFromAlternatePaths'] }, + 'managedfromdocumentid' => { 505 => [\'ManagedFrom','ManagedFromDocumentID'] }, + 'managedfromfilepath' => { 505 => [\'ManagedFrom','ManagedFromFilePath'] }, + 'managedfromfrompart' => { 505 => [\'ManagedFrom','ManagedFromFromPart'] }, + 'managedfrominstanceid' => { 505 => [\'ManagedFrom','ManagedFromInstanceID'] }, + 'managedfromlastmodifydate' => { 505 => [\'ManagedFrom','ManagedFromLastModifyDate'] }, + 'managedfromlasturl' => { 505 => [\'ManagedFrom','ManagedFromLastURL'] }, + 'managedfromlinkcategory' => { 505 => [\'ManagedFrom','ManagedFromLinkCategory'] }, + 'managedfromlinkform' => { 505 => [\'ManagedFrom','ManagedFromLinkForm'] }, + 'managedfrommanager' => { 505 => [\'ManagedFrom','ManagedFromManager'] }, + 'managedfrommanagervariant' => { 505 => [\'ManagedFrom','ManagedFromManagerVariant'] }, + 'managedfrommanageto' => { 505 => [\'ManagedFrom','ManagedFromManageTo'] }, + 'managedfrommanageui' => { 505 => [\'ManagedFrom','ManagedFromManageUI'] }, + 'managedfrommaskmarkers' => { 505 => [\'ManagedFrom','ManagedFromMaskMarkers'] }, + 'managedfromoriginaldocumentid' => { 505 => [\'ManagedFrom','ManagedFromOriginalDocumentID'] }, + 'managedfrompartmapping' => { 505 => [\'ManagedFrom','ManagedFromPartMapping'] }, + 'managedfromplacedresolutionunit' => { 505 => [\'ManagedFrom','ManagedFromPlacedResolutionUnit'] }, + 'managedfromplacedxresolution' => { 505 => [\'ManagedFrom','ManagedFromPlacedXResolution'] }, + 'managedfromplacedyresolution' => { 505 => [\'ManagedFrom','ManagedFromPlacedYResolution'] }, + 'managedfromrenditionclass' => { 505 => [\'ManagedFrom','ManagedFromRenditionClass'] }, + 'managedfromrenditionparams' => { 505 => [\'ManagedFrom','ManagedFromRenditionParams'] }, + 'managedfromtopart' => { 505 => [\'ManagedFrom','ManagedFromToPart'] }, + 'managedfromversionid' => { 505 => [\'ManagedFrom','ManagedFromVersionID'] }, + 'manager' => { 505 => 'Manager' }, + 'managervariant' => { 505 => 'ManagerVariant' }, + 'manageto' => { 505 => 'ManageTo' }, + 'manageui' => { 505 => 'ManageUI' }, + 'manifest' => { 505 => 'Manifest' }, + 'manifestlinkform' => { 505 => [\'Manifest','ManifestLinkForm'] }, + 'manifestplacedresolutionunit' => { 505 => [\'Manifest','ManifestPlacedResolutionUnit'] }, + 'manifestplacedxresolution' => { 505 => [\'Manifest','ManifestPlacedXResolution'] }, + 'manifestplacedyresolution' => { 505 => [\'Manifest','ManifestPlacedYResolution'] }, + 'manifestreference' => { 505 => [\'Manifest','ManifestReference'] }, + 'manifestreferencealternatepaths' => { 505 => [\'Manifest','ManifestReferenceAlternatePaths'] }, + 'manifestreferencedocumentid' => { 505 => [\'Manifest','ManifestReferenceDocumentID'] }, + 'manifestreferencefilepath' => { 505 => [\'Manifest','ManifestReferenceFilePath'] }, + 'manifestreferencefrompart' => { 505 => [\'Manifest','ManifestReferenceFromPart'] }, + 'manifestreferenceinstanceid' => { 505 => [\'Manifest','ManifestReferenceInstanceID'] }, + 'manifestreferencelastmodifydate' => { 505 => [\'Manifest','ManifestReferenceLastModifyDate'] }, + 'manifestreferencelasturl' => { 505 => [\'Manifest','ManifestReferenceLastURL'] }, + 'manifestreferencelinkcategory' => { 505 => [\'Manifest','ManifestReferenceLinkCategory'] }, + 'manifestreferencelinkform' => { 505 => [\'Manifest','ManifestReferenceLinkForm'] }, + 'manifestreferencemanager' => { 505 => [\'Manifest','ManifestReferenceManager'] }, + 'manifestreferencemanagervariant' => { 505 => [\'Manifest','ManifestReferenceManagerVariant'] }, + 'manifestreferencemanageto' => { 505 => [\'Manifest','ManifestReferenceManageTo'] }, + 'manifestreferencemanageui' => { 505 => [\'Manifest','ManifestReferenceManageUI'] }, + 'manifestreferencemaskmarkers' => { 505 => [\'Manifest','ManifestReferenceMaskMarkers'] }, + 'manifestreferenceoriginaldocumentid' => { 505 => [\'Manifest','ManifestReferenceOriginalDocumentID'] }, + 'manifestreferencepartmapping' => { 505 => [\'Manifest','ManifestReferencePartMapping'] }, + 'manifestreferenceplacedresolutionunit' => { 505 => [\'Manifest','ManifestReferencePlacedResolutionUnit'] }, + 'manifestreferenceplacedxresolution' => { 505 => [\'Manifest','ManifestReferencePlacedXResolution'] }, + 'manifestreferenceplacedyresolution' => { 505 => [\'Manifest','ManifestReferencePlacedYResolution'] }, + 'manifestreferencerenditionclass' => { 505 => [\'Manifest','ManifestReferenceRenditionClass'] }, + 'manifestreferencerenditionparams' => { 505 => [\'Manifest','ManifestReferenceRenditionParams'] }, + 'manifestreferencetopart' => { 505 => [\'Manifest','ManifestReferenceToPart'] }, + 'manifestreferenceversionid' => { 505 => [\'Manifest','ManifestReferenceVersionID'] }, + 'manometerpressure' => { 297 => 0x900, 320 => 0x86 }, + 'manometerreading' => { 297 => 0x901 }, + 'manualafpointselectpattern' => { 84 => 0x513 }, 'manualafpointselpattern' => { 2 => 0xf }, - 'manualflash' => { 277 => 0x1209 }, - 'manualflashoutput' => { 33 => 0x29, 259 => '8.2', 262 => '22.2', 263 => '23.1', 264 => '23.2', 266 => '16.2', 267 => '23.2', 268 => '8.2', 269 => '23.2', 272 => '24.2', 358 => 0x100c }, - 'manualflashstrength' => { 274 => 0x406 }, - 'manualfocusdistance' => { 211 => 0x85, 279 => 0x100c, 367 => 0x223 }, - 'manualtv' => { 77 => 0x5, 78 => 0x705 }, - 'manufacturedate' => { 181 => 0x6705, 312 => 0x1 }, - 'manufacturedate1' => { 360 => 0x4 }, - 'manufacturedate2' => { 360 => 0x5 }, - 'manufacturer' => { 426 => 'Manufacturer', 455 => 'manufacturer' }, - 'mariahchromablursize' => { 131 => 0xf0d }, - 'mariahmaphithreshold' => { 131 => 0xf0c }, - 'mariahmaplothreshold' => { 131 => 0xf0b }, - 'mariahsigmathreshold' => { 131 => 0xf0e }, - 'mariahtexturethreshold' => { 131 => 0xf0a }, - 'marked' => { 453 => 'Marked', 470 => 'Marked' }, - 'markers' => { 466 => 'markers' }, - 'markerscomment' => { 466 => [\'markers','markersComment'] }, - 'markerscuepointparams' => { 466 => [\'markers','markersCuePointParams'] }, - 'markerscuepointparamskey' => { 466 => [\'markers','markersCuePointParamsKey'] }, - 'markerscuepointparamsvalue' => { 466 => [\'markers','markersCuePointParamsValue'] }, - 'markerscuepointtype' => { 466 => [\'markers','markersCuePointType'] }, - 'markersduration' => { 466 => [\'markers','markersDuration'] }, - 'markerslocation' => { 466 => [\'markers','markersLocation'] }, - 'markersname' => { 466 => [\'markers','markersName'] }, - 'markersprobability' => { 466 => [\'markers','markersProbability'] }, - 'markersspeaker' => { 466 => [\'markers','markersSpeaker'] }, - 'markersstarttime' => { 466 => [\'markers','markersStartTime'] }, - 'markerstarget' => { 466 => [\'markers','markersTarget'] }, - 'markerstype' => { 466 => [\'markers','markersType'] }, - 'maskedareas' => { 113 => 0xc68e }, - 'masterdocumentid' => { 125 => 0xb9 }, - 'mastergain' => { 218 => 0x50 }, - 'materialsample' => { 112 => 'MaterialSample' }, - 'materialsampleid' => { 112 => [\'MaterialSample','MaterialSampleMaterialSampleID'] }, - 'matrixmetering' => { 258 => '50.1', 260 => '48.1', 261 => '48.1', 270 => '48.1', 271 => '48.1' }, - 'matrixselectk' => { 131 => 0x91b }, - 'matrixselectthreshold' => { 131 => 0x91a }, - 'matrixselectthreshold1' => { 131 => 0x91e }, - 'matrixselectthreshold2' => { 131 => 0x91f }, - 'matrixstructure' => { 352 => 0xa }, - 'maxaperture' => { 33 => 0x1a, 131 => 0x3f9, 137 => 0x6103, 154 => 'MaxAperture', 171 => 0x17, 177 => 0x49c5, 275 => 0x20a, 323 => '14.1' }, - 'maxapertureatmaxfocal' => { 121 => 0x1407, 154 => 'MaxApertureAtMaxFocal', 206 => 0xb, 207 => 0x10, 208 => 0x11, 275 => 0x206 }, - 'maxapertureatminfocal' => { 121 => 0x1406, 206 => 0xa, 207 => 0xf, 208 => 0x10, 275 => 0x205 }, - 'maxaperturevalue' => { 113 => 0x9205, 341 => 0x414, 446 => 'MaxApertureValue' }, - 'maxavailheight' => { 452 => 'MaxAvailHeight' }, - 'maxavailwidth' => { 452 => 'MaxAvailWidth' }, - 'maxcontinuousrelease' => { 257 => 0xb, 258 => 0xc, 260 => '12.1', 261 => '12.1', 266 => 0xc, 267 => 0xb, 270 => '12.1', 271 => '12.1' }, - 'maxfaces' => { 278 => 0x1202 }, - 'maxfocallength' => { 6 => 0xe6, 7 => 0x10, 8 => 0x1ab, 9 => 0x13, 10 => 0x115, 11 => 0x13, 12 => 0x153, 13 => 0xda, 15 => 0xfa, 16 => 0xee, 17 => 0x103, 18 => 0x95, 19 => 0xea, 20 => 0x157, 21 => 0xee, 22 => 0xec, 23 => 0x12b, 24 => 0x165, 25 => 0x16a, 26 => 0x188, 27 => 0x116, 28 => 0x18d, 33 => 0x17, 121 => 0x1405, 154 => 'MaxFocalLength', 206 => 0x9, 207 => 0xe, 208 => 0xf, 275 => 0x208, 400 => 0x127c, 401 => 0x1138, 402 => 0x330, 403 => 0x330, 404 => 0x30e }, - 'maximumdensityrange' => { 127 => 0x8c }, - 'maxpagesize' => { 471 => 'MaxPageSize' }, - 'maxpagesizeh' => { 471 => [\'MaxPageSize','MaxPageSizeH'] }, - 'maxpagesizeunit' => { 471 => [\'MaxPageSize','MaxPageSizeUnit'] }, - 'maxpagesizew' => { 471 => [\'MaxPageSize','MaxPageSizeW'] }, - 'maxpixelvaluethreshold' => { 131 => 0xc7d }, - 'maxsamplevalue' => { 113 => 0x119 }, - 'maxstorage' => { 461 => 'maxstorage' }, - 'mb-d10batteries' => { 257 => '12.6' }, - 'mb-d10batterytype' => { 266 => '13.3' }, - 'mb-d11batterytype' => { 267 => '2.3' }, - 'mb-d12batterytype' => { 270 => '3.2' }, - 'mb-d80batteries' => { 268 => '6.5' }, - 'mb-d80batterytype' => { 272 => '3.2' }, - 'mcuversion' => { 206 => 0xc, 207 => 0x11, 208 => 0x12 }, - 'md5digest' => { 155 => 'zmd5' }, - 'mditemfindercomment' => { 164 => 'MDItemFinderComment' }, - 'mditemfscreationdate' => { 164 => 'MDItemFSCreationDate' }, - 'mditemfslabel' => { 164 => 'MDItemFSLabel' }, - 'mditemusertags' => { 164 => 'MDItemUserTags' }, - 'meal' => { 458 => 'meal' }, - 'measuredev' => { 27 => 0x9, 72 => 0x3, 91 => 0x1814, 147 => 'MeasuredEV' }, - 'measuredev2' => { 12 => 0x8, 27 => 0x8, 72 => 0x17 }, - 'measuredev3' => { 12 => 0x9 }, - 'measuredlv' => { 177 => 0x690, 292 => 0x312, 295 => 0x312, 296 => 0x312, 299 => 0x3407 }, - 'measuredrggb' => { 61 => 0x1 }, - 'measuredrggbdata' => { 41 => 0x287 }, - 'measurementaccuracy' => { 112 => [\'MeasurementOrFact','MeasurementOrFactMeasurementAccuracy'] }, - 'measurementdeterminedby' => { 112 => [\'MeasurementOrFact','MeasurementOrFactMeasurementDeterminedBy'] }, - 'measurementdetermineddate' => { 112 => [\'MeasurementOrFact','MeasurementOrFactMeasurementDeterminedDate'] }, - 'measurementid' => { 112 => [\'MeasurementOrFact','MeasurementOrFactMeasurementID'] }, - 'measurementmethod' => { 112 => [\'MeasurementOrFact','MeasurementOrFactMeasurementMethod'] }, - 'measurementorfact' => { 112 => 'MeasurementOrFact' }, - 'measurementremarks' => { 112 => [\'MeasurementOrFact','MeasurementOrFactMeasurementRemarks'] }, - 'measurementtype' => { 112 => [\'MeasurementOrFact','MeasurementOrFactMeasurementType'] }, - 'measurementunit' => { 112 => [\'MeasurementOrFact','MeasurementOrFactMeasurementUnit'] }, - 'measurementvalue' => { 112 => [\'MeasurementOrFact','MeasurementOrFactMeasurementValue'] }, - 'measuretype' => { 426 => 'MeasureType' }, - 'mechanicalshuttercount' => { 211 => 0x37 }, - 'mediaconstraints' => { 284 => 'MediaConstraints' }, - 'mediacreatedate' => { 349 => 0x1 }, - 'mediaeventiddate' => { 431 => 'MediaEventIdDate' }, - 'mediamodifydate' => { 349 => 0x2 }, - 'mediasummarycode' => { 284 => 'MediaSummaryCode' }, - 'memoaudioquality' => { 78 => 0x812 }, - 'memorycardconfiguration' => { 382 => 0x16 }, - 'memorycardnumber' => { 197 => 0x2 }, - 'menubuttondisplayposition' => { 76 => 0xb, 79 => 0xa, 80 => 0xb, 83 => 0xb }, - 'menubuttonreturn' => { 84 => 0xb }, - 'menumonitorofftime' => { 257 => '26.1', 258 => '22.1', 260 => '22.1', 261 => '22.1', 265 => '21.1', 266 => '8.2', 267 => '21.1', 270 => '22.1', 271 => '22.1', 272 => '22.1' }, - 'metadatadate' => { 464 => 'MetadataDate' }, - 'metadatamoddate' => { 466 => 'metadataModDate' }, - 'metaversion' => { 395 => 0x34 }, - 'meterinfo1row1' => { 389 => 0x0, 390 => 0x0 }, - 'meterinfo1row2' => { 389 => 0x6c, 390 => 0x5a }, - 'meterinfo1row3' => { 389 => 0xd8, 390 => 0xb4 }, - 'meterinfo1row4' => { 389 => 0x144, 390 => 0x10e }, - 'meterinfo1row5' => { 389 => 0x1b0, 390 => 0x168 }, - 'meterinfo1row6' => { 389 => 0x21c, 390 => 0x1c2 }, - 'meterinfo1row7' => { 389 => 0x288, 390 => 0x21c }, - 'meterinfo2row1' => { 389 => 0x2f4, 390 => 0x276 }, - 'meterinfo2row2' => { 389 => 0x378, 390 => 0x2e4 }, - 'meterinfo2row3' => { 389 => 0x3fc, 390 => 0x352 }, - 'meterinfo2row4' => { 389 => 0x480, 390 => 0x3c0 }, - 'meterinfo2row5' => { 389 => 0x504, 390 => 0x42e }, - 'meterinfo2row6' => { 389 => 0x588, 390 => 0x49c }, - 'meterinfo2row7' => { 389 => 0x60c, 390 => 0x50a }, - 'meterinfo2row8' => { 389 => 0x690, 390 => 0x578 }, - 'meterinfo2row9' => { 389 => 0x714, 390 => 0x5e6 }, - 'metering' => { 259 => '6.1' }, - 'meteringmode' => { 33 => 0x11, 113 => 0x9207, 133 => 0x1c, 171 => 0x7, 172 => 0x25, 174 => 0x12, 274 => 0x202, 332 => 0x17, 368 => 0x9, 376 => 0x15, 377 => 0x13, 378 => 0x7, 393 => 0x3, 396 => 0x1174, 397 => 0x1178, 398 => 0x1154, 399 => 0x11d0, 400 => 0x11ac, 401 => 0x1064, 402 => 0x25c, 403 => 0x25c, 404 => 0x24b, 446 => 'MeteringMode' }, - 'meteringmode2' => { 313 => '2.1', 388 => 0x202c }, - 'meteringmode3' => { 313 => '16.1' }, - 'meteringoffscaleindicator' => { 174 => 0x53 }, - 'meteringtime' => { 257 => '22.2', 259 => '3.2', 262 => '17.1', 263 => '18.1', 266 => '7.3', 267 => '18.1', 268 => '3.2', 272 => '19.1' }, - 'micro1version' => { 354 => 0x1f }, - 'micro2version' => { 354 => 0x2d }, - 'mieversion' => { 155 => '0Vers' }, - 'mime' => { 426 => 'Mime' }, - 'minaperture' => { 33 => 0x1b, 131 => 0x3f8, 154 => 'MinAperture', 323 => '0.2' }, - 'minaperturevalue' => { 341 => 0x415 }, - 'minfocallength' => { 6 => 0xe4, 7 => 0xe, 8 => 0x1a9, 9 => 0x11, 10 => 0x113, 11 => 0x11, 12 => 0x151, 13 => 0xd8, 15 => 0xf8, 16 => 0xec, 17 => 0x101, 18 => 0x93, 19 => 0xe8, 20 => 0x155, 21 => 0xec, 22 => 0xea, 23 => 0x129, 24 => 0x163, 25 => 0x168, 26 => 0x186, 27 => 0x114, 28 => 0x18b, 33 => 0x18, 121 => 0x1404, 154 => 'MinFocalLength', 206 => 0x8, 207 => 0xd, 208 => 0xe, 275 => 0x207, 400 => 0x127a, 401 => 0x1136, 402 => 0x32e, 403 => 0x32e, 404 => 0x30c }, - 'minfocusdistance' => { 323 => 0x3 }, - 'minintegrationrows' => { 131 => 0x1874 }, - 'minoltadate' => { 171 => 0x15 }, - 'minoltaimagesize' => { 171 => 0x4, 172 => 0xc, 173 => 0x2, 176 => 0x103 }, - 'minoltamodelid' => { 171 => 0x25 }, - 'minoltaquality' => { 171 => 0x5, 172 => 0xd, 173 => 0x3, 176 => [0x102,0x103] }, - 'minoltatime' => { 171 => 0x16 }, - 'minormodelagedisclosure' => { 284 => 'MinorModelAgeDisclosure' }, - 'minorversion' => { 432 => 'MinorVersion' }, - 'minsamplevalue' => { 113 => 0x118 }, - 'mirrorlockup' => { 76 => 0xc, 77 => 0xc, 78 => 0x60f, 79 => 0xb, 80 => 0xc, 81 => 0x6, 82 => 0x6, 83 => 0xc, 84 => 0x3 }, - 'mobilecountrycode' => { 440 => 'mcc' }, - 'mobilenetworkcode' => { 440 => 'mnc' }, - 'moddate' => { 287 => 'modify-date', 453 => 'ModDate' }, - 'modedialposition' => { 382 => 0x14 }, - 'model' => { 92 => 0x6, 113 => 0x110, 147 => 'Model', 287 => 'Model', 302 => 0x110, 332 => 0x23f, 368 => 0x84, 426 => 'Model', 455 => 'model', 462 => 'Model' }, - 'modelage' => { 452 => 'ModelAge' }, - 'modelid' => { 273 => 0x0 }, - 'modelingflash' => { 257 => '21.4', 258 => '31.1', 260 => '31.1', 261 => '31.1', 266 => '26.4', 267 => '30.2', 268 => '7.4', 269 => '30.1', 270 => '31.1', 271 => '31.1', 272 => '31.3' }, - 'modelreleaseid' => { 284 => 'ModelReleaseID' }, - 'modelreleasestatus' => { 284 => 'ModelReleaseStatus' }, - 'modelreleaseyear' => { 408 => 0x52, 409 => 0x46, 410 => 0x53 }, - 'modelyear' => { 455 => 'modelYear' }, - 'modificationdate' => { 456 => 'modificationDate' }, - 'modifiedcolortemp' => { 62 => 0x9 }, - 'modifieddigitalgain' => { 62 => 0xb }, - 'modifiedparamflag' => { 55 => 0x1 }, - 'modifiedpicturestyle' => { 62 => 0xa }, - 'modifiedsaturation' => { 274 => 0x504 }, - 'modifiedsensorbluelevel' => { 62 => 0x5 }, - 'modifiedsensorredlevel' => { 62 => 0x4 }, - 'modifiedsharpness' => { 62 => 0x2 }, - 'modifiedsharpnessfreq' => { 62 => 0x3 }, - 'modifiedtonecurve' => { 62 => 0x1 }, - 'modifiedwhitebalance' => { 62 => 0x8 }, - 'modifiedwhitebalanceblue' => { 62 => 0x7 }, - 'modifiedwhitebalancered' => { 62 => 0x6 }, - 'modifydate' => { 113 => 0x132, 148 => 'ModifyDate', 283 => 'ModDate', 285 => 'tIME', 348 => 'ModDate', 350 => 0x2, 464 => 'ModifyDate' }, - 'moirefilter' => { 113 => 0xfe58, 442 => 'MoireFilter' }, - 'monitordisplayoff' => { 174 => 0x4c }, - 'monitormatrix' => { 131 => 0x8fc }, - 'monitorofftime' => { 257 => '18.2', 259 => '3.1', 268 => '3.1' }, - 'monochromecolor' => { 274 => 0x53b }, - 'monochromecontrast' => { 103 => 0x3c }, - 'monochromefiltereffect' => { 97 => 0x20307, 103 => 0x3a, 332 => 0x73 }, - 'monochromelinear' => { 103 => 0x3d }, - 'monochromeoutputhighlightpoint' => { 103 => 0x41 }, - 'monochromeoutputshadowpoint' => { 103 => 0x42 }, - 'monochromeprofilesettings' => { 274 => 0x537 }, - 'monochromerawhighlight' => { 103 => 0x7a }, - 'monochromerawhighlightpoint' => { 103 => 0x3f }, - 'monochromerawshadow' => { 103 => 0x83 }, - 'monochromerawshadowpoint' => { 103 => 0x40 }, - 'monochromesharpness' => { 103 => 0x3e }, - 'monochrometoning' => { 332 => 0x74 }, - 'monochrometoningeffect' => { 97 => 0x20306, 103 => 0x3b }, - 'monochromeunsharpmaskfineness' => { 103 => 0xb2 }, - 'monochromeunsharpmaskstrength' => { 103 => 0xb0 }, - 'monochromeunsharpmaskthreshold' => { 103 => 0xb4 }, - 'monochromevignetting' => { 274 => 0x53a }, - 'monthdaycreated' => { 133 => 0x12, 142 => 0xe }, - 'moonphase' => { 353 => 0x12, 354 => 0x43 }, - 'morepermissions' => { 439 => 'morePermissions' }, - 'motionsensitivity' => { 353 => 0x29 }, - 'movieaelockbuttonassignment' => { 270 => '40.1' }, - 'moviefunc1button' => { 260 => '41.1', 261 => '41.1', 271 => '41.1' }, - 'moviefunctionbutton' => { 258 => '41.1', 270 => '41.1' }, - 'moviefunctionbuttonplusdials' => { 258 => '52.1' }, - 'moviepreviewbutton' => { 258 => '41.2', 260 => '41.2', 261 => '41.2', 270 => '41.2', 271 => '41.2' }, - 'moviepreviewbuttonplusdials' => { 258 => '52.2' }, - 'movieshutterbutton' => { 258 => '38.3', 260 => '38.3', 261 => '38.3', 270 => '38.3', 271 => '38.3' }, - 'moviesubselectorassignment' => { 258 => '48.2' }, - 'moviesubselectorassignmentplusdials' => { 258 => '53.1' }, - 'multiburstimageheight' => { 388 => 0x1002 }, - 'multiburstimagewidth' => { 388 => 0x1001 }, - 'multiburstmode' => { 388 => 0x1000 }, - 'multicontrollerwhilemetering' => { 78 => 0x517 }, - 'multiexposure' => { 64 => 0x1, 297 => 0xb4 }, - 'multiexposureautogain' => { 212 => 0x3 }, - 'multiexposurecontrol' => { 64 => 0x2 }, - 'multiexposuremode' => { 212 => 0x1 }, - 'multiexposureshots' => { 64 => 0x3, 212 => 0x2 }, - 'multiframenoisereduction' => { 378 => 0x35, 388 => 0x200b, 393 => 0x15 }, - 'multiframenreffect' => { 388 => 0x2023 }, - 'multifunctionlock' => { 78 => 0x70f }, - 'multipleexposuremode' => { 278 => 0x101c }, - 'multipleexposureset' => { 313 => '10.1' }, - 'multisample' => { 218 => 0x40 }, - 'multiselector' => { 257 => '9.4', 258 => '10.3', 260 => '10.3', 261 => '10.3', 266 => '27.4', 270 => '10.3', 271 => '10.3' }, - 'multiselectorliveview' => { 257 => '4.3', 260 => '37.1', 261 => '37.1', 270 => '37.1', 271 => '37.1' }, - 'multiselectorliveviewmode' => { 228 => 0x18c2 }, - 'multiselectorplaybackmode' => { 257 => ['13.5','9.2'], 258 => '10.2', 261 => '10.2', 266 => '27.2', 270 => '10.2', 271 => '10.2' }, - 'multiselectorshootmode' => { 257 => '9.1', 258 => '10.1', 260 => '10.1', 261 => '10.1', 266 => '27.1', 270 => '10.1', 271 => '10.1' }, - 'multishot' => { 302 => 0x121 }, - 'mycolormode' => { 65 => 0x2 }, - 'nationalcatalognumber' => { 456 => 'nationalCatalogNumber' }, - 'nativedigest' => { 446 => 'NativeDigest', 462 => 'NativeDigest' }, - 'ndfilter' => { 72 => 0x1c, 274 => 0x204, 358 => 0x1019 }, - 'near' => { 426 => 'Near' }, - 'nefbitdepth' => { 211 => 0xe22 }, - 'nefcompression' => { 211 => 0x93 }, - 'neflinearizationtable' => { 211 => 0x96 }, - 'negativecachelargepreviewsize' => { 442 => 'NegativeCacheLargePreviewSize' }, - 'negativecachemaximumsize' => { 442 => 'NegativeCacheMaximumSize' }, - 'negativecachepath' => { 442 => 'NegativeCachePath' }, - 'neutraldensityfilter' => { 332 => 0x88 }, - 'neutraloutputhighlightpoint' => { 103 => 0x2f }, - 'neutraloutputshadowpoint' => { 103 => 0x30 }, - 'neutralrawcolortone' => { 103 => 0x28 }, - 'neutralrawcontrast' => { 103 => 0x2a }, - 'neutralrawhighlight' => { 103 => 0x78 }, - 'neutralrawhighlightpoint' => { 103 => 0x2d }, - 'neutralrawlinear' => { 103 => 0x2b }, - 'neutralrawsaturation' => { 103 => 0x29 }, - 'neutralrawshadow' => { 103 => 0x81 }, - 'neutralrawshadowpoint' => { 103 => 0x2e }, - 'neutralrawsharpness' => { 103 => 0x2c }, - 'neutralunsharpmaskfineness' => { 103 => 0xa6 }, - 'neutralunsharpmaskthreshold' => { 103 => 0xa8 }, - 'neutraunsharpmaskstrength' => { 103 => 0xa4 }, - 'newrawimagedigest' => { 113 => 0xc7a7 }, - 'newsphotoversion' => { 127 => 0x0 }, - 'nickname' => { 464 => 'Nickname' }, - 'nikoncapturedata' => { 211 => 0xe01 }, - 'nikoncaptureeditversions' => { 211 => 0xe13 }, - 'nikoncaptureoutput' => { 211 => 0xe1e }, - 'nikoncaptureversion' => { 211 => 0xe09 }, - 'nikoniccprofile' => { 211 => 0xe1d }, - 'nikonimagesize' => { 225 => '723.1', 226 => '732.1', 235 => 0x2c4 }, - 'noisefilter' => { 274 => 0x527 }, - 'noiseprofile' => { 113 => 0xc761 }, - 'noisereduction' => { 121 => [0x100b,0x100e], 172 => 0xb0, 173 => 0x60, 174 => 0x3f, 211 => 0x95, 250 => 0x753dcbc0, 251 => 0x17, 274 => 0x50a, 279 => 0x103a, 297 => 0x2d, 332 => 0x49, 358 => 0x100f, 360 => 0x2a }, - 'noisereduction2' => { 278 => 0x1010 }, - 'noisereductionapplied' => { 113 => 0xc6f7 }, - 'noisereductionintensity' => { 251 => 0x9 }, - 'noisereductionmethod' => { 251 => 0x11 }, - 'noisereductionmode' => { 421 => 0x801e }, - 'noisereductionparametersatcapture' => { 131 => 0xe73 }, - 'noisereductionparameterscamera' => { 131 => 0xe72 }, - 'noisereductionparametershost3mp' => { 131 => 0xe71 }, - 'noisereductionparametershost6mp' => { 131 => 0xe70 }, - 'noisereductionparametershostrgb' => { 131 => 0xe6f }, - 'noisereductionparameterskhufu3mp' => { 131 => 0xe65 }, - 'noisereductionparameterskhufu6mp' => { 131 => 0xe64 }, - 'noisereductionparameterskhufurgb' => { 131 => 0xe63 }, - 'noisereductionparams' => { 302 => 0x1b }, - 'noisereductionsharpness' => { 251 => 0xd }, - 'noisereductionvalue' => { 421 => 0x8027 }, - 'nomemorycard' => { 257 => '22.1', 258 => '4.2', 259 => '0.3', 262 => '2.4', 263 => '3.2', 264 => '3.2', 266 => '33.7', 267 => '3.2', 268 => '0.3', 270 => '4.2', 272 => '4.5' }, - 'nominalmaxaperture' => { 323 => 0xa }, - 'nominalminaperture' => { 323 => '10.1' }, - 'normallinetime' => { 131 => 0x186a }, - 'normalwhitelevel' => { 42 => [0x2b8,0x2cf,0x2d3], 44 => 0x1e3, 45 => [0x1fc,0x2dc], 46 => [0x230,0x30e], 47 => 0x31c }, - 'notes' => { 422 => 'Notes', 436 => 'notes' }, - 'npages' => { 471 => 'NPages' }, - 'nullrecord' => { 91 => 0x0 }, - 'numafpoints' => { 309 => 0x2 }, - 'number' => { 456 => 'number' }, - 'numberofbeats' => { 466 => 'numberOfBeats' }, - 'numberoffocuspoints' => { 260 => '1.2', 261 => '1.2', 264 => '0.2', 265 => '0.3', 267 => '0.3' }, - 'numfaceelements' => { 121 => 0x4200 }, - 'numfacepositions' => { 289 => 0x0 }, - 'numindexentries' => { 127 => 0x54 }, - 'numwbentries' => { 303 => 0x0, 304 => 0x0 }, - 'object' => { 456 => 'object' }, - 'objectattributereference' => { 125 => 0x4 }, - 'objectcycle' => { 125 => 0x4b, 436 => 'ObjectCycle' }, - 'objectdescription' => { 455 => 'objectDescription' }, - 'objectdistance' => { 106 => 0x6, 107 => 0x2022 }, - 'objectname' => { 125 => 0x5 }, - 'objectpreviewdata' => { 125 => 0xca }, - 'objectpreviewfileformat' => { 125 => 0xc8 }, - 'objectpreviewfileversion' => { 125 => 0xc9 }, - 'objectsubtype' => { 455 => 'objectSubtype' }, - 'objecttype' => { 455 => 'objectType' }, - 'objecttypereference' => { 125 => 0x3 }, - 'occurrence' => { 112 => 'Occurrence' }, - 'occurrenceassociatedmedia' => { 112 => [\'Occurrence','OccurrenceAssociatedMedia'] }, - 'occurrenceassociatedoccurrences' => { 112 => [\'Occurrence','OccurrenceAssociatedOccurrences'] }, - 'occurrenceassociatedreferences' => { 112 => [\'Occurrence','OccurrenceAssociatedReferences'] }, - 'occurrenceassociatedsequences' => { 112 => [\'Occurrence','OccurrenceAssociatedSequences'] }, - 'occurrenceassociatedtaxa' => { 112 => [\'Occurrence','OccurrenceAssociatedTaxa'] }, - 'occurrencebehavior' => { 112 => [\'Occurrence','OccurrenceBehavior'] }, - 'occurrencecatalognumber' => { 112 => [\'Occurrence','OccurrenceCatalogNumber'] }, - 'occurrencedetails' => { 112 => [\'Occurrence','OccurrenceOccurrenceDetails'] }, - 'occurrencedisposition' => { 112 => [\'Occurrence','OccurrenceDisposition'] }, - 'occurrenceestablishmentmeans' => { 112 => [\'Occurrence','OccurrenceEstablishmentMeans'] }, - 'occurrenceid' => { 112 => [\'Occurrence','OccurrenceOccurrenceID'] }, - 'occurrenceindividualcount' => { 112 => [\'Occurrence','OccurrenceIndividualCount'] }, - 'occurrenceindividualid' => { 112 => [\'Occurrence','OccurrenceIndividualID'] }, - 'occurrencelifestage' => { 112 => [\'Occurrence','OccurrenceLifeStage'] }, - 'occurrenceorganismquantity' => { 112 => [\'Occurrence','OccurrenceOrganismQuantity'] }, - 'occurrenceorganismquantitytype' => { 112 => [\'Occurrence','OccurrenceOrganismQuantityType'] }, - 'occurrenceothercatalognumbers' => { 112 => [\'Occurrence','OccurrenceOtherCatalogNumbers'] }, - 'occurrencepreparations' => { 112 => [\'Occurrence','OccurrencePreparations'] }, - 'occurrencepreviousidentifications' => { 112 => [\'Occurrence','OccurrencePreviousIdentifications'] }, - 'occurrencerecordedby' => { 112 => [\'Occurrence','OccurrenceRecordedBy'] }, - 'occurrencerecordnumber' => { 112 => [\'Occurrence','OccurrenceRecordNumber'] }, - 'occurrenceremarks' => { 112 => [\'Occurrence','OccurrenceOccurrenceRemarks'] }, - 'occurrencereproductivecondition' => { 112 => [\'Occurrence','OccurrenceReproductiveCondition'] }, - 'occurrencesex' => { 112 => [\'Occurrence','OccurrenceSex'] }, - 'occurrencestatus' => { 112 => [\'Occurrence','OccurrenceOccurrenceStatus'] }, - 'oecfcolumns' => { 446 => [\'OECF','OECFColumns'] }, - 'oecfnames' => { 446 => [\'OECF','OECFNames'] }, - 'oecfrows' => { 446 => [\'OECF','OECFRows'] }, - 'oecfvalues' => { 446 => [\'OECF','OECFValues'] }, - 'offsaledate' => { 456 => 'offSaleDate' }, - 'offsaledatea-platform' => { 456 => [\'offSaleDate','offSaleDateA-platform'] }, - 'offsaledatedate' => { 456 => [\'offSaleDate','offSaleDateDate'] }, - 'offsetdacvalue' => { 131 => 0x190a }, - 'offsetschema' => { 113 => 0xea1d }, - 'offsettime' => { 113 => 0x9010 }, - 'offsettimedigitized' => { 113 => 0x9012 }, - 'offsettimeoriginal' => { 113 => 0x9011 }, - 'okbutton' => { 267 => '15.1', 272 => '16.1' }, - 'oldsubfiletype' => { 113 => 0xff }, - 'olympusimageheight' => { 279 => 0x102f }, - 'olympusimagewidth' => { 279 => 0x102e }, - 'omenatcapturestrength' => { 131 => 0xa60 }, - 'omenautostrength' => { 131 => 0xa5f }, - 'omenearlystrength' => { 131 => 0xa5e }, - 'omenfocallengthlimit' => { 131 => 0xa62 }, - 'omeninitialipfstrength' => { 131 => 0xa5d }, - 'omensurfaceindex' => { 131 => 0xa64 }, + 'manualflash' => { 300 => 0x1209 }, + 'manualflashoutput' => { 34 => 0x29, 281 => '8.2', 284 => '22.2', 285 => '23.1', 286 => '23.2', 288 => '16.2', 289 => '23.2', 290 => '8.2', 291 => '23.2', 294 => '24.2', 387 => 0x100c }, + 'manualflashstrength' => { 297 => 0x406 }, + 'manualfocusdistance' => { 226 => 0x85, 302 => 0x100c, 396 => 0x223 }, + 'manualfocuspointillumination' => { 295 => 0x17 }, + 'manualfocusringinafmode' => { 295 => 0x1a }, + 'manualtv' => { 83 => 0x5, 84 => 0x705 }, + 'manufacturedate' => { 191 => 0x6705, 335 => 0x1 }, + 'manufacturedate1' => { 389 => 0x4 }, + 'manufacturedate2' => { 389 => 0x5 }, + 'manufacturer' => { 463 => 'Manufacturer', 493 => 'manufacturer' }, + 'mariahchromablursize' => { 138 => 0xf0d }, + 'mariahmaphithreshold' => { 138 => 0xf0c }, + 'mariahmaplothreshold' => { 138 => 0xf0b }, + 'mariahsigmathreshold' => { 138 => 0xf0e }, + 'mariahtexturethreshold' => { 138 => 0xf0a }, + 'marked' => { 491 => 'Marked', 508 => 'Marked' }, + 'markers' => { 504 => 'markers' }, + 'markerscomment' => { 504 => [\'markers','markersComment'] }, + 'markerscuepointparams' => { 504 => [\'markers','markersCuePointParams'] }, + 'markerscuepointparamskey' => { 504 => [\'markers','markersCuePointParamsKey'] }, + 'markerscuepointparamsvalue' => { 504 => [\'markers','markersCuePointParamsValue'] }, + 'markerscuepointtype' => { 504 => [\'markers','markersCuePointType'] }, + 'markersduration' => { 504 => [\'markers','markersDuration'] }, + 'markerslocation' => { 504 => [\'markers','markersLocation'] }, + 'markersname' => { 504 => [\'markers','markersName'] }, + 'markersprobability' => { 504 => [\'markers','markersProbability'] }, + 'markersspeaker' => { 504 => [\'markers','markersSpeaker'] }, + 'markersstarttime' => { 504 => [\'markers','markersStartTime'] }, + 'markerstarget' => { 504 => [\'markers','markersTarget'] }, + 'markerstype' => { 504 => [\'markers','markersType'] }, + 'maskedareas' => { 119 => 0xc68e }, + 'maskgroupbasedcorractive' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionActive'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionActive'] }, + 'maskgroupbasedcorramount' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionAmount'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionAmount'] }, + 'maskgroupbasedcorrblacks2012' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalBlacks2012'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalBlacks2012'] }, + 'maskgroupbasedcorrbrightness' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalBrightness'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalBrightness'] }, + 'maskgroupbasedcorrclarity' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalClarity'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalClarity'] }, + 'maskgroupbasedcorrclarity2012' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalClarity2012'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalClarity2012'] }, + 'maskgroupbasedcorrcontrast' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalContrast'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalContrast'] }, + 'maskgroupbasedcorrcontrast2012' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalContrast2012'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalContrast2012'] }, + 'maskgroupbasedcorrcorrectionname' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionName'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionName'] }, + 'maskgroupbasedcorrcorrectionsyncid' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionSyncID'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionSyncID'] }, + 'maskgroupbasedcorrdefringe' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalDefringe'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalDefringe'] }, + 'maskgroupbasedcorrdehaze' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalDehaze'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalDehaze'] }, + 'maskgroupbasedcorrections' => { 478 => 'MaskGroupBasedCorrections', 480 => 'MaskGroupBasedCorrections' }, + 'maskgroupbasedcorrexposure' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalExposure'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalExposure'] }, + 'maskgroupbasedcorrexposure2012' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalExposure2012'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalExposure2012'] }, + 'maskgroupbasedcorrhighlights2012' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalHighlights2012'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalHighlights2012'] }, + 'maskgroupbasedcorrhue' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalHue'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalHue'] }, + 'maskgroupbasedcorrluminancenoise' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalLuminanceNoise'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalLuminanceNoise'] }, + 'maskgroupbasedcorrmask' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasks'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasks'] }, + 'maskgroupbasedcorrmaskalpha' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksAlpha'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksAlpha'] }, + 'maskgroupbasedcorrmaskangle' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksAngle'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksAngle'] }, + 'maskgroupbasedcorrmaskbottom' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksBottom'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksBottom'] }, + 'maskgroupbasedcorrmaskcentervalue' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCenterValue'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCenterValue'] }, + 'maskgroupbasedcorrmaskcenterweight' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCenterWeight'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCenterWeight'] }, + 'maskgroupbasedcorrmaskdabs' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksDabs'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksDabs'] }, + 'maskgroupbasedcorrmaskfeather' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksFeather'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksFeather'] }, + 'maskgroupbasedcorrmaskflipped' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksFlipped'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksFlipped'] }, + 'maskgroupbasedcorrmaskflow' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksFlow'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksFlow'] }, + 'maskgroupbasedcorrmaskfullx' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksFullX'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksFullX'] }, + 'maskgroupbasedcorrmaskfully' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksFullY'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksFullY'] }, + 'maskgroupbasedcorrmaskinputdigest' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksInputDigest'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksInputDigest'] }, + 'maskgroupbasedcorrmaskleft' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksLeft'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksLeft'] }, + 'maskgroupbasedcorrmaskmaskactive' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskActive'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskActive'] }, + 'maskgroupbasedcorrmaskmaskblendmode' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskBlendMode'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskBlendMode'] }, + 'maskgroupbasedcorrmaskmaskdigest' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskDigest'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskDigest'] }, + 'maskgroupbasedcorrmaskmaskinverted' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskInverted'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskInverted'] }, + 'maskgroupbasedcorrmaskmaskname' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskName'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskName'] }, + 'maskgroupbasedcorrmaskmasks' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasks'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasks'] }, + 'maskgroupbasedcorrmaskmasksalpha' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksAlpha'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksAlpha'] }, + 'maskgroupbasedcorrmaskmasksangle' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksAngle'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksAngle'] }, + 'maskgroupbasedcorrmaskmasksbottom' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksBottom'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksBottom'] }, + 'maskgroupbasedcorrmaskmaskscentervalue' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksCenterValue'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksCenterValue'] }, + 'maskgroupbasedcorrmaskmaskscenterweight' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksCenterWeight'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksCenterWeight'] }, + 'maskgroupbasedcorrmaskmasksdabs' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksDabs'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksDabs'] }, + 'maskgroupbasedcorrmaskmasksfeather' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksFeather'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksFeather'] }, + 'maskgroupbasedcorrmaskmasksflipped' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksFlipped'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksFlipped'] }, + 'maskgroupbasedcorrmaskmasksflow' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksFlow'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksFlow'] }, + 'maskgroupbasedcorrmaskmasksfullx' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksFullX'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksFullX'] }, + 'maskgroupbasedcorrmaskmasksfully' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksFullY'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksFullY'] }, + 'maskgroupbasedcorrmaskmasksinputdigest' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksInputDigest'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksInputDigest'] }, + 'maskgroupbasedcorrmaskmasksleft' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksLeft'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksLeft'] }, + 'maskgroupbasedcorrmaskmasksmaskactive' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskActive'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskActive'] }, + 'maskgroupbasedcorrmaskmasksmaskblendmode' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskBlendMode'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskBlendMode'] }, + 'maskgroupbasedcorrmaskmasksmaskdigest' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskDigest'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskDigest'] }, + 'maskgroupbasedcorrmaskmasksmaskinverted' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskInverted'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskInverted'] }, + 'maskgroupbasedcorrmaskmasksmaskname' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskName'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskName'] }, + 'maskgroupbasedcorrmaskmasksmasksubtype' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskSubType'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskSubType'] }, + 'maskgroupbasedcorrmaskmasksmasksyncid' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskSyncID'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskSyncID'] }, + 'maskgroupbasedcorrmaskmasksmaskversion' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskVersion'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskVersion'] }, + 'maskgroupbasedcorrmaskmasksmidpoint' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMidpoint'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMidpoint'] }, + 'maskgroupbasedcorrmaskmasksorigin' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksOrigin'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksOrigin'] }, + 'maskgroupbasedcorrmaskmasksperimetervalue' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksPerimeterValue'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksPerimeterValue'] }, + 'maskgroupbasedcorrmaskmasksradius' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksRadius'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksRadius'] }, + 'maskgroupbasedcorrmaskmasksreferencepoint' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksReferencePoint'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksReferencePoint'] }, + 'maskgroupbasedcorrmaskmasksright' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksRight'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksRight'] }, + 'maskgroupbasedcorrmaskmasksroundness' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksRoundness'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksRoundness'] }, + 'maskgroupbasedcorrmaskmaskssizex' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksSizeX'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksSizeX'] }, + 'maskgroupbasedcorrmaskmaskssizey' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksSizeY'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksSizeY'] }, + 'maskgroupbasedcorrmaskmaskstop' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksTop'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksTop'] }, + 'maskgroupbasedcorrmaskmasksubtype' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskSubType'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskSubType'] }, + 'maskgroupbasedcorrmaskmasksvalue' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskValue'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksMaskValue'] }, + 'maskgroupbasedcorrmaskmasksversion' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksVersion'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksVersion'] }, + 'maskgroupbasedcorrmaskmaskswhat' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksWhat'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksWhat'] }, + 'maskgroupbasedcorrmaskmaskswholeimagearea' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksWholeImageArea'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksWholeImageArea'] }, + 'maskgroupbasedcorrmaskmasksx' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksX'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksX'] }, + 'maskgroupbasedcorrmaskmasksy' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksY'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksY'] }, + 'maskgroupbasedcorrmaskmasksyncid' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskSyncID'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskSyncID'] }, + 'maskgroupbasedcorrmaskmaskszerox' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksZeroX'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksZeroX'] }, + 'maskgroupbasedcorrmaskmaskszeroy' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksZeroY'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMasksZeroY'] }, + 'maskgroupbasedcorrmaskmaskversion' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskVersion'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskVersion'] }, + 'maskgroupbasedcorrmaskmidpoint' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMidpoint'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMidpoint'] }, + 'maskgroupbasedcorrmaskorigin' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksOrigin'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksOrigin'] }, + 'maskgroupbasedcorrmaskperimetervalue' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksPerimeterValue'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksPerimeterValue'] }, + 'maskgroupbasedcorrmaskradius' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksRadius'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksRadius'] }, + 'maskgroupbasedcorrmaskrange' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMask'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMask'] }, + 'maskgroupbasedcorrmaskrangeareamodels' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModels'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModels'] }, + 'maskgroupbasedcorrmaskrangeareamodelscolorsampleinfo' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'] }, + 'maskgroupbasedcorrmaskrangeareamodelscomponents' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsAreaComponents'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsAreaComponents'] }, + 'maskgroupbasedcorrmaskrangecoloramount' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskColorAmount'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskColorAmount'] }, + 'maskgroupbasedcorrmaskrangedepthfeather' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthFeather'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthFeather'] }, + 'maskgroupbasedcorrmaskrangedepthmax' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMax'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMax'] }, + 'maskgroupbasedcorrmaskrangedepthmin' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMin'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMin'] }, + 'maskgroupbasedcorrmaskrangeinvert' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskInvert'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskInvert'] }, + 'maskgroupbasedcorrmaskrangelumfeather' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumFeather'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumFeather'] }, + 'maskgroupbasedcorrmaskrangeluminancedepthsampleinfo' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskLuminanceDepthSampleInfo'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskLuminanceDepthSampleInfo'] }, + 'maskgroupbasedcorrmaskrangelummax' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMax'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMax'] }, + 'maskgroupbasedcorrmaskrangelummin' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMin'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMin'] }, + 'maskgroupbasedcorrmaskrangelumrange' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumRange'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumRange'] }, + 'maskgroupbasedcorrmaskrangesampletype' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskSampleType'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskSampleType'] }, + 'maskgroupbasedcorrmaskrangetype' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskType'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskType'] }, + 'maskgroupbasedcorrmaskrangeversion' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskVersion'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksCorrectionRangeMaskVersion'] }, + 'maskgroupbasedcorrmaskreferencepoint' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksReferencePoint'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksReferencePoint'] }, + 'maskgroupbasedcorrmaskright' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksRight'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksRight'] }, + 'maskgroupbasedcorrmaskroundness' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksRoundness'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksRoundness'] }, + 'maskgroupbasedcorrmasksizex' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksSizeX'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksSizeX'] }, + 'maskgroupbasedcorrmasksizey' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksSizeY'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksSizeY'] }, + 'maskgroupbasedcorrmasktop' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksTop'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksTop'] }, + 'maskgroupbasedcorrmaskvalue' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskValue'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksMaskValue'] }, + 'maskgroupbasedcorrmaskversion' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksVersion'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksVersion'] }, + 'maskgroupbasedcorrmaskwhat' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksWhat'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksWhat'] }, + 'maskgroupbasedcorrmaskwholeimagearea' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksWholeImageArea'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksWholeImageArea'] }, + 'maskgroupbasedcorrmaskx' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksX'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksX'] }, + 'maskgroupbasedcorrmasky' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksY'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksY'] }, + 'maskgroupbasedcorrmaskzerox' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksZeroX'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksZeroX'] }, + 'maskgroupbasedcorrmaskzeroy' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksZeroY'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionMasksZeroY'] }, + 'maskgroupbasedcorrmoire' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalMoire'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalMoire'] }, + 'maskgroupbasedcorrrangemask' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMask'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMask'] }, + 'maskgroupbasedcorrrangemaskareamodels' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskAreaModels'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskAreaModels'] }, + 'maskgroupbasedcorrrangemaskareamodelscolorsampleinfo' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'] }, + 'maskgroupbasedcorrrangemaskareamodelscomponents' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskAreaModelsAreaComponents'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskAreaModelsAreaComponents'] }, + 'maskgroupbasedcorrrangemaskcoloramount' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskColorAmount'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskColorAmount'] }, + 'maskgroupbasedcorrrangemaskdepthfeather' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskDepthFeather'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskDepthFeather'] }, + 'maskgroupbasedcorrrangemaskdepthmax' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskDepthMax'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskDepthMax'] }, + 'maskgroupbasedcorrrangemaskdepthmin' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskDepthMin'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskDepthMin'] }, + 'maskgroupbasedcorrrangemaskinvert' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskInvert'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskInvert'] }, + 'maskgroupbasedcorrrangemasklumfeather' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskLumFeather'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskLumFeather'] }, + 'maskgroupbasedcorrrangemaskluminancedepthsampleinfo' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskLuminanceDepthSampleInfo'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskLuminanceDepthSampleInfo'] }, + 'maskgroupbasedcorrrangemasklummax' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskLumMax'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskLumMax'] }, + 'maskgroupbasedcorrrangemasklummin' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskLumMin'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskLumMin'] }, + 'maskgroupbasedcorrrangemasklumrange' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskLumRange'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskLumRange'] }, + 'maskgroupbasedcorrrangemasksampletype' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskSampleType'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskSampleType'] }, + 'maskgroupbasedcorrrangemasktype' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskType'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskType'] }, + 'maskgroupbasedcorrrangemaskversion' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskVersion'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsCorrectionRangeMaskVersion'] }, + 'maskgroupbasedcorrsaturation' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalSaturation'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalSaturation'] }, + 'maskgroupbasedcorrshadows2012' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalShadows2012'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalShadows2012'] }, + 'maskgroupbasedcorrsharpness' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalSharpness'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalSharpness'] }, + 'maskgroupbasedcorrtemperature' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalTemperature'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalTemperature'] }, + 'maskgroupbasedcorrtexture' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalTexture'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalTexture'] }, + 'maskgroupbasedcorrtint' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalTint'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalTint'] }, + 'maskgroupbasedcorrtoninghue' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalToningHue'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalToningHue'] }, + 'maskgroupbasedcorrtoningsaturation' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalToningSaturation'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalToningSaturation'] }, + 'maskgroupbasedcorrwhat' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsWhat'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsWhat'] }, + 'maskgroupbasedcorrwhites2012' => { 478 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalWhites2012'], 480 => [\'MaskGroupBasedCorrections','MaskGroupBasedCorrectionsLocalWhites2012'] }, + 'masterdocumentid' => { 131 => 0xb9 }, + 'mastergain' => { 237 => 0x50 }, + 'materialsample' => { 118 => 'MaterialSample' }, + 'materialsampleid' => { 118 => [\'MaterialSample','MaterialSampleMaterialSampleID'] }, + 'matrixmetering' => { 280 => '50.1', 282 => '48.1', 283 => '48.1', 292 => '48.1', 293 => '48.1', 295 => 0x233 }, + 'matrixselectk' => { 138 => 0x91b }, + 'matrixselectthreshold' => { 138 => 0x91a }, + 'matrixselectthreshold1' => { 138 => 0x91e }, + 'matrixselectthreshold2' => { 138 => 0x91f }, + 'matrixstructure' => { 379 => 0xa }, + 'maxaperture' => { 34 => 0x1a, 138 => 0x3f9, 144 => 0x6103, 163 => 'MaxAperture', 181 => 0x17, 187 => 0x49c5, 224 => 0x36, 298 => 0x20a, 346 => '14.1' }, + 'maxapertureatmaxfocal' => { 127 => 0x1407, 163 => 'MaxApertureAtMaxFocal', 218 => 0xb, 219 => 0x10, 220 => 0x11, 224 => 0x12, 298 => 0x206 }, + 'maxapertureatminfocal' => { 127 => 0x1406, 218 => 0xa, 219 => 0xf, 220 => 0x10, 224 => 0x11, 298 => 0x205 }, + 'maxaperturevalue' => { 119 => 0x9205, 364 => 0x414, 484 => 'MaxApertureValue' }, + 'maxavailheight' => { 490 => 'MaxAvailHeight' }, + 'maxavailwidth' => { 490 => 'MaxAvailWidth' }, + 'maxcontinuousrelease' => { 279 => 0xb, 280 => 0xc, 282 => '12.1', 283 => '12.1', 288 => 0xc, 289 => 0xb, 292 => '12.1', 293 => '12.1', 295 => 0x3d }, + 'maxfaces' => { 301 => 0x1202 }, + 'maxfocallength' => { 7 => 0xe6, 8 => 0x10, 9 => 0x1ab, 10 => 0x13, 11 => 0x115, 12 => 0x13, 13 => 0x153, 14 => 0xda, 16 => 0xfa, 17 => 0xee, 18 => 0x103, 19 => 0x95, 20 => 0xea, 21 => 0x157, 22 => 0xee, 23 => 0xec, 24 => 0x12b, 25 => 0x165, 26 => 0x16a, 27 => 0x188, 28 => 0x116, 29 => 0x18d, 34 => 0x17, 127 => 0x1405, 163 => 'MaxFocalLength', 218 => 0x9, 219 => 0xe, 220 => 0xf, 224 => 0x10, 298 => 0x208, 433 => 0x127c, 434 => 0x1138, 435 => 0x330, 436 => 0x330, 437 => 0x30e }, + 'maximumdensityrange' => { 133 => 0x8c }, + 'maxpagesize' => { 509 => 'MaxPageSize' }, + 'maxpagesizeh' => { 509 => [\'MaxPageSize','MaxPageSizeH'] }, + 'maxpagesizeunit' => { 509 => [\'MaxPageSize','MaxPageSizeUnit'] }, + 'maxpagesizew' => { 509 => [\'MaxPageSize','MaxPageSizeW'] }, + 'maxpixelvaluethreshold' => { 138 => 0xc7d }, + 'maxsamplevalue' => { 119 => 0x119 }, + 'maxstorage' => { 499 => 'maxstorage' }, + 'mb-d10batteries' => { 279 => '12.6' }, + 'mb-d10batterytype' => { 288 => '13.3' }, + 'mb-d11batterytype' => { 289 => '2.3' }, + 'mb-d12batterytype' => { 292 => '3.2' }, + 'mb-d80batteries' => { 290 => '6.5' }, + 'mb-d80batterytype' => { 294 => '3.2' }, + 'mcuversion' => { 218 => 0xc, 219 => 0x11, 220 => 0x12, 224 => 0x13 }, + 'md5digest' => { 164 => 'zmd5' }, + 'mditemfindercomment' => { 173 => 'MDItemFinderComment' }, + 'mditemfscreationdate' => { 173 => 'MDItemFSCreationDate' }, + 'mditemfslabel' => { 173 => 'MDItemFSLabel' }, + 'mditemusertags' => { 173 => 'MDItemUserTags' }, + 'meal' => { 496 => 'meal' }, + 'measuredev' => { 28 => 0x9, 77 => 0x3, 97 => 0x1814, 156 => 'MeasuredEV' }, + 'measuredev2' => { 13 => 0x8, 28 => 0x8, 77 => 0x17 }, + 'measuredev3' => { 13 => 0x9 }, + 'measuredlv' => { 187 => 0x690, 315 => 0x312, 318 => 0x312, 319 => 0x312, 322 => 0x3407 }, + 'measuredrggb' => { 65 => 0x1 }, + 'measuredrggbdata' => { 44 => 0x287 }, + 'measurementaccuracy' => { 118 => [\'MeasurementOrFact','MeasurementOrFactMeasurementAccuracy'] }, + 'measurementdeterminedby' => { 118 => [\'MeasurementOrFact','MeasurementOrFactMeasurementDeterminedBy'] }, + 'measurementdetermineddate' => { 118 => [\'MeasurementOrFact','MeasurementOrFactMeasurementDeterminedDate'] }, + 'measurementid' => { 118 => [\'MeasurementOrFact','MeasurementOrFactMeasurementID'] }, + 'measurementmethod' => { 118 => [\'MeasurementOrFact','MeasurementOrFactMeasurementMethod'] }, + 'measurementorfact' => { 118 => 'MeasurementOrFact' }, + 'measurementremarks' => { 118 => [\'MeasurementOrFact','MeasurementOrFactMeasurementRemarks'] }, + 'measurementtype' => { 118 => [\'MeasurementOrFact','MeasurementOrFactMeasurementType'] }, + 'measurementunit' => { 118 => [\'MeasurementOrFact','MeasurementOrFactMeasurementUnit'] }, + 'measurementvalue' => { 118 => [\'MeasurementOrFact','MeasurementOrFactMeasurementValue'] }, + 'measuretype' => { 463 => 'MeasureType' }, + 'mechanicalshuttercount' => { 226 => 0x37 }, + 'mediaclassprimaryid' => { 179 => 'WM/MediaClassPrimaryID' }, + 'mediaclasssecondaryid' => { 179 => 'WM/MediaClassSecondaryID' }, + 'mediaconstraints' => { 307 => 'MediaConstraints' }, + 'mediacreatedate' => { 376 => 0x1 }, + 'mediaeventiddate' => { 468 => 'MediaEventIdDate' }, + 'mediagroupuuid' => { 1 => 0x11 }, + 'mediamodifydate' => { 376 => 0x2 }, + 'mediasummarycode' => { 307 => 'MediaSummaryCode' }, + 'mediatype' => { 372 => 'stik' }, + 'memoaudioquality' => { 84 => 0x812 }, + 'memorycardconfiguration' => { 413 => 0x16 }, + 'memorycardnumber' => { 208 => 0x2 }, + 'menubuttondisplayposition' => { 82 => 0xb, 85 => 0xa, 86 => 0xb, 89 => 0xb }, + 'menubuttonreturn' => { 90 => 0xb }, + 'menumonitorofftime' => { 279 => '26.1', 280 => '22.1', 282 => '22.1', 283 => '22.1', 287 => '21.1', 288 => '8.2', 289 => '21.1', 292 => '22.1', 293 => '22.1', 294 => '22.1', 295 => 0x35 }, + 'menusettingsz7iioffset' => { 260 => 0xceb6 }, + 'metadataauthority' => { 490 => 'metadataAuthority' }, + 'metadataauthorityidentifier' => { 490 => [\'metadataAuthority','metadataAuthorityIdentifier'] }, + 'metadataauthorityname' => { 490 => [\'metadataAuthority','metadataAuthorityName'] }, + 'metadatadate' => { 502 => 'MetadataDate' }, + 'metadatalastedited' => { 490 => 'metadataLastEdited' }, + 'metadatalasteditor' => { 490 => 'metadataLastEditor' }, + 'metadatalasteditoridentifier' => { 490 => [\'metadataLastEditor','metadataLastEditorIdentifier'] }, + 'metadatalasteditorname' => { 490 => [\'metadataLastEditor','metadataLastEditorName'] }, + 'metadatamoddate' => { 504 => 'metadataModDate' }, + 'metaversion' => { 428 => 0x34 }, + 'meterinfo1row1' => { 421 => 0x0, 422 => 0x0 }, + 'meterinfo1row2' => { 421 => 0x6c, 422 => 0x5a }, + 'meterinfo1row3' => { 421 => 0xd8, 422 => 0xb4 }, + 'meterinfo1row4' => { 421 => 0x144, 422 => 0x10e }, + 'meterinfo1row5' => { 421 => 0x1b0, 422 => 0x168 }, + 'meterinfo1row6' => { 421 => 0x21c, 422 => 0x1c2 }, + 'meterinfo1row7' => { 421 => 0x288, 422 => 0x21c }, + 'meterinfo2row1' => { 421 => 0x2f4, 422 => 0x276 }, + 'meterinfo2row2' => { 421 => 0x378, 422 => 0x2e4 }, + 'meterinfo2row3' => { 421 => 0x3fc, 422 => 0x352 }, + 'meterinfo2row4' => { 421 => 0x480, 422 => 0x3c0 }, + 'meterinfo2row5' => { 421 => 0x504, 422 => 0x42e }, + 'meterinfo2row6' => { 421 => 0x588, 422 => 0x49c }, + 'meterinfo2row7' => { 421 => 0x60c, 422 => 0x50a }, + 'meterinfo2row8' => { 421 => 0x690, 422 => 0x578 }, + 'meterinfo2row9' => { 421 => 0x714, 422 => 0x5e6 }, + 'metering' => { 281 => '6.1' }, + 'meteringmode' => { 34 => 0x11, 119 => 0x9207, 140 => 0x1c, 181 => 0x7, 182 => 0x25, 184 => 0x12, 297 => 0x202, 355 => 0x17, 397 => 0x9, 407 => 0x15, 408 => 0x13, 409 => 0x7, 425 => 0x3, 429 => 0x1174, 430 => 0x1178, 431 => 0x1154, 432 => 0x11d0, 433 => 0x11ac, 434 => 0x1064, 435 => 0x25c, 436 => 0x25c, 437 => 0x24b, 484 => 'MeteringMode' }, + 'meteringmode2' => { 336 => '2.1', 420 => 0x202c }, + 'meteringmode3' => { 336 => '16.1' }, + 'meteringoffscaleindicator' => { 184 => 0x53 }, + 'meteringtime' => { 279 => '22.2', 281 => '3.2', 284 => '17.1', 285 => '18.1', 288 => '7.3', 289 => '18.1', 290 => '3.2', 294 => '19.1' }, + 'micro1version' => { 382 => 0x1f }, + 'micro2version' => { 382 => 0x2d }, + 'microphoneattenuator' => { 229 => 0x2d2 }, + 'microphonefrequencyresponse' => { 229 => 0x2d4 }, + 'microphonejackpower' => { 229 => 0x2fa }, + 'microphonesensitivity' => { 229 => 0x2d0 }, + 'microvideo' => { 461 => 'MicroVideo' }, + 'microvideooffset' => { 461 => 'MicroVideoOffset' }, + 'microvideopresentationtimestampus' => { 461 => 'MicroVideoPresentationTimestampUs' }, + 'microvideoversion' => { 461 => 'MicroVideoVersion' }, + 'midrangesharpness' => { 233 => 0x3b }, + 'mieversion' => { 164 => '0Vers' }, + 'mime' => { 463 => 'Mime' }, + 'minaperture' => { 34 => 0x1b, 138 => 0x3f8, 163 => 'MinAperture', 346 => '0.2' }, + 'minaperturevalue' => { 364 => 0x415 }, + 'minfocallength' => { 7 => 0xe4, 8 => 0xe, 9 => 0x1a9, 10 => 0x11, 11 => 0x113, 12 => 0x11, 13 => 0x151, 14 => 0xd8, 16 => 0xf8, 17 => 0xec, 18 => 0x101, 19 => 0x93, 20 => 0xe8, 21 => 0x155, 22 => 0xec, 23 => 0xea, 24 => 0x129, 25 => 0x163, 26 => 0x168, 27 => 0x186, 28 => 0x114, 29 => 0x18b, 34 => 0x18, 127 => 0x1404, 163 => 'MinFocalLength', 218 => 0x8, 219 => 0xd, 220 => 0xe, 224 => 0xf, 298 => 0x207, 433 => 0x127a, 434 => 0x1136, 435 => 0x32e, 436 => 0x32e, 437 => 0x30c }, + 'minfocusdistance' => { 346 => 0x3 }, + 'minintegrationrows' => { 138 => 0x1874 }, + 'minoltadate' => { 181 => 0x15 }, + 'minoltaimagesize' => { 181 => 0x4, 182 => 0xc, 183 => 0x2, 186 => 0x103 }, + 'minoltamodelid' => { 181 => 0x25 }, + 'minoltaquality' => { 181 => 0x5, 182 => 0xd, 183 => 0x3, 186 => [0x102,0x103] }, + 'minoltatime' => { 181 => 0x16 }, + 'minormodelagedisclosure' => { 307 => 'MinorModelAgeDisclosure' }, + 'minorversion' => { 469 => 'MinorVersion' }, + 'minsamplevalue' => { 119 => 0x118 }, + 'mirrorlockup' => { 82 => 0xc, 83 => 0xc, 84 => 0x60f, 85 => 0xb, 86 => 0xc, 87 => 0x6, 88 => 0x6, 89 => 0xc, 90 => 0x3 }, + 'mobilecountrycode' => { 477 => 'mcc' }, + 'mobilenetworkcode' => { 477 => 'mnc' }, + 'moddate' => { 310 => 'modify-date', 491 => 'ModDate' }, + 'modedialposition' => { 413 => 0x14 }, + 'model' => { 98 => 0x6, 119 => 0x110, 156 => 'Model', 310 => 'Model', 325 => 0x110, 355 => 0x23f, 374 => 'model', 380 => ['@mod','CNMN','cmnm',"\xa9mdl","\xa9mod"], 397 => 0x84, 463 => 'Model', 493 => 'model', 500 => 'Model' }, + 'modelage' => { 490 => 'ModelAge' }, + 'modelid' => { 296 => 0x0 }, + 'modelingflash' => { 279 => '21.4', 280 => '31.1', 282 => '31.1', 283 => '31.1', 288 => '26.4', 289 => '30.2', 290 => '7.4', 291 => '30.1', 292 => '31.1', 293 => '31.1', 294 => '31.3', 295 => 0x5d }, + 'modelreleaseid' => { 307 => 'ModelReleaseID' }, + 'modelreleasestatus' => { 307 => 'ModelReleaseStatus' }, + 'modelreleaseyear' => { 442 => 0x52, 443 => 0x46, 444 => 0x53 }, + 'modeltiepoint' => { 119 => 0x8482 }, + 'modeltransform' => { 119 => 0x85d8 }, + 'modelyear' => { 493 => 'modelYear' }, + 'modificationdate' => { 494 => 'modificationDate' }, + 'modifiedcolortemp' => { 66 => 0x9 }, + 'modifieddigitalgain' => { 66 => 0xb }, + 'modifiedparamflag' => { 58 => 0x1 }, + 'modifiedpicturestyle' => { 66 => 0xa }, + 'modifiedsaturation' => { 297 => 0x504 }, + 'modifiedsensorbluelevel' => { 66 => 0x5 }, + 'modifiedsensorredlevel' => { 66 => 0x4 }, + 'modifiedsharpness' => { 66 => 0x2 }, + 'modifiedsharpnessfreq' => { 66 => 0x3 }, + 'modifiedtonecurve' => { 66 => 0x1 }, + 'modifiedwhitebalance' => { 66 => 0x8 }, + 'modifiedwhitebalanceblue' => { 66 => 0x7 }, + 'modifiedwhitebalancered' => { 66 => 0x6 }, + 'modifydate' => { 119 => 0x132, 157 => 'ModifyDate', 306 => 'ModDate', 308 => 'tIME', 371 => 'ModDate', 377 => 0x2, 502 => 'ModifyDate' }, + 'moirefilter' => { 119 => 0xfe58, 478 => 'MoireFilter', 480 => 'MoireFilter' }, + 'monitorbrightness' => { 229 => 0x59a }, + 'monitordisplayoff' => { 184 => 0x4c }, + 'monitormatrix' => { 138 => 0x8fc }, + 'monitorofftime' => { 279 => '18.2', 281 => '3.1', 290 => '3.1' }, + 'monochromecolor' => { 297 => 0x53b }, + 'monochromecontrast' => { 109 => 0x3c }, + 'monochromefiltereffect' => { 103 => 0x20307, 109 => 0x3a, 320 => 0xac, 355 => 0x73 }, + 'monochromegraineffect' => { 320 => 0xd2 }, + 'monochromelinear' => { 109 => 0x3d }, + 'monochromeoutputhighlightpoint' => { 109 => 0x41 }, + 'monochromeoutputshadowpoint' => { 109 => 0x42 }, + 'monochromeprofilesettings' => { 297 => 0x537 }, + 'monochromerawhighlight' => { 109 => 0x7a }, + 'monochromerawhighlightpoint' => { 109 => 0x3f }, + 'monochromerawshadow' => { 109 => 0x83 }, + 'monochromerawshadowpoint' => { 109 => 0x40 }, + 'monochromesharpness' => { 109 => 0x3e }, + 'monochrometoning' => { 355 => 0x74 }, + 'monochrometoningeffect' => { 103 => 0x20306, 109 => 0x3b }, + 'monochromeunsharpmaskfineness' => { 109 => 0xb2 }, + 'monochromeunsharpmaskstrength' => { 109 => 0xb0 }, + 'monochromeunsharpmaskthreshold' => { 109 => 0xb4 }, + 'monochromevignetting' => { 297 => 0x53a }, + 'monthdaycreated' => { 140 => 0x12, 149 => 0xe }, + 'mood' => { 179 => 'WM/Mood' }, + 'moonphase' => { 381 => 0x12, 382 => 0x43, 383 => 0x4c }, + 'morepermissions' => { 476 => 'morePermissions' }, + 'motionsensitivity' => { 381 => 0x29, 383 => 0x60 }, + 'movementcount' => { 372 => "\xa9mvc" }, + 'movementname' => { 372 => "\xa9mvn" }, + 'movementnumber' => { 372 => "\xa9mvi" }, + 'movieactived-lighting' => { 228 => 0x238, 229 => 0x2b8 }, + 'movieaelockbuttonassignment' => { 292 => '40.1' }, + 'movieaf-onbutton' => { 295 => 0xcb }, + 'movieafareamode' => { 229 => 0x2c6, 295 => 0x203 }, + 'movieafspeed' => { 295 => 0xdd }, + 'movieafspeedapply' => { 295 => 0xdf }, + 'movieaftrackingsensitivity' => { 295 => 0xe1 }, + 'movieaperturelock' => { 295 => 0x259 }, + 'movieautodistortioncontrol' => { 228 => 0x242 }, + 'moviediffractioncompensation' => { 228 => 0x241 }, + 'moviedxcropalert' => { 229 => 0x2fb }, + 'movieelectronicvr' => { 229 => 0x2cc }, + 'movieevfgrid' => { 295 => 0x21d }, + 'movieflickerreduction' => { 229 => 0x2c0 }, + 'moviefocusmode' => { 228 => 0x248, 229 => 0x2c4 }, + 'moviefocuspointlock' => { 295 => 0x226 }, + 'movieframerate' => { 228 => 0x1f8, 229 => 0x2f4 }, + 'movieframesize' => { 228 => 0x1f6, 229 => 0x2f2 }, + 'moviefunc1button' => { 282 => '41.1', 283 => '41.1', 293 => '41.1', 295 => 0xc3 }, + 'moviefunc3button' => { 295 => 0x127 }, + 'moviefunctionbutton' => { 280 => '41.1', 292 => '41.1' }, + 'moviefunctionbuttonplusdials' => { 280 => '52.1' }, + 'moviehighisonoisereduction' => { 228 => 0x23c, 229 => 0x2ba }, + 'moviehighlightdisplaythreshold' => { 295 => 0x215 }, + 'movieimagearea' => { 229 => 0x25c }, + 'movieisoautocontrolmanualmode' => { 229 => 0x26a }, + 'movieisoautohilimit' => { 229 => 0x268 }, + 'movieisoautomanualmode' => { 228 => 0x204, 229 => 0x26c }, + 'moviemeteringmode' => { 229 => 0x2c2 }, + 'moviemidtonedisplayrange' => { 295 => 0x219 }, + 'moviemidtonedisplayvalue' => { 295 => 0x217 }, + 'moviemultiselector' => { 295 => 0xd9 }, + 'moviepreviewbutton' => { 280 => '41.2', 282 => '41.2', 283 => '41.2', 292 => '41.2', 293 => '41.2' }, + 'moviepreviewbuttonplusdials' => { 280 => '52.2' }, + 'movierecordbuttonplaybackmode' => { 295 => 0x1b5 }, + 'movieshutterbutton' => { 280 => '38.3', 282 => '38.3', 283 => '38.3', 292 => '38.3', 293 => '38.3' }, + 'movieshutterspeedlock' => { 295 => 0x225 }, + 'movieslowmotion' => { 228 => 0x1fa }, + 'moviesoundrecording' => { 229 => 0x2ce }, + 'moviesubjectdetection' => { 229 => 0x2fc }, + 'moviesubselectorassignment' => { 280 => '48.2' }, + 'moviesubselectorassignmentplusdials' => { 280 => '53.1' }, + 'movietonemap' => { 229 => 0x2ec }, + 'movietype' => { 228 => 0x1fe, 229 => 0x266, 252 => 0xc55c }, + 'movievibrationreduction' => { 228 => 0x24e }, + 'movievibrationreductionsameasphoto' => { 228 => 0x24f }, + 'movievignettecontrol' => { 228 => 0x23e, 229 => 0x1a0 }, + 'movievignettecontrolsameasphoto' => { 228 => 0x240 }, + 'movievrmode' => { 229 => 0x2c8 }, + 'moviezebrapattern' => { 295 => 0x213 }, + 'multiburstimageheight' => { 420 => 0x1002 }, + 'multiburstimagewidth' => { 420 => 0x1001 }, + 'multiburstmode' => { 420 => 0x1000 }, + 'multicontrollerwhilemetering' => { 84 => 0x517 }, + 'multiexposure' => { 68 => 0x1, 320 => 0xb4 }, + 'multiexposureautogain' => { 230 => 0x3 }, + 'multiexposurecontrol' => { 68 => 0x2 }, + 'multiexposuremode' => { 230 => 0x1 }, + 'multiexposureshots' => { 68 => 0x3, 229 => 0x8e, 230 => 0x2 }, + 'multiframenoisereduction' => { 409 => 0x35, 420 => 0x200b, 425 => 0x15 }, + 'multiframenreffect' => { 420 => 0x2023 }, + 'multifunctionlock' => { 84 => 0x70f }, + 'multipleexposuremode' => { 229 => 0x8c, 301 => 0x101c }, + 'multipleexposureset' => { 336 => '10.1' }, + 'multisample' => { 237 => 0x40 }, + 'multiselector' => { 279 => '9.4', 280 => '10.3', 282 => '10.3', 283 => '10.3', 288 => '27.4', 292 => '10.3', 293 => '10.3' }, + 'multiselectorliveview' => { 279 => '4.3', 282 => '37.1', 283 => '37.1', 292 => '37.1', 293 => '37.1' }, + 'multiselectorliveviewmode' => { 247 => 0x18c2 }, + 'multiselectorplaybackmode' => { 279 => ['13.5','9.2'], 280 => '10.2', 283 => '10.2', 288 => '27.2', 292 => '10.2', 293 => '10.2', 295 => 0xb3 }, + 'multiselectorshootmode' => { 279 => '9.1', 280 => '10.1', 282 => '10.1', 283 => '10.1', 288 => '27.1', 292 => '10.1', 293 => '10.1', 295 => 0xaf }, + 'multishot' => { 325 => 0x121 }, + 'mute' => { 374 => 'player.movie.audio.mute' }, + 'mycolormode' => { 69 => 0x2 }, + 'name' => { 380 => 'name', 478 => 'Name', 480 => 'Name' }, + 'narrator' => { 372 => "\xa9nrt" }, + 'nationalcatalognumber' => { 494 => 'nationalCatalogNumber' }, + 'nativedigest' => { 484 => 'NativeDigest', 500 => 'NativeDigest' }, + 'ndfilter' => { 77 => 0x1c, 297 => 0x204, 387 => 0x1019 }, + 'near' => { 463 => 'Near' }, + 'nefbitdepth' => { 226 => 0xe22 }, + 'nefcompression' => { 226 => 0x93, 227 => 0xa }, + 'neflinearizationtable' => { 226 => 0x96 }, + 'negativecachelargepreviewsize' => { 478 => 'NegativeCacheLargePreviewSize', 480 => 'NegativeCacheLargePreviewSize' }, + 'negativecachemaximumsize' => { 478 => 'NegativeCacheMaximumSize', 480 => 'NegativeCacheMaximumSize' }, + 'negativecachepath' => { 478 => 'NegativeCachePath', 480 => 'NegativeCachePath' }, + 'neutraldensityfactor' => { 475 => 'NeutralDensityFactor' }, + 'neutraldensityfilter' => { 355 => 0x88 }, + 'neutraloutputhighlightpoint' => { 109 => 0x2f }, + 'neutraloutputshadowpoint' => { 109 => 0x30 }, + 'neutralrawcolortone' => { 109 => 0x28 }, + 'neutralrawcontrast' => { 109 => 0x2a }, + 'neutralrawhighlight' => { 109 => 0x78 }, + 'neutralrawhighlightpoint' => { 109 => 0x2d }, + 'neutralrawlinear' => { 109 => 0x2b }, + 'neutralrawsaturation' => { 109 => 0x29 }, + 'neutralrawshadow' => { 109 => 0x81 }, + 'neutralrawshadowpoint' => { 109 => 0x2e }, + 'neutralrawsharpness' => { 109 => 0x2c }, + 'neutralunsharpmaskfineness' => { 109 => 0xa6 }, + 'neutralunsharpmaskthreshold' => { 109 => 0xa8 }, + 'neutraunsharpmaskstrength' => { 109 => 0xa4 }, + 'newrawimagedigest' => { 119 => 0xc7a7 }, + 'newsphotoversion' => { 133 => 0x0 }, + 'nickname' => { 502 => 'Nickname' }, + 'nikoncapturedata' => { 226 => 0xe01 }, + 'nikoncaptureeditversions' => { 226 => 0xe13 }, + 'nikoncaptureoffsets' => { 226 => 0xe0e }, + 'nikoncaptureoutput' => { 226 => 0xe1e }, + 'nikoncaptureversion' => { 226 => 0xe09 }, + 'nikoniccprofile' => { 226 => 0xe1d }, + 'nikonimagesize' => { 244 => '723.1', 245 => '732.1', 255 => 0x2c4 }, + 'nikonmeteringmode' => { 228 => 0x146, 248 => 0x2ea4, 257 => 0x175e }, + 'nikonsettings' => { 226 => 0x4e }, + 'noisefilter' => { 297 => 0x527 }, + 'noiseprofile' => { 119 => 0xc761 }, + 'noisereduction' => { 127 => [0x100b,0x100e], 182 => 0xb0, 183 => 0x60, 184 => 0x3f, 226 => 0x95, 272 => 0x753dcbc0, 273 => 0x17, 297 => 0x50a, 302 => 0x103a, 320 => 0x2d, 355 => 0x49, 387 => 0x100f, 389 => 0x2a }, + 'noisereduction2' => { 301 => 0x1010 }, + 'noisereductionapplied' => { 119 => 0xc6f7 }, + 'noisereductionintensity' => { 273 => 0x9 }, + 'noisereductionmethod' => { 273 => 0x11 }, + 'noisereductionmode' => { 455 => 0x801e }, + 'noisereductionparametersatcapture' => { 138 => 0xe73 }, + 'noisereductionparameterscamera' => { 138 => 0xe72 }, + 'noisereductionparametershost3mp' => { 138 => 0xe71 }, + 'noisereductionparametershost6mp' => { 138 => 0xe70 }, + 'noisereductionparametershostrgb' => { 138 => 0xe6f }, + 'noisereductionparameterskhufu3mp' => { 138 => 0xe65 }, + 'noisereductionparameterskhufu6mp' => { 138 => 0xe64 }, + 'noisereductionparameterskhufurgb' => { 138 => 0xe63 }, + 'noisereductionparams' => { 325 => 0x1b }, + 'noisereductionsharpness' => { 273 => 0xd }, + 'noisereductionstrength' => { 320 => 0xd6 }, + 'noisereductionvalue' => { 455 => 0x8027 }, + 'nomemorycard' => { 279 => '22.1', 280 => '4.2', 281 => '0.3', 284 => '2.4', 285 => '3.2', 286 => '3.2', 288 => '33.7', 289 => '3.2', 290 => '0.3', 292 => '4.2', 294 => '4.5' }, + 'nominalmaxaperture' => { 346 => 0xa }, + 'nominalminaperture' => { 346 => '10.1' }, + 'normallinetime' => { 138 => 0x186a }, + 'normalwhitelevel' => { 41 => 0x32a, 42 => 0x280, 45 => [0x2b8,0x2cf,0x2d3], 46 => 0x569, 47 => 0x1e3, 48 => [0x1fc,0x2dc], 49 => [0x230,0x30e], 50 => 0x31c }, + 'notes' => { 456 => 'Notes', 473 => 'notes' }, + 'npages' => { 509 => 'NPages' }, + 'nullrecord' => { 97 => 0x0 }, + 'numafpoints' => { 332 => 0x2 }, + 'number' => { 494 => 'number' }, + 'numberofbeats' => { 504 => 'numberOfBeats' }, + 'numberoffocuspoints' => { 282 => '1.3', 283 => '1.3', 286 => '0.2', 287 => '0.3', 289 => '0.3' }, + 'numfaceelements' => { 127 => 0x4200 }, + 'numfacepositions' => { 312 => 0x0 }, + 'numindexentries' => { 133 => 0x54 }, + 'numwbentries' => { 326 => 0x0, 327 => 0x0 }, + 'object' => { 494 => 'object' }, + 'objectattributereference' => { 131 => 0x4 }, + 'objectcycle' => { 131 => 0x4b, 473 => 'ObjectCycle' }, + 'objectdescription' => { 493 => 'objectDescription' }, + 'objectdistance' => { 112 => 0x6, 113 => 0x2022 }, + 'objectname' => { 131 => 0x5 }, + 'objectpreviewdata' => { 131 => 0xca }, + 'objectpreviewfileformat' => { 131 => 0xc8 }, + 'objectpreviewfileversion' => { 131 => 0xc9 }, + 'objectsubtype' => { 493 => 'objectSubtype' }, + 'objecttype' => { 493 => 'objectType' }, + 'objecttypereference' => { 131 => 0x3 }, + 'occurrence' => { 118 => 'Occurrence' }, + 'occurrenceassociatedmedia' => { 118 => [\'Occurrence','OccurrenceAssociatedMedia'] }, + 'occurrenceassociatedoccurrences' => { 118 => [\'Occurrence','OccurrenceAssociatedOccurrences'] }, + 'occurrenceassociatedreferences' => { 118 => [\'Occurrence','OccurrenceAssociatedReferences'] }, + 'occurrenceassociatedsequences' => { 118 => [\'Occurrence','OccurrenceAssociatedSequences'] }, + 'occurrenceassociatedtaxa' => { 118 => [\'Occurrence','OccurrenceAssociatedTaxa'] }, + 'occurrencebehavior' => { 118 => [\'Occurrence','OccurrenceBehavior'] }, + 'occurrencecatalognumber' => { 118 => [\'Occurrence','OccurrenceCatalogNumber'] }, + 'occurrencedegreeofestablishment' => { 118 => [\'Occurrence','OccurrenceDegreeOfEstablishment'] }, + 'occurrencedetails' => { 118 => [\'Occurrence','OccurrenceOccurrenceDetails'] }, + 'occurrencedisposition' => { 118 => [\'Occurrence','OccurrenceDisposition'] }, + 'occurrenceestablishmentmeans' => { 118 => [\'Occurrence','OccurrenceEstablishmentMeans'] }, + 'occurrencegeoreferenceverificationstatus' => { 118 => [\'Occurrence','OccurrenceGeoreferenceVerificationStatus'] }, + 'occurrenceid' => { 118 => [\'Occurrence','OccurrenceOccurrenceID'] }, + 'occurrenceindividualcount' => { 118 => [\'Occurrence','OccurrenceIndividualCount'] }, + 'occurrenceindividualid' => { 118 => [\'Occurrence','OccurrenceIndividualID'] }, + 'occurrencelifestage' => { 118 => [\'Occurrence','OccurrenceLifeStage'] }, + 'occurrenceorganismquantity' => { 118 => [\'Occurrence','OccurrenceOrganismQuantity'] }, + 'occurrenceorganismquantitytype' => { 118 => [\'Occurrence','OccurrenceOrganismQuantityType'] }, + 'occurrenceothercatalognumbers' => { 118 => [\'Occurrence','OccurrenceOtherCatalogNumbers'] }, + 'occurrencepathway' => { 118 => [\'Occurrence','OccurrencePathway'] }, + 'occurrencepreparations' => { 118 => [\'Occurrence','OccurrencePreparations'] }, + 'occurrencepreviousidentifications' => { 118 => [\'Occurrence','OccurrencePreviousIdentifications'] }, + 'occurrencerecordedby' => { 118 => [\'Occurrence','OccurrenceRecordedBy'] }, + 'occurrencerecordedbyid' => { 118 => [\'Occurrence','OccurrenceRecordedByID'] }, + 'occurrencerecordnumber' => { 118 => [\'Occurrence','OccurrenceRecordNumber'] }, + 'occurrenceremarks' => { 118 => [\'Occurrence','OccurrenceOccurrenceRemarks'] }, + 'occurrencereproductivecondition' => { 118 => [\'Occurrence','OccurrenceReproductiveCondition'] }, + 'occurrencesex' => { 118 => [\'Occurrence','OccurrenceSex'] }, + 'occurrencestatus' => { 118 => [\'Occurrence','OccurrenceOccurrenceStatus'] }, + 'oecfcolumns' => { 484 => [\'OECF','OECFColumns'] }, + 'oecfnames' => { 484 => [\'OECF','OECFNames'] }, + 'oecfrows' => { 484 => [\'OECF','OECFRows'] }, + 'oecfvalues' => { 484 => [\'OECF','OECFValues'] }, + 'offsaledate' => { 494 => 'offSaleDate' }, + 'offsaledatea-platform' => { 494 => [\'offSaleDate','offSaleDateA-platform'] }, + 'offsaledatedate' => { 494 => [\'offSaleDate','offSaleDateDate'] }, + 'offsetdacvalue' => { 138 => 0x190a }, + 'offsetschema' => { 119 => 0xea1d }, + 'offsettime' => { 119 => 0x9010 }, + 'offsettimedigitized' => { 119 => 0x9012 }, + 'offsettimeoriginal' => { 119 => 0x9011 }, + 'okbutton' => { 289 => '15.1', 294 => '16.1' }, + 'oldsubfiletype' => { 119 => 0xff }, + 'olympusimageheight' => { 302 => 0x102f }, + 'olympusimagewidth' => { 302 => 0x102e }, + 'omenatcapturestrength' => { 138 => 0xa60 }, + 'omenautostrength' => { 138 => 0xa5f }, + 'omenearlystrength' => { 138 => 0xa5e }, + 'omenfocallengthlimit' => { 138 => 0xa62 }, + 'omeninitialipfstrength' => { 138 => 0xa5d }, + 'omensurfaceindex' => { 138 => 0xa64 }, 'oneshotafrelease' => { 2 => 0x9 }, - 'onetouchwb' => { 279 => 0x302 }, - 'onsaledate' => { 456 => 'onSaleDate' }, - 'onsaledatea-platform' => { 456 => [\'onSaleDate','onSaleDateA-platform'] }, - 'onsaledatedate' => { 456 => [\'onSaleDate','onSaleDateDate'] }, - 'onsaleday' => { 456 => 'onSaleDay' }, - 'onsaledaya-platform' => { 456 => [\'onSaleDay','onSaleDayA-platform'] }, - 'onsaledayday' => { 456 => [\'onSaleDay','onSaleDayDay'] }, - 'opcodelist1' => { 113 => 0xc740 }, - 'opcodelist2' => { 113 => 0xc741 }, - 'opcodelist3' => { 113 => 0xc74e }, - 'opticalzoom' => { 135 => 0xfa3d, 137 => [0x6006,0xf006], 138 => 0x1000, 139 => 0xf, 142 => 0x1e, 154 => 'OpticalZoom' }, - 'opticalzoomcode' => { 72 => 0xa }, - 'opticalzoommode' => { 297 => 0x34 }, - 'opticalzoomon' => { 367 => 0x219 }, - 'optionenddate' => { 459 => 'optionEndDate' }, - 'opto-electricconvfactor' => { 446 => 'OECF' }, - 'orangehsl' => { 97 => 0x20911 }, - 'ordernumber' => { 121 => 0x8002 }, - 'organisationinimagecode' => { 452 => 'OrganisationInImageCode' }, - 'organisationinimagename' => { 452 => 'OrganisationInImageName' }, - 'organism' => { 112 => 'Organism' }, - 'organismassociatedoccurrences' => { 112 => [\'Organism','OrganismAssociatedOccurrences'] }, - 'organismassociatedorganisms' => { 112 => [\'Organism','OrganismAssociatedOrganisms'] }, - 'organismid' => { 112 => [\'Organism','OrganismOrganismID'] }, - 'organismname' => { 112 => [\'Organism','OrganismOrganismName'] }, - 'organismpreviousidentifications' => { 112 => [\'Organism','OrganismPreviousIdentifications'] }, - 'organismremarks' => { 112 => [\'Organism','OrganismOrganismRemarks'] }, - 'organismscope' => { 112 => [\'Organism','OrganismOrganismScope'] }, - 'organization' => { 456 => 'organization' }, - 'orientation' => { 113 => 0x112, 302 => 0x112, 455 => 'orientation', 462 => 'Orientation' }, - 'orientation2' => { 393 => [0x28,0x2e] }, + 'onetouchwb' => { 302 => 0x302 }, + 'onsaledate' => { 494 => 'onSaleDate' }, + 'onsaledatea-platform' => { 494 => [\'onSaleDate','onSaleDateA-platform'] }, + 'onsaledatedate' => { 494 => [\'onSaleDate','onSaleDateDate'] }, + 'onsaleday' => { 494 => 'onSaleDay' }, + 'onsaledaya-platform' => { 494 => [\'onSaleDay','onSaleDayA-platform'] }, + 'onsaledayday' => { 494 => [\'onSaleDay','onSaleDayDay'] }, + 'opcodelist1' => { 119 => 0xc740 }, + 'opcodelist2' => { 119 => 0xc741 }, + 'opcodelist3' => { 119 => 0xc74e }, + 'opticalzoom' => { 142 => 0xfa3d, 144 => [0x6006,0xf006], 145 => 0x1000, 146 => 0xf, 149 => 0x1e, 151 => 0x20, 152 => 0x1c, 163 => 'OpticalZoom' }, + 'opticalzoomcode' => { 77 => 0xa }, + 'opticalzoommode' => { 320 => 0x34 }, + 'opticalzoomon' => { 396 => 0x219 }, + 'optionenddate' => { 497 => 'optionEndDate' }, + 'opto-electricconvfactor' => { 484 => 'OECF' }, + 'orangehsl' => { 103 => 0x20911 }, + 'ordernumber' => { 127 => 0x8002 }, + 'organisationinimagecode' => { 490 => 'OrganisationInImageCode' }, + 'organisationinimagename' => { 490 => 'OrganisationInImageName' }, + 'organism' => { 118 => 'Organism' }, + 'organismassociatedoccurrences' => { 118 => [\'Organism','OrganismAssociatedOccurrences'] }, + 'organismassociatedorganisms' => { 118 => [\'Organism','OrganismAssociatedOrganisms'] }, + 'organismid' => { 118 => [\'Organism','OrganismOrganismID'] }, + 'organismname' => { 118 => [\'Organism','OrganismOrganismName'] }, + 'organismpreviousidentifications' => { 118 => [\'Organism','OrganismPreviousIdentifications'] }, + 'organismremarks' => { 118 => [\'Organism','OrganismOrganismRemarks'] }, + 'organismscope' => { 118 => [\'Organism','OrganismOrganismScope'] }, + 'organization' => { 494 => 'organization' }, + 'orientation' => { 119 => 0x112, 325 => 0x112, 493 => 'orientation', 500 => 'Orientation' }, + 'orientation2' => { 425 => [0x28,0x2e] }, 'orientationlinkedaf' => { 2 => 0xe }, - 'orientationlinkedafpoint' => { 78 => 0x516 }, - 'originalbestqualitysize' => { 113 => 0xc792 }, - 'originalcreatedatetime' => { 431 => 'OriginalCreateDateTime' }, - 'originaldecisiondata' => { 108 => 'OriginalDecisionData' }, - 'originaldecisiondataoffset' => { 60 => 0x83 }, - 'originaldefaultcropsize' => { 113 => 0xc793 }, - 'originaldefaultfinalsize' => { 113 => 0xc791 }, - 'originaldirectory' => { 294 => 0x408 }, - 'originaldocumentid' => { 467 => 'OriginalDocumentID' }, - 'originalfilename' => { 91 => 0x816, 131 => 0x3e9, 143 => 0x20, 294 => 0x407, 431 => 'OriginalFilename' }, - 'originalimageheight' => { 74 => 0xc, 117 => 0x1 }, - 'originalimagewidth' => { 74 => 0xb, 117 => 0x0 }, - 'originalrawfiledata' => { 113 => 0xc68c }, - 'originalrawfiledigest' => { 113 => 0xc71d }, - 'originalrawfilename' => { 113 => 0xc68b }, - 'originaltransmissionreference' => { 125 => 0x67 }, - 'originatingprogram' => { 125 => 0x41, 436 => 'OriginatingProgram' }, - 'originplatform' => { 456 => 'originPlatform' }, - 'os' => { 444 => 'os' }, - 'otherconditions' => { 284 => 'OtherConditions' }, - 'otherconstraints' => { 284 => 'OtherConstraints' }, - 'otherimage' => { 108 => 'OtherImage' }, - 'otherimageinfo' => { 284 => 'OtherImageInfo' }, - 'otherimagelength' => { 113 => 0x202 }, - 'otherimagestart' => { 113 => 0x201 }, - 'otherlicensedocuments' => { 284 => 'OtherLicenseDocuments' }, - 'otherlicenseinfo' => { 284 => 'OtherLicenseInfo' }, - 'otherlicenserequirements' => { 284 => 'OtherLicenseRequirements' }, - 'outcue' => { 466 => 'outCue' }, - 'outcuescale' => { 466 => [\'outCue','outCueScale'] }, - 'outcuevalue' => { 466 => [\'outCue','outCueValue'] }, - 'outputimageheight' => { 186 => 0x3 }, - 'outputimagewidth' => { 186 => 0x2 }, - 'outputlut' => { 297 => 0xa7 }, - 'outputprofile' => { 131 => 0x138b }, - 'outputresolution' => { 186 => 0x4 }, - 'overclockcols' => { 131 => 0x189c }, - 'overclockrows' => { 131 => 0x18c4 }, - 'owner' => { 470 => 'Owner' }, - 'ownerid' => { 125 => 0xbc }, - 'ownername' => { 14 => 0x10f, 60 => 0x9, 91 => 0x810, 113 => [0xa430,0xfde8], 147 => 'OwnerName', 438 => 'OwnerName', 447 => 'CameraOwnerName' }, - 'padding' => { 113 => 0xea1c }, - 'pagecount' => { 456 => 'pageCount' }, - 'pageimage' => { 464 => [\'PageInfo','PageInfoImage'] }, - 'pageimageformat' => { 464 => [\'PageInfo','PageInfoFormat'] }, - 'pageimageheight' => { 464 => [\'PageInfo','PageInfoHeight'] }, - 'pageimagepagenumber' => { 464 => [\'PageInfo','PageInfoPageNumber'] }, - 'pageimagewidth' => { 464 => [\'PageInfo','PageInfoWidth'] }, - 'pageinfo' => { 464 => 'PageInfo' }, - 'pagename' => { 113 => 0x11d }, - 'pagenumber' => { 113 => 0x129 }, - 'pageprogressiondirection' => { 456 => 'pageProgressionDirection' }, - 'pagerange' => { 456 => 'pageRange' }, - 'paintbasedcorrectionmasks' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasks'] }, - 'paintbasedcorrections' => { 442 => 'PaintBasedCorrections' }, - 'paintcorrectionactive' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionActive'] }, - 'paintcorrectionamount' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionAmount'] }, - 'paintcorrectionbrightness' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalBrightness'] }, - 'paintcorrectionclarity' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalClarity'] }, - 'paintcorrectionclarity2012' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalClarity2012'] }, - 'paintcorrectioncontrast' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalContrast'] }, - 'paintcorrectioncontrast2012' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalContrast2012'] }, - 'paintcorrectiondefringe' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalDefringe'] }, - 'paintcorrectionexposure' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalExposure'] }, - 'paintcorrectionexposure2012' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalExposure2012'] }, - 'paintcorrectionhighlights2012' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalHighlights2012'] }, - 'paintcorrectionhue' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalToningHue'] }, - 'paintcorrectionluminancenoise' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalLuminanceNoise'] }, - 'paintcorrectionmaskalpha' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksAlpha'] }, - 'paintcorrectionmaskangle' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksAngle'] }, - 'paintcorrectionmaskbottom' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksBottom'] }, - 'paintcorrectionmaskcentervalue' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCenterValue'] }, - 'paintcorrectionmaskcenterweight' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCenterWeight'] }, - 'paintcorrectionmaskdabs' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksDabs'] }, - 'paintcorrectionmaskfeather' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFeather'] }, - 'paintcorrectionmaskflipped' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFlipped'] }, - 'paintcorrectionmaskflow' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFlow'] }, - 'paintcorrectionmaskfullx' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFullX'] }, - 'paintcorrectionmaskfully' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFullY'] }, - 'paintcorrectionmaskleft' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksLeft'] }, - 'paintcorrectionmaskmidpoint' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMidpoint'] }, - 'paintcorrectionmaskperimetervalue' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksPerimeterValue'] }, - 'paintcorrectionmaskradius' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksRadius'] }, - 'paintcorrectionmaskright' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksRight'] }, - 'paintcorrectionmaskroundness' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksRoundness'] }, - 'paintcorrectionmasksizex' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksSizeX'] }, - 'paintcorrectionmasksizey' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksSizeY'] }, - 'paintcorrectionmasktop' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksTop'] }, - 'paintcorrectionmaskvalue' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskValue'] }, - 'paintcorrectionmaskversion' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksVersion'] }, - 'paintcorrectionmaskwhat' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksWhat'] }, - 'paintcorrectionmaskx' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksX'] }, - 'paintcorrectionmasky' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksY'] }, - 'paintcorrectionmaskzerox' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksZeroX'] }, - 'paintcorrectionmaskzeroy' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksZeroY'] }, - 'paintcorrectionmoire' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalMoire'] }, - 'paintcorrectionsaturation' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalSaturation','PaintBasedCorrectionsLocalToningSaturation'] }, - 'paintcorrectionshadows2012' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalShadows2012'] }, - 'paintcorrectionsharpness' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalSharpness'] }, - 'paintcorrectiontemperature' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalTemperature'] }, - 'paintcorrectiontint' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalTint'] }, - 'paintcorrectionwhat' => { 442 => [\'PaintBasedCorrections','PaintBasedCorrectionsWhat'] }, - 'panasonicdatetime' => { 300 => 0x0 }, - 'panasonicexifversion' => { 297 => 0x26 }, - 'panasonicimageheight' => { 297 => 0x4c }, - 'panasonicimagewidth' => { 297 => 0x4b }, - 'panasonicrawversion' => { 302 => 0x1 }, - 'panasonictitle' => { 113 => 0xc6d2 }, - 'panasonictitle2' => { 113 => 0xc6d3 }, - 'panoramaangle' => { 121 => 0x1153 }, - 'panoramacropbottom' => { 394 => 0x7 }, - 'panoramacropleft' => { 394 => 0x4 }, - 'panoramacropright' => { 394 => 0x6 }, - 'panoramacroptop' => { 394 => 0x5 }, - 'panoramadirection' => { 68 => 0x5, 121 => 0x1154, 394 => 0x3 }, - 'panoramaframeheight' => { 394 => 0x9 }, - 'panoramaframenumber' => { 68 => 0x2 }, - 'panoramaframewidth' => { 394 => 0x8 }, - 'panoramafullheight' => { 394 => 0x2 }, - 'panoramafullwidth' => { 394 => 0x1 }, - 'panoramamode' => { 133 => 0x3c, 274 => 0x601 }, - 'panoramasize3d' => { 378 => 0x38 }, - 'panoramasourceheight' => { 394 => 0xb }, - 'panoramasourcewidth' => { 394 => 0xa }, - 'panoramicstitchcameramotion' => { 167 => 'PanoramicStitchCameraMotion', 168 => 0x1 }, - 'panoramicstitchmaptype' => { 167 => 'PanoramicStitchMapType', 168 => 0x2 }, - 'panoramicstitchphi0' => { 167 => 'PanoramicStitchPhi0', 168 => 0x5 }, - 'panoramicstitchphi1' => { 167 => 'PanoramicStitchPhi1', 168 => 0x6 }, - 'panoramicstitchtheta0' => { 167 => 'PanoramicStitchTheta0', 168 => 0x3 }, - 'panoramicstitchtheta1' => { 167 => 'PanoramicStitchTheta1', 168 => 0x4 }, - 'panoramicstitchversion' => { 168 => 0x0 }, - 'pantry' => { 467 => 'Pantry' }, - 'parallax' => { 121 => 0xb211, 273 => 0x28 }, - 'parametricdarks' => { 442 => 'ParametricDarks' }, - 'parametrichighlights' => { 442 => 'ParametricHighlights' }, - 'parametrichighlightsplit' => { 442 => 'ParametricHighlightSplit' }, - 'parametriclights' => { 442 => 'ParametricLights' }, - 'parametricmidtonesplit' => { 442 => 'ParametricMidtoneSplit' }, - 'parametricshadows' => { 442 => 'ParametricShadows' }, - 'parametricshadowsplit' => { 442 => 'ParametricShadowSplit' }, - 'parentmediaeventid' => { 431 => 'ParentMediaEventID' }, - 'parentmeid' => { 431 => 'ParentMEID' }, - 'parentreference1' => { 450 => [\'TagStructure','TagStructureParentReference'] }, - 'parentreference2' => { 450 => [\'TagStructure','TagStructureSubLabelsParentReference'] }, - 'parentreference3' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsParentReference'] }, - 'parentreference4' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsParentReference'] }, - 'parentreference5' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsParentReference'] }, - 'parentreference6' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsSubLabelsParentReference'] }, - 'partialactivecols1' => { 131 => 0x17e8 }, - 'partialactivecols2' => { 131 => 0x17f2 }, - 'partialactiverows1' => { 131 => 0x17fc }, - 'partialactiverows2' => { 131 => 0x1806 }, - 'partofcompilation' => { 466 => 'partOfCompilation' }, - 'patientbirthdate' => { 423 => 'PatientDOB' }, - 'patientid' => { 423 => 'PatientID' }, - 'patientname' => { 423 => 'PatientName' }, - 'patientsex' => { 423 => 'PatientSex' }, - 'patternareaheight' => { 131 => 0x963 }, - 'patternareawidth' => { 131 => 0x962 }, - 'patterncorrectionfactorscale' => { 131 => 0x969 }, - 'patterncropcols1' => { 131 => 0x96c }, - 'patterncropcols2' => { 131 => 0x96d }, - 'patterncroprows1' => { 131 => 0x96a }, - 'patterncroprows2' => { 131 => 0x96b }, - 'patternimagerheight' => { 131 => 0x961 }, - 'patternimagerwidth' => { 131 => 0x960 }, - 'patternx' => { 131 => 0x966 }, - 'patterny' => { 131 => 0x967 }, - 'pdfversion' => { 453 => 'PDFVersion' }, - 'pentaximagesize' => { 332 => 0x9 }, - 'pentaxmodelid' => { 312 => 0x0, 332 => 0x5 }, - 'pentaxmodeltype' => { 332 => 0x1 }, - 'pentaxversion' => { 332 => 0x0 }, - 'people' => { 424 => 'People', 434 => 'People' }, - 'perchannelblacklevel' => { 41 => 0xc4, 42 => [0x2b4,0x2cb,0x2cf], 43 => [0x108,0x14d], 44 => 0x1df, 45 => [0x1f8,0x2d8], 46 => [0x22c,0x30a], 47 => 0x149 }, - 'peripheralillumcentralradius' => { 421 => 0x8030 }, - 'peripheralillumcentralvalue' => { 421 => 0x8031 }, - 'peripheralillumination' => { 97 => 0x20702, 103 => 0x68 }, - 'peripheralilluminationcorr' => { 59 => 0x1, 322 => 0x2 }, - 'peripheralilluminationon' => { 97 => '0x20702.0', 103 => 0x64 }, - 'peripheralillumperiphvalue' => { 421 => 0x8032 }, - 'peripherallighting' => { 74 => 0x2 }, - 'peripherallightingsetting' => { 75 => 0x5 }, - 'peripherallightingvalue' => { 74 => 0x6 }, - 'permissions' => { 459 => 'permissions' }, - 'permits' => { 439 => 'permits' }, - 'person' => { 456 => 'person' }, - 'personality' => { 431 => 'Personality' }, - 'personheard' => { 452 => 'PersonHeard' }, - 'personheardidentifier' => { 452 => [\'PersonHeard','PersonHeardIdentifier'] }, - 'personheardname' => { 452 => [\'PersonHeard','PersonHeardName'] }, - 'personinimage' => { 452 => 'PersonInImage' }, - 'personinimagecharacteristic' => { 452 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonCharacteristic'] }, - 'personinimagecvtermcvid' => { 452 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonCharacteristicCvId'] }, - 'personinimagecvtermid' => { 452 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonCharacteristicCvTermId'] }, - 'personinimagecvtermname' => { 452 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonCharacteristicCvTermName'] }, - 'personinimagecvtermrefinedabout' => { 452 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonCharacteristicCvTermRefinedAbout'] }, - 'personinimagedescription' => { 452 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonDescription'] }, - 'personinimageid' => { 452 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonId'] }, - 'personinimagename' => { 452 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonName'] }, - 'personinimagewdetails' => { 452 => 'PersonInImageWDetails' }, - 'perspectiveaspect' => { 442 => 'PerspectiveAspect' }, - 'perspectivehorizontal' => { 442 => 'PerspectiveHorizontal' }, - 'perspectiverotate' => { 442 => 'PerspectiveRotate' }, - 'perspectivescale' => { 442 => 'PerspectiveScale' }, - 'perspectiveupright' => { 442 => 'PerspectiveUpright' }, - 'perspectivevertical' => { 442 => 'PerspectiveVertical' }, - 'perspectivex' => { 442 => 'PerspectiveX' }, - 'perspectivey' => { 442 => 'PerspectiveY' }, - 'pf0customfuncregistration' => { 86 => 0x1 }, - 'pf10retainprogramshift' => { 86 => 0xb }, - 'pf13drivepriority' => { 86 => 0xe }, - 'pf14disablefocussearch' => { 86 => 0xf }, - 'pf15disableafassistbeam' => { 86 => 0x10 }, - 'pf16autofocuspointshoot' => { 86 => 0x11 }, - 'pf17disableafpointsel' => { 86 => 0x12 }, - 'pf18enableautoafpointsel' => { 86 => 0x13 }, - 'pf19continuousshootspeed' => { 86 => 0x14 }, - 'pf19shootingspeedhigh' => { 85 => 0xa }, - 'pf19shootingspeedlow' => { 85 => 0x9 }, - 'pf1disableshootingmodes' => { 86 => 0x2 }, - 'pf1value' => { 85 => 0x1 }, - 'pf20limitcontinousshots' => { 86 => 0x15 }, - 'pf20maxcontinousshots' => { 85 => 0xb }, - 'pf21enablequietoperation' => { 86 => 0x16 }, - 'pf23felocktime' => { 85 => 0xd }, - 'pf23postreleasetime' => { 85 => 0xe }, - 'pf23settimerlengths' => { 86 => 0x18 }, - 'pf23shutterbuttontime' => { 85 => 0xc }, - 'pf24lightlcdduringbulb' => { 86 => 0x19 }, - 'pf25aemode' => { 85 => 0xf }, - 'pf25afmode' => { 85 => 0x12 }, - 'pf25afpointsel' => { 85 => 0x13 }, - 'pf25colormatrix' => { 85 => 0x17 }, - 'pf25defaultclearsettings' => { 86 => 0x1a }, - 'pf25drivemode' => { 85 => 0x11 }, - 'pf25imagesize' => { 85 => 0x14 }, - 'pf25meteringmode' => { 85 => 0x10 }, - 'pf25parameters' => { 85 => 0x16 }, - 'pf25wbmode' => { 85 => 0x15 }, - 'pf26shortenreleaselag' => { 86 => 0x1b }, - 'pf27reversedialrotation' => { 86 => 0x1c }, - 'pf27value' => { 85 => 0x18 }, - 'pf28noquickdialexpcomp' => { 86 => 0x1d }, - 'pf29quickdialswitchoff' => { 86 => 0x1e }, - 'pf2disablemeteringmodes' => { 86 => 0x3 }, - 'pf2value' => { 85 => 0x2 }, - 'pf30enlargementmode' => { 86 => 0x1f }, - 'pf31originaldecisiondata' => { 86 => 0x20 }, - 'pf3manualexposuremetering' => { 86 => 0x4 }, - 'pf3value' => { 85 => 0x3 }, - 'pf4exposuretimelimits' => { 86 => 0x5 }, - 'pf4exposuretimemax' => { 85 => 0x5 }, - 'pf4exposuretimemin' => { 85 => 0x4 }, - 'pf5aperturelimits' => { 86 => 0x6 }, - 'pf5aperturemax' => { 85 => 0x7 }, - 'pf5aperturemin' => { 85 => 0x6 }, - 'pf6presetshootingmodes' => { 86 => 0x7 }, - 'pf7bracketcontinuousshoot' => { 86 => 0x8 }, - 'pf8bracketshots' => { 85 => 0x8 }, - 'pf8setbracketshots' => { 86 => 0x9 }, - 'pf9changebracketsequence' => { 86 => 0xa }, - 'phasedetectaf' => { 183 => 0x6 }, - 'phonenumber' => { 148 => 'Phone' }, - 'photoeffect' => { 33 => 0x28 }, - 'photoeffecthistoryxml' => { 250 => 0xe9651831 }, - 'photoeffects' => { 250 => 0xab5eca5e }, - 'photoeffectsblue' => { 252 => 0x8 }, - 'photoeffectsgreen' => { 252 => 0x6 }, - 'photoeffectsred' => { 252 => 0x4 }, - 'photoeffectstype' => { 252 => 0x0 }, - 'photographicsensitivity' => { 447 => 'PhotographicSensitivity' }, - 'photoinfoplayback' => { 257 => '17.6', 266 => '33.6' }, - 'photometricinterpretation' => { 113 => 0x106, 462 => 'PhotometricInterpretation' }, - 'photoshootingmenubank' => { 229 => 0xe7d, 238 => 0xfbd }, - 'photoshootingmenubankimagearea' => { 229 => '3716.1', 238 => 0x791 }, - 'photoshopbgrthumbnail' => { 346 => 0x409 }, - 'photoshopquality' => { 345 => 0x0 }, - 'photoshopthumbnail' => { 346 => 0x40c }, - 'photostyle' => { 297 => 0x89 }, - 'picklabel' => { 445 => 'PickLabel' }, - 'pictinfo' => { 367 => 0x208 }, - 'picturecontrol' => { 250 => 0xe2173c47 }, - 'picturecontrolactive' => { 253 => 0x0 }, - 'picturecontroladjust' => { 213 => 0x30, 214 => 0x30 }, - 'picturecontrolbase' => { 213 => 0x18, 214 => 0x18 }, - 'picturecontroldata' => { 211 => [0xbd,0x23] }, - 'picturecontrolmode' => { 253 => 0x13 }, - 'picturecontrolname' => { 213 => 0x4, 214 => 0x4 }, - 'picturecontrolquickadjust' => { 213 => 0x31, 214 => 0x31 }, - 'pictureeffect' => { 388 => 0x200e }, - 'pictureeffect2' => { 396 => 0x1163, 397 => 0x1167, 398 => 0x1143, 399 => 0x11bf, 400 => 0x119b, 401 => 0x1053, 402 => 0x24b, 403 => 0x24b, 404 => 0x23c, 417 => 0x46 }, - 'picturefinish' => { 172 => 0x71 }, - 'picturemode' => { 121 => 0x1031, 274 => 0x520, 332 => [0xb,0x33], 368 => 0x3d }, - 'picturemode2' => { 313 => 0x0 }, - 'picturemodebwfilter' => { 274 => 0x525 }, - 'picturemodecontrast' => { 274 => 0x523 }, - 'picturemodeeffect' => { 274 => 0x52d }, - 'picturemodehue' => { 274 => 0x522 }, - 'picturemodesaturation' => { 274 => 0x521 }, - 'picturemodesharpness' => { 274 => 0x524 }, - 'picturemodetone' => { 274 => 0x526 }, - 'pictureprofile' => { 396 => [0x115e,0x115f], 397 => [0x1162,0x1163], 398 => [0x113e,0x113f], 399 => [0x11ba,0x11bb], 400 => [0x1196,0x1197], 401 => [0x104e,0x104f], 402 => [0x246,0x247], 403 => [0x246,0x247], 404 => [0x237,0x238] }, - 'picturestyle' => { 7 => [0x4b,0x51], 8 => 0xf4, 9 => 0x6c, 10 => 0x86, 11 => 0x73, 15 => 0xab, 16 => 0xa7, 17 => 0xb0, 18 => 0x6c, 19 => 0xa7, 20 => 0xf4, 21 => 0xb3, 23 => 0xf4, 24 => 0xfa, 26 => 0x169, 70 => 0xa, 97 => 0x20301, 103 => 0x2 }, - 'picturewizard' => { 365 => 0x21 }, - 'picturewizardcolor' => { 364 => 0x1 }, - 'picturewizardcontrast' => { 364 => 0x4 }, - 'picturewizardmode' => { 364 => 0x0 }, - 'picturewizardsaturation' => { 364 => 0x2 }, - 'picturewizardsharpness' => { 364 => 0x3 }, - 'pipelineversion' => { 167 => 'PipelineVersion' }, - 'pitch' => { 109 => 0x6, 258 => '4.1', 270 => '4.1' }, - 'pitchangle' => { 228 => 0x350f, 229 => 0x2c28, 237 => 0x36f8, 274 => 0x904, 297 => 0x91, 331 => 0x2, 363 => 0x1 }, - 'pixelclockfrequency' => { 131 => 0x40b }, - 'pixelcorrectionoffset' => { 131 => 0x972 }, - 'pixelcorrectionscale' => { 131 => 0x971 }, - 'pixelshiftinfo' => { 388 => 0x202f }, - 'pixelshiftresolution' => { 333 => 0x0 }, - 'pixelsperunitx' => { 286 => 0x0 }, - 'pixelsperunity' => { 286 => 0x4 }, - 'pixelunits' => { 286 => 0x8 }, - 'planarconfiguration' => { 113 => 0x11c, 462 => 'PlanarConfiguration' }, - 'planningref' => { 452 => 'PlanningRef' }, - 'planningrefidentifier' => { 452 => [\'PlanningRef','PlanningRefIdentifier'] }, - 'planningrefname' => { 452 => [\'PlanningRef','PlanningRefName'] }, - 'planningrefrole' => { 452 => [\'PlanningRef','PlanningRefRole'] }, - 'platenames' => { 471 => 'PlateNames' }, - 'platform' => { 456 => 'platform' }, - 'playbackmenustime' => { 262 => '20.1', 263 => '21.1', 264 => '21.1' }, - 'playbackmonitorofftime' => { 257 => '25.2', 258 => '36.1', 260 => '36.1', 261 => '36.1', 265 => '35.1', 266 => '8.1', 267 => '35.1', 270 => '36.1', 271 => '36.1', 272 => '21.1' }, - 'playbackzoom' => { 258 => '37.1' }, - 'playdisplay' => { 174 => 0x4e }, - 'plusversion' => { 284 => 'Version' }, - 'pmversion' => { 344 => 'PMVersion' }, - 'pngwarning' => { 287 => 'Warning' }, - 'poilevel' => { 210 => 0x8 }, - 'portraitoutputhighlightpoint' => { 103 => 0x1d }, - 'portraitoutputshadowpoint' => { 103 => 0x1e }, - 'portraitrawcolortone' => { 103 => 0x16 }, - 'portraitrawcontrast' => { 103 => 0x18 }, - 'portraitrawhighlight' => { 103 => 0x76 }, - 'portraitrawhighlightpoint' => { 103 => 0x1b }, - 'portraitrawlinear' => { 103 => 0x19 }, - 'portraitrawsaturation' => { 103 => 0x17 }, - 'portraitrawshadow' => { 103 => 0x7f }, - 'portraitrawshadowpoint' => { 103 => 0x1c }, - 'portraitrawsharpness' => { 103 => 0x1a }, - 'portraitrefiner' => { 107 => 0x302b }, - 'portraitunsharpmaskfineness' => { 103 => 0x9a }, - 'portraitunsharpmaskstrength' => { 103 => 0x98 }, - 'portraitunsharpmaskthreshold' => { 103 => 0x9c }, - 'poseheadingdegrees' => { 429 => 'PoseHeadingDegrees' }, - 'posepitchdegrees' => { 429 => 'PosePitchDegrees' }, - 'poserolldegrees' => { 429 => 'PoseRollDegrees' }, - 'positiondescriptor' => { 455 => 'positionDescriptor' }, - 'postalcode' => { 152 => 'PostalCode' }, - 'postcropvignetteamount' => { 442 => 'PostCropVignetteAmount' }, - 'postcropvignettefeather' => { 442 => 'PostCropVignetteFeather' }, - 'postcropvignettehighlightcontrast' => { 442 => 'PostCropVignetteHighlightContrast' }, - 'postcropvignettemidpoint' => { 442 => 'PostCropVignetteMidpoint' }, - 'postcropvignetteroundness' => { 442 => 'PostCropVignetteRoundness' }, - 'postcropvignettestyle' => { 442 => 'PostCropVignetteStyle' }, - 'potentialface1position' => { 386 => 0xb }, - 'potentialface2position' => { 386 => 0x15 }, - 'potentialface3position' => { 386 => 0x1f }, - 'potentialface4position' => { 386 => 0x29 }, - 'potentialface5position' => { 386 => 0x33 }, - 'potentialface6position' => { 386 => 0x3d }, - 'potentialface7position' => { 386 => 0x47 }, - 'potentialface8position' => { 386 => 0x51 }, - 'powersource' => { 311 => '0.1' }, - 'poweruptime' => { 211 => 0xb6 }, - 'precaptureframes' => { 279 => 0x300 }, - 'predictor' => { 113 => 0x13d }, - 'preflashreturnstrength' => { 226 => 0x28a }, - 'prefs' => { 125 => 0xdd, 344 => 'Prefs' }, - 'prereadfastresetcount' => { 131 => 0x187e }, - 'preservedfilename' => { 467 => 'PreservedFileName' }, - 'preservedspecimen' => { 112 => 'PreservedSpecimen' }, - 'preservedspecimenmaterialsampleid' => { 112 => [\'PreservedSpecimen','PreservedSpecimenMaterialSampleID'] }, - 'presetwhitebalance' => { 174 => 0x24, 421 => 0x8002 }, - 'presetwhitebalanceadj' => { 421 => 0x8014 }, - 'pressure' => { 113 => 0x9402, 447 => 'Pressure' }, - 'previewapplicationname' => { 113 => 0xc716 }, - 'previewapplicationversion' => { 113 => 0xc717 }, - 'previewbutton' => { 257 => ['14.1','15.1'], 258 => '15.1', 260 => '15.1', 261 => '15.1', 266 => '29.1', 267 => '14.1', 270 => '15.1', 271 => '15.1' }, - 'previewbuttonplusdials' => { 257 => ['14.2','15.2'], 258 => '15.2', 260 => '43.1', 261 => '43.1', 266 => '31.2', 270 => '43.1', 271 => '43.1' }, - 'previewcolorspace' => { 113 => 0xc71a }, - 'previewcropbottom' => { 343 => 0xef }, - 'previewcropleft' => { 343 => 0xec }, - 'previewcropright' => { 343 => 0xee }, - 'previewcroptop' => { 343 => 0xed }, - 'previewdate' => { 351 => 0x0 }, - 'previewdatetime' => { 113 => 0xc71b }, - 'previewimage' => { 107 => 0x2000, 108 => 'PreviewImage', 114 => 'PreviewImage', 116 => 0x4, 157 => 'data', 176 => 0x81, 279 => 0x280, 295 => 0x300, 388 => 0x2001 }, - 'previewimageborders' => { 332 => 0x3e }, - 'previewimageheight' => { 69 => 0x4, 135 => 0xfa58 }, - 'previewimagelength' => { 69 => 0x2, 107 => 0x3, 113 => [0x117,0x202], 176 => 0x89, 215 => 0x202, 274 => 0x102, 279 => 0x1037, 332 => 0x3, 357 => 0x1e, 362 => 0x3, 368 => [0x1b,0x1d], 379 => 0x202 }, - 'previewimagename' => { 157 => '1Name' }, - 'previewimagesize' => { 107 => 0x2, 140 => 0x2, 157 => 'ImageSize', 332 => 0x2, 368 => [0x1c,0x1e], 388 => 0xb02c, 421 => 0x9012 }, - 'previewimagestart' => { 69 => 0x5, 107 => 0x4, 113 => [0x111,0x201], 176 => 0x88, 215 => 0x201, 274 => 0x101, 279 => 0x1036, 332 => 0x4, 357 => 0x1c, 362 => 0x2, 368 => [0x1a,0x1c], 379 => 0x201 }, - 'previewimagetype' => { 157 => '0Type' }, - 'previewimagevalid' => { 274 => 0x100, 279 => 0x1035 }, - 'previewimagewidth' => { 69 => 0x3, 135 => 0xfa57 }, - 'previewquality' => { 69 => 0x1 }, - 'previewsettingsdigest' => { 113 => 0xc719 }, - 'previewsettingsname' => { 113 => 0xc718 }, - 'primaryafpoint' => { 183 => [0x44,0x7] }, - 'primarychromaticities' => { 113 => 0x13f, 462 => 'PrimaryChromaticities' }, - 'primaryftp' => { 431 => 'PrimaryFTP' }, - 'primaryslot' => { 229 => 0xe7f, 238 => 0xfbf }, - 'printim' => { 113 => 0xc4a5 }, - 'prioritysetinawb' => { 388 => 0x202b }, - 'prioritysetupshutterrelease' => { 174 => 0x1d, 376 => 0x28 }, - 'privatertkinfo' => { 433 => 'privateRTKInfo' }, - 'processbordercolsleft' => { 131 => 0xc61 }, - 'processbordercolsright' => { 131 => 0xc62 }, - 'processborderrowsbottom' => { 131 => 0xc64 }, - 'processborderrowstop' => { 131 => 0xc63 }, - 'processingsoftware' => { 113 => 0xb }, - 'processversion' => { 442 => 'ProcessVersion' }, - 'producer' => { 283 => 'Producer', 453 => 'Producer' }, - 'productcode' => { 456 => 'productCode' }, - 'productid' => { 126 => 0x32, 455 => 'productID' }, - 'productidtype' => { 455 => 'productIDType' }, - 'productinimage' => { 452 => 'ProductInImage' }, - 'productinimagedescription' => { 452 => [\'ProductInImage','ProductInImageProductDescription'] }, - 'productinimagegtin' => { 452 => [\'ProductInImage','ProductInImageProductGTIN'] }, - 'productinimagename' => { 452 => [\'ProductInImage','ProductInImageProductName'] }, - 'productioncode' => { 312 => 0x2 }, - 'productorserviceconstraints' => { 284 => 'ProductOrServiceConstraints' }, - 'profession' => { 456 => 'profession' }, - 'profilecalibrationsig' => { 113 => 0xc6f4 }, - 'profilecopyright' => { 113 => 0xc6fe }, - 'profileembedpolicy' => { 113 => 0xc6fd }, - 'profilehuesatmapdata1' => { 113 => 0xc6fa }, - 'profilehuesatmapdata2' => { 113 => 0xc6fb }, - 'profilehuesatmapdims' => { 113 => 0xc6f9 }, - 'profilehuesatmapencoding' => { 113 => 0xc7a3 }, - 'profilelooktabledata' => { 113 => 0xc726 }, - 'profilelooktabledims' => { 113 => 0xc725 }, - 'profilelooktableencoding' => { 113 => 0xc7a4 }, - 'profilename' => { 113 => 0xc6f8 }, - 'profiletonecurve' => { 113 => 0xc6fc }, - 'programiso' => { 297 => 0x3c }, - 'programline' => { 313 => '1.1' }, - 'programmode' => { 179 => 0x5 }, - 'programshift' => { 211 => 0xd }, - 'programversion' => { 125 => 0x46 }, - 'prohibits' => { 439 => 'prohibits' }, - 'projectiontype' => { 429 => 'ProjectionType', 430 => 'ProjectionType' }, - 'projectname' => { 466 => 'projectName' }, - 'projectref' => { 466 => 'projectRef' }, - 'projectrefpath' => { 466 => [\'projectRef','projectRefPath'] }, - 'projectreftype' => { 466 => [\'projectRef','projectRefType'] }, - 'propertyreleaseid' => { 284 => 'PropertyReleaseID' }, - 'propertyreleasestatus' => { 284 => 'PropertyReleaseStatus' }, - 'province-state' => { 125 => 0x5f }, - 'publicationdate' => { 456 => 'publicationDate' }, - 'publicationdatea-platform' => { 456 => [\'publicationDate','publicationDateA-platform'] }, - 'publicationdatedate' => { 456 => [\'publicationDate','publicationDateDate'] }, - 'publicationdisplaydate' => { 456 => 'publicationDisplayDate' }, - 'publicationdisplaydatea-platform' => { 456 => [\'publicationDisplayDate','publicationDisplayDateA-platform'] }, - 'publicationdisplaydatedate' => { 456 => [\'publicationDisplayDate','publicationDisplayDateDate'] }, - 'publicationevent' => { 452 => 'PublicationEvent' }, - 'publicationeventdate' => { 452 => [\'PublicationEvent','PublicationEventDate'] }, - 'publicationeventidentifier' => { 452 => [\'PublicationEvent','PublicationEventIdentifier'] }, - 'publicationeventname' => { 452 => [\'PublicationEvent','PublicationEventName'] }, - 'publicationname' => { 456 => 'publicationName' }, - 'publisher' => { 443 => 'publisher' }, - 'publishingfrequency' => { 456 => 'publishingFrequency' }, - 'pulldown' => { 466 => 'pullDown' }, - 'purplehsl' => { 97 => 0x20916 }, - 'pxshiftperiphedgenr' => { 421 => 0x9013 }, - 'pxshiftperiphedgenrvalue' => { 421 => 0x9014 }, - 'quality' => { 0 => 0x1, 33 => 0x3, 106 => 0x2, 107 => 0x3002, 121 => 0x1000, 133 => 0x9, 211 => 0x4, 240 => 0x3, 279 => 0x201, 292 => 0x300, 332 => 0x8, 339 => 0x2, 368 => 0x16, 376 => 0x56, 377 => 0x56, 378 => 0xb, 388 => [0x102,0x202e] }, - 'quality2' => { 396 => 0x1170, 397 => 0x1174, 398 => 0x1150, 400 => 0x11a8, 401 => 0x1060, 402 => 0x258, 403 => 0x258, 404 => 0x247, 408 => 0x29, 409 => 0x25, 410 => 0x2a }, - 'qualitymode' => { 107 => 0x8 }, - 'quantizationmethod' => { 127 => 0x78 }, - 'quickadjust' => { 253 => 0x2a }, - 'quickcontroldialinmeter' => { 78 => 0x703 }, - 'quickfix' => { 250 => 0x416391c6 }, - 'quickshot' => { 367 => 0x213 }, - 'quiettime' => { 131 => 0x188a }, - 'rangefinder' => { 262 => '4.1', 263 => '5.1', 264 => '5.1' }, - 'rasterizedcaption' => { 125 => 0x7d }, - 'rating' => { 113 => 0x4746, 121 => 0x1431, 343 => 0xdf, 388 => 0x2002, 436 => 'rating', 444 => 'rating', 452 => 'Rating', 456 => 'rating', 464 => 'Rating' }, - 'ratingpercent' => { 113 => 0x4749, 169 => 'Rating' }, - 'ratingratingregion' => { 452 => [\'Rating','RatingRatingRegion'] }, - 'ratingregioncity' => { 452 => [\'Rating','RatingRatingRegionCity'] }, - 'ratingregioncountrycode' => { 452 => [\'Rating','RatingRatingRegionCountryCode'] }, - 'ratingregioncountryname' => { 452 => [\'Rating','RatingRatingRegionCountryName'] }, - 'ratingregiongpsaltitude' => { 452 => [\'Rating','RatingRatingRegionGPSAltitude'] }, - 'ratingregiongpslatitude' => { 452 => [\'Rating','RatingRatingRegionGPSLatitude'] }, - 'ratingregiongpslongitude' => { 452 => [\'Rating','RatingRatingRegionGPSLongitude'] }, - 'ratingregionidentifier' => { 452 => [\'Rating','RatingRatingRegionIdentifier'] }, - 'ratingregionlocationid' => { 452 => [\'Rating','RatingRatingRegionLocationId'] }, - 'ratingregionlocationname' => { 452 => [\'Rating','RatingRatingRegionLocationName'] }, - 'ratingregionprovincestate' => { 452 => [\'Rating','RatingRatingRegionProvinceState'] }, - 'ratingregionsublocation' => { 452 => [\'Rating','RatingRatingRegionSublocation'] }, - 'ratingregionworldregion' => { 452 => [\'Rating','RatingRatingRegionWorldRegion'] }, - 'ratingscalemaxvalue' => { 452 => [\'Rating','RatingRatingScaleMaxValue'] }, - 'ratingscaleminvalue' => { 452 => [\'Rating','RatingRatingScaleMinValue'] }, - 'ratingsourcelink' => { 452 => [\'Rating','RatingRatingSourceLink'] }, - 'ratingvalue' => { 452 => [\'Rating','RatingRatingValue'] }, - 'ratingvaluelogolink' => { 452 => [\'Rating','RatingRatingValueLogoLink'] }, - 'rawandjpgrecording' => { 76 => 0x8, 176 => 0x109, 313 => 0xd }, - 'rawbrightnessadj' => { 97 => 0x20001, 102 => 0x38 }, - 'rawcoloradj' => { 102 => 0x2e }, - 'rawcropbottom' => { 343 => 0xd4 }, - 'rawcropleft' => { 343 => 0xd1 }, - 'rawcropright' => { 343 => 0xd3 }, - 'rawcroptop' => { 343 => 0xd2 }, - 'rawcustomsaturation' => { 102 => 0x30 }, - 'rawcustomtone' => { 102 => 0x34 }, - 'rawdata' => { 365 => 0xa048 }, - 'rawdatabyteorder' => { 365 => 0x40 }, - 'rawdatacfapattern' => { 365 => 0x50 }, - 'rawdatauniqueid' => { 113 => 0xc65d }, - 'rawdepth' => { 178 => 0x10 }, - 'rawdevartfilter' => { 281 => 0x121 }, - 'rawdevautogradation' => { 281 => 0x119 }, - 'rawdevcolorspace' => { 280 => 0x108, 281 => 0x109 }, - 'rawdevcontrastvalue' => { 280 => 0x106, 281 => 0x105 }, - 'rawdeveditstatus' => { 280 => 0x10b }, - 'rawdevelopmentprocess' => { 332 => 0x62 }, - 'rawdevengine' => { 280 => 0x109, 281 => 0x10b }, - 'rawdevexposurebiasvalue' => { 280 => 0x100, 281 => 0x100 }, - 'rawdevgradation' => { 281 => 0x112 }, - 'rawdevgraypoint' => { 280 => 0x103, 281 => 0x104 }, - 'rawdevmemorycoloremphasis' => { 280 => 0x105, 281 => 0x108 }, - 'rawdevnoisereduction' => { 280 => 0x10a, 281 => 0x10a }, - 'rawdevpicturemode' => { 281 => 0x10c }, - 'rawdevpm_bwfilter' => { 281 => 0x110 }, - 'rawdevpmcontrast' => { 281 => 0x10e }, - 'rawdevpmnoisefilter' => { 281 => 0x120 }, - 'rawdevpmpicturetone' => { 281 => 0x111 }, - 'rawdevpmsaturation' => { 281 => 0x10d }, - 'rawdevpmsharpness' => { 281 => 0x10f }, - 'rawdevsaturation3' => { 281 => 0x113 }, - 'rawdevsaturationemphasis' => { 280 => 0x104, 281 => 0x107 }, - 'rawdevsettings' => { 280 => 0x10c }, - 'rawdevsharpnessvalue' => { 280 => 0x107, 281 => 0x106 }, - 'rawdevversion' => { 280 => 0x0, 281 => 0x0 }, - 'rawdevwbfineadjustment' => { 280 => 0x102, 281 => 0x103 }, - 'rawdevwhitebalance' => { 281 => 0x101 }, - 'rawdevwhitebalancevalue' => { 280 => 0x101, 281 => 0x102 }, - 'rawfile' => { 113 => 0xfe4c }, - 'rawfilename' => { 442 => 'RawFileName' }, - 'rawfiletype' => { 388 => 0x2029 }, - 'rawformat' => { 302 => 0x2d, 341 => 0x10e }, - 'rawimagecenter' => { 211 => 0x99 }, - 'rawimagedigest' => { 113 => 0xc71c }, - 'rawimagesize' => { 332 => 0x39 }, - 'rawinfoversion' => { 282 => 0x0 }, - 'rawjpgheight' => { 93 => 0x4 }, - 'rawjpgquality' => { 54 => 0x6, 93 => 0x1 }, - 'rawjpgsize' => { 54 => 0x7, 93 => 0x2 }, - 'rawjpgwidth' => { 93 => 0x3 }, - 'rawmeasuredrggb' => { 40 => 0x26a, 42 => 0x280, 44 => 0x194, 45 => [0x1ad,0x26b] }, - 'rawrppused' => { 436 => 'rawrppused' }, - 'rawtopreviewgain' => { 113 => 0xc7a8 }, - 'readouttypeactual' => { 131 => 0x1903 }, - 'readouttyperequested' => { 131 => 0x1902 }, - 'reardisplay' => { 257 => '12.3', 258 => '6.2' }, - 'recdevice' => { 452 => 'RecDevice' }, - 'recdeviceattlensdescription' => { 452 => [\'RecDevice','RecDeviceAttLensDescription'] }, - 'recdevicemanufacturer' => { 452 => [\'RecDevice','RecDeviceManufacturer'] }, - 'recdevicemodelname' => { 452 => [\'RecDevice','RecDeviceModelName'] }, - 'recdeviceownersdeviceid' => { 452 => [\'RecDevice','RecDeviceOwnersDeviceId'] }, - 'recdeviceserialnumber' => { 452 => [\'RecDevice','RecDeviceSerialNumber'] }, - 'recipeendingpage' => { 458 => 'recipeEndingPage' }, - 'recipepagerange' => { 458 => 'recipePageRange' }, - 'recipesource' => { 458 => 'recipeSource' }, - 'recipestartingpage' => { 458 => 'recipeStartingPage' }, - 'recipetitle' => { 458 => 'recipeTitle' }, - 'recognizedface1age' => { 290 => 0x20 }, - 'recognizedface1name' => { 290 => 0x4 }, - 'recognizedface1position' => { 290 => 0x18 }, - 'recognizedface2age' => { 290 => 0x50 }, - 'recognizedface2name' => { 290 => 0x34 }, - 'recognizedface2position' => { 290 => 0x48 }, - 'recognizedface3age' => { 290 => 0x80 }, - 'recognizedface3name' => { 290 => 0x64 }, - 'recognizedface3position' => { 290 => 0x78 }, - 'recognizedfaceflags' => { 297 => 0x63 }, - 'recommendedexposureindex' => { 113 => 0x8832, 447 => 'RecommendedExposureIndex' }, - 'record' => { 112 => 'Record' }, - 'recordbasisofrecord' => { 112 => [\'Record','RecordBasisOfRecord'] }, - 'recordcollectioncode' => { 112 => [\'Record','RecordCollectionCode'] }, - 'recordcollectionid' => { 112 => [\'Record','RecordCollectionID'] }, - 'recorddatageneralizations' => { 112 => [\'Record','RecordDataGeneralizations'] }, - 'recorddatasetid' => { 112 => [\'Record','RecordDatasetID'] }, - 'recorddatasetname' => { 112 => [\'Record','RecordDatasetName'] }, - 'recorddisplay' => { 174 => 0x4d }, - 'recorddynamicproperties' => { 112 => [\'Record','RecordDynamicProperties'] }, - 'recordid' => { 91 => 0x1804 }, - 'recordinformationwithheld' => { 112 => [\'Record','RecordInformationWithheld'] }, - 'recordingformat' => { 358 => 0x1000 }, - 'recordingmode' => { 106 => 0x1, 339 => 0x1 }, - 'recordinstitutioncode' => { 112 => [\'Record','RecordInstitutionCode'] }, - 'recordinstitutionid' => { 112 => [\'Record','RecordInstitutionID'] }, - 'recordmode' => { 33 => 0x9, 107 => 0x3000 }, - 'recordownerinstitutioncode' => { 112 => [\'Record','RecordOwnerInstitutionCode'] }, - 'recordshutterrelease' => { 367 => 0x217 }, - 'redbalance' => { 279 => 0x1017, 302 => 0x11, 332 => 0x1c }, - 'redcurvelimits' => { 102 => 0x18a }, - 'redcurvepoints' => { 101 => 0x2d, 102 => 0x160 }, - 'redeyecorrection' => { 254 => 0x0 }, - 'redeyeinfo' => { 442 => 'RedEyeInfo' }, - 'redeyereduction' => { 174 => 0x41, 376 => 0x6a, 378 => 0x28 }, - 'redeyeremoval' => { 297 => 0xb9 }, - 'redhsl' => { 97 => 0x20910 }, - 'redhue' => { 442 => 'RedHue' }, - 'redsaturation' => { 442 => 'RedSaturation' }, - 'reductionmatrix1' => { 113 => 0xc625 }, - 'reductionmatrix2' => { 113 => 0xc626 }, - 'reelname' => { 113 => 0xc789 }, - 'reference1' => { 450 => [\'TagStructure','TagStructureReference'] }, - 'reference2' => { 450 => [\'TagStructure','TagStructureSubLabelsReference'] }, - 'reference3' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsReference'] }, - 'reference4' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsReference'] }, - 'reference5' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsReference'] }, - 'reference6' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsSubLabelsReference'] }, - 'referenceblackwhite' => { 113 => 0x214, 462 => 'ReferenceBlackWhite' }, - 'referencedate' => { 125 => 0x2f }, - 'referencenumber' => { 125 => 0x32 }, - 'references' => { 148 => 'References' }, - 'referenceservice' => { 125 => 0x2d }, - 'regionappliedtodimensions' => { 163 => [\'Regions','RegionsAppliedToDimensions'] }, - 'regionappliedtodimensionsh' => { 163 => [\'Regions','RegionsAppliedToDimensionsH'] }, - 'regionappliedtodimensionsunit' => { 163 => [\'Regions','RegionsAppliedToDimensionsUnit'] }, - 'regionappliedtodimensionsw' => { 163 => [\'Regions','RegionsAppliedToDimensionsW'] }, - 'regionarea' => { 163 => [\'Regions','RegionsRegionListArea'] }, - 'regionaread' => { 163 => [\'Regions','RegionsRegionListAreaD'] }, - 'regionareah' => { 163 => [\'Regions','RegionsRegionListAreaH'] }, - 'regionareaunit' => { 163 => [\'Regions','RegionsRegionListAreaUnit'] }, - 'regionareaw' => { 163 => [\'Regions','RegionsRegionListAreaW'] }, - 'regionareax' => { 163 => [\'Regions','RegionsRegionListAreaX'] }, - 'regionareay' => { 163 => [\'Regions','RegionsRegionListAreaY'] }, - 'regionbarcodevalue' => { 163 => [\'Regions','RegionsRegionListBarCodeValue'] }, - 'regionconstraints' => { 284 => 'RegionConstraints' }, - 'regiondescription' => { 163 => [\'Regions','RegionsRegionListDescription'] }, - 'regionextensions' => { 163 => [\'Regions','RegionsRegionListExtensions'] }, - 'regionfocususage' => { 163 => [\'Regions','RegionsRegionListFocusUsage'] }, - 'regioninfo' => { 163 => 'Regions' }, - 'regioninfodateregionsvalid' => { 166 => [\'RegionInfo','RegionInfoDateRegionsValid'] }, - 'regioninfomp' => { 166 => 'RegionInfo' }, - 'regioninforegions' => { 166 => [\'RegionInfo','RegionInfoRegions'] }, - 'regionlist' => { 163 => [\'Regions','RegionsRegionList'] }, - 'regionname' => { 163 => [\'Regions','RegionsRegionListName'] }, - 'regionpersondisplayname' => { 166 => [\'RegionInfo','RegionInfoRegionsPersonDisplayName'] }, - 'regionpersonemaildigest' => { 166 => [\'RegionInfo','RegionInfoRegionsPersonEmailDigest'] }, - 'regionpersonliveidcid' => { 166 => [\'RegionInfo','RegionInfoRegionsPersonLiveIdCID'] }, - 'regionpersonsourceid' => { 166 => [\'RegionInfo','RegionInfoRegionsPersonSourceID'] }, - 'regionrectangle' => { 166 => [\'RegionInfo','RegionInfoRegionsRectangle'] }, - 'regionrotation' => { 163 => [\'Regions','RegionsRegionListRotation'] }, - 'regionseealso' => { 163 => [\'Regions','RegionsRegionListSeeAlso'] }, - 'regiontype' => { 163 => [\'Regions','RegionsRegionListType'] }, - 'registryentryrole' => { 452 => [\'RegistryId','RegistryIdRegEntryRole'] }, - 'registryid' => { 452 => 'RegistryId' }, - 'registryitemid' => { 452 => [\'RegistryId','RegistryIdRegItemId'] }, - 'registryorganisationid' => { 452 => [\'RegistryId','RegistryIdRegOrgId'] }, - 'relatedaudiofile' => { 146 => 'data' }, - 'relatedaudiofilename' => { 146 => '1Name' }, - 'relatedaudiofiletype' => { 146 => '0Type' }, - 'relatedimagefileformat' => { 113 => 0x1000 }, - 'relatedimageheight' => { 113 => 0x1002 }, - 'relatedimagewidth' => { 113 => 0x1001 }, - 'relatedresourceid' => { 112 => [\'ResourceRelationship','ResourceRelationshipRelatedResourceID'] }, - 'relatedsoundfile' => { 113 => 0xa004, 446 => 'RelatedSoundFile' }, - 'relatedvideofile' => { 160 => 'data' }, - 'relatedvideofilename' => { 160 => '1Name' }, - 'relatedvideofiletype' => { 160 => '0Type' }, - 'relation' => { 443 => 'relation' }, - 'relationshipaccordingto' => { 112 => [\'ResourceRelationship','ResourceRelationshipRelationshipAccordingTo'] }, - 'relationshipestablisheddate' => { 112 => [\'ResourceRelationship','ResourceRelationshipRelationshipEstablishedDate'] }, - 'relationshipofresource' => { 112 => [\'ResourceRelationship','ResourceRelationshipRelationshipOfResource'] }, - 'relationshipremarks' => { 112 => [\'ResourceRelationship','ResourceRelationshipRelationshipRemarks'] }, - 'relativealtitude' => { 110 => 'RelativeAltitude' }, - 'relativepeakaudiofilepath' => { 466 => 'relativePeakAudioFilePath' }, - 'relativetimestamp' => { 466 => 'relativeTimestamp' }, - 'relativetimestampscale' => { 466 => [\'relativeTimestamp','relativeTimestampScale'] }, - 'relativetimestampvalue' => { 466 => [\'relativeTimestamp','relativeTimestampValue'] }, - 'releasebuttontousedial' => { 257 => '17.8', 258 => '18.5', 260 => '18.4', 261 => '18.4', 266 => '33.8', 267 => '17.6', 270 => '18.5', 271 => '18.4' }, - 'releasedate' => { 125 => 0x1e, 436 => 'ReleaseDate', 466 => 'releaseDate' }, - 'releasemode' => { 107 => 0x3001, 228 => 0x184d, 388 => 0xb049 }, - 'releasemode2' => { 396 => 0x112c, 397 => [0x112c,0x8], 398 => [0x1108,0x8], 399 => [0x1184,0x8], 400 => [0x1160,0x8], 401 => [0x4,0x1018], 402 => [0x4,0x210], 403 => [0x4,0x210], 404 => [0x4,0x208], 406 => [0x67,0x3f], 407 => [0x73,0x4b], 408 => 0x10, 409 => 0x10, 410 => 0x9, 417 => 0x34 }, - 'releasemode3' => { 396 => 0x1128, 397 => 0x1128, 398 => 0x1104, 399 => 0x1180, 400 => 0x115c, 401 => 0x1014, 402 => 0x20c, 403 => 0x20c, 404 => 0x204 }, - 'releaseready' => { 452 => 'ReleaseReady' }, - 'releasesetting' => { 91 => 0x1016 }, - 'releasetime' => { 125 => 0x23, 436 => 'ReleaseTime' }, - 'remoteonduration' => { 259 => '3.4', 262 => '17.2', 263 => '18.2', 264 => '18.2', 265 => '18.2', 267 => '18.2', 268 => '4.3', 272 => '19.2' }, - 'renditionclass' => { 467 => 'RenditionClass' }, - 'renditionof' => { 467 => 'RenditionOf' }, - 'renditionofalternatepaths' => { 467 => [\'RenditionOf','RenditionOfAlternatePaths'] }, - 'renditionofdocumentid' => { 467 => [\'RenditionOf','RenditionOfDocumentID'] }, - 'renditionoffilepath' => { 467 => [\'RenditionOf','RenditionOfFilePath'] }, - 'renditionoffrompart' => { 467 => [\'RenditionOf','RenditionOfFromPart'] }, - 'renditionofinstanceid' => { 467 => [\'RenditionOf','RenditionOfInstanceID'] }, - 'renditionoflastmodifydate' => { 467 => [\'RenditionOf','RenditionOfLastModifyDate'] }, - 'renditionoflasturl' => { 467 => [\'RenditionOf','RenditionOfLastURL'] }, - 'renditionoflinkcategory' => { 467 => [\'RenditionOf','RenditionOfLinkCategory'] }, - 'renditionoflinkform' => { 467 => [\'RenditionOf','RenditionOfLinkForm'] }, - 'renditionofmanager' => { 467 => [\'RenditionOf','RenditionOfManager'] }, - 'renditionofmanagervariant' => { 467 => [\'RenditionOf','RenditionOfManagerVariant'] }, - 'renditionofmanageto' => { 467 => [\'RenditionOf','RenditionOfManageTo'] }, - 'renditionofmanageui' => { 467 => [\'RenditionOf','RenditionOfManageUI'] }, - 'renditionofmaskmarkers' => { 467 => [\'RenditionOf','RenditionOfMaskMarkers'] }, - 'renditionoforiginaldocumentid' => { 467 => [\'RenditionOf','RenditionOfOriginalDocumentID'] }, - 'renditionofpartmapping' => { 467 => [\'RenditionOf','RenditionOfPartMapping'] }, - 'renditionofplacedresolutionunit' => { 467 => [\'RenditionOf','RenditionOfPlacedResolutionUnit'] }, - 'renditionofplacedxresolution' => { 467 => [\'RenditionOf','RenditionOfPlacedXResolution'] }, - 'renditionofplacedyresolution' => { 467 => [\'RenditionOf','RenditionOfPlacedYResolution'] }, - 'renditionofrenditionclass' => { 467 => [\'RenditionOf','RenditionOfRenditionClass'] }, - 'renditionofrenditionparams' => { 467 => [\'RenditionOf','RenditionOfRenditionParams'] }, - 'renditionoftopart' => { 467 => [\'RenditionOf','RenditionOfToPart'] }, - 'renditionofversionid' => { 467 => [\'RenditionOf','RenditionOfVersionID'] }, - 'renditionparams' => { 467 => 'RenditionParams' }, - 'repeatingflashcount' => { 198 => 0xd, 199 => 0xe, 200 => 0xe, 201 => 0xe, 202 => 0xe, 266 => '17.2', 267 => '24.2', 268 => '9.2', 269 => '24.2', 272 => '25.2' }, - 'repeatingflashcountbuilt-in' => { 236 => 0x4db }, - 'repeatingflashcountexternal' => { 236 => 0x4c3 }, - 'repeatingflashoutput' => { 266 => '17.1', 267 => '24.1', 268 => '9.1', 269 => '24.1', 272 => '25.1' }, - 'repeatingflashoutputexternal' => { 236 => 0x4c0 }, - 'repeatingflashrate' => { 198 => 0xc, 199 => 0xd, 200 => 0xd, 201 => 0xd, 202 => 0xd, 266 => '18.1', 267 => '25.1', 268 => '10.1', 269 => '25.1', 272 => '26.1' }, - 'repeatingflashratebuilt-in' => { 236 => 0x4da }, - 'repeatingflashrateexternal' => { 236 => 0x4c2 }, - 'requires' => { 439 => 'requires' }, - 'resampleparams' => { 466 => 'resampleParams' }, - 'resampleparamsquality' => { 466 => [\'resampleParams','resampleParamsQuality'] }, - 'resamplingkerneldenominators050' => { 131 => 0xe50 }, - 'resamplingkerneldenominators067' => { 131 => 0xe4f }, - 'resamplingkerneldenominators100' => { 131 => 0xe51 }, - 'resaved' => { 367 => 0x21e }, - 'resetblacksegrows' => { 131 => 0x181a }, - 'resolution' => { 153 => 'Resolution' }, - 'resolutionmode' => { 368 => 0x4 }, - 'resolutionunit' => { 113 => 0x128, 128 => 0x2, 462 => 'ResolutionUnit' }, - 'resourceid' => { 112 => [\'ResourceRelationship','ResourceRelationshipResourceID'] }, - 'resourcerelationship' => { 112 => 'ResourceRelationship' }, - 'resourcerelationshipid' => { 112 => [\'ResourceRelationship','ResourceRelationshipResourceRelationshipID'] }, - 'restrictdrivemodes' => { 78 => 0x612 }, - 'restrictions' => { 459 => 'restrictions' }, - 'retouchareafeather' => { 442 => [\'RetouchAreas','RetouchAreasFeather'] }, - 'retouchareamaskalpha' => { 442 => [\'RetouchAreas','RetouchAreasMasksAlpha'] }, - 'retouchareamaskangle' => { 442 => [\'RetouchAreas','RetouchAreasMasksAngle'] }, - 'retouchareamaskbottom' => { 442 => [\'RetouchAreas','RetouchAreasMasksBottom'] }, - 'retouchareamaskcentervalue' => { 442 => [\'RetouchAreas','RetouchAreasMasksCenterValue'] }, - 'retouchareamaskcenterweight' => { 442 => [\'RetouchAreas','RetouchAreasMasksCenterWeight'] }, - 'retouchareamaskdabs' => { 442 => [\'RetouchAreas','RetouchAreasMasksDabs'] }, - 'retouchareamaskfeather' => { 442 => [\'RetouchAreas','RetouchAreasMasksFeather'] }, - 'retouchareamaskflipped' => { 442 => [\'RetouchAreas','RetouchAreasMasksFlipped'] }, - 'retouchareamaskflow' => { 442 => [\'RetouchAreas','RetouchAreasMasksFlow'] }, - 'retouchareamaskfullx' => { 442 => [\'RetouchAreas','RetouchAreasMasksFullX'] }, - 'retouchareamaskfully' => { 442 => [\'RetouchAreas','RetouchAreasMasksFullY'] }, - 'retouchareamaskleft' => { 442 => [\'RetouchAreas','RetouchAreasMasksLeft'] }, - 'retouchareamaskmidpoint' => { 442 => [\'RetouchAreas','RetouchAreasMasksMidpoint'] }, - 'retouchareamaskperimetervalue' => { 442 => [\'RetouchAreas','RetouchAreasMasksPerimeterValue'] }, - 'retouchareamaskradius' => { 442 => [\'RetouchAreas','RetouchAreasMasksRadius'] }, - 'retouchareamaskright' => { 442 => [\'RetouchAreas','RetouchAreasMasksRight'] }, - 'retouchareamaskroundness' => { 442 => [\'RetouchAreas','RetouchAreasMasksRoundness'] }, - 'retouchareamasks' => { 442 => [\'RetouchAreas','RetouchAreasMasks'] }, - 'retouchareamasksizex' => { 442 => [\'RetouchAreas','RetouchAreasMasksSizeX'] }, - 'retouchareamasksizey' => { 442 => [\'RetouchAreas','RetouchAreasMasksSizeY'] }, - 'retouchareamasktop' => { 442 => [\'RetouchAreas','RetouchAreasMasksTop'] }, - 'retouchareamaskvalue' => { 442 => [\'RetouchAreas','RetouchAreasMasksMaskValue'] }, - 'retouchareamaskversion' => { 442 => [\'RetouchAreas','RetouchAreasMasksVersion'] }, - 'retouchareamaskwhat' => { 442 => [\'RetouchAreas','RetouchAreasMasksWhat'] }, - 'retouchareamaskx' => { 442 => [\'RetouchAreas','RetouchAreasMasksX'] }, - 'retouchareamasky' => { 442 => [\'RetouchAreas','RetouchAreasMasksY'] }, - 'retouchareamaskzerox' => { 442 => [\'RetouchAreas','RetouchAreasMasksZeroX'] }, - 'retouchareamaskzeroy' => { 442 => [\'RetouchAreas','RetouchAreasMasksZeroY'] }, - 'retouchareamethod' => { 442 => [\'RetouchAreas','RetouchAreasMethod'] }, - 'retouchareaoffsety' => { 442 => [\'RetouchAreas','RetouchAreasOffsetY'] }, - 'retouchareaopacity' => { 442 => [\'RetouchAreas','RetouchAreasOpacity'] }, - 'retouchareas' => { 442 => 'RetouchAreas' }, - 'retouchareaseed' => { 442 => [\'RetouchAreas','RetouchAreasSeed'] }, - 'retouchareasourcestate' => { 442 => [\'RetouchAreas','RetouchAreasSourceState'] }, - 'retouchareasourcex' => { 442 => [\'RetouchAreas','RetouchAreasSourceX'] }, - 'retouchareaspottype' => { 442 => [\'RetouchAreas','RetouchAreasSpotType'] }, - 'retouchhistory' => { 211 => 0x9e }, - 'retouchinfo' => { 442 => 'RetouchInfo' }, - 'retouchnefprocessing' => { 217 => 0x5 }, - 'retractlensonpoweroff' => { 78 => 0x814 }, - 'reuse' => { 284 => 'Reuse' }, - 'reuseallowed' => { 469 => 'ReuseAllowed' }, - 'reuseprohibited' => { 459 => 'reuseProhibited' }, - 'reverseexposurecompdial' => { 264 => '5.2' }, - 'reverseindicators' => { 257 => '12.1', 258 => '6.1', 260 => '6.1', 261 => '6.1', 262 => '4.3', 263 => '5.2', 264 => '5.4', 266 => '33.5', 267 => '5.1', 270 => '6.1', 271 => '6.1', 272 => '6.2' }, - 'reverseshutterspeedaperture' => { 264 => '5.3' }, - 'revision' => { 444 => 'revision' }, - 'rflensmffocusringsensitivity' => { 78 => 0x714 }, - 'rgbcurvelimits' => { 102 => 0x238 }, - 'rgbcurvepoints' => { 101 => 0x7, 102 => 0x20e }, - 'richtextcomment' => { 449 => 'RichTextComment' }, - 'ricohdate' => { 357 => 0x6 }, - 'ricohimageheight' => { 357 => 0x2 }, - 'ricohimagewidth' => { 357 => 0x0 }, - 'rightalbedo' => { 432 => 'RightAlbedo' }, - 'rightascension' => { 156 => 'RightAscension' }, - 'rights' => { 443 => 'rights' }, - 'rightsagent' => { 459 => 'rightsAgent' }, - 'rightsowner' => { 459 => 'rightsOwner' }, - 'roll' => { 109 => 0x8 }, - 'rollangle' => { 228 => 0x350b, 229 => 0x2c24, 237 => 0x36f4, 274 => 0x903, 297 => 0x90, 331 => 0x1, 363 => 0x2 }, - 'romoperationmode' => { 91 => 0x80d }, - 'rotation' => { 29 => 0x17, 30 => 0x18, 90 => 0x3, 97 => 0x10002, 102 => 0x26e, 108 => 'Rotation', 117 => 0x4, 156 => 'Rotation', 172 => [0x65,0x50], 173 => 0x46, 174 => 0x5a, 177 => 0x10, 228 => 0x3693, 229 => 0xca, 235 => '590.1', 250 => 0x76a43207, 297 => 0x30, 313 => '17.2', 343 => 0xd8, 376 => 0x3f, 377 => 0x3f, 387 => 0x10 }, - 'routedto' => { 448 => 'RoutedTo' }, - 'routing' => { 348 => 'Routing' }, - 'routingdestinations' => { 431 => 'RoutingDestinations' }, - 'routingexclusions' => { 431 => 'RoutingExclusions' }, - 'routingnotes' => { 448 => 'RoutingNotes' }, - 'rowsperstrip' => { 113 => 0x116 }, - 'rpp' => { 436 => 'rpp' }, - 'safetyshift' => { 78 => 0x108 }, - 'safetyshiftinavortv' => { 76 => 0x10, 77 => 0x10, 79 => 0xf, 80 => 0x10, 83 => 0x10 }, - 'sameexposurefornewaperture' => { 78 => 0x112 }, - 'samplebits' => { 146 => 'SampleBits' }, - 'samplepagerange' => { 456 => 'samplePageRange' }, - 'samplerate' => { 146 => 'SampleRate' }, - 'samplesperpixel' => { 113 => 0x115, 302 => 0x8, 462 => 'SamplesPerPixel' }, - 'samplestructure' => { 127 => 0x5a }, - 'samsungmodelid' => { 365 => 0x3 }, - 'sanyoquality' => { 367 => 0x201 }, - 'sanyothumbnail' => { 367 => 0x100 }, - 'saturation' => { 9 => 0x6e, 11 => 0x76, 33 => 0xe, 48 => 0x1, 106 => 0xd, 107 => [0x3013,0x1f], 113 => [0xa409,0xfe55], 121 => 0x1003, 147 => 'Saturation', 171 => 0x1f, 172 => 0x32, 173 => 0x28, 174 => 0x1a, 179 => 0x1, 211 => [0x94,0xaa], 213 => 0x35, 214 => 0x3b, 297 => 0x40, 299 => 0x300d, 332 => 0x1f, 339 => 0xd, 353 => 0x27, 357 => 0x28, 358 => 0x1013, 368 => 0x10, 376 => 0x1e, 377 => 0x1b, 388 => 0x2005, 442 => 'Saturation', 446 => 'Saturation' }, - 'saturationadj' => { 97 => 0x20901, 102 => 0x116, 249 => 0x1, 253 => 0x2e, 421 => 0x8016 }, - 'saturationadjustmentaqua' => { 442 => 'SaturationAdjustmentAqua' }, - 'saturationadjustmentblue' => { 442 => 'SaturationAdjustmentBlue' }, - 'saturationadjustmentgreen' => { 442 => 'SaturationAdjustmentGreen' }, - 'saturationadjustmentmagenta' => { 442 => 'SaturationAdjustmentMagenta' }, - 'saturationadjustmentorange' => { 442 => 'SaturationAdjustmentOrange' }, - 'saturationadjustmentpurple' => { 442 => 'SaturationAdjustmentPurple' }, - 'saturationadjustmentred' => { 442 => 'SaturationAdjustmentRed' }, - 'saturationadjustmentyellow' => { 442 => 'SaturationAdjustmentYellow' }, - 'saturationauto' => { 67 => 0x98 }, - 'saturationfaithful' => { 18 => 0xfe, 66 => 0x68, 67 => 0x68 }, - 'saturationlandscape' => { 18 => 0xfc, 66 => 0x38, 67 => 0x38 }, - 'saturationmonochrome' => { 66 => 0x80, 67 => 0x80 }, - 'saturationneutral' => { 18 => 0xfd, 66 => 0x50, 67 => 0x50 }, - 'saturationportrait' => { 18 => 0xfb, 66 => 0x20, 67 => 0x20 }, - 'saturationsetting' => { 282 => 0x1010, 378 => 0x11, 393 => 0x9 }, - 'saturationstandard' => { 18 => 0xfa, 66 => 0x8, 67 => 0x8 }, - 'saturationuserdef1' => { 18 => 0x100, 66 => 0x98, 67 => 0xb0 }, - 'saturationuserdef2' => { 18 => 0x101, 66 => 0xb0, 67 => 0xc8 }, - 'saturationuserdef3' => { 18 => 0x102, 66 => 0xc8, 67 => 0xe0 }, - 'saveid' => { 467 => 'SaveID' }, - 'sbaanalysiscomplete' => { 131 => 0xc35 }, - 'sbablack' => { 131 => 0xc25 }, - 'sbagmoffset' => { 131 => 0xc4a }, - 'sbagray' => { 131 => 0xc26 }, - 'sbagreenmagentabal' => { 131 => 0xc33 }, - 'sbahighgray' => { 131 => 0xc46 }, - 'sbailloffset' => { 131 => 0xc49 }, - 'sbailluminantbal' => { 131 => 0xc34 }, - 'sbalowgray' => { 131 => 0xc47 }, - 'sbaneutralbal' => { 131 => 0xc32 }, - 'sbawhite' => { 131 => 0xc27 }, - 'scaletype' => { 466 => 'scaleType' }, - 'scanimageenhancer' => { 218 => 0x60 }, - 'scanningdirection' => { 127 => 0x64 }, - 'scene' => { 451 => 'Scene', 466 => 'scene' }, - 'scenearea' => { 277 => 0x211, 279 => 0x1031 }, - 'sceneassist' => { 211 => 0x9c }, - 'scenecapturetype' => { 113 => 0xa406, 446 => 'SceneCaptureType' }, - 'scenedetect' => { 277 => 0x210, 279 => 0x1030 }, - 'scenedetectdata' => { 277 => 0x212, 279 => 0x1033 }, - 'scenemode' => { 135 => 0xfa02, 176 => 0x100, 211 => 0x8f, 274 => 0x509, 279 => 0x403, 297 => 0x8001, 306 => 0xf, 388 => 0xb023 }, - 'scenemodeused' => { 137 => [0x6002,0xf002] }, - 'scenerecognition' => { 121 => 0x1425 }, - 'sceneselect' => { 367 => 0x21f }, - 'scenetype' => { 113 => 0xa301, 446 => 'SceneType' }, - 'screentips' => { 257 => '12.7', 258 => '5.3', 266 => '13.1', 267 => '4.4', 270 => '5.4', 272 => '5.1' }, - 'scriptversion' => { 131 => 0x1770 }, - 'season' => { 452 => 'Season', 455 => 'season' }, - 'seasonidentifier' => { 452 => [\'Season','SeasonIdentifier'] }, - 'seasonname' => { 452 => [\'Season','SeasonName'] }, - 'seasonnumber' => { 452 => [\'Season','SeasonNumber'] }, - 'secondaryftp' => { 431 => 'SecondaryFTP' }, - 'secondaryslotfunction' => { 228 => 0x1d0, 237 => 0x1d0 }, - 'section' => { 456 => 'section' }, - 'securityclassification' => { 113 => 0x9212 }, - 'selectableafpoint' => { 78 => 0x509 }, + 'orientationlinkedafpoint' => { 84 => 0x516 }, + 'originalalbumtitle' => { 179 => 'WM/OriginalAlbumTitle' }, + 'originalartist' => { 179 => 'WM/OriginalArtist', 372 => "\xa9ope" }, + 'originalbestqualitysize' => { 119 => 0xc792 }, + 'originalcreatedatetime' => { 468 => 'OriginalCreateDateTime' }, + 'originaldecisiondata' => { 114 => 'Canon-OriginalDecisionData' }, + 'originaldecisiondataoffset' => { 64 => 0x83 }, + 'originaldefaultcropsize' => { 119 => 0xc793 }, + 'originaldefaultfinalsize' => { 119 => 0xc791 }, + 'originaldirectory' => { 317 => 0x408 }, + 'originaldocumentid' => { 505 => 'OriginalDocumentID' }, + 'originalfilename' => { 97 => 0x816, 138 => 0x3e9, 150 => 0x20, 317 => 0x407, 468 => 'OriginalFilename' }, + 'originalimageheight' => { 79 => 0xc, 123 => 0x1 }, + 'originalimagewidth' => { 79 => 0xb, 123 => 0x0 }, + 'originallyricist' => { 179 => 'WM/OriginalLyricist' }, + 'originalrawfiledata' => { 119 => 0xc68c }, + 'originalrawfiledigest' => { 119 => 0xc71d }, + 'originalrawfilename' => { 119 => 0xc68b }, + 'originaltransmissionreference' => { 131 => 0x67 }, + 'originatingprogram' => { 131 => 0x41, 473 => 'OriginatingProgram' }, + 'originplatform' => { 494 => 'originPlatform' }, + 'os' => { 482 => 'os' }, + 'otherconditions' => { 307 => 'OtherConditions' }, + 'otherconstraints' => { 307 => 'OtherConstraints' }, + 'otherimage' => { 114 => 'Exif-OtherImage' }, + 'otherimageinfo' => { 307 => 'OtherImageInfo' }, + 'otherimagelength' => { 119 => 0x202 }, + 'otherimagestart' => { 119 => 0x201 }, + 'otherlicensedocuments' => { 307 => 'OtherLicenseDocuments' }, + 'otherlicenseinfo' => { 307 => 'OtherLicenseInfo' }, + 'otherlicenserequirements' => { 307 => 'OtherLicenseRequirements' }, + 'outcue' => { 504 => 'outCue' }, + 'outcuescale' => { 504 => [\'outCue','outCueScale'] }, + 'outcuevalue' => { 504 => [\'outCue','outCueValue'] }, + 'outputimageheight' => { 197 => 0x3 }, + 'outputimagewidth' => { 197 => 0x2 }, + 'outputlut' => { 320 => 0xa7 }, + 'outputprofile' => { 138 => 0x138b }, + 'outputresolution' => { 197 => 0x4 }, + 'overclockcols' => { 138 => 0x189c }, + 'overclockrows' => { 138 => 0x18c4 }, + 'overridelookvignette' => { 478 => 'OverrideLookVignette', 480 => 'OverrideLookVignette' }, + 'owner' => { 508 => 'Owner' }, + 'ownerid' => { 131 => 0xbc }, + 'ownername' => { 15 => 0x10f, 64 => 0x9, 97 => 0x810, 119 => [0xa430,0xfde8], 156 => 'OwnerName', 475 => 'OwnerName', 485 => 'CameraOwnerName' }, + 'padding' => { 119 => 0xea1c }, + 'pagecount' => { 494 => 'pageCount' }, + 'pageimage' => { 502 => [\'PageInfo','PageInfoImage'] }, + 'pageimageformat' => { 502 => [\'PageInfo','PageInfoFormat'] }, + 'pageimageheight' => { 502 => [\'PageInfo','PageInfoHeight'] }, + 'pageimagepagenumber' => { 502 => [\'PageInfo','PageInfoPageNumber'] }, + 'pageimagewidth' => { 502 => [\'PageInfo','PageInfoWidth'] }, + 'pageinfo' => { 502 => 'PageInfo' }, + 'pagename' => { 119 => 0x11d }, + 'pagenumber' => { 119 => 0x129 }, + 'pageprogressiondirection' => { 494 => 'pageProgressionDirection' }, + 'pagerange' => { 494 => 'pageRange' }, + 'paintbasedcorrectionmasks' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasks'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasks'] }, + 'paintbasedcorrections' => { 478 => 'PaintBasedCorrections', 480 => 'PaintBasedCorrections' }, + 'paintcorrectionactive' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionActive'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionActive'] }, + 'paintcorrectionamount' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionAmount'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionAmount'] }, + 'paintcorrectionblacks2012' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalBlacks2012'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalBlacks2012'] }, + 'paintcorrectionbrightness' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalBrightness'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalBrightness'] }, + 'paintcorrectionclarity' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalClarity'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalClarity'] }, + 'paintcorrectionclarity2012' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalClarity2012'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalClarity2012'] }, + 'paintcorrectioncontrast' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalContrast'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalContrast'] }, + 'paintcorrectioncontrast2012' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalContrast2012'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalContrast2012'] }, + 'paintcorrectioncorrectionname' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionName'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionName'] }, + 'paintcorrectioncorrectionsyncid' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionSyncID'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionSyncID'] }, + 'paintcorrectiondefringe' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalDefringe'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalDefringe'] }, + 'paintcorrectiondehaze' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalDehaze'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalDehaze'] }, + 'paintcorrectionexposure' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalExposure'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalExposure'] }, + 'paintcorrectionexposure2012' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalExposure2012'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalExposure2012'] }, + 'paintcorrectionhighlights2012' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalHighlights2012'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalHighlights2012'] }, + 'paintcorrectionhue' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalHue'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalHue'] }, + 'paintcorrectionluminancenoise' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalLuminanceNoise'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalLuminanceNoise'] }, + 'paintcorrectionmaskalpha' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksAlpha'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksAlpha'] }, + 'paintcorrectionmaskangle' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksAngle'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksAngle'] }, + 'paintcorrectionmaskbottom' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksBottom'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksBottom'] }, + 'paintcorrectionmaskcentervalue' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCenterValue'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCenterValue'] }, + 'paintcorrectionmaskcenterweight' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCenterWeight'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCenterWeight'] }, + 'paintcorrectionmaskdabs' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksDabs'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksDabs'] }, + 'paintcorrectionmaskfeather' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFeather'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFeather'] }, + 'paintcorrectionmaskflipped' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFlipped'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFlipped'] }, + 'paintcorrectionmaskflow' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFlow'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFlow'] }, + 'paintcorrectionmaskfullx' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFullX'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFullX'] }, + 'paintcorrectionmaskfully' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFullY'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksFullY'] }, + 'paintcorrectionmaskinputdigest' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksInputDigest'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksInputDigest'] }, + 'paintcorrectionmaskleft' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksLeft'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksLeft'] }, + 'paintcorrectionmaskmaskactive' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskActive'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskActive'] }, + 'paintcorrectionmaskmaskblendmode' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskBlendMode'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskBlendMode'] }, + 'paintcorrectionmaskmaskdigest' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskDigest'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskDigest'] }, + 'paintcorrectionmaskmaskinverted' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskInverted'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskInverted'] }, + 'paintcorrectionmaskmaskname' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskName'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskName'] }, + 'paintcorrectionmaskmasks' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasks'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasks'] }, + 'paintcorrectionmaskmasksalpha' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksAlpha'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksAlpha'] }, + 'paintcorrectionmaskmasksangle' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksAngle'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksAngle'] }, + 'paintcorrectionmaskmasksbottom' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksBottom'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksBottom'] }, + 'paintcorrectionmaskmaskscentervalue' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksCenterValue'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksCenterValue'] }, + 'paintcorrectionmaskmaskscenterweight' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksCenterWeight'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksCenterWeight'] }, + 'paintcorrectionmaskmasksdabs' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksDabs'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksDabs'] }, + 'paintcorrectionmaskmasksfeather' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksFeather'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksFeather'] }, + 'paintcorrectionmaskmasksflipped' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksFlipped'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksFlipped'] }, + 'paintcorrectionmaskmasksflow' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksFlow'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksFlow'] }, + 'paintcorrectionmaskmasksfullx' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksFullX'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksFullX'] }, + 'paintcorrectionmaskmasksfully' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksFullY'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksFullY'] }, + 'paintcorrectionmaskmasksinputdigest' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksInputDigest'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksInputDigest'] }, + 'paintcorrectionmaskmasksleft' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksLeft'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksLeft'] }, + 'paintcorrectionmaskmasksmaskactive' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskActive'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskActive'] }, + 'paintcorrectionmaskmasksmaskblendmode' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskBlendMode'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskBlendMode'] }, + 'paintcorrectionmaskmasksmaskdigest' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskDigest'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskDigest'] }, + 'paintcorrectionmaskmasksmaskinverted' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskInverted'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskInverted'] }, + 'paintcorrectionmaskmasksmaskname' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskName'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskName'] }, + 'paintcorrectionmaskmasksmasksubtype' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskSubType'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskSubType'] }, + 'paintcorrectionmaskmasksmasksyncid' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskSyncID'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskSyncID'] }, + 'paintcorrectionmaskmasksmaskversion' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskVersion'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskVersion'] }, + 'paintcorrectionmaskmasksmidpoint' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMidpoint'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMidpoint'] }, + 'paintcorrectionmaskmasksorigin' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksOrigin'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksOrigin'] }, + 'paintcorrectionmaskmasksperimetervalue' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksPerimeterValue'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksPerimeterValue'] }, + 'paintcorrectionmaskmasksradius' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksRadius'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksRadius'] }, + 'paintcorrectionmaskmasksreferencepoint' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksReferencePoint'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksReferencePoint'] }, + 'paintcorrectionmaskmasksright' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksRight'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksRight'] }, + 'paintcorrectionmaskmasksroundness' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksRoundness'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksRoundness'] }, + 'paintcorrectionmaskmaskssizex' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksSizeX'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksSizeX'] }, + 'paintcorrectionmaskmaskssizey' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksSizeY'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksSizeY'] }, + 'paintcorrectionmaskmaskstop' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksTop'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksTop'] }, + 'paintcorrectionmaskmasksubtype' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskSubType'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskSubType'] }, + 'paintcorrectionmaskmasksvalue' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskValue'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksMaskValue'] }, + 'paintcorrectionmaskmasksversion' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksVersion'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksVersion'] }, + 'paintcorrectionmaskmaskswhat' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksWhat'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksWhat'] }, + 'paintcorrectionmaskmaskswholeimagearea' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksWholeImageArea'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksWholeImageArea'] }, + 'paintcorrectionmaskmasksx' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksX'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksX'] }, + 'paintcorrectionmaskmasksy' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksY'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksY'] }, + 'paintcorrectionmaskmasksyncid' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskSyncID'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskSyncID'] }, + 'paintcorrectionmaskmaskszerox' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksZeroX'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksZeroX'] }, + 'paintcorrectionmaskmaskszeroy' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksZeroY'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMasksZeroY'] }, + 'paintcorrectionmaskmaskversion' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskVersion'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskVersion'] }, + 'paintcorrectionmaskmidpoint' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMidpoint'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMidpoint'] }, + 'paintcorrectionmaskorigin' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksOrigin'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksOrigin'] }, + 'paintcorrectionmaskperimetervalue' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksPerimeterValue'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksPerimeterValue'] }, + 'paintcorrectionmaskradius' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksRadius'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksRadius'] }, + 'paintcorrectionmaskrange' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMask'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMask'] }, + 'paintcorrectionmaskrangeareamodels' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModels'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModels'] }, + 'paintcorrectionmaskrangeareamodelscolorsampleinfo' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'] }, + 'paintcorrectionmaskrangeareamodelscomponents' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsAreaComponents'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskAreaModelsAreaComponents'] }, + 'paintcorrectionmaskrangecoloramount' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskColorAmount'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskColorAmount'] }, + 'paintcorrectionmaskrangedepthfeather' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthFeather'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthFeather'] }, + 'paintcorrectionmaskrangedepthmax' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMax'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMax'] }, + 'paintcorrectionmaskrangedepthmin' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMin'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskDepthMin'] }, + 'paintcorrectionmaskrangeinvert' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskInvert'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskInvert'] }, + 'paintcorrectionmaskrangelumfeather' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumFeather'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumFeather'] }, + 'paintcorrectionmaskrangeluminancedepthsampleinfo' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskLuminanceDepthSampleInfo'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskLuminanceDepthSampleInfo'] }, + 'paintcorrectionmaskrangelummax' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMax'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMax'] }, + 'paintcorrectionmaskrangelummin' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMin'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumMin'] }, + 'paintcorrectionmaskrangelumrange' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumRange'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskLumRange'] }, + 'paintcorrectionmaskrangesampletype' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskSampleType'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskSampleType'] }, + 'paintcorrectionmaskrangetype' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskType'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskType'] }, + 'paintcorrectionmaskrangeversion' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskVersion'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksCorrectionRangeMaskVersion'] }, + 'paintcorrectionmaskreferencepoint' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksReferencePoint'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksReferencePoint'] }, + 'paintcorrectionmaskright' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksRight'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksRight'] }, + 'paintcorrectionmaskroundness' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksRoundness'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksRoundness'] }, + 'paintcorrectionmasksizex' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksSizeX'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksSizeX'] }, + 'paintcorrectionmasksizey' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksSizeY'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksSizeY'] }, + 'paintcorrectionmasktop' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksTop'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksTop'] }, + 'paintcorrectionmaskvalue' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskValue'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksMaskValue'] }, + 'paintcorrectionmaskversion' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksVersion'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksVersion'] }, + 'paintcorrectionmaskwhat' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksWhat'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksWhat'] }, + 'paintcorrectionmaskwholeimagearea' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksWholeImageArea'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksWholeImageArea'] }, + 'paintcorrectionmaskx' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksX'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksX'] }, + 'paintcorrectionmasky' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksY'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksY'] }, + 'paintcorrectionmaskzerox' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksZeroX'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksZeroX'] }, + 'paintcorrectionmaskzeroy' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksZeroY'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionMasksZeroY'] }, + 'paintcorrectionmoire' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalMoire'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalMoire'] }, + 'paintcorrectionrangemask' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMask'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMask'] }, + 'paintcorrectionrangemaskareamodels' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskAreaModels'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskAreaModels'] }, + 'paintcorrectionrangemaskareamodelscolorsampleinfo' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'] }, + 'paintcorrectionrangemaskareamodelscomponents' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskAreaModelsAreaComponents'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskAreaModelsAreaComponents'] }, + 'paintcorrectionrangemaskcoloramount' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskColorAmount'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskColorAmount'] }, + 'paintcorrectionrangemaskdepthfeather' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskDepthFeather'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskDepthFeather'] }, + 'paintcorrectionrangemaskdepthmax' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskDepthMax'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskDepthMax'] }, + 'paintcorrectionrangemaskdepthmin' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskDepthMin'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskDepthMin'] }, + 'paintcorrectionrangemaskinvert' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskInvert'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskInvert'] }, + 'paintcorrectionrangemasklumfeather' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskLumFeather'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskLumFeather'] }, + 'paintcorrectionrangemaskluminancedepthsampleinfo' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskLuminanceDepthSampleInfo'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskLuminanceDepthSampleInfo'] }, + 'paintcorrectionrangemasklummax' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskLumMax'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskLumMax'] }, + 'paintcorrectionrangemasklummin' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskLumMin'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskLumMin'] }, + 'paintcorrectionrangemasklumrange' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskLumRange'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskLumRange'] }, + 'paintcorrectionrangemasksampletype' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskSampleType'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskSampleType'] }, + 'paintcorrectionrangemasktype' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskType'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskType'] }, + 'paintcorrectionrangemaskversion' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskVersion'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsCorrectionRangeMaskVersion'] }, + 'paintcorrectionsaturation' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalSaturation'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalSaturation'] }, + 'paintcorrectionshadows2012' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalShadows2012'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalShadows2012'] }, + 'paintcorrectionsharpness' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalSharpness'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalSharpness'] }, + 'paintcorrectiontemperature' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalTemperature'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalTemperature'] }, + 'paintcorrectiontexture' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalTexture'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalTexture'] }, + 'paintcorrectiontint' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalTint'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalTint'] }, + 'paintcorrectiontoninghue' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalToningHue'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalToningHue'] }, + 'paintcorrectiontoningsaturation' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalToningSaturation'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalToningSaturation'] }, + 'paintcorrectionwhat' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsWhat'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsWhat'] }, + 'paintcorrectionwhites2012' => { 478 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalWhites2012'], 480 => [\'PaintBasedCorrections','PaintBasedCorrectionsLocalWhites2012'] }, + 'panasonicdatetime' => { 323 => 0x0 }, + 'panasonicexifversion' => { 320 => 0x26 }, + 'panasonicimageheight' => { 320 => 0x4c }, + 'panasonicimagewidth' => { 320 => 0x4b }, + 'panasonicrawversion' => { 325 => 0x1 }, + 'panasonictitle' => { 119 => 0xc6d2 }, + 'panasonictitle2' => { 119 => 0xc6d3 }, + 'panoramaangle' => { 127 => 0x1153 }, + 'panoramacropbottom' => { 426 => 0x7 }, + 'panoramacropleft' => { 426 => 0x4 }, + 'panoramacropright' => { 426 => 0x6 }, + 'panoramacroptop' => { 426 => 0x5 }, + 'panoramadirection' => { 72 => 0x5, 127 => 0x1154, 426 => 0x3 }, + 'panoramaframeheight' => { 426 => 0x9 }, + 'panoramaframenumber' => { 72 => 0x2 }, + 'panoramaframewidth' => { 426 => 0x8 }, + 'panoramafullheight' => { 426 => 0x2 }, + 'panoramafullwidth' => { 426 => 0x1 }, + 'panoramamode' => { 140 => 0x3c, 297 => 0x601 }, + 'panoramasize3d' => { 409 => 0x38 }, + 'panoramasourceheight' => { 426 => 0xb }, + 'panoramasourcewidth' => { 426 => 0xa }, + 'panoramicstitchcameramotion' => { 176 => 'PanoramicStitchCameraMotion', 177 => 0x1 }, + 'panoramicstitchmaptype' => { 176 => 'PanoramicStitchMapType', 177 => 0x2 }, + 'panoramicstitchphi0' => { 176 => 'PanoramicStitchPhi0', 177 => 0x5 }, + 'panoramicstitchphi1' => { 176 => 'PanoramicStitchPhi1', 177 => 0x6 }, + 'panoramicstitchtheta0' => { 176 => 'PanoramicStitchTheta0', 177 => 0x3 }, + 'panoramicstitchtheta1' => { 176 => 'PanoramicStitchTheta1', 177 => 0x4 }, + 'panoramicstitchversion' => { 177 => 0x0 }, + 'pantry' => { 505 => 'Pantry' }, + 'pantryinstanceid' => { 505 => [\'Pantry','PantryInstanceID'] }, + 'parallax' => { 127 => 0xb211, 296 => 0x28 }, + 'parametricdarks' => { 478 => 'ParametricDarks', 480 => 'ParametricDarks' }, + 'parametrichighlights' => { 478 => 'ParametricHighlights', 480 => 'ParametricHighlights' }, + 'parametrichighlightsplit' => { 478 => 'ParametricHighlightSplit', 480 => 'ParametricHighlightSplit' }, + 'parametriclights' => { 478 => 'ParametricLights', 480 => 'ParametricLights' }, + 'parametricmidtonesplit' => { 478 => 'ParametricMidtoneSplit', 480 => 'ParametricMidtoneSplit' }, + 'parametricshadows' => { 478 => 'ParametricShadows', 480 => 'ParametricShadows' }, + 'parametricshadowsplit' => { 478 => 'ParametricShadowSplit', 480 => 'ParametricShadowSplit' }, + 'parentalrating' => { 179 => 'WM/ParentalRating' }, + 'parentid' => { 490 => 'parentId' }, + 'parentmediaeventid' => { 468 => 'ParentMediaEventID' }, + 'parentmeid' => { 468 => 'ParentMEID' }, + 'parentproductid' => { 372 => '@ppi' }, + 'parentreference1' => { 488 => [\'TagStructure','TagStructureParentReference'] }, + 'parentreference2' => { 488 => [\'TagStructure','TagStructureSubLabelsParentReference'] }, + 'parentreference3' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsParentReference'] }, + 'parentreference4' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsParentReference'] }, + 'parentreference5' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsParentReference'] }, + 'parentreference6' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsSubLabelsParentReference'] }, + 'parentshorttitle' => { 372 => '@PST' }, + 'parenttitle' => { 372 => '@pti' }, + 'partialactivecols1' => { 138 => 0x17e8 }, + 'partialactivecols2' => { 138 => 0x17f2 }, + 'partialactiverows1' => { 138 => 0x17fc }, + 'partialactiverows2' => { 138 => 0x1806 }, + 'partofcompilation' => { 504 => 'partOfCompilation' }, + 'patientbirthdate' => { 457 => 'PatientDOB' }, + 'patientid' => { 457 => 'PatientID' }, + 'patientname' => { 457 => 'PatientName' }, + 'patientsex' => { 457 => 'PatientSex' }, + 'patternareaheight' => { 138 => 0x963 }, + 'patternareawidth' => { 138 => 0x962 }, + 'patterncorrectionfactorscale' => { 138 => 0x969 }, + 'patterncropcols1' => { 138 => 0x96c }, + 'patterncropcols2' => { 138 => 0x96d }, + 'patterncroprows1' => { 138 => 0x96a }, + 'patterncroprows2' => { 138 => 0x96b }, + 'patternimagerheight' => { 138 => 0x961 }, + 'patternimagerwidth' => { 138 => 0x960 }, + 'patternx' => { 138 => 0x966 }, + 'patterny' => { 138 => 0x967 }, + 'pdfversion' => { 491 => 'PDFVersion' }, + 'pentaximagesize' => { 355 => 0x9 }, + 'pentaxmodelid' => { 335 => 0x0, 355 => 0x5 }, + 'pentaxmodeltype' => { 355 => 0x1 }, + 'pentaxversion' => { 355 => 0x0 }, + 'people' => { 459 => 'People', 471 => 'People' }, + 'perchannelblacklevel' => { 41 => 0x157, 42 => 0x16b, 44 => 0xc4, 45 => [0x2b4,0x2cb,0x2cf], 46 => [0x108,0x14d], 47 => 0x1df, 48 => [0x1f8,0x2d8], 49 => [0x22c,0x30a], 50 => 0x149 }, + 'performer' => { 372 => 'perf', 380 => 'perf' }, + 'performerkeywords' => { 380 => "\xa9prk" }, + 'performers' => { 380 => "\xa9prf" }, + 'performerurl' => { 380 => "\xa9prl" }, + 'period' => { 179 => 'WM/Period' }, + 'peripheralillumcentralradius' => { 455 => 0x8030 }, + 'peripheralillumcentralvalue' => { 455 => 0x8031 }, + 'peripheralillumination' => { 103 => 0x20702, 109 => 0x68 }, + 'peripheralilluminationcorr' => { 62 => 0x1, 345 => 0x2 }, + 'peripheralilluminationon' => { 103 => '0x20702.0', 109 => 0x64 }, + 'peripheralillumperiphvalue' => { 455 => 0x8032 }, + 'peripherallighting' => { 79 => 0x2, 127 => 0x3804 }, + 'peripherallightingsetting' => { 80 => 0x5 }, + 'peripherallightingvalue' => { 79 => 0x6 }, + 'permissions' => { 497 => 'permissions' }, + 'permits' => { 476 => 'permits' }, + 'person' => { 494 => 'person' }, + 'personality' => { 468 => 'Personality' }, + 'personheard' => { 490 => 'PersonHeard' }, + 'personheardidentifier' => { 490 => [\'PersonHeard','PersonHeardIdentifier'] }, + 'personheardname' => { 490 => [\'PersonHeard','PersonHeardName'] }, + 'personinimage' => { 490 => 'PersonInImage' }, + 'personinimagecharacteristic' => { 490 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonCharacteristic'] }, + 'personinimagecvtermcvid' => { 490 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonCharacteristicCvId'] }, + 'personinimagecvtermid' => { 490 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonCharacteristicCvTermId'] }, + 'personinimagecvtermname' => { 490 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonCharacteristicCvTermName'] }, + 'personinimagecvtermrefinedabout' => { 490 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonCharacteristicCvTermRefinedAbout'] }, + 'personinimagedescription' => { 490 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonDescription'] }, + 'personinimageid' => { 490 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonId'] }, + 'personinimagename' => { 490 => [\'PersonInImageWDetails','PersonInImageWDetailsPersonName'] }, + 'personinimagewdetails' => { 490 => 'PersonInImageWDetails' }, + 'perspectiveaspect' => { 478 => 'PerspectiveAspect', 480 => 'PerspectiveAspect' }, + 'perspectivehorizontal' => { 478 => 'PerspectiveHorizontal', 480 => 'PerspectiveHorizontal' }, + 'perspectiverotate' => { 478 => 'PerspectiveRotate', 480 => 'PerspectiveRotate' }, + 'perspectivescale' => { 478 => 'PerspectiveScale', 480 => 'PerspectiveScale' }, + 'perspectiveupright' => { 478 => 'PerspectiveUpright', 480 => 'PerspectiveUpright' }, + 'perspectivevertical' => { 478 => 'PerspectiveVertical', 480 => 'PerspectiveVertical' }, + 'perspectivex' => { 478 => 'PerspectiveX', 480 => 'PerspectiveX' }, + 'perspectivey' => { 478 => 'PerspectiveY', 480 => 'PerspectiveY' }, + 'pf0customfuncregistration' => { 92 => 0x1 }, + 'pf10retainprogramshift' => { 92 => 0xb }, + 'pf13drivepriority' => { 92 => 0xe }, + 'pf14disablefocussearch' => { 92 => 0xf }, + 'pf15disableafassistbeam' => { 92 => 0x10 }, + 'pf16autofocuspointshoot' => { 92 => 0x11 }, + 'pf17disableafpointsel' => { 92 => 0x12 }, + 'pf18enableautoafpointsel' => { 92 => 0x13 }, + 'pf19continuousshootspeed' => { 92 => 0x14 }, + 'pf19shootingspeedhigh' => { 91 => 0xa }, + 'pf19shootingspeedlow' => { 91 => 0x9 }, + 'pf1disableshootingmodes' => { 92 => 0x2 }, + 'pf1value' => { 91 => 0x1 }, + 'pf20limitcontinousshots' => { 92 => 0x15 }, + 'pf20maxcontinousshots' => { 91 => 0xb }, + 'pf21enablequietoperation' => { 92 => 0x16 }, + 'pf23felocktime' => { 91 => 0xd }, + 'pf23postreleasetime' => { 91 => 0xe }, + 'pf23settimerlengths' => { 92 => 0x18 }, + 'pf23shutterbuttontime' => { 91 => 0xc }, + 'pf24lightlcdduringbulb' => { 92 => 0x19 }, + 'pf25aemode' => { 91 => 0xf }, + 'pf25afmode' => { 91 => 0x12 }, + 'pf25afpointsel' => { 91 => 0x13 }, + 'pf25colormatrix' => { 91 => 0x17 }, + 'pf25defaultclearsettings' => { 92 => 0x1a }, + 'pf25drivemode' => { 91 => 0x11 }, + 'pf25imagesize' => { 91 => 0x14 }, + 'pf25meteringmode' => { 91 => 0x10 }, + 'pf25parameters' => { 91 => 0x16 }, + 'pf25wbmode' => { 91 => 0x15 }, + 'pf26shortenreleaselag' => { 92 => 0x1b }, + 'pf27reversedialrotation' => { 92 => 0x1c }, + 'pf27value' => { 91 => 0x18 }, + 'pf28noquickdialexpcomp' => { 92 => 0x1d }, + 'pf29quickdialswitchoff' => { 92 => 0x1e }, + 'pf2disablemeteringmodes' => { 92 => 0x3 }, + 'pf2value' => { 91 => 0x2 }, + 'pf30enlargementmode' => { 92 => 0x1f }, + 'pf31originaldecisiondata' => { 92 => 0x20 }, + 'pf3manualexposuremetering' => { 92 => 0x4 }, + 'pf3value' => { 91 => 0x3 }, + 'pf4exposuretimelimits' => { 92 => 0x5 }, + 'pf4exposuretimemax' => { 91 => 0x5 }, + 'pf4exposuretimemin' => { 91 => 0x4 }, + 'pf5aperturelimits' => { 92 => 0x6 }, + 'pf5aperturemax' => { 91 => 0x7 }, + 'pf5aperturemin' => { 91 => 0x6 }, + 'pf6presetshootingmodes' => { 92 => 0x7 }, + 'pf7bracketcontinuousshoot' => { 92 => 0x8 }, + 'pf8bracketshots' => { 91 => 0x8 }, + 'pf8setbracketshots' => { 92 => 0x9 }, + 'pf9changebracketsequence' => { 92 => 0xa }, + 'phasedetectaf' => { 193 => 0x6 }, + 'phonenumber' => { 157 => 'Phone' }, + 'photoeffect' => { 34 => 0x28 }, + 'photoeffecthistoryxml' => { 272 => 0xe9651831 }, + 'photoeffects' => { 272 => 0xab5eca5e }, + 'photoeffectsblue' => { 274 => 0x8 }, + 'photoeffectsgreen' => { 274 => 0x6 }, + 'photoeffectsred' => { 274 => 0x4 }, + 'photoeffectstype' => { 274 => 0x0 }, + 'photographicsensitivity' => { 485 => 'PhotographicSensitivity' }, + 'photoinfoplayback' => { 279 => '17.6', 288 => '33.6' }, + 'photometricinterpretation' => { 119 => 0x106, 500 => 'PhotometricInterpretation' }, + 'photoshootingmenubank' => { 229 => 0x112, 248 => 0xe7d, 258 => 0xfbd }, + 'photoshootingmenubankimagearea' => { 229 => 0x134, 248 => '3716.1', 258 => 0x791 }, + 'photoshopbgrthumbnail' => { 369 => 0x409 }, + 'photoshopquality' => { 368 => 0x0 }, + 'photoshopthumbnail' => { 369 => 0x40c }, + 'photostyle' => { 320 => 0x89 }, + 'picklabel' => { 483 => 'PickLabel' }, + 'pictinfo' => { 396 => 0x208 }, + 'picturecontrol' => { 272 => 0xe2173c47 }, + 'picturecontrolactive' => { 275 => 0x0 }, + 'picturecontroladjust' => { 231 => 0x30, 232 => 0x30, 233 => 0x36 }, + 'picturecontrolbase' => { 231 => 0x18, 232 => 0x18, 233 => 0x1c }, + 'picturecontroldata' => { 226 => [0xbd,0x23] }, + 'picturecontrolmode' => { 275 => 0x13 }, + 'picturecontrolname' => { 231 => 0x4, 232 => 0x4, 233 => 0x8 }, + 'picturecontrolquickadjust' => { 231 => 0x31, 232 => 0x31, 233 => 0x37 }, + 'pictureeffect' => { 420 => 0x200e }, + 'pictureeffect2' => { 429 => 0x1163, 430 => 0x1167, 431 => 0x1143, 432 => 0x11bf, 433 => 0x119b, 434 => 0x1053, 435 => 0x24b, 436 => 0x24b, 437 => 0x23c, 451 => 0x46 }, + 'picturefinish' => { 182 => 0x71 }, + 'picturemode' => { 127 => 0x1031, 297 => 0x520, 355 => [0xb,0x33], 397 => 0x3d }, + 'picturemode2' => { 336 => 0x0 }, + 'picturemodebwfilter' => { 297 => 0x525 }, + 'picturemodecontrast' => { 297 => 0x523 }, + 'picturemodeeffect' => { 297 => 0x52d }, + 'picturemodehue' => { 297 => 0x522 }, + 'picturemodesaturation' => { 297 => 0x521 }, + 'picturemodesharpness' => { 297 => 0x524 }, + 'picturemodetone' => { 297 => 0x526 }, + 'pictureprofile' => { 429 => [0x115e,0x115f], 430 => [0x1162,0x1163], 431 => [0x113e,0x113f], 432 => [0x11ba,0x11bb], 433 => [0x1196,0x1197], 434 => [0x104e,0x104f], 435 => [0x246,0x247], 436 => [0x246,0x247], 437 => [0x237,0x238] }, + 'picturestyle' => { 8 => [0x4b,0x51], 9 => 0xf4, 10 => 0x6c, 11 => 0x86, 12 => 0x73, 16 => 0xab, 17 => 0xa7, 18 => 0xb0, 19 => 0x6c, 20 => 0xa7, 21 => 0xf4, 22 => 0xb3, 24 => 0xf4, 25 => 0xfa, 27 => 0x169, 74 => 0xa, 103 => 0x20301, 109 => 0x2 }, + 'picturestylepc' => { 64 => 0x4009 }, + 'picturestyleuserdef' => { 64 => 0x4008 }, + 'picturewizard' => { 394 => 0x21 }, + 'picturewizardcolor' => { 393 => 0x1 }, + 'picturewizardcontrast' => { 393 => 0x4 }, + 'picturewizardmode' => { 393 => 0x0 }, + 'picturewizardsaturation' => { 393 => 0x2 }, + 'picturewizardsharpness' => { 393 => 0x3 }, + 'pipelineversion' => { 176 => 'PipelineVersion' }, + 'pitch' => { 115 => 0x6, 280 => '4.1', 292 => '4.1', 380 => ['ptch',"\xa9fpt"] }, + 'pitchangle' => { 247 => 0x350f, 248 => 0x2c28, 252 => 0xc21e, 257 => 0x36f8, 258 => 0x2eff, 260 => 0xce36, 261 => 0xeaef, 297 => 0x904, 320 => 0x91, 354 => 0x2, 392 => 0x1 }, + 'pitchshift' => { 374 => 'player.movie.audio.pitchshift' }, + 'pixelaspectratio' => { 373 => 'pasp' }, + 'pixelclockfrequency' => { 138 => 0x40b }, + 'pixelcorrectionoffset' => { 138 => 0x972 }, + 'pixelcorrectionscale' => { 138 => 0x971 }, + 'pixelscale' => { 119 => 0x830e }, + 'pixelshiftinfo' => { 420 => 0x202f }, + 'pixelshiftoffset' => { 127 => 0x1106 }, + 'pixelshiftresolution' => { 356 => 0x0 }, + 'pixelshiftshots' => { 127 => 0x1105 }, + 'pixelsperunitx' => { 309 => 0x0 }, + 'pixelsperunity' => { 309 => 0x4 }, + 'pixelunits' => { 309 => 0x8 }, + 'planarconfiguration' => { 119 => 0x11c, 500 => 'PlanarConfiguration' }, + 'plane' => { 458 => [\'Planes','PlanesPlane'] }, + 'planeboundary' => { 458 => [\'Planes','PlanesPlaneBoundary'] }, + 'planeboundaryvertexcount' => { 458 => [\'Planes','PlanesPlaneBoundaryVertexCount'] }, + 'planeextentx' => { 458 => [\'Planes','PlanesPlaneExtentX'] }, + 'planeextentz' => { 458 => [\'Planes','PlanesPlaneExtentZ'] }, + 'planepose' => { 458 => [\'Planes','PlanesPlanePose'] }, + 'planeposepositionx' => { 458 => [\'Planes','PlanesPlanePosePositionX'] }, + 'planeposepositiony' => { 458 => [\'Planes','PlanesPlanePosePositionY'] }, + 'planeposepositionz' => { 458 => [\'Planes','PlanesPlanePosePositionZ'] }, + 'planeposerotationw' => { 458 => [\'Planes','PlanesPlanePoseRotationW'] }, + 'planeposerotationx' => { 458 => [\'Planes','PlanesPlanePoseRotationX'] }, + 'planeposerotationy' => { 458 => [\'Planes','PlanesPlanePoseRotationY'] }, + 'planeposerotationz' => { 458 => [\'Planes','PlanesPlanePoseRotationZ'] }, + 'planeposetimestamp' => { 458 => [\'Planes','PlanesPlanePoseTimestamp'] }, + 'planes' => { 458 => 'Planes' }, + 'planningref' => { 490 => 'PlanningRef' }, + 'planningrefidentifier' => { 490 => [\'PlanningRef','PlanningRefIdentifier'] }, + 'planningrefname' => { 490 => [\'PlanningRef','PlanningRefName'] }, + 'planningrefrole' => { 490 => [\'PlanningRef','PlanningRefRole'] }, + 'platenames' => { 509 => 'PlateNames' }, + 'platform' => { 494 => 'platform' }, + 'playallframes' => { 380 => 'AllF' }, + 'playbackflickdown' => { 295 => 0x159 }, + 'playbackflickup' => { 295 => 0x155 }, + 'playbackmenustime' => { 284 => '20.1', 285 => '21.1', 286 => '21.1' }, + 'playbackmonitorofftime' => { 279 => '25.2', 280 => '36.1', 282 => '36.1', 283 => '36.1', 287 => '35.1', 288 => '8.1', 289 => '35.1', 292 => '36.1', 293 => '36.1', 294 => '21.1', 295 => 0x33 }, + 'playbackzoom' => { 280 => '37.1' }, + 'playdisplay' => { 184 => 0x4e }, + 'playerversion' => { 374 => 'player.version' }, + 'playgap' => { 372 => 'pgap' }, + 'playlistid' => { 372 => 'plID' }, + 'playmode' => { 380 => 'SDLN' }, + 'playselection' => { 380 => 'SelO' }, + 'plusversion' => { 307 => 'Version' }, + 'pmversion' => { 367 => 'PMVersion' }, + 'pngwarning' => { 310 => 'Warning' }, + 'podcast' => { 372 => 'pcst' }, + 'podcasturl' => { 372 => 'purl' }, + 'poilevel' => { 225 => 0x8 }, + 'portraitimpressionbalance' => { 260 => 0x7fa0 }, + 'portraitnote' => { 461 => 'PortraitNote' }, + 'portraitoutputhighlightpoint' => { 109 => 0x1d }, + 'portraitoutputshadowpoint' => { 109 => 0x1e }, + 'portraitrawcolortone' => { 109 => 0x16 }, + 'portraitrawcontrast' => { 109 => 0x18 }, + 'portraitrawhighlight' => { 109 => 0x76 }, + 'portraitrawhighlightpoint' => { 109 => 0x1b }, + 'portraitrawlinear' => { 109 => 0x19 }, + 'portraitrawsaturation' => { 109 => 0x17 }, + 'portraitrawshadow' => { 109 => 0x7f }, + 'portraitrawshadowpoint' => { 109 => 0x1c }, + 'portraitrawsharpness' => { 109 => 0x1a }, + 'portraitrefiner' => { 113 => 0x302b }, + 'portraitrequest' => { 461 => 'PortraitRequest' }, + 'portraitunsharpmaskfineness' => { 109 => 0x9a }, + 'portraitunsharpmaskstrength' => { 109 => 0x98 }, + 'portraitunsharpmaskthreshold' => { 109 => 0x9c }, + 'portraitversion' => { 461 => 'PortraitVersion' }, + 'pose' => { 458 => 'Pose' }, + 'poseheadingdegrees' => { 466 => 'PoseHeadingDegrees' }, + 'posepitchdegrees' => { 466 => 'PosePitchDegrees' }, + 'posepositionx' => { 458 => [\'Pose','PosePositionX'] }, + 'posepositiony' => { 458 => [\'Pose','PosePositionY'] }, + 'posepositionz' => { 458 => [\'Pose','PosePositionZ'] }, + 'poserolldegrees' => { 466 => 'PoseRollDegrees' }, + 'poserotationw' => { 458 => [\'Pose','PoseRotationW'] }, + 'poserotationx' => { 458 => [\'Pose','PoseRotationX'] }, + 'poserotationy' => { 458 => [\'Pose','PoseRotationY'] }, + 'poserotationz' => { 458 => [\'Pose','PoseRotationZ'] }, + 'posetimestamp' => { 458 => [\'Pose','PoseTimestamp'] }, + 'positiondescriptor' => { 493 => 'positionDescriptor' }, + 'postalcode' => { 161 => 'PostalCode' }, + 'postcropvignetteamount' => { 478 => 'PostCropVignetteAmount', 480 => 'PostCropVignetteAmount' }, + 'postcropvignettefeather' => { 478 => 'PostCropVignetteFeather', 480 => 'PostCropVignetteFeather' }, + 'postcropvignettehighlightcontrast' => { 478 => 'PostCropVignetteHighlightContrast', 480 => 'PostCropVignetteHighlightContrast' }, + 'postcropvignettemidpoint' => { 478 => 'PostCropVignetteMidpoint', 480 => 'PostCropVignetteMidpoint' }, + 'postcropvignetteroundness' => { 478 => 'PostCropVignetteRoundness', 480 => 'PostCropVignetteRoundness' }, + 'postcropvignettestyle' => { 478 => 'PostCropVignetteStyle', 480 => 'PostCropVignetteStyle' }, + 'postfocusmerging' => { 320 => 0xbf }, + 'potentialface1position' => { 417 => 0xb }, + 'potentialface2position' => { 417 => 0x15 }, + 'potentialface3position' => { 417 => 0x1f }, + 'potentialface4position' => { 417 => 0x29 }, + 'potentialface5position' => { 417 => 0x33 }, + 'potentialface6position' => { 417 => 0x3d }, + 'potentialface7position' => { 417 => 0x47 }, + 'potentialface8position' => { 417 => 0x51 }, + 'powersource' => { 334 => '0.1' }, + 'poweruptime' => { 226 => 0xb6 }, + 'preaf' => { 126 => '0.2' }, + 'precaptureframes' => { 302 => 0x300 }, + 'predictor' => { 119 => 0x13d }, + 'preflashreturnstrength' => { 245 => 0x28a }, + 'prefs' => { 131 => 0xdd, 367 => 'Prefs' }, + 'prereadfastresetcount' => { 138 => 0x187e }, + 'preservedfilename' => { 505 => 'PreservedFileName' }, + 'preservedspecimen' => { 118 => 'PreservedSpecimen' }, + 'preservedspecimenmaterialsampleid' => { 118 => [\'PreservedSpecimen','PreservedSpecimenMaterialSampleID'] }, + 'presettype' => { 478 => 'PresetType', 480 => 'PresetType' }, + 'presetwhitebalance' => { 184 => 0x24, 455 => 0x8002 }, + 'presetwhitebalanceadj' => { 455 => 0x8014 }, + 'pressure' => { 119 => 0x9402, 485 => 'Pressure' }, + 'previewapplicationname' => { 119 => 0xc716 }, + 'previewapplicationversion' => { 119 => 0xc717 }, + 'previewbutton' => { 279 => ['14.1','15.1'], 280 => '15.1', 282 => '15.1', 283 => '15.1', 288 => '29.1', 289 => '14.1', 292 => '15.1', 293 => '15.1' }, + 'previewbuttonplusdials' => { 279 => ['14.2','15.2'], 280 => '15.2', 282 => '43.1', 283 => '43.1', 288 => '31.2', 292 => '43.1', 293 => '43.1' }, + 'previewcolorspace' => { 119 => 0xc71a }, + 'previewcropbottom' => { 366 => 0xef }, + 'previewcropleft' => { 366 => 0xec }, + 'previewcropright' => { 366 => 0xee }, + 'previewcroptop' => { 366 => 0xed }, + 'previewdate' => { 378 => 0x0 }, + 'previewdatetime' => { 119 => 0xc71b }, + 'previewimage' => { 113 => 0x2000, 114 => 'Exif-PreviewImage', 120 => 'PreviewImage', 122 => 0x4, 166 => 'data', 186 => 0x81, 302 => 0x280, 318 => 0x300, 380 => 'mcvr', 420 => 0x2001 }, + 'previewimageborders' => { 355 => 0x3e }, + 'previewimageheight' => { 73 => 0x4, 142 => 0xfa58 }, + 'previewimagelength' => { 73 => 0x2, 113 => 0x3, 119 => [0x117,0x202], 186 => 0x89, 234 => 0x202, 297 => 0x102, 302 => 0x1037, 355 => 0x3, 386 => 0x1e, 391 => 0x3, 397 => [0x1b,0x1d], 410 => 0x202 }, + 'previewimagename' => { 166 => '1Name' }, + 'previewimagesize' => { 113 => 0x2, 147 => 0x2, 166 => 'ImageSize', 355 => 0x2, 397 => [0x1c,0x1e], 420 => 0xb02c, 455 => 0x9012 }, + 'previewimagestart' => { 73 => 0x5, 113 => 0x4, 119 => [0x111,0x201], 186 => 0x88, 234 => 0x201, 297 => 0x101, 302 => 0x1036, 355 => 0x4, 386 => 0x1c, 391 => 0x2, 397 => [0x1a,0x1c], 410 => 0x201 }, + 'previewimagetype' => { 166 => '0Type' }, + 'previewimagevalid' => { 297 => 0x100, 302 => 0x1035 }, + 'previewimagewidth' => { 73 => 0x3, 142 => 0xfa57 }, + 'previewquality' => { 73 => 0x1 }, + 'previewsettingsdigest' => { 119 => 0xc719 }, + 'previewsettingsname' => { 119 => 0xc718 }, + 'primaryafpoint' => { 193 => [0x38,0x44,0x7] }, + 'primarychromaticities' => { 119 => 0x13f, 500 => 'PrimaryChromaticities' }, + 'primaryftp' => { 468 => 'PrimaryFTP' }, + 'primaryslot' => { 248 => 0xe7f, 258 => 0xfbf }, + 'printim' => { 119 => 0xc4a5 }, + 'prioritysetinawb' => { 420 => 0x202b }, + 'prioritysetupshutterrelease' => { 184 => 0x1d, 407 => 0x28 }, + 'privatertkinfo' => { 470 => 'privateRTKInfo' }, + 'processbordercolsleft' => { 138 => 0xc61 }, + 'processbordercolsright' => { 138 => 0xc62 }, + 'processborderrowsbottom' => { 138 => 0xc64 }, + 'processborderrowstop' => { 138 => 0xc63 }, + 'processingsoftware' => { 119 => 0xb }, + 'processversion' => { 478 => 'ProcessVersion', 480 => 'ProcessVersion' }, + 'producer' => { 179 => 'WM/Producer', 306 => 'Producer', 372 => "\xa9prd", 374 => 'producer', 380 => "\xa9prd", 491 => 'Producer' }, + 'producerkeywords' => { 380 => "\xa9pdk" }, + 'productcode' => { 494 => 'productCode' }, + 'productid' => { 132 => 0x32, 372 => 'prID', 493 => 'productID' }, + 'productidtype' => { 493 => 'productIDType' }, + 'productinimage' => { 490 => 'ProductInImage' }, + 'productinimagedescription' => { 490 => [\'ProductInImage','ProductInImageProductDescription'] }, + 'productinimagegtin' => { 490 => [\'ProductInImage','ProductInImageProductGTIN'] }, + 'productinimagename' => { 490 => [\'ProductInImage','ProductInImageProductName'] }, + 'productioncode' => { 335 => 0x2 }, + 'productorserviceconstraints' => { 307 => 'ProductOrServiceConstraints' }, + 'productversion' => { 372 => 'VERS' }, + 'profession' => { 494 => 'profession' }, + 'profile' => { 458 => [\'Profiles','ProfilesProfile'] }, + 'profilecalibrationsig' => { 119 => 0xc6f4 }, + 'profilecameraindices' => { 458 => [\'Profiles','ProfilesProfileCameraIndices'] }, + 'profilecopyright' => { 119 => 0xc6fe }, + 'profileembedpolicy' => { 119 => 0xc6fd }, + 'profilegaintablemap' => { 119 => 0xcd2d }, + 'profilehuesatmapdata1' => { 119 => 0xc6fa }, + 'profilehuesatmapdata2' => { 119 => 0xc6fb }, + 'profilehuesatmapdata3' => { 119 => 0xcd39 }, + 'profilehuesatmapdims' => { 119 => 0xc6f9 }, + 'profilehuesatmapencoding' => { 119 => 0xc7a3 }, + 'profilelooktabledata' => { 119 => 0xc726 }, + 'profilelooktabledims' => { 119 => 0xc725 }, + 'profilelooktableencoding' => { 119 => 0xc7a4 }, + 'profilename' => { 119 => 0xc6f8, 308 => 'iCCP-name' }, + 'profiles' => { 458 => 'Profiles' }, + 'profiletonecurve' => { 119 => 0xc6fc }, + 'profiletype' => { 458 => [\'Profiles','ProfilesProfileType'] }, + 'programiso' => { 320 => 0x3c }, + 'programline' => { 336 => '1.1' }, + 'programmode' => { 189 => 0x5 }, + 'programshift' => { 226 => 0xd }, + 'programversion' => { 131 => 0x46 }, + 'prohibits' => { 476 => 'prohibits' }, + 'projectiontype' => { 466 => 'ProjectionType', 467 => 'ProjectionType' }, + 'projectname' => { 504 => 'projectName' }, + 'projectref' => { 504 => 'projectRef' }, + 'projectrefpath' => { 504 => [\'projectRef','projectRefPath'] }, + 'projectreftype' => { 504 => [\'projectRef','projectRefType'] }, + 'promotionurl' => { 179 => 'WM/PromotionURL' }, + 'propertyreleaseid' => { 307 => 'PropertyReleaseID' }, + 'propertyreleasestatus' => { 307 => 'PropertyReleaseStatus' }, + 'provider' => { 179 => 'WM/Provider' }, + 'province-state' => { 131 => 0x5f }, + 'publicationdate' => { 494 => 'publicationDate' }, + 'publicationdatea-platform' => { 494 => [\'publicationDate','publicationDateA-platform'] }, + 'publicationdatedate' => { 494 => [\'publicationDate','publicationDateDate'] }, + 'publicationdisplaydate' => { 494 => 'publicationDisplayDate' }, + 'publicationdisplaydatea-platform' => { 494 => [\'publicationDisplayDate','publicationDisplayDateA-platform'] }, + 'publicationdisplaydatedate' => { 494 => [\'publicationDisplayDate','publicationDisplayDateDate'] }, + 'publicationevent' => { 490 => 'PublicationEvent' }, + 'publicationeventdate' => { 490 => [\'PublicationEvent','PublicationEventDate'] }, + 'publicationeventidentifier' => { 490 => [\'PublicationEvent','PublicationEventIdentifier'] }, + 'publicationeventname' => { 490 => [\'PublicationEvent','PublicationEventName'] }, + 'publicationname' => { 494 => 'publicationName' }, + 'publisher' => { 179 => 'WM/Publisher', 372 => "\xa9pub", 374 => 'publisher', 481 => 'publisher' }, + 'publishingfrequency' => { 494 => 'publishingFrequency' }, + 'pulldown' => { 504 => 'pullDown' }, + 'purchasedate' => { 372 => 'purd' }, + 'purplehsl' => { 103 => 0x20916 }, + 'pxshiftperiphedgenr' => { 455 => 0x9013 }, + 'pxshiftperiphedgenrvalue' => { 455 => 0x9014 }, + 'quality' => { 0 => 0x1, 34 => 0x3, 112 => 0x2, 113 => 0x3002, 127 => 0x1000, 140 => 0x9, 226 => 0x4, 262 => 0x3, 302 => 0x201, 315 => 0x300, 355 => 0x8, 362 => 0x2, 397 => 0x16, 407 => 0x56, 408 => 0x56, 409 => 0xb, 420 => [0x102,0x202e] }, + 'quality2' => { 429 => 0x1170, 430 => 0x1174, 431 => 0x1150, 433 => 0x11a8, 434 => 0x1060, 435 => 0x258, 436 => 0x258, 437 => 0x247, 442 => 0x29, 443 => 0x25, 444 => 0x2a }, + 'qualitybutton' => { 295 => 0x17d }, + 'qualitybuttonplaybackmode' => { 295 => 0x1bf }, + 'qualitymode' => { 113 => 0x8 }, + 'quantizationmethod' => { 133 => 0x78 }, + 'quickadjust' => { 275 => 0x2a }, + 'quickcontroldialinmeter' => { 84 => 0x703 }, + 'quickfix' => { 272 => 0x416391c6 }, + 'quickshot' => { 396 => 0x213 }, + 'quiettime' => { 138 => 0x188a }, + 'rads' => { 380 => 'rads' }, + 'rangefinder' => { 284 => '4.1', 285 => '5.1', 286 => '5.1' }, + 'rangemask' => { 478 => 'RangeMaskMapInfo', 480 => 'RangeMaskMapInfo' }, + 'rangemaskmapinfo' => { 478 => [\'RangeMaskMapInfo','RangeMaskMapInfoRangeMaskMapInfo'], 480 => [\'RangeMaskMapInfo','RangeMaskMapInfoRangeMaskMapInfo'] }, + 'rangemaskmapinfolabmax' => { 478 => [\'RangeMaskMapInfo','RangeMaskMapInfoRangeMaskMapInfoLabMax'], 480 => [\'RangeMaskMapInfo','RangeMaskMapInfoRangeMaskMapInfoLabMax'] }, + 'rangemaskmapinfolabmin' => { 478 => [\'RangeMaskMapInfo','RangeMaskMapInfoRangeMaskMapInfoLabMin'], 480 => [\'RangeMaskMapInfo','RangeMaskMapInfoRangeMaskMapInfoLabMin'] }, + 'rangemaskmapinfolumeq' => { 478 => [\'RangeMaskMapInfo','RangeMaskMapInfoRangeMaskMapInfoLumEq'], 480 => [\'RangeMaskMapInfo','RangeMaskMapInfoRangeMaskMapInfoLumEq'] }, + 'rangemaskmapinforgbmax' => { 478 => [\'RangeMaskMapInfo','RangeMaskMapInfoRangeMaskMapInfoRGBMax'], 480 => [\'RangeMaskMapInfo','RangeMaskMapInfoRangeMaskMapInfoRGBMax'] }, + 'rangemaskmapinforgbmin' => { 478 => [\'RangeMaskMapInfo','RangeMaskMapInfoRangeMaskMapInfoRGBMin'], 480 => [\'RangeMaskMapInfo','RangeMaskMapInfoRangeMaskMapInfoRGBMin'] }, + 'rasterizedcaption' => { 131 => 0x7d }, + 'rating' => { 119 => 0x4746, 127 => 0x1431, 366 => 0xdf, 372 => 'rtng', 380 => 'rtng', 420 => 0x2002, 473 => 'rating', 482 => 'rating', 490 => 'Rating', 494 => 'rating', 502 => 'Rating' }, + 'ratingpercent' => { 119 => 0x4749, 178 => 'Rating', 372 => 'rate', 502 => 'RatingPercent' }, + 'ratingregion' => { 490 => [\'Rating','RatingRatingRegion'] }, + 'ratingregioncity' => { 490 => [\'Rating','RatingRatingRegionCity'] }, + 'ratingregioncountrycode' => { 490 => [\'Rating','RatingRatingRegionCountryCode'] }, + 'ratingregioncountryname' => { 490 => [\'Rating','RatingRatingRegionCountryName'] }, + 'ratingregiongpsaltitude' => { 490 => [\'Rating','RatingRatingRegionGPSAltitude'] }, + 'ratingregiongpslatitude' => { 490 => [\'Rating','RatingRatingRegionGPSLatitude'] }, + 'ratingregiongpslongitude' => { 490 => [\'Rating','RatingRatingRegionGPSLongitude'] }, + 'ratingregionidentifier' => { 490 => [\'Rating','RatingRatingRegionIdentifier'] }, + 'ratingregionlocationid' => { 490 => [\'Rating','RatingRatingRegionLocationId'] }, + 'ratingregionlocationname' => { 490 => [\'Rating','RatingRatingRegionLocationName'] }, + 'ratingregionprovincestate' => { 490 => [\'Rating','RatingRatingRegionProvinceState'] }, + 'ratingregionsublocation' => { 490 => [\'Rating','RatingRatingRegionSublocation'] }, + 'ratingregionworldregion' => { 490 => [\'Rating','RatingRatingRegionWorldRegion'] }, + 'ratingscalemaxvalue' => { 490 => [\'Rating','RatingRatingScaleMaxValue'] }, + 'ratingscaleminvalue' => { 490 => [\'Rating','RatingRatingScaleMinValue'] }, + 'ratingsourcelink' => { 490 => [\'Rating','RatingRatingSourceLink'] }, + 'ratingvalue' => { 490 => [\'Rating','RatingRatingValue'] }, + 'ratingvaluelogolink' => { 490 => [\'Rating','RatingRatingValueLogoLink'] }, + 'rawandjpgrecording' => { 82 => 0x8, 186 => 0x109, 336 => 0xd }, + 'rawbrightnessadj' => { 103 => 0x20001, 108 => 0x38 }, + 'rawburstimagecount' => { 75 => 0x2 }, + 'rawburstimagenum' => { 75 => 0x1 }, + 'rawcoloradj' => { 108 => 0x2e }, + 'rawcropbottom' => { 366 => 0xd4 }, + 'rawcropleft' => { 366 => 0xd1 }, + 'rawcropright' => { 366 => 0xd3 }, + 'rawcroptop' => { 366 => 0xd2 }, + 'rawcustomsaturation' => { 108 => 0x30 }, + 'rawcustomtone' => { 108 => 0x34 }, + 'rawdata' => { 394 => 0xa048 }, + 'rawdatabyteorder' => { 394 => 0x40 }, + 'rawdatacfapattern' => { 394 => 0x50 }, + 'rawdatauniqueid' => { 119 => 0xc65d }, + 'rawdepth' => { 188 => 0x10 }, + 'rawdevartfilter' => { 304 => 0x121 }, + 'rawdevautogradation' => { 304 => 0x119 }, + 'rawdevcolorspace' => { 303 => 0x108, 304 => 0x109 }, + 'rawdevcontrastvalue' => { 303 => 0x106, 304 => 0x105 }, + 'rawdeveditstatus' => { 303 => 0x10b }, + 'rawdevelopmentprocess' => { 355 => 0x62 }, + 'rawdevengine' => { 303 => 0x109, 304 => 0x10b }, + 'rawdevexposurebiasvalue' => { 303 => 0x100, 304 => 0x100 }, + 'rawdevgradation' => { 304 => 0x112 }, + 'rawdevgraypoint' => { 303 => 0x103, 304 => 0x104 }, + 'rawdevmemorycoloremphasis' => { 303 => 0x105, 304 => 0x108 }, + 'rawdevnoisereduction' => { 303 => 0x10a, 304 => 0x10a }, + 'rawdevpicturemode' => { 304 => 0x10c }, + 'rawdevpm_bwfilter' => { 304 => 0x110 }, + 'rawdevpmcontrast' => { 304 => 0x10e }, + 'rawdevpmnoisefilter' => { 304 => 0x120 }, + 'rawdevpmpicturetone' => { 304 => 0x111 }, + 'rawdevpmsaturation' => { 304 => 0x10d }, + 'rawdevpmsharpness' => { 304 => 0x10f }, + 'rawdevsaturation3' => { 304 => 0x113 }, + 'rawdevsaturationemphasis' => { 303 => 0x104, 304 => 0x107 }, + 'rawdevsettings' => { 303 => 0x10c }, + 'rawdevsharpnessvalue' => { 303 => 0x107, 304 => 0x106 }, + 'rawdevversion' => { 303 => 0x0, 304 => 0x0 }, + 'rawdevwbfineadjustment' => { 303 => 0x102, 304 => 0x103 }, + 'rawdevwhitebalance' => { 304 => 0x101 }, + 'rawdevwhitebalancevalue' => { 303 => 0x101, 304 => 0x102 }, + 'rawfile' => { 119 => 0xfe4c }, + 'rawfilename' => { 478 => 'RawFileName', 480 => 'RawFileName' }, + 'rawfiletype' => { 420 => 0x2029 }, + 'rawformat' => { 325 => 0x2d, 364 => 0x10e }, + 'rawimagecenter' => { 226 => 0x99 }, + 'rawimagedigest' => { 119 => 0xc71c }, + 'rawimagesize' => { 355 => 0x39 }, + 'rawinfoversion' => { 305 => 0x0 }, + 'rawjpgheight' => { 99 => 0x4 }, + 'rawjpgquality' => { 57 => 0x6, 99 => 0x1 }, + 'rawjpgsize' => { 57 => 0x7, 99 => 0x2 }, + 'rawjpgwidth' => { 99 => 0x3 }, + 'rawmeasuredrggb' => { 43 => 0x26a, 45 => 0x280, 47 => 0x194, 48 => [0x1ad,0x26b] }, + 'rawrppused' => { 473 => 'rawrppused' }, + 'rawtopreviewgain' => { 119 => 0xc7a8 }, + 'readouttypeactual' => { 138 => 0x1903 }, + 'readouttyperequested' => { 138 => 0x1902 }, + 'reardisplay' => { 279 => '12.3', 280 => '6.2' }, + 'recdevice' => { 490 => 'RecDevice' }, + 'recdeviceattlensdescription' => { 490 => [\'RecDevice','RecDeviceAttLensDescription'] }, + 'recdevicemanufacturer' => { 490 => [\'RecDevice','RecDeviceManufacturer'] }, + 'recdevicemodelname' => { 490 => [\'RecDevice','RecDeviceModelName'] }, + 'recdeviceownersdeviceid' => { 490 => [\'RecDevice','RecDeviceOwnersDeviceId'] }, + 'recdeviceserialnumber' => { 490 => [\'RecDevice','RecDeviceSerialNumber'] }, + 'recipeendingpage' => { 496 => 'recipeEndingPage' }, + 'recipepagerange' => { 496 => 'recipePageRange' }, + 'recipesource' => { 496 => 'recipeSource' }, + 'recipestartingpage' => { 496 => 'recipeStartingPage' }, + 'recipetitle' => { 496 => 'recipeTitle' }, + 'recognizedface1age' => { 313 => 0x20 }, + 'recognizedface1name' => { 313 => 0x4 }, + 'recognizedface1position' => { 313 => 0x18 }, + 'recognizedface2age' => { 313 => 0x50 }, + 'recognizedface2name' => { 313 => 0x34 }, + 'recognizedface2position' => { 313 => 0x48 }, + 'recognizedface3age' => { 313 => 0x80 }, + 'recognizedface3name' => { 313 => 0x64 }, + 'recognizedface3position' => { 313 => 0x78 }, + 'recognizedfaceflags' => { 320 => 0x63 }, + 'recommendedexposureindex' => { 119 => 0x8832, 485 => 'RecommendedExposureIndex' }, + 'record' => { 118 => 'Record' }, + 'recordbasisofrecord' => { 118 => [\'Record','RecordBasisOfRecord'] }, + 'recordcollectioncode' => { 118 => [\'Record','RecordCollectionCode'] }, + 'recordcollectionid' => { 118 => [\'Record','RecordCollectionID'] }, + 'recorddatageneralizations' => { 118 => [\'Record','RecordDataGeneralizations'] }, + 'recorddatasetid' => { 118 => [\'Record','RecordDatasetID'] }, + 'recorddatasetname' => { 118 => [\'Record','RecordDatasetName'] }, + 'recorddisplay' => { 184 => 0x4d }, + 'recorddynamicproperties' => { 118 => [\'Record','RecordDynamicProperties'] }, + 'recordid' => { 97 => 0x1804 }, + 'recordinformationwithheld' => { 118 => [\'Record','RecordInformationWithheld'] }, + 'recordingcopyright' => { 380 => "\xa9phg" }, + 'recordingformat' => { 387 => 0x1000 }, + 'recordingmode' => { 112 => 0x1, 362 => 0x1 }, + 'recordinstitutioncode' => { 118 => [\'Record','RecordInstitutionCode'] }, + 'recordinstitutionid' => { 118 => [\'Record','RecordInstitutionID'] }, + 'recordlabelname' => { 380 => "\xa9lab" }, + 'recordlabelurl' => { 380 => "\xa9lal" }, + 'recordlocationdata' => { 229 => 0x660 }, + 'recordmode' => { 34 => 0x9, 113 => 0x3000 }, + 'recordownerinstitutioncode' => { 118 => [\'Record','RecordOwnerInstitutionCode'] }, + 'recordshutterrelease' => { 396 => 0x217 }, + 'redbalance' => { 302 => 0x1017, 325 => 0x11, 355 => 0x1c }, + 'redcurvelimits' => { 108 => 0x18a }, + 'redcurvepoints' => { 107 => 0x2d, 108 => 0x160 }, + 'redeyecorrection' => { 276 => 0x0 }, + 'redeyeinfo' => { 478 => 'RedEyeInfo', 480 => 'RedEyeInfo' }, + 'redeyereduction' => { 184 => 0x41, 407 => 0x6a, 409 => 0x28 }, + 'redeyeremoval' => { 320 => 0xb9 }, + 'redhsl' => { 103 => 0x20910 }, + 'redhue' => { 478 => 'RedHue', 480 => 'RedHue' }, + 'redsaturation' => { 478 => 'RedSaturation', 480 => 'RedSaturation' }, + 'reductionmatrix1' => { 119 => 0xc625 }, + 'reductionmatrix2' => { 119 => 0xc626 }, + 'reductionmatrix3' => { 119 => 0xcd3a }, + 'reelname' => { 119 => 0xc789, 380 => 'reel' }, + 'reference1' => { 488 => [\'TagStructure','TagStructureReference'] }, + 'reference2' => { 488 => [\'TagStructure','TagStructureSubLabelsReference'] }, + 'reference3' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsReference'] }, + 'reference4' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsReference'] }, + 'reference5' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsReference'] }, + 'reference6' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsSubLabelsReference'] }, + 'referenceblackwhite' => { 119 => 0x214, 500 => 'ReferenceBlackWhite' }, + 'referencedate' => { 131 => 0x2f }, + 'referencenumber' => { 131 => 0x32 }, + 'references' => { 157 => 'References' }, + 'referenceservice' => { 131 => 0x2d }, + 'regionappliedtodimensions' => { 172 => [\'Regions','RegionsAppliedToDimensions'] }, + 'regionappliedtodimensionsh' => { 172 => [\'Regions','RegionsAppliedToDimensionsH'] }, + 'regionappliedtodimensionsunit' => { 172 => [\'Regions','RegionsAppliedToDimensionsUnit'] }, + 'regionappliedtodimensionsw' => { 172 => [\'Regions','RegionsAppliedToDimensionsW'] }, + 'regionarea' => { 172 => [\'Regions','RegionsRegionListArea'] }, + 'regionaread' => { 172 => [\'Regions','RegionsRegionListAreaD'] }, + 'regionareah' => { 172 => [\'Regions','RegionsRegionListAreaH'] }, + 'regionareaunit' => { 172 => [\'Regions','RegionsRegionListAreaUnit'] }, + 'regionareaw' => { 172 => [\'Regions','RegionsRegionListAreaW'] }, + 'regionareax' => { 172 => [\'Regions','RegionsRegionListAreaX'] }, + 'regionareay' => { 172 => [\'Regions','RegionsRegionListAreaY'] }, + 'regionbarcodevalue' => { 172 => [\'Regions','RegionsRegionListBarCodeValue'] }, + 'regionconstraints' => { 307 => 'RegionConstraints' }, + 'regiondescription' => { 172 => [\'Regions','RegionsRegionListDescription'] }, + 'regionextensions' => { 172 => [\'Regions','RegionsRegionListExtensions'] }, + 'regionfocususage' => { 172 => [\'Regions','RegionsRegionListFocusUsage'] }, + 'regioninfo' => { 172 => 'Regions' }, + 'regioninfodateregionsvalid' => { 175 => [\'RegionInfo','RegionInfoDateRegionsValid'] }, + 'regioninfomp' => { 175 => 'RegionInfo' }, + 'regioninforegions' => { 175 => [\'RegionInfo','RegionInfoRegions'] }, + 'regionlist' => { 172 => [\'Regions','RegionsRegionList'] }, + 'regionname' => { 172 => [\'Regions','RegionsRegionListName'] }, + 'regionpersondisplayname' => { 175 => [\'RegionInfo','RegionInfoRegionsPersonDisplayName'] }, + 'regionpersonemaildigest' => { 175 => [\'RegionInfo','RegionInfoRegionsPersonEmailDigest'] }, + 'regionpersonliveidcid' => { 175 => [\'RegionInfo','RegionInfoRegionsPersonLiveIdCID'] }, + 'regionpersonsourceid' => { 175 => [\'RegionInfo','RegionInfoRegionsPersonSourceID'] }, + 'regionrectangle' => { 175 => [\'RegionInfo','RegionInfoRegionsRectangle'] }, + 'regionrotation' => { 172 => [\'Regions','RegionsRegionListRotation'] }, + 'regionseealso' => { 172 => [\'Regions','RegionsRegionListSeeAlso'] }, + 'regiontype' => { 172 => [\'Regions','RegionsRegionListType'] }, + 'registryentryrole' => { 490 => [\'RegistryId','RegistryIdRegEntryRole'] }, + 'registryid' => { 490 => 'RegistryId' }, + 'registryitemid' => { 490 => [\'RegistryId','RegistryIdRegItemId'] }, + 'registryorganisationid' => { 490 => [\'RegistryId','RegistryIdRegOrgId'] }, + 'relatedaudiofile' => { 155 => 'data' }, + 'relatedaudiofilename' => { 155 => '1Name' }, + 'relatedaudiofiletype' => { 155 => '0Type' }, + 'relatedimagefileformat' => { 119 => 0x1000 }, + 'relatedimageheight' => { 119 => 0x1002 }, + 'relatedimagewidth' => { 119 => 0x1001 }, + 'relatedresourceid' => { 118 => [\'ResourceRelationship','ResourceRelationshipRelatedResourceID'] }, + 'relatedsoundfile' => { 119 => 0xa004, 484 => 'RelatedSoundFile' }, + 'relatedvideofile' => { 169 => 'data' }, + 'relatedvideofilename' => { 169 => '1Name' }, + 'relatedvideofiletype' => { 169 => '0Type' }, + 'relation' => { 481 => 'relation' }, + 'relationshipaccordingto' => { 118 => [\'ResourceRelationship','ResourceRelationshipRelationshipAccordingTo'] }, + 'relationshipestablisheddate' => { 118 => [\'ResourceRelationship','ResourceRelationshipRelationshipEstablishedDate'] }, + 'relationshipofresource' => { 118 => [\'ResourceRelationship','ResourceRelationshipRelationshipOfResource'] }, + 'relationshipofresourceid' => { 118 => [\'ResourceRelationship','ResourceRelationshipRelationshipOfResourceID'] }, + 'relationshipremarks' => { 118 => [\'ResourceRelationship','ResourceRelationshipRelationshipRemarks'] }, + 'relativealtitude' => { 116 => 'RelativeAltitude' }, + 'relativepeakaudiofilepath' => { 504 => 'relativePeakAudioFilePath' }, + 'relativetimestamp' => { 504 => 'relativeTimestamp' }, + 'relativetimestampscale' => { 504 => [\'relativeTimestamp','relativeTimestampScale'] }, + 'relativetimestampvalue' => { 504 => [\'relativeTimestamp','relativeTimestampValue'] }, + 'releasebuttontousedial' => { 279 => '17.8', 280 => '18.5', 282 => '18.4', 283 => '18.4', 288 => '33.8', 289 => '17.6', 292 => '18.5', 293 => '18.4' }, + 'releasedate' => { 131 => 0x1e, 372 => 'rldt', 473 => 'ReleaseDate', 504 => 'releaseDate' }, + 'releasemode' => { 113 => 0x3001, 247 => 0x184d, 420 => 0xb049 }, + 'releasemode2' => { 429 => 0x112c, 430 => [0x112c,0x8], 431 => [0x1108,0x8], 432 => [0x1184,0x8], 433 => [0x1160,0x8], 434 => [0x4,0x1018], 435 => [0x4,0x210], 436 => [0x4,0x210], 437 => [0x4,0x208], 439 => [0x67,0x3f], 440 => [0x6b,0x6d,0x73,0x4b], 441 => [0x6b,0x4b], 442 => 0x10, 443 => 0x10, 444 => 0x9, 451 => 0x34 }, + 'releasemode3' => { 429 => 0x1128, 430 => 0x1128, 431 => 0x1104, 432 => 0x1180, 433 => 0x115c, 434 => 0x1014, 435 => 0x20c, 436 => 0x20c, 437 => 0x204 }, + 'releaseready' => { 490 => 'ReleaseReady' }, + 'releasesetting' => { 97 => 0x1016 }, + 'releasetime' => { 131 => 0x23, 473 => 'ReleaseTime' }, + 'remoteonduration' => { 281 => '3.4', 284 => '17.2', 285 => '18.2', 286 => '18.2', 287 => '18.2', 289 => '18.2', 290 => '4.3', 294 => '19.2' }, + 'renditionclass' => { 505 => 'RenditionClass' }, + 'renditionof' => { 505 => 'RenditionOf' }, + 'renditionofalternatepaths' => { 505 => [\'RenditionOf','RenditionOfAlternatePaths'] }, + 'renditionofdocumentid' => { 505 => [\'RenditionOf','RenditionOfDocumentID'] }, + 'renditionoffilepath' => { 505 => [\'RenditionOf','RenditionOfFilePath'] }, + 'renditionoffrompart' => { 505 => [\'RenditionOf','RenditionOfFromPart'] }, + 'renditionofinstanceid' => { 505 => [\'RenditionOf','RenditionOfInstanceID'] }, + 'renditionoflastmodifydate' => { 505 => [\'RenditionOf','RenditionOfLastModifyDate'] }, + 'renditionoflasturl' => { 505 => [\'RenditionOf','RenditionOfLastURL'] }, + 'renditionoflinkcategory' => { 505 => [\'RenditionOf','RenditionOfLinkCategory'] }, + 'renditionoflinkform' => { 505 => [\'RenditionOf','RenditionOfLinkForm'] }, + 'renditionofmanager' => { 505 => [\'RenditionOf','RenditionOfManager'] }, + 'renditionofmanagervariant' => { 505 => [\'RenditionOf','RenditionOfManagerVariant'] }, + 'renditionofmanageto' => { 505 => [\'RenditionOf','RenditionOfManageTo'] }, + 'renditionofmanageui' => { 505 => [\'RenditionOf','RenditionOfManageUI'] }, + 'renditionofmaskmarkers' => { 505 => [\'RenditionOf','RenditionOfMaskMarkers'] }, + 'renditionoforiginaldocumentid' => { 505 => [\'RenditionOf','RenditionOfOriginalDocumentID'] }, + 'renditionofpartmapping' => { 505 => [\'RenditionOf','RenditionOfPartMapping'] }, + 'renditionofplacedresolutionunit' => { 505 => [\'RenditionOf','RenditionOfPlacedResolutionUnit'] }, + 'renditionofplacedxresolution' => { 505 => [\'RenditionOf','RenditionOfPlacedXResolution'] }, + 'renditionofplacedyresolution' => { 505 => [\'RenditionOf','RenditionOfPlacedYResolution'] }, + 'renditionofrenditionclass' => { 505 => [\'RenditionOf','RenditionOfRenditionClass'] }, + 'renditionofrenditionparams' => { 505 => [\'RenditionOf','RenditionOfRenditionParams'] }, + 'renditionoftopart' => { 505 => [\'RenditionOf','RenditionOfToPart'] }, + 'renditionofversionid' => { 505 => [\'RenditionOf','RenditionOfVersionID'] }, + 'renditionparams' => { 505 => 'RenditionParams' }, + 'repeatingflashcount' => { 209 => 0xd, 210 => 0xe, 211 => 0xe, 212 => 0xe, 213 => 0xe, 288 => '17.2', 289 => '24.2', 290 => '9.2', 291 => '24.2', 294 => '25.2' }, + 'repeatingflashcountbuilt-in' => { 256 => 0x4db }, + 'repeatingflashcountexternal' => { 256 => 0x4c3 }, + 'repeatingflashoutput' => { 288 => '17.1', 289 => '24.1', 290 => '9.1', 291 => '24.1', 294 => '25.1' }, + 'repeatingflashoutputexternal' => { 256 => 0x4c0 }, + 'repeatingflashrate' => { 209 => 0xc, 210 => 0xd, 211 => 0xd, 212 => 0xd, 213 => 0xd, 288 => '18.1', 289 => '25.1', 290 => '10.1', 291 => '25.1', 294 => '26.1' }, + 'repeatingflashratebuilt-in' => { 256 => 0x4da }, + 'repeatingflashrateexternal' => { 256 => 0x4c2 }, + 'requirements' => { 380 => "\xa9req" }, + 'requires' => { 476 => 'requires' }, + 'resampleparams' => { 504 => 'resampleParams' }, + 'resampleparamsquality' => { 504 => [\'resampleParams','resampleParamsQuality'] }, + 'resamplingkerneldenominators050' => { 138 => 0xe50 }, + 'resamplingkerneldenominators067' => { 138 => 0xe4f }, + 'resamplingkerneldenominators100' => { 138 => 0xe51 }, + 'resaved' => { 396 => 0x21e }, + 'resetblacksegrows' => { 138 => 0x181a }, + 'resolution' => { 162 => 'Resolution' }, + 'resolutionmode' => { 397 => [0x87,0x4] }, + 'resolutionunit' => { 119 => 0x128, 134 => 0x2, 500 => 'ResolutionUnit' }, + 'resourceid' => { 118 => [\'ResourceRelationship','ResourceRelationshipResourceID'] }, + 'resourcerelationship' => { 118 => 'ResourceRelationship' }, + 'resourcerelationshipid' => { 118 => [\'ResourceRelationship','ResourceRelationshipResourceRelationshipID'] }, + 'restrictdrivemodes' => { 84 => 0x612 }, + 'restrictions' => { 497 => 'restrictions' }, + 'retouchareafeather' => { 478 => [\'RetouchAreas','RetouchAreasFeather'], 480 => [\'RetouchAreas','RetouchAreasFeather'] }, + 'retouchareamaskalpha' => { 478 => [\'RetouchAreas','RetouchAreasMasksAlpha'], 480 => [\'RetouchAreas','RetouchAreasMasksAlpha'] }, + 'retouchareamaskangle' => { 478 => [\'RetouchAreas','RetouchAreasMasksAngle'], 480 => [\'RetouchAreas','RetouchAreasMasksAngle'] }, + 'retouchareamaskbottom' => { 478 => [\'RetouchAreas','RetouchAreasMasksBottom'], 480 => [\'RetouchAreas','RetouchAreasMasksBottom'] }, + 'retouchareamaskcentervalue' => { 478 => [\'RetouchAreas','RetouchAreasMasksCenterValue'], 480 => [\'RetouchAreas','RetouchAreasMasksCenterValue'] }, + 'retouchareamaskcenterweight' => { 478 => [\'RetouchAreas','RetouchAreasMasksCenterWeight'], 480 => [\'RetouchAreas','RetouchAreasMasksCenterWeight'] }, + 'retouchareamaskdabs' => { 478 => [\'RetouchAreas','RetouchAreasMasksDabs'], 480 => [\'RetouchAreas','RetouchAreasMasksDabs'] }, + 'retouchareamaskfeather' => { 478 => [\'RetouchAreas','RetouchAreasMasksFeather'], 480 => [\'RetouchAreas','RetouchAreasMasksFeather'] }, + 'retouchareamaskflipped' => { 478 => [\'RetouchAreas','RetouchAreasMasksFlipped'], 480 => [\'RetouchAreas','RetouchAreasMasksFlipped'] }, + 'retouchareamaskflow' => { 478 => [\'RetouchAreas','RetouchAreasMasksFlow'], 480 => [\'RetouchAreas','RetouchAreasMasksFlow'] }, + 'retouchareamaskfullx' => { 478 => [\'RetouchAreas','RetouchAreasMasksFullX'], 480 => [\'RetouchAreas','RetouchAreasMasksFullX'] }, + 'retouchareamaskfully' => { 478 => [\'RetouchAreas','RetouchAreasMasksFullY'], 480 => [\'RetouchAreas','RetouchAreasMasksFullY'] }, + 'retouchareamaskinputdigest' => { 478 => [\'RetouchAreas','RetouchAreasMasksInputDigest'], 480 => [\'RetouchAreas','RetouchAreasMasksInputDigest'] }, + 'retouchareamaskleft' => { 478 => [\'RetouchAreas','RetouchAreasMasksLeft'], 480 => [\'RetouchAreas','RetouchAreasMasksLeft'] }, + 'retouchareamaskmaskactive' => { 478 => [\'RetouchAreas','RetouchAreasMasksMaskActive'], 480 => [\'RetouchAreas','RetouchAreasMasksMaskActive'] }, + 'retouchareamaskmaskblendmode' => { 478 => [\'RetouchAreas','RetouchAreasMasksMaskBlendMode'], 480 => [\'RetouchAreas','RetouchAreasMasksMaskBlendMode'] }, + 'retouchareamaskmaskdigest' => { 478 => [\'RetouchAreas','RetouchAreasMasksMaskDigest'], 480 => [\'RetouchAreas','RetouchAreasMasksMaskDigest'] }, + 'retouchareamaskmaskinverted' => { 478 => [\'RetouchAreas','RetouchAreasMasksMaskInverted'], 480 => [\'RetouchAreas','RetouchAreasMasksMaskInverted'] }, + 'retouchareamaskmaskname' => { 478 => [\'RetouchAreas','RetouchAreasMasksMaskName'], 480 => [\'RetouchAreas','RetouchAreasMasksMaskName'] }, + 'retouchareamaskmasks' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasks'], 480 => [\'RetouchAreas','RetouchAreasMasksMasks'] }, + 'retouchareamaskmasksalpha' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksAlpha'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksAlpha'] }, + 'retouchareamaskmasksangle' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksAngle'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksAngle'] }, + 'retouchareamaskmasksbottom' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksBottom'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksBottom'] }, + 'retouchareamaskmaskscentervalue' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksCenterValue'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksCenterValue'] }, + 'retouchareamaskmaskscenterweight' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksCenterWeight'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksCenterWeight'] }, + 'retouchareamaskmasksdabs' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksDabs'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksDabs'] }, + 'retouchareamaskmasksfeather' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksFeather'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksFeather'] }, + 'retouchareamaskmasksflipped' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksFlipped'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksFlipped'] }, + 'retouchareamaskmasksflow' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksFlow'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksFlow'] }, + 'retouchareamaskmasksfullx' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksFullX'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksFullX'] }, + 'retouchareamaskmasksfully' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksFullY'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksFullY'] }, + 'retouchareamaskmasksinputdigest' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksInputDigest'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksInputDigest'] }, + 'retouchareamaskmasksleft' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksLeft'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksLeft'] }, + 'retouchareamaskmasksmaskactive' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksMaskActive'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksMaskActive'] }, + 'retouchareamaskmasksmaskblendmode' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksMaskBlendMode'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksMaskBlendMode'] }, + 'retouchareamaskmasksmaskdigest' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksMaskDigest'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksMaskDigest'] }, + 'retouchareamaskmasksmaskinverted' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksMaskInverted'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksMaskInverted'] }, + 'retouchareamaskmasksmaskname' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksMaskName'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksMaskName'] }, + 'retouchareamaskmasksmasksubtype' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksMaskSubType'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksMaskSubType'] }, + 'retouchareamaskmasksmasksyncid' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksMaskSyncID'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksMaskSyncID'] }, + 'retouchareamaskmasksmaskversion' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksMaskVersion'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksMaskVersion'] }, + 'retouchareamaskmasksmidpoint' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksMidpoint'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksMidpoint'] }, + 'retouchareamaskmasksorigin' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksOrigin'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksOrigin'] }, + 'retouchareamaskmasksperimetervalue' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksPerimeterValue'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksPerimeterValue'] }, + 'retouchareamaskmasksradius' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksRadius'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksRadius'] }, + 'retouchareamaskmasksreferencepoint' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksReferencePoint'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksReferencePoint'] }, + 'retouchareamaskmasksright' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksRight'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksRight'] }, + 'retouchareamaskmasksroundness' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksRoundness'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksRoundness'] }, + 'retouchareamaskmaskssizex' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksSizeX'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksSizeX'] }, + 'retouchareamaskmaskssizey' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksSizeY'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksSizeY'] }, + 'retouchareamaskmaskstop' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksTop'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksTop'] }, + 'retouchareamaskmasksubtype' => { 478 => [\'RetouchAreas','RetouchAreasMasksMaskSubType'], 480 => [\'RetouchAreas','RetouchAreasMasksMaskSubType'] }, + 'retouchareamaskmasksvalue' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksMaskValue'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksMaskValue'] }, + 'retouchareamaskmasksversion' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksVersion'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksVersion'] }, + 'retouchareamaskmaskswhat' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksWhat'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksWhat'] }, + 'retouchareamaskmaskswholeimagearea' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksWholeImageArea'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksWholeImageArea'] }, + 'retouchareamaskmasksx' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksX'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksX'] }, + 'retouchareamaskmasksy' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksY'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksY'] }, + 'retouchareamaskmasksyncid' => { 478 => [\'RetouchAreas','RetouchAreasMasksMaskSyncID'], 480 => [\'RetouchAreas','RetouchAreasMasksMaskSyncID'] }, + 'retouchareamaskmaskszerox' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksZeroX'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksZeroX'] }, + 'retouchareamaskmaskszeroy' => { 478 => [\'RetouchAreas','RetouchAreasMasksMasksZeroY'], 480 => [\'RetouchAreas','RetouchAreasMasksMasksZeroY'] }, + 'retouchareamaskmaskversion' => { 478 => [\'RetouchAreas','RetouchAreasMasksMaskVersion'], 480 => [\'RetouchAreas','RetouchAreasMasksMaskVersion'] }, + 'retouchareamaskmidpoint' => { 478 => [\'RetouchAreas','RetouchAreasMasksMidpoint'], 480 => [\'RetouchAreas','RetouchAreasMasksMidpoint'] }, + 'retouchareamaskorigin' => { 478 => [\'RetouchAreas','RetouchAreasMasksOrigin'], 480 => [\'RetouchAreas','RetouchAreasMasksOrigin'] }, + 'retouchareamaskperimetervalue' => { 478 => [\'RetouchAreas','RetouchAreasMasksPerimeterValue'], 480 => [\'RetouchAreas','RetouchAreasMasksPerimeterValue'] }, + 'retouchareamaskradius' => { 478 => [\'RetouchAreas','RetouchAreasMasksRadius'], 480 => [\'RetouchAreas','RetouchAreasMasksRadius'] }, + 'retouchareamaskrange' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMask'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMask'] }, + 'retouchareamaskrangeareamodels' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskAreaModels'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskAreaModels'] }, + 'retouchareamaskrangeareamodelscolorsampleinfo' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskAreaModelsColorRangeMaskAreaSampleInfo'] }, + 'retouchareamaskrangeareamodelscomponents' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskAreaModelsAreaComponents'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskAreaModelsAreaComponents'] }, + 'retouchareamaskrangecoloramount' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskColorAmount'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskColorAmount'] }, + 'retouchareamaskrangedepthfeather' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskDepthFeather'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskDepthFeather'] }, + 'retouchareamaskrangedepthmax' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskDepthMax'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskDepthMax'] }, + 'retouchareamaskrangedepthmin' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskDepthMin'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskDepthMin'] }, + 'retouchareamaskrangeinvert' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskInvert'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskInvert'] }, + 'retouchareamaskrangelumfeather' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskLumFeather'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskLumFeather'] }, + 'retouchareamaskrangeluminancedepthsampleinfo' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskLuminanceDepthSampleInfo'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskLuminanceDepthSampleInfo'] }, + 'retouchareamaskrangelummax' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskLumMax'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskLumMax'] }, + 'retouchareamaskrangelummin' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskLumMin'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskLumMin'] }, + 'retouchareamaskrangelumrange' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskLumRange'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskLumRange'] }, + 'retouchareamaskrangesampletype' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskSampleType'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskSampleType'] }, + 'retouchareamaskrangetype' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskType'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskType'] }, + 'retouchareamaskrangeversion' => { 478 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskVersion'], 480 => [\'RetouchAreas','RetouchAreasMasksCorrectionRangeMaskVersion'] }, + 'retouchareamaskreferencepoint' => { 478 => [\'RetouchAreas','RetouchAreasMasksReferencePoint'], 480 => [\'RetouchAreas','RetouchAreasMasksReferencePoint'] }, + 'retouchareamaskright' => { 478 => [\'RetouchAreas','RetouchAreasMasksRight'], 480 => [\'RetouchAreas','RetouchAreasMasksRight'] }, + 'retouchareamaskroundness' => { 478 => [\'RetouchAreas','RetouchAreasMasksRoundness'], 480 => [\'RetouchAreas','RetouchAreasMasksRoundness'] }, + 'retouchareamasks' => { 478 => [\'RetouchAreas','RetouchAreasMasks'], 480 => [\'RetouchAreas','RetouchAreasMasks'] }, + 'retouchareamasksizex' => { 478 => [\'RetouchAreas','RetouchAreasMasksSizeX'], 480 => [\'RetouchAreas','RetouchAreasMasksSizeX'] }, + 'retouchareamasksizey' => { 478 => [\'RetouchAreas','RetouchAreasMasksSizeY'], 480 => [\'RetouchAreas','RetouchAreasMasksSizeY'] }, + 'retouchareamasktop' => { 478 => [\'RetouchAreas','RetouchAreasMasksTop'], 480 => [\'RetouchAreas','RetouchAreasMasksTop'] }, + 'retouchareamaskvalue' => { 478 => [\'RetouchAreas','RetouchAreasMasksMaskValue'], 480 => [\'RetouchAreas','RetouchAreasMasksMaskValue'] }, + 'retouchareamaskversion' => { 478 => [\'RetouchAreas','RetouchAreasMasksVersion'], 480 => [\'RetouchAreas','RetouchAreasMasksVersion'] }, + 'retouchareamaskwhat' => { 478 => [\'RetouchAreas','RetouchAreasMasksWhat'], 480 => [\'RetouchAreas','RetouchAreasMasksWhat'] }, + 'retouchareamaskwholeimagearea' => { 478 => [\'RetouchAreas','RetouchAreasMasksWholeImageArea'], 480 => [\'RetouchAreas','RetouchAreasMasksWholeImageArea'] }, + 'retouchareamaskx' => { 478 => [\'RetouchAreas','RetouchAreasMasksX'], 480 => [\'RetouchAreas','RetouchAreasMasksX'] }, + 'retouchareamasky' => { 478 => [\'RetouchAreas','RetouchAreasMasksY'], 480 => [\'RetouchAreas','RetouchAreasMasksY'] }, + 'retouchareamaskzerox' => { 478 => [\'RetouchAreas','RetouchAreasMasksZeroX'], 480 => [\'RetouchAreas','RetouchAreasMasksZeroX'] }, + 'retouchareamaskzeroy' => { 478 => [\'RetouchAreas','RetouchAreasMasksZeroY'], 480 => [\'RetouchAreas','RetouchAreasMasksZeroY'] }, + 'retouchareamethod' => { 478 => [\'RetouchAreas','RetouchAreasMethod'], 480 => [\'RetouchAreas','RetouchAreasMethod'] }, + 'retouchareaoffsety' => { 478 => [\'RetouchAreas','RetouchAreasOffsetY'], 480 => [\'RetouchAreas','RetouchAreasOffsetY'] }, + 'retouchareaopacity' => { 478 => [\'RetouchAreas','RetouchAreasOpacity'], 480 => [\'RetouchAreas','RetouchAreasOpacity'] }, + 'retouchareas' => { 478 => 'RetouchAreas', 480 => 'RetouchAreas' }, + 'retouchareaseed' => { 478 => [\'RetouchAreas','RetouchAreasSeed'], 480 => [\'RetouchAreas','RetouchAreasSeed'] }, + 'retouchareasourcestate' => { 478 => [\'RetouchAreas','RetouchAreasSourceState'], 480 => [\'RetouchAreas','RetouchAreasSourceState'] }, + 'retouchareasourcex' => { 478 => [\'RetouchAreas','RetouchAreasSourceX'], 480 => [\'RetouchAreas','RetouchAreasSourceX'] }, + 'retouchareaspottype' => { 478 => [\'RetouchAreas','RetouchAreasSpotType'], 480 => [\'RetouchAreas','RetouchAreasSpotType'] }, + 'retouchhistory' => { 226 => 0x9e }, + 'retouchinfo' => { 478 => 'RetouchInfo', 480 => 'RetouchInfo' }, + 'retouchnefprocessing' => { 236 => 0x5 }, + 'retractlensonpoweroff' => { 84 => 0x814 }, + 'reuse' => { 307 => 'Reuse' }, + 'reuseallowed' => { 507 => 'ReuseAllowed' }, + 'reuseprohibited' => { 497 => 'reuseProhibited' }, + 'reverseexposurecompdial' => { 286 => '5.2' }, + 'reversefocusring' => { 295 => 0x163 }, + 'reverseindicators' => { 279 => '12.1', 280 => '6.1', 282 => '6.1', 283 => '6.1', 284 => '4.3', 285 => '5.2', 286 => '5.4', 288 => '33.5', 289 => '5.1', 292 => '6.1', 293 => '6.1', 294 => '6.2', 295 => 0xc1 }, + 'reverseshutterspeedaperture' => { 286 => '5.3' }, + 'revision' => { 482 => 'revision' }, + 'rflensmffocusringsensitivity' => { 84 => 0x714 }, + 'rflenstype' => { 57 => 0x3d }, + 'rgbcurvelimits' => { 108 => 0x238 }, + 'rgbcurvepoints' => { 107 => 0x7, 108 => 0x20e }, + 'rgbtables' => { 119 => 0xcd3b }, + 'richtextcomment' => { 487 => 'RichTextComment' }, + 'ricohdate' => { 386 => 0x6 }, + 'ricohimageheight' => { 386 => 0x2 }, + 'ricohimagewidth' => { 386 => 0x0 }, + 'rightalbedo' => { 469 => 'RightAlbedo' }, + 'rightascension' => { 165 => 'RightAscension' }, + 'rights' => { 481 => 'rights' }, + 'rightsagent' => { 497 => 'rightsAgent' }, + 'rightsowner' => { 497 => 'rightsOwner' }, + 'roll' => { 115 => 0x8, 380 => ['roll',"\xa9frl"] }, + 'rollangle' => { 247 => 0x350b, 248 => 0x2c24, 252 => 0xc21a, 257 => 0x36f4, 258 => 0x2efb, 260 => 0xce32, 261 => 0xeaeb, 297 => 0x903, 320 => 0x90, 354 => 0x1, 392 => 0x2 }, + 'romoperationmode' => { 97 => 0x80d }, + 'rotation' => { 30 => 0x17, 31 => 0x18, 96 => 0x3, 103 => 0x10002, 108 => 0x26e, 114 => 'QuickTime-Rotation', 123 => 0x4, 165 => 'Rotation', 182 => [0x65,0x50], 183 => 0x46, 184 => 0x5a, 187 => 0x10, 247 => 0x3693, 248 => 0xca, 255 => '590.1', 272 => 0x76a43207, 320 => 0x30, 336 => '17.2', 366 => 0xd8, 373 => 'irot', 407 => 0x3f, 408 => 0x3f, 418 => 0x10 }, + 'routedto' => { 486 => 'RoutedTo' }, + 'routing' => { 371 => 'Routing' }, + 'routingdestinations' => { 468 => 'RoutingDestinations' }, + 'routingexclusions' => { 468 => 'RoutingExclusions' }, + 'routingnotes' => { 486 => 'RoutingNotes' }, + 'rowsperstrip' => { 119 => 0x116 }, + 'rpp' => { 473 => 'rpp' }, + 'rtkflag' => { 116 => 'RtkFlag' }, + 'rtkstdhgt' => { 116 => 'RtkStdHgt' }, + 'rtkstdlat' => { 116 => 'RtkStdLat' }, + 'rtkstdlon' => { 116 => 'RtkStdLon' }, + 'safetyshift' => { 84 => 0x108 }, + 'safetyshiftinavortv' => { 82 => 0x10, 83 => 0x10, 85 => 0xf, 86 => 0x10, 89 => 0x10 }, + 'sameexposurefornewaperture' => { 84 => 0x112 }, + 'samplebits' => { 155 => 'SampleBits' }, + 'samplepagerange' => { 494 => 'samplePageRange' }, + 'samplerate' => { 155 => 'SampleRate' }, + 'samplesperpixel' => { 119 => 0x115, 325 => 0x8, 500 => 'SamplesPerPixel' }, + 'samplestructure' => { 133 => 0x5a }, + 'samsungmodelid' => { 394 => 0x3 }, + 'sanyoquality' => { 396 => 0x201 }, + 'sanyothumbnail' => { 396 => 0x100 }, + 'saturation' => { 10 => 0x6e, 12 => 0x76, 34 => 0xe, 51 => 0x1, 63 => 0x7, 112 => 0xd, 113 => [0x3013,0x1f], 119 => [0xa409,0xfe55], 127 => 0x1003, 156 => 'Saturation', 181 => 0x1f, 182 => 0x32, 183 => 0x28, 184 => 0x1a, 189 => 0x1, 226 => 0xaa, 231 => 0x35, 232 => 0x3b, 233 => 0x43, 320 => 0x40, 322 => 0x300d, 355 => 0x1f, 362 => 0xd, 381 => 0x27, 383 => 0x58, 386 => 0x28, 387 => 0x1013, 397 => 0x10, 407 => 0x1e, 408 => 0x1b, 420 => 0x2005, 478 => 'Saturation', 480 => 'Saturation', 484 => 'Saturation' }, + 'saturationadj' => { 103 => 0x20901, 108 => 0x116, 226 => 0x94, 271 => 0x1, 275 => 0x2e, 455 => 0x8016 }, + 'saturationadjustmentaqua' => { 478 => 'SaturationAdjustmentAqua', 480 => 'SaturationAdjustmentAqua' }, + 'saturationadjustmentblue' => { 478 => 'SaturationAdjustmentBlue', 480 => 'SaturationAdjustmentBlue' }, + 'saturationadjustmentgreen' => { 478 => 'SaturationAdjustmentGreen', 480 => 'SaturationAdjustmentGreen' }, + 'saturationadjustmentmagenta' => { 478 => 'SaturationAdjustmentMagenta', 480 => 'SaturationAdjustmentMagenta' }, + 'saturationadjustmentorange' => { 478 => 'SaturationAdjustmentOrange', 480 => 'SaturationAdjustmentOrange' }, + 'saturationadjustmentpurple' => { 478 => 'SaturationAdjustmentPurple', 480 => 'SaturationAdjustmentPurple' }, + 'saturationadjustmentred' => { 478 => 'SaturationAdjustmentRed', 480 => 'SaturationAdjustmentRed' }, + 'saturationadjustmentyellow' => { 478 => 'SaturationAdjustmentYellow', 480 => 'SaturationAdjustmentYellow' }, + 'saturationauto' => { 71 => 0x98 }, + 'saturationfaithful' => { 19 => 0xfe, 70 => 0x68, 71 => 0x68 }, + 'saturationlandscape' => { 19 => 0xfc, 70 => 0x38, 71 => 0x38 }, + 'saturationmonochrome' => { 70 => 0x80, 71 => 0x80 }, + 'saturationneutral' => { 19 => 0xfd, 70 => 0x50, 71 => 0x50 }, + 'saturationportrait' => { 19 => 0xfb, 70 => 0x20, 71 => 0x20 }, + 'saturationsetting' => { 305 => 0x1010, 409 => 0x11, 425 => 0x9 }, + 'saturationstandard' => { 19 => 0xfa, 70 => 0x8, 71 => 0x8 }, + 'saturationuserdef1' => { 19 => 0x100, 70 => 0x98, 71 => 0xb0 }, + 'saturationuserdef2' => { 19 => 0x101, 70 => 0xb0, 71 => 0xc8 }, + 'saturationuserdef3' => { 19 => 0x102, 70 => 0xc8, 71 => 0xe0 }, + 'saveid' => { 505 => 'SaveID' }, + 'sbaanalysiscomplete' => { 138 => 0xc35 }, + 'sbablack' => { 138 => 0xc25 }, + 'sbagmoffset' => { 138 => 0xc4a }, + 'sbagray' => { 138 => 0xc26 }, + 'sbagreenmagentabal' => { 138 => 0xc33 }, + 'sbahighgray' => { 138 => 0xc46 }, + 'sbailloffset' => { 138 => 0xc49 }, + 'sbailluminantbal' => { 138 => 0xc34 }, + 'sbalowgray' => { 138 => 0xc47 }, + 'sbaneutralbal' => { 138 => 0xc32 }, + 'sbawhite' => { 138 => 0xc27 }, + 'scaletype' => { 504 => 'scaleType' }, + 'scanimageenhancer' => { 237 => 0x60 }, + 'scanningdirection' => { 133 => 0x64 }, + 'scene' => { 380 => 'scen', 489 => 'Scene', 504 => 'scene' }, + 'scenearea' => { 300 => 0x211, 302 => 0x1031 }, + 'sceneassist' => { 226 => 0x9c }, + 'scenecapturetype' => { 119 => 0xa406, 484 => 'SceneCaptureType' }, + 'scenedetect' => { 300 => 0x210, 302 => 0x1030 }, + 'scenedetectdata' => { 300 => 0x212, 302 => 0x1033 }, + 'scenemode' => { 142 => 0xfa02, 186 => 0x100, 226 => 0x8f, 297 => 0x509, 302 => 0x403, 320 => 0x8001, 329 => 0xf, 420 => 0xb023 }, + 'scenemodeused' => { 144 => [0x6002,0xf002] }, + 'scenerecognition' => { 127 => 0x1425 }, + 'sceneselect' => { 396 => 0x21f }, + 'scenetype' => { 119 => 0xa301, 484 => 'SceneType' }, + 'screentips' => { 279 => '12.7', 280 => '5.3', 288 => '13.1', 289 => '4.4', 292 => '5.4', 294 => '5.1' }, + 'scriptversion' => { 138 => 0x1770 }, + 'season' => { 490 => 'Season', 493 => 'season' }, + 'seasonidentifier' => { 490 => [\'Season','SeasonIdentifier'] }, + 'seasonname' => { 490 => [\'Season','SeasonName'] }, + 'seasonnumber' => { 490 => [\'Season','SeasonNumber'] }, + 'secondaryftp' => { 468 => 'SecondaryFTP' }, + 'secondaryslotfunction' => { 229 => 0x22c, 247 => 0x1d0, 257 => 0x1d0 }, + 'section' => { 494 => 'section' }, + 'securityclassification' => { 119 => 0x9212 }, + 'selectableafpoint' => { 84 => 0x509 }, 'selectafareaselectionmode' => { 2 => 0xc }, - 'selectafareaselectmode' => { 78 => 0x512 }, - 'selftimer' => { 33 => 0x2, 297 => 0x2e, 367 => 0x214, 396 => 0x1134, 397 => 0x1134, 398 => 0x1110, 399 => 0x118c, 400 => 0x1168, 401 => 0x1020, 402 => 0x218, 403 => 0x218, 404 => 0x210 }, - 'selftimer2' => { 72 => 0x1d }, - 'selftimerinterval' => { 267 => '19.2' }, - 'selftimermode' => { 113 => 0x882b }, - 'selftimershotcount' => { 258 => '20.2', 260 => '20.3', 261 => '20.3', 262 => '18.2', 263 => '19.2', 264 => '19.2', 265 => '19.3', 267 => '19.3', 270 => '20.3', 271 => '20.3', 272 => '20.2' }, - 'selftimershotinterval' => { 258 => '20.3', 260 => '20.2', 261 => '20.2', 265 => '19.2', 270 => '20.2', 271 => '20.2' }, - 'selftimertime' => { 91 => 0x1806, 174 => 0x1f, 257 => '18.1', 258 => '20.1', 259 => '3.3', 260 => '20.1', 261 => '20.1', 262 => '18.1', 263 => '19.1', 264 => '19.1', 265 => '19.1', 266 => '7.2', 267 => '19.1', 268 => '3.3', 270 => '20.1', 271 => '20.1', 272 => '20.1' }, - 'sellingagency' => { 456 => 'sellingAgency' }, - 'seminfo' => { 113 => 0x8546 }, - 'sensingmethod' => { 113 => 0xa217, 446 => 'SensingMethod' }, - 'sensitivityadjust' => { 332 => 0x40 }, - 'sensitivitysteps' => { 313 => ['14.3','17.4'], 315 => 0x1 }, - 'sensitivitytype' => { 113 => 0x8830, 447 => 'SensitivityType' }, - 'sensor' => { 181 => 0x665e }, - 'sensorareas' => { 365 => 0xa010 }, - 'sensorbitdepth' => { 299 => 0x312d }, - 'sensorbluelevel' => { 70 => 0x5 }, - 'sensorcalibration' => { 278 => 0x805 }, - 'sensorcleaning' => { 84 => 0xd }, - 'sensorfullheight' => { 130 => 0xf904 }, - 'sensorfullwidth' => { 130 => 0xf903 }, - 'sensorheight' => { 130 => 0xf901, 135 => 0xfa21, 178 => 0x8, 299 => 0x312c, 341 => 0x109, 358 => 0x1602 }, - 'sensorimageheight' => { 131 => 0x3ee }, - 'sensorimagewidth' => { 131 => 0x3ed }, - 'sensorleftborder' => { 131 => 0x3eb }, - 'sensorleftmargin' => { 341 => 0x10a }, - 'sensorpixelsize' => { 211 => 0x9a }, - 'sensorredlevel' => { 70 => 0x4 }, - 'sensorserialnumber' => { 131 => 0x9ce }, - 'sensorsize' => { 147 => 'SensorSize', 332 => 0x35 }, - 'sensortemperature' => { 277 => 0x1500, 279 => 0x1007, 337 => 0xc, 341 => 0x210, 368 => [0x39,0x55] }, - 'sensortemperature2' => { 337 => 0xe, 341 => 0x211 }, - 'sensortopborder' => { 131 => 0x3ec }, - 'sensortopmargin' => { 341 => 0x10b }, - 'sensorwidth' => { 130 => 0xf900, 135 => 0xfa20, 178 => 0xa, 299 => 0x312b, 341 => 0x108, 358 => 0x1601 }, - 'sequence' => { 353 => 0x7, 354 => 0x35 }, - 'sequencefilenumber' => { 397 => 0x4, 398 => 0x4, 399 => 0x4, 400 => 0x4, 408 => 0xc, 409 => 0xc, 410 => 0x1a }, - 'sequenceimagenumber' => { 397 => 0x0, 398 => 0x0, 399 => 0x0, 400 => 0x0, 408 => 0x8, 409 => 0x8, 410 => 0x12, 417 => 0x24 }, - 'sequencelength' => { 408 => 0x22, 409 => 0x1e, 410 => [0x16,0x1e] }, - 'sequencename' => { 455 => 'sequenceName' }, - 'sequencenumber' => { 72 => 0x9, 107 => 0x301c, 121 => 0x1101, 133 => 0x1d, 236 => 0x51c, 297 => 0x2b, 378 => [0x10c,0x30c], 388 => 0xb04a, 455 => 'sequenceNumber' }, - 'sequenceshotinterval' => { 367 => 0x224 }, - 'sequencetotalnumber' => { 455 => 'sequenceTotalNumber' }, - 'sequentialshot' => { 367 => 0x20e }, - 'serialnumber' => { 60 => 0xc, 91 => 0x180b, 113 => [0xa431,0xfde9], 130 => 0xfa04, 132 => 0xfa00, 134 => 0xc354, 135 => 0xfa19, 144 => 0x0, 147 => 'SerialNumber', 211 => [0xa0,0x1d], 275 => 0x101, 279 => [0x404,0x101a], 292 => 0x303, 294 => 0x305, 299 => 0x3103, 332 => 0x229, 341 => 0x102, 342 => 0x407, 353 => 0x15, 354 => 0x4b, 358 => 0x5, 365 => 0xa002, 368 => 0x2, 388 => 0x2031, 438 => 'SerialNumber', 447 => 'BodySerialNumber' }, - 'serialnumberformat' => { 60 => 0x15, 91 => 0x183b }, - 'series' => { 452 => 'Series' }, - 'seriesdatetime' => { 423 => 'SeriesDateTime' }, - 'seriesdescription' => { 423 => 'SeriesDescription' }, - 'seriesidentifier' => { 452 => [\'Series','SeriesIdentifier'] }, - 'seriesmodality' => { 423 => 'SeriesModality' }, - 'seriesname' => { 452 => [\'Series','SeriesName'] }, - 'seriesnumber' => { 423 => 'SeriesNumber', 456 => 'seriesNumber' }, - 'seriestitle' => { 456 => 'seriesTitle' }, - 'serviceidentifier' => { 126 => 0x1e }, - 'servingsize' => { 458 => 'servingSize' }, - 'setbuttoncrosskeysfunc' => { 81 => 0x0, 82 => 0x0 }, - 'setbuttonwhenshooting' => { 76 => 0x1, 78 => 0x704, 84 => 0xc }, - 'setfunctionwhenshooting' => { 79 => 0x0, 80 => 0x1, 83 => 0x1 }, - 'setting' => { 455 => 'setting' }, - 'shadingcompensation' => { 274 => 0x50c, 297 => 0x8a }, - 'shadingcompensation2' => { 278 => 0x1012 }, - 'shadow' => { 368 => 0xe }, - 'shadowadj' => { 97 => 0x2030b }, - 'shadowcorrection' => { 332 => 0x79 }, - 'shadowprotection' => { 249 => 0x0 }, - 'shadows' => { 113 => 0xfe52, 435 => 'Shadows', 442 => 'Shadows' }, - 'shadows2012' => { 442 => 'Shadows2012' }, - 'shadowsadj' => { 421 => 0x901a }, - 'shadowscale' => { 113 => 0xc633 }, - 'shadowtint' => { 442 => 'ShadowTint' }, - 'shadowtone' => { 121 => 0x1040 }, - 'shakereduction' => { 334 => 0x1, 335 => 0x1 }, - 'sharpendetail' => { 442 => 'SharpenDetail' }, - 'sharpenedgemasking' => { 442 => 'SharpenEdgeMasking' }, - 'sharpening' => { 299 => 0x300b }, - 'sharpeningadj' => { 253 => 0x2b }, - 'sharpeningkernel' => { 131 => 0x92f }, - 'sharpenradius' => { 442 => 'SharpenRadius' }, - 'sharpness' => { 7 => [0x42,0x48], 9 => 0x72, 11 => 0x74, 33 => 0xf, 70 => 0x2, 106 => 0xb, 107 => [0x3011,0x21], 113 => [0xa40a,0xfe56], 121 => 0x1001, 133 => 0x6b, 142 => 0x37, 147 => 'Sharpness', 171 => 0x21, 172 => 0x30, 173 => 0x26, 174 => 0x18, 179 => 0x3, 211 => 0x6, 213 => 0x32, 214 => 0x33, 279 => 0x100f, 297 => 0x41, 332 => 0x21, 339 => 0xb, 353 => 0x26, 357 => 0x22, 358 => [0x1003,0x1014], 368 => 0x11, 376 => 0x1c, 377 => 0x19, 388 => 0x2006, 417 => 0x52, 442 => 'Sharpness', 446 => 'Sharpness' }, - 'sharpnessadj' => { 97 => 0x20310, 102 => 0x25a, 421 => 0x801a }, - 'sharpnessadjon' => { 97 => '0x20310.0' }, - 'sharpnessauto' => { 67 => 0x94 }, - 'sharpnessfactor' => { 279 => 0x102a }, - 'sharpnessfaithful' => { 18 => 0xf5, 66 => 0x64, 67 => 0x64 }, - 'sharpnessfrequency' => { 7 => [0x41,0x47], 70 => 0x3 }, - 'sharpnesslandscape' => { 18 => 0xf3, 66 => 0x34, 67 => 0x34 }, - 'sharpnessmonochrome' => { 18 => 0xf6, 66 => 0x7c, 67 => 0x7c }, - 'sharpnessneutral' => { 18 => 0xf4, 66 => 0x4c, 67 => 0x4c }, - 'sharpnessovershoot' => { 421 => 0x801b }, - 'sharpnessportrait' => { 18 => 0xf2, 66 => 0x1c, 67 => 0x1c }, - 'sharpnesssetting' => { 274 => 0x506, 282 => 0x1013, 378 => 0x12, 393 => 0xa }, - 'sharpnessstandard' => { 18 => 0xf1, 66 => 0x4, 67 => 0x4 }, - 'sharpnessstrength' => { 97 => 0x20311 }, - 'sharpnessthreshold' => { 421 => 0x801d }, - 'sharpnessundershoot' => { 421 => 0x801c }, - 'sharpnessuserdef1' => { 18 => 0xf7, 66 => 0x94, 67 => 0xac }, - 'sharpnessuserdef2' => { 18 => 0xf8, 66 => 0xac, 67 => 0xc4 }, - 'sharpnessuserdef3' => { 18 => 0xf9, 66 => 0xc4, 67 => 0xdc }, - 'shiftcols' => { 131 => 0xc70 }, - 'shootid' => { 455 => 'shootID' }, - 'shootingdistance' => { 97 => 0x20701 }, - 'shootinginfodisplay' => { 257 => '13.2', 258 => '5.1', 266 => '10.2', 267 => '4.1', 270 => '5.1', 272 => '5.3' }, - 'shootinginfomonitorofftime' => { 257 => '26.2', 258 => '22.2', 260 => '22.2', 261 => '22.2', 265 => '21.2', 266 => '9.1', 267 => '21.2', 270 => '22.2', 271 => '22.2', 272 => '22.2' }, - 'shootingmode' => { 147 => 'ShootingMode', 211 => 0x89, 297 => 0x1f }, - 'shootingmodesetting' => { 259 => '5.1' }, - 'shortdescription' => { 444 => 'shortdescription' }, - 'shortdocumentid' => { 125 => 0xba }, - 'shortownername' => { 18 => 0xac }, - 'shortreleasetimelag' => { 78 => 0x80d }, - 'shotdate' => { 466 => 'shotDate' }, - 'shotday' => { 466 => 'shotDay' }, - 'shotlocation' => { 466 => 'shotLocation' }, - 'shotname' => { 466 => 'shotName' }, - 'shotnumber' => { 466 => 'shotNumber' }, - 'shotnumbersincepowerup' => { 392 => 0x44e, 408 => 0x1a, 409 => 0x16, 410 => 0xa }, - 'shotnumbersincepowerup2' => { 378 => 0x200 }, - 'shotsize' => { 466 => 'shotSize' }, - 'shownevent' => { 452 => 'EventExt' }, - 'showneventidentifier' => { 452 => [\'EventExt','EventExtIdentifier'] }, - 'showneventname' => { 452 => [\'EventExt','EventExtName'] }, - 'shutter-aelock' => { 76 => 0x4, 78 => 0x701, 79 => 0x3, 80 => 0x4, 81 => 0x3, 82 => 0x3, 83 => 0x4, 84 => 0x2 }, - 'shutteraelbutton' => { 77 => 0x4 }, - 'shutterbuttonafonbutton' => { 78 => 0x701 }, - 'shuttercount' => { 10 => 0x176, 54 => 0x1, 211 => 0xa7, 219 => [0x6a,0x157,0x24d], 220 => 0x286, 221 => 0x279, 222 => 0x284, 223 => 0x242, 224 => 0x280, 225 => 0x276, 226 => [0x27d,0x27f], 227 => 0x246, 230 => 0x2d6, 231 => 0x321, 232 => 0xbd8, 233 => 0x287, 234 => 0x320, 235 => 0x24a, 236 => 0x5fb, 239 => 0x2d5, 332 => 0x5d, 387 => 0x846, 391 => [0x125,0x14a] }, - 'shuttercurtainsync' => { 76 => 0xf, 77 => 0xf, 78 => 0x305, 79 => 0xe, 80 => 0xf, 81 => 0x8, 82 => 0x8, 83 => 0xf, 84 => 0x8 }, - 'shuttermode' => { 133 => 0x1b }, - 'shutterreleasebuttonae-l' => { 257 => '17.7', 258 => '18.4', 260 => '78.4', 261 => '78.4', 262 => '16.1', 263 => '17.1', 264 => '17.1', 265 => '17.1', 266 => '7.1', 267 => '17.5', 270 => '18.4', 271 => '78.4', 272 => '18.2' }, - 'shutterreleasemethod' => { 91 => 0x1010 }, - 'shutterreleasenocfcard' => { 76 => 0x2, 77 => 0x2, 84 => 0xf }, - 'shutterreleasetiming' => { 91 => 0x1011 }, - 'shutterreleasewithoutlens' => { 78 => 0x711 }, - 'shutterspeedlock' => { 258 => '38.1', 260 => '38.1', 261 => '38.1', 270 => '38.1', 271 => '38.1' }, - 'shutterspeedrange' => { 78 => 0x10c }, - 'shutterspeedsetting' => { 174 => 0x6, 376 => 0x2f, 377 => 0x28, 378 => 0x0 }, - 'shutterspeedvalue' => { 87 => 0x1, 113 => 0x9201, 279 => 0x1000, 341 => 0x400, 446 => 'ShutterSpeedValue' }, - 'shuttertype' => { 121 => 0x1050, 297 => 0x9f }, - 'sidecarforextension' => { 454 => 'SidecarForExtension' }, - 'sigmaimpulseparameters' => { 131 => 0xe0d }, - 'sigmascalingfactorcamera' => { 131 => 0xe0c }, - 'sigmascalingfactorlowres' => { 131 => 0xe0b }, - 'sigmasizetable' => { 131 => 0xe0f }, - 'similarityindex' => { 125 => 0xe4 }, - 'singleframebracketing' => { 174 => 0x21 }, - 'skilllevel' => { 458 => 'skillLevel' }, - 'skintonecorrection' => { 332 => 0x95 }, - 'skiplinetime' => { 131 => 0x184e }, - 'slaveflashmeteringsegments' => { 332 => 0x20b }, - 'slideshowname' => { 455 => 'slideshowName' }, - 'slideshownumber' => { 455 => 'slideshowNumber' }, - 'slideshowtotalnumber' => { 455 => 'slideshowTotalNumber' }, - 'slowshutter' => { 72 => 0x8 }, - 'slowsync' => { 121 => 0x1030 }, - 'smartalbumcolor' => { 365 => 0x20 }, - 'smartrange' => { 365 => 0xa012 }, - 'smileshutter' => { 378 => 0x31 }, - 'smileshuttermode' => { 378 => 0x27 }, - 'smoothness' => { 113 => 0xfe57, 442 => 'Smoothness' }, - 'snapshot' => { 452 => 'SnapshotLink' }, - 'snapshotformat' => { 452 => [\'SnapshotLink','SnapshotLinkFormat'] }, - 'snapshotheightpixels' => { 452 => [\'SnapshotLink','SnapshotLinkHeightPixels'] }, - 'snapshotimagerole' => { 452 => [\'SnapshotLink','SnapshotLinkImageRole'] }, - 'snapshotlink' => { 452 => [\'SnapshotLink','SnapshotLinkLink'] }, - 'snapshotlinkqualifier' => { 452 => [\'SnapshotLink','SnapshotLinkLinkQualifier'] }, - 'snapshots' => { 436 => 'Snapshots' }, - 'snapshotusedvideoframe' => { 452 => [\'SnapshotLink','SnapshotLinkUsedVideoFrame'] }, - 'snapshotusedvideoframetimeformat' => { 452 => [\'SnapshotLink','SnapshotLinkUsedVideoFrameTimeFormat'] }, - 'snapshotusedvideoframetimevalue' => { 452 => [\'SnapshotLink','SnapshotLinkUsedVideoFrameTimeValue'] }, - 'snapshotusedvideoframevalue' => { 452 => [\'SnapshotLink','SnapshotLinkUsedVideoFrameValue'] }, - 'snapshotwidthpixels' => { 452 => [\'SnapshotLink','SnapshotLinkWidthPixels'] }, - 'softskineffect' => { 388 => 0x200f }, - 'software' => { 113 => 0x131, 148 => 'Software', 287 => 'Software', 341 => 0x203, 368 => 0x18, 426 => 'Software', 462 => 'Software' }, - 'softwareversion' => { 367 => 0x207 }, - 'sonydatetime' => { 395 => 0x6, 397 => 0x1b6, 398 => 0x210, 399 => 0x1fe, 400 => 0x22c }, - 'sonydatetime2' => { 406 => 0x51 }, - 'sonyexposuretime' => { 406 => 0x3a, 407 => 0x46 }, - 'sonyexposuretime2' => { 417 => 0xe }, - 'sonyfnumber' => { 406 => 0x3c, 407 => 0x48, 417 => 0x14 }, - 'sonyimageheight' => { 395 => 0x1a, 408 => 0x44, 409 => 0x3f, 410 => 0x47 }, - 'sonyimageheightmax' => { 417 => 0x40 }, - 'sonyimagesize' => { 174 => 0x3b, 376 => 0x54, 377 => 0x54, 378 => 0x9 }, - 'sonyimagewidth' => { 395 => 0x1c }, - 'sonyimagewidthmax' => { 417 => 0x3e }, - 'sonyiso' => { 397 => 0x1218, 398 => 0x11f4, 399 => 0x1270, 400 => [0x1254,0x1258,0x1280], 401 => 0x113c, 402 => 0x344, 403 => 0x346, 404 => 0x320, 417 => 0x4 }, - 'sonymaxaperture' => { 406 => 0x0, 407 => 0x0 }, - 'sonymaxaperturevalue' => { 417 => 0x16 }, - 'sonyminaperture' => { 406 => 0x1, 407 => 0x1 }, - 'sonymodelid' => { 388 => 0xb001 }, - 'sonyquality' => { 174 => 0x3c }, - 'sonytimeminsec' => { 407 => 0x61 }, - 'source' => { 125 => 0x73, 287 => 'Source', 443 => 'source', 444 => 'source', 454 => 'Source' }, - 'sourcecount' => { 430 => 'SourceCount' }, - 'sourcedirectoryindex' => { 319 => 0x0 }, - 'sourcefileindex' => { 319 => 0x2 }, - 'sourcephotoscount' => { 429 => 'SourcePhotosCount' }, - 'sourceprofileprefix' => { 131 => 0x1390 }, - 'spatialfrequencyresponse' => { 446 => 'SpatialFrequencyResponse' }, - 'spatialfrequencyresponsecolumns' => { 446 => [\'SpatialFrequencyResponse','SpatialFrequencyResponseColumns'] }, - 'spatialfrequencyresponsenames' => { 446 => [\'SpatialFrequencyResponse','SpatialFrequencyResponseNames'] }, - 'spatialfrequencyresponserows' => { 446 => [\'SpatialFrequencyResponse','SpatialFrequencyResponseRows'] }, - 'spatialfrequencyresponsevalues' => { 446 => [\'SpatialFrequencyResponse','SpatialFrequencyResponseValues'] }, - 'speakerplacement' => { 466 => 'speakerPlacement' }, - 'specialeffectlevel' => { 107 => 0x3030 }, - 'specialeffectmode' => { 107 => 0x2076 }, - 'specialeffectsetting' => { 107 => 0x3031 }, - 'specialinstructions' => { 125 => 0x28 }, - 'specialmode' => { 279 => 0x200, 367 => 0x200 }, - 'specialoccasion' => { 458 => 'specialOccasion' }, - 'spectralsensitivity' => { 113 => 0x8824, 446 => 'SpectralSensitivity' }, - 'specularwhitelevel' => { 42 => [0x2b9,0x2d0,0x2d4], 44 => 0x1e4, 45 => [0x1fd,0x2dd], 46 => [0x231,0x30f], 47 => 0x31d }, - 'speedx' => { 109 => 0x3 }, - 'speedy' => { 109 => 0x4 }, - 'speedz' => { 109 => 0x5 }, - 'spherical' => { 430 => 'Spherical' }, - 'splitcolumn' => { 341 => 0x222 }, - 'splittoningbalance' => { 442 => 'SplitToningBalance' }, - 'splittoninghighlighthue' => { 442 => 'SplitToningHighlightHue' }, - 'splittoninghighlightsaturation' => { 442 => 'SplitToningHighlightSaturation' }, - 'splittoningshadowhue' => { 442 => 'SplitToningShadowHue' }, - 'splittoningshadowsaturation' => { 442 => 'SplitToningShadowSaturation' }, - 'sport' => { 456 => 'sport' }, - 'spotfocuspointx' => { 171 => 0x2d }, - 'spotfocuspointy' => { 171 => 0x2e }, - 'spotmeteringmode' => { 33 => 0x27 }, - 'spotmeterlinktoafpoint' => { 78 => 0x107 }, - 'sractive' => { 313 => '17.1' }, - 'srawquality' => { 33 => 0x2e }, - 'srfocallength' => { 334 => 0x3 }, - 'srhalfpresstime' => { 334 => 0x2 }, - 'srresult' => { 334 => 0x0, 335 => 0x0 }, - 'stackedimage' => { 274 => 0x804 }, - 'standardmatrixcustom' => { 131 => 0x7d4 }, - 'standardmatrixdaylight' => { 131 => 0x7d0 }, - 'standardmatrixflash' => { 131 => 0x7d3 }, - 'standardmatrixfluorescent' => { 131 => 0x7d2 }, - 'standardmatrixtungsten' => { 131 => 0x7d1 }, - 'standardoutputhighlightpoint' => { 103 => 0x14 }, - 'standardoutputsensitivity' => { 113 => 0x8831, 447 => 'StandardOutputSensitivity' }, - 'standardoutputshadowpoint' => { 103 => 0x15 }, - 'standardrawcolortone' => { 103 => 0xd }, - 'standardrawcontrast' => { 103 => 0xf }, - 'standardrawhighlight' => { 103 => 0x75 }, - 'standardrawhighlightpoint' => { 103 => 0x12 }, - 'standardrawlinear' => { 103 => 0x10 }, - 'standardrawsaturation' => { 103 => 0xe }, - 'standardrawshadow' => { 103 => 0x7e }, - 'standardrawshadowpoint' => { 103 => 0x13 }, - 'standardrawsharpness' => { 103 => 0x11 }, - 'standardunsharpmaskfineness' => { 103 => 0x94 }, - 'standardunsharpmaskstrength' => { 103 => 0x92 }, - 'standardunsharpmaskthreshold' => { 103 => 0x96 }, - 'standardwhitecustom' => { 131 => 0x838 }, - 'standardwhitedaylight' => { 131 => 0x834 }, - 'standardwhiteflash' => { 131 => 0x837 }, - 'standardwhitefluorescent' => { 131 => 0x836 }, - 'standardwhitetungsten' => { 131 => 0x835 }, - 'standbytimer' => { 258 => '19.1', 260 => '19.1', 261 => '19.1', 264 => '18.1', 265 => '18.1', 270 => '19.1', 271 => '19.1' }, - 'startingpage' => { 456 => 'startingPage' }, - 'startmovieshooting' => { 78 => 0x70d }, - 'starttimecode' => { 466 => 'startTimecode' }, - 'starttimecodetimeformat' => { 466 => [\'startTimecode','startTimecodeTimeFormat'] }, - 'starttimecodetimevalue' => { 466 => [\'startTimecode','startTimecodeTimeValue'] }, - 'starttimecodevalue' => { 466 => [\'startTimecode','startTimecodeValue'] }, - 'starttimesamplesize' => { 466 => 'startTimeSampleSize' }, - 'starttimescale' => { 466 => 'startTimeScale' }, - 'state' => { 152 => 'State', 297 => 0x6b, 454 => 'State' }, - 'status' => { 424 => 'Status', 434 => 'Status' }, - 'stereomode' => { 430 => 'StereoMode' }, - 'stitched' => { 430 => 'Stitched' }, - 'stitchingsoftware' => { 429 => 'StitchingSoftware', 430 => 'StitchingSoftware' }, - 'stopsabovebaseiso' => { 396 => 0x113e, 397 => 0x113e, 398 => 0x111a, 399 => 0x1196, 400 => 0x1172, 401 => 0x102a, 402 => 0x222, 403 => 0x222, 404 => 0x217, 417 => 0xa }, - 'storagemethod' => { 178 => 0x12 }, - 'storebyorientation' => { 258 => '46.3', 260 => '47.3', 261 => '47.3', 270 => '47.3', 271 => '47.3' }, - 'storylineidentifier' => { 452 => 'StorylineIdentifier' }, - 'straightenangle' => { 250 => 0x2fc08431 }, - 'streamready' => { 452 => 'StreamReady' }, - 'streamtype' => { 167 => 'StreamType' }, - 'stretchmode' => { 466 => 'stretchMode' }, - 'studydatetime' => { 423 => 'StudyDateTime' }, - 'studydescription' => { 423 => 'StudyDescription' }, - 'studyid' => { 423 => 'StudyID' }, - 'studyphysician' => { 423 => 'StudyPhysician' }, - 'styleperiod' => { 452 => 'StylePeriod' }, - 'sub-location' => { 125 => 0x5c }, - 'subfiledata' => { 155 => 'data' }, - 'subfiledirectory' => { 155 => '1Directory' }, - 'subfilemimetype' => { 155 => '2MIME' }, - 'subfilename' => { 155 => '1Name' }, - 'subfileresource' => { 155 => 'rsrc' }, - 'subfiletype' => { 113 => 0xfe, 155 => '0Type' }, - 'subject' => { 283 => 'Subject', 348 => 'Subject', 443 => 'subject', 453 => 'Subject', 467 => 'subject' }, - 'subjectarea' => { 113 => 0x9214, 446 => 'SubjectArea' }, - 'subjectcode' => { 451 => 'SubjectCode' }, - 'subjectdistance' => { 113 => 0x9206, 133 => 0x3e, 446 => 'SubjectDistance' }, - 'subjectdistancerange' => { 113 => 0xa40c, 446 => 'SubjectDistanceRange' }, - 'subjectlocation' => { 113 => 0xa214, 446 => 'SubjectLocation' }, - 'subjectmotion' => { 260 => '78.2', 261 => '78.2', 271 => '78.2' }, - 'subjectprogram' => { 171 => 0x22 }, - 'subjectreference' => { 125 => 0xc }, - 'sublabels4' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabels'] }, - 'sublabels5' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsSubLabels'] }, - 'sublables1' => { 450 => [\'TagStructure','TagStructureSubLabels'] }, - 'sublables2' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabels'] }, - 'sublables3' => { 450 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabels'] }, - 'subseccreatedate' => { 108 => 'SubSecCreateDate' }, - 'subsecdatetimeoriginal' => { 108 => 'SubSecDateTimeOriginal' }, - 'subsecmodifydate' => { 108 => 'SubSecModifyDate' }, - 'subsectime' => { 113 => 0x9290 }, - 'subsectimedigitized' => { 113 => 0x9292 }, - 'subsectimeoriginal' => { 113 => 0x9291 }, - 'subsection1' => { 456 => 'subsection1' }, - 'subsection2' => { 456 => 'subsection2' }, - 'subsection3' => { 456 => 'subsection3' }, - 'subsection4' => { 456 => 'subsection4' }, - 'subselector' => { 258 => '49.1', 260 => '71.1', 261 => '71.1', 271 => '71.1' }, - 'subselectorassignment' => { 258 => '48.1' }, - 'subselectorcenter' => { 260 => '72.1', 261 => '72.1', 271 => '72.1' }, - 'subselectorplusdials' => { 258 => '49.2', 260 => '73.1', 261 => '73.1', 271 => '73.1' }, - 'subtitle' => { 456 => 'subtitle' }, - 'subversionfilename' => { 450 => [\'SubVersions','SubVersionsFileName'] }, - 'subversionreference' => { 450 => [\'SubVersions','SubVersionsVersRef'] }, - 'subversions' => { 450 => 'SubVersions' }, - 'superimposeddisplay' => { 76 => 0xa, 78 => 0x510, 79 => 0x9, 80 => 0xa, 83 => 0xa, 84 => 0xe }, - 'supermacro' => { 60 => 0x1a }, - 'supplementalcategories' => { 125 => 0x14, 454 => 'SupplementalCategories' }, - 'supplementaltype' => { 127 => 0x37 }, - 'supplementdisplayid' => { 456 => 'supplementDisplayID' }, - 'supplementstartingpage' => { 456 => 'supplementStartingPage' }, - 'supplementtitle' => { 456 => 'supplementTitle' }, - 'supplychainsource' => { 452 => 'SupplyChainSource' }, - 'supplychainsourceidentifier' => { 452 => [\'SupplyChainSource','SupplyChainSourceIdentifier'] }, - 'supplychainsourcename' => { 452 => [\'SupplyChainSource','SupplyChainSourceName'] }, - 'svisosetting' => { 313 => 0x14 }, - 'swatchcoloranta' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsA'] }, - 'swatchcolorantb' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsB'] }, - 'swatchcolorantblack' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsBlack'] }, - 'swatchcolorantblue' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsBlue'] }, - 'swatchcolorantcyan' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsCyan'] }, - 'swatchcolorantgray' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsGray'] }, - 'swatchcolorantgreen' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsGreen'] }, - 'swatchcolorantl' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsL'] }, - 'swatchcolorantmagenta' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsMagenta'] }, - 'swatchcolorantmode' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsMode'] }, - 'swatchcolorantred' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsRed'] }, - 'swatchcolorantswatchname' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsSwatchName'] }, - 'swatchcoloranttint' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsTint'] }, - 'swatchcoloranttype' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsType'] }, - 'swatchcolorantyellow' => { 471 => [\'SwatchGroups','SwatchGroupsColorantsYellow'] }, - 'swatchgroupname' => { 471 => [\'SwatchGroups','SwatchGroupsGroupName'] }, - 'swatchgroups' => { 471 => 'SwatchGroups' }, - 'swatchgroupscolorants' => { 471 => [\'SwatchGroups','SwatchGroupsColorants'] }, - 'swatchgrouptype' => { 471 => [\'SwatchGroups','SwatchGroupsGroupType'] }, - 'sweeppanoramadirection' => { 297 => 0x93, 378 => 0x33 }, - 'sweeppanoramafieldofview' => { 297 => 0x94 }, - 'sweeppanoramasize' => { 378 => 0x32 }, - 'switchtoregisteredafpoint' => { 77 => 0x12, 78 => 0x50a }, - 'syncreleasemode' => { 260 => '77.1', 261 => '77.1', 271 => '77.1' }, - 'system' => { 341 => 0x204 }, - 'tagged' => { 343 => 0xdd, 344 => 'Tagged', 436 => 'tagged' }, - 'tagslist' => { 445 => 'TagsList' }, - 'tagstructure' => { 450 => 'TagStructure' }, - 'takenumber' => { 466 => 'takeNumber' }, - 'tapename' => { 466 => 'tapeName' }, - 'targetaperture' => { 72 => 0x4 }, - 'targetcompressionratio' => { 89 => 0x1 }, - 'targetdistancesetting' => { 91 => 0x1807 }, - 'targetexposuretime' => { 72 => 0x5 }, - 'targetimagetype' => { 91 => 0x100a }, - 'targetprinter' => { 113 => 0x151 }, - 'taxon' => { 112 => 'Taxon' }, - 'taxonacceptednameusage' => { 112 => [\'Taxon','TaxonAcceptedNameUsage'] }, - 'taxonacceptednameusageid' => { 112 => [\'Taxon','TaxonAcceptedNameUsageID'] }, - 'taxonclass' => { 112 => [\'Taxon','TaxonClass'] }, - 'taxonconceptid' => { 112 => [\'Taxon','TaxonTaxonConceptID'] }, - 'taxonfamily' => { 112 => [\'Taxon','TaxonFamily'] }, - 'taxongenus' => { 112 => [\'Taxon','TaxonGenus'] }, - 'taxonhigherclassification' => { 112 => [\'Taxon','TaxonHigherClassification'] }, - 'taxonid' => { 112 => [\'Taxon','TaxonTaxonID'] }, - 'taxoninfraspecificepithet' => { 112 => [\'Taxon','TaxonInfraspecificEpithet'] }, - 'taxonkingdom' => { 112 => [\'Taxon','TaxonKingdom'] }, - 'taxonnameaccordingto' => { 112 => [\'Taxon','TaxonNameAccordingTo'] }, - 'taxonnameaccordingtoid' => { 112 => [\'Taxon','TaxonNameAccordingToID'] }, - 'taxonnamepublishedin' => { 112 => [\'Taxon','TaxonNamePublishedIn'] }, - 'taxonnamepublishedinid' => { 112 => [\'Taxon','TaxonNamePublishedInID'] }, - 'taxonnamepublishedinyear' => { 112 => [\'Taxon','TaxonNamePublishedInYear'] }, - 'taxonnomenclaturalcode' => { 112 => [\'Taxon','TaxonNomenclaturalCode'] }, - 'taxonnomenclaturalstatus' => { 112 => [\'Taxon','TaxonNomenclaturalStatus'] }, - 'taxonorder' => { 112 => [\'Taxon','TaxonOrder'] }, - 'taxonoriginalnameusage' => { 112 => [\'Taxon','TaxonOriginalNameUsage'] }, - 'taxonoriginalnameusageid' => { 112 => [\'Taxon','TaxonOriginalNameUsageID'] }, - 'taxonparentnameusage' => { 112 => [\'Taxon','TaxonParentNameUsage'] }, - 'taxonparentnameusageid' => { 112 => [\'Taxon','TaxonParentNameUsageID'] }, - 'taxonphylum' => { 112 => [\'Taxon','TaxonPhylum'] }, - 'taxonrank' => { 112 => [\'Taxon','TaxonTaxonRank'] }, - 'taxonremarks' => { 112 => [\'Taxon','TaxonTaxonRemarks'] }, - 'taxonscientificname' => { 112 => [\'Taxon','TaxonScientificName'] }, - 'taxonscientificnameauthorship' => { 112 => [\'Taxon','TaxonScientificNameAuthorship'] }, - 'taxonscientificnameid' => { 112 => [\'Taxon','TaxonScientificNameID'] }, - 'taxonspecificepithet' => { 112 => [\'Taxon','TaxonSpecificEpithet'] }, - 'taxonsubgenus' => { 112 => [\'Taxon','TaxonSubgenus'] }, - 'taxontaxonomicstatus' => { 112 => [\'Taxon','TaxonTaxonomicStatus'] }, - 'taxonverbatimtaxonrank' => { 112 => [\'Taxon','TaxonVerbatimTaxonRank'] }, - 'taxonvernacularname' => { 112 => [\'Taxon','TaxonVernacularName'] }, - 'tda1bandwidth' => { 131 => 0x196f }, - 'tda1edgepolarity' => { 131 => 0x1971 }, - 'tda1gain' => { 131 => 0x1970 }, - 'tda1offset' => { 131 => 0x196e }, - 'tda2bandwidth' => { 131 => 0x1979 }, - 'tda2edgepolarity' => { 131 => 0x197b }, - 'tda2gain' => { 131 => 0x197a }, - 'tda2offset' => { 131 => 0x1978 }, - 'tda3bandwidth' => { 131 => 0x1983 }, - 'tda3edgepolarity' => { 131 => 0x1985 }, - 'tda3gain' => { 131 => 0x1984 }, - 'tda3offset' => { 131 => 0x1982 }, - 'tda4bandwidth' => { 131 => 0x198d }, - 'tda4edgepolarity' => { 131 => 0x198f }, - 'tda4gain' => { 131 => 0x198e }, - 'tda4offset' => { 131 => 0x198c }, - 'teaser' => { 456 => 'teaser' }, - 'teleconverter' => { 176 => 0x105, 388 => 0x105 }, - 'tempampgainx100' => { 131 => 0x1914 }, - 'tempo' => { 466 => 'tempo' }, - 'temporalcoverage' => { 452 => 'TemporalCoverage' }, - 'temporalcoveragefrom' => { 452 => [\'TemporalCoverage','TemporalCoverageTempCoverageFrom'] }, - 'temporalcoverageto' => { 452 => [\'TemporalCoverage','TemporalCoverageTempCoverageTo'] }, - 'termsandconditionstext' => { 284 => 'TermsAndConditionsText' }, - 'termsandconditionsurl' => { 284 => 'TermsAndConditionsURL' }, - 'testname' => { 114 => 'TestName' }, - 'textencoding' => { 210 => 0x4 }, - 'textlayername' => { 454 => [\'TextLayers','TextLayersLayerName'] }, - 'textlayers' => { 454 => 'TextLayers' }, - 'textlayertext' => { 454 => [\'TextLayers','TextLayersLayerText'] }, - 'textstamp' => { 297 => [0x8008,0x8009,0x3b,0x3e] }, - 'three-dtrackingfacedetection' => { 260 => '1.3', 261 => '1.3', 271 => '1.4' }, - 'three-dtrackingwatcharea' => { 260 => '78.1', 261 => '78.1', 271 => '78.1' }, - 'thresholding' => { 113 => 0x107 }, - 'thumbnailfilename' => { 91 => 0x817 }, - 'thumbnailformat' => { 464 => [\'Thumbnails','ThumbnailsFormat'] }, - 'thumbnailheight' => { 135 => 0xfa55, 464 => [\'Thumbnails','ThumbnailsHeight'] }, - 'thumbnailimage' => { 91 => 0x2008, 108 => 'ThumbnailImage', 116 => 0x3, 158 => 'data', 279 => 0x100, 464 => [\'Thumbnails','ThumbnailsImage'] }, - 'thumbnailimagename' => { 158 => '1Name' }, - 'thumbnailimagesize' => { 158 => 'ImageSize' }, - 'thumbnailimagetype' => { 158 => '0Type' }, - 'thumbnailimagevalidarea' => { 60 => 0x13 }, - 'thumbnaillength' => { 113 => 0x202 }, - 'thumbnailoffset' => { 113 => 0x201 }, - 'thumbnails' => { 464 => 'Thumbnails' }, - 'thumbnailwidth' => { 135 => 0xfa54, 464 => [\'Thumbnails','ThumbnailsWidth'] }, - 'ticker' => { 456 => 'ticker' }, - 'tiffhandling' => { 442 => 'TIFFHandling' }, - 'tiffmeteringimage' => { 177 => 0x104c, 387 => 0x1110 }, - 'tilelength' => { 113 => 0x143 }, - 'tilewidth' => { 113 => 0x142 }, - 'time' => { 131 => 0x401, 332 => 0x7 }, - 'timecodes' => { 113 => 0xc763 }, - 'timecreated' => { 125 => 0x3c, 133 => 0x14, 142 => 0x10, 344 => 'TimeCreated' }, - 'timelapseshotnumber' => { 300 => 0x10 }, - 'timeperiod' => { 456 => 'timePeriod' }, - 'timerfunctionbutton' => { 259 => '5.2', 262 => '12.1', 263 => '13.1' }, - 'timerlength' => { 78 => 0x80c }, - 'timerrecording' => { 297 => 0x96 }, - 'timescaleparams' => { 466 => 'timeScaleParams' }, - 'timescaleparamsframeoverlappingpercentage' => { 466 => [\'timeScaleParams','timeScaleParamsFrameOverlappingPercentage'] }, - 'timescaleparamsframesize' => { 466 => [\'timeScaleParams','timeScaleParamsFrameSize'] }, - 'timescaleparamsquality' => { 466 => [\'timeScaleParams','timeScaleParamsQuality'] }, - 'timesent' => { 126 => 0x50 }, - 'timeshot' => { 431 => 'TimeShot' }, - 'timesignature' => { 466 => 'timeSignature' }, - 'timesincepoweron' => { 297 => 0x29 }, - 'timestamp' => { 10 => 0x45e, 18 => 0x11c, 273 => 0x8, 287 => 'TimeStamp', 297 => 0xaf, 430 => 'Timestamp', 437 => 'Timestamp', 450 => 'TimeStamp' }, - 'timestamp1' => { 10 => 0x45a }, - 'timezone' => { 73 => 0x1, 242 => 0x0, 361 => 0xa }, - 'timezonecity' => { 73 => 0x2 }, - 'timezonecode' => { 94 => 0x1 }, - 'timezoneinfo' => { 94 => 0x2 }, - 'timezoneoffset' => { 113 => 0x882a }, - 'tint' => { 442 => 'Tint' }, - 'title' => { 148 => 'Title', 283 => 'Title', 287 => 'Title', 297 => 0x65, 348 => 'Title', 443 => 'title', 453 => 'Title', 464 => 'Title' }, - 'tonecomp' => { 211 => 0x81 }, - 'tonecurve' => { 70 => 0x1, 332 => 0x402, 442 => 'ToneCurve' }, - 'tonecurveactive' => { 102 => 0x110 }, - 'tonecurveadobergb' => { 365 => 0xa043 }, - 'tonecurveadobergbdefault' => { 365 => 0xa041 }, - 'tonecurveblue' => { 442 => 'ToneCurveBlue' }, - 'tonecurvebluex' => { 421 => 0x9003 }, - 'tonecurvebluey' => { 421 => 0x9007 }, - 'tonecurvebrightness' => { 97 => 0x20410 }, - 'tonecurvebrightnessx' => { 421 => 0x9000 }, - 'tonecurvebrightnessy' => { 421 => 0x9004 }, - 'tonecurvecolorspace' => { 101 => 0x0 }, - 'tonecurvecontrast' => { 97 => 0x20411 }, - 'tonecurvegreen' => { 442 => 'ToneCurveGreen' }, - 'tonecurvegreenx' => { 421 => 0x9002 }, - 'tonecurvegreeny' => { 421 => 0x9006 }, - 'tonecurveinputrange' => { 101 => 0x3 }, - 'tonecurveinterpolation' => { 102 => 0x159 }, - 'tonecurvemode' => { 102 => 0x113 }, - 'tonecurvename' => { 442 => 'ToneCurveName' }, - 'tonecurvename2012' => { 442 => 'ToneCurveName2012' }, - 'tonecurveoriginal' => { 97 => '0x20400.1' }, - 'tonecurveoutputrange' => { 101 => 0x5 }, - 'tonecurveprofilename' => { 131 => 0x1391 }, - 'tonecurveproperty' => { 102 => 0x3c }, - 'tonecurvepv2012' => { 442 => 'ToneCurvePV2012' }, - 'tonecurvepv2012blue' => { 442 => 'ToneCurvePV2012Blue' }, - 'tonecurvepv2012green' => { 442 => 'ToneCurvePV2012Green' }, - 'tonecurvepv2012red' => { 442 => 'ToneCurvePV2012Red' }, - 'tonecurvered' => { 442 => 'ToneCurveRed' }, - 'tonecurveredx' => { 421 => 0x9001 }, - 'tonecurveredy' => { 421 => 0x9005 }, - 'tonecurves' => { 332 => 0x403 }, - 'tonecurveshape' => { 101 => 0x1 }, - 'tonecurvesrgb' => { 365 => 0xa042 }, - 'tonecurvesrgbdefault' => { 365 => 0xa040 }, - 'tonecurvex' => { 101 => 0xa }, - 'tonecurvey' => { 101 => 0xb }, - 'tonelevel' => { 274 => 0x52e }, - 'tonemapstrength' => { 442 => 'ToneMapStrength' }, - 'toningeffect' => { 54 => 0xf, 211 => 0xb3, 213 => 0x38, 214 => 0x40, 358 => 0x1015 }, - 'toningeffectauto' => { 67 => 0xa4 }, - 'toningeffectfaithful' => { 66 => 0x74, 67 => 0x74 }, - 'toningeffectlandscape' => { 66 => 0x44, 67 => 0x44 }, - 'toningeffectmonochrome' => { 18 => 0x108, 66 => 0x8c, 67 => 0x8c }, - 'toningeffectneutral' => { 66 => 0x5c, 67 => 0x5c }, - 'toningeffectportrait' => { 66 => 0x2c, 67 => 0x2c }, - 'toningeffectstandard' => { 66 => 0x14, 67 => 0x14 }, - 'toningeffectuserdef1' => { 66 => 0xa4, 67 => 0xbc }, - 'toningeffectuserdef2' => { 66 => 0xbc, 67 => 0xd4 }, - 'toningeffectuserdef3' => { 66 => 0xd4, 67 => 0xec }, - 'toningsaturation' => { 213 => 0x39, 214 => 0x41 }, - 'totalzoom' => { 133 => 0x62 }, - 'touchae' => { 297 => 0xab }, - 'trackcreatedate' => { 352 => 0x1 }, - 'trackmodifydate' => { 352 => 0x2 }, - 'tracknumber' => { 466 => 'trackNumber' }, - 'tracks' => { 466 => 'Tracks' }, - 'tracksframerate' => { 466 => [\'Tracks','TracksFrameRate'] }, - 'tracksmarkers' => { 466 => [\'Tracks','TracksMarkers'] }, - 'tracksmarkerscomment' => { 466 => [\'Tracks','TracksMarkersComment'] }, - 'tracksmarkerscuepointparams' => { 466 => [\'Tracks','TracksMarkersCuePointParams'] }, - 'tracksmarkerscuepointparamskey' => { 466 => [\'Tracks','TracksMarkersCuePointParamsKey'] }, - 'tracksmarkerscuepointparamsvalue' => { 466 => [\'Tracks','TracksMarkersCuePointParamsValue'] }, - 'tracksmarkerscuepointtype' => { 466 => [\'Tracks','TracksMarkersCuePointType'] }, - 'tracksmarkersduration' => { 466 => [\'Tracks','TracksMarkersDuration'] }, - 'tracksmarkerslocation' => { 466 => [\'Tracks','TracksMarkersLocation'] }, - 'tracksmarkersname' => { 466 => [\'Tracks','TracksMarkersName'] }, - 'tracksmarkersprobability' => { 466 => [\'Tracks','TracksMarkersProbability'] }, - 'tracksmarkersspeaker' => { 466 => [\'Tracks','TracksMarkersSpeaker'] }, - 'tracksmarkersstarttime' => { 466 => [\'Tracks','TracksMarkersStartTime'] }, - 'tracksmarkerstarget' => { 466 => [\'Tracks','TracksMarkersTarget'] }, - 'tracksmarkerstype' => { 466 => [\'Tracks','TracksMarkersType'] }, - 'trackstrackname' => { 466 => [\'Tracks','TracksTrackName'] }, - 'trackstracktype' => { 466 => [\'Tracks','TracksTrackType'] }, - 'trailersignature' => { 155 => 'zmie' }, - 'transcript' => { 452 => 'Transcript' }, - 'transcriptlink' => { 452 => 'TranscriptLink' }, - 'transcriptlinklink' => { 452 => [\'TranscriptLink','TranscriptLinkLink'] }, - 'transcriptlinklinkqualifier' => { 452 => [\'TranscriptLink','TranscriptLinkLinkQualifier'] }, - 'transferfunction' => { 113 => 0x12d, 462 => 'TransferFunction' }, - 'transfertimenormal' => { 131 => 0x1888 }, - 'transfertimetest' => { 131 => 0x1889 }, - 'transform' => { 297 => [0x8012,0x59] }, - 'transmissionreference' => { 454 => 'TransmissionReference' }, - 'trapped' => { 283 => 'Trapped', 453 => 'Trapped' }, - 'trashbuttonfunction' => { 78 => 0x710 }, - 'travelday' => { 297 => 0x36 }, - 'triggermode' => { 353 => 0x6, 354 => 0x34 }, - 'tstop' => { 113 => 0xc772 }, - 'ttl_da_adown' => { 320 => 0x5 }, - 'ttl_da_aup' => { 320 => 0x4 }, - 'ttl_da_bdown' => { 320 => 0x7 }, - 'ttl_da_bup' => { 320 => 0x6 }, - 'tungstenawb' => { 310 => 0x1 }, - 'tvexposuretimesetting' => { 313 => 0x12 }, - 'type' => { 443 => 'type', 461 => 'type' }, - 'typestatus' => { 112 => [\'Identification','IdentificationTypeStatus'] }, - 'uniquecameramodel' => { 113 => 0xc614 }, - 'uniquedocumentid' => { 125 => 0xbb }, - 'uniquematrixauto' => { 131 => 0x7e9 }, - 'uniquematrixcustom' => { 131 => 0x7e8 }, - 'uniquematrixdaylight' => { 131 => 0x7e4 }, - 'uniquematrixflash' => { 131 => 0x7e7 }, - 'uniquematrixfluorescent' => { 131 => 0x7e6 }, - 'uniquematrixtungsten' => { 131 => 0x7e5 }, - 'uniqueobjectname' => { 126 => 0x64 }, - 'units' => { 426 => 'Units' }, - 'unknownblock' => { 332 => 0x405 }, - 'unknownblock1' => { 278 => 0x635 }, - 'unknownblock2' => { 278 => 0x636 }, - 'unknownblock3' => { 278 => 0x1103 }, - 'unknownblock4' => { 278 => 0x1104 }, - 'unknowncontrast' => { 103 => 0x45 }, - 'unknowndate' => { 341 => 0x212 }, - 'unknownev' => { 131 => 0x1 }, - 'unknownlinear' => { 103 => 0x46 }, - 'unknownnumber' => { 91 => 0x180b }, - 'unknownoutputhighlightpoint' => { 103 => 0x4a }, - 'unknownoutputshadowpoint' => { 103 => 0x4b }, - 'unknownrawhighlight' => { 103 => 0x7b }, - 'unknownrawhighlightpoint' => { 103 => 0x48 }, - 'unknownrawshadow' => { 103 => 0x84 }, - 'unknownrawshadowpoint' => { 103 => 0x49 }, - 'unknownsharpness' => { 103 => 0x47 }, - 'unknowntemperature' => { 115 => 0x4 }, - 'unsharp1color' => { 255 => 0x13 }, - 'unsharp1halowidth' => { 255 => 0x19 }, - 'unsharp1intensity' => { 255 => 0x17 }, - 'unsharp1threshold' => { 255 => 0x1b }, - 'unsharp2color' => { 255 => 0x2e }, - 'unsharp2halowidth' => { 255 => 0x34 }, - 'unsharp2intensity' => { 255 => 0x32 }, - 'unsharp2threshold' => { 255 => 0x36 }, - 'unsharp3color' => { 255 => 0x49 }, - 'unsharp3halowidth' => { 255 => 0x4f }, - 'unsharp3intensity' => { 255 => 0x4d }, - 'unsharp3threshold' => { 255 => 0x51 }, - 'unsharp4color' => { 255 => 0x64 }, - 'unsharp4halowidth' => { 255 => 0x6a }, - 'unsharp4intensity' => { 255 => 0x68 }, - 'unsharp4threshold' => { 255 => 0x6c }, - 'unsharpcount' => { 255 => 0x0 }, - 'unsharpmask' => { 103 => 0x90, 250 => 0x76a43200 }, - 'unsharpmaskfineness' => { 97 => 0x20309 }, - 'unsharpmaskstrength' => { 97 => 0x20308 }, - 'unsharpmaskthreshold' => { 97 => 0x2030a }, - 'uprightcentermode' => { 442 => 'UprightCenterMode' }, - 'uprightcenternormx' => { 442 => 'UprightCenterNormX' }, - 'uprightcenternormy' => { 442 => 'UprightCenterNormY' }, - 'uprightdependentdigest' => { 442 => 'UprightDependentDigest' }, - 'uprightfocallength35mm' => { 442 => 'UprightFocalLength35mm' }, - 'uprightfocalmode' => { 442 => 'UprightFocalMode' }, - 'uprightfoursegmentscount' => { 442 => 'UprightFourSegmentsCount' }, - 'uprightpreview' => { 442 => 'UprightPreview' }, - 'uprighttransform_0' => { 442 => 'UprightTransform_0' }, - 'uprighttransform_1' => { 442 => 'UprightTransform_1' }, - 'uprighttransform_2' => { 442 => 'UprightTransform_2' }, - 'uprighttransform_3' => { 442 => 'UprightTransform_3' }, - 'uprighttransform_4' => { 442 => 'UprightTransform_4' }, - 'uprighttransform_5' => { 442 => 'UprightTransform_5' }, - 'uprighttransformcount' => { 442 => 'UprightTransformCount' }, - 'uprightversion' => { 442 => 'UprightVersion' }, - 'urgency' => { 125 => 0xa, 454 => 'Urgency' }, - 'url' => { 148 => 'URL', 287 => 'URL', 346 => 0x40b, 456 => 'url' }, - 'url_list' => { 346 => 0x41e }, - 'urla-platform' => { 456 => [\'url','urlA-platform'] }, - 'urlurl' => { 456 => [\'url','urlUrl'] }, - 'usablemeteringmodes' => { 78 => 0x10a }, - 'usableshootingmodes' => { 78 => 0x109 }, - 'usage' => { 457 => 'usage' }, - 'usageterms' => { 470 => 'UsageTerms' }, - 'useguidelines' => { 439 => 'useGuidelines' }, - 'usepanoramaviewer' => { 429 => 'UsePanoramaViewer' }, - 'usercomment' => { 91 => 0x805, 113 => 0x9286, 446 => 'UserComment' }, - 'userdef1picturestyle' => { 18 => 0x10c, 66 => 0xd8, 67 => 0xf0 }, - 'userdef2picturestyle' => { 18 => 0x10e, 66 => 0xda, 67 => 0xf2 }, - 'userdef3picturestyle' => { 18 => 0x110, 66 => 0xdc, 67 => 0xf4 }, - 'userfields' => { 434 => 'UserFields' }, - 'userlabel' => { 353 => 0x2b, 354 => 0x5a }, - 'userprofile' => { 292 => 0x302, 299 => 0x3038 }, - 'usmlenselectronicmf' => { 2 => 0x7, 77 => 0x7, 78 => 0x501 }, - 'uspsnumber' => { 456 => 'uspsNumber' }, - 'utmeasting' => { 159 => 'Easting' }, - 'utmmapdatum' => { 159 => 'Datum' }, - 'utmnorthing' => { 159 => 'Northing' }, - 'utmzone' => { 159 => 'Zone' }, - 'uv-irfiltercorrection' => { 292 => 0x325 }, - 'validbits' => { 278 => 0x611, 279 => 0x102c }, - 'validpixeldepth' => { 282 => 0x611 }, - 'variablelowpassfilter' => { 388 => 0x2028 }, - 'variousmodes' => { 133 => 0x26 }, - 'variousmodes2' => { 133 => 0x3a }, - 'variprogram' => { 211 => 0xab }, - 'varraydacnominalvalues' => { 131 => 0x191e }, - 'version' => { 121 => 0x0, 348 => 'Version', 442 => 'Version' }, - 'versioncreatedate' => { 421 => 0xd100 }, - 'versionid' => { 467 => 'VersionID' }, - 'versionidentifier' => { 456 => 'versionIdentifier' }, - 'versionmodifydate' => { 421 => 0xd101 }, - 'versions' => { 467 => 'Versions' }, - 'versionscomments' => { 467 => [\'Versions','VersionsComments'] }, - 'versionsevent' => { 467 => [\'Versions','VersionsEvent'] }, - 'versionseventaction' => { 467 => [\'Versions','VersionsEventAction'] }, - 'versionseventchanged' => { 467 => [\'Versions','VersionsEventChanged'] }, - 'versionseventinstanceid' => { 467 => [\'Versions','VersionsEventInstanceID'] }, - 'versionseventparameters' => { 467 => [\'Versions','VersionsEventParameters'] }, - 'versionseventsoftwareagent' => { 467 => [\'Versions','VersionsEventSoftwareAgent'] }, - 'versionseventwhen' => { 467 => [\'Versions','VersionsEventWhen'] }, - 'versionsmodifier' => { 467 => [\'Versions','VersionsModifier'] }, - 'versionsmodifydate' => { 467 => [\'Versions','VersionsModifyDate'] }, - 'versionsversion' => { 467 => [\'Versions','VersionsVersion'] }, - 'verticalafonbutton' => { 257 => '3.2', 258 => '47.2', 260 => '79.1' }, - 'verticalclockoverlaps' => { 131 => 0x412 }, - 'verticalfuncbutton' => { 258 => '42.2', 260 => '67.1' }, - 'verticalfuncbuttonplusdials' => { 258 => '43.1' }, - 'verticalfuncplusdials' => { 260 => '68.1' }, - 'verticalmultiselector' => { 258 => '42.1', 260 => '66.1', 261 => '66.1', 271 => '66.1' }, - 'vfdisplayillumination' => { 2 => 0x11, 78 => [0x510,0x51d] }, - 'vibrance' => { 435 => 'Vibrance', 442 => 'Vibrance' }, - 'vibrationreduction' => { 219 => [0x75,0x82,0x1ae], 227 => '586.1', 235 => '590.2', 241 => 0x4 }, - 'videoalphamode' => { 466 => 'videoAlphaMode' }, - 'videoalphapremultiplecolor' => { 466 => 'videoAlphaPremultipleColor' }, - 'videoalphapremultiplecolora' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorA'] }, - 'videoalphapremultiplecolorb' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorB'] }, - 'videoalphapremultiplecolorblack' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorBlack'] }, - 'videoalphapremultiplecolorblue' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorBlue'] }, - 'videoalphapremultiplecolorcyan' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorCyan'] }, - 'videoalphapremultiplecolorgray' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorGray'] }, - 'videoalphapremultiplecolorgreen' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorGreen'] }, - 'videoalphapremultiplecolorl' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorL'] }, - 'videoalphapremultiplecolormagenta' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorMagenta'] }, - 'videoalphapremultiplecolormode' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorMode'] }, - 'videoalphapremultiplecolorred' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorRed'] }, - 'videoalphapremultiplecolorswatchname' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorSwatchName'] }, - 'videoalphapremultiplecolortint' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorTint'] }, - 'videoalphapremultiplecolortype' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorType'] }, - 'videoalphapremultiplecoloryellow' => { 466 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorYellow'] }, - 'videoalphaunityistransparent' => { 466 => 'videoAlphaUnityIsTransparent' }, - 'videobitrate' => { 452 => 'videoBitRate' }, - 'videobitratemode' => { 452 => 'videoBitRateMode' }, - 'videoburstmode' => { 297 => 0xbb }, - 'videocodec' => { 63 => 0x74 }, - 'videocolorspace' => { 466 => 'videoColorSpace' }, - 'videocompressor' => { 466 => 'videoCompressor' }, - 'videodisplayaspectratio' => { 452 => 'videoDisplayAspectRatio' }, - 'videoencodingprofile' => { 452 => 'videoEncodingProfile' }, - 'videofieldorder' => { 466 => 'videoFieldOrder' }, - 'videoframerate' => { 466 => 'videoFrameRate' }, - 'videoframesize' => { 466 => 'videoFrameSize' }, - 'videoframesizeh' => { 466 => [\'videoFrameSize','videoFrameSizeH'] }, - 'videoframesizeunit' => { 466 => [\'videoFrameSize','videoFrameSizeUnit'] }, - 'videoframesizew' => { 466 => [\'videoFrameSize','videoFrameSizeW'] }, - 'videomoddate' => { 466 => 'videoModDate' }, - 'videopixelaspectratio' => { 466 => 'videoPixelAspectRatio' }, - 'videopixeldepth' => { 466 => 'videoPixelDepth' }, - 'videoquality' => { 107 => 0x4003 }, - 'videoshottype' => { 452 => 'VideoShotType' }, - 'videoshottypeidentifier' => { 452 => [\'VideoShotType','VideoShotTypeIdentifier'] }, - 'videoshottypename' => { 452 => [\'VideoShotType','VideoShotTypeName'] }, - 'videostreamscount' => { 452 => 'videoStreamsCount' }, - 'viewfinder' => { 341 => 0x455 }, - 'viewfinderdisplay' => { 257 => '12.4', 258 => '6.3' }, - 'viewfinderwarning' => { 257 => '13.4', 267 => '3.5', 268 => '6.2', 272 => '4.4' }, - 'viewfinderwarnings' => { 78 => 0x40a }, - 'viewinfoduringexposure' => { 78 => 0x407 }, - 'viewingmode' => { 378 => 0x2f, 393 => 0x18 }, - 'viewingmode2' => { 378 => [0x85,0x285] }, - 'viewpoint' => { 455 => 'viewpoint' }, - 'vignetteamount' => { 442 => 'VignetteAmount' }, - 'vignettecontrol' => { 211 => 0x2a, 250 => 0x76a43205 }, - 'vignettecontrolintensity' => { 250 => 0xac6bd5c0 }, - 'vignettecorrectionalreadyapplied' => { 438 => 'VignetteCorrectionAlreadyApplied' }, - 'vignettemidpoint' => { 442 => 'VignetteMidpoint' }, - 'vignetting' => { 358 => 0x1011, 365 => 0xa052 }, - 'vignettingcorrection' => { 113 => 0x7031, 365 => 0xa053, 388 => 0x2011 }, - 'vignettingcorrparams' => { 113 => 0x7032, 416 => 0x64a, 417 => [0x34a,0x350,0x35c,0x368] }, - 'vignettingsetting' => { 365 => 0xa054 }, - 'visualcolor' => { 452 => 'VisualColour' }, - 'visualtechnique' => { 455 => 'visualTechnique' }, - 'voicememo' => { 367 => 0x216 }, - 'volume' => { 456 => 'volume' }, - 'vr_0x66' => { 219 => 0x66 }, - 'vrdoffset' => { 60 => 0xd0 }, - 'vrmode' => { 241 => 0x6 }, - 'waterdepth' => { 113 => 0x9403, 447 => 'WaterDepth' }, - 'wb_bluelevel3500k' => { 177 => 0x19a }, - 'wb_bluelevel6500k' => { 177 => 0x18a }, - 'wb_bluelevelcustom' => { 177 => 0x18e }, - 'wb_bluelevelscloudy' => { 177 => 0x106 }, - 'wb_bluelevelsdaylight' => { 177 => 0xea }, - 'wb_bluelevelsflash' => { 177 => 0x122 }, - 'wb_bluelevelsfluorescent' => { 177 => [0x40a,0x15a] }, - 'wb_bluelevelskelvin' => { 177 => 0x254 }, - 'wb_bluelevelsshade' => { 177 => 0x176 }, - 'wb_bluelevelstungsten' => { 177 => 0xce }, - 'wb_gbrglevels' => { 177 => 0xae, 180 => 0x4 }, - 'wb_glevel' => { 278 => 0x11f }, - 'wb_glevel3000k' => { 278 => 0x113 }, - 'wb_glevel3300k' => { 278 => 0x114 }, - 'wb_glevel3600k' => { 278 => 0x115 }, - 'wb_glevel3900k' => { 278 => 0x116 }, - 'wb_glevel4000k' => { 278 => 0x117 }, - 'wb_glevel4300k' => { 278 => 0x118 }, - 'wb_glevel4500k' => { 278 => 0x119 }, - 'wb_glevel4800k' => { 278 => 0x11a }, - 'wb_glevel5300k' => { 278 => 0x11b }, - 'wb_glevel6000k' => { 278 => 0x11c }, - 'wb_glevel6600k' => { 278 => 0x11d }, - 'wb_glevel7500k' => { 278 => 0x11e }, - 'wb_grbglevels' => { 190 => 0x0 }, - 'wb_rbgglevels' => { 187 => 0x0 }, - 'wb_rblevels' => { 191 => 0x270, 211 => 0xc, 278 => 0x100 }, - 'wb_rblevels1' => { 303 => 0x2 }, - 'wb_rblevels2' => { 303 => 0x5 }, - 'wb_rblevels3' => { 303 => 0x8 }, - 'wb_rblevels3000k' => { 278 => 0x102 }, - 'wb_rblevels3300k' => { 278 => 0x103 }, - 'wb_rblevels3500k' => { 177 => 0x430 }, - 'wb_rblevels3600k' => { 278 => 0x104 }, - 'wb_rblevels3900k' => { 278 => 0x105 }, - 'wb_rblevels4' => { 303 => 0xb }, - 'wb_rblevels4000k' => { 278 => 0x106 }, - 'wb_rblevels4300k' => { 278 => 0x107 }, - 'wb_rblevels4500k' => { 278 => 0x108 }, - 'wb_rblevels4800k' => { 278 => 0x109 }, - 'wb_rblevels5' => { 303 => 0xe }, - 'wb_rblevels5300k' => { 278 => 0x10a }, - 'wb_rblevels6' => { 303 => 0x11 }, - 'wb_rblevels6000k' => { 278 => 0x10b }, - 'wb_rblevels6500k' => { 177 => 0x420 }, - 'wb_rblevels6600k' => { 278 => 0x10c }, - 'wb_rblevels7' => { 303 => 0x14 }, - 'wb_rblevels7500k' => { 278 => 0x10d }, - 'wb_rblevelsauto' => { 191 => 0x272, 282 => 0x110 }, - 'wb_rblevelscloudy' => { 177 => 0x3f0, 179 => 0x10, 191 => 0x296, 282 => 0x121 }, - 'wb_rblevelscoolwhitef' => { 177 => 0x308, 179 => 0x14 }, - 'wb_rblevelscoolwhitefluor' => { 282 => 0x132 }, - 'wb_rblevelscustom' => { 177 => 0x424 }, - 'wb_rblevelscwb1' => { 278 => 0x10e }, - 'wb_rblevelscwb2' => { 278 => 0x10f }, - 'wb_rblevelscwb3' => { 278 => 0x110 }, - 'wb_rblevelscwb4' => { 278 => 0x111 }, - 'wb_rblevelsdaylight' => { 177 => [0x3ec,0x528], 179 => 0xc, 191 => 0x274 }, - 'wb_rblevelsdaylightf' => { 179 => 0x24 }, - 'wb_rblevelsdaylightfluor' => { 282 => 0x130 }, - 'wb_rblevelsdaywhitef' => { 179 => 0x28 }, - 'wb_rblevelsdaywhitefluor' => { 282 => 0x131 }, - 'wb_rblevelseveningsunlight' => { 282 => 0x124 }, - 'wb_rblevelsfineweather' => { 282 => 0x122 }, - 'wb_rblevelsflash' => { 177 => [0x3f4,0x304], 179 => 0x18, 191 => 0x2a4 }, - 'wb_rblevelsfluorescent' => { 191 => 0x290 }, - 'wb_rblevelsincandescent' => { 191 => 0x282 }, - 'wb_rblevelsshade' => { 177 => 0x418, 179 => 0x20, 191 => 0x2b2, 282 => 0x120 }, - 'wb_rblevelstungsten' => { 177 => 0x3e8, 179 => 0x8, 282 => 0x123 }, - 'wb_rblevelsunknown' => { 179 => 0x1c }, - 'wb_rblevelsused' => { 282 => 0x100 }, - 'wb_rblevelswhitef' => { 179 => 0x2c }, - 'wb_rblevelswhitefluorescent' => { 282 => 0x133 }, - 'wb_redlevel3500k' => { 177 => 0x198 }, - 'wb_redlevel6500k' => { 177 => 0x188 }, - 'wb_redlevelcustom' => { 177 => 0x18c }, - 'wb_redlevelscloudy' => { 177 => 0xf8 }, - 'wb_redlevelsdaylight' => { 177 => 0xdc }, - 'wb_redlevelsflash' => { 177 => 0x114 }, - 'wb_redlevelsfluorescent' => { 177 => [0x3fc,0x14c] }, - 'wb_redlevelskelvin' => { 177 => 0x1be }, - 'wb_redlevelsshade' => { 177 => 0x168 }, - 'wb_redlevelstungsten' => { 177 => 0xc0 }, - 'wb_rgbglevels' => { 189 => 0x0 }, - 'wb_rgblevels' => { 177 => [0x546,0x96], 293 => 0xd, 294 => 0x413, 299 => 0x3036, 341 => 0x107, 396 => 0x117c, 397 => 0x1180, 398 => 0x115c, 399 => 0x11d8, 400 => 0x11b4, 401 => 0x106c, 402 => 0x264, 403 => 0x264, 404 => 0x252 }, - 'wb_rgblevels1' => { 304 => 0x2 }, - 'wb_rgblevels2' => { 304 => 0x6 }, - 'wb_rgblevels3' => { 304 => 0xa }, - 'wb_rgblevels4' => { 304 => 0xe }, - 'wb_rgblevels5' => { 304 => 0x12 }, - 'wb_rgblevels6' => { 304 => 0x16 }, - 'wb_rgblevels7' => { 304 => 0x1a }, - 'wb_rgbmuldaylight' => { 131 => 0x852 }, - 'wb_rgbmulflash' => { 131 => 0x855 }, - 'wb_rgbmulfluorescent' => { 131 => 0x854 }, - 'wb_rgbmultungsten' => { 131 => 0x853 }, - 'wb_rggbblacklevels' => { 34 => 0x25 }, - 'wb_rggblevels' => { 180 => 0x4, 188 => 0x0, 192 => 0x13e8, 193 => 0x38 }, - 'wb_rggblevelsasshot' => { 37 => 0x0, 38 => 0x0, 39 => 0x19, 40 => 0x22, 41 => 0x3f, 44 => 0x3f, 45 => 0x3f, 46 => 0x3f, 47 => 0x47 }, - 'wb_rggblevelsauto' => { 34 => 0x1, 37 => 0x5, 38 => 0x8, 39 => 0x1e, 40 => 0x18, 41 => 0x44, 44 => 0x44, 45 => 0x44, 46 => 0x44, 47 => 0x4c, 192 => 0x1478, 193 => 0x114, 365 => 0xa022 }, - 'wb_rggblevelsblack' => { 365 => 0xa028 }, - 'wb_rggblevelscloudy' => { 34 => 0xd, 37 => 0x1e, 38 => 0x30, 39 => 0x2d, 40 => 0x31, 41 => 0x58, 44 => 0x71, 45 => 0x8a, 46 => 0x8f, 47 => 0x92, 192 => 0x1408, 193 => 0x60, 332 => 0x20f, 340 => 0x14 }, - 'wb_rggblevelscustom' => { 34 => 0x1d, 41 => 0x80, 192 => 0x1468, 193 => 0x100 }, - 'wb_rggblevelscustom1' => { 39 => 0x41 }, - 'wb_rggblevelscustom2' => { 39 => 0x46 }, - 'wb_rggblevelsdaylight' => { 34 => 0x5, 37 => 0x14, 38 => 0x20, 39 => 0x23, 40 => 0x27, 41 => 0x4e, 44 => 0x67, 45 => 0x80, 46 => 0x85, 47 => 0x88, 192 => 0x13f8, 193 => 0x4c, 332 => 0x20d, 340 => 0x2 }, - 'wb_rggblevelsflash' => { 34 => 0x19, 37 => 0x32, 38 => 0x50, 39 => 0x3c, 40 => 0x45, 41 => 0x6c, 44 => 0x85, 45 => 0x9e, 46 => 0xa3, 47 => 0xa6, 192 => 0x1448, 332 => 0x214, 340 => 0x41 }, - 'wb_rggblevelsfluorescent' => { 34 => 0x15, 37 => 0x28, 38 => 0x40, 39 => 0x37, 40 => 0x3b, 41 => 0x62, 44 => 0x7b, 45 => 0x94, 46 => 0x99, 47 => 0x9c }, - 'wb_rggblevelsfluorescentd' => { 193 => 0xc4, 332 => 0x211, 340 => 0x26 }, - 'wb_rggblevelsfluorescentl' => { 340 => 0x4a }, - 'wb_rggblevelsfluorescentn' => { 193 => 0xb0, 332 => 0x212, 340 => 0x2f }, - 'wb_rggblevelsfluorescentw' => { 192 => 0x1438, 193 => 0x9c, 332 => 0x213, 340 => 0x38 }, - 'wb_rggblevelshtmercury' => { 193 => 0xd8 }, - 'wb_rggblevelsilluminator1' => { 365 => 0xa023 }, - 'wb_rggblevelsilluminator2' => { 365 => 0xa024 }, - 'wb_rggblevelskelvin' => { 34 => 0x21, 37 => 0x2d, 38 => 0x48, 40 => 0x40, 41 => 0x67, 44 => 0x80, 45 => 0x99, 46 => 0x9e, 47 => 0xa1 }, - 'wb_rggblevelsmeasured' => { 37 => 0xa, 38 => 0x10, 41 => 0x49, 44 => 0x49, 45 => 0x49, 46 => 0x49, 47 => 0x51 }, - 'wb_rggblevelspc1' => { 40 => 0x90, 41 => 0x71 }, - 'wb_rggblevelspc2' => { 40 => 0x95, 41 => 0x76 }, - 'wb_rggblevelspc3' => { 40 => 0x9a, 41 => 0x7b }, - 'wb_rggblevelsshade' => { 34 => 0x9, 37 => 0x19, 38 => 0x28, 39 => 0x28, 40 => 0x2c, 41 => 0x53, 44 => 0x6c, 45 => 0x85, 46 => 0x8a, 47 => 0x8d, 193 => 0x74, 332 => 0x20e, 340 => 0xb }, - 'wb_rggblevelstungsten' => { 34 => 0x11, 37 => 0x23, 38 => 0x38, 39 => 0x32, 40 => 0x36, 41 => 0x5d, 44 => 0x76, 45 => 0x8f, 46 => 0x94, 47 => 0x97, 192 => 0x1428, 193 => 0x88, 332 => 0x210, 340 => 0x1d }, - 'wb_rggblevelsuncorrected' => { 365 => 0xa021 }, - 'wb_rggblevelsunknown' => { 37 => 0xf, 38 => 0x18, 40 => 0x1d, 44 => 0x4e, 45 => 0x4e, 46 => 0x4e, 47 => 0x56, 340 => 0x53 }, - 'wb_rggblevelsunknown10' => { 37 => 0x5f, 38 => 0x98, 40 => 0x72, 44 => 0x9e, 45 => 0x7b, 46 => 0x7b, 47 => 0x83 }, - 'wb_rggblevelsunknown11' => { 37 => 0x64, 38 => 0xa0, 40 => 0x77, 44 => 0xa3, 45 => 0xa3, 46 => 0x80, 47 => 0xab }, - 'wb_rggblevelsunknown12' => { 37 => 0x69, 38 => 0xa8, 40 => 0x7c, 44 => 0xa8, 45 => 0xa8, 46 => 0xa8, 47 => 0xb0 }, - 'wb_rggblevelsunknown13' => { 37 => 0x6e, 38 => 0xb0, 40 => 0x81, 44 => 0xad, 45 => 0xad, 46 => 0xad, 47 => 0xb5 }, - 'wb_rggblevelsunknown14' => { 40 => 0x86, 44 => 0xb2, 45 => 0xb2, 46 => 0xb2, 47 => 0xba }, - 'wb_rggblevelsunknown15' => { 40 => 0x8b, 44 => 0xb7, 45 => 0xb7, 46 => 0xb7, 47 => 0xbf }, - 'wb_rggblevelsunknown16' => { 40 => 0x9f, 45 => 0xbc, 46 => 0xbc, 47 => 0xc4 }, - 'wb_rggblevelsunknown17' => { 45 => 0xc1, 46 => 0xc1, 47 => 0xc9 }, - 'wb_rggblevelsunknown18' => { 45 => 0xc6, 46 => 0xc6, 47 => 0xce }, - 'wb_rggblevelsunknown19' => { 45 => 0xcb, 46 => 0xcb, 47 => 0xd3 }, - 'wb_rggblevelsunknown2' => { 37 => 0x37, 38 => 0x58, 40 => 0x4a, 44 => 0x53, 45 => 0x53, 46 => 0x53, 47 => 0x5b }, - 'wb_rggblevelsunknown20' => { 45 => 0xd0, 46 => 0xd0, 47 => 0xd8 }, - 'wb_rggblevelsunknown21' => { 46 => 0xd5, 47 => 0xdd }, - 'wb_rggblevelsunknown22' => { 46 => 0xda, 47 => 0xe2 }, - 'wb_rggblevelsunknown23' => { 46 => 0xdf, 47 => 0xe7 }, - 'wb_rggblevelsunknown24' => { 46 => 0xe4, 47 => 0xec }, - 'wb_rggblevelsunknown25' => { 46 => 0xe9, 47 => 0xf1 }, - 'wb_rggblevelsunknown26' => { 46 => 0xee, 47 => 0xf6 }, - 'wb_rggblevelsunknown27' => { 46 => 0xf3, 47 => 0xfb }, - 'wb_rggblevelsunknown28' => { 46 => 0xf8, 47 => 0x100 }, - 'wb_rggblevelsunknown29' => { 46 => 0xfd, 47 => 0x105 }, - 'wb_rggblevelsunknown3' => { 37 => 0x3c, 38 => 0x60, 40 => 0x4f, 44 => 0x58, 45 => 0x58, 46 => 0x58, 47 => 0x60 }, - 'wb_rggblevelsunknown30' => { 46 => 0x102 }, - 'wb_rggblevelsunknown4' => { 37 => 0x41, 38 => 0x68, 40 => 0x54, 44 => 0x5d, 45 => 0x5d, 46 => 0x5d, 47 => 0x65 }, - 'wb_rggblevelsunknown5' => { 37 => 0x46, 38 => 0x70, 40 => 0x59, 44 => 0x62, 45 => 0x62, 46 => 0x62, 47 => 0x6a }, - 'wb_rggblevelsunknown6' => { 37 => 0x4b, 38 => 0x78, 40 => 0x5e, 44 => 0x8a, 45 => 0x67, 46 => 0x67, 47 => 0x6f }, - 'wb_rggblevelsunknown7' => { 37 => 0x50, 38 => 0x80, 40 => 0x63, 44 => 0x8f, 45 => 0x6c, 46 => 0x6c, 47 => 0x74 }, - 'wb_rggblevelsunknown8' => { 37 => 0x55, 38 => 0x88, 40 => 0x68, 44 => 0x94, 45 => 0x71, 46 => 0x71, 47 => 0x79 }, - 'wb_rggblevelsunknown9' => { 37 => 0x5a, 38 => 0x90, 40 => 0x6d, 44 => 0x99, 45 => 0x76, 46 => 0x76, 47 => 0x7e }, - 'wb_rggblevelsuserselected' => { 340 => 0x5c }, - 'wbadjblueamber' => { 97 => 0x20106 }, - 'wbadjbluebalance' => { 256 => 0x8 }, - 'wbadjcolortemp' => { 97 => 0x20102, 102 => 0x1a }, - 'wbadjlighting' => { 256 => 0x14 }, - 'wbadjmagentagreen' => { 97 => 0x20105 }, - 'wbadjmode' => { 256 => 0x10 }, - 'wbadjredbalance' => { 256 => 0x0 }, - 'wbadjrggblevels' => { 97 => 0x20125, 102 => 0x6 }, - 'wbadjtemperature' => { 256 => 0x18 }, - 'wbadjtint' => { 256 => 0x25 }, - 'wbbluelevel' => { 292 => 0x324, 297 => 0x8006, 302 => 0x26 }, - 'wbbracketingsteps' => { 228 => 0x174d, 229 => 0x87c, 237 => 0x1757 }, - 'wbbracketmode' => { 54 => 0x9 }, - 'wbbracketshotnumber' => { 177 => 0x2b, 358 => 0x101a }, - 'wbbracketvalueab' => { 54 => 0xc }, - 'wbbracketvaluegm' => { 54 => 0xd }, - 'wbfinetuneactive' => { 102 => 0x24 }, - 'wbfinetunesaturation' => { 102 => 0x28 }, - 'wbfinetunetone' => { 102 => 0x2c }, - 'wbgreenlevel' => { 292 => 0x323, 297 => 0x8005, 302 => 0x25 }, - 'wbmediaimagesizesetting' => { 78 => 0x708 }, - 'wbmode' => { 179 => 0x4, 279 => 0x1015 }, - 'wbredlevel' => { 292 => 0x322, 297 => 0x8004, 302 => 0x24 }, - 'wbscale' => { 180 => 0x0 }, - 'wbshiftab' => { 70 => 0xc, 297 => 0x46, 314 => 0x10 }, - 'wbshiftab_gm' => { 388 => 0x2014 }, - 'wbshiftab_gm_precise' => { 388 => 0x2026 }, - 'wbshiftcreativecontrol' => { 297 => 0x92 }, - 'wbshiftgm' => { 70 => 0xd, 297 => 0x47, 314 => 0x11 }, - 'wbshiftintelligentauto' => { 297 => 0x8b }, - 'wbtype1' => { 303 => 0x1, 304 => 0x1 }, - 'wbtype2' => { 303 => 0x4, 304 => 0x5 }, - 'wbtype3' => { 303 => 0x7, 304 => 0x9 }, - 'wbtype4' => { 303 => 0xa, 304 => 0xd }, - 'wbtype5' => { 303 => 0xd, 304 => 0x11 }, - 'wbtype6' => { 303 => 0x10, 304 => 0x15 }, - 'wbtype7' => { 303 => 0x13, 304 => 0x19 }, - 'webstatement' => { 470 => 'WebStatement' }, - 'what' => { 442 => 'What' }, - 'whitebalance' => { 6 => 0x6f, 7 => [0x44,0x4a], 8 => 0xbc, 9 => 0x36, 10 => 0x5e, 11 => 0x36, 12 => 0x78, 13 => 0x6f, 14 => 0x6f, 15 => 0x73, 16 => 0x6f, 17 => 0x78, 18 => 0x54, 19 => 0x6f, 20 => 0xbc, 21 => 0x7b, 23 => 0xbc, 24 => 0xc2, 26 => 0x131, 27 => 0x77, 70 => 0x8, 72 => 0x7, 106 => 0x7, 107 => [0x19,0x2012], 113 => [0xa403,0xfe4e], 121 => 0x1002, 131 => 0x3fc, 132 => 0xfa0d, 133 => 0x40, 171 => 0x3, 172 => 0xe, 173 => 0x4, 174 => 0xb, 176 => 0x115, 211 => 0x5, 240 => 0x7, 292 => 0x304, 297 => 0x3, 299 => 0x3033, 332 => 0x19, 339 => 0x7, 357 => 0x26, 358 => 0x1003, 368 => [0x3c,0x7,0x58], 376 => 0xf, 377 => 0xe, 388 => [0x115,0xb054], 442 => 'WhiteBalance', 446 => 'WhiteBalance' }, - 'whitebalance0' => { 167 => 'WhiteBalance0' }, - 'whitebalance1' => { 167 => 'WhiteBalance1' }, - 'whitebalance2' => { 167 => 'WhiteBalance2', 274 => 0x500 }, - 'whitebalanceadj' => { 97 => 0x20101, 102 => 0x18, 250 => 0x76a43204 }, - 'whitebalanceautoadjustment' => { 310 => 0x0 }, - 'whitebalancebias' => { 107 => 0x2011, 279 => 0x304, 297 => 0x23 }, - 'whitebalanceblue' => { 70 => 0x7 }, - 'whitebalancebracket' => { 274 => 0x502, 279 => 0x303 }, - 'whitebalancebracketing' => { 174 => 0x22, 177 => 0x2c, 387 => 0x2c }, - 'whitebalancecomp' => { 282 => 0x1001 }, - 'whitebalancedetected' => { 131 => 0x3fb }, - 'whitebalancefinetune' => { 121 => 0x100a, 174 => 0x38, 176 => 0x112, 211 => 0xb, 358 => 0x1004, 376 => 0x6, 377 => 0x5, 388 => 0x112 }, - 'whitebalancemode' => { 131 => 0x3fa, 332 => 0x1a }, - 'whitebalancered' => { 70 => 0x6 }, - 'whitebalanceset' => { 313 => 0xa }, - 'whitebalancesetting' => { 174 => 0x23, 376 => 0x5, 377 => 0x4, 378 => 0x16, 393 => 0xd }, - 'whitebalancesetup' => { 365 => 0x41 }, - 'whitebalancetemperature' => { 274 => 0x501 }, - 'whiteboard' => { 279 => 0x301 }, - 'whitelevel' => { 113 => 0xc61d, 332 => 0x7e }, - 'whitepoint' => { 113 => 0x13e, 332 => 0x201, 462 => 'WhitePoint' }, - 'whites2012' => { 442 => 'Whites2012' }, - 'whitesadj' => { 421 => 0x9017 }, - 'wideadapter' => { 358 => 0x1017 }, - 'widefocuszone' => { 171 => 0x2f }, - 'widerange' => { 367 => 0x20f }, - 'windmode' => { 131 => 0x3f4 }, - 'windowsatom' => { 441 => 'windowsAtom' }, - 'windowsatomextension' => { 441 => [\'windowsAtom','windowsAtomExtension'] }, - 'windowsatominvocationflags' => { 441 => [\'windowsAtom','windowsAtomInvocationFlags'] }, - 'windowsatomuncprojectpath' => { 441 => [\'windowsAtom','windowsAtomUncProjectPath'] }, - 'wordcount' => { 456 => 'wordCount' }, - 'workcolorspace' => { 97 => 0x10200, 102 => 0x270 }, - 'workflowtag' => { 452 => 'WorkflowTag' }, - 'workflowtagcvid' => { 452 => [\'WorkflowTag','WorkflowTagCvId'] }, - 'workflowtagcvtermid' => { 452 => [\'WorkflowTag','WorkflowTagCvTermId'] }, - 'workflowtagcvtermname' => { 452 => [\'WorkflowTag','WorkflowTagCvTermName'] }, - 'workflowtagcvtermrefinedabout' => { 452 => [\'WorkflowTag','WorkflowTagCvTermRefinedAbout'] }, - 'worktodo' => { 448 => 'WorkToDo' }, - 'worldtimelocation' => { 297 => 0x3a, 332 => 0x22, 338 => '0.1' }, - 'writer-editor' => { 125 => 0x7a }, - 'x3filllight' => { 368 => 0x12 }, - 'xattrquarantine' => { 165 => 'com.apple.quarantine' }, - 'xilinxversion' => { 131 => 0x414 }, - 'xml' => { 129 => 'xml ' }, - 'xmp' => { 100 => 0xffff00f6, 114 => 'XMP' }, - 'xmptoolkit' => { 463 => 'xmptk' }, - 'xpauthor' => { 113 => 0x9c9d }, - 'xpcomment' => { 113 => 0x9c9c }, - 'xpkeywords' => { 113 => 0x9c9e }, - 'xposition' => { 113 => 0x11e }, - 'xpsubject' => { 113 => 0x9c9f }, - 'xptitle' => { 113 => 0x9c9b }, - 'xresolution' => { 113 => 0x11a, 128 => 0x3, 347 => 0x0, 462 => 'XResolution' }, - 'xyresolution' => { 117 => 0x3 }, - 'yaw' => { 109 => 0x7 }, - 'yawangle' => { 228 => 0x3513, 229 => 0x2c2c, 237 => 0x36fc, 363 => 0x0 }, - 'ycbcrcoefficients' => { 113 => 0x211, 462 => 'YCbCrCoefficients' }, - 'ycbcrpositioning' => { 113 => 0x213, 462 => 'YCbCrPositioning' }, - 'ycbcrsubsampling' => { 113 => 0x212, 462 => 'YCbCrSubSampling' }, - 'yearcreated' => { 133 => 0x10, 142 => 0xc }, - 'yellowhsl' => { 97 => 0x20912 }, - 'yield' => { 458 => 'yield' }, - 'yposition' => { 113 => 0x11f }, - 'yresolution' => { 113 => 0x11b, 128 => 0x5, 347 => 0x4, 462 => 'YResolution' }, - 'zonematching' => { 176 => 0x10a, 179 => [0x3a,0x4a], 388 => 0xb024 }, - 'zonematchingmode' => { 174 => 0x14 }, - 'zonematchingon' => { 173 => 0x75 }, - 'zonematchingvalue' => { 376 => 0x1f }, - 'zoomedpreviewlength' => { 279 => 0xf05 }, - 'zoomedpreviewsize' => { 279 => 0xf06 }, - 'zoomedpreviewstart' => { 279 => 0xf04 }, - 'zoomsourcewidth' => { 33 => 0x24 }, - 'zoomstepcount' => { 277 => 0x300, 279 => 0x100d }, - 'zoomtargetwidth' => { 33 => 0x25 }, + 'selectafareaselectmode' => { 84 => 0x512 }, + 'selfdata' => { 116 => 'SelfData' }, + 'selftimer' => { 34 => 0x2, 320 => 0x2e, 396 => 0x214, 429 => 0x1134, 430 => 0x1134, 431 => 0x1110, 432 => 0x118c, 433 => 0x1168, 434 => 0x1020, 435 => 0x218, 436 => 0x218, 437 => 0x210 }, + 'selftimer2' => { 77 => 0x1d }, + 'selftimerinterval' => { 289 => '19.2' }, + 'selftimermode' => { 119 => 0x882b }, + 'selftimershotcount' => { 280 => '20.2', 282 => '20.3', 283 => '20.3', 284 => '18.2', 285 => '19.2', 286 => '19.2', 287 => '19.3', 289 => '19.3', 292 => '20.3', 293 => '20.3', 294 => '20.2', 295 => 0x2d }, + 'selftimershotinterval' => { 280 => '20.3', 282 => '20.2', 283 => '20.2', 287 => '19.2', 292 => '20.2', 293 => '20.2', 295 => 0x31 }, + 'selftimertime' => { 97 => 0x1806, 184 => 0x1f, 279 => '18.1', 280 => '20.1', 281 => '3.3', 282 => '20.1', 283 => '20.1', 284 => '18.1', 285 => '19.1', 286 => '19.1', 287 => '19.1', 288 => '7.2', 289 => '19.1', 290 => '3.3', 292 => '20.1', 293 => '20.1', 294 => '20.1', 295 => 0x2b }, + 'sellingagency' => { 494 => 'sellingAgency' }, + 'seminfo' => { 119 => 0x8546 }, + 'sensingmethod' => { 119 => 0xa217, 484 => 'SensingMethod' }, + 'sensitivityadjust' => { 355 => 0x40 }, + 'sensitivitysteps' => { 336 => ['14.3','17.4'], 338 => 0x1 }, + 'sensitivitytype' => { 119 => 0x8830, 485 => 'SensitivityType' }, + 'sensor' => { 191 => 0x665e }, + 'sensorarea' => { 302 => 0x400 }, + 'sensorareas' => { 394 => 0xa010 }, + 'sensorbitdepth' => { 322 => 0x312d }, + 'sensorbluelevel' => { 74 => 0x5 }, + 'sensorcalibration' => { 301 => 0x805 }, + 'sensorcleaning' => { 90 => 0xd }, + 'sensorfullheight' => { 137 => 0xf904 }, + 'sensorfullwidth' => { 137 => 0xf903 }, + 'sensorheight' => { 137 => 0xf901, 142 => 0xfa21, 188 => 0x8, 322 => 0x312c, 364 => 0x109, 387 => 0x1602 }, + 'sensorimageheight' => { 138 => 0x3ee }, + 'sensorimagewidth' => { 138 => 0x3ed }, + 'sensorleftborder' => { 138 => 0x3eb }, + 'sensorleftmargin' => { 364 => 0x10a }, + 'sensorpixelsize' => { 226 => 0x9a }, + 'sensorredlevel' => { 74 => 0x4 }, + 'sensorserialnumber' => { 138 => 0x9ce }, + 'sensorshield' => { 229 => 0x66d }, + 'sensorsize' => { 156 => 'SensorSize', 355 => 0x35 }, + 'sensortemperature' => { 300 => 0x1500, 302 => 0x1007, 360 => 0xc, 364 => 0x210, 397 => [0x39,0x55] }, + 'sensortemperature2' => { 360 => 0xe, 364 => 0x211 }, + 'sensortopborder' => { 138 => 0x3ec }, + 'sensortopmargin' => { 364 => 0x10b }, + 'sensortype' => { 320 => 0xca }, + 'sensorwidth' => { 137 => 0xf900, 142 => 0xfa20, 188 => 0xa, 322 => 0x312b, 364 => 0x108, 387 => 0x1601 }, + 'sequence' => { 381 => 0x7, 382 => 0x35, 383 => 0x36 }, + 'sequencefilenumber' => { 430 => 0x4, 431 => 0x4, 432 => 0x4, 433 => 0x4, 442 => 0xc, 443 => 0xc, 444 => 0x1a }, + 'sequenceimagenumber' => { 430 => 0x0, 431 => 0x0, 432 => 0x0, 433 => 0x0, 442 => 0x8, 443 => 0x8, 444 => 0x12, 451 => 0x24 }, + 'sequencelength' => { 442 => 0x22, 443 => 0x1e, 444 => [0x16,0x1e] }, + 'sequencename' => { 493 => 'sequenceName' }, + 'sequencenumber' => { 77 => 0x9, 113 => 0x301c, 127 => 0x1101, 140 => 0x1d, 256 => 0x51c, 320 => 0x2b, 409 => [0x10c,0x30c], 420 => 0xb04a, 493 => 'sequenceNumber' }, + 'sequenceshotinterval' => { 396 => 0x224 }, + 'sequencetotalnumber' => { 493 => 'sequenceTotalNumber' }, + 'sequentialshot' => { 396 => 0x20e }, + 'serialnumber' => { 64 => 0xc, 97 => 0x180b, 119 => [0xa431,0xfde9], 137 => 0xfa04, 139 => 0xfa00, 141 => 0xc354, 142 => 0xfa19, 153 => 0x0, 156 => 'SerialNumber', 191 => 0x5501, 226 => [0xa0,0x1d], 298 => 0x101, 302 => [0x404,0x101a], 315 => 0x303, 317 => 0x305, 322 => 0x3103, 355 => 0x229, 364 => 0x102, 365 => 0x407, 380 => ['SNum','slno'], 381 => 0x15, 382 => 0x4b, 383 => 0x7e, 387 => 0x5, 394 => 0xa002, 397 => 0x2, 420 => 0x2031, 475 => 'SerialNumber', 485 => 'BodySerialNumber' }, + 'serialnumberformat' => { 64 => 0x15, 97 => 0x183b }, + 'serialnumberhash' => { 380 => 'CAME' }, + 'series' => { 490 => 'Series' }, + 'seriesdatetime' => { 457 => 'SeriesDateTime' }, + 'seriesdescription' => { 457 => 'SeriesDescription' }, + 'seriesidentifier' => { 490 => [\'Series','SeriesIdentifier'] }, + 'seriesmodality' => { 457 => 'SeriesModality' }, + 'seriesname' => { 490 => [\'Series','SeriesName'] }, + 'seriesnumber' => { 457 => 'SeriesNumber', 494 => 'seriesNumber' }, + 'seriestitle' => { 494 => 'seriesTitle' }, + 'serviceidentifier' => { 132 => 0x1e }, + 'servingsize' => { 496 => 'servingSize' }, + 'setbuttoncrosskeysfunc' => { 87 => 0x0, 88 => 0x0 }, + 'setbuttonwhenshooting' => { 82 => 0x1, 84 => 0x704, 90 => 0xc }, + 'setclockfromlocationdata' => { 229 => 0x61d }, + 'setfunctionwhenshooting' => { 85 => 0x0, 86 => 0x1, 89 => 0x1 }, + 'setting' => { 493 => 'setting' }, + 'shadingcompensation' => { 297 => 0x50c, 320 => 0x8a }, + 'shadingcompensation2' => { 301 => 0x1012 }, + 'shadow' => { 397 => 0xe }, + 'shadowadj' => { 103 => 0x2030b }, + 'shadowcorrection' => { 355 => 0x79 }, + 'shadowprotection' => { 271 => 0x0 }, + 'shadows' => { 119 => 0xfe52, 420 => 0x2032, 472 => 'Shadows', 478 => 'Shadows', 480 => 'Shadows' }, + 'shadows2012' => { 478 => 'Shadows2012', 480 => 'Shadows2012' }, + 'shadowsadj' => { 455 => 0x901a }, + 'shadowscale' => { 119 => 0xc633 }, + 'shadowtint' => { 478 => 'ShadowTint', 480 => 'ShadowTint' }, + 'shadowtone' => { 127 => 0x1040 }, + 'shakereduction' => { 357 => 0x1, 358 => 0x1 }, + 'shareduserrating' => { 179 => 'WM/SharedUserRating' }, + 'sharpendetail' => { 478 => 'SharpenDetail', 480 => 'SharpenDetail' }, + 'sharpenedgemasking' => { 478 => 'SharpenEdgeMasking', 480 => 'SharpenEdgeMasking' }, + 'sharpening' => { 322 => 0x300b }, + 'sharpeningadj' => { 275 => 0x2b }, + 'sharpeningkernel' => { 138 => 0x92f }, + 'sharpenradius' => { 478 => 'SharpenRadius', 480 => 'SharpenRadius' }, + 'sharpness' => { 8 => [0x42,0x48], 10 => 0x72, 12 => 0x74, 34 => 0xf, 63 => 0x6, 74 => 0x2, 112 => 0xb, 113 => [0x3011,0x21], 119 => [0xa40a,0xfe56], 127 => 0x1001, 140 => 0x6b, 149 => 0x37, 156 => 'Sharpness', 181 => 0x21, 182 => 0x30, 183 => 0x26, 184 => 0x18, 189 => 0x3, 226 => 0x6, 231 => 0x32, 232 => 0x33, 233 => 0x39, 302 => 0x100f, 320 => 0x41, 355 => 0x21, 362 => 0xb, 381 => 0x26, 383 => 0x56, 386 => 0x22, 387 => [0x1003,0x1014], 397 => 0x11, 407 => 0x1c, 408 => 0x19, 420 => 0x2006, 451 => 0x52, 478 => 'Sharpness', 480 => 'Sharpness', 484 => 'Sharpness' }, + 'sharpnessadj' => { 103 => 0x20310, 108 => 0x25a, 455 => 0x801a }, + 'sharpnessadjon' => { 103 => '0x20310.0' }, + 'sharpnessauto' => { 71 => 0x94 }, + 'sharpnessfactor' => { 302 => 0x102a }, + 'sharpnessfaithful' => { 19 => 0xf5, 70 => 0x64, 71 => 0x64 }, + 'sharpnessfrequency' => { 8 => [0x41,0x47], 74 => 0x3 }, + 'sharpnesslandscape' => { 19 => 0xf3, 70 => 0x34, 71 => 0x34 }, + 'sharpnessmonochrome' => { 19 => 0xf6, 70 => 0x7c, 71 => 0x7c }, + 'sharpnessneutral' => { 19 => 0xf4, 70 => 0x4c, 71 => 0x4c }, + 'sharpnessovershoot' => { 455 => 0x801b }, + 'sharpnessportrait' => { 19 => 0xf2, 70 => 0x1c, 71 => 0x1c }, + 'sharpnessrange' => { 420 => 0x2035 }, + 'sharpnesssetting' => { 297 => 0x506, 305 => 0x1013, 409 => 0x12, 425 => 0xa }, + 'sharpnessstandard' => { 19 => 0xf1, 70 => 0x4, 71 => 0x4 }, + 'sharpnessstrength' => { 103 => 0x20311 }, + 'sharpnessthreshold' => { 455 => 0x801d }, + 'sharpnessundershoot' => { 455 => 0x801c }, + 'sharpnessuserdef1' => { 19 => 0xf7, 70 => 0x94, 71 => 0xac }, + 'sharpnessuserdef2' => { 19 => 0xf8, 70 => 0xac, 71 => 0xc4 }, + 'sharpnessuserdef3' => { 19 => 0xf9, 70 => 0xc4, 71 => 0xdc }, + 'shiftcols' => { 138 => 0xc70 }, + 'shootid' => { 493 => 'shootID' }, + 'shootingdistance' => { 103 => 0x20701 }, + 'shootinginfodisplay' => { 279 => '13.2', 280 => '5.1', 288 => '10.2', 289 => '4.1', 292 => '5.1', 294 => '5.3' }, + 'shootinginfomonitorofftime' => { 279 => '26.2', 280 => '22.2', 282 => '22.2', 283 => '22.2', 287 => '21.2', 288 => '9.1', 289 => '21.2', 292 => '22.2', 293 => '22.2', 294 => '22.2', 295 => 0x37 }, + 'shootingmode' => { 156 => 'ShootingMode', 226 => 0x89, 320 => 0x1f }, + 'shootingmodesetting' => { 281 => '5.1' }, + 'shortdescription' => { 482 => 'shortdescription' }, + 'shortdocumentid' => { 131 => 0xba }, + 'shortname' => { 478 => 'ShortName', 480 => 'ShortName' }, + 'shortownername' => { 19 => 0xac }, + 'shortreleasetimelag' => { 84 => 0x80d }, + 'shorttitle' => { 372 => '@sti' }, + 'shotdate' => { 504 => 'shotDate' }, + 'shotday' => { 504 => 'shotDay' }, + 'shotlocation' => { 504 => 'shotLocation' }, + 'shotname' => { 380 => 'shot', 504 => 'shotName' }, + 'shotnumber' => { 504 => 'shotNumber' }, + 'shotnumbersincepowerup' => { 424 => 0x44e, 442 => 0x1a, 443 => 0x16, 444 => 0xa }, + 'shotnumbersincepowerup2' => { 409 => 0x200 }, + 'shotsize' => { 504 => 'shotSize' }, + 'shotsperinterval' => { 228 => 0xb4, 229 => 0xc0, 252 => 0xc412 }, + 'showmovement' => { 372 => 'shwm' }, + 'shownevent' => { 490 => 'EventExt' }, + 'showneventidentifier' => { 490 => [\'EventExt','EventExtIdentifier'] }, + 'showneventname' => { 490 => [\'EventExt','EventExtName'] }, + 'shutter' => { 439 => 0x20, 440 => 0x26, 441 => 0x26 }, + 'shutter-aelock' => { 82 => 0x4, 84 => 0x701, 85 => 0x3, 86 => 0x4, 87 => 0x3, 88 => 0x3, 89 => 0x4, 90 => 0x2 }, + 'shutteraelbutton' => { 83 => 0x4 }, + 'shutterbuttonafonbutton' => { 84 => 0x701 }, + 'shuttercount' => { 11 => 0x176, 57 => 0x1, 226 => 0xa7, 238 => [0x6a,0x157,0x24d], 239 => 0x286, 240 => 0x279, 241 => 0x284, 242 => 0x242, 243 => 0x280, 244 => 0x276, 245 => [0x27d,0x27f], 246 => 0x246, 249 => 0x2d6, 250 => 0x321, 251 => 0xbd8, 253 => 0x287, 254 => 0x320, 255 => 0x24a, 256 => 0x5fb, 259 => 0x2d5, 355 => 0x5d, 418 => 0x846, 423 => [0x125,0x14a], 439 => 0x32, 440 => 0x3a, 441 => 0x3a }, + 'shuttercount2' => { 439 => 0x4c, 440 => [0x50,0x52,0x58], 441 => 0x50 }, + 'shuttercount3' => { 439 => [0x1a0,0x1aa,0x1bd], 440 => [0x19f,0x1cb,0x1cd] }, + 'shuttercurtainsync' => { 82 => 0xf, 83 => 0xf, 84 => 0x305, 85 => 0xe, 86 => 0xf, 87 => 0x8, 88 => 0x8, 89 => 0xf, 90 => 0x8 }, + 'shuttermode' => { 57 => 0x17, 140 => 0x1b, 226 => 0x34 }, + 'shutterreleasebuttonae-l' => { 279 => '17.7', 280 => '18.4', 282 => '78.4', 283 => '78.4', 284 => '16.1', 285 => '17.1', 286 => '17.1', 287 => '17.1', 288 => '7.1', 289 => '17.5', 292 => '18.4', 293 => '78.4', 294 => '18.2', 295 => 0x29 }, + 'shutterreleasemethod' => { 97 => 0x1010 }, + 'shutterreleasenocfcard' => { 82 => 0x2, 83 => 0x2, 90 => 0xf }, + 'shutterreleasetiming' => { 97 => 0x1011 }, + 'shutterreleasewithoutlens' => { 84 => 0x711 }, + 'shutterspeedlock' => { 280 => '38.1', 282 => '38.1', 283 => '38.1', 292 => '38.1', 293 => '38.1', 295 => 0xb7 }, + 'shutterspeedrange' => { 84 => 0x10c }, + 'shutterspeedsetting' => { 184 => 0x6, 407 => 0x2f, 408 => 0x28, 409 => 0x0 }, + 'shutterspeedvalue' => { 93 => 0x1, 119 => 0x9201, 302 => 0x1000, 364 => 0x400, 484 => 'ShutterSpeedValue' }, + 'shuttertype' => { 127 => 0x1050, 320 => 0x9f, 355 => 0x87 }, + 'sidecarforextension' => { 492 => 'SidecarForExtension' }, + 'sigmaimpulseparameters' => { 138 => 0xe0d }, + 'sigmascalingfactorcamera' => { 138 => 0xe0c }, + 'sigmascalingfactorlowres' => { 138 => 0xe0b }, + 'sigmasizetable' => { 138 => 0xe0f }, + 'silentphotography' => { 226 => 0xbf }, + 'similarityindex' => { 131 => 0xe4 }, + 'singleframebracketing' => { 184 => 0x21 }, + 'skilllevel' => { 496 => 'skillLevel' }, + 'skintonecorrection' => { 355 => 0x95 }, + 'skiplinetime' => { 138 => 0x184e }, + 'slaveflashmeteringsegments' => { 355 => 0x20b }, + 'slideshowname' => { 493 => 'slideshowName' }, + 'slideshownumber' => { 493 => 'slideshowNumber' }, + 'slideshowtotalnumber' => { 493 => 'slideshowTotalNumber' }, + 'slowshutter' => { 77 => 0x8 }, + 'slowsync' => { 127 => 0x1030 }, + 'smartalbumcolor' => { 394 => 0x20 }, + 'smartrange' => { 394 => 0xa012 }, + 'smileshutter' => { 409 => 0x31 }, + 'smileshuttermode' => { 409 => 0x27 }, + 'smoothness' => { 119 => 0xfe57, 478 => 'Smoothness', 480 => 'Smoothness' }, + 'snapshot' => { 490 => 'SnapshotLink' }, + 'snapshotformat' => { 490 => [\'SnapshotLink','SnapshotLinkFormat'] }, + 'snapshotheightpixels' => { 490 => [\'SnapshotLink','SnapshotLinkHeightPixels'] }, + 'snapshotimagerole' => { 490 => [\'SnapshotLink','SnapshotLinkImageRole'] }, + 'snapshotlink' => { 490 => [\'SnapshotLink','SnapshotLinkLink'] }, + 'snapshotlinkqualifier' => { 490 => [\'SnapshotLink','SnapshotLinkLinkQualifier'] }, + 'snapshots' => { 473 => 'Snapshots' }, + 'snapshotusedvideoframe' => { 490 => [\'SnapshotLink','SnapshotLinkUsedVideoFrame'] }, + 'snapshotusedvideoframetimeformat' => { 490 => [\'SnapshotLink','SnapshotLinkUsedVideoFrameTimeFormat'] }, + 'snapshotusedvideoframetimevalue' => { 490 => [\'SnapshotLink','SnapshotLinkUsedVideoFrameTimeValue'] }, + 'snapshotusedvideoframevalue' => { 490 => [\'SnapshotLink','SnapshotLinkUsedVideoFrameValue'] }, + 'snapshotwidthpixels' => { 490 => [\'SnapshotLink','SnapshotLinkWidthPixels'] }, + 'softskineffect' => { 420 => 0x200f }, + 'software' => { 119 => 0x131, 157 => 'Software', 310 => 'Software', 364 => 0x203, 374 => 'software', 397 => 0x18, 463 => 'Software', 500 => 'Software' }, + 'softwareversion' => { 380 => ['@swr',"\xa9swr"], 396 => 0x207 }, + 'soloist' => { 372 => "\xa9sol" }, + 'songwriter' => { 380 => "\xa9swf" }, + 'songwriterkeywords' => { 380 => "\xa9swk" }, + 'sonycropsize' => { 119 => 0x74c8 }, + 'sonycroptopleft' => { 119 => 0x74c7 }, + 'sonydatetime' => { 428 => 0x6, 430 => 0x1b6, 431 => 0x210, 432 => 0x1fe, 433 => 0x22c }, + 'sonydatetime2' => { 439 => 0x51 }, + 'sonyexposuretime' => { 439 => 0x3a, 440 => 0x46, 441 => [0x66,0x46] }, + 'sonyexposuretime2' => { 451 => 0xe }, + 'sonyfnumber' => { 439 => 0x3c, 440 => 0x48, 441 => [0x68,0x48], 451 => 0x14 }, + 'sonyimageheight' => { 428 => 0x1a, 442 => 0x44, 443 => 0x3f, 444 => 0x47 }, + 'sonyimageheightmax' => { 451 => 0x40 }, + 'sonyimagesize' => { 184 => 0x3b, 407 => 0x54, 408 => 0x54, 409 => 0x9 }, + 'sonyimagewidth' => { 428 => 0x1c }, + 'sonyimagewidthmax' => { 451 => 0x3e }, + 'sonyiso' => { 430 => 0x1218, 431 => 0x11f4, 432 => 0x1270, 433 => [0x1254,0x1258,0x1280], 434 => 0x113c, 435 => 0x344, 436 => 0x346, 437 => 0x320, 451 => 0x4 }, + 'sonymaxaperture' => { 439 => 0x0, 440 => 0x0 }, + 'sonymaxaperturevalue' => { 451 => 0x16 }, + 'sonyminaperture' => { 439 => 0x1, 440 => 0x1 }, + 'sonymodelid' => { 420 => 0xb001 }, + 'sonyquality' => { 184 => 0x3c }, + 'sonytimeminsec' => { 440 => 0x61 }, + 'sortalbum' => { 372 => 'soal' }, + 'sortalbumartist' => { 372 => 'soaa' }, + 'sortartist' => { 372 => 'soar' }, + 'sortcomposer' => { 372 => 'soco' }, + 'sortname' => { 372 => 'sonm', 478 => 'SortName', 480 => 'SortName' }, + 'sortshow' => { 372 => 'sosn' }, + 'soundengineer' => { 372 => "\xa9sne" }, + 'source' => { 131 => 0x73, 310 => 'Source', 481 => 'source', 482 => 'source', 492 => 'Source' }, + 'sourcecount' => { 467 => 'SourceCount' }, + 'sourcecredits' => { 380 => "\xa9src" }, + 'sourcedirectoryindex' => { 342 => 0x0 }, + 'sourcefileindex' => { 342 => 0x2 }, + 'sourcephotoscount' => { 466 => 'SourcePhotosCount' }, + 'sourceprofileprefix' => { 138 => 0x1390 }, + 'spatialfrequencyresponse' => { 484 => 'SpatialFrequencyResponse' }, + 'spatialfrequencyresponsecolumns' => { 484 => [\'SpatialFrequencyResponse','SpatialFrequencyResponseColumns'] }, + 'spatialfrequencyresponsenames' => { 484 => [\'SpatialFrequencyResponse','SpatialFrequencyResponseNames'] }, + 'spatialfrequencyresponserows' => { 484 => [\'SpatialFrequencyResponse','SpatialFrequencyResponseRows'] }, + 'spatialfrequencyresponsevalues' => { 484 => [\'SpatialFrequencyResponse','SpatialFrequencyResponseValues'] }, + 'speakerplacement' => { 504 => 'speakerPlacement' }, + 'specialeffectlevel' => { 113 => 0x3030 }, + 'specialeffectmode' => { 113 => 0x2076 }, + 'specialeffectsetting' => { 113 => 0x3031 }, + 'specialinstructions' => { 131 => 0x28 }, + 'specialmode' => { 302 => 0x200, 396 => 0x200 }, + 'specialoccasion' => { 496 => 'specialOccasion' }, + 'specialtypeid' => { 461 => 'SpecialTypeID' }, + 'spectralsensitivity' => { 119 => 0x8824, 484 => 'SpectralSensitivity' }, + 'specularwhitelevel' => { 41 => 0x32b, 42 => 0x281, 45 => [0x2b9,0x2d0,0x2d4], 46 => 0x56a, 47 => 0x1e4, 48 => [0x1fd,0x2dd], 49 => [0x231,0x30f], 50 => 0x31d }, + 'speedx' => { 115 => 0x3, 380 => "\xa9xsp" }, + 'speedy' => { 115 => 0x4, 380 => "\xa9ysp" }, + 'speedz' => { 115 => 0x5, 380 => "\xa9zsp" }, + 'spherical' => { 467 => 'Spherical' }, + 'splitcolumn' => { 364 => 0x222 }, + 'splittoningbalance' => { 478 => 'SplitToningBalance', 480 => 'SplitToningBalance' }, + 'splittoninghighlighthue' => { 478 => 'SplitToningHighlightHue', 480 => 'SplitToningHighlightHue' }, + 'splittoninghighlightsaturation' => { 478 => 'SplitToningHighlightSaturation', 480 => 'SplitToningHighlightSaturation' }, + 'splittoningshadowhue' => { 478 => 'SplitToningShadowHue', 480 => 'SplitToningShadowHue' }, + 'splittoningshadowsaturation' => { 478 => 'SplitToningShadowSaturation', 480 => 'SplitToningShadowSaturation' }, + 'sport' => { 494 => 'sport' }, + 'spotfocuspointx' => { 181 => 0x2d }, + 'spotfocuspointy' => { 181 => 0x2e }, + 'spotmeteringmode' => { 34 => 0x27 }, + 'spotmeterlinktoafpoint' => { 84 => 0x107 }, + 'sractive' => { 336 => '17.1' }, + 'srawquality' => { 34 => 0x2e }, + 'srfocallength' => { 357 => 0x3 }, + 'srgbrendering' => { 308 => 'sRGB' }, + 'srhalfpresstime' => { 357 => 0x2 }, + 'srresult' => { 357 => 0x0, 358 => 0x0 }, + 'stackedimage' => { 297 => 0x804 }, + 'standardmatrixcustom' => { 138 => 0x7d4 }, + 'standardmatrixdaylight' => { 138 => 0x7d0 }, + 'standardmatrixflash' => { 138 => 0x7d3 }, + 'standardmatrixfluorescent' => { 138 => 0x7d2 }, + 'standardmatrixtungsten' => { 138 => 0x7d1 }, + 'standardoutputhighlightpoint' => { 109 => 0x14 }, + 'standardoutputsensitivity' => { 119 => 0x8831, 485 => 'StandardOutputSensitivity' }, + 'standardoutputshadowpoint' => { 109 => 0x15 }, + 'standardrawcolortone' => { 109 => 0xd }, + 'standardrawcontrast' => { 109 => 0xf }, + 'standardrawhighlight' => { 109 => 0x75 }, + 'standardrawhighlightpoint' => { 109 => 0x12 }, + 'standardrawlinear' => { 109 => 0x10 }, + 'standardrawsaturation' => { 109 => 0xe }, + 'standardrawshadow' => { 109 => 0x7e }, + 'standardrawshadowpoint' => { 109 => 0x13 }, + 'standardrawsharpness' => { 109 => 0x11 }, + 'standardunsharpmaskfineness' => { 109 => 0x94 }, + 'standardunsharpmaskstrength' => { 109 => 0x92 }, + 'standardunsharpmaskthreshold' => { 109 => 0x96 }, + 'standardwhitecustom' => { 138 => 0x838 }, + 'standardwhitedaylight' => { 138 => 0x834 }, + 'standardwhiteflash' => { 138 => 0x837 }, + 'standardwhitefluorescent' => { 138 => 0x836 }, + 'standardwhitetungsten' => { 138 => 0x835 }, + 'standbytimer' => { 280 => '19.1', 282 => '19.1', 283 => '19.1', 286 => '18.1', 287 => '18.1', 292 => '19.1', 293 => '19.1' }, + 'starlightview' => { 295 => 0x249 }, + 'startingpage' => { 494 => 'startingPage' }, + 'startmovieshooting' => { 84 => 0x70d }, + 'starttimecode' => { 380 => "\xa9TIM", 504 => 'startTimecode' }, + 'starttimecodetimeformat' => { 504 => [\'startTimecode','startTimecodeTimeFormat'] }, + 'starttimecodetimevalue' => { 504 => [\'startTimecode','startTimecodeTimeValue'] }, + 'starttimecodevalue' => { 504 => [\'startTimecode','startTimecodeValue'] }, + 'starttimesamplesize' => { 380 => "\xa9TSZ", 504 => 'startTimeSampleSize' }, + 'starttimescale' => { 380 => "\xa9TSC", 504 => 'startTimeScale' }, + 'state' => { 161 => 'State', 320 => 0x6b, 492 => 'State' }, + 'status' => { 459 => 'Status', 471 => 'Status' }, + 'stereomode' => { 467 => 'StereoMode' }, + 'stitched' => { 467 => 'Stitched' }, + 'stitchingsoftware' => { 466 => 'StitchingSoftware', 467 => 'StitchingSoftware' }, + 'stopsabovebaseiso' => { 429 => 0x113e, 430 => 0x113e, 431 => 0x111a, 432 => 0x1196, 433 => 0x1172, 434 => 0x102a, 435 => 0x222, 436 => 0x222, 437 => 0x217, 451 => 0xa }, + 'storagemethod' => { 188 => 0x12 }, + 'storebyorientation' => { 280 => '46.3', 282 => '47.3', 283 => '47.3', 292 => '47.3', 293 => '47.3', 295 => 0xd }, + 'storedescription' => { 372 => 'sdes' }, + 'storylineidentifier' => { 490 => 'StorylineIdentifier' }, + 'straightenangle' => { 272 => 0x2fc08431 }, + 'streamready' => { 490 => 'StreamReady' }, + 'streamtype' => { 176 => 'StreamType' }, + 'stretchmode' => { 504 => 'stretchMode' }, + 'studydatetime' => { 457 => 'StudyDateTime' }, + 'studydescription' => { 457 => 'StudyDescription' }, + 'studyid' => { 457 => 'StudyID' }, + 'studyphysician' => { 457 => 'StudyPhysician' }, + 'styleperiod' => { 490 => 'StylePeriod' }, + 'sub-location' => { 131 => 0x5c }, + 'subcommanddialplaybackmode' => { 295 => 0x1cf }, + 'subfiledata' => { 164 => 'data' }, + 'subfiledirectory' => { 164 => '1Directory' }, + 'subfilemimetype' => { 164 => '2MIME' }, + 'subfilename' => { 164 => '1Name' }, + 'subfileresource' => { 164 => 'rsrc' }, + 'subfiletype' => { 119 => 0xfe, 164 => '0Type' }, + 'subject' => { 306 => 'Subject', 371 => 'Subject', 481 => 'subject', 491 => 'Subject', 505 => 'subject' }, + 'subjectarea' => { 119 => 0x9214, 484 => 'SubjectArea' }, + 'subjectcode' => { 489 => 'SubjectCode' }, + 'subjectdetection' => { 229 => 0x23e }, + 'subjectdistance' => { 119 => 0x9206, 140 => 0x3e, 484 => 'SubjectDistance' }, + 'subjectdistancerange' => { 119 => 0xa40c, 484 => 'SubjectDistanceRange' }, + 'subjectlocation' => { 119 => 0xa214, 484 => 'SubjectLocation' }, + 'subjectmotion' => { 282 => '78.2', 283 => '78.2', 293 => '78.2', 295 => 0x103 }, + 'subjectprogram' => { 181 => 0x22 }, + 'subjectreference' => { 131 => 0xc }, + 'sublabels1' => { 488 => [\'TagStructure','TagStructureSubLabels'] }, + 'sublabels2' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabels'] }, + 'sublabels3' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabels'] }, + 'sublabels4' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabels'] }, + 'sublabels5' => { 488 => [\'TagStructure','TagStructureSubLabelsSubLabelsSubLabelsSubLabelsSubLabels'] }, + 'subseccreatedate' => { 114 => 'Exif-SubSecCreateDate' }, + 'subsecdatetimeoriginal' => { 114 => 'Exif-SubSecDateTimeOriginal' }, + 'subsecmodifydate' => { 114 => 'Exif-SubSecModifyDate' }, + 'subsectime' => { 119 => 0x9290 }, + 'subsectimedigitized' => { 119 => 0x9292 }, + 'subsectimeoriginal' => { 119 => 0x9291 }, + 'subsection1' => { 494 => 'subsection1' }, + 'subsection2' => { 494 => 'subsection2' }, + 'subsection3' => { 494 => 'subsection3' }, + 'subsection4' => { 494 => 'subsection4' }, + 'subselector' => { 280 => '49.1', 282 => '71.1', 283 => '71.1', 293 => '71.1', 295 => 0x8f }, + 'subselectorassignment' => { 280 => '48.1' }, + 'subselectorcenter' => { 282 => '72.1', 283 => '72.1', 293 => '72.1' }, + 'subselectorplusdials' => { 280 => '49.2', 282 => '73.1', 283 => '73.1', 293 => '73.1' }, + 'subtitle' => { 179 => 'WM/SubTitle', 372 => "\xa9st3", 380 => "\xa9snm", 494 => 'subtitle' }, + 'subtitlekeywords' => { 380 => "\xa9snk" }, + 'subversionfilename' => { 488 => [\'SubVersions','SubVersionsFileName'] }, + 'subversionreference' => { 488 => [\'SubVersions','SubVersionsVersRef'] }, + 'subversions' => { 488 => 'SubVersions' }, + 'superimposeddisplay' => { 82 => 0xa, 84 => 0x510, 85 => 0x9, 86 => 0xa, 89 => 0xa, 90 => 0xe }, + 'supermacro' => { 64 => 0x1a }, + 'supplementalcategories' => { 131 => 0x14, 492 => 'SupplementalCategories' }, + 'supplementaltype' => { 133 => 0x37 }, + 'supplementdisplayid' => { 494 => 'supplementDisplayID' }, + 'supplementstartingpage' => { 494 => 'supplementStartingPage' }, + 'supplementtitle' => { 494 => 'supplementTitle' }, + 'supplychainsource' => { 490 => 'SupplyChainSource' }, + 'supplychainsourceidentifier' => { 490 => [\'SupplyChainSource','SupplyChainSourceIdentifier'] }, + 'supplychainsourcename' => { 490 => [\'SupplyChainSource','SupplyChainSourceName'] }, + 'supportsamount' => { 478 => 'SupportsAmount', 480 => 'SupportsAmount' }, + 'supportscolor' => { 478 => 'SupportsColor', 480 => 'SupportsColor' }, + 'supportshighdynamicrange' => { 478 => 'SupportsHighDynamicRange', 480 => 'SupportsHighDynamicRange' }, + 'supportsmonochrome' => { 478 => 'SupportsMonochrome', 480 => 'SupportsMonochrome' }, + 'supportsnormaldynamicrange' => { 478 => 'SupportsNormalDynamicRange', 480 => 'SupportsNormalDynamicRange' }, + 'supportsoutputreferred' => { 478 => 'SupportsOutputReferred', 480 => 'SupportsOutputReferred' }, + 'supportsscenereferred' => { 478 => 'SupportsSceneReferred', 480 => 'SupportsSceneReferred' }, + 'svisosetting' => { 336 => 0x14 }, + 'swatchcoloranta' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsA'] }, + 'swatchcolorantb' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsB'] }, + 'swatchcolorantblack' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsBlack'] }, + 'swatchcolorantblue' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsBlue'] }, + 'swatchcolorantcyan' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsCyan'] }, + 'swatchcolorantgray' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsGray'] }, + 'swatchcolorantgreen' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsGreen'] }, + 'swatchcolorantl' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsL'] }, + 'swatchcolorantmagenta' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsMagenta'] }, + 'swatchcolorantmode' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsMode'] }, + 'swatchcolorantred' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsRed'] }, + 'swatchcolorantswatchname' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsSwatchName'] }, + 'swatchcoloranttint' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsTint'] }, + 'swatchcoloranttype' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsType'] }, + 'swatchcolorantyellow' => { 509 => [\'SwatchGroups','SwatchGroupsColorantsYellow'] }, + 'swatchgroupname' => { 509 => [\'SwatchGroups','SwatchGroupsGroupName'] }, + 'swatchgroups' => { 509 => 'SwatchGroups' }, + 'swatchgroupscolorants' => { 509 => [\'SwatchGroups','SwatchGroupsColorants'] }, + 'swatchgrouptype' => { 509 => [\'SwatchGroups','SwatchGroupsGroupType'] }, + 'sweeppanoramadirection' => { 320 => 0x93, 409 => 0x33 }, + 'sweeppanoramafieldofview' => { 320 => 0x94 }, + 'sweeppanoramasize' => { 409 => 0x32 }, + 'switchtoregisteredafpoint' => { 83 => 0x12, 84 => 0x50a }, + 'symlink' => { 120 => 'SymLink' }, + 'syncreleasemode' => { 282 => '77.1', 283 => '77.1', 293 => '77.1', 295 => 0x41 }, + 'system' => { 364 => 0x204 }, + 'tagged' => { 366 => 0xdd, 367 => 'Tagged', 473 => 'tagged' }, + 'tagslist' => { 483 => 'TagsList' }, + 'tagstructure' => { 488 => 'TagStructure' }, + 'takenumber' => { 504 => 'takeNumber' }, + 'tapename' => { 504 => 'tapeName' }, + 'targetaperture' => { 77 => 0x4 }, + 'targetcompressionratio' => { 95 => 0x1 }, + 'targetdistancesetting' => { 97 => 0x1807 }, + 'targetexposuretime' => { 77 => 0x5 }, + 'targetimagetype' => { 97 => 0x100a }, + 'targetprinter' => { 119 => 0x151 }, + 'taxon' => { 118 => 'Taxon' }, + 'taxonacceptednameusage' => { 118 => [\'Taxon','TaxonAcceptedNameUsage'] }, + 'taxonacceptednameusageid' => { 118 => [\'Taxon','TaxonAcceptedNameUsageID'] }, + 'taxonclass' => { 118 => [\'Taxon','TaxonClass'] }, + 'taxonconceptid' => { 118 => [\'Taxon','TaxonTaxonConceptID'] }, + 'taxoncultivarepithet' => { 118 => [\'Taxon','TaxonCultivarEpithet'] }, + 'taxonfamily' => { 118 => [\'Taxon','TaxonFamily'] }, + 'taxongenus' => { 118 => [\'Taxon','TaxonGenus'] }, + 'taxonhigherclassification' => { 118 => [\'Taxon','TaxonHigherClassification'] }, + 'taxonid' => { 118 => [\'Taxon','TaxonTaxonID'] }, + 'taxoninfraspecificepithet' => { 118 => [\'Taxon','TaxonInfraspecificEpithet'] }, + 'taxonkingdom' => { 118 => [\'Taxon','TaxonKingdom'] }, + 'taxonnameaccordingto' => { 118 => [\'Taxon','TaxonNameAccordingTo'] }, + 'taxonnameaccordingtoid' => { 118 => [\'Taxon','TaxonNameAccordingToID'] }, + 'taxonnamepublishedin' => { 118 => [\'Taxon','TaxonNamePublishedIn'] }, + 'taxonnamepublishedinid' => { 118 => [\'Taxon','TaxonNamePublishedInID'] }, + 'taxonnamepublishedinyear' => { 118 => [\'Taxon','TaxonNamePublishedInYear'] }, + 'taxonnomenclaturalcode' => { 118 => [\'Taxon','TaxonNomenclaturalCode'] }, + 'taxonnomenclaturalstatus' => { 118 => [\'Taxon','TaxonNomenclaturalStatus'] }, + 'taxonorder' => { 118 => [\'Taxon','TaxonOrder'] }, + 'taxonoriginalnameusage' => { 118 => [\'Taxon','TaxonOriginalNameUsage'] }, + 'taxonoriginalnameusageid' => { 118 => [\'Taxon','TaxonOriginalNameUsageID'] }, + 'taxonparentnameusage' => { 118 => [\'Taxon','TaxonParentNameUsage'] }, + 'taxonparentnameusageid' => { 118 => [\'Taxon','TaxonParentNameUsageID'] }, + 'taxonphylum' => { 118 => [\'Taxon','TaxonPhylum'] }, + 'taxonrank' => { 118 => [\'Taxon','TaxonTaxonRank'] }, + 'taxonremarks' => { 118 => [\'Taxon','TaxonTaxonRemarks'] }, + 'taxonscientificname' => { 118 => [\'Taxon','TaxonScientificName'] }, + 'taxonscientificnameauthorship' => { 118 => [\'Taxon','TaxonScientificNameAuthorship'] }, + 'taxonscientificnameid' => { 118 => [\'Taxon','TaxonScientificNameID'] }, + 'taxonspecificepithet' => { 118 => [\'Taxon','TaxonSpecificEpithet'] }, + 'taxonsubgenus' => { 118 => [\'Taxon','TaxonSubgenus'] }, + 'taxontaxonomicstatus' => { 118 => [\'Taxon','TaxonTaxonomicStatus'] }, + 'taxonverbatimtaxonrank' => { 118 => [\'Taxon','TaxonVerbatimTaxonRank'] }, + 'taxonvernacularname' => { 118 => [\'Taxon','TaxonVernacularName'] }, + 'tda1bandwidth' => { 138 => 0x196f }, + 'tda1edgepolarity' => { 138 => 0x1971 }, + 'tda1gain' => { 138 => 0x1970 }, + 'tda1offset' => { 138 => 0x196e }, + 'tda2bandwidth' => { 138 => 0x1979 }, + 'tda2edgepolarity' => { 138 => 0x197b }, + 'tda2gain' => { 138 => 0x197a }, + 'tda2offset' => { 138 => 0x1978 }, + 'tda3bandwidth' => { 138 => 0x1983 }, + 'tda3edgepolarity' => { 138 => 0x1985 }, + 'tda3gain' => { 138 => 0x1984 }, + 'tda3offset' => { 138 => 0x1982 }, + 'tda4bandwidth' => { 138 => 0x198d }, + 'tda4edgepolarity' => { 138 => 0x198f }, + 'tda4gain' => { 138 => 0x198e }, + 'tda4offset' => { 138 => 0x198c }, + 'teaser' => { 494 => 'teaser' }, + 'teleconverter' => { 186 => 0x105, 420 => 0x105 }, + 'tempampgainx100' => { 138 => 0x1914 }, + 'tempo' => { 504 => 'tempo' }, + 'temporalcoverage' => { 490 => 'TemporalCoverage' }, + 'temporalcoveragefrom' => { 490 => [\'TemporalCoverage','TemporalCoverageTempCoverageFrom'] }, + 'temporalcoverageto' => { 490 => [\'TemporalCoverage','TemporalCoverageTempCoverageTo'] }, + 'termsandconditionstext' => { 307 => 'TermsAndConditionsText' }, + 'termsandconditionsurl' => { 307 => 'TermsAndConditionsURL' }, + 'testname' => { 120 => 'TestName' }, + 'textencoding' => { 225 => 0x4 }, + 'textlayername' => { 492 => [\'TextLayers','TextLayersLayerName'] }, + 'textlayers' => { 492 => 'TextLayers' }, + 'textlayertext' => { 492 => [\'TextLayers','TextLayersLayerText'] }, + 'textstamp' => { 320 => [0x8008,0x8009,0x3b,0x3e] }, + 'texture' => { 478 => 'Texture', 480 => 'Texture' }, + 'three-dtrackingfacedetection' => { 282 => '1.4', 283 => '1.4', 293 => '1.4' }, + 'three-dtrackingwatcharea' => { 282 => '78.1', 283 => '78.1', 293 => '78.1' }, + 'thresholding' => { 119 => 0x107 }, + 'thumbnailfilename' => { 97 => 0x817 }, + 'thumbnailformat' => { 502 => [\'Thumbnails','ThumbnailsFormat'] }, + 'thumbnailheight' => { 142 => 0xfa55, 502 => [\'Thumbnails','ThumbnailsHeight'] }, + 'thumbnailimage' => { 6 => 'CNDA', 97 => 0x2008, 114 => 'Exif-ThumbnailImage', 122 => 0x3, 167 => 'data', 302 => 0x100, 380 => 'thmb', 502 => [\'Thumbnails','ThumbnailsImage'] }, + 'thumbnailimagename' => { 167 => '1Name' }, + 'thumbnailimagesize' => { 167 => 'ImageSize' }, + 'thumbnailimagetype' => { 167 => '0Type' }, + 'thumbnailimagevalidarea' => { 64 => 0x13 }, + 'thumbnaillength' => { 119 => 0x202 }, + 'thumbnailoffset' => { 119 => 0x201 }, + 'thumbnailpng' => { 380 => 'thmb' }, + 'thumbnails' => { 502 => 'Thumbnails' }, + 'thumbnailwidth' => { 142 => 0xfa54, 502 => [\'Thumbnails','ThumbnailsWidth'] }, + 'ticker' => { 494 => 'ticker' }, + 'tiffhandling' => { 478 => 'TIFFHandling', 480 => 'TIFFHandling' }, + 'tiffmeteringimage' => { 187 => 0x104c, 418 => 0x1110 }, + 'tilelength' => { 119 => 0x143 }, + 'tilewidth' => { 119 => 0x142 }, + 'time' => { 138 => 0x401, 355 => 0x7 }, + 'timecodes' => { 119 => 0xc763 }, + 'timecreated' => { 131 => 0x3c, 140 => 0x14, 149 => 0x10, 367 => 'TimeCreated' }, + 'timelapseshotnumber' => { 323 => 0x10 }, + 'timeperiod' => { 494 => 'timePeriod' }, + 'timerfunctionbutton' => { 281 => '5.2', 284 => '12.1', 285 => '13.1' }, + 'timerlength' => { 84 => 0x80c }, + 'timerrecording' => { 320 => 0x96 }, + 'timescaleparams' => { 504 => 'timeScaleParams' }, + 'timescaleparamsframeoverlappingpercentage' => { 504 => [\'timeScaleParams','timeScaleParamsFrameOverlappingPercentage'] }, + 'timescaleparamsframesize' => { 504 => [\'timeScaleParams','timeScaleParamsFrameSize'] }, + 'timescaleparamsquality' => { 504 => [\'timeScaleParams','timeScaleParamsQuality'] }, + 'timesent' => { 132 => 0x50 }, + 'timeshot' => { 468 => 'TimeShot' }, + 'timesignature' => { 504 => 'timeSignature' }, + 'timesincepoweron' => { 320 => 0x29 }, + 'timestamp' => { 11 => 0x45e, 19 => 0x11c, 296 => 0x8, 310 => 'TimeStamp', 320 => 0xaf, 467 => 'Timestamp', 474 => 'Timestamp', 488 => 'TimeStamp' }, + 'timestamp1' => { 11 => 0x45a }, + 'timezone' => { 78 => 0x1, 229 => 0x594, 264 => 0x0, 390 => 0xa }, + 'timezonecity' => { 78 => 0x2 }, + 'timezonecode' => { 100 => 0x1 }, + 'timezoneinfo' => { 100 => 0x2 }, + 'timezoneoffset' => { 119 => 0x882a }, + 'tint' => { 374 => 'player.movie.visual.tint', 478 => 'Tint', 480 => 'Tint' }, + 'title' => { 157 => 'Title', 306 => 'Title', 310 => 'Title', 320 => 0x65, 371 => 'Title', 372 => ['titl',"\xa9nam"], 374 => 'title', 380 => ['titl',"\xa9nam"], 481 => 'title', 491 => 'Title', 502 => 'Title' }, + 'togglestyleamount' => { 478 => 'ToggleStyleAmount', 480 => 'ToggleStyleAmount' }, + 'togglestyledigest' => { 478 => 'ToggleStyleDigest', 480 => 'ToggleStyleDigest' }, + 'tonecomp' => { 226 => 0x81 }, + 'tonecurve' => { 74 => 0x1, 355 => 0x402, 478 => 'ToneCurve', 480 => 'ToneCurve' }, + 'tonecurveactive' => { 108 => 0x110 }, + 'tonecurveadobergb' => { 394 => 0xa043 }, + 'tonecurveadobergbdefault' => { 394 => 0xa041 }, + 'tonecurveblue' => { 478 => 'ToneCurveBlue', 480 => 'ToneCurveBlue' }, + 'tonecurvebluex' => { 455 => 0x9003 }, + 'tonecurvebluey' => { 455 => 0x9007 }, + 'tonecurvebrightness' => { 103 => 0x20410 }, + 'tonecurvebrightnessx' => { 455 => 0x9000 }, + 'tonecurvebrightnessy' => { 455 => 0x9004 }, + 'tonecurvecolorspace' => { 107 => 0x0 }, + 'tonecurvecontrast' => { 103 => 0x20411 }, + 'tonecurvegreen' => { 478 => 'ToneCurveGreen', 480 => 'ToneCurveGreen' }, + 'tonecurvegreenx' => { 455 => 0x9002 }, + 'tonecurvegreeny' => { 455 => 0x9006 }, + 'tonecurveinputrange' => { 107 => 0x3 }, + 'tonecurveinterpolation' => { 108 => 0x159 }, + 'tonecurvemode' => { 108 => 0x113 }, + 'tonecurvename' => { 478 => 'ToneCurveName', 480 => 'ToneCurveName' }, + 'tonecurvename2012' => { 478 => 'ToneCurveName2012', 480 => 'ToneCurveName2012' }, + 'tonecurveoriginal' => { 103 => '0x20400.1' }, + 'tonecurveoutputrange' => { 107 => 0x5 }, + 'tonecurveprofilename' => { 138 => 0x1391 }, + 'tonecurveproperty' => { 108 => 0x3c }, + 'tonecurvepv2012' => { 478 => 'ToneCurvePV2012', 480 => 'ToneCurvePV2012' }, + 'tonecurvepv2012blue' => { 478 => 'ToneCurvePV2012Blue', 480 => 'ToneCurvePV2012Blue' }, + 'tonecurvepv2012green' => { 478 => 'ToneCurvePV2012Green', 480 => 'ToneCurvePV2012Green' }, + 'tonecurvepv2012red' => { 478 => 'ToneCurvePV2012Red', 480 => 'ToneCurvePV2012Red' }, + 'tonecurvered' => { 478 => 'ToneCurveRed', 480 => 'ToneCurveRed' }, + 'tonecurveredx' => { 455 => 0x9001 }, + 'tonecurveredy' => { 455 => 0x9005 }, + 'tonecurves' => { 355 => 0x403 }, + 'tonecurveshape' => { 107 => 0x1 }, + 'tonecurvesrgb' => { 394 => 0xa042 }, + 'tonecurvesrgbdefault' => { 394 => 0xa040 }, + 'tonecurvex' => { 107 => 0xa }, + 'tonecurvey' => { 107 => 0xb }, + 'tonelevel' => { 297 => 0x52e }, + 'tonemapstrength' => { 478 => 'ToneMapStrength', 480 => 'ToneMapStrength' }, + 'toningeffect' => { 57 => 0xf, 226 => 0xb3, 231 => 0x38, 232 => 0x40, 233 => 0x48, 387 => 0x1015 }, + 'toningeffectauto' => { 71 => 0xa4 }, + 'toningeffectfaithful' => { 70 => 0x74, 71 => 0x74 }, + 'toningeffectlandscape' => { 70 => 0x44, 71 => 0x44 }, + 'toningeffectmonochrome' => { 19 => 0x108, 70 => 0x8c, 71 => 0x8c }, + 'toningeffectneutral' => { 70 => 0x5c, 71 => 0x5c }, + 'toningeffectportrait' => { 70 => 0x2c, 71 => 0x2c }, + 'toningeffectstandard' => { 70 => 0x14, 71 => 0x14 }, + 'toningeffectuserdef1' => { 70 => 0xa4, 71 => 0xbc }, + 'toningeffectuserdef2' => { 70 => 0xbc, 71 => 0xd4 }, + 'toningeffectuserdef3' => { 70 => 0xd4, 71 => 0xec }, + 'toningsaturation' => { 231 => 0x39, 232 => 0x41, 233 => 0x49 }, + 'totalzoom' => { 140 => 0x62 }, + 'touchae' => { 320 => 0xab }, + 'track' => { 372 => "\xa9trk", 380 => "\xa9trk" }, + 'trackcreatedate' => { 379 => 0x1 }, + 'trackmodifydate' => { 379 => 0x2 }, + 'tracknumber' => { 372 => 'trkn', 504 => 'trackNumber' }, + 'tracks' => { 504 => 'Tracks' }, + 'tracksframerate' => { 504 => [\'Tracks','TracksFrameRate'] }, + 'tracksmarkers' => { 504 => [\'Tracks','TracksMarkers'] }, + 'tracksmarkerscomment' => { 504 => [\'Tracks','TracksMarkersComment'] }, + 'tracksmarkerscuepointparams' => { 504 => [\'Tracks','TracksMarkersCuePointParams'] }, + 'tracksmarkerscuepointparamskey' => { 504 => [\'Tracks','TracksMarkersCuePointParamsKey'] }, + 'tracksmarkerscuepointparamsvalue' => { 504 => [\'Tracks','TracksMarkersCuePointParamsValue'] }, + 'tracksmarkerscuepointtype' => { 504 => [\'Tracks','TracksMarkersCuePointType'] }, + 'tracksmarkersduration' => { 504 => [\'Tracks','TracksMarkersDuration'] }, + 'tracksmarkerslocation' => { 504 => [\'Tracks','TracksMarkersLocation'] }, + 'tracksmarkersname' => { 504 => [\'Tracks','TracksMarkersName'] }, + 'tracksmarkersprobability' => { 504 => [\'Tracks','TracksMarkersProbability'] }, + 'tracksmarkersspeaker' => { 504 => [\'Tracks','TracksMarkersSpeaker'] }, + 'tracksmarkersstarttime' => { 504 => [\'Tracks','TracksMarkersStartTime'] }, + 'tracksmarkerstarget' => { 504 => [\'Tracks','TracksMarkersTarget'] }, + 'tracksmarkerstype' => { 504 => [\'Tracks','TracksMarkersType'] }, + 'trackstrackname' => { 504 => [\'Tracks','TracksTrackName'] }, + 'trackstracktype' => { 504 => [\'Tracks','TracksTrackType'] }, + 'tracktype' => { 380 => 'kgtt' }, + 'trailer' => { 120 => 'Trailer' }, + 'trailersignature' => { 164 => 'zmie' }, + 'transcript' => { 490 => 'Transcript' }, + 'transcriptlink' => { 490 => 'TranscriptLink' }, + 'transcriptlinklink' => { 490 => [\'TranscriptLink','TranscriptLinkLink'] }, + 'transcriptlinklinkqualifier' => { 490 => [\'TranscriptLink','TranscriptLinkLinkQualifier'] }, + 'transferfunction' => { 119 => 0x12d, 500 => 'TransferFunction' }, + 'transfertimenormal' => { 138 => 0x1888 }, + 'transfertimetest' => { 138 => 0x1889 }, + 'transform' => { 320 => [0x8012,0x59] }, + 'transmissionreference' => { 492 => 'TransmissionReference' }, + 'trapped' => { 306 => 'Trapped', 491 => 'Trapped' }, + 'trashbuttonfunction' => { 84 => 0x710 }, + 'travelday' => { 320 => 0x36 }, + 'treble' => { 374 => 'player.movie.audio.treble' }, + 'triggermode' => { 381 => 0x6, 382 => 0x34, 383 => 0x34 }, + 'tstop' => { 119 => 0xc772 }, + 'ttl_da_adown' => { 343 => 0x5 }, + 'ttl_da_aup' => { 343 => 0x4 }, + 'ttl_da_bdown' => { 343 => 0x7 }, + 'ttl_da_bup' => { 343 => 0x6 }, + 'tungstenawb' => { 333 => 0x1 }, + 'tvepisode' => { 372 => 'tves' }, + 'tvepisodeid' => { 372 => 'tven' }, + 'tvexposuretimesetting' => { 336 => 0x12 }, + 'tvnetworkname' => { 372 => 'tvnn' }, + 'tvseason' => { 372 => 'tvsn' }, + 'tvshow' => { 372 => 'tvsh' }, + 'type' => { 481 => 'type', 499 => 'type' }, + 'typestatus' => { 118 => [\'Identification','IdentificationTypeStatus'] }, + 'uniquecameramodel' => { 119 => 0xc614 }, + 'uniquedocumentid' => { 131 => 0xbb }, + 'uniquematrixauto' => { 138 => 0x7e9 }, + 'uniquematrixcustom' => { 138 => 0x7e8 }, + 'uniquematrixdaylight' => { 138 => 0x7e4 }, + 'uniquematrixflash' => { 138 => 0x7e7 }, + 'uniquematrixfluorescent' => { 138 => 0x7e6 }, + 'uniquematrixtungsten' => { 138 => 0x7e5 }, + 'uniqueobjectname' => { 132 => 0x64 }, + 'units' => { 463 => 'Units' }, + 'unknown_aacr' => { 372 => 'AACR' }, + 'unknown_cdek' => { 372 => 'CDEK' }, + 'unknown_cdet' => { 372 => 'CDET' }, + 'unknownblock' => { 355 => 0x405 }, + 'unknownblock1' => { 301 => 0x635 }, + 'unknownblock2' => { 301 => 0x636 }, + 'unknownblock3' => { 301 => 0x1103 }, + 'unknownblock4' => { 301 => 0x1104 }, + 'unknowncontrast' => { 109 => 0x45 }, + 'unknowndate' => { 364 => 0x212 }, + 'unknownev' => { 138 => 0x1 }, + 'unknownlinear' => { 109 => 0x46 }, + 'unknownnumber' => { 97 => 0x180b }, + 'unknownoutputhighlightpoint' => { 109 => 0x4a }, + 'unknownoutputshadowpoint' => { 109 => 0x4b }, + 'unknownrawhighlight' => { 109 => 0x7b }, + 'unknownrawhighlightpoint' => { 109 => 0x48 }, + 'unknownrawshadow' => { 109 => 0x84 }, + 'unknownrawshadowpoint' => { 109 => 0x49 }, + 'unknownsharpness' => { 109 => 0x47 }, + 'unknowntags' => { 380 => 'TAGS' }, + 'unknowntemperature' => { 121 => 0x4 }, + 'unknownthumbnail' => { 380 => 'thmb' }, + 'unsharp1color' => { 277 => 0x13 }, + 'unsharp1halowidth' => { 277 => 0x19 }, + 'unsharp1intensity' => { 277 => 0x17 }, + 'unsharp1threshold' => { 277 => 0x1b }, + 'unsharp2color' => { 277 => 0x2e }, + 'unsharp2halowidth' => { 277 => 0x34 }, + 'unsharp2intensity' => { 277 => 0x32 }, + 'unsharp2threshold' => { 277 => 0x36 }, + 'unsharp3color' => { 277 => 0x49 }, + 'unsharp3halowidth' => { 277 => 0x4f }, + 'unsharp3intensity' => { 277 => 0x4d }, + 'unsharp3threshold' => { 277 => 0x51 }, + 'unsharp4color' => { 277 => 0x64 }, + 'unsharp4halowidth' => { 277 => 0x6a }, + 'unsharp4intensity' => { 277 => 0x68 }, + 'unsharp4threshold' => { 277 => 0x6c }, + 'unsharpcount' => { 277 => 0x0 }, + 'unsharpmask' => { 109 => 0x90, 272 => 0x76a43200 }, + 'unsharpmaskfineness' => { 103 => 0x20309 }, + 'unsharpmaskstrength' => { 103 => 0x20308 }, + 'unsharpmaskthreshold' => { 103 => 0x2030a }, + 'uprightcentermode' => { 478 => 'UprightCenterMode', 480 => 'UprightCenterMode' }, + 'uprightcenternormx' => { 478 => 'UprightCenterNormX', 480 => 'UprightCenterNormX' }, + 'uprightcenternormy' => { 478 => 'UprightCenterNormY', 480 => 'UprightCenterNormY' }, + 'uprightdependentdigest' => { 478 => 'UprightDependentDigest', 480 => 'UprightDependentDigest' }, + 'uprightfocallength35mm' => { 478 => 'UprightFocalLength35mm', 480 => 'UprightFocalLength35mm' }, + 'uprightfocalmode' => { 478 => 'UprightFocalMode', 480 => 'UprightFocalMode' }, + 'uprightfoursegmentscount' => { 478 => 'UprightFourSegmentsCount', 480 => 'UprightFourSegmentsCount' }, + 'uprightpreview' => { 478 => 'UprightPreview', 480 => 'UprightPreview' }, + 'uprighttransform_0' => { 478 => 'UprightTransform_0', 480 => 'UprightTransform_0' }, + 'uprighttransform_1' => { 478 => 'UprightTransform_1', 480 => 'UprightTransform_1' }, + 'uprighttransform_2' => { 478 => 'UprightTransform_2', 480 => 'UprightTransform_2' }, + 'uprighttransform_3' => { 478 => 'UprightTransform_3', 480 => 'UprightTransform_3' }, + 'uprighttransform_4' => { 478 => 'UprightTransform_4', 480 => 'UprightTransform_4' }, + 'uprighttransform_5' => { 478 => 'UprightTransform_5', 480 => 'UprightTransform_5' }, + 'uprighttransformcount' => { 478 => 'UprightTransformCount', 480 => 'UprightTransformCount' }, + 'uprightversion' => { 478 => 'UprightVersion', 480 => 'UprightVersion' }, + 'urgency' => { 131 => 0xa, 492 => 'Urgency' }, + 'url' => { 157 => 'URL', 310 => 'URL', 369 => 0x40b, 494 => 'url' }, + 'url_list' => { 369 => 0x41e }, + 'urla-platform' => { 494 => [\'url','urlA-platform'] }, + 'urlurl' => { 494 => [\'url','urlUrl'] }, + 'usablemeteringmodes' => { 84 => 0x10a }, + 'usableshootingmodes' => { 84 => 0x109 }, + 'usage' => { 495 => 'usage' }, + 'usageterms' => { 508 => 'UsageTerms' }, + 'usbpowerdelivery' => { 229 => 0x664 }, + 'usedialwithouthold' => { 295 => 0xbf }, + 'useguidelines' => { 476 => 'useGuidelines' }, + 'usepanoramaviewer' => { 466 => 'UsePanoramaViewer' }, + 'usercollection' => { 374 => 'collection.user' }, + 'usercomment' => { 97 => 0x805, 119 => 0x9286, 484 => 'UserComment' }, + 'userdef1picturestyle' => { 19 => 0x10c, 70 => 0xd8, 71 => 0xf0 }, + 'userdef2picturestyle' => { 19 => 0x10e, 70 => 0xda, 71 => 0xf2 }, + 'userdef3picturestyle' => { 19 => 0x110, 70 => 0xdc, 71 => 0xf4 }, + 'userfields' => { 471 => 'UserFields' }, + 'userlabel' => { 381 => 0x2b, 382 => 0x5a, 383 => 0x68 }, + 'userprofile' => { 315 => 0x302, 319 => 0x34c, 322 => 0x3038 }, + 'userrating' => { 374 => 'rating.user', 380 => 'urat' }, + 'usmlenselectronicmf' => { 2 => 0x7, 83 => 0x7, 84 => 0x501 }, + 'uspsnumber' => { 494 => 'uspsNumber' }, + 'utmeasting' => { 168 => 'Easting' }, + 'utmmapdatum' => { 168 => 'Datum' }, + 'utmnorthing' => { 168 => 'Northing' }, + 'utmzone' => { 168 => 'Zone' }, + 'uuid' => { 478 => 'UUID', 480 => 'UUID' }, + 'uv-irfiltercorrection' => { 315 => 0x325 }, + 'validbits' => { 301 => 0x611, 302 => 0x102c }, + 'validpixeldepth' => { 305 => 0x611 }, + 'variablelowpassfilter' => { 420 => 0x2028 }, + 'variousmodes' => { 140 => 0x26 }, + 'variousmodes2' => { 140 => 0x3a }, + 'variprogram' => { 226 => 0xab }, + 'varraydacnominalvalues' => { 138 => 0x191e }, + 'vendor' => { 380 => 'vndr' }, + 'vendorinfo' => { 458 => 'VendorInfo' }, + 'vendorinfomanufacturer' => { 458 => [\'VendorInfo','VendorInfoManufacturer'] }, + 'vendorinfomodel' => { 458 => [\'VendorInfo','VendorInfoModel'] }, + 'vendorinfonotes' => { 458 => [\'VendorInfo','VendorInfoNotes'] }, + 'verbatimidentification' => { 118 => [\'Identification','IdentificationVerbatimIdentification'] }, + 'version' => { 127 => 0x0, 371 => 'Version', 374 => 'version', 478 => 'Version', 480 => 'Version' }, + 'versioncreatedate' => { 455 => 0xd100 }, + 'versionid' => { 505 => 'VersionID' }, + 'versionidentifier' => { 494 => 'versionIdentifier' }, + 'versionmodifydate' => { 455 => 0xd101 }, + 'versions' => { 505 => 'Versions' }, + 'versionscomments' => { 505 => [\'Versions','VersionsComments'] }, + 'versionsevent' => { 505 => [\'Versions','VersionsEvent'] }, + 'versionseventaction' => { 505 => [\'Versions','VersionsEventAction'] }, + 'versionseventchanged' => { 505 => [\'Versions','VersionsEventChanged'] }, + 'versionseventinstanceid' => { 505 => [\'Versions','VersionsEventInstanceID'] }, + 'versionseventparameters' => { 505 => [\'Versions','VersionsEventParameters'] }, + 'versionseventsoftwareagent' => { 505 => [\'Versions','VersionsEventSoftwareAgent'] }, + 'versionseventwhen' => { 505 => [\'Versions','VersionsEventWhen'] }, + 'versionsmodifier' => { 505 => [\'Versions','VersionsModifier'] }, + 'versionsmodifydate' => { 505 => [\'Versions','VersionsModifyDate'] }, + 'versionsversion' => { 505 => [\'Versions','VersionsVersion'] }, + 'verticalafonbutton' => { 279 => '3.2', 280 => '47.2', 282 => '79.1', 295 => 0x11d }, + 'verticalclockoverlaps' => { 138 => 0x412 }, + 'verticalfuncbutton' => { 280 => '42.2', 282 => '67.1', 295 => 0x115 }, + 'verticalfuncbuttonplaybackmode' => { 295 => 0x1b7 }, + 'verticalfuncbuttonplusdials' => { 280 => '43.1' }, + 'verticalfuncplusdials' => { 282 => '68.1' }, + 'verticalmovieafonbutton' => { 295 => 0x1f9 }, + 'verticalmoviefuncbutton' => { 295 => 0x1e1 }, + 'verticalmultiselector' => { 280 => '42.1', 282 => '66.1', 283 => '66.1', 293 => '66.1', 295 => 0x18f }, + 'verticalmultiselectorplaybackmode' => { 295 => 0x125 }, + 'vfdisplayillumination' => { 2 => 0x11, 84 => [0x510,0x51d] }, + 'vibrance' => { 472 => 'Vibrance', 478 => 'Vibrance', 480 => 'Vibrance' }, + 'vibrationreduction' => { 238 => [0x75,0x82,0x1ae], 246 => '586.1', 255 => '590.2', 263 => 0x4 }, + 'videoalphamode' => { 504 => 'videoAlphaMode' }, + 'videoalphapremultiplecolor' => { 504 => 'videoAlphaPremultipleColor' }, + 'videoalphapremultiplecolora' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorA'] }, + 'videoalphapremultiplecolorb' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorB'] }, + 'videoalphapremultiplecolorblack' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorBlack'] }, + 'videoalphapremultiplecolorblue' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorBlue'] }, + 'videoalphapremultiplecolorcyan' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorCyan'] }, + 'videoalphapremultiplecolorgray' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorGray'] }, + 'videoalphapremultiplecolorgreen' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorGreen'] }, + 'videoalphapremultiplecolorl' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorL'] }, + 'videoalphapremultiplecolormagenta' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorMagenta'] }, + 'videoalphapremultiplecolormode' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorMode'] }, + 'videoalphapremultiplecolorred' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorRed'] }, + 'videoalphapremultiplecolorswatchname' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorSwatchName'] }, + 'videoalphapremultiplecolortint' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorTint'] }, + 'videoalphapremultiplecolortype' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorType'] }, + 'videoalphapremultiplecoloryellow' => { 504 => [\'videoAlphaPremultipleColor','videoAlphaPremultipleColorYellow'] }, + 'videoalphaunityistransparent' => { 504 => 'videoAlphaUnityIsTransparent' }, + 'videobitrate' => { 490 => 'videoBitRate' }, + 'videobitratemode' => { 490 => 'videoBitRateMode' }, + 'videoburstmode' => { 320 => 0xbb }, + 'videoburstresolution' => { 320 => 0xb3 }, + 'videocodec' => { 67 => 0x74 }, + 'videocolorspace' => { 504 => 'videoColorSpace' }, + 'videocompression' => { 127 => 0x3806 }, + 'videocompressor' => { 504 => 'videoCompressor' }, + 'videodisplayaspectratio' => { 490 => 'videoDisplayAspectRatio' }, + 'videoencodingprofile' => { 490 => 'videoEncodingProfile' }, + 'videofieldorder' => { 504 => 'videoFieldOrder' }, + 'videoframerate' => { 320 => 0x27, 504 => 'videoFrameRate' }, + 'videoframesize' => { 504 => 'videoFrameSize' }, + 'videoframesizeh' => { 504 => [\'videoFrameSize','videoFrameSizeH'] }, + 'videoframesizeunit' => { 504 => [\'videoFrameSize','videoFrameSizeUnit'] }, + 'videoframesizew' => { 504 => [\'videoFrameSize','videoFrameSizeW'] }, + 'videomoddate' => { 504 => 'videoModDate' }, + 'videopixelaspectratio' => { 504 => 'videoPixelAspectRatio' }, + 'videopixeldepth' => { 504 => 'videoPixelDepth' }, + 'videopreburst' => { 320 => 0xc1 }, + 'videoquality' => { 113 => 0x4003 }, + 'videorecordingmode' => { 127 => 0x3803 }, + 'videoshottype' => { 490 => 'VideoShotType' }, + 'videoshottypeidentifier' => { 490 => [\'VideoShotType','VideoShotTypeIdentifier'] }, + 'videoshottypename' => { 490 => [\'VideoShotType','VideoShotTypeName'] }, + 'videostreamscount' => { 490 => 'videoStreamsCount' }, + 'viewfinder' => { 364 => 0x455 }, + 'viewfinderdisplay' => { 279 => '12.4', 280 => '6.3' }, + 'viewfinderwarning' => { 279 => '13.4', 289 => '3.5', 290 => '6.2', 294 => '4.4' }, + 'viewfinderwarnings' => { 84 => 0x40a }, + 'viewinfoduringexposure' => { 84 => 0x407 }, + 'viewingmode' => { 409 => 0x2f, 425 => 0x18 }, + 'viewingmode2' => { 409 => [0x85,0x285] }, + 'viewpoint' => { 493 => 'viewpoint' }, + 'vignetteamount' => { 478 => 'VignetteAmount', 480 => 'VignetteAmount' }, + 'vignettecontrol' => { 226 => 0x2a, 272 => 0x76a43205 }, + 'vignettecontrolintensity' => { 272 => 0xac6bd5c0 }, + 'vignettecorrectionalreadyapplied' => { 475 => 'VignetteCorrectionAlreadyApplied' }, + 'vignettemidpoint' => { 478 => 'VignetteMidpoint', 480 => 'VignetteMidpoint' }, + 'vignetting' => { 387 => 0x1011, 394 => 0xa052 }, + 'vignettingcorrection' => { 119 => 0x7031, 394 => 0xa053, 420 => 0x2011 }, + 'vignettingcorrparams' => { 119 => 0x7032, 450 => 0x64a, 451 => [0x34a,0x350,0x35c,0x368] }, + 'vignettingsetting' => { 394 => 0xa054 }, + 'virtualhorizonstyle' => { 295 => 0x167 }, + 'visualcolor' => { 490 => 'VisualColour' }, + 'visualtechnique' => { 493 => 'visualTechnique' }, + 'voicememo' => { 396 => 0x216 }, + 'volume' => { 494 => 'volume' }, + 'vr_0x66' => { 238 => 0x66 }, + 'vrdoffset' => { 64 => 0xd0 }, + 'vrmode' => { 229 => 0x212, 263 => 0x6 }, + 'waterdepth' => { 119 => 0x9403, 485 => 'WaterDepth' }, + 'wb_bluelevel3500k' => { 187 => 0x19a }, + 'wb_bluelevel6500k' => { 187 => 0x18a }, + 'wb_bluelevelcustom' => { 187 => 0x18e }, + 'wb_bluelevelscloudy' => { 187 => 0x106 }, + 'wb_bluelevelsdaylight' => { 187 => 0xea }, + 'wb_bluelevelsflash' => { 187 => 0x122 }, + 'wb_bluelevelsfluorescent' => { 187 => [0x40a,0x15a] }, + 'wb_bluelevelskelvin' => { 187 => 0x254 }, + 'wb_bluelevelsshade' => { 187 => 0x176 }, + 'wb_bluelevelstungsten' => { 187 => 0xce }, + 'wb_gbrglevels' => { 187 => 0xae, 190 => 0x4 }, + 'wb_glevel' => { 301 => 0x11f }, + 'wb_glevel3000k' => { 301 => 0x113 }, + 'wb_glevel3300k' => { 301 => 0x114 }, + 'wb_glevel3600k' => { 301 => 0x115 }, + 'wb_glevel3900k' => { 301 => 0x116 }, + 'wb_glevel4000k' => { 301 => 0x117 }, + 'wb_glevel4300k' => { 301 => 0x118 }, + 'wb_glevel4500k' => { 301 => 0x119 }, + 'wb_glevel4800k' => { 301 => 0x11a }, + 'wb_glevel5300k' => { 301 => 0x11b }, + 'wb_glevel6000k' => { 301 => 0x11c }, + 'wb_glevel6600k' => { 301 => 0x11d }, + 'wb_glevel7500k' => { 301 => 0x11e }, + 'wb_grbglevels' => { 201 => 0x0, 427 => 0x7303 }, + 'wb_grbglevelsauto' => { 81 => 0x2, 427 => 0x7302 }, + 'wb_grbglevelscloudy' => { 81 => 0x12 }, + 'wb_grbglevelscustom1' => { 81 => 0x42 }, + 'wb_grbglevelscustom2' => { 81 => 0x4a }, + 'wb_grbglevelsdaylight' => { 81 => 0xa }, + 'wb_grbglevelsflash' => { 81 => 0x32 }, + 'wb_grbglevelsfluorescent' => { 81 => 0x22 }, + 'wb_grbglevelsfluorhigh' => { 81 => 0x2a }, + 'wb_grbglevelstungsten' => { 81 => 0x1a }, + 'wb_grbglevelsunderwater' => { 81 => 0x3a }, + 'wb_rbgglevels' => { 198 => 0x0 }, + 'wb_rblevels' => { 202 => 0x270, 226 => 0xc, 301 => 0x100 }, + 'wb_rblevels1' => { 326 => 0x2 }, + 'wb_rblevels2' => { 326 => 0x5 }, + 'wb_rblevels3' => { 326 => 0x8 }, + 'wb_rblevels3000k' => { 301 => 0x102 }, + 'wb_rblevels3300k' => { 301 => 0x103 }, + 'wb_rblevels3500k' => { 187 => 0x430 }, + 'wb_rblevels3600k' => { 301 => 0x104 }, + 'wb_rblevels3900k' => { 301 => 0x105 }, + 'wb_rblevels4' => { 326 => 0xb }, + 'wb_rblevels4000k' => { 301 => 0x106 }, + 'wb_rblevels4300k' => { 301 => 0x107 }, + 'wb_rblevels4500k' => { 301 => 0x108 }, + 'wb_rblevels4800k' => { 301 => 0x109 }, + 'wb_rblevels5' => { 326 => 0xe }, + 'wb_rblevels5300k' => { 301 => 0x10a }, + 'wb_rblevels6' => { 326 => 0x11 }, + 'wb_rblevels6000k' => { 301 => 0x10b }, + 'wb_rblevels6500k' => { 187 => 0x420 }, + 'wb_rblevels6600k' => { 301 => 0x10c }, + 'wb_rblevels7' => { 326 => 0x14 }, + 'wb_rblevels7500k' => { 301 => 0x10d }, + 'wb_rblevelsauto' => { 202 => 0x272, 305 => 0x110 }, + 'wb_rblevelscloudy' => { 187 => 0x3f0, 189 => 0x10, 202 => 0x296, 305 => 0x121 }, + 'wb_rblevelscoolwhitef' => { 187 => 0x308, 189 => 0x14 }, + 'wb_rblevelscoolwhitefluor' => { 305 => 0x132 }, + 'wb_rblevelscustom' => { 187 => 0x424, 189 => 0x1c }, + 'wb_rblevelscwb1' => { 301 => 0x10e }, + 'wb_rblevelscwb2' => { 301 => 0x10f }, + 'wb_rblevelscwb3' => { 301 => 0x110 }, + 'wb_rblevelscwb4' => { 301 => 0x111 }, + 'wb_rblevelsdaylight' => { 187 => [0x3ec,0x528], 189 => 0xc, 202 => 0x274 }, + 'wb_rblevelsdaylightf' => { 189 => 0x24 }, + 'wb_rblevelsdaylightfluor' => { 305 => 0x130 }, + 'wb_rblevelsdaywhitef' => { 189 => 0x28 }, + 'wb_rblevelsdaywhitefluor' => { 305 => 0x131 }, + 'wb_rblevelseveningsunlight' => { 305 => 0x124 }, + 'wb_rblevelsfineweather' => { 305 => 0x122 }, + 'wb_rblevelsflash' => { 187 => [0x3f4,0x304], 189 => 0x18, 202 => 0x2a4 }, + 'wb_rblevelsfluorescent' => { 202 => 0x290 }, + 'wb_rblevelsincandescent' => { 202 => 0x282 }, + 'wb_rblevelsshade' => { 187 => 0x418, 189 => 0x20, 202 => 0x2b2, 305 => 0x120 }, + 'wb_rblevelstungsten' => { 187 => 0x3e8, 189 => 0x8, 305 => 0x123 }, + 'wb_rblevelsused' => { 305 => 0x100 }, + 'wb_rblevelswhitef' => { 189 => 0x2c }, + 'wb_rblevelswhitefluorescent' => { 305 => 0x133 }, + 'wb_redlevel3500k' => { 187 => 0x198 }, + 'wb_redlevel6500k' => { 187 => 0x188 }, + 'wb_redlevelcustom' => { 187 => 0x18c }, + 'wb_redlevelscloudy' => { 187 => 0xf8 }, + 'wb_redlevelsdaylight' => { 187 => 0xdc }, + 'wb_redlevelsflash' => { 187 => 0x114 }, + 'wb_redlevelsfluorescent' => { 187 => [0x3fc,0x14c] }, + 'wb_redlevelskelvin' => { 187 => 0x1be }, + 'wb_redlevelsshade' => { 187 => 0x168 }, + 'wb_redlevelstungsten' => { 187 => 0xc0 }, + 'wb_rgbglevels' => { 200 => 0x0 }, + 'wb_rgblevels' => { 187 => [0x546,0x96], 316 => 0xd, 317 => 0x413, 322 => 0x3036, 364 => 0x107, 429 => 0x117c, 430 => 0x1180, 431 => 0x115c, 432 => 0x11d8, 433 => 0x11b4, 434 => 0x106c, 435 => 0x264, 436 => 0x264, 437 => 0x252 }, + 'wb_rgblevels1' => { 327 => 0x2 }, + 'wb_rgblevels2' => { 327 => 0x6 }, + 'wb_rgblevels2500k' => { 427 => 0x782d }, + 'wb_rgblevels3' => { 327 => 0xa }, + 'wb_rgblevels3200k' => { 427 => 0x782c }, + 'wb_rgblevels4' => { 327 => 0xe }, + 'wb_rgblevels4500k' => { 427 => [0x7484,0x7824] }, + 'wb_rgblevels5' => { 327 => 0x12 }, + 'wb_rgblevels6' => { 327 => 0x16 }, + 'wb_rgblevels6000k' => { 427 => 0x782b }, + 'wb_rgblevels7' => { 327 => 0x1a }, + 'wb_rgblevels8500k' => { 427 => 0x782a }, + 'wb_rgblevelsauto' => { 398 => 0x0 }, + 'wb_rgblevelscloudy' => { 427 => [0x7481,0x7821] }, + 'wb_rgblevelscustom1' => { 398 => 0x15 }, + 'wb_rgblevelscustom2' => { 398 => 0x18 }, + 'wb_rgblevelscustom3' => { 398 => 0x1b }, + 'wb_rgblevelsdaylight' => { 398 => 0x3, 427 => [0x7480,0x7820] }, + 'wb_rgblevelsflash' => { 398 => 0x12, 427 => [0x7483,0x7823] }, + 'wb_rgblevelsfluorescent' => { 398 => 0xf, 427 => [0x7486,0x7826] }, + 'wb_rgblevelsfluorescentm1' => { 427 => 0x7829 }, + 'wb_rgblevelsfluorescentp1' => { 427 => 0x7827 }, + 'wb_rgblevelsfluorescentp2' => { 427 => 0x7828 }, + 'wb_rgblevelsincandescent' => { 398 => 0xc }, + 'wb_rgblevelsovercast' => { 398 => 0x9 }, + 'wb_rgblevelsshade' => { 398 => 0x6, 427 => 0x7825 }, + 'wb_rgblevelstungsten' => { 427 => [0x7482,0x7822] }, + 'wb_rgblevelsunknown0' => { 399 => 0x0 }, + 'wb_rgblevelsunknown1' => { 399 => 0x3 }, + 'wb_rgblevelsunknown2' => { 399 => 0x6 }, + 'wb_rgblevelsunknown3' => { 399 => 0x9 }, + 'wb_rgblevelsunknown4' => { 399 => 0xc }, + 'wb_rgblevelsunknown5' => { 399 => 0xf }, + 'wb_rgblevelsunknown6' => { 399 => 0x12 }, + 'wb_rgblevelsunknown7' => { 399 => 0x15 }, + 'wb_rgblevelsunknown8' => { 399 => 0x18 }, + 'wb_rgblevelsunknown9' => { 399 => 0x1b }, + 'wb_rgbmuldaylight' => { 138 => 0x852 }, + 'wb_rgbmulflash' => { 138 => 0x855 }, + 'wb_rgbmulfluorescent' => { 138 => 0x854 }, + 'wb_rgbmultungsten' => { 138 => 0x853 }, + 'wb_rggbblacklevels' => { 35 => 0x25 }, + 'wb_rggblevels' => { 190 => 0x4, 199 => 0x0, 203 => 0x13e8, 204 => 0x38, 427 => 0x7313 }, + 'wb_rggblevelsasshot' => { 38 => 0x0, 39 => 0x0, 40 => 0x19, 41 => 0x55, 42 => 0x69, 43 => 0x22, 44 => 0x3f, 47 => 0x3f, 48 => 0x3f, 49 => 0x3f, 50 => 0x47 }, + 'wb_rggblevelsauto' => { 35 => 0x1, 38 => 0x5, 39 => 0x8, 40 => 0x1e, 41 => 0x5a, 42 => 0x6e, 43 => 0x18, 44 => 0x44, 47 => 0x44, 48 => 0x44, 49 => 0x44, 50 => 0x4c, 203 => 0x1478, 204 => 0x114, 394 => 0xa022, 427 => 0x7312 }, + 'wb_rggblevelsblack' => { 394 => 0xa028 }, + 'wb_rggblevelscloudy' => { 35 => 0xd, 38 => 0x1e, 39 => 0x30, 40 => 0x2d, 41 => 0xa0, 42 => 0xd7, 43 => 0x31, 44 => 0x58, 47 => 0x71, 48 => 0x8a, 49 => 0x8f, 50 => 0x92, 203 => 0x1408, 204 => 0x60, 355 => 0x20f, 363 => 0x14 }, + 'wb_rggblevelscustom' => { 35 => 0x1d, 44 => 0x80, 203 => 0x1468, 204 => 0x100 }, + 'wb_rggblevelscustom1' => { 40 => 0x41 }, + 'wb_rggblevelscustom2' => { 40 => 0x46 }, + 'wb_rggblevelsdaylight' => { 35 => 0x5, 38 => 0x14, 39 => 0x20, 40 => 0x23, 41 => 0x96, 42 => 0xcd, 43 => 0x27, 44 => 0x4e, 47 => 0x67, 48 => 0x80, 49 => 0x85, 50 => 0x88, 203 => 0x13f8, 204 => 0x4c, 355 => 0x20d, 363 => 0x2 }, + 'wb_rggblevelsflash' => { 35 => 0x19, 38 => 0x32, 39 => 0x50, 40 => 0x3c, 41 => 0xb4, 42 => 0xeb, 43 => 0x45, 44 => 0x6c, 47 => 0x85, 48 => 0x9e, 49 => 0xa3, 50 => 0xa6, 203 => 0x1448, 355 => 0x214, 363 => 0x41 }, + 'wb_rggblevelsfluorescent' => { 35 => 0x15, 38 => 0x28, 39 => 0x40, 40 => 0x37, 41 => 0xaa, 42 => 0xe1, 43 => 0x3b, 44 => 0x62, 47 => 0x7b, 48 => 0x94, 49 => 0x99, 50 => 0x9c }, + 'wb_rggblevelsfluorescentd' => { 204 => 0xc4, 355 => 0x211, 363 => 0x26 }, + 'wb_rggblevelsfluorescentl' => { 363 => 0x4a }, + 'wb_rggblevelsfluorescentn' => { 204 => 0xb0, 355 => 0x212, 363 => 0x2f }, + 'wb_rggblevelsfluorescentw' => { 203 => 0x1438, 204 => 0x9c, 355 => 0x213, 363 => 0x38 }, + 'wb_rggblevelshtmercury' => { 204 => 0xd8 }, + 'wb_rggblevelsilluminator1' => { 394 => 0xa023 }, + 'wb_rggblevelsilluminator2' => { 394 => 0xa024 }, + 'wb_rggblevelskelvin' => { 35 => 0x21, 38 => 0x2d, 39 => 0x48, 41 => 0xaf, 42 => 0xe6, 43 => 0x40, 44 => 0x67, 47 => 0x80, 48 => 0x99, 49 => 0x9e, 50 => 0xa1 }, + 'wb_rggblevelsmeasured' => { 38 => 0xa, 39 => 0x10, 41 => 0x5f, 42 => 0x73, 44 => 0x49, 47 => 0x49, 48 => 0x49, 49 => 0x49, 50 => 0x51 }, + 'wb_rggblevelspc1' => { 43 => 0x90, 44 => 0x71 }, + 'wb_rggblevelspc2' => { 43 => 0x95, 44 => 0x76 }, + 'wb_rggblevelspc3' => { 43 => 0x9a, 44 => 0x7b }, + 'wb_rggblevelsshade' => { 35 => 0x9, 38 => 0x19, 39 => 0x28, 40 => 0x28, 41 => 0x9b, 42 => 0xd2, 43 => 0x2c, 44 => 0x53, 47 => 0x6c, 48 => 0x85, 49 => 0x8a, 50 => 0x8d, 204 => 0x74, 355 => 0x20e, 363 => 0xb }, + 'wb_rggblevelstungsten' => { 35 => 0x11, 38 => 0x23, 39 => 0x38, 40 => 0x32, 41 => 0xa5, 42 => 0xdc, 43 => 0x36, 44 => 0x5d, 47 => 0x76, 48 => 0x8f, 49 => 0x94, 50 => 0x97, 203 => 0x1428, 204 => 0x88, 355 => 0x210, 363 => 0x1d }, + 'wb_rggblevelsuncorrected' => { 394 => 0xa021 }, + 'wb_rggblevelsunknown' => { 38 => 0xf, 39 => 0x18, 41 => 0x64, 42 => 0x78, 43 => 0x1d, 47 => 0x4e, 48 => 0x4e, 49 => 0x4e, 50 => 0x56, 363 => 0x53 }, + 'wb_rggblevelsunknown10' => { 38 => 0x5f, 39 => 0x98, 41 => 0x91, 42 => 0xa5, 43 => 0x72, 47 => 0x9e, 48 => 0x7b, 49 => 0x7b, 50 => 0x83 }, + 'wb_rggblevelsunknown11' => { 38 => 0x64, 39 => 0xa0, 41 => 0xb9, 42 => [0xaa,0xaf], 43 => 0x77, 47 => 0xa3, 48 => 0xa3, 49 => 0x80, 50 => 0xab }, + 'wb_rggblevelsunknown12' => { 38 => 0x69, 39 => 0xa8, 41 => 0xbe, 42 => 0xb4, 43 => 0x7c, 47 => 0xa8, 48 => 0xa8, 49 => 0xa8, 50 => 0xb0 }, + 'wb_rggblevelsunknown13' => { 38 => 0x6e, 39 => 0xb0, 41 => 0xc3, 42 => 0xb9, 43 => 0x81, 47 => 0xad, 48 => 0xad, 49 => 0xad, 50 => 0xb5 }, + 'wb_rggblevelsunknown14' => { 41 => 0xc8, 42 => 0xbe, 43 => 0x86, 47 => 0xb2, 48 => 0xb2, 49 => 0xb2, 50 => 0xba }, + 'wb_rggblevelsunknown15' => { 41 => 0xcd, 42 => 0xc3, 43 => 0x8b, 47 => 0xb7, 48 => 0xb7, 49 => 0xb7, 50 => 0xbf }, + 'wb_rggblevelsunknown16' => { 41 => 0xd2, 42 => 0xc8, 43 => 0x9f, 48 => 0xbc, 49 => 0xbc, 50 => 0xc4 }, + 'wb_rggblevelsunknown17' => { 41 => 0xd7, 42 => 0xf0, 48 => 0xc1, 49 => 0xc1, 50 => 0xc9 }, + 'wb_rggblevelsunknown18' => { 41 => 0xdc, 42 => 0xf5, 48 => 0xc6, 49 => 0xc6, 50 => 0xce }, + 'wb_rggblevelsunknown19' => { 41 => 0xe1, 42 => 0xfa, 48 => 0xcb, 49 => 0xcb, 50 => 0xd3 }, + 'wb_rggblevelsunknown2' => { 38 => 0x37, 39 => 0x58, 41 => 0x69, 42 => 0x7d, 43 => 0x4a, 47 => 0x53, 48 => 0x53, 49 => 0x53, 50 => 0x5b }, + 'wb_rggblevelsunknown20' => { 41 => 0xe6, 42 => 0xff, 48 => 0xd0, 49 => 0xd0, 50 => 0xd8 }, + 'wb_rggblevelsunknown21' => { 41 => 0xeb, 42 => 0x104, 49 => 0xd5, 50 => 0xdd }, + 'wb_rggblevelsunknown22' => { 41 => 0xf0, 42 => 0x109, 49 => 0xda, 50 => 0xe2 }, + 'wb_rggblevelsunknown23' => { 41 => 0xf5, 42 => 0x10e, 49 => 0xdf, 50 => 0xe7 }, + 'wb_rggblevelsunknown24' => { 41 => 0xfa, 42 => 0x113, 49 => 0xe4, 50 => 0xec }, + 'wb_rggblevelsunknown25' => { 41 => 0xff, 42 => 0x118, 49 => 0xe9, 50 => 0xf1 }, + 'wb_rggblevelsunknown26' => { 41 => 0x104, 42 => 0x11d, 49 => 0xee, 50 => 0xf6 }, + 'wb_rggblevelsunknown27' => { 41 => 0x109, 42 => 0x122, 49 => 0xf3, 50 => 0xfb }, + 'wb_rggblevelsunknown28' => { 41 => 0x10e, 49 => 0xf8, 50 => 0x100 }, + 'wb_rggblevelsunknown29' => { 41 => 0x113, 49 => 0xfd, 50 => 0x105 }, + 'wb_rggblevelsunknown3' => { 38 => 0x3c, 39 => 0x60, 41 => 0x6e, 42 => 0x82, 43 => 0x4f, 47 => 0x58, 48 => 0x58, 49 => 0x58, 50 => 0x60 }, + 'wb_rggblevelsunknown30' => { 49 => 0x102 }, + 'wb_rggblevelsunknown4' => { 38 => 0x41, 39 => 0x68, 41 => 0x73, 42 => 0x87, 43 => 0x54, 47 => 0x5d, 48 => 0x5d, 49 => 0x5d, 50 => 0x65 }, + 'wb_rggblevelsunknown5' => { 38 => 0x46, 39 => 0x70, 41 => 0x78, 42 => 0x8c, 43 => 0x59, 47 => 0x62, 48 => 0x62, 49 => 0x62, 50 => 0x6a }, + 'wb_rggblevelsunknown6' => { 38 => 0x4b, 39 => 0x78, 41 => 0x7d, 42 => 0x91, 43 => 0x5e, 47 => 0x8a, 48 => 0x67, 49 => 0x67, 50 => 0x6f }, + 'wb_rggblevelsunknown7' => { 38 => 0x50, 39 => 0x80, 41 => 0x82, 42 => 0x96, 43 => 0x63, 47 => 0x8f, 48 => 0x6c, 49 => 0x6c, 50 => 0x74 }, + 'wb_rggblevelsunknown8' => { 38 => 0x55, 39 => 0x88, 41 => 0x87, 42 => 0x9b, 43 => 0x68, 47 => 0x94, 48 => 0x71, 49 => 0x71, 50 => 0x79 }, + 'wb_rggblevelsunknown9' => { 38 => 0x5a, 39 => 0x90, 41 => 0x8c, 42 => 0xa0, 43 => 0x6d, 47 => 0x99, 48 => 0x76, 49 => 0x76, 50 => 0x7e }, + 'wb_rggblevelsuserselected' => { 363 => 0x5c }, + 'wbadjblueamber' => { 103 => 0x20106 }, + 'wbadjbluebalance' => { 278 => 0x8 }, + 'wbadjcolortemp' => { 103 => 0x20102, 108 => 0x1a }, + 'wbadjlighting' => { 278 => 0x14 }, + 'wbadjmagentagreen' => { 103 => 0x20105 }, + 'wbadjmode' => { 278 => 0x10 }, + 'wbadjredbalance' => { 278 => 0x0 }, + 'wbadjrggblevels' => { 103 => 0x20125, 108 => 0x6 }, + 'wbadjtemperature' => { 278 => 0x18 }, + 'wbadjtint' => { 278 => 0x25 }, + 'wbbluelevel' => { 315 => 0x324, 320 => 0x8006, 325 => 0x26 }, + 'wbbracketingsteps' => { 247 => 0x174d, 248 => 0x87c, 257 => 0x1757 }, + 'wbbracketmode' => { 57 => 0x9 }, + 'wbbracketshotnumber' => { 187 => 0x2b, 387 => 0x101a }, + 'wbbracketvalueab' => { 57 => 0xc }, + 'wbbracketvaluegm' => { 57 => 0xd }, + 'wbfinetuneactive' => { 108 => 0x24 }, + 'wbfinetunesaturation' => { 108 => 0x28 }, + 'wbfinetunetone' => { 108 => 0x2c }, + 'wbgreenlevel' => { 315 => 0x323, 320 => 0x8005, 325 => 0x25 }, + 'wbmediaimagesizesetting' => { 84 => 0x708 }, + 'wbmode' => { 189 => 0x4, 302 => 0x1015 }, + 'wbredlevel' => { 315 => 0x322, 320 => 0x8004, 325 => 0x24 }, + 'wbscale' => { 190 => 0x0 }, + 'wbshiftab' => { 74 => 0xc, 320 => 0x46, 337 => 0x10 }, + 'wbshiftab_gm' => { 420 => 0x2014 }, + 'wbshiftab_gm_precise' => { 420 => 0x2026 }, + 'wbshiftcreativecontrol' => { 320 => 0x92 }, + 'wbshiftgm' => { 74 => 0xd, 320 => 0x47, 337 => 0x11 }, + 'wbshiftintelligentauto' => { 320 => 0x8b }, + 'wbtype1' => { 326 => 0x1, 327 => 0x1 }, + 'wbtype2' => { 326 => 0x4, 327 => 0x5 }, + 'wbtype3' => { 326 => 0x7, 327 => 0x9 }, + 'wbtype4' => { 326 => 0xa, 327 => 0xd }, + 'wbtype5' => { 326 => 0xd, 327 => 0x11 }, + 'wbtype6' => { 326 => 0x10, 327 => 0x15 }, + 'wbtype7' => { 326 => 0x13, 327 => 0x19 }, + 'webstatement' => { 508 => 'WebStatement' }, + 'weightedflatsubject' => { 470 => 'weightedFlatSubject' }, + 'what' => { 478 => 'What', 480 => 'What' }, + 'whitebalance' => { 7 => 0x6f, 8 => [0x44,0x4a], 9 => 0xbc, 10 => 0x36, 11 => 0x5e, 12 => 0x36, 13 => 0x78, 14 => 0x6f, 15 => 0x6f, 16 => 0x73, 17 => 0x6f, 18 => 0x78, 19 => 0x54, 20 => 0x6f, 21 => 0xbc, 22 => 0x7b, 24 => 0xbc, 25 => 0xc2, 27 => 0x131, 28 => 0x77, 74 => 0x8, 77 => 0x7, 112 => 0x7, 113 => [0x19,0x2012], 119 => [0xa403,0xfe4e], 127 => 0x1002, 138 => 0x3fc, 139 => 0xfa0d, 140 => 0x40, 151 => 0x1a, 181 => 0x3, 182 => 0xe, 183 => 0x4, 184 => 0xb, 186 => 0x115, 226 => 0x5, 262 => 0x7, 315 => 0x304, 320 => 0x3, 322 => 0x3033, 355 => 0x19, 362 => 0x7, 386 => 0x26, 387 => 0x1003, 397 => [0x88,0x3c,0x7,0x58], 407 => 0xf, 408 => 0xe, 420 => [0x115,0xb054], 478 => 'WhiteBalance', 480 => 'WhiteBalance', 484 => 'WhiteBalance' }, + 'whitebalance0' => { 176 => 'WhiteBalance0' }, + 'whitebalance1' => { 176 => 'WhiteBalance1' }, + 'whitebalance2' => { 176 => 'WhiteBalance2', 297 => 0x500 }, + 'whitebalanceadj' => { 103 => 0x20101, 108 => 0x18, 272 => 0x76a43204 }, + 'whitebalanceautoadjustment' => { 333 => 0x0 }, + 'whitebalancebias' => { 113 => 0x2011, 302 => 0x304, 320 => 0x23 }, + 'whitebalanceblue' => { 74 => 0x7 }, + 'whitebalancebracket' => { 297 => 0x502, 302 => 0x303 }, + 'whitebalancebracketing' => { 184 => 0x22, 187 => 0x2c, 418 => 0x2c }, + 'whitebalancebuttonplaybackmode' => { 295 => 0x1c5 }, + 'whitebalancecomp' => { 305 => 0x1001 }, + 'whitebalancedetected' => { 138 => 0x3fb }, + 'whitebalancefinetune' => { 127 => 0x100a, 184 => 0x38, 186 => 0x112, 226 => [0xb,0x3f], 387 => 0x1004, 407 => 0x6, 408 => 0x5, 420 => 0x112 }, + 'whitebalancemode' => { 138 => 0x3fa, 355 => 0x1a }, + 'whitebalancered' => { 74 => 0x6 }, + 'whitebalanceset' => { 336 => 0xa }, + 'whitebalancesetting' => { 184 => 0x23, 407 => 0x5, 408 => 0x4, 409 => 0x16, 425 => 0xd }, + 'whitebalancesetup' => { 394 => 0x41 }, + 'whitebalancetemperature' => { 297 => 0x501 }, + 'whiteboard' => { 302 => 0x301 }, + 'whitelevel' => { 119 => 0xc61d, 355 => 0x7e, 427 => 0x787f }, + 'whitepoint' => { 119 => 0x13e, 319 => 0x35d, 355 => 0x201, 500 => 'WhitePoint' }, + 'whites2012' => { 478 => 'Whites2012', 480 => 'Whites2012' }, + 'whitesadj' => { 455 => 0x9017 }, + 'wideadapter' => { 387 => 0x1017 }, + 'widefocuszone' => { 181 => 0x2f }, + 'widerange' => { 396 => 0x20f }, + 'windmode' => { 138 => 0x3f4 }, + 'windnoisereduction' => { 229 => 0x2d6 }, + 'windowlocation' => { 380 => 'WLOC' }, + 'windowsatom' => { 479 => 'windowsAtom' }, + 'windowsatomextension' => { 479 => [\'windowsAtom','windowsAtomExtension'] }, + 'windowsatominvocationflags' => { 479 => [\'windowsAtom','windowsAtomInvocationFlags'] }, + 'windowsatomuncprojectpath' => { 479 => [\'windowsAtom','windowsAtomUncProjectPath'] }, + 'wordcount' => { 494 => 'wordCount' }, + 'work' => { 372 => "\xa9wrk" }, + 'workcolorspace' => { 103 => 0x10200, 108 => 0x270 }, + 'workflowtag' => { 490 => 'WorkflowTag' }, + 'workflowtagcvid' => { 490 => [\'WorkflowTag','WorkflowTagCvId'] }, + 'workflowtagcvtermid' => { 490 => [\'WorkflowTag','WorkflowTagCvTermId'] }, + 'workflowtagcvtermname' => { 490 => [\'WorkflowTag','WorkflowTagCvTermName'] }, + 'workflowtagcvtermrefinedabout' => { 490 => [\'WorkflowTag','WorkflowTagCvTermRefinedAbout'] }, + 'worktodo' => { 486 => 'WorkToDo' }, + 'worldtimelocation' => { 320 => 0x3a, 355 => 0x22, 361 => '0.1' }, + 'writer' => { 179 => 'WM/Writer' }, + 'writer-editor' => { 131 => 0x7a }, + 'x3filllight' => { 397 => 0x12 }, + 'xattrquarantine' => { 174 => 'com.apple.quarantine' }, + 'xilinxversion' => { 138 => 0x414 }, + 'xml' => { 136 => 'xml ' }, + 'xmp' => { 106 => 0xffff00f6, 120 => 'XMP' }, + 'xmptoolkit' => { 501 => 'xmptk' }, + 'xpauthor' => { 119 => 0x9c9d }, + 'xpcomment' => { 119 => 0x9c9c }, + 'xpkeywords' => { 119 => 0x9c9e }, + 'xposition' => { 119 => 0x11e }, + 'xpsubject' => { 119 => 0x9c9f }, + 'xptitle' => { 119 => 0x9c9b }, + 'xresolution' => { 119 => 0x11a, 134 => 0x3, 370 => 0x0, 500 => 'XResolution' }, + 'xyresolution' => { 123 => 0x3 }, + 'yaw' => { 115 => 0x7, 380 => ['_yaw',"\xa9fyw"] }, + 'yawangle' => { 247 => 0x3513, 248 => 0x2c2c, 252 => 0xc222, 257 => 0x36fc, 258 => 0x2f03, 260 => 0xce3a, 261 => 0xeaf3, 392 => 0x0 }, + 'ycbcrcoefficients' => { 119 => 0x211, 500 => 'YCbCrCoefficients' }, + 'ycbcrpositioning' => { 119 => 0x213, 500 => 'YCbCrPositioning' }, + 'ycbcrsubsampling' => { 119 => 0x212, 500 => 'YCbCrSubSampling' }, + 'year' => { 372 => 'yrrc', 374 => 'year', 380 => 'yrrc' }, + 'yearcreated' => { 140 => 0x10, 149 => 0xc }, + 'yellowhsl' => { 103 => 0x20912 }, + 'yield' => { 496 => 'yield' }, + 'yposition' => { 119 => 0x11f }, + 'yresolution' => { 119 => 0x11b, 134 => 0x5, 370 => 0x4, 500 => 'YResolution' }, + 'zebrapatterntonerange' => { 295 => 0x211 }, + 'zoneidentifier' => { 120 => 'ZoneIdentifier' }, + 'zonematching' => { 186 => 0x10a, 189 => [0x3a,0x4a], 420 => 0xb024 }, + 'zonematchingmode' => { 184 => 0x14 }, + 'zonematchingon' => { 183 => 0x75 }, + 'zonematchingvalue' => { 407 => 0x1f }, + 'zoomedpreviewlength' => { 302 => 0xf05 }, + 'zoomedpreviewsize' => { 302 => 0xf06 }, + 'zoomedpreviewstart' => { 302 => 0xf04 }, + 'zoomsourcewidth' => { 34 => 0x24 }, + 'zoomstepcount' => { 300 => 0x300, 302 => 0x100d }, + 'zoomtargetwidth' => { 34 => 0x25 }, ); # lookup for non-writable tags to check if the name exists @@ -5864,7 +7127,13 @@ my %tagExists = ( 'abovecolor' => 1, 'abstract' => 1, 'abstractfilename' => 1, + 'accel360fly' => 1, + 'acceldata' => 1, + 'accelerometermatrix' => 1, 'accelerometertime' => 1, + 'accelerometerunknown' => 1, + 'accelmode' => 1, + 'accelypr' => 1, 'accessdate' => 1, 'accountname' => 1, 'acdsee' => 1, @@ -5890,6 +7159,8 @@ my %tagExists = ( 'actualscalemin' => 1, 'actualsoftpostpadding' => 1, 'actualsoftprepadding' => 1, + 'additionalinfo' => 1, + 'adjdebuginfo' => 1, 'adjustedtbnimageheight' => 1, 'adjustedtbnimagewidth' => 1, 'adobe_cm' => 1, @@ -5909,11 +7180,18 @@ my %tagExists = ( 'advancedscenemode' => 1, 'adventrevision' => 1, 'adventscale' => 1, + 'aedebuginfo' => 1, 'aeflags' => 1, + 'aehistograminfo' => 1, 'aeinfo' => 1, 'aeinfo2' => 1, 'aeinfo3' => 1, 'aeinfounknown' => 1, + 'aeliveviewhistograminfo' => 1, + 'aeliveviewlocalhistogram' => 1, + 'aelocalhistogram' => 1, + 'af-cprioritysel' => 1, + 'af-sprioritysel' => 1, 'afarea' => 1, 'afareaheights' => 1, 'afareawidths' => 1, @@ -5923,6 +7201,7 @@ my %tagExists = ( 'afcp' => 1, 'afcp_iptc' => 1, 'afcsettings' => 1, + 'afdebuginfo' => 1, 'aff1' => 1, 'aff5' => 1, 'affheader' => 1, @@ -5950,18 +7229,15 @@ my %tagExists = ( 'ainumlayers' => 1, 'aipdfprivatedata' => 1, 'aiprivatedata' => 1, + 'airspeed' => 1, 'airulerunits' => 1, 'aitargetresolution' => 1, 'album2' => 1, - 'albumartist' => 1, 'albumartistsortorder' => 1, - 'albumcoverurl' => 1, 'albumid' => 1, 'albumidalbumartist' => 1, 'albumname' => 1, 'albumsortorder' => 1, - 'albumtitle' => 1, - 'albumtitleid' => 1, 'albumtitlesortorder' => 1, 'aliaslayermetadata' => 1, 'alignment' => 1, @@ -5986,6 +7262,7 @@ my %tagExists = ( 'alternateduotonecolors' => 1, 'alternatesourceurl' => 1, 'alternatespotcolors' => 1, + 'altitudefromtakeoff' => 1, 'ambienceinfo' => 1, 'angleaxis' => 1, 'angularvelocity' => 1, @@ -6007,36 +7284,38 @@ my %tagExists = ( 'anta' => 1, 'aperture' => 1, 'aperturedisplayed' => 1, - 'aperturemode' => 1, 'apeversion' => 1, 'app14flags0' => 1, 'app14flags1' => 1, 'app1_profile' => 1, 'apple-fi' => 1, + 'appledataoffsets' => 1, 'applemaildatereceived' => 1, + 'applemaildatesent' => 1, 'applemailflagged' => 1, + 'applemailisremoteattachment' => 1, 'applemailmessageid' => 1, 'applemailpriority' => 1, 'applemailread' => 1, 'applemailrepliedto' => 1, - 'applestoreaccount' => 1, - 'applestoreaccounttype' => 1, - 'applestorecatalogid' => 1, - 'applestorecountry' => 1, 'application' => 1, 'applicationdata' => 1, 'applicationmissingmsg' => 1, 'applicationversion' => 1, + 'applysettingstoliveview' => 1, + 'appname' => 1, 'archivallocation' => 1, 'archivedfilename' => 1, + 'arcoreaccel' => 1, + 'arcorecustom' => 1, + 'arcoregyro' => 1, + 'arcorevideo' => 1, 'ardronefile' => 1, 'ardronetelemetry' => 1, - 'arranger' => 1, - 'arrangerkeywords' => 1, 'artist2' => 1, 'artistlen' => 1, + 'artists' => 1, 'artisturl' => 1, - 'artwork' => 1, 'ascender' => 1, 'ascent' => 1, 'asfleakybucketpairs' => 1, @@ -6049,9 +7328,12 @@ my %tagExists = ( 'aspectratioy' => 1, 'assistantsname' => 1, 'assistantsphone' => 1, + 'associateddatalist' => 1, + 'associatedimagefile' => 1, 'association' => 1, 'assumeddisplaysize' => 1, 'assumeddistanceview' => 1, + 'ast' => 1, 'atmospherictemperature' => 1, 'atmospherictransalpha1' => 1, 'atmospherictransalpha2' => 1, @@ -6061,10 +7343,13 @@ my %tagExists = ( 'atob0' => 1, 'atob1' => 1, 'atob2' => 1, + 'atob3' => 1, + 'atom0' => 1, 'atsccontent' => 1, 'attachments' => 1, 'attitude' => 1, 'attitudetarget' => 1, + 'attr' => 1, 'attributes' => 1, 'audible_cvrx' => 1, 'audible_meta' => 1, @@ -6097,7 +7382,6 @@ my %tagExists = ( 'audiofileurl' => 1, 'audioformat' => 1, 'audioframesize' => 1, - 'audiogain' => 1, 'audiohasvariablepacketbytesizes' => 1, 'audioheader' => 1, 'audioinfo' => 1, @@ -6132,21 +7416,29 @@ my %tagExists = ( 'audiozeroframespadded' => 1, 'authenticationtime' => 1, 'authenticationtype' => 1, + 'authoridentifier' => 1, 'authoringsoftwarerelease' => 1, 'authorlen' => 1, + 'authorname' => 1, 'authorship' => 1, 'authorsortorder' => 1, - 'authorurl' => 1, + 'autoareaafstartingpoint' => 1, 'autoisomin' => 1, 'autolowlightduration' => 1, + 'automationanimation' => 1, + 'automationflags' => 1, 'autorotation' => 1, 'autosavefilepath' => 1, 'autosaveformat' => 1, 'autosummary' => 1, 'aux' => 1, + 'auxiliaryimageref' => 1, 'auxiliaryimagetype' => 1, + 'av1configuration' => 1, + 'av1configurationversion' => 1, 'avcconfiguration' => 1, 'averagebitrate' => 1, + 'averageframerate' => 1, 'averagelevel' => 1, 'avgbitrate' => 1, 'avgbytespersec' => 1, @@ -6156,10 +7448,14 @@ my %tagExists = ( 'avi1' => 1, 'avif' => 1, 'aviheader' => 1, + 'awbdebuginfo' => 1, 'awbinfo' => 1, 'axisdistancex' => 1, 'axisdistancey' => 1, 'axisdistancez' => 1, + 'axml' => 1, + 'b1' => 1, + 'b2' => 1, 'background' => 1, 'backgroundcolor' => 1, 'backgroundcolorindicator' => 1, @@ -6171,7 +7467,6 @@ my %tagExists = ( 'backuptime' => 1, 'badfaxlines' => 1, 'bahpver' => 1, - 'balance' => 1, 'balpver' => 1, 'band' => 1, 'bandwidthsharing' => 1, @@ -6180,12 +7475,14 @@ my %tagExists = ( 'bannerimagetype' => 1, 'bannerimageurl' => 1, 'barcode' => 1, + 'barcodes' => 1, 'barometerinfo' => 1, 'barometerinfoversion' => 1, 'baselinelength' => 1, + 'basename' => 1, 'baseviewpointnum' => 1, + 'basicfileinfo' => 1, 'basisobject' => 1, - 'bass' => 1, 'battery' => 1, 'batterycapacity' => 1, 'batterycurrent' => 1, @@ -6198,16 +7495,22 @@ my %tagExists = ( 'bccaddresses' => 1, 'bccnames' => 1, 'beats-per-minute' => 1, - 'beatsperminute' => 1, + 'beautycolorlevel' => 1, + 'beautyretouchlevel' => 1, 'belowcolor' => 1, 'beta' => 1, 'bibligraphicfilename' => 1, 'bikebroaccel' => 1, 'bikebrogps' => 1, 'billinginformation' => 1, + 'binarydata' => 1, + 'binarydatatype' => 1, 'binaryfilter' => 1, 'binaryxml' => 1, + 'binning' => 1, 'birthday' => 1, + 'bitdepthchroma' => 1, + 'bitdepthluma' => 1, 'bitrate' => 1, 'bitrateinfo' => 1, 'bitratemutualexclusion' => 1, @@ -6248,8 +7551,10 @@ my %tagExists = ( 'bluetrc' => 1, 'bluex' => 1, 'bluey' => 1, + 'blurstrength' => 1, 'bmpversion' => 1, 'boardtemperature' => 1, + 'bokehshape' => 1, 'bookname' => 1, 'booktitle' => 1, 'booktype' => 1, @@ -6269,15 +7574,46 @@ my %tagExists = ( 'bottommag' => 1, 'boundaryorigin' => 1, 'boundingbox' => 1, + 'bracketingburstoptions' => 1, 'bracketingcounter' => 1, - 'bracketinginfooffset' => 1, 'bracketingmode' => 1, - 'bracketingoffset' => 1, 'bracketingstep' => 1, 'bracketshot' => 1, 'brain' => 1, 'brandingimageid' => 1, 'brandingname' => 1, + 'brdfatob0' => 1, + 'brdfatob1' => 1, + 'brdfatob2' => 1, + 'brdfatob3' => 1, + 'brdfbtoa0' => 1, + 'brdfbtoa1' => 1, + 'brdfbtoa2' => 1, + 'brdfbtoa3' => 1, + 'brdfbtod0' => 1, + 'brdfbtod1' => 1, + 'brdfbtod2' => 1, + 'brdfbtod3' => 1, + 'brdfcolorimetricparam0' => 1, + 'brdfcolorimetricparam1' => 1, + 'brdfcolorimetricparam2' => 1, + 'brdfcolorimetricparam3' => 1, + 'brdfdtob0' => 1, + 'brdfdtob1' => 1, + 'brdfdtob2' => 1, + 'brdfdtob3' => 1, + 'brdfmtob0' => 1, + 'brdfmtob1' => 1, + 'brdfmtob2' => 1, + 'brdfmtob3' => 1, + 'brdfmtos0' => 1, + 'brdfmtos1' => 1, + 'brdfmtos2' => 1, + 'brdfmtos3' => 1, + 'brdfspectralparam0' => 1, + 'brdfspectralparam1' => 1, + 'brdfspectralparam2' => 1, + 'brdfspectralparam3' => 1, 'breakchar' => 1, 'brightdefectintegrationms' => 1, 'brightdefectisocode' => 1, @@ -6290,6 +7626,7 @@ my %tagExists = ( 'btoa0' => 1, 'btoa1' => 1, 'btoa2' => 1, + 'btoa3' => 1, 'btod0' => 1, 'btod1' => 1, 'btod2' => 1, @@ -6312,10 +7649,13 @@ my %tagExists = ( 'buytickets' => 1, 'bw_halftoninginfo' => 1, 'bw_transferfunc' => 1, + 'bwf_umid' => 1, 'bwfversion' => 1, 'bytelength' => 1, 'byteorder' => 1, + 'byteordermark' => 1, 'bytes' => 1, + 'bytesperline' => 1, 'bytesperminute' => 1, 'cachecontrol' => 1, 'cachedimageheight' => 1, @@ -6327,7 +7667,6 @@ my %tagExists = ( 'callbacknumber' => 1, 'callletters' => 1, 'camcore' => 1, - 'camera' => 1, 'camera1' => 1, 'camera2' => 1, 'cameraarrangementinterval' => 1, @@ -6335,8 +7674,6 @@ my %tagExists = ( 'camerabody' => 1, 'camerabyteorder' => 1, 'cameradatetime' => 1, - 'cameradirection' => 1, - 'cameraidentifier' => 1, 'cameraifd' => 1, 'camerainfo' => 1, 'camerainfo2' => 1, @@ -6345,7 +7682,6 @@ my %tagExists = ( 'camerainfounknown' => 1, 'cameramaker' => 1, 'cameramanufacturer' => 1, - 'cameramotion' => 1, 'cameraname' => 1, 'cameraobjbacktype' => 1, 'cameraobject' => 1, @@ -6353,6 +7689,7 @@ my %tagExists = ( 'cameraobjtype' => 1, 'cameraobjversion' => 1, 'cameraoperator' => 1, + 'camerapan' => 1, 'camerapartnumber' => 1, 'cameraprofileversion' => 1, 'camerascalemax' => 1, @@ -6372,6 +7709,7 @@ my %tagExists = ( 'cameratemperatureminclip' => 1, 'cameratemperatureminsaturated' => 1, 'cameratemperatureminwarn' => 1, + 'cameratilt' => 1, 'camm0' => 1, 'camm1' => 1, 'camm2' => 1, @@ -6461,6 +7799,7 @@ my %tagExists = ( 'capturexresolutionunit' => 1, 'captureyresolution' => 1, 'captureyresolutionunit' => 1, + 'car' => 1, 'carphone' => 1, 'casio' => 1, 'casiodata' => 1, @@ -6468,6 +7807,8 @@ my %tagExists = ( 'casioquality' => 1, 'casioqvmi' => 1, 'cast' => 1, + 'catalognumber' => 1, + 'cbordata' => 1, 'cc' => 1, 'ccaddresses' => 1, 'ccdrect' => 1, @@ -6522,7 +7863,6 @@ my %tagExists = ( 'channelusage' => 1, 'chapter' => 1, 'chaptercount' => 1, - 'chapterlist' => 1, 'chapterlisttrackid' => 1, 'chaptername' => 1, 'chapternum' => 1, @@ -6550,6 +7890,8 @@ my %tagExists = ( 'checkedby' => 1, 'children' => 1, 'chmversion' => 1, + 'chromaformat' => 1, + 'chromasampleposition' => 1, 'chromaticaberrationparams' => 1, 'chromaticadaptation' => 1, 'chromaticities' => 1, @@ -6569,7 +7911,6 @@ my %tagExists = ( 'cip3side' => 1, 'circleofconfusion' => 1, 'class' => 1, - 'classification' => 1, 'cleanaperture' => 1, 'cleanaperturedimensions' => 1, 'cleanapertureheight' => 1, @@ -6579,8 +7920,6 @@ my %tagExists = ( 'cleanfaxdata' => 1, 'clientid' => 1, 'clipboundary' => 1, - 'clipfilename' => 1, - 'clipid' => 1, 'clipobjects' => 1, 'clippath' => 1, 'clippingboundary' => 1, @@ -6590,7 +7929,13 @@ my %tagExists = ( 'cloneobject' => 1, 'clonetype' => 1, 'closedcaptioning' => 1, + 'cmddialsaperturesetting' => 1, + 'cmddialschangemainsub' => 1, + 'cmddialschangemainsubexposure' => 1, + 'cmddialsmenuandplayback' => 1, + 'cmddialsreverserotexposurecomp' => 1, 'cmmflags' => 1, + 'cmp1' => 1, 'cmykequivalent' => 1, 'coarsedata' => 1, 'coarsemapimage' => 1, @@ -6604,7 +7949,6 @@ my %tagExists = ( 'codesize' => 1, 'codestreamheader' => 1, 'codestreamregistration' => 1, - 'codeversion' => 1, 'codinghistory' => 1, 'codingmethods' => 1, 'codirectors' => 1, @@ -6615,7 +7959,9 @@ my %tagExists = ( 'colorant3coordinates' => 1, 'colorant3name' => 1, 'colorantcount' => 1, + 'colorantinfoout' => 1, 'colorantorder' => 1, + 'colorantorderout' => 1, 'coloranttable' => 1, 'coloranttableout' => 1, 'coloraverages' => 1, @@ -6644,6 +7990,8 @@ my %tagExists = ( 'colorcoefs2' => 1, 'colorcomponents' => 1, 'colordata1' => 1, + 'colordata10' => 1, + 'colordata11' => 1, 'colordata2' => 1, 'colordata3' => 1, 'colordata4' => 1, @@ -6653,9 +8001,11 @@ my %tagExists = ( 'colordata8' => 1, 'colordata9' => 1, 'colordataunknown' => 1, + 'colorencodingparams' => 1, 'colorgroup' => 1, 'colorhalftoninginfo' => 1, 'colorimetricintentimagestate' => 1, + 'colorimetricspecification' => 1, 'colorimetry' => 1, 'colorinfo' => 1, 'colormap' => 1, @@ -6664,7 +8014,9 @@ my %tagExists = ( 'colorobjtype' => 1, 'colorobjversion' => 1, 'colorpalette' => 1, + 'colorpopstrength' => 1, 'colorprimaries' => 1, + 'colorprofiles' => 1, 'colorresolutiondepth' => 1, 'colorresponseunit' => 1, 'colors' => 1, @@ -6672,17 +8024,15 @@ my %tagExists = ( 'colorsamplersresource2' => 1, 'colorsetup' => 1, 'colorspacedata' => 1, - 'colorspecapproximation' => 1, - 'colorspecdata' => 1, + 'colorspacename' => 1, 'colorspecification' => 1, - 'colorspecmethod' => 1, - 'colorspecprecedence' => 1, 'colortable' => 1, 'colortemperatures' => 1, 'colortransferfuncs' => 1, 'colortransform' => 1, 'colortwistmatrix' => 1, 'colortype' => 1, + 'columncount' => 1, 'columngainfactors' => 1, 'columnresetoffsets' => 1, 'command' => 1, @@ -6703,7 +8053,6 @@ my %tagExists = ( 'compatibility' => 1, 'compatiblebrands' => 1, 'compatiblefontname' => 1, - 'compilation' => 1, 'complete' => 1, 'compobj' => 1, 'compobjusertype' => 1, @@ -6712,7 +8061,6 @@ my %tagExists = ( 'componentdefinition' => 1, 'componentmapping' => 1, 'componenttable' => 1, - 'composerkeywords' => 1, 'composers' => 1, 'composersortorder' => 1, 'compositinglayerheader' => 1, @@ -6732,36 +8080,32 @@ my %tagExists = ( 'compressiontype' => 1, 'compressorid' => 1, 'compressorname' => 1, - 'compressorversion' => 1, 'computedatmospherictrans' => 1, 'computer' => 1, 'concreteflag' => 1, 'condition' => 1, 'conditionalfec' => 1, - 'conductor' => 1, 'conductors' => 1, 'confirmedobjectsize' => 1, 'connectionspaceilluminant' => 1, 'consecutivebadfaxlines' => 1, 'consoledata' => 1, 'consolefedata' => 1, + 'constantframerate' => 1, + 'constraintindicatorflags' => 1, 'cont' => 1, 'contactnames' => 1, 'containerversion' => 1, 'contake' => 1, 'contentbranding' => 1, - 'contentcreatedate' => 1, 'contentdescribes' => 1, 'contentdescription' => 1, 'contentdescriptionnotes' => 1, 'contentdisposition' => 1, - 'contentdistributor' => 1, 'contentdistributorduration' => 1, - 'contentdistributorid' => 1, 'contentdistributortype' => 1, 'contentencryption' => 1, 'contentgroupdescription' => 1, - 'contentid' => 1, 'contentlanguage' => 1, 'contentprotected' => 1, 'contentprotectedpercent' => 1, @@ -6788,10 +8132,8 @@ my %tagExists = ( 'count' => 1, 'countinfo' => 1, 'country-region' => 1, - 'coverart' => 1, 'coverartmimetype' => 1, 'coverarttype' => 1, - 'coveruri' => 1, 'coyotesense' => 1, 'coyotestatus' => 1, 'cpuarchitecture' => 1, @@ -6801,12 +8143,15 @@ my %tagExists = ( 'cputype' => 1, 'cpuversions' => 1, 'cr2cfapattern' => 1, + 'crc' => 1, 'crcdevelparams' => 1, + 'crd' => 1, 'crdinfo' => 1, 'createdby' => 1, 'creatingapplication' => 1, 'creatingtransform' => 1, 'creationpathvector' => 1, + 'creatorapp' => 1, 'creatorapplication' => 1, 'creatorappversion' => 1, 'creatoratom' => 1, @@ -6847,10 +8192,13 @@ my %tagExists = ( 'crossref' => 1, 'crs' => 1, 'crwparam' => 1, + 'cs0' => 1, 'cs1' => 1, 'ctmd' => 1, 'cubemapproj' => 1, 'cuepoint' => 1, + 'cuepointlabel' => 1, + 'cuepointnote' => 1, 'cuepoints' => 1, 'cuesheet' => 1, 'currentbitrate' => 1, @@ -6890,11 +8238,12 @@ my %tagExists = ( 'customsettingsd810' => 1, 'customsettingsd850' => 1, 'customsettingsd90' => 1, - 'customsettingsoffset' => 1, - 'cx' => 1, - 'cy' => 1, + 'customsettingsz9' => 1, + 'customtostandardpcc' => 1, + 'cxf' => 1, 'd-lightinghqdata' => 1, 'd-lightinghsdata' => 1, + 'd2' => 1, 'daccountspervolt' => 1, 'dacgainscoarse' => 1, 'dacgainscoarseadjpreif41' => 1, @@ -6907,6 +8256,7 @@ my %tagExists = ( 'darkrefoffsettest' => 1, 'darkthreshold' => 1, 'darwindata' => 1, + 'data' => 1, 'data1' => 1, 'data2' => 1, 'databasename' => 1, @@ -6914,7 +8264,6 @@ my %tagExists = ( 'datadump' => 1, 'datadump2' => 1, 'datainfo' => 1, - 'datainformation' => 1, 'datakey' => 1, 'datalen' => 1, 'datalength' => 1, @@ -6961,6 +8310,7 @@ my %tagExists = ( 'daymat7' => 1, 'daymat8' => 1, 'daymat9' => 1, + 'db' => 1, 'dblcoldcacthres1' => 1, 'dblcoldcacthres2' => 1, 'dc' => 1, @@ -6979,6 +8329,7 @@ my %tagExists = ( 'decoderversion' => 1, 'defaultaudiostream' => 1, 'defaultchar' => 1, + 'defaultcmyk' => 1, 'defaultdisplayheight' => 1, 'defaultdisplaywidth' => 1, 'defaultimagecolor' => 1, @@ -6994,6 +8345,7 @@ my %tagExists = ( 'delay' => 1, 'delaycols' => 1, 'delaytime' => 1, + 'delimiter' => 1, 'delta12to8spline' => 1, 'delta8to12spline' => 1, 'deltapngheader' => 1, @@ -7003,11 +8355,17 @@ my %tagExists = ( 'dependentimage1entrynumber' => 1, 'dependentimage2entrynumber' => 1, 'depth' => 1, + 'depthhwheight' => 1, + 'depthhwwidth' => 1, 'depthmapdata' => 1, + 'depthmapdata2' => 1, 'depthmapheight' => 1, 'depthmapname' => 1, 'depthmaptiff' => 1, 'depthmapwidth' => 1, + 'depthswheight' => 1, + 'depthswwidth' => 1, + 'derivedimageref' => 1, 'descender' => 1, 'designer' => 1, 'designerurl' => 1, @@ -7027,6 +8385,7 @@ my %tagExists = ( 'devicemodel' => 1, 'devicemodeldesc' => 1, 'devicename' => 1, + 'deviceorientation' => 1, 'devicesettings' => 1, 'dex' => 1, 'dialect' => 1, @@ -7045,10 +8404,25 @@ my %tagExists = ( 'digitalimagebroker' => 1, 'digitalsignature' => 1, 'dimensions' => 1, + 'directionalatob0' => 1, + 'directionalatob1' => 1, + 'directionalatob2' => 1, + 'directionalatob3' => 1, + 'directionalbtoa0' => 1, + 'directionalbtoa1' => 1, + 'directionalbtoa2' => 1, + 'directionalbtoa3' => 1, + 'directionalbtod0' => 1, + 'directionalbtod1' => 1, + 'directionalbtod2' => 1, + 'directionalbtod3' => 1, + 'directionaldtob0' => 1, + 'directionaldtob1' => 1, + 'directionaldtob2' => 1, + 'directionaldtob3' => 1, 'directors' => 1, 'disableflagspresent' => 1, 'discardobjects' => 1, - 'disknumber' => 1, 'displayartist' => 1, 'displayinfo' => 1, 'displayresolution' => 1, @@ -7061,6 +8435,8 @@ my %tagExists = ( 'displayyresolutionunit' => 1, 'dispose' => 1, 'disposition' => 1, + 'distance' => 1, + 'distancefromhome' => 1, 'distortinfo' => 1, 'distortioninfo' => 1, 'distortionversion' => 1, @@ -7068,6 +8444,7 @@ my %tagExists = ( 'distribution' => 1, 'dittokey' => 1, 'division' => 1, + 'dji_dtat' => 1, 'djvuversion' => 1, 'dlnaserverudn' => 1, 'dlnasourceuri' => 1, @@ -7135,6 +8512,10 @@ my %tagExists = ( 'drmkeyid' => 1, 'drmserverid' => 1, 'drone-dji' => 1, + 'dronepitch' => 1, + 'dronequaternion' => 1, + 'droneroll' => 1, + 'droneyaw' => 1, 'dropbykeyword' => 1, 'dropchunks' => 1, 'dtcpiphost' => 1, @@ -7146,7 +8527,7 @@ my %tagExists = ( 'dtvcontent' => 1, 'dualcameraimage' => 1, 'dualcameraimagename' => 1, - 'dualshotinfo' => 1, + 'dualshotextra' => 1, 'ducky' => 1, 'duedate' => 1, 'dummycolsleft' => 1, @@ -7158,6 +8539,7 @@ my %tagExists = ( 'dustinfo' => 1, 'dvdid' => 1, 'dwc' => 1, + 'dynamicranger128' => 1, 'e-mail2' => 1, 'e-mail3' => 1, 'e-mailaddress' => 1, @@ -7167,25 +8549,20 @@ my %tagExists = ( 'edgesplinehigh' => 1, 'edgesplinelow' => 1, 'edgesplinemed' => 1, - 'edit1' => 1, - 'edit2' => 1, - 'edit3' => 1, - 'edit4' => 1, 'edit4data' => 1, - 'edit5' => 1, - 'edit6' => 1, - 'edit7' => 1, - 'edit8' => 1, - 'edit9' => 1, 'editdata' => 1, 'editedby' => 1, 'editor' => 1, 'edittagarray' => 1, 'effect' => 1, 'effectivebw' => 1, + 'effectstrength' => 1, 'effectsvisible' => 1, + 'effecttype' => 1, 'eighteenpercentpoint' => 1, 'eighthlanguage' => 1, + 'electricalextendermagnification' => 1, + 'electronicimagestabilization' => 1, 'electronicvr' => 1, 'elementarystreamtrack' => 1, 'embeddedaudiofile' => 1, @@ -7194,6 +8571,7 @@ my %tagExists = ( 'embeddedfilename' => 1, 'embeddedfileusagerights' => 1, 'embeddedimage' => 1, + 'embeddedimage2' => 1, 'embeddedimagecolorspace' => 1, 'embeddedimagefilter' => 1, 'embeddedimageheight' => 1, @@ -7202,16 +8580,13 @@ my %tagExists = ( 'embeddedimagewidth' => 1, 'embeddedjpg' => 1, 'embeddedpng' => 1, + 'embeddedvideo' => 1, 'embeddedvideofile' => 1, 'embeddedvideotype' => 1, 'emphasis' => 1, 'empty' => 1, - 'encodedby' => 1, 'encodedpixelsdimensions' => 1, 'encodedusing' => 1, - 'encodedwith' => 1, - 'encoder' => 1, - 'encoderid' => 1, 'encoderoptions' => 1, 'encodersettings' => 1, 'encodervendor' => 1, @@ -7222,10 +8597,10 @@ my %tagExists = ( 'encodingprocess' => 1, 'encodingscheme' => 1, 'encodingsettings' => 1, - 'encodingtime' => 1, 'encrypt' => 1, 'encryption' => 1, 'enddate' => 1, + 'endianness' => 1, 'endpoints' => 1, 'endtime' => 1, 'endtimecode' => 1, @@ -7233,7 +8608,6 @@ my %tagExists = ( 'entrytype' => 1, 'environmentmap' => 1, 'envvardata' => 1, - 'episodeglobaluniqueid' => 1, 'eppim' => 1, 'eprint' => 1, 'epsoptions' => 1, @@ -7303,11 +8677,14 @@ my %tagExists = ( 'expressionmedia' => 1, 'exrversion' => 1, 'extcache' => 1, + 'extendedalbumname' => 1, + 'extendedartistname' => 1, 'extendedaviheader' => 1, 'extendedcontentdescr' => 1, 'extendedcontentencryption' => 1, 'extendedinfo' => 1, 'extendedstreamprops' => 1, + 'extendedtracktitle' => 1, 'extendedxmp' => 1, 'extensionclassid' => 1, 'extensioncreatedate' => 1, @@ -7379,7 +8756,6 @@ my %tagExists = ( 'fedexedr' => 1, 'fffheader' => 1, 'fieldmdp' => 1, - 'fieldofview' => 1, 'fieldpermissions' => 1, 'fifthlanguage' => 1, 'file1duration' => 1, @@ -7401,6 +8777,7 @@ my %tagExists = ( 'fileflagsmask' => 1, 'filefunctionflags' => 1, 'fileglobalprofile' => 1, + 'fileguid' => 1, 'filehardlinks' => 1, 'fileid' => 1, 'fileinfo' => 1, @@ -7438,10 +8815,14 @@ my %tagExists = ( 'filterinfo' => 1, 'filtering' => 1, 'filtermodel' => 1, + 'filterparametersbinary' => 1, + 'filterparameterscustomcustomdata' => 1, + 'filterparametersexportexportdata' => 1, 'filterpartnumber' => 1, 'filterserialnumber' => 1, 'finalflushsequence' => 1, 'finalframeblocks' => 1, + 'finetune' => 1, 'finishedfileprocessingrequest' => 1, 'finishipaversion' => 1, 'finishipfversion' => 1, @@ -7467,6 +8848,7 @@ my %tagExists = ( 'flashinfo0103' => 1, 'flashinfo0106' => 1, 'flashinfo0107' => 1, + 'flashinfo0300' => 1, 'flashinfounknown' => 1, 'flashinfoversion' => 1, 'flashmat0' => 1, @@ -7487,6 +8869,9 @@ my %tagExists = ( 'flashused' => 1, 'flashversion' => 1, 'flavor' => 1, + 'flightdegree' => 1, + 'flightspeed' => 1, + 'flipstatus' => 1, 'flir' => 1, 'flir_gps' => 1, 'flir_moreinfo' => 1, @@ -7506,6 +8891,7 @@ my %tagExists = ( 'fluormat8' => 1, 'fluormat9' => 1, 'flushtiming' => 1, + 'flyingstate' => 1, 'focalinfo' => 1, 'focallength35efl' => 1, 'focallength35mm' => 1, @@ -7513,12 +8899,17 @@ my %tagExists = ( 'focalrange' => 1, 'focusdistance2' => 1, 'focusedgemap' => 1, + 'focusframesize' => 1, 'focusinfo' => 1, 'focusinfoifd' => 1, + 'focuspointbrightness' => 1, + 'focuspointselectionspeed' => 1, 'focuspos' => 1, 'focussettings' => 1, 'folder' => 1, 'folderpath' => 1, + 'follow-meanimation' => 1, + 'follow-memode' => 1, 'font' => 1, 'fontsize' => 1, 'fontsubfamily' => 1, @@ -7553,15 +8944,17 @@ my %tagExists = ( 'fragmentlist' => 1, 'fragmenttable' => 1, 'frame' => 1, + 'framebaseview' => 1, 'frameexposuretime' => 1, 'frameid' => 1, 'frameinfo' => 1, 'framepriority' => 1, - 'framereadouttime' => 1, 'framesize' => 1, 'framesizemax' => 1, 'framesizemin' => 1, 'framespersecond' => 1, + 'frameview' => 1, + 'framinggriddisplay' => 1, 'free' => 1, 'free-busystatus' => 1, 'freebytecounts' => 1, @@ -7578,6 +8971,9 @@ my %tagExists = ( 'fujilayout' => 1, 'fullname' => 1, 'fullscreen' => 1, + 'fusion360fly' => 1, + 'fusionmode' => 1, + 'fusionypr' => 1, 'gain' => 1, 'gaindeaddata' => 1, 'gaindeadmapimage' => 1, @@ -7590,15 +8986,23 @@ my %tagExists = ( 'gammared' => 1, 'gammatable' => 1, 'gamut' => 1, + 'gamutboundarydescription0' => 1, + 'gamutboundarydescription1' => 1, + 'gamutboundarydescription2' => 1, + 'gamutboundarydescription3' => 1, 'gapless' => 1, 'gaudio' => 1, 'gaussianweights' => 1, - 'gdalmetadata' => 1, - 'gdalnodata' => 1, + 'gcamera' => 1, + 'gcreations' => 1, 'gdepth' => 1, 'geminfo' => 1, 'genbalance' => 1, 'gender' => 1, + 'generallevelidc' => 1, + 'generalprofileidc' => 1, + 'generalprofilespace' => 1, + 'generaltierflag' => 1, 'generator' => 1, 'generatorversion' => 1, 'genflags' => 1, @@ -7607,8 +9011,8 @@ my %tagExists = ( 'genmediainfo' => 1, 'genmediaversion' => 1, 'genopcolor' => 1, + 'genprofilecompatibilityflags' => 1, 'genr' => 1, - 'genreid' => 1, 'geo' => 1, 'geogangularunits' => 1, 'geogangularunitsize' => 1, @@ -7636,6 +9040,7 @@ my %tagExists = ( 'gifplaintextextension' => 1, 'gifversion' => 1, 'gimage' => 1, + 'gimbaldegree' => 1, 'gimbalpitch' => 1, 'gimbalroll' => 1, 'gimbalyaw' => 1, @@ -7647,29 +9052,30 @@ my %tagExists = ( 'globalparametersifd' => 1, 'globalpixelsize' => 1, 'googlebot' => 1, - 'googlehostheader' => 1, - 'googlepingmessage' => 1, - 'googlepingurl' => 1, - 'googlesourcedata' => 1, - 'googlestarttime' => 1, - 'googletrackduration' => 1, 'gopro' => 1, 'goprogpmf' => 1, - 'goprotype' => 1, 'gpano' => 1, - 'gpmd' => 1, + 'gpmd_fmas' => 1, + 'gpmd_gopro' => 1, + 'gpmd_kingslim' => 1, + 'gpmd_rove' => 1, 'gps' => 1, + 'gps360fly' => 1, 'gpsaltituderaw' => 1, - 'gpscoordinates' => 1, 'gpsdatalist' => 1, + 'gpsdatalist2' => 1, 'gpsdatetimeraw' => 1, + 'gpsdestaltitude' => 1, + 'gpsframingaltitude' => 1, + 'gpsframinglatitude' => 1, + 'gpsframinglongitude' => 1, 'gpshorizontalaccuracy' => 1, 'gpsinfo' => 1, 'gpslatituderaw' => 1, 'gpslog' => 1, 'gpslongituderaw' => 1, + 'gpsmode' => 1, 'gpspos' => 1, - 'gpsposition' => 1, 'gpsraw' => 1, 'gpsspeed3d' => 1, 'gpsspeedaccuracy' => 1, @@ -7677,8 +9083,12 @@ my %tagExists = ( 'gpsspeedx' => 1, 'gpsspeedy' => 1, 'gpsspeedz' => 1, + 'gpstargetaltitude' => 1, + 'gpstargetlatitude' => 1, + 'gpstargetlongitude' => 1, 'gpstrackraw' => 1, 'gpsvalid' => 1, + 'gpsvelocitydown' => 1, 'gpsvelocityeast' => 1, 'gpsvelocitynorth' => 1, 'gpsvelocityup' => 1, @@ -7700,17 +9110,20 @@ my %tagExists = ( 'greenx' => 1, 'greeny' => 1, 'gridguidesinfo' => 1, - 'group' => 1, + 'groupareac1' => 1, 'groupcaption' => 1, - 'grouping' => 1, 'groupmutualexclusion' => 1, + 'groups' => 1, 'gsensor' => 1, 'gspherical' => 1, 'gtcitation' => 1, 'gtmodeltype' => 1, 'gtrastertype' => 1, - 'guid' => 1, + 'gyro360fly' => 1, + 'gyromode' => 1, 'gyroscope' => 1, + 'gyroscopeunknown' => 1, + 'gyroypr' => 1, 'handler' => 1, 'handlerclass' => 1, 'handlerdescription' => 1, @@ -7732,14 +9145,19 @@ my %tagExists = ( 'hasmetadata' => 1, 'hasrealmergeddata' => 1, 'hasscript' => 1, + 'hasselbladexif' => 1, + 'hasselbladrawimage' => 1, 'hasvideo' => 1, 'hasxfa' => 1, 'hcusage' => 1, 'hdcontent' => 1, + 'hdmibitdepth' => 1, + 'hdmiexternalrecorder' => 1, + 'hdmioutputhdr' => 1, + 'hdmioutputrange' => 1, 'hdrinfo' => 1, 'hdrl' => 1, 'hdrtoninginfo' => 1, - 'hdvideo' => 1, 'header' => 1, 'header4' => 1, 'headerext' => 1, @@ -7749,17 +9167,20 @@ my %tagExists = ( 'headingpairs' => 1, 'heightresolution' => 1, 'hevcconfiguration' => 1, + 'hevcconfigurationversion' => 1, 'hiddenslides' => 1, + 'highbitdepth' => 1, 'highisomode' => 1, 'highlightdata' => 1, 'highlightendpoints' => 1, + 'highnote' => 1, + 'highvelocity' => 1, 'hintformat' => 1, 'hintheader' => 1, 'hintinfo' => 1, 'hintsampledesc' => 1, 'hinttrackinfo' => 1, 'hinttrackversion' => 1, - 'hintversion' => 1, 'histogram' => 1, 'historybuffersize' => 1, 'hmaphandling' => 1, @@ -7789,19 +9210,21 @@ my %tagExists = ( 'htctrack' => 1, 'http-equiv' => 1, 'httphostheader' => 1, + 'huawei' => 1, 'huffmantable' => 1, 'huffmantablelength' => 1, 'huffmantablevalue' => 1, 'hyperfocaldistance' => 1, + 'hyperlapsdebuginfo' => 1, 'hyperlinkbase' => 1, 'hyperlinks' => 1, 'hyperlinkschanged' => 1, + 'iad1' => 1, 'icc_untagged' => 1, 'iccbased' => 1, 'iconenvdata' => 1, 'iconfilename' => 1, 'iconindex' => 1, - 'iconuri' => 1, 'ics' => 1, 'id' => 1, 'id3' => 1, @@ -7878,7 +9301,6 @@ my %tagExists = ( 'imageresources' => 1, 'imagerinitialtimingcode' => 1, 'imagerlogicprogram' => 1, - 'imagerotated' => 1, 'imagerotation' => 1, 'imagerotationstatus' => 1, 'imagertimingdata' => 1, @@ -7924,31 +9346,35 @@ my %tagExists = ( 'indexedcolortablecount' => 1, 'indexoffset' => 1, 'indexparameters' => 1, + 'indications' => 1, 'info' => 1, - 'information' => 1, - 'infourl' => 1, 'ingrreserved' => 1, + 'initialdelaysamples' => 1, 'initialdisplayeffect' => 1, 'initializationvector' => 1, 'initializeddatasize' => 1, - 'initialkey' => 1, 'initialobjectdescriptor' => 1, 'initials' => 1, 'inknames' => 1, 'inputdataobjectlist' => 1, 'inputdevicename' => 1, 'inputdeviceserialnumber' => 1, + 'inputheight' => 1, + 'inputorientation' => 1, + 'inputuniformity' => 1, + 'inputwidth' => 1, 'insertmode' => 1, 'insetnwpixelx' => 1, 'insetnwpixely' => 1, + 'insta360' => 1, 'institution' => 1, 'instructionset' => 1, + 'insv' => 1, 'integratetiming' => 1, 'intellectualproperty' => 1, 'intellectualpropertynotes' => 1, 'intensitystereo' => 1, 'intergraphflagregisters' => 1, - 'intergraphmatrix' => 1, 'intergraphpacketdata' => 1, 'interlace' => 1, 'interleavedfield' => 1, @@ -7987,6 +9413,7 @@ my %tagExists = ( 'irwindowtransmission' => 1, 'is_protected' => 1, 'is_trusted' => 1, + 'isartbokeh' => 1, 'isattachment' => 1, 'isbasefont' => 1, 'iscompleted' => 1, @@ -8003,7 +9430,6 @@ my %tagExists = ( 'isotherm2color' => 1, 'isprotected' => 1, 'isrc' => 1, - 'isrccode' => 1, 'isrcnumber' => 1, 'isrecurring' => 1, 'isvbr' => 1, @@ -8032,10 +9458,10 @@ my %tagExists = ( 'iterations' => 1, 'itunesinfo' => 1, 'itunesmediatype' => 1, - 'itunesu' => 1, 'itunmovi' => 1, 'itunsmpb' => 1, 'ituntool' => 1, + 'ixml' => 1, 'jbigoptions' => 1, 'jfif' => 1, 'jfifversion' => 1, @@ -8053,6 +9479,7 @@ my %tagExists = ( 'jpegdctables' => 1, 'jpegdigest' => 1, 'jpegexifdata' => 1, + 'jpegimagelength' => 1, 'jpeginfo' => 1, 'jpeglosslesspredictors' => 1, 'jpegpointtransforms' => 1, @@ -8065,13 +9492,33 @@ my %tagExists = ( 'jpegqualityestimate' => 1, 'jpegrestartinterval' => 1, 'jpegtables' => 1, - 'jpginfooffset' => 1, 'jplcartoifd' => 1, + 'jps' => 1, + 'jpscomment' => 1, + 'jpsflags' => 1, + 'jpslayout' => 1, + 'jpsseparation' => 1, + 'jpstype' => 1, + 'jsondata' => 1, 'jsonmetadata' => 1, + 'jumbf' => 1, + 'jumbfbox' => 1, + 'jumbfdescr' => 1, + 'jumdid' => 1, + 'jumdlabel' => 1, + 'jumdsignature' => 1, + 'jumdtoggles' => 1, + 'jumdtype' => 1, 'jumptoxpep' => 1, 'junk' => 1, + 'jxlcodestream' => 1, + 'k1' => 1, + 'k2' => 1, + 'k3' => 1, + 'k4' => 1, 'kbytesize' => 1, 'kdc_ifd' => 1, + 'keepexposurewithteleconverter' => 1, 'keepuntil' => 1, 'kelvinwb' => 1, 'keycode' => 1, @@ -8079,6 +9526,7 @@ my %tagExists = ( 'keyframestimes' => 1, 'keyid' => 1, 'keys' => 1, + 'kf' => 1, 'kf8coveruri' => 1, 'khufui0thresholds' => 1, 'khufui1thresholds' => 1, @@ -8095,7 +9543,10 @@ my %tagExists = ( 'khufusigmascalingfactors6mp' => 1, 'khufuuspacec2mixingcoefficient' => 1, 'kids' => 1, + 'kilocalories' => 1, 'kinds' => 1, + 'kj' => 1, + 'kk' => 1, 'klut' => 1, 'klut12tolin12' => 1, 'knownfolderdata' => 1, @@ -8114,8 +9565,7 @@ my %tagExists = ( 'label1' => 1, 'label2' => 1, 'label3' => 1, - 'labelid' => 1, - 'labeltext' => 1, + 'labeledtext' => 1, 'lamebitrate' => 1, 'lameheader' => 1, 'lamelowpassfilter' => 1, @@ -8196,6 +9646,7 @@ my %tagExists = ( 'leftdarkcol2' => 1, 'leftdarkrect' => 1, 'leftmag' => 1, + 'leftmargin' => 1, 'legalcopyright' => 1, 'legaltrademarks' => 1, 'leicaleic' => 1, @@ -8209,8 +9660,12 @@ my %tagExists = ( 'lensdata0201' => 1, 'lensdata0204' => 1, 'lensdata0400' => 1, + 'lensdata0402' => 1, + 'lensdata0403' => 1, + 'lensdata0800' => 1, 'lensdataunknown' => 1, 'lensdataversion' => 1, + 'lensfacing' => 1, 'lensinfoq' => 1, 'lensmaker' => 1, 'lensnumber' => 1, @@ -8219,7 +9674,6 @@ my %tagExists = ( 'lensshading' => 1, 'lenstableindex' => 1, 'levelinfo' => 1, - 'levelmeter' => 1, 'libraryid' => 1, 'libraryname' => 1, 'licenseinfourl' => 1, @@ -8229,41 +9683,57 @@ my %tagExists = ( 'lights' => 1, 'lightvalue' => 1, 'limage' => 1, + 'limitaf-areamodeselautoanimals' => 1, + 'limitaf-areamodeselautopeople' => 1, + 'limitaf-areamodeseldynamic' => 1, + 'limitaf-areamodeselwidelanimals' => 1, + 'limitaf-areamodeselwidelpeople' => 1, + 'limitafareamodesel3d' => 1, + 'limitafareamodeseld105' => 1, + 'limitafareamodeseld25' => 1, + 'limitafareamodeseld49' => 1, + 'limitafareamodeseld9' => 1, + 'limitafareamodeselgroup' => 1, + 'limitafareamodeselgroupc1' => 1, + 'limitafareamodeselgroupc2' => 1, + 'limitreleasemodeselmirror-up' => 1, + 'limitreleasemodeselq' => 1, + 'limitreleasemodeseltimer' => 1, + 'limitselectableimagearea5to4' => 1, 'lin12toklut12' => 1, 'lin12toklut8' => 1, 'linearitysplinetags' => 1, 'linearizationcoefficients1' => 1, 'linearizationcoefficients2' => 1, 'linearized' => 1, + 'linecount' => 1, 'lineorder' => 1, 'lines' => 1, 'linkedprofilename' => 1, 'linkerversion' => 1, + 'linkgoodput' => 1, 'linkinfo' => 1, + 'linkquality' => 1, 'linkstatus' => 1, 'linksuptodate' => 1, 'linktarget' => 1, 'linlogtable' => 1, 'listtype' => 1, 'lit' => 1, + 'livephotoinfo' => 1, 'ln0' => 1, 'ln1' => 1, 'localbasepath' => 1, 'localdeltatype' => 1, 'localeindicator' => 1, 'localpositionned' => 1, - 'locationbody' => 1, - 'locationdate' => 1, 'locationinfo' => 1, - 'locationinformation' => 1, - 'locationnote' => 1, - 'locationrole' => 1, 'lockedpropertylist' => 1, 'locks' => 1, + 'loginfo' => 1, 'loglintable' => 1, 'logoiconurl' => 1, 'logourl' => 1, - 'longdescription' => 1, 'lookheadbacktype' => 1, 'lookheader' => 1, 'lookheadname' => 1, @@ -8281,21 +9751,26 @@ my %tagExists = ( 'lookmat9' => 1, 'lookmodtransform' => 1, 'lookuptable' => 1, - 'loopstyle' => 1, 'lotus' => 1, + 'lowlightaf' => 1, + 'lownote' => 1, + 'lowvelocity' => 1, 'lr' => 1, 'lslv' => 1, + 'lucasjunk' => 1, 'luminance' => 1, 'luminanceconsts' => 1, 'lyricist' => 1, 'lyrics_synchronised' => 1, - 'lyricsuri' => 1, 'machineid' => 1, 'machinetype' => 1, 'macintoshnsprintinfo' => 1, 'macintoshprintinfo' => 1, + 'mag360fly' => 1, + 'magmode' => 1, 'magneticfield' => 1, 'magnetometer' => 1, + 'magnetometerxyz' => 1, 'magnification' => 1, 'magnifyobject' => 1, 'mailingaddress' => 1, @@ -8309,9 +9784,7 @@ my %tagExists = ( 'makernotepentax5a' => 1, 'makernotepentax5b' => 1, 'makernotepentax5c' => 1, - 'makernotepentaxunknown' => 1, 'makernotes' => 1, - 'makerurl' => 1, 'mandatorybackground' => 1, 'manufacturecode' => 1, 'manufactureindex' => 1, @@ -8326,6 +9799,10 @@ my %tagExists = ( 'marker' => 1, 'markerid' => 1, 'markinfo' => 1, + 'marl' => 1, + 'masksubarea' => 1, + 'mastergainadjustment' => 1, + 'matrixcoefficients' => 1, 'matrixworldtocamera' => 1, 'matrixworldtoscreen' => 1, 'mattcolor' => 1, @@ -8339,6 +9816,7 @@ my %tagExists = ( 'maximumimageindex' => 1, 'maximumobjectsize' => 1, 'maximumoperationindex' => 1, + 'maximumshutterangle' => 1, 'maximumtransformindex' => 1, 'maxjpegtableindex' => 1, 'maxpacketsize' => 1, @@ -8349,6 +9827,7 @@ my %tagExists = ( 'maxval' => 1, 'maxwidth' => 1, 'mc' => 1, + 'mccdata' => 1, 'mcdi' => 1, 'md5signature' => 1, 'md5sum' => 1, @@ -8361,15 +9840,19 @@ my %tagExists = ( 'mditemacquisitionmodel' => 1, 'mditemaltitude' => 1, 'mditemaperture' => 1, + 'mditemaudiobitrate' => 1, + 'mditemaudiochannelcount' => 1, 'mditemauthoremailaddresses' => 1, 'mditemauthors' => 1, 'mditembitspersample' => 1, 'mditembundleidentifier' => 1, 'mditemcity' => 1, + 'mditemcodecs' => 1, 'mditemcolorspace' => 1, 'mditemcomment' => 1, 'mditemcontentcreationdate' => 1, 'mditemcontentcreationdate_ranking' => 1, + 'mditemcontentcreationdateranking' => 1, 'mditemcontentmodificationdate' => 1, 'mditemcontenttype' => 1, 'mditemcontenttypetree' => 1, @@ -8382,6 +9865,7 @@ my %tagExists = ( 'mditemdescription' => 1, 'mditemdisplayname' => 1, 'mditemdownloadeddate' => 1, + 'mditemdurationseconds' => 1, 'mditememailconversationid' => 1, 'mditemencodingapplications' => 1, 'mditemexifgpsversion' => 1, @@ -8412,6 +9896,7 @@ my %tagExists = ( 'mditemidentifier' => 1, 'mditemimagedirection' => 1, 'mditeminterestingdate_ranking' => 1, + 'mditeminterestingdateranking' => 1, 'mditemisapplicationmanaged' => 1, 'mditemisexistingthread' => 1, 'mditemislikelyjunk' => 1, @@ -8419,11 +9904,14 @@ my %tagExists = ( 'mditemkeywords' => 1, 'mditemkind' => 1, 'mditemlastuseddate' => 1, + 'mditemlastuseddate_ranking' => 1, 'mditemlatitude' => 1, + 'mditemlensmodel' => 1, 'mditemlogicalsize' => 1, 'mditemlongitude' => 1, 'mditemmailboxes' => 1, 'mditemmaildatereceived_ranking' => 1, + 'mditemmediatypes' => 1, 'mditemnumberofpages' => 1, 'mditemorientation' => 1, 'mditemoriginapplicationidentifier' => 1, @@ -8446,12 +9934,23 @@ my %tagExists = ( 'mditemsecuritymethod' => 1, 'mditemspeed' => 1, 'mditemstateorprovince' => 1, + 'mditemstreamable' => 1, 'mditemsubject' => 1, 'mditemtimestamp' => 1, 'mditemtitle' => 1, + 'mditemtotalbitrate' => 1, 'mditemusecount' => 1, 'mditemuseddates' => 1, + 'mditemuserdownloadeddate' => 1, + 'mditemuserdownloadeduserhandle' => 1, + 'mditemusersharedreceiveddate' => 1, + 'mditemusersharedreceivedrecipient' => 1, + 'mditemusersharedreceivedrecipienthandle' => 1, + 'mditemusersharedreceivedsender' => 1, + 'mditemusersharedreceivedsenderhandle' => 1, + 'mditemusersharedreceivedtransport' => 1, 'mditemversion' => 1, + 'mditemvideobitrate' => 1, 'mditemwherefroms' => 1, 'mditemwhitebalance' => 1, 'mdlabname' => 1, @@ -8472,18 +9971,19 @@ my %tagExists = ( 'measurementgeometry' => 1, 'measurementilluminant' => 1, 'measurementinfo' => 1, + 'measurementinputinfo' => 1, 'measurementobserver' => 1, 'measurementscale' => 1, 'mebx' => 1, 'media' => 1, 'mediablackpoint' => 1, - 'mediaclassprimaryid' => 1, - 'mediaclasssecondaryid' => 1, 'mediacolor' => 1, 'mediacontenttypes' => 1, 'mediacreated' => 1, 'mediacredits' => 1, 'mediadata' => 1, + 'mediadataoffset' => 1, + 'mediadatasize' => 1, 'mediaduration' => 1, 'mediaflags' => 1, 'mediaheader' => 1, @@ -8523,12 +10023,14 @@ my %tagExists = ( 'mediathumbwidth' => 1, 'mediatimescale' => 1, 'mediatrackbytes' => 1, - 'mediatype' => 1, + 'mediauniqueid' => 1, 'mediaweight' => 1, 'mediawhitepoint' => 1, 'medium' => 1, 'megapixels' => 1, 'melodicpolyphony' => 1, + 'menusettingsz7ii' => 1, + 'menusettingsz9' => 1, 'message' => 1, 'meta' => 1, 'metadata' => 1, @@ -8537,20 +10039,29 @@ my %tagExists = ( 'metadatalibrary' => 1, 'metadatanumber' => 1, 'metadatasource' => 1, + 'metadataversion' => 1, 'metaformat' => 1, + 'metaimagesize' => 1, + 'metarelation' => 1, 'metasampledesc' => 1, + 'metatype' => 1, 'metdata' => 1, 'meterinfo' => 1, + 'meteringbutton' => 1, 'meterlink' => 1, 'metermode' => 1, + 'mett' => 1, 'microsoft' => 1, 'microsoftxtra' => 1, 'middlename' => 1, 'midicontrol' => 1, 'midicontrolversion' => 1, + 'midipitchfraction' => 1, 'midisong' => 1, + 'midiunitynote' => 1, 'mie' => 1, 'mileage' => 1, + 'mimeencoding' => 1, 'mimetype' => 1, 'miniaturefilter' => 1, 'miniaturefilterorientation' => 1, @@ -8573,6 +10084,7 @@ my %tagExists = ( 'minoltattw' => 1, 'minoltawbg' => 1, 'minpacketsize' => 1, + 'minspatialsegmentationidc' => 1, 'mintransmissiontime' => 1, 'mmclips' => 1, 'mngheader' => 1, @@ -8582,8 +10094,6 @@ my %tagExists = ( 'modeflags' => 1, 'model2' => 1, 'modelandversion' => 1, - 'modeltiepoint' => 1, - 'modeltransform' => 1, 'modeltype' => 1, 'modenumber' => 1, 'modificationnumber' => 1, @@ -8592,11 +10102,11 @@ my %tagExists = ( 'modifiedinfo' => 1, 'moiversion' => 1, 'monomonitormatrix' => 1, + 'monostrength' => 1, 'monotonescaletable' => 1, 'monouniquematrix' => 1, 'montage' => 1, 'month' => 1, - 'mood' => 1, 'moreinfo' => 1, 'moreinfo0201' => 1, 'moreinfo0401' => 1, @@ -8609,14 +10119,16 @@ my %tagExists = ( 'movableinfo' => 1, 'moveobjects' => 1, 'movie' => 1, - 'moviedata' => 1, - 'moviedataoffset' => 1, - 'moviedatasize' => 1, 'moviefragment' => 1, + 'moviefragmentheader' => 1, + 'moviefragmentsequence' => 1, + 'moviefunc2button' => 1, 'movieheader' => 1, 'movieheaderversion' => 1, + 'moviehighlightdisplaypattern' => 1, 'movieinfo' => 1, 'moviestreamname' => 1, + 'moviewhitebalancesameasphoto' => 1, 'mp' => 1, 'mp1' => 1, 'mpeg7binary' => 1, @@ -8636,9 +10148,20 @@ my %tagExists = ( 'msdocumenttextposition' => 1, 'mspropertysetstorage' => 1, 'msstereo' => 1, + 'mtoa0' => 1, + 'mtob0' => 1, + 'mtob1' => 1, + 'mtob2' => 1, + 'mtob3' => 1, + 'mtos0' => 1, + 'mtos1' => 1, + 'mtos2' => 1, + 'mtos3' => 1, 'multiexp' => 1, 'multiexposureversion' => 1, 'multimediatype' => 1, + 'multiplexdefaultvalues' => 1, + 'multiplextypearray' => 1, 'multiprofiles' => 1, 'multiquality' => 1, 'multishoton' => 1, @@ -8646,18 +10169,15 @@ my %tagExists = ( 'musicby' => 1, 'musiccdidentifier' => 1, 'musiciancredits' => 1, - 'mute' => 1, 'mwg-coll' => 1, 'mwg-kw' => 1, 'mwg-rs' => 1, 'mxfversion' => 1, 'mycolors' => 1, - 'name' => 1, 'namedcolor' => 1, 'namedcolor2' => 1, 'nametableversion' => 1, 'nameutf-8' => 1, - 'narrator' => 1, 'nativedisplayinfo' => 1, 'nativeresolutionunit' => 1, 'nativexresolution' => 1, @@ -8682,6 +10202,7 @@ my %tagExists = ( 'newbitdepth' => 1, 'newcolortype' => 1, 'newguid' => 1, + 'newlines' => 1, 'nexttrackid' => 1, 'nifnonlinearity' => 1, 'nifnonlinearity12bit' => 1, @@ -8689,14 +10210,17 @@ my %tagExists = ( 'nifnonlinearity16bit' => 1, 'nifnonlinearityext' => 1, 'nikon' => 1, - 'nikoncaptureoffsets' => 1, + 'nikonapp' => 1, 'nikondata' => 1, 'nikondatetime' => 1, 'nikonncdb' => 1, 'nikonncdt' => 1, + 'nikonnefinfo' => 1, 'nikonscanifd' => 1, 'nikontags' => 1, 'nikonvers' => 1, + 'nine' => 1, + 'nineedits' => 1, 'ninthlanguage' => 1, 'nitf' => 1, 'nitfversion' => 1, @@ -8744,12 +10268,20 @@ my %tagExists = ( 'numproperties' => 1, 'numrules' => 1, 'numsampleframes' => 1, + 'numsampleloops' => 1, 'numslices' => 1, 'numstreams' => 1, + 'numtemporallayers' => 1, 'objectfiletype' => 1, 'objectflags' => 1, 'objectid' => 1, + 'objectorientation' => 1, 'objectsizeannounced' => 1, + 'observationdate' => 1, + 'observationdateend' => 1, + 'observationtime' => 1, + 'observationtimeend' => 1, + 'observer' => 1, 'obsoletephotoshoptag1' => 1, 'obsoletephotoshoptag2' => 1, 'obsoletephotoshoptag3' => 1, @@ -8822,6 +10354,14 @@ my %tagExists = ( 'omenroicoefficients' => 1, 'omenroicoordinates' => 1, 'omensmoothingkernel' => 1, + 'on1_settingsdata' => 1, + 'on1_settingsmetadatacreated' => 1, + 'on1_settingsmetadatamodified' => 1, + 'on1_settingsmetadataname' => 1, + 'on1_settingsmetadatapluginid' => 1, + 'on1_settingsmetadatatimestamp' => 1, + 'on1_settingsmetadatausage' => 1, + 'on1_settingsmetadatavisibletouser' => 1, 'onionskins' => 1, 'opacity' => 1, 'opcolor' => 1, @@ -8833,6 +10373,7 @@ my %tagExists = ( 'operationid' => 1, 'operationnumber' => 1, 'opiproxy' => 1, + 'opticalvr' => 1, 'optics' => 1, 'optimalbitrate' => 1, 'optionalattendeeaddresses' => 1, @@ -8843,17 +10384,14 @@ my %tagExists = ( 'organizeraddress' => 1, 'organizername' => 1, 'orientationinfo' => 1, - 'orientationoffset' => 1, 'originalalbum' => 1, - 'originalalbumtitle' => 1, - 'originalartist' => 1, + 'originaldate' => 1, 'originaldocumentsize' => 1, 'originalfilesize' => 1, 'originalfiletype' => 1, 'originalformat' => 1, 'originalframerate' => 1, 'originalimagebroker' => 1, - 'originallyricist' => 1, 'originalmedia' => 1, 'originalmedium' => 1, 'originalrawcreator' => 1, @@ -8869,6 +10407,7 @@ my %tagExists = ( 'originalthmfiletype' => 1, 'originalthmimage' => 1, 'originalthmresource' => 1, + 'originalyear' => 1, 'originator' => 1, 'originatorreference' => 1, 'originpathinfo' => 1, @@ -8884,6 +10423,8 @@ my %tagExists = ( 'otherfirmware' => 1, 'otherformat' => 1, 'otherinfo' => 1, + 'othermeta' => 1, + 'othername' => 1, 'otherpobox' => 1, 'otherpostalcode' => 1, 'othersampledesc' => 1, @@ -8892,7 +10433,10 @@ my %tagExists = ( 'otherstreet' => 1, 'outputdataobjectlist' => 1, 'outputgain' => 1, + 'outputheight' => 1, + 'outputorientation' => 1, 'outputresponse' => 1, + 'outputwidth' => 1, 'overclockcolsright' => 1, 'overclockrowsbottom' => 1, 'overflowcolor' => 1, @@ -8931,18 +10475,22 @@ my %tagExists = ( 'panoverlaph' => 1, 'panoverlapv' => 1, 'paragraphs' => 1, + 'parallelismtype' => 1, 'param0' => 1, 'param1' => 1, 'param2' => 1, 'param3' => 1, 'parameter' => 1, 'parameterinfo' => 1, + 'parameters' => 1, 'parasites' => 1, - 'parentalrating' => 1, 'parentalratingreason' => 1, - 'parentproductid' => 1, - 'parentshorttitle' => 1, - 'parenttitle' => 1, + 'parrotautomation' => 1, + 'parrotfollowme' => 1, + 'parrottimestamp' => 1, + 'parrotv1' => 1, + 'parrotv2' => 1, + 'parrotv3' => 1, 'part' => 1, 'partialactivecolsleft' => 1, 'partialactivecolsright' => 1, @@ -8971,6 +10519,8 @@ my %tagExists = ( 'pdf' => 1, 'pdfx' => 1, 'peakbitrate' => 1, + 'peaklevelr128' => 1, + 'peaklevelsample' => 1, 'peakspectralsensitivity' => 1, 'peakvalue' => 1, 'pefversion' => 1, @@ -8985,12 +10535,8 @@ my %tagExists = ( 'perceivedtype' => 1, 'perceptualrenderingintentgamut' => 1, 'percussivepolyphony' => 1, - 'performer' => 1, - 'performerkeywords' => 1, - 'performers' => 1, + 'perfmode' => 1, 'performersortorder' => 1, - 'performerurl' => 1, - 'period' => 1, 'perms' => 1, 'perpicturenotes' => 1, 'personalfunctions' => 1, @@ -9031,21 +10577,20 @@ my %tagExists = ( 'picturelength' => 1, 'picturemimetype' => 1, 'picturestyleinfo' => 1, - 'picturestylepc' => 1, - 'picturestyleuserdef' => 1, 'picturetype' => 1, 'picturewidth' => 1, 'pieceinfo' => 1, 'piecelength' => 1, 'pieces' => 1, + 'pilotingmode' => 1, 'pip' => 1, 'pipx1' => 1, 'pipx2' => 1, 'pipy1' => 1, 'pipy2' => 1, 'pitchandfamily' => 1, - 'pitchshift' => 1, - 'pixelaspectratio' => 1, + 'pitchrollyaw' => 1, + 'pittasoft' => 1, 'pixelaspectratiox' => 1, 'pixelaspectratioy' => 1, 'pixelcalibration' => 1, @@ -9056,7 +10601,6 @@ my %tagExists = ( 'pixelintensityrange' => 1, 'pixellive' => 1, 'pixelmagicjbigoptions' => 1, - 'pixelscale' => 1, 'pixelspermeterx' => 1, 'pixelspermetery' => 1, 'pixheight' => 1, @@ -9067,32 +10611,25 @@ my %tagExists = ( 'plancko' => 1, 'planckr1' => 1, 'planckr2' => 1, - 'planes' => 1, - 'playallframes' => 1, + 'playbackflickdownrating' => 1, + 'playbackflickuprating' => 1, 'playcounter' => 1, - 'playerversion' => 1, - 'playgap' => 1, + 'playlist' => 1, 'playlistdelay' => 1, - 'playlistid' => 1, 'playlistindex' => 1, - 'playmode' => 1, - 'playselection' => 1, 'plus' => 1, 'pmi' => 1, 'pobox' => 1, - 'podcast' => 1, 'podcastcategory' => 1, 'podcastdescription' => 1, 'podcastid' => 1, 'podcastkeywords' => 1, - 'podcasturl' => 1, 'pointsize' => 1, 'popularimeter' => 1, 'popupfillattributes' => 1, 'popupflash' => 1, 'portraitmatrix' => 1, 'portraittonescaletable' => 1, - 'pose' => 1, 'poseyawdegrees' => 1, 'position' => 1, 'postertime' => 1, @@ -9108,6 +10645,7 @@ my %tagExists = ( 'preferredrate' => 1, 'preferredsubfamily' => 1, 'preferredvolume' => 1, + 'prefersubselectorcenter' => 1, 'preroll' => 1, 'presentationformat' => 1, 'presentationtarget' => 1, @@ -9133,6 +10671,7 @@ my %tagExists = ( 'previewversion' => 1, 'previewwmf' => 1, 'primarye-mail' => 1, + 'primaryfileguid' => 1, 'primaryitemreference' => 1, 'primaryphone' => 1, 'primaryplatform' => 1, @@ -9165,7 +10704,6 @@ my %tagExists = ( 'producedby' => 1, 'produceddate' => 1, 'producednotice' => 1, - 'producerkeywords' => 1, 'producers' => 1, 'product' => 1, 'productionaperturedimensions' => 1, @@ -9174,9 +10712,7 @@ my %tagExists = ( 'productionstudio' => 1, 'productname' => 1, 'producttype' => 1, - 'productversion' => 1, 'productversionnumber' => 1, - 'profile' => 1, 'profile1audiocodec' => 1, 'profile1height' => 1, 'profile1videocodec' => 1, @@ -9193,11 +10729,10 @@ my %tagExists = ( 'profileheader' => 1, 'profileid' => 1, 'profileifd' => 1, - 'profiles' => 1, 'profilesequencedesc' => 1, 'profilesequenceidentifier' => 1, + 'profilesequenceinfo' => 1, 'profilesize' => 1, - 'profiletype' => 1, 'profileversion' => 1, 'progid' => 1, 'programdescription' => 1, @@ -9236,7 +10771,6 @@ my %tagExists = ( 'projstdparallel2' => 1, 'projstraightvertpolelong' => 1, 'promoteparent' => 1, - 'promotionurl' => 1, 'prop' => 1, 'properties' => 1, 'propertysetidcodes' => 1, @@ -9248,7 +10782,6 @@ my %tagExists = ( 'protectioninfo' => 1, 'protectiontype' => 1, 'protune' => 1, - 'provider' => 1, 'providercopyright' => 1, 'providerlogourl' => 1, 'providerrating' => 1, @@ -9258,12 +10791,12 @@ my %tagExists = ( 'ps2renderingintent' => 1, 'psfontinfo' => 1, 'pstringcaption' => 1, + 'ptrh' => 1, 'publishdate' => 1, 'publishdatestart' => 1, 'publisherlimit' => 1, 'publisherurl' => 1, 'pur' => 1, - 'purchasedate' => 1, 'purchasefileformat' => 1, 'purchaseinfo' => 1, 'purpose' => 1, @@ -9283,6 +10816,8 @@ my %tagExists = ( 'qualcomm' => 1, 'quickedit' => 1, 'quickmaskinfo' => 1, + 'quietshuttershootingspeed' => 1, + 'quoting' => 1, 'qvci' => 1, 'ra3' => 1, 'ra4' => 1, @@ -9291,7 +10826,6 @@ my %tagExists = ( 'radioformat' => 1, 'radiostationname' => 1, 'radiostationowner' => 1, - 'rads' => 1, 'rafdata' => 1, 'rafversion' => 1, 'rasterpadding' => 1, @@ -9299,6 +10833,7 @@ my %tagExists = ( 'rated' => 1, 'ratingorg' => 1, 'ratioimage' => 1, + 'rawburstmoderoll' => 1, 'rawcfacomponentaverages' => 1, 'rawcodecversion' => 1, 'rawdatalength' => 1, @@ -9311,6 +10846,9 @@ my %tagExists = ( 'rawexposurebias' => 1, 'rawgsensor' => 1, 'rawhistogram' => 1, + 'rawimageaspectratio' => 1, + 'rawimagecroppedsize' => 1, + 'rawimagecroptopleft' => 1, 'rawimagefullheight' => 1, 'rawimagefullsize' => 1, 'rawimagefullwidth' => 1, @@ -9327,6 +10865,8 @@ my %tagExists = ( 'rawthermalimagewidth' => 1, 'rawvaluemedian' => 1, 'rawvaluerange' => 1, + 'rawvaluerangemax' => 1, + 'rawvaluerangemin' => 1, 'rawzorcreatorversion' => 1, 'rawzorrequiredversion' => 1, 'rdf' => 1, @@ -9351,6 +10891,17 @@ my %tagExists = ( 'readstatus' => 1, 'real2ir' => 1, 'realtimestreamingprotocol' => 1, + 'rearcontropaneldisplay' => 1, + 'recallshootfuncaf-on' => 1, + 'recallshootfuncafareamode' => 1, + 'recallshootfuncaperture' => 1, + 'recallshootfuncexposurecomp' => 1, + 'recallshootfuncexposuremode' => 1, + 'recallshootfuncfocustracking' => 1, + 'recallshootfunciso' => 1, + 'recallshootfuncmeteringmode' => 1, + 'recallshootfuncshutterspeed' => 1, + 'recallshootfuncwhitebalance' => 1, 'receivedfrom' => 1, 'recengineer' => 1, 'recinfo' => 1, @@ -9358,7 +10909,6 @@ my %tagExists = ( 'reconstructiontype' => 1, 'recordedby' => 1, 'recordeddate' => 1, - 'recordingcopyright' => 1, 'recordingdates' => 1, 'recordingtime' => 1, 'recordingtimeday' => 1, @@ -9366,8 +10916,6 @@ my %tagExists = ( 'recordingtimeyear' => 1, 'recordingtimeyearmonth' => 1, 'recordingtimeyearmonthday' => 1, - 'recordlabelname' => 1, - 'recordlabelurl' => 1, 'rect' => 1, 'rectangleofinterest' => 1, 'red1header' => 1, @@ -9388,14 +10936,17 @@ my %tagExists = ( 'reelnumber' => 1, 'reeltimecode' => 1, 'reference' => 1, + 'referencename' => 1, 'referencetemperature' => 1, 'reflectedapparenttemperature' => 1, + 'reflection' => 1, 'reflectionhardcopyorigcolorimetry' => 1, 'reflectionprintoutputcolorimetry' => 1, 'refresh' => 1, 'regionxformtackpoint' => 1, 'registerreadtiming' => 1, 'relatedimagefile' => 1, + 'relationship' => 1, 'relativeexposure' => 1, 'relativehumidity' => 1, 'relativelocation' => 1, @@ -9410,6 +10961,7 @@ my %tagExists = ( 'rembrandtportraittonescale' => 1, 'rembrandttonescale' => 1, 'remindertime' => 1, + 'remotefuncbutton' => 1, 'removehistoryduplicates' => 1, 'renderingintent' => 1, 'renderingtransform' => 1, @@ -9420,6 +10972,9 @@ my %tagExists = ( 'replaygainalbumpeak' => 1, 'replaygaintrackgain' => 1, 'replaygaintrackpeak' => 1, + 'replaytrackgain' => 1, + 'replaytrackpeak' => 1, + 'replayvolumelevel' => 1, 'replyto' => 1, 'representativedisparityfar' => 1, 'representativedisparitynear' => 1, @@ -9428,7 +10983,6 @@ my %tagExists = ( 'requeststate' => 1, 'requiredattendeeaddresses' => 1, 'requiredattendees' => 1, - 'requirements' => 1, 'rerun' => 1, 'reserved1' => 1, 'reserved5' => 1, @@ -9508,10 +11062,14 @@ my %tagExists = ( 'rollingshutterskewtime' => 1, 'root' => 1, 'rootdirectorycreatedate' => 1, + 'rot360fly' => 1, 'rotationangle' => 1, - 'rotationinfooffset' => 1, + 'rotationxyz' => 1, + 'rotmode' => 1, 'roundtripversion' => 1, + 'rowcount' => 1, 'rowinterleavefactor' => 1, + 'rsrc' => 1, 'rtmd' => 1, 'rtptimescale' => 1, 'runtime' => 1, @@ -9525,13 +11083,18 @@ my %tagExists = ( 'rvmi_srev' => 1, 's2n' => 1, 'sampleblacksequence' => 1, + 'sampledatetime' => 1, 'sampledegradationpriority' => 1, 'sampleduration' => 1, 'sampleflag' => 1, 'sampleformat' => 1, 'samplegroupdescription' => 1, 'samplepaddingbits' => 1, + 'sampleperiod' => 1, + 'sampler' => 1, 'samplerate2' => 1, + 'samplerdata' => 1, + 'samplerdatalen' => 1, 'samplesize' => 1, 'samplesizes' => 1, 'sampletable' => 1, @@ -9550,11 +11113,14 @@ my %tagExists = ( 'samsungsmta' => 1, 'samsungsvss' => 1, 'samsungtags' => 1, + 'samsungtrailer' => 1, + 'samsunguniqueid' => 1, 'sanyomov' => 1, 'sanyomp4' => 1, 'sap' => 1, 'saturationinfo' => 1, 'saturationrenderingintentgamut' => 1, + 'savefocus' => 1, 'saveobjbacktype' => 1, 'saveobjects' => 1, 'saveobjname' => 1, @@ -9607,13 +11173,17 @@ my %tagExists = ( 'school' => 1, 'screenbuffersize' => 1, 'screendescriptor' => 1, + 'screenheight' => 1, 'screening' => 1, 'screeningdesc' => 1, 'screennail' => 1, + 'screenwidth' => 1, 'screenwindowcenter' => 1, 'screenwindowwidth' => 1, 'screenwriters' => 1, + 'script' => 1, 'scriptcommand' => 1, + 'sdc' => 1, 'searchranking' => 1, 'secondarygenre' => 1, 'secondlanguage' => 1, @@ -9621,6 +11191,8 @@ my %tagExists = ( 'seekable' => 1, 'seekpoint' => 1, 'seektable' => 1, + 'segheight' => 1, + 'segwidth' => 1, 'selection' => 1, 'selectionduration' => 1, 'selectiontime' => 1, @@ -9628,19 +11200,26 @@ my %tagExists = ( 'selobjname' => 1, 'selobjtype' => 1, 'selobjversion' => 1, + 'semanticinstanceifd' => 1, + 'semanticname' => 1, 'sendduration' => 1, 'senderaddress' => 1, 'sendername' => 1, 'sensitivity' => 1, + 'sensitivityvalue' => 1, 'sensorbottomborder' => 1, + 'sensordata' => 1, 'sensordefects' => 1, 'sensorid' => 1, 'sensorinfo' => 1, + 'sensorreadouttime' => 1, 'sensorrightborder' => 1, + 'seqlevelidx0' => 1, + 'seqprofile' => 1, + 'seqtier0' => 1, 'sequenceframenumber' => 1, 'sequencenumberrandomoffset' => 1, 'serialinfo' => 1, - 'serialnumberhash' => 1, 'seriesuid' => 1, 'serviceid' => 1, 'serviceorganizationname' => 1, @@ -9659,7 +11238,6 @@ my %tagExists = ( 'shared' => 1, 'shareddata' => 1, 'shareddoc' => 1, - 'shareduserrating' => 1, 'sharedwith' => 1, 'sharpenforthumbnail' => 1, 'sharpeningon' => 1, @@ -9676,14 +11254,12 @@ my %tagExists = ( 'shifttiming' => 1, 'shimdata' => 1, 'shootingcount' => 1, - 'shootingmenuoffset' => 1, 'shootingrecord' => 1, 'shootobjbacktype' => 1, 'shootobjname' => 1, 'shootobjtype' => 1, 'shootobjversion' => 1, 'shootsetup' => 1, - 'shorttitle' => 1, 'shotinfo' => 1, 'shotinfo02xx' => 1, 'shotinfod300a' => 1, @@ -9701,6 +11277,7 @@ my %tagExists = ( 'shotinfod5000' => 1, 'shotinfod5100' => 1, 'shotinfod5200' => 1, + 'shotinfod6' => 1, 'shotinfod610' => 1, 'shotinfod700' => 1, 'shotinfod7000' => 1, @@ -9711,13 +11288,16 @@ my %tagExists = ( 'shotinfod90' => 1, 'shotinfounknown' => 1, 'shotinfoversion' => 1, + 'shotinfoz7ii' => 1, + 'shotinfoz9' => 1, 'showmode' => 1, 'showobjects' => 1, - 'shutter' => 1, + 'shutterangle' => 1, 'shuttercurtainhack' => 1, 'shutterspeed' => 1, 'shutterspeeddisplayed' => 1, 'sidebars' => 1, + 'sidelightstrength' => 1, 'sigma' => 1, 'sigmanoisefiltercaltablev1' => 1, 'sigmanoisefiltertablev1' => 1, @@ -9737,6 +11317,9 @@ my %tagExists = ( 'simpleindex' => 1, 'simplicityprofile' => 1, 'singlequality' => 1, + 'singleshotdepthmap' => 1, + 'singleshotdepthmaptiff' => 1, + 'singleshotmeta' => 1, 'site' => 1, 'siteenter' => 1, 'siteexit' => 1, @@ -9752,6 +11335,8 @@ my %tagExists = ( 'slideshow' => 1, 'smaxsamplevalue' => 1, 'sminsamplevalue' => 1, + 'smpteformat' => 1, + 'smpteoffset' => 1, 'snapshotid' => 1, 'snapshotname' => 1, 'soctemperature' => 1, @@ -9759,21 +11344,14 @@ my %tagExists = ( 'softfocusfilter' => 1, 'softwarecomponents' => 1, 'softwarerelease' => 1, - 'songwriter' => 1, - 'songwriterkeywords' => 1, 'sony' => 1, + 'sony_0x9416' => 1, + 'sonyfnumber2' => 1, 'sonyrawfiletype' => 1, 'sonytonecurve' => 1, - 'sortalbum' => 1, - 'sortalbumartist' => 1, - 'sortartist' => 1, - 'sortcomposer' => 1, - 'sortname' => 1, - 'sortshow' => 1, 'soundfile' => 1, 'soundschemetitle' => 1, 'sourcecreatedate' => 1, - 'sourcecredits' => 1, 'sourcedata' => 1, 'sourcedate' => 1, 'sourceedition' => 1, @@ -9797,11 +11375,14 @@ my %tagExists = ( 'specialeffectsopticalfilter' => 1, 'specialfolderdata' => 1, 'specificationversion' => 1, + 'spectralviewingconditions' => 1, + 'spectralwhitepoint' => 1, 'speed' => 1, 'sphericalvideo' => 1, 'sphericalvideoxml' => 1, 'spiff' => 1, 'spiffversion' => 1, + 'spinstrength' => 1, 'spothalftone' => 1, 'spouse' => 1, 'sr2dataifd' => 1, @@ -9813,9 +11394,10 @@ my %tagExists = ( 'srf2key' => 1, 'srf6offset' => 1, 'srfdataoffset' => 1, - 'srgbrendering' => 1, 'stampinfo' => 1, 'stamptoolcount' => 1, + 'standardtocustompcc' => 1, + 'standbymonitorofftime' => 1, 'starring' => 1, 'startdate' => 1, 'startedgecode' => 1, @@ -9840,6 +11422,7 @@ my %tagExists = ( 'stereo' => 1, 'stereoimage' => 1, 'stereoscopic3d' => 1, + 'stillimagetime' => 1, 'stim' => 1, 'stimversion' => 1, 'stitchcolumns' => 1, @@ -9890,6 +11473,13 @@ my %tagExists = ( 'structuretype' => 1, 'studio' => 1, 'sub-sampleinformation' => 1, + 'subdialframeadvance' => 1, + 'subdialframeadvancerating0' => 1, + 'subdialframeadvancerating1' => 1, + 'subdialframeadvancerating2' => 1, + 'subdialframeadvancerating3' => 1, + 'subdialframeadvancerating4' => 1, + 'subdialframeadvancerating5' => 1, 'subdir3000' => 1, 'subdir3100' => 1, 'subdir3400' => 1, @@ -9926,11 +11516,11 @@ my %tagExists = ( 'subsystemversion' => 1, 'subtileblocksize' => 1, 'subtitledescription' => 1, - 'subtitlekeywords' => 1, 'suffix' => 1, 'suggestedpalette' => 1, 'summary' => 1, 'summaryinfo' => 1, + 'surfacemap' => 1, 'surroundmode' => 1, 'surroundshotvideo' => 1, 'surroundshotvideoname' => 1, @@ -9977,9 +11567,11 @@ my %tagExists = ( 'tag900b' => 1, 'tag9050a' => 1, 'tag9050b' => 1, + 'tag9050c' => 1, 'tag9400a' => 1, 'tag9400b' => 1, 'tag9400c' => 1, + 'tag9401' => 1, 'tag9402' => 1, 'tag9403' => 1, 'tag9404a' => 1, @@ -9991,6 +11583,7 @@ my %tagExists = ( 'tag940a' => 1, 'tag940c' => 1, 'tag940e' => 1, + 'tag9416_0000' => 1, 'taggedpdf' => 1, 'taggingtime' => 1, 'take' => 1, @@ -10009,10 +11602,12 @@ my %tagExists = ( 'technician' => 1, 'technology' => 1, 'telephonenumber' => 1, + 'telescope' => 1, 'telex' => 1, 'temperature' => 1, 'tempinfo' => 1, 'template' => 1, + 'temporalidnested' => 1, 'temporary' => 1, 'terminationaction' => 1, 'terminationcondition' => 1, @@ -10034,6 +11629,9 @@ my %tagExists = ( 'textureformat' => 1, 'theora' => 1, 'theoraversion' => 1, + 'thermalcalibration' => 1, + 'thermaldata' => 1, + 'thermalparams' => 1, 'thetasubdir' => 1, 'things' => 1, 'thirdlanguage' => 1, @@ -10043,9 +11641,11 @@ my %tagExists = ( 'thumbnailclip' => 1, 'thumbnailcompressiontable' => 1, 'thumbnailexpansiontable' => 1, - 'thumbnailpng' => 1, + 'thumbnailhash' => 1, + 'thumbnailref' => 1, 'thumbnailresizeratio' => 1, 'thumbnailtiff' => 1, + 'thumbnailurl' => 1, 'tickspersecond' => 1, 'tiff' => 1, 'tiff-epstandardid' => 1, @@ -10066,6 +11666,7 @@ my %tagExists = ( 'timeoffset' => 1, 'timereference' => 1, 'timescale' => 1, + 'timestamplist' => 1, 'timestamprandomoffset' => 1, 'timetosampletable' => 1, 'title2' => 1, @@ -10077,6 +11678,12 @@ my %tagExists = ( 'toaddresses' => 1, 'tocitems' => 1, 'todotitle' => 1, + 'tomtomad' => 1, + 'tomtomhl' => 1, + 'tomtomid' => 1, + 'tomtommetadata' => 1, + 'tomtomvd' => 1, + 'tomtomvi' => 1, 'tonames' => 1, 'tonecurvematching' => 1, 'tonecurvetable' => 1, @@ -10115,6 +11722,7 @@ my %tagExists = ( 'topdarkrow1' => 1, 'topdarkrow2' => 1, 'topmag' => 1, + 'topmargin' => 1, 'totalbitrate' => 1, 'totalbytes' => 1, 'totalbytesnortpheaders' => 1, @@ -10128,7 +11736,6 @@ my %tagExists = ( 'totalsamples' => 1, 'totalsize' => 1, 'toycamerafilter' => 1, - 'track' => 1, 'trackaperture' => 1, 'trackcategory' => 1, 'trackcomments' => 1, @@ -10143,10 +11750,11 @@ my %tagExists = ( 'tracklyrics' => 1, 'trackproperty' => 1, 'trackref' => 1, - 'tracktype' => 1, 'trackvolume' => 1, 'trademark' => 1, 'transactionid' => 1, + 'transfercharacteristic' => 1, + 'transfercharacteristics' => 1, 'transferrange' => 1, 'transfersequence' => 1, 'transformation' => 1, @@ -10158,11 +11766,12 @@ my %tagExists = ( 'transformtitle' => 1, 'transparency' => 1, 'transparencyindicator' => 1, + 'transparentcolor' => 1, 'transparentindex' => 1, 'trapindicator' => 1, 'trashcolsright' => 1, 'trashrowsbottom' => 1, - 'trebel' => 1, + 'trim' => 1, 'tty-ttdphone' => 1, 'tungmat0' => 1, 'tungmat1' => 1, @@ -10174,11 +11783,7 @@ my %tagExists = ( 'tungmat7' => 1, 'tungmat8' => 1, 'tungmat9' => 1, - 'tvepisode' => 1, - 'tvepisodeid' => 1, - 'tvnetworkname' => 1, - 'tvseason' => 1, - 'tvshow' => 1, + 'twelvebit' => 1, 'tx3g' => 1, 'typeoforiginal' => 1, 'typist' => 1, @@ -10197,14 +11802,17 @@ my %tagExists = ( 'unicodealphanames' => 1, 'uninitializeddatasize' => 1, 'uniquefileidentifier' => 1, + 'uniqueid' => 1, 'unknown' => 1, - 'unknown_aacr' => 1, - 'unknown_cdek' => 1, - 'unknown_cdet' => 1, + 'unknown00' => 1, + 'unknown01' => 1, + 'unknown02' => 1, + 'unknown03' => 1, 'unknown_cndb' => 1, 'unknown_slmt' => 1, 'unknownd30' => 1, 'unknowndata' => 1, + 'unknownexif' => 1, 'unknowninfo' => 1, 'unknowninfo2' => 1, 'unknowninfo2version' => 1, @@ -10214,11 +11822,10 @@ my %tagExists = ( 'unknownserial2' => 1, 'unknownserial3' => 1, 'unknownserial4' => 1, - 'unknowntags' => 1, 'unknowntemperature1' => 1, 'unknowntemperature2' => 1, - 'unknownthumbnail' => 1, 'unsharpdata' => 1, + 'unshiftednote' => 1, 'untitled0' => 1, 'untitled1' => 1, 'untitled2' => 1, @@ -10239,7 +11846,6 @@ my %tagExists = ( 'usedextensionnumbers' => 1, 'useraccess' => 1, 'useradjsba_rgbshifts' => 1, - 'usercollection' => 1, 'usercustom1' => 1, 'usercustom2' => 1, 'userdata' => 1, @@ -10258,9 +11864,9 @@ my %tagExists = ( 'userplaycountnight' => 1, 'userplaycountweekday' => 1, 'userplaycountweekend' => 1, - 'userrating' => 1, 'userselectgrouptitle' => 1, 'userservicerating' => 1, + 'usertext' => 1, 'userweburl' => 1, 'usingtransforms' => 1, 'usmparametershigh' => 1, @@ -10272,7 +11878,9 @@ my %tagExists = ( 'usptomiscellaneous' => 1, 'usptooriginalcontenttype' => 1, 'utm' => 1, + 'uuid-c2paclaimsignature' => 1, 'uuid-canon' => 1, + 'uuid-canon2' => 1, 'uuid-exif' => 1, 'uuid-exif2' => 1, 'uuid-exif_bad' => 1, @@ -10282,6 +11890,7 @@ my %tagExists = ( 'uuid-iptc2' => 1, 'uuid-photoshop' => 1, 'uuid-prof' => 1, + 'uuid-signature' => 1, 'uuid-unknown' => 1, 'uuid-usmt' => 1, 'uuid-xmp' => 1, @@ -10301,7 +11910,6 @@ my %tagExists = ( 'vddimdacnominalvalues' => 1, 'vegasversionmajor' => 1, 'vegasversionminor' => 1, - 'vendor' => 1, 'vendorid' => 1, 'vendorname' => 1, 'vendorurl' => 1, @@ -10312,12 +11920,14 @@ my %tagExists = ( 'versioninfo' => 1, 'versionrestrictions' => 1, 'versionyear' => 1, + 'verticalaf-onbutton' => 1, 'verticalcitation' => 1, 'verticalcstype' => 1, 'verticaldatum' => 1, 'verticaldivergence' => 1, 'verticalresolution' => 1, 'verticalscale' => 1, + 'verticalspeed' => 1, 'verticalunits' => 1, 'video' => 1, 'videoattributes' => 1, @@ -10329,7 +11939,6 @@ my %tagExists = ( 'videocodecid' => 1, 'videocodecinfo' => 1, 'videocodecname' => 1, - 'videocompression' => 1, 'videoencoding' => 1, 'videoformat' => 1, 'videoframecount' => 1, @@ -10345,6 +11954,7 @@ my %tagExists = ( 'videoscantype' => 1, 'videosize' => 1, 'videostreamtype' => 1, + 'videotimestamp' => 1, 'videotrackid' => 1, 'videowidth' => 1, 'view' => 1, @@ -10361,6 +11971,7 @@ my %tagExists = ( 'vignettingcorrunknown2' => 1, 'vignettingcorrversion' => 1, 'vignettingparams' => 1, + 'vintagestrength' => 1, 'virtualimageheight' => 1, 'virtualimagewidth' => 1, 'virtualpage' => 1, @@ -10382,6 +11993,7 @@ my %tagExists = ( 'volumeexpirationdate' => 1, 'volumeid' => 1, 'volumelabel' => 1, + 'volumelevelr128' => 1, 'volumemodifydate' => 1, 'volumename' => 1, 'volumenormalization' => 1, @@ -10420,7 +12032,6 @@ my %tagExists = ( 'wb_cfa1_leveldaylight' => 1, 'wb_cfa2_leveldaylight' => 1, 'wb_cfa3_leveldaylight' => 1, - 'wb_grbglevelsauto' => 1, 'wb_grblevels' => 1, 'wb_grblevelsauto' => 1, 'wb_grblevelsstandard' => 1, @@ -10439,23 +12050,8 @@ my %tagExists = ( 'wb_rgbcoeffsflash' => 1, 'wb_rgbcoeffsfluorescent' => 1, 'wb_rgbcoeffstungsten' => 1, - 'wb_rgblevels2500k' => 1, - 'wb_rgblevels3200k' => 1, - 'wb_rgblevels4500k' => 1, - 'wb_rgblevels6000k' => 1, - 'wb_rgblevels8500k' => 1, 'wb_rgblevelsasshot' => 1, - 'wb_rgblevelsauto' => 1, - 'wb_rgblevelscloudy' => 1, 'wb_rgblevelscustom' => 1, - 'wb_rgblevelsdaylight' => 1, - 'wb_rgblevelsflash' => 1, - 'wb_rgblevelsfluorescent' => 1, - 'wb_rgblevelsfluorescentm1' => 1, - 'wb_rgblevelsfluorescentp1' => 1, - 'wb_rgblevelsfluorescentp2' => 1, - 'wb_rgblevelsshade' => 1, - 'wb_rgblevelstungsten' => 1, 'wbadjdata' => 1, 'wbblueasshot' => 1, 'wbbluecloudy' => 1, @@ -10479,6 +12075,8 @@ my %tagExists = ( 'wbredflash' => 1, 'wbredfluorescent' => 1, 'wbredtungsten' => 1, + 'wbsettings' => 1, + 'wbsettings2' => 1, 'wcsprofiles' => 1, 'webpage' => 1, 'weight' => 1, @@ -10497,7 +12095,7 @@ my %tagExists = ( 'wide' => 1, 'widthbytes' => 1, 'widthresolution' => 1, - 'windowlocation' => 1, + 'wifirssi' => 1, 'windoworigin' => 1, 'windoworiginauto' => 1, 'windowsdevmode' => 1, @@ -10529,14 +12127,17 @@ my %tagExists = ( 'worldtocamera' => 1, 'worldtondc' => 1, 'wrapmodes' => 1, - 'writer' => 1, 'writername' => 1, 'writers' => 1, 'writtenby' => 1, 'wwsfamilyname' => 1, 'wwssubfamilyname' => 1, 'x' => 1, + 'xattrapplemaildatereceived' => 1, + 'xattrapplemaildatesent' => 1, + 'xattrapplemailisremoteattachment' => 1, 'xattrfinderinfo' => 1, + 'xattrlastuseddate' => 1, 'xattrmditemdownloadeddate' => 1, 'xattrmditemfindercomment' => 1, 'xattrmditemwherefroms' => 1, @@ -10545,10 +12146,12 @@ my %tagExists = ( 'xcfversion' => 1, 'xclippathunits' => 1, 'xheight' => 1, + 'xidiri' => 1, 'xmag' => 1, 'xmethod' => 1, 'xmldata' => 1, 'xmlfiletype' => 1, + 'xmlpackets' => 1, 'xmp_profile' => 1, 'xmpbj' => 1, 'xmpdm' => 1, @@ -10565,7 +12168,6 @@ my %tagExists = ( 'xyoffsetinfo' => 1, 'yclippathunits' => 1, 'ycrcbmatrix' => 1, - 'year' => 1, 'ylevel' => 1, 'ymag' => 1, 'ymethod' => 1, @@ -10575,14 +12177,17 @@ my %tagExists = ( 'zipcompressedsize' => 1, 'zipcompression' => 1, 'zipcrc' => 1, + 'zipfilecomment' => 1, 'zipfilename' => 1, 'zipmodifydate' => 1, 'ziprequiredversion' => 1, 'zipuncompressedsize' => 1, + 'zisrawversion' => 1, 'zoom' => 1, 'zoomedpreviewimage' => 1, 'zoompos' => 1, 'zoomposition' => 1, + 'zoomstrength' => 1, 'zxif' => 1, ); @@ -10590,6 +12195,9 @@ my %tagExists = ( my %compositeModules = ( 'filenumber' => 'Image::ExifTool::Canon', 'flash' => 'Image::ExifTool::XMP', + 'gpslatitude' => 'Image::ExifTool::GPS', + 'gpslongitude' => 'Image::ExifTool::GPS', + 'gpsposition' => 'Image::ExifTool::Exif', 'jpgfromraw' => 'Image::ExifTool::Exif', 'originaldecisiondata' => 'Image::ExifTool::Canon', 'otherimage' => 'Image::ExifTool::Exif', @@ -10635,7 +12243,7 @@ if (@Image::ExifTool::pluginTags) { # Inputs: 0) tag table ref for flattened tags, 1) tagID, 2) lowercase tag name, # 3) tag ID list ref, 4) reference to list of lowercase tag names # 5) table number in lookup, 6) tagInfo hash for parent structure -# 7) tag ID of top-level stucture +# 7) tag ID of top-level structure # Notes: Used only for user-defined structures sub AddFields($$$$$$;$$) { @@ -10802,7 +12410,7 @@ sub FindTagInfo($) } } while ($lookup) { - foreach $tableNum (keys %$lookup) { + foreach $tableNum (sort { $a <=> $b } keys %$lookup) { my $table = GetTagTable($tableList[$tableNum]); my $le = $$lookup{$tableNum}; my ($tagID, $tagIDs); @@ -10826,7 +12434,10 @@ sub FindTagInfo($) my $reload; # call write proc if it exists in case it adds tags to the table my $writeProc = $table->{WRITE_PROC}; - $reload = 1 if $writeProc and &$writeProc(); + if ($writeProc) { + no strict 'refs'; + $reload = 1 if &$writeProc(); + } # load module with composite tag if necessary my $compMod = $compositeModules{$lcTag}; $reload = 1 if $compMod and eval "require $compMod"; @@ -10872,7 +12483,7 @@ Provides a fast, case insensitive lookup for tag names. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/TagNames.pod b/src/Image-ExifTool/lib/Image/ExifTool/TagNames.pod index 3646f385..728a24e4 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/TagNames.pod +++ b/src/Image-ExifTool/lib/Image/ExifTool/TagNames.pod @@ -12,6 +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 25828 tags, with 16515 unique tag names. B<Tag ID>, B<Index#> or B<Sequence> is given in the first column of each table. A B<Tag ID> is the computer-readable equivalent of a tag name, and @@ -19,8 +20,10 @@ is the identifier that is actually stored in the file. B<Index#> refers to the offset of a value when found at a fixed position within a data block (B<#> is the multiplier for calculating a byte offset: B<1>, B<2>, B<4> or B<8>). These offsets may have a decimal part which is used only to -differentiate tags which have values stored at the same position. -B<Sequence> gives the order of values for a serial data stream. +differentiate tags with values stored at the same position. (Note that +writable tags within binary data blocks are not individually deletable, +and the usual alternative is to set them to a value of zero.) B<Sequence> +gives the order of values for a serial data stream. A B<Tag Name> is the handle by which the information is accessed in ExifTool. In some instances, more than one name may correspond to a single @@ -36,20 +39,20 @@ instead of the descriptions, use C<exiftool -s>. The B<Writable> column indicates whether the tag is writable by ExifTool. Anything but a C<no> in this column means the tag is writable. A C<yes> indicates writable information that is either unformatted or written using -the existing format. Other expressions give details about the information -format, and vary depending on the general type of information. The format -name may be followed by a number in square brackets to indicate the number -of values written, or the number of characters in a fixed-length string -(including a null terminator which is added if required). +the existing format. Other expressions give details about the format of the +stored value, and vary depending on the general type of information. The +format name may be followed by a number in square brackets to indicate the +number of values written, or the number of characters in a fixed-length +string (including a null terminator which is added if required). A plus sign (C<+>) after an entry in the B<Writable> column indicates a I<List> tag which supports multiple values and allows individual values to be added and deleted. A slash (C</>) indicates a tag that ExifTool will -I<Avoid> when writing. These tags are not created when writing if another -same-named tag may be created instead. To write these tags, the group +I<Avoid> when writing. These will be edited but not created if another +same-named tag may be created instead. To create these tags, the group should be specified. A tilde (C<~>) indicates a tag this is writable only when the print conversion is disabled (by setting PrintConv to 0, using the --n option, or suffixing the tag name with a C<#> character). An exclamation +-n option, or suffixing the tag name with a C<#> character). An exclamation point (C<!>) indicates a tag that is considered I<Unsafe> to write under normal circumstances. These tags are not written unless specified explicitly (ie. not when wildcards or "all" are used), and care should be @@ -59,15 +62,16 @@ writable directly, but is written automatically by ExifTool (often when a corresponding L<Composite|Image::ExifTool::TagNames/Composite Tags> or L<Extra|Image::ExifTool::TagNames/Extra Tags> tag is written). A colon (C<:>) indicates a I<Mandatory> tag which may be added automatically when -writing. +writing. Normally MakerNotes tags may not be deleted individually, but a +caret (C<^>) indicates a I<Deletable> MakerNotes tag. The HTML version of these tables also lists possible B<Values> for discrete-valued tags, as well as B<Notes> for some tags. The B<Values> are -listed as the computer-readable and human-readable values on the left and -right hand side of an equals sign (C<=>) respectively. The human-readable +listed with the computer-readable values on the left of the equals sign +(C<=>), and the human-readable values on the right. The human-readable values are used by default when reading and writing, but the computer-readable values may be accessed by disabling the value conversion -with the -n option on the command line, by setting the ValueConv option to 0 +with the -n option on the command line, by setting the PrintConv option to 0 in the API, or or on a per-tag basis by adding a hash (C<#>) after the tag name. @@ -104,28 +108,37 @@ L<https://www.w3.org/Graphics/JPEG/jfif3.pdf> for the JPEG specification. XMP XMP QVCI Casio QVCI FLIR FLIR FFF + RawThermalImage no 'APP2' ICC_Profile ICC_Profile FPXR FlashPix MPF MPF PreviewImage no 'APP3' Meta Kodak Meta Stim Stim + JPS JPEG JPS + ThermalData no PreviewImage no 'APP4' Scalado Scalado FPXR FlashPix + ThermalParams DJI ThermalParams PreviewImage no 'APP5' RMETA Ricoh RMETA + SamsungUniqueID Samsung APP5 + ThermalCalibration no PreviewImage no 'APP6' EPPIM JPEG EPPIM NITF JPEG NITF HP_TDHD HP TDHD GoPro GoPro GPMF + DJI_DTAT no 'APP7' Pentax Pentax + Huawei Unknown Qualcomm Qualcomm 'APP8' SPIFF JPEG SPIFF 'APP9' MediaJukebox JPEG MediaJukebox 'APP10' Comment no 'APP11' JPEG-HDR JPEG HDR + JUMBF Jpeg2000 'APP12' PictureInfo APP12 PictureInfo Ducky APP12 Ducky 'APP13' Photoshop Photoshop @@ -141,6 +154,9 @@ L<https://www.w3.org/Graphics/JPEG/jfif3.pdf> for the JPEG specification. PhotoMechanic PhotoMechanic MIE MIE Samsung Samsung Trailer + EmbeddedVideo no + Insta360 no + NikonApp no PreviewImage yes =head3 JPEG AVI1 Tags @@ -160,6 +176,18 @@ images). ------ -------- -------- 'Rev' OcadRevision no +=head3 JPEG JPS Tags + +Tags found in JPEG Stereo (JPS) images. + + Index1 Tag Name Writable + ------ -------- -------- + 10 JPSSeparation no + 11 JPSFlags no + 12 JPSLayout no + 13 JPSType no + 16 JPSComment no + =head3 JPEG EPPIM Tags APP6 is used in by the Toshiba PDR-M700 to store a TIFF structure containing @@ -306,11 +334,11 @@ tags remain. The table below lists all EXIF tags. Also listed are TIFF, DNG, HDP and other tags which are not part of the EXIF specification, but may co-exist -with EXIF tags in some images. Tags which are part of the EXIF 2.31 +with EXIF tags in some images. Tags which are part of the EXIF 2.32 specification have an underlined B<Tag Name> in the HTML version of this documentation. See -L<http://www.cipa.jp/std/documents/e/DC-008-Translation-2016-E.pdf> for the -official EXIF 2.31 specification. +L<https://web.archive.org/web/20190624045241if_/http://www.cipa.jp:80/std/documents/e/DC-008-Translation-2019-E.pdf> +for the official EXIF 2.32 specification. Tag ID Tag Name Group Writable ------ -------- ----- -------- @@ -454,6 +482,8 @@ official EXIF 2.31 specification. 0x7035 ChromaticAberrationCorrParams SubIFD int16s[33]! 0x7036 DistortionCorrection SubIFD int16s! 0x7037 DistortionCorrParams SubIFD int16s[17]! + 0x74c7 SonyCropTopLeft SubIFD int32u[2]! + 0x74c8 SonyCropSize SubIFD int32u[2]! 0x800d ImageID - no 0x80a3 WangTag1 - no 0x80a4 WangAnnotation - no @@ -490,7 +520,7 @@ official EXIF 2.31 specification. 0x82aa MDPrepDate - no 0x82ab MDPrepTime - no 0x82ac MDFileUnits - no - 0x830e PixelScale - no + 0x830e PixelScale IFD0 double[3] 0x8335 AdventScale - no 0x8336 AdventRevision - no 0x835c UIC1Tag - no @@ -500,9 +530,9 @@ official EXIF 2.31 specification. 0x83bb IPTC-NAA IFD0 IPTC 0x847e IntergraphPacketData - no 0x847f IntergraphFlagRegisters - no - 0x8480 IntergraphMatrix - no + 0x8480 IntergraphMatrix IFD0 double[n] 0x8481 INGRReserved - no - 0x8482 ModelTiePoint - no + 0x8482 ModelTiePoint IFD0 double[n] 0x84e0 Site - no 0x84e1 ColorSequence - no 0x84e2 IT8Header - no @@ -524,7 +554,7 @@ official EXIF 2.31 specification. 0x8568 AFCP_IPTC - IPTC 0x85b8 PixelMagicJBIGOptions - no 0x85d7 JPLCartoIFD - no - 0x85d8 ModelTransform - no + 0x85d8 ModelTransform IFD0 double[16] 0x8602 WB_GRGBLevels - no 0x8606 LeafData - Leaf 0x8649 PhotoshopSettings IFD0 Photoshop @@ -535,8 +565,8 @@ official EXIF 2.31 specification. 0x8781 SharedData - no 0x8782 T88Options - no 0x87ac ImageLayer - no - 0x87af GeoTiffDirectory IFD0 undef - 0x87b0 GeoTiffDoubleParams IFD0 undef + 0x87af GeoTiffDirectory IFD0 int16u[0.5] + 0x87b0 GeoTiffDoubleParams IFD0 double[0.125] 0x87b1 GeoTiffAsciiParams IFD0 string 0x87be JBIGOptions - no 0x8822 ExposureProgram ExifIFD int16u @@ -599,6 +629,7 @@ official EXIF 2.31 specification. MakerNoteCanon ExifIFD Canon MakerNoteCasio ExifIFD Casio MakerNoteCasio2 ExifIFD Casio Type2 + MakerNoteDJIInfo ExifIFD DJI Info MakerNoteDJI ExifIFD DJI MakerNoteFLIR ExifIFD FLIR MakerNoteFujiFilm ExifIFD FujiFilm @@ -639,6 +670,7 @@ official EXIF 2.31 specification. MakerNoteNintendo ExifIFD Nintendo MakerNoteOlympus ExifIFD Olympus MakerNoteOlympus2 ExifIFD Olympus + MakerNoteOlympus3 ExifIFD Olympus MakerNoteLeica ExifIFD Panasonic MakerNoteLeica2 ExifIFD Panasonic Leica2 MakerNoteLeica3 ExifIFD Panasonic Leica3 @@ -648,6 +680,7 @@ official EXIF 2.31 specification. MakerNoteLeica7 ExifIFD Panasonic Leica6 MakerNoteLeica8 ExifIFD Panasonic Leica5 MakerNoteLeica9 ExifIFD Panasonic Leica9 + MakerNoteLeica10 ExifIFD Panasonic MakerNotePanasonic ExifIFD Panasonic MakerNotePanasonic2 ExifIFD Panasonic Type2 MakerNotePanasonic3 ExifIFD Panasonic @@ -660,6 +693,8 @@ official EXIF 2.31 specification. MakerNotePhaseOne ExifIFD PhaseOne MakerNoteReconyx ExifIFD Reconyx MakerNoteReconyx2 ExifIFD Reconyx Type2 + MakerNoteReconyx3 ExifIFD Reconyx Type3 + MakerNoteRicohPentax ExifIFD Pentax MakerNoteRicoh ExifIFD Ricoh MakerNoteRicoh2 ExifIFD Ricoh Type2 MakerNoteRicohText ExifIFD Ricoh Text @@ -744,8 +779,11 @@ official EXIF 2.31 specification. 0xa433 LensMake ExifIFD string 0xa434 LensModel ExifIFD string 0xa435 LensSerialNumber ExifIFD string - 0xa480 GDALMetadata - no - 0xa481 GDALNoData - no + 0xa460 CompositeImage ExifIFD int16u + 0xa461 CompositeImageCount ExifIFD int16u[2] + 0xa462 CompositeImageExposureTimes ExifIFD undef + 0xa480 GDALMetadata IFD0 string + 0xa481 GDALNoData IFD0 string 0xa500 Gamma ExifIFD rational64u 0xafc0 ExpandSoftware - no 0xafc1 ExpandLens - no @@ -753,6 +791,7 @@ official EXIF 2.31 specification. 0xafc3 ExpandFilterLens - no 0xafc4 ExpandScanner - no 0xafc5 ExpandFlashLamp - no + 0xb4c3 HasselbladRawImage - no 0xbc01 PixelFormat - no 0xbc02 Transformation - no 0xbc03 Uncompressed - no @@ -773,6 +812,7 @@ official EXIF 2.31 specification. 0xc42a OceImageLogic - no 0xc44f Annotations - no 0xc4a5 PrintIM IFD0 PrintIM + 0xc51b HasselbladExif - no 0xc573 OriginalFileName - no 0xc580 USPTOOriginalContentType - no 0xc5e0 CR2CFAPattern - no @@ -814,6 +854,8 @@ official EXIF 2.31 specification. DNGAdobeData IFD0 DNG AdobeData MakerNotePentax IFD0 Pentax MakerNotePentax5 IFD0 Pentax + MakerNoteRicohPentax IFD0 Pentax + MakerNoteDJIInfo IFD0 DJI Info DNGPrivateData IFD0 int8u! 0xc635 MakerNoteSafety IFD0 int16u 0xc640 RawImageSegmentation - no @@ -860,9 +902,9 @@ official EXIF 2.31 specification. 0xc71f RowInterleaveFactor - no 0xc725 ProfileLookTableDims IFD0 int32u[3]! 0xc726 ProfileLookTableData IFD0 float[n]! - 0xc740 OpcodeList1 SubIFD undef! - 0xc741 OpcodeList2 SubIFD undef! - 0xc74e OpcodeList3 SubIFD undef! + 0xc740 OpcodeList1 SubIFD undef~! + 0xc741 OpcodeList2 SubIFD undef~! + 0xc74e OpcodeList3 SubIFD undef~! 0xc761 NoiseProfile SubIFD double[n]! 0xc763 TimeCodes IFD0 int8u[n] 0xc764 FrameRate IFD0 rational64s @@ -880,6 +922,27 @@ official EXIF 2.31 specification. 0xc7a8 RawToPreviewGain IFD0 double! 0xc7aa CacheVersion SubIFD2 int32u! 0xc7b5 DefaultUserCrop SubIFD rational64u[4]! + 0xc7d5 NikonNEFInfo - Nikon NEFInfo + 0xc7e9 DepthFormat IFD0 int16u! + 0xc7ea DepthNear IFD0 rational64u! + 0xc7eb DepthFar IFD0 rational64u! + 0xc7ec DepthUnits IFD0 int16u! + 0xc7ed DepthMeasureType IFD0 int16u! + 0xc7ee EnhanceParams IFD0 string! + 0xcd2d ProfileGainTableMap SubIFD undef! + 0xcd2e SemanticName SubIFD no + 0xcd30 SemanticInstanceIFD SubIFD no + 0xcd31 CalibrationIlluminant3 IFD0 int16u! + 0xcd32 CameraCalibration3 IFD0 rational64s[n]! + 0xcd33 ColorMatrix3 IFD0 rational64s[n]! + 0xcd34 ForwardMatrix3 IFD0 rational64s[n]! + 0xcd35 IlluminantData1 IFD0 undef! + 0xcd36 IlluminantData2 IFD0 undef! + 0xcd37 IlluminantData3 IFD0 undef! + 0xcd38 MaskSubArea SubIFD no + 0xcd39 ProfileHueSatMapData3 IFD0 float[n]! + 0xcd3a ReductionMatrix3 IFD0 rational64s[n]! + 0xcd3b RGBTables IFD0 undef! 0xea1c Padding ExifIFD undef! 0xea1d OffsetSchema ExifIFD int32s! 0xfde8 OwnerName ExifIFD string/ @@ -1104,41 +1167,6 @@ IPTC group only in the standard location. ------ -------- -------- [no tags known] -=head2 DJI Tags - -This table lists tags found in the maker notes of images from some DJI -Phantom drones. - - Tag ID Tag Name Writable - ------ -------- -------- - 0x0001 Make string - 0x0003 SpeedX float - 0x0004 SpeedY float - 0x0005 SpeedZ float - 0x0006 Pitch float - 0x0007 Yaw float - 0x0008 Roll float - 0x0009 CameraPitch float - 0x000a CameraYaw float - 0x000b CameraRoll float - -=head3 DJI XMP Tags - -XMP tags used by DJI for images from drones. - -These tags belong to the ExifTool XMP-drone-dji family 1 group. - - Tag Name Writable - -------- -------- - AbsoluteAltitude real - FlightPitchDegree real - FlightRollDegree real - FlightYawDegree real - GimbalPitchDegree real - GimbalRollDegree real - GimbalYawDegree real - RelativeAltitude real - =head2 XMP Tags XMP stands for "Extensible Metadata Platform", an XML/RDF-based metadata @@ -1160,21 +1188,22 @@ C<integer> is a string of digits (possibly beginning with a '+' or '-'), C<real> is a floating point number, C<rational> is entered as a floating point number but stored as two C<integer> strings separated by a '/' character, C<date> is a date/time string entered in the format "YYYY:mm:dd -HH:MM:SS[.ss][+/-HH:MM]", C<boolean> is either "True" or "False", C<struct> -indicates a structured tag, and C<lang-alt> is a tag that supports alternate -languages. +HH:MM:SS[.ss][+/-HH:MM]", C<boolean> is either "True" or "False" (but "true" +and "false" may be written as a ValueConv value for compatibility with +non-conforming applications), C<struct> indicates a structured tag, and +C<lang-alt> is a tag that supports alternate languages. When reading, C<struct> tags are extracted only if the Struct (-struct) option is used. Otherwise the corresponding I<Flattened> tags, indicated by an underline (C<_>) after the B<Writable> type, are extracted. When copying, by default both structured and flattened tags are available, but -the flattened tags are considered "unsafe" so they they aren't copied unless +the flattened tags are considered "unsafe" so they aren't copied unless specified explicitly. The Struct option may be disabled by setting Struct to 0 via the API or with --struct on the command line to copy only flattened tags, or enabled by setting Struct to 1 via the API or with -struct on the command line to copy only as structures. When writing, the Struct option has no effect, and both structured and flattened tags may be written. See -L<http://owl.phy.queensu.ca/~phil/exiftool/struct.html> for more details. +L<https://exiftool.org/struct.html> for more details. Individual languages for C<lang-alt> tags are accessed by suffixing the tag name with a '-', followed by an RFC 3066 language code (eg. "XMP:Title-fr", @@ -1186,12 +1215,13 @@ to preserve other existing languages (eg. "XMP-dc:Description-x-default"). When reading, "x-default" is not specified. The XMP tags are organized according to schema B<Namespace> in the following -tables. In general, the ExifTool family 1 group names are derived from the -namespace prefixes by adding a leading "XMP-" (eg. "XMP-dc"), but a few of -the longer prefixes have been shortened for convenience (as mentioned in the -documentation below). The tags of any namespace may be deleted as a group -by specifying the family 1 group name (eg. "-XMP-dc:all=" on the command -line). This includes namespaces which are not pre-defined by ExifTool. +tables. The ExifTool family 1 group names are derived from the namespace +prefixes by adding a leading "XMP-" (eg. "XMP-dc"). A few of the longer +prefixes have been shortened (as mentioned in the documentation below) to +avoid excessively long ExifTool group names. The tags of any namespace may +be deleted as a group by specifying the family 1 group name (eg. +"-XMP-dc:all=" on the command line). This includes namespaces which are not +pre-defined by ExifTool. In cases where a tag name exists in more than one namespace, less common namespaces are avoided when writing. However, a specific namespace may be @@ -1204,7 +1234,7 @@ recommended if possible. For structures, the heading of the first column is B<Field Name>. Field names are very similar to tag names, except they are used to identify fields inside structures instead of stand-alone tags. See -L<http://owl.phy.queensu.ca/~phil/exiftool/struct.html#Fields> for more +L<https://exiftool.org/struct.html#Fields> for more details. ExifTool will extract XMP information even if it is not listed in these @@ -1225,12 +1255,15 @@ L<http://www.adobe.com/devnet/xmp/> for the official XMP specification. acdsee XMP acdsee album XMP Album apple-fi XMP apple_fi + ast Nikon ast aux XMP aux cc XMP cc cell XMP cell + crd XMP crd creatorAtom XMP creatorAtom crs XMP crs dc XMP dc + Device XMP Device dex XMP dex DICOM XMP DICOM digiKam XMP digiKam @@ -1242,6 +1275,8 @@ L<http://www.adobe.com/devnet/xmp/> for the official XMP specification. extensis XMP extensis fpv XMP fpv GAudio XMP GAudio + GCamera XMP GCamera + GCreations XMP GCreations GDepth XMP GDepth getty XMP GettyImages GFocus XMP GFocus @@ -1260,6 +1295,7 @@ L<http://www.adobe.com/devnet/xmp/> for the official XMP specification. mwg-coll MWG Collections mwg-kw MWG Keywords mwg-rs MWG Regions + nine Nikon nine pdf XMP pdf pdfx XMP pdfx photomech PhotoMechanic XMP @@ -1272,6 +1308,7 @@ L<http://www.adobe.com/devnet/xmp/> for the official XMP specification. prm XMP prm pur XMP pur rdf XMP rdf + sdc Nikon sdc swf XMP swf tiff XMP tiff x XMP x @@ -1404,6 +1441,7 @@ These tags belong to the ExifTool XMP-aux family 1 group. LensID string LensInfo string/ LensSerialNumber string/ + NeutralDensityFactor string OwnerName string/ SerialNumber string/ VignetteCorrectionAlreadyApplied boolean @@ -1445,6 +1483,1136 @@ These tags belong to the ExifTool XMP-cell family 1 group. MobileNetworkCode string CellR string +=head3 XMP crd Tags + +Adobe Camera Raw Defaults tags. + +These tags belong to the ExifTool XMP-crd family 1 group. + + Tag Name Writable + -------- -------- + AlreadyApplied boolean/ + AutoBrightness boolean/ + AutoContrast boolean/ + AutoExposure boolean/ + AutoLateralCA integer/ + AutoShadows boolean/ + AutoTone boolean/ + AutoToneDigest string/ + AutoToneDigestNoSat string/ + AutoWhiteVersion integer/ + Blacks2012 integer/ + BlueHue integer/ + BlueSaturation integer/ + Brightness integer/ + CameraModelRestriction string/ + CameraProfile string/ + CameraProfileDigest string/ + ChromaticAberrationB integer/ + ChromaticAberrationR integer/ + CircularGradientBasedCorrections Correction Struct+ + CircGradBasedCorrActive boolean/_ + CircGradBasedCorrAmount real/_ + CircGradBasedCorrMasks CorrectionMask Struct_+ + CircGradBasedCorrMaskAlpha real/_ + CircGradBasedCorrMaskAngle real/_ + CircGradBasedCorrMaskBottom real/_ + CircGradBasedCorrMaskCenterValue real/_ + CircGradBasedCorrMaskCenterWeight real/_ + CircGradBasedCorrMaskRange CorrRangeMask Struct_+ + CircGradBasedCorrMaskRangeAreaModels AreaModels Struct_+ + CircGradBasedCorrMaskRangeAreaModelsComponents string/_+ + CircGradBasedCorrMaskRangeAreaModelsColorSampleInfo string/_+ + CircGradBasedCorrMaskRangeColorAmount real/_+ + CircGradBasedCorrMaskRangeDepthFeather real/_+ + CircGradBasedCorrMaskRangeDepthMax real/_+ + CircGradBasedCorrMaskRangeDepthMin real/_+ + CircGradBasedCorrMaskRangeInvert boolean/_+ + CircGradBasedCorrMaskRangeLumFeather real/_+ + CircGradBasedCorrMaskRangeLuminanceDepthSampleInfo string/_+ + CircGradBasedCorrMaskRangeLumMax real/_+ + CircGradBasedCorrMaskRangeLumMin real/_+ + CircGradBasedCorrMaskRangeLumRange string/_+ + CircGradBasedCorrMaskRangeSampleType integer/_+ + CircGradBasedCorrMaskRangeType string/_+ + CircGradBasedCorrMaskRangeVersion string/_+ + CircGradBasedCorrMaskDabs string/_ + CircGradBasedCorrMaskFeather real/_ + CircGradBasedCorrMaskFlipped boolean/_ + CircGradBasedCorrMaskFlow real/_ + CircGradBasedCorrMaskFullX real/_ + CircGradBasedCorrMaskFullY real/_ + CircGradBasedCorrMaskInputDigest string/_ + CircGradBasedCorrMaskLeft real/_ + CircGradBasedCorrMaskMaskActive boolean/_ + CircGradBasedCorrMaskMaskBlendMode integer/_ + CircGradBasedCorrMaskMaskDigest string/_ + CircGradBasedCorrMaskMaskInverted boolean/_ + CircGradBasedCorrMaskMaskName string/_ + CircGradBasedCorrMaskMasks CorrectionMask Struct_+ + CircGradBasedCorrMaskMasksAlpha real/_ + CircGradBasedCorrMaskMasksAngle real/_ + CircGradBasedCorrMaskMasksBottom real/_ + CircGradBasedCorrMaskMasksCenterValue real/_ + CircGradBasedCorrMaskMasksCenterWeight real/_ + CircGradBasedCorrMaskMasksDabs string/_+ + CircGradBasedCorrMaskMasksFeather real/_ + CircGradBasedCorrMaskMasksFlipped boolean/_ + CircGradBasedCorrMaskMasksFlow real/_ + CircGradBasedCorrMaskMasksFullX real/_ + CircGradBasedCorrMaskMasksFullY real/_ + CircGradBasedCorrMaskMasksInputDigest string/_ + CircGradBasedCorrMaskMasksLeft real/_ + CircGradBasedCorrMaskMasksMaskActive boolean/_ + CircGradBasedCorrMaskMasksMaskBlendMode integer/_ + CircGradBasedCorrMaskMasksMaskDigest string/_ + CircGradBasedCorrMaskMasksMaskInverted boolean/_ + CircGradBasedCorrMaskMasksMaskName string/_ + CircGradBasedCorrMaskMasksMaskSubType string/_ + CircGradBasedCorrMaskMasksMaskSyncID string/_ + CircGradBasedCorrMaskMasksValue real/_ + CircGradBasedCorrMaskMasksMaskVersion string/_ + CircGradBasedCorrMaskMasksMidpoint real/_ + CircGradBasedCorrMaskMasksOrigin string/_ + CircGradBasedCorrMaskMasksPerimeterValue real/_ + CircGradBasedCorrMaskMasksRadius real/_ + CircGradBasedCorrMaskMasksReferencePoint string/_ + CircGradBasedCorrMaskMasksRight real/_ + CircGradBasedCorrMaskMasksRoundness real/_ + CircGradBasedCorrMaskMasksSizeX real/_ + CircGradBasedCorrMaskMasksSizeY real/_ + CircGradBasedCorrMaskMasksTop real/_ + CircGradBasedCorrMaskMaskSubType string/_ + CircGradBasedCorrMaskMasksVersion integer/_ + CircGradBasedCorrMaskMasksWhat string/_ + CircGradBasedCorrMaskMasksWholeImageArea string/_ + CircGradBasedCorrMaskMasksX real/_ + CircGradBasedCorrMaskMasksY real/_ + CircGradBasedCorrMaskMaskSyncID string/_ + CircGradBasedCorrMaskMasksZeroX real/_ + CircGradBasedCorrMaskMasksZeroY real/_ + CircGradBasedCorrMaskValue real/_ + CircGradBasedCorrMaskMaskVersion string/_ + CircGradBasedCorrMaskMidpoint real/_ + CircGradBasedCorrMaskOrigin string/_ + CircGradBasedCorrMaskPerimeterValue real/_ + CircGradBasedCorrMaskRadius real/_ + CircGradBasedCorrMaskReferencePoint string/_ + CircGradBasedCorrMaskRight real/_ + CircGradBasedCorrMaskRoundness real/_ + CircGradBasedCorrMaskSizeX real/_ + CircGradBasedCorrMaskSizeY real/_ + CircGradBasedCorrMaskTop real/_ + CircGradBasedCorrMaskVersion integer/_ + CircGradBasedCorrMaskWhat string/_ + CircGradBasedCorrMaskWholeImageArea string/_ + CircGradBasedCorrMaskX real/_ + CircGradBasedCorrMaskY real/_ + CircGradBasedCorrMaskZeroX real/_ + CircGradBasedCorrMaskZeroY real/_ + CircGradBasedCorrCorrectionName string/_+ + CircGradBasedCorrRangeMask CorrRangeMask Struct_+ + CircGradBasedCorrRangeMaskAreaModels AreaModels Struct_+ + CircGradBasedCorrRangeMaskAreaModelsComponents string/_+ + CircGradBasedCorrRangeMaskAreaModelsColorSampleInfo string/_+ + CircGradBasedCorrRangeMaskColorAmount real/_+ + CircGradBasedCorrRangeMaskDepthFeather real/_+ + CircGradBasedCorrRangeMaskDepthMax real/_+ + CircGradBasedCorrRangeMaskDepthMin real/_+ + CircGradBasedCorrRangeMaskInvert boolean/_+ + CircGradBasedCorrRangeMaskLumFeather real/_+ + CircGradBasedCorrRangeMaskLuminanceDepthSampleInfo string/_+ + CircGradBasedCorrRangeMaskLumMax real/_+ + CircGradBasedCorrRangeMaskLumMin real/_+ + CircGradBasedCorrRangeMaskLumRange string/_+ + CircGradBasedCorrRangeMaskSampleType integer/_+ + CircGradBasedCorrRangeMaskType string/_+ + CircGradBasedCorrRangeMaskVersion string/_+ + CircGradBasedCorrCorrectionSyncID string/_+ + CircGradBasedCorrBlacks2012 real/_ + CircGradBasedCorrBrightness real/_ + CircGradBasedCorrClarity real/_ + CircGradBasedCorrClarity2012 real/_ + CircGradBasedCorrContrast real/_ + CircGradBasedCorrContrast2012 real/_ + CircGradBasedCorrDefringe real/_ + CircGradBasedCorrDehaze real/_ + CircGradBasedCorrExposure real/_ + CircGradBasedCorrExposure2012 real/_ + CircGradBasedCorrHighlights2012 real/_ + CircGradBasedCorrHue real/_ + CircGradBasedCorrLuminanceNoise real/_ + CircGradBasedCorrMoire real/_ + CircGradBasedCorrSaturation real/_ + CircGradBasedCorrShadows2012 real/_ + CircGradBasedCorrSharpness real/_ + CircGradBasedCorrTemperature real/_ + CircGradBasedCorrTexture real/_ + CircGradBasedCorrTint real/_ + CircGradBasedCorrToningHue real/_ + CircGradBasedCorrToningSaturation real/_ + CircGradBasedCorrWhites2012 real/_ + CircGradBasedCorrWhat string/_ + Clarity integer/ + Clarity2012 integer/ + ClipboardAspectRatio integer/ + ClipboardOrientation integer/ + Cluster string/ + ColorGradeBlending integer/ + ColorGradeGlobalHue integer/ + ColorGradeGlobalLum integer/ + ColorGradeGlobalSat integer/ + ColorGradeHighlightLum integer/ + ColorGradeMidtoneHue integer/ + ColorGradeMidtoneLum integer/ + ColorGradeMidtoneSat integer/ + ColorGradeShadowLum integer/ + ColorNoiseReduction integer/ + ColorNoiseReductionDetail integer/ + ColorNoiseReductionSmoothness integer/ + CompatibleVersion string/ + ContactInfo string/ + Contrast integer/ + Contrast2012 integer/ + Converter string/ + ConvertToGrayscale boolean/ + Copyright string/ + CropAngle real/ + CropBottom real/ + CropConstrainToWarp integer/ + CropHeight real/ + CropLeft real/ + CropRight real/ + CropTop real/ + CropUnit integer/ + CropUnits integer/ + CropWidth real/ + DefaultAutoGray boolean/ + DefaultAutoTone boolean/ + DefaultsSpecificToISO boolean/ + DefaultsSpecificToSerial boolean/ + Defringe integer/ + DefringeGreenAmount integer/ + DefringeGreenHueHi integer/ + DefringeGreenHueLo integer/ + DefringePurpleAmount integer/ + DefringePurpleHueHi integer/ + DefringePurpleHueLo integer/ + Dehaze real/ + Description lang-alt/ + DNGIgnoreSidecars boolean/ + Exposure real/ + Exposure2012 real/ + FillLight integer/ + GradientBasedCorrections Correction Struct+ + GradientBasedCorrActive boolean/_ + GradientBasedCorrAmount real/_ + GradientBasedCorrMasks CorrectionMask Struct_+ + GradientBasedCorrMaskAlpha real/_ + GradientBasedCorrMaskAngle real/_ + GradientBasedCorrMaskBottom real/_ + GradientBasedCorrMaskCenterValue real/_ + GradientBasedCorrMaskCenterWeight real/_ + GradientBasedCorrMaskRange CorrRangeMask Struct_+ + GradientBasedCorrMaskRangeAreaModels AreaModels Struct_+ + GradientBasedCorrMaskRangeAreaModelsComponents string/_+ + GradientBasedCorrMaskRangeAreaModelsColorSampleInfo string/_+ + GradientBasedCorrMaskRangeColorAmount real/_+ + GradientBasedCorrMaskRangeDepthFeather real/_+ + GradientBasedCorrMaskRangeDepthMax real/_+ + GradientBasedCorrMaskRangeDepthMin real/_+ + GradientBasedCorrMaskRangeInvert boolean/_+ + GradientBasedCorrMaskRangeLumFeather real/_+ + GradientBasedCorrMaskRangeLuminanceDepthSampleInfo string/_+ + GradientBasedCorrMaskRangeLumMax real/_+ + GradientBasedCorrMaskRangeLumMin real/_+ + GradientBasedCorrMaskRangeLumRange string/_+ + GradientBasedCorrMaskRangeSampleType integer/_+ + GradientBasedCorrMaskRangeType string/_+ + GradientBasedCorrMaskRangeVersion string/_+ + GradientBasedCorrMaskDabs string/_ + GradientBasedCorrMaskFeather real/_ + GradientBasedCorrMaskFlipped boolean/_ + GradientBasedCorrMaskFlow real/_ + GradientBasedCorrMaskFullX real/_ + GradientBasedCorrMaskFullY real/_ + GradientBasedCorrMaskInputDigest string/_ + GradientBasedCorrMaskLeft real/_ + GradientBasedCorrMaskMaskActive boolean/_ + GradientBasedCorrMaskMaskBlendMode integer/_ + GradientBasedCorrMaskMaskDigest string/_ + GradientBasedCorrMaskMaskInverted boolean/_ + GradientBasedCorrMaskMaskName string/_ + GradientBasedCorrMaskMasks CorrectionMask Struct_+ + GradientBasedCorrMaskMasksAlpha real/_ + GradientBasedCorrMaskMasksAngle real/_ + GradientBasedCorrMaskMasksBottom real/_ + GradientBasedCorrMaskMasksCenterValue real/_ + GradientBasedCorrMaskMasksCenterWeight real/_ + GradientBasedCorrMaskMasksDabs string/_+ + GradientBasedCorrMaskMasksFeather real/_ + GradientBasedCorrMaskMasksFlipped boolean/_ + GradientBasedCorrMaskMasksFlow real/_ + GradientBasedCorrMaskMasksFullX real/_ + GradientBasedCorrMaskMasksFullY real/_ + GradientBasedCorrMaskMasksInputDigest string/_ + GradientBasedCorrMaskMasksLeft real/_ + GradientBasedCorrMaskMasksMaskActive boolean/_ + GradientBasedCorrMaskMasksMaskBlendMode integer/_ + GradientBasedCorrMaskMasksMaskDigest string/_ + GradientBasedCorrMaskMasksMaskInverted boolean/_ + GradientBasedCorrMaskMasksMaskName string/_ + GradientBasedCorrMaskMasksMaskSubType string/_ + GradientBasedCorrMaskMasksMaskSyncID string/_ + GradientBasedCorrMaskMasksValue real/_ + GradientBasedCorrMaskMasksMaskVersion string/_ + GradientBasedCorrMaskMasksMidpoint real/_ + GradientBasedCorrMaskMasksOrigin string/_ + GradientBasedCorrMaskMasksPerimeterValue real/_ + GradientBasedCorrMaskMasksRadius real/_ + GradientBasedCorrMaskMasksReferencePoint string/_ + GradientBasedCorrMaskMasksRight real/_ + GradientBasedCorrMaskMasksRoundness real/_ + GradientBasedCorrMaskMasksSizeX real/_ + GradientBasedCorrMaskMasksSizeY real/_ + GradientBasedCorrMaskMasksTop real/_ + GradientBasedCorrMaskMaskSubType string/_ + GradientBasedCorrMaskMasksVersion integer/_ + GradientBasedCorrMaskMasksWhat string/_ + GradientBasedCorrMaskMasksWholeImageArea string/_ + GradientBasedCorrMaskMasksX real/_ + GradientBasedCorrMaskMasksY real/_ + GradientBasedCorrMaskMaskSyncID string/_ + GradientBasedCorrMaskMasksZeroX real/_ + GradientBasedCorrMaskMasksZeroY real/_ + GradientBasedCorrMaskValue real/_ + GradientBasedCorrMaskMaskVersion string/_ + GradientBasedCorrMaskMidpoint real/_ + GradientBasedCorrMaskOrigin string/_ + GradientBasedCorrMaskPerimeterValue real/_ + GradientBasedCorrMaskRadius real/_ + GradientBasedCorrMaskReferencePoint string/_ + GradientBasedCorrMaskRight real/_ + GradientBasedCorrMaskRoundness real/_ + GradientBasedCorrMaskSizeX real/_ + GradientBasedCorrMaskSizeY real/_ + GradientBasedCorrMaskTop real/_ + GradientBasedCorrMaskVersion integer/_ + GradientBasedCorrMaskWhat string/_ + GradientBasedCorrMaskWholeImageArea string/_ + GradientBasedCorrMaskX real/_ + GradientBasedCorrMaskY real/_ + GradientBasedCorrMaskZeroX real/_ + GradientBasedCorrMaskZeroY real/_ + GradientBasedCorrCorrectionName string/_+ + GradientBasedCorrRangeMask CorrRangeMask Struct_+ + GradientBasedCorrRangeMaskAreaModels AreaModels Struct_+ + GradientBasedCorrRangeMaskAreaModelsComponents string/_+ + GradientBasedCorrRangeMaskAreaModelsColorSampleInfo string/_+ + GradientBasedCorrRangeMaskColorAmount real/_+ + GradientBasedCorrRangeMaskDepthFeather real/_+ + GradientBasedCorrRangeMaskDepthMax real/_+ + GradientBasedCorrRangeMaskDepthMin real/_+ + GradientBasedCorrRangeMaskInvert boolean/_+ + GradientBasedCorrRangeMaskLumFeather real/_+ + GradientBasedCorrRangeMaskLuminanceDepthSampleInfo string/_+ + GradientBasedCorrRangeMaskLumMax real/_+ + GradientBasedCorrRangeMaskLumMin real/_+ + GradientBasedCorrRangeMaskLumRange string/_+ + GradientBasedCorrRangeMaskSampleType integer/_+ + GradientBasedCorrRangeMaskType string/_+ + GradientBasedCorrRangeMaskVersion string/_+ + GradientBasedCorrCorrectionSyncID string/_+ + GradientBasedCorrBlacks2012 real/_ + GradientBasedCorrBrightness real/_ + GradientBasedCorrClarity real/_ + GradientBasedCorrClarity2012 real/_ + GradientBasedCorrContrast real/_ + GradientBasedCorrContrast2012 real/_ + GradientBasedCorrDefringe real/_ + GradientBasedCorrDehaze real/_ + GradientBasedCorrExposure real/_ + GradientBasedCorrExposure2012 real/_ + GradientBasedCorrHighlights2012 real/_ + GradientBasedCorrHue real/_ + GradientBasedCorrLuminanceNoise real/_ + GradientBasedCorrMoire real/_ + GradientBasedCorrSaturation real/_ + GradientBasedCorrShadows2012 real/_ + GradientBasedCorrSharpness real/_ + GradientBasedCorrTemperature real/_ + GradientBasedCorrTexture real/_ + GradientBasedCorrTint real/_ + GradientBasedCorrToningHue real/_ + GradientBasedCorrToningSaturation real/_ + GradientBasedCorrWhites2012 real/_ + GradientBasedCorrWhat string/_ + GrainAmount integer/ + GrainFrequency integer/ + GrainSeed integer/ + GrainSize integer/ + GrayMixerAqua integer/ + GrayMixerBlue integer/ + GrayMixerGreen integer/ + GrayMixerMagenta integer/ + GrayMixerOrange integer/ + GrayMixerPurple integer/ + GrayMixerRed integer/ + GrayMixerYellow integer/ + GreenHue integer/ + GreenSaturation integer/ + Group lang-alt/ + HasCrop boolean/ + HasSettings boolean/ + Highlight2012 integer/ + HighlightRecovery integer/ + Highlights2012 integer/ + HueAdjustmentAqua integer/ + HueAdjustmentBlue integer/ + HueAdjustmentGreen integer/ + HueAdjustmentMagenta integer/ + HueAdjustmentOrange integer/ + HueAdjustmentPurple integer/ + HueAdjustmentRed integer/ + HueAdjustmentYellow integer/ + IncrementalTemperature integer/ + IncrementalTint integer/ + JPEGHandling string/ + LensManualDistortionAmount integer/ + LensProfileChromaticAberrationScale integer/ + LensProfileDigest string/ + LensProfileDistortionScale integer/ + LensProfileEnable integer/ + LensProfileFilename string/ + LensProfileIsEmbedded boolean/ + LensProfileMatchKeyCameraModelName string/ + LensProfileMatchKeyExifMake string/ + LensProfileMatchKeyExifModel string/ + LensProfileMatchKeyIsRaw boolean/ + LensProfileMatchKeyLensID string/ + LensProfileMatchKeyLensInfo string/ + LensProfileMatchKeyLensName string/ + LensProfileMatchKeySensorFormatFactor real/ + LensProfileName string/ + LensProfileSetup string/ + LensProfileVignettingScale integer/ + Look Look Struct + LookAmount string/_ + LookCluster string/_ + LookCopyright string/_ + LookGroup lang-alt/_ + LookName string/ + LookParameters LookParms Struct_ + LookParametersCameraProfile string/_ + LookParametersClarity2012 string/_ + LookParametersConvertToGrayscale string/_ + LookParametersLookTable string/_ + LookParametersProcessVersion string/_ + LookParametersToneCurvePV2012 string/_+ + LookParametersToneCurvePV2012Blue string/_+ + LookParametersToneCurvePV2012Green string/_+ + LookParametersToneCurvePV2012Red string/_+ + LookParametersVersion string/_ + LookSupportsAmount string/_ + LookSupportsMonochrome string/_ + LookSupportsOutputReferred string/_ + LookUUID string/_ + LuminanceAdjustmentAqua integer/ + LuminanceAdjustmentBlue integer/ + LuminanceAdjustmentGreen integer/ + LuminanceAdjustmentMagenta integer/ + LuminanceAdjustmentOrange integer/ + LuminanceAdjustmentPurple integer/ + LuminanceAdjustmentRed integer/ + LuminanceAdjustmentYellow integer/ + LuminanceNoiseReductionContrast integer/ + LuminanceNoiseReductionDetail integer/ + LuminanceSmoothing integer/ + MaskGroupBasedCorrections Correction Struct+ + MaskGroupBasedCorrActive boolean/_ + MaskGroupBasedCorrAmount real/_ + MaskGroupBasedCorrMask CorrectionMask Struct_+ + MaskGroupBasedCorrMaskAlpha real/_ + MaskGroupBasedCorrMaskAngle real/_ + MaskGroupBasedCorrMaskBottom real/_ + MaskGroupBasedCorrMaskCenterValue real/_ + MaskGroupBasedCorrMaskCenterWeight real/_ + MaskGroupBasedCorrMaskRange CorrRangeMask Struct_+ + MaskGroupBasedCorrMaskRangeAreaModels AreaModels Struct_+ + MaskGroupBasedCorrMaskRangeAreaModelsComponents string/_+ + MaskGroupBasedCorrMaskRangeAreaModelsColorSampleInfo string/_+ + MaskGroupBasedCorrMaskRangeColorAmount real/_+ + MaskGroupBasedCorrMaskRangeDepthFeather real/_+ + MaskGroupBasedCorrMaskRangeDepthMax real/_+ + MaskGroupBasedCorrMaskRangeDepthMin real/_+ + MaskGroupBasedCorrMaskRangeInvert boolean/_+ + MaskGroupBasedCorrMaskRangeLumFeather real/_+ + MaskGroupBasedCorrMaskRangeLuminanceDepthSampleInfo string/_+ + MaskGroupBasedCorrMaskRangeLumMax real/_+ + MaskGroupBasedCorrMaskRangeLumMin real/_+ + MaskGroupBasedCorrMaskRangeLumRange string/_+ + MaskGroupBasedCorrMaskRangeSampleType integer/_+ + MaskGroupBasedCorrMaskRangeType string/_+ + MaskGroupBasedCorrMaskRangeVersion string/_+ + MaskGroupBasedCorrMaskDabs string/_+ + MaskGroupBasedCorrMaskFeather real/_ + MaskGroupBasedCorrMaskFlipped boolean/_ + MaskGroupBasedCorrMaskFlow real/_ + MaskGroupBasedCorrMaskFullX real/_ + MaskGroupBasedCorrMaskFullY real/_ + MaskGroupBasedCorrMaskInputDigest string/_ + MaskGroupBasedCorrMaskLeft real/_ + MaskGroupBasedCorrMaskMaskActive boolean/_ + MaskGroupBasedCorrMaskMaskBlendMode integer/_ + MaskGroupBasedCorrMaskMaskDigest string/_ + MaskGroupBasedCorrMaskMaskInverted boolean/_ + MaskGroupBasedCorrMaskMaskName string/_ + MaskGroupBasedCorrMaskMasks CorrectionMask Struct_+ + MaskGroupBasedCorrMaskMasksAlpha real/_ + MaskGroupBasedCorrMaskMasksAngle real/_ + MaskGroupBasedCorrMaskMasksBottom real/_ + MaskGroupBasedCorrMaskMasksCenterValue real/_ + MaskGroupBasedCorrMaskMasksCenterWeight real/_ + MaskGroupBasedCorrMaskMasksDabs string/_+ + MaskGroupBasedCorrMaskMasksFeather real/_ + MaskGroupBasedCorrMaskMasksFlipped boolean/_ + MaskGroupBasedCorrMaskMasksFlow real/_ + MaskGroupBasedCorrMaskMasksFullX real/_ + MaskGroupBasedCorrMaskMasksFullY real/_ + MaskGroupBasedCorrMaskMasksInputDigest string/_ + MaskGroupBasedCorrMaskMasksLeft real/_ + MaskGroupBasedCorrMaskMasksMaskActive boolean/_ + MaskGroupBasedCorrMaskMasksMaskBlendMode integer/_ + MaskGroupBasedCorrMaskMasksMaskDigest string/_ + MaskGroupBasedCorrMaskMasksMaskInverted boolean/_ + MaskGroupBasedCorrMaskMasksMaskName string/_ + MaskGroupBasedCorrMaskMasksMaskSubType string/_ + MaskGroupBasedCorrMaskMasksMaskSyncID string/_ + MaskGroupBasedCorrMaskMasksValue real/_ + MaskGroupBasedCorrMaskMasksMaskVersion string/_ + MaskGroupBasedCorrMaskMasksMidpoint real/_ + MaskGroupBasedCorrMaskMasksOrigin string/_ + MaskGroupBasedCorrMaskMasksPerimeterValue real/_ + MaskGroupBasedCorrMaskMasksRadius real/_ + MaskGroupBasedCorrMaskMasksReferencePoint string/_ + MaskGroupBasedCorrMaskMasksRight real/_ + MaskGroupBasedCorrMaskMasksRoundness real/_ + MaskGroupBasedCorrMaskMasksSizeX real/_ + MaskGroupBasedCorrMaskMasksSizeY real/_ + MaskGroupBasedCorrMaskMasksTop real/_ + MaskGroupBasedCorrMaskMaskSubType string/_ + MaskGroupBasedCorrMaskMasksVersion integer/_ + MaskGroupBasedCorrMaskMasksWhat string/_ + MaskGroupBasedCorrMaskMasksWholeImageArea string/_ + MaskGroupBasedCorrMaskMasksX real/_ + MaskGroupBasedCorrMaskMasksY real/_ + MaskGroupBasedCorrMaskMaskSyncID string/_ + MaskGroupBasedCorrMaskMasksZeroX real/_ + MaskGroupBasedCorrMaskMasksZeroY real/_ + MaskGroupBasedCorrMaskValue real/_ + MaskGroupBasedCorrMaskMaskVersion string/_ + MaskGroupBasedCorrMaskMidpoint real/_ + MaskGroupBasedCorrMaskOrigin string/_ + MaskGroupBasedCorrMaskPerimeterValue real/_ + MaskGroupBasedCorrMaskRadius real/_ + MaskGroupBasedCorrMaskReferencePoint string/_ + MaskGroupBasedCorrMaskRight real/_ + MaskGroupBasedCorrMaskRoundness real/_ + MaskGroupBasedCorrMaskSizeX real/_ + MaskGroupBasedCorrMaskSizeY real/_ + MaskGroupBasedCorrMaskTop real/_ + MaskGroupBasedCorrMaskVersion integer/_ + MaskGroupBasedCorrMaskWhat string/_ + MaskGroupBasedCorrMaskWholeImageArea string/_ + MaskGroupBasedCorrMaskX real/_ + MaskGroupBasedCorrMaskY real/_ + MaskGroupBasedCorrMaskZeroX real/_ + MaskGroupBasedCorrMaskZeroY real/_ + MaskGroupBasedCorrCorrectionName string/_+ + MaskGroupBasedCorrRangeMask CorrRangeMask Struct_+ + MaskGroupBasedCorrRangeMaskAreaModels AreaModels Struct_+ + MaskGroupBasedCorrRangeMaskAreaModelsComponents string/_+ + MaskGroupBasedCorrRangeMaskAreaModelsColorSampleInfo string/_+ + MaskGroupBasedCorrRangeMaskColorAmount real/_+ + MaskGroupBasedCorrRangeMaskDepthFeather real/_+ + MaskGroupBasedCorrRangeMaskDepthMax real/_+ + MaskGroupBasedCorrRangeMaskDepthMin real/_+ + MaskGroupBasedCorrRangeMaskInvert boolean/_+ + MaskGroupBasedCorrRangeMaskLumFeather real/_+ + MaskGroupBasedCorrRangeMaskLuminanceDepthSampleInfo string/_+ + MaskGroupBasedCorrRangeMaskLumMax real/_+ + MaskGroupBasedCorrRangeMaskLumMin real/_+ + MaskGroupBasedCorrRangeMaskLumRange string/_+ + MaskGroupBasedCorrRangeMaskSampleType integer/_+ + MaskGroupBasedCorrRangeMaskType string/_+ + MaskGroupBasedCorrRangeMaskVersion string/_+ + MaskGroupBasedCorrCorrectionSyncID string/_+ + MaskGroupBasedCorrBlacks2012 real/_ + MaskGroupBasedCorrBrightness real/_ + MaskGroupBasedCorrClarity real/_ + MaskGroupBasedCorrClarity2012 real/_ + MaskGroupBasedCorrContrast real/_ + MaskGroupBasedCorrContrast2012 real/_ + MaskGroupBasedCorrDefringe real/_ + MaskGroupBasedCorrDehaze real/_ + MaskGroupBasedCorrExposure real/_ + MaskGroupBasedCorrExposure2012 real/_ + MaskGroupBasedCorrHighlights2012 real/_ + MaskGroupBasedCorrHue real/_ + MaskGroupBasedCorrLuminanceNoise real/_ + MaskGroupBasedCorrMoire real/_ + MaskGroupBasedCorrSaturation real/_ + MaskGroupBasedCorrShadows2012 real/_ + MaskGroupBasedCorrSharpness real/_ + MaskGroupBasedCorrTemperature real/_ + MaskGroupBasedCorrTexture real/_ + MaskGroupBasedCorrTint real/_ + MaskGroupBasedCorrToningHue real/_ + MaskGroupBasedCorrToningSaturation real/_ + MaskGroupBasedCorrWhites2012 real/_ + MaskGroupBasedCorrWhat string/_ + MoireFilter string/ + Name lang-alt/ + NegativeCacheLargePreviewSize integer/ + NegativeCacheMaximumSize real/ + NegativeCachePath string/ + OverrideLookVignette boolean/ + PaintBasedCorrections Correction Struct+ + PaintCorrectionActive boolean/_ + PaintCorrectionAmount real/_ + PaintBasedCorrectionMasks CorrectionMask Struct_+ + PaintCorrectionMaskAlpha real/_ + PaintCorrectionMaskAngle real/_ + PaintCorrectionMaskBottom real/_ + PaintCorrectionMaskCenterValue real/_ + PaintCorrectionMaskCenterWeight real/_ + PaintCorrectionMaskRange CorrRangeMask Struct_+ + PaintCorrectionMaskRangeAreaModels AreaModels Struct_+ + PaintCorrectionMaskRangeAreaModelsComponents string/_+ + PaintCorrectionMaskRangeAreaModelsColorSampleInfo string/_+ + PaintCorrectionMaskRangeColorAmount real/_+ + PaintCorrectionMaskRangeDepthFeather real/_+ + PaintCorrectionMaskRangeDepthMax real/_+ + PaintCorrectionMaskRangeDepthMin real/_+ + PaintCorrectionMaskRangeInvert boolean/_+ + PaintCorrectionMaskRangeLumFeather real/_+ + PaintCorrectionMaskRangeLuminanceDepthSampleInfo string/_+ + PaintCorrectionMaskRangeLumMax real/_+ + PaintCorrectionMaskRangeLumMin real/_+ + PaintCorrectionMaskRangeLumRange string/_+ + PaintCorrectionMaskRangeSampleType integer/_+ + PaintCorrectionMaskRangeType string/_+ + PaintCorrectionMaskRangeVersion string/_+ + PaintCorrectionMaskDabs string/_ + PaintCorrectionMaskFeather real/_ + PaintCorrectionMaskFlipped boolean/_ + PaintCorrectionMaskFlow real/_ + PaintCorrectionMaskFullX real/_ + PaintCorrectionMaskFullY real/_ + PaintCorrectionMaskInputDigest string/_ + PaintCorrectionMaskLeft real/_ + PaintCorrectionMaskMaskActive boolean/_ + PaintCorrectionMaskMaskBlendMode integer/_ + PaintCorrectionMaskMaskDigest string/_ + PaintCorrectionMaskMaskInverted boolean/_ + PaintCorrectionMaskMaskName string/_ + PaintCorrectionMaskMasks CorrectionMask Struct_+ + PaintCorrectionMaskMasksAlpha real/_ + PaintCorrectionMaskMasksAngle real/_ + PaintCorrectionMaskMasksBottom real/_ + PaintCorrectionMaskMasksCenterValue real/_ + PaintCorrectionMaskMasksCenterWeight real/_ + PaintCorrectionMaskMasksDabs string/_+ + PaintCorrectionMaskMasksFeather real/_ + PaintCorrectionMaskMasksFlipped boolean/_ + PaintCorrectionMaskMasksFlow real/_ + PaintCorrectionMaskMasksFullX real/_ + PaintCorrectionMaskMasksFullY real/_ + PaintCorrectionMaskMasksInputDigest string/_ + PaintCorrectionMaskMasksLeft real/_ + PaintCorrectionMaskMasksMaskActive boolean/_ + PaintCorrectionMaskMasksMaskBlendMode integer/_ + PaintCorrectionMaskMasksMaskDigest string/_ + PaintCorrectionMaskMasksMaskInverted boolean/_ + PaintCorrectionMaskMasksMaskName string/_ + PaintCorrectionMaskMasksMaskSubType string/_ + PaintCorrectionMaskMasksMaskSyncID string/_ + PaintCorrectionMaskMasksValue real/_ + PaintCorrectionMaskMasksMaskVersion string/_ + PaintCorrectionMaskMasksMidpoint real/_ + PaintCorrectionMaskMasksOrigin string/_ + PaintCorrectionMaskMasksPerimeterValue real/_ + PaintCorrectionMaskMasksRadius real/_ + PaintCorrectionMaskMasksReferencePoint string/_ + PaintCorrectionMaskMasksRight real/_ + PaintCorrectionMaskMasksRoundness real/_ + PaintCorrectionMaskMasksSizeX real/_ + PaintCorrectionMaskMasksSizeY real/_ + PaintCorrectionMaskMasksTop real/_ + PaintCorrectionMaskMaskSubType string/_ + PaintCorrectionMaskMasksVersion integer/_ + PaintCorrectionMaskMasksWhat string/_ + PaintCorrectionMaskMasksWholeImageArea string/_ + PaintCorrectionMaskMasksX real/_ + PaintCorrectionMaskMasksY real/_ + PaintCorrectionMaskMaskSyncID string/_ + PaintCorrectionMaskMasksZeroX real/_ + PaintCorrectionMaskMasksZeroY real/_ + PaintCorrectionMaskValue real/_ + PaintCorrectionMaskMaskVersion string/_ + PaintCorrectionMaskMidpoint real/_ + PaintCorrectionMaskOrigin string/_ + PaintCorrectionMaskPerimeterValue real/_ + PaintCorrectionMaskRadius real/_ + PaintCorrectionMaskReferencePoint string/_ + PaintCorrectionMaskRight real/_ + PaintCorrectionMaskRoundness real/_ + PaintCorrectionMaskSizeX real/_ + PaintCorrectionMaskSizeY real/_ + PaintCorrectionMaskTop real/_ + PaintCorrectionMaskVersion integer/_ + PaintCorrectionMaskWhat string/_ + PaintCorrectionMaskWholeImageArea string/_ + PaintCorrectionMaskX real/_ + PaintCorrectionMaskY real/_ + PaintCorrectionMaskZeroX real/_ + PaintCorrectionMaskZeroY real/_ + PaintCorrectionCorrectionName string/_+ + PaintCorrectionRangeMask CorrRangeMask Struct_+ + PaintCorrectionRangeMaskAreaModels AreaModels Struct_+ + PaintCorrectionRangeMaskAreaModelsComponents string/_+ + PaintCorrectionRangeMaskAreaModelsColorSampleInfo string/_+ + PaintCorrectionRangeMaskColorAmount real/_+ + PaintCorrectionRangeMaskDepthFeather real/_+ + PaintCorrectionRangeMaskDepthMax real/_+ + PaintCorrectionRangeMaskDepthMin real/_+ + PaintCorrectionRangeMaskInvert boolean/_+ + PaintCorrectionRangeMaskLumFeather real/_+ + PaintCorrectionRangeMaskLuminanceDepthSampleInfo string/_+ + PaintCorrectionRangeMaskLumMax real/_+ + PaintCorrectionRangeMaskLumMin real/_+ + PaintCorrectionRangeMaskLumRange string/_+ + PaintCorrectionRangeMaskSampleType integer/_+ + PaintCorrectionRangeMaskType string/_+ + PaintCorrectionRangeMaskVersion string/_+ + PaintCorrectionCorrectionSyncID string/_+ + PaintCorrectionBlacks2012 real/_ + PaintCorrectionBrightness real/_ + PaintCorrectionClarity real/_ + PaintCorrectionClarity2012 real/_ + PaintCorrectionContrast real/_ + PaintCorrectionContrast2012 real/_ + PaintCorrectionDefringe real/_ + PaintCorrectionDehaze real/_ + PaintCorrectionExposure real/_ + PaintCorrectionExposure2012 real/_ + PaintCorrectionHighlights2012 real/_ + PaintCorrectionHue real/_ + PaintCorrectionLuminanceNoise real/_ + PaintCorrectionMoire real/_ + PaintCorrectionSaturation real/_ + PaintCorrectionShadows2012 real/_ + PaintCorrectionSharpness real/_ + PaintCorrectionTemperature real/_ + PaintCorrectionTexture real/_ + PaintCorrectionTint real/_ + PaintCorrectionToningHue real/_ + PaintCorrectionToningSaturation real/_ + PaintCorrectionWhites2012 real/_ + PaintCorrectionWhat string/_ + ParametricDarks integer/ + ParametricHighlights integer/ + ParametricHighlightSplit integer/ + ParametricLights integer/ + ParametricMidtoneSplit integer/ + ParametricShadows integer/ + ParametricShadowSplit integer/ + PerspectiveAspect integer/ + PerspectiveHorizontal integer/ + PerspectiveRotate real/ + PerspectiveScale integer/ + PerspectiveUpright integer/ + PerspectiveVertical integer/ + PerspectiveX real/ + PerspectiveY real/ + PostCropVignetteAmount integer/ + PostCropVignetteFeather integer/ + PostCropVignetteHighlightContrast integer/ + PostCropVignetteMidpoint integer/ + PostCropVignetteRoundness integer/ + PostCropVignetteStyle integer/ + PresetType string/ + ProcessVersion string/ + RangeMask RangeMask Struct + RangeMaskMapInfo MapInfo Struct_ + RangeMaskMapInfoLabMax string/_ + RangeMaskMapInfoLabMin string/_ + RangeMaskMapInfoLumEq string/_+ + RangeMaskMapInfoRGBMax string/_ + RangeMaskMapInfoRGBMin string/_ + RawFileName string/ + RedEyeInfo string/+ + RedHue integer/ + RedSaturation integer/ + RetouchAreas RetouchArea Struct+ + RetouchAreaFeather real/_ + RetouchAreaMasks CorrectionMask Struct_+ + RetouchAreaMaskAlpha real/_ + RetouchAreaMaskAngle real/_ + RetouchAreaMaskBottom real/_ + RetouchAreaMaskCenterValue real/_ + RetouchAreaMaskCenterWeight real/_ + RetouchAreaMaskRange CorrRangeMask Struct_+ + RetouchAreaMaskRangeAreaModels AreaModels Struct_+ + RetouchAreaMaskRangeAreaModelsComponents string/_+ + RetouchAreaMaskRangeAreaModelsColorSampleInfo string/_+ + RetouchAreaMaskRangeColorAmount real/_+ + RetouchAreaMaskRangeDepthFeather real/_+ + RetouchAreaMaskRangeDepthMax real/_+ + RetouchAreaMaskRangeDepthMin real/_+ + RetouchAreaMaskRangeInvert boolean/_+ + RetouchAreaMaskRangeLumFeather real/_+ + RetouchAreaMaskRangeLuminanceDepthSampleInfo string/_+ + RetouchAreaMaskRangeLumMax real/_+ + RetouchAreaMaskRangeLumMin real/_+ + RetouchAreaMaskRangeLumRange string/_+ + RetouchAreaMaskRangeSampleType integer/_+ + RetouchAreaMaskRangeType string/_+ + RetouchAreaMaskRangeVersion string/_+ + RetouchAreaMaskDabs string/_ + RetouchAreaMaskFeather real/_ + RetouchAreaMaskFlipped boolean/_ + RetouchAreaMaskFlow real/_ + RetouchAreaMaskFullX real/_ + RetouchAreaMaskFullY real/_ + RetouchAreaMaskInputDigest string/_ + RetouchAreaMaskLeft real/_ + RetouchAreaMaskMaskActive boolean/_ + RetouchAreaMaskMaskBlendMode integer/_ + RetouchAreaMaskMaskDigest string/_ + RetouchAreaMaskMaskInverted boolean/_ + RetouchAreaMaskMaskName string/_ + RetouchAreaMaskMasks CorrectionMask Struct_+ + RetouchAreaMaskMasksAlpha real/_ + RetouchAreaMaskMasksAngle real/_ + RetouchAreaMaskMasksBottom real/_ + RetouchAreaMaskMasksCenterValue real/_ + RetouchAreaMaskMasksCenterWeight real/_ + RetouchAreaMaskMasksDabs string/_+ + RetouchAreaMaskMasksFeather real/_ + RetouchAreaMaskMasksFlipped boolean/_ + RetouchAreaMaskMasksFlow real/_ + RetouchAreaMaskMasksFullX real/_ + RetouchAreaMaskMasksFullY real/_ + RetouchAreaMaskMasksInputDigest string/_ + RetouchAreaMaskMasksLeft real/_ + RetouchAreaMaskMasksMaskActive boolean/_ + RetouchAreaMaskMasksMaskBlendMode integer/_ + RetouchAreaMaskMasksMaskDigest string/_ + RetouchAreaMaskMasksMaskInverted boolean/_ + RetouchAreaMaskMasksMaskName string/_ + RetouchAreaMaskMasksMaskSubType string/_ + RetouchAreaMaskMasksMaskSyncID string/_ + RetouchAreaMaskMasksValue real/_ + RetouchAreaMaskMasksMaskVersion string/_ + RetouchAreaMaskMasksMidpoint real/_ + RetouchAreaMaskMasksOrigin string/_ + RetouchAreaMaskMasksPerimeterValue real/_ + RetouchAreaMaskMasksRadius real/_ + RetouchAreaMaskMasksReferencePoint string/_ + RetouchAreaMaskMasksRight real/_ + RetouchAreaMaskMasksRoundness real/_ + RetouchAreaMaskMasksSizeX real/_ + RetouchAreaMaskMasksSizeY real/_ + RetouchAreaMaskMasksTop real/_ + RetouchAreaMaskMaskSubType string/_ + RetouchAreaMaskMasksVersion integer/_ + RetouchAreaMaskMasksWhat string/_ + RetouchAreaMaskMasksWholeImageArea string/_ + RetouchAreaMaskMasksX real/_ + RetouchAreaMaskMasksY real/_ + RetouchAreaMaskMaskSyncID string/_ + RetouchAreaMaskMasksZeroX real/_ + RetouchAreaMaskMasksZeroY real/_ + RetouchAreaMaskValue real/_ + RetouchAreaMaskMaskVersion string/_ + RetouchAreaMaskMidpoint real/_ + RetouchAreaMaskOrigin string/_ + RetouchAreaMaskPerimeterValue real/_ + RetouchAreaMaskRadius real/_ + RetouchAreaMaskReferencePoint string/_ + RetouchAreaMaskRight real/_ + RetouchAreaMaskRoundness real/_ + RetouchAreaMaskSizeX real/_ + RetouchAreaMaskSizeY real/_ + RetouchAreaMaskTop real/_ + RetouchAreaMaskVersion integer/_ + RetouchAreaMaskWhat string/_ + RetouchAreaMaskWholeImageArea string/_ + RetouchAreaMaskX real/_ + RetouchAreaMaskY real/_ + RetouchAreaMaskZeroX real/_ + RetouchAreaMaskZeroY real/_ + RetouchAreaMethod string/_ + RetouchAreaOffsetY real/_ + RetouchAreaOpacity real/_ + RetouchAreaSeed integer/_ + RetouchAreaSourceState string/_ + RetouchAreaSourceX real/_ + RetouchAreaSpotType string/_ + RetouchInfo string/+ + Saturation integer/ + SaturationAdjustmentAqua integer/ + SaturationAdjustmentBlue integer/ + SaturationAdjustmentGreen integer/ + SaturationAdjustmentMagenta integer/ + SaturationAdjustmentOrange integer/ + SaturationAdjustmentPurple integer/ + SaturationAdjustmentRed integer/ + SaturationAdjustmentYellow integer/ + Shadows integer/ + Shadows2012 integer/ + ShadowTint integer/ + SharpenDetail integer/ + SharpenEdgeMasking integer/ + SharpenRadius real/ + Sharpness integer/ + ShortName lang-alt/ + Smoothness integer/ + SortName lang-alt/ + SplitToningBalance integer/ + SplitToningHighlightHue integer/ + SplitToningHighlightSaturation integer/ + SplitToningShadowHue integer/ + SplitToningShadowSaturation integer/ + SupportsAmount boolean/ + SupportsColor boolean/ + SupportsHighDynamicRange boolean/ + SupportsMonochrome boolean/ + SupportsNormalDynamicRange boolean/ + SupportsOutputReferred boolean/ + SupportsSceneReferred boolean/ + ColorTemperature integer/ + Texture integer/ + TIFFHandling string/ + Tint integer/ + ToggleStyleAmount integer/ + ToggleStyleDigest string/ + ToneCurve string/+ + ToneCurveBlue string/+ + ToneCurveGreen string/+ + ToneCurveName string/ + ToneCurveName2012 string/ + ToneCurvePV2012 string/+ + ToneCurvePV2012Blue string/+ + ToneCurvePV2012Green string/+ + ToneCurvePV2012Red string/+ + ToneCurveRed string/+ + ToneMapStrength real/ + UprightCenterMode integer/ + UprightCenterNormX real/ + UprightCenterNormY real/ + UprightDependentDigest string/ + UprightFocalLength35mm real/ + UprightFocalMode integer/ + UprightFourSegmentsCount integer/ + UprightPreview boolean/ + UprightTransform_0 string/ + UprightTransform_1 string/ + UprightTransform_2 string/ + UprightTransform_3 string/ + UprightTransform_4 string/ + UprightTransform_5 string/ + UprightTransformCount integer/ + UprightVersion integer/ + UUID string/ + Version string/ + Vibrance integer/ + VignetteAmount integer/ + VignetteMidpoint integer/ + What string/ + WhiteBalance string/ + Whites2012 integer/ + +=head3 XMP Correction Struct + + Field Name Writable + ---------- -------- + CorrectionActive boolean + CorrectionAmount real + CorrectionMasks CorrectionMask Struct+ + CorrectionName string + CorrRangeMask CorrRangeMask Struct + - + CorrectionSyncID string + LocalBlacks2012 real + LocalBrightness real + LocalClarity real + LocalClarity2012 real + LocalContrast real + LocalContrast2012 real + LocalDefringe real + LocalDehaze real + LocalExposure real + LocalExposure2012 real + LocalHighlights2012 real + LocalHue real + LocalLuminanceNoise real + LocalMoire real + LocalSaturation real + LocalShadows2012 real + LocalSharpness real + LocalTemperature real + LocalTexture real + LocalTint real + LocalToningHue real + LocalToningSaturation real + LocalWhites2012 real + What string + +=head3 XMP CorrectionMask Struct + + Field Name Writable + ---------- -------- + Alpha real + Angle real + Bottom real + CenterValue real + CenterWeight real + CorrRangeMask CorrRangeMask Struct + - + Dabs string+ + Feather real + Flipped boolean + Flow real + FullX real + FullY real + InputDigest string + Left real + MaskActive boolean + MaskBlendMode integer + MaskDigest string + MaskInverted boolean + MaskName string + MaskSubType string + MaskSyncID string + MaskValue real + MaskVersion string + Masks CorrectionMask Struct + Midpoint real + Origin string + PerimeterValue real + Radius real + ReferencePoint string + Right real + Roundness real + SizeX real + SizeY real + Top real + Version integer + What string + WholeImageArea string + X real + Y real + ZeroX real + ZeroY real + +=head3 XMP CorrRangeMask Struct + +Called CorrectionRangeMask by the spec. + + Field Name Writable + ---------- -------- + AreaModels AreaModels Struct+ + ColorAmount real + DepthFeather real + DepthMax real + DepthMin real + Invert boolean + LumFeather real + LumMax real + LumMin real + LumRange string + LuminanceDepthSampleInfo string + SampleType integer + Type string + Version string + +=head3 XMP AreaModels Struct + + Field Name Writable + ---------- -------- + AreaComponents string+ + ColorRangeMaskAreaSampleInfo string + +=head3 XMP Look Struct + + Field Name Writable + ---------- -------- + Amount string + Cluster string + Copyright string + Group lang-alt + Name string + Parameters LookParms Struct + SupportsAmount string + SupportsMonochrome string + SupportsOutputReferred string + UUID string + +=head3 XMP LookParms Struct + + Field Name Writable + ---------- -------- + CameraProfile string + Clarity2012 string + ConvertToGrayscale string + LookTable string + ProcessVersion string + ToneCurvePV2012 string+ + ToneCurvePV2012Blue string+ + ToneCurvePV2012Green string+ + ToneCurvePV2012Red string+ + Version string + +=head3 XMP RangeMask Struct + +This structure is actually called RangeMaskMapInfo, but it only contains one +element which is a RangeMaskMapInfo structure (Yes, really!). So these are +renamed to RangeMask and MapInfo respectively to avoid confusion and +redundancy in the tag names. + + Field Name Writable + ---------- -------- + RangeMaskMapInfo MapInfo Struct + +=head3 XMP MapInfo Struct + +Called RangeMaskMapInfo by the specification, the same as the containing +structure. + + Field Name Writable + ---------- -------- + LabMax string + LabMin string + LumEq string+ + RGBMax string + RGBMin string + +=head3 XMP RetouchArea Struct + + Field Name Writable + ---------- -------- + Feather real + Masks CorrectionMask Struct+ + Method string + OffsetY real + Opacity real + Seed integer + SourceState string + SourceX real + SpotType string + =head3 XMP creatorAtom Tags Adobe creatorAtom tags, written by After Effects. @@ -1509,11 +2677,15 @@ These tags belong to the ExifTool XMP-crs family 1 group. AutoExposure boolean AutoLateralCA integer AutoShadows boolean + AutoTone boolean + AutoToneDigest string + AutoToneDigestNoSat string AutoWhiteVersion integer Blacks2012 integer BlueHue integer BlueSaturation integer Brightness integer + CameraModelRestriction string CameraProfile string CameraProfileDigest string ChromaticAberrationB integer @@ -1527,17 +2699,85 @@ These tags belong to the ExifTool XMP-crs family 1 group. CircGradBasedCorrMaskBottom real_ CircGradBasedCorrMaskCenterValue real_ CircGradBasedCorrMaskCenterWeight real_ + CircGradBasedCorrMaskRange CorrRangeMask Struct_+ + CircGradBasedCorrMaskRangeAreaModels AreaModels Struct_+ + CircGradBasedCorrMaskRangeAreaModelsComponents string_+ + CircGradBasedCorrMaskRangeAreaModelsColorSampleInfo string_+ + CircGradBasedCorrMaskRangeColorAmount real_+ + CircGradBasedCorrMaskRangeDepthFeather real_+ + CircGradBasedCorrMaskRangeDepthMax real_+ + CircGradBasedCorrMaskRangeDepthMin real_+ + CircGradBasedCorrMaskRangeInvert boolean_+ + CircGradBasedCorrMaskRangeLumFeather real_+ + CircGradBasedCorrMaskRangeLuminanceDepthSampleInfo string_+ + CircGradBasedCorrMaskRangeLumMax real_+ + CircGradBasedCorrMaskRangeLumMin real_+ + CircGradBasedCorrMaskRangeLumRange string_+ + CircGradBasedCorrMaskRangeSampleType integer_+ + CircGradBasedCorrMaskRangeType string_+ + CircGradBasedCorrMaskRangeVersion string_+ CircGradBasedCorrMaskDabs string_ CircGradBasedCorrMaskFeather real_ CircGradBasedCorrMaskFlipped boolean_ CircGradBasedCorrMaskFlow real_ CircGradBasedCorrMaskFullX real_ CircGradBasedCorrMaskFullY real_ + CircGradBasedCorrMaskInputDigest string_ CircGradBasedCorrMaskLeft real_ + CircGradBasedCorrMaskMaskActive boolean_ + CircGradBasedCorrMaskMaskBlendMode integer_ + CircGradBasedCorrMaskMaskDigest string_ + CircGradBasedCorrMaskMaskInverted boolean_ + CircGradBasedCorrMaskMaskName string_ + CircGradBasedCorrMaskMasks CorrectionMask Struct_+ + CircGradBasedCorrMaskMasksAlpha real_ + CircGradBasedCorrMaskMasksAngle real_ + CircGradBasedCorrMaskMasksBottom real_ + CircGradBasedCorrMaskMasksCenterValue real_ + CircGradBasedCorrMaskMasksCenterWeight real_ + CircGradBasedCorrMaskMasksDabs string_+ + CircGradBasedCorrMaskMasksFeather real_ + CircGradBasedCorrMaskMasksFlipped boolean_ + CircGradBasedCorrMaskMasksFlow real_ + CircGradBasedCorrMaskMasksFullX real_ + CircGradBasedCorrMaskMasksFullY real_ + CircGradBasedCorrMaskMasksInputDigest string_ + CircGradBasedCorrMaskMasksLeft real_ + CircGradBasedCorrMaskMasksMaskActive boolean_ + CircGradBasedCorrMaskMasksMaskBlendMode integer_ + CircGradBasedCorrMaskMasksMaskDigest string_ + CircGradBasedCorrMaskMasksMaskInverted boolean_ + CircGradBasedCorrMaskMasksMaskName string_ + CircGradBasedCorrMaskMasksMaskSubType string_ + CircGradBasedCorrMaskMasksMaskSyncID string_ + CircGradBasedCorrMaskMasksValue real_ + CircGradBasedCorrMaskMasksMaskVersion string_ + CircGradBasedCorrMaskMasksMidpoint real_ + CircGradBasedCorrMaskMasksOrigin string_ + CircGradBasedCorrMaskMasksPerimeterValue real_ + CircGradBasedCorrMaskMasksRadius real_ + CircGradBasedCorrMaskMasksReferencePoint string_ + CircGradBasedCorrMaskMasksRight real_ + CircGradBasedCorrMaskMasksRoundness real_ + CircGradBasedCorrMaskMasksSizeX real_ + CircGradBasedCorrMaskMasksSizeY real_ + CircGradBasedCorrMaskMasksTop real_ + CircGradBasedCorrMaskMaskSubType string_ + CircGradBasedCorrMaskMasksVersion integer_ + CircGradBasedCorrMaskMasksWhat string_ + CircGradBasedCorrMaskMasksWholeImageArea string_ + CircGradBasedCorrMaskMasksX real_ + CircGradBasedCorrMaskMasksY real_ + CircGradBasedCorrMaskMaskSyncID string_ + CircGradBasedCorrMaskMasksZeroX real_ + CircGradBasedCorrMaskMasksZeroY real_ CircGradBasedCorrMaskValue real_ + CircGradBasedCorrMaskMaskVersion string_ CircGradBasedCorrMaskMidpoint real_ + CircGradBasedCorrMaskOrigin string_ CircGradBasedCorrMaskPerimeterValue real_ CircGradBasedCorrMaskRadius real_ + CircGradBasedCorrMaskReferencePoint string_ CircGradBasedCorrMaskRight real_ CircGradBasedCorrMaskRoundness real_ CircGradBasedCorrMaskSizeX real_ @@ -1545,38 +2785,78 @@ These tags belong to the ExifTool XMP-crs family 1 group. CircGradBasedCorrMaskTop real_ CircGradBasedCorrMaskVersion integer_ CircGradBasedCorrMaskWhat string_ + CircGradBasedCorrMaskWholeImageArea string_ CircGradBasedCorrMaskX real_ CircGradBasedCorrMaskY real_ CircGradBasedCorrMaskZeroX real_ CircGradBasedCorrMaskZeroY real_ + CircGradBasedCorrCorrectionName string_+ + CircGradBasedCorrRangeMask CorrRangeMask Struct_+ + CircGradBasedCorrRangeMaskAreaModels AreaModels Struct_+ + CircGradBasedCorrRangeMaskAreaModelsComponents string_+ + CircGradBasedCorrRangeMaskAreaModelsColorSampleInfo string_+ + CircGradBasedCorrRangeMaskColorAmount real_+ + CircGradBasedCorrRangeMaskDepthFeather real_+ + CircGradBasedCorrRangeMaskDepthMax real_+ + CircGradBasedCorrRangeMaskDepthMin real_+ + CircGradBasedCorrRangeMaskInvert boolean_+ + CircGradBasedCorrRangeMaskLumFeather real_+ + CircGradBasedCorrRangeMaskLuminanceDepthSampleInfo string_+ + CircGradBasedCorrRangeMaskLumMax real_+ + CircGradBasedCorrRangeMaskLumMin real_+ + CircGradBasedCorrRangeMaskLumRange string_+ + CircGradBasedCorrRangeMaskSampleType integer_+ + CircGradBasedCorrRangeMaskType string_+ + CircGradBasedCorrRangeMaskVersion string_+ + CircGradBasedCorrCorrectionSyncID string_+ + CircGradBasedCorrBlacks2012 real_ CircGradBasedCorrBrightness real_ CircGradBasedCorrClarity real_ CircGradBasedCorrClarity2012 real_ CircGradBasedCorrContrast real_ CircGradBasedCorrContrast2012 real_ CircGradBasedCorrDefringe real_ + CircGradBasedCorrDehaze real_ CircGradBasedCorrExposure real_ CircGradBasedCorrExposure2012 real_ CircGradBasedCorrHighlights2012 real_ + CircGradBasedCorrHue real_ CircGradBasedCorrLuminanceNoise real_ CircGradBasedCorrMoire real_ CircGradBasedCorrSaturation real_ CircGradBasedCorrShadows2012 real_ CircGradBasedCorrSharpness real_ CircGradBasedCorrTemperature real_ + CircGradBasedCorrTexture real_ CircGradBasedCorrTint real_ - CircGradBasedCorrHue real_ - CircGradBasedCorrSaturation real_ + CircGradBasedCorrToningHue real_ + CircGradBasedCorrToningSaturation real_ + CircGradBasedCorrWhites2012 real_ CircGradBasedCorrWhat string_ Clarity integer Clarity2012 integer + ClipboardAspectRatio integer + ClipboardOrientation integer + Cluster string + ColorGradeBlending integer + ColorGradeGlobalHue integer + ColorGradeGlobalLum integer + ColorGradeGlobalSat integer + ColorGradeHighlightLum integer + ColorGradeMidtoneHue integer + ColorGradeMidtoneLum integer + ColorGradeMidtoneSat integer + ColorGradeShadowLum integer ColorNoiseReduction integer ColorNoiseReductionDetail integer ColorNoiseReductionSmoothness integer + CompatibleVersion string + ContactInfo string Contrast integer/ Contrast2012 integer Converter string ConvertToGrayscale boolean + Copyright string/ CropAngle real CropBottom real CropConstrainToWarp integer @@ -1599,6 +2879,7 @@ These tags belong to the ExifTool XMP-crs family 1 group. DefringePurpleHueHi integer DefringePurpleHueLo integer Dehaze real + Description lang-alt/ DNGIgnoreSidecars boolean Exposure real Exposure2012 real @@ -1612,17 +2893,85 @@ These tags belong to the ExifTool XMP-crs family 1 group. GradientBasedCorrMaskBottom real_ GradientBasedCorrMaskCenterValue real_ GradientBasedCorrMaskCenterWeight real_ + GradientBasedCorrMaskRange CorrRangeMask Struct_+ + GradientBasedCorrMaskRangeAreaModels AreaModels Struct_+ + GradientBasedCorrMaskRangeAreaModelsComponents string_+ + GradientBasedCorrMaskRangeAreaModelsColorSampleInfo string_+ + GradientBasedCorrMaskRangeColorAmount real_+ + GradientBasedCorrMaskRangeDepthFeather real_+ + GradientBasedCorrMaskRangeDepthMax real_+ + GradientBasedCorrMaskRangeDepthMin real_+ + GradientBasedCorrMaskRangeInvert boolean_+ + GradientBasedCorrMaskRangeLumFeather real_+ + GradientBasedCorrMaskRangeLuminanceDepthSampleInfo string_+ + GradientBasedCorrMaskRangeLumMax real_+ + GradientBasedCorrMaskRangeLumMin real_+ + GradientBasedCorrMaskRangeLumRange string_+ + GradientBasedCorrMaskRangeSampleType integer_+ + GradientBasedCorrMaskRangeType string_+ + GradientBasedCorrMaskRangeVersion string_+ GradientBasedCorrMaskDabs string_ GradientBasedCorrMaskFeather real_ GradientBasedCorrMaskFlipped boolean_ GradientBasedCorrMaskFlow real_ GradientBasedCorrMaskFullX real_ GradientBasedCorrMaskFullY real_ + GradientBasedCorrMaskInputDigest string_ GradientBasedCorrMaskLeft real_ + GradientBasedCorrMaskMaskActive boolean_ + GradientBasedCorrMaskMaskBlendMode integer_ + GradientBasedCorrMaskMaskDigest string_ + GradientBasedCorrMaskMaskInverted boolean_ + GradientBasedCorrMaskMaskName string_ + GradientBasedCorrMaskMasks CorrectionMask Struct_+ + GradientBasedCorrMaskMasksAlpha real_ + GradientBasedCorrMaskMasksAngle real_ + GradientBasedCorrMaskMasksBottom real_ + GradientBasedCorrMaskMasksCenterValue real_ + GradientBasedCorrMaskMasksCenterWeight real_ + GradientBasedCorrMaskMasksDabs string_+ + GradientBasedCorrMaskMasksFeather real_ + GradientBasedCorrMaskMasksFlipped boolean_ + GradientBasedCorrMaskMasksFlow real_ + GradientBasedCorrMaskMasksFullX real_ + GradientBasedCorrMaskMasksFullY real_ + GradientBasedCorrMaskMasksInputDigest string_ + GradientBasedCorrMaskMasksLeft real_ + GradientBasedCorrMaskMasksMaskActive boolean_ + GradientBasedCorrMaskMasksMaskBlendMode integer_ + GradientBasedCorrMaskMasksMaskDigest string_ + GradientBasedCorrMaskMasksMaskInverted boolean_ + GradientBasedCorrMaskMasksMaskName string_ + GradientBasedCorrMaskMasksMaskSubType string_ + GradientBasedCorrMaskMasksMaskSyncID string_ + GradientBasedCorrMaskMasksValue real_ + GradientBasedCorrMaskMasksMaskVersion string_ + GradientBasedCorrMaskMasksMidpoint real_ + GradientBasedCorrMaskMasksOrigin string_ + GradientBasedCorrMaskMasksPerimeterValue real_ + GradientBasedCorrMaskMasksRadius real_ + GradientBasedCorrMaskMasksReferencePoint string_ + GradientBasedCorrMaskMasksRight real_ + GradientBasedCorrMaskMasksRoundness real_ + GradientBasedCorrMaskMasksSizeX real_ + GradientBasedCorrMaskMasksSizeY real_ + GradientBasedCorrMaskMasksTop real_ + GradientBasedCorrMaskMaskSubType string_ + GradientBasedCorrMaskMasksVersion integer_ + GradientBasedCorrMaskMasksWhat string_ + GradientBasedCorrMaskMasksWholeImageArea string_ + GradientBasedCorrMaskMasksX real_ + GradientBasedCorrMaskMasksY real_ + GradientBasedCorrMaskMaskSyncID string_ + GradientBasedCorrMaskMasksZeroX real_ + GradientBasedCorrMaskMasksZeroY real_ GradientBasedCorrMaskValue real_ + GradientBasedCorrMaskMaskVersion string_ GradientBasedCorrMaskMidpoint real_ + GradientBasedCorrMaskOrigin string_ GradientBasedCorrMaskPerimeterValue real_ GradientBasedCorrMaskRadius real_ + GradientBasedCorrMaskReferencePoint string_ GradientBasedCorrMaskRight real_ GradientBasedCorrMaskRoundness real_ GradientBasedCorrMaskSizeX real_ @@ -1630,31 +2979,57 @@ These tags belong to the ExifTool XMP-crs family 1 group. GradientBasedCorrMaskTop real_ GradientBasedCorrMaskVersion integer_ GradientBasedCorrMaskWhat string_ + GradientBasedCorrMaskWholeImageArea string_ GradientBasedCorrMaskX real_ GradientBasedCorrMaskY real_ GradientBasedCorrMaskZeroX real_ GradientBasedCorrMaskZeroY real_ + GradientBasedCorrCorrectionName string_+ + GradientBasedCorrRangeMask CorrRangeMask Struct_+ + GradientBasedCorrRangeMaskAreaModels AreaModels Struct_+ + GradientBasedCorrRangeMaskAreaModelsComponents string_+ + GradientBasedCorrRangeMaskAreaModelsColorSampleInfo string_+ + GradientBasedCorrRangeMaskColorAmount real_+ + GradientBasedCorrRangeMaskDepthFeather real_+ + GradientBasedCorrRangeMaskDepthMax real_+ + GradientBasedCorrRangeMaskDepthMin real_+ + GradientBasedCorrRangeMaskInvert boolean_+ + GradientBasedCorrRangeMaskLumFeather real_+ + GradientBasedCorrRangeMaskLuminanceDepthSampleInfo string_+ + GradientBasedCorrRangeMaskLumMax real_+ + GradientBasedCorrRangeMaskLumMin real_+ + GradientBasedCorrRangeMaskLumRange string_+ + GradientBasedCorrRangeMaskSampleType integer_+ + GradientBasedCorrRangeMaskType string_+ + GradientBasedCorrRangeMaskVersion string_+ + GradientBasedCorrCorrectionSyncID string_+ + GradientBasedCorrBlacks2012 real_ GradientBasedCorrBrightness real_ GradientBasedCorrClarity real_ GradientBasedCorrClarity2012 real_ GradientBasedCorrContrast real_ GradientBasedCorrContrast2012 real_ GradientBasedCorrDefringe real_ + GradientBasedCorrDehaze real_ GradientBasedCorrExposure real_ GradientBasedCorrExposure2012 real_ GradientBasedCorrHighlights2012 real_ + GradientBasedCorrHue real_ GradientBasedCorrLuminanceNoise real_ GradientBasedCorrMoire real_ GradientBasedCorrSaturation real_ GradientBasedCorrShadows2012 real_ GradientBasedCorrSharpness real_ GradientBasedCorrTemperature real_ + GradientBasedCorrTexture real_ GradientBasedCorrTint real_ - GradientBasedCorrHue real_ - GradientBasedCorrSaturation real_ + GradientBasedCorrToningHue real_ + GradientBasedCorrToningSaturation real_ + GradientBasedCorrWhites2012 real_ GradientBasedCorrWhat string_ GrainAmount integer GrainFrequency integer + GrainSeed integer GrainSize integer GrayMixerAqua integer GrayMixerBlue integer @@ -1666,8 +3041,10 @@ These tags belong to the ExifTool XMP-crs family 1 group. GrayMixerYellow integer GreenHue integer GreenSaturation integer + Group lang-alt/ HasCrop boolean HasSettings boolean + Highlight2012 integer HighlightRecovery integer Highlights2012 integer HueAdjustmentAqua integer @@ -1687,6 +3064,7 @@ These tags belong to the ExifTool XMP-crs family 1 group. LensProfileDistortionScale integer LensProfileEnable integer LensProfileFilename string + LensProfileIsEmbedded boolean LensProfileMatchKeyCameraModelName string LensProfileMatchKeyExifMake string LensProfileMatchKeyExifModel string @@ -1698,6 +3076,27 @@ These tags belong to the ExifTool XMP-crs family 1 group. LensProfileName string LensProfileSetup string LensProfileVignettingScale integer + Look Look Struct + LookAmount string_ + LookCluster string_ + LookCopyright string_ + LookGroup lang-alt_ + LookName string + LookParameters LookParms Struct_ + LookParametersCameraProfile string_ + LookParametersClarity2012 string_ + LookParametersConvertToGrayscale string_ + LookParametersLookTable string_ + LookParametersProcessVersion string_ + LookParametersToneCurvePV2012 string_+ + LookParametersToneCurvePV2012Blue string_+ + LookParametersToneCurvePV2012Green string_+ + LookParametersToneCurvePV2012Red string_+ + LookParametersVersion string_ + LookSupportsAmount string_ + LookSupportsMonochrome string_ + LookSupportsOutputReferred string_ + LookUUID string_ LuminanceAdjustmentAqua integer LuminanceAdjustmentBlue integer LuminanceAdjustmentGreen integer @@ -1709,10 +3108,155 @@ These tags belong to the ExifTool XMP-crs family 1 group. LuminanceNoiseReductionContrast integer LuminanceNoiseReductionDetail integer LuminanceSmoothing integer + MaskGroupBasedCorrections Correction Struct+ + MaskGroupBasedCorrActive boolean_ + MaskGroupBasedCorrAmount real_ + MaskGroupBasedCorrMask CorrectionMask Struct_+ + MaskGroupBasedCorrMaskAlpha real_ + MaskGroupBasedCorrMaskAngle real_ + MaskGroupBasedCorrMaskBottom real_ + MaskGroupBasedCorrMaskCenterValue real_ + MaskGroupBasedCorrMaskCenterWeight real_ + MaskGroupBasedCorrMaskRange CorrRangeMask Struct_+ + MaskGroupBasedCorrMaskRangeAreaModels AreaModels Struct_+ + MaskGroupBasedCorrMaskRangeAreaModelsComponents string_+ + MaskGroupBasedCorrMaskRangeAreaModelsColorSampleInfo string_+ + MaskGroupBasedCorrMaskRangeColorAmount real_+ + MaskGroupBasedCorrMaskRangeDepthFeather real_+ + MaskGroupBasedCorrMaskRangeDepthMax real_+ + MaskGroupBasedCorrMaskRangeDepthMin real_+ + MaskGroupBasedCorrMaskRangeInvert boolean_+ + MaskGroupBasedCorrMaskRangeLumFeather real_+ + MaskGroupBasedCorrMaskRangeLuminanceDepthSampleInfo string_+ + MaskGroupBasedCorrMaskRangeLumMax real_+ + MaskGroupBasedCorrMaskRangeLumMin real_+ + MaskGroupBasedCorrMaskRangeLumRange string_+ + MaskGroupBasedCorrMaskRangeSampleType integer_+ + MaskGroupBasedCorrMaskRangeType string_+ + MaskGroupBasedCorrMaskRangeVersion string_+ + MaskGroupBasedCorrMaskDabs string_+ + MaskGroupBasedCorrMaskFeather real_ + MaskGroupBasedCorrMaskFlipped boolean_ + MaskGroupBasedCorrMaskFlow real_ + MaskGroupBasedCorrMaskFullX real_ + MaskGroupBasedCorrMaskFullY real_ + MaskGroupBasedCorrMaskInputDigest string_ + MaskGroupBasedCorrMaskLeft real_ + MaskGroupBasedCorrMaskMaskActive boolean_ + MaskGroupBasedCorrMaskMaskBlendMode integer_ + MaskGroupBasedCorrMaskMaskDigest string_ + MaskGroupBasedCorrMaskMaskInverted boolean_ + MaskGroupBasedCorrMaskMaskName string_ + MaskGroupBasedCorrMaskMasks CorrectionMask Struct_+ + MaskGroupBasedCorrMaskMasksAlpha real_ + MaskGroupBasedCorrMaskMasksAngle real_ + MaskGroupBasedCorrMaskMasksBottom real_ + MaskGroupBasedCorrMaskMasksCenterValue real_ + MaskGroupBasedCorrMaskMasksCenterWeight real_ + MaskGroupBasedCorrMaskMasksDabs string_+ + MaskGroupBasedCorrMaskMasksFeather real_ + MaskGroupBasedCorrMaskMasksFlipped boolean_ + MaskGroupBasedCorrMaskMasksFlow real_ + MaskGroupBasedCorrMaskMasksFullX real_ + MaskGroupBasedCorrMaskMasksFullY real_ + MaskGroupBasedCorrMaskMasksInputDigest string_ + MaskGroupBasedCorrMaskMasksLeft real_ + MaskGroupBasedCorrMaskMasksMaskActive boolean_ + MaskGroupBasedCorrMaskMasksMaskBlendMode integer_ + MaskGroupBasedCorrMaskMasksMaskDigest string_ + MaskGroupBasedCorrMaskMasksMaskInverted boolean_ + MaskGroupBasedCorrMaskMasksMaskName string_ + MaskGroupBasedCorrMaskMasksMaskSubType string_ + MaskGroupBasedCorrMaskMasksMaskSyncID string_ + MaskGroupBasedCorrMaskMasksValue real_ + MaskGroupBasedCorrMaskMasksMaskVersion string_ + MaskGroupBasedCorrMaskMasksMidpoint real_ + MaskGroupBasedCorrMaskMasksOrigin string_ + MaskGroupBasedCorrMaskMasksPerimeterValue real_ + MaskGroupBasedCorrMaskMasksRadius real_ + MaskGroupBasedCorrMaskMasksReferencePoint string_ + MaskGroupBasedCorrMaskMasksRight real_ + MaskGroupBasedCorrMaskMasksRoundness real_ + MaskGroupBasedCorrMaskMasksSizeX real_ + MaskGroupBasedCorrMaskMasksSizeY real_ + MaskGroupBasedCorrMaskMasksTop real_ + MaskGroupBasedCorrMaskMaskSubType string_ + MaskGroupBasedCorrMaskMasksVersion integer_ + MaskGroupBasedCorrMaskMasksWhat string_ + MaskGroupBasedCorrMaskMasksWholeImageArea string_ + MaskGroupBasedCorrMaskMasksX real_ + MaskGroupBasedCorrMaskMasksY real_ + MaskGroupBasedCorrMaskMaskSyncID string_ + MaskGroupBasedCorrMaskMasksZeroX real_ + MaskGroupBasedCorrMaskMasksZeroY real_ + MaskGroupBasedCorrMaskValue real_ + MaskGroupBasedCorrMaskMaskVersion string_ + MaskGroupBasedCorrMaskMidpoint real_ + MaskGroupBasedCorrMaskOrigin string_ + MaskGroupBasedCorrMaskPerimeterValue real_ + MaskGroupBasedCorrMaskRadius real_ + MaskGroupBasedCorrMaskReferencePoint string_ + MaskGroupBasedCorrMaskRight real_ + MaskGroupBasedCorrMaskRoundness real_ + MaskGroupBasedCorrMaskSizeX real_ + MaskGroupBasedCorrMaskSizeY real_ + MaskGroupBasedCorrMaskTop real_ + MaskGroupBasedCorrMaskVersion integer_ + MaskGroupBasedCorrMaskWhat string_ + MaskGroupBasedCorrMaskWholeImageArea string_ + MaskGroupBasedCorrMaskX real_ + MaskGroupBasedCorrMaskY real_ + MaskGroupBasedCorrMaskZeroX real_ + MaskGroupBasedCorrMaskZeroY real_ + MaskGroupBasedCorrCorrectionName string_+ + MaskGroupBasedCorrRangeMask CorrRangeMask Struct_+ + MaskGroupBasedCorrRangeMaskAreaModels AreaModels Struct_+ + MaskGroupBasedCorrRangeMaskAreaModelsComponents string_+ + MaskGroupBasedCorrRangeMaskAreaModelsColorSampleInfo string_+ + MaskGroupBasedCorrRangeMaskColorAmount real_+ + MaskGroupBasedCorrRangeMaskDepthFeather real_+ + MaskGroupBasedCorrRangeMaskDepthMax real_+ + MaskGroupBasedCorrRangeMaskDepthMin real_+ + MaskGroupBasedCorrRangeMaskInvert boolean_+ + MaskGroupBasedCorrRangeMaskLumFeather real_+ + MaskGroupBasedCorrRangeMaskLuminanceDepthSampleInfo string_+ + MaskGroupBasedCorrRangeMaskLumMax real_+ + MaskGroupBasedCorrRangeMaskLumMin real_+ + MaskGroupBasedCorrRangeMaskLumRange string_+ + MaskGroupBasedCorrRangeMaskSampleType integer_+ + MaskGroupBasedCorrRangeMaskType string_+ + MaskGroupBasedCorrRangeMaskVersion string_+ + MaskGroupBasedCorrCorrectionSyncID string_+ + MaskGroupBasedCorrBlacks2012 real_ + MaskGroupBasedCorrBrightness real_ + MaskGroupBasedCorrClarity real_ + MaskGroupBasedCorrClarity2012 real_ + MaskGroupBasedCorrContrast real_ + MaskGroupBasedCorrContrast2012 real_ + MaskGroupBasedCorrDefringe real_ + MaskGroupBasedCorrDehaze real_ + MaskGroupBasedCorrExposure real_ + MaskGroupBasedCorrExposure2012 real_ + MaskGroupBasedCorrHighlights2012 real_ + MaskGroupBasedCorrHue real_ + MaskGroupBasedCorrLuminanceNoise real_ + MaskGroupBasedCorrMoire real_ + MaskGroupBasedCorrSaturation real_ + MaskGroupBasedCorrShadows2012 real_ + MaskGroupBasedCorrSharpness real_ + MaskGroupBasedCorrTemperature real_ + MaskGroupBasedCorrTexture real_ + MaskGroupBasedCorrTint real_ + MaskGroupBasedCorrToningHue real_ + MaskGroupBasedCorrToningSaturation real_ + MaskGroupBasedCorrWhites2012 real_ + MaskGroupBasedCorrWhat string_ MoireFilter string + Name lang-alt/ NegativeCacheLargePreviewSize integer NegativeCacheMaximumSize real NegativeCachePath string + OverrideLookVignette boolean PaintBasedCorrections Correction Struct+ PaintCorrectionActive boolean_ PaintCorrectionAmount real_ @@ -1722,17 +3266,85 @@ These tags belong to the ExifTool XMP-crs family 1 group. PaintCorrectionMaskBottom real_ PaintCorrectionMaskCenterValue real_ PaintCorrectionMaskCenterWeight real_ + PaintCorrectionMaskRange CorrRangeMask Struct_+ + PaintCorrectionMaskRangeAreaModels AreaModels Struct_+ + PaintCorrectionMaskRangeAreaModelsComponents string_+ + PaintCorrectionMaskRangeAreaModelsColorSampleInfo string_+ + PaintCorrectionMaskRangeColorAmount real_+ + PaintCorrectionMaskRangeDepthFeather real_+ + PaintCorrectionMaskRangeDepthMax real_+ + PaintCorrectionMaskRangeDepthMin real_+ + PaintCorrectionMaskRangeInvert boolean_+ + PaintCorrectionMaskRangeLumFeather real_+ + PaintCorrectionMaskRangeLuminanceDepthSampleInfo string_+ + PaintCorrectionMaskRangeLumMax real_+ + PaintCorrectionMaskRangeLumMin real_+ + PaintCorrectionMaskRangeLumRange string_+ + PaintCorrectionMaskRangeSampleType integer_+ + PaintCorrectionMaskRangeType string_+ + PaintCorrectionMaskRangeVersion string_+ PaintCorrectionMaskDabs string_ PaintCorrectionMaskFeather real_ PaintCorrectionMaskFlipped boolean_ PaintCorrectionMaskFlow real_ PaintCorrectionMaskFullX real_ PaintCorrectionMaskFullY real_ + PaintCorrectionMaskInputDigest string_ PaintCorrectionMaskLeft real_ + PaintCorrectionMaskMaskActive boolean_ + PaintCorrectionMaskMaskBlendMode integer_ + PaintCorrectionMaskMaskDigest string_ + PaintCorrectionMaskMaskInverted boolean_ + PaintCorrectionMaskMaskName string_ + PaintCorrectionMaskMasks CorrectionMask Struct_+ + PaintCorrectionMaskMasksAlpha real_ + PaintCorrectionMaskMasksAngle real_ + PaintCorrectionMaskMasksBottom real_ + PaintCorrectionMaskMasksCenterValue real_ + PaintCorrectionMaskMasksCenterWeight real_ + PaintCorrectionMaskMasksDabs string_+ + PaintCorrectionMaskMasksFeather real_ + PaintCorrectionMaskMasksFlipped boolean_ + PaintCorrectionMaskMasksFlow real_ + PaintCorrectionMaskMasksFullX real_ + PaintCorrectionMaskMasksFullY real_ + PaintCorrectionMaskMasksInputDigest string_ + PaintCorrectionMaskMasksLeft real_ + PaintCorrectionMaskMasksMaskActive boolean_ + PaintCorrectionMaskMasksMaskBlendMode integer_ + PaintCorrectionMaskMasksMaskDigest string_ + PaintCorrectionMaskMasksMaskInverted boolean_ + PaintCorrectionMaskMasksMaskName string_ + PaintCorrectionMaskMasksMaskSubType string_ + PaintCorrectionMaskMasksMaskSyncID string_ + PaintCorrectionMaskMasksValue real_ + PaintCorrectionMaskMasksMaskVersion string_ + PaintCorrectionMaskMasksMidpoint real_ + PaintCorrectionMaskMasksOrigin string_ + PaintCorrectionMaskMasksPerimeterValue real_ + PaintCorrectionMaskMasksRadius real_ + PaintCorrectionMaskMasksReferencePoint string_ + PaintCorrectionMaskMasksRight real_ + PaintCorrectionMaskMasksRoundness real_ + PaintCorrectionMaskMasksSizeX real_ + PaintCorrectionMaskMasksSizeY real_ + PaintCorrectionMaskMasksTop real_ + PaintCorrectionMaskMaskSubType string_ + PaintCorrectionMaskMasksVersion integer_ + PaintCorrectionMaskMasksWhat string_ + PaintCorrectionMaskMasksWholeImageArea string_ + PaintCorrectionMaskMasksX real_ + PaintCorrectionMaskMasksY real_ + PaintCorrectionMaskMaskSyncID string_ + PaintCorrectionMaskMasksZeroX real_ + PaintCorrectionMaskMasksZeroY real_ PaintCorrectionMaskValue real_ + PaintCorrectionMaskMaskVersion string_ PaintCorrectionMaskMidpoint real_ + PaintCorrectionMaskOrigin string_ PaintCorrectionMaskPerimeterValue real_ PaintCorrectionMaskRadius real_ + PaintCorrectionMaskReferencePoint string_ PaintCorrectionMaskRight real_ PaintCorrectionMaskRoundness real_ PaintCorrectionMaskSizeX real_ @@ -1740,28 +3352,53 @@ These tags belong to the ExifTool XMP-crs family 1 group. PaintCorrectionMaskTop real_ PaintCorrectionMaskVersion integer_ PaintCorrectionMaskWhat string_ + PaintCorrectionMaskWholeImageArea string_ PaintCorrectionMaskX real_ PaintCorrectionMaskY real_ PaintCorrectionMaskZeroX real_ PaintCorrectionMaskZeroY real_ + PaintCorrectionCorrectionName string_+ + PaintCorrectionRangeMask CorrRangeMask Struct_+ + PaintCorrectionRangeMaskAreaModels AreaModels Struct_+ + PaintCorrectionRangeMaskAreaModelsComponents string_+ + PaintCorrectionRangeMaskAreaModelsColorSampleInfo string_+ + PaintCorrectionRangeMaskColorAmount real_+ + PaintCorrectionRangeMaskDepthFeather real_+ + PaintCorrectionRangeMaskDepthMax real_+ + PaintCorrectionRangeMaskDepthMin real_+ + PaintCorrectionRangeMaskInvert boolean_+ + PaintCorrectionRangeMaskLumFeather real_+ + PaintCorrectionRangeMaskLuminanceDepthSampleInfo string_+ + PaintCorrectionRangeMaskLumMax real_+ + PaintCorrectionRangeMaskLumMin real_+ + PaintCorrectionRangeMaskLumRange string_+ + PaintCorrectionRangeMaskSampleType integer_+ + PaintCorrectionRangeMaskType string_+ + PaintCorrectionRangeMaskVersion string_+ + PaintCorrectionCorrectionSyncID string_+ + PaintCorrectionBlacks2012 real_ PaintCorrectionBrightness real_ PaintCorrectionClarity real_ PaintCorrectionClarity2012 real_ PaintCorrectionContrast real_ PaintCorrectionContrast2012 real_ PaintCorrectionDefringe real_ + PaintCorrectionDehaze real_ PaintCorrectionExposure real_ PaintCorrectionExposure2012 real_ PaintCorrectionHighlights2012 real_ + PaintCorrectionHue real_ PaintCorrectionLuminanceNoise real_ PaintCorrectionMoire real_ PaintCorrectionSaturation real_ PaintCorrectionShadows2012 real_ PaintCorrectionSharpness real_ PaintCorrectionTemperature real_ + PaintCorrectionTexture real_ PaintCorrectionTint real_ - PaintCorrectionHue real_ - PaintCorrectionSaturation real_ + PaintCorrectionToningHue real_ + PaintCorrectionToningSaturation real_ + PaintCorrectionWhites2012 real_ PaintCorrectionWhat string_ ParametricDarks integer ParametricHighlights integer @@ -1784,7 +3421,15 @@ These tags belong to the ExifTool XMP-crs family 1 group. PostCropVignetteMidpoint integer PostCropVignetteRoundness integer PostCropVignetteStyle integer + PresetType string ProcessVersion string + RangeMask RangeMask Struct + RangeMaskMapInfo MapInfo Struct_ + RangeMaskMapInfoLabMax string_ + RangeMaskMapInfoLabMin string_ + RangeMaskMapInfoLumEq string_+ + RangeMaskMapInfoRGBMax string_ + RangeMaskMapInfoRGBMin string_ RawFileName string RedEyeInfo string+ RedHue integer @@ -1797,17 +3442,85 @@ These tags belong to the ExifTool XMP-crs family 1 group. RetouchAreaMaskBottom real_ RetouchAreaMaskCenterValue real_ RetouchAreaMaskCenterWeight real_ + RetouchAreaMaskRange CorrRangeMask Struct_+ + RetouchAreaMaskRangeAreaModels AreaModels Struct_+ + RetouchAreaMaskRangeAreaModelsComponents string_+ + RetouchAreaMaskRangeAreaModelsColorSampleInfo string_+ + RetouchAreaMaskRangeColorAmount real_+ + RetouchAreaMaskRangeDepthFeather real_+ + RetouchAreaMaskRangeDepthMax real_+ + RetouchAreaMaskRangeDepthMin real_+ + RetouchAreaMaskRangeInvert boolean_+ + RetouchAreaMaskRangeLumFeather real_+ + RetouchAreaMaskRangeLuminanceDepthSampleInfo string_+ + RetouchAreaMaskRangeLumMax real_+ + RetouchAreaMaskRangeLumMin real_+ + RetouchAreaMaskRangeLumRange string_+ + RetouchAreaMaskRangeSampleType integer_+ + RetouchAreaMaskRangeType string_+ + RetouchAreaMaskRangeVersion string_+ RetouchAreaMaskDabs string_ RetouchAreaMaskFeather real_ RetouchAreaMaskFlipped boolean_ RetouchAreaMaskFlow real_ RetouchAreaMaskFullX real_ RetouchAreaMaskFullY real_ + RetouchAreaMaskInputDigest string_ RetouchAreaMaskLeft real_ + RetouchAreaMaskMaskActive boolean_ + RetouchAreaMaskMaskBlendMode integer_ + RetouchAreaMaskMaskDigest string_ + RetouchAreaMaskMaskInverted boolean_ + RetouchAreaMaskMaskName string_ + RetouchAreaMaskMasks CorrectionMask Struct_+ + RetouchAreaMaskMasksAlpha real_ + RetouchAreaMaskMasksAngle real_ + RetouchAreaMaskMasksBottom real_ + RetouchAreaMaskMasksCenterValue real_ + RetouchAreaMaskMasksCenterWeight real_ + RetouchAreaMaskMasksDabs string_+ + RetouchAreaMaskMasksFeather real_ + RetouchAreaMaskMasksFlipped boolean_ + RetouchAreaMaskMasksFlow real_ + RetouchAreaMaskMasksFullX real_ + RetouchAreaMaskMasksFullY real_ + RetouchAreaMaskMasksInputDigest string_ + RetouchAreaMaskMasksLeft real_ + RetouchAreaMaskMasksMaskActive boolean_ + RetouchAreaMaskMasksMaskBlendMode integer_ + RetouchAreaMaskMasksMaskDigest string_ + RetouchAreaMaskMasksMaskInverted boolean_ + RetouchAreaMaskMasksMaskName string_ + RetouchAreaMaskMasksMaskSubType string_ + RetouchAreaMaskMasksMaskSyncID string_ + RetouchAreaMaskMasksValue real_ + RetouchAreaMaskMasksMaskVersion string_ + RetouchAreaMaskMasksMidpoint real_ + RetouchAreaMaskMasksOrigin string_ + RetouchAreaMaskMasksPerimeterValue real_ + RetouchAreaMaskMasksRadius real_ + RetouchAreaMaskMasksReferencePoint string_ + RetouchAreaMaskMasksRight real_ + RetouchAreaMaskMasksRoundness real_ + RetouchAreaMaskMasksSizeX real_ + RetouchAreaMaskMasksSizeY real_ + RetouchAreaMaskMasksTop real_ + RetouchAreaMaskMaskSubType string_ + RetouchAreaMaskMasksVersion integer_ + RetouchAreaMaskMasksWhat string_ + RetouchAreaMaskMasksWholeImageArea string_ + RetouchAreaMaskMasksX real_ + RetouchAreaMaskMasksY real_ + RetouchAreaMaskMaskSyncID string_ + RetouchAreaMaskMasksZeroX real_ + RetouchAreaMaskMasksZeroY real_ RetouchAreaMaskValue real_ + RetouchAreaMaskMaskVersion string_ RetouchAreaMaskMidpoint real_ + RetouchAreaMaskOrigin string_ RetouchAreaMaskPerimeterValue real_ RetouchAreaMaskRadius real_ + RetouchAreaMaskReferencePoint string_ RetouchAreaMaskRight real_ RetouchAreaMaskRoundness real_ RetouchAreaMaskSizeX real_ @@ -1815,6 +3528,7 @@ These tags belong to the ExifTool XMP-crs family 1 group. RetouchAreaMaskTop real_ RetouchAreaMaskVersion integer_ RetouchAreaMaskWhat string_ + RetouchAreaMaskWholeImageArea string_ RetouchAreaMaskX real_ RetouchAreaMaskY real_ RetouchAreaMaskZeroX real_ @@ -1843,15 +3557,27 @@ These tags belong to the ExifTool XMP-crs family 1 group. SharpenEdgeMasking integer SharpenRadius real Sharpness integer/ + ShortName lang-alt Smoothness integer + SortName lang-alt SplitToningBalance integer SplitToningHighlightHue integer SplitToningHighlightSaturation integer SplitToningShadowHue integer SplitToningShadowSaturation integer + SupportsAmount boolean + SupportsColor boolean + SupportsHighDynamicRange boolean + SupportsMonochrome boolean + SupportsNormalDynamicRange boolean + SupportsOutputReferred boolean + SupportsSceneReferred boolean ColorTemperature integer + Texture integer TIFFHandling string Tint integer + ToggleStyleAmount integer + ToggleStyleDigest string ToneCurve string+ ToneCurveBlue string+ ToneCurveGreen string+ @@ -1879,6 +3605,7 @@ These tags belong to the ExifTool XMP-crs family 1 group. UprightTransform_5 string UprightTransformCount integer UprightVersion integer + UUID string/ Version string Vibrance integer VignetteAmount integer @@ -1887,79 +3614,6 @@ These tags belong to the ExifTool XMP-crs family 1 group. WhiteBalance string/ Whites2012 integer -=head3 XMP Correction Struct - - Field Name Writable - ---------- -------- - CorrectionActive boolean - CorrectionAmount real - CorrectionMasks CorrectionMask Struct+ - LocalBrightness real - LocalClarity real - LocalClarity2012 real - LocalContrast real - LocalContrast2012 real - LocalDefringe real - LocalExposure real - LocalExposure2012 real - LocalHighlights2012 real - LocalLuminanceNoise real - LocalMoire real - LocalSaturation real - LocalShadows2012 real - LocalSharpness real - LocalTemperature real - LocalTint real - LocalToningHue real - LocalToningSaturation real - What string - -=head3 XMP CorrectionMask Struct - - Field Name Writable - ---------- -------- - Alpha real - Angle real - Bottom real - CenterValue real - CenterWeight real - Dabs string+ - Feather real - Flipped boolean - Flow real - FullX real - FullY real - Left real - MaskValue real - Midpoint real - PerimeterValue real - Radius real - Right real - Roundness real - SizeX real - SizeY real - Top real - Version integer - What string - X real - Y real - ZeroX real - ZeroY real - -=head3 XMP RetouchArea Struct - - Field Name Writable - ---------- -------- - Feather real - Masks CorrectionMask Struct+ - Method string - OffsetY real - Opacity real - Seed integer - SourceState string - SourceX real - SpotType string - =head3 XMP dc Tags Dublin Core namespace tags. @@ -1984,7 +3638,292 @@ These tags belong to the ExifTool XMP-dc family 1 group. Title lang-alt Type string+ -=head3 XMP dex Tags +=head3 XMP Device Tags + +Google depth-map Device tags. See +L<https://developer.android.com/training/camera2/Dynamic-depth-v1.0.pdf> for +the specification. + +These tags belong to the ExifTool XMP-Device family 1 group. + + Tag Name Writable + -------- -------- + AppInfo AppInfo Struct + AppInfoApplication string_ + AppInfoItemURI string_ + AppInfoVersion string_ + Cameras DeviceCameras Struct+ + Camera DeviceCamera Struct_+ + CameraAppInfo AppInfo Struct_+ + CameraAppInfoApplication string_+ + CameraAppInfoItemURI string_+ + CameraAppInfoVersion string_+ + CameraDepthMap DeviceDepthMap Struct_+ + CameraDepthMapConfidenceURI string_+ + CameraDepthMapDepthURI string_+ + CameraDepthMapFar real_+ + CameraDepthMapFocalTable string_+ + CameraDepthMapFocalTableEntryCount integer_+ + CameraDepthMapFormat string_+ + CameraDepthMapItemSemantic string_+ + CameraDepthMapMeasureType string_+ + CameraDepthMapNear real_+ + CameraDepthMapSoftware string_+ + CameraDepthMapUnits string_+ + CameraImage DeviceImage Struct_+ + CameraImageItemSemantic string_+ + CameraImageItemURI string_+ + CameraImagingModel DeviceImagingModel Struct_+ + CameraImagingModelDistortion string_+ + CameraImagingModelDistortionCount integer_+ + CameraImagingModelFocalLengthX real_+ + CameraImagingModelFocalLengthY real_+ + CameraImagingModelImageHeight integer_+ + CameraImagingModelImageWidth integer_+ + CameraImagingModelPixelAspectRatio real_+ + CameraImagingModelPrincipalPointX real_+ + CameraImagingModelPrincipalPointY real_+ + CameraImagingModelSkew real_+ + CameraLightEstimate DeviceLightEstimate Struct_+ + CameraLightEstimateColorCorrectionB real_+ + CameraLightEstimateColorCorrectionG real_+ + CameraLightEstimateColorCorrectionR real_+ + CameraLightEstimatePixelIntensity real_+ + CameraPointCloud DevicePointCloud Struct_+ + CameraPointCloudMetric boolean_+ + CameraPointCloudPointCloud integer_+ + CameraPointCloudPoints string_+ + CameraPose Pose Struct_+ + CameraPosePositionX real_+ + CameraPosePositionY real_+ + CameraPosePositionZ real_+ + CameraPoseRotationW real_+ + CameraPoseRotationX real_+ + CameraPoseRotationY real_+ + CameraPoseRotationZ real_+ + CameraPoseTimestamp integer_+ + CameraTrait string_+ + CameraVendorInfo VendorInfo Struct_+ + CameraVendorInfoManufacturer string_+ + CameraVendorInfoModel string_+ + CameraVendorInfoNotes string_+ + Container DeviceContainer Struct + ContainerDirectory DeviceDirectory Struct_+ + ContainerDirectoryItem DeviceItem Struct_+ + ContainerDirectoryItemDataURI string_+ + ContainerDirectoryItemLength integer_+ + ContainerDirectoryItemMime string_+ + ContainerDirectoryItemPadding integer_+ + EarthPos EarthPose Struct + EarthPosAltitude real_ + EarthPosLatitude real_ + EarthPosLongitude real_ + EarthPosRotationW real_ + EarthPosRotationX real_ + EarthPosRotationY real_ + EarthPosRotationZ real_ + EarthPosTimestamp integer_ + Planes DevicePlanes Struct+ + Plane DevicePlane Struct_+ + PlaneBoundary string_+ + PlaneBoundaryVertexCount integer_+ + PlaneExtentX real_+ + PlaneExtentZ real_+ + PlanePose Pose Struct_+ + PlanePosePositionX real_+ + PlanePosePositionY real_+ + PlanePosePositionZ real_+ + PlanePoseRotationW real_+ + PlanePoseRotationX real_+ + PlanePoseRotationY real_+ + PlanePoseRotationZ real_+ + PlanePoseTimestamp integer_+ + Pose Pose Struct + PosePositionX real_ + PosePositionY real_ + PosePositionZ real_ + PoseRotationW real_ + PoseRotationX real_ + PoseRotationY real_ + PoseRotationZ real_ + PoseTimestamp integer_ + Profiles DeviceProfiles Struct+ + Profile DeviceProfile Struct_+ + ProfileCameraIndices integer_+ + ProfileType string_+ + VendorInfo VendorInfo Struct + VendorInfoManufacturer string_ + VendorInfoModel string_ + VendorInfoNotes string_ + +=head3 XMP AppInfo Struct + + Field Name Writable + ---------- -------- + Application string + ItemURI string + Version string + +=head3 XMP DeviceCameras Struct + + Field Name Writable + ---------- -------- + Camera DeviceCamera Struct + +=head3 XMP DeviceCamera Struct + + Field Name Writable + ---------- -------- + AppInfo AppInfo Struct + DepthMap DeviceDepthMap Struct + Image DeviceImage Struct + ImagingModel DeviceImagingModel Struct + LightEstimate DeviceLightEstimate Struct + PointCloud DevicePointCloud Struct + Pose Pose Struct + Trait string + VendorInfo VendorInfo Struct + +=head3 XMP DeviceDepthMap Struct + + Field Name Writable + ---------- -------- + ConfidenceURI string + DepthURI string + Far real + FocalTable string + FocalTableEntryCount integer + Format string + ItemSemantic string + MeasureType string + Near real + Software string + Units string + +=head3 XMP DeviceImage Struct + + Field Name Writable + ---------- -------- + ItemSemantic string + ItemURI string + +=head3 XMP DeviceImagingModel Struct + + Field Name Writable + ---------- -------- + Distortion string + DistortionCount integer + FocalLengthX real + FocalLengthY real + ImageHeight integer + ImageWidth integer + PixelAspectRatio real + PrincipalPointX real + PrincipalPointY real + Skew real + +=head3 XMP DeviceLightEstimate Struct + + Field Name Writable + ---------- -------- + ColorCorrectionB real + ColorCorrectionG real + ColorCorrectionR real + PixelIntensity real + +=head3 XMP DevicePointCloud Struct + + Field Name Writable + ---------- -------- + Metric boolean + PointCloud integer + Points string + +=head3 XMP Pose Struct + + Field Name Writable + ---------- -------- + PositionX real + PositionY real + PositionZ real + RotationW real + RotationX real + RotationY real + RotationZ real + Timestamp integer + +=head3 XMP VendorInfo Struct + + Field Name Writable + ---------- -------- + Manufacturer string + Model string + Notes string + +=head3 XMP DeviceContainer Struct + + Field Name Writable + ---------- -------- + Directory DeviceDirectory Struct+ + +=head3 XMP DeviceDirectory Struct + + Field Name Writable + ---------- -------- + Item DeviceItem Struct + +=head3 XMP DeviceItem Struct + + Field Name Writable + ---------- -------- + DataURI string + Length integer + Mime string + Padding integer + +=head3 XMP EarthPose Struct + + Field Name Writable + ---------- -------- + Altitude real + Latitude real + Longitude real + RotationW real + RotationX real + RotationY real + RotationZ real + Timestamp integer + +=head3 XMP DevicePlanes Struct + + Field Name Writable + ---------- -------- + Plane DevicePlane Struct + +=head3 XMP DevicePlane Struct + + Field Name Writable + ---------- -------- + Boundary string + BoundaryVertexCount integer + ExtentX real + ExtentZ real + Pose Pose Struct + +=head3 XMP DeviceProfiles Struct + + Field Name Writable + ---------- -------- + Profile DeviceProfile Struct + +=head3 XMP DeviceProfile Struct + + Field Name Writable + ---------- -------- + CameraIndices integer+ + Type string + +=head3 XMP dex Tags Description Explorer namespace tags. These tags are not very common. The Source and Rating tags are avoided when writing due to name conflicts with @@ -2049,8 +3988,8 @@ These tags belong to the ExifTool XMP-digiKam family 1 group. =head3 XMP exif Tags EXIF namespace for EXIF tags. See -L<http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf> for the -specification. +L<https://web.archive.org/web/20180921145139if_/http://www.cipa.jp:80/std/documents/e/DC-010-2017_E.pdf> +for the specification. These tags belong to the ExifTool XMP-exif family 1 group. @@ -2194,8 +4133,8 @@ These tags belong to the ExifTool XMP-exif family 1 group. =head3 XMP exifEX Tags -EXIF tags added by the EXIF 2.31 for XMP specification (see -L<http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf>). +EXIF tags added by the EXIF 2.32 for XMP specification (see +L<https://cipa.jp/std/documents/download_e.html?DC-010-2020_E>). These tags belong to the ExifTool XMP-exifEX family 1 group. @@ -2205,6 +4144,19 @@ These tags belong to the ExifTool XMP-exifEX family 1 group. SerialNumber string CameraElevationAngle rational OwnerName string + CompositeImage integer + CompositeImageCount integer+ + CompositeImageExposureTimes CompImageExp Struct + CompImageMaxExposureAll rational_ + CompImageMaxExposureUsed rational_ + CompImageMinExposureAll rational_ + CompImageMinExposureUsed rational_ + CompImageImagesPerSequence integer_ + CompImageNumSequences integer_ + CompImageSumExposureAll rational_ + CompImageSumExposureUsed rational_ + CompImageTotalExposurePeriod rational_ + CompImageValues rational_+ Gamma rational Humidity rational InteropIndex string @@ -2223,6 +4175,21 @@ These tags belong to the ExifTool XMP-exifEX family 1 group. AmbientTemperature rational WaterDepth rational +=head3 XMP CompImageExp Struct + + Field Name Writable + ---------- -------- + MaxExposureTimesOfAll rational + MaxExposureTimesOfUsed rational + MinExposureTimesOfAll rational + MinExposureTimesOfUsed rational + NumberOfImagesInSequences integer + NumberOfSequences integer + SumOfExposureTimesOfAll rational + SumOfExposureTimesOfUsed rational + TotalExposurePeriod rational + Values rational+ + =head3 XMP ExpressionMedia Tags Microsoft Expression Media namespace tags. These tags are avoided when @@ -2274,6 +4241,37 @@ These tags belong to the ExifTool XMP-GAudio family 1 group. AudioData string AudioMimeType string +=head3 XMP GCamera Tags + +Camera information found in Google panorama images. + +These tags belong to the ExifTool XMP-GCamera family 1 group. + + Tag Name Writable + -------- -------- + BurstID string + BurstPrimary string + DisableAutoCreation string+ + HDRPMakerNote string + MicroVideo integer + MicroVideoOffset integer + MicroVideoPresentationTimestampUs integer + MicroVideoVersion integer + PortraitNote string + PortraitRequest string + PortraitVersion string + SpecialTypeID string+ + +=head3 XMP GCreations Tags + +Google creations tags. + +These tags belong to the ExifTool XMP-GCreations family 1 group. + + Tag Name Writable + -------- -------- + CameraBurstID string + =head3 XMP GDepth Tags Google depthmap information. See @@ -2285,7 +4283,7 @@ These tags belong to the ExifTool XMP-GDepth family 1 group. -------- -------- Confidence string/ ConfidenceMime string/ - Data string/ + DepthImage string/ Far real/ Format string/ ImageHeight real/ @@ -2322,7 +4320,7 @@ These tags belong to the ExifTool XMP-getty family 1 group. OriginalFileName string ParentMediaEventID string ParentMEID string - Personality string + Personality string+ PrimaryFTP string+ RoutingDestinations string+ RoutingExclusions string+ @@ -2371,6 +4369,7 @@ These tags belong to the ExifTool XMP-GPano family 1 group. FullPanoWidthPixels real InitialCameraDolly real InitialHorizontalFOVDegrees real + InitialVerticalFOVDegrees real InitialViewHeadingDegrees real InitialViewPitchDegrees real InitialViewRollDegrees real @@ -2390,7 +4389,8 @@ These tags belong to the ExifTool XMP-GPano family 1 group. =head3 XMP GSpherical Tags Not actually XMP. These RDF/XML tags are used in Google spherical MP4 -videos. See +videos. These tags are written into the video track of MOV/MP4 files, and +not at the top level like other XMP tags. See L<https://github.com/google/spatial-media/blob/master/docs/spherical-video-rfc.md> for the specification. @@ -2433,15 +4433,15 @@ These tags belong to the ExifTool XMP-ics family 1 group. LabelName1 string_+ ParentReference1 string_+ Reference1 string_+ - SubLables1 TagStructure Struct_+ + SubLabels1 TagStructure Struct_+ LabelName2 string_+ ParentReference2 string_+ Reference2 string_+ - SubLables2 TagStructure Struct_+ + SubLabels2 TagStructure Struct_+ LabelName3 string_+ ParentReference3 string_+ Reference3 string_+ - SubLables3 TagStructure Struct_+ + SubLabels3 TagStructure Struct_+ LabelName4 string_+ ParentReference4 string_+ Reference4 string_+ @@ -2482,6 +4482,7 @@ These tags belong to the ExifTool XMP-iptcCore family 1 group. Tag Name Writable -------- -------- + AltTextAccessibility lang-alt CountryCode string CreatorContactInfo ContactInfo Struct CreatorCity string_ @@ -2492,6 +4493,7 @@ These tags belong to the ExifTool XMP-iptcCore family 1 group. CreatorWorkEmail string_ CreatorWorkTelephone string_ CreatorWorkURL string_ + ExtDescrAccessibility lang-alt IntellectualGenre string Location string Scene string+ @@ -2512,9 +4514,11 @@ These tags belong to the ExifTool XMP-iptcCore family 1 group. =head3 XMP iptcExt Tags -IPTC Extension namespace tags. The actual namespace prefix is -"Iptc4xmpExt", but ExifTool shortens this for the family 1 group name. (see -L<http://www.iptc.org/IPTC4XMP/>) +This table contains tags defined by the IPTC Extension schema version 1.6 +and IPTC Video Metadata version 1.3. The actual namespace prefix is +"Iptc4xmpExt", but ExifTool shortens this for the family 1 group name. (See +L<http://www.iptc.org/standards/photo-metadata/iptc-standard/> and +L<https://iptc.org/standards/video-metadata-hub/>.) These tags belong to the ExifTool XMP-iptcExt family 1 group. @@ -2590,6 +4594,7 @@ These tags belong to the ExifTool XMP-iptcExt family 1 group. ShownEvent Entity Struct+ ShownEventIdentifier string_+ ShownEventName lang-alt_+ + EventID string+ ExternalMetadataLink string+ FeedIdentifier string Genre CVTermDetails Struct+ @@ -2598,6 +4603,26 @@ These tags belong to the ExifTool XMP-iptcExt family 1 group. GenreCvTermName lang-alt_+ GenreCvTermRefinedAbout string_+ Headline lang-alt/ + ImageRegion ImageRegion Struct+ + ImageRegionName lang-alt_+ + ImageRegionCtype Entity Struct_+ + ImageRegionCtypeIdentifier string_+ + ImageRegionCtypeName lang-alt_+ + ImageRegionBoundary RegionBoundary Struct_+ + ImageRegionBoundaryH real_+ + ImageRegionBoundaryRx real_+ + ImageRegionBoundaryShape string_+ + ImageRegionBoundaryUnit string_+ + ImageRegionBoundaryVertices BoundaryPoint Struct_+ + ImageRegionBoundaryVerticesX real_+ + ImageRegionBoundaryVerticesY real_+ + ImageRegionBoundaryW real_+ + ImageRegionBoundaryX real_+ + ImageRegionBoundaryY real_+ + ImageRegionID string_+ + ImageRegionRole Entity Struct_+ + ImageRegionRoleIdentifier string_+ + ImageRegionRoleName lang-alt_+ IPTCLastEdited date LinkedEncRightsExpr LEREDetails Struct+ LinkedEncodedRightsExpr string_+ @@ -2631,9 +4656,17 @@ These tags belong to the ExifTool XMP-iptcExt family 1 group. LocationShownWorldRegion string_+ MaxAvailHeight integer MaxAvailWidth integer + MetadataAuthority Entity Struct + MetadataAuthorityIdentifier string_+ + MetadataAuthorityName lang-alt_ + MetadataLastEdited date + MetadataLastEditor Entity Struct + MetadataLastEditorIdentifier string_+ + MetadataLastEditorName lang-alt_ ModelAge integer+ OrganisationInImageCode string+ OrganisationInImageName string+ + ParentID string PersonHeard Entity Struct+ PersonHeardIdentifier string_+ PersonHeardName lang-alt_+ @@ -2660,7 +4693,7 @@ These tags belong to the ExifTool XMP-iptcExt family 1 group. PublicationEventIdentifier string_+ PublicationEventName string_+ Rating Rating Struct+ - RatingRatingRegion LocationDetails Struct_+ + RatingRegion LocationDetails Struct_+ RatingRegionCity string_+ RatingRegionCountryCode string_+ RatingRegionCountryName string_+ @@ -2822,6 +4855,41 @@ These tags belong to the ExifTool XMP-iptcExt family 1 group. Name string Number string +=head3 XMP ImageRegion Struct + +This structure is new in the IPTC Extension version 1.5 specification. As +well as the fields defined below, this structure may contain any top-level +XMP tags, but since they aren't pre-defined the only way to add these tags +is to write ImageRegion as a structure with these tags as new fields. + + Field Name Writable + ---------- -------- + Name lang-alt + RegionBoundary RegionBoundary Struct + RCtype Entity Struct+ + RId string + RRole Entity Struct+ + +=head3 XMP RegionBoundary Struct + + Field Name Writable + ---------- -------- + RbH real + RbRx real + RbShape string + RbUnit string + RbVertices BoundaryPoint Struct+ + RbW real + RbX real + RbY real + +=head3 XMP BoundaryPoint Struct + + Field Name Writable + ---------- -------- + RbX real + RbY real + =head3 XMP LEREDetails Struct Field Name Writable @@ -2840,7 +4908,6 @@ These tags belong to the ExifTool XMP-iptcExt family 1 group. GPSAltitude rational GPSLatitude string GPSLongitude string - GROUPS string Identifier string+ LocationId string+ LocationName lang-alt @@ -2958,6 +5025,7 @@ These tags belong to the ExifTool XMP-lr family 1 group. -------- -------- HierarchicalSubject string+ PrivateRTKInfo string + WeightedFlatSubject string+ =head3 XMP MediaPro Tags @@ -3052,7 +5120,7 @@ These tags belong to the ExifTool XMP-photoshop family 1 group. =head3 XMP PixelLive Tags -PixelLive namespace tags. These tags are not writable becase they are very +PixelLive namespace tags. These tags are not writable because they are very uncommon and I haven't been able to locate a reference which gives the namespace URI. @@ -3124,20 +5192,20 @@ These tags belong to the ExifTool XMP-prism family 1 group. AggregateIssueNumber integer/ AggregationType string/+ AlternateTitle prismAlternateTitle Struct+ - AlternateTitleA-lang string_+ - AlternateTitleA-platform string_+ - AlternateTitleText string_+ + AlternateTitleA-lang string/_+ + AlternateTitleA-platform string/_+ + AlternateTitleText string/_+ BlogTitle string/ BlogURL string/ BookEdition string/ ByteCount integer/ Channel prismChannel Struct+ - ChannelA-lang string_+ - ChannelChannel string_+ - ChannelSubchannel1 string_+ - ChannelSubchannel2 string_+ - ChannelSubchannel3 string_+ - ChannelSubchannel4 string_+ + ChannelA-lang string/_+ + ChannelChannel string/_+ + ChannelSubchannel1 string/_+ + ChannelSubchannel2 string/_+ + ChannelSubchannel3 string/_+ + ChannelSubchannel4 string/_+ ComplianceProfile string/ ContentType string/ CopyrightYear string/ @@ -3156,9 +5224,9 @@ These tags belong to the ExifTool XMP-prism family 1 group. Genre string/+ HasAlternative string/+ HasCorrection prismHasCorrection Struct - HasCorrectionA-lang string_ - HasCorrectionA-platform string_ - HasCorrectionText string_ + HasCorrectionA-lang string/_ + HasCorrectionA-platform string/_ + HasCorrectionText string/_ HasTranslation string/+ Industry string/+ IsAlternativeOf string/+ @@ -3172,8 +5240,8 @@ These tags belong to the ExifTool XMP-prism family 1 group. IsTranslationOf string/ Keyword string/+ KillDate prismKillDate Struct - KillDateA-platform string_ - KillDateDate date_ + KillDateA-platform string/_ + KillDateDate date/_ Link string/+ Location string/+ ModificationDate date/ @@ -3181,14 +5249,14 @@ These tags belong to the ExifTool XMP-prism family 1 group. Number string/ Object string/+ OffSaleDate prismOffSaleDate Struct+ - OffSaleDateA-platform string_+ - OffSaleDateDate date_+ + OffSaleDateA-platform string/_+ + OffSaleDateDate date/_+ OnSaleDate prismOnSaleDate Struct+ - OnSaleDateA-platform string_+ - OnSaleDateDate date_+ + OnSaleDateA-platform string/_+ + OnSaleDateDate date/_+ OnSaleDay prismOnSaleDay Struct+ - OnSaleDayA-platform string_+ - OnSaleDayDay string_+ + OnSaleDayA-platform string/_+ + OnSaleDayDay string/_+ Organization string/+ OriginPlatform string/+ PageCount integer/ @@ -3199,11 +5267,11 @@ These tags belong to the ExifTool XMP-prism family 1 group. ProductCode string/ Profession string/ PublicationDate prismPublicationDate Struct+ - PublicationDateA-platform string_+ - PublicationDateDate date_+ + PublicationDateA-platform string/_+ + PublicationDateDate date/_+ PublicationDisplayDate prismPublicationDate Struct+ - PublicationDisplayDateA-platform string_+ - PublicationDisplayDateDate date_+ + PublicationDisplayDateA-platform string/_+ + PublicationDisplayDateDate date/_+ PublicationName string/ PublishingFrequency string/ Rating string/ @@ -3226,8 +5294,8 @@ These tags belong to the ExifTool XMP-prism family 1 group. Ticker string/+ TimePeriod string/ URL prismUrl Struct+ - URLA-platform string_+ - URLUrl string_+ + URLA-platform string/_+ + URLUrl string/_+ UspsNumber string/ VersionIdentifier string/ Volume string/ @@ -3396,8 +5464,8 @@ These tags belong to the ExifTool XMP-swf family 1 group. =head3 XMP tiff Tags EXIF namespace for TIFF tags. See -L<http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf> for the -specification. +L<https://web.archive.org/web/20180921145139if_/http://www.cipa.jp:80/std/documents/e/DC-010-2017_E.pdf> +for the specification. These tags belong to the ExifTool XMP-tiff family 1 group. @@ -3413,7 +5481,7 @@ These tags belong to the ExifTool XMP-tiff family 1 group. ImageWidth integer Make string Model string - NativeDigest string + NativeDigest string/ Orientation integer PhotometricInterpretation integer PlanarConfiguration integer @@ -3473,6 +5541,7 @@ These tags belong to the ExifTool XMP-xmp family 1 group. PageImagePageNumber integer_+ PageImageWidth integer_+ Rating real + RatingPercent real/ Thumbnails Thumbnail Struct+ ThumbnailFormat string_+ ThumbnailHeight integer_+ @@ -3921,6 +5990,7 @@ These tags belong to the ExifTool XMP-xmpMM family 1 group. ManifestReferenceVersionID string_+ OriginalDocumentID string Pantry PantryItem Struct+ + PantryInstanceID string_ PreservedFileName string RenditionClass string RenditionOf ResourceRef Struct @@ -4481,32 +6551,98 @@ specification. 'A2B0' AToB0 no 'A2B1' AToB1 no 'A2B2' AToB2 no + 'A2B3' AToB3 no + 'A2M0' AToM0 no 'B2A0' BToA0 no 'B2A1' BToA1 no 'B2A2' BToA2 no + 'B2A3' BToA3 no 'B2D0' BToD0 no 'B2D1' BToD1 no 'B2D2' BToD2 no 'B2D3' BToD3 no + 'CxF ' CXF no 'D2B0' DToB0 no 'D2B1' DToB1 no 'D2B2' DToB2 no 'D2B3' DToB3 no 'Header' ProfileHeader ICC_Profile Header + 'M2A0' MToA0 no + 'M2B0' MToB0 no + 'M2B1' MToB1 no + 'M2B2' MToB2 no + 'M2B3' MToB3 no + 'M2S0' MToS0 no + 'M2S1' MToS1 no + 'M2S2' MToS2 no + 'M2S3' MToS3 no 'MS00' WCSProfiles no + 'bAB0' BRDFAToB0 no + 'bAB1' BRDFAToB1 no + 'bAB2' BRDFAToB2 no + 'bAB3' BRDFAToB3 no + 'bBA0' BRDFBToA0 no + 'bBA1' BRDFBToA1 no + 'bBA2' BRDFBToA2 no + 'bBA3' BRDFBToA3 no + 'bBD0' BRDFBToD0 no + 'bBD1' BRDFBToD1 no + 'bBD2' BRDFBToD2 no + 'bBD3' BRDFBToD3 no + 'bDB0' BRDFDToB0 no + 'bDB1' BRDFDToB1 no + 'bDB2' BRDFDToB2 no + 'bDB3' BRDFDToB3 no + 'bMB0' BRDFMToB0 no + 'bMB1' BRDFMToB1 no + 'bMB2' BRDFMToB2 no + 'bMB3' BRDFMToB3 no + 'bMS0' BRDFMToS0 no + 'bMS1' BRDFMToS1 no + 'bMS2' BRDFMToS2 no + 'bMS3' BRDFMToS3 no 'bTRC' BlueTRC no 'bXYZ' BlueMatrixColumn no + 'bcp0' BRDFColorimetricParam0 no + 'bcp1' BRDFColorimetricParam1 no + 'bcp2' BRDFColorimetricParam2 no + 'bcp3' BRDFColorimetricParam3 no 'bfd ' UCRBG no 'bkpt' MediaBlackPoint no + 'bsp0' BRDFSpectralParam0 no + 'bsp1' BRDFSpectralParam1 no + 'bsp2' BRDFSpectralParam2 no + 'bsp3' BRDFSpectralParam3 no + 'c2sp' CustomToStandardPcc no 'calt' CalibrationDateTime no + 'cept' ColorEncodingParams no 'chad' ChromaticAdaptation no 'chrm' Chromaticity ICC_Profile Chromaticity 'ciis' ColorimetricIntentImageState no + 'clio' ColorantInfoOut no + 'cloo' ColorantOrderOut no 'clot' ColorantTableOut no 'clro' ColorantOrder no 'clrt' ColorantTable ICC_Profile ColorantTable 'cprt' ProfileCopyright no 'crdi' CRDInfo no + 'csnm' ColorSpaceName no + 'dAB0' DirectionalAToB0 no + 'dAB1' DirectionalAToB1 no + 'dAB2' DirectionalAToB2 no + 'dAB3' DirectionalAToB3 no + 'dBA0' DirectionalBToA0 no + 'dBA1' DirectionalBToA1 no + 'dBA2' DirectionalBToA2 no + 'dBA3' DirectionalBToA3 no + 'dBD0' DirectionalBToD0 no + 'dBD1' DirectionalBToD1 no + 'dBD2' DirectionalBToD2 no + 'dBD3' DirectionalBToD3 no + 'dDB0' DirectionalDToB0 no + 'dDB1' DirectionalDToB1 no + 'dDB2' DirectionalDToB2 no + 'dDB3' DirectionalDToB3 no 'desc' ProfileDescription no 'devs' DeviceSettings no 'dmdd' DeviceModelDesc no @@ -4516,14 +6652,23 @@ specification. 'gTRC' GreenTRC no 'gXYZ' GreenMatrixColumn no 'gamt' Gamut no + 'gdb0' GamutBoundaryDescription0 no + 'gdb1' GamutBoundaryDescription1 no + 'gdb2' GamutBoundaryDescription2 no + 'gdb3' GamutBoundaryDescription3 no 'kTRC' GrayTRC no 'lumi' Luminance no + 'mcta' MultiplexTypeArray no + 'mdv ' MultiplexDefaultValues no 'meas' Measurement ICC_Profile Measurement 'meta' Metadata ICC_Profile Metadata + 'miin' MeasurementInputInfo no + 'minf' MeasurementInfo no 'mmod' MakeAndModel no 'ncl2' NamedColor2 no 'ncol' NamedColor no 'ndin' NativeDisplayInfo no + 'nmcl' NamedColor no 'pre0' Preview0 no 'pre1' Preview1 no 'pre2' Preview2 no @@ -4535,18 +6680,24 @@ specification. 'psd3' PostScript2CRD3 no 'pseq' ProfileSequenceDesc no 'psid' ProfileSequenceIdentifier no + 'psin' ProfileSequenceInfo no 'psvm' PS2CRDVMSize no 'rTRC' RedTRC no 'rXYZ' RedMatrixColumn no 'resp' OutputResponse no + 'rfnm' ReferenceName no 'rhoc' ReflectionHardcopyOrigColorimetry no 'rig0' PerceptualRenderingIntentGamut no 'rig2' SaturationRenderingIntentGamut no 'rpoc' ReflectionPrintOutputColorimetry no + 's2cp' StandardToCustomPcc no 'sape' SceneAppearanceEstimates no 'scoe' SceneColorimetryEstimates no 'scrd' ScreeningDesc no 'scrn' Screening no + 'smap' SurfaceMap no + 'svcn' SpectralViewingConditions no + 'swpt' SpectralWhitePoint no 'targ' CharTarget no 'tech' Technology no 'vcgt' VideoCardGamma no @@ -4615,6 +6766,7 @@ Metadata tags that exist. Tag Name Writable -------- -------- + CreatorApp no ManufacturerName no MediaColor no MediaWeight no @@ -4839,7 +6991,8 @@ Tags extracted from the maker notes of iPhone images. 0x0008 AccelerationVector rational64s[3] 0x000a HDRImageType int32s 0x000b BurstUUID string - 0x0011 ContentIdentifier string + 0x000c FocusDistanceRange rational64s[2] + 0x0011 MediaGroupUUID string 0x0015 ImageUniqueID string =head3 Apple RunTime Tags @@ -4855,6 +7008,219 @@ boot, not including standby time. 'timescale' RunTimeScale no 'value' RunTimeValue no +=head2 NikonSettings Tags + +User settings for newer Nikon models. A number of the tags are marked as +Unknown only to reduce the volume of the normal output. + + Tag ID Tag Name Writable + ------ -------- -------- + 0x0001 ISOAutoHiLimit no + 0x0002 ISOAutoFlashLimit no + 0x0003 ISOAutoShutterTime no + 0x000b FlickerReductionShooting no + 0x000c FlickerReductionIndicator no + 0x000d MovieISOAutoHiLimit no + 0x000e MovieISOAutoControlManualMode no + 0x000f MovieWhiteBalanceSameAsPhoto no + 0x001d AF-CPrioritySel no + 0x001e AF-SPrioritySel no + 0x0020 AFPointSel no + 0x0022 AFActivation no + 0x0023 FocusPointWrap no + 0x0025 ManualFocusPointIllumination no + 0x0026 AF-AssistIlluminator no + 0x0027 ManualFocusRingInAFMode no + 0x0029 ISOStepSize no + 0x002a ExposureControlStepSize no + 0x002b EasyExposureCompensation no + 0x002c MatrixMetering no + 0x002d CenterWeightedAreaSize no + 0x002f FineTuneOptMatrixMetering no + 0x0030 FineTuneOptCenterWeighted no + 0x0031 FineTuneOptSpotMetering no + 0x0032 FineTuneOptHighlightWeighted no + 0x0033 ShutterReleaseButtonAE-L no + 0x0034 StandbyMonitorOffTime no + 0x0035 SelfTimerTime no + 0x0036 SelfTimerShotCount no + 0x0037 SelfTimerShotInterval no + 0x0038 PlaybackMonitorOffTime no + 0x0039 MenuMonitorOffTime no + 0x003a ShootingInfoMonitorOffTime no + 0x003b ImageReviewMonitorOffTime no + 0x003c LiveViewMonitorOffTime no + 0x003e CLModeShootingSpeed no + 0x003f MaxContinuousRelease no + 0x0040 ExposureDelayMode no + 0x0041 ElectronicFront-CurtainShutter no + 0x0042 FileNumberSequence no + 0x0043 FramingGridDisplay no + 0x0045 LCDIllumination no + 0x0046 OpticalVR no + 0x0047 FlashSyncSpeed no + 0x0048 FlashShutterSpeed no + 0x0049 FlashExposureCompArea no + 0x004a AutoFlashISOSensitivity no + 0x0051 AssignBktButton no + 0x0052 AssignMovieRecordButton no + 0x0053 MultiSelectorShootMode no + 0x0054 MultiSelectorPlaybackMode no + 0x0056 MultiSelectorLiveView no + 0x0058 CmdDialsReverseRotExposureComp? no + 0x0059 CmdDialsChangeMainSubExposure? no + 0x005a CmdDialsChangeMainSub no + 0x005b CmdDialsMenuAndPlayback no + 0x005c SubDialFrameAdvance no + 0x005d ReleaseButtonToUseDial no + 0x005e ReverseIndicators no + 0x0062 MovieShutterButton no + 0x0063 Language no + 0x006c ShootingInfoDisplay no + 0x0074 FlickAdvanceDirection no + 0x0075 HDMIOutputResolution no + 0x0077 HDMIOutputRange no + 0x0080 RemoteFuncButton no + 0x008b CmdDialsReverseRotation no + 0x008d FocusPeakingHighlightColor no + 0x008e ContinuousModeDisplay no + 0x008f ShutterSpeedLock no + 0x0090 ApertureLock no + 0x0091 MovieHighlightDisplayThreshold no + 0x0092 HDMIExternalRecorder no + 0x0093 BlockShotAFResponse no + 0x0094 SubjectMotion no + 0x0095 Three-DTrackingFaceDetection no + 0x0097 StoreByOrientation no + 0x0099 DynamicAreaAFAssist no + 0x009a ExposureCompStepSize no + 0x009b SyncReleaseMode no + 0x009c ModelingFlash no + 0x009d AutoBracketModeM no + 0x009e PreviewButton no + 0x00a0 Func1Button no + 0x00a2 Func2Button no + 0x00a3 AF-OnButton no + 0x00a4 SubSelector no + 0x00a5 SubSelectorCenter no + 0x00a7 LensFunc1Button no + 0x00a8 CmdDialsApertureSetting no + 0x00a9 MultiSelector no + 0x00aa LiveViewButtonOptions no + 0x00ab LightSwitch no + 0x00b1 MoviePreviewButton no + MovieFunc1Button no + 0x00b3 MovieFunc1Button no + MovieFunc2Button no + 0x00b5 MovieFunc2Button no + 0x00b6 AssignMovieSubselector no + 0x00b8 LimitAFAreaModeSelD9? no + 0x00b9 LimitAFAreaModeSelD25? no + 0x00bc LimitAFAreaModeSel3D? no + 0x00bd LimitAFAreaModeSelGroup? no + 0x00be LimitAFAreaModeSelAuto? no + 0x00c1 LimitSelectableImageArea5To4? no + 0x00c2 LimitSelectableImageArea1To1? no + 0x00d4 PhotoShootingMenuBank no + 0x00d5 CustomSettingsBank no + 0x00d6 LimitAF-AreaModeSelPinpoint? no + 0x00d7 LimitAF-AreaModeSelDynamic? no + 0x00d8 LimitAF-AreaModeSelWideAF_S? no + 0x00d9 LimitAF-AreaModeSelWideAF_L? no + 0x00da LowLightAF no + 0x00db LimitSelectableImageAreaDX? no + 0x00dc LimitSelectableImageArea5To4? no + 0x00dd LimitSelectableImageArea1To1? no + 0x00de LimitSelectableImageArea16To9? no + 0x00df ApplySettingsToLiveView no + 0x00e0 FocusPeakingLevel no + 0x00ea LensControlRing no + 0x00ed MovieMultiSelector no + 0x00ee MovieAFSpeed no + 0x00ef MovieAFSpeedApply no + 0x00f0 MovieAFTrackingSensitivity no + 0x00f1 MovieHighlightDisplayPattern no + 0x00f2 SubDialFrameAdvanceRating5? no + 0x00f3 SubDialFrameAdvanceRating4? no + 0x00f4 SubDialFrameAdvanceRating3? no + 0x00f5 SubDialFrameAdvanceRating2? no + 0x00f6 SubDialFrameAdvanceRating1? no + 0x00f7 SubDialFrameAdvanceRating0? no + 0x00f9 MovieAF-OnButton no + 0x00fb SecondarySlotFunction no + 0x00fc SilentPhotography no + 0x00fd ExtendedShutterSpeeds no + 0x0102 HDMIBitDepth no + 0x0103 HDMIOutputHDR no + 0x0104 HDMIViewAssist no + 0x0109 BracketSet no + 0x010a BracketProgram no + 0x010b BracketIncrement no + 0x010c BracketIncrement no + 0x010e MonitorBrightness no + 0x0116 GroupAreaC1 no + 0x0117 AutoAreaAFStartingPoint no + 0x0118 FocusPointPersistence no + 0x0119 LimitAFAreaModeSelD49? no + 0x011a LimitAFAreaModeSelD105? no + 0x011b LimitAFAreaModeSelGroupC1? no + 0x011c LimitAFAreaModeSelGroupC2? no + 0x011d AutoFocusModeRestrictions no + 0x011e FocusPointBrightness no + 0x011f CHModeShootingSpeed no + 0x0120 CLModeShootingSpeed no + 0x0121 QuietShutterShootingSpeed no + 0x0122 LimitReleaseModeSelCL? no + 0x0123 LimitReleaseModeSelCH? no + 0x0124 LimitReleaseModeSelQ? no + 0x0125 LimitReleaseModeSelTimer? no + 0x0126 LimitReleaseModeSelMirror-Up? no + 0x0127 LimitSelectableImageArea16To9? no + 0x0128 RearControPanelDisplay no + 0x0129 FlashBurstPriority no + 0x012a RecallShootFuncExposureMode no + 0x012b RecallShootFuncShutterSpeed no + 0x012c RecallShootFuncAperture no + 0x012d RecallShootFuncExposureComp no + 0x012e RecallShootFuncISO no + 0x012f RecallShootFuncMeteringMode no + 0x0130 RecallShootFuncWhiteBalance no + 0x0131 RecallShootFuncAFAreaMode no + 0x0132 RecallShootFuncFocusTracking no + 0x0133 RecallShootFuncAF-On no + 0x0134 VerticalFuncButton no + 0x0135 Func3Button no + 0x0136 VerticalAF-OnButton no + 0x0137 VerticalMultiSelector no + 0x0138 MeteringButton no + 0x0139 PlaybackFlickUp no + 0x013a PlaybackFlickUpRating no + 0x013b PlaybackFlickDown no + 0x013c PlaybackFlickDownRating no + 0x013d MovieFunc3Button no + 0x0150 ShutterType no + 0x0151 LensFunc2Button no + 0x0158 USBPowerDelivery no + 0x0159 EnergySavingMode no + 0x015c BracketingBurstOptions no + 0x015e PrimarySlot no + 0x015f ReverseFocusRing no + 0x0160 VerticalFuncButton no + 0x0161 VerticalAFOnButton no + 0x0162 VerticalMultiSelector no + 0x0164 VerticalMovieFuncButton no + 0x0165 VerticalMovieAFOnButton no + 0x0169 LimitAF-AreaModeSelAutoPeople? no + 0x016a LimitAF-AreaModeSelAutoAnimals? no + 0x016b LimitAF-AreaModeSelWideLPeople? no + 0x016c LimitAF-AreaModeSelWideLAnimals? no + 0x016d SaveFocus no + 0x016e AFAreaMode no + 0x016f MovieAFAreaMode no + 0x0170 PreferSubSelectorCenter no + 0x0171 KeepExposureWithTeleconverter no + 0x0174 FocusPointSelectionSpeed no + =head2 Canon Tags Tag ID Tag Name Writable @@ -4928,6 +7294,7 @@ boot, not including standby time. 0x0026 CanonAFInfo2 Canon AFInfo2 0x0027 ContrastInfo Canon ContrastInfo 0x0028 ImageUniqueID int8u + 0x0029 WBInfo Canon WBInfo 0x002f FaceDetect3 Canon FaceDetect3 0x0035 TimeInfo Canon TimeInfo 0x0038 BatteryType undef @@ -4971,6 +7338,8 @@ boot, not including standby time. ColorData7 Canon ColorData7 ColorData8 Canon ColorData8 ColorData9 Canon ColorData9 + ColorData10 Canon ColorData10 + ColorData11 Canon ColorData11 ColorDataUnknown Canon ColorDataUnknown 0x4002 CRWParam? no 0x4003 ColorInfo Canon ColorInfo @@ -4991,7 +7360,9 @@ boot, not including standby time. 0x4021 MultiExp Canon MultiExp 0x4024 FilterInfo Canon FilterInfo 0x4025 HDRInfo Canon HDRInfo + 0x4026 LogInfo Canon LogInfo 0x4028 AFConfig Canon AFConfig + 0x403f RawBurstModeRoll Canon RawBurstInfo =head3 Canon CameraSettings Tags @@ -5630,6 +8001,7 @@ CameraInfo tags for the EOS 60D and 1200D. 25 CameraTemperature int8u 30 FocalLength int16uRev 54 CameraOrientation int8u + 58 CameraOrientation int8u 85 FocusDistanceUpper int16uRev 87 FocusDistanceLower int16uRev 125 ColorTemperature int16u @@ -5667,7 +8039,7 @@ CameraInfo tags for the EOS 70D. =head3 Canon CameraInfo80D Tags -CameraInfo tags for the EOS 70D. +CameraInfo tags for the EOS 80D. Index1 Tag Name Writable ------ -------- -------- @@ -5835,6 +8207,7 @@ CameraInfo tags for the EOS 750D and 760D. 6 ISO int8u 27 CameraTemperature int8u 35 FocalLength int16uRev + 150 CameraOrientation int8u 165 FocusDistanceUpper int16uRev 167 FocusDistanceLower int16uRev 305 WhiteBalance int16u @@ -5932,6 +8305,7 @@ Unknown CameraInfo tags are divided into 3 tables based on format size. Index1 Tag Name Writable ------ -------- -------- 363 LensSerialNumber undef[5] + 1473 FirmwareVersion no =head3 Canon MovieInfo Tags @@ -6036,6 +8410,23 @@ may be 7, 9, 11, 19, 31, 45 or 61, depending on the camera model. ------ -------- -------- 4 IntelligentContrast int16u +=head3 Canon WBInfo Tags + +WB tags for the Canon G9. + + Index4 Tag Name Writable + ------ -------- -------- + 2 WB_GRBGLevelsAuto int32s[4] + 10 WB_GRBGLevelsDaylight int32s[4] + 18 WB_GRBGLevelsCloudy int32s[4] + 26 WB_GRBGLevelsTungsten int32s[4] + 34 WB_GRBGLevelsFluorescent int32s[4] + 42 WB_GRBGLevelsFluorHigh int32s[4] + 50 WB_GRBGLevelsFlash int32s[4] + 58 WB_GRBGLevelsUnderwater int32s[4] + 66 WB_GRBGLevelsCustom1 int32s[4] + 74 WB_GRBGLevelsCustom2 int32s[4] + =head3 Canon FaceDetect3 Tags Index2 Tag Name Writable @@ -6071,7 +8462,9 @@ may be 7, 9, 11, 19, 31, 45 or 61, depending on the camera model. 19 LiveViewShooting int16s 20 FocusDistanceUpper int16u 21 FocusDistanceLower int16u + 23 ShutterMode int16s 25 FlashExposureLock int16s + 61 RFLensType int16u =head3 Canon SerialInfo Tags @@ -6130,6 +8523,7 @@ These tags are used by the 10D and 300D. 21 WB_RGGBLevelsFluorescent int16s[4] 25 WB_RGGBLevelsFlash int16s[4] 29 WB_RGGBLevelsCustom int16s[4] + BlackLevels int16s[4] 33 WB_RGGBLevelsKelvin int16s[4] 37 WB_RGGBBlackLevels int16s[4] @@ -6435,6 +8829,8 @@ These tags are used by many EOS M and PowerShot models. 255 ColorCalib2? Canon ColorCalib2 264 PerChannelBlackLevel int16s[4] 333 PerChannelBlackLevel int16s[4] + 1385 NormalWhiteLevel int16u + 1386 SpecularWhiteLevel int16u =head3 Canon ColorCoefs2 Tags @@ -6576,7 +8972,8 @@ These tags are used by the EOS 600D and 1200D. =head3 Canon ColorData7 Tags -These tags are used by the EOS 1DX, 5DmkIII, 6D, 100D, 650D, 700D, M and 7DmkII. +These tags are used by the EOS 1DX, 5DmkIII, 6D, 7DmkII, 100D, 650D, 700D, +8000D, M and M2. Index2 Tag Name Writable ------ -------- -------- @@ -6656,6 +9053,9 @@ These tags are used by the EOS 1DX, 5DmkIII, 6D, 100D, 650D, 700D, M and 7DmkII. =head3 Canon ColorData8 Tags +These tags are used by the EOS 1DXmkII, 5DS, 5DSR, 5DmkIV, 6DmkII, 77D, 80D, +200D, 800D, 1300D, 2000D, 4000D and 9000D. + Index2 Tag Name Writable ------ -------- -------- 0 ColorDataVersion int16s @@ -6752,6 +9152,8 @@ These tags are used by the EOS 1DX, 5DmkIII, 6D, 100D, 650D, 700D, M and 7DmkII. =head3 Canon ColorData9 Tags +These tags are used by the M6mkII, M50, M200, EOS R, RP, 90D, 250D and 850D + Index2 Tag Name Writable ------ -------- -------- 0 ColorDataVersion int16s @@ -6839,6 +9241,186 @@ These tags are used by the EOS 1DX, 5DmkIII, 6D, 100D, 650D, 700D, M and 7DmkII. 797 SpecularWhiteLevel int16u 798 LinearityUpperMargin int16u +=head3 Canon ColorData10 Tags + +These tags are used by the R5, R5 and EOS 1DXmkIII. + + Index2 Tag Name Writable + ------ -------- -------- + 0 ColorDataVersion int16s + 85 WB_RGGBLevelsAsShot int16s[4] + 89 ColorTempAsShot int16s + 90 WB_RGGBLevelsAuto int16s[4] + 94 ColorTempAuto int16s + 95 WB_RGGBLevelsMeasured int16s[4] + 99 ColorTempMeasured int16s + 100 WB_RGGBLevelsUnknown? int16s[4] + 104 ColorTempUnknown? int16s + 105 WB_RGGBLevelsUnknown2? int16s[4] + 109 ColorTempUnknown2? int16s + 110 WB_RGGBLevelsUnknown3? int16s[4] + 114 ColorTempUnknown3? int16s + 115 WB_RGGBLevelsUnknown4? int16s[4] + 119 ColorTempUnknown4? int16s + 120 WB_RGGBLevelsUnknown5? int16s[4] + 124 ColorTempUnknown5? int16s + 125 WB_RGGBLevelsUnknown6? int16s[4] + 129 ColorTempUnknown6? int16s + 130 WB_RGGBLevelsUnknown7? int16s[4] + 134 ColorTempUnknown7? int16s + 135 WB_RGGBLevelsUnknown8? int16s[4] + 139 ColorTempUnknown8? int16s + 140 WB_RGGBLevelsUnknown9? int16s[4] + 144 ColorTempUnknown9? int16s + 145 WB_RGGBLevelsUnknown10? int16s[4] + 149 ColorTempUnknown10? int16s + 150 WB_RGGBLevelsDaylight int16s[4] + 154 ColorTempDaylight int16s + 155 WB_RGGBLevelsShade int16s[4] + 159 ColorTempShade int16s + 160 WB_RGGBLevelsCloudy int16s[4] + 164 ColorTempCloudy int16s + 165 WB_RGGBLevelsTungsten int16s[4] + 169 ColorTempTungsten int16s + 170 WB_RGGBLevelsFluorescent int16s[4] + 174 ColorTempFluorescent int16s + 175 WB_RGGBLevelsKelvin int16s[4] + 179 ColorTempKelvin int16s + 180 WB_RGGBLevelsFlash int16s[4] + 184 ColorTempFlash int16s + 185 WB_RGGBLevelsUnknown11? int16s[4] + 189 ColorTempUnknown11? int16s + 190 WB_RGGBLevelsUnknown12? int16s[4] + 194 ColorTempUnknown12? int16s + 195 WB_RGGBLevelsUnknown13? int16s[4] + 199 ColorTempUnknown13? int16s + 200 WB_RGGBLevelsUnknown14? int16s[4] + 204 ColorTempUnknown14? int16s + 205 WB_RGGBLevelsUnknown15? int16s[4] + 209 ColorTempUnknown15? int16s + 210 WB_RGGBLevelsUnknown16? int16s[4] + 214 ColorTempUnknown16? int16s + 215 WB_RGGBLevelsUnknown17? int16s[4] + 219 ColorTempUnknown17? int16s + 220 WB_RGGBLevelsUnknown18? int16s[4] + 224 ColorTempUnknown18? int16s + 225 WB_RGGBLevelsUnknown19? int16s[4] + 229 ColorTempUnknown19? int16s + 230 WB_RGGBLevelsUnknown20? int16s[4] + 234 ColorTempUnknown20? int16s + 235 WB_RGGBLevelsUnknown21? int16s[4] + 239 ColorTempUnknown21? int16s + 240 WB_RGGBLevelsUnknown22? int16s[4] + 244 ColorTempUnknown22? int16s + 245 WB_RGGBLevelsUnknown23? int16s[4] + 249 ColorTempUnknown23? int16s + 250 WB_RGGBLevelsUnknown24? int16s[4] + 254 ColorTempUnknown24? int16s + 255 WB_RGGBLevelsUnknown25? int16s[4] + 259 ColorTempUnknown25? int16s + 260 WB_RGGBLevelsUnknown26? int16s[4] + 264 ColorTempUnknown26? int16s + 265 WB_RGGBLevelsUnknown27? int16s[4] + 269 ColorTempUnknown27? int16s + 270 WB_RGGBLevelsUnknown28? int16s[4] + 274 ColorTempUnknown28? int16s + 275 WB_RGGBLevelsUnknown29? int16s[4] + 279 ColorTempUnknown29? int16s + 280 ColorCalib? Canon ColorCalib + 343 PerChannelBlackLevel int16u[4] + 810 NormalWhiteLevel int16u + 811 SpecularWhiteLevel int16u + 812 LinearityUpperMargin int16u + +=head3 Canon ColorData11 Tags + +These tags are used by the EOS R3 + + Index2 Tag Name Writable + ------ -------- -------- + 0 ColorDataVersion int16s + 105 WB_RGGBLevelsAsShot int16s[4] + 109 ColorTempAsShot int16s + 110 WB_RGGBLevelsAuto int16s[4] + 114 ColorTempAuto int16s + 115 WB_RGGBLevelsMeasured int16s[4] + 119 ColorTempMeasured int16s + 120 WB_RGGBLevelsUnknown? int16s[4] + 124 ColorTempUnknown? int16s + 125 WB_RGGBLevelsUnknown2? int16s[4] + 129 ColorTempUnknown2? int16s + 130 WB_RGGBLevelsUnknown3? int16s[4] + 134 ColorTempUnknown3? int16s + 135 WB_RGGBLevelsUnknown4? int16s[4] + 139 ColorTempUnknown4? int16s + 140 WB_RGGBLevelsUnknown5? int16s[4] + 144 ColorTempUnknown5? int16s + 145 WB_RGGBLevelsUnknown6? int16s[4] + 149 ColorTempUnknown6? int16s + 150 WB_RGGBLevelsUnknown7? int16s[4] + 154 ColorTempUnknown7? int16s + 155 WB_RGGBLevelsUnknown8? int16s[4] + 159 ColorTempUnknown8? int16s + 160 WB_RGGBLevelsUnknown9? int16s[4] + 164 ColorTempUnknown9? int16s + 165 WB_RGGBLevelsUnknown10? int16s[4] + 169 ColorTempUnknown10? int16s + 170 WB_RGGBLevelsUnknown11? int16s[4] + 174 ColorTempUnknown11? int16s + 175 WB_RGGBLevelsUnknown11? int16s[4] + 179 ColorTempUnknown11? int16s + 180 WB_RGGBLevelsUnknown12? int16s[4] + 184 ColorTempUnknown12? int16s + 185 WB_RGGBLevelsUnknown13? int16s[4] + 189 ColorTempUnknown13? int16s + 190 WB_RGGBLevelsUnknown14? int16s[4] + 194 ColorTempUnknown14? int16s + 195 WB_RGGBLevelsUnknown15? int16s[4] + 199 ColorTempUnknown15? int16s + 200 WB_RGGBLevelsUnknown16? int16s[4] + 204 ColorTempUnknown16? int16s + 205 WB_RGGBLevelsDaylight int16s[4] + 209 ColorTempDaylight int16s + 210 WB_RGGBLevelsShade int16s[4] + 214 ColorTempShade int16s + 215 WB_RGGBLevelsCloudy int16s[4] + 219 ColorTempCloudy int16s + 220 WB_RGGBLevelsTungsten int16s[4] + 224 ColorTempTungsten int16s + 225 WB_RGGBLevelsFluorescent int16s[4] + 229 ColorTempFluorescent int16s + 230 WB_RGGBLevelsKelvin int16s[4] + 234 ColorTempKelvin int16s + 235 WB_RGGBLevelsFlash int16s[4] + 239 ColorTempFlash int16s + 240 WB_RGGBLevelsUnknown17? int16s[4] + 244 ColorTempUnknown17? int16s + 245 WB_RGGBLevelsUnknown18? int16s[4] + 249 ColorTempUnknown18? int16s + 250 WB_RGGBLevelsUnknown19? int16s[4] + 254 ColorTempUnknown19? int16s + 255 WB_RGGBLevelsUnknown20? int16s[4] + 259 ColorTempUnknown20? int16s + 260 WB_RGGBLevelsUnknown21? int16s[4] + 264 ColorTempUnknown21? int16s + 265 WB_RGGBLevelsUnknown22? int16s[4] + 269 ColorTempUnknown22? int16s + 270 WB_RGGBLevelsUnknown23? int16s[4] + 274 ColorTempUnknown23? int16s + 275 WB_RGGBLevelsUnknown24? int16s[4] + 279 ColorTempUnknown24? int16s + 280 WB_RGGBLevelsUnknown25? int16s[4] + 284 ColorTempUnknown25? int16s + 285 WB_RGGBLevelsUnknown26? int16s[4] + 289 ColorTempUnknown26? int16s + 290 WB_RGGBLevelsUnknown27? int16s[4] + 294 ColorTempUnknown27? int16s + 300 ColorCalib? Canon ColorCalib + 363 PerChannelBlackLevel int16u[4] + 640 NormalWhiteLevel int16u + 641 SpecularWhiteLevel int16u + 642 LinearityUpperMargin int16u + =head3 Canon ColorDataUnknown Tags Index2 Tag Name Writable @@ -6868,9 +9450,11 @@ This information is found in images from newer EOS models. ------ -------- -------- 0 VignettingCorrVersion no 2 PeripheralLighting int16s + 3 DistortionCorrection int16s 4 ChromaticAberrationCorr int16s 5 ChromaticAberrationCorr int16s 6 PeripheralLightingValue int16s + 9 DistortionCorrectionValue int16s 11 OriginalImageWidth int16s 12 OriginalImageHeight int16s @@ -6888,6 +9472,7 @@ Vignetting correction from PowerShot models. ------ -------- -------- 5 PeripheralLightingSetting int32s 6 ChromaticAberrationSetting int32s + 7 DistortionCorrectionSetting int32s =head3 Canon LightingOpt Tags @@ -6945,6 +9530,18 @@ Information about creative filter settings. 1 HDR int32s 2 HDREffect int32s +=head3 Canon LogInfo Tags + + Index4 Tag Name Writable + ------ -------- -------- + 4 CompressionFormat int32s + 6 Sharpness int32s + 7 Saturation int32s + 8 ColorTone int32s + 9 ColorSpace2 int32s + 10 ColorMatrix int32s + 11 CanonLogVersion int32s + =head3 Canon AFConfig Tags Index4 Tag Name Writable @@ -6969,12 +9566,68 @@ Information about creative filter settings. 18 AFStatusViewfinder int32s 19 InitialAFPointInServo int32s +=head3 Canon RawBurstInfo Tags + + Index4 Tag Name Writable + ------ -------- -------- + 1 RawBurstImageNum int32u + 2 RawBurstImageCount int32u + +=head3 Canon CTMD Tags + +Canon Timed MetaData tags found in CR3 images. The ExtractEmbedded option +is automatically applied when reading CR3 files to be able to extract this +information. + + Tag ID Tag Name Writable + ------ -------- -------- + 0x0001 TimeStamp no + 0x0004 FocalInfo Canon FocalInfo + 0x0005 ExposureInfo Canon ExposureInfo + 0x0007 ExifInfo7 Canon ExifInfo + 0x0008 ExifInfo8 Canon ExifInfo + 0x0009 ExifInfo9 Canon ExifInfo + +=head3 Canon FocalInfo Tags + + Index4 Tag Name Writable + ------ -------- -------- + 0 FocalLength no + +=head3 Canon ExposureInfo Tags + + Index4 Tag Name Writable + ------ -------- -------- + 0 FNumber no + 1 ExposureTime no + 2 ISO no + +=head3 Canon ExifInfo Tags + + Tag ID Tag Name Writable + ------ -------- -------- + 0x8769 ExifIFD EXIF + 0x927c MakerNoteCanon Canon + =head3 Canon CDI1 Tags Tag ID Tag Name Writable ------ -------- -------- + 'IAD1' IAD1 Canon IAD1 + +=head3 Canon IAD1 Tags + + Index2 Tag Name Writable + ------ -------- -------- [no tags known] +=head3 Canon CMP1 Tags + + Index2 Tag Name Writable + ------ -------- -------- + 8 ImageWidth no + 10 ImageHeight no + =head3 Canon CNOP Tags Tag ID Tag Name Writable @@ -6983,12 +9636,12 @@ Information about creative filter settings. =head3 Canon CNTH Tags -Canon-specific QuickTime tags found in the CNTH atom of MOV videos from some -cameras such as the PowerShot S95. +Canon-specific QuickTime tags found in the CNTH atom of MOV/MP4 videos from +some cameras. Tag ID Tag Name Writable ------ -------- -------- - 'CNDA' ThumbnailImage no + 'CNDA' ThumbnailImage undef =head3 Canon uuid Tags @@ -7021,41 +9674,11 @@ Information found in the "skip" atom of Canon MOV videos. ------ -------- -------- 'CNDB' Unknown_CNDB? no -=head3 Canon CTMD Tags - -Canon Timed MetaData tags found in CR3 images. The ExtractEmbedded option -is automatically applied when reading CR3 files to be able to extract this -information. - - Tag ID Tag Name Writable - ------ -------- -------- - 0x0001 TimeStamp no - 0x0004 FocalInfo Canon FocalInfo - 0x0005 ExposureInfo Canon ExposureInfo - 0x0007 ExifInfo7 Canon ExifInfo - 0x0008 ExifInfo8 Canon ExifInfo - 0x0009 ExifInfo9 Canon ExifInfo - -=head3 Canon FocalInfo Tags - - Index4 Tag Name Writable - ------ -------- -------- - 0 FocalLength no - -=head3 Canon ExposureInfo Tags - - Index4 Tag Name Writable - ------ -------- -------- - 0 FNumber no - 1 ExposureTime no - 2 ISO no - -=head3 Canon ExifInfo Tags +=head3 Canon uuid2 Tags Tag ID Tag Name Writable ------ -------- -------- - 0x8769 ExifIFD EXIF - 0x927c MakerNoteCanon Canon + 'CNOP' CanonVRD CanonVRD =head2 CanonCustom Tags @@ -7330,8 +9953,10 @@ well as newer tags and values added by later models. AEBShotCount int32s[2] 0x0107 SpotMeterLinkToAFPoint int32s 0x0108 SafetyShift int32s - 0x0109 UsableShootingModes int32s[2] - 0x010a UsableMeteringModes int32s[2] + 0x0109 UsableShootingModes int32s + UsableShootingModes int32s[2] + 0x010a UsableMeteringModes int32s + UsableMeteringModes int32s[2] 0x010b ExposureModeInManual int32s 0x010c ShutterSpeedRange int32s[3] ShutterSpeedRange int32s[4] @@ -7389,9 +10014,12 @@ well as newer tags and values added by later models. 0x051d VFDisplayIllumination int32s 0x051e InitialAFPointAIServoAF int32s 0x060f MirrorLockup int32s - 0x0610 ContinuousShootingSpeed int32s[3] + 0x0610 ContinuousShootingSpeed int32s[6] + ContinuousShootingSpeed int32s[5] + ContinuousShootingSpeed int32s[3] 0x0611 ContinuousShotLimit int32s[2] - 0x0612 RestrictDriveModes int32s[2] + 0x0612 RestrictDriveModes int32s + RestrictDriveModes int32s[2] 0x0701 Shutter-AELock int32s AFAndMeteringButtons int32s ShutterButtonAFOnButton int32s @@ -7416,7 +10044,8 @@ well as newer tags and values added by later models. 0x0714 RFLensMFFocusRingSensitivity int32s 0x0715 CustomizeDials int32s 0x080b FocusingScreen int32s - 0x080c TimerLength int32s[4] + 0x080c TimerLength int32s[3] + TimerLength int32s[4] 0x080d ShortReleaseTimeLag int32s 0x080e AddAspectRatioInfo int32s 0x080f AddOriginalDecisionData int32s @@ -7426,6 +10055,7 @@ well as newer tags and values added by later models. 0x0813 DefaultEraseOption int32s 0x0814 RetractLensOnPowerOff int32s 0x0815 AddIPTCInformation int32s + 0x0816 AudioCompression int32s =head2 CanonVRD Tags @@ -7979,25 +10609,128 @@ This information is found in Casio GV-10 AVI videos. ------ -------- -------- 0 Software no -=head2 FLIR Tags +=head2 DJI Tags -Information extracted from the maker notes of JPEG images from thermal -imaging cameras by FLIR Systems Inc. +This table lists tags found in the maker notes of images from some DJI +Phantom drones. Tag ID Tag Name Writable ------ -------- -------- - 0x0001 ImageTemperatureMax rational64u - 0x0002 ImageTemperatureMin rational64u - 0x0003 Emissivity rational64u - 0x0004 UnknownTemperature? rational64u - 0x0005 CameraTemperatureRangeMax? rational64u - 0x0006 CameraTemperatureRangeMin? rational64u + 0x0001 Make string + 0x0003 SpeedX float + 0x0004 SpeedY float + 0x0005 SpeedZ float + 0x0006 Pitch float + 0x0007 Yaw float + 0x0008 Roll float + 0x0009 CameraPitch float + 0x000a CameraYaw float + 0x000b CameraRoll float -=head3 FLIR FFF Tags +=head3 DJI XMP Tags -Information extracted from FLIR FFF images and the APP1 FLIR segment of JPEG -images. These tags may also be extracted from the first frame of an FLIR -SEQ file. +XMP tags used by DJI for images from drones. + +These tags belong to the ExifTool XMP-drone-dji family 1 group. + + Tag Name Writable + -------- -------- + AbsoluteAltitude real + CalibratedFocalLength real + CalibratedOpticalCenterX real + CalibratedOpticalCenterY real + CamReverse string + DewarpData string + DewarpFlag string + FlightPitchDegree real + FlightRollDegree real + FlightXSpeed real + FlightYSpeed real + FlightYawDegree real + FlightZSpeed real + GPSLatitude real/ + GPSLongitude real/ + GPSLongtitude real + GimbalPitchDegree real + GimbalReverse string + GimbalRollDegree real + GimbalYawDegree real + Latitude real + Longitude real + RelativeAltitude real + RtkFlag string + RtkStdHgt real + RtkStdLat real + RtkStdLon real + SelfData string + +=head3 DJI Info Tags + +Tags written by some DJI drones. + + Tag ID Tag Name Writable + ------ -------- -------- + 'FlightDegree(Y,P,R)' FlightDegree no + 'FlightSpeed(X,Y,Z)' FlightSpeed no + 'GimbalDegree(Y,P,R)' GimbalDegree no + 'adj_dbg_info' ADJDebugInfo no + 'ae_dbg_info' AEDebugInfo no + 'ae_histogram_info' AEHistogramInfo no + 'ae_liveview_histogram_info' + AELiveViewHistogramInfo no + 'ae_liveview_local_histogram' + AELiveViewLocalHistogram no + 'ae_local_histogram' AELocalHistogram no + 'af_dbg_info' AFDebugInfo no + 'awb_dbg_info' AWBDebugInfo no + 'hiso' Histogram no + 'hyperlapse_dbg_info' HyperlapsDebugInfo no + 'sensor_id' SensorID no + 'xidiri' Xidiri no + +=head3 DJI ThermalParams Tags + +Thermal parameters extracted from APP4 of DJI RJPEG files from the ZH20T. + + Index1 Tag Name Writable + ------ -------- -------- + 36 K1 no + 40 K2 no + 44 K3 no + 48 K4 no + 52 KF no + 56 B1 no + 60 B2 no + 68 ObjectDistance no + 70 RelativeHumidity no + 72 Emissivity no + 74 Reflection no + 76 AmbientTemperature no + 80 D2 no + 84 KJ no + 86 DB no + 88 KK no + +=head2 FLIR Tags + +Information extracted from the maker notes of JPEG images from thermal +imaging cameras by FLIR Systems Inc. + + Tag ID Tag Name Writable + ------ -------- -------- + 0x0001 ImageTemperatureMax rational64u + 0x0002 ImageTemperatureMin rational64u + 0x0003 Emissivity rational64u + 0x0004 UnknownTemperature? rational64u + 0x0005 CameraTemperatureRangeMax? rational64u + 0x0006 CameraTemperatureRangeMin? rational64u + +=head3 FLIR FFF Tags + +Information extracted from FLIR FFF images and the APP1 FLIR segment of JPEG +images. These tags may also be extracted from the first frame of an FLIR +SEQ file, or all frames if the ExtractEmbedded option is used. Setting +ExtractEmbedded to 2 also the raw thermal data from all frames. Tag ID Tag Name Writable ------ -------- -------- @@ -8075,7 +10808,7 @@ Information found in FFF-format .CRS correction image files. FLIR camera information. The Planck tags are variables used in the temperature calculation. See -L<http://u88.n24.queensu.ca/exiftool/forum/index.php?topic=4898.msg23972#msg23972> +L<https://exiftool.org/forum/index.php?topic=4898.msg23972#msg23972> for details. Index1 Tag Name Writable @@ -8116,6 +10849,8 @@ for details. 540 FilterSerialNumber no 776 PlanckO no 780 PlanckR2 no + 784 RawValueRangeMin no + 786 RawValueRangeMax no 824 RawValueMedian no 828 RawValueRange no 900 DateTimeOriginal no @@ -8205,8 +10940,10 @@ FLIR Picture in Picture tags. 64 GPSDOP no 68 GPSSpeedRef no 70 GPSTrackRef no + 72 GPSImgDirectionRef no 76 GPSSpeed no 80 GPSTrack no + 84 GPSImgDirection no 88 GPSMapDatum no =head3 FLIR MeterLink Tags @@ -8448,10 +11185,14 @@ Tags extracted from FLIR Public image Format (FPF) files. 0x1047 GrainEffect int32s 0x1048 ColorChromeEffect int32s 0x1049 BWAdjustment int8s + 0x104d CropMode int16u + 0x104e ColorChromeFXBlue int32s 0x1050 ShutterType int16u 0x1100 AutoBracketing int16u 0x1101 SequenceNumber int16u 0x1103 DriveSettings FujiFilm DriveSettings + 0x1105 PixelShiftShots int16u + 0x1106 PixelShiftOffset rational64s[2] 0x1153 PanoramaAngle int16u 0x1154 PanoramaDirection int16u 0x1201 AdvancedFilter int32u @@ -8478,9 +11219,16 @@ Tags extracted from FLIR Public image Format (FPF) files. 0x1444 DRangePriorityAuto int16u 0x1445 DRangePriorityFixed int16u 0x1446 FlickerReduction int32u + 0x1447 FirmwareVersion string + 0x1448 FirmwareVersion2 string + 0x3803 VideoRecordingMode int32u + 0x3804 PeripheralLighting int16u + 0x3806 VideoCompression int16u 0x3820 FrameRate int16u 0x3821 FrameWidth int16u 0x3822 FrameHeight int16u + 0x3824 FullHDHighSpeedRec int32u + 0x4005 FaceElementSelected int16u[4] 0x4100 FacesDetected int16u 0x4103 FacePositions int16u[n] 0x4200 NumFaceElements int16u @@ -8503,10 +11251,11 @@ Tags extracted from FLIR Public image Format (FPF) files. Index4 Tag Name Writable ------ -------- -------- - 0.1 FocusMode2 int32u & 0xff - 0.2 AFAreaMode int32u & 0xf00 - 0.3 AFAreaPointSize int32u & 0xf000 - 0.4 AFAreaZoneSize int32u & 0xf0000 + 0.1 FocusMode2 int32u & 0x0f + 0.2 PreAF int32u & 0xf0 + 0.3 AFAreaMode int32u & 0xf00 + 0.4 AFAreaPointSize int32u & 0xf000 + 0.5 AFAreaZoneSize int32u & 0xf0000 =head3 FujiFilm AFCSettings Tags @@ -8565,6 +11314,9 @@ RAF-format information. Tag ID Tag Name Writable ------ -------- -------- 0x0100 RawImageFullSize no + 0x0110 RawImageCropTopLeft no + 0x0111 RawImageCroppedSize no + 0x0115 RawImageAspectRatio no 0x0121 RawImageSize no 0x0130 FujiLayout no 0x0131 XTransLayout no @@ -9595,6 +12347,7 @@ data, however ExifTool will extract information from any tags found here. 'ISO' ISO no 'ISO Speed' ISO no 'Image Number' ImageNumber no + 'Lens' Lens no 'Max Aperture' MaxAperture no 'Meter Mode' MeterMode no 'Min Aperture' MinAperture no @@ -10048,7 +12801,7 @@ they don't appear in these tables. Tag ID Tag Name Writable ------ -------- -------- - 'JPEG_preview_data' PreviewImage undef + 'JPEG_preview_data' PreviewImage no 'JPEG_preview_info' PreviewInfo no 'PDA_histogram_data' PDAHistogram no 'back_serial_number' BackSerial no @@ -10702,6 +13455,10 @@ DiMAGE X and Xt. Tag ID Tag Name Writable ------ -------- -------- + 0x5500 BuildNumber string + 0x5501 SerialNumber string + 0x6420 CustomRendered string + 0x64d0 DriveMode string 0x665e Sensor string 0x6705 ManufactureDate string @@ -10745,16 +13502,23 @@ DiMAGE X and Xt. 0x0022 ActiveD-Lighting int16u 0x0023 PictureControlData Nikon PictureControl Nikon PictureControl2 + Nikon PictureControl3 + Nikon PictureControlUnknown 0x0024 WorldTime Nikon WorldTime 0x0025 ISOInfo Nikon ISOInfo 0x002a VignetteControl int16u 0x002b DistortInfo Nikon DistortInfo 0x002c UnknownInfo Nikon UnknownInfo 0x0032 UnknownInfo2 Nikon UnknownInfo2 + 0x0034 ShutterMode int16u 0x0035 HDRInfo Nikon HDRInfo 0x0037 MechanicalShutterCount int32u 0x0039 LocationInfo Nikon LocationInfo 0x003d BlackLevel int16u[4] + 0x003e ImageSizeRAW yes + 0x003f WhiteBalanceFineTune rational64s[2] + 0x0045 CropArea int16u[4] + 0x004e NikonSettings NikonSettings 0x004f ColorTemperatureAuto int16u 0x0080 ImageAdjustment string 0x0081 ToneComp string @@ -10794,12 +13558,15 @@ DiMAGE X and Xt. ShotInfoD4S Nikon ShotInfoD4S ShotInfoD5 Nikon ShotInfoD500 ShotInfoD500 Nikon ShotInfoD500 + ShotInfoD6 Nikon ShotInfoD6 ShotInfoD610 Nikon ShotInfoD610 + ShotInfoZ7II Nikon ShotInfoZ7II + ShotInfoZ9 Nikon ShotInfoZ9 ShotInfo02xx Nikon ShotInfo ShotInfoUnknown Nikon ShotInfo 0x0092 HueAdjustment int16s 0x0093 NEFCompression int16u - 0x0094 Saturation int16s + 0x0094 SaturationAdj int16s 0x0095 NoiseReduction string 0x0096 NEFLinearizationTable undef! 0x0097 ColorBalance0100 Nikon ColorBalance1 @@ -10819,10 +13586,14 @@ DiMAGE X and Xt. LensData0201 Nikon LensData01 LensData0204 Nikon LensData0204 LensData0400 Nikon LensData0400 + LensData0402 Nikon LensData0402 + LensData0403 Nikon LensData0403 + LensData0800 Nikon LensData0800 LensDataUnknown Nikon LensDataUnknown 0x0099 RawImageCenter int16u[2] 0x009a SensorPixelSize rational64u[2] 0x009c SceneAssist string + 0x009d DateStampMode int16u 0x009e RetouchHistory int16u[10] 0x00a0 SerialNumber string 0x00a2 ImageDataSize int32u @@ -10834,6 +13605,7 @@ DiMAGE X and Xt. FlashInfo0103 Nikon FlashInfo0103 FlashInfo0106 Nikon FlashInfo0106 FlashInfo0107 Nikon FlashInfo0107 + FlashInfo0300 Nikon FlashInfo0300 FlashInfoUnknown Nikon FlashInfoUnknown 0x00a9 ImageOptimization string 0x00aa Saturation string @@ -10845,24 +13617,83 @@ DiMAGE X and Xt. 0x00b1 HighISONoiseReduction int16u 0x00b3 ToningEffect string 0x00b6 PowerUpTime undef - 0x00b7 AFInfo2 Nikon AFInfo2 + 0x00b7 AFInfo2 Nikon AFInfo2V0400 + Nikon AFInfo2 0x00b8 FileInfo Nikon FileInfo Nikon FileInfo 0x00b9 AFTune Nikon AFTune 0x00bb RetouchInfo Nikon RetouchInfo 0x00bd PictureControlData Nikon PictureControl + 0x00bf SilentPhotography yes 0x00c3 BarometerInfo Nikon BarometerInfo 0x0e00 PrintIM PrintIM 0x0e01 NikonCaptureData NikonCapture - 0x0e09 NikonCaptureVersion string + 0x0e09 NikonCaptureVersion string^ 0x0e0e NikonCaptureOffsets Nikon CaptureOffsets 0x0e10 NikonScanIFD Nikon Scan 0x0e13 NikonCaptureEditVersions NikonCapture - NikonCaptureEditVersions undef! + NikonCaptureEditVersions undef!^ 0x0e1d NikonICCProfile ICC_Profile 0x0e1e NikonCaptureOutput Nikon CaptureOutput 0x0e22 NEFBitDepth int16u[4]! +=head3 Nikon ast Tags + +Tags used by Nikon NX Studio in Nikon NKSC sidecar files and trailers. + +These tags belong to the ExifTool XMP-ast family 1 group. + + Tag Name Writable + -------- -------- + About no + GPSAltitude no + GPSAltitudeRef no + GPSImgDirection no + GPSImgDirectionRef no + GPSLatitude no + GPSLatitudeRef no + GPSLongitude no + GPSLongitudeRef no + GPSMapDatum no + GPSVersionID no + IPTC IPTC + Version no + XMLPackets XMP + +=head3 Nikon nine Tags + +These tags belong to the ExifTool XMP-nine family 1 group. + + Tag Name Writable + -------- -------- + About no + Label no + NineEdits Nikon NineEdits + Rating no + Trim no + Version no + +=head3 Nikon NineEdits Tags + +XML-based tags used to store editing information. + + Tag Name Writable + -------- -------- + FilterParametersBinary no + FilterParametersCustomCustomData no + FilterParametersExportExportData no + +=head3 Nikon sdc Tags + +These tags belong to the ExifTool XMP-sdc family 1 group. + + Tag Name Writable + -------- -------- + About no + AppName no + AppVersion no + Version no + =head3 Nikon PreviewIFD Tags Tag ID Tag Name Writable @@ -10989,6 +13820,32 @@ Color balance tags used by the P1000, P7000, P7100 and B700. 64 ToningEffect int8u 65 ToningSaturation int8u +=head3 Nikon PictureControl3 Tags + + Index1 Tag Name Writable + ------ -------- -------- + 0 PictureControlVersion no + 8 PictureControlName string[20] + 28 PictureControlBase string[20] + 54 PictureControlAdjust int8u + 55 PictureControlQuickAdjust int8u + 57 Sharpness int8u + 59 MidRangeSharpness int8u + 61 Clarity int8u + 63 Contrast int8u + 65 Brightness int8u + 67 Saturation int8u + 69 Hue int8u + 71 FilterEffect int8u + 72 ToningEffect int8u + 73 ToningSaturation int8u + +=head3 Nikon PictureControlUnknown Tags + + Index1 Tag Name Writable + ------ -------- -------- + 0 PictureControlVersion no + =head3 Nikon WorldTime Tags Index1 Tag Name Writable @@ -11047,6 +13904,13 @@ Tags written by some Nikon GPS-equipped cameras like the AW100. 8 POILevel int8u 9 Location undef[70] +=head3 Nikon MakerNotes0x51 Tags + + Index1 Tag Name Writable + ------ -------- -------- + 0 FirmwareVersion no + 10 NEFCompression int16u[0.5] + =head3 Nikon AFInfo Tags Index1 Tag Name Writable @@ -11226,19 +14090,18 @@ These tags are extracted from encrypted data in images from the D800. =head3 Nikon ShotInfoD810 Tags -These tags are extracted from encrypted data in images from the D810. +These tags are extracted from encrypted data in images from the D810. Note +that the indices listed below are for firmware version 1.0, but they may be +different for other firmware versions. Index Tag Name Writable ----- -------- -------- 0 ShotInfoVersion no 4 FirmwareVersion no - 36 BracketingOffset no - 64 CustomSettingsOffset no - 132 OrientationOffset no 464 SecondarySlotFunction int8u & 0x03 5974 AEBracketingSteps int8u & 0xff 5975 WBBracketingSteps int8u & 0xff - 5982 D810MeteringMode int8u & 0x03 + 5982 NikonMeteringMode int8u & 0x03 6236 ISOAutoShutterTime int8u & 0x3f 6237 ISOAutoHiLimit int8u & 0xff 6315 CustomSettingsD810 NikonCustom SettingsD810 @@ -11254,11 +14117,13 @@ These tags are extracted from encrypted data in images from the D850. ----- -------- -------- 0 ShotInfoVersion no 4 FirmwareVersion no - 88 CustomSettingsOffset no 1937 PhotoShootingMenuBankImageArea int8u & 0x07 4029 PhotoShootingMenuBank int8u & 0x03 4031 PrimarySlot int8u & 0x80 4152 CustomSettingsD850 NikonCustom SettingsD850 + 12027 RollAngle fixed32u + 12031 PitchAngle fixed32u + 12035 YawAngle fixed32u =head3 Nikon ShotInfoD5000 Tags @@ -11343,13 +14208,9 @@ These tags are extracted from encrypted data in images from the D5 and D500. ----- -------- -------- 0 ShotInfoVersion no 4 FirmwareVersion no - 16 RotationInfoOffset no - 20 JPGInfoOffset no - 44 BracketingInfoOffset no - 80 ShootingMenuOffset no - 88 CustomSettingsOffset no - 160 OrientationOffset no 202 Rotation int8u & 0x03 + 208 Interval int8u~ + 212 IntervalFrame int8u~ 1506 FlickerReductionIndicator int8u & 0x01 2004 JPGCompression int8u & 0x01 2171 AEBracketingSteps int8u & 0xff @@ -11367,6 +14228,38 @@ These tags are extracted from encrypted data in images from the D5 and D500. 11300 RollAngle fixed32u 11304 PitchAngle fixed32u 11308 YawAngle fixed32u + 11940 NikonMeteringMode int8u & 0x03 + +=head3 Nikon ShotInfoD6 Tags + +These tags are extracted from encrypted data in images from the D6. + + Index Tag Name Writable + ----- -------- -------- + 0 ShotInfoVersion no + 4 FirmwareVersion no + 30220 IntervalShooting int16u~ + 49690 RollAngle fixed32u + 49694 PitchAngle fixed32u + 49698 YawAngle fixed32u + 50190 Intervals int32u + 50194 ShotsPerInterval int32u + 50198 IntervalExposureSmoothing int8u + 50200 IntervalPriority int8u + 50234 FocusShiftNumberShots int8u + 50238 FocusShiftStepWidth int8u + 50242 FocusShiftInterval int8u~ + 50246 FocusShiftExposureLock int8u + 50336 DiffractionCompensation int8u + 50342 FlashControlMode int8u + 50348 FlashGNDistance? no + 50352 FlashOutput? int8u + 50362 FlashRemoteControl? int8u + 50366 FlashMasterControlMode int8u + 50368 FlashMasterCompensation? int8s + 50372 FlashMasterOutput? int8u + 50374 FlashWirelessOption? int8u + 50524 MovieType? int8u =head3 Nikon ShotInfoD610 Tags @@ -11378,6 +14271,157 @@ These tags are extracted from encrypted data in images from the D610. 4 FirmwareVersion no 1999 CustomSettingsD610 NikonCustom SettingsD610 +=head3 Nikon ShotInfoZ7II Tags + +These tags are extracted from encrypted data in images from the Z7II. + + Index Tag Name Writable + ----- -------- -------- + 0 ShotInfoVersion no + 4 FirmwareVersion no + 30220 IntervalShooting int16u~ + 32672 PortraitImpressionBalance int8u[2]~ + 52786 RollAngle fixed32u + 52790 PitchAngle fixed32u + 52794 YawAngle fixed32u + 52918 MenuSettingsZ7IIOffset int8u + 52920 MenuSettingsZ7II Nikon MenuSettingsZ7II + +=head3 Nikon MenuSettingsZ7II Tags + +These tags are used by the Z5, Z6, Z7, Z6II, Z7II, Z50 and Zfc. + + Index1 Tag Name Writable + ------ -------- -------- + 160 IntervalDurationHours int32u + 164 IntervalDurationMinutes int32u + 168 IntervalDurationSeconds int32u + 176 Intervals int32u + 180 ShotsPerInterval int32u + 184 IntervalExposureSmoothing int8u + 186 IntervalPriority int8u + 220 FocusShiftNumberShots int8u + 224 FocusShiftStepWidth int8u + 228 FocusShiftInterval int8u~ + 232 FocusShiftExposureLock int8u + 322 DiffractionCompensation int8u + 323 AutoDistortionControl int8u + 326 NikonMeteringMode int8u + 328 FlashControlMode int8u + 334 FlashGNDistance? no + 338 FlashOutput? int8u + 346 FlashWirelessOption? int8u + 348 FlashRemoteControl? int8u + 352 FlashMasterControlMode int8u + 354 FlashMasterCompensation? int8s + 358 FlashMasterOutput? int8u + 502 MovieFrameSize? int8u + 504 MovieFrameRate? int8u + 506 MovieSlowMotion? int8u + 510 MovieType? int8u + 516 MovieISOAutoManualMode? int16u + 568 MovieActiveD-Lighting? int8u + 572 MovieHighISONoiseReduction? int8u + 574 MovieVignetteControl? int8u + 576 MovieVignetteControlSameAsPhoto? int8u + 577 MovieDiffractionCompensation? int8u + 578 MovieAutoDistortionControl? int8u + 584 MovieFocusMode? int8u + 590 MovieVibrationReduction? int8u + 591 MovieVibrationReductionSameAsPhoto? int8u + 858 HDMIOutputN-Log? int8u + +=head3 Nikon ShotInfoZ9 Tags + +These tags are extracted from encrypted data in images from the Z9. + + Index Tag Name Writable + ----- -------- -------- + 0 ShotInfoVersion no + 4 FirmwareVersion no + 27800 IntervalShooting int16u~ + 30788 FocusShiftShooting int8u~ + 60139 RollAngle fixed32u + 60143 PitchAngle fixed32u + 60147 YawAngle fixed32u + 60491 MenuSettingsZ9 Nikon MenuSettingsZ9 + +=head3 Nikon MenuSettingsZ9 Tags + +These tags are used by the Z9. + + Index1 Tag Name Writable + ------ -------- -------- + 140 MultipleExposureMode int8u + 142 MultiExposureShots int8u + 188 Intervals int32u + 192 ShotsPerInterval int32u + 232 FocusShiftNumberShots int8u + 236 FocusShiftStepWidth int8u + 240 FocusShiftInterval int8u~ + 244 FocusShiftExposureLock? int8u + 274 PhotoShootingMenuBank int8u + 276 ExtendedMenuBanks int8u + 308 PhotoShootingMenuBankImageArea int8u + 322 AutoISO int8u + 324 ISOAutoHiLimit? int16u + 326 ISOAutoFlashLimit? int16u + 334 ISOAutoShutterTime no + 416 MovieVignetteControl? int8u + 418 DiffractionCompensation int8u + 420 FlickerReductionShooting int8u + 424 FlashControlMode int8u + 426 FlashMasterCompensation? int8s + 430 FlashGNDistance? no + 434 FlashOutput? int8u + 444 FlashRemoteControl? int8u + 456 FlashWirelessOption? int8u + 528 AFAreaMode int8u + 530 VRMode int8u + 534 BracketSet int8u + 536 BracketProgram int8u + 538 BracketIncrement int8u + 556 SecondarySlotFunction int8u + 572 DXCropAlert int8u + 574 SubjectDetection int8u + 604 MovieImageArea? int8u & 0x01 + 614 MovieType? int8u + 616 MovieISOAutoHiLimit? int16u + 618 MovieISOAutoControlManualMode? int8u + 620 MovieISOAutoManualMode? int16u + 696 MovieActiveD-Lighting? int8u + 698 MovieHighISONoiseReduction? int8u + 704 MovieFlickerReduction int8u + 706 MovieMeteringMode? int8u + 708 MovieFocusMode? int8u + 710 MovieAFAreaMode int8u + 712 MovieVRMode? int8u + 716 MovieElectronicVR? int8u + 718 MovieSoundRecording? int8u + 720 MicrophoneSensitivity? int8u + 722 MicrophoneAttenuator? int8u + 724 MicrophoneFrequencyResponse? int8u + 726 WindNoiseReduction? int8u + 748 MovieToneMap? int8u + 754 MovieFrameSize? int8u + 756 MovieFrameRate? int8u + 762 MicrophoneJackPower? int8u + 763 MovieDXCropAlert? int8u + 764 MovieSubjectDetection? int8u + 799 CustomSettingsZ9 NikonCustom SettingsZ9 + 1426 Language? int8u + 1428 TimeZone int8u + 1434 MonitorBrightness? no + 1456 AFFineTune? int8u + 1552 HDMIOutputResolution int8u + 1565 SetClockFromLocationData? int8u + 1572 AirplaneMode? int8u + 1573 EmptySlotRelease? int8u + 1608 EnergySavingMode? int8u + 1632 RecordLocationData? int8u + 1636 USBPowerDelivery? int8u + 1645 SensorShield? int8u + =head3 Nikon ShotInfo Tags This information is encrypted for ShotInfoVersion 02xx, and some tags are @@ -11492,13 +14536,60 @@ extracted. =head3 Nikon LensData0400 Tags -Tags extracted from the encrypted lens data of Nikon 1 models. +Tags extracted from the encrypted lens data of the Nikon 1J1/1V1/1J2. Index1 Tag Name Writable ------ -------- -------- 0 LensDataVersion no 394 LensModel string[64] +=head3 Nikon LensData0402 Tags + +Tags extracted from the encrypted lens data of the Nikon 1J3/1S1/1V2. + + Index1 Tag Name Writable + ------ -------- -------- + 0 LensDataVersion no + 395 LensModel string[64] + +=head3 Nikon LensData0403 Tags + +Tags extracted from the encrypted lens data of the Nikon 1J4/1J5. + + Index1 Tag Name Writable + ------ -------- -------- + 0 LensDataVersion no + 684 LensModel string[64] + +=head3 Nikon LensData0800 Tags + +Tags found in the encrypted LensData from cameras such as the Z6 and Z7. + + Index1 Tag Name Writable + ------ -------- -------- + 0 LensDataVersion no + 4 ExitPupilPosition int8u + 5 AFAperture int8u + 11 FocusDistance int8u + 12 FocalLength int8u + 13 LensIDNumber int8u + 14 LensFStops int8u + 15 MinFocalLength int8u + 16 MaxFocalLength int8u + 17 MaxApertureAtMinFocal int8u + 18 MaxApertureAtMaxFocal int8u + 19 MCUVersion int8u + 20 EffectiveMaxAperture int8u + 48 LensID int16u + 53 LensMountType? int8u + 54 MaxAperture int16u + 56 FNumber int16u + 60 FocalLength int16u + 76 FocusDistanceRangeWidth? int8u + 78 FocusDistance int16u~ + 86 LensDriveEnd? int8u + 90 LensPositionAbsolute? int32s + =head3 Nikon LensDataUnknown Tags Index1 Tag Name Writable @@ -11651,6 +14742,15 @@ These tags are used by the D4S, D750, D810, D5500, D7200 (FlashInfoVersion 42 FlashGroupCOutput int8u FlashGroupCCompensation int8s +=head3 Nikon FlashInfo0300 Tags + + Index1 Tag Name Writable + ------ -------- -------- + 0 FlashInfoVersion no + 4 FlashSource int8u + 6 ExternalFlashFirmware int8u[2] + 10 FlashCompensation int8s + =head3 Nikon FlashInfoUnknown Tags Index1 Tag Name Writable @@ -11666,6 +14766,18 @@ These tags are used by the D4S, D750, D810, D5500, D7200 (FlashInfoVersion 2 MultiExposureShots int32u 3 MultiExposureAutoGain int32u +=head3 Nikon AFInfo2V0400 Tags + + Index1 Tag Name Writable + ------ -------- -------- + 0 AFInfo2Version no + 62 AFImageWidth int16u + 64 AFImageHeight int16u + 67 FocusPositionHorizontal int8u~ + 69 FocusPositionVertical int8u~ + 70 AFAreaWidth int16u + 72 AFAreaHeight int16u + =head3 Nikon AFInfo2 Tags These tags are written by Nikon DSLR's which have the live view feature. @@ -11684,7 +14796,9 @@ These tags are written by Nikon DSLR's which have the live view feature. AFPointsUsed undef[21] AFPointsUsed undef[29] AFPointsUsed undef[20] + AFPointsUsed undef[13] AFPointsUsed undef[7] + 10 AFPointsUsed undef[14] 16 AFImageWidth int16u 18 AFImageHeight int16u 20 AFAreaXPosition int16u @@ -11692,6 +14806,17 @@ These tags are written by Nikon DSLR's which have the live view feature. 24 AFAreaWidth int16u 26 AFAreaHeight int16u 28 ContrastDetectAFInFocus int8u + AFPointsSelected undef[20] + 42 AFImageWidth int16u + 44 AFImageHeight int16u + 46 AFAreaXPosition int16u + 47 AFFocusPointXPosition int8u~ + 48 AFAreaYPosition int16u + AFPointsInFocus undef[20] + 49 AFFocusPointYPosition int8u~ + 50 AFAreaWidth int16u + 52 AFAreaHeight int16u + 56 PrimaryAFPoint int8u 68 PrimaryAFPoint int8u 70 AFImageWidth int16u 72 AFImageHeight int16u @@ -11717,6 +14842,7 @@ These tags are written by Nikon DSLR's which have the live view feature. 0 AFFineTune int8u 1 AFFineTuneIndex int8u 2 AFFineTuneAdj int8s + 3 AFFineTuneAdjTele int8s =head3 Nikon RetouchInfo Tags @@ -11792,6 +14918,15 @@ This information is written by the Nikon Scan software. 0x000a DigitalZoom yes 0x000b Converter yes +=head3 Nikon NEFInfo Tags + +As-yet unknown information found in SubIFD1 tag 0xc7d5 of NEF images from +cameras such as the Z6 and Z7, and NRW images from some Coolpix cameras. + + Tag ID Tag Name Writable + ------ -------- -------- + [no tags known] + =head3 Nikon NCDT Tags Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from @@ -11861,28 +14996,33 @@ videos from some Nikon cameras. 0x120001d GPSDateStamp no 0x2000001 MakerNoteVersion no 0x2000005 WhiteBalance no - 0x2000007 FocusMode string + 0x2000007 FocusMode no 0x200000b WhiteBalanceFineTune no - 0x200001b CropHiSpeed int16u[7] + 0x200001b CropHiSpeed no 0x200001e ColorSpace no 0x200001f VRInfo Nikon VRInfo - 0x2000022 ActiveD-Lighting int16u + 0x2000022 ActiveD-Lighting no 0x2000023 PictureControlData Nikon PictureControl Nikon PictureControl2 + Nikon PictureControl3 + Nikon PictureControlUnknown 0x2000024 WorldTime Nikon WorldTime 0x2000025 ISOInfo Nikon ISOInfo - 0x200002a VignetteControl int16u + 0x200002a VignetteControl no 0x200002c UnknownInfo Nikon UnknownInfo 0x2000032 UnknownInfo2 Nikon UnknownInfo2 0x2000039 LocationInfo Nikon LocationInfo 0x2000083 LensType no 0x2000084 Lens no - 0x2000087 FlashMode int8u + 0x2000087 FlashMode no 0x2000098 LensData0100 Nikon LensData00 LensData0101 Nikon LensData01 LensData0201 Nikon LensData01 LensData0204 Nikon LensData0204 LensData0400 Nikon LensData0400 + LensData0402 Nikon LensData0402 + LensData0403 Nikon LensData0403 + LensData0800 Nikon LensData0800 LensDataUnknown Nikon LensDataUnknown 0x20000a7 ShutterCount no 0x20000a8 FlashInfo0100 Nikon FlashInfo0100 @@ -11891,8 +15031,8 @@ videos from some Nikon cameras. FlashInfo0106 Nikon FlashInfo0106 FlashInfo0107 Nikon FlashInfo0107 FlashInfoUnknown Nikon FlashInfoUnknown - 0x20000ab VariProgram string - 0x20000b1 HighISONoiseReduction int16u + 0x20000ab VariProgram no + 0x20000b1 HighISONoiseReduction no 0x20000b7 AFInfo2 Nikon AFInfo2 0x20000c3 BarometerInfo Nikon BarometerInfo @@ -12773,9 +15913,9 @@ Custom settings for the D5. ------ -------- -------- 0.1 CustomSettingsBank int8u & 0x03 1.1 AF-CPrioritySelection int8u & 0xc0 - 1.2 NumberOfFocusPoints int8u & 0x10 - 1.3 Three-DTrackingFaceDetection int8u & 0x08 - 1.4 AF-SPrioritySelection int8u & 0x20 + 1.2 AF-SPrioritySelection int8u & 0x20 + 1.3 NumberOfFocusPoints int8u & 0x10 + 1.4 Three-DTrackingFaceDetection int8u & 0x08 1.5 BlockShotAFResponse int8u & 0x07 2.1 FocusPointWrap int8u & 0x08 2.2 AFPointBrightness int8u & 0x06 @@ -12869,9 +16009,9 @@ Custom settings for the D500. ------ -------- -------- 0.1 CustomSettingsBank int8u & 0x03 1.1 AF-CPrioritySelection int8u & 0xc0 - 1.2 NumberOfFocusPoints int8u & 0x10 - 1.3 Three-DTrackingFaceDetection int8u & 0x08 - 1.4 AF-SPrioritySelection int8u & 0x20 + 1.2 AF-SPrioritySelection int8u & 0x20 + 1.3 NumberOfFocusPoints int8u & 0x10 + 1.4 Three-DTrackingFaceDetection int8u & 0x08 1.5 BlockShotAFResponse int8u & 0x07 2.1 FocusPointWrap int8u & 0x08 2.2 AFPointBrightness int8u & 0x06 @@ -12989,6 +16129,151 @@ Custom settings for the D610. 21.2 ShootingInfoMonitorOffTime int8u & 0x1c 35.1 PlaybackMonitorOffTime int8u & 0xe0 +=head3 NikonCustom SettingsZ9 Tags + +Custom settings for the Z9. + + Index1 Tag Name Writable + ------ -------- -------- + 1 CustomSettingsBank int8u + 3 AF-CPrioritySelection int8u + 5 AF-SPrioritySelection int8u + 7 BlockShotAFResponse int8u + 11 AFPointSel int8u + 13 StoreByOrientation int8u + 15 AFActivation int8u + 16 AF-OnOutOfFocusRelease? int8u + 17 LimitAF-AreaModeSelPinpoint? int8u + 19 LimitAF-AreaModeSelWideAF_S? int8u + 20 LimitAF-AreaModeSelWideAF_L? int8u + 21 LimitAFAreaModeSelAuto? int8u + 22 FocusPointWrap? int8u + 23 ManualFocusPointIllumination? int8u + 24 DynamicAreaAFAssist? int8u + 25 AF-AssistIlluminator int8u + 26 ManualFocusRingInAFMode int8u + 27 ExposureControlStepSize int8u + 29 EasyExposureCompensation int8u + 31 CenterWeightedAreaSize int8u + 33 FineTuneOptMatrixMetering int8s + 35 FineTuneOptCenterWeighted int8s + 37 FineTuneOptSpotMetering int8s + 39 FineTuneOptHighlightWeighted int8s + 41 ShutterReleaseButtonAE-L int8u + 43 SelfTimerTime int8u + 45 SelfTimerShotCount int8u + 49 SelfTimerShotInterval int8u + 51 PlaybackMonitorOffTime int8u + 53 MenuMonitorOffTime int8u + 55 ShootingInfoMonitorOffTime int8u + 57 ImageReviewMonitorOffTime int8u + 59 CLModeShootingSpeed int8u + 61 MaxContinuousRelease no + 65 SyncReleaseMode? int8u + 69 LimitSelectableImageAreaDX? int8u + 70 LimitSelectableImageArea1To1? int8u + 71 LimitSelectableImageArea16To9? int8u + 72 FileNumberSequence int8u + 73 FocusPeakingLevel? int8u + 75 FocusPeakingHighlightColor? int8u + 81 ContinuousModeDisplay int8u + 83 FlashSyncSpeed no + 85 HighSpeedSync int8u + 87 FlashShutterSpeed no + 89 FlashExposureCompArea int8u + 91 AutoFlashISOSensitivity int8u + 93 ModelingFlash int8u + 95 AutoBracketModeM int8u + 97 AutoBracketOrder int8u + 99 Func1Button int8u + 115 Func2Button int8u + 131 AFOnButton int8u + 143 SubSelector? int8u + 155 AssignMovieRecordButton? int8u + 159 LensFunc1Button int8u + 167 LensFunc2Button int8u + 173 LensControlRing int8u + 175 MultiSelectorShootMode int8u + 179 MultiSelectorPlaybackMode int8u + 183 ShutterSpeedLock int8u + 184 ApertureLock int8u + 186 CmdDialsReverseRotation int8u + 191 UseDialWithoutHold? int8u + 193 ReverseIndicators? int8u + 195 MovieFunc1Button int8u + 203 MovieAF-OnButton int8u + 217 MovieMultiSelector? int8u + 221 MovieAFSpeed int8u + 223 MovieAFSpeedApply int8u + 225 MovieAFTrackingSensitivity int8u + 257 LCDIllumination? int8u + 258 ExtendedShutterSpeeds int8u + 259 SubjectMotion int8u + 261 FocusPointPersistence int8u + 263 AutoFocusModeRestrictions? int8u + 267 CHModeShootingSpeed int8u + 269.1 LimitReleaseModeSelCL? int8u & 0x02 + 269.2 LimitReleaseModeSelCH? int8u & 0x04 + 269.3 LimitReleaseModeSelC30? int8u & 0x10 + 269.4 LimitReleaseModeSelC120? int8u & 0x40 + 269.5 LimitReleaseModeSelSelf? int8u & 0x80 + 273 FlashBurstPriority? int8u + 277 VerticalFuncButton int8u + 281 Func3Button int8u + 285 VerticalAFOnButton int8u + 293 VerticalMultiSelectorPlaybackMode? int8u + 295 MovieFunc3Button int8u + 335 LimitAF-AreaModeSelDynamic_S? int8u + 336 LimitAF-AreaModeSelDynamic_M? int8u + 337 LimitAF-AreaModeSelDynamic_L? int8u + 339 LimitAF-AreaModeSel3DTracking? int8u + 341 PlaybackFlickUp? int8u + 345 PlaybackFlickDown? int8u + 349 ISOStepSize int8u + 355 ReverseFocusRing int8u + 356 EVFImageFrame? int8u + 357 EVFGrid? int8u + 359 VirtualHorizonStyle? int8u + 373 Func4Button? int8u + 379 AudioButton? int8u + 381 QualityButton? int8u + 399 VerticalMultiSelector? int8u + 421 Func1ButtonPlaybackMode? int8u + 423 Func2ButtonPlaybackMode? int8u + 425 Func3ButtonPlaybackMode? int8u + 431 Func4ButtonPlaybackMode? int8u + 437 MovieRecordButtonPlaybackMode? int8u + 439 VerticalFuncButtonPlaybackMode? int8u + 441 AudioButtonPlaybackMode? int8u + 447 QualityButtonPlaybackMode? int8u + 453 WhiteBalanceButtonPlaybackMode? int8u + 459 CommandDialPlaybackMode? int8u + 463 SubCommandDialPlaybackMode? int8u + 467 FocusPointLock? int8u + 469 ControlRingResponse int8u + 481 VerticalMovieFuncButton? int8u + 505 VerticalMovieAFOnButton? int8u + 515 MovieAFAreaMode? int8u + 527 HDMIViewAssist? int8u + 529 ZebraPatternToneRange? int8u + 531 MovieZebraPattern? int8u + 533 MovieHighlightDisplayThreshold? int8u + 535 MovieMidtoneDisplayValue? int8u + 537 MovieMidtoneDisplayRange? int8u~ + 541 MovieEVFGrid? int8u + 549 MovieShutterSpeedLock? int8u + 550 MovieFocusPointLock? int8u + 563 MatrixMetering? int8u + 564 AF-CFocusDisplay int8u + 565 FocusPeakingDisplay? int8u + 567 KeepExposure int8u + 585 StarlightView? int8u + 587 EVFWarmDisplayMode? int8u + 589 EVFWarmDisplayBrightness? int8s + 591 EVFReleaseIndicator? int8u + 601 MovieApertureLock? int8u + 607 FlickAdvanceDirection? int8u + =head2 NikonCapture Tags This information is written by the Nikon Capture software in tag 0x0e01 of @@ -13219,8 +16504,8 @@ Pentax, Ricoh, Samsung, Sanyo, SeaLife, Sony, Supra and Vivitar. 0x0207 CameraType string 0x0208 TextInfo Olympus TextInfo 0x0209 CameraID string - 0x020b EpsonImageWidth int16u - 0x020c EpsonImageHeight int16u + 0x020b EpsonImageWidth int32u + 0x020c EpsonImageHeight int32u 0x020d EpsonSoftware string 0x0280 PreviewImage int8u 0x0300 PreCaptureFrames int16u @@ -13228,6 +16513,7 @@ Pentax, Ricoh, Samsung, Sanyo, SeaLife, Sony, Supra and Vivitar. 0x0302 OneTouchWB int16u 0x0303 WhiteBalanceBracket int16u 0x0304 WhiteBalanceBias int16u + 0x0400 SensorArea undef[8] 0x0401 BlackLevel int32u[4] 0x0403 SceneMode int16u 0x0404 SerialNumber string @@ -13400,6 +16686,8 @@ any information found here will be extracted, even if the tag is not listed. 0x0305 AFPointSelected rational64s[5] 0x0306 AFFineTune int8u 0x0307 AFFineTuneAdj int16s[3] + 0x0308 FocusBracketStepSize int8u + 0x0309 AISubjectTrackingMode int16u 0x0400 FlashMode int16u 0x0401 FlashExposureComp rational64s 0x0403 FlashRemoteControl int16u @@ -13758,6 +17046,7 @@ such as the OM E-M5. 44 Model no 131 DateTime1 no 157 DateTime2 no + 383 LensModel no =head3 Olympus scrn2 Tags @@ -13869,6 +17158,7 @@ These tags are used in Panasonic/Leica cameras. 0x0024 FlashBias int16s 0x0025 InternalSerialNumber undef[16] 0x0026 PanasonicExifVersion undef + 0x0027 VideoFrameRate int16u 0x0028 ColorEffect int16u 0x0029 TimeSincePowerOn int32u 0x002a BurstMode int16u @@ -13883,6 +17173,7 @@ These tags are used in Panasonic/Leica cameras. 0x0034 OpticalZoomMode int16u 0x0035 ConversionLens int16u 0x0036 TravelDay int16u + 0x0038 BatteryLevel int16u 0x0039 Contrast int16u 0x003a WorldTimeLocation int16u 0x003b TextStamp int16u @@ -13944,15 +17235,29 @@ These tags are used in Panasonic/Leica cameras. 0x009d InternalNDFilter rational64u 0x009e HDR int16u 0x009f ShutterType int16u + 0x00a1 FilterEffect rational64u[0.5] 0x00a3 ClearRetouchValue rational64u 0x00a7 OutputLUT yes 0x00ab TouchAE int16u + 0x00ac MonochromeFilterEffect int16u 0x00ad HighlightShadow int16u[2] 0x00af TimeStamp string + 0x00b3 VideoBurstResolution int16u 0x00b4 MultiExposure int16u 0x00b9 RedEyeRemoval int16u 0x00bb VideoBurstMode int32u 0x00bc DiffractionCorrection int16u + 0x00bd FocusBracket int16u + 0x00be LongExposureNRUsed int16u + 0x00bf PostFocusMerging int32u[2] + 0x00c1 VideoPreburst int16u + 0x00c4 LensTypeMake int16u + 0x00c5 LensTypeModel int16u + 0x00ca SensorType int16u + 0x00d1 ISO int32u + 0x00d2 MonochromeGrainEffect int16u + 0x00d6 NoiseReductionStrength rational64s + 0x00e4 LensTypeModel int16u 0x0e00 PrintIM PrintIM 0x2003 TimeInfo Panasonic TimeInfo 0x8000 MakerNoteVersion undef @@ -14144,13 +17449,19 @@ images. =head3 Panasonic Leica9 Tags -This information is written by the Leica S (Typ 007). +This information is written by the Leica S (Typ 007) and M10 models. Tag ID Tag Name Writable ------ -------- -------- 0x0304 FocusDistance int32u 0x0311 ExternalSensorBrightnessValue rational64s 0x0312 MeasuredLV rational64s + 0x034c UserProfile string + 0x0359 ISOSelected int32s + 0x035a FNumber int32s + 0x035b CorrelatedColorTemp int16u + 0x035c ColorTint int16s + 0x035d WhitePoint rational64u[2] =head3 Panasonic Type2 Tags @@ -14168,29 +17479,30 @@ iPalm. Tags extracted from the PANA and LEIC user data found in MP4 videos from various Panasonic and Leica models. - Index1 Tag Name Writable - ------ -------- -------- - 0 Make no - 4 Model no - 12 Model no - 16 JPEG-likeData EXIF - 22 Model no - 52 Version1 no - 62 Version2 no - 80 MakerNoteLeica5 Panasonic Leica5 - 88 ThumbnailWidth no - 90 ThumbnailHeight no - 92 ThumbnailImage no - 1334 ThumbnailWidth no - 1338 ThumbnailHeight no - 1342 ThumbnailLength no - 1350 ThumbnailImage no - 1358 ThumbnailWidth no - 1362 ThumbnailHeight no - 1366 ThumbnailLength no - 1374 ThumbnailImage no - 16488 ExifData EXIF - 16512 ExifData EXIF + Index1 Tag Name Writable + ------ -------- -------- + 0 Make no + 4 Model no + 12 Model no + 16 JPEG-likeData EXIF + 22 Model no + 52 Version1 no + 62 Version2 no + 80 MakerNoteLeica5 Panasonic Leica5 + 88 ThumbnailWidth no + 90 ThumbnailHeight no + 92 ThumbnailImage no + 1334 ThumbnailWidth no + 1338 ThumbnailHeight no + 1342 ThumbnailLength no + 1350 ThumbnailImage no + 1358 ThumbnailWidth no + 1362 ThumbnailHeight no + 1366 ThumbnailLength no + 1374 ThumbnailImage no + 16488 ExifData EXIF + 16512 ExifData EXIF + 0x00200080 ExifData EXIF =head2 Pentax Tags @@ -14299,10 +17611,12 @@ These tags are used in Pentax/Asahi cameras. 0x0080 AspectRatio yes 0x0082 BlurControl int8u[4] 0x0085 HDR int8u[4] - 0x0088 NeutralDensityFilter int8u + 0x0087 ShutterType int8u + 0x0088 NeutralDensityFilter int8u[n] 0x008b ISO int32u 0x0092 IntervalShooting int16u[2] 0x0095 SkinToneCorrection int8s[2] + SkinToneCorrection int8s[3] 0x0096 ClarityControl int8s[2] 0x0200 BlackPoint int16u[4] 0x0201 WhitePoint int16u[4] @@ -14335,6 +17649,8 @@ These tags are used in Pentax/Asahi cameras. 0x0215 CameraInfo Pentax CameraInfo 0x0216 BatteryInfo Pentax BatteryInfo 0x021b SaturationInfo? no + 0x021c ColorMatrixA2 undef[18] + 0x021d ColorMatrixB2 undef[18] 0x021f AFInfo Pentax AFInfo 0x0220 HuffmanTable? no 0x0221 KelvinWB Pentax KelvinWB @@ -14345,6 +17661,7 @@ These tags are used in Pentax/Asahi cameras. 0x0228 FaceSize Pentax FaceSize 0x0229 SerialNumber string 0x022a FilterInfo Pentax FilterInfo + Pentax FilterInfo 0x022b LevelInfo Pentax LevelInfo 0x022d WBLevels Pentax WBLevels 0x022e Artist string @@ -14940,7 +18257,7 @@ Tags extracted from the maker notes of AVI videos from the Optio S1. Tag ID Tag Name Writable ------ -------- -------- - 0x0000 MakerNoteVersion undef[4] + 0x0000 MakerNoteVersion no =head3 Pentax PENT Tags @@ -15136,6 +18453,38 @@ Tags extracted from models such as the UltraFire. 75 SerialNumber string[15] 90 UserLabel string[21] +=head3 Reconyx Type3 Tags + +Tags extracted from models such as the HF2 PRO. + + Index1 Tag Name Writable + ------ -------- -------- + 16 FileNumber int16u + 18 DirectoryNumber int16u + 42 FirmwareVersion int16u[3] + 48 FirmwareDate int16u[2] + 52 TriggerMode string[2] + 54 Sequence int16u[2] + 58 EventNumber int16u[2] + 62 DateTimeOriginal int16u[6] + 74 DayOfWeek int16u + 76 MoonPhase int16u + 78 AmbientTemperatureFahrenheit int16s + 80 AmbientTemperature int16s + 82 Contrast int16u + 84 Brightness int16u + 86 Sharpness int16u + 88 Saturation int16u + 90 Flash int16u + 92 AmbientInfrared int16u + 94 AmbientLight int16u + 96 MotionSensitivity int16u + 98 BatteryVoltage int16u + 100 BatteryVoltageAvg int16u + 102 BatteryType int16u + 104 UserLabel string[22] + 126 SerialNumber unicode[15] + =head2 Sanyo Tags Tag ID Tag Name Writable @@ -15320,35 +18669,80 @@ Camera orientation information written by the Gear 360 (SM-C200). 3 PictureWizardSharpness int16u 4 PictureWizardContrast int16u +=head3 Samsung APP5 Tags + + Tag ID Tag Name Writable + ------ -------- -------- + 'ssuniqueid' UniqueID no + =head3 Samsung Trailer Tags Tags extracted from the trailer of JPEG images written when using certain features (such as "Sound & Shot" or "Shot & More") from Samsung models such -as the Galaxy S4 and Tab S. +as the Galaxy S4 and Tab S, and from the 'sefd' atom in HEIC images from the +Samsung S10+. Tag Name Writable -------- -------- DepthMapData no + DepthMapData2 no DepthMapName no DualCameraImage no DualCameraImageName no - DualShotInfo Samsung DualShotInfo + DualShotExtra Samsung DualShotExtra EmbeddedAudioFile no EmbeddedAudioFileName no EmbeddedImage no + EmbeddedImage2 no EmbeddedImageName no EmbeddedVideoFile no EmbeddedVideoType no + MCCData no + SingleShotDepthMap no + SingleShotMeta Samsung SingleShotMeta SurroundShotVideo no SurroundShotVideoName no TimeStamp no -=head3 Samsung DualShotInfo Tags +=head3 Samsung DualShotExtra Tags Index4 Tag Name Writable ------ -------- -------- - 9 DepthMapWidth no - 10 DepthMapHeight no + 16 DepthMapWidth no + 17 DepthMapHeight no + +=head3 Samsung SingleShotMeta Tags + + Tag ID Tag Name Writable + ------ -------- -------- + 'beautyColorLevel' BeautyColorLevel no + 'beautyRetouchLevel' BeautyRetouchLevel no + 'blurStrength' BlurStrength no + 'bokehShape' BokehShape no + 'colorpopStrength' ColorpopStrength no + 'depthHWHeight' DepthHWHeight no + 'depthHWWidth' DepthHWWidth no + 'depthSWHeight' DepthSWHeight no + 'depthSWWidth' DepthSWWidth no + 'deviceOrientation' DeviceOrientation no + 'effectStrength' EffectStrength no + 'effectType' EffectType no + 'flipStatus' FlipStatus no + 'inputHeight' InputHeight no + 'inputWidth' InputWidth no + 'isArtBokeh' IsArtBokeh no + 'lensFacing' LensFacing no + 'monoStrength' MonoStrength no + 'objectOrientation' ObjectOrientation no + 'outputHeight' OutputHeight no + 'outputWidth' OutputWidth no + 'perfMode' PerfMode no + 'segHeight' SegHeight no + 'segWidth' SegWidth no + 'sidelightStrength' SidelightStrength no + 'spinStrength' SpinStrength no + 'vintageStrength' VintageStrength no + 'zoomStrength' ZoomStrength no =head3 Samsung sec Tags @@ -15450,7 +18844,7 @@ such as the Galaxy S4. 0x1015 ToningEffect int16u 0x1016 HueAdjust int16u 0x1017 WideAdapter int16u - 0x1018 CropMode35mm int16u + 0x1018 CropMode int16u 0x1019 NDFilter int16u 0x101a WBBracketShotNumber int16u 0x1200 AFStatus int16u @@ -15547,7 +18941,7 @@ cameras. Tag ID Tag Name Writable ------ -------- -------- - 0x0207 RicohModel string + 0x0207 RicohModel no 0x0300 RicohMake no =head3 Ricoh Text Tags @@ -15578,6 +18972,7 @@ defined below, ExifTool will extract any information found here. 'Location' Location no 'Sign type' SignType no '_audio' SoundFile no + '_barcode' Barcodes no+ =head3 Ricoh AVI Tags @@ -15643,6 +19038,8 @@ are less than consistent about their metadata formats. 0x0024 Calibration string 0x0026 FileFormat string 0x0027 LensType string + LensType - + Sigma LensType 0x002a LensFocalRange rational64u[2] 0x002b LensMaxApertureRange rational64u[2] 0x002c ColorMode int32u @@ -15665,10 +19062,47 @@ are less than consistent about their metadata formats. 0x004d ExposureCompensation rational64s 0x0055 SensorTemperature string 0x0056 FlashExposureComp rational64s - 0x0057 Firmware string + 0x0057 Firmware2 string 0x0058 WhiteBalance string 0x0059 DigitalFilter string 0x0084 Model string + 0x0086 ISO int16u + 0x0087 ResolutionMode string + 0x0088 WhiteBalance string + 0x008c Firmware string + 0x011f CameraCalibration float[9] + 0x0120 WBSettings Sigma WBSettings + 0x0121 WBSettings2 Sigma WBSettings2 + +=head3 Sigma WBSettings Tags + + Index4 Tag Name Writable + ------ -------- -------- + 0 WB_RGBLevelsAuto float[3] + 3 WB_RGBLevelsDaylight float[3] + 6 WB_RGBLevelsShade float[3] + 9 WB_RGBLevelsOvercast float[3] + 12 WB_RGBLevelsIncandescent float[3] + 15 WB_RGBLevelsFluorescent float[3] + 18 WB_RGBLevelsFlash float[3] + 21 WB_RGBLevelsCustom1 float[3] + 24 WB_RGBLevelsCustom2 float[3] + 27 WB_RGBLevelsCustom3 float[3] + +=head3 Sigma WBSettings2 Tags + + Index4 Tag Name Writable + ------ -------- -------- + 0 WB_RGBLevelsUnknown0? float[3] + 3 WB_RGBLevelsUnknown1? float[3] + 6 WB_RGBLevelsUnknown2? float[3] + 9 WB_RGBLevelsUnknown3? float[3] + 12 WB_RGBLevelsUnknown4? float[3] + 15 WB_RGBLevelsUnknown5? float[3] + 18 WB_RGBLevelsUnknown6? float[3] + 21 WB_RGBLevelsUnknown7? float[3] + 24 WB_RGBLevelsUnknown8? float[3] + 27 WB_RGBLevelsUnknown9? float[3] =head2 Sony Tags @@ -15748,13 +19182,22 @@ MakerNotes. 0x202e Quality int16u[2] 0x202f PixelShiftInfo undef 0x2031 SerialNumber string + 0x2032 Shadows int32s + 0x2033 Highlights int32s + 0x2034 Fade int32s + 0x2035 SharpnessRange int32s + 0x2036 Clarity int32s + 0x2037 FocusFrameSize no + 0x2039 JPEG-HEIFSwitch int16u 0x3000 ShotInfo Sony ShotInfo 0x900b Tag900b Sony Tag900b 0x9050 Tag9050a Sony Tag9050a Tag9050b Sony Tag9050b + Tag9050c Sony Tag9050c 0x9400 Tag9400a Sony Tag9400a Tag9400b Sony Tag9400b Tag9400c Sony Tag9400c + 0x9401 Tag9401 Sony Tag9401 0x9402 Tag9402 Sony Tag9402 0x9403 Tag9403 Sony Tag9403 0x9404 Tag9404a Sony Tag9404a @@ -15767,6 +19210,7 @@ MakerNotes. 0x940c Tag940c Sony Tag940c 0x940e AFInfo Sony AFInfo Tag940e Sony Tag940e + 0x9416 Sony_0x9416 Sony Tag9416 0xb000 FileFormat int8u[4] 0xb001 SonyModelID int16u 0xb020 CreativeStyle string @@ -16337,25 +19781,25 @@ rotation -- the width is always the longer dimension. Valid for NEX-5N. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x04b0 MeterInfo? Sony MeterInfo - 0x1128 ReleaseMode3 int8u - 0x112c ReleaseMode2 int8u - 0x1134 SelfTimer int8u - 0x1138 FlashMode int8u - 0x113e StopsAboveBaseISO int16u - 0x1140 BrightnessValue int16u - 0x1144 DynamicRangeOptimizer int8u - 0x1148 HDRSetting int8u - 0x114c ExposureCompensation int16s - 0x115e PictureProfile int8u - 0x115f PictureProfile int8u - 0x1163 PictureEffect2 int8u - 0x1170 Quality2 int8u - 0x1174 MeteringMode int8u - 0x1175 ExposureProgram int8u - 0x117c WB_RGBLevels int16u[3] + 1200 MeterInfo? Sony MeterInfo + 4392 ReleaseMode3 int8u + 4396 ReleaseMode2 int8u + 4404 SelfTimer int8u + 4408 FlashMode int8u + 4414 StopsAboveBaseISO int16u + 4416 BrightnessValue int16u + 4420 DynamicRangeOptimizer int8u + 4424 HDRSetting int8u + 4428 ExposureCompensation int16s + 4446 PictureProfile int8u + 4447 PictureProfile int8u + 4451 PictureEffect2 int8u + 4464 Quality2 int8u + 4468 MeteringMode int8u + 4469 ExposureProgram int8u + 4476 WB_RGBLevels int16u[3] =head3 Sony MeterInfo Tags @@ -16385,281 +19829,282 @@ option is used. Valid for SLT-A65/A77, NEX-7/VG20E. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0000 SequenceImageNumber int32u - 0x0004 SequenceFileNumber int32u - 0x0008 ReleaseMode2 int32u - 0x01b6 SonyDateTime undef[7] - 0x0324 DynamicRangeOptimizer int8u - 0x04b4 MeterInfo? Sony MeterInfo - 0x1128 ReleaseMode3 int8u - 0x112c ReleaseMode2 int8u - 0x1134 SelfTimer int8u - 0x1138 FlashMode int8u - 0x113e StopsAboveBaseISO int16u - 0x1140 BrightnessValue int16u - 0x1144 DynamicRangeOptimizer int8u - 0x1148 HDRSetting int8u - 0x114c ExposureCompensation int16s - 0x1162 PictureProfile int8u - 0x1163 PictureProfile int8u - 0x1167 PictureEffect2 int8u - 0x1174 Quality2 int8u - 0x1178 MeteringMode int8u - 0x1179 ExposureProgram int8u - 0x1180 WB_RGBLevels int16u[3] - 0x1218 SonyISO int16u - 0x1a23 DistortionCorrParams int16s[16] + 0 SequenceImageNumber int32u + 4 SequenceFileNumber int32u + 8 ReleaseMode2 int32u + 438 SonyDateTime undef[7] + 804 DynamicRangeOptimizer int8u + 1204 MeterInfo? Sony MeterInfo + 4392 ReleaseMode3 int8u + 4396 ReleaseMode2 int8u + 4404 SelfTimer int8u + 4408 FlashMode int8u + 4414 StopsAboveBaseISO int16u + 4416 BrightnessValue int16u + 4420 DynamicRangeOptimizer int8u + 4424 HDRSetting int8u + 4428 ExposureCompensation int16s + 4450 PictureProfile int8u + 4451 PictureProfile int8u + 4455 PictureEffect2 int8u + 4468 Quality2 int8u + 4472 MeteringMode int8u + 4473 ExposureProgram int8u + 4480 WB_RGBLevels int16u[3] + 4632 SonyISO int16u + 6691 DistortionCorrParams int16s[16] =head3 Sony Tag2010c Tags Valid for SLT-A37/A57 and NEX-F3. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0000 SequenceImageNumber int32u - 0x0004 SequenceFileNumber int32u - 0x0008 ReleaseMode2 int32u - 0x0200 DigitalZoomRatio int8u - 0x0210 SonyDateTime undef[7] - 0x0300 DynamicRangeOptimizer int8u - 0x0490 MeterInfo? Sony MeterInfo - 0x1104 ReleaseMode3 int8u - 0x1108 ReleaseMode2 int8u - 0x1110 SelfTimer int8u - 0x1114 FlashMode int8u - 0x111a StopsAboveBaseISO int16u - 0x111c BrightnessValue int16u - 0x1120 DynamicRangeOptimizer int8u - 0x1124 HDRSetting int8u - 0x1128 ExposureCompensation int16s - 0x113e PictureProfile int8u - 0x113f PictureProfile int8u - 0x1143 PictureEffect2 int8u - 0x1150 Quality2 int8u - 0x1154 MeteringMode int8u - 0x1155 ExposureProgram int8u - 0x115c WB_RGBLevels int16u[3] - 0x11f4 SonyISO int16u + 0 SequenceImageNumber int32u + 4 SequenceFileNumber int32u + 8 ReleaseMode2 int32u + 512 DigitalZoomRatio int8u + 528 SonyDateTime undef[7] + 768 DynamicRangeOptimizer int8u + 1168 MeterInfo? Sony MeterInfo + 4356 ReleaseMode3 int8u + 4360 ReleaseMode2 int8u + 4368 SelfTimer int8u + 4372 FlashMode int8u + 4378 StopsAboveBaseISO int16u + 4380 BrightnessValue int16u + 4384 DynamicRangeOptimizer int8u + 4388 HDRSetting int8u + 4392 ExposureCompensation int16s + 4414 PictureProfile int8u + 4415 PictureProfile int8u + 4419 PictureEffect2 int8u + 4432 Quality2 int8u + 4436 MeteringMode int8u + 4437 ExposureProgram int8u + 4444 WB_RGBLevels int16u[3] + 4596 SonyISO int16u =head3 Sony Tag2010d Tags Valid for DSC-HX10V/HX20V/HX200V/TX66/TX200V/TX300V/WX50/WX100/WX150, but not valid for panorama images. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0000 SequenceImageNumber int32u - 0x0004 SequenceFileNumber int32u - 0x0008 ReleaseMode2 int32u - 0x01fe SonyDateTime undef[7] - 0x037c DynamicRangeOptimizer int8u - 0x050c MeterInfo? Sony MeterInfo - 0x1180 ReleaseMode3 int8u - 0x1184 ReleaseMode2 int8u - 0x118c SelfTimer int8u - 0x1190 FlashMode int8u - 0x1196 StopsAboveBaseISO int16u - 0x1198 BrightnessValue int16u - 0x119c DynamicRangeOptimizer int8u - 0x11a0 HDRSetting int8u - 0x11ba PictureProfile int8u - 0x11bb PictureProfile int8u - 0x11bf PictureEffect2 int8u - 0x11d0 MeteringMode int8u - 0x11d1 ExposureProgram int8u - 0x11d8 WB_RGBLevels int16u[3] - 0x1270 SonyISO int16u + 0 SequenceImageNumber int32u + 4 SequenceFileNumber int32u + 8 ReleaseMode2 int32u + 510 SonyDateTime undef[7] + 892 DynamicRangeOptimizer int8u + 1292 MeterInfo? Sony MeterInfo + 4480 ReleaseMode3 int8u + 4484 ReleaseMode2 int8u + 4492 SelfTimer int8u + 4496 FlashMode int8u + 4502 StopsAboveBaseISO int16u + 4504 BrightnessValue int16u + 4508 DynamicRangeOptimizer int8u + 4512 HDRSetting int8u + 4538 PictureProfile int8u + 4539 PictureProfile int8u + 4543 PictureEffect2 int8u + 4560 MeteringMode int8u + 4561 ExposureProgram int8u + 4568 WB_RGBLevels int16u[3] + 4720 SonyISO int16u =head3 Sony Tag2010e Tags -Valid for SLT-A58/A99, ILCE-3000/3500, NEX-3N/5R/5T/6/VG30E/VG900, DSC-RX100, -DSC-RX1/RX1R. Also valid for DSC-HX300/HX50V/TX30/WX60/WX200/WX300, but not -for panorama images. - - Tag ID Tag Name Writable - ------ -------- -------- - 0x0000 SequenceImageNumber int32u - 0x0004 SequenceFileNumber int32u - 0x0008 ReleaseMode2 int32u - 0x021c DigitalZoomRatio int8u - 0x022c SonyDateTime undef[7] - 0x0328 DynamicRangeOptimizer int8u - 0x04b8 MeterInfo? Sony MeterInfo - 0x115c ReleaseMode3 int8u - 0x1160 ReleaseMode2 int8u - 0x1168 SelfTimer int8u - 0x116c FlashMode int8u - 0x1172 StopsAboveBaseISO int16u - 0x1174 BrightnessValue int16u - 0x1178 DynamicRangeOptimizer int8u - 0x117c HDRSetting int8u - 0x1180 ExposureCompensation int16s - 0x1196 PictureProfile int8u - 0x1197 PictureProfile int8u - 0x119b PictureEffect2 int8u - 0x11a8 Quality2 int8u - 0x11ac MeteringMode int8u - 0x11ad ExposureProgram int8u - 0x11b4 WB_RGBLevels int16u[3] - 0x1254 SonyISO int16u - 0x1258 SonyISO int16u - 0x1278 FocalLength int16u - 0x127a MinFocalLength int16u - 0x127c MaxFocalLength int16u - 0x1280 SonyISO int16u - 0x1870 DistortionCorrParams int16s[16] - 0x1891 LensFormat int8u - 0x1892 LensMount int8u - 0x1893 LensType2 int16u - 0x1896 LensType int16u - 0x1898 DistortionCorrParamsPresent int8u - 0x1899 DistortionCorrParamsNumber int8u +Valid for SLT-A58/A99, ILCE-3000/3500, NEX-3N/5R/5T/6/VG30E/VG900, +DSC-RX100, DSC-RX1/RX1R. Also valid for DSC-HX300/HX50V/TX30/WX60/WX200/ +WX300, but not for panorama images. + + Index1 Tag Name Writable + ------ -------- -------- + 0 SequenceImageNumber int32u + 4 SequenceFileNumber int32u + 8 ReleaseMode2 int32u + 540 DigitalZoomRatio int8u + 556 SonyDateTime undef[7] + 808 DynamicRangeOptimizer int8u + 1208 MeterInfo? Sony MeterInfo + 4444 ReleaseMode3 int8u + 4448 ReleaseMode2 int8u + 4456 SelfTimer int8u + 4460 FlashMode int8u + 4466 StopsAboveBaseISO int16u + 4468 BrightnessValue int16u + 4472 DynamicRangeOptimizer int8u + 4476 HDRSetting int8u + 4480 ExposureCompensation int16s + 4502 PictureProfile int8u + 4503 PictureProfile int8u + 4507 PictureEffect2 int8u + 4520 Quality2 int8u + 4524 MeteringMode int8u + 4525 ExposureProgram int8u + 4532 WB_RGBLevels int16u[3] + 4692 SonyISO int16u + 4696 SonyISO int16u + 4728 FocalLength int16u + 4730 MinFocalLength int16u + 4732 MaxFocalLength int16u + 4736 SonyISO int16u + 6256 DistortionCorrParams int16s[16] + 6289 LensFormat int8u + 6290 LensMount int8u + 6291 LensType2 int16u + 6294 LensType int16u + 6296 DistortionCorrParamsPresent int8u + 6297 DistortionCorrParamsNumber int8u =head3 Sony Tag2010f Tags Valid for DSC-RX100M2, DSC-QX10/QX100. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0004 ReleaseMode2 int32u - 0x0050 DynamicRangeOptimizer int8u - 0x01e0 MeterInfo? Sony MeterInfo - 0x1014 ReleaseMode3 int8u - 0x1018 ReleaseMode2 int8u - 0x1020 SelfTimer int8u - 0x1024 FlashMode int8u - 0x102a StopsAboveBaseISO int16u - 0x102c BrightnessValue int16u - 0x1030 DynamicRangeOptimizer int8u - 0x1034 HDRSetting int8u - 0x1038 ExposureCompensation int16s - 0x104e PictureProfile int8u - 0x104f PictureProfile int8u - 0x1053 PictureEffect2 int8u - 0x1060 Quality2 int8u - 0x1064 MeteringMode int8u - 0x1065 ExposureProgram int8u - 0x106c WB_RGBLevels int16u[3] - 0x1134 FocalLength int16u - 0x1136 MinFocalLength int16u - 0x1138 MaxFocalLength int16u - 0x113c SonyISO int16u + 4 ReleaseMode2 int32u + 80 DynamicRangeOptimizer int8u + 480 MeterInfo? Sony MeterInfo + 4116 ReleaseMode3 int8u + 4120 ReleaseMode2 int8u + 4128 SelfTimer int8u + 4132 FlashMode int8u + 4138 StopsAboveBaseISO int16u + 4140 BrightnessValue int16u + 4144 DynamicRangeOptimizer int8u + 4148 HDRSetting int8u + 4152 ExposureCompensation int16s + 4174 PictureProfile int8u + 4175 PictureProfile int8u + 4179 PictureEffect2 int8u + 4192 Quality2 int8u + 4196 MeteringMode int8u + 4197 ExposureProgram int8u + 4204 WB_RGBLevels int16u[3] + 4404 FocalLength int16u + 4406 MinFocalLength int16u + 4408 MaxFocalLength int16u + 4412 SonyISO int16u =head3 Sony Tag2010g Tags Valid for DSC-HX60V/HX350/HX400V/QX30/RX10/RX100M3/WX220/WX350, ILCE-7/7R/7S/7M2/5000/5100/6000/QX1, ILCA-68/77M2. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0004 ReleaseMode2 int32u - 0x0050 DynamicRangeOptimizer int8u - 0x020c ReleaseMode3 int8u - 0x0210 ReleaseMode2 int8u - 0x0218 SelfTimer int8u - 0x021c FlashMode int8u - 0x0222 StopsAboveBaseISO int16u - 0x0224 BrightnessValue int16u - 0x0228 DynamicRangeOptimizer int8u - 0x022c HDRSetting int8u - 0x0230 ExposureCompensation int16s - 0x0246 PictureProfile int8u - 0x0247 PictureProfile int8u - 0x024b PictureEffect2 int8u - 0x0258 Quality2 int8u - 0x025c MeteringMode int8u - 0x025d ExposureProgram int8u - 0x0264 WB_RGBLevels int16u[3] - 0x032c FocalLength int16u - 0x032e MinFocalLength int16u - 0x0330 MaxFocalLength int16u - 0x0344 SonyISO int16u - 0x0388 MeterInfo? Sony MeterInfo - 0x189c DistortionCorrParams int16s[16] - 0x18bd LensFormat int8u - 0x18be LensMount int8u - 0x18bf LensType2 int16u - 0x18c2 LensType int16u - 0x18c4 DistortionCorrParamsPresent int8u - 0x18c5 DistortionCorrParamsNumber int8u + 4 ReleaseMode2 int32u + 80 DynamicRangeOptimizer int8u + 524 ReleaseMode3 int8u + 528 ReleaseMode2 int8u + 536 SelfTimer int8u + 540 FlashMode int8u + 546 StopsAboveBaseISO int16u + 548 BrightnessValue int16u + 552 DynamicRangeOptimizer int8u + 556 HDRSetting int8u + 560 ExposureCompensation int16s + 582 PictureProfile int8u + 583 PictureProfile int8u + 587 PictureEffect2 int8u + 600 Quality2 int8u + 604 MeteringMode int8u + 605 ExposureProgram int8u + 612 WB_RGBLevels int16u[3] + 812 FocalLength int16u + 814 MinFocalLength int16u + 816 MaxFocalLength int16u + 836 SonyISO int16u + 904 MeterInfo? Sony MeterInfo + 6300 DistortionCorrParams int16s[16] + 6333 LensFormat int8u + 6334 LensMount int8u + 6335 LensType2 int16u + 6338 LensType int16u + 6340 DistortionCorrParamsPresent int8u + 6341 DistortionCorrParamsNumber int8u =head3 Sony Tag2010h Tags -Valid for DSC-HX90V/RX0/RX1RM2/RX10M2/RX10M3/RX100M4/RX100M5/WX500, +Valid for DSC-HX80/HX90V/RX0/RX1RM2/RX10M2/RX10M3/RX100M4/RX100M5/WX500, ILCE-6300/6500/7RM2/7SM2, ILCA-99M2. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0004 ReleaseMode2 int32u - 0x0050 DynamicRangeOptimizer int8u - 0x020c ReleaseMode3 int8u - 0x0210 ReleaseMode2 int8u - 0x0218 SelfTimer int8u - 0x021c FlashMode int8u - 0x0222 StopsAboveBaseISO int16u - 0x0224 BrightnessValue int16u - 0x0228 DynamicRangeOptimizer int8u - 0x022c HDRSetting int8u - 0x0230 ExposureCompensation int16s - 0x0246 PictureProfile int8u - 0x0247 PictureProfile int8u - 0x024b PictureEffect2 int8u - 0x0258 Quality2 int8u - 0x025c MeteringMode int8u - 0x025d ExposureProgram int8u - 0x0264 WB_RGBLevels int16u[3] - 0x032c FocalLength int16u - 0x032e MinFocalLength int16u - 0x0330 MaxFocalLength int16u - 0x0346 SonyISO int16u - 0x0388 MeterInfo? Sony MeterInfo - 0x0398 MeterInfo? Sony MeterInfo - 0x18cc DistortionCorrParams int16s[16] - 0x18ed LensFormat int8u - 0x18ee LensMount int8u - 0x18ef LensType2 int16u - 0x18f2 LensType int16u - 0x18f4 DistortionCorrParamsPresent int8u - 0x18f5 DistortionCorrParamsNumber int8u + 4 ReleaseMode2 int32u + 80 DynamicRangeOptimizer int8u + 524 ReleaseMode3 int8u + 528 ReleaseMode2 int8u + 536 SelfTimer int8u + 540 FlashMode int8u + 546 StopsAboveBaseISO int16u + 548 BrightnessValue int16u + 552 DynamicRangeOptimizer int8u + 556 HDRSetting int8u + 560 ExposureCompensation int16s + 582 PictureProfile int8u + 583 PictureProfile int8u + 587 PictureEffect2 int8u + 600 Quality2 int8u + 604 MeteringMode int8u + 605 ExposureProgram int8u + 612 WB_RGBLevels int16u[3] + 812 FocalLength int16u + 814 MinFocalLength int16u + 816 MaxFocalLength int16u + 838 SonyISO int16u + 904 MeterInfo? Sony MeterInfo + 920 MeterInfo? Sony MeterInfo + 6348 DistortionCorrParams int16s[16] + 6381 LensFormat int8u + 6382 LensMount int8u + 6383 LensType2 int16u + 6386 LensType int16u + 6388 DistortionCorrParamsPresent int8u + 6389 DistortionCorrParamsNumber int8u =head3 Sony Tag2010i Tags -Valid for ILCE-7M3/7RM3/9, DSC-RX10M4/RX100M6/RX100M5A. - - Tag ID Tag Name Writable - ------ -------- -------- - 0x0004 ReleaseMode2 int32u - 0x004e DynamicRangeOptimizer int8u - 0x0204 ReleaseMode3 int8u - 0x0208 ReleaseMode2 int8u - 0x0210 SelfTimer int8u - 0x0211 FlashMode int8u - 0x0217 StopsAboveBaseISO int16u - 0x0219 BrightnessValue int16u - 0x021b DynamicRangeOptimizer int8u - 0x021f HDRSetting int8u - 0x0223 ExposureCompensation int16s - 0x0237 PictureProfile int8u - 0x0238 PictureProfile int8u - 0x023c PictureEffect2 int8u - 0x0247 Quality2 int8u - 0x024b MeteringMode int8u - 0x024c ExposureProgram int8u - 0x0252 WB_RGBLevels int16u[3] - 0x030a FocalLength int16u - 0x030c MinFocalLength int16u - 0x030e MaxFocalLength int16u - 0x0320 SonyISO int16u - 0x036d MeterInfo? Sony MeterInfo9 - 0x17d0 DistortionCorrParams int16s[16] - 0x17f1 LensFormat int8u - 0x17f2 LensMount int8u - 0x17f3 LensType2 int16u - 0x17f6 LensType int16u - 0x17f8 DistortionCorrParamsPresent int8u - 0x17f9 DistortionCorrParamsNumber int8u +Valid for ILCE-6100/6400/6600/7C/7M3/7RM3/7RM4/9/9M2, DSC-RX0M2/RX10M4/RX100M6/ +RX100M5A/RX100M7/HX99. + + Index1 Tag Name Writable + ------ -------- -------- + 4 ReleaseMode2 int32u + 78 DynamicRangeOptimizer int8u + 516 ReleaseMode3 int8u + 520 ReleaseMode2 int8u + 528 SelfTimer int8u + 529 FlashMode int8u + 535 StopsAboveBaseISO int16u + 537 BrightnessValue int16u + 539 DynamicRangeOptimizer int8u + 543 HDRSetting int8u + 547 ExposureCompensation int16s + 567 PictureProfile int8u + 568 PictureProfile int8u + 572 PictureEffect2 int8u + 583 Quality2 int8u + 587 MeteringMode int8u + 588 ExposureProgram int8u + 594 WB_RGBLevels int16u[3] + 778 FocalLength int16u + 780 MinFocalLength int16u + 782 MaxFocalLength int16u + 800 SonyISO int16u + 877 MeterInfo? Sony MeterInfo9 + 6096 DistortionCorrParams int16s[16] + 6129 LensFormat int8u + 6130 LensMount int8u + 6131 LensType2 int16u + 6134 LensType int16u + 6136 DistortionCorrParamsPresent int8u + 6137 DistortionCorrParamsNumber int8u =head3 Sony MeterInfo9 Tags @@ -16749,282 +20194,343 @@ option is used. =head3 Sony Tag900b Tags - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0002 FacesDetected no - 0x00bd FaceDetection no + 2 FacesDetected no + 189 FaceDetection no =head3 Sony Tag9050a Tags Data for tags 0x9050, 0x94xx and 0x2010 is encrypted by a simple substitution cipher, but the deciphered values are listed below. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0000 SonyMaxAperture int8u - 0x0001 SonyMinAperture int8u - 0x0031 FlashStatus int8u - 0x0032 ImageCount int32u - 0x003a SonyExposureTime int16u - 0x003c SonyFNumber int16u - 0x003f ReleaseMode2 int8u - 0x004c ImageCount2 int32u - 0x0051 SonyDateTime2 undef[6] - 0x0067 ReleaseMode2 int8u - 0x007c InternalSerialNumber int8u[4]~ - 0x00f0 InternalSerialNumber int8u[5] - 0x0105 LensMount int8u - 0x0106 LensFormat int8u - 0x0107 LensType2 int16u - 0x0109 LensType int16u - 0x010b DistortionCorrParamsPresent int8u - 0x0115 LensSpecFeatures undef[2] - 0x0116 LensSpecFeatures undef[2] - 0x01a0 ImageCount3 int32u - 0x01aa ImageCount3 int32u - 0x01bd ImageCount3 int32u + 0 SonyMaxAperture int8u + 1 SonyMinAperture int8u + 32 Shutter int16u[3] + 49 FlashStatus int8u + 50 ShutterCount int32u + 58 SonyExposureTime int16u + 60 SonyFNumber int16u + 63 ReleaseMode2 int8u + 76 ShutterCount2 int32u + 81 SonyDateTime2 undef[6] + 103 ReleaseMode2 int8u + 124 InternalSerialNumber int8u[4]~ + 240 InternalSerialNumber int8u[5] + 261 LensMount int8u + 262 LensFormat int8u + 263 LensType2 int16u + 265 LensType int16u + 267 DistortionCorrParamsPresent int8u + 276 APS-CSizeCapture int8u + 277 LensSpecFeatures undef[2] + 278 LensSpecFeatures undef[2] + 416 ShutterCount3 int32u + 426 ShutterCount3 int32u + 445 ShutterCount3 int32u =head3 Sony Tag9050b Tags -Valid from July 2015 for ILCE-6300/6500/7M3/7RM2/7RM3/7SM2/9, ILCA-99M2. - - Tag ID Tag Name Writable - ------ -------- -------- - 0x0000 SonyMaxAperture int8u - 0x0001 SonyMinAperture int8u - 0x0039 FlashStatus int8u - 0x003a ImageCount int32u - 0x0046 SonyExposureTime int16u - 0x0048 SonyFNumber int16u - 0x004b ReleaseMode2 int8u - 0x0052 ImageCount2 int32u~ - 0x0058 ImageCount2 int32u - 0x0061 SonyTimeMinSec no - 0x0073 ReleaseMode2 int8u - 0x0088 InternalSerialNumber int8u[6]~ - 0x0105 LensMount int8u - 0x0106 LensFormat int8u - 0x0107 LensType2 int16u - 0x0109 LensType int16u - 0x010b DistortionCorrParamsPresent int8u - 0x0116 LensSpecFeatures undef[2] - 0x019f ImageCount3 int32u - 0x01cb ImageCount3 int32u - 0x01cd ImageCount3 int32u - 0x021c LensSpecFeatures undef[2] - 0x021e LensSpecFeatures undef[2] +Valid from July 2015 for ILCE-6100/6300/6400/6500/6600/7C/7M3/7RM2/7RM3/7RM4/ +7SM2/9/9M2, ILCA-99M2. + + Index1 Tag Name Writable + ------ -------- -------- + 0 SonyMaxAperture int8u + 1 SonyMinAperture int8u + 38 Shutter int16u[3] + 57 FlashStatus int8u + 58 ShutterCount int32u + 70 SonyExposureTime int16u + 72 SonyFNumber int16u + 75 ReleaseMode2 int8u + 80 ShutterCount2 int32u + 82 ShutterCount2 int32u + 88 ShutterCount2 int32u + 97 SonyTimeMinSec no + 107 ReleaseMode2 int8u + 109 ReleaseMode2 int8u + 115 ReleaseMode2 int8u + 136 InternalSerialNumber int8u[6]~ + 261 LensMount int8u + 262 LensFormat int8u + 263 LensType2 int16u + 265 LensType int16u + 267 DistortionCorrParamsPresent int8u + 276 APS-CSizeCapture int8u + 278 LensSpecFeatures undef[2] + 415 ShutterCount3 int32u + 459 ShutterCount3 int32u + 461 ShutterCount3 int32u + 491 APS-CSizeCapture int8u + 493 LensSpecFeatures undef[2] + 494 APS-CSizeCapture int8u + 496 LensSpecFeatures undef[2] + 538 APS-CSizeCapture int8u + 540 LensSpecFeatures undef[2] + APS-CSizeCapture int8u + 542 LensSpecFeatures undef[2] + +=head3 Sony Tag9050c Tags + +Valid from July 2020 for ILCE-1/7SM3, ILME-FX3. + + Index1 Tag Name Writable + ------ -------- -------- + 38 Shutter int16u[3] + 57 FlashStatus int8u + 58 ShutterCount int32u~ + 70 SonyExposureTime int16u + 72 SonyFNumber int16u + 75 ReleaseMode2 int8u + 80 ShutterCount2 int32u + 102 SonyExposureTime int16u + 104 SonyFNumber int16u + 107 ReleaseMode2 int8u + 136 InternalSerialNumber int8u[6]~ + 138 InternalSerialNumber int8u[6]~ =head3 Sony Tag9400a Tags Valid for many DSC, NEX and SLT models - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0008 SequenceImageNumber int32u - 0x000c SequenceFileNumber int32u - 0x0010 ReleaseMode2 int8u - 0x0012 DigitalZoom int8u - 0x001a ShotNumberSincePowerUp int32u - 0x0022 SequenceLength int8u - 0x0028 CameraOrientation int8u - 0x0029 Quality2 int8u - 0x0044 SonyImageHeight int16u~ - 0x0052 ModelReleaseYear int8u~ + 8 SequenceImageNumber int32u + 12 SequenceFileNumber int32u + 16 ReleaseMode2 int8u + 18 DigitalZoom int8u + 26 ShotNumberSincePowerUp int32u + 34 SequenceLength int8u + 40 CameraOrientation int8u + 41 Quality2 int8u + 68 SonyImageHeight int16u~ + 82 ModelReleaseYear int8u~ =head3 Sony Tag9400b Tags Valid for NEX-3N, ILCE-3000/3500, SLT-A58, DSC-WX60, DSC-WX300, DSC-RX100M2, DSC-HX50V, DSC-QX10/QX100. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0008 SequenceImageNumber int32u - 0x000c SequenceFileNumber int32u - 0x0010 ReleaseMode2 int8u - 0x0012 DigitalZoom int8u - 0x0016 ShotNumberSincePowerUp int32u - 0x001e SequenceLength int8u - 0x0024 CameraOrientation int8u - 0x0025 Quality2 int8u - 0x003f SonyImageHeight int16u~ - 0x0046 ModelReleaseYear int8u~ + 8 SequenceImageNumber int32u + 12 SequenceFileNumber int32u + 16 ReleaseMode2 int8u + 18 DigitalZoom int8u + 22 ShotNumberSincePowerUp int32u + 30 SequenceLength int8u + 36 CameraOrientation int8u + 37 Quality2 int8u + 63 SonyImageHeight int16u~ + 70 ModelReleaseYear int8u~ =head3 Sony Tag9400c Tags -Valid for DSC-HX60V/HX90V/HX350/HX400V/QX30/RX0/RX1RM2/RX10/RX10M2/RX10M3/ -RX10M4/RX100M3/RX100M4/RX100M5/RX100M6/WX220/WX350/WX500, ILCE-7/7R/7S/ -7M2/7M3/7RM2/7RM3/7SM2/9/5000/5100/6000/6300/6500/QX1, ILCA-68/77M2/99M2. +Valid for DSC-HX60V/HX80/HX90V/HX99/HX350/HX400V/QX30/RX0/RX1RM2/RX10/ +RX10M2/RX10M3/RX10M4/RX100M3/RX100M4/RX100M5/RX100M5A/RX100M6/RX100M7/WX220/ +WX350/WX500, ILCE-1/7/7C/7R/7S/7M2/7M3/7RM2/7RM3/7RM4/7SM2/7SM3/9/9M2/5000/ +5100/6000/6100/6300/6400/6500/6600/QX1, ILCA-68/77M2/99M2. - Tag ID Tag Name Writable + Index1 Tag Name Writable + ------ -------- -------- + 9 ReleaseMode2 int8u + 10 ShotNumberSincePowerUp int32u + 18 SequenceImageNumber int32u + 22 SequenceLength int8u + 26 SequenceFileNumber int32u + 30 SequenceLength int8u + 41 CameraOrientation int8u + 42 Quality2 int8u + 71 SonyImageHeight int16u~ + 83 ModelReleaseYear int8u~ + +=head3 Sony Tag9401 Tags + + Index1 Tag Name Writable + ------ -------- -------- + 1176 ISOInfo Sony ISOInfo + 1181 ISOInfo Sony ISOInfo + 1185 ISOInfo Sony ISOInfo + 1186 ISOInfo Sony ISOInfo + 1437 ISOInfo Sony ISOInfo + 1588 ISOInfo Sony ISOInfo + 1590 ISOInfo Sony ISOInfo + 1612 ISOInfo Sony ISOInfo + 1619 ISOInfo Sony ISOInfo + 1656 ISOInfo Sony ISOInfo + 1720 ISOInfo Sony ISOInfo + 1758 ISOInfo Sony ISOInfo + 1767 ISOInfo Sony ISOInfo + +=head3 Sony ISOInfo Tags + + Index1 Tag Name Writable ------ -------- -------- - 0x0009 ReleaseMode2 int8u - 0x000a ShotNumberSincePowerUp int8u - ShotNumberSincePowerUp int32u - 0x0012 SequenceImageNumber int32u - 0x0016 SequenceLength int8u - 0x001a SequenceFileNumber int32u - 0x001e SequenceLength int8u - 0x0029 CameraOrientation int8u - 0x002a Quality2 int8u - 0x0047 SonyImageHeight int16u~ - 0x0053 ModelReleaseYear int8u~ + 0 ISOSetting int8u + 2 ISOAutoMin int8u + 4 ISOAutoMax int8u =head3 Sony Tag9402 Tags - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0004 AmbientTemperature int8s - 0x0016 FocusMode int8u & 0x7f - 0x0017 AFAreaMode int8u - 0x002d FocusPosition2 int8u + 4 AmbientTemperature int8s + 22 FocusMode int8u & 0x7f + 23 AFAreaMode int8u + 45 FocusPosition2 int8u =head3 Sony Tag9403 Tags - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0005 CameraTemperature int8s + 5 CameraTemperature int8s =head3 Sony Tag9404a Tags - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x000b ExposureProgram int8u - 0x000d IntelligentAuto int8u - 0x0019 LensZoomPosition int16u + 11 ExposureProgram int8u + 13 IntelligentAuto int8u + 25 LensZoomPosition int16u =head3 Sony Tag9404b Tags - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x000c ExposureProgram int8u - 0x000e IntelligentAuto int8u - 0x001e LensZoomPosition int16u - 0x0020 FocusPosition2 int8u + 12 ExposureProgram int8u + 14 IntelligentAuto int8u + 30 LensZoomPosition int16u + 32 FocusPosition2 int8u =head3 Sony Tag9404c Tags - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x000b ExposureProgram int8u - 0x000d IntelligentAuto int8u + 11 ExposureProgram int8u + 13 IntelligentAuto int8u =head3 Sony Tag9405a Tags Valid for SLT, NEX, ILCE-3000/3500 and several DSC models. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0600 DistortionCorrParamsPresent int8u - 0x0601 DistortionCorrection int8u - 0x0603 LensFormat int8u - 0x0604 LensMount int8u - 0x0605 LensType2 int16u - 0x0608 LensType int16u - 0x064a VignettingCorrParams int16s[16] - 0x066a ChromaticAberrationCorrParams int16s[32] - 0x06ca DistortionCorrParams int16s[16] + 1536 DistortionCorrParamsPresent int8u + 1537 DistortionCorrection int8u + 1539 LensFormat int8u + 1540 LensMount int8u + 1541 LensType2 int16u + 1544 LensType int16u + 1610 VignettingCorrParams int16s[16] + 1642 ChromaticAberrationCorrParams int16s[32] + 1738 DistortionCorrParams int16s[16] =head3 Sony Tag9405b Tags -Valid for DSC-HX60V/HX350/HX400V/QX30/RX0/RX10/RX10M2/RX10M3/RX10M4/ -RX100M3/RX100M4/RX100M5/RX100M6/WX220/WX350, ILCE-7/7M2/7M3/7R/7RM2/ -7S/7SM2/9/5000/5100/6000/6300/6500/QX1, ILCA-68/77M2/99M2. - - Tag ID Tag Name Writable - ------ -------- -------- - 0x0004 SonyISO int16u - 0x0006 BaseISO int16u - 0x000a StopsAboveBaseISO int16u - 0x000e SonyExposureTime2 int16u - 0x0010 ExposureTime rational32u - 0x0014 SonyFNumber int16u - 0x0016 SonyMaxApertureValue int16u - 0x0024 SequenceImageNumber int32u - 0x0034 ReleaseMode2 int8u - 0x003e SonyImageWidthMax int16u - 0x0040 SonyImageHeightMax int16u - 0x0042 HighISONoiseReduction int8u - 0x0044 LongExposureNoiseReduction int8u - 0x0046 PictureEffect2 int8u - 0x0048 ExposureProgram int8u - 0x004a CreativeStyle int8u - 0x0052 Sharpness int8s - 0x005a DistortionCorrParamsPresent int8u - 0x005b DistortionCorrection int8u - 0x005d LensFormat int8u - 0x005e LensMount int8u - 0x0060 LensType2 int16u - 0x0062 LensType int16u - 0x0064 DistortionCorrParams int16s[16] - 0x0342 LensZoomPosition int16u - 0x034a VignettingCorrParams int16s[16] - 0x0350 VignettingCorrParams int16s[16] - 0x035a LensZoomPosition int16u - 0x035c VignettingCorrParams int16s[16] - 0x0368 VignettingCorrParams int16s[16] - 0x037c ChromaticAberrationCorrParams int16s[32] - 0x0384 ChromaticAberrationCorrParams int16s[32] - 0x039c ChromaticAberrationCorrParams int16s[32] - 0x03b0 ChromaticAberrationCorrParams int16s[32] - 0x03b8 ChromaticAberrationCorrParams int16s[32] +Valid for DSC-HX60V/HX80/HX90V/HX99/HX350/HX400V/QX30/RX0/RX10/RX10M2/ +RX10M3/RX10M4/RX100M3/RX100M4/RX100M5/RX100M5A/RX100M6/RX100M7/WX220/WX350, +ILCE-7/7M2/7M3/7R/7RM2/7RM3/7RM4/7S/7SM2/9/9M2/5000/5100/6000/6100/6300/ +6400/6500/6600/QX1, ILCA-68/77M2/99M2. + + Index1 Tag Name Writable + ------ -------- -------- + 4 SonyISO int16u + 6 BaseISO int16u + 10 StopsAboveBaseISO int16u + 14 SonyExposureTime2 int16u + 16 ExposureTime rational32u + 20 SonyFNumber int16u + 22 SonyMaxApertureValue int16u + 36 SequenceImageNumber int32u + 52 ReleaseMode2 int8u + 62 SonyImageWidthMax int16u + 64 SonyImageHeightMax int16u + 66 HighISONoiseReduction int8u + 68 LongExposureNoiseReduction int8u + 70 PictureEffect2 int8u + 72 ExposureProgram int8u + 74 CreativeStyle int8u + 82 Sharpness int8s + 90 DistortionCorrParamsPresent int8u + 91 DistortionCorrection int8u + 93 LensFormat int8u + 94 LensMount int8u + 96 LensType2 int16u + 98 LensType int16u + 100 DistortionCorrParams int16s[16] + 834 LensZoomPosition int16u + 842 VignettingCorrParams int16s[16] + 846 LensZoomPosition int16u + 848 VignettingCorrParams int16s[16] + 858 LensZoomPosition int16u + 860 VignettingCorrParams int16s[16] + 872 VignettingCorrParams int16s[16] + 892 ChromaticAberrationCorrParams int16s[32] + 900 ChromaticAberrationCorrParams int16s[32] + 924 ChromaticAberrationCorrParams int16s[32] + 944 ChromaticAberrationCorrParams int16s[32] + 952 ChromaticAberrationCorrParams int16s[32] =head3 Sony Tag9406 Tags - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0005 BatteryTemperature int8u - 0x0006 BatteryLevelGrip1 int8u - 0x0007 BatteryLevel int8u - 0x0008 BatteryLevelGrip2 int8u + 5 BatteryTemperature int8u + 6 BatteryLevelGrip1 int8u + 7 BatteryLevel int8u + 8 BatteryLevelGrip2 int8u =head3 Sony Tag940a Tags These tags are currently extracted for SLT models only. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0004 AFPointsSelected int32u + 4 AFPointsSelected int32u =head3 Sony Tag940c Tags -NEX and ILCE models only. +E-mount cameras only. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0008 LensMount2 int8u - 0x0009 LensType3 int16u - 0x000b CameraE-mountVersion int16u - 0x000d LensE-mountVersion int16u - 0x0014 LensFirmwareVersion int16u~ + 8 LensMount2 int8u + 9 LensType3 int16u + 11 CameraE-mountVersion int16u + 13 LensE-mountVersion int16u + 20 LensFirmwareVersion int16u~ =head3 Sony AFInfo Tags These tags are currently extracted for SLT models only. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x0002 AFType int8u - 0x0004 AFStatusActiveSensor int16s - 0x0005 FocusMode int8u - 0x0007 AFPoint int8u - 0x0008 AFPointInFocus int8u - 0x0009 AFPointAtShutterRelease int8u - 0x000a AFAreaMode int8u - 0x000b FocusMode int8u - 0x0010 AFPointsUsed int8u[10] - 0x0011 AFStatus15 Sony AFStatus15 + 2 AFType int8u + 4 AFStatusActiveSensor int16s + 5 FocusMode int8u + 7 AFPoint int8u + 8 AFPointInFocus int8u + 9 AFPointAtShutterRelease int8u + 10 AFAreaMode int8u + 11 FocusMode int8u + 16 AFPointsUsed int8u[10] + 17 AFStatus15 Sony AFStatus15 AFStatus19 Sony AFStatus19 - 0x0037 AFPoint int8u - 0x0038 AFPointInFocus int8u - 0x0039 AFPointAtShutterRelease int8u - 0x003a AFAreaMode int8u - 0x003b AFStatusActiveSensor int16s - 0x0043 ExposureProgram int8u - 0x0050 AFMicroAdj int8s - 0x007d AFStatus79 Sony AFStatus79 - 0x016e AFPointsUsed int32u - 0x017d AFMicroAdj int8s - 0x017e ExposureProgram int8u + 55 AFPoint int8u + 56 AFPointInFocus int8u + 57 AFPointAtShutterRelease int8u + 58 AFAreaMode int8u + 59 AFStatusActiveSensor int16s + 67 ExposureProgram int8u + 80 AFMicroAdj int8s + 125 AFStatus79 Sony AFStatus79 + 366 AFPointsUsed int32u + 381 AFMicroAdj int8s + 382 ExposureProgram int8u =head3 Sony AFStatus19 Tags @@ -17169,11 +20675,41 @@ AF Status information for models with 79-point AF. E-mount models. - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 0x1a06 TiffMeteringImageWidth no - 0x1a07 TiffMeteringImageHeight no - 0x1a08 TiffMeteringImage no + 6662 TiffMeteringImageWidth no + 6663 TiffMeteringImageHeight no + 6664 TiffMeteringImage no + +=head3 Sony Tag9416 Tags + +Valid for the ILCE-1/7M4/7SM3, ILME-FX3. + + Index1 Tag Name Writable + ------ -------- -------- + 0 Tag9416_0000 no + 4 SonyISO no + 6 StopsAboveBaseISO no + 10 SonyExposureTime2 no + 12 ExposureTime no + 16 SonyFNumber2 no + 18 SonyMaxApertureValue no + 29 SequenceImageNumber no + 53 ExposureProgram no + 72 LensMount no + 73 LensFormat no + 74 LensMount no + 75 LensType2 no + 77 LensType no + 79 DistortionCorrParams no + 112 PictureProfile no + 113 FocalLength no + 115 MinFocalLength no + 117 MaxFocalLength no + 2191 VignettingCorrParams no + 2193 VignettingCorrParams no + 2324 ChromaticAberrationCorrParams no + 2326 ChromaticAberrationCorrParams no =head3 Sony PIC Tags @@ -17272,39 +20808,39 @@ Tags in the encrypted SR2SubIFD Tag ID Tag Name Writable ------ -------- -------- - 0x7300 BlackLevel no - 0x7302 WB_GRBGLevelsAuto no - 0x7303 WB_GRBGLevels no - 0x7310 BlackLevel no - 0x7312 WB_RGGBLevelsAuto no - 0x7313 WB_RGGBLevels no - 0x7480 WB_RGBLevelsDaylight no - 0x7481 WB_RGBLevelsCloudy no - 0x7482 WB_RGBLevelsTungsten no - 0x7483 WB_RGBLevelsFlash no - 0x7484 WB_RGBLevels4500K no - 0x7486 WB_RGBLevelsFluorescent no + 0x7300 BlackLevel int16u[4]! + 0x7302 WB_GRBGLevelsAuto int16s[4]! + 0x7303 WB_GRBGLevels int16s[4]! + 0x7310 BlackLevel int16u[4]! + 0x7312 WB_RGGBLevelsAuto int16s[4]! + 0x7313 WB_RGGBLevels int16s[4]! + 0x7480 WB_RGBLevelsDaylight int16s[4]! + 0x7481 WB_RGBLevelsCloudy int16s[4]! + 0x7482 WB_RGBLevelsTungsten int16s[4]! + 0x7483 WB_RGBLevelsFlash int16s[4]! + 0x7484 WB_RGBLevels4500K int16s[4]! + 0x7486 WB_RGBLevelsFluorescent int16s[4]! 0x74a0 MaxApertureAtMaxFocal no 0x74a1 MaxApertureAtMinFocal no 0x74a2 MaxFocalLength no 0x74a3 MinFocalLength no 0x74c0 SR2DataIFD Sony SR2DataIFD 0x7800 ColorMatrix no - 0x7820 WB_RGBLevelsDaylight no - 0x7821 WB_RGBLevelsCloudy no - 0x7822 WB_RGBLevelsTungsten no - 0x7823 WB_RGBLevelsFlash no - 0x7824 WB_RGBLevels4500K no - 0x7825 WB_RGBLevelsShade no - 0x7826 WB_RGBLevelsFluorescent no - 0x7827 WB_RGBLevelsFluorescentP1 no - 0x7828 WB_RGBLevelsFluorescentP2 no - 0x7829 WB_RGBLevelsFluorescentM1 no - 0x782a WB_RGBLevels8500K no - 0x782b WB_RGBLevels6000K no - 0x782c WB_RGBLevels3200K no - 0x782d WB_RGBLevels2500K no - 0x787f WhiteLevel no + 0x7820 WB_RGBLevelsDaylight int16s[3]! + 0x7821 WB_RGBLevelsCloudy int16s[3]! + 0x7822 WB_RGBLevelsTungsten int16s[3]! + 0x7823 WB_RGBLevelsFlash int16s[3]! + 0x7824 WB_RGBLevels4500K int16s[3]! + 0x7825 WB_RGBLevelsShade int16s[3]! + 0x7826 WB_RGBLevelsFluorescent int16s[3]! + 0x7827 WB_RGBLevelsFluorescentP1 int16s[3]! + 0x7828 WB_RGBLevelsFluorescentP2 int16s[3]! + 0x7829 WB_RGBLevelsFluorescentM1 int16s[3]! + 0x782a WB_RGBLevels8500K int16s[3]! + 0x782b WB_RGBLevels6000K int16s[3]! + 0x782c WB_RGBLevels3200K int16s[3]! + 0x782d WB_RGBLevels2500K int16s[3]! + 0x787f WhiteLevel int16u[3]! 0x797d VignettingCorrParams no 0x7980 ChromaticAberrationCorrParams no 0x7982 DistortionCorrParams no @@ -17344,7 +20880,25 @@ some models when the ExtractEmbedded option is used. Tag ID Tag Name Writable ------ -------- -------- + 0x8000 FNumber no + 0x8109 ExposureTime no + 0x810a MasterGainAdjustment no + 0x810b ISO no + 0x810c ElectricalExtenderMagnification no + 0x8500 GPSVersionID no + 0x8501 GPSLatitudeRef no + 0x8502 GPSLatitude no + 0x8503 GPSLongitudeRef no + 0x8504 GPSLongitude no + 0x8507 GPSTimeStamp no + 0x8509 GPSStatus no + 0x850a GPSMeasureMode no + 0x8512 GPSMapDatum no + 0x851d GPSDateStamp no + 0xe303 WhiteBalance no 0xe304 DateTime no + 0xe43b PitchRollYaw no + 0xe44b Accelerometer no =head2 SonyIDC Tags @@ -17449,6 +21003,7 @@ still proprietary) Adobe format. MakerNoteCanon Canon MakerNoteCasio Casio MakerNoteCasio2 Casio Type2 + MakerNoteDJIInfo DJI Info MakerNoteDJI DJI MakerNoteFLIR FLIR MakerNoteFujiFilm FujiFilm @@ -17489,6 +21044,7 @@ still proprietary) Adobe format. MakerNoteNintendo Nintendo MakerNoteOlympus Olympus MakerNoteOlympus2 Olympus + MakerNoteOlympus3 Olympus MakerNoteLeica Panasonic MakerNoteLeica2 Panasonic Leica2 MakerNoteLeica3 Panasonic Leica3 @@ -17498,6 +21054,7 @@ still proprietary) Adobe format. MakerNoteLeica7 Panasonic Leica6 MakerNoteLeica8 Panasonic Leica5 MakerNoteLeica9 Panasonic Leica9 + MakerNoteLeica10 Panasonic MakerNotePanasonic Panasonic MakerNotePanasonic2 Panasonic Type2 MakerNotePanasonic3 Panasonic @@ -17510,6 +21067,8 @@ still proprietary) Adobe format. MakerNotePhaseOne PhaseOne MakerNoteReconyx Reconyx MakerNoteReconyx2 Reconyx Type2 + MakerNoteReconyx3 Reconyx Type3 + MakerNoteRicohPentax Pentax MakerNoteRicoh Ricoh MakerNoteRicoh2 Ricoh Type2 MakerNoteRicohText Ricoh Text @@ -17556,7 +21115,9 @@ These tags apply to CRW-format Canon RAW files and information in the APP0 "CIFF" segment of JPEG images. When writing CanonRaw/CIFF information, the length of the information is preserved (and the new information is truncated or padded as required) unless B<Writable> is C<resize>. Currently, only -JpgFromRaw and ThumbnailImage are allowed to change size. +JpgFromRaw and ThumbnailImage are allowed to change size. See +L<https://exiftool.org/canon_raw.html> for a description of the Canon CRW +format. CRW images also support the addition of a CanonVRD trailer, which in turn supports XMP. This trailer is created automatically if necessary when @@ -17615,8 +21176,8 @@ ExifTool is used to write XMP to a CRW image. 0x1835 DecoderTable CanonRaw DecoderTable 0x183b SerialNumberFormat int32u 0x2005 RawData no - 0x2007 JpgFromRaw resize - 0x2008 ThumbnailImage resize + 0x2007 JpgFromRaw resize^ + 0x2008 ThumbnailImage resize^ 0x2804 ImageDescription CanonRaw 0x2807 CameraObject CanonRaw 0x3002 ShootingRecord CanonRaw @@ -17760,7 +21321,7 @@ These tags are used in Minolta RAW format (MRW) images. 16 WB_RBLevelsCloudy int16u[2] 20 WB_RBLevelsCoolWhiteF int16u[2] 24 WB_RBLevelsFlash int16u[2] - 28 WB_RBLevelsUnknown? int16u[2] + 28 WB_RBLevelsCustom int16u[2] 32 WB_RBLevelsShade int16u[2] 36 WB_RBLevelsDaylightF int16u[2] 40 WB_RBLevelsDayWhiteF int16u[2] @@ -17901,23 +21462,29 @@ Lens distortion correction information. Tag ID Tag Name Writable ------ -------- -------- - 0x1001 MultishotOn int32u - 0x1100 FocusStepNear int16s - 0x1101 FocusStepCount int16s - 0x1102 FlashFired int32u - 0x1105 ZoomPosition int32u - 0x1200 LensAttached int32u - 0x1203 FocalLengthIn35mmFormat int16u - 0x1305 HighISOMode int16u - 0x3200 WB_CFA0_LevelDaylight int16u - 0x3201 WB_CFA1_LevelDaylight int16u - 0x3202 WB_CFA2_LevelDaylight int16u - 0x3203 WB_CFA3_LevelDaylight int16u - 0x3300 WhiteBalanceSet int8u - 0x3420 WB_RedLevelAuto int16u - 0x3421 WB_BlueLevelAuto int16u - 0x3501 Orientation int8u - 0x3600 WhiteBalanceDetected int8u + 0x1001 MultishotOn no + 0x1100 FocusStepNear no + 0x1101 FocusStepCount no + 0x1102 FlashFired no + 0x1105 ZoomPosition no + 0x1200 LensAttached no + 0x1201 LensTypeMake no + 0x1202 LensTypeModel no + 0x1203 FocalLengthIn35mmFormat no + 0x1301 ApertureValue no + 0x1302 ShutterSpeedValue no + 0x1303 SensitivityValue no + 0x1305 HighISOMode no + 0x1412 FacesDetected no + 0x3200 WB_CFA0_LevelDaylight no + 0x3201 WB_CFA1_LevelDaylight no + 0x3202 WB_CFA2_LevelDaylight no + 0x3203 WB_CFA3_LevelDaylight no + 0x3300 WhiteBalanceSet no + 0x3420 WB_RedLevelAuto no + 0x3421 WB_BlueLevelAuto no + 0x3501 Orientation no + 0x3600 WhiteBalanceDetected no =head2 SigmaRaw Tags @@ -18103,32 +21670,35 @@ FPXR segment of JPEG images. As well, FlashPix information is extracted from DOC, PPT, XLS (Microsoft Word, PowerPoint and Excel) documents, VSD (Microsoft Visio) drawings, and FLA (Macromedia/Adobe Flash project) files since these are based on the same file format as FlashPix (the Windows -Compound Binary File format). See +Compound Binary File format). Note that ExifTool identifies any +unrecognized Windows Compound Binary file as a FlashPix (FPX) file. See L<http://graphcomp.com/info/specs/livepicture/fpx.pdf> for the FlashPix specification. - Tag ID Tag Name Writable - ------ -------- -------- - "\x01CompObj" CompObj FlashPix CompObj - "\x05Audio Info" AudioInfo FlashPix AudioInfo - "\x05Data Object" DataObject FlashPix DataObject + Tag ID Tag Name Writable + ------ -------- -------- + "\x01CompObj" CompObj FlashPix CompObj + "\x05Audio Info" AudioInfo FlashPix AudioInfo + "\x05Data Object" DataObject FlashPix DataObject "\x05DocumentSummaryInformation" DocumentInfo FlashPix DocumentInfo - "\x05Extension List" Extensions FlashPix Extensions - "\x05Global Info" GlobalInfo FlashPix GlobalInfo - "\x05Image Contents" Image FlashPix Image - "\x05Image Info" ImageInfo FlashPix ImageInfo - "\x05Operation" Operation FlashPix Operation - "\x05Screen Nail" ScreenNail no - "\x05SummaryInformation" SummaryInfo FlashPix SummaryInfo - "\x05Transform" Transform FlashPix Transform - 'Audio Stream' AudioStream no - 'Contents' Contents XMP - 'Current User' CurrentUser no - 'ICC Profile 0001' ICC_Profile ICC_Profile - 'Preview' PreviewImage no - 'Property' PreviewInfo FlashPix PreviewInfo - 'Subimage 0000 Header' SubimageHdr FlashPix SubimageHdr - 'WordDocument' WordDocument FlashPix WordDocument + "\x05Extension List" Extensions FlashPix Extensions + "\x05Global Info" GlobalInfo FlashPix GlobalInfo + "\x05Image Contents" Image FlashPix Image + "\x05Image Info" ImageInfo FlashPix ImageInfo + "\x05Operation" Operation FlashPix Operation + "\x05Screen Nail" ScreenNail no + "\x05SummaryInformation" SummaryInfo FlashPix SummaryInfo + "\x05Transform" Transform FlashPix Transform + 'Audio Stream' AudioStream no + 'BasicFileInfo' BasicFileInfo no + 'Contents' Contents XMP + 'Current User' CurrentUser no + 'ICC Profile 0001' ICC_Profile ICC_Profile + 'IeImg' EmbeddedImage no + 'Preview' PreviewImage no + 'Property' PreviewInfo FlashPix PreviewInfo + 'Subimage 0000 Header' SubimageHdr FlashPix SubimageHdr + 'WordDocument' WordDocument FlashPix WordDocument =head3 FlashPix CompObj Tags @@ -18445,8 +22015,8 @@ found in the APP2 "MPF" segment of JPEG images. MPImage data referenced from this segment is stored as a JPEG trailer. The MPF tags are not writable, however the MPF segment may be deleted as a group (with "MPF:All") but then the JPEG trailer should also be deleted (with "Trailer:All"). See -L<http://www.cipa.jp/std/documents/e/DC-007_E.pdf> for the official -specification. +L<https://web.archive.org/web/20190713230858/http://www.cipa.jp/std/documents/e/DC-007_E.pdf> +for the official specification. Tag ID Tag Name Writable ------ -------- -------- @@ -18491,8 +22061,8 @@ embedded images. These tags are part of the CIPA Stereo Still Image specification, and are found in the APP3 "Stim" segment of JPEG images. See -L<http://www.cipa.jp/std/documents/e/DC-006_E.pdf> for the -official specification. +L<https://web.archive.org/web/20190718152459/http://www.cipa.jp/std/documents/e/DC-006_E.pdf> +for the official specification. Tag ID Tag Name Writable ------ -------- -------- @@ -18554,12 +22124,12 @@ L<http://www.scalado.com/>.) =head3 GoPro GPMF Tags -Tags extracted from the GPMF box of GoPro MP4 videos, the APP6 "GoPro" segment -of JPEG files, and from the "gpmd" timed metadata if the ExtractEmbedded option -is enabled. Many more tags exist, but are currently unknown and extracted only -with the -u option. Please let me know if you discover the meaning of any of -these unknown tags. See L<https://github.com/gopro/gpmf-parser> for details -about this format. +Tags extracted from the GPMF box of GoPro MP4 videos, the APP6 "GoPro" +segment of JPEG files, and from the "gpmd" timed metadata if the +ExtractEmbedded (-ee) option is enabled. Many more tags exist, but are +currently unknown and extracted only with the Unknown (-u) option. Please +let me know if you discover the meaning of any of these unknown tags. See +L<https://github.com/gopro/gpmf-parser> for details about this format. Tag ID Tag Name Writable ------ -------- -------- @@ -18576,8 +22146,10 @@ about this format. 'DVID' DeviceID? no 'DVNM' DeviceName no 'DZOM' DigitalZoom no + 'EISA' ElectronicImageStabilization no 'EMPT' Empty? no 'ESCS' EscapeStatus? no + 'EXPT' MaximumShutterAngle no 'FACE' FaceDetected no 'FCNM' FaceNumbers no 'FMWR' FirmwareVersion no @@ -18595,7 +22167,11 @@ about this format. 'LNED' LocalPositionNED no 'MAGN' Magnetometer no 'MINF' Model no + 'MTRX' AccelerometerMatrix no + 'MUID' MediaUniqueID no 'OREN' AutoRotation no + 'ORIN' InputOrientation no + 'ORIO' OutputOrientation no 'PHDR' HDRSetting no 'PIMN' AutoISOMin no 'PIMX' AutoISOMax no @@ -18612,6 +22188,7 @@ about this format. 'SHUT' ExposureTimes no 'SIMU' ScaledIMU no 'SIUN' SIUnits? no + 'SROT' SensorReadoutTime no 'STMP' TimeStamp no 'STNM' StreamName? no 'STRM' NestedSignalStream GoPro GPMF @@ -18619,7 +22196,9 @@ about this format. 'TMPC' CameraTemperature no 'TSMP' TotalSamples? no 'TYPE' StructureType? no + 'UNIF' InputUniformity no 'UNIT' Units? no + 'VERS' MetadataVersion no 'VFOV' FieldOfView no 'VFRH' VisualFlightRulesHUD no 'WBAL' ColorTemperatures no @@ -18678,7 +22257,7 @@ Battery status information found in GoPro Karma videos. =head3 GoPro fdsc Tags Tags extracted from the MP4 "fdsc" timed metadata when the ExtractEmbedded -option is used. +(-ee) option is used. Index1 Tag Name Writable ------ -------- -------- @@ -19885,20 +23464,223 @@ even if it is not listed in this table. YhiYloCorK1 no YhiYloCorK2 no -=head2 APP12 Tags - -=head3 APP12 PictureInfo Tags +=head2 Jpeg2000 Tags -The JPEG APP12 "Picture Info" segment was used by some older cameras, and -contains ASCII-based meta information. Below are some tags which have been -observed Agfa and Polaroid images, however ExifTool will extract information -from any tags found in this segment. +The tags below are found in JPEG 2000 images and the JUMBF metadata in JPEG +images, but not all of these are extracted. Note that ExifTool currently +writes only EXIF, IPTC and XMP tags in Jpeg2000 images. - Tag ID Tag Name Writable - ------ -------- -------- - 'Aperture' Aperture no - 'ColorMode' ColorMode no - 'ConTake' ConTake no + Tag ID Tag Name Writable + ------ -------- -------- + 'Exif' EXIF EXIF + 'asoc' Association Jpeg2000 + 'bfdb' BinaryDataType no + 'bfil' BinaryFilter no + 'bidb' BinaryData no + 'bpcc' BitsPerComponent no + 'cbor' CBORData CBOR + 'cdef' ComponentDefinition no + 'cgrp' ColorGroup no + 'chck' DigitalSignature no + 'cmap' ComponentMapping no + 'colr' ColorSpecification Jpeg2000 ColorSpec + 'comp' Composition no + 'copt' CompositionOptions no + 'cref' Cross-Reference no + 'creg' CodestreamRegistration no + 'drep' DesiredReproductions no + 'dtbl' DataReference no + 'flst' FragmentList no + 'free' Free no + 'ftbl' FragmentTable no + 'ftyp' FileType Jpeg2000 FileType + 'gtso' GraphicsTechnologyStandardOutput no + 'ihdr' ImageHeader Jpeg2000 ImageHeader + 'inst' InstructionSet no + 'jP ' JP2Signature no + 'jp2c' ContiguousCodestream no + PreviewImage no + 'jp2h' JP2Header Jpeg2000 + 'jp2i' IntellectualProperty XMP + 'jpch' CodestreamHeader Jpeg2000 + 'jplh' CompositingLayerHeader Jpeg2000 + 'json' JSONData JSON + 'jumb' JUMBFBox Jpeg2000 + 'jumd' JUMBFDescr Jpeg2000 JUMD + 'jxlc' JXLCodestream no + 'lbl ' Label no + 'mdat' MediaData no + 'mp7b' MPEG7Binary no + 'nlst' NumberList no + 'opct' Opacity no + 'pclr' Palette no + 'prfl' Profile no + 'res ' Resolution Jpeg2000 + 'resc' CaptureResolution Jpeg2000 CaptureResolution + 'resd' DisplayResolution Jpeg2000 DisplayResolution + 'roid' ROIDescription no + 'rreq' ReaderRequirements no + 'uinf' UUIDInfo Jpeg2000 + 'ulst' UUIDList no + 'url ' URL no + 'uuid' UUID-EXIF EXIF + UUID-EXIF2 EXIF + UUID-EXIF_bad EXIF + UUID-IPTC IPTC + UUID-IPTC2 IPTC + UUID-XMP XMP + UUID-GeoJP2 EXIF + UUID-Photoshop Photoshop + UUID-Signature no + UUID-C2PAClaimSignature - + UUID-Unknown no + 'xml ' XML XMP XML + XMP - + XMP + +=head3 Jpeg2000 ColorSpec Tags + +The table below contains tags in the color specification (colr) box. This +box may be rewritten by writing either ICC_Profile, ColorSpace or +ColorSpecData. When writing, any existing colr boxes are replaced with the +newly created colr box. + +B<NOTE>: Care must be taken when writing this color specification because +writing a specification that is incompatible with the image data may make +the image undisplayable. + + Index1 Tag Name Writable + ------ -------- -------- + 0 ColorSpecMethod int8s! + 1 ColorSpecPrecedence int8s! + 2 ColorSpecApproximation int8s! + 3 ICC_Profile ICC_Profile + ColorSpace int32u! + ColorSpecData undef! + +=head3 Jpeg2000 FileType Tags + + Index4 Tag Name Writable + ------ -------- -------- + 0 MajorBrand no + 1 MinorVersion no + 2 CompatibleBrands no + +=head3 Jpeg2000 ImageHeader Tags + + Index1 Tag Name Writable + ------ -------- -------- + 0 ImageHeight no + 4 ImageWidth no + 8 NumberOfComponents no + 10 BitsPerComponent no + 11 Compression no + +=head3 Jpeg2000 JUMD Tags + +Information extracted from the JUMBF description box. + + Tag ID Tag Name Writable + ------ -------- -------- + 'id' JUMDID no + 'label' JUMDLabel no + 'sig' JUMDSignature no + 'toggles' JUMDToggles? no + 'type' JUMDType no + +=head3 Jpeg2000 CaptureResolution Tags + + Index1 Tag Name Writable + ------ -------- -------- + 0 CaptureYResolution no + 4 CaptureXResolution no + 8 CaptureYResolutionUnit no + 9 CaptureXResolutionUnit no + +=head3 Jpeg2000 DisplayResolution Tags + + Index1 Tag Name Writable + ------ -------- -------- + 0 DisplayYResolution no + 4 DisplayXResolution no + 8 DisplayYResolutionUnit no + 9 DisplayXResolutionUnit no + +=head2 JSON Tags + +Other than a few tags in the table below, JSON tags have not been +pre-defined. However, ExifTool will read any existing tags from basic +JSON-formatted files. + + Tag Name Writable + -------- -------- + ON1_SettingsData PLIST + ON1_SettingsMetadataCreated no + ON1_SettingsMetadataModified no + ON1_SettingsMetadataName no + ON1_SettingsMetadataPluginID no + ON1_SettingsMetadataTimestamp no + ON1_SettingsMetadataUsage no + ON1_SettingsMetadataVisibleToUser no + +=head2 CBOR Tags + +The tags below are extracted from CBOR (Concise Binary Object +Representation) metadata. The C2PA specification uses this format for some +metadata. As well as these tags, ExifTool will read any existing tags. + + Tag Name Writable + -------- -------- + AuthorIdentifier no + AuthorName no + DocumentID no + Format no + InstanceID no + Relationship no + ThumbnailHash no+ + ThumbnailURL no + Title no + +=head2 PLIST Tags + +Apple Property List tags. ExifTool reads both XML and binary-format PLIST +files, and will extract any existing tags even if they aren't listed below. +These tags belong to the family 0 "PLIST" group, but family 1 group may be +either "XML" or "PLIST" depending on whether the format is XML or binary. + + Tag ID Tag Name Writable + ------ -------- -------- + 'MetaDataList//DateTimeOriginal' + DateTimeOriginal no + 'MetaDataList//Duration' Duration no + 'MetaDataList//Geolocation/Latitude' + GPSLatitude no + 'MetaDataList//Geolocation/Longitude' + GPSLongitude no + 'MetaDataList//Geolocation/MapDatum' + GPSMapDatum no + 'XMLFileType' XMLFileType no + 'cast//name' Cast no+ + 'codirectors//name' Codirectors no+ + 'directors//name' Directors no+ + 'producers//name' Producers no+ + 'screenwriters//name' Screenwriters no+ + 'studio//name' Studio no+ + +=head2 APP12 Tags + +=head3 APP12 PictureInfo Tags + +The JPEG APP12 "Picture Info" segment was used by some older cameras, and +contains ASCII-based meta information. Below are some tags which have been +observed Agfa and Polaroid images, however ExifTool will extract information +from any tags found in this segment. + + Tag ID Tag Name Writable + ------ -------- -------- + 'Aperture' Aperture no + 'ColorMode' ColorMode no + 'ConTake' ConTake no 'ExpBias' ExposureCompensation no 'FNumber' FNumber no 'FWare' FirmwareVersion no @@ -20009,15 +23791,16 @@ These tags belong to the ExifTool XMP-dwc family 1 group. DCVerbatimLocality string_ DCVerbatimLongitude string_ DCVerbatimSRS string_ + DCVerticalDatum string_ DCWaterBody string_ DCEvent DarwinCore Event Struct EventDay integer_ EventEarliestDate date_ EventEndDayOfYear integer_ EventDate date_ - EventID string_ + EventID string/_ EventRemarks lang-alt_ - EventTime date_ + EventTime string_ EventFieldNotes string_ EventFieldNumber string_ EventHabitat string_ @@ -20057,9 +23840,9 @@ These tags belong to the ExifTool XMP-dwc family 1 group. HumanObservationEarliestDate date_ HumanObservationEndDayOfYear integer_ HumanObservationEventDate date_ - HumanObservationEventID string_ + HumanObservationEventID string/_ HumanObservationEventRemarks lang-alt_ - HumanObservationEventTime date_ + HumanObservationEventTime string_ HumanObservationFieldNotes string_ HumanObservationFieldNumber string_ HumanObservationHabitat string_ @@ -20081,7 +23864,9 @@ These tags belong to the ExifTool XMP-dwc family 1 group. IdentificationRemarks string_ IdentificationVerificationStatus string_ IdentifiedBy string_ + IdentifiedByID string_ TypeStatus string_ + VerbatimIdentification string_ LivingSpecimen DarwinCore MaterialSample Struct LivingSpecimenMaterialSampleID string_ MachineObservation DarwinCore Event Struct @@ -20089,9 +23874,9 @@ These tags belong to the ExifTool XMP-dwc family 1 group. MachineObservationEarliestDate date_ MachineObservationEndDayOfYear integer_ MachineObservationEventDate date_ - MachineObservationEventID string_ + MachineObservationEventID string/_ MachineObservationEventRemarks lang-alt_ - MachineObservationEventTime date_ + MachineObservationEventTime string_ MachineObservationFieldNotes string_ MachineObservationFieldNumber string_ MachineObservationHabitat string_ @@ -20125,8 +23910,10 @@ These tags belong to the ExifTool XMP-dwc family 1 group. OccurrenceAssociatedTaxa string_ OccurrenceBehavior string_ OccurrenceCatalogNumber string_ + OccurrenceDegreeOfEstablishment string_ OccurrenceDisposition string_ OccurrenceEstablishmentMeans string_ + OccurrenceGeoreferenceVerificationStatus string_ OccurrenceIndividualCount string_ OccurrenceIndividualID string_ OccurrenceLifeStage string_ @@ -20137,9 +23924,11 @@ These tags belong to the ExifTool XMP-dwc family 1 group. OccurrenceOrganismQuantity string_ OccurrenceOrganismQuantityType string_ OccurrenceOtherCatalogNumbers string_ + OccurrencePathway string_ OccurrencePreparations string_ OccurrencePreviousIdentifications string_ OccurrenceRecordedBy string_ + OccurrenceRecordedByID string_ OccurrenceRecordNumber string_ OccurrenceReproductiveCondition string_ OccurrenceSex string_ @@ -20170,6 +23959,7 @@ These tags belong to the ExifTool XMP-dwc family 1 group. RelationshipAccordingTo string_ RelationshipEstablishedDate date_ RelationshipOfResource string_ + RelationshipOfResourceID string_ RelationshipRemarks string_ ResourceID string_ ResourceRelationshipID string_ @@ -20177,6 +23967,7 @@ These tags belong to the ExifTool XMP-dwc family 1 group. TaxonAcceptedNameUsage string_ TaxonAcceptedNameUsageID string_ TaxonClass string_ + TaxonCultivarEpithet string_ TaxonFamily string_ TaxonGenus string_ TaxonHigherClassification string_ @@ -20255,6 +24046,7 @@ These tags belong to the ExifTool XMP-dwc family 1 group. VerbatimLocality string VerbatimLongitude string VerbatimSRS string + VerticalDatum string WaterBody string =head3 DarwinCore Event Struct @@ -20267,7 +24059,7 @@ These tags belong to the ExifTool XMP-dwc family 1 group. EventDate date EventID string EventRemarks lang-alt - EventTime date + EventTime string FieldNotes string FieldNumber string Habitat string @@ -20322,7 +24114,9 @@ These tags belong to the ExifTool XMP-dwc family 1 group. IdentificationRemarks string IdentificationVerificationStatus string IdentifiedBy string + IdentifiedByID string TypeStatus string + VerbatimIdentification string =head3 DarwinCore MeasurementOrFact Struct @@ -20349,8 +24143,10 @@ These tags belong to the ExifTool XMP-dwc family 1 group. AssociatedTaxa string Behavior string CatalogNumber string + DegreeOfEstablishment string Disposition string EstablishmentMeans string + GeoreferenceVerificationStatus string IndividualCount string IndividualID string LifeStage string @@ -20361,10 +24157,12 @@ These tags belong to the ExifTool XMP-dwc family 1 group. OrganismQuantity string OrganismQuantityType string OtherCatalogNumbers string + Pathway string Preparations string PreviousIdentifications string RecordNumber string RecordedBy string + RecordedByID string ReproductiveCondition string Sex string @@ -20404,6 +24202,7 @@ These tags belong to the ExifTool XMP-dwc family 1 group. RelationshipAccordingTo string RelationshipEstablishedDate date RelationshipOfResource string + RelationshipOfResourceID string RelationshipRemarks string ResourceID string ResourceRelationshipID string @@ -20415,6 +24214,7 @@ These tags belong to the ExifTool XMP-dwc family 1 group. AcceptedNameUsage string AcceptedNameUsageID string Class string + CultivarEpithet string Family string Genus string HigherClassification string @@ -20629,8 +24429,13 @@ Windows Live Photo Gallery. =head3 Microsoft Xtra Tags -Tags extracted from the Microsoft "Xtra" atom of QuickTime videos. Tag ID's -are not shown because some are unruly GUID's. +Tags found in the Microsoft "Xtra" atom of QuickTime videos. Tag ID's are +not shown because some are unruly GUID's. Currently most of these tags are +not writable because the Microsoft documentation is poor and samples were +not available, but more tags may be made writable in the future if samples +are provided. Note that writable tags in this table are are flagged to +"Avoid", which means that other more common tags will be written instead if +possible unless the Microsoft group is specified explicitly. Tag Name Writable -------- -------- @@ -20642,13 +24447,13 @@ are not shown because some are unruly GUID's. AcquisitionTimeYear no AcquisitionTimeYearMonth no AcquisitionTimeYearMonthDay no - AlbumArtist no + AlbumArtist Unicode/ AlbumArtist no AlbumArtistSortOrder no - AlbumCoverURL no + AlbumCoverURL Unicode/ AlbumID no AlbumIDAlbumArtist no - AlbumTitle no + AlbumTitle Unicode/ AlbumTitle no AlbumTitleSortOrder no AlternateSourceURL no @@ -20665,6 +24470,7 @@ are not shown because some are unruly GUID's. Author no Author no AuthorSortOrder no + AuthorURL Unicode/ AutoSummary no AverageLevel no BccAddresses no @@ -20697,7 +24503,7 @@ are not shown because some are unruly GUID's. CameraModel no CameraModel no CarPhone no - Category no + Category Unicode/+ Category no CcAddresses no CcNames no @@ -20716,13 +24522,13 @@ are not shown because some are unruly GUID's. Company no CompanyMainPhone no Complete no - Composer no + Composer Unicode/ Composers no Computer no - Conductor no + Conductor Unicode/+ Conductors no ContactNames no - ContentDistributor no + ContentDistributor Unicode/ ContentDistributorDuration no ContentDistributorType no ContentGroupDescription no @@ -20745,7 +24551,7 @@ are not shown because some are unruly GUID's. DataRate no Date no DateAccessed no - DateAcquired no + DateAcquired vt_filetime/ DateArchived no DateCompleted no DateCreated no @@ -20762,7 +24568,7 @@ are not shown because some are unruly GUID's. Description no Description no Dimensions no - Director no + Director Unicode/+ Directors no DisplayArtist no Division no @@ -20776,8 +24582,9 @@ are not shown because some are unruly GUID's. E-mailAddress no E-mailDisplayName no E-mailList no + EncodedBy Unicode/ EncodedBy no - EncodingTime no + EncodingTime date/ EndDate no EntryType no EpisodeName no @@ -20835,7 +24642,7 @@ are not shown because some are unruly GUID's. ISOSpeed no Importance no Incomplete no - InitialKey no + InitialKey Unicode/ InitialKey no Initials no IsAttachment no @@ -20869,8 +24676,8 @@ are not shown because some are unruly GUID's. MCDI no MailingAddress no MaxAperture no - MediaClassPrimaryID no - MediaClassSecondaryID no + MediaClassPrimaryID GUID/ + MediaClassSecondaryID GUID/ MediaContentTypes no MediaCreated no MediaOriginalBroadcastDateTime no @@ -20881,7 +24688,7 @@ are not shown because some are unruly GUID's. MiddleName no Mileage no ModifiedBy no - Mood no + Mood Unicode/ Mood no MoreInfo no Name no @@ -20894,9 +24701,9 @@ are not shown because some are unruly GUID's. OrganizerAddress no OrganizerName no Orientation no - OriginalAlbumTitle no - OriginalArtist no - OriginalLyricist no + OriginalAlbumTitle Unicode/ + OriginalArtist Unicode/ + OriginalLyricist Unicode/ OtherAddress no OtherCity no OtherCountry-Region no @@ -20908,7 +24715,7 @@ are not shown because some are unruly GUID's. POBox no Pager no Pages no - ParentalRating no + ParentalRating Unicode/ ParentalRating no ParentalRatingReason no PartOfSet no @@ -20918,7 +24725,7 @@ are not shown because some are unruly GUID's. Path no PeakValue no PerceivedType no - Period no + Period Unicode/ Period no PersonalTitle no PixelAspectRatioX no @@ -20928,7 +24735,7 @@ are not shown because some are unruly GUID's. PrimaryE-mail no PrimaryPhone no Priority no - Producer no + Producer Unicode/+ Producers no ProductName no ProductVersion no @@ -20937,15 +24744,16 @@ are not shown because some are unruly GUID's. ProgramMode no ProgramName no Project no + PromotionURL Unicode/ Protected no ProtectionType no Provider no - Provider no + Provider Unicode/ ProviderLogoURL no ProviderRating no ProviderStyle no ProviderURL no - Publisher no + Publisher Unicode/ Publisher no RadioBand no RadioFormat no @@ -20979,7 +24787,7 @@ are not shown because some are unruly GUID's. Sensitivity no ShadowFilePath no Shared no - SharedUserRating no + SharedUserRating int64u/ SharedWith no Size no Slides no @@ -21000,7 +24808,7 @@ are not shown because some are unruly GUID's. Subject no SubjectDistance no SubscriptionContentID no - Subtitle no + Subtitle Unicode/ Subtitle no SubtitleDescription no Suffix no @@ -21079,7 +24887,7 @@ are not shown because some are unruly GUID's. WhiteBalance no WindowsFileName no WordCount no - Writer no + Writer Unicode/ Writers no Year no Year no @@ -21158,8 +24966,8 @@ written. 4) ExifTool writes compressed metadata to MIE files if the Compress (-z) option is used and Compress::Zlib is available. -See L<http://owl.phy.queensu.ca/~phil/exiftool/MIE1.1-20070121.pdf> for the -official MIE specification. +See L<https://exiftool.org/MIE1.1-20070121.pdf> for the official MIE +specification. Tag ID Tag Name Writable ------ -------- -------- @@ -21433,132 +25241,26 @@ to avoid name conflicts. 'Duration' Duration rational64u~ 'data' RelatedVideoFile undef -=head2 Jpeg2000 Tags +=head2 GIF Tags -The tags below are extracted from JPEG 2000 images, however ExifTool -currently writes only EXIF, IPTC and XMP tags in these images. +This table lists information extracted from GIF images. See +L<http://www.w3.org/Graphics/GIF/spec-gif89a.txt> for the official GIF89a +specification. - Tag ID Tag Name Writable - ------ -------- -------- - 'asoc' Association no - 'bfil' BinaryFilter no - 'bpcc' BitsPerComponent no - 'cdef' ComponentDefinition no - 'cgrp' ColorGroup no - 'chck' DigitalSignature no - 'cmap' ComponentMapping no - 'colr' ColorSpecification Jpeg2000 ColorSpec - 'comp' Composition no - 'copt' CompositionOptions no - 'cref' Cross-Reference no - 'creg' CodestreamRegistration no - 'drep' DesiredReproductions no - 'dtbl' DataReference no - 'flst' FragmentList no - 'free' Free no - 'ftbl' FragmentTable no - 'ftyp' FileType Jpeg2000 FileType - 'gtso' GraphicsTechnologyStandardOutput no - 'ihdr' ImageHeader Jpeg2000 ImageHeader - 'inst' InstructionSet no - 'jP ' JP2Signature no - 'jp2c' ContiguousCodestream no - 'jp2h' JP2Header Jpeg2000 - 'jp2i' IntellectualProperty XMP - 'jpch' CodestreamHeader Jpeg2000 - 'jplh' CompositingLayerHeader Jpeg2000 - 'lbl ' Label no - 'mdat' MediaData no - 'mp7b' MPEG7Binary no - 'nlst' NumberList no - 'opct' Opacity no - 'pclr' Palette no - 'prfl' Profile no - 'res ' Resolution Jpeg2000 - 'resc' CaptureResolution Jpeg2000 CaptureResolution - 'resd' DisplayResolution Jpeg2000 DisplayResolution - 'roid' ROIDescription no - 'rreq' ReaderRequirements no - 'uinf' UUIDInfo Jpeg2000 - 'ulst' UUIDList no - 'url ' URL no - 'uuid' UUID-EXIF EXIF - UUID-EXIF2 EXIF - UUID-EXIF_bad EXIF - UUID-IPTC IPTC - UUID-IPTC2 IPTC - UUID-XMP XMP - UUID-GeoJP2 EXIF - UUID-Photoshop Photoshop - UUID-Unknown no - 'xml ' XML XMP + Tag Name Writable + -------- -------- + Comment yes + Duration no + Extensions GIF Extensions + FrameCount no + GIFVersion no + ScreenDescriptor GIF Screen + Text no + TransparentColor no -=head3 Jpeg2000 ColorSpec Tags +=head3 GIF Extensions Tags - Index1 Tag Name Writable - ------ -------- -------- - 0 ColorSpecMethod no - 1 ColorSpecPrecedence no - 2 ColorSpecApproximation no - 3 ICC_Profile ICC_Profile - ColorSpace no - ColorSpecData no - -=head3 Jpeg2000 FileType Tags - - Index4 Tag Name Writable - ------ -------- -------- - 0 MajorBrand no - 1 MinorVersion no - 2 CompatibleBrands no - -=head3 Jpeg2000 ImageHeader Tags - - Index1 Tag Name Writable - ------ -------- -------- - 0 ImageHeight no - 4 ImageWidth no - 8 NumberOfComponents no - 10 BitsPerComponent no - 11 Compression no - -=head3 Jpeg2000 CaptureResolution Tags - - Index1 Tag Name Writable - ------ -------- -------- - 0 CaptureYResolution no - 4 CaptureXResolution no - 8 CaptureYResolutionUnit no - 9 CaptureXResolutionUnit no - -=head3 Jpeg2000 DisplayResolution Tags - - Index1 Tag Name Writable - ------ -------- -------- - 0 DisplayYResolution no - 4 DisplayXResolution no - 8 DisplayYResolutionUnit no - 9 DisplayXResolutionUnit no - -=head2 GIF Tags - -This table lists information extracted from GIF images. See -L<http://www.w3.org/Graphics/GIF/spec-gif89a.txt> for the official GIF89a -specification. - - Tag Name Writable - -------- -------- - Comment yes - Duration no - Extensions GIF Extensions - FrameCount no - GIFVersion no - ScreenDescriptor GIF Screen - Text no - -=head3 GIF Extensions Tags - -Tags extracted from GIF89a application extensions. +Tags extracted from GIF89a application extensions. Tag ID Tag Name Writable ------ -------- -------- @@ -21601,6 +25303,7 @@ Information extracted from the GIF logical screen descriptor. 4.2 ColorResolutionDepth no 4.3 BitsPerPixel no 5 BackgroundColor no + 6 PixelAspectRatio no =head2 BMP Tags @@ -21853,6 +25556,19 @@ it is specifically deleted with C<-Trailer:All=>. When reading, a minor warning is issued if this trailer exists, and ExifTool will attempt to parse this data as additional PNG chunks. +Also according to the PNG specification, there is no restriction on the +location of text-type chunks (tEXt, zTXt and iTXt). However, certain +utilities (including some Apple and Adobe utilities) won't read the XMP iTXt +chunk if it comes after the IDAT chunk, and at least one utility won't read +other text chunks here. For this reason, when writing, ExifTool 11.63 and +later create new text chunks (including XMP) before IDAT, and move existing +text chunks to before IDAT. + +The PNG format contains CRC checksums that are validated when reading with +either the Verbose or Validate option. When writing, these checksums are +validated by default, but the FastScan option may be used to bypass this +check if speed is more of a concern. + Tag ID Tag Name Writable ------ -------- -------- 'IHDR' ImageHeader PNG ImageHeader @@ -21863,13 +25579,14 @@ this data as additional PNG chunks. 'dSIG' DigitalSignature no 'eXIf' eXIf EXIF 'fRAc' FractalParameters no - 'gAMA' Gamma no + 'gAMA' Gamma yes! 'gIFg' GIFGraphicControlExtension no 'gIFt' GIFPlainTextExtension no 'gIFx' GIFApplicationExtension no 'hIST' PaletteHistogram no 'iCCP' ICC_Profile ICC_Profile - 'iCCP-name' ProfileName no + 'iCCP-name' ProfileName yes + 'iDOT' AppleDataOffsets no 'iTXt' InternationalText PNG TextualData 'oFFs' ImageOffset no 'pCAL' PixelCalibration no @@ -21877,7 +25594,7 @@ this data as additional PNG chunks. 'sBIT' SignificantBits no 'sCAL' SubjectScale PNG SubjectScale 'sPLT' SuggestedPalette no - 'sRGB' SRGBRendering no + 'sRGB' SRGBRendering yes! 'sTER' StereoImage PNG StereoImage 'tEXt' TextualData PNG TextualData 'tIME' ModifyDate yes @@ -21901,7 +25618,7 @@ this data as additional PNG chunks. =head3 PNG AnimationControl Tags -Tags found in the Animation Conrol chunk. See +Tags found in the Animation Control chunk. See L<https://wiki.mozilla.org/APNG_Specification> for details. Index4 Tag Name Writable @@ -21938,6 +25655,8 @@ available. Alternate language tags and values containing special characters if the Compress option is used and Compress::Zlib is available. Raw profile information is always created as compressed zTXt if Compress::Zlib is available, or tEXt otherwise. Standard XMP is written as uncompressed iTXt. +User-defined tags may set an 'iTXt' flag in the tag definition to be written +only as iTXt. Alternate languages are accessed by suffixing the tag name with a '-', followed by an RFC 3066 language code (eg. "PNG:Comment-fr", or @@ -22356,6 +26075,8 @@ Tags extracted from DPX (Digital Picture Exchange) images. 776 ImageHeight no 780 DataSign no 800 ComponentsConfiguration no + 801 TransferCharacteristic no + 802 ColorimetricSpecification no 803 BitDepth no 820 ImageDescription no 892 Image2Description no @@ -22369,9 +26090,13 @@ Tags extracted from DPX (Digital Picture Exchange) images. 1532 SourceCreateDate no 1556 InputDeviceName no 1588 InputDeviceSerialNumber no - 1724 FrameRate no + 1628 AspectRatio no + 1724 OriginalFrameRate no + 1728 ShutterAngle no 1732 FrameID no 1764 SlateInformation no + 1920 TimeCode no + 1940 FrameRate no 1972 Reserved5? no 2048 UserID no @@ -22420,6 +26145,177 @@ the official specification. 'wrapmodes' WrapModes no 'xDensity' XResolution no +=head2 ZISRAW Tags + +As well as the header information listed below, ExifTool also extracts the +top-level XML-based metadata from Zeiss Integrated Software RAW (ZISRAW) CZI +files. + + Index1 Tag Name Writable + ------ -------- -------- + 32 ZISRAWVersion no + 48 PrimaryFileGUID no + 64 FileGUID no + +=head2 MRC Tags + +Tags extracted from Medical Research Council (MRC) format imaging files. +See L<https://www.ccpem.ac.uk/mrc_format/mrc2014.php> for the specification. + + Index4 Tag Name Writable + ------ -------- -------- + 0 ImageWidth no + 1 ImageHeight no + 2 ImageDepth no + 3 ImageMode no + 4 StartPoint no + 7 GridSize no + 10 CellWidth no + 11 CellHeight no + 12 CellDepth no + 13 CellAlpha no + 14 CellBeta no + 15 CellGamma no + 16 ImageWidthAxis no + 17 ImageHeightAxis no + 18 ImageDepthAxis no + 19 DensityMin no + 20 DensityMax no + 21 DensityMean no + 22 SpaceGroupNumber no + 23 ExtendedHeaderSize no + 26 ExtendedHeaderType no + 27 MRCVersion no + 49 Origin no + 53 MachineStamp no + 54 RMSDeviation no + 55 NumberOfLabels no + 56 Label0 no + 76 Label1 no + 96 Label2 no + 116 Label3 no + 136 Label4 no + 156 Label5 no + 176 Label6 no + 196 Label7 no + 216 Label8 no + 236 Label9 no + +=head3 MRC FEI12 Tags + +Tags extracted from FEI1 and FEI2 extended headers. + + Index1 Tag Name Writable + ------ -------- -------- + 0 MetadataSize no + 4 MetadataVersion no + 8 Bitmask1 no + 12 TimeStamp no + 20 MicroscopeType no + 36 MicroscopeID no + 52 Application no + 68 AppVersion no + 84 HighTension no + 92 Dose no + 100 AlphaTilt no + 108 BetaTilt no + 116 XStage no + 124 YStage no + 132 ZStage no + 140 TiltAxisAngle no + 148 DualAxisRot no + 156 PixelSizeX no + 164 PixelSizeY no + 220 Defocus no + 228 STEMDefocus no + 236 AppliedDefocus no + 244 InstrumentMode no + 248 ProjectionMode no + 252 ObjectiveLens no + 268 HighMagnificationMode no + 284 ProbeMode no + 288 EFTEMOn no + 289 Magnification no + 297 Bitmask2 no + 301 CameraLength no + 309 SpotIndex no + 313 IlluminationArea no + 321 Intensity no + 329 ConvergenceAngle no + 337 IlluminationMode no + 353 WideConvergenceAngleRange no + 354 SlitInserted no + 355 SlitWidth no + 363 AccelVoltOffset no + 371 DriftTubeVolt no + 379 EnergyShift no + 387 ShiftOffsetX no + 395 ShiftOffsetY no + 403 ShiftX no + 411 ShiftY no + 419 IntegrationTime no + 427 BinningWidth no + 431 BinningHeight no + 435 CameraName no + 451 ReadoutAreaLeft no + 455 ReadoutAreaTop no + 459 ReadoutAreaRight no + 463 ReadoutAreaBottom no + 467 CetaNoiseReduct no + 468 CetaFramesSummed no + 472 DirectDetElectronCounting no + 473 DirectDetAlignFrames no + 490 Bitmask3 no + 518 PhasePlate no + 519 STEMDetectorName no + 535 Gain no + 543 Offset no + 571 DwellTime no + 579 FrameTime no + 587 ScanSizeLeft no + 591 ScanSizeTop no + 595 ScanSizeRight no + 599 ScanSizeBottom no + 603 FullScanFOV_X no + 611 FullScanFOV_Y no + 619 Element no + 635 EnergyIntervalLower no + 643 EnergyIntervalHigher no + 651 Method no + 655 IsDoseFraction no + 656 FractionNumber no + 660 StartFrame no + 664 EndFrame no + 668 InputStackFilename no + 748 Bitmask4 no + 752 AlphaTiltMin no + 760 AlphaTiltMax no + 768 ScanRotation no + 776 DiffractionPatternRotation no + 784 ImageRotation no + 792 ScanModeEnumeration no + 796 AcquisitionTimeStamp no + 804 DetectorCommercialName no + 820 StartTiltAngle no + 828 EndTiltAngle no + 836 TiltPerImage no + 844 TitlSpeed no + 852 BeamCenterX no + 856 BeamCenterY no + 860 CFEGFlashTimeStamp no + 868 PhasePlatePosition no + 872 ObjectiveAperture no + +=head2 LIF Tags + +Tags extracted from Leica Image Format (LIF) imaging files. As well as the +tags listed below, all available information is extracted from the +XML-format metadata in the LIF header. + + Tag Name Writable + -------- -------- + TimeStampList no + =head2 MIFF Tags The MIFF (Magick Image File Format) format allows aribrary tag names to be @@ -22464,6 +26360,28 @@ decode any tags found in the image. 'units' Units no 'white-point' WhitePoint no +=head2 PCX Tags + +Tags extracted from PC Paintbrush images. + + Index1 Tag Name Writable + ------ -------- -------- + 0 Manufacturer no + 1 Software no + 2 Encoding no + 3 BitsPerPixel no + 4 LeftMargin no + 6 TopMargin no + 8 ImageWidth no + 10 ImageHeight no + 12 XResolution no + 14 YResolution no + 65 ColorPlanes no + 66 BytesPerLine no + 68 ColorMode no + 70 ScreenWidth no + 72 ScreenHeight no + =head2 PGF Tags The following table lists information extracted from the header of @@ -22573,6 +26491,7 @@ specification. Tag ID Tag Name Writable ------ -------- -------- '_command' Command no + '_comment' Comment no '_orient' Orientation no 'colorcorr' ColorCorrection no 'exposure' Exposure no @@ -22583,6 +26502,18 @@ specification. 'software' Software no 'view' View no +=head3 Other PFM Tags + +Tags extracted from Portable FloatMap images. See +L<http://www.pauldebevec.com/Research/HDR/PFM/> for the specification. + + Tag Name Writable + -------- -------- + ByteOrder no + ColorSpace no + ImageHeight no + ImageWidth no + =head2 PDF Tags The tags listed in the PDF tables below are those which are used by ExifTool @@ -22761,15 +26692,11 @@ This is the PDF document catalog. Tag ID Tag Name Writable ------ -------- -------- - 'Cs1' Cs1 PDF Cs1 + 'CS0' CS0 PDF DefaultRGB + 'Cs1' Cs1 PDF DefaultRGB + 'DefaultCMYK' DefaultCMYK PDF DefaultRGB 'DefaultRGB' DefaultRGB PDF DefaultRGB -=head3 PDF Cs1 Tags - - Tag ID Tag Name Writable - ------ -------- -------- - '_stream' _stream ICC_Profile - =head3 PDF DefaultRGB Tags Tag ID Tag Name Writable @@ -22893,13 +26820,13 @@ Additional document permissions imposed by digital signatures. =head2 ID3 Tags -ExifTool extracts ID3 information from MP3, MPEG, AIFF, OGG, FLAC, APE, MPC -and RealAudio files. ID3v2 tags which support multiple languages (eg. -Comment and Lyrics) are extracted by specifying the tag name, followed by a -dash ('-'), then a 3-character ISO 639-2 language code (eg. "Comment-spa"). -See L<http://www.id3.org/> for the official ID3 specification and -L<http://www.loc.gov/standards/iso639-2/php/code_list.php> for a list of ISO -639-2 language codes. +ExifTool extracts ID3 and Lyrics3 information from MP3, MPEG, WAV, AIFF, +OGG, FLAC, APE, MPC and RealAudio files. ID3v2 tags which support multiple +languages (eg. Comment and Lyrics) are extracted by specifying the tag name, +followed by a dash ('-'), then a 3-character ISO 639-2 language code (eg. +"Comment-spa"). See L<https://id3.org/> for the official ID3 specification +and L<http://www.loc.gov/standards/iso639-2/php/code_list.php> for a list of +ISO 639-2 language codes. Tag Name Writable -------- -------- @@ -23030,9 +26957,12 @@ software. 'APIC-2' PictureType no 'APIC-3' PictureDescription no 'COMM' Comment no + 'GRP1' Grouping no 'IPLS' InvolvedPeople no 'ITNU' iTunesU? no 'MCDI' MusicCDIdentifier no + 'MVIN' MovementNumber no + 'MVNM' MovementName no 'OWNE' Ownership no 'PCNT' PlayCounter no 'PCST' Podcast? no @@ -23132,8 +27062,11 @@ software. 'APIC-2' PictureType no 'APIC-3' PictureDescription no 'COMM' Comment no + 'GRP1' Grouping no 'ITNU' iTunesU? no 'MCDI' MusicCDIdentifier no + 'MVIN' MovementNumber no + 'MVNM' MovementName no 'OWNE' Ownership no 'PCNT' PlayCounter no 'PCST' Podcast? no @@ -23212,6 +27145,23 @@ software. 'XSOP' PerformerSortOrder no 'XSOT' TitleSortOrder no +=head3 ID3 Lyrics3 Tags + +ExifTool extracts Lyrics3 version 1.00 and 2.00 tags from any file that +supports ID3. See L<https://id3.org/Lyrics3> for the specification. + + Tag ID Tag Name Writable + ------ -------- -------- + 'AUT' Author no + 'CRC' CRC no + 'EAL' ExtendedAlbumName no + 'EAR' ExtendedArtistName no + 'ETT' ExtendedTrackTitle no + 'IMG' AssociatedImageFile no + 'IND' Indications no + 'INF' AdditionalInfo no + 'LYR' Lyrics no + =head2 ITC Tags This information is found in iTunes Cover Flow data files. @@ -23669,6 +27619,7 @@ which case subsequent occurrences are extracted as sub-documents). 0x00c5 GPSImgDirectionRef no 0x00c6 GPSImgDirection no 0x00c7 GPSMapDatum no + 0x00ca GPSDateStamp no 0x00e0 MakeModel H264 MakeModel 0x00e1 RecInfo H264 RecInfo 0x00e4 Model no @@ -23722,56 +27673,104 @@ Frame rate information stored by some Canon video cameras. =head2 QuickTime Tags The QuickTime format is used for many different types of audio, video and -image files (most notably, MOV/MP4 videos and HEIC/CR3 images). Exiftool -extracts standard meta information a variety of audio, video and image +image files (most notably, MOV/MP4 videos and HEIC/CR3 images). ExifTool +extracts standard meta information and a variety of audio, video and image parameters, as well as proprietary information written by many camera models. Tags with a question mark after their name are not extracted unless the Unknown option is set. -ExifTool currently has a very limited ability to write metadata in -QuickTime-format videos. It can edit/create/delete any XMP tags, but may -only be used to edit certain date/time tags and the video orientation in -native QuickTime metadata. - -According to the specification, many QuickTime date/time tags should be -stored as UTC. Unfortunately, digital cameras often store local time values -instead (presumably because they don't know the time zone). For this -reason, by default ExifTool does not assume a time zone for these values. -However, if the QuickTimeUTC API option is set, then ExifTool will assume -these values are properly stored as UTC, and will convert them to local time -when extracting. +When writing, ExifTool creates both QuickTime and XMP tags by default, but +the group may be specified to write one or the other separately. If no +location is specified, newly created QuickTime tags are added in the +L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> location if +possible, otherwise in +L<UserData|Image::ExifTool::TagNames/QuickTime UserData Tags>, and +finally in L<Keys|Image::ExifTool::TagNames/QuickTime Keys Tags>, +but this order may be changed by setting the PREFERRED level of the +appropriate table in the config file (see +example.config in the full distribution for an +example). Note that some tags with the same name but different ID's may +exist in the same location, but the family 7 group names may be used to +differentiate these. ExifTool currently writes only top-level metadata in +QuickTime-based files; it extracts other track-specific and timed metadata, +but can not yet edit tags in these locations (with the exception of +track-level date/time tags). + +Alternate language tags may be accessed for +L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> and +L<Keys|Image::ExifTool::TagNames/QuickTime Keys Tags> tags by adding +a 3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2 +country code to the tag name (eg. "ItemList:Artist-deu" or +"ItemList::Artist-deu-DE"). Most +L<UserData|Image::ExifTool::TagNames/QuickTime UserData Tags> tags support a +language code, but without a country code. If no language code is specified +when writing, the default language is written and alternate languages for +the tag are deleted. Use the "und" language code to write the default +language without deleting alternate languages. Note that "eng" is treated +as a default language when reading, but not when writing. + +According to the specification, integer-format QuickTime date/time tags +should be stored as UTC. Unfortunately, digital cameras often store local +time values instead (presumably because they don't know the time zone). For +this reason, by default ExifTool does not assume a time zone for these +values. However, if the API QuickTimeUTC option is set, then ExifTool will +assume these values are properly stored as UTC, and will convert them to +local time when extracting. + +When writing string-based date/time tags, the system time zone is added if +the PrintConv option is enabled and no time zone is specified. This is +because Apple software may display crazy values if the time zone is missing +for some tags. + +By default ExifTool will remove null padding from some QuickTime containers +in Canon CR3 files when writing, but the +QuickTimePad option may be used to preserve +the original size by padding with nulls if necessary. See -L<http://developer.apple.com/mac/library/documentation/QuickTime/QTFF/QTFFChap1/qtff1.html> +L<https://developer.apple.com/library/archive/documentation/QuickTime/QTFF/> for the official specification. Tag ID Tag Name Writable ------ -------- -------- + 'GPS ' GPSDataList2? no + 'IDIT' DateTimeOriginal string 'PICT' PreviewPICT no '_htc' HTCInfo QuickTime HTCInfo 'ardt' ARDroneFile no 'frea' Kodak_frea Kodak frea 'free' KodakFree Kodak Free + Pittasoft QuickTime Pittasoft + ThumbnailImage no Free? no 'ftyp' FileType QuickTime FileType + 'gps0' GPSTrack QuickTime Stream + 'gsen' GSensor QuickTime Stream 'junk' Junk? no - 'mdat' MovieData? no - 'mdat-offset' MovieDataOffset no - 'mdat-size' MovieDataSize no + 'mdat' MediaData? no + 'mdat-offset' MediaDataOffset no + 'mdat-size' MediaDataSize no + 'meco' OtherMeta QuickTime OtherMeta 'meta' Meta QuickTime Meta 'moof' MovieFragment QuickTime MovieFragment 'moov' Movie QuickTime Movie 'pict' PreviewPICT no 'pnot' Preview QuickTime Preview 'prrt' ARDroneTelemetry no + 'sefd' SamsungTrailer Samsung Trailer 'skip' CanonSkip Canon Skip + PreviewImage no Skip? no + 'thm ' ThumbnailImage no 'thum' ThumbnailImage no 'udat' GPSLog no 'udta' UserData FLIR UserData 'uuid' XMP XMP UUID-PROF QuickTime Profile UUID-Flip QuickTime Flip + UUID-Canon2 Canon uuid2 + SensorData QuickTime Tags360Fly + SensorData no PreviewImage no UUID-Unknown? no 'wide' Wide? no @@ -23784,6 +27783,318 @@ Tags written by some HTC camera phones. ------ -------- -------- 'slmt' Unknown_slmt? no +=head3 QuickTime Pittasoft Tags + +Tags found in Pittasoft Blackvue dashcam "free" data. + + Tag ID Tag Name Writable + ------ -------- -------- + '3gf ' AccelData QuickTime Stream + 'cprt' Copyright no + 'gps ' GPSLog no + 'ptnm' OriginalFileName no + 'ptrh' Ptrh QuickTime Pittasoft + 'sttm' StartTime no + 'thum' PreviewImage no + +=head3 QuickTime Stream Tags + +The tags below are extracted from timed metadata in QuickTime and other +formats of video files when the ExtractEmbedded option is used. Although +most of these tags are combined into the single table below, ExifTool +currently reads 59 different formats of timed GPS metadata from video files. + + Tag Name Writable + -------- -------- + Accelerometer no + AccelerometerData no + AngularVelocity no + CTMD Canon CTMD + CameraDateTime no + Car no + Distance no + ExposureCompensation no + ExposureTime no + FNumber no + FrameNumber no + GPSAltitude no + GPSDOP no + GPSDateTime no + GPSLatitude no + GPSLongitude no + GPSSatellites no + GPSSpeed no + GPSSpeedRef no + GPSTimeStamp no + GPSTrack no + GPSTrackRef no + GSensor no + INSV QuickTime INSV_MakerNotes + ISO no + JpgFromRaw no + KiloCalories no + PreviewInfo QuickTime PreviewInfo + RVMI_gReV QuickTime RVMI_gReV + RVMI_sReV QuickTime RVMI_sReV + RawGSensor no + SampleDateTime no + SampleDuration no + SampleTime no + Text no + TimeCode no + Unknown00? no + Unknown01? no + Unknown02? no + Unknown03? no + UserLabel no + VerticalSpeed no + VideoTimeStamp no + camm0 QuickTime camm0 + camm1 QuickTime camm1 + camm2 QuickTime camm2 + camm3 QuickTime camm3 + camm4 QuickTime camm4 + camm5 QuickTime camm5 + camm6 QuickTime camm6 + camm7 QuickTime camm7 + fdsc GoPro fdsc + gpmd_Kingslim QuickTime Stream + gpmd_Rove QuickTime Stream + gpmd_FMAS QuickTime Stream + gpmd_GoPro GoPro GPMF + marl QuickTime marl + mebx QuickTime Keys + mett Parrot mett + rtmd Sony rtmd + tx3g QuickTime tx3g + +=head3 QuickTime INSV_MakerNotes Tags + + Tag ID Tag Name Writable + ------ -------- -------- + 0x000a SerialNumber no + 0x0012 Model no + 0x001a Firmware no + 0x002a Parameters no + +=head3 QuickTime PreviewInfo Tags + +Preview stored by TomTom Bandit ActionCam. + + Index1 Tag Name Writable + ------ -------- -------- + 8 PreviewImage no + +=head3 QuickTime RVMI_gReV Tags + +GPS information extracted from the RVMI box of MOV videos. + + Index1 Tag Name Writable + ------ -------- -------- + 4 GPSLatitude no + 8 GPSLongitude no + 16 GPSSpeed no + 18 GPSTrack no + +=head3 QuickTime RVMI_sReV Tags + +G-sensor information extracted from the RVMI box of MOV videos. + + Index1 Tag Name Writable + ------ -------- -------- + 4 GSensor no + +=head3 QuickTime camm0 Tags + +The camm0 through camm7 tables define tags extracted from the Google Street +View Camera Motion Metadata of MP4 videos. See +L<https://developers.google.com/streetview/publish/camm-spec> for the +specification. + + Index1 Tag Name Writable + ------ -------- -------- + 4 AngleAxis no + +=head3 QuickTime camm1 Tags + + Index1 Tag Name Writable + ------ -------- -------- + 4 PixelExposureTime no + 8 RollingShutterSkewTime no + +=head3 QuickTime camm2 Tags + + Index1 Tag Name Writable + ------ -------- -------- + 4 AngularVelocity no + +=head3 QuickTime camm3 Tags + + Index1 Tag Name Writable + ------ -------- -------- + 4 Acceleration no + +=head3 QuickTime camm4 Tags + + Index1 Tag Name Writable + ------ -------- -------- + 4 Position no + +=head3 QuickTime camm5 Tags + + Index1 Tag Name Writable + ------ -------- -------- + 4 GPSLatitude no + 12 GPSLongitude no + 20 GPSAltitude no + +=head3 QuickTime camm6 Tags + + Index1 Tag Name Writable + ------ -------- -------- + 4 GPSDateTime no + 12 GPSMeasureMode no + 16 GPSLatitude no + 24 GPSLongitude no + 32 GPSAltitude no + 36 GPSHorizontalAccuracy no + 40 GPSVerticalAccuracy no + 44 GPSVelocityEast no + 48 GPSVelocityNorth no + 52 GPSVelocityUp no + 56 GPSSpeedAccuracy no + +=head3 QuickTime camm7 Tags + + Index1 Tag Name Writable + ------ -------- -------- + 4 MagneticField no + +=head3 QuickTime marl Tags + +Tags extracted from the marl ctbx timed metadata of GM cars. + + Tag ID Tag Name Writable + ------ -------- -------- + [no tags known] + +=head3 QuickTime Keys Tags + +This directory contains a list of key names which are used to decode tags +written by the "mdta" handler. Also in this table are a few tags found in +timed metadata that are not yet writable by ExifTool. The prefix of +"com.apple.quicktime." has been removed from the TagID's below. These tags +support alternate languages in the same way as the +L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> tags. Note +that by default, +L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> and +L<UserData|Image::ExifTool::TagNames/QuickTime UserData Tags> tags are +preferred when writing, so to create a tag when a same-named tag exists in +either of these tables, either the "Keys" location must be specified (eg. +C<-Keys:Author=Phil> on the command line), or the PREFERRED level must be +changed via the config file. + + Tag ID Tag Name Writable + ------ -------- -------- + 'Encoded_With' EncodedWith yes + 'album' Album yes + 'apple.photos.variation-identifier' + ApplePhotosVariationIdentifier int64s + 'artist' Artist yes + 'artwork' Artwork yes + 'author' Author yes + 'camera.framereadouttimeinmicroseconds' + FrameReadoutTime yes + 'camera.identifier' CameraIdentifier yes + 'collection.user' UserCollection yes + 'com.android.version' AndroidVersion yes + 'com.apple.photos.captureMode' CaptureMode yes + 'comment' Comment yes + 'copyright' Copyright yes + 'creationdate' CreationDate yes + 'description' Description yes + 'detected-face' FaceInfo QuickTime FaceInfo + 'detected-face.bounds' DetectedFaceBounds no + 'detected-face.face-id' DetectedFaceID no + 'detected-face.roll-angle' + DetectedFaceRollAngle no + 'detected-face.yaw-angle' + DetectedFaceYawAngle no + 'direction.facing' CameraDirection yes + 'direction.motion' CameraMotion yes + 'director' Director yes + 'displayname' DisplayName yes + 'genre' Genre yes + 'information' Information yes + 'keywords' Keywords yes + 'live-photo-info' LivePhotoInfo no + 'live-photo.auto' LivePhotoAuto int8u + 'live-photo.vitality-score' + LivePhotoVitalityScore float + 'live-photo.vitality-scoring-version' + LivePhotoVitalityScoringVersion int64s + 'location.ISO6709' GPSCoordinates yes + 'location.accuracy.horizontal' + LocationAccuracyHorizontal yes + 'location.body' LocationBody yes + 'location.date' LocationDate yes + 'location.name' LocationName yes + 'location.note' LocationNote yes + 'location.role' LocationRole yes + 'make' Make yes + 'model' Model yes + 'player.movie.audio.balance' Balance yes + 'player.movie.audio.bass' Bass yes + 'player.movie.audio.gain' AudioGain yes + 'player.movie.audio.mute' Mute int8u + 'player.movie.audio.pitchshift' PitchShift yes + 'player.movie.audio.treble' Treble yes + 'player.movie.visual.brightness' Brightness yes + 'player.movie.visual.color' Color yes + 'player.movie.visual.contrast' Contrast yes + 'player.movie.visual.tint' Tint yes + 'player.version' PlayerVersion yes + 'producer' Producer yes + 'publisher' Publisher yes + 'rating.user' UserRating yes + 'software' Software yes + 'still-image-time' StillImageTime no + 'title' Title yes + 'version' Version yes + 'video-orientation' VideoOrientation no + 'year' Year yes + +=head3 QuickTime FaceInfo Tags + + Tag ID Tag Name Writable + ------ -------- -------- + 'crec' FaceRec QuickTime FaceRec + +=head3 QuickTime FaceRec Tags + + Tag ID Tag Name Writable + ------ -------- -------- + 'cits' FaceItem QuickTime Keys + +=head3 QuickTime tx3g Tags + +Tags extracted from the tx3g sbtl timed metadata of Yuneec drones, and +subtitle text in some other videos. + + Tag ID Tag Name Writable + ------ -------- -------- + 'Alt' GPSAltitude no + 'DateTime' DateTime no + 'GimPitch' GimbalPitch no + 'GimRoll' GimbalRoll no + 'GimYaw' GimbalYaw no + 'Lat' GPSLatitude no + 'Lon' GPSLongitude no + 'Pitch' Pitch no + 'Roll' Roll no + 'Text' Text no + 'Yaw' Yaw no + =head3 QuickTime FileType Tags Index4 Tag Name Writable @@ -23792,14 +28103,28 @@ Tags written by some HTC camera phones. 1 MinorVersion no 2 CompatibleBrands no +=head3 QuickTime OtherMeta Tags + + Tag ID Tag Name Writable + ------ -------- -------- + 'mere' MetaRelation QuickTime MetaRelation + 'meta' Meta QuickTime Meta + +=head3 QuickTime MetaRelation Tags + + Index4 Tag Name Writable + ------ -------- -------- + [no tags known] + =head3 QuickTime Meta Tags Tag ID Tag Name Writable ------ -------- -------- 'bxml' BinaryXML? no - 'dinf' DataInformation? no + 'dinf' DataInfo QuickTime DataInfo 'free' Free? no 'hdlr' Handler QuickTime Handler + 'idat' MetaImageSize no 'iinf' ItemInformation QuickTime ItemInfo QuickTime ItemInfo 'iloc' ItemLocation no @@ -23810,8 +28135,28 @@ Tags written by some HTC camera phones. 'iref' ItemReference QuickTime ItemRef 'keys' Keys QuickTime Keys 'pitm' PrimaryItemReference no + 'uuid' MetaVersion no + UUID-Unknown? no 'xml ' XML XMP XML +=head3 QuickTime DataInfo Tags + +MP4 data information box. + + Tag ID Tag Name Writable + ------ -------- -------- + 'dref' DataRef QuickTime DataRef + +=head3 QuickTime DataRef Tags + +MP4 data reference box. + + Tag ID Tag Name Writable + ------ -------- -------- + "url\0" URL no + 'url ' URL no + 'urn ' URN no + =head3 QuickTime Handler Tags Index1 Tag Name Writable @@ -23829,112 +28174,157 @@ Tags written by some HTC camera phones. =head3 QuickTime ItemList Tags -As well as these tags, the "mdta" handler uses numerical tag ID's which are -added dynamically to this table after processing the Meta Keys information. +This is the preferred location for creating new QuickTime tags. Tags in +this table support alternate languages which are accessed by adding a +3-character ISO 639-2 language code and an optional ISO 3166-1 alpha 2 +country code to the tag name (eg. "ItemList:Title-fra" or +"ItemList::Title-fra-FR"). When creating a new Meta box to contain the +ItemList directory, by default ExifTool adds an 'mdir' (Metadata) Handler +box because Apple software may ignore ItemList tags otherwise, but the API +QuickTimeHandler option may be set to 0 to avoid this. Tag ID Tag Name Writable ------ -------- -------- '----' iTunesInfo QuickTime iTunesInfo - '@PST' ParentShortTitle no - '@ppi' ParentProductID no - '@pti' ParentTitle no - '@sti' ShortTitle no - 'AACR' Unknown_AACR? no - 'CDEK' Unknown_CDEK? no - 'CDET' Unknown_CDET? no - 'GUID' GUID no - 'VERS' ProductVersion no - 'aART' AlbumArtist no - 'akID' AppleStoreAccountType no - 'albm' Album no - 'apID' AppleStoreAccount no - 'atID' AlbumTitleID no - 'auth' Author no - 'catg' Category no - 'cnID' AppleStoreCatalogID no - 'covr' CoverArt no - 'cpil' Compilation no - 'cprt' Copyright no - 'desc' Description no - 'disk' DiskNumber no - 'dscp' Description no - 'egid' EpisodeGlobalUniqueID no - 'geID' GenreID no - 'gnre' Genre no - 'grup' Grouping no - 'gshh' GoogleHostHeader no - 'gspm' GooglePingMessage no - 'gspu' GooglePingURL no - 'gssd' GoogleSourceData no - 'gsst' GoogleStartTime no - 'gstd' GoogleTrackDuration no - 'hdvd' HDVideo no - 'itnu' iTunesU no - 'keyw' Keyword no - 'ldes' LongDescription no - 'pcst' Podcast no - 'perf' Performer no - 'pgap' PlayGap no - 'plID' PlayListID no - 'prID' ProductID no - 'purd' PurchaseDate no - 'purl' PodcastURL no - 'rate' RatingPercent no - 'rldt' ReleaseDate no - 'rtng' Rating no - 'sfID' AppleStoreCountry no - 'soaa' SortAlbumArtist no - 'soal' SortAlbum no - 'soar' SortArtist no - 'soco' SortComposer no - 'sonm' SortName no - 'sosn' SortShow no - 'stik' MediaType no - 'titl' Title no - 'tmpo' BeatsPerMinute no - 'trkn' TrackNumber no - 'tven' TVEpisodeID no - 'tves' TVEpisode no - 'tvnn' TVNetworkName no - 'tvsh' TVShow no - 'tvsn' TVSeason no - 'yrrc' Year no - "\xa9ART" Artist no - "\xa9alb" Album no - "\xa9cmt" Comment no - "\xa9com" Composer no - "\xa9cpy" Copyright no - "\xa9day" ContentCreateDate no - "\xa9des" Description no - "\xa9enc" EncodedBy no - "\xa9gen" Genre no - "\xa9grp" Grouping no - "\xa9lyr" Lyrics no - "\xa9nam" Title no - "\xa9nrt" Narrator no - "\xa9pub" Publisher no - "\xa9too" Encoder no - "\xa9trk" Track no - "\xa9wrt" Composer no + '@PST' ParentShortTitle string + '@ppi' ParentProductID string + '@pti' ParentTitle string + '@sti' ShortTitle string + 'AACR' Unknown_AACR? string + 'CDEK' Unknown_CDEK? string + 'CDET' Unknown_CDET? string + 'GUID' GUID string + 'VERS' ProductVersion string + 'aART' AlbumArtist string + 'akID' AppleStoreAccountType int8s + 'albm' Album string/ + 'apID' AppleStoreAccount string + 'atID' AlbumTitleID int32s + 'auth' Author string + 'catg' Category string + 'cnID' AppleStoreCatalogID int32s + 'covr' CoverArt string + 'cpil' Compilation int8s + 'cprt' Copyright string + 'desc' Description string/ + 'disk' DiskNumber undef + 'dscp' Description string/ + 'egid' EpisodeGlobalUniqueID string + 'geID' GenreID int32s + 'gnre' Genre undef/ + 'grup' Grouping string/ + 'gshh' GoogleHostHeader string + 'gspm' GooglePingMessage string + 'gspu' GooglePingURL string + 'gssd' GoogleSourceData string + 'gsst' GoogleStartTime string + 'gstd' GoogleTrackDuration string + 'hdvd' HDVideo int8s + 'itnu' iTunesU int8s + 'keyw' Keyword string + 'ldes' LongDescription string + 'pcst' Podcast int8s + 'perf' Performer string + 'pgap' PlayGap int8s + 'plID' PlayListID int32s[0.25] + 'prID' ProductID string + 'purd' PurchaseDate string + 'purl' PodcastURL string + 'rate' RatingPercent string + 'rldt' ReleaseDate string + 'rtng' Rating int8s + 'sdes' StoreDescription string + 'sfID' AppleStoreCountry int32s + 'shwm' ShowMovement int8s + 'soaa' SortAlbumArtist string + 'soal' SortAlbum string + 'soar' SortArtist string + 'soco' SortComposer string + 'sonm' SortName string + 'sosn' SortShow string + 'stik' MediaType int8s + 'titl' Title string/ + 'tmpo' BeatsPerMinute int16s + 'trkn' TrackNumber undef + 'tven' TVEpisodeID string + 'tves' TVEpisode int32s + 'tvnn' TVNetworkName string + 'tvsh' TVShow string + 'tvsn' TVSeason int32u + 'yrrc' Year string + "\xa9ART" Artist string + "\xa9alb" Album string + "\xa9ard" ArtDirector string + "\xa9arg" Arranger string + "\xa9aut" Author string/ + "\xa9cmt" Comment string + "\xa9com" Composer string/ + "\xa9con" Conductor string + "\xa9cpy" Copyright string/ + "\xa9day" ContentCreateDate string + "\xa9des" Description string + "\xa9dir" Director string + "\xa9enc" EncodedBy string + "\xa9gen" Genre string + "\xa9grp" Grouping string + "\xa9lyr" Lyrics string + "\xa9mvc" MovementCount int16s + "\xa9mvi" MovementNumber int16s + "\xa9mvn" MovementName string + "\xa9nam" Title string + "\xa9nrt" Narrator string + "\xa9ope" OriginalArtist string + "\xa9prd" Producer string + "\xa9pub" Publisher string + "\xa9sne" SoundEngineer string + "\xa9sol" Soloist string + "\xa9st3" Subtitle string + "\xa9too" Encoder string + "\xa9trk" Track string + "\xa9wrk" Work string + "\xa9wrt" Composer string + "\xa9xpd" ExecutiveProducer string + "\xa9xyz" GPSCoordinates string =head3 QuickTime iTunesInfo Tags ExifTool will extract any iTunesInfo tags that exist, even if they are not -defined in this table. +defined in this table. These tags belong to the family 1 "iTunes" group, +and are not currently writable. Tag ID Tag Name Writable ------ -------- -------- + 'ARTISTS' Artists no + 'BARCODE' Barcode no + 'CATALOGNUMBER' CatalogNumber no 'DISCNUMBER' DiscNumber no + 'Dynamic Range (DR)' DynamicRange no + 'Dynamic Range (R128)' DynamicRangeR128 no 'Encoding Params' EncodingParams QuickTime EncodingParams + 'LABEL' Label no + 'MEDIA' Media no + 'MOOD' Mood no + 'Peak Level (R128)' PeakLevelR128 no + 'Peak Level (Sample)' PeakLevelSample no + 'RATING' Rating no + 'SCRIPT' Script no 'TRACKNUMBER' TrackNumber no + 'Volume Level (R128)' VolumeLevelR128 no + 'Volume Level (ReplayGain)' ReplayVolumeLevel no 'iTunEXTC' ContentRating no 'iTunMOVI' iTunMOVI PLIST 'iTunNORM' VolumeNormalization no 'iTunSMPB' iTunSMPB no 'iTunes_CDDB_1' CDDB1Info no 'iTunes_CDDB_TrackNumber' CDDBTrackNumber no + 'initialkey' InitialKey no + 'originaldate' OriginalDate no + 'originalyear' OriginalYear no 'popularimeter' Popularimeter no + 'replaygain_track_gain' ReplayTrackGain no + 'replaygain_track_peak' ReplayTrackPeak no 'tool' iTunTool no + '~length' Length no =head3 QuickTime EncodingParams Tags @@ -23977,106 +28367,93 @@ defined in this table. Tag ID Tag Name Writable ------ -------- -------- 'auxC' AuxiliaryImageType no + 'av1C' AV1Configuration QuickTime AV1Config 'clap' CleanAperture no 'colr' ICC_Profile ICC_Profile - 'hvcC' HEVCConfiguration? no - 'irot' Rotation no + ColorRepresentation QuickTime ColorRep + 'hvcC' HEVCConfiguration QuickTime HEVCConfig + 'irot' Rotation int8u! 'ispe' ImageSpatialExtent no - 'pasp' PixelAspectRatio no + 'pasp' PixelAspectRatio int32u! 'pixi' ImagePixelDepth no 'rloc' RelativeLocation no -=head3 QuickTime ItemRef Tags +=head3 QuickTime AV1Config Tags - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 'cdsc' ContentDescribes no + 0 AV1ConfigurationVersion no + 1 SeqProfile? no + 1.1 SeqLevelIdx0? no + 2 SeqTier0? no + 2.1 HighBitDepth? no + 2.2 TwelveBit? no + 2.3 ChromaFormat no + 2.4 ChromaSamplePosition no + 3 InitialDelaySamples? no -=head3 QuickTime Keys Tags +=head3 QuickTime ColorRep Tags -This directory contains a list of key names which are used to decode -ItemList tags written by the "mdta" handler. The prefix of -"com.apple.quicktime." has been removed from all TagID's below. - - Tag ID Tag Name Writable - ------ -------- -------- - 'Encoded_With' EncodedWith no - 'album' Album no - 'artist' Artist no - 'artwork' Artwork no - 'author' Author no - 'camera.framereadouttimeinmicroseconds' - FrameReadoutTime no - 'camera.identifier' CameraIdentifier no - 'collection.user' UserCollection no - 'comment' Comment no - 'copyright' Copyright no - 'creationdate' CreationDate no - 'description' Description no - 'detected-face' FaceInfo QuickTime FaceInfo - 'detected-face.bounds' DetectedFaceBounds no - 'detected-face.face-id' DetectedFaceID no - 'detected-face.roll-angle' - DetectedFaceRollAngle no - 'detected-face.yaw-angle' - DetectedFaceYawAngle no - 'direction.facing' CameraDirection no - 'direction.motion' CameraMotion no - 'director' Director no - 'genre' Genre no - 'information' Information no - 'keywords' Keywords no - 'location.ISO6709' GPSCoordinates no - 'location.body' LocationBody no - 'location.date' LocationDate no - 'location.name' LocationName no - 'location.note' LocationNote no - 'location.role' LocationRole no - 'make' Make no - 'model' Model no - 'player.movie.audio.balance' Balance no - 'player.movie.audio.bass' Bass no - 'player.movie.audio.gain' AudioGain no - 'player.movie.audio.mute' Mute no - 'player.movie.audio.pitchshift' PitchShift no - 'player.movie.audio.treble' Trebel no - 'player.movie.visual.brightness' Brightness no - 'player.movie.visual.color' Color no - 'player.movie.visual.contrast' Contrast no - 'player.movie.visual.tint' Tint no - 'player.version' PlayerVersion no - 'producer' Producer no - 'publisher' Publisher no - 'rating.user' UserRating no - 'software' Software no - 'title' Title no - 'version' Version no - 'video-orientation' VideoOrientation no - 'year' Year no + Index1 Tag Name Writable + ------ -------- -------- + 0 ColorProfiles no + 4 ColorPrimaries no + 6 TransferCharacteristics no + 8 MatrixCoefficients no -=head3 QuickTime FaceInfo Tags +=head3 QuickTime HEVCConfig Tags - Tag ID Tag Name Writable + Index1 Tag Name Writable ------ -------- -------- - 'crec' FaceRec QuickTime FaceRec + 0 HEVCConfigurationVersion no + 1 GeneralProfileSpace no + 1.1 GeneralTierFlag no + 1.2 GeneralProfileIDC no + 2 GenProfileCompatibilityFlags no + 6 ConstraintIndicatorFlags no + 12 GeneralLevelIDC no + 13 MinSpatialSegmentationIDC no + 15 ParallelismType no + 16 ChromaFormat no + 17 BitDepthLuma no + 18 BitDepthChroma no + 19 AverageFrameRate no + 21 ConstantFrameRate no + 21.1 NumTemporalLayers no + 21.2 TemporalIDNested no -=head3 QuickTime FaceRec Tags +=head3 QuickTime ItemRef Tags + +The Item reference entries listed in the table below contain information about +the associations between items in the file. This information is used by +ExifTool, but these entries are not extracted as tags. Tag ID Tag Name Writable ------ -------- -------- - 'cits' FaceItem QuickTime Keys + 'auxl' AuxiliaryImageRef no + 'cdsc' ContentDescribes no + 'dimg' DerivedImageRef no + 'thmb' ThumbnailRef no =head3 QuickTime MovieFragment Tags Tag ID Tag Name Writable ------ -------- -------- + 'meta' Meta QuickTime Meta + 'mfhd' MovieFragmentHeader QuickTime MovieFragHdr 'traf' TrackFragment QuickTime TrackFragment +=head3 QuickTime MovieFragHdr Tags + + Index4 Tag Name Writable + ------ -------- -------- + 1 MovieFragmentSequence no + =head3 QuickTime TrackFragment Tags Tag ID Tag Name Writable ------ -------- -------- - [no tags known] + 'meta' Meta QuickTime Meta =head3 QuickTime Movie Tags @@ -24086,6 +28463,7 @@ ItemList tags written by the "mdta" handler. The prefix of 'gps ' GPSDataList? no 'htka' HTCTrack QuickTime Track 'iods' InitialObjectDescriptor? no + 'meco' OtherMeta QuickTime OtherMeta 'meta' Meta QuickTime Meta 'mvhd' MovieHeader QuickTime MovieHeader 'trak' Track QuickTime Track @@ -24105,6 +28483,7 @@ ItemList tags written by the "mdta" handler. The prefix of Tag ID Tag Name Writable ------ -------- -------- 'mdia' Media QuickTime Media + 'meco' OtherMeta QuickTime OtherMeta 'meta' Meta QuickTime Meta 'tapt' TrackAperture QuickTime TrackAperture 'tkhd' TrackHeader QuickTime TrackHeader @@ -24141,32 +28520,14 @@ MP4 media info box. Tag ID Tag Name Writable ------ -------- -------- - 'dinf' DataInfo QuickTime DataInfo - 'gmhd' GenMediaHeader QuickTime GenMediaHeader - 'hdlr' Handler QuickTime Handler - 'hmhd' HintHeader QuickTime HintHeader - 'nmhd' NullMediaHeader? no - 'smhd' AudioHeader QuickTime AudioHeader - 'stbl' SampleTable QuickTime SampleTable - 'vmhd' VideoHeader QuickTime VideoHeader - -=head3 QuickTime DataInfo Tags - -MP4 data information box. - - Tag ID Tag Name Writable - ------ -------- -------- - 'dref' DataRef QuickTime DataRef - -=head3 QuickTime DataRef Tags - -MP4 data reference box. - - Tag ID Tag Name Writable - ------ -------- -------- - "url\0" URL no - 'url ' URL no - 'urn ' URN no + 'dinf' DataInfo QuickTime DataInfo + 'gmhd' GenMediaHeader QuickTime GenMediaHeader + 'hdlr' Handler QuickTime Handler + 'hmhd' HintHeader QuickTime HintHeader + 'nmhd' NullMediaHeader? no + 'smhd' AudioHeader QuickTime AudioHeader + 'stbl' SampleTable QuickTime SampleTable + 'vmhd' VideoHeader QuickTime VideoHeader =head3 QuickTime GenMediaHeader Tags @@ -24318,6 +28679,7 @@ Child atoms found in "sinf" and/or "pinf" atoms. Tag ID Tag Name Writable ------ -------- -------- + 'enda' Endianness no 'frma' OriginalFormat no 'schi' SchemeInfo QuickTime SchemeInfo 'schm' SchemeType QuickTime SchemeType @@ -24358,6 +28720,7 @@ Child atoms found in "sinf" and/or "pinf" atoms. Tag ID Tag Name Writable ------ -------- -------- + 'enda' Endianness no 'frma' PurchaseFileFormat no =head3 QuickTime ImageDesc Tags @@ -24373,11 +28736,12 @@ Child atoms found in "sinf" and/or "pinf" atoms. 25 CompressorName no 41 BitDepth no 'CDI1' CDI1 Canon CDI1 + 'CMP1' CMP1 Canon CMP1 'JPEG' JPEGInfo? no 'avcC' AVCConfiguration? no 'btrt' BitrateInfo QuickTime Bitrate 'clap' CleanAperture QuickTime CleanAperture - 'colr' ColorRepresentation no + 'colr' ColorRepresentation QuickTime ColorRep 'fiel' VideoFieldOrder no 'gama' Gamma no 'pasp' PixelAspectRatio no @@ -24464,6 +28828,7 @@ MP4 metadata sample description. Tag ID Tag Name Writable ------ -------- -------- 0x0004 MetaFormat no + 0x0008 MetaType no 'btrt' BitrateInfo QuickTime Bitrate 'keys' Keys QuickTime Keys @@ -24473,6 +28838,7 @@ MP4 metadata sample description. ------ -------- -------- 0x0004 OtherFormat no 'ftab' FontTable no + 'name' OtherName no =head3 QuickTime VideoHeader Tags @@ -24502,7 +28868,7 @@ MP4 video media header. 5 TrackDuration no 8 TrackLayer no 9 TrackVolume no - 10 MatrixStructure fixed32s[9] + 10 MatrixStructure fixed32s[9]! 19 ImageWidth no 20 ImageHeight no @@ -24518,31 +28884,42 @@ MP4 video media header. =head3 QuickTime UserData Tags Tag ID's beginning with the copyright symbol (hex 0xa9) are multi-language -text. Alternate language tags are accessed by adding a dash followed by the -language/country code to the tag name. ExifTool will extract any -multi-language user data tags found, even if they don't exist in this table. +text. Alternate language tags are accessed by adding a dash followed by a +3-character ISO 639-2 language code to the tag name. ExifTool will extract +any multi-language user data tags found, even if they aren't in this table. +Note when creating new tags, +L<ItemList|Image::ExifTool::TagNames/QuickTime ItemList Tags> tags are +preferred over these, so to create the tag when a same-named ItemList tag +exists, either "UserData" must be specified (eg. C<-UserData:Artist=Monet> +on the command line), or the PREFERRED level must be changed via +the config file. Tag ID Tag Name Writable ------ -------- -------- + '@day' ContentCreateDate string/ + '@mak' Make string/ + '@mod' Model string/ '@sec' SamsungSec Samsung sec - 'AllF' PlayAllFrames no - 'CAME' SerialNumberHash no - 'CNCV' CompressorVersion no - 'CNFV' FirmwareVersion no - 'CNMN' Model no + '@swr' SoftwareVersion string/ + '@xyz' GPSCoordinates string/ + 'AllF' PlayAllFrames int8u + 'CAME' SerialNumberHash string + 'CNCV' CompressorVersion string + 'CNFV' FirmwareVersion string + 'CNMN' Model string/ 'CNOP' CanonCNOP Canon CNOP 'CNTH' CanonCNTH Canon CNTH 'DcMD' KodakDcMD Kodak DcMD 'FFMV' FujiFilmFFMV FujiFilm FFMV - 'FIRM' FirmwareVersion no - "FOV\0" FieldOfView no + 'FIRM' FirmwareVersion string/ + "FOV\0" FieldOfView string 'GPMF' GoProGPMF GoPro GPMF - 'GoPr' GoProType no + 'GoPr' GoProType string 'INFO' SamsungINFO Samsung INFO 'LEIC' LeicaLEIC Panasonic PANA - 'LENS' LensSerialNumber no - 'LOOP' LoopStyle no - 'Lvlm' LevelMeter? no + 'LENS' LensSerialNumber string + 'LOOP' LoopStyle int32u + 'Lvlm' LevelMeter? rational64s 'MMA0' MinoltaMMA0 Minolta MMA 'MMA1' MinoltaMMA1 Minolta MMA 'MVTG' FujiFilmMVTG EXIF @@ -24551,14 +28928,14 @@ multi-language user data tags found, even if they don't exist in this table. 'PENT' PentaxPENT Pentax PENT 'PXMN' MakerNotePentax5b Pentax MakerNotePentax5c Pentax - MakerNotePentaxUnknown no + MakerNotePentaxUnknown string 'PXTH' PentaxPreview Pentax PXTH 'QVMI' CasioQVMI EXIF 'RMKN' RicohRMKN EXIF 'RTHU' PreviewImage no - 'SDLN' PlayMode no - 'SNum' SerialNumber no - 'SelO' PlaySelection no + 'SDLN' PlayMode string + 'SNum' SerialNumber string/ + 'SelO' PlaySelection int8u 'TAGS' FujiFilmTags FujiFilm MOV KodakTags Kodak MOV KonicaMinoltaTags Minolta MOV1 @@ -24572,132 +28949,151 @@ multi-language user data tags found, even if they don't exist in this table. SamsungTags Samsung MP4 SanyoMOV Sanyo MOV SanyoMP4 Sanyo MP4 - UnknownTags? no - 'WLOC' WindowLocation no + UnknownTags? string + 'TTMD' TomTomMetaData QuickTime TomTom + 'WLOC' WindowLocation int16u 'XMP_' XMP XMP 'Xtra' MicrosoftXtra Microsoft Xtra - '_cx_' CX? no - '_cy_' CY? no - '_yaw' Yaw no - 'albm' Album no - 'albr' AlbumArtist no - 'angl' CameraAngle no - 'apmd' ApertureMode no - 'auth' Author no - 'ccid' ContentID no - 'cdis' ContentDistributorID no + '_cx_' CX? rational64s + '_cy_' CY? rational64s + '_yaw' Yaw rational64s/ + 'albm' Album string/ + 'albr' AlbumArtist string + 'angl' CameraAngle string + 'apmd' ApertureMode undef + 'auth' Author string/ + 'ccid' ContentID string + 'cdis' ContentDistributorID string 'chpl' ChapterList no - 'clfn' ClipFileName no - 'clid' ClipID no - 'clsf' Classification no - 'cmid' CameraID no - 'cmnm' Model no - 'coll' CollectionName no - 'cprt' Copyright no - 'cver' CodeVersion no - 'cvru' CoverURI no - 'date' DateTimeOriginal no - 'dscp' Description no - 'gnre' Genre no + 'clfn' ClipFileName string + 'clid' ClipID string + 'clsf' Classification undef/ + 'cmid' CameraID string + 'cmnm' Model string/ + 'coll' CollectionName string/ + 'cprt' Copyright string/ + 'cver' CodeVersion string + 'cvru' CoverURI string + 'date' DateTimeOriginal string + 'dscp' Description string/ + 'gnre' Genre string/ 'hinf' HintTrackInfo QuickTime HintTrackInfo - 'hinv' HintVersion no + 'hinv' HintVersion string 'hnti' HintInfo QuickTime HintInfo 'htcb' HTCBinary QuickTime HTCBinary - 'icnu' IconURI no - 'infu' InfoURL no - 'kgtt' TrackType no + 'icnu' IconURI string + 'infu' InfoURL string + 'kgtt' TrackType string 'kywd' Keywords no - 'loci' LocationInformation no - 'lrcu' LyricsURI no - 'lvlm' LevelMeter? no + 'loci' LocationInformation undef/ + 'lrcu' LyricsURI string + 'lvlm' LevelMeter? rational64s 'manu' Make no + 'mcvr' PreviewImage string 'meta' Meta QuickTime Meta 'modl' Model no - 'name' Name no - 'perf' Performer no + 'name' Name string + 'perf' Performer string/ + 'pmcc' GarminSettings string 'pose' pose Kodak pose - 'ptch' Pitch no + 'ptch' Pitch rational64s/ 'ptv ' PrintToVideo QuickTime Video - 'rads' Rads? no - 'reel' ReelName no - 'roll' Roll no - 'rtng' Rating no - 'scen' Scene no + 'rads' Rads? rational64s + 'reel' ReelName string + 'roll' Roll rational64s/ + 'rtng' Rating undef/ + 'scen' Scene string 'scrn' OlympusPreview Olympus scrn - 'shot' ShotName no - 'slno' SerialNumber no + 'shot' ShotName string + 'slno' SerialNumber string 'smta' SamsungSmta Samsung smta 'tags' Audible_tags Audible tags 'thmb' MakerNotePentax5a Pentax OlympusThumbnail Olympus thmb - ThumbnailImage no - ThumbnailPNG no - UnknownThumbnail no - 'titl' Title no - 'urat' UserRating no - 'vndr' Vendor no - 'yrrc' Year no - "\xa9ART" Artist no - "\xa9TSC" StartTimeScale no - "\xa9TSZ" StartTimeSampleSize no - "\xa9alb" Album no - "\xa9arg" Arranger no - "\xa9ark" ArrangerKeywords no - "\xa9cmt" Comment no - "\xa9cok" ComposerKeywords no - "\xa9com" Composer no - "\xa9cpy" Copyright no - "\xa9day" ContentCreateDate no - "\xa9dir" Director no - "\xa9ed1" Edit1 no - "\xa9ed2" Edit2 no - "\xa9ed3" Edit3 no - "\xa9ed4" Edit4 no - "\xa9ed5" Edit5 no - "\xa9ed6" Edit6 no - "\xa9ed7" Edit7 no - "\xa9ed8" Edit8 no - "\xa9ed9" Edit9 no - "\xa9enc" EncoderID no - "\xa9fmt" Format no - "\xa9fpt" Pitch no - "\xa9frl" Roll no - "\xa9fyw" Yaw no - "\xa9gen" Genre no - "\xa9gpt" CameraPitch no - "\xa9grl" CameraRoll no - "\xa9grp" Grouping no - "\xa9gyw" CameraYaw no - "\xa9inf" Information no - "\xa9isr" ISRCCode no - "\xa9lab" RecordLabelName no - "\xa9lal" RecordLabelURL no - "\xa9lyr" Lyrics no - "\xa9mak" Make no - "\xa9mal" MakerURL no - "\xa9mdl" Model no - "\xa9mod" Model no - "\xa9nam" Title no - "\xa9pdk" ProducerKeywords no - "\xa9phg" RecordingCopyright no - "\xa9prd" Producer no - "\xa9prf" Performers no - "\xa9prk" PerformerKeywords no - "\xa9prl" PerformerURL no - "\xa9req" Requirements no - "\xa9snk" SubtitleKeywords no - "\xa9snm" Subtitle no - "\xa9src" SourceCredits no - "\xa9swf" SongWriter no - "\xa9swk" SongWriterKeywords no - "\xa9swr" SoftwareVersion no - "\xa9too" Encoder no - "\xa9trk" Track no - "\xa9wrt" Composer no - "\xa9xsp" SpeedX no - "\xa9xyz" GPSCoordinates no - "\xa9ysp" SpeedY no - "\xa9zsp" SpeedZ no + ThumbnailImage string + ThumbnailPNG string + UnknownThumbnail string + 'titl' Title string/ + 'urat' UserRating undef/ + 'uuid' GarminSoftware string + UUID-Unknown? no + 'vndr' Vendor string + 'vrot' AccelerometerData no + 'yrrc' Year undef/ + "\xa9ART" Artist string + "\xa9TIM" StartTimecode string + "\xa9TSC" StartTimeScale string + "\xa9TSZ" StartTimeSampleSize string + "\xa9alb" Album string + "\xa9arg" Arranger string + "\xa9ark" ArrangerKeywords string + "\xa9cmt" Comment string + "\xa9cok" ComposerKeywords string + "\xa9com" Composer string + "\xa9cpy" Copyright string + "\xa9day" ContentCreateDate string + "\xa9dir" Director string + "\xa9ed1" Edit1 string + "\xa9ed2" Edit2 string + "\xa9ed3" Edit3 string + "\xa9ed4" Edit4 string + "\xa9ed5" Edit5 string + "\xa9ed6" Edit6 string + "\xa9ed7" Edit7 string + "\xa9ed8" Edit8 string + "\xa9ed9" Edit9 string + "\xa9enc" EncoderID string + "\xa9fmt" Format string + "\xa9fpt" Pitch string + "\xa9frl" Roll string + "\xa9fyw" Yaw string + "\xa9gen" Genre string + "\xa9gpt" CameraPitch string + "\xa9grl" CameraRoll string + "\xa9grp" Grouping string + "\xa9gyw" CameraYaw string + "\xa9inf" Information string + "\xa9isr" ISRCCode string + "\xa9lab" RecordLabelName string + "\xa9lal" RecordLabelURL string + "\xa9lyr" Lyrics string + "\xa9mak" Make string + "\xa9mal" MakerURL string + "\xa9mdl" Model string/ + "\xa9mod" Model string + "\xa9nam" Title string + "\xa9pdk" ProducerKeywords string + "\xa9phg" RecordingCopyright string + "\xa9prd" Producer string + "\xa9prf" Performers string + "\xa9prk" PerformerKeywords string + "\xa9prl" PerformerURL string + "\xa9req" Requirements string + "\xa9snk" SubtitleKeywords string + "\xa9snm" Subtitle string + "\xa9src" SourceCredits string + "\xa9swf" SongWriter string + "\xa9swk" SongWriterKeywords string + "\xa9swr" SoftwareVersion string + "\xa9too" Encoder string + "\xa9trk" Track string + "\xa9wrt" Composer string/ + "\xa9xsp" SpeedX string + "\xa9xyz" GPSCoordinates string + "\xa9ysp" SpeedY string + "\xa9zsp" SpeedZ string + +=head3 QuickTime TomTom Tags + +Tags found in TomTom Bandit Action Cam MP4 videos. + + Tag ID Tag Name Writable + ------ -------- -------- + 'TTAD' TomTomAD QuickTime Stream + 'TTHL' TomTomHL? no + 'TTID' TomTomID no + 'TTVD' TomTomVD no + 'TTVI' TomTomVI? no =head3 QuickTime HintTrackInfo Tags @@ -24846,194 +29242,268 @@ Found in MP4 files from Flip Video cameras. 14 SerialNumber no 28 PreviewImage no -=head3 QuickTime ImageFile Tags +=head3 QuickTime Tags360Fly Tags -Tags used in QTIF QuickTime Image Files. +Timed metadata found in MP4 videos from the 360Fly. Tag ID Tag Name Writable ------ -------- -------- - 'idat' ImageData no - 'idsc' ImageDescription QuickTime ImageDesc - 'iicc' ICC_Profile ICC_Profile + 0x0001 Accel360Fly QuickTime Accel360Fly + 0x0002 Gyro360Fly QuickTime Gyro360Fly + 0x0003 Mag360Fly QuickTime Mag360Fly + 0x0005 GPS360Fly QuickTime GPS360Fly + 0x0006 Rot360Fly QuickTime Rot360Fly + 0x00fa Fusion360Fly QuickTime Fusion360Fly -=head3 QuickTime Stream Tags +=head3 QuickTime Accel360Fly Tags -Timed metadata extracted from QuickTime movie data and some AVI videos when -the ExtractEmbedded option is used. + Index1 Tag Name Writable + ------ -------- -------- + 1 AccelMode? no + 2 SampleTime no + 10 AccelYPR no - Tag Name Writable - -------- -------- - Accelerometer no - CTMD Canon CTMD - CameraDateTime no - FrameNumber no - GPSAltitude no - GPSDOP no - GPSDateTime no - GPSLatitude no - GPSLongitude no - GPSSatellites no - GPSSpeed no - GPSSpeedRef no - GPSTimeStamp no - GPSTrack no - GPSTrackRef no - JpgFromRaw no - RVMI_gReV QuickTime RVMI_gReV - RVMI_sReV QuickTime RVMI_sReV - RawGSensor no - SampleDuration no - SampleTime no - Text no - TimeCode no - UserLabel no - camm0 QuickTime camm0 - camm1 QuickTime camm1 - camm2 QuickTime camm2 - camm3 QuickTime camm3 - camm4 QuickTime camm4 - camm5 QuickTime camm5 - camm6 QuickTime camm6 - camm7 QuickTime camm7 - fdsc GoPro fdsc - gpmd GoPro GPMF - mebx QuickTime Keys - rtmd Sony rtmd - tx3g QuickTime tx3g +=head3 QuickTime Gyro360Fly Tags -=head3 QuickTime RVMI_gReV Tags + Index1 Tag Name Writable + ------ -------- -------- + 1 GyroMode? no + 2 SampleTime no + 10 GyroYPR no -GPS information extracted from the RVMI box of MOV videos. +=head3 QuickTime Mag360Fly Tags Index1 Tag Name Writable ------ -------- -------- - 4 GPSLatitude no - 8 GPSLongitude no - 16 GPSSpeed no - 18 GPSTrack no - -=head3 QuickTime RVMI_sReV Tags + 1 MagMode? no + 2 SampleTime no + 10 MagnetometerXYZ no -G-sensor information extracted from the RVMI box of MOV videos. +=head3 QuickTime GPS360Fly Tags Index1 Tag Name Writable ------ -------- -------- - 4 GSensor no - -=head3 QuickTime camm0 Tags + 1 GPSMode? no + 2 SampleTime no + 10 GPSLatitude no + 14 GPSLongitude no + 18 GPSAltitude no + 22 GPSSpeed no + 24 GPSTrack no + 26 Acceleration no -The camm0 through camm7 tables define tags extracted from the Google Street -View Camera Motion Metadata of MP4 videos. See -L<https://developers.google.com/streetview/publish/camm-spec> for the -specification. +=head3 QuickTime Rot360Fly Tags Index1 Tag Name Writable ------ -------- -------- - 4 AngleAxis no + 1 RotMode? no + 2 SampleTime no + 10 RotationXYZ no -=head3 QuickTime camm1 Tags +=head3 QuickTime Fusion360Fly Tags Index1 Tag Name Writable ------ -------- -------- - 4 PixelExposureTime no - 8 RollingShutterSkewTime no + 1 FusionMode? no + 2 SampleTime no + 10 FusionYPR no -=head3 QuickTime camm2 Tags +=head3 QuickTime ImageFile Tags - Index1 Tag Name Writable +Tags used in QTIF QuickTime Image Files. + + Tag ID Tag Name Writable ------ -------- -------- - 4 AngularVelocity no + 'idat' ImageData no + 'idsc' ImageDescription QuickTime ImageDesc + 'iicc' ICC_Profile ICC_Profile -=head3 QuickTime camm3 Tags +=head2 Parrot Tags + +=head3 Parrot mett Tags + +Streaming metadata found in Parrot drone videos. See +L<https://developer.parrot.com/docs/pdraw/metadata.html> for the +specification. + + Tag ID Tag Name Writable + ------ -------- -------- + 'P1' ParrotV1 Parrot V1 + 'P2' ParrotV2 Parrot V2 + 'P3' ParrotV3 Parrot V3 + 'E1' ParrotTimeStamp Parrot TimeStamp + 'E2' ParrotFollowMe Parrot FollowMe + 'E3' ParrotAutomation Parrot Automation + 'application/arcore-accel' ARCoreAccel Parrot ARCoreAccel + 'application/arcore-custom-event' + ARCoreCustom Parrot ARCoreCustom + 'application/arcore-gyro' ARCoreGyro Parrot ARCoreGyro + 'application/arcore-video-0' ARCoreVideo Parrot ARCoreVideo + +=head3 Parrot V1 Tags + +Parrot version 1 streaming metadata. + + Index1 Tag Name Writable + ------ -------- -------- + 4 DroneYaw no + 6 DronePitch no + 8 DroneRoll no + 10 CameraPan no + 12 CameraTilt no + 14 FrameView no + 22 ExposureTime no + 24 ISO no + 26 WifiRSSI no + 27 Battery no + 28 GPSLatitude no + 32 GPSLongitude no + 36 GPSAltitude no + 36.1 GPSSatellites no + 40 AltitudeFromTakeOff no + 44 DistanceFromHome no + 48 SpeedX no + 50 SpeedY no + 52 SpeedZ no + 54 Binning no + 54.1 FlyingState no + 55 Animation no + 55.1 PilotingMode no + +=head3 Parrot V2 Tags + +Parrot version 2 basic streaming metadata. + + Index1 Tag Name Writable + ------ -------- -------- + 4 Elevation no + 8 GPSLatitude no + 12 GPSLongitude no + 16 GPSAltitude no + 16.1 GPSSatellites no + 20 GPSVelocityNorth no + 22 GPSVelocityEast no + 24 GPSVelocityDown no + 26 AirSpeed no + 28 DroneQuaternion no + 36 FrameView no + 44 CameraPan no + 46 CameraTilt no + 48 ExposureTime no + 50 ISO no + 52 Binning no + 52.1 FlyingState no + 53 Animation no + 53.1 PilotingMode no + 54 WifiRSSI no + 55 Battery no + 'Groups' Groups no + +=head3 Parrot V3 Tags + +Parrot version 3 basic streaming metadata. + + Index1 Tag Name Writable + ------ -------- -------- + 4 Elevation no + 8 GPSLatitude no + 12 GPSLongitude no + 16 GPSAltitude no + 16.1 GPSSatellites no + 20 GPSVelocityNorth no + 22 GPSVelocityEast no + 24 GPSVelocityDown no + 26 AirSpeed no + 28 DroneQuaternion no + 36 FrameBaseView no + 44 FrameView no + 52 ExposureTime no + 54 ISO no + 56 RedBalance no + 58 BlueBalance no + 60 FOV no + 64 LinkGoodput no + 64.1 LinkQuality no + 68 WifiRSSI no + 69 Battery no + 70 Binning no + 70.1 FlyingState no + 71 Animation no + 71.1 PilotingMode no + +=head3 Parrot TimeStamp Tags + +Parrot streaming metadata timestamp extension. Index1 Tag Name Writable ------ -------- -------- - 4 Acceleration no + 4 TimeStamp no -=head3 QuickTime camm4 Tags +=head3 Parrot FollowMe Tags + +Parrot streaming metadata follow-me extension. Index1 Tag Name Writable ------ -------- -------- - 4 Position no + 4 GPSTargetLatitude no + 8 GPSTargetLongitude no + 12 GPSTargetAltitude no + 16 Follow-meMode no + 17 Follow-meAnimation no -=head3 QuickTime camm5 Tags +=head3 Parrot Automation Tags + +Parrot streaming metadata automation extension. Index1 Tag Name Writable ------ -------- -------- - 4 GPSLatitude no - 12 GPSLongitude no - 20 GPSAltitude no + 4 GPSFramingLatitude no + 8 GPSFramingLongitude no + 12 GPSFramingAltitude no + 16 GPSDestLatitude no + 20 GPSDestLongitude no + 24 GPSDestAltitude no + 28 AutomationAnimation no + 29 AutomationFlags no -=head3 QuickTime camm6 Tags +=head3 Parrot ARCoreAccel Tags + +ARCore accelerometer data. Index1 Tag Name Writable ------ -------- -------- - 4 GPSDateTime no - 12 GPSMeasureMode no - 16 GPSLatitude no - 24 GPSLongitude no - 32 GPSAltitude no - 36 GPSHorizontalAccuracy no - 40 GPSVerticalAccuracy no - 44 GPSVelocityEast no - 48 GPSVelocityNorth no - 52 GPSVelocityUp no - 56 GPSSpeedAccuracy no + 4 AccelerometerUnknown? no + 5 Accelerometer no -=head3 QuickTime camm7 Tags +=head3 Parrot ARCoreCustom Tags Index1 Tag Name Writable ------ -------- -------- - 4 MagneticField no - -=head3 QuickTime tx3g Tags + [no tags known] -Tags extracted from the tx3g sbtl timed metadata of Yuneec drones. +=head3 Parrot ARCoreGyro Tags - Tag ID Tag Name Writable - ------ -------- -------- - 'Alt' GPSAltitude no - 'GimPitch' GimbalPitch no - 'GimRoll' GimbalRoll no - 'GimYaw' GimbalYaw no - 'Lat' GPSLatitude no - 'Lon' GPSLongitude no - 'Pitch' Pitch no - 'Roll' Roll no - 'Yaw' Yaw no +ARCore accelerometer data. -=head2 PLIST Tags + Index1 Tag Name Writable + ------ -------- -------- + 4 GyroscopeUnknown? no + 5 Gyroscope no -Apple Property List tags. ExifTool reads both XML and binary-format PLIST -files, and will extract any existing tags even if they aren't listed below. -These tags belong to the family 0 "PLIST" group, but family 1 group may be -either "XML" or "PLIST" depending on whether the format is XML or binary. +=head3 Parrot ARCoreVideo Tags - Tag ID Tag Name Writable - ------ -------- -------- - 'MetaDataList//DateTimeOriginal' - DateTimeOriginal no - 'MetaDataList//Duration' Duration no - 'MetaDataList//Geolocation/Latitude' - GPSLatitude no - 'MetaDataList//Geolocation/Longitude' - GPSLongitude no - 'MetaDataList//Geolocation/MapDatum' - GPSMapDatum no - 'XMLFileType' XMLFileType no - 'cast//name' Cast no+ - 'codirectors//name' Codirectors no+ - 'directors//name' Directors no+ - 'producers//name' Producers no+ - 'screenwriters//name' Screenwriters no+ - 'studio//name' Studio no+ + Index1 Tag Name Writable + ------ -------- -------- + [no tags known] =head2 Matroska Tags The following tags are extracted from Matroska multimedia container files. This container format is used by file types such as MKA, MKV, MKS and WEBM. -For speed, ExifTool extracts tags only up to the first Cluster unless the -Verbose (-v) or Unknown = 2 (-U) option is used. See +For speed, by default ExifTool extracts tags only up to the first Cluster. +However, the Verbose (-v) and Unknown = 2 (-U) options force processing of +Cluster data, and the ExtractEmbedded (-ee) option skips over Clusters to +read subsequent tags. See L<http://www.matroska.org/technical/specs/index.html> for the official Matroska specification. @@ -25215,6 +29685,7 @@ Matroska specification. 0x3eb5 Signature? no 0x7670 Projection Matroska Projection 0x2b59c TrackLanguage no + 0x2b59d TrackLanguageIETF no 0x3314f TrackTimecodeScale no 0x383e3 FrameRate no 0x3e383 VideoFrameRate no @@ -25255,9 +29726,10 @@ for the specification. 0x7671 ProjectionType no 0x7672 EquirectangularProj QuickTime equi CubemapProj QuickTime cbmp - 0x7673 ProjectionPosYaw no - 0x7674 ProjectionPosPitch no - 0x7675 ProjectionPosRoll no + ProjectionPrivate no + 0x7673 ProjectionPoseYaw no + 0x7674 ProjectionPosePitch no + 0x7675 ProjectionPoseRoll no =head2 MOI Tags @@ -26891,7 +31363,7 @@ because they are bulky 16-byte binary values. VideoAndFilmFrameRelationship no VideoAverageBitrate no VideoClipDuration no - VideoCodingSchemeID? no + VideoCodingSchemeID no VideoColorKind no VideoCompressionAlgorithm no VideoDeviceKind no @@ -27380,6 +31852,7 @@ sub-documents, but the Duration is calculated for the full video. 'ANMF' ANMF RIFF ANMF 'CSET' CharacterSet RIFF CSET 'EXIF' EXIF EXIF + UnknownEXIF no 'ICCP' ICC_Profile ICC_Profile 'IDIT' DateTimeOriginal no 'JUNK' OlympusJunk Olympus AVI @@ -27387,10 +31860,13 @@ sub-documents, but the Duration is calculated for the full video. RicohJunk Ricoh AVI PentaxJunk Pentax Junk PentaxJunk2 Pentax Junk2 + LucasJunk QuickTime Stream TextJunk no 'JUNQ' OldXMP no + 'LIST_INF0' Info RIFF Info 'LIST_INFO' Info RIFF Info 'LIST_Tdat' Tdat RIFF Tdat + 'LIST_adtl' AssociatedDataList RIFF 'LIST_exif' Exif RIFF Exif 'LIST_hdrl' Hdrl RIFF Hdrl 'LIST_hydt' PentaxData Pentax AVI @@ -27403,15 +31879,27 @@ sub-documents, but the Duration is calculated for the full video. 'VP8X' VP8X RIFF VP8X 'XMP ' XMP XMP '_PMX' XMP XMP + 'aXML' AXML XMP XML 'afsp' Afsp no 'bext' BroadcastExtension RIFF BroadcastExt 'cue ' CuePoints no 'ds64' DataSize64 RIFF DS64 'fact' NumberOfSamples no 'fmt ' AudioFormat RIFF AudioFormat - 'labl' Label RIFF Label + 'gps0' GPSTrack QuickTime Stream + 'gsen' GSensor QuickTime Stream + 'iXML' IXML XMP XML + 'id3 ' ID3 ID3 + 'inst' Instrument RIFF Instrument + 'labl' CuePointLabel no 'list' ListType no + 'ltxt' LabeledText no + 'note' CuePointNote no 'olym' Olym Olympus WAV + 'plst' Playlist no + 'smpl' Sampler RIFF Sampler + 'tx_USER' UserText RIFF UserText + 'tx_Unknown' Text no =head3 RIFF ALPH Tags @@ -27442,12 +31930,12 @@ WebP animation frame chunk. =head3 RIFF CSET Tags - Tag ID Tag Name Writable + Index2 Tag Name Writable ------ -------- -------- - 0x0000 CodePage no - 0x0001 CountryCode no - 0x0002 LanguageCode no - 0x0003 Dialect no + 0 CodePage no + 1 CountryCode no + 2 LanguageCode no + 3 Dialect no =head3 RIFF Info Tags @@ -27523,6 +32011,7 @@ by some software. 'ISTD' ProductionStudio no 'ISTR' Starring no 'ITCH' Technician no + 'ITRK' TrackNumber no 'IWMU' WatermarkURL no 'IWRI' WrittenBy no 'LANG' Language no @@ -27692,6 +32181,7 @@ L<http://tech.ebu.ch/docs/tech/tech3285.pdf>). 320 DateTimeOriginal no 338 TimeReference no 346 BWFVersion no + 348 BWF_UMID no 602 CodingHistory no =head3 RIFF DS64 Tags @@ -27705,12 +32195,46 @@ L<https://tech.ebu.ch/docs/tech/tech3306-2009.pdf> for the specification. 1 DataSize64 no 2 NumberOfSamples64 no -=head3 RIFF Label Tags +=head3 RIFF Instrument Tags + + Index1 Tag Name Writable + ------ -------- -------- + 0 UnshiftedNote no + 1 FineTune no + 2 Gain no + 3 LowNote no + 4 HighNote no + 5 LowVelocity no + 6 HighVelocity no + +=head3 RIFF Sampler Tags Index4 Tag Name Writable ------ -------- -------- - 0 LabelID no - 1 LabelText no + 0 Manufacturer no + 1 Product no + 2 SamplePeriod no + 3 MIDIUnityNote no + 4 MIDIPitchFraction no + 5 SMPTEFormat no + 6 SMPTEOffset no + 7 NumSampleLoops no + 8 SamplerDataLen no + 9 SamplerData no + +=head3 RIFF UserText Tags + +Tags decoded from the USER-format txts stream written by Momento M6 dashcam. +Extracted only if the ExtractEmbedded option is used. + + Index1 Tag Name Writable + ------ -------- -------- + 28 GPSAltitude no + 40 Accelerometer no + 56 GPSSpeed no + 60 GPSLatitude no + 64 GPSLongitude no + 68 GPSDateTime no =head2 AIFF Tags @@ -27722,6 +32246,7 @@ the AIFF specification. ------ -------- -------- '(c) ' Copyright no 'ANNO' Annotation no + 'APPL' ApplicationData no 'AUTH' Author no 'COMM' Common AIFF Common 'COMT' Comment AIFF Comment @@ -31290,14 +35815,28 @@ L<XMP DICOM Tags|Image::ExifTool::TagNames/XMP DICOM Tags>. FFFE,E00D EndOfItems no FFFE,E0DD EndOfSequence no -=head2 JSON Tags +=head2 FITS Tags -No JSON tags have been pre-defined, but ExifTool will read any existing -tags from basic JSON-formatted files. +This table lists some standard Flexible Image Transport System (FITS) tags, +but ExifTool will extract any other tags found. See +L<https://fits.gsfc.nasa.gov/fits_standard.html> for the specification. - Tag ID Tag Name Writable - ------ -------- -------- - [no tags known] + Tag ID Tag Name Writable + ------ -------- -------- + 'AUTHOR' Author no + 'BACKGRND' Background no + 'COMMENT' Comment no + 'DATE' CreateDate no + 'DATE-END' ObservationDateEnd no + 'DATE-OBS' ObservationDate no + 'HISTORY' History no + 'INSTRUME' Instrument no + 'OBJECT' Object no + 'OBSERVER' Observer no + 'REFERENC' Reference no + 'TELESCOP' Telescope no + 'TIME-END' ObservationTimeEnd no + 'TIME-OBS' ObservationTime no =head2 HTML Tags @@ -32070,15 +36609,38 @@ name. See L<http://tools.ietf.org/html/rfc5545> for the official iCalendar 'X-wr-relcalid' CalendarID no 'X-wr-timezone' TimeZone2 no +=head2 Text Tags + +Although basic text files contain no metadata, the following tags are +determined from a simple analysis of the data in TXT and CSV files. +Statistics are generated only for 8-bit encodings, but the FastScan (-fast) +option may be used to limit processing to the first 64 kB in which case some +tags are not produced. To avoid long processing delays, ExifTool will issue +a minor warning and process only the first 64 kB of any file larger than 20 +MB unless the IgnoreMinorErrors (-m) +option is used. + + Tag Name Writable + -------- -------- + ByteOrderMark no + ColumnCount no + Delimiter no + LineCount no + MIMEEncoding no + Newlines no + Quoting no + RowCount no + WordCount no + =head2 RSRC Tags -Tags extracted from Mac OS resource files and DFONT files. These tags may -also be extracted from the resource fork of any file in OS X, either by -adding "/..namedfork/rsrc" to the filename to process the resource fork -alone, or by using the ExtractEmbedded (-ee) option to process the resource -fork as a sub-document of the main file. When writing, ExifTool preserves -the Mac OS resource fork by default, but it may deleted with C<-rsrc:all=> -on the command line. +Tags extracted from Mac OS resource files, DFONT files and "._" sidecar +files. These tags may also be extracted from the resource fork of any file +in OS X, either by adding "/..namedfork/rsrc" to the filename to process the +resource fork alone, or by using the ExtractEmbedded (-ee) option to process +the resource fork as a sub-document of the main file. When writing, +ExifTool preserves the Mac OS resource fork by default, but it may deleted +with C<-rsrc:all=> on the command line. Tag ID Tag Name Writable ------ -------- -------- @@ -32127,6 +36689,7 @@ document number (ie. the exiftool C<-g3> option). 9 ZipCompressedSize no 11 ZipUncompressedSize no 15 ZipFileName no + '_com' ZipFileComment no =head3 ZIP GZIP Tags @@ -32328,10 +36891,10 @@ Tags extracted from ISO 9660 disk images. =head2 MacOS Tags -On MacOS systems, there are a number of additional tags with names beginning -with "MDItem" and "XAttr" that may be extracted. These tags are not -extracted by default -- they must be specifically requested or enabled via -an API option. +On MacOS systems, the there are additional MDItem and XAttr Finder tags that +may be extracted. These tags are not extracted by default -- they must be +specifically requested or enabled via an API option. (Except when reading +MacOS "._" files directly, see below.) The tables below list some of the tags that may be extracted, but ExifTool will extract all available information even for tags not listed. @@ -32340,17 +36903,53 @@ Tags in these tables are referred to as "pseudo" tags because their information is not stored in the file itself. As such, B<Writable> tags in these tables may be changed without having to rewrite the file. +Note that on some filesystems, MacOS creates sidecar files with names that +begin with "._". ExifTool will read these files if specified, and extract +the information listed in the following table without the need for extra +options, but these files are not writable directly. + + Tag ID Tag Name Writable + ------ -------- -------- + 0x0002 RSRC RSRC + 0x0009 ATTR MacOS XAttr + +=head3 MacOS XAttr Tags + +XAttr tags are extracted using the "xattr" utility. They are extracted if +any "XAttr*" tag or the MacOS group is specifically requested, or by setting +the API XAttrTags option to 1 or the API RequestAll option to 2 or higher. +And they are extracted by default from MacOS "._" files when reading +these files directly. + + Tag Name Writable + -------- -------- + XAttrAppleMailDateReceived no + XAttrAppleMailDateSent no + XAttrAppleMailIsRemoteAttachment no + XAttrFinderInfo no + XAttrLastUsedDate no + XAttrMDItemDownloadedDate no + XAttrMDItemFinderComment no + XAttrMDItemWhereFroms no + XAttrMDLabel no + XAttrQuarantine yes! + XAttrResourceFork no + =head3 MacOS MDItem Tags MDItem tags are extracted using the "mdls" utility. They are extracted if any "MDItem*" tag or the MacOS group is specifically requested, or by -setting the MDItemTags API option to 1 or the RequestAll API option to 2 or -higher. +setting the API MDItemTags option to 1 or the API RequestAll option to 2 or +higher. Note that these tags do not necessarily reflect the current +metadata of a file -- it may take some time for the MacOS mdworker daemon to +index the file after a metadata change. Tag Name Writable -------- -------- AppleMailDateReceived no + AppleMailDateSent no AppleMailFlagged no + AppleMailIsRemoteAttachment no AppleMailMessageID no AppleMailPriority no AppleMailRead no @@ -32361,14 +36960,18 @@ higher. MDItemAcquisitionModel no MDItemAltitude no MDItemAperture no + MDItemAudioBitRate no + MDItemAudioChannelCount no MDItemAuthorEmailAddresses no MDItemAuthors no MDItemBitsPerSample no MDItemBundleIdentifier no MDItemCity no + MDItemCodecs no MDItemColorSpace no MDItemComment no MDItemContentCreationDate no + MDItemContentCreationDateRanking no MDItemContentCreationDate_Ranking no MDItemContentModificationDate no MDItemContentType no @@ -32382,6 +36985,7 @@ higher. MDItemDescription no MDItemDisplayName no MDItemDownloadedDate no + MDItemDurationSeconds no MDItemEXIFGPSVersion no MDItemEXIFVersion no MDItemEmailConversationID no @@ -32415,6 +37019,7 @@ higher. MDItemISOSpeed no MDItemIdentifier no MDItemImageDirection no + MDItemInterestingDateRanking no MDItemInterestingDate_Ranking no MDItemIsApplicationManaged no MDItemIsExistingThread no @@ -32422,11 +37027,14 @@ higher. MDItemKeywords no MDItemKind no MDItemLastUsedDate no + MDItemLastUsedDate_Ranking no MDItemLatitude no + MDItemLensModel no MDItemLogicalSize no MDItemLongitude no MDItemMailDateReceived_Ranking no MDItemMailboxes no + MDItemMediaTypes no MDItemNumberOfPages no MDItemOrientation no MDItemOriginApplicationIdentifier no @@ -32449,32 +37057,27 @@ higher. MDItemSecurityMethod no MDItemSpeed no MDItemStateOrProvince no + MDItemStreamable no MDItemSubject no MDItemTimestamp no MDItemTitle no + MDItemTotalBitRate no MDItemUseCount no MDItemUsedDates no + MDItemUserDownloadedDate no + MDItemUserDownloadedUserHandle no + MDItemUserSharedReceivedDate no + MDItemUserSharedReceivedRecipient no + MDItemUserSharedReceivedRecipientHandle no + MDItemUserSharedReceivedSender no + MDItemUserSharedReceivedSenderHandle no + MDItemUserSharedReceivedTransport no MDItemUserTags yes!+ MDItemVersion no + MDItemVideoBitRate no MDItemWhereFroms no MDItemWhiteBalance no -=head3 MacOS XAttr Tags - -XAttr tags are extracted using the "xattr" utility. They are extracted if -any "XAttr*" tag or the MacOS group is specifically requested, or by setting -the XAttrTags API option to 1 or the RequestAll API option to 2 or higher. - - Tag Name Writable - -------- -------- - XAttrFinderInfo no - XAttrMDItemDownloadedDate no - XAttrMDItemFinderComment no - XAttrMDItemWhereFroms no - XAttrMDLabel no - XAttrQuarantine yes! - XAttrResourceFork no - =head2 Extra Tags The extra tags provide extra features or extra information extracted or @@ -32492,12 +37095,14 @@ FileName. Tag Name Group Writable -------- ----- -------- Adobe Adobe yes! - CanonDR4 CanonVRD yes! - CanonVRD CanonVRD yes! + BaseName System no + CanonDR4 CanonVRD yes!^ + CanonVRD CanonVRD yes!^ Comment File yes CurrentIPTCDigest File no Directory System yes! EXIF EXIF yes! + EmbeddedVideo File no Error ExifTool no ExifByteOrder File yes ExifToolVersion ExifTool no @@ -32533,12 +37138,14 @@ FileName. ImageHeight File no ImageWidth File no JPEGDigest File no + JPEGImageLength File no JPEGQualityEstimate File no MIMEType File no MaxVal File no NewGUID ExifTool no Now ExifTool no OtherImage File no + PageCount File no PreviewImage File yes PreviewPDF File no PreviewPNG File no @@ -32547,13 +37154,17 @@ FileName. ProcessingTime ExifTool no RAFVersion File no ResourceForkSize System no + SymLink - yes! TestName - yes! ThumbnailImage File no + Trailer File yes! Validate ExifTool no Warning ExifTool no + XML XML no XMP XMP yes! XResolution File no YResolution File no + ZoneIdentifier System yes! =head2 Composite Tags @@ -32577,7 +37188,7 @@ values, may created via the ExifTool configuration file. MPEG:VBRFrames AutoFocus Nikon:PhaseDetectAF no Nikon:ContrastDetectAF - AvgBitrate QuickTime::MovieDataSize no + AvgBitrate QuickTime::MediaDataSize no QuickTime::Duration BlueBalance WB_RGGBLevels no WB_RGBGLevels @@ -32627,14 +37238,14 @@ values, may created via the ExifTool configuration file. Canon:DigitalZoom DriveMode ContinuousDrive no SelfTimer - Duration FLAC:SampleRate no - FLAC:TotalSamples - Duration Vorbis:NominalBitrate no - FileSize + Duration AIFF:SampleRate no + AIFF:NumSampleFrames Duration APE:SampleRate no APE:TotalFrames APE:BlocksPerFrame APE:FinalFrameBlocks + Duration FLAC:SampleRate no + FLAC:TotalSamples Duration FileSize no ID3Size MPEG:AudioBitrate @@ -32650,8 +37261,8 @@ values, may created via the ExifTool configuration file. FileSize FrameCount VideoFrameCount - Duration AIFF:SampleRate no - AIFF:NumSampleFrames + Duration Vorbis:NominalBitrate no + FileSize ExtenderStatus Olympus:Extender no Olympus:LensType MaxApertureValue @@ -32683,23 +37294,32 @@ values, may created via the ExifTool configuration file. GPSAltitudeRef QuickTime:LocationInformation no GPSDateTime GPS:GPSDateStamp no GPS:GPSTimeStamp + GPSDateTime Parrot:GPSLatitude no + Main:CreateDate + SampleTime + GPSDateTime Sony:GPSDateStamp no + Sony:GPSTimeStamp GPSDestLatitude GPS:GPSDestLatitude no GPS:GPSDestLatitudeRef - GPSDestLatitudeRef XMP:GPSDestLatitude no + GPSDestLatitudeRef XMP-exif:GPSDestLatitude no GPSDestLongitude GPS:GPSDestLongitude no GPS:GPSDestLongitudeRef - GPSDestLongitudeRef XMP:GPSDestLongitude no - GPSLatitude GPS:GPSLatitude no + GPSDestLongitudeRef XMP-exif:GPSDestLongitude no + GPSLatitude GPS:GPSLatitude yes/ GPS:GPSLatitudeRef GPSLatitude QuickTime:GPSCoordinates no GPSLatitude QuickTime:LocationInformation no - GPSLatitudeRef XMP:GPSLatitude no - GPSLongitude GPS:GPSLongitude no + GPSLatitude Sony:GPSLatitude no + Sony:GPSLatitudeRef + GPSLatitudeRef XMP-exif:GPSLatitude no + GPSLongitude GPS:GPSLongitude yes/ GPS:GPSLongitudeRef GPSLongitude QuickTime:GPSCoordinates no GPSLongitude QuickTime:LocationInformation no - GPSLongitudeRef XMP:GPSLongitude no - GPSPosition GPSLatitude no + GPSLongitude Sony:GPSLongitude no + Sony:GPSLongitudeRef + GPSLongitudeRef XMP-exif:GPSLongitude no + GPSPosition GPSLatitude yes! GPSLongitude HyperfocalDistance FocalLength no Aperture @@ -32709,18 +37329,19 @@ values, may created via the ExifTool configuration file. ISO Canon:CameraISO no Canon:BaseISO Canon:AutoISO - ImageHeight Main:PostScript:ImageData no - PostScript:BoundingBox ImageHeight IFD0:SensorTopBorder no IFD0:SensorBottomBorder + ImageHeight Main:PostScript:ImageData no + PostScript:BoundingBox ImageSize ImageWidth no ImageHeight ExifImageWidth ExifImageHeight - ImageWidth Main:PostScript:ImageData no - PostScript:BoundingBox + RawImageCroppedSize ImageWidth IFD0:SensorLeftBorder no IFD0:SensorRightBorder + ImageWidth Main:PostScript:ImageData no + PostScript:BoundingBox JpgFromRaw JpgFromRawStart yes JpgFromRawLength Lens Canon:MinFocalLength no @@ -32739,13 +37360,13 @@ values, may created via the ExifTool configuration file. LensFocalRange LensSpec LensType2 + LensType3 LensFocalLength - LensID XMP-aux:LensID no + RFLensType + LensID LensModel no + Lens + XMP-aux:LensID Make - LensInfo - FocalLength - LensModel - MaxApertureValue LensID Nikon:LensIDNumber no LensFStops MinFocalLength @@ -32755,8 +37376,16 @@ values, may created via the ExifTool configuration file. MCUVersion Nikon:LensType LensID Ricoh:LensFirmware no + LensID XMP-aux:LensID no + Make + LensInfo + FocalLength + LensModel + MaxApertureValue LensSpec Nikon:Lens no Nikon:LensType + LensType LensTypeMake no + LensTypeModel LightValue Aperture no ShutterSpeed ISO @@ -32791,7 +37420,7 @@ values, may created via the ExifTool configuration file. FlashBits RicohPitch Ricoh:Accelerometer no RicohRoll Ricoh:Accelerometer no - Rotation QuickTime:MatrixStructure yes + Rotation QuickTime:MatrixStructure yes! QuickTime:HandlerType RunTimeSincePowerUp Apple:RunTimeValue no Apple:RunTimeScale @@ -32819,6 +37448,9 @@ values, may created via the ExifTool configuration file. ShutterSpeed ExposureTime no ShutterSpeedValue BulbDuration + SingleShotDepthMapTiff SingleShotDepthMap no + SegWidth + SegHeight SubSecCreateDate EXIF:CreateDate yes SubSecTimeDigitized OffsetTimeDigitized @@ -32981,6 +37613,7 @@ for more details. MakerNoteCasio MakerNoteCasio2 MakerNoteDJI + MakerNoteDJIInfo MakerNoteFLIR MakerNoteFujiFilm MakerNoteGE @@ -33021,6 +37654,7 @@ for more details. MakerNoteNintendo MakerNoteOlympus MakerNoteOlympus2 + MakerNoteOlympus3 MakerNoteLeica MakerNoteLeica2 MakerNoteLeica3 @@ -33030,6 +37664,7 @@ for more details. MakerNoteLeica7 MakerNoteLeica8 MakerNoteLeica9 + MakerNoteLeica10 MakerNotePanasonic MakerNotePanasonic2 MakerNotePanasonic3 @@ -33042,8 +37677,10 @@ for more details. MakerNotePhaseOne MakerNoteReconyx MakerNoteReconyx2 + MakerNoteReconyx3 MakerNoteRicoh MakerNoteRicoh2 + MakerNoteRicohPentax MakerNoteRicohText MakerNoteSamsung1a MakerNoteSamsung1b @@ -33099,6 +37736,13 @@ for more details. InteropIFD:InteropVersion InteropIFD:RelatedImageWidth InteropIFD:RelatedImageHeight + ls-l FilePermissions yes + FileHardLinks + FileUserID + FileGroupID + FileSize# + FileModifyDate + FileName =head2 MWG Tags @@ -33107,7 +37751,8 @@ overlapping EXIF, IPTC and XMP tags to be reconciled when reading, and synchronized when writing. The MWG Composite tags below are designed to aid in the implementation of these recommendations. As well, the MWG defines new XMP tags which are listed in the subsequent tables below. See -L<http://www.metadataworkinggroup.org/> for the official MWG specification. +L<https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf> +for the official MWG specification. =head3 MWG Composite Tags @@ -33217,7 +37862,8 @@ implements this policy and changes EXIF:Artist to a list-type tag. Image region metadata defined by the MWG 2.0 specification. These tags may be accessed without the need to load the MWG Composite tags above. See -L<http://www.metadataworkinggroup.org/> for the official specification. +L<https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf> +for the official specification. These tags belong to the ExifTool XMP-mwg-rs family 1 group. @@ -33285,8 +37931,9 @@ conversion). Hierarchical keywords metadata defined by the MWG 2.0 specification. ExifTool unrolls keyword structures to an arbitrary depth of 6 to allow individual levels to be accessed with different tag names, and to avoid -infinite recursion. See L<http://www.metadataworkinggroup.org/> for the -official specification. +infinite recursion. See +L<https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf> +for the official specification. These tags belong to the ExifTool XMP-mwg-kw family 1 group. @@ -33329,7 +37976,8 @@ These tags belong to the ExifTool XMP-mwg-kw family 1 group. =head3 MWG Collections Tags Collections metadata defined by the MWG 2.0 specification. See -L<http://www.metadataworkinggroup.org/> for the official specification. +L<https://web.archive.org/web/20180919181934/http://www.metadataworkinggroup.org/pdf/mwg_guidance.pdf> +for the official specification. These tags belong to the ExifTool XMP-mwg-coll family 1 group. @@ -33353,7 +38001,7 @@ L<Image::ExifTool::BuildTagLookup|Image::ExifTool::BuildTagLookup>. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Text.pm b/src/Image-ExifTool/lib/Image/ExifTool/Text.pm new file mode 100644 index 00000000..283cc964 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/Text.pm @@ -0,0 +1,245 @@ +#------------------------------------------------------------------------------ +# File: Text.pm +# +# Description: Deduce characteristics of TXT and CSV files +# +# Revisions: 2019-11-01 - P. Harvey Created +# 2020-02-13 - PH Added CSV file support +# +# References: 1) https://github.com/file/file +#------------------------------------------------------------------------------ + +package Image::ExifTool::Text; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); +use Image::ExifTool::XMP; + +$VERSION = '1.03'; + +# Text tags +%Image::ExifTool::Text::Main = ( + VARS => { NO_ID => 1 }, + GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Document' }, + NOTES => q{ + Although basic text files contain no metadata, the following tags are + determined from a simple analysis of the data in TXT and CSV files. + Statistics are generated only for 8-bit encodings, but the L<FastScan|../ExifTool.html#FastScan> (-fast) + option may be used to limit processing to the first 64 kB in which case some + tags are not produced. To avoid long processing delays, ExifTool will issue + a minor warning and process only the first 64 kB of any file larger than 20 + MB unless the L<IgnoreMinorErrors|../ExifTool.html#IgnoreMinorErrors> (-m) + option is used. + }, + MIMEEncoding => { Groups => { 2 => 'Other' } }, + Newlines => { + PrintConv => { + "\r\n" => 'Windows CRLF', + "\r" => 'Macintosh CR', + "\n" => 'Unix LF', + '' => '(none)', + }, + }, + ByteOrderMark => { PrintConv => { 0 => 'No', 1 => 'Yes' } }, + LineCount => { }, + WordCount => { }, + Delimiter => { PrintConv => { '' => '(none)', ',' => 'Comma', ';' => 'Semicolon', "\t" => 'Tab' }}, + Quoting => { PrintConv => { '' => '(none)', '"' => 'Double quotes', "'" => 'Single quotes' }}, + RowCount => { }, + ColumnCount => { }, +); + +#------------------------------------------------------------------------------ +# Extract some stats from a text file +# Inputs: 0) ExifTool ref, 1) dirInfo ref +# Returns: 1 on success, 0 if this wasn't a text file +sub ProcessTXT($$) +{ + my ($et, $dirInfo) = @_; + my $dataPt = $$dirInfo{TestBuff}; + my $raf = $$dirInfo{RAF}; + my $fast = $et->Options('FastScan') || 0; + my ($buff, $enc, $isBOM, $isUTF8); + my $nl = ''; + + return 0 unless length $$dataPt; # can't call it a text file if it has no text + + # read more from the file if necessary + if ($fast < 3 and length($$dataPt) == $Image::ExifTool::testLen) { + $raf->Read($buff, 65536) or return 0; + $dataPt = \$buff; + } +# +# make our best guess at the character encoding (EBCDIC is not supported) +# + if ($$dataPt =~ /([\0-\x06\x0e-\x1a\x1c-\x1f\x7f])/) { + # file contains weird control characters, could be multi-byte Unicode + if ($$dataPt =~ /^(\xff\xfe\0\0|\0\0\xfe\xff)/) { + if ($1 eq "\xff\xfe\0\0") { + $enc = 'utf-32le'; + $nl = $1 if $$dataPt =~ /(\r\0\0\0\n|\r|\n)\0\0\0/; + } else { + $enc = 'utf-32be'; + $nl = $1 if $$dataPt =~ /\0\0\0(\r\0\0\0\n|\r|\n)/; + } + } elsif ($$dataPt =~ /^(\xff\xfe|\xfe\xff)/) { + if ($1 eq "\xff\xfe") { + $enc = 'utf-16le'; + $nl = $1 if $$dataPt =~ /(\r\0\n|\r|\n)\0/; + } else { + $enc = 'utf-16be'; + $nl = $1 if $$dataPt =~ /\0(\r\0\n|\r|\n)/; + } + } else { + return 0; # probably not a text file + } + $nl =~ tr/\0//d; # remove nulls from newline sequence + $isBOM = 1; # (we don't recognize UTF-16/UTF-32 without one) + } else { + $isUTF8 = Image::ExifTool::XMP::IsUTF8($dataPt, 1); + if ($isUTF8 == 0) { + $enc = 'us-ascii'; + } elsif ($isUTF8 > 0) { + $enc = 'utf-8'; + $isBOM = ($$dataPt =~ /^\xef\xbb\xbf/ ? 1 : 0); + } elsif ($$dataPt !~ /[\x80-\x9f]/) { + $enc = 'iso-8859-1'; + } else { + $enc = 'unknown-8bit'; + } + $nl = $1 if $$dataPt =~ /(\r\n|\r|\n)/; + } + + my $tagTablePtr = GetTagTable('Image::ExifTool::Text::Main'); + + $et->SetFileType(); + $et->HandleTag($tagTablePtr, MIMEEncoding => $enc); + + return 1 if $fast == 3 or not $raf->Seek(0,0); + + $et->HandleTag($tagTablePtr, ByteOrderMark => $isBOM) if defined $isBOM; + $et->HandleTag($tagTablePtr, Newlines => $nl); + + return 1 if $fast or not defined $isUTF8; +# +# generate stats for CSV files +# + if ($$et{FileType} eq 'CSV') { + my ($delim, $quot, $ncols); + my $nrows = 0; + while ($raf->ReadLine($buff)) { + if (not defined $delim) { + my %count = ( ',' => 0, ';' => 0, "\t" => 0 ); + ++$count{$_} foreach $buff =~ /[,;\t]/g; + if ($count{','} > $count{';'} and $count{','} > $count{"\t"}) { + $delim = ','; + } elsif ($count{';'} > $count{"\t"}) { + $delim = ';'; + } elsif ($count{"\t"}) { + $delim = "\t"; + } else { + $delim = ''; + $ncols = 1; + } + unless ($ncols) { + # account for delimiters in quotes (simplistically) + while ($buff =~ /(^|$delim)(["'])(.*?)\2(?=$delim|$)/sg) { + $quot = $2; + my $field = $3; + $count{$delim} -= () = $field =~ /$delim/g; + } + $ncols = $count{$delim} + 1; + } + } elsif (not $quot) { + $quot = $2 if $buff =~ /(^|$delim)(["'])(.*?)\2(?=$delim|$)/sg; + } + if (++$nrows == 1000 and $et->Warn('Not counting rows past 1000', 2)) { + undef $nrows; + last; + } + } + $et->HandleTag($tagTablePtr, Delimiter => ($delim || '')); + $et->HandleTag($tagTablePtr, Quoting => ($quot || '')); + $et->HandleTag($tagTablePtr, ColumnCount => $ncols); + $et->HandleTag($tagTablePtr, RowCount => $nrows) if $nrows; + return 1; + } + return 1 if $$et{VALUE}{FileSize} and $$et{VALUE}{FileSize} > 20000000 and + $et->Warn('Not counting lines/words in text file larger than 20 MB', 2); +# +# count lines/words and check encoding of the rest of the file +# + my ($lines, $words) = (0, 0); + my $oldNL = $/; + $/ = $nl if $nl; + while ($raf->ReadLine($buff)) { + ++$lines; + ++$words while $buff =~ /\S+/g; + if (not $nl and $buff =~ /(\r\n|\r|\n)$/) { + # (the first line must have been longer than 64 kB) + $$et{VALUE}{Newlines} = $nl = $1; + } + next if $raf->Tell() < 65536; + # continue to check encoding after the first 64 kB + if ($isUTF8 >= 0) { # (if ascii or utf8) + $isUTF8 = Image::ExifTool::XMP::IsUTF8(\$buff); + if ($isUTF8 > 0) { + $enc = 'utf-8'; + } elsif ($isUTF8 < 0) { + $enc = $buff =~ /[\x80-\x9f]/ ? 'unknown-8bit' : 'iso-8859-1'; + } + } elsif ($enc eq 'iso-8859-1' and $buff =~ /[\x80-\x9f]/) { + $enc = 'unknown-8bit'; + } + } + if ($$et{VALUE}{MIMEEncoding} ne $enc) { + $$et{VALUE}{MIMEEncoding} = $enc; + $et->VPrint(0," MIMEEncoding [override] = $enc\n"); + } + $/ = $oldNL; + $et->HandleTag($tagTablePtr, LineCount => $lines); + $et->HandleTag($tagTablePtr, WordCount => $words); + return 1; +} + + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::Text - Read Text meta information + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to deduce some +characteristics of TXT and CSV files. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<https://github.com/file/file> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/Text Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Theora.pm b/src/Image-ExifTool/lib/Image/ExifTool/Theora.pm index 3936d26e..f80560dc 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Theora.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Theora.pm @@ -122,7 +122,7 @@ information from Theora video streams. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Torrent.pm b/src/Image-ExifTool/lib/Image/ExifTool/Torrent.pm index ea88a1ca..f79d89fc 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Torrent.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Torrent.pm @@ -13,10 +13,11 @@ package Image::ExifTool::Torrent; use strict; use vars qw($VERSION); use Image::ExifTool qw(:DataAccess :Utils); +use Image::ExifTool::XMP; -$VERSION = '1.03'; +$VERSION = '1.05'; -sub ReadBencode($$); +sub ReadBencode($$$); sub ExtractTags($$$;$$@); # tags extracted from BitTorrent files @@ -41,7 +42,10 @@ sub ExtractTags($$$;$$@); PrintConv => '$self->ConvertDateTime($val)', }, 'encoding' => { }, - 'info' => { SubDirectory => { TagTable => 'Image::ExifTool::Torrent::Info' } }, + 'info' => { + SubDirectory => { TagTable => 'Image::ExifTool::Torrent::Info' }, + Notes => 'extracted as a structure with the Struct option', + }, 'url-list' => { Name => 'URLList1' }, ); @@ -96,12 +100,12 @@ sub ReadMore($$) #------------------------------------------------------------------------------ # Read bencoded value -# Inputs: 0) input file, 1) buffer (pos must be set to current position) +# Inputs: 0) ExifTool ref, 1) input file, 2) buffer (pos must be set to current position) # Returns: HASH ref, ARRAY ref, SCALAR ref, SCALAR, or undef on error or end of data # Notes: Sets BencodeError element of RAF on any error -sub ReadBencode($$) +sub ReadBencode($$$) { - my ($raf, $dataPt) = @_; + my ($et, $raf, $dataPt) = @_; # read more if necessary (keep a minimum of 64 bytes in the buffer) my $pos = pos($$dataPt); @@ -120,21 +124,21 @@ sub ReadBencode($$) } elsif ($tok eq 'd') { # dictionary $val = { }; for (;;) { - my $k = ReadBencode($raf, $dataPt); + my $k = ReadBencode($et, $raf, $dataPt); last unless defined $k; # the key must be a byte string if (ref $k) { ref $k ne 'SCALAR' and $$raf{BencodeError} = 'Bad dictionary key', last; $k = $$k; } - my $v = ReadBencode($raf, $dataPt); + my $v = ReadBencode($et, $raf, $dataPt); last unless defined $v; $$val{$k} = $v; } } elsif ($tok eq 'l') { # list $val = [ ]; for (;;) { - my $v = ReadBencode($raf, $dataPt); + my $v = ReadBencode($et, $raf, $dataPt); last unless defined $v; push @$val, $v; } @@ -162,8 +166,14 @@ sub ReadBencode($$) } if (defined $value) { # return as binary data unless it is a reasonable-length ASCII string - if (length($value) > 256 or $value =~ /[^\t\x20-\x7e]/) { + if (length($value) > 256) { $val = \$value; + } elsif ($value =~ /[^\t\x20-\x7e]/) { + if (Image::ExifTool::XMP::IsUTF8(\$value) >= 0) { + $val = $et->Decode($value, 'UTF8'); + } else { + $val = \$value; + } } else { $val = $value; } @@ -203,7 +213,7 @@ sub ExtractTags($$$;$$@) my $tagInfo = $et->GetTagInfo($tagTablePtr, $id) or next; if (ref $val eq 'ARRAY') { if ($$tagInfo{JoinPath}) { - $val = join '/', @$val; + $val = join '/', map { ref $_ ? '(Binary data)' : $_ } @$val; } else { push @more, @$val; next if ref $more[0] eq 'ARRAY'; # continue expanding nested lists @@ -232,6 +242,11 @@ sub ExtractTags($$$;$$@) $tagInfo = $et->GetTagInfo($tagTablePtr, $id) or next; } if (ref $val eq 'HASH') { + if ($et->Options('Struct') and $tagInfo and $$tagInfo{Name} eq 'Info') { + $et->FoundTag($tagInfo, $val); + ++$count; + next; + } # extract tags from this dictionary my ($table, $rootID, $rootName); if ($$tagInfo{SubDirectory}) { @@ -265,10 +280,10 @@ sub ProcessTorrent($$) my $raf = $$dirInfo{RAF}; my $buff = ''; pos($buff) = 0; - my $dict = ReadBencode($raf, \$buff); + my $dict = ReadBencode($et, $raf, \$buff); my $err = $$raf{BencodeError}; $et->Warn("Bencode error: $err") if $err; - if (ref $dict eq 'HASH' and $$dict{announce}) { + if (ref $dict eq 'HASH' and ($$dict{announce} or $$dict{'created by'})) { $et->SetFileType(); my $tagTablePtr = GetTagTable('Image::ExifTool::Torrent::Main'); ExtractTags($et, $dict, $tagTablePtr) and $success = 1; @@ -295,7 +310,7 @@ bencoded information from BitTorrent files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Unknown.pm b/src/Image-ExifTool/lib/Image/ExifTool/Unknown.pm index 0f47b7fd..51370b70 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Unknown.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Unknown.pm @@ -53,7 +53,7 @@ unknown manufacturers. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/VCard.pm b/src/Image-ExifTool/lib/Image/ExifTool/VCard.pm new file mode 100644 index 00000000..55b9bd73 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/VCard.pm @@ -0,0 +1,443 @@ +#------------------------------------------------------------------------------ +# File: VCard.pm +# +# Description: Read vCard and iCalendar meta information +# +# Revisions: 2015/04/05 - P. Harvey Created +# 2015/05/02 - PH Added iCalendar support +# +# References: 1) http://en.m.wikipedia.org/wiki/VCard +# 2) http://tools.ietf.org/html/rfc6350 +# 3) http://tools.ietf.org/html/rfc5545 +#------------------------------------------------------------------------------ + +package Image::ExifTool::VCard; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.06'; + +my %unescapeVCard = ( '\\'=>'\\', ','=>',', 'n'=>"\n", 'N'=>"\n" ); + +# lookup for iCalendar components (used to generate family 1 group names if top level) +my %isComponent = ( Event=>1, Todo=>1, Journal=>1, Freebusy=>1, Timezone=>1, Alarm=>1 ); + +my %timeInfo = ( + # convert common date/time formats to EXIF style + ValueConv => q{ + $val =~ s/(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(Z?)/$1:$2:$3 $4:$5:$6$7/g; + $val =~ s/(\d{4})(\d{2})(\d{2})/$1:$2:$3/g; + $val =~ s/(\d{4})-(\d{2})-(\d{2})/$1:$2:$3/g; + return $val; + }, + PrintConv => '$self->ConvertDateTime($val)', +); + +# vCard tags (ref 1/2/PH) +# Note: The case of all tag ID's is normalized to lowercase with uppercase first letter +%Image::ExifTool::VCard::Main = ( + GROUPS => { 2 => 'Document' }, + VARS => { NO_LOOKUP => 1 }, # omit tags from lookup + NOTES => q{ + This table lists common vCard tags, but ExifTool will also extract any other + vCard tags found. Tag names may have "Pref" added to indicate the preferred + instance of a vCard property, and other "TYPE" parameters may also added to + the tag name. VCF files may contain multiple vCard entries which are + distinguished by the ExifTool family 3 group name (document number). See + L<http://tools.ietf.org/html/rfc6350> for the vCard 4.0 specification. + }, + Version => { Name => 'VCardVersion', Description => 'VCard Version' }, + Fn => { Name => 'FormattedName', Groups => { 2 => 'Author' } }, + N => { Name => 'Name', Groups => { 2 => 'Author' } }, + Bday => { Name => 'Birthday', Groups => { 2 => 'Time' }, %timeInfo }, + Tz => { Name => 'TimeZone', Groups => { 2 => 'Time' } }, + Adr => { Name => 'Address', Groups => { 2 => 'Location' } }, + Geo => { + Name => 'Geolocation', + Groups => { 2 => 'Location' }, + # when used as a parameter, VCard 4.0 adds a "geo:" prefix that we need to remove + ValueConv => '$val =~ s/^geo://; $val', + }, + Anniversary => { }, + Email => { }, + Gender => { }, + Impp => 'IMPP', + Lang => 'Language', + Logo => { }, + Nickname => { }, + Note => { }, + Org => 'Organization', + Photo => { Groups => { 2 => 'Preview' } }, + Prodid => 'Software', + Rev => 'Revision', + Sound => { }, + Tel => 'Telephone', + Title => 'JobTitle', + Uid => 'UID', + Url => 'URL', + 'X-ablabel' => { Name => 'ABLabel', PrintConv => '$val =~ s/^_\$!<(.*)>!\$_$/$1/; $val' }, + 'X-abdate' => { Name => 'ABDate', Groups => { 2 => 'Time' }, %timeInfo }, + 'X-aim' => 'AIM', + 'X-icq' => 'ICQ', + 'X-abuid' => 'AB_UID', + 'X-abrelatednames' => 'ABRelatedNames', + 'X-socialprofile' => 'SocialProfile', +); + +%Image::ExifTool::VCard::VCalendar = ( + GROUPS => { 1 => 'VCalendar', 2 => 'Document' }, + VARS => { + NO_LOOKUP => 1, # omit tags from lookup + LONG_TAGS => 6, # some X-microsoft tags have unavoidably long ID's + }, + NOTES => q{ + The VCard module is also used to process iCalendar ICS files since they use + a format similar to vCard. The following table lists standard iCalendar + tags, but any existing tags will be extracted. Top-level iCalendar + components (eg. Event, Todo, Timezone, etc.) are used for the family 1 group + names, and embedded components (eg. Alarm) are added as a prefix to the tag + name. See L<http://tools.ietf.org/html/rfc5545> for the official iCalendar + 2.0 specification. + }, + Version => { Name => 'VCalendarVersion', Description => 'VCalendar Version' }, + Calscale => 'CalendarScale', + Method => { }, + Prodid => 'Software', + Attach => 'Attachment', + Categories => { }, + Class => 'Classification', + Comment => { }, + Description => { }, + Geo => { + Name => 'Geolocation', + Groups => { 2 => 'Location' }, + ValueConv => '$val =~ s/^geo://; $val', + }, + Location => { Name => 'Location', Groups => { 2 => 'Location' } }, + 'Percent-complete' => 'PercentComplete', + Priority => { }, + Resources => { }, + Status => { }, + Summary => { }, + Completed => { Name => 'DateTimeCompleted', Groups => { 2 => 'Time' }, %timeInfo }, + Dtend => { Name => 'DateTimeEnd', Groups => { 2 => 'Time' }, %timeInfo }, + Due => { Name => 'DateTimeDue', Groups => { 2 => 'Time' }, %timeInfo }, + Dtstart => { Name => 'DateTimeStart', Groups => { 2 => 'Time' }, %timeInfo }, + Duration => { }, + Freebusy => 'FreeBusyTime', + Transp => 'TimeTransparency', + Tzid => { Name => 'TimezoneID', Groups => { 2 => 'Time' } }, + Tzname => { Name => 'TimezoneName', Groups => { 2 => 'Time' } }, + Tzoffsetfrom=> { Name => 'TimezoneOffsetFrom', Groups => { 2 => 'Time' } }, + Tzoffsetto => { Name => 'TimezoneOffsetTo', Groups => { 2 => 'Time' } }, + Tzurl => { Name => 'TimeZoneURL', Groups => { 2 => 'Time' } }, + Attendee => { }, + Contact => { }, + Organizer => { }, + 'Recurrence-id' => 'RecurrenceID', + 'Related-to' => 'RelatedTo', + Url => 'URL', + Uid => 'UID', + Exdate => { Name => 'ExceptionDateTimes', Groups => { 2 => 'Time' }, %timeInfo }, + Rdate => { Name => 'RecurrenceDateTimes', Groups => { 2 => 'Time' }, %timeInfo }, + Rrule => { Name => 'RecurrenceRule', Groups => { 2 => 'Time' } }, + Action => { }, + Repeat => { }, + Trigger => { }, + Created => { Name => 'DateCreated', Groups => { 2 => 'Time' }, %timeInfo }, + Dtstamp => { Name => 'DateTimeStamp', Groups => { 2 => 'Time' }, %timeInfo }, + 'Last-modified' => { Name => 'ModifyDate', Groups => { 2 => 'Time' }, %timeInfo }, + Sequence => 'SequenceNumber', + 'Request-status' => 'RequestStatus', + Acknowledged=> { Name => 'Acknowledged', Groups => { 2 => 'Time' }, %timeInfo }, +# +# Observed X-tags (not a comprehensive list): +# + 'X-apple-calendar-color'=> 'CalendarColor', + 'X-apple-default-alarm' => 'DefaultAlarm', + 'X-apple-local-default-alarm' => 'LocalDefaultAlarm', + 'X-microsoft-cdo-appt-sequence' => 'AppointmentSequence', + 'X-microsoft-cdo-ownerapptid' => 'OwnerAppointmentID', + 'X-microsoft-cdo-busystatus' => 'BusyStatus', + 'X-microsoft-cdo-intendedstatus' => 'IntendedBusyStatus', + 'X-microsoft-cdo-alldayevent' => 'AllDayEvent', + 'X-microsoft-cdo-importance' => { + Name => 'Importance', + PrintConv => { + 0 => 'Low', + 1 => 'Normal', + 2 => 'High', + }, + }, + 'X-microsoft-cdo-insttype' => { + Name => 'InstanceType', + PrintConv => { + 0 => 'Non-recurring Appointment', + 1 => 'Recurring Appointment', + 2 => 'Single Instance of Recurring Appointment', + 3 => 'Exception to Recurring Appointment', + }, + }, + 'X-microsoft-donotforwardmeeting' => 'DoNotForwardMeeting', + 'X-microsoft-disallow-counter' => 'DisallowCounterProposal', + 'X-microsoft-locations' => { Name => 'MeetingLocations', Groups => { 2 => 'Location' } }, + 'X-wr-caldesc' => 'CalendarDescription', + 'X-wr-calname' => 'CalendarName', + 'X-wr-relcalid' => 'CalendarID', + 'X-wr-timezone' => { Name => 'TimeZone2', Groups => { 2 => 'Time' } }, + 'X-wr-alarmuid' => 'AlarmUID', +); + +#------------------------------------------------------------------------------ +# Get vCard tag, creating if necessary +# Inputs: 0) ExifTool ref, 1) tag table ref, 2) tag ID, 3) tag Name, +# 4) source tagInfo ref, 5) lang code +# Returns: tagInfo ref +sub GetVCardTag($$$$;$$) +{ + my ($et, $tagTablePtr, $tag, $name, $srcInfo, $langCode) = @_; + my $tagInfo = $$tagTablePtr{$tag}; + unless ($tagInfo) { + if ($srcInfo) { + $tagInfo = { %$srcInfo }; + } else { + $tagInfo = { }; + $et->VPrint(0, $$et{INDENT}, "[adding $tag]\n"); + } + $$tagInfo{Name} = $name; + delete $$tagInfo{Description}; # create new description + AddTagToTable($tagTablePtr, $tag, $tagInfo); + } + # handle alternate languages (the "language" parameter) + $tagInfo = Image::ExifTool::GetLangInfo($tagInfo, $langCode) if $langCode; + return $tagInfo; +} + +#------------------------------------------------------------------------------ +# Decode vCard text +# Inputs: 0) ExifTool ref, 1) vCard text, 2) encoding +# Returns: decoded text (or array ref for a list of values) +sub DecodeVCardText($$;$) +{ + my ($et, $val, $enc) = @_; + $enc = defined($enc) ? lc $enc : ''; + if ($enc eq 'b' or $enc eq 'base64') { + require Image::ExifTool::XMP; + $val = Image::ExifTool::XMP::DecodeBase64($val); + } else { + if ($enc eq 'quoted-printable') { + # convert "=HH" hex codes to characters + $val =~ s/=([0-9a-f]{2})/chr(hex($1))/ige; + } + $val = $et->Decode($val, 'UTF8'); # convert from UTF-8 + # convert unescaped commas to nulls to separate list items + $val =~ s/(\\.)|(,)/$1 || "\0"/sge; + # unescape necessary characters in value + $val =~ s/\\(.)/$unescapeVCard{$1}||$1/sge; + # split into list if necessary + my @vals = split /\0/, $val; + $val = \@vals if @vals > 1; + } + return $val; +} + +#------------------------------------------------------------------------------ +# Read information in a vCard file +# Inputs: 0) ExifTool ref, 1) dirInfo ref +# Returns: 1 on success, 0 if this wasn't a valid vCard file +sub ProcessVCard($$) +{ + local $_; + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my ($buff, $val, $ok, $component, %compNum, @count); + + return 0 unless $raf->Read($buff, 24) and $raf->Seek(0,0) and $buff=~/^BEGIN:(VCARD|VCALENDAR)\r\n/i; + my ($type, $lbl, $tbl, $ext) = uc($1) eq 'VCARD' ? qw(VCard vCard Main VCF) : qw(ICS iCalendar VCalendar ICS); + $et->SetFileType($type, undef, $ext); + return 1 if $$et{OPTIONS}{FastScan} and $$et{OPTIONS}{FastScan} == 3; + local $/ = "\r\n"; + my $tagTablePtr = GetTagTable("Image::ExifTool::VCard::$tbl"); + my $more = $raf->ReadLine($buff); # read first line + chomp $buff if $more; + while ($more) { + # retrieve previous line from $buff + $val = $buff if defined $buff; + # read ahead to next line to see if is a continuation + $more = $raf->ReadLine($buff); + if ($more) { + chomp $buff; + # add continuation line if necessary + $buff =~ s/^[ \t]// and $val .= $buff, undef($buff), next; + } + if ($val =~ /^(BEGIN|END):(V?)(\w+)$/i) { + my ($begin, $v, $what) = ((lc($1) eq 'begin' ? 1 : 0), $2, ucfirst lc $3); + if ($what eq 'Card' or $what eq 'Calendar') { + if ($begin) { + @count = ( { } ); # reset group counters + } else { + $ok = 1; # ok if we read at least on full VCARD or VCALENDAR + } + next; + } + # absorb top-level component into family 1 group name + if ($isComponent{$what}) { + if ($begin) { + unless ($component) { + # begin a new top-level component + @count = ( { } ); + $component = $what; + $compNum{$component} = ($compNum{$component} || 0) + 1; + next; + } + } elsif ($component and $component eq $what) { + # this top-level component has ended + undef $component; + next; + } + } + # keep count of each component at this level + if ($begin) { + $count[-1]{$what} = ($count[-1]{$what} || 0) + 1 if $v; + push @count, { obj => $what }; + } elsif (@count > 1) { + pop @count; + } + next; + } elsif ($ok) { + $ok = 0; + $$et{DOC_NUM} = ++$$et{DOC_COUNT}; # read next card as a new document + } + unless ($val =~ s/^([-A-Za-z0-9.]+)//) { + $et->WarnOnce("Unrecognized line in $lbl file"); + next; + } + my $tag = $1; + # set group if it exists + if ($tag =~ s/^([-A-Za-z0-9]+)\.//) { + $$et{SET_GROUP1} = ucfirst lc $1; + } elsif ($component) { + $$et{SET_GROUP1} = $component . $compNum{$component}; + } else { + delete $$et{SET_GROUP1}; + } + my ($name, %param, $p); + # vCard tag ID's are case-insensitive, so normalize to lowercase with + # an uppercase first letter for use as a tag name + $name = ucfirst $tag if $tag =~ /[a-z]/; # preserve mixed case in name if it exists + $tag = ucfirst lc $tag; + # get source tagInfo reference + my $srcInfo = $et->GetTagInfo($tagTablePtr, $tag); + if ($srcInfo) { + $name = $$srcInfo{Name}; # use our name + } else { + $name or $name = $tag; + # remove leading "X-" from name if it exists + $name =~ s/^X-// and $name = ucfirst $name; + } + # add object name(s) to tag if necessary + if (@count > 1) { + my $i; + for ($i=$#count-1; $i>=0; --$i) { + my $pre = $count[$i-1]{obj}; # use containing object name as tag prefix + my $c = $count[$i]{$pre}; # add index for object number + $c = '' unless defined $c; + $tag = $pre . $c . $tag; + $name = $pre . $c . $name; + } + } + # parse parameters + while ($val =~ s/^;([-A-Za-z0-9]*)(=?)//) { + $p = ucfirst lc $1; + # convert old vCard 2.x parameters to the new "TYPE=" format + $2 or $val = $1 . $val, $p = 'Type'; + # read parameter value + for (;;) { + last unless $val =~ s/^"([^"]*)",?// or $val =~ s/^([^";:,]+,?)//; + my $v = $p eq 'Type' ? ucfirst lc $1 : $1; + $param{$p} = defined($param{$p}) ? $param{$p} . $v : $v; + } + if (defined $param{$p}) { + $param{$p} =~ s/\\(.)/$unescapeVCard{$1}||$1/sge; + } else { + $param{$p} = ''; + } + } + $val =~ s/^:// or $et->WarnOnce("Invalid line in $lbl file"), next; + # add 'Type' parameter to id and name if it exists + $param{Type} and $tag .= $param{Type}, $name .= $param{Type}; + # convert base64-encoded data + if ($val =~ s{^data:(\w+)/(\w+);base64,}{}) { + my $xtra = ucfirst(lc $1) . ucfirst(lc $2); + $tag .= $xtra; + $name .= $xtra; + $param{Encoding} = 'base64'; + } + $val = DecodeVCardText($et, $val, $param{Encoding}); + my $tagInfo = GetVCardTag($et, $tagTablePtr, $tag, $name, $srcInfo, $param{Language}); + $et->HandleTag($tagTablePtr, $tag, $val, TagInfo => $tagInfo); + # handle some other parameters that we care about (ignore the rest for now) + foreach $p (qw(Geo Label Tzid)) { + next unless defined $param{$p}; + # use tag attributes from our table if it exists + my $srcTag2 = $et->GetTagInfo($tagTablePtr, $p); + my $pn = $srcTag2 ? $$srcTag2{Name} : $p; + $val = DecodeVCardText($et, $param{$p}); + # add parameter to tag ID and name + my ($tg, $nm) = ($tag . $p, $name . $pn); + $tagInfo = GetVCardTag($et, $tagTablePtr, $tg, $nm, $srcTag2, $param{Language}); + $et->HandleTag($tagTablePtr, $tg, $val, TagInfo => $tagInfo); + } + } + delete $$et{SET_GROUP1}; + delete $$et{DOC_NUM}; + $ok or $et->Warn("Missing $lbl end"); + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::VCard - Read vCard and iCalendar meta information + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to read meta +information from vCard VCF and iCalendar ICS files. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<http://en.m.wikipedia.org/wiki/VCard> + +=item L<http://tools.ietf.org/html/rfc6350> + +=item L<http://tools.ietf.org/html/rfc5545> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/VCard Tags>, +L<Image::ExifTool::TagNames/VCard VCalendar Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Validate.pm b/src/Image-ExifTool/lib/Image/ExifTool/Validate.pm new file mode 100644 index 00000000..9d81776f --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/Validate.pm @@ -0,0 +1,672 @@ +#------------------------------------------------------------------------------ +# File: Validate.pm +# +# Description: Additional metadata validation +# +# Created: 2017/01/18 - P. Harvey +# +# Notes: My apologies for the convoluted logic contained herein, but it +# is done this way to retro-fit the Validate feature into the +# existing ExifTool code while reducing the possibility of +# introducing bugs or slowing down processing when this feature +# is not used. +#------------------------------------------------------------------------------ + +package Image::ExifTool::Validate; + +use strict; +use vars qw($VERSION %exifSpec); + +$VERSION = '1.19'; + +use Image::ExifTool qw(:Utils); +use Image::ExifTool::Exif; + +# EXIF table tag ID's which are part of the EXIF 2.32 specification +# (with ExifVersion numbers for tags where I can determine the version) +# (also used by BuildTagLookup to add underlines in HTML version of EXIF Tag Table) +%exifSpec = ( + 0x1 => 210, + 0x100 => 1, 0x8298 => 1, 0x9207 => 1, 0xa217 => 1, + 0x101 => 1, 0x829a => 1, 0x9208 => 1, 0xa300 => 1, + 0x102 => 1, 0x829d => 1, 0x9209 => 1, 0xa301 => 1, + 0x103 => 1, 0x8769 => 1, 0x920a => 1, 0xa302 => 1, + 0x106 => 1, 0x8822 => 1, 0x9214 => 220, 0xa401 => 220, + 0x10e => 1, 0x8824 => 1, 0x927c => 1, 0xa402 => 220, + 0x10f => 1, 0x8825 => 200, 0x9286 => 1, 0xa403 => 220, + 0x110 => 1, 0x8827 => 1, 0x9290 => 1, 0xa404 => 220, + 0x111 => 1, 0x8828 => 1, 0x9291 => 1, 0xa405 => 220, + 0x112 => 1, 0x8830 => 230, 0x9292 => 1, 0xa406 => 220, + 0x115 => 1, 0x8831 => 230, 0x9400 => 231, 0xa407 => 220, + 0x116 => 1, 0x8832 => 230, 0x9401 => 231, 0xa408 => 220, + 0x117 => 1, 0x8833 => 230, 0x9402 => 231, 0xa409 => 220, + 0x11a => 1, 0x8834 => 230, 0x9403 => 231, 0xa40a => 220, + 0x11b => 1, 0x8835 => 230, 0x9404 => 231, 0xa40b => 220, + 0x11c => 1, 0x9000 => 1, 0x9405 => 231, 0xa40c => 220, + 0x128 => 1, 0x9003 => 1, 0xa000 => 1, 0xa460 => 232, + 0x12d => 1, 0x9004 => 1, 0xa001 => 1, 0xa461 => 232, + 0x131 => 1, 0x9010 => 231, 0xa002 => 1, 0xa462 => 232, + 0x132 => 1, 0x9011 => 231, 0xa003 => 1, 0xa420 => 220, + 0x13b => 1, 0x9012 => 231, 0xa004 => 1, 0xa430 => 230, + 0x13e => 1, 0x9101 => 1, 0xa005 => 210, 0xa431 => 230, + 0x13f => 1, 0x9102 => 1, 0xa20b => 1, 0xa432 => 230, + 0x201 => 1, 0x9201 => 1, 0xa20c => 1, 0xa433 => 230, + 0x202 => 1, 0x9202 => 1, 0xa20e => 1, 0xa434 => 230, + 0x211 => 1, 0x9203 => 1, 0xa20f => 1, 0xa435 => 230, + 0x212 => 1, 0x9204 => 1, 0xa210 => 1, 0xa500 => 221, + 0x213 => 1, 0x9205 => 1, 0xa214 => 1, + 0x214 => 1, 0x9206 => 1, 0xa215 => 1, +); + +# GPSVersionID numbers when each tag was introduced +my %gpsVer = ( + 0x01 => 2000, 0x09 => 2000, 0x11 => 2000, 0x19 => 2000, + 0x02 => 2000, 0x0a => 2000, 0x12 => 2000, 0x1a => 2000, + 0x03 => 2000, 0x0b => 2000, 0x13 => 2000, 0x1b => 2200, + 0x04 => 2000, 0x0c => 2000, 0x14 => 2000, 0x1c => 2200, + 0x05 => 2000, 0x0d => 2000, 0x15 => 2000, 0x1d => 2200, + 0x06 => 2000, 0x0e => 2000, 0x16 => 2000, 0x1e => 2200, + 0x07 => 2000, 0x0f => 2000, 0x17 => 2000, 0x1f => 2300, + 0x08 => 2000, 0x10 => 2000, 0x18 => 2000, +); + +# lookup to check version numbers +my %verCheck = ( + ExifIFD => { ExifVersion => \%exifSpec }, + InteropIFD => { ExifVersion => \%exifSpec }, + GPS => { GPSVersionID => \%gpsVer }, +); + +# tags standard in various RAW file formats +my %otherSpec = ( + CR2 => { 0xc5d8 => 1, 0xc5d9 => 1, 0xc5e0 => 1, 0xc640 => 1, 0xc6dc => 1, 0xc6dd => 1 }, + NEF => { 0x9216 => 1, 0x9217 => 1 }, + DNG => { 0x882a => 1, 0x9211 => 1, 0x9216 => 1 }, + ARW => { 0x7000 => 1, 0x7001 => 1, 0x7010 => 1, 0x7011 => 1, 0x7020 => 1, 0x7031 => 1, + 0x7032 => 1, 0x7034 => 1, 0x7035 => 1, 0x7036 => 1, 0x7037 => 1, 0x7038 => 1, + 0x7310 => 1, 0x7313 => 1, 0x7316 => 1, 0x74c7 => 1, 0x74c8 => 1, 0xa500 => 1 }, + RW2 => { All => 1 }, # ignore all unknown tags in RW2 + RWL => { All => 1 }, + RAF => { All => 1 }, # (temporary) + DCR => { All => 1 }, + KDC => { All => 1 }, + JXR => { All => 1 }, + SRW => { 0xa010 => 1, 0xa011 => 1, 0xa101 => 1, 0xa102 => 1 }, + NRW => { 0x9216 => 1, 0x9217 => 1 }, + X3F => { 0xa500 => 1 }, +); + +# standard format for tags (not necessary for exifSpec or GPS tags where Writable is defined) +my %stdFormat = ( + ExifIFD => { + 0xa002 => 'int(16|32)u', + 0xa003 => 'int(16|32)u', + }, + InteropIFD => { + 0x01 => 'string', + 0x02 => 'undef', + 0x1000 => 'string', + 0x1001 => 'int(16|32)u', + 0x1002 => 'int(16|32)u', + }, + IFD => { + # TIFF, EXIF, XMP, IPTC, ICC_Profile and PrintIM standard tags: + 0xfe => 'int32u', 0x11f => 'rational64u', 0x14a => 'int32u', 0x205 => 'int16u', + 0xff => 'int16u', 0x120 => 'int32u', 0x14c => 'int16u', 0x206 => 'int16u', + 0x100 => 'int(16|32)u', 0x121 => 'int32u', 0x14d => 'string', 0x207 => 'int32u', + 0x101 => 'int(16|32)u', 0x122 => 'int16u', 0x14e => 'int16u', 0x208 => 'int32u', + 0x107 => 'int16u', 0x123 => 'int16u', 0x150 => 'int(8|16)u', 0x209 => 'int32u', + 0x108 => 'int16u', 0x124 => 'int32u', 0x151 => 'string', 0x211 => 'rational64u', + 0x109 => 'int16u', 0x125 => 'int32u', 0x152 => 'int16u', 0x212 => 'int16u', + 0x10a => 'int16u', 0x129 => 'int16u', 0x153 => 'int16u', 0x213 => 'int16u', + 0x10d => 'string', 0x13c => 'string', 0x154 => '.*', 0x214 => 'rational64u', + 0x111 => 'int(16|32)u', 0x13d => 'int16u', 0x155 => '.*', 0x2bc => 'int8u', + 0x116 => 'int(16|32)u', 0x140 => 'int16u', 0x156 => 'int16u', 0x828d => 'int16u', + 0x117 => 'int(16|32)u', 0x141 => 'int16u', 0x15b => 'undef', 0x828e => 'int8u', + 0x118 => 'int16u', 0x142 => 'int(16|32)u', 0x200 => 'int16u', 0x83bb => 'int32u', + 0x119 => 'int16u', 0x143 => 'int(16|32)u', 0x201 => 'int32u', 0x8649 => 'int8u', + 0x11d => 'string', 0x144 => 'int32u', 0x202 => 'int32u', 0x8773 => 'undef', + 0x11e => 'rational64u', 0x145 => 'int(16|32)u', 0x203 => 'int16u', 0xc4a5 => 'undef', + # Windows Explorer tags: + 0x9c9b => 'int8u', 0x9c9d => 'int8u', 0x9c9f => 'int8u', + 0x9c9c => 'int8u', 0x9c9e => 'int8u', + # GeoTiff tags: + 0x830e => 'double', 0x8482 => 'double', 0x87af => 'int16u', 0x87b1 => 'string', + 0x8480 => 'double', 0x85d8 => 'double', 0x87b0 => 'double', + # DNG tags: + 0xc615 => '(string|int8u)', 0xc6d3 => '', + 0xc61a => '(int16u|int32u|rational64u)', 0xc6f4 => '(string|int8u)', + 0xc61d => 'int(16|32)u', 0xc6f6 => '(string|int8u)', + 0xc61f => '(int16u|int32u|rational64u)', 0xc6f8 => '(string|int8u)', + 0xc620 => '(int16u|int32u|rational64u)', 0xc6fe => '(string|int8u)', + 0xc628 => '(int16u|rational64u)', 0xc716 => '(string|int8u)', + 0xc634 => 'int8u', 0xc717 => '(string|int8u)', + 0xc640 => '', 0xc718 => '(string|int8u)', + 0xc660 => '', 0xc71e => 'int(16|32)u', + 0xc68b => '(string|int8u)', 0xc71f => 'int(16|32)u', + 0xc68d => 'int(16|32)u', 0xc791 => 'int(16|32)u', + 0xc68e => 'int(16|32)u', 0xc792 => 'int(16|32)u', + 0xc6d2 => '', 0xc793 => '(int16u|int32u|rational64u)', + }, +); + +# generate lookup for any IFD +my %stdFormatAnyIFD = map { %{$stdFormat{$_}} } keys %stdFormat; + +# tag values to validate based on file type (from EXIF specification) +# - validation code may access $val and %val, and returns 1 on success, +# or error message otherwise ('' for a generic message) +# - entry is undef if tag must not exist (same as 'not defined $val' in code) +my %validValue = ( + JPEG => { + IFD0 => { + 0x100 => undef, # ImageWidth + 0x101 => undef, # ImageLength + 0x102 => undef, # BitsPerSample + 0x103 => undef, # Compression + 0x106 => undef, # PhotometricInterpretation + 0x111 => undef, # StripOffsets + 0x115 => undef, # SamplesPerPixel + 0x116 => undef, # RowsPerStrip + 0x117 => undef, # StripByteCounts + 0x11a => 'defined $val', # XResolution + 0x11b => 'defined $val', # YResolution + 0x11c => undef, # PlanarConfiguration + 0x128 => '$val =~ /^[123]$/', # ResolutionUnit + 0x201 => undef, # JPEGInterchangeFormat + 0x202 => undef, # JPEGInterchangeFormatLength + 0x212 => undef, # YCbCrSubSampling + 0x213 => '$val =~ /^[12]$/', # YCbCrPositioning + }, + IFD1 => { + 0x100 => undef, # ImageWidth + 0x101 => undef, # ImageLength + 0x102 => undef, # BitsPerSample + 0x103 => '$val == 6', # Compression + 0x106 => undef, # PhotometricInterpretation + 0x111 => undef, # StripOffsets + 0x115 => undef, # SamplesPerPixel + 0x116 => undef, # RowsPerStrip + 0x117 => undef, # StripByteCounts + 0x11a => 'defined $val', # XResolution + 0x11b => 'defined $val', # YResolution + 0x11c => undef, # PlanarConfiguration + 0x128 => '$val =~ /^[123]$/', # ResolutionUnit + 0x201 => 'defined $val', # JPEGInterchangeFormat + 0x202 => 'defined $val', # JPEGInterchangeFormatLength + 0x212 => undef, # YCbCrSubSampling + }, + ExifIFD => { + 0x9000 => 'defined $val and $val =~ /^\d{4}$/', # ExifVersion + 0x9101 => 'defined $val', # ComponentsConfiguration + 0xa000 => 'defined $val', # FlashpixVersion + 0xa001 => '$val == 1 or $val == 0xffff', # ColorSpace + 0xa002 => 'defined $val', # PixelXDimension + 0xa003 => 'defined $val', # PixelYDimension + }, + GPS => { + 0x00 => 'defined $val and $val =~ /^\d \d \d \d$/', # GPSVersionID + 0x1b => 'not defined $val or $val =~ /^(GPS|CELLID|WLAN|MANUAL)$/', # GPSProcessingMethod + }, + InteropIFD => { }, # (needed for ExifVersion check) + }, + TIFF => { + IFD0 => { + 0x100 => 'defined $val', # ImageWidth + 0x101 => 'defined $val', # ImageLength + # (default is 1) 0x102 => 'defined $val', # BitsPerSample + 0x103 => q{ + not defined $val or $val =~ /^(1|5|6|32773)$/ or + ($val == 2 and (not defined $val{0x102} or $val{0x102} == 1)); + }, # Compression + 0x106 => '$val =~ /^[0123]$/', # PhotometricInterpretation + 0x111 => 'defined $val', # StripOffsets + # SamplesPerPixel + 0x115 => q{ + my $pi = $val{0x106} || 0; + my $xtra = ($val{0x152} ? scalar(split ' ', $val{0x152}) : 0); + if ($pi == 2 or $pi == 6) { + return $val == 3 + $xtra; + } elsif ($pi == 5) { + return $val == 4 + $xtra; + } else { + return 1; + } + }, + 0x116 => 'defined $val', # RowsPerStrip + 0x117 => 'defined $val', # StripByteCounts + 0x11a => 'defined $val', # XResolution + 0x11b => 'defined $val', # YResolution + 0x128 => 'not defined $val or $val =~ /^[123]$/', # ResolutionUnit + # ColorMap (must be palette image with correct number of colors) + 0x140 => q{ + return '' if defined $val{0x106} and $val{0x106} == 3 xor defined $val; + return 1 if not defined $val or length($val) == 6 * 2 ** ($val{0x102} || 0); + return 'Invalid count for'; + }, + 0x201 => undef, # JPEGInterchangeFormat + 0x202 => undef, # JPEGInterchangeFormatLength + }, + ExifIFD => { + 0x9000 => 'defined $val', # ExifVersion + 0x9101 => undef, # ComponentsConfiguration + 0x9102 => undef, # CompressedBitsPerPixel + 0xa000 => 'defined $val', # FlashpixVersion + 0xa001 => '$val == 1 or $val == 0xffff', # ColorSpace + 0xa002 => undef, # PixelXDimension + 0xa003 => undef, # PixelYDimension + }, + InteropIFD => { + 0x0001 => undef, # InteropIndex + }, + GPS => { + 0x00 => 'defined $val and $val =~ /^\d \d \d \d$/', # GPSVersionID + 0x1b => '$val =~ /^(GPS|CELLID|WLAN|MANUAL)$/', # GPSProcessingMethod + }, + }, +); + +# validity ranges for constrained date/time fields +my @validDateField = ( + [ 'Month', 1, 12 ], + [ 'Day', 1, 31 ], + [ 'Hour', 0, 23 ], + [ 'Minutes', 0, 59 ], + [ 'Seconds', 0, 59 ], + [ 'TZhr', 0, 14 ], + [ 'TZmin', 0, 59 ], +); + +# "Validate" tag information +my %validateInfo = ( + Groups => { 0 => 'ExifTool', 1 => 'ExifTool', 2 => 'ExifTool' }, + Notes => q{ + generated only if specifically requested. Requesting this tag automatically + enables the API L<Validate|../ExifTool.html#Validate> option, imposing + additional validation checks when extracting metadata. Returns the number + of errors, warnings and minor warnings encountered. Note that the Validate + feature focuses mainly on validation of EXIF/TIFF metadata + }, + PrintConv => { + '0 0 0' => 'OK', + OTHER => sub { + my @val = split ' ', shift; + my @rtn; + push @rtn, sprintf('%d Error%s', $val[0], $val[0] == 1 ? '' : 's') if $val[0]; + push @rtn, sprintf('%d Warning%s', $val[1], $val[1] == 1 ? '' : 's') if $val[1]; + if ($val[2]) { + my $str = ($val[1] == $val[2] ? ($val[1] == 1 ? '' : 'all ') : "$val[2] "); + $rtn[-1] .= " (${str}minor)"; + } + return join(' and ', @rtn); + }, + }, +); + +# add "Validate" tag to Extra table +AddTagToTable(\%Image::ExifTool::Extra, Validate => \%validateInfo, 1); + +#------------------------------------------------------------------------------ +# Validate the raw value of a tag +# Inputs: 0) ExifTool ref, 1) tag key, 2) raw tag value +# Returns: nothing, but issues a minor Warning if a problem was detected +sub ValidateRaw($$$) +{ + my ($self, $tag, $val) = @_; + my $tagInfo = $$self{TAG_INFO}{$tag}; + my $wrn; + + # evaluate Validate code if specified + if ($$tagInfo{Validate}) { + local $SIG{'__WARN__'} = \&Image::ExifTool::SetWarning; + undef $Image::ExifTool::evalWarning; + #### eval Validate ($self, $val, $tagInfo) + my $wrn = eval $$tagInfo{Validate}; + my $err = $Image::ExifTool::evalWarning || $@; + if ($wrn or $err) { + my $name = $$tagInfo{Table}{GROUPS}{0} . ':' . Image::ExifTool::GetTagName($tag); + $self->Warn("Validate $name: $err", 1) if $err; + $self->Warn("$wrn for $name", 1) if $wrn; + } + } + # check for unknown values in PrintConv lookup for all standard EXIF tags + if (ref $$tagInfo{PrintConv} eq 'HASH' and ($$tagInfo{Table}{SHORT_NAME} eq 'GPS::Main' or + ($$tagInfo{Table} eq \%Image::ExifTool::Exif::Main and $exifSpec{$$tagInfo{TagID}}))) + { + my $prt = $self->GetValue($tag, 'PrintConv'); + $wrn = 'Unknown value for' if $prt and $prt =~ /^Unknown \(/; + } + $wrn = 'Undefined value for' if $val eq 'undef'; + if ($wrn) { + my $name = $$self{DIR_NAME} . ':' . Image::ExifTool::GetTagName($tag); + $self->Warn("$wrn $name", 1); + } +} + +#------------------------------------------------------------------------------ +# Validate raw EXIF date/time value +# Inputs: 0) date/time value +# Returns: error string +sub ValidateExifDate($) +{ + my $val = shift; + if ($val =~ /^\d{4}:(\d{2}):(\d{2}) (\d{2}):(\d{2}):(\d{2})$/) { + my @a = ($1,$2,$3,$4,$5); + my ($i, @bad); + for ($i=0; $i<@a; ++$i) { + next if $a[$i] eq ' ' or ($a[$i] >= $validDateField[$i][1] and $a[$i] <= $validDateField[$i][2]); + push @bad, $validDateField[$i][0]; + } + return join('+', @bad) . ' out of range' if @bad; + # the EXIF specification allows blank fields or an entire blank value + } elsif ($val ne ' : : : : ' and $val ne ' ') { + return 'Invalid date/time format'; + } + return undef; # OK! +} + +#------------------------------------------------------------------------------ +# Validate EXIF-reformatted XMP date/time value +# Inputs: 0) date/time value +# Returns: error string +sub ValidateXMPDate($) +{ + my $val = shift; + if ($val =~ /^\d{4}$/ or + $val =~ /^\d{4}:(\d{2})$/ or + $val =~ /^\d{4}:(\d{2}):(\d{2})$/ or + $val =~ /^\d{4}:(\d{2}):(\d{2}) (\d{2}):(\d{2})()(Z|[-+](\d{2}):(\d{2}))?$/ or + $val =~ /^\d{4}:(\d{2}):(\d{2}) (\d{2}):(\d{2}):(\d{2})(Z|[-+](\d{2}):(\d{2}))?$/ or + $val =~ /^\d{4}:(\d{2}):(\d{2}) (\d{2}):(\d{2}):(\d{2})\.?\d*(Z|[-+](\d{2}):(\d{2}))?$/) + { + my @a = ($1,$2,$3,$4,$5,$7,$8); + my ($i, @bad); + for ($i=0; $i<@a; ++$i) { + last unless defined $a[$i]; + next if $a[$i] eq '' or ($a[$i] >= $validDateField[$i][1] and $a[$i] <= $validDateField[$i][2]); + push @bad, $validDateField[$i][0]; + } + return join('+', @bad) . ' out of range' if @bad; + } else { + return 'Invalid date/time format'; + } + return undef; # OK! +} + +#------------------------------------------------------------------------------ +# Validate EXIF tag +# Inputs: 0) ExifTool ref, 1) tag table ref, 2) tag ID, 3) tagInfo ref, +# 4) previous tag ID, 5) IFD name, 6) number of values, 7) value format string +# Returns: Nothing, but sets Warning tags if any problems are found +sub ValidateExif($$$$$$$$) +{ + my ($et, $tagTablePtr, $tag, $tagInfo, $lastTag, $ifd, $count, $formatStr) = @_; + + $et->WarnOnce("Entries in $ifd are out of order") if $tag <= $lastTag; + + # (get tagInfo for unknown tags if Unknown option not used) + if (not defined $tagInfo and $$tagTablePtr{$tag} and ref $$tagTablePtr{$tag} eq 'HASH') { + $tagInfo = $$tagTablePtr{$tag}; + } + if (defined $tagInfo) { + my $ti = $tagInfo || $$tagTablePtr{$tag}; + $ti = $$ti[-1] if ref $ti eq 'ARRAY'; + my $stdFmt = $stdFormat{$ifd} || $stdFormat{IFD}; + if (defined $$stdFmt{All} or ($tagTablePtr eq \%Image::ExifTool::Exif::Main and + ($exifSpec{$tag} or $$stdFmt{$tag} or + ($tag >= 0xc612 and $tag <= 0xc7b5 and not defined $$stdFmt{$tag}))) or # (DNG tags) + $$tagTablePtr{SHORT_NAME} eq 'GPS::Main') + { + my $wgp = $$ti{WriteGroup} || $$tagTablePtr{WRITE_GROUP}; + if ($wgp and $wgp ne $ifd and $wgp ne 'All' and not $$ti{OffsetPair} and + ($ifd =~ /^(Sub|Profile)?IFD\d*$/ xor $wgp =~ /^(Sub)?IFD\d*$/) and + ($$ti{Writable} or $$ti{WriteGroup}) and $ifd !~ /^SRF\d+$/) + { + $et->Warn(sprintf('Wrong IFD for 0x%.4x %s (should be %s not %s)', $tag, $$ti{Name}, $wgp, $ifd)); + } + my $fmt = $$stdFmt{$tag} || $$ti{Writable}; + if ($fmt and $formatStr !~ /^$fmt$/ and (not $tagInfo or + not $$tagInfo{IsOffset} or $Image::ExifTool::Exif::intFormat{$formatStr})) + { + $et->Warn(sprintf('Non-standard format (%s) for %s 0x%.4x %s', $formatStr, $ifd, $tag, $$ti{Name})) + } + } elsif ($stdFormatAnyIFD{$tag}) { + if ($$ti{Writable} || $$ti{WriteGroup}) { + my $wgp = $$ti{WriteGroup} || $$tagTablePtr{WRITE_GROUP}; + if ($wgp and $wgp ne $ifd) { + $et->Warn(sprintf('Wrong IFD for 0x%.4x %s (should be %s not %s)', $tag, $$ti{Name}, $wgp, $ifd)); + } + } + } elsif (not $otherSpec{$$et{VALUE}{FileType}} or + (not $otherSpec{$$et{VALUE}{FileType}}{$tag} and not $otherSpec{$$et{VALUE}{FileType}}{All})) + { + if ($tagTablePtr eq \%Image::ExifTool::Exif::Main or $$tagInfo{Unknown}) { + $et->Warn(sprintf('Non-standard %s tag 0x%.4x %s', $ifd, $tag, $$ti{Name}), 1); + } + } + # change expected count from read Format to Writable size + my $tiCount = $$ti{Count}; + if ($tiCount) { + if ($$ti{Format} and $$ti{Writable} and + $Image::ExifTool::Exif::formatNumber{$$ti{Format}} and + $Image::ExifTool::Exif::formatNumber{$$ti{Writable}}) + { + my $s1 = $Image::ExifTool::Exif::formatSize[$Image::ExifTool::Exif::formatNumber{$$ti{Format}}]; + my $s2 = $Image::ExifTool::Exif::formatSize[$Image::ExifTool::Exif::formatNumber{$$ti{Writable}}]; + $tiCount = int($tiCount * $s1 / $s2); + } + if ($tiCount > 0 and $count != $tiCount) { + $et->Warn(sprintf('Non-standard count (%d) for %s 0x%.4x %s', $count, $ifd, $tag, $$ti{Name})); + } + } + } elsif (not $otherSpec{$$et{VALUE}{FileType}} or + (not $otherSpec{$$et{VALUE}{FileType}}{$tag} and not $otherSpec{$$et{VALUE}{FileType}}{All})) + { + $et->Warn(sprintf('Unknown %s tag 0x%.4x', $ifd, $tag), 1); + } +} + +#------------------------------------------------------------------------------ +# Validate image data offsets/sizes +# Inputs: 0) ExifTool ref, 1) offset info hash ref (arrays of tagInfo/value pairs, keyed by tagID) +# 2) directory name, 3) optional flag for minor warning +sub ValidateOffsetInfo($$$;$) +{ + local $_; + my ($et, $offsetInfo, $dirName, $minor) = @_; + + my $fileSize = $$et{VALUE}{FileSize} or return; + + # (don't test RWZ files and some other file types) + return if $$et{DontValidateImageData}; + # (Minolta A200 uses wrong byte order for these) + return if $$et{TIFF_TYPE} eq 'MRW' and $dirName eq 'IFD0' and $$et{Model} =~ /^DiMAGE A200/; + # (don't test 3FR, RWL or RW2 files) + return if $$et{TIFF_TYPE} =~ /^(3FR|RWL|RW2)$/; + + Image::ExifTool::Exif::ValidateImageData($et, $offsetInfo, $dirName); + + # loop through all offsets + while (%$offsetInfo) { + my ($id1) = sort keys %$offsetInfo; + my $offsets = $$offsetInfo{$id1}; + delete $$offsetInfo{$id1}; + next unless ref $offsets eq 'ARRAY'; + my $id2 = $$offsets[0]{OffsetPair}; + unless (defined $id2 and $$offsetInfo{$id2}) { + unless ($$offsets[0]{NotRealPair} or (defined $id2 and $id2 == -1)) { + my $corr = $$offsets[0]{IsOffset} ? 'size' : 'offset'; + $et->Warn("$dirName:$$offsets[0]{Name} is missing the corresponding $corr tag") unless $minor; + } + next; + } + my $sizes = $$offsetInfo{$id2}; + delete $$offsetInfo{$id2}; + ($sizes, $offsets) = ($offsets, $sizes) if $$sizes[0]{IsOffset}; + my @offsets = split ' ', $$offsets[1]; + my @sizes = split ' ', $$sizes[1]; + if (@sizes != @offsets) { + $et->Warn(sprintf('Wrong number of values in %s 0x%.4x %s', + $dirName, $$offsets[0]{TagID}, $$offsets[0]{Name}), $minor); + next; + } + while (@offsets) { + my $start = pop @offsets; + my $end = $start + pop @sizes; + $et->WarnOnce("$dirName:$$offsets[0]{Name} is zero", $minor) if $start == 0; + $et->WarnOnce("$dirName:$$sizes[0]{Name} is zero", $minor) if $start == $end; + next unless $end > $fileSize; + if ($start >= $fileSize) { + if ($start == 0xffffffff) { + $et->Warn("$dirName:$$offsets[0]{Name} is invalid (0xffffffff)", $minor); + } else { + $et->Warn("$dirName:$$offsets[0]{Name} is past end of file", $minor); + } + } else { + $et->Warn("$dirName:$$offsets[0]{Name}+$$sizes[0]{Name} runs past end of file", $minor); + } + last; + } + } +} + +#------------------------------------------------------------------------------ +# Finish Validating tags +# Inputs: 0) ExifTool ref, 1) True to generate Validate tag +sub FinishValidate($$) +{ + local $_; + my ($et, $mkTag) = @_; + + my $fileType = $$et{FILE_TYPE} || ''; + $fileType = $$et{TIFF_TYPE} if $fileType eq 'TIFF'; + + if ($validValue{$fileType}) { + my ($grp, $tag, %val); + local $SIG{'__WARN__'} = \&Image::ExifTool::SetWarning; + foreach $grp (sort keys %{$validValue{$fileType}}) { + next unless $$et{FOUND_DIR}{$grp}; + my ($key, %val, %info, $minor, $verTag, $ver, $vstr); + my $verCheck = $verCheck{$grp}; + if ($verCheck) { + ($verTag) = keys %$verCheck; + ($ver = $$et{VALUE}{$verTag}) =~ tr/0-9//dc; # (remove non-digits) + undef $ver unless $ver =~ /^\d{4}$/; # (already warned if invalid version) + } + # get all tags in this group + foreach $key (sort keys %{$$et{VALUE}}) { + next unless $et->GetGroup($key, 1) eq $grp; + next if $$et{TAG_EXTRA}{$key} and $$et{TAG_EXTRA}{$key}{G3}; # ignore sub-documents + # fill in %val lookup with values based on tag ID + my $tag = $$et{TAG_INFO}{$key}{TagID}; + $val{$tag} = $$et{VALUE}{$key}; + # save TagInfo ref for later + $info{$tag} = $$et{TAG_INFO}{$key}; + next unless defined $ver; + my $chk = $$verCheck{$verTag}; + next if not defined $$chk{$tag} or $$chk{$tag} == 1 or $ver >= $$chk{$tag}; + if ($verTag eq 'GPSVersionID') { + ($vstr = $$chk{$tag}) =~ s/^(\d)(\d)(\d)/$1.$2.$3./; + } else { + $vstr = sprintf('%.4d', $$chk{$tag}); + } + $et->Warn(sprintf('%s tag 0x%.4x %s requires %s %s or higher', + $grp, $tag, $$et{TAG_INFO}{$key}{Name}, $verTag, $vstr)); + } + # make quick lookup for values based on tag ID + my $validValue = $validValue{$fileType}{$grp}; + foreach $tag (sort { $a <=> $b } keys %$validValue) { + my $val = $val{$tag}; + my ($pre, $post); + if (defined $$validValue{$tag}) { + #### eval ($val, %val) + my $result = eval $$validValue{$tag}; + if (not defined $result) { + $pre = 'Internal error validating'; + } elsif ($result eq '') { + $pre = defined $val ? 'Invalid value for' : "Missing required $fileType"; + } else { + next if $result eq '1'; + $pre = $result; + } + } else { + next unless defined $val; + $post = "is not allowed in $fileType"; + $minor = 1; + } + my $name; + if ($info{$tag}) { + $name = $info{$tag}{Name}; + } else { + my $table = 'Image::ExifTool::'.($grp eq 'GPS' ? 'GPS' : 'Exif').'::Main'; + my $tagInfo = GetTagTable($table)->{$tag}; + $tagInfo = $$tagInfo[0] if ref $tagInfo eq 'ARRAY'; + $name = $tagInfo ? $$tagInfo{Name} : '<unknown>'; + } + next if $$et{WrongFormat} and $$et{WrongFormat}{"$grp:$name"}; + $pre ? ($pre .= ' ') : ($pre = ''); + $post ? ($post = ' '.$post) : ($post = ''); + $et->Warn(sprintf('%s%s tag 0x%.4x %s%s', $pre, $grp, $tag, $name, $post), $minor); + } + } + } + # validate file extension + if ($$et{FILENAME} ne '') { + my $fileExt = ($$et{FILENAME} =~ /^.*\.([^.]+)$/s) ? uc($1) : ''; + my $extFileType = Image::ExifTool::GetFileType($fileExt); + if ($extFileType and $extFileType ne $fileType) { + my $normExt = $$et{VALUE}{FileTypeExtension}; + if ($normExt and $normExt ne $fileExt) { + my $lkup = $Image::ExifTool::fileTypeLookup{$fileExt}; + if (ref $lkup or $lkup ne $normExt) { + $et->Warn("File has wrong extension (should be $normExt, not $fileExt)"); + } + } + } + } + # issue warning if FastScan option used + $et->Warn('Validation incomplete because FastScan option used') if $et->Options('FastScan'); + + # generate Validate tag if necessary + if ($mkTag) { + my (@num, $key); + push @num, $$et{VALUE}{Error} ? ($$et{DUPL_TAG}{Error} || 0) + 1 : 0, + $$et{VALUE}{Warning} ? ($$et{DUPL_TAG}{Warning} || 0) + 1 : 0, 0; + for ($key = 'Warning'; ; ) { + ++$num[2] if $$et{VALUE}{$key} and $$et{VALUE}{$key} =~ /^\[minor\]/i; + $key = $et->NextTagKey($key) or last; + } + $et->FoundTag(Validate => "@num"); + } +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::Validate - Additional metadata validation + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains additional routines and definitions used when the +ExifTool Validate option is enabled. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 SEE ALSO + +L<Image::ExifTool(3pm)|Image::ExifTool>, +L<Image::ExifTool::TagNames/Extra Tags> + +=cut diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Vorbis.pm b/src/Image-ExifTool/lib/Image/ExifTool/Vorbis.pm index b9a07193..b6911648 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Vorbis.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/Vorbis.pm @@ -228,7 +228,7 @@ information from Ogg Vorbis audio headers. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/WTV.pm b/src/Image-ExifTool/lib/Image/ExifTool/WTV.pm new file mode 100644 index 00000000..8fe8ac31 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/WTV.pm @@ -0,0 +1,319 @@ +#------------------------------------------------------------------------------ +# File: WTV.pm +# +# Description: Read WTV meta information +# +# Revisions: 2018-05-30 - P. Harvey Created +# +# References: 1) https://wiki.multimedia.cx/index.php?title=WTV +#------------------------------------------------------------------------------ + +package Image::ExifTool::WTV; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.00'; + +sub ProcessMetadata($$$); + +my %timeInfo = ( + # time looks like 100 ns intervals since 0:00 UTC Jan 1, 0001 (ref PH) + ValueConv => q{ # (719162 days from 0001:01:01 to 1970:01:01) + my $t = $val / 1e7 - 719162*24*3600; + return Image::ExifTool::ConvertUnixTime($t) . 'Z'; + }, + PrintConv => '$self->ConvertDateTime($val)', +); + +my %bool = ( PrintConv => { 0 => 'No', 1 => 'Yes' }, PrintConvColumns => 2 ); + +# WTV chunks +%Image::ExifTool::WTV::Main = ( + GROUPS => { 0 => 'WTV', 1 => 'WTV', 2 => 'Video' }, + NOTES => 'Tags found in Windows recorded TV (WTV) videos.', + # 'timeline.table.0.header.Events' (not decoded) + # 'timeline.table.0.entries.Events' (not decoded) + # 'timeline' (not decoded) + # 'table.0.header.legacy_attrib' (not decoded) + 'table.0.entries.legacy_attrib' => { + Name => 'Metdata', + SubDirectory => { TagTable => 'Image::ExifTool::WTV::Metadata' }, + }, + # 'table.0.redirector.legacy_attrib' (not decoded) + # 'table.0.header.time' (not decoded) + # 'table.0.entries.time' (not decoded) +); + +# Note: Many of these tags are similar to those found in Image::ExifTool::Microsoft::Xtra +# and Image::ExifTool::ASF::ExtendedDescr +%Image::ExifTool::WTV::Metadata = ( + GROUPS => { 0 => 'WTV', 1 => 'WTV', 2 => 'Video' }, + PROCESS_PROC => \&ProcessMetadata, + NOTES => 'ExifTool will extract any tag found, even if not in this table.', + VARS => { NO_ID => 1 }, + 'Duration' => { + Name => 'Duration', + ValueConv => '$val/1e7', + PrintConv => 'ConvertDuration($val)', + }, + 'Title' => { }, + 'WM/Genre' => 'Genre', + 'WM/Language' => 'Language', + 'WM/MediaClassPrimaryID' => 'MediaClassPrimaryID', + 'WM/MediaClassSecondaryID' => 'MediaClassSecondaryID', + 'WM/MediaCredits' => 'MediaCredits', + 'WM/MediaIsDelay' => { Name => 'MediaIsDelay', %bool }, + 'WM/MediaIsFinale' => { Name => 'MediaIsFinale', %bool }, + 'WM/MediaIsLive' => { Name => 'MediaIsLive', %bool }, + 'WM/MediaIsMovie' => { Name => 'MediaIsMovie', %bool }, + 'WM/MediaIsPremiere' => { Name => 'MediaIsPremiere', %bool }, + 'WM/MediaIsRepeat' => { Name => 'MediaIsRepeat', %bool }, + 'WM/MediaIsSAP' => { Name => 'MediaIsSAP', %bool }, + 'WM/MediaIsSport' => { Name => 'MediaIsSport', %bool }, + 'WM/MediaIsStereo' => { Name => 'MediaIsStereo', %bool, Groups => { 2 => 'Audio' } }, + 'WM/MediaIsSubtitled' => { Name => 'MediaIsSubtitled',%bool }, + 'WM/MediaIsTape' => { Name => 'MediaIsTape', %bool }, + 'WM/MediaNetworkAffiliation'=> 'MediaNetworkAffiliation', + 'WM/MediaOriginalBroadcastDateTime' => { + Name => 'MediaOriginalBroadcastDateTime', + Groups => { 2 => 'Time' }, + ValueConv => '$val =~ tr/-T/: /; $val', + PrintConv => '$self->ConvertDateTime($val)', + }, + 'WM/MediaOriginalChannel' => { Name => 'MediaOriginalChannel' }, + 'WM/MediaOriginalChannelSubNumber' => { Name => 'MediaOriginalChannelSubNumber' }, + 'WM/MediaOriginalRunTime' => { + Name => 'MediaOriginalRunTime', + ValueConv => '$val / 1e7', + PrintConv => 'ConvertDuration($val)', + }, + 'WM/MediaStationCallSign' => 'MediaStationCallSign', + 'WM/MediaStationName' => 'MediaStationName', + 'WM/MediaThumbAspectRatioX' => 'MediaThumbAspectRatioX', + 'WM/MediaThumbAspectRatioY' => 'MediaThumbAspectRatioY', + 'WM/MediaThumbHeight' => 'MediaThumbHeight', + 'WM/MediaThumbRatingAttributes' => { Name => 'MediaThumbRatingAttributes' }, + 'WM/MediaThumbRatingLevel' => 'MediaThumbRatingLevel', + 'WM/MediaThumbRatingSystem' => 'MediaThumbRatingSystem', + 'WM/MediaThumbRet' => 'MediaThumbRet', + 'WM/MediaThumbStride' => 'MediaThumbStride', + 'WM/MediaThumbTimeStamp' => { Name => 'MediaThumbTimeStamp', Notes => 'unknown units', Unknown => 1 }, + 'WM/MediaThumbWidth' => 'MediaThumbWidth', + 'WM/OriginalReleaseTime' => { + Name => 'OriginalReleaseTime', + Groups => { 2 => 'Time' }, + ValueConv => '$val=~tr/-T/: /; $val', + PrintConv => '$self->ConvertDateTime($val)', + }, + 'WM/ParentalRating' => 'ParentalRating', + 'WM/ParentalRatingReason' => 'ParentalRatingReason', + 'WM/Provider' => 'Provider', + 'WM/ProviderCopyright' => 'ProviderCopyright', + 'WM/ProviderRating' => 'ProviderRating', + 'WM/SubTitle' => 'Subtitle', + 'WM/SubTitleDescription' => 'SubtitleDescription', + 'WM/VideoClosedCaptioning' => { Name => 'VideoClosedCaptioning', %bool }, + 'WM/WMRVATSCContent' => { Name => 'ATSCContent', %bool }, + 'WM/WMRVActualSoftPostPadding' => 'ActualSoftPostPadding', + 'WM/WMRVActualSoftPrePadding' => 'ActualSoftPrePadding', + 'WM/WMRVBitrate' => { Name => 'Bitrate', Notes => 'unknown units', Unknown => 1 }, + 'WM/WMRVBrandingImageID' => 'BrandingImageID', + 'WM/WMRVBrandingName' => 'BrandingName', + 'WM/WMRVContentProtected' => { Name => 'ContentProtected', %bool }, + 'WM/WMRVContentProtectedPercent' => 'ContentProtectedPercent', + 'WM/WMRVDTVContent' => { Name => 'DTVContent', %bool }, + 'WM/WMRVEncodeTime' => { Name => 'EncodeTime', Groups => { 2 => 'Time' }, %timeInfo }, + 'WM/WMRVEndTime' => { Name => 'EndTime', Groups => { 2 => 'Time' }, %timeInfo }, + 'WM/WMRVExpirationDate' => { Name => 'ExpirationDate', Groups => { 2 => 'Time' }, %timeInfo, Unknown => 1 }, + 'WM/WMRVExpirationSpan' => { Name => 'ExpirationSpan', Notes => 'unknown units', Unknown => 1 }, + 'WM/WMRVHDContent' => { Name => 'HDContent', %bool }, + 'WM/WMRVHardPostPadding' => 'HardPostPadding', + 'WM/WMRVHardPrePadding' => 'HardPrePadding', + 'WM/WMRVInBandRatingAttributes' => 'InBandRatingAttributes', + 'WM/WMRVInBandRatingLevel' => 'InBandRatingLevel', + 'WM/WMRVInBandRatingSystem' => 'InBandRatingSystem', + 'WM/WMRVKeepUntil' => 'KeepUntil', + 'WM/WMRVOriginalSoftPostPadding'=> 'OriginalSoftPostPadding', + 'WM/WMRVOriginalSoftPrePadding' => 'OriginalSoftPrePadding', + 'WM/WMRVProgramID' => 'ProgramID', + 'WM/WMRVQuality' => 'Quality', + 'WM/WMRVRequestID' => 'RequestID', + 'WM/WMRVScheduleItemID' => 'ScheduleItemID', + 'WM/WMRVSeriesUID' => 'SeriesUID', + 'WM/WMRVServiceID' => 'ServiceID', + 'WM/WMRVWatched' => { Name => 'Watched', %bool }, +); + +#------------------------------------------------------------------------------ +# Read specified sectors from the file +# Inputs: 0) raf ref, 1) sector table ref, 2) offset in sector table, 3) sector size +# Returns: Data or undef on error +sub ReadSectors($$$$) +{ + my ($raf, $secPt, $pos, $secSize) = @_; + my ($data, $buff); + while ($pos <= length($$secPt) - 4) { + my $sec = Get32u($secPt, $pos); + return undef if $sec == 0xffff; # (just in case) + last unless $sec; # a null marks the end of the sector table + defined($data) ? ($data .= $buff) : ($data = $buff); + return undef unless $raf->Seek($sec*$secSize,0) and $raf->Read($buff,$secSize) == $secSize; + $pos += 4; + } + return defined($data) ? $data . $buff : $buff; +} + +#------------------------------------------------------------------------------ +# Process WTV metadata +# Inputs: 0) ExifTool object reference, 1) dirInfo reference, 2) tag table ref +# Returns: 1 on success +sub ProcessMetadata($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + my $dataPt = $$dirInfo{DataPt}; + my $pos = 0; + my $end = length $$dataPt; + $et->VerboseDir('WTV Metadata', undef, $end); + while ($pos + 0x18 < $end) { + last unless substr($$dataPt,$pos,16) eq "\x5a\xfe\xd7\x6d\xc8\x1d\x8f\x4a\x99\x22\xfa\xb1\x1c\x38\x14\x53"; + my $fmt = Get32u($dataPt, $pos + 0x10); + my $len = Get32u($dataPt, $pos + 0x14); + my $str = ''; + $pos += 0x18; + for (;;) { + $pos + 2 > $end and $et->Warn('Corrupt metadata directory'), last; + my $ch = substr($$dataPt, $pos, 2); + $pos += 2; + last if $ch eq "\0\0"; + $str .= $ch; + } + last if $pos + $len > $end; + my $tag = $et->Decode($str, 'UCS2', undef, 'UTF8'); + my $dat = substr($$dataPt, $pos, $len); + # add tag if not already there + unless ($$tagTablePtr{$tag}) { + my $name = $tag; + $name =~ s{^(WTV_Metadata_)?WM/(WMRV)?}{}; + AddTagToTable($tagTablePtr, $tag, $name); + $et->VPrint(0, $$et{INDENT}, "[adding WTV:$name]\n"); + } + my $val; + if ($fmt==0 or $fmt==3) { # int32u or boolean32 + $val = Get32s(\$dat, 0); + } elsif ($fmt == 1) { # string + $val = $et->Decode($dat, 'UCS2'); + } elsif ($fmt == 6) { # GUID + $val = unpack('H*', $dat); + } elsif ($fmt == 4) { # int64u (date/time values use this) + $val = Get64u(\$dat, 0); + } else { + $val = $dat; + $fmt = "Unknown($fmt)"; + } + $et->HandleTag($tagTablePtr, $tag, $val, + Format => "format $fmt", + Size => length $dat, + ); + $et->VerboseDump(\$dat); + $pos += $len; + } +} + +#------------------------------------------------------------------------------ +# Extract information from a WTV video +# Inputs: 0) ExifTool object reference, 1) dirInfo reference +# Returns: 1 on success, 0 if this wasn't a valid WTV file +sub ProcessWTV($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my $verbose = $et->Options('Verbose'); + my ($buff, $tagTablePtr, $pos, $len); + + # verify this is a valid WTV file + return 0 unless $raf->Read($buff, 0x60) == 0x60; + return 0 unless $buff =~ /^\xb7\xd8\x00\x20\x37\x49\xda\x11\xa6\x4e\x00\x07\xe9\x5e\xad\x8d/; + $et->SetFileType(); + SetByteOrder('II'); + # 0x28 - int32u: sector size? (=0x1000) (PH NC) + # 0x38 - int32u: sector number for main WTV directory (PH assume this is a sector table, NC) + # 0x58 - int32u: total number of sectors in file + my $secSize = Get32u(\$buff, 0x28); + # in case I'm wrong about this, constrain sector size to + # either 0x1000 (standard) or 0x100 (ExifTool test file) - PH + $secSize = 0x1000 unless $secSize == 0x1000 or $secSize == 0x100; + $buff = ReadSectors($raf, \$buff, 0x38, $secSize); # read the WTV directory + return 0 unless defined $buff; + $tagTablePtr = GetTagTable('Image::ExifTool::WTV::Main'); + # parse the WTV directory + $et->VerboseDir('WTV'); + for ($pos=0; $pos<length($buff)-0x28; $pos+=$len) { + unless (substr($buff,$pos,0x10) eq "\x92\xb7\x74\x91\x59\x70\x70\x44\x88\xdf\x06\x3b\x82\xcc\x21\x3d") { + $et->Warn("WTV directory wasn't at expected location") unless $pos; + last; + } + $len = Get32u(\$buff, $pos+0x10); + last if $pos + $len > length($buff); + my $n = Get32u(\$buff, $pos + 0x20); + 0x28 + $n*2 + 8 > $len and $et->Warn('WTV directory error'), last; + my $tag = $et->Decode(substr($buff,$pos+0x28,$n*2), 'UCS2', undef, 'UTF8'); + my $ptr = $pos + 0x28 + $n * 2; + my $flg = Get32u(\$buff, $ptr + 4); + if ($verbose) { + my $s = Get32s(\$buff, $ptr); + $s = sprintf('0x%x', $s) unless $s < 0; + $et->VPrint(1,"- Tag '${tag}' (sector=$s, flag=$flg)"); + } + next unless $$tagTablePtr{$tag} and ($flg == 0 or $flg == 1); + my $sec = substr($buff, $ptr, 4); + my $data = ReadSectors($raf, \$sec, 0, $secSize); + last unless defined $data; + # read sectors from table if necessary (flag=1 indicates a sector table) + $data = ReadSectors($raf, \$data, 0, $secSize) if $flg == 1; + defined $data or $et->Warn("Error fetching data for $tag"), next; + $et->HandleTag($tagTablePtr, $tag, $data); + } + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::WTV - Read WTV meta information + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to read WTV +(Windows recorded TV show) videos. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<https://wiki.multimedia.cx/index.php?title=WTV> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/WTV Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/WriteCanonRaw.pl b/src/Image-ExifTool/lib/Image/ExifTool/WriteCanonRaw.pl index 8cbcbb55..5b8d3a23 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/WriteCanonRaw.pl +++ b/src/Image-ExifTool/lib/Image/ExifTool/WriteCanonRaw.pl @@ -454,7 +454,7 @@ ($$$) # pad with original garbage in case it contained something useful $value .= substr($buff, $pt+2+8-$len, 8-$len); } elsif ($len > 8) { # this shouldn't happen - warn "Value too long! -- trucated\n"; + warn "Value too long! -- truncated\n"; $value = substr($value, 0, 8); } # create new directory entry @@ -521,7 +521,7 @@ ($$) if ($$et{DEL_GROUP}{MakerNotes}) { if ($type eq 'CCDR') { - $et->Error("Can't delete MakerNotes group in CRW file"); + $et->Error("Can't delete MakerNotes from CRW"); return 0; } else { ++$$et{CHANGED}; @@ -617,13 +617,13 @@ =head1 DESCRIPTION =head1 NOTES The CRW format is a pleasure to work with. All pointer offsets are relative -to the start of the data for each directory. If TIFF/EXIF had implemented -pointers in this way, it would be MUCH easier to read and write TIFF/JPEG -files, and would lead to far fewer problems with corrupted metadata. +to the start of the data for each directory. If EXIF/TIFF had implemented +pointers in this way, it would be MUCH easier to read and write TIFF and +JPEG files, and would lead to far fewer problems with corrupted metadata. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. @@ -632,6 +632,6 @@ =head1 SEE ALSO L<Image::ExifTool::CanonRaw(3pm)|Image::ExifTool::CanonRaw>, L<Image::ExifTool(3pm)|Image::ExifTool>, -L<http://owl.phy.queensu.ca/~phil/exiftool/canon_raw.html> +L<https://exiftool.org/canon_raw.html> =cut diff --git a/src/Image-ExifTool/lib/Image/ExifTool/WriteExif.pl b/src/Image-ExifTool/lib/Image/ExifTool/WriteExif.pl index cc80d9da..3864b4c0 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/WriteExif.pl +++ b/src/Image-ExifTool/lib/Image/ExifTool/WriteExif.pl @@ -38,7 +38,7 @@ package Image::ExifTool::Exif; 0x0128 => 2, # ResolutionUnit (inches) }, ExifIFD => { - 0x9000 => '0231', # ExifVersion + 0x9000 => '0232', # ExifVersion 0x9101 => "1 2 3 0",# ComponentsConfiguration 0xa000 => '0100', # FlashpixVersion 0xa001 => 0xffff, # ColorSpace (uncalibrated) @@ -367,9 +367,11 @@ ($$$;$) my $minor; $minor = 1 if $$et{DOC_NUM} or $$et{FILE_TYPE} ne 'TIFF'; unless (@bitsPerSample == $samplesPerPix) { - # (just a warning for this problem) - my $s = $samplesPerPix eq '1' ? '' : 's'; - $et->Warn("$dirName BitsPerSample should have $samplesPerPix value$s", $minor); + unless ($$et{FILE_TYPE} eq 'EPS' and @bitsPerSample == 1) { + # (just a warning for this problem) + my $s = $samplesPerPix eq '1' ? '' : 's'; + $et->Warn("$dirName BitsPerSample should have $samplesPerPix value$s", $minor); + } push @bitsPerSample, $bitsPerSample[0] while @bitsPerSample < $samplesPerPix; foreach (@bitsPerSample) { $et->WarnOnce("$dirName BitsPerSample values are different", $minor) if $_ ne $bitsPerSample[0]; @@ -412,7 +414,7 @@ ($$$) { my ($et, $errStr, $tagTablePtr) = @_; # MakerNote errors are minor by default - my $minor = ($$tagTablePtr{GROUPS}{0} eq 'MakerNotes'); + my $minor = ($$tagTablePtr{GROUPS}{0} eq 'MakerNotes' or $$et{FILE_TYPE} eq 'MOV'); if ($$tagTablePtr{VARS} and $$tagTablePtr{VARS}{MINOR_ERRORS}) { $et->Warn("$errStr. IFD dropped.") and return '' if $minor; $minor = 1; @@ -520,6 +522,9 @@ ($$$) my $name = $$dirInfo{Name}; $name = $dirName unless $name and $dirName eq 'MakerNotes' and $name !~ /^MakerNote/; + # save byte order of existing EXIF + $$et{SaveExifByteOrder} = GetByteOrder() if $dirName eq 'IFD0' or $dirName eq 'ExifIFD'; + # set encoding for strings $strEnc = $et->Options('CharsetEXIF') if $$tagTablePtr{GROUPS}{0} eq 'EXIF'; @@ -543,7 +548,7 @@ ($$$) my $mustRead; if ($dirStart < 0 or $dirStart > $dataLen-2) { $mustRead = 1; - } elsif ($dirLen > 2) { + } elsif ($dirLen >= 2) { my $len = 2 + 12 * Get16u($dataPt, $dirStart); $mustRead = 1 if $dirStart + $len > $dataLen; } @@ -574,33 +579,37 @@ ($$$) # only account for nextIFD pointer if we are going to use it $len += 4 if $dataLen==$len+6 and ($$dirInfo{Multi} or $buff =~ /\0{4}$/); UpdateTiffEnd($et, $offset+$base+2+$len); - } elsif ($dirLen) { + } elsif ($dirLen and $dirStart + 4 >= $dataLen) { # error if we can't load IFD (unless we are creating # from scratch, in which case dirLen will be zero) my $str = $et->Options('IgnoreMinorErrors') ? 'Deleted bad' : 'Bad'; $et->Error("$str $name directory", 1); } } - my ($index, $dirEnd, $numEntries); + my ($index, $dirEnd, $numEntries, %hasOldID, $unsorted); if ($dirStart + 4 < $dataLen) { $numEntries = Get16u($dataPt, $dirStart); $dirEnd = $dirStart + 2 + 12 * $numEntries; if ($dirEnd > $dataLen) { - return ExifErr($et, "Truncated $name directory", $tagTablePtr); + my $n = int(($dataLen - $dirStart - 2) / 12); + my $rtn = ExifErr($et, "Truncated $name directory", $tagTablePtr); + return undef unless $n and defined $rtn; + $numEntries = $n; # continue processing the entries we have } - # sort entries if necessary (but not in maker notes IFDs) - unless ($inMakerNotes) { - my $lastID = -1; - for ($index=0; $index<$numEntries; ++$index) { - my $tagID = Get16u($dataPt, $dirStart + 2 + 12 * $index); - # check for proper sequence (but ignore null entries at end) - if ($tagID < $lastID and ($tagID or $$tagTablePtr{0})) { - SortIFD($dataPt, $dirStart, $numEntries, $$tagTablePtr{0}); - $et->Warn("Entries in $name were out of sequence. Fixed.",1); - last; - } - $lastID = $tagID; - } + # create lookup for existing tag ID's and determine if directory is sorted + my $lastID = -1; + for ($index=0; $index<$numEntries; ++$index) { + my $tagID = Get16u($dataPt, $dirStart + 2 + 12 * $index); + $hasOldID{$tagID} = 1; + # check for proper sequence (but ignore null entries at end) + $unsorted = 1 if $tagID < $lastID and ($tagID or $$tagTablePtr{0}); + $lastID = $tagID; + } + # sort entries if out-of-order (but not in maker notes IFDs or RAW files) + if ($unsorted and not ($inMakerNotes or $et->IsRawType())) { + SortIFD($dataPt, $dirStart, $numEntries, $$tagTablePtr{0}); + $et->Warn("Entries in $name were out of sequence. Fixed.",1); + $unsorted = 0; } } else { $numEntries = 0; @@ -608,11 +617,12 @@ ($$$) } # loop through new values and accumulate all information for this IFD - my (%set, %mayDelete, $tagInfo); + my (%set, %mayDelete, $tagInfo, %hasNewID); my $wrongDir = $crossDelete{$dirName}; my @newTagInfo = $et->GetNewTagInfoList($tagTablePtr); foreach $tagInfo (@newTagInfo) { my $tagID = $$tagInfo{TagID}; + $hasNewID{$tagID} = 1; # must evaluate Condition later when we have all DataMember's available $set{$tagID} = (ref $$tagTablePtr{$tagID} eq 'ARRAY' or $$tagInfo{Condition}) ? '' : $tagInfo; } @@ -964,7 +974,7 @@ ($$$) $readCount = $oldSize / $formatSize[$readFormat]; } } - if ($oldID <= $lastTagID and not $inMakerNotes) { + if ($oldID <= $lastTagID and not ($inMakerNotes or $et->IsRawType())) { my $str = $oldInfo ? "$$oldInfo{Name} tag" : sprintf('tag 0x%x',$oldID); if ($oldID == $lastTagID) { $et->Warn("Duplicate $str in $name"); @@ -998,6 +1008,23 @@ ($$$) } } else { $isNew = $oldID <=> $newID; + # special logic needed if directory has out-of-order entries + if ($unsorted and $isNew) { + if ($isNew > 0 and $hasOldID{$newID}) { + # we wanted to create the new tag, but an old tag + # does exist with this ID, so defer writing the new tag + $isNew = -1; + } + if ($isNew < 0 and $hasNewID{$oldID}) { + # we wanted to write the old tag, but we have + # a new tag with this ID, so move it up in the order + my @tmpTags = ( $oldID ); + $_ == $oldID or push @tmpTags, $_ foreach @newTags; + @newTags = @tmpTags; + $newID = $oldID; + $isNew = 0; + } + } } my $newInfo = $oldInfo; my $newFormat = $oldFormat; @@ -1318,7 +1345,7 @@ ($$$) unless (defined $offsetData{$dataTag} or $dataTag eq 'LeicaTrailer') { # prefer tag from Composite table if it exists (otherwise # PreviewImage data would be taken from Extra tag) - my $compInfo = $Image::ExifTool::Composite{$dataTag}; + my $compInfo = Image::ExifTool::GetCompositeTagInfo($dataTag); $offsetData{$dataTag} = $et->GetNewValue($compInfo || $dataTag); my $err; if (defined $offsetData{$dataTag}) { @@ -1345,11 +1372,15 @@ ($$$) if ($$et{DEL_GROUP}{MakerNotes} and ($$et{DEL_GROUP}{MakerNotes} != 2 or $isNew <= 0)) { - if ($isNew <= 0) { - ++$$et{CHANGED}; - $verbose and print $out " Deleting MakerNotes\n"; + if ($et->IsRawType()) { + $et->WarnOnce("Can't delete MakerNotes from $$et{FileType}",1); + } else { + if ($isNew <= 0) { + ++$$et{CHANGED}; + $verbose and print $out " Deleting MakerNotes\n"; + } + next; } - next; } my $saveOrder = GetByteOrder(); if ($isNew >= 0 and defined $set{$newID}) { @@ -1765,7 +1796,7 @@ ($$$) # - I'm going out of my way here to preserve data which is # invalidated anyway by our edits my $odd; - my $oddInfo = $Image::ExifTool::Composite{OriginalDecisionData}; + my $oddInfo = Image::ExifTool::GetCompositeTagInfo('OriginalDecisionData'); if ($oddInfo and $$et{NEW_VALUE}{$oddInfo}) { $odd = $et->GetNewValue($dataTag); if ($verbose > 1) { @@ -1820,6 +1851,7 @@ ($$$) warn "Internal error writing offsets for $$newInfo{Name}\n"; return undef; } + $newValuePt = \$newValue; } $offsetInfo or $offsetInfo = $offsetInfo[$ifd] = { }; # save location of valuePtr in new directory @@ -2157,17 +2189,39 @@ ($$$) my @offsetList; if ($ifd >= 0) { my $offsetInfo = $offsetInfo[$ifd] or next; + if ($$offsetInfo{0x111} and $$offsetInfo{0x144}) { + # SubIFD may contain double-referenced data as both strips and tiles + # for Sony ARW files when SonyRawFileType is "Lossless Compressed RAW 2" + if ($dirName eq 'SubIFD' and $$et{TIFF_TYPE} eq 'ARW' and + $$offsetInfo{0x117} and $$offsetInfo{0x145} and + $$offsetInfo{0x111}[2]==1) # (must be a single strip or the tile offsets could get out of sync) + { + # some Sony ARW images contain double-referenced raw data stored as both strips + # and tiles. Copy the data using only the strip tags, but store the TileOffets + # information for updating later (see PanasonicRaw:PatchRawDataOffset for a + # description of offsetInfo elements) + $$offsetInfo{0x111}[5] = $$offsetInfo{0x144}; # hack to save TileOffsets + # delete tile information from offsetInfo because we will copy as strips + delete $$offsetInfo{0x144}; + delete $$offsetInfo{0x145}; + } else { + $et->Error("TIFF $dirName contains both strip and tile data"); + } + } # patch Panasonic RAW/RW2 StripOffsets/StripByteCounts if necessary my $stripOffsets = $$offsetInfo{0x111}; - if ($stripOffsets and $$stripOffsets[0]{PanasonicHack}) { + my $rawDataOffset = $$offsetInfo{0x118}; + if ($stripOffsets and $$stripOffsets[0]{PanasonicHack} or + $rawDataOffset and $$rawDataOffset[0]{PanasonicHack}) + { require Image::ExifTool::PanasonicRaw; my $err = Image::ExifTool::PanasonicRaw::PatchRawDataOffset($offsetInfo, $raf, $ifd); $err and $et->Error($err); } my $tagID; - # loop through all tags in reverse order so we save thumbnail + # loop through all tags in reverse numerical order so we save thumbnail # data before main image data if both exist in the same IFD - foreach $tagID (reverse sort keys %$offsetInfo) { + foreach $tagID (reverse sort { $a <=> $b } keys %$offsetInfo) { my $tagInfo = $$offsetInfo{$tagID}[0]; next unless $$tagInfo{IsOffset}; # handle byte counts with offsets my $sizeInfo = $$offsetInfo{$$tagInfo{OffsetPair}}; @@ -2285,8 +2339,8 @@ ($$$) } elsif ($ifd < 0) { # pad if necessary (but don't pad contiguous image blocks) my $pad = 0; - ++$pad if $size & 0x01 and ($n+1 >= $count or not $oldEnd or - $oldEnd != $$oldOffset[$n+1]); + ++$pad if ($blockSize + $size) & 0x01 and ($n+1 >= $count or + not $oldEnd or $oldEnd != $$oldOffset[$n+1]); # preserve original image padding if specified if ($$origDirInfo{PreserveImagePadding} and $n+1 < $count and $oldEnd and $$oldOffset[$n+1] > $oldEnd) @@ -2393,10 +2447,28 @@ ($$$) # also add to subIfdDataFixup if necessary $subIfdDataFixup->AddFixup($offsetPos, $dataTag) if $subIfdDataFixup; # must also (sometimes) update StripOffsets in Panasonic RW2 images + # and TileOffsets in Sony ARW images my $otherPos = $$offsetPair[0][5]; - if ($otherPos and $$tagInfo{PanasonicHack}) { - Set32u($newOffset, \$newData, $otherPos); - $fixup->AddFixup($otherPos, $dataTag); + if ($otherPos) { + if ($$tagInfo{PanasonicHack}) { + Set32u($newOffset, \$newData, $otherPos); + $fixup->AddFixup($otherPos, $dataTag); + } elsif (ref $otherPos eq 'ARRAY') { + # the image data was copied as one large strip, and is double-referenced + # as tile data, so all we need to do now is properly update the tile offsets + my $oldRawDataOffset = $$offsetPair[0][3][0]; + my $count = $$otherPos[2]; + my $i; + # point to offsets in value data if more than one pointer + $$otherPos[1] = Get32u(\$newData, $$otherPos[1]) if $count > 1; + for ($i=0; $i<$count; ++$i) { + my $oldTileOffset = $$otherPos[3][$i]; + my $ptrPos = $$otherPos[1] + 4 * $i; + Set32u($newOffset + $oldTileOffset - $oldRawDataOffset, \$newData, $ptrPos); + $fixup->AddFixup($ptrPos, $dataTag); + $subIfdDataFixup->AddFixup($ptrPos, $dataTag) if $subIfdDataFixup; + } + } } if ($ifd >= 0) { # buff length must be even (Note: may have changed since $size was set) @@ -2550,7 +2622,7 @@ =head1 DESCRIPTION =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/WriteIPTC.pl b/src/Image-ExifTool/lib/Image/ExifTool/WriteIPTC.pl index e740bc3e..ffac9564 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/WriteIPTC.pl +++ b/src/Image-ExifTool/lib/Image/ExifTool/WriteIPTC.pl @@ -105,7 +105,7 @@ ($$$) my $format = $$tagInfo{Format} || $$tagInfo{Table}{FORMAT} || ''; if ($format =~ /^int(\d+)/) { my $bytes = int(($1 || 0) / 8); - if ($bytes ne 1 and $bytes ne 2 and $bytes ne 4) { + if ($bytes != 1 and $bytes != 2 and $bytes != 4) { return "Can't write $bytes-byte integer"; } my $val = $$valPtr; @@ -170,7 +170,7 @@ ($$$$$;$) } else { my $len = int(($1 || 0) / 8); if ($len == 1) { # 1 byte - $$valPtr = chr($$valPtr); + $$valPtr = chr($$valPtr & 0xff); } elsif ($len == 2) { # 2-byte integer $$valPtr = pack('n', $$valPtr); } else { # 4-byte integer @@ -191,7 +191,7 @@ ($$$$$;$) my $len = length $$valPtr; $maxlen or $maxlen = $minlen; if ($len < $minlen) { - if ($et->Warn("String to short for IPTC:$$tagInfo{Name} (padded)", 2)) { + if ($et->Warn("String too short for IPTC:$$tagInfo{Name} (padded)", 2)) { $$valPtr .= ' ' x ($minlen - $len); } } elsif ($len > $maxlen) { @@ -215,7 +215,7 @@ ($$$$$;$) sub IptcDate($) { my $val = shift; - unless ($val =~ s/^.*(\d{4}):?(\d{2}):?(\d{2}).*/$1$2$3/s) { + unless ($val =~ s{^.*(\d{4})[-:/.]?(\d{2})[-:/.]?(\d{2}).*}{$1$2$3}s) { warn "Invalid date format (use YYYY:mm:dd)\n"; undef $val; } @@ -242,7 +242,7 @@ ($) if ($date and $date =~ /^(\d{4}):(\d{2}):(\d{2})\s*$/ and eval { require Time::Local }) { # we were given a date too, so determine the local timezone # offset at the specified date/time - my @d = ($3,$2-1,$1-1900); + my @d = ($3,$2-1,$1); $val =~ /(\d{2})(\d{2})(\d{2})/; @tm = ($3,$2,$1,@d); $time = Image::ExifTool::TimeLocal(@tm); @@ -334,13 +334,9 @@ ($$$) # - improves speed # - avoids changing current MD5 digest unnecessarily # - avoids adding mandatory tags unless some other IPTC is changed - unless (exists $$et{EDIT_DIRS}{$$dirInfo{DirName}} or + return undef unless exists $$et{EDIT_DIRS}{$$dirInfo{DirName}} or # standard IPTC tags in other locations should be edited too (eg. AFCP_IPTC) - ($tagTablePtr eq \%Image::ExifTool::IPTC::Main and exists $$et{EDIT_DIRS}{IPTC})) - { - print $out "$$et{INDENT} [nothing changed]\n" if $verbose; - return undef; - } + ($tagTablePtr eq \%Image::ExifTool::IPTC::Main and exists $$et{EDIT_DIRS}{IPTC}); my $dataPt = $$dirInfo{DataPt}; unless ($dataPt) { my $emptyData = ''; @@ -715,7 +711,7 @@ =head1 DESCRIPTION =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/WritePDF.pl b/src/Image-ExifTool/lib/Image/ExifTool/WritePDF.pl index 4d67d99f..98207367 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/WritePDF.pl +++ b/src/Image-ExifTool/lib/Image/ExifTool/WritePDF.pl @@ -293,20 +293,19 @@ ($$) my $newTool = new Image::ExifTool; $newTool->Options(List => 1); $newTool->Options(Password => $et->Options('Password')); + $newTool->Options(NoPDFList => $et->Options('NoPDFList')); $$newTool{PDF_CAPTURE} = \%capture; my $info = $newTool->ImageInfo($raf, 'XMP', 'PDF:*', 'Error', 'Warning'); # not a valid PDF file unless we got a version number # (note: can't just check $$info{PDFVersion} due to possibility of XMP-pdf:PDFVersion) my $vers = $newTool->GetInfo('PDF:PDFVersion'); - ($pdfVer) = values %$vers; + # take highest version number if multiple versions in an incremental save + ($pdfVer) = sort { $b <=> $a } values %$vers; $pdfVer or $et->Error('Missing PDF:PDFVersion'), return 0; # check version number if ($pdfVer > 1.7) { - if ($pdfVer >= 2.0) { - $et->Error("Can't yet write PDF version $pdfVer"); # (future major version changes) - return 1; - } - $et->Warn("ExifTool is untested with PDF version $pdfVer files", 1); + $et->Warn("The PDF $pdfVer specification is not freely available", 1); + # (so writing by ExifTool is based on trial and error) } # fail if we had any serious errors while extracting information if ($capture{Error} or $$info{Error}) { @@ -751,7 +750,7 @@ =head1 NOTES =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/WritePNG.pl b/src/Image-ExifTool/lib/Image/ExifTool/WritePNG.pl index 0e89331b..9fbb5d57 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/WritePNG.pl +++ b/src/Image-ExifTool/lib/Image/ExifTool/WritePNG.pl @@ -13,7 +13,7 @@ package Image::ExifTool::PNG; #------------------------------------------------------------------------------ # Calculate CRC or update running CRC (ref 1) -# Inputs: 0) data reference, 1) running crc to update (undef intially) +# Inputs: 0) data reference, 1) running crc to update (undef initially) # 2) data position (undef for 0), 3) data length (undef for all data), # Returns: updated CRC my @crcTable; @@ -61,7 +61,7 @@ ($) #------------------------------------------------------------------------------ # Write profile chunk (possibly compressed if Zlib is available) -# Inputs: 0) outfile, 1) Raw profile type, 2) data ref +# Inputs: 0) outfile, 1) Raw profile type (SCALAR ref for iCCP name), 2) data ref # 3) profile header type (undef if not a text profile) # Returns: 1 on success sub WriteProfile($$$;$) @@ -73,16 +73,16 @@ ($$$;$) } if (not defined $profile) { # write ICC profile as compressed iCCP chunk if possible - if ($rawType eq 'icm') { + if (ref $rawType) { return 0 unless $deflate; $chunk = 'iCCP'; - $prefix = "$rawType\0\0"; + $prefix = "$$rawType\0\0"; } else { $chunk = $rawType; if ($rawType eq $stdCase{zxif}) { - $prefix = "\0" . pack('N', length $$dataPt); + $prefix = "\0" . pack('N', length $$dataPt); # (proposed compressed EXIF) } else { - $prefix = ''; + $prefix = ''; # standard EXIF } } if ($deflate) { @@ -116,7 +116,7 @@ ($$$;$) } #------------------------------------------------------------------------------ -# Add iCCP to the PNG image if necessary (must come before PLTE and IDAT) +# Add iCCP-related chunks to the PNG image if necessary (must come before PLTE and IDAT) # Inputs: 0) ExifTool object ref, 1) output file or scalar ref # Returns: true on success sub Add_iCCP($$) @@ -127,10 +127,28 @@ ($$) my $tagTablePtr = Image::ExifTool::GetTagTable('Image::ExifTool::ICC_Profile::Main'); my %dirInfo = ( Parent => 'PNG', DirName => 'ICC_Profile' ); my $buff = $et->WriteDirectory(\%dirInfo, $tagTablePtr); - if (defined $buff and length $buff and WriteProfile($outfile, 'icm', \$buff)) { - $et->VPrint(0, "Created ICC profile\n"); - delete $$et{ADD_DIRS}{ICC_Profile}; # don't add it again - $$et{PNGDoneDir}{ICC_Profile} = 2; + if (defined $buff and length $buff) { + my $profileName = $et->GetNewValue($Image::ExifTool::PNG::Main{'iCCP-name'}); + $profileName = 'icm' unless defined $profileName; + if (WriteProfile($outfile, \$profileName, \$buff)) { + $et->VPrint(0, "Created ICC profile with name '${profileName}'\n"); + delete $$et{ADD_DIRS}{ICC_Profile}; # don't add it again + } + } + } + # must also add sRGB and gAMA before PLTE and IDAT + if ($$et{ADD_PNG}) { + my ($tag, %addBeforePLTE); + foreach $tag (qw(sRGB gAMA)) { + next unless $$et{ADD_PNG}{$tag}; + $addBeforePLTE{$tag} = $$et{ADD_PNG}{$tag}; + delete $$et{ADD_PNG}{$tag}; + } + if (%addBeforePLTE) { + my $save = $$et{ADD_PNG}; + $$et{ADD_PNG} = \%addBeforePLTE; + AddChunks($et, $outfile); + $$et{ADD_PNG} = $save; } } return 1; @@ -144,29 +162,15 @@ ($$) sub DoneDir($$$;$) { my ($et, $dir, $outBuff, $nonStandard) = @_; - $dir = 'IFD0' if $dir eq 'EXIF'; + my $saveDir = $dir; + $dir = 'EXIF' if $dir eq 'IFD0'; # don't add this directory again unless this is in a non-standard location - delete $$et{ADD_DIRS}{$dir} unless $nonStandard; - # handle problem with duplicate XMP when using PNGEarlyXMP option - return unless $dir eq 'XMP' and defined $$outBuff and length $$outBuff; - if ($nonStandard and $$et{DEL_GROUP}{$dir}) { + if (not $nonStandard) { + delete $$et{ADD_DIRS}{$dir}; + delete $$et{ADD_DIRS}{IFD0} if $dir eq 'EXIF'; + } elsif ($$et{DEL_GROUP}{$dir} or $$et{DEL_GROUP}{$saveDir}) { $et->VPrint(0," Deleting non-standard $dir\n"); $$outBuff = ''; - } elsif (not $$et{PNGDoneDir}{$dir}) { - $$et{PNGDoneDir}{$dir} = 1; # set flag indicating the directory exists - } elsif ($$et{OPTIONS}{PNGEarlyXMP}) { - if ($$et{PNGDoneDir}{$dir} == 2) { - if ($$et{OPTIONS}{IgnoreMinorErrors}) { - $et->Warn("Deleted existing $dir"); - } else { - $et->Error("Duplicate $dir created. Ignore to delete existing $dir", 1); - return; - } - } elsif ($et->Warn("Duplicate $dir. Ignore to delete", 2)) { - return; # warning not ignored: don't delete the duplicate - } - $et->VPrint(0," Deleting duplicate $dir\n"); - $$outBuff = ''; } } @@ -194,6 +198,8 @@ ($$$$$) $tag =~ s/-$lang$//; # remove language code from tagID } elsif ($$et{OPTIONS}{Charset} ne 'Latin' and $val =~ /[\x80-\xff]/) { $iTXt = 1; # write as iTXt if it contains non-Latin special characters + } elsif ($$tagInfo{iTXt}) { + $iTXt = 1; # write as iTXt if specified in user-defined tag } } if ($comp) { @@ -238,15 +244,16 @@ ($$$$$) #------------------------------------------------------------------------------ # Add any outstanding new chunks to the PNG image # Inputs: 0) ExifTool object ref, 1) output file or scalar ref -# 2-N) dirs to add (empty to add all, including PNG tags) +# 2-N) dirs to add (empty to add all except EXIF 'IFD0', including PNG tags) # Returns: true on success sub AddChunks($$;@) { my ($et, $outfile, @add) = @_; - my ($addTags, $tag, $dir, $err, $tagTablePtr); + my ($addTags, $tag, $dir, $err, $tagTablePtr, $specified); if (@add) { $addTags = { }; # don't add any PNG tags + $specified = 1; } else { $addTags = $$et{ADD_PNG}; # add all PNG tags... delete $$et{ADD_PNG}; # ...once @@ -256,9 +263,10 @@ ($$;@) # write any outstanding PNG tags foreach $tag (sort keys %$addTags) { my $tagInfo = $$addTags{$tag}; + next if $$tagInfo{FakeTag}; # (iCCP-name) my $nvHash = $et->GetNewValueHash($tagInfo); - # (native PNG information is always preferred, so don't check IsCreating) - next unless $et->IsOverwriting($nvHash); + # (native PNG information is always preferred, so don't rely on just IsCreating) + next unless $$nvHash{IsCreating} or $et->IsOverwriting($nvHash) > 0; my $val = $et->GetNewValue($nvHash); if (defined $val) { next if $$nvHash{EditOnly}; @@ -274,7 +282,6 @@ ($$;@) my $cbuf = pack('N', CalculateCRC(\$data, undef)); Write($outfile, $hdr, $data, $cbuf) or $err = 1; $et->VerboseValue("+ PNG:$$tagInfo{Name}", $val); - $$et{PNGDoneTag}{$tag} = 1; # set flag indicating this tag was added ++$$et{CHANGED}; } } @@ -287,6 +294,7 @@ ($$;@) DirName => $dir, ); if ($dir eq 'IFD0') { + next unless $specified; # wait until specifically asked to write EXIF 'IFD0' my $chunk = $stdCase{exif}; # (zxIf was not adopted) #if ($et->Options('Compress')) { @@ -322,7 +330,7 @@ ($$;@) Write($outfile, $hdr, $buff, $cbuf) or $err = 1; } } elsif ($dir eq 'IPTC') { - $et->Warn('Creating non-standard EXIF in PNG', 1); + $et->Warn('Creating non-standard IPTC in PNG', 1); $et->VPrint(0, "Creating IPTC profile:\n"); # write new IPTC data (stored in a Photoshop directory) $dirInfo{DirName} = 'Photoshop'; @@ -341,7 +349,7 @@ ($$;@) $et->Warn('Wrote ICC as a raw profile (no Compress::Zlib)'); } } elsif ($dir eq 'PNG-pHYs') { - $et->VPrint(0, "Creating pHYs chunk:\n"); + $et->VPrint(0, "Creating pHYs chunk (default 2834 pixels per meter):\n"); $tagTablePtr = Image::ExifTool::GetTagTable('Image::ExifTool::PNG::PhysicalPixel'); my $blank = "\0\0\x0b\x12\0\0\x0b\x12\x01"; # 2834 pixels per meter (72 dpi) $dirInfo{DataPt} = \$blank; @@ -356,8 +364,6 @@ ($$;@) next; } delete $$et{ADD_DIRS}{$dir}; # don't add again - # keep track of the directories that we added - $$et{PNGDoneDir}{$dir} = 2 if defined $buff and length $buff; } return not $err; } @@ -395,7 +401,7 @@ =head1 NOTES =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/WritePhotoshop.pl b/src/Image-ExifTool/lib/Image/ExifTool/WritePhotoshop.pl index 2623709e..07f60c84 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/WritePhotoshop.pl +++ b/src/Image-ExifTool/lib/Image/ExifTool/WritePhotoshop.pl @@ -138,9 +138,13 @@ ($$$) unless ($tagInfo) { # process subdirectory anyway if writable (except EXIF to avoid recursion) # --> this allows IPTC to be processed if found here in TIFF images + # (but allow EXIF to be written in PSD files if XMP or IPTC tags are + # being written because I have seen cases of XMP in PSD-EXIFInfo-IFD0 + # and IPTC in PSD-EXIFInfo-IFD0-IPTC, see forum10768 and forum13198) my $tmpInfo = $et->GetTagInfo($tagTablePtr, $tagID); if ($tmpInfo and $$tmpInfo{SubDirectory} and - $tmpInfo->{SubDirectory}->{TagTable} ne 'Image::ExifTool::Exif::Main') + ($tmpInfo->{SubDirectory}->{TagTable} ne 'Image::ExifTool::Exif::Main' or + ($$et{FILE_TYPE} eq 'PSD' and ($$editDirs{0x0404} or $$editDirs{0x0424})))) { my $table = Image::ExifTool::GetTagTable($tmpInfo->{SubDirectory}->{TagTable}); $tagInfo = $tmpInfo if $$table{WRITE_PROC}; @@ -253,7 +257,7 @@ =head1 NOTES =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/WritePostScript.pl b/src/Image-ExifTool/lib/Image/ExifTool/WritePostScript.pl index 6bc96fbc..d78fa9a0 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/WritePostScript.pl +++ b/src/Image-ExifTool/lib/Image/ExifTool/WritePostScript.pl @@ -59,6 +59,7 @@ package Image::ExifTool::PostScript; Photoshop => 'PostScript', IPTC => 'Photoshop', EXIFInfo => 'Photoshop', + EXIF => 'EXIFInfo', IFD0 => 'EXIFInfo', IFD1 => 'IFD0', ICC_Profile => 'PostScript', @@ -156,11 +157,11 @@ ($$$$$) # it would be really difficult to delete the XMP, # so instead we write a blank XMP record $val = <<EMPTY_XMP; -<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?> +<?xpacket begin='\xef\xbb\xbf' id='W5M0MpCehiHzreSzNTczkc9d'?> <x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool $Image::ExifTool::VERSION'> </x:xmpmeta> EMPTY_XMP - $val .= ((' ' x 100) . "\n") x 24 unless $et->Options('Compact'); + $val .= ((' ' x 100) . "\n") x 24 unless $$et{OPTIONS}{Compact}{NoPadding}; $val .= q{<?xpacket end='w'?>}; $dataPt = \$val; $len = length $val; @@ -302,54 +303,6 @@ ($$$) return $success; } -#------------------------------------------------------------------------------ -# check to be sure we haven't read past end of PS data in DOS-style file -# Inputs: 0) RAF ref, 1) pointer to end of PS, 2) data -# - modifies data and sets RAF to EOF if end of PS is reached -sub CheckPSEnd($$$) -{ - my $pos = $_[0]->Tell(); - if ($pos >= $_[1]) { - $_[0]->Seek(0, 2); # seek to end of file so we can't read any more - $_[2] = substr($_[2], 0, length($_[2]) - $pos + $_[1]) if $pos > $_[1]; - } -} - -#------------------------------------------------------------------------------ -# Split into lines ending in any CR, LF or CR+LF combination -# (this is annoying, and could be avoided if EPS files didn't mix linefeeds!) -# Inputs: 0) data pointer, 1) reference to lines array -# Notes: Updates data to contain next line and fills list with remaining lines -sub SplitLine($$) -{ - my ($dataPt, $lines) = @_; - for (;;) { - my $endl; - # find the position of the first LF (\x0a) - $endl = pos($$dataPt), pos($$dataPt) = 0 if $$dataPt =~ /\x0a/g; - if ($$dataPt =~ /\x0d/g) { # find the first CR (\x0d) - if (defined $endl) { - # (remember, CR+LF is a DOS newline...) - $endl = pos($$dataPt) if pos($$dataPt) < $endl - 1; - } else { - $endl = pos($$dataPt); - } - } elsif (not defined $endl) { - push @$lines, $$dataPt; - last; - } - # split into separate lines - if (length $$dataPt == $endl) { - push @$lines, $$dataPt; - last; - } else { - push @$lines, substr($$dataPt, 0, $endl); - $$dataPt = substr($$dataPt, $endl); - } - } - $$dataPt = shift @$lines; # set $$dataPt to first line -} - #------------------------------------------------------------------------------ # Write PS file # Inputs: 0) ExifTool object reference, 1) source dirInfo reference @@ -365,7 +318,7 @@ ($$) my $verbose = $et->Options('Verbose'); my $out = $et->Options('TextOut'); my ($data, $buff, %flags, $err, $mode, $endToken); - my ($dos, $psStart, $psEnd, $psNewStart, $xmpHint); + my ($dos, $psStart, $psNewStart, $xmpHint, @lines); $raf->Read($data, 4) == 4 or return 0; return 0 unless $data =~ /^(%!PS|%!Ad|\xc5\xd0\xd3\xc6)/; @@ -390,7 +343,7 @@ ($$) $et->Error('Invalid PS header'); return 1; } - $psEnd = $psStart + Get32u(\$dos, 8); + $$raf{PSEnd} = $psStart + Get32u(\$dos, 8); my $base = Get32u(\$dos, 20); Set16u(0xffff, \$dos, 28); # ignore checksum if ($base) { @@ -465,34 +418,9 @@ ($$) $xmpHint = 0 if $$et{DEL_GROUP}{XMP}; $$newTags{XMP_HINT} = $xmpHint if $xmpHint; # add special tag to newTags list - my (@lines, $changedNL); - my $altnl = ($/ eq "\x0d") ? "\x0a" : "\x0d"; - for (;;) { - if (@lines) { - $data = shift @lines; - } else { - $raf->ReadLine($data) or last; - $dos and CheckPSEnd($raf, $psEnd, $data); - # split line if it contains other newline sequences - if ($data =~ /$altnl/) { - if (length($data) > 500000 and IsPC()) { - # patch for Windows memory problem - unless ($changedNL) { - $changedNL = 1; - my $t = $/; - $/ = $altnl; - $altnl = $t; - $raf->Seek(-length($data), 1); - next; - } - } else { - # split into separate lines - SplitLine(\$data, \@lines); - } - } - } - undef $changedNL; + @lines or GetNextLine($raf, \@lines) or last; + $data = shift @lines; if ($endToken) { # look for end token if ($data =~ m/^$endToken\s*$/is) { @@ -641,7 +569,7 @@ ($$) $data = shift @lines; } else { $raf->ReadLine($data) or undef($data), last; - $dos and CheckPSEnd($raf, $psEnd, $data); + $dos and CheckPSEnd($raf, \$data); if ($data =~ /[\x0d\x0a]%%EOF\b/g) { # split data before "%%EOF" # (necessary if data contains other newline sequences) @@ -659,7 +587,7 @@ ($$) Write($outfile, $data) or $err = 1; Write($outfile, @lines) or $err = 1 if @lines; while ($raf->Read($data, 65536)) { - $dos and CheckPSEnd($raf, $psEnd, $data); + $dos and CheckPSEnd($raf, \$data); Write($outfile, $data) or $err = 1; } } @@ -759,7 +687,7 @@ =head1 ACKNOWLEDGEMENTS =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/WriteQuickTime.pl b/src/Image-ExifTool/lib/Image/ExifTool/WriteQuickTime.pl index a52f1f79..fbfa0d3c 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/WriteQuickTime.pl +++ b/src/Image-ExifTool/lib/Image/ExifTool/WriteQuickTime.pl @@ -9,33 +9,744 @@ package Image::ExifTool::QuickTime; use strict; -# map for adding directories to QuickTime-format files +# maps for adding metadata to various QuickTime-based file types my %movMap = ( - # MOV (no 'ftyp', or 'ftyp'='qt ') -> 'moov'-'udta'-'XMP_' - XMP => 'UserData', - UserData => 'Movie', - Movie => 'MOV', + # MOV (no 'ftyp', or 'ftyp'='qt ') -> XMP in 'moov'-'udta'-'XMP_' + QuickTime => 'ItemList', # (default location for QuickTime tags) + ItemList => 'Meta', # MOV-Movie-UserData-Meta-ItemList + Keys => 'Movie', # MOV-Movie-Meta-Keys !! (hack due to different Meta location) + Meta => 'UserData', + XMP => 'UserData', # MOV-Movie-UserData-XMP + Microsoft => 'UserData', # MOV-Movie-UserData-Microsoft + UserData => 'Movie', # MOV-Movie-UserData + Movie => 'MOV', + GSpherical => 'SphericalVideoXML', # MOV-Movie-Track-SphericalVideoXML + SphericalVideoXML => 'Track', # (video track specifically, don't create if it doesn't exist) + Track => 'Movie', ); my %mp4Map = ( - # MP4 ('ftyp' compatible brand 'mp41', 'mp42' or 'f4v ') -> top level 'uuid' - XMP => 'MOV', + # MP4 ('ftyp' compatible brand 'mp41', 'mp42' or 'f4v ') -> XMP at top level + QuickTime => 'ItemList', # (default location for QuickTime tags) + ItemList => 'Meta', # MOV-Movie-UserData-Meta-ItemList + Keys => 'Movie', # MOV-Movie-Meta-Keys !! (hack due to different Meta location) + Meta => 'UserData', + UserData => 'Movie', # MOV-Movie-UserData + Microsoft => 'UserData', # MOV-Movie-UserData-Microsoft + Movie => 'MOV', + XMP => 'MOV', # MOV-XMP + GSpherical => 'SphericalVideoXML', # MOV-Movie-Track-SphericalVideoXML + SphericalVideoXML => 'Track', # (video track specifically, don't create if it doesn't exist) + Track => 'Movie', +); +my %heicMap = ( + # HEIC/HEIF/AVIF ('ftyp' compatible brand 'heic','mif1','avif') -> XMP/EXIF in top level 'meta' + Meta => 'MOV', + ItemInformation => 'Meta', + ItemPropertyContainer => 'Meta', + XMP => 'ItemInformation', + EXIF => 'ItemInformation', + ICC_Profile => 'ItemPropertyContainer', + IFD0 => 'EXIF', + IFD1 => 'IFD0', + ExifIFD => 'IFD0', + GPS => 'IFD0', + SubIFD => 'IFD0', + GlobParamIFD => 'IFD0', + PrintIM => 'IFD0', + InteropIFD => 'ExifIFD', + MakerNotes => 'ExifIFD', +); +my %cr3Map = ( + # CR3 ('ftyp' compatible brand 'crx ') -> XMP at top level + Movie => 'MOV', + XMP => 'MOV', + 'UUID-Canon'=>'Movie', + ExifIFD => 'UUID-Canon', + IFD0 => 'UUID-Canon', + GPS => 'UUID-Canon', + #MakerNoteCanon => 'UUID-Canon', # (doesn't yet work -- goes into ExifIFD instead) + 'UUID-Canon2' => 'MOV', + CanonVRD => 'UUID-Canon2', ); my %dirMap = ( - MOV => \%movMap, - MP4 => \%mp4Map, - HEIC => { }, # can't currently write XMP to HEIC files + MOV => \%movMap, + MP4 => \%mp4Map, + CR3 => \%cr3Map, + HEIC => \%heicMap, +); + +# convert ExifTool Format to QuickTime type +my %qtFormat = ( + 'undef' => 0x00, string => 0x01, + int8s => 0x15, int16s => 0x15, int32s => 0x15, int64s => 0x15, + int8u => 0x16, int16u => 0x16, int32u => 0x16, int64u => 0x16, + float => 0x17, double => 0x18, +); +my $undLang = 0x55c4; # numeric code for default ('und') language + +my $maxReadLen = 100000000; # maximum size of atom to read into memory (100 MB) + +# boxes that may exist in an "empty" Meta box: +my %emptyMeta = ( + hdlr => 'Handler', 'keys' => 'Keys', lang => 'Language', ctry => 'Country', free => 'Free', ); +# lookup for CTBO ID number based on uuid for Canon CR3 files +my %ctboID = ( + "\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac" => 1, # XMP + "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16" => 2, # PreviewImage + # ID 3 is used for 'mdat' atom (not a uuid) +); + +# mark UserData tags that don't have ItemList counterparts as Preferred +# - and set Preferred to 0 for any Avoid-ed tag +# - also, for now, set Writable to 0 for any tag with a RawConv and no RawConvInv +{ + my $itemList = \%Image::ExifTool::QuickTime::ItemList; + my $userData = \%Image::ExifTool::QuickTime::UserData; + my (%pref, $tag); + foreach $tag (TagTableKeys($itemList)) { + my $tagInfo = $$itemList{$tag}; + if (ref $tagInfo ne 'HASH') { + next if ref $tagInfo; + $tagInfo = $$itemList{$tag} = { Name => $tagInfo }; + } else { + $$tagInfo{Writable} = 0 if $$tagInfo{RawConv} and not $$tagInfo{RawConvInv}; + $$tagInfo{Avoid} and $$tagInfo{Preferred} = 0, next; + next if defined $$tagInfo{Preferred} and not $$tagInfo{Preferred}; + } + $pref{$$tagInfo{Name}} = 1; + } + foreach $tag (TagTableKeys($userData)) { + my $tagInfo = $$userData{$tag}; + if (ref $tagInfo ne 'HASH') { + next if ref $tagInfo; + $tagInfo = $$userData{$tag} = { Name => $tagInfo }; + } else { + $$tagInfo{Writable} = 0 if $$tagInfo{RawConv} and not $$tagInfo{RawConvInv}; + $$tagInfo{Avoid} and $$tagInfo{Preferred} = 0, next; + next if defined $$tagInfo{Preferred} or $pref{$$tagInfo{Name}}; + } + $$tagInfo{Preferred} = 1; + } +} + +#------------------------------------------------------------------------------ +# Format GPSCoordinates for writing +# Inputs: 0) PrintConv value +# Returns: ValueConv value +sub PrintInvGPSCoordinates($) +{ + my ($val, $et) = @_; + my @v = split /, */, $val; + if (@v == 2 or @v == 3) { + my $below = ($v[2] and $v[2] =~ /below/i); + $v[0] = Image::ExifTool::GPS::ToDegrees($v[0], 1); + $v[1] = Image::ExifTool::GPS::ToDegrees($v[1], 1); + $v[2] = Image::ExifTool::ToFloat($v[2]) * ($below ? -1 : 1) if @v == 3; + return "@v"; + } + return $val if $val =~ /^([-+]\d+(\.\d*)?){2,3}(CRS.*)?\/?$/; # already in ISO6709 format? + return undef; +} + #------------------------------------------------------------------------------ -# Check to see if path is current -# Inputs: 0) ExifTool object ref, 1) directory name -# Returns: true if current path is the root of the specified directory -sub IsCurPath($$) +# Convert GPS coordinates back to ISO6709 format +# Inputs: 0) ValueConv value +# Returns: ISO6709 coordinates +sub ConvInvISO6709($) { local $_; - my ($et, $dir) = @_; - $dir = $$et{DirMap}{$dir} and $dir eq $_ or last foreach reverse @{$$et{PATH}}; - return($dir and $dir eq 'MOV'); + my $val = shift; + my @a = split ' ', $val; + if (@a == 2 or @a == 3) { + # latitude must have 2 digits before the decimal, and longitude 3, + # and all values must start with a "+" or "-", and Google Photos + # requires at least 3 digits after the decimal point + # (and as of Apr 2021, Google Photos doesn't accept coordinats + # with more than 5 digits after the decimal place: + # https://exiftool.org/forum/index.php?topic=11055.msg67171#msg67171 ) + my @fmt = ('%s%02d.%s%s','%s%03d.%s%s','%s%d.%s%s'); + foreach (@a) { + return undef unless Image::ExifTool::IsFloat($_); + $_ =~ s/^([-+]?)(\d+)\.?(\d*)/sprintf(shift(@fmt),$1||'+',$2,$3,length($3)<3 ? '0'x(3-length($3)) : '')/e; + } + return join '', @a, '/'; + } + return $val if $val =~ /^([-+]\d+(\.\d*)?){2,3}(CRS.*)?\/?$/; # already in ISO6709 format? + return undef; +} + +#------------------------------------------------------------------------------ +# Handle offsets in iloc (ItemLocation) atom when writing (ref ISO 14496-12:2015 pg.79) +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) data ref, 3) output buffer ref +# Returns: true on success +# Notes: see also ParseItemLocation() in QuickTime.pm +# (variable names with underlines correspond to names in ISO 14496-12) +sub Handle_iloc($$$$) +{ + my ($et, $dirInfo, $dataPt, $outfile) = @_; + my ($i, $j, $num, $pos, $id); + + my $off = $$dirInfo{ChunkOffset}; + my $len = length $$dataPt; + return 0 if $len < 8; + my $ver = Get8u($dataPt, 0); + my $siz = Get16u($dataPt, 4); + my $noff = ($siz >> 12); + my $nlen = ($siz >> 8) & 0x0f; + my $nbas = ($siz >> 4) & 0x0f; + my $nind = $siz & 0x0f; + my %ok = ( 0 => 1, 4 => 1, 8 => 8 ); + return 0 unless $ok{$noff} and $ok{$nlen} and $ok{$nbas} and $ok{$nind}; + # piggy-back on existing code to fix up stco/co64 4/8-byte offsets + my $tag = $noff == 4 ? 'stco_iloc' : 'co64_iloc'; + if ($ver < 2) { + $num = Get16u($dataPt, 6); + $pos = 8; + } else { + return 0 if $len < 10; + $num = Get32u($dataPt, 6); + $pos = 10; + } + for ($i=0; $i<$num; ++$i) { + if ($ver < 2) { + return 0 if $pos + 2 > $len; + $id = Get16u($dataPt, $pos); + $pos += 2; + } else { + return 0 if $pos + 4 > $len; + $id = Get32u($dataPt, $pos); + $pos += 4; + } + my ($constOff, @offBase, @offItem, $minOffset); + if ($ver == 1 or $ver == 2) { + return 0 if $pos + 2 > $len; + # offsets are absolute only if ConstructionMethod is 0, otherwise + # the relative offsets are constant as far as we are concerned + $constOff = Get16u($dataPt, $pos) & 0x0f; + $pos += 2; + } + return 0 if $pos + 2 > $len; + my $drefIdx = Get16u($dataPt, $pos); + if ($drefIdx) { + if ($$et{QtDataRef} and $$et{QtDataRef}[$drefIdx - 1]) { + my $dref = $$et{QtDataRef}[$drefIdx - 1]; + # these offsets are constant unless the data is in this file + $constOff = 1 unless $$dref[1] == 1 and $$dref[0] ne 'rsrc'; + } else { + $et->Error("No data reference for iloc entry $i"); + return 0; + } + } + $pos += 2; + # get base offset and save its location if in this file + my $base_offset = GetVarInt($dataPt, $pos, $nbas); + if ($base_offset and not $constOff) { + my $tg = ($nbas == 4 ? 'stco' : 'co64') . '_iloc'; + push @offBase, [ $tg, length($$outfile) + 8 + $pos - $nbas, $nbas, 0, $id ]; + } + return 0 if $pos + 2 > $len; + my $ext_num = Get16u($dataPt, $pos); + $pos += 2; + my $listStartPos = $pos; + # run through the item list to get offset locations and the minimum offset in this file + for ($j=0; $j<$ext_num; ++$j) { + $pos += $nind if $ver == 1 or $ver == 2; + my $extent_offset = GetVarInt($dataPt, $pos, $noff); + return 0 unless defined $extent_offset; + unless ($constOff) { + push @offItem, [ $tag, length($$outfile) + 8 + $pos - $noff, $noff, 0, $id ] if $noff; + $minOffset = $extent_offset if not defined $minOffset or $minOffset > $extent_offset; + } + return 0 if $pos + $nlen > length $$dataPt; + $pos += $nlen; + } + # decide whether to fix up the base offset or individual item offsets + # (adjust the one that is larger) + if (defined $minOffset and $minOffset > $base_offset) { + $$_[3] = $base_offset foreach @offItem; + push @$off, @offItem; + } else { + $$_[3] = $minOffset foreach @offBase; + push @$off, @offBase; + } + } + return 1; +} + +#------------------------------------------------------------------------------ +# Get localized version of tagInfo hash +# Inputs: 0) tagInfo hash ref, 1) language code (eg. "fra-FR") +# Returns: new tagInfo hash ref, or undef if invalid or no language code +sub GetLangInfo($$) +{ + my ($tagInfo, $langCode) = @_; + return undef unless $langCode; + # only allow alternate language tags in lang-alt lists + my $writable = $$tagInfo{Writable}; + $writable = $$tagInfo{Table}{WRITABLE} unless defined $writable; + return undef unless $writable; + $langCode =~ tr/_/-/; # RFC 3066 specifies '-' as a separator + my $langInfo = Image::ExifTool::GetLangInfo($tagInfo, $langCode); + return $langInfo; +} + +#------------------------------------------------------------------------------ +# validate raw values for writing +# Inputs: 0) ExifTool ref, 1) tagInfo hash ref, 2) raw value ref +# Returns: error string or undef (and possibly changes value) on success +sub CheckQTValue($$$) +{ + my ($et, $tagInfo, $valPtr) = @_; + my $format = $$tagInfo{Format} || $$tagInfo{Writable} || $$tagInfo{Table}{FORMAT}; + return undef unless $format; + return Image::ExifTool::CheckValue($valPtr, $format, $$tagInfo{Count}); +} + +#------------------------------------------------------------------------------ +# Format QuickTime value for writing +# Inputs: 0) ExifTool ref, 1) value ref, 2) Format (or undef), 3) Writable (or undef) +# Returns: Flags for QT data type, and reformats value as required +sub FormatQTValue($$;$$) +{ + my ($et, $valPt, $format, $writable) = @_; + my $flags; + if ($format and $format ne 'string' or not $format and $writable and $writable ne 'string') { + $$valPt = WriteValue($$valPt, $format || $writable); + if ($writable and $qtFormat{$writable}) { + $flags = $qtFormat{$writable}; + } else { + $flags = $qtFormat{$format || 0} || 0; + } + } elsif ($$valPt =~ /^\xff\xd8\xff/) { + $flags = 0x0d; # JPG + } elsif ($$valPt =~ /^(\x89P|\x8aM|\x8bJ)NG\r\n\x1a\n/) { + $flags = 0x0e; # PNG + } elsif ($$valPt =~ /^BM.{15}\0/s) { + $flags = 0x1b; # BMP + } else { + $flags = 0x01; # UTF8 + $$valPt = $et->Encode($$valPt, 'UTF8'); + } + return $flags; +} + +#------------------------------------------------------------------------------ +# Set variable-length integer (used by WriteItemInfo) +# Inputs: 0) value, 1) integer size in bytes (0, 4 or 8), +# Returns: packed integer +sub SetVarInt($$) +{ + my ($val, $n) = @_; + if ($n == 4) { + return Set32u($val); + } elsif ($n == 8) { + return Set64u($val); + } + return ''; +} + +#------------------------------------------------------------------------------ +# Write Meta Keys to add/delete entries as necessary ('mdta' handler) (ref PH) +# Inputs: 0) ExifTool object ref, 1) dirInfo ref, 2) tag table ref +# Returns: updated keys box data +sub WriteKeys($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + $et or return 1; # allow dummy access to autoload this package + my $dataPt = $$dirInfo{DataPt}; + my $dirLen = length $$dataPt; + my $outfile = $$dirInfo{OutFile}; + my ($tag, %done, %remap, %info, %add, $i); + + $dirLen < 8 and $et->Warn('Short Keys box'), $dirLen = 8, $$dataPt = "\0" x 8; + if ($$et{DEL_GROUP}{Keys}) { + $dirLen = 8; # delete all existing keys + # deleted keys are identified by a zero entry in the Remap lookup + my $n = Get32u($dataPt, 4); + for ($i=1; $i<=$n; ++$i) { $remap{$i} = 0; } + $et->VPrint(0, " [deleting $n Keys entr".($n==1 ? 'y' : 'ies')."]\n"); + ++$$et{CHANGED}; + } + my $pos = 8; + my $newTags = $et->GetNewTagInfoHash($tagTablePtr); + my $newData = substr($$dataPt, 0, $pos); + + my $newIndex = 1; + my $index = 1; + while ($pos < $dirLen - 4) { + my $len = unpack("x${pos}N", $$dataPt); + last if $len < 8 or $pos + $len > $dirLen; + my $ns = substr($$dataPt, $pos + 4, 4); + $tag = substr($$dataPt, $pos + 8, $len - 8); + $tag =~ s/\0.*//s; # truncate at null + $tag =~ s/^com\.apple\.quicktime\.// if $ns eq 'mdta'; # remove apple quicktime domain + $tag = "Tag_$ns" unless $tag; + $done{$tag} = 1; # set flag to avoid creating this tag + my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); + if ($tagInfo) { + $info{$index} = $tagInfo; + if ($$newTags{$tag}) { + my $nvHash = $et->GetNewValueHash($tagInfo); + # drop this tag if it is being deleted + if ($nvHash and $et->IsOverwriting($nvHash) > 0 and not defined $et->GetNewValue($nvHash)) { + # don't delete this key if we could be writing any alternate-language version of this tag + my ($t, $dontDelete); + foreach $t (keys %$newTags) { + next unless $$newTags{$t}{SrcTagInfo} and $$newTags{$t}{SrcTagInfo} eq $tagInfo; + my $nv = $et->GetNewValueHash($$newTags{$t}); + next unless $et->IsOverwriting($nv) and defined $et->GetNewValue($nv); + $dontDelete = 1; + last; + } + unless ($dontDelete) { + # delete this key + $et->VPrint(1, "$$et{INDENT}\[deleting Keys entry $index '${tag}']\n"); + $pos += $len; + $remap{$index++} = 0; + ++$$et{CHANGED}; + next; + } + } + } + } + # add to the Keys box data + $newData .= substr($$dataPt, $pos, $len); + $remap{$index++} = $newIndex++; + $pos += $len; + } + # add keys for any tags we need to create + foreach $tag (sort keys %$newTags) { + my $tagInfo = $$newTags{$tag}; + my $id; + if ($$tagInfo{LangCode} and $$tagInfo{SrcTagInfo}) { + $id = $$tagInfo{SrcTagInfo}{TagID}; + } else { + $id = $tag; + } + next if $done{$id}; + my $nvHash = $et->GetNewValueHash($tagInfo); + next unless $$nvHash{IsCreating} and $et->IsOverwriting($nvHash) and + defined $et->GetNewValue($nvHash); + # add new entry to 'keys' data + my $val = $id =~ /^com\./ ? $id : "com.apple.quicktime.$id"; + $newData .= Set32u(8 + length($val)) . 'mdta' . $val; + $et->VPrint(1, "$$et{INDENT}\[adding Keys entry $newIndex '${id}']\n"); + $add{$newIndex++} = $tagInfo; + ++$$et{CHANGED}; + } + my $num = $newIndex - 1; + if ($num) { + Set32u($num, \$newData, 4); # update count in header + } else { + $newData = ''; # delete empty Keys box + } + # save temporary variables for use when writing ItemList: + # Remap - lookup for remapping Keys ID numbers (0 if item is deleted) + # Info - Keys tag information, based on old index value + # Add - Keys items deleted, based on old index value + # Num - Number of items in edited Keys box + $$et{Keys} = { Remap => \%remap, Info => \%info, Add => \%add, Num => $num }; + + return $newData; # return updated Keys box +} + +#------------------------------------------------------------------------------ +# Write ItemInformation in HEIC files +# Inputs: 0) ExifTool ref, 1) dirInfo ref (with BoxPos entry), 2) output buffer ref +# Returns: mdat edit list ref (empty if nothing changed) +sub WriteItemInfo($$$) +{ + my ($et, $dirInfo, $outfile) = @_; + my $boxPos = $$dirInfo{BoxPos}; # hash of [length,position] for each box + my $raf = $$et{RAF}; + my $items = $$et{ItemInfo}; + my (%did, @mdatEdit, $name); + + return () unless $items and $raf; + + # extract information from EXIF/XMP metadata items + my $primary = $$et{PrimaryItem}; + my $curPos = $raf->Tell(); + my $id; + foreach $id (sort { $a <=> $b } keys %$items) { + $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; + # get ExifTool name for this item + $name = { Exif => 'EXIF', 'application/rdf+xml' => 'XMP' }->{$type}; + next unless $name; # only care about EXIF and XMP + next unless $$et{EDIT_DIRS}{$name}; + $did{$name} = 1; # set flag to prevent creating this metadata + my ($warn, $extent, $buff, @edit); + $warn = 'Missing iloc box' unless $$boxPos{iloc}; + $warn = "No Extents for $type item" unless $$item{Extents} and @{$$item{Extents}}; + $warn = "Can't currently decode encoded $type metadata" if $$item{ContentEncoding}; + $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}; + $warn = "$type metadata is not this file" if $$item{DataReferenceIndex}; + $warn and $et->Warn($warn), next; + my $base = $$item{BaseOffset} || 0; + my $val = ''; + foreach $extent (@{$$item{Extents}}) { + $val .= $buff if defined $buff; + my $pos = $$extent[1] + $base; + if ($$extent[2]) { + $raf->Seek($pos, 0) or last; + $raf->Read($buff, $$extent[2]) or last; + } else { + $buff = ''; + } + push @edit, [ $pos, $pos + $$extent[2] ]; # replace or delete this if changed + } + next unless defined $buff; + $buff = $val . $buff if length $val; + my ($hdr, $subTable, $proc); + if ($name eq 'EXIF') { + if (not length $buff) { + # create EXIF from scratch + $hdr = "\0\0\0\x06Exif\0\0"; + } elsif ($buff =~ /^(MM\0\x2a|II\x2a\0)/) { + $et->Warn('Missing Exif header'); + $hdr = ''; + } elsif (length($buff) >= 4 and length($buff) >= 4 + unpack('N',$buff)) { + $hdr = substr($buff, 0, 4 + unpack('N',$buff)); + } else { + $et->Warn('Invalid Exif header'); + next; + } + $subTable = GetTagTable('Image::ExifTool::Exif::Main'); + $proc = \&Image::ExifTool::WriteTIFF; + } else { + $hdr = ''; + $subTable = GetTagTable('Image::ExifTool::XMP::Main'); + } + my %dirInfo = ( + DataPt => \$buff, + DataLen => length $buff, + DirStart => length $hdr, + DirLen => length($buff) - length $hdr, + ); + my $changed = $$et{CHANGED}; + my $newVal = $et->WriteDirectory(\%dirInfo, $subTable, $proc); + if (defined $newVal and $changed ne $$et{CHANGED} and + # nothing changed if deleting an empty directory + ($dirInfo{DirLen} or length $newVal)) + { + $newVal = $hdr . $newVal if length $hdr and length $newVal; + $edit[0][2] = \$newVal; # replace the old chunk with the new data + $edit[0][3] = $id; # mark this chunk with the item ID + push @mdatEdit, @edit; + # update item extent_length + my $n = length $newVal; + foreach $extent (@{$$item{Extents}}) { + my ($nlen, $lenPt) = @$extent[3,4]; + if ($nlen == 8) { + Set64u($n, $outfile, $$boxPos{iloc}[0] + 8 + $lenPt); + } elsif ($n <= 0xffffffff) { + Set32u($n, $outfile, $$boxPos{iloc}[0] + 8 + $lenPt); + } else { + $et->Error("Can't yet promote iloc length to 64 bits"); + return (); + } + $n = 0; + } + if (@{$$item{Extents}} != 1) { + $et->Error("Can't yet handle $name in multiple parts. Please submit sample for testing"); + } + } + $$et{CHANGED} = $changed; # (will set this later if successful in editing mdat) + } + $raf->Seek($curPos, 0); # seek back to original position + + # add necessary metadata types if they didn't already exist + my ($countNew, %add, %usedID); + foreach $name ('EXIF','XMP') { + next if $did{$name} or not $$et{ADD_DIRS}{$name}; + my @missing; + $$boxPos{$_} or push @missing, $_ foreach qw(iinf iloc); + if (@missing) { + my $str = @missing > 1 ? join(' and ', @missing) . ' boxes' : "@missing box"; + $et->Warn("Can't create $name. Missing expected $str"); + last; + } + unless (defined $$et{PrimaryItem}) { + unless (defined $primary) { + $et->Warn("Can't create $name. No items to reference"); + last; + } + # add new primary item reference box after hdrl box + if ($primary < 0x10000) { + $add{hdlr} = pack('Na4Nn', 14, 'pitm', 0, $primary); + } else { + $add{hdlr} = pack('Na4CCCCN', 16, 'pitm', 1, 0, 0, 0, $primary); + } + $et->Warn("Added missing PrimaryItemReference (for item $primary)", 1); + } + my $buff = ''; + my ($hdr, $subTable, $proc); + if ($name eq 'EXIF') { + $hdr = "\0\0\0\x06Exif\0\0"; + $subTable = GetTagTable('Image::ExifTool::Exif::Main'); + $proc = \&Image::ExifTool::WriteTIFF; + } else { + $hdr = ''; + $subTable = GetTagTable('Image::ExifTool::XMP::Main'); + } + my %dirInfo = ( + DataPt => \$buff, + DataLen => 0, + DirStart => 0, + DirLen => 0, + ); + my $changed = $$et{CHANGED}; + my $newVal = $et->WriteDirectory(\%dirInfo, $subTable, $proc); + if (defined $newVal and $changed ne $$et{CHANGED}) { + my $irefVer; + if ($$boxPos{iref}) { + $irefVer = Get8u($outfile, $$boxPos{iref}[0] + 8); + } else { + # create iref box after end of iinf box (and save version in boxPos list) + $irefVer = ($primary < 0x10000 ? 0 : 1); + $$boxPos{iref} = [ $$boxPos{iinf}[0] + $$boxPos{iinf}[1], 0, $irefVer ]; + } + $newVal = $hdr . $newVal if length $hdr; + # add new infe to iinf + $add{iinf} = $add{iref} = $add{iloc} = '' unless defined $add{iinf}; + my ($type, $mime); + if ($name eq 'XMP') { + $type = "mime\0"; + $mime = "application/rdf+xml\0"; + } else { + $type = "Exif\0"; + $mime = ''; + } + my $id = 1; + ++$id while $$items{$id} or $usedID{$id}; # find next unused item ID + my $n = length($type) + length($mime) + 16; + if ($id < 0x10000) { + $add{iinf} .= pack('Na4CCCCnn', $n, 'infe', 2, 0, 0, 1, $id, 0) . $type . $mime; + } else { + $n += 2; + $add{iinf} .= pack('Na4CCCCNn', $n, 'infe', 3, 0, 0, 1, $id, 0) . $type . $mime; + } + # add new cdsc to iref + if ($irefVer) { + $add{iref} .= pack('Na4NnN', 18, 'cdsc', $id, 1, $primary); + } else { + $add{iref} .= pack('Na4nnn', 14, 'cdsc', $id, 1, $primary); + } + # add new entry to iloc table (see ISO14496-12:2015 pg.79) + my $ilocVer = Get8u($outfile, $$boxPos{iloc}[0] + 8); + my $siz = Get16u($outfile, $$boxPos{iloc}[0] + 12); # get size information + my $noff = ($siz >> 12); + my $nlen = ($siz >> 8) & 0x0f; + my $nbas = ($siz >> 4) & 0x0f; + my $nind = $siz & 0x0f; + my ($pbas, $poff); + if ($ilocVer == 0) { + # set offset to 0 as flag that this is a new idat chunk being added + $pbas = length($add{iloc}) + 4; + $poff = $pbas + $nbas + 2; + $add{iloc} .= pack('nn',$id,0) . SetVarInt(0,$nbas) . Set16u(1) . + SetVarInt(0,$noff) . SetVarInt(length($newVal),$nlen); + } elsif ($ilocVer == 1) { + $pbas = length($add{iloc}) + 6; + $poff = $pbas + $nbas + 2 + $nind; + $add{iloc} .= pack('nnn',$id,0,0) . SetVarInt(0,$nbas) . Set16u(1) . SetVarInt(0,$nind) . + SetVarInt(0,$noff) . SetVarInt(length($newVal),$nlen); + } elsif ($ilocVer == 2) { + $pbas = length($add{iloc}) + 8; + $poff = $pbas + $nbas + 2 + $nind; + $add{iloc} .= pack('Nnn',$id,0,0) . SetVarInt(0,$nbas) . Set16u(1) . SetVarInt(0,$nind) . + SetVarInt(0,$noff) . SetVarInt(length($newVal),$nlen); + } else { + $et->Warn("Can't create $name. Unsupported iloc version $ilocVer"); + last; + } + # add new ChunkOffset entry to update this new offset + my $off = $$dirInfo{ChunkOffset} or $et->Warn('Internal error. Missing ChunkOffset'), last; + my $newOff; + if ($noff == 4) { + $newOff = [ 'stco_iloc', $$boxPos{iloc}[0] + $$boxPos{iloc}[1] + $poff, $noff, 0, $id ]; + } elsif ($noff == 8) { + $newOff = [ 'co64_iloc', $$boxPos{iloc}[0] + $$boxPos{iloc}[1] + $poff, $noff, 0, $id ]; + } elsif ($noff == 0) { + # offset_size is zero, so store the offset in base_offset instead + if ($nbas == 4) { + $newOff = [ 'stco_iloc', $$boxPos{iloc}[0] + $$boxPos{iloc}[1] + $pbas, $nbas, 0, $id ]; + } elsif ($nbas == 8) { + $newOff = [ 'co64_iloc', $$boxPos{iloc}[0] + $$boxPos{iloc}[1] + $pbas, $nbas, 0, $id ]; + } else { + $et->Warn("Can't create $name. Invalid iloc offset+base size"); + last; + } + } else { + $et->Warn("Can't create $name. Invalid iloc offset size"); + last; + } + # add directory as a new mdat chunk + push @$off, $newOff; + push @mdatEdit, [ 0, 0, \$newVal, $id ]; + $usedID{$id} = 1; + $countNew = ($countNew || 0) + 1; + $$et{CHANGED} = $changed; # set this later if successful in editing mdat + } + } + if ($countNew) { + # insert new entries into iinf, iref and iloc boxes, + # and add new pitm box after hdlr if necessary + my $added = 0; + my $tag; + foreach $tag (sort { $$boxPos{$a}[0] <=> $$boxPos{$b}[0] } keys %$boxPos) { + next unless $add{$tag}; + my $pos = $$boxPos{$tag}[0] + $added; + unless ($$boxPos{$tag}[1]) { + $tag eq 'iref' or $et->Error('Internal error adding iref box'), last; + # create new iref box + $add{$tag} = Set32u(12 + length $add{$tag}) . $tag . + Set8u($$boxPos{$tag}[2]) . "\0\0\0" . $add{$tag}; + } elsif ($tag ne 'hdlr') { + my $n = Get32u($outfile, $pos); + Set32u($n + length($add{$tag}), $outfile, $pos); # increase box size + } + if ($tag eq 'iinf') { + my $iinfVer = Get8u($outfile, $pos + 8); + if ($iinfVer == 0) { + my $n = Get16u($outfile, $pos + 12); + Set16u($n + $countNew, $outfile, $pos + 12); # incr count + } else { + my $n = Get32u($outfile, $pos + 12); + Set32u($n + $countNew, $outfile, $pos + 12); # incr count + } + } elsif ($tag eq 'iref') { + # nothing more to do + } elsif ($tag eq 'iloc') { + my $ilocVer = Get8u($outfile, $pos + 8); + if ($ilocVer < 2) { + my $n = Get16u($outfile, $pos + 14); + Set16u($n + $countNew, $outfile, $pos + 14); # incr count + } else { + my $n = Get32u($outfile, $pos + 14); + Set32u($n + $countNew, $outfile, $pos + 14); # incr count + } + # must also update pointer locations in this box + if ($added) { + $$_[1] += $added foreach @{$$dirInfo{ChunkOffset}}; + } + } elsif ($tag ne 'hdlr') { + next; + } + # add new entries to this box (or add pitm after hdlr) + substr($$outfile, $pos + $$boxPos{$tag}[1], 0) = $add{$tag}; + $added += length $add{$tag}; # positions are shifted by length of new entries + } + } + delete $$et{ItemInfo}; + return @mdatEdit ? \@mdatEdit : undef; } #------------------------------------------------------------------------------ @@ -44,115 +755,285 @@ ($$) # Returns: A) if dirInfo contains DataPt: new directory data # B) otherwise: true on success, 0 if a write error occurred # (true but sets an Error on a file format error) +# Notes: Yes, this is a real mess. Just like the QuickTime metadata situation. sub WriteQuickTime($$$) { + local $_; my ($et, $dirInfo, $tagTablePtr) = @_; - my ($foundMDAT, $lengthChanged, @hold, $track); - my $outfile = $$dirInfo{OutFile} or return 0; - my $raf = $$dirInfo{RAF}; - my $dataPt = $$dirInfo{DataPt}; + $et or return 1; # allow dummy access to autoload this package + my ($mdat, @mdat, @mdatEdit, $edit, $track, $outBuff, $co, $term, $delCount); + my (%langTags, $canCreate, $delGrp, %boxPos, %didDir, $writeLast, $err, $atomCount); + my $outfile = $$dirInfo{OutFile} || return 0; + my $raf = $$dirInfo{RAF}; # (will be null for lower-level atoms) + my $dataPt = $$dirInfo{DataPt}; # (will be null for top-level atoms) my $dirName = $$dirInfo{DirName}; + my $dirStart = $$dirInfo{DirStart} || 0; my $parent = $$dirInfo{Parent}; my $addDirs = $$et{ADD_DIRS}; - my $rtnVal = 1; + my $didTag = $$et{DidTag}; + my $newTags = { }; + my $createKeys = 0; + my ($rtnVal, $rtnErr) = $dataPt ? (undef, undef) : (1, 0); if ($dataPt) { $raf = new File::RandomAccess($dataPt); - my $outBuff = ''; - $outfile = \$outBuff; } else { return 0 unless $raf; } - for (;;) { - my ($hdr, $buff); + # use buffered output for everything but 'mdat' atoms + $outBuff = ''; + $outfile = \$outBuff; + + $raf->Seek($dirStart, 1) if $dirStart; # skip header if it exists + + my $curPath = join '-', @{$$et{PATH}}; + my ($dir, $writePath) = ($dirName, $dirName); + $writePath = "$dir-$writePath" while defined($dir = $$et{DirMap}{$dir}); + # hack to create Keys directories if necessary (its containing Meta is in a different location) + if ($$addDirs{Keys} and $curPath =~ /^MOV-Movie(-Meta)?$/) { + $createKeys = 1; # create new Keys directories + } elsif ($curPath eq 'MOV-Movie-Meta-ItemList') { + $createKeys = 2; # create new Keys tags + my $keys = $$et{Keys}; + if ($keys) { + # add new tag entries for existing Keys tags, now that we know their ID's + # - first make lookup to convert Keys tagInfo ref to index number + my ($index, %keysInfo); + foreach $index (keys %{$$keys{Info}}) { + $keysInfo{$$keys{Info}{$index}} = $index if $$keys{Remap}{$index}; + } + my $keysTable = GetTagTable('Image::ExifTool::QuickTime::Keys'); + my $newKeysTags = $et->GetNewTagInfoHash($keysTable); + foreach (keys %$newKeysTags) { + my $tagInfo = $$newKeysTags{$_}; + $index = $keysInfo{$tagInfo} || ($$tagInfo{SrcTagInfo} and $keysInfo{$$tagInfo{SrcTagInfo}}); + next unless $index; + my $id = Set32u($index); + if ($$tagInfo{LangCode}) { + # add to lookup of language tags we are writing with this ID + $langTags{$id} = { } unless $langTags{$id}; + $langTags{$id}{$_} = $tagInfo; + $id .= '-' . $$tagInfo{LangCode}; + } + $$newTags{$id} = $tagInfo; + } + } + } else { + # get hash of new tags to edit/create in this directory + $newTags = $et->GetNewTagInfoHash($tagTablePtr); + # make lookup of language tags for each ID + foreach (keys %$newTags) { + next unless $$newTags{$_}{LangCode} and $$newTags{$_}{SrcTagInfo}; + my $id = $$newTags{$_}{SrcTagInfo}{TagID}; + $langTags{$id} = { } unless $langTags{$id}; + $langTags{$id}{$_} = $$newTags{$_}; + } + } + if ($curPath eq $writePath or $createKeys) { + $canCreate = 1; + $delGrp = $$et{DEL_GROUP}{$dirName}; + } + $atomCount = $$tagTablePtr{VARS}{ATOM_COUNT} if $$tagTablePtr{VARS}; + + for (;;) { # loop through all atoms at this level + if (defined $atomCount and --$atomCount < 0 and $dataPt) { + # stop processing now and just copy the rest of the atom + Write($outfile, substr($$dataPt, $raf->Tell())) or $rtnVal=$rtnErr, $err=1; + last; + } + my ($hdr, $buff, $keysIndex); my $n = $raf->Read($hdr, 8); unless ($n == 8) { if ($n == 4 and $hdr eq "\0\0\0\0") { # "for historical reasons" the udta is optionally terminated by 4 zeros (ref 1) # --> hold this terminator to the end - push @hold, $hdr; + $term = $hdr; } elsif ($n != 0) { - $et->Error('File format error'); + $et->Error("Unknown $n bytes at end of file", 1); } last; } - my ($size, $tag) = unpack('Na4', $hdr); - if ($size >= 8) { - $size -= 8; - } elsif ($size == 1) { + my $size = Get32u(\$hdr, 0) - 8; # (atom size without 8-byte header) + my $tag = substr($hdr, 4, 4); + if ($size == -7) { # read the extended size $raf->Read($buff, 8) == 8 or $et->Error('Truncated extended atom'), last; $hdr .= $buff; my ($hi, $lo) = unpack('NN', $buff); + if ($hi or $lo > 0x7fffffff) { + if ($hi > 0x7fffffff) { + $et->Error('Invalid atom size'); + last; + } elsif (not $et->Options('LargeFileSupport')) { + $et->Error('End of processing at large atom (LargeFileSupport not enabled)'); + last; + } + } $size = $hi * 4294967296 + $lo - 16; $size < 0 and $et->Error('Invalid extended atom size'), last; - } elsif (not $size and not $dataPt) { - # size of zero is only valid for top-level atom, and - # indicates the atom extends to the end of file - if (not $raf->{FILE_PT}) { - # get file size from image in memory - $size = length ${$$raf{BUFF_PT}}; - } else { - $size = -s $$raf{FILE_PT}; - } - if ($size and ($size -= $raf->Tell()) >= 0 and $size <= 0x7fffffff) { - Set32u($size + 8, \$hdr, 0); - } elsif (@hold) { - $et->Error("Sorry, can't yet add tags to this type of QuickTime file"); - return $rtnVal; + } elsif ($size == -8) { + if ($dataPt) { + last if $$dirInfo{DirName} eq 'CanonCNTH'; # (this is normal for Canon CNTH atom) + my $pos = $raf->Tell() - 4; + $raf->Seek(0,2); + my $str = $$dirInfo{DirName} . ' with ' . ($raf->Tell() - $pos) . ' bytes'; + $et->Error("Terminator found in $str remaining", 1); } else { - # blindly copy the rest of the file - Write($outfile, $hdr) or $rtnVal = 0; - while ($raf->Read($buff, 65536)) { - Write($outfile, $buff) or $rtnVal = 0, last; - } - return $rtnVal; + # size of zero is only valid for top-level atom, and + # indicates the atom extends to the end of file + # (save in mdat list to write later; with zero end position to copy rest of file) + push @mdat, [ $raf->Tell(), 0, $hdr ]; } - } else { + last; + } elsif ($size < 0) { $et->Error('Invalid atom size'); last; } - # set flag if we have passed the 'mdat' atom + # keep track of 'mdat' atom locations for writing later if ($tag eq 'mdat') { if ($dataPt) { $et->Error("'mdat' not at top level"); - } elsif ($foundMDAT and $foundMDAT == 1 and $lengthChanged and - not $et->Options('FixCorruptedMOV')) - { - $et->Error("Multiple 'mdat' blocks! Can only edit existing tags"); - $foundMDAT = 2; + last; + } + push @mdat, [ $raf->Tell(), $raf->Tell() + $size, $hdr ]; + $raf->Seek($size, 1) or $et->Error("Seek error in mdat atom"), return $rtnVal; + next; + } elsif ($tag eq 'cmov') { + $et->Error("Can't yet write compressed movie metadata"); + return $rtnVal; + } elsif ($tag eq 'wide') { + next; # drop 'wide' tag + } + + # read the atom data + my $got; + if (not $size) { + $buff = ''; + $got = 0; + } else { + # read the atom data (but only first 64kB if data is huge) + $got = $raf->Read($buff, $size > $maxReadLen ? 0x10000 : $size); + } + if ($got != $size) { + # ignore up to 256 bytes of garbage at end of file + if ($got <= 256 and $size >= 1024 and $tag ne 'mdat') { + my $bytes = $got + length $hdr; + if ($$et{OPTIONS}{IgnoreMinorErrors}) { + $et->Warn("Deleted garbage at end of file ($bytes bytes)"); + $buff = $hdr = ''; + } else { + $et->Error("Possible garbage at end of file ($bytes bytes)", 1); + return $rtnVal; + } } else { - $foundMDAT = 1; + $tag = PrintableTagID($tag,3); + if ($size > $maxReadLen and $got == 0x10000) { + my $mb = int($size / 0x100000 + 0.5); + $et->Error("'${tag}' atom is too large for rewriting ($mb MB)"); + } else { + $et->Error("Truncated '${tag}' atom"); + } + return $rtnVal; + } + } + # save the handler type for this track + if ($tag eq 'hdlr' and length $buff >= 12) { + my $hdlr = substr($buff,8,4); + $$et{HandlerType} = $hdlr if $hdlr =~ /^(vide|soun)$/; + } + + # if this atom stores offsets, save its location so we can fix up offsets later + # (are there any other atoms that may store absolute file offsets?) + if ($tag =~ /^(stco|co64|iloc|mfra|moof|sidx|saio|gps |CTBO|uuid)$/) { + # (note that we only need to do this if the media data is stored in this file) + my $flg = $$et{QtDataFlg}; + if ($tag eq 'mfra' or $tag eq 'moof') { + $et->Error("Can't yet handle movie fragments when writing"); + return $rtnVal; + } elsif ($tag eq 'sidx' or $tag eq 'saio') { + $et->Error("Can't yet handle $tag box when writing"); + return $rtnVal; + } elsif ($tag eq 'iloc') { + Handle_iloc($et, $dirInfo, \$buff, $outfile) or $et->Error('Error parsing iloc atom'); + } elsif ($tag eq 'gps ') { + # (only care about the 'gps ' box in 'moov') + if ($$dirInfo{DirID} and $$dirInfo{DirID} eq 'moov' and length $buff > 8) { + my $off = $$dirInfo{ChunkOffset}; + my $num = Get32u(\$buff, 4); + $num = int((length($buff) - 8) / 8) if $num * 8 + 8 > length($buff); + my $i; + for ($i=0; $i<$num; ++$i) { + push @$off, [ 'stco_gps ', length($$outfile) + length($hdr) + 8 + $i * 8, 4 ]; + } + } + } elsif ($tag eq 'CTBO' or $tag eq 'uuid') { # hack for updating CR3 CTBO offsets + push @{$$dirInfo{ChunkOffset}}, [ $tag, length($$outfile), length($hdr) + $size ]; + } elsif (not $flg) { + my $grp = $$et{CUR_WRITE_GROUP} || $parent; + $et->Error("Can't locate data reference to update offsets for $grp"); + return $rtnVal; + } elsif ($flg == 3) { + $et->Error("Can't write files with mixed internal/external media data"); + return $rtnVal; + } elsif ($flg == 1) { + # must update offsets since the data is in this file + push @{$$dirInfo{ChunkOffset}}, [ $tag, length($$outfile) + length($hdr), $size ]; } } # rewrite this atom - my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag); - if (defined $tagInfo and not $tagInfo) { - my $n = $size < 256 ? $size : 256; - unless ($raf->Read($buff, $n) == $n and $raf->Seek(-$n, 1)) { - $et->Error("Read/seek error in $tag atom"); - last; + my $tagInfo = $et->GetTagInfo($tagTablePtr, $tag, \$buff); + + # call write hook if it exists + &{$$tagInfo{WriteHook}}($buff,$et) if $tagInfo and $$tagInfo{WriteHook}; + + # allow numerical tag ID's (ItemList entries defined by Keys) + if (not $tagInfo and $dirName eq 'ItemList' and $$et{Keys}) { + $keysIndex = unpack('N', $tag); + my $newIndex = $$et{Keys}{Remap}{$keysIndex}; + if (defined $newIndex) { + $tagInfo = $$et{Keys}{Info}{$keysIndex}; + unless ($newIndex) { + if ($tagInfo) { + $et->VPrint(1," - Keys:$$tagInfo{Name}"); + } else { + $delCount = ($delCount || 0) + 1; + } + ++$$et{CHANGED}; + next; + } + # use the new Keys index of this item if it changed + unless ($keysIndex == $newIndex) { + $tag = Set32u($newIndex); + substr($hdr, 4, 4) = $tag; + } + } else { + undef $keysIndex; } - $tagInfo = $et->GetTagInfo($tagTablePtr, $tag, \$buff); } - if ($tagInfo) { - if ($$tagInfo{Unknown}) { - undef $tagInfo; - } elsif ($size > 100000000) { - # limit maximum size of atom that we load into memory - my $mb = $size / 0x100000; - $et->Warn("Not editing metadata in $tag atom. $mb MB is too big"); - undef $tagInfo; + # delete all ItemList tags when deleting group, but take care not to delete UserData Meta + if ($delGrp) { + if ($dirName eq 'ItemList') { + $delCount = ($delCount || 0) + 1; + ++$$et{CHANGED}; + next; + } elsif ($dirName eq 'UserData' and (not $tagInfo or not $$tagInfo{SubDirectory})) { + $delCount = ($delCount || 0) + 1; + ++$$et{CHANGED}; + next; } } + undef $tagInfo if $tagInfo and $$tagInfo{Unknown}; + if ($tagInfo and (not defined $$tagInfo{Writable} or $$tagInfo{Writable})) { - # read the atom data - $raf->Read($buff, $size) == $size or $et->Error("Error reading $tag data"), last; my $subdir = $$tagInfo{SubDirectory}; - my $newData; - if ($subdir) { + my ($newData, @chunkOffset); + + if ($subdir) { # process atoms in this container from a buffer in memory + + undef $$et{HandlerType} if $tag eq 'trak'; # init handler type for this track + my $subName = $$subdir{DirName} || $$tagInfo{Name}; my $start = $$subdir{Start} || 0; my $base = ($$dirInfo{Base} || 0) + $raf->Tell() - $size; @@ -168,17 +1049,27 @@ ($$$) my %subdirInfo = ( Parent => $dirName, DirName => $subName, + Name => $$tagInfo{Name}, + DirID => $tag, DataPt => \$buff, DataLen => $size, DataPos => $dPos, DirStart => $start, DirLen => $size - $start, Base => $base, - HasData => $$subdir{HasData}, # necessary? + HasData => $$subdir{HasData}, Multi => $$subdir{Multi}, # necessary? OutFile => $outfile, - InPlace => 2, # (to write fixed-length XMP if possible) + NoRefTest=> 1, # don't check directory references + WriteGroup => $$tagInfo{WriteGroup}, + # initialize array to hold details about chunk offset table + # (each entry has 3-5 items: 0=atom type, 1=table offset, 2=table size, + # 3=optional base offset, 4=optional item ID) + ChunkOffset => \@chunkOffset, ); + # set InPlace flag so XMP will be padded properly when + # QuickTimePad is used if this is an XMP directory + $subdirInfo{InPlace} = 2 if $et->Options('QuickTimePad'); # pass the header pointer if necessary (for EXIF IFD's # where the Base offset is at the end of the header) if ($hdrLen and $hdrLen < $size) { @@ -195,113 +1086,774 @@ ($$$) # demote non-QuickTime errors to warnings $$et{DemoteErrors} = 1 unless $$subTable{GROUPS}{0} eq 'QuickTime'; my $oldChanged = $$et{CHANGED}; - $newData = $et->WriteDirectory(\%subdirInfo, $subTable); + $newData = $et->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc}); if ($$et{DemoteErrors}) { - # just copy existing subdirectory a non-quicktime error occurred + # just copy existing subdirectory if a non-quicktime error occurred $$et{CHANGED} = $oldChanged if $$et{DemoteErrors} > 1; delete $$et{DemoteErrors}; } - undef $newData if $$et{CHANGED} == $oldChanged; # don't change unless necessary + if (defined $newData and not length $newData and ($$tagInfo{Permanent} or + ($$tagTablePtr{PERMANENT} and not defined $$tagInfo{Permanent}))) + { + # do nothing if trying to delete tag from a PERMANENT table + $$et{CHANGED} = $oldChanged; + undef $newData; + } $$et{CUR_WRITE_GROUP} = $oldWriteGroup; SetByteOrder('MM'); # add back header if necessary - if ($start and defined $newData and length $newData) { + if ($start and defined $newData and (length $newData or + (defined $$tagInfo{Permanent} and not $$tagInfo{Permanent}))) + { $newData = substr($buff,0,$start) . $newData; + $$_[1] += $start foreach @chunkOffset; } # the directory exists, so we don't need to add it - delete $$addDirs{$subName} if IsCurPath($et, $subName); - } else { - # --> this is where individual QuickTime tags would be edited, - # (this is such a can of worms, so don't implement this for now) - } - if (defined $newData) { - my $len = length $newData; - $len > 0x7ffffff7 and $et->Error("$tag to large to write"), last; - if ($len == $size or $dataPt or $foundMDAT) { - # write the updated directory now (unless length is zero, or it is needed as padding) - if ($len or (not $dataPt and not $foundMDAT) or - ($et->Options('FixCorruptedMOV') and $tag eq 'udta')) - { - Write($outfile, Set32u($len+8), $tag, $newData) or $rtnVal = 0, last; - $lengthChanged = 1 if $len != $size; + if ($curPath eq $writePath and $$addDirs{$subName} and $$addDirs{$subName} eq $dirName) { + delete $$addDirs{$subName}; + } + $didDir{$tag} = 1; # (note: keyed by tag ID) + + } else { # modify existing QuickTime tags in various formats + + my $nvHash = $et->GetNewValueHash($tagInfo); + if ($nvHash or $langTags{$tag} or $delGrp) { + my $nvHashNoLang = $nvHash; + my ($val, $len, $lang, $type, $flags, $ctry, $charsetQuickTime); + my $format = $$tagInfo{Format}; + my $hasData = ($$dirInfo{HasData} and $buff =~ /\0...data\0/s); + my $langInfo = $tagInfo; + if ($hasData) { + my $pos = 0; + for (;;$pos+=$len) { + if ($pos + 16 > $size) { + # add any new alternate language tags now + if ($langTags{$tag}) { + my $tg; + foreach $tg ('', sort keys %{$langTags{$tag}}) { + my $ti = $tg ? $langTags{$tag}{$tg} : $nvHashNoLang; + $nvHash = $et->GetNewValueHash($ti); + next unless $nvHash and not $$didTag{$nvHash}; + $$didTag{$nvHash} = 1; + next unless $$nvHash{IsCreating} and $et->IsOverwriting($nvHash); + my $newVal = $et->GetNewValue($nvHash); + next unless defined $newVal; + my $prVal = $newVal; + my $flags = FormatQTValue($et, \$newVal, $format, $$tagInfo{Writable}); + next unless defined $newVal; + my ($ctry, $lang) = (0, 0); + if ($$ti{LangCode}) { + unless ($$ti{LangCode} =~ /^([A-Z]{3})?[-_]?([A-Z]{2})?$/i) { + $et->Warn("Invalid language code for $$ti{Name}"); + next; + } + # pack language and country codes + if ($1 and $1 ne 'und') { + $lang = ($lang << 5) | ($_ - 0x60) foreach unpack 'C*', lc($1); + } + $ctry = unpack('n', pack('a2',uc($2))) if $2 and $2 ne 'ZZ'; + } + $newData = substr($buff, 0, $pos) unless defined $newData; + $newData .= pack('Na4Nnn',16+length($newVal),'data',$flags,$ctry,$lang).$newVal; + my $grp = $et->GetGroup($ti, 1); + $et->VerboseValue("+ $grp:$$ti{Name}", $prVal); + ++$$et{CHANGED}; + } + } + last; + } + ($len, $type, $flags, $ctry, $lang) = unpack("x${pos}Na4Nnn", $buff); + $lang or $lang = $undLang; # treat both 0 and 'und' as 'und' + $langInfo = $tagInfo; + my $delTag = $delGrp; + my $newVal; + my $langCode = GetLangCode($lang, $ctry, 1); + for (;;) { + $langInfo = GetLangInfo($tagInfo, $langCode); + $nvHash = $et->GetNewValueHash($langInfo); + last if $nvHash or not $ctry or $lang ne $undLang or length($langCode)==2; + # check to see if tag was written with a 2-char country code only + $langCode = lc unpack('a2',pack('n',$ctry)); + } + # set flag to delete language tag when writing default + # (except for a default-language Keys entry) + if (not $nvHash and $nvHashNoLang) { + if ($lang eq $undLang and not $ctry and not $$didTag{$nvHashNoLang}) { + $nvHash = $nvHashNoLang; # write existing default + } else { + $delTag = 1; # delete tag + } + } + last if $pos + $len > $size; + if ($type eq 'data' and $len >= 16) { + $pos += 16; + $len -= 16; + $val = substr($buff, $pos, $len); + # decode value (see QuickTime.pm for an explanation) + if ($stringEncoding{$flags}) { + $val = $et->Decode($val, $stringEncoding{$flags}); + $val =~ s/\0$// unless $$tagInfo{Binary}; + $flags = 0x01; # write all strings as UTF-8 + } else { + if ($format) { + # update flags for the format we are writing + if ($$tagInfo{Writable} and $qtFormat{$$tagInfo{Writable}}) { + $flags = $qtFormat{$$tagInfo{Writable}}; + } elsif ($qtFormat{$format}) { + $flags = $qtFormat{$format}; + } + } else { + $format = QuickTimeFormat($flags, $len); + } + $val = ReadValue(\$val, 0, $format, $$tagInfo{Count}, $len) if $format; + } + if (($nvHash and $et->IsOverwriting($nvHash, $val)) or $delTag) { + $newVal = $et->GetNewValue($nvHash) if defined $nvHash; + if ($delTag or not defined $newVal or $$didTag{$nvHash}) { + # delete the tag + my $grp = $et->GetGroup($langInfo, 1); + $et->VerboseValue("- $grp:$$langInfo{Name}", $val); + # copy data up to start of this tag to delete this value + $newData = substr($buff, 0, $pos-16) unless defined $newData; + ++$$et{CHANGED}; + next; + } + my $prVal = $newVal; + # format new value for writing (and get new flags) + $flags = FormatQTValue($et, \$newVal, $format, $$tagInfo{Writable}); + my $grp = $et->GetGroup($langInfo, 1); + $et->VerboseValue("- $grp:$$langInfo{Name}", $val); + $et->VerboseValue("+ $grp:$$langInfo{Name}", $prVal); + $newData = substr($buff, 0, $pos-16) unless defined $newData; + my $wLang = $lang eq $undLang ? 0 : $lang; + $newData .= pack('Na4Nnn', length($newVal)+16, $type, $flags, $ctry, $wLang); + $newData .= $newVal; + ++$$et{CHANGED}; + } elsif (defined $newData) { + $newData .= substr($buff, $pos-16, $len+16); + } + } elsif (defined $newData) { + $newData .= substr($buff, $pos, $len); + } + $$didTag{$nvHash} = 1 if $nvHash; + } + $newData .= substr($buff, $pos) if defined $newData and $pos < $size; + undef $val; # (already constructed $newData) + } elsif ($format) { + $val = ReadValue(\$buff, 0, $format, undef, $size); + } elsif (($tag =~ /^\xa9/ or $$tagInfo{IText}) and $size >= ($$tagInfo{IText} || 4)) { + my $hdr; + if ($$tagInfo{IText} and $$tagInfo{IText} >= 6) { + my $iText = $$tagInfo{IText}; + my $pos = $iText - 2; + $lang = unpack("x${pos}n", $buff); + $hdr = substr($buff,4,$iText-6); + $len = $size - $iText; + $val = substr($buff, $iText, $len); + } else { + ($len, $lang) = unpack('nn', $buff); + $len -= 4 if 4 + $len > $size; # (see QuickTime.pm for explanation) + $len = $size - 4 if $len > $size - 4 or $len < 0; + $val = substr($buff, 4, $len); + } + $lang or $lang = $undLang; # treat both 0 and 'und' as 'und' + my $enc; + if ($lang < 0x400 and $val !~ /^\xfe\xff/) { + $charsetQuickTime = $et->Options('CharsetQuickTime'); + $enc = $charsetQuickTime; + } else { + $enc = $val=~s/^\xfe\xff// ? 'UTF16' : 'UTF8'; + } + unless ($$tagInfo{NoDecode}) { + $val = $et->Decode($val, $enc); + $val =~ s/\0+$//; # remove trailing nulls if they exist + } + $val = $hdr . $val if defined $hdr; + my $langCode = UnpackLang($lang, 1); + $langInfo = GetLangInfo($tagInfo, $langCode); + $nvHash = $et->GetNewValueHash($langInfo); + if (not $nvHash and $nvHashNoLang) { + if ($lang eq $undLang and not $$didTag{$nvHashNoLang}) { + $nvHash = $nvHashNoLang; + } elsif ($canCreate) { + # delete other languages when writing default + my $grp = $et->GetGroup($langInfo, 1); + $et->VerboseValue("- $grp:$$langInfo{Name}", $val); + ++$$et{CHANGED}; + next; + } + } } else { - $lengthChanged = 1; # (we deleted this atom) + $val = $buff; + if ($tag =~ /^\xa9/ or $$tagInfo{IText}) { + $et->Warn("Corrupted $$tagInfo{Name} value"); + } } - next; - } else { - # bad things happen if 'mdat' atom is moved (eg. Adobe Bridge crashes -- - # there are absolute offsets that point into mdat), so hold this atom - # and write it out later - if ($len) { - push @hold, Set32u($len+8), $tag, $newData; - $et->VPrint(0," Moving '${tag}' atom to after 'mdat'"); - } else { - $et->VPrint(0," Freeing '${tag}' atom (and zeroing data)"); + if ($nvHash and defined $val) { + if ($et->IsOverwriting($nvHash, $val)) { + $newData = $et->GetNewValue($nvHash); + $newData = '' unless defined $newData or $canCreate; + ++$$et{CHANGED}; + my $grp = $et->GetGroup($langInfo, 1); + $et->VerboseValue("- $grp:$$langInfo{Name}", $val); + next unless defined $newData and not $$didTag{$nvHash}; + $et->VerboseValue("+ $grp:$$langInfo{Name}", $newData); + # add back necessary header and encode as necessary + if (defined $lang) { + my $iText = $$tagInfo{IText} || 0; + my $hdr; + if ($iText > 6) { + $newData .= ' 'x($iText-6) if length($newData) < $iText-6; + $hdr = substr($newData, 0, $iText-6); + $newData = substr($newData, $iText-6); + } + unless ($$tagInfo{NoDecode}) { + $newData = $et->Encode($newData, $lang < 0x400 ? $charsetQuickTime : 'UTF8'); + } + my $wLang = $lang eq $undLang ? 0 : $lang; + if ($iText < 6) { + $newData = pack('nn', length($newData), $wLang) . $newData; + } elsif ($iText == 6) { + $newData = pack('Nn', 0, $wLang) . $newData . "\0"; + } else { + $newData = "\0\0\0\0" . $hdr . pack('n', $wLang) . $newData . "\0"; + } + } elsif (not $format or $format =~ /^string/ and + not $$tagInfo{Binary} and not $$tagInfo{ValueConv}) + { + # write all strings as UTF-8 + $newData = $et->Encode($newData, 'UTF8'); + } elsif ($format and not $$tagInfo{Binary}) { + # format new value for writing + $newData = WriteValue($newData, $format); + } + } + $$didTag{$nvHash} = 1; # set flag so we don't add this tag again } - # write a 'free' atom here to keep 'mdat' at the same offset - substr($hdr, 4, 4) = 'free'; - $buff = "\0" x length($buff); # zero out old data } } - # write out the existing atom (or 'free' padding) - Write($outfile, $hdr, $buff) or $rtnVal = 0, last; + # write the new atom if it was modified + if (defined $newData) { + my $sizeDiff = length($buff) - length($newData); + # pad to original size if specified, otherwise give verbose message about the changed size + if ($sizeDiff > 0 and $$tagInfo{PreservePadding} and $et->Options('QuickTimePad')) { + $newData .= "\0" x $sizeDiff; + $et->VPrint(1, " ($$tagInfo{Name} padded to original size)"); + } elsif ($sizeDiff) { + $et->VPrint(1, " ($$tagInfo{Name} changed size)"); + } + my $len = length($newData) + 8; + $len > 0x7fffffff and $et->Error("$$tagInfo{Name} to large to write"), last; + # update size in ChunkOffset list for modified 'uuid' atom + $$dirInfo{ChunkOffset}[-1][2] = $len if $tag eq 'uuid'; + next unless $len > 8; # don't write empty atom header + # maintain pointer to chunk offsets if necessary + if (@chunkOffset) { + $$_[1] += 8 + length $$outfile foreach @chunkOffset; + push @{$$dirInfo{ChunkOffset}}, @chunkOffset; + } + if ($$tagInfo{WriteLast}) { + $writeLast = ($writeLast || '') . Set32u($len) . $tag . $newData; + } else { + $boxPos{$tag} = [ length($$outfile), length($newData) + 8 ]; + # write the updated directory with its atom header + Write($outfile, Set32u($len), $tag, $newData) or $rtnVal=$rtnErr, $err=1, last; + } + next; + } + } + # keep track of data references in this track + if ($tag eq 'dinf') { + $$et{QtDataRef} = [ ]; # initialize list of data references + } elsif ($parent eq 'DataInfo' and length($buff) >= 4) { + # save data reference type and version/flags + push @{$$et{QtDataRef}}, [ $tag, Get32u(\$buff,0) ]; + } elsif ($tag eq 'stsd' and length($buff) >= 8) { + my $n = Get32u(\$buff, 4); # get number of sample descriptions in table + my ($pos, $flg) = (8, 0); + my ($i, $msg); + for ($i=0; $i<$n; ++$i) { # loop through sample descriptions + $pos + 16 <= length($buff) or $msg = 'Truncated sample table', last; + my $siz = Get32u(\$buff, $pos); + $pos + $siz <= length($buff) or $msg = 'Truncated sample table', last; + my $drefIdx = Get16u(\$buff, $pos + 14); + my $drefTbl = $$et{QtDataRef}; + if (not $drefIdx) { + $flg |= 0x01; # in this file if data reference index is 0 (if like iloc) + } elsif ($drefTbl and $$drefTbl[$drefIdx-1]) { + my $dref = $$drefTbl[$drefIdx-1]; + # $flg = 0x01-in this file, 0x02-in some other file + $flg |= ($$dref[1] == 1 and $$dref[0] ne 'rsrc') ? 0x01 : 0x02; + } else { + $msg = "No data reference for sample description $i"; + last; + } + $pos += $siz; + } + if ($msg) { + # (allow empty sample description for non-audio/video handler types, eg. 'url ', 'meta') + if ($$et{HandlerType}) { + my $grp = $$et{CUR_WRITE_GROUP} || $parent; + $et->Error("$msg for $grp"); + return $rtnErr; + } + $flg = 1; # (this seems to be the case) + } + $$et{QtDataFlg} = $flg; + } + if ($tagInfo and $$tagInfo{WriteLast}) { + $writeLast = ($writeLast || '') . $hdr . $buff; } else { - # write the unknown/large atom header - Write($outfile, $hdr) or $rtnVal = 0, last; - next unless $size; - # copy the atom data - my $result = Image::ExifTool::CopyBlock($raf, $outfile, $size); - defined $result or $rtnVal = 0, last; - $result or $et->Error("Truncated $tag atom"), last; + # save position of this box in the output buffer + $boxPos{$tag} = [ length($$outfile), length($hdr) + length($buff) ]; + # copy the existing atom + Write($outfile, $hdr, $buff) or $rtnVal=$rtnErr, $err=1, last; } } - # add new directories at this level if necessary - if (exists $$et{EDIT_DIRS}{$dirName}) { + $et->VPrint(0, " [deleting $delCount $dirName tag".($delCount==1 ? '' : 's')."]\n") if $delCount; + + $createKeys &= ~0x01 unless $$addDirs{Keys}; # (Keys may have been written) + + # add new directories/tags at this level if necessary + if ($canCreate and (exists $$et{EDIT_DIRS}{$dirName} or $createKeys)) { # get a hash of tagInfo references to add to this directory my $dirs = $et->GetAddDirHash($tagTablePtr, $dirName); # make sorted list of new tags to be added - my @addTags = sort keys(%$dirs); - my $tag; + my @addTags = sort(keys(%$dirs), keys %$newTags); + my ($tag, $index); + # add Keys tags if necessary + if ($createKeys) { + if ($curPath eq 'MOV-Movie') { + # add Meta for Keys if necessary + unless ($didDir{meta}) { + $$dirs{meta} = $Image::ExifTool::QuickTime::Movie{meta}; + push @addTags, 'meta'; + } + } elsif ($curPath eq 'MOV-Movie-Meta') { + # special case for Keys Meta -- reset directories and start again + undef @addTags; + $dirs = { }; + foreach ('keys','ilst') { + next if $didDir{$_}; # don't add again + $$dirs{$_} = $Image::ExifTool::QuickTime::Meta{$_}; + push @addTags, $_; + } + } elsif ($curPath eq 'MOV-Movie-Meta-ItemList' and $$et{Keys}) { + foreach $index (sort { $a <=> $b } keys %{$$et{Keys}{Add}}) { + my $id = Set32u($index); + $$newTags{$id} = $$et{Keys}{Add}{$index}; + push @addTags, $id; + } + } else { + $dirs = $et->GetAddDirHash($tagTablePtr, $dirName); + push @addTags, sort keys %$dirs; + } + } + # (note that $tag may be a binary Keys index here) foreach $tag (@addTags) { - my $tagInfo = $$dirs{$tag}; - my $subdir = $$tagInfo{SubDirectory} or next; + my $tagInfo = $$dirs{$tag} || $$newTags{$tag}; + next if defined $$tagInfo{CanCreate} and not $$tagInfo{CanCreate}; + next if defined $$tagInfo{HandlerType} and + (not $$et{HandlerType} or $$et{HandlerType} ne $$tagInfo{HandlerType}); + my $subdir = $$tagInfo{SubDirectory}; + unless ($subdir) { + my $nvHash = $et->GetNewValueHash($tagInfo); + next unless $nvHash and not $$didTag{$nvHash}; + next unless $$nvHash{IsCreating} and $et->IsOverwriting($nvHash); + my $newVal = $et->GetNewValue($nvHash); + next unless defined $newVal; + my $prVal = $newVal; + my $flags = FormatQTValue($et, \$newVal, $$tagInfo{Format}, $$tagInfo{Writable}); + next unless defined $newVal; + my ($ctry, $lang) = (0, 0); + # handle alternate languages + if ($$tagInfo{LangCode}) { + $tag = substr($tag, 0, 4); # strip language code from tag ID + unless ($$tagInfo{LangCode} =~ /^([A-Z]{3})?[-_]?([A-Z]{2})?$/i) { + $et->Warn("Invalid language code for $$tagInfo{Name}"); + next; + } + # pack language and country codes + if ($1 and $1 ne 'und') { + $lang = ($lang << 5) | ($_ - 0x60) foreach unpack 'C*', lc($1); + } + $ctry = unpack('n', pack('a2',uc($2))) if $2 and $2 ne 'ZZ'; + } + if ($$dirInfo{HasData}) { + # add 'data' header + $newVal = pack('Na4Nnn',16+length($newVal),'data',$flags,$ctry,$lang).$newVal; + } elsif ($tag =~ /^\xa9/ or $$tagInfo{IText}) { + if ($ctry) { + my $grp = $et->GetGroup($tagInfo,1); + $et->Warn("Can't use country code for $grp:$$tagInfo{Name}"); + next; + } elsif ($$tagInfo{IText} and $$tagInfo{IText} >= 6) { + # add 6-byte langText header and trailing null + # (with extra junk before language code if IText > 6) + my $n = $$tagInfo{IText} - 6; + $newVal .= ' ' x $n if length($newVal) < $n; + $newVal = "\0\0\0\0" . substr($newVal,0,$n) . pack('n',0,$lang) . substr($newVal,$n) . "\0"; + } else { + # add IText header + $newVal = pack('nn',length($newVal),$lang) . $newVal; + } + } elsif ($ctry or $lang) { + my $grp = $et->GetGroup($tagInfo,1); + $et->Warn("Can't use language code for $grp:$$tagInfo{Name}"); + next; + } + if ($$tagInfo{WriteLast}) { + $writeLast = ($writeLast || '') . Set32u(8+length($newVal)) . $tag . $newVal; + } else { + $boxPos{$tag} = [ length($$outfile), 8 + length($newVal) ]; + Write($outfile, Set32u(8+length($newVal)), $tag, $newVal) or $rtnVal=$rtnErr, $err=1; + } + my $grp = $et->GetGroup($tagInfo, 1); + $et->VerboseValue("+ $grp:$$tagInfo{Name}", $prVal); + $$didTag{$nvHash} = 1; + ++$$et{CHANGED}; + next; + } my $subName = $$subdir{DirName} || $$tagInfo{Name}; # QuickTime hierarchy is complex, so check full directory path before adding - next unless IsCurPath($et, $subName); - my $buff = ''; # write from scratch + my $buff; + if ($createKeys and $curPath eq 'MOV-Movie' and $subName eq 'Meta') { + $et->VPrint(0, " Creating Meta with mdta Handler and Keys\n"); + # init Meta box for Keys tags with mdta Handler and empty Keys+ItemList + $buff = "\0\0\0\x20hdlr\0\0\0\0\0\0\0\0mdta\0\0\0\0\0\0\0\0\0\0\0\0" . + "\0\0\0\x10keys\0\0\0\0\0\0\0\0" . + "\0\0\0\x08ilst"; + } elsif ($createKeys and $curPath eq 'MOV-Movie-Meta') { + $buff = ($subName eq 'Keys' ? "\0\0\0\0\0\0\0\0" : ''); + } elsif ($subName eq 'Meta' and $$et{OPTIONS}{QuickTimeHandler}) { + $et->VPrint(0, " Creating Meta with mdir Handler\n"); + # init Meta box for ItemList tags with mdir Handler + $buff = "\0\0\0\x20hdlr\0\0\0\0\0\0\0\0mdir\0\0\0\0\0\0\0\0\0\0\0\0"; + } else { + next unless $curPath eq $writePath and $$addDirs{$subName} and $$addDirs{$subName} eq $dirName; + $buff = ''; # write from scratch + } my %subdirInfo = ( Parent => $dirName, DirName => $subName, DataPt => \$buff, DirStart => 0, + HasData => $$subdir{HasData}, OutFile => $outfile, + ChunkOffset => [ ], # (just to be safe) + WriteGroup => $$tagInfo{WriteGroup}, ); my $subTable = GetTagTable($$subdir{TagTable}); - my $newData = $et->WriteDirectory(\%subdirInfo, $subTable); + my $newData = $et->WriteDirectory(\%subdirInfo, $subTable, $$subdir{WriteProc}); if ($newData and length($newData) <= 0x7ffffff7) { - my $uuid = ''; - # add atom ID if necessary (obtain from Condition expression) + my $prefix = ''; + # add atom version or ID if necessary if ($$subdir{Start}) { - my $cond = $$tagInfo{Condition}; - $uuid = eval qq("$1") if $cond and $cond =~ m{=~\s*\/\^(.*)/}; - length($uuid) == $$subdir{Start} or $et->Error('Internal UUID error'); + if ($$subdir{Start} == 4) { + $prefix = "\0\0\0\0"; # a simple version number + } else { + # get UUID from Condition expression + my $cond = $$tagInfo{Condition}; + $prefix = eval qq("$1") if $cond and $cond =~ m{=~\s*\/\^(.*)/}; + length($prefix) == $$subdir{Start} or $et->Error('Internal UUID error'); + } + } + my $newHdr = Set32u(8+length($newData)+length($prefix)) . $tag . $prefix; + if ($$tagInfo{WriteLast}) { + $writeLast = ($writeLast || '') . $newHdr . $newData; + } else { + if ($tag eq 'uuid') { + # add offset for new uuid (needed for CR3 CTBO offsets) + my $off = $$dirInfo{ChunkOffset}; + push @$off, [ $tag, length($$outfile), length($newHdr) + length($newData) ]; + } + $boxPos{$tag} = [ length($$outfile), length($newHdr) + length($newData) ]; + Write($outfile, $newHdr, $newData) or $rtnVal=$rtnErr, $err=1; } - my $newHdr = Set32u(8+length($newData)+length($uuid)) . $tag . $uuid; - Write($outfile, $newHdr, $newData) or $rtnVal = 0; - $lengthChanged = 1; } - delete $$addDirs{$subName}; # add only once (must delete _after_ call to WriteDirectory()) + # add only once (must delete _after_ call to WriteDirectory()) + # (Keys is a special case, and will be removed after Meta is processed) + delete $$addDirs{$subName} unless $subName eq 'Keys'; + } + } + # write HEIC metadata after top-level 'meta' box has been processed if editing this information + if ($curPath eq 'MOV-Meta' and $$et{EDIT_DIRS}{ItemInformation}) { + $$dirInfo{BoxPos} = \%boxPos; + my $mdatEdit = WriteItemInfo($et, $dirInfo, $outfile); + if ($mdatEdit) { + $et->Error('Multiple top-level Meta containers') if $$et{mdatEdit}; + $$et{mdatEdit} = $mdatEdit; + } + } + # write out any necessary terminator + Write($outfile, $term) or $rtnVal=$rtnErr, $err=1 if $term and length $$outfile; + + # delete temporary Keys variables after Meta is processed + if ($dirName eq 'Meta') { + # delete any Meta box with no useful information (ie. only 'hdlr','keys','lang','ctry') + my $isEmpty = 1; + $emptyMeta{$_} or $isEmpty = 0, last foreach keys %boxPos; + if ($isEmpty) { + $et->VPrint(0,' Deleting ' . join('+', sort map { $emptyMeta{$_} } keys %boxPos)) if %boxPos; + $$outfile = ''; + ++$$et{CHANGED}; + } + if ($curPath eq 'MOV-Movie-Meta') { + delete $$addDirs{Keys}; # prevent creation of another Meta for Keys tags + delete $$et{Keys}; } } - # write out any atoms that we are holding until the end - Write($outfile, @hold) or $rtnVal = 0 if @hold; + + # return now if writing subdirectory + if ($dataPt) { + $et->Error("Internal error: WriteLast not on top-level atom!\n") if $writeLast; + return $err ? undef : $$outfile; + } # issue minor error if we didn't find an 'mdat' atom - # (we could duplicate atoms indefinitely through repeated editing if we - # held back some atoms here, so in this case it isn't a minor error) - $dataPt or $foundMDAT or $et->Error('No mdat atom found', @hold ? 0 : 1); + my $off = $$dirInfo{ChunkOffset}; + if (not @mdat) { + foreach $co (@$off) { + next if $$co[0] eq 'uuid'; + $et->Error('Media data referenced but not found'); + return $rtnVal; + } + $et->Warn('No media data', 1); + } + + # edit mdat blocks as required + # (0=old pos [0 if creating], 1=old end [0 if creating], 2=new data ref or undef to delete, + # 3=new data item id) + if ($$et{mdatEdit}) { + @mdatEdit = @{$$et{mdatEdit}}; + delete $$et{mdatEdit}; + } + foreach $edit (@mdatEdit) { + my (@thisMdat, @newMdat, $changed); + foreach $mdat (@mdat) { + # keep track of all chunks for the mdat with this header + if (length $$mdat[2]) { + push @newMdat, @thisMdat; + undef @thisMdat; + } + push @thisMdat, $mdat; + # is this edit inside this mdat chunk? + # - $$edit[0] and $$edit[1] will both be zero if we are creating a new chunk + # - $$mdat[1] is zero if mdat runs to end of file + # - $$edit[0] == $$edit[1] == $$mdat[0] if reviving a deleted chunk + # - $$mdat[5] is defined if this was a newly added/edited chunk + next if defined $$mdat[5] or $changed; # don't replace a newly added chunk + if (not $$edit[0] or # (newly created chunk) + # (edit is inside chunk) + ((($$edit[0] < $$mdat[1] or not $$mdat[1]) and $$edit[1] > $$mdat[0]) or + # (edit inserted at start or end of chunk) + ($$edit[0] == $$edit[1] and ($$edit[0] == $$mdat[0] or $$edit[0] == $$mdat[1])))) + { + if (not $$edit[0]) { + $$edit[0] = $$edit[1] = $$mdat[0]; # insert at start of this mdat + } elsif ($$edit[0] < $$mdat[0] or ($$edit[1] > $$mdat[1] and $$mdat[1])) { + $et->Error('ItemInfo runs across mdat boundary'); + return $rtnVal; + } + my $hdrChunk = $thisMdat[0]; + $hdrChunk or $et->Error('Internal error finding mdat header'), return $rtnVal; + # calculate difference in mdat size + my $diff = ($$edit[2] ? length(${$$edit[2]}) : 0) - ($$edit[1] - $$edit[0]); + # edit size of mdat in header if necessary + if ($diff) { + if (length($$hdrChunk[2]) == 8) { + my $size = Get32u(\$$hdrChunk[2], 0) + $diff; + $size > 0xffffffff and $et->Error("Can't yet grow mdat across 4GB boundary"), return $rtnVal; + Set32u($size, \$$hdrChunk[2], 0); + } elsif (length($$hdrChunk[2]) == 16) { + my $size = Get64u(\$$hdrChunk[2], 8) + $diff; + Set64u($size, \$$hdrChunk[2], 8); + } else { + $et->Error('Internal error. Invalid mdat header'); + return $rtnVal; + } + } + $changed = 1; + # remove the edited section of this chunk (if any) and replace with new data (if any) + if ($$edit[0] > $$mdat[0]) { + push @thisMdat, [ $$edit[0], $$edit[1], '', 0, $$edit[2], $$edit[3] ] if $$edit[2]; + # add remaining data after edit (or empty stub in case it is referenced by an offset) + push @thisMdat, [ $$edit[1], $$mdat[1], '' ]; + $$mdat[1] = $$edit[0]; # now ends at start of edit + } else { + if ($$edit[2]) { + # insert the new chunk before this chunk, moving the header to the new chunk + splice @thisMdat, -1, 0, [ $$edit[0],$$edit[1],$$mdat[2],0,$$edit[2],$$edit[3] ]; + $$mdat[2] = ''; # (header was moved to new chunk) + # initialize ChunkOffset pointer if necessary + if ($$edit[3]) { + my $n = 0; + foreach $co (@$off) { + next unless defined $$co[4] and $$co[4] == $$edit[3]; + ++$n; + if ($$co[0] eq 'stco_iloc') { + Set32u($$mdat[0], $outfile, $$co[1]); + } else { + Set64u($$mdat[0], $outfile, $$co[1]); + } + } + $n == 1 or $et->Error('Internal error updating chunk offsets'); + } + } + $$mdat[0] = $$edit[1]; # remove old data + } + } + } + if ($changed) { + @mdat = ( @newMdat, @thisMdat ); + ++$$et{CHANGED}; + } else { + $et->Error('Internal error modifying mdat'); + } + } + + # determine our new mdat positions + # (0=old pos, 1=old end, 2=mdat header, 3=new pos, 4=new data ref if changed, 5=new item ID) + my $pos = length $$outfile; + foreach $mdat (@mdat) { + $pos += length $$mdat[2]; + $$mdat[3] = $pos; + $pos += $$mdat[4] ? length(${$$mdat[4]}) : $$mdat[1] - $$mdat[0]; + } + + # fix up offsets for new mdat position(s) (and uuid positions in CR3 images) + foreach $co (@$off) { + my ($type, $ptr, $len, $base, $id) = @$co; + $base = 0 unless $base; + unless ($type =~ /^(stco|co64)_?(.*)$/) { + next if $type eq 'uuid'; + $type eq 'CTBO' or $et->Error('Internal error fixing offsets'), last; + # update 'CTBO' item offsets/sizes in Canon CR3 images + $$co[2] > 12 or $et->Error('Invalid CTBO atom'), last; + @mdat or $et->Error('Missing CR3 image data'), last; + my $n = Get32u($outfile, $$co[1] + 8); + $$co[2] < $n * 20 + 12 and $et->Error('Truncated CTBO atom'), last; + my (%ctboOff, $i); + # determine uuid types, and build an offset lookup based on CTBO ID number + foreach (@$off) { + next unless $$_[0] eq 'uuid' and $$_[2] >= 24; # (ignore undersized and deleted uuid boxes) + my $pos = $$_[1]; + next if $pos + 24 > length $$outfile; # (will happen for WriteLast uuid tags) + my $siz = Get32u($outfile, $pos); # get size of uuid atom + if ($siz == 1) { # check for extended (8-byte) size + next unless $$_[2] >= 32; + $pos += 8; + } + # get CTBO entry ID based on 16-byte UUID identifier + my $id = $ctboID{substr($$outfile, $pos+8, 16)}; + $ctboOff{$id} = $_ if defined $id; + } + # calculate new offset for the first mdat (size of -1 indicates it didn't change) + $ctboOff{3} = [ 'mdat', $mdat[0][3] - length $mdat[0][2], -1 ]; + for ($i=0; $i<$n; ++$i) { + my $pos = $$co[1] + 12 + $i * 20; + my $id = Get32u($outfile, $pos); + # ignore if size is zero unless we can add this entry + # (note: can't yet add/delete PreviewImage, but leave this possibility open) + next unless Get64u($outfile, $pos + 12) or $id == 1 or $id == 2; + if (not defined $ctboOff{$id}) { + $id==1 or $id==2 or $et->Error("Can't handle CR3 CTBO ID number $id"), last; + # XMP or PreviewImage was deleted -- set offset and size to zero + $ctboOff{$id} = [ 'uuid', 0, 0 ]; + } + # update the new offset and size of this entry + Set64u($ctboOff{$id}[1], $outfile, $pos + 4); + Set64u($ctboOff{$id}[2], $outfile, $pos + 12) unless $ctboOff{$id}[2] < 0; + } + next; + } + my $siz = $1 eq 'co64' ? 8 : 4; + my ($n, $tag); + if ($2) { # is this an offset in an iloc or 'gps ' atom? + $n = 1; + $type = $1; + $tag = $2; + } else { # this is an stco or co84 atom + next if $len < 8; + $n = Get32u($outfile, $ptr + 4); # get number of entries in table + $ptr += 8; + $len -= 8; + $tag = $1; + } + my $end = $ptr + $n * $siz; + $end > $ptr + $len and $et->Error("Invalid $tag table"), return $rtnVal; + for (; $ptr<$end; $ptr+=$siz) { + my ($ok, $i); + my $val = $type eq 'co64' ? Get64u($outfile, $ptr) : Get32u($outfile, $ptr); + for ($i=0; $i<@mdat; ++$i) { + $mdat = $mdat[$i]; + my $pos = $val + $base; + if (defined $$mdat[5]) { # is this chunk associated with an item we edited? + # set offset only for the corresponding new chunk + unless (defined $id and $id == $$mdat[5]) { + # could have pointed to empty chunk before inserted chunk + next unless $pos == $$mdat[0] and $$mdat[0] != $$mdat[1]; + } + } else { + # (have seen $pos == $$mdat[1], which is a real PITA) + next unless $pos >= $$mdat[0] and ($pos <= $$mdat[1] or not $$mdat[1]); + # step to next chunk if contiguous and at the end of this one + next if $pos == $$mdat[1] and $i+1 < @mdat and $pos == $mdat[$i+1][0]; + } + $val += $$mdat[3] - $$mdat[0]; + if ($val < 0) { + $et->Error("Error fixing up $tag offset"); + return $rtnVal; + } + if ($type eq 'co64') { + Set64u($val, $outfile, $ptr); + } elsif ($val <= 0xffffffff) { + Set32u($val, $outfile, $ptr); + } else { + $et->Error("Can't yet promote $tag offset to 64 bits"); + return $rtnVal; + } + $ok = 1; + last; + } + unless ($ok) { + $et->Error("Chunk offset in $tag atom is outside media data"); + return $rtnVal; + } + } + } + + # switch back to actual output file + $outfile = $$dirInfo{OutFile}; + + # write the metadata + Write($outfile, $outBuff) or $rtnVal = 0; + + # write the media data + foreach $mdat (@mdat) { + Write($outfile, $$mdat[2]) or $rtnVal = 0; # write mdat header + if ($$mdat[4]) { + Write($outfile, ${$$mdat[4]}) or $rtnVal = 0; + } else { + $raf->Seek($$mdat[0], 0) or $et->Error('Seek error'), last; + if ($$mdat[1]) { + my $result = Image::ExifTool::CopyBlock($raf, $outfile, $$mdat[1] - $$mdat[0]); + defined $result or $rtnVal = 0, last; + $result or $et->Error("Truncated mdat atom"), last; + } else { + # mdat continues to end of file + my $buff; + while ($raf->Read($buff, 65536)) { + Write($outfile, $buff) or $rtnVal = 0, last; + } + } + } + } + + # write the stuff that must come last + Write($outfile, $writeLast) or $rtnVal = 0 if $writeLast; - return $dataPt ? ($rtnVal ? $$outfile : undef) : $rtnVal; + return $rtnVal; } #------------------------------------------------------------------------------ @@ -312,7 +1864,7 @@ ($$$) sub WriteMOV($$) { my ($et, $dirInfo) = @_; - $et or return 1; + $et or return 1; # allow dummy access to autoload this package my $raf = $$dirInfo{RAF} or return 0; my ($buff, $ftype); @@ -325,15 +1877,16 @@ ($$) my $tagTablePtr = GetTagTable('Image::ExifTool::QuickTime::Main'); return 0 unless $$tagTablePtr{$tag}; - # determine the file type + # determine the file type (by default, assume MP4 if 'ftyp' exists + # without 'qt ' as a compatible brand, but HEIC is an exception) if ($tag eq 'ftyp' and $size >= 12 and $size < 100000 and $raf->Read($buff, $size-8) == $size-8 and $buff !~ /^(....)+(qt )/s) { - # file is MP4 format if 'ftyp' exists without 'qt ' as a compatible brand - if ($buff =~ /^(heic|mif1|msf1|heix|hevc|hevx)/) { + if ($buff =~ /^crx /) { + $ftype = 'CR3', + } elsif ($buff =~ /^(heic|mif1|msf1|heix|hevc|hevx|avif)/) { $ftype = 'HEIC'; - $et->Error("Can't currently write HEIC/HEIF files"); } else { $ftype = 'MP4'; } @@ -341,14 +1894,17 @@ ($$) $ftype = 'MOV'; } $et->SetFileType($ftype); # need to set "FileType" tag for a Condition - $et->InitWriteDirs($dirMap{$ftype}, 'XMP'); + $et->InitWriteDirs($dirMap{$ftype}, 'XMP', 'QuickTime'); $$et{DirMap} = $dirMap{$ftype}; # need access to directory map when writing + # track tags globally to avoid creating multiple tags in the case of duplicate directories + $$et{DidTag} = { }; SetByteOrder('MM'); $raf->Seek(0,0); # write the file $$dirInfo{Parent} = ''; $$dirInfo{DirName} = 'MOV'; + $$dirInfo{ChunkOffset} = [ ]; # (just to be safe) return WriteQuickTime($et, $dirInfo, $tagTablePtr) ? 1 : -1; } @@ -371,7 +1927,7 @@ =head1 DESCRIPTION =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/WriteXMP.pl b/src/Image-ExifTool/lib/Image/ExifTool/WriteXMP.pl index 9dec862e..9ff5adcc 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/WriteXMP.pl +++ b/src/Image-ExifTool/lib/Image/ExifTool/WriteXMP.pl @@ -12,7 +12,7 @@ package Image::ExifTool::XMP; use Image::ExifTool qw(:DataAccess :Utils); -sub CheckXMP($$$); +sub CheckXMP($$$;$); sub CaptureXMP($$$;$); sub SetPropertyPath($$;$$$$); @@ -45,7 +45,7 @@ package Image::ExifTool::XMP; my $xmpClose = "</x:xmpmeta>\n"; my $pktCloseW = "<?xpacket end='w'?>"; # writable by default my $pktCloseR = "<?xpacket end='r'?>"; -my $noPad; +my ($sp, $nl); #------------------------------------------------------------------------------ # Get XMP opening tag (and set x:xmptk appropriately) @@ -90,11 +90,11 @@ ($;$) #------------------------------------------------------------------------------ # Validate XMP property -# Inputs: 0) ExifTool ref, 1) validate hash ref +# Inputs: 0) ExifTool ref, 1) validate hash ref, 2) attribute hash ref # - issues warnings if problems detected -sub ValidateProperty($$) +sub ValidateProperty($$;$) { - my ($et, $propList) = @_; + my ($et, $propList, $attr) = @_; if ($$et{XmpValidate} and @$propList > 2) { if ($$propList[0] =~ /^x:x[ma]pmeta$/ and @@ -105,10 +105,23 @@ ($$) if ($$propList[-1] =~ /^rdf:(Bag|Seq|Alt)$/) { $et->Warn("Ignored empty $$propList[-1] list for $$propList[-2]", 1); } else { + if ($$propList[-2] eq 'rdf:Alt' and $attr) { + my $lang = $$attr{'xml:lang'}; + if ($lang and @$propList >= 5) { + my $langPath = join('/', @$propList[3..($#$propList-2)]); + my $valLang = $$et{XmpValidateLangAlt} || ($$et{XmpValidateLangAlt} = { }); + $$valLang{$langPath} or $$valLang{$langPath} = { }; + if ($$valLang{$langPath}{$lang}) { + $et->WarnOnce("Duplicate language ($lang) in lang-alt list: $langPath"); + } else { + $$valLang{$langPath}{$lang} = 1; + } + } + } my $xmpValidate = $$et{XmpValidate}; my $path = join('/', @$propList[3..$#$propList]); if (defined $$xmpValidate{$path}) { - $et->Warn("Duplicate XMP property: $path") if defined $$xmpValidate{$path}; + $et->Warn("Duplicate XMP property: $path"); } else { $$xmpValidate{$path} = 1; } @@ -124,7 +137,7 @@ ($$) #------------------------------------------------------------------------------ # Check XMP date values for validity and format accordingly -# Inputs: 1) date string +# Inputs: 1) EXIF-format date string # Returns: XMP date/time string (or undef on error) sub FormatXMPDate($) { @@ -152,12 +165,12 @@ ($) #------------------------------------------------------------------------------ # Check XMP values for validity and format accordingly -# Inputs: 0) ExifTool object ref, 1) tagInfo hash ref, 2) raw value ref +# Inputs: 0) ExifTool object ref, 1) tagInfo hash ref, 2) raw value ref, 3) conversion type # Returns: error string or undef (and may change value) on success # Note: copies structured information to avoid conflicts with calling code -sub CheckXMP($$$) +sub CheckXMP($$$;$) { - my ($et, $tagInfo, $valPtr) = @_; + my ($et, $tagInfo, $valPtr, $convType) = @_; if ($$tagInfo{Struct}) { require 'Image/ExifTool/XMPStruct.pl'; @@ -237,9 +250,12 @@ ($$$) return "Invalid date/time (use YYYY:mm:dd HH:MM:SS[.ss][+/-HH:MM|Z])" unless $newDate; $$valPtr = $newDate; } elsif ($format eq 'boolean') { + # (allow lower-case 'true' and 'false' if not setting PrintConv value) if (not $$valPtr or $$valPtr =~ /false/i or $$valPtr =~ /^no$/i) { - $$valPtr = 'False'; - } else { + if (not $$valPtr or $$valPtr ne 'false' or not $convType or $convType eq 'PrintConv') { + $$valPtr = 'False'; + } + } elsif ($$valPtr ne 'true' or not $convType or $convType eq 'PrintConv') { $$valPtr = 'True'; } } elsif ($format eq '1') { @@ -282,6 +298,8 @@ ($$;$$$$) $flatInfo = $$tagTablePtr{$flatID}; if ($flatInfo) { return if $$flatInfo{PropertyPath}; + } elsif (@$propList > 50) { + return; # avoid deep recursion } else { # flattened tag doesn't exist, so create it now # (could happen if we were just writing a structure) @@ -324,9 +342,8 @@ ($$;$$$$) # add required properties if this is a list push @propList, "rdf:$listType", 'rdf:li 10' if $listType and $listType ne '1'; # set PropertyPath for all flattened tags of this structure if necessary - # (note: don't do this for variable-namespace structures (undef NAMESPACE)) my $strTable = $$tagInfo{Struct}; - if ($strTable and $$strTable{NAMESPACE} and not ($parentID and + if ($strTable and not ($parentID and # must test NoSubStruct flag to avoid infinite recursion (($$tagTablePtr{$parentID} and $$tagTablePtr{$parentID}{NoSubStruct}) or length $parentID > 500))) # avoid deep recursion @@ -491,10 +508,10 @@ ($$) my $prop; foreach $prop (@propList) { my ($ns, $tag) = $prop =~ /(.+?):(.*)/; - next if $$nsUsed{$ns}; + next if not defined $ns or $$nsUsed{$ns}; my $uri = $nsURI{$ns}; unless ($uri) { - warn "No URI for namepace prefix $ns!\n"; + warn "No URI for namespace prefix $ns!\n"; next; } my $ns2; @@ -543,6 +560,36 @@ ($$$$;$) } } +#------------------------------------------------------------------------------ +# Hack to use XMP writer for SphericalVideoXML +# Inputs: 0) ExifTool ref, 1) dirInfo ref, 2) tag table ref +# Returns: SphericalVideoXML data +sub WriteGSpherical($$$) +{ + my ($et, $dirInfo, $tagTablePtr) = @_; + $$dirInfo{Compact} = 1, + my $dataPt = $$dirInfo{DataPt}; + if ($dataPt and $$dataPt) { + # make it look like XMP for writing + my $buff = $$dataPt; + $buff =~ s/<rdf:SphericalVideo/<?xpacket begin='.*?' id='W5M0MpCehiHzreSzNTczkc9d'?>\n<x:xmpmeta xmlns:x='adobe:ns:meta\/'><rdf:RDF/; + $buff =~ s/\s*xmlns:GSpherical/>\n<rdf:Description xmlns:GSpherical/s; + $buff =~ s/<\/rdf:SphericalVideo>/<\/rdf:Description>/; + $buff .= "</rdf:RDF></x:xmpmeta><?xpacket end='w'?>"; + $$dirInfo{DataPt} = \$buff; + $$dirInfo{DirLen} = length($buff) - ($$dirInfo{DirStart} || 0); + } + my $xmp = Image::ExifTool::XMP::WriteXMP($et, $dirInfo, $tagTablePtr); + if ($xmp) { + # change back to rdf:SphericalVideo structure + $xmp =~ s/^<\?xpacket begin.*?<rdf:RDF/<rdf:SphericalVideo\n/s; + $xmp =~ s/>\s*<rdf:Description rdf:about=''\s*/\n /; + $xmp =~ s/\s*<\/rdf:Description>\s*(<\/rdf:RDF>)/\n<\/rdf:SphericalVideo>$1/s; + $xmp =~ s/\s*<\/rdf:RDF>\s*<\/x:xmpmeta>.*//s; + } + return $xmp; +} + #------------------------------------------------------------------------------ # Utility routine to encode data in base64 # Inputs: 0) binary data string, 1) flag to avoid inserting newlines @@ -604,13 +651,12 @@ ($$$$$$) push @$startPt, length($$dataPt); # add end offset to list my $newData = substr($$dataPt, 0, $$startPt[0]); my $guid = '0' x 32; - my $sp = $noPad ? '' : ' '; # write the required xmpNote:HasExtendedXMP property - $newData .= "\n$sp<$rdfDesc rdf:about='${about}'\n$sp${sp}xmlns:xmpNote='$nsURI{xmpNote}'"; - if ($et->Options('XMPShorthand')) { + $newData .= "$nl$sp<$rdfDesc rdf:about='${about}'\n$sp${sp}xmlns:xmpNote='$nsURI{xmpNote}'"; + if ($$et{OPTIONS}{Compact}{Shorthand}) { $newData .= "\n$sp${sp}xmpNote:HasExtendedXMP='${guid}'/>\n"; } else { - $newData .= ">\n$sp$sp<xmpNote:HasExtendedXMP>$guid</xmpNote:HasExtendedXMP>\n$sp</$rdfDesc>\n"; + $newData .= ">$nl$sp$sp<xmpNote:HasExtendedXMP>$guid</xmpNote:HasExtendedXMP>$nl$sp</$rdfDesc>\n"; } my ($i, %descSize, $start); @@ -645,49 +691,49 @@ ($$$$$$) # Close out bottom-level property # Inputs: 0) current property path list ref, 1) longhand properties at each resource # level, 2) shorthand properties at each resource level, 3) resource flag for -# each property path level (set only if XMPShorthand is enabled) +# each property path level (set only if Shorthand is enabled) sub CloseProperty($$$$) { my ($curPropList, $long, $short, $resFlag) = @_; my $prop = pop @$curPropList; $prop =~ s/ .*//; # remove list index if it exists - my $pad = $noPad ? '' : ' ' x (scalar(@$curPropList) + 1); + my $pad = $sp x (scalar(@$curPropList) + 1); if ($$resFlag[@$curPropList]) { # close this XMP structure with possible shorthand properties if (length $$short[-1]) { if (length $$long[-1]) { # require a new Description if both longhand and shorthand properties - $$long[-2] .= ">\n$pad<$rdfDesc"; - $$short[-1] .= ">\n"; - $$long[-1] .= "$pad</$rdfDesc>\n"; + $$long[-2] .= ">$nl$pad<$rdfDesc"; + $$short[-1] .= ">$nl"; + $$long[-1] .= "$pad</$rdfDesc>$nl"; } else { # simply close empty property if all shorthand - $$short[-1] .= "/>\n"; + $$short[-1] .= "/>$nl"; } } else { # use "parseType" instead of opening a new Description $$long[-2] .= ' rdf:parseType="Resource"'; - $$short[-1] = length $$long[-1] ? ">\n" : "/>\n"; + $$short[-1] = length $$long[-1] ? ">$nl" : "/>$nl"; } - $$long[-1] .= "$pad</$prop>\n" if length $$long[-1]; + $$long[-1] .= "$pad</$prop>$nl" if length $$long[-1]; $$long[-2] .= $$short[-1] . $$long[-1]; pop @$short; pop @$long; } elsif (defined $$resFlag[@$curPropList]) { # close this top level Description with possible shorthand values if (length $$long[-1]) { - $$long[-2] .= $$short[-1] . ">\n" . $$long[-1] . "$pad</$prop>\n"; + $$long[-2] .= $$short[-1] . ">$nl" . $$long[-1] . "$pad</$prop>$nl"; } else { - $$long[-2] .= $$short[-1] . "/>\n"; # empty element (ie. all shorthand) + $$long[-2] .= $$short[-1] . "/>$nl"; # empty element (ie. all shorthand) } $$short[-1] = $$long[-1] = ''; } else { # close this property (no chance of shorthand) - $$long[-1] .= "$pad</$prop>\n"; + $$long[-1] .= "$pad</$prop>$nl"; unless (@$curPropList) { # add properties now that this top-level Description is complete - $$long[-2] .= ">\n" . $$long[-1]; + $$long[-2] .= ">$nl" . $$long[-1]; $$long[-1] = ''; } } @@ -696,8 +742,8 @@ ($$$$) #------------------------------------------------------------------------------ # Write XMP information -# Inputs: 0) ExifTool object reference, 1) source dirInfo reference, -# 2) [optional] tag table reference +# Inputs: 0) ExifTool ref, 1) source dirInfo ref (with optional WriteGroup), +# 2) [optional] tag table ref # Returns: with tag table: new XMP data (may be empty if no XMP data) or undef on error # without tag table: 1 on success, 0 if not valid XMP file, -1 on write error # Notes: May set dirInfo InPlace flag to rewrite with specified DirLen (=2 to allow larger) @@ -715,11 +761,10 @@ ($$;$) my $xmpFile = (not $tagTablePtr); # this is an XMP data file if no $tagTablePtr # prefer XMP over other metadata formats in some types of files my $preferred = $xmpFile || ($$et{PreferredGroup} and $$et{PreferredGroup} eq 'XMP'); - my $verbose = $et->Options('Verbose'); - my $compact = $et->Options('Compact') || 0; + my $verbose = $$et{OPTIONS}{Verbose}; + my %compact = ( %{$$et{OPTIONS}{Compact}} ); # (make a copy so we can change settings) my $dirLen = $$dirInfo{DirLen}; $dirLen = length($$dataPt) if not defined $dirLen and $dataPt; - $noPad = ($compact > 1); # # extract existing XMP information into %capture hash # @@ -736,6 +781,9 @@ ($$;$) delete $$et{XMP_IS_XML}; delete $$et{XMP_IS_SVG}; + # set current padding characters + ($sp, $nl) = ($compact{NoIndent} ? '' : ' ', $compact{NoNewline} ? '' : "\n"); + # get value for new rdf:about my $tagInfo = $Image::ExifTool::XMP::rdf{about}; if (defined $$et{NEW_VALUE}{$tagInfo}) { @@ -816,7 +864,7 @@ ($$;$) # if (%{$$et{DEL_GROUP}} and (grep /^XMP-.+$/, keys %{$$et{DEL_GROUP}} or # (logic is a bit more complex for group names in exiftool XML files) - grep m{^http://ns.exiftool.ca/}, values %nsUsed)) + grep m{^http://ns.exiftool.(?:ca|org)/}, values %nsUsed)) { my $del = $$et{DEL_GROUP}; my $path; @@ -827,7 +875,7 @@ ($$;$) $ns = $stdXlatNS{$ns} if $stdXlatNS{$ns}; my ($grp, @g); # no "XMP-" added to most groups in exiftool RDF/XML output file - if ($nsUsed{$ns} and (@g = ($nsUsed{$ns} =~ m{^http://ns.exiftool.ca/(.*?)/(.*?)/}))) { + if ($nsUsed{$ns} and (@g = ($nsUsed{$ns} =~ m{^http://ns.exiftool.(?:ca|org)/(.*?)/(.*?)/}))) { if ($g[1] =~ /^\d/) { $grp = "XML-$g[0]"; #(all XML-* groups stored as uppercase DEL_GROUP key) @@ -861,10 +909,12 @@ ($$;$) # get hash of all information we want to change # (sorted by tag name so alternate languages come last, but with structures # first so flattened tags may be used to override individual structure elements) - my @tagInfoList; + my (@tagInfoList, $delLangPath, %delLangPaths, %delAllLang, $firstNewPath); + my $writeGroup = $$dirInfo{WriteGroup}; foreach $tagInfo (sort ByTagName $et->GetNewTagInfoList()) { next unless $et->GetGroup($tagInfo, 0) eq 'XMP'; next if $$tagInfo{Name} eq 'XMP'; # (ignore full XMP block if we didn't write it already) + next if $writeGroup and $writeGroup ne $$et{NEW_VALUE}{$tagInfo}{WriteGroup}; if ($$tagInfo{Struct}) { unshift @tagInfoList, $tagInfo; } else { @@ -872,6 +922,7 @@ ($$;$) } } foreach $tagInfo (@tagInfoList) { + my @delPaths; # list of deleted paths my $tag = $$tagInfo{TagID}; my $path = GetPropertyPath($tagInfo); unless ($path) { @@ -987,9 +1038,33 @@ ($$;$) my $nvHash = $et->GetNewValueHash($tagInfo); my $overwrite = $et->IsOverwriting($nvHash); my $writable = $$tagInfo{Writable} || ''; - my (%attrs, $deleted, $added, $existed); + my (%attrs, $deleted, $added, $existed, $newLang); + # set up variables to save/restore paths of deleted lang-alt tags + if ($writable eq 'lang-alt') { + $newLang = lc($$tagInfo{LangCode} || 'x-default'); + if ($delLangPath and $delLangPath eq $path) { + # restore paths of deleted entries for this language + @delPaths = @{$delLangPaths{$newLang}} if $delLangPaths{$newLang}; + } else { + undef %delLangPaths; + $delLangPath = $path; # base path for deleted lang-alt tags + undef %delAllLang; + undef $firstNewPath; # reset first path for new lang-alt tag + } + if (%delAllLang) { + # add missing paths to delete list for entries where all languages were deleted + my ($prefix, $reSort); + foreach $prefix (keys %delAllLang) { + next if grep /^$prefix/, @delPaths; + push @delPaths, "${prefix}10"; + $reSort = 1; + } + @delPaths = sort @delPaths if $reSort; + } + } # delete existing entry if necessary if ($isStruct) { + # delete all structure (or pseudo-structure) elements require 'Image/ExifTool/XMPStruct.pl'; ($deleted, $added, $existed) = DeleteStruct($et, \%capture, \$path, $nvHash, \$changed); next unless $deleted or $added or $et->IsOverwriting($nvHash); @@ -999,7 +1074,7 @@ ($$;$) # take attributes from old values if they exist %attrs = %{$$cap[1]}; if ($overwrite) { - my ($delPath, $oldLang, $delLang, $addLang, @matchingPaths); + my ($oldLang, $delLang, $addLang, @matchingPaths, $langPathPat, %langsHere); # check to see if this is an indexed list item if ($path =~ / /) { my $pp; @@ -1008,17 +1083,24 @@ ($$;$) } else { push @matchingPaths, $path; } + my $oldOverwrite = $overwrite; foreach $path (@matchingPaths) { my ($val, $attrs) = @{$capture{$path}}; if ($writable eq 'lang-alt') { + # get original language code (lc for comparisons) + $oldLang = lc($$attrs{'xml:lang'} || 'x-default'); + # revert to original overwrite flag if this is in a different structure + if (not $langPathPat or $path !~ /^$langPathPat$/) { + $overwrite = $oldOverwrite; + ($langPathPat = $path) =~ s/\d+$/\\d+/; + } + # remember languages in this lang-alt list + $langsHere{$langPathPat}{$oldLang} = 1; unless (defined $addLang) { # add to lang-alt list by default if creating this tag from scratch $addLang = $$nvHash{IsCreating} ? 1 : 0; } - # get original language code (lc for comparisons) - $oldLang = lc($$attrs{'xml:lang'} || 'x-default'); if ($overwrite < 0) { - my $newLang = lc($$tagInfo{LangCode} || 'x-default'); next unless $oldLang eq $newLang; # only add new tag if we are overwriting this one # (note: this won't match if original XML contains CDATA!) @@ -1058,9 +1140,23 @@ ($$;$) } # save attributes and path from first deleted property # so we can replace it exactly - unless ($delPath) { - %attrs = %$attrs; - $delPath = $path; + %attrs = %$attrs unless @delPaths; + if ($writable eq 'lang-alt') { + $langsHere{$langPathPat}{$oldLang} = 0; # (lang was deleted) + } + # save deleted paths so we can replace the same elements + # (separately for each language of a lang-alt list) + if ($writable ne 'lang-alt' or $oldLang eq $newLang) { + push @delPaths, $path; + } else { + $delLangPaths{$oldLang} or $delLangPaths{$oldLang} = [ ]; + push @{$delLangPaths{$oldLang}}, $path; + } + # keep track of paths where we deleted all languages of a lang-alt tag + if ($delLang) { + my $p; + ($p = $path) =~ s/\d+$//; + $delAllLang{$p} = 1; } # delete this tag delete $capture{$path}; @@ -1072,14 +1168,28 @@ ($$;$) delete $capture{"$pp/rdf:type"} if @a == 1; } } - next unless $delPath or $$tagInfo{List} or $addLang; - if ($delPath) { - $path = $delPath; + next unless @delPaths or $$tagInfo{List} or $addLang; + if (@delPaths) { + $path = shift @delPaths; + # make sure new path is unique + while ($capture{$path}) { + last unless $path =~ s/ \d(\d+)$/' '.length($1+1).($1+1)/e; + } $deleted = 1; } else { # don't change tag if we couldn't delete old copy # unless this is a list or an lang-alt tag next unless $$tagInfo{List} or $oldLang; + # avoid adding duplicate entry to lang-alt in a list + if ($writable eq 'lang-alt' and %langsHere) { + foreach (sort keys %langsHere) { + next unless $path =~ /^$_$/; + last unless $langsHere{$_}{$newLang}; + $path =~ /(.* )\d(\d+)(.*? \d+)$/ or $et->Error('Internal error writing lang-alt list'), last; + my $nxt = $2 + 1; + $path = $1 . length($nxt) . ($nxt) . $3; # step to next index + } + } # (match last index to put in same lang-alt list for Bag of lang-alt items) $path =~ m/.* (\d+)/g or warn "Internal error: no list index!\n", next; $added = $1; @@ -1087,7 +1197,15 @@ ($$;$) } else { # we are never overwriting, so we must be adding to a list # match the last index unless this is a list of lang-alt lists - my $pat = $writable eq 'lang-alt' ? '.* (\d+)(.*? \d+)' : '.* (\d+)'; + my $pat = '.* (\d+)'; + if ($writable eq 'lang-alt') { + if ($firstNewPath) { + $path = $firstNewPath; + $overwrite = 1; # necessary to put x-default entry first below + } else { + $pat = '.* (\d+)(.*? \d+)'; + } + } if ($path =~ m/$pat/g) { $added = $1; # set position to end of matching index number @@ -1104,7 +1222,7 @@ ($$;$) $$tagInfo{LangCode} eq 'x-default')) { my $saveCap = $capture{$path}; - for (;;) { + while ($saveCap) { my $p = $path; substr($p, $pos, $len) = length($nxt) . $nxt; # increment index in the path of the existing item @@ -1116,10 +1234,9 @@ ($$;$) } } else { # add to end of list - for (;;) { + while ($capture{$path}) { my $try = length($nxt) . $nxt; substr($path, $pos, $len) = $try; - last unless $capture{$path}; $len = length $try; ++$nxt; } @@ -1142,8 +1259,10 @@ ($$;$) my @newValues = $et->GetNewValue($nvHash) or next; # set language attribute for lang-alt lists - $attrs{'xml:lang'} = $$tagInfo{LangCode} || 'x-default' if $writable eq 'lang-alt'; - + if ($writable eq 'lang-alt') { + $attrs{'xml:lang'} = $$tagInfo{LangCode} || 'x-default'; + $firstNewPath = $path if defined $added; # save path of first lang-alt tag added + } # add new value(s) to %capture hash my $subIdx; for (;;) { @@ -1164,7 +1283,9 @@ ($$;$) $et->Warn("$grp:$$tagInfo{Name} written as a literal because value is not a valid URI", 1); # fall through to write as a string literal } - delete $attrs{'rdf:resource'}; # (remove existing resource if necessary) + # remove existing value and/or resource attribute if they exist + delete $attrs{'rdf:value'}; + delete $attrs{'rdf:resource'}; $capture{$path} = [ $newValue, \%attrs ]; last; } @@ -1182,15 +1303,23 @@ ($$;$) # match last index except for lang-alt items where we want to put each # item in a different lang-alt list (so match the 2nd-last for these) my $pat = $writable eq 'lang-alt' ? '.* (\d+)(.*? \d+)' : '.* (\d+)'; - $path =~ m/$pat/g or warn("Internal error: no list index for $tag!\n"), next; + pos($path) = 0; + $path =~ m/$pat/g or warn("Internal error: no list index for $tag ($path) ($pat)!\n"), next; my $idx = $1; my $len = length $1; my $pos = pos($path) - $len - ($2 ? length $2 : 0); - # generate unique list sub-indices to store additional values in sequence + # use sub-indices if necessary to store additional values in sequence if ($subIdx) { $idx = substr($idx, 0, -length($subIdx)); # remove old sub-index $subIdx = substr($subIdx, 1) + 1; $subIdx = length($subIdx) . $subIdx; + } elsif (@delPaths) { + $path = shift @delPaths; + # make sure new path is unique + while ($capture{$path}) { + last unless $path =~ s/ \d(\d+)$/' '.length($1+1).($1+1)/e; + } + next; } else { $subIdx = '10'; } @@ -1228,7 +1357,6 @@ ($$;$) # write out the new XMP information (serialize it) # # start writing the XMP data - my $useShorthand = $et->Options('XMPShorthand'); my (@long, @short, @resFlag); $long[0] = $long[1] = $short[0] = ''; if ($$et{XMP_NO_XPACKET}) { @@ -1291,7 +1419,17 @@ ($$;$) my $uri = $nsUsed{$1}; unless ($uri) { $uri = $nsURI{$1}; # we must have added a namespace - $uri or $xmpErr = "Undefined XMP namespace: $1", next; + unless ($uri) { + # (namespace prefix may be empty if trying to write empty XMP structure, forum12384) + if (length $1) { + my $err = "Undefined XMP namespace: $1"; + if (not $xmpErr or $err ne $xmpErr) { + $xmpFile ? $et->Error($err) : $et->Warn($err); + $xmpErr = $err; + } + } + next; + } } $nsNew{$1} = $uri; # need a new description if any new namespaces @@ -1306,7 +1444,7 @@ ($$;$) my ($path2, $ns2); foreach $path2 (@pathList) { my @ns2s = ($path2 =~ m{(?:^|/)([^/]+?):}g); - my $opening = 0; + my $opening = $compact{OneDesc} ? 1 : 0; foreach $ns2 (@ns2s) { next if $ns2 eq 'rdf'; $nsNew{$ns2} and ++$opening, next; @@ -1335,18 +1473,17 @@ ($$;$) # open the new description $prop = $rdfDesc; %nsCur = %nsNew; # save current namespaces - my $sp = $noPad ? '' : ' '; my @ns = sort keys %nsCur; - $long[-2] .= "\n$sp<$prop rdf:about='${about}'"; + $long[-2] .= "$nl$sp<$prop rdf:about='${about}'"; # generate et:toolkit attribute if this is an exiftool RDF/XML output file - if (@ns and $nsCur{$ns[0]} =~ m{^http://ns.exiftool.ca/}) { - $long[-2] .= "\n$sp${sp}xmlns:et='http://ns.exiftool.ca/1.0/'" . + if (@ns and $nsCur{$ns[0]} =~ m{^http://ns.exiftool.(?:ca|org)/}) { + $long[-2] .= "\n$sp${sp}xmlns:et='http://ns.exiftool.org/1.0/'" . " et:toolkit='Image::ExifTool $Image::ExifTool::VERSION'"; } $long[-2] .= "\n$sp${sp}xmlns:$_='$nsCur{$_}'" foreach @ns; push @curPropList, $prop; - # set resFlag to 0 to indicate base description when XMPShorthand enabled - $resFlag[0] = 0 if $useShorthand; + # set resFlag to 0 to indicate base description when Shorthand enabled + $resFlag[0] = 0 if $compact{Shorthand}; } my ($val, $attrs) = @{$capture{$path}}; $debug and print "$path = $val\n"; @@ -1358,34 +1495,34 @@ ($$;$) $prop =~ s/ .*//; # remove list index if it exists # (we may add parseType and shorthand properties later, # so leave off the trailing ">" for now) - $long[-1] .= ($noPad ? '' : ' ' x scalar(@curPropList)) . "<$prop"; + $long[-1] .= ($compact{NoIndent} ? '' : ' ' x scalar(@curPropList)) . "<$prop"; if ($prop ne $rdfDesc and ($propList[$n+1] !~ /^rdf:/ or ($propList[$n+1] eq 'rdf:type' and $n+1 == $#propList))) { # check for empty structure if ($propList[$n+1] =~ /:~dummy~$/) { - $long[-1] .= " rdf:parseType='Resource'/>\n"; + $long[-1] .= " rdf:parseType='Resource'/>$nl"; pop @curPropList; $dummy = 1; last; } - if ($useShorthand) { + if ($compact{Shorthand}) { $resFlag[$#curPropList] = 1; push @long, ''; push @short, ''; } else { # use rdf:parseType='Resource' to avoid new 'rdf:Description' - $long[-1] .= " rdf:parseType='Resource'>\n"; + $long[-1] .= " rdf:parseType='Resource'>$nl"; } } else { - $long[-1] .= ">\n"; # (will be no shorthand properties) + $long[-1] .= ">$nl"; # (will be no shorthand properties) } } my $prop2 = pop @propList; # get new property name # add element unless it was a dummy structure field unless ($dummy or ($val eq '' and $prop2 =~ /:~dummy~$/)) { $prop2 =~ s/ .*//; # remove list index if it exists - my $pad = $noPad ? '' : ' ' x (scalar(@curPropList) + 1); + my $pad = $compact{NoIndent} ? '' : ' ' x (scalar(@curPropList) + 1); # (can't write as shortcut if it has attributes or CDATA) if (defined $resFlag[$#curPropList] and not %$attrs and $val !~ /<!\[CDATA\[/) { $short[-1] .= "\n$pad$prop2='${val}'"; @@ -1397,7 +1534,7 @@ ($$;$) my $quot = ($attrVal =~ /'/) ? '"' : "'"; $long[-1] .= " $attr=$quot$attrVal$quot"; } - $long[-1] .= length $val ? ">$val</$prop2>\n" : "/>\n"; + $long[-1] .= length $val ? ">$val</$prop2>$nl" : "/>$nl"; } } } @@ -1414,9 +1551,9 @@ ($$;$) $$dirInfo{ExtendedXMP} = $rtn[0]; $$dirInfo{ExtendedGUID} = $rtn[1]; # compact if necessary to fit - $compact = 1 if length($long[-2]) + 101 * $numPadLines > $maxDataLen; + $compact{NoPadding} = 1 if length($long[-2]) + 101 * $numPadLines > $maxDataLen; } - $compact = 1 if $$dirInfo{Compact}; + $compact{NoPadding} = 1 if $$dirInfo{Compact}; # # close out the XMP, clean up, and return our data # @@ -1438,7 +1575,7 @@ ($$;$) # pad to specified DirLen if ($len > $dirLen) { my $str = 'Not enough room to edit XMP in place'; - $str .= '. Try XMPShorthand option' unless $$et{OPTIONS}{XMPShorthand}; + $str .= '. Try Shorthand feature' unless $compact{Shorthand}; $et->Warn($str); return undef; } @@ -1448,7 +1585,7 @@ ($$;$) $len += length($pad) * $num; } $len < $dirLen and $long[-2] .= (' ' x ($dirLen - $len - 1)) . "\n"; - } elsif (not $compact and not $xmpFile and not $$dirInfo{ReadOnly}) { + } elsif (not $compact{NoPadding} and not $xmpFile and not $$dirInfo{ReadOnly}) { $long[-2] .= $pad x $numPadLines; } $long[-2] .= ($$dirInfo{ReadOnly} ? $pktCloseR : $pktCloseW); @@ -1457,14 +1594,7 @@ ($$;$) unless (%capture or $xmpFile or $$dirInfo{InPlace} or $$dirInfo{NoDelete}) { $long[-2] = ''; } - if ($xmpErr) { - if ($xmpFile) { - $et->Error($xmpErr); - return -1; - } - $et->Warn($xmpErr); - return undef; - } + return($xmpFile ? -1 : undef) if $xmpErr; $$et{CHANGED} += $changed; $debug > 1 and $long[-2] and print $long[-2],"\n"; return $long[-2] unless $xmpFile; @@ -1491,7 +1621,7 @@ =head1 DESCRIPTION =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/Writer.pl b/src/Image-ExifTool/lib/Image/ExifTool/Writer.pl index 37627271..93baf5de 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/Writer.pl +++ b/src/Image-ExifTool/lib/Image/ExifTool/Writer.pl @@ -5,7 +5,7 @@ # # Notes: Also contains some less used ExifTool functions # -# URL: http://owl.phy.queensu.ca/~phil/exiftool/ +# URL: https://exiftool.org/ # # Revisions: 12/16/2004 - P. Harvey Created #------------------------------------------------------------------------------ @@ -28,7 +28,7 @@ package Image::ExifTool; sub ConvInv($$$$$;$$); my $loadedAllTables; # flag indicating we loaded all tables -my $advFmtSelf; # ExifTool during evaluation of advanced formatting expr +my $advFmtSelf; # ExifTool object during evaluation of advanced formatting expr # the following is a road map of where we write each directory # in the different types of files. @@ -48,6 +48,7 @@ package Image::ExifTool; MakerNotes => 'ExifIFD', CanonVRD => 'MakerNotes', # (so VRDOffset will get updated) NikonCapture => 'MakerNotes', # (to allow delete by group) + PhaseOne => 'MakerNotes', # (for editing PhaseOne SensorCalibration tags) ); my %exifMap = ( IFD1 => 'IFD0', @@ -104,6 +105,7 @@ package Image::ExifTool; ICC => [ 'ICC_Profile', 'WriteICC' ], IND => 'InDesign', JP2 => 'Jpeg2000', + JXL => 'Jpeg2000', MIE => undef, MOV => [ 'QuickTime', 'WriteMOV' ], MRW => 'MinoltaRaw', @@ -118,22 +120,41 @@ package Image::ExifTool; XMP => [ undef, 'WriteXMP' ], ); +# RAW file types +my %rawType = ( + '3FR'=> 1, CR3 => 1, IIQ => 1, NEF => 1, RW2 => 1, + ARQ => 1, CRW => 1, K25 => 1, NRW => 1, RWL => 1, + ARW => 1, DCR => 1, KDC => 1, ORF => 1, SR2 => 1, + ARW => 1, ERF => 1, MEF => 1, PEF => 1, SRF => 1, + CR2 => 1, FFF => 1, MOS => 1, RAW => 1, SRW => 1, +); + # groups we are allowed to delete # Notes: # 1) these names must either exist in %dirMap, or be translated in InitWriteDirs()) # 2) any dependencies must be added to %excludeGroups my @delGroups = qw( - Adobe AFCP APP0 APP1 APP2 APP3 APP4 APP5 APP6 APP7 APP8 APP9 APP10 APP11 APP12 - APP13 APP14 APP15 CanonVRD CIFF Ducky EXIF ExifIFD File FlashPix FotoStation - GlobParamIFD GPS ICC_Profile IFD0 IFD1 InteropIFD IPTC JFIF Jpeg2000 MakerNotes - Meta MetaIFD MIE MPF NikonCapture PDF PDF-update PhotoMechanic Photoshop PNG - PNG-pHYs PrintIM RMETA RSRC SubIFD Trailer XML XML-* XMP XMP-* + Adobe AFCP APP0 APP1 APP2 APP3 APP4 APP5 APP6 APP7 APP8 APP9 APP10 APP11 + APP12 APP13 APP14 APP15 CanonVRD CIFF Ducky EXIF ExifIFD File FlashPix + FotoStation GlobParamIFD GPS ICC_Profile IFD0 IFD1 Insta360 InteropIFD IPTC + ItemList JFIF Jpeg2000 Keys MakerNotes Meta MetaIFD Microsoft MIE MPF + NikonApp NikonCapture PDF PDF-update PhotoMechanic Photoshop PNG PNG-pHYs + PrintIM QuickTime RMETA RSRC SubIFD Trailer UserData XML XML-* XMP XMP-* ); # family 2 group names that we can delete my @delGroup2 = qw( Audio Author Camera Document ExifTool Image Location Other Preview Printing Time Video ); +# Extra groups to delete when deleting another group +my %delMore = ( + QuickTime => [ qw(ItemList UserData Keys) ], + XMP => [ 'XMP-*' ], + XML => [ 'XML-*' ], +); + +# family 0 groups where directories should never be deleted +my %permanentDir = ( QuickTime => 1, Jpeg2000 => 1 ); # lookup for all valid family 2 groups (lower case) my %family2groups = map { lc $_ => 1 } @delGroup2, 'Unknown'; @@ -168,6 +189,7 @@ package Image::ExifTool; CanonVRD => [ 'Trailer' ], PhotoMechanic=> [ 'Trailer' ], MIE => [ 'Trailer' ], + QuickTime => [ qw(ItemList UserData Keys) ], ); # translate (lower case) wanted group when writing for tags where group name may change my %translateWantGroup = ( @@ -218,7 +240,7 @@ package Image::ExifTool; 'int64s' => [-9223372036854775808, 9223372036854775807], ); # lookup for file types with block-writable EXIF -my %blockExifTypes = map { $_ => 1 } qw(JPEG PNG JP2 MIE EXIF FLIF); +my %blockExifTypes = map { $_ => 1 } qw(JPEG PNG JP2 MIE EXIF FLIF MOV MP4); my $maxSegmentLen = 0xfffd; # maximum length of data in a JPEG segment my $maxXMPLen = $maxSegmentLen; # maximum length of XMP data in JPEG @@ -249,6 +271,7 @@ package Image::ExifTool; # NoFlat => treat flattened tags as 'unsafe' # NoShortcut => true to prevent looking up shortcut tags # ProtectSaved => protect existing new values with a save count greater than this +# IgnorePermanent => ignore attempts to delete a permanent tag # CreateGroups => [internal use] createGroups hash ref from related tags # ListOnly => [internal use] set only list or non-list tags # SetTags => [internal use] hash ref to return tagInfo refs of set tags @@ -258,12 +281,12 @@ package Image::ExifTool; # each value in the list. Internally, the new information is stored in # the following members of the $$self{NEW_VALUE}{$tagInfo} hash: # TagInfo - tag info ref -# DelValue - list ref for values to delete -# Value - list ref for values to add (not defined if deleting the tag) +# DelValue - list ref for raw values to delete +# Value - list ref for raw values to add (not defined if deleting the tag) # IsCreating - must be set for the tag to be added for the standard file types, # otherwise just changed if it already exists. This may be # overridden for file types with a PREFERRED metadata type. -# Set to 2 to create inidividual tags but not new groups +# Set to 2 to create individual tags but not new groups # EditOnly - flag set if tag should never be created (regardless of file type). # If this is set, then IsCreating must be false # CreateOnly - flag set if creating only (never edit existing tag) @@ -336,19 +359,26 @@ ($;$$%) $options{Type} = 'ValueConv' if $tag =~ s/#$//; my $convType = $options{Type} || ($$self{OPTIONS}{PrintConv} ? 'PrintConv' : 'ValueConv'); + # filter value if necessary + $self->Filter($$self{OPTIONS}{FilterW}, \$value) or return 0 if $convType eq 'PrintConv'; + my (@wantGroup, $family2); my $wantGroup = $options{Group}; if ($wantGroup) { foreach (split /:/, $wantGroup) { next unless length($_) and /^(\d+)?(.*)/; # separate family number and group name - my ($f, $g) = ($1, lc $2); + my ($f, $g) = ($1, $2); + my $lcg = lc $g; # save group/family unless '*' or 'all' - push @wantGroup, [ $f, $g ] unless $g eq '*' or $g eq 'all'; - if (defined $f) { - $f > 2 and return 0; # only allow family 0, 1 or 2 - $family2 = 1 if $f == 2; # set flag indicating family 2 was used + push @wantGroup, [ $f, $lcg ] unless $lcg eq '*' or $lcg eq 'all'; + if ($g =~ s/^ID-//i) { # family 7 is a tag ID + return 0 if defined $f and $f ne 7; + $wantGroup[-1] = [ 7, $g ]; # group name with 'ID-' removed and case preserved + } elsif (defined $f) { + $f > 2 and return 0; # only allow family 0, 1 or 2 + $family2 = 1 if $f == 2; # set flag indicating family 2 was used } else { - $family2 = 1 if $family2groups{$g}; + $family2 = 1 if $family2groups{$lcg}; } } undef $wantGroup unless @wantGroup; @@ -423,10 +453,9 @@ ($;$$%) } } else { $$delGroup{$grp} = 1; - # add flag for XMP/XML family 1 groups if deleting all XMP - if ($grp =~ /^XM[LP]$/) { - $$delGroup{"$grp-*"} = 1; - push @donegrps, "$grp-*"; + # add extra groups to delete if necessary + if ($delMore{$grp}) { + $$delGroup{$_} = 1, push @donegrps, $_ foreach @{$delMore{$grp}}; } # remove all of this group from previous new values $self->RemoveNewValuesForGroup($grp); @@ -489,7 +518,10 @@ ($;$$%) # must load XMP table to set group1 names my $table = GetTagTable('Image::ExifTool::XMP::Main'); my $writeProc = $$table{WRITE_PROC}; - $writeProc and &$writeProc(); + if ($writeProc) { + no strict 'refs'; + &$writeProc(); + } } # fix case for known groups $wantGroup =~ s/$grpName/$grpName/i if $grpName and $grpName ne $_; @@ -503,7 +535,7 @@ ($;$$%) my $langCode; # allow language suffix of form "-en_CA" or "-<rfc3066>" on tag name if ($tag =~ /^([?*\w]+)-([a-z]{2})(_[a-z]{2})$/i or # MIE - $tag =~ /^([?*\w]+)-([a-z]{2,3}|[xi])(-[a-z\d]{2,8}(-[a-z\d]{1,8})*)?$/i) # XMP/PNG + $tag =~ /^([?*\w]+)-([a-z]{2,3}|[xi])(-[a-z\d]{2,8}(-[a-z\d]{1,8})*)?$/i) # XMP/PNG/QuickTime { $tag = $1; # normalize case of language codes @@ -542,6 +574,9 @@ ($;$$%) my $pre = $wantGroup ? $wantGroup . ':' : ''; $err = "Tag '$pre${origTag}' is not defined"; $err .= ' or has a bad language code' if $origTag =~ /-/; + if (not $pre and uc($origTag) eq 'TAG') { + $err .= " (specify a writable tag name, not '${origTag}' literally)" + } } else { $err = "Invalid tag name '${tag}'"; $err .= " (remove the leading '\$')" if $tag =~ /^\$/; @@ -567,7 +602,7 @@ ($;$$%) # the highest priority group # my (@tagInfoList, @writeAlsoList, %writeGroup, %preferred, %tagPriority); - my (%avoid, $wasProtected, $noCreate, %highestPriority); + my (%avoid, $wasProtected, $noCreate, %highestPriority, %highestQT); TAG: foreach $tagInfo (@matchingTags) { $tag = $$tagInfo{Name}; # get tag name for warnings @@ -575,22 +610,28 @@ ($;$$%) # initialize highest priority if we are starting a new tag $highestPriority{$lcTag} = -999 unless defined $highestPriority{$lcTag}; my ($priority, $writeGroup); + my $prfTag = defined $$tagInfo{Preferred} ? $$tagInfo{Preferred} : $$tagInfo{Table}{PREFERRED}; if ($wantGroup) { # a WriteGroup of All is special my $wgAll = ($$tagInfo{WriteGroup} and $$tagInfo{WriteGroup} eq 'All'); my @grp = $self->GetGroup($tagInfo); + my $hiPri = 1000; foreach $fg (@wantGroup) { my ($fam, $lcWant) = @$fg; $lcWant = $translateWantGroup{$lcWant} if $translateWantGroup{$lcWant}; # only set tag in specified group + # bump priority of preferred tag + $hiPri += $prfTag if $prfTag; if (not defined $fam) { if ($lcWant eq lc $grp[0]) { - # don't go to more generate write group of "All" + # don't go to more general write group of "All" # if something more specific was wanted $writeGroup = $grp[0] if $wgAll and not $writeGroup; next; } next if $lcWant eq lc $grp[2]; + } elsif ($fam == 7) { + next if IsSameID($$tagInfo{TagID}, $lcWant); } elsif ($fam != 1 and not $$tagInfo{AllowGroup}) { next if $lcWant eq lc $grp[$fam]; if ($wgAll and not $fam and $allFam0{$lcWant}) { @@ -610,9 +651,15 @@ ($;$$%) # can't yet write PreviewIFD tags (except for image) $lcWant eq 'PreviewIFD' and ++$foundMatch, next TAG; $writeGroup = $ifdName; # write to the specified IFD - } elsif ($grp[0] eq 'QuickTime' and $grp[1] eq 'Track#') { - next TAG unless $movGroup and $lcWant eq lc($movGroup); - $writeGroup = $movGroup; + } elsif ($grp[0] eq 'QuickTime') { + if ($grp[1] eq 'Track#') { + next TAG unless $movGroup and $lcWant eq lc($movGroup); + $writeGroup = $movGroup; + } else { + my $grp = $$tagInfo{Table}{WRITE_GROUP}; + next TAG unless $grp and $lcWant eq lc $grp; + $writeGroup = $grp; + } } elsif ($grp[0] eq 'MIE') { next TAG unless $mieGroup and $lcWant eq lc($mieGroup); $writeGroup = $mieGroup; # write to specific MIE group @@ -626,8 +673,8 @@ ($;$$%) next TAG unless $lcWant eq lc $grp[1]; } } - $writeGroup or $writeGroup = ($$tagInfo{WriteGroup} || $grp[0]); - $priority = 1000; # highest priority since group was specified + $writeGroup or $writeGroup = ($$tagInfo{WriteGroup} || $$tagInfo{Table}{WRITE_GROUP} || $grp[0]); + $priority = $hiPri; # highest priority since group was specified } ++$foundMatch; # must do a dummy call to the write proc to autoload write package @@ -639,7 +686,10 @@ ($;$$%) my $src = GetTagTable($$table{SRC_TABLE}); $writeProc = $$src{WRITE_PROC} unless $writeProc; } - next unless $writeProc and &$writeProc(); + { + no strict 'refs'; + next unless $writeProc and &$writeProc(); + } # must still check writable flags in case of UserDefined tags my $writable = $$tagInfo{Writable}; next unless $writable or ($$table{WRITABLE} and @@ -660,6 +710,8 @@ ($;$$%) $priority = $$self{WRITE_PRIORITY}{lc($group0)} || 0; } } + # adjust priority based on Preferred level for this tag + $priority += $prfTag if $prfTag; } # don't write tag if protected my $prot = $$tagInfo{Protected}; @@ -678,6 +730,9 @@ ($;$$%) } # set priority for this tag $tagPriority{$tagInfo} = $priority; + # keep track of highest priority QuickTime tag + $highestQT{$lcTag} = $priority if $$table{GROUPS}{0} eq 'QuickTime' and + (not defined $highestQT{$lcTag} or $highestQT{$lcTag} < $priority); if ($priority > $highestPriority{$lcTag}) { $highestPriority{$lcTag} = $priority; $preferred{$lcTag} = { $tagInfo => 1 }; @@ -693,9 +748,14 @@ ($;$$%) } else { push @tagInfoList, $tagInfo; } + # special case to allow override of XMP WriteGroup + if ($writeGroup eq 'XMP') { + my $wg = $$tagInfo{WriteGroup} || $$table{WRITE_GROUP}; + $writeGroup = $wg if $wg; + } $writeGroup{$tagInfo} = $writeGroup; } - # sort tag info list in reverse order of priority (higest number last) + # sort tag info list in reverse order of priority (highest number last) # so we get the highest priority error message in the end @tagInfoList = sort { $tagPriority{$a} <=> $tagPriority{$b} } @tagInfoList; # must write any tags which also write other tags first @@ -727,7 +787,9 @@ ($;$$%) my $priority = $tagPriority{$tagInfo} or next; next if $priority == $highestPriority{$lcTag}; next if $priority < $nextHighest; - next if $$tagInfo{Avoid} or $$tagInfo{Permanent}; + my $permanent = $$tagInfo{Permanent}; + $permanent = $$tagInfo{Table}{PERMANENT} unless defined $permanent; + next if $$tagInfo{Avoid} or $permanent; next if $writeGroup{$tagInfo} eq 'MakerNotes'; if ($nextHighest < $priority) { $nextHighest = $priority; @@ -760,10 +822,12 @@ ($;$$%) my $noConv; my $writeGroup = $writeGroup{$tagInfo}; my $permanent = $$tagInfo{Permanent}; + $permanent = $$tagInfo{Table}{PERMANENT} unless defined $permanent; $writeGroup eq 'MakerNotes' and $permanent = 1 unless defined $permanent; my $wgrp1 = $self->GetWriteGroup1($tagInfo, $writeGroup); $tag = $$tagInfo{Name}; # get tag name for warnings - my $pref = $preferred{lc $tag} || { }; + my $lcTag = lc $tag; + my $pref = $preferred{$lcTag} || { }; my $shift = $options{Shift}; my $addValue = $options{AddValue}; if (defined $shift) { @@ -794,7 +858,7 @@ ($;$$%) ($shift or ($shiftable eq '0' and $options{DelValue}))) { $err = "$wgrp1:$tag is not shiftable"; - $verbose > 2 and print $out "$err\n"; + $verbose and print $out "$err\n"; next; } } @@ -803,7 +867,7 @@ ($;$$%) # check to make sure this is a List or Shift tag if adding if ($addValue and not ($shift or $$tagInfo{List})) { if ($addValue eq '2') { - undef $addValue; # quitely reset this option + undef $addValue; # quietly reset this option } else { $err = "Can't add $wgrp1:$tag (not a List type)"; $verbose > 2 and print $out "$err\n"; @@ -838,6 +902,7 @@ ($;$$%) next; } } elsif ($permanent) { + return 0 if $options{IgnorePermanent}; # can't delete permanent tags, so set them to DelValue or empty string instead if (defined $$tagInfo{DelValue}) { $val = $$tagInfo{DelValue}; @@ -863,6 +928,20 @@ ($;$$%) next; } } + # set group delete flag if this tag represents an entire group + if ($$tagInfo{DelGroup} and not $options{DelValue}) { + my @del = ( $tag ); + $$self{DEL_GROUP}{$tag} = 1; + # delete extra groups if necessary + if ($delMore{$tag}) { + $$self{DEL_GROUP}{$_} = 1, push(@del,$_) foreach @{$delMore{$tag}}; + } + # remove all of this group from previous new values + $self->RemoveNewValuesForGroup($tag); + $verbose and print $out " Deleting tags in: @del\n"; + ++$numSet; + next; + } $noConv = 1; # value is not defined, so don't do conversion } # apply inverse PrintConv and ValueConv conversions @@ -896,7 +975,7 @@ ($;$$%) } else { $wgrp = ''; } - foreach $wtag (keys %{$$tagInfo{WriteAlso}}) { + foreach $wtag (sort keys %{$$tagInfo{WriteAlso}}) { my ($n,$e) = $self->SetNewValue($wgrp . $wtag, undef, Replace=>2); $numSet += $n; } @@ -949,7 +1028,12 @@ ($;$$%) # set priority flag to add only the high priority info # (will only create the priority tag if it doesn't exist, # others get changed only if they already exist) - if ($$pref{$tagInfo} or $$tagInfo{Table}{PREFERRED}) { + my $prf = defined $$tagInfo{Preferred} ? $$tagInfo{Preferred} : $$tagInfo{Table}{PREFERRED}; + # hack to prefer only a single tag in the QuickTime group + if ($$tagInfo{Table}{GROUPS}{0} eq 'QuickTime') { + $prf = 0 if $tagPriority{$tagInfo} < $highestQT{$lcTag}; + } + if ($$pref{$tagInfo} or $prf) { if ($permanent or $shift) { # don't create permanent or Shift-ed tag but define IsCreating # so we know that it is the preferred tag @@ -1039,7 +1123,7 @@ ($;$$%) $wgrp = ''; } local $SIG{'__WARN__'} = \&SetWarning; - foreach $wtag (keys %$writeAlso) { + foreach $wtag (sort keys %$writeAlso) { my %opts = ( Type => 'ValueConv', Protected => $protected | 0x02, @@ -1053,6 +1137,9 @@ ($;$$%) undef $evalWarning; #### eval WriteAlso ($val) my $v = eval $$writeAlso{$wtag}; + # we wanted to do the eval in case there are side effect, but we + # don't want to write a value for a tag that is being deleted: + undef $v unless defined $val; $@ and $evalWarning = $@; unless ($evalWarning) { ($n,$evalWarning) = $self->SetNewValue($wgrp . $wtag, $v, %opts); @@ -1181,7 +1268,9 @@ ($$;@) Filter => $$options{Filter}, FixBase => $$options{FixBase}, GlobalTimeShift => $$options{GlobalTimeShift}, + HexTagIDs => $$options{HexTagIDs}, IgnoreMinorErrors=>$$options{IgnoreMinorErrors}, + IgnoreTags => $$options{IgnoreTags}, Lang => $$options{Lang}, LargeFileSupport=> $$options{LargeFileSupport}, List => 1, @@ -1196,6 +1285,8 @@ ($$;@) QuickTimeUTC => $$options{QuickTimeUTC}, RequestAll => $$options{RequestAll} || 1, # (is this still necessary now that RequestTags are being set?) RequestTags => $$options{RequestTags}, + SaveFormat => $$options{SaveFormat}, + SavePath => $$options{SavePath}, ScanForXMP => $$options{ScanForXMP}, StrictDate => defined $$options{StrictDate} ? $$options{StrictDate} : 1, Struct => $structOpt, @@ -1259,13 +1350,13 @@ ($$;@) foreach $tag (@tags) { # don't try to set errors or warnings next if $tag =~ /^(Error|Warning)\b/; - # get approprite value type if necessary + # get appropriate value type if necessary if ($opts{SrcType} and $opts{SrcType} ne $srcType) { $$info{$tag} = $srcExifTool->GetValue($tag, $opts{SrcType}); } # set value for this tag my ($n, $e) = $self->SetNewValue($tag, $$info{$tag}, %opts); - # delete this tag if we could't set it + # delete this tag if we couldn't set it $n or delete $$info{$tag}; } return $info; @@ -1310,7 +1401,10 @@ ($$;@) } } # validate tag name(s) - $$opts{EXPR} or ValidTagName($tag) or $self->Warn("Invalid tag name '${tag}'"), next; + unless ($$opts{EXPR} or ValidTagName($tag)) { + $self->Warn("Invalid tag name '${tag}'. Use '=' not '<' to assign a tag value"); + next; + } ValidTagName($dstTag) or $self->Warn("Invalid tag name '${dstTag}'"), next; # translate '+' and '-' to appropriate SetNewValue option if ($opt) { @@ -1330,7 +1424,9 @@ ($$;@) foreach (split /:/, $grp) { # save family/groups in list (ignoring 'all' and '*') next unless length($_) and /^(\d+)?(.*)/; - push @fg, [ $1, $2 ] unless $2 eq '*' or $2 eq 'all'; + my ($f, $g) = ($1, $2); + $f = 7 if $g =~ s/^ID-//i; + push @fg, [ $f, $g ] unless $g eq '*' or $g eq 'all'; } } # allow ValueConv to be specified by a '#' on the tag name @@ -1396,10 +1492,12 @@ ($$;@) } foreach (@{$$set[0]}) { my ($f, $g) = @$_; - if (defined $f) { - next SET unless defined $grp[$f] and $g eq $grp[$f]; - } else { + if (not defined $f) { next SET unless $grp{$g}; + } elsif ($f == 7) { + next SET unless IsSameID($srcExifTool->GetTagID($tag), $g); + } else { + next SET unless defined $grp[$f] and $g eq $grp[$f]; } } } @@ -1492,9 +1590,8 @@ ($$;@) #------------------------------------------------------------------------------ # Get new value(s) for tag -# Inputs: 0) ExifTool object reference, 1) tag name or tagInfo hash ref +# Inputs: 0) ExifTool object reference, 1) tag name (or tagInfo or nvHash ref, not public) # 2) optional pointer to return new value hash reference (not part of public API) -# or 0) ExifTool ref, 1) new value hash reference (not part of public API) # Returns: List of new Raw values (list may be empty if tag is being deleted) # Notes: 1) Preferentially returns new value from Extra table if writable Extra tag exists # 2) Must call AFTER IsOverwriting() returns 1 to get proper value for shifted times @@ -1520,21 +1617,25 @@ ($$;$) $nvHash = $self->GetNewValueHash($tagInfo); } else { # separate group from tag name - $group = $1 if $tag =~ s/(.*)://; + my @groups; + @groups = split ':', $1 if $tag =~ s/(.*)://; my @tagInfoList = FindTagInfo($tag); # decide which tag we want GNV_TagInfo: foreach $tagInfo (@tagInfoList) { my $nvh = $self->GetNewValueHash($tagInfo) or next; - # select tag in specified group if necessary - while ($group and $group ne $$nvh{WriteGroup}) { + # select tag in specified group(s) if necessary + foreach (@groups) { + next if $_ eq $$nvh{WriteGroup}; my @grps = $self->GetGroup($tagInfo); if ($grps[0] eq $$nvh{WriteGroup}) { # check family 1 group only if WriteGroup is not specific - last if $group eq $grps[1]; + next if $_ eq $grps[1]; } else { # otherwise check family 0 group - last if $group eq $grps[0]; + next if $_ eq $grps[0]; } + # also check family 7 + next if /^ID-(.*)/i and IsSameID($$tagInfo{TagID}, $1); # step to next entry in list $nvh = $$nvh{Next} or next GNV_TagInfo; } @@ -1662,6 +1763,8 @@ ($) # Notes: Restores saved new values, but currently doesn't restore them in the # original order, so there may be some minor side-effects when restoring tags # with overlapping groups. eg) XMP:Identifier, XMP-dc:Identifier +# Also, this doesn't do the right thing for list-type tags which accumulate +# values across a save point sub RestoreNewValues($) { my $self = shift; @@ -1761,7 +1864,7 @@ ($$;$$$) # Change file name and/or directory from FileName and Directory tags # Inputs: 0) ExifTool object reference, 1) current file name (including path) # 2) new name (or undef to build from FileName and Directory tags) -# 3) option: 'Link' to create link instead of renaming file +# 3) option: 'HardLink'/'SymLink' to create hard/symbolic link instead of renaming # 'Test' to only print new file name # 4) 0 to indicate that a file will no longer exist (used for 'Test' only) # Returns: 1=name changed OK, 0=nothing changed, -1=error changing name @@ -1776,8 +1879,10 @@ ($$;$$$) # determine the new file name unless (defined $newName) { if ($opt) { - if ($opt eq 'Link') { + if ($opt eq 'HardLink' or $opt eq 'Link') { $newName = $self->GetNewValue('HardLink'); + } elsif ($opt eq 'SymLink') { + $newName = $self->GetNewValue('SymLink'); } elsif ($opt eq 'Test') { $newName = $self->GetNewValue('TestName'); } @@ -1827,9 +1932,12 @@ ($$;$$$) length $newName or $self->Warn('New file name is empty'), return -1; # don't replace existing file if ($self->Exists($newName) and (not defined $usedFlag or $usedFlag)) { - if ($file ne $newName or $opt eq 'Link') { - $self->Warn("File '${newName}' already exists"); - return -1; + if ($file ne $newName or $opt =~ /Link$/) { + # allow for case-insensitive filesystem + if ($opt =~ /Link$/ or not $self->IsSameFile($file, $newName)) { + $self->Warn("File '${newName}' already exists"); + return -1; + } } else { $self->Warn('File name is unchanged'); return 0; @@ -1847,28 +1955,52 @@ ($$;$$$) $self->Warn("Error creating directory for '${newName}'"); return -1; } - $self->VPrint(0, "Created directory for '${newName}'"); + $self->VPrint(0, "Created directory for '${newName}'\n"); } - if ($opt eq 'Link') { + if ($opt eq 'HardLink' or $opt eq 'Link') { unless (link $file, $newName) { - $self->Warn("Error creating link '${newName}'"); + $self->Warn("Error creating hard link '${newName}'"); return -1; } ++$$self{CHANGED}; $self->VerboseValue('+ HardLink', $newName); return 1; + } elsif ($opt eq 'SymLink') { + $^O eq 'MSWin32' and $self->Warn('SymLink not supported in Windows'), return -1; + $newName =~ s(^\./)(); # remove leading "./" from link name if it exists + # path to linked file must be relative to the $newName directory, but $file + # is relative to the current directory, so convert it to an absolute path + # if using a relative directory and $newName isn't in the current directory + if ($file !~ m(^/) and $newName =~ m(/)) { + unless (eval { require Cwd }) { + $self->Warn('Install Cwd to make symlinks to other directories'); + return -1; + } + $file = eval { Cwd::abs_path($file) }; + unless (defined $file) { + $self->Warn('Error in Cwd::abs_path when creating symlink'); + return -1; + } + } + unless (eval { symlink $file, $newName } ) { + $self->Warn("Error creating symbolic link '${newName}'"); + return -1; + } + ++$$self{CHANGED}; + $self->VerboseValue('+ SymLink', $newName); + return 1; } # attempt to rename the file unless ($self->Rename($file, $newName)) { local (*EXIFTOOL_SFN_IN, *EXIFTOOL_SFN_OUT); # renaming didn't work, so copy the file instead unless ($self->Open(\*EXIFTOOL_SFN_IN, $file)) { - $self->Warn("Error opening '${file}'"); + $self->Error("Error opening '${file}'"); return -1; } unless ($self->Open(\*EXIFTOOL_SFN_OUT, $newName, '>')) { close EXIFTOOL_SFN_IN; - $self->Warn("Error creating '${newName}'"); + $self->Error("Error creating '${newName}'"); return -1; } binmode EXIFTOOL_SFN_IN; @@ -1881,7 +2013,7 @@ ($$;$$$) close EXIFTOOL_SFN_IN; if ($err) { $self->Unlink($newName); # erase bad output file - $self->Warn("Error writing '${newName}'"); + $self->Error("Error writing '${newName}'"); return -1; } # preserve modification time @@ -1898,7 +2030,7 @@ ($$;$$$) #------------------------------------------------------------------------------ # Set file permissions, group/user id and various MDItem tags from new tag values -# Inputs: 0) Exiftool ref, 1) file name or glob (must be a name for MDItem tags) +# Inputs: 0) ExifTool ref, 1) file name or glob (must be a name for MDItem tags) # Returns: 1=something was set OK, 0=didn't try, -1=error (and warning set) # Notes: There may be errors even if 1 is returned sub SetSystemTags($$) @@ -1946,6 +2078,46 @@ ($$) last; } } + # delete Windows Zone.Identifier if specified + my $zhash = $self->GetNewValueHash($Image::ExifTool::Extra{ZoneIdentifier}); + if ($zhash) { + my $res = -1; + if ($^O ne 'MSWin32') { + $self->Warn('ZoneIdentifer is a Windows-only tag'); + } elsif (ref $file) { + $self->Warn('Writing ZoneIdentifer requires a file name'); + } elsif (defined $self->GetNewValue('ZoneIdentifier', \$zhash)) { + $self->Warn('ZoneIndentifier may only be delted'); + } elsif (not eval { require Win32API::File }) { + $self->Warn('Install Win32API::File to write ZoneIdentifier'); + } else { + my ($wattr, $wide); + my $zfile = "${file}:Zone.Identifier"; + if ($self->EncodeFileName($zfile)) { + $wide = 1; + $wattr = eval { Win32API::File::GetFileAttributesW($zfile) }; + } else { + $wattr = eval { Win32API::File::GetFileAttributes($zfile) }; + } + if ($wattr == Win32API::File::INVALID_FILE_ATTRIBUTES()) { + $res = 0; # file doesn't exist, nothing to do + } elsif ($wattr & Win32API::File::FILE_ATTRIBUTE_READONLY()) { + $self->Warn('Zone.Identifier stream is read-only'); + } else { + if ($wide) { + $res = 1 if eval { Win32API::File::DeleteFileW($zfile) }; + } else { + $res = 1 if eval { Win32API::File::DeleteFile($zfile) }; + } + if ($res > 0) { + $self->VPrint(0, " Deleting Zone.Identifier stream\n"); + } else { + $self->Warn('Error deleting Zone.Identifier stream'); + } + } + } + $result = $res if $res == 1 or not $result; + } return $result; } @@ -1961,13 +2133,15 @@ ($$;$$) { local ($_, *EXIFTOOL_FILE2, *EXIFTOOL_OUTFILE); my ($self, $infile, $outfile, $outType) = @_; - my (@fileTypeList, $fileType, $tiffType, $hdr, $seekErr, $type, $tmpfile, $hardLink, $testName); + my (@fileTypeList, $fileType, $tiffType, $hdr, $seekErr, $type, $tmpfile); my ($inRef, $outRef, $closeIn, $closeOut, $outPos, $outBuff, $eraseIn, $raf, $fileExt); + my ($hardLink, $symLink, $testName); my $oldRaf = $$self{RAF}; my $rtnVal = 0; # initialize member variables $self->Init(); + $$self{IsWriting} = 1; # first, save original file modify date if necessary # (do this now in case we are modifying file in place and shifting date) @@ -1993,8 +2167,10 @@ ($$;$$) my ($numNew, $numPseudo) = $self->CountNewValues(); if (not defined $outfile and defined $infile) { $hardLink = $self->GetNewValue('HardLink'); + $symLink = $self->GetNewValue('SymLink'); $testName = $self->GetNewValue('TestName'); undef $hardLink if defined $hardLink and not length $hardLink; + undef $symLink if defined $symLink and not length $symLink; undef $testName if defined $testName and not length $testName; my $newFileName = $self->GetNewValue('FileName', \$nvHash); my $newDir = $self->GetNewValue('Directory'); @@ -2005,19 +2181,24 @@ ($$;$$) } if ($numNew == $numPseudo) { $rtnVal = 2; + if ((defined $newFileName or defined $newDir) and not ref $infile) { + my $result = $self->SetFileName($infile); + if ($result > 0) { + $infile = $$self{NewName}; # file name changed + $rtnVal = 1; + } elsif ($result < 0) { + return 0; # don't try to do anything else + } + } if (not ref $infile or UNIVERSAL::isa($infile,'GLOB')) { $self->SetFileModifyDate($infile) > 0 and $rtnVal = 1 if $setModDate; $self->SetFileModifyDate($infile, undef, 'FileCreateDate') > 0 and $rtnVal = 1 if $setCreateDate; $self->SetSystemTags($infile) > 0 and $rtnVal = 1; } - if ((defined $newFileName or defined $newDir) and not ref $infile) { - $self->SetFileName($infile) > 0 and $rtnVal = 1; - } - if (defined $hardLink or defined $testName) { - my $src = $$self{NewName}; - $src = $infile unless defined $src; - $hardLink and $self->SetFileName($src, $hardLink, 'Link') and $rtnVal = 1; - $testName and $self->SetFileName($src, $testName, 'Test') and $rtnVal = 1; + if (defined $hardLink or defined $symLink or defined $testName) { + $hardLink and $self->SetFileName($infile, $hardLink, 'HardLink') and $rtnVal = 1; + $symLink and $self->SetFileName($infile, $symLink, 'SymLink') and $rtnVal = 1; + $testName and $self->SetFileName($infile, $testName, 'Test') and $rtnVal = 1; } return $rtnVal; } elsif (defined $newFileName and length $newFileName) { @@ -2191,6 +2372,10 @@ ($$;$$) $fileType = $tiffType; undef $rtnVal; } else { + if ($tiffType eq 'FFF') { + # (see https://exiftool.org/forum/index.php?topic=10848.0) + $self->Error('Phocus may not properly update previews of edited FFF images', 1); + } $dirInfo{Parent} = $tiffType; $rtnVal = $self->ProcessTIFF(\%dirInfo); } @@ -2382,7 +2567,8 @@ ($$;$$) # set FileCreateDate if requested (and if possible!) ++$$self{CHANGED} if $setCreateDate and $self->SetFileModifyDate($target, $createTime, 'FileCreateDate', 1) > 0; # create hard link if requested and no output filename specified (and if possible!) - ++$$self{CHANGED} if defined $hardLink and $self->SetFileName($target, $hardLink, 'Link'); + ++$$self{CHANGED} if defined $hardLink and $self->SetFileName($target, $hardLink, 'HardLink'); + ++$$self{CHANGED} if defined $symLink and $self->SetFileName($target, $symLink, 'SymLink'); defined $testName and $self->SetFileName($target, $testName, 'Test'); } } @@ -2501,15 +2687,19 @@ (;$) #------------------------------------------------------------------------------ # Get list of all group names -# Inputs: 0) Group family number +# Inputs: 0) [optional] ExifTool ref, 1) Group family number # Returns: List of group names (sorted alphabetically) -sub GetAllGroups($) +sub GetAllGroups($;$) { local $_; my $family = shift || 0; + my $self; + ref $family and $self = $family, $family = shift || 0; $family == 3 and return('Doc#', 'Main'); $family == 4 and return('Copy#'); + $family == 5 and return('[too many possibilities to list]'); + $family == 6 and return(@Image::ExifTool::Exif::formatName[1..$#Image::ExifTool::Exif::formatName]); LoadAllTables(); # first load all our tables @@ -2523,9 +2713,23 @@ ($) $allGroups{$grp} = 1 if ($grps = $$table{GROUPS}) and ($grp = $$grps{$family}); foreach $tag (TagTableKeys($table)) { my @infoArray = GetTagInfoList($table, $tag); - foreach $tagInfo (@infoArray) { - next unless ($grps = $$tagInfo{Groups}) and ($grp = $$grps{$family}); - $allGroups{$grp} = 1; + if ($family == 7) { + foreach $tagInfo (@infoArray) { + my $id = $$tagInfo{TagID}; + if (not defined $id) { + $id = ''; # (just to be safe) + } elsif ($id =~ /^\d+$/) { + $id = sprintf('0x%x', $id) if $self and $$self{OPTIONS}{HexTagIDs}; + } else { + $id =~ s/([^-_A-Za-z0-9])/sprintf('%.2x',ord $1)/ge; + } + $allGroups{'ID-' . $id} = 1; + } + } else { + foreach $tagInfo (@infoArray) { + next unless ($grps = $$tagInfo{Groups}) and ($grp = $$grps{$family}); + $allGroups{$grp} = 1; + } } } } @@ -2607,7 +2811,7 @@ ($$) if ($$self{OPTIONS}{Escape} eq 'XML') { $$valPt = Image::ExifTool::XMP::UnescapeXML($$valPt); } elsif ($$self{OPTIONS}{Escape} eq 'HTML') { - $$valPt = Image::ExifTool::HTML::UnescapeHTML($$valPt); + $$valPt = Image::ExifTool::HTML::UnescapeHTML($$valPt, $$self{OPTIONS}{Charset}); } } } @@ -2626,6 +2830,8 @@ ($$$$$;$$) my ($self, $val, $tagInfo, $tag, $wgrp1, $convType, $wantGroup) = @_; my ($err, $type); + $convType or $convType = $$self{ConvType} || 'PrintConv'; + Conv: for (;;) { if (not defined $type) { # split value into list if necessary @@ -2635,11 +2841,11 @@ ($$$$$;$$) ($wantGroup or not defined $wantGroup)) { $listSplit = ',?\s+' if $listSplit eq '1' and $$tagInfo{AutoSplit}; - my @splitVal = split /$listSplit/, $val; - $val = \@splitVal if @splitVal > 1; + my @splitVal = split /$listSplit/, $val, -1; + $val = @splitVal > 1 ? \@splitVal : @splitVal ? $splitVal[0] : ''; } } - $type = $convType || $$self{ConvType} || 'PrintConv'; + $type = $convType; } elsif ($type eq 'PrintConv') { $type = 'ValueConv'; } else { @@ -2662,11 +2868,11 @@ ($$$$$;$$) if (ref $val eq 'ARRAY') { # loop through array values foreach $v (@$val) { - $err2 = &$checkProc($self, $tagInfo, \$v); + $err2 = &$checkProc($self, $tagInfo, \$v, $convType); last if $err2; } } else { - $err2 = &$checkProc($self, $tagInfo, \$val); + $err2 = &$checkProc($self, $tagInfo, \$val, $convType); } } } @@ -2733,7 +2939,7 @@ ($$$$$;$$) last Conv; } } elsif ($conv) { - if (ref $conv eq 'HASH') { + if (ref $conv eq 'HASH' and (not exists $$tagInfo{"${type}Inv"} or $convInvList)) { my ($multi, $lc); # insert alternate language print conversions if required if ($$self{CUR_LANG} and $type eq 'PrintConv' and @@ -2810,14 +3016,16 @@ ($$$$$;$$) } #------------------------------------------------------------------------------ -# convert tag names to values in a string (eg. '${EXIF:ISO}x $$' --> '100x $') +# Convert tag names to values or variables in a string +# (eg. '${EXIF:ISO}x $$' --> '100x $' without hash ref, or "$info{'EXIF:ISO'}x $" with) # Inputs: 0) ExifTool object ref, 1) reference to list of found tags # 2) string with embedded tag names, 3) Options: # undef - set missing tags to '' # 'Error' - issue minor error on missing tag (and return undef) # 'Warn' - issue minor warning on missing tag (and return undef) # 'Silent' - just return undef on missing tag (no errors/warnings) -# Hash ref - hash for return of tag/value pairs +# Hash ref - defined to interpolate as variables in string instead of values +# --> receives tag/value pairs for interpolation of the variables # 4) document group name if extracting from a specific document # 5) hash ref to cache tag keys for subsequent calls in document loop # Returns: string with embedded tag values (or '$info{TAGNAME}' entries with Hash ref option) @@ -2833,7 +3041,7 @@ ($$$;$$$) local $_; my ($self, $foundTags, $line, $opt, $docGrp, $cache) = @_; my $rtnStr = ''; - my $docNum; + my ($docNum, $tag); if ($docGrp) { $docNum = $docGrp =~ /(\d+)$/ ? $1 : 0; } else { @@ -2844,9 +3052,13 @@ ($$$;$$$) my (@tags, $val, $tg, @val, $type, $expr, $didExpr, $level, $asList); # "$$" represents a "$" symbol, and "$/" is a newline if ($var eq '$' or $var eq '/') { - $var = "\n" if $var eq '/'; - $rtnStr .= "$pre$var"; $line =~ s/^\s*\}// if $bra; + if ($var eq '/') { + $var = "\n"; + } elsif ($line =~ /^self\b/ and not $rtnStr =~ /\$$/) { + $var = '$$'; # ("$$self{var}" in string) + } + $rtnStr .= "$pre$var"; next; } # allow multiple group names @@ -2857,7 +3069,7 @@ ($$$;$$$) } # allow trailing '#' to indicate ValueConv value $type = 'ValueConv' if $line =~ s/^#//; - # (undocumented feature to allow '@' to evaluate list values separately, but only in braces) + # special advanced formatting '@' feature to evaluate list values separately if ($bra and $line =~ s/^\@(#)?//) { $asList = 1; $type = 'ValueConv' if $1; @@ -2886,8 +3098,9 @@ ($$$;$$$) for (;;) { # temporarily reset ListJoin option if evaluating list values separately - my $oldListJoin = $self->Options(ListJoin => undef) if $asList; - my $tag = shift @tags; + my $oldListJoin; + $oldListJoin = $self->Options(ListJoin => undef) if $asList; + $tag = shift @tags; my $lcTag = lc $tag; if ($cache and $lcTag !~ /(^|:)all$/) { # remove group from tag name (but not lower-case version) @@ -2914,7 +3127,10 @@ ($$$;$$$) } } my $doc = $lcTag =~ /\b(main|doc(\d+)):/ ? ($2 || 0) : $docNum; - $val = $self->GetValue($$cacheTag[$doc], $type) if $$cacheTag[$doc]; + if ($$cacheTag[$doc]) { + $tag = $$cacheTag[$doc]; + $val = $self->GetValue($tag, $type); + } } else { # add document number to tag if specified and it doesn't already exist if ($docGrp and $lcTag !~ /\b(main|doc\d+):/) { @@ -2947,6 +3163,8 @@ ($$$;$$$) last unless $tag =~ / /; # all done if we got our best match } } + } elsif ($tag eq 'self') { + $val = $self; # ("$self{var}" or "$self->{var}" in string) } else { # get the tag value $val = $self->GetValue($tag, $type); @@ -3098,13 +3316,52 @@ ($) return 1 if $$tagInfo{Table}{WRITABLE}; # must call WRITE_PROC to autoload writer because this may set the writable tag my $writeProc = $$tagInfo{Table}{WRITE_PROC}; - next unless $writeProc; - &$writeProc(); # dummy call to autoload writer - return 1 if $$tagInfo{Writable}; + if ($writeProc) { + no strict 'refs'; + &$writeProc(); # dummy call to autoload writer + return 1 if $$tagInfo{Writable}; + } } return 0; } +#------------------------------------------------------------------------------ +# Check to see if these are the same file +# Inputs: 0) ExifTool ref, 1) first file name, 2) second file name +# Returns: true if file names reference the same file +sub IsSameFile($$$) +{ + my ($self, $file, $file2) = @_; + return 0 unless lc $file eq lc $file2; # (only looking for differences in case) + my ($isSame, $interrupted); + my $tmp1 = "${file}_ExifTool_tmp_$$"; + my $tmp2 = "${file2}_ExifTool_tmp_$$"; + { + local *TMP1; + local $SIG{INT} = sub { $interrupted = 1 }; + if ($self->Open(\*TMP1, $tmp1, '>')) { + close TMP1; + $isSame = 1 if $self->Exists($tmp2); + $self->Unlink($tmp1); + } + } + if ($interrupted and $SIG{INT}) { + no strict 'refs'; + &{$SIG{INT}}(); + } + return $isSame; +} + +#------------------------------------------------------------------------------ +# Is this a raw file type? +# Inputs: 0) ExifTool ref +# Returns: true if FileType is a type of RAW image +sub IsRawType($) +{ + my $self = shift; + return $rawType{$$self{FileType}}; +} + #------------------------------------------------------------------------------ # Create directory for specified file # Inputs: 0) ExifTool ref, 1) complete file name including path @@ -3220,6 +3477,8 @@ ($$) if ($val =~ /^Unknown\s*\((.*)\)$/i) { $val = $1; # was unknown if ($val =~ /^0x([\da-fA-F]+)$/) { + # disable "Hexadecimal number > 0xffffffff non-portable" warning + local $SIG{'__WARN__'} = sub { }; $val = hex($val); # convert hex value } } else { @@ -3274,7 +3533,8 @@ ($$) # 2) optional tag value (before RawConv) if deleting specific values # Returns: >0 - tag should be overwritten # =0 - the tag should be preserved -# <0 - not sure, we need the value to know +# <0 - not sure, we need the old value to tell (if there is no old value +# then the tag should be written if $$nvHash{IsCreating} is true) # Notes: $$nvHash{Value} is updated with the new value when shifting a value sub IsOverwriting($$;$) { @@ -3372,7 +3632,7 @@ ($) sub GetWriteGroup1($$) { my ($self, $tagInfo, $writeGroup) = @_; - return $writeGroup unless $writeGroup =~ /^(MakerNotes|XMP|Composite)$/; + return $writeGroup unless $writeGroup =~ /^(MakerNotes|XMP|Composite|QuickTime)$/; return $self->GetGroup($tagInfo, 1); } @@ -3387,6 +3647,7 @@ ($$) sub GetNewValueHash($$;$$$$) { my ($self, $tagInfo, $writeGroup, $opts) = @_; + return undef unless $tagInfo; my $nvHash = $$self{NEW_VALUE}{$tagInfo}; my %opts; # quick lookup for options @@ -3395,10 +3656,11 @@ ($$;$$$$) if ($writeGroup) { # find the new value in the list with the specified write group - # (QuickTime and All are special cases because all group1 tags may be updated at once) - while ($nvHash and $$nvHash{WriteGroup} ne $writeGroup and - $$nvHash{WriteGroup} !~ /^(QuickTime|All)$/) - { + while ($nvHash and $$nvHash{WriteGroup} ne $writeGroup) { + # QuickTime and All are special cases because all group1 tags may be updated at once + last if $$nvHash{WriteGroup} =~ /^(QuickTime|All)$/; + # replace existing entry if WriteGroup is 'All' (avoids confusion of forum10349) + last if $$tagInfo{WriteGroup} and $$tagInfo{WriteGroup} eq 'All'; $nvHash = $$nvHash{Next}; } } @@ -3475,7 +3737,10 @@ () $table = GetTagTable(shift @tableNames); # call write proc if it exists in case it adds tags to the table my $writeProc = $$table{WRITE_PROC}; - $writeProc and &$writeProc(); + if ($writeProc) { + no strict 'refs'; + &$writeProc(); + } # recursively scan through tables in subdirectories foreach (TagTableKeys($table)) { my @infoArray = GetTagInfoList($table,$_); @@ -3672,14 +3937,14 @@ ($$) # initialize ADD_DIRS and EDIT_DIRS hashes for all directories that need # to be created or will have tags changed in them # Inputs: 0) ExifTool object reference, 1) file type string (or map hash ref) -# 2) preferred family 0 group name for creating tags +# 2) preferred family 0 group for creating tags, 3) alternate preferred group # Notes: # - the ADD_DIRS and EDIT_DIRS keys are the directory names, and the values # are the names of the parent directories (undefined for a top-level directory) # - also initializes FORCE_WRITE lookup -sub InitWriteDirs($$;$) +sub InitWriteDirs($$;$$) { - my ($self, $fileType, $preferredGroup) = @_; + my ($self, $fileType, $preferredGroup, $altGroup) = @_; my $editDirs = $$self{EDIT_DIRS} = { }; my $addDirs = $$self{ADD_DIRS} = { }; my $fileDirs = $dirMap{$fileType}; @@ -3698,18 +3963,21 @@ ($$;$) for ($nvHash=$self->GetNewValueHash($tagInfo); $nvHash; $nvHash=$$nvHash{Next}) { # are we creating this tag? (otherwise just deleting or editing it) my $isCreating = $$nvHash{IsCreating}; - if ($isCreating) { - # if another group is taking priority, only create - # directory if specifically adding tags to this group - # or if this tag isn't being added to the priority group - $isCreating = 0 if $preferredGroup and - $preferredGroup ne $self->GetGroup($tagInfo, 0) and - $$nvHash{CreateGroups}{$preferredGroup}; - } else { - # creating this directory if any tag is preferred and has a value - $isCreating = 1 if ($preferredGroup and $$nvHash{Value} and - $preferredGroup eq $self->GetGroup($tagInfo, 0)) and - not $$nvHash{EditOnly}; + if ($preferredGroup) { + my $g0 = $self->GetGroup($tagInfo, 0); + if ($isCreating) { + # if another group is taking priority, only create + # directory if specifically adding tags to this group + # or if this tag isn't being added to the priority group + $isCreating = 0 if $preferredGroup ne $g0 and + $$nvHash{CreateGroups}{$preferredGroup} and + (not $altGroup or $altGroup ne $g0); + } else { + # create this directory if any tag is preferred and has a value + # (unless group creation is disabled via the WriteMode option) + $isCreating = 1 if $$nvHash{Value} and $preferredGroup eq $g0 and + not $$nvHash{EditOnly} and $$self{OPTIONS}{WriteMode} =~ /g/; + } } # tag belongs to directory specified by WriteGroup, or by # the Group0 name if WriteGroup not defined @@ -3719,11 +3987,11 @@ ($$;$) $dirName = 'MIE' . ($1 || ''); } my @dirNames; - # allow a group name of '*' to force writing EXIF/IPTC/XMP (ForceWrite tag) + # allow a group name of '*' to force writing EXIF/IPTC/XMP/PNG (ForceWrite tag) if ($dirName eq '*' and $$nvHash{Value}) { my $val = $$nvHash{Value}[0]; if ($val) { - foreach (qw(EXIF IPTC XMP FixBase)) { + foreach (qw(EXIF IPTC XMP PNG FixBase)) { next unless $val =~ /\b($_|All)\b/i; push @dirNames, $_; push @dirNames, 'EXIF' if $_ eq 'FixBase'; @@ -3731,6 +3999,9 @@ ($$;$) } } $dirName = shift @dirNames; + } elsif ($dirName eq 'QuickTime') { + # write to specific QuickTime group + $dirName = $self->GetGroup($tagInfo, 1); } while ($dirName) { my $parent = $$fileDirs{$dirName}; @@ -3791,7 +4062,7 @@ ($$;$) sub WriteDirectory($$$;$) { my ($self, $dirInfo, $tagTablePtr, $writeProc) = @_; - my ($out, $nvHash); + my ($out, $nvHash, $delFlag); $tagTablePtr or return undef; $out = $$self{OPTIONS}{TextOut} if $$self{OPTIONS}{Verbose}; @@ -3804,9 +4075,18 @@ ($$$;$) my $delGroup = $$self{DEL_GROUP}; # delete entire directory if specified my $grp1 = $dirName; - my $delFlag = ($$delGroup{$grp0} or $$delGroup{$grp1}); + $delFlag = ($$delGroup{$grp0} or $$delGroup{$grp1}) unless $permanentDir{$grp0}; + # (never delete an entire QuickTime group) if ($delFlag) { - unless ($blockExifTypes{$$self{FILE_TYPE}}) { + if (($grp0 =~ /^(MakerNotes)$/ or $grp1 =~ /^(IFD0|ExifIFD|MakerNotes)$/) and + $self->IsRawType() and + # allow non-permanent MakerNote directories to be deleted (ie. NikonCapture) + (not $$dirInfo{TagInfo} or not defined $$dirInfo{TagInfo}{Permanent} or + $$dirInfo{TagInfo}{Permanent})) + { + $self->WarnOnce("Can't delete $1 from $$self{FileType}",1); + undef $grp1; + } elsif (not $blockExifTypes{$$self{FILE_TYPE}}) { # restrict delete logic to prevent entire tiff image from being killed # (don't allow IFD0 to be deleted, and delete only ExifIFD if EXIF specified) if ($$self{FILE_TYPE} eq 'PSD') { @@ -3826,6 +4106,7 @@ ($$$;$) if ($dataPt or $$dirInfo{RAF}) { ++$$self{CHANGED}; $out and print $out " Deleting $grp1\n"; + $self->Warn('ICC_Profile deleted. Image colors may be affected') if $grp1 eq 'ICC_Profile'; # can no longer validate TIFF_END if deleting an entire IFD delete $$self{TIFF_END} if $dirName =~ /IFD/; } @@ -3886,7 +4167,7 @@ ($$$;$) $self->Warn("Can't write EXIF as a block to $$self{FILE_TYPE} file"); last; } - # this can happen if we call WriteDirectory for an EXIF directory without going + # this can happen if we call WriteDirectory for an EXIF directory without going # through WriteTIFF as the WriteProc (which happens if conditionally replacing # the EXIF block and the condition fails), but we never want to do a block write # in this case because the EXIF block would end up with two TIFF headers @@ -3897,6 +4178,11 @@ ($$$;$) my $newVal = $self->GetNewValue($nvHash); unless (defined $newVal and length $newVal) { return '' unless $dataPt or $$dirInfo{RAF}; # nothing to do if block never existed + # don't allow MakerNotes to be removed from RAW files + if ($blockName eq 'MakerNotes' and $rawType{$$self{FileType}}) { + $self->Warn("Can't delete MakerNotes from $$self{VALUE}{FileType}",1); + return undef; + } $verb = 'Deleting'; $newVal = ''; } @@ -3906,7 +4192,9 @@ ($$$;$) return $newVal; } # guard against writing the same directory twice - if (defined $dataPt and defined $$dirInfo{DirStart} and defined $$dirInfo{DataPos}) { + if (defined $dataPt and defined $$dirInfo{DirStart} and defined $$dirInfo{DataPos} and + not $$dirInfo{NoRefTest}) + { my $addr = $$dirInfo{DirStart} + $$dirInfo{DataPos} + ($$dirInfo{Base}||0) + $$self{BASE}; # (Phase One P25 IIQ files have ICC_Profile duplicated in IFD0 and IFD1) if ($$self{PROCESSED}{$addr} and ($dirName ne 'ICC_Profile' or $$self{TIFF_TYPE} ne 'IIQ')) { @@ -3943,14 +4231,21 @@ ($$$;$) $$self{DIR_NAME} = $dirName; push @{$$self{PATH}}, $dirName; $$dirInfo{IsWriting} = 1; - my $newData = &$writeProc($self, $dirInfo, $tagTablePtr); + my $newData; + { + no strict 'refs'; + $newData = &$writeProc($self, $dirInfo, $tagTablePtr); + } pop @{$$self{PATH}}; # nothing changed if error occurred or nothing was created $$self{CHANGED} = $oldChanged unless defined $newData and (length($newData) or $isRewriting); $$self{DIR_NAME} = $oldDir; @$self{'Compression','SubfileType'} = @save; SetByteOrder($saveOrder); - print $out " Deleting $name\n" if $out and defined $newData and not length $newData; + if ($out) { + print $out " Deleting $name\n" if defined $newData and not length $newData; + print $out "$$self{INDENT} [nothing changed in $dirName]\n" if $$self{CHANGED} == $oldChanged; + } return $newData; } @@ -4239,7 +4534,7 @@ ($$) # add to Preview block list if valid and in the trailer $image{$prePos} = [$tag, $preLen] if $prePos and $preLen and $prePos+$preLen > $pos; last if $lastOne; # checked all images - # look for MPF images (in the the proper order) + # look for MPF images (in the proper order) ++$mpImageNum; $prePos = $$self{VALUE}{"MPImageStart ($mpImageNum)"}; if (defined $prePos) { @@ -4486,17 +4781,17 @@ ($$;$$) { my ($self, $val, $tzFlag, $dateOnly) = @_; my ($rtnVal, $tz); + my $fmt = $$self{OPTIONS}{DateFormat}; # strip off timezone first if it exists - if ($val =~ s/([+-])(\d{1,2}):?(\d{2})\s*$//i) { + if (not $fmt and $val =~ s/([-+])(\d{1,2}):?(\d{2})\s*(DST)?$//i) { $tz = sprintf("$1%.2d:$3", $2); - } elsif ($val =~ s/Z$//i) { + } elsif (not $fmt and $val =~ s/Z$//i) { $tz = 'Z'; } else { $tz = ''; # allow special value of 'now' return $self->TimeNow($tzFlag) if lc($val) eq 'now'; } - my $fmt = $$self{OPTIONS}{DateFormat}; # only convert date if a format was specified and the date is recognizable if ($fmt) { unless (defined $strptimeLib) { @@ -4511,6 +4806,8 @@ ($$;$$) $strptimeLib = ''; } } + # handle factional seconds (%f), but only at the end of the string + my $fs = ($fmt =~ s/%f$// and $val =~ s/(\.\d+)\s*$//) ? $1 : ''; my ($lib, $wrn, @a); TryLib: for ($lib=$strptimeLib; ; $lib='') { if (not $lib) { @@ -4520,6 +4817,11 @@ ($$;$$) } elsif ($lib eq 'POSIX::strptime') { @a = eval { POSIX::strptime($val, $fmt) }; } else { + # protect against a negative epoch time, it can cause a hard crash in Windows + if ($^O eq 'MSWin32' and $fmt =~ /%s/ and $val =~ /-\d/) { + warn "Can't convert negative epoch time\n"; + return undef; + } @a = eval { my $t = Time::Piece->strptime($val, $fmt); return ($t->sec, $t->min, $t->hour, $t->mday, $t->_mon, $t->_year); @@ -4542,10 +4844,10 @@ ($$;$$) next TryLib; } } elsif (length($a[$i]) < 2) { - $$a[$i] = "0$a[$i]";# pad to 2 digits if necessary + $a[$i] = "0$a[$i]"; # pad to 2 digits if necessary } } - $val = join(':', @a[5,4,3]) . ' ' . join(':', @a[2,1,0]); + $val = join(':', @a[5,4,3]) . ' ' . join(':', @a[2,1,0]) . $fs; last; } } @@ -4563,7 +4865,7 @@ ($$;$$) if (not $tz) { if (eval { require Time::Local }) { # determine timezone offset for this time - my @args = ($a[4],$a[3],$a[2],$a[1],$a[0]-1,$yr-1900); + my @args = ($a[4],$a[3],$a[2],$a[1],$a[0]-1,$yr); my $diff = Time::Local::timegm(@args) - TimeLocal(@args); $tz = TimeZoneString($diff / 60); } else { @@ -4573,7 +4875,7 @@ ($$;$$) } elsif (defined $tzFlag) { $tz = $fs = ''; # remove timezone and sub-seconds } - if (defined $ss) { + if (defined $ss and $ss < 60) { $ss = ":$ss"; } elsif ($dateOnly) { $ss = ''; @@ -4581,6 +4883,16 @@ ($$;$$) $ss = ':00'; } # construct properly formatted date/time string + if ($a[0] < 1 or $a[0] > 12) { + warn "Month '$a[0]' out of range 1..12\n"; + return undef; + } + if ($a[1] < 1 or $a[1] > 31) { + warn "Day '$a[1]' out of range 1..31\n"; + return undef; + } + $a[2] > 24 and warn("Hour '$a[2]' out of range 0..24\n"), return undef; + $a[3] > 59 and warn("Minutes '$a[3]' out of range 0..59\n"), return undef; $rtnVal = "$yr:$a[0]:$a[1] $a[2]:$a[3]$ss$fs$tz"; } elsif ($dateOnly) { $rtnVal = join ':', $yr, @a; @@ -4592,19 +4904,20 @@ ($$;$$) #------------------------------------------------------------------------------ # Set byte order according to our current preferences -# Inputs: 0) ExifTool object ref +# Inputs: 0) ExifTool object ref, 1) default byte order # Returns: new byte order ('II' or 'MM') and sets current byte order # Notes: takes the first of the following that is valid: # 1) ByteOrder option # 2) new value for ExifByteOrder -# 3) makenote byte order from last file read -# 4) big endian -sub SetPreferredByteOrder($) +# 3) default byte order passed to this routine +# 4) makenote byte order from last file read +# 5) big endian +sub SetPreferredByteOrder($;$) { - my $self = shift; + my ($self, $default) = @_; my $byteOrder = $self->Options('ByteOrder') || $self->GetNewValue('ExifByteOrder') || - $$self{MAKER_NOTE_BYTE_ORDER} || 'MM'; + $default || $$self{MAKER_NOTE_BYTE_ORDER} || 'MM'; unless (SetByteOrder($byteOrder)) { warn "Invalid byte order '${byteOrder}'\n" if $self->Options('Verbose'); $byteOrder = $$self{MAKER_NOTE_BYTE_ORDER} || 'MM'; @@ -4684,7 +4997,7 @@ (@) } sub Set64u(@) { - my $val = shift; + my $val = $_[0]; my $hi = int($val / 4294967296); my $lo = Set32u($val - $hi * 4294967296); $hi = Set32u($hi); @@ -4692,6 +5005,12 @@ (@) $_[1] and substr(${$_[1]}, $_[2], length($val)) = $val; return $val; } +sub Set64s(@) +{ + my $val = shift; + $val < 0 and $val += 4294967296 * 4294967296; # (temporary hack won't really work due to round-off errors) + return Set64u($val, @_); +} sub SetRational64u(@) { my ($numer,$denom) = Rationalize($_[0],0xffffffff); my $val = Set32u($numer) . Set32u($denom); @@ -4753,6 +5072,7 @@ (@) int16uRev => \&Set16uRev, int32s => \&Set32s, int32u => \&Set32u, + int64s => \&Set64s, int64u => \&Set64u, rational32s => \&SetRational32s, rational32u => \&SetRational32u, @@ -5201,7 +5521,7 @@ ($$) } unless ($marker and $marker == 0xda) { $isEXV or $self->Error('Corrupted JPEG image'), return 1; - $marker and $marker ne 0xd9 and $self->Error('Corrupted EXV file'), return 1; + $marker and $marker != 0xd9 and $self->Error('Corrupted EXV file'), return 1; } $raf->Seek($pos, 0) or $self->Error('Seek error'), return 1; # @@ -5312,7 +5632,11 @@ ($$) my $buff = $self->WriteDirectory(\%dirInfo, $tagTablePtr, \&WriteTIFF); if (defined $buff and length $buff) { if (length($buff) + length($exifAPP1hdr) > $maxSegmentLen) { - $self->Warn('Creating multi-segment EXIF',1); + if ($self->Options('NoMultiExif')) { + $self->Error('EXIF is too large for JPEG segment'); + } else { + $self->Warn('Creating multi-segment EXIF',1); + } } # switch to buffered output if required if (($$self{PREVIEW_INFO} or $$self{LeicaTrailer}) and not $oldOutfile) { @@ -5466,7 +5790,8 @@ ($$) my ($buff, $endPos, $trailInfo); my $delPreview = $$self{DEL_PREVIEW}; $trailInfo = IdentifyTrailer($raf) unless $$delGroup{Trailer}; - unless ($oldOutfile or $delPreview or $trailInfo or $$delGroup{Trailer}) { + my $nvTrail = $self->GetNewValueHash($Image::ExifTool::Extra{Trailer}); + unless ($oldOutfile or $delPreview or $trailInfo or $$delGroup{Trailer} or $nvTrail) { # blindly copy the rest of the file while ($raf->Read($buff, 65536)) { Write($outfile, $buff) or $err = 1, last; @@ -5497,7 +5822,20 @@ ($$) } # remember position of last data copied $endPos = $raf->Tell() - length($buff); - # rewrite trailers if they exist + # write new trailer if specified + if ($nvTrail) { + # access new value directly to avoid copying a potentially very large data block + if ($$nvTrail{Value} and $$nvTrail{Value}[0]) { # (note: "0" will also delete the trailer) + $self->VPrint(0, ' Writing new trailer'); + Write($outfile, $$nvTrail{Value}[0]) or $err = 1; + ++$$self{CHANGED}; + } elsif ($raf->Seek(0, 2) and $raf->Tell() != $endPos) { + $self->VPrint(0, ' Deleting trailer (', $raf->Tell() - $endPos, ' bytes)'); + ++$$self{CHANGED}; # changed if there was previously a trailer + } + last; # all done + } + # rewrite existing trailers if ($trailInfo) { my $tbuf = ''; $raf->Seek(-length($buff), 1); # seek back to just after EOI @@ -5661,9 +5999,10 @@ ($$) HexDump($segDataPt, undef, %dumpParms); } } - # group delete of APP segements + # group delete of APP segments if ($$delGroup{$dirName}) { $verbose and print $out " Deleting $dirName segment\n"; + $self->Warn('ICC_Profile deleted. Image colors may be affected') if $dirName eq 'ICC_Profile'; ++$$self{CHANGED}; next Marker; } @@ -5770,7 +6109,11 @@ ($$) # delete segment if IFD contains no entries length $$segDataPt or $del = 1, last; if (length($$segDataPt) + length($exifAPP1hdr) > $maxSegmentLen) { - $self->Warn('Writing multi-segment EXIF',1); + if ($self->Options('NoMultiExif')) { + $self->Error('EXIF is too large for JPEG segment'); + } else { + $self->Warn('Writing multi-segment EXIF',1); + } } # switch to buffered output if required if (($$self{PREVIEW_INFO} or $$self{LeicaTrailer}) and not $oldOutfile) { @@ -6366,7 +6709,17 @@ ($$;$$$$) # open file by name if necessary unless (ref $file) { # (file will be automatically closed when *FH goes out of scope) - $self->Open(\*FH, $file, '+<') or $self->Warn('Error opening file for update'), return 0; + unless ($self->Open(\*FH, $file, '+<')) { + my $success; + if (defined $atime or defined $mtime) { + my ($a, $m, $c) = $self->GetFileTime($file); + $atime = $a unless defined $atime; + $mtime = $m unless defined $mtime; + $success = eval { utime($atime, $mtime, $file) } if defined $atime and defined $mtime; + } + $self->Warn('Error opening file for update') unless $success; + return $success; + } $saveFile = $file; $file = \*FH; } @@ -6454,7 +6807,7 @@ ($$$) } #------------------------------------------------------------------------------ -# copy image data from one file to another +# Copy image data from one file to another # Inputs: 0) ExifTool object reference # 1) reference to list of image data [ position, size, pad bytes ] # 2) output file ref @@ -6483,7 +6836,7 @@ ($$$) } #------------------------------------------------------------------------------ -# write to binary data block +# Write to binary data block # Inputs: 0) ExifTool object ref, 1) source dirInfo ref, 2) tag table ref # Returns: Binary data block or undefined on error sub WriteBinaryData($$$) @@ -6524,7 +6877,6 @@ ($$$) next unless $writeInfo and $writeInfo eq $tagInfo; } # add offsets for variable-sized tags if necessary - my $varFmt; while (@varInfo and $varInfo[0][0] < $tagID) { $varSize = $varInfo[0][1]; # get accumulated variable size shift @varInfo; @@ -6553,9 +6905,11 @@ ($$$) my $val = ReadValue($dataPt, $entry, $format, $count, $dirLen-$entry); next unless defined $val; my $nvHash = $self->GetNewValueHash($tagInfo, $$self{CUR_WRITE_GROUP}); - next unless $self->IsOverwriting($nvHash, $val); + next unless $self->IsOverwriting($nvHash, $val) > 0; my $newVal = $self->GetNewValue($nvHash); next unless defined $newVal; # can't delete from a binary table + # update DataMember with new value if necessary + $$self{$$tagInfo{DataMember}} = $newVal if $$tagInfo{DataMember}; # only write masked bits if specified my $mask = $$tagInfo{Mask}; $newVal = (($newVal << $$tagInfo{BitShift}) & $mask) | ($val & ~$mask) if $mask; @@ -6612,7 +6966,7 @@ ($$$) $$previewInfo{IsShort} = 1 unless $format eq 'int32u'; $$previewInfo{Absolute} = 1 if $$tagInfo{IsOffset} and $$tagInfo{IsOffset} eq '3'; # get the value of the Composite::PreviewImage tag - $$previewInfo{Data} = $self->GetNewValue($Image::ExifTool::Composite{PreviewImage}); + $$previewInfo{Data} = $self->GetNewValue(GetCompositeTagInfo('PreviewImage')); unless (defined $$previewInfo{Data}) { if ($offset >= 0 and $offset + $size <= $$dirInfo{DataLen}) { $$previewInfo{Data} = substr(${$$dirInfo{DataPt}},$offset,$size); @@ -6661,6 +7015,7 @@ ($$$) sub WriteTIFF($$$) { my ($self, $dirInfo, $tagTablePtr) = @_; + $self or return 1; # allow dummy access my $buff = ''; $$dirInfo{OutFile} = \$buff; return $buff if $self->ProcessTIFF($dirInfo, $tagTablePtr) > 0; @@ -6686,7 +7041,7 @@ =head1 DESCRIPTION =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/XMP.pm b/src/Image-ExifTool/lib/Image/ExifTool/XMP.pm index 7bf252b0..7d6af83c 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/XMP.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/XMP.pm @@ -25,7 +25,8 @@ # 10) http://www.adobe.com/devnet/xmp/pdfs/XMPSpecificationPart2.pdf (Oct 2008) # 11) http://www.extensis.com/en/support/kb_article.jsp?articleNumber=6102211 # 12) http://www.cipa.jp/std/documents/e/DC-010-2012_E.pdf -# 13) http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf +# 13) http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf (changed to +# http://www.cipa.jp/std/documents/e/DC-X010-2017.pdf) # # Notes: - Property qualifiers are handled as if they were separate # properties (with no associated namespace). @@ -49,25 +50,33 @@ use Image::ExifTool::Exif; use Image::ExifTool::GPS; require Exporter; -$VERSION = '3.17'; +$VERSION = '3.52'; @ISA = qw(Exporter); @EXPORT_OK = qw(EscapeXML UnescapeXML); sub ProcessXMP($$;$); sub WriteXMP($$;$); -sub CheckXMP($$$); +sub CheckXMP($$$;$); sub ParseXMPElement($$$;$$$$); sub DecodeBase64($); sub EncodeBase64($;$); sub SaveBlankInfo($$$;$); sub ProcessBlankInfo($$$;$); sub ValidateXMP($;$); -sub ValidateProperty($$); -sub UnescapeChar($$); +sub ValidateProperty($$;$); +sub UnescapeChar($$;$); sub AddFlattenedTags($;$$); sub FormatXMPDate($); sub ConvertRational($); sub ConvertRationalList($); +sub WriteGSpherical($$$); + +# standard path locations for XMP in major file types +my %stdPath = ( + JPEG => 'JPEG-APP1-XMP', + TIFF => 'TIFF-IFD0-XMP', + PSD => 'PSD-XMP', +); # lookup for translating to ExifTool namespaces (and family 1 group names) %stdXlatNS = ( @@ -100,6 +109,7 @@ my %xmpNS = ( aux => 'http://ns.adobe.com/exif/1.0/aux/', album => 'http://ns.adobe.com/album/1.0/', cc => 'http://creativecommons.org/ns#', # changed 2007/12/21 - PH + crd => 'http://ns.adobe.com/camera-raw-defaults/1.0/', crs => 'http://ns.adobe.com/camera-raw-settings/1.0/', crss => 'http://ns.adobe.com/camera-raw-saved-settings/1.0/', dc => 'http://purl.org/dc/elements/1.1/', @@ -145,7 +155,7 @@ my %xmpNS = ( DICOM => 'http://ns.adobe.com/DICOM/', 'drone-dji'=> 'http://www.dji.com/drone-dji/1.0/', svg => 'http://www.w3.org/2000/svg', - et => 'http://ns.exiftool.ca/1.0/', + et => 'http://ns.exiftool.org/1.0/', # # namespaces defined in XMP2.pl: # @@ -176,13 +186,19 @@ my %xmpNS = ( GSpherical=> 'http://ns.google.com/videos/1.0/spherical/', GDepth => 'http://ns.google.com/photos/1.0/depthmap/', GFocus => 'http://ns.google.com/photos/1.0/focus/', + GCamera => 'http://ns.google.com/photos/1.0/camera/', + GCreations=> 'http://ns.google.com/photos/1.0/creations/', dwc => 'http://rs.tdwg.org/dwc/index.htm', GettyImagesGIFT => 'http://xmp.gettyimages.com/gift/1.0/', LImage => 'http://ns.leiainc.com/photos/1.0/image/', + Profile => 'http://ns.google.com/photos/dd/1.0/profile/', + sdc => 'http://ns.nikon.com/sdc/1.0/', + ast => 'http://ns.nikon.com/asteroid/1.0/', + nine => 'http://ns.nikon.com/nine/1.0/', ); # build reverse namespace lookup -my %uri2ns; +my %uri2ns = ( 'http://ns.exiftool.ca/1.0/' => 'et' ); # (allow exiftool.ca as well as exiftool.org) { my $ns; foreach $ns (keys %nsURI) { @@ -195,13 +211,13 @@ my %uri2ns; ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)', ValueConvInv => 'Image::ExifTool::GPS::ToDMS($self, $val, 2, "N")', PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "N")', - PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1)', + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lat")', ); %longConv = ( ValueConv => 'Image::ExifTool::GPS::ToDegrees($val, 1)', ValueConvInv => 'Image::ExifTool::GPS::ToDMS($self, $val, 2, "E")', PrintConv => 'Image::ExifTool::GPS::ToDMS($self, $val, 1, "E")', - PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1)', + PrintConvInv => 'Image::ExifTool::GPS::ToDegrees($val, 1, "lon")', ); %dateTimeInfo = ( # NOTE: Do NOT put "Groups" here because Groups hash must not be common! @@ -423,9 +439,38 @@ my %sOECF = ( Names => { List => 'Seq' }, Values => { List => 'Seq', Writable => 'rational' }, ); - +my %sAreaModels = ( + STRUCT_NAME => 'AreaModels', + NAMESPACE => 'crs', + ColorRangeMaskAreaSampleInfo => { FlatName => 'ColorSampleInfo' }, + AreaComponents => { FlatName => 'Components', List => 'Seq' }, +); +my %sCorrRangeMask = ( + STRUCT_NAME => 'CorrRangeMask', + NAMESPACE => 'crs', + NOTES => 'Called CorrectionRangeMask by the spec.', + Version => { }, + Type => { }, + ColorAmount => { Writable => 'real' }, + LumMin => { Writable => 'real' }, + LumMax => { Writable => 'real' }, + LumFeather => { Writable => 'real' }, + DepthMin => { Writable => 'real' }, + DepthMax => { Writable => 'real' }, + DepthFeather=> { Writable => 'real' }, + # new in LR 11.0 + Invert => { Writable => 'boolean' }, + SampleType => { Writable => 'integer' }, + AreaModels => { + List => 'Seq', + Struct => \%sAreaModels, + }, + LumRange => { }, + LuminanceDepthSampleInfo => { }, +); # new LR2 crs structures (PH) -my %sCorrectionMask = ( +my %sCorrectionMask; +%sCorrectionMask = ( STRUCT_NAME => 'CorrectionMask', NAMESPACE => 'crs', # disable List behaviour of flattened Gradient/PaintBasedCorrections @@ -460,6 +505,26 @@ my %sCorrectionMask = ( Alpha => { Writable => 'real', List => 0 }, CenterValue => { Writable => 'real', List => 0 }, PerimeterValue=>{ Writable => 'real', List => 0 }, + # new in LR 11.0 MaskGroupBasedCorrections + MaskActive => { Writable => 'boolean', List => 0 }, + MaskName => { List => 0 }, + MaskBlendMode=> { Writable => 'integer', List => 0 }, + MaskInverted => { Writable => 'boolean', List => 0 }, + MaskSyncID => { List => 0 }, + MaskVersion => { List => 0 }, + MaskSubType => { List => 0 }, + ReferencePoint => { List => 0 }, + InputDigest => { List => 0 }, + MaskDigest => { List => 0 }, + WholeImageArea => { List => 0 }, + Origin => { List => 0 }, + Masks => { Struct => \%sCorrectionMask, NoSubStruct => 1 }, + CorrectionRangeMask => { + Name => 'CorrRangeMask', + Notes => 'called CorrectionRangeMask by the spec', + FlatName => 'Range', + Struct => \%sCorrRangeMask, + }, ); my %sCorrection = ( STRUCT_NAME => 'Correction', @@ -473,8 +538,8 @@ my %sCorrection = ( LocalClarity => { FlatName => 'Clarity', Writable => 'real', List => 0 }, LocalSharpness => { FlatName => 'Sharpness', Writable => 'real', List => 0 }, LocalBrightness => { FlatName => 'Brightness', Writable => 'real', List => 0 }, - LocalToningHue => { FlatName => 'Hue', Writable => 'real', List => 0 }, - LocalToningSaturation => { FlatName => 'Saturation', Writable => 'real', List => 0 }, + LocalToningHue => { FlatName => 'ToningHue', Writable => 'real', List => 0 }, + LocalToningSaturation => { FlatName => 'ToningSaturation', Writable => 'real', List => 0 }, LocalExposure2012 => { FlatName => 'Exposure2012', Writable => 'real', List => 0 }, LocalContrast2012 => { FlatName => 'Contrast2012', Writable => 'real', List => 0 }, LocalHighlights2012 => { FlatName => 'Highlights2012', Writable => 'real', List => 0 }, @@ -485,11 +550,25 @@ my %sCorrection = ( LocalDefringe => { FlatName => 'Defringe', Writable => 'real', List => 0 }, LocalTemperature => { FlatName => 'Temperature',Writable => 'real', List => 0 }, LocalTint => { FlatName => 'Tint', Writable => 'real', List => 0 }, + LocalHue => { FlatName => 'Hue', Writable => 'real', List => 0 }, + LocalWhites2012 => { FlatName => 'Whites2012', Writable => 'real', List => 0 }, + LocalBlacks2012 => { FlatName => 'Blacks2012', Writable => 'real', List => 0 }, + LocalDehaze => { FlatName => 'Dehaze', Writable => 'real', List => 0 }, + LocalTexture => { FlatName => 'Texture', Writable => 'real', List => 0 }, + # new in LR 11.0 + CorrectionRangeMask => { + Name => 'CorrRangeMask', + Notes => 'called CorrectionRangeMask by the spec', + FlatName => 'RangeMask', + Struct => \%sCorrRangeMask, + }, CorrectionMasks => { FlatName => 'Mask', Struct => \%sCorrectionMask, List => 'Seq', }, + CorrectionName => { }, + CorrectionSyncID => { }, ); my %sRetouchArea = ( STRUCT_NAME => 'RetouchArea', @@ -508,6 +587,30 @@ my %sRetouchArea = ( List => 'Seq', }, ); +my %sMapInfo = ( + STRUCT_NAME => 'MapInfo', + NAMESPACE => 'crs', + NOTES => q{ + Called RangeMaskMapInfo by the specification, the same as the containing + structure. + }, + RGBMin => { }, + RGBMax => { }, + LabMin => { }, + LabMax => { }, + LumEq => { List => 'Seq' }, +); +my %sRangeMask = ( + STRUCT_NAME => 'RangeMask', + NAMESPACE => 'crs', + NOTES => q{ + This structure is actually called RangeMaskMapInfo, but it only contains one + element which is a RangeMaskMapInfo structure (Yes, really!). So these are + renamed to RangeMask and MapInfo respectively to avoid confusion and + redundancy in the tag names. + }, + RangeMaskMapInfo => { FlatName => 'MapInfo', Struct => \%sMapInfo }, +); # main XMP tag table (tag ID's are used for the family 1 group names) %Image::ExifTool::XMP::Main = ( @@ -558,6 +661,10 @@ my %sRetouchArea = ( Name => 'photoshop', SubDirectory => { TagTable => 'Image::ExifTool::XMP::photoshop' }, }, + crd => { + Name => 'crd', + SubDirectory => { TagTable => 'Image::ExifTool::XMP::crd' }, + }, crs => { Name => 'crs', SubDirectory => { TagTable => 'Image::ExifTool::XMP::crs' }, @@ -746,6 +853,14 @@ my %sRetouchArea = ( Name => 'GFocus', SubDirectory => { TagTable => 'Image::ExifTool::XMP::GFocus' }, }, + GCamera => { + Name => 'GCamera', + SubDirectory => { TagTable => 'Image::ExifTool::XMP::GCamera' }, + }, + GCreations => { + Name => 'GCreations', + SubDirectory => { TagTable => 'Image::ExifTool::XMP::GCreations' }, + }, dwc => { Name => 'dwc', SubDirectory => { TagTable => 'Image::ExifTool::DarwinCore::Main' }, @@ -762,6 +877,22 @@ my %sRetouchArea = ( Name => 'LImage', SubDirectory => { TagTable => 'Image::ExifTool::XMP::LImage' }, }, + Device => { + Name => 'Device', + SubDirectory => { TagTable => 'Image::ExifTool::XMP::Device' }, + }, + sdc => { + Name => 'sdc', + SubDirectory => { TagTable => 'Image::ExifTool::Nikon::sdc' }, + }, + ast => { + Name => 'ast', + SubDirectory => { TagTable => 'Image::ExifTool::Nikon::ast' }, + }, + nine => { + Name => 'nine', + SubDirectory => { TagTable => 'Image::ExifTool::Nikon::nine' }, + }, ); # hack to allow XML containing Dublin Core metadata to be handled like XMP (eg. EPUB - see ZIP.pm) @@ -868,6 +999,7 @@ my %sRetouchArea = ( ModifyDate => { Groups => { 2 => 'Time' }, %dateTimeInfo, Priority => 0 }, Nickname => { }, Rating => { Writable => 'real', Notes => 'a value from 0 to 5, or -1 for "rejected"' }, + RatingPercent=>{ Writable => 'real', Avoid => 1, Notes => 'non-standard' }, Thumbnails => { FlatName => 'Thumbnail', Struct => \%sThumbnail, @@ -935,7 +1067,7 @@ my %sPantryItem = ( This structure must have an InstanceID field, but may also contain any other XMP properties. }, - InstanceID => { Namespace => 'xmpMM' }, + InstanceID => { Namespace => 'xmpMM', List => 0 }, ); # XMP Media Management namespace properties (xmpMM, xapMM) @@ -1123,7 +1255,7 @@ my %sPantryItem = ( LayerText => { }, }, }, - TransmissionReference => { }, + TransmissionReference => { Notes => 'Now used as a job identifier' }, Urgency => { Writable => 'integer', Notes => 'should be in the range 1-8 to conform with the XMP spec', @@ -1268,11 +1400,11 @@ my %sPantryItem = ( SharpenDetail => { Writable => 'integer' }, SharpenEdgeMasking => { Writable => 'integer' }, SharpenRadius => { Writable => 'real' }, - SplitToningBalance => { Writable => 'integer' }, - SplitToningHighlightHue => { Writable => 'integer' }, - SplitToningHighlightSaturation => { Writable => 'integer' }, - SplitToningShadowHue => { Writable => 'integer' }, - SplitToningShadowSaturation => { Writable => 'integer' }, + SplitToningBalance => { Writable => 'integer', Notes => 'also used for newer ColorGrade settings' }, + SplitToningHighlightHue => { Writable => 'integer', Notes => 'also used for newer ColorGrade settings' }, + SplitToningHighlightSaturation => { Writable => 'integer', Notes => 'also used for newer ColorGrade settings' }, + SplitToningShadowHue => { Writable => 'integer', Notes => 'also used for newer ColorGrade settings' }, + SplitToningShadowSaturation => { Writable => 'integer', Notes => 'also used for newer ColorGrade settings' }, Vibrance => { Writable => 'integer' }, # new tags written by LR 1.4 (not sure in what version they first appeared) GrayMixerRed => { Writable => 'integer' }, @@ -1358,6 +1490,7 @@ my %sPantryItem = ( Exposure2012 => { Writable => 'real' }, Contrast2012 => { Writable => 'integer' }, Highlights2012 => { Writable => 'integer' }, + Highlight2012 => { Writable => 'integer' }, # (written by Nikon software) Shadows2012 => { Writable => 'integer' }, Whites2012 => { Writable => 'integer' }, Blacks2012 => { Writable => 'integer' }, @@ -1452,6 +1585,90 @@ my %sPantryItem = ( PerspectiveX => { Writable => 'real' }, PerspectiveY => { Writable => 'real' }, UprightFourSegmentsCount => { Writable => 'integer' }, + AutoTone => { Writable => 'boolean' }, + Texture => { Writable => 'integer' }, + # more stuff (ref forum10721) + OverrideLookVignette => { Writable => 'boolean' }, + Look => { + Struct => { + STRUCT_NAME => 'Look', + NAMESPACE => 'crs', + Name => { }, + Amount => { }, + Cluster => { }, + UUID => { }, + SupportsMonochrome => { }, + SupportsAmount => { }, + SupportsOutputReferred => { }, + Copyright => { }, + Group => { Writable => 'lang-alt' }, + Parameters => { + Struct => { + STRUCT_NAME => 'LookParms', + NAMESPACE => 'crs', + Version => { }, + ProcessVersion => { }, + Clarity2012 => { }, + ConvertToGrayscale => { }, + CameraProfile => { }, + LookTable => { }, + ToneCurvePV2012 => { List => 'Seq' }, + ToneCurvePV2012Red => { List => 'Seq' }, + ToneCurvePV2012Green => { List => 'Seq' }, + ToneCurvePV2012Blue => { List => 'Seq' }, + }, + }, + } + }, + # more again (ref forum11258) + GrainSeed => { }, + ClipboardOrientation => { Writable => 'integer' }, + ClipboardAspectRatio => { Writable => 'integer' }, + PresetType => { }, + Cluster => { }, + UUID => { Avoid => 1 }, + SupportsAmount => { Writable => 'boolean' }, + SupportsColor => { Writable => 'boolean' }, + SupportsMonochrome => { Writable => 'boolean' }, + SupportsHighDynamicRange=> { Writable => 'boolean' }, + SupportsNormalDynamicRange=> { Writable => 'boolean' }, + SupportsSceneReferred => { Writable => 'boolean' }, + SupportsOutputReferred => { Writable => 'boolean' }, + CameraModelRestriction => { }, + Copyright => { Avoid => 1 }, + ContactInfo => { }, + GrainSeed => { Writable => 'integer' }, + Name => { Writable => 'lang-alt', Avoid => 1 }, + ShortName => { Writable => 'lang-alt' }, + SortName => { Writable => 'lang-alt' }, + Group => { Writable => 'lang-alt', Avoid => 1 }, + Description => { Writable => 'lang-alt', Avoid => 1 }, + # new for DNG converter 13.0 + LookName => { NotFlat => 1 }, # (grr... conflicts with "Name" element of "Look" struct!) + # new for Lightroom CC 2021 (ref forum11745) + ColorGradeMidtoneHue => { Writable => 'integer' }, + ColorGradeMidtoneSat => { Writable => 'integer' }, + ColorGradeShadowLum => { Writable => 'integer' }, + ColorGradeMidtoneLum => { Writable => 'integer' }, + ColorGradeHighlightLum => { Writable => 'integer' }, + ColorGradeBlending => { Writable => 'integer' }, + ColorGradeGlobalHue => { Writable => 'integer' }, + ColorGradeGlobalSat => { Writable => 'integer' }, + ColorGradeGlobalLum => { Writable => 'integer' }, + # new for Adobe Camera Raw 13 (ref forum11745) + LensProfileIsEmbedded => { Writable => 'boolean'}, + AutoToneDigest => { }, + AutoToneDigestNoSat => { }, + ToggleStyleDigest => { }, + ToggleStyleAmount => { Writable => 'integer' }, + # new for LightRoom 11.0 + CompatibleVersion => { }, + MaskGroupBasedCorrections => { + FlatName => 'MaskGroupBasedCorr', + Struct => \%sCorrection, + List => 'Seq', + }, + RangeMaskMapInfo => { Name => 'RangeMask', Struct => \%sRangeMask, FlatName => 'RangeMask' }, ); # Tiff namespace properties (tiff) @@ -1463,8 +1680,8 @@ my %sPantryItem = ( TABLE_DESC => 'XMP TIFF', NOTES => q{ EXIF namespace for TIFF tags. See - L<http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf> for the - specification. + L<https://web.archive.org/web/20180921145139if_/http://www.cipa.jp:80/std/documents/e/DC-010-2017_E.pdf> + for the specification. }, ImageWidth => { Writable => 'integer' }, ImageLength => { Writable => 'integer', Name => 'ImageHeight' }, @@ -1543,7 +1760,7 @@ my %sPantryItem = ( Software => { }, Artist => { Groups => { 2 => 'Author' } }, Copyright => { Groups => { 2 => 'Author' }, Writable => 'lang-alt' }, - NativeDigest => { }, #PH + NativeDigest => { Avoid => 1 }, #PH ); # Exif namespace properties (exif) @@ -1554,8 +1771,8 @@ my %sPantryItem = ( PRIORITY => 0, # not as reliable as actual EXIF tags NOTES => q{ EXIF namespace for EXIF tags. See - L<http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf> for the - specification. + L<https://web.archive.org/web/20180921145139if_/http://www.cipa.jp:80/std/documents/e/DC-010-2017_E.pdf> + for the specification. }, ExifVersion => { }, FlashpixVersion => { }, @@ -1891,6 +2108,11 @@ my %sPantryItem = ( Groups => { 2 => 'Location' }, Writable => 'integer', PrintConv => { + OTHER => sub { + my ($val, $inv) = @_; + return undef unless $inv and $val =~ /^([-+0-9])/; + return($1 eq '-' ? 1 : 0); + }, 0 => 'Above Sea Level', 1 => 'Below Sea Level', }, @@ -1927,8 +2149,8 @@ my %sPantryItem = ( Groups => { 2 => 'Location' }, Writable => 'integer', PrintConv => { - 2 => '2-Dimensional', - 3 => '3-Dimensional', + 2 => '2-Dimensional Measurement', + 3 => '3-Dimensional Measurement', }, }, GPSDOP => { Groups => { 2 => 'Location' }, Writable => 'rational' }, @@ -1998,6 +2220,7 @@ my %sPantryItem = ( PrintConvInv => '$val=~s/\s*m$//; $val', }, NativeDigest => { }, #PH + # new Exif ); # Exif extended properties (exifEX, ref 12) @@ -2007,8 +2230,8 @@ my %sPantryItem = ( NAMESPACE => 'exifEX', PRIORITY => 0, # not as reliable as actual EXIF tags NOTES => q{ - EXIF tags added by the EXIF 2.31 for XMP specification (see - L<http://www.cipa.jp/std/documents/e/DC-010-2017_E.pdf>). + EXIF tags added by the EXIF 2.32 for XMP specification (see + L<https://cipa.jp/std/documents/download_e.html?DC-010-2020_E>). }, Gamma => { Writable => 'rational' }, PhotographicSensitivity => { Writable => 'integer' }, @@ -2037,10 +2260,11 @@ my %sPantryItem = ( Writable => 'integer', }, CameraOwnerName => { Name => 'OwnerName' }, - BodySerialNumber => { Name => 'SerialNumber' }, + BodySerialNumber => { Name => 'SerialNumber', Groups => { 2 => 'Camera' } }, LensSpecification => { Name => 'LensInfo', Writable => 'rational', + Groups => { 2 => 'Camera' }, List => 'Seq', RawJoin => 1, # join list into a string before ValueConv ValueConv => \&ConvertRationalList, @@ -2064,9 +2288,9 @@ my %sPantryItem = ( instead of using the existing XMP-aux:LensInfo }, }, - LensMake => { }, - LensModel => { }, - LensSerialNumber => { }, + LensMake => { Groups => { 2 => 'Camera' } }, + LensModel => { Groups => { 2 => 'Camera' } }, + LensSerialNumber => { Groups => { 2 => 'Camera' } }, InteroperabilityIndex => { Name => 'InteropIndex', Description => 'Interoperability Index', @@ -2083,6 +2307,35 @@ my %sPantryItem = ( WaterDepth => { Writable => 'rational' }, Acceleration => { Writable => 'rational' }, CameraElevationAngle=> { Writable => 'rational' }, + # new in Exif 2.32 (according to the spec, these should use a different namespace + # URI, but the same namespace prefix... Exactly how is that supposed to work?!! + # -- I'll just stick with the same URI) + CompositeImage => { Writable => 'integer', + PrintConv => { + 0 => 'Unknown', + 1 => 'Not a Composite Image', + 2 => 'General Composite Image', + 3 => 'Composite Image Captured While Shooting', + }, + }, + CompositeImageCount => { List => 'Seq', Writable => 'integer' }, + CompositeImageExposureTimes => { + FlatName => 'CompImage', + Struct => { + STRUCT_NAME => 'CompImageExp', + NAMESPACE => 'exifEX', + TotalExposurePeriod => { Writable => 'rational' }, + SumOfExposureTimesOfAll => { Writable => 'rational', FlatName => 'SumExposureAll' }, + SumOfExposureTimesOfUsed=> { Writable => 'rational', FlatName => 'SumExposureUsed' }, + MaxExposureTimesOfAll => { Writable => 'rational', FlatName => 'MaxExposureAll' }, + MaxExposureTimesOfUsed => { Writable => 'rational', FlatName => 'MaxExposureUsed' }, + MinExposureTimesOfAll => { Writable => 'rational', FlatName => 'MinExposureAll' }, + MinExposureTimesOfUsed => { Writable => 'rational', FlatName => 'MinExposureUsed' }, + NumberOfSequences => { Writable => 'integer', FlatName => 'NumSequences' }, + NumberOfImagesInSequences=>{ Writable => 'integer', FlatName => 'ImagesPerSequence' }, + Values => { List => 'Seq', Writable => 'rational' }, + }, + }, ); # Auxiliary namespace properties (aux) - not fully documented (ref PH) @@ -2130,7 +2383,7 @@ my %sPantryItem = ( Priority => 0, # prevent this from getting set from a LensID that has been converted ValueConvInv => q{ - warn "Expected one or more integer values" if $val =~ /[^\d ]/; + warn "Expected one or more integer values" if $val =~ /[^-\d ]/; return $val; }, }, @@ -2142,6 +2395,7 @@ my %sPantryItem = ( VignetteCorrectionAlreadyApplied => { Writable => 'boolean' }, LateralChromaticAberrationCorrectionAlreadyApplied => { Writable => 'boolean' }, LensDistortInfo => { }, # (LR 7.5.1, 4 signed rational values) + NeutralDensityFactor => { }, # (LR 11.0 - rational value, but denominator seems significant) ); # IPTC Core namespace properties (Iptc4xmpCore) (ref 4) @@ -2183,6 +2437,10 @@ my %sPantryItem = ( Location => { Groups => { 2 => 'Location' } }, Scene => { Groups => { 2 => 'Other' }, List => 'Bag' }, SubjectCode => { Groups => { 2 => 'Other' }, List => 'Bag' }, + # Copyright - have seen this in a sample (Jan 2021), but I think it is non-standard + # new IPTC Core 1.3 properties + AltTextAccessibility => { Groups => { 2 => 'Other' }, Writable => 'lang-alt' }, + ExtDescrAccessibility => { Groups => { 2 => 'Other' }, Writable => 'lang-alt' }, ); # Adobe Lightroom namespace properties (lr) (ref PH) @@ -2194,6 +2452,7 @@ my %sPantryItem = ( NOTES => 'Adobe Lightroom "lr" namespace tags.', privateRTKInfo => { }, hierarchicalSubject => { List => 'Bag' }, + weightedFlatSubject => { List => 'Bag' }, ); # Adobe Album namespace properties (album) (ref PH) @@ -2214,10 +2473,12 @@ my %sPantryItem = ( # Composite XMP tags %Image::ExifTool::XMP::Composite = ( - # get latitude/logitude reference from XMP lat/long tags + # get latitude/longitude reference from XMP lat/long tags # (used to set EXIF GPS position from XMP tags) GPSLatitudeRef => { - Require => 'XMP:GPSLatitude', + Require => 'XMP-exif:GPSLatitude', + Groups => { 2 => 'Location' }, + # Note: Do not Inihibit based on EXIF:GPSLatitudeRef (see forum10192) ValueConv => q{ IsFloat($val[0]) and return $val[0] < 0 ? "S" : "N"; $val[0] =~ /^.*([NS])/; @@ -2226,7 +2487,8 @@ my %sPantryItem = ( PrintConv => { N => 'North', S => 'South' }, }, GPSLongitudeRef => { - Require => 'XMP:GPSLongitude', + Require => 'XMP-exif:GPSLongitude', + Groups => { 2 => 'Location' }, ValueConv => q{ IsFloat($val[0]) and return $val[0] < 0 ? "W" : "E"; $val[0] =~ /^.*([EW])/; @@ -2235,7 +2497,8 @@ my %sPantryItem = ( PrintConv => { E => 'East', W => 'West' }, }, GPSDestLatitudeRef => { - Require => 'XMP:GPSDestLatitude', + Require => 'XMP-exif:GPSDestLatitude', + Groups => { 2 => 'Location' }, ValueConv => q{ IsFloat($val[0]) and return $val[0] < 0 ? "S" : "N"; $val[0] =~ /^.*([NS])/; @@ -2244,7 +2507,8 @@ my %sPantryItem = ( PrintConv => { N => 'North', S => 'South' }, }, GPSDestLongitudeRef => { - Require => 'XMP:GPSDestLongitude', + Require => 'XMP-exif:GPSDestLongitude', + Groups => { 2 => 'Location' }, ValueConv => q{ IsFloat($val[0]) and return $val[0] < 0 ? "W" : "E"; $val[0] =~ /^.*([EW])/; @@ -2267,6 +2531,7 @@ my %sPantryItem = ( Inhibit => { 6 => 'Composite:LensID', # don't override existing Composite:LensID }, + Groups => { 2 => 'Camera' }, ValueConv => '$val', PrintConv => 'Image::ExifTool::XMP::PrintLensID($self, @val)', }, @@ -2280,6 +2545,7 @@ my %sPantryItem = ( 4 => 'XMP:FlashRedEyeMode', 5 => 'XMP:Flash', # handle structured flash information too }, + Groups => { 2 => 'Camera' }, Writable => 1, PrintHex => 1, SeparateTable => 'EXIF Flash', @@ -2289,11 +2555,11 @@ my %sPantryItem = ( my $i = 0; $val[$i++] = $val[5]{$_} foreach qw(Fired Return Mode Function RedEyeMode); } - return (($val[0] and lc($val[0]) eq 'true') ? 0x01 : 0) | + return((($val[0] and lc($val[0]) eq 'true') ? 0x01 : 0) | (($val[1] || 0) << 1) | (($val[2] || 0) << 3) | (($val[3] and lc($val[3]) eq 'true') ? 0x20 : 0) | - (($val[4] and lc($val[4]) eq 'true') ? 0x40 : 0); + (($val[4] and lc($val[4]) eq 'true') ? 0x40 : 0)); }, PrintConv => \%Image::ExifTool::Exif::flash, WriteAlso => { @@ -2333,13 +2599,14 @@ sub EscapeXML($) # Unescape XML character references (entities and numerical) # Inputs: 0) string to be unescaped # 1) optional hash reference to convert entity names to numbers +# 2) optional character encoding # Returns: unescaped string my %charNum = ('quot'=>34, 'amp'=>38, 'apos'=>39, 'lt'=>60, 'gt'=>62); -sub UnescapeXML($;$) +sub UnescapeXML($;$$) { - my ($str, $conv) = @_; + my ($str, $conv, $enc) = @_; $conv = \%charNum unless $conv; - $str =~ s/&(#?\w+);/UnescapeChar($1,$conv)/sge; + $str =~ s/&(#?\w+);/UnescapeChar($1,$conv,$enc)/sge; return $str; } @@ -2377,10 +2644,11 @@ sub FullUnescapeXML($) # Convert XML character reference to UTF-8 # Inputs: 0) XML character reference stripped of the '&' and ';' (eg. 'quot', '#34', '#x22') # 1) hash reference for looking up character numbers by name +# 2) optional character encoding (default 'UTF8') # Returns: UTF-8 equivalent (or original character on conversion error) -sub UnescapeChar($$) +sub UnescapeChar($$;$) { - my ($ch, $conv) = @_; + my ($ch, $conv, $enc) = @_; my $val = $$conv{$ch}; unless (defined $val) { if ($ch =~ /^#x([0-9a-fA-F]+)$/) { @@ -2392,20 +2660,21 @@ sub UnescapeChar($$) } } return chr($val) if $val < 0x80; # simple ASCII - return pack('C0U', $val) if $] >= 5.006001; - return Image::ExifTool::PackUTF8($val); + $val = $] >= 5.006001 ? pack('C0U', $val) : Image::ExifTool::PackUTF8($val); + $val = Image::ExifTool::Decode(undef, $val, 'UTF8', undef, $enc) if $enc and $enc ne 'UTF8'; + return $val; } #------------------------------------------------------------------------------ # Does a string contain valid UTF-8 characters? -# Inputs: 0) string reference +# Inputs: 0) string reference, 1) true to allow last character to be truncated # Returns: 0=regular ASCII, -1=invalid UTF-8, 1=valid UTF-8 with maximum 16-bit # wide characters, 2=valid UTF-8 requiring 32-bit wide characters # Notes: Changes current string position # (see http://www.fileformat.info/info/unicode/utf8.htm for help understanding this) -sub IsUTF8($) +sub IsUTF8($;$) { - my $strPt = shift; + my ($strPt, $trunc) = @_; pos($$strPt) = 0; # start at beginning of string return 0 unless $$strPt =~ /([\x80-\xff])/g; my $rtnVal = 1; @@ -2427,7 +2696,11 @@ sub IsUTF8($) # were required in the UTF-8 character $rtnVal = 2; } - return -1 unless $$strPt =~ /\G([\x80-\xbf]{$n})/g; + my $pos = pos $$strPt; + unless ($$strPt =~ /\G([\x80-\xbf]{$n})/g) { + return $rtnVal if $trunc and $pos + $n > length $$strPt; + return -1; + } # the following is ref https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c if ($n == 2) { return -1 if ($ch == 0xe0 and (ord($1) & 0xe0) == 0x80) or @@ -2647,8 +2920,6 @@ sub AddFlattenedTags($;$$) $$tagInfo{Struct} = $strTable; # replace old-style name with HASH ref delete $$tagInfo{SubDirectory}; # deprecated use of SubDirectory in Struct tags } - # do not add flattened tags to variable-namespace structures - next if exists $$strTable{NAMESPACE} and not defined $$strTable{NAMESPACE}; # get prefix for flattened tag names my $flat = (defined $$tagInfo{FlatName} ? $$tagInfo{FlatName} : $$tagInfo{Name}); @@ -2671,8 +2942,9 @@ sub AddFlattenedTags($;$$) if ($flatInfo) { ref $flatInfo eq 'HASH' or warn("$flatInfo is not a HASH!\n"), next; # (to be safe) # pre-defined flattened tags should have Flat flag set - if (not defined $$flatInfo{Flat} and $Image::ExifTool::debug) { - warn "Missing Flat flag for $$flatInfo{Name}\n"; + if (not defined $$flatInfo{Flat}) { + next if $$flatInfo{NotFlat}; + warn "Missing Flat flag for $$flatInfo{Name}\n" if $Image::ExifTool::debug; } $$flatInfo{Flat} = 0; # copy all missing entries from field information @@ -2690,6 +2962,7 @@ sub AddFlattenedTags($;$$) # generate new flattened tag information based on structure field my $flatName = $flat . $flatField; $flatInfo = { %$fieldInfo, Name => $flatName, Flat => 0 }; + $$flatInfo{FlatName} = $flatName if $$fieldInfo{FlatName}; # make a copy of the Groups hash if necessary $$flatInfo{Groups} = { %{$$fieldInfo{Groups}} } if $$fieldInfo{Groups}; # add new flattened tag to table @@ -2858,13 +3131,15 @@ sub PrintLensID(@) # for Pentax, CS4 stores an int16u, but we use 2 x int8u $id = join(' ', unpack('C*', pack('n', $id))); } - my $str = $$printConv{$id} || "Unknown ($id)"; # Nikon is a special case because Adobe doesn't store the full LensID + # (Apple Photos does, but we have to convert back to hex) if ($mk eq 'Nikon') { - my $hex = sprintf("%.2X", $id); + $id = sprintf('%X', $id); + $id = "0$id" if length($id) & 0x01; # pad with leading 0 if necessary + $id =~ s/(..)/$1 /g and $id =~ s/ $//; # put spaces between bytes my (%newConv, %used); my $i = 0; - foreach (grep /^$hex /, keys %$printConv) { + foreach (grep /^$id/, keys %$printConv) { my $lens = $$printConv{$_}; next if $used{$lens}; # avoid duplicates $used{$lens} = 1; @@ -2873,6 +3148,7 @@ sub PrintLensID(@) } $printConv = \%newConv; } + my $str = $$printConv{$id} || "Unknown ($id)"; return Image::ExifTool::Exif::PrintLensID($et, $str, $printConv, undef, $id, $focalLength, $sa, $maxAv, $sf, $lf, $lensModel); } @@ -2960,18 +3236,35 @@ sub FoundXMP($$$$;$) } } - if (not $ns and $$tagTablePtr{GROUPS}{0} ne 'XMP') { - # this is a simple XML table (no namespaces) + my $xmlGroups; + my $grp0 = $$tagTablePtr{GROUPS}{0}; + if (not $ns and $grp0 ne 'XMP') { $tagID = $tag; + } elsif ($grp0 eq 'XML' and not $table) { + # this is an XML table (no namespace lookup) + $tagID = "$ns:$tag"; } else { + $xmlGroups = 1 if $grp0 eq 'XML'; # look up this tag in the appropriate table $table or $table = 'Image::ExifTool::XMP::other'; $tagTablePtr = GetTagTable($table); if ($$tagTablePtr{NAMESPACE}) { $tagID = $tag; } else { + $xns = $xmpNS{$ns}; + unless (defined $xns) { + $xns = $ns; + # validate namespace prefix + unless ($ns =~ /^[A-Z_a-z\x80-\xff][-.0-9A-Z_a-z\x80-\xff]*$/ or $ns eq '') { + $et->Warn("Invalid XMP namespace prefix '${ns}'"); + # clean up prefix for use as an ExifTool group name + $ns =~ tr/-.0-9A-Z_a-z\x80-\xff//dc; + $ns =~ /^[A-Z_a-z\x80-\xff]/ or $ns = "ns_$ns"; + $stdXlatNS{$xns} = $ns; + $xmpNS{$ns} = $xns; + } + } # add XMP namespace prefix to avoid collisions in variable-namespace tables - $xns = $xmpNS{$ns} || $ns; $tagID = "$xns:$tag"; # add namespace to top-level structure property $structProps[0][0] = "$xns:" . $structProps[0][0] if @structProps; @@ -2997,14 +3290,6 @@ NoLoop: $ti = $$tagTablePtr{$t} or next; next unless ref $ti eq 'HASH' and $$ti{Struct}; $addedFlat = AddFlattenedTags($tagTablePtr, $t); - if ($tagInfo) { - # all done if we just wanted to initialize the flattened tag - if ($$tagInfo{Flat}) { - warn "Orphan tagInfo with Flat flag set: $$tagInfo{Name}\n"; - delete $$tagInfo{Flat}; - } - last NoLoop; - } # all done if we generated the tag we are looking for $tagInfo = $$tagTablePtr{$tagID} and last NoLoop if $addedFlat; } @@ -3062,11 +3347,8 @@ NoLoop: } last unless $sti; } - $tagInfo = { - %$sti, - Name => $flat . $$sti{Name}, - WasAdded => 1, - }; + # generate new tagInfo hash based on existing top-level tag + $tagInfo = { %$sti, Name => $flat . $$sti{Name} }; # be careful not to copy elements we shouldn't... delete $$tagInfo{Description}; # Description will be different # can't copy group hash because group 1 will be different and @@ -3076,11 +3358,18 @@ NoLoop: last; } } - $tagInfo or $tagInfo = { Name => $name, WasAdded => 1, Priority => 0 }; - + # generate a default tagInfo hash if necessary + unless ($tagInfo) { + # shorten tag name if necessary + if ($$et{ShortenXmpTags}) { + my $shorten = $$et{ShortenXmpTags}; + $name = &$shorten($name); + } + $tagInfo = { Name => $name, IsDefault => 1, Priority => 0 }; + } # add tag Namespace entry for tags in variable-namespace tables $$tagInfo{Namespace} = $xns if $xns; - if ($$et{curURI}{$ns} and $$et{curURI}{$ns} =~ m{^http://ns.exiftool.ca/(.*?)/(.*?)/}) { + if ($$et{curURI}{$ns} and $$et{curURI}{$ns} =~ m{^http://ns.exiftool.(?:ca|org)/(.*?)/(.*?)/}) { my %grps = ( 0 => $1, 1 => $2 ); # apply a little magic to recover original group names # from this exiftool-written RDF/XML file @@ -3108,8 +3397,13 @@ NoLoop: #} elsif (grep / /, @$props) { # $$tagInfo{List} = 1; } + # save property list for verbose "adding" message unless this tag already exists + $added = \@tagList unless $$tagTablePtr{$tagID}; + # if this is an empty structure, we must add a Struct field + if (not length $val and $$attrs{'rdf:parseType'} and $$attrs{'rdf:parseType'} eq 'Resource') { + $$tagInfo{Struct} = { STRUCT_NAME => 'XMP Unknown' }; + } AddTagToTable($tagTablePtr, $tagID, $tagInfo); - $added = 1; last; } # decode value if necessary (et:encoding was used before exiftool 7.71) @@ -3145,7 +3439,7 @@ NoLoop: $val = $et->Decode($val, 'UTF8'); # convert rational and date values to a more sensible format my $fmt = $$tagInfo{Writable}; - my $new = $$tagInfo{WasAdded} && $$et{OPTIONS}{XMPAutoConv}; + my $new = $$tagInfo{IsDefault} && $$et{OPTIONS}{XMPAutoConv}; if ($fmt or $new) { $rawVal = $val; # save raw value for verbose output if (($new or $fmt eq 'rational') and ConvertRational($val)) { @@ -3153,6 +3447,13 @@ NoLoop: } else { $val = ConvertXMPDate($val, $new) if $new or $fmt eq 'date'; } + if ($$et{XmpValidate} and $fmt and $fmt eq 'boolean' and $val!~/^True|False$/) { + if ($val =~ /^true|false$/) { + $et->WarnOnce("Boolean value for XMP-$ns:$$tagInfo{Name} should be capitalized",1); + } else { + $et->WarnOnce(qq(Boolean value for XMP-$ns:$$tagInfo{Name} should be "True" or "False"),1); + } + } # protect against large binary data in unknown tags $$tagInfo{Binary} = 1 if $new and length($val) > 65536; } @@ -3167,18 +3468,52 @@ NoLoop: $$et{TAG_EXTRA}{$key}{Struct} = \@structProps; $$et{IsStruct} = 1; } - if ($ns and not $$tagInfo{StaticGroup1}) { + if ($xmlGroups) { + $et->SetGroup($key, 'XML', 0); + $et->SetGroup($key, "XML-$ns", 1); + } elsif ($ns and not $$tagInfo{StaticGroup1}) { # set group1 dynamically according to the namespace $et->SetGroup($key, "$$tagTablePtr{GROUPS}{0}-$ns"); } if ($$et{OPTIONS}{Verbose}) { if ($added) { + my $props; + if (@$added > 1) { + $$tagInfo{Flat} = 0; # this is a flattened tag + my @props = map { $$_[0] } @$added; + $props = ' (' . join('/',@props) . ')'; + } else { + $props = ''; + } my $g1 = $et->GetGroup($key, 1); - $et->VPrint(0, $$et{INDENT}, "[adding $g1:$tag]\n"); + $et->VPrint(0, $$et{INDENT}, "[adding $g1:$tag]$props\n"); } my $tagID = join('/',@$props); $et->VerboseInfo($tagID, $tagInfo, Value => $rawVal || $val); } + # allow read-only subdirectories (eg. embedded base64 XMP/IPTC in NKSC files) + if ($$tagInfo{SubDirectory} and not $$et{IsWriting}) { + my $subdir = $$tagInfo{SubDirectory}; + my $dataPt = ref $$et{VALUE}{$key} ? $$et{VALUE}{$key} : \$$et{VALUE}{$key}; + # decode if necessary (eg. Nikon XMP-ast:XMLPackets) + $dataPt = DecodeBase64($$dataPt) if $$tagInfo{Encoding} and $$tagInfo{Encoding} eq 'Base64'; + # process subdirectory information + my %dirInfo = ( + DirName => $$subdir{DirName} || $$tagInfo{Name}, + DataPt => $dataPt, + DirLen => length $$dataPt, + IgnoreProp => $$subdir{IgnoreProp}, # (allow XML to ignore specified properties) + IsExtended => 1, # (hack to avoid Duplicate warning for embedded XMP) + ); + my $oldOrder = GetByteOrder(); + SetByteOrder($$subdir{ByteOrder}) if $$subdir{ByteOrder}; + my $oldNS = $$et{definedNS}; + delete $$et{definedNS}; + my $subTablePtr = GetTagTable($$subdir{TagTable}) || $tagTablePtr; + $et->ProcessDirectory(\%dirInfo, $subTablePtr, $$subdir{ProcessProc}); + SetByteOrder($oldOrder); + $$et{definedNS} = $oldNS; + } return 1; } @@ -3244,7 +3579,6 @@ sub ParseXMPElement($$$;$$$$) # (empty elements end with '/', eg. <a:b/>) if ($attrs !~ s/\/$//) { my $nesting = 1; - my $tok; for (;;) { # this match fails with perl 5.6.2 (perl bug!), but it works without # the '(.*?)', so we must do it differently... @@ -3272,6 +3606,17 @@ sub ParseXMPElement($$$;$$$$) } $start = pos($$dataPt); # start from here the next time around + # ignore specified XMP namespaces/properties + if ($$et{EXCL_XMP_LOOKUP} and not $isWriting and $prop =~ /^(.+):(.*)/) { + my ($ns, $nm) = (lc($stdXlatNS{$1} || $1), lc($2)); + if ($$et{EXCL_XMP_LOOKUP}{"xmp-$ns:all"} or $$et{EXCL_XMP_LOOKUP}{"xmp-$ns:$nm"} or + $$et{EXCL_XMP_LOOKUP}{"xmp-all:$nm"}) + { + ++$count; # (pretend we found something so we don't store as a tag value) + next; + } + } + # extract property attributes my ($parseResource, %attrs, @attrs); while ($attrs =~ m/(\S+?)\s*=\s*(['"])(.*?)\2/sg) { @@ -3369,9 +3714,9 @@ sub ParseXMPElement($$$;$$$$) if ($nItems == 1000) { my ($tg,$ns) = GetXMPTagID($propList); if ($isWriting) { - $et->Warn("Excessive number of items for $ns:$tg. Processing may be slow", 1); + $et->WarnOnce("Excessive number of items for $ns:$tg. Processing may be slow", 1); } elsif (not $$et{OPTIONS}{IgnoreMinorErrors}) { - $et->Warn("Extracted only 1000 $ns:$tg items. Ignore minor errors to extract all", 2); + $et->WarnOnce("Extracted only 1000 $ns:$tg items. Ignore minor errors to extract all", 2); last; } } @@ -3393,7 +3738,11 @@ sub ParseXMPElement($$$;$$$$) } elsif ($prop eq 'rdf:Description') { # remove unnecessary rdf:Description elements since parseType='Resource' # is more efficient (also necessary to make property path consistent) - $parseResource = 1 if grep /^rdf:Description$/, @$propList; + if (grep /^rdf:Description$/, @$propList) { + $parseResource = 1; + # set parseType so we know this is a structure + $attrs{'rdf:parseType'} = 'Resource'; + } } elsif ($prop eq 'xmp:xmpmeta') { # patch MicrosoftPhoto unconformity $prop = 'x:xmpmeta'; @@ -3433,6 +3782,11 @@ sub ParseXMPElement($$$;$$$$) # add svg namespace prefix if missing to ignore these entries in the tag name $$propList[-1] = "svg:$prop"; } + } elsif ($$et{XmpIgnoreProps}) { # ignore specified properties for tag name + foreach (@{$$et{XmpIgnoreProps}}) { + last unless @$propList; + pop @$propList if $_ eq $$propList[0]; + } } # handle properties inside element attributes (RDF shorthand format): @@ -3544,10 +3898,10 @@ sub ParseXMPElement($$$;$$$$) if ($prop eq 'rdf:Description' and $val) { $val =~ s/<!--.*?-->//g; $val =~ s/^\s+//; $val =~ s/\s+$//; } - # if element value is empty, take value from 'resource' attribute - # (preferentially) or 'about' attribute (if no 'resource') - if ($val eq '' and ($attrs =~ /\bresource=(['"])(.*?)\1/ or - $attrs =~ /\babout=(['"])(.*?)\1/)) + # if element value is empty, take value from RDF 'value' or 'resource' attribute + # (preferentially) or 'about' attribute (if no 'value' or 'resource') + if ($val eq '' and ($attrs =~ /\brdf:(?:value|resource)=(['"])(.*?)\1/ or + $attrs =~ /\brdf:about=(['"])(.*?)\1/)) { $val = $2; $wasEmpty = 1; @@ -3557,6 +3911,7 @@ sub ParseXMPElement($$$;$$$$) # (unless we already extracted shorthand values from this element) if (length $val or not $shorthand) { my $lastProp = $$propList[-1]; + $lastProp = '' unless defined $lastProp; if (defined $nodeID) { SaveBlankInfo($blankInfo, $propList, $val); } elsif ($lastProp eq 'rdf:type' and $wasEmpty) { @@ -3565,7 +3920,7 @@ sub ParseXMPElement($$$;$$$$) # ignore et:desc, and et:val if preceded by et:prt --$count; } else { - ValidateProperty($et, $propList) if $$et{XmpValidate}; + ValidateProperty($et, $propList, \%attrs) if $$et{XmpValidate}; &$foundProc($et, $tagTablePtr, $propList, $val, \%attrs); } } @@ -3630,6 +3985,7 @@ sub ProcessXMP($$;$) my ($buff, $fmt, $hasXMP, $isXML, $isRDF, $isSVG); my $rtnVal = 0; my $bom = 0; + my $path = $et->MetadataPath(); # namespaces and prefixes currently in effect while parsing the file, # and lookup to translate brain-dead-Microsoft-Photo-software prefixes @@ -3639,6 +3995,7 @@ sub ProcessXMP($$;$) $$et{definedNS} = { }; delete $$et{XmpAbout}; delete $$et{XmpValidate}; # don't validate by default + delete $$et{XmpValidateLangAlt}; # ignore non-standard XMP while in strict MWG compatibility mode if (($Image::ExifTool::MWG::strict or $$et{OPTIONS}{Validate}) and @@ -3646,11 +4003,7 @@ sub ProcessXMP($$;$) (($$dirInfo{DirName} || '') eq 'XMP' or $$et{FILE_TYPE} eq 'XMP')) { $$et{XmpValidate} = { } if $$et{OPTIONS}{Validate}; - my $path = $et->MetadataPath(); - my $nonStd; - if ($$et{FILE_TYPE} =~ /^(JPEG|TIFF|PSD)$/ and $path !~ /^(JPEG-APP1-XMP|TIFF-IFD0-XMP|PSD-XMP)$/) { - $nonStd = 1; - } + my $nonStd = ($stdPath{$$et{FILE_TYPE}} and $path ne $stdPath{$$et{FILE_TYPE}}); if ($nonStd and $Image::ExifTool::MWG::strict) { $et->Warn("Ignored non-standard XMP at $path"); return 1; @@ -3700,7 +4053,7 @@ sub ProcessXMP($$;$) $fmt = 'n'; # UTF-16 or 32 MM with BOM } elsif ($buf2 =~ /^(\xff\xfe)(<\?xml|<rdf:RDF|<x(mp)?:x[ma]pmeta)/g) { $fmt = 'v'; # UTF-16 or 32 II with BOM - } elsif ($buf2 =~ /^(\xef\xbb\xbf)?(<\?xml|<rdf:RDF|<x(mp)?:x[ma]pmeta)/g) { + } elsif ($buf2 =~ /^(\xef\xbb\xbf)?(<\?xml|<rdf:RDF|<x(mp)?:x[ma]pmeta|<svg\b)/g) { $fmt = 0; # UTF-8 with BOM or unknown encoding without BOM } elsif ($buf2 =~ /^(\xfe\xff|\xff\xfe|\xef\xbb\xbf)(<\?xpacket begin=)/g) { $double = $1; # double-encoded UTF @@ -3729,7 +4082,7 @@ sub ProcessXMP($$;$) } elsif ($1 eq 'REDXIF') { $type = 'RMD'; $mime = 'application/xml'; - } else { + } elsif ($1 ne 'fcpxml') { # Final Cut Pro XML return 0; } } elsif ($buf2 =~ /<svg[\s>]/) { @@ -3739,14 +4092,16 @@ sub ProcessXMP($$;$) } elsif ($buf2 =~ /<plist[\s>]/) { $type = 'PLIST'; } - if ($isSVG and $$et{XMP_CAPTURE}) { - $et->Error("ExifTool does not yet support writing of SVG images"); - return 0; - } } $isXML = 1; } elsif ($2 eq '<rdf:RDF') { $isRDF = 1; # recognize XMP without x:xmpmeta element + } elsif ($2 eq '<svg') { + $isSVG = $isXML = 1; + } + if ($isSVG and $$et{XMP_CAPTURE}) { + $et->Error("ExifTool does not yet support writing of SVG images"); + return 0; } if ($buff =~ /^\0\0/) { $fmt = 'N'; # UTF-32 MM with or without BOM @@ -3846,13 +4201,16 @@ sub ProcessXMP($$;$) $dirLen = $dataLen = length $$dataPt; } - # extract XMP as a block if specified + # extract XMP/XML as a block if specified my $blockName = $$dirInfo{BlockInfo} ? $$dirInfo{BlockInfo}{Name} : 'XMP'; + my $blockExtract = $et->Options('BlockExtract'); if (($$et{REQ_TAG_LOOKUP}{lc $blockName} or ($$et{TAGS_FROM_FILE} and - not $$et{EXCL_TAG_LOOKUP}{lc $blockName})) and - ($$dirInfo{DirName} and $$dirInfo{DirName} eq 'XMP')) + not $$et{EXCL_TAG_LOOKUP}{lc $blockName}) or $blockExtract) and + (($$et{FileType} eq 'XMP' and $blockName eq 'XMP') or + ($$dirInfo{DirName} and $$dirInfo{DirName} eq $blockName))) { $et->FoundTag($$dirInfo{BlockInfo} || 'XMP', substr($$dataPt, $dirStart, $dirLen)); + return 1 if $blockExtract and $blockExtract > 1; } $tagTablePtr or $tagTablePtr = GetTagTable('Image::ExifTool::XMP::Main'); @@ -3907,6 +4265,13 @@ sub ProcessXMP($$;$) } defined $fmt or $et->Warn('XMP character encoding error'); } + # warn if standard XMP is missing xpacket wrapper + if ($$et{XMP_NO_XPACKET} and $$et{OPTIONS}{Validate} and + $stdPath{$$et{FILE_TYPE}} and $path eq $stdPath{$$et{FILE_TYPE}} and + not $$dirInfo{IsExtended} and not $$et{DOC_NUM}) + { + $et->Warn('XMP is missing xpacket wrapper', 1); + } if ($fmt) { # trim if necessary to avoid converting non-UTF data if ($dirStart or $dirEnd != length($$dataPt)) { @@ -4012,7 +4377,7 @@ information. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/XMP2.pl b/src/Image-ExifTool/lib/Image/ExifTool/XMP2.pl index bd6f847a..79a2a2a4 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/XMP2.pl +++ b/src/Image-ExifTool/lib/Image/ExifTool/XMP2.pl @@ -15,6 +15,8 @@ # 9) http://www.w3.org/TR/SVG11/ # 11) http://www.extensis.com/en/support/kb_article.jsp?articleNumber=6102211 # 12) XMPSpecificationPart3_May2013, page 58 +# 13) https://developer.android.com/training/camera2/Dynamic-depth-v1.0.pdf +# 14) http://www.iptc.org/standards/photo-metadata/iptc-standard/ #------------------------------------------------------------------------------ package Image::ExifTool::XMP; @@ -23,6 +25,8 @@ package Image::ExifTool::XMP; use Image::ExifTool qw(:Utils); use Image::ExifTool::XMP; +sub Init_crd($); + #------------------------------------------------------------------------------ # xmpDM structure definitions @@ -74,6 +78,77 @@ package Image::ExifTool::XMP; timeValue => { }, value => { Writable => 'integer', Notes => 'only in XMP 2008 spec; an error?' }, ); +my %sPose = ( + STRUCT_NAME => 'Pose', + NAMESPACE => { Pose => 'http://ns.google.com/photos/dd/1.0/pose/' }, + PositionX => { Writable => 'real', Groups => { 2 => 'Location' } }, + PositionY => { Writable => 'real', Groups => { 2 => 'Location' } }, + PositionZ => { Writable => 'real', Groups => { 2 => 'Location' } }, + RotationX => { Writable => 'real', Groups => { 2 => 'Location' } }, + RotationY => { Writable => 'real', Groups => { 2 => 'Location' } }, + RotationZ => { Writable => 'real', Groups => { 2 => 'Location' } }, + RotationW => { Writable => 'real', Groups => { 2 => 'Location' } }, + Timestamp => { + Writable => 'integer', + Shift => 'Time', + Groups => { 2 => 'Time' }, + ValueConv => 'ConvertUnixTime($val / 1000, 1, 3)', + ValueConvInv => 'int(GetUnixTime($val, 1) * 1000)', + PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val,undef,1)', + }, +); +my %sEarthPose = ( + STRUCT_NAME => 'EarthPose', + NAMESPACE => { EarthPose => 'http://ns.google.com/photos/dd/1.0/earthpose/' }, + Latitude => { Writable => 'real', Groups => { 2 => 'Location' }, %latConv }, + Longitude => { Writable => 'real', Groups => { 2 => 'Location' }, %longConv }, + Altitude => { + Writable => 'real', + Groups => { 2 => 'Location' }, + PrintConv => '"$val m"', + PrintConvInv => '$val=~s/\s*m$//;$val', + }, + RotationX => { Writable => 'real', Groups => { 2 => 'Location' } }, + RotationY => { Writable => 'real', Groups => { 2 => 'Location' } }, + RotationZ => { Writable => 'real', Groups => { 2 => 'Location' } }, + RotationW => { Writable => 'real', Groups => { 2 => 'Location' } }, + Timestamp => { + Writable => 'integer', + Shift => 'Time', + Groups => { 2 => 'Time' }, + ValueConv => 'ConvertUnixTime($val / 1000, 1, 3)', + ValueConvInv => 'int(GetUnixTime($val, 1) * 1000)', + PrintConv => '$self->ConvertDateTime($val)', + PrintConvInv => '$self->InverseDateTime($val,undef,1)', + }, +); +my %sVendorInfo = ( + STRUCT_NAME => 'VendorInfo', + NAMESPACE => { VendorInfo => 'http://ns.google.com/photos/dd/1.0/vendorinfo/' }, + Model => { }, + Manufacturer => { }, + Notes => { }, +); +my %sAppInfo = ( + STRUCT_NAME => 'AppInfo', + NAMESPACE => { AppInfo => 'http://ns.google.com/photos/dd/1.0/appinfo/' }, + Application => { }, + Version => { }, + ItemURI => { }, +); + +# camera-raw defaults +%Image::ExifTool::XMP::crd = ( + %xmpTableDefaults, + INIT_TABLE => \&Init_crd, + GROUPS => { 1 => 'XMP-crd', 2 => 'Image' }, + NAMESPACE => 'crd', + AVOID => 1, + TABLE_DESC => 'Photoshop Camera Defaults namespace', + NOTES => 'Adobe Camera Raw Defaults tags.', + # (tags added dynamically when WRITE_PROC is called) +); # XMP Dynamic Media namespace properties (xmpDM) %Image::ExifTool::XMP::xmpDM = ( @@ -375,7 +450,7 @@ package Image::ExifTool::XMP; RatingScaleMaxValue => { FlatName => 'ScaleMaxValue' }, RatingValueLogoLink => { FlatName => 'ValueLogoLink' }, RatingRegion => { - FlatName => 'RatingRegion', + FlatName => 'Region', Struct => \%sLocationDetails, List => 'Bag', }, @@ -422,17 +497,52 @@ package Image::ExifTool::XMP; HeightPixels=> { Writable => 'integer' }, UsedVideoFrame => { Struct => \%sTimecode }, ); +my %sBoundaryPoint = ( # new in 1.5 + STRUCT_NAME => 'BoundaryPoint', + NAMESPACE => 'Iptc4xmpExt', + rbX => { FlatName => 'X', Writable => 'real' }, + rbY => { FlatName => 'Y', Writable => 'real' }, +); +my %sRegionBoundary = ( # new in 1.5 + STRUCT_NAME => 'RegionBoundary', + NAMESPACE => 'Iptc4xmpExt', + rbShape => { FlatName => 'Shape', PrintConv => { rectangle => 'Rectangle', circle => 'Circle', polygon => 'Polygon' } }, + rbUnit => { FlatName => 'Unit', PrintConv => { pixel => 'Pixel', relative => 'Relative' } }, + rbX => { FlatName => 'X', Writable => 'real' }, + rbY => { FlatName => 'Y', Writable => 'real' }, + rbW => { FlatName => 'W', Writable => 'real' }, + rbH => { FlatName => 'H', Writable => 'real' }, + rbRx => { FlatName => 'Rx', Writable => 'real' }, + rbVertices => { FlatName => 'Vertices', List => 'Seq', Struct => \%sBoundaryPoint }, +); +my %sImageRegion = ( # new in 1.5 + STRUCT_NAME => 'ImageRegion', + NAMESPACE => undef, # undefined to allow variable-namespace extensions + NOTES => q{ + This structure is new in the IPTC Extension version 1.5 specification. As + well as the fields defined below, this structure may contain any top-level + XMP tags, but since they aren't pre-defined the only way to add these tags + is to write ImageRegion as a structure with these tags as new fields. + }, + RegionBoundary => { Namespace => 'Iptc4xmpExt', FlatName => 'Boundary', Struct => \%sRegionBoundary }, + rId => { Namespace => 'Iptc4xmpExt', FlatName => 'ID' }, + Name => { Namespace => 'Iptc4xmpExt', Writable => 'lang-alt' }, + rCtype => { Namespace => 'Iptc4xmpExt', FlatName => 'Ctype', List => 'Bag', Struct => \%sEntity }, + rRole => { Namespace => 'Iptc4xmpExt', FlatName => 'Role', List => 'Bag', Struct => \%sEntity }, +); -# IPTC Extension namespace properties (Iptc4xmpExt) (ref 4) +# IPTC Extension namespace properties (Iptc4xmpExt) (ref 4, 14) %Image::ExifTool::XMP::iptcExt = ( %xmpTableDefaults, GROUPS => { 1 => 'XMP-iptcExt', 2 => 'Author' }, NAMESPACE => 'Iptc4xmpExt', TABLE_DESC => 'XMP IPTC Extension', NOTES => q{ - IPTC Extension namespace tags. The actual namespace prefix is - "Iptc4xmpExt", but ExifTool shortens this for the family 1 group name. (see - L<http://www.iptc.org/IPTC4XMP/>) + This table contains tags defined by the IPTC Extension schema version 1.6 + and IPTC Video Metadata version 1.3. The actual namespace prefix is + "Iptc4xmpExt", but ExifTool shortens this for the family 1 group name. (See + L<http://www.iptc.org/standards/photo-metadata/iptc-standard/> and + L<https://iptc.org/standards/video-metadata-hub/>.) }, AboutCvTerm => { Struct => \%sCVTermDetails, @@ -489,12 +599,13 @@ package Image::ExifTool::XMP; List => 'Bag', Notes => 'deprecated by version 1.2', }, - DigImageGUID => { Name => 'DigitalImageGUID' }, + DigImageGUID => { Groups => { 2 => 'Image' }, Name => 'DigitalImageGUID' }, DigitalSourcefileType => { Name => 'DigitalSourceFileType', Notes => 'now deprecated -- replaced by DigitalSourceType', + Groups => { 2 => 'Image' }, }, - DigitalSourceType => { Name => 'DigitalSourceType' }, + DigitalSourceType => { Name => 'DigitalSourceType', Groups => { 2 => 'Image' } }, EmbdEncRightsExpr => { Struct => { STRUCT_NAME => 'EEREDetails', @@ -537,8 +648,8 @@ package Image::ExifTool::XMP; Groups => { 2 => 'Location' }, List => 'Bag', }, - MaxAvailHeight => { Writable => 'integer' }, - MaxAvailWidth => { Writable => 'integer' }, + MaxAvailHeight => { Groups => { 2 => 'Image' }, Writable => 'integer' }, + MaxAvailWidth => { Groups => { 2 => 'Image' }, Writable => 'integer' }, ModelAge => { List => 'Bag', Writable => 'integer' }, OrganisationInImageCode => { List => 'Bag' }, OrganisationInImageName => { List => 'Bag' }, @@ -673,6 +784,7 @@ package Image::ExifTool::XMP; # new IPTC video metadata 1.2 properties # (ref http://www.iptc.org/std/videometadatahub/recommendation/IPTC-VideoMetadataHub-props-Rec_1.2.html) RecDevice => { + Groups => { 2 => 'Device' }, Struct => { STRUCT_NAME => 'Device', NAMESPACE => 'Iptc4xmpExt', @@ -684,7 +796,17 @@ package Image::ExifTool::XMP; }, }, PlanningRef => { List => 'Bag', Struct => \%sEntityWithRole }, - audioBitsPerSample => { Writable => 'integer' }, + audioBitsPerSample => { Groups => { 2 => 'Audio' }, Writable => 'integer' }, + # new IPTC video metadata 1.3 properties + # (ref https://iptc.org/std/videometadatahub/recommendation/IPTC-VideoMetadataHub-props-Rec_1.3.html) + metadataLastEdited => { Groups => { 2 => 'Time' }, %dateTimeInfo }, + metadataLastEditor => { Struct => \%sEntity }, + metadataAuthority => { Struct => \%sEntity }, + parentId => { Name => 'ParentID' }, + # new IPTC Extension schema 1.5 property + ImageRegion => { Groups => { 2 => 'Image' }, List => 'Bag', Struct => \%sImageRegion }, + # new Extension 1.6 property + EventId => { Name => 'EventID', List => 'Bag' }, ); #------------------------------------------------------------------------------ @@ -1116,7 +1238,7 @@ package Image::ExifTool::XMP; NAMESPACE => 'PixelLive', AVOID => 1, NOTES => q{ - PixelLive namespace tags. These tags are not writable becase they are very + PixelLive namespace tags. These tags are not writable because they are very uncommon and I haven't been able to locate a reference which gives the namespace URI. }, @@ -1174,15 +1296,15 @@ package Image::ExifTool::XMP; TagStructure => { Struct => \%sTagStruct, List => 'Bag' }, TagStructureLabelName => { Name => 'LabelName1', Flat => 1 }, TagStructureReference => { Name => 'Reference1', Flat => 1 }, - TagStructureSubLabels => { Name => 'SubLables1', Flat => 1 }, + TagStructureSubLabels => { Name => 'SubLabels1', Flat => 1 }, TagStructureParentReference => { Name => 'ParentReference1', Flat => 1 }, TagStructureSubLabelsLabelName => { Name => 'LabelName2', Flat => 1 }, TagStructureSubLabelsReference => { Name => 'Reference2', Flat => 1 }, - TagStructureSubLabelsSubLabels => { Name => 'SubLables2', Flat => 1 }, + TagStructureSubLabelsSubLabels => { Name => 'SubLabels2', Flat => 1 }, TagStructureSubLabelsParentReference => { Name => 'ParentReference2', Flat => 1 }, TagStructureSubLabelsSubLabelsLabelName => { Name => 'LabelName3', Flat => 1 }, TagStructureSubLabelsSubLabelsReference => { Name => 'Reference3', Flat => 1 }, - TagStructureSubLabelsSubLabelsSubLabels => { Name => 'SubLables3', Flat => 1 }, + TagStructureSubLabelsSubLabelsSubLabels => { Name => 'SubLabels3', Flat => 1 }, TagStructureSubLabelsSubLabelsParentReference => { Name => 'ParentReference3', Flat => 1 }, TagStructureSubLabelsSubLabelsSubLabelsLabelName => { Name => 'LabelName4', Flat => 1 }, TagStructureSubLabelsSubLabelsSubLabelsReference => { Name => 'Reference4', Flat => 1 }, @@ -1373,7 +1495,7 @@ package Image::ExifTool::XMP; ); # Microsoft ExpressionMedia namespace properties (expressionmedia) -# (ref http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,4235.0.html) +# (ref https://exiftool.org/forum/index.php/topic,4235.0.html) %Image::ExifTool::XMP::ExpressionMedia = ( %xmpTableDefaults, GROUPS => { 1 => 'XMP-expressionmedia', 2 => 'Image' }, @@ -1566,7 +1688,7 @@ package Image::ExifTool::XMP; ); # Google panorama namespace properties -# (ref http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,4569.0.html) +# (ref https://exiftool.org/forum/index.php/topic,4569.0.html) %Image::ExifTool::XMP::GPano = ( %xmpTableDefaults, GROUPS => { 1 => 'XMP-GPano', 2 => 'Image' }, @@ -1586,6 +1708,7 @@ package Image::ExifTool::XMP; InitialViewPitchDegrees => { Writable => 'real' }, InitialViewRollDegrees => { Writable => 'real' }, InitialHorizontalFOVDegrees => { Writable => 'real' }, + InitialVerticalFOVDegrees => { Writable => 'real' }, FirstPhotoDate => { %dateTimeInfo, Groups => { 2 => 'Time' } }, LastPhotoDate => { %dateTimeInfo, Groups => { 2 => 'Time' } }, SourcePhotosCount => { Writable => 'integer' }, @@ -1608,11 +1731,13 @@ package Image::ExifTool::XMP; %Image::ExifTool::XMP::GSpherical = ( %xmpTableDefaults, GROUPS => { 1 => 'XMP-GSpherical', 2 => 'Image' }, + WRITE_GROUP => 'GSpherical', # write in special location for video files NAMESPACE => 'GSpherical', AVOID => 1, NOTES => q{ Not actually XMP. These RDF/XML tags are used in Google spherical MP4 - videos. See + videos. These tags are written into the video track of MOV/MP4 files, and + not at the top level like other XMP tags. See L<https://github.com/google/spatial-media/blob/master/docs/spherical-video-rfc.md> for the specification. }, @@ -1647,8 +1772,8 @@ package Image::ExifTool::XMP; # Google depthmap information (ref https://developers.google.com/depthmap-metadata/reference) %Image::ExifTool::XMP::GDepth = ( GROUPS => { 0 => 'XMP', 1 => 'XMP-GDepth', 2 => 'Image' }, - NAMESPACE => { 'GDepth' => 'http://ns.google.com/photos/1.0/depthmap/' }, - AVOID => 1, # (too potential tag name conflicts) + NAMESPACE => 'GDepth', + AVOID => 1, # (too many potential tag name conflicts) NOTES => q{ Google depthmap information. See L<https://developers.google.com/depthmap-metadata/> for the specification. @@ -1665,6 +1790,7 @@ package Image::ExifTool::XMP; Far => { Writable => 'real' }, Mime => { }, Data => { + Name => 'DepthImage', ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)', ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)', }, @@ -1699,6 +1825,198 @@ package Image::ExifTool::XMP; FocalPointY => { Writable => 'real' }, ); +# Google camera namespace (ref PH) +%Image::ExifTool::XMP::GCamera = ( + %xmpTableDefaults, + GROUPS => { 1 => 'XMP-GCamera', 2 => 'Camera' }, + NAMESPACE => 'GCamera', + NOTES => 'Camera information found in Google panorama images.', + BurstID => { }, + BurstPrimary => { }, + PortraitNote => { }, + PortraitRequest => { + Notes => 'High Definition Render Pipeline (HDRP) data', #PH (guess) + ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)', + ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)', + }, + PortraitVersion => { }, + SpecialTypeID => { List => 'Bag' }, + PortraitNote => { }, + DisableAutoCreation => { List => 'Bag' }, + hdrp_makernote => { + Name => 'HDRPMakerNote', + # decoded data starts with the following bytes, but nothing yet is known about its contents: + # 48 44 52 50 02 ef 64 35 6d 5e 70 1e 2c ea e3 4c [HDRP..d5m^p.,..L] + ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)', + ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)', + }, + MicroVideo => { Writable => 'integer' }, + MicroVideoVersion => { Writable => 'integer' }, + MicroVideoOffset => { Writable => 'integer' }, + MicroVideoPresentationTimestampUs => { Writable => 'integer' }, +); + +# Google creations namespace (ref PH) +%Image::ExifTool::XMP::GCreations = ( + %xmpTableDefaults, + GROUPS => { 1 => 'XMP-GCreations', 2 => 'Camera' }, + NAMESPACE => 'GCreations', + NOTES => 'Google creations tags.', + CameraBurstID => { }, +); + +# Google depth-map Device namespace (ref 13) +%Image::ExifTool::XMP::Device = ( + %xmpTableDefaults, + GROUPS => { 1 => 'XMP-Device', 2 => 'Camera' }, + NAMESPACE => { Device => 'http://ns.google.com/photos/dd/1.0/device/' }, + NOTES => q{ + Google depth-map Device tags. See + L<https://developer.android.com/training/camera2/Dynamic-depth-v1.0.pdf> for + the specification. + }, + Container => { + Struct => { + STRUCT_NAME => 'DeviceContainer', + NAMESPACE => { Container => 'http://ns.google.com/photos/dd/1.0/container/' }, + Directory => { + List => 'Seq', + Struct => { + STRUCT_NAME => 'DeviceDirectory', + NAMESPACE => { Container => 'http://ns.google.com/photos/dd/1.0/container/' }, + Item => { + Struct => { + STRUCT_NAME => 'DeviceItem', + NAMESPACE => { Item => 'http://ns.google.com/photos/dd/1.0/item/' }, + Mime => { }, + Length => { Writable => 'integer' }, + Padding => { Writable => 'integer' }, + DataURI => { }, + }, + }, + }, + } + }, + }, + Profiles => { + List => 'Seq', + FlatName => '', + Struct => { + STRUCT_NAME => 'DeviceProfiles', + NAMESPACE => { Device => 'http://ns.google.com/photos/dd/1.0/device/' }, + Profile => { + Struct => { + STRUCT_NAME => 'DeviceProfile', + NAMESPACE => { Profile => 'http://ns.google.com/photos/dd/1.0/profile/' }, + CameraIndices => { List => 'Seq', Writable => 'integer' }, + Type => { }, + }, + }, + }, + }, + Cameras => { + List => 'Seq', + FlatName => '', + Struct => { + STRUCT_NAME => 'DeviceCameras', + NAMESPACE => { Device => 'http://ns.google.com/photos/dd/1.0/device/' }, + Camera => { + Struct => { + STRUCT_NAME => 'DeviceCamera', + NAMESPACE => { Camera => 'http://ns.google.com/photos/dd/1.0/camera/' }, + DepthMap => { + Struct => { + STRUCT_NAME => 'DeviceDepthMap', + NAMESPACE => { DepthMap => 'http://ns.google.com/photos/dd/1.0/depthmap/' }, + ConfidenceURI => { }, + DepthURI => { }, + Far => { Writable => 'real' }, + Format => { }, + ItemSemantic=> { }, + MeasureType => { }, + Near => { Writable => 'real' }, + Units => { }, + Software => { }, + FocalTableEntryCount => { Writable => 'integer' }, + FocalTable => { }, # (base64) + }, + }, + Image => { + Struct => { + STRUCT_NAME => 'DeviceImage', + NAMESPACE => { Image => 'http://ns.google.com/photos/dd/1.0/image/' }, + ItemSemantic=> { }, + ItemURI => { }, + }, + }, + ImagingModel => { + Struct => { + STRUCT_NAME => 'DeviceImagingModel', + NAMESPACE => { ImagingModel => 'http://ns.google.com/photos/dd/1.0/imagingmodel/' }, + Distortion => { }, # (base64) + DistortionCount => { Writable => 'integer' }, + FocalLengthX => { Writable => 'real' }, + FocalLengthY => { Writable => 'real' }, + ImageHeight => { Writable => 'integer' }, + ImageWidth => { Writable => 'integer' }, + PixelAspectRatio=> { Writable => 'real' }, + PrincipalPointX => { Writable => 'real' }, + PrincipalPointY => { Writable => 'real' }, + Skew => { Writable => 'real' }, + }, + }, + PointCloud => { + Struct => { + STRUCT_NAME => 'DevicePointCloud', + NAMESPACE => { PointCloud => 'http://ns.google.com/photos/dd/1.0/pointcloud/' }, + PointCloud => { Writable => 'integer' }, + Points => { }, + Metric => { Writable => 'boolean' }, + }, + }, + Pose => { Struct => \%sPose }, + LightEstimate => { + Struct => { + STRUCT_NAME => 'DeviceLightEstimate', + NAMESPACE => { LightEstimate => 'http://ns.google.com/photos/dd/1.0/lightestimate/' }, + ColorCorrectionR => { Writable => 'real' }, + ColorCorrectionG => { Writable => 'real' }, + ColorCorrectionB => { Writable => 'real' }, + PixelIntensity => { Writable => 'real' }, + }, + }, + VendorInfo => { Struct => \%sVendorInfo }, + AppInfo => { Struct => \%sAppInfo }, + Trait => { }, + }, + }, + }, + }, + VendorInfo => { Struct => \%sVendorInfo }, + AppInfo => { Struct => \%sAppInfo }, + EarthPos => { Struct => \%sEarthPose }, + Pose => { Struct => \%sPose }, + Planes => { + List => 'Seq', + FlatName => '', + Struct => { + STRUCT_NAME => 'DevicePlanes', + NAMESPACE => { Device => 'http://ns.google.com/photos/dd/1.0/device/' }, + Plane => { + Struct => { + STRUCT_NAME => 'DevicePlane', + NAMESPACE => { Plane => 'http://ns.google.com/photos/dd/1.0/plane/' }, + Pose => { Struct => \%sPose }, + ExtentX => { Writable => 'real' }, + ExtentZ => { Writable => 'real' }, + BoundaryVertexCount => { Writable => 'integer' }, + Boundary => { }, + }, + }, + }, + }, +); + # Getty Images namespace (ref PH) %Image::ExifTool::XMP::GettyImages = ( %xmpTableDefaults, @@ -1709,7 +2027,7 @@ package Image::ExifTool::XMP; prefix recorded in the file, but ExifTool shortens this for the family 1 group name. }, - Personality => { }, + Personality => { List => 'Bag' }, OriginalFilename => { Name => 'OriginalFileName' }, ParentMEID => { }, # the following from StarGeek @@ -1742,6 +2060,7 @@ package Image::ExifTool::XMP; MinorVersion => { }, RightAlbedo => { Notes => 'Right stereoscopic image', + Groups => { 2 => 'Preview' }, ValueConv => 'Image::ExifTool::XMP::DecodeBase64($val)', ValueConvInv => 'Image::ExifTool::XMP::EncodeBase64($val)', }, @@ -1779,6 +2098,23 @@ package Image::ExifTool::XMP; NAMESPACE => undef, # variable namespace ); +#------------------------------------------------------------------------------ +# Generate crd tags +# Inputs: 0) tag table ref +sub Init_crd($) +{ + my $tagTablePtr = shift; + # import tags from CRS namespace + my $crsTable = GetTagTable('Image::ExifTool::XMP::crs'); + my $tag; + foreach $tag (Image::ExifTool::TagTableKeys($crsTable)) { + my $crsInfo = $$crsTable{$tag}; + my $tagInfo = $$tagTablePtr{$tag} = { %$crsInfo }; + $$tagInfo{Groups} = { 0 => 'XMP', 1 => 'XMP-crd' , 2 => $$crsInfo{Groups}{2} } if $$crsInfo{Groups}; + } +} + + 1; #end __END__ @@ -1797,7 +2133,7 @@ =head1 DESCRIPTION =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/XMPStruct.pl b/src/Image-ExifTool/lib/Image/ExifTool/XMPStruct.pl index 570e98f0..edb4654c 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/XMPStruct.pl +++ b/src/Image-ExifTool/lib/Image/ExifTool/XMPStruct.pl @@ -32,7 +32,9 @@ ($;$) my ($key, $val, @vals, $rtnVal); if (ref $obj eq 'HASH') { - foreach $key (sort keys %$obj) { + # support hashes with ordered keys + my @keys = $$obj{_ordered_keys_} ? @{$$obj{_ordered_keys_}} : sort keys %$obj; + foreach $key (@keys) { push @vals, $key . '=' . SerializeStruct($$obj{$key}, '}'); } $rtnVal = '{' . join(',', @vals) . '}'; @@ -107,7 +109,8 @@ ($;$) $val = ''; $delim = $delim ? "\\$delim|,|\\||\$" : ',|\\||$'; for (;;) { - $$obj =~ s/^(.*?)($delim)//s and $val .= $1; + $$obj =~ s/^(.*?)($delim)//s or last; + $val .= $1; last unless $2; $2 eq '|' or $$obj = $2 . $$obj, last; $$obj =~ s/^(.)//s and $val .= $1; # add escaped character @@ -232,7 +235,7 @@ ($$$) # create new structure field if necessary $fieldInfo or $fieldInfo = $$strTable{$tag} = { %$tagInfo, # (also copies the necessary TagID and PropertyPath) - Namespace => $$tagInfo{Table}{NAMESPACE}, + Namespace => $$tagInfo{Namespace} || $$tagInfo{Table}{NAMESPACE}, LangCode => $langCode, }; # delete stuff we don't need (shouldn't cause harm, but better safe than sorry) @@ -397,7 +400,11 @@ ($$$$$) my $verbose = $et->Options('Verbose'); @delPaths = sort @delPaths if $verbose > 1; foreach $p (@delPaths) { - $et->VerboseValue("- XMP-$p", $$capture{$p}[0]) if $verbose > 1; + if ($verbose > 1) { + my $p2 = $p; + $p2 =~ s/^(\w+)/$stdXlatNS{$1} || $1/e; + $et->VerboseValue("- XMP-$p2", $$capture{$p}[0]); + } delete $$capture{$p}; $deleted = 1; ++$$changed; @@ -461,7 +468,9 @@ ($$$$$$) $$capture{$path} = [ $val, \%attrs ]; # print verbose message if ($et and $et->Options('Verbose') > 1) { - $et->VerboseValue("+ XMP-$path", $val); + my $p = $path; + $p =~ s/^(\w+)/$stdXlatNS{$1} || $1/e; + $et->VerboseValue("+ XMP-$p", $val); } } @@ -512,6 +521,7 @@ ($$$$$$) next unless $$fieldInfo{List}; my $i = 0; my ($item, $p); + my $level = scalar(() = ($propPath =~ / \d+/g)); # loop through all list items (note: can't yet write multi-dimensional lists) foreach $item (@{$val}) { if ($i) { @@ -526,7 +536,8 @@ ($$$$$$) if (ref $item eq 'HASH') { my $subStruct = $$fieldInfo{Struct} or next; AddNewStruct($et, $tagInfo, $capture, $p, $item, $subStruct) or next; - } elsif (length $item) { # don't write empty items in list + # don't write empty items in upper-level list + } elsif (length $item or (defined $item and $level == 1)) { AddNewTag($et, $fieldInfo, $capture, $p, \$item, \%langIdx); $addedTag = 1; } @@ -550,7 +561,11 @@ ($$$$$$) my $path = $basePath . '/' . ConformPathToNamespace($et, "rdf:type"); unless ($$capture{$path}) { $$capture{$path} = [ '', { 'rdf:resource' => $$strTable{TYPE} } ]; - $et->VerboseValue("+ XMP-$path", $$strTable{TYPE}) if $verbose > 1; + if ($verbose > 1) { + my $p = $path; + $p =~ s/^(\w+)/$stdXlatNS{$1} || $1/e; + $et->VerboseValue("+ XMP-$p", $$strTable{TYPE}); + } } } return $changed; @@ -619,14 +634,14 @@ ($;$) local $_; my ($et, $keepFlat) = @_; my ($key, %structs, %var, %lists, $si, %listKeys, @siList); - my $ex = $$et{TAG_EXTRA}; my $valueHash = $$et{VALUE}; + my $fileOrder = $$et{FILE_ORDER}; my $tagExtra = $$et{TAG_EXTRA}; foreach $key (keys %{$$et{TAG_INFO}}) { - $$ex{$key} or next; - my $structProps = $$ex{$key}{Struct} or next; - delete $$ex{$key}{Struct}; # (don't re-use) - my $tagInfo = $$et{TAG_INFO}{$key}; # tagInfo for flattened tag + $$tagExtra{$key} or next; + my $structProps = $$tagExtra{$key}{Struct} or next; + delete $$tagExtra{$key}{Struct}; # (don't re-use) + my $tagInfo = $$et{TAG_INFO}{$key}; # tagInfo for flattened tag my $table = $$tagInfo{Table}; my $prop = shift @$structProps; my $tag = $$prop[0]; @@ -764,7 +779,13 @@ ($;$) # everything else, and this is really what we care about) my $k = $listKeys{$oldStruct}; if ($k) { # ($k will be undef for an empty structure) - $k lt $key and $et->DeleteTag($key), next; + if ($k lt $key) { + # keep lowest file order + $$fileOrder{$k} = $$fileOrder{$key} if $$fileOrder{$k} > $$fileOrder{$key}; + $et->DeleteTag($key); + next; + } + $$fileOrder{$key} = $$fileOrder{$k} if $$fileOrder{$key} > $$fileOrder{$k}; $et->DeleteTag($k); # remove tag with greater copy number } } @@ -775,11 +796,11 @@ ($;$) # save strInfo ref and file order if ($var{$strInfo}) { # set file order to just before the first associated flattened tag - if ($var{$strInfo}[1] > $$et{FILE_ORDER}{$key}) { - $var{$strInfo}[1] = $$et{FILE_ORDER}{$key} - 0.5; + if ($var{$strInfo}[1] > $$fileOrder{$key}) { + $var{$strInfo}[1] = $$fileOrder{$key} - 0.5; } } else { - $var{$strInfo} = [ $strInfo, $$et{FILE_ORDER}{$key} - 0.5 ]; + $var{$strInfo} = [ $strInfo, $$fileOrder{$key} - 0.5 ]; } # preserve original flattened tags if requested if ($keepFlat) { @@ -807,9 +828,24 @@ ($;$) $var{$_} and push @siList, $_ foreach keys %structs; # save new structures in the same order they were read from file foreach $si (sort { $var{$a}[1] <=> $var{$b}[1] } @siList) { - $key = $et->FoundTag($var{$si}[0], ''); - $$valueHash{$key} = $structs{$si}; - $$et{FILE_ORDER}{$key} = $var{$si}[1]; + # test to see if a tag for this structure has already been generated + # (this could happen only if one of the structures in a list was empty) + $key = $var{$si}[0]{Name}; + my $found; + if ($$valueHash{$key}) { + my @keys = grep /^$key( \(\d+\))?$/, keys %$valueHash; + foreach $key (@keys) { + next unless $$valueHash{$key} eq $structs{$si}; + $found = 1; + last; + } + } + unless ($found) { + # otherwise, generate a new tag for this structure + $key = $et->FoundTag($var{$si}[0], ''); + $$valueHash{$key} = $structs{$si}; + } + $$fileOrder{$key} = $var{$si}[1]; } } @@ -833,7 +869,7 @@ =head1 DESCRIPTION =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/ZIP.pm b/src/Image-ExifTool/lib/Image/ExifTool/ZIP.pm index a822d277..e6ecab5e 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/ZIP.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/ZIP.pm @@ -19,7 +19,7 @@ use strict; use vars qw($VERSION $warnString); use Image::ExifTool qw(:DataAccess :Utils); -$VERSION = '1.23'; +$VERSION = '1.27'; sub WarnProc($) { $warnString = $_[0]; } @@ -43,6 +43,14 @@ my %iWorkFile = ( 'Index/Tables/DataList.iwa' => 'NUMBERS', ); +my %iWorkType = ( + NUMBERS => 'NUMBERS', + PAGES => 'PAGES', + KEY => 'KEY', + KTH => 'KTH', + NMBTEMPLATE => 'NMBTEMPLATE', +); + # ZIP metadata blocks %Image::ExifTool::ZIP::Main = ( PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, @@ -117,6 +125,7 @@ my %iWorkFile = ( Name => 'ZipFileName', Format => 'string[$$self{ZipFileNameLength}]', }, + _com => 'ZipFileComment', ); # GNU ZIP tags (ref 3) @@ -274,7 +283,7 @@ sub ProcessRAR($$) last if $size < 0; next unless $size; # ignore blocks with no data # don't try to read very large blocks unless LargeFileSupport is enabled - if ($size > 0x80000000 and not $et->Options('LargeFileSupport')) { + if ($size >= 0x80000000 and not $et->Options('LargeFileSupport')) { $et->Warn('Large block encountered. Aborting.'); last; } @@ -300,6 +309,9 @@ sub ProcessRAR($$) $raf->Seek($size, 1) or last if $size; } $$et{DOC_NUM} = 0; + if ($docNum > 1 and not $et->Options('Duplicates')) { + $et->Warn("Use the Duplicates option to extract tags for all $docNum files", 1); + } return 1; } @@ -369,6 +381,8 @@ sub HandleMember($$;$) $et->HandleTag($tagTablePtr, 9, $member->compressedSize()); $et->HandleTag($tagTablePtr, 11, $member->uncompressedSize()); $et->HandleTag($tagTablePtr, 15, $member->fileName()); + my $com = $member->fileComment(); + $et->HandleTag($tagTablePtr, '_com', $com) if defined $com and length $com; } #------------------------------------------------------------------------------ @@ -379,13 +393,14 @@ sub ProcessZIP($$) { my ($et, $dirInfo) = @_; my $raf = $$dirInfo{RAF}; - my ($buff, $buf2, $zip, $docNum); + my ($buff, $buf2, $zip); return 0 unless $raf->Read($buff, 30) == 30 and $buff =~ /^PK\x03\x04/; my $tagTablePtr = GetTagTable('Image::ExifTool::ZIP::Main'); + my $docNum = 0; - # use Archive::Zip if avilable + # use Archive::Zip if available for (;;) { unless (eval { require Archive::Zip } and eval { require IO::File }) { if ($$et{FILE_EXT} and $$et{FILE_EXT} ne 'ZIP') { @@ -436,15 +451,26 @@ sub ProcessZIP($$) $et->Warn("$err reading ZIP file"); last; } + # extract zip file comment + my $comment = $zip->zipfileComment(); + $et->FoundTag(Comment => $comment) if defined $comment and length $comment; + $$dirInfo{ZIP} = $zip; # check for an Office Open file (DOCX, etc) # --> read '[Content_Types].xml' to determine the file type - my ($mime, @members, $epub); + my ($mime, @members); my $cType = $zip->memberNamed('[Content_Types].xml'); if ($cType) { ($buff, $status) = $zip->contents($cType); - if (not $status and $buff =~ /ContentType\s*=\s*(['"])([^"']+)\.main(\+xml)?\1/) { + if (not $status and ( + # first look for the main document with the expected name + $buff =~ m{\sPartName\s*=\s*['"](?:/ppt/presentation.xml|/word/document.xml|/xl/workbook.xml)['"][^>]*\sContentType\s*=\s*(['"])([^"']+)\.main(\+xml)?\1} or + # then look for the main part + $buff =~ /<Override[^>]*\sPartName[^<]+\sContentType\s*=\s*(['"])([^"']+)\.main(\+xml)?\1/ or + # and if all else fails, use the default main + $buff =~ /ContentType\s*=\s*(['"])([^"']+)\.main(\+xml)?\1/)) + { $mime = $2; } } @@ -558,7 +584,6 @@ sub ProcessZIP($$) # otherwise just extract general ZIP information $et->SetFileType(); @members = $zip->members(); - $docNum = 0; my ($member, $iWorkType); # special files to extract my %extract = ( @@ -587,7 +612,8 @@ sub ProcessZIP($$) $et->FoundTag($extract{$file} => $buff); } } elsif ($file eq 'Index/Document.iwa' and not $iWorkType) { - $iWorkType = 'PAGES'; + my $type = $iWorkType{$$et{FILE_EXT} || ''}; + $iWorkType = $type || 'PAGES'; } elsif ($iWorkFile{$file}) { $iWorkType = $iWorkFile{$file}; } @@ -599,12 +625,14 @@ sub ProcessZIP($$) if ($zip) { delete $$dirInfo{ZIP}; delete $$et{DOC_NUM}; + if ($docNum > 1 and not $et->Options('Duplicates')) { + $et->Warn("Use the Duplicates option to extract tags for all $docNum files", 1); + } return 1; } # # process the ZIP file by hand (funny, but this seems easier than using Archive::Zip) # - $docNum = 0; $et->VPrint(1, " -- processing as binary data --\n"); $raf->Seek(30, 0); $et->SetFileType(); @@ -634,6 +662,7 @@ sub ProcessZIP($$) DataLen => 30 + $len, DirStart => 0, DirLen => 30 + $len, + MixedTags => 1, # (to ignore FileComment tag) ); $et->ProcessDirectory(\%dirInfo, $tagTablePtr); my $flags = Get16u(\$buff, 6); @@ -650,6 +679,9 @@ sub ProcessZIP($$) $raf->Read($buff, 30) == 30 and $buff =~ /^PK\x03\x04/ or last; } delete $$et{DOC_NUM}; + if ($docNum > 1 and not $et->Options('Duplicates')) { + $et->Warn("Use the Duplicates option to extract tags for all $docNum files", 1); + } return 1; } @@ -676,7 +708,7 @@ Electronic Publication (EPUB), and Sketch design files (SKETCH). =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. diff --git a/src/Image-ExifTool/lib/Image/ExifTool/ZISRAW.pm b/src/Image-ExifTool/lib/Image/ExifTool/ZISRAW.pm new file mode 100644 index 00000000..19397829 --- /dev/null +++ b/src/Image-ExifTool/lib/Image/ExifTool/ZISRAW.pm @@ -0,0 +1,242 @@ +#------------------------------------------------------------------------------ +# File: ZISRAW.pm +# +# Description: Read ZISRAW (CZI) meta information +# +# Revisions: 2020-08-07 - P. Harvey Created +# +# References: 1) https://www.zeiss.com/microscopy/us/products/microscope-software/zen/czi.html +#------------------------------------------------------------------------------ + +package Image::ExifTool::ZISRAW; + +use strict; +use vars qw($VERSION); +use Image::ExifTool qw(:DataAccess :Utils); + +$VERSION = '1.01'; + +%Image::ExifTool::ZISRAW::Main = ( + PROCESS_PROC => \&Image::ExifTool::ProcessBinaryData, + GROUPS => { 0 => 'File', 1 => 'File', 2 => 'Image' }, + NOTES => q{ + As well as the header information listed below, ExifTool also extracts the + top-level XML-based metadata from Zeiss Integrated Software RAW (ZISRAW) CZI + files. + }, + 0x20 => { + Name => 'ZISRAWVersion', + Format => 'int32u[2]', + PrintConv => '$val =~ tr/ /./; $val', + }, + 0x30 => { + Name => 'PrimaryFileGUID', + Format => 'undef[16]', + ValueConv => 'unpack("H*",$val)', + }, + 0x40 => { + Name => 'FileGUID', + Format => 'undef[16]', + ValueConv => 'unpack("H*",$val)', + }, +); + +#------------------------------------------------------------------------------ +# Shorten obscenely long CZI tag names +# Inputs: Tag name +# Returns: Shortened tag name +sub ShortenTagNames($) +{ + local $_; + $_ = shift; + s/^HardwareSetting//; + s/^DevicesDevice/Device/; + s/LightPathNode//g; + s/Successors//g; + s/ExperimentExperiment/Experiment/g; + s/ObjectivesObjective/Objective/; + s/ChannelsChannel/Channel/; + s/TubeLensesTubeLens/TubeLens/; + s/^ExperimentHardwareSettingsPoolHardwareSetting/HardwareSetting/; + s/SharpnessMeasureSetSharpnessMeasure/Sharpness/; + s/FocusSetupAutofocusSetup/Autofocus/; + s/TracksTrack/Track/; + s/ChannelRefsChannelRef/ChannelRef/; + s/ChangerChanger/Changer/; + s/ElementsChangerElement/Changer/; + s/ChangerElements/Changer/; + s/ContrastChangerContrast/Contrast/; + s/KeyFunctionsKeyFunction/KeyFunction/; + s/ManagerContrastManager(Contrast)?/ManagerContrast/; + s/ObjectiveChangerObjective/ObjectiveChanger/; + s/ManagerLightManager/ManagerLight/; + s/WavelengthAreasWavelengthArea/WavelengthArea/; + s/ReflectorChangerReflector/ReflectorChanger/; + s/^StageStageAxesStageAxis/StageAxis/; + s/ShutterChangerShutter/ShutterChanger/; + s/OnOffChangerOnOff/OnOffChanger/; + s/UnsharpMaskStateUnsharpMask/UnsharpMask/; + s/Acquisition/Acq/; + s/Continuous/Cont/; + s/Resolution/Res/; + s/Experiment/Expt/g; + s/Threshold/Thresh/; + s/Reference/Ref/; + s/Magnification/Mag/; + s/Original/Orig/; + s/FocusSetupFocusStrategySetup/Focus/; + s/ParametersParameter/Parameter/; + s/IntervalInfo/Interval/; + s/ExptBlocksAcqBlock/AcqBlock/; + s/MicroscopesMicroscope/Microscope/; + s/TimeSeriesInterval/TimeSeries/; + s/Interval(.*Interval)/$1/; + s/SingleTileRegionsSingleTileRegion/SingleTileRegion/; + s/AcquisitionMode//; + s/DetectorsDetector/Detector/; + s/Setup//; + s/Setting//; + s/TrackTrack/Track/; + s/AnalogOutMaximumsAnalogOutMaximum/AnalogOutMaximum/; + s/AnalogOutMinimumsAnalogOutMinimum/AnalogOutMinimum/; + s/DigitalOutLabelsDigitalOutLabelLabel/DigitalOutLabelLabel/; + s/(VivaTomeOpticalSectionInformation)+VivaTomeOpticalSectionInformation/VivaTomeOpticalSectionInformation/; + s/FocusDefiniteFocus/FocusDefinite/; + s/ChangerChanger/Changer/; + s/Calibration/Cal/; + s/LightSwitchChangerRLTLSwitch/LightSwitchChangerRLTL/; + s/Parameters//; + s/Fluorescence/Fluor/; + s/CameraGeometryCameraGeometry/CameraGeometry/; + s/CameraCamera/Camera/; + s/DetectorsCamera/Camera/; + s/FilterChangerLeftChangerEmissionFilter/LeftChangerEmissionFilter/; + s/SwitchingStatesSwitchingState/SwitchingState/; + s/Information/Info/; + s/SubDimensions?//g; + s/Setups?//; + s/Parameters?//; + s/Calculate/Calc/; + s/Visibility/Vis/; + s/Orientation/Orient/; + s/ListItems/Items/; + s/Increment/Incr/; + s/Parameter/Param/; + s/(ParfocalParcentralValues)+ParfocalParcentralValue/Parcentral/; + s/ParcentralParcentral/Parcentral/; + s/CorrFocusCorrection/FocusCorr/; + s/(ApoTomeDepthInfo)+Element/ApoTomeDepth/; + s/(ApoTomeClickStopInfo)+Element/ApoTomeClickStop/; + s/DepthDepth/Depth/; + s/(Devices?)+Device/Device/; + s/(BeamPathNode)+/BeamPathNode/; + s/BeamPathsBeamPath/BeamPath/g; + s/BeamPathBeamPath/BeamPath/g; + s/Configuration/Config/; + s/StageAxesStageAxis/StageAxis/; + s/RangesRange/Range/; + s/DataGridDatasGridData(Grid)?/DataGrid/; + s/DataMicroscopeDatasMicroscopeData(Microscope)?/DataMicroscope/; + s/DataWegaDatasWegaData/DataWega/; + s/ClickStopPositionsClickStopPosition/ClickStopPosition/; + s/LightSourcess?LightSource(Settings)?(LightSource)?/LightSource/; + s/FilterSetsFilterSet/FilterSet/; + s/EmissionFiltersEmissionFilter/EmissionFilter/; + s/ExcitationFiltersExcitationFilter/ExcitationFilter/; + s/FiltersFilter/Filter/; + s/DichroicsDichroic/Dichronic/; + s/WavelengthsWavelength/Wavelength/; + s/MultiTrackSetup/MultiTrack/; + s/TrackTrack/Track/; + s/DataGrabberSetup/DataGrabber/; + s/CameraFrameSetup/CameraFrame/; + s/TimeSeries(TimeSeries|Setups)/TimeSeries/; + s/FocusFocus/Focus/; + s/FocusAutofocus/Autofocus/; + s/Focus(Hardware|Software)(Autofocus)+/Autofocus$1/; + s/AutofocusAutofocus/Autofocus/; + return $_; +} + +#------------------------------------------------------------------------------ +# Extract metadata from a ZISRAW (CZI) image +# Inputs: 0) ExifTool object reference, 1) dirInfo reference +# Returns: 1 on success, 0 if this wasn't a valid CZI file +sub ProcessCZI($$) +{ + my ($et, $dirInfo) = @_; + my $raf = $$dirInfo{RAF}; + my ($buff, $tagTablePtr); + + # verify this is a valid CZI file + return 0 unless $raf->Read($buff, 100) == 100; + return 0 unless $buff =~ /^ZISRAWFILE\0{6}/; + $et->SetFileType(); + SetByteOrder('II'); + my %dirInfo = ( + DataPt => \$buff, + DirStart => 0, + DirLen => length($buff), + ); + $tagTablePtr = GetTagTable('Image::ExifTool::ZISRAW::Main'); + $et->ProcessDirectory(\%dirInfo, $tagTablePtr); + + # read the metadata section + my $pos = Get64u(\$buff, 92) or return 1; + $raf->Seek($pos, 0) or $et->Warn('Error seeking to metadata'), return 0; + $raf->Read($buff, 288) == 288 or $et->Warn('Error reading metadata header'), return 0; + $buff =~ /^ZISRAWMETADATA\0\0/ or $et->Warn('Invalid metadata header'), return 0; + my $len = Get32u(\$buff, 32); + $len < 200000000 or $et->Warn('Metadata section too large. Ignoring'), return 0; + $raf->Read($buff, $len) or $et->Warn('Error reading XML metadata'), return 0; + $et->FoundTag('XML', $buff); # extract as a block + $tagTablePtr = GetTagTable('Image::ExifTool::XMP::XML'); + $dirInfo{DirLen} = length $buff; + # shorten tag names somewhat by removing 'ImageDocumentMetadata' prefix from all + $$et{XmpIgnoreProps} = [ 'ImageDocument', 'Metadata', 'Information' ]; + $$et{ShortenXmpTags} = \&ShortenTagNames; + + $et->ProcessDirectory(\%dirInfo, $tagTablePtr); + + return 1; +} + +1; # end + +__END__ + +=head1 NAME + +Image::ExifTool::ZISRAW - Read ZISRAW (CZI) meta information + +=head1 SYNOPSIS + +This module is used by Image::ExifTool + +=head1 DESCRIPTION + +This module contains definitions required by Image::ExifTool to read +metadata from Zeiss Integrated Software RAW (ZISRAW) CZI files. + +=head1 AUTHOR + +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) + +This library is free software; you can redistribute it and/or modify it +under the same terms as Perl itself. + +=head1 REFERENCES + +=over 4 + +=item L<https://www.zeiss.com/microscopy/us/products/microscope-software/zen/czi.html> + +=back + +=head1 SEE ALSO + +L<Image::ExifTool::TagNames/ZISRAW Tags>, +L<Image::ExifTool(3pm)|Image::ExifTool> + +=cut + diff --git a/src/Image-ExifTool/lib/Image/ExifTool/iWork.pm b/src/Image-ExifTool/lib/Image/ExifTool/iWork.pm index be5310d8..74d2fdb2 100644 --- a/src/Image-ExifTool/lib/Image/ExifTool/iWork.pm +++ b/src/Image-ExifTool/lib/Image/ExifTool/iWork.pm @@ -14,7 +14,7 @@ use Image::ExifTool qw(:DataAccess :Utils); use Image::ExifTool::XMP; use Image::ExifTool::ZIP; -$VERSION = '1.05'; +$VERSION = '1.06'; # test for recognized iWork document extensions and outer XML elements my %iWorkType = ( @@ -70,7 +70,7 @@ sub GetTagID($) { my $props = shift; return 0 if $$props[-1] =~ /^\w+:ID$/; # ignore ID tags - return ($$props[0] =~ /^.*?:(.*)/) ? $1 : $$props[0]; + return $$props[0] =~ /^.*?:(.*)/ ? $1 : $$props[0]; } #------------------------------------------------------------------------------ @@ -155,7 +155,7 @@ sub Process_iWork($$) Image::ExifTool::ZIP::HandleMember($et, $member); # process only the index XML and JPEG thumbnail/preview files - next unless $file =~ m{^(index\.(xml|apxl)|QuickLook/Thumbnail\.jpg|[^/]+/preview.jpg)$}i; + next unless $file =~ m{^(index\.(xml|apxl)|QuickLook/Thumbnail\.jpg|[^/]+/preview(-micro|-web)?.jpg)$}i; # get the file contents if necessary # (CAREFUL! $buff MUST be local since we hand off a value ref to PreviewImage) my ($buff, $buffPt); @@ -169,7 +169,8 @@ sub Process_iWork($$) } # extract JPEG as PreviewImage (should only be QuickLook/Thumbnail.jpg) if ($file =~ /\.jpg$/) { - $et->FoundTag('PreviewImage', $buffPt); + my $type = ($file =~ /preview-(\w+)/) ? ($1 eq 'web' ? 'Other' : 'Thumbnail') : 'Preview'; + $et->FoundTag($type . 'Image', $buffPt); next; } # process "metadata" section of XML index file @@ -214,7 +215,7 @@ information from Apple iWork '09 XML+ZIP files. =head1 AUTHOR -Copyright 2003-2018, Phil Harvey (phil at owl.phy.queensu.ca) +Copyright 2003-2022, Phil Harvey (philharvey66 at gmail.com) This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.