Added preview support (Vladimir Nadvornik)

This commit is contained in:
Andreas Huggel 2008-09-18 10:26:58 +00:00
parent 6b93409e26
commit 26b488a255
5 changed files with 563 additions and 1 deletions

View File

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

View File

@ -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
View 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
View 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_