From: Lutz M?l. <lu...@us...> - 2004-01-19 21:49:53
|
Update of /cvsroot/libexif/libexif/contrib/c++ In directory sc8-pr-cvs1:/tmp/cvs-serv7833/contrib/c++ Added Files: Makefile exif.hxx exif_module.cxx Log Message: 2004-01-19 Lutz Mueller <lu...@us...> * contrib/c++: Files contributed by Hans Meine <han...@gm...>. Completely untested. --- NEW FILE: exif_module.cxx --- /* exif-content.c * * Copyright 2002,2003 Hans Meine <han...@gm...> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "exif.hxx" #include <string> #include <iostream> #include <Python.h> #include <boost/python.hpp> using namespace boost::python; template<class Wrapper, class Pointer> struct WrappedObjectIterator { //typedef Wrapper value_type; Pointer *it_, *end_; WrappedObjectIterator(Pointer *it, Pointer *end) : it_(it), end_(end) {} Wrapper next() { if(it_ == end_) { PyErr_SetString(PyExc_StopIteration, "iterator exhausted"); throw_error_already_set(); } return Wrapper(*it_++); } }; struct PythonEntry : public Exif::Entry { PythonEntry() {} PythonEntry(Exif::Entry const &other) : Exif::Entry(other) {} object component(long index) const { switch(format()) { case EXIF_FORMAT_BYTE: return object(getByte(index)); case EXIF_FORMAT_SHORT: return object(getShort(index)); case EXIF_FORMAT_LONG: return object(getLong(index)); case EXIF_FORMAT_SLONG: return object(getSLong(index)); case EXIF_FORMAT_RATIONAL: return object(getRational(index)); case EXIF_FORMAT_SRATIONAL: return object(getSRational(index)); case EXIF_FORMAT_ASCII: //std::cerr << "returning " << entry_->size << " bytes of data..\n"; //std::cerr << " (copied into " << std::string((char *)data, entry_->size).size() << "-character string)\n"; return object(std::string((char *)entry_->data, entry_->size)); default: break; } return object(); } object data() const { if((format() == EXIF_FORMAT_ASCII) || (components()==1)) return component(0); else { list result; for(unsigned int i=0; i<components(); ++i) result.append(component(i)); return result; } } template<class Type> Type extractComponent(unsigned int index, object value, const char *errorString) { extract<Type> extr(value); if(!extr.check()) { PyErr_SetString(PyExc_TypeError, errorString); throw_error_already_set(); } return extr(); } void setComponent(unsigned int index, object value) { unsigned char *data= entry_->data + index * exif_format_get_size(format()); ExifByteOrder bo = exif_data_get_byte_order(entry_->parent->parent); switch(format()) { case EXIF_FORMAT_BYTE: *data= extractComponent<ExifByte>(index, value, "invalid assignment to data: could not convert value to byte format"); break; case EXIF_FORMAT_SHORT: exif_set_short(data, bo, extractComponent<ExifShort>(index, value, "invalid assignment to data: could not convert value to short format")); break; case EXIF_FORMAT_LONG: exif_set_long(data, bo, extractComponent<ExifLong>(index, value, "invalid assignment to data: could not convert value to long format")); break; case EXIF_FORMAT_SLONG: exif_set_slong(data, bo, extractComponent<ExifSLong>(index, value, "invalid assignment to data: could not convert value to signed long format")); break; case EXIF_FORMAT_RATIONAL: exif_set_rational(data, bo, extractComponent<ExifRational>(index, value, "invalid assignment to data: could not convert value to rational format (2-tuple expected)")); break; case EXIF_FORMAT_SRATIONAL: exif_set_srational(data, bo, extractComponent<ExifSRational>(index, value, "invalid assignment to data: could not convert value to signed rational format (2-tuple expected)")); break; case EXIF_FORMAT_ASCII: // handled in setData directly case EXIF_FORMAT_UNDEFINED: break; } return; } void setData(object data) { if(format() == EXIF_FORMAT_ASCII) { extract<std::string> xstr(data); if(xstr.check()) { std::string s= xstr(); if(entry_->data) free(entry_->data); entry_->components= s.size(); //std::cerr << "assigning " << s.size() << "-character string..\n"; entry_->size= exif_format_get_size(format()) * entry_->components; entry_->data= (unsigned char *)malloc(entry_->size); memcpy(entry_->data, s.data(), entry_->size); entry_->data[entry_->size]= 0; } else { PyErr_SetString(PyExc_TypeError, "invalid assignment to data of ASCII format entry: string expected"); throw_error_already_set(); } } else { if(components()==1) setComponent(0, data); else { extract<list> xlist(data); if(xlist.check()) { list l= xlist(); for(unsigned i=0; i<components(); ++i) setComponent(i, l[i]); } else { PyErr_SetString(PyExc_TypeError, "invalid assignment to data of entry with more than one component: list expected"); throw_error_already_set(); } } } } }; struct PythonContent : public Exif::Content { typedef WrappedObjectIterator<PythonEntry, ExifEntry *> iterator; PythonContent() {} PythonContent(Exif::Content const &other) : Exif::Content(other) {} PythonEntry entry(object index) { // TODO: use Exif::Content::entry() functions extract<ExifTag> xtag(index); if(xtag.check()) { ExifTag index= xtag(); for(unsigned int i=0; i<size(); i++) { if(content_->entries[i]->tag == index) return Exif::Entry(content_->entries[i]); } PyErr_SetString(PyExc_KeyError, "tag not present in IFD content"); throw_error_already_set(); } extract<int> xint(index); if(xint.check()) { int index= xint(); if((index>=0) && (index<(long)size())) return Exif::Entry(content_->entries[index]); if((index<0) && (index>=-(long)size())) return Exif::Entry(content_->entries[size()+index]); PyErr_SetString(PyExc_IndexError, "invalid integer index into IFD content"); throw_error_already_set(); } PyErr_SetString(PyExc_TypeError, "invalid index into EXIF data (integer or IFD expected)"); throw_error_already_set(); return Exif::Entry(); // never reached } iterator __iter__() { // FIXME: the public API is exif_content_foreach, // relying on memory layout here! return iterator(content_->entries, content_->entries + content_->count); } }; struct PythonData : public Exif::Data { typedef WrappedObjectIterator<PythonContent, ExifContent *> iterator; bool success_; PythonData() {} PythonData(const char *path) : Exif::Data(path, &success_) { if(!success_) { PyErr_SetFromErrno(PyExc_IOError); //PyErr_SetString(PyExc_IOError, ""); throw_error_already_set(); } } PythonData(const unsigned char *data, unsigned int size) : Exif::Data(data, size) {} PythonData(Exif::Data const &other) : Exif::Data(other) {} PythonContent ifdContent(object index) { extract<ExifIfd> xifd(index); if(xifd.check()) { ExifIfd index= xifd(); if(index<EXIF_IFD_COUNT) return Exif::Content(data_->ifd[index]); PyErr_SetString(PyExc_IndexError, "invalid IFD index into EXIF data"); throw_error_already_set(); } extract<int> xint(index); if(xint.check()) { int index= xint(); if((index>=0) && (index<(long)size())) return Exif::Content(data_->ifd[index]); if((index<0) && (index>=-(long)size())) return Exif::Content(data_->ifd[size()+index]); PyErr_SetString(PyExc_IndexError, "invalid integer index into EXIF data"); throw_error_already_set(); } PyErr_SetString(PyExc_TypeError, "invalid index into EXIF data (integer or IFD expected)"); throw_error_already_set(); return Exif::Content(); // never reached } iterator __iter__() { return iterator(data_->ifd, data_->ifd + EXIF_IFD_COUNT); } }; template<class Rational, class Component> struct RationalConverter { RationalConverter() { converter::registry::insert(&convertible, &construct, type_id<Rational>()); } static void* convertible(PyObject* obj) { extract<tuple> xtup(obj); if(xtup.check()) { tuple t= xtup(); if((t.attr("__len__")() == 2) && extract<Component>(t[0]).check() && extract<Component>(t[1]).check()) { Rational *result = new Rational; result->numerator = extract<Component>(t[0])(); result->denominator = extract<Component>(t[1])(); return result; } } return NULL; } static void construct(PyObject* obj, converter::rvalue_from_python_stage1_data* data) { Rational const* r = static_cast<Rational*>(data->convertible); void* storage = ((converter::rvalue_from_python_storage<Rational>*)data)->storage.bytes; new (storage) Rational(); ((Rational*)storage)->numerator = r->numerator; ((Rational*)storage)->denominator = r->denominator; data->convertible = storage; delete r; } static PyObject *convert(Rational r) { tuple t= make_tuple(r.numerator, r.denominator); PyObject *result= t.ptr(); Py_INCREF(result); return result; } }; BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(entrydumps, Exif::Entry::dump, 0, 1) BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(contentdumps, Exif::Content::dump, 0, 1) BOOST_PYTHON_MODULE(exif) { RationalConverter<ExifRational, ExifLong>(); RationalConverter<ExifSRational, ExifSLong>(); to_python_converter<ExifRational, RationalConverter<ExifRational, ExifLong> >(); to_python_converter<ExifSRational, RationalConverter<ExifSRational, ExifSLong> >(); enum_<ExifByteOrder>("ByteOrder") .value("MOTOROLA", EXIF_BYTE_ORDER_MOTOROLA) .value("INTEL", EXIF_BYTE_ORDER_INTEL); def("name", &exif_byte_order_get_name); enum_<ExifIfd>("IFD") .value("ZERO", EXIF_IFD_0) .value("ONE", EXIF_IFD_1) .value("EXIF", EXIF_IFD_EXIF) .value("GPS", EXIF_IFD_GPS) .value("INTEROPERABILITY", EXIF_IFD_INTEROPERABILITY); //.value("COUNT", EXIF_IFD_COUNT) def("name", &exif_ifd_get_name); enum_<ExifFormat>("Format") .value("BYTE", EXIF_FORMAT_BYTE) .value("ASCII", EXIF_FORMAT_ASCII) .value("SHORT", EXIF_FORMAT_SHORT) .value("LONG", EXIF_FORMAT_LONG) .value("RATIONAL", EXIF_FORMAT_RATIONAL) .value("UNDEFINED", EXIF_FORMAT_UNDEFINED) .value("SLONG", EXIF_FORMAT_SLONG) .value("SRATIONAL", EXIF_FORMAT_SRATIONAL); def("name", &exif_format_get_name); def("size", &exif_format_get_size); enum_<ExifTag>("Tag") .value("INTEROPERABILITY_INDEX", EXIF_TAG_INTEROPERABILITY_INDEX) .value("INTEROPERABILITY_VERSION", EXIF_TAG_INTEROPERABILITY_VERSION) .value("IMAGE_WIDTH", EXIF_TAG_IMAGE_WIDTH) .value("IMAGE_LENGTH", EXIF_TAG_IMAGE_LENGTH) .value("BITS_PER_SAMPLE", EXIF_TAG_BITS_PER_SAMPLE) .value("COMPRESSION", EXIF_TAG_COMPRESSION) .value("PHOTOMETRIC_INTERPRETATION", EXIF_TAG_PHOTOMETRIC_INTERPRETATION) .value("FILL_ORDER", EXIF_TAG_FILL_ORDER) .value("DOCUMENT_NAME", EXIF_TAG_DOCUMENT_NAME) .value("IMAGE_DESCRIPTION", EXIF_TAG_IMAGE_DESCRIPTION) .value("MAKE", EXIF_TAG_MAKE) .value("MODEL", EXIF_TAG_MODEL) .value("STRIP_OFFSETS", EXIF_TAG_STRIP_OFFSETS) .value("ORIENTATION", EXIF_TAG_ORIENTATION) .value("SAMPLES_PER_PIXEL", EXIF_TAG_SAMPLES_PER_PIXEL) .value("ROWS_PER_STRIP", EXIF_TAG_ROWS_PER_STRIP) .value("STRIP_BYTE_COUNTS", EXIF_TAG_STRIP_BYTE_COUNTS) .value("X_RESOLUTION", EXIF_TAG_X_RESOLUTION) .value("Y_RESOLUTION", EXIF_TAG_Y_RESOLUTION) .value("PLANAR_CONFIGURATION", EXIF_TAG_PLANAR_CONFIGURATION) .value("RESOLUTION_UNIT", EXIF_TAG_RESOLUTION_UNIT) .value("TRANSFER_FUNCTION", EXIF_TAG_TRANSFER_FUNCTION) .value("SOFTWARE", EXIF_TAG_SOFTWARE) .value("DATE_TIME", EXIF_TAG_DATE_TIME) .value("ARTIST", EXIF_TAG_ARTIST) .value("WHITE_POINT", EXIF_TAG_WHITE_POINT) .value("PRIMARY_CHROMATICITIES", EXIF_TAG_PRIMARY_CHROMATICITIES) .value("TRANSFER_RANGE", EXIF_TAG_TRANSFER_RANGE) .value("JPEG_PROC", EXIF_TAG_JPEG_PROC) .value("JPEG_INTERCHANGE_FORMAT", EXIF_TAG_JPEG_INTERCHANGE_FORMAT) .value("JPEG_INTERCHANGE_FORMAT_LENGTH", EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH) .value("YCBCR_COEFFICIENTS", EXIF_TAG_YCBCR_COEFFICIENTS) .value("YCBCR_SUB_SAMPLING", EXIF_TAG_YCBCR_SUB_SAMPLING) .value("YCBCR_POSITIONING", EXIF_TAG_YCBCR_POSITIONING) .value("REFERENCE_BLACK_WHITE", EXIF_TAG_REFERENCE_BLACK_WHITE) .value("RELATED_IMAGE_FILE_FORMAT", EXIF_TAG_RELATED_IMAGE_FILE_FORMAT) .value("RELATED_IMAGE_WIDTH", EXIF_TAG_RELATED_IMAGE_WIDTH) .value("RELATED_IMAGE_LENGTH", EXIF_TAG_RELATED_IMAGE_LENGTH) .value("CFA_REPEAT_PATTERN_DIM", EXIF_TAG_CFA_REPEAT_PATTERN_DIM) .value("CFA_PATTERN", EXIF_TAG_CFA_PATTERN) .value("BATTERY_LEVEL", EXIF_TAG_BATTERY_LEVEL) .value("COPYRIGHT", EXIF_TAG_COPYRIGHT) .value("EXPOSURE_TIME", EXIF_TAG_EXPOSURE_TIME) .value("FNUMBER", EXIF_TAG_FNUMBER) .value("IPTC_NAA", EXIF_TAG_IPTC_NAA) .value("EXIF_IFD_POINTER", EXIF_TAG_EXIF_IFD_POINTER) .value("INTER_COLOR_PROFILE", EXIF_TAG_INTER_COLOR_PROFILE) .value("EXPOSURE_PROGRAM", EXIF_TAG_EXPOSURE_PROGRAM) .value("SPECTRAL_SENSITIVITY", EXIF_TAG_SPECTRAL_SENSITIVITY) .value("GPS_INFO_IFD_POINTER", EXIF_TAG_GPS_INFO_IFD_POINTER) .value("ISO_SPEED_RATINGS", EXIF_TAG_ISO_SPEED_RATINGS) .value("OECF", EXIF_TAG_OECF) .value("EXIF_VERSION", EXIF_TAG_EXIF_VERSION) .value("DATE_TIME_ORIGINAL", EXIF_TAG_DATE_TIME_ORIGINAL) .value("DATE_TIME_DIGITIZED", EXIF_TAG_DATE_TIME_DIGITIZED) .value("COMPONENTS_CONFIGURATION", EXIF_TAG_COMPONENTS_CONFIGURATION) .value("COMPRESSED_BITS_PER_PIXEL", EXIF_TAG_COMPRESSED_BITS_PER_PIXEL) .value("SHUTTER_SPEED_VALUE", EXIF_TAG_SHUTTER_SPEED_VALUE) .value("APERTURE_VALUE", EXIF_TAG_APERTURE_VALUE) .value("BRIGHTNESS_VALUE", EXIF_TAG_BRIGHTNESS_VALUE) .value("EXPOSURE_BIAS_VALUE", EXIF_TAG_EXPOSURE_BIAS_VALUE) .value("MAX_APERTURE_VALUE", EXIF_TAG_MAX_APERTURE_VALUE) .value("SUBJECT_DISTANCE", EXIF_TAG_SUBJECT_DISTANCE) .value("METERING_MODE", EXIF_TAG_METERING_MODE) .value("LIGHT_SOURCE", EXIF_TAG_LIGHT_SOURCE) .value("FLASH", EXIF_TAG_FLASH) .value("FOCAL_LENGTH", EXIF_TAG_FOCAL_LENGTH) .value("SUBJECT_AREA", EXIF_TAG_SUBJECT_AREA) .value("MAKER_NOTE", EXIF_TAG_MAKER_NOTE) .value("USER_COMMENT", EXIF_TAG_USER_COMMENT) .value("SUBSEC_TIME", EXIF_TAG_SUBSEC_TIME) .value("SUB_SEC_TIME_ORIGINAL", EXIF_TAG_SUB_SEC_TIME_ORIGINAL) .value("SUB_SEC_TIME_DIGITIZED", EXIF_TAG_SUB_SEC_TIME_DIGITIZED) .value("FLASH_PIX_VERSION", EXIF_TAG_FLASH_PIX_VERSION) .value("COLOR_SPACE", EXIF_TAG_COLOR_SPACE) .value("PIXEL_X_DIMENSION", EXIF_TAG_PIXEL_X_DIMENSION) .value("PIXEL_Y_DIMENSION", EXIF_TAG_PIXEL_Y_DIMENSION) .value("RELATED_SOUND_FILE", EXIF_TAG_RELATED_SOUND_FILE) .value("INTEROPERABILITY_IFD_POINTER", EXIF_TAG_INTEROPERABILITY_IFD_POINTER) .value("FLASH_ENERGY", EXIF_TAG_FLASH_ENERGY) .value("SPATIAL_FREQUENCY_RESPONSE", EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE) .value("FOCAL_PLANE_X_RESOLUTION", EXIF_TAG_FOCAL_PLANE_X_RESOLUTION) .value("FOCAL_PLANE_Y_RESOLUTION", EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION) .value("FOCAL_PLANE_RESOLUTION_UNIT", EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT) .value("SUBJECT_LOCATION", EXIF_TAG_SUBJECT_LOCATION) .value("EXPOSURE_INDEX", EXIF_TAG_EXPOSURE_INDEX) .value("SENSING_METHOD", EXIF_TAG_SENSING_METHOD) .value("FILE_SOURCE", EXIF_TAG_FILE_SOURCE) .value("SCENE_TYPE", EXIF_TAG_SCENE_TYPE) .value("NEW_CFA_PATTERN", EXIF_TAG_NEW_CFA_PATTERN) .value("CUSTOM_RENDERED", EXIF_TAG_CUSTOM_RENDERED) .value("EXPOSURE_MODE", EXIF_TAG_EXPOSURE_MODE) .value("WHITE_BALANCE", EXIF_TAG_WHITE_BALANCE) .value("DIGITAL_ZOOM_RATIO", EXIF_TAG_DIGITAL_ZOOM_RATIO) .value("FOCAL_LENGTH_IN_35MM_FILM", EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM) .value("SCENE_CAPTURE_TYPE", EXIF_TAG_SCENE_CAPTURE_TYPE) .value("GAIN_CONTROL", EXIF_TAG_GAIN_CONTROL) .value("CONTRAST", EXIF_TAG_CONTRAST) .value("SATURATION", EXIF_TAG_SATURATION) .value("SHARPNESS", EXIF_TAG_SHARPNESS) .value("DEVICE_SETTING_DESCRIPTION", EXIF_TAG_DEVICE_SETTING_DESCRIPTION) .value("SUBJECT_DISTANCE_RANGE", EXIF_TAG_SUBJECT_DISTANCE_RANGE) .value("IMAGE_UNIQUE_ID", EXIF_TAG_IMAGE_UNIQUE_ID); def("name", &exif_tag_get_name); def("title", &exif_tag_get_title); def("description", &exif_tag_get_description); class_<PythonEntry>("Entry") .add_property("tag", &Exif::Entry::tag) .add_property("format", &Exif::Entry::format) .add_property("components", &Exif::Entry::components) .add_property("data", &PythonEntry::data, &PythonEntry::setData) .def("value", &Exif::Entry::value) .def("briefValue", &Exif::Entry::briefValue) .def("dump", &Exif::Entry::dump);//, entrydumps()); class_<PythonContent::iterator>("ContentIterator", no_init) .def("next", &PythonContent::iterator::next); class_<PythonContent>("Content") .def("__len__", &Exif::Content::size) .def("__getitem__", &PythonContent::entry) .def("__iter__", &PythonContent::__iter__) .def("dump", &Exif::Content::dump);//, contentdumps()); class_<PythonData::iterator>("DataIterator", no_init) .def("next", &PythonData::iterator::next); class_<PythonData>("Data") .def(init<const char *>()) .def(init<const unsigned char *, unsigned int>()) .def("__len__", &Exif::Data::size) .def("__getitem__", &PythonData::ifdContent) .def("__iter__", &PythonData::__iter__) .def("byteOrder", &Exif::Data::byteOrder) .def("dump", &Exif::Data::dump); } --- NEW FILE: Makefile --- BOOST_PYTHON_LIB = -L/usr/local/boost_1_29_0/lib -lboost_python BOOST_INCLUDES = -I/usr/local/boost_1_29_0/src dynmoddir = `pwd`/local CXX = g++ CXXFLAGS := -O2 -Wall CPPFLAGS := -I/usr/include/python2.2 LIBTOOL = $(SHELL) ./libtool LIBCXX = $(LIBTOOL) --tag=CXX --mode=compile $(CXX) LINKCXX = $(LIBTOOL) --tag=CXX --mode=link $(CXX) LINKCXXLIB = $(LINKCXX) -rpath $(dynmoddir) LINKCXXMODULE = $(LINKCXXLIB) -module -avoid-version LIBINSTALL = $(LIBTOOL) --mode=install /bin/install -c -p INSTALL = /bin/install -c -p TARGET = exif.la OBJS = \ exif_module.lo all: $(TARGET) install: $(TARGET) $(INSTALL) -d $(dynmoddir) $(LIBINSTALL) $(TARGET) $(dynmoddir) $(TARGET): $(OBJS) $(LINKCXXMODULE) -o $(TARGET) $(OBJS) $(BOOST_PYTHON_LIB) -lexif clean:: rm -rf .libs *.o *.so *.lo *.ld $(TARGET) %.o: %.cxx $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $*.cxx %.lo: %.cxx $(LIBCXX) $(CXXFLAGS) $(CPPFLAGS) -c $*.cxx %.d: %.cxx @echo updating header dependencies for $*.cxx @rm -f $*.d @$(CXX) -M $(CXXFLAGS) $(CPPFLAGS) -c $*.cxx | sed "s@$*.o@$*.d $*.o@" > $*.d \ || { rm -f $*.d; exit 1; } %.ld: %.cxx @echo updating header dependencies for $*.cxx @rm -f $*.ld @$(CXX) -M $(CXXFLAGS) $(CPPFLAGS) -c $*.cxx | sed "s@$*.o@$*.ld $*.lo@" > $*.ld \ || { rm -f $*.ld; exit 1; } ifneq "$(MAKECMDGOALS)" "clean" include $(patsubst %.lo, %.ld, $(OBJS)) endif --- NEW FILE: exif.hxx --- /* exif.hxx * * Copyright 2002,2003 Hans Meine <han...@gm...> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifndef EXIF_HXX #define EXIF_HXX #include <libexif/exif-entry.h> #include <libexif/exif-content.h> #include <libexif/exif-ifd.h> #include <libexif/exif-data.h> #include <libexif/exif-format.h> #include <libexif/exif-utils.h> #include <stdexcept> #include <string> namespace Exif { #ifndef EXIF_NO_EXCEPTIONS struct InvalidIndex : std::runtime_error { InvalidIndex(const std::string& s) : std::runtime_error(s) {} }; struct InvalidFormat : std::runtime_error { InvalidFormat(const std::string& s) : std::runtime_error(s) {} }; struct IOError : std::runtime_error { IOError(const std::string& s) : std::runtime_error(s) {} }; #endif // EXIF_NO_EXCEPTIONS struct Entry { ExifEntry *entry_; // construct an empty entry, FIXME: is this needed in the public API? Entry() : entry_(exif_entry_new()) {} // construct an entry for the given tag Entry(ExifTag tag) : entry_(exif_entry_new()) { exif_entry_initialize(entry_, tag); } // copy constructor Entry(Entry const &other) : entry_(other.entry_) { exif_entry_ref(entry_); } // internal, do not use directly Entry(ExifEntry *entry) : entry_(entry) { exif_entry_ref(entry_); } ~Entry() { exif_entry_unref(entry_); } Entry &operator=(Entry const &other) { exif_entry_unref(entry_); entry_ = other.entry_; exif_entry_ref(entry_); return *this; } ExifTag tag() const { return entry_->tag; } /* void setTag(ExifTag tag) { entry_->tag = tag; } */ ExifFormat format() const { return entry_->format; } /* void setFormat(ExifFormat format) { entry_->format = format; } */ unsigned long components() const { return entry_->components; } /* void setComponents(unsigned long components) { entry_->components = components; } void initialize(ExifTag tag) { exif_entry_initialize(entry_, tag); } */ ExifByte getByte(unsigned int index) const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_BYTE) throw InvalidFormat( "Exif::Entry::getByte(): Format is not EXIF_FORMAT_BYTE"); if(index >= components()) throw InvalidIndex( "Exif::getByte: component index out of range"); #endif return *(entry_->data + index * exif_format_get_size(entry_->format)); } const ExifAscii getAscii() const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_ASCII) throw InvalidFormat( "Exif::Entry::getAscii(): Format is not EXIF_FORMAT_ASCII"); #endif return (ExifAscii)entry_->data; } ExifShort getShort(unsigned int index) const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_SHORT) throw InvalidFormat( "Exif::Entry::getShort(): Format is not EXIF_FORMAT_SHORT"); if(index >= components()) throw InvalidIndex( "Exif::getShort: component index out of range"); #endif return exif_get_short(entry_->data + index * exif_format_get_size(entry_->format), exif_data_get_byte_order(entry_->parent->parent)); } ExifLong getLong(unsigned int index) const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_LONG) throw InvalidFormat( "Exif::Entry::getLong(): Format is not EXIF_FORMAT_LONG"); if(index >= components()) throw InvalidIndex( "Exif::getLong: component index out of range"); #endif return exif_get_long(entry_->data + index * exif_format_get_size(entry_->format), exif_data_get_byte_order(entry_->parent->parent)); } ExifSLong getSLong(unsigned int index) const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_SLONG) throw InvalidFormat( "Exif::Entry::getSLong(): Format is not EXIF_FORMAT_SLONG"); if(index >= components()) throw InvalidIndex( "Exif::getSLong: component index out of range"); #endif return exif_get_slong(entry_->data + index * exif_format_get_size(entry_->format), exif_data_get_byte_order(entry_->parent->parent)); } ExifRational getRational(unsigned int index) const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_RATIONAL) throw InvalidFormat( "Exif::Entry::getRational(): Format is not EXIF_FORMAT_RATIONAL"); if(index >= components()) throw InvalidIndex( "Exif::getRational: component index out of range"); #endif return exif_get_rational(entry_->data + index * exif_format_get_size(entry_->format), exif_data_get_byte_order(entry_->parent->parent)); } ExifSRational getSRational(unsigned int index) const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_SRATIONAL) throw InvalidFormat( "Exif::Entry::getSRational(): Format is not EXIF_FORMAT_SRATIONAL"); if(index >= components()) throw InvalidIndex( "Exif::getSRational: component index out of range"); #endif return exif_get_srational(entry_->data + index * exif_format_get_size(entry_->format), exif_data_get_byte_order(entry_->parent->parent)); } void setByte(unsigned int index, ExifByte value) const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_BYTE) throw InvalidFormat( "Exif::Entry::setByte(): Format is not EXIF_FORMAT_BYTE"); if(index >= components()) throw InvalidIndex( "Exif::setByte: component index out of range"); #endif *(entry_->data + index * exif_format_get_size(entry_->format)) = value; } /* const ExifAscii setAscii() const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_ASCII) throw InvalidFormat( "Exif::Entry::setAscii(): Format is not EXIF_FORMAT_ASCII"); #endif return (ExifAscii)entry_->data; } */ void setShort(unsigned int index, ExifShort value) const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_SHORT) throw InvalidFormat( "Exif::Entry::setShort(): Format is not EXIF_FORMAT_SHORT"); if(index >= components()) throw InvalidIndex( "Exif::setShort: component index out of range"); #endif return exif_set_short(entry_->data + index * exif_format_get_size(entry_->format), exif_data_get_byte_order(entry_->parent->parent), value); } void setLong(unsigned int index, ExifLong value) const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_LONG) throw InvalidFormat( "Exif::Entry::setLong(): Format is not EXIF_FORMAT_LONG"); if(index >= components()) throw InvalidIndex( "Exif::setLong: component index out of range"); #endif return exif_set_long(entry_->data + index * exif_format_get_size(entry_->format), exif_data_get_byte_order(entry_->parent->parent), value); } void setSLong(unsigned int index, ExifSLong value) const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_SLONG) throw InvalidFormat( "Exif::Entry::setSLong(): Format is not EXIF_FORMAT_SLONG"); if(index >= components()) throw InvalidIndex( "Exif::setSLong: component index out of range"); #endif return exif_set_slong(entry_->data + index * exif_format_get_size(entry_->format), exif_data_get_byte_order(entry_->parent->parent), value); } void setRational(unsigned int index, ExifRational value) const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_RATIONAL) throw InvalidFormat( "Exif::Entry::setRational(): Format is not EXIF_FORMAT_RATIONAL"); if(index >= components()) throw InvalidIndex( "Exif::setRational: component index out of range"); #endif return exif_set_rational(entry_->data + index * exif_format_get_size(entry_->format), exif_data_get_byte_order(entry_->parent->parent), value); } void setSRational(unsigned int index, ExifSRational value) const { #ifndef EXIF_NO_EXCEPTIONS if(entry_->format != EXIF_FORMAT_SRATIONAL) throw InvalidFormat( "Exif::Entry::setSRational(): Format is not EXIF_FORMAT_SRATIONAL"); if(index >= components()) throw InvalidIndex( "Exif::setSRational: component index out of range"); #endif return exif_set_srational(entry_->data + index * exif_format_get_size(entry_->format), exif_data_get_byte_order(entry_->parent->parent), value); } const char *value() { return exif_entry_get_value(entry_); } const char *briefValue() { return exif_entry_get_value_brief(entry_); } void dump(unsigned int indent = 0) const { exif_entry_dump(entry_, indent); } }; struct Content { ExifContent *content_; Content() : content_(exif_content_new()) {} Content(Content const &other) : content_(other.content_) { exif_content_ref(content_); } // internal, do not use directly Content(ExifContent *content) : content_(content) { exif_content_ref(content_); } ~Content() { exif_content_unref(content_); } Content &operator=(Content const &other) { exif_content_unref(content_); content_ = other.content_; exif_content_ref(content_); return *this; } Entry operator[](ExifTag tag) { ExifEntry *result = exif_content_get_entry(content_, tag); if(result) return Entry(result); #ifndef EXIF_NO_EXCEPTIONS throw InvalidIndex( "Exif::Content: IFD does not contain given tag"); #endif return Entry(); } Entry operator[](unsigned int index) { if(index < size()) return Entry(content_->entries[index]); #ifndef EXIF_NO_EXCEPTIONS throw InvalidIndex( "Exif::Content: numeric entry index out of range"); #endif // EXIF_NO_EXCEPTIONS return Entry(); } unsigned int size() const { // FIXME: content_ should never be NULL, so this is unneeded!? return content_ ? content_->count : 0; } void add(Entry &entry) { exif_content_add_entry(content_, entry.entry_); } void remove(Entry &entry) { exif_content_remove_entry(content_, entry.entry_); } // for your convenience const char *value(ExifTag tag) { return exif_content_get_value(content_, tag); } // for your convenience const char *briefValue(ExifTag tag) { return exif_content_get_value_brief(content_, tag); } void dump(unsigned int indent = 0) const { exif_content_dump(content_, indent); } }; struct Data { ExifData *data_; Data() : data_(exif_data_new()) {} Data(const char *path, bool *success = 0) : data_(exif_data_new_from_file(path)) { if(success) *success = data_; #ifndef EXIF_NO_EXCEPTIONS else if(!data_) throw IOError("Exif::Data: Could not load file"); #endif // EXIF_NO_EXCEPTIONS if(!data_) exif_data_new(); } Data(const unsigned char *data, unsigned int size) : data_(exif_data_new_from_data(data, size)) {} Data(Data const &other) : data_(other.data_) { exif_data_ref(data_); } ~Data() { exif_data_unref(data_); } Data &operator=(Data const &other) { exif_data_unref(data_); data_ = other.data_; exif_data_ref(data_); return *this; } void save(unsigned char **d, unsigned int *size) { exif_data_save_data(data_, d, size); } unsigned int size() const { return EXIF_IFD_COUNT; } Content operator[](unsigned int index) { if(index < size()) return Content(data_->ifd[index]); #ifndef EXIF_NO_EXCEPTIONS throw InvalidIndex( "Exif::Data: IFD index out of range"); #endif // EXIF_NO_EXCEPTIONS return Content(); } ExifByteOrder byteOrder() const { return exif_data_get_byte_order(data_); } void setByteOrder(ExifByteOrder bo) const { exif_data_set_byte_order(data_, bo); } void dump() { exif_data_dump(data_); } }; } // namespace Exif #endif // EXIF_HXX |