aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/exiv2wrapper.cpp49
-rw-r--r--src/exiv2wrapper.hpp9
-rw-r--r--src/exiv2wrapper_python.cpp5
-rw-r--r--src/pyexiv2/exif.py36
-rw-r--r--src/pyexiv2/metadata.py10
5 files changed, 108 insertions, 1 deletions
diff --git a/src/exiv2wrapper.cpp b/src/exiv2wrapper.cpp
index a5ae4aa..a9060d4 100644
--- a/src/exiv2wrapper.cpp
+++ b/src/exiv2wrapper.cpp
@@ -44,6 +44,8 @@ namespace exiv2wrapper
void Image::_instantiate_image()
{
+ _exifThumbnail = 0;
+
// If an exception is thrown, it has to be done outside of the
// Py_{BEGIN,END}_ALLOW_THREADS block.
Exiv2::Error error(0);
@@ -117,6 +119,10 @@ Image::~Image()
{
delete[] _data;
}
+ if (_exifThumbnail != 0)
+ {
+ delete _exifThumbnail;
+ }
}
void Image::readMetadata()
@@ -444,6 +450,49 @@ std::string Image::getDataBuffer() const
return buffer;
}
+Exiv2::ExifThumb* Image::_getExifThumbnail()
+{
+ CHECK_METADATA_READ
+ if (_exifThumbnail == 0)
+ {
+ _exifThumbnail = new Exiv2::ExifThumb(*_exifData);
+ }
+ return _exifThumbnail;
+}
+
+const std::string Image::getExifThumbnailMimeType()
+{
+ return std::string(_getExifThumbnail()->mimeType());
+}
+
+const std::string Image::getExifThumbnailExtension()
+{
+ return std::string(_getExifThumbnail()->extension());
+}
+
+void Image::writeExifThumbnailToFile(const std::string& path)
+{
+ _getExifThumbnail()->writeFile(path);
+}
+
+const std::string Image::getExifThumbnailData()
+{
+ Exiv2::DataBuf buffer = _getExifThumbnail()->copy();
+ // Copy the data buffer in a string. Since the data buffer can contain null
+ // characters ('\x00'), the string cannot be simply constructed like that:
+ // data = std::string((char*) buffer.pData_);
+ // because it would be truncated after the first occurence of a null
+ // character. Therefore, it has to be copied character by character.
+ // First allocate the memory for the whole string...
+ std::string data = std::string(buffer.size_, ' ');
+ // ... then fill it with the raw data.
+ for(unsigned int i = 0; i < buffer.size_; ++i)
+ {
+ data[i] = buffer.pData_[i];
+ }
+ return data;
+}
+
ExifTag::ExifTag(const std::string& key, Exiv2::Exifdatum* datum, Exiv2::ExifData* data): _key(key)
{
diff --git a/src/exiv2wrapper.hpp b/src/exiv2wrapper.hpp
index 5abf07d..c94cafb 100644
--- a/src/exiv2wrapper.hpp
+++ b/src/exiv2wrapper.hpp
@@ -230,6 +230,13 @@ public:
// Read access to the thumbnail embedded in the image.
boost::python::list previews();
+ // Manipulate the JPEG/TIFF thumbnail embedded in the EXIF data.
+ const std::string getExifThumbnailMimeType();
+ const std::string getExifThumbnailExtension();
+ void writeExifThumbnailToFile(const std::string& path);
+ const std::string getExifThumbnailData();
+ // TODO: other accessors (getters and setters)
+
// Copy the metadata to another image.
void copyMetadata(Image& other, bool exif=true, bool iptc=true, bool xmp=true) const;
@@ -249,6 +256,8 @@ private:
Exiv2::ExifData* _exifData;
Exiv2::IptcData* _iptcData;
Exiv2::XmpData* _xmpData;
+ Exiv2::ExifThumb* _exifThumbnail;
+ Exiv2::ExifThumb* _getExifThumbnail();
// true if the image's internal metadata has already been read,
// false otherwise
diff --git a/src/exiv2wrapper_python.cpp b/src/exiv2wrapper_python.cpp
index d6a1425..4ede5f4 100644
--- a/src/exiv2wrapper_python.cpp
+++ b/src/exiv2wrapper_python.cpp
@@ -144,6 +144,11 @@ BOOST_PYTHON_MODULE(libexiv2python)
.def("_copyMetadata", &Image::copyMetadata)
.def("_getDataBuffer", &Image::getDataBuffer)
+
+ .def("_getExifThumbnailMimeType", &Image::getExifThumbnailMimeType)
+ .def("_getExifThumbnailExtension", &Image::getExifThumbnailExtension)
+ .def("_writeExifThumbnailToFile", &Image::writeExifThumbnailToFile)
+ .def("_getExifThumbnailData", &Image::getExifThumbnailData)
;
}
diff --git a/src/pyexiv2/exif.py b/src/pyexiv2/exif.py
index b265d1f..5da21e6 100644
--- a/src/pyexiv2/exif.py
+++ b/src/pyexiv2/exif.py
@@ -414,3 +414,39 @@ class ExifTag(ListenerInterface):
right = self._raw_value
return '<%s = %s>' % (left, right)
+
+class ExifThumbnail(object):
+
+ """
+ DOCME
+ """
+
+ def __init__(self, _image):
+ self._image = _image
+
+ @property
+ def mime_type(self):
+ """The mime type of the preview image (e.g. ``image/jpeg``)."""
+ return self._image._getExifThumbnailMimeType()
+
+ @property
+ def extension(self):
+ """The file extension of the preview image with a leading dot
+ (e.g. ``.jpg``)."""
+ return self._image._getExifThumbnailExtension()
+
+ def write_to_file(self, path):
+ """
+ Write the thumbnail image to a file on disk.
+ The file extension will be automatically appended to the path.
+
+ :param path: path to write the thumbnail to (without an extension)
+ :type path: string
+ """
+ return self._image._writeExifThumbnailToFile(path)
+
+ @property
+ def data(self):
+ """The thumbnail image data buffer."""
+ return self._image._getExifThumbnailData()
+
diff --git a/src/pyexiv2/metadata.py b/src/pyexiv2/metadata.py
index 5ec296d..a5f8be4 100644
--- a/src/pyexiv2/metadata.py
+++ b/src/pyexiv2/metadata.py
@@ -36,7 +36,7 @@ from itertools import chain
import libexiv2python
-from pyexiv2.exif import ExifTag
+from pyexiv2.exif import ExifTag, ExifThumbnail
from pyexiv2.iptc import IptcTag
from pyexiv2.xmp import XmpTag
from pyexiv2.preview import Preview
@@ -64,6 +64,7 @@ class ImageMetadata(MutableMapping):
self._image = None
self._keys = {'exif': None, 'iptc': None, 'xmp': None}
self._tags = {'exif': {}, 'iptc': {}, 'xmp': {}}
+ self._exif_thumbnail = None
def _instantiate_image(self, filename):
# This method is meant to be overridden in unit tests to easily replace
@@ -392,3 +393,10 @@ class ImageMetadata(MutableMapping):
"""
return self._image._getDataBuffer()
+ @property
+ def exif_thumbnail(self):
+ """DOCME."""
+ if self._exif_thumbnail is None:
+ self._exif_thumbnail = ExifThumbnail(self._image)
+ return self._exif_thumbnail
+