Merged unstable branch to trunk.

v0.27.3
Andreas Huggel 17 years ago
parent b47b8085db
commit 0d55992e2f

@ -58,22 +58,19 @@ BINSRC = addmoddel.cpp \
convert-test.cpp \
crwedit.cpp \
crwparse.cpp \
dataarea-test.cpp \
exifcomment.cpp \
exifdata-test.cpp \
exifprint.cpp \
ifd-test.cpp \
iotest.cpp \
iptceasy.cpp \
iptcprint.cpp \
iptctest.cpp \
key-test.cpp \
largeiptc-test.cpp \
makernote-test.cpp \
stringto-test.cpp \
tiff-test.cpp \
write-test.cpp \
write2-test.cpp \
tiffparse.cpp \
xmpparse.cpp \
xmpparser-test.cpp \
xmpsample.cpp

@ -75,7 +75,7 @@ try {
ed3["Exif.Photo.DateTimeOriginal"] = "Sunday, 11am";
ed3["Exif.Photo.MeteringMode"] = uint16_t(1);
ed3["Exif.Iop.InteroperabilityIndex"] = "123";
// ed3["Exif.Thumbnail.Orientation"] = uint16_t(2);
ed3["Exif.Thumbnail.Orientation"] = uint16_t(2);
write(file, ed3);
print(file);
std::cout << "----------------------------------------------\n";

@ -1,209 +0,0 @@
// ***************************************************************** -*- C++ -*-
/*
Abstract : Simple test program to test class Ifd.
File : ifd-test.cpp
Version : $Rev$
Author(s): Andreas Huggel (ahu)
History : 15-Feb-05, ahu
*/
// *****************************************************************************
// included header files
#include <exiv2/ifd.hpp>
#include <exiv2/error.hpp>
#include <iostream>
#include <string>
#include <cstring>
int main()
try {
// -------------------------------------------------------------------------
std::cout << "Read standard Ifd from data buffer\n";
const long len = 77;
Exiv2::byte buf[]
= { 0xff, // Filler
// No
0x00,0x04,
// Tag Type Components Offset/Data
0x00,0x01, 0x00,0x02, 0x00,0x00,0x00,0x04, 'T', 'h', 'e', '\0',
0x00,0x02, 0x00,0x02, 0x00,0x00,0x00,0x06, 0x00,0x00,0x00,0x37,
0x00,0x03, 0x00,0x02, 0x00,0x00,0x00,0x07, 0x00,0x00,0x00,0x3d,
0x00,0x04, 0x00,0x02, 0x00,0x00,0x00,0x09, 0x00,0x00,0x00,0x44,
// Next
0x00,0x00,0x00,0x00,
// Data
'K', 'u', 'a', 'l', 'a', '\0',
'L', 'u', 'm', 'p', 'u', 'r', '\0',
'M', 'a', 'l', 'a', 'y', 's', 'i', 'a', '\0'
};
Exiv2::Ifd ifd(Exiv2::ifd0Id, 0, false);
int rc = ifd.read(buf, len, 1, Exiv2::bigEndian);
if (rc) {
std::cout << "Ifd::read (1) failed, rc = " << rc << "\n";
return rc;
}
ifd.print(std::cout);
Exiv2::Ifd::iterator pos = ifd.findTag(0x0004);
if (pos == ifd.end()) {
std::cout << "Tag not found!\n";
return 1;
}
Exiv2::byte data[] = { 'T', 'H', 'R', 'E', 'E', '\0' };
std::cout << "Setting value of entry 3...\n";
pos->setValue(2, 6, data, 6);
Exiv2::DataBuf db(1024);
rc = ifd.copy(db.pData_ + 1, Exiv2::bigEndian);
std::cout << "Wrote " << rc << " characters to data buffer\n";
rc = ifd.read(db.pData_, len, 1, Exiv2::bigEndian);
if (rc) {
std::cout << "Ifd::read (1a) failed, rc = " << rc << "\n";
return rc;
}
ifd.print(std::cout);
// -------------------------------------------------------------------------
std::cout << "\nRead non-standard Ifd from data buffer\n";
const long len2 = 76;
Exiv2::byte buf2[]
= { // Data
'K', 'u', 'a', 'l', 'a', '\0',
'L', 'u', 'm', 'p', 'u', 'r', '\0',
'M', 'a', 'l', 'a', 'y', 's', 'i', 'a', '\0',
// No
0x00,0x04,
// Tag Type Components Offset/Data
0x00,0x01, 0x00,0x02, 0x00,0x00,0x00,0x04, 'T', 'h', 'e', '\0',
0x00,0x02, 0x00,0x02, 0x00,0x00,0x00,0x06, 0x00,0x00,0x00,0x00,
0x00,0x03, 0x00,0x02, 0x00,0x00,0x00,0x07, 0x00,0x00,0x00,0x06,
0x00,0x04, 0x00,0x02, 0x00,0x00,0x00,0x09, 0x00,0x00,0x00,0x0d,
// Next
0x00,0x00,0x00,0x00
};
Exiv2::Ifd ifd2(Exiv2::ifd0Id, 0, false);
rc = ifd2.read(buf2, len2, 22, Exiv2::bigEndian);
if (rc) {
std::cout << "Ifd::read (2) failed, rc = " << rc << "\n";
return rc;
}
ifd2.print(std::cout);
pos = ifd2.findTag(0x0004);
if (pos == ifd2.end()) {
std::cout << "Tag not found!\n";
return 1;
}
Exiv2::byte data2[] = { 'T', 'H', 'R', 'E', 'E', '\0' };
std::cout << "Setting value of entry 3...\n";
pos->setValue(2, 6, data2, 6);
ifd2.print(std::cout);
// -------------------------------------------------------------------------
std::cout << "\nTest boundary checks, the following reads should generate warnings or errors\n";
std::cout << "--- read (3)" << std::endl;
rc = ifd.read(buf, len-1, 1, Exiv2::bigEndian);
if (rc) {
std::cout << "Ifd::read (3) failed, rc = " << rc << "\n";
}
std::cout << "--- read (4)" << std::endl;
rc = ifd.read(buf, len-17, 1, Exiv2::bigEndian);
if (rc) {
std::cout << "Ifd::read (4) failed, rc = " << rc << "\n";
}
std::cout << "--- read (5)" << std::endl;
rc = ifd.read(buf, len-16, 1, Exiv2::bigEndian);
if (rc) {
std::cout << "Ifd::read (5) failed, rc = " << rc << "\n";
}
std::cout << "--- read (6)" << std::endl;
rc = ifd.read(buf, len-23, 1, Exiv2::bigEndian);
if (rc) {
std::cout << "Ifd::read (6) failed, rc = " << rc << "\n";
}
std::cout << "--- read (7)" << std::endl;
rc = ifd2.read(buf2, len2-1, 22, Exiv2::bigEndian);
if (rc) {
std::cout << "Ifd::read (7) failed, rc = " << rc << "\n";
}
// -------------------------------------------------------------------------
std::cout << "\nCreate Ifd from scratch\n";
Exiv2::Ifd ifd3(Exiv2::ifd0Id);
Exiv2::Entry e;
e.setIfdId(Exiv2::ifd0Id);
e.setIdx(0);
e.setTag(0x0001);
e.setOffset(0); // will be calculated when the IFD is written
Exiv2::byte data0x01[] = { 'T', 'h', 'e', '\0' };
e.setValue(2, 4, data0x01, 4);
ifd3.add(e);
e.setTag(0x0002);
e.setOffset(0); // will be calculated when the IFD is written
Exiv2::byte data0x02[] = { 'K', 'u', 'a', 'l', 'a', '\0' };
e.setValue(2, 6, data0x02, 6);
ifd3.add(e);
e.setTag(0x0003);
e.setOffset(0); // will be calculated when the IFD is written
Exiv2::byte data0x03[] = { 'L', 'u', 'm', 'p', 'u', 'r', '\0' };
e.setValue(2, 7, data0x03, 7);
ifd3.add(e);
e.setTag(0x0004);
e.setOffset(0); // will be calculated when the IFD is written
Exiv2::byte data0x04[] = { 'M', 'a', 'l', 'a', 'y', 's', 'i', 'a', '\0' };
e.setValue(2, 9, data0x04, 9);
ifd3.add(e);
Exiv2::DataBuf ibuf(256);
long len3 = ifd3.copy(ibuf.pData_, Exiv2::bigEndian);
Exiv2::Ifd ifd4(Exiv2::ifd0Id, 0, false);
rc = ifd4.read(ibuf.pData_, len3, 0, Exiv2::bigEndian);
if (rc) {
std::cout << "Ifd::read (8) failed, rc = " << rc << "\n";
}
ifd4.print(std::cout);
// -------------------------------------------------------------------------
std::cout << "\nMove data buffer\n";
Exiv2::Ifd ifd5(Exiv2::ifd0Id, 0, false);
rc = ifd5.read(buf, len, 1, Exiv2::bigEndian);
if (rc) {
std::cout << "Ifd::read (1) failed, rc = " << rc << "\n";
return rc;
}
ifd5.print(std::cout);
Exiv2::byte* newBuf = new Exiv2::byte[len];
std::memset(newBuf, 0x00, len);
std::memcpy(newBuf, buf, len);
std::memset(buf, 0x0, len);
ifd5.updateBase(newBuf);
ifd5.print(std::cout);
delete[] newBuf;
return 0;
}
catch (const Exiv2::AnyError& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return 1;
}

@ -122,86 +122,6 @@ int main()
// -----
long len = 76;
byte buf[]
= { // No
0x00,0x04,
// Tag Type Components Offset/Data
0x00,0x01, 0x00,0x02, 0x00,0x00,0x00,0x04, 'T', 'h', 'e', '\0',
0x00,0x02, 0x00,0x02, 0x00,0x00,0x00,0x06, 0x00,0x00,0x00,0x37,
0x00,0x03, 0x00,0x02, 0x00,0x00,0x00,0x07, 0x00,0x00,0x00,0x3d,
0x00,0x04, 0x00,0x02, 0x00,0x00,0x00,0x09, 0x00,0x00,0x00,0x44,
// Next
0x00,0x00,0x00,0x00,
// Data
'K', 'u', 'a', 'l', 'a', '\0',
'L', 'u', 'm', 'p', 'u', 'r', '\0',
'M', 'a', 'l', 'a', 'y', 's', 'i', 'a', '\0'
};
Ifd ifd(Exiv2::iopIfdId, 0, false);
int ret = ifd.read(buf, len, 0, bigEndian, 1);
if (ret) {
std::cout << "Ifd::read failed, ret = " << ret << "\n";
return ret;
}
Ifd::const_iterator i = ifd.findTag(0x0002);
if (i == ifd.end()) {
std::cout << "Ifd::findTag failed" << "\n";
}
else {
ExifKey ek3(*i);
// operator<<
tc += 1;
std::ostringstream os2;
os2 << ek3;
if (os2.str() != key) {
std::cout << "Testcase failed (operator<<)" << std::endl;
rc += 1;
}
// familyName
tc += 1;
if (std::string(ek3.familyName()) != "Exif") {
std::cout << "Testcase failed (familyName)" << std::endl;
rc += 1;
}
// groupName
tc += 1;
if (ek3.groupName() != "Iop") {
std::cout << "Testcase failed (groupName)" << std::endl;
rc += 1;
}
// tagName
tc += 1;
if (ek3.tagName() != "InteroperabilityVersion") {
std::cout << "Testcase failed (tagName)" << std::endl;
rc += 1;
}
// tagName
tc += 1;
if (ek3.tag() != 0x0002) {
std::cout << "Testcase failed (tag)" << std::endl;
rc += 1;
}
// ifdName
tc += 1;
if (std::string(ek3.ifdName()) != "Iop") {
std::cout << "Testcase failed (ifdName: " << std::endl;
rc += 1;
}
// sectionName
tc += 1;
if (ek3.sectionName() != "Interoperability") {
std::cout << "Testcase failed (sectionName)" << std::endl;
rc += 1;
}
}
// -----
ExifKey ek4("Exif.Image.0x0110");
tc += 1;
if (ek4.key() != "Exif.Image.Model") {

@ -47,7 +47,7 @@ try {
uint32_t sizeHdr;
uint32_t sizeData;
Exiv2::Photoshop::locateIptcIrb(irb.pData_, irb.size_, &record, &sizeHdr, &sizeData);
Exiv2::DataBuf rawIptc = iptcData.copy();
Exiv2::DataBuf rawIptc = Exiv2::IptcParser::encode(iptcData);
std::cout << "Comparing IPTC and IRB size... ";
if (static_cast<uint32_t>(rawIptc.size_) != sizeData) {
std::cout << "not ";

@ -1,49 +0,0 @@
#include <exiv2/makernote.hpp>
#include <iostream>
#include <string>
#include <utility>
void testMatch(const std::string& reg, const std::string& key);
int main()
{
testMatch("Canon", "Canon");
testMatch("Canon*", "Canon");
testMatch("Canon*", "Canon Corp.");
testMatch("PENTAX*", "PENTAX Corporation");
testMatch("*foo*bar*", "foobar");
testMatch("*foo*bar*", "barfoofoobarbar");
testMatch("foo*bar", "foo");
testMatch("foo*bar", "bar");
testMatch("foo*bar", "foobar");
testMatch("foo*bar", "fooYAHOObar");
testMatch("foo*bar", "Thefoobar");
testMatch("foo*bar", "foobarTrick");
testMatch("foo*bar", "ThefoobarTrick");
testMatch("foo*bar", "ThefooYAHOObarTrick");
testMatch("*", "anything");
testMatch("**", "anything times two");
testMatch("*bar", "bar");
testMatch("b*bar", "bar");
testMatch("b*bar", "bbar");
testMatch("*foobar", "bar");
testMatch("*bar", "foobar");
return 0;
}
void testMatch(const std::string& reg, const std::string& key)
{
int rc = Exiv2::MakerNoteFactory::match(reg, key);
if (rc) {
std::cout << "Key '" << key << "' matches '" << reg << "' "
<< "with a score of " << rc << ".\n";
}
else {
std::cout << "Key '" << key << "' does not match '" << reg << "'.\n";
}
}

@ -0,0 +1,108 @@
// ***************************************************************** -*- C++ -*-
// tiff-test.cpp, $Rev$
// First and very simple TIFF write test.
#include <exiv2/tiffimage.hpp>
#include <exiv2/exif.hpp>
#include <exiv2/error.hpp>
#include <string>
#include <iostream>
#include <iomanip>
#include <cassert>
using namespace Exiv2;
void print(const ExifData& exifData);
void mini1(const char* path);
void mini9(const char* path);
int main(int argc, char* const argv[])
try {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
const char* path = argv[1];
mini1(path);
mini9(path);
return 0;
}
catch (const AnyError& e) {
std::cout << e << "\n";
}
void mini1(const char* path)
{
ExifData exifData;
Blob blob;
WriteMethod wm;
// Write nothing to a new structure, without a previous binary image
wm = ExifParser::encode(blob, 0, 0, bigEndian, exifData);
assert(wm == wmIntrusive);
assert(blob.size() == 0);
std::cout << "Test 1: Writing empty Exif data without original binary data: ok.\n";
// Write nothing, this time with a previous binary image
DataBuf buf = readFile(path);
wm = ExifParser::encode(blob, buf.pData_, buf.size_, bigEndian, exifData);
assert(wm == wmIntrusive);
assert(blob.size() == 0);
std::cout << "Test 2: Writing empty Exif data with original binary data: ok.\n";
// Write something to a new structure, without a previous binary image
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
wm = ExifParser::encode(blob, 0, 0, bigEndian, exifData);
assert(wm == wmIntrusive);
std::cout << "Test 3: Wrote non-empty Exif data without original binary data:\n";
exifData.clear();
ByteOrder bo = ExifParser::decode(exifData, &blob[0], blob.size());
assert(bo == bigEndian);
print(exifData);
}
void mini9(const char* path)
{
TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false);
tiffImage.readMetadata();
std::cout << "MIME type: " << tiffImage.mimeType() << "\n";
std::cout << "Image size: " << tiffImage.pixelWidth() << " x " << tiffImage.pixelHeight() << "\n";
ExifData& exifData = tiffImage.exifData();
std::cout << "Before\n";
print(exifData);
std::cout << "======\n";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
std::cout << "After\n";
print(exifData);
tiffImage.writeMetadata();
}
void print(const ExifData& exifData)
{
if (exifData.empty()) {
std::string error("No Exif data found in the file");
throw Exiv2::Error(1, error);
}
Exiv2::ExifData::const_iterator end = exifData.end();
for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i) {
std::cout << std::setw(44) << std::setfill(' ') << std::left
<< i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right
<< std::hex << i->tag() << " "
<< std::setw(9) << std::setfill(' ') << std::left
<< i->typeName() << " "
<< std::dec << std::setw(3)
<< std::setfill(' ') << std::right
<< i->count() << " "
<< std::dec << i->value()
<< "\n";
}
}

@ -0,0 +1,136 @@
// ***************************************************************** -*- C++ -*-
// tiffaddpath-test.cpp, $Rev$
// Test driver to test adding new tags to a TIFF composite structure
#include "tiffcomposite_int.hpp"
#include "makernote2_int.hpp"
#include "tiffimage_int.hpp"
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstdlib>
using namespace Exiv2;
void addPath(TiffComponent* pRootDir,
uint16_t tag,
TiffPath& tiffPath);
void printPath(TiffPath tiffPath,
uint32_t tag,
uint16_t grp);
struct TiffTagInfo {
bool operator==(const uint32_t& tag) const;
uint32_t tag_;
const char* name_;
};
extern const TiffTagInfo tiffTagInfo[] = {
{ 0x10000, "none" },
{ 0x20000, "root" },
{ 0x30000, "next" },
{ 0x40000, "all" }
};
bool TiffTagInfo::operator==(const uint32_t& tag) const
{
return tag_ == tag;
}
std::string tiffTagName(uint32_t tag)
{
const TiffTagInfo* gi = find(tiffTagInfo, tag);
std::string name;
if (gi != 0) {
name = gi->name_;
}
else {
std::ostringstream os;
os << "0x" << std::hex << std::setw(4)
<< std::setfill('0') << std::right << tag;
name = os.str();
}
return name;
}
// -----------------------------------------------------------------------------
// Main program
int main(int argc, char* const argv[])
{
if (argc != 3) {
std::cout << "Usage: " << argv[0] << " tag group\n"
<< "Print the TIFF path for a tag and group (decimal numbers)\n";
return 1;
}
uint32_t tag = atol(argv[1]);
uint16_t grp = atol(argv[2]);
TiffComponent* pRootDir = new TiffDirectory(0, 1);
TiffPath tiffPath1;
TiffCreator::getPath(tiffPath1, tag, grp);
printPath(tiffPath1, tag, grp);
addPath(pRootDir, tag, tiffPath1);
++tag;
TiffPath tiffPath2;
TiffCreator::getPath(tiffPath2, tag, grp);
printPath(tiffPath2, tag, grp);
addPath(pRootDir, tag, tiffPath2);
return 0;
}
// -----------------------------------------------------------------------------
void addPath(TiffComponent* pRootDir,
uint16_t tag,
TiffPath& tiffPath)
{
TiffComponent* tc = pRootDir->addPath(tag, tiffPath);
TiffPrinter tiffPrinter(std::cout);
pRootDir->accept(tiffPrinter);
std::cout << std::endl;
if (tc) {
std::cout << "Added tag " << tiffTagName(tc->tag())
<< ", group " << tiffGroupName(tc->group()) << "\n";
}
else {
std::cout << "No tag added\n";
}
std::cout << std::endl;
}
// -----------------------------------------------------------------------------
void printPath(TiffPath tiffPath,
uint32_t tag,
uint16_t grp)
{
std::cout << "\nTiff path for tag "
<< std::setw(6) << std::setfill(' ') << std::left
<< tiffTagName(tag)
<< ", group " << tiffGroupName(grp)
<< " (id = " << std::dec << grp << "):\n\n"
<< "ext. tag group new group \n"
<< "-------- ------------ ------------\n";
while (!tiffPath.empty())
{
const TiffStructure* ts = tiffPath.top();
tiffPath.pop();
std::cout << std::setw(8) << std::setfill(' ') << std::left
<< tiffTagName(ts->extendedTag_)
<< " " << std::setw(12) << std::setfill(' ') << std::left
<< tiffGroupName(ts->group_)
<< " " << std::setw(12) << std::setfill(' ') << std::left
<< tiffGroupName(ts->newGroup_)
<< "\n";
}
std::cout << std::endl;
}

@ -17,7 +17,6 @@
// included header files
#include <exiv2/image.hpp>
#include <exiv2/exif.hpp>
#include <exiv2/makernote.hpp>
#include <iostream>
#include <sstream>
@ -195,7 +194,8 @@ void testCase(const std::string& file1,
exifPrint(ed2);
std::cerr << "---> Writing Exif thumbnail to file " << thumb << ".*\n";
ed2.writeThumbnail(thumb);
ExifThumbC et2(ed2);
et2.writeFile(thumb);
}
// *****************************************************************************

@ -63,7 +63,6 @@ CCHDR = exv_conf.h \
exv_msvc.h \
mn.hpp \
rcsid.hpp \
tifffwd.hpp \
version.hpp
# Add library C++ source files to this list
@ -79,12 +78,10 @@ CCSRC = basicio.cpp \
futils.cpp \
fujimn.cpp \
gifimage.cpp \
ifd.cpp \
image.cpp \
iptc.cpp \
jp2image.cpp \
jpgimage.cpp \
makernote.cpp \
makernote2.cpp \
metadatum.cpp \
minoltamn.cpp \
@ -106,7 +103,6 @@ CCSRC += psdimage.cpp \
tgaimage.cpp \
tiffcomposite.cpp \
tiffimage.cpp \
tiffparser.cpp \
tiffvisitor.cpp \
types.cpp \
value.cpp \

@ -97,14 +97,16 @@ namespace {
time_t modtime_;
};
// Convert a string "YYYY:MM:DD HH:MI:SS" to a struct tm type,
// returns 0 if successful
/*!
@brief Convert a string "YYYY:MM:DD HH:MI:SS" to a struct tm type,
returns 0 if successful
*/
int str2Tm(const std::string& timeStr, struct tm* tm);
// Convert a UTC time to a string "YYYY:MM:DD HH:MI:SS", "" on error
//! Convert a UTC time to a string "YYYY:MM:DD HH:MI:SS", "" on error
std::string time2Str(time_t time);
// Convert a tm structure to a string "YYYY:MM:DD HH:MI:SS", "" on error
//! Convert a tm structure to a string "YYYY:MM:DD HH:MI:SS", "" on error
std::string tm2Str(struct tm* tm);
/*!
@ -137,8 +139,9 @@ namespace {
/*!
@brief Make a file path from the current file path, destination
directory (if any) and the filename extension passed in.
@param path Path of the existing file
@param ext New filename extension (incl. the dot '.' if required)
@param ext New filename extension (incl. the dot '.' if required)
@return 0 if successful, 1 if the new file exists and the user
chose not to overwrite it.
*/
@ -550,13 +553,14 @@ namespace Action {
// Thumbnail
printLabel(_("Thumbnail"));
std::string thumbExt = exifData.thumbnailExtension();
Exiv2::ExifThumbC exifThumb(exifData);
std::string thumbExt = exifThumb.extension();
if (thumbExt.empty()) {
std::cout << _("None");
}
else {
Exiv2::DataBuf buf = exifData.copyThumbnail();
std::cout << exifData.thumbnailFormat() << ", "
Exiv2::DataBuf buf = exifThumb.copy();
std::cout << exifThumb.mimeType() << ", "
<< buf.size_ << " " << _("Bytes");
}
std::cout << std::endl;
@ -710,7 +714,7 @@ namespace Action {
continue;
}
Exiv2::DataBuf buf(md->size());
md->copy(buf.pData_, exifData.byteOrder());
md->copy(buf.pData_, image->byteOrder());
Exiv2::hexdump(std::cout, buf.pData_, buf.size_);
}
std::cout << std::endl;
@ -958,15 +962,14 @@ namespace Action {
int Erase::eraseThumbnail(Exiv2::Image* image) const
{
Exiv2::ExifData& exifData = image->exifData();
std::string thumbExt = exifData.thumbnailExtension();
Exiv2::ExifThumb exifThumb(image->exifData());
std::string thumbExt = exifThumb.extension();
if (thumbExt.empty()) {
return 0;
}
long delta = exifData.eraseThumbnail();
exifThumb.erase();
if (Params::instance().verbose_) {
std::cout << _("Erasing") << " " << delta
<< " " << _("Bytes of thumbnail data") << std::endl;
std::cout << _("Erasing thumbnail data") << std::endl;
}
return 0;
}
@ -1061,7 +1064,8 @@ namespace Action {
return -3;
}
int rc = 0;
std::string thumbExt = exifData.thumbnailExtension();
Exiv2::ExifThumb exifThumb(exifData);
std::string thumbExt = exifThumb.extension();
if (thumbExt.empty()) {
std::cerr << path_ << ": " << _("Image does not contain an Exif thumbnail\n");
}
@ -1070,14 +1074,13 @@ namespace Action {
std::string thumbPath = thumb + thumbExt;
if (dontOverwrite(thumbPath)) return 0;
if (Params::instance().verbose_) {
Exiv2::DataBuf buf = exifData.copyThumbnail();
std::cout << _("Writing") << " "
<< exifData.thumbnailFormat() << " " << _("thumbnail") << " ("
Exiv2::DataBuf buf = exifThumb.copy();
std::cout << _("Writing thumbnail") << " (" << exifThumb.mimeType() << ", "
<< buf.size_ << " " << _("Bytes") << ") " << _("to file") << " "
<< thumbPath << std::endl;
}
rc = exifData.writeThumbnail(thumb);
if (rc) {
rc = exifThumb.writeFile(thumb);
if (rc == 0) {
std::cerr << path_ << ": " << _("Exif data doesn't contain a thumbnail\n");
}
}
@ -1176,8 +1179,8 @@ namespace Action {
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path);
assert(image.get() != 0);
image->readMetadata();
Exiv2::ExifData& exifData = image->exifData();
exifData.setJpegThumbnail(thumbPath);
Exiv2::ExifThumb exifThumb(image->exifData());
exifThumb.setJpegThumbnail(thumbPath);
image->writeMetadata();
return 0;
@ -1637,6 +1640,7 @@ namespace Action {
// local definitions
namespace {
//! @cond IGNORE
int Timestamp::read(const std::string& path)
{
struct stat buf;
@ -1668,6 +1672,7 @@ namespace {
buf.modtime = modtime_;
return utime(path.c_str(), &buf);
}
//! @endcond
int str2Tm(const std::string& timeStr, struct tm* tm)
{

@ -34,9 +34,7 @@ EXIV2_RCSID("@(#) $Id$")
// included header files
#include "types.hpp"
#include "canonmn.hpp"
#include "makernote.hpp"
#include "value.hpp"
#include "ifd.hpp"
#include "i18n.h" // NLS support.
// + standard includes
@ -52,26 +50,6 @@ EXIV2_RCSID("@(#) $Id$")
// class member definitions
namespace Exiv2 {
//! @cond IGNORE
CanonMakerNote::RegisterMn::RegisterMn()
{
MakerNoteFactory::registerMakerNote("Canon", "*", createCanonMakerNote);
MakerNoteFactory::registerMakerNote(
canonIfdId, MakerNote::AutoPtr(new CanonMakerNote));
MakerNoteFactory::registerMakerNote(
canonCsIfdId, MakerNote::AutoPtr(new CanonMakerNote));
MakerNoteFactory::registerMakerNote(
canonSiIfdId, MakerNote::AutoPtr(new CanonMakerNote));
MakerNoteFactory::registerMakerNote(
canonPaIfdId, MakerNote::AutoPtr(new CanonMakerNote));
MakerNoteFactory::registerMakerNote(
canonCfIfdId, MakerNote::AutoPtr(new CanonMakerNote));
MakerNoteFactory::registerMakerNote(
canonPiIfdId, MakerNote::AutoPtr(new CanonMakerNote));
}
//! @endcond
//! ModelId, tag 0x0010
extern const TagDetails canonModelId[] = {
{ 0x1010000, N_("PowerShot A30") },
@ -661,293 +639,9 @@ namespace Exiv2 {
return tagInfoPi_;
}
int CanonMakerNote::read(const byte* buf,
long len,
long start,
ByteOrder byteOrder,
long shift)
{
int rc = IfdMakerNote::read(buf, len, start, byteOrder, shift);
if (rc) return rc;
// Decode camera settings 1 and add settings as additional entries
Entries::iterator cs = ifd_.findTag(0x0001);
if (cs != ifd_.end() && cs->type() == unsignedShort) {
for (uint16_t c = 1; cs->count() > c; ++c) {
if (c == 23 && cs->count() > 25) {
// Pack related lens info into one tag
addCsEntry(canonCsIfdId, c, cs->offset() + c*2,
cs->data() + c*2, 3);
c += 2;
}
else {
addCsEntry(canonCsIfdId, c, cs->offset() + c*2,
cs->data() + c*2, 1);
}
}
// Discard the original entry
ifd_.erase(cs);
}
// Decode camera settings 2 and add settings as additional entries
cs = ifd_.findTag(0x0004);
if (cs != ifd_.end() && cs->type() == unsignedShort) {
for (uint16_t c = 1; cs->count() > c; ++c) {
addCsEntry(canonSiIfdId, c, cs->offset() + c*2,
cs->data() + c*2, 1);
}
// Discard the original entry
ifd_.erase(cs);
}
// Decode panorama information and add each as an additional entry
cs = ifd_.findTag(0x0005);
if (cs != ifd_.end() && cs->type() == unsignedShort) {
for (uint16_t c = 1; cs->count() > c; ++c) {
addCsEntry(canonPaIfdId, c, cs->offset() + c*2,
cs->data() + c*2, 1);
}
// Discard the original entry
ifd_.erase(cs);
}
// Decode custom functions and add each as an additional entry
cs = ifd_.findTag(0x000f);
if (cs != ifd_.end() && cs->type() == unsignedShort) {
for (uint16_t c = 1; cs->count() > c; ++c) {
addCsEntry(canonCfIfdId, c, cs->offset() + c*2,
cs->data() + c*2, 1);
}
// Discard the original entry
ifd_.erase(cs);
}
// Decode picture info and add each as an additional entry
cs = ifd_.findTag(0x0012);
if (cs != ifd_.end() && cs->type() == unsignedShort) {
for (uint16_t c = 1; cs->count() > c; ++c) {
addCsEntry(canonPiIfdId, c, cs->offset() + c*2,
cs->data() + c*2, 1);
}
// Discard the original entry
ifd_.erase(cs);
}
// Copy remaining ifd entries
entries_.insert(entries_.begin(), ifd_.begin(), ifd_.end());
// Set idx
int idx = 0;
Entries::iterator e = entries_.end();
for (Entries::iterator i = entries_.begin(); i != e; ++i) {
i->setIdx(++idx);
}
return 0;
}
void CanonMakerNote::addCsEntry(IfdId ifdId,
uint16_t tag,
long offset,
const byte* data,
int count)
{
Entry e(false);
e.setIfdId(ifdId);
e.setTag(tag);
e.setOffset(offset);
e.setValue(unsignedShort, count, data, 2*count);
add(e);
}
void CanonMakerNote::add(const Entry& entry)
{
assert(alloc_ == entry.alloc());
assert( entry.ifdId() == canonIfdId
|| entry.ifdId() == canonCsIfdId
|| entry.ifdId() == canonSiIfdId
|| entry.ifdId() == canonPaIfdId
|| entry.ifdId() == canonCfIfdId
|| entry.ifdId() == canonPiIfdId);
// allow duplicates
entries_.push_back(entry);
}
long CanonMakerNote::copy(byte* buf, ByteOrder byteOrder, long offset)
{
if (byteOrder_ == invalidByteOrder) byteOrder_ = byteOrder;
assert(ifd_.alloc());
ifd_.clear();
// Add all standard Canon entries to the IFD
Entries::const_iterator end = entries_.end();
for (Entries::const_iterator i = entries_.begin(); i != end; ++i) {
if (i->ifdId() == canonIfdId) {
ifd_.add(*i);
}
}
// Collect camera settings entries and add the original Canon tag
Entry cs;
if (assemble(cs, canonCsIfdId, 0x0001, byteOrder_)) {
ifd_.erase(0x0001);
ifd_.add(cs);
}
// Collect shot info entries and add the original Canon tag
Entry si;
if (assemble(si, canonSiIfdId, 0x0004, byteOrder_)) {
ifd_.erase(0x0004);
ifd_.add(si);
}
// Collect panorama entries and add the original Canon tag
Entry pa;
if (assemble(pa, canonPaIfdId, 0x0005, byteOrder_)) {
ifd_.erase(0x0005);
ifd_.add(pa);
}
// Collect custom function entries and add the original Canon tag
Entry cf;
if (assemble(cf, canonCfIfdId, 0x000f, byteOrder_)) {
ifd_.erase(0x000f);
ifd_.add(cf);
}
// Collect picture info entries and add the original Canon tag
Entry pi;
if (assemble(pi, canonPiIfdId, 0x0012, byteOrder_)) {
ifd_.erase(0x0012);
ifd_.add(pi);
}
return IfdMakerNote::copy(buf, byteOrder_, offset);
} // CanonMakerNote::copy
void CanonMakerNote::updateBase(byte* pNewBase)
{
byte* pBase = ifd_.updateBase(pNewBase);
if (absShift_ && !alloc_) {
Entries::iterator end = entries_.end();
for (Entries::iterator pos = entries_.begin(); pos != end; ++pos) {
pos->updateBase(pBase, pNewBase);
}
}
} // CanonMakerNote::updateBase
long CanonMakerNote::size() const
{
Ifd ifd(canonIfdId, 0, alloc_); // offset doesn't matter
// Add all standard Canon entries to the IFD
Entries::const_iterator end = entries_.end();
for (Entries::const_iterator i = entries_.begin(); i != end; ++i) {
if (i->ifdId() == canonIfdId) {
ifd.add(*i);
}
}
// Collect camera settings entries and add the original Canon tag
Entry cs(alloc_);
if (assemble(cs, canonCsIfdId, 0x0001, littleEndian)) {
ifd.erase(0x0001);
ifd.add(cs);
}
// Collect shot info entries and add the original Canon tag
Entry si(alloc_);
if (assemble(si, canonSiIfdId, 0x0004, littleEndian)) {
ifd.erase(0x0004);
ifd.add(si);
}
// Collect panorama entries and add the original Canon tag
Entry pa(alloc_);
if (assemble(pa, canonPaIfdId, 0x0005, littleEndian)) {
ifd.erase(0x0005);
ifd.add(pa);
}
// Collect custom function entries and add the original Canon tag
Entry cf(alloc_);
if (assemble(cf, canonCfIfdId, 0x000f, littleEndian)) {
ifd.erase(0x000f);
ifd.add(cf);
}
// Collect picture info entries and add the original Canon tag
Entry pi(alloc_);
if (assemble(pi, canonPiIfdId, 0x0012, littleEndian)) {
ifd.erase(0x0012);
ifd.add(pi);
}
return headerSize() + ifd.size() + ifd.dataSize();
} // CanonMakerNote::size
long CanonMakerNote::assemble(Entry& e,
IfdId ifdId,
uint16_t tag,
ByteOrder byteOrder) const
{
DataBuf buf(1024);
std::memset(buf.pData_, 0x0, 1024);
uint16_t len = 0;
Entries::const_iterator end = entries_.end();
for (Entries::const_iterator i = entries_.begin(); i != end; ++i) {
if (i->ifdId() == ifdId) {
uint16_t pos = i->tag() * 2;
uint16_t size = pos + static_cast<uint16_t>(i->size());
assert(size <= 1024);
std::memcpy(buf.pData_ + pos, i->data(), i->size());
if (len < size) len = size;
}
}
if (len > 0) {
// Number of shorts in the buffer (rounded up)
uint16_t s = (len+1) / 2;
us2Data(buf.pData_, s*2, byteOrder);
e.setIfdId(canonIfdId);
e.setIdx(0); // don't care
e.setTag(tag);
e.setOffset(0); // will be calculated when the IFD is written
e.setValue(unsignedShort, s, buf.pData_, s*2);
}
return len;
} // CanonMakerNote::assemble
Entries::const_iterator CanonMakerNote::findIdx(int idx) const
{
return std::find_if(entries_.begin(), entries_.end(),
FindEntryByIdx(idx));
}
CanonMakerNote::CanonMakerNote(bool alloc)
: IfdMakerNote(canonIfdId, alloc)
{
}
CanonMakerNote::CanonMakerNote(const CanonMakerNote& rhs)
: IfdMakerNote(rhs)
{
entries_ = rhs.entries_;
}
CanonMakerNote::AutoPtr CanonMakerNote::create(bool alloc) const
{
return AutoPtr(create_(alloc));
}
CanonMakerNote* CanonMakerNote::create_(bool alloc) const
{
return new CanonMakerNote(alloc);
}
CanonMakerNote::AutoPtr CanonMakerNote::clone() const
{
return AutoPtr(clone_());
}
CanonMakerNote* CanonMakerNote::clone_() const
{
return new CanonMakerNote(*this);
}
std::ostream& CanonMakerNote::print0x0008(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
std::string n = value.toString();
if (n.length() < 4) return os << "(" << n << ")";
@ -956,7 +650,8 @@ namespace Exiv2 {
}
std::ostream& CanonMakerNote::print0x000c(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
std::istringstream is(value.toString());
uint32_t l;
@ -968,7 +663,8 @@ namespace Exiv2 {
}
std::ostream& CanonMakerNote::printCs0x0002(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
if (value.typeId() != unsignedShort) return os << value;
long l = value.toLong();
@ -982,7 +678,8 @@ namespace Exiv2 {
}
std::ostream& CanonMakerNote::printCsLens(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
if ( value.count() < 3
|| value.typeId() != unsignedShort) {
@ -1006,14 +703,16 @@ namespace Exiv2 {
}
std::ostream& CanonMakerNote::printSi0x0002(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
// Ported from Exiftool by Will Stokes
return os << exp(canonEv(value.toLong()) * log(2.0)) * 100.0 / 32.0;
}
std::ostream& CanonMakerNote::printSi0x0009(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
if (value.typeId() != unsignedShort) return os << value;
long l = value.toLong();
@ -1023,7 +722,8 @@ namespace Exiv2 {
}
std::ostream& CanonMakerNote::printSi0x000e(std::ostream& os,
const Value& value)
const Value& value,
const ExifData* pExifData)
{
if (value.typeId() != unsignedShort) return os << value;
long l = value.toLong();
@ -1034,14 +734,15 @@ namespace Exiv2 {
os << "none";
}
else {
EXV_PRINT_TAG_BITMASK(canonSiAFPointUsed)(os, value);
EXV_PRINT_TAG_BITMASK(canonSiAFPointUsed)(os, value, pExifData);
}
os << " used";
return os;
}
std::ostream& CanonMakerNote::printSi0x0013(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
if (value.typeId() != unsignedShort) return os << value;
long l = value.toLong();
@ -1055,7 +756,8 @@ namespace Exiv2 {
}
std::ostream& CanonMakerNote::printSi0x0015(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
if (value.typeId() != unsignedShort) return os << value;
@ -1069,7 +771,8 @@ namespace Exiv2 {
}
std::ostream& CanonMakerNote::printSi0x0016(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
if (value.typeId() != unsignedShort) return os << value;
@ -1084,15 +787,6 @@ namespace Exiv2 {
// *****************************************************************************
// free functions
MakerNote::AutoPtr createCanonMakerNote( bool alloc,
const byte* /*buf*/,
long /*len*/,
ByteOrder /*byteOrder*/,
long /*offset*/)
{
return MakerNote::AutoPtr(new CanonMakerNote(alloc));
}
float canonEv(long val)
{
// temporarily remove sign

@ -36,7 +36,6 @@
// *****************************************************************************
// included header files
#include "types.hpp"
#include "makernote.hpp"
#include "tags.hpp"
// + standard includes
@ -52,81 +51,12 @@ namespace Exiv2 {
// class declarations
class Value;
// *****************************************************************************
// free functions
/*!
@brief Return an auto-pointer to a newly created empty MakerNote
initialized to operate in the memory management model indicated.
The caller owns this copy and the auto-pointer ensures that it
will be deleted.
@param alloc Memory management model for the new MakerNote. Determines if
memory required to store data should be allocated and deallocated
(true) or not (false). If false, only pointers to the buffer
provided to read() will be kept. See Ifd for more background on
this concept.
@param buf Pointer to the makernote character buffer (not used).
@param len Length of the makernote character buffer (not used).
@param byteOrder Byte order in which the Exif data (and possibly the
makernote) is encoded (not used).
@param offset Offset from the start of the TIFF header of the makernote
buffer (not used).
@return An auto-pointer to a newly created empty MakerNote. The caller
owns this copy and the auto-pointer ensures that it will be
deleted.
*/
MakerNote::AutoPtr createCanonMakerNote(bool alloc,
const byte* buf,
long len,
ByteOrder byteOrder,
long offset);
// *****************************************************************************
// class definitions
//! MakerNote for Canon cameras
class CanonMakerNote : public IfdMakerNote {
class CanonMakerNote {
public:
//! Shortcut for a %CanonMakerNote auto pointer.
typedef std::auto_ptr<CanonMakerNote> AutoPtr;
//! @name Creators
//@{
/*!
@brief Constructor. Allows to choose whether or not memory management
is required for the makernote entries.
*/
CanonMakerNote(bool alloc =true);
//! Copy constructor
CanonMakerNote(const CanonMakerNote& rhs);
//! Virtual destructor
virtual ~CanonMakerNote() {}
//@}
//! @name Manipulators
//@{
int read(const byte* buf,
long len,
long start,
ByteOrder byteOrder,
long shift);
long copy(byte* buf, ByteOrder byteOrder, long offset);
void add(const Entry& entry);
Entries::iterator begin() { return entries_.begin(); }
Entries::iterator end() { return entries_.end(); }
void updateBase(byte* pNewBase);
//@}
//! @name Accessors
//@{
Entries::const_iterator begin() const { return entries_.begin(); }
Entries::const_iterator end() const { return entries_.end(); }
Entries::const_iterator findIdx(int idx) const;
long size() const;
AutoPtr create(bool alloc =true) const;
AutoPtr clone() const;
//! Return read-only list of built-in Canon tags
static const TagInfo* tagList();
//! Return read-only list of built-in Canon Camera Settings tags
@ -139,66 +69,33 @@ namespace Exiv2 {
static const TagInfo* tagListCf();
//! Return read-only list of built-in Canon Picture Info tags
static const TagInfo* tagListPi();
//@}
//! @name Print functions for Canon %MakerNote tags
//@{
//! Print the image number
static std::ostream& print0x0008(std::ostream& os, const Value& value);
static std::ostream& print0x0008(std::ostream& os, const Value& value, const ExifData*);
//! Print the serial number of the camera
static std::ostream& print0x000c(std::ostream& os, const Value& value);
static std::ostream& print0x000c(std::ostream& os, const Value& value, const ExifData*);
//! Self timer
static std::ostream& printCs0x0002(std::ostream& os, const Value& value);
static std::ostream& printCs0x0002(std::ostream& os, const Value& value, const ExifData*);
//! Camera lens information
static std::ostream& printCsLens(std::ostream& os, const Value& value);
static std::ostream& printCsLens(std::ostream& os, const Value& value, const ExifData*);
//! ISO speed used
static std::ostream& printSi0x0002(std::ostream& os, const Value& value);
static std::ostream& printSi0x0002(std::ostream& os, const Value& value, const ExifData*);
//! Sequence number
static std::ostream& printSi0x0009(std::ostream& os, const Value& value);
static std::ostream& printSi0x0009(std::ostream& os, const Value& value, const ExifData*);
//! AF point used
static std::ostream& printSi0x000e(std::ostream& os, const Value& value);
static std::ostream& printSi0x000e(std::ostream& os, const Value& value, const ExifData* pExifData);
//! Subject distance
static std::ostream& printSi0x0013(std::ostream& os, const Value& value);
static std::ostream& printSi0x0013(std::ostream& os, const Value& value, const ExifData*);
//! Aperture
static std::ostream& printSi0x0015(std::ostream& os, const Value& value);
static std::ostream& printSi0x0015(std::ostream& os, const Value& value, const ExifData*);
//! Shutter speed
static std::ostream& printSi0x0016(std::ostream& os, const Value& value);
static std::ostream& printSi0x0016(std::ostream& os, const Value& value, const ExifData*);
//@}
//! @cond IGNORE
// Public only so that we can create a static instance
struct RegisterMn {
RegisterMn();
};
//! @endcond
private:
//! @name Manipulators
//@{
//! Add a camera settings entry to the makernote entries
void addCsEntry(IfdId ifdId,
uint16_t tag,
long offset,
const byte* data,
int count);
//@}
//! @name Accessors
//@{
//! Assemble special Canon entries into an entry with the original tag
long assemble(Entry& e,
IfdId ifdId,
uint16_t tag,
ByteOrder byteOrder) const;
//! Internal virtual create function.
CanonMakerNote* create_(bool alloc =true) const;
//! Internal virtual copy constructor.
CanonMakerNote* clone_() const;
//@}
// DATA
//! Container to store Makernote entries (instead of Ifd)
Entries entries_;
//! Tag information
static const TagInfo tagInfo_[];
@ -210,8 +107,6 @@ namespace Exiv2 {
}; // class CanonMakerNote
static CanonMakerNote::RegisterMn registerCanonMakerNote;
// *****************************************************************************
// template, inline and free functions

@ -1191,7 +1191,7 @@ namespace Exiv2 {
MD5Init(&context);
DataBuf data = iptcData_->copy();
DataBuf data = IptcParser::encode(*iptcData_);
MD5Update(&context, data.pData_, data.size_);
MD5Final(digest, &context);
res << std::setw(2) << std::setfill('0') << std::hex << std::uppercase;

@ -38,9 +38,10 @@ EXIV2_RCSID("@(#) $Id$")
#endif
#include "cr2image.hpp"
#include "tiffcomposite.hpp"
#include "tiffparser.hpp"
#include "tiffvisitor.hpp"
#include "cr2image_int.hpp"
#include "tiffcomposite_int.hpp"
#include "tiffimage_int.hpp"
#include "tiffvisitor_int.hpp"
#include "image.hpp"
#include "error.hpp"
#include "futils.hpp"
@ -56,37 +57,7 @@ EXIV2_RCSID("@(#) $Id$")
// class member definitions
namespace Exiv2 {
// CR2 decoder table for special CR2 decoding requirements
const TiffDecoderInfo Cr2Decoder::cr2DecoderInfo_[] = {
{ "*", Tag::all, Group::ignr, 0 }, // Do not decode tags with group == Group::ignr
{ "*", 0x014a, Group::ifd0, 0 }, // Todo: Controversial, causes problems with Exiftool
{ "*", 0x0100, Group::ifd0, 0 }, // CR2 IFD0 refers to a preview image, ignore these tags
{ "*", 0x0101, Group::ifd0, 0 },
{ "*", 0x0102, Group::ifd0, 0 },
{ "*", 0x0103, Group::ifd0, 0 },
{ "*", 0x0111, Group::ifd0, 0 },
{ "*", 0x0117, Group::ifd0, 0 },
{ "*", 0x011a, Group::ifd0, 0 },
{ "*", 0x011b, Group::ifd0, 0 },
{ "*", 0x0128, Group::ifd0, 0 },
{ "*", 0x02bc, Group::ifd0, &TiffMetadataDecoder::decodeXmp },
{ "*", 0x83bb, Group::ifd0, &TiffMetadataDecoder::decodeIptc },
{ "*", 0x8649, Group::ifd0, &TiffMetadataDecoder::decodeIptc }
};
DecoderFct Cr2Decoder::findDecoder(const std::string& make,
uint32_t extendedTag,
uint16_t group)
{
DecoderFct decoderFct = &TiffMetadataDecoder::decodeStdTiffEntry;
const TiffDecoderInfo* td = find(cr2DecoderInfo_,
TiffDecoderInfo::Key(make, extendedTag, group));
if (td) {
// This may set decoderFct to 0, meaning that the tag should not be decoded
decoderFct = td->decoderFct_;
}
return decoderFct;
}
using namespace Internal;
Cr2Image::Cr2Image(BasicIo::AutoPtr io, bool /*create*/)
: Image(ImageType::cr2, mdExif | mdIptc, io)
@ -138,19 +109,141 @@ namespace Exiv2 {
throw Error(3, "CR2");
}
clearMetadata();
Cr2Header cr2Header;
TiffParser::decode(this, io_->mmap(), io_->size(),
TiffCreator::create, Cr2Decoder::findDecoder,
&cr2Header);
ByteOrder bo = Cr2Parser::decode(exifData_,
iptcData_,
xmpData_,
io_->mmap(),
io_->size());
setByteOrder(bo);
} // Cr2Image::readMetadata
void Cr2Image::writeMetadata()
{
//! Todo: implement me!
// Todo: implement me!
throw(Error(31, "CR2"));
} // Cr2Image::writeMetadata
ByteOrder Cr2Parser::decode(
ExifData& exifData,
IptcData& iptcData,
XmpData& xmpData,
const byte* pData,
uint32_t size
)
{
Cr2Header cr2Header;
return TiffParserWorker::decode(exifData,
iptcData,
xmpData,
pData,
size,
TiffCreator::create,
Cr2Mapping::findDecoder,
&cr2Header);
}
WriteMethod Cr2Parser::encode(
Blob& blob,
const byte* pData,
uint32_t size,
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData
)
{
/* Todo: Implement me!
TiffParserWorker::encode(blob,
pData,
size,
exifData,
iptcData,
xmpData,
TiffCreator::create,
TiffMapping::findEncoder);
*/
blob.clear();
return wmIntrusive;
}
// *************************************************************************
// free functions
Image::AutoPtr newCr2Instance(BasicIo::AutoPtr io, bool create)
{
Image::AutoPtr image(new Cr2Image(io, create));
if (!image->good()) {
image.reset();
}
return image;
}
bool isCr2Type(BasicIo& iIo, bool advance)
{
const int32_t len = 16;
byte buf[len];
iIo.read(buf, len);
if (iIo.error() || iIo.eof()) {
return false;
}
Cr2Header header;
bool rc = header.read(buf, len);
if (!advance || !rc) {
iIo.seek(-len, BasicIo::cur);
}
return rc;
}
} // namespace Exiv2
namespace Exiv2 {
namespace Internal {
// CR2 mapping table for special CR2 decoding requirements
const TiffMappingInfo Cr2Mapping::cr2MappingInfo_[] = {
{ "*", Tag::all, Group::ignr, 0, 0 }, // Do not decode tags with group == Group::ignr
{ "*", 0x014a, Group::ifd0, 0, 0 }, // Todo: Controversial, causes problems with Exiftool
{ "*", 0x0100, Group::ifd0, 0, 0 }, // CR2 IFD0 refers to a preview image, ignore these tags
{ "*", 0x0101, Group::ifd0, 0, 0 },
{ "*", 0x0102, Group::ifd0, 0, 0 },
{ "*", 0x0103, Group::ifd0, 0, 0 },
{ "*", 0x0111, Group::ifd0, 0, 0 },
{ "*", 0x0117, Group::ifd0, 0, 0 },
{ "*", 0x011a, Group::ifd0, 0, 0 },
{ "*", 0x011b, Group::ifd0, 0, 0 },
{ "*", 0x0128, Group::ifd0, 0, 0 },
{ "*", 0x02bc, Group::ifd0, &TiffDecoder::decodeXmp, &TiffEncoder::encodeXmp },
{ "*", 0x83bb, Group::ifd0, &TiffDecoder::decodeIptc, &TiffEncoder::encodeIptc },
{ "*", 0x8649, Group::ifd0, &TiffDecoder::decodeIptc, &TiffEncoder::encodeIptc }
};
DecoderFct Cr2Mapping::findDecoder(const std::string& make,
uint32_t extendedTag,
uint16_t group)
{
DecoderFct decoderFct = &TiffDecoder::decodeStdTiffEntry;
const TiffMappingInfo* td = find(cr2MappingInfo_,
TiffMappingInfo::Key(make, extendedTag, group));
if (td) {
// This may set decoderFct to 0, meaning that the tag should not be decoded
decoderFct = td->decoderFct_;
}
return decoderFct;
}
EncoderFct Cr2Mapping::findEncoder(const std::string& make,
uint32_t extendedTag,
uint16_t group)
{
EncoderFct encoderFct = 0;
const TiffMappingInfo* td = find(cr2MappingInfo_,
TiffMappingInfo::Key(make, extendedTag, group));
if (td) {
// Returns 0 if no special encoder function is found
encoderFct = td->encoderFct_;
}
return encoderFct;
}
const char* Cr2Header::cr2sig_ = "CR\2\0";
Cr2Header::Cr2Header()
@ -184,36 +277,10 @@ namespace Exiv2 {
return true;
} // Cr2Header::read
void Cr2Header::write(Blob& blob) const
uint32_t Cr2Header::write(Blob& blob) const
{
// Todo: Implement me!
return 0;
}
// *************************************************************************
// free functions
Image::AutoPtr newCr2Instance(BasicIo::AutoPtr io, bool create)
{
Image::AutoPtr image(new Cr2Image(io, create));
if (!image->good()) {
image.reset();
}
return image;
}
bool isCr2Type(BasicIo& iIo, bool advance)
{
const int32_t len = 16;
byte buf[len];
iIo.read(buf, len);
if (iIo.error() || iIo.eof()) {
return false;
}
Cr2Header header;
bool rc = header.read(buf, len);
if (!advance || !rc) {
iIo.seek(-len, BasicIo::cur);
}
return rc;
}
} // namespace Exiv2
}} // namespace Internal, Exiv2

@ -33,9 +33,7 @@
// included header files
#include "image.hpp"
#include "basicio.hpp"
#include "tifffwd.hpp"
#include "types.hpp"
#include "tiffimage.hpp"
// + standard includes
#include <string>
@ -122,60 +120,38 @@ namespace Exiv2 {
}; // class Cr2Image
/*!
@brief Table of Cr2 decoding functions and find function. See
TiffDecoder for details.
@brief Stateless parser class for data in CR2 format. Images use this
class to decode and encode CR2 data.
See class TiffParser for details.
*/
class Cr2Decoder {
class Cr2Parser {
public:
/*!
@brief Find the decoder function for a key.
If the returned pointer is 0, the tag should not be decoded,
else the decoder function should be used.
@param make Camera make
@param extendedTag Extended tag
@param group %Group
@return Pointer to the decoder function
*/
static DecoderFct findDecoder(const std::string& make,
uint32_t extendedTag,
uint16_t group);
private:
static const TiffDecoderInfo cr2DecoderInfo_[]; //<! CR2 decoder table
}; // class Cr2Decoder
/*!
@brief Canon CR2 header structure.
*/
class Cr2Header : public TiffHeaderBase {
public:
//! @name Creators
//@{
//! Default constructor
Cr2Header();
//! Destructor.
~Cr2Header();
//@}
//! @name Manipulators
//@{
bool read(const byte* pData, uint32_t size);
//@}
//! @name Accessors
//@{
void write(Blob& blob) const;
//@}
private:
// DATA
uint32_t offset2_; //!< Bytes 12-15 from the header
static const char* cr2sig_; //!< Signature for CR2 type TIFF
}; // class Cr2Header
@brief Decode metadata from a buffer \em pData of length \em size
with data in CR2 format to the provided metadata containers.
See TiffParser::decode().
*/
static ByteOrder decode(
ExifData& exifData,
IptcData& iptcData,
XmpData& xmpData,
const byte* pData,
uint32_t size
);
/*!
@brief Encode metadata from the provided metadata to CR2 format.
See TiffParser::encode().
*/
static WriteMethod encode(
Blob& blob,
const byte* pData,
uint32_t size,
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData
);
}; // class Cr2Parser
// *****************************************************************************
// template, inline and free functions

@ -0,0 +1,122 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*!
@file cr2image_int.hpp
@brief Internal classes to support CR2 image format
@version $Rev$
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 23-Apr-08, ahu: created
*/
#ifndef CR2IMAGE_INT_HPP_
#define CR2IMAGE_INT_HPP_
// *****************************************************************************
// included header files
#include "tiffimage_int.hpp"
#include "types.hpp"
// + standard includes
#include <string>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
namespace Internal {
// *****************************************************************************
// class definitions
/*!
@brief Table of CR2 decoding functions and find function. See
TiffMapping for details.
*/
class Cr2Mapping {
public:
/*!
@brief Find the decoder function for a key.
If the returned pointer is 0, the tag should not be decoded,
else the decoder function should be used.
@param make Camera make
@param extendedTag Extended tag
@param group %Group
@return Pointer to the decoder function
*/
static DecoderFct findDecoder(const std::string& make,
uint32_t extendedTag,
uint16_t group);
/*!
@brief Find the encoder function for a key.
If the returned pointer is 0, the tag should not be encoded,
else the encoder function should be used.
@param make Camera make
@param extendedTag Extended tag
@param group %Group
@return Pointer to the encoder function
*/
static EncoderFct findEncoder(const std::string& make,
uint32_t extendedTag,
uint16_t group);
private:
static const TiffMappingInfo cr2MappingInfo_[]; //<! CR2 mapping table
}; // class Cr2Mapping
/*!
@brief Canon CR2 header structure.
*/
class Cr2Header : public TiffHeaderBase {
public:
//! @name Creators
//@{
//! Default constructor
Cr2Header();
//! Destructor.
~Cr2Header();
//@}
//! @name Manipulators
//@{
bool read(const byte* pData, uint32_t size);
//@}
//! @name Accessors
//@{
uint32_t write(Blob& blob) const;
//@}
private:
// DATA
uint32_t offset2_; //!< Bytes 12-15 from the header
static const char* cr2sig_; //!< Signature for CR2 type TIFF
}; // class Cr2Header
}} // namespace Internal, Exiv2
#endif // #ifndef CR2IMAGE_INT_HPP_

@ -1046,8 +1046,8 @@ namespace Exiv2 {
Image& image,
ByteOrder /*byteOrder*/)
{
image.exifData().setJpegThumbnail(ciffComponent.pData(),
ciffComponent.size());
ExifThumb exifThumb(image.exifData());
exifThumb.setJpegThumbnail(ciffComponent.pData(), ciffComponent.size());
} // CrwMap::decode0x2008
void CrwMap::decodeBasic(const CiffComponent& ciffComponent,
@ -1287,7 +1287,8 @@ namespace Exiv2 {
assert(pCrwMapping != 0);
assert(pHead != 0);
DataBuf buf = image.exifData().copyThumbnail();
ExifThumbC exifThumb(image.exifData());
DataBuf buf = exifThumb.copy();
if (buf.size_ != 0) {
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
}
@ -1355,6 +1356,7 @@ namespace Exiv2 {
// *****************************************************************************
// local definitions
namespace {
//! @cond IGNORE
const RotationMap::OmList RotationMap::omList_[] = {
{ 1, 0 },
{ 3, 180 },
@ -1390,4 +1392,5 @@ namespace {
}
return d;
}
//! @endcond
}

@ -65,7 +65,7 @@ namespace Exiv2 {
ErrMsg( 20, N_("Failed to read input data")),
ErrMsg( 21, N_("Failed to write image")),
ErrMsg( 22, N_("Input data does not contain a valid image")),
ErrMsg( 23, N_("Failed to create Makernote for ifdId %1")), // %1=ifdId
ErrMsg( 23, N_("Invalid ifdId %1")), // %1=ifdId
ErrMsg( 24, N_("Entry::setValue: Value too large (tag=%1, size=%2, requested=%3)")), // %1=tag, %2=dataSize, %3=required size
ErrMsg( 25, N_("Entry::setDataArea: Value too large (tag=%1, size=%2, requested=%3)")), // %1=tag, %2=dataAreaSize, %3=required size
ErrMsg( 26, N_("Offset out of range")),
@ -91,6 +91,9 @@ namespace Exiv2 {
ErrMsg( 46, N_("No namespace registered for prefix `%1'")), // %1=prefix
ErrMsg( 47, N_("Aliases are not supported. Please send this XMP packet to ahuggel@gmx.net `%1', `%2', `%3'")), // %1=namespace, %2=property path, %3=value
ErrMsg( 48, N_("Invalid XmpText type `%1'")), // %1=type
ErrMsg( 49, N_("TIFF directory %1 has too many entries")), // %1=TIFF directory name
ErrMsg( 50, N_("Multiple TIFF array element tags %1 in one directory")), // %1=tag number
ErrMsg( 51, N_("TIFF array element tag %1 has wrong type or more than one component")), // %1=tag number
// Last error message (message is not used)
ErrMsg( -2, N_("(Unknown Error)"))

File diff suppressed because it is too large Load Diff

@ -32,11 +32,9 @@
// *****************************************************************************
// included header files
#include "metadatum.hpp"
#include "types.hpp"
#include "error.hpp"
#include "value.hpp"
#include "ifd.hpp"
#include "tags.hpp"
#include "value.hpp"
#include "types.hpp"
// + standard includes
#include <string>
@ -47,16 +45,13 @@
// namespace extensions
/*!
@brief Provides classes and functions to encode and decode Exif and Iptc data.
This namespace corresponds to the <b>libexiv2</b> library.
The <b>libexiv2</b> API consists of the objects of this namespace.
*/
namespace Exiv2 {
// *****************************************************************************
// class declarations
class ExifData;
class MakerNote;
class TiffHeader;
// *****************************************************************************
// class definitions
@ -82,8 +77,6 @@ namespace Exiv2 {
@throw Error if the key cannot be parsed and converted.
*/
explicit Exifdatum(const ExifKey& key, const Value* pValue =0);
//! Constructor to build an %Exifdatum from an IFD entry.
Exifdatum(const Entry& e, ByteOrder byteOrder);
//! Copy constructor
Exifdatum(const Exifdatum& rhs);
//! Destructor
@ -142,10 +135,6 @@ namespace Exiv2 {
created. An AsciiValue is created for unknown tags.
*/
void setValue(const std::string& value);
/*!
@brief Set the value from an IFD entry.
*/
void setValue(const Entry& e, ByteOrder byteOrder);
/*!
@brief Set the data area by copying (cloning) the buffer pointed to
by \em buf.
@ -258,154 +247,168 @@ namespace Exiv2 {
}; // class Exifdatum
/*!
@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
the Exif data. This class is used internally by ExifData, it is
probably not useful for a client as a standalone class. Instead,
use an instance of ExifData to access the Exif thumbnail image.
@brief Access to a Exif %thumbnail image. This class provides higher level
accessors to the thumbnail image that is optionally embedded in IFD1
of the Exif data. These methods do not write to the Exif metadata.
Manipulators are provided in subclass ExifThumb.
@note Various other preview and thumbnail images may be contained in an
image, depending on its format and the camera make and model. This
class only provides access to the Exif thumbnail as specified in the
Exif standard.
*/
class Thumbnail {
class ExifThumbC {
public:
//! Shortcut for a %Thumbnail auto pointer.
typedef std::auto_ptr<Thumbnail> AutoPtr;
//! @name Creators
//@{
//! Virtual destructor
virtual ~Thumbnail() {}
//! Constructor.
ExifThumbC(const ExifData& exifData);
//@}
//! @name Accessors
//@{
/*!
@brief Set the image data as data area of the appropriate Exif
metadatum. Read the thumbnail image data from data buffer
\em buf. Return 0 if successful.
@param exifData Exif data corresponding to the data buffer.
@param pIfd1 Corresponding raw IFD1.
@param buf Data buffer containing the thumbnail data. The buffer must
start with the TIFF header.
@param len Number of bytes in the data buffer.
@return 0 if successful;<BR>
1 in case of inconsistent thumbnail Exif data; or<BR>
2 if the data area is outside of the data buffer
*/
virtual int setDataArea(ExifData& exifData,
Ifd* pIfd1,
const byte* buf,
long len) const =0;
/*!
@brief Return the thumbnail image in a %DataBuf. The caller owns the
data buffer and %DataBuf ensures that it will be deleted.
*/
virtual DataBuf copy(const ExifData& exifData) const =0;
DataBuf copy() const;
/*!
@brief Return a short string for the format of the thumbnail
("TIFF", "JPEG").
@brief Write the thumbnail image to a file.
A filename extension is appended to \em path according to the image
type of the thumbnail, so \em path should not include an extension.
The function will overwrite an existing file of the same name.
@param path File name of the thumbnail without extension.
@return The number of bytes written.
*/
long writeFile(const std::string& path) const;
/*!
@brief Return the MIME type of the thumbnail, either \c "image/tiff"
or \c "image/jpeg".
*/
virtual const char* format() const =0;
const char* mimeType() const;
/*!
@brief Return the file extension for the format of the thumbnail
(".tif", ".jpg").
(".tif" or ".jpg").
*/
virtual const char* extension() const =0;
const char* extension() const;
//@}
protected:
//! @name Manipulators
//@{
/*!
@brief Assignment operator. Protected so that it can only be used
by subclasses but not directly.
*/
Thumbnail& operator=(const Thumbnail& rhs);
//@}
private:
const ExifData& exifData_; //!< Const reference to the Exif metadata.
}; // class Thumbnail
}; // class ExifThumb
//! Exif thumbnail image in TIFF format
class TiffThumbnail : public Thumbnail {
/*!
@brief Access and modify an Exif %thumbnail image. This class implements
manipulators to set and erase the thumbnail image that is optionally
embedded in IFD1 of the Exif data. Accessors are provided by the
base class, ExifThumbC.
@note Various other preview and thumbnail images may be contained in an
image, depending on its format and the camera make and model. This
class only provides access to the Exif thumbnail as specified in the
Exif standard.
*/
class ExifThumb : public ExifThumbC {
public:
//! Shortcut for a %TiffThumbnail auto pointer.
typedef std::auto_ptr<TiffThumbnail> AutoPtr;
//! @name Manipulators
//! @name Creators
//@{
//! Assignment operator.
TiffThumbnail& operator=(const TiffThumbnail& rhs);
//! Constructor.
ExifThumb(ExifData& exifData);
//@}
//! @name Accessors
//! @name Manipulators
//@{
int setDataArea(ExifData& exifData,
Ifd* pIfd1,
const byte* buf,
long len) const;
DataBuf copy(const ExifData& exifData) const;
const char* format() const;
const char* extension() const;
//@}
/*!
@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.
}; // class TiffThumbnail
This results in the minimal thumbnail tags being set for a JPEG
thumbnail, as mandated by the Exif standard.
//! Exif thumbnail image in JPEG format
class JpegThumbnail : public Thumbnail {
public:
//! Shortcut for a %JpegThumbnail auto pointer.
typedef std::auto_ptr<JpegThumbnail> AutoPtr;
@throw Error if reading the file fails.
//! @name Manipulators
//@{
//! Assignment operator.
JpegThumbnail& operator=(const JpegThumbnail& rhs);
//@}
@note No checks on the file format or size are performed.
@note Additional existing Exif thumbnail tags are not modified.
@note The JPEG image inserted as thumbnail image should not
itself contain Exif data (or other metadata), as existing
applications may have problems with that. (The preview
application that comes with OS X for one.) - David Harvey.
*/
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.
//! @name Accessors
//@{
int setDataArea(ExifData& exifData,
Ifd* pIfd1,
const byte* buf,
long len) const;
DataBuf copy(const ExifData& exifData) const;
const char* format() const;
const char* extension() const;
//@}
This results in the minimal thumbnail tags being set for a JPEG
thumbnail, as mandated by the Exif standard.
}; // class JpegThumbnail
@throw Error if reading the file fails.
//! Container type to hold all metadata
typedef std::vector<Exifdatum> ExifMetadata;
@note No checks on the image format or size are performed.
@note Additional existing Exif thumbnail tags are not modified.
@note The JPEG image inserted as thumbnail image should not
itself contain Exif data (or other metadata), as existing
applications may have problems with that. (The preview
application that comes with OS X for one.) - David Harvey.
*/
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.
//! Unary predicate that matches a Exifdatum 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) {}
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.)
@throw Error if reading the file fails.
@note No checks on the file format or size are performed.
@note Additional existing Exif thumbnail tags are not modified.
*/
void setJpegThumbnail(const std::string& path);
/*!
@brief Returns true if the ifd id and idx of the argument
\em exifdatum is equal to that of the object.
*/
bool operator()(const Exifdatum& exifdatum) const
{ return ifdId_ == exifdatum.ifdId() && idx_ == exifdatum.idx(); }
@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., Exif IFD1 tags.
*/
void erase();
//@}
private:
IfdId ifdId_;
int idx_;
ExifData& exifData_; //!< Reference to the related Exif metadata.
}; // class ExifThumb
}; // class FindMetadatumByIfdIdIdx
//! Container type to hold all metadata
typedef std::vector<Exifdatum> ExifMetadata;
/*!
@brief A container for Exif data. This is a top-level class of the %Exiv2
@ -426,53 +429,8 @@ namespace Exiv2 {
//! ExifMetadata const iterator type
typedef ExifMetadata::const_iterator const_iterator;
//! @name Creators
//@{
//! Default constructor
ExifData();
//! Copy constructor (Todo: copy image data also)
ExifData(const ExifData& rhs);
//! Destructor
~ExifData();
//@}
//! @name Manipulators
//@{
//! Assignment operator (Todo: assign image data also)
ExifData& operator=(const ExifData& rhs);
/*!
@brief Load the Exif data from a byte buffer. The data buffer
must start with the TIFF header. This method is deprecated.
Use ImageFactory::open() instead.
@param buf Pointer to the data buffer to read from
@param len Number of bytes in the data buffer
@return 0 if successful.
*/
int load(const byte* buf, long len);
/*!
@brief Write the Exif data to a data buffer, which is returned. The
caller owns this copy and %DataBuf ensures that it will be
deleted. The copied data starts with the TIFF header.
Tries to update the original data buffer and write it back with
minimal changes, in a 'non-intrusive' fashion, if possible. In this
case, tag data that ExifData does not understand stand a good chance
to remain valid. (In particular, if the Exif data contains a
Makernote in IFD format, the offsets in its IFD will remain valid.)
<BR>
If 'non-intrusive' writing is not possible, the Exif data will be
re-built from scratch, in which case the absolute position of the
metadata entries within the data buffer may (and in most cases will)
be different from their original position. Furthermore, in this case,
the Exif data is updated with the metadata from the actual thumbnail
image (overriding existing metadata).
@note If there is no Exif data to write, the buffer is empty, i.e.,
no TIFF header is written in this case.
@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
@ -482,15 +440,6 @@ namespace Exiv2 {
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
checks are performed, i.e., it is possible to add multiple
metadata with the same key.
*/
void add(Entries::const_iterator begin,
Entries::const_iterator end,
ByteOrder byteOrder);
/*!
@brief Add an Exifdatum from the supplied key and value pair. This
method copies (clones) key and value. No duplicate checks are
@ -520,8 +469,6 @@ namespace Exiv2 {
void clear();
//! Sort metadata by key
void sortByKey();
//! Sort metadata by tag
void sortByTag();
//! Begin of the metadata
iterator begin() { return exifMetadata_.begin(); }
//! End of the metadata
@ -531,98 +478,6 @@ namespace Exiv2 {
iterator to it.
*/
iterator findKey(const ExifKey& key);
/*!
@brief Find the first Exifdatum with the given \em ifdId and \em idx,
return an iterator to it.
This method can be used to uniquely identify an exifdatum 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.
*/
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.
@throw Error if reading the file fails.
@note No checks on the file format or size are performed.
@note Additional existing Exif thumbnail tags are not modified.
@note The Jpeg image inserted as thumbnail image should not
itself contain Exif data (or other metadata), as existing
applications may have problems with that. (The preview
application that comes with OS X for one.) - David Harvey.
*/
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.
@throw Error if reading the file fails.
@note No checks on the image format or size are performed.
@note Additional existing Exif thumbnail tags are not modified.
@note The Jpeg image inserted as thumbnail image should not
itself contain Exif data (or other metadata), as existing
applications may have problems with that. (The preview
application that comes with OS X for one.) - David Harvey.
*/
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.)
@throw Error if reading the file fails.
@note No checks on the file format or size are performed.
@note Additional existing Exif thumbnail tags are not modified.
*/
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.
@return The number of bytes of thumbnail data erased from the original
Exif data. Note that the original image size may differ from
the size of the image after deleting the thumbnail by more
than this number. This is the case if the Exif data contains
extra bytes (often at the end of the Exif block) or gaps and
the thumbnail is not located at the end of the Exif block so
that non-intrusive writing of a truncated Exif block is not
possible. Instead it is in this case necessary to write the
Exif data, without the thumbnail, from the metadata and all
extra bytes and gaps are lost, resulting in a smaller image.
*/
long eraseThumbnail();
//@}
//! @name Accessors
@ -636,215 +491,73 @@ namespace Exiv2 {
iterator to it.
*/
const_iterator findKey(const ExifKey& key) const;
/*!
@brief Find the first Exifdatum with the given \em ifdId and \em idx,
return an iterator to it.
This method can be used to uniquely identify a Exifdatum 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.
*/
const_iterator findIfdIdIdx(IfdId ifdId, int idx) const;
//! Return true if there is no Exif metadata
bool empty() const { return count() == 0; }
//! Get the number of metadata entries
long count() const { return static_cast<long>(exifMetadata_.size()); }
/*!
@brief Returns the byte order. Default is little endian.
*/
ByteOrder byteOrder() const;
/*!
@brief Write the thumbnail image to a file. A filename extension
is appended to \em path according to the image type of the
thumbnail, so \em path should not include an extension.
This will overwrite an existing file of the same name.
@param path Path of the filename without image type extension
@throw Error if writing to the file fails.
@return 0 if successful;<BR>
8 if the Exif data does not contain a thumbnail.
*/
int writeThumbnail(const std::string& path) const;
/*!
@brief Return the thumbnail image in a %DataBuf. The caller owns the
data buffer and %DataBuf ensures that it will be deleted.
*/
DataBuf copyThumbnail() const;
/*!
@brief Return a short string describing the format of the Exif
thumbnail ("TIFF", "JPEG").
*/
const char* thumbnailFormat() const;
/*!
@brief Return the file extension for the Exif thumbnail depending
on the format (".tif", ".jpg").
*/
const char* thumbnailExtension() const;
/*!
@brief Return a thumbnail object of the correct type, corresponding to
the current Exif data. Caller owns this object and the auto
pointer ensures that it will be deleted.
*/
Thumbnail::AutoPtr getThumbnail() const;
//@}
private:
//! @name Manipulators
//@{
/*!
@brief Read the thumbnail from the data buffer. Assigns the thumbnail
data area with the appropriate Exif tags. Return 0 if successful,
i.e., if there is a thumbnail.
*/
int readThumbnail();
/*!
@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,
ByteOrder byteOrder);
/*!
@brief Write the Exif data to a data buffer the hard way, return the
data buffer. The caller owns this data buffer and %DataBuf
ensures that it will be deleted.
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).
@return A %DataBuf containing the Exif data.
*/
DataBuf copyFromMetadata();
//@}
//! @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.
*/
bool compatible() const;
/*!
@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;
/*!
@brief Check if IFD1, the IFD1 data and thumbnail data are located at
the end of the Exif data. Return true, if they are or if there
is no thumbnail at all, else return false.
*/
bool stdThumbPosition() const;
//@}
// DATA
ExifMetadata exifMetadata_;
// The pointers below are used only if Exif data is read from a
// raw data buffer
TiffHeader* pTiffHeader_; //! Pointer to the TIFF header
Ifd* pIfd0_; //! Pointer to Ifd0
Ifd* pExifIfd_; //! Pointer to ExifIfd
Ifd* pIopIfd_; //! Pointer to IopIfd
Ifd* pGpsIfd_; //! Pointer to GpsIfd
Ifd* pIfd1_; //! Pointer to Ifd1
MakerNote* pMakerNote_; //! Pointer to the MakerNote, if any
long size_; //!< Size of the Exif raw data in bytes
byte* pData_; //!< Exif raw data buffer
/*!
Can be set to false to indicate that non-intrusive writing is not
possible. If it is true (the default), then the compatibility checks
will be performed to determine which writing method to use.
*/
bool compatible_;
}; // class ExifData
// *****************************************************************************
// template, inline and free functions
template<typename T>
Exifdatum& setValue(Exifdatum& exifDatum, const T& value)
{
std::auto_ptr<ValueType<T> > v
= std::auto_ptr<ValueType<T> >(new ValueType<T>);
v->value_.push_back(value);
exifDatum.value_ = v;
return exifDatum;
}
/*!
@brief Returns the IfdId of the first Exif makernote tag it finds in the
Exif metadata or ifdIdNotSet if there is no Exif makernote tag.
*/
IfdId hasMakerNote(const ExifData& exifData);
/*!
@brief Add all metadata in the range from iterator position begin to
iterator position end, which have an IFD id matching that of the
IFD to the list of directory entries of ifd. No duplicate checks
are performed, i.e., it is possible to add multiple metadata with
the same key to an IFD.
*/
void addToIfd(Ifd& ifd,
ExifMetadata::const_iterator begin,
ExifMetadata::const_iterator end,
ByteOrder byteOrder);
/*!
@brief Add the Exifdatum to the IFD. No duplicate checks are performed,
i.e., it is possible to add multiple metadata with the same key to
an IFD.
*/
void addToIfd(Ifd& ifd, const Exifdatum& exifdatum, ByteOrder byteOrder);
/*!
@brief Add all metadata in the range from iterator position begin to
iterator position end with IFD id 'makerIfd' to the list of
makernote entries of the object pointed to be makerNote. No
duplicate checks are performed, i.e., it is possible to add
multiple metadata with the same key to a makernote.
@brief Stateless parser class for Exif data. Images use this class to
decode and encode binary Exif data. See class TiffParser for details.
*/
void addToMakerNote(MakerNote* makerNote,
ExifMetadata::const_iterator begin,
ExifMetadata::const_iterator end,
ByteOrder byteOrder);
/*!
@brief Add the Exifdatum to makerNote, encoded in byte order byteOrder.
No duplicate checks are performed, i.e., it is possible to add
multiple metadata with the same key to a makernote.
*/
void addToMakerNote(MakerNote* makerNote,
const Exifdatum& exifdatum,
ByteOrder byteOrder);
class ExifParser {
public:
/*!
@brief Decode metadata from a buffer \em pData of length \em size
with binary Exif data to the provided metadata container.
Return byte order in which the data is encoded.
See TiffParser::decode().
*/
static ByteOrder decode(
ExifData& exifData,
const byte* pData,
uint32_t size
);
/*!
@brief Encode metadata from the provided metadata to Exif format.
See TiffParser::encode().
*/
static WriteMethod encode(
Blob& blob,
const byte* pData,
uint32_t size,
ByteOrder byteOrder,
const ExifData& exifData
);
/*!
@brief Encode metadata from the provided metadata to Exif format.
See TiffParser::encode().
Encode Exif metadata from the \em ExifData container to binary format
in the \em blob encoded in \em byteOrder.
This simpler encode method uses "intrusive" writing, i.e., it builds
the binary representation of the metadata from scratch. It does not
attempt "non-intrusive", i.e., in-place updating. It's better to use
the other encode() method, if the metadata is already available in
binary format, in order to allow for "non-intrusive" updating of the
existing binary representation.
This is just an inline wrapper for
ExifParser::encode(blob, 0, 0, byteOrder, exifData).
*/
static void encode(
Blob& blob,
ByteOrder byteOrder,
const ExifData& exifData
)
{
encode(blob, 0, 0, byteOrder, exifData);
}
}; // class ExifParser
} // namespace Exiv2

@ -35,7 +35,6 @@ EXIV2_RCSID("@(#) $Id$")
// included header files
#include "types.hpp"
#include "fujimn.hpp"
#include "makernote.hpp"
#include "value.hpp"
#include "i18n.h" // NLS support.
@ -50,15 +49,6 @@ EXIV2_RCSID("@(#) $Id$")
// class member definitions
namespace Exiv2 {
//! @cond IGNORE
FujiMakerNote::RegisterMn::RegisterMn()
{
MakerNoteFactory::registerMakerNote("FUJIFILM", "*", createFujiMakerNote);
MakerNoteFactory::registerMakerNote(
fujiIfdId, MakerNote::AutoPtr(new FujiMakerNote));
}
//! @endcond
//! OffOn, multiple tags
extern const TagDetails fujiOffOn[] = {
{ 0, N_("Off") },
@ -293,81 +283,4 @@ namespace Exiv2 {
return tagInfo_;
}
FujiMakerNote::FujiMakerNote(bool alloc)
: IfdMakerNote(fujiIfdId, alloc)
{
byteOrder_ = littleEndian;
absShift_ = false;
byte buf[] = {
'F', 'U', 'J', 'I', 'F', 'I', 'L', 'M', 0x0c, 0x00, 0x00, 0x00
};
readHeader(buf, 12, byteOrder_);
}
FujiMakerNote::FujiMakerNote(const FujiMakerNote& rhs)
: IfdMakerNote(rhs)
{
}
int FujiMakerNote::readHeader(const byte* buf,
long len,
ByteOrder /*byteOrder*/)
{
if (len < 12) return 1;
header_.alloc(12);
std::memcpy(header_.pData_, buf, header_.size_);
// Read offset to the IFD relative to the start of the makernote
// from the header. Note that we ignore the byteOrder paramter
start_ = getUShort(header_.pData_ + 8, byteOrder_);
return 0;
}
int FujiMakerNote::checkHeader() const
{
int rc = 0;
// Check the FUJIFILM prefix
if ( header_.size_ < 12
|| std::string(reinterpret_cast<char*>(header_.pData_), 8)
!= std::string("FUJIFILM", 8)) {
rc = 2;
}
return rc;
}
FujiMakerNote::AutoPtr FujiMakerNote::create(bool alloc) const
{
return AutoPtr(create_(alloc));
}
FujiMakerNote* FujiMakerNote::create_(bool alloc) const
{
AutoPtr makerNote(new FujiMakerNote(alloc));
assert(makerNote.get() != 0);
makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
return makerNote.release();
}
FujiMakerNote::AutoPtr FujiMakerNote::clone() const
{
return AutoPtr(clone_());
}
FujiMakerNote* FujiMakerNote::clone_() const
{
return new FujiMakerNote(*this);
}
// *****************************************************************************
// free functions
MakerNote::AutoPtr createFujiMakerNote(bool alloc,
const byte* /*buf*/,
long /*len*/,
ByteOrder /*byteOrder*/,
long /*offset*/)
{
return MakerNote::AutoPtr(new FujiMakerNote(alloc));
}
} // namespace Exiv2

@ -37,111 +37,27 @@
// *****************************************************************************
// included header files
#include "types.hpp"
#include "makernote.hpp"
#include "tags.hpp"
// + standard includes
#include <string>
#include <iosfwd>
#include <memory>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class Value;
// *****************************************************************************
// free functions
/*!
@brief Return an auto-pointer to a newly created empty MakerNote
initialized to operate in the memory management model indicated.
The caller owns this copy and the auto-pointer ensures that it
will be deleted.
@param alloc Memory management model for the new MakerNote. Determines if
memory required to store data should be allocated and deallocated
(true) or not (false). If false, only pointers to the buffer
provided to read() will be kept. See Ifd for more background on
this concept.
@param buf Pointer to the makernote character buffer (not used).
@param len Length of the makernote character buffer (not used).
@param byteOrder Byte order in which the Exif data (and possibly the
makernote) is encoded (not used).
@param offset Offset from the start of the TIFF header of the makernote
buffer (not used).
@return An auto-pointer to a newly created empty MakerNote. The caller
owns this copy and the auto-pointer ensures that it will be
deleted.
*/
MakerNote::AutoPtr createFujiMakerNote(bool alloc,
const byte* buf,
long len,
ByteOrder byteOrder,
long offset);
// *****************************************************************************
// class definitions
//! MakerNote for Fujifilm cameras
class FujiMakerNote : public IfdMakerNote {
class FujiMakerNote {
public:
//! Shortcut for a %FujiMakerNote auto pointer.
typedef std::auto_ptr<FujiMakerNote> AutoPtr;
//! @name Creators
//@{
/*!
@brief Constructor. Allows to choose whether or not memory management
is required for the makernote entries.
*/
FujiMakerNote(bool alloc =true);
//! Copy constructor
FujiMakerNote(const FujiMakerNote& rhs);
//! Virtual destructor
virtual ~FujiMakerNote() {}
//@}
//! @name Manipulators
//@{
int readHeader(const byte* buf,
long len,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
int checkHeader() const;
AutoPtr create(bool alloc =true) const;
AutoPtr clone() const;
//! Return read-only list of built-in Fujifilm tags
static const TagInfo* tagList();
//@}
//! @cond IGNORE
// Public only so that we can create a static instance
struct RegisterMn {
RegisterMn();
};
//! @endcond
private:
//! Internal virtual create function.
FujiMakerNote* create_(bool alloc =true) const;
//! Internal virtual copy constructor.
FujiMakerNote* clone_() const;
//! Tag information
static const TagInfo tagInfo_[];
}; // class FujiMakerNote
static FujiMakerNote::RegisterMn registerFujiMakerNote;
} // namespace Exiv2
#endif // #ifndef FUJIMN_HPP_

@ -1,788 +0,0 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*
File: ifd.cpp
Version: $Rev$
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("@(#) $Id$")
// *****************************************************************************
// included header files
#include "ifd.hpp"
#include "types.hpp"
#include "error.hpp"
#include "tags.hpp" // for ExifTags::ifdName
#include "i18n.h" // NLS support.
// + standard includes
#include <iostream>
#include <iomanip>
#include <sstream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cassert>
// *****************************************************************************
// class member definitions
namespace Exiv2 {
Entry::Entry(bool alloc)
: alloc_(alloc), ifdId_(ifdIdNotSet), idx_(0),
tag_(0), type_(0), count_(0), offset_(0), size_(0), pData_(0),
sizeDataArea_(0), pDataArea_(0), byteOrder_(invalidByteOrder)
{
}
Entry::~Entry()
{
if (alloc_) {
delete[] pData_;
delete[] pDataArea_;
}
}
Entry::Entry(const Entry& rhs)
: alloc_(rhs.alloc_), ifdId_(rhs.ifdId_), idx_(rhs.idx_),
tag_(rhs.tag_), type_(rhs.type_),
count_(rhs.count_), offset_(rhs.offset_), size_(rhs.size_), pData_(0),
sizeDataArea_(rhs.sizeDataArea_), pDataArea_(0), byteOrder_(rhs.byteOrder_)
{
if (alloc_) {
if (rhs.pData_) {
pData_ = new byte[rhs.size()];
std::memcpy(pData_, rhs.pData_, rhs.size());
}
if (rhs.pDataArea_) {
pDataArea_ = new byte[rhs.sizeDataArea()];
std::memcpy(pDataArea_, rhs.pDataArea_, rhs.sizeDataArea());
}
}
else {
pData_ = rhs.pData_;
pDataArea_ = rhs.pDataArea_;
}
}
Entry& Entry::operator=(const Entry& rhs)
{
if (this == &rhs) return *this;
alloc_ = rhs.alloc_;
ifdId_ = rhs.ifdId_;
idx_ = rhs.idx_;
tag_ = rhs.tag_;
type_ = rhs.type_;
count_ = rhs.count_;
offset_ = rhs.offset_;
size_ = rhs.size_;
sizeDataArea_ = rhs.sizeDataArea_;
byteOrder_ = rhs.byteOrder_;
if (alloc_) {
delete[] pData_;
pData_ = 0;
if (rhs.pData_) {
pData_ = new byte[rhs.size()];
std::memcpy(pData_, rhs.pData_, rhs.size());
}
delete[] pDataArea_;
pDataArea_ = 0;
if (rhs.pDataArea_) {
pDataArea_ = new byte[rhs.sizeDataArea()];
std::memcpy(pDataArea_, rhs.pDataArea_, rhs.sizeDataArea());
}
}
else {
pData_ = rhs.pData_;
pDataArea_ = rhs.pDataArea_;
}
return *this;
} // Entry::operator=
void Entry::setValue(uint32_t data, ByteOrder byteOrder)
{
if (pData_ == 0 || size_ < 4) {
assert(alloc_);
size_ = 4;
delete[] pData_;
pData_ = new byte[size_];
}
ul2Data(pData_, data, byteOrder);
// do not change size_
type_ = unsignedLong;
count_ = 1;
}
void Entry::setValue(uint16_t type, uint32_t count, const byte* buf, long len, ByteOrder byteOrder)
{
byteOrder_ = byteOrder;
long dataSize = count * TypeInfo::typeSize(TypeId(type));
// No minimum size requirement, but make sure the buffer can hold the data
if (len < dataSize) throw Error(24, tag(), dataSize, len);
if (alloc_) {
delete[] pData_;
pData_ = new byte[len];
std::memset(pData_, 0x0, len);
std::memcpy(pData_, buf, dataSize);
size_ = len;
}
else {
if (size_ == 0) {
// Set the data pointer of a virgin entry
pData_ = const_cast<byte*>(buf);
size_ = len;
}
else {
// Overwrite existing data if it fits into the buffer
if (size_ < dataSize) throw Error(24, tag(), dataSize, size_);
std::memset(pData_, 0x0, size_);
std::memcpy(pData_, buf, dataSize);
// do not change size_
}
}
type_ = type;
count_ = count;
} // Entry::setValue
void Entry::setDataArea(const byte* buf, long len)
{
if (alloc_) {
delete[] pDataArea_;
pDataArea_ = new byte[len];
std::memcpy(pDataArea_, buf, len);
sizeDataArea_ = len;
}
else {
if (sizeDataArea_ == 0) {
// Set the data area pointer of a virgin entry
pDataArea_ = const_cast<byte*>(buf);
sizeDataArea_ = len;
}
else {
// Overwrite existing data if it fits into the buffer
if (sizeDataArea_ < len) {
throw Error(25, tag(), sizeDataArea_, len);
}
std::memset(pDataArea_, 0x0, sizeDataArea_);
std::memcpy(pDataArea_, buf, len);
// do not change sizeDataArea_
}
}
} // Entry::setDataArea
void Entry::setDataAreaOffsets(uint32_t offset, ByteOrder byteOrder)
{
// Hack: Do not require offsets to start from 0, except for rationals
uint16_t fusOffset = 0;
uint32_t fulOffset = 0;
int16_t fsOffset = 0;
int32_t flOffset = 0;
for (uint32_t i = 0; i < count(); ++i) {
byte* buf = pData_ + i * typeSize();
switch(TypeId(type())) {
case unsignedShort: {
if (i == 0) fusOffset = getUShort(buf, byteOrder);
uint16_t d = getUShort(buf, byteOrder) - fusOffset;
if (d + offset > 0xffff) throw Error(26);
us2Data(buf, d + static_cast<uint16_t>(offset), byteOrder);
break;
}
case unsignedLong: {
if (i == 0) fulOffset = getULong(buf, byteOrder);
ul2Data(buf, getULong(buf, byteOrder) - fulOffset + offset, byteOrder);
break;
}
case unsignedRational: {
URational d = getURational(buf, byteOrder);
d.first = d.first + offset * d.second;
ur2Data(buf, d, byteOrder);
break;
}
case signedShort: {
if (i == 0) fsOffset = getShort(buf, byteOrder);
int16_t d = getShort(buf, byteOrder) - fsOffset;
if (d + static_cast<int32_t>(offset) > 0xffff) throw Error(26);
s2Data(buf, d + static_cast<int16_t>(offset), byteOrder);
break;
}
case signedLong: {
if (i == 0) flOffset = getLong(buf, byteOrder);
int32_t d = getLong(buf, byteOrder) - flOffset;
l2Data(buf, d + static_cast<int32_t>(offset), byteOrder);
break;
}
case signedRational: {
Rational d = getRational(buf, byteOrder);
d.first = d.first + static_cast<int32_t>(offset) * d.second;
r2Data(buf, d, byteOrder);
break;
}
default:
throw Error(27);
break;
}
}
} // Entry::setDataAreaOffsets
void Entry::updateBase(byte* pOldBase, byte* pNewBase)
{
if (!alloc_) {
if (pDataArea_) {
pDataArea_ = pDataArea_ - pOldBase + pNewBase;
}
if (pData_) {
pData_ = pData_ - pOldBase + pNewBase;
}
}
} // Entry::updateBase
const byte* Entry::component(uint32_t n) const
{
if (n >= count()) return 0;
return data() + n * typeSize();
} // Entry::component
Ifd::Ifd(IfdId ifdId)
: alloc_(true), ifdId_(ifdId), pBase_(0), offset_(0),
dataOffset_(0), hasNext_(true), pNext_(0), next_(0)
{
pNext_ = new byte[4];
std::memset(pNext_, 0x0, 4);
}
Ifd::Ifd(IfdId ifdId, long offset)
: alloc_(true), ifdId_(ifdId), pBase_(0), offset_(offset),
dataOffset_(0), hasNext_(true), pNext_(0), next_(0)
{
pNext_ = new byte[4];
std::memset(pNext_, 0x0, 4);
}
Ifd::Ifd(IfdId ifdId, long offset, bool alloc, bool hasNext)
: alloc_(alloc), ifdId_(ifdId), pBase_(0), offset_(offset),
dataOffset_(0), hasNext_(hasNext), pNext_(0), next_(0)
{
if (alloc_ && hasNext_) {
pNext_ = new byte[4];
std::memset(pNext_, 0x0, 4);
}
}
Ifd::~Ifd()
{
// do not delete pBase_
if (alloc_ && hasNext_) delete[] pNext_;
}
Ifd::Ifd(const Ifd& rhs)
: alloc_(rhs.alloc_), entries_(rhs.entries_), ifdId_(rhs.ifdId_),
pBase_(rhs.pBase_), offset_(rhs.offset_), dataOffset_(rhs.dataOffset_),
hasNext_(rhs.hasNext_), pNext_(rhs.pNext_), next_(rhs.next_)
{
if (alloc_ && hasNext_) {
pNext_ = new byte[4];
std::memset(pNext_, 0x0, 4);
if (rhs.pNext_) std::memcpy(pNext_, rhs.pNext_, 4);
}
}
int Ifd::read(const byte* buf,
long len,
long start,
ByteOrder byteOrder,
long shift)
{
int rc = 0;
long o = start;
Ifd::PreEntries preEntries;
if (o < 0 || len < o + 2) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Error: " << ExifTags::ifdName(ifdId_)
<< " lies outside of the IFD memory buffer.\n";
#endif
rc = 6;
}
int n = 0;
if (rc == 0) {
offset_ = start - shift;
n = getUShort(buf + o, byteOrder);
o += 2;
// Sanity check with an "unreasonably" large number
if (n > 256) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Error: "
<< "Directory " << ExifTags::ifdName(ifdId_) << " with "
<< n << " entries considered invalid; not read.\n";
#endif
rc = 6;
}
}
if (rc == 0) {
for (int i = 0; i < n; ++i) {
if (len < o + 12) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Error: " << ExifTags::ifdName(ifdId_)
<< " entry " << i
<< " lies outside of the IFD memory buffer.\n";
#endif
rc = 6;
break;
}
Ifd::PreEntry pe;
pe.tag_ = getUShort(buf + o, byteOrder);
pe.type_ = getUShort(buf + o + 2, byteOrder);
pe.count_ = getULong(buf + o + 4, byteOrder);
uint32_t ts = TypeInfo::typeSize(TypeId(pe.type_));
if (pe.count_ >= 0x10000000) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: "
<< ExifTags::ifdName(ifdId_) << " tag 0x"
<< std::setw(4) << std::setfill('0') << std::hex
<< pe.tag_ << " has invalid size "
<< std::dec << pe.count_ << "*" << ts
<< "; truncating the data.\n";
#endif
pe.count_ = 0;
}
pe.size_ = pe.count_ * ts;
pe.offsetLoc_ = o + 8 - shift;
pe.offset_ = pe.size_ > 4 ? getLong(buf + o + 8, byteOrder) : 0;
preEntries.push_back(pe);
o += 12;
}
}
if (rc == 0 && hasNext_) {
if (len < o + 4) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Error: " << ExifTags::ifdName(ifdId_)
<< " memory of the pointer to the next IFD"
<< " lies outside of the IFD memory buffer.\n";
#endif
rc = 6;
}
else {
if (alloc_) {
std::memcpy(pNext_, buf + o, 4);
}
else {
pNext_ = const_cast<byte*>(buf + o);
}
next_ = getULong(buf + o, byteOrder);
if ( static_cast<long>(next_) + shift < 0
|| static_cast<long>(next_) + shift >= len) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: " << ExifTags::ifdName(ifdId_)
<< ": Pointer to next IFD is out of bounds; ignored.\n";
#endif
next_ = 0;
}
}
}
// Set the offset of the first data entry outside of the IFD.
if (rc == 0 && preEntries.size() > 0) {
// Find the entry with the smallest offset
Ifd::PreEntries::const_iterator i = std::min_element(
preEntries.begin(), preEntries.end(), cmpPreEntriesByOffset);
// Only do something if there is at least one entry with data
// outside the IFD directory itself.
if (i->size_ > 4) {
// Set the offset of the first data entry outside of the IFD
if (i->offset_ + shift < 0) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Error: Offset of the 1st data entry of "
<< ExifTags::ifdName(ifdId_)
<< " is out of bounds:\n"
<< " Offset = 0x" << std::setw(8)
<< std::setfill('0') << std::hex
<< i->offset_ - offset_ // relative to start of IFD
<< ", is before start of buffer by "
<< std::dec << -1 * (i->offset_ + shift)
<< " Bytes\n";
#endif
rc = 6;
}
else if (i->offset_ + shift + i->size_ > len) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Error: Upper boundary of the 1st data entry of "
<< ExifTags::ifdName(ifdId_)
<< " is out of bounds:\n"
<< " Offset = 0x" << std::setw(8)
<< std::setfill('0') << std::hex
<< i->offset_ - offset_ // relative to start of IFD
<< ", exceeds buffer size by "
<< std::dec << i->offset_ + shift + i->size_ - len
<< " Bytes\n";
#endif
rc = 6;
}
else {
dataOffset_ = i->offset_;
}
}
}
// Convert the pre-IFD entries to the actual entries, assign the data
// to each IFD entry and calculate relative offsets, relative to the
// start of the IFD
if (rc == 0) {
entries_.clear();
int idx = 0;
const Ifd::PreEntries::iterator begin = preEntries.begin();
const Ifd::PreEntries::iterator end = preEntries.end();
for (Ifd::PreEntries::iterator i = begin; i != end; ++i) {
Entry e(alloc_);
e.setIfdId(ifdId_);
e.setIdx(++idx);
e.setTag(i->tag_);
long tmpOffset = // still from the start of the TIFF header
i->size_ > 4 ? i->offset_ : i->offsetLoc_;
if (tmpOffset + shift + i->size_ > len) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Upper boundary of data for "
<< ExifTags::ifdName(ifdId_)
<< " entry " << static_cast<int>(i - begin)
<< " is out of bounds:\n"
<< " Offset = 0x" << std::setw(8)
<< std::setfill('0') << std::hex
<< tmpOffset - offset_ // relative to start of IFD
<< ", size = " << std::dec << i->size_
<< ", exceeds buffer size by "
<< tmpOffset + shift + i->size_ - len
<< " Bytes; Truncating the data.\n";
#endif
// Truncate the entry
i->size_ = 0;
i->count_ = 0;
tmpOffset = i->offsetLoc_;
}
// Set the offset to the data, relative to start of IFD
e.setOffset(tmpOffset - offset_);
// Set the size to at least for bytes to accomodate offset-data
#ifndef SUPPRESS_WARNINGS
if (i->type_ < 1 || i->type_ > 10) {
std::cerr << "Warning: "
<< ExifTags::ifdName(ifdId_) << " tag 0x"
<< std::setw(4) << std::setfill('0') << std::hex
<< i->tag_ << " has invalid Exif type "
<< std::dec << i->type_
<< "; using 7 (undefined).\n";
}
#endif
e.setValue(i->type_, i->count_, buf + start + e.offset(),
std::max(long(4), i->size_));
this->add(e);
}
}
if (!alloc_) pBase_ = const_cast<byte*>(buf);
if (rc) this->clear();
return rc;
} // Ifd::read
Ifd::const_iterator Ifd::findIdx(int idx) const
{
return std::find_if(entries_.begin(), entries_.end(),
FindEntryByIdx(idx));
}
Ifd::iterator Ifd::findIdx(int idx)
{
return std::find_if(entries_.begin(), entries_.end(),
FindEntryByIdx(idx));
}
Ifd::const_iterator Ifd::findTag(uint16_t tag) const
{
return std::find_if(entries_.begin(), entries_.end(),
FindEntryByTag(tag));
}
Ifd::iterator Ifd::findTag(uint16_t tag)
{
return std::find_if(entries_.begin(), entries_.end(),
FindEntryByTag(tag));
}
void Ifd::sortByTag()
{
std::sort(entries_.begin(), entries_.end(), cmpEntriesByTag);
}
int Ifd::readSubIfd(
Ifd& dest, const byte* buf, long len, ByteOrder byteOrder, uint16_t tag
) const
{
int rc = 0;
const_iterator pos = findTag(tag);
if (pos != entries_.end()) {
long offset = getULong(pos->data(), byteOrder);
if (len < offset) {
rc = 6;
}
else {
rc = dest.read(buf, len, offset, byteOrder);
}
}
return rc;
} // Ifd::readSubIfd
long Ifd::copy(byte* buf, ByteOrder byteOrder, long offset)
{
if (entries_.size() == 0 && next_ == 0) return 0;
if (offset != 0) offset_ = offset;
// Add the number of entries to the data buffer
us2Data(buf, static_cast<uint16_t>(entries_.size()), byteOrder);
long o = 2;
// Add all directory entries to the data buffer
long dataSize = 0;
long dataAreaSize = 0;
long totalDataSize = 0;
const iterator b = entries_.begin();
const iterator e = entries_.end();
iterator i;
for (i = b; i != e; ++i) {
if (i->size() > 4) {
totalDataSize += i->size();
}
}
for (i = b; i != e; ++i) {
us2Data(buf + o, i->tag(), byteOrder);
us2Data(buf + o + 2, i->type(), byteOrder);
ul2Data(buf + o + 4, i->count(), byteOrder);
if (i->sizeDataArea() > 0) {
long dataAreaOffset = offset_+size()+totalDataSize+dataAreaSize;
i->setDataAreaOffsets(dataAreaOffset, byteOrder);
dataAreaSize += i->sizeDataArea();
}
if (i->size() > 4) {
// Set the offset of the entry, data immediately follows the IFD
i->setOffset(size() + dataSize);
l2Data(buf + o + 8, offset_ + i->offset(), byteOrder);
dataSize += i->size();
}
else {
// Copy data into the offset field
std::memset(buf + o + 8, 0x0, 4);
std::memcpy(buf + o + 8, i->data(), i->size());
}
o += 12;
}
if (hasNext_) {
// Add the offset to the next IFD to the data buffer
if (pNext_) {
std::memcpy(buf + o, pNext_, 4);
}
else {
std::memset(buf + o, 0x0, 4);
}
o += 4;
}
// Add the data of all IFD entries to the data buffer
for (i = b; i != e; ++i) {
if (i->size() > 4) {
std::memcpy(buf + o, i->data(), i->size());
o += i->size();
}
}
// Add all data areas to the data buffer
for (i = b; i != e; ++i) {
if (i->sizeDataArea() > 0) {
std::memcpy(buf + o, i->dataArea(), i->sizeDataArea());
o += i->sizeDataArea();
}
}
return o;
} // Ifd::copy
void Ifd::clear()
{
entries_.clear();
offset_ = 0;
dataOffset_ = 0;
if (hasNext_) {
if (alloc_) {
std::memset(pNext_, 0x0, 4);
}
else {
pBase_ = 0;
pNext_ = 0;
}
next_ = 0;
}
} // Ifd::clear
void Ifd::setNext(uint32_t next, ByteOrder byteOrder)
{
if (hasNext_) {
assert(pNext_);
ul2Data(pNext_, next, byteOrder);
next_ = next;
}
}
void Ifd::add(const Entry& entry)
{
assert(alloc_ == entry.alloc());
assert(ifdId_ == entry.ifdId());
// allow duplicates
entries_.push_back(entry);
}
int Ifd::erase(uint16_t tag)
{
int idx = 0;
iterator pos = findTag(tag);
if (pos != end()) {
idx = pos->idx();
erase(pos);
}
return idx;
}
Ifd::iterator Ifd::erase(iterator pos)
{
return entries_.erase(pos);
}
byte* Ifd::updateBase(byte* pNewBase)
{
byte *pOld = 0;
if (!alloc_) {
iterator end = this->end();
for (iterator pos = begin(); pos != end; ++pos) {
pos->updateBase(pBase_, pNewBase);
}
if (hasNext_) {
pNext_ = pNext_ - pBase_ + pNewBase;
}
pOld = pBase_;
pBase_ = pNewBase;
}
return pOld;
}
long Ifd::size() const
{
if (entries_.size() == 0 && next_ == 0) return 0;
return static_cast<long>(2 + 12 * entries_.size() + (hasNext_ ? 4 : 0));
}
long Ifd::dataSize() const
{
long dataSize = 0;
const_iterator end = this->end();
for (const_iterator i = begin(); i != end; ++i) {
if (i->size() > 4) dataSize += i->size();
dataSize += i->sizeDataArea();
}
return dataSize;
}
void Ifd::print(std::ostream& os, const std::string& prefix) const
{
if (entries_.size() == 0) return;
// Print a header
os << prefix << _("IFD Offset") << ": 0x"
<< std::setw(8) << std::setfill('0') << std::hex << std::right
<< offset_
<< ", " << _("IFD Entries") << ": "
<< std::setfill(' ') << std::dec << std::right
<< static_cast<unsigned int>(entries_.size()) << "\n"
<< prefix << _("Entry Tag Format (Bytes each) Number Offset\n")
<< prefix << "----- ------ --------------------- ------ -----------\n";
// Print IFD entries
const const_iterator b = entries_.begin();
const const_iterator e = entries_.end();
const_iterator i = b;
for (; i != e; ++i) {
std::ostringstream offset;
if (i->size() > 4) {
offset << " 0x" << std::setw(8) << std::setfill('0')
<< std::hex << std::right << static_cast<int32_t>(i->offset());
}
else {
const byte* data = i->data();
for (int k = 0; k < i->size(); ++k) {
offset << std::setw(2) << std::setfill('0') << std::hex
<< (int)data[k] << " ";
}
}
os << prefix << std::setw(5) << std::setfill(' ') << std::dec
<< std::right << static_cast<int>(i - b)
<< " 0x" << std::setw(4) << std::setfill('0') << std::hex
<< std::right << i->tag()
<< " " << std::setw(17) << std::setfill(' ')
<< std::left << i->typeName()
<< " (" << std::dec << i->typeSize() << ")"
<< " " << std::setw(6) << std::setfill(' ') << std::dec
<< std::right << i->count()
<< " " << offset.str()
<< "\n";
}
if (hasNext_) {
os << prefix << _("Next IFD") << ": 0x"
<< std::setw(8) << std::setfill('0') << std::hex
<< std::right << next() << "\n";
}
// Print data of IFD entries
for (i = b; i != e; ++i) {
if (i->size() > 4) {
os << _("Data of entry") << " " << static_cast<int>(i - b) << ":\n";
hexdump(os, i->data(), i->size(), offset_ + i->offset());
}
}
} // Ifd::print
// *************************************************************************
// free functions
bool cmpEntriesByTag(const Entry& lhs, const Entry& rhs)
{
return lhs.tag() < rhs.tag();
}
bool cmpPreEntriesByOffset(const Ifd::PreEntry& lhs, const Ifd::PreEntry& rhs)
{
// We need to ignore entries with size <= 4, so by definition,
// entries with size <= 4 are greater than those with size > 4
// when compared by their offset.
if (lhs.size_ <= 4) {
return false; // lhs is greater by definition, or they are equal
}
if (rhs.size_ <= 4) {
return true; // rhs is greater by definition (they cannot be equal)
}
return lhs.offset_ < rhs.offset_;
} // cmpPreEntriesByOffset
} // namespace Exiv2

@ -1,616 +0,0 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*!
@file ifd.hpp
@brief Encoding and decoding of IFD (%Image File Directory) data
@version $Rev$
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 09-Jan-04, ahu: created<BR>
11-Feb-04, ahu: isolated as a component
*/
#ifndef IFD_HPP_
#define IFD_HPP_
// *****************************************************************************
// included header files
#include "types.hpp"
// + standard includes
#include <string>
#include <vector>
#include <iosfwd>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class Ifd;
// *****************************************************************************
// class definitions
/*!
@brief Data structure for one IFD directory entry. See the description of
class Ifd for an explanation of the supported modes for memory
allocation.
*/
class Entry {
public:
//! @name Creators
//@{
/*!
@brief Default constructor. The entry allocates memory for its
data if alloc is true (the default), otherwise it remembers
just the pointers into a read and writeable data buffer which
it doesn't allocate or delete.
*/
explicit Entry(bool alloc =true);
//! Destructor
~Entry();
//! Copy constructor
Entry(const Entry& rhs);
//@}
//! @name Manipulators
//@{
//! Assignment operator
Entry& operator=(const Entry& rhs);
//! Set the tag
void setTag(uint16_t tag) { tag_ = tag; }
//! Set the IFD id
void setIfdId(IfdId ifdId) { ifdId_ = ifdId; }
//! Set the index (unique id of an entry within one IFD)
void setIdx(int idx) { idx_ = idx; }
//! Set the offset. The offset is relative to the start of the IFD.
void setOffset(long offset) { offset_ = offset; }
/*!
@brief Set the value of the entry to a single unsigned long component,
i.e., set the type of the entry to unsigned long, number of
components to one and the value according to the data provided.
The size of the data buffer is set to at least four bytes, but is left
unchanged if it can accomodate the pointer. This method can be used
to set the value of a tag which contains a pointer (offset) to a
location in the Exif data (like e.g., ExifTag, 0x8769 in IFD0, which
contains a pointer to the Exif IFD).
<BR>This method cannot be used to set the value of a newly created
%Entry in non-alloc mode.
@note This method is now deprecated, use data area related methods
instead.
*/
void setValue(uint32_t data, ByteOrder byteOrder);
/*!
@brief Set type, count, the data buffer and its size.
Copies the provided buffer when called in memory allocation mode.
<BR>In non-alloc mode, use this method to initialise the data of a
newly created %Entry. In this case, only the pointer to the buffer is
copied, i.e., the buffer must remain valid throughout the life of the
%Entry. Subsequent calls in non-alloc mode will overwrite the data
pointed to by this pointer with the data provided, i.e., the buffer
provided in subsequent calls can be deleted after the call.
<BR>In either memory allocation mode, the data buffer provided must be
large enough to hold count components of type. The size of the buffer
will be as indicated in the size argument. I.e., it is possible to
allocate (set) a data buffer larger than required to hold count
components of the given type.
@param type The type of the data.
@param count Number of components in the buffer.
@param data Pointer to the data buffer.
@param size Size of the desired data buffer in bytes.
@param byteOrder Optional byte order.
@throw Error if no memory allocation is allowed
and the size of the data buffer is larger than the existing
data buffer of the entry or if size is not large enough to hold
count components of the given type.
*/
void setValue(uint16_t type, uint32_t count, const byte* data, long size, ByteOrder byteOrder =invalidByteOrder);
/*!
@brief Set the data area. Memory management as for
setValue(uint16_t, uint32_t, const byte*, long)
For certain tags the regular value of an IFD entry is an offset to a
data area outside of the IFD. Examples are Exif tag 0x8769 in IFD0
(Exif.Image.ExifTag) or tag 0x0201 in IFD1
(Exif.Thumbnail.JPEGInterchangeFormat). The offset of ExifTag points
to a data area containing the Exif IFD. That of JPEGInterchangeFormat
contains the JPEG thumbnail image.
This method sets the data area of a tag in accordance with the memory
allocation mode.
@param buf Pointer to the data area.
@param len Size of the data area.
@throw Error in non-alloc mode, if there already is a dataarea but the
size of the existing dataarea is not large enough for the
new buffer.
*/
void setDataArea(const byte* buf, long len);
/*!
@brief Set the offset(s) to the data area of an entry.
Add @em offset to each data component of the entry. This is used by
Ifd::copy to convert the data components of an entry containing
offsets relative to the data area to become offsets from the start of
the TIFF header. Usually, entries with a data area have exactly one
unsigned long data component, which is 0.
@param offset Offset
@param byteOrder Byte order
@throw Error if the offset is out of range for the data type of the
tag or the data type is not supported.
*/
void setDataAreaOffsets(uint32_t offset, ByteOrder byteOrder);
/*!
@brief Update the base pointer of the Entry from \em pOldBase
to \em pNewBase.
Allows to re-locate the underlying data buffer to a new location
\em pNewBase. This method only has an effect in non-alloc mode.
@param pOldBase Base pointer of the old data buffer
@param pNewBase Base pointer of the new data buffer
*/
void updateBase(byte* pOldBase, byte* pNewBase);
//@}
//! @name Accessors
//@{
//! Return the tag
uint16_t tag() const { return tag_; }
//! Return the type id.
uint16_t type() const { return type_; }
//! Return the name of the type
const char* typeName() const
{ return TypeInfo::typeName(TypeId(type_)); }
//! Return the size in bytes of one element of this type
long typeSize() const
{ return TypeInfo::typeSize(TypeId(type_)); }
//! Return the IFD id
IfdId ifdId() const { return ifdId_; }
//! Return the index (unique id >0 of an entry within an IFD, 0 if not set)
int idx() const { return idx_; }
//! Return the number of components in the value
uint32_t count() const { return count_; }
/*!
@brief Return the size of the data buffer in bytes.
@note There is no minimum size for the data buffer, except that it
must be large enough to hold the data.
*/
long size() const { return size_; }
//! Return the offset from the start of the IFD to the data of the entry
long offset() const { return offset_; }
/*!
@brief Return a pointer to the data buffer. Do not attempt to write
to this pointer.
*/
const byte* data() const { return pData_; }
/*!
@brief Return a pointer to the n-th component, 0 if there is no
n-th component. Do not attempt to write to this pointer.
*/
const byte* component(uint32_t n) const;
//! Get the memory allocation mode
bool alloc() const { return alloc_; }
//! Return the size of the data area.
long sizeDataArea() const { return sizeDataArea_; }
/*!
@brief Return a pointer to the data area. Do not attempt to write to
this pointer.
For certain tags the regular value of an IFD entry is an offset to a
data area outside of the IFD. Examples are Exif tag 0x8769 in IFD0
(Exif.Image.ExifTag) or tag 0x0201 in IFD1
(Exif.Thumbnail.JPEGInterchangeFormat). The offset of ExifTag points
to a data area containing the Exif IFD. That of JPEGInterchangeFormat
contains the JPEG thumbnail image.
Use this method to access (read-only) the data area of a tag. Use
setDataArea() to write to the data area.
@return Return a pointer to the data area.
*/
const byte* dataArea() const { return pDataArea_; }
/*!
@brief Return the byte order of the entry. There should generally
not be a need for this, it is only used in special cases
(Minolta Makernote CameraSettings tags).
*/
ByteOrder byteOrder() const { return byteOrder_; }
//@}
private:
// DATA
/*!
True: Requires memory allocation and deallocation,<BR>
False: No memory management needed.
*/
bool alloc_;
//! Redundant IFD id (it is also at the IFD)
IfdId ifdId_;
//! Unique id of an entry within an IFD (0 if not set)
int idx_;
//! Tag
uint16_t tag_;
//! Type
uint16_t type_;
//! Number of components
uint32_t count_;
//! Offset from the start of the IFD to the data
long offset_;
/*!
Size of the data buffer holding the value in bytes, there is
no minimum size.
*/
long size_;
//! Pointer to the data buffer
byte* pData_;
//! Size of the data area
long sizeDataArea_;
//! Pointer to the data area
byte* pDataArea_;
//! Byte order (optional, only used for special cases)
ByteOrder byteOrder_;
}; // class Entry
//! Container type to hold all IFD directory entries
typedef std::vector<Entry> Entries;
//! Unary predicate that matches an Entry with a given index
class FindEntryByIdx {
public:
//! Constructor, initializes the object with the index to look for
FindEntryByIdx(int idx) : idx_(idx) {}
/*!
@brief Returns true if the idx of the argument entry is equal
to that of the object.
*/
bool operator()(const Entry& entry) const
{ return idx_ == entry.idx(); }
private:
int idx_;
}; // class FindEntryByIdx
//! 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_t tag) : tag_(tag) {}
/*!
@brief Returns true if the tag of the argument entry is equal
to that of the object.
*/
bool operator()(const Entry& entry) const
{ return tag_ == entry.tag(); }
private:
uint16_t tag_;
}; // class FindEntryByTag
/*!
@brief Models an IFD (%Image File Directory)
This class models an IFD as described in the TIFF 6.0 specification.
An instance of class %Ifd can operate in two modes, one that allocates and
deallocates the memory required to store data, and one that doesn't
perform such memory management.
<BR>An external data buffer (not managed by %Ifd) is needed for an instance
of %Ifd which operates in no memory management mode. The %Ifd will
maintain only pointers into this buffer.
<BR> The mode without memory management is used to make "non-intrusive
write support" possible. This allows writing to Exif data of an image
without changing the data layout of the Exif data, to maximize chances
that tag data, which the Exif reader may not understand (e.g., the
Makernote) remains valid. A "non-intrusive write operation" is the
modification of tag data without increasing the data size.
@note Use the mode with memory management (the default) if you are unsure
or if these memory management considerations are of no concern to you.
@note The two different modes imply completely different copy and
assignment behaviours, with the first resulting in entirely separate
classes and the second mode resulting in multiple classes using one
and the same data buffer.
*/
class Ifd {
//! @name Not implemented
//@{
//! Assignment not allowed (memory management mode alloc_ is const)
Ifd& operator=(const Ifd& rhs);
//@}
public:
//! %Entries const iterator type
typedef Entries::const_iterator const_iterator;
//! %Entries iterator type
typedef Entries::iterator iterator;
//! @name Creators
//@{
/*!
@brief Constructor. Allows to set the IFD identifier. Memory management
is enabled, offset is set to 0. Serves as default constructor.
*/
explicit Ifd(IfdId ifdId =ifdIdNotSet);
/*!
@brief Constructor. Allows to set the IFD identifier and the offset of
the IFD from the start of TIFF header. Memory management is
enabled.
*/
Ifd(IfdId ifdId, long offset);
/*!
@brief Constructor. Allows to set the IFD identifier, offset of the
IFD from the start of TIFF header, choose whether or not
memory management is required for the Entries, and decide
whether this IFD has a next pointer.
*/
Ifd(IfdId ifdId, long offset, bool alloc, bool hasNext =true);
//! Copy constructor
Ifd(const Ifd& rhs);
//! Destructor
~Ifd();
//@}
//! @name Manipulators
//@{
/*!
@brief Read a complete IFD and its data from a data buffer
@param buf Pointer to the Exif data buffer that contains the IFD to
decode. Usually, the buffer will contain all Exif data
starting from the TIFF header.
@param len Number of bytes in the Exif data buffer.
@param start IFD starts at buf + start.
@param byteOrder Applicable byte order (little or big endian).
@param shift IFD offsets are relative to buf + shift.
@return 0 if successful;<BR>
6 if the data buffer is too small, e.g., if an offset points
beyond the provided buffer. The IFD is cleared in this
case.
*/
int read(const byte* buf,
long len,
long start,
ByteOrder byteOrder,
long shift =0);
/*!
@brief Copy the IFD to a data array, update the offsets of the IFD and
all its entries, return the number of bytes written.
First the number of IFD entries is written (2 bytes), followed
by all directory entries: tag (2), type (2), number of data
components (4) and offset to the data or the data, if it
occupies not more than four bytes (4). The directory entries
are followed by the offset of the next IFD (4). All these
fields are encoded according to the byte order argument. Data
that doesn't fit into the offset fields follows immediately
after the IFD entries. The offsets in the IFD are set to
correctly point to the data fields, using the offset parameter
or the offset of the IFD.
@param buf Pointer to the data buffer. The user must ensure that the
buffer has enough memory. Otherwise the call results in
undefined behaviour.
@param byteOrder Applicable byte order (little or big endian).
@param offset Target offset from the start of the TIFF header of the
data array. The IFD offsets will be adjusted as necessary. If
not given, then it is assumed that the IFD will remain at its
original position, i.e., the offset of the IFD will be used.
@return Returns the number of characters written.
*/
long copy(byte* buf, ByteOrder byteOrder, long offset =0);
/*!
@brief Reset the IFD. Delete all IFD entries from the class and put
the object in a state where it can accept completely new
entries.
*/
void clear();
/*!
@brief Set the offset of the next IFD. Byte order is needed to update
the underlying data buffer in non-alloc mode. This method only
has an effect if the IFD was instantiated with hasNext = true.
*/
void setNext(uint32_t next, ByteOrder byteOrder);
/*!
@brief Add the entry to the IFD. No duplicate-check is performed,
i.e., it is possible to add multiple entries with the same tag.
The memory allocation mode of the entry to be added must match
that of the IFD and the IFD ids of the IFD and entry must
match.
*/
void add(const Entry& entry);
/*!
@brief Delete the directory entry with the given tag. Return the index
of the deleted entry or 0 if no entry with tag was found.
*/
int erase(uint16_t tag);
/*!
@brief Delete the directory entry at iterator position pos, return the
position of the next entry. Note that iterators into the
directory, including pos, are potentially invalidated by this
call.
*/
iterator erase(iterator pos);
//! Sort the IFD entries by tag
void sortByTag();
//! The first entry
iterator begin() { return entries_.begin(); }
//! End of the entries
iterator end() { return entries_.end(); }
//! Find an IFD entry by idx, return an iterator into the entries list
iterator findIdx(int idx);
//! Find an IFD entry by tag, return an iterator into the entries list
iterator findTag(uint16_t tag);
/*!
@brief Update the base pointer of the Ifd and all entries to \em pNewBase.
Allows to re-locate the underlying data buffer to a new location
\em pNewBase. This method only has an effect in non-alloc mode.
@param pNewBase Pointer to the new data buffer
@return Old base pointer or 0 if called in alloc mode
*/
byte* updateBase(byte* pNewBase);
//@}
//! @name Accessors
//@{
/*!
@brief Read a sub-IFD from the location pointed to by the directory entry
with the given tag.
@param dest References the destination IFD.
@param buf The data buffer to read from. The buffer must contain all Exif
data starting from the TIFF header.
@param len Number of bytes in the data buffer
@param byteOrder Applicable byte order (little or big endian).
@param tag Tag to look for.
@return 0 if successful;<BR>
6 if reading the sub-IFD failed (see read() above) or
the location pointed to by the directory entry with the
given tag is outside of the data buffer.
@note It is not considered an error if the tag cannot be found in the
IFD. 0 is returned and no action is taken in this case.
*/
int readSubIfd(
Ifd& dest, const byte* buf, long len, ByteOrder byteOrder, uint16_t tag
) const;
//! Get the memory allocation mode, see the Ifd class description for details
bool alloc() const { return alloc_; }
//! The first entry
const_iterator begin() const { return entries_.begin(); }
//! End of the entries
const_iterator end() const { return entries_.end(); }
//! Find an IFD entry by idx, return a const iterator into the entries list
const_iterator findIdx(int idx) const;
//! Find an IFD entry by tag, return a const iterator into the entries list
const_iterator findTag(uint16_t tag) const;
//! Get the IfdId of the IFD
IfdId ifdId() const { return ifdId_; }
//! Get the offset of the IFD from the start of the TIFF header
long offset() const { return offset_; }
/*!
@brief Get the offset of the first data entry outside of the IFD from
the start of the TIFF header, return 0 if there is none. The
data offset is determined when the IFD is read.
*/
long dataOffset() const { return dataOffset_; }
//! Get the offset to the next IFD from the start of the TIFF header
uint32_t next() const { return next_; }
//! Get the number of directory entries in the IFD
long count() const { return static_cast<long>(entries_.size()); }
//! Get the size of this IFD in bytes (IFD only, without data)
long size() const;
/*!
@brief Return the total size of the data of this IFD in bytes; sums
the size of all directory entries where size is greater than
four plus the size of all data areas, i.e., all data that
requires memory outside the IFD directory entries is counted.
*/
long dataSize() const;
/*!
@brief Print the IFD in human readable format to the given stream;
begin each line with prefix.
*/
void print(std::ostream& os, const std::string& prefix ="") const;
//@}
private:
//! Helper structure to build IFD entries
struct PreEntry {
uint16_t tag_;
uint16_t type_;
uint32_t count_;
long size_;
long offsetLoc_;
long offset_;
};
//! cmpPreEntriesByOffset needs to know about PreEntry, that's all.
friend bool cmpPreEntriesByOffset(const PreEntry&, const PreEntry&);
//! Container for 'pre-entries'
typedef std::vector<PreEntry> PreEntries;
// DATA
/*!
True: requires memory allocation and deallocation,
False: no memory management needed.
*/
const bool alloc_;
//! IFD entries
Entries entries_;
//! IFD Id
IfdId ifdId_;
//! Pointer to IFD
byte* pBase_;
//! Offset of the IFD from the start of the TIFF header
long offset_;
//! Offset of the first data entry outside of the IFD directory
long dataOffset_;
//! Indicates whether the IFD has a next pointer
bool hasNext_;
//! Pointer to the offset of next IFD
byte* pNext_;
/*!
The offset of the next IFD from the start of the TIFF header as data
value (always in sync with *pNext_)
*/
uint32_t next_;
}; // class Ifd
// *****************************************************************************
// free functions
/*!
@brief Compare two IFD entries by tag. Return true if the tag of entry
lhs is less than that of rhs.
*/
bool cmpEntriesByTag(const Entry& lhs, const Entry& rhs);
/*!
@brief Compare two 'pre-IFD entries' by offset, taking care of special
cases where one or both of the entries don't have an offset.
Return true if the offset of entry lhs is less than that of rhs,
else false. By definition, entries without an offset are greater
than those with an offset.
*/
bool cmpPreEntriesByOffset(const Ifd::PreEntry& lhs, const Ifd::PreEntry& rhs);
} // namespace Exiv2
#endif // #ifndef IFD_HPP_

@ -117,10 +117,11 @@ namespace Exiv2 {
imageType_(imageType),
supportedMetadata_(supportedMetadata),
#ifdef EXV_HAVE_XMP_TOOLKIT
writeXmpFromPacket_(false)
writeXmpFromPacket_(false),
#else
writeXmpFromPacket_(true)
writeXmpFromPacket_(true),
#endif
byteOrder_(invalidByteOrder)
{
}
@ -203,6 +204,11 @@ namespace Exiv2 {
comment_ = comment;
}
void Image::setByteOrder(ByteOrder byteOrder)
{
byteOrder_ = byteOrder;
}
bool Image::good() const
{
if (io_->open() != 0) return false;
@ -341,47 +347,6 @@ namespace Exiv2 {
return Image::AutoPtr();
} // ImageFactory::create
TiffHeader::TiffHeader(ByteOrder byteOrder)
: byteOrder_(byteOrder), tag_(0x002a), offset_(0x00000008)
{
}
int TiffHeader::read(const byte* buf)
{
if (buf[0] == 0x49 && buf[1] == 0x49) {
byteOrder_ = littleEndian;
}
else if (buf[0] == 0x4d && buf[1] == 0x4d) {
byteOrder_ = bigEndian;
}
else {
return 1;
}
tag_ = getUShort(buf+2, byteOrder_);
offset_ = getULong(buf+4, byteOrder_);
return 0;
}
long TiffHeader::copy(byte* buf) const
{
switch (byteOrder_) {
case littleEndian:
buf[0] = 0x49;
buf[1] = 0x49;
break;
case bigEndian:
buf[0] = 0x4d;
buf[1] = 0x4d;
break;
case invalidByteOrder:
// do nothing
break;
}
us2Data(buf+2, 0x002a, byteOrder_);
ul2Data(buf+4, 0x00000008, byteOrder_);
return size();
} // TiffHeader::copy
// *****************************************************************************
// template, inline and free functions

@ -50,12 +50,6 @@
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// type definitions
//! Container for binary image
typedef std::vector<byte> Blob;
// *****************************************************************************
// class definitions
@ -274,10 +268,25 @@ namespace Exiv2 {
access to the raw XMP packet.
*/
void writeXmpFromPacket(bool flag);
/*!
@brief Set the byte order to encode the Exif metadata in.
The setting is only used when new Exif metadata is created and may
not be applicable at all for some image formats. If the target image
already contains Exif metadata, the byte order of the existing data
is used. If byte order is not set when writeMetadata() is called,
little-endian byte order (II) is used by default.
*/
void setByteOrder(ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
/*!
@brief Return the byte order in which the Exif metadata of the image is
encoded. Initially, it is not set (\em invalidByteOrder).
*/
ByteOrder byteOrder() const { return byteOrder_; }
/*!
@brief Check if the Image instance is valid. Use after object
construction.
@ -402,6 +411,7 @@ namespace Exiv2 {
const int imageType_; //!< Image type
const uint16_t supportedMetadata_; //!< Bitmap with all supported metadata types
bool writeXmpFromPacket_;//!< Determines the source when writing XMP
ByteOrder byteOrder_; //!< Byte order
}; // class Image
@ -577,60 +587,6 @@ namespace Exiv2 {
static const Registry registry_[];
}; // class ImageFactory
//! Helper class modelling the TIFF header structure.
class TiffHeader {
public:
//! @name Creators
//@{
/*!
@brief Default constructor. Optionally sets the byte order
(default: little endian).
*/
explicit TiffHeader(ByteOrder byteOrder =littleEndian);
//@}
//! @name Manipulators
//@{
//! Read the TIFF header from a data buffer. Returns 0 if successful.
int read(const byte* buf);
//@}
//! @name Accessors
//@{
/*!
@brief Write a standard TIFF header into buf as a data string, return
number of bytes copied.
Only the byte order of the TIFF header varies, the values written for
offset and tag are constant, i.e., independent of the values possibly
read before a call to this function. The value 0x00000008 is written
for the offset, tag is set to 0x002a.
@param buf The data buffer to write to.
@return The number of bytes written.
*/
long copy(byte* buf) const;
//! Return the size of the TIFF header in bytes.
long size() const { return 8; }
//! Return the byte order (little or big endian).
ByteOrder byteOrder() const { return byteOrder_; }
//! Return the tag value.
uint16_t tag() const { return tag_; }
/*!
@brief Return the offset to IFD0 from the start of the TIFF header.
The offset is 0x00000008 if IFD0 begins immediately after the
TIFF header.
*/
uint32_t offset() const { return offset_; }
//@}
private:
ByteOrder byteOrder_;
uint16_t tag_;
uint32_t offset_;
}; // class TiffHeader
// *****************************************************************************
// template, inline and free functions

@ -41,6 +41,27 @@ EXIV2_RCSID("@(#) $Id$")
#include <iostream>
#include <algorithm>
// *****************************************************************************
namespace {
/*!
@brief Read a single dataset payload and create a new metadata entry.
@param iptcData IPTC metadata container to add the dataset to
@param dataSet DataSet number
@param record Record Id
@param data Pointer to the first byte of dataset payload
@param sizeData Length in bytes of dataset payload
@return 0 if successful.
*/
int readData(
Exiv2::IptcData& iptcData,
uint16_t dataSet,
uint16_t record,
const Exiv2::byte* data,
uint32_t sizeData
);
}
// *****************************************************************************
// class member definitions
namespace Exiv2 {
@ -123,8 +144,6 @@ namespace Exiv2 {
value_->read(value);
}
const byte IptcData::marker_ = 0x1C; // Dataset marker
Iptcdatum& IptcData::operator[](const std::string& key)
{
IptcKey iptcKey(key);
@ -136,20 +155,100 @@ namespace Exiv2 {
return *pos;
}
int IptcData::load(const byte* buf, long len)
long IptcData::size() const
{
long newSize = 0;
const_iterator iter = iptcMetadata_.begin();
const_iterator end = iptcMetadata_.end();
for ( ; iter != end; ++iter) {
// marker, record Id, dataset num, first 2 bytes of size
newSize += 5;
long dataSize = iter->size();
newSize += dataSize;
if (dataSize > 32767) {
// extended dataset (we always use 4 bytes)
newSize += 4;
}
}
return newSize;
} // IptcData::size
int IptcData::add(const IptcKey& key, Value* value)
{
return add(Iptcdatum(key, value));
}
int IptcData::add(const Iptcdatum& iptcDatum)
{
if (!IptcDataSets::dataSetRepeatable(
iptcDatum.tag(), iptcDatum.record()) &&
findId(iptcDatum.tag(), iptcDatum.record()) != end()) {
return 6;
}
// allow duplicates
iptcMetadata_.push_back(iptcDatum);
return 0;
}
IptcData::const_iterator IptcData::findKey(const IptcKey& key) const
{
return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
FindMetadatumById(key.tag(), key.record()));
}
IptcData::iterator IptcData::findKey(const IptcKey& key)
{
return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
FindMetadatumById(key.tag(), key.record()));
}
IptcData::const_iterator IptcData::findId(uint16_t dataset, uint16_t record) const
{
return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
FindMetadatumById(dataset, record));
}
IptcData::iterator IptcData::findId(uint16_t dataset, uint16_t record)
{
return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
FindMetadatumById(dataset, record));
}
void IptcData::sortByKey()
{
std::sort(iptcMetadata_.begin(), iptcMetadata_.end(), cmpMetadataByKey);
}
void IptcData::sortByTag()
{
std::sort(iptcMetadata_.begin(), iptcMetadata_.end(), cmpMetadataByTag);
}
IptcData::iterator IptcData::erase(IptcData::iterator pos)
{
return iptcMetadata_.erase(pos);
}
const byte IptcParser::marker_ = 0x1C; // Dataset marker
int IptcParser::decode(
IptcData& iptcData,
const byte* pData,
uint32_t size
)
{
#ifdef DEBUG
std::cerr << "IptcData::load, len = " << len << "\n";
std::cerr << "IptcParser::decode, size = " << size << "\n";
#endif
const byte* pRead = buf;
iptcMetadata_.clear();
const byte* pRead = pData;
iptcData.clear();
uint16_t record = 0;
uint16_t dataSet = 0;
uint32_t sizeData = 0;
byte extTest = 0;
while (pRead + 3 < buf + len) {
while (pRead + 3 < pData + size) {
// First byte should be a marker. If it isn't, scan forward and skip
// the chunk bytes present in some images. This deviates from the
// standard, which advises to treat such cases as errors.
@ -173,9 +272,9 @@ namespace Exiv2 {
sizeData = getUShort(pRead, bigEndian);
pRead += 2;
}
if (pRead + sizeData <= buf + len) {
if (pRead + sizeData <= pData + size) {
int rc = 0;
if ((rc = readData(dataSet, record, pRead, sizeData)) != 0) {
if ((rc = readData(iptcData, dataSet, record, pRead, sizeData)) != 0) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: "
<< "Failed to read IPTC dataset "
@ -195,38 +294,15 @@ namespace Exiv2 {
}
return 0;
} // IptcData::load
} // IptcParser::decode
int IptcData::readData(uint16_t dataSet, uint16_t record,
const byte* data, uint32_t sizeData)
DataBuf IptcParser::encode(const IptcData& iptcData)
{
Value::AutoPtr value;
TypeId type = IptcDataSets::dataSetType(dataSet, record);
value = Value::create(type);
int rc = value->read(data, sizeData, bigEndian);
if (0 == rc) {
IptcKey key(dataSet, record);
add(key, value.get());
}
else if (1 == rc) {
// If the first attempt failed, try with a string value
value = Value::create(string);
rc = value->read(data, sizeData, bigEndian);
if (0 == rc) {
IptcKey key(dataSet, record);
add(key, value.get());
}
}
return rc;
}
DataBuf IptcData::copy() const
{
DataBuf buf(size());
DataBuf buf(iptcData.size());
byte *pWrite = buf.pData_;
const_iterator iter = iptcMetadata_.begin();
const_iterator end = iptcMetadata_.end();
IptcData::const_iterator iter = iptcData.begin();
IptcData::const_iterator end = iptcData.end();
for ( ; iter != end; ++iter) {
// marker, record Id, dataset num
*pWrite++ = marker_;
@ -247,85 +323,44 @@ namespace Exiv2 {
us2Data(pWrite, static_cast<uint16_t>(dataSize), bigEndian);
pWrite += 2;
}
pWrite += iter->value().copy(pWrite, bigEndian);
}
return buf;
} // IptcData::copy
} // IptcParser::encode
long IptcData::size() const
{
long newSize = 0;
const_iterator iter = iptcMetadata_.begin();
const_iterator end = iptcMetadata_.end();
for ( ; iter != end; ++iter) {
// marker, record Id, dataset num, first 2 bytes of size
newSize += 5;
long dataSize = iter->size();
newSize += dataSize;
if (dataSize > 32767) {
// extended dataset (we always use 4 bytes)
newSize += 4;
}
}
return newSize;
} // IptcData::size
int IptcData::add(const IptcKey& key, Value* value)
{
return add(Iptcdatum(key, value));
}
} // namespace Exiv2
int IptcData::add(const Iptcdatum& iptcDatum)
// *****************************************************************************
// local definitions
namespace {
int readData(
Exiv2::IptcData& iptcData,
uint16_t dataSet,
uint16_t record,
const Exiv2::byte* data,
uint32_t sizeData
)
{
if (!IptcDataSets::dataSetRepeatable(
iptcDatum.tag(), iptcDatum.record()) &&
findId(iptcDatum.tag(), iptcDatum.record()) != end()) {
return 6;
Exiv2::Value::AutoPtr value;
Exiv2::TypeId type = Exiv2::IptcDataSets::dataSetType(dataSet, record);
value = Exiv2::Value::create(type);
int rc = value->read(data, sizeData, Exiv2::bigEndian);
if (0 == rc) {
Exiv2::IptcKey key(dataSet, record);
iptcData.add(key, value.get());
}
// allow duplicates
iptcMetadata_.push_back(iptcDatum);
return 0;
}
IptcData::const_iterator IptcData::findKey(const IptcKey& key) const
{
return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
FindMetadatumById(key.tag(), key.record()));
}
IptcData::iterator IptcData::findKey(const IptcKey& key)
{
return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
FindMetadatumById(key.tag(), key.record()));
}
IptcData::const_iterator IptcData::findId(uint16_t dataset, uint16_t record) const
{
return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
FindMetadatumById(dataset, record));
}
IptcData::iterator IptcData::findId(uint16_t dataset, uint16_t record)
{
return std::find_if(iptcMetadata_.begin(), iptcMetadata_.end(),
FindMetadatumById(dataset, record));
}
void IptcData::sortByKey()
{
std::sort(iptcMetadata_.begin(), iptcMetadata_.end(), cmpMetadataByKey);
}
void IptcData::sortByTag()
{
std::sort(iptcMetadata_.begin(), iptcMetadata_.end(), cmpMetadataByTag);
}
IptcData::iterator IptcData::erase(IptcData::iterator pos)
{
return iptcMetadata_.erase(pos);
else if (1 == rc) {
// If the first attempt failed, try with a string value
value = Exiv2::Value::create(Exiv2::string);
rc = value->read(data, sizeData, Exiv2::bigEndian);
if (0 == rc) {
Exiv2::IptcKey key(dataSet, record);
iptcData.add(key, value.get());
}
}
return rc;
}
} // namespace Exiv2
}

@ -214,15 +214,6 @@ namespace Exiv2 {
//! @name Manipulators
//@{
/*!
@brief Load the IPTC data from a byte buffer. The format must follow
the IPTC IIM4 standard.
@param buf Pointer to the data buffer to read from
@param len Number of bytes in the data buffer
@return 0 if successful;<BR>
5 if IPTC data is invalid or corrupt;<BR>
*/
int load(const byte* buf, long len);
/*!
@brief Returns a reference to the %Iptcdatum that is associated with a
particular \em key. If %IptcData does not already contain such
@ -285,13 +276,6 @@ namespace Exiv2 {
const_iterator begin() const { return iptcMetadata_.begin(); }
//! End of the metadata
const_iterator end() const { return iptcMetadata_.end(); }
/*!
@brief Write the IPTC data to a data buffer and return the data buffer.
Caller owns this buffer. The copied data follows the IPTC IIM4
standard.
@return Data buffer containing the IPTC data.
*/
DataBuf copy() const;
/*!
@brief Find the first Iptcdatum with the given key, return a const
iterator to it.
@ -314,23 +298,50 @@ namespace Exiv2 {
//@}
private:
// DATA
IptcMetadata iptcMetadata_;
}; // class IptcData
/*!
@brief Stateless parser class for IPTC data. Images use this class to
decode and encode binary IPTC data.
*/
class IptcParser {
public:
/*!
@brief Read a single dataset payload and create a new metadata entry
@param dataSet DataSet number
@param record Record Id
@param data Pointer to the first byte of dataset payload
@param sizeData Length in bytes of dataset payload
@return 0 if successful.
@brief Decode IPTC data in IPTC IIM4 format from a buffer \em pData
of length \em size to the provided metadata container.
@param iptcData Metadata container to add the decoded IPTC data to.
@param pData Pointer to the data buffer to read from.
@param size Number of bytes in the data buffer.
@return 0 if successful;<BR>
5 if the binary IPTC data is invalid or corrupt
*/
static int decode(
IptcData& iptcData,
const byte* pData,
uint32_t size
);
/*!
@brief Encode metadata from the provided metadata to IPTC IIM4 format.
Write the IPTC data to a data buffer and return the data buffer.
Caller owns this buffer. The copied data follows the IPTC IIM4
standard.
@return Data buffer containing the IPTC data.
*/
int readData(uint16_t dataSet, uint16_t record,
const byte* data, uint32_t sizeData);
static DataBuf encode(
const IptcData& iptcData
);
private:
// Constant data
static const byte marker_; // Dataset marker
static const byte marker_; // Dataset marker
// DATA
IptcMetadata iptcMetadata_;
}; // class IptcData
}; // class IptcParser
} // namespace Exiv2

@ -176,7 +176,9 @@ namespace Exiv2 {
DataBuf rawExif(box.boxLength - (sizeof(box) + sizeof(uuid)));
io_->read(rawExif.pData_, rawExif.size_);
if (io_->error() || io_->eof()) throw Error(14);
if (exifData_.load(rawExif.pData_, rawExif.size_)) {
ByteOrder bo = ExifParser::decode(exifData_, rawExif.pData_, rawExif.size_);
setByteOrder(bo);
if (rawExif.size_ > 0 && byteOrder() == invalidByteOrder) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Failed to decode Exif metadata.\n";
#endif
@ -189,7 +191,7 @@ namespace Exiv2 {
DataBuf rawIPTC(box.boxLength - (sizeof(box) + sizeof(uuid)));
io_->read(rawIPTC.pData_, rawIPTC.size_);
if (io_->error() || io_->eof()) throw Error(14);
if (iptcData_.load(rawIPTC.pData_, rawIPTC.size_)) {
if (IptcParser::decode(iptcData_, rawIPTC.pData_, rawIPTC.size_)) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Failed to decode IPTC metadata.\n";
#endif

@ -197,7 +197,7 @@ namespace Exiv2 {
append(psBlob, pPsData, sizeFront);
}
// Write new iptc record if we have it
DataBuf rawIptc(iptcData.copy());
DataBuf rawIptc = IptcParser::encode(iptcData);
if (rawIptc.size_ > 0) {
byte tmpBuf[12];
std::memcpy(tmpBuf, Photoshop::bimId_, 4);
@ -315,7 +315,9 @@ namespace Exiv2 {
DataBuf rawExif(size - 8);
io_->read(rawExif.pData_, rawExif.size_);
if (io_->error() || io_->eof()) throw Error(14);
if (exifData_.load(rawExif.pData_, rawExif.size_)) {
ByteOrder bo = ExifParser::decode(exifData_, rawExif.pData_, rawExif.size_);
setByteOrder(bo);
if (rawExif.size_ > 0 && byteOrder() == invalidByteOrder) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Failed to decode Exif metadata.\n";
#endif
@ -422,7 +424,7 @@ namespace Exiv2 {
break;
}
// Skip the remainder of the unknown segment
if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(14);
if (io_->seek(size - bufRead, BasicIo::cur)) throw Error(14);
}
// Read the beginning of the next segment
marker = advanceToMarker();
@ -433,7 +435,7 @@ namespace Exiv2 {
} // while there are segments to process
if ( iptcBlob.size() > 0
&& iptcData_.load(&iptcBlob[0], static_cast<long>(iptcBlob.size()))) {
&& IptcParser::decode(iptcData_, &iptcBlob[0], iptcBlob.size())) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Failed to decode IPTC metadata.\n";
#endif
@ -484,6 +486,7 @@ namespace Exiv2 {
int skipApp13Ps3 = -1;
int skipCom = -1;
DataBuf psData;
DataBuf rawExif;
// Write image header
if (writeHeader(outIo)) throw Error(21);
@ -510,7 +513,11 @@ namespace Exiv2 {
if (size < 8) throw Error(22);
skipApp1Exif = count;
++search;
if (io_->seek(size-bufRead, BasicIo::cur)) throw Error(22);
// Seek to beginning and read the current Exif data
io_->seek(8 - bufRead, BasicIo::cur);
rawExif.alloc(size - 8);
io_->read(rawExif.pData_, rawExif.size_);
if (io_->error() || io_->eof()) throw Error(22);
}
else if (marker == app1_ && memcmp(buf.pData_ + 2, xmpId_, 29) == 0) {
if (size < 31) throw Error(22);
@ -589,20 +596,36 @@ namespace Exiv2 {
--search;
}
if (exifData_.count() > 0) {
DataBuf rawExif = exifData_.copy();
if (rawExif.size_ > 0) {
Blob blob;
ByteOrder bo = byteOrder();
if (bo == invalidByteOrder) {
bo = littleEndian;
setByteOrder(bo);
}
WriteMethod wm = ExifParser::encode(blob,
rawExif.pData_,
rawExif.size_,
bo,
exifData_);
const byte* pExifData = rawExif.pData_;
uint32_t exifSize = rawExif.size_;
if (wm == wmIntrusive) {
pExifData = &blob[0];
exifSize = blob.size();
}
if (exifSize > 0) {
// Write APP1 marker, size of APP1 field, Exif id and Exif data
tmpBuf[0] = 0xff;
tmpBuf[1] = app1_;
if (rawExif.size_ + 8 > 0xffff) throw Error(37, "Exif");
us2Data(tmpBuf + 2, static_cast<uint16_t>(rawExif.size_ + 8), bigEndian);
if (exifSize + 8 > 0xffff) throw Error(37, "Exif");
us2Data(tmpBuf + 2, static_cast<uint16_t>(exifSize + 8), bigEndian);
std::memcpy(tmpBuf + 4, exifId_, 6);
if (outIo.write(tmpBuf, 10) != 10) throw Error(21);
// Write new Exif data buffer
if ( outIo.write(rawExif.pData_, rawExif.size_)
!= rawExif.size_) throw Error(21);
if ( outIo.write(pExifData, exifSize)
!= static_cast<long>(exifSize)) throw Error(21);
if (outIo.error()) throw Error(21);
--search;
}

@ -1,459 +0,0 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*
File: makernote.cpp
Version: $Rev$
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 18-Feb-04, ahu: created
*/
// *****************************************************************************
#include "rcsid.hpp"
EXIV2_RCSID("@(#) $Id$")
// Define DEBUG_* to output debug information to std::cerr, e.g, by calling
// make like this: make DEFS=-DDEBUG_MAKERNOTE makernote.o
//#define DEBUG_MAKERNOTE
//#define DEBUG_REGISTRY
// *****************************************************************************
// included header files
#include "makernote.hpp"
#include "error.hpp"
// + standard includes
#include <string>
#include <sstream>
#include <iomanip>
#include <iostream>
#include <cassert>
#include <cstring>
// *****************************************************************************
// class member definitions
namespace Exiv2 {
MakerNote::MakerNote(bool alloc)
: alloc_(alloc), offset_(0), byteOrder_(invalidByteOrder)
{
}
MakerNote::AutoPtr MakerNote::create(bool alloc) const
{
return AutoPtr(create_(alloc));
}
MakerNote::AutoPtr MakerNote::clone() const
{
return AutoPtr(clone_());
}
IfdMakerNote::IfdMakerNote(IfdId ifdId, bool alloc, bool hasNext)
: MakerNote(alloc),
absShift_(true), shift_(0), start_(0), ifd_(ifdId, 0, alloc, hasNext)
{
}
IfdMakerNote::IfdMakerNote(const IfdMakerNote& rhs)
: MakerNote(rhs), absShift_(rhs.absShift_), shift_(rhs.shift_),
start_(rhs.start_), header_(rhs.header_.size_), ifd_(rhs.ifd_)
{
std::memcpy(header_.pData_, rhs.header_.pData_, header_.size_);
}
int IfdMakerNote::read(const byte* buf,
long len,
long start,
ByteOrder byteOrder,
long shift)
{
// Remember the offset
offset_ = start - shift;
// Set byte order if none is set yet
if (byteOrder_ == invalidByteOrder) byteOrder_ = byteOrder;
// Read and check the header (and set offset adjustment)
int rc = readHeader(buf + start, len - start, byteOrder);
if (rc == 0) {
rc = checkHeader();
}
// Adjust shift
long newShift = absShift_ ? shift + shift_ : start + shift_;
// Read the makernote IFD
if (rc == 0) {
rc = ifd_.read(buf, len, start + start_, byteOrder_, newShift);
}
if (rc == 0) {
// IfdMakerNote currently does not support multiple IFDs
if (ifd_.next() != 0) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Makernote IFD has a next pointer != 0 ("
<< ifd_.next()
<< "). Ignored.\n";
#endif
}
}
#ifdef DEBUG_MAKERNOTE
hexdump(std::cerr, buf + start, len - start);
if (rc == 0) ifd_.print(std::cerr);
#endif
return rc;
} // IfdMakerNote::read
long IfdMakerNote::copy(byte* buf, ByteOrder byteOrder, long offset)
{
// Remember the new offset
offset_ = offset;
// Set byte order if none is set yet
if (byteOrder_ == invalidByteOrder) byteOrder_ = byteOrder;
// Adjust the offset
offset = absShift_ ? offset + start_ - shift_ : start_ - shift_;
long len = 0;
len += copyHeader(buf);
len += ifd_.copy(buf + len, byteOrder_, offset);
return len;
} // IfdMakerNote::copy
int IfdMakerNote::readHeader(const byte* /*buf*/,
long /*len*/,
ByteOrder /*byteOrder*/)
{
// Default implementation does nothing, assuming there is no header
return 0;
}
void IfdMakerNote::updateBase(byte* pNewBase)
{
ifd_.updateBase(pNewBase);
}
int IfdMakerNote::checkHeader() const
{
// Default implementation does nothing, assuming there is no header
return 0;
}
long IfdMakerNote::copyHeader(byte* buf) const
{
if (header_.size_ != 0) std::memcpy(buf, header_.pData_, header_.size_);
return header_.size_;
}
long IfdMakerNote::headerSize() const
{
return header_.size_;
}
Entries::const_iterator IfdMakerNote::findIdx(int idx) const
{
return ifd_.findIdx(idx);
}
long IfdMakerNote::size() const
{
return headerSize() + ifd_.size() + ifd_.dataSize();
}
IfdMakerNote::AutoPtr IfdMakerNote::create(bool alloc) const
{
return AutoPtr(create_(alloc));
}
IfdMakerNote::AutoPtr IfdMakerNote::clone() const
{
return AutoPtr(clone_());
}
int MakerNoteFactory::Init::count = 0;
MakerNoteFactory::Init::Init()
{
++count;
}
MakerNoteFactory::Init::~Init()
{
if (--count == 0) {
Exiv2::MakerNoteFactory::cleanup();
}
}
MakerNoteFactory::Registry* MakerNoteFactory::pRegistry_ = 0;
MakerNoteFactory::IfdIdRegistry* MakerNoteFactory::pIfdIdRegistry_ = 0;
void MakerNoteFactory::cleanup()
{
if (pRegistry_ != 0) {
Registry::iterator e = pRegistry_->end();
for (Registry::iterator i = pRegistry_->begin(); i != e; ++i) {
delete i->second;
}
delete pRegistry_;
}
if (pIfdIdRegistry_ != 0) {
IfdIdRegistry::iterator e = pIfdIdRegistry_->end();
for (IfdIdRegistry::iterator i = pIfdIdRegistry_->begin(); i != e; ++i) {
delete i->second;
}
delete pIfdIdRegistry_;
}
}
void MakerNoteFactory::init()
{
if (0 == pRegistry_) {
pRegistry_ = new Registry;
}
if (0 == pIfdIdRegistry_) {
pIfdIdRegistry_ = new IfdIdRegistry;
}
} // MakerNoteFactory::init
void MakerNoteFactory::registerMakerNote(IfdId ifdId,
MakerNote::AutoPtr makerNote)
{
init();
MakerNote* pMakerNote = makerNote.release();
assert(pMakerNote);
IfdIdRegistry::iterator pos = pIfdIdRegistry_->find(ifdId);
if (pos != pIfdIdRegistry_->end()) {
delete pos->second;
pos->second = 0;
}
(*pIfdIdRegistry_)[ifdId] = pMakerNote;
} // MakerNoteFactory::registerMakerNote
MakerNote::AutoPtr MakerNoteFactory::create(IfdId ifdId, bool alloc)
{
assert(pIfdIdRegistry_ != 0);
IfdIdRegistry::const_iterator i = pIfdIdRegistry_->find(ifdId);
if (i == pIfdIdRegistry_->end()) return MakerNote::AutoPtr(0);
assert(i->second);
return i->second->create(alloc);
} // MakerNoteFactory::create
void MakerNoteFactory::registerMakerNote(const std::string& make,
const std::string& model,
CreateFct createMakerNote)
{
#ifdef DEBUG_REGISTRY
std::cerr << "Registering MakerNote create function for \""
<< make << "\" and \"" << model << "\".\n";
#endif
init();
// Todo: use case insensitive make and model comparisons
// Find or create a registry entry for make
ModelRegistry* pModelRegistry = 0;
assert(pRegistry_ != 0);
Registry::const_iterator end1 = pRegistry_->end();
Registry::const_iterator pos1;
for (pos1 = pRegistry_->begin(); pos1 != end1; ++pos1) {
if (pos1->first == make) break;
}
if (pos1 != end1) {
pModelRegistry = pos1->second;
}
else {
pModelRegistry = new ModelRegistry;
pRegistry_->push_back(std::make_pair(make, pModelRegistry));
}
// Find or create a registry entry for model
ModelRegistry::iterator end2 = pModelRegistry->end();
ModelRegistry::iterator pos2;
for (pos2 = pModelRegistry->begin(); pos2 != end2; ++pos2) {
if (pos2->first == model) break;
}
if (pos2 != end2) {
pos2->second = createMakerNote;
}
else {
pModelRegistry->push_back(std::make_pair(model, createMakerNote));
}
} // MakerNoteFactory::registerMakerNote
MakerNote::AutoPtr MakerNoteFactory::create(const std::string& make,
const std::string& model,
bool alloc,
const byte* buf,
long len,
ByteOrder byteOrder,
long offset)
{
#ifdef DEBUG_REGISTRY
std::cerr << "Entering MakerNoteFactory::create(\""
<< make << "\", \"" << model << "\", "
<< (alloc == true ? "true" : "false") << ")\n";
#endif
// loop through each make of the registry to find the best matching make
int score = 0;
ModelRegistry* pModelRegistry = 0;
#ifdef DEBUG_REGISTRY
std::string makeMatch;
std::cerr << "Searching make registry...\n";
#endif
assert(pRegistry_ != 0);
Registry::const_iterator end1 = pRegistry_->end();
Registry::const_iterator pos1;
for (pos1 = pRegistry_->begin(); pos1 != end1; ++pos1) {
int rc = match(pos1->first, make);
if (rc > score) {
score = rc;
#ifdef DEBUG_REGISTRY
makeMatch = pos1->first;
#endif
pModelRegistry = pos1->second;
}
}
if (pModelRegistry == 0) return MakerNote::AutoPtr(0);
#ifdef DEBUG_REGISTRY
std::cerr << "Best match is \"" << makeMatch << "\".\n";
#endif
// loop through each model of the model registry to find the best match
score = 0;
CreateFct createMakerNote = 0;
#ifdef DEBUG_REGISTRY
std::string modelMatch;
std::cerr << "Searching model registry...\n";
#endif
ModelRegistry::const_iterator end2 = pModelRegistry->end();
ModelRegistry::const_iterator pos2;
for (pos2 = pModelRegistry->begin(); pos2 != end2; ++pos2) {
int rc = match(pos2->first, model);
if (rc > score) {
score = rc;
#ifdef DEBUG_REGISTRY
modelMatch = pos2->first;
#endif
createMakerNote = pos2->second;
}
}
if (createMakerNote == 0) return MakerNote::AutoPtr(0);
#ifdef DEBUG_REGISTRY
std::cerr << "Best match is \"" << modelMatch << "\".\n";
#endif
return createMakerNote(alloc, buf, len, byteOrder, offset);
} // MakerNoteFactory::create
int MakerNoteFactory::match(const std::string& regEntry,
const std::string& key)
{
#ifdef DEBUG_REGISTRY
std::cerr << " Matching registry entry \"" << regEntry << "\" ("
<< (int)regEntry.size() << ") with key \"" << key << "\" ("
<< (int)key.size() << "): ";
#endif
// Todo: make the comparisons case insensitive
// Handle exact match (this is only necessary because of the different
// return value - the following algorithm also finds exact matches)
if (regEntry == key) {
#ifdef DEBUG_REGISTRY
std::cerr << "Exact match (score: " << (int)key.size() + 2 << ")\n";
#endif
return static_cast<int>(key.size()) + 2;
}
std::string uKey = key;
std::string uReg = regEntry;
int count = 0; // number of matching characters
std::string::size_type ei = 0; // index in the registry entry
std::string::size_type ki = 0; // index in the key
while (ei != std::string::npos) {
std::string::size_type pos = uReg.find('*', ei);
if (pos != ei) {
std::string ss = pos == std::string::npos ?
uReg.substr(ei) : uReg.substr(ei, pos - ei);
if (ki == std::string::npos) {
#ifdef DEBUG_REGISTRY
std::cerr << "Not a match.\n";
#endif
return 0;
}
bool found = false;
// Find the substr ss in the key starting from index ki.
// Take care of the special cases
// + where the substr must match the key from beg to end,
// + from beg,
// + to end
// + and where it can be anywhere in the key.
// If found, ki is adjusted to the position in the key after ss.
if (ei == 0 && pos == std::string::npos) { // ei == 0 => ki == 0
if (0 == uKey.compare(ss)) {
found = true;
ki = std::string::npos;
}
}
else if (ei == 0) { // ei == 0 => ki == 0
if (0 == uKey.compare(0, ss.size(), ss)) {
found = true;
ki = ss.size();
}
}
else if (pos == std::string::npos) {
if ( ss.size() <= uKey.size()
&& ki <= uKey.size() - ss.size()) {
if (0 == uKey.compare(
uKey.size() - ss.size(), ss.size(), ss)) {
found = true;
ki = std::string::npos;
}
}
}
else {
std::string::size_type idx = uKey.find(ss, ki);
if (idx != std::string::npos) {
found = true;
ki = idx + ss.size();
}
}
if (found) {
count += static_cast<int>(ss.size());
}
else {
#ifdef DEBUG_REGISTRY
std::cerr << "Not a match.\n";
#endif
return 0;
}
} // if the substr is not empty
ei = pos == std::string::npos ? std::string::npos : pos + 1;
} // while ei doesn't point to the end of the registry entry
#ifdef DEBUG_REGISTRY
std::cerr << "Match (score: " << count + 1 << ")\n";
#endif
return count + 1;
} // MakerNoteFactory::match
} // namespace Exiv2

@ -1,519 +0,0 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*!
@file makernote.hpp
@brief Contains the Exif %MakerNote interface, IFD %MakerNote and a
MakerNote factory
@version $Rev$
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 18-Feb-04, ahu: created
*/
#ifndef MAKERNOTE_HPP_
#define MAKERNOTE_HPP_
// *****************************************************************************
// included header files
#include "types.hpp"
#include "ifd.hpp"
// + standard includes
#include <string>
#include <iosfwd>
#include <utility>
#include <vector>
#include <map>
#include <memory>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class Value;
// *****************************************************************************
// class definitions
/*!
@brief Exif makernote interface
%MakerNote is a low-level container for makernote entries. The ExifData
container uses makernote entries just like the other Exif metadata. Thus,
clients can access Exif and makernote tags and their values uniformly
through the ExifData interface. The role of %MakerNote is very similar to
that of class Ifd (but makernotes do not need to be in IFD format, see
below). In addition, it provides %MakerNote specific tag descriptions and
print functions to interpret the makernote values.
MakerNote holds methods and functionality to
- read the makernote from a character buffer
- copy the makernote to a character buffer
- maintain a list of makernote entries (similar to IFD entries)
- interpret (print) the values of makernote tags
Makernotes can be added to the system by subclassing %MakerNote and
registering a create function for the new subclass together with the
camera make and model (which may contain wildcards) in the
MakerNoteFactory. Since the majority of makernotes are in IFD format,
subclass IfdMakerNote is provided. It contains an IFD container and
implements all interface methods related to the makernote entries. <BR>
To implement a new IFD makernote, all that you need to do is
- subclass %IfdMakerNote,
- implement methods to read and check the header (if any) as well as
clone and create functions,
- add a list of tag descriptions and appropriate print functions and
- register the camera make/model and create function in the makernote factory.
.
See existing makernote implementations for examples, e.g., CanonMakerNote
or FujiMakerNote.
Finally, the header file which defines the static variable
\em register*MakerNote needs to be included from mn.hpp, to ensure that
the makernote is automatically registered in the factory.
*/
class MakerNote {
//! @name Not implemented
//@{
//! Assignment not allowed (memory management mode alloc_ is const)
MakerNote& operator=(const MakerNote& rhs);
//@}
public:
//! Shortcut for a %MakerNote auto pointer.
typedef std::auto_ptr<MakerNote> AutoPtr;
//! @name Creators
//@{
/*!
@brief Constructor. Allows to choose whether or not memory management
is required for the Entries.
*/
explicit MakerNote(bool alloc =true);
//! Virtual destructor.
virtual ~MakerNote() {}
//@}
//! @name Manipulators
//@{
/*!
@brief Read the makernote, including the makernote header, from the
Exif data buffer.
@param buf Pointer to the Exif data buffer that contains the
MakerNote to decode. The buffer should contain all Exif
data starting from the TIFF header.
@param len Number of bytes in the Exif data buffer
@param start MakerNote starts at buf + start.
@param byteOrder Applicable byte order (little or big endian).
@param shift IFD offsets are relative to buf + shift.
@return 0 if successful.
*/
virtual int read(const byte* buf,
long len,
long start,
ByteOrder byteOrder,
long shift =0) =0;
/*!
@brief Copy (write) the makerNote to the character buffer buf at
position offset (from the start of the TIFF header), encoded
in byte order byteOrder. Update internal offsets if necessary.
Return the number of bytes written.
*/
virtual long copy(byte* buf, ByteOrder byteOrder, long offset) =0;
/*!
@brief Add the entry to the makernote. No duplicate-check is performed,
i.e., it is possible to add multiple entries with the same tag.
The memory allocation mode of the entry to be added must be the
same as that of the makernote and the IFD id of the entry must
be set to 'makerIfd'.
*/
virtual void add(const Entry& entry) =0;
//! The first makernote entry
virtual Entries::iterator begin() =0;
//! End of the makernote entries
virtual Entries::iterator end() =0;
/*!
@brief Update the base pointer of the %MakerNote and all its entries
to \em pNewBase.
Allows to re-locate the underlying data buffer to a new location
\em pNewBase. This method only has an effect in non-alloc mode.
*/
virtual void updateBase(byte* pNewBase) =0;
//@}
//! @name Accessors
//@{
//! Return the byte order (little or big endian).
ByteOrder byteOrder() const { return byteOrder_; }
//! Return the offset of the makernote from the start of the TIFF header
long offset() const { return offset_; }
/*!
@brief Return an auto-pointer to an newly created, empty instance of
the same type as this. The makernote entries are <B>not</B>
copied. The caller owns the new object and the auto-pointer
ensures that it will be deleted.
@param alloc Memory management model for the newly created object.
Indicates if memory required to store data should be allocated
and deallocated (true) or not (false). If false, only pointers
to the buffer provided to read() will be kept. See Ifd for more
background on this concept.
*/
AutoPtr create(bool alloc =true) const;
/*!
@brief Return an auto-pointer to a clone of this object. The caller
owns the new object and the auto-pointer ensures that it will
be deleted.
@note In non-alloc mode the clone potentially contains pointers to
the same data buffer as the original.
Use updateBase(byte* pNewBase) to adjust them.
*/
AutoPtr clone() const;
//! The first makernote entry
virtual Entries::const_iterator begin() const =0;
//! End of the makernote entries
virtual Entries::const_iterator end() const =0;
//! Find an entry by idx, return a const iterator to the record
virtual Entries::const_iterator findIdx(int idx) const =0;
//! Return the size of the makernote in bytes
virtual long size() const =0;
//@}
protected:
// DATA
/*!
@brief Flag to control the memory management: <BR>
True: requires memory allocation and deallocation, <BR>
False: no memory management needed.
*/
const bool alloc_;
/*!
@brief Offset of the makernote from the start of the TIFF header
(for offset()).
*/
long offset_;
/*!
@brief Alternative byte order to use, invalid if the byte order of the
Exif block can be used
*/
ByteOrder byteOrder_;
private:
//! Internal virtual create function.
virtual MakerNote* create_(bool alloc =true) const =0;
//! Internal virtual copy constructor.
virtual MakerNote* clone_() const =0;
}; // class MakerNote
//! Type for a pointer to a function creating a makernote
typedef MakerNote::AutoPtr (*CreateFct)(bool, const byte*, long, ByteOrder, long);
/*!
@brief Interface for MakerNotes in IFD format. See MakerNote.
*/
class IfdMakerNote : public MakerNote {
//! @name Not implemented
//@{
//! Assignment not allowed (Ifd does not have an assignment operator)
IfdMakerNote& operator=(const IfdMakerNote& rhs);
//@}
public:
//! Shortcut for an %IfdMakerNote auto pointer.
typedef std::auto_ptr<IfdMakerNote> AutoPtr;
//! @name Creators
//@{
/*!
@brief Constructor. Requires an %Ifd id and allows to choose whether
or not memory management is needed for the Entries and whether
the IFD has a next pointer.
*/
explicit IfdMakerNote(IfdId ifdId, bool alloc =true, bool hasNext =true);
//! Copy constructor
IfdMakerNote(const IfdMakerNote& rhs);
//! Virtual destructor
virtual ~IfdMakerNote() {}
//@}
//! @name Manipulators
//@{
virtual int read(const byte* buf,
long len,
long start,
ByteOrder byteOrder,
long shift);
/*!
@brief Read the makernote header from the makernote databuffer. This
method must set the offset to the start of the IFD (start_), if
needed (assuming that the required information is in the header).
Return 0 if successful.
@note The default implementation does nothing, assuming there is no
header
*/
virtual int readHeader(const byte* buf,
long len,
ByteOrder byteOrder);
virtual long copy(byte* buf, ByteOrder byteOrder, long offset);
virtual void add(const Entry& entry) { ifd_.add(entry); }
virtual Entries::iterator begin() { return ifd_.begin(); }
virtual Entries::iterator end() { return ifd_.end(); }
virtual void updateBase(byte* pNewBase);
//@}
//! @name Accessors
//@{
virtual Entries::const_iterator begin() const { return ifd_.begin(); }
virtual Entries::const_iterator end() const { return ifd_.end(); }
virtual Entries::const_iterator findIdx(int idx) const;
virtual long size() const;
AutoPtr create(bool alloc =true) const;
AutoPtr clone() const;
/*!
@brief Check the makernote header. This will typically check if a
required prefix string is present in the header. Return 0 if
successful.
@note The default implementation does nothing, assuming there is no
header
*/
virtual int checkHeader() const;
/*!
@brief Write the makernote header to a character buffer, return the
number of characters written.
@note The default implementation copies the header_ buffer.
*/
virtual long copyHeader(byte* buf) const;
/*!
@brief Return the size of the makernote header in bytes.
@note The default implementation returns the size of the header_
buffer.
*/
virtual long headerSize() const;
//@}
protected:
// DATA
/*!
@brief True: IFD offsets are relative to the start of the TIFF
header (i.e., the start of the Exif data section)
+ shift_
False: IFD offsets are relative to the start of the
makernote + shift_
*/
bool absShift_;
/*!
@brief Adjustment for IFD offsets, see absShift_.
*/
long shift_;
/*!
@brief Start of the makernote IFD relative to the start of the
makernote.
*/
long start_;
//! Data buffer for the makernote header
DataBuf header_;
//! The makernote IFD
Ifd ifd_;
private:
virtual IfdMakerNote* create_(bool alloc =true) const =0;
virtual IfdMakerNote* clone_() const =0;
}; // class IfdMakerNote
/*!
@brief Factory for MakerNote objects.
Maintains an associative list (tree) of camera makes/models and
corresponding %MakerNote create functions. Creates an instance of the
%MakerNote for one camera make/model. The factory is implemented as a
static class.
*/
class MakerNoteFactory {
public:
//! Destructor.
static void cleanup();
/*!
@brief Register a %MakerNote create function for a camera make and
model.
Registers a create function for a %MakerNote for a given make and
model combination with the factory. Both the make and model strings
may contain wildcards ('*', e.g., "Canon*"). If the make already
exists in the registry, then a new branch for the model is added. If
the model also already exists, then the new create function replaces
the old one.
@param make Camera manufacturer. (Typically the string from the Exif
make tag.)
@param model Camera model. (Typically the string from the Exif
model tag.)
@param createMakerNote Pointer to a function to create a new
%MakerNote of a particular type.
*/
static void registerMakerNote(const std::string& make,
const std::string& model,
CreateFct createMakerNote);
//! Register a %MakerNote prototype in the IFD id registry.
static void registerMakerNote(IfdId ifdId, MakerNote::AutoPtr makerNote);
/*!
@brief Create the appropriate %MakerNote based on camera make and
model and possibly the contents of the makernote itself, return
an auto-pointer to the newly created MakerNote instance. Return
0 if no %MakerNote is defined for the camera model.
The method searches the make-model tree for a make and model
combination in the registry that matches the search key. The search is
case insensitive (Todo: implement case-insensitive comparisons) and
wildcards in the registry entries are supported. First the best
matching make is searched, then the best matching model for this make
is searched. If there is no matching make or no matching model within
the models registered for the best matching make, then no makernote
is created and the function returns 0. If a match is found, the
function invokes the registered create function and returns an
auto-pointer to the newly created MakerNote. The makernote pointed to
is owned by the caller of the function and the auto-pointer ensures
that it is deleted. The best match is an exact match, then a match is
rated according to the number of matching characters. The makernote
buffer is passed on to the create function, which can based on its
content, automatically determine the correct version or flavour of the
makernote required. This is used, e.g., to determine which of the
three Nikon makernotes to create.
@param make Camera manufacturer. (Typically the string from the Exif
make tag.)
@param model Camera model. (Typically the string from the Exif
model tag.)
@param alloc Memory management model for the new MakerNote. Determines
if memory required to store data should be allocated and
deallocated (true) or not (false). If false, only pointers to
the buffer provided to read() will be kept. See Ifd for more
background on this concept.
@param buf Pointer to the makernote character buffer.
@param len Length of the makernote character buffer.
@param byteOrder Byte order in which the Exif data (and possibly the
makernote) is encoded.
@param offset Offset from the start of the TIFF header of the makernote
buffer.
@return An auto-pointer that owns a %MakerNote for the camera model.
If the camera is not supported, the pointer is 0.
*/
static MakerNote::AutoPtr create(const std::string& make,
const std::string& model,
bool alloc,
const byte* buf,
long len,
ByteOrder byteOrder,
long offset);
//! Create a %MakerNote for an IFD id.
static MakerNote::AutoPtr create(IfdId ifdId, bool alloc =true);
/*!
@brief Match a registry entry with a key (used for make and model).
The matching algorithm is case insensitive and wildcards ('*') in the
registry entry are supported. The best match is an exact match, then
a match is rated according to the number of matching characters.
@return A score value indicating how good the key and registry entry
match. 0 means no match, values greater than 0 indicate a
match, larger values are better matches:<BR>
0: key and registry entry do not match<BR>
1: a pure wildcard match, i.e., the registry entry is just
a wildcard.<BR>
Score values greater than 1 are computed by adding 1 to the
number of matching characters, except for an exact match,
which scores 2 plus the number of matching characters.
*/
static int match(const std::string& regEntry, const std::string& key);
/*!
@brief Class Init is used to execute initialisation and termination
code exactly once, at the begin and end of the program.
See Bjarne Stroustrup, 'The C++ Programming Language 3rd
Edition', section 21.5.2 for details about this pattern.
*/
class Init {
static int count; //!< Counts calls to constructor
public:
//! @name Creators
//@{
//! Perform one-time initialisations.
Init();
//! Perform one-time cleanup operations.
~Init();
//@}
};
private:
//! @name Creators
//@{
//! Prevent construction: not implemented.
MakerNoteFactory() {}
//! Prevent copy construction: not implemented.
MakerNoteFactory(const MakerNoteFactory& rhs);
//@}
//! Creates the private static instance
static void init();
//! Type used to store model labels and %MakerNote create functions
typedef std::vector<std::pair<std::string, CreateFct> > ModelRegistry;
//! Type used to store a list of make labels and model registries
typedef std::vector<std::pair<std::string, ModelRegistry*> > Registry;
//! Type used to store a list of IFD ids and %MakerNote prototypes
typedef std::map<IfdId, MakerNote*> IfdIdRegistry;
// DATA
//! List of makernote types and corresponding makernote create functions.
static Registry* pRegistry_;
//! List of makernote IFD ids and corresponding create functions.
static IfdIdRegistry* pIfdIdRegistry_;
}; // class MakerNoteFactory
} // namespace Exiv2
namespace {
/*!
Each translation unit that includes makernote.hpp declares its own
Init object. The destructor ensures that the factory is properly
freed exactly once.
See Bjarne Stroustrup, 'The C++ Programming Language 3rd
Edition', section 21.5.2 for details about this pattern.
*/
Exiv2::MakerNoteFactory::Init makerNoteFactoryInit;
}
#endif // #ifndef MAKERNOTE_HPP_

@ -36,10 +36,11 @@ EXIV2_RCSID("@(#) $Id$")
# include "exv_conf.h"
#endif
#include "makernote2.hpp"
#include "tiffcomposite.hpp"
#include "tiffvisitor.hpp"
#include "makernote2_int.hpp"
#include "tiffcomposite_int.hpp"
#include "tiffvisitor_int.hpp"
#include "tiffimage.hpp"
#include "tiffimage_int.hpp"
// + standard includes
#include <string>
@ -48,25 +49,37 @@ EXIV2_RCSID("@(#) $Id$")
// *****************************************************************************
// class member definitions
namespace Exiv2 {
namespace Internal {
const TiffMnRegistry TiffMnCreator::registry_[] = {
{ "Canon", newCanonMn, Group::canonmn },
{ "FOVEON", newSigmaMn, Group::sigmamn },
{ "FUJIFILM", newFujiMn, Group::fujimn },
{ "KONICA MINOLTA", newMinoltaMn, Group::minoltamn },
{ "Minolta", newMinoltaMn, Group::minoltamn },
{ "NIKON", newNikonMn, Group::nikonmn },
{ "OLYMPUS", newOlympusMn, Group::olympmn },
{ "Panasonic", newPanasonicMn, Group::panamn },
{ "PENTAX", newPentaxMn, Group::pentaxmn },
{ "SIGMA", newSigmaMn, Group::sigmamn },
{ "SONY", newSonyMn, Group::sonymn }
{ "Canon", Group::canonmn, newIfdMn, newIfdMn2 },
{ "FOVEON", Group::sigmamn, newSigmaMn, newSigmaMn2 },
{ "FUJIFILM", Group::fujimn, newFujiMn, newFujiMn2 },
{ "KONICA MINOLTA", Group::minoltamn, newIfdMn, newIfdMn2 },
{ "Minolta", Group::minoltamn, newIfdMn, newIfdMn2 },
{ "NIKON", Group::nikonmn, newNikonMn, 0 },
{ "OLYMPUS", Group::olympmn, newOlympusMn, newOlympusMn2 },
{ "Panasonic", Group::panamn, newPanasonicMn, newPanasonicMn2 },
{ "PENTAX", Group::pentaxmn, newPentaxMn, newPentaxMn2 },
{ "SIGMA", Group::sigmamn, newSigmaMn, newSigmaMn2 },
{ "SONY", Group::sonymn, newSonyMn, 0 },
// Entries below are only used for lookup by group
{ "-", Group::nikon1mn, 0, newIfdMn2 },
{ "-", Group::nikon2mn, 0, newNikon2Mn2 },
{ "-", Group::nikon3mn, 0, newNikon3Mn2 },
{ "-", Group::sony1mn, 0, newSony1Mn2 },
{ "-", Group::sony2mn, 0, newSony2Mn2 }
};
bool TiffMnRegistry::operator==(const TiffMnRegistry::Key& key) const
bool TiffMnRegistry::operator==(const std::string& key) const
{
std::string make(make_);
return make == key.make_.substr(0, make.length());
return make == key.substr(0, make.length());
}
bool TiffMnRegistry::operator==(const uint16_t& key) const
{
return mnGroup_ == key;
}
TiffComponent* TiffMnCreator::create(uint16_t tag,
@ -77,13 +90,29 @@ namespace Exiv2 {
ByteOrder byteOrder)
{
TiffComponent* tc = 0;
const TiffMnRegistry* tmr = find(registry_, TiffMnRegistry::Key(make));
if (tmr) tc = tmr->newMnFct_(tag,
group,
tmr->mnGroup_,
pData,
size,
byteOrder);
const TiffMnRegistry* tmr = find(registry_, make);
if (tmr) {
assert(tmr->newMnFct_);
tc = tmr->newMnFct_(tag,
group,
tmr->mnGroup_,
pData,
size,
byteOrder);
}
return tc;
} // TiffMnCreator::create
TiffComponent* TiffMnCreator::create(uint16_t tag,
uint16_t group,
uint16_t mnGroup)
{
TiffComponent* tc = 0;
const TiffMnRegistry* tmr = find(registry_, mnGroup);
if (tmr) {
assert(tmr->newMnFct2_);
tc = tmr->newMnFct2_(tag, group, mnGroup);
}
return tc;
} // TiffMnCreator::create
@ -118,23 +147,99 @@ namespace Exiv2 {
return pHeader_->read(pData, size, byteOrder);
}
void TiffIfdMakernote::doAddChild(TiffComponent::AutoPtr tiffComponent)
uint32_t TiffIfdMakernote::sizeHeader() const
{
ifd_.addChild(tiffComponent);
if (!pHeader_) return 0;
return pHeader_->size();
}
uint32_t TiffIfdMakernote::writeHeader(Blob& blob, ByteOrder byteOrder) const
{
if (!pHeader_) return 0;
return pHeader_->write(blob, byteOrder);
}
TiffComponent* TiffIfdMakernote::doAddPath(uint16_t tag, TiffPath& tiffPath)
{
return ifd_.addPath(tag, tiffPath);
}
TiffComponent* TiffIfdMakernote::doAddChild(TiffComponent::AutoPtr tiffComponent)
{
return ifd_.addChild(tiffComponent);
}
void TiffIfdMakernote::doAddNext(TiffComponent::AutoPtr tiffComponent)
TiffComponent* TiffIfdMakernote::doAddNext(TiffComponent::AutoPtr tiffComponent)
{
ifd_.addNext(tiffComponent);
return ifd_.addNext(tiffComponent);
}
void TiffIfdMakernote::doAccept(TiffVisitor& visitor)
{
if (visitor.go()) visitor.visitIfdMakernote(this);
if (visitor.go(TiffVisitor::geTraverse)) visitor.visitIfdMakernote(this);
ifd_.accept(visitor);
if (visitor.go()) visitor.visitIfdMakernoteEnd(this);
if (visitor.go(TiffVisitor::geTraverse)) visitor.visitIfdMakernoteEnd(this);
}
uint32_t TiffIfdMakernote::doWrite(Blob& blob,
ByteOrder byteOrder,
int32_t offset,
uint32_t /*valueIdx*/,
uint32_t /*dataIdx*/,
uint32_t imageIdx)
{
if (this->byteOrder() != invalidByteOrder) {
byteOrder = this->byteOrder();
}
uint32_t len = writeHeader(blob, byteOrder);
len += ifd_.write(blob, byteOrder,
offset - baseOffset(offset) + len,
uint32_t(-1), uint32_t(-1),
imageIdx);
return len;
} // TiffIfdMakernote::doWrite
uint32_t TiffIfdMakernote::doWriteData(Blob& /*blob*/,
ByteOrder /*byteOrder*/,
int32_t /*offset*/,
uint32_t /*dataIdx*/,
uint32_t /*imageIdx*/) const
{
assert(false);
return 0;
} // TiffIfdMakernote::doWriteData
uint32_t TiffIfdMakernote::doWriteImage(Blob& /*blob*/,
ByteOrder /*byteOrder*/,
int32_t /*offset*/,
uint32_t /*imageIdx*/) const
{
assert(false);
return 0;
} // TiffIfdMakernote::doWriteImage
uint32_t TiffIfdMakernote::doSize() const
{
return sizeHeader() + ifd_.size();
} // TiffIfdMakernote::doSize
uint32_t TiffIfdMakernote::doCount() const
{
return ifd_.count();
} // TiffIfdMakernote::doCount
uint32_t TiffIfdMakernote::doSizeData() const
{
assert(false);
return 0;
} // TiffIfdMakernote::doSizeData
uint32_t TiffIfdMakernote::doSizeImage() const
{
assert(false);
return 0;
} // TiffIfdMakernote::doSizeImage
const byte OlympusMnHeader::signature_[] = {
'O', 'L', 'Y', 'M', 'P', 0x00, 0x01, 0x00
};
@ -162,6 +267,13 @@ namespace Exiv2 {
return true;
} // OlympusMnHeader::read
uint32_t OlympusMnHeader::write(Blob& blob,
ByteOrder /*byteOrder*/) const
{
append(blob, signature_, size_);
return size_;
} // OlympusMnHeader::write
const byte FujiMnHeader::signature_[] = {
'F', 'U', 'J', 'I', 'F', 'I', 'L', 'M', 0x0c, 0x00, 0x00, 0x00
};
@ -195,9 +307,15 @@ namespace Exiv2 {
return true;
} // FujiMnHeader::read
uint32_t FujiMnHeader::write(Blob& blob,
ByteOrder /*byteOrder*/) const
{
append(blob, signature_, size_);
return size_;
} // FujiMnHeader::write
const byte Nikon2MnHeader::signature_[] = {
'N', 'i', 'k', 'o', 'n', '\0', 0x00, 0x01
'N', 'i', 'k', 'o', 'n', '\0', 0x01, 0x00
};
const uint32_t Nikon2MnHeader::size_ = 8;
@ -221,6 +339,13 @@ namespace Exiv2 {
} // Nikon2MnHeader::read
uint32_t Nikon2MnHeader::write(Blob& blob,
ByteOrder /*byteOrder*/) const
{
append(blob, signature_, size_);
return size_;
} // Nikon2MnHeader::write
const byte Nikon3MnHeader::signature_[] = {
'N', 'i', 'k', 'o', 'n', '\0',
0x02, 0x10, 0x00, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08
@ -250,6 +375,13 @@ namespace Exiv2 {
} // Nikon3MnHeader::read
uint32_t Nikon3MnHeader::write(Blob& blob,
ByteOrder /*byteOrder*/) const
{
append(blob, signature_, size_);
return size_;
} // Nikon3MnHeader::write
const byte PanasonicMnHeader::signature_[] = {
'P', 'a', 'n', 'a', 's', 'o', 'n', 'i', 'c', 0x00, 0x00, 0x00
};
@ -261,8 +393,8 @@ namespace Exiv2 {
}
bool PanasonicMnHeader::read(const byte* pData,
uint32_t size,
ByteOrder /*byteOrder*/)
uint32_t size,
ByteOrder /*byteOrder*/)
{
assert (pData != 0);
@ -275,6 +407,13 @@ namespace Exiv2 {
} // PanasonicMnHeader::read
uint32_t PanasonicMnHeader::write(Blob& blob,
ByteOrder /*byteOrder*/) const
{
append(blob, signature_, size_);
return size_;
} // PanasonicMnHeader::write
const byte PentaxMnHeader::signature_[] = {
'A', 'O', 'C', 0x00, 'M', 'M'
};
@ -292,7 +431,6 @@ namespace Exiv2 {
assert (pData != 0);
if (size < size_) return false;
header_.alloc(size_);
std::memcpy(header_.pData_, pData, header_.size_);
if ( static_cast<uint32_t>(header_.size_) < size_
@ -302,6 +440,13 @@ namespace Exiv2 {
return true;
} // PentaxMnHeader::read
uint32_t PentaxMnHeader::write(Blob& blob,
ByteOrder /*byteOrder*/) const
{
append(blob, signature_, size_);
return size_;
} // PentaxMnHeader::write
const byte SigmaMnHeader::signature1_[] = {
'S', 'I', 'G', 'M', 'A', '\0', '\0', '\0', 0x01, 0x00
};
@ -331,6 +476,13 @@ namespace Exiv2 {
} // SigmaMnHeader::read
uint32_t SigmaMnHeader::write(Blob& blob,
ByteOrder /*byteOrder*/) const
{
append(blob, signature1_, size_);
return size_;
} // SigmaMnHeader::write
const byte SonyMnHeader::signature_[] = {
'S', 'O', 'N', 'Y', ' ', 'D', 'S', 'C', ' ', '\0', '\0', '\0'
};
@ -356,25 +508,29 @@ namespace Exiv2 {
} // SonyMnHeader::read
uint32_t SonyMnHeader::write(Blob& blob,
ByteOrder /*byteOrder*/) const
{
append(blob, signature_, size_);
return size_;
} // SonyMnHeader::write
// *************************************************************************
// free functions
TiffComponent* newCanonMn(uint16_t tag,
uint16_t group,
uint16_t mnGroup,
const byte* /*pData*/,
uint32_t /*size*/,
ByteOrder /*byteOrder*/)
TiffComponent* newIfdMn(uint16_t tag,
uint16_t group,
uint16_t mnGroup,
const byte* /*pData*/,
uint32_t /*size*/,
ByteOrder /*byteOrder*/)
{
return new TiffIfdMakernote(tag, group, mnGroup, 0);
return newIfdMn2(tag, group, mnGroup);
}
TiffComponent* newMinoltaMn(uint16_t tag,
uint16_t group,
uint16_t mnGroup,
const byte* /*pData*/,
uint32_t /*size*/,
ByteOrder /*byteOrder*/)
TiffComponent* newIfdMn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup)
{
return new TiffIfdMakernote(tag, group, mnGroup, 0);
}
@ -385,6 +541,13 @@ namespace Exiv2 {
const byte* /*pData*/,
uint32_t /*size*/,
ByteOrder /*byteOrder*/)
{
return newOlympusMn2(tag, group, mnGroup);
}
TiffComponent* newOlympusMn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup)
{
return new TiffIfdMakernote(tag, group, mnGroup, new OlympusMnHeader);
}
@ -395,6 +558,13 @@ namespace Exiv2 {
const byte* /*pData*/,
uint32_t /*size*/,
ByteOrder /*byteOrder*/)
{
return newFujiMn2(tag, group, mnGroup);
}
TiffComponent* newFujiMn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup)
{
return new TiffIfdMakernote(tag, group, mnGroup, new FujiMnHeader);
}
@ -409,7 +579,7 @@ namespace Exiv2 {
// If there is no "Nikon" string it must be Nikon1 format
if (size < 6 || std::string(reinterpret_cast<const char*>(pData), 6)
!= std::string("Nikon\0", 6)) {
return new TiffIfdMakernote(tag, group, Group::nikon1mn, 0);
return newIfdMn2(tag, group, Group::nikon1mn);
}
// If the "Nikon" string is not followed by a TIFF header, we assume
// Nikon2 format
@ -417,10 +587,24 @@ namespace Exiv2 {
if ( size < 18
|| !tiffHeader.read(pData + 10, size - 10)
|| tiffHeader.tag() != 0x002a) {
return new TiffIfdMakernote(tag, group, Group::nikon2mn, new Nikon2MnHeader);
return newNikon2Mn2(tag, group, Group::nikon2mn);
}
// Else we have a Nikon3 makernote
return new TiffIfdMakernote(tag, group, Group::nikon3mn, new Nikon3MnHeader);
return newNikon3Mn2(tag, group, Group::nikon3mn);
}
TiffComponent* newNikon2Mn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup)
{
return new TiffIfdMakernote(tag, group, mnGroup, new Nikon2MnHeader);
}
TiffComponent* newNikon3Mn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup)
{
return new TiffIfdMakernote(tag, group, mnGroup, new Nikon3MnHeader);
}
TiffComponent* newPanasonicMn(uint16_t tag,
@ -429,6 +613,13 @@ namespace Exiv2 {
const byte* /*pData*/,
uint32_t /*size*/,
ByteOrder /*byteOrder*/)
{
return newPanasonicMn2(tag, group, mnGroup);
}
TiffComponent* newPanasonicMn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup)
{
return new TiffIfdMakernote(tag, group, mnGroup, new PanasonicMnHeader, false);
}
@ -439,6 +630,13 @@ namespace Exiv2 {
const byte* /*pData*/,
uint32_t /*size*/,
ByteOrder /*byteOrder*/)
{
return newPentaxMn2(tag, group, mnGroup);
}
TiffComponent* newPentaxMn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup)
{
return new TiffIfdMakernote(tag, group, mnGroup, new PentaxMnHeader);
}
@ -449,6 +647,13 @@ namespace Exiv2 {
const byte* /*pData*/,
uint32_t /*size*/,
ByteOrder /*byteOrder*/)
{
return newSigmaMn2(tag, group, mnGroup);
}
TiffComponent* newSigmaMn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup)
{
return new TiffIfdMakernote(tag, group, mnGroup, new SigmaMnHeader);
}
@ -463,9 +668,23 @@ namespace Exiv2 {
// If there is no "SONY DSC " string we assume it's a simple IFD Makernote
if (size < 12 || std::string(reinterpret_cast<const char*>(pData), 12)
!= std::string("SONY DSC \0\0\0", 12)) {
return new TiffIfdMakernote(tag, group, Group::sony2mn, 0, true);
return newSony2Mn2(tag, group, Group::sony2mn);
}
return new TiffIfdMakernote(tag, group, Group::sony1mn, new SonyMnHeader, false);
return newSony1Mn2(tag, group, Group::sony1mn);
}
TiffComponent* newSony1Mn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup)
{
return new TiffIfdMakernote(tag, group, mnGroup, new SonyMnHeader, false);
}
TiffComponent* newSony2Mn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup)
{
return new TiffIfdMakernote(tag, group, mnGroup, 0, true);
}
} // namespace Exiv2
}} // namespace Internal, Exiv2

@ -19,21 +19,20 @@
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*!
@file makernote2.hpp
@brief Makernote TIFF composite class TiffIfdMakernote and classes for
various makernote headers.
@file makernote2_int.hpp
@brief Internal Makernote TIFF composite class TiffIfdMakernote and classes
for various makernote headers.
@version $Rev$
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 11-Apr-06, ahu: created
*/
#ifndef MAKERNOTE2_HPP_
#define MAKERNOTE2_HPP_
#ifndef MAKERNOTE2_INT_HPP_
#define MAKERNOTE2_INT_HPP_
// *****************************************************************************
// included header files
#include "tiffcomposite.hpp"
#include "tiffvisitor.hpp"
#include "tiffcomposite_int.hpp"
#include "types.hpp"
// + standard includes
@ -42,6 +41,7 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
namespace Internal {
namespace Group {
const uint16_t olympmn = 257; //!< Olympus makernote
@ -72,7 +72,7 @@ namespace Exiv2 {
// *****************************************************************************
// class definitions
//! Type for a pointer to a function creating a makernote
//! Type for a pointer to a function creating a makernote (image)
typedef TiffComponent* (*NewMnFct)(uint16_t tag,
uint16_t group,
uint16_t mnGroup,
@ -80,28 +80,31 @@ namespace Exiv2 {
uint32_t size,
ByteOrder byteOrder);
//! Type for a pointer to a function creating a makernote (group)
typedef TiffComponent* (*NewMnFct2)(uint16_t tag,
uint16_t group,
uint16_t mnGroup);
//! Makernote registry structure
struct TiffMnRegistry {
struct Key;
struct MakeKey;
/*!
@brief Compare a TiffMnRegistry structure with a TiffMnRegistry::Key
The two are equal if TiffMnRegistry::make_ equals a substring
of the key of the same size. E.g., registry = "OLYMPUS",
@brief Compare a TiffMnRegistry structure with a key being the make
string from the image. The two are equal if
TiffMnRegistry::make_ equals a substring of the key of the
same size. E.g., registry = "OLYMPUS",
key = "OLYMPUS OPTICAL CO.,LTD" (found in the image) match.
*/
bool operator==(const Key& key) const;
bool operator==(const std::string& key) const;
//! Compare a TiffMnRegistry structure with a makernote group
bool operator==(const uint16_t& key) const;
// DATA
const char* make_; //!< Camera make
NewMnFct newMnFct_; //!< Makernote create function
uint16_t mnGroup_; //!< Group identifier
};
//! Search key for Makernote registry structure.
struct TiffMnRegistry::Key {
//! Constructor
Key(const std::string& make) : make_(make) {}
std::string make_; //!< Camera make
NewMnFct newMnFct_; //!< Makernote create function (image)
NewMnFct2 newMnFct2_; //!< Makernote create function (group)
};
/*!
@ -113,7 +116,8 @@ namespace Exiv2 {
@brief Create the Makernote for camera \em make and details from
the makernote entry itself if needed. Return a pointer to
the newly created TIFF component. Set tag and group of the
new component to \em tag and \em group.
new component to \em tag and \em group. This method is used
when a makernote is parsed from the Exif block.
@note Ownership for the component is transferred to the caller,
who is responsible to delete the component. No smart pointer
is used to indicate this transfer here in order to reduce
@ -125,6 +129,14 @@ namespace Exiv2 {
const byte* pData,
uint32_t size,
ByteOrder byteOrder);
/*!
@brief Create the Makernote for a given group. This method is used
when a makernote is written back from Exif tags.
*/
static TiffComponent* create(uint16_t tag,
uint16_t group,
uint16_t mnGroup);
protected:
//! Prevent destruction (needed if used as a policy class)
~TiffMnCreator() {}
@ -151,12 +163,15 @@ namespace Exiv2 {
//@{
//! Return the size of the header (in bytes).
virtual uint32_t size() const =0;
//! Write the header to a data buffer, return the number of bytes written.
virtual uint32_t write(Blob& blob,
ByteOrder byteOrder) const =0;
/*!
@brief Return the offset to the start of the Makernote IFD from
the start of the Makernote (= the start of the header).
*/
virtual uint32_t ifdOffset() const { return 0; }
/*!
/*!
@brief Return the byte order for the makernote. If the return value is
invalidByteOrder, this means that the byte order of the the
image should be used for the makernote.
@ -179,7 +194,7 @@ namespace Exiv2 {
Contains a makernote header (which can be 0) and an IFD and
implements child mgmt functions to deal with the IFD entries. The
various makernote weirdnesses are taken care of in the makernote
header.
header (and possibly in special purpose IFD entries).
*/
class TiffIfdMakernote : public TiffComponent {
friend class TiffReader;
@ -211,12 +226,17 @@ namespace Exiv2 {
//! @name Accessors
//@{
//! Return the size of the header in bytes.
uint32_t sizeHeader() const;
//! Write the header to a data buffer, return the number of bytes written.
uint32_t writeHeader(Blob& blob, ByteOrder byteOrder) const;
//@}
/*!
@brief Return the offset to the start of the Makernote IFD from
the start of the Makernote.
*/
uint32_t ifdOffset() const;
/*!
/*!
@brief Return the byte order for the makernote. Default (if there is
no header) is invalidByteOrder. This means that the byte order
of the the image should be used for the makernote.
@ -236,11 +256,68 @@ namespace Exiv2 {
protected:
//! @name Manipulators
//@{
virtual void doAddChild(TiffComponent::AutoPtr tiffComponent);
virtual void doAddNext(TiffComponent::AutoPtr tiffComponent);
virtual TiffComponent* doAddPath(uint16_t tag, TiffPath& tiffPath);
virtual TiffComponent* doAddChild(TiffComponent::AutoPtr tiffComponent);
virtual TiffComponent* doAddNext(TiffComponent::AutoPtr tiffComponent);
virtual void doAccept(TiffVisitor& visitor);
//@}
//! @name Write support (Manipulators)
//@{
/*!
@brief Implements write(). Write the Makernote header, TIFF directory,
values and additional data to the blob, return the number of
bytes written.
*/
virtual uint32_t doWrite(Blob& blob,
ByteOrder byteOrder,
int32_t offset,
uint32_t valueIdx,
uint32_t dataIdx,
uint32_t imageIdx);
//@}
//! @name Write support (Accessors)
//@{
/*!
@brief This class does not really implement writeData(), it only has
write(). This method must not be called; it commits suicide.
*/
virtual uint32_t doWriteData(Blob& blob,
ByteOrder byteOrder,
int32_t offset,
uint32_t dataIdx,
uint32_t imageIdx) const;
/*!
@brief This class does not really implement writeImage(), it only has
write(). This method must not be called; it commits suicide.
*/
virtual uint32_t doWriteImage(Blob& blob,
ByteOrder byteOrder,
int32_t offset,
uint32_t imageIdx) const;
/*!
@brief Implements size(). Return the size of the Makernote header,
TIFF directory, values and additional data.
*/
virtual uint32_t doSize() const;
/*!
@brief Implements count(). Return the number of entries in the IFD
of the Makernote. Does not count entries which are marked as
deleted.
*/
virtual uint32_t doCount() const;
/*!
@brief This class does not really implement sizeData(), it only has
size(). This method must not be called; it commits suicide.
*/
virtual uint32_t doSizeData() const;
/*!
@brief This class does not really implement sizeData(), it only has
size(). This method must not be called; it commits suicide.
*/
virtual uint32_t doSizeImage() const;
//@}
private:
// DATA
MnHeader* pHeader_; //!< Makernote header
@ -267,6 +344,7 @@ namespace Exiv2 {
//! @name Accessors
//@{
virtual uint32_t size() const { return header_.size_; }
virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const;
virtual uint32_t ifdOffset() const { return size_; }
//@}
@ -296,9 +374,10 @@ namespace Exiv2 {
//! @name Accessors
//@{
virtual uint32_t size() const { return header_.size_; }
virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const;
virtual uint32_t ifdOffset() const { return start_; }
virtual ByteOrder byteOrder() const { return byteOrder_; }
virtual uint32_t baseOffset(uint32_t mnOffset) const { return mnOffset; }
virtual uint32_t baseOffset(uint32_t mnOffset) const { return mnOffset; }
//@}
private:
@ -329,6 +408,7 @@ namespace Exiv2 {
//! @name Accessors
//@{
virtual uint32_t size() const { return size_; }
virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const;
virtual uint32_t ifdOffset() const { return start_; }
//@}
@ -359,6 +439,7 @@ namespace Exiv2 {
//! @name Accessors
//@{
virtual uint32_t size() const { return size_; }
virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const;
virtual uint32_t ifdOffset() const { return start_; }
virtual ByteOrder byteOrder() const { return byteOrder_; }
virtual uint32_t baseOffset(uint32_t mnOffset) const { return mnOffset + 10; }
@ -392,6 +473,7 @@ namespace Exiv2 {
//! @name Accessors
//@{
virtual uint32_t size() const { return size_; }
virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const;
virtual uint32_t ifdOffset() const { return start_; }
//@}
@ -422,6 +504,7 @@ namespace Exiv2 {
//! @name Accessors
//@{
virtual uint32_t size() const { return header_.size_; }
virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const;
virtual uint32_t ifdOffset() const { return size_; }
//@}
@ -451,6 +534,7 @@ namespace Exiv2 {
//! @name Accessors
//@{
virtual uint32_t size() const { return size_; }
virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const;
virtual uint32_t ifdOffset() const { return start_; }
//@}
@ -482,6 +566,7 @@ namespace Exiv2 {
//! @name Accessors
//@{
virtual uint32_t size() const { return size_; }
virtual uint32_t write(Blob& blob, ByteOrder byteOrder) const;
virtual uint32_t ifdOffset() const { return start_; }
//@}
@ -496,21 +581,18 @@ namespace Exiv2 {
// *****************************************************************************
// template, inline and free functions
//! Function to create a Canon makernote
TiffComponent* newCanonMn(uint16_t tag,
uint16_t group,
uint16_t mnGroup,
const byte* pData,
uint32_t size,
ByteOrder byteOrder);
//! Function to create a simple IFD makernote (Canon, Minolta, Nikon1)
TiffComponent* newIfdMn(uint16_t tag,
uint16_t group,
uint16_t mnGroup,
const byte* pData,
uint32_t size,
ByteOrder byteOrder);
//! Function to create a Minolta makernote
TiffComponent* newMinoltaMn(uint16_t tag,
uint16_t group,
uint16_t mnGroup,
const byte* pData,
uint32_t size,
ByteOrder byteOrder);
//! Function to create a simple IFD makernote (Canon, Minolta, Nikon1)
TiffComponent* newIfdMn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup);
//! Function to create an Olympus makernote
TiffComponent* newOlympusMn(uint16_t tag,
@ -520,6 +602,11 @@ namespace Exiv2 {
uint32_t size,
ByteOrder byteOrder);
//! Function to create an Olympus makernote
TiffComponent* newOlympusMn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup);
//! Function to create a Fujifilm makernote
TiffComponent* newFujiMn(uint16_t tag,
uint16_t group,
@ -528,6 +615,11 @@ namespace Exiv2 {
uint32_t size,
ByteOrder byteOrder);
//! Function to create a Fujifilm makernote
TiffComponent* newFujiMn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup);
/*!
@brief Function to create a Nikon makernote. This will create the
appropriate Nikon 1, 2 or 3 makernote, based on the arguments.
@ -539,6 +631,16 @@ namespace Exiv2 {
uint32_t size,
ByteOrder byteOrder);
//! Function to create a Nikon2 makernote
TiffComponent* newNikon2Mn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup);
//! Function to create a Nikon3 makernote
TiffComponent* newNikon3Mn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup);
//! Function to create a Panasonic makernote
TiffComponent* newPanasonicMn(uint16_t tag,
uint16_t group,
@ -547,13 +649,23 @@ namespace Exiv2 {
uint32_t size,
ByteOrder byteOrder);
//! Function to create a Panasonic makernote
TiffComponent* newPanasonicMn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup);
//! Function to create an Pentax makernote
TiffComponent* newPentaxMn(uint16_t tag,
uint16_t group,
uint16_t mnGroup,
const byte* pData,
uint32_t size,
ByteOrder byteOrder);
uint16_t group,
uint16_t mnGroup,
const byte* pData,
uint32_t size,
ByteOrder byteOrder);
//! Function to create an Pentax makernote
TiffComponent* newPentaxMn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup);
//! Function to create a Sigma makernote
TiffComponent* newSigmaMn(uint16_t tag,
@ -563,6 +675,11 @@ namespace Exiv2 {
uint32_t size,
ByteOrder byteOrder);
//! Function to create a Sigma makernote
TiffComponent* newSigmaMn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup);
//! Function to create a Sony makernote
TiffComponent* newSonyMn(uint16_t tag,
uint16_t group,
@ -571,6 +688,16 @@ namespace Exiv2 {
uint32_t size,
ByteOrder byteOrder);
} // namespace Exiv2
//! Function to create a Sony1 makernote
TiffComponent* newSony1Mn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup);
//! Function to create a Sony2 makernote
TiffComponent* newSony2Mn2(uint16_t tag,
uint16_t group,
uint16_t mnGroup);
}} // namespace Internal, Exiv2
#endif // #ifndef MAKERNOTE2_HPP_
#endif // #ifndef MAKERNOTE2_INT_HPP_

@ -35,7 +35,6 @@ EXIV2_RCSID("@(#) $Id$")
// included header files
#include "types.hpp"
#include "minoltamn.hpp"
#include "makernote.hpp"
#include "value.hpp"
#include "tags.hpp"
#include "i18n.h" // NLS support.
@ -531,42 +530,42 @@ namespace Exiv2 {
{ 2, N_("Manual flash control") }
};
std::ostream& MinoltaMakerNote::printMinoltaExposureSpeedStd(std::ostream& os, const Value& value)
std::ostream& MinoltaMakerNote::printMinoltaExposureSpeedStd(std::ostream& os, const Value& value, const ExifData*)
{
// From the PHP JPEG Metadata Toolkit
os << (value.toLong()/8)-1;
return os;
}
std::ostream& MinoltaMakerNote::printMinoltaExposureTimeStd(std::ostream& os, const Value& value)
std::ostream& MinoltaMakerNote::printMinoltaExposureTimeStd(std::ostream& os, const Value& value, const ExifData*)
{
// From the PHP JPEG Metadata Toolkit
os << (value.toLong()/8)-6;
return os;
}
std::ostream& MinoltaMakerNote::printMinoltaFNumberStd(std::ostream& os, const Value& value)
std::ostream& MinoltaMakerNote::printMinoltaFNumberStd(std::ostream& os, const Value& value, const ExifData*)
{
// From the PHP JPEG Metadata Toolkit
os << (value.toLong()/8)-1;
return os;
}
std::ostream& MinoltaMakerNote::printMinoltaExposureCompensationStd(std::ostream& os, const Value& value)
std::ostream& MinoltaMakerNote::printMinoltaExposureCompensationStd(std::ostream& os, const Value& value, const ExifData*)
{
// From the PHP JPEG Metadata Toolkit
os << value.toLong()/256;
return os;
}
std::ostream& MinoltaMakerNote::printMinoltaFocalLengthStd(std::ostream& os, const Value& value)
std::ostream& MinoltaMakerNote::printMinoltaFocalLengthStd(std::ostream& os, const Value& value, const ExifData*)
{
// From the PHP JPEG Metadata Toolkit
os << (value.toLong()/3)-2;
return os;
}
std::ostream& MinoltaMakerNote::printMinoltaDateStd(std::ostream& os, const Value& value)
std::ostream& MinoltaMakerNote::printMinoltaDateStd(std::ostream& os, const Value& value, const ExifData*)
{
// From the PHP JPEG Metadata Toolkit
os << value.toLong() / 65536 << ":" << std::right << std::setw(2) << std::setfill('0')
@ -575,7 +574,7 @@ namespace Exiv2 {
return os;
}
std::ostream& MinoltaMakerNote::printMinoltaTimeStd(std::ostream& os, const Value& value)
std::ostream& MinoltaMakerNote::printMinoltaTimeStd(std::ostream& os, const Value& value, const ExifData*)
{
// From the PHP JPEG Metadata Toolkit
os << std::right << std::setw(2) << std::setfill('0') << value.toLong() / 65536
@ -585,21 +584,21 @@ namespace Exiv2 {
return os;
}
std::ostream& MinoltaMakerNote::printMinoltaFlashExposureCompStd(std::ostream& os, const Value& value)
std::ostream& MinoltaMakerNote::printMinoltaFlashExposureCompStd(std::ostream& os, const Value& value, const ExifData*)
{
// From the PHP JPEG Metadata Toolkit
os << (value.toLong()-6)/3;
return os;
}
std::ostream& MinoltaMakerNote::printMinoltaWhiteBalanceStd(std::ostream& os, const Value& value)
std::ostream& MinoltaMakerNote::printMinoltaWhiteBalanceStd(std::ostream& os, const Value& value, const ExifData*)
{
// From the PHP JPEG Metadata Toolkit
os << value.toLong()/256;
return os;
}
std::ostream& MinoltaMakerNote::printMinoltaBrightnessStd(std::ostream& os, const Value& value)
std::ostream& MinoltaMakerNote::printMinoltaBrightnessStd(std::ostream& os, const Value& value, const ExifData*)
{
// From the PHP JPEG Metadata Toolkit
os << (value.toLong()/8)-6;
@ -1096,7 +1095,7 @@ namespace Exiv2 {
};
//! Method to convert Minolta Dynax 5D exposure manual bias values.
std::ostream& MinoltaMakerNote::printMinoltaExposureManualBias5D(std::ostream& os, const Value& value)
std::ostream& MinoltaMakerNote::printMinoltaExposureManualBias5D(std::ostream& os, const Value& value, const ExifData*)
{
// From Xavier Raynaud: the value is converted from 0:256 to -5.33:5.33
@ -1109,7 +1108,7 @@ namespace Exiv2 {
}
//! Method to convert Minolta Dynax 5D exposure compensation values.
std::ostream& MinoltaMakerNote::printMinoltaExposureCompensation5D(std::ostream& os, const Value& value)
std::ostream& MinoltaMakerNote::printMinoltaExposureCompensation5D(std::ostream& os, const Value& value, const ExifData*)
{
std::ostringstream oss;
oss.copyfmt(os);
@ -1219,306 +1218,4 @@ namespace Exiv2 {
// TODO : Add camera settings tags info "New2"...
//! @cond IGNORE
MinoltaMakerNote::RegisterMn::RegisterMn()
{
MakerNoteFactory::registerMakerNote("KONICA MINOLTA*", "*", createMinoltaMakerNote);
MakerNoteFactory::registerMakerNote("Minolta*", "*", createMinoltaMakerNote);
MakerNoteFactory::registerMakerNote(minoltaIfdId, MakerNote::AutoPtr(new MinoltaMakerNote));
MakerNoteFactory::registerMakerNote(minoltaCs5DIfdId, MakerNote::AutoPtr(new MinoltaMakerNote));
MakerNoteFactory::registerMakerNote(minoltaCs7DIfdId, MakerNote::AutoPtr(new MinoltaMakerNote));
MakerNoteFactory::registerMakerNote(minoltaCsOldIfdId, MakerNote::AutoPtr(new MinoltaMakerNote));
MakerNoteFactory::registerMakerNote(minoltaCsNewIfdId, MakerNote::AutoPtr(new MinoltaMakerNote));
}
//! @endcond
int MinoltaMakerNote::read(const byte* buf, long len, long start, ByteOrder byteOrder, long shift)
{
int rc = IfdMakerNote::read(buf, len, start, byteOrder, shift);
if (rc) return rc;
// Decode Dynax 5D camera settings and add settings as additional entries
Entries::iterator cs5D = ifd_.findTag(0x0114);
if (cs5D != ifd_.end() && cs5D->type() == undefined) {
for (uint16_t c = 0; cs5D->count()/2 > c; ++c) {
addCsEntry(minoltaCs5DIfdId, c, cs5D->offset() + c*2, cs5D->data() + c*2, 1);
}
// Discard the original entry
ifd_.erase(cs5D);
}
// Decode Dynax 7D camera settings and add settings as additional entries
Entries::iterator cs7D = ifd_.findTag(0x0004);
if (cs7D != ifd_.end() && cs7D->type() == undefined) {
for (uint16_t c = 0; cs7D->count()/2 > c; ++c) {
addCsEntry(minoltaCs7DIfdId, c, cs7D->offset() + c*2, cs7D->data() + c*2, 1);
}
// Discard the original entry
ifd_.erase(cs7D);
}
// Decode Old Std camera settings and add settings as additional entries
Entries::iterator csOldStd = ifd_.findTag(0x0001);
if (csOldStd != ifd_.end() && csOldStd->type() == undefined) {
for (uint16_t c = 0; csOldStd->count()/4 > c; ++c) {
addCsStdEntry(minoltaCsOldIfdId, c, csOldStd->offset() + c*4, csOldStd->data() + c*4, 1);
}
// Discard the original entry
ifd_.erase(csOldStd);
}
// Decode New Std camera settings and add settings as additional entries
Entries::iterator csNewStd = ifd_.findTag(0x0003);
if (csNewStd != ifd_.end() && csNewStd->type() == undefined) {
for (uint16_t c = 0; csNewStd->count()/4 > c; ++c) {
addCsStdEntry(minoltaCsNewIfdId, c, csNewStd->offset() + c*4, csNewStd->data() + c*4, 1);
}
// Discard the original entry
ifd_.erase(csNewStd);
}
// Copy remaining ifd entries
entries_.insert(entries_.begin(), ifd_.begin(), ifd_.end());
// Set idx
int idx = 0;
Entries::iterator e = entries_.end();
for (Entries::iterator i = entries_.begin(); i != e; ++i) {
i->setIdx(++idx);
}
return 0;
}
void MinoltaMakerNote::addCsEntry(IfdId ifdId, uint16_t tag, long offset, const byte* data, int count)
{
Entry e(false);
e.setIfdId(ifdId);
e.setTag(tag);
e.setOffset(offset);
e.setValue(unsignedShort, count, data, 2*count, bigEndian);
add(e);
}
void MinoltaMakerNote::addCsStdEntry(IfdId ifdId, uint32_t tag, long offset, const byte* data, int count)
{
Entry e(false);
e.setIfdId(ifdId);
e.setTag(tag);
e.setOffset(offset);
e.setValue(unsignedLong, count, data, 4*count, bigEndian);
add(e);
}
void MinoltaMakerNote::add(const Entry& entry)
{
assert(alloc_ == entry.alloc());
assert( entry.ifdId() == minoltaIfdId
|| entry.ifdId() == minoltaCs5DIfdId
|| entry.ifdId() == minoltaCs7DIfdId
|| entry.ifdId() == minoltaCsOldIfdId
|| entry.ifdId() == minoltaCsNewIfdId);
// allow duplicates
entries_.push_back(entry);
}
long MinoltaMakerNote::copy(byte* buf, ByteOrder byteOrder, long offset)
{
if (byteOrder_ == invalidByteOrder) byteOrder_ = byteOrder;
assert(ifd_.alloc());
ifd_.clear();
// Add all standard Minolta entries to the IFD
Entries::const_iterator end = entries_.end();
for (Entries::const_iterator i = entries_.begin(); i != end; ++i) {
if (i->ifdId() == minoltaIfdId) {
ifd_.add(*i);
}
}
// Collect Dynax 5D camera settings entries and add the original Minolta tag
Entry cs5D;
if (assemble(cs5D, minoltaCs5DIfdId, 0x0114, bigEndian)) {
ifd_.erase(0x0114);
ifd_.add(cs5D);
}
// Collect Dynax 7D camera settings entries and add the original Minolta tag
Entry cs7D;
if (assemble(cs7D, minoltaCs7DIfdId, 0x0004, bigEndian)) {
ifd_.erase(0x0004);
ifd_.add(cs7D);
}
// Collect Old Std camera settings entries and add the original Minolta tag
Entry csOldStd;
if (assembleStd(csOldStd, minoltaCsOldIfdId, 0x0001, bigEndian)) {
ifd_.erase(0x0001);
ifd_.add(csOldStd);
}
// Collect New Std camera settings entries and add the original Minolta tag
Entry csNewStd;
if (assembleStd(csNewStd, minoltaCsNewIfdId, 0x0003, bigEndian)) {
ifd_.erase(0x0003);
ifd_.add(csNewStd);
}
return IfdMakerNote::copy(buf, byteOrder_, offset);
} // MinoltaMakerNote::copy
void MinoltaMakerNote::updateBase(byte* pNewBase)
{
byte* pBase = ifd_.updateBase(pNewBase);
if (absShift_ && !alloc_) {
Entries::iterator end = entries_.end();
for (Entries::iterator pos = entries_.begin(); pos != end; ++pos) {
pos->updateBase(pBase, pNewBase);
}
}
} // MinoltaMakerNote::updateBase
long MinoltaMakerNote::size() const
{
Ifd ifd(minoltaIfdId, 0, alloc_); // offset doesn't matter
// Add all standard Minolta entries to the IFD
Entries::const_iterator end = entries_.end();
for (Entries::const_iterator i = entries_.begin(); i != end; ++i) {
if (i->ifdId() == minoltaIfdId) {
ifd.add(*i);
}
}
// Collect Dynax 5D camera settings entries and add the original Minolta tag
Entry cs5D(alloc_);
if (assemble(cs5D, minoltaCs5DIfdId, 0x0114, bigEndian)) {
ifd.erase(0x0114);
ifd.add(cs5D);
}
// Collect Dynax 7D camera settings entries and add the original Minolta tag
Entry cs7D(alloc_);
if (assemble(cs7D, minoltaCs7DIfdId, 0x0004, bigEndian)) {
ifd.erase(0x0004);
ifd.add(cs7D);
}
// Collect Old Std camera settings entries and add the original Minolta tag
Entry csOldStd(alloc_);
if (assembleStd(csOldStd, minoltaCsOldIfdId, 0x0001, bigEndian)) {
ifd.erase(0x0001);
ifd.add(csOldStd);
}
// Collect New Std camera settings entries and add the original Minolta tag
Entry csNewStd(alloc_);
if (assembleStd(csNewStd, minoltaCsNewIfdId, 0x0003, bigEndian)) {
ifd.erase(0x0003);
ifd.add(csNewStd);
}
return headerSize() + ifd.size() + ifd.dataSize();
} // MinoltaMakerNote::size
long MinoltaMakerNote::assemble(Entry& e, IfdId ifdId, uint16_t tag, ByteOrder /*byteOrder*/) const
{
DataBuf buf(1024);
std::memset(buf.pData_, 0x0, 1024);
uint16_t len = 0;
Entries::const_iterator end = entries_.end();
for (Entries::const_iterator i = entries_.begin(); i != end; ++i) {
if (i->ifdId() == ifdId) {
uint16_t pos = i->tag() * 2;
uint16_t size = pos + static_cast<uint16_t>(i->size());
assert(size <= 1024);
std::memcpy(buf.pData_ + pos, i->data(), i->size());
if (len < size) len = size;
}
}
if (len > 0) {
e.setIfdId(minoltaIfdId);
e.setIdx(0); // don't care
e.setTag(tag);
e.setOffset(0); // will be calculated when the IFD is written
e.setValue(undefined, len, buf.pData_, len * 2);
}
return len;
} // MinoltaMakerNote::assemble
long MinoltaMakerNote::assembleStd(Entry& e, IfdId ifdId, uint32_t tag, ByteOrder /*byteOrder*/) const
{
DataBuf buf(1024);
std::memset(buf.pData_, 0x0, 1024);
uint32_t len = 0;
Entries::const_iterator end = entries_.end();
for (Entries::const_iterator i = entries_.begin(); i != end; ++i) {
if (i->ifdId() == ifdId) {
uint32_t pos = i->tag() * 4;
uint32_t size = pos + static_cast<uint32_t>(i->size());
assert(size <= 1024);
std::memcpy(buf.pData_ + pos, i->data(), i->size());
if (len < size) len = size;
}
}
if (len > 0) {
e.setIfdId(minoltaIfdId);
e.setIdx(0); // don't care
e.setTag(tag);
e.setOffset(0); // will be calculated when the IFD is written
e.setValue(undefined, len, buf.pData_, len * 4);
}
return len;
} // MinoltaMakerNote::assembleStd
Entries::const_iterator MinoltaMakerNote::findIdx(int idx) const
{
return std::find_if(entries_.begin(), entries_.end(), FindEntryByIdx(idx));
}
MinoltaMakerNote::MinoltaMakerNote(bool alloc)
: IfdMakerNote(minoltaIfdId, alloc)
{
}
MinoltaMakerNote::MinoltaMakerNote(const MinoltaMakerNote& rhs)
: IfdMakerNote(rhs)
{
entries_ = rhs.entries_;
}
MinoltaMakerNote::AutoPtr MinoltaMakerNote::create(bool alloc) const
{
return AutoPtr(create_(alloc));
}
MinoltaMakerNote* MinoltaMakerNote::create_(bool alloc) const
{
return new MinoltaMakerNote(alloc);
}
MinoltaMakerNote::AutoPtr MinoltaMakerNote::clone() const
{
return AutoPtr(clone_());
}
MinoltaMakerNote* MinoltaMakerNote::clone_() const
{
return new MinoltaMakerNote(*this);
}
// *****************************************************************************
// free functions
MakerNote::AutoPtr createMinoltaMakerNote(bool alloc, const byte* /*buf*/, long /*len*/,
ByteOrder /*byteOrder*/, long /*offset*/)
{
return MakerNote::AutoPtr(new MinoltaMakerNote(alloc));
}
} // namespace Exiv2

@ -38,94 +38,21 @@
// *****************************************************************************
// included header files
#include "types.hpp"
#include "makernote.hpp"
#include "tags.hpp"
// + standard includes
#include <string>
#include <iosfwd>
#include <memory>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class Value;
// *****************************************************************************
// free functions
/*!
@brief Return an auto-pointer to a newly created empty MakerNote
initialized to operate in the memory management model indicated.
The caller owns this copy and the auto-pointer ensures that it
will be deleted.
@param alloc Memory management model for the new MakerNote. Determines if
memory required to store data should be allocated and deallocated
(true) or not (false). If false, only pointers to the buffer
provided to read() will be kept. See Ifd for more background on
this concept.
@param buf Pointer to the makernote character buffer (not used).
@param len Length of the makernote character buffer (not used).
@param byteOrder Byte order in which the Exif data (and possibly the
makernote) is encoded (not used).
@param offset Offset from the start of the TIFF header of the makernote
buffer (not used).
@return An auto-pointer to a newly created empty MakerNote. The caller
owns this copy and the auto-pointer ensures that it will be
deleted.
*/
MakerNote::AutoPtr createMinoltaMakerNote(bool alloc,
const byte* buf,
long len,
ByteOrder byteOrder,
long offset);
// *****************************************************************************
// class definitions
//! MakerNote for Minolta cameras
class MinoltaMakerNote : public IfdMakerNote {
class MinoltaMakerNote {
public:
//! Shortcut for a %MinoltaMakerNote auto pointer.
typedef std::auto_ptr<MinoltaMakerNote> AutoPtr;
//! @name Creators
//@{
/*!
@brief Constructor. Allows to choose whether or not memory management
is required for the makernote entries.
*/
MinoltaMakerNote(bool alloc =true);
//! Copy constructor
MinoltaMakerNote(const MinoltaMakerNote& rhs);
//! Virtual destructor
virtual ~MinoltaMakerNote() {}
//@}
//! @name Manipulators
//@{
int read(const byte* buf, long len, long start, ByteOrder byteOrder, long shift);
long copy(byte* buf, ByteOrder byteOrder, long offset);
void add(const Entry& entry);
Entries::iterator begin() { return entries_.begin(); }
Entries::iterator end() { return entries_.end(); }
void updateBase(byte* pNewBase);
//@}
//! @name Accessors
//@{
Entries::const_iterator begin() const { return entries_.begin(); }
Entries::const_iterator end() const { return entries_.end(); }
Entries::const_iterator findIdx(int idx) const;
long size() const;
AutoPtr create(bool alloc =true) const;
AutoPtr clone() const;
//! Return read-only list of built-in Minolta tags
static const TagInfo* tagList();
//! Return read-only list of built-in Minolta Standard Camera Settings tags
@ -134,69 +61,37 @@ namespace Exiv2 {
static const TagInfo* tagListCs7D();
//! Return read-only list of built-in Minolta 5D Camera Settings tags
static const TagInfo* tagListCs5D();
//@}
//! @name Print functions for Minolta %MakerNote tags
//@{
//! Print Exposure Speed setting from standard Minolta Camera Settings makernote
static std::ostream& printMinoltaExposureSpeedStd(std::ostream& os, const Value& value);
static std::ostream& printMinoltaExposureSpeedStd(std::ostream& os, const Value& value, const ExifData*);
//! Print Exposure Time setting from standard Minolta Camera Settings makernote
static std::ostream& printMinoltaExposureTimeStd(std::ostream& os, const Value& value);
static std::ostream& printMinoltaExposureTimeStd(std::ostream& os, const Value& value, const ExifData*);
//! Print F Number setting from standard Minolta Camera Settings makernote
static std::ostream& printMinoltaFNumberStd(std::ostream& os, const Value& value);
static std::ostream& printMinoltaFNumberStd(std::ostream& os, const Value& value, const ExifData*);
//! Print Exposure Compensation setting from standard Minolta Camera Settings makernote
static std::ostream& printMinoltaExposureCompensationStd(std::ostream& os, const Value& value);
static std::ostream& printMinoltaExposureCompensationStd(std::ostream& os, const Value& value, const ExifData*);
//! Print Focal Length setting from standard Minolta Camera Settings makernote
static std::ostream& printMinoltaFocalLengthStd(std::ostream& os, const Value& value);
static std::ostream& printMinoltaFocalLengthStd(std::ostream& os, const Value& value, const ExifData*);
//! Print Minolta Date from standard Minolta Camera Settings makernote
static std::ostream& printMinoltaDateStd(std::ostream& os, const Value& value);
static std::ostream& printMinoltaDateStd(std::ostream& os, const Value& value, const ExifData*);
//! Print Minolta Time from standard Minolta Camera Settings makernote
static std::ostream& printMinoltaTimeStd(std::ostream& os, const Value& value);
static std::ostream& printMinoltaTimeStd(std::ostream& os, const Value& value, const ExifData*);
//! Print Flash Exposure Compensation setting from standard Minolta Camera Settings makernote
static std::ostream& printMinoltaFlashExposureCompStd(std::ostream& os, const Value& value);
static std::ostream& printMinoltaFlashExposureCompStd(std::ostream& os, const Value& value, const ExifData*);
//! Print White Balance setting from standard Minolta Camera Settings makernote
static std::ostream& printMinoltaWhiteBalanceStd(std::ostream& os, const Value& value);
static std::ostream& printMinoltaWhiteBalanceStd(std::ostream& os, const Value& value, const ExifData*);
//! Print Brightness setting from standard Minolta Camera Settings makernote
static std::ostream& printMinoltaBrightnessStd(std::ostream& os, const Value& value);
static std::ostream& printMinoltaBrightnessStd(std::ostream& os, const Value& value, const ExifData*);
//! Print Exposure Manual Bias setting from 5D Minolta Camera Settings makernote
static std::ostream& printMinoltaExposureManualBias5D(std::ostream& os, const Value& value);
static std::ostream& printMinoltaExposureManualBias5D(std::ostream& os, const Value& value, const ExifData*);
//! Print Exposure Compensation setting from 5D Minolta Camera Settings makernote
static std::ostream& printMinoltaExposureCompensation5D(std::ostream& os, const Value& value);
static std::ostream& printMinoltaExposureCompensation5D(std::ostream& os, const Value& value, const ExifData*);
//@}
//! @cond IGNORE
// Public only so that we can create a static instance
struct RegisterMn {
RegisterMn();
};
//! @endcond
private:
//! @name Manipulators
//@{
//! Add a Dynax 5D and 7D camera settings entry to the makernote entries
void addCsEntry(IfdId ifdId, uint16_t tag, long offset, const byte* data, int count);
//! Add a standard camera settings entry to the makernote entries
void addCsStdEntry(IfdId ifdId, uint32_t tag, long offset, const byte* data, int count);
//@}
//! @name Accessors
//@{
//! Assemble special Dynax 5D or 7D Minolta entries into an entry with the original tag
long assemble(Entry& e, IfdId ifdId, uint16_t tag, ByteOrder byteOrder) const;
//! Assemble special standard Minolta entries into an entry with the original tag
long assembleStd(Entry& e, IfdId ifdId, uint32_t tag, ByteOrder byteOrder) const;
//! Internal virtual create function.
MinoltaMakerNote* create_(bool alloc =true) const;
//! Internal virtual copy constructor.
MinoltaMakerNote* clone_() const;
//@}
// DATA
//! Container to store Makernote entries (instead of Ifd)
Entries entries_;
//! Tag information
static const TagInfo tagInfo_[];
static const TagInfo tagInfoCs5D_[];
@ -205,7 +100,6 @@ namespace Exiv2 {
}; // class MinoltaMakerNote
static MinoltaMakerNote::RegisterMn registerMinoltaMakerNote;
} // namespace Exiv2
#endif // #ifndef MINOLTAMN_HPP_

@ -38,7 +38,7 @@ EXIV2_RCSID("@(#) $Id$")
#endif
#include "mrwimage.hpp"
#include "tiffparser.hpp"
#include "tiffimage.hpp"
#include "image.hpp"
#include "basicio.hpp"
#include "error.hpp"
@ -142,8 +142,12 @@ namespace Exiv2 {
io_->read(buf.pData_, buf.size_);
if (io_->error() || io_->eof()) throw Error(14);
TiffParser::decode(this, buf.pData_, buf.size_,
TiffCreator::create, TiffDecoder::findDecoder);
ByteOrder bo = TiffParser::decode(exifData_,
iptcData_,
xmpData_,
buf.pData_,
buf.size_);
setByteOrder(bo);
} // MrwImage::readMetadata
void MrwImage::writeMetadata()

@ -0,0 +1,49 @@
// ***************************************************************** -*- C++ -*-
// mrwthumb.cpp, $Rev$
// Sample program to extract a Minolta thumbnail from the makernote
#include "image.hpp"
#include "exif.hpp"
#include "error.hpp"
#include <cassert>
int main(int argc, char* const argv[])
try {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(argv[1]);
assert(image.get() != 0);
image->readMetadata();
Exiv2::ExifData &exifData = image->exifData();
if (exifData.empty()) {
std::string error(argv[1]);
error += ": No Exif data found in the file";
throw Exiv2::Error(1, error);
}
Exiv2::ExifKey key("Exif.Minolta.ThumbnailOffset");
Exiv2::ExifData::const_iterator format = exifData.findKey(key);
if (format != exifData.end()) {
Exiv2::DataBuf buf = format->dataArea();
// The first byte of the buffer needs to be patched
buf.pData_[0] = 0xff;
Exiv2::FileIo file("img_thumb.jpg");
file.open("wb");
file.write(buf.pData_, buf.size_);
file.close();
}
return 0;
}
catch (Exiv2::AnyError& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}

@ -37,7 +37,6 @@ EXIV2_RCSID("@(#) $Id$")
// included header files
#include "types.hpp"
#include "nikonmn.hpp"
#include "makernote.hpp"
#include "value.hpp"
#include "image.hpp"
#include "tags.hpp"
@ -147,15 +146,6 @@ namespace Exiv2 {
{ 6, N_("Strong") }
};
//! @cond IGNORE
Nikon1MakerNote::RegisterMn::RegisterMn()
{
MakerNoteFactory::registerMakerNote("NIKON*", "*", createNikonMakerNote);
MakerNoteFactory::registerMakerNote(
nikon1IfdId, MakerNote::AutoPtr(new Nikon1MakerNote));
}
//! @endcond
// Nikon1 MakerNote Tag Info
const TagInfo Nikon1MakerNote::tagInfo_[] = {
TagInfo(0x0001, "Version", N_("Version"),
@ -218,38 +208,9 @@ namespace Exiv2 {
return tagInfo_;
}
Nikon1MakerNote::Nikon1MakerNote(bool alloc)
: IfdMakerNote(nikon1IfdId, alloc)
{
}
Nikon1MakerNote::Nikon1MakerNote(const Nikon1MakerNote& rhs)
: IfdMakerNote(rhs)
{
}
Nikon1MakerNote::AutoPtr Nikon1MakerNote::create(bool alloc) const
{
return AutoPtr(create_(alloc));
}
Nikon1MakerNote* Nikon1MakerNote::create_(bool alloc) const
{
return new Nikon1MakerNote(alloc);
}
Nikon1MakerNote::AutoPtr Nikon1MakerNote::clone() const
{
return AutoPtr(clone_());
}
Nikon1MakerNote* Nikon1MakerNote::clone_() const
{
return new Nikon1MakerNote(*this);
}
std::ostream& Nikon1MakerNote::print0x0002(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
if (value.count() > 1) {
os << value.toLong(1);
@ -261,7 +222,8 @@ namespace Exiv2 {
}
std::ostream& Nikon1MakerNote::print0x0007(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
std::string focus = value.toString();
if (focus == "AF-C ") os << _("Continuous autofocus");
@ -271,7 +233,8 @@ namespace Exiv2 {
}
std::ostream& Nikon1MakerNote::print0x0085(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
Rational distance = value.toRational();
if (distance.first == 0) {
@ -292,7 +255,8 @@ namespace Exiv2 {
}
std::ostream& Nikon1MakerNote::print0x0086(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
Rational zoom = value.toRational();
if (zoom.first == 0) {
@ -313,7 +277,8 @@ namespace Exiv2 {
}
std::ostream& Nikon1MakerNote::print0x0088(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
if (value.count() >= 1) {
unsigned long focusArea = value.toLong(0);
@ -380,14 +345,6 @@ namespace Exiv2 {
return os;
}
//! @cond IGNORE
Nikon2MakerNote::RegisterMn::RegisterMn()
{
MakerNoteFactory::registerMakerNote(
nikon2IfdId, MakerNote::AutoPtr(new Nikon2MakerNote));
}
//! @endcond
//! Quality, tag 0x0003
extern const TagDetails nikon2Quality[] = {
{ 1, N_("VGA Basic") },
@ -478,69 +435,9 @@ namespace Exiv2 {
return tagInfo_;
}
Nikon2MakerNote::Nikon2MakerNote(bool alloc)
: IfdMakerNote(nikon2IfdId, alloc)
{
byte buf[] = {
'N', 'i', 'k', 'o', 'n', '\0', 0x00, 0x01
};
readHeader(buf, 8, byteOrder_);
}
Nikon2MakerNote::Nikon2MakerNote(const Nikon2MakerNote& rhs)
: IfdMakerNote(rhs)
{
}
int Nikon2MakerNote::readHeader(const byte* buf,
long len,
ByteOrder /*byteOrder*/)
{
if (len < 8) return 1;
header_.alloc(8);
std::memcpy(header_.pData_, buf, header_.size_);
start_ = 8;
return 0;
}
int Nikon2MakerNote::checkHeader() const
{
int rc = 0;
// Check the Nikon prefix
if ( header_.size_ < 8
|| std::string(reinterpret_cast<char*>(header_.pData_), 6)
!= std::string("Nikon\0", 6)) {
rc = 2;
}
return rc;
}
Nikon2MakerNote::AutoPtr Nikon2MakerNote::create(bool alloc) const
{
return AutoPtr(create_(alloc));
}
Nikon2MakerNote* Nikon2MakerNote::create_(bool alloc) const
{
AutoPtr makerNote(new Nikon2MakerNote(alloc));
assert(makerNote.get() != 0);
makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
return makerNote.release();
}
Nikon2MakerNote::AutoPtr Nikon2MakerNote::clone() const
{
return AutoPtr(clone_());
}
Nikon2MakerNote* Nikon2MakerNote::clone_() const
{
return new Nikon2MakerNote(*this);
}
std::ostream& Nikon2MakerNote::print0x000a(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
Rational zoom = value.toRational();
if (zoom.first == 0) {
@ -560,14 +457,6 @@ namespace Exiv2 {
return os;
}
//! @cond IGNORE
Nikon3MakerNote::RegisterMn::RegisterMn()
{
MakerNoteFactory::registerMakerNote(
nikon3IfdId, MakerNote::AutoPtr(new Nikon3MakerNote));
}
//! @endcond
// Nikon3 MakerNote Tag Info
const TagInfo Nikon3MakerNote::tagInfo_[] = {
TagInfo(0x0001, "Version", N_("Version"),
@ -800,75 +689,9 @@ namespace Exiv2 {
return tagInfo_;
}
Nikon3MakerNote::Nikon3MakerNote(bool alloc)
: IfdMakerNote(nikon3IfdId, alloc)
{
absShift_ = false;
byte buf[] = {
'N', 'i', 'k', 'o', 'n', '\0',
0x02, 0x10, 0x00, 0x00, 0x4d, 0x4d, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x08
};
readHeader(buf, 18, byteOrder_);
}
Nikon3MakerNote::Nikon3MakerNote(const Nikon3MakerNote& rhs)
: IfdMakerNote(rhs)
{
}
int Nikon3MakerNote::readHeader(const byte* buf,
long len,
ByteOrder /*byteOrder*/)
{
if (len < 18) return 1;
header_.alloc(18);
std::memcpy(header_.pData_, buf, header_.size_);
TiffHeader tiffHeader;
tiffHeader.read(header_.pData_ + 10);
byteOrder_ = tiffHeader.byteOrder();
start_ = 10 + tiffHeader.offset();
shift_ = 10;
return 0;
}
int Nikon3MakerNote::checkHeader() const
{
int rc = 0;
// Check the Nikon prefix
if ( header_.size_ < 18
|| std::string(reinterpret_cast<char*>(header_.pData_), 6)
!= std::string("Nikon\0", 6)) {
rc = 2;
}
return rc;
}
Nikon3MakerNote::AutoPtr Nikon3MakerNote::create(bool alloc) const
{
return AutoPtr(create_(alloc));
}
Nikon3MakerNote* Nikon3MakerNote::create_(bool alloc) const
{
AutoPtr makerNote(new Nikon3MakerNote(alloc));
assert(makerNote.get() != 0);
makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
return makerNote.release();
}
Nikon3MakerNote::AutoPtr Nikon3MakerNote::clone() const
{
return AutoPtr(clone_());
}
Nikon3MakerNote* Nikon3MakerNote::clone_() const
{
return new Nikon3MakerNote(*this);
}
std::ostream& Nikon3MakerNote::print0x0002(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
if (value.count() > 1) {
os << value.toLong(1);
@ -880,7 +703,8 @@ namespace Exiv2 {
}
std::ostream& Nikon3MakerNote::print0x0007(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
std::string focus = value.toString();
if (focus == "AF-C ") os << _("Continuous autofocus");
@ -890,7 +714,8 @@ namespace Exiv2 {
}
std::ostream& Nikon3MakerNote::print0x0083(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
long lensType = value.toLong();
@ -923,7 +748,8 @@ namespace Exiv2 {
}
std::ostream& Nikon3MakerNote::print0x0084(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
if ( value.count() != 4
|| value.toRational(0).second == 0
@ -954,7 +780,8 @@ namespace Exiv2 {
}
std::ostream& Nikon3MakerNote::print0x0085(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
Rational distance = value.toRational();
if (distance.first == 0) {
@ -975,7 +802,8 @@ namespace Exiv2 {
}
std::ostream& Nikon3MakerNote::print0x0086(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
Rational zoom = value.toRational();
if (zoom.first == 0) {
@ -996,7 +824,8 @@ namespace Exiv2 {
}
std::ostream& Nikon3MakerNote::print0x0088(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
if (value.size() != 4) { // Size is 4 even for those who map this way...
os << "(" << value << ")";
@ -1064,7 +893,8 @@ namespace Exiv2 {
}
std::ostream& Nikon3MakerNote::print0x008b(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
// Decoded by Robert Rottmerhusen <email@rottmerhusen.com>
if ( value.size() != 4
@ -1079,7 +909,8 @@ namespace Exiv2 {
}
std::ostream& Nikon3MakerNote::print0x0098(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
#ifdef EXV_HAVE_LENSDATA
//#-----------------------------------------
@ -1448,9 +1279,9 @@ namespace Exiv2 {
idx = 11;
}
else if (0 == memcmp(lens.pData_, "0201", 4)) {
// Here we should decrypt(lens.pData_ + 4, lens.size_ - 4);
// however, the decrypt algorithm requires access to serial number
// and shutter count tags but print functions are static...
// Todo: decrypt(lens.pData_ + 4, lens.size_ - 4);
// The decrypt algorithm requires access to serial number
// and shutter count tags
idx = 11;
}
if (idx == 0 || lens.size_ < idx + 7) {
@ -1476,29 +1307,4 @@ namespace Exiv2 {
#endif // EXV_HAVE_LENSDATA
}
// *****************************************************************************
// free functions
MakerNote::AutoPtr createNikonMakerNote(bool alloc,
const byte* buf,
long len,
ByteOrder /*byteOrder*/,
long /*offset*/)
{
// If there is no "Nikon" string it must be Nikon1 format
if (len < 6 || std::string(reinterpret_cast<const char*>(buf), 6)
!= std::string("Nikon\0", 6)) {
return MakerNote::AutoPtr(new Nikon1MakerNote(alloc));
}
// If the "Nikon" string is not followed by a TIFF header, we assume
// Nikon2 format
TiffHeader tiffHeader;
if ( len < 18
|| tiffHeader.read(buf + 10) != 0 || tiffHeader.tag() != 0x002a) {
return MakerNote::AutoPtr(new Nikon2MakerNote(alloc));
}
// Else we have a Nikon3 makernote
return MakerNote::AutoPtr(new Nikon3MakerNote(alloc));
}
} // namespace Exiv2

@ -42,8 +42,6 @@
// *****************************************************************************
// included header files
#include "types.hpp"
#include "makernote.hpp"
#include "tags.hpp"
// + standard includes
@ -55,246 +53,90 @@
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class Value;
// *****************************************************************************
// free functions
/*!
@brief Return an auto-pointer to a newly created empty MakerNote
initialized to operate in the memory management model indicated.
The caller owns this copy and the auto-pointer ensures that it
will be deleted.
@param alloc Memory management model for the new MakerNote. Determines if
memory required to store data should be allocated and deallocated
(true) or not (false). If false, only pointers to the buffer
provided to read() will be kept. See Ifd for more background on
this concept.
@param buf Pointer to the makernote character buffer (not used).
@param len Length of the makernote character buffer (not used).
@param byteOrder Byte order in which the Exif data (and possibly the
makernote) is encoded (not used).
@param offset Offset from the start of the TIFF header of the makernote
buffer (not used).
@return An auto-pointer to a newly created empty MakerNote. The caller
owns this copy and the auto-pointer ensures that it will be
deleted.
*/
MakerNote::AutoPtr createNikonMakerNote(bool alloc,
const byte* buf,
long len,
ByteOrder byteOrder,
long offset);
// *****************************************************************************
// class definitions
//! A MakerNote format used by Nikon cameras, such as the E990 and D1.
class Nikon1MakerNote : public IfdMakerNote {
class Nikon1MakerNote {
public:
//! Shortcut for a %Nikon1MakerNote auto pointer.
typedef std::auto_ptr<Nikon1MakerNote> AutoPtr;
//! @name Creators
//@{
/*!
@brief Constructor. Allows to choose whether or not memory management
is required for the makernote entries.
*/
Nikon1MakerNote(bool alloc =true);
//! Copy constructor
Nikon1MakerNote(const Nikon1MakerNote& rhs);
//! Virtual destructor
virtual ~Nikon1MakerNote() {}
//@}
//! @name Accessors
//@{
AutoPtr create(bool alloc =true) const;
AutoPtr clone() const;
//! Return read-only list of built-in Nikon1 tags
static const TagInfo* tagList();
//@}
//! @name Print functions for Nikon1 %MakerNote tags
//@{
//! Print ISO setting
static std::ostream& print0x0002(std::ostream& os, const Value& value);
static std::ostream& print0x0002(std::ostream& os, const Value& value, const ExifData*);
//! Print autofocus mode
static std::ostream& print0x0007(std::ostream& os, const Value& value);
static std::ostream& print0x0007(std::ostream& os, const Value& value, const ExifData*);
//! Print manual focus distance
static std::ostream& print0x0085(std::ostream& os, const Value& value);
static std::ostream& print0x0085(std::ostream& os, const Value& value, const ExifData*);
//! Print digital zoom setting
static std::ostream& print0x0086(std::ostream& os, const Value& value);
static std::ostream& print0x0086(std::ostream& os, const Value& value, const ExifData*);
//! Print AF focus position
static std::ostream& print0x0088(std::ostream& os, const Value& value);
static std::ostream& print0x0088(std::ostream& os, const Value& value, const ExifData*);
//@}
//! @cond IGNORE
// Public only so that we can create a static instance
struct RegisterMn {
RegisterMn();
};
//! @endcond
private:
//! Internal virtual create function.
Nikon1MakerNote* create_(bool alloc =true) const;
//! Internal virtual copy constructor.
Nikon1MakerNote* clone_() const;
//! Tag information
static const TagInfo tagInfo_[];
}; // class Nikon1MakerNote
static Nikon1MakerNote::RegisterMn registerNikon1MakerNote;
/*!
@brief A second MakerNote format used by Nikon cameras, including the
E700, E800, E900, E900S, E910, E950
*/
class Nikon2MakerNote : public IfdMakerNote {
class Nikon2MakerNote {
public:
//! Shortcut for a %Nikon2MakerNote auto pointer.
typedef std::auto_ptr<Nikon2MakerNote> AutoPtr;
//! @name Creators
//@{
/*!
@brief Constructor. Allows to choose whether or not memory management
is required for the makernote entries.
*/
Nikon2MakerNote(bool alloc =true);
//! Copy constructor
Nikon2MakerNote(const Nikon2MakerNote& rhs);
//! Virtual destructor
virtual ~Nikon2MakerNote() {}
//@}
//! @name Manipulators
//@{
int readHeader(const byte* buf,
long len,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
int checkHeader() const;
AutoPtr create(bool alloc =true) const;
AutoPtr clone() const;
//! Return read-only list of built-in Nikon2 tags
static const TagInfo* tagList();
//@}
//! @name Print functions for Nikon2 %MakerNote tags
//@{
//! Print digital zoom setting
static std::ostream& print0x000a(std::ostream& os, const Value& value);
static std::ostream& print0x000a(std::ostream& os, const Value& value, const ExifData*);
//@}
//! @cond IGNORE
// Public only so that we can create a static instance
struct RegisterMn {
RegisterMn();
};
//! @endcond
private:
//! Internal virtual create function.
Nikon2MakerNote* create_(bool alloc =true) const;
//! Internal virtual copy constructor.
Nikon2MakerNote* clone_() const;
//! Tag information
static const TagInfo tagInfo_[];
}; // class Nikon2MakerNote
static Nikon2MakerNote::RegisterMn registerNikon2MakerNote;
//! A third MakerNote format used by Nikon cameras, e.g., E5400, SQ, D2H, D70
class Nikon3MakerNote : public IfdMakerNote {
class Nikon3MakerNote {
public:
//! Shortcut for a %Nikon3MakerNote auto pointer.
typedef std::auto_ptr<Nikon3MakerNote> AutoPtr;
//! @name Creators
//@{
/*!
@brief Constructor. Allows to choose whether or not memory management
is required for the makernote entries.
*/
Nikon3MakerNote(bool alloc =true);
//! Copy constructor
Nikon3MakerNote(const Nikon3MakerNote& rhs);
//! Virtual destructor
virtual ~Nikon3MakerNote() {}
//@}
//! @name Manipulators
//@{
int readHeader(const byte* buf,
long len,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
int checkHeader() const;
AutoPtr create(bool alloc =true) const;
AutoPtr clone() const;
//! Return read-only list of built-in Nikon3 tags
static const TagInfo* tagList();
//@}
//! @name Print functions for Nikon3 %MakerNote tags
//@{
//! Print ISO setting
static std::ostream& print0x0002(std::ostream& os, const Value& value);
static std::ostream& print0x0002(std::ostream& os, const Value& value, const ExifData*);
//! Print autofocus mode
static std::ostream& print0x0007(std::ostream& os, const Value& value);
static std::ostream& print0x0007(std::ostream& os, const Value& value, const ExifData*);
//! Print lens type
static std::ostream& print0x0083(std::ostream& os, const Value& value);
static std::ostream& print0x0083(std::ostream& os, const Value& value, const ExifData*);
//! Print lens information
static std::ostream& print0x0084(std::ostream& os, const Value& value);
static std::ostream& print0x0084(std::ostream& os, const Value& value, const ExifData*);
//! Print manual focus distance
static std::ostream& print0x0085(std::ostream& os, const Value& value);
static std::ostream& print0x0085(std::ostream& os, const Value& value, const ExifData*);
//! Print digital zoom setting
static std::ostream& print0x0086(std::ostream& os, const Value& value);
static std::ostream& print0x0086(std::ostream& os, const Value& value, const ExifData*);
//! Print AF point
static std::ostream& print0x0088(std::ostream& os, const Value& value);
static std::ostream& print0x0088(std::ostream& os, const Value& value, const ExifData*);
//! Print number of lens stops
static std::ostream& print0x008b(std::ostream& os, const Value& value);
static std::ostream& print0x008b(std::ostream& os, const Value& value, const ExifData*);
//! Print number of lens data
static std::ostream& print0x0098(std::ostream& os, const Value& value);
static std::ostream& print0x0098(std::ostream& os, const Value& value, const ExifData*);
//@}
//! @cond IGNORE
// Public only so that we can create a static instance
struct RegisterMn {
RegisterMn();
};
//! @endcond
private:
//! Internal virtual create function.
Nikon3MakerNote* create_(bool alloc =true) const;
//! Internal virtual copy constructor.
Nikon3MakerNote* clone_() const;
//! Tag information
static const TagInfo tagInfo_[];
}; // class Nikon3MakerNote
static Nikon3MakerNote::RegisterMn registerNikon3MakerNote;
} // namespace Exiv2
#endif // #ifndef NIKONMN_HPP_

@ -36,7 +36,6 @@ EXIV2_RCSID("@(#) $Id$")
// included header files
#include "types.hpp"
#include "olympusmn.hpp"
#include "makernote.hpp"
#include "value.hpp"
#include "i18n.h" // NLS support.
@ -404,76 +403,7 @@ namespace Exiv2 {
return tagInfo_;
}
//! @cond IGNORE
OlympusMakerNote::RegisterMn::RegisterMn()
{
MakerNoteFactory::registerMakerNote("OLYMPUS*", "*", createOlympusMakerNote);
MakerNoteFactory::registerMakerNote(olympusIfdId, MakerNote::AutoPtr(new OlympusMakerNote));
}
//! @endcond
OlympusMakerNote::OlympusMakerNote(bool alloc)
: IfdMakerNote(olympusIfdId, alloc)
{
byte buf[] = {
'O', 'L', 'Y', 'M', 'P', 0x00, 0x01, 0x00
};
readHeader(buf, 8, byteOrder_);
}
OlympusMakerNote::OlympusMakerNote(const OlympusMakerNote& rhs)
: IfdMakerNote(rhs)
{
}
int OlympusMakerNote::readHeader(const byte* buf, long len, ByteOrder /*byteOrder*/)
{
if (len < 8) return 1;
// Copy the header
header_.alloc(8);
std::memcpy(header_.pData_, buf, header_.size_);
// Adjust the offset of the IFD for the prefix
start_ = 8;
return 0;
}
int OlympusMakerNote::checkHeader() const
{
int rc = 0;
// Check the OLYMPUS prefix
if ( header_.size_ < 8
|| std::string(reinterpret_cast<char*>(header_.pData_), 5)
!= std::string("OLYMP", 5)) {
rc = 2;
}
return rc;
}
OlympusMakerNote::AutoPtr OlympusMakerNote::create(bool alloc) const
{
return AutoPtr(create_(alloc));
}
OlympusMakerNote* OlympusMakerNote::create_(bool alloc) const
{
AutoPtr makerNote(new OlympusMakerNote(alloc));
assert(makerNote.get() != 0);
makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
return makerNote.release();
}
OlympusMakerNote::AutoPtr OlympusMakerNote::clone() const
{
return AutoPtr(clone_());
}
OlympusMakerNote* OlympusMakerNote::clone_() const
{
return new OlympusMakerNote(*this);
}
std::ostream& OlympusMakerNote::print0x0200(std::ostream& os, const Value& value)
std::ostream& OlympusMakerNote::print0x0200(std::ostream& os, const Value& value, const ExifData*)
{
if (value.count() != 3 || value.typeId() != unsignedLong) {
return os << value;
@ -504,7 +434,7 @@ namespace Exiv2 {
return os;
} // OlympusMakerNote::print0x0200
std::ostream& OlympusMakerNote::print0x0204(std::ostream& os, const Value& value)
std::ostream& OlympusMakerNote::print0x0204(std::ostream& os, const Value& value, const ExifData*)
{
if ( value.count() == 0
|| value.toRational().second == 0) {
@ -519,7 +449,7 @@ namespace Exiv2 {
return os;
} // OlympusMakerNote::print0x0204
std::ostream& OlympusMakerNote::print0x1015(std::ostream& os, const Value& value)
std::ostream& OlympusMakerNote::print0x1015(std::ostream& os, const Value& value, const ExifData*)
{
if (value.count() != 2 || value.typeId() != unsignedShort) {
return os << value;
@ -561,13 +491,4 @@ namespace Exiv2 {
return os;
} // OlympusMakerNote::print0x1015
// *****************************************************************************
// free functions
MakerNote::AutoPtr createOlympusMakerNote(bool alloc, const byte* /*buf*/, long /*len*/,
ByteOrder /*byteOrder*/, long /*offset*/)
{
return MakerNote::AutoPtr(new OlympusMakerNote(alloc));
}
} // namespace Exiv2

@ -40,7 +40,6 @@
// *****************************************************************************
// included header files
#include "types.hpp"
#include "makernote.hpp"
#include "tags.hpp"
// + standard includes
@ -52,108 +51,31 @@
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class Value;
// *****************************************************************************
// free functions
/*!
@brief Return an auto-pointer to a newly created empty MakerNote
initialized to operate in the memory management model indicated.
The caller owns this copy and the auto-pointer ensures that it
will be deleted.
@param alloc Memory management model for the new MakerNote. Determines if
memory required to store data should be allocated and deallocated
(true) or not (false). If false, only pointers to the buffer
provided to read() will be kept. See Ifd for more background on
this concept.
@param buf Pointer to the makernote character buffer (not used).
@param len Length of the makernote character buffer (not used).
@param byteOrder Byte order in which the Exif data (and possibly the
makernote) is encoded (not used).
@param offset Offset from the start of the TIFF header of the makernote
buffer (not used).
@return An auto-pointer to a newly created empty MakerNote. The caller
owns this copy and the auto-pointer ensures that it will be
deleted.
*/
MakerNote::AutoPtr createOlympusMakerNote(bool alloc,
const byte* buf,
long len,
ByteOrder byteOrder,
long offset);
// *****************************************************************************
// class definitions
//! MakerNote for Olympus cameras
class OlympusMakerNote : public IfdMakerNote {
class OlympusMakerNote {
public:
//! Shortcut for a %OlympusMakerNote auto pointer.
typedef std::auto_ptr<OlympusMakerNote> AutoPtr;
//! @name Creators
//@{
/*!
@brief Constructor. Allows to choose whether or not memory management
is required for the makernote entries.
*/
OlympusMakerNote(bool alloc =true);
//! Copy constructor
OlympusMakerNote(const OlympusMakerNote& rhs);
//! Virtual destructor
virtual ~OlympusMakerNote() {}
//@}
//! @name Manipulators
//@{
int readHeader(const byte* buf,
long len,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
int checkHeader() const;
AutoPtr create(bool alloc =true) const;
AutoPtr clone() const;
//! Return read-only list of built-in Olympus tags
static const TagInfo* tagList();
//@}
//! @name Print functions for Olympus %MakerNote tags
//@{
//! Print 'Special Mode'
static std::ostream& print0x0200(std::ostream& os, const Value& value);
static std::ostream& print0x0200(std::ostream& os, const Value& value, const ExifData*);
//! Print Digital Zoom Factor
static std::ostream& print0x0204(std::ostream& os, const Value& value);
static std::ostream& print0x0204(std::ostream& os, const Value& value, const ExifData*);
//! Print White Balance Mode
static std::ostream& print0x1015(std::ostream& os, const Value& value);
static std::ostream& print0x1015(std::ostream& os, const Value& value, const ExifData*);
//@}
//! @cond IGNORE
// Public only so that we can create a static instance
struct RegisterMn {
RegisterMn();
};
//! @endcond
private:
//! Internal virtual create function.
OlympusMakerNote* create_(bool alloc =true) const;
//! Internal virtual copy constructor.
OlympusMakerNote* clone_() const;
//! Tag information
static const TagInfo tagInfo_[];
}; // class OlympusMakerNote
static OlympusMakerNote::RegisterMn registerOlympusMakerNote;
} // namespace Exiv2
#endif // #ifndef OLYMPUSMN_HPP_

@ -38,7 +38,8 @@ EXIV2_RCSID("@(#) $Id$")
#endif
#include "orfimage.hpp"
#include "tiffparser.hpp"
#include "orfimage_int.hpp"
#include "tiffimage_int.hpp"
#include "image.hpp"
#include "basicio.hpp"
#include "error.hpp"
@ -54,6 +55,8 @@ EXIV2_RCSID("@(#) $Id$")
// class member definitions
namespace Exiv2 {
using namespace Internal;
OrfImage::OrfImage(BasicIo::AutoPtr io, bool /*create*/)
: Image(ImageType::orf, mdExif | mdIptc, io)
{
@ -112,10 +115,12 @@ namespace Exiv2 {
throw Error(3, "ORF");
}
clearMetadata();
OrfHeader orfHeader;
TiffParser::decode(this, io_->mmap(), io_->size(),
TiffCreator::create, TiffDecoder::findDecoder,
&orfHeader);
ByteOrder bo = OrfParser::decode(exifData_,
iptcData_,
xmpData_,
io_->mmap(),
io_->size());
setByteOrder(bo);
} // OrfImage::readMetadata
void OrfImage::writeMetadata()
@ -124,38 +129,47 @@ namespace Exiv2 {
throw(Error(31, "ORF"));
} // OrfImage::writeMetadata
OrfHeader::OrfHeader()
: TiffHeaderBase('O'<< 8 | 'R', 8, littleEndian, 0x00000008)
{
}
OrfHeader::~OrfHeader()
ByteOrder OrfParser::decode(
ExifData& exifData,
IptcData& iptcData,
XmpData& xmpData,
const byte* pData,
uint32_t size
)
{
OrfHeader orfHeader;
return TiffParserWorker::decode(exifData,
iptcData,
xmpData,
pData,
size,
TiffCreator::create,
TiffMapping::findDecoder,
&orfHeader);
}
bool OrfHeader::read(const byte* pData, uint32_t size)
{
if (size < 8) return false;
if (pData[0] == 0x49 && pData[1] == 0x49) {
setByteOrder(littleEndian);
}
else if (pData[0] == 0x4d && pData[1] == 0x4d) {
setByteOrder(bigEndian);
}
else {
return false;
}
if (tag() != getUShort(pData + 2, byteOrder())) return false;
setOffset(getULong(pData + 4, byteOrder()));
if (offset() != 0x00000008) return false;
return true;
} // OrfHeader::read
void OrfHeader::write(Blob& blob) const
WriteMethod OrfParser::encode(
Blob& blob,
const byte* pData,
uint32_t size,
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData
)
{
// Todo: Implement me!
/* Todo: Implement me!
return TiffParserWorker::encode(blob,
pData,
size,
exifData,
iptcData,
xmpData,
TiffCreator::create,
TiffMapping::findEncoder);
*/
blob.clear();
return wmIntrusive;
}
// *************************************************************************
@ -186,3 +200,43 @@ namespace Exiv2 {
}
} // namespace Exiv2
namespace Exiv2 {
namespace Internal {
OrfHeader::OrfHeader()
: TiffHeaderBase('O'<< 8 | 'R', 8, littleEndian, 0x00000008)
{
}
OrfHeader::~OrfHeader()
{
}
bool OrfHeader::read(const byte* pData, uint32_t size)
{
if (size < 8) return false;
if (pData[0] == 0x49 && pData[1] == 0x49) {
setByteOrder(littleEndian);
}
else if (pData[0] == 0x4d && pData[1] == 0x4d) {
setByteOrder(bigEndian);
}
else {
return false;
}
if (tag() != getUShort(pData + 2, byteOrder())) return false;
setOffset(getULong(pData + 4, byteOrder()));
if (offset() != 0x00000008) return false;
return true;
} // OrfHeader::read
uint32_t OrfHeader::write(Blob& blob) const
{
// Todo: Implement me!
return 0;
}
}} // namespace Internal, Exiv2

@ -33,7 +33,7 @@
// included header files
#include "image.hpp"
#include "basicio.hpp"
#include "tiffimage.hpp"
#include "types.hpp"
// + standard includes
#include <string>
@ -120,28 +120,38 @@ namespace Exiv2 {
}; // class OrfImage
/*!
@brief Olympus ORF header structure.
@brief Stateless parser class for data in ORF format. Images use this
class to decode and encode ORF data.
See class TiffParser for details.
*/
class OrfHeader : public TiffHeaderBase {
class OrfParser {
public:
//! @name Creators
//@{
//! Default constructor
OrfHeader();
//! Destructor.
~OrfHeader();
//@}
//! @name Manipulators
//@{
bool read(const byte* pData, uint32_t size);
//@}
//! @name Accessors
//@{
void write(Blob& blob) const;
//@}
}; // class OrfHeader
/*!
@brief Decode metadata from a buffer \em pData of length \em size
with data in ORF format to the provided metadata containers.
See TiffParser::decode().
*/
static ByteOrder decode(
ExifData& exifData,
IptcData& iptcData,
XmpData& xmpData,
const byte* pData,
uint32_t size
);
/*!
@brief Encode metadata from the provided metadata to ORF format.
See TiffParser::encode().
*/
static WriteMethod encode(
Blob& blob,
const byte* pData,
uint32_t size,
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData
);
}; // class OrfParser
// *****************************************************************************
// template, inline and free functions

@ -0,0 +1,72 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*!
@file orfimage_int.hpp
@brief Internal classes to support Olympus RAW image format
@version $Rev$
@author Jeff Costlow
<a href="mailto:costlow@gmail.com">costlow@gmail.com</a>
@date 31-Jul-07, costlow: created
23-Apr-08, ahu: Moved to _int file
*/
#ifndef ORFIMAGE_INT_HPP_
#define ORFIMAGE_INT_HPP_
// *****************************************************************************
// included header files
#include "tiffimage_int.hpp"
#include "types.hpp"
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
namespace Internal {
// *****************************************************************************
// class definitions
/*!
@brief Olympus ORF header structure.
*/
class OrfHeader : public TiffHeaderBase {
public:
//! @name Creators
//@{
//! Default constructor
OrfHeader();
//! Destructor.
~OrfHeader();
//@}
//! @name Manipulators
//@{
bool read(const byte* pData, uint32_t size);
//@}
//! @name Accessors
//@{
uint32_t write(Blob& blob) const;
//@}
}; // class OrfHeader
}} // namespace Internal, Exiv2
#endif // #ifndef ORFIMAGE_INT_HPP_

@ -34,7 +34,6 @@ EXIV2_RCSID("@(#) $Id$")
// included header files
#include "types.hpp"
#include "panasonicmn.hpp"
#include "makernote.hpp"
#include "value.hpp"
#include "i18n.h" // NLS support.
@ -49,15 +48,6 @@ EXIV2_RCSID("@(#) $Id$")
// class member definitions
namespace Exiv2 {
//! @cond IGNORE
PanasonicMakerNote::RegisterMn::RegisterMn()
{
MakerNoteFactory::registerMakerNote("Panasonic", "*", createPanasonicMakerNote);
MakerNoteFactory::registerMakerNote(
panasonicIfdId, MakerNote::AutoPtr(new PanasonicMakerNote));
}
//! @endcond
//! Quality, tag 0x0001
extern const TagDetails panasonicQuality[] = {
{ 2, N_("High") },
@ -284,70 +274,9 @@ namespace Exiv2 {
return tagInfo_;
}
PanasonicMakerNote::PanasonicMakerNote(bool alloc)
: IfdMakerNote(panasonicIfdId, alloc, false)
{
byte buf[] = {
'P', 'a', 'n', 'a', 's', 'o', 'n', 'i', 'c', 0x00, 0x00, 0x00
};
readHeader(buf, 12, byteOrder_);
}
PanasonicMakerNote::PanasonicMakerNote(const PanasonicMakerNote& rhs)
: IfdMakerNote(rhs)
{
}
int PanasonicMakerNote::readHeader(const byte* buf,
long len,
ByteOrder /*byteOrder*/)
{
if (len < 12) return 1;
header_.alloc(12);
std::memcpy(header_.pData_, buf, header_.size_);
// Adjust the offset of the IFD for the prefix
start_ = 12;
return 0;
}
int PanasonicMakerNote::checkHeader() const
{
int rc = 0;
// Check the Panasonic prefix
if ( header_.size_ < 12
|| std::string(reinterpret_cast<char*>(header_.pData_), 9)
!= std::string("Panasonic", 9)) {
rc = 2;
}
return rc;
}
PanasonicMakerNote::AutoPtr PanasonicMakerNote::create(bool alloc) const
{
return AutoPtr(create_(alloc));
}
PanasonicMakerNote* PanasonicMakerNote::create_(bool alloc) const
{
AutoPtr makerNote(new PanasonicMakerNote(alloc));
assert(makerNote.get() != 0);
makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
return makerNote.release();
}
PanasonicMakerNote::AutoPtr PanasonicMakerNote::clone() const
{
return AutoPtr(clone_());
}
PanasonicMakerNote* PanasonicMakerNote::clone_() const
{
return new PanasonicMakerNote(*this);
}
std::ostream& PanasonicMakerNote::print0x000f(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
if (value.count() < 2 || value.typeId() != unsignedByte) {
return os << value;
@ -360,7 +289,8 @@ namespace Exiv2 {
} // PanasonicMakerNote::print0x000f
std::ostream& PanasonicMakerNote::print0x0023(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
std::ostringstream oss;
oss.copyfmt(os);
@ -372,16 +302,4 @@ namespace Exiv2 {
} // PanasonicMakerNote::print0x0023
// *****************************************************************************
// free functions
MakerNote::AutoPtr createPanasonicMakerNote(bool alloc,
const byte* /*buf*/,
long /*len*/,
ByteOrder /*byteOrder*/,
long /*offset*/)
{
return MakerNote::AutoPtr(new PanasonicMakerNote(alloc));
}
} // namespace Exiv2

@ -37,118 +37,39 @@
// *****************************************************************************
// included header files
#include "types.hpp"
#include "makernote.hpp"
#include "tags.hpp"
// + standard includes
#include <string>
#include <iosfwd>
#include <memory>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class Value;
// *****************************************************************************
// free functions
/*!
@brief Return an auto-pointer to a newly created empty MakerNote
initialized to operate in the memory management model indicated.
The caller owns this copy and the auto-pointer ensures that it
will be deleted.
@param alloc Memory management model for the new MakerNote. Determines if
memory required to store data should be allocated and deallocated
(true) or not (false). If false, only pointers to the buffer
provided to read() will be kept. See Ifd for more background on
this concept.
@param buf Pointer to the makernote character buffer (not used).
@param len Length of the makernote character buffer (not used).
@param byteOrder Byte order in which the Exif data (and possibly the
makernote) is encoded (not used).
@param offset Offset from the start of the TIFF header of the makernote
buffer (not used).
@return An auto-pointer to a newly created empty MakerNote. The caller
owns this copy and the auto-pointer ensures that it will be
deleted.
*/
MakerNote::AutoPtr createPanasonicMakerNote(bool alloc,
const byte* buf,
long len,
ByteOrder byteOrder,
long offset);
// *****************************************************************************
// class definitions
//! MakerNote for Panasonic cameras
class PanasonicMakerNote : public IfdMakerNote {
class PanasonicMakerNote {
public:
//! Shortcut for a %PanasonicMakerNote auto pointer.
typedef std::auto_ptr<PanasonicMakerNote> AutoPtr;
//! @name Creators
//@{
/*!
@brief Constructor. Allows to choose whether or not memory management
is required for the makernote entries.
*/
PanasonicMakerNote(bool alloc =true);
//! Copy constructor
PanasonicMakerNote(const PanasonicMakerNote& rhs);
//! Virtual destructor
virtual ~PanasonicMakerNote() {}
//@}
//! @name Manipulators
//@{
int readHeader(const byte* buf,
long len,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
int checkHeader() const;
AutoPtr create(bool alloc =true) const;
AutoPtr clone() const;
//! Return read-only list of built-in Panasonic tags
static const TagInfo* tagList();
//@}
//! @name Print functions for Panasonic %MakerNote tags
//@{
//! Print SpotMode
static std::ostream& print0x000f(std::ostream& os, const Value& value);
static std::ostream& print0x000f(std::ostream& os, const Value& value, const ExifData*);
//! Print WhiteBalanceBias
static std::ostream& print0x0023(std::ostream& os, const Value& value);
static std::ostream& print0x0023(std::ostream& os, const Value& value, const ExifData*);
//@}
//! @cond IGNORE
// Public only so that we can create a static instance
struct RegisterMn {
RegisterMn();
};
//! @endcond
private:
//! Internal virtual create function.
PanasonicMakerNote* create_(bool alloc =true) const;
//! Internal virtual copy constructor.
PanasonicMakerNote* clone_() const;
//! Tag information
static const TagInfo tagInfo_[];
}; // class PanasonicMakerNote
static PanasonicMakerNote::RegisterMn registerPanasonicMakerNote;
} // namespace Exiv2
#endif // #ifndef PANASONICMN_HPP_

@ -36,7 +36,6 @@ EXIV2_RCSID("@(#) $Id$")
// included header files
#include "types.hpp"
#include "pentaxmn.hpp"
#include "makernote.hpp"
#include "value.hpp"
#include "i18n.h" // NLS support.
@ -51,15 +50,6 @@ EXIV2_RCSID("@(#) $Id$")
// class member definitions
namespace Exiv2 {
//! @cond IGNORE
PentaxMakerNote::RegisterMn::RegisterMn()
{
MakerNoteFactory::registerMakerNote("PENTAX*", "*", createPentaxMakerNote);
MakerNoteFactory::registerMakerNote(
pentaxIfdId, MakerNote::AutoPtr(new PentaxMakerNote));
}
//! @endcond
//! ShootingMode, tag 0x0001
extern const TagDetails pentaxShootingMode[] = {
{ 0, N_("Auto") },
@ -650,7 +640,7 @@ namespace Exiv2 {
{ 3, N_("Strong") },
};
std::ostream& PentaxMakerNote::printPentaxVersion(std::ostream& os, const Value& value)
std::ostream& PentaxMakerNote::printPentaxVersion(std::ostream& os, const Value& value, const ExifData*)
{
std::string val = value.toString();
size_t i;
@ -661,7 +651,7 @@ namespace Exiv2 {
return os;
}
std::ostream& PentaxMakerNote::printPentaxResolution(std::ostream& os, const Value& value)
std::ostream& PentaxMakerNote::printPentaxResolution(std::ostream& os, const Value& value, const ExifData*)
{
std::string val = value.toString();
size_t i;
@ -672,7 +662,7 @@ namespace Exiv2 {
return os;
}
std::ostream& PentaxMakerNote::printPentaxDate(std::ostream& os, const Value& value)
std::ostream& PentaxMakerNote::printPentaxDate(std::ostream& os, const Value& value, const ExifData*)
{
/* I choose same format as is used inside EXIF itself */
os << ((value.toLong(0) << 8) + value.toLong(1));
@ -683,7 +673,7 @@ namespace Exiv2 {
return os;
}
std::ostream& PentaxMakerNote::printPentaxTime(std::ostream& os, const Value& value)
std::ostream& PentaxMakerNote::printPentaxTime(std::ostream& os, const Value& value, const ExifData*)
{
os << std::setw(2) << std::setfill('0') << value.toLong(0);
os << ":";
@ -693,20 +683,20 @@ namespace Exiv2 {
return os;
}
std::ostream& PentaxMakerNote::printPentaxExposure(std::ostream& os, const Value& value)
std::ostream& PentaxMakerNote::printPentaxExposure(std::ostream& os, const Value& value, const ExifData*)
{
os << static_cast<float>(value.toLong()) / 100 << " ms";
return os;
}
std::ostream& PentaxMakerNote::printPentaxFValue(std::ostream& os, const Value& value)
std::ostream& PentaxMakerNote::printPentaxFValue(std::ostream& os, const Value& value, const ExifData*)
{
os << "F" << std::setprecision(2)
<< static_cast<float>(value.toLong()) / 10;
return os;
}
std::ostream& PentaxMakerNote::printPentaxFocalLength(std::ostream& os, const Value& value)
std::ostream& PentaxMakerNote::printPentaxFocalLength(std::ostream& os, const Value& value, const ExifData*)
{
os << std::fixed << std::setprecision(1)
<< static_cast<float>(value.toLong()) / 100
@ -714,7 +704,7 @@ namespace Exiv2 {
return os;
}
std::ostream& PentaxMakerNote::printPentaxCompensation(std::ostream& os, const Value& value)
std::ostream& PentaxMakerNote::printPentaxCompensation(std::ostream& os, const Value& value, const ExifData*)
{
os << std::setprecision(2)
<< (static_cast<float>(value.toLong()) - 50) / 10
@ -722,13 +712,13 @@ namespace Exiv2 {
return os;
}
std::ostream& PentaxMakerNote::printPentaxTemperature(std::ostream& os, const Value& value)
std::ostream& PentaxMakerNote::printPentaxTemperature(std::ostream& os, const Value& value, const ExifData*)
{
os << value.toLong() << " C";
return os;
}
std::ostream& PentaxMakerNote::printPentaxFlashCompensation(std::ostream& os, const Value& value)
std::ostream& PentaxMakerNote::printPentaxFlashCompensation(std::ostream& os, const Value& value, const ExifData*)
{
os << std::setprecision(2)
<< static_cast<float>(value.toLong()) / 256
@ -736,7 +726,7 @@ namespace Exiv2 {
return os;
}
std::ostream& PentaxMakerNote::printPentaxBracketing(std::ostream& os, const Value& value)
std::ostream& PentaxMakerNote::printPentaxBracketing(std::ostream& os, const Value& value, const ExifData*)
{
long l0 = value.toLong(0);
@ -1036,77 +1026,4 @@ namespace Exiv2 {
return tagInfo_;
}
PentaxMakerNote::PentaxMakerNote(bool alloc)
: IfdMakerNote(pentaxIfdId, alloc)
{
byte buf[] = {
'A', 'O', 'C', 0x00, 'M', 'M'
};
readHeader(buf, 6, byteOrder_);
}
PentaxMakerNote::PentaxMakerNote(const PentaxMakerNote& rhs)
: IfdMakerNote(rhs)
{
}
int PentaxMakerNote::readHeader(const byte* buf,
long len,
ByteOrder /*byteOrder*/)
{
if (len < 6) return 1;
header_.alloc(6);
std::memcpy(header_.pData_, buf, header_.size_);
start_ = 6;
return 0;
}
int PentaxMakerNote::checkHeader() const
{
int rc = 0;
// Check the AOC prefix
if ( header_.size_ < 6
|| std::string(reinterpret_cast<char*>(header_.pData_), 3)
!= std::string("AOC", 3)) {
rc = 2;
}
return rc;
}
PentaxMakerNote::AutoPtr PentaxMakerNote::create(bool alloc) const
{
return AutoPtr(create_(alloc));
}
PentaxMakerNote* PentaxMakerNote::create_(bool alloc) const
{
AutoPtr makerNote(new PentaxMakerNote(alloc));
assert(makerNote.get() != 0);
makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
return makerNote.release();
}
PentaxMakerNote::AutoPtr PentaxMakerNote::clone() const
{
return AutoPtr(clone_());
}
PentaxMakerNote* PentaxMakerNote::clone_() const
{
return new PentaxMakerNote(*this);
}
// *****************************************************************************
// free functions
MakerNote::AutoPtr createPentaxMakerNote(bool alloc,
const byte* /*buf*/,
long /*len*/,
ByteOrder /*byteOrder*/,
long /*offset*/)
{
return MakerNote::AutoPtr(new PentaxMakerNote(alloc));
}
} // namespace Exiv2

@ -35,7 +35,6 @@
// *****************************************************************************
// included header files
#include "types.hpp"
#include "makernote.hpp"
#include "tags.hpp"
// + standard includes
@ -48,135 +47,57 @@
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class Value;
// *****************************************************************************
// free functions
/*!
@brief Return an auto-pointer to a newly created empty MakerNote
initialized to operate in the memory management model indicated.
The caller owns this copy and the auto-pointer ensures that it
will be deleted.
@param alloc Memory management model for the new MakerNote. Determines if
memory required to store data should be allocated and deallocated
(true) or not (false). If false, only pointers to the buffer
provided to read() will be kept. See Ifd for more background on
this concept.
@param buf Pointer to the makernote character buffer (not used).
@param len Length of the makernote character buffer (not used).
@param byteOrder Byte order in which the Exif data (and possibly the
makernote) is encoded (not used).
@param offset Offset from the start of the TIFF header of the makernote
buffer (not used).
@return An auto-pointer to a newly created empty MakerNote. The caller
owns this copy and the auto-pointer ensures that it will be
deleted.
*/
MakerNote::AutoPtr createPentaxMakerNote(bool alloc,
const byte* buf,
long len,
ByteOrder byteOrder,
long offset);
// *****************************************************************************
// class definitions
//! MakerNote for Pentaxfilm cameras
class PentaxMakerNote : public IfdMakerNote {
class PentaxMakerNote {
public:
//! Shortcut for a %PentaxMakerNote auto pointer.
typedef std::auto_ptr<PentaxMakerNote> AutoPtr;
//! @name Creators
//@{
/*!
@brief Constructor. Allows to choose whether or not memory management
is required for the makernote entries.
*/
PentaxMakerNote(bool alloc =true);
//! Copy constructor
PentaxMakerNote(const PentaxMakerNote& rhs);
//! Virtual destructor
virtual ~PentaxMakerNote() {}
//@}
//! @name Manipulators
//@{
int readHeader(const byte* buf,
long len,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
int checkHeader() const;
AutoPtr create(bool alloc =true) const;
AutoPtr clone() const;
//! Return read-only list of built-in Pentaxfilm tags
static const TagInfo* tagList();
//@}
//! @cond IGNORE
// Public only so that we can create a static instance
struct RegisterMn {
RegisterMn();
};
//! @endcond
//! Print Pentax version
static std::ostream& printPentaxVersion(std::ostream& os, const Value& value);
static std::ostream& printPentaxVersion(std::ostream& os, const Value& value, const ExifData*);
//! Print Pentax resolution
static std::ostream& printPentaxResolution(std::ostream& os, const Value& value);
static std::ostream& printPentaxResolution(std::ostream& os, const Value& value, const ExifData*);
//! Print Pentax date
static std::ostream& printPentaxDate(std::ostream& os, const Value& value);
static std::ostream& printPentaxDate(std::ostream& os, const Value& value, const ExifData*);
//! Print Pentax time
static std::ostream& printPentaxTime(std::ostream& os, const Value& value);
static std::ostream& printPentaxTime(std::ostream& os, const Value& value, const ExifData*);
//! Print Pentax exposure
static std::ostream& printPentaxExposure(std::ostream& os, const Value& value);
static std::ostream& printPentaxExposure(std::ostream& os, const Value& value, const ExifData*);
//! Print Pentax F value
static std::ostream& printPentaxFValue(std::ostream& os, const Value& value);
static std::ostream& printPentaxFValue(std::ostream& os, const Value& value, const ExifData*);
//! Print Pentax focal length
static std::ostream& printPentaxFocalLength(std::ostream& os, const Value& value);
static std::ostream& printPentaxFocalLength(std::ostream& os, const Value& value, const ExifData*);
//! Print Pentax compensation
static std::ostream& printPentaxCompensation(std::ostream& os, const Value& value);
static std::ostream& printPentaxCompensation(std::ostream& os, const Value& value, const ExifData*);
//! Print Pentax temperature
static std::ostream& printPentaxTemperature(std::ostream& os, const Value& value);
static std::ostream& printPentaxTemperature(std::ostream& os, const Value& value, const ExifData*);
//! Print Pentax flash compensation
static std::ostream& printPentaxFlashCompensation(std::ostream& os, const Value& value);
static std::ostream& printPentaxFlashCompensation(std::ostream& os, const Value& value, const ExifData*);
//! Print Pentax bracketing
static std::ostream& printPentaxBracketing(std::ostream& os, const Value& value);
static std::ostream& printPentaxBracketing(std::ostream& os, const Value& value, const ExifData*);
private:
//! Internal virtual create function.
PentaxMakerNote* create_(bool alloc =true) const;
//! Internal virtual copy constructor.
PentaxMakerNote* clone_() const;
//! Tag information
static const TagInfo tagInfo_[];
}; // class PentaxMakerNote
static PentaxMakerNote::RegisterMn registerPentaxMakerNote;
/*!
@brief Print function to translate Pentax "combi-values" to a description
by looking up a reference table.
*/
template <int N, const TagDetails (&array)[N], int count, int ignoredcount>
std::ostream& printCombiTag(std::ostream& os, const Value& value)
std::ostream& printCombiTag(std::ostream& os, const Value& value, const ExifData* metadata)
{
if ((value.count() != count && value.count() != (count + ignoredcount)) || count > 4) {
return printValue(os, value);
return printValue(os, value, metadata);
}
unsigned long l = 0;
for (int c = 0; c < count; ++c) {
if (value.toLong(c) < 0 || value.toLong(c) > 255) {
return printValue(os, value);
return printValue(os, value, metadata);
}
l += (value.toLong(c) << ((count - c - 1) * 8));
}

@ -48,7 +48,7 @@ EXIV2_RCSID("@(#) $Id: pngchunk.cpp 823 2006-06-23 07:35:00Z cgilles $")
#include <zlib.h>
#include "pngchunk.hpp"
#include "tiffparser.hpp"
#include "tiffimage.hpp"
#include "exif.hpp"
#include "iptc.hpp"
#include "image.hpp"
@ -317,8 +317,12 @@ namespace Exiv2 {
std::cerr << "Exiv2::PngChunk::decode: Exif header found at position " << pos << "\n";
#endif
pos = pos + sizeof(exifHeader);
TiffParser::decode(pImage, exifData.pData_ + pos, length - pos,
TiffCreator::create, TiffDecoder::findDecoder);
ByteOrder bo = TiffParser::decode(pImage->exifData(),
pImage->iptcData(),
pImage->xmpData(),
exifData.pData_ + pos,
length - pos);
pImage->setByteOrder(bo);
}
}
}
@ -332,7 +336,7 @@ namespace Exiv2 {
long length = iptcData.size_;
if (length > 0)
pImage->iptcData().load(iptcData.pData_, length);
IptcParser::decode(pImage->iptcData(), iptcData.pData_, length);
}
// We look if an ImageMagick XMP raw profile exist.

@ -817,7 +817,7 @@ namespace Exiv2 {
const XmpPrintInfo* info = find(xmpPrintInfo, key);
if (info) fct = info->printFct_;
}
return fct(os, value);
return fct(os, value, 0);
}
//! @cond IGNORE

@ -256,7 +256,7 @@ namespace Exiv2 {
DataBuf rawIPTC(resourceSize);
io_->read(rawIPTC.pData_, rawIPTC.size_);
if (io_->error() || io_->eof()) throw Error(14);
if (iptcData_.load(rawIPTC.pData_, rawIPTC.size_)) {
if (IptcParser::decode(iptcData_, rawIPTC.pData_, rawIPTC.size_)) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Failed to decode IPTC metadata.\n";
#endif
@ -270,7 +270,9 @@ namespace Exiv2 {
DataBuf rawExif(resourceSize);
io_->read(rawExif.pData_, rawExif.size_);
if (io_->error() || io_->eof()) throw Error(14);
if (exifData_.load(rawExif.pData_, rawExif.size_)) {
ByteOrder bo = ExifParser::decode(exifData_, rawExif.pData_, rawExif.size_);
setByteOrder(bo);
if (rawExif.size_ > 0 && byteOrder() == invalidByteOrder) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Failed to decode Exif metadata.\n";
#endif

@ -38,7 +38,7 @@ EXIV2_RCSID("@(#) $Id$")
#endif
#include "rafimage.hpp"
#include "tiffparser.hpp"
#include "tiffimage.hpp"
#include "image.hpp"
#include "basicio.hpp"
#include "error.hpp"
@ -107,8 +107,12 @@ namespace Exiv2 {
uint32_t const start = getULong(pData + 84, bigEndian) + 12;
if (static_cast<uint32_t>(size) < start) throw Error(14);
clearMetadata();
TiffParser::decode(this, pData + start, size - start,
TiffCreator::create, TiffDecoder::findDecoder);
ByteOrder bo = TiffParser::decode(exifData_,
iptcData_,
xmpData_,
pData + start,
size - start);
setByteOrder(bo);
} // RafImage::readMetadata
void RafImage::writeMetadata()

@ -35,7 +35,6 @@ EXIV2_RCSID("@(#) $Id$")
// included header files
#include "types.hpp"
#include "sigmamn.hpp"
#include "makernote.hpp"
#include "value.hpp"
#include "i18n.h" // NLS support.
@ -50,16 +49,6 @@ EXIV2_RCSID("@(#) $Id$")
// class member definitions
namespace Exiv2 {
//! @cond IGNORE
SigmaMakerNote::RegisterMn::RegisterMn()
{
MakerNoteFactory::registerMakerNote("SIGMA", "*", createSigmaMakerNote);
MakerNoteFactory::registerMakerNote("FOVEON", "*", createSigmaMakerNote);
MakerNoteFactory::registerMakerNote(
sigmaIfdId, MakerNote::AutoPtr(new SigmaMakerNote));
}
//! @endcond
// Sigma (Foveon) MakerNote Tag Info
const TagInfo SigmaMakerNote::tagInfo_[] = {
TagInfo(0x0002, "SerialNumber", N_("Serial Number"),
@ -141,75 +130,9 @@ namespace Exiv2 {
return tagInfo_;
}
SigmaMakerNote::SigmaMakerNote(bool alloc)
: IfdMakerNote(sigmaIfdId, alloc)
{
byte buf[] = {
'S', 'I', 'G', 'M', 'A', '\0', '\0', '\0', 0x01, 0x00
};
readHeader(buf, 10, byteOrder_);
}
SigmaMakerNote::SigmaMakerNote(const SigmaMakerNote& rhs)
: IfdMakerNote(rhs)
{
}
int SigmaMakerNote::readHeader(const byte* buf,
long len,
ByteOrder /*byteOrder*/)
{
if (len < 10) return 1;
// Copy the header. My one and only Sigma sample has two undocumented
// extra bytes (0x01, 0x00) between the ID string and the start of the
// Makernote IFD. So we copy 10 bytes into the header.
header_.alloc(10);
std::memcpy(header_.pData_, buf, header_.size_);
// Adjust the offset of the IFD for the prefix
start_ = 10;
return 0;
}
int SigmaMakerNote::checkHeader() const
{
int rc = 0;
// Check the SIGMA or FOVEON prefix
if ( header_.size_ < 10
|| ( std::string(reinterpret_cast<char*>(header_.pData_), 8)
!= std::string("SIGMA\0\0\0", 8)
&& std::string(reinterpret_cast<char*>(header_.pData_), 8)
!= std::string("FOVEON\0\0", 8))) {
rc = 2;
}
return rc;
}
SigmaMakerNote::AutoPtr SigmaMakerNote::create(bool alloc) const
{
return AutoPtr(create_(alloc));
}
SigmaMakerNote* SigmaMakerNote::create_(bool alloc) const
{
AutoPtr makerNote(new SigmaMakerNote(alloc));
assert(makerNote.get() != 0);
makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
return makerNote.release();
}
SigmaMakerNote::AutoPtr SigmaMakerNote::clone() const
{
return AutoPtr(clone_());
}
SigmaMakerNote* SigmaMakerNote::clone_() const
{
return new SigmaMakerNote(*this);
}
std::ostream& SigmaMakerNote::printStripLabel(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
std::string v = value.toString();
std::string::size_type pos = v.find(':');
@ -221,7 +144,8 @@ namespace Exiv2 {
}
std::ostream& SigmaMakerNote::print0x0008(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
switch (value.toString()[0]) {
case 'P': os << _("Program"); break;
@ -234,7 +158,8 @@ namespace Exiv2 {
}
std::ostream& SigmaMakerNote::print0x0009(std::ostream& os,
const Value& value)
const Value& value,
const ExifData*)
{
switch (value.toString()[0]) {
case 'A': os << _("Average"); break;
@ -245,16 +170,4 @@ namespace Exiv2 {
return os;
}
// *****************************************************************************
// free functions
MakerNote::AutoPtr createSigmaMakerNote(bool alloc,
const byte* /*buf*/,
long /*len*/,
ByteOrder /*byteOrder*/,
long /*offset*/)
{
return MakerNote::AutoPtr(new SigmaMakerNote(alloc));
}
} // namespace Exiv2

@ -34,7 +34,6 @@
// *****************************************************************************
// included header files
#include "types.hpp"
#include "makernote.hpp"
#include "tags.hpp"
// + standard includes
@ -46,108 +45,31 @@
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class Value;
// *****************************************************************************
// free functions
/*!
@brief Return an auto-pointer to a newly created empty MakerNote
initialized to operate in the memory management model indicated.
The caller owns this copy and the auto-pointer ensures that it
will be deleted.
@param alloc Memory management model for the new MakerNote. Determines if
memory required to store data should be allocated and deallocated
(true) or not (false). If false, only pointers to the buffer
provided to read() will be kept. See Ifd for more background on
this concept.
@param buf Pointer to the makernote character buffer (not used).
@param len Length of the makernote character buffer (not used).
@param byteOrder Byte order in which the Exif data (and possibly the
makernote) is encoded (not used).
@param offset Offset from the start of the TIFF header of the makernote
buffer (not used).
@return An auto-pointer to a newly created empty MakerNote. The caller
owns this copy and the auto-pointer ensures that it will be
deleted.
*/
MakerNote::AutoPtr createSigmaMakerNote(bool alloc,
const byte* buf,
long len,
ByteOrder byteOrder,
long offset);
// *****************************************************************************
// class definitions
//! MakerNote for Sigma (Foveon) cameras
class SigmaMakerNote : public IfdMakerNote {
class SigmaMakerNote {
public:
//! Shortcut for a %SigmaMakerNote auto pointer.
typedef std::auto_ptr<SigmaMakerNote> AutoPtr;
//! @name Creators
//@{
/*!
@brief Constructor. Allows to choose whether or not memory management
is required for the makernote entries.
*/
SigmaMakerNote(bool alloc =true);
//! Copy constructor
SigmaMakerNote(const SigmaMakerNote& rhs);
//! Virtual destructor
virtual ~SigmaMakerNote() {}
//@}
//! @name Manipulators
//@{
int readHeader(const byte* buf,
long len,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
int checkHeader() const;
AutoPtr create(bool alloc =true) const;
AutoPtr clone() const;
//! Return read-only list of built-in Sigma tags
static const TagInfo* tagList();
//@}
//! @name Print functions for Sigma (Foveon) %MakerNote tags
//@{
//! Strip the label from the value and print the remainder
static std::ostream& printStripLabel(std::ostream& os, const Value& value);
static std::ostream& printStripLabel(std::ostream& os, const Value& value, const ExifData*);
//! Print exposure mode
static std::ostream& print0x0008(std::ostream& os, const Value& value);
static std::ostream& print0x0008(std::ostream& os, const Value& value, const ExifData*);
//! Print metering mode
static std::ostream& print0x0009(std::ostream& os, const Value& value);
static std::ostream& print0x0009(std::ostream& os, const Value& value, const ExifData*);
//@}
//! @cond IGNORE
// Public only so that we can create a static instance
struct RegisterMn {
RegisterMn();
};
//! @endcond
private:
//! Internal virtual create function.
SigmaMakerNote* create_(bool alloc =true) const;
//! Internal virtual copy constructor.
SigmaMakerNote* clone_() const;
//! Tag information
static const TagInfo tagInfo_[];
}; // class SigmaMakerNote
static SigmaMakerNote::RegisterMn registerSigmaMakerNote;
} // namespace Exiv2
#endif // #ifndef SIGMAMN_HPP_

@ -32,7 +32,6 @@ EXIV2_RCSID("@(#) $Id$")
// included header files
#include "types.hpp"
#include "sonymn.hpp"
#include "makernote.hpp"
#include "value.hpp"
#include "i18n.h" // NLS support.
@ -47,15 +46,6 @@ EXIV2_RCSID("@(#) $Id$")
// class member definitions
namespace Exiv2 {
//! @cond IGNORE
SonyMakerNote::RegisterMn::RegisterMn()
{
MakerNoteFactory::registerMakerNote("SONY", "*", createSonyMakerNote);
MakerNoteFactory::registerMakerNote(
sonyIfdId, MakerNote::AutoPtr(new SonyMakerNote));
}
//! @endcond
// Sony MakerNote Tag Info
const TagInfo SonyMakerNote::tagInfo_[] = {
TagInfo(0x2000, "0x2000", "0x2000",
@ -96,77 +86,4 @@ namespace Exiv2 {
return tagInfo_;
}
SonyMakerNote::SonyMakerNote(bool alloc)
: IfdMakerNote(sonyIfdId, alloc, false)
{
byte buf[] = {
'S', 'O', 'N', 'Y', ' ', 'D', 'S', 'C', ' ', '\0', '\0', '\0'
};
readHeader(buf, 12, byteOrder_);
}
SonyMakerNote::SonyMakerNote(const SonyMakerNote& rhs)
: IfdMakerNote(rhs)
{
}
int SonyMakerNote::readHeader(const byte* buf,
long len,
ByteOrder /*byteOrder*/)
{
if (len < 12) return 1;
header_.alloc(12);
std::memcpy(header_.pData_, buf, header_.size_);
// Adjust the offset of the IFD for the prefix
start_ = 12;
return 0;
}
int SonyMakerNote::checkHeader() const
{
int rc = 0;
// Check the SONY prefix
if ( header_.size_ < 12
|| std::string(reinterpret_cast<char*>(header_.pData_), 12)
!= std::string("SONY DSC \0\0\0", 12)) {
rc = 2;
}
return rc;
}
SonyMakerNote::AutoPtr SonyMakerNote::create(bool alloc) const
{
return AutoPtr(create_(alloc));
}
SonyMakerNote* SonyMakerNote::create_(bool alloc) const
{
AutoPtr makerNote(new SonyMakerNote(alloc));
assert(makerNote.get() != 0);
makerNote->readHeader(header_.pData_, header_.size_, byteOrder_);
return makerNote.release();
}
SonyMakerNote::AutoPtr SonyMakerNote::clone() const
{
return AutoPtr(clone_());
}
SonyMakerNote* SonyMakerNote::clone_() const
{
return new SonyMakerNote(*this);
}
// *****************************************************************************
// free functions
MakerNote::AutoPtr createSonyMakerNote(bool alloc,
const byte* /*buf*/,
long /*len*/,
ByteOrder /*byteOrder*/,
long /*offset*/)
{
return MakerNote::AutoPtr(new SonyMakerNote(alloc));
}
} // namespace Exiv2

@ -32,110 +32,31 @@
// *****************************************************************************
// included header files
#include "types.hpp"
#include "makernote.hpp"
#include "tags.hpp"
// + standard includes
#include <string>
#include <iosfwd>
#include <memory>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class Value;
// *****************************************************************************
// free functions
/*!
@brief Return an auto-pointer to a newly created empty MakerNote
initialized to operate in the memory management model indicated.
The caller owns this copy and the auto-pointer ensures that it
will be deleted.
@param alloc Memory management model for the new MakerNote. Determines if
memory required to store data should be allocated and deallocated
(true) or not (false). If false, only pointers to the buffer
provided to read() will be kept. See Ifd for more background on
this concept.
@param buf Pointer to the makernote character buffer (not used).
@param len Length of the makernote character buffer (not used).
@param byteOrder Byte order in which the Exif data (and possibly the
makernote) is encoded (not used).
@param offset Offset from the start of the TIFF header of the makernote
buffer (not used).
@return An auto-pointer to a newly created empty MakerNote. The caller
owns this copy and the auto-pointer ensures that it will be
deleted.
*/
MakerNote::AutoPtr createSonyMakerNote(bool alloc,
const byte* buf,
long len,
ByteOrder byteOrder,
long offset);
// *****************************************************************************
// class definitions
//! MakerNote for Sony cameras
class SonyMakerNote : public IfdMakerNote {
class SonyMakerNote {
public:
//! Shortcut for a %SonyMakerNote auto pointer.
typedef std::auto_ptr<SonyMakerNote> AutoPtr;
//! @name Creators
//@{
/*!
@brief Constructor. Allows to choose whether or not memory management
is required for the makernote entries.
*/
SonyMakerNote(bool alloc =true);
//! Copy constructor
SonyMakerNote(const SonyMakerNote& rhs);
//! Virtual destructor
virtual ~SonyMakerNote() {}
//@}
//! @name Manipulators
//@{
int readHeader(const byte* buf,
long len,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
int checkHeader() const;
AutoPtr create(bool alloc =true) const;
AutoPtr clone() const;
//! Return read-only list of built-in Sony tags
static const TagInfo* tagList();
//@}
//! @cond IGNORE
// Public only so that we can create a static instance
struct RegisterMn {
RegisterMn();
};
//! @endcond
private:
//! Internal virtual create function.
SonyMakerNote* create_(bool alloc =true) const;
//! Internal virtual copy constructor.
SonyMakerNote* clone_() const;
//! Tag information
static const TagInfo tagInfo_[];
}; // class SonyMakerNote
static SonyMakerNote::RegisterMn registerSonyMakerNote;
} // namespace Exiv2
#endif // #ifndef SONYMN_HPP_

@ -8,7 +8,6 @@
History: 07-Jan-04, ahu: created
*/
// *****************************************************************************
#include "makernote.hpp"
#include "tags.hpp"
#include "datasets.hpp"
#include "properties.hpp"

@ -36,9 +36,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "tags.hpp"
#include "error.hpp"
#include "futils.hpp"
#include "ifd.hpp"
#include "value.hpp"
#include "makernote.hpp"
#include "mn.hpp" // To ensure that all makernotes are registered
#include "i18n.h" // NLS support.
@ -513,9 +511,9 @@ namespace Exiv2 {
TagInfo(0x9c9f, "XPSubject", N_("Windows Subject"),
N_("Subject tag used by Windows, encoded in UCS2"),
ifd0Id, otherTags, unsignedByte, printUcs2), // Windows Tag
TagInfo(0xc4a5, "PrintImageMatching", N_("Print Image Matching"),
N_("Print Image Matching, descriptiont needed."),
ifd0Id, otherTags, undefined, printValue),
TagInfo(0xc4a5, "PrintImageMatching", N_("Print Image Matching"),
N_("Print Image Matching, descriptiont needed."),
ifd0Id, otherTags, undefined, printValue),
// End of list marker
TagInfo(0xffff, "(UnknownIfdTag)", N_("Unknown IFD tag"),
N_("Unknown IFD tag"),
@ -1259,6 +1257,20 @@ namespace Exiv2 {
return rc;
} // ExifTags::isMakerIfd
bool ExifTags::isExifIfd(IfdId ifdId)
{
bool rc;
switch (ifdId) {
case ifd0Id: rc = true; break;
case exifIfdId: rc = true; break;
case gpsIfdId: rc = true; break;
case iopIfdId: rc = true; break;
case ifd1Id: rc = true; break;
default: rc = false; break;
}
return rc;
} // ExifTags::isExifIfd
std::string ExifTags::tagName(uint16_t tag, IfdId ifdId)
{
const TagInfo* ti = tagInfo(tag, ifdId);
@ -1359,13 +1371,14 @@ namespace Exiv2 {
std::ostream& ExifTags::printTag(std::ostream& os,
uint16_t tag,
IfdId ifdId,
const Value& value)
const Value& value,
const ExifData* pExifData)
{
if (value.count() == 0) return os;
PrintFct fct = printValue;
const TagInfo* ti = tagInfo(tag, ifdId);
if (ti != 0) fct = ti->printFct_;
return fct(os, value);
return fct(os, value, pExifData);
} // ExifTags::printTag
void ExifTags::taglist(std::ostream& os)
@ -1408,9 +1421,8 @@ namespace Exiv2 {
idx_(0), key_("")
{
IfdId ifdId = ExifTags::ifdIdByIfdItem(ifdItem);
if (ExifTags::isMakerIfd(ifdId)) {
MakerNote::AutoPtr makerNote = MakerNoteFactory::create(ifdId);
if (makerNote.get() == 0) throw Error(23, ifdId);
if (!ExifTags::isExifIfd(ifdId) && !ExifTags::isMakerIfd(ifdId)) {
throw Error(23, ifdId);
}
tag_ = tag;
ifdId_ = ifdId;
@ -1418,14 +1430,6 @@ namespace Exiv2 {
makeKey();
}
ExifKey::ExifKey(const Entry& e)
: tag_(e.tag()), ifdId_(e.ifdId()),
ifdItem_(ExifTags::ifdItem(e.ifdId())),
idx_(e.idx()), key_("")
{
makeKey();
}
ExifKey::ExifKey(const ExifKey& rhs)
: Key(rhs), tag_(rhs.tag_), ifdId_(rhs.ifdId_), ifdItem_(rhs.ifdItem_),
idx_(rhs.idx_), key_(rhs.key_)
@ -1493,9 +1497,8 @@ namespace Exiv2 {
// Find IfdId
IfdId ifdId = ExifTags::ifdIdByIfdItem(ifdItem);
if (ifdId == ifdIdNotSet) throw Error(6, key_);
if (ExifTags::isMakerIfd(ifdId)) {
MakerNote::AutoPtr makerNote = MakerNoteFactory::create(ifdId);
if (makerNote.get() == 0) throw Error(6, key_);
if (!ExifTags::isExifIfd(ifdId) && !ExifTags::isMakerIfd(ifdId)) {
throw Error(6, key_);
}
// Convert tag
uint16_t tag = ExifTags::tag(tagName, ifdId);
@ -1519,20 +1522,6 @@ namespace Exiv2 {
// *************************************************************************
// free functions
bool isExifIfd(IfdId ifdId)
{
bool rc;
switch (ifdId) {
case ifd0Id: rc = true; break;
case exifIfdId: rc = true; break;
case gpsIfdId: rc = true; break;
case iopIfdId: rc = true; break;
case ifd1Id: rc = true; break;
default: rc = false; break;
}
return rc;
} // isExifIfd
std::ostream& operator<<(std::ostream& os, const TagInfo& ti)
{
ExifKey exifKey(ti.tag_, ExifTags::ifdItem(ti.ifdId_));
@ -1579,26 +1568,26 @@ namespace Exiv2 {
return is;
}
std::ostream& printValue(std::ostream& os, const Value& value)
std::ostream& printValue(std::ostream& os, const Value& value, const ExifData*)
{
return os << value;
}
std::ostream& printLong(std::ostream& os, const Value& value)
std::ostream& printLong(std::ostream& os, const Value& value, const ExifData*)
{
Rational r = value.toRational();
if (r.second != 0) return os << static_cast<long>(r.first) / r.second;
return os << "(" << value << ")";
} // printLong
std::ostream& printFloat(std::ostream& os, const Value& value)
std::ostream& printFloat(std::ostream& os, const Value& value, const ExifData*)
{
Rational r = value.toRational();
if (r.second != 0) return os << static_cast<float>(r.first) / r.second;
return os << "(" << value << ")";
} // printFloat
std::ostream& printDegrees(std::ostream& os, const Value& value)
std::ostream& printDegrees(std::ostream& os, const Value& value, const ExifData*)
{
if (value.count() == 3) {
std::ostringstream oss;
@ -1628,7 +1617,7 @@ namespace Exiv2 {
return os;
} // printDegrees
std::ostream& printUcs2(std::ostream& os, const Value& value)
std::ostream& printUcs2(std::ostream& os, const Value& value, const ExifData*)
{
#if defined EXV_HAVE_ICONV && defined EXV_HAVE_PRINTUCS2
bool go = true;
@ -1686,12 +1675,12 @@ namespace Exiv2 {
} // printUcs2
std::ostream& printExifUnit(std::ostream& os, const Value& value)
std::ostream& printExifUnit(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifUnit)(os, value);
return EXV_PRINT_TAG(exifUnit)(os, value, metadata);
}
std::ostream& print0x0000(std::ostream& os, const Value& value)
std::ostream& print0x0000(std::ostream& os, const Value& value, const ExifData*)
{
if (value.size() != 4 || value.typeId() != unsignedByte) {
return os << value;
@ -1706,12 +1695,12 @@ namespace Exiv2 {
return os;
}
std::ostream& print0x0005(std::ostream& os, const Value& value)
std::ostream& print0x0005(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifGPSAltitudeRef)(os, value);
return EXV_PRINT_TAG(exifGPSAltitudeRef)(os, value, metadata);
}
std::ostream& print0x0006(std::ostream& os, const Value& value)
std::ostream& print0x0006(std::ostream& os, const Value& value, const ExifData*)
{
std::ostringstream oss;
oss.copyfmt(os);
@ -1724,7 +1713,7 @@ namespace Exiv2 {
return os;
}
std::ostream& print0x0007(std::ostream& os, const Value& value)
std::ostream& print0x0007(std::ostream& os, const Value& value, const ExifData*)
{
if (value.count() == 3) {
for (int i = 0; i < 3; ++i) {
@ -1758,42 +1747,42 @@ namespace Exiv2 {
return os;
}
std::ostream& print0x0009(std::ostream& os, const Value& value)
std::ostream& print0x0009(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifGPSStatus)(os, value);
return EXV_PRINT_TAG(exifGPSStatus)(os, value, metadata);
}
std::ostream& print0x000a(std::ostream& os, const Value& value)
std::ostream& print0x000a(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifGPSMeasureMode)(os, value);
return EXV_PRINT_TAG(exifGPSMeasureMode)(os, value, metadata);
}
std::ostream& print0x000c(std::ostream& os, const Value& value)
std::ostream& print0x000c(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifGPSSpeedRef)(os, value);
return EXV_PRINT_TAG(exifGPSSpeedRef)(os, value, metadata);
}
std::ostream& print0x0019(std::ostream& os, const Value& value)
std::ostream& print0x0019(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifGPSDestDistanceRef)(os, value);
return EXV_PRINT_TAG(exifGPSDestDistanceRef)(os, value, metadata);
}
std::ostream& print0x001e(std::ostream& os, const Value& value)
std::ostream& print0x001e(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifGPSDifferential)(os, value);
return EXV_PRINT_TAG(exifGPSDifferential)(os, value, metadata);
}
std::ostream& print0x0112(std::ostream& os, const Value& value)
std::ostream& print0x0112(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifOrientation)(os, value);
return EXV_PRINT_TAG(exifOrientation)(os, value, metadata);
}
std::ostream& print0x0213(std::ostream& os, const Value& value)
std::ostream& print0x0213(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifYCbCrPositioning)(os, value);
return EXV_PRINT_TAG(exifYCbCrPositioning)(os, value, metadata);
}
std::ostream& print0x8298(std::ostream& os, const Value& value)
std::ostream& print0x8298(std::ostream& os, const Value& value, const ExifData*)
{
// Print the copyright information in the format Photographer, Editor
std::string val = value.toString();
@ -1813,7 +1802,7 @@ namespace Exiv2 {
return os;
}
std::ostream& print0x829a(std::ostream& os, const Value& value)
std::ostream& print0x829a(std::ostream& os, const Value& value, const ExifData*)
{
Rational t = value.toRational();
if (t.first > 1 && t.second > 1 && t.second >= t.first) {
@ -1835,7 +1824,7 @@ namespace Exiv2 {
return os;
}
std::ostream& print0x829d(std::ostream& os, const Value& value)
std::ostream& print0x829d(std::ostream& os, const Value& value, const ExifData*)
{
Rational fnumber = value.toRational();
if (fnumber.second != 0) {
@ -1851,17 +1840,17 @@ namespace Exiv2 {
return os;
}
std::ostream& print0x8822(std::ostream& os, const Value& value)
std::ostream& print0x8822(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifExposureProgram)(os, value);
return EXV_PRINT_TAG(exifExposureProgram)(os, value, metadata);
}
std::ostream& print0x8827(std::ostream& os, const Value& value)
std::ostream& print0x8827(std::ostream& os, const Value& value, const ExifData*)
{
return os << value.toLong();
}
std::ostream& print0x9101(std::ostream& os, const Value& value)
std::ostream& print0x9101(std::ostream& os, const Value& value, const ExifData*)
{
for (long i = 0; i < value.count(); ++i) {
long l = value.toLong(i);
@ -1879,7 +1868,7 @@ namespace Exiv2 {
return os;
}
std::ostream& print0x9201(std::ostream& os, const Value& value)
std::ostream& print0x9201(std::ostream& os, const Value& value, const ExifData*)
{
Rational r = value.toRational();
if (!value.ok() || r.second == 0) return os << "(" << value << ")";
@ -1892,7 +1881,7 @@ namespace Exiv2 {
return os << " s";
}
std::ostream& print0x9202(std::ostream& os, const Value& value)
std::ostream& print0x9202(std::ostream& os, const Value& value, const ExifData*)
{
if ( value.count() == 0
|| value.toRational().second == 0) {
@ -1905,7 +1894,7 @@ namespace Exiv2 {
return os;
}
std::ostream& print0x9204(std::ostream& os, const Value& value)
std::ostream& print0x9204(std::ostream& os, const Value& value, const ExifData*)
{
Rational bias = value.toRational();
if (bias.second <= 0) {
@ -1926,7 +1915,7 @@ namespace Exiv2 {
return os;
}
std::ostream& print0x9206(std::ostream& os, const Value& value)
std::ostream& print0x9206(std::ostream& os, const Value& value, const ExifData*)
{
Rational distance = value.toRational();
if (distance.first == 0) {
@ -1949,17 +1938,17 @@ namespace Exiv2 {
return os;
}
std::ostream& print0x9207(std::ostream& os, const Value& value)
std::ostream& print0x9207(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifMeteringMode)(os, value);
return EXV_PRINT_TAG(exifMeteringMode)(os, value, metadata);
}
std::ostream& print0x9208(std::ostream& os, const Value& value)
std::ostream& print0x9208(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifLightSource)(os, value);
return EXV_PRINT_TAG(exifLightSource)(os, value, metadata);
}
std::ostream& print0x920a(std::ostream& os, const Value& value)
std::ostream& print0x920a(std::ostream& os, const Value& value, const ExifData*)
{
Rational length = value.toRational();
if (length.second != 0) {
@ -1977,7 +1966,7 @@ namespace Exiv2 {
}
// Todo: Implement this properly
std::ostream& print0x9286(std::ostream& os, const Value& value)
std::ostream& print0x9286(std::ostream& os, const Value& value, const ExifData*)
{
if (value.size() > 8) {
DataBuf buf(value.size());
@ -1991,42 +1980,42 @@ namespace Exiv2 {
return os;
}
std::ostream& print0xa001(std::ostream& os, const Value& value)
std::ostream& print0xa001(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifColorSpace)(os, value);
return EXV_PRINT_TAG(exifColorSpace)(os, value, metadata);
}
std::ostream& print0xa217(std::ostream& os, const Value& value)
std::ostream& print0xa217(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifSensingMethod)(os, value);
return EXV_PRINT_TAG(exifSensingMethod)(os, value, metadata);
}
std::ostream& print0xa300(std::ostream& os, const Value& value)
std::ostream& print0xa300(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifFileSource)(os, value);
return EXV_PRINT_TAG(exifFileSource)(os, value, metadata);
}
std::ostream& print0xa301(std::ostream& os, const Value& value)
std::ostream& print0xa301(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifSceneType)(os, value);
return EXV_PRINT_TAG(exifSceneType)(os, value, metadata);
}
std::ostream& print0xa401(std::ostream& os, const Value& value)
std::ostream& print0xa401(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifCustomRendered)(os, value);
return EXV_PRINT_TAG(exifCustomRendered)(os, value, metadata);
}
std::ostream& print0xa402(std::ostream& os, const Value& value)
std::ostream& print0xa402(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifExposureMode)(os, value);
return EXV_PRINT_TAG(exifExposureMode)(os, value, metadata);
}
std::ostream& print0xa403(std::ostream& os, const Value& value)
std::ostream& print0xa403(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifWhiteBalance)(os, value);
return EXV_PRINT_TAG(exifWhiteBalance)(os, value, metadata);
}
std::ostream& print0xa404(std::ostream& os, const Value& value)
std::ostream& print0xa404(std::ostream& os, const Value& value, const ExifData*)
{
Rational zoom = value.toRational();
if (zoom.second == 0) {
@ -2042,7 +2031,7 @@ namespace Exiv2 {
return os;
}
std::ostream& print0xa405(std::ostream& os, const Value& value)
std::ostream& print0xa405(std::ostream& os, const Value& value, const ExifData*)
{
long length = value.toLong();
if (length == 0) {
@ -2054,37 +2043,37 @@ namespace Exiv2 {
return os;
}
std::ostream& print0xa406(std::ostream& os, const Value& value)
std::ostream& print0xa406(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifSceneCaptureType)(os, value);
return EXV_PRINT_TAG(exifSceneCaptureType)(os, value, metadata);
}
std::ostream& print0xa407(std::ostream& os, const Value& value)
std::ostream& print0xa407(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifGainControl)(os, value);
return EXV_PRINT_TAG(exifGainControl)(os, value, metadata);
}
std::ostream& print0xa409(std::ostream& os, const Value& value)
std::ostream& print0xa409(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifSaturation)(os, value);
return EXV_PRINT_TAG(exifSaturation)(os, value, metadata);
}
std::ostream& print0xa40c(std::ostream& os, const Value& value)
std::ostream& print0xa40c(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifSubjectDistanceRange)(os, value);
return EXV_PRINT_TAG(exifSubjectDistanceRange)(os, value, metadata);
}
std::ostream& printGPSDirRef(std::ostream& os, const Value& value)
std::ostream& printGPSDirRef(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifGPSDirRef)(os, value);
return EXV_PRINT_TAG(exifGPSDirRef)(os, value, metadata);
}
std::ostream& printNormalSoftHard(std::ostream& os, const Value& value)
std::ostream& printNormalSoftHard(std::ostream& os, const Value& value, const ExifData* metadata)
{
return EXV_PRINT_TAG(exifNormalSoftHard)(os, value);
return EXV_PRINT_TAG(exifNormalSoftHard)(os, value, metadata);
}
std::ostream& printExifVersion(std::ostream& os, const Value& value)
std::ostream& printExifVersion(std::ostream& os, const Value& value, const ExifData*)
{
if (value.size() != 4 || value.typeId() != undefined) {
return os << "(" << value << ")";
@ -2099,7 +2088,7 @@ namespace Exiv2 {
return printVersion(os, s);
}
std::ostream& printXmpVersion(std::ostream& os, const Value& value)
std::ostream& printXmpVersion(std::ostream& os, const Value& value, const ExifData*)
{
if (value.size() != 4 || value.typeId() != xmpText) {
return os << "(" << value << ")";
@ -2108,7 +2097,7 @@ namespace Exiv2 {
return printVersion(os, value.toString());
}
std::ostream& printXmpDate(std::ostream& os, const Value& value)
std::ostream& printXmpDate(std::ostream& os, const Value& value, const ExifData*)
{
if (!(value.size() == 19 || value.size() == 20) || value.typeId() != xmpText) {
return os << value;

@ -48,15 +48,15 @@ namespace Exiv2 {
// *****************************************************************************
// class declarations
class ExifData;
class Value;
class Entry;
struct TagInfo;
// *****************************************************************************
// type definitions
//! Type for a function pointer for functions interpreting the tag value
typedef std::ostream& (*PrintFct)(std::ostream&, const Value&);
typedef std::ostream& (*PrintFct)(std::ostream&, const Value&, const ExifData* pExifData);
//! A function returning a tag list.
typedef const TagInfo* (*TagListFct)();
/*!
@ -146,7 +146,7 @@ namespace Exiv2 {
by looking up a reference table.
*/
template <int N, const TagDetails (&array)[N]>
std::ostream& printTag(std::ostream& os, const Value& value)
std::ostream& printTag(std::ostream& os, const Value& value, const ExifData*)
{
const TagDetails* td = find(array, value.toLong());
if (td) {
@ -166,7 +166,7 @@ namespace Exiv2 {
by looking up bitmasks in a reference table.
*/
template <int N, const TagDetailsBitmask (&array)[N]>
std::ostream& printTagBitmask(std::ostream& os, const Value& value)
std::ostream& printTagBitmask(std::ostream& os, const Value& value, const ExifData*)
{
const uint32_t val = static_cast<uint32_t>(value.toLong());
bool sep = false;
@ -279,7 +279,8 @@ namespace Exiv2 {
static std::ostream& printTag(std::ostream& os,
uint16_t tag,
IfdId ifdId,
const Value& value);
const Value& value,
const ExifData* pExifData =0);
//! Return read-only list of built-in IFD0/1 tags
static const TagInfo* ifdTagList();
//! Return read-only list of built-in Exif IFD tags
@ -298,6 +299,13 @@ namespace Exiv2 {
makerIfd returns false.
*/
static bool isMakerIfd(IfdId ifdId);
/*!
@brief Return true if \em ifdId is an Exif %Ifd Id, i.e., one of
ifd0Id, exifIfdId, gpsIfdId, iopIfdId or ifd1Id, else false.
This is used to differentiate between standard Exif %Ifds
and %Ifds associated with the makernote.
*/
static bool isExifIfd(IfdId ifdId);
private:
static const TagInfo* tagList(IfdId ifdId);
@ -338,8 +346,6 @@ namespace Exiv2 {
item parameters.
*/
ExifKey(uint16_t tag, const std::string& ifdItem);
//! Constructor to build an ExifKey from an IFD entry.
explicit ExifKey(const Entry& e);
//! Copy constructor
ExifKey(const ExifKey& rhs);
virtual ~ExifKey();
@ -414,117 +420,109 @@ namespace Exiv2 {
// *****************************************************************************
// free functions
/*!
@brief Return true if \em ifdId is an Exif %Ifd Id, i.e., one of
ifd0Id, exifIfdId, gpsIfdId, iopIfdId or ifd1Id, else false.
This is used to differentiate between standard Exif %Ifds
and %Ifds associated with the makernote.
*/
bool isExifIfd(IfdId ifdId);
//! Output operator for TagInfo
std::ostream& operator<<(std::ostream& os, const TagInfo& ti);
//! @name Functions printing interpreted tag values
//@{
//! Default print function, using the Value output operator
std::ostream& printValue(std::ostream& os, const Value& value);
std::ostream& printValue(std::ostream& os, const Value& value, const ExifData*);
//! Print the value converted to a long
std::ostream& printLong(std::ostream& os, const Value& value);
std::ostream& printLong(std::ostream& os, const Value& value, const ExifData*);
//! Print a Rational or URational value in floating point format
std::ostream& printFloat(std::ostream& os, const Value& value);
std::ostream& printFloat(std::ostream& os, const Value& value, const ExifData*);
//! Print a longitude or latitude value
std::ostream& printDegrees(std::ostream& os, const Value& value);
std::ostream& printDegrees(std::ostream& os, const Value& value, const ExifData*);
//! Print function converting from UCS-2LE to UTF-8
std::ostream& printUcs2(std::ostream& os, const Value& value);
std::ostream& printUcs2(std::ostream& os, const Value& value, const ExifData*);
//! Print function for Exif units
std::ostream& printExifUnit(std::ostream& os, const Value& value);
std::ostream& printExifUnit(std::ostream& os, const Value& value, const ExifData*);
//! Print GPS version
std::ostream& print0x0000(std::ostream& os, const Value& value);
std::ostream& print0x0000(std::ostream& os, const Value& value, const ExifData*);
//! Print GPS altitude ref
std::ostream& print0x0005(std::ostream& os, const Value& value);
std::ostream& print0x0005(std::ostream& os, const Value& value, const ExifData*);
//! Print GPS altitude
std::ostream& print0x0006(std::ostream& os, const Value& value);
std::ostream& print0x0006(std::ostream& os, const Value& value, const ExifData*);
//! Print GPS timestamp
std::ostream& print0x0007(std::ostream& os, const Value& value);
std::ostream& print0x0007(std::ostream& os, const Value& value, const ExifData*);
//! Print GPS status
std::ostream& print0x0009(std::ostream& os, const Value& value);
std::ostream& print0x0009(std::ostream& os, const Value& value, const ExifData*);
//! Print GPS measurement mode
std::ostream& print0x000a(std::ostream& os, const Value& value);
std::ostream& print0x000a(std::ostream& os, const Value& value, const ExifData*);
//! Print GPS speed ref
std::ostream& print0x000c(std::ostream& os, const Value& value);
std::ostream& print0x000c(std::ostream& os, const Value& value, const ExifData*);
//! Print GPS destination distance ref
std::ostream& print0x0019(std::ostream& os, const Value& value);
std::ostream& print0x0019(std::ostream& os, const Value& value, const ExifData*);
//! Print GPS differential correction
std::ostream& print0x001e(std::ostream& os, const Value& value);
std::ostream& print0x001e(std::ostream& os, const Value& value, const ExifData*);
//! Print orientation
std::ostream& print0x0112(std::ostream& os, const Value& value);
std::ostream& print0x0112(std::ostream& os, const Value& value, const ExifData*);
//! Print YCbCrPositioning
std::ostream& print0x0213(std::ostream& os, const Value& value);
std::ostream& print0x0213(std::ostream& os, const Value& value, const ExifData*);
//! Print the copyright
std::ostream& print0x8298(std::ostream& os, const Value& value);
std::ostream& print0x8298(std::ostream& os, const Value& value, const ExifData*);
//! Print the exposure time
std::ostream& print0x829a(std::ostream& os, const Value& value);
std::ostream& print0x829a(std::ostream& os, const Value& value, const ExifData*);
//! Print the f-number
std::ostream& print0x829d(std::ostream& os, const Value& value);
std::ostream& print0x829d(std::ostream& os, const Value& value, const ExifData*);
//! Print exposure program
std::ostream& print0x8822(std::ostream& os, const Value& value);
std::ostream& print0x8822(std::ostream& os, const Value& value, const ExifData*);
//! Print ISO speed ratings
std::ostream& print0x8827(std::ostream& os, const Value& value);
std::ostream& print0x8827(std::ostream& os, const Value& value, const ExifData*);
//! Print components configuration specific to compressed data
std::ostream& print0x9101(std::ostream& os, const Value& value);
std::ostream& print0x9101(std::ostream& os, const Value& value, const ExifData*);
//! Print exposure time converted from APEX shutter speed value
std::ostream& print0x9201(std::ostream& os, const Value& value);
std::ostream& print0x9201(std::ostream& os, const Value& value, const ExifData*);
//! Print f-number converted from APEX aperture value
std::ostream& print0x9202(std::ostream& os, const Value& value);
std::ostream& print0x9202(std::ostream& os, const Value& value, const ExifData*);
//! Print the exposure bias value
std::ostream& print0x9204(std::ostream& os, const Value& value);
std::ostream& print0x9204(std::ostream& os, const Value& value, const ExifData*);
//! Print the subject distance
std::ostream& print0x9206(std::ostream& os, const Value& value);
std::ostream& print0x9206(std::ostream& os, const Value& value, const ExifData*);
//! Print metering mode
std::ostream& print0x9207(std::ostream& os, const Value& value);
std::ostream& print0x9207(std::ostream& os, const Value& value, const ExifData*);
//! Print light source
std::ostream& print0x9208(std::ostream& os, const Value& value);
std::ostream& print0x9208(std::ostream& os, const Value& value, const ExifData*);
//! Print the actual focal length of the lens
std::ostream& print0x920a(std::ostream& os, const Value& value);
std::ostream& print0x920a(std::ostream& os, const Value& value, const ExifData*);
//! Print the user comment
std::ostream& print0x9286(std::ostream& os, const Value& value);
std::ostream& print0x9286(std::ostream& os, const Value& value, const ExifData*);
//! Print color space
std::ostream& print0xa001(std::ostream& os, const Value& value);
std::ostream& print0xa001(std::ostream& os, const Value& value, const ExifData*);
//! Print sensing method
std::ostream& print0xa217(std::ostream& os, const Value& value);
std::ostream& print0xa217(std::ostream& os, const Value& value, const ExifData*);
//! Print file source
std::ostream& print0xa300(std::ostream& os, const Value& value);
std::ostream& print0xa300(std::ostream& os, const Value& value, const ExifData*);
//! Print scene type
std::ostream& print0xa301(std::ostream& os, const Value& value);
std::ostream& print0xa301(std::ostream& os, const Value& value, const ExifData*);
//! Print custom rendered
std::ostream& print0xa401(std::ostream& os, const Value& value);
std::ostream& print0xa401(std::ostream& os, const Value& value, const ExifData*);
//! Print exposure mode
std::ostream& print0xa402(std::ostream& os, const Value& value);
std::ostream& print0xa402(std::ostream& os, const Value& value, const ExifData*);
//! Print white balance
std::ostream& print0xa403(std::ostream& os, const Value& value);
std::ostream& print0xa403(std::ostream& os, const Value& value, const ExifData*);
//! Print digital zoom ratio
std::ostream& print0xa404(std::ostream& os, const Value& value);
std::ostream& print0xa404(std::ostream& os, const Value& value, const ExifData*);
//! Print 35mm equivalent focal length
std::ostream& print0xa405(std::ostream& os, const Value& value);
std::ostream& print0xa405(std::ostream& os, const Value& value, const ExifData*);
//! Print scene capture type
std::ostream& print0xa406(std::ostream& os, const Value& value);
std::ostream& print0xa406(std::ostream& os, const Value& value, const ExifData*);
//! Print gain control
std::ostream& print0xa407(std::ostream& os, const Value& value);
std::ostream& print0xa407(std::ostream& os, const Value& value, const ExifData*);
//! Print saturation
std::ostream& print0xa409(std::ostream& os, const Value& value);
std::ostream& print0xa409(std::ostream& os, const Value& value, const ExifData*);
//! Print subject distance range
std::ostream& print0xa40c(std::ostream& os, const Value& value);
std::ostream& print0xa40c(std::ostream& os, const Value& value, const ExifData*);
//! Print GPS direction ref
std::ostream& printGPSDirRef(std::ostream& os, const Value& value);
std::ostream& printGPSDirRef(std::ostream& os, const Value& value, const ExifData*);
//! Print contrast, sharpness (normal, soft, hard)
std::ostream& printNormalSoftHard(std::ostream& os, const Value& value);
std::ostream& printNormalSoftHard(std::ostream& os, const Value& value, const ExifData*);
//! Print any version packed in 4 Bytes format : major major minor minor
std::ostream& printExifVersion(std::ostream& os, const Value& value);
std::ostream& printExifVersion(std::ostream& os, const Value& value, const ExifData*);
//! Print any version encoded in the ASCII string majormajorminorminor
std::ostream& printXmpVersion(std::ostream& os, const Value& value);
std::ostream& printXmpVersion(std::ostream& os, const Value& value, const ExifData*);
//! Print a date following the format YYYY-MM-DDTHH:MM:SSZ
std::ostream& printXmpDate(std::ostream& os, const Value& value);
std::ostream& printXmpDate(std::ostream& os, const Value& value, const ExifData*);
//@}
//! Calculate F number from an APEX aperture value

@ -0,0 +1,76 @@
// ***************************************************************** -*- C++ -*-
// tiff-test.cpp, $Rev$
// TIFF writer tests.
#include "tiffimage.hpp"
#include "exif.hpp"
#include "error.hpp"
#include <iostream>
#include <iomanip>
/*
Tests:
+ All types of components
+ Makernotes
+ Data entries, thumbnails
+ Special use-cases
+ IFD1
+ Multiple sub-IFDs
+ Comment
+ Other/unknown TIFF types
*/
using namespace Exiv2;
void print(const ExifData& exifData);
int main()
try {
BasicIo::AutoPtr io(new FileIo("image.tif"));
TiffImage tiffImage(io, false);
ExifData& exifData = tiffImage.exifData();
exifData["Exif.Image.ImageWidth"] = uint32_t(42);
exifData["Exif.Image.ImageLength"] = 24;
exifData["Exif.Image.Model"] = "Model";
exifData["Exif.Image.Make"] = "FujiFilm";
exifData["Exif.Photo.0x0001"] = "Just for fun";
exifData["Exif.Iop.RelatedImageFileFormat"] = "TIFF";
exifData["Exif.Photo.InteroperabilityTag"] = uint32_t(132); // for non-intrusive writing
exifData["Exif.Image.ExifTag"] = uint32_t(89); // for non-intrusive writingti
exifData.setJpegThumbnail("exiv2-empty.jpg");
// The setJpegThumbnail method sets this to 0.
//exifData["Exif.Thumbnail.JPEGInterchangeFormat"] = uint32_t(197);
print(exifData);
tiffImage.writeMetadata();
return 0;
}
catch (const Error& e) {
std::cerr << e << "\n";
return 1;
}
void print(const ExifData& exifData)
{
if (exifData.empty()) {
std::string error("No Exif data found in the file");
throw Exiv2::Error(1, error);
}
Exiv2::ExifData::const_iterator end = exifData.end();
for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i) {
std::cout << std::setw(44) << std::setfill(' ') << std::left
<< i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right
<< std::hex << i->tag() << " "
<< std::setw(9) << std::setfill(' ') << std::left
<< i->typeName() << " "
<< std::dec << std::setw(3)
<< std::setfill(' ') << std::right
<< i->count() << " "
<< std::dec << i->value()
<< "\n";
}
}

File diff suppressed because it is too large Load Diff

@ -1,641 +0,0 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*!
@file tiffcomposite.hpp
@brief Various classes used in a TIFF composite structure
@version $Rev$
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 11-Apr-06, ahu: created
*/
#ifndef TIFFCOMPOSITE_HPP_
#define TIFFCOMPOSITE_HPP_
// *****************************************************************************
// included header files
#include "image.hpp" // for Blob
#include "tifffwd.hpp"
#include "types.hpp"
// + standard includes
#include <iosfwd>
#include <vector>
#include <string>
#include <cassert>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
Known TIFF groups
Todo: what exactly are these and where should they go?
Are they going to be mapped to the second part of an Exif key or are they
the second part of the key?
*/
namespace Group {
const uint16_t none = 0; //!< Dummy group
const uint16_t ifd0 = 1; //!< Exif IFD0
const uint16_t ifd1 = 2; //!< Thumbnail IFD
const uint16_t exif = 3; //!< Exif IFD
const uint16_t gps = 4; //!< GPS IFD
const uint16_t iop = 5; //!< Interoperability IFD
const uint16_t sub0_0 = 6; //!< Tiff SubIFD 0 in IFD0
const uint16_t sub0_1 = 7; //!< Tiff SubIFD 1 in IFD0
const uint16_t sub0_2 = 8; //!< Tiff SubIFD 2 in IFD0
const uint16_t sub0_3 = 9; //!< Tiff SubIFD 3 in IFD0
const uint16_t mn = 256; //!< Makernote
const uint16_t ignr = 511; //!< Read but do not decode
}
/*!
Special TIFF tags for the use in TIFF structures only
Todo: Same Q as above...
*/
namespace Tag {
const uint32_t none = 0x10000; //!< Dummy tag
const uint32_t root = 0x20000; //!< Special tag: root IFD
const uint32_t next = 0x30000; //!< Special tag: next IFD
const uint32_t all = 0x40000; //!< Special tag: all tags in a group
}
/*!
@brief Interface class for components of a TIFF directory hierarchy
(Composite pattern). Both TIFF directories as well as entries
implement this interface. A component can be uniquely identified
by a tag, group tupel. This class is implemented as a NVI
(Non-Virtual Interface) and it has an interface for visitors
(Visitor pattern).
*/
class TiffComponent {
public:
//! TiffComponent auto_ptr type
typedef std::auto_ptr<TiffComponent> AutoPtr;
//! Container type to hold all metadata
typedef std::vector<TiffComponent*> Components;
//! @name Creators
//@{
//! Constructor
TiffComponent(uint16_t tag, uint16_t group)
: tag_(tag), group_(group), pData_(0) {}
//! Virtual destructor.
virtual ~TiffComponent() {}
//@}
//! @name Manipulators
//@{
//! Add a child to the component. Default is to do nothing.
void addChild(AutoPtr tiffComponent);
//! Add a "next" component to the component. Default is to do nothing.
void addNext(AutoPtr tiffComponent);
/*!
@brief Interface to accept visitors (Visitor pattern).
@param visitor The visitor.
*/
void accept(TiffVisitor& visitor);
/*!
@brief Set a pointer to the start of the binary representation of the
component in a memory buffer. The buffer must be allocated and
freed outside of this class.
*/
void setStart(const byte* pData) { pData_ = const_cast<byte*>(pData); }
//@}
//! @name Accessors
//@{
//! Return the tag of this entry.
uint16_t tag() const { return tag_; }
//! Return the group id of this component
uint16_t group() const { return group_; }
//! Return the group name of this component
std::string groupName() const;
//! Return a pointer to the start of the binary representation of the component
const byte* start() const { return pData_; }
protected:
//! @name Manipulators
//@{
//! Implements addChild(). The default implementation does nothing.
virtual void doAddChild(AutoPtr /*tiffComponent*/) {}
//! Implements addNext(). The default implementation does nothing.
virtual void doAddNext(AutoPtr /*tiffComponent*/) {}
//! Implements accept()
virtual void doAccept(TiffVisitor& visitor) =0;
//@}
private:
// DATA
uint16_t tag_; //!< Tag that identifies the component
uint16_t group_; //!< Group id for this component
/*!
Pointer to the start of the binary representation of the component in
a memory buffer. The buffer is allocated and freed outside of this class.
*/
byte* pData_;
}; // class TiffComponent
/*!
@brief Data structure used as a row (element) of a table (array)
describing the TIFF structure of an image format for reading and
writing. Different tables can be used to support different TIFF
based image formats.
*/
struct TiffStructure {
struct Key;
//! Comparison operator to compare a TiffStructure with a TiffStructure::Key
bool operator==(const Key& key) const;
//! Return the tag corresponding to the extended tag
uint16_t tag() const { return static_cast<uint16_t>(extendedTag_ & 0xffff); }
// DATA
uint32_t extendedTag_; //!< Tag (32 bit so that it can contain special tags)
uint16_t group_; //!< Group that contains the tag
NewTiffCompFct newTiffCompFct_; //!< Function to create the correct TIFF component
uint16_t newGroup_; //!< Group of the newly created component
};
//! Search key for TIFF structure.
struct TiffStructure::Key {
//! Constructor
Key(uint32_t e, uint16_t g) : e_(e), g_(g) {}
uint32_t e_; //!< Extended tag
uint16_t g_; //!< %Group
};
//! TIFF decoder table for functions to decode special cases
struct TiffDecoderInfo {
struct Key;
/*!
@brief Compare a TiffDecoderInfo with a TiffDecoderInfo::Key.
The two are equal if TiffDecoderInfo::make_ equals a substring
of the key of the same size. E.g., decoder info = "OLYMPUS",
key = "OLYMPUS OPTICAL CO.,LTD" (found in the image) match,
the extendedTag is Tag::all or equal to the extended tag of the
key, and the group is equal to that of the key.
*/
bool operator==(const Key& key) const;
//! Return the tag corresponding to the extended tag
uint16_t tag() const { return static_cast<uint16_t>(extendedTag_ & 0xffff); }
// DATA
const char* make_; //!< Camera make for which this decoder function applies
uint32_t extendedTag_; //!< Tag (32 bit so that it can contain special tags)
uint16_t group_; //!< Group that contains the tag
DecoderFct decoderFct_; //!< Decoder function for matching tags
}; // struct TiffDecoderInfo
//! Search key for TIFF decoder structures.
struct TiffDecoderInfo::Key {
//! Constructor
Key(const std::string& m, uint32_t e, uint16_t g) : m_(m), e_(e), g_(g) {}
std::string m_; //!< Camera make
uint32_t e_; //!< Extended tag
uint16_t g_; //!< %Group
};
/*!
@brief This abstract base class provides the common functionality of an
IFD directory entry and defines an extended interface for derived
concrete entries, which allows access to the attributes of the
entry.
*/
class TiffEntryBase : public TiffComponent {
friend class TiffReader;
public:
//! @name Creators
//@{
//! Default constructor
TiffEntryBase(uint16_t tag, uint16_t group)
: TiffComponent(tag, group),
type_(0), count_(0), offset_(0),
size_(0), pData_(0), isAllocated_(false), pValue_(0) {}
//! Virtual destructor.
virtual ~TiffEntryBase();
//@}
//! @name Accessors
//@{
//! Return the Exiv2 type which corresponds to the field type
TypeId typeId() const { return TypeId(type_); }
//! Return the number of components in this entry
uint32_t count() const { return count_; }
/*!
Return the offset to the data area relative to the base for
the component (usually the start of the TIFF header)
*/
uint32_t offset() const { return offset_; }
//! Return the size of this component in bytes
uint32_t size() const { return size_; }
//! Return a pointer to the data area of this component
const byte* pData() const { return pData_; }
//! Return a pointer to the converted value of this component
const Value* pValue() const { return pValue_; }
//@}
private:
// DATA
uint16_t type_; //!< Field Type
uint32_t count_; //!< The number of values of the indicated Type
uint32_t offset_; //!< Offset to the data area
/*!
Size of the data buffer holding the value in bytes, there is no
minimum size.
*/
uint32_t size_;
const byte* pData_; //!< Pointer to the data area
bool isAllocated_; //!< True if this entry owns the value data
Value* pValue_; //!< Converted data value
}; // class TiffEntryBase
/*!
@brief A standard TIFF IFD entry.
*/
class TiffEntry : public TiffEntryBase {
public:
//! @name Creators
//@{
//! Constructor
TiffEntry(uint16_t tag, uint16_t group) : TiffEntryBase(tag, group) {}
//! Virtual destructor.
virtual ~TiffEntry() {}
//@}
private:
//! @name Manipulators
//@{
virtual void doAccept(TiffVisitor& visitor);
//@}
}; // class TiffEntry
/*!
@brief A standard TIFF IFD entry consisting of a value which is an offset
to a data area and the data area. The size of the data area is
provided in a related TiffSizeEntry, tag and group of which are set
in the constructor. This component is used, e.g., for
\em Exif.Thumbnail.JPEGInterchangeFormat for which the size is
provided in \em Exif.Thumbnail.JPEGInterchangeFormatLength.
*/
class TiffDataEntry : public TiffEntryBase {
public:
//! @name Creators
//@{
//! Constructor
TiffDataEntry(uint16_t tag, uint16_t group, uint16_t szTag, uint16_t szGroup)
: TiffEntryBase(tag, group), szTag_(szTag), szGroup_(szGroup) {}
//! Virtual destructor.
virtual ~TiffDataEntry() {}
//@}
//! @name Accessors
//@{
//! Return the group of the entry which has the size
uint16_t szTag() const { return szTag_; }
//! Return the group of the entry which has the size
uint16_t szGroup() const { return szGroup_; }
//@}
private:
//! @name Manipulators
//@{
virtual void doAccept(TiffVisitor& visitor);
//@}
private:
// DATA
const uint16_t szTag_; //!< Tag of the entry with the size
const uint16_t szGroup_; //!< Group of the entry with the size
}; // class TiffDataEntry
/*!
@brief A TIFF IFD entry containing the size of a data area of a related
TiffDataEntry. This component is used, e.g. for
\em Exif.Thumbnail.JPEGInterchangeFormatLength, which contains the
size of \em Exif.Thumbnail.JPEGInterchangeFormat.
*/
class TiffSizeEntry : public TiffEntryBase {
public:
//! @name Creators
//@{
//! Constructor
TiffSizeEntry(uint16_t tag, uint16_t group, uint16_t dtTag, uint16_t dtGroup)
: TiffEntryBase(tag, group), dtTag_(dtTag), dtGroup_(dtGroup) {}
//! Virtual destructor.
virtual ~TiffSizeEntry() {}
//@}
//! @name Accessors
//@{
//! Return the group of the related entry which has the data area
uint16_t dtTag() const { return dtTag_; }
//! Return the group of the related entry which has the data area
uint16_t dtGroup() const { return dtGroup_; }
//@}
private:
//! @name Manipulators
//@{
virtual void doAccept(TiffVisitor& visitor);
//@}
private:
// DATA
const uint16_t dtTag_; //!< Tag of the entry with the data area
const uint16_t dtGroup_; //!< Group of the entry with the data area
}; // class TiffSizeEntry
/*!
@brief This class models a TIFF directory (%Ifd). It is a composite
component of the TIFF tree.
*/
class TiffDirectory : public TiffComponent {
friend class TiffPrinter;
public:
//! @name Creators
//@{
//! Default constructor
TiffDirectory(uint16_t tag, uint16_t group, bool hasNext =true)
: TiffComponent(tag, group), hasNext_(hasNext), pNext_(0) {}
//! Virtual destructor
virtual ~TiffDirectory();
//@}
//! @name Manipulators
//@{
//! Return true if the directory has a next pointer
bool hasNext() const { return hasNext_; }
//@}
private:
//! @name Manipulators
//@{
virtual void doAddChild(TiffComponent::AutoPtr tiffComponent);
virtual void doAddNext(TiffComponent::AutoPtr tiffComponent);
virtual void doAccept(TiffVisitor& visitor);
//@}
private:
// DATA
Components components_; //!< List of components in this directory
const bool hasNext_; //!< True if the directory has a next pointer
TiffComponent* pNext_; //!< Pointer to the next IFD
}; // class TiffDirectory
//! A collection of TIFF directories (IFDs)
typedef std::vector<TiffDirectory*> Ifds;
/*!
@brief This class models a TIFF sub-directory (sub-IFD). A sub-IFD
is an entry with one or more values that are pointers to IFD
structures containing an IFD. The TIFF standard defines
some important tags to be sub-IFDs, including the %Exif and
GPS tags.
*/
class TiffSubIfd : public TiffEntryBase {
friend class TiffReader;
public:
//! @name Creators
//@{
//! Default constructor
TiffSubIfd(uint16_t tag, uint16_t group, uint16_t newGroup)
: TiffEntryBase(tag, group), newGroup_(newGroup) {}
//! Virtual destructor
virtual ~TiffSubIfd();
//@}
private:
//! @name Manipulators
//@{
virtual void doAddChild(TiffComponent::AutoPtr tiffComponent);
virtual void doAccept(TiffVisitor& visitor);
//@}
private:
// DATA
uint16_t newGroup_; //!< Start of the range of group numbers for the sub-IFDs
Ifds ifds_; //!< The subdirectories
}; // class TiffSubIfd
/*!
@brief This class is the basis for Makernote support in TIFF. It contains
a pointer to a concrete Makernote. The TiffReader visitor has the
responsibility to create the correct Make/Model specific Makernote
for a particular TIFF file. Calls to child management methods are
forwarded to the concrete Makernote, if there is one.
*/
class TiffMnEntry : public TiffEntryBase {
friend class TiffReader;
friend class TiffMetadataDecoder;
friend class TiffPrinter;
public:
//! @name Creators
//@{
//! Default constructor
TiffMnEntry(uint16_t tag, uint16_t group, uint16_t mnGroup)
: TiffEntryBase(tag, group), mnGroup_(mnGroup), mn_(0) {}
//! Virtual destructor
virtual ~TiffMnEntry();
//@}
private:
//! @name Manipulators
//@{
virtual void doAddChild(TiffComponent::AutoPtr tiffComponent);
virtual void doAddNext(TiffComponent::AutoPtr tiffComponent);
virtual void doAccept(TiffVisitor& visitor);
//@}
private:
// DATA
uint16_t mnGroup_; //!< New group for concrete mn
TiffComponent* mn_; //!< The Makernote
}; // class TiffMnEntry
/*!
@brief Composite to model an array of tags, each consisting of one
unsigned short value. Canon and Minolta makernotes use such tags.
The elements of this component are usually of type
TiffArrayElement.
*/
class TiffArrayEntry : public TiffEntryBase {
public:
//! @name Creators
//@{
//! Default constructor
TiffArrayEntry(uint16_t tag,
uint16_t group,
uint16_t elGroup,
uint16_t elSize)
: TiffEntryBase(tag, group),
elSize_(elSize),
elGroup_(elGroup) {}
//! Virtual destructor
virtual ~TiffArrayEntry();
//@}
//! @name Accessors
//@{
//! Return the type for the array elements
uint16_t elSize() const { return elSize_; }
//! Return the group for the array elements
uint16_t elGroup() const { return elGroup_; }
//@}
private:
//! @name Manipulators
//@{
virtual void doAddChild(TiffComponent::AutoPtr tiffComponent);
virtual void doAccept(TiffVisitor& visitor);
//@}
private:
// DATA
uint16_t elSize_; //!< Size of the array elements (in bytes)
uint16_t elGroup_; //!< Group for the elements
Components elements_; //!< List of elements in this composite
}; // class TiffArrayEntry
/*!
@brief Element of a TiffArrayEntry. The value is exactly one unsigned
short component. Canon and Minolta makernotes use arrays of
such elements.
*/
class TiffArrayElement : public TiffEntryBase {
public:
//! @name Creators
//@{
//! Constructor
TiffArrayElement(uint16_t tag,
uint16_t group,
TypeId elTypeId,
ByteOrder elByteOrder)
: TiffEntryBase(tag, group),
elTypeId_(elTypeId),
elByteOrder_(elByteOrder) {}
//! Virtual destructor.
virtual ~TiffArrayElement() {}
//@}
//! @name Accessors
//@{
TypeId elTypeId() const { return elTypeId_; }
ByteOrder elByteOrder() const { return elByteOrder_; }
//@}
private:
//! @name Manipulators
//@{
virtual void doAccept(TiffVisitor& visitor);
//@}
private:
// DATA
TypeId elTypeId_; //!< Type of the element
ByteOrder elByteOrder_; //!< Byte order to read/write the element
}; // class TiffArrayElement
// *****************************************************************************
// template, inline and free functions
//! Return the group name for a group
const char* tiffGroupName(uint16_t group);
//! Function to create and initialize a new TIFF directory
TiffComponent::AutoPtr newTiffDirectory(uint16_t tag,
const TiffStructure* ts);
//! Function to create and initialize a new TIFF sub-directory
TiffComponent::AutoPtr newTiffSubIfd(uint16_t tag,
const TiffStructure* ts);
//! Function to create and initialize a new TIFF makernote entry
TiffComponent::AutoPtr newTiffMnEntry(uint16_t tag,
const TiffStructure* ts);
//! Function to create and initialize a new array entry
template<uint16_t elSize>
TiffComponent::AutoPtr newTiffArrayEntry(uint16_t tag,
const TiffStructure* ts)
{
assert(ts);
return TiffComponent::AutoPtr(
new TiffArrayEntry(tag, ts->group_, ts->newGroup_, elSize));
}
//! Function to create and initialize a new array element
template<TypeId typeId, ByteOrder byteOrder>
TiffComponent::AutoPtr newTiffArrayElement(uint16_t tag,
const TiffStructure* ts)
{
assert(ts);
return TiffComponent::AutoPtr(
new TiffArrayElement(tag, ts->group_, typeId, byteOrder));
}
template<TypeId typeId>
TiffComponent::AutoPtr newTiffArrayElement(uint16_t tag,
const TiffStructure* ts)
{
return newTiffArrayElement<typeId, invalidByteOrder>(tag, ts);
}
//! Function to create and initialize a new TIFF entry for a thumbnail (data)
template<uint16_t szTag, uint16_t szGroup>
TiffComponent::AutoPtr newTiffThumbData(uint16_t tag,
const TiffStructure* ts)
{
assert(ts);
return TiffComponent::AutoPtr(
new TiffDataEntry(tag, ts->group_, szTag, szGroup));
}
//! Function to create and initialize a new TIFF entry for a thumbnail (size)
template<uint16_t dtTag, uint16_t dtGroup>
TiffComponent::AutoPtr newTiffThumbSize(uint16_t tag,
const TiffStructure* ts)
{
assert(ts);
return TiffComponent::AutoPtr(
new TiffSizeEntry(tag, ts->group_, dtTag, dtGroup));
}
} // namespace Exiv2
#endif // #ifndef TIFFCOMPOSITE_HPP_

File diff suppressed because it is too large Load Diff

@ -19,15 +19,15 @@
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*!
@file tifffwd.hpp
@brief TIFF parser related typedefs and forward definitions.
@file tifffwd_int.hpp
@brief Internal TIFF parser related typedefs and forward definitions.
@version $Rev$
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 24-Jun-06, ahu: created
*/
#ifndef TIFFFWD_HPP_
#define TIFFFWD_HPP_
#ifndef TIFFFWD_INT_HPP_
#define TIFFFWD_INT_HPP_
// *****************************************************************************
// included header files
@ -35,14 +35,17 @@
// + standard includes
#include <memory>
#include <stack>
// *****************************************************************************
// namespace extensions
// Exiv2 namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
class Exifdatum;
namespace Internal {
class TiffHeaderBase;
class TiffComponent;
struct TiffStructure;
class TiffEntryBase;
@ -59,31 +62,41 @@ namespace Exiv2 {
class TiffVisitor;
class TiffFinder;
class TiffMetadataDecoder;
class TiffDecoder;
class TiffEncoder;
class TiffReader;
class TiffPrinter;
class TiffHeaderBase;
class TiffRwState;
struct TiffDecoderInfo;
class Image;
class Value;
struct TiffMappingInfo;
// *****************************************************************************
// class definitions
// type definitions
/*!
@brief Function pointer type for a TiffMetadataDecoder member function
@brief Function pointer type for a TiffDecoder member function
to decode a TIFF component.
*/
typedef void (TiffMetadataDecoder::*DecoderFct)(const TiffEntryBase*);
typedef void (TiffDecoder::*DecoderFct)(const TiffEntryBase*);
/*!
@brief Function pointer type for a TiffDecoder member function
to decode a TIFF component.
*/
typedef void (TiffEncoder::*EncoderFct)(TiffEntryBase*, const Exifdatum*);
/*!
@brief Type for a function pointer for a function to decode a TIFF component.
*/
typedef DecoderFct (*FindDecoderFct)(const std::string& make,
uint32_t extendedTag,
uint16_t group);
/*!
@brief Type for a function pointer for a function to encode a TIFF component.
*/
typedef EncoderFct (*FindEncoderFct)(
const std::string& make,
uint32_t extendedTag,
uint16_t group
);
/*!
@brief Type for a function pointer for a function to create a TIFF component.
Use TiffComponent::AutoPtr, it is not used in this declaration only
@ -91,14 +104,17 @@ namespace Exiv2 {
*/
typedef std::auto_ptr<TiffComponent> (*NewTiffCompFct)( uint16_t tag,
const TiffStructure* ts);
//! Stack to hold a path from the TIFF root element to a TIFF entry
typedef std::stack<const TiffStructure*> TiffPath;
/*!
@brief Type for a factory function to create new TIFF components.
Use TiffComponent::AutoPtr, it is not used in this declaration only
to reduce dependencies.
*/
typedef std::auto_ptr<TiffComponent> (*TiffCompFactoryFct)(uint32_t extendedTag,
uint16_t group);
typedef std::auto_ptr<Internal::TiffComponent> (*TiffCompFactoryFct)(uint32_t extendedTag,
uint16_t group);
} // namespace Exiv2
}} // namespace Internal, Exiv2
#endif // #ifndef TIFFFWD_HPP_
#endif // #ifndef TIFFFWD_INT_HPP_

@ -38,10 +38,14 @@ EXIV2_RCSID("@(#) $Id$")
#endif
#include "tiffimage.hpp"
#include "tiffparser.hpp"
#include "tiffimage_int.hpp"
#include "tiffcomposite_int.hpp"
#include "tiffvisitor_int.hpp"
#include "makernote2_int.hpp"
#include "image.hpp"
#include "error.hpp"
#include "futils.hpp"
#include "types.hpp"
#include "i18n.h" // NLS support.
// + standard includes
@ -49,11 +53,49 @@ EXIV2_RCSID("@(#) $Id$")
#include <iostream>
#include <iomanip>
#include <cassert>
#include <memory>
/* --------------------------------------------------------------------------
Todo:
+ Support all TIFF data types
+ Review boundary checking, is it better to check the offsets?
+ Define and implement consistent error handling for recursive hierarchy
+ Make TiffImage a template StandardImage, which can be parametrized with
a parser and the necessary checking functions to cover all types of
images which need to be loaded completely.
+ TiffComponent: should it have end() and setEnd() or pData and size?
+ Can NewTiffCompFct and TiffCompFactoryFct be combined?
+ Create function is repeated when actually only the table changes. Fix it.
+ Is it easier (for writing) to combine all creation tables into one?
+ CR2 Makernotes don't seem to have a next pointer but Canon Jpeg Makernotes
do. What a mess. (That'll become an issue when it comes to writing to CR2)
+ Sony makernotes in RAW files do not seem to have header like those in Jpegs.
And maybe no next pointer either.
+ Filtering of large unknown tags: Should be moved to writing/encoding code
and done only if really needed (i.e., if writing to a Jpeg segment)
+ Make Tiff parser completely standalone, depending only on very low level
stuff from exiv2
in crwimage.* :
+ Fix CiffHeader according to TiffHeade2
+ Combine Error(15) and Error(33), add format argument %1
+ Search crwimage for todos, fix writeMetadata comment
+ Add Ciff components to TIFF component hierarchy
+ rename all Ciff stuff to Crw for easier reference - not needed when CIFF
components are part of the TIFF hierarchy
+ rename loadStack to getPath for consistency
-------------------------------------------------------------------------- */
// *****************************************************************************
// class member definitions
namespace Exiv2 {
using namespace Internal;
TiffImage::TiffImage(BasicIo::AutoPtr io, bool /*create*/)
: Image(ImageType::tiff, mdExif | mdIptc, io)
{
@ -79,18 +121,6 @@ namespace Exiv2 {
return 0;
}
void TiffImage::setExifData(const ExifData& /*exifData*/)
{
// Todo: implement me!
throw(Error(32, "Exif metadata", "TIFF"));
}
void TiffImage::setIptcData(const IptcData& /*iptcData*/)
{
// Todo: implement me!
throw(Error(32, "IPTC metadata", "TIFF"));
}
void TiffImage::setComment(const std::string& /*comment*/)
{
// not supported
@ -110,16 +140,475 @@ namespace Exiv2 {
throw Error(3, "TIFF");
}
clearMetadata();
TiffParser::decode(this, io_->mmap(), io_->size(),
TiffCreator::create, TiffDecoder::findDecoder);
ByteOrder bo = TiffParser::decode(exifData_,
iptcData_,
xmpData_,
io_->mmap(),
io_->size());
setByteOrder(bo);
} // TiffImage::readMetadata
void TiffImage::writeMetadata()
{
//! Todo: implement me!
throw(Error(31, "TIFF"));
#ifdef DEBUG
std::cerr << "Writing TIFF file " << io_->path() << "\n";
#endif
// Read existing image
ByteOrder bo = byteOrder();
DataBuf buf;
if (io_->open() == 0) {
IoCloser closer(*io_);
// Ensure that this is the correct image type
if (isTiffType(*io_, false)) {
// Read the image into a memory buffer
buf.alloc(io_->size());
io_->read(buf.pData_, buf.size_);
if (io_->error() || io_->eof()) {
buf.reset();
}
TiffHeade2 tiffHeader;
if (0 == tiffHeader.read(buf.pData_, 8)) {
bo = tiffHeader.byteOrder();
}
}
}
if (bo == invalidByteOrder) {
bo = littleEndian;
}
setByteOrder(bo);
Blob blob;
WriteMethod wm = TiffParser::encode(blob,
buf.pData_,
buf.size_,
bo,
exifData_,
iptcData_,
xmpData_);
// Write updated or new buffer to file
BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
assert(tempIo.get() != 0);
if (wm == wmNonIntrusive) {
// Buffer may be modified but size is unchanged, write buffer back
tempIo->write(buf.pData_, buf.size_);
}
else {
// Size of the buffer changed, write from blob
tempIo->write(&blob[0], static_cast<long>(blob.size()));
}
io_->close();
io_->transfer(*tempIo); // may throw
} // TiffImage::writeMetadata
ByteOrder TiffParser::decode(
ExifData& exifData,
IptcData& iptcData,
XmpData& xmpData,
const byte* pData,
uint32_t size
)
{
return TiffParserWorker::decode(exifData,
iptcData,
xmpData,
pData,
size,
TiffCreator::create,
TiffMapping::findDecoder);
} // TiffParser::decode
WriteMethod TiffParser::encode(
Blob& blob,
const byte* pData,
uint32_t size,
ByteOrder byteOrder,
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData
)
{
std::auto_ptr<TiffHeaderBase> header(new TiffHeade2(byteOrder));
return TiffParserWorker::encode(blob,
pData,
size,
exifData,
iptcData,
xmpData,
TiffCreator::create,
TiffMapping::findEncoder,
header.get());
} // TiffParser::encode
// *************************************************************************
// free functions
Image::AutoPtr newTiffInstance(BasicIo::AutoPtr io, bool create)
{
Image::AutoPtr image(new TiffImage(io, create));
if (!image->good()) {
image.reset();
}
return image;
}
bool isTiffType(BasicIo& iIo, bool advance)
{
const int32_t len = 8;
byte buf[len];
iIo.read(buf, len);
if (iIo.error() || iIo.eof()) {
return false;
}
TiffHeade2 tiffHeader;
bool rc = tiffHeader.read(buf, len);
if (!advance || !rc) {
iIo.seek(-len, BasicIo::cur);
}
return rc;
}
} // namespace Exiv2
namespace Exiv2 {
namespace Internal {
/*
This table describes the standard TIFF layout (including non-standard
Makernote structures) and determines the corresponding Exiv2 TIFF
components. The key of the table consists of the first two attributes,
(extended) tag and group. Tag is the TIFF tag or one of a few extended
tags, group identifies the IFD or any other composite TIFF component.
Each entry of the table defines for a particular tag and group
combination, which create function is used, what the group and parent tag
and group of the new component are.
*/
const TiffStructure TiffCreator::tiffStructure_[] = {
// ext. tag group child group parent tag parent group create function
//--------- ----------------- ----------------- ---------- ----------------- -------------------
// Root directory
{ Tag::root, Group::none, Group::ifd0, Tag::root, Group::none, newTiffDirectory },
// IFD0
{ 0x8769, Group::ifd0, Group::exif, Tag::root, Group::none, newTiffSubIfd },
{ 0x8825, Group::ifd0, Group::gps, Tag::root, Group::none, newTiffSubIfd },
{ 0x0111, Group::ifd0, Group::ifd0, Tag::root, Group::none, newTiffImageData<0x0117, Group::ifd0> },
{ 0x0117, Group::ifd0, Group::ifd0, Tag::root, Group::none, newTiffImageSize<0x0111, Group::ifd0> },
// SubIfd found in NEF images (up to 3 sub directories seen, groups sub0_0, sub0_1, sub0_2)
{ 0x014a, Group::ifd0, Group::sub0_0, Tag::root, Group::none, newTiffSubIfd },
{ Tag::next, Group::ifd0, Group::ifd1, Tag::root, Group::none, newTiffDirectory },
{ Tag::all, Group::ifd0, Group::ifd0, Tag::root, Group::none, newTiffEntry },
// Subdir sub0_0
{ Tag::next, Group::sub0_0, Group::ignr, 0x014a, Group::ifd0, newTiffDirectory },
{ Tag::all, Group::sub0_0, Group::sub0_0, 0x014a, Group::ifd0, newTiffEntry },
// Subdir sub0_1
{ Tag::next, Group::sub0_1, Group::ignr, 0x014a, Group::ifd0, newTiffDirectory },
{ Tag::all, Group::sub0_1, Group::sub0_1, 0x014a, Group::ifd0, newTiffEntry },
// Subdir sub0_2
{ Tag::next, Group::sub0_2, Group::ignr, 0x014a, Group::ifd0, newTiffDirectory },
{ Tag::all, Group::sub0_2, Group::sub0_2, 0x014a, Group::ifd0, newTiffEntry },
// Exif subdir
{ 0xa005, Group::exif, Group::iop, 0x8769, Group::ifd0, newTiffSubIfd },
{ 0x927c, Group::exif, Group::mn, 0x8769, Group::ifd0, newTiffMnEntry },
{ Tag::next, Group::exif, Group::ignr, 0x8769, Group::ifd0, newTiffDirectory },
{ Tag::all, Group::exif, Group::exif, 0x8769, Group::ifd0, newTiffEntry },
// GPS subdir
{ Tag::next, Group::gps, Group::ignr, 0x8825, Group::ifd0, newTiffDirectory },
{ Tag::all, Group::gps, Group::gps, 0x8825, Group::ifd0, newTiffEntry },
// IOP subdir
{ Tag::next, Group::iop, Group::ignr, 0xa005, Group::exif, newTiffDirectory },
{ Tag::all, Group::iop, Group::iop, 0xa005, Group::exif, newTiffEntry },
// IFD1
{ 0x0111, Group::ifd1, Group::ifd1, Tag::next, Group::ifd0, newTiffThumbData<0x0117, Group::ifd1> },
{ 0x0117, Group::ifd1, Group::ifd1, Tag::next, Group::ifd0, newTiffThumbSize<0x0111, Group::ifd1> },
{ 0x0201, Group::ifd1, Group::ifd1, Tag::next, Group::ifd0, newTiffThumbData<0x0202, Group::ifd1> },
{ 0x0202, Group::ifd1, Group::ifd1, Tag::next, Group::ifd0, newTiffThumbSize<0x0201, Group::ifd1> },
{ Tag::next, Group::ifd1, Group::ignr, Tag::next, Group::ifd0, newTiffDirectory },
{ Tag::all, Group::ifd1, Group::ifd1, Tag::next, Group::ifd0, newTiffEntry },
// Olympus makernote - some Olympus cameras use Minolta structures
// Todo: Adding such tags will not work (maybe result in a Minolta makernote), need separate groups
{ 0x0001, Group::olympmn, Group::minocso, 0x927c, Group::exif, newTiffArrayEntry<unsignedLong, false> },
{ 0x0003, Group::olympmn, Group::minocsn, 0x927c, Group::exif, newTiffArrayEntry<unsignedLong, false> },
{ Tag::next, Group::olympmn, Group::ignr, 0x927c, Group::exif, newTiffDirectory },
{ Tag::all, Group::olympmn, Group::olympmn, 0x927c, Group::exif, newTiffEntry },
// Fujifilm makernote
{ Tag::next, Group::fujimn, Group::ignr, 0x927c, Group::exif, newTiffDirectory },
{ Tag::all, Group::fujimn, Group::fujimn, 0x927c, Group::exif, newTiffEntry },
// Canon makernote
{ 0x0001, Group::canonmn, Group::canoncs, 0x927c, Group::exif, newTiffArrayEntry<unsignedShort, true> },
{ 0x0004, Group::canonmn, Group::canonsi, 0x927c, Group::exif, newTiffArrayEntry<unsignedShort, true> },
{ 0x0005, Group::canonmn, Group::canonpa, 0x927c, Group::exif, newTiffArrayEntry<unsignedShort, true> },
{ 0x000f, Group::canonmn, Group::canoncf, 0x927c, Group::exif, newTiffArrayEntry<unsignedShort, true> },
{ 0x0012, Group::canonmn, Group::canonpi, 0x927c, Group::exif, newTiffArrayEntry<unsignedShort, true> },
{ Tag::next, Group::canonmn, Group::ignr, 0x927c, Group::exif, newTiffDirectory },
{ Tag::all, Group::canonmn, Group::canonmn, 0x927c, Group::exif, newTiffEntry },
// Canon makernote composite tags
{ Tag::all, Group::canoncs, Group::canoncs, 0x0001, Group::canonmn, newTiffArrayElement<unsignedShort> },
{ Tag::all, Group::canonsi, Group::canonsi, 0x0004, Group::canonmn, newTiffArrayElement<unsignedShort> },
{ Tag::all, Group::canonpa, Group::canonpa, 0x0005, Group::canonmn, newTiffArrayElement<unsignedShort> },
{ Tag::all, Group::canoncf, Group::canoncf, 0x000f, Group::canonmn, newTiffArrayElement<unsignedShort> },
{ Tag::all, Group::canonpi, Group::canonpi, 0x0012, Group::canonmn, newTiffArrayElement<unsignedShort> },
// Nikon1 makernote
{ Tag::next, Group::nikon1mn, Group::ignr, 0x927c, Group::exif, newTiffDirectory },
{ Tag::all, Group::nikon1mn, Group::nikon1mn, 0x927c, Group::exif, newTiffEntry },
// Nikon2 makernote
{ Tag::next, Group::nikon2mn, Group::ignr, 0x927c, Group::exif, newTiffDirectory },
{ Tag::all, Group::nikon2mn, Group::nikon2mn, 0x927c, Group::exif, newTiffEntry },
// Nikon3 makernote
{ Tag::next, Group::nikon3mn, Group::ignr, 0x927c, Group::exif, newTiffDirectory },
{ Tag::all, Group::nikon3mn, Group::nikon3mn, 0x927c, Group::exif, newTiffEntry },
// Panasonic makernote
{ Tag::next, Group::panamn, Group::ignr, 0x927c, Group::exif, newTiffDirectory },
{ Tag::all, Group::panamn, Group::panamn, 0x927c, Group::exif, newTiffEntry },
// Sigma/Foveon makernote
{ Tag::next, Group::sigmamn, Group::ignr, 0x927c, Group::exif, newTiffDirectory },
{ Tag::all, Group::sigmamn, Group::sigmamn, 0x927c, Group::exif, newTiffEntry },
// Sony1 makernote
{ Tag::next, Group::sony1mn, Group::ignr, 0x927c, Group::exif, newTiffDirectory },
{ Tag::all, Group::sony1mn, Group::sony1mn, 0x927c, Group::exif, newTiffEntry },
// Sony2 makernote
{ Tag::next, Group::sony2mn, Group::ignr, 0x927c, Group::exif, newTiffDirectory },
{ Tag::all, Group::sony2mn, Group::sony2mn, 0x927c, Group::exif, newTiffEntry },
// Minolta makernote
{ 0x0001, Group::minoltamn, Group::minocso, 0x927c, Group::exif, newTiffArrayEntry<unsignedLong, false> },
{ 0x0003, Group::minoltamn, Group::minocsn, 0x927c, Group::exif, newTiffArrayEntry<unsignedLong, false> },
{ 0x0004, Group::minoltamn, Group::minocs7, 0x927c, Group::exif, newTiffArrayEntry<unsignedShort, false> },
{ 0x0088, Group::minoltamn, Group::minoltamn, 0x927c, Group::exif, newTiffThumbData<0x0089, Group::minoltamn> },
{ 0x0089, Group::minoltamn, Group::minoltamn, 0x927c, Group::exif, newTiffThumbSize<0x0088, Group::minoltamn> },
{ 0x0114, Group::minoltamn, Group::minocs5, 0x927c, Group::exif, newTiffArrayEntry<unsignedShort, false> },
{ Tag::next, Group::minoltamn, Group::ignr, 0x927c, Group::exif, newTiffDirectory },
{ Tag::all, Group::minoltamn, Group::minoltamn, 0x927c, Group::exif, newTiffEntry },
// Minolta makernote composite tags
{ Tag::all, Group::minocso, Group::minocso, 0x0001, Group::minoltamn, newTiffArrayElement<unsignedLong, bigEndian> },
{ Tag::all, Group::minocsn, Group::minocsn, 0x0003, Group::minoltamn, newTiffArrayElement<unsignedLong, bigEndian> },
{ Tag::all, Group::minocs7, Group::minocs7, 0x0004, Group::minoltamn, newTiffArrayElement<unsignedShort, bigEndian> },
{ Tag::all, Group::minocs5, Group::minocs5, 0x0114, Group::minoltamn, newTiffArrayElement<unsignedShort, bigEndian> },
// Tags which are not de/encoded
{ Tag::next, Group::ignr, Group::ignr, Tag::none, Group::none, newTiffDirectory },
{ Tag::all, Group::ignr, Group::ignr, Tag::none, Group::none, newTiffEntry }
};
// TIFF mapping table for special decoding and encoding requirements
const TiffMappingInfo TiffMapping::tiffMappingInfo_[] = {
{ "*", Tag::all, Group::ignr, 0, 0 }, // Do not decode tags with group == Group::ignr
{ "OLYMPUS", 0x0100, Group::olympmn, &TiffDecoder::decodeOlympThumb, &TiffEncoder::encodeOlympThumb },
{ "*", 0x014a, Group::ifd0, 0, 0 }, // Todo: Controversial, causes problems with Exiftool
{ "*", Tag::all, Group::sub0_0, &TiffDecoder::decodeSubIfd, 0 /*Todo*/ },
{ "*", Tag::all, Group::sub0_1, &TiffDecoder::decodeSubIfd, 0 /*Todo*/ },
{ "*", 0x02bc, Group::ifd0, &TiffDecoder::decodeXmp, &TiffEncoder::encodeXmp },
{ "*", 0x83bb, Group::ifd0, &TiffDecoder::decodeIptc, &TiffEncoder::encodeIptc },
{ "*", 0x8649, Group::ifd0, &TiffDecoder::decodeIptc, &TiffEncoder::encodeIptc },
// Minolta makernote entries which need to be encoded in big endian byte order
{ "*", Tag::all, Group::minocso, &TiffDecoder::decodeStdTiffEntry, &TiffEncoder::encodeBigEndianEntry },
{ "*", Tag::all, Group::minocso, &TiffDecoder::decodeStdTiffEntry, &TiffEncoder::encodeBigEndianEntry },
{ "*", Tag::all, Group::minocso, &TiffDecoder::decodeStdTiffEntry, &TiffEncoder::encodeBigEndianEntry },
{ "*", Tag::all, Group::minocso, &TiffDecoder::decodeStdTiffEntry, &TiffEncoder::encodeBigEndianEntry }
};
DecoderFct TiffMapping::findDecoder(const std::string& make,
uint32_t extendedTag,
uint16_t group)
{
DecoderFct decoderFct = &TiffDecoder::decodeStdTiffEntry;
const TiffMappingInfo* td = find(tiffMappingInfo_,
TiffMappingInfo::Key(make, extendedTag, group));
if (td) {
// This may set decoderFct to 0, meaning that the tag should not be decoded
decoderFct = td->decoderFct_;
}
return decoderFct;
}
EncoderFct TiffMapping::findEncoder(
const std::string& make,
uint32_t extendedTag,
uint16_t group
)
{
EncoderFct encoderFct = 0;
const TiffMappingInfo* td = find(tiffMappingInfo_,
TiffMappingInfo::Key(make, extendedTag, group));
if (td) {
// Returns 0 if no special encoder function is found
encoderFct = td->encoderFct_;
}
return encoderFct;
}
TiffComponent::AutoPtr TiffCreator::create(uint32_t extendedTag,
uint16_t group)
{
TiffComponent::AutoPtr tc(0);
uint16_t tag = static_cast<uint16_t>(extendedTag & 0xffff);
const TiffStructure* ts = find(tiffStructure_,
TiffStructure::Key(extendedTag, group));
if (ts && ts->newTiffCompFct_) {
tc = ts->newTiffCompFct_(tag, ts);
}
#ifdef DEBUG
else {
if (!ts) {
std::cerr << "Warning: No TIFF structure entry found for ";
}
else {
std::cerr << "Warning: No TIFF component creator found for ";
}
std::cerr << "extended tag 0x" << std::setw(4) << std::setfill('0')
<< std::hex << std::right << extendedTag
<< ", group " << tiffGroupName(group) << "\n";
}
#endif
return tc;
} // TiffCreator::create
void TiffCreator::getPath(TiffPath& tiffPath, uint32_t extendedTag, uint16_t group)
{
const TiffStructure* ts = 0;
do {
ts = find(tiffStructure_, TiffStructure::Key(extendedTag, group));
assert(ts != 0);
tiffPath.push(ts);
extendedTag = ts->parentExtTag_;
group = ts->parentGroup_;
} while (!(ts->extendedTag_ == Tag::root && ts->group_ == Group::none));
} // TiffCreator::getPath
ByteOrder TiffParserWorker::decode(
ExifData& exifData,
IptcData& iptcData,
XmpData& xmpData,
const byte* pData,
uint32_t size,
TiffCompFactoryFct createFct,
FindDecoderFct findDecoderFct,
TiffHeaderBase* pHeader
)
{
// Create standard TIFF header if necessary
std::auto_ptr<TiffHeaderBase> ph;
if (!pHeader) {
ph = std::auto_ptr<TiffHeaderBase>(new TiffHeade2);
pHeader = ph.get();
}
TiffComponent::AutoPtr rootDir = parse(pData, size, createFct, pHeader);
if (0 != rootDir.get()) {
TiffDecoder decoder(exifData,
iptcData,
xmpData,
rootDir.get(),
findDecoderFct);
rootDir->accept(decoder);
}
return pHeader->byteOrder();
} // TiffParserWorker::decode
WriteMethod TiffParserWorker::encode(
Blob& blob,
const byte* pData,
uint32_t size,
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData,
TiffCompFactoryFct createFct,
FindEncoderFct findEncoderFct,
TiffHeaderBase* pHeader
)
{
/*
1) parse the binary image, if one is provided, and
2) attempt updating the parsed tree in-place ("non-intrusive writing")
3) else, create a new tree and write a new TIFF structure ("intrusive
writing"). If there is a parsed tree, it is only used to access the
image data in this case.
*/
assert(pHeader);
assert(pHeader->byteOrder() != invalidByteOrder);
blob.clear();
WriteMethod writeMethod = wmIntrusive;
TiffComponent::AutoPtr createdTree;
TiffComponent::AutoPtr parsedTree = parse(pData, size, createFct, pHeader);
if (0 != parsedTree.get()) {
// Attempt to update existing TIFF components based on metadata entries
TiffEncoder encoder(exifData,
iptcData,
xmpData,
parsedTree.get(),
pHeader->byteOrder(),
findEncoderFct);
parsedTree->accept(encoder);
if (!encoder.dirty()) writeMethod = wmNonIntrusive;
}
if (writeMethod == wmIntrusive) {
createdTree = createFct(Tag::root, Group::none);
TiffEncoder encoder(exifData,
iptcData,
xmpData,
createdTree.get(),
pHeader->byteOrder(),
findEncoderFct);
// Add entries from metadata to composite
encoder.add(createdTree.get(), parsedTree.get(), createFct);
// Write binary representation from the composite tree
uint32_t offset = pHeader->write(blob);
uint32_t len = createdTree->write(blob, pHeader->byteOrder(), offset, uint32_t(-1), uint32_t(-1), uint32_t(-1));
// Avoid writing just the header if there is no IFD data
if (len == 0) blob.clear();
#ifdef DEBUG
std::cerr << "Intrusive writing\n";
#endif
}
#ifdef DEBUG
else {
std::cerr << "Non-intrusive writing\n";
}
#endif
return writeMethod;
} // TiffParserWorker::encode
TiffComponent::AutoPtr TiffParserWorker::parse(
const byte* pData,
uint32_t size,
TiffCompFactoryFct createFct,
TiffHeaderBase* pHeader
)
{
if (pData == 0 || size == 0) return TiffComponent::AutoPtr(0);
if (!pHeader->read(pData, size) || pHeader->offset() >= size) {
throw Error(3, "TIFF");
}
TiffComponent::AutoPtr rootDir = createFct(Tag::root, Group::none);
if (0 != rootDir.get()) {
rootDir->setStart(pData + pHeader->offset());
TiffRwState::AutoPtr state(
new TiffRwState(pHeader->byteOrder(), 0, createFct));
TiffReader reader(pData, size, rootDir.get(), state);
rootDir->accept(reader);
}
return rootDir;
} // TiffParserWorker::parse
TiffHeaderBase::TiffHeaderBase(uint16_t tag,
uint32_t size,
ByteOrder byteOrder,
@ -137,7 +626,7 @@ namespace Exiv2 {
bool TiffHeaderBase::read(const byte* pData, uint32_t size)
{
if (size < 8) return false;
if (!pData || size < 8) return false;
if (pData[0] == 0x49 && pData[1] == 0x49) {
byteOrder_ = littleEndian;
@ -154,9 +643,26 @@ namespace Exiv2 {
return true;
} // TiffHeaderBase::read
void TiffHeaderBase::write(Blob& blob) const
uint32_t TiffHeaderBase::write(Blob& blob) const
{
// Todo: Implement me!
byte buf[8];
switch (byteOrder_) {
case littleEndian:
buf[0] = 0x49;
buf[1] = 0x49;
break;
case bigEndian:
buf[0] = 0x4d;
buf[1] = 0x4d;
break;
case invalidByteOrder:
assert(false);
break;
}
us2Data(buf + 2, tag_, byteOrder_);
ul2Data(buf + 4, 0x00000008, byteOrder_);
append(blob, buf, 8);
return 8;
}
void TiffHeaderBase::print(std::ostream& os, const std::string& prefix) const
@ -204,8 +710,8 @@ namespace Exiv2 {
return tag_;
}
TiffHeade2::TiffHeade2()
: TiffHeaderBase(42, 8, littleEndian, 0x00000008)
TiffHeade2::TiffHeade2(ByteOrder byteOrder)
: TiffHeaderBase(42, 8, byteOrder, 0x00000008)
{
}
@ -213,31 +719,4 @@ namespace Exiv2 {
{
}
// *************************************************************************
// free functions
Image::AutoPtr newTiffInstance(BasicIo::AutoPtr io, bool create)
{
Image::AutoPtr image(new TiffImage(io, create));
if (!image->good()) {
image.reset();
}
return image;
}
bool isTiffType(BasicIo& iIo, bool advance)
{
const int32_t len = 8;
byte buf[len];
iIo.read(buf, len);
if (iIo.error() || iIo.eof()) {
return false;
}
TiffHeade2 tiffHeader;
bool rc = tiffHeader.read(buf, len);
if (!advance || !rc) {
iIo.seek(-len, BasicIo::cur);
}
return rc;
}
} // namespace Exiv2
}} // namespace Internal, Exiv2

@ -78,21 +78,7 @@ namespace Exiv2 {
//! @name Manipulators
//@{
void readMetadata();
/*!
@brief Todo: Write metadata back to the image. This method is not
yet implemented. Calling it will throw an Error(31).
*/
void writeMetadata();
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(32).
*/
void setExifData(const ExifData& exifData);
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(32).
*/
void setIptcData(const IptcData& iptcData);
/*!
@brief Not supported. TIFF format does not contain a comment.
Calling this function will throw an Error(32).
@ -119,90 +105,75 @@ namespace Exiv2 {
}; // class TiffImage
/*!
@brief Abstract base class defining the interface of an image header.
Used internally by classes for TIFF-based images. Default
implementation is for the regular TIFF header.
@brief Stateless parser class for data in TIFF format. Images use this
class to decode and encode TIFF data. It is a wrapper of the
internal class Internal::TiffParserWorker.
*/
class TiffHeaderBase {
class TiffParser {
public:
//! @name Constructors
//@{
//! Constructor taking \em tag, \em size and default \em byteOrder and \em offset.
TiffHeaderBase(uint16_t tag,
uint32_t size,
ByteOrder byteOrder,
uint32_t offset);
//! Virtual destructor.
virtual ~TiffHeaderBase() =0;
//@}
//! @name Manipulators
//@{
/*!
@brief Read the image header from a data buffer. Return false if the
data buffer does not contain an image header of the expected
format, else true.
@param pData Pointer to the data buffer.
@param size Number of bytes in the data buffer.
*/
virtual bool read(const byte* pData, uint32_t size);
//! Set the byte order.
virtual void setByteOrder(ByteOrder byteOrder);
//! Set the offset to the start of the root directory.
virtual void setOffset(uint32_t offset);
//@}
//! @name Accessors
//@{
/*!
@brief Write the image header to the binary image \em blob.
This method appends to the blob.
@param blob Binary image to add to.
@throw Error If the header cannot be written.
*/
virtual void write(Blob& blob) const;
@brief Decode metadata from a buffer \em pData of length \em size
with data in TIFF format to the provided metadata containers.
@param exifData Exif metadata container.
@param iptcData IPTC metadata container.
@param xmpData XMP metadata container.
@param pData Pointer to the data buffer. Must point to data in TIFF
format; no checks are performed.
@param size Length of the data buffer.
@return Byte order in which the data is encoded.
*/
static ByteOrder decode(
ExifData& exifData,
IptcData& iptcData,
XmpData& xmpData,
const byte* pData,
uint32_t size
);
/*!
@brief Print debug info for the image header to \em os.
@param os Output stream to write to.
@param prefix Prefix to be written before each line of output.
*/
virtual void print(std::ostream& os, const std::string& prefix ="") const;
//! Return the byte order (little or big endian).
virtual ByteOrder byteOrder() const;
//! Return the offset to the start of the root directory.
virtual uint32_t offset() const;
//! Return the size (in bytes) of the image header.
virtual uint32_t size() const;
//! Return the tag value (magic number) which identifies the buffer as TIFF data
virtual uint16_t tag() const;
//@}
private:
// DATA
const uint16_t tag_; //!< Tag to identify the buffer as TIFF data
const uint32_t size_; //!< Size of the header
ByteOrder byteOrder_; //!< Applicable byte order
uint32_t offset_; //!< Offset to the start of the root dir
}; // class TiffHeaderBase
/*!
@brief Standard TIFF header structure.
*/
class TiffHeade2 : public TiffHeaderBase {
public:
//! @name Creators
//@{
//! Default constructor
TiffHeade2();
//! Destructor
~TiffHeade2();
//@}
}; // class TiffHeade2
@brief Encode metadata from the provided metadata to TIFF format.
The original binary image in the memory block \em pData, \em size is
parsed and updated in-place if possible ("non-intrusive" writing).
If that is not possible (e.g., if new tags were added), the entire
TIFF structure is re-written to the \em blob ("intrusive" writing).<br>
The return value indicates which write method was used. If it is
\c wmNonIntrusive, the original memory \em pData, \em size contains
the result and \em blob is empty. If the return value is
\c wmIntrusive, a new TIFF structure was created and returned in
\em blob. The memory block \em pData, \em size may be partly updated
in this case and should not be used anymore.
@note If there is no metadata to encode, i.e., all metadata
containers are empty, then the return value is \c wmIntrusive
and the \em blob is empty, i.e., no TIFF header is written.
@param blob Container for the binary image if "intrusive"
writing is necessary. Empty otherwise.
@param pData Pointer to the binary image data buffer. Must
point to data in TIFF format; no checks are
performed. Will be modified if "non-intrusive"
writing is possible.
@param size Length of the data buffer.
@param byteOrder Byte order to use.
@param exifData Exif metadata container.
@param iptcData IPTC metadata container.
@param xmpData XMP metadata container.
@return Write method used.
*/
static WriteMethod encode(
Blob& blob,
const byte* pData,
uint32_t size,
ByteOrder byteOrder,
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData
);
}; // class TiffParser
// *****************************************************************************
// template, inline and free functions

@ -0,0 +1,287 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*!
@file tiffimage_int.hpp
@brief Internal class TiffParserWorker to parse TIFF data.
@version $Rev$
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 23-Apr-08, ahu: created
*/
#ifndef TIFFIMAGE_INT_HPP_
#define TIFFIMAGE_INT_HPP_
// *****************************************************************************
// included header files
#include "tifffwd_int.hpp"
#include "image.hpp"
#include "types.hpp"
// + standard includes
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
/*!
@brief Contains internal objects which are not published and are not part
of the <b>libexiv2</b> API.
*/
namespace Internal {
// *****************************************************************************
// class definitions
/*!
@brief Abstract base class defining the interface of an image header.
Used internally by classes for TIFF-based images. Default
implementation is for the regular TIFF header.
*/
class TiffHeaderBase {
public:
//! @name Creators
//@{
//! Constructor taking \em tag, \em size and default \em byteOrder and \em offset.
TiffHeaderBase(uint16_t tag,
uint32_t size,
ByteOrder byteOrder,
uint32_t offset);
//! Virtual destructor.
virtual ~TiffHeaderBase() =0;
//@}
//! @name Manipulators
//@{
/*!
@brief Read the image header from a data buffer. Return false if the
data buffer does not contain an image header of the expected
format, else true.
@param pData Pointer to the data buffer.
@param size Number of bytes in the data buffer.
@return True if the TIFF header was read successfully. False if the
data buffer does not contain a valid TIFF header.
*/
virtual bool read(const byte* pData, uint32_t size);
//! Set the byte order.
virtual void setByteOrder(ByteOrder byteOrder);
//! Set the offset to the start of the root directory.
virtual void setOffset(uint32_t offset);
//@}
//! @name Accessors
//@{
/*!
@brief Write the image header to the binary image \em blob.
This method appends to the blob.
@param blob Binary image to add to.
@return Number of bytes written.
*/
virtual uint32_t write(Blob& blob) const;
/*!
@brief Print debug info for the image header to \em os.
@param os Output stream to write to.
@param prefix Prefix to be written before each line of output.
*/
virtual void print(std::ostream& os, const std::string& prefix ="") const;
//! Return the byte order (little or big endian).
virtual ByteOrder byteOrder() const;
//! Return the offset to the start of the root directory.
virtual uint32_t offset() const;
//! Return the size (in bytes) of the image header.
virtual uint32_t size() const;
//! Return the tag value (magic number) which identifies the buffer as TIFF data
virtual uint16_t tag() const;
//@}
private:
// DATA
const uint16_t tag_; //!< Tag to identify the buffer as TIFF data
const uint32_t size_; //!< Size of the header
ByteOrder byteOrder_; //!< Applicable byte order
uint32_t offset_; //!< Offset to the start of the root dir
}; // class TiffHeaderBase
/*!
@brief Standard TIFF header structure.
*/
class TiffHeade2 : public TiffHeaderBase {
public:
//! @name Creators
//@{
//! Default constructor
TiffHeade2(ByteOrder byteOrder =littleEndian);
//! Destructor
~TiffHeade2();
//@}
}; // class TiffHeade2
/*!
@brief TIFF component factory for standard TIFF components.
*/
class TiffCreator {
public:
/*!
@brief Create the TiffComponent for TIFF entry \em extendedTag and
\em group based on the embedded lookup table. If the pointer
that is returned is 0, then the TIFF entry should be ignored.
*/
static std::auto_ptr<TiffComponent> create(uint32_t extendedTag,
uint16_t group);
/*!
@brief Get the path, i.e., a list of TiffStructure pointers, from
the root TIFF element to the TIFF entry \em extendedTag and
\em group.
*/
static void getPath(TiffPath& tiffPath,
uint32_t extendedTag,
uint16_t group);
private:
static const TiffStructure tiffStructure_[]; //<! TIFF structure
}; // class TiffCreator
/*!
@brief Stateless parser class for data in TIFF format. Images use this
class to decode and encode TIFF-based data.
*/
class TiffParserWorker {
public:
/*!
@brief Decode TIFF metadata from a data buffer \em pData of length
\em size into the provided metadata containers.
This is the entry point to access image data in TIFF format. The
parser uses classes TiffHeade2 and the TiffComponent and TiffVisitor
hierarchies.
@param exifData Exif metadata container.
@param iptcData IPTC metadata container.
@param xmpData XMP metadata container.
@param pData Pointer to the data buffer. Must point to data
in TIFF format; no checks are performed.
@param size Length of the data buffer.
@param createFct Factory function to create new TIFF components.
@param findDecoderFct Function to access special decoding info.
@param pHeader Optional pointer to a TIFF header. If not provided,
a standard TIFF header is used.
@return Byte order in which the data is encoded, invalidByteOrder if
decoding failed.
*/
static ByteOrder decode(
ExifData& exifData,
IptcData& iptcData,
XmpData& xmpData,
const byte* pData,
uint32_t size,
TiffCompFactoryFct createFct,
FindDecoderFct findDecoderFct,
TiffHeaderBase* pHeader =0);
/*!
@brief Encode TIFF metadata from the metadata containers into a
memory block \em blob.
*/
static WriteMethod encode(
Blob& blob,
const byte* pData,
uint32_t size,
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData,
TiffCompFactoryFct createFct,
FindEncoderFct findEncoderFct,
TiffHeaderBase* pHeader
);
private:
/*!
@brief Parse TIFF metadata from a data buffer \em pData of length
\em size into a TIFF composite structure.
@param pData Pointer to the data buffer. Must point to data
in TIFF format; no checks are performed.
@param size Length of the data buffer.
@return An auto pointer with the root element of the TIFF
composite structure. If \em pData is 0 or \em size
is 0, the return value is a 0 pointer.
*/
static std::auto_ptr<TiffComponent>
parse(const byte* pData,
uint32_t size,
TiffCompFactoryFct createFct,
TiffHeaderBase* pHeader);
}; // class TiffParserWorker
/*!
@brief Table of TIFF decoding and encoding functions and find functions.
This class is separated from the metadata decoder and encoder
visitors so that the parser can be parametrized with a different
table if needed. This is used, eg., for CR2 format, which uses a
different decoder table.
*/
class TiffMapping {
public:
/*!
@brief Find the decoder function for a key.
If the returned pointer is 0, the tag should not be decoded,
else the decoder function should be used.
@param make Camera make
@param extendedTag Extended tag
@param group %Group
@return Pointer to the decoder function
*/
static DecoderFct findDecoder(const std::string& make,
uint32_t extendedTag,
uint16_t group);
/*!
@brief Find special encoder function for a key.
If the returned pointer is 0, the tag should be encoded with the
encoder function of the TIFF component, else the encoder function
should be used.
@param make Camera make
@param extendedTag Extended tag
@param group %Group
@return Pointer to the encoder function
*/
static EncoderFct findEncoder(
const std::string& make,
uint32_t extendedTag,
uint16_t group
);
private:
static const TiffMappingInfo tiffMappingInfo_[]; //<! TIFF mapping table
}; // class TiffMapping
}} // namespace Internal, Exiv2
#endif // #ifndef TIFFIMAGE_INT_HPP_

@ -0,0 +1,212 @@
// ***************************************************************** -*- C++ -*-
// tiffmn-test.cpp, $Rev$
// Makernote TIFF writer tests.
#include "tiffimage.hpp"
#include "exif.hpp"
#include "error.hpp"
#include <string>
#include <iostream>
#include <iomanip>
using namespace Exiv2;
void canonmn(const std::string& path);
void fujimn(const std::string& path);
void minoltamn(const std::string& path);
void nikon1mn(const std::string& path);
void nikon2mn(const std::string& path);
void nikon3mn(const std::string& path);
void olympusmn(const std::string& path);
void panasonicmn(const std::string& path);
void sigmamn(const std::string& path);
void sony1mn(const std::string& path);
void sony2mn(const std::string& path);
void print(const ExifData& exifData);
int main()
try {
canonmn("exiv2-canonmn.tif");
fujimn("exiv2-fujimn.tif");
minoltamn("exiv2-minoltamn.tif");
nikon1mn("exiv2-nikon1mn.tif");
nikon2mn("exiv2-nikon2mn.tif");
nikon3mn("exiv2-nikon3mn.tif");
olympusmn("exiv2-olympusmn.tif");
panasonicmn("exiv2-panasonicmn.tif");
sigmamn("exiv2-sigmamn.tif");
sony1mn("exiv2-sony1mn.tif");
sony2mn("exiv2-sony2mn.tif");
return 0;
}
catch (const Error& e) {
std::cout << e << "\n";
}
void canonmn(const std::string& path)
{
TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false);
ExifData& exifData = tiffImage.exifData();
exifData["Exif.Image.Make"] = "Canon";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
exifData["Exif.Canon.OwnerName"] = "Camera Owner";
print(exifData);
tiffImage.writeMetadata();
}
void fujimn(const std::string& path)
{
TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false);
ExifData& exifData = tiffImage.exifData();
exifData["Exif.Image.Make"] = "FUJIFILM";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
exifData["Exif.Fujifilm.Quality"] = "Very good";
print(exifData);
tiffImage.writeMetadata();
}
void minoltamn(const std::string& path)
{
TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false);
ExifData& exifData = tiffImage.exifData();
exifData["Exif.Image.Make"] = "Minolta";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
exifData["Exif.Minolta.Quality"] = uint32_t(42);
print(exifData);
tiffImage.writeMetadata();
}
void nikon1mn(const std::string& path)
{
TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false);
ExifData& exifData = tiffImage.exifData();
exifData["Exif.Image.Make"] = "NIKON";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
exifData["Exif.Nikon1.Quality"] = "Excellent";
print(exifData);
tiffImage.writeMetadata();
}
void nikon2mn(const std::string& path)
{
TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false);
ExifData& exifData = tiffImage.exifData();
exifData["Exif.Image.Make"] = "NIKON";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
exifData["Exif.Nikon2.Quality"] = uint16_t(42);
print(exifData);
tiffImage.writeMetadata();
}
void nikon3mn(const std::string& path)
{
TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false);
ExifData& exifData = tiffImage.exifData();
exifData["Exif.Image.Make"] = "NIKON";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
exifData["Exif.Nikon3.Quality"] = "Nikon3 quality";
print(exifData);
tiffImage.writeMetadata();
}
void olympusmn(const std::string& path)
{
TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false);
ExifData& exifData = tiffImage.exifData();
exifData["Exif.Image.Make"] = "OLYMPUS";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
exifData["Exif.Olympus.Quality"] = uint16_t(42);
print(exifData);
tiffImage.writeMetadata();
}
void panasonicmn(const std::string& path)
{
TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false);
ExifData& exifData = tiffImage.exifData();
exifData["Exif.Image.Make"] = "Panasonic";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
exifData["Exif.Panasonic.Quality"] = uint16_t(42);
print(exifData);
tiffImage.writeMetadata();
}
void sigmamn(const std::string& path)
{
TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false);
ExifData& exifData = tiffImage.exifData();
exifData["Exif.Image.Make"] = "SIGMA";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
exifData["Exif.Sigma.Quality"] = "Sigma quality";
print(exifData);
tiffImage.writeMetadata();
}
void sony1mn(const std::string& path)
{
TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false);
ExifData& exifData = tiffImage.exifData();
exifData["Exif.Image.Make"] = "SONY";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
exifData["Exif.Sony.0x2000"] = uint16_t(42);
print(exifData);
tiffImage.writeMetadata();
}
void sony2mn(const std::string& path)
{
TiffImage tiffImage(BasicIo::AutoPtr(new FileIo(path)), false);
ExifData& exifData = tiffImage.exifData();
exifData["Exif.Image.Make"] = "SONY";
exifData["Exif.Photo.DateTimeOriginal"] = "Yesterday at noon";
exifData["Exif.Sony.0x2001"] = uint16_t(43);
print(exifData);
tiffImage.writeMetadata();
}
void print(const ExifData& exifData)
{
if (exifData.empty()) {
std::string error("No Exif data found in the file");
throw Exiv2::Error(1, error);
}
Exiv2::ExifData::const_iterator end = exifData.end();
for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != end; ++i) {
std::cout << std::setw(44) << std::setfill(' ') << std::left
<< i->key() << " "
<< "0x" << std::setw(4) << std::setfill('0') << std::right
<< std::hex << i->tag() << " "
<< std::setw(9) << std::setfill(' ') << std::left
<< i->typeName() << " "
<< std::dec << std::setw(3)
<< std::setfill(' ') << std::right
<< i->count() << " "
<< std::dec << i->value()
<< "\n";
}
}

@ -1,214 +0,0 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*
File: tiffparser.cpp
Version: $Rev$
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 15-Mar-06, ahu: created
*/
// *****************************************************************************
#include "rcsid.hpp"
EXIV2_RCSID("@(#) $Id$")
// *****************************************************************************
// included header files
#ifdef _MSC_VER
# include "exv_msvc.h"
#else
# include "exv_conf.h"
#endif
#include "types.hpp"
#include "tiffparser.hpp"
#include "tiffcomposite.hpp"
#include "makernote2.hpp"
#include "tiffvisitor.hpp"
#include "tiffimage.hpp"
#include "error.hpp"
// + standard includes
#include <cassert>
#include <memory>
/* --------------------------------------------------------------------------
Todo:
+ Add further child mgmt stuff to TIFF composite: remove
+ Review boundary checking, is it better to check the offsets?
+ Define and implement consistent error handling for recursive hierarchy
+ Make TiffImage a template StandardImage, which can be parametrized with
a parser and the necessary checking functions to cover all types of
images which need to be loaded completely.
+ TiffComponent: should it have end() and setEnd() or pData and size?
+ Can NewTiffCompFct and TiffCompFactoryFct be combined?
+ Create function is repeated when actually only the table changes. Fix it.
+ Is it easier (for writing) to combine all creation tables into one?
+ CR2 Makernotes don't seem to have a next pointer but Canon Jpeg Makernotes
do. What a mess. (That'll become an issue when it comes to writing to CR2)
+ Sony makernotes in RAW files do not seem to have header like those in Jpegs.
And maybe no next pointer either.
+ Filtering of large unknown tags: Should be moved to writing/encoding code
and done only if really needed (i.e., if writing to a Jpeg segment)
in crwimage.* :
+ Fix CiffHeader according to TiffHeade2
+ Combine Error(15) and Error(33), add format argument %1
+ Search crwimage for todos, fix writeMetadata comment
+ rename all Ciff stuff to Crw for easier reference
-------------------------------------------------------------------------- */
// *****************************************************************************
// class member definitions
namespace Exiv2 {
/*
This table describes the standard TIFF layout (including non-standard
Makernote structures) and determines the corresponding Exiv2 TIFF
components. The key of the table consists of the first two attributes,
(extended) tag and group. Tag is the TIFF tag or one of a few extended
tags, group identifies the IFD or any other composite TIFF component.
Each entry of the table defines for a particular tag and group
combination, which create function is used and what the group of the new
component is.
*/
const TiffStructure TiffCreator::tiffStructure_[] = {
// ext. tag group create function new group
//--------- -------------- ------------------- --------------
{ Tag::root, Group::none, newTiffDirectory, Group::ifd0 },
{ 0x8769, Group::ifd0, newTiffSubIfd, Group::exif },
{ 0x8825, Group::ifd0, newTiffSubIfd, Group::gps },
{ 0xa005, Group::exif, newTiffSubIfd, Group::iop },
{ 0x927c, Group::exif, newTiffMnEntry, Group::mn },
{ 0x0111, Group::ifd1, newTiffThumbData<0x0117, Group::ifd1>, Group::ifd1 },
{ 0x0117, Group::ifd1, newTiffThumbSize<0x0111, Group::ifd1>, Group::ifd1 },
{ 0x0201, Group::ifd1, newTiffThumbData<0x0202, Group::ifd1>, Group::ifd1 },
{ 0x0202, Group::ifd1, newTiffThumbSize<0x0201, Group::ifd1>, Group::ifd1 },
{ Tag::next, Group::ifd0, newTiffDirectory, Group::ifd1 },
{ Tag::next, Group::ifd1, newTiffDirectory, Group::ignr },
{ Tag::next, Group::ignr, newTiffDirectory, Group::ignr },
// SubIfd found in NEF images
{ 0x014a, Group::ifd0, newTiffSubIfd, Group::sub0_0 },
// Canon makernote structure
{ 0x0001, Group::canonmn, newTiffArrayEntry<2>, Group::canoncs },
{ 0x0004, Group::canonmn, newTiffArrayEntry<2>, Group::canonsi },
{ 0x0005, Group::canonmn, newTiffArrayEntry<2>, Group::canonpa },
{ 0x000f, Group::canonmn, newTiffArrayEntry<2>, Group::canoncf },
{ 0x0012, Group::canonmn, newTiffArrayEntry<2>, Group::canonpi },
{ Tag::all, Group::canoncs, newTiffArrayElement<unsignedShort>, Group::canoncs },
{ Tag::all, Group::canonsi, newTiffArrayElement<unsignedShort>, Group::canonsi },
{ Tag::all, Group::canonpa, newTiffArrayElement<unsignedShort>, Group::canonpa },
{ Tag::all, Group::canoncf, newTiffArrayElement<unsignedShort>, Group::canoncf },
{ Tag::all, Group::canonpi, newTiffArrayElement<unsignedShort>, Group::canonpi },
// Some Olympus cameras use Minolta structures
{ 0x0001, Group::olympmn, newTiffArrayEntry<4>, Group::minocso },
{ 0x0003, Group::olympmn, newTiffArrayEntry<4>, Group::minocsn },
// Minolta makernote structure
{ 0x0001, Group::minoltamn, newTiffArrayEntry<4>, Group::minocso },
{ 0x0003, Group::minoltamn, newTiffArrayEntry<4>, Group::minocsn },
{ 0x0004, Group::minoltamn, newTiffArrayEntry<2>, Group::minocs7 },
{ 0x0114, Group::minoltamn, newTiffArrayEntry<2>, Group::minocs5 },
{ Tag::all, Group::minocso, newTiffArrayElement<unsignedLong, bigEndian>, Group::minocso },
{ Tag::all, Group::minocsn, newTiffArrayElement<unsignedLong, bigEndian>, Group::minocsn },
{ Tag::all, Group::minocs7, newTiffArrayElement<unsignedShort, bigEndian>, Group::minocs7 },
{ Tag::all, Group::minocs5, newTiffArrayElement<unsignedShort, bigEndian>, Group::minocs5 }
};
// TIFF Decoder table for special decoding requirements, default decoder is decodeStdTiffEntry
const TiffDecoderInfo TiffDecoder::tiffDecoderInfo_[] = {
{ "*", Tag::all, Group::ignr, 0 }, // Do not decode tags with group == Group::ignr
{ "OLYMPUS", 0x0100, Group::olympmn, &TiffMetadataDecoder::decodeOlympThumb },
{ "*", 0x014a, Group::ifd0, 0 }, // Todo: Controversial, causes problems with Exiftool
{ "*", Tag::all, Group::sub0_0, &TiffMetadataDecoder::decodeSubIfd },
{ "*", Tag::all, Group::sub0_1, &TiffMetadataDecoder::decodeSubIfd },
{ "*", 0x02bc, Group::ifd0, &TiffMetadataDecoder::decodeXmp },
{ "*", 0x83bb, Group::ifd0, &TiffMetadataDecoder::decodeIptc },
{ "*", 0x8649, Group::ifd0, &TiffMetadataDecoder::decodeIptc }
};
DecoderFct TiffDecoder::findDecoder(const std::string& make,
uint32_t extendedTag,
uint16_t group)
{
DecoderFct decoderFct = &TiffMetadataDecoder::decodeStdTiffEntry;
const TiffDecoderInfo* td = find(tiffDecoderInfo_,
TiffDecoderInfo::Key(make, extendedTag, group));
if (td) {
// This may set decoderFct to 0, meaning that the tag should not be decoded
decoderFct = td->decoderFct_;
}
return decoderFct;
}
TiffComponent::AutoPtr TiffCreator::create(uint32_t extendedTag,
uint16_t group)
{
TiffComponent::AutoPtr tc(0);
uint16_t tag = static_cast<uint16_t>(extendedTag & 0xffff);
const TiffStructure* ts = find(tiffStructure_,
TiffStructure::Key(extendedTag, group));
if (ts && ts->newTiffCompFct_) {
tc = ts->newTiffCompFct_(tag, ts);
}
if (!ts && extendedTag != Tag::next) {
tc = TiffComponent::AutoPtr(new TiffEntry(tag, group));
}
return tc;
} // TiffCreator::create
void TiffParser::decode(Image* pImage,
const byte* pData,
uint32_t size,
TiffCompFactoryFct createFct,
FindDecoderFct findDecoderFct,
TiffHeaderBase* pHeader)
{
assert(pImage != 0);
assert(pData != 0);
std::auto_ptr<TiffHeaderBase> ph;
if (!pHeader) {
ph = std::auto_ptr<TiffHeaderBase>(new TiffHeade2);
pHeader = ph.get();
}
if (!pHeader->read(pData, size) || pHeader->offset() >= size) {
throw Error(3, "TIFF");
}
TiffComponent::AutoPtr rootDir = createFct(Tag::root, Group::none);
if (0 == rootDir.get()) return;
rootDir->setStart(pData + pHeader->offset());
TiffRwState::AutoPtr state(
new TiffRwState(pHeader->byteOrder(), 0, createFct));
TiffReader reader(pData, size, rootDir.get(), state);
rootDir->accept(reader);
TiffMetadataDecoder decoder(pImage, rootDir.get(), findDecoderFct, 4096);
rootDir->accept(decoder);
} // TiffParser::decode
} // namespace Exiv2

@ -1,132 +0,0 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*!
@file tiffparser.hpp
@brief Class TiffParser to parse TIFF data.
@version $Rev$
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 15-Mar-06, ahu: created
*/
#ifndef TIFFPARSER_HPP_
#define TIFFPARSER_HPP_
// *****************************************************************************
// included header files
#include "tifffwd.hpp"
#include "types.hpp"
// + standard includes
#include <iosfwd>
#include <cassert>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
/*!
@brief TIFF component factory for standard TIFF components.
*/
class TiffCreator {
public:
/*!
@brief Create the TiffComponent for TIFF entry \em extendedTag and
\em group based on the embedded lookup table.
If a tag and group combination is not found in the table, a TiffEntry
is created. If the pointer that is returned is 0, then the TIFF entry
should be ignored.
*/
static std::auto_ptr<TiffComponent> create(uint32_t extendedTag,
uint16_t group);
private:
static const TiffStructure tiffStructure_[]; //<! TIFF structure
}; // class TiffCreator
/*!
@brief Stateless parser class for data in TIFF format. Images use this
class to decode and encode TIFF-based data. Uses class
CreationPolicy for the creation of TIFF components.
*/
class TiffParser {
public:
/*!
@brief Decode TIFF metadata from a data buffer \em pData of length
\em size into \em pImage.
This is the entry point to access image data in TIFF format. The
parser uses classes TiffHeade2 and the TiffComponent and TiffVisitor
hierarchies.
@param pImage Pointer to the image to hold the metadata
@param pData Pointer to the data buffer. Must point to data
in TIFF format; no checks are performed.
@param size Length of the data buffer.
@param createFct Factory function to create new TIFF components.
@param findDecoderFct Function to access special decoding info.
@param pHeader Optional pointer to a TIFF header. If not provided,
a standard TIFF header is used.
*/
static void decode( Image* pImage,
const byte* pData,
uint32_t size,
TiffCompFactoryFct createFct,
FindDecoderFct findDecoderFct,
TiffHeaderBase* pHeader =0);
}; // class TiffParser
/*!
@brief Table of TIFF decoding functions and find function.
This class is separated from the metadata decoder visitor so that
the parser can be parametrized with a different table if needed.
This is used, eg., for CR2 format, which uses a different decoder
table.
*/
class TiffDecoder {
public:
/*!
@brief Find the decoder function for a key.
If the returned pointer is 0, the tag should not be decoded,
else the decoder function should be used.
@param make Camera make
@param extendedTag Extended tag
@param group %Group
@return Pointer to the decoder function
*/
static DecoderFct findDecoder(const std::string& make,
uint32_t extendedTag,
uint16_t group);
private:
static const TiffDecoderInfo tiffDecoderInfo_[]; //<! TIFF decoder table
}; // class TiffDecoder
} // namespace Exiv2
#endif // #ifndef TIFFPARSER_HPP_

File diff suppressed because it is too large Load Diff

@ -19,20 +19,21 @@
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*!
@file tiffvisitor.hpp
@brief Operations on a TIFF composite tree, implemented as visitor classes.
@file tiffvisitor_int.hpp
@brief Internal operations on a TIFF composite tree, implemented as visitor
classes.
@version $Rev$
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 11-Apr-06, ahu: created
*/
#ifndef TIFFVISITOR_HPP_
#define TIFFVISITOR_HPP_
#ifndef TIFFVISITOR_INT_HPP_
#define TIFFVISITOR_INT_HPP_
// *****************************************************************************
// included header files
#include "exif.hpp"
#include "tifffwd.hpp"
#include "tifffwd_int.hpp"
#include "types.hpp"
// + standard includes
@ -45,6 +46,7 @@
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
namespace Internal {
// *****************************************************************************
// class definitions
@ -65,11 +67,25 @@ namespace Exiv2 {
@endcode
*/
class TiffVisitor {
public:
//! Events for the stop/go flag. See setGo().
enum GoEvent {
//! Signal to control traversing of the composite tree.
geTraverse = 0,
//! Signal used by TiffReader to signal an unknown makernote.
geKnownMakernote = 1
// Note: If you add more events here, adjust the events_ constant too!
};
private:
static const int events_ = 2; //!< The number of stop/go flags.
bool go_[events_]; //!< Array of stop/go flags. See setGo().
public:
//! @name Creators
//@{
//! Default constructor
TiffVisitor() : go_(true) {}
//! Default constructor. Initialises all stop/go flags to true.
TiffVisitor();
//! Virtual destructor
virtual ~TiffVisitor() {}
//@}
@ -79,19 +95,21 @@ namespace Exiv2 {
/*!
@brief Set the stop/go flag: true for go, false for stop.
This mechanism can be used by concrete visitors to signal certain
events. For example, TiffFinder sets the stop flag as soon as it finds
the correct component to signal to that the search should be
stopped. TiffReader uses it to signal problems reading a makernote.
As the flag doesn't carry any information on the type of event which
triggered it, it is for each visitor to establish and adhere to
conventions about its meaning.
This mechanism is used by visitors and components to signal special
events. Specifically, TiffFinder sets the geTraverse flag as soon as
it finds the correct component to signal to components that the search
should be aborted. TiffReader uses geKnownMakernote to signal problems
reading a makernote to the TiffMnEntry component. There is an array
of flags, one for each defined \em event, so different signals can be
used independent of each other.
*/
void setGo(bool go) { go_ = go; }
void setGo(GoEvent event, bool go);
//! Operation to perform for a TIFF entry
virtual void visitEntry(TiffEntry* object) =0;
//! Operation to perform for a TIFF data entry
virtual void visitDataEntry(TiffDataEntry* object) =0;
//! Operation to perform for a TIFF image entry
virtual void visitImageEntry(TiffImageEntry* object) =0;
//! Operation to perform for a TIFF size entry
virtual void visitSizeEntry(TiffSizeEntry* object) =0;
//! Operation to perform for a TIFF directory
@ -122,13 +140,10 @@ namespace Exiv2 {
//! @name Accessors
//@{
//! Check if stop flag is clear, return true if it's clear.
bool go() { return go_; }
//! Check if stop flag for \em event is clear, return true if it's clear.
bool go(GoEvent event) const;
//@}
private:
bool go_; //!< Set this to false to abort the iteration
}; // class TiffVisitor
/*!
@ -141,7 +156,7 @@ namespace Exiv2 {
public:
//! @name Creators
//@{
//! Constructor, taking the image to add the metadata to
//! Constructor, taking \em tag and \em group of the component to find.
TiffFinder(uint16_t tag, uint16_t group)
: tag_(tag), group_(group), tiffComponent_(0) {}
//! Virtual destructor
@ -154,6 +169,8 @@ namespace Exiv2 {
virtual void visitEntry(TiffEntry* object);
//! Find tag and group in a TIFF data entry
virtual void visitDataEntry(TiffDataEntry* object);
//! Find tag and group in a TIFF image entry
virtual void visitImageEntry(TiffImageEntry* object);
//! Find tag and group in a TIFF size entry
virtual void visitSizeEntry(TiffSizeEntry* object);
//! Find tag and group in a TIFF directory
@ -196,23 +213,24 @@ namespace Exiv2 {
pattern). Used by TiffParser to decode the metadata from a
TIFF composite.
*/
class TiffMetadataDecoder : public TiffVisitor {
class TiffDecoder : public TiffVisitor {
public:
//! @name Creators
//@{
/*!
@brief Constructor, taking the image to add the metadata to, the root
element of the composite to decode and an optional
threshold. Unknown tags with values larger (in bytes) than the
threshold will be ignored. Default is not to ignore any
tags (0).
@brief Constructor, taking metadata containers to add the metadata to,
the root element of the composite to decode and a FindDecoderFct
function to get the decoder function for each tag.
*/
TiffMetadataDecoder(Image* pImage,
TiffComponent* const pRoot,
FindDecoderFct findDecoderFct =0,
uint32_t threshold =0);
TiffDecoder(
ExifData& exifData,
IptcData& iptcData,
XmpData& xmpData,
TiffComponent* const pRoot,
FindDecoderFct findDecoderFct
);
//! Virtual destructor
virtual ~TiffMetadataDecoder() {}
virtual ~TiffDecoder() {}
//@}
//! @name Manipulators
@ -221,6 +239,8 @@ namespace Exiv2 {
virtual void visitEntry(TiffEntry* object);
//! Decode a TIFF data entry
virtual void visitDataEntry(TiffDataEntry* object);
//! Decode a TIFF image entry
virtual void visitImageEntry(TiffImageEntry* object);
//! Decode a TIFF size entry
virtual void visitSizeEntry(TiffSizeEntry* object);
//! Decode a TIFF directory
@ -251,6 +271,8 @@ namespace Exiv2 {
//@}
private:
//! @name Manipulators
//@{
//! Set an Exif tag in the image. Overwrites existing tags
void setExifTag(const ExifKey& key, const Value* pValue);
/*!
@ -266,12 +288,15 @@ namespace Exiv2 {
uint16_t tag,
uint16_t group,
const TiffEntryBase* object);
//@}
private:
// DATA
Image* pImage_; //!< Pointer to the image to which the metadata is added
ExifData& exifData_; //!< Exif metadata container
IptcData& iptcData_; //!< IPTC metadata container
XmpData& xmpData_; //!< XMP metadata container
TiffComponent* const pRoot_; //!< Root element of the composite
const FindDecoderFct findDecoderFct_; //!< Ptr to the function to find special decoding functions
const uint32_t threshold_; //!< Threshold, see constructor documentation.
std::string make_; //!< Camera make, determined from the tags to decode
//! Type used to remember tag 0x00fe (NewSubfileType) for each group
@ -279,7 +304,193 @@ namespace Exiv2 {
GroupType groupType_; //!< NewSubfileType for each group
bool decodedIptc_; //!< Indicates if IPTC has been decoded yet
}; // class TiffMetadataDecoder
}; // class TiffDecoder
/*!
@brief TIFF composite visitor to encode metadata from an image to the TIFF
tree. The metadata containers and root element of the tree are
supplied in the constructor. Used by TiffParserWorker to encode the
metadata into a TIFF composite.
For non-intrusive writing, the encoder is used as a visitor (by
passing it to the accept() member of a TiffComponent). The
composite tree is then traversed and metadata from the image is
used to encode each existing component.
For intrusive writing, add() is called, which loops through the
metadata and creates and populates corresponding TiffComponents
as needed.
*/
class TiffEncoder : public TiffVisitor {
public:
//! @name Creators
//@{
/*!
@brief Constructor, taking the root element of the composite to encode
to, the image with the metadata to encode and a function to
find special encoders.
*/
TiffEncoder(
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData,
TiffComponent* pRoot,
ByteOrder byteOrder,
FindEncoderFct findEncoderFct
);
//! Virtual destructor
virtual ~TiffEncoder() {}
//@}
//! @name Manipulators
//@{
//! Encode a TIFF entry
virtual void visitEntry(TiffEntry* object);
//! Encode a TIFF data entry
virtual void visitDataEntry(TiffDataEntry* object);
//! Encode a TIFF image entry
virtual void visitImageEntry(TiffImageEntry* object);
//! Encode a TIFF size entry
virtual void visitSizeEntry(TiffSizeEntry* object);
//! Encode a TIFF directory
virtual void visitDirectory(TiffDirectory* object);
//! Update directory entries
virtual void visitDirectoryNext(TiffDirectory* object);
//! Encode a TIFF sub-IFD
virtual void visitSubIfd(TiffSubIfd* object);
//! Encode a TIFF makernote
virtual void visitMnEntry(TiffMnEntry* object);
//! Encode an IFD makernote
virtual void visitIfdMakernote(TiffIfdMakernote* object);
//! Reset encoder to its original state, undo makernote specific settings
virtual void visitIfdMakernoteEnd(TiffIfdMakernote* object);
//! Encode an array entry component
virtual void visitArrayEntry(TiffArrayEntry* object);
//! Encode an array element
virtual void visitArrayElement(TiffArrayElement* object);
/*!
@brief Top level encoder function. Determines how to encode each TIFF
component. This function is called by the visit methods of the
encoder as well as the add() method.
If no \em datum is provided, search the metadata based on tag and
group of the \em object. This is the case if the function is called
from a visit method.
Then check if a special encoder function is registered for the tag,
and if so use it to encode the \em object. Else use the callback
encoder function at the object (which results in a double-dispatch to
the appropriate encoding function of the encoder.
@param object Object in the TIFF component tree to encode.
@param datum The corresponding metadatum with the updated value.
@note Encoder functions may use metadata other than \em datum.
*/
void encodeTiffComponent(
TiffEntryBase* object,
const Exifdatum* datum =0
);
//! Callback encoder function for an array element.
void encodeArrayElement(TiffArrayElement* object, const Exifdatum* datum);
//! Callback encoder function for an array entry.
void encodeArrayEntry(TiffArrayEntry* object, const Exifdatum* datum);
//! Callback encoder function for a data entry.
void encodeDataEntry(TiffDataEntry* object, const Exifdatum* datum);
//! Callback encoder function for a standard TIFF entry
void encodeTiffEntry(TiffEntry* object, const Exifdatum* datum);
//! Callback encoder function for an image entry.
void encodeImageEntry(TiffImageEntry* object, const Exifdatum* datum);
//! Callback encoder function for a %Makernote entry.
void encodeMnEntry(TiffMnEntry* object, const Exifdatum* datum);
//! Callback encoder function for a size entry.
void encodeSizeEntry(TiffSizeEntry* object, const Exifdatum* datum);
//! Callback encoder function for a sub-IFD entry.
void encodeSubIfd(TiffSubIfd* object, const Exifdatum* datum);
//! Special encoder function for the base part of a TIFF entry.
void encodeTiffEntryBase(TiffEntryBase* object, const Exifdatum* datum);
//! Special encoder function for an offset entry.
void encodeOffsetEntry(TiffEntryBase* object, const Exifdatum* datum);
//! Special encoder function to encode an Olympus Thumbnail from the TIFF makernote into IFD1.
void encodeOlympThumb(TiffEntryBase* object, const Exifdatum* datum);
//! Special encoder function to encode SubIFD contents to Image group if it contains primary image data
// Todo void encodeNikonSubIfd(TiffEntryBase* object, const Exifdatum* datum);
//! Special encoder function to encode IPTC data to an IPTCNAA or Photoshop ImageResources tag.
void encodeIptc(TiffEntryBase* object, const Exifdatum* datum);
//! Special encoder function to encode an XMP packet to an XMLPacket tag.
void encodeXmp(TiffEntryBase* object, const Exifdatum* datum);
//! Special encoder function for a standard TIFF entry using big endian byte order.
void encodeBigEndianEntry(TiffEntryBase* object, const Exifdatum* datum);
/*!
@brief Add metadata from image to the TIFF composite.
For each Exif metadatum, the corresponding TiffComponent is created
if necessary and populated using encodeTiffComponent(). The add() function
is used during intrusive writing, to create a new TIFF structure.
@note For non-intrusive writing, the encoder is used as a visitor (by
passing it to the accept() member of a TiffComponent). The composite
tree is then traversed and metadata from the image is used to encode
each existing component.
*/
void add(
TiffComponent* pRootDir,
TiffComponent* pSourceDir,
TiffCompFactoryFct createFct
);
//! Set the dirty flag and end of traversing signal.
void setDirty(bool flag =true);
//@}
//! @name Accessors
//@{
/*!
@brief Return the applicable byte order. May be different for
the Makernote and the rest of the TIFF entries.
*/
ByteOrder byteOrder() const { return byteOrder_; }
/*!
@brief True if any tag was deleted or allocated in the process of
visiting a TIFF composite tree.
*/
bool dirty() const;
//! Return the write method used.
WriteMethod writeMethod() const { return writeMethod_; }
//@}
private:
//! @name Accessors
//@{
/*!
@brief Update a directory entry. This is called after all directory
entries are encoded. It takes care of type and count changes
and size shrinkage for non-intrusive writing.
*/
uint32_t updateDirEntry(byte* buf,
ByteOrder byteOrder,
TiffComponent* pTiffComponent) const;
//@}
private:
// DATA
ExifData exifData_; //!< Copy of the Exif data to encode
IptcData iptcData_; //!< Copy of the IPTC data to encode
XmpData xmpData_; //!< Copy of the XMP data to encode
bool del_; //!< Indicates if Exif data entries should be deleted after encoding
TiffComponent* pRoot_; //!< Root element of the composite
TiffComponent* pSourceTree_; //!< Parsed source tree for reference
ByteOrder byteOrder_; //!< Byteorder for encoding
ByteOrder origByteOrder_; //!< Byteorder as set in the c'tor
const FindEncoderFct findEncoderFct_; //!< Ptr to the function to find special encoding functions
std::string make_; //!< Camera make, determined from the tags to encode
bool dirty_; //!< Signals if any tag is deleted or allocated
WriteMethod writeMethod_; //!< Write method used.
}; // class TiffEncoder
/*!
@brief Simple state class containing relevant state information for
@ -355,7 +566,7 @@ namespace Exiv2 {
@param pData Pointer to the data buffer, starting with a TIFF header.
@param size Number of bytes in the data buffer.
@param pRoot Root element of the TIFF composite.
@param state State object for creation function, byteorder and
@param state State object for creation function, byte order and
base offset.
*/
TiffReader(const byte* pData,
@ -373,6 +584,8 @@ namespace Exiv2 {
virtual void visitEntry(TiffEntry* object);
//! Read a TIFF data entry from the data buffer
virtual void visitDataEntry(TiffDataEntry* object);
//! Read a TIFF image entry from the data buffer
virtual void visitImageEntry(TiffImageEntry* object);
//! Read a TIFF size entry from the data buffer
virtual void visitSizeEntry(TiffSizeEntry* object);
//! Read a TIFF directory from the data buffer
@ -392,6 +605,8 @@ namespace Exiv2 {
//! Read a standard TIFF entry from the data buffer
void readTiffEntry(TiffEntryBase* object);
//! Read a TiffDataEntryBase from the data buffer
void readDataEntryBase(TiffDataEntryBase* object);
//! Set the \em state class. Assumes ownership of the object passed in.
void changeState(TiffRwState::AutoPtr state);
//! Reset the state to the original state as set in the constructor.
@ -409,13 +624,6 @@ namespace Exiv2 {
uint16_t group) const;
//@}
private:
//! @name Manipulators
//@{
//! Helper function to set the thumbnail data area
void setDataArea(TiffEntryBase* pOffsetEntry, const Value* pSize);
//@}
private:
// DATA
const byte* pData_; //!< Pointer to the memory buffer
@ -448,6 +656,8 @@ namespace Exiv2 {
virtual void visitEntry(TiffEntry* object);
//! Print a TIFF data entry.
virtual void visitDataEntry(TiffDataEntry* object);
//! Print a TIFF image entry.
virtual void visitImageEntry(TiffImageEntry* object);
//! Print a TIFF size entry.
virtual void visitSizeEntry(TiffSizeEntry* object);
//! Print a TIFF directory
@ -490,6 +700,6 @@ namespace Exiv2 {
static const std::string indent_; //!< Indent for one level
}; // class TiffPrinter
} // namespace Exiv2
}} // namespace Internal, Exiv2
#endif // #ifndef TIFFVISITOR_HPP_
#endif // #ifndef TIFFVISITOR_INT_HPP_

@ -43,6 +43,7 @@
// + standard includes
#include <string>
#include <vector>
#include <iosfwd>
#include <utility>
#include <algorithm>
@ -89,6 +90,9 @@ namespace Exiv2 {
//! Type to express the byte order (little or big endian)
enum ByteOrder { invalidByteOrder, littleEndian, bigEndian };
//! Type to indicate write method used by TIFF parsers
enum WriteMethod { wmIntrusive, wmNonIntrusive };
//! An identifier for each type of metadata
enum MetadataId { mdNone=0, mdExif=1, mdIptc=2, mdComment=4, mdXmp=8 };
@ -123,6 +127,9 @@ namespace Exiv2 {
valueData, directoryData,
lastDataLocId };
//! Container for binary data
typedef std::vector<byte> Blob;
// *****************************************************************************
// class definitions

@ -244,6 +244,7 @@ namespace Exiv2 {
long StringValueBase::copy(byte* buf, ByteOrder /*byteOrder*/) const
{
if (value_.size() == 0) return 0;
// byteOrder not needed
assert(buf != 0);
return static_cast<long>(
@ -463,7 +464,7 @@ namespace Exiv2 {
std::ostringstream os;
write(os);
std::string s = os.str();
std::memcpy(buf, &s[0], s.size());
std::memcpy(buf, &s[0], s.size());
return static_cast<long>(s.size());
}
@ -725,7 +726,7 @@ namespace Exiv2 {
float LangAltValue::toFloat(long /*n*/) const
{
ok_ = false;
return 0.0;
return 0.0f;
}
Rational LangAltValue::toRational(long /*n*/) const

@ -1552,6 +1552,7 @@ namespace Exiv2 {
inline long ValueType<Rational>::toLong(long n) const
{
ok_ = (value_[n].second != 0);
if (!ok_) return 0;
return value_[n].first / value_[n].second;
}
// Specialization for unsigned rational
@ -1559,6 +1560,7 @@ namespace Exiv2 {
inline long ValueType<URational>::toLong(long n) const
{
ok_ = (value_[n].second != 0);
if (!ok_) return 0;
return value_[n].first / value_[n].second;
}
// Default implementation
@ -1573,6 +1575,7 @@ namespace Exiv2 {
inline float ValueType<Rational>::toFloat(long n) const
{
ok_ = (value_[n].second != 0);
if (!ok_) return 0.0f;
return static_cast<float>(value_[n].first) / value_[n].second;
}
// Specialization for unsigned rational
@ -1580,6 +1583,7 @@ namespace Exiv2 {
inline float ValueType<URational>::toFloat(long n) const
{
ok_ = (value_[n].second != 0);
if (!ok_) return 0.0f;
return static_cast<float>(value_[n].first) / value_[n].second;
}
// Default implementation

@ -0,0 +1,35 @@
// ***************************************************************** -*- C++ -*-
// xmpdump.cpp, $Rev$
// Sample program to dump the XMP packet of an image
#include "image.hpp"
#include <string>
#include <iostream>
#include <cassert>
int main(int argc, char* const argv[])
try {
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " file\n";
return 1;
}
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(argv[1]);
assert(image.get() != 0);
image->readMetadata();
const std::string& xmpPacket = image->xmpPacket();
if (xmpPacket.empty()) {
std::string error(argv[1]);
error += ": No XMP packet found in the file";
throw Exiv2::Error(1, error);
}
std::cout << xmpPacket << "\n";
return 0;
}
catch (Exiv2::AnyError& e) {
std::cout << "Caught Exiv2 exception '" << e << "'\n";
return -1;
}

@ -57,10 +57,22 @@ SHELL = /bin/sh
.PHONY: all test clean distclean maintainer-clean
# Add test drivers to this list
TESTS = addmoddel.sh bugfixes-test.sh crw-test.sh exifdata-test.sh \
exiv2-test.sh ifd-test.sh imagetest.sh iotest.sh iptctest.sh \
makernote-test.sh modify-test.sh path-test.sh stringto-test.sh \
write-test.sh write2-test.sh xmpparser-test.sh conversions.sh
TESTS = addmoddel.sh \
bugfixes-test.sh \
crw-test.sh \
exifdata-test.sh \
exiv2-test.sh \
imagetest.sh \
iotest.sh \
iptctest.sh \
modify-test.sh \
path-test.sh \
stringto-test.sh \
tiff-test.sh \
write-test.sh \
write2-test.sh \
xmpparser-test.sh \
conversions.sh
test:
@list='$(TESTS)'; for p in $$list; do \

@ -8,5 +8,5 @@ Deleted key "Exif.Image.PrimaryChromaticities"
0x0115 Image SamplesPerPixel Short 1 162
0x011a Image XResolution SLong 1 -2
0x011b Image YResolution SRational 1 -2/3
0x8769 Image ExifTag Long 1 89
0x8769 Image ExifTag Long 1 90
0x9003 Photo DateTimeOriginal Ascii 20 2000:12:31 23:59:59

@ -96,12 +96,12 @@ Iptc.Application2.LocationName String 12 Kuala Lumpur
Testcase 14
===========
Exif.Image.ExifTag Long 1 38
Exif.Image.GPSTag Long 1 134
Exif.Photo.ExifVersion Undefined 4 48 50 50 49
Exif.Photo.DateTimeOriginal Ascii 20 2003:12:14 12:01:44
Exif.Photo.ComponentsConfiguration Undefined 4 1 2 3 0
Exif.Photo.Flash Short 1 73
Exif.Photo.SubSecTimeOriginal Ascii 10 999999999
Exif.Image.GPSTag Long 1 134
Exif.GPSInfo.GPSVersionID Byte 4 2 2 0 1
Exif.GPSInfo.GPSLatitudeRef Ascii 2 N
Exif.GPSInfo.GPSLatitude Rational 3 3/1 8/1 29734512/1000000
@ -150,12 +150,12 @@ Xmp.tiff.DateTime XmpText 20 2003-12-14T12:01:44Z
Xmp.photoshop.DateCreated XmpText 10 2007-05-09
Exif.Image.DateTime Ascii 20 2003:12:14 20:01:44
Exif.Image.ExifTag Long 1 70
Exif.Image.GPSTag Long 1 166
Exif.Photo.ExifVersion Undefined 4 48 50 50 49
Exif.Photo.DateTimeOriginal Ascii 20 2003:12:14 12:01:44
Exif.Photo.ComponentsConfiguration Undefined 4 1 2 3 0
Exif.Photo.Flash Short 1 73
Exif.Photo.SubSecTimeOriginal Ascii 10 999999999
Exif.Image.GPSTag Long 1 166
Exif.GPSInfo.GPSVersionID Byte 4 2 2 0 1
Exif.GPSInfo.GPSLatitudeRef Ascii 2 N
Exif.GPSInfo.GPSLatitude Rational 3 3/1 8/1 1858407/62500

@ -7,7 +7,7 @@ Exif.Image.XResolution 0x011a IFD0 Rational 1
Exif.Image.YResolution 0x011b IFD0 Rational 1 72/1
Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2
Exif.Image.Software 0x0131 IFD0 Ascii 22 DC-4300 Ver1.03
Exif.Image.DateTime 0x0132 IFD0 Ascii 20 Sunday, 11am
Exif.Image.DateTime 0x0132 IFD0 Ascii 13 Sunday, 11am
Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2
Exif.Image.ExifTag 0x8769 IFD0 Long 1 6480
Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/95
@ -15,7 +15,7 @@ Exif.Photo.FNumber 0x829d Exif Rational 1
Exif.Photo.ExposureProgram 0x8822 Exif Short 1 8
Exif.Photo.ISOSpeedRatings 0x8827 Exif Short 1 100
Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 49 48
Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 20 Sunday, 11am
Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 13 Sunday, 11am
Exif.Photo.DateTimeDigitized 0x9004 Exif Ascii 20 2004:06:08 16:04:50
Exif.Photo.ComponentsConfiguration 0x9101 Exif Undefined 4 1 2 3 0
Exif.Photo.ShutterSpeedValue 0x9201 Exif SRational 1 66/10
@ -30,14 +30,14 @@ Exif.Photo.ColorSpace 0xa001 Exif Short 1
Exif.Photo.PixelXDimension 0xa002 Exif Long 1 1600
Exif.Photo.PixelYDimension 0xa003 Exif Long 1 2400
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 6738
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123
Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Thumbnail.ImageWidth 0x0100 IFD1 Long 1 133
Exif.Thumbnail.ImageLength 0x0101 IFD1 Long 1 200
Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6
Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 1
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 196
Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 6144
----------------------------------------------
Copy construction, intrusive changes
@ -51,7 +51,7 @@ Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1
Exif.Image.Software 0x0131 IFD0 Ascii 22 DC-4300 Ver1.03
Exif.Image.DateTime 0x0132 IFD0 Ascii 29 Sunday, 11am and ten minutes
Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2
Exif.Image.ExifTag 0x8769 IFD0 Long 1 263
Exif.Image.ExifTag 0x8769 IFD0 Long 1 264
Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/95
Exif.Photo.FNumber 0x829d Exif Rational 1 91/10
Exif.Photo.ExposureProgram 0x8822 Exif Short 1 8
@ -71,15 +71,15 @@ Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4
Exif.Photo.ColorSpace 0xa001 Exif Short 1 1
Exif.Photo.PixelXDimension 0xa002 Exif Long 1 1600
Exif.Photo.PixelYDimension 0xa003 Exif Long 1 2400
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 630
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 632
Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 5 1234
Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Thumbnail.ImageWidth 0x0100 IFD1 Long 1 133
Exif.Thumbnail.ImageLength 0x0101 IFD1 Long 1 200
Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6
Exif.Thumbnail.Orientation 0x0112 IFD1 Short 5 2 3 4 5 6
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 756
Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 6144
----------------------------------------------
Assignment, non-intrusive changes
@ -91,15 +91,15 @@ Exif.Image.XResolution 0x011a IFD0 Rational 1
Exif.Image.YResolution 0x011b IFD0 Rational 1 72/1
Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2
Exif.Image.Software 0x0131 IFD0 Ascii 22 DC-4300 Ver1.03
Exif.Image.DateTime 0x0132 IFD0 Ascii 20 Sunday, 11am
Exif.Image.DateTime 0x0132 IFD0 Ascii 13 Sunday, 11am
Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2
Exif.Image.ExifTag 0x8769 IFD0 Long 1 6480
Exif.Image.ExifTag 0x8769 IFD0 Long 1 264
Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/95
Exif.Photo.FNumber 0x829d Exif Rational 1 91/10
Exif.Photo.ExposureProgram 0x8822 Exif Short 1 8
Exif.Photo.ISOSpeedRatings 0x8827 Exif Short 1 100
Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 49 48
Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 20 Sunday, 11am
Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 13 Sunday, 11am
Exif.Photo.DateTimeDigitized 0x9004 Exif Ascii 20 2004:06:08 16:04:50
Exif.Photo.ComponentsConfiguration 0x9101 Exif Undefined 4 1 2 3 0
Exif.Photo.ShutterSpeedValue 0x9201 Exif SRational 1 66/10
@ -113,15 +113,15 @@ Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4
Exif.Photo.ColorSpace 0xa001 Exif Short 1 1
Exif.Photo.PixelXDimension 0xa002 Exif Long 1 1600
Exif.Photo.PixelYDimension 0xa003 Exif Long 1 2400
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 6738
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 632
Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123
Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Thumbnail.ImageWidth 0x0100 IFD1 Long 1 133
Exif.Thumbnail.ImageLength 0x0101 IFD1 Long 1 200
Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6
Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 1
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0
Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 2
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 756
Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 6144
----------------------------------------------
Assignment, intrusive changes
@ -135,7 +135,7 @@ Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1
Exif.Image.Software 0x0131 IFD0 Ascii 22 DC-4300 Ver1.03
Exif.Image.DateTime 0x0132 IFD0 Ascii 29 Sunday, 11am and ten minutes
Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2
Exif.Image.ExifTag 0x8769 IFD0 Long 1 263
Exif.Image.ExifTag 0x8769 IFD0 Long 1 264
Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/95
Exif.Photo.FNumber 0x829d Exif Rational 1 91/10
Exif.Photo.ExposureProgram 0x8822 Exif Short 1 8
@ -155,15 +155,15 @@ Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4
Exif.Photo.ColorSpace 0xa001 Exif Short 1 1
Exif.Photo.PixelXDimension 0xa002 Exif Long 1 1600
Exif.Photo.PixelYDimension 0xa003 Exif Long 1 2400
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 618
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 620
Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123
Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Thumbnail.ImageWidth 0x0100 IFD1 Long 1 133
Exif.Thumbnail.ImageLength 0x0101 IFD1 Long 1 200
Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6
Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 2
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 728
Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 6144
Copy construction, non-intrusive changes
Exif.Image.Make 0x010f IFD0 Ascii 6 Canon
@ -172,13 +172,13 @@ Exif.Image.Orientation 0x0112 IFD0 Short 1
Exif.Image.XResolution 0x011a IFD0 Rational 1 180/1
Exif.Image.YResolution 0x011b IFD0 Rational 1 180/1
Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2
Exif.Image.DateTime 0x0132 IFD0 Ascii 20 Sunday, 11am
Exif.Image.DateTime 0x0132 IFD0 Ascii 13 Sunday, 11am
Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 1
Exif.Image.ExifTag 0x8769 IFD0 Long 1 196
Exif.Image.ExifTag 0x8769 IFD0 Long 1 178
Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/500
Exif.Photo.FNumber 0x829d Exif Rational 1 49/10
Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 50 48
Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 20 Sunday, 11am
Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 13 Sunday, 11am
Exif.Photo.DateTimeDigitized 0x9004 Exif Ascii 20 2003:12:14 12:01:44
Exif.Photo.ComponentsConfiguration 0x9101 Exif Undefined 4 1 2 3 0
Exif.Photo.CompressedBitsPerPixel 0x9102 Exif Rational 1 5/1
@ -189,32 +189,8 @@ Exif.Photo.MaxApertureValue 0x9205 Exif Rational 1
Exif.Photo.MeteringMode 0x9207 Exif Short 1 1
Exif.Photo.Flash 0x9209 Exif Short 1 24
Exif.Photo.FocalLength 0x920a Exif Rational 1 682/32
Exif.Photo.UserComment 0x9286 Exif Undefined 264
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 1
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1416
Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280
Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210
Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215
Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0
Exif.Canon.0x0000 0x0000 Makernote Short 6 0 0 0 0 0 0
Exif.Canon.0x0000 0x0000 Makernote Short 4 0 0 0 0
Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG
Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10
Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771
Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel
Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328
Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0
Exif.CanonCs.Macro 0x0001 Makernote Short 1 2
Exif.CanonCs.Selftimer 0x0002 Makernote Short 1 0
Exif.CanonCs.Quality 0x0003 Makernote Short 1 5
@ -252,6 +228,8 @@ Exif.CanonCs.ZoomSourceWidth 0x0024 Makernote Short 1
Exif.CanonCs.ZoomTargetWidth 0x0025 Makernote Short 1 2272
Exif.CanonCs.0x0026 0x0026 Makernote Short 1 0
Exif.CanonCs.0x0027 0x0027 Makernote Short 1 1
Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215
Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0
Exif.CanonSi.0x0001 0x0001 Makernote Short 1 0
Exif.CanonSi.ISOSpeed 0x0002 Makernote Short 1 160
Exif.CanonSi.0x0003 0x0003 Makernote Short 1 276
@ -278,15 +256,37 @@ Exif.CanonSi.0x0017 0x0017 Makernote Short 1
Exif.CanonSi.0x0018 0x0018 Makernote Short 1 0
Exif.CanonSi.0x0019 0x0019 Makernote Short 1 0
Exif.CanonSi.0x001a 0x001a Makernote Short 1 250
Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG
Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10
Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771
Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel
Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0
Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328
Exif.Photo.UserComment 0x9286 Exif Undefined 264
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 1
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1372
Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123
Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48
Exif.Iop.RelatedImageWidth 0x1001 Iop Short 1 2272
Exif.Iop.RelatedImageLength 0x1002 Iop Short 1 1704
Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280
Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210
Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6
Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 180/1
Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 180/1
Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 1520
Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 5448
----------------------------------------------
Copy construction, intrusive changes
@ -298,7 +298,7 @@ Exif.Image.YResolution 0x011b IFD0 Rational 1
Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2
Exif.Image.DateTime 0x0132 IFD0 Ascii 29 Sunday, 11am and ten minutes
Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 1
Exif.Image.ExifTag 0x8769 IFD0 Long 1 201
Exif.Image.ExifTag 0x8769 IFD0 Long 1 202
Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/500
Exif.Photo.FNumber 0x829d Exif Rational 1 49/10
Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 50 48
@ -313,32 +313,8 @@ Exif.Photo.MaxApertureValue 0x9205 Exif Rational 1
Exif.Photo.MeteringMode 0x9207 Exif Short 6 1 2 3 4 5 6
Exif.Photo.Flash 0x9209 Exif Short 1 24
Exif.Photo.FocalLength 0x920a Exif Rational 1 682/32
Exif.Photo.UserComment 0x9286 Exif Undefined 264
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 1
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1442
Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280
Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210
Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215
Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0
Exif.Canon.0x0000 0x0000 Makernote Short 6 0 0 0 0 0 0
Exif.Canon.0x0000 0x0000 Makernote Short 4 0 0 0 0
Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG
Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10
Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771
Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel
Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328
Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0
Exif.CanonCs.Macro 0x0001 Makernote Short 1 2
Exif.CanonCs.Selftimer 0x0002 Makernote Short 1 0
Exif.CanonCs.Quality 0x0003 Makernote Short 1 5
@ -376,6 +352,8 @@ Exif.CanonCs.ZoomSourceWidth 0x0024 Makernote Short 1
Exif.CanonCs.ZoomTargetWidth 0x0025 Makernote Short 1 2272
Exif.CanonCs.0x0026 0x0026 Makernote Short 1 0
Exif.CanonCs.0x0027 0x0027 Makernote Short 1 1
Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215
Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0
Exif.CanonSi.0x0001 0x0001 Makernote Short 1 0
Exif.CanonSi.ISOSpeed 0x0002 Makernote Short 1 160
Exif.CanonSi.0x0003 0x0003 Makernote Short 1 276
@ -402,16 +380,38 @@ Exif.CanonSi.0x0017 0x0017 Makernote Short 1
Exif.CanonSi.0x0018 0x0018 Makernote Short 1 0
Exif.CanonSi.0x0019 0x0019 Makernote Short 1 0
Exif.CanonSi.0x001a 0x001a Makernote Short 1 250
Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG
Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10
Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771
Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel
Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0
Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328
Exif.Photo.UserComment 0x9286 Exif Undefined 264
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 1
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1424
Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 5 1234
Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48
Exif.Iop.RelatedImageWidth 0x1001 Iop Short 1 2272
Exif.Iop.RelatedImageLength 0x1002 Iop Short 1 1704
Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280
Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210
Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6
Exif.Thumbnail.Orientation 0x0112 IFD1 Short 5 2 3 4 5 6
Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 180/1
Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 180/1
Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 1600
Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 5448
----------------------------------------------
Assignment, non-intrusive changes
@ -421,13 +421,13 @@ Exif.Image.Orientation 0x0112 IFD0 Short 1
Exif.Image.XResolution 0x011a IFD0 Rational 1 180/1
Exif.Image.YResolution 0x011b IFD0 Rational 1 180/1
Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2
Exif.Image.DateTime 0x0132 IFD0 Ascii 20 Sunday, 11am
Exif.Image.DateTime 0x0132 IFD0 Ascii 13 Sunday, 11am
Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 1
Exif.Image.ExifTag 0x8769 IFD0 Long 1 196
Exif.Image.ExifTag 0x8769 IFD0 Long 1 202
Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/500
Exif.Photo.FNumber 0x829d Exif Rational 1 49/10
Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 50 48
Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 20 Sunday, 11am
Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 13 Sunday, 11am
Exif.Photo.DateTimeDigitized 0x9004 Exif Ascii 20 2003:12:14 12:01:44
Exif.Photo.ComponentsConfiguration 0x9101 Exif Undefined 4 1 2 3 0
Exif.Photo.CompressedBitsPerPixel 0x9102 Exif Rational 1 5/1
@ -438,32 +438,8 @@ Exif.Photo.MaxApertureValue 0x9205 Exif Rational 1
Exif.Photo.MeteringMode 0x9207 Exif Short 1 1
Exif.Photo.Flash 0x9209 Exif Short 1 24
Exif.Photo.FocalLength 0x920a Exif Rational 1 682/32
Exif.Photo.UserComment 0x9286 Exif Undefined 264
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 1
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1416
Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280
Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210
Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215
Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0
Exif.Canon.0x0000 0x0000 Makernote Short 6 0 0 0 0 0 0
Exif.Canon.0x0000 0x0000 Makernote Short 4 0 0 0 0
Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG
Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10
Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771
Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel
Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328
Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0
Exif.CanonCs.Macro 0x0001 Makernote Short 1 2
Exif.CanonCs.Selftimer 0x0002 Makernote Short 1 0
Exif.CanonCs.Quality 0x0003 Makernote Short 1 5
@ -501,6 +477,8 @@ Exif.CanonCs.ZoomSourceWidth 0x0024 Makernote Short 1
Exif.CanonCs.ZoomTargetWidth 0x0025 Makernote Short 1 2272
Exif.CanonCs.0x0026 0x0026 Makernote Short 1 0
Exif.CanonCs.0x0027 0x0027 Makernote Short 1 1
Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215
Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0
Exif.CanonSi.0x0001 0x0001 Makernote Short 1 0
Exif.CanonSi.ISOSpeed 0x0002 Makernote Short 1 160
Exif.CanonSi.0x0003 0x0003 Makernote Short 1 276
@ -527,15 +505,38 @@ Exif.CanonSi.0x0017 0x0017 Makernote Short 1
Exif.CanonSi.0x0018 0x0018 Makernote Short 1 0
Exif.CanonSi.0x0019 0x0019 Makernote Short 1 0
Exif.CanonSi.0x001a 0x001a Makernote Short 1 250
Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG
Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10
Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771
Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel
Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0
Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328
Exif.Photo.UserComment 0x9286 Exif Undefined 264
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 1
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1424
Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123
Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48
Exif.Iop.RelatedImageWidth 0x1001 Iop Short 1 2272
Exif.Iop.RelatedImageLength 0x1002 Iop Short 1 1704
Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280
Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210
Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6
Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 2
Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 180/1
Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 180/1
Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 1600
Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 5448
----------------------------------------------
Assignment, intrusive changes
@ -547,7 +548,7 @@ Exif.Image.YResolution 0x011b IFD0 Rational 1
Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2
Exif.Image.DateTime 0x0132 IFD0 Ascii 29 Sunday, 11am and ten minutes
Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 1
Exif.Image.ExifTag 0x8769 IFD0 Long 1 201
Exif.Image.ExifTag 0x8769 IFD0 Long 1 202
Exif.Photo.ExposureTime 0x829a Exif Rational 1 1/500
Exif.Photo.FNumber 0x829d Exif Rational 1 49/10
Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 50 48
@ -562,32 +563,8 @@ Exif.Photo.MaxApertureValue 0x9205 Exif Rational 1
Exif.Photo.MeteringMode 0x9207 Exif Short 1 1
Exif.Photo.Flash 0x9209 Exif Short 1 24
Exif.Photo.FocalLength 0x920a Exif Rational 1 682/32
Exif.Photo.UserComment 0x9286 Exif Undefined 264
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 1
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1430
Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280
Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210
Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215
Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0
Exif.Canon.0x0000 0x0000 Makernote Short 6 0 0 0 0 0 0
Exif.Canon.0x0000 0x0000 Makernote Short 4 0 0 0 0
Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG
Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10
Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771
Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel
Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328
Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0
Exif.CanonCs.Macro 0x0001 Makernote Short 1 2
Exif.CanonCs.Selftimer 0x0002 Makernote Short 1 0
Exif.CanonCs.Quality 0x0003 Makernote Short 1 5
@ -625,6 +602,8 @@ Exif.CanonCs.ZoomSourceWidth 0x0024 Makernote Short 1
Exif.CanonCs.ZoomTargetWidth 0x0025 Makernote Short 1 2272
Exif.CanonCs.0x0026 0x0026 Makernote Short 1 0
Exif.CanonCs.0x0027 0x0027 Makernote Short 1 1
Exif.Canon.0x0002 0x0002 Makernote Short 4 2 682 286 215
Exif.Canon.0x0003 0x0003 Makernote Short 4 0 0 0 0
Exif.CanonSi.0x0001 0x0001 Makernote Short 1 0
Exif.CanonSi.ISOSpeed 0x0002 Makernote Short 1 160
Exif.CanonSi.0x0003 0x0003 Makernote Short 1 276
@ -651,16 +630,38 @@ Exif.CanonSi.0x0017 0x0017 Makernote Short 1
Exif.CanonSi.0x0018 0x0018 Makernote Short 1 0
Exif.CanonSi.0x0019 0x0019 Makernote Short 1 0
Exif.CanonSi.0x001a 0x001a Makernote Short 1 250
Exif.Canon.ImageType 0x0006 Makernote Ascii 32 IMG:PowerShot S40 JPEG
Exif.Canon.FirmwareVersion 0x0007 Makernote Ascii 24 Firmware Version 1.10
Exif.Canon.ImageNumber 0x0008 Makernote Long 1 1171771
Exif.Canon.OwnerName 0x0009 Makernote Ascii 32 Andreas Huggel
Exif.Canon.0x000d 0x000d Makernote Short 21 42 3 32769 378 32769 0 0 0 259 2 0 10 0 0 0 57 198 5 0 0 0
Exif.Canon.ModelID 0x0010 Makernote Long 1 17891328
Exif.Photo.UserComment 0x9286 Exif Undefined 264
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 1
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 2272
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 1704
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 1412
Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123
Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48
Exif.Iop.RelatedImageWidth 0x1001 Iop Short 1 2272
Exif.Iop.RelatedImageLength 0x1002 Iop Short 1 1704
Exif.Photo.FocalPlaneXResolution 0xa20e Exif Rational 1 2272000/280
Exif.Photo.FocalPlaneYResolution 0xa20f Exif Rational 1 1704000/210
Exif.Photo.FocalPlaneResolutionUnit 0xa210 Exif Short 1 2
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 2272/2272
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6
Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 2
Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 180/1
Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 180/1
Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 1572
Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 5448
Copy construction, non-intrusive changes
Exif.Image.Make 0x010f IFD0 Ascii 18 NIKON CORPORATION
@ -670,7 +671,7 @@ Exif.Image.XResolution 0x011a IFD0 Rational 1
Exif.Image.YResolution 0x011b IFD0 Rational 1 300/1
Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2
Exif.Image.Software 0x0131 IFD0 Ascii 10 Ver.1.01
Exif.Image.DateTime 0x0132 IFD0 Ascii 20 Sunday, 11am
Exif.Image.DateTime 0x0132 IFD0 Ascii 13 Sunday, 11am
Exif.Image.WhitePoint 0x013e IFD0 Rational 2 313/1000 329/1000
Exif.Image.PrimaryChromaticities 0x013f IFD0 Rational 6 64/100 33/100 21/100 71/100 15/100 6/100
Exif.Image.YCbCrCoefficients 0x0211 IFD0 Rational 3 299/1000 587/1000 114/1000
@ -680,7 +681,7 @@ Exif.Photo.ExposureTime 0x829a Exif Rational 1
Exif.Photo.FNumber 0x829d Exif Rational 1 90/10
Exif.Photo.ExposureProgram 0x8822 Exif Short 1 2
Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 50 49
Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 20 Sunday, 11am
Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 13 Sunday, 11am
Exif.Photo.DateTimeDigitized 0x9004 Exif Ascii 20 2004:03:30 10:43:46
Exif.Photo.ComponentsConfiguration 0x9101 Exif Undefined 4 1 2 3 0
Exif.Photo.CompressedBitsPerPixel 0x9102 Exif Rational 1 4/1
@ -690,31 +691,6 @@ Exif.Photo.MeteringMode 0x9207 Exif Short 1
Exif.Photo.LightSource 0x9208 Exif Short 1 0
Exif.Photo.Flash 0x9209 Exif Short 1 0
Exif.Photo.FocalLength 0x920a Exif Rational 1 500/10
Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii"
Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00
Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00
Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 30306
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.SceneType 0xa301 Exif Undefined 1 1
Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1
Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Photo.GainControl 0xa407 Exif Short 1 0
Exif.Photo.Contrast 0xa408 Exif Short 1 0
Exif.Photo.Saturation 0xa409 Exif Short 1 0
Exif.Photo.Sharpness 0xa40a Exif Short 1 0
Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0
Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10
Exif.Nikon3.Version 0x0001 Makernote Undefined 4 48 50 49 48
Exif.Nikon3.ISOSpeed 0x0002 Makernote Short 2 0 200
Exif.Nikon3.Quality 0x0004 Makernote Ascii 8 FINE
@ -757,13 +733,38 @@ Exif.Nikon3.0x00a8 0x00a8 Makernote Undefined 20
Exif.Nikon3.ImageOptimization 0x00a9 Makernote Ascii 16 NORMAL
Exif.Nikon3.Saturation 0x00aa Makernote Ascii 16 NORMAL
Exif.Nikon3.VariProgram 0x00ab Makernote Ascii 16
Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii"
Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00
Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00
Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 30306
Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123
Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.SceneType 0xa301 Exif Undefined 1 1
Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1
Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Photo.GainControl 0xa407 Exif Short 1 0
Exif.Photo.Contrast 0xa408 Exif Short 1 0
Exif.Photo.Saturation 0xa409 Exif Short 1 0
Exif.Photo.Sharpness 0xa40a Exif Short 1 0
Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0
Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10
Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6
Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 300/1
Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 300/1
Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 30444
Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 8930
Exif.Thumbnail.YCbCrPositioning 0x0213 IFD1 Short 1 2
----------------------------------------------
@ -780,7 +781,7 @@ Exif.Image.WhitePoint 0x013e IFD0 Rational 2
Exif.Image.PrimaryChromaticities 0x013f IFD0 Rational 6 64/100 33/100 21/100 71/100 15/100 6/100
Exif.Image.YCbCrCoefficients 0x0211 IFD0 Rational 3 299/1000 587/1000 114/1000
Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2
Exif.Image.ExifTag 0x8769 IFD0 Long 1 349
Exif.Image.ExifTag 0x8769 IFD0 Long 1 350
Exif.Photo.ExposureTime 0x829a Exif Rational 1 10/2500
Exif.Photo.FNumber 0x829d Exif Rational 1 90/10
Exif.Photo.ExposureProgram 0x8822 Exif Short 1 2
@ -795,31 +796,6 @@ Exif.Photo.MeteringMode 0x9207 Exif Short 6
Exif.Photo.LightSource 0x9208 Exif Short 1 0
Exif.Photo.Flash 0x9209 Exif Short 1 0
Exif.Photo.FocalLength 0x920a Exif Rational 1 500/10
Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii"
Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00
Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00
Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 2425
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.SceneType 0xa301 Exif Undefined 1 1
Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1
Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Photo.GainControl 0xa407 Exif Short 1 0
Exif.Photo.Contrast 0xa408 Exif Short 1 0
Exif.Photo.Saturation 0xa409 Exif Short 1 0
Exif.Photo.Sharpness 0xa40a Exif Short 1 0
Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0
Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10
Exif.Nikon3.Version 0x0001 Makernote Undefined 4 48 50 49 48
Exif.Nikon3.ISOSpeed 0x0002 Makernote Short 2 0 200
Exif.Nikon3.Quality 0x0004 Makernote Ascii 8 FINE
@ -862,14 +838,39 @@ Exif.Nikon3.0x00a8 0x00a8 Makernote Undefined 20
Exif.Nikon3.ImageOptimization 0x00a9 Makernote Ascii 16 NORMAL
Exif.Nikon3.Saturation 0x00aa Makernote Ascii 16 NORMAL
Exif.Nikon3.VariProgram 0x00ab Makernote Ascii 16
Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii"
Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00
Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00
Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 2438
Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 5 1234
Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.SceneType 0xa301 Exif Undefined 1 1
Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1
Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Photo.GainControl 0xa407 Exif Short 1 0
Exif.Photo.Contrast 0xa408 Exif Short 1 0
Exif.Photo.Saturation 0xa409 Exif Short 1 0
Exif.Photo.Sharpness 0xa40a Exif Short 1 0
Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0
Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10
Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6
Exif.Thumbnail.Orientation 0x0112 IFD1 Short 5 2 3 4 5 6
Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 300/1
Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 300/1
Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 2602
Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 8930
Exif.Thumbnail.YCbCrPositioning 0x0213 IFD1 Short 1 2
----------------------------------------------
@ -881,17 +882,17 @@ Exif.Image.XResolution 0x011a IFD0 Rational 1
Exif.Image.YResolution 0x011b IFD0 Rational 1 300/1
Exif.Image.ResolutionUnit 0x0128 IFD0 Short 1 2
Exif.Image.Software 0x0131 IFD0 Ascii 10 Ver.1.01
Exif.Image.DateTime 0x0132 IFD0 Ascii 20 Sunday, 11am
Exif.Image.DateTime 0x0132 IFD0 Ascii 13 Sunday, 11am
Exif.Image.WhitePoint 0x013e IFD0 Rational 2 313/1000 329/1000
Exif.Image.PrimaryChromaticities 0x013f IFD0 Rational 6 64/100 33/100 21/100 71/100 15/100 6/100
Exif.Image.YCbCrCoefficients 0x0211 IFD0 Rational 3 299/1000 587/1000 114/1000
Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2
Exif.Image.ExifTag 0x8769 IFD0 Long 1 340
Exif.Image.ExifTag 0x8769 IFD0 Long 1 350
Exif.Photo.ExposureTime 0x829a Exif Rational 1 10/2500
Exif.Photo.FNumber 0x829d Exif Rational 1 90/10
Exif.Photo.ExposureProgram 0x8822 Exif Short 1 2
Exif.Photo.ExifVersion 0x9000 Exif Undefined 4 48 50 50 49
Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 20 Sunday, 11am
Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 13 Sunday, 11am
Exif.Photo.DateTimeDigitized 0x9004 Exif Ascii 20 2004:03:30 10:43:46
Exif.Photo.ComponentsConfiguration 0x9101 Exif Undefined 4 1 2 3 0
Exif.Photo.CompressedBitsPerPixel 0x9102 Exif Rational 1 4/1
@ -901,31 +902,6 @@ Exif.Photo.MeteringMode 0x9207 Exif Short 1
Exif.Photo.LightSource 0x9208 Exif Short 1 0
Exif.Photo.Flash 0x9209 Exif Short 1 0
Exif.Photo.FocalLength 0x920a Exif Rational 1 500/10
Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii"
Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00
Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00
Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 30306
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.SceneType 0xa301 Exif Undefined 1 1
Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1
Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Photo.GainControl 0xa407 Exif Short 1 0
Exif.Photo.Contrast 0xa408 Exif Short 1 0
Exif.Photo.Saturation 0xa409 Exif Short 1 0
Exif.Photo.Sharpness 0xa40a Exif Short 1 0
Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0
Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10
Exif.Nikon3.Version 0x0001 Makernote Undefined 4 48 50 49 48
Exif.Nikon3.ISOSpeed 0x0002 Makernote Short 2 0 200
Exif.Nikon3.Quality 0x0004 Makernote Ascii 8 FINE
@ -968,13 +944,39 @@ Exif.Nikon3.0x00a8 0x00a8 Makernote Undefined 20
Exif.Nikon3.ImageOptimization 0x00a9 Makernote Ascii 16 NORMAL
Exif.Nikon3.Saturation 0x00aa Makernote Ascii 16 NORMAL
Exif.Nikon3.VariProgram 0x00ab Makernote Ascii 16
Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii"
Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00
Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00
Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 2438
Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123
Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.SceneType 0xa301 Exif Undefined 1 1
Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1
Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Photo.GainControl 0xa407 Exif Short 1 0
Exif.Photo.Contrast 0xa408 Exif Short 1 0
Exif.Photo.Saturation 0xa409 Exif Short 1 0
Exif.Photo.Sharpness 0xa40a Exif Short 1 0
Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0
Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10
Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6
Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 2
Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 300/1
Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 300/1
Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 2602
Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 8930
Exif.Thumbnail.YCbCrPositioning 0x0213 IFD1 Short 1 2
----------------------------------------------
@ -991,7 +993,7 @@ Exif.Image.WhitePoint 0x013e IFD0 Rational 2
Exif.Image.PrimaryChromaticities 0x013f IFD0 Rational 6 64/100 33/100 21/100 71/100 15/100 6/100
Exif.Image.YCbCrCoefficients 0x0211 IFD0 Rational 3 299/1000 587/1000 114/1000
Exif.Image.YCbCrPositioning 0x0213 IFD0 Short 1 2
Exif.Image.ExifTag 0x8769 IFD0 Long 1 349
Exif.Image.ExifTag 0x8769 IFD0 Long 1 350
Exif.Photo.ExposureTime 0x829a Exif Rational 1 10/2500
Exif.Photo.FNumber 0x829d Exif Rational 1 90/10
Exif.Photo.ExposureProgram 0x8822 Exif Short 1 2
@ -1006,31 +1008,6 @@ Exif.Photo.MeteringMode 0x9207 Exif Short 1
Exif.Photo.LightSource 0x9208 Exif Short 1 0
Exif.Photo.Flash 0x9209 Exif Short 1 0
Exif.Photo.FocalLength 0x920a Exif Rational 1 500/10
Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii"
Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00
Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00
Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 2413
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.SceneType 0xa301 Exif Undefined 1 1
Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1
Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Photo.GainControl 0xa407 Exif Short 1 0
Exif.Photo.Contrast 0xa408 Exif Short 1 0
Exif.Photo.Saturation 0xa409 Exif Short 1 0
Exif.Photo.Sharpness 0xa40a Exif Short 1 0
Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0
Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10
Exif.Nikon3.Version 0x0001 Makernote Undefined 4 48 50 49 48
Exif.Nikon3.ISOSpeed 0x0002 Makernote Short 2 0 200
Exif.Nikon3.Quality 0x0004 Makernote Ascii 8 FINE
@ -1073,13 +1050,38 @@ Exif.Nikon3.0x00a8 0x00a8 Makernote Undefined 20
Exif.Nikon3.ImageOptimization 0x00a9 Makernote Ascii 16 NORMAL
Exif.Nikon3.Saturation 0x00aa Makernote Ascii 16 NORMAL
Exif.Nikon3.VariProgram 0x00ab Makernote Ascii 16
Exif.Photo.UserComment 0x9286 Exif Undefined 44 charset="Ascii"
Exif.Photo.SubSecTime 0x9290 Exif Ascii 3 00
Exif.Photo.SubSecTimeOriginal 0x9291 Exif Ascii 3 00
Exif.Photo.SubSecTimeDigitized 0x9292 Exif Ascii 3 00
Exif.Photo.FlashpixVersion 0xa000 Exif Undefined 4 48 49 48 48
Exif.Photo.ColorSpace 0xa001 Exif Short 1 65535
Exif.Photo.PixelXDimension 0xa002 Exif Short 1 3008
Exif.Photo.PixelYDimension 0xa003 Exif Short 1 2000
Exif.Photo.InteroperabilityTag 0xa005 Exif Long 1 2426
Exif.Iop.InteroperabilityIndex 0x0001 Iop Ascii 4 123
Exif.Iop.InteroperabilityVersion 0x0002 Iop Undefined 4 48 49 48 48
Exif.Photo.SensingMethod 0xa217 Exif Short 1 2
Exif.Photo.FileSource 0xa300 Exif Undefined 1 3
Exif.Photo.SceneType 0xa301 Exif Undefined 1 1
Exif.Photo.CFAPattern 0xa302 Exif Undefined 8 0 2 0 2 2 1 1 0
Exif.Photo.CustomRendered 0xa401 Exif Short 1 0
Exif.Photo.ExposureMode 0xa402 Exif Short 1 0
Exif.Photo.WhiteBalance 0xa403 Exif Short 1 0
Exif.Photo.DigitalZoomRatio 0xa404 Exif Rational 1 1/1
Exif.Photo.FocalLengthIn35mmFilm 0xa405 Exif Short 1 75
Exif.Photo.SceneCaptureType 0xa406 Exif Short 1 0
Exif.Photo.GainControl 0xa407 Exif Short 1 0
Exif.Photo.Contrast 0xa408 Exif Short 1 0
Exif.Photo.Saturation 0xa409 Exif Short 1 0
Exif.Photo.Sharpness 0xa40a Exif Short 1 0
Exif.Photo.SubjectDistanceRange 0xa40c Exif Short 1 0
Exif.Photo.0xa500 0xa500 Exif Rational 1 22/10
Exif.Thumbnail.Compression 0x0103 IFD1 Short 1 6
Exif.Thumbnail.Orientation 0x0112 IFD1 Short 1 2
Exif.Thumbnail.XResolution 0x011a IFD1 Rational 1 300/1
Exif.Thumbnail.YResolution 0x011b IFD1 Rational 1 300/1
Exif.Thumbnail.ResolutionUnit 0x0128 IFD1 Short 1 2
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 0
Exif.Thumbnail.JPEGInterchangeFormat 0x0201 IFD1 Long 1 2574
Exif.Thumbnail.JPEGInterchangeFormatLength 0x0202 IFD1 Long 1 8930
Exif.Thumbnail.YCbCrPositioning 0x0213 IFD1 Short 1 2

Binary file not shown.

@ -17,7 +17,7 @@ File 1/2: exiv2-empty.jpg
exiv2-empty.jpg Exif.Image.DateTime Ascii 19 Zwanzig nach fuenf
exiv2-empty.jpg Exif.Image.Artist Ascii 17 Vincent van Gogh
exiv2-empty.jpg Exif.Image.WhitePoint Short 5 32 12 4 5 6
exiv2-empty.jpg Exif.Image.ExifTag Long 1 108
exiv2-empty.jpg Exif.Image.ExifTag Long 1 110
exiv2-empty.jpg Exif.Photo.UserComment Undefined 37 This is an ASCII Exif comment
File 2/2: exiv2-gc.jpg
exiv2-gc.jpg Exif.Image.ImageDescription Ascii 18 Exif JPEG
@ -27,7 +27,7 @@ exiv2-gc.jpg Exif.Image.Orientation Short 1
exiv2-gc.jpg Exif.Image.XResolution Rational 1 72
exiv2-gc.jpg Exif.Image.YResolution Rational 1 72
exiv2-gc.jpg Exif.Image.ResolutionUnit Short 1 inch
exiv2-gc.jpg Exif.Image.Software Ascii 22 Exiv2 utility!!
exiv2-gc.jpg Exif.Image.Software Ascii 16 Exiv2 utility!!
exiv2-gc.jpg Exif.Image.DateTime Ascii 20 2004:06:08 16:04:50
exiv2-gc.jpg Exif.Image.YCbCrPositioning Short 1 Co-sited
exiv2-gc.jpg Exif.Image.ExifTag Long 1 6480
@ -51,12 +51,12 @@ exiv2-gc.jpg Exif.Photo.ColorSpace Short 1
exiv2-gc.jpg Exif.Photo.PixelXDimension Long 1 1600
exiv2-gc.jpg Exif.Photo.PixelYDimension Long 1 2400
exiv2-gc.jpg Exif.Photo.InteroperabilityTag Long 1 6738
exiv2-gc.jpg Exif.Photo.FileSource Undefined 1 Digital still camera
exiv2-gc.jpg Exif.Iop.InteroperabilityIndex Ascii 4 R98
exiv2-gc.jpg Exif.Iop.InteroperabilityVersion Undefined 4 1.00
exiv2-gc.jpg Exif.Photo.FileSource Undefined 1 Digital still camera
exiv2-gc.jpg Exif.Thumbnail.ImageWidth Long 1 133
exiv2-gc.jpg Exif.Thumbnail.ImageLength Long 1 200
exiv2-gc.jpg Exif.Thumbnail.Compression Short 1 JPEG (old-style)
exiv2-gc.jpg Exif.Thumbnail.Orientation Short 1 top, left
exiv2-gc.jpg Exif.Thumbnail.JPEGInterchangeFormat Long 1 0
exiv2-gc.jpg Exif.Thumbnail.JPEGInterchangeFormat Long 1 196
exiv2-gc.jpg Exif.Thumbnail.JPEGInterchangeFormatLength Long 1 6144

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

@ -0,0 +1,138 @@
File Name = mini9.tif
File Type = TIFF:II
File Size = 526
@000000000=0 : TIFF(II=0x4949) magic=0x002a='*\0' ifd offset = 0xfc/252
@0x00000fc=252 : <IFD 0> 17 entries starting at file offset 0xfe=254
@0x00000fe=254 : <0x00fe= 254> NewSubFileType [4 =LONG 1] = 0 = 'primary'
@0x000010a=266 : <0x0100= 256> ImageWidth [3 =SHORT 1] = 9
@0x0000116=278 : <0x0101= 257> ImageLength [3 =SHORT 1] = 9
@0x0000122=290 : <0x0102= 258> BitsPerSample [3 =SHORT 3] = @0x1ce=462
@0x000012e=302 : <0x0103= 259> Compression [3 =SHORT 1] = 1 = 'uncompressed'
@0x000013a=314 : <0x0106= 262> PhotometricInterpretation [3 =SHORT 1] = 2 = 'RGB'
@0x0000146=326 : <0x010d= 269> DocumentName [2 =ASCII 24] = @0x1d4=468
@0x0000152=338 : <0x010e= 270> ImageDescription [2 =ASCII 18] = @0x1ec=492
@0x000015e=350 : <0x0111= 273> StripOffsets [4 =LONG 1] = @8
@0x000016a=362 : <0x0112= 274> Orientation [3 =SHORT 1] = 1 = '0,0 is top left'
@0x0000176=374 : <0x0115= 277> SamplesPerPixel [3 =SHORT 1] = 3
@0x0000182=386 : <0x0116= 278> RowsPerStrip [3 =SHORT 1] = 64
@0x000018e=398 : <0x0117= 279> StripByteCounts [4 =LONG 1] = 243
@0x000019a=410 : <0x011a= 282> XResolution [5 =RATIONAL 1] = @0x1fe=510
@0x00001a6=422 : <0x011b= 283> YResolution [5 =RATIONAL 1] = @0x206=518
@0x00001b2=434 : <0x011c= 284> PlanarConfiguration [3 =SHORT 1] = 1 = 'chunky/contig'
@0x00001be=446 : <0x0128= 296> ResolutionUnit [3 =SHORT 1] = 2 = 'pixels per inch'
@0x00001ca=458 : **** next IFD offset 0
@0x00001ce=462 : ============= VALUES, IFD 0 ============
@0x00001ce=462 : BitsPerSample = 8,8,8
@0x00001d4=468 : DocumentName = '/home/ahuggel/mini9.tif\0'
@0x00001ec=492 : ImageDescription = 'Created with GIMP\0'
@0x00001fe=510 : XResolution = 72
@0x0000206=518 : YResolution = 72
@0x000020d=525 : </IFD 0>
@0x0000008=8 : <=-=-=> Start of TIFF RGB uncompressed image data for IFD 0, data length 243
0x0000008=8 : ff 00 00 ff 00 00 ff 00 00 ff 00 00 00 ff 00 00 |................|
0x0000018=24 : 00 ff ff 00 00 ff 00 00 ff 00 00 00 ff 00 00 ff |................|
0x0000028=40 : 00 00 ff 00 3f 7f bf 3f 7f bf 3f 7f bf 00 ff 00 |....?..?..?.....|
0x0000038=56 : 00 ff 00 00 ff 00 00 00 ff 00 00 ff 3f 7f bf ff |............?...| etc...
@0x00000fa=250 : </=-=-=> End of image data
-0x000020d=525 : END OF FILE
@0x0000008=8 : Start of TIFF RGB uncompressed primary image [9x9] length 243 (IFD 0)
-0x00000fa=250 : End of TIFF primary image data
Number of images = 1
File Format = TIFFEP
Test 1: Writing empty Exif data without original binary data: ok.
Test 2: Writing empty Exif data with original binary data: ok.
Test 3: Wrote non-empty Exif data without original binary data:
Exif.Image.ExifTag 0x8769 Long 1 26
Exif.Photo.DateTimeOriginal 0x9003 Ascii 18 Yesterday at noon
MIME type: image/tiff
Image size: 9 x 9
Before
Exif.Image.NewSubfileType 0x00fe Long 1 0
Exif.Image.ImageWidth 0x0100 Short 1 9
Exif.Image.ImageLength 0x0101 Short 1 9
Exif.Image.BitsPerSample 0x0102 Short 3 8 8 8
Exif.Image.Compression 0x0103 Short 1 1
Exif.Image.PhotometricInterpretation 0x0106 Short 1 2
Exif.Image.DocumentName 0x010d Ascii 24 /home/ahuggel/mini9.tif
Exif.Image.ImageDescription 0x010e Ascii 18 Created with GIMP
Exif.Image.StripOffsets 0x0111 Long 1 8
Exif.Image.Orientation 0x0112 Short 1 1
Exif.Image.SamplesPerPixel 0x0115 Short 1 3
Exif.Image.RowsPerStrip 0x0116 Short 1 64
Exif.Image.StripByteCounts 0x0117 Long 1 243
Exif.Image.XResolution 0x011a Rational 1 1207959552/16777216
Exif.Image.YResolution 0x011b Rational 1 1207959552/16777216
Exif.Image.PlanarConfiguration 0x011c Short 1 1
Exif.Image.ResolutionUnit 0x0128 Short 1 2
======
After
Exif.Image.NewSubfileType 0x00fe Long 1 0
Exif.Image.ImageWidth 0x0100 Short 1 9
Exif.Image.ImageLength 0x0101 Short 1 9
Exif.Image.BitsPerSample 0x0102 Short 3 8 8 8
Exif.Image.Compression 0x0103 Short 1 1
Exif.Image.PhotometricInterpretation 0x0106 Short 1 2
Exif.Image.DocumentName 0x010d Ascii 24 /home/ahuggel/mini9.tif
Exif.Image.ImageDescription 0x010e Ascii 18 Created with GIMP
Exif.Image.StripOffsets 0x0111 Long 1 8
Exif.Image.Orientation 0x0112 Short 1 1
Exif.Image.SamplesPerPixel 0x0115 Short 1 3
Exif.Image.RowsPerStrip 0x0116 Short 1 64
Exif.Image.StripByteCounts 0x0117 Long 1 243
Exif.Image.XResolution 0x011a Rational 1 1207959552/16777216
Exif.Image.YResolution 0x011b Rational 1 1207959552/16777216
Exif.Image.PlanarConfiguration 0x011c Short 1 1
Exif.Image.ResolutionUnit 0x0128 Short 1 2
Exif.Photo.DateTimeOriginal 0x9003 Ascii 18 Yesterday at noon
File Name = mini9.tif
File Type = TIFF:II
File Size = 573
@000000000=0 : TIFF(II=0x4949) magic=0x002a='*\0' ifd offset = 0x8/8
@0x0000008=8 : <IFD 0> 18 entries starting at file offset 0xa=10
@0x000000a=10 : <0x00fe= 254> NewSubFileType [4 =LONG 1] = 0 = 'primary'
@0x0000016=22 : <0x0100= 256> ImageWidth [3 =SHORT 1] = 9
@0x0000022=34 : <0x0101= 257> ImageLength [3 =SHORT 1] = 9
@0x000002e=46 : <0x0102= 258> BitsPerSample [3 =SHORT 3] = @0xe6=230
@0x000003a=58 : <0x0103= 259> Compression [3 =SHORT 1] = 1 = 'uncompressed'
@0x0000046=70 : <0x0106= 262> PhotometricInterpretation [3 =SHORT 1] = 2 = 'RGB'
@0x0000052=82 : <0x010d= 269> DocumentName [2 =ASCII 24] = @0xec=236
@0x000005e=94 : <0x010e= 270> ImageDescription [2 =ASCII 18] = @0x104=260
@0x000006a=106 : <0x0111= 273> StripOffsets [4 =LONG 1] = @330
@0x0000076=118 : <0x0112= 274> Orientation [3 =SHORT 1] = 1 = '0,0 is top left'
@0x0000082=130 : <0x0115= 277> SamplesPerPixel [3 =SHORT 1] = 3
@0x000008e=142 : <0x0116= 278> RowsPerStrip [3 =SHORT 1] = 64
@0x000009a=154 : <0x0117= 279> StripByteCounts [4 =LONG 1] = 243
@0x00000a6=166 : <0x011a= 282> XResolution [5 =RATIONAL 1] = @0x116=278
@0x00000b2=178 : <0x011b= 283> YResolution [5 =RATIONAL 1] = @0x11e=286
@0x00000be=190 : <0x011c= 284> PlanarConfiguration [3 =SHORT 1] = 1 = 'chunky/contig'
@0x00000ca=202 : <0x0128= 296> ResolutionUnit [3 =SHORT 1] = 2 = 'pixels per inch'
@0x00000d6=214 : <0x8769=34665> ExifIFDPointer [4 =LONG 1] = @0x126=294
@0x00000e2=226 : **** next IFD offset 0
@0x00000e6=230 : ============= VALUES, IFD 0 ============
@0x00000e6=230 : BitsPerSample = 8,8,8
@0x00000ec=236 : DocumentName = '/home/ahuggel/mini9.tif\0'
@0x0000104=260 : ImageDescription = 'Created with GIMP\0'
@0x0000116=278 : XResolution = 72
@0x000011e=286 : YResolution = 72
@0x0000126=294 : <EXIF IFD> (in IFD 0) 1 entries starting at file offset 0x128=296
@0x0000128=296 : <0x9003=36867> DateTimeOriginal [2 =ASCII 18] = @0x138=312
@0x0000134=308 : **** next IFD offset 0
@0x0000138=312 : ============= VALUES, EXIF IFD ============
@0x0000138=312 : DateTimeOriginal = 'Yesterday at noon\0'
-0x0000149=329 : </EXIF IFD>
@0x0000149=329 : </IFD 0>
@0x000014a=330 : <=-=-=> Start of TIFF RGB uncompressed image data for IFD 0, data length 243
0x000014a=330 : ff 00 00 ff 00 00 ff 00 00 ff 00 00 00 ff 00 00 |................|
0x000015a=346 : 00 ff ff 00 00 ff 00 00 ff 00 00 00 ff 00 00 ff |................|
0x000016a=362 : 00 00 ff 00 3f 7f bf 3f 7f bf 3f 7f bf 00 ff 00 |....?..?..?.....|
0x000017a=378 : 00 ff 00 00 ff 00 00 00 ff 00 00 ff 3f 7f bf ff |............?...| etc...
@0x000023c=572 : </=-=-=> End of image data
-0x000023c=572 : END OF FILE
@0x000014a=330 : Start of TIFF RGB uncompressed primary image [9x9] length 243 (IFD 0)
-0x000023c=572 : End of TIFF primary image data
Number of images = 1
File Format = TIFFEP/EXIF

@ -13,7 +13,6 @@ Exif.Photo.DateTimeOriginal 0x9003 Exif Ascii 7
Exif.Image.Make 0x010f IFD0 Ascii 6 Canon
Exif.Image.Model 0x0110 IFD0 Ascii 20 Canon PowerShot S40
Exif.Image.ExifTag 0x8769 IFD0 Long 1 76
Exif.Canon.0xabcd 0xabcd Makernote Ascii 22 A Canon makernote tag
Exif.CanonCs.Macro 0x0001 Makernote Short 1 0
Exif.CanonCs.Selftimer 0x0002 Makernote Short 1 41
Exif.CanonSi.0x0001 0x0001 Makernote Short 1 0
@ -24,12 +23,12 @@ Exif.CanonSi.TargetShutterSpeed 0x0005 Makernote Short 1
Exif.CanonPa.0x0001 0x0001 Makernote Short 1 45
Exif.CanonCf.NoiseReduction 0x0001 Makernote Short 1 43
Exif.CanonPi.0x0001 0x0001 Makernote Short 1 44
Exif.Canon.0xabcd 0xabcd Makernote Ascii 22 A Canon makernote tag
----- Non-intrusive writing of special Canon MakerNote tags
Exif.Image.Make 0x010f IFD0 Ascii 6 Canon
Exif.Image.Model 0x0110 IFD0 Ascii 20 Canon PowerShot S40
Exif.Image.ExifTag 0x8769 IFD0 Long 1 76
Exif.Canon.0xabcd 0xabcd Makernote Ascii 22 A Canon makernote tag
Exif.CanonCs.Macro 0x0001 Makernote Short 1 88
Exif.CanonCs.Selftimer 0x0002 Makernote Short 1 41
Exif.CanonSi.0x0001 0x0001 Makernote Short 1 0
@ -40,6 +39,7 @@ Exif.CanonSi.TargetShutterSpeed 0x0005 Makernote Short 1
Exif.CanonPa.0x0001 0x0001 Makernote Short 1 45
Exif.CanonCf.NoiseReduction 0x0001 Makernote Short 1 43
Exif.CanonPi.0x0001 0x0001 Makernote Short 1 44
Exif.Canon.0xabcd 0xabcd Makernote Ascii 22 A Canon makernote tag
----- One Fujifilm MakerNote tag
Exif.Image.Make 0x010f IFD0 Ascii 9 FUJIFILM

@ -1,24 +0,0 @@
#! /bin/sh
# Test driver for Ifd unit tests
results="./tmp/ifd-test.out"
good="./data/ifd-test.out"
diffargs="--strip-trailing-cr"
tmpfile=tmp/ttt
touch $tmpfile
diff -q $diffargs $tmpfile $tmpfile 2>/dev/null
if [ $? -ne 0 ] ; then
diffargs=""
fi
(
binpath=" $VALGRIND ../../samples"
cd ./tmp
$binpath/ifd-test
) > $results 2>&1
diff -q $diffargs $results $good
rc=$?
if [ $rc -eq 0 ] ; then
echo "All testcases passed."
else
diff $diffargs $results $good
fi

@ -1,24 +0,0 @@
#! /bin/sh
# Test driver for tests of MakerNoteFactory::match
results="./tmp/makernote-test.out"
good="./data/makernote-test.out"
diffargs="--strip-trailing-cr"
tmpfile=tmp/ttt
touch $tmpfile
diff -q $diffargs $tmpfile $tmpfile 2>/dev/null
if [ $? -ne 0 ] ; then
diffargs=""
fi
(
binpath="$VALGRIND ../../samples"
cd ./tmp
$binpath/makernote-test
) > $results
diff -q $diffargs $results $good
rc=$?
if [ $rc -eq 0 ] ; then
echo "All testcases passed."
else
diff $diffargs $results $good
fi

@ -0,0 +1,35 @@
#! /bin/sh
# TIFF parser test driver
# ----------------------------------------------------------------------
# Setup
results="./tmp/tiff-test.out"
good="./data/tiff-test.out"
# ----------------------------------------------------------------------
# Main routine
(
binpath="$VALGRIND ../../samples"
exiv2="$VALGRIND ../../src/exiv2"
cd ./tmp
# ----------------------------------------------------------------------
# Basic write test
testfile=mini9.tif
cp -f ../data/$testfile .
exifprobe $testfile
$binpath/tiff-test $testfile
exifprobe $testfile
) > $results
# ----------------------------------------------------------------------
# Evaluate results
cat $results | tr -d '\r' > $results-stripped
diff -q $results-stripped $good
rc=$?
if [ $rc -eq 0 ] ; then
echo "All testcases passed."
else
diff $results-stripped $good
fi
Loading…
Cancel
Save