Changes for makernote write support, documentation updates

This commit is contained in:
Andreas Huggel
2004-03-07 08:47:20 +00:00
parent 4ee8aac263
commit 1daee4d7ae
2 changed files with 325 additions and 156 deletions
+113 -55
View File
@@ -20,14 +20,14 @@
*/
/*
File: exif.cpp
Version: $Name: $ $Revision: 1.22 $
Version: $Name: $ $Revision: 1.23 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 26-Jan-04, ahu: created
11-Feb-04, ahu: isolated as a component
*/
// *****************************************************************************
#include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.22 $ $RCSfile: exif.cpp,v $")
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.23 $ $RCSfile: exif.cpp,v $")
// *****************************************************************************
// included header files
@@ -60,6 +60,7 @@ namespace {
entry of type unsigned long with one component is created.
*/
void setOffsetTag(Exif::Ifd& ifd,
int idx,
Exif::uint16 tag,
Exif::uint32 offset,
Exif::ByteOrder byteOrder);
@@ -71,8 +72,8 @@ namespace {
namespace Exif {
Metadatum::Metadatum(const Entry& e, ByteOrder byteOrder)
: tag_(e.tag()), ifdId_(e.ifdId()), makerNote_(e.makerNote()),
value_(0), key_(makeKey(e))
: tag_(e.tag()), ifdId_(e.ifdId()), idx_(e.idx()),
makerNote_(e.makerNote()), value_(0), key_(makeKey(e))
{
value_ = Value::create(TypeId(e.type()));
value_->read(e.data(), e.count() * e.typeSize(), byteOrder);
@@ -81,7 +82,7 @@ namespace Exif {
Metadatum::Metadatum(const std::string& key,
const Value* value,
MakerNote* makerNote)
: makerNote_(makerNote), value_(0), key_(key)
: idx_(0), makerNote_(makerNote), value_(0), key_(key)
{
if (value) value_ = value->clone();
std::pair<uint16, IfdId> p = decomposeKey(key, makerNote);
@@ -98,8 +99,8 @@ namespace Exif {
}
Metadatum::Metadatum(const Metadatum& rhs)
: tag_(rhs.tag_), ifdId_(rhs.ifdId_), makerNote_(rhs.makerNote_),
value_(0), key_(rhs.key_)
: tag_(rhs.tag_), ifdId_(rhs.ifdId_), idx_(rhs.idx_),
makerNote_(rhs.makerNote_), value_(0), key_(rhs.key_)
{
if (rhs.value_ != 0) value_ = rhs.value_->clone(); // deep copy
}
@@ -109,6 +110,7 @@ namespace Exif {
if (this == &rhs) return *this;
tag_ = rhs.tag_;
ifdId_ = rhs.ifdId_;
idx_ = rhs.idx_;
makerNote_ = rhs.makerNote_;
delete value_;
value_ = 0;
@@ -498,18 +500,6 @@ namespace Exif {
// Find and read ExifIFD sub-IFD of IFD0
rc = ifd0_.readSubIfd(exifIfd_, data_, byteOrder(), 0x8769);
if (rc) return rc;
// Find and read Interoperability IFD in ExifIFD
rc = exifIfd_.readSubIfd(iopIfd_, data_, byteOrder(), 0xa005);
if (rc) return rc;
// Find and read GPSInfo sub-IFD in IFD0
rc = ifd0_.readSubIfd(gpsIfd_, data_, byteOrder(), 0x8825);
if (rc) return rc;
// Read IFD1
if (ifd0_.next()) {
rc = ifd1_.read(data_ + ifd0_.next(), byteOrder(), ifd0_.next());
if (rc) return rc;
}
// Find MakerNote in ExifIFD, create a MakerNote class
Ifd::iterator pos = exifIfd_.findTag(0x927c);
Ifd::iterator make = ifd0_.findTag(0x010f);
@@ -535,7 +525,17 @@ namespace Exif {
if (makerNote_) {
exifIfd_.erase(pos);
}
// Find and read Interoperability IFD in ExifIFD
rc = exifIfd_.readSubIfd(iopIfd_, data_, byteOrder(), 0xa005);
if (rc) return rc;
// Find and read GPSInfo sub-IFD in IFD0
rc = ifd0_.readSubIfd(gpsIfd_, data_, byteOrder(), 0x8825);
if (rc) return rc;
// Read IFD1
if (ifd0_.next()) {
rc = ifd1_.read(data_ + ifd0_.next(), byteOrder(), ifd0_.next());
if (rc) return rc;
}
// Find and delete ExifIFD sub-IFD of IFD1
pos = ifd1_.findTag(0x8769);
if (pos != ifd1_.end()) {
@@ -586,7 +586,7 @@ namespace Exif {
// If we can update the internal IFDs and the underlying data buffer
// from the metadata without changing the data size, then it is enough
// to copy the data buffer.
if (updateIfds()) {
if (updateEntries()) {
//ahu Todo: remove debugging output
std::cout << "->>>>>> using non-intrusive writing <<<<<<-\n";
@@ -618,11 +618,24 @@ std::cout << "->>>>>> writing from metadata <<<<<<-\n";
long exifIfdOffset = ifd0Offset + ifd0.size() + ifd0.dataSize();
Ifd exifIfd(exifIfd, exifIfdOffset);
addToIfd(exifIfd, begin(), end(), byteOrder());
if (makerNote_) {
// Create a placeholder MakerNote entry of the correct size and
// add it to the Exif IFD
Entry e;
e.setIfdId(makerIfd);
e.setTag(0x927c);
long size = makerNote_->size();
char* buf = new char[size];
memset(buf, 0x0, size);
e.setValue(undefined, size, buf, size);
exifIfd.add(e);
delete[] buf;
}
// Set the offset to the Exif IFD in IFD0
ifd0.erase(0x8769);
int idx = ifd0.erase(0x8769);
if (exifIfd.size() > 0) {
setOffsetTag(ifd0, 0x8769, exifIfdOffset, byteOrder());
setOffsetTag(ifd0, idx, 0x8769, exifIfdOffset, byteOrder());
}
// Build Interoperability IFD from metadata
@@ -631,9 +644,9 @@ std::cout << "->>>>>> writing from metadata <<<<<<-\n";
addToIfd(iopIfd, begin(), end(), byteOrder());
// Set the offset to the Interoperability IFD in Exif IFD
exifIfd.erase(0xa005);
idx = exifIfd.erase(0xa005);
if (iopIfd.size() > 0) {
setOffsetTag(exifIfd, 0xa005, iopIfdOffset, byteOrder());
setOffsetTag(exifIfd, idx, 0xa005, iopIfdOffset, byteOrder());
}
// Build GPSInfo IFD from metadata
@@ -642,9 +655,9 @@ std::cout << "->>>>>> writing from metadata <<<<<<-\n";
addToIfd(gpsIfd, begin(), end(), byteOrder());
// Set the offset to the GPSInfo IFD in IFD0
ifd0.erase(0x8825);
idx = ifd0.erase(0x8825);
if (gpsIfd.size() > 0) {
setOffsetTag(ifd0, 0x8825, gpsIfdOffset, byteOrder());
setOffsetTag(ifd0, idx, 0x8825, gpsIfdOffset, byteOrder());
}
// Update Exif data from thumbnail, build IFD1 from updated metadata
@@ -660,11 +673,18 @@ std::cout << "->>>>>> writing from metadata <<<<<<-\n";
ifd0.setNext(ifd1Offset);
}
// Copy all IFDs and the thumbnail image to the data buffer
// Copy all IFDs, the MakerNote data and the thumbnail to the data buffer
ifd0.sortByTag();
ifd0.copy(buf + ifd0Offset, byteOrder(), ifd0Offset);
exifIfd.sortByTag();
exifIfd.copy(buf + exifIfdOffset, byteOrder(), exifIfdOffset);
if (makerNote_) {
// Copy the MakerNote over the placeholder data
Entries::iterator mn = exifIfd.findTag(0x927c);
makerNote_->copy(buf + exifIfdOffset + mn->offset(),
byteOrder(),
exifIfdOffset + mn->offset());
}
iopIfd.sortByTag();
iopIfd.copy(buf + iopIfdOffset, byteOrder(), iopIfdOffset);
gpsIfd.sortByTag();
@@ -737,6 +757,18 @@ std::cout << "->>>>>> writing from metadata <<<<<<-\n";
FindMetadatumByKey(key));
}
ExifData::const_iterator ExifData::findIfdIdIdx(IfdId ifdId, int idx) const
{
return std::find_if(metadata_.begin(), metadata_.end(),
FindMetadatumByIfdIdIdx(ifdId, idx));
}
ExifData::iterator ExifData::findIfdIdIdx(IfdId ifdId, int idx)
{
return std::find_if(metadata_.begin(), metadata_.end(),
FindMetadatumByIfdIdIdx(ifdId, idx));
}
void ExifData::sortByKey()
{
std::sort(metadata_.begin(), metadata_.end(), cmpMetadataByKey);
@@ -752,30 +784,30 @@ std::cout << "->>>>>> writing from metadata <<<<<<-\n";
metadata_.erase(pos);
}
bool ExifData::updateIfds()
bool ExifData::updateEntries()
{
if (!this->compatible()) return false;
bool compatible = true;
compatible |= updateIfd(ifd0_);
compatible |= updateIfd(exifIfd_);
compatible |= updateIfd(iopIfd_);
compatible |= updateIfd(gpsIfd_);
compatible |= updateIfd(ifd1_);
compatible |= updateRange(ifd0_.begin(), ifd0_.end());
compatible |= updateRange(exifIfd_.begin(), exifIfd_.end());
if (makerNote_) {
compatible |= updateRange(makerNote_->begin(), makerNote_->end());
}
compatible |= updateRange(iopIfd_.begin(), iopIfd_.end());
compatible |= updateRange(gpsIfd_.begin(), gpsIfd_.end());
compatible |= updateRange(ifd1_.begin(), ifd1_.end());
return compatible;
} // ExifData::updateIfds
} // ExifData::updateEntries
bool ExifData::updateIfd(Ifd& ifd)
bool ExifData::updateRange(const Entries::iterator& begin,
const Entries::iterator& end)
{
if (ifd.alloc()) throw Error("Invariant violated in ExifData::updateIfd");
bool compatible = true;
Ifd::iterator end = ifd.end();
for (Ifd::iterator entry = ifd.begin(); entry != end; ++entry) {
for (Entries::iterator entry = begin; entry != end; ++entry) {
// find the corresponding metadatum
std::string key = makeKey(*entry);
const_iterator md = findKey(key);
const_iterator md = findIfdIdIdx(entry->ifdId(), entry->idx());
if (md == this->end()) {
// corresponding metadatum was deleted: this is not (yet) a
// supported non-intrusive write operation.
@@ -796,31 +828,54 @@ std::cout << "->>>>>> writing from metadata <<<<<<-\n";
}
}
return compatible;
} // ExifData::updateIfd
} // ExifData::updateRange
bool ExifData::compatible() const
{
bool compatible = true;
const_iterator end = this->end();
for (const_iterator md = begin(); md != end; ++md) {
// Check if the metadatum is compatible with the
// corresponding IFD entry
const Ifd* ifd = getIfd(md->ifdId());
if (!ifd) {
compatible = false;
break;
}
Ifd::const_iterator entry = ifd->findTag(md->tag());
if (entry == ifd->end()) {
// For each metadatum, check if it is compatible with the corresponding
// IFD or MakerNote entry
for (const_iterator md = begin(); md != this->end(); ++md) {
std::pair<bool, Entries::const_iterator> rc;
rc = findEntry(md->ifdId(), md->idx());
// Make sure that we have an entry
if (!rc.first) {
compatible = false;
break;
}
if (md->size() > entry->size()) {
// Make sure that the size of the metadatum fits the available size
// of the entry
if (md->size() > rc.second->size()) {
compatible = false;
break;
}
}
return compatible;
} // ExifData::compatible
std::pair<bool, Entries::const_iterator>
ExifData::findEntry(IfdId ifdId, int idx) const
{
Entries::const_iterator entry;
std::pair<bool, Entries::const_iterator> rc(false, entry);
if (ifdId == makerIfd && makerNote_) {
entry = makerNote_->findIdx(idx);
if (entry != makerNote_->end()) {
rc.first = true;
rc.second = entry;
}
return rc;
}
const Ifd* ifd = getIfd(ifdId);
if (ifdId != makerIfd && ifd) {
entry = ifd->findIdx(idx);
if (entry != ifd->end()) {
rc.first = true;
rc.second = entry;
}
}
return rc;
}
const Ifd* ExifData::getIfd(IfdId ifdId) const
@@ -872,6 +927,7 @@ std::cout << "->>>>>> writing from metadata <<<<<<-\n";
Entry e(ifd.alloc());
e.setIfdId(metadatum.ifdId());
e.setIdx(metadatum.idx());
e.setTag(metadatum.tag());
e.setOffset(0); // will be calculated when the IFD is written
char* buf = new char[metadatum.size()];
@@ -924,6 +980,7 @@ std::cout << "->>>>>> writing from metadata <<<<<<-\n";
namespace {
void setOffsetTag(Exif::Ifd& ifd,
int idx,
Exif::uint16 tag,
Exif::uint32 offset,
Exif::ByteOrder byteOrder)
@@ -932,6 +989,7 @@ namespace {
if (pos == ifd.end()) {
Exif::Entry e(ifd.alloc());
e.setIfdId(ifd.ifdId());
e.setIdx(idx);
e.setTag(tag);
e.setOffset(0); // will be calculated when the IFD is written
ifd.add(e);
+212 -101
View File
@@ -21,7 +21,7 @@
/*!
@file exif.hpp
@brief Encoding and decoding of %Exif data
@version $Name: $ $Revision: 1.24 $
@version $Name: $ $Revision: 1.25 $
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 09-Jan-04, ahu: created
@@ -61,16 +61,14 @@ namespace Exif {
*/
class Metadatum {
public:
//! @name Creators
//@{
/*!
@brief Constructor to build a metadatum from an IFD entry.
*/
Metadatum(const Entry& e, ByteOrder byteOrder);
/*!
@brief Constructor for new tags created by an application, which only
needs to provide a key / value pair. %Metadatum copies (clones)
the value if one is provided. Alternatively, a program can
create an 'empty' metadatum with only a key and set the value
later, using setValue().
@brief Constructor for new tags created by an application. The
metadatum is created from a key / value pair. %Metadatum copies
(clones) the value if one is provided. Alternatively, a program
can create an 'empty' metadatum with only a key and set the
value using setValue().
@param key The key of the metadatum.
@param value Pointer to a metadatum value.
@@ -82,10 +80,16 @@ namespace Exif {
explicit Metadatum(const std::string& key,
const Value* value =0,
MakerNote* makerNote =0);
//! Destructor
~Metadatum();
//! Constructor to build a metadatum from an IFD entry.
Metadatum(const Entry& e, ByteOrder byteOrder);
//! Copy constructor
Metadatum(const Metadatum& rhs);
//! Destructor
~Metadatum();
//@}
//! @name Manipulators
//@{
//! Assignment operator
Metadatum& operator=(const Metadatum& rhs);
/*!
@@ -98,6 +102,10 @@ namespace Exif {
not have a value yet, then an AsciiValue is created.
*/
void setValue(const std::string& buf);
//@}
//! @name Accessors
//@{
/*!
@brief Write value to a character data buffer and return the number
of characters (bytes) written.
@@ -111,22 +119,21 @@ namespace Exif {
*/
long copy(char* buf, ByteOrder byteOrder) const
{ return value_ == 0 ? 0 : value_->copy(buf, byteOrder); }
//! @name Accessors
//@{
/*!
@brief Return a key for the tag. The key is of the form
'ifdItem.sectionName.tagName'.
@brief Return the key of the metadatum. The key is of the form
'ifdItem.sectionName.tagName'. Note however that the key
is not necessarily unique.
*/
std::string key() const { return key_; }
//! Return the related image item
//! Return the related image item (the first part of the key)
const char* ifdItem() const { return ExifTags::ifdItem(ifdId_); }
//! Return the name of the section
//! Return the name of the section (the second part of the key)
std::string sectionName() const;
//! Return the name of the tag
//! Return the name of the tag (which is also the third part of the key)
std::string tagName() const;
//! Return the tag
uint16 tag() const { return tag_; }
//! Return the type id.
//! Return the type id of the value
TypeId typeId() const { return value_ == 0 ? invalid : value_->typeId(); }
//! Return the name of the type
const char* typeName() const { return TypeInfo::typeName(typeId()); }
@@ -140,6 +147,8 @@ namespace Exif {
IfdId ifdId() const { return ifdId_; }
//! Return the name of the IFD
const char* ifdName() const { return ExifTags::ifdName(ifdId_); }
//! Return the index (unique id of this metadatum within the original IFD)
int idx() const { return idx_; }
//! Return the pointer to the associated MakerNote
MakerNote* makerNote() const { return makerNote_; }
//! Return the value as a string.
@@ -208,6 +217,7 @@ namespace Exif {
private:
uint16 tag_; //!< Tag value
IfdId ifdId_; //!< The IFD associated with this tag
int idx_; //!< Unique id of an entry within one IFD
MakerNote* makerNote_; //!< Pointer to the associated MakerNote
Value* value_; //!< Pointer to the value
std::string key_; //!< Key
@@ -220,39 +230,26 @@ namespace Exif {
*/
std::ostream& operator<<(std::ostream& os, const Metadatum& md);
//! Container type to hold all metadata
typedef std::vector<Metadatum> Metadata;
//! Unary predicate that matches a Metadatum with a given key
class FindMetadatumByKey {
public:
//! Constructor, initializes the object with the tag to look for
FindMetadatumByKey(const std::string& key) : key_(key) {}
/*!
@brief Returns true if the key of the argument metadatum is equal
to that of the object.
*/
bool operator()(const Metadatum& metadatum) const
{ return key_ == metadatum.key(); }
private:
std::string key_;
}; // class FindMetadatumByTag
//! %Thumbnail data Todo: add, create, rotate, delete
class Thumbnail {
public:
//! %Thumbnail image types
enum Type { none, jpeg, tiff };
//! @name Creators
//@{
//! Default constructor
Thumbnail();
//! Destructor
~Thumbnail();
//! Copy constructor
Thumbnail(const Thumbnail& rhs);
//@}
//! @name Manipulators
//@{
//! Assignment operator
Thumbnail& operator=(const Thumbnail& rhs);
//! %Thumbnail image types
enum Type { none, jpeg, tiff };
/*!
@brief Read the thumbnail from the data buffer buf, using %Exif
metadata exifData. Return 0 if successful.
@@ -272,6 +269,10 @@ namespace Exif {
int read(const char* buf,
const ExifData& exifData,
ByteOrder byteOrder =littleEndian);
//@}
//! @name Accessors
//@{
/*!
@brief Write thumbnail to file path, return 0 if successful, -1 if
there is no thumbnail image to write.
@@ -312,15 +313,21 @@ namespace Exif {
long size() const;
//! Return the type of the thumbnail
Type type() const { return type_; }
//@}
private:
//! @name Manipulators
//@{
//! Read a compressed (JPEG) thumbnail image from the data buffer
int readJpegImage(const char* buf, const ExifData& exifData);
//! Read an uncompressed (TIFF) thumbnail image from the data buffer
int readTiffImage(const char* buf,
const ExifData& exifData,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
//! Update the Exif data according to the actual JPEG thumbnail image
void updateJpegImage(ExifData& exifData) const;
//! Update the Exif data according to the actual TIFF thumbnail image
@@ -333,15 +340,56 @@ namespace Exif {
void setJpegImageOffsets(Ifd& ifd1, ByteOrder byteOrder) const;
//! Update the offsets to the TIFF thumbnail image in the IFD
void setTiffImageOffsets(Ifd& ifd1, ByteOrder byteOrder) const;
//@}
// DATA
Type type_; // Type of thumbnail image
long size_; // Size of the image data
char* image_; // Thumbnail image data
TiffHeader tiffHeader_; // Thumbnail TIFF Header, only for TIFF thumbs
Ifd ifd_; // Thumbnail IFD, only for TIFF thumbnails
}; // class Thumbnail
//! Container type to hold all metadata
typedef std::vector<Metadatum> Metadata;
//! Unary predicate that matches a Metadatum with a given key
class FindMetadatumByKey {
public:
//! Constructor, initializes the object with the tag to look for
FindMetadatumByKey(const std::string& key) : key_(key) {}
/*!
@brief Returns true if the key of the argument metadatum is equal
to that of the object.
*/
bool operator()(const Metadatum& metadatum) const
{ return key_ == metadatum.key(); }
private:
std::string key_;
}; // class FindMetadatumByTag
//! Unary predicate that matches a Metadatum with a given ifd id and idx
class FindMetadatumByIfdIdIdx {
public:
//! Constructor, initializes the object with the ifd id and idx to look for
FindMetadatumByIfdIdIdx(IfdId ifdId, int idx)
: ifdId_(ifdId), idx_(idx) {}
/*!
@brief Returns true if the ifd id and idx of the argument metadatum
is equal to that of the object.
*/
bool operator()(const Metadatum& metadatum) const
{ return ifdId_ == metadatum.ifdId() && idx_ == metadatum.idx(); }
private:
IfdId ifdId_;
int idx_;
}; // class FindMetadatumByIfdIdIdx
/*!
@brief A container for %Exif data. This is the top-level class of
the Exiv2 library.
@@ -355,15 +403,29 @@ namespace Exif {
- extract and delete %Exif thumbnail (JPEG and TIFF thumbnails)
*/
class ExifData {
// Copying not allowed (Todo: implement me!)
//! @name Not implemented
//@{
//! Copying not allowed (Todo: implement me!)
ExifData(const ExifData& rhs);
// Assignment not allowed (Todo: implement me!)
//! Assignment not allowed (Todo: implement me!)
ExifData& operator=(const ExifData& rhs);
//@}
public:
//! Metadata iterator type
typedef Metadata::iterator iterator;
//! Metadata const iterator type
typedef Metadata::const_iterator const_iterator;
//! @name Creators
//@{
//! Default constructor
ExifData();
//! Destructor
~ExifData();
//@}
//! @name Manipulators
//@{
/*!
@brief Read the %Exif data from file path.
@param path Path to the file
@@ -436,25 +498,12 @@ namespace Exif {
multiple metadata with the same key.
*/
void add(const Metadatum& metadatum);
/*!
@brief Return the approximate size of all %Exif data (TIFF header plus
metadata). The number returned may be bigger than the actual
size of the %Exif data, but it is never smaller. Only copy()
returns the exact size.
*/
long size() const;
//! Returns the byte order as specified in the TIFF header
ByteOrder byteOrder() const { return tiffHeader_.byteOrder(); }
//! Metadata iterator type
typedef Metadata::iterator iterator;
//! Metadata const iterator type
typedef Metadata::const_iterator const_iterator;
//! Begin of the metadata
const_iterator begin() const { return metadata_.begin(); }
//! End of the metadata
const_iterator end() const { return metadata_.end(); }
//! Delete the metadatum at iterator position pos
void erase(iterator pos);
//! Sort metadata by key
void sortByKey();
//! Sort metadata by tag
void sortByTag();
//! Begin of the metadata
iterator begin() { return metadata_.begin(); }
//! End of the metadata
@@ -465,19 +514,57 @@ namespace Exif {
which of the matching metadata is found.
*/
iterator findKey(const std::string& key);
/*!
@brief Find the metadatum with the given ifd id and idx, return an
iterator to it.
This method can be used to uniquely identify a metadatum that was
created from an IFD or from the makernote (with idx greater than
0). Metadata created by an application (not read from an IFD or a
makernote) all have their idx field set to 0, i.e., they cannot be
uniquely identified with this method. If multiple metadata with the
same key exist, it is undefined which of the matching metadata is
found.
*/
iterator findIfdIdIdx(IfdId ifdId, int idx);
//@}
//! @name Accessors
//@{
//! Begin of the metadata
const_iterator begin() const { return metadata_.begin(); }
//! End of the metadata
const_iterator end() const { return metadata_.end(); }
/*!
@brief Find a metadatum with the given key, return a const iterator to
it. If multiple metadata with the same key exist, it is
undefined which of the matching metadata is found.
*/
const_iterator findKey(const std::string& key) const;
//! Sort metadata by key
void sortByKey();
//! Sort metadata by tag
void sortByTag();
//! Delete the metadatum at iterator position pos
void erase(iterator pos);
/*!
@brief Find the metadatum with the given ifd id and idx, return an
iterator to it.
This method can be used to uniquely identify a metadatum that was
created from an IFD or from the makernote (with idx greater than
0). Metadata created by an application (not read from an IFD or a
makernote) all have their idx field set to 0, i.e., they cannot be
uniquely identified with this method. If multiple metadata with the
same key exist, it is undefined which of the matching metadata is
found.
*/
const_iterator findIfdIdIdx(IfdId ifdId, int idx) const;
//! Get the number of metadata entries
long count() const { return metadata_.size(); }
/*!
@brief Return the approximate size of all %Exif data (TIFF header plus
metadata). The number returned may be bigger than the actual
size of the %Exif data, but it is never smaller. Only copy()
returns the exact size.
*/
long size() const;
//! Returns the byte order as specified in the TIFF header
ByteOrder byteOrder() const { return tiffHeader_.byteOrder(); }
/*!
@brief Write the thumbnail image to a file. The filename extension
will be set according to the image type of the thumbnail, so
@@ -489,44 +576,68 @@ namespace Exif {
Thumbnail::Type thumbnailType() const { return thumbnail_.type(); }
//! Return the size of the thumbnail data
long thumbnailSize() const { return thumbnail_.size(); }
//@}
private:
// Return a pointer to the internal IFD identified by its IFD id
const Ifd* getIfd(IfdId ifdId) const;
/*
Check if the metadata changed and update the internal IFDs if the
changes are compatible with the existing data (non-intrusive write
support). Return true if only compatible changes were detected in the
metadata and the internal IFDs (i.e., data buffer) were updated
successfully. Return false, if non-intrusive writing is not
possible. The internal IFDs and the data buffer may or may not be
modified in this case.
*/
bool updateIfds();
/*
Update the metadata of one IFD. Called by updateIfds() for each
of the internal IFDs.
*/
bool updateIfd(Ifd& ifd);
/*
Check if the metadata is compatible with the internal IFDs for
non-intrusive writing. Return true if compatible, false if not.
//! @name Accessors
//@{
/*!
@brief Check if the metadata is compatible with the internal IFDs for
non-intrusive writing. Return true if compatible, false if not.
Note: This function does not detect deleted metadata as incompatible,
although the deletion of metadata is not (yet) a supported
non-intrusive write operation.
@note This function does not detect deleted metadata as incompatible,
although the deletion of metadata is not (yet) a supported
non-intrusive write operation.
*/
bool compatible() const;
/*
Write Exif data to a data buffer the hard way, return number of bytes
written. Rebuilds the Exif data from scratch, using the TIFF header,
metadata container and thumbnail. In particular, the internal IFDs and
the original data buffer are not used. Furthermore, this method
updates the Exif data with the metadata from the actual thumbnail
image (overriding existing metadata).
/*!
@brief Find the IFD or makernote entry corresponding to ifd id and idx.
@return A pair of which the first part determines if a match was found
and, if true, the second contains an iterator to the entry.
*/
std::pair<bool, Entries::const_iterator>
findEntry(IfdId ifdId, int idx) const;
//! Return a pointer to the internal IFD identified by its IFD id
const Ifd* getIfd(IfdId ifdId) const;
//@}
//! @name Manipulators
//@{
/*!
@brief Check if the metadata changed and update the internal IFDs and
the MakerNote if the changes are compatible with the existing
data (non-intrusive write support).
@return True if only compatible changes were detected in the metadata
and the internal IFDs and MakerNote (and thus the data buffer)
were updated successfully. Return false, if non-intrusive
writing is not possible. The internal IFDs and the MakerNote
(and thus the data buffer) may or may not be modified in this
case.
*/
bool updateEntries();
/*!
@brief Update the metadata for a range of entries. Called by
updateEntries() for each of the internal IFDs and the MakerNote
(if any).
*/
bool updateRange(const Entries::iterator& begin,
const Entries::iterator& end);
/*!
@brief Write Exif data to a data buffer the hard way, return number of
bytes written.
Rebuilds the Exif data from scratch, using the TIFF header, metadata
container and thumbnail. In particular, the internal IFDs and the
original data buffer are not used. Furthermore, this method updates
the Exif data with the metadata from the actual thumbnail image
(overriding existing metadata).
*/
long copyFromMetadata(char* buf);
//@}
// DATA
TiffHeader tiffHeader_;
Metadata metadata_;
Thumbnail thumbnail_;