Added ExifData setJpegThumbnail and op[] and Exifdatum op=. With the operator stuff you can now do things like: exifData["Exif.Thumbnail.Compression"] = uint16_t(6);

v0.27.3
Andreas Huggel 21 years ago
parent d05e3c1644
commit bd5b6d2ccc

@ -15,14 +15,29 @@
// *****************************************************************************
// Main
int main()
int main(int argc, char* const argv[])
try {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
std::string file(argv[1]);
// Container for all metadata
Exiv2::ExifData exifData;
// *************************************************************************
// Add to the Exif data
// This is the quickest way to add (simple) Exif data. If a metadatum for
// a given key already exists, its value is overwritten (without changing
// the type of the value). Otherwise a new tag is added.
exifData["Exif.Image.Model"] = "Test 1"; // AsciiValue
exifData["Exif.Image.SamplesPerPixel"] = uint16_t(162); // UShortValue
exifData["Exif.Image.XResolution"] = int32_t(-2); // LongValue
exifData["Exif.Image.YResolution"] = Exiv2::Rational(-2, 3); // RationalValue
std::cout << "Added a few tags the quick way.\n";
// Create a ASCII string value (note the use of create)
Exiv2::Value::AutoPtr v = Exiv2::Value::create(Exiv2::asciiString);
// Set the value to a string
@ -47,20 +62,18 @@ try {
// *************************************************************************
// Modify Exif data
// Find the timestamp metadatum by its key
key = Exiv2::ExifKey("Exif.Photo.DateTimeOriginal");
Exiv2::ExifData::iterator pos = exifData.findKey(key);
if (pos == exifData.end()) throw Exiv2::Error("Key not found");
// Modify the value
std::string date = pos->toString();
// Since we know that the metadatum exists (or we don't mind creating a new
// tag if it doesn't), we can simply do this:
Exiv2::Exifdatum& tag = exifData["Exif.Photo.DateTimeOriginal"];
std::string date = tag.toString();
date.replace(0, 4, "2000");
pos->setValue(date);
tag.setValue(date);
std::cout << "Modified key \"" << key
<< "\", new value \"" << pos->value() << "\"\n";
<< "\", new value \"" << tag.value() << "\"\n";
// Find the other key
// Alternatively, we can use findKey()
key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities");
pos = exifData.findKey(key);
Exiv2::ExifData::iterator pos = exifData.findKey(key);
if (pos == exifData.end()) throw Exiv2::Error("Key not found");
// Get a pointer to a copy of the value
v = pos->getValue();
@ -87,9 +100,9 @@ try {
// *************************************************************************
// Finally, write the remaining Exif data to an image file
int rc = exifData.write("img_2158.jpg");
int rc = exifData.write(file);
if (rc) {
std::string error = Exiv2::ExifData::strError(rc, "img_2158.jpg");
std::string error = Exiv2::ExifData::strError(rc, file);
throw Exiv2::Error(error);
}

@ -30,7 +30,7 @@
EXIV2_RCSID("@(#) $Id$");
// Define DEBUG_MAKERNOTE to output debug information to std::cerr
#define DEBUG_MAKERNOTE
#undef DEBUG_MAKERNOTE
// *****************************************************************************
// included header files
@ -51,6 +51,12 @@ EXIV2_RCSID("@(#) $Id$");
#include <map>
#include <cstring>
#include <cassert>
#include <cstdio>
#include <sys/types.h> // for stat()
#include <sys/stat.h> // for stat()
#ifdef HAVE_UNISTD_H
# include <unistd.h> // for stat()
#endif
// *****************************************************************************
// local declarations
@ -67,6 +73,9 @@ namespace {
uint32_t offset,
Exiv2::ByteOrder byteOrder);
// Read file path into a DataBuf, which is returned.
Exiv2::DataBuf readFile(const std::string& path);
}
// *****************************************************************************
@ -263,6 +272,17 @@ namespace Exiv2 {
delete[] pData_;
}
Exifdatum& ExifData::operator[](const std::string& key)
{
ExifKey exifKey(key);
iterator pos = findKey(exifKey);
if (pos == end()) {
add(Exifdatum(exifKey));
pos = findKey(exifKey);
}
return *pos;
}
int ExifData::read(const std::string& path)
{
if (!fileExists(path, true)) return -1;
@ -647,6 +667,37 @@ namespace Exiv2 {
return exifMetadata_.erase(pos);
}
void ExifData::setJpegThumbnail(const byte* buf, long size)
{
(*this)["Exif.Thumbnail.Compression"] = uint16_t(6);
Exifdatum& format = (*this)["Exif.Thumbnail.JPEGInterchangeFormat"];
format = uint32_t(0);
format.setDataArea(buf, size);
(*this)["Exif.Thumbnail.JPEGInterchangeFormatLength"] = uint32_t(size);
}
void ExifData::setJpegThumbnail(const byte* buf, long size,
URational xres, URational yres, uint16_t unit)
{
setJpegThumbnail(buf, size);
(*this)["Exif.Thumbnail.XResolution"] = xres;
(*this)["Exif.Thumbnail.YResolution"] = yres;
(*this)["Exif.Thumbnail.ResolutionUnit"] = unit;
}
void ExifData::setJpegThumbnail(const std::string& path)
{
DataBuf thumb = readFile(path);
setJpegThumbnail(thumb.pData_, thumb.size_);
}
void ExifData::setJpegThumbnail(const std::string& path,
URational xres, URational yres, uint16_t unit)
{
DataBuf thumb = readFile(path);
setJpegThumbnail(thumb.pData_, thumb.size_, xres, yres, unit);
}
long ExifData::eraseThumbnail()
{
// Delete all Exif.Thumbnail.* (IFD1) metadata
@ -826,7 +877,7 @@ namespace Exiv2 {
else {
// Hack: Set the entry's value only if there is no data area.
// This ensures that the original offsets are not overwritten
// with relative offsets from the ExifDatum (which require
// with relative offsets from the Exifdatum (which require
// conversion to offsets relative to the start of the TIFF
// header and that is currently only done in intrusive write
// mode). On the other hand, it is thus now not possible to
@ -1044,7 +1095,6 @@ namespace Exiv2 {
assert(md.key_.get() != 0);
return md.key_->printTag(os, md.value());
}
} // namespace Exiv2
// *****************************************************************************
@ -1070,4 +1120,19 @@ namespace {
pos->setValue(offset, byteOrder);
}
Exiv2::DataBuf readFile(const std::string& path)
{
Exiv2::FileCloser file(fopen(path.c_str(), "rb"));
if (!file.fp_)
throw Exiv2::Error("Couldn't open input file");
struct stat st;
if (0 != stat(path.c_str(), &st))
throw Exiv2::Error("Couldn't stat input file");
Exiv2::DataBuf buf(st.st_size);
long len = (long)fread(buf.pData_, 1, buf.size_, file.fp_);
if (len != buf.size_)
throw Exiv2::Error("Couldn't read input file");
return buf;
}
}

@ -66,6 +66,7 @@ namespace Exiv2 {
*/
class Exifdatum : public Metadatum {
friend std::ostream& operator<<(std::ostream&, const Exifdatum&);
template<typename T> friend Exifdatum& setValue(Exifdatum&, const T&);
public:
//! @name Creators
//@{
@ -76,12 +77,12 @@ namespace Exiv2 {
a program can create an 'empty' %Exifdatum with only a key
and set the value using setValue().
@param key ExifKey.
@param pValue Pointer to a Exifdatum value.
@param key %ExifKey.
@param pValue Pointer to an %Exifdatum value.
@throw Error ("Invalid key") if the key cannot be parsed and converted.
*/
explicit Exifdatum(const ExifKey& key, const Value* pValue =0);
//! Constructor to build a Exifdatum from an IFD entry.
//! Constructor to build an %Exifdatum from an IFD entry.
Exifdatum(const Entry& e, ByteOrder byteOrder);
//! Copy constructor
Exifdatum(const Exifdatum& rhs);
@ -93,6 +94,55 @@ namespace Exiv2 {
//@{
//! Assignment operator
Exifdatum& operator=(const Exifdatum& rhs);
/*!
@brief Assign \em value to the %Exifdatum. If the object already has a
value, it is replaced with \em value. Otherwise a new
AsciiValue value is created and set to \em value.
*/
Exifdatum& operator=(const std::string& value)
{ setValue(value); return *this; }
/*!
@brief Assign \em value to the %Exifdatum. If the object already has a
value, it is replaced with \em value. Otherwise a new
UShortValue value is created and set to \em value.
*/
Exifdatum& operator=(const uint16_t& value)
{ return Exiv2::setValue(*this, value); }
/*!
@brief Assign \em value to the %Exifdatum. If the object already has a
value, it is replaced with \em value. Otherwise a new
ULongValue value is created and set to \em value.
*/
Exifdatum& operator=(const uint32_t& value)
{ return Exiv2::setValue(*this, value); }
/*!
@brief Assign \em value to the %Exifdatum. If the object already has a
value, it is replaced with \em value. Otherwise a new
URational value is created and set to \em value.
*/
Exifdatum& operator=(const URational& value)
{ return Exiv2::setValue(*this, value); }
/*!
@brief Assign \em value to the %Exifdatum. If the object already has a
value, it is replaced with \em value. Otherwise a new
ShortValue value is created and set to \em value.
*/
Exifdatum& operator=(const int16_t& value)
{ return Exiv2::setValue(*this, value); }
/*!
@brief Assign \em value to the %Exifdatum. If the object already has a
value, it is replaced with \em value. Otherwise a new
LongValue value is created and set to \em value.
*/
Exifdatum& operator=(const int32_t& value)
{ return Exiv2::setValue(*this, value); }
/*!
@brief Assign \em value to the %Exifdatum. If the object already has a
value, it is replaced with \em value. Otherwise a new
Rational value is created and set to \em value.
*/
Exifdatum& operator=(const Rational& value)
{ return Exiv2::setValue(*this, value); }
/*!
@brief Set the value. This method copies (clones) the value pointed
to by \em pValue.
@ -275,6 +325,17 @@ namespace Exiv2 {
*/
std::ostream& operator<<(std::ostream& os, const Exifdatum& md);
/*!
@brief Set the value of \em exifDatum to \em value. If the object already
has a value, it is replaced. Otherwise a new ValueType\<T\> value
is created and set to \em value.
This is a helper function, called from Exifdatum members. It is meant to
be used with T = (u)int16_t, (u)int32_t or (U)Rational. Do not use directly.
*/
template<typename T>
Exifdatum& setValue(Exifdatum& exifDatum, const T& value);
/*!
@brief Exif %Thumbnail image. This abstract base class provides the
interface for the thumbnail image that is optionally embedded in
@ -509,6 +570,15 @@ namespace Exiv2 {
@return A %DataBuf containing the Exif data.
*/
DataBuf copy();
/*!
@brief Returns a reference to the %Exifdatum that is associated with a
particular \em key. If %ExifData does not already contain such
an %Exifdatum, operator[] adds object \em Exifdatum(key).
@note Since operator[] might insert a new element, it can't be a const
member function.
*/
Exifdatum& operator[](const std::string& key);
/*!
@brief Add all (IFD) entries in the range from iterator position begin
to iterator position end to the Exif metadata. No duplicate
@ -519,7 +589,7 @@ namespace Exiv2 {
Entries::const_iterator end,
ByteOrder byteOrder);
/*!
@brief Add a Exifdatum from the supplied key and value pair. This
@brief Add an Exifdatum from the supplied key and value pair. This
method copies (clones) key and value. No duplicate checks are
performed, i.e., it is possible to add multiple metadata with
the same key.
@ -567,6 +637,65 @@ namespace Exiv2 {
found.
*/
iterator findIfdIdIdx(IfdId ifdId, int idx);
/*!
@brief Set the Exif thumbnail to the Jpeg image \em path. Set
XResolution, YResolution and ResolutionUnit to \em xres,
\em yres and \em unit, respectively.
This results in the minimal thumbnail tags being set for a Jpeg
thumbnail, as mandated by the Exif standard.
@note No checks on the file format or size are performed.
@note Additional existing Exif thumbnail tags are not modified.
@throw Error ("Couldn't open input file") if fopen fails,
@throw Error ("Couldn't stat input file") if stat fails, or
@throw Error ("Couldn't read input file") if fread fails.
*/
void setJpegThumbnail(const std::string& path,
URational xres, URational yres, uint16_t unit);
/*!
@brief Set the Exif thumbnail to the Jpeg image pointed to by \em buf,
and size \em size. Set XResolution, YResolution and
ResolutionUnit to \em xres, \em yres and \em unit, respectively.
This results in the minimal thumbnail tags being set for a Jpeg
thumbnail, as mandated by the Exif standard.
@note No checks on the image format or size are performed.
@note Additional existing Exif thumbnail tags are not modified.
*/
void setJpegThumbnail(const byte* buf, long size,
URational xres, URational yres, uint16_t unit);
/*!
@brief Set the Exif thumbnail to the Jpeg image \em path.
This sets only the Compression, JPEGInterchangeFormat and
JPEGInterchangeFormatLength tags, which is not all the thumbnail
Exif information mandatory according to the Exif standard. (But it's
enough to work with the thumbnail.)
@note No checks on the file format or size are performed.
@note Additional existing Exif thumbnail tags are not modified.
@throw Error ("Couldn't open input file") if fopen fails,
@throw Error ("Couldn't stat input file") if stat fails, or
@throw Error ("Couldn't read input file") if fread fails.
*/
void setJpegThumbnail(const std::string& path);
/*!
@brief Set the Exif thumbnail to the Jpeg image pointed to by \em buf,
and size \em size.
This sets only the Compression, JPEGInterchangeFormat and
JPEGInterchangeFormatLength tags, which is not all the thumbnail
Exif information mandatory according to the Exif standard. (But it's
enough to work with the thumbnail.)
@note No checks on the image format or size are performed.
@note Additional existing Exif thumbnail tags are not modified.
*/
void setJpegThumbnail(const byte* buf, long size);
/*!
@brief Delete the thumbnail from the Exif data. Removes all
Exif.%Thumbnail.*, i.e., IFD1 metadata.
@ -769,8 +898,22 @@ namespace Exiv2 {
}; // class ExifData
// *****************************************************************************
// free functions
// template, inline and free functions
template<typename T>
Exifdatum& setValue(Exifdatum& exifDatum, const T& value)
{
if (exifDatum.value_.get() == 0) {
std::auto_ptr<ValueType<T> > v
= std::auto_ptr<ValueType<T> >(new ValueType<T>);
v->value_.push_back(value);
exifDatum.value_ = v;
}
else {
exifDatum.value_->read(Exiv2::toString(value));
}
return exifDatum;
}
/*!
@brief Add all metadata in the range from iterator position begin to
iterator position end, which have an IFD id matching that of the
@ -811,4 +954,3 @@ namespace Exiv2 {
} // namespace Exiv2
#endif // #ifndef EXIF_HPP_

@ -31,9 +31,7 @@ try {
std::cout <<"----- Some IFD0 tags\n";
Exiv2::ExifData ed1;
Exiv2::Exifdatum md1(Exiv2::ExifKey("Exif.Image.Model"));
md1.setValue("Test 1");
ed1.add(md1);
ed1["Exif.Image.Model"] = "Test 1";
Exiv2::Value::AutoPtr v1 = Exiv2::Value::create(Exiv2::unsignedShort);
v1->read("160 161 162 163");
@ -56,136 +54,86 @@ try {
std::cout <<"\n----- One Exif tag\n";
Exiv2::ExifData ed2;
Exiv2::Exifdatum md2(Exiv2::ExifKey("Exif.Photo.DateTimeOriginal"));
md2.setValue("Test 2");
ed2.add(md2);
ed2["Exif.Photo.DateTimeOriginal"] = "Test 2";
write(file, ed2);
print(file);
std::cout <<"\n----- One Canon MakerNote tag\n";
Exiv2::ExifData edMn1;
Exiv2::Exifdatum mdMn1(Exiv2::ExifKey("Exif.Image.Make"));
mdMn1.setValue("Canon");
edMn1.add(mdMn1);
Exiv2::Exifdatum mdMn2(Exiv2::ExifKey("Exif.Image.Model"));
mdMn2.setValue("Canon PowerShot S40");
edMn1.add(mdMn2);
Exiv2::Exifdatum mdMn3(Exiv2::ExifKey("Exif.Canon.0xabcd"));
mdMn3.setValue("A Canon makernote tag");
edMn1.add(mdMn3);
edMn1["Exif.Image.Make"] = "Canon";
edMn1["Exif.Image.Model"] = "Canon PowerShot S40";
edMn1["Exif.Canon.0xabcd"] = "A Canon makernote tag";
write(file, edMn1);
print(file);
std::cout <<"\n----- One Fujifilm MakerNote tag\n";
Exiv2::ExifData edMn2;
Exiv2::Exifdatum mdMn4(Exiv2::ExifKey("Exif.Image.Make"));
mdMn4.setValue("FUJIFILM");
edMn2.add(mdMn4);
Exiv2::Exifdatum mdMn5(Exiv2::ExifKey("Exif.Image.Model"));
mdMn5.setValue("FinePixS2Pro");
edMn2.add(mdMn5);
Exiv2::Exifdatum mdMn6(Exiv2::ExifKey("Exif.Fujifilm.0x1000"));
mdMn6.setValue("A Fujifilm QUALITY tag");
edMn2.add(mdMn6);
edMn2["Exif.Image.Make"] = "FUJIFILM";
edMn2["Exif.Image.Model"] = "FinePixS2Pro";
edMn2["Exif.Fujifilm.0x1000"] = "A Fujifilm QUALITY tag";
write(file, edMn2);
print(file);
std::cout <<"\n----- One Sigma/Foveon MakerNote tag\n";
Exiv2::ExifData edMn3;
Exiv2::Exifdatum mdMn7(Exiv2::ExifKey("Exif.Image.Make"));
mdMn7.setValue("SIGMA");
edMn3.add(mdMn7);
Exiv2::Exifdatum mdMn8(Exiv2::ExifKey("Exif.Image.Model"));
mdMn8.setValue("SIGMA SD10");
edMn3.add(mdMn8);
Exiv2::Exifdatum mdMn9(Exiv2::ExifKey("Exif.Sigma.0x0018"));
mdMn9.setValue("Software? Exiv2!");
edMn3.add(mdMn9);
edMn3["Exif.Image.Make"] = "SIGMA";
edMn3["Exif.Image.Model"] = "SIGMA SD10";
edMn3["Exif.Sigma.0x0018"] = "Software? Exiv2!";
write(file, edMn3);
print(file);
std::cout <<"\n----- One Nikon1 MakerNote tag\n";
Exiv2::ExifData edMn4;
Exiv2::Exifdatum mdMn10(Exiv2::ExifKey("Exif.Image.Make"));
mdMn10.setValue("NIKON");
edMn4.add(mdMn10);
Exiv2::Exifdatum mdMn11(Exiv2::ExifKey("Exif.Image.Model"));
mdMn11.setValue("E990");
edMn4.add(mdMn11);
Exiv2::Exifdatum mdMn12(Exiv2::ExifKey("Exif.Nikon1.0x0080"));
mdMn12.setValue("ImageAdjustment by Exiv2");
edMn4.add(mdMn12);
edMn4["Exif.Image.Make"] = "NIKON";
edMn4["Exif.Image.Model"] = "E990";
edMn4["Exif.Nikon1.0x0080"] = "ImageAdjustment by Exiv2";
write(file, edMn4);
print(file);
std::cout <<"\n----- One Nikon2 MakerNote tag\n";
Exiv2::ExifData edMn5;
Exiv2::Exifdatum mdMn13(Exiv2::ExifKey("Exif.Image.Make"));
mdMn13.setValue("NIKON");
edMn5.add(mdMn13);
Exiv2::Exifdatum mdMn14(Exiv2::ExifKey("Exif.Image.Model"));
mdMn14.setValue("E950");
edMn5.add(mdMn14);
Exiv2::Exifdatum mdMn15(Exiv2::ExifKey("Exif.Nikon2.0xffff"));
mdMn15.setValue("An obscure Nikon2 tag");
edMn5.add(mdMn15);
edMn5["Exif.Image.Make"] = "NIKON";
edMn5["Exif.Image.Model"] = "E950";
edMn5["Exif.Nikon2.0xffff"] = "An obscure Nikon2 tag";
write(file, edMn5);
print(file);
std::cout <<"\n----- One Nikon3 MakerNote tag\n";
Exiv2::ExifData edMn6;
Exiv2::Exifdatum mdMn16(Exiv2::ExifKey("Exif.Image.Make"));
mdMn16.setValue("NIKON CORPORATION");
edMn6.add(mdMn16);
Exiv2::Exifdatum mdMn17(Exiv2::ExifKey("Exif.Image.Model"));
mdMn17.setValue("NIKON D70");
edMn6.add(mdMn17);
Exiv2::Exifdatum mdMn18(Exiv2::ExifKey("Exif.Nikon3.0x0004"));
mdMn18.setValue("A boring Nikon3 Quality tag");
edMn6.add(mdMn18);
edMn6["Exif.Image.Make"] = "NIKON CORPORATION";
edMn6["Exif.Image.Model"] = "NIKON D70";
edMn6["Exif.Nikon3.0x0004"] = "A boring Nikon3 Quality tag";
write(file, edMn6);
print(file);
std::cout <<"\n----- One IOP tag\n";
Exiv2::ExifData ed3;
Exiv2::Exifdatum md3(Exiv2::ExifKey("Exif.Iop.InteroperabilityVersion"));
md3.setValue("Test 3");
ed3.add(md3);
ed3["Exif.Iop.InteroperabilityVersion"] = "Test 3";
write(file, ed3);
print(file);
std::cout <<"\n----- One GPS tag\n";
Exiv2::ExifData ed4;
Exiv2::Exifdatum md4(Exiv2::ExifKey("Exif.GPSInfo.GPSVersionID"));
md4.setValue("Test 4");
ed4.add(md4);
ed4["Exif.GPSInfo.GPSVersionID"] = "Test 4";
write(file, ed4);
print(file);
std::cout <<"\n----- One IFD1 tag\n";
Exiv2::ExifData ed5;
Exiv2::Exifdatum md5(Exiv2::ExifKey("Exif.Thumbnail.Artist"));
md5.setValue("Test 5");
ed5.add(md5);
ed5["Exif.Thumbnail.Artist"] = "Test 5";
write(file, ed5);
print(file);
std::cout <<"\n----- One IOP and one IFD1 tag\n";
Exiv2::ExifData ed6;
Exiv2::Exifdatum md6(Exiv2::ExifKey("Exif.Iop.InteroperabilityVersion"));
md6.setValue("Test 6 Iop tag");
ed6.add(md6);
Exiv2::Exifdatum md7(Exiv2::ExifKey("Exif.Thumbnail.Artist"));
md7.setValue("Test 6 Ifd1 tag");
ed6.add(md7);
ed6["Exif.Iop.InteroperabilityVersion"] = "Test 6 Iop tag";
ed6["Exif.Thumbnail.Artist"] = "Test 6 Ifd1 tag";
write(file, ed6);
print(file);
std::cout <<"\n----- One IFD0 and one IFD1 tag\n";
Exiv2::ExifData ed7;
Exiv2::Exifdatum md8(Exiv2::ExifKey("Exif.Thumbnail.Artist"));
md8.setValue("Test 7");
ed7.add(md8);
ed7["Exif.Thumbnail.Artist"] = "Test 7";
Exiv2::Value::AutoPtr v5 = Exiv2::Value::create(Exiv2::unsignedShort);
v5->read("160 161 162 163");
ed7.add(Exiv2::ExifKey("Exif.Image.SamplesPerPixel"), v5.get());

Loading…
Cancel
Save