#635: Added experimental write-support for CR2.

v0.27.3
Andreas Huggel 13 years ago
parent c2fe8be4ef
commit 0e0845d7be

@ -86,18 +86,6 @@ namespace Exiv2 {
return 0;
}
void Cr2Image::setExifData(const ExifData& /*exifData*/)
{
// Todo: implement me!
throw(Error(32, "Exif metadata", "CR2"));
}
void Cr2Image::setIptcData(const IptcData& /*iptcData*/)
{
// Todo: implement me!
throw(Error(32, "IPTC metadata", "CR2"));
}
void Cr2Image::setComment(const std::string& /*comment*/)
{
// not supported
@ -129,8 +117,29 @@ namespace Exiv2 {
void Cr2Image::writeMetadata()
{
// Todo: implement me!
throw(Error(31, "CR2"));
#ifdef DEBUG
std::cerr << "Writing CR2 file " << io_->path() << "\n";
#endif
ByteOrder bo = byteOrder();
byte* pData = 0;
long size = 0;
IoCloser closer(*io_);
if (io_->open() == 0) {
// Ensure that this is the correct image type
if (isCr2Type(*io_, false)) {
pData = io_->mmap(true);
size = io_->size();
Cr2Header cr2Header;
if (0 == cr2Header.read(pData, 16)) {
bo = cr2Header.byteOrder();
}
}
}
if (bo == invalidByteOrder) {
bo = littleEndian;
}
setByteOrder(bo);
Cr2Parser::encode(*io_, pData, size, bo, exifData_, iptcData_, xmpData_); // may throw
} // Cr2Image::writeMetadata
ByteOrder Cr2Parser::decode(
@ -153,27 +162,45 @@ namespace Exiv2 {
}
WriteMethod Cr2Parser::encode(
Blob& blob,
const byte* /*pData*/,
uint32_t /*size*/,
const ExifData& /*exifData*/,
const IptcData& /*iptcData*/,
const XmpData& /*xmpData*/
BasicIo& io,
const byte* pData,
uint32_t size,
ByteOrder byteOrder,
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData
)
{
/* Todo: Implement me!
TiffParserWorker::encode(blob,
pData,
size,
exifData,
iptcData,
xmpData,
TiffCreator::create,
TiffMapping::findEncoder);
*/
blob.clear();
return wmIntrusive;
// Copy to be able to modify the Exif data
ExifData ed = exifData;
// Delete IFDs which do not occur in TIFF images
static const IfdId filteredIfds[] = {
panaRawId
};
for (unsigned int i = 0; i < EXV_COUNTOF(filteredIfds); ++i) {
#ifdef DEBUG
std::cerr << "Warning: Exif IFD " << filteredIfds[i] << " not encoded\n";
#endif
ed.erase(std::remove_if(ed.begin(),
ed.end(),
FindExifdatum(filteredIfds[i])),
ed.end());
}
std::auto_ptr<TiffHeaderBase> header(new Cr2Header(byteOrder));
OffsetWriter offsetWriter;
offsetWriter.setOrigin(OffsetWriter::cr2RawIfdOffset, Cr2Header::offset2addr(), byteOrder);
return TiffParserWorker::encode(io,
pData,
size,
ed,
iptcData,
xmpData,
Tag::root,
TiffMapping::findEncoder,
header.get(),
&offsetWriter);
}
// *************************************************************************
@ -210,8 +237,8 @@ namespace Exiv2 {
const char* Cr2Header::cr2sig_ = "CR\2\0";
Cr2Header::Cr2Header()
: TiffHeaderBase(42, 16, littleEndian, 0x00000010),
Cr2Header::Cr2Header(ByteOrder byteOrder)
: TiffHeaderBase(42, 16, byteOrder, 0x00000010),
offset2_(0x00000000)
{
}
@ -243,8 +270,26 @@ namespace Exiv2 {
DataBuf Cr2Header::write() const
{
// Todo: Implement me!
return DataBuf();
}
DataBuf buf(16);
switch (byteOrder()) {
case littleEndian:
buf.pData_[0] = 0x49;
buf.pData_[1] = 0x49;
break;
case bigEndian:
buf.pData_[0] = 0x4d;
buf.pData_[1] = 0x4d;
break;
case invalidByteOrder:
assert(false);
break;
}
us2Data(buf.pData_ + 2, tag(), byteOrder());
ul2Data(buf.pData_ + 4, 0x00000010, byteOrder());
memcpy(buf.pData_ + 8, cr2sig_, 4);
// Write a dummy value for the RAW IFD offset. The offset-writer is used to set this offset in a second pass.
ul2Data(buf.pData_ + 12, 0x00000000, byteOrder());
return buf;
} // Cr2Header::write
}} // namespace Internal, Exiv2

@ -79,21 +79,7 @@ namespace Exiv2 {
//! @name Manipulators
//@{
void readMetadata();
/*!
@brief Todo: Write metadata back to the image. This method is not
yet implemented. Calling it will throw an Error(31).
*/
void writeMetadata();
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(32).
*/
void setExifData(const ExifData& exifData);
/*!
@brief Todo: Not supported yet, requires writeMetadata(). Calling
this function will throw an Error(32).
*/
void setIptcData(const IptcData& iptcData);
/*!
@brief Not supported. CR2 format does not contain a comment.
Calling this function will throw an Error(32).
@ -143,9 +129,10 @@ namespace Exiv2 {
See TiffParser::encode().
*/
static WriteMethod encode(
Blob& blob,
BasicIo& io,
const byte* pData,
uint32_t size,
ByteOrder byteOrder,
const ExifData& exifData,
const IptcData& iptcData,
const XmpData& xmpData

@ -53,7 +53,7 @@ namespace Exiv2 {
//! @name Creators
//@{
//! Default constructor
Cr2Header();
Cr2Header(ByteOrder byteOrder =littleEndian);
//! Destructor.
~Cr2Header();
//@}
@ -68,6 +68,9 @@ namespace Exiv2 {
DataBuf write() const;
//@}
// Return the address of offset2 from the start of the header
static uint32_t offset2addr() { return 12; }
private:
// DATA
uint32_t offset2_; //!< Bytes 12-15 from the header

@ -720,7 +720,8 @@ namespace Exiv2 {
emptyXmp,
Tag::root,
TiffMapping::findEncoder,
header.get());
header.get(),
0);
if (mio1.size() <= 65527) {
append(blob, mio1.mmap(), mio1.size());
return wm;
@ -817,7 +818,8 @@ namespace Exiv2 {
emptyXmp,
Tag::root,
TiffMapping::findEncoder,
header.get());
header.get(),
0);
append(blob, mio2.mmap(), mio2.size());
#ifdef DEBUG
if (wm == wmIntrusive) {

@ -197,7 +197,8 @@ namespace Exiv2 {
xmpData,
Tag::root,
TiffMapping::findEncoder,
header.get());
header.get(),
0);
}
// *************************************************************************

@ -69,8 +69,8 @@ namespace Exiv2 {
&& key.g_ == group_;
}
IoWrapper::IoWrapper(BasicIo& io, const byte* pHeader, long size)
: io_(io), pHeader_(pHeader), size_(size), wroteHeader_(false)
IoWrapper::IoWrapper(BasicIo& io, const byte* pHeader, long size, OffsetWriter* pow)
: io_(io), pHeader_(pHeader), size_(size), wroteHeader_(false), pow_(pow)
{
if (pHeader_ == 0 || size_ == 0) wroteHeader_ = true;
}
@ -93,6 +93,11 @@ namespace Exiv2 {
return io_.putb(data);
}
void IoWrapper::setTarget(int id, uint32_t target)
{
if (pow_) pow_->setTarget(OffsetWriter::OffsetId(id), target);
}
TiffComponent::TiffComponent(uint16_t tag, IfdId group)
: tag_(tag), group_(group), pStart_(0)
{
@ -1095,6 +1100,15 @@ namespace Exiv2 {
// Nothing to do if there are no entries and the size of the next IFD is 0
if (compCount == 0 && sizeNext == 0) return 0;
// Remember the offset of the CR2 RAW IFD
if (group() == ifd3Id) {
#ifdef DEBUG
std::cerr << "Directory " << groupName(group()) << " offset is 0x"
<< std::setw(8) << std::setfill('0') << std::hex << offset << std::dec
<< "\n";
#endif
ioWrapper.setTarget(OffsetWriter::cr2RawIfdOffset, offset);
}
// Size of all directory entries, without values and additional data
const uint32_t sizeDir = 2 + 12 * compCount + (hasNext_ ? 4 : 0);
@ -1392,7 +1406,7 @@ namespace Exiv2 {
std::sort(elements_.begin(), elements_.end(), cmpTagLt);
uint32_t idx = 0;
MemIo mio;
IoWrapper mioWrapper(mio, 0, 0);
IoWrapper mioWrapper(mio, 0, 0, 0);
// Some array entries need to have the size in the first element
if (cfg()->hasSize_) {
byte buf[4];

@ -130,10 +130,10 @@ namespace Exiv2 {
/*!
brief Constructor.
The IO wrapper owns neither of the objects passed in so the caller is
The IO wrapper owns none of the objects passed in so the caller is
responsible to keep them alive.
*/
IoWrapper(BasicIo& io, const byte* pHeader, long size);
IoWrapper(BasicIo& io, const byte* pHeader, long size, OffsetWriter* pow);
//@}
//! @name Manipulators
@ -152,6 +152,8 @@ namespace Exiv2 {
by the data passed in the argument.
*/
int putb(byte data);
//! Wrapper for OffsetWriter::setTarget(), using an int instead of the enum to reduce include deps
void setTarget(int id, uint32_t target);
//@}
private:
@ -160,6 +162,7 @@ namespace Exiv2 {
const byte* pHeader_; //! Pointer to the header data.
long size_; //! Size of the header data.
bool wroteHeader_; //! Indicates if the header has been written.
OffsetWriter* pow_; //! Pointer to an offset-writer, if any, or 0
}; // class IoWrapper
/*!

@ -73,6 +73,7 @@ namespace Exiv2 {
struct TiffMappingInfo;
class IoWrapper;
class OffsetWriter;
// *****************************************************************************
// type definitions

@ -273,7 +273,8 @@ namespace Exiv2 {
xmpData,
Tag::root,
TiffMapping::findEncoder,
header.get());
header.get(),
0);
} // TiffParser::encode
// *************************************************************************
@ -1840,7 +1841,8 @@ namespace Exiv2 {
const XmpData& xmpData,
uint32_t root,
FindEncoderFct findEncoderFct,
TiffHeaderBase* pHeader
TiffHeaderBase* pHeader,
OffsetWriter* pOffsetWriter
)
{
/*
@ -1890,7 +1892,7 @@ namespace Exiv2 {
DataBuf header = pHeader->write();
BasicIo::AutoPtr tempIo(io.temporary()); // may throw
assert(tempIo.get() != 0);
IoWrapper ioWrapper(*tempIo, header.pData_, header.size_);
IoWrapper ioWrapper(*tempIo, header.pData_, header.size_, pOffsetWriter);
uint32_t imageIdx(uint32_t(-1));
createdTree->write(ioWrapper,
pHeader->byteOrder(),
@ -1898,6 +1900,7 @@ namespace Exiv2 {
uint32_t(-1),
uint32_t(-1),
imageIdx);
if (pOffsetWriter) pOffsetWriter->writeOffsets(*tempIo);
io.transfer(*tempIo); // may throw
#ifndef SUPPRESS_WARNINGS
EXV_INFO << "Write strategy: Intrusive\n";
@ -2202,6 +2205,27 @@ namespace Exiv2 {
std::cerr << "Not an image tag: " << key << " (4)\n";
#endif
return false;
} // TiffHeader::isImageTag
void OffsetWriter::setOrigin(OffsetId id, uint32_t origin, ByteOrder byteOrder)
{
offsetList_[id] = OffsetData(origin, byteOrder);
}
void OffsetWriter::setTarget(OffsetId id, uint32_t target)
{
OffsetList::iterator it = offsetList_.find(id);
if (it != offsetList_.end()) it->second.target_ = target;
}
void OffsetWriter::writeOffsets(BasicIo& io) const
{
for (OffsetList::const_iterator it = offsetList_.begin(); it != offsetList_.end(); ++it) {
io.seek(it->second.origin_, BasicIo::beg);
byte buf[4] = { 0, 0, 0, 0 };
l2Data(buf, it->second.target_, it->second.byteOrder_);
io.write(buf, 4);
}
}
}} // namespace Internal, Exiv2

@ -38,6 +38,8 @@
#include "types.hpp"
// + standard includes
#include <map>
#include <utility>
// *****************************************************************************
// namespace extensions
@ -328,7 +330,8 @@ namespace Exiv2 {
const XmpData& xmpData,
uint32_t root,
FindEncoderFct findEncoderFct,
TiffHeaderBase* pHeader
TiffHeaderBase* pHeader,
OffsetWriter* pOffsetWriter
);
private:
@ -413,6 +416,60 @@ namespace Exiv2 {
}; // class TiffMapping
/*!
@brief Class to insert pointers or offsets to computed addresses at
specific locations in an image. Used for offsets which are
best computed during the regular write process. They are
written in a second pass, using the writeOffsets() method.
*/
class OffsetWriter {
public:
//! Identifiers for supported offsets
enum OffsetId {
cr2RawIfdOffset //!< CR2 RAW IFD offset, a pointer in the CR2 header to the 4th IFD in a CR2 image
};
//! @name Manipulators
//@{
/*!
@brief Set the \em origin of the offset for \em id, i.e., the location in the image where the offset is,
and the byte order to encode the offset.
If the list doesn't contain an entry for \em id yet, this function will create one.
*/
void setOrigin(OffsetId id, uint32_t origin, ByteOrder byteOrder);
/*!
@brief Set the \em target for offset \em id, i.e., the address to which the offset points.
If the list doesn't contain an entry with \em id yet, this function won't do anything.
*/
void setTarget(OffsetId id, uint32_t target);
//@}
//! @name Accessors
//@{
//! Write the offsets to the IO instance \em io.
void writeOffsets(BasicIo& io) const;
//@}
private:
//! Data structure for the offset list.
struct OffsetData {
//! Default constructor
OffsetData() : origin_(0), target_(0), byteOrder_(littleEndian) {}
//! Constructor
OffsetData(uint32_t origin, ByteOrder byteOrder) : origin_(origin), target_(0), byteOrder_(byteOrder) {}
// DATA
uint32_t origin_; //!< Origin address
uint32_t target_; //!< Target address
ByteOrder byteOrder_; //!< Byte order to use to encode target address
};
//! Type of the list containing an identifier and an address pair.
typedef std::map<OffsetId, OffsetData> OffsetList;
// DATA
OffsetList offsetList_; //!< List of the offsets to replace
}; // class OffsetWriter
// Todo: Move this class to metadatum_int.hpp or tags_int.hpp
//! Unary predicate that matches an Exifdatum with a given IfdId.
class FindExifdatum {

Loading…
Cancel
Save