49b8e07c9eb0ef4dba8f5a913840f3bbd03eeec5
[geeqie.git] / src / exiv2.cc
1 /*
2  * Copyright (C) 2008 - 2016 The Geeqie Team
3  *
4  * Author: Vladimir Nadvornik
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "config.h"
22
23 #ifdef HAVE_EXIV2
24
25 #include <exiv2/image.hpp>
26 #include <exiv2/exif.hpp>
27 #include <iostream>
28 #include <string>
29
30 // EXIV2_TEST_VERSION is defined in Exiv2 0.15 and newer.
31 #ifndef EXIV2_TEST_VERSION
32 # define EXIV2_TEST_VERSION(major,minor,patch) \
33         ( EXIV2_VERSION >= EXIV2_MAKE_VERSION(major,minor,patch) )
34 #endif
35
36
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <sys/mman.h>
42
43 #if !EXIV2_TEST_VERSION(0,17,90)
44 #include <exiv2/tiffparser.hpp>
45 #include <exiv2/tiffcomposite.hpp>
46 #include <exiv2/tiffvisitor.hpp>
47 #include <exiv2/tiffimage.hpp>
48 #include <exiv2/cr2image.hpp>
49 #include <exiv2/crwimage.hpp>
50 #if EXIV2_TEST_VERSION(0,16,0)
51 #include <exiv2/orfimage.hpp>
52 #endif
53 #if EXIV2_TEST_VERSION(0,13,0)
54 #include <exiv2/rafimage.hpp>
55 #endif
56 #include <exiv2/futils.hpp>
57 #else
58 #include <exiv2/preview.hpp>
59 #endif
60
61 #if EXIV2_TEST_VERSION(0,17,0)
62 #include <exiv2/convert.hpp>
63 #include <exiv2/xmpsidecar.hpp>
64 #endif
65
66 extern "C" {
67 #include <glib.h>
68
69 #include "main.h"
70 #include "exif.h"
71
72 #include "filefilter.h"
73 #include "ui_fileops.h"
74
75 #include "misc.h"
76 }
77
78 typedef struct _AltKey AltKey;
79
80 struct _AltKey
81 {
82         const gchar *xmp_key;
83         const gchar *exif_key;
84         const gchar *iptc_key;
85 };
86
87 /* this is a list of keys that should be converted, even with the older Exiv2 which does not support it directly */
88 static const AltKey alt_keys[] = {
89         {"Xmp.tiff.Orientation",                "Exif.Image.Orientation",       NULL},
90         {"Xmp.dc.title",                        NULL,                           "Iptc.Application2.ObjectName"          },
91         {"Xmp.photoshop.Urgency",               NULL,                           "Iptc.Application2.Urgency"             },
92         {"Xmp.photoshop.Category",              NULL,                           "Iptc.Application2.Category"            },
93         {"Xmp.photoshop.SupplementalCategory",  NULL,                           "Iptc.Application2.SuppCategory"        },
94         {"Xmp.dc.subject",                      NULL,                           "Iptc.Application2.Keywords"            },
95         {"Xmp.iptc.Location",                   NULL,                           "Iptc.Application2.LocationName"        },
96         {"Xmp.photoshop.Instruction",           NULL,                           "Iptc.Application2.SpecialInstructions" },
97         {"Xmp.photoshop.DateCreated",           NULL,                           "Iptc.Application2.DateCreated"         },
98         {"Xmp.dc.creator",                      NULL,                           "Iptc.Application2.Byline"              },
99         {"Xmp.photoshop.AuthorsPosition",       NULL,                           "Iptc.Application2.BylineTitle"         },
100         {"Xmp.photoshop.City",                  NULL,                           "Iptc.Application2.City"                },
101         {"Xmp.photoshop.State",                 NULL,                           "Iptc.Application2.ProvinceState"       },
102         {"Xmp.iptc.CountryCode",                NULL,                           "Iptc.Application2.CountryCode"         },
103         {"Xmp.photoshop.Country",               NULL,                           "Iptc.Application2.CountryName"         },
104         {"Xmp.photoshop.TransmissionReference", NULL,                           "Iptc.Application2.TransmissionReference"},
105         {"Xmp.photoshop.Headline",              NULL,                           "Iptc.Application2.Headline"            },
106         {"Xmp.photoshop.Credit",                NULL,                           "Iptc.Application2.Credit"              },
107         {"Xmp.photoshop.Source",                NULL,                           "Iptc.Application2.Source"              },
108         {"Xmp.dc.rights",                       NULL,                           "Iptc.Application2.Copyright"           },
109         {"Xmp.dc.description",                  NULL,                           "Iptc.Application2.Caption"             },
110         {"Xmp.photoshop.CaptionWriter",         NULL,                           "Iptc.Application2.Writer"              },
111         {NULL, NULL, NULL}
112         };
113
114 static void _debug_exception(const char* file,
115                              int line,
116                              const char* func,
117                              Exiv2::AnyError& e)
118 {
119         gchar *str = g_locale_from_utf8(e.what(), -1, NULL, NULL, NULL);
120         DEBUG_1("%s:%d:%s:Exiv2: %s", file, line, func, str);
121         g_free(str);
122 }
123
124 #define debug_exception(e) _debug_exception(__FILE__, __LINE__, __func__, e)
125
126 struct _ExifData
127 {
128         Exiv2::ExifData::const_iterator exifIter; /* for exif_get_next_item */
129         Exiv2::IptcData::const_iterator iptcIter; /* for exif_get_next_item */
130 #if EXIV2_TEST_VERSION(0,16,0)
131         Exiv2::XmpData::const_iterator xmpIter; /* for exif_get_next_item */
132 #endif
133
134         virtual ~_ExifData()
135         {
136         }
137
138         virtual void writeMetadata(gchar *path = NULL)
139         {
140                 g_critical("Unsupported method of writing metadata");
141         }
142
143         virtual ExifData *original()
144         {
145                 return NULL;
146         }
147
148         virtual Exiv2::Image *image() = 0;
149
150         virtual Exiv2::ExifData &exifData() = 0;
151
152         virtual Exiv2::IptcData &iptcData() = 0;
153
154 #if EXIV2_TEST_VERSION(0,16,0)
155         virtual Exiv2::XmpData &xmpData() = 0;
156 #endif
157
158         virtual void add_jpeg_color_profile(unsigned char *cp_data, guint cp_length) = 0;
159
160         virtual guchar *get_jpeg_color_profile(guint *data_len) = 0;
161 };
162
163 // This allows read-only access to the original metadata
164 struct _ExifDataOriginal : public _ExifData
165 {
166 protected:
167         Exiv2::Image::AutoPtr image_;
168
169         /* the icc profile in jpeg is not technically exif - store it here */
170         unsigned char *cp_data_;
171         guint cp_length_;
172         gboolean valid_;
173         gchar *pathl_;
174
175         Exiv2::ExifData emptyExifData_;
176         Exiv2::IptcData emptyIptcData_;
177 #if EXIV2_TEST_VERSION(0,16,0)
178         Exiv2::XmpData emptyXmpData_;
179 #endif
180
181 public:
182         _ExifDataOriginal(Exiv2::Image::AutoPtr image)
183         {
184                 cp_data_ = NULL;
185                 cp_length_ = 0;
186                 image_ = image;
187                 valid_ = TRUE;
188         }
189
190         _ExifDataOriginal(gchar *path)
191         {
192                 cp_data_ = NULL;
193                 cp_length_ = 0;
194                 valid_ = TRUE;
195
196                 pathl_ = path_from_utf8(path);
197                 try
198                         {
199                         image_ = Exiv2::ImageFactory::open(pathl_);
200 //                      g_assert (image.get() != 0);
201                         image_->readMetadata();
202
203 #if EXIV2_TEST_VERSION(0,16,0)
204                         if (image_->mimeType() == "application/rdf+xml")
205                                 {
206                                 //Exiv2 sidecar converts xmp to exif and iptc, we don't want it.
207                                 image_->clearExifData();
208                                 image_->clearIptcData();
209                                 }
210 #endif
211
212 #if EXIV2_TEST_VERSION(0,14,0)
213                         if (image_->mimeType() == "image/jpeg")
214                                 {
215                                 /* try to get jpeg color profile */
216                                 Exiv2::BasicIo &io = image_->io();
217                                 gint open = io.isopen();
218                                 if (!open) io.open();
219                                 if (io.isopen())
220                                         {
221                                         unsigned char *mapped = (unsigned char*)io.mmap();
222                                         if (mapped) exif_jpeg_parse_color(this, mapped, io.size());
223                                         io.munmap();
224                                         }
225                                 if (!open) io.close();
226                                 }
227 #endif
228                         }
229                 catch (Exiv2::AnyError& e)
230                         {
231                         valid_ = FALSE;
232                         }
233         }
234
235         virtual ~_ExifDataOriginal()
236         {
237                 if (cp_data_) g_free(cp_data_);
238                 if (pathl_) g_free(pathl_);
239         }
240
241         virtual Exiv2::Image *image()
242         {
243                 if (!valid_) return NULL;
244                 return image_.get();
245         }
246
247         virtual Exiv2::ExifData &exifData ()
248         {
249                 if (!valid_) return emptyExifData_;
250                 return image_->exifData();
251         }
252
253         virtual Exiv2::IptcData &iptcData ()
254         {
255                 if (!valid_) return emptyIptcData_;
256                 return image_->iptcData();
257         }
258
259 #if EXIV2_TEST_VERSION(0,16,0)
260         virtual Exiv2::XmpData &xmpData ()
261         {
262                 if (!valid_) return emptyXmpData_;
263                 return image_->xmpData();
264         }
265 #endif
266
267         virtual void add_jpeg_color_profile(unsigned char *cp_data, guint cp_length)
268         {
269                 if (cp_data_) g_free(cp_data_);
270                 cp_data_ = cp_data;
271                 cp_length_ = cp_length;
272         }
273
274         virtual guchar *get_jpeg_color_profile(guint *data_len)
275         {
276                 if (cp_data_)
277                 {
278                         if (data_len) *data_len = cp_length_;
279                         return (unsigned char *) g_memdup(cp_data_, cp_length_);
280                 }
281                 return NULL;
282         }
283 };
284
285 extern "C" {
286 static void _ExifDataProcessed_update_xmp(gpointer key, gpointer value, gpointer data);
287 }
288
289 // This allows read-write access to the metadata
290 struct _ExifDataProcessed : public _ExifData
291 {
292 protected:
293         _ExifDataOriginal *imageData_;
294         _ExifDataOriginal *sidecarData_;
295
296         Exiv2::ExifData exifData_;
297         Exiv2::IptcData iptcData_;
298 #if EXIV2_TEST_VERSION(0,16,0)
299         Exiv2::XmpData xmpData_;
300 #endif
301
302 public:
303         _ExifDataProcessed(gchar *path, gchar *sidecar_path, GHashTable *modified_xmp)
304         {
305                 imageData_ = new _ExifDataOriginal(path);
306                 sidecarData_ = NULL;
307 #if EXIV2_TEST_VERSION(0,16,0)
308                 if (sidecar_path)
309                         {
310                         sidecarData_ = new _ExifDataOriginal(sidecar_path);
311                         xmpData_ = sidecarData_->xmpData();
312                         }
313                 else
314                         {
315                         xmpData_ = imageData_->xmpData();
316                         }
317
318 #endif
319                 exifData_ = imageData_->exifData();
320                 iptcData_ = imageData_->iptcData();
321 #if EXIV2_TEST_VERSION(0,17,0)
322                 try
323                         {
324                         syncExifWithXmp(exifData_, xmpData_);
325                         }
326                 catch (...)
327                         {
328                         DEBUG_1("Exiv2: Catching bug\n");
329                         }
330 #endif
331                 if (modified_xmp)
332                         {
333                         g_hash_table_foreach(modified_xmp, _ExifDataProcessed_update_xmp, this);
334                         }
335         }
336
337         virtual ~_ExifDataProcessed()
338         {
339                 if (imageData_) delete imageData_;
340                 if (sidecarData_) delete sidecarData_;
341         }
342
343         virtual ExifData *original()
344         {
345                 return imageData_;
346         }
347
348         virtual void writeMetadata(gchar *path = NULL)
349         {
350                 if (!path)
351                         {
352 #if EXIV2_TEST_VERSION(0,17,0)
353                         if (options->metadata.save_legacy_IPTC)
354                                 copyXmpToIptc(xmpData_, iptcData_);
355                         else
356                                 iptcData_.clear();
357
358                         copyXmpToExif(xmpData_, exifData_);
359 #endif
360                         Exiv2::Image *image = imageData_->image();
361
362                         if (!image) Exiv2::Error(21);
363                         image->setExifData(exifData_);
364                         image->setIptcData(iptcData_);
365 #if EXIV2_TEST_VERSION(0,16,0)
366                         image->setXmpData(xmpData_);
367 #endif
368                         image->writeMetadata();
369                         }
370                 else
371                         {
372 #if EXIV2_TEST_VERSION(0,17,0)
373                         gchar *pathl = path_from_utf8(path);;
374
375                         Exiv2::Image::AutoPtr sidecar = Exiv2::ImageFactory::create(Exiv2::ImageType::xmp, pathl);
376
377                         g_free(pathl);
378
379                         sidecar->setXmpData(xmpData_);
380                         sidecar->writeMetadata();
381 #else
382                         throw Exiv2::Error(3, "xmp");
383 #endif
384                         }
385         }
386
387         virtual Exiv2::Image *image()
388         {
389                 return imageData_->image();
390         }
391
392         virtual Exiv2::ExifData &exifData ()
393         {
394                 return exifData_;
395         }
396
397         virtual Exiv2::IptcData &iptcData ()
398         {
399                 return iptcData_;
400         }
401
402 #if EXIV2_TEST_VERSION(0,16,0)
403         virtual Exiv2::XmpData &xmpData ()
404         {
405                 return xmpData_;
406         }
407 #endif
408
409         virtual void add_jpeg_color_profile(unsigned char *cp_data, guint cp_length)
410         {
411                 imageData_->add_jpeg_color_profile(cp_data, cp_length);
412         }
413
414         virtual guchar *get_jpeg_color_profile(guint *data_len)
415         {
416                 return imageData_->get_jpeg_color_profile(data_len);
417         }
418 };
419
420
421
422
423 extern "C" {
424
425
426 void exif_init(void)
427 {
428 #ifdef EXV_ENABLE_NLS
429         bind_textdomain_codeset (EXV_PACKAGE, "UTF-8");
430 #endif
431 }
432
433
434
435 static void _ExifDataProcessed_update_xmp(gpointer key, gpointer value, gpointer data)
436 {
437         exif_update_metadata((ExifData *)data, (gchar *)key, (GList *)value);
438 }
439
440 ExifData *exif_read(gchar *path, gchar *sidecar_path, GHashTable *modified_xmp)
441 {
442         DEBUG_1("exif read %s, sidecar: %s", path, sidecar_path ? sidecar_path : "-");
443         try {
444                 return new _ExifDataProcessed(path, sidecar_path, modified_xmp);
445         }
446         catch (Exiv2::AnyError& e) {
447                 debug_exception(e);
448                 return NULL;
449         }
450
451 }
452
453 gboolean exif_write(ExifData *exif)
454 {
455         try {
456                 exif->writeMetadata();
457                 return TRUE;
458         }
459         catch (Exiv2::AnyError& e) {
460                 debug_exception(e);
461                 return FALSE;
462         }
463 }
464
465 gboolean exif_write_sidecar(ExifData *exif, gchar *path)
466 {
467         try {
468                 exif->writeMetadata(path);
469                 return TRUE;
470         }
471         catch (Exiv2::AnyError& e) {
472                 debug_exception(e);
473                 return FALSE;
474         }
475
476 }
477
478
479 void exif_free(ExifData *exif)
480 {
481         if (!exif) return;
482         g_assert(dynamic_cast<_ExifDataProcessed *>(exif)); // this should not be called on ExifDataOriginal
483         delete exif;
484 }
485
486 ExifData *exif_get_original(ExifData *exif)
487 {
488         return exif->original();
489 }
490
491
492 ExifItem *exif_get_item(ExifData *exif, const gchar *key)
493 {
494         try {
495                 Exiv2::Metadatum *item = NULL;
496                 try {
497                         Exiv2::ExifKey ekey(key);
498                         Exiv2::ExifData::iterator pos = exif->exifData().findKey(ekey);
499                         if (pos == exif->exifData().end()) return NULL;
500                         item = &*pos;
501                 }
502                 catch (Exiv2::AnyError& e) {
503                         try {
504                                 Exiv2::IptcKey ekey(key);
505                                 Exiv2::IptcData::iterator pos = exif->iptcData().findKey(ekey);
506                                 if (pos == exif->iptcData().end()) return NULL;
507                                 item = &*pos;
508                         }
509                         catch (Exiv2::AnyError& e) {
510 #if EXIV2_TEST_VERSION(0,16,0)
511                                 Exiv2::XmpKey ekey(key);
512                                 Exiv2::XmpData::iterator pos = exif->xmpData().findKey(ekey);
513                                 if (pos == exif->xmpData().end()) return NULL;
514                                 item = &*pos;
515 #endif
516                         }
517                 }
518                 return (ExifItem *)item;
519         }
520         catch (Exiv2::AnyError& e) {
521                 debug_exception(e);
522                 return NULL;
523         }
524 }
525
526 ExifItem *exif_add_item(ExifData *exif, const gchar *key)
527 {
528         try {
529                 Exiv2::Metadatum *item = NULL;
530                 try {
531                         Exiv2::ExifKey ekey(key);
532                         exif->exifData().add(ekey, NULL);
533                         Exiv2::ExifData::iterator pos = exif->exifData().end(); // a hack, there should be a better way to get the currently added item
534                         pos--;
535                         item = &*pos;
536                 }
537                 catch (Exiv2::AnyError& e) {
538                         try {
539                                 Exiv2::IptcKey ekey(key);
540                                 exif->iptcData().add(ekey, NULL);
541                                 Exiv2::IptcData::iterator pos = exif->iptcData().end();
542                                 pos--;
543                                 item = &*pos;
544                         }
545                         catch (Exiv2::AnyError& e) {
546 #if EXIV2_TEST_VERSION(0,16,0)
547                                 Exiv2::XmpKey ekey(key);
548                                 exif->xmpData().add(ekey, NULL);
549                                 Exiv2::XmpData::iterator pos = exif->xmpData().end();
550                                 pos--;
551                                 item = &*pos;
552 #endif
553                         }
554                 }
555                 return (ExifItem *)item;
556         }
557         catch (Exiv2::AnyError& e) {
558                 debug_exception(e);
559                 return NULL;
560         }
561 }
562
563
564 ExifItem *exif_get_first_item(ExifData *exif)
565 {
566         try {
567                 exif->exifIter = exif->exifData().begin();
568                 exif->iptcIter = exif->iptcData().begin();
569 #if EXIV2_TEST_VERSION(0,16,0)
570                 exif->xmpIter = exif->xmpData().begin();
571 #endif
572                 if (exif->exifIter != exif->exifData().end())
573                         {
574                         const Exiv2::Metadatum *item = &*exif->exifIter;
575                         exif->exifIter++;
576                         return (ExifItem *)item;
577                         }
578                 if (exif->iptcIter != exif->iptcData().end())
579                         {
580                         const Exiv2::Metadatum *item = &*exif->iptcIter;
581                         exif->iptcIter++;
582                         return (ExifItem *)item;
583                         }
584 #if EXIV2_TEST_VERSION(0,16,0)
585                 if (exif->xmpIter != exif->xmpData().end())
586                         {
587                         const Exiv2::Metadatum *item = &*exif->xmpIter;
588                         exif->xmpIter++;
589                         return (ExifItem *)item;
590                         }
591 #endif
592                 return NULL;
593
594         }
595         catch (Exiv2::AnyError& e) {
596                 debug_exception(e);
597                 return NULL;
598         }
599 }
600
601 ExifItem *exif_get_next_item(ExifData *exif)
602 {
603         try {
604                 if (exif->exifIter != exif->exifData().end())
605                         {
606                         const Exiv2::Metadatum *item = &*exif->exifIter;
607                         exif->exifIter++;
608                         return (ExifItem *)item;
609                 }
610                 if (exif->iptcIter != exif->iptcData().end())
611                         {
612                         const Exiv2::Metadatum *item = &*exif->iptcIter;
613                         exif->iptcIter++;
614                         return (ExifItem *)item;
615                 }
616 #if EXIV2_TEST_VERSION(0,16,0)
617                 if (exif->xmpIter != exif->xmpData().end())
618                         {
619                         const Exiv2::Metadatum *item = &*exif->xmpIter;
620                         exif->xmpIter++;
621                         return (ExifItem *)item;
622                 }
623 #endif
624                 return NULL;
625         }
626         catch (Exiv2::AnyError& e) {
627                 debug_exception(e);
628                 return NULL;
629         }
630 }
631
632 char *exif_item_get_tag_name(ExifItem *item)
633 {
634         try {
635                 if (!item) return NULL;
636                 return g_strdup(((Exiv2::Metadatum *)item)->key().c_str());
637         }
638         catch (Exiv2::AnyError& e) {
639                 debug_exception(e);
640                 return NULL;
641         }
642 }
643
644 guint exif_item_get_tag_id(ExifItem *item)
645 {
646         try {
647                 if (!item) return 0;
648                 return ((Exiv2::Metadatum *)item)->tag();
649         }
650         catch (Exiv2::AnyError& e) {
651                 debug_exception(e);
652                 return 0;
653         }
654 }
655
656 guint exif_item_get_elements(ExifItem *item)
657 {
658         try {
659                 if (!item) return 0;
660                 return ((Exiv2::Metadatum *)item)->count();
661         }
662         catch (Exiv2::AnyError& e) {
663                 debug_exception(e);
664                 return 0;
665         }
666 }
667
668 char *exif_item_get_data(ExifItem *item, guint *data_len)
669 {
670         try {
671                 if (!item) return 0;
672                 Exiv2::Metadatum *md = (Exiv2::Metadatum *)item;
673                 if (data_len) *data_len = md->size();
674                 char *data = (char *)g_malloc(md->size());
675                 long res = md->copy((Exiv2::byte *)data, Exiv2::littleEndian /* should not matter */);
676                 g_assert(res == md->size());
677                 return data;
678         }
679         catch (Exiv2::AnyError& e) {
680                 debug_exception(e);
681                 return NULL;
682         }
683 }
684
685 char *exif_item_get_description(ExifItem *item)
686 {
687         try {
688                 if (!item) return NULL;
689                 return utf8_validate_or_convert(((Exiv2::Metadatum *)item)->tagLabel().c_str());
690         }
691         catch (std::exception& e) {
692 //              debug_exception(e);
693                 return NULL;
694         }
695 }
696
697 /*
698 invalidTypeId, unsignedByte, asciiString, unsignedShort,
699   unsignedLong, unsignedRational, signedByte, undefined,
700   signedShort, signedLong, signedRational, string,
701   date, time, comment, directory,
702   xmpText, xmpAlt, xmpBag, xmpSeq,
703   langAlt, lastTypeId
704 */
705
706 static guint format_id_trans_tbl [] = {
707         EXIF_FORMAT_UNKNOWN,
708         EXIF_FORMAT_BYTE_UNSIGNED,
709         EXIF_FORMAT_STRING,
710         EXIF_FORMAT_SHORT_UNSIGNED,
711         EXIF_FORMAT_LONG_UNSIGNED,
712         EXIF_FORMAT_RATIONAL_UNSIGNED,
713         EXIF_FORMAT_BYTE,
714         EXIF_FORMAT_UNDEFINED,
715         EXIF_FORMAT_SHORT,
716         EXIF_FORMAT_LONG,
717         EXIF_FORMAT_RATIONAL,
718         EXIF_FORMAT_STRING,
719         EXIF_FORMAT_STRING,
720         EXIF_FORMAT_STRING,
721         EXIF_FORMAT_UNDEFINED,
722         EXIF_FORMAT_STRING,
723         EXIF_FORMAT_STRING,
724         EXIF_FORMAT_STRING,
725         EXIF_FORMAT_STRING
726         };
727
728
729
730 guint exif_item_get_format_id(ExifItem *item)
731 {
732         try {
733                 if (!item) return EXIF_FORMAT_UNKNOWN;
734                 guint id = ((Exiv2::Metadatum *)item)->typeId();
735                 if (id >= (sizeof(format_id_trans_tbl) / sizeof(format_id_trans_tbl[0])) ) return EXIF_FORMAT_UNKNOWN;
736                 return format_id_trans_tbl[id];
737         }
738         catch (Exiv2::AnyError& e) {
739                 debug_exception(e);
740                 return EXIF_FORMAT_UNKNOWN;
741         }
742 }
743
744 const char *exif_item_get_format_name(ExifItem *item, gboolean brief)
745 {
746         try {
747                 if (!item) return NULL;
748                 return ((Exiv2::Metadatum *)item)->typeName();
749         }
750         catch (Exiv2::AnyError& e) {
751                 debug_exception(e);
752                 return NULL;
753         }
754 }
755
756
757 gchar *exif_item_get_data_as_text(ExifItem *item)
758 {
759         try {
760                 if (!item) return NULL;
761                 Exiv2::Metadatum *metadatum = (Exiv2::Metadatum *)item;
762 #if EXIV2_TEST_VERSION(0,17,0)
763                 return utf8_validate_or_convert(metadatum->print().c_str());
764 #else
765                 std::stringstream str;
766                 Exiv2::Exifdatum *exifdatum;
767                 Exiv2::Iptcdatum *iptcdatum;
768 #if EXIV2_TEST_VERSION(0,16,0)
769                 Exiv2::Xmpdatum *xmpdatum;
770 #endif
771                 if ((exifdatum = dynamic_cast<Exiv2::Exifdatum *>(metadatum)))
772                         str << *exifdatum;
773                 else if ((iptcdatum = dynamic_cast<Exiv2::Iptcdatum *>(metadatum)))
774                         str << *iptcdatum;
775 #if EXIV2_TEST_VERSION(0,16,0)
776                 else if ((xmpdatum = dynamic_cast<Exiv2::Xmpdatum *>(metadatum)))
777                         str << *xmpdatum;
778 #endif
779
780                 return utf8_validate_or_convert(str.str().c_str());
781 #endif
782         }
783         catch (Exiv2::AnyError& e) {
784                 return NULL;
785         }
786 }
787
788 gchar *exif_item_get_string(ExifItem *item, int idx)
789 {
790         try {
791                 if (!item) return NULL;
792                 Exiv2::Metadatum *em = (Exiv2::Metadatum *)item;
793 #if EXIV2_TEST_VERSION(0,16,0)
794                 std::string str = em->toString(idx);
795 #else
796                 std::string str = em->toString(); // FIXME
797 #endif
798                 if (idx == 0 && str == "") str = em->toString();
799                 if (str.length() > 5 && str.substr(0, 5) == "lang=")
800                         {
801                         std::string::size_type pos = str.find_first_of(' ');
802                         if (pos != std::string::npos) str = str.substr(pos+1);
803                         }
804
805                 return utf8_validate_or_convert(str.c_str());
806         }
807         catch (Exiv2::AnyError& e) {
808                 return NULL;
809         }
810 }
811
812
813 gint exif_item_get_integer(ExifItem *item, gint *value)
814 {
815         try {
816                 if (!item || exif_item_get_elements(item) == 0) return 0;
817                 *value = ((Exiv2::Metadatum *)item)->toLong();
818                 return 1;
819         }
820         catch (Exiv2::AnyError& e) {
821                 debug_exception(e);
822                 return 0;
823         }
824 }
825
826 ExifRational *exif_item_get_rational(ExifItem *item, gint *sign, guint n)
827 {
828         try {
829                 if (!item) return NULL;
830                 if (n >= exif_item_get_elements(item)) return NULL;
831                 Exiv2::Rational v = ((Exiv2::Metadatum *)item)->toRational(n);
832                 static ExifRational ret;
833                 ret.num = v.first;
834                 ret.den = v.second;
835                 if (sign) *sign = (((Exiv2::Metadatum *)item)->typeId() == Exiv2::signedRational);
836                 return &ret;
837         }
838         catch (Exiv2::AnyError& e) {
839                 debug_exception(e);
840                 return NULL;
841         }
842 }
843
844 gchar *exif_get_tag_description_by_key(const gchar *key)
845 {
846         try {
847                 Exiv2::ExifKey ekey(key);
848                 return utf8_validate_or_convert(ekey.tagLabel().c_str());
849         }
850         catch (Exiv2::AnyError& e) {
851                 try {
852                         Exiv2::IptcKey ikey(key);
853                         return utf8_validate_or_convert(ikey.tagLabel().c_str());
854                 }
855                 catch (Exiv2::AnyError& e) {
856                         try {
857 #if EXIV2_TEST_VERSION(0,16,0)
858                                 Exiv2::XmpKey xkey(key);
859                                 return utf8_validate_or_convert(xkey.tagLabel().c_str());
860 #endif
861                         }
862                         catch (Exiv2::AnyError& e) {
863                                 debug_exception(e);
864                                 return NULL;
865                         }
866                 }
867         }
868         return NULL;
869 }
870
871 static const AltKey *find_alt_key(const gchar *xmp_key)
872 {
873         gint i = 0;
874
875         while (alt_keys[i].xmp_key)
876                 {
877                 if (strcmp(xmp_key, alt_keys[i].xmp_key) == 0) return &alt_keys[i];
878                 i++;
879                 }
880         return NULL;
881 }
882
883 static gint exif_update_metadata_simple(ExifData *exif, const gchar *key, const GList *values)
884 {
885         try {
886                 const GList *work = values;
887
888                 try {
889                         Exiv2::ExifKey ekey(key);
890
891                         Exiv2::ExifData::iterator pos = exif->exifData().findKey(ekey);
892                         while (pos != exif->exifData().end())
893                                 {
894                                 exif->exifData().erase(pos);
895                                 pos = exif->exifData().findKey(ekey);
896                                 }
897
898                         while (work)
899                                 {
900                                 exif->exifData()[key] = (gchar *)work->data;
901                                 work = work->next;
902                                 }
903                 }
904                 catch (Exiv2::AnyError& e) {
905 #if EXIV2_TEST_VERSION(0,16,0)
906                         try
907 #endif
908                         {
909                                 Exiv2::IptcKey ekey(key);
910                                 Exiv2::IptcData::iterator pos = exif->iptcData().findKey(ekey);
911                                 while (pos != exif->iptcData().end())
912                                         {
913                                         exif->iptcData().erase(pos);
914                                         pos = exif->iptcData().findKey(ekey);
915                                         }
916
917                                 while (work)
918                                         {
919                                         exif->iptcData()[key] = (gchar *)work->data;
920                                         work = work->next;
921                                         }
922                         }
923 #if EXIV2_TEST_VERSION(0,16,0)
924                         catch (Exiv2::AnyError& e) {
925                                 Exiv2::XmpKey ekey(key);
926                                 Exiv2::XmpData::iterator pos = exif->xmpData().findKey(ekey);
927                                 while (pos != exif->xmpData().end())
928                                         {
929                                         exif->xmpData().erase(pos);
930                                         pos = exif->xmpData().findKey(ekey);
931                                         }
932
933                                 while (work)
934                                         {
935                                         exif->xmpData()[key] = (gchar *)work->data;
936                                         work = work->next;
937                                         }
938                         }
939 #endif
940                 }
941                 return 1;
942         }
943         catch (Exiv2::AnyError& e) {
944                 debug_exception(e);
945                 return 0;
946         }
947 }
948
949 gint exif_update_metadata(ExifData *exif, const gchar *key, const GList *values)
950 {
951         gint ret = exif_update_metadata_simple(exif, key, values);
952
953         if (
954 #if !EXIV2_TEST_VERSION(0,17,0)
955             TRUE || /* no conversion support */
956 #endif
957             !values || /* deleting item */
958             !ret  /* writing to the explicitely given xmp tag failed */
959             )
960                 {
961                 /* deleted xmp metadatum can't be converted, we have to delete also the corresponding legacy tag */
962                 /* if we can't write xmp, update at least the legacy tag */
963                 const AltKey *alt_key = find_alt_key(key);
964                 if (alt_key && alt_key->iptc_key)
965                         ret = exif_update_metadata_simple(exif, alt_key->iptc_key, values);
966
967                 if (alt_key && alt_key->exif_key)
968                         ret = exif_update_metadata_simple(exif, alt_key->exif_key, values);
969                 }
970         return ret;
971 }
972
973
974 static GList *exif_add_value_to_glist(GList *list, Exiv2::Metadatum &item, MetadataFormat format, const Exiv2::ExifData *metadata)
975 {
976 #if EXIV2_TEST_VERSION(0,16,0)
977         Exiv2::TypeId id = item.typeId();
978         if (format == METADATA_FORMATTED ||
979             id == Exiv2::asciiString ||
980             id == Exiv2::undefined ||
981             id == Exiv2::string ||
982             id == Exiv2::date ||
983             id == Exiv2::time ||
984             id == Exiv2::xmpText ||
985             id == Exiv2::langAlt ||
986             id == Exiv2::comment
987             )
988                 {
989 #endif
990                 /* read as a single entry */
991                 std::string str;
992
993                 if (format == METADATA_FORMATTED)
994                         {
995 #if EXIV2_TEST_VERSION(0,17,0)
996                         str = item.print(
997 #if EXIV2_TEST_VERSION(0,18,0)
998                                         metadata
999 #endif
1000                                         );
1001 #else
1002                         std::stringstream stream;
1003                         Exiv2::Exifdatum *exifdatum;
1004                         Exiv2::Iptcdatum *iptcdatum;
1005 #if EXIV2_TEST_VERSION(0,16,0)
1006                         Exiv2::Xmpdatum *xmpdatum;
1007 #endif
1008                         if ((exifdatum = dynamic_cast<Exiv2::Exifdatum *>(&item)))
1009                                 stream << *exifdatum;
1010                         else if ((iptcdatum = dynamic_cast<Exiv2::Iptcdatum *>(&item)))
1011                                 stream << *iptcdatum;
1012 #if EXIV2_TEST_VERSION(0,16,0)
1013                         else if ((xmpdatum = dynamic_cast<Exiv2::Xmpdatum *>(&item)))
1014                                 stream << *xmpdatum;
1015 #endif
1016                         str = stream.str();
1017 #endif
1018                         if (str.length() > 1024)
1019                                 {
1020                                 /* truncate very long strings, they cause problems in gui */
1021                                 str.erase(1024);
1022                                 str.append("...");
1023                                 }
1024                         }
1025                 else
1026                         {
1027                         str = item.toString();
1028                         }
1029                 if (str.length() > 5 && str.substr(0, 5) == "lang=")
1030                         {
1031                         std::string::size_type pos = str.find_first_of(' ');
1032                         if (pos != std::string::npos) str = str.substr(pos+1);
1033                         }
1034                 list = g_list_append(list, utf8_validate_or_convert(str.c_str()));
1035 #if EXIV2_TEST_VERSION(0,16,0)
1036                 }
1037         else
1038                 {
1039                 /* read as a list */
1040                 gint i;
1041                 for (i = 0; i < item.count(); i++)
1042                         list = g_list_append(list, utf8_validate_or_convert(item.toString(i).c_str()));
1043                 }
1044 #endif
1045         return list;
1046 }
1047
1048 static GList *exif_get_metadata_simple(ExifData *exif, const gchar *key, MetadataFormat format)
1049 {
1050         GList *list = NULL;
1051         try {
1052                 try {
1053                         Exiv2::ExifKey ekey(key);
1054                         Exiv2::ExifData::iterator pos = exif->exifData().findKey(ekey);
1055                         if (pos != exif->exifData().end())
1056                                 list = exif_add_value_to_glist(list, *pos, format, &exif->exifData());
1057
1058                 }
1059                 catch (Exiv2::AnyError& e) {
1060                         try {
1061                                 Exiv2::IptcKey ekey(key);
1062                                 Exiv2::IptcData::iterator pos = exif->iptcData().begin();
1063                                 while (pos != exif->iptcData().end())
1064                                         {
1065                                         if (pos->key() == key)
1066                                                 list = exif_add_value_to_glist(list, *pos, format, NULL);
1067                                         ++pos;
1068                                         }
1069
1070                         }
1071                         catch (Exiv2::AnyError& e) {
1072 #if EXIV2_TEST_VERSION(0,16,0)
1073                                 Exiv2::XmpKey ekey(key);
1074                                 Exiv2::XmpData::iterator pos = exif->xmpData().findKey(ekey);
1075                                 if (pos != exif->xmpData().end())
1076                                         list = exif_add_value_to_glist(list, *pos, format, NULL);
1077 #endif
1078                         }
1079                 }
1080         }
1081         catch (Exiv2::AnyError& e) {
1082                 debug_exception(e);
1083         }
1084         return list;
1085 }
1086
1087 GList *exif_get_metadata(ExifData *exif, const gchar *key, MetadataFormat format)
1088 {
1089         GList *list = NULL;
1090
1091         if (!key) return NULL;
1092
1093         if (format == METADATA_FORMATTED)
1094                 {
1095                 gchar *text;
1096                 gint key_valid;
1097                 text = exif_get_formatted_by_key(exif, key, &key_valid);
1098                 if (key_valid) return g_list_append(NULL, text);
1099                 }
1100
1101         list = exif_get_metadata_simple(exif, key, format);
1102
1103         /* the following code can be ifdefed out as soon as Exiv2 supports it */
1104         if (!list)
1105                 {
1106                 const AltKey *alt_key = find_alt_key(key);
1107                 if (alt_key && alt_key->iptc_key)
1108                         list = exif_get_metadata_simple(exif, alt_key->iptc_key, format);
1109
1110 #if !EXIV2_TEST_VERSION(0,17,0)
1111                 /* with older Exiv2 versions exif is not synced */
1112                 if (!list && alt_key && alt_key->exif_key)
1113                         list = exif_get_metadata_simple(exif, alt_key->exif_key, format);
1114 #endif
1115                 }
1116         return list;
1117 }
1118
1119
1120 void exif_add_jpeg_color_profile(ExifData *exif, unsigned char *cp_data, guint cp_length)
1121 {
1122         exif->add_jpeg_color_profile(cp_data, cp_length);
1123 }
1124
1125 guchar *exif_get_color_profile(ExifData *exif, guint *data_len)
1126 {
1127         guchar *ret = exif->get_jpeg_color_profile(data_len);
1128         if (ret) return ret;
1129
1130         ExifItem *prof_item = exif_get_item(exif, "Exif.Image.InterColorProfile");
1131         if (prof_item && exif_item_get_format_id(prof_item) == EXIF_FORMAT_UNDEFINED)
1132                 ret = (guchar *)exif_item_get_data(prof_item, data_len);
1133         return ret;
1134 }
1135
1136 #if EXIV2_TEST_VERSION(0,17,90)
1137
1138 guchar *exif_get_preview(ExifData *exif, guint *data_len, gint requested_width, gint requested_height)
1139 {
1140         if (!exif) return NULL;
1141
1142         if (!exif->image()) return NULL;
1143
1144         std::string const path = exif->image()->io().path();
1145         /* given image pathname, first do simple (and fast) file extension test */
1146         gboolean is_raw = filter_file_class(path.c_str(), FORMAT_CLASS_RAWIMAGE);
1147
1148         if (!is_raw && requested_width == 0) return NULL;
1149
1150         try {
1151
1152                 Exiv2::PreviewManager pm(*exif->image());
1153
1154                 Exiv2::PreviewPropertiesList list = pm.getPreviewProperties();
1155
1156                 if (!list.empty())
1157                         {
1158                         Exiv2::PreviewPropertiesList::iterator pos;
1159                         Exiv2::PreviewPropertiesList::iterator last = --list.end();
1160
1161                         if (requested_width == 0)
1162                                 {
1163                                 pos = last; // the largest
1164                                 }
1165                         else
1166                                 {
1167                                 pos = list.begin();
1168                                 while (pos != last)
1169                                         {
1170                                         if (pos->width_ >= (uint32_t)requested_width &&
1171                                             pos->height_ >= (uint32_t)requested_height) break;
1172                                         ++pos;
1173                                         }
1174
1175                                 // we are not interested in smaller thumbnails in normal image formats - we can use full image instead
1176                                 if (!is_raw)
1177                                         {
1178                                         if (pos->width_ < (uint32_t)requested_width || pos->height_ < (uint32_t)requested_height) return NULL;
1179                                         }
1180                                 }
1181
1182                         Exiv2::PreviewImage image = pm.getPreviewImage(*pos);
1183
1184                         Exiv2::DataBuf buf = image.copy();
1185                         std::pair<Exiv2::byte*, long> p = buf.release();
1186
1187                         *data_len = p.second;
1188                         return p.first;
1189                         }
1190                 return NULL;
1191         }
1192         catch (Exiv2::AnyError& e) {
1193                 debug_exception(e);
1194                 return NULL;
1195         }
1196 }
1197
1198 void exif_free_preview(guchar *buf)
1199 {
1200         delete[] (Exiv2::byte*)buf;
1201 }
1202 #endif
1203
1204 }
1205 #if !EXIV2_TEST_VERSION(0,17,90)
1206
1207 /* This is a dirty hack to support raw file preview, bassed on
1208 tiffparse.cpp from Exiv2 examples */
1209
1210 class RawFile {
1211         public:
1212
1213         RawFile(Exiv2::BasicIo &io);
1214         ~RawFile();
1215
1216         const Exiv2::Value *find(uint16_t tag, uint16_t group);
1217
1218         unsigned long preview_offset();
1219
1220         private:
1221         int type;
1222         Exiv2::TiffComponent::AutoPtr rootDir;
1223         Exiv2::BasicIo &io_;
1224         const Exiv2::byte *map_data;
1225         size_t map_len;
1226         unsigned long offset;
1227 };
1228
1229 typedef struct _UnmapData UnmapData;
1230 struct _UnmapData
1231 {
1232         guchar *ptr;
1233         guchar *map_data;
1234         size_t map_len;
1235 };
1236
1237 static GList *exif_unmap_list = 0;
1238
1239 extern "C" guchar *exif_get_preview(ExifData *exif, guint *data_len, gint requested_width, gint requested_height)
1240 {
1241         unsigned long offset;
1242
1243         if (!exif) return NULL;
1244         if (!exif->image()) return NULL;
1245
1246         std::string const path = exif->image()->io().path();
1247
1248         /* given image pathname, first do simple (and fast) file extension test */
1249         if (!filter_file_class(path.c_str(), FORMAT_CLASS_RAWIMAGE)) return NULL;
1250
1251         try {
1252                 struct stat st;
1253                 guchar *map_data;
1254                 size_t map_len;
1255                 UnmapData *ud;
1256                 int fd;
1257
1258                 RawFile rf(exif->image()->io());
1259                 offset = rf.preview_offset();
1260                 DEBUG_1("%s: offset %lu", path.c_str(), offset);
1261
1262                 fd = open(path.c_str(), O_RDONLY);
1263                 if (fd == -1)
1264                         {
1265                         return NULL;
1266                         }
1267
1268                 if (fstat(fd, &st) == -1)
1269                         {
1270                         close(fd);
1271                         return NULL;
1272                         }
1273                 map_len = st.st_size;
1274                 map_data = (guchar *) mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0);
1275                 close(fd);
1276                 if (map_data == MAP_FAILED)
1277                         {
1278                         return NULL;
1279                         }
1280                 *data_len = map_len - offset;
1281                 ud = g_new(UnmapData, 1);
1282                 ud->ptr = map_data + offset;
1283                 ud->map_data = map_data;
1284                 ud->map_len = map_len;
1285
1286                 exif_unmap_list = g_list_prepend(exif_unmap_list, ud);
1287                 return ud->ptr;
1288
1289         }
1290         catch (Exiv2::AnyError& e) {
1291                 debug_exception(e);
1292         }
1293         return NULL;
1294
1295 }
1296
1297 void exif_free_preview(guchar *buf)
1298 {
1299         GList *work = exif_unmap_list;
1300
1301         while (work)
1302                 {
1303                 UnmapData *ud = (UnmapData *)work->data;
1304                 if (ud->ptr == buf)
1305                         {
1306                         munmap(ud->map_data, ud->map_len);
1307                         exif_unmap_list = g_list_remove_link(exif_unmap_list, work);
1308                         g_free(ud);
1309                         return;
1310                         }
1311                 work = work->next;
1312                 }
1313         g_assert_not_reached();
1314 }
1315
1316 using namespace Exiv2;
1317
1318 RawFile::RawFile(BasicIo &io) : io_(io), map_data(NULL), map_len(0), offset(0)
1319 {
1320 /*
1321         struct stat st;
1322         if (fstat(fd, &st) == -1)
1323                 {
1324                 throw Error(14);
1325                 }
1326         map_len = st.st_size;
1327         map_data = (Exiv2::byte *) mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0);
1328         if (map_data == MAP_FAILED)
1329                 {
1330                 throw Error(14);
1331                 }
1332 */
1333         if (io.open() != 0) {
1334             throw Error(9, io.path(), strError());
1335         }
1336
1337         map_data = io.mmap();
1338         map_len = io.size();
1339
1340
1341         type = Exiv2::ImageFactory::getType(map_data, map_len);
1342
1343 #if EXIV2_TEST_VERSION(0,16,0)
1344         TiffHeaderBase *tiffHeader = NULL;
1345 #else
1346         TiffHeade2 *tiffHeader = NULL;
1347 #endif
1348         Cr2Header *cr2Header = NULL;
1349
1350         switch (type) {
1351                 case Exiv2::ImageType::tiff:
1352                         tiffHeader = new TiffHeade2();
1353                         break;
1354                 case Exiv2::ImageType::cr2:
1355                         cr2Header = new Cr2Header();
1356                         break;
1357 #if EXIV2_TEST_VERSION(0,16,0)
1358                 case Exiv2::ImageType::orf:
1359                         tiffHeader = new OrfHeader();
1360                         break;
1361 #endif
1362 #if EXIV2_TEST_VERSION(0,13,0)
1363                 case Exiv2::ImageType::raf:
1364                         if (map_len < 84 + 4) throw Error(14);
1365                         offset = getULong(map_data + 84, bigEndian);
1366                         return;
1367 #endif
1368                 case Exiv2::ImageType::crw:
1369                         {
1370                         // Parse the image, starting with a CIFF header component
1371                         Exiv2::CiffHeader::AutoPtr parseTree(new Exiv2::CiffHeader);
1372                         parseTree->read(map_data, map_len);
1373                         CiffComponent *entry = parseTree->findComponent(0x2007, 0);
1374                         if (entry) offset =  entry->pData() - map_data;
1375                         return;
1376                         }
1377
1378                 default:
1379                         throw Error(3, "RAW");
1380         }
1381
1382         // process tiff-like formats
1383
1384         TiffCompFactoryFct createFct = TiffCreator::create;
1385
1386         rootDir = createFct(Tag::root, Group::none);
1387         if (0 == rootDir.get()) {
1388                 throw Error(1, "No root element defined in TIFF structure");
1389         }
1390
1391         if (tiffHeader)
1392                 {
1393                 if (!tiffHeader->read(map_data, map_len)) throw Error(3, "TIFF");
1394 #if EXIV2_TEST_VERSION(0,16,0)
1395                 rootDir->setStart(map_data + tiffHeader->offset());
1396 #else
1397                 rootDir->setStart(map_data + tiffHeader->ifdOffset());
1398 #endif
1399                 }
1400
1401         if (cr2Header)
1402                 {
1403                 rootDir->setStart(map_data + cr2Header->offset());
1404                 }
1405
1406         TiffRwState::AutoPtr state(new TiffRwState(tiffHeader ? tiffHeader->byteOrder() : littleEndian, 0, createFct));
1407
1408         TiffReader reader(map_data,
1409                           map_len,
1410                           rootDir.get(),
1411                           state);
1412
1413         rootDir->accept(reader);
1414
1415         if (tiffHeader)
1416                 delete tiffHeader;
1417         if (cr2Header)
1418                 delete cr2Header;
1419 }
1420
1421 RawFile::~RawFile(void)
1422 {
1423         io_.munmap();
1424         io_.close();
1425 }
1426
1427 const Value * RawFile::find(uint16_t tag, uint16_t group)
1428 {
1429         TiffFinder finder(tag, group);
1430         rootDir->accept(finder);
1431         TiffEntryBase* te = dynamic_cast<TiffEntryBase*>(finder.result());
1432         if (te)
1433                 {
1434                 DEBUG_1("(tag: %04x %04x) ", tag, group);
1435                 return te->pValue();
1436                 }
1437         else
1438                 return NULL;
1439 }
1440
1441 unsigned long RawFile::preview_offset(void)
1442 {
1443         const Value *val;
1444         if (offset) return offset;
1445
1446         if (type == Exiv2::ImageType::cr2)
1447                 {
1448                 val = find(0x111, Group::ifd0);
1449                 if (val) return val->toLong();
1450
1451                 return 0;
1452                 }
1453
1454         val = find(0x201, Group::sub0_0);
1455         if (val) return val->toLong();
1456
1457         val = find(0x201, Group::ifd0);
1458         if (val) return val->toLong();
1459
1460         val = find(0x201, Group::ignr); // for PEF files, originally it was probably ifd2
1461         if (val) return val->toLong();
1462
1463         val = find(0x111, Group::sub0_1); // dng
1464         if (val) return val->toLong();
1465
1466         return 0;
1467 }
1468
1469
1470 #endif
1471
1472
1473 #endif
1474 /* HAVE_EXIV2 */
1475 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */