diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/SConscript | 4 | ||||
-rw-r--r-- | src/exiv2wrapper.cpp | 483 | ||||
-rw-r--r-- | src/exiv2wrapper.hpp | 161 | ||||
-rw-r--r-- | src/exiv2wrapper_python.cpp | 70 | ||||
-rw-r--r-- | src/libpyexiv2.cpp | 499 | ||||
-rw-r--r-- | src/libpyexiv2.hpp | 166 | ||||
-rw-r--r-- | src/libpyexiv2_wrapper.cpp | 70 |
7 files changed, 716 insertions, 737 deletions
diff --git a/src/SConscript b/src/SConscript index c2280fa..60e13b6 100644 --- a/src/SConscript +++ b/src/SConscript @@ -15,8 +15,8 @@ libs = ['boost_python', 'exiv2'] env.Append(LIBS=libs) # Build shared library libpyexiv2 -cpp_sources = ['libpyexiv2.cpp', 'libpyexiv2_wrapper.cpp'] -libpyexiv2 = env.SharedLibrary('libpyexiv2', cpp_sources) +cpp_sources = ['exiv2wrapper.cpp', 'exiv2wrapper_python.cpp'] +libpyexiv2 = env.SharedLibrary('exiv2python', cpp_sources) # Install the shared library and the Python module, invoked using # 'scons install'. If DESTDIR is specified on the command line when invoking diff --git a/src/exiv2wrapper.cpp b/src/exiv2wrapper.cpp new file mode 100644 index 0000000..5b24472 --- /dev/null +++ b/src/exiv2wrapper.cpp @@ -0,0 +1,483 @@ +// ***************************************************************************** +/* + * Copyright (C) 2006-2008 Olivier Tilloy <olivier@tilloy.net> + * + * This file is part of the pyexiv2 distribution. + * + * pyexiv2 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. + * + * pyexiv2 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 pyexiv2; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/* + File: exiv2wrapper.cpp + Author(s): Olivier Tilloy <olivier@tilloy.net> + */ +// ***************************************************************************** + +#include "exiv2wrapper.hpp" + +// Custom error codes for Exiv2 exceptions +#define METADATA_NOT_READ 101 +#define NON_REPEATABLE 102 +#define KEY_NOT_FOUND 103 +#define THUMB_ACCESS 104 +#define NO_THUMBNAIL 105 + +namespace exiv2wrapper +{ + +// Base constructor +Image::Image(const std::string& filename) +{ + _filename = filename; + _image = Exiv2::ImageFactory::open(filename); + assert(_image.get() != 0); + _dataRead = false; +} + +// Copy constructor +Image::Image(const Image& image) +{ + _filename = image._filename; + _image = Exiv2::ImageFactory::open(_filename); + assert(_image.get() != 0); + _dataRead = false; +} + +void Image::readMetadata() +{ + _image->readMetadata(); + _exifData = _image->exifData(); + //_iptcData = _image->iptcData(); + _dataRead = true; +} + +/*void Image::writeMetadata() +{ + if(_dataRead) + { + _image->setExifData(_exifData); + _image->setIptcData(_iptcData); + _image->writeMetadata(); + } + else + throw Exiv2::Error(METADATA_NOT_READ); +}*/ + +boost::python::list Image::exifKeys() +{ + boost::python::list keys; + if(_dataRead) + { + for(Exiv2::ExifMetadata::iterator i = _exifData.begin(); + i != _exifData.end(); + ++i) + { + keys.append(i->key()); + } + return keys; + } + else + { + throw Exiv2::Error(METADATA_NOT_READ); + } +} + +boost::python::tuple Image::getExifTag(std::string key) +{ + if(_dataRead) + { + Exiv2::ExifKey exifKey = Exiv2::ExifKey(key); + if(_exifData.findKey(exifKey) != _exifData.end()) + { + Exiv2::Exifdatum exifDatum = _exifData[key]; + std::string sTagName = exifDatum.tagName(); + std::string sTagLabel = exifDatum.tagLabel(); + std::string sTagDesc(Exiv2::ExifTags::tagDesc(exifKey.tag(), exifKey.ifdId())); + std::string sTagType = exifDatum.typeName(); + std::string sTagValue = exifDatum.toString(); + std::ostringstream sTagStringValueBuffer; + sTagStringValueBuffer << exifDatum; + std::string sTagStringValue = sTagStringValueBuffer.str(); + return boost::python::make_tuple(sTagName, sTagLabel, sTagDesc, sTagType, sTagValue, sTagStringValue); + } + else + { + throw Exiv2::Error(KEY_NOT_FOUND, key); + } + } + else + { + throw Exiv2::Error(METADATA_NOT_READ); + } +} + +/*std::string Image::getExifTagToString(std::string key) +{ + if(_dataRead) + { + Exiv2::ExifKey exifKey = Exiv2::ExifKey(key); + Exiv2::ExifMetadata::iterator i = _exifData.findKey(exifKey); + if(i != _exifData.end()) + { + Exiv2::Exifdatum exifDatum = _exifData[key]; + std::ostringstream buffer; + buffer << exifDatum; + return buffer.str(); + } + else + throw Exiv2::Error(KEY_NOT_FOUND, key); + } + else + throw Exiv2::Error(METADATA_NOT_READ); +} + +boost::python::tuple Image::setExifTag(std::string key, std::string value) +{ + boost::python::tuple returnValue; + if(_dataRead) + { + Exiv2::ExifKey exifKey = Exiv2::ExifKey(key); + Exiv2::ExifMetadata::iterator i = _exifData.findKey(exifKey); + if(i != _exifData.end()) + { + Exiv2::Exifdatum exifDatum = _exifData[key]; + returnValue = boost::python::make_tuple(std::string(exifDatum.typeName()), exifDatum.toString()); + // First erase the existing tag: in some case (and + // I don't know why), the new value won't replace + // the old one if not previously erased... + _exifData.erase(i); + } + else + { + // The key was not found + returnValue = boost::python::make_tuple(std::string(""), std::string("")); + } + _exifData[key] = value; + return returnValue; + } + else + throw Exiv2::Error(METADATA_NOT_READ); +} + +boost::python::tuple Image::deleteExifTag(std::string key) +{ + boost::python::tuple returnValue; + if(_dataRead) + { + Exiv2::ExifKey exifKey = Exiv2::ExifKey(key); + Exiv2::ExifMetadata::iterator i = _exifData.findKey(exifKey); + if(i != _exifData.end()) + { + Exiv2::Exifdatum exifDatum = _exifData[key]; + returnValue = boost::python::make_tuple(std::string(exifDatum.typeName()), exifDatum.toString()); + _exifData.erase(i); + return returnValue; + } + else + throw Exiv2::Error(KEY_NOT_FOUND, key); + } + else + throw Exiv2::Error(METADATA_NOT_READ); +} + +boost::python::list Image::iptcKeys() +{ + boost::python::list list; + if(_dataRead) + { + for(Exiv2::IptcMetadata::iterator i = _iptcData.begin() ; i != _iptcData.end() ; i++) + { + // The key is appended to the list if and only if it is not + // already present. + if (list.count(i->key()) == 0) + list.append(i->key()); + } + return list; + } + else + throw Exiv2::Error(METADATA_NOT_READ); +} + +boost::python::list Image::getIptcTag(std::string key) +{ + if(_dataRead) + { + boost::python::list valuesList; + unsigned int valueOccurences = 0; + Exiv2::IptcKey iptcKey = Exiv2::IptcKey(key); + for (Exiv2::IptcMetadata::iterator dataIterator = _iptcData.begin(); + dataIterator != _iptcData.end(); ++dataIterator) + { + if (dataIterator->key() == key) + { + valuesList.append(boost::python::make_tuple(std::string(dataIterator->typeName()), dataIterator->toString())); + ++valueOccurences; + } + } + if (valueOccurences > 0) + return valuesList; + else + throw Exiv2::Error(KEY_NOT_FOUND, key); + } + else + throw Exiv2::Error(METADATA_NOT_READ); +} + +boost::python::tuple Image::setIptcTag(std::string key, std::string value, unsigned int index=0) +{ + if(_dataRead) + { + boost::python::tuple returnValue; + unsigned int indexCounter = index; + Exiv2::IptcKey iptcKey = Exiv2::IptcKey(key); + Exiv2::IptcMetadata::iterator dataIterator = _iptcData.findKey(iptcKey); + while ((indexCounter > 0) && (dataIterator != _iptcData.end())) + { + dataIterator = std::find_if(++dataIterator, _iptcData.end(), + Exiv2::FindMetadatumById::FindMetadatumById(iptcKey.tag(), iptcKey.record())); + --indexCounter; + } + if (dataIterator != _iptcData.end()) + { + // The tag at given index already exists, override it + returnValue = boost::python::make_tuple(std::string(dataIterator->typeName()), dataIterator->toString()); + dataIterator->setValue(value); + } + else + { + // Either index is greater than the index of the last repetition + // of the tag, or the tag does not exist yet. + // In both cases, it is created. + returnValue = boost::python::make_tuple(std::string(""), std::string("")); + Exiv2::Iptcdatum iptcDatum(iptcKey); + iptcDatum.setValue(value); + int state = _iptcData.add(iptcDatum); + if (state == 6) + throw Exiv2::Error(NON_REPEATABLE); + } + return returnValue; + } + else + throw Exiv2::Error(METADATA_NOT_READ); +} + +boost::python::tuple Image::deleteIptcTag(std::string key, unsigned int index=0) +{ + if(_dataRead) + { + boost::python::tuple returnValue; + unsigned int indexCounter = index; + Exiv2::IptcKey iptcKey = Exiv2::IptcKey(key); + Exiv2::IptcMetadata::iterator dataIterator = _iptcData.findKey(iptcKey); + while ((indexCounter > 0) && (dataIterator != _iptcData.end())) + { + dataIterator = std::find_if(++dataIterator, _iptcData.end(), + Exiv2::FindMetadatumById::FindMetadatumById(iptcKey.tag(), iptcKey.record())); + --indexCounter; + } + if (dataIterator != _iptcData.end()) + { + // The tag at given index already exists, delete it + returnValue = boost::python::make_tuple(std::string(dataIterator->typeName()), dataIterator->toString()); + _iptcData.erase(dataIterator); + return returnValue; + } + else + throw Exiv2::Error(KEY_NOT_FOUND, key); + } + else + throw Exiv2::Error(METADATA_NOT_READ); +} + +boost::python::tuple Image::tagDetails(std::string key) +{ + std::string keyFamily = key.substr(0, 4); + if (keyFamily == "Exif") + { + Exiv2::ExifKey exifKey = Exiv2::ExifKey(key); + std::string tagLabel = exifKey.tagLabel(); + std::string tagDesc = std::string(Exiv2::ExifTags::tagDesc(exifKey.tag(), exifKey.ifdId())); + return boost::python::make_tuple(tagLabel, tagDesc); + } + else if (keyFamily == "Iptc") + { + Exiv2::IptcKey iptcKey = Exiv2::IptcKey(key); + std::string tagLabel = iptcKey.tagLabel(); + std::string tagDesc = std::string(Exiv2::IptcDataSets::dataSetDesc(iptcKey.tag(), iptcKey.record())); + return boost::python::make_tuple(tagLabel, tagDesc); + } +} + +boost::python::tuple Image::getThumbnailData() +{ + if(_dataRead) + { + Exiv2::Thumbnail::AutoPtr thumbnail = _exifData.getThumbnail(); + if (thumbnail.get() != 0) + { + std::string format(_exifData.thumbnailFormat()); + // Copy the data buffer in a string. Since the data buffer can + // contain null char ('\x00'), the string cannot be simply + // constructed like that: + // std::string data((char*) dataBuffer.pData_); + // because it would be truncated after the first occurence of a + // null char. Therefore, it has to be copied char by char. + Exiv2::DataBuf dataBuffer = _exifData.copyThumbnail(); + char* charData = (char*) dataBuffer.pData_; + long dataLen = dataBuffer.size_; + // First allocate the memory for the whole string... + std::string data(dataLen, ' '); + // ... then fill it with the raw jpeg data. + for(long i = 0; i < dataLen; ++i) + { + data[i] = charData[i]; + } + return boost::python::make_tuple(format, data); + } + else + throw Exiv2::Error(THUMB_ACCESS); + } + else + throw Exiv2::Error(METADATA_NOT_READ); +} + +void Image::setThumbnailData(std::string data) +{ + if(_dataRead) + { + const Exiv2::byte* dataBuf = (const Exiv2::byte*) data.c_str(); + _exifData.setJpegThumbnail(dataBuf, data.size()); + } + else + throw Exiv2::Error(METADATA_NOT_READ); +} + +void Image::deleteThumbnail() +{ + if(_dataRead) + _exifData.eraseThumbnail(); + else + throw Exiv2::Error(METADATA_NOT_READ); +} + +void Image::dumpThumbnailToFile(const std::string path) +{ + if(_dataRead) + { + int result = _exifData.writeThumbnail(path); + if (result == 8) + throw Exiv2::Error(NO_THUMBNAIL); + } + else + throw Exiv2::Error(METADATA_NOT_READ); +} + +void Image::setThumbnailFromJpegFile(const std::string path) +{ + if(_dataRead) + { + _exifData.setJpegThumbnail(path); + } + else + throw Exiv2::Error(METADATA_NOT_READ); +}*/ + +void translateExiv2Error(Exiv2::Error const& error) +{ + // Use the Python 'C' API to set up an exception object + + // Building a C++ string first allows this code to compile with all + // versions of libexiv2 (< 0.13 and >= 0.13), because the way exceptions + // are handled in libexiv2 was changed in 0.13. + const std::string sMessage(error.what()); + const char* message = sMessage.c_str(); + + // The type of the Python exception depends on the error code + // Warning: this piece of code should be updated in case the error codes + // defined by Exiv2 (file 'src/error.cpp') are changed + switch (error.code()) + { + case -2: + case -1: + case 1: + case 2: + PyErr_SetString(PyExc_RuntimeError, message); + break; + case 3: + case 9: + case 10: + case 11: + case 12: + case 13: + case 14: + case 15: + case 17: + case 18: + case 20: + case 21: + case 23: + case 31: + case 32: + case 33: + case 36: + case 37: + PyErr_SetString(PyExc_IOError, message); + break; + case 4: + case 5: + case 6: + case 7: + PyErr_SetString(PyExc_IndexError, message); + break; + case 8: + case 22: + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 34: + PyErr_SetString(PyExc_ValueError, message); + break; + case 16: + case 19: + case 35: + PyErr_SetString(PyExc_MemoryError, message); + break; + + // custom error codes + case METADATA_NOT_READ: + PyErr_SetString(PyExc_IOError, "Image metadata has not been read yet"); + break; + case NON_REPEATABLE: + PyErr_SetString(PyExc_KeyError, "Tag is not repeatable"); + break; + case KEY_NOT_FOUND: + PyErr_SetString(PyExc_KeyError, "Tag not set"); + break; + case THUMB_ACCESS: + PyErr_SetString(PyExc_IOError, "Cannot access image thumbnail"); + break; + case NO_THUMBNAIL: + PyErr_SetString(PyExc_IOError, "The EXIF data does not contain a thumbnail"); + break; + + default: + PyErr_SetString(PyExc_RuntimeError, message); + } +} + +} // End of namespace exiv2wrapper diff --git a/src/exiv2wrapper.hpp b/src/exiv2wrapper.hpp new file mode 100644 index 0000000..340fd1b --- /dev/null +++ b/src/exiv2wrapper.hpp @@ -0,0 +1,161 @@ +// ***************************************************************************** +/* + * Copyright (C) 2006-2008 Olivier Tilloy <olivier@tilloy.net> + * + * This file is part of the pyexiv2 distribution. + * + * pyexiv2 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. + * + * pyexiv2 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 pyexiv2; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/* + File: exiv2wrapper.hpp + Author(s): Olivier Tilloy <olivier@tilloy.net> + */ +// ***************************************************************************** + +#ifndef __exiv2wrapper__ +#define __exiv2wrapper__ + +#include <string> + +#include "exiv2/image.hpp" +#include "exiv2/exif.hpp" +//#include "exiv2/iptc.hpp" + +#include "boost/python.hpp" + +namespace exiv2wrapper +{ + +class Image +{ +public: + // Constructors + Image(const std::string& filename); + Image(const Image& image); + + void readMetadata(); + //void writeMetadata(); + + // Read and write access to the EXIF tags. + // For a complete list of the available EXIF tags, see + // libexiv2's documentation (http://exiv2.org/tags.html). + + // Return a list of all the keys of available EXIF tags set in the + // image. + boost::python::list exifKeys(); + + // Return a tuple containing the type (as a string) and the value + // (as a string as well) of the required EXIF tag. + // Throw an exception if the tag is not set. + // tagname + // taglabel + // tagdesc + // type + // tagvalue + // tagvalue (human-readable) + boost::python::tuple getExifTag(std::string key); + + // Return a human-readable string containing the value of the + // required EXIF tag. + // Throw an exception if the tag is not set. + //std::string getExifTagToString(std::string key); + + // Set the EXIF tag's value and return a tuple containing the + // type and previous value of the tag (empty strings if not previously + // set). If the tag was not previously set, it is created. + //boost::python::tuple setExifTag(std::string key, std::string value); + + // Delete the required EXIF tag and return a tuple containing the + // type and previous value. + // Throw an exception if the tag was not set. + //boost::python::tuple deleteExifTag(std::string key); + + // Read and write access to the IPTC tags. + // For a complete list of the available IPTC tags, see + // libexiv2's documentation (http://exiv2.org/iptc.html). + + // Returns a list of all the keys of available IPTC tags set in the + // image. This list has no duplicates: each of its items is unique, + // even if a tag is present more than once. + //boost::python::list iptcKeys(); + + // Return a list of tuples, each containing the type (as a string) and + // the value (as a string as well) of the required IPTC tag. + // Throw an exception if the tag is not set. + //boost::python::list getIptcTag(std::string key); + + // Set the IPTC tag's value and return a tuple containing the + // type and previous value of the tag (empty strings if not previously + // set). If the tag was not previously set, it is created. + // If the key references a repeatable tag, the parameter index (starting + // from 0 like a list index) is used to determine which of the + // repetitions is to be set. In case of an index greater than the + // highest existing one, adds a repetition of the tag. + //boost::python::tuple setIptcTag(std::string key, std::string value, unsigned int index); + + // Delete the required IPTC tag and return a tuple containing the + // type and previous value. + // If the key references a repeatable tag, the parameter index (starting + // from 0 like a list index) is used to determine which of the + // repetitions is to be deleted. + // Throw an exception if the tag was not set or if the index is greater + // than the highest existing one. + //boost::python::tuple deleteIptcTag(std::string key, unsigned int index); + + // Return a tuple containing the name of the tag and its description. + //boost::python::tuple tagDetails(std::string key); + + // Read and write access to the thumbnail embedded in the image. + + // Return a tuple containing the format of the thumbnail ("TIFF" or + // "JPEG") and the thumbnail raw data as a string buffer. + // Throw an exception if the thumbnail data cannot be accessed. + //boost::python::tuple getThumbnailData(); + + // Set the thumbnail of the image. The parameter is the thumbnail raw + // jpeg data as a string buffer. + //void setThumbnailData(std::string data); + + // Delete the thumbnail embedded in the image. + //void deleteThumbnail(); + + // Write the thumbnail to an image file. + // A filename extension is appended to the given path according to the + // image type of the thumbnail, so it should not include an extension. + // Throw an exception if the image does not contain a thumbnail. + //void dumpThumbnailToFile(const std::string path); + + // Set the image contained in the jpeg file passed as a parameter as + // the thumbnail of the image. + //void setThumbnailFromJpegFile(const std::string path); + +private: + std::string _filename; + Exiv2::Image::AutoPtr _image; + Exiv2::ExifData _exifData; + //Exiv2::IptcData _iptcData; + + // true if the image's internal metadata has already been read, + // false otherwise + bool _dataRead; +}; + +// Translate an Exiv2 generic exception into a Python exception +void translateExiv2Error(Exiv2::Error const& error); + +} // End of namespace exiv2wrapper + +#endif + diff --git a/src/exiv2wrapper_python.cpp b/src/exiv2wrapper_python.cpp new file mode 100644 index 0000000..fabaf6b --- /dev/null +++ b/src/exiv2wrapper_python.cpp @@ -0,0 +1,70 @@ +// ***************************************************************************** +/* + * Copyright (C) 2006-2008 Olivier Tilloy <olivier@tilloy.net> + * + * This file is part of the pyexiv2 distribution. + * + * pyexiv2 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. + * + * pyexiv2 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 pyexiv2; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/* + File: exiv2wrapper_python.cpp + Author(s): Olivier Tilloy <olivier@tilloy.net> + */ +// ***************************************************************************** + +#include "exiv2wrapper.hpp" + +#include <boost/python.hpp> + +using namespace boost::python; + +using namespace exiv2wrapper; + +BOOST_PYTHON_MODULE(libexiv2python) +{ + register_exception_translator<Exiv2::Error>(&translateExiv2Error); + + // Exported method names prefixed by "_Image__" are going to be "private" + // and are not meant to be used directly + class_<Image>("Image", init<std::string>()) + + .def("readMetadata", &Image::readMetadata) +// .def("writeMetadata", &Image::writeMetadata) + + .def("exifKeys", &Image::exifKeys) + .def("_Image__getExifTag", &Image::getExifTag) +// .def("_Image__getExifTagToString", &Image::getExifTagToString) +// .def("_Image__setExifTag", &Image::setExifTag) +// .def("_Image__deleteExifTag", &Image::deleteExifTag) + +// .def("iptcKeys", &Image::iptcKeys) +// .def("_Image__getIptcTag", &Image::getIptcTag) +// .def("_Image__setIptcTag", &Image::setIptcTag) +// .def("_Image__deleteIptcTag", &Image::deleteIptcTag) + +// .def("tagDetails", &Image::tagDetails) + +// .def("getThumbnailData", &Image::getThumbnailData) +// .def("setThumbnailData", &Image::setThumbnailData) +// .def("deleteThumbnail", &Image::deleteThumbnail) +// .def("dumpThumbnailToFile", &Image::dumpThumbnailToFile) +// .def("setThumbnailFromJpegFile", &Image::setThumbnailFromJpegFile) + +// .def("getComment", &Image::getComment) +// .def("setComment", &Image::setComment) +// .def("clearComment", &Image::clearComment) + ; +} + diff --git a/src/libpyexiv2.cpp b/src/libpyexiv2.cpp deleted file mode 100644 index 97f6c2f..0000000 --- a/src/libpyexiv2.cpp +++ /dev/null @@ -1,499 +0,0 @@ -// ***************************************************************************** -/* - * Copyright (C) 2006-2008 Olivier Tilloy <olivier@tilloy.net> - * - * This file is part of the pyexiv2 distribution. - * - * pyexiv2 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. - * - * pyexiv2 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 pyexiv2; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. - */ -/* - File: libpyexiv2.cpp - Author(s): Olivier Tilloy <olivier@tilloy.net> - */ -// ***************************************************************************** - -#include "libpyexiv2.hpp" - -// Custom error codes for Exiv2 exceptions -#define METADATA_NOT_READ 101 -#define NON_REPEATABLE 102 -#define KEY_NOT_FOUND 103 -#define THUMB_ACCESS 104 -#define NO_THUMBNAIL 105 - -namespace LibPyExiv2 -{ - - // Base constructor - Image::Image(std::string filename) - { - _filename = filename; - _image = Exiv2::ImageFactory::open(filename); - assert(_image.get() != 0); - _dataRead = false; - } - - // Copy constructor - Image::Image(const Image & image) - { - _filename = image._filename; - _image = Exiv2::ImageFactory::open(_filename); - assert(_image.get() != 0); - _dataRead = false; - } - - void Image::readMetadata() - { - _image->readMetadata(); - _exifData = _image->exifData(); - _iptcData = _image->iptcData(); - _dataRead = true; - } - - void Image::writeMetadata() - { - if(_dataRead) - { - _image->setExifData(_exifData); - _image->setIptcData(_iptcData); - _image->writeMetadata(); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - boost::python::list Image::exifKeys() - { - boost::python::list list; - if(_dataRead) - { - for(Exiv2::ExifMetadata::iterator i = _exifData.begin() ; i != _exifData.end() ; ++i) - { - list.append(i->key()); - } - return list; - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - boost::python::tuple Image::getExifTag(std::string key) - { - if(_dataRead) - { - Exiv2::ExifKey exifKey = Exiv2::ExifKey(key); - Exiv2::ExifMetadata::iterator i = _exifData.findKey(exifKey); - if(i != _exifData.end()) - { - Exiv2::Exifdatum exifDatum = _exifData[key]; - return boost::python::make_tuple(std::string(exifDatum.typeName()), exifDatum.toString()); - } - else - throw Exiv2::Error(KEY_NOT_FOUND, key); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - std::string Image::getExifTagToString(std::string key) - { - if(_dataRead) - { - Exiv2::ExifKey exifKey = Exiv2::ExifKey(key); - Exiv2::ExifMetadata::iterator i = _exifData.findKey(exifKey); - if(i != _exifData.end()) - { - Exiv2::Exifdatum exifDatum = _exifData[key]; - std::ostringstream buffer; - buffer << exifDatum; - return buffer.str(); - } - else - throw Exiv2::Error(KEY_NOT_FOUND, key); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - boost::python::tuple Image::setExifTag(std::string key, std::string value) - { - if(_dataRead) - { - std::string typeName; - std::string oldValue(""); - Exiv2::ExifKey exifKey = Exiv2::ExifKey(key); - Exiv2::ExifMetadata::iterator i = _exifData.findKey(exifKey); - if(i != _exifData.end()) - { - Exiv2::Exifdatum exifDatum = _exifData[key]; - oldValue = exifDatum.toString(); - // First erase the existing tag: in some case (and - // I don't know why), the new value won't replace - // the old one if not previously erased... - _exifData.erase(i); - } - _exifData[key] = value; - typeName = std::string(_exifData[key].typeName()); - return boost::python::make_tuple(typeName, oldValue); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - boost::python::tuple Image::deleteExifTag(std::string key) - { - if(_dataRead) - { - Exiv2::ExifKey exifKey = Exiv2::ExifKey(key); - Exiv2::ExifMetadata::iterator i = _exifData.findKey(exifKey); - if(i != _exifData.end()) - { - Exiv2::Exifdatum exifDatum = _exifData[key]; - boost::python::tuple returnValue = - boost::python::make_tuple(std::string(exifDatum.typeName()), exifDatum.toString()); - _exifData.erase(i); - return returnValue; - } - else - throw Exiv2::Error(KEY_NOT_FOUND, key); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - boost::python::list Image::iptcKeys() - { - boost::python::list list; - if(_dataRead) - { - for(Exiv2::IptcMetadata::iterator i = _iptcData.begin() ; i != _iptcData.end() ; i++) - { - // The key is appended to the list if and only if it is not - // already present. - if (list.count(i->key()) == 0) - list.append(i->key()); - } - return list; - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - boost::python::list Image::getIptcTag(std::string key) - { - if(_dataRead) - { - boost::python::list valuesList; - unsigned int valueOccurences = 0; - Exiv2::IptcKey iptcKey = Exiv2::IptcKey(key); - for (Exiv2::IptcMetadata::iterator dataIterator = _iptcData.begin(); - dataIterator != _iptcData.end(); ++dataIterator) - { - if (dataIterator->key() == key) - { - valuesList.append(boost::python::make_tuple(std::string(dataIterator->typeName()), dataIterator->toString())); - ++valueOccurences; - } - } - if (valueOccurences > 0) - return valuesList; - else - throw Exiv2::Error(KEY_NOT_FOUND, key); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - boost::python::tuple Image::setIptcTag(std::string key, std::string value, unsigned int index=0) - { - if(_dataRead) - { - std::string typeName; - std::string oldValue(""); - unsigned int indexCounter = index; - Exiv2::IptcKey iptcKey = Exiv2::IptcKey(key); - Exiv2::IptcMetadata::iterator dataIterator = _iptcData.findKey(iptcKey); - while ((indexCounter > 0) && (dataIterator != _iptcData.end())) - { - dataIterator = std::find_if(++dataIterator, _iptcData.end(), - Exiv2::FindMetadatumById::FindMetadatumById(iptcKey.tag(), iptcKey.record())); - --indexCounter; - } - if (dataIterator != _iptcData.end()) - { - // The tag at given index already exists, override it - dataIterator->setValue(value); - typeName = std::string(dataIterator->typeName()); - oldValue = dataIterator->toString(); - } - else - { - // Either index is greater than the index of the last repetition - // of the tag, or the tag does not exist yet. - // In both cases, it is created. - Exiv2::Iptcdatum iptcDatum(iptcKey); - typeName = std::string(iptcDatum.typeName()); - iptcDatum.setValue(value); - int state = _iptcData.add(iptcDatum); - if (state == 6) - throw Exiv2::Error(NON_REPEATABLE); - } - return boost::python::make_tuple(typeName, oldValue); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - boost::python::tuple Image::deleteIptcTag(std::string key, unsigned int index=0) - { - if(_dataRead) - { - unsigned int indexCounter = index; - Exiv2::IptcKey iptcKey = Exiv2::IptcKey(key); - Exiv2::IptcMetadata::iterator dataIterator = _iptcData.findKey(iptcKey); - while ((indexCounter > 0) && (dataIterator != _iptcData.end())) - { - dataIterator = std::find_if(++dataIterator, _iptcData.end(), - Exiv2::FindMetadatumById::FindMetadatumById(iptcKey.tag(), iptcKey.record())); - --indexCounter; - } - if (dataIterator != _iptcData.end()) - { - // The tag at given index already exists, delete it - boost::python::tuple returnValue = - boost::python::make_tuple(std::string(dataIterator->typeName()), dataIterator->toString()); - _iptcData.erase(dataIterator); - return returnValue; - } - else - throw Exiv2::Error(KEY_NOT_FOUND, key); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - boost::python::tuple Image::tagDetails(std::string key) - { - std::string keyFamily = key.substr(0, 4); - if (keyFamily == "Exif") - { - Exiv2::ExifKey exifKey = Exiv2::ExifKey(key); - std::string tagLabel = exifKey.tagLabel(); - std::string tagDesc = - std::string(Exiv2::ExifTags::tagDesc(exifKey.tag(), exifKey.ifdId())); - return boost::python::make_tuple(tagLabel, tagDesc); - } - else if (keyFamily == "Iptc") - { - Exiv2::IptcKey iptcKey = Exiv2::IptcKey(key); - std::string tagLabel = iptcKey.tagLabel(); - std::string tagDesc = - std::string(Exiv2::IptcDataSets::dataSetDesc(iptcKey.tag(), iptcKey.record())); - return boost::python::make_tuple(tagLabel, tagDesc); - } - } - - boost::python::tuple Image::getThumbnailData() - { - if(_dataRead) - { - Exiv2::Thumbnail::AutoPtr thumbnail = _exifData.getThumbnail(); - if (thumbnail.get() != 0) - { - std::string format(_exifData.thumbnailFormat()); - // Copy the data buffer in a string. Since the data buffer can - // contain null char ('\x00'), the string cannot be simply - // constructed like that: - // std::string data((char*) dataBuffer.pData_); - // because it would be truncated after the first occurence of a - // null char. Therefore, it has to be copied char by char. - Exiv2::DataBuf dataBuffer = _exifData.copyThumbnail(); - char* charData = (char*) dataBuffer.pData_; - long dataLen = dataBuffer.size_; - // First allocate the memory for the whole string... - std::string data(dataLen, ' '); - // ... then fill it with the raw jpeg data. - for(long i = 0; i < dataLen; ++i) - { - data[i] = charData[i]; - } - return boost::python::make_tuple(format, data); - } - else - throw Exiv2::Error(THUMB_ACCESS); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - void Image::setThumbnailData(std::string data) - { - if(_dataRead) - { - const Exiv2::byte* dataBuf = (const Exiv2::byte*) data.c_str(); - _exifData.setJpegThumbnail(dataBuf, data.size()); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - void Image::deleteThumbnail() - { - if(_dataRead) - _exifData.eraseThumbnail(); - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - void Image::dumpThumbnailToFile(const std::string path) - { - if(_dataRead) - { - int result = _exifData.writeThumbnail(path); - if (result == 8) - throw Exiv2::Error(NO_THUMBNAIL); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - void Image::setThumbnailFromJpegFile(const std::string path) - { - if(_dataRead) - { - _exifData.setJpegThumbnail(path); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - const std::string Image::getComment() const - { - if(_dataRead) - { - return _image->comment(); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - void Image::setComment(const std::string& comment) - { - if(_dataRead) - { - _image->setComment(comment); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - void Image::clearComment() - { - if(_dataRead) - { - _image->clearComment(); - } - else - throw Exiv2::Error(METADATA_NOT_READ); - } - - void translateExiv2Error(Exiv2::Error const& e) - { - // Use the Python 'C' API to set up an exception object - - // Building a C++ string first allows this code to compile with all - // versions of libexiv2 (< 0.13 and >= 0.13), because the way exceptions - // are handled in libexiv2 was changed in 0.13. - const std::string sMessage(e.what()); - const char* message = sMessage.c_str(); - - // The type of the Python exception depends on the error code - // Warning: this piece of code should be updated in case the error codes - // defined by Exiv2 (file 'src/error.cpp') are changed - switch (e.code()) - { - case -2: - case -1: - case 1: - case 2: - PyErr_SetString(PyExc_RuntimeError, message); - break; - case 3: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 17: - case 18: - case 20: - case 21: - case 23: - case 31: - case 32: - case 33: - case 36: - case 37: - PyErr_SetString(PyExc_IOError, message); - break; - case 4: - case 5: - case 6: - case 7: - PyErr_SetString(PyExc_IndexError, message); - break; - case 8: - case 22: - case 24: - case 25: - case 26: - case 27: - case 28: - case 29: - case 30: - case 34: - PyErr_SetString(PyExc_ValueError, message); - break; - case 16: - case 19: - case 35: - PyErr_SetString(PyExc_MemoryError, message); - break; - - // custom error codes - case METADATA_NOT_READ: - PyErr_SetString(PyExc_IOError, "Image metadata has not been read yet"); - break; - case NON_REPEATABLE: - PyErr_SetString(PyExc_KeyError, "Tag is not repeatable"); - break; - case KEY_NOT_FOUND: - PyErr_SetString(PyExc_KeyError, "Tag not set"); - break; - case THUMB_ACCESS: - PyErr_SetString(PyExc_IOError, "Cannot access image thumbnail"); - break; - case NO_THUMBNAIL: - PyErr_SetString(PyExc_IOError, "The EXIF data does not contain a thumbnail"); - break; - - default: - PyErr_SetString(PyExc_RuntimeError, message); - } - } - -} // End of namespace LibPyExiv2 diff --git a/src/libpyexiv2.hpp b/src/libpyexiv2.hpp deleted file mode 100644 index eb1f153..0000000 --- a/src/libpyexiv2.hpp +++ /dev/null @@ -1,166 +0,0 @@ -// ***************************************************************************** -/* - * Copyright (C) 2006-2008 Olivier Tilloy <olivier@tilloy.net> - * - * This file is part of the pyexiv2 distribution. - * - * pyexiv2 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. - * - * pyexiv2 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 pyexiv2; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. - */ -/* - File: libpyexiv2.hpp - Author(s): Olivier Tilloy <olivier@tilloy.net> - */ -// ***************************************************************************** - -#ifndef __libpyexiv2_wrapper__ -#define __libpyexiv2_wrapper__ - -#include <string> - -#include "exiv2/image.hpp" -#include "exiv2/exif.hpp" -#include "exiv2/iptc.hpp" - -#include <boost/python.hpp> - -namespace LibPyExiv2 -{ - - class Image - { - public: - // Constructors - Image(std::string filename); - Image(const Image& image); - - void readMetadata(); - void writeMetadata(); - - // Read and write access to the EXIF tags. - // For a complete list of the available EXIF tags, see - // libexiv2's documentation (http://exiv2.org/tags.html). - - // Return a list of all the keys of available EXIF tags set in the - // image. - boost::python::list exifKeys(); - - // Return a tuple containing the type (as a string) and the value - // (as a string as well) of the required EXIF tag. - // Throw an exception if the tag is not set. - boost::python::tuple getExifTag(std::string key); - - // Return a human-readable string containing the value of the - // required EXIF tag. - // Throw an exception if the tag is not set. - std::string getExifTagToString(std::string key); - - // Set the EXIF tag's value and return a tuple containing the - // type and previous value of the tag (an empty string for the value if - // not previously set). If the tag was not previously set, it is - // created. - boost::python::tuple setExifTag(std::string key, std::string value); - - // Delete the required EXIF tag and return a tuple containing the - // type and previous value. - // Throw an exception if the tag was not set. - boost::python::tuple deleteExifTag(std::string key); - - // Read and write access to the IPTC tags. - // For a complete list of the available IPTC tags, see - // libexiv2's documentation (http://exiv2.org/iptc.html). - - // Returns a list of all the keys of available IPTC tags set in the - // image. This list has no duplicates: each of its items is unique, - // even if a tag is present more than once. - boost::python::list iptcKeys(); - - // Return a list of tuples, each containing the type (as a string) and - // the value (as a string as well) of the required IPTC tag. - // Throw an exception if the tag is not set. - boost::python::list getIptcTag(std::string key); - - // Set the IPTC tag's value and return a tuple containing the - // type and previous value of the tag (an empty string for the value if - // not previously set). If the tag was not previously set, it is - // created. If the key references a repeatable tag, the parameter index - // (starting from 0 like a list index) is used to determine which of the - // repetitions is to be set. In case of an index greater than the - // highest existing one, adds a repetition of the tag. - boost::python::tuple setIptcTag(std::string key, std::string value, unsigned int index); - - // Delete the required IPTC tag and return a tuple containing the - // type and previous value. - // If the key references a repeatable tag, the parameter index (starting - // from 0 like a list index) is used to determine which of the - // repetitions is to be deleted. - // Throw an exception if the tag was not set or if the index is greater - // than the highest existing one. - boost::python::tuple deleteIptcTag(std::string key, unsigned int index); - - // Return a tuple containing the name of the tag and its description. - boost::python::tuple tagDetails(std::string key); - - // Read and write access to the thumbnail embedded in the image. - - // Return a tuple containing the format of the thumbnail ("TIFF" or - // "JPEG") and the thumbnail raw data as a string buffer. - // Throw an exception if the thumbnail data cannot be accessed. - boost::python::tuple getThumbnailData(); - - // Set the thumbnail of the image. The parameter is the thumbnail raw - // jpeg data as a string buffer. - void setThumbnailData(std::string data); - - // Delete the thumbnail embedded in the image. - void deleteThumbnail(); - - // Write the thumbnail to an image file. - // A filename extension is appended to the given path according to the - // image type of the thumbnail, so it should not include an extension. - // Throw an exception if the image does not contain a thumbnail. - void dumpThumbnailToFile(const std::string path); - - // Set the image contained in the jpeg file passed as a parameter as - // the thumbnail of the image. - void setThumbnailFromJpegFile(const std::string path); - - // Read and write access to the JPEG comment embedded in the image. - - // Get the JPEG comment contained in the image as a string. - const std::string getComment() const; - - // Set the JPEG comment of the image. - void setComment(const std::string& comment); - - // Clear the JPEG comment of the image (set it to an empty string). - void clearComment(); - - private: - std::string _filename; - Exiv2::Image::AutoPtr _image; - Exiv2::ExifData _exifData; - Exiv2::IptcData _iptcData; - - // true if the image's internal metadata has already been read, - // false otherwise - bool _dataRead; - }; - - // Translate an Exiv2 generic exception into a Python exception - void translateExiv2Error(Exiv2::Error const& e); - -} // End of namespace LibPyExiv2 - -#endif diff --git a/src/libpyexiv2_wrapper.cpp b/src/libpyexiv2_wrapper.cpp deleted file mode 100644 index a191c5b..0000000 --- a/src/libpyexiv2_wrapper.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// ***************************************************************************** -/* - * Copyright (C) 2006-2008 Olivier Tilloy <olivier@tilloy.net> - * - * This file is part of the pyexiv2 distribution. - * - * pyexiv2 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. - * - * pyexiv2 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 pyexiv2; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. - */ -/* - File: libpyexiv2_wrapper.cpp - Author(s): Olivier Tilloy <olivier@tilloy.net> - */ -// ***************************************************************************** - -#include "libpyexiv2.hpp" - -#include <boost/python.hpp> - -using namespace boost::python; - -using namespace LibPyExiv2; - -BOOST_PYTHON_MODULE(libpyexiv2) -{ - register_exception_translator<Exiv2::Error>(&translateExiv2Error); - - // Exported method names prefixed by "_Image__" are going to be "private" - // and are not meant to be used directly - class_<Image>("Image", init<std::string>()) - - .def("readMetadata", &Image::readMetadata) - .def("writeMetadata", &Image::writeMetadata) - - .def("exifKeys", &Image::exifKeys) - .def("_Image__getExifTag", &Image::getExifTag) - .def("_Image__getExifTagToString", &Image::getExifTagToString) - .def("_Image__setExifTag", &Image::setExifTag) - .def("_Image__deleteExifTag", &Image::deleteExifTag) - - .def("iptcKeys", &Image::iptcKeys) - .def("_Image__getIptcTag", &Image::getIptcTag) - .def("_Image__setIptcTag", &Image::setIptcTag) - .def("_Image__deleteIptcTag", &Image::deleteIptcTag) - - .def("tagDetails", &Image::tagDetails) - - .def("getThumbnailData", &Image::getThumbnailData) - .def("setThumbnailData", &Image::setThumbnailData) - .def("deleteThumbnail", &Image::deleteThumbnail) - .def("dumpThumbnailToFile", &Image::dumpThumbnailToFile) - .def("setThumbnailFromJpegFile", &Image::setThumbnailFromJpegFile) - - .def("getComment", &Image::getComment) - .def("setComment", &Image::setComment) - .def("clearComment", &Image::clearComment) - ; -} - |