Added support for XMP sidecar files.

v0.27.3
Andreas Huggel 18 years ago
parent 07723af4a8
commit e4c96433d4

@ -106,7 +106,8 @@ CCSRC += rafimage.cpp \
value.cpp \
version.cpp \
properties.cpp \
xmp.cpp
xmp.cpp \
xmpsidecar.cpp
# Add library C source files to this list
ifndef HAVE_TIMEGM

@ -54,6 +54,7 @@ EXIV2_RCSID("@(#) $Id$")
#include "rafimage.hpp"
#include "tiffimage.hpp"
#include "orfimage.hpp"
#include "xmpsidecar.hpp"
// + standard includes
#include <cerrno>
@ -87,6 +88,7 @@ namespace Exiv2 {
{ ImageType::png, newPngInstance, isPngType, amRead, amRead, amRead, amNone },
#endif // EXV_HAVE_LIBZ
{ ImageType::raf, newRafInstance, isRafType, amRead, amRead, amRead, amNone },
{ ImageType::xmp, newXmpInstance, isXmpType, amNone, amNone, amReadWrite, amNone },
// End of list marker
{ ImageType::none, 0, 0, amNone, amNone, amNone, amNone }
};

@ -746,12 +746,7 @@ namespace Exiv2 {
Image::AutoPtr newExvInstance(BasicIo::AutoPtr io, bool create)
{
Image::AutoPtr image;
if (create) {
image = Image::AutoPtr(new ExvImage(io, true));
}
else {
image = Image::AutoPtr(new ExvImage(io, false));
}
image = Image::AutoPtr(new ExvImage(io, create));
if (!image->good()) image.reset();
return image;
}
@ -767,7 +762,7 @@ namespace Exiv2 {
|| memcmp(tmpBuf + 2, ExvImage::exiv2Id_, 5) != 0) {
result = false;
}
if (!advance || !result ) iIo.seek(-7, BasicIo::cur);
if (!advance || !result) iIo.seek(-7, BasicIo::cur);
return result;
}

@ -95,7 +95,7 @@ namespace Exiv2 {
*/
void setIptcData(const IptcData& iptcData);
/*!
@brief Not supported. MRW format does not contain a comment.
@brief Not supported. ORF format does not contain a comment.
Calling this function will throw an Error(32).
*/
void setComment(const std::string& comment);
@ -141,21 +141,19 @@ namespace Exiv2 {
//@}
}; // class OrfHeader
// *****************************************************************************
// 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 MrwImage instance and return an auto-pointer to it.
@brief Create a new OrfImage 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 newOrfInstance(BasicIo::AutoPtr io, bool create);
//! Check if the file iIo is a MRW image.
//! Check if the file iIo is an ORF image.
bool isOrfType(BasicIo& iIo, bool advance);
} // namespace Exiv2

@ -0,0 +1,180 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*
File: xmpsidecar.cpp
Version: $Rev$
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 07-Mar-08, ahu: created
Credits: See header file
*/
// *****************************************************************************
#include "rcsid.hpp"
EXIV2_RCSID("@(#) $Id$")
// *****************************************************************************
// included header files
#ifdef _MSC_VER
# include "exv_msvc.h"
#else
# include "exv_conf.h"
#endif
#include "xmpsidecar.hpp"
#include "image.hpp"
#include "basicio.hpp"
#include "error.hpp"
#include "xmp.hpp"
#include "futils.hpp"
// + standard includes
#include <string>
#include <iostream>
#include <cassert>
// *****************************************************************************
// class member definitions
namespace Exiv2 {
XmpSidecar::XmpSidecar(BasicIo::AutoPtr io)
: Image(ImageType::xmp, mdXmp, io)
{
} // XmpSidecar::XmpSidecar
void XmpSidecar::setExifData(const ExifData& /*exifData*/)
{
// Todo: implement me!
throw(Error(32, "Exif metadata", "XMP"));
}
void XmpSidecar::setIptcData(const IptcData& /*iptcData*/)
{
// Todo: implement me!
throw(Error(32, "IPTC metadata", "XMP"));
}
void XmpSidecar::setComment(const std::string& /*comment*/)
{
// not supported
throw(Error(32, "Image comment", "XMP"));
}
void XmpSidecar::readMetadata()
{
#ifdef DEBUG
std::cerr << "Reading XMP 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 (!isXmpType(*io_, false)) {
if (io_->error() || io_->eof()) throw Error(14);
throw Error(3, "XMP");
}
// Read the XMP packet from the IO stream
std::string xmpPacket;
const long len = 64 * 1024;
byte buf[len];
long l;
while ((l = io_->read(buf, len)) > 0) {
xmpPacket.append(reinterpret_cast<char*>(buf), l);
}
if (io_->error()) throw Error(14);
clearMetadata();
xmpPacket_ = xmpPacket;
if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Failed to decode XMP metadata.\n";
#endif
}
} // XmpSidecar::readMetadata
void XmpSidecar::writeMetadata()
{
if (io_->open() != 0) {
throw Error(9, io_->path(), strError());
}
IoCloser closer(*io_);
if (writeXmpFromPacket() == false) {
if (XmpParser::encode(xmpPacket_, xmpData_)) {
#ifndef SUPPRESS_WARNINGS
std::cerr << "Error: Failed to encode XMP metadata.\n";
#endif
}
}
if (xmpPacket_.size() > 0) {
BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
assert(tempIo.get() != 0);
// Write XMP packet
if ( tempIo->write(reinterpret_cast<const byte*>(xmpPacket_.data()),
static_cast<long>(xmpPacket_.size()))
!= static_cast<long>(xmpPacket_.size())) throw Error(21);
if (tempIo->error()) throw Error(21);
io_->close();
io_->transfer(*tempIo); // may throw
}
} // XmpSidecar::writeMetadata
// *************************************************************************
// free functions
Image::AutoPtr newXmpInstance(BasicIo::AutoPtr io, bool /*create*/)
{
Image::AutoPtr image(new XmpSidecar(io));
if (!image->good()) {
image.reset();
}
return image;
}
bool isXmpType(BasicIo& iIo, bool advance)
{
/*
Make sure the file starts with and (optional) XML declaration,
followed by an XMP header (<?xpacket ... ?>) or an <x:xmpmeta>
element. That doesn't cover all cases, since also x:xmpmeta is
optional, but let's wait and see.
*/
// Todo: Proper implementation
const int32_t len = 10;
byte buf[len];
iIo.read(buf, len);
if (iIo.error() || iIo.eof()) {
return false;
}
bool rc = false;
const std::string head(reinterpret_cast<const char*>(buf), len);
if ( head.substr(0, 5) == "<?xml"
|| head.substr(0, 9) == "<?xpacket"
|| head.substr(0, 10) == "<x:xmpmeta") {
rc = true;
}
if (!advance || !rc) {
iIo.seek(-len, BasicIo::cur);
}
return rc;
}
} // namespace Exiv2

@ -0,0 +1,127 @@
// ***************************************************************** -*- C++ -*-
/*
* Copyright (C) 2004-2008 Andreas Huggel <ahuggel@gmx.net>
*
* This program is part of the Exiv2 distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
*/
/*!
@file xmpsidecar.hpp
@brief An Image subclass to support XMP sidecar files
@version $Rev$
@author Andreas Huggel
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 07-Mar-08, ahu: created
*/
#ifndef XMPSIDECAR_HPP_
#define XMPSIDECAR_HPP_
// *****************************************************************************
// included header files
#include "image.hpp"
#include "basicio.hpp"
// + standard includes
#include <string>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
// *****************************************************************************
// class definitions
// Add XMP to the supported image formats
namespace ImageType {
const int xmp = 10; //!< XMP sidecar files (see class XmpSidecar)
}
/*!
@brief Class to access XMP sidecar files. They contain only XMP metadata.
*/
class XmpSidecar : public Image {
public:
//! @name Creators
//@{
/*!
@brief Constructor for an XMP sidecar file. 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.
*/
XmpSidecar(BasicIo::AutoPtr io);
//@}
//! @name Manipulators
//@{
void readMetadata();
void writeMetadata();
/*!
@brief Todo: Not supported yet, requires conversion from Exif to XMP.
Calling this function will throw an instance of Error(32).
*/
void setExifData(const ExifData& exifData);
/*!
@brief Todo: Not supported yet, requires conversion from IPTC to XMP.
Calling this function will throw an instance of Error(32).
*/
void setIptcData(const IptcData& iptcData);
/*!
@brief Not supported. XMP sidecar files do not contain a comment.
Calling this function will throw an instance of Error(32).
*/
void setComment(const std::string& comment);
//@}
//! @name Accessors
//@{
std::string mimeType() const { return "application/rdf+xml"; }
//@}
private:
//! @name NOT Implemented
//@{
//! Copy constructor
XmpSidecar(const XmpSidecar& rhs);
//! Assignment operator
XmpSidecar& operator=(const XmpSidecar& rhs);
//@}
}; // class XmpSidecar
// *****************************************************************************
// 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 XmpSidecar 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 newXmpInstance(BasicIo::AutoPtr io, bool create);
//! Check if the file iIo is an XMP sidecar file.
bool isXmpType(BasicIo& iIo, bool advance);
} // namespace Exiv2
#endif // #ifndef XMPSIDECAR_HPP_
Loading…
Cancel
Save