From afe8efcc319f1699deb3bd0bc783cc73d0f4795f Mon Sep 17 00:00:00 2001 From: Andreas Huggel Date: Mon, 2 Feb 2009 16:19:57 +0000 Subject: [PATCH] Improved Panasonic RW2 decoder: now uses a dedicated PanasonicRaw tag table and reads Exif data from embedded preview image. --- doc/templates/Makefile | 2 +- doc/templates/tags-panasonic.html.in | 7 ++++++ src/panasonicmn.cpp | 34 ++++++++++++++++++++++++++ src/panasonicmn.hpp | 6 ++++- src/preview.cpp | 2 +- src/rw2image.cpp | 36 +++++++++++++++++++++++++--- src/taglist.cpp | 2 +- src/tags.cpp | 7 ++++-- src/tags.hpp | 2 +- src/tiffcomposite.cpp | 1 + src/tiffcomposite_int.hpp | 5 ++++ src/tiffimage.cpp | 21 +++++++++++++++- src/types.hpp | 3 ++- 13 files changed, 116 insertions(+), 12 deletions(-) diff --git a/doc/templates/Makefile b/doc/templates/Makefile index 36b59d5a..e6d9d9e0 100644 --- a/doc/templates/Makefile +++ b/doc/templates/Makefile @@ -52,7 +52,7 @@ TABLES = Exif \ Nikon1 Nikon2 Nikon3 \ Olympus OlympusCs OlympusEq OlympusRd OlympusRd2 \ OlympusIp OlympusFi OlympusFe1 OlympusRi \ - Panasonic \ + Panasonic PanasonicRaw \ Pentax \ Sigma \ Sony diff --git a/doc/templates/tags-panasonic.html.in b/doc/templates/tags-panasonic.html.in index c8ff8329..149c51a3 100644 --- a/doc/templates/tags-panasonic.html.in +++ b/doc/templates/tags-panasonic.html.in @@ -13,6 +13,13 @@ __index2__ __Panasonic__ +

Panasonic RAW Tags defined in Exiv2

+
+

Tags found in IFD0 of Panasonic RAW and RW2 images.

+

Click on a column header to sort the table.

+
+__PanasonicRaw__ + diff --git a/src/panasonicmn.cpp b/src/panasonicmn.cpp index 24a9fe9a..6e6786a0 100644 --- a/src/panasonicmn.cpp +++ b/src/panasonicmn.cpp @@ -324,4 +324,38 @@ namespace Exiv2 { } // PanasonicMakerNote::print0x0023 + // Panasonic MakerNote Tag Info + const TagInfo PanasonicMakerNote::tagInfoRaw_[] = { + TagInfo(0x0001, "Version", N_("Version"), N_("Panasonic raw version"), panaRawIfdId, panaRaw, undefined, printExifVersion), + TagInfo(0x0002, "SensorWidth", N_("Sensor Width"), N_("Sensor width"), panaRawIfdId, panaRaw, unsignedShort, printValue), + TagInfo(0x0003, "SensorHeight", N_("Sensor Height"), N_("Sensor height"), panaRawIfdId, panaRaw, unsignedShort, printValue), + TagInfo(0x0004, "SensorTopBorder", N_("Sensor Top Border"), N_("Sensor top border"), panaRawIfdId, panaRaw, unsignedShort, printValue), + TagInfo(0x0005, "SensorLeftBorder", N_("Sensor Left Border"), N_("Sensor left border"), panaRawIfdId, panaRaw, unsignedShort, printValue), + TagInfo(0x0006, "ImageHeight", N_("Image Height"), N_("Image height"), panaRawIfdId, panaRaw, unsignedShort, printValue), + TagInfo(0x0007, "ImageWidth", N_("Image Width"), N_("Image width"), panaRawIfdId, panaRaw, unsignedShort, printValue), + TagInfo(0x0011, "RedBalance", N_("Red Balance"), N_("Red balance (found in Digilux 2 RAW images)"), panaRawIfdId, panaRaw, unsignedShort, printValue), + TagInfo(0x0012, "BlueBalance", N_("Blue Balance"), N_("Blue balance"), panaRawIfdId, panaRaw, unsignedShort, printValue), + TagInfo(0x0017, "ISOSpeed", N_("ISO Speed"), N_("ISO speed setting"), panaRawIfdId, panaRaw, unsignedShort, printValue), + TagInfo(0x0024, "WBRedLevel", N_("WB Red Level"), N_("WB red level"), panaRawIfdId, panaRaw, unsignedShort, printValue), + TagInfo(0x0025, "WBGreenLevel", N_("WB Green Level"), N_("WB green level"), panaRawIfdId, panaRaw, unsignedShort, printValue), + TagInfo(0x0026, "WBBlueLevel", N_("WB Blue Level"), N_("WB blue level"), panaRawIfdId, panaRaw, unsignedShort, printValue), + TagInfo(0x002e, "PreviewImage", N_("Preview Image"), N_("Preview image"), panaRawIfdId, panaRaw, undefined, printValue), + TagInfo(0x010f, "Make", N_("Manufacturer"), N_("The manufacturer of the recording equipment"), panaRawIfdId, panaRaw, asciiString, printValue), + TagInfo(0x0110, "Model", N_("Model"), N_("The model name or model number of the equipment"), panaRawIfdId, panaRaw, asciiString, printValue), + TagInfo(0x0111, "StripOffsets", N_("Strip Offsets"), N_("Strip offsets"), panaRawIfdId, panaRaw, unsignedLong, printValue), + TagInfo(0x0112, "Orientation", N_("Orientation"), N_("Orientation"), panaRawIfdId, panaRaw, unsignedShort, print0x0112), + TagInfo(0x0116, "RowsPerStrip", N_("Rows Per Strip"), N_("The number of rows per strip"), panaRawIfdId, panaRaw, unsignedShort, printValue), + TagInfo(0x0117, "StripByteCounts", N_("Strip Byte Counts"), N_("Strip byte counts"), panaRawIfdId, panaRaw, unsignedLong, printValue), + TagInfo(0x0118, "RawDataOffset", N_("Raw Data Offset"), N_("Raw data offset"), panaRawIfdId, panaRaw, unsignedLong, printValue), + TagInfo(0x8769, "ExifTag", N_("Exif IFD Pointer"), N_("A pointer to the Exif IFD"), panaRawIfdId, panaRaw, unsignedLong, printValue), + TagInfo(0x8825, "GPSTag", N_("GPS Info IFD Pointer"), N_("A pointer to the GPS Info IFD"), panaRawIfdId, panaRaw, unsignedLong, printValue), + // End of list marker + TagInfo(0xffff, "(UnknownPanasonicRawTag)", "(UnknownPanasonicRawTag)", N_("Unknown PanasonicRaw tag"), panaRawIfdId, panaRaw, invalidTypeId, printValue) + }; + + const TagInfo* PanasonicMakerNote::tagListRaw() + { + return tagInfoRaw_; + } + } // namespace Exiv2 diff --git a/src/panasonicmn.hpp b/src/panasonicmn.hpp index be3a1534..92e9ce8d 100644 --- a/src/panasonicmn.hpp +++ b/src/panasonicmn.hpp @@ -55,6 +55,8 @@ namespace Exiv2 { public: //! Return read-only list of built-in Panasonic tags static const TagInfo* tagList(); + //! Return read-only list of built-in Panasonic RAW image tags (IFD0) + static const TagInfo* tagListRaw(); //! @name Print functions for Panasonic %MakerNote tags //@{ @@ -65,8 +67,10 @@ namespace Exiv2 { //@} private: - //! Tag information + //! Makernote tag list static const TagInfo tagInfo_[]; + //! Taglist for IFD0 of Panasonic RAW images + static const TagInfo tagInfoRaw_[]; }; // class PanasonicMakerNote diff --git a/src/preview.cpp b/src/preview.cpp index 34d53537..e0cefb7c 100644 --- a/src/preview.cpp +++ b/src/preview.cpp @@ -283,7 +283,7 @@ namespace { { "Exif.Olympus.ThumbnailImage", 0 }, // 4 { "Exif.Olympus2.ThumbnailImage", 0 }, // 5 { "Exif.Minolta.Thumbnail", 0 }, // 6 - { "Exif.Image.0x002e", 0 } // 7 + { "Exif.PanasonicRaw.PreviewImage", 0 } // 7 }; const LoaderTiff::Param LoaderTiff::param_[] = { diff --git a/src/rw2image.cpp b/src/rw2image.cpp index bdec8ab7..e673c8e4 100644 --- a/src/rw2image.cpp +++ b/src/rw2image.cpp @@ -42,6 +42,7 @@ EXIV2_RCSID("@(#) $Id$") #include "tiffcomposite_int.hpp" #include "tiffimage_int.hpp" #include "image.hpp" +#include "preview.hpp" #include "error.hpp" #include "futils.hpp" @@ -63,7 +64,8 @@ namespace Exiv2 { int Rw2Image::pixelWidth() const { - ExifData::const_iterator imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Image.0x0007")); + ExifData::const_iterator imageWidth = + exifData_.findKey(Exiv2::ExifKey("Exif.PanasonicRaw.SensorWidth")); if (imageWidth != exifData_.end() && imageWidth->count() > 0) { return imageWidth->toLong(); } @@ -72,7 +74,8 @@ namespace Exiv2 { int Rw2Image::pixelHeight() const { - ExifData::const_iterator imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Image.0x0006")); + ExifData::const_iterator imageHeight = + exifData_.findKey(Exiv2::ExifKey("Exif.PanasonicRaw.SensorHeight")); if (imageHeight != exifData_.end() && imageHeight->count() > 0) { return imageHeight->toLong(); } @@ -118,6 +121,33 @@ namespace Exiv2 { io_->mmap(), io_->size()); setByteOrder(bo); + + // A lot more metadata is hidden in the embedded preview image + // Todo: This should go into the Rw2Parser, but for that it needs the Image + PreviewManager loader(*this); + PreviewPropertiesList list = loader.getPreviewProperties(); + // Todo: What if there are more preview images? + if (list.size() > 1) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Warning: RW2 image contains more than one preview. None used.\n"; +#endif + } + if (list.size() != 1) return; + ExifData exifData; + PreviewImage preview = loader.getPreviewImage(*list.begin()); + Image::AutoPtr image = ImageFactory::open(preview.pData(), preview.size()); + if (image.get() == 0) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Warning: Failed to open RW2 preview image.\n"; +#endif + return; + } + image->readMetadata(); + for (ExifData::const_iterator pos = image->exifData().begin(); + pos != image->exifData().end(); ++pos) { + exifData_.add(*pos); + } + } // Rw2Image::readMetadata void Rw2Image::writeMetadata() @@ -140,7 +170,7 @@ namespace Exiv2 { xmpData, pData, size, - Tag::root, + Tag::pana, TiffMapping::findDecoder, &rw2Header); } diff --git a/src/taglist.cpp b/src/taglist.cpp index 3314b00a..576fe357 100644 --- a/src/taglist.cpp +++ b/src/taglist.cpp @@ -38,7 +38,7 @@ try { } IfdId ifdId = ExifTags::ifdIdByIfdItem(item); - if (ExifTags::isMakerIfd(ifdId)) { + if (ExifTags::isExifIfd(ifdId) || ExifTags::isMakerIfd(ifdId)) { ExifTags::taglist(std::cout, ifdId); break; } diff --git a/src/tags.cpp b/src/tags.cpp index e965d486..d28b3072 100644 --- a/src/tags.cpp +++ b/src/tags.cpp @@ -132,6 +132,7 @@ namespace Exiv2 { { olympusFe9IfdId, "Makernote", "OlympusFe9", OlympusMakerNote::tagListFe }, { olympusRiIfdId, "Makernote", "OlympusRi", OlympusMakerNote::tagListRi }, { panasonicIfdId, "Makernote", "Panasonic", PanasonicMakerNote::tagList }, + { panaRawIfdId, "PanaRaw", "PanasonicRaw", PanasonicMakerNote::tagListRaw }, { pentaxIfdId, "Makernote", "Pentax", PentaxMakerNote::tagList }, { sigmaIfdId, "Makernote", "Sigma", SigmaMakerNote::tagList }, { sonyIfdId, "Makernote", "Sony", SonyMakerNote::tagList }, @@ -155,6 +156,7 @@ namespace Exiv2 { { iopTags, "Interoperability", N_("Interoperability information") }, { makerTags, "Makernote", N_("Vendor specific information") }, { dngTags, "DngTags", N_("Adobe DNG tags") }, + { panaRaw, "PanasonicRaw", N_("Panasonic RAW tags") }, { lastSectionId, "(LastSection)", N_("Last section") } }; @@ -1690,8 +1692,9 @@ namespace Exiv2 { case subImage1Id: case subImage2Id: case subImage3Id: - case subImage4Id: rc = true; break; - default: rc = false; break; + case subImage4Id: + case panaRawIfdId: rc = true; break; + default: rc = false; break; } return rc; } // ExifTags::isExifIfd diff --git a/src/tags.hpp b/src/tags.hpp index 92273cc1..33dcbad9 100644 --- a/src/tags.hpp +++ b/src/tags.hpp @@ -66,7 +66,7 @@ namespace Exiv2 { enum SectionId { sectionIdNotSet, imgStruct, recOffset, imgCharacter, otherTags, exifFormat, exifVersion, imgConfig, userInfo, relatedFile, dateTime, - captureCond, gpsTags, iopTags, makerTags, dngTags, + captureCond, gpsTags, iopTags, makerTags, dngTags, panaRaw, lastSectionId }; // ***************************************************************************** diff --git a/src/tiffcomposite.cpp b/src/tiffcomposite.cpp index 8e7a7049..55b07272 100644 --- a/src/tiffcomposite.cpp +++ b/src/tiffcomposite.cpp @@ -79,6 +79,7 @@ namespace Exiv2 { { 8, "SubImage2" }, { 9, "SubImage3" }, { 10, "SubImage4" }, + { 64, "PanasonicRaw" }, { 256, "MakerNote" }, // 257 not needed (olympmn) { 258, "Fujifilm" }, diff --git a/src/tiffcomposite_int.hpp b/src/tiffcomposite_int.hpp index 38c21066..fa3e60a3 100644 --- a/src/tiffcomposite_int.hpp +++ b/src/tiffcomposite_int.hpp @@ -77,6 +77,9 @@ namespace Exiv2 { Todo: what exactly are these and where should they go? Are they going to be mapped to the second part of an Exif key or are they the second part of the key? + + @note Groups with ids > mn are Makernote groups and get treated slightly + differently. */ namespace Group { const uint16_t none = 0; //!< Dummy group @@ -90,6 +93,7 @@ namespace Exiv2 { const uint16_t subimg2 = 8; //!< 2nd TIFF SubIFD in IFD0 const uint16_t subimg3 = 9; //!< 3rd TIFF SubIFD in IFD0 const uint16_t subimg4 = 10; //!< 4th TIFF SubIFD in IFD0 + const uint16_t panaraw = 64; //!< IFD0 of Panasonic RAW images const uint16_t mn = 256; //!< Makernote const uint16_t ignr = 511; //!< Read but do not decode } @@ -104,6 +108,7 @@ namespace Exiv2 { const uint32_t root = 0x20000; //!< Special tag: root IFD const uint32_t next = 0x30000; //!< Special tag: next IFD const uint32_t all = 0x40000; //!< Special tag: all tags in a group + const uint32_t pana = 0x80000; //!< Special tag: root IFD of Panasonic RAW images } /*! diff --git a/src/tiffimage.cpp b/src/tiffimage.cpp index 5c301f1a..45c40462 100644 --- a/src/tiffimage.cpp +++ b/src/tiffimage.cpp @@ -313,7 +313,13 @@ namespace Exiv2 { { Tag::root, Group::minocso, Group::minoltamn, 0x0001 }, { Tag::root, Group::minocsn, Group::minoltamn, 0x0003 }, { Tag::root, Group::minocs7, Group::minoltamn, 0x0004 }, - { Tag::root, Group::minocs5, Group::minoltamn, 0x0114 } + { Tag::root, Group::minocs5, Group::minoltamn, 0x0114 }, + // --------------------------------------------------------- + // Panasonic RW2 raw images + { Tag::pana, Group::none, Group::none, Tag::pana }, + { Tag::pana, Group::panaraw, Group::none, Tag::pana }, + { Tag::pana, Group::exif, Group::panaraw, 0x8769 }, + { Tag::pana, Group::gps, Group::panaraw, 0x8825 } }; /* @@ -572,6 +578,19 @@ namespace Exiv2 { { Tag::all, Group::minocs7, newTiffArrayElement }, { Tag::all, Group::minocs5, newTiffArrayElement }, + // ----------------------------------------------------------------------- + // Root directory of Panasonic RAW images + { Tag::pana, Group::none, newTiffDirectory }, + + // IFD0 of Panasonic RAW images + { 0x8769, Group::panaraw, newTiffSubIfd }, + { 0x8825, Group::panaraw, newTiffSubIfd }, +// { 0x0111, Group::panaraw, newTiffImageData<0x0117, Group::panaraw> }, +// { 0x0117, Group::panaraw, newTiffImageSize<0x0111, Group::panaraw> }, + { Tag::next, Group::panaraw, newTiffDirectory }, + { Tag::all, Group::panaraw, newTiffEntry }, + + // ----------------------------------------------------------------------- // Tags which are not de/encoded { Tag::next, Group::ignr, newTiffDirectory }, { Tag::all, Group::ignr, newTiffEntry } diff --git a/src/types.hpp b/src/types.hpp index d4f29aa8..b2b7cef5 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -149,7 +149,8 @@ namespace Exiv2 { olympusFe1IfdId, olympusFe2IfdId, olympusFe3IfdId, olympusFe4IfdId, olympusFe5IfdId, olympusFe6IfdId, olympusFe7IfdId, olympusFe8IfdId, olympusFe9IfdId, olympusRiIfdId, - panasonicIfdId, pentaxIfdId, sigmaIfdId, sonyIfdId, + panasonicIfdId, panaRawIfdId, + pentaxIfdId, sigmaIfdId, sonyIfdId, lastIfdId }; //! Container for binary data