Alpha status TIFF image and parser, not yet added to Makefile

v0.27.3
Andreas Huggel 20 years ago
parent 23d1c91788
commit ef30cbbd50

@ -0,0 +1,226 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2006 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*
File: tiffimage.cpp
Version: $Rev$
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 15-Mar-06, ahu: created
*/
// *****************************************************************************
#include "rcsid.hpp"
EXIV2_RCSID("@(#) $Id: tiffparser.cpp 675 2006-01-25 04:16:58Z ahuggel $");
// Define DEBUG to output debug information to std::cerr, e.g, by calling make
// like this: make DEFS=-DDEBUG tiffparser.o
//#define DEBUG
// *****************************************************************************
// included header files
#ifdef _MSC_VER
# include "exv_msvc.h"
#else
# include "exv_conf.h"
#endif
#include "tiffimage.hpp"
#include "tiffparser.hpp"
#include "image.hpp"
#include "error.hpp"
#include "futils.hpp"
// + standard includes
#include <iostream>
#include <cassert>
// *****************************************************************************
// class member definitions
namespace Exiv2 {
const TiffStructure TiffImage::tiffStructure_[] = {
{ Tag::root, Group::none, newTiffDirectory, Group::ifd0 },
{ 0x8769, Group::ifd0, newTiffSubIfd, Group::exif },
{ 0x8825, Group::ifd0, newTiffSubIfd, Group::gps },
{ 0xa005, Group::exif, newTiffSubIfd, Group::iop },
{ Tag::next, Group::ifd0, newTiffDirectory, Group::ifd0 },
// End of list marker
{ Tag::none, Group::none, 0, Group::none }
};
TiffImage::TiffImage(BasicIo::AutoPtr io, bool create)
: Image(mdExif | mdComment), io_(io)
{
if (create) {
IoCloser closer(*io_);
io_->open();
}
} // TiffImage::TiffImage
bool TiffImage::good() const
{
if (io_->open() != 0) return false;
IoCloser closer(*io_);
return isThisType(*io_, false);
}
void TiffImage::clearMetadata()
{
clearExifData();
clearComment();
}
void TiffImage::setMetadata(const Image& image)
{
setExifData(image.exifData());
setComment(image.comment());
}
void TiffImage::clearExifData()
{
exifData_.clear();
}
void TiffImage::setExifData(const ExifData& exifData)
{
exifData_ = exifData;
}
void TiffImage::clearIptcData()
{
// not supported
}
void TiffImage::setIptcData(const IptcData& /*iptcData*/)
{
// not supported
}
void TiffImage::clearComment()
{
comment_.erase();
}
void TiffImage::setComment(const std::string& comment)
{
comment_ = comment;
}
void TiffImage::readMetadata()
{
#ifdef DEBUG
std::cerr << "Reading TIFF file " << io_->path() << "\n";
#endif
if (io_->open() != 0) {
throw Error(9, io_->path(), strError());
}
IoCloser closer(*io_);
// Ensure that this is the correct image type
if (!isThisType(*io_, false)) {
if (io_->error() || io_->eof()) throw Error(14);
throw Error(33);
}
clearMetadata();
// Read the image into a memory buffer
long len = io_->size();
DataBuf buf(len);
io_->read(buf.pData_, len);
if (io_->error() || io_->eof()) throw Error(14);
TiffParser::decode(this, tiffStructure_, buf.pData_, buf.size_);
} // TiffImage::readMetadata
void TiffImage::writeMetadata()
{
/*
Todo: implement me!
#ifdef DEBUG
std::cerr << "Writing TIFF file " << io_->path() << "\n";
#endif
// Read existing image
DataBuf buf;
if (io_->open() == 0) {
IoCloser closer(*io_);
// Ensure that this is the correct image type
if (isThisType(*io_, false)) {
// Read the image into a memory buffer
buf.alloc(io_->size());
io_->read(buf.pData_, buf.size_);
if (io_->error() || io_->eof()) {
buf.reset();
}
}
}
// Parse image, starting with a TIFF header component
TiffHeade2::AutoPtr head(new TiffHeade2);
if (buf.size_ != 0) {
head->read(buf.pData_, buf.size_);
}
Blob blob;
TiffParser::encode(blob, head.get(), this);
// Write new buffer to file
BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
assert (tempIo.get() != 0);
tempIo->write(&blob[0], static_cast<long>(blob.size()));
io_->close();
io_->transfer(*tempIo); // may throw
*/
} // TiffImage::writeMetadata
bool TiffImage::isThisType(BasicIo& iIo, bool advance) const
{
return isTiffType(iIo, advance);
}
// *************************************************************************
// free functions
Image::AutoPtr newTiffInstance(BasicIo::AutoPtr io, bool create)
{
Image::AutoPtr image(new TiffImage(io, create));
if (!image->good()) {
image.reset();
}
return image;
}
bool isTiffType(BasicIo& iIo, bool advance)
{
const uint32_t len = 8;
byte buf[len];
iIo.read(buf, len);
if (iIo.error() || iIo.eof()) {
return false;
}
TiffHeade2 tiffHeader;
bool rc = tiffHeader.read(buf, len);
if (!advance || !rc) {
iIo.seek(-len, BasicIo::cur);
}
return rc;
}
} // namespace Exiv2

@ -0,0 +1,191 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2006 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*!
@file tiffimage.hpp
@brief Class TiffImage
@version $Rev$
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 15-Mar-06, ahu: created
*/
#ifndef TIFFIMAGE_HPP_
#define TIFFIMAGE_HPP_
// *****************************************************************************
// included header files
#include "exif.hpp"
#include "iptc.hpp"
#include "image.hpp"
// + standard includes
#include <string>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
struct TiffStructure;
// *****************************************************************************
// type definitions
// *****************************************************************************
// class definitions
// Add TIFF to the supported image formats
namespace ImageType {
const int tiff = 4; //!< TIFF image type (see class TiffImage)
}
/*!
@brief Class to access raw TIFF images. Only Exif metadata and a comment
are supported. TIFF format does not contain IPTC metadata.
*/
class TiffImage : public Image {
friend bool isTiffType(BasicIo& iIo, bool advance);
//! @name NOT Implemented
//@{
//! Copy constructor
TiffImage(const TiffImage& rhs);
//! Assignment operator
TiffImage& operator=(const TiffImage& rhs);
//@}
public:
//! @name Creators
//@{
/*!
@brief Constructor that can either open an existing TIFF image or create
a new image from scratch. If a new image is to be created, any
existing data is overwritten. Since the constructor can not return
a result, callers should check the good() method after object
construction to determine success or failure.
@param io An auto-pointer that owns a BasicIo instance used for
reading and writing image metadata. \b Important: The constructor
takes ownership of the passed in BasicIo instance through the
auto-pointer. Callers should not continue to use the BasicIo
instance after it is passed to this method. Use the Image::io()
method to get a temporary reference.
@param create Specifies if an existing image should be read (false)
or if a new file should be created (true).
*/
TiffImage(BasicIo::AutoPtr io, bool create);
//! Destructor
~TiffImage() {}
//@}
//! @name Manipulators
//@{
void readMetadata();
/*!
@brief Todo: Write metadata back to the image. This method is not
yet implemented.
*/
void writeMetadata();
void setExifData(const ExifData& exifData);
void clearExifData();
/*!
@brief Not supported. TIFF format does not contain IPTC metadata.
Calling this function will do nothing.
*/
void setIptcData(const IptcData& iptcData);
/*!
@brief Not supported. TIFF format does not contain IPTC metadata.
Calling this function will do nothing.
*/
void clearIptcData();
void setComment(const std::string& comment);
void clearComment();
void setMetadata(const Image& image);
void clearMetadata();
ExifData& exifData() { return exifData_; }
IptcData& iptcData() { return iptcData_; }
//@}
//! @name Accessors
//@{
bool good() const;
const ExifData& exifData() const { return exifData_; }
const IptcData& iptcData() const { return iptcData_; }
std::string comment() const { return comment_; }
BasicIo& io() const { return *io_; }
//@}
private:
//! @name Accessors
//@{
/*!
@brief Determine if the content of the BasicIo instance is a TIFF image.
The advance flag determines if the read position in the stream is
moved (see below). This applies only if the type matches and the
function returns true. If the type does not match, the stream
position is not changed. However, if reading from the stream fails,
the stream position is undefined. Consult the stream state to obtain
more information in this case.
@param iIo BasicIo instance to read from.
@param advance Flag indicating whether the position of the io
should be advanced by the number of characters read to
analyse the data (true) or left at its original
position (false). This applies only if the type matches.
@return true if the data matches the type of this class;<BR>
false if the data does not match
*/
bool isThisType(BasicIo& iIo, bool advance) const;
/*!
@brief Todo: Write TIFF header. Not implemented yet.
*/
int writeHeader(BasicIo& oIo) const;
//@}
// DATA
BasicIo::AutoPtr io_; //!< Image data io pointer
ExifData exifData_; //!< Exif data container
IptcData iptcData_; //!< IPTC data container
std::string comment_; //!< User comment
static const TiffStructure tiffStructure_[]; //<! TIFF structure
}; // class TiffImage
// *****************************************************************************
// template, inline and free functions
// These could be static private functions on Image subclasses but then
// ImageFactory needs to be made a friend.
/*!
@brief Create a new TiffImage instance and return an auto-pointer to it.
Caller owns the returned object and the auto-pointer ensures that
it will be deleted.
*/
Image::AutoPtr newTiffInstance(BasicIo::AutoPtr io, bool create);
//! Check if the file iIo is a TIFF image.
bool isTiffType(BasicIo& iIo, bool advance);
} // namespace Exiv2
#endif // #ifndef TIFFIMAGE_HPP_

@ -0,0 +1,411 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2006 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*
File: tiffparser.cpp
Version: $Rev$
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 15-Mar-06, ahu: created
*/
// *****************************************************************************
#include "rcsid.hpp"
EXIV2_RCSID("@(#) $Id: tiffparser.cpp 675 2006-01-25 04:16:58Z ahuggel $");
// Define DEBUG to output debug information to std::cerr, e.g, by calling make
// like this: make DEFS=-DDEBUG tiffparser.o
//#define DEBUG
// *****************************************************************************
// included header files
#ifdef _MSC_VER
# include "exv_msvc.h"
#else
# include "exv_conf.h"
#endif
#include "tiffparser.hpp"
#include "image.hpp"
#include "exif.hpp"
#include "tags.hpp"
#include "error.hpp"
#include "futils.hpp"
// + standard includes
#include <iostream>
#include <iomanip>
#include <cassert>
/* --------------------------------------------------------------------------
Todo:
+ Fix CiffHeader according to TiffHeade2
+ Combine Error(15) and Error(33), add format argument %1
+ Search crwimage for todos, fix writeMetadata comment
+ rename all Ciff stuff to Crw for easier reference
-------------------------------------------------------------------------- */
// *****************************************************************************
// class member definitions
namespace Exiv2 {
void TiffParser::decode(Image* pImage,
const TiffStructure* pTiffStructure,
const byte* pData,
uint32_t size)
{
assert(pImage != 0);
assert(pData != 0);
TiffHeade2 tiffHeader;
if (!tiffHeader.read(pData, size) || tiffHeader.offset() >= size) {
throw Error(3, "TIFF");
}
TiffComponent::AutoPtr rootDir
= create(Tag::root, Group::none, pTiffStructure);
if (0 == rootDir.get()) return;
rootDir->read(pData, size, tiffHeader.offset(), tiffHeader.byteOrder());
#ifdef DEBUG
tiffHeader.print(std::cerr);
rootDir->print(std::cerr, tiffHeader.byteOrder());
#endif
rootDir->decode(*pImage, tiffHeader.byteOrder());
} // TiffParser::decode
TiffComponent::AutoPtr TiffParser::create(int32_t tag,
uint16_t group,
const TiffStructure* pTiffStructure)
{
const TiffStructure* ts = 0;
for (int i = 0; pTiffStructure[i].tag_ != Tag::none; ++i) {
if (tag == pTiffStructure[i].tag_ && group == pTiffStructure[i].group_) {
ts = &pTiffStructure[i];
break;
}
}
TiffComponent::AutoPtr tc(0);
if (ts && ts->newTiffCompFct_) {
tc = ts->newTiffCompFct_(ts->newGroup_, pTiffStructure);
}
if (!ts) {
tc = TiffComponent::AutoPtr(new TiffEntry);
}
return tc;
} // TiffParser::create
TiffDirectory::~TiffDirectory()
{
Components::iterator b = components_.begin();
Components::iterator e = components_.end();
for (Components::iterator i = b; i != e; ++i) {
delete *i;
}
delete pNext_;
} // TiffDirectory::~TiffDirectory
TiffEntryBase::~TiffEntryBase()
{
if (isAllocated_) delete[] pData_;
} // TiffEntryBase::~TiffEntryBase
const uint16_t TiffHeade2::tag_ = 42;
bool TiffHeade2::read(const byte* pData, uint32_t size)
{
if (size < 8) return false;
if (pData[0] == 0x49 && pData[1] == 0x49) {
byteOrder_ = littleEndian;
}
else if (pData[0] == 0x4d && pData[1] == 0x4d) {
byteOrder_ = bigEndian;
}
else {
return false;
}
if (tag_ != getUShort(pData + 2, byteOrder_)) return false;
offset_ = getULong(pData + 4, byteOrder_);
return true;
} // TiffHeade2::read
void TiffComponent::read(const byte* pData,
uint32_t size,
uint32_t start,
ByteOrder byteOrder)
{
doRead(pData, size, start, byteOrder);
} // TiffComponent::read
void TiffEntryBase::doRead(const byte* pData,
uint32_t size,
uint32_t start,
ByteOrder byteOrder)
{
if (size - start < 12) throw Error(3, "TIFF");
const byte* p = pData + start;
tag_ = getUShort(p, byteOrder);
p += 2;
type_ = getUShort(p, byteOrder);
// todo: check type
p += 2;
count_ = getULong(p, byteOrder);
p += 4;
offset_ = getULong(p, byteOrder);
#ifdef DEBUG
std::cout << "TiffEntryBase for "
<< "tag 0x" << std::hex << tag_
<< ", type " << std::dec << type_
<< ", count " << count_
<< ", offset 0x" << std::hex << offset_
<< std::dec"\n";
#endif
size_ = TypeInfo::typeSize(typeId()) * count();
if (size_ > 4) {
if (size < offset() + size_) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Upper boundary of data for "
<< "directory " << group() << ", " // todo: ExifTags::ifdName(ifdId_)
<< " entry 0x" << std::setw(4)
<< std::setfill('0') << std::hex << tag()
<< " is out of bounds:\n"
<< " Offset = 0x" << std::setw(8)
<< std::setfill('0') << std::hex << offset()
<< ", size = " << std::dec << size_
<< ", exceeds buffer size by "
<< offset() + size_ - size
<< " Bytes; adjusting the size\n";
#endif
size_ = size - offset();
// todo: adjust count_, make size_ a multiple of typeSize
}
pData_ = pData + offset();
}
else {
pData_ = pData + start + 8;
}
} // TiffEntryBase::doRead
void TiffEntry::doRead(const byte* pData,
uint32_t size,
uint32_t start,
ByteOrder byteOrder)
{
TiffEntryBase::doRead(pData, size, start, byteOrder);
} // TiffEntry::doRead
void TiffDirectory::doRead(const byte* pData,
uint32_t size,
uint32_t start,
ByteOrder byteOrder)
{
if (size < start + 2) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Error: "
<< "Directory " << group() << ": " // todo: ExifTags::ifdName(ifdId_)
<< " IFD exceeds data buffer, cannot read entry count.\n";
#endif
return;
}
uint32_t o = start;
const uint16_t n = getUShort(pData + o, byteOrder);
o += 2;
for (uint16_t i = 0; i < n; ++i) {
if (size < o + 12) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Error: "
<< "Directory " << group() << ": " // todo: ExifTags::ifdName(ifdId_)
<< " IFD entry " << i
<< " lies outside of the data buffer.\n";
#endif
return;
}
uint16_t tag = getUShort(pData + o, byteOrder);
TiffComponent::AutoPtr tc
= TiffParser::create(tag, group(), pTiffStructure());
tc->read(pData, size, o, byteOrder);
components_.push_back(tc.release());
o += 12;
}
if (size < o + 4) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Error: "
<< "Directory " << group() << ": " // todo: ExifTags::ifdName(ifdId_)
<< " IFD exceeds data buffer, cannot read next pointer.\n";
#endif
return;
}
uint32_t next = getLong(pData + o, byteOrder);
if (next) {
pNext_ = TiffParser::create(Tag::next, group(), pTiffStructure()).release();
pNext_->read(pData, size, next, byteOrder);
}
} // TiffDirectory::doRead
void TiffSubIfd::doRead(const byte* pData,
uint32_t size,
uint32_t start,
ByteOrder byteOrder)
{
TiffEntryBase::doRead(pData, size, start, byteOrder);
if (typeId() == unsignedLong && count() >= 1) {
uint32_t offset = getULong(this->pData(), byteOrder);
ifd_.read(pData, size, offset, byteOrder);
}
#ifndef SUPPRESS_WARNINGS
else {
std::cerr << "Warning: "
<< "Directory " << group() << ", " // todo: ExifTags::ifdName(ifdId_)
<< " entry 0x" << std::setw(4)
<< std::setfill('0') << std::hex << tag()
<< " doesn't look like a sub-IFD.";
}
#endif
} // TiffSubIfd::read
void TiffComponent::decode(Image& image, ByteOrder byteOrder) const
{
doDecode(image, byteOrder);
} // TiffComponent::decode
void TiffEntryBase::doDecode(Image& image, ByteOrder byteOrder) const
{
ExifKey k(tag(), "Image"); // todo needs ifdItem
TypeId t = typeId();
Value::AutoPtr v = Value::create(t);
v->read(pData_, size_, byteOrder);
image.exifData().add(k, v.get());
} // TiffEntryBase::doDecode
void TiffEntry::doDecode(Image& image, ByteOrder byteOrder) const
{
TiffEntryBase::doDecode(image, byteOrder);
} // TiffEntry::doDecode
void TiffDirectory::doDecode(Image& image, ByteOrder byteOrder) const
{
Components::const_iterator b = components_.begin();
Components::const_iterator e = components_.end();
for (Components::const_iterator i = b; i != e; ++i) {
(*i)->decode(image, byteOrder);
}
if (pNext_) pNext_->decode(image, byteOrder);
} // TiffDirectory::doDecode
void TiffSubIfd::doDecode(Image& image, ByteOrder byteOrder) const
{
ifd_.decode(image, byteOrder);
} // TiffSubIfd::doDecode
void TiffHeade2::print(std::ostream& os, const std::string& prefix) const
{
os << prefix
<< "Header, offset = 0x" << std::setw(8) << std::setfill('0')
<< std::hex << std::right << offset_ << "\n";
} // TiffHeade2::print
void TiffComponent::print(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const
{
doPrint(os, byteOrder, prefix);
} // TiffComponent::print
void TiffEntryBase::doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const
{
os << prefix
<< "tag = 0x" << std::setw(4) << std::setfill('0')
<< std::hex << std::right << tag()
<< ", type = " << TypeInfo::typeName(typeId())
<< ", count = " << std::dec << count()
<< ", offset = " << offset() << "\n";
TypeId t = typeId();
Value::AutoPtr v = Value::create(t);
v->read(pData_, size_, byteOrder);
if (v->size() < 100) {
os << prefix << *v << "\n";
}
} // TiffEntryBase::doPrint
void TiffEntry::doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const
{
TiffEntryBase::doPrint(os, byteOrder, prefix);
} // TiffEntry::doPrint
void TiffDirectory::doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const
{
os << prefix << "Directory " << group()
<< " with " << components_.size() << " entries.\n";
Components::const_iterator b = components_.begin();
Components::const_iterator e = components_.end();
for (Components::const_iterator i = b; i != e; ++i) {
(*i)->print(os, byteOrder, prefix + " ");
}
if (pNext_) {
os << prefix << "Next directory:\n";
pNext_->print(os, byteOrder, prefix);
}
else {
os << prefix << "No next directory.\n";
}
} // TiffDirectory::doPrint
void TiffSubIfd::doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const
{
TiffEntryBase::doPrint(os, byteOrder, prefix);
ifd_.print(os, byteOrder, prefix);
} // TiffSubIfd::doPrint
// *************************************************************************
// free functions
TiffComponent::AutoPtr newTiffDirectory(uint16_t group,
const TiffStructure* pTiffStructure)
{
return TiffComponent::AutoPtr(new TiffDirectory(group, pTiffStructure));
}
TiffComponent::AutoPtr newTiffSubIfd(uint16_t group,
const TiffStructure* pTiffStructure)
{
return TiffComponent::AutoPtr(new TiffSubIfd(group, pTiffStructure));
}
} // namespace Exiv2

@ -0,0 +1,491 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2006 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*!
@file tiffparser.hpp
@brief Class TiffParser to parse TIFF data.
@version $Rev$
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 15-Mar-06, ahu: created
*/
#ifndef TIFFPARSER_HPP_
#define TIFFPARSER_HPP_
// *****************************************************************************
// included header files
#include "exif.hpp"
#include "iptc.hpp"
#include "image.hpp"
#include "types.hpp"
// + standard includes
#include <iostream>
#include <iosfwd>
#include <string>
#include <vector>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class declarations
struct TiffStructure;
// *****************************************************************************
// type definitions
// *****************************************************************************
// class definitions
/*!
Known TIFF groups
Todo: what exactly are these and where should they go?
Are they going to be mapped to the second part of an Exif key or are they
the second part of the key?
*/
namespace Group {
const uint16_t none = 0; //!< Dummy group
const uint16_t ifd0 = 1; //!< Exif IFD0
const uint16_t ifd1 = 2; //!< Thumbnail IFD
const uint16_t exif = 3; //!< Exif IFD
const uint16_t gps = 4; //!< GPS IFD
const uint16_t iop = 5; //!< Interoperability IFD
const uint16_t makernote = 256; //!< Makernote
const uint16_t canonmn = 257; //!< Canon makernote
}
/*!
Known TIFF tags
Todo: Same Q as above...
*/
namespace Tag {
const int32_t none = -1; //!< Dummy tag
const int32_t root = -2; //!< Special tag: root IFD
const int32_t next = -3; //!< Special tag: next IFD
}
/*!
@brief Interface class for components of a TIFF directory hierarchy. Both
TIFF directories as well as entries implement this interface. This
class is implemented as NVI (non-virtual interface).
*/
class TiffComponent {
public:
//! TiffComponent auto_ptr type
typedef std::auto_ptr<TiffComponent> AutoPtr;
//! Container type to hold all metadata
typedef std::vector<TiffComponent*> Components;
//! @name Creators
//@{
//! Constructor
TiffComponent(uint16_t group, const TiffStructure* pTiffStructure)
: group_(group), pTiffStructure_(pTiffStructure) {}
//! Virtual destructor.
virtual ~TiffComponent() {}
//@}
//! @name Manipulators
//@{
/*!
@brief Read a component from a data buffer
@param pData Pointer to the data buffer, starting with a TIFF header.
@param size Number of bytes in the data buffer.
@param start Component starts at \em pData + \em start.
@param byteOrder Applicable byte order (little or big endian).
@throw Error If the component cannot be parsed.
*/
void read(const byte* pData,
uint32_t size,
uint32_t start,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
//*! Return the group id of this component
uint16_t group() const { return group_; }
//*! Return the TIFF structure
const TiffStructure* pTiffStructure() const { return pTiffStructure_; }
/*!
@brief Decode metadata from the component and add it to
\em image.
@param image Image to add the metadata to
@param byteOrder Byte order
*/
void decode(Image& image, ByteOrder byteOrder) const;
/*!
@brief Print debug info about a component to \em os.
@param os Output stream to write to
@param byteOrder Byte order
@param prefix Prefix to be written before each line of output
*/
void print(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix ="") const;
//@}
protected:
//! @name Manipulators
//@{
//! Implements read().
virtual void doRead(const byte* pData,
uint32_t size,
uint32_t start,
ByteOrder byteOrder) =0;
//@}
//! @name Accessors
//@{
//! Implements decode()
virtual void doDecode(Image& image,
ByteOrder byteOrder) const =0;
//! Implements print()
virtual void doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const =0;
//@}
private:
// DATA
uint16_t group_; //!< Group id for this component
const TiffStructure* pTiffStructure_; //!< TIFF structure for this component
}; // class TiffComponent
/*!
@brief This baseclass provides the common functionality of an IFD directory entry
and defines the interface for derived concrete entries.
todo: make sure this class is an ABC
*/
class TiffEntryBase : public TiffComponent {
public:
//! @name Creators
//@{
//! Default constructor
TiffEntryBase()
: TiffComponent(Group::none, 0),
tag_(0), type_(0), count_(0), offset_(0),
size_(0), pData_(0), isAllocated_(false) {}
//! Virtual destructor.
virtual ~TiffEntryBase();
//@}
//! @name Accessors
//@{
//! Return the tag of this entry.
uint16_t tag() const { return tag_; }
//! Return the Exiv2 type which corresponds to the field type.
TypeId typeId() const { return TypeId(type_); }
//! Return the number of components in this entry.
uint32_t count() const { return count_; }
//! Return the offset relative to the start of the TIFF header.
uint32_t offset() const { return offset_; }
//! Return the size of this component in bytes
uint32_t size() const { return size_; }
//! Return a pointer to the data area of this component
const byte* pData() const { return pData_; }
//@}
protected:
//! @name Manipulators
//@{
//! Implements read().
virtual void doRead(const byte* pData,
uint32_t size,
uint32_t start,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
//! Implements decode() for a TIFF IFD entry
virtual void doDecode(Image& image, ByteOrder byteOrder) const;
//! Implements print() for a TIFF IFD entry
virtual void doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const;
//@}
private:
// DATA
uint16_t tag_; //!< Tag that identifies the field
uint16_t type_; //!< Field Type
uint32_t count_; //!< The number of values of the indicated Type
uint32_t offset_; //!< Offset to the data area from start of the TIFF header
/*!
Size of the data buffer holding the value in bytes, there is no
minimum size.
*/
uint32_t size_;
const byte* pData_; //!< Pointer to the data area
bool isAllocated_; //!< True if this entry owns the value data
}; // class TiffEntryBase
/*!
@brief A standard TIFF IFD entry. The value is kept in a data buffer.
*/
class TiffEntry : public TiffEntryBase {
public:
//! @name Creators
//@{
//! Virtual destructor.
virtual ~TiffEntry() {}
//@}
private:
//! @name Manipulators
//@{
//! Implements read().
virtual void doRead(const byte* pData,
uint32_t size,
uint32_t start,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
virtual void doDecode(Image& image, ByteOrder byteOrder) const;
//! Implements print() for a TIFF IFD entry
virtual void doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const;
//@}
}; // class TiffEntry
//! This class models a TIFF directory (%Ifd).
class TiffDirectory : public TiffComponent {
public:
//! @name Creators
//@{
//! Default constructor
TiffDirectory(uint16_t group, const TiffStructure* pTiffStructure)
: TiffComponent(group, pTiffStructure), pNext_(0) {}
//! Virtual destructor
virtual ~TiffDirectory();
//@}
private:
//! @name Manipulators
//@{
virtual void doRead(const byte* pData,
uint32_t size,
uint32_t start,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
virtual void doDecode(Image& image,
ByteOrder byteOrder) const;
virtual void doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const;
//@}
private:
// DATA
Components components_; //!< List of components in this directory
TiffComponent* pNext_; //!< Pointer to the next IFD
}; // class TiffDirectory
//! This class models a TIFF sub-directory (%SubIfd).
class TiffSubIfd : public TiffEntryBase {
public:
//! @name Creators
//@{
//! Default constructor
TiffSubIfd(uint16_t group, const TiffStructure* pTiffStructure)
: ifd_(group, pTiffStructure) {}
//! Virtual destructor
virtual ~TiffSubIfd() {}
//@}
private:
//! @name Manipulators
//@{
virtual void doRead(const byte* pData,
uint32_t size,
uint32_t start,
ByteOrder byteOrder);
//@}
//! @name Accessors
//@{
virtual void doDecode(Image& image,
ByteOrder byteOrder) const;
virtual void doPrint(std::ostream& os,
ByteOrder byteOrder,
const std::string& prefix) const;
//@}
private:
// DATA
TiffDirectory ifd_; //!< The subdirectory
}; // class TiffDirectory
/*!
@brief This class models a TIFF header structure.
*/
class TiffHeade2 {
public:
//! @name Creators
//@{
//! Default constructor
TiffHeade2()
: byteOrder_ (littleEndian),
offset_ (0x00000008)
{}
//@}
//! @name Manipulators
//@{
/*!
@brief Read the TIFF header from a data buffer. Return false if the
data buffer does not contain a TIFF header, else true.
@param pData Pointer to the data buffer.
@param size Number of bytes in the data buffer.
*/
bool read(const byte* pData, uint32_t size);
//@}
//! @name Accessors
//@{
/*!
@brief Write the TIFF header to the binary image \em blob.
This method appends to the blob.
@param blob Binary image to add to.
@throw Error If the header cannot be written.
*/
void write(Blob& blob) const;
/*!
@brief Print debug info for the TIFF header to \em os.
@param os Output stream to write to.
@param prefix Prefix to be written before each line of output.
*/
void print(std::ostream& os, const std::string& prefix ="") const;
//! Return the byte order (little or big endian).
ByteOrder byteOrder() const { return byteOrder_; }
//! Return the offset to the start of the root directory
uint32_t offset() const { return offset_; }
//@}
private:
// DATA
ByteOrder byteOrder_; //!< Applicable byte order
uint32_t offset_; //!< Offset to the start of the root dir
static const uint16_t tag_; //!< 42, identifies the buffer as TIFF data
}; // class TiffHeade2
/*!
Type for a function pointer for functions to create TIFF components.
Todo: This may eventually need to also have access to the image or parse tree
in order to make decisions based on the value of other tags.
*/
typedef TiffComponent::AutoPtr (*NewTiffCompFct)(uint16_t group,
const TiffStructure* tiffStructure);
/*!
Table describing the TIFF structure of an image format for reading and writing.
Different tables can be used to support different TIFF based image formats.
*/
struct TiffStructure {
int32_t tag_; //!< Tag
uint16_t group_; //!< Group that contains the tag
NewTiffCompFct newTiffCompFct_; //!< Function to create the correct TIFF component
uint16_t newGroup_; //!< Group of the newly created component
};
/*!
Stateless parser class for data in TIFF format.
*/
class TiffParser {
public:
/*!
@brief Decode TIFF metadata from a data buffer \em pData of length
\em size into \em image.
This is the entry point to access image data in TIFF format. The
parser uses classes TiffHeade2, TiffEntry, TiffDirectory.
@param pImage Pointer to the %Exiv2 TIFF image to hold the
metadata read from the buffer.
@param pTiffStructure Pointer to a table describing the TIFF structure
used to decode the data.
@param pData Pointer to the data buffer. Must point to data
in TIFF format; no checks are performed.
@param size Length of the data buffer.
@throw Error If the data buffer cannot be parsed.
*/
static void decode( Image* pImage,
const TiffStructure* pTiffStructure,
const byte* pData,
uint32_t size);
/*!
@brief Create the appropriate TiffComponent to handle the \em tag in
\em group.
Uses table \em pTiffStructure to derive the correct component. If a
tag, group tupel is not found in the table, a TiffEntry is created. If
the pointer that is returned is 0, then the tag should be ignored.
*/
static TiffComponent::AutoPtr create( int32_t tag,
uint16_t group,
const TiffStructure* pTiffStructure);
}; // class TiffParser
// *****************************************************************************
// template, inline and free functions
//!< Function to create and initialize a new TIFF directory
TiffComponent::AutoPtr newTiffDirectory(uint16_t group,
const TiffStructure* pTiffStructure);
//!< Function to create and initialize a new TIFF sub-directory
TiffComponent::AutoPtr newTiffSubIfd(uint16_t group,
const TiffStructure* pTiffStructure);
} // namespace Exiv2
#endif // #ifndef TIFFPARSER_HPP_
Loading…
Cancel
Save