Completed CRW write support, feature #438. Only tested on Linux
This commit is contained in:
parent
92b9339cd2
commit
d545215ceb
@ -1,4 +1,4 @@
|
||||
# Doxyfile 1.4.5
|
||||
# Doxyfile 1.4.6
|
||||
|
||||
# This file describes the settings to be used by the documentation system
|
||||
# doxygen (www.doxygen.org) for a project
|
||||
@ -385,7 +385,7 @@ SHOW_USED_FILES = YES
|
||||
|
||||
# If the sources in your project are distributed over multiple directories
|
||||
# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
|
||||
# in the documentation. The default is YES.
|
||||
# in the documentation. The default is NO.
|
||||
|
||||
SHOW_DIRECTORIES = NO
|
||||
|
||||
|
||||
4
doc/templates/__index1__
vendored
4
doc/templates/__index1__
vendored
@ -1,9 +1,9 @@
|
||||
<!-- Main index from Doxygen 1.4.5 -->
|
||||
<!-- Main index from Doxygen 1.4.6 -->
|
||||
<div class="tabs">
|
||||
<ul>
|
||||
<li><a href="index.html"><span>Main Page</span></a></li>
|
||||
<li><a href="namespaces.html"><span>Namespaces</span></a></li>
|
||||
<li><a href="annotated.html"><span>Classes</span></a></li>
|
||||
<li><a href="classes.html"><span>Classes</span></a></li>
|
||||
<li><a href="files.html"><span>Files</span></a></li>
|
||||
<li><a href="examples.html"><span>Examples</span></a></li>
|
||||
</ul>
|
||||
|
||||
@ -60,7 +60,7 @@ CCSRC = basicio.cpp canonmn.cpp crwimage.cpp datasets.cpp error.cpp exif.cpp \
|
||||
BINSRC = addmoddel.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 makernote-test.cpp taglist.cpp write-test.cpp \
|
||||
write2-test.cpp crwparse.cpp
|
||||
write2-test.cpp crwparse.cpp crwedit.cpp
|
||||
|
||||
# Main source file of the Exiv2 application
|
||||
EXIV2MAIN = exiv2.cpp
|
||||
|
||||
@ -184,7 +184,7 @@ namespace Exiv2 {
|
||||
close();
|
||||
fileIo->close();
|
||||
// MSVCRT rename that does not overwrite existing files
|
||||
if (std::remove(path_.c_str()) != 0) {
|
||||
if (fileExists(path_) && std::remove(path_.c_str()) != 0) {
|
||||
throw Error(2, path_, strError(), "std::remove");
|
||||
}
|
||||
if (std::rename(fileIo->path_.c_str(), path_.c_str()) == -1) {
|
||||
@ -192,7 +192,7 @@ namespace Exiv2 {
|
||||
}
|
||||
std::remove(fileIo->path_.c_str());
|
||||
}
|
||||
else{
|
||||
else {
|
||||
// Generic handling, reopen both to reset to start
|
||||
if (open("w+b") != 0) {
|
||||
throw Error(10, path_, "w+b", strError());
|
||||
|
||||
131
src/crwedit.cpp
Normal file
131
src/crwedit.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
// crwedit.cpp, $Rev$
|
||||
// Print the CIFF structure of a CRW file
|
||||
|
||||
#include "crwimage.hpp"
|
||||
#include "futils.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
void remove(Exiv2::CiffHeader* pHead);
|
||||
void add(Exiv2::CiffHeader* pHead);
|
||||
void help();
|
||||
void write(const std::string& filename, const Exiv2::CiffHeader* pHead);
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
try {
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
std::cout << "Edit the CIFF structure of a CRW file\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string filename(argv[1]);
|
||||
Exiv2::FileIo io(filename);
|
||||
if(io.open() != 0) {
|
||||
throw Exiv2::Error(9, io.path(), Exiv2::strError());
|
||||
}
|
||||
Exiv2::IoCloser closer(io);
|
||||
|
||||
// Ensure that this is a CRW image
|
||||
if (!Exiv2::isCrwType(io, false)) {
|
||||
if (io.error() || io.eof()) throw Exiv2::Error(14);
|
||||
throw Exiv2::Error(33);
|
||||
}
|
||||
|
||||
// Read the image into a memory buffer
|
||||
long len = io.size();
|
||||
Exiv2::DataBuf buf(len);
|
||||
io.read(buf.pData_, len);
|
||||
if (io.error() || io.eof()) throw Exiv2::Error(14);
|
||||
|
||||
// Parse the image, starting with a CIFF header component
|
||||
Exiv2::CiffHeader::AutoPtr parseTree(new Exiv2::CiffHeader);
|
||||
parseTree->read(buf.pData_, buf.size_);
|
||||
|
||||
// Allow user to make changes
|
||||
bool go = true;
|
||||
while (go) {
|
||||
char cmd;
|
||||
std::cout << "command> ";
|
||||
std::cin >> cmd;
|
||||
switch (cmd) {
|
||||
case 'q': go = false; break;
|
||||
case 'p': parseTree->print(std::cout); break;
|
||||
case 'a': add(parseTree.get()); break;
|
||||
case 'd': remove(parseTree.get()); break;
|
||||
case 'w': write(filename, parseTree.get()); break;
|
||||
case 'h': help(); break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (Exiv2::AnyError& e) {
|
||||
std::cerr << e << "\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
void write(const std::string& filename, const Exiv2::CiffHeader* pHead)
|
||||
{
|
||||
Exiv2::Blob blob;
|
||||
pHead->write(blob);
|
||||
|
||||
Exiv2::FileIo io(filename);
|
||||
if(io.open("wb") != 0) {
|
||||
throw Exiv2::Error(9, io.path(), Exiv2::strError());
|
||||
}
|
||||
Exiv2::IoCloser closer(io);
|
||||
long ret = io.write(&blob[0], blob.size());
|
||||
if (static_cast<size_t>(ret) != blob.size()) throw Exiv2::Error(21);
|
||||
io.close();
|
||||
}
|
||||
|
||||
void remove(Exiv2::CiffHeader* pHead)
|
||||
{
|
||||
uint16_t crwTag, crwDir;
|
||||
std::cout << "crwTag> 0x";
|
||||
std::cin >> std::hex >> crwTag;
|
||||
std::cout << "crwDir> 0x";
|
||||
std::cin >> std::hex >> crwDir;
|
||||
std::cout << "Deleting tag 0x" << std::hex << crwTag
|
||||
<< " in dir 0x" << crwDir << ", ok? ";
|
||||
char cmd;
|
||||
std::cin >> cmd;
|
||||
if (cmd != 'n' && cmd != 'N') {
|
||||
pHead->remove(crwTag, crwDir);
|
||||
}
|
||||
else {
|
||||
std::cout << "Canceled.\n";
|
||||
}
|
||||
}
|
||||
|
||||
void add(Exiv2::CiffHeader* pHead)
|
||||
{
|
||||
uint16_t crwTag, crwDir;
|
||||
uint32_t size;
|
||||
std::cout << "crwTag> 0x";
|
||||
std::cin >> std::hex >> crwTag;
|
||||
std::cout << "crwDir> 0x";
|
||||
std::cin >> std::hex >> crwDir;
|
||||
std::cout << "size> ";
|
||||
std::cin >> std::dec >> size;
|
||||
std::cout << "Adding tag 0x" << std::hex << crwTag
|
||||
<< " in dir 0x" << crwDir << ", " << size << " bytes, ok? ";
|
||||
char cmd;
|
||||
std::cin >> cmd;
|
||||
if (cmd != 'n' && cmd != 'N') {
|
||||
Exiv2::DataBuf buf(size);
|
||||
memset(buf.pData_, 0xaa, size);
|
||||
pHead->add(crwTag, crwDir, buf);
|
||||
}
|
||||
else {
|
||||
std::cout << "Canceled.\n";
|
||||
}
|
||||
}
|
||||
|
||||
void help()
|
||||
{
|
||||
std::cout << "a: add tag, d: delete tag, p: print tags, w: write file, q: quit\n";
|
||||
}
|
||||
505
src/crwimage.cpp
505
src/crwimage.cpp
@ -38,6 +38,7 @@ EXIV2_RCSID("@(#) $Id$");
|
||||
#ifdef _MSC_VER
|
||||
# include "exv_msvc.h"
|
||||
#else
|
||||
# define _XOPEN_SOURCE /* glibc2 needs this for strptime */
|
||||
# include "exv_conf.h"
|
||||
#endif
|
||||
|
||||
@ -56,6 +57,9 @@ EXIV2_RCSID("@(#) $Id$");
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <cmath>
|
||||
#ifndef EXV_HAVE_TIMEGM
|
||||
# include "timegm.h"
|
||||
#endif
|
||||
|
||||
// *****************************************************************************
|
||||
// class member definitions
|
||||
@ -64,15 +68,15 @@ namespace Exiv2 {
|
||||
const CrwMapping CrwMap::crwMapping_[] = {
|
||||
// CrwTag CrwDir Size ExifTag IfdId decodeFct encodeFct
|
||||
// ------ ------ ---- ------- ----- --------- ---------
|
||||
CrwMapping(0x0805, 0x300a, 0, 0x9286, exifIfdId, decode0x0805, encode0x0805),
|
||||
CrwMapping(0x080a, 0x2807, 0, 0x010f, ifd0Id, decode0x080a, encode0x080a),
|
||||
CrwMapping(0x0805, 0x300a, 0, 0, canonIfdId, decode0x0805, encode0x0805),
|
||||
CrwMapping(0x080a, 0x2807, 0, 0, canonIfdId, decode0x080a, encode0x080a),
|
||||
CrwMapping(0x080b, 0x3004, 0, 0x0007, canonIfdId, decodeBasic, encodeBasic),
|
||||
CrwMapping(0x0810, 0x2807, 0, 0x0009, canonIfdId, decodeBasic, encodeBasic),
|
||||
CrwMapping(0x0815, 0x2804, 0, 0x0006, canonIfdId, decodeBasic, encodeBasic),
|
||||
CrwMapping(0x1029, 0x300b, 0, 0x0002, canonIfdId, decodeBasic, encodeBasic),
|
||||
CrwMapping(0x102a, 0x300b, 0, 0x0004, canonIfdId, decode0x102a, 0),
|
||||
CrwMapping(0x102d, 0x300b, 0, 0x0001, canonIfdId, decode0x102d, 0),
|
||||
CrwMapping(0x1033, 0x300b, 0, 0x000f, canonIfdId, decodeBasic, encodeBasic),
|
||||
CrwMapping(0x102a, 0x300b, 0, 0x0004, canonIfdId, decodeArray, encodeArray),
|
||||
CrwMapping(0x102d, 0x300b, 0, 0x0001, canonIfdId, decodeArray, encodeArray),
|
||||
CrwMapping(0x1033, 0x300b, 0, 0x000f, canonIfdId, decodeArray, encodeArray),
|
||||
CrwMapping(0x1038, 0x300b, 0, 0x0012, canonIfdId, decodeBasic, encodeBasic),
|
||||
CrwMapping(0x10a9, 0x300b, 0, 0x00a9, canonIfdId, decodeBasic, encodeBasic),
|
||||
// Mapped to Exif.Photo.ColorSpace instead (see below)
|
||||
@ -83,15 +87,12 @@ namespace Exiv2 {
|
||||
CrwMapping(0x10c1, 0x300b, 0, 0x00c1, canonIfdId, decodeBasic, encodeBasic),
|
||||
CrwMapping(0x1807, 0x3002, 0, 0x9206, exifIfdId, decodeBasic, encodeBasic),
|
||||
CrwMapping(0x180b, 0x2807, 0, 0x000c, canonIfdId, decodeBasic, encodeBasic),
|
||||
CrwMapping(0x180e, 0x300a, 0, 0x9003, exifIfdId, decode0x180e, 0),
|
||||
CrwMapping(0x1810, 0x300a, 0, 0xa002, exifIfdId, decode0x1810, 0),
|
||||
CrwMapping(0x1810, 0x300a, 0, 0xa003, exifIfdId, 0, 0),
|
||||
CrwMapping(0x180e, 0x300a, 0, 0x9003, exifIfdId, decode0x180e, encode0x180e),
|
||||
CrwMapping(0x1810, 0x300a, 0, 0xa002, exifIfdId, decode0x1810, encode0x1810),
|
||||
CrwMapping(0x1817, 0x300a, 4, 0x0008, canonIfdId, decodeBasic, encodeBasic),
|
||||
//CrwMapping(0x1818, 0x3002, 0, 0x9204, exifIfdId, decodeBasic, encodeBasic),
|
||||
CrwMapping(0x183b, 0x300b, 0, 0x0015, canonIfdId, decodeBasic, encodeBasic),
|
||||
CrwMapping(0x2008, 0x0000, 0, 0x0201, ifd1Id, decode0x2008, 0),
|
||||
CrwMapping(0x2008, 0x0000, 0, 0x0202, ifd1Id, 0, 0),
|
||||
CrwMapping(0x2008, 0x0000, 0, 0x0103, ifd1Id, 0, 0),
|
||||
CrwMapping(0x2008, 0x0000, 0, 0, ifd1Id, decode0x2008, encode0x2008),
|
||||
// End of list marker
|
||||
CrwMapping(0x0000, 0x0000, 0, 0x0000, ifdIdNotSet, 0, 0)
|
||||
}; // CrwMap::crwMapping_[]
|
||||
@ -126,30 +127,15 @@ namespace Exiv2 {
|
||||
{ 0xffff, 0xffff }
|
||||
};
|
||||
|
||||
const byte CrwImage::blank_[] = {
|
||||
0x00
|
||||
};
|
||||
|
||||
CrwImage::CrwImage(BasicIo::AutoPtr io, bool create)
|
||||
: io_(io)
|
||||
{
|
||||
if (create) {
|
||||
initImage(blank_, sizeof(blank_));
|
||||
IoCloser closer(*io_);
|
||||
io_->open();
|
||||
}
|
||||
} // CrwImage::CrwImage
|
||||
|
||||
int CrwImage::initImage(const byte initData[], long dataSize)
|
||||
{
|
||||
if (io_->open() != 0) {
|
||||
return 4;
|
||||
}
|
||||
IoCloser closer(*io_);
|
||||
if (io_->write(initData, dataSize) != dataSize) {
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
} // CrwImage::initImage
|
||||
|
||||
bool CrwImage::good() const
|
||||
{
|
||||
if (io_->open() != 0) return false;
|
||||
@ -352,29 +338,6 @@ namespace Exiv2 {
|
||||
pRootDir_->readDirectory(pData + offset_, size - offset_, byteOrder_);
|
||||
} // CiffHeader::read
|
||||
|
||||
void CiffDirectory::readDirectory(const byte* pData,
|
||||
uint32_t size,
|
||||
ByteOrder byteOrder)
|
||||
{
|
||||
uint32_t o = getULong(pData + size - 4, byteOrder);
|
||||
if (o + 2 > size) throw Error(33);
|
||||
uint16_t count = getUShort(pData + o, byteOrder);
|
||||
o += 2;
|
||||
for (uint16_t i = 0; i < count; ++i) {
|
||||
if (o + 10 > size) throw Error(33);
|
||||
uint16_t tag = getUShort(pData + o, byteOrder);
|
||||
AutoPtr m;
|
||||
switch (CiffComponent::typeId(tag)) {
|
||||
case directory: m = AutoPtr(new CiffDirectory); break;
|
||||
default: m = AutoPtr(new CiffEntry); break;
|
||||
}
|
||||
m->setDir(this->tag());
|
||||
m->read(pData, size, o, byteOrder);
|
||||
add(m);
|
||||
o += 10;
|
||||
}
|
||||
} // CiffDirectory::readDirectory
|
||||
|
||||
void CiffComponent::read(const byte* pData,
|
||||
uint32_t size,
|
||||
uint32_t start,
|
||||
@ -403,6 +366,13 @@ namespace Exiv2 {
|
||||
offset_ = start + 2;
|
||||
}
|
||||
pData_ = pData + offset_;
|
||||
#ifdef DEBUG
|
||||
std::cout << " Entry for tag 0x"
|
||||
<< std::hex << tagId() << " (0x" << tag()
|
||||
<< "), " << std::dec << size_
|
||||
<< " Bytes, Offset is " << offset_ << "\n";
|
||||
#endif
|
||||
|
||||
} // CiffComponent::doRead
|
||||
|
||||
void CiffDirectory::doRead(const byte* pData,
|
||||
@ -411,9 +381,42 @@ namespace Exiv2 {
|
||||
ByteOrder byteOrder)
|
||||
{
|
||||
CiffComponent::doRead(pData, size, start, byteOrder);
|
||||
#ifdef DEBUG
|
||||
std::cout << "Reading directory 0x" << std::hex << tag() << "\n";
|
||||
#endif
|
||||
readDirectory(pData + offset(), this->size(), byteOrder);
|
||||
#ifdef DEBUG
|
||||
std::cout << "<---- 0x" << std::hex << tag() << "\n";
|
||||
#endif
|
||||
} // CiffDirectory::doRead
|
||||
|
||||
void CiffDirectory::readDirectory(const byte* pData,
|
||||
uint32_t size,
|
||||
ByteOrder byteOrder)
|
||||
{
|
||||
uint32_t o = getULong(pData + size - 4, byteOrder);
|
||||
if (o + 2 > size) throw Error(33);
|
||||
uint16_t count = getUShort(pData + o, byteOrder);
|
||||
#ifdef DEBUG
|
||||
std::cout << "Directory at offset " << std::dec << o
|
||||
<<", " << count << " entries \n";
|
||||
#endif
|
||||
o += 2;
|
||||
for (uint16_t i = 0; i < count; ++i) {
|
||||
if (o + 10 > size) throw Error(33);
|
||||
uint16_t tag = getUShort(pData + o, byteOrder);
|
||||
AutoPtr m;
|
||||
switch (CiffComponent::typeId(tag)) {
|
||||
case directory: m = AutoPtr(new CiffDirectory); break;
|
||||
default: m = AutoPtr(new CiffEntry); break;
|
||||
}
|
||||
m->setDir(this->tag());
|
||||
m->read(pData, size, o, byteOrder);
|
||||
add(m);
|
||||
o += 10;
|
||||
}
|
||||
} // CiffDirectory::readDirectory
|
||||
|
||||
void CiffHeader::decode(Image& image) const
|
||||
{
|
||||
// Nothing to decode from the header itself, just add correct byte order
|
||||
@ -472,7 +475,6 @@ namespace Exiv2 {
|
||||
ByteOrder byteOrder,
|
||||
uint32_t offset)
|
||||
{
|
||||
if (remove_) return offset;
|
||||
return doWrite(blob, byteOrder, offset);
|
||||
}
|
||||
|
||||
@ -486,6 +488,10 @@ namespace Exiv2 {
|
||||
uint32_t CiffComponent::writeValueData(Blob& blob, uint32_t offset)
|
||||
{
|
||||
if (dataLocation() == valueData) {
|
||||
#ifdef DEBUG
|
||||
std::cout << " Data for tag 0x" << std::hex << tagId()
|
||||
<< ", " << std::dec << size_ << " Bytes\n";
|
||||
#endif
|
||||
offset_ = offset;
|
||||
append(blob, pData_, size_);
|
||||
offset += size_;
|
||||
@ -502,8 +508,11 @@ namespace Exiv2 {
|
||||
ByteOrder byteOrder,
|
||||
uint32_t offset)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cout << "Writing directory 0x" << std::hex << tag() << "---->\n";
|
||||
#endif
|
||||
// Ciff offsets are relative to the start of the directory
|
||||
uint32_t dirOffset = 0;
|
||||
uint32_t dirOffset = 0;
|
||||
|
||||
// Value data
|
||||
const Components::iterator b = components_.begin();
|
||||
@ -515,7 +524,7 @@ namespace Exiv2 {
|
||||
|
||||
// Number of directory entries
|
||||
byte buf[4];
|
||||
us2Data(buf, components_.size(), byteOrder);
|
||||
us2Data(buf, static_cast<uint16_t>(components_.size()), byteOrder);
|
||||
append(blob, buf, 2);
|
||||
dirOffset += 2;
|
||||
|
||||
@ -534,11 +543,22 @@ namespace Exiv2 {
|
||||
setOffset(offset);
|
||||
setSize(dirOffset);
|
||||
|
||||
#ifdef DEBUG
|
||||
std::cout << "Directory is at offset " << std::dec << dirStart
|
||||
<< ", " << components_.size() << " entries\n"
|
||||
<< "<---- 0x" << std::hex << tag() << "\n";
|
||||
#endif
|
||||
return offset + dirOffset;
|
||||
} // CiffDirectory::doWrite
|
||||
|
||||
void CiffComponent::writeDirEntry(Blob& blob, ByteOrder byteOrder) const
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cout << " Directory entry for tag 0x"
|
||||
<< std::hex << tagId() << " (0x" << tag()
|
||||
<< "), " << std::dec << size_
|
||||
<< " Bytes, Offset is " << offset_ << "\n";
|
||||
#endif
|
||||
byte buf[4];
|
||||
|
||||
DataLocId dl = dataLocation();
|
||||
@ -662,46 +682,46 @@ namespace Exiv2 {
|
||||
} // CiffComponent::dataLocation
|
||||
|
||||
/*!
|
||||
@brief Finds \em crwTag in directory \em crwDir, returning a pointer to
|
||||
@brief Finds \em crwTagId in directory \em crwDir, returning a pointer to
|
||||
the component or 0 if not found.
|
||||
|
||||
*/
|
||||
CiffComponent* CiffHeader::findComponent(uint16_t crwTag,
|
||||
CiffComponent* CiffHeader::findComponent(uint16_t crwTagId,
|
||||
uint16_t crwDir) const
|
||||
{
|
||||
if (pRootDir_ == 0) return 0;
|
||||
return pRootDir_->findComponent(crwTag, crwDir);
|
||||
return pRootDir_->findComponent(crwTagId, crwDir);
|
||||
} // CiffHeader::findComponent
|
||||
|
||||
CiffComponent* CiffComponent::findComponent(uint16_t crwTag,
|
||||
CiffComponent* CiffComponent::findComponent(uint16_t crwTagId,
|
||||
uint16_t crwDir) const
|
||||
{
|
||||
return doFindComponent(crwTag, crwDir);
|
||||
return doFindComponent(crwTagId, crwDir);
|
||||
} // CiffComponent::findComponent
|
||||
|
||||
CiffComponent* CiffComponent::doFindComponent(uint16_t crwTag,
|
||||
CiffComponent* CiffComponent::doFindComponent(uint16_t crwTagId,
|
||||
uint16_t crwDir) const
|
||||
{
|
||||
if (tagId() == crwTag && dir() == crwDir) {
|
||||
if (tagId() == crwTagId && dir() == crwDir) {
|
||||
return const_cast<CiffComponent*>(this);
|
||||
}
|
||||
return 0;
|
||||
} // CiffComponent::doFindComponent
|
||||
|
||||
CiffComponent* CiffDirectory::doFindComponent(uint16_t crwTag,
|
||||
CiffComponent* CiffDirectory::doFindComponent(uint16_t crwTagId,
|
||||
uint16_t crwDir) const
|
||||
{
|
||||
CiffComponent* cc = 0;
|
||||
const Components::const_iterator b = components_.begin();
|
||||
const Components::const_iterator e = components_.end();
|
||||
for (Components::const_iterator i = b; i != e; ++i) {
|
||||
cc = (*i)->findComponent(crwTag, crwDir);
|
||||
cc = (*i)->findComponent(crwTagId, crwDir);
|
||||
if (cc) return cc;
|
||||
}
|
||||
return 0;
|
||||
} // CiffDirectory::doFindComponent
|
||||
|
||||
CiffComponent* CiffHeader::addTag(uint16_t crwTag, uint16_t crwDir)
|
||||
void CiffHeader::add(uint16_t crwTagId, uint16_t crwDir, DataBuf buf)
|
||||
{
|
||||
CrwDirs crwDirs;
|
||||
CrwMap::loadStack(crwDirs, crwDir);
|
||||
@ -709,28 +729,29 @@ namespace Exiv2 {
|
||||
assert(rootDirectory == 0x0000);
|
||||
crwDirs.pop();
|
||||
if (!pRootDir_) pRootDir_ = new CiffDirectory;
|
||||
return pRootDir_->addTag(crwDirs, crwTag);
|
||||
} // CiffHeader::addTag
|
||||
CiffComponent* cc = pRootDir_->add(crwDirs, crwTagId);
|
||||
cc->setValue(buf);
|
||||
} // CiffHeader::add
|
||||
|
||||
CiffComponent* CiffComponent::addTag(CrwDirs& crwDirs, uint16_t crwTag)
|
||||
CiffComponent* CiffComponent::add(CrwDirs& crwDirs, uint16_t crwTagId)
|
||||
{
|
||||
return doAddTag(crwDirs, crwTag);
|
||||
} // CiffComponent::addTag
|
||||
return doAdd(crwDirs, crwTagId);
|
||||
} // CiffComponent::add
|
||||
|
||||
CiffComponent* CiffComponent::doAddTag(CrwDirs& crwDirs, uint16_t crwTag)
|
||||
CiffComponent* CiffComponent::doAdd(CrwDirs& crwDirs, uint16_t crwTagId)
|
||||
{
|
||||
return 0;
|
||||
} // CiffComponent::doAddTag
|
||||
} // CiffComponent::doAdd
|
||||
|
||||
CiffComponent* CiffDirectory::doAddTag(CrwDirs& crwDirs, uint16_t crwTag)
|
||||
CiffComponent* CiffDirectory::doAdd(CrwDirs& crwDirs, uint16_t crwTagId)
|
||||
{
|
||||
/*
|
||||
addTag()
|
||||
add()
|
||||
if stack not empty
|
||||
pop from stack
|
||||
find dir among components
|
||||
if not found, create it
|
||||
addTag()
|
||||
add()
|
||||
else
|
||||
find tag among components
|
||||
if not found, create it
|
||||
@ -758,25 +779,93 @@ namespace Exiv2 {
|
||||
add(m);
|
||||
}
|
||||
// Recursive call to next lower level directory
|
||||
cc = cc->addTag(crwDirs, crwTag);
|
||||
cc = cc->add(crwDirs, crwTagId);
|
||||
}
|
||||
else {
|
||||
// Find the tag
|
||||
for (Components::iterator i = b; i != e; ++i) {
|
||||
if ((*i)->tag() == crwTag) {
|
||||
if ((*i)->tagId() == crwTagId) {
|
||||
cc = *i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cc == 0) {
|
||||
// Tag doesn't exist yet, add it
|
||||
AutoPtr m(new CiffEntry(crwTag, tag()));
|
||||
AutoPtr m(new CiffEntry(crwTagId, tag()));
|
||||
cc = m.get();
|
||||
add(m);
|
||||
}
|
||||
}
|
||||
return cc;
|
||||
} // CiffDirectory::doAddTag
|
||||
} // CiffDirectory::doAdd
|
||||
|
||||
void CiffHeader::remove(uint16_t crwTagId, uint16_t crwDir)
|
||||
{
|
||||
if (pRootDir_) {
|
||||
CrwDirs crwDirs;
|
||||
CrwMap::loadStack(crwDirs, crwDir);
|
||||
uint16_t rootDirectory = crwDirs.top().crwDir_;
|
||||
assert(rootDirectory == 0x0000);
|
||||
crwDirs.pop();
|
||||
pRootDir_->remove(crwDirs, crwTagId);
|
||||
}
|
||||
} // CiffHeader::remove
|
||||
|
||||
void CiffComponent::remove(CrwDirs& crwDirs, uint16_t crwTagId)
|
||||
{
|
||||
return doRemove(crwDirs, crwTagId);
|
||||
} // CiffComponent::remove
|
||||
|
||||
void CiffComponent::doRemove(CrwDirs& crwDirs, uint16_t crwTagId)
|
||||
{
|
||||
// do nothing
|
||||
} // CiffComponent::doRemove
|
||||
|
||||
void CiffDirectory::doRemove(CrwDirs& crwDirs, uint16_t crwTagId)
|
||||
{
|
||||
const Components::iterator b = components_.begin();
|
||||
const Components::iterator e = components_.end();
|
||||
Components::iterator i;
|
||||
|
||||
if (!crwDirs.empty()) {
|
||||
CrwSubDir csd = crwDirs.top();
|
||||
crwDirs.pop();
|
||||
// Find the directory
|
||||
for (i = b; i != e; ++i) {
|
||||
if ((*i)->tag() == csd.crwDir_) {
|
||||
// Recursive call to next lower level directory
|
||||
(*i)->remove(crwDirs, crwTagId);
|
||||
if ((*i)->empty()) components_.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Find the tag
|
||||
for (i = b; i != e; ++i) {
|
||||
if ((*i)->tagId() == crwTagId) {
|
||||
// Remove the entry and abort the loop
|
||||
components_.erase(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // CiffDirectory::doRemove
|
||||
|
||||
bool CiffComponent::empty() const
|
||||
{
|
||||
return doEmpty();
|
||||
}
|
||||
|
||||
bool CiffComponent::doEmpty() const
|
||||
{
|
||||
return size_ == 0;
|
||||
}
|
||||
|
||||
bool CiffDirectory::doEmpty() const
|
||||
{
|
||||
return components_.empty();
|
||||
}
|
||||
|
||||
void CrwMap::decode(const CiffComponent& ciffComponent,
|
||||
Image& image,
|
||||
@ -789,11 +878,11 @@ namespace Exiv2 {
|
||||
}
|
||||
} // CrwMap::decode
|
||||
|
||||
const CrwMapping* CrwMap::crwMapping(uint16_t dir, uint16_t tagId)
|
||||
const CrwMapping* CrwMap::crwMapping(uint16_t crwDir, uint16_t crwTagId)
|
||||
{
|
||||
for (int i = 0; crwMapping_[i].ifdId_ != ifdIdNotSet; ++i) {
|
||||
if ( crwMapping_[i].crwDir_ == dir
|
||||
&& crwMapping_[i].crwTagId_ == tagId) {
|
||||
if ( crwMapping_[i].crwDir_ == crwDir
|
||||
&& crwMapping_[i].crwTagId_ == crwTagId) {
|
||||
return &(crwMapping_[i]);
|
||||
}
|
||||
}
|
||||
@ -814,9 +903,7 @@ namespace Exiv2 {
|
||||
Image& image,
|
||||
ByteOrder byteOrder)
|
||||
{
|
||||
if (ciffComponent.typeId() != asciiString) {
|
||||
return decodeBasic(ciffComponent, pCrwMapping, image, byteOrder);
|
||||
}
|
||||
if (ciffComponent.typeId() != asciiString) return;
|
||||
|
||||
// Make
|
||||
ExifKey key1("Exif.Image.Make");
|
||||
@ -841,10 +928,10 @@ namespace Exiv2 {
|
||||
image.exifData().add(key2, value2.get());
|
||||
} // CrwMap::decode0x080a
|
||||
|
||||
void CrwMap::decode0x102a(const CiffComponent& ciffComponent,
|
||||
const CrwMapping* pCrwMapping,
|
||||
Image& image,
|
||||
ByteOrder byteOrder)
|
||||
void CrwMap::decodeArray(const CiffComponent& ciffComponent,
|
||||
const CrwMapping* pCrwMapping,
|
||||
Image& image,
|
||||
ByteOrder byteOrder)
|
||||
{
|
||||
if (ciffComponent.typeId() != unsignedShort) {
|
||||
return decodeBasic(ciffComponent, pCrwMapping, image, byteOrder);
|
||||
@ -853,59 +940,47 @@ namespace Exiv2 {
|
||||
long aperture = 0;
|
||||
long shutterSpeed = 0;
|
||||
|
||||
std::string ifdItem(ExifTags::ifdItem(canonCs2IfdId));
|
||||
IfdId ifdId = ifdIdNotSet;
|
||||
switch (pCrwMapping->tag_) {
|
||||
case 0x0001: ifdId = canonCs1IfdId; break;
|
||||
case 0x0004: ifdId = canonCs2IfdId; break;
|
||||
case 0x000f: ifdId = canonCfIfdId; break;
|
||||
}
|
||||
assert(ifdId != ifdIdNotSet);
|
||||
|
||||
std::string ifdItem(ExifTags::ifdItem(ifdId));
|
||||
uint16_t c = 1;
|
||||
while (uint32_t(c)*2 < ciffComponent.size()) {
|
||||
uint16_t n = 1;
|
||||
ExifKey key(c, ifdItem);
|
||||
UShortValue value;
|
||||
if (ifdId == canonCs1IfdId && c == 23 && ciffComponent.size() > 50) n = 3;
|
||||
value.read(ciffComponent.pData() + c*2, n*2, byteOrder);
|
||||
image.exifData().add(key, &value);
|
||||
if (c == 21) aperture = value.toLong();
|
||||
if (c == 22) shutterSpeed = value.toLong();
|
||||
if (ifdId == canonCs2IfdId && c == 21) aperture = value.toLong();
|
||||
if (ifdId == canonCs2IfdId && c == 22) shutterSpeed = value.toLong();
|
||||
c += n;
|
||||
}
|
||||
|
||||
// Exif.Photo.FNumber
|
||||
float f = fnumber(canonEv(aperture));
|
||||
// Beware: primitive conversion algorithm
|
||||
uint32_t den = 1000000;
|
||||
uint32_t nom = static_cast<uint32_t>(f * den);
|
||||
uint32_t g = gcd(nom, den);
|
||||
URational ur(nom/g, den/g);
|
||||
URationalValue fn;
|
||||
fn.value_.push_back(ur);
|
||||
image.exifData().add(ExifKey("Exif.Photo.FNumber"), &fn);
|
||||
if (ifdId == canonCs2IfdId) {
|
||||
// Exif.Photo.FNumber
|
||||
float f = fnumber(canonEv(aperture));
|
||||
// Beware: primitive conversion algorithm
|
||||
uint32_t den = 1000000;
|
||||
uint32_t nom = static_cast<uint32_t>(f * den);
|
||||
uint32_t g = gcd(nom, den);
|
||||
URational ur(nom/g, den/g);
|
||||
URationalValue fn;
|
||||
fn.value_.push_back(ur);
|
||||
image.exifData().add(ExifKey("Exif.Photo.FNumber"), &fn);
|
||||
|
||||
// Exif.Photo.ExposureTime
|
||||
ur = exposureTime(canonEv(shutterSpeed));
|
||||
URationalValue et;
|
||||
et.value_.push_back(ur);
|
||||
image.exifData().add(ExifKey("Exif.Photo.ExposureTime"), &et);
|
||||
|
||||
} // CrwMap::decode0x102a
|
||||
|
||||
void CrwMap::decode0x102d(const CiffComponent& ciffComponent,
|
||||
const CrwMapping* pCrwMapping,
|
||||
Image& image,
|
||||
ByteOrder byteOrder)
|
||||
{
|
||||
if (ciffComponent.typeId() != unsignedShort) {
|
||||
return decodeBasic(ciffComponent, pCrwMapping, image, byteOrder);
|
||||
// Exif.Photo.ExposureTime
|
||||
ur = exposureTime(canonEv(shutterSpeed));
|
||||
URationalValue et;
|
||||
et.value_.push_back(ur);
|
||||
image.exifData().add(ExifKey("Exif.Photo.ExposureTime"), &et);
|
||||
}
|
||||
|
||||
std::string ifdItem(ExifTags::ifdItem(canonCs1IfdId));
|
||||
uint16_t c = 1;
|
||||
while (uint32_t(c)*2 < ciffComponent.size()) {
|
||||
uint16_t n = 1;
|
||||
ExifKey key(c, ifdItem);
|
||||
UShortValue value;
|
||||
if (c == 23 && ciffComponent.size() > 50) n = 3;
|
||||
value.read(ciffComponent.pData() + c*2, n*2, byteOrder);
|
||||
image.exifData().add(key, &value);
|
||||
c += n;
|
||||
}
|
||||
} // CrwMap::decode0x102d
|
||||
} // CrwMap::decodeArray
|
||||
|
||||
void CrwMap::decode0x180e(const CiffComponent& ciffComponent,
|
||||
const CrwMapping* pCrwMapping,
|
||||
@ -1034,56 +1109,51 @@ namespace Exiv2 {
|
||||
ExifKey ek(pCrwMapping->tag_, ExifTags::ifdItem(pCrwMapping->ifdId_));
|
||||
ExifData::const_iterator ed = image.exifData().findKey(ek);
|
||||
|
||||
// Find the target metadatum in the Ciff parse tree
|
||||
CiffComponent* cc = pHead->findComponent(pCrwMapping->crwTagId_,
|
||||
pCrwMapping->crwDir_);
|
||||
|
||||
// Set the new value or remove the entry
|
||||
if (ed != image.exifData().end()) {
|
||||
// Create the directory and component as needed
|
||||
if (cc == 0) cc = pHead->addTag(pCrwMapping->crwTagId_,
|
||||
pCrwMapping->crwDir_);
|
||||
// Set the new value
|
||||
DataBuf buf(ed->size());
|
||||
ed->copy(buf.pData_, pHead->byteOrder());
|
||||
cc->setValue(buf);
|
||||
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
||||
}
|
||||
else {
|
||||
if (cc) cc->remove();
|
||||
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
|
||||
}
|
||||
} // CrwMap::encodeBasic
|
||||
|
||||
void CrwMap::encode0x0805(const Image& image,
|
||||
const CrwMapping* /*pCrwMapping*/,
|
||||
const CrwMapping* pCrwMapping,
|
||||
CiffHeader* pHead)
|
||||
{
|
||||
assert(pCrwMapping != 0);
|
||||
assert(pHead != 0);
|
||||
|
||||
std::string comment = image.comment();
|
||||
|
||||
const uint16_t crwTag = 0x0805;
|
||||
const uint16_t crwDir = 0x300a;
|
||||
CiffComponent* cc = pHead->findComponent(crwTag, crwDir);
|
||||
|
||||
CiffComponent* cc = pHead->findComponent(pCrwMapping->crwTagId_,
|
||||
pCrwMapping->crwDir_);
|
||||
if (!comment.empty()) {
|
||||
if (cc == 0) cc = pHead->addTag(crwTag, crwDir);
|
||||
DataBuf buf(std::max(cc->size(), comment.size()));
|
||||
uint32_t size = comment.size();
|
||||
if (cc && cc->size() > size) size = cc->size();
|
||||
DataBuf buf(size);
|
||||
memset(buf.pData_, 0x0, buf.size_);
|
||||
memcpy(buf.pData_, comment.data(), comment.size());
|
||||
cc->setValue(buf);
|
||||
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
||||
}
|
||||
else {
|
||||
if (cc) {
|
||||
// Just delete the value, do not remove the tag
|
||||
DataBuf buf(cc->size());
|
||||
memset(buf.pData_, 0x0, buf.size_);
|
||||
cc->setValue(buf);
|
||||
}
|
||||
}
|
||||
} // CrwMap::encode0x0805
|
||||
|
||||
void CrwMap::encode0x080a(const Image& image,
|
||||
const CrwMapping* /*pCrwMapping*/,
|
||||
const CrwMapping* pCrwMapping,
|
||||
CiffHeader* pHead)
|
||||
{
|
||||
assert(pCrwMapping != 0);
|
||||
assert(pHead != 0);
|
||||
|
||||
const ExifKey k1("Exif.Image.Make");
|
||||
@ -1091,25 +1161,125 @@ namespace Exiv2 {
|
||||
const ExifData::const_iterator ed1 = image.exifData().findKey(k1);
|
||||
const ExifData::const_iterator ed2 = image.exifData().findKey(k2);
|
||||
const ExifData::const_iterator edEnd = image.exifData().end();
|
||||
|
||||
const uint16_t crwTag = 0x080a;
|
||||
const uint16_t crwDir = 0x2807;
|
||||
CiffComponent* cc = pHead->findComponent(crwTag, crwDir);
|
||||
|
||||
long size = 0;
|
||||
if (ed1 != edEnd) size += ed1->size();
|
||||
if (ed2 != edEnd) size += ed2->size();
|
||||
if (size != 0) {
|
||||
if (cc == 0) cc = pHead->addTag(crwTag, crwDir);
|
||||
DataBuf buf(size);
|
||||
if (ed1 != edEnd) ed1->copy(buf.pData_, pHead->byteOrder());
|
||||
if (ed2 != edEnd) ed2->copy(buf.pData_ + ed1->size(), pHead->byteOrder());
|
||||
cc->setValue(buf);
|
||||
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
||||
}
|
||||
else {
|
||||
if (cc) cc->remove();
|
||||
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
|
||||
}
|
||||
} // encode0x080a
|
||||
} // CrwMap::encode0x080a
|
||||
|
||||
void CrwMap::encodeArray(const Image& image,
|
||||
const CrwMapping* pCrwMapping,
|
||||
CiffHeader* pHead)
|
||||
{
|
||||
assert(pCrwMapping != 0);
|
||||
assert(pHead != 0);
|
||||
|
||||
IfdId ifdId = ifdIdNotSet;
|
||||
switch (pCrwMapping->tag_) {
|
||||
case 0x0001: ifdId = canonCs1IfdId; break;
|
||||
case 0x0004: ifdId = canonCs2IfdId; break;
|
||||
case 0x000f: ifdId = canonCfIfdId; break;
|
||||
}
|
||||
assert(ifdId != ifdIdNotSet);
|
||||
DataBuf buf = packIfdId(image.exifData(), ifdId, pHead->byteOrder());
|
||||
if (buf.size_ == 0) {
|
||||
// Try the undecoded tag
|
||||
encodeBasic(image, pCrwMapping, pHead);
|
||||
}
|
||||
if (buf.size_ > 0) {
|
||||
// Write the number of shorts to the beginning of buf
|
||||
us2Data(buf.pData_, buf.size_, pHead->byteOrder());
|
||||
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
||||
}
|
||||
else {
|
||||
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
|
||||
}
|
||||
} // CrwMap::encodeArray
|
||||
|
||||
void CrwMap::encode0x180e(const Image& image,
|
||||
const CrwMapping* pCrwMapping,
|
||||
CiffHeader* pHead)
|
||||
{
|
||||
assert(pCrwMapping != 0);
|
||||
assert(pHead != 0);
|
||||
|
||||
time_t t = 0;
|
||||
const ExifKey key(pCrwMapping->tag_, ExifTags::ifdItem(pCrwMapping->ifdId_));
|
||||
const ExifData::const_iterator ed = image.exifData().findKey(key);
|
||||
if (ed != image.exifData().end()) {
|
||||
struct tm tm;
|
||||
char* p = strptime(ed->toString().c_str(), "%Y:%m:%d %T", &tm);
|
||||
if (p != 0) t = timegm(&tm);
|
||||
}
|
||||
if (t != 0) {
|
||||
DataBuf buf(12);
|
||||
memset(buf.pData_, 0x0, 12);
|
||||
ul2Data(buf.pData_, static_cast<uint32_t>(t), pHead->byteOrder());
|
||||
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
||||
}
|
||||
else {
|
||||
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
|
||||
}
|
||||
} // CrwMap::encode0x180e
|
||||
|
||||
void CrwMap::encode0x1810(const Image& image,
|
||||
const CrwMapping* pCrwMapping,
|
||||
CiffHeader* pHead)
|
||||
{
|
||||
assert(pCrwMapping != 0);
|
||||
assert(pHead != 0);
|
||||
|
||||
const ExifKey kX("Exif.Photo.PixelXDimension");
|
||||
const ExifKey kY("Exif.Photo.PixelYDimension");
|
||||
const ExifData::const_iterator edX = image.exifData().findKey(kX);
|
||||
const ExifData::const_iterator edY = image.exifData().findKey(kY);
|
||||
const ExifData::const_iterator edEnd = image.exifData().end();
|
||||
|
||||
CiffComponent* cc = pHead->findComponent(pCrwMapping->crwTagId_,
|
||||
pCrwMapping->crwDir_);
|
||||
if (edX != edEnd || edY != edEnd) {
|
||||
uint32_t size = 28;
|
||||
if (cc && cc->size() > size) size = cc->size();
|
||||
DataBuf buf(size);
|
||||
memset(buf.pData_, 0x0, buf.size_);
|
||||
if (cc) memcpy(buf.pData_ + 8, cc->pData() + 8, cc->size() - 8);
|
||||
if (edX != edEnd && edX->size() == 4) {
|
||||
edX->copy(buf.pData_, pHead->byteOrder());
|
||||
}
|
||||
if (edY != edEnd && edY->size() == 4) {
|
||||
edY->copy(buf.pData_ + 4, pHead->byteOrder());
|
||||
}
|
||||
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
||||
}
|
||||
else {
|
||||
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
|
||||
}
|
||||
} // CrwMap::encode0x1810
|
||||
|
||||
void CrwMap::encode0x2008(const Image& image,
|
||||
const CrwMapping* pCrwMapping,
|
||||
CiffHeader* pHead)
|
||||
{
|
||||
assert(pCrwMapping != 0);
|
||||
assert(pHead != 0);
|
||||
|
||||
DataBuf buf = image.exifData().copyThumbnail();
|
||||
if (buf.size_ != 0) {
|
||||
pHead->add(pCrwMapping->crwTagId_, pCrwMapping->crwDir_, buf);
|
||||
}
|
||||
else {
|
||||
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
|
||||
}
|
||||
} // CrwMap::encode0x1810
|
||||
|
||||
// *************************************************************************
|
||||
// free functions
|
||||
@ -1143,4 +1313,27 @@ namespace Exiv2 {
|
||||
return result;
|
||||
}
|
||||
|
||||
DataBuf packIfdId(const ExifData& exifData,
|
||||
IfdId ifdId,
|
||||
ByteOrder byteOrder)
|
||||
{
|
||||
const uint16_t size = 1024;
|
||||
DataBuf buf(size);
|
||||
memset(buf.pData_, 0x0, buf.size_);
|
||||
|
||||
uint16_t len = 0;
|
||||
const ExifData::const_iterator b = exifData.begin();
|
||||
const ExifData::const_iterator e = exifData.end();
|
||||
for (ExifData::const_iterator i = b; i != e; ++i) {
|
||||
if (i->ifdId() != ifdId) continue;
|
||||
const uint16_t s = i->tag()*2 + static_cast<uint16_t>(i->size());
|
||||
assert(s <= size);
|
||||
if (len < s) len = s;
|
||||
i->copy(buf.pData_ + i->tag()*2, byteOrder);
|
||||
}
|
||||
// Round the size to make it even.
|
||||
buf.size_ = len + len%2;
|
||||
return buf;
|
||||
}
|
||||
|
||||
} // namespace Exiv2
|
||||
|
||||
165
src/crwimage.hpp
165
src/crwimage.hpp
@ -157,12 +157,6 @@ namespace Exiv2 {
|
||||
//@}
|
||||
|
||||
private:
|
||||
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
int initImage(const byte initData[], long dataSize);
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
//@{
|
||||
/*!
|
||||
@ -191,8 +185,6 @@ namespace Exiv2 {
|
||||
//@}
|
||||
|
||||
// DATA
|
||||
static const byte blank_[]; //!< Minimal Crw image
|
||||
|
||||
BasicIo::AutoPtr io_; //!< Image data io pointer
|
||||
ExifData exifData_; //!< Exif data container
|
||||
IptcData iptcData_; //!< Iptc data container
|
||||
@ -254,11 +246,11 @@ namespace Exiv2 {
|
||||
//! Default constructor
|
||||
CiffComponent()
|
||||
: dir_(0), tag_(0), size_(0), offset_(0), pData_(0),
|
||||
remove_(false), isAllocated_(false) {}
|
||||
isAllocated_(false) {}
|
||||
//! Constructor taking a tag and directory
|
||||
CiffComponent(uint16_t tag, uint16_t dir)
|
||||
: dir_(dir), tag_(tag), size_(0), offset_(0), pData_(0),
|
||||
remove_(false), isAllocated_(false) {}
|
||||
isAllocated_(false) {}
|
||||
//! Virtual destructor.
|
||||
virtual ~CiffComponent();
|
||||
//@}
|
||||
@ -269,6 +261,30 @@ namespace Exiv2 {
|
||||
|
||||
//! Add a component to the composition
|
||||
void add(AutoPtr component);
|
||||
/*!
|
||||
@brief Add \em crwTagId to the parse tree, if it doesn't exist
|
||||
yet. \em crwDirs contains the path of subdirectories, starting
|
||||
with the root directory, leading to \em crwTagId. Directories
|
||||
that don't exist yet are added along the way. Returns a pointer
|
||||
to the newly added component.
|
||||
|
||||
@param crwDirs Subdirectory path from root to the subdirectory
|
||||
containing the tag to be added.
|
||||
@param crwTagId Tag to be added.
|
||||
|
||||
@return A pointer to the newly added component.
|
||||
*/
|
||||
CiffComponent* add(CrwDirs& crwDirs, uint16_t crwTagId);
|
||||
/*!
|
||||
@brief Remove \em crwTagId from the parse tree, if it exists yet. \em
|
||||
crwDirs contains the path of subdirectories, starting with the
|
||||
root directory, leading to \em crwTagId.
|
||||
|
||||
@param crwDirs Subdirectory path from root to the subdirectory
|
||||
containing the tag to be removed.
|
||||
@param crwTagId Tag to be removed.
|
||||
*/
|
||||
void remove(CrwDirs& crwDirs, uint16_t crwTagId);
|
||||
/*!
|
||||
@brief Read a component from a data buffer
|
||||
|
||||
@ -294,18 +310,6 @@ namespace Exiv2 {
|
||||
@return New offset
|
||||
*/
|
||||
uint32_t write(Blob& blob, ByteOrder byteOrder, uint32_t offset);
|
||||
/*!
|
||||
@brief Add \em crwTag to the parse tree, if it doesn' exist yet. \em
|
||||
crwDirs contains the path of subdirectories, starting with the
|
||||
root directory, leading to \em crwTag. Directories that don't
|
||||
exist yet are added along the way. Returns a pointer to the
|
||||
newly added component.
|
||||
|
||||
@param crwDirs Subdirectory path from root to the subdirectory containing
|
||||
the tag to be added.
|
||||
@param crwTag Tag to be added.
|
||||
*/
|
||||
CiffComponent* addTag(CrwDirs& crwDirs, uint16_t crwTag);
|
||||
/*!
|
||||
@brief Writes the entry's value if size is larger than eight bytes. If
|
||||
needed, the value is padded with one 0 byte to make the number
|
||||
@ -319,8 +323,6 @@ namespace Exiv2 {
|
||||
uint32_t writeValueData(Blob& blob, uint32_t offset);
|
||||
//! Set the directory tag for this component.
|
||||
void setDir(uint16_t dir) { dir_ = dir; }
|
||||
//! Mark the component as deleted, so that it won't be written.
|
||||
void remove() { remove_ = true; }
|
||||
//! Set the data value of the entry.
|
||||
void setValue(DataBuf buf);
|
||||
//@}
|
||||
@ -362,6 +364,9 @@ namespace Exiv2 {
|
||||
//! Return the tag of this component
|
||||
uint16_t tag() const { return tag_; }
|
||||
|
||||
//! Return true if the component is empty, else false
|
||||
bool empty() const;
|
||||
|
||||
/*!
|
||||
@brief Return the data size of this component
|
||||
|
||||
@ -388,10 +393,10 @@ namespace Exiv2 {
|
||||
DataLocId dataLocation() const { return dataLocation(tag_); }
|
||||
|
||||
/*!
|
||||
@brief Finds \em crwTag in directory \em crwDir, returning a pointer to
|
||||
@brief Finds \em crwTagId in directory \em crwDir, returning a pointer to
|
||||
the component or 0 if not found.
|
||||
*/
|
||||
CiffComponent* findComponent(uint16_t crwTag, uint16_t crwDir) const;
|
||||
CiffComponent* findComponent(uint16_t crwTagId, uint16_t crwDir) const;
|
||||
//@}
|
||||
|
||||
protected:
|
||||
@ -399,6 +404,10 @@ namespace Exiv2 {
|
||||
//@{
|
||||
//! Implements add()
|
||||
virtual void doAdd(AutoPtr component) =0;
|
||||
//! Implements add(). The default implementation does nothing.
|
||||
virtual CiffComponent* doAdd(CrwDirs& crwDirs, uint16_t crwTagId);
|
||||
//! Implements remove(). The default implementation does nothing.
|
||||
virtual void doRemove(CrwDirs& crwDirs, uint16_t crwTagId);
|
||||
//! Implements read(). The default implementation reads a directory entry.
|
||||
virtual void doRead(const byte* pData,
|
||||
uint32_t size,
|
||||
@ -408,8 +417,6 @@ namespace Exiv2 {
|
||||
virtual uint32_t doWrite(Blob& blob,
|
||||
ByteOrder byteOrder,
|
||||
uint32_t offset) =0;
|
||||
//! Implements addTag(). The default implementation does nothing.
|
||||
virtual CiffComponent* doAddTag(CrwDirs& crwDirs, uint16_t crwTag);
|
||||
//! Set the size of the data area.
|
||||
void setSize(uint32_t size) { size_ = size; }
|
||||
//! Set the offset for this component.
|
||||
@ -425,8 +432,10 @@ namespace Exiv2 {
|
||||
virtual void doPrint(std::ostream& os,
|
||||
ByteOrder byteOrder,
|
||||
const std::string& prefix) const;
|
||||
//! Implements empty(). Default implementation returns true if size is 0.
|
||||
virtual bool doEmpty() const;
|
||||
//! Implements findComponent(). The default implementation checks the entry.
|
||||
virtual CiffComponent* doFindComponent(uint16_t crwTag,
|
||||
virtual CiffComponent* doFindComponent(uint16_t crwTagId,
|
||||
uint16_t crwDir) const;
|
||||
//@}
|
||||
|
||||
@ -437,7 +446,6 @@ namespace Exiv2 {
|
||||
uint32_t size_; //!< Size of the data area
|
||||
uint32_t offset_; //!< Offset to the data area from start of dir
|
||||
const byte* pData_; //!< Pointer to the data area
|
||||
bool remove_; //!< If true, the entry should not be written
|
||||
bool isAllocated_; //!< True if this entry owns the value data
|
||||
|
||||
}; // class CiffComponent
|
||||
@ -518,6 +526,10 @@ namespace Exiv2 {
|
||||
//@{
|
||||
// See base class comment
|
||||
virtual void doAdd(AutoPtr component);
|
||||
// See base class comment
|
||||
virtual CiffComponent* doAdd(CrwDirs& crwDirs, uint16_t crwTagId);
|
||||
// See base class comment
|
||||
virtual void doRemove(CrwDirs& crwDirs, uint16_t crwTagId);
|
||||
/*!
|
||||
@brief Implements write(). Writes the complete Ciff directory to
|
||||
the blob.
|
||||
@ -530,8 +542,6 @@ namespace Exiv2 {
|
||||
uint32_t size,
|
||||
uint32_t start,
|
||||
ByteOrder byteOrder);
|
||||
// See base class comment
|
||||
virtual CiffComponent* doAddTag(CrwDirs& crwDirs, uint16_t crwTag);
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
@ -544,8 +554,12 @@ namespace Exiv2 {
|
||||
virtual void doPrint(std::ostream& os,
|
||||
ByteOrder byteOrder,
|
||||
const std::string& prefix) const;
|
||||
|
||||
//! See base class comment. A directory is empty if it has no components.
|
||||
virtual bool doEmpty() const;
|
||||
|
||||
// See base class comment
|
||||
virtual CiffComponent* doFindComponent(uint16_t crwTag,
|
||||
virtual CiffComponent* doFindComponent(uint16_t crwTagId,
|
||||
uint16_t crwDir) const;
|
||||
//@}
|
||||
|
||||
@ -555,7 +569,12 @@ namespace Exiv2 {
|
||||
|
||||
}; // class CiffDirectory
|
||||
|
||||
//! This class models the header of a Crw (Canon Raw data) image.
|
||||
/*!
|
||||
@brief This class models the header of a Crw (Canon Raw data) image. It
|
||||
is the head of a CIFF parse tree, consisting of CiffDirectory and
|
||||
CiffEntry objects. Most of its methods will walk the parse tree to
|
||||
perform the requested action.
|
||||
*/
|
||||
class CiffHeader {
|
||||
public:
|
||||
//! CiffHeader auto_ptr type
|
||||
@ -586,18 +605,24 @@ namespace Exiv2 {
|
||||
*/
|
||||
void read(const byte* pData, uint32_t size);
|
||||
/*!
|
||||
@brief Adds an entry for \em crwTag in directory \em crwDir to the
|
||||
parse tree if it doesn't exist yet. Directories that don't
|
||||
exist yet are added along the way. Nothing is added if the tag
|
||||
already exists in the correct directory. Returns the newly
|
||||
added component.
|
||||
@brief Set the value of entry \em crwTagId in directory \em crwDir to
|
||||
\em buf. If this tag doesn't exist, it is added along with all
|
||||
directories needed.
|
||||
|
||||
@param crwTag Tag to be added.
|
||||
@param crwDir Parent directory of the tag.
|
||||
|
||||
@return The newly added component.
|
||||
@param crwTagId Tag to be added.
|
||||
@param crwDir Parent directory of the tag.
|
||||
@param buf Value to be set.
|
||||
*/
|
||||
CiffComponent* addTag(uint16_t crwTag, uint16_t crwDir);
|
||||
void add(uint16_t crwTagId, uint16_t crwDir, DataBuf buf);
|
||||
/*!
|
||||
@brief Remove entry \em crwTagId in directory \em crwDir from the parse
|
||||
tree. If it's the last entry in the directory, the directory is
|
||||
removed as well, etc.
|
||||
|
||||
@param crwTagId Tag id to be removed.
|
||||
@param crwDir Parent directory of the tag.
|
||||
*/
|
||||
void remove(uint16_t crwTagId, uint16_t crwDir);
|
||||
//@}
|
||||
|
||||
//! Return a pointer to the Canon Crw signature.
|
||||
@ -630,10 +655,10 @@ namespace Exiv2 {
|
||||
//! Return the byte order (little or big endian).
|
||||
ByteOrder byteOrder() const { return byteOrder_; }
|
||||
/*!
|
||||
@brief Finds \em crwTag in directory \em crwDir in the parse tree,
|
||||
@brief Finds \em crwTagId in directory \em crwDir in the parse tree,
|
||||
returning a pointer to the component or 0 if not found.
|
||||
*/
|
||||
CiffComponent* findComponent(uint16_t crwTag, uint16_t crwDir) const;
|
||||
CiffComponent* findComponent(uint16_t crwTagId, uint16_t crwDir) const;
|
||||
//@}
|
||||
|
||||
private:
|
||||
@ -734,8 +759,8 @@ namespace Exiv2 {
|
||||
static void loadStack(CrwDirs& crwDirs, uint16_t crwDir);
|
||||
|
||||
private:
|
||||
//! Return conversion information for one Crw \em dir and \em tagId
|
||||
static const CrwMapping* crwMapping(uint16_t dir, uint16_t tagId);
|
||||
//! Return conversion information for one \em crwDir and \em crwTagId
|
||||
static const CrwMapping* crwMapping(uint16_t crwDir, uint16_t crwTagId);
|
||||
|
||||
/*!
|
||||
@brief Standard decode function to convert Crw entries to
|
||||
@ -763,17 +788,11 @@ namespace Exiv2 {
|
||||
Image& image,
|
||||
ByteOrder byteOrder);
|
||||
|
||||
//! Decode Canon Camera Settings 2
|
||||
static void decode0x102a(const CiffComponent& ciffComponent,
|
||||
const CrwMapping* pCrwMapping,
|
||||
Image& image,
|
||||
ByteOrder byteOrder);
|
||||
|
||||
//! Decode Canon Camera Settings 1
|
||||
static void decode0x102d(const CiffComponent& ciffComponent,
|
||||
const CrwMapping* pCrwMapping,
|
||||
Image& image,
|
||||
ByteOrder byteOrder);
|
||||
//! Decode Canon Camera Settings 1, 2 and Custom Function arrays
|
||||
static void decodeArray(const CiffComponent& ciffComponent,
|
||||
const CrwMapping* pCrwMapping,
|
||||
Image& image,
|
||||
ByteOrder byteOrder);
|
||||
|
||||
//! Decode the date when the picture was taken
|
||||
static void decode0x180e(const CiffComponent& ciffComponent,
|
||||
@ -821,6 +840,25 @@ namespace Exiv2 {
|
||||
const CrwMapping* pCrwMapping,
|
||||
CiffHeader* pHead);
|
||||
|
||||
//! Encode Canon Camera Settings 1, 2 and Custom Function arrays
|
||||
static void encodeArray(const Image& image,
|
||||
const CrwMapping* pCrwMapping,
|
||||
CiffHeader* pHead);
|
||||
|
||||
//! Encode the date when the picture was taken
|
||||
static void encode0x180e(const Image& image,
|
||||
const CrwMapping* pCrwMapping,
|
||||
CiffHeader* pHead);
|
||||
|
||||
//! Encode image width and height
|
||||
static void encode0x1810(const Image& image,
|
||||
const CrwMapping* pCrwMapping,
|
||||
CiffHeader* pHead);
|
||||
|
||||
//! Encode the thumbnail image
|
||||
static void encode0x2008(const Image& image,
|
||||
const CrwMapping* pCrwMapping,
|
||||
CiffHeader* pHead);
|
||||
private:
|
||||
// DATA
|
||||
static const CrwMapping crwMapping_[]; //!< Metadata conversion table
|
||||
@ -843,6 +881,15 @@ namespace Exiv2 {
|
||||
//! Check if the file iIo is a Crw image.
|
||||
bool isCrwType(BasicIo& iIo, bool advance);
|
||||
|
||||
/*!
|
||||
@brief Pack the tag values of all \em ifdId tags in \em exifData into a
|
||||
data buffer. This function is used to pack Canon Camera Settings1,2
|
||||
and Custom Function tags.
|
||||
*/
|
||||
DataBuf packIfdId(const ExifData& exifData,
|
||||
IfdId ifdId,
|
||||
ByteOrder byteOrder);
|
||||
|
||||
} // namespace Exiv2
|
||||
|
||||
#endif // #ifndef CRWIMAGE_HPP_
|
||||
|
||||
@ -15,9 +15,10 @@ SHELL = /bin/sh
|
||||
.PHONY: all test clean distclean maintainer-clean
|
||||
|
||||
# Add test drivers to this list
|
||||
TESTS = addmoddel.sh bugfixes-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 write-test.sh write2-test.sh
|
||||
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 write-test.sh \
|
||||
write2-test.sh
|
||||
|
||||
test:
|
||||
@list='$(TESTS)'; for p in $$list; do \
|
||||
|
||||
@ -20,34 +20,12 @@ LD_LIBRARY_PATH=../../src:$LD_LIBRARY_PATH
|
||||
export LD_LIBRARY_PATH
|
||||
binpath="$VALGRIND ../../src"
|
||||
cmdfile=cmdfile
|
||||
crwfile=CanonRaw.crw
|
||||
crwfile=exiv2-canon-powershot-s40.crw
|
||||
|
||||
cd ./tmp
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Testcases: Add tags
|
||||
|
||||
# Create an image from scratch with just one tag
|
||||
# Add one tag to an existing image
|
||||
# Add a non-CIFF tag
|
||||
# Add a second tag with the same tag id
|
||||
# Are new tags created as directory data if possible?
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Testcases: Modify tags
|
||||
|
||||
# Modify tag value only
|
||||
# Change number of components (from directory data to value data)
|
||||
# Change value type
|
||||
|
||||
# Exif.Canon.FirmwareVersion Ascii
|
||||
# Exif.Canon.OwnerName Ascii
|
||||
# Exif.Canon.ImageType Ascii
|
||||
# Exif.Canon.0x0002 Short
|
||||
# Exif.Canon.CustomFunctions Short
|
||||
# Exif.Canon.PictureInfo Short
|
||||
# Exif.Canon.SerialNumber Short
|
||||
# Exif.Canon.ImageNumber Long
|
||||
# Testcases: Add and modify tags
|
||||
|
||||
cat > $cmdfile <<EOF
|
||||
set Exif.Photo.ColorSpace 65535
|
||||
@ -55,6 +33,8 @@ set Exif.Canon.OwnerName Somebody else's Camera
|
||||
set Exif.Canon.FirmwareVersion Whatever version
|
||||
set Exif.Canon.SerialNumber 1
|
||||
add Exif.Canon.SerialNumber 2
|
||||
set Exif.Photo.ISOSpeedRatings 155
|
||||
set Exif.Photo.DateTimeOriginal 2007:11:11 09:10:11
|
||||
EOF
|
||||
|
||||
cp -f ../data/$crwfile .
|
||||
@ -68,10 +48,17 @@ $binpath/exiv2 -v -pt $crwfile
|
||||
# ----------------------------------------------------------------------
|
||||
# Testcases: Delete tags
|
||||
|
||||
# Delete one tag
|
||||
# Delete one directory completely
|
||||
# Delete all
|
||||
cat > $cmdfile <<EOF
|
||||
del Exif.Canon.OwnerName
|
||||
EOF
|
||||
|
||||
cp -f ../data/$crwfile .
|
||||
$binpath/exiv2 -v -pt $crwfile
|
||||
|
||||
$binpath/exiv2 -v -m $cmdfile $crwfile
|
||||
$binpath/crwparse $crwfile
|
||||
|
||||
$binpath/exiv2 -v -pt $crwfile
|
||||
|
||||
) > $results 2>&1
|
||||
|
||||
|
||||
Binary file not shown.
BIN
test/data/exiv2-canon-powershot-s40.crw
Normal file
BIN
test/data/exiv2-canon-powershot-s40.crw
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user