Changes for makernote write support, documentation updates
This commit is contained in:
+113
-55
@@ -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
@@ -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_;
|
||||
|
||||
Reference in New Issue
Block a user