1/* exif-content.c 2 * 3 * Copyright 2002,2003 Hans Meine <hans_meine@gmx.net> 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the 17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * Boston, MA 02110-1301 USA. 19 */ 20 21#include "exif.hxx" 22#include <string> 23#include <iostream> 24 25#include <Python.h> 26#include <boost/python.hpp> 27using namespace boost::python; 28 29template<class Wrapper, class Pointer> 30struct WrappedObjectIterator 31{ 32 //typedef Wrapper value_type; 33 Pointer *it_, *end_; 34 35 WrappedObjectIterator(Pointer *it, Pointer *end) 36 : it_(it), end_(end) 37 {} 38 39 Wrapper next() 40 { 41 if(it_ == end_) 42 { 43 PyErr_SetString(PyExc_StopIteration, "iterator exhausted"); 44 throw_error_already_set(); 45 } 46 return Wrapper(*it_++); 47 } 48}; 49 50struct PythonEntry : public Exif::Entry 51{ 52 PythonEntry() {} 53 PythonEntry(Exif::Entry const &other) : Exif::Entry(other) {} 54 55 object component(long index) const 56 { 57 switch(format()) 58 { 59 case EXIF_FORMAT_BYTE: 60 return object(getByte(index)); 61 case EXIF_FORMAT_SHORT: 62 return object(getShort(index)); 63 case EXIF_FORMAT_LONG: 64 return object(getLong(index)); 65 case EXIF_FORMAT_SLONG: 66 return object(getSLong(index)); 67 case EXIF_FORMAT_RATIONAL: 68 return object(getRational(index)); 69 case EXIF_FORMAT_SRATIONAL: 70 return object(getSRational(index)); 71 case EXIF_FORMAT_ASCII: 72 //std::cerr << "returning " << entry_->size << " bytes of data..\n"; 73 //std::cerr << " (copied into " << std::string((char *)data, entry_->size).size() << "-character string)\n"; 74 return object(std::string((char *)entry_->data, entry_->size)); 75 default: 76 break; 77 } 78 return object(); 79 } 80 81 object data() const 82 { 83 if((format() == EXIF_FORMAT_ASCII) || (components()==1)) 84 return component(0); 85 else 86 { 87 list result; 88 for(unsigned int i=0; i<components(); ++i) 89 result.append(component(i)); 90 return result; 91 } 92 } 93 94 template<class Type> 95 Type extractComponent(unsigned int index, object value, 96 const char *errorString) 97 { 98 extract<Type> extr(value); 99 if(!extr.check()) 100 { 101 PyErr_SetString(PyExc_TypeError, errorString); 102 throw_error_already_set(); 103 } 104 return extr(); 105 } 106 107 void setComponent(unsigned int index, object value) 108 { 109 unsigned char *data= entry_->data 110 + index * exif_format_get_size(format()); 111 ExifByteOrder bo = exif_data_get_byte_order(entry_->parent->parent); 112 113 switch(format()) 114 { 115 case EXIF_FORMAT_BYTE: 116 *data= extractComponent<ExifByte>(index, value, "invalid assignment to data: could not convert value to byte format"); 117 break; 118 case EXIF_FORMAT_SHORT: 119 exif_set_short(data, bo, extractComponent<ExifShort>(index, value, "invalid assignment to data: could not convert value to short format")); 120 break; 121 case EXIF_FORMAT_LONG: 122 exif_set_long(data, bo, extractComponent<ExifLong>(index, value, "invalid assignment to data: could not convert value to long format")); 123 break; 124 case EXIF_FORMAT_SLONG: 125 exif_set_slong(data, bo, extractComponent<ExifSLong>(index, value, "invalid assignment to data: could not convert value to signed long format")); 126 break; 127 case EXIF_FORMAT_RATIONAL: 128 exif_set_rational(data, bo, extractComponent<ExifRational>(index, value, "invalid assignment to data: could not convert value to rational format (2-tuple expected)")); 129 break; 130 case EXIF_FORMAT_SRATIONAL: 131 exif_set_srational(data, bo, extractComponent<ExifSRational>(index, value, "invalid assignment to data: could not convert value to signed rational format (2-tuple expected)")); 132 break; 133 case EXIF_FORMAT_ASCII: // handled in setData directly 134 case EXIF_FORMAT_UNDEFINED: 135 break; 136 } 137 return; 138 } 139 140 void setData(object data) 141 { 142 if(format() == EXIF_FORMAT_ASCII) 143 { 144 extract<std::string> xstr(data); 145 if(xstr.check()) 146 { 147 std::string s= xstr(); 148 if(entry_->data) 149 free(entry_->data); 150 entry_->components= s.size(); 151 //std::cerr << "assigning " << s.size() << "-character string..\n"; 152 entry_->size= 153 exif_format_get_size(format()) * entry_->components; 154 entry_->data= (unsigned char *)malloc(entry_->size); 155 memcpy(entry_->data, s.data(), entry_->size); 156 entry_->data[entry_->size]= 0; 157 } 158 else 159 { 160 PyErr_SetString(PyExc_TypeError, 161 "invalid assignment to data of ASCII format entry: string expected"); 162 throw_error_already_set(); 163 } 164 } 165 else 166 { 167 if(components()==1) 168 setComponent(0, data); 169 else 170 { 171 extract<list> xlist(data); 172 if(xlist.check()) 173 { 174 list l= xlist(); 175 for(unsigned i=0; i<components(); ++i) 176 setComponent(i, l[i]); 177 } 178 else 179 { 180 PyErr_SetString(PyExc_TypeError, 181 "invalid assignment to data of entry with more than one component: list expected"); 182 throw_error_already_set(); 183 } 184 } 185 } 186 } 187}; 188 189struct PythonContent : public Exif::Content 190{ 191 typedef WrappedObjectIterator<PythonEntry, ExifEntry *> iterator; 192 193 PythonContent() {} 194 PythonContent(Exif::Content const &other) : Exif::Content(other) {} 195 196 PythonEntry entry(object index) 197 { 198 // TODO: use Exif::Content::entry() functions 199 200 extract<ExifTag> xtag(index); 201 if(xtag.check()) 202 { 203 ExifTag index= xtag(); 204 for(unsigned int i=0; i<size(); i++) 205 { 206 if(content_->entries[i]->tag == index) 207 return Exif::Entry(content_->entries[i]); 208 } 209 PyErr_SetString(PyExc_KeyError, 210 "tag not present in IFD content"); 211 throw_error_already_set(); 212 } 213 extract<int> xint(index); 214 if(xint.check()) 215 { 216 int index= xint(); 217 if((index>=0) && (index<(long)size())) 218 return Exif::Entry(content_->entries[index]); 219 if((index<0) && (index>=-(long)size())) 220 return Exif::Entry(content_->entries[size()+index]); 221 PyErr_SetString(PyExc_IndexError, 222 "invalid integer index into IFD content"); 223 throw_error_already_set(); 224 } 225 PyErr_SetString(PyExc_TypeError, 226 "invalid index into EXIF data (integer or IFD expected)"); 227 throw_error_already_set(); 228 return Exif::Entry(); // never reached 229 } 230 231 iterator __iter__() 232 { 233 // FIXME: the public API is exif_content_foreach, 234 // relying on memory layout here! 235 return iterator(content_->entries, 236 content_->entries + content_->count); 237 } 238}; 239 240struct PythonData : public Exif::Data 241{ 242 typedef WrappedObjectIterator<PythonContent, ExifContent *> iterator; 243 bool success_; 244 245 PythonData() {} 246 PythonData(const char *path) 247 : Exif::Data(path, &success_) 248 { 249 if(!success_) 250 { 251 PyErr_SetFromErrno(PyExc_IOError); 252 //PyErr_SetString(PyExc_IOError, ""); 253 throw_error_already_set(); 254 } 255 } 256 PythonData(const unsigned char *data, 257 unsigned int size) : Exif::Data(data, size) {} 258 PythonData(Exif::Data const &other) : Exif::Data(other) {} 259 260 PythonContent ifdContent(object index) 261 { 262 extract<ExifIfd> xifd(index); 263 if(xifd.check()) 264 { 265 ExifIfd index= xifd(); 266 if(index<EXIF_IFD_COUNT) 267 return Exif::Content(data_->ifd[index]); 268 PyErr_SetString(PyExc_IndexError, 269 "invalid IFD index into EXIF data"); 270 throw_error_already_set(); 271 } 272 extract<int> xint(index); 273 if(xint.check()) 274 { 275 int index= xint(); 276 if((index>=0) && (index<(long)size())) 277 return Exif::Content(data_->ifd[index]); 278 if((index<0) && (index>=-(long)size())) 279 return Exif::Content(data_->ifd[size()+index]); 280 PyErr_SetString(PyExc_IndexError, 281 "invalid integer index into EXIF data"); 282 throw_error_already_set(); 283 } 284 PyErr_SetString(PyExc_TypeError, 285 "invalid index into EXIF data (integer or IFD expected)"); 286 throw_error_already_set(); 287 return Exif::Content(); // never reached 288 } 289 290 iterator __iter__() 291 { 292 return iterator(data_->ifd, data_->ifd + EXIF_IFD_COUNT); 293 } 294}; 295 296template<class Rational, class Component> 297struct RationalConverter 298{ 299 RationalConverter() 300 { 301 converter::registry::insert(&convertible, &construct, 302 type_id<Rational>()); 303 } 304 305 static void* convertible(PyObject* obj) 306 { 307 extract<tuple> xtup(obj); 308 if(xtup.check()) 309 { 310 tuple t= xtup(); 311 if((t.attr("__len__")() == 2) && 312 extract<Component>(t[0]).check() && 313 extract<Component>(t[1]).check()) 314 { 315 Rational *result = new Rational; 316 result->numerator = extract<Component>(t[0])(); 317 result->denominator = extract<Component>(t[1])(); 318 return result; 319 } 320 } 321 return NULL; 322 } 323 324 static void construct(PyObject* obj, converter::rvalue_from_python_stage1_data* data) 325 { 326 Rational const* r = 327 static_cast<Rational*>(data->convertible); 328 void* storage = 329 ((converter::rvalue_from_python_storage<Rational>*)data)->storage.bytes; 330 new (storage) Rational(); 331 ((Rational*)storage)->numerator = r->numerator; 332 ((Rational*)storage)->denominator = r->denominator; 333 data->convertible = storage; 334 delete r; 335 } 336 337 static PyObject *convert(Rational r) 338 { 339 tuple t= make_tuple(r.numerator, r.denominator); 340 PyObject *result= t.ptr(); 341 Py_INCREF(result); 342 return result; 343 } 344}; 345 346BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(entrydumps, Exif::Entry::dump, 0, 1) 347BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(contentdumps, Exif::Content::dump, 0, 1) 348 349BOOST_PYTHON_MODULE(exif) 350{ 351 RationalConverter<ExifRational, ExifLong>(); 352 RationalConverter<ExifSRational, ExifSLong>(); 353 to_python_converter<ExifRational, 354 RationalConverter<ExifRational, ExifLong> >(); 355 to_python_converter<ExifSRational, 356 RationalConverter<ExifSRational, ExifSLong> >(); 357 358 enum_<ExifByteOrder>("ByteOrder") 359 .value("MOTOROLA", EXIF_BYTE_ORDER_MOTOROLA) 360 .value("INTEL", EXIF_BYTE_ORDER_INTEL); 361 362 def("name", &exif_byte_order_get_name); 363 364 enum_<ExifIfd>("IFD") 365 .value("ZERO", EXIF_IFD_0) 366 .value("ONE", EXIF_IFD_1) 367 .value("EXIF", EXIF_IFD_EXIF) 368 .value("GPS", EXIF_IFD_GPS) 369 .value("INTEROPERABILITY", EXIF_IFD_INTEROPERABILITY); 370 //.value("COUNT", EXIF_IFD_COUNT) 371 372 def("name", &exif_ifd_get_name); 373 374 enum_<ExifFormat>("Format") 375 .value("BYTE", EXIF_FORMAT_BYTE) 376 .value("ASCII", EXIF_FORMAT_ASCII) 377 .value("SHORT", EXIF_FORMAT_SHORT) 378 .value("LONG", EXIF_FORMAT_LONG) 379 .value("RATIONAL", EXIF_FORMAT_RATIONAL) 380 .value("UNDEFINED", EXIF_FORMAT_UNDEFINED) 381 .value("SLONG", EXIF_FORMAT_SLONG) 382 .value("SRATIONAL", EXIF_FORMAT_SRATIONAL); 383 384 def("name", &exif_format_get_name); 385 def("size", &exif_format_get_size); 386 387 enum_<ExifTag>("Tag") 388 .value("INTEROPERABILITY_INDEX", EXIF_TAG_INTEROPERABILITY_INDEX) 389 .value("INTEROPERABILITY_VERSION", EXIF_TAG_INTEROPERABILITY_VERSION) 390 .value("IMAGE_WIDTH", EXIF_TAG_IMAGE_WIDTH) 391 .value("IMAGE_LENGTH", EXIF_TAG_IMAGE_LENGTH) 392 .value("BITS_PER_SAMPLE", EXIF_TAG_BITS_PER_SAMPLE) 393 .value("COMPRESSION", EXIF_TAG_COMPRESSION) 394 .value("PHOTOMETRIC_INTERPRETATION", EXIF_TAG_PHOTOMETRIC_INTERPRETATION) 395 .value("FILL_ORDER", EXIF_TAG_FILL_ORDER) 396 .value("DOCUMENT_NAME", EXIF_TAG_DOCUMENT_NAME) 397 .value("IMAGE_DESCRIPTION", EXIF_TAG_IMAGE_DESCRIPTION) 398 .value("MAKE", EXIF_TAG_MAKE) 399 .value("MODEL", EXIF_TAG_MODEL) 400 .value("STRIP_OFFSETS", EXIF_TAG_STRIP_OFFSETS) 401 .value("ORIENTATION", EXIF_TAG_ORIENTATION) 402 .value("SAMPLES_PER_PIXEL", EXIF_TAG_SAMPLES_PER_PIXEL) 403 .value("ROWS_PER_STRIP", EXIF_TAG_ROWS_PER_STRIP) 404 .value("STRIP_BYTE_COUNTS", EXIF_TAG_STRIP_BYTE_COUNTS) 405 .value("X_RESOLUTION", EXIF_TAG_X_RESOLUTION) 406 .value("Y_RESOLUTION", EXIF_TAG_Y_RESOLUTION) 407 .value("PLANAR_CONFIGURATION", EXIF_TAG_PLANAR_CONFIGURATION) 408 .value("RESOLUTION_UNIT", EXIF_TAG_RESOLUTION_UNIT) 409 .value("TRANSFER_FUNCTION", EXIF_TAG_TRANSFER_FUNCTION) 410 .value("SOFTWARE", EXIF_TAG_SOFTWARE) 411 .value("DATE_TIME", EXIF_TAG_DATE_TIME) 412 .value("ARTIST", EXIF_TAG_ARTIST) 413 .value("WHITE_POINT", EXIF_TAG_WHITE_POINT) 414 .value("PRIMARY_CHROMATICITIES", EXIF_TAG_PRIMARY_CHROMATICITIES) 415 .value("TRANSFER_RANGE", EXIF_TAG_TRANSFER_RANGE) 416 .value("JPEG_PROC", EXIF_TAG_JPEG_PROC) 417 .value("JPEG_INTERCHANGE_FORMAT", EXIF_TAG_JPEG_INTERCHANGE_FORMAT) 418 .value("JPEG_INTERCHANGE_FORMAT_LENGTH", EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH) 419 .value("YCBCR_COEFFICIENTS", EXIF_TAG_YCBCR_COEFFICIENTS) 420 .value("YCBCR_SUB_SAMPLING", EXIF_TAG_YCBCR_SUB_SAMPLING) 421 .value("YCBCR_POSITIONING", EXIF_TAG_YCBCR_POSITIONING) 422 .value("REFERENCE_BLACK_WHITE", EXIF_TAG_REFERENCE_BLACK_WHITE) 423 .value("RELATED_IMAGE_FILE_FORMAT", EXIF_TAG_RELATED_IMAGE_FILE_FORMAT) 424 .value("RELATED_IMAGE_WIDTH", EXIF_TAG_RELATED_IMAGE_WIDTH) 425 .value("RELATED_IMAGE_LENGTH", EXIF_TAG_RELATED_IMAGE_LENGTH) 426 .value("CFA_REPEAT_PATTERN_DIM", EXIF_TAG_CFA_REPEAT_PATTERN_DIM) 427 .value("CFA_PATTERN", EXIF_TAG_CFA_PATTERN) 428 .value("BATTERY_LEVEL", EXIF_TAG_BATTERY_LEVEL) 429 .value("COPYRIGHT", EXIF_TAG_COPYRIGHT) 430 .value("EXPOSURE_TIME", EXIF_TAG_EXPOSURE_TIME) 431 .value("FNUMBER", EXIF_TAG_FNUMBER) 432 .value("IPTC_NAA", EXIF_TAG_IPTC_NAA) 433 .value("EXIF_IFD_POINTER", EXIF_TAG_EXIF_IFD_POINTER) 434 .value("INTER_COLOR_PROFILE", EXIF_TAG_INTER_COLOR_PROFILE) 435 .value("EXPOSURE_PROGRAM", EXIF_TAG_EXPOSURE_PROGRAM) 436 .value("SPECTRAL_SENSITIVITY", EXIF_TAG_SPECTRAL_SENSITIVITY) 437 .value("GPS_INFO_IFD_POINTER", EXIF_TAG_GPS_INFO_IFD_POINTER) 438 .value("ISO_SPEED_RATINGS", EXIF_TAG_ISO_SPEED_RATINGS) 439 .value("OECF", EXIF_TAG_OECF) 440 .value("EXIF_VERSION", EXIF_TAG_EXIF_VERSION) 441 .value("DATE_TIME_ORIGINAL", EXIF_TAG_DATE_TIME_ORIGINAL) 442 .value("DATE_TIME_DIGITIZED", EXIF_TAG_DATE_TIME_DIGITIZED) 443 .value("COMPONENTS_CONFIGURATION", EXIF_TAG_COMPONENTS_CONFIGURATION) 444 .value("COMPRESSED_BITS_PER_PIXEL", EXIF_TAG_COMPRESSED_BITS_PER_PIXEL) 445 .value("SHUTTER_SPEED_VALUE", EXIF_TAG_SHUTTER_SPEED_VALUE) 446 .value("APERTURE_VALUE", EXIF_TAG_APERTURE_VALUE) 447 .value("BRIGHTNESS_VALUE", EXIF_TAG_BRIGHTNESS_VALUE) 448 .value("EXPOSURE_BIAS_VALUE", EXIF_TAG_EXPOSURE_BIAS_VALUE) 449 .value("MAX_APERTURE_VALUE", EXIF_TAG_MAX_APERTURE_VALUE) 450 .value("SUBJECT_DISTANCE", EXIF_TAG_SUBJECT_DISTANCE) 451 .value("METERING_MODE", EXIF_TAG_METERING_MODE) 452 .value("LIGHT_SOURCE", EXIF_TAG_LIGHT_SOURCE) 453 .value("FLASH", EXIF_TAG_FLASH) 454 .value("FOCAL_LENGTH", EXIF_TAG_FOCAL_LENGTH) 455 .value("SUBJECT_AREA", EXIF_TAG_SUBJECT_AREA) 456 .value("MAKER_NOTE", EXIF_TAG_MAKER_NOTE) 457 .value("USER_COMMENT", EXIF_TAG_USER_COMMENT) 458 .value("SUBSEC_TIME", EXIF_TAG_SUBSEC_TIME) 459 .value("SUB_SEC_TIME_ORIGINAL", EXIF_TAG_SUB_SEC_TIME_ORIGINAL) 460 .value("SUB_SEC_TIME_DIGITIZED", EXIF_TAG_SUB_SEC_TIME_DIGITIZED) 461 .value("FLASH_PIX_VERSION", EXIF_TAG_FLASH_PIX_VERSION) 462 .value("COLOR_SPACE", EXIF_TAG_COLOR_SPACE) 463 .value("PIXEL_X_DIMENSION", EXIF_TAG_PIXEL_X_DIMENSION) 464 .value("PIXEL_Y_DIMENSION", EXIF_TAG_PIXEL_Y_DIMENSION) 465 .value("RELATED_SOUND_FILE", EXIF_TAG_RELATED_SOUND_FILE) 466 .value("INTEROPERABILITY_IFD_POINTER", EXIF_TAG_INTEROPERABILITY_IFD_POINTER) 467 .value("FLASH_ENERGY", EXIF_TAG_FLASH_ENERGY) 468 .value("SPATIAL_FREQUENCY_RESPONSE", EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE) 469 .value("FOCAL_PLANE_X_RESOLUTION", EXIF_TAG_FOCAL_PLANE_X_RESOLUTION) 470 .value("FOCAL_PLANE_Y_RESOLUTION", EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION) 471 .value("FOCAL_PLANE_RESOLUTION_UNIT", EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT) 472 .value("SUBJECT_LOCATION", EXIF_TAG_SUBJECT_LOCATION) 473 .value("EXPOSURE_INDEX", EXIF_TAG_EXPOSURE_INDEX) 474 .value("SENSING_METHOD", EXIF_TAG_SENSING_METHOD) 475 .value("FILE_SOURCE", EXIF_TAG_FILE_SOURCE) 476 .value("SCENE_TYPE", EXIF_TAG_SCENE_TYPE) 477 .value("NEW_CFA_PATTERN", EXIF_TAG_NEW_CFA_PATTERN) 478 .value("CUSTOM_RENDERED", EXIF_TAG_CUSTOM_RENDERED) 479 .value("EXPOSURE_MODE", EXIF_TAG_EXPOSURE_MODE) 480 .value("WHITE_BALANCE", EXIF_TAG_WHITE_BALANCE) 481 .value("DIGITAL_ZOOM_RATIO", EXIF_TAG_DIGITAL_ZOOM_RATIO) 482 .value("FOCAL_LENGTH_IN_35MM_FILM", EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM) 483 .value("SCENE_CAPTURE_TYPE", EXIF_TAG_SCENE_CAPTURE_TYPE) 484 .value("GAIN_CONTROL", EXIF_TAG_GAIN_CONTROL) 485 .value("CONTRAST", EXIF_TAG_CONTRAST) 486 .value("SATURATION", EXIF_TAG_SATURATION) 487 .value("SHARPNESS", EXIF_TAG_SHARPNESS) 488 .value("DEVICE_SETTING_DESCRIPTION", EXIF_TAG_DEVICE_SETTING_DESCRIPTION) 489 .value("SUBJECT_DISTANCE_RANGE", EXIF_TAG_SUBJECT_DISTANCE_RANGE) 490 .value("IMAGE_UNIQUE_ID", EXIF_TAG_IMAGE_UNIQUE_ID); 491 492 def("name", &exif_tag_get_name); 493 def("title", &exif_tag_get_title); 494 def("description", &exif_tag_get_description); 495 496 class_<PythonEntry>("Entry") 497 .add_property("tag", &Exif::Entry::tag) 498 .add_property("format", &Exif::Entry::format) 499 .add_property("components", &Exif::Entry::components) 500 .add_property("data", &PythonEntry::data, 501 &PythonEntry::setData) 502 .def("value", &Exif::Entry::value) 503 .def("briefValue", &Exif::Entry::briefValue) 504 .def("dump", &Exif::Entry::dump);//, entrydumps()); 505 506 class_<PythonContent::iterator>("ContentIterator", no_init) 507 .def("next", &PythonContent::iterator::next); 508 class_<PythonContent>("Content") 509 .def("__len__", &Exif::Content::size) 510 .def("__getitem__", &PythonContent::entry) 511 .def("__iter__", &PythonContent::__iter__) 512 .def("dump", &Exif::Content::dump);//, contentdumps()); 513 514 class_<PythonData::iterator>("DataIterator", no_init) 515 .def("next", &PythonData::iterator::next); 516 class_<PythonData>("Data") 517 .def(init<const char *>()) 518 .def(init<const unsigned char *, unsigned int>()) 519 .def("__len__", &Exif::Data::size) 520 .def("__getitem__", &PythonData::ifdContent) 521 .def("__iter__", &PythonData::__iter__) 522 .def("byteOrder", &Exif::Data::byteOrder) 523 .def("dump", &Exif::Data::dump); 524} 525