Completed CRW write support, feature #438. Only tested on Linux

v0.27.3
Andreas Huggel 20 years ago
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

@ -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&nbsp;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());

@ -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";
}

@ -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,6 +508,9 @@ 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;
@ -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));
uint16_t c = 1;
while (uint32_t(c)*2 < ciffComponent.size()) {
uint16_t n = 1;
ExifKey key(c, ifdItem);
UShortValue value;
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();
c += n;
IfdId ifdId = ifdIdNotSet;
switch (pCrwMapping->tag_) {
case 0x0001: ifdId = canonCs1IfdId; break;
case 0x0004: ifdId = canonCs2IfdId; break;
case 0x000f: ifdId = canonCfIfdId; break;
}
assert(ifdId != ifdIdNotSet);
// 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);
}
std::string ifdItem(ExifTags::ifdItem(canonCs1IfdId));
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 (c == 23 && ciffComponent.size() > 50) n = 3;
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 (ifdId == canonCs2IfdId && c == 21) aperture = value.toLong();
if (ifdId == canonCs2IfdId && c == 22) shutterSpeed = value.toLong();
c += n;
}
} // CrwMap::decode0x102d
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::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");
@ -1092,24 +1162,124 @@ namespace Exiv2 {
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 {
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
}
} // 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 {
if (cc) cc->remove();
pHead->remove(pCrwMapping->crwTagId_, pCrwMapping->crwDir_);
}
} // encode0x080a
} // 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

@ -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.
@param crwTagId Tag to be added.
@param crwDir Parent directory of the tag.
@param buf Value to be set.
*/
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.
@return The newly added component.
@param crwTagId Tag id to be removed.
@param crwDir Parent directory of the tag.
*/
CiffComponent* addTag(uint16_t crwTag, uint16_t crwDir);
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.
Loading…
Cancel
Save