#689: Provide support for JPEG previews stored in the XMP metadata

v0.27.3
vog 14 years ago
parent 49f4536c36
commit 9e36ca5dbf

@ -36,6 +36,7 @@ EXIV2_RCSID("@(#) $Id$")
# include "exv_conf.h"
#endif
#include <climits>
#include <string>
#include "preview.hpp"
@ -66,6 +67,11 @@ namespace {
return l < r;
}
/*!
@brief Decode a Base64 string.
*/
std::string decodeBase64(const std::string &src);
/*!
Base class for image loaders. Provides virtual methods for reading properties
and DataBuf.
@ -236,6 +242,29 @@ namespace {
//! Function to create new LoaderTiff
Loader::AutoPtr createLoaderTiff(PreviewId id, const Image &image, int parIdx);
//! Loader for JPEG previews stored in the XMP metadata
class LoaderXmpJpeg : public Loader {
public:
//! Constructor
LoaderXmpJpeg(PreviewId id, const Image &image, int parIdx);
//! Get properties of a preview image with given params
virtual PreviewProperties getProperties() const;
//! Get a buffer that contains the preview image
virtual DataBuf getData() const;
//! Read preview image dimensions
virtual bool readDimensions();
protected:
//! Preview image data
std::string preview_;
};
//! Function to create new LoaderXmpJpeg
Loader::AutoPtr createLoaderXmpJpeg(PreviewId id, const Image &image, int parIdx);
// *****************************************************************************
// class member definitions
@ -265,7 +294,8 @@ namespace {
{ 0, createLoaderExifJpeg, 5 },
{ 0, createLoaderExifJpeg, 6 },
{ "image/x-canon-cr2", createLoaderExifJpeg, 7 },
{ 0, createLoaderExifJpeg, 8 }
{ 0, createLoaderExifJpeg, 8 },
{ 0, createLoaderXmpJpeg, 0 }
};
const LoaderExifJpeg::Param LoaderExifJpeg::param_[] = {
@ -663,6 +693,96 @@ namespace {
return DataBuf(mio.mmap(), mio.size());
}
LoaderXmpJpeg::LoaderXmpJpeg(PreviewId id, const Image &image, int parIdx)
: Loader(id, image)
{
(void)parIdx;
const Exiv2::XmpData &xmpData = image_.xmpData();
XmpData::const_iterator imageDatum = xmpData.findKey(XmpKey("Xmp.xmp.Thumbnails[1]/xmpGImg:image"));
if (imageDatum == xmpData.end()) return;
XmpData::const_iterator formatDatum = xmpData.findKey(XmpKey("Xmp.xmp.Thumbnails[1]/xmpGImg:format"));
if (formatDatum == xmpData.end()) return;
XmpData::const_iterator widthDatum = xmpData.findKey(XmpKey("Xmp.xmp.Thumbnails[1]/xmpGImg:width"));
if (widthDatum == xmpData.end()) return;
XmpData::const_iterator heightDatum = xmpData.findKey(XmpKey("Xmp.xmp.Thumbnails[1]/xmpGImg:height"));
if (heightDatum == xmpData.end()) return;
if (formatDatum->toString() != "JPEG") return;
width_ = widthDatum->toLong();
height_ = heightDatum->toLong();
preview_ = decodeBase64(imageDatum->toString());
size_ = preview_.size();
valid_ = true;
}
Loader::AutoPtr createLoaderXmpJpeg(PreviewId id, const Image &image, int parIdx)
{
return Loader::AutoPtr(new LoaderXmpJpeg(id, image, parIdx));
}
PreviewProperties LoaderXmpJpeg::getProperties() const
{
PreviewProperties prop = Loader::getProperties();
prop.mimeType_ = "image/jpeg";
prop.extension_ = ".jpg";
#ifdef EXV_UNICODE_PATH
prop.wextension_ = EXV_WIDEN(".jpg");
#endif
return prop;
}
DataBuf LoaderXmpJpeg::getData() const
{
if (!valid()) return DataBuf();
return DataBuf(reinterpret_cast<const Exiv2::byte*>(preview_.data()), preview_.size());
}
bool LoaderXmpJpeg::readDimensions()
{
return valid();
}
static const char encodeBase64Table[64 + 1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string decodeBase64(const std::string& src)
{
const unsigned int srcSize = src.size();
// create decoding table
unsigned int invalid = 64;
unsigned int decodeBase64Table[256];
for (unsigned int i = 0; i < 256; i++) decodeBase64Table[i] = invalid;
for (unsigned int i = 0; i < 64; i++) decodeBase64Table[(unsigned char)encodeBase64Table[i]] = i;
// calculate dest size
unsigned int validSrcSize = 0;
for (unsigned int srcPos = 0; srcPos < srcSize; srcPos++) {
if (decodeBase64Table[(unsigned char)src[srcPos]] != invalid) validSrcSize++;
}
if (validSrcSize > UINT_MAX / 3) return std::string(); // avoid integer overflow
const unsigned int destSize = (validSrcSize * 3) / 4;
// allocate dest buffer
std::string dest(destSize, 0);
// decode
for (unsigned int srcPos = 0, destPos = 0; destPos < destSize;) {
unsigned int buffer = 0;
for (int bufferPos = 3; bufferPos >= 0 && srcPos < srcSize; srcPos++) {
unsigned int srcValue = decodeBase64Table[(unsigned char)src[srcPos]];
if (srcValue == invalid) continue;
buffer |= srcValue << (bufferPos * 6);
bufferPos--;
}
for (int bufferPos = 2; bufferPos >= 0 && destPos < destSize; bufferPos--, destPos++) {
dest[destPos] = buffer >> (bufferPos * 8);
}
}
return dest;
}
} // namespace
// *****************************************************************************

@ -529,6 +529,7 @@ Xmp.xmpMM.History[8]/stEvt:changed XmpText 1 /
Exit code: 253
Command: exiv2 -pp eps-flat_oodraw_ai-10-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -eX eps-flat_oodraw_ai-10-lev2.eps
@ -735,6 +736,7 @@ Xmp.xmpMM.History[10]/stEvt:changed XmpText 1 /
Exit code: 253
Command: exiv2 -pp eps-flat_oodraw_ai-8-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -eX eps-flat_oodraw_ai-8-lev2.eps
@ -915,6 +917,7 @@ Xmp.xmpMM.History[9]/stEvt:changed XmpText 1 /
Exit code: 253
Command: exiv2 -pp eps-flat_oodraw_ai-9-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -eX eps-flat_oodraw_ai-9-lev2.eps
@ -1063,6 +1066,7 @@ Xmp.xmpMM.History[7]/stEvt:changed XmpText 1 /
Exit code: 253
Command: exiv2 -pp eps-flat_oodraw_ai-cs-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -eX eps-flat_oodraw_ai-cs-lev2.eps
@ -1205,6 +1209,7 @@ Xmp.xmpMM.History[6]/stEvt:changed XmpText 1 /
Exit code: 253
Command: exiv2 -pp eps-flat_oodraw_ai-cs2-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -eX eps-flat_oodraw_ai-cs2-lev2.eps
@ -1341,6 +1346,7 @@ Xmp.xmpMM.History[5]/stEvt:changed XmpText 1 /
Exit code: 253
Command: exiv2 -pp eps-flat_oodraw_ai-cs3-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -eX eps-flat_oodraw_ai-cs3-lev2.eps
@ -1471,6 +1477,7 @@ Xmp.xmpMM.History[4]/stEvt:changed XmpText 1 /
Exit code: 253
Command: exiv2 -pp eps-flat_oodraw_ai-cs4-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -eX eps-flat_oodraw_ai-cs4-lev2.eps
@ -1567,6 +1574,7 @@ Xmp.dc.format XmpText 22 application/postscri
Exit code: 253
Command: exiv2 -pp eps-flat_oodraw_ai-cs5-lev2.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -eX eps-flat_oodraw_ai-cs5-lev2.eps
@ -1685,6 +1693,7 @@ Xmp.xmpMM.History[2]/stEvt:changed XmpText 1 /
Exit code: 253
Command: exiv2 -pp eps-flat_oodraw_ai-cs5-lev3-nodocthumb.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -eX eps-flat_oodraw_ai-cs5-lev3-nodocthumb.eps
@ -1801,6 +1810,7 @@ Xmp.xmpMM.History[1]/stEvt:changed XmpText 1 /
Exit code: 253
Command: exiv2 -pp eps-flat_oodraw_ai-cs5-lev3.eps
Preview 1: image/jpeg, 256x208 pixels, 3166 bytes
Exit code: 0
Command: exiv2 -f -eX eps-flat_oodraw_ai-cs5-lev3.eps

Loading…
Cancel
Save