Metadatum interface, Ifd::Entry

v0.27.3
Andreas Huggel 22 years ago
parent 158db49a87
commit 478e5f21a5

@ -25,7 +25,7 @@
RCS information RCS information
$Name: $ $Name: $
$Revision: 1.5 $ $Revision: 1.6 $
*/ */
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
@ -47,7 +47,7 @@ namespace {
// Compare two IFD entries by offset, taking care of special cases // Compare two IFD entries by offset, taking care of special cases
// where one or both of the entries don't have an offset. // where one or both of the entries don't have an offset.
bool cmpOffset(const Exif::Metadatum& lhs, const Exif::Metadatum& rhs); bool cmpOffset(const Exif::Ifd::Entry& lhs, const Exif::Ifd::Entry& rhs);
} }
@ -295,21 +295,17 @@ namespace Exif {
} }
Metadatum::Metadatum() Metadatum::Metadatum()
: tag_(0), type_(0), count_(0), offset_(0), : tag_(0), type_(0), ifdId_(IfdIdNotSet), ifdIdx_(-1), value_(0)
ifdId_(IfdIdNotSet), ifdIdx_(-1), value_(0), size_(0)
{ {
} }
Metadatum::Metadatum(uint16 tag, uint16 type, uint32 count, uint32 offset, Metadatum::Metadatum(uint16 tag, uint16 type,
IfdId ifdId, int ifdIdx, Value* value) IfdId ifdId, int ifdIdx, Value* value)
: tag_(tag), type_(type), count_(count), offset_(offset), : tag_(tag), type_(type), ifdId_(ifdId), ifdIdx_(ifdIdx), value_(value)
ifdId_(ifdId), ifdIdx_(ifdIdx), value_(value)
{ {
key_ = std::string(ifdItem()) key_ = std::string(ifdItem())
+ "." + std::string(sectionName()) + "." + std::string(sectionName())
+ "." + std::string(tagName()); + "." + std::string(tagName());
size_ = count_ * typeSize();
} }
Metadatum::~Metadatum() Metadatum::~Metadatum()
@ -321,40 +317,76 @@ namespace Exif {
{ {
tag_ = rhs.tag_; tag_ = rhs.tag_;
type_ = rhs.type_; type_ = rhs.type_;
count_ = rhs.count_;
offset_ = rhs.offset_;
ifdId_ = rhs.ifdId_; ifdId_ = rhs.ifdId_;
ifdIdx_ = rhs.ifdIdx_; ifdIdx_ = rhs.ifdIdx_;
value_ = 0; value_ = 0;
if (rhs.value_ != 0) value_ = rhs.value_->clone(); // deep copy if (rhs.value_ != 0) value_ = rhs.value_->clone(); // deep copy
key_ = rhs.key_; key_ = rhs.key_;
size_ = rhs.size_;
} }
Metadatum& Metadatum::operator=(const Metadatum& rhs) Metadatum& Metadatum::operator=(const Metadatum& rhs)
{ {
if (this == &rhs) return *this; if (this == &rhs) return *this;
tag_ = rhs.tag_; tag_ = rhs.tag_;
type_ = rhs.type_; type_ = rhs.type_;
count_ = rhs.count_;
offset_ = rhs.offset_;
ifdId_ = rhs.ifdId_; ifdId_ = rhs.ifdId_;
ifdIdx_ = rhs.ifdIdx_; ifdIdx_ = rhs.ifdIdx_;
delete value_; delete value_;
value_ = 0; value_ = 0;
if (rhs.value_ != 0) value_ = rhs.value_->clone(); // deep copy if (rhs.value_ != 0) value_ = rhs.value_->clone(); // deep copy
key_ = rhs.key_; key_ = rhs.key_;
return *this;
} // Metadatum::operator=
void Metadatum::setValue(Value* value)
{
delete value_;
value_ = value;
}
Ifd::Entry::Entry()
: ifdIdx_(-1), tag_(0), type_(0), count_(0), offset_(0),
data_(0), size_(0)
{
}
Ifd::Entry::~Entry()
{
delete[] data_;
}
Ifd::Entry::Entry(const Entry& rhs)
{
ifdIdx_ = rhs.ifdIdx_;
tag_ = rhs.tag_;
type_ = rhs.type_;
count_ = rhs.count_;
offset_ = rhs.offset_;
data_ = 0;
if (rhs.data_) {
data_ = new char[rhs.size_];
::memcpy(data_, rhs.data_, rhs.size_);
}
size_ = rhs.size_; size_ = rhs.size_;
}
Ifd::Entry::Entry& Ifd::Entry::operator=(const Entry& rhs)
{
if (this == &rhs) return *this;
ifdIdx_ = rhs.ifdIdx_;
tag_ = rhs.tag_;
type_ = rhs.type_;
count_ = rhs.count_;
offset_ = rhs.offset_;
delete data_;
data_ = 0;
if (rhs.data_) {
data_ = new char[rhs.size_];
::memcpy(data_, rhs.data_, rhs.size_);
}
size_ = rhs.size_;
return *this; return *this;
} // Metadatum::operator= }
Ifd::Ifd(IfdId ifdId) Ifd::Ifd(IfdId ifdId)
: ifdId_(ifdId), offset_(0), next_(0), size_(0) : ifdId_(ifdId), offset_(0), next_(0), size_(0)
@ -369,16 +401,15 @@ namespace Exif {
entries_.clear(); entries_.clear();
for (int i=0; i<n; ++i) { for (int i=0; i<n; ++i) {
Metadatum e; Entry e;
e.ifdId_ = ifdId_;
e.ifdIdx_ = i; e.ifdIdx_ = i;
e.tag_ = getUShort(buf+o, byteOrder); e.tag_ = getUShort(buf+o, byteOrder);
e.type_ = getUShort(buf+o+2, byteOrder); e.type_ = getUShort(buf+o+2, byteOrder);
e.count_ = getULong(buf+o+4, byteOrder); e.count_ = getULong(buf+o+4, byteOrder);
// offset will be converted to a relative offset below // offset will be converted to a relative offset below
e.offset_ = getULong(buf+o+8, byteOrder); e.offset_ = getULong(buf+o+8, byteOrder);
// data_ is set later, see below
e.size_ = e.count_ * e.typeSize(); e.size_ = e.count_ * e.typeSize();
// value_ is set later, see below
entries_.push_back(e); entries_.push_back(e);
o += 12; o += 12;
} }
@ -389,9 +420,9 @@ namespace Exif {
// on the assumption that the smallest offset points to a data // on the assumption that the smallest offset points to a data
// buffer directly following the IFD. // buffer directly following the IFD.
// Subsequently all offsets of IFD entries need to be recalculated. // Subsequently all offsets of IFD entries need to be recalculated.
const Metadata::iterator eb = entries_.begin(); const Entries::iterator eb = entries_.begin();
const Metadata::iterator ee = entries_.end(); const Entries::iterator ee = entries_.end();
Metadata::iterator i = eb; Entries::iterator i = eb;
if (offset_ == 0 && i != ee) { if (offset_ == 0 && i != ee) {
// Find the entry with the smallest offset // Find the entry with the smallest offset
i = std::min_element(eb, ee, cmpOffset); i = std::min_element(eb, ee, cmpOffset);
@ -401,29 +432,28 @@ namespace Exif {
} }
} }
// Assign the values to each IFD entry and // Assign the values to each IFD entry and
// calculate offsets relative to the start of the IFD // calculate offsets relative to the start of the IFD
for (i = eb; i != ee; ++i) { for (i = eb; i != ee; ++i) {
delete i->value_; delete[] i->data_;
i->value_ = Value::create(TypeId(i->type_));
if (i->size_ > 4) { if (i->size_ > 4) {
i->offset_ = i->offset_ - offset_; i->offset_ = i->offset_ - offset_;
i->value_->read(buf + i->offset_, i->size_, byteOrder); i->data_ = new char[i->size_];
::memcpy(i->data_, buf + i->offset_, i->size_);
} }
else { else {
char tmpbuf[4]; i->data_ = new char[4];
ul2Data(tmpbuf, i->offset_, byteOrder); ul2Data(i->data_, i->offset_, byteOrder);
i->value_->read(tmpbuf, i->size_, byteOrder);
} }
} }
return 0; return 0;
} // Ifd::read } // Ifd::read
Metadata::const_iterator Ifd::findTag(uint16 tag) const Ifd::Entries::const_iterator Ifd::findTag(uint16 tag) const
{ {
return std::find_if(entries_.begin(), entries_.end(), return std::find_if(entries_.begin(), entries_.end(),
FindMetadatumByTag(tag)); FindEntryByTag(tag));
} }
int Ifd::readSubIfd( int Ifd::readSubIfd(
@ -431,7 +461,7 @@ namespace Exif {
) const ) const
{ {
int rc = 0; int rc = 0;
Metadata::const_iterator pos = findTag(tag); Entries::const_iterator pos = findTag(tag);
if (pos != entries_.end()) { if (pos != entries_.end()) {
rc = dest.read(buf + pos->offset_, byteOrder, pos->offset_); rc = dest.read(buf + pos->offset_, byteOrder, pos->offset_);
} }
@ -448,9 +478,9 @@ namespace Exif {
// Add all directory entries to the data buffer // Add all directory entries to the data buffer
long dataSize = 0; long dataSize = 0;
const Metadata::const_iterator b = entries_.begin(); const Entries::const_iterator b = entries_.begin();
const Metadata::const_iterator e = entries_.end(); const Entries::const_iterator e = entries_.end();
Metadata::const_iterator i = b; Entries::const_iterator i = b;
for (; i != e; ++i) { for (; i != e; ++i) {
us2Data(buf+o, i->tag_, byteOrder); us2Data(buf+o, i->tag_, byteOrder);
us2Data(buf+o+2, i->type_, byteOrder); us2Data(buf+o+2, i->type_, byteOrder);
@ -460,10 +490,7 @@ namespace Exif {
dataSize += i->size_; dataSize += i->size_;
} }
else { else {
char tmpbuf[4]; ::memcpy(buf+o+8, i->data_, 4);
::memset(tmpbuf, 0x0, 4);
i->value_->copy(tmpbuf, byteOrder);
::memcpy(buf+o+8, tmpbuf, 4);
} }
o += 12; o += 12;
} }
@ -481,10 +508,8 @@ namespace Exif {
// Add the data of all IFD entries to the data buffer // Add the data of all IFD entries to the data buffer
for (i = b; i != e; ++i) { for (i = b; i != e; ++i) {
if (i->size_ > 4) { if (i->size_ > 4) {
// Todo: Check this! There seems to be an inconsistency ::memcpy(buf + o, i->data_, i->size_);
// in the use of size_ and the return value of copy() here o += i->size_;
// Todo: And can value_ be 0?
o += i->value_->copy(buf+o, byteOrder);
} }
} }
@ -504,28 +529,20 @@ namespace Exif {
<< prefix << "Entry Tag Format (Bytes each) Number Offset\n" << prefix << "Entry Tag Format (Bytes each) Number Offset\n"
<< prefix << "----- ------ --------------------- ------ -----------\n"; << prefix << "----- ------ --------------------- ------ -----------\n";
const Metadata::const_iterator b = entries_.begin(); const Entries::const_iterator b = entries_.begin();
const Metadata::const_iterator e = entries_.end(); const Entries::const_iterator e = entries_.end();
Metadata::const_iterator i = b; Entries::const_iterator i = b;
for (; i != e; ++i) { for (; i != e; ++i) {
std::ostringstream offset; std::ostringstream offset;
if (i->typeSize() * i->count_ <= 4) { if (i->size_ <= 4) {
offset << std::setw(2) << std::setfill('0') << std::hex
// Todo: Fix me! This doesn't work with Value anymore because we do not know << (int)*(unsigned char*)i->data_ << " "
// the byte order here. (Wait for Ifd to use a more special type) << std::setw(2) << std::setfill('0') << std::hex
// << (int)*(unsigned char*)(i->data_+1) << " "
// char tmpbuf[4]; << std::setw(2) << std::setfill('0') << std::hex
// i->value_->copy(tmpbuf, byteOrder); << (int)*(unsigned char*)(i->data_+2) << " "
// offset << std::setw(2) << std::setfill('0') << std::hex << std::setw(2) << std::setfill('0') << std::hex
// << (int)*(unsigned char*)tmpbuf << " " << (int)*(unsigned char*)(i->data_+3) << " ";
// << std::setw(2) << std::setfill('0') << std::hex
// << (int)*(unsigned char*)(tmpbuf+1) << " "
// << std::setw(2) << std::setfill('0') << std::hex
// << (int)*(unsigned char*)(tmpbuf+2) << " "
// << std::setw(2) << std::setfill('0') << std::hex
// << (int)*(unsigned char*)(tmpbuf+3) << " ";
offset << "n/a";
} }
else { else {
offset << " 0x" << std::setw(8) << std::setfill('0') << std::hex offset << " 0x" << std::setw(8) << std::setfill('0') << std::hex
@ -548,42 +565,42 @@ namespace Exif {
<< std::setw(8) << std::setfill('0') << std::hex << std::setw(8) << std::setfill('0') << std::hex
<< std::right << next_ << "\n"; << std::right << next_ << "\n";
// Todo: Fix me! This does not work with Value anymore for (i = b; i != e; ++i) {
// for (i = b; i != e; ++i) { if (i->size_ > 4) {
// if (i->size_ > 4) { os << "Data of entry " << i-b << ":\n";
// os << "Data of entry " << i-b << ":\n"; hexdump(os, i->data_, i->size_);
// hexdump(os, i->data_, i->size_); }
// } }
// }
} // Ifd::print } // Ifd::print
// Todo: implement this properly.. // Todo: implement this properly..
// - Tag values 0x0201 and 0x0202 may be long OR short types... // - Tag values 0x0201 and 0x0202 may be long OR short types...
// - TIFF thumbnails // - TIFF thumbnails
// Rewrite: it should use the higher level Metadata interface
int Thumbnail::read(const char* buf, const Ifd& ifd1, ByteOrder byteOrder) int Thumbnail::read(const char* buf, const Ifd& ifd1, ByteOrder byteOrder)
{ {
Metadata::const_iterator pos = ifd1.findTag(0x0103); // Ifd::Entries::const_iterator pos = ifd1.findTag(0x0103);
if (pos == ifd1.entries().end()) return 1; // if (pos == ifd1.entries().end()) return 1;
const UShortValue& compression = dynamic_cast<const UShortValue&>(pos->value()); // const UShortValue& compression = dynamic_cast<const UShortValue&>(pos->value());
if (compression.value() == 6) { // if (compression.value() == 6) {
pos = ifd1.findTag(0x0201); // pos = ifd1.findTag(0x0201);
if (pos == ifd1.entries().end()) return 2; // if (pos == ifd1.entries().end()) return 2;
const ULongValue& offset = dynamic_cast<const ULongValue&>(pos->value()); // const ULongValue& offset = dynamic_cast<const ULongValue&>(pos->value());
pos = ifd1.findTag(0x0202); // pos = ifd1.findTag(0x0202);
if (pos == ifd1.entries().end()) return 3; // if (pos == ifd1.entries().end()) return 3;
const ULongValue& size = dynamic_cast<const ULongValue&>(pos->value()); // const ULongValue& size = dynamic_cast<const ULongValue&>(pos->value());
thumbnail_ = std::string(buf + offset.value(), size.value()); // thumbnail_ = std::string(buf + offset.value(), size.value());
} // }
else if (compression.value() == 1) { // else if (compression.value() == 1) {
// Todo: to be continued... // // Todo: to be continued...
return 4; // return 4;
} // }
else { // else {
// invalid compression value // // invalid compression value
return 5; // return 5;
} // }
return 0; return 0;
} }
@ -654,16 +671,16 @@ namespace Exif {
rc = ifd1.readSubIfd(ifd1GpsIfd, buf, byteOrder(), 0x8825); rc = ifd1.readSubIfd(ifd1GpsIfd, buf, byteOrder(), 0x8825);
if (rc) return rc; if (rc) return rc;
// Copy all metadata from the IFDs to the internal metadata // Copy all entries from the IFDs to the internal metadata
metadata_.clear(); metadata_.clear();
add(ifd0.entries()); add(ifd0, byteOrder());
add(exifIfd.entries()); add(exifIfd, byteOrder());
add(iopIfd.entries()); add(iopIfd, byteOrder());
add(gpsIfd.entries()); add(gpsIfd, byteOrder());
add(ifd1.entries()); add(ifd1, byteOrder());
add(ifd1ExifIfd.entries()); add(ifd1ExifIfd, byteOrder());
add(ifd1IopIfd.entries()); add(ifd1IopIfd, byteOrder());
add(ifd1GpsIfd.entries()); add(ifd1GpsIfd, byteOrder());
// Read the thumbnail // Read the thumbnail
thumbnail_.read(buf, ifd1, byteOrder()); thumbnail_.read(buf, ifd1, byteOrder());
@ -683,9 +700,16 @@ namespace Exif {
return 0; return 0;
} }
void ExifData::add(const Metadata& src) void ExifData::add(const Ifd& ifd, ByteOrder byteOrder)
{ {
metadata_.insert(metadata_.end(), src.begin(), src.end()); Ifd::const_iterator i = ifd.begin();
Ifd::const_iterator end = ifd.end();
for (; i != end; ++i) {
Value* value = Value::create(TypeId(i->type_));
value->read(i->data_, i->size_, byteOrder);
Metadatum md(i->tag_, i->type_, ifd.ifdId(), i->ifdIdx_, value);
add(md);
}
} }
void ExifData::add(const Metadatum& src) void ExifData::add(const Metadatum& src)
@ -857,7 +881,7 @@ namespace Exif {
// local definitions // local definitions
namespace { namespace {
bool cmpOffset(const Exif::Metadatum& lhs, const Exif::Metadatum& rhs) bool cmpOffset(const Exif::Ifd::Entry& lhs, const Exif::Ifd::Entry& rhs)
{ {
// We need to ignore entries with size <= 4, so by definition, // We need to ignore entries with size <= 4, so by definition,
// entries with size <= 4 are greater than those with size > 4 // entries with size <= 4 are greater than those with size > 4

@ -21,7 +21,7 @@
/*! /*!
@file exif.hpp @file exif.hpp
@brief Encoding and decoding of %Exif data @brief Encoding and decoding of %Exif data
@version $Name: $ $Revision: 1.5 $ @version $Name: $ $Revision: 1.6 $
@author Andreas Huggel (ahu) @author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a> <a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 09-Jan-03, ahu: created @date 09-Jan-03, ahu: created
@ -196,6 +196,8 @@ namespace Exif {
@return Number of characters written. @return Number of characters written.
*/ */
virtual long copy(char* buf, ByteOrder byteOrder) const =0; virtual long copy(char* buf, ByteOrder byteOrder) const =0;
//! Return the number of components of the value
virtual long count() const =0;
//! Return the size of the value in bytes //! Return the size of the value in bytes
virtual long size() const =0; virtual long size() const =0;
/*! /*!
@ -259,6 +261,7 @@ namespace Exif {
@return Number of characters written. @return Number of characters written.
*/ */
virtual long copy(char* buf, ByteOrder byteOrder) const; virtual long copy(char* buf, ByteOrder byteOrder) const;
virtual long count() const { return size(); }
virtual long size() const; virtual long size() const;
virtual Value* clone() const; virtual Value* clone() const;
virtual std::ostream& write(std::ostream& os) const; virtual std::ostream& write(std::ostream& os) const;
@ -296,6 +299,7 @@ namespace Exif {
@return Number of characters written. @return Number of characters written.
*/ */
virtual long copy(char* buf, ByteOrder byteOrder) const; virtual long copy(char* buf, ByteOrder byteOrder) const;
virtual long count() const { return size(); }
virtual long size() const; virtual long size() const;
virtual Value* clone() const; virtual Value* clone() const;
virtual std::ostream& write(std::ostream& os) const; virtual std::ostream& write(std::ostream& os) const;
@ -323,6 +327,7 @@ namespace Exif {
*/ */
virtual void read(const std::string& buf); virtual void read(const std::string& buf);
virtual long copy(char* buf, ByteOrder byteOrder) const; virtual long copy(char* buf, ByteOrder byteOrder) const;
virtual long count() const { return value_.size(); }
virtual long size() const; virtual long size() const;
virtual Value* clone() const; virtual Value* clone() const;
virtual std::ostream& write(std::ostream& os) const; virtual std::ostream& write(std::ostream& os) const;
@ -371,7 +376,7 @@ namespace Exif {
of the value pointer if one is provided, so the application of the value pointer if one is provided, so the application
must not delete it! must not delete it!
*/ */
Metadatum(uint16 tag, uint16 type, uint32 count, uint32 offset, Metadatum(uint16 tag, uint16 type,
IfdId ifdId, int ifdIdx, Value* value =0); IfdId ifdId, int ifdIdx, Value* value =0);
/*! /*!
@brief Constructor for new tags created by an application, @brief Constructor for new tags created by an application,
@ -387,7 +392,13 @@ namespace Exif {
//! Assignment operator //! Assignment operator
Metadatum& operator=(const Metadatum& rhs); Metadatum& operator=(const Metadatum& rhs);
//! Return the name of the type /*!
@brief Set the value. The Metadatum takes ownership of the value
pointer, so the application must not delete it!
*/
void setValue(Value* value);
//! Return the name of the tag
const char* tagName() const { return ExifTags::tagName(tag_, ifdId_); } const char* tagName() const { return ExifTags::tagName(tag_, ifdId_); }
//! Return the name of the type //! Return the name of the type
const char* typeName() const { return ExifTags::typeName(TypeId(type_)); } const char* typeName() const { return ExifTags::typeName(TypeId(type_)); }
@ -406,8 +417,10 @@ namespace Exif {
uint16 tag() const { return tag_; } uint16 tag() const { return tag_; }
//! Return the type //! Return the type
TypeId type() const { return TypeId(type_); } TypeId type() const { return TypeId(type_); }
//! Return the count //! Return the number of components in the value
uint32 count() const { return count_; } long count() const { return value_ == 0 ? 0 : value_->count(); }
//! Return the size of the value in bytes
long size() const { return value_ == 0 ? 0 : value_->size(); }
//! Return the IFD id //! Return the IFD id
IfdId ifdId() const { return ifdId_; } IfdId ifdId() const { return ifdId_; }
//! Return the position in the IFD (-1: not set) //! Return the position in the IFD (-1: not set)
@ -422,53 +435,82 @@ namespace Exif {
std::string key() const { return key_; } std::string key() const { return key_; }
//@} //@}
public: private:
uint16 tag_; //!< Tag value uint16 tag_; //!< Tag value
uint16 type_; //!< Type of the data uint16 type_; //!< Type of the data
uint32 count_; //!< Number of components
uint32 offset_; //!< Offset of the data from start of IFD
IfdId ifdId_; //!< The IFD associated with this tag IfdId ifdId_; //!< The IFD associated with this tag
int ifdIdx_; //!< Position in the IFD (-1: not set) int ifdIdx_; //!< Position in the IFD (-1: not set)
Value* value_; //!< Pointer to the value Value* value_; //!< Pointer to the value
std::string key_; //!< Unique key std::string key_; //!< Unique key
long size_; //!< Size of the data in bytes
}; // class Metadatum }; // class Metadatum
//! Container type to hold all metadata //! Container type to hold all metadata
typedef std::vector<Metadatum> Metadata; typedef std::vector<Metadatum> Metadata;
//! Unary predicate that matches a Metadatum with a given tag
class FindMetadatumByTag {
public:
//! Constructor, initializes the object with the tag to look for
FindMetadatumByTag(uint16 tag) : tag_(tag) {}
/*!
@brief Returns true if the tag of the argument metadatum is equal
to that of the object.
*/
bool operator()(const Metadatum& metadatum) const
{ return tag_ == metadatum.tag_; }
private:
uint16 tag_;
}; // class FindMetadatumByTag
/*! /*!
@brief Models an IFD (Image File Directory) @brief Models an IFD (Image File Directory)
Todo: Todo:
- make the data handling more intelligent - make the data handling more intelligent
- should we return the size and do away with size() ?
*/ */
class Ifd { class Ifd {
public: public:
//! Constructor. Allows to set the IFD identifier. //! Constructor. Allows to set the IFD identifier.
explicit Ifd(IfdId ifdId =IfdIdNotSet); explicit Ifd(IfdId ifdId =IfdIdNotSet);
//! Data structure for one IFD directory entry
struct Entry {
Entry(); //!< Default constructor
~Entry(); //!< Destructor
Entry(const Entry& rhs); //!< Copy constructor
Entry& operator=(const Entry& rhs); //!< Assignment operator
//! Return the size in bytes of one element of this type
long typeSize() const
{ return ExifTags::typeSize(TypeId(type_)); }
//! Return the name of the type
const char* typeName() const
{ return ExifTags::typeName(TypeId(type_)); }
int ifdIdx_; //!< Position in the IFD
uint16 tag_; //!< Tag
uint16 type_; //!< Type
uint32 count_; //!< Number of components
//! Offset from the start of the IFD
uint32 offset_;
//! Pointer to the data buffer
char* data_;
//! Size of the data buffer in bytes
long size_;
}; // struct Entry
//! Container type to hold all IFD directory entries
typedef std::vector<Entry> Entries;
//! Entries iterator type (const)
typedef Entries::const_iterator const_iterator;
//! The first entry
const_iterator begin() const { return entries_.begin(); }
//! End of the entries
const_iterator end() const { return entries_.end(); }
//! Unary predicate that matches an Entry with a given tag
class FindEntryByTag {
public:
//! Constructor, initializes the object with the tag to look for
FindEntryByTag(uint16 tag) : tag_(tag) {}
/*!
@brief Returns true if the tag of the argument metadatum is equal
to that of the object.
*/
bool operator()(const Ifd::Entry& entry) const
{ return tag_ == entry.tag_; }
private:
uint16 tag_;
}; // class FindEntryByTag
/*! /*!
@brief Read a complete IFD and its data from a data buffer @brief Read a complete IFD and its data from a data buffer
@ -521,12 +563,12 @@ namespace Exif {
void print(std::ostream& os, const std::string& prefix ="") const; void print(std::ostream& os, const std::string& prefix ="") const;
//! @name Accessors //! @name Accessors
//@{ //@{
//! Ifd id of the IFD
IfdId ifdId() const { return ifdId_; }
//! Offset of the IFD from SOI //! Offset of the IFD from SOI
long offset() const { return offset_; } long offset() const { return offset_; }
//! Get the IFD entries
const Metadata& entries() const { return entries_; }
//! Find an IFD entry by tag, return an iterator into the entries list //! Find an IFD entry by tag, return an iterator into the entries list
Metadata::const_iterator findTag(uint16 tag) const; Entries::const_iterator findTag(uint16 tag) const;
//! Get the offset to the next IFD from the start of the Tiff header //! Get the offset to the next IFD from the start of the Tiff header
long next() const { return next_; } long next() const { return next_; }
//! Get the size of this IFD in bytes (IFD only, without data) //! Get the size of this IFD in bytes (IFD only, without data)
@ -534,10 +576,11 @@ namespace Exif {
//@} //@}
private: private:
Entries entries_; // IFD entries
IfdId ifdId_; // IFD Id IfdId ifdId_; // IFD Id
long offset_; // offset of the IFD from the start of long offset_; // offset of the IFD from the start of
// Tiff header // Tiff header
Metadata entries_; // IFD metadata entries
long next_; // offset of next IFD from the start of long next_; // offset of next IFD from the start of
// the Tiff header // the Tiff header
long size_; // size of the IFD in bytes long size_; // size of the IFD in bytes
@ -599,8 +642,8 @@ namespace Exif {
//! Returns the byte order as specified in the Tiff header //! Returns the byte order as specified in the Tiff header
ByteOrder byteOrder() const { return tiffHeader_.byteOrder(); } ByteOrder byteOrder() const { return tiffHeader_.byteOrder(); }
//! Add all entries of src to the Exif metadata //! Add all entries of an IFD to the Exif metadata
void add(const Metadata& src); void add(const Ifd& ifd, ByteOrder byteOrder);
//! Add Metadatum src to the Exif metadata //! Add Metadatum src to the Exif metadata
void add(const Metadatum& src); void add(const Metadatum& src);

@ -22,14 +22,14 @@ int main(int argc, char* const argv[])
for (; i != end; ++i) { for (; i != end; ++i) {
std::cout << "0x" std::cout << "0x"
<< std::hex << std::setw(4) << std::setfill('0') << std::right << std::hex << std::setw(4) << std::setfill('0') << std::right
<< i->tag_ << " " << i->tag() << " "
<< std::setw(27) << std::setfill(' ') << std::left << std::setw(27) << std::setfill(' ') << std::left
<< i->tagName() << " " << i->tagName() << " "
<< std::setw(17) << std::setfill(' ') << std::left << std::setw(17) << std::setfill(' ') << std::left
<< i->typeName() << " " << i->typeName() << " "
<< std::dec << std::setw(3) << std::dec << std::setw(3)
<< std::setfill(' ') << std::right << std::setfill(' ') << std::right
<< i->count_ << " " << i->count() << " "
<< std::dec << i->value() << "\n"; << std::dec << i->value() << "\n";
} }
} }

Loading…
Cancel
Save