Added MakerNote support, basics
parent
d42550f8aa
commit
1f94309899
@ -0,0 +1,597 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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) <ahuggel@gmx.net>
|
||||
History: 18-Feb-04, ahu: created
|
||||
Credits: Canon MakerNote implemented according to the specification
|
||||
"EXIF MakerNote of Canon" <http://www.burren.cx/david/canon.html>
|
||||
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 <string>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
// 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<const UShortValue*>(&value)) {
|
||||
return os << value;
|
||||
}
|
||||
const UShortValue& val = dynamic_cast<const UShortValue&>(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<const UShortValue*>(&value)) {
|
||||
return os << value;
|
||||
}
|
||||
const UShortValue& val = dynamic_cast<const UShortValue&>(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
|
@ -0,0 +1,281 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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)
|
||||
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
|
||||
@date 18-Feb-04, ahu: created
|
||||
*/
|
||||
#ifndef MAKERNOTE_HPP_
|
||||
#define MAKERNOTE_HPP_
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "types.hpp"
|
||||
#include "ifd.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
|
||||
// *****************************************************************************
|
||||
// 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<std::string, MakerNote*> 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_
|
Loading…
Reference in New Issue