8 #include <exiv2/image.hpp>
9 #include <exiv2/exif.hpp>
12 #include <sys/types.h>
18 #include <exiv2/tiffparser.hpp>
19 #include <exiv2/tiffcomposite.hpp>
20 #include <exiv2/tiffvisitor.hpp>
21 #include <exiv2/tiffimage.hpp>
22 #include <exiv2/cr2image.hpp>
23 #include <exiv2/orfimage.hpp>
24 #include <exiv2/rafimage.hpp>
25 #include <exiv2/futils.hpp>
37 Exiv2::ExifData exifData;
38 Exiv2::ExifData::const_iterator exifIter; /* for exif_get_next_item */
39 Exiv2::IptcData iptcData;
40 Exiv2::IptcData::const_iterator iptcIter; /* for exif_get_next_item */
41 Exiv2::XmpData xmpData;
42 Exiv2::XmpData::const_iterator xmpIter; /* for exif_get_next_item */
44 _ExifData(gchar *path, gint parse_color_profile)
46 Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path);
47 g_assert (image.get() != 0);
48 image->readMetadata();
49 exifData = image->exifData();
50 iptcData = image->iptcData();
51 xmpData = image->xmpData();
58 ExifData *exif_read(gchar *path, gint parse_color_profile)
60 printf("exif %s\n", path);
62 return new ExifData(path, parse_color_profile);
64 catch (Exiv2::AnyError& e) {
65 std::cout << "Caught Exiv2 exception '" << e << "'\n";
71 void exif_free(ExifData *exif)
77 ExifItem *exif_get_item(ExifData *exif, const gchar *key)
80 Exiv2::Metadatum *item;
82 Exiv2::ExifKey ekey(key);
83 Exiv2::ExifData::iterator pos = exif->exifData.findKey(ekey);
84 if (pos == exif->exifData.end()) return NULL;
87 catch (Exiv2::AnyError& e) {
89 Exiv2::IptcKey ekey(key);
90 Exiv2::IptcData::iterator pos = exif->iptcData.findKey(ekey);
91 if (pos == exif->iptcData.end()) return NULL;
94 catch (Exiv2::AnyError& e) {
95 Exiv2::XmpKey ekey(key);
96 Exiv2::XmpData::iterator pos = exif->xmpData.findKey(ekey);
97 if (pos == exif->xmpData.end()) return NULL;
101 return (ExifItem *)item;
103 catch (Exiv2::AnyError& e) {
104 std::cout << "Caught Exiv2 exception '" << e << "'\n";
110 ExifItem *exif_get_first_item(ExifData *exif)
113 exif->exifIter = exif->exifData.begin();
114 exif->iptcIter = exif->iptcData.begin();
115 exif->xmpIter = exif->xmpData.begin();
116 if (exif->exifIter != exif->exifData.end())
118 const Exiv2::Metadatum *item = &*exif->exifIter;
120 return (ExifItem *)item;
122 if (exif->iptcIter != exif->iptcData.end())
124 const Exiv2::Metadatum *item = &*exif->iptcIter;
126 return (ExifItem *)item;
128 if (exif->xmpIter != exif->xmpData.end())
130 const Exiv2::Metadatum *item = &*exif->xmpIter;
132 return (ExifItem *)item;
137 catch (Exiv2::AnyError& e) {
138 std::cout << "Caught Exiv2 exception '" << e << "'\n";
143 ExifItem *exif_get_next_item(ExifData *exif)
146 if (exif->exifIter != exif->exifData.end())
148 const Exiv2::Metadatum *item = &*exif->exifIter;
150 return (ExifItem *)item;
152 if (exif->iptcIter != exif->iptcData.end())
154 const Exiv2::Metadatum *item = &*exif->iptcIter;
156 return (ExifItem *)item;
158 if (exif->xmpIter != exif->xmpData.end())
160 const Exiv2::Metadatum *item = &*exif->xmpIter;
162 return (ExifItem *)item;
166 catch (Exiv2::AnyError& e) {
167 std::cout << "Caught Exiv2 exception '" << e << "'\n";
172 char *exif_item_get_tag_name(ExifItem *item)
175 if (!item) return NULL;
176 return g_strdup(((Exiv2::Metadatum *)item)->key().c_str());
178 catch (Exiv2::AnyError& e) {
179 std::cout << "Caught Exiv2 exception '" << e << "'\n";
184 guint exif_item_get_tag_id(ExifItem *item)
188 return ((Exiv2::Metadatum *)item)->tag();
190 catch (Exiv2::AnyError& e) {
191 std::cout << "Caught Exiv2 exception '" << e << "'\n";
196 guint exif_item_get_elements(ExifItem *item)
200 return ((Exiv2::Metadatum *)item)->count();
202 catch (Exiv2::AnyError& e) {
203 std::cout << "Caught Exiv2 exception '" << e << "'\n";
208 char *exif_item_get_data(ExifItem *item, guint *data_len)
212 char *exif_item_get_description(ExifItem *item)
215 if (!item) return NULL;
216 return g_strdup(((Exiv2::Metadatum *)item)->tagLabel().c_str());
218 catch (std::exception& e) {
219 // std::cout << "Caught Exiv2 exception '" << e << "'\n";
225 invalidTypeId, unsignedByte, asciiString, unsignedShort,
226 unsignedLong, unsignedRational, signedByte, undefined,
227 signedShort, signedLong, signedRational, string,
228 date, time, comment, directory,
229 xmpText, xmpAlt, xmpBag, xmpSeq,
233 static guint format_id_trans_tbl [] = {
235 EXIF_FORMAT_BYTE_UNSIGNED,
237 EXIF_FORMAT_SHORT_UNSIGNED,
238 EXIF_FORMAT_LONG_UNSIGNED,
239 EXIF_FORMAT_RATIONAL_UNSIGNED,
241 EXIF_FORMAT_UNDEFINED,
244 EXIF_FORMAT_RATIONAL,
248 EXIF_FORMAT_UNDEFINED,
257 guint exif_item_get_format_id(ExifItem *item)
260 if (!item) return EXIF_FORMAT_UNKNOWN;
261 guint id = ((Exiv2::Metadatum *)item)->typeId();
262 if (id >= (sizeof(format_id_trans_tbl) / sizeof(format_id_trans_tbl[0])) ) return EXIF_FORMAT_UNKNOWN;
263 return format_id_trans_tbl[id];
265 catch (Exiv2::AnyError& e) {
266 std::cout << "Caught Exiv2 exception '" << e << "'\n";
267 return EXIF_FORMAT_UNKNOWN;
271 const char *exif_item_get_format_name(ExifItem *item, gint brief)
274 if (!item) return NULL;
275 return ((Exiv2::Metadatum *)item)->typeName();
277 catch (Exiv2::AnyError& e) {
278 std::cout << "Caught Exiv2 exception '" << e << "'\n";
284 gchar *exif_item_get_data_as_text(ExifItem *item)
287 if (!item) return NULL;
288 // std::stringstream str; // does not work with Exiv2::Metadatum because operator<< is not virtual
289 // str << *((Exiv2::Metadatum *)item);
290 // return g_strdup(str.str().c_str());
291 return g_strdup(((Exiv2::Metadatum *)item)->toString().c_str());
293 catch (Exiv2::AnyError& e) {
299 gint exif_item_get_integer(ExifItem *item, gint *value)
303 *value = ((Exiv2::Metadatum *)item)->toLong();
306 catch (Exiv2::AnyError& e) {
307 std::cout << "Caught Exiv2 exception '" << e << "'\n";
312 ExifRational *exif_item_get_rational(ExifItem *item, gint *sign)
315 if (!item) return NULL;
316 Exiv2::Rational v = ((Exiv2::Metadatum *)item)->toRational();
317 static ExifRational ret;
322 catch (Exiv2::AnyError& e) {
323 std::cout << "Caught Exiv2 exception '" << e << "'\n";
328 const gchar *exif_get_tag_description_by_key(const gchar *key)
331 Exiv2::ExifKey ekey(key);
332 return Exiv2::ExifTags::tagLabel(ekey.tag(), ekey.ifdId ());
334 catch (Exiv2::AnyError& e) {
335 std::cout << "Caught Exiv2 exception '" << e << "'\n";
343 /* This is a dirty hack to support raw file preview, bassed on
344 tiffparse.cpp from Exiv2 examples */
352 const Exiv2::Value *find(uint16_t tag, uint16_t group);
354 unsigned long preview_offset();
358 Exiv2::TiffComponent::AutoPtr rootDir;
359 Exiv2::byte *map_data;
361 unsigned long offset;
364 using namespace Exiv2;
366 RawFile::RawFile(int fd) : map_data(NULL), map_len(0), offset(0)
369 if (fstat(fd, &st) == -1)
373 map_len = st.st_size;
374 map_data = (Exiv2::byte *) mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0);
375 if (map_data == MAP_FAILED)
379 type = Exiv2::ImageFactory::getType(map_data, map_len);
381 TiffHeaderBase *tiffHeader;
383 case Exiv2::ImageType::tiff:
384 tiffHeader = new TiffHeade2();
386 case Exiv2::ImageType::cr2:
387 tiffHeader = new Cr2Header();
389 case Exiv2::ImageType::orf:
390 tiffHeader = new OrfHeader();
392 case Exiv2::ImageType::raf:
393 if (map_len < 84 + 4) throw Error(14);
394 offset = getULong(map_data + 84, bigEndian);
398 throw Error(3, "RAW");
401 // process tiff-like formats
402 if (!tiffHeader->read(map_data, map_len)) throw Error(3, "TIFF");
404 TiffCompFactoryFct createFct = TiffCreator::create;
406 rootDir = createFct(Tag::root, Group::none);
407 if (0 == rootDir.get()) {
408 throw Error(1, "No root element defined in TIFF structure");
410 rootDir->setStart(map_data + tiffHeader->offset());
412 TiffRwState::AutoPtr state(
413 new TiffRwState(tiffHeader->byteOrder(), 0, createFct));
415 TiffReader reader(map_data,
420 rootDir->accept(reader);
427 if (map_data && munmap(map_data, map_len) == -1)
429 printf("Failed to unmap file \n");
433 const Value * RawFile::find(uint16_t tag, uint16_t group)
435 printf("%04x %04x\n", tag, group);
436 TiffFinder finder(tag, group);
437 rootDir->accept(finder);
438 TiffEntryBase* te = dynamic_cast<TiffEntryBase*>(finder.result());
445 unsigned long RawFile::preview_offset()
448 if (offset) return offset;
450 if (type == Exiv2::ImageType::cr2)
452 val = find(0x111, Group::ifd0);
453 if (val) return val->toLong();
458 val = find(0x201, Group::sub0_0);
459 if (val) return val->toLong();
461 val = find(0x201, Group::ifd0);
462 if (val) return val->toLong();
464 val = find(0x201, Group::ignr); // for PEF files, originally it was probably ifd2
465 if (val) return val->toLong();
467 val = find(0x111, Group::sub0_1); // dng
468 if (val) return val->toLong();
474 const static char *raw_ext_list[] = { ".cr2", ".nef", ".pef", ".arw", NULL };
476 extern "C" gint format_raw_img_exif_offsets_fd(int fd, const gchar *path,
477 unsigned char *header_data, const guint header_len,
478 guint *image_offset, guint *exif_offset)
481 unsigned long offset;
483 /* given image pathname, first do simple (and fast) file extension test */
490 ext = strrchr(path, '.');
491 if (!ext) return FALSE;
493 for (i = 0; raw_ext_list[i]; i++)
495 if (strcasecmp(raw_ext_list[i], ext) == 0)
502 if (!match) return FALSE;
508 offset = rf.preview_offset();
510 catch (Exiv2::AnyError& e) {
511 std::cout << "Caught Exiv2 exception '" << e << "'\n";
517 *image_offset = offset;
518 if (lseek(fd, *image_offset, SEEK_SET) != *image_offset)
520 printf("Failed to seek to embedded image\n");
523 if (*exif_offset) *exif_offset = 0;