diff --git a/src/Makefile b/src/Makefile index 2e634070..cf17aaa4 100644 --- a/src/Makefile +++ b/src/Makefile @@ -20,7 +20,7 @@ # 02111-1307, USA. # # File: Makefile -# Version: $Name: $ $Revision: 1.10 $ +# Version: $Name: $ $Revision: 1.11 $ # Author(s): Andreas Huggel (ahu) # History: 10-Dec-03, ahu: created # @@ -51,7 +51,7 @@ include $(top_srcdir)/config.mk CCHDR = rcsid.hpp error.hpp # Add library C++ source files to this list -CCSRC = exif.cpp ifd.cpp image.cpp tags.cpp types.cpp value.cpp +CCSRC = exif.cpp ifd.cpp image.cpp makernote.cpp tags.cpp types.cpp value.cpp # Add source files of simple applications to this list BINSRC = example1.cpp taglist.cpp exifprint.cpp exiftest.cpp @@ -130,7 +130,7 @@ ifeq ($(strip $(MAKECMDGOALS)),) -include $(DEP) else # ...or the target is _not_ one in the list of targets below. -NOINCLUDE = uninstall uninstall-lib check doc mostlyclean clean \ +NOINCLUDE = uninstall uninstall-lib check doc ctags mostlyclean clean \ install-header uninstall-header distclean maintainer-clean \ uninstall-archive uninstall-sharedlib ifneq ($(MAKECMDGOALS), $(filter $(MAKECMDGOALS), $(NOINCLUDE))) @@ -168,7 +168,7 @@ $(EXIV2BIN): %: %.o # ****************************************************************************** # Targets -.PHONY: all archive sharedlib bin check doc \ +.PHONY: all archive sharedlib bin check ctags doc \ clean mostlyclean distclean maintainer-clean \ install install-archive install-header \ install-sharedlib install-lib \ @@ -251,6 +251,10 @@ uninstall-sharedlib: uninstall-lib: $(UNINSTALL_LIB) uninstall-header +ctags: + ctags-exuberant --extra=+q -e * + ctags-exuberant --extra=+q * + check: @echo "No checks available for this library." diff --git a/src/makernote.cpp b/src/makernote.cpp new file mode 100644 index 00000000..a44cf731 --- /dev/null +++ b/src/makernote.cpp @@ -0,0 +1,597 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004 Andreas Huggel + * + * This program is part of the Exiv2 distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* + File: makernote.cpp + Version: $Name: $ $Revision: 1.1 $ + Author(s): Andreas Huggel (ahu) + History: 18-Feb-04, ahu: created + Credits: Canon MakerNote implemented according to the specification + "EXIF MakerNote of Canon" + by David Burren + */ +// ***************************************************************************** +#include "rcsid.hpp" +EXIV2_RCSID("@(#) $Name: $ $Revision: 1.1 $ $RCSfile: makernote.cpp,v $") + +// ***************************************************************************** +// included header files +#include "makernote.hpp" +#include "value.hpp" +#include "tags.hpp" // for ExifTags::ifdItem, printValue +#include "error.hpp" + +// + standard includes +#include +#include +#include + +// Define DEBUG_MAKERNOTE to output debug information to std::cerr +#define DEBUG_MAKERNOTE + +// ***************************************************************************** +// class member definitions +namespace Exif { + + std::string MakerNote::makeKey(uint16 tag) const + { + return std::string(ExifTags::ifdItem(makerIfd)) + + "." + sectionName(tag) + "." + tagName(tag); + } + + uint16 MakerNote::decomposeKey(const std::string& key) const + { + // Get the IFD, section name and tag name parts of the key + std::string::size_type pos1 = key.find('.'); + if (pos1 == std::string::npos) throw Error("Invalid key"); + std::string ifdItem = key.substr(0, pos1); + std::string::size_type pos0 = pos1 + 1; + pos1 = key.find('.', pos0); + if (pos1 == std::string::npos) throw Error("Invalid key"); + std::string sectionName = key.substr(pos0, pos1 - pos0); + pos0 = pos1 + 1; + std::string tagName = key.substr(pos0); + if (tagName == "") throw Error("Invalid key"); + + if (ifdItem != ExifTags::ifdItem(makerIfd)) return 0xffff; + uint16 tag = this->tag(tagName); + if (tag == 0xffff) return tag; + if (sectionName != this->sectionName(tag)) return 0xffff; + + return tag; + } + + std::string MakerNote::tagName(uint16 tag) const + { + std::string tagName; + if (mnTagInfo_) { + for (int i = 0; mnTagInfo_[i].tag_ != 0xffff; ++i) { + if (mnTagInfo_[i].tag_ == tag) { + tagName = mnTagInfo_[i].name_; + break; + } + } + } + if (tagName.empty()) { + std::ostringstream os; + os << "0x" << std::setw(4) << std::setfill('0') << std::right + << std::hex << tag; + tagName = os.str(); + } + return tagName; + } + + uint16 MakerNote::tag(const std::string& tagName) const + { + uint16 tag = 0xffff; + if (mnTagInfo_) { + for (int i = 0; mnTagInfo_[i].tag_ != 0xffff; ++i) { + if (mnTagInfo_[i].name_ == tagName) { + tag = mnTagInfo_[i].tag_; + break; + } + } + } + if (tag == 0xffff) { + std::istringstream is(tagName); + is >> std::hex >> tag; + } + return tag; + } + + MakerNoteFactory* MakerNoteFactory::instance_ = 0; + + MakerNoteFactory& MakerNoteFactory::instance() + { + if (0 == instance_) { + instance_ = new MakerNoteFactory; + } + return *instance_; + } // MakerNoteFactory::instance + + void MakerNoteFactory::registerMakerNote(const std::string& make, + const std::string& model, + MakerNote* makerNote) + { + std::string key = make + "+" + model; + Registry::iterator i = registry_.find(key); + if (i != registry_.end()) { + delete i->second; + } + registry_[key] = makerNote; + } // MakerNoteFactory::registerMakerNote + + MakerNoteFactory::MakerNoteFactory() + { + // Register a prototype of each known MakerNote + registerMakerNote("Canon", "Canon PowerShot S40", new CanonMakerNote); + } // MakerNoteFactory c'tor + + MakerNote* MakerNoteFactory::create(const std::string& make, + const std::string& model) const + { + MakerNote* makerNote = 0; + std::string key = make + "+" + model; + Registry::const_iterator i = registry_.find(key); + if (i != registry_.end() && i->second != 0) { + makerNote = i->second->clone(); + } + return makerNote; + } // MakerNoteFactory::create + + int IfdMakerNote::read(const char* buf, + long len, + ByteOrder byteOrder, + long offset) + { + int rc = ifd_.read(buf, byteOrder, offset); + if (rc == 0) { + // Todo: Make sure the Next field is 0. + Entries::iterator end = ifd_.end(); + for (Entries::iterator i = ifd_.begin(); i != end; ++i) { + i->setMakerNote(this); + } + } +#ifdef DEBUG_MAKERNOTE + hexdump(std::cerr, buf, len); + if (rc == 0) ifd_.print(std::cerr); +#endif + return rc; + } + + long IfdMakerNote::copy(char* buf, ByteOrder byteOrder, long offset) const + { + return ifd_.copy(buf, byteOrder, offset); + } + + long IfdMakerNote::size() const + { + return ifd_.size() + ifd_.dataSize(); + } + + // Canon MakerNote Tag Info + static const MakerNote::MnTagInfo canonMnTagInfo[] = { + MakerNote::MnTagInfo(0x0001, "CameraSettings1", "Various camera settings (1)"), + MakerNote::MnTagInfo(0x0004, "CameraSettings2", "Various camera settings (2)"), + MakerNote::MnTagInfo(0x0006, "ImageType", "Image type"), + MakerNote::MnTagInfo(0x0007, "FirmwareVersion", "Firmware version"), + MakerNote::MnTagInfo(0x0008, "ImageNumber", "Image number"), + MakerNote::MnTagInfo(0x0009, "OwnerName", "Owner Name"), + MakerNote::MnTagInfo(0x000c, "SerialNumber", "Camera serial number"), + MakerNote::MnTagInfo(0x000f, "EosD30Functions", "EOS D30 Custom Functions"), + // End of list marker + MakerNote::MnTagInfo(0xffff, "(UnknownCanonMakerNoteTag)", "Unknown CanonMakerNote tag") + }; + + CanonMakerNote::CanonMakerNote() + : IfdMakerNote(canonMnTagInfo), sectionName_("Canon") + { + } + + MakerNote* CanonMakerNote::clone() const + { + return new CanonMakerNote(*this); + } + + std::ostream& CanonMakerNote::printTag(std::ostream& os, + uint16 tag, + const Value& value) const + { + switch (tag) { + case 0x0001: print0x0001(os, value); break; + case 0x0004: print0x0004(os, value); break; + case 0x0008: print0x0008(os, value); break; + case 0x000c: print0x000c(os, value); break; + case 0x000f: print0x000f(os, value); break; + default: + // All other tags (known or unknown) go here + os << value; + break; + } + return os; + } + + std::ostream& CanonMakerNote::print0x0001( + std::ostream& os, const Value& value) const + { + if (0 == dynamic_cast(&value)) { + return os << value; + } + const UShortValue& val = dynamic_cast(value); + uint32 count = val.count(); + + if (count < 2) return os; + uint16 s = val.value_[1]; + os << std::setw(30) << "\n Macro mode "; + switch (s) { + case 1: os << "On"; break; + case 2: os << "Off"; break; + default: os << "(" << s << ")"; break; + } + + if (count < 3) return os; + s = val.value_[2]; + os << std::setw(30) << "\n Self timer "; + if (s == 0) { + os << "Off"; + } + else { + os << s / 10.0 << " s"; + } + if (count < 4) return os; + s = val.value_[3]; + os << std::setw(30) << "\n Quality "; + switch (s) { + case 2: os << "Normal"; break; + case 3: os << "Fine"; break; + case 5: os << "Superfine"; break; + default: os << "(" << s << ")"; break; + } + + if (count < 5) return os; + s = val.value_[4]; + os << std::setw(30) << "\n Flash mode "; + switch (s) { + case 0: os << "Off"; break; + case 1: os << "Auto"; break; + case 2: os << "On"; break; + case 3: os << "Red-eye"; break; + case 4: os << "Slow sync"; break; + case 5: os << "Auto + red-eye"; break; + case 6: os << "On + red-eye"; break; + case 16: os << "External"; break; + default: os << "(" << s << ")"; break; + } + + if (count < 6) return os; + s = val.value_[5]; + os << std::setw(30) << "\n Drive mode "; + switch (s) { + case 0: os << "Single / timer"; break; + case 1: os << "Continuous"; break; + default: os << "(" << s << ")"; break; + } + + // Meaning of the 6th ushort is unknown - ignore it + + if (count < 8) return os; + s = val.value_[7]; + os << std::setw(30) << "\n Focus mode "; + switch (s) { + case 0: os << "One shot"; break; + case 1: os << "AI servo"; break; + case 2: os << "AI Focus"; break; + case 3: os << "MF"; break; + case 4: os << "Single"; break; + case 5: os << "Continuous"; break; + case 6: os << "MF"; break; + default: os << "(" << s << ")"; break; + } + + // Meaning of the 8th ushort is unknown - ignore it + // Meaning of the 9th ushort is unknown - ignore it + + if (count < 11) return os; + s = val.value_[10]; + os << std::setw(30) << "\n Image size "; + switch (s) { + case 0: os << "Large"; break; + case 1: os << "Medium"; break; + case 2: os << "Small"; break; + default: os << "(" << s << ")"; break; + } + + if (count < 12) return os; + s = val.value_[11]; + os << std::setw(30) << "\n Easy shooting mode "; + switch (s) { + case 0: os << "Full auto"; break; + case 1: os << "Manual"; break; + case 2: os << "Landscape"; break; + case 3: os << "Fast shutter"; break; + case 4: os << "Slow shutter"; break; + case 5: os << "Night"; break; + case 6: os << "B&W"; break; + case 7: os << "Sepia"; break; + case 8: os << "Portrait"; break; + case 9: os << "Sports"; break; + case 10: os << "Macro / close-up"; break; + case 11: os << "Pan focus"; break; + default: os << "(" << s << ")"; break; + } + + if (count < 13) return os; + s = val.value_[12]; + os << std::setw(30) << "\n Digital zoom "; + switch (s) { + case 0: os << "None"; break; + case 1: os << "2x"; break; + case 2: os << "4x"; break; + default: os << "(" << s << ")"; break; + } + + if (count < 14) return os; + s = val.value_[13]; + os << std::setw(30) << "\n Contrast "; + switch (s) { + case 0xffff: os << "Low"; break; + case 0x0000: os << "Normal"; break; + case 0x0001: os << "High"; break; + default: os << "(" << s << ")"; break; + } + + if (count < 15) return os; + s = val.value_[14]; + os << std::setw(30) << "\n Saturation "; + switch (s) { + case 0xffff: os << "Low"; break; + case 0x0000: os << "Normal"; break; + case 0x0001: os << "High"; break; + default: os << "(" << s << ")"; break; + } + + if (count < 16) return os; + s = val.value_[15]; + os << std::setw(30) << "\n Sharpness "; + switch (s) { + case 0xffff: os << "Low"; break; + case 0x0000: os << "Normal"; break; + case 0x0001: os << "High"; break; + default: os << "(" << s << ")"; break; + } + + if (count < 17) return os; + s = val.value_[16]; + if (s != 0) { + os << std::setw(30) << "\n ISO "; + switch (s) { + case 15: os << "Auto"; break; + case 16: os << "50"; break; + case 17: os << "100"; break; + case 18: os << "200"; break; + case 19: os << "400"; break; + default: os << "(" << s << ")"; break; + } + } + + if (count < 18) return os; + s = val.value_[17]; + os << std::setw(30) << "\n Metering mode "; + switch (s) { + case 3: os << "Evaluative"; break; + case 4: os << "Partial"; break; + case 5: os << "Center weighted"; break; + default: os << "(" << s << ")"; break; + } + + if (count < 19) return os; + s = val.value_[18]; + os << std::setw(30) << "\n Focus type "; + switch (s) { + case 0: os << "Manual"; break; + case 1: os << "Auto"; break; + case 3: os << "Close-up (macro)"; break; + case 8: os << "Locked (pan mode)"; break; + default: os << "(" << s << ")"; break; + } + + if (count < 20) return os; + s = val.value_[19]; + os << std::setw(30) << "\n AF point selected "; + switch (s) { + case 0x3000: os << "None (MF)"; break; + case 0x3001: os << "Auto-selected"; break; + case 0x3002: os << "Right"; break; + case 0x3003: os << "Center"; break; + case 0x3004: os << "Left"; break; + default: os << "(" << s << ")"; break; + } + + if (count < 21) return os; + s = val.value_[20]; + os << std::setw(30) << "\n Exposure mode "; + switch (s) { + case 0: os << "Easy shooting"; break; + case 1: os << "Program"; break; + case 2: os << "Tv priority"; break; + case 3: os << "Av priority"; break; + case 4: os << "Manual"; break; + case 5: os << "A-DEP"; break; + default: os << "(" << s << ")"; break; + } + + // Meaning of the 21st ushort is unknown - ignore it + // Meaning of the 22nd ushort is unknown - ignore it + + if (count < 26) return os; + float fu = val.value_[25]; + float len1 = val.value_[23] / fu; + float len2 = val.value_[24] / fu; + std::ostringstream oss; + oss.copyfmt(os); + os << std::setw(30) << "\n Lens " + << std::fixed << std::setprecision(1) + << len2 << " - " << len1 << " mm"; + os.copyfmt(oss); + + // Meaning of the 26th ushort is unknown - ignore it + // Meaning of the 27th ushort is unknown - ignore it + + if (count < 29) return os; + s = val.value_[28]; + os << std::setw(30) << "\n Flash activity "; + switch (s) { + case 0: os << "Did not fire"; break; + case 1: os << "Fired"; break; + default: os << "(" << s << ")"; break; + } + + if (count < 30) return os; + s = val.value_[29]; + // Todo: decode bitmask + os << std::setw(30) << "\n Flash details " + << std::dec << s << " (Todo: decode bitmask)"; + + // Meaning of the 30th ushort is unknown - ignore it + // Meaning of the 31st ushort is unknown - ignore it + + if (count < 33) return os; + s = val.value_[32]; + os << std::setw(30) << "\n Focus mode "; + switch (s) { + case 0: os << "Single"; break; + case 1: os << "Continuous"; break; + default: os << "(" << s << ")"; break; + } + + // Meaning of any further ushorts is unknown - ignore them + + return os; + + } // CanonMakerNote::print0x0001 + + std::ostream& CanonMakerNote::print0x0004( + std::ostream& os, const Value& value) const + { + if (0 == dynamic_cast(&value)) { + return os << value; + } + const UShortValue& val = dynamic_cast(value); + uint32 count = val.count(); + + // Meaning of ushorts 1-6 is unknown - ignore them + + if (count < 8) return os; + uint16 s = val.value_[7]; + os << std::setw(30) << "\n White balance "; + switch (s) { + case 0: os << "Auto"; break; + case 1: os << "Sunny"; break; + case 2: os << "Cloudy"; break; + case 3: os << "Tungsten"; break; + case 4: os << "Fluorescent"; break; + case 5: os << "Flash"; break; + case 6: os << "Custom"; break; + default: os << "(" << s << ")"; break; + } + + // Meaning of ushort 8 is unknown - ignore it + + if (count < 10) return os; + s = val.value_[9]; + os << std::setw(30) << "\n Sequence number " << s << ""; + + // Meaning of ushorts 10-13 is unknown - ignore them + + if (count < 15) return os; + s = val.value_[14]; + // Todo: decode bitmask + os << std::setw(30) << "\n AF point used " + << s << " (Todo: decode bitmask)"; + + if (count < 16) return os; + s = val.value_[15]; + os << std::setw(30) << "\n Flash bias "; + switch (s) { + case 0xffc0: os << "-2 EV"; break; + case 0xffcc: os << "-1.67 EV"; break; + case 0xffd0: os << "-1.50 EV"; break; + case 0xffd4: os << "-1.33 EV"; break; + case 0xffe0: os << "-1 EV"; break; + case 0xffec: os << "-0.67 EV"; break; + case 0xfff0: os << "-0.50 EV"; break; + case 0xfff4: os << "-0.33 EV"; break; + case 0x0000: os << "0 EV"; break; + case 0x000c: os << "0.33 EV"; break; + case 0x0010: os << "0.50 EV"; break; + case 0x0014: os << "0.67 EV"; break; + case 0x0020: os << "1 EV"; break; + case 0x002c: os << "1.33 EV"; break; + case 0x0030: os << "1.50 EV"; break; + case 0x0034: os << "1.67 EV"; break; + case 0x0040: os << "2 EV"; break; + default: os << "(" << s << ")"; break; + } + + // Meaning of ushorts 16-18 is unknown - ignore them + + if (count < 20) return os; + s = val.value_[19]; + os << std::setw(30) << "\n Subject distance (0.01m or 0.001m) "; + if (s == 0xffff) { + os << "Infinite"; + } + else { + os << s << ""; + } + + return os; + + } // CanonMakerNote::print0x0004 + + std::ostream& CanonMakerNote::print0x0008( + std::ostream& os, const Value& value) const + { + std::string n = value.toString(); + return os << n.substr(0, n.length() - 4) << "-" + << n.substr(n.length() - 4); + } + + std::ostream& CanonMakerNote::print0x000c( + std::ostream& os, const Value& value) const + { + std::istringstream is(value.toString()); + uint32 l; + is >> l; + return os << std::setw(4) << std::setfill('0') << std::hex + << ((l & 0xffff0000) >> 16) + << std::setw(5) << std::setfill('0') << std::dec + << (l & 0x0000ffff); + } + + std::ostream& CanonMakerNote::print0x000f( + std::ostream& os, const Value& value) const + { + // Todo: Decode EOS D30 Custom Functions + return os << "EOS D30 Custom Functions " + << value << " (Todo: decode this field)"; + } + +} // namespace Exif diff --git a/src/makernote.hpp b/src/makernote.hpp new file mode 100644 index 00000000..37097c83 --- /dev/null +++ b/src/makernote.hpp @@ -0,0 +1,281 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004 Andreas Huggel + * + * This program is part of the Exiv2 distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/*! + @file makernote.hpp + @brief + @version $Name: $ $Revision: 1.1 $ + @author Andreas Huggel (ahu) + ahuggel@gmx.net + @date 18-Feb-04, ahu: created + */ +#ifndef MAKERNOTE_HPP_ +#define MAKERNOTE_HPP_ + +// ***************************************************************************** +// included header files +#include "types.hpp" +#include "ifd.hpp" + +// + standard includes +#include +#include +#include + +// ***************************************************************************** +// namespace extensions +namespace Exif { + + class Value; + +// ***************************************************************************** +// class definitions + + /*! + @brief %Exif makernote interface + + Defines methods to + - read the makernote from a character buffer + - copy the makernote to a character buffer + - add the makernote tags to the %Exif metadata + - access Makernote specific tag descriptions and print functions + + Todo: Synchronization with ExifData: + Add a MakerNote pointer to ExifData (owner) and Metadata + Instead of ExifData as the owner, there should be a reference counter + Does Entry need a MakerNote poiner too? (not nice cos of the circ deps) + */ + class MakerNote { + public: + + //! MakerNote Tag information + struct MnTagInfo { + //! Constructor + MnTagInfo(uint16 tag, const char* name, const char* desc) + : tag_(tag), name_(name), desc_(desc) {} + + uint16 tag_; //!< Tag + const char* name_; //!< One word tag label + const char* desc_; //!< Short tag description + }; // struct MnTagInfo + + //! Constructor. Takes an optional MakerNote info tag array. + MakerNote(const MnTagInfo* mnTagInfo =0) : mnTagInfo_(mnTagInfo) {} + //! Virtual destructor. + virtual ~MakerNote() {} + /*! + @brief Return a pointer to a copy of itself (deep copy). + The caller owns this copy and is responsible to delete it! + */ + virtual MakerNote* clone() const =0; + /*! + @brief Read the MakerNote from character buffer buf of length len at + position offset (from the start of the TIFF header) and encoded + in byte order byteOrder. + */ + virtual int read(const char* buf, + long len, + ByteOrder byteOrder, + long offset) =0; + /*! + @brief Copy (write) the makerNote to the character buffer buf at + position offset (from the start of the TIFF header), encoded + in byte order byteOrder. Return the number of bytes written. + */ + virtual long copy(char* buf, ByteOrder byteOrder, long offset) const =0; + + //! @name Accessors + //@{ + //! Return the size of the makernote in bytes. + virtual long size() const =0; + //! The first %MakerNote entry + virtual Entries::const_iterator begin() const =0; + //! End of the %MakerNote entries + virtual Entries::const_iterator end() const =0; + //! The first %MakerNote entry + virtual Entries::iterator begin() =0; + //! End of the %MakerNote entries + virtual Entries::iterator end() =0; + //! Return the key for the tag. + std::string makeKey(uint16 tag) const; + //! Return the associated tag for a makernote key. + uint16 decomposeKey(const std::string& key) const; + /*! + @brief Return the name of a makernote tag. The default implementation + looks up the %MakerNote info tag array if one is set, else + it translates the tag to a string with the hexadecimal value of + the tag. + */ + virtual std::string tagName(uint16 tag) const; + /*! + @brief Return the tag associated with a makernote tag name. The + default implementation looks up the %MakerNote info tag array + if one is set, else it expects tag names in the form \"0x01ff\" + and converts them to unsigned integer. + */ + virtual uint16 tag(const std::string& tagName) const; + //! Return the name of the makernote section + virtual std::string sectionName(uint16 tag) const =0; + //! Interpret and print the value of a makernote tag + virtual std::ostream& printTag(std::ostream& os, + uint16 tag, + const Value& value) const =0; + //@} + + protected: + //! Pointer to an array of MakerNote tag infos + const MnTagInfo* mnTagInfo_; + + }; // class MakerNote + + /*! + @brief %MakerNote factory. + + Creates an instance of the %MakerNote for one camera model. The factory is + implemented as a singleton, which can be accessed only through the static + member function instance(). + + Todo: Implement more intelligent registry that allows wildcards in the + make and model strings to register classes + */ + class MakerNoteFactory { + public: + /*! + @brief Access the makerNote factory. Clients access the task factory + exclusively through this method. + */ + static MakerNoteFactory& instance(); + + /*! + @brief Create the appropriate %MakerNote based on camera make and + model, return a pointer to the newly created MakerNote + instance. Return 0 if no %MakerNote is defined for the camera + model. + + @param make Camera manufacturer. (Typically the string from the %Exif + make tag.) + @param model Camera model. (Typically the string from the %Exif + model tag.) + @return A pointer that owns a %MakerNote for the camera model. If + the camera is not supported, the pointer is 0. + */ + MakerNote* create(const std::string& make, + const std::string& model) const; + + /*! + @brief Register a %MakerNote prototype for a camera model. + + The %MakerNote factory creates new %MakerNotes for a camera by cloning + the associated prototype. Additional %MakerNotes can be registered. + If called for a camera model for which a %MakerNote is already + registered, the corresponding prototype is replaced. + + @param make Camera manufacturer. (Typically the string from the %Exif + make tag.) + @param model Camera model. (Typically the string from the %Exif + model tag.) + @param makerNote Pointer to the prototype. Ownership is transfered to the + %MakerNote factory. + */ + void registerMakerNote(const std::string& make, + const std::string& model, + MakerNote* makerNote); + + private: + //! Prevent construction other than through instance(). + MakerNoteFactory(); + //! Prevent copy construction: not implemented. + MakerNoteFactory(const MakerNoteFactory& rhs); + + //! Pointer to the one and only instance of this class. + static MakerNoteFactory* instance_; + //! Type used to store %MakerNote prototype classes + typedef std::map Registry; + //! List of makernote types and corresponding prototypes. + Registry registry_; + + }; // class MakerNoteFactory + + /*! + @brief Interface for MakerNotes in IFD format + + Todo: Allow for a 'prefix' before the IFD (OLYMP, etc) + Cater for offsets from start of TIFF header as well as relative to Mn + */ + class IfdMakerNote : public MakerNote { + public: + //! Constructor. Takes an optional MakerNote info tag array. + IfdMakerNote(const MakerNote::MnTagInfo* mnTagInfo =0) + : MakerNote(mnTagInfo), ifd_(makerIfd, 0, false) {} + virtual ~IfdMakerNote() {} + virtual MakerNote* clone() const =0; + + int read(const char* buf, long len, ByteOrder byteOrder, long offset); + long copy(char* buf, ByteOrder byteOrder, long offset) const; + long size() const; + Entries::const_iterator begin() const { return ifd_.begin(); } + Entries::const_iterator end() const { return ifd_.end(); } + Entries::iterator begin() { return ifd_.begin(); } + Entries::iterator end() { return ifd_.end(); } + virtual std::string sectionName(uint16 tag) const =0; + virtual std::ostream& printTag(std::ostream& os, + uint16 tag, + const Value& value) const =0; + + protected: + Ifd ifd_; //!< MakerNote IFD + + }; // class IfdMakerNote + + //! MakerNote for Canon cameras + class CanonMakerNote : public IfdMakerNote { + public: + //! Default constructor + CanonMakerNote(); + virtual ~CanonMakerNote() {} + MakerNote* clone() const; + //! Return the name of the makernote section ("Canon") + std::string sectionName(uint16 tag) const { return sectionName_; } + std::ostream& printTag(std::ostream& os, + uint16 tag, + const Value& value) const; + + //! @name Print functions for Canon %MakerNote tags + //@{ + //! Print various camera settings, part 1 + std::ostream& print0x0001(std::ostream& os, const Value& value) const; + //! Print various camera settings, part 2 + std::ostream& print0x0004(std::ostream& os, const Value& value) const; + //! Print the image number + std::ostream& print0x0008(std::ostream& os, const Value& value) const; + //! Print the serial number of the camera + std::ostream& print0x000c(std::ostream& os, const Value& value) const; + //! Print EOS D30 custom functions + std::ostream& print0x000f(std::ostream& os, const Value& value) const; + //@} + + private: + std::string sectionName_; + + }; // class CanonMakerNote + +} // namespace Exif + +#endif // #ifndef MAKERNOTE_HPP_