Added preview support (Vladimir Nadvornik)
This commit is contained in:
parent
6b93409e26
commit
26b488a255
@ -65,6 +65,7 @@ BINSRC = addmoddel.cpp \
|
||||
iptctest.cpp \
|
||||
key-test.cpp \
|
||||
largeiptc-test.cpp \
|
||||
prevtest.cpp \
|
||||
stringto-test.cpp \
|
||||
tiff-test.cpp \
|
||||
write-test.cpp \
|
||||
|
||||
42
samples/prevtest.cpp
Normal file
42
samples/prevtest.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
// prevtest.cpp, $Rev$
|
||||
// Test access to preview images
|
||||
|
||||
#include <exiv2/image.hpp>
|
||||
#include <exiv2/preview.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
int main(int argc, char* const argv[])
|
||||
try {
|
||||
|
||||
if (argc != 2) {
|
||||
std::cout << "Usage: " << argv[0] << " file\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(argv[1]);
|
||||
assert(image.get() != 0);
|
||||
image->readMetadata();
|
||||
|
||||
Exiv2::PreviewImageLoader loader(*image);
|
||||
|
||||
Exiv2::PreviewPropertiesList list = loader.getPreviewPropertiesList();
|
||||
|
||||
for (Exiv2::PreviewPropertiesList::iterator pos = list.begin(); pos != list.end(); pos++)
|
||||
{
|
||||
char buf[50];
|
||||
Exiv2::PreviewImage image = loader.getPreviewImage(*pos);
|
||||
sprintf(buf, "%ld", image.length());
|
||||
image.writeFile(std::string(argv[1]) + "_" + buf);
|
||||
std::cout << "found preview " << pos->id_ << ", length: " << pos->length_ << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (Exiv2::AnyError& e) {
|
||||
std::cout << "Caught Exiv2 exception '" << e << "'\n";
|
||||
return -1;
|
||||
}
|
||||
@ -94,7 +94,8 @@ ifdef HAVE_LIBZ
|
||||
CCSRC += pngimage.cpp \
|
||||
pngchunk.cpp
|
||||
endif
|
||||
CCSRC += properties.cpp \
|
||||
CCSRC += preview.cpp \
|
||||
properties.cpp \
|
||||
psdimage.cpp \
|
||||
rafimage.cpp \
|
||||
sigmamn.cpp \
|
||||
|
||||
362
src/preview.cpp
Normal file
362
src/preview.cpp
Normal file
@ -0,0 +1,362 @@
|
||||
// ***************************************************************** -*- 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: preview.cpp
|
||||
Version: $Rev$
|
||||
Author(s): Vladimir Nadvornik (vn) <nadvornik@suse.cz>
|
||||
History: 18-Sep-08, vn: created
|
||||
*/
|
||||
// *****************************************************************************
|
||||
#include "rcsid.hpp"
|
||||
EXIV2_RCSID("@(#) $Id$")
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#ifdef _MSC_VER
|
||||
# include "exv_msvc.h"
|
||||
#else
|
||||
# include "exv_conf.h"
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "preview.hpp"
|
||||
#include "futils.hpp"
|
||||
|
||||
#include "image.hpp"
|
||||
#include "cr2image.hpp"
|
||||
|
||||
|
||||
namespace Exiv2 {
|
||||
|
||||
/*!
|
||||
Base class for image loaders. Provides virtual methods for reading properties
|
||||
and DataBuf.
|
||||
*/
|
||||
class Loader {
|
||||
protected:
|
||||
Loader(PreviewProperties::PreviewId id, const Image &image);
|
||||
|
||||
public:
|
||||
typedef std::auto_ptr<Loader> AutoPtr;
|
||||
|
||||
//! Create a Loader subclass for requested id
|
||||
static Loader::AutoPtr create(PreviewProperties::PreviewId id, const Image &image);
|
||||
|
||||
//! Check if a preview image with given params exists in the image
|
||||
virtual bool valid() const = 0;
|
||||
|
||||
//! Get properties of a preview image with given params
|
||||
virtual PreviewProperties getProperties() const;
|
||||
|
||||
//! Get properties of a preview image with given params
|
||||
virtual DataBuf getData() const = 0;
|
||||
|
||||
//! A number of image loaders configured in the loaderList_ table
|
||||
static PreviewProperties::PreviewId getNumLoaders();
|
||||
|
||||
protected:
|
||||
typedef AutoPtr (*CreateFunc)(PreviewProperties::PreviewId id, const Image &image, int parIdx);
|
||||
|
||||
struct LoaderList {
|
||||
const char *imageMimeType_; //!< Image type for which is the loader valid, NULL matches all images
|
||||
CreateFunc create_; //!< Function that creates particular loader instance
|
||||
int parIdx_; //!< Parameter that is passed into CreateFunc
|
||||
|
||||
};
|
||||
|
||||
static const LoaderList loaderList_[]; // PreviewId is an index to this table
|
||||
|
||||
PreviewProperties::PreviewId id_;
|
||||
const Image &image_;
|
||||
};
|
||||
|
||||
|
||||
//! Loader for Jpeg previews that are not read into ExifData directly
|
||||
class LoaderExifJpeg : public Loader {
|
||||
public:
|
||||
LoaderExifJpeg(PreviewProperties::PreviewId id, const Image &image, int parIdx);
|
||||
|
||||
virtual bool valid() const;
|
||||
virtual PreviewProperties getProperties() const;
|
||||
virtual DataBuf getData() const;
|
||||
|
||||
long getOffset() const;
|
||||
long getLength() const;
|
||||
|
||||
protected:
|
||||
|
||||
// this table lists possible offset/length key pairs
|
||||
// parIdx is an index to this table
|
||||
|
||||
struct Param {
|
||||
const char* offsetKey_;
|
||||
const char* lengthKey_;
|
||||
};
|
||||
static const Param param_[];
|
||||
|
||||
ExifKey offsetKey_;
|
||||
ExifKey lengthKey_;
|
||||
};
|
||||
|
||||
Loader::AutoPtr createLoaderExifJpeg(PreviewProperties::PreviewId id, const Image &image, int parIdx);
|
||||
|
||||
|
||||
//! Loader for standard Exif thumbnail - just a wrapper around ExifThumbC
|
||||
class LoaderExifThumbC : public Loader {
|
||||
public:
|
||||
LoaderExifThumbC(PreviewProperties::PreviewId id, const Image &image);
|
||||
|
||||
virtual bool valid() const;
|
||||
virtual PreviewProperties getProperties() const;
|
||||
virtual DataBuf getData() const;
|
||||
|
||||
protected:
|
||||
ExifThumbC thumb_;
|
||||
};
|
||||
|
||||
Loader::AutoPtr createLoaderExifThumbC(PreviewProperties::PreviewId id, const Image &image, int parIdx);
|
||||
|
||||
// *****************************************************************************
|
||||
// class member definitions
|
||||
|
||||
const Loader::LoaderList Loader::loaderList_[] = {
|
||||
{ NULL, createLoaderExifThumbC, 0},
|
||||
{ NULL, createLoaderExifJpeg, 0},
|
||||
{ NULL, createLoaderExifJpeg, 1},
|
||||
{ NULL, createLoaderExifJpeg, 2},
|
||||
{ NULL, createLoaderExifJpeg, 3},
|
||||
{ "image/x-canon-cr2", createLoaderExifJpeg, 4} // FIXME: this needs to be fixed (enabled) in cr2image.cpp
|
||||
};
|
||||
|
||||
const LoaderExifJpeg::Param LoaderExifJpeg::param_[] = {
|
||||
{ "Exif.Image.JPEGInterchangeFormat", "Exif.Image.JPEGInterchangeFormatLength" }, // 0
|
||||
{ "Exif.SubImage1.JPEGInterchangeFormat", "Exif.SubImage1.JPEGInterchangeFormatLength", }, // 1
|
||||
{ "Exif.SubImage2.JPEGInterchangeFormat", "Exif.SubImage2.JPEGInterchangeFormatLength", }, // 2
|
||||
{ "Exif.Image2.JPEGInterchangeFormat", "Exif.Image2.JPEGInterchangeFormatLength", }, // 3
|
||||
{ "Exif.Image.StripOffsets", "Exif.Image.StripByteCounts", }, // 4
|
||||
};
|
||||
|
||||
|
||||
PreviewImage::PreviewImage(const PreviewProperties &properties, DataBuf &data)
|
||||
: properties_(properties), data_(data)
|
||||
{
|
||||
}
|
||||
|
||||
PreviewImage::PreviewImage(const PreviewImage &src)
|
||||
: properties_(src.properties_), data_(const_cast<DataBuf&>(src.data_))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
long PreviewImage::writeFile(const std::string& path) const
|
||||
{
|
||||
std::string name = path + extension();
|
||||
return Exiv2::writeFile(data_, name);
|
||||
}
|
||||
|
||||
DataBuf &PreviewImage::data()
|
||||
{
|
||||
return data_;
|
||||
}
|
||||
|
||||
const char* PreviewImage::mimeType() const
|
||||
{
|
||||
return properties_.mimeType_;
|
||||
}
|
||||
|
||||
const char* PreviewImage::extension() const
|
||||
{
|
||||
return properties_.extension_;
|
||||
}
|
||||
|
||||
long PreviewImage::length() const
|
||||
{
|
||||
return properties_.length_;
|
||||
}
|
||||
|
||||
Loader::AutoPtr Loader::create(PreviewProperties::PreviewId id, const Image &image)
|
||||
{
|
||||
if (id < 0 || id >= Loader::getNumLoaders())
|
||||
return AutoPtr();
|
||||
|
||||
if (loaderList_[id].imageMimeType_ &&
|
||||
std::string(loaderList_[id].imageMimeType_) != std::string(image.mimeType()))
|
||||
return AutoPtr();
|
||||
|
||||
AutoPtr loader = loaderList_[id].create_(id, image, loaderList_[id].parIdx_);
|
||||
|
||||
if (loader.get() && !loader->valid()) loader.reset();
|
||||
return loader;
|
||||
}
|
||||
|
||||
Loader::Loader(PreviewProperties::PreviewId id, const Image &image)
|
||||
: id_(id), image_(image)
|
||||
{
|
||||
}
|
||||
|
||||
PreviewProperties Loader::getProperties() const
|
||||
{
|
||||
PreviewProperties prop;
|
||||
prop.id_ = id_;
|
||||
return prop;
|
||||
}
|
||||
|
||||
PreviewProperties::PreviewId Loader::getNumLoaders()
|
||||
{
|
||||
return (PreviewProperties::PreviewId)EXV_COUNTOF(loaderList_);
|
||||
}
|
||||
|
||||
LoaderExifJpeg::LoaderExifJpeg(PreviewProperties::PreviewId id, const Image &image, int parIdx)
|
||||
: Loader(id, image),
|
||||
offsetKey_(param_[parIdx].offsetKey_),
|
||||
lengthKey_(param_[parIdx].lengthKey_)
|
||||
{
|
||||
}
|
||||
|
||||
Loader::AutoPtr createLoaderExifJpeg(PreviewProperties::PreviewId id, const Image &image, int parIdx)
|
||||
{
|
||||
return Loader::AutoPtr(new LoaderExifJpeg(id, image, parIdx));
|
||||
}
|
||||
|
||||
long LoaderExifJpeg::getLength() const
|
||||
{
|
||||
long length = 0;
|
||||
ExifData::const_iterator pos = image_.exifData().findKey(lengthKey_);
|
||||
if (pos != image_.exifData().end()) {
|
||||
length = pos->toLong();
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
long LoaderExifJpeg::getOffset() const
|
||||
{
|
||||
long offset = 0;
|
||||
ExifData::const_iterator pos = image_.exifData().findKey(offsetKey_);
|
||||
if (pos != image_.exifData().end()) {
|
||||
offset = pos->toLong();
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
bool LoaderExifJpeg::valid() const
|
||||
{
|
||||
long offset = getOffset();
|
||||
long length = getLength();
|
||||
|
||||
if (offset == 0 || length == 0) return false;
|
||||
if (offset + length > image_.io().size()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
PreviewProperties LoaderExifJpeg::getProperties() const
|
||||
{
|
||||
PreviewProperties prop = Loader::getProperties();
|
||||
prop.mimeType_ = "image/jpeg";
|
||||
prop.extension_ = ".jpg";
|
||||
prop.length_ = getLength();
|
||||
return prop;
|
||||
}
|
||||
|
||||
DataBuf LoaderExifJpeg::getData() const
|
||||
{
|
||||
if (!valid()) return DataBuf();
|
||||
BasicIo &io = image_.io();
|
||||
|
||||
if (io.open() != 0) {
|
||||
throw Error(9, io.path(), strError());
|
||||
}
|
||||
IoCloser closer(io);
|
||||
|
||||
long offset = getOffset();
|
||||
long length = getLength();
|
||||
|
||||
const byte *base = io.mmap();
|
||||
|
||||
return DataBuf(base + offset, length);
|
||||
}
|
||||
|
||||
|
||||
LoaderExifThumbC::LoaderExifThumbC(PreviewProperties::PreviewId id, const Image &image)
|
||||
: Loader(id, image),
|
||||
thumb_(image_.exifData())
|
||||
{
|
||||
}
|
||||
|
||||
Loader::AutoPtr createLoaderExifThumbC(PreviewProperties::PreviewId id, const Image &image, int /* parIdx */)
|
||||
{
|
||||
return Loader::AutoPtr(new LoaderExifThumbC(id, image));
|
||||
}
|
||||
|
||||
bool LoaderExifThumbC::valid() const
|
||||
{
|
||||
return thumb_.copy().size_ > 0; // FIXME: this is inefficient
|
||||
}
|
||||
|
||||
PreviewProperties LoaderExifThumbC::getProperties() const
|
||||
{
|
||||
PreviewProperties prop = Loader::getProperties();
|
||||
prop.length_ = thumb_.copy().size_; // FIXME: this is inefficient
|
||||
prop.mimeType_ = thumb_.mimeType();
|
||||
prop.extension_ = thumb_.extension();
|
||||
return prop;
|
||||
}
|
||||
|
||||
DataBuf LoaderExifThumbC::getData() const
|
||||
{
|
||||
return thumb_.copy();
|
||||
}
|
||||
|
||||
bool cmpPreviewProperties(const PreviewProperties& lhs, const PreviewProperties& rhs)
|
||||
{
|
||||
return lhs.length_ < rhs.length_;
|
||||
}
|
||||
|
||||
PreviewImageLoader::PreviewImageLoader(const Image& image)
|
||||
: image_(image)
|
||||
{
|
||||
}
|
||||
|
||||
PreviewPropertiesList PreviewImageLoader::getPreviewPropertiesList() const
|
||||
{
|
||||
PreviewPropertiesList list;
|
||||
// go through the loader table and store all successfuly created loaders in the list
|
||||
for (PreviewProperties::PreviewId id = 0; id < Loader::getNumLoaders(); id++) {
|
||||
Loader::AutoPtr loader = Loader::create(id, image_);
|
||||
if (loader.get()) {
|
||||
list.push_back(loader->getProperties());
|
||||
}
|
||||
}
|
||||
std::sort(list.begin(), list.end(), cmpPreviewProperties);
|
||||
return list;
|
||||
}
|
||||
|
||||
PreviewImage PreviewImageLoader::getPreviewImage(const PreviewProperties &properties) const
|
||||
{
|
||||
Loader::AutoPtr loader = Loader::create(properties.id_, image_);
|
||||
DataBuf buf;
|
||||
if (loader.get()) {
|
||||
buf = loader->getData();
|
||||
}
|
||||
return PreviewImage(properties, buf);
|
||||
}
|
||||
|
||||
} // namespace Exiv2
|
||||
156
src/preview.hpp
Normal file
156
src/preview.hpp
Normal file
@ -0,0 +1,156 @@
|
||||
// ***************************************************************** -*- 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 preview.hpp
|
||||
@brief Classes to access preview images embedded in an image.
|
||||
@version $Rev$
|
||||
@author Vladimir Nadvornik (vn)
|
||||
<a href="mailto:nadvornik@suse.cz">nadvornik@suse.cz</a>
|
||||
@date 18-Sep-08, vn: created
|
||||
*/
|
||||
#ifndef PREVIEW_HPP_
|
||||
#define PREVIEW_HPP_
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "types.hpp"
|
||||
#include "image.hpp"
|
||||
#include "basicio.hpp"
|
||||
|
||||
// *****************************************************************************
|
||||
// namespace extensions
|
||||
namespace Exiv2 {
|
||||
|
||||
// *****************************************************************************
|
||||
// class definitions
|
||||
|
||||
/*!
|
||||
@brief Preview image properties.
|
||||
*/
|
||||
struct PreviewProperties
|
||||
{
|
||||
public:
|
||||
//! type of preview image.
|
||||
typedef int PreviewId;
|
||||
|
||||
//! Preview image mime type.
|
||||
const char* mimeType_;
|
||||
|
||||
//! Preview image extension.
|
||||
const char* extension_;
|
||||
|
||||
//! Preview image length in bytes.
|
||||
long length_;
|
||||
|
||||
//! identifies type of preview image.
|
||||
PreviewId id_;
|
||||
};
|
||||
|
||||
//! Container type to hold all preview images metadata.
|
||||
typedef std::vector<PreviewProperties> PreviewPropertiesList;
|
||||
|
||||
/*!
|
||||
@brief Compare two preview images by length. Return true if the
|
||||
lhs is smaller than rhs.
|
||||
*/
|
||||
bool cmpPreviewProperties(const PreviewProperties& lhs, const PreviewProperties& rhs);
|
||||
|
||||
/*!
|
||||
@brief Class that holds preview image properties and data buffer.
|
||||
*/
|
||||
class PreviewImage {
|
||||
public:
|
||||
//@{
|
||||
//! Constructor.
|
||||
PreviewImage(const PreviewProperties &properties, DataBuf &data);
|
||||
|
||||
//! Copy constructor
|
||||
PreviewImage(const PreviewImage &src);
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
//@{
|
||||
|
||||
/*!
|
||||
@brief Return a reference to image data.
|
||||
*/
|
||||
DataBuf &data();
|
||||
|
||||
/*!
|
||||
@brief Write the thumbnail image to a file.
|
||||
|
||||
A filename extension is appended to \em path according to the image
|
||||
type of the thumbnail, so \em path should not include an extension.
|
||||
The function will overwrite an existing file of the same name.
|
||||
|
||||
@param path File name of the thumbnail without extension.
|
||||
@return The number of bytes written.
|
||||
*/
|
||||
long writeFile(const std::string& path) const;
|
||||
/*!
|
||||
@brief Return the MIME type of the thumbnail, either \c "image/tiff"
|
||||
or \c "image/jpeg".
|
||||
*/
|
||||
const char* mimeType() const;
|
||||
/*!
|
||||
@brief Return the file extension for the format of the thumbnail
|
||||
(".tif" or ".jpg").
|
||||
*/
|
||||
const char* extension() const;
|
||||
|
||||
/*!
|
||||
@brief Return the thumbnail length in bytes.
|
||||
*/
|
||||
long length() const;
|
||||
//@}
|
||||
|
||||
private:
|
||||
PreviewProperties properties_;
|
||||
DataBuf data_;
|
||||
}; // class PreviewImage
|
||||
|
||||
/*!
|
||||
@brief Class for extracting preview images from image metadata.
|
||||
*/
|
||||
class PreviewImageLoader {
|
||||
public:
|
||||
//@{
|
||||
//! Constructor.
|
||||
PreviewImageLoader(const Image& image);
|
||||
|
||||
/*!
|
||||
@brief Return list of preview properties.
|
||||
*/
|
||||
PreviewPropertiesList getPreviewPropertiesList() const;
|
||||
/*!
|
||||
@brief Return image data for given properties.
|
||||
*/
|
||||
PreviewImage getPreviewImage(const PreviewProperties &properties) const;
|
||||
|
||||
//@}
|
||||
|
||||
private:
|
||||
const Image &image_;
|
||||
|
||||
}; // class PreviewImageLoader
|
||||
} // namespace Exiv2
|
||||
|
||||
#endif // #ifndef PREVIEW_HPP_
|
||||
Loading…
Reference in New Issue
Block a user