Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
exif.cc
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2014, 2016 johannes hanika.
4 Copyright (C) 2010-2012 Henrik Andersson.
5 Copyright (C) 2010, 2012-2015 Pascal de Bruijn.
6 Copyright (C) 2010-2018 Tobias Ellinghaus.
7 Copyright (C) 2011-2012, 2018 Edouard Gomez.
8 Copyright (C) 2011 Jochen Schroeder.
9 Copyright (C) 2011 Johanes Schneider.
10 Copyright (C) 2011-2012 Jérémy Rosen.
11 Copyright (C) 2011 Kanstantsin Shautsou.
12 Copyright (C) 2011 Robert Bieber.
13 Copyright (C) 2011, 2013 Simon Spannagel.
14 Copyright (C) 2011 Uli Scholler.
15 Copyright (C) 2012-2013, 2020 Aldric Renaudin.
16 Copyright (C) 2012 Alexander Clausen.
17 Copyright (C) 2012 James C. McPherson.
18 Copyright (C) 2012-2013 José Carlos García Sogo.
19 Copyright (C) 2012 Richard Wonka.
20 Copyright (C) 2012 Sergey Pavlov.
21 Copyright (C) 2012-2014, 2016 Ulrich Pegelow.
22 Copyright (C) 2012 Wolfgang Kühnel.
23 Copyright (C) 2013 Dennis Gnad.
24 Copyright (C) 2013 Jacek Naglak.
25 Copyright (C) 2013-2015, 2018-2022 Pascal Obry.
26 Copyright (C) 2013-2017 Roman Lebedev.
27 Copyright (C) 2014-2015 Jan Niklas Fingerle.
28 Copyright (C) 2014 Michael Neumann.
29 Copyright (C) 2014-2016 Pedro Côrte-Real.
30 Copyright (C) 2015 Jake Probst.
31 Copyright (C) 2015, 2018 Marcel Müller.
32 Copyright (C) 2015 Tom Vijlbrief.
33 Copyright (C) 2015 Torsten Bronger.
34 Copyright (C) 2016 Matthieu Volat.
35 Copyright (C) 2017, 2020 David-Tillmann Schaefer.
36 Copyright (C) 2017, 2019, 2021 luzpaz.
37 Copyright (C) 2018-2019 Andreas Schneider.
38 Copyright (C) 2018-2019 Edgardo Hoszowski.
39 Copyright (C) 2018 Fabian Wenzel.
40 Copyright (C) 2019 codingdave.
41 Copyright (C) 2019-2021 Hanno Schwalm.
42 Copyright (C) 2019-2022 Philippe Weyland.
43 Copyright (C) 2020 Chris Elston.
44 Copyright (C) 2020-2021 Hubert Kowalski.
45 Copyright (C) 2020 JP Verrue.
46 Copyright (C) 2020 Matt Maguire.
47 Copyright (C) 2020-2022 Miloš Komarčević.
48 Copyright (C) 2020-2021 Ralf Brown.
49 Copyright (C) 2021, 2023, 2025-2026 Aurélien PIERRE.
50 Copyright (C) 2021 Daniel Vogelbacher.
51 Copyright (C) 2021 Victor Forsiuk.
52 Copyright (C) 2022 gi-man.
53 Copyright (C) 2022 Martin Bařinka.
54 Copyright (C) 2022 paolodepetrillo.
55 Copyright (C) 2023, 2025 Alynx Zhou.
56 Copyright (C) 2023 Ricky Moon.
57 Copyright (C) 2025-2026 Guillaume Stutin.
58
59 darktable is free software: you can redistribute it and/or modify
60 it under the terms of the GNU General Public License as published by
61 the Free Software Foundation, either version 3 of the License, or
62 (at your option) any later version.
63
64 darktable is distributed in the hope that it will be useful,
65 but WITHOUT ANY WARRANTY; without even the implied warranty of
66 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
67 GNU General Public License for more details.
68
69 You should have received a copy of the GNU General Public License
70 along with darktable. If not, see <http://www.gnu.org/licenses/>.
71 */
72
73#define __STDC_FORMAT_MACROS
74
75#ifdef HAVE_CONFIG_H
76#include "config.h"
77#endif
78
79#include <errno.h>
80#include <glib.h>
81#include <sqlite3.h>
82#include <sys/stat.h>
83#include <sys/types.h>
84#include <time.h>
85#include <unistd.h>
86#include <zlib.h>
87
88#include <array>
89#include <cassert>
90#include <cmath>
91#include <cstdlib>
92#include <cstring>
93#include <fstream>
94#include <iostream>
95#include <sstream>
96#include <string>
97
98#include <exiv2/exiv2.hpp>
99
100#if defined(_WIN32) && defined(EXV_UNICODE_PATH)
101 #define WIDEN(s) pugi::as_wide(s)
102#else
103 #define WIDEN(s) (s)
104#endif
105
106#include <pugixml.hpp>
107
108#include "glib.h"
109
110#include "common/colorlabels.h"
111#include "common/darktable.h"
112#include "common/deprecations.h"
113#include "common/debug.h"
114#include "common/dng_opcode.h"
115#include "common/image_cache.h"
116#include "common/imageio.h"
117#include "common/exif.h"
118#include "common/imageio_jpeg.h"
119#include "common/metadata.h"
120#include "common/ratings.h"
121#include "common/tags.h"
122#include "common/iop_order.h"
123#include "common/variables.h"
124#include "common/utility.h"
125#include "common/history.h"
126#include "common/datetime.h"
127#include "control/conf.h"
128#include "control/control.h"
129#include "develop/imageop.h"
130#include "develop/blend.h"
131#include "develop/masks.h"
132
133using namespace std;
134
135#define DT_XMP_EXIF_VERSION 5
136
137#if EXIV2_TEST_VERSION(0,28,0)
138#define AnyError Error
139#define toLong toInt64
140#endif
141
142// persistent list of exiv2 tags. set up in dt_init()
143static GList *exiv2_taglist = NULL;
144
145static const char *_get_exiv2_type(const int type)
146{
147 switch(type)
148 {
149 case 1:
150 return "Byte";
151 case 2:
152 return "Ascii";
153 case 3:
154 return "Short";
155 case 4:
156 return "Long";
157 case 5:
158 return "Rational"; // two LONGs: numerator and denumerator of a fraction
159 case 6:
160 return "SByte";
161 case 7:
162 return "Undefined";
163 case 8:
164 return "SShort";
165 case 9:
166 return "SLong";
167 case 10:
168 return "SRational"; // two SLONGs: numerator and denumerator of a fraction.
169 case 11:
170 return "Float"; // single precision (4-byte) IEEE format
171 case 12:
172 return "Double"; // double precision (8-byte) IEEE format.
173 case 13:
174 return "Ifd"; // 32-bit (4-byte) unsigned integer
175 case 16:
176 return "LLong"; // 64-bit (8-byte) unsigned integer
177 case 17:
178 return "LLong"; // 64-bit (8-byte) signed integer
179 case 18:
180 return "Ifd8"; // 64-bit (8-byte) unsigned integer
181 case 0x10000:
182 return "String";
183 case 0x10001:
184 return "Date";
185 case 0x10002:
186 return "Time";
187 case 0x10003:
188 return "Comment";
189 case 0x10004:
190 return "Directory";
191 case 0x10005:
192 return "XmpText";
193 case 0x10006:
194 return "XmpAlt";
195 case 0x10007:
196 return "XmpBag";
197 case 0x10008:
198 return "XmpSeq";
199 case 0x10009:
200 return "LangAlt";
201 case 0x1fffe:
202 return "Invalid";
203 case 0x1ffff:
204 return "LastType";
205 default:
206 return "Invalid";
207 }
208}
209
210static void _get_xmp_tags(const char *prefix, GList **taglist)
211{
212 const Exiv2::XmpPropertyInfo *pl = Exiv2::XmpProperties::propertyList(prefix);
213 if(pl)
214 {
215 for (int i = 0; pl[i].name_ != 0; ++i)
216 {
217 char *tag = dt_util_dstrcat(NULL, "Xmp.%s.%s,%s", prefix, pl[i].name_, _get_exiv2_type(pl[i].typeId_));
218 *taglist = g_list_prepend(*taglist, tag);
219 }
220 }
221}
222
224{
225 switch(illu)
226 {
228 case DT_LS_Tungsten:
229 return 2850;
231 return 3200;
233 return 4871;
235 return 6774;
236 case DT_LS_D50:
237 return 5000;
238 case DT_LS_D55:
239 case DT_LS_Daylight:
241 case DT_LS_Flash:
242 return 5500;
243 case DT_LS_D65:
245 return 6500;
246 case DT_LS_D75:
247 case DT_LS_Shade:
248 return 7500;
250 return 6430;
252 return 5000;
254 return 4150;
256 return 4230;
258 return 3450;
260 return 2940;
261 default:
262 return 0;
263 }
264}
265
267{
268 if(exiv2_taglist) return;
269
270 try
271 {
272 const Exiv2::GroupInfo *groupList = Exiv2::ExifTags::groupList();
273 if(groupList)
274 {
275 while(groupList->tagList_)
276 {
277 const std::string groupName(groupList->groupName_);
278 if(groupName.substr(0, 3) != "Sub" &&
279 groupName != "Image2" &&
280 groupName != "Image3" &&
281 groupName != "Thumbnail"
282 )
283 {
284 const Exiv2::TagInfo *tagInfo = groupList->tagList_();
285 while(tagInfo->tag_ != 0xFFFF)
286 {
287 char *tag = dt_util_dstrcat(NULL, "Exif.%s.%s,%s", groupList->groupName_, tagInfo->name_, _get_exiv2_type(tagInfo->typeId_));
288 exiv2_taglist = g_list_prepend(exiv2_taglist, tag);
289 tagInfo++;
290 }
291 }
292 groupList++;
293 }
294 }
295
296 const Exiv2::DataSet *iptcEnvelopeList = Exiv2::IptcDataSets::envelopeRecordList();
297 while(iptcEnvelopeList->number_ != 0xFFFF)
298 {
299 char *tag = dt_util_dstrcat(NULL, "Iptc.Envelope.%s,%s%s", iptcEnvelopeList->name_,
300 _get_exiv2_type(iptcEnvelopeList->type_),
301 iptcEnvelopeList->repeatable_ ? "-R" : "");
302 exiv2_taglist = g_list_prepend(exiv2_taglist, tag);
303 iptcEnvelopeList++;
304 }
305
306 const Exiv2::DataSet *iptcApplication2List = Exiv2::IptcDataSets::application2RecordList();
307 while(iptcApplication2List->number_ != 0xFFFF)
308 {
309 char *tag = dt_util_dstrcat(NULL, "Iptc.Application2.%s,%s%s", iptcApplication2List->name_,
310 _get_exiv2_type(iptcApplication2List->type_),
311 iptcApplication2List->repeatable_ ? "-R" : "");
312 exiv2_taglist = g_list_prepend(exiv2_taglist, tag);
313 iptcApplication2List++;
314 }
315
318 _get_xmp_tags("xmpRights", &exiv2_taglist);
319 _get_xmp_tags("xmpMM", &exiv2_taglist);
320 _get_xmp_tags("xmpBJ", &exiv2_taglist);
321 _get_xmp_tags("xmpTPg", &exiv2_taglist);
322 _get_xmp_tags("xmpDM", &exiv2_taglist);
324 _get_xmp_tags("photoshop", &exiv2_taglist);
328 _get_xmp_tags("exifEX", &exiv2_taglist);
331 _get_xmp_tags("iptcExt", &exiv2_taglist);
333 _get_xmp_tags("mwg-rs", &exiv2_taglist);
334 _get_xmp_tags("mwg-kw", &exiv2_taglist);
336 _get_xmp_tags("dcterms", &exiv2_taglist);
337 _get_xmp_tags("digiKam", &exiv2_taglist);
339 _get_xmp_tags("GPano", &exiv2_taglist);
343 _get_xmp_tags("MPReg", &exiv2_taglist);
344 _get_xmp_tags("acdsee", &exiv2_taglist);
345 _get_xmp_tags("mediapro", &exiv2_taglist);
346 _get_xmp_tags("expressionmedia", &exiv2_taglist);
347 _get_xmp_tags("MicrosoftPhoto", &exiv2_taglist);
348 }
349 catch (Exiv2::AnyError& e)
350 {
351 std::string s(e.what());
352 std::cerr << "[exiv2 taglist] " << s << std::endl;
353 }
354}
355
357{
358 if(!exiv2_taglist)
360 return exiv2_taglist;
361}
362
363static const char *_exif_get_exiv2_tag_type(const char *tagname)
364{
365 if(IS_NULL_PTR(tagname)) return NULL;
366 for(GList *tag = exiv2_taglist; tag; tag = g_list_next(tag))
367 {
368 char *t = (char *)tag->data;
369 if(g_str_has_prefix(t, tagname) && t[strlen(tagname)] == ',')
370 if(t)
371 {
372 t += strlen(tagname) + 1;
373 return t;
374 }
375 }
376 return NULL;
377}
378
379// exiv2's readMetadata is not thread safe in 0.26. so we lock it. since readMetadata might throw an exception we
380// wrap it into some c++ magic to make sure we unlock in all cases. well, actually not magic but basic raii.
381// FIXME: check again once we rely on 0.27
388
389#define read_metadata_threadsafe(image) \
390{ \
391 Lock lock; \
392 image->readMetadata(); \
393}
394
395static void _exif_import_tags(dt_image_t *img, Exiv2::XmpData::iterator &pos);
396static void read_xmp_timestamps(Exiv2::XmpData &xmpData, dt_image_t *img, const int xmp_version);
397
398// this array should contain all XmpBag and XmpSeq keys used by dt
399const char *dt_xmp_keys[]
400 = { "Xmp.dc.subject", "Xmp.lr.hierarchicalSubject", "Xmp.darktable.colorlabels", "Xmp.darktable.history",
401 "Xmp.darktable.history_modversion", "Xmp.darktable.history_enabled", "Xmp.darktable.history_end",
402 "Xmp.darktable.iop_order_version", "Xmp.darktable.iop_order_list",
403 "Xmp.darktable.history_operation", "Xmp.darktable.history_params", "Xmp.darktable.blendop_params",
404 "Xmp.darktable.blendop_version", "Xmp.darktable.multi_priority", "Xmp.darktable.multi_name",
405 "Xmp.darktable.iop_order",
406 "Xmp.darktable.xmp_version", "Xmp.darktable.raw_params", "Xmp.darktable.auto_presets_applied",
407 "Xmp.darktable.mask_id", "Xmp.darktable.mask_type", "Xmp.darktable.mask_name",
408 "Xmp.darktable.masks_history", "Xmp.darktable.mask_num", "Xmp.darktable.mask_points",
409 "Xmp.darktable.mask_version", "Xmp.darktable.mask", "Xmp.darktable.mask_nb", "Xmp.darktable.mask_src",
410 "Xmp.darktable.history_basic_hash", "Xmp.darktable.history_auto_hash", "Xmp.darktable.history_current_hash",
411 "Xmp.darktable.import_timestamp", "Xmp.darktable.change_timestamp",
412 "Xmp.darktable.export_timestamp", "Xmp.darktable.print_timestamp",
413 "Xmp.acdsee.notes", "Xmp.darktable.version_name",
414 "Xmp.dc.creator", "Xmp.dc.publisher", "Xmp.dc.title", "Xmp.dc.description", "Xmp.dc.rights",
415 "Xmp.xmpMM.DerivedFrom" };
416
417static const guint dt_xmp_keys_n = G_N_ELEMENTS(dt_xmp_keys); // the number of XmpBag XmpSeq keys that dt uses
418
419// inspired by ufraw_exiv2.cc:
420
421static void dt_strlcpy_to_utf8(char *dest, size_t dest_max, Exiv2::ExifData::const_iterator &pos,
422 Exiv2::ExifData &exifData)
423{
424 std::string str = pos->print(&exifData);
425
426 char *s = g_locale_to_utf8(str.c_str(), str.length(), NULL, NULL, NULL);
427 if(!IS_NULL_PTR(s))
428 {
429 g_strlcpy(dest, s, dest_max);
430 dt_free(s);
431 }
432 else
433 {
434 g_strlcpy(dest, str.c_str(), dest_max);
435 }
436}
437
438// function to remove known dt keys and subtrees from xmpdata, so not to append them twice
439// this should work because dt first reads all known keys
440static void dt_remove_known_keys(Exiv2::XmpData &xmp)
441{
442 xmp.sortByKey();
443 for(unsigned int i = 0; i < dt_xmp_keys_n; i++)
444 {
445 Exiv2::XmpData::iterator pos = xmp.findKey(Exiv2::XmpKey(dt_xmp_keys[i]));
446
447 while(pos != xmp.end())
448 {
449 std::string key = pos->key();
450 const char *ckey = key.c_str();
451 size_t len = key.size();
452 // stop iterating once the key no longer matches what we are trying to delete. this assumes sorted input
453 if(!(g_str_has_prefix(ckey, dt_xmp_keys[i]) && (ckey[len] == '[' || ckey[len] == '\0')))
454 break;
455 pos = xmp.erase(pos);
456 }
457 }
458}
459
460static void dt_remove_exif_keys(Exiv2::ExifData &exif, const char *keys[], unsigned int n_keys)
461{
462 for(unsigned int i = 0; i < n_keys; i++)
463 {
464 try
465 {
466 Exiv2::ExifData::iterator pos;
467 while((pos = exif.findKey(Exiv2::ExifKey(keys[i]))) != exif.end())
468 exif.erase(pos);
469 }
470 catch(Exiv2::AnyError &e)
471 {
472 // the only exception we may get is "invalid" tag, which is not
473 // important enough to either stop the function, or even display
474 // a message (it's probably the tag is not implemented in the
475 // exiv2 version used)
476 }
477 }
478}
479
480static void dt_remove_xmp_keys(Exiv2::XmpData &xmp, const char *keys[], unsigned int n_keys)
481{
482 for(unsigned int i = 0; i < n_keys; i++)
483 {
484 try
485 {
486 Exiv2::XmpData::iterator pos;
487 while((pos = xmp.findKey(Exiv2::XmpKey(keys[i]))) != xmp.end())
488 xmp.erase(pos);
489 }
490 catch(Exiv2::AnyError &e)
491 {
492 // the only exception we may get is "invalid" tag, which is not
493 // important enough to either stop the function, or even display
494 // a message (it's probably the tag is not implemented in the
495 // exiv2 version used)
496 }
497 }
498}
499
500static bool dt_exif_read_xmp_tag(Exiv2::XmpData &xmpData, Exiv2::XmpData::iterator *pos, string key)
501{
502 try
503 {
504 return (*pos = xmpData.findKey(Exiv2::XmpKey(key))) != xmpData.end() && (*pos)->size();
505 }
506 catch(Exiv2::AnyError &e)
507 {
508 std::string s(e.what());
509 std::cerr << "[exiv2 read_xmp_tag] " << s << std::endl;
510 return false;
511 }
512}
513#define FIND_XMP_TAG(key) dt_exif_read_xmp_tag(xmpData, &pos, key)
514
515
516// FIXME: according to http://www.exiv2.org/doc/classExiv2_1_1Metadatum.html#63c2b87249ba96679c29e01218169124
517// there is no need to pass xmpData
518// version = -1 -> version ignored
519static bool _exif_decode_xmp_data(dt_image_t *img, Exiv2::XmpData &xmpData, int version,
520 bool exif_read)
521{
522 // as this can be called several times during the image lifetime, clean up first
523 GList *imgs = NULL;
524 imgs = g_list_prepend(imgs, GINT_TO_POINTER(img->id));
525 try
526 {
527 Exiv2::XmpData::iterator pos;
528
529 // older darktable version did not write this data correctly:
530 // the reasoning behind strdup'ing all the strings before passing it to sqlite3 is, that
531 // they are somehow corrupt after the call to sqlite3_prepare_v2() -- don't ask me
532 // why for they don't get passed to that function.
533 if(version == -1 || version > 0)
534 {
535 if(!exif_read) dt_metadata_clear(imgs, FALSE);
536 for(unsigned int i = 0; i < DT_METADATA_NUMBER; i++)
537 {
538 const gchar *key = dt_metadata_get_key(i);
539 if(FIND_XMP_TAG(key))
540 {
541 char *value = strdup(pos->toString().c_str());
542 char *adr = value;
543 // skip any lang="" or charset=xxx
544 while(!strncmp(value, "lang=", 5) || !strncmp(value, "charset=", 8))
545 {
546 while(*value != ' ' && *value) value++;
547 while(*value == ' ') value++;
548 }
550 dt_free(adr);
551 }
552 }
553 }
554
555 if(FIND_XMP_TAG("Xmp.xmp.Rating"))
556 {
557 const int stars = pos->toLong();
558 dt_image_set_xmp_rating(img, stars);
559 }
560 else
562
563 if(!exif_read) dt_colorlabels_remove_labels(img->id);
564 if(FIND_XMP_TAG("Xmp.xmp.Label"))
565 {
566 std::string label = pos->toString();
567 if(label == "Red") // Is it really called like that in XMP files?
569 else if(label == "Yellow") // Is it really called like that in XMP files?
571 else if(label == "Green")
573 else if(label == "Blue") // Is it really called like that in XMP files?
575 else if(label == "Purple") // Is it really called like that in XMP files?
577 }
578 // if Xmp.xmp.Label not managed from an external app use dt colors
579 else if(FIND_XMP_TAG("Xmp.darktable.colorlabels"))
580 {
581 // color labels
582 const int cnt = pos->count();
583 for(int i = 0; i < cnt; i++)
584 {
585 dt_colorlabels_set_label(img->id, pos->toLong(i));
586 }
587 }
588
589 if((dt_image_get_xmp_mode()) ||
590 dt_conf_get_bool("ui_last/import_last_tags_imported"))
591 {
592 GList *tags = NULL;
593 // preserve dt tags which are not saved in xmp file
594 if(!exif_read) dt_tag_set_tags(tags, imgs, TRUE, TRUE, FALSE);
595 if(FIND_XMP_TAG("Xmp.lr.hierarchicalSubject"))
596 _exif_import_tags(img, pos);
597 else if(FIND_XMP_TAG("Xmp.dc.subject"))
598 _exif_import_tags(img, pos);
599 }
600
601 /* read gps location */
602 if(FIND_XMP_TAG("Xmp.exif.GPSLatitude"))
603 {
604 img->geoloc.latitude = dt_util_gps_string_to_number(pos->toString().c_str());
605 }
606
607 if(FIND_XMP_TAG("Xmp.exif.GPSLongitude"))
608 {
609 img->geoloc.longitude = dt_util_gps_string_to_number(pos->toString().c_str());
610 }
611
612 if(FIND_XMP_TAG("Xmp.exif.GPSAltitude"))
613 {
614 Exiv2::XmpData::const_iterator ref = xmpData.findKey(Exiv2::XmpKey("Xmp.exif.GPSAltitudeRef"));
615 if(ref != xmpData.end() && ref->size())
616 {
617 std::string sign_str = ref->toString();
618 const char *sign = sign_str.c_str();
619 double elevation = 0.0;
620 if(dt_util_gps_elevation_to_number(pos->toRational(0).first, pos->toRational(0).second, sign[0], &elevation))
621 img->geoloc.elevation = elevation;
622 }
623 }
624
625 /* read lens type from Xmp.exifEX.LensModel */
626 if(FIND_XMP_TAG("Xmp.exifEX.LensModel"))
627 {
628 // lens model
629 char *lens = strdup(pos->toString().c_str());
630 char *adr = lens;
631 if(strncmp(lens, "lang=", 5) == 0)
632 {
633 lens = strchr(lens, ' ');
634 if(!IS_NULL_PTR(lens)) lens++;
635 }
636 // no need to do any Unicode<->locale conversion, the field is specified as ASCII
637 g_strlcpy(img->exif_lens, lens, sizeof(img->exif_lens));
638 dt_free(adr);
639 }
640
641 /* read timestamp from Xmp.exif.DateTimeOriginal */
642 if(FIND_XMP_TAG("Xmp.exif.DateTimeOriginal")
643 || FIND_XMP_TAG("Xmp.photoshop.DateCreated"))
644 {
645 char *datetime = strdup(pos->toString().c_str());
646 if(datetime[0] != '\0') dt_datetime_exif_to_img(img, datetime);
647 dt_free(datetime);
648 }
649
650 if(imgs)
651 {
652 g_list_free(imgs);
653 imgs = NULL;
654 }
655 imgs = NULL;
656 return true;
657 }
658 catch(Exiv2::AnyError &e)
659 {
660 if(imgs)
661 {
662 g_list_free(imgs);
663 imgs = NULL;
664 }
665 imgs = NULL;
666 std::string s(e.what());
667 std::cerr << "[exiv2 _exif_decode_xmp_data] " << img->filename << ": " << s << std::endl;
668 return false;
669 }
670}
671
672static bool dt_exif_read_iptc_tag(Exiv2::IptcData &iptcData, Exiv2::IptcData::const_iterator *pos, string key)
673{
674 try
675 {
676 return (*pos = iptcData.findKey(Exiv2::IptcKey(key))) != iptcData.end() && (*pos)->size();
677 }
678 catch(Exiv2::AnyError &e)
679 {
680 std::string s(e.what());
681 std::cerr << "[exiv2 read_iptc_tag] " << s << std::endl;
682 return false;
683 }
684}
685#define FIND_IPTC_TAG(key) dt_exif_read_iptc_tag(iptcData, &pos, key)
686
687
688// FIXME: according to http://www.exiv2.org/doc/classExiv2_1_1Metadatum.html#63c2b87249ba96679c29e01218169124
689// there is no need to pass iptcData
690static bool _exif_decode_iptc_data(dt_image_t *img, Exiv2::IptcData &iptcData)
691{
692 try
693 {
694 Exiv2::IptcData::const_iterator pos;
695 iptcData.sortByKey(); // this helps to quickly find all Iptc.Application2.Keywords
696
697 if((pos = iptcData.findKey(Exiv2::IptcKey("Iptc.Application2.Keywords"))) != iptcData.end())
698 {
699 while(pos != iptcData.end())
700 {
701 std::string key = pos->key();
702 if(g_strcmp0(key.c_str(), "Iptc.Application2.Keywords")) break;
703 std::string str = pos->print();
704 char *tag = dt_util_foo_to_utf8(str.c_str());
705 guint tagid = 0;
706 dt_tag_new(tag, &tagid);
707 dt_tag_attach(tagid, img->id, FALSE, FALSE);
708 dt_free(tag);
709 ++pos;
710 }
712 }
713 if(FIND_IPTC_TAG("Iptc.Application2.Caption"))
714 {
715 std::string str = pos->print(/*&iptcData*/);
716 dt_metadata_set_import(img->id, "Xmp.dc.description", str.c_str());
717 }
718 if(FIND_IPTC_TAG("Iptc.Application2.Copyright"))
719 {
720 std::string str = pos->print(/*&iptcData*/);
721 dt_metadata_set_import(img->id, "Xmp.dc.rights", str.c_str());
722 }
723 if(FIND_IPTC_TAG("Iptc.Application2.Byline"))
724 {
725 std::string str = pos->print(/*&iptcData*/);
726 dt_metadata_set_import(img->id, "Xmp.dc.creator", str.c_str());
727 }
728 else if(FIND_IPTC_TAG("Iptc.Application2.Writer"))
729 {
730 std::string str = pos->print(/*&iptcData*/);
731 dt_metadata_set_import(img->id, "Xmp.dc.creator", str.c_str());
732 }
733 else if(FIND_IPTC_TAG("Iptc.Application2.Contact"))
734 {
735 std::string str = pos->print(/*&iptcData*/);
736 dt_metadata_set_import(img->id, "Xmp.dc.creator", str.c_str());
737 }
738 if(FIND_IPTC_TAG("Iptc.Application2.DateCreated"))
739 {
740 // exiv2 already converts IPTC date and time into ISO 8601 format
741 GString *datetime = g_string_new(pos->toString().c_str());
742
743 datetime = g_string_append(datetime, "T");
744 if(FIND_IPTC_TAG("Iptc.Application2.TimeCreated"))
745 {
746 gchar *time = g_strdup(pos->toString().c_str());
747 datetime = g_string_append(datetime, time);
748 dt_free(time);
749 }
750 else
751 datetime = g_string_append(datetime, "00:00:00");
752
753 if(datetime->str[0] != '\0') dt_datetime_exif_to_img(img, datetime->str);
754 g_string_free(datetime, TRUE);
755 }
756
757 return true;
758 }
759 catch(Exiv2::AnyError &e)
760 {
761 std::string s(e.what());
762 std::cerr << "[exiv2 _exif_decode_iptc_data] " << img->filename << ": " << s << std::endl;
763 return false;
764 }
765}
766
767static bool _exif_read_exif_tag(Exiv2::ExifData &exifData,
768 Exiv2::ExifData::const_iterator *pos, string key)
769{
770 try
771 {
772 return (*pos = exifData.findKey(Exiv2::ExifKey(key)))
773 != exifData.end() && (*pos)->size();
774 }
775 catch(Exiv2::AnyError &e)
776 {
777 std::string s(e.what());
778 std::cerr << "[exiv2 read_exif_tag] " << s << std::endl;
779 return false;
780 }
781}
782#define FIND_EXIF_TAG(key) _exif_read_exif_tag(exifData, &pos, key)
783
784// Support DefaultUserCrop, what is the safe exif tag?
785// DefaultUserCrop is known by name only from 0.27.4
786// Magic-nr taken from dng specs, the specs also say it has 4 floats (top,left,bottom,right
787// We only take them if a) we find a value != the default *and* b) data are plausible
788static bool _check_usercrop(Exiv2::ExifData &exifData, dt_image_t *img)
789{
790 Exiv2::ExifData::const_iterator pos =
791 exifData.findKey(Exiv2::ExifKey("Exif.SubImage1.0xc7b5"));
792 // DNGs without an embedded preview have the raw image tags under
793 // Exif.Image instead of Exif.SubImage1
794 if(pos == exifData.end())
795 pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.0xc7b5"));
796 if(pos != exifData.end() && pos->count() == 4 && pos->size())
797 {
798 dt_boundingbox_t crop;
799 for(int i = 0; i < 4; i++) crop[i] = pos->toFloat(i);
800 if(((crop[0] > 0)
801 ||(crop[1] > 0)
802 ||(crop[2] < 1)
803 ||(crop[3] < 1))
804 && (crop[2] - crop[0] > 0.05f)
805 && (crop[3] - crop[1] > 0.05f))
806 {
807 for (int i=0; i<4; i++) img->usercrop[i] = crop[i];
808 return TRUE;
809 }
810 }
811 return FALSE;
812}
813
814static gboolean _check_dng_opcodes(Exiv2::ExifData &exifData, dt_image_t *img)
815{
816 gboolean has_opcodes = FALSE;
817 Exiv2::ExifData::const_iterator pos = exifData.findKey(Exiv2::ExifKey("Exif.SubImage1.OpcodeList2"));
818 // DNGs without an embedded preview have the opcodes under Exif.Image instead of Exif.SubImage1
819 if(pos == exifData.end())
820 pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.OpcodeList2"));
821 if(pos != exifData.end())
822 {
823 uint8_t *data = (uint8_t *)g_malloc(pos->size());
824 pos->copy(data, Exiv2::invalidByteOrder);
825 dt_dng_opcode_process_opcode_list_2(data, pos->size(), img);
826 dt_free(data);
827 has_opcodes = TRUE;
828 }
829 else
830 {
831 dt_vprint(DT_DEBUG_IMAGEIO, "DNG OpcodeList2 tag not found\n");
832 }
833 return has_opcodes;
834}
835
836void dt_exif_img_check_additional_tags(dt_image_t *img, const char *filename)
837{
838 try
839 {
840 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(WIDEN(filename)));
841 assert(image.get() != 0);
843 Exiv2::ExifData &exifData = image->exifData();
844 if(!exifData.empty())
845 {
846 _check_usercrop(exifData, img);
847 _check_dng_opcodes(exifData, img);
848 // _check_lens_correction_data(exifData, img);
849 }
850 return;
851 }
852 catch(Exiv2::AnyError &e)
853 {
854 std::string s(e.what());
855 std::cerr << "[exiv2 reading DefaultUserCrop] " << filename << ": " << s << std::endl;
856 return;
857 }
858}
859
860static void _find_datetime_taken(Exiv2::ExifData &exifData,
861 Exiv2::ExifData::const_iterator pos,
862 char *exif_datetime_taken)
863{
864 if((FIND_EXIF_TAG("Exif.Image.DateTimeOriginal") || FIND_EXIF_TAG("Exif.Photo.DateTimeOriginal"))
865 && pos->size() == DT_DATETIME_EXIF_LENGTH)
866 {
867 dt_strlcpy_to_utf8(exif_datetime_taken, DT_DATETIME_EXIF_LENGTH, pos, exifData);
868 if(FIND_EXIF_TAG("Exif.Photo.SubSecTimeOriginal")
869 && pos->size() > 1)
870 {
871 char msec[4];
872 dt_strlcpy_to_utf8(msec, sizeof(msec), pos, exifData);
873 dt_datetime_add_subsec_to_exif(exif_datetime_taken, DT_DATETIME_LENGTH, msec);
874 }
875 }
876 else
877 {
878 *exif_datetime_taken = '\0';
879 }
880}
881
882static void _find_exif_maker(Exiv2::ExifData &exifData,
883 Exiv2::ExifData::const_iterator pos,
884 char *maker,
885 const size_t m_size)
886{
887 // look for maker & model first so we can use that info later
888 if(FIND_EXIF_TAG("Exif.Image.Make"))
889 {
890 dt_strlcpy_to_utf8(maker, m_size, pos, exifData);
891 }
892 else if(FIND_EXIF_TAG("Exif.PanasonicRaw.Make"))
893 {
894 dt_strlcpy_to_utf8(maker, m_size, pos, exifData);
895 }
896
897 for(char *c = maker + m_size - 1; c > maker; c--)
898 if(*c != ' ' && *c != '\0')
899 {
900 *(c + 1) = '\0';
901 break;
902 }
903}
904
905static void _find_exif_model(Exiv2::ExifData &exifData,
906 Exiv2::ExifData::const_iterator pos,
907 char *model,
908 const size_t m_size)
909{
910 if(FIND_EXIF_TAG("Exif.Image.Model"))
911 {
912 dt_strlcpy_to_utf8(model, m_size, pos, exifData);
913 }
914 else if(FIND_EXIF_TAG("Exif.PanasonicRaw.Model"))
915 {
916 dt_strlcpy_to_utf8(model, m_size, pos, exifData);
917 }
918
919 for(char *c = model + m_size - 1; c > model; c--)
920 if(*c != ' ' && *c != '\0')
921 {
922 *(c + 1) = '\0';
923 break;
924 }
925}
926
927static bool _exif_decode_exif_data(dt_image_t *img, Exiv2::ExifData &exifData)
928{
929 try
930 {
931 /* List of tag names taken from exiv2's printSummary() in actions.cpp */
932 Exiv2::ExifData::const_iterator pos;
933
934 _find_exif_maker(exifData, pos, img->exif_maker, sizeof(img->exif_maker));
935 _find_exif_model(exifData, pos, img->exif_model, sizeof(img->exif_model));
936
937 // Make sure we copy the exif make and model to the correct place if needed
939
940 /* Read shutter time */
941 if((pos = Exiv2::exposureTime(exifData)) != exifData.end() && pos->size())
942 {
943 img->exif_exposure = pos->toFloat();
944 }
945 else if(FIND_EXIF_TAG("Exif.Photo.ShutterSpeedValue") || FIND_EXIF_TAG("Exif.Image.ShutterSpeedValue"))
946 {
947 // uf_strlcpy_to_utf8(uf->conf->shutterText, max_name, pos, exifData);
948 img->exif_exposure = exp2f(-1.0f * pos->toFloat()); // convert from APEX value
949 }
950
951 // Read exposure bias
952 if(FIND_EXIF_TAG("Exif.Photo.ExposureBiasValue") || FIND_EXIF_TAG("Exif.Image.ExposureBiasValue"))
953 {
954 img->exif_exposure_bias = pos->toFloat();
955 }
956
957 /* Read aperture */
958 if((pos = Exiv2::fNumber(exifData)) != exifData.end() && pos->size())
959 {
960 img->exif_aperture = pos->toFloat();
961 }
962 else if(FIND_EXIF_TAG("Exif.Photo.ApertureValue") || FIND_EXIF_TAG("Exif.Image.ApertureValue"))
963 {
964 img->exif_aperture = exp2f(pos->toFloat() / 2.0f); // convert from APEX value
965 }
966
967 /* Read ISO speed - Nikon happens to return a pair for Lo and Hi modes */
968 if((pos = Exiv2::isoSpeed(exifData)) != exifData.end() && pos->size())
969 {
970 // if standard exif iso tag, use the old way of interpreting the return value to be more regression-save
971 if(strcmp(pos->key().c_str(), "Exif.Photo.ISOSpeedRatings") == 0)
972 {
973 int isofield = pos->count() > 1 ? 1 : 0;
974 img->exif_iso = pos->toFloat(isofield);
975 }
976 else
977 {
978 std::string str = pos->print();
979 img->exif_iso = (float)std::atof(str.c_str());
980 }
981 }
982 // some newer cameras support iso settings that exceed the 16 bit of exif's ISOSpeedRatings
983 if(img->exif_iso == 65535 || img->exif_iso == 0)
984 {
985 if(FIND_EXIF_TAG("Exif.PentaxDng.ISO") || FIND_EXIF_TAG("Exif.Pentax.ISO"))
986 {
987 std::string str = pos->print();
988 img->exif_iso = (float)std::atof(str.c_str());
989 }
990 else if((!g_strcmp0(img->exif_maker, "SONY") || !g_strcmp0(img->exif_maker, "Canon"))
991 && FIND_EXIF_TAG("Exif.Photo.RecommendedExposureIndex"))
992 {
993 img->exif_iso = pos->toFloat();
994 }
995 }
996
997 /* Read focal length */
998 if((pos = Exiv2::focalLength(exifData)) != exifData.end() && pos->size())
999 {
1000 // This works around a bug in exiv2 the developers refuse to fix
1001 // For details see http://dev.exiv2.org/issues/1083
1002 if (pos->key() == "Exif.Canon.FocalLength" && pos->count() == 4)
1003 img->exif_focal_length = pos->toFloat(1);
1004 else
1005 img->exif_focal_length = pos->toFloat();
1006 }
1007
1008 // Read focal length in 35mm if available and try to calculate crop factor.
1009 if(FIND_EXIF_TAG("Exif.Photo.FocalLengthIn35mmFilm"))
1010 {
1011 const float focal_length_35mm = pos->toFloat();
1012 if(focal_length_35mm > 0.0f && img->exif_focal_length > 0.0f)
1013 img->exif_crop = focal_length_35mm / img->exif_focal_length;
1014 else
1015 img->exif_crop = 0.0f;
1016 }
1017
1018 // If the tag for the equivalent focal length is missing or contains zero,
1019 // let's try to get the crop factor by calculating the diagonal of the sensor:
1020 if(img->exif_crop == 0.0f && FIND_EXIF_TAG("Exif.Photo.FocalPlaneXResolution"))
1021 {
1022 float x_resolution = pos->toFloat();
1023 float y_resolution = 0.0f;
1024 if(FIND_EXIF_TAG("Exif.Photo.FocalPlaneYResolution"))
1025 y_resolution = pos->toFloat();
1026 guint res_unit = 1;
1027 if(FIND_EXIF_TAG("Exif.Photo.FocalPlaneResolutionUnit"))
1028 res_unit = pos->toLong();
1029 if(res_unit == 2) // inch
1030 {
1031 x_resolution /= 25.4f;
1032 y_resolution /= 25.4f;
1033 }
1034 else
1035 if(res_unit == 3) // centimeter
1036 {
1037 x_resolution /= 10.0f;
1038 y_resolution /= 10.0f;
1039 }
1040 guint image_width = 0;
1041 guint image_height = 0;
1042 // We are entering the zoo of image dimensions metadata.
1043 // Let's first try the Exif way of telling dimensions.
1044 // For Canon and Sigma cameras, these are the valid raw image
1045 // dimensions matching the the resolution tags.
1046 // For Fujifilm cameras, this will get the pixel dimensions
1047 // of the preview, not the sensor, because that's what the data
1048 // in the resolution tags on most Fujifilm cameras seems to be
1049 // calculated for.
1050 if(FIND_EXIF_TAG("Exif.Photo.PixelXDimension"))
1051 image_width = pos->toLong();
1052 if(FIND_EXIF_TAG("Exif.Photo.PixelYDimension"))
1053 image_height = pos->toLong();
1054 // Then try the Adobe DNG way of telling dimensions.
1055 // Exif.Image.ImageWidth/Length tags are also present in DNG files,
1056 // but may contain the pixel dimensions of the preview image, which in
1057 // this case will cause the diagonal calculation to be incorrect.
1058 if(image_width == 0 && FIND_EXIF_TAG("Exif.SubImage1.NewSubfileType"))
1059 {
1060 if(pos->toLong() == 0) // Primary image
1061 {
1062 if(FIND_EXIF_TAG("Exif.SubImage1.ImageWidth"))
1063 image_width = pos->toLong();
1064 if(FIND_EXIF_TAG("Exif.SubImage1.ImageLength"))
1065 image_height = pos->toLong();
1066 }
1067 }
1068 // The following tags in certain formats may contain pixel dimensions of
1069 // the preview instead of the full image, while resolution is calculated
1070 // relative to the full image dimensions. So we check them last.
1071 if(image_width == 0)
1072 {
1073 if(FIND_EXIF_TAG("Exif.Image.ImageWidth"))
1074 image_width = pos->toLong();
1075 if(FIND_EXIF_TAG("Exif.Image.ImageLength"))
1076 image_height = pos->toLong();
1077 }
1078
1079 const float x_size_mm = (float)image_width / x_resolution;
1080 const float y_size_mm = (float)image_height / y_resolution;
1081 if(image_width && image_height) // We've got the data and can calculate the crop factor
1082 {
1083 const float sensor_diagonal = dt_fast_hypotf(x_size_mm, y_size_mm);
1084 const float fullframe_diagonal = dt_fast_hypotf(36.0f, 24.0f);
1085 img->exif_crop = fullframe_diagonal / sensor_diagonal;
1086 }
1087 else
1088 img->exif_crop = 0.0f; // Will be shown as "no data" in the image information module
1089 }
1090
1091 if(_check_usercrop(exifData, img))
1092 {
1094 guint tagid = 0;
1095 char tagname[64];
1096 snprintf(tagname, sizeof(tagname), "darktable|mode|exif-crop");
1097 dt_tag_new(tagname, &tagid);
1098 dt_tag_attach(tagid, img->id, FALSE, FALSE);
1099 }
1100
1101 if(_check_dng_opcodes(exifData, img))
1102 {
1104 }
1105
1106 /*
1107 * Get the focus distance in meters.
1108 */
1109 if(Exiv2::testVersion(0, 27, 4) && FIND_EXIF_TAG("Exif.NikonLd4.LensID") && pos->toLong() != 0)
1110 {
1111 // Z lens, need to specifically look for the second instance of Exif.NikonLd4.FocusDistance
1112 // unless using Exiv2 0.28.x and later (also expanded to 2 bytes of precision since 0.28.1).
1113#if EXIV2_TEST_VERSION(0, 28, 0)
1114 if(FIND_EXIF_TAG("Exif.NikonLd4.FocusDistance2"))
1115 {
1116 float value = pos->toFloat();
1117 if(Exiv2::testVersion(0, 28, 1)) value /= 256.0f;
1118#else
1119 pos = exifData.end();
1120 for(auto it = exifData.begin(); it != exifData.end(); it++)
1121 {
1122 if(it->key() == "Exif.NikonLd4.FocusDistance") pos = it;
1123 }
1124 if(pos != exifData.end() && pos->size())
1125 {
1126 float value = pos->toFloat();
1127#endif
1128 img->exif_focus_distance = 0.01f * pow(10.0f, value / 40.0f);
1129 }
1130 }
1131 else if(FIND_EXIF_TAG("Exif.NikonLd2.FocusDistance") || FIND_EXIF_TAG("Exif.NikonLd3.FocusDistance")
1132 || (Exiv2::testVersion(0, 27, 4) && FIND_EXIF_TAG("Exif.NikonLd4.FocusDistance")))
1133 {
1134 float value = pos->toFloat();
1135 img->exif_focus_distance = 0.01f * pow(10.0f, value / 40.0f);
1136 }
1137 else if(FIND_EXIF_TAG("Exif.OlympusFi.FocusDistance"))
1138 {
1139 /* the distance is stored as a rational (fraction). according to
1140 * http://www.dpreview.com/forums/thread/1173960?page=4
1141 * some Olympus cameras have a wrong denominator of 10 in there while the nominator is always in mm.
1142 * thus we ignore the denominator
1143 * and divide with 1000.
1144 * "I've checked a number of E-1 and E-300 images, and I agree that the FocusDistance looks like it is
1145 * in mm for the E-1. However,
1146 * it looks more like cm for the E-300.
1147 * For both cameras, this value is stored as a rational. With the E-1, the denominator is always 1,
1148 * while for the E-300 it is 10.
1149 * Therefore, it looks like the numerator in both cases is in mm (which makes a bit of sense, in an odd
1150 * sort of way). So I think
1151 * what I will do in ExifTool is to take the numerator and divide by 1000 to display the focus distance
1152 * in meters."
1153 * -- Boardhead, dpreview forums in 2005
1154 */
1155 int nominator = pos->toRational(0).first;
1156 img->exif_focus_distance = fmax(0.0, (0.001 * nominator));
1157 }
1158 else if(FIND_EXIF_TAG("Exif.CanonFi.FocusDistanceUpper"))
1159 {
1160 const float FocusDistanceUpper = pos->toFloat();
1161 if(FocusDistanceUpper <= 0.0f || (int)FocusDistanceUpper >= 0xffff)
1162 {
1163 img->exif_focus_distance = 0.0f;
1164 }
1165 else
1166 {
1167 img->exif_focus_distance = FocusDistanceUpper / 100.0;
1168 if(FIND_EXIF_TAG("Exif.CanonFi.FocusDistanceLower"))
1169 {
1170 const float FocusDistanceLower = pos->toFloat();
1171 if(FocusDistanceLower > 0.0f && (int)FocusDistanceLower < 0xffff)
1172 {
1173 img->exif_focus_distance += FocusDistanceLower / 100.0;
1174 img->exif_focus_distance /= 2.0;
1175 }
1176 }
1177 }
1178 }
1179 else if(FIND_EXIF_TAG("Exif.CanonSi.SubjectDistance"))
1180 {
1181 img->exif_focus_distance = pos->toFloat() / 100.0;
1182 }
1183 else if((pos = Exiv2::subjectDistance(exifData)) != exifData.end() && pos->size())
1184 {
1185 img->exif_focus_distance = pos->toFloat();
1186 }
1187 else if(Exiv2::testVersion(0,27,2) && FIND_EXIF_TAG("Exif.Sony2Fp.FocusPosition2"))
1188 {
1189 const float focus_position = pos->toFloat();
1190
1191 if (focus_position && FIND_EXIF_TAG("Exif.Photo.FocalLengthIn35mmFilm")) {
1192 const float focal_length_35mm = pos->toFloat();
1193
1194 /* http://u88.n24.queensu.ca/exiftool/forum/index.php/topic,3688.msg29653.html#msg29653 */
1195 img->exif_focus_distance = (pow(2, focus_position / 16 - 5) + 1) * focal_length_35mm / 1000;
1196 }
1197 }
1198
1199 /*
1200 * Read image orientation
1201 */
1202 if(FIND_EXIF_TAG("Exif.Image.Orientation"))
1203 {
1204 img->orientation = dt_image_orientation_to_flip_bits(pos->toLong());
1205 }
1206 else if(FIND_EXIF_TAG("Exif.PanasonicRaw.Orientation"))
1207 {
1208 img->orientation = dt_image_orientation_to_flip_bits(pos->toLong());
1209 }
1210 /* for e.g. Sinar backs the raw orientation is in a different subdirectory */
1211 if(FIND_EXIF_TAG("Exif.Thumbnail.PhotometricInterpretation") && (32803 == pos->toLong())
1212 && FIND_EXIF_TAG("Exif.Thumbnail.Orientation"))
1213 {
1214 img->orientation = dt_image_orientation_to_flip_bits(pos->toLong());
1215 }
1216
1217 /* read gps location */
1218 if(FIND_EXIF_TAG("Exif.GPSInfo.GPSLatitude"))
1219 {
1220 Exiv2::ExifData::const_iterator ref = exifData.findKey(Exiv2::ExifKey("Exif.GPSInfo.GPSLatitudeRef"));
1221 if(ref != exifData.end() && ref->size() && pos->count() == 3)
1222 {
1223 std::string sign_str = ref->toString();
1224 const char *sign = sign_str.c_str();
1225 double latitude = 0.0;
1226 if(dt_util_gps_rationale_to_number(pos->toRational(0).first, pos->toRational(0).second,
1227 pos->toRational(1).first, pos->toRational(1).second,
1228 pos->toRational(2).first, pos->toRational(2).second, sign[0], &latitude))
1229 img->geoloc.latitude = latitude;
1230 }
1231 }
1232
1233 if(FIND_EXIF_TAG("Exif.GPSInfo.GPSLongitude"))
1234 {
1235 Exiv2::ExifData::const_iterator ref = exifData.findKey(Exiv2::ExifKey("Exif.GPSInfo.GPSLongitudeRef"));
1236 if(ref != exifData.end() && ref->size() && pos->count() == 3)
1237 {
1238 std::string sign_str = ref->toString();
1239 const char *sign = sign_str.c_str();
1240 double longitude = 0.0;
1241 if(dt_util_gps_rationale_to_number(pos->toRational(0).first, pos->toRational(0).second,
1242 pos->toRational(1).first, pos->toRational(1).second,
1243 pos->toRational(2).first, pos->toRational(2).second, sign[0], &longitude))
1244 img->geoloc.longitude = longitude;
1245 }
1246 }
1247
1248 if(FIND_EXIF_TAG("Exif.GPSInfo.GPSAltitude"))
1249 {
1250 Exiv2::ExifData::const_iterator ref = exifData.findKey(Exiv2::ExifKey("Exif.GPSInfo.GPSAltitudeRef"));
1251 if(ref != exifData.end() && ref->size())
1252 {
1253 std::string sign_str = ref->toString();
1254 const char *sign = sign_str.c_str();
1255 double elevation = 0.0;
1256 if(dt_util_gps_elevation_to_number(pos->toRational(0).first, pos->toRational(0).second, sign[0], &elevation))
1257 img->geoloc.elevation = elevation;
1258 }
1259 }
1260
1261 /* Read lens name */
1262 if((FIND_EXIF_TAG("Exif.CanonCs.LensType")
1263 && pos->toLong() != 61182 // prefer the other tag for RF lenses
1264 && pos->toLong() != 0
1265 && pos->toLong() != 65535)
1266 || FIND_EXIF_TAG("Exif.Canon.LensModel"))
1267 {
1268 dt_strlcpy_to_utf8(img->exif_lens, sizeof(img->exif_lens), pos, exifData);
1269 }
1270 else if(FIND_EXIF_TAG("Exif.PentaxDng.LensType"))
1271 {
1272 dt_strlcpy_to_utf8(img->exif_lens, sizeof(img->exif_lens), pos, exifData);
1273 }
1274 else if(FIND_EXIF_TAG("Exif.Panasonic.LensType"))
1275 {
1276 dt_strlcpy_to_utf8(img->exif_lens, sizeof(img->exif_lens), pos, exifData);
1277 }
1278 else if(FIND_EXIF_TAG("Exif.OlympusEq.LensType"))
1279 {
1280 /* For every Olympus camera Exif.OlympusEq.LensType is present. */
1281 dt_strlcpy_to_utf8(img->exif_lens, sizeof(img->exif_lens), pos, exifData);
1282
1283 /* We have to check if Exif.OlympusEq.LensType has been translated by
1284 * exiv2. If it hasn't, fall back to Exif.OlympusEq.LensModel. */
1285 std::string lens(img->exif_lens);
1286 if(std::string::npos == lens.find_first_not_of(" 1234567890"))
1287 {
1288 /* Exif.OlympusEq.LensType contains only digits and spaces.
1289 * This means that exiv2 couldn't convert it to human readable
1290 * form. */
1291 if(FIND_EXIF_TAG("Exif.OlympusEq.LensModel"))
1292 {
1293 dt_strlcpy_to_utf8(img->exif_lens, sizeof(img->exif_lens), pos, exifData);
1294 }
1295 /* Just in case Exif.OlympusEq.LensModel hasn't been found */
1296 else if(FIND_EXIF_TAG("Exif.Photo.LensModel"))
1297 {
1298 dt_strlcpy_to_utf8(img->exif_lens, sizeof(img->exif_lens), pos, exifData);
1299 }
1300 fprintf(stderr, "[exif] Warning: lens \"%s\" unknown as \"%s\"\n", img->exif_lens, lens.c_str());
1301 }
1302 }
1303 else if(Exiv2::testVersion(0,27,4) && FIND_EXIF_TAG("Exif.NikonLd4.LensID") && pos->toLong() == 0)
1304 {
1305 /* Z body w/ FTZ adapter or recent F body (e.g. D780, D6) detected.
1306 * Prioritize the legacy ID lookup instead of Exif.Photo.LensModel included
1307 * in the default Exiv2::lensName() search below. */
1308 if(FIND_EXIF_TAG("Exif.NikonLd4.LensIDNumber"))
1309 dt_strlcpy_to_utf8(img->exif_lens, sizeof(img->exif_lens), pos, exifData);
1310 }
1311 else if((pos = Exiv2::lensName(exifData)) != exifData.end() && pos->size())
1312 {
1313 dt_strlcpy_to_utf8(img->exif_lens, sizeof(img->exif_lens), pos, exifData);
1314 }
1315
1316 /* Use pretty name for Canon RF & RF-S lenses (as exiftool/exiv2/lensfun) */
1317 if(g_str_has_prefix(img->exif_lens, "RF"))
1318 {
1319 char *pretty;
1320 if(img->exif_lens[2] == '-')
1321 pretty = g_strconcat("Canon RF-S ", &img->exif_lens[4], (char *)NULL);
1322 else
1323 pretty = g_strconcat("Canon RF ", &img->exif_lens[2], (char *)NULL);
1324 g_strlcpy(img->exif_lens, pretty, sizeof(img->exif_lens));
1325 dt_free(pretty);
1326 }
1327
1328 /* Capitalize Nikon Z-mount lenses properly for UI presentation */
1329 if(g_str_has_prefix(img->exif_lens, "NIKKOR") || g_str_has_prefix(img->exif_lens, "TAMRON"))
1330 {
1331 for(size_t i = 1; i <= 5; ++i)
1332 img->exif_lens[i] = g_ascii_tolower(img->exif_lens[i]);
1333 }
1334
1335 // finally the lens has only numbers and parentheses, let's try to use
1336 // Exif.Photo.LensModel if defined.
1337
1338 std::string lens(img->exif_lens);
1339 if(std::string::npos == lens.find_first_not_of(" (1234567890)")
1340 && FIND_EXIF_TAG("Exif.Photo.LensModel"))
1341 {
1342 dt_strlcpy_to_utf8(img->exif_lens, sizeof(img->exif_lens), pos, exifData);
1343 }
1344
1345#if 0
1346 /* Read flash mode */
1347 if ( (pos=exifData.findKey(Exiv2::ExifKey("Exif.Photo.Flash")))
1348 != exifData.end() && pos->size())
1349 {
1350 uf_strlcpy_to_utf8(uf->conf->flashText, max_name, pos, exifData);
1351 }
1352 /* Read White Balance Setting */
1353 if ( (pos=exifData.findKey(Exiv2::ExifKey("Exif.Photo.WhiteBalance")))
1354 != exifData.end() && pos->size())
1355 {
1356 uf_strlcpy_to_utf8(uf->conf->whiteBalanceText, max_name, pos, exifData);
1357 }
1358#endif
1359
1360 char datetime[DT_DATETIME_LENGTH];
1361 _find_datetime_taken(exifData, pos, datetime);
1362 if(datetime[0] != '\0') dt_datetime_exif_to_img(img, datetime);
1363
1364 if(FIND_EXIF_TAG("Exif.Image.Artist"))
1365 {
1366 std::string str = pos->print(&exifData);
1367 dt_metadata_set_import(img->id, "Xmp.dc.creator", str.c_str());
1368 }
1369 else if(FIND_EXIF_TAG("Exif.Canon.OwnerName"))
1370 {
1371 std::string str = pos->print(&exifData);
1372 dt_metadata_set_import(img->id, "Xmp.dc.creator", str.c_str());
1373 }
1374
1375 // FIXME: Should the UserComment go into the description? Or do we need an extra field for this?
1376 if(FIND_EXIF_TAG("Exif.Photo.UserComment"))
1377 {
1378 std::string str = pos->print(&exifData);
1379 Exiv2::CommentValue value(str);
1380 std::string str2 = value.comment();
1381 if(str2 != "binary comment")
1382 dt_metadata_set_import(img->id, "Xmp.dc.description", str2.c_str());
1383 }
1384 else if(FIND_EXIF_TAG("Exif.Image.ImageDescription"))
1385 {
1386 std::string str = pos->print(&exifData);
1387 dt_metadata_set_import(img->id, "Xmp.dc.description", str.c_str());
1388 }
1389
1390 if(FIND_EXIF_TAG("Exif.Image.Copyright"))
1391 {
1392 std::string str = pos->print(&exifData);
1393 dt_metadata_set_import(img->id, "Xmp.dc.rights", str.c_str());
1394 }
1395
1396 if(FIND_EXIF_TAG("Exif.Image.Rating"))
1397 {
1398 const int stars = pos->toLong();
1399 dt_image_set_xmp_rating(img, stars);
1400 }
1401 else if(FIND_EXIF_TAG("Exif.Image.RatingPercent"))
1402 {
1403 const int stars = pos->toLong() * 5. / 100;
1404 dt_image_set_xmp_rating(img, stars);
1405 }
1406 else
1407 dt_image_set_xmp_rating(img, -2);
1408
1409 // read embedded color matrix as used in DNGs
1410 {
1411 float colmatrix[3][12];
1412 colmatrix[0][0] = colmatrix[1][0] = colmatrix[2][0] = NAN;
1414 img->d65_color_matrix[0] = NAN; // make sure for later testing
1415
1416 // fallback later via `find_temperature_from_raw_coeffs` if there is no valid illuminant
1417
1418 // The correction matrices are taken from
1419 // http://www.brucelindbloom.com - chromatic Adaption.
1420 // using Bradford method: found Illuminant -> D65
1421 const float correctmat[13][9] = {
1422 { 0.9555766, -0.0230393, 0.0631636, -0.0282895, 1.0099416, 0.0210077, 0.0122982, -0.0204830,
1423 1.3299098 }, // D50
1424 { 0.9726856, -0.0135482, 0.0361731, -0.0167463, 1.0049102, 0.0120598, 0.0070026, -0.0116372,
1425 1.1869548 }, // D55
1426 { 1.0206905, 0.0091588, -0.0228796, 0.0115005, 0.9984917, -0.0076762, -0.0043619, 0.0072053,
1427 0.8853432 }, // D75
1428 { 0.8446965, -0.1179225, 0.3948108, -0.1366303, 1.1041226, 0.1291718, 0.0798489, -0.1348999,
1429 3.1924009 }, // Standard light A
1430 { 0.9415037, -0.0321240, 0.0584672, -0.0428238, 1.0250998, 0.0203309, 0.0101511, -0.0161170,
1431 1.2847354 }, // Standard light B
1432 { 0.9904476, -0.0071683, -0.0116156, -0.0123712, 1.0155950, -0.0029282, -0.0035635, 0.0067697,
1433 0.9181569 }, // Standard light C
1434 { 0.9212269, -0.0449128, 0.1211620, -0.0553723, 1.0277243, 0.0403563, 0.0235086, -0.0391019,
1435 1.6390644 }, // Fluorescent (F2)
1436 // The following are calculated using the same Bradford method,
1437 // with xy coord from DNG SDK as reference -> XYZ -> D65
1438 { 0.8663030, -0.0913083, 0.2771784, -0.1090504, 1.0746895, 0.0913841, 0.0550856, -0.0924636,
1439 2.5119387 }, // ISO Studio Tungsten (3200K first converted to xy as DNG SDK does)
1440 { 1.0096114, 0.0061501, 0.0068113, 0.0102539, 0.9888663, 0.0015575, 0.0023119, -0.0044823,
1441 1.0525915 }, // DaylightFluorescent (F1)
1442 { 0.9554129, -0.0231280, 0.0637169, -0.0283629, 1.0099053, 0.0211824, 0.0124188, -0.0206922,
1443 1.3330592 }, // DayWhiteFluorescent (F8)
1444 { 0.9147843, -0.0492842, 0.1202810, -0.0622085, 1.034984, 0.0404480, 0.0228014, -0.0375807,
1445 1.6259804 }, // CoolWhiteFluorescent (F9)
1446 { 0.8805388, -0.0774890, 0.2293784, -0.0932136, 1.0589267, 0.0757827, 0.0453660, -0.0760107,
1447 2.2417979 }, // WhiteFluorescent (F3)
1448 { 0.8488316, -0.1107439, 0.3471428, -0.1310107, 1.0986874, 0.1141548, 0.0694025, -0.1167541,
1449 2.9109462 } // WarmWhiteFluorescent (F4)
1450 };
1451
1452 Exiv2::ExifData::const_iterator cm1_pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.ColorMatrix1"));
1453 if((cm1_pos != exifData.end()) && (cm1_pos->count() == 9))
1454 {
1455 for(int i = 0; i < 9; i++) colmatrix[0][i] = cm1_pos->toFloat(i);
1456
1457 if(FIND_EXIF_TAG("Exif.Image.CalibrationIlluminant1")) illu[0] = (dt_dng_illuminant_t) pos->toLong();
1458 }
1459
1460 Exiv2::ExifData::const_iterator cm2_pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.ColorMatrix2"));
1461 if((cm2_pos != exifData.end()) && (cm2_pos->count() == 9))
1462 {
1463 for(int i = 0; i < 9; i++) colmatrix[1][i] = cm2_pos->toFloat(i);
1464
1465 if(FIND_EXIF_TAG("Exif.Image.CalibrationIlluminant2")) illu[1] = (dt_dng_illuminant_t) pos->toLong();
1466 }
1467
1468 // So far the Exif.Image.CalibrationIlluminant3 tag and friends have not been implemented and there are no images to test
1469#if EXIV2_TEST_VERSION(0,27,4)
1470 Exiv2::ExifData::const_iterator cm3_pos = exifData.findKey(Exiv2::ExifKey("Exif.Image.ColorMatrix3"));
1471 if((cm3_pos != exifData.end()) && (cm3_pos->count() == 9))
1472 {
1473 for(int i = 0; i < 9; i++) colmatrix[2][i] = cm3_pos->toFloat(i);
1474
1475 if(FIND_EXIF_TAG("Exif.Image.CalibrationIlluminant3")) illu[2] = (dt_dng_illuminant_t) pos->toLong();
1476 }
1477#endif
1478
1479 int sel_illu = -1;
1480 int sel_temp = 0;
1481 const int D65temp = _illu_to_temp(DT_LS_D65);
1482 int delta_min = D65temp;
1483 // Which illuminant will be used for the color matrix?
1484 // We first try to find D65 or take the next higher
1485 for(int i = 0; i < 3; ++i)
1486 {
1487 int temp_cur = _illu_to_temp(illu[i]);
1488 int delta_cur = abs(temp_cur - D65temp);
1489 if((temp_cur > sel_temp) && (delta_cur <= delta_min))
1490 {
1491 sel_illu = i;
1492 sel_temp = temp_cur;
1493 delta_min = delta_cur;
1494 }
1495 }
1496 // If there is none defined we'll use the first valid color matrix
1497 // without correction, i.e. assume D65 (keep dt < 3.8 behaviour)
1498 // TODO: "Other" illuminant is currently unsupported
1499 if(sel_illu == -1)
1500 for(int i = 0; i < 3; ++i)
1501 {
1502 if((illu[i] == DT_LS_Unknown) && !isnan(colmatrix[i][0]))
1503 {
1504 sel_illu = i;
1505 sel_temp = D65temp;
1506 break;
1507 }
1508 }
1509
1510 if((sel_illu > -1) && (darktable.unmuted & DT_DEBUG_IMAGEIO))
1511 {
1512 fprintf(stderr, "[exif] `%s` dng illuminant %i (%iK) selected from ", img->filename, illu[sel_illu], sel_temp);
1513 for(int i = 0; i < 3; i++)
1514 fprintf(stderr," -- [%i] %i (%iK)", i + 1, illu[i], _illu_to_temp(illu[i]));
1515 fprintf(stderr, "\n");
1516 }
1517
1518 // Take the found CalibrationIlluminant / ColorMatrix pair.
1519 // D65: just copy. Otherwise multiply by the specific correction matrix.
1520 if(sel_illu > -1)
1521 {
1522 // If no supported Illuminant is found/assumed it's better NOT to use any matrix.
1523 // The colorin module will write an error message and use a fallback matrix
1524 // instead of showing wrong colors.
1525 switch(illu[sel_illu])
1526 {
1527 case DT_LS_D50:
1528 mat3mul(img->d65_color_matrix, correctmat[0], colmatrix[sel_illu]);
1529 break;
1530 case DT_LS_D55:
1531 case DT_LS_Daylight:
1532 case DT_LS_FineWeather:
1533 case DT_LS_Flash:
1534 mat3mul(img->d65_color_matrix, correctmat[1], colmatrix[sel_illu]);
1535 break;
1536 case DT_LS_D75:
1537 case DT_LS_Shade:
1538 mat3mul(img->d65_color_matrix, correctmat[2], colmatrix[sel_illu]);
1539 break;
1540 case DT_LS_Tungsten:
1542 mat3mul(img->d65_color_matrix, correctmat[3], colmatrix[sel_illu]);
1543 break;
1545 mat3mul(img->d65_color_matrix, correctmat[4], colmatrix[sel_illu]);
1546 break;
1548 mat3mul(img->d65_color_matrix, correctmat[5], colmatrix[sel_illu]);
1549 break;
1550 case DT_LS_Fluorescent:
1551 mat3mul(img->d65_color_matrix, correctmat[6], colmatrix[sel_illu]);
1552 break;
1554 mat3mul(img->d65_color_matrix, correctmat[7], colmatrix[sel_illu]);
1555 break;
1557 mat3mul(img->d65_color_matrix, correctmat[8], colmatrix[sel_illu]);
1558 break;
1560 mat3mul(img->d65_color_matrix, correctmat[9], colmatrix[sel_illu]);
1561 break;
1563 mat3mul(img->d65_color_matrix, correctmat[10], colmatrix[sel_illu]);
1564 break;
1566 mat3mul(img->d65_color_matrix, correctmat[11], colmatrix[sel_illu]);
1567 break;
1569 mat3mul(img->d65_color_matrix, correctmat[12], colmatrix[sel_illu]);
1570 break;
1571 case DT_LS_D65:
1573 case DT_LS_Unknown: // exceptional fallback to keep dt < 3.8 behaviour
1574 for(int i = 0; i < 9; i++) img->d65_color_matrix[i] = colmatrix[sel_illu][i];
1575 break;
1576
1577 default:
1578 fprintf(stderr,"[exif] did not find a proper dng correction matrix for illuminant %i\n", illu[sel_illu]);
1579 break;
1580 }
1581 }
1582 }
1583
1584 // Finding out about DNG hdr and monochrome images can be done here while reading exif data.
1585 if(FIND_EXIF_TAG("Exif.Image.DNGVersion"))
1586 {
1587 int format = 1;
1588 int bps = 0;
1589 int spp = 0;
1590 int phi = 0;
1591
1592 if(FIND_EXIF_TAG("Exif.SubImage1.SampleFormat"))
1593 format = pos->toLong();
1594 else if(FIND_EXIF_TAG("Exif.Image.SampleFormat"))
1595 format = pos->toLong();
1596
1597 if(FIND_EXIF_TAG("Exif.SubImage1.BitsPerSample"))
1598 bps = pos->toLong();
1599 else if(FIND_EXIF_TAG("Exif.Image.BitsPerSample"))
1600 bps = pos->toLong();
1601
1602 if(FIND_EXIF_TAG("Exif.SubImage1.SamplesPerPixel"))
1603 spp = pos->toLong();
1604 else if(FIND_EXIF_TAG("Exif.Image.SamplesPerPixel"))
1605 spp = pos->toLong();
1606
1607 if(FIND_EXIF_TAG("Exif.SubImage1.PhotometricInterpretation"))
1608 phi = pos->toLong();
1609 else if(FIND_EXIF_TAG("Exif.Image.PhotometricInterpretation"))
1610 phi = pos->toLong();
1611
1612 if((format == 3) && (bps >= 16) && ((phi == 32803) || (phi == 34892)))
1613 img->flags |= DT_IMAGE_HDR;
1614
1615 if((spp == 1) && (phi == 34892))
1616 img->flags |= DT_IMAGE_MONOCHROME;
1617 }
1618
1619 // some files have the display colorspace explicitly set. try to read that. The Exif.Photo.ColorSpace
1620 // tag only exists in display-referred integer images, so gate on "not raw and not HDR-float"
1621 // rather than on DT_IMAGE_LDR: at this point the dynamic range of an ambiguous container (TIFF,
1622 // AVIF, HEIF) is not yet known (the extension can't tell, the buffer is not decoded), so the LDR
1623 // flag may legitimately be unset here even for an integer image.
1624 // tag absent -> leave colorspace as none
1625 // 0x01 -> sRGB
1626 // 0x02 -> AdobeRGB
1627 // 0xffff -> Uncalibrated
1628 // + Exif.Iop.InteroperabilityIndex of 'R03' -> AdobeRGB
1629 // + Exif.Iop.InteroperabilityIndex of 'R98' -> sRGB
1630 if(!dt_image_is_raw(img) && FIND_EXIF_TAG("Exif.Photo.ColorSpace"))
1631 {
1632 int colorspace = pos->toLong();
1633 if(colorspace == 0x01)
1635 else if(colorspace == 0x02)
1637 else if(colorspace == 0xffff)
1638 {
1639 if(FIND_EXIF_TAG("Exif.Iop.InteroperabilityIndex"))
1640 {
1641 std::string interop_index = pos->toString();
1642 if(interop_index == "R03")
1644 else if(interop_index == "R98")
1646 }
1647 }
1648 }
1649
1650 // Improve lens detection for Sony SAL lenses.
1651 if(FIND_EXIF_TAG("Exif.Sony2.LensID") && pos->toLong() != 65535 && pos->print().find('|') == std::string::npos)
1652 {
1653 dt_strlcpy_to_utf8(img->exif_lens, sizeof(img->exif_lens), pos, exifData);
1654 }
1655 // Workaround for an issue on newer Sony NEX cams.
1656 // The default EXIF field is not used by Sony to store lens data
1657 // http://dev.exiv2.org/issues/883
1658 // http://darktable.org/redmine/issues/8813
1659 // FIXME: This is still a workaround
1660 else if((!strncmp(img->exif_model, "NEX", 3)) || (!strncmp(img->exif_model, "ILCE", 4)))
1661 {
1662 snprintf(img->exif_lens, sizeof(img->exif_lens), "(unknown)");
1663 if(FIND_EXIF_TAG("Exif.Photo.LensModel"))
1664 {
1665 std::string str = pos->print(&exifData);
1666 snprintf(img->exif_lens, sizeof(img->exif_lens), "%s", str.c_str());
1667 }
1668 };
1669
1670 img->exif_inited = TRUE;
1671 return true;
1672 }
1673 catch(Exiv2::AnyError &e)
1674 {
1675 std::string s(e.what());
1676 std::cerr << "[exiv2 _exif_decode_exif_data] " << img->filename << ": " << s << std::endl;
1677 return false;
1678 }
1679}
1680
1681// TODO: can this blob also contain xmp and iptc data?
1682int dt_exif_read_from_blob(dt_image_t *img, uint8_t *blob, const int size)
1683{
1684 try
1685 {
1686 Exiv2::ExifData exifData;
1687 Exiv2::ExifParser::decode(exifData, blob, size);
1688 bool res = _exif_decode_exif_data(img, exifData);
1689 return res ? 0 : 1;
1690 }
1691 catch(Exiv2::AnyError &e)
1692 {
1693 std::string s(e.what());
1694 std::cerr << "[exiv2 dt_exif_read_from_blob] " << img->filename << ": " << s << std::endl;
1695 return 1;
1696 }
1697}
1698
1702int dt_exif_get_thumbnail(const char *path, uint8_t **buffer, size_t *size, char **mime_type, int *width, int *height, int min_width)
1703{
1704 try
1705 {
1706 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(WIDEN(path)));
1707 assert(image.get() != 0);
1709
1710 // Get a list of preview images available in the image. The list is sorted
1711 // by the preview image pixel size, starting with the smallest preview.
1712 Exiv2::PreviewManager loader(*image);
1713 Exiv2::PreviewPropertiesList list = loader.getPreviewProperties();
1714 if(list.empty())
1715 {
1716 dt_print(DT_DEBUG_LIGHTTABLE, "[exiv2 dt_exif_get_thumbnail] couldn't find thumbnail for %s\n", path);
1717 return 1;
1718 }
1719
1720 // Get the largest mipmap
1721 Exiv2::PreviewProperties selected = list.back();
1722
1723 // Get the selected preview image
1724 Exiv2::PreviewImage preview = loader.getPreviewImage(selected);
1725 const unsigned char *tmp = preview.pData();
1726 size_t _size = preview.size();
1727
1728 *size = _size;
1729 *width = preview.width();
1730 *height = preview.height();
1731 *mime_type = strdup(preview.mimeType().c_str());
1732 *buffer = (uint8_t *)malloc(_size);
1733 if(IS_NULL_PTR(*buffer)) {
1734 std::cerr << "[exiv2 dt_exif_get_thumbnail] couldn't allocate memory for thumbnail for " << path << std::endl;
1735 return 1;
1736 }
1737
1738 memcpy(*buffer, tmp, _size);
1739
1740 return 0;
1741 }
1742 catch(Exiv2::AnyError &e)
1743 {
1744 std::string s(e.what());
1745 std::cerr << "[exiv2 dt_exif_get_thumbnail] " << path << ": " << s << std::endl;
1746 return 1;
1747 }
1748}
1749
1753int dt_exif_read(dt_image_t *img, const char *path)
1754{
1755 // Seed the provisional image-type flag (LDR / HDR / RAW, from the file extension) before we probe
1756 // dt_image_is_ldr() / dt_image_is_hdr() while decoding the EXIF below. This function can run on a
1757 // freshly dt_image_init()'d object (import preview, path-pattern expansion) long before the buffer
1758 // is decoded and dt_image_buffer_resolve_flags() sets the authoritative datatype-derived flags.
1759 // Only seed when nothing is classified yet, so a DB-loaded / already-resolved image is untouched.
1761 {
1762 const char *ext = g_strrstr(path, ".");
1763 if(ext) img->flags |= dt_imageio_get_type_from_extension(ext + 1);
1764 }
1765
1766 // at least set datetime taken to something useful in case there is no exif data in this file (pfm, png,
1767 // ...)
1768 struct stat statbuf;
1769
1770 if(!stat(path, &statbuf))
1771 {
1772 dt_datetime_unix_to_img(img, &statbuf.st_mtime);
1773 }
1774
1775 try
1776 {
1777 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(WIDEN(path)));
1778 assert(image.get() != 0);
1780 bool res = true;
1781
1782 // EXIF metadata
1783 Exiv2::ExifData &exifData = image->exifData();
1784 if(!exifData.empty())
1785 {
1786 res = _exif_decode_exif_data(img, exifData);
1787 }
1788 else
1789 img->exif_inited = 1;
1790
1791 // IPTC metadata.
1792 Exiv2::IptcData &iptcData = image->iptcData();
1793 if(!iptcData.empty()) res = _exif_decode_iptc_data(img, iptcData) && res;
1794
1795 // XMP metadata
1796 Exiv2::XmpData &xmpData = image->xmpData();
1797 if(!xmpData.empty())
1798 res = _exif_decode_xmp_data(img, xmpData, -1, true) && res;
1799
1800 // Initialize size - don't wait for full raw to be loaded to get this
1801 // information. If use_embedded_thumbnail is set, it will take a
1802 // change in development history to have this information
1803 img->height = image->pixelHeight();
1804 img->width = image->pixelWidth();
1805
1806 return res ? 0 : 1;
1807 }
1808 catch(Exiv2::AnyError &e)
1809 {
1810 std::string s(e.what());
1811 std::cerr << "[exiv2 dt_exif_read] " << path << ": " << s << std::endl;
1812 return 1;
1813 }
1814}
1815
1816int dt_exif_write_blob(uint8_t *blob, uint32_t size, const char *path, const int compressed)
1817{
1818 try
1819 {
1820 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(WIDEN(path)));
1821 assert(image.get() != 0);
1823 Exiv2::ExifData &imgExifData = image->exifData();
1824 Exiv2::ExifData blobExifData;
1825 Exiv2::ExifParser::decode(blobExifData, blob, size);
1826 Exiv2::ExifData::const_iterator end = blobExifData.end();
1827 Exiv2::ExifData::iterator it;
1828 for(Exiv2::ExifData::const_iterator i = blobExifData.begin(); i != end; ++i)
1829 {
1830 // add() does not override! we need to delete existing key first.
1831 Exiv2::ExifKey key(i->key());
1832 if((it = imgExifData.findKey(key)) != imgExifData.end()) imgExifData.erase(it);
1833
1834 imgExifData.add(Exiv2::ExifKey(i->key()), &i->value());
1835 }
1836
1837 {
1838 // Remove thumbnail
1839 static const char *keys[] = {
1840 "Exif.Thumbnail.Compression",
1841 "Exif.Thumbnail.XResolution",
1842 "Exif.Thumbnail.YResolution",
1843 "Exif.Thumbnail.ResolutionUnit",
1844 "Exif.Thumbnail.JPEGInterchangeFormat",
1845 "Exif.Thumbnail.JPEGInterchangeFormatLength"
1846 };
1847 static const guint n_keys = G_N_ELEMENTS(keys);
1848 dt_remove_exif_keys(imgExifData, keys, n_keys);
1849 }
1850
1851 // only compressed images may set PixelXDimension and PixelYDimension
1852 if(!compressed)
1853 {
1854 static const char *keys[] = {
1855 "Exif.Photo.PixelXDimension",
1856 "Exif.Photo.PixelYDimension"
1857 };
1858 static const guint n_keys = G_N_ELEMENTS(keys);
1859 dt_remove_exif_keys(imgExifData, keys, n_keys);
1860 }
1861
1862 imgExifData.sortByTag();
1863 image->writeMetadata();
1864 }
1865 catch(Exiv2::AnyError &e)
1866 {
1867 std::string s(e.what());
1868 std::cerr << "[exiv2 dt_exif_write_blob] " << path << ": " << s << std::endl;
1869 return 0;
1870 }
1871 return 1;
1872}
1873
1874static void dt_remove_exif_geotag(Exiv2::ExifData &exifData)
1875{
1876 static const char *keys[] =
1877 {
1878 "Exif.GPSInfo.GPSLatitude",
1879 "Exif.GPSInfo.GPSLongitude",
1880 "Exif.GPSInfo.GPSAltitude",
1881 "Exif.GPSInfo.GPSLatitudeRef",
1882 "Exif.GPSInfo.GPSLongitudeRef",
1883 "Exif.GPSInfo.GPSAltitudeRef",
1884 "Exif.GPSInfo.GPSVersionID"
1885 };
1886 static const guint n_keys = G_N_ELEMENTS(keys);
1887 dt_remove_exif_keys(exifData, keys, n_keys);
1888}
1889
1890int dt_exif_read_blob(uint8_t **buf, const char *path, const int32_t imgid, const int sRGB, const int out_width,
1891 const int out_height, const int dng_mode)
1892{
1893 *buf = NULL;
1894 try
1895 {
1896 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(WIDEN(path)));
1897 assert(image.get() != 0);
1899 Exiv2::ExifData &exifData = image->exifData();
1900
1901 // get rid of thumbnails
1902 Exiv2::ExifThumb(exifData).erase();
1903 Exiv2::ExifData::const_iterator pos;
1904
1905 {
1906 static const char *keys[] = {
1907 "Exif.Image.ImageWidth",
1908 "Exif.Image.ImageLength",
1909 "Exif.Image.BitsPerSample",
1910 "Exif.Image.Compression",
1911 "Exif.Image.PhotometricInterpretation",
1912 "Exif.Image.FillOrder",
1913 "Exif.Image.SamplesPerPixel",
1914 "Exif.Image.StripOffsets",
1915 "Exif.Image.RowsPerStrip",
1916 "Exif.Image.StripByteCounts",
1917 "Exif.Image.TileWidth",
1918 "Exif.Image.TileLength",
1919 "Exif.Image.TileOffsets",
1920 "Exif.Image.TileByteCounts",
1921 "Exif.Image.PlanarConfiguration"
1922 };
1923 static const guint n_keys = G_N_ELEMENTS(keys);
1924 dt_remove_exif_keys(exifData, keys, n_keys);
1925 }
1926
1927 /* Many tags should be removed in all cases as they are simply wrong also for dng files */
1928
1929 // remove subimage* trees, related to thumbnails or HDR usually; also UserCrop
1930 for(Exiv2::ExifData::iterator i = exifData.begin(); i != exifData.end();)
1931 {
1932 static const std::string needle = "Exif.SubImage";
1933 if(i->key().compare(0, needle.length(), needle) == 0)
1934 i = exifData.erase(i);
1935 else
1936 ++i;
1937 }
1938
1939 {
1940 static const char *keys[] = {
1941 // Canon color space info
1942 "Exif.Canon.ColorSpace",
1943 "Exif.Canon.ColorData",
1944
1945 // Nikon thumbnail data
1946 "Exif.Nikon3.Preview",
1947 "Exif.NikonPreview.JPEGInterchangeFormat",
1948
1949 // TIFF/EP & Exif stuff irrelevant after developing
1950 "Exif.Image.CFARepeatPatternDim",
1951 "Exif.Image.CFAPattern",
1952 "Exif.Image.InterColorProfile",
1953 "Exif.Image.SpectralSensitivity",
1954 "Exif.Image.OECF",
1955 "Exif.Image.SpatialFrequencyResponse",
1956 "Exif.Image.Noise",
1957 "Exif.Image.SensingMethod",
1958 "Exif.Image.TIFFEPStandardID",
1959 "Exif.Photo.SpectralSensitivity",
1960 "Exif.Photo.OECF",
1961 "Exif.Photo.SpatialFrequencyResponse",
1962 "Exif.Photo.SensingMethod",
1963 "Exif.Photo.CFAPattern",
1964
1965 // DNG stuff that is irrelevant or misleading
1966 "Exif.Image.DNGVersion",
1967 "Exif.Image.DNGBackwardVersion",
1968 "Exif.Image.DNGPrivateData",
1969 "Exif.Image.DefaultBlackRender",
1970 "Exif.Image.DefaultCropOrigin",
1971 "Exif.Image.DefaultCropSize",
1972 "Exif.Image.RawDataUniqueID",
1973 "Exif.Image.OriginalRawFileName",
1974 "Exif.Image.OriginalRawFileData",
1975 "Exif.Image.ActiveArea",
1976 "Exif.Image.MaskedAreas",
1977 "Exif.Image.AsShotICCProfile",
1978 "Exif.Image.OpcodeList1",
1979 "Exif.Image.OpcodeList2",
1980 "Exif.Image.OpcodeList3",
1981 "Exif.Image.AsShotNeutral",
1982 "Exif.Image.AsShotWhiteXY",
1983 "Exif.Image.BaselineExposure",
1984 "Exif.Image.BaselineNoise",
1985 "Exif.Image.BaselineSharpness",
1986 "Exif.Image.LinearResponseLimit",
1987 "Exif.Image.ShadowScale",
1988 "Exif.Image.PreviewApplicationName",
1989 "Exif.Image.PreviewApplicationVersion",
1990 "Exif.Image.PreviewSettingsDigest",
1991 "Exif.Image.PreviewColorSpace",
1992 "Exif.Image.PreviewDateTime",
1993 "Exif.Image.NoiseProfile",
1994 "Exif.Image.NewRawImageDigest",
1995 "Exif.Image.RawImageDigest",
1996
1997 "Exif.Photo.MakerNote",
1998
1999 // Pentax thumbnail data
2000 "Exif.Pentax.PreviewResolution",
2001 "Exif.Pentax.PreviewLength",
2002 "Exif.Pentax.PreviewOffset",
2003 "Exif.PentaxDng.PreviewResolution",
2004 "Exif.PentaxDng.PreviewLength",
2005 "Exif.PentaxDng.PreviewOffset",
2006 // Pentax color info
2007 "Exif.PentaxDng.ColorInfo",
2008
2009 // Minolta thumbnail data
2010 "Exif.Minolta.Thumbnail",
2011 "Exif.Minolta.ThumbnailOffset",
2012 "Exif.Minolta.ThumbnailLength",
2013
2014 // Sony thumbnail data
2015 "Exif.SonyMinolta.ThumbnailOffset",
2016 "Exif.SonyMinolta.ThumbnailLength",
2017
2018 // Olympus thumbnail data
2019 "Exif.Olympus.Thumbnail",
2020 "Exif.Olympus.ThumbnailOffset",
2021 "Exif.Olympus.ThumbnailLength",
2022
2023 "Exif.Image.BaselineExposureOffset",
2024
2025 // Samsung makernote cleanup, the entries below have no
2026 // relevance for exported images
2027 "Exif.Samsung2.SensorAreas",
2028 "Exif.Samsung2.ColorSpace",
2029 "Exif.Samsung2.EncryptionKey",
2030 "Exif.Samsung2.WB_RGGBLevelsUncorrected",
2031 "Exif.Samsung2.WB_RGGBLevelsAuto",
2032 "Exif.Samsung2.WB_RGGBLevelsIlluminator1",
2033 "Exif.Samsung2.WB_RGGBLevelsIlluminator2",
2034 "Exif.Samsung2.WB_RGGBLevelsBlack",
2035 "Exif.Samsung2.ColorMatrix",
2036 "Exif.Samsung2.ColorMatrixSRGB",
2037 "Exif.Samsung2.ColorMatrixAdobeRGB",
2038 "Exif.Samsung2.ToneCurve1",
2039 "Exif.Samsung2.ToneCurve2",
2040 "Exif.Samsung2.ToneCurve3",
2041 "Exif.Samsung2.ToneCurve4"
2042 };
2043 static const guint n_keys = G_N_ELEMENTS(keys);
2044 dt_remove_exif_keys(exifData, keys, n_keys);
2045 }
2046
2047 static const char *dngkeys[] = {
2048 // Embedded color profile info
2049 "Exif.Image.ColorMatrix1",
2050 "Exif.Image.ColorMatrix2",
2051 "Exif.Image.CameraCalibration1",
2052 "Exif.Image.CameraCalibration2",
2053 "Exif.Image.ReductionMatrix1",
2054 "Exif.Image.ReductionMatrix2",
2055 "Exif.Image.AnalogBalance",
2056 "Exif.Image.CalibrationIlluminant1",
2057 "Exif.Image.CalibrationIlluminant2",
2058 "Exif.Image.CameraCalibrationSignature",
2059 "Exif.Image.ProfileCalibrationSignature",
2060 "Exif.Image.ExtraCameraProfiles",
2061 "Exif.Image.AsShotProfileName",
2062 "Exif.Image.ProfileName",
2063 "Exif.Image.ProfileHueSatMapDims",
2064 "Exif.Image.ProfileHueSatMapData1",
2065 "Exif.Image.ProfileHueSatMapData2",
2066 "Exif.Image.ProfileToneCurve",
2067 "Exif.Image.ProfileEmbedPolicy",
2068 "Exif.Image.ProfileCopyright",
2069 "Exif.Image.ForwardMatrix1",
2070 "Exif.Image.ForwardMatrix2",
2071 "Exif.Image.ProfileLookTableDims",
2072 "Exif.Image.ProfileLookTableData",
2073 "Exif.Image.ProfileLookTableEncoding",
2074 "Exif.Image.ProfileHueSatMapEncoding"
2075 };
2076 static const guint n_dngkeys = G_N_ELEMENTS(dngkeys);
2077 dt_remove_exif_keys(exifData, dngkeys, n_dngkeys);
2078
2079 /* Write appropriate color space tag if using sRGB output */
2080 if(sRGB)
2081 exifData["Exif.Photo.ColorSpace"] = uint16_t(1); /* sRGB */
2082 else
2083 exifData["Exif.Photo.ColorSpace"] = uint16_t(0xFFFF); /* Uncalibrated */
2084
2085 // we don't write the orientation here for dng as it is set in dt_imageio_dng_write_tiff_header
2086 // or might be defined in this blob.
2087 if(!dng_mode) exifData["Exif.Image.Orientation"] = uint16_t(1);
2088
2089 /* Replace RAW dimension with output dimensions (for example after crop/scale, or orientation for dng
2090 * mode) */
2091 if(out_width > 0) exifData["Exif.Photo.PixelXDimension"] = (uint32_t)out_width;
2092 if(out_height > 0) exifData["Exif.Photo.PixelYDimension"] = (uint32_t)out_height;
2093
2094 const int resolution = dt_conf_get_int("metadata/resolution");
2095 exifData["Exif.Image.XResolution"] = Exiv2::Rational(resolution, 1);
2096 exifData["Exif.Image.YResolution"] = Exiv2::Rational(resolution, 1);
2097 exifData["Exif.Image.ResolutionUnit"] = uint16_t(2); /* inches */
2098
2099 exifData["Exif.Image.Software"] = darktable_package_string;
2100
2101 // TODO: find a nice place for the missing metadata (tags, publisher, colorlabels?). Additionally find out
2102 // how to embed XMP data.
2103 // And shall we add a description of the history stack to Exif.Image.ImageHistory?
2104 if(imgid >= 0)
2105 {
2106 /* Delete metadata taken from the original file if it's fields we manage in dt, too */
2107 static const char * keys[] = {
2108 "Exif.Image.Artist",
2109 "Exif.Image.ImageDescription",
2110 "Exif.Photo.UserComment",
2111 "Exif.Image.Copyright",
2112 "Exif.Image.Rating",
2113 "Exif.Image.RatingPercent",
2114 "Exif.Photo.SubSecTimeOriginal",
2115 "Exif.GPSInfo.GPSVersionID",
2116 "Exif.GPSInfo.GPSLongitudeRef",
2117 "Exif.GPSInfo.GPSLatitudeRef",
2118 "Exif.GPSInfo.GPSLongitude",
2119 "Exif.GPSInfo.GPSLatitude",
2120 "Exif.GPSInfo.GPSAltitudeRef",
2121 "Exif.GPSInfo.GPSAltitude"
2122 };
2123 static const guint n_keys = G_N_ELEMENTS(keys);
2124 dt_remove_exif_keys(exifData, keys, n_keys);
2125
2126 GList *res = dt_metadata_get(imgid, "Xmp.dc.creator", NULL);
2127 if(!IS_NULL_PTR(res))
2128 {
2129 exifData["Exif.Image.Artist"] = (char *)res->data;
2130 g_list_free_full(res, dt_free_gpointer);
2131 res = NULL;
2132 }
2133
2134 res = dt_metadata_get(imgid, "Xmp.dc.description", NULL);
2135 if(!IS_NULL_PTR(res))
2136 {
2137 char *desc = (char *)res->data;
2138 if(g_str_is_ascii(desc))
2139 exifData["Exif.Image.ImageDescription"] = desc;
2140 else
2141 exifData["Exif.Photo.UserComment"] = desc;
2142 g_list_free_full(res, dt_free_gpointer);
2143 res = NULL;
2144 }
2145#if EXIV2_TEST_VERSION(0,27,4)
2146 else
2147 // mandatory tag for TIFF/EP and recommended for Exif, empty is ok (unknown)
2148 // but correctly written only by exiv2 >= 0.27.4
2149 exifData["Exif.Image.ImageDescription"] = "";
2150#endif
2151
2152 res = dt_metadata_get(imgid, "Xmp.dc.rights", NULL);
2153 if(!IS_NULL_PTR(res))
2154 {
2155 exifData["Exif.Image.Copyright"] = (char *)res->data;
2156 g_list_free_full(res, dt_free_gpointer);
2157 res = NULL;
2158 }
2159#if EXIV2_TEST_VERSION(0,27,4)
2160 else
2161 // mandatory tag for TIFF/EP and optional for Exif, empty is ok (unknown)
2162 // but correctly written only by exiv2 >= 0.27.4
2163 exifData["Exif.Image.Copyright"] = "";
2164#endif
2165
2166 res = dt_metadata_get(imgid, "Xmp.xmp.Rating", NULL);
2167 if(!IS_NULL_PTR(res))
2168 {
2169 const int rating = GPOINTER_TO_INT(res->data) + 1;
2170 exifData["Exif.Image.Rating"] = rating;
2171 g_list_free(res);
2172 res = NULL;
2173 }
2174
2175 // GPS data
2176 dt_remove_exif_geotag(exifData);
2177 const dt_image_t *cimg = dt_image_cache_get(darktable.image_cache, imgid, 'r');
2178 if(!isnan(cimg->geoloc.longitude) && !isnan(cimg->geoloc.latitude))
2179 {
2180 exifData["Exif.GPSInfo.GPSVersionID"] = "02 02 00 00";
2181 exifData["Exif.GPSInfo.GPSLongitudeRef"] = (cimg->geoloc.longitude < 0) ? "W" : "E";
2182 exifData["Exif.GPSInfo.GPSLatitudeRef"] = (cimg->geoloc.latitude < 0) ? "S" : "N";
2183
2184 long long_deg = (int)floor(fabs(cimg->geoloc.longitude));
2185 long lat_deg = (int)floor(fabs(cimg->geoloc.latitude));
2186 long long_min = (int)floor((fabs(cimg->geoloc.longitude) - floor(fabs(cimg->geoloc.longitude))) * 60000000);
2187 long lat_min = (int)floor((fabs(cimg->geoloc.latitude) - floor(fabs(cimg->geoloc.latitude))) * 60000000);
2188 gchar *long_str = g_strdup_printf("%ld/1 %ld/1000000 0/1", long_deg, long_min);
2189 gchar *lat_str = g_strdup_printf("%ld/1 %ld/1000000 0/1", lat_deg, lat_min);
2190 exifData["Exif.GPSInfo.GPSLongitude"] = long_str;
2191 exifData["Exif.GPSInfo.GPSLatitude"] = lat_str;
2192 dt_free(long_str);
2193 dt_free(lat_str);
2194 }
2195 if(!isnan(cimg->geoloc.elevation))
2196 {
2197 exifData["Exif.GPSInfo.GPSVersionID"] = "02 02 00 00";
2198 exifData["Exif.GPSInfo.GPSAltitudeRef"] = (cimg->geoloc.elevation < 0) ? "1" : "0";
2199
2200 long ele_dm = (int)floor(fabs(10.0 * cimg->geoloc.elevation));
2201 gchar *ele_str = g_strdup_printf("%ld/10", ele_dm);
2202 exifData["Exif.GPSInfo.GPSAltitude"] = ele_str;
2203 dt_free(ele_str);
2204 }
2205
2206 // According to the Exif specs DateTime is to be set to the last modification time while
2207 // DateTimeOriginal is to be kept.
2208 // For us "keeping" it means to write out what we have in DB to support people adding a time offset in
2209 // the geotagging module.
2210 gchar new_datetime[DT_DATETIME_EXIF_LENGTH];
2211 dt_datetime_now_to_exif(new_datetime);
2212 exifData["Exif.Image.DateTime"] = new_datetime;
2213 gchar datetime[DT_DATETIME_LENGTH];
2214 dt_datetime_img_to_exif(datetime, sizeof(datetime), cimg);
2215 datetime[DT_DATETIME_EXIF_LENGTH - 1] = '\0';
2216 exifData["Exif.Image.DateTimeOriginal"] = datetime;
2217 exifData["Exif.Photo.DateTimeOriginal"] = datetime;
2218 if(g_strcmp0(&datetime[DT_DATETIME_EXIF_LENGTH], "000"))
2219 exifData["Exif.Photo.SubSecTimeOriginal"] = &datetime[DT_DATETIME_EXIF_LENGTH];
2220
2222 }
2223
2224 Exiv2::Blob blob;
2225 Exiv2::ExifParser::encode(blob, Exiv2::bigEndian, exifData);
2226 const size_t length = blob.size();
2227 *buf = (uint8_t *)malloc(length);
2228 if (IS_NULL_PTR(*buf))
2229 {
2230 return 0;
2231 }
2232 memcpy(*buf, &(blob[0]), length);
2233 return length;
2234 }
2235 catch(Exiv2::AnyError &e)
2236 {
2237 // std::cerr.rdbuf(savecerr);
2238 std::string s(e.what());
2239 std::cerr << "[exiv2 dt_exif_read_blob] " << path << ": " << s << std::endl;
2240 dt_free(*buf);
2241 return 0;
2242 }
2243}
2244
2245// encode binary blob into text:
2246char *dt_exif_xmp_encode(const unsigned char *input, const int len, int *output_len)
2247{
2248#define COMPRESS_THRESHOLD 100
2249
2250 gboolean do_compress = FALSE;
2251
2252 // if input data field exceeds a certain size we compress it and convert to base64;
2253 // main reason for compression: make more xmp data fit into 64k segment within
2254 // JPEG output files.
2255 char *config = dt_conf_get_string("compress_xmp_tags");
2256 if(config)
2257 {
2258 if(!strcmp(config, "always"))
2259 do_compress = TRUE;
2260 else if((len > COMPRESS_THRESHOLD) && !strcmp(config, "only large entries"))
2261 do_compress = TRUE;
2262 else
2263 do_compress = FALSE;
2264 dt_free(config);
2265 }
2266
2267 return dt_exif_xmp_encode_internal(input, len, output_len, do_compress);
2268
2269#undef COMPRESS_THRESHOLD
2270}
2271
2272char *dt_exif_xmp_encode_internal(const unsigned char *input, const int len, int *output_len, gboolean do_compress)
2273{
2274 char *output = NULL;
2275
2276 if(do_compress)
2277 {
2278 int result;
2279 uLongf destLen = compressBound(len);
2280 unsigned char *buffer1 = (unsigned char *)malloc(destLen);
2281
2282 result = compress(buffer1, &destLen, input, len);
2283
2284 if(result != Z_OK)
2285 {
2286 dt_free(buffer1);
2287 return NULL;
2288 }
2289
2290 // we store the compression factor
2291 const int factor = MIN(len / destLen + 1, 99);
2292
2293 char *buffer2 = (char *)g_base64_encode(buffer1, destLen);
2294 dt_free(buffer1);
2295 if(IS_NULL_PTR(buffer2)) return NULL;
2296
2297 int outlen = strlen(buffer2) + 5; // leading "gz" + compression factor + base64 string + trailing '\0'
2298 output = (char *)malloc(outlen);
2299 if(IS_NULL_PTR(output))
2300 {
2301 dt_free(buffer2);
2302 return NULL;
2303 }
2304
2305 output[0] = 'g';
2306 output[1] = 'z';
2307 output[2] = factor / 10 + '0';
2308 output[3] = factor % 10 + '0';
2309 g_strlcpy(output + 4, buffer2, outlen);
2310 dt_free(buffer2);
2311
2312 if(output_len) *output_len = outlen;
2313 }
2314 else
2315 {
2316 const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
2317
2318 output = (char *)malloc(2 * len + 1);
2319 if(IS_NULL_PTR(output)) return NULL;
2320
2321 if(output_len) *output_len = 2 * len + 1;
2322
2323 for(int i = 0; i < len; i++)
2324 {
2325 const int hi = input[i] >> 4;
2326 const int lo = input[i] & 15;
2327 output[2 * i] = hex[hi];
2328 output[2 * i + 1] = hex[lo];
2329 }
2330 output[2 * len] = '\0';
2331 }
2332
2333 return output;
2334}
2335
2336// and back to binary
2337unsigned char *dt_exif_xmp_decode(const char *input, const int len, int *output_len)
2338{
2339 unsigned char *output = NULL;
2340
2341 // check if data is in compressed format
2342 if(!strncmp(input, "gz", 2))
2343 {
2344 // we have compressed data in base64 representation with leading "gz"
2345
2346 // get stored compression factor so we know the needed buffer size for uncompress
2347 const float factor = 10 * (input[2] - '0') + (input[3] - '0');
2348
2349 // get a rw copy of input buffer omitting leading "gz" and compression factor
2350 unsigned char *buffer = (unsigned char *)strdup(input + 4);
2351 if(IS_NULL_PTR(buffer)) return NULL;
2352
2353 // decode from base64 to compressed binary
2354 gsize compressed_size;
2355 g_base64_decode_inplace((char *)buffer, &compressed_size);
2356
2357 // do the actual uncompress step
2358 int result = Z_BUF_ERROR;
2359 uLongf bufLen = factor * compressed_size;
2360 uLongf destLen;
2361
2362 // we know the actual compression factor but if that fails we re-try with
2363 // increasing buffer sizes, eg. we don't know (unlikely) factors > 99
2364 do
2365 {
2366 if(output)
2367 {
2368 dt_free(output);
2369 }
2370 output = (unsigned char *)malloc(bufLen);
2371 if(IS_NULL_PTR(output)) break;
2372
2373 destLen = bufLen;
2374
2375 result = uncompress(output, &destLen, buffer, compressed_size);
2376
2377 bufLen *= 2;
2378
2379 } while(result == Z_BUF_ERROR);
2380
2381
2382 dt_free(buffer);
2383
2384 if(result != Z_OK)
2385 {
2386 if(output)
2387 {
2388 dt_free(output);
2389 }
2390 return NULL;
2391 }
2392
2393 if(output_len) *output_len = destLen;
2394 }
2395 else
2396 {
2397// we have uncompressed data in hexadecimal ascii representation
2398
2399// ascii table:
2400// 48- 57 0-9
2401// 97-102 a-f
2402#define TO_BINARY(a) (a > 57 ? a - 97 + 10 : a - 48)
2403
2404 // make sure that we don't find any unexpected characters indicating corrupted data
2405 if(strspn(input, "0123456789abcdef") != strlen(input)) return NULL;
2406
2407 output = (unsigned char *)malloc(len / 2);
2408 if(IS_NULL_PTR(output)) return NULL;
2409
2410 if(output_len) *output_len = len / 2;
2411
2412 for(int i = 0; i < len / 2; i++)
2413 {
2414 const int hi = TO_BINARY(input[2 * i]);
2415 const int lo = TO_BINARY(input[2 * i + 1]);
2416 output[i] = (hi << 4) | lo;
2417 }
2418#undef TO_BINARY
2419 }
2420
2421 return output;
2422}
2423
2424static void _exif_import_tags(dt_image_t *img, Exiv2::XmpData::iterator &pos)
2425{
2426 // tags in array
2427 const int cnt = pos->count();
2428
2429 sqlite3_stmt *stmt_sel_id, *stmt_ins_tags, *stmt_ins_tagged;
2430 DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM data.tags WHERE name = ?1", -1,
2431 &stmt_sel_id, NULL);
2432 DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "INSERT INTO data.tags (id, name) VALUES (NULL, ?1)",
2433 -1, &stmt_ins_tags, NULL);
2434 // clang-format off
2436 "INSERT INTO main.tagged_images (tagid, imgid, position)"
2437 " VALUES (?1, ?2,"
2438 " (SELECT (IFNULL(MAX(position),0) & 0xFFFFFFFF00000000) + (1 << 32)"
2439 " FROM main.tagged_images))",
2440 -1, &stmt_ins_tagged, NULL);
2441 // clang-format on
2442 for(int i = 0; i < cnt; i++)
2443 {
2444 char tagbuf[1024];
2445 std::string pos_str = pos->toString(i);
2446 g_strlcpy(tagbuf, pos_str.c_str(), sizeof(tagbuf));
2447 int tagid = -1;
2448 char *tag = tagbuf;
2449 while(tag)
2450 {
2451 char *next_tag = strstr(tag, ",");
2452 if(next_tag) *(next_tag++) = 0;
2453 // check if tag is available, get its id:
2454 for(int k = 0; k < 2; k++)
2455 {
2456 DT_DEBUG_SQLITE3_BIND_TEXT(stmt_sel_id, 1, tag, -1, SQLITE_TRANSIENT);
2457 if(sqlite3_step(stmt_sel_id) == SQLITE_ROW) tagid = sqlite3_column_int(stmt_sel_id, 0);
2458 sqlite3_reset(stmt_sel_id);
2459 sqlite3_clear_bindings(stmt_sel_id);
2460
2461 if(tagid > 0) break;
2462
2463 fprintf(stderr, "[xmp_import] creating tag: %s\n", tag);
2464 // create this tag (increment id, leave icon empty), retry.
2465 DT_DEBUG_SQLITE3_BIND_TEXT(stmt_ins_tags, 1, tag, -1, SQLITE_TRANSIENT);
2466 sqlite3_step(stmt_ins_tags);
2467 sqlite3_reset(stmt_ins_tags);
2468 sqlite3_clear_bindings(stmt_ins_tags);
2469 }
2470 // associate image and tag.
2471 DT_DEBUG_SQLITE3_BIND_INT(stmt_ins_tagged, 1, tagid);
2472 DT_DEBUG_SQLITE3_BIND_INT(stmt_ins_tagged, 2, img->id);
2473 sqlite3_step(stmt_ins_tagged);
2474 sqlite3_reset(stmt_ins_tagged);
2475 sqlite3_clear_bindings(stmt_ins_tagged);
2476
2477 tag = next_tag;
2478 }
2479 }
2480 sqlite3_finalize(stmt_sel_id);
2481 sqlite3_finalize(stmt_ins_tags);
2482 sqlite3_finalize(stmt_ins_tagged);
2483}
2484
2485typedef struct history_entry_t
2486{
2488 gboolean enabled;
2490 unsigned char *params;
2493 // int multi_name_hand_edited;
2496 unsigned char *blendop_params;
2498 int num;
2499 double iop_order; // kept for compatibility with xmp version < 4
2500
2501 // sanity checking
2504
2505// used for a hash table that maps mask_id to the mask data
2521
2522static void print_history_entry(history_entry_t *entry) __attribute__((unused));
2524{
2525 if(IS_NULL_PTR(entry) || IS_NULL_PTR(entry->operation))
2526 {
2527 std::cout << "malformed entry" << std::endl;
2528 return;
2529 }
2530
2531 std::cout << entry->operation << std::endl;
2532 std::cout << " modversion :" << entry->modversion << std::endl;
2533 std::cout << " enabled :" << entry->enabled << std::endl;
2534 std::cout << " params :" << (entry->params ? "<found>" : "<missing>") << std::endl;
2535 std::cout << " multi_name :" << (entry->multi_name ? entry->multi_name : "<missing>") << std::endl;
2536 std::cout << " multi_priority :" << entry->multi_priority << std::endl;
2537 std::cout << " iop_order :" << entry->iop_order << std::endl;
2538 std::cout << " blendop_version :" << entry->blendop_version << std::endl;
2539 std::cout << " blendop_params :" << (entry->blendop_params ? "<found>" : "<missing>") << std::endl;
2540 std::cout << std::endl;
2541}
2542
2543static void free_history_entry(gpointer data)
2544{
2545 history_entry_t *entry = (history_entry_t *)data;
2546 dt_free(entry->operation);
2547 dt_free(entry->multi_name);
2548 dt_free(entry->params);
2549 dt_free(entry->blendop_params);
2550 dt_free(entry);
2551}
2552
2553// we have to use pugixml as the old format could contain empty rdf:li elements in the multi_name array
2554// which causes problems when accessing it with libexiv2 :(
2555// superold is a flag indicating that data is wrapped in <rdf:Bag> instead of <rdf:Seq>.
2556static GList *read_history_v1(const std::string &xmpPacket, const char *filename, const int superold)
2557{
2558 GList *history_entries = NULL;
2559
2560 pugi::xml_document doc;
2561#if defined(PUGIXML_VERSION) && PUGIXML_VERSION >= 150
2562 pugi::xml_parse_result result = doc.load_string(xmpPacket.c_str());
2563#else
2564 pugi::xml_parse_result result = doc.load(xmpPacket.c_str());
2565#endif
2566
2567 if(!result)
2568 {
2569 std::cerr << "XML '" << filename << "' parsed with errors" << std::endl;
2570 std::cerr << "Error description: " << result.description() << std::endl;
2571 std::cerr << "Error offset: " << result.offset << std::endl;
2572 return NULL;
2573 }
2574
2575 // get the old elements
2576 // select_single_node() is deprecated and just kept for old versions shipped in some distributions
2577#if defined(PUGIXML_VERSION) && PUGIXML_VERSION >= 150
2578 pugi::xpath_node modversion = superold ?
2579 doc.select_node("//darktable:history_modversion/rdf:Bag"):
2580 doc.select_node("//darktable:history_modversion/rdf:Seq");
2581 pugi::xpath_node enabled = superold ?
2582 doc.select_node("//darktable:history_enabled/rdf:Bag"):
2583 doc.select_node("//darktable:history_enabled/rdf:Seq");
2584 pugi::xpath_node operation = superold ?
2585 doc.select_node("//darktable:history_operation/rdf:Bag"):
2586 doc.select_node("//darktable:history_operation/rdf:Seq");
2587 pugi::xpath_node params = superold ?
2588 doc.select_node("//darktable:history_params/rdf:Bag"):
2589 doc.select_node("//darktable:history_params/rdf:Seq");
2590 pugi::xpath_node blendop_params = superold ?
2591 doc.select_node("//darktable:blendop_params/rdf:Bag"):
2592 doc.select_node("//darktable:blendop_params/rdf:Seq");
2593 pugi::xpath_node blendop_version = superold ?
2594 doc.select_node("//darktable:blendop_version/rdf:Bag"):
2595 doc.select_node("//darktable:blendop_version/rdf:Seq");
2596 pugi::xpath_node multi_priority = superold ?
2597 doc.select_node("//darktable:multi_priority/rdf:Bag"):
2598 doc.select_node("//darktable:multi_priority/rdf:Seq");
2599 pugi::xpath_node multi_name = superold ?
2600 doc.select_node("//darktable:multi_name/rdf:Bag"):
2601 doc.select_node("//darktable:multi_name/rdf:Seq");
2602#else
2603 pugi::xpath_node modversion = superold ?
2604 doc.select_single_node("//darktable:history_modversion/rdf:Bag"):
2605 doc.select_single_node("//darktable:history_modversion/rdf:Seq");
2606 pugi::xpath_node enabled = superold ?
2607 doc.select_single_node("//darktable:history_enabled/rdf:Bag"):
2608 doc.select_single_node("//darktable:history_enabled/rdf:Seq");
2609 pugi::xpath_node operation = superold ?
2610 doc.select_single_node("//darktable:history_operation/rdf:Bag"):
2611 doc.select_single_node("//darktable:history_operation/rdf:Seq");
2612 pugi::xpath_node params = superold ?
2613 doc.select_single_node("//darktable:history_params/rdf:Bag"):
2614 doc.select_single_node("//darktable:history_params/rdf:Seq");
2615 pugi::xpath_node blendop_params = superold ?
2616 doc.select_single_node("//darktable:blendop_params/rdf:Bag"):
2617 doc.select_single_node("//darktable:blendop_params/rdf:Seq");
2618 pugi::xpath_node blendop_version = superold ?
2619 doc.select_single_node("//darktable:blendop_version/rdf:Bag"):
2620 doc.select_single_node("//darktable:blendop_version/rdf:Seq");
2621 pugi::xpath_node multi_priority = superold ?
2622 doc.select_single_node("//darktable:multi_priority/rdf:Bag"):
2623 doc.select_single_node("//darktable:multi_priority/rdf:Seq");
2624 pugi::xpath_node multi_name = superold ?
2625 doc.select_single_node("//darktable:multi_name/rdf:Bag"):
2626 doc.select_single_node("//darktable:multi_name/rdf:Seq");
2627#endif
2628
2629 // fill the list of history entries. we are iterating over history_operation as we know that it's there.
2630 // the other iters are taken care of manually.
2631 auto modversion_iter = modversion.node().children().begin();
2632 auto enabled_iter = enabled.node().children().begin();
2633 auto params_iter = params.node().children().begin();
2634 auto blendop_params_iter = blendop_params.node().children().begin();
2635 auto blendop_version_iter = blendop_version.node().children().begin();
2636 auto multi_priority_iter = multi_priority.node().children().begin();
2637 auto multi_name_iter = multi_name.node().children().begin();
2638
2639 for(pugi::xml_node operation_iter: operation.node().children())
2640 {
2641 history_entry_t *current_entry = (history_entry_t *)calloc(1, sizeof(history_entry_t));
2642 current_entry->blendop_version = 1; // default version in case it's not specified
2643 history_entries = g_list_append(history_entries, current_entry);
2644
2645 current_entry->operation = g_strdup(operation_iter.child_value());
2646
2647 current_entry->enabled = g_strcmp0(enabled_iter->child_value(), "0") != 0;
2648
2649 current_entry->modversion = atoi(modversion_iter->child_value());
2650
2651 current_entry->params = dt_exif_xmp_decode(params_iter->child_value(), strlen(params_iter->child_value()),
2652 &current_entry->params_len);
2653
2654 if(multi_name && multi_name_iter != multi_name.node().children().end())
2655 {
2656 current_entry->multi_name = g_strdup(multi_name_iter->child_value());
2657 multi_name_iter++;
2658 }
2659
2660 if(multi_priority && multi_priority_iter != multi_priority.node().children().end())
2661 {
2662 current_entry->multi_priority = atoi(multi_priority_iter->child_value());
2663 multi_priority_iter++;
2664 }
2665
2666 if(blendop_version && blendop_version_iter != blendop_version.node().children().end())
2667 {
2668 current_entry->blendop_version = atoi(blendop_version_iter->child_value());
2669 blendop_version_iter++;
2670 }
2671
2672 if(blendop_params && blendop_params_iter != blendop_params.node().children().end())
2673 {
2674 current_entry->blendop_params = dt_exif_xmp_decode(blendop_params_iter->child_value(),
2675 strlen(blendop_params_iter->child_value()),
2676 &current_entry->blendop_params_len);
2677 blendop_params_iter++;
2678 }
2679
2680 current_entry->iop_order = -1.0;
2681
2682 modversion_iter++;
2683 enabled_iter++;
2684 params_iter++;
2685 }
2686
2687 return history_entries;
2688}
2689
2690static GList *read_history_v2(Exiv2::XmpData &xmpData, const char *filename)
2691{
2692 GList *history_entries = NULL;
2693 history_entry_t *current_entry = NULL;
2694
2695 for(auto history = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.history")); history != xmpData.end(); history++)
2696 {
2697 // TODO: support human readable params via introspection with something like this:
2698 // XmpText: Xmp.darktable.history[1]/darktable:settings[1]/darktable:name = width
2699 // XmpText: Xmp.darktable.history[1]/darktable:settings[1]/darktable:value = 23
2700
2701 std::string key_item = history->key();
2702 char *key = g_strdup(key_item.c_str());
2703 char *key_iter = key;
2704 if(g_str_has_prefix(key, "Xmp.darktable.history["))
2705 {
2706 key_iter += strlen("Xmp.darktable.history[");
2707 errno = 0;
2708 unsigned int n = strtol(key_iter, &key_iter, 10);
2709 if(errno)
2710 {
2711 std::cerr << "error reading history from '" << key << "' (" << filename << ")" << std::endl;
2712 g_list_free_full(history_entries, free_history_entry);
2713 history_entries = NULL;
2714 dt_free(key);
2715 return NULL;
2716 }
2717
2718 // skip everything that isn't part of the actual array
2719 if(*(key_iter++) != ']')
2720 {
2721 std::cerr << "error reading history from '"
2722 << key << "' (" << filename << ")" << std::endl;
2723 g_list_free_full(history_entries, free_history_entry);
2724 history_entries = NULL;
2725 dt_free(key);
2726 return NULL;
2727 }
2728 if(*(key_iter++) != '/') goto skip;
2729 if(*key_iter == '?') key_iter++;
2730
2731 // make sure we are filling in the details of the correct entry
2732 unsigned int length = g_list_length(history_entries);
2733 if(n > length)
2734 {
2735 current_entry = (history_entry_t *)calloc(1, sizeof(history_entry_t));
2736 current_entry->blendop_version = 1; // default version in case it's not specified
2737 current_entry->iop_order = -1.0;
2738 history_entries = g_list_append(history_entries, current_entry);
2739 }
2740 else if(n < length)
2741 {
2742 // AFAICT this can't happen with regular exiv2 parsed XMP data, but better safe than sorry.
2743 // it can happen though when constructing things in a unusual order and then passing it to us without
2744 // serializing it in between
2745 current_entry = (history_entry_t *)g_list_nth_data(history_entries, n - 1); // XMP starts counting at 1!
2746 }
2747
2748 // go on reading things into current_entry
2749 if(g_str_has_prefix(key_iter, "darktable:operation"))
2750 {
2751 current_entry->have_operation = TRUE;
2752 std::string value_item = history->toString();
2753 current_entry->operation = g_strdup(value_item.c_str());
2754 }
2755 else if(g_str_has_prefix(key_iter, "darktable:num"))
2756 {
2757 current_entry->num = history->toLong();
2758 }
2759 else if(g_str_has_prefix(key_iter, "darktable:enabled"))
2760 {
2761 current_entry->enabled = history->toLong() == 1;
2762 }
2763 else if(g_str_has_prefix(key_iter, "darktable:modversion"))
2764 {
2765 current_entry->have_modversion = TRUE;
2766 current_entry->modversion = history->toLong();
2767 }
2768 else if(g_str_has_prefix(key_iter, "darktable:params"))
2769 {
2770 current_entry->have_params = TRUE;
2771 std::string value_item = history->toString();
2772 current_entry->params = dt_exif_xmp_decode(value_item.c_str(),
2773 history->size(),
2774 &current_entry->params_len);
2775 }
2776 /*
2777 else if(g_str_has_prefix(key_iter, "darktable:multi_name_hand_edited"))
2778 {
2779 current_entry->multi_name_hand_edited = history->toLong() == 1;
2780 }
2781 */
2782 else if(g_str_has_prefix(key_iter, "darktable:multi_name"))
2783 {
2784 std::string value_item = history->toString();
2785 current_entry->multi_name = g_strdup(value_item.c_str());
2786 }
2787 else if(g_str_has_prefix(key_iter, "darktable:multi_priority"))
2788 {
2789 current_entry->multi_priority = history->toLong();
2790 }
2791 else if(g_str_has_prefix(key_iter, "darktable:iop_order"))
2792 {
2793 // we ensure reading the iop_order as a high precision float
2794 std::string value_item = history->toString();
2795 string str = g_strdup(value_item.c_str());
2796 static const std::locale& c_locale = std::locale("C");
2797 std::istringstream istring(str);
2798 istring.imbue(c_locale);
2799 istring >> current_entry->iop_order;
2800 }
2801 else if(g_str_has_prefix(key_iter, "darktable:blendop_version"))
2802 {
2803 current_entry->blendop_version = history->toLong();
2804 }
2805 else if(g_str_has_prefix(key_iter, "darktable:blendop_params"))
2806 {
2807 std::string value_item = history->toString();
2808 current_entry->blendop_params =
2809 dt_exif_xmp_decode(value_item.c_str(),
2810 history->size(),
2811 &current_entry->blendop_params_len);
2812 }
2813 }
2814skip:
2815 dt_free(key);
2816 }
2817
2818 // a final sanity check
2819 for(GList *iter = history_entries; iter; iter = g_list_next(iter))
2820 {
2821 history_entry_t *entry = (history_entry_t *)iter->data;
2822 if(!(entry->have_operation && entry->have_params && entry->have_modversion))
2823 {
2824 std::cerr << "[exif] error: reading history from '" << filename << "' failed due to missing tags" << std::endl;
2825 g_list_free_full(history_entries, free_history_entry);
2826 history_entries = NULL;
2827 break;
2828 }
2829 }
2830
2831 return history_entries;
2832}
2833
2834void free_mask_entry(gpointer data)
2835{
2836 mask_entry_t *entry = (mask_entry_t *)data;
2837 dt_free(entry->mask_name);
2838 dt_free(entry->mask_points);
2839 dt_free(entry->mask_src);
2840 dt_free(entry);
2841}
2842
2843static GHashTable *read_masks(Exiv2::XmpData &xmpData, const char *filename, const int version)
2844{
2845 GHashTable *mask_entries = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, free_mask_entry);
2846
2847 // TODO: turn that into something like Xmp.darktable.history!
2848 Exiv2::XmpData::iterator mask;
2849 Exiv2::XmpData::iterator mask_name;
2850 Exiv2::XmpData::iterator mask_type;
2851 Exiv2::XmpData::iterator mask_version;
2852 Exiv2::XmpData::iterator mask_id;
2853 Exiv2::XmpData::iterator mask_nb;
2854 Exiv2::XmpData::iterator mask_src;
2855 if((mask = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.mask"))) != xmpData.end()
2856 && (mask_src = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.mask_src"))) != xmpData.end()
2857 && (mask_name = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.mask_name"))) != xmpData.end()
2858 && (mask_type = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.mask_type"))) != xmpData.end()
2859 && (mask_version = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.mask_version"))) != xmpData.end()
2860 && (mask_id = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.mask_id"))) != xmpData.end()
2861 && (mask_nb = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.mask_nb"))) != xmpData.end())
2862 {
2863 // fixes API change happened after exiv2 v0.27.2.1
2864 const size_t cnt = (size_t)mask->count();
2865 const size_t mask_src_cnt = (size_t)mask_src->count();
2866 const size_t mask_name_cnt = (size_t)mask_name->count();
2867 const size_t mask_type_cnt = (size_t)mask_type->count();
2868 const size_t mask_version_cnt = (size_t)mask_version->count();
2869 const size_t mask_id_cnt = (size_t)mask_id->count();
2870 const size_t mask_nb_cnt = (size_t)mask_nb->count();
2871 if(cnt == mask_src_cnt && cnt == mask_name_cnt && cnt == mask_type_cnt
2872 && cnt == mask_version_cnt && cnt == mask_id_cnt && cnt == mask_nb_cnt)
2873 {
2874 for(size_t i = 0; i < cnt; i++)
2875 {
2876 mask_entry_t *entry = (mask_entry_t *)calloc(1, sizeof(mask_entry_t));
2877
2878 entry->version = version;
2879 entry->mask_id = mask_id->toLong(i);
2880 entry->mask_type = mask_type->toLong(i);
2881 std::string mask_name_str = mask_name->toString(i);
2882 if(mask_name_str.c_str() != NULL)
2883 entry->mask_name = g_strdup(mask_name_str.c_str());
2884 else
2885 entry->mask_name = g_strdup("form");
2886
2887 entry->mask_version = mask_version->toLong(i);
2888
2889 std::string mask_str = mask->toString(i);
2890 const char *mask_c = mask_str.c_str();
2891 const size_t mask_c_len = strlen(mask_c);
2892 entry->mask_points = dt_exif_xmp_decode(mask_c, mask_c_len, &entry->mask_points_len);
2893
2894 entry->mask_nb = mask_nb->toLong(i);
2895
2896 std::string mask_src_str = mask_src->toString(i);
2897 const char *mask_src_c = mask_src_str.c_str();
2898 const size_t mask_src_c_len = strlen(mask_src_c);
2899 entry->mask_src = dt_exif_xmp_decode(mask_src_c, mask_src_c_len, &entry->mask_src_len);
2900
2901 g_hash_table_insert(mask_entries, &entry->mask_id, (gpointer)entry);
2902 }
2903 }
2904 }
2905
2906 return mask_entries;
2907}
2908
2909static GList *read_masks_v3(Exiv2::XmpData &xmpData, const char *filename, const int version)
2910{
2911 GList *history_entries = NULL;
2912 mask_entry_t *current_entry = NULL;
2913
2914 for(auto history = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.masks_history")); history != xmpData.end(); history++)
2915 {
2916 // TODO: support human readable params via introspection with something like this:
2917 // XmpText: Xmp.darktable.history[1]/darktable:settings[1]/darktable:name = width
2918 // XmpText: Xmp.darktable.history[1]/darktable:settings[1]/darktable:value = 23
2919
2920 std::string key_item = history->key();
2921 char *key = g_strdup(key_item.c_str());
2922 char *key_iter = key;
2923 if(g_str_has_prefix(key, "Xmp.darktable.masks_history["))
2924 {
2925 key_iter += strlen("Xmp.darktable.masks_history[");
2926 errno = 0;
2927 unsigned int n = strtol(key_iter, &key_iter, 10);
2928 if(errno)
2929 {
2930 std::cerr << "error reading masks history from '" << key << "' (" << filename << ")" << std::endl;
2931 g_list_free_full(history_entries, free_mask_entry);
2932 history_entries = NULL;
2933 dt_free(key);
2934 return NULL;
2935 }
2936
2937 // skip everything that isn't part of the actual array
2938 if(*(key_iter++) != ']')
2939 {
2940 std::cerr << "error reading masks history from '" << key << "' (" << filename << ")" << std::endl;
2941 g_list_free_full(history_entries, free_mask_entry);
2942 history_entries = NULL;
2943 dt_free(key);
2944 return NULL;
2945 }
2946 if(*(key_iter++) != '/') goto skip;
2947 if(*key_iter == '?') key_iter++;
2948
2949 // make sure we are filling in the details of the correct entry
2950 unsigned int length = g_list_length(history_entries);
2951 if(n > length)
2952 {
2953 current_entry = (mask_entry_t *)calloc(1, sizeof(mask_entry_t));
2954 current_entry->version = version;
2955 history_entries = g_list_append(history_entries, current_entry);
2956 }
2957 else if(n < length)
2958 {
2959 // AFAICT this can't happen with regular exiv2 parsed XMP data, but better safe than sorry.
2960 // it can happen though when constructing things in a unusual order and then passing it to us without
2961 // serializing it in between
2962 current_entry = (mask_entry_t *)g_list_nth_data(history_entries, n - 1); // XMP starts counting at 1!
2963 }
2964
2965 // go on reading things into current_entry
2966 if(g_str_has_prefix(key_iter, "darktable:mask_num"))
2967 {
2968 current_entry->mask_num = history->toLong();
2969 }
2970 else if(g_str_has_prefix(key_iter, "darktable:mask_id"))
2971 {
2972 current_entry->mask_id = history->toLong();
2973 }
2974 else if(g_str_has_prefix(key_iter, "darktable:mask_type"))
2975 {
2976 current_entry->mask_type = history->toLong();
2977 }
2978 else if(g_str_has_prefix(key_iter, "darktable:mask_name"))
2979 {
2980 std::string value_item = history->toString();
2981 current_entry->mask_name = g_strdup(value_item.c_str());
2982 }
2983 else if(g_str_has_prefix(key_iter, "darktable:mask_version"))
2984 {
2985 current_entry->mask_version = history->toLong();
2986 }
2987 else if(g_str_has_prefix(key_iter, "darktable:mask_points"))
2988 {
2989 std::string value_item = history->toString();
2990 current_entry->mask_points = dt_exif_xmp_decode(value_item.c_str(),
2991 history->size(),
2992 &current_entry->mask_points_len);
2993 }
2994 else if(g_str_has_prefix(key_iter, "darktable:mask_nb"))
2995 {
2996 current_entry->mask_nb = history->toLong();
2997 }
2998 else if(g_str_has_prefix(key_iter, "darktable:mask_src"))
2999 {
3000 std::string value_item = history->toString();
3001 current_entry->mask_src = dt_exif_xmp_decode(value_item.c_str(),
3002 history->size(),
3003 &current_entry->mask_src_len);
3004 }
3005
3006 }
3007skip:
3008 dt_free(key);
3009 }
3010
3011 return history_entries;
3012}
3013
3014static void add_mask_entry_to_db(int32_t imgid, mask_entry_t *entry)
3015{
3016 // add the mask entry only once
3017 if(entry->already_added)
3018 return;
3019
3020 const int mask_num = 0;
3021
3022 sqlite3_stmt *stmt;
3023 // clang-format off
3026 "INSERT INTO main.masks_history (imgid, num, formid, form, name, version, points, points_count, source) "
3027 "VALUES (?1, ?9, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",
3028 -1, &stmt, NULL);
3029 // clang-format on
3030 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
3031 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, entry->mask_id);
3032 DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, entry->mask_type);
3033 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 4, entry->mask_name, -1, SQLITE_TRANSIENT);
3034 DT_DEBUG_SQLITE3_BIND_INT(stmt, 5, entry->mask_version);
3035 DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 6, entry->mask_points, entry->mask_points_len, SQLITE_TRANSIENT);
3036 DT_DEBUG_SQLITE3_BIND_INT(stmt, 7, entry->mask_nb);
3037 DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 8, entry->mask_src, entry->mask_src_len, SQLITE_TRANSIENT);
3038 if(entry->version < 3)
3039 {
3040 DT_DEBUG_SQLITE3_BIND_INT(stmt, 9, mask_num);
3041 }
3042 else
3043 {
3044 DT_DEBUG_SQLITE3_BIND_INT(stmt, 9, entry->mask_num);
3045 }
3046 int prepare_result = sqlite3_step(stmt);
3047 sqlite3_finalize(stmt);
3048
3049 // Mark entry to true only after confirmation the sql insert was successful
3050 if(prepare_result == SQLITE_OK)
3051 {
3052 entry->already_added = TRUE;
3053 }
3054}
3055
3056static void add_non_clone_mask_entries_to_db(gpointer key, gpointer value, gpointer user_data)
3057{
3058 int32_t imgid = *(int *)user_data;
3059 mask_entry_t *entry = (mask_entry_t *)value;
3060 if(!(entry->mask_type & (DT_MASKS_CLONE | DT_MASKS_NON_CLONE))) add_mask_entry_to_db(imgid, entry);
3061}
3062
3063static void add_mask_entries_to_db(int32_t imgid, GHashTable *mask_entries, int mask_id)
3064{
3065 if(mask_id <= 0) return;
3066
3067 // look for mask_id in the hash table
3068 mask_entry_t *entry = (mask_entry_t *)g_hash_table_lookup(mask_entries, &mask_id);
3069
3070 if(IS_NULL_PTR(entry)) return;
3071
3072 // if it's a group: recurse into the children first
3073 if(entry->mask_type & DT_MASKS_GROUP)
3074 {
3076 if((int)(entry->mask_nb * sizeof(dt_masks_form_group_t)) != entry->mask_points_len)
3077 {
3078 fprintf(stderr, "[masks] error loading masks from xmp file, bad binary blob size.\n");
3079 return;
3080 }
3081 for(int i = 0; i < entry->mask_nb; i++)
3082 add_mask_entries_to_db(imgid, mask_entries, group[i].formid);
3083 }
3084
3085 add_mask_entry_to_db(imgid, entry);
3086}
3087
3088// get MAX multi_priority
3089int _get_max_multi_priority(GList *history, const char *operation)
3090{
3091 int max_prio = 0;
3092
3093 for(GList *iter = history; iter; iter = g_list_next(iter))
3094 {
3095 history_entry_t *entry = (history_entry_t *)iter->data;
3096
3097 if(!strcmp(entry->operation, operation))
3098 max_prio = MAX(max_prio, entry->multi_priority);
3099 }
3100
3101 return max_prio;
3102}
3103
3104// need a write lock on *img (non-const) to write stars (and soon color labels).
3105int dt_exif_xmp_read(dt_image_t *img, const char *filename, const int history_only)
3106{
3107 // exclude pfm to avoid stupid errors on the console
3108 const char *c = filename + strlen(filename) - 4;
3109 if(c >= filename && !strcmp(c, ".pfm")) return 1;
3110 try
3111 {
3112 // read xmp sidecar
3113 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(WIDEN(filename)));
3114 assert(image.get() != 0);
3116 Exiv2::XmpData &xmpData = image->xmpData();
3117
3118 sqlite3_stmt *stmt;
3119
3120 Exiv2::XmpData::iterator pos;
3121
3122 int xmp_version = 0;
3123 GList *iop_order_list = NULL;
3124 dt_iop_order_t iop_order_version = DT_IOP_ORDER_LEGACY;
3125
3126 int num_masks = 0;
3127 if((pos = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.xmp_version"))) != xmpData.end())
3128 xmp_version = pos->toLong();
3129
3130 if(!history_only)
3131 {
3132 // otherwise we ignore title, description, ... from non-dt xmp files :(
3133 const size_t ns_pos = image->xmpPacket().find("xmlns:darktable=\"http://darktable.sf.net/\"");
3134 const bool is_a_dt_xmp = (ns_pos != std::string::npos);
3135 _exif_decode_xmp_data(img, xmpData, is_a_dt_xmp ? xmp_version : -1, false);
3136 }
3137
3138
3139 // convert legacy flip bits (will not be written anymore, convert to flip history item here):
3140 if((pos = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.raw_params"))) != xmpData.end())
3141 {
3142 union {
3143 int32_t in;
3145 } raw_params;
3146 raw_params.in = pos->toLong();
3147 const int32_t user_flip = raw_params.out.user_flip;
3148 img->legacy_flip.user_flip = user_flip;
3149 img->legacy_flip.legacy = 0;
3150 }
3151
3152 int32_t preset_applied = 0;
3153
3154 if((pos = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.auto_presets_applied"))) != xmpData.end())
3155 {
3156 preset_applied = pos->toLong();
3157
3158 // in any case, this is no legacy image.
3160 }
3161 else if(xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.xmp_version")) == xmpData.end())
3162 {
3163 // if there is no darktable xmp_version in the XMP, this XMP must have been generated by another
3164 // program; since this is the first time darktable sees it, there can't be legacy presets
3166 }
3167 else
3168 {
3169 // so we are legacy (thus have to clear the no-legacy flag)
3170 img->flags &= ~DT_IMAGE_NO_LEGACY_PRESETS;
3171 }
3172 // when we are reading the xmp data it doesn't make sense to flag the image as removed
3173 img->flags &= ~DT_IMAGE_REMOVE;
3174
3175 if(xmp_version == 4 || xmp_version == 5)
3176 {
3177 if((pos = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.iop_order_version"))) != xmpData.end())
3178 {
3179 iop_order_version = (dt_iop_order_t)pos->toLong();
3180 }
3181
3182 if((pos = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.iop_order_list"))) != xmpData.end())
3183 {
3184 iop_order_list = dt_ioppr_deserialize_text_iop_order_list(pos->toString().c_str());
3185 }
3186 else
3187 iop_order_list = dt_ioppr_get_iop_order_list_version(iop_order_version);
3188 }
3189 else if(xmp_version == 3)
3190 {
3191 iop_order_version = DT_IOP_ORDER_LEGACY;
3192
3193 if((pos = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.iop_order_version"))) != xmpData.end())
3194 {
3195 // All iop-order version before 3 are legacy one. Starting with version 3 we have the first
3196 // attempts to propose the final v3 iop-order.
3197 iop_order_version = pos->toLong() < 3 ? DT_IOP_ORDER_LEGACY : DT_IOP_ORDER_ANSEL_RAW;
3198 iop_order_list = dt_ioppr_get_iop_order_list_version(iop_order_version);
3199 }
3200 else
3202 }
3203 else
3204 {
3205 iop_order_version = DT_IOP_ORDER_LEGACY;
3207 }
3208
3209 // masks
3210 GHashTable *mask_entries = NULL;
3211 GList *mask_entries_v3 = NULL;
3212
3213 // clean all old masks for this image
3215
3216 // read the masks from the file first so we can add them to the db while reading history entries
3217 if(xmp_version < 3)
3218 mask_entries = read_masks(xmpData, filename, xmp_version);
3219 else
3220 mask_entries_v3 = read_masks_v3(xmpData, filename, xmp_version);
3221
3222 // now add all masks that are not used for cloning. keeping them might be useful.
3223 // TODO: make this configurable? or remove it altogether?
3225
3226 if(xmp_version < 3)
3227 {
3228 g_hash_table_foreach(mask_entries, add_non_clone_mask_entries_to_db, &img->id);
3229 }
3230 else
3231 {
3232 for(GList *m_entries = g_list_first(mask_entries_v3); m_entries; m_entries = g_list_next(m_entries))
3233 {
3234 mask_entry_t *mask_entry = (mask_entry_t *)m_entries->data;
3235
3236 add_mask_entry_to_db(img->id, mask_entry);
3237 }
3238 }
3239
3241
3242 // history
3243 int num = 0;
3244 gboolean all_ok = TRUE;
3245 GList *history_entries = NULL;
3246
3247 if(xmp_version < 2)
3248 {
3249 std::string &xmpPacket = image->xmpPacket();
3250 history_entries = read_history_v1(xmpPacket, filename, 0);
3251 if(!history_entries) // didn't work? try super old version with rdf:Bag
3252 history_entries = read_history_v1(xmpPacket, filename, 1);
3253 }
3254 else if(xmp_version == 2 || xmp_version == 3 || xmp_version == 4 || xmp_version == 5 )
3255 history_entries = read_history_v2(xmpData, filename);
3256 else
3257 {
3258 std::cerr << "error: Xmp schema version " << xmp_version << " in " << filename << " not supported" << std::endl;
3259 g_hash_table_destroy(mask_entries);
3260 return 1;
3261 }
3262
3264
3266 {
3267 fprintf(stderr, "[exif] error deleting history for image %d\n", img->id);
3268 fprintf(stderr, "[exif] %s\n", sqlite3_errmsg(dt_database_get(darktable.db)));
3269 all_ok = FALSE;
3270 goto end;
3271 }
3272
3273 for(GList *iter = history_entries; iter; iter = g_list_next(iter))
3274 {
3275 history_entry_t *entry = (history_entry_t *)iter->data;
3276 const int db_num = (xmp_version < 3) ? num : entry->num;
3277
3278 if(entry->blendop_params)
3279 {
3280 if(xmp_version < 3)
3281 {
3282 // check what mask entries belong to this iop and add them to the db
3283 const dt_develop_blend_params_t *blendop_params = (dt_develop_blend_params_t *)entry->blendop_params;
3284 add_mask_entries_to_db(img->id, mask_entries, blendop_params->mask_id);
3285 }
3286 }
3287
3288 if(!dt_history_db_write_history_item(img->id, db_num, entry->operation,
3289 entry->params, entry->params_len,
3290 entry->modversion, entry->enabled != 0,
3291 entry->blendop_params, entry->blendop_params_len,
3292 entry->blendop_version, entry->multi_priority,
3293 entry->multi_name ? entry->multi_name : ""))
3294 {
3295 fprintf(stderr, "[exif] error adding history entry for image %d\n", img->id);
3296 fprintf(stderr, "[exif] %s\n", sqlite3_errmsg(dt_database_get(darktable.db)));
3297 all_ok = FALSE;
3298 goto end;
3299 }
3300
3301 num++;
3302 }
3303
3304 // we now need to create and store the proper iop-order taking into account all multi-instances
3305 // for previous xmp versions.
3306
3307 if(xmp_version < 4)
3308 {
3309 // in this version we had iop-order, use it
3310
3311 for(GList *iter = history_entries; iter; iter = g_list_next(iter))
3312 {
3313 history_entry_t *entry = (history_entry_t *)iter->data;
3314
3316 memcpy(e->operation, entry->operation, sizeof(e->operation));
3317 e->instance = entry->multi_priority;
3318
3319 if(xmp_version < 3)
3320 {
3321 // prior to v3 there was no iop-order, all multi instances where grouped, use the multièpriority
3322 // to restore the order.
3323 GList *base_order = dt_ioppr_get_iop_order_link(iop_order_list, entry->operation, -1);
3324
3325 if(base_order)
3326 e->o.iop_order_f = ((dt_iop_order_entry_t *)(base_order->data))->o.iop_order_f
3327 - entry->multi_priority / 100.0f;
3328 else if(!dt_deprecated(entry->operation))
3329 {
3330 fprintf(stderr,
3331 "[exif] cannot get iop-order for module '%s', XMP may be corrupted\n",
3332 entry->operation);
3333 g_list_free_full(iop_order_list, dt_free_gpointer);
3334 iop_order_list = NULL;
3335 g_list_free_full(history_entries, free_history_entry);
3336 history_entries = NULL;
3337 g_list_free_full(mask_entries_v3, free_mask_entry);
3338 mask_entries_v3 = NULL;
3339 if(mask_entries) g_hash_table_destroy(mask_entries);
3340 dt_free(e);
3341 return 1;
3342 }
3343 }
3344 else
3345 {
3346 // otherwise use the iop_order for the entry
3347 e->o.iop_order_f = entry->iop_order; // legacy iop-order is used to insert item at the right location
3348 }
3349
3350 // remove a current entry from the iop-order list if found as it will be replaced, possibly with another iop-order
3351 // with a new item in the history.
3352
3353 GList *link = dt_ioppr_get_iop_order_link(iop_order_list, e->operation, e->instance);
3354 if(link) iop_order_list = g_list_delete_link(iop_order_list, link);
3355
3356 iop_order_list = g_list_append(iop_order_list, e);
3357 }
3358
3359 // and finally reorder the full list based on the iop-order
3360
3361 iop_order_list = g_list_sort(iop_order_list, dt_sort_iop_list_by_order_f);
3362 }
3363
3364 // if masks have been read, create a mask manager entry in history
3365 if(xmp_version < 3)
3366 {
3368 "SELECT COUNT(*) FROM main.masks_history WHERE imgid = ?1", -1,
3369 &stmt, NULL);
3370 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, img->id);
3371 if(sqlite3_step(stmt) == SQLITE_ROW)
3372 num_masks = sqlite3_column_int(stmt, 0);
3373 sqlite3_finalize(stmt);
3374
3375 if(num_masks > 0)
3376 {
3377 // make room for mask_manager entry
3379 {
3380 fprintf(stderr, "[exif] error shifting history nums for image %d\n", img->id);
3381 fprintf(stderr, "[exif] %s\n", sqlite3_errmsg(dt_database_get(darktable.db)));
3382 all_ok = FALSE;
3383 goto end;
3384 }
3385 if(!dt_history_db_write_history_item(img->id, 0, "mask_manager", NULL, 0, 1, 0, NULL, 0, 0, 0, ""))
3386 {
3387 fprintf(stderr, "[exif] error adding mask history entry for image %d\n", img->id);
3388 fprintf(stderr, "[exif] %s\n", sqlite3_errmsg(dt_database_get(darktable.db)));
3389 all_ok = FALSE;
3390 goto end;
3391 }
3392
3393 num++;
3394 }
3395 }
3396
3397 // we shouldn't change history_end when no history was read!
3398 if((pos = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.history_end"))) != xmpData.end() && num > 0)
3399 {
3400 int history_end = MIN(pos->toLong(), num);
3401 if(num_masks > 0) history_end++;
3402 if((history_end < 1) && preset_applied) preset_applied = -1;
3403 if(!dt_history_set_end(img->id, history_end))
3404 {
3405 fprintf(stderr, "[exif] error writing history_end for image %d\n", img->id);
3406 fprintf(stderr, "[exif] %s\n", sqlite3_errmsg(dt_database_get(darktable.db)));
3407 all_ok = FALSE;
3408 goto end;
3409 }
3410 }
3411 else
3412 {
3413 if(preset_applied) preset_applied = -1;
3414 const int32_t history_end = dt_history_db_get_next_history_num(img->id);
3415 if(!dt_history_set_end(img->id, history_end))
3416 {
3417 fprintf(stderr, "[exif] error writing history_end for image %d\n", img->id);
3418 fprintf(stderr, "[exif] %s\n", sqlite3_errmsg(dt_database_get(darktable.db)));
3419 all_ok = FALSE;
3420 goto end;
3421 }
3422 }
3423 if(!dt_ioppr_write_iop_order_list(iop_order_list, img->id))
3424 {
3425 fprintf(stderr, "[exif] error writing iop_list for image %d\n", img->id);
3426 fprintf(stderr, "[exif] %s\n", sqlite3_errmsg(dt_database_get(darktable.db)));
3427 all_ok = FALSE;
3428 goto end;
3429 }
3430
3431 end:
3432
3433 read_xmp_timestamps(xmpData, img, xmp_version);
3434
3435 // set or clear bit in image struct. ONLY set if the Xmp.darktable.auto_presets_applied was 1
3436 // AND there was a history in xmp
3437 if(preset_applied > 0)
3438 {
3440 }
3441 else
3442 {
3443 // not found for old or buggy xmp where it was found but history was 0
3444 img->flags &= ~DT_IMAGE_AUTO_PRESETS_APPLIED;
3445
3446 if(preset_applied < 0)
3447 {
3448 fprintf(stderr,"[exif] dt_exif_xmp_read for %s, id %i found auto_presets_applied but there was no history\n",filename,img->id);
3449 }
3450 }
3451
3452 g_list_free_full(iop_order_list, dt_free_gpointer);
3453 iop_order_list = NULL;
3454 g_list_free_full(history_entries, free_history_entry);
3455 history_entries = NULL;
3456 g_list_free_full(mask_entries_v3, free_mask_entry);
3457 mask_entries_v3 = NULL;
3458 if(mask_entries) g_hash_table_destroy(mask_entries);
3459
3460 if(all_ok)
3461 {
3463
3464 // history_hash (current only)
3465 if((pos = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.history_current_hash"))) != xmpData.end())
3466 {
3467 int hash_len = 0;
3468 unsigned char *decoded = dt_exif_xmp_decode(pos->toString().c_str(), strlen(pos->toString().c_str()),
3469 &hash_len);
3470 if(decoded && hash_len == (int)sizeof(uint64_t))
3471 {
3472 uint64_t be_hash = 0;
3473 memcpy(&be_hash, decoded, sizeof(be_hash));
3474 img->history_hash = GUINT64_FROM_BE(be_hash);
3475 }
3476 dt_free(decoded);
3477 }
3478 }
3479 else
3480 {
3481 std::cerr << "[exif] error reading history from '" << filename << "'" << std::endl;
3483 return 1;
3484 }
3485
3486 }
3487 catch(Exiv2::AnyError &e)
3488 {
3489 // actually nobody's interested in that if the file doesn't exist:
3490 // std::string s(e.what());
3491 // std::cerr << "[exiv2] " << filename << ": " << s << std::endl;
3492 return 1;
3493 }
3494 return 0;
3495}
3496
3497// add history metadata to XmpData
3498static void dt_set_xmp_dt_history(Exiv2::XmpData &xmpData, const int32_t imgid, int history_end)
3499{
3500 sqlite3_stmt *stmt;
3501
3502 // masks:
3503 char key[1024];
3504
3505 // masks history:
3506 int num = 1;
3507
3508 // create an array:
3509 Exiv2::XmpTextValue tvm("");
3510 tvm.setXmpArrayType(Exiv2::XmpValue::xaSeq);
3511 xmpData.add(Exiv2::XmpKey("Xmp.darktable.masks_history"), &tvm);
3512 // clang-format off
3515 "SELECT imgid, formid, form, name, version, points, points_count, source, num"
3516 " FROM main.masks_history"
3517 " WHERE imgid = ?1"
3518 " ORDER BY num",
3519 -1, &stmt, NULL);
3520 // clang-format on
3521 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
3522 while(sqlite3_step(stmt) == SQLITE_ROW)
3523 {
3524 const int32_t mask_num = sqlite3_column_int(stmt, 8);
3525 const int32_t mask_id = sqlite3_column_int(stmt, 1);
3526 const int32_t mask_type = sqlite3_column_int(stmt, 2);
3527 const char *mask_name = (const char *)sqlite3_column_text(stmt, 3);
3528 const int32_t mask_version = sqlite3_column_int(stmt, 4);
3529 int32_t len = sqlite3_column_bytes(stmt, 5);
3530 char *mask_d = dt_exif_xmp_encode((const unsigned char *)sqlite3_column_blob(stmt, 5), len, NULL);
3531 const int32_t mask_nb = sqlite3_column_int(stmt, 6);
3532 len = sqlite3_column_bytes(stmt, 7);
3533 char *mask_src = dt_exif_xmp_encode((const unsigned char *)sqlite3_column_blob(stmt, 7), len, NULL);
3534
3535 snprintf(key, sizeof(key), "Xmp.darktable.masks_history[%d]/darktable:mask_num", num);
3536 xmpData[key] = mask_num;
3537 snprintf(key, sizeof(key), "Xmp.darktable.masks_history[%d]/darktable:mask_id", num);
3538 xmpData[key] = mask_id;
3539 snprintf(key, sizeof(key), "Xmp.darktable.masks_history[%d]/darktable:mask_type", num);
3540 xmpData[key] = mask_type;
3541 snprintf(key, sizeof(key), "Xmp.darktable.masks_history[%d]/darktable:mask_name", num);
3542 xmpData[key] = mask_name;
3543 snprintf(key, sizeof(key), "Xmp.darktable.masks_history[%d]/darktable:mask_version", num);
3544 xmpData[key] = mask_version;
3545 snprintf(key, sizeof(key), "Xmp.darktable.masks_history[%d]/darktable:mask_points", num);
3546 xmpData[key] = mask_d;
3547 snprintf(key, sizeof(key), "Xmp.darktable.masks_history[%d]/darktable:mask_nb", num);
3548 xmpData[key] = mask_nb;
3549 snprintf(key, sizeof(key), "Xmp.darktable.masks_history[%d]/darktable:mask_src", num);
3550 xmpData[key] = mask_src;
3551
3552 dt_free(mask_d);
3553 dt_free(mask_src);
3554
3555 num++;
3556 }
3557 sqlite3_finalize(stmt);
3558
3559 // history stack:
3560 num = 1;
3561
3562 // create an array:
3563 Exiv2::XmpTextValue tv("");
3564 tv.setXmpArrayType(Exiv2::XmpValue::xaSeq);
3565 xmpData.add(Exiv2::XmpKey("Xmp.darktable.history"), &tv);
3566 // clang-format off
3569 "SELECT module, operation, op_params, enabled, blendop_params, "
3570 " blendop_version, multi_priority, multi_name, num"
3571 " FROM main.history"
3572 " WHERE imgid = ?1"
3573 " ORDER BY num",
3574 -1, &stmt, NULL);
3575 // clang-format on
3576 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
3577 while(sqlite3_step(stmt) == SQLITE_ROW)
3578 {
3579 int32_t modversion = sqlite3_column_int(stmt, 0);
3580 const char *operation = (const char *)sqlite3_column_text(stmt, 1);
3581 int32_t params_len = sqlite3_column_bytes(stmt, 2);
3582 const void *params_blob = sqlite3_column_blob(stmt, 2);
3583 const int32_t enabled = sqlite3_column_int(stmt, 3);
3584 const void *blendop_blob = sqlite3_column_blob(stmt, 4);
3585 int32_t blendop_params_len = sqlite3_column_bytes(stmt, 4);
3586 int32_t blendop_version = sqlite3_column_int(stmt, 5);
3587 int32_t multi_priority = sqlite3_column_int(stmt, 6);
3588 const char *multi_name = (const char *)sqlite3_column_text(stmt, 7);
3589 int32_t hist_num = sqlite3_column_int(stmt, 8);
3590
3591 if(IS_NULL_PTR(operation)) continue; // no op is fatal.
3592
3593 char *params = dt_exif_xmp_encode((const unsigned char *)params_blob, params_len, NULL);
3594
3595 snprintf(key, sizeof(key), "Xmp.darktable.history[%d]/darktable:num", num);
3596 xmpData[key] = hist_num;
3597 snprintf(key, sizeof(key), "Xmp.darktable.history[%d]/darktable:operation", num);
3598 xmpData[key] = operation;
3599 snprintf(key, sizeof(key), "Xmp.darktable.history[%d]/darktable:enabled", num);
3600 xmpData[key] = enabled;
3601 snprintf(key, sizeof(key), "Xmp.darktable.history[%d]/darktable:modversion", num);
3602 xmpData[key] = modversion;
3603 snprintf(key, sizeof(key), "Xmp.darktable.history[%d]/darktable:params", num);
3604 xmpData[key] = params;
3605 snprintf(key, sizeof(key), "Xmp.darktable.history[%d]/darktable:multi_name", num);
3606 xmpData[key] = multi_name ? multi_name : "";
3607 snprintf(key, sizeof(key), "Xmp.darktable.history[%d]/darktable:multi_priority", num);
3608 xmpData[key] = multi_priority;
3609
3610 if(blendop_blob)
3611 {
3612 // this shouldn't fail in general, but reading is robust enough to allow it,
3613 // and flipping images from LT will result in this being left out
3614 char *blendop_params = dt_exif_xmp_encode((const unsigned char *)blendop_blob, blendop_params_len, NULL);
3615 snprintf(key, sizeof(key), "Xmp.darktable.history[%d]/darktable:blendop_version", num);
3616 xmpData[key] = blendop_version;
3617 snprintf(key, sizeof(key), "Xmp.darktable.history[%d]/darktable:blendop_params", num);
3618 xmpData[key] = blendop_params;
3619 dt_free(blendop_params);
3620 }
3621
3622 dt_free(params);
3623
3624 num++;
3625 }
3626
3627 sqlite3_finalize(stmt);
3628 if(history_end == -1) history_end = num - 1;
3629 else history_end = MIN(history_end, num - 1); // safeguard for some old buggy libraries
3630 xmpData["Xmp.darktable.history_end"] = history_end;
3631}
3632
3633// add timestamps to XmpData.
3634static void set_xmp_timestamps(Exiv2::XmpData &xmpData, const int32_t imgid)
3635{
3636 static const char *keys[] =
3637 {
3638 "Xmp.darktable.import_timestamp",
3639 "Xmp.darktable.change_timestamp",
3640 "Xmp.darktable.export_timestamp",
3641 "Xmp.darktable.print_timestamp"
3642 };
3643 static const guint n_keys = G_N_ELEMENTS(keys);
3644 dt_remove_xmp_keys(xmpData, keys, n_keys);
3645
3646 sqlite3_stmt *stmt;
3647 // clang-format off
3650 "SELECT import_timestamp, change_timestamp, export_timestamp, print_timestamp"
3651 " FROM main.images"
3652 " WHERE id = ?1",
3653 -1, &stmt, NULL);
3654 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
3655 // clang-format on
3656
3657 if(sqlite3_step(stmt) == SQLITE_ROW)
3658 {
3659 if(sqlite3_column_type(stmt, 0) != SQLITE_NULL)
3660 xmpData["Xmp.darktable.import_timestamp"] = sqlite3_column_int64(stmt, 0);
3661 if(sqlite3_column_type(stmt, 1) != SQLITE_NULL)
3662 xmpData["Xmp.darktable.change_timestamp"] = sqlite3_column_int64(stmt, 1);
3663 if(sqlite3_column_type(stmt, 2) != SQLITE_NULL)
3664 xmpData["Xmp.darktable.export_timestamp"] = sqlite3_column_int64(stmt, 2);
3665 if(sqlite3_column_type(stmt, 3) != SQLITE_NULL)
3666 xmpData["Xmp.darktable.print_timestamp"] = sqlite3_column_int64(stmt, 3);
3667 }
3668 sqlite3_finalize(stmt);
3669}
3670
3671GTimeSpan _convert_unix_to_gtimespan(const time_t unix)
3672{
3673 GDateTime *gdt = g_date_time_new_from_unix_utc(unix);
3674 if(gdt)
3675 {
3676 GTimeSpan gts = dt_datetime_gdatetime_to_gtimespan(gdt);
3677 g_date_time_unref(gdt);
3678 return gts;
3679 }
3680 return 0;
3681}
3682
3683// read timestamps from XmpData
3684void read_xmp_timestamps(Exiv2::XmpData &xmpData, dt_image_t *img, const int xmp_version)
3685{
3686 Exiv2::XmpData::iterator pos;
3687
3688 // Do not read for import_ts. It must be updated at each import.
3689 if((pos = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.change_timestamp"))) != xmpData.end())
3690 {
3691 if(xmp_version > 5)
3692 img->change_timestamp = pos->toLong();
3693 else if(pos->toLong() >= 1)
3694 img->change_timestamp = _convert_unix_to_gtimespan(pos->toLong());
3695 }
3696 if((pos = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.export_timestamp"))) != xmpData.end())
3697 {
3698 if(xmp_version > 5)
3699 img->export_timestamp = pos->toLong();
3700 else if(pos->toLong() >= 1)
3701 img->export_timestamp = _convert_unix_to_gtimespan(pos->toLong());
3702 }
3703 if((pos = xmpData.findKey(Exiv2::XmpKey("Xmp.darktable.print_timestamp"))) != xmpData.end())
3704 {
3705 if(xmp_version > 5)
3706 img->print_timestamp = pos->toLong();
3707 else if(pos->toLong() >= 1)
3708 img->print_timestamp = _convert_unix_to_gtimespan(pos->toLong());
3709 }
3710}
3711
3712static void dt_remove_xmp_exif_geotag(Exiv2::XmpData &xmpData)
3713{
3714 static const char *keys[] =
3715 {
3716 "Xmp.exif.GPSVersionID",
3717 "Xmp.exif.GPSLongitude",
3718 "Xmp.exif.GPSLatitude",
3719 "Xmp.exif.GPSAltitudeRef",
3720 "Xmp.exif.GPSAltitude"
3721 };
3722 static const guint n_keys = G_N_ELEMENTS(keys);
3723 dt_remove_xmp_keys(xmpData, keys, n_keys);
3724}
3725
3726static void dt_set_xmp_exif_geotag(Exiv2::XmpData &xmpData, double longitude, double latitude, double altitude)
3727{
3729 if(!isnan(longitude) && !isnan(latitude))
3730 {
3731 char long_dir = 'E', lat_dir = 'N';
3732 if(longitude < 0) long_dir = 'W';
3733 if(latitude < 0) lat_dir = 'S';
3734
3735 longitude = fabs(longitude);
3736 latitude = fabs(latitude);
3737
3738 int long_deg = (int)floor(longitude);
3739 int lat_deg = (int)floor(latitude);
3740 double long_min = (longitude - (double)long_deg) * 60.0;
3741 double lat_min = (latitude - (double)lat_deg) * 60.0;
3742
3743 char *str = (char *)g_malloc(G_ASCII_DTOSTR_BUF_SIZE);
3744
3745 g_ascii_formatd(str, G_ASCII_DTOSTR_BUF_SIZE, "%08f", long_min);
3746 gchar *long_str = g_strdup_printf("%d,%s%c", long_deg, str, long_dir);
3747 g_ascii_formatd(str, G_ASCII_DTOSTR_BUF_SIZE, "%08f", lat_min);
3748 gchar *lat_str = g_strdup_printf("%d,%s%c", lat_deg, str, lat_dir);
3749
3750 xmpData["Xmp.exif.GPSVersionID"] = "2.2.0.0";
3751 xmpData["Xmp.exif.GPSLongitude"] = long_str;
3752 xmpData["Xmp.exif.GPSLatitude"] = lat_str;
3753 dt_free(long_str);
3754 dt_free(lat_str);
3755 dt_free(str);
3756 }
3757 if(!isnan(altitude))
3758 {
3759 xmpData["Xmp.exif.GPSAltitudeRef"] = (altitude < 0) ? "1" : "0";
3760
3761 long ele_dm = (int)floor(fabs(10.0 * altitude));
3762 gchar *ele_str = g_strdup_printf("%ld/10", ele_dm);
3763 xmpData["Xmp.exif.GPSAltitude"] = ele_str;
3764 dt_free(ele_str);
3765 }
3766}
3767
3768static void dt_set_xmp_dt_metadata(Exiv2::XmpData &xmpData, const int32_t imgid, const gboolean export_flag)
3769{
3770 sqlite3_stmt *stmt;
3771 // metadata
3772 DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT key, value FROM main.meta_data WHERE id = ?1",
3773 -1, &stmt, NULL);
3774 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
3775 while(sqlite3_step(stmt) == SQLITE_ROW)
3776 {
3777 int keyid = sqlite3_column_int(stmt, 0);
3778 if(export_flag && (dt_metadata_get_type(keyid) != DT_METADATA_TYPE_INTERNAL))
3779 {
3780 const gchar *name = dt_metadata_get_name(keyid);
3781 gchar *setting = dt_util_dstrcat(NULL, "plugins/lighttable/metadata/%s_flag", name);
3782 const uint32_t flag = dt_conf_get_int(setting);
3783 dt_free(setting);
3785 xmpData[dt_metadata_get_key(keyid)] = sqlite3_column_text(stmt, 1);
3786 }
3787 else
3788 xmpData[dt_metadata_get_key(keyid)] = sqlite3_column_text(stmt, 1);
3789 }
3790 sqlite3_finalize(stmt);
3791
3792 // color labels
3793 char val[2048];
3794 std::unique_ptr<Exiv2::Value> v(Exiv2::Value::create(Exiv2::xmpSeq)); // or xmpBag or xmpAlt.
3795
3796 /* Already initialized v = Exiv2::Value::create(Exiv2::xmpSeq); // or xmpBag or xmpAlt.*/
3797 DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT color FROM main.color_labels WHERE imgid=?1",
3798 -1, &stmt, NULL);
3799 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
3800 while(sqlite3_step(stmt) == SQLITE_ROW)
3801 {
3802 snprintf(val, sizeof(val), "%d", sqlite3_column_int(stmt, 0));
3803 v->read(val);
3804 }
3805 sqlite3_finalize(stmt);
3806 if(v->count() > 0) xmpData.add(Exiv2::XmpKey("Xmp.darktable.colorlabels"), v.get());
3807}
3808
3809// helper to create an xmp data thing. throws exiv2 exceptions if stuff goes wrong.
3810static void _exif_xmp_append_history_hash(Exiv2::XmpData &xmpData, const int32_t imgid,
3811 const dt_image_t *image)
3812{
3813 const dt_image_t *cached = image;
3814 if(IS_NULL_PTR(cached))
3815 cached = dt_image_cache_get(darktable.image_cache, imgid, 'r');
3816
3817 if(cached)
3818 {
3819 if(cached->history_hash != UINT64_MAX)
3820 {
3821 const uint64_t be_hash = GUINT64_TO_BE(cached->history_hash);
3822 char *value = dt_exif_xmp_encode(reinterpret_cast<const unsigned char *>(&be_hash), sizeof(be_hash), NULL);
3823 if(value)
3824 {
3825 xmpData["Xmp.darktable.history_current_hash"] = value;
3826 dt_free(value);
3827 }
3828 }
3829 if(IS_NULL_PTR(image))
3831 }
3832}
3833
3834static void _exif_xmp_read_data(Exiv2::XmpData &xmpData, const int32_t imgid, const dt_image_t *image)
3835{
3836 const int xmp_version = DT_XMP_EXIF_VERSION;
3837 int stars = 1, raw_params = 0, history_end = -1;
3838 double longitude = NAN, latitude = NAN, altitude = NAN;
3839 gchar *filename = NULL;
3840 gchar *iop_order_list = NULL;
3841 GTimeSpan gts = 0;
3842
3843 // get stars and raw params from db
3844 sqlite3_stmt *stmt;
3845 // clang-format off
3847 "SELECT filename, flags, raw_parameters, "
3848 " longitude, latitude, altitude, history_end, datetime_taken"
3849 " FROM main.images"
3850 " WHERE id = ?1",
3851 -1, &stmt, NULL);
3852 // clang-format on
3853 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
3854 if(sqlite3_step(stmt) == SQLITE_ROW)
3855 {
3856 filename = (gchar *)sqlite3_column_text(stmt, 0);
3857 stars = sqlite3_column_int(stmt, 1);
3858 raw_params = sqlite3_column_int(stmt, 2);
3859 if(sqlite3_column_type(stmt, 3) == SQLITE_FLOAT) longitude = sqlite3_column_double(stmt, 3);
3860 if(sqlite3_column_type(stmt, 4) == SQLITE_FLOAT) latitude = sqlite3_column_double(stmt, 4);
3861 if(sqlite3_column_type(stmt, 5) == SQLITE_FLOAT) altitude = sqlite3_column_double(stmt, 5);
3862 history_end = sqlite3_column_int(stmt, 6);
3863 gts = sqlite3_column_int64(stmt, 7);
3864 }
3865
3866 // The pipe order only matters when history entries are exported. After
3867 // deleting history, avoid rebuilding a default order just to write an empty
3868 // sidecar: the default will be selected again when the image is opened.
3869 dt_iop_order_t iop_order_version = DT_IOP_ORDER_ANSEL_RAW;
3870 if(history_end > 0)
3871 {
3872 iop_order_version = dt_ioppr_get_iop_order_version(imgid);
3873 GList *iop_list = dt_ioppr_get_iop_order_list(imgid, TRUE);
3874
3875 if(iop_order_version == DT_IOP_ORDER_CUSTOM || dt_ioppr_has_multiple_instances(iop_list))
3876 {
3877 iop_order_list = dt_ioppr_serialize_text_iop_order_list(iop_list);
3878 }
3879 g_list_free_full(iop_list, dt_free_gpointer);
3880 iop_list = NULL;
3881 }
3882
3883 // Store datetime_taken as DateTimeOriginal to take into account the user's selected date/time
3884 gchar exif_datetime[DT_DATETIME_LENGTH];
3885 dt_datetime_gtimespan_to_exif(exif_datetime, sizeof(exif_datetime), gts);
3886 xmpData["Xmp.exif.DateTimeOriginal"] = exif_datetime;
3887
3888 // We have to erase the old ratings first as exiv2 seems to not change it otherwise.
3889 Exiv2::XmpData::iterator pos = xmpData.findKey(Exiv2::XmpKey("Xmp.xmp.Rating"));
3890 if(pos != xmpData.end()) xmpData.erase(pos);
3891 xmpData["Xmp.xmp.Rating"] = dt_image_get_xmp_rating_from_flags(stars);
3892
3893 // The original file name
3894 if(filename) xmpData["Xmp.xmpMM.DerivedFrom"] = filename;
3895
3896 // timestamps
3897 set_xmp_timestamps(xmpData, imgid);
3898
3899 // GPS data
3900 dt_set_xmp_exif_geotag(xmpData, longitude, latitude, altitude);
3901
3902 // the meta data
3903 dt_set_xmp_dt_metadata(xmpData, imgid, FALSE);
3904
3905 // get tags from db, store in dublin core
3906 std::unique_ptr<Exiv2::Value> v1(Exiv2::Value::create(Exiv2::xmpBag));
3907
3908 std::unique_ptr<Exiv2::Value> v2(Exiv2::Value::create(Exiv2::xmpBag));
3909
3910 GList *tags = dt_tag_get_list(imgid);
3911 try
3912 {
3913 for(GList *tag = tags; tag; tag = g_list_next(tag))
3914 {
3915 v1->read((char *)tag->data);
3916 }
3917 }
3918 catch(...)
3919 {
3920 g_list_free_full(tags, dt_free_gpointer);
3921 throw;
3922 }
3923 if(v1->count() > 0) xmpData.add(Exiv2::XmpKey("Xmp.dc.subject"), v1.get());
3924 g_list_free_full(tags, dt_free_gpointer);
3925 tags = NULL;
3926
3927 GList *hierarchical = dt_tag_get_hierarchical(imgid);
3928 try
3929 {
3930 for(GList *hier = hierarchical; hier; hier = g_list_next(hier))
3931 {
3932 v2->read((char *)hier->data);
3933 }
3934 }
3935 catch(...)
3936 {
3937 g_list_free_full(hierarchical, dt_free_gpointer);
3938 throw;
3939 }
3940 if(v2->count() > 0) xmpData.add(Exiv2::XmpKey("Xmp.lr.hierarchicalSubject"), v2.get());
3941 g_list_free_full(hierarchical, dt_free_gpointer);
3942 hierarchical = NULL;
3943 /* TODO: Add tags to IPTC namespace as well */
3944
3945 xmpData["Xmp.darktable.xmp_version"] = xmp_version;
3946 xmpData["Xmp.darktable.raw_params"] = raw_params;
3948 xmpData["Xmp.darktable.auto_presets_applied"] = 1;
3949 else
3950 xmpData["Xmp.darktable.auto_presets_applied"] = 0;
3951 dt_set_xmp_dt_history(xmpData, imgid, history_end);
3952
3953 if(history_end > 0)
3954 {
3955 xmpData["Xmp.darktable.iop_order_version"] = iop_order_version;
3956 if(iop_order_list) xmpData["Xmp.darktable.iop_order_list"] = iop_order_list;
3957 }
3958
3959 _exif_xmp_append_history_hash(xmpData, imgid, image);
3960
3961 sqlite3_finalize(stmt);
3962 dt_free(iop_order_list);
3963}
3964
3965// helper to create an xmp data thing. throws exiv2 exceptions if stuff goes wrong.
3966static void _exif_xmp_read_data_export(Exiv2::XmpData &xmpData, const int32_t imgid, dt_export_metadata_t *metadata)
3967{
3968 const int xmp_version = DT_XMP_EXIF_VERSION;
3969 int stars = 1, raw_params = 0, history_end = -1;
3970 double longitude = NAN, latitude = NAN, altitude = NAN;
3971 gchar *filename = NULL;
3972 GTimeSpan gts = 0;
3973 gchar *iop_order_list = NULL;
3974
3975 // get stars and raw params from db
3976 sqlite3_stmt *stmt;
3977 // clang-format off
3979 "SELECT filename, flags, raw_parameters, "
3980 " longitude, latitude, altitude, history_end, datetime_taken"
3981 " FROM main.images"
3982 " WHERE id = ?1",
3983 -1, &stmt, NULL);
3984 // clang-format on
3985 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
3986 if(sqlite3_step(stmt) == SQLITE_ROW)
3987 {
3988 filename = (gchar *)sqlite3_column_text(stmt, 0);
3989 stars = sqlite3_column_int(stmt, 1);
3990 raw_params = sqlite3_column_int(stmt, 2);
3991 if(sqlite3_column_type(stmt, 3) == SQLITE_FLOAT) longitude = sqlite3_column_double(stmt, 3);
3992 if(sqlite3_column_type(stmt, 4) == SQLITE_FLOAT) latitude = sqlite3_column_double(stmt, 4);
3993 if(sqlite3_column_type(stmt, 5) == SQLITE_FLOAT) altitude = sqlite3_column_double(stmt, 5);
3994 history_end = sqlite3_column_int(stmt, 6);
3995 gts = sqlite3_column_int64(stmt, 7);
3996 }
3997
3998 // The pipe order only matters when history entries are exported. After
3999 // deleting history, avoid rebuilding a default order just to write an empty
4000 // sidecar: the default will be selected again when the image is opened.
4001 dt_iop_order_t iop_order_version = DT_IOP_ORDER_ANSEL_RAW;
4002 if(history_end > 0)
4003 {
4004 iop_order_version = dt_ioppr_get_iop_order_version(imgid);
4005 GList *iop_list = dt_ioppr_get_iop_order_list(imgid, TRUE);
4006
4007 if(iop_order_version == DT_IOP_ORDER_CUSTOM || dt_ioppr_has_multiple_instances(iop_list))
4008 {
4009 iop_order_list = dt_ioppr_serialize_text_iop_order_list(iop_list);
4010 }
4011 g_list_free_full(iop_list, dt_free_gpointer);
4012 iop_list = NULL;
4013 }
4014
4015 if(metadata->flags & DT_META_METADATA)
4016 {
4017 // Store datetime_taken as DateTimeOriginal to take into account the user's selected date/time
4018 if (!(metadata->flags & DT_META_EXIF))
4019 {
4020 gchar exif_datetime[DT_DATETIME_LENGTH];
4021 dt_datetime_gtimespan_to_exif(exif_datetime, sizeof(exif_datetime), gts);
4022 xmpData["Xmp.exif.DateTimeOriginal"] = exif_datetime;
4023 }
4024 // We have to erase the old ratings first as exiv2 seems to not change it otherwise.
4025 Exiv2::XmpData::iterator pos = xmpData.findKey(Exiv2::XmpKey("Xmp.xmp.Rating"));
4026 if(pos != xmpData.end()) xmpData.erase(pos);
4027 xmpData["Xmp.xmp.Rating"] = dt_image_get_xmp_rating_from_flags(stars);
4028
4029 // The original file name
4030 if(filename) xmpData["Xmp.xmpMM.DerivedFrom"] = filename;
4031 }
4032
4033 // GPS data
4034 if (metadata->flags & DT_META_GEOTAG)
4035 dt_set_xmp_exif_geotag(xmpData, longitude, latitude, altitude);
4036 else
4038
4039
4040 // the meta data
4041 if (metadata->flags & DT_META_METADATA)
4042 dt_set_xmp_dt_metadata(xmpData, imgid, TRUE);
4043
4044 // tags
4045 if (metadata->flags & DT_META_TAG)
4046 {
4047 // get tags from db, store in dublin core
4048 std::unique_ptr<Exiv2::Value> v1(Exiv2::Value::create(Exiv2::xmpBag));
4049 GList *tags = dt_tag_get_list_export(imgid, metadata->flags);
4050 try
4051 {
4052 for(GList *tag = tags; tag; tag = g_list_next(tag))
4053 {
4054 v1->read((char *)tag->data);
4055 }
4056 }
4057 catch(...)
4058 {
4059 g_list_free_full(tags, dt_free_gpointer);
4060 throw;
4061 }
4062 if(v1->count() > 0) xmpData.add(Exiv2::XmpKey("Xmp.dc.subject"), v1.get());
4063 g_list_free_full(tags, dt_free_gpointer);
4064 tags = NULL;
4065 }
4066
4067 if (metadata->flags & DT_META_HIERARCHICAL_TAG)
4068 {
4069 std::unique_ptr<Exiv2::Value> v2(Exiv2::Value::create(Exiv2::xmpBag));
4070 GList *hierarchical = dt_tag_get_hierarchical_export(imgid, metadata->flags);
4071 try
4072 {
4073 for(GList *hier = hierarchical; hier; hier = g_list_next(hier))
4074 {
4075 v2->read((char *)hier->data);
4076 }
4077 }
4078 catch(...)
4079 {
4080 g_list_free_full(hierarchical, dt_free_gpointer);
4081 throw;
4082 }
4083 if(v2->count() > 0) xmpData.add(Exiv2::XmpKey("Xmp.lr.hierarchicalSubject"), v2.get());
4084 g_list_free_full(hierarchical, dt_free_gpointer);
4085 hierarchical = NULL;
4086 }
4087
4088 if (metadata->flags & DT_META_DT_HISTORY)
4089 {
4090 xmpData["Xmp.darktable.xmp_version"] = xmp_version;
4091 xmpData["Xmp.darktable.raw_params"] = raw_params;
4093 xmpData["Xmp.darktable.auto_presets_applied"] = 1;
4094 else
4095 xmpData["Xmp.darktable.auto_presets_applied"] = 0;
4096 dt_set_xmp_dt_history(xmpData, imgid, history_end);
4097
4098 if(history_end > 0)
4099 {
4100 xmpData["Xmp.darktable.iop_order_version"] = iop_order_version;
4101 if(iop_order_list) xmpData["Xmp.darktable.iop_order_list"] = iop_order_list;
4102 }
4103 _exif_xmp_append_history_hash(xmpData, imgid, NULL);
4104 }
4105
4106 sqlite3_finalize(stmt);
4107 dt_free(iop_order_list);
4108}
4109
4110#if EXIV2_TEST_VERSION(0,27,0)
4111#define ERROR_CODE(a) (static_cast<Exiv2::ErrorCode>((a)))
4112#else
4113#define ERROR_CODE(a) (a)
4114#endif
4115
4116char *dt_exif_xmp_read_string(const int32_t imgid)
4117{
4118 try
4119 {
4120 char input_filename[PATH_MAX] = { 0 };
4121 gboolean from_cache = FALSE;
4122 dt_image_full_path(imgid, input_filename, sizeof(input_filename), &from_cache, __FUNCTION__);
4123
4124 // first take over the data from the source image
4125 Exiv2::XmpData xmpData;
4126 if(g_file_test(input_filename, G_FILE_TEST_EXISTS))
4127 {
4128 std::string xmpPacket;
4129
4130 Exiv2::DataBuf buf = Exiv2::readFile(WIDEN(input_filename));
4131#if EXIV2_TEST_VERSION(0,28,0)
4132 xmpPacket.assign(buf.c_str(), buf.size());
4133#else
4134 xmpPacket.assign(reinterpret_cast<char *>(buf.pData_), buf.size_);
4135#endif
4136 Exiv2::XmpParser::decode(xmpData, xmpPacket);
4137 // because XmpSeq or XmpBag are added to the list, we first have
4138 // to remove these so that we don't end up with a string of duplicates
4139 dt_remove_known_keys(xmpData);
4140 }
4141
4142 // now add whatever we have in the sidecar XMP. this overwrites stuff from the source image
4143 dt_image_path_append_version(imgid, input_filename, sizeof(input_filename));
4144 g_strlcat(input_filename, ".xmp", sizeof(input_filename));
4145 if(g_file_test(input_filename, G_FILE_TEST_EXISTS))
4146 {
4147 Exiv2::XmpData sidecarXmpData;
4148 std::string xmpPacket;
4149
4150 Exiv2::DataBuf buf = Exiv2::readFile(WIDEN(input_filename));
4151#if EXIV2_TEST_VERSION(0,28,0)
4152 xmpPacket.assign(buf.c_str(), buf.size());
4153#else
4154 xmpPacket.assign(reinterpret_cast<char *>(buf.pData_), buf.size_);
4155#endif
4156 Exiv2::XmpParser::decode(sidecarXmpData, xmpPacket);
4157
4158 for(Exiv2::XmpData::const_iterator it = sidecarXmpData.begin(); it != sidecarXmpData.end(); ++it)
4159 xmpData.add(*it);
4160 }
4161
4162 dt_remove_known_keys(xmpData); // is this needed?
4163
4164 // last but not least attach what we have in DB to the XMP. in theory that should be
4165 // the same as what we just copied over from the sidecar file, but you never know ...
4166 _exif_xmp_read_data(xmpData, imgid, NULL);
4167
4168 // serialize the xmp data and output the xmp packet
4169 std::string xmpPacket;
4170 if(Exiv2::XmpParser::encode(xmpPacket, xmpData,
4171 Exiv2::XmpParser::useCompactFormat | Exiv2::XmpParser::omitPacketWrapper) != 0)
4172 {
4173 throw Exiv2::Error(ERROR_CODE(1), "[xmp_write] failed to serialize xmp data");
4174 }
4175 return g_strdup(xmpPacket.c_str());
4176 }
4177 catch(Exiv2::AnyError &e)
4178 {
4179 std::cerr << "[xmp_read_blob] caught exiv2 exception '" << e << "'\n";
4180 return NULL;
4181 }
4182}
4183
4184static void dt_remove_xmp_key(Exiv2::XmpData &xmp, const char *key)
4185{
4186 try
4187 {
4188 Exiv2::XmpData::iterator pos = xmp.findKey(Exiv2::XmpKey(key));
4189 if (pos != xmp.end())
4190 xmp.erase(pos);
4191 }
4192 catch(Exiv2::AnyError &e)
4193 {
4194 }
4195}
4196
4197static void _remove_xmp_keys(Exiv2::XmpData &xmpData, const char *key)
4198{
4199 try
4200 {
4201 const std::string needle = key;
4202 for(Exiv2::XmpData::iterator i = xmpData.begin(); i != xmpData.end();)
4203 {
4204 if(i->key().compare(0, needle.length(), needle) == 0)
4205 i = xmpData.erase(i);
4206 else
4207 ++i;
4208 }
4209 }
4210 catch(Exiv2::AnyError &e)
4211 {
4212 }
4213}
4214
4215static void dt_remove_exif_key(Exiv2::ExifData &exif, const char *key)
4216{
4217 try
4218 {
4219 Exiv2::ExifData::iterator pos = exif.findKey(Exiv2::ExifKey(key));
4220 if (pos != exif.end())
4221 exif.erase(pos);
4222 }
4223 catch(Exiv2::AnyError &e)
4224 {
4225 }
4226}
4227
4228static void dt_remove_iptc_key(Exiv2::IptcData &iptc, const char *key)
4229{
4230 try
4231 {
4232 Exiv2::IptcData::iterator pos;
4233 while((pos = iptc.findKey(Exiv2::IptcKey(key))) != iptc.end())
4234 iptc.erase(pos);
4235 }
4236 catch(Exiv2::AnyError &e)
4237 {
4238 }
4239}
4240
4241int dt_exif_xmp_attach_export(const int32_t imgid, const char *filename, void *metadata)
4242{
4244 try
4245 {
4246 char input_filename[PATH_MAX] = { 0 };
4247 gboolean from_cache = TRUE;
4248 dt_image_full_path(imgid, input_filename, sizeof(input_filename), &from_cache, __FUNCTION__);
4249
4250 std::unique_ptr<Exiv2::Image> img(Exiv2::ImageFactory::open(WIDEN(filename)));
4251 // unfortunately it seems we have to read the metadata, to not erase the exif (which we just wrote).
4252 // will make export slightly slower, oh well.
4253 // img->clearXmpPacket();
4255
4256 try
4257 {
4258 // initialize XMP and IPTC data with the one from the original file
4259 std::unique_ptr<Exiv2::Image> input_image(Exiv2::ImageFactory::open(WIDEN(input_filename)));
4260 if(input_image.get() != 0)
4261 {
4262 read_metadata_threadsafe(input_image);
4263 img->setIptcData(input_image->iptcData());
4264 img->setXmpData(input_image->xmpData());
4265 }
4266 }
4267 catch(Exiv2::AnyError &e)
4268 {
4269 std::cerr << "[xmp_attach] " << input_filename << ": caught exiv2 exception '" << e << "'\n";
4270 }
4271
4272 Exiv2::XmpData &xmpData = img->xmpData();
4273
4274 // now add whatever we have in the sidecar XMP. this overwrites stuff from the source image
4275 dt_image_path_append_version(imgid, input_filename, sizeof(input_filename));
4276 g_strlcat(input_filename, ".xmp", sizeof(input_filename));
4277 if(g_file_test(input_filename, G_FILE_TEST_EXISTS))
4278 {
4279 Exiv2::XmpData sidecarXmpData;
4280 std::string xmpPacket;
4281
4282 Exiv2::DataBuf buf = Exiv2::readFile(WIDEN(input_filename));
4283#if EXIV2_TEST_VERSION(0,28,0)
4284 xmpPacket.assign(buf.c_str(), buf.size());
4285#else
4286 xmpPacket.assign(reinterpret_cast<char *>(buf.pData_), buf.size_);
4287#endif
4288 Exiv2::XmpParser::decode(sidecarXmpData, xmpPacket);
4289
4290 for(Exiv2::XmpData::const_iterator it = sidecarXmpData.begin(); it != sidecarXmpData.end(); ++it)
4291 xmpData.add(*it);
4292 }
4293
4294 dt_remove_known_keys(xmpData); // is this needed?
4295
4296 {
4297 // We also want to make sure to not have some tags that might
4298 // have come in from XMP files created by digikam or similar
4299 static const char *keys[] = {
4300 "Xmp.tiff.Orientation"
4301 };
4302 static const guint n_keys = G_N_ELEMENTS(keys);
4303 dt_remove_xmp_keys(xmpData, keys, n_keys);
4304 }
4305
4306 // last but not least attach what we have in DB to the XMP. in theory that should be
4307 // the same as what we just copied over from the sidecar file, but you never know ...
4308 // make sure to remove all geotags if necessary
4309 if(m)
4310 {
4311 Exiv2::ExifData exifOldData;
4312 Exiv2::ExifData &exifData = img->exifData();
4313 if(!(m->flags & DT_META_EXIF))
4314 {
4315 for(Exiv2::ExifData::const_iterator i = exifData.begin(); i != exifData.end() ; ++i)
4316 {
4317 exifOldData[i->key()] = i->value();
4318 }
4319 img->clearExifData();
4320 }
4321
4322 _exif_xmp_read_data_export(xmpData, imgid, m);
4323
4324 Exiv2::IptcData &iptcData = img->iptcData();
4325
4326 if(!(m->flags & DT_META_GEOTAG))
4327 dt_remove_exif_geotag(exifData);
4328 // calculated metadata
4329 dt_variables_params_t *params;
4330 dt_variables_params_init(&params);
4331 params->filename = input_filename;
4332 params->jobcode = "infos";
4333 params->sequence = 0;
4334 params->imgid = imgid;
4335
4336 dt_variables_set_tags_flags(params, m->flags);
4337 for (GList *tags = m->list; tags; tags = g_list_next(tags))
4338 {
4339 gchar *tagname = (gchar *)tags->data;
4340 tags = g_list_next(tags);
4341 if (IS_NULL_PTR(tags)) break;
4342 gchar *formula = (gchar *)tags->data;
4343 if (formula[0])
4344 {
4345 if(!(m->flags & DT_META_EXIF) && (formula[0] == '=') && g_str_has_prefix(tagname, "Exif."))
4346 {
4347 // remove this specific exif
4348 Exiv2::ExifData::const_iterator pos;
4349 if(_exif_read_exif_tag(exifOldData, &pos, tagname))
4350 {
4351 exifData[tagname] = pos->value();
4352 }
4353 }
4354 else
4355 {
4356 gchar *result = dt_variables_expand(params, formula, FALSE);
4357 if(result && result[0])
4358 {
4359 if(g_str_has_prefix(tagname, "Xmp."))
4360 {
4361 const char *type = _exif_get_exiv2_tag_type(tagname);
4362 // if xmpBag or xmpSeq, split the list when necessary
4363 // else provide the string as is (can be a list of strings)
4364 if(!g_strcmp0(type, "XmpBag") || !g_strcmp0(type, "XmpSeq"))
4365 {
4366 char *tuple = g_strrstr(result, ",");
4367 while(tuple)
4368 {
4369 tuple[0] = '\0';
4370 tuple++;
4371 xmpData[tagname] = tuple;
4372 tuple = g_strrstr(result, ",");
4373 }
4374 }
4375 xmpData[tagname] = result;
4376 }
4377 else if(g_str_has_prefix(tagname, "Iptc."))
4378 {
4379 const char *type = _exif_get_exiv2_tag_type(tagname);
4380 if(!g_strcmp0(type, "String-R"))
4381 {
4382 // clean up the original tags before giving new values
4383 dt_remove_iptc_key(iptcData, tagname);
4384 // convert the input list (separator ", ") into different tags
4385 // FIXME if an element of the list contains a ", " it is not correctly exported
4386 Exiv2::IptcKey key(tagname);
4387 Exiv2::Iptcdatum id(key);
4388 gchar **values = g_strsplit(result, ", ", 0);
4389 if(values)
4390 {
4391 gchar **entry = values;
4392 while (*entry)
4393 {
4394 char *e = g_strstrip(*entry);
4395 if(*e)
4396 {
4397 id.setValue(e);
4398 iptcData.add(id);
4399 }
4400 entry++;
4401 }
4402 }
4403 g_strfreev(values);
4404 }
4405 else iptcData[tagname] = result;
4406 }
4407 else if(g_str_has_prefix(tagname, "Exif."))
4408 {
4409 const char *type = _exif_get_exiv2_tag_type(tagname);
4410 if((!g_strcmp0(type, "Rational") || !g_strcmp0(type, "SRational")) &&
4411 (g_strstr_len(result, strlen(result), "/") == NULL))
4412 {
4413 float float_value = (float)std::atof(result);
4414 if(!isnan(float_value))
4415 {
4416 dt_free(result);
4417 int int_value = (int)float_value;
4418 int divisor = 1;
4419 while(fabs(float_value - int_value) > 0.000001)
4420 {
4421 divisor *= 10;
4422 float_value *= 10.0;
4423 int_value = (int)float_value;
4424 }
4425 result = g_strdup_printf("%d/%d", (int)float_value, divisor);
4426 }
4427 }
4428 exifData[tagname] = result;
4429 }
4430 }
4431 dt_free(result);
4432 }
4433 }
4434 else
4435 {
4436 if (g_str_has_prefix(tagname, "Xmp."))
4437 dt_remove_xmp_key(xmpData, tagname);
4438 else if (g_str_has_prefix(tagname, "Exif."))
4439 dt_remove_exif_key(exifData, tagname);
4440 else if (g_str_has_prefix(tagname, "Iptc."))
4441 dt_remove_iptc_key(iptcData, tagname);
4442 }
4443 }
4445 }
4446
4447 try
4448 {
4449 img->writeMetadata();
4450 }
4451 catch(Exiv2::AnyError &e)
4452 {
4453#if EXIV2_TEST_VERSION(0,27,0)
4454 if(e.code() == Exiv2::ErrorCode::kerTooLargeJpegSegment)
4455#else
4456 if(e.code() == 37)
4457#endif
4458 {
4459 _remove_xmp_keys(xmpData, "Xmp.darktable.history");
4460 _remove_xmp_keys(xmpData, "Xmp.darktable.masks_history");
4461 _remove_xmp_keys(xmpData, "Xmp.darktable.auto_presets_applied");
4462 _remove_xmp_keys(xmpData, "Xmp.darktable.iop_order");
4463 try
4464 {
4465 img->writeMetadata();
4466 }
4467 catch(Exiv2::AnyError &e2)
4468 {
4469 std::cerr << "[dt_exif_xmp_attach_export] without history " << filename << ": caught exiv2 exception '" << e2 << "'\n";
4470 return -1;
4471 }
4472 }
4473 else
4474 throw;
4475 }
4476 return 0;
4477 }
4478 catch(Exiv2::AnyError &e)
4479 {
4480 std::cerr << "[dt_exif_xmp_attach_export] " << filename << ": caught exiv2 exception '" << e << "'\n";
4481 return -1;
4482 }
4483}
4484
4485// write xmp sidecar file:
4486int dt_exif_xmp_write_with_imgpath(const dt_image_t *image, const char *filename,
4487 const char *imgpath)
4488{
4489 // refuse to write sidecar for non-existent image:
4490 if(IS_NULL_PTR(image) || image->id <= 0) return 1;
4491 if(IS_NULL_PTR(imgpath) || !*imgpath) return 1;
4492 if(!g_file_test(imgpath, G_FILE_TEST_IS_REGULAR)) return 1;
4493 const int32_t imgid = image->id;
4494
4495 try
4496 {
4497 Exiv2::XmpData xmpData;
4498 std::string xmpPacket;
4499 char *checksum_old = NULL;
4500 if(g_file_test(filename, G_FILE_TEST_EXISTS))
4501 {
4502 // we want to avoid writing the sidecar file if it didn't change to avoid issues when using the same images
4503 // from different computers. sample use case: images on NAS, several computers using them NOT AT THE SAME TIME and
4504 // the xmp crawler is used to find changed sidecars.
4505 errno = 0;
4506 size_t end;
4507 unsigned char *content = (unsigned char*)dt_read_file(filename, &end);
4508 if(content)
4509 {
4510 if(end > 1000000)
4511 {
4512 dt_control_log(_("The XMP file \n'%s'\n weighs %.2f MB. Writing it will take some time."), filename, (float)end / 1000000);
4513 fprintf(stdout, "The XMP file '%s' weighs %.2f MB. Writing it will take some time.\n", filename, (float)end / 1000000);
4514 }
4515
4516 checksum_old = g_compute_checksum_for_data(G_CHECKSUM_MD5, content, end);
4517 dt_free(content);
4518 }
4519 else
4520 {
4521 fprintf(stderr, "cannot read xmp file '%s': '%s'\n", filename, strerror(errno));
4522 dt_control_log(_("cannot read xmp file '%s': '%s'"), filename, strerror(errno));
4523 }
4524
4525 Exiv2::DataBuf buf = Exiv2::readFile(WIDEN(filename));
4526#if EXIV2_TEST_VERSION(0,28,0)
4527 xmpPacket.assign(buf.c_str(), buf.size());
4528#else
4529 xmpPacket.assign(reinterpret_cast<char *>(buf.pData_), buf.size_);
4530#endif
4531 Exiv2::XmpParser::decode(xmpData, xmpPacket);
4532 // because XmpSeq or XmpBag are added to the list, we first have
4533 // to remove these so that we don't end up with a string of duplicates
4534 dt_remove_known_keys(xmpData);
4535 }
4536
4537 // initialize xmp data:
4538 _exif_xmp_read_data(xmpData, imgid, image);
4539
4540 // serialize the xmp data and output the xmp packet
4541 if(Exiv2::XmpParser::encode(xmpPacket, xmpData,
4542 Exiv2::XmpParser::useCompactFormat | Exiv2::XmpParser::omitPacketWrapper) != 0)
4543 {
4544 throw Exiv2::Error(ERROR_CODE(1), "[xmp_write] failed to serialize xmp data");
4545 }
4546
4547 // hash the new data and compare it to the old hash (if applicable)
4548 const char *xml_header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
4549 gboolean write_sidecar = TRUE;
4550 if(checksum_old)
4551 {
4552 GChecksum *checksum = g_checksum_new(G_CHECKSUM_MD5);
4553 if(checksum)
4554 {
4555 g_checksum_update(checksum, (unsigned char*)xml_header, -1);
4556 g_checksum_update(checksum, (unsigned char*)xmpPacket.c_str(), -1);
4557 const char *checksum_new = g_checksum_get_string(checksum);
4558 write_sidecar = g_strcmp0(checksum_old, checksum_new) != 0;
4559 g_checksum_free(checksum);
4560 }
4561 dt_free(checksum_old);
4562 }
4563
4564 if(write_sidecar)
4565 {
4566 // using std::ofstream isn't possible here -- on Windows it doesn't support Unicode filenames with mingw
4567 errno = 0;
4568 FILE *fout = g_fopen(filename, "wb");
4569 if(fout)
4570 {
4571 fprintf(fout, "%s", xml_header);
4572 fprintf(fout, "%s", xmpPacket.c_str());
4573 fclose(fout);
4574 }
4575 else
4576 {
4577 fprintf(stderr, "cannot write xmp file '%s': '%s'\n", filename, strerror(errno));
4578 dt_control_log(_("cannot write xmp file '%s': '%s'"), filename, strerror(errno));
4579 return -1;
4580 }
4581 }
4582
4583 return 0;
4584 }
4585 catch(Exiv2::AnyError &e)
4586 {
4587 std::cerr << "[dt_exif_xmp_write] " << filename << ": caught exiv2 exception '" << e << "'\n";
4588 return -1;
4589 }
4590}
4591
4593{
4594 try
4595 {
4596 Exiv2::ExifData::const_iterator pos;
4597 Exiv2::ExifData exifData;
4598 Exiv2::ExifParser::decode(exifData, data, size);
4599 // clang-format off
4600 // 0x01 -> sRGB
4601 // 0x02 -> AdobeRGB
4602 // 0xffff -> Uncalibrated
4603 // + Exif.Iop.InteroperabilityIndex of 'R03' -> AdobeRGB
4604 // + Exif.Iop.InteroperabilityIndex of 'R98' -> sRGB
4605 // clang-format on
4606 if((pos = exifData.findKey(Exiv2::ExifKey("Exif.Photo.ColorSpace"))) != exifData.end() && pos->size())
4607 {
4608 int colorspace = pos->toLong();
4609 if(colorspace == 0x01)
4610 return DT_COLORSPACE_SRGB;
4611 else if(colorspace == 0x02)
4613 else if(colorspace == 0xffff)
4614 {
4615 if((pos = exifData.findKey(Exiv2::ExifKey("Exif.Iop.InteroperabilityIndex"))) != exifData.end()
4616 && pos->size())
4617 {
4618 std::string interop_index = pos->toString();
4619 if(interop_index == "R03")
4621 else if(interop_index == "R98")
4622 return DT_COLORSPACE_SRGB;
4623 }
4624 }
4625 }
4626
4627 return DT_COLORSPACE_DISPLAY; // nothing embedded
4628 }
4629 catch(Exiv2::AnyError &e)
4630 {
4631 std::string s(e.what());
4632 std::cerr << "[exiv2 dt_exif_get_color_space] " << s << std::endl;
4633 return DT_COLORSPACE_DISPLAY;
4634 }
4635}
4636
4637void dt_exif_get_datetime_taken(const uint8_t *data, size_t size, char *datetime_taken)
4638{
4639 try
4640 {
4641 Exiv2::ExifData::const_iterator pos;
4642 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(data, size));
4644 Exiv2::ExifData &exifData = image->exifData();
4645
4646 _find_datetime_taken(exifData, pos, datetime_taken);
4647 }
4648 catch(Exiv2::AnyError &e)
4649 {
4650 std::string s(e.what());
4651 std::cerr << "[exiv2 dt_exif_get_datetime_taken] " << s << std::endl;
4652 }
4653}
4654
4655static void dt_exif_log_handler(int log_level, const char *message)
4656{
4657 if(log_level >= Exiv2::LogMsg::level())
4658 {
4659 // We don't seem to need \n in the format string as exiv2 includes it
4660 // in the messages themselves
4661 dt_print(DT_DEBUG_CAMERA_SUPPORT, "[exiv2] %s", message);
4662 }
4663}
4664
4666{
4667 // preface the exiv2 messages with "[exiv2] "
4668 Exiv2::LogMsg::setHandler(&dt_exif_log_handler);
4669
4670 // enable isobmff support if exiv2 was built with it
4671 // the enableBMFF function is deprecated from exiv2 0.28.0
4672 #if !EXIV2_TEST_VERSION(0,28,0)
4673 #ifdef HAVE_LIBEXIV2_WITH_ISOBMFF
4674 Exiv2::enableBMFF();
4675 #endif
4676 #endif
4677
4678 // XmpParser init/term are required on older exiv2, but are deprecated no-ops from 0.28+.
4679 #if !EXIV2_TEST_VERSION(0,28,0)
4680 Exiv2::XmpParser::initialize();
4681 #endif
4682 // this has to stay with the old url (namespace already propagated outside dt)
4683 Exiv2::XmpProperties::registerNs("http://darktable.sf.net/", "darktable");
4684 // check is Exiv2 version already knows these prefixes
4685 try
4686 {
4687 Exiv2::XmpProperties::propertyList("lr");
4688 }
4689 catch(Exiv2::AnyError &e)
4690 {
4691 // if lightroom is not known register it
4692 Exiv2::XmpProperties::registerNs("http://ns.adobe.com/lightroom/1.0/", "lr");
4693 }
4694 try
4695 {
4696 Exiv2::XmpProperties::propertyList("exifEX");
4697 }
4698 catch(Exiv2::AnyError &e)
4699 {
4700 // if exifEX is not known register it
4701 Exiv2::XmpProperties::registerNs("http://cipa.jp/exif/1.0/", "exifEX");
4702 }
4703}
4704
4706{
4707 // Keep explicit termination for older exiv2; deprecated no-op in 0.28+.
4708 #if !EXIV2_TEST_VERSION(0,28,0)
4709 Exiv2::XmpParser::terminate();
4710 #endif
4711}
4712
4713// clang-format off
4714// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
4715// vim: shiftwidth=2 expandtab tabstop=2 cindent
4716// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
4717// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
#define m
Definition basecurve.c:278
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
Definition exif.cc:383
~Lock()
Definition exif.cc:386
Lock()
Definition exif.cc:385
void dt_colorlabels_remove_labels(const int32_t imgid)
void dt_colorlabels_set_label(const int32_t imgid, const int color)
dt_colorspaces_color_profile_type_t
Definition colorspaces.h:81
@ DT_COLORSPACE_ADOBERGB
Definition colorspaces.h:85
@ DT_COLORSPACE_DISPLAY
Definition colorspaces.h:91
@ DT_COLORSPACE_SRGB
Definition colorspaces.h:84
static dt_aligned_pixel_t sRGB
const dt_colormatrix_t dt_aligned_pixel_t out
gboolean dt_history_set_end(const int32_t imgid, const int32_t history_end)
gboolean dt_history_db_write_history_item(const int32_t imgid, const int num, const char *operation, const void *op_params, const int op_params_size, const int module_version, const gboolean enabled, const void *blendop_params, const int blendop_params_size, const int blendop_version, const int multi_priority, const char *multi_name)
gboolean dt_history_db_shift_history_nums(const int32_t imgid, const int delta)
int32_t dt_history_db_get_next_history_num(const int32_t imgid)
gboolean dt_history_db_delete_masks_history(const int32_t imgid)
gboolean dt_history_db_delete_history(const int32_t imgid)
gboolean dt_image_is_raw(const dt_image_t *img)
void dt_image_path_append_version(const int32_t imgid, char *pathname, size_t pathname_len)
void dt_image_refresh_makermodel(dt_image_t *img)
int dt_image_get_xmp_rating_from_flags(const int flags)
gboolean dt_image_get_xmp_mode()
void dt_image_set_xmp_rating(dt_image_t *img, const int rating)
void dt_image_full_path(const int32_t imgid, char *pathname, size_t pathname_len, gboolean *from_cache, const char *calling_func)
Get the full path of an image out of the database.
void dt_metadata_clear(const GList *imgs, const gboolean undo_on)
char * key
const char * dt_metadata_get_key(const uint32_t keyid)
const char * dt_metadata_get_name(const uint32_t keyid)
int type
GList * dt_metadata_get(const int id, const char *key, uint32_t *count)
void dt_metadata_set_import(const int32_t imgid, const char *key, const char *value)
int dt_metadata_get_type(const uint32_t keyid)
char * name
const char darktable_package_string[]
int dt_conf_get_bool(const char *name)
gchar * dt_conf_get_string(const char *name)
int dt_conf_get_int(const char *name)
void dt_control_log(const char *msg,...)
Definition control.c:761
void dt_vprint(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1567
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
@ DT_DEBUG_LIGHTTABLE
Definition darktable.h:725
@ DT_DEBUG_CAMERA_SUPPORT
Definition darktable.h:731
@ DT_DEBUG_IMAGEIO
Definition darktable.h:733
float dt_boundingbox_t[4]
Definition darktable.h:709
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:463
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Enable aggressive floating-point arithmetic optimizations, in denormals handling. Set through user pr...
Definition darktable.h:524
static const dt_aligned_pixel_simd_t sign
Definition darktable.h:551
#define dt_free(ptr)
Definition darktable.h:456
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
#define PATH_MAX
Definition darktable.h:1062
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
sqlite3 * dt_database_get(const dt_database_t *db)
Definition database.c:3646
void dt_database_rollback_transaction(const struct dt_database_t *db)
Definition database.c:4711
#define dt_database_start_transaction(db)
Definition database.h:77
#define dt_database_release_transaction(db)
Definition database.h:78
gboolean dt_datetime_img_to_exif(char *exif, const size_t exif_size, const dt_image_t *img)
Definition datetime.c:234
void dt_datetime_now_to_exif(char *exif)
Definition datetime.c:204
void dt_datetime_add_subsec_to_exif(char *exif, const size_t exif_size, const char *subsec)
Definition datetime.c:374
gboolean dt_datetime_unix_to_img(dt_image_t *img, const time_t *unix)
Definition datetime.c:178
gboolean dt_datetime_gtimespan_to_exif(char *sdt, const size_t sdt_size, const GTimeSpan gts)
Definition datetime.c:384
GTimeSpan dt_datetime_gdatetime_to_gtimespan(GDateTime *gdt)
Definition datetime.c:438
void dt_datetime_exif_to_img(dt_image_t *img, const char *exif)
Definition datetime.c:222
#define DT_DATETIME_LENGTH
Definition datetime.h:37
#define DT_DATETIME_EXIF_LENGTH
Definition datetime.h:38
#define DT_DEBUG_SQLITE3_BIND_BLOB(a, b, c, d, e)
Definition debug.h:119
#define DT_DEBUG_SQLITE3_PREPARE_V2(a, b, c, d, e)
Definition debug.h:107
#define DT_DEBUG_SQLITE3_BIND_TEXT(a, b, c, d, e)
Definition debug.h:118
#define DT_DEBUG_SQLITE3_BIND_INT(a, b, c)
Definition debug.h:115
int dt_deprecated(const char *op)
Modules without a proper IOP order should throw errors and log, except if they are deprecated definit...
void dt_dng_opcode_process_opcode_list_2(uint8_t *buf, uint32_t buf_size, dt_image_t *img)
Definition dng_opcode.c:58
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:374
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:364
static const char * _exif_get_exiv2_tag_type(const char *tagname)
Definition exif.cc:363
unsigned char * dt_exif_xmp_decode(const char *input, const int len, int *output_len)
Definition exif.cc:2337
int dt_exif_xmp_attach_export(const int32_t imgid, const char *filename, void *metadata)
Definition exif.cc:4241
static void dt_remove_xmp_key(Exiv2::XmpData &xmp, const char *key)
Definition exif.cc:4184
dt_colorspaces_color_profile_type_t dt_exif_get_color_space(const uint8_t *data, size_t size)
Definition exif.cc:4592
int dt_exif_read_from_blob(dt_image_t *img, uint8_t *blob, const int size)
Definition exif.cc:1682
static void dt_remove_known_keys(Exiv2::XmpData &xmp)
Definition exif.cc:440
static void free_history_entry(gpointer data)
Definition exif.cc:2543
void dt_exif_get_datetime_taken(const uint8_t *data, size_t size, char *datetime_taken)
Definition exif.cc:4637
#define FIND_IPTC_TAG(key)
Definition exif.cc:685
#define FIND_XMP_TAG(key)
Definition exif.cc:513
static void read_xmp_timestamps(Exiv2::XmpData &xmpData, dt_image_t *img, const int xmp_version)
Definition exif.cc:3684
static void dt_set_xmp_exif_geotag(Exiv2::XmpData &xmpData, double longitude, double latitude, double altitude)
Definition exif.cc:3726
static void dt_set_xmp_dt_history(Exiv2::XmpData &xmpData, const int32_t imgid, int history_end)
Definition exif.cc:3498
static void dt_remove_xmp_keys(Exiv2::XmpData &xmp, const char *keys[], unsigned int n_keys)
Definition exif.cc:480
#define WIDEN(s)
Definition exif.cc:103
void dt_exif_set_exiv2_taglist()
Definition exif.cc:266
static GList * read_masks_v3(Exiv2::XmpData &xmpData, const char *filename, const int version)
Definition exif.cc:2909
void dt_exif_init()
Definition exif.cc:4665
static int _illu_to_temp(dt_dng_illuminant_t illu)
Definition exif.cc:223
int dt_exif_xmp_write_with_imgpath(const dt_image_t *image, const char *filename, const char *imgpath)
Definition exif.cc:4486
int dt_exif_read(dt_image_t *img, const char *path)
Definition exif.cc:1753
GTimeSpan _convert_unix_to_gtimespan(const time_t unix)
Definition exif.cc:3671
static void dt_exif_log_handler(int log_level, const char *message)
Definition exif.cc:4655
#define read_metadata_threadsafe(image)
Definition exif.cc:389
static void _get_xmp_tags(const char *prefix, GList **taglist)
Definition exif.cc:210
static GList * read_history_v1(const std::string &xmpPacket, const char *filename, const int superold)
Definition exif.cc:2556
static bool _check_usercrop(Exiv2::ExifData &exifData, dt_image_t *img)
Definition exif.cc:788
char * dt_exif_xmp_encode_internal(const unsigned char *input, const int len, int *output_len, gboolean do_compress)
Definition exif.cc:2272
static void print_history_entry(history_entry_t *entry) __attribute__((unused))
Definition exif.cc:2523
#define FIND_EXIF_TAG(key)
Definition exif.cc:782
int dt_exif_xmp_read(dt_image_t *img, const char *filename, const int history_only)
Definition exif.cc:3105
static bool dt_exif_read_xmp_tag(Exiv2::XmpData &xmpData, Exiv2::XmpData::iterator *pos, string key)
Definition exif.cc:500
static bool _exif_decode_exif_data(dt_image_t *img, Exiv2::ExifData &exifData)
Definition exif.cc:927
static const char * _get_exiv2_type(const int type)
Definition exif.cc:145
char * dt_exif_xmp_encode(const unsigned char *input, const int len, int *output_len)
Definition exif.cc:2246
static gboolean _check_dng_opcodes(Exiv2::ExifData &exifData, dt_image_t *img)
Definition exif.cc:814
static void dt_remove_xmp_exif_geotag(Exiv2::XmpData &xmpData)
Definition exif.cc:3712
int dt_exif_get_thumbnail(const char *path, uint8_t **buffer, size_t *size, char **mime_type, int *width, int *height, int min_width)
Definition exif.cc:1702
void dt_exif_img_check_additional_tags(dt_image_t *img, const char *filename)
Definition exif.cc:836
static void _find_exif_model(Exiv2::ExifData &exifData, Exiv2::ExifData::const_iterator pos, char *model, const size_t m_size)
Definition exif.cc:905
static void add_mask_entry_to_db(int32_t imgid, mask_entry_t *entry)
Definition exif.cc:3014
static void dt_strlcpy_to_utf8(char *dest, size_t dest_max, Exiv2::ExifData::const_iterator &pos, Exiv2::ExifData &exifData)
Definition exif.cc:421
static bool _exif_read_exif_tag(Exiv2::ExifData &exifData, Exiv2::ExifData::const_iterator *pos, string key)
Definition exif.cc:767
#define DT_XMP_EXIF_VERSION
Definition exif.cc:135
void dt_exif_cleanup()
Definition exif.cc:4705
static void _remove_xmp_keys(Exiv2::XmpData &xmpData, const char *key)
Definition exif.cc:4197
const char * dt_xmp_keys[]
Definition exif.cc:400
static void _find_exif_maker(Exiv2::ExifData &exifData, Exiv2::ExifData::const_iterator pos, char *maker, const size_t m_size)
Definition exif.cc:882
int dt_exif_read_blob(uint8_t **buf, const char *path, const int32_t imgid, const int sRGB, const int out_width, const int out_height, const int dng_mode)
Definition exif.cc:1890
static void dt_remove_exif_key(Exiv2::ExifData &exif, const char *key)
Definition exif.cc:4215
static bool dt_exif_read_iptc_tag(Exiv2::IptcData &iptcData, Exiv2::IptcData::const_iterator *pos, string key)
Definition exif.cc:672
static void dt_remove_exif_keys(Exiv2::ExifData &exif, const char *keys[], unsigned int n_keys)
Definition exif.cc:460
char * dt_exif_xmp_read_string(const int32_t imgid)
Definition exif.cc:4116
static void _exif_xmp_read_data_export(Exiv2::XmpData &xmpData, const int32_t imgid, dt_export_metadata_t *metadata)
Definition exif.cc:3966
static GList * exiv2_taglist
Definition exif.cc:143
static bool _exif_decode_xmp_data(dt_image_t *img, Exiv2::XmpData &xmpData, int version, bool exif_read)
Definition exif.cc:519
static void _find_datetime_taken(Exiv2::ExifData &exifData, Exiv2::ExifData::const_iterator pos, char *exif_datetime_taken)
Definition exif.cc:860
static void _exif_import_tags(dt_image_t *img, Exiv2::XmpData::iterator &pos)
Definition exif.cc:2424
int _get_max_multi_priority(GList *history, const char *operation)
Definition exif.cc:3089
static void _exif_xmp_append_history_hash(Exiv2::XmpData &xmpData, const int32_t imgid, const dt_image_t *image)
Definition exif.cc:3810
static void dt_remove_iptc_key(Exiv2::IptcData &iptc, const char *key)
Definition exif.cc:4228
static GList * read_history_v2(Exiv2::XmpData &xmpData, const char *filename)
Definition exif.cc:2690
static GHashTable * read_masks(Exiv2::XmpData &xmpData, const char *filename, const int version)
Definition exif.cc:2843
static void add_non_clone_mask_entries_to_db(gpointer key, gpointer value, gpointer user_data)
Definition exif.cc:3056
const GList * dt_exif_get_exiv2_taglist()
Definition exif.cc:356
int dt_exif_write_blob(uint8_t *blob, uint32_t size, const char *path, const int compressed)
Definition exif.cc:1816
#define COMPRESS_THRESHOLD
#define ERROR_CODE(a)
Definition exif.cc:4113
#define TO_BINARY(a)
static void _exif_xmp_read_data(Exiv2::XmpData &xmpData, const int32_t imgid, const dt_image_t *image)
Definition exif.cc:3834
static bool _exif_decode_iptc_data(dt_image_t *img, Exiv2::IptcData &iptcData)
Definition exif.cc:690
void free_mask_entry(gpointer data)
Definition exif.cc:2834
static const guint dt_xmp_keys_n
Definition exif.cc:417
static void set_xmp_timestamps(Exiv2::XmpData &xmpData, const int32_t imgid)
Definition exif.cc:3634
static void dt_set_xmp_dt_metadata(Exiv2::XmpData &xmpData, const int32_t imgid, const gboolean export_flag)
Definition exif.cc:3768
static void add_mask_entries_to_db(int32_t imgid, GHashTable *mask_entries, int mask_id)
Definition exif.cc:3063
static void dt_remove_exif_geotag(Exiv2::ExifData &exifData)
Definition exif.cc:1874
dt_dng_illuminant_t
Definition exif.h:46
@ DT_LS_D65
Definition exif.h:64
@ DT_LS_DayWhiteFluorescent
Definition exif.h:56
@ DT_LS_Fluorescent
Definition exif.h:49
@ DT_LS_Daylight
Definition exif.h:48
@ DT_LS_D75
Definition exif.h:65
@ DT_LS_CloudyWeather
Definition exif.h:53
@ DT_LS_D50
Definition exif.h:66
@ DT_LS_StandardLightB
Definition exif.h:61
@ DT_LS_StandardLightC
Definition exif.h:62
@ DT_LS_CoolWhiteFluorescent
Definition exif.h:57
@ DT_LS_Shade
Definition exif.h:54
@ DT_LS_Flash
Definition exif.h:51
@ DT_LS_Tungsten
Definition exif.h:50
@ DT_LS_Unknown
Definition exif.h:47
@ DT_LS_WarmWhiteFluorescent
Definition exif.h:59
@ DT_LS_StandardLightA
Definition exif.h:60
@ DT_LS_FineWeather
Definition exif.h:52
@ DT_LS_D55
Definition exif.h:63
@ DT_LS_DaylightFluorescent
Definition exif.h:55
@ DT_LS_ISOStudioTungsten
Definition exif.h:67
@ DT_LS_WhiteFluorescent
Definition exif.h:58
@ DT_IMAGE_COLORSPACE_ADOBE_RGB
Definition image.h:181
@ DT_IMAGE_COLORSPACE_SRGB
Definition image.h:180
static dt_image_orientation_t dt_image_orientation_to_flip_bits(const int orient)
Definition image.h:530
const char flag
Definition image.h:252
@ DT_IMAGE_NO_LEGACY_PRESETS
Definition image.h:119
@ DT_IMAGE_HAS_ADDITIONAL_DNG_TAGS
Definition image.h:132
@ DT_IMAGE_AUTO_PRESETS_APPLIED
Definition image.h:117
@ DT_IMAGE_S_RAW
Definition image.h:134
@ DT_IMAGE_RAW
Definition image.h:111
@ DT_IMAGE_MONOCHROME
Definition image.h:129
@ DT_IMAGE_HDR
Definition image.h:113
@ DT_IMAGE_LDR
Definition image.h:109
void dt_image_cache_read_release(dt_image_cache_t *cache, const dt_image_t *img)
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
dt_image_flags_t dt_imageio_get_type_from_extension(const char *extension)
Map Exiv2 preview MIME types to decoder format identifiers.
Definition imageio.c:180
const char * maker
const char * model
GList * dt_ioppr_get_iop_order_list(int32_t imgid, gboolean sorted)
Load the order list for an image from the DB.
Definition iop_order.c:1096
gboolean dt_ioppr_has_multiple_instances(GList *iop_order_list)
Detect whether multiple instances are grouped for a non-custom order.
Definition iop_order.c:945
GList * dt_ioppr_get_iop_order_list_version(dt_iop_order_t version)
Return the built-in order list for a given version.
Definition iop_order.c:1044
gint dt_sort_iop_list_by_order_f(gconstpointer a, gconstpointer b)
Compare two list nodes holding modules by iop_order.
Definition iop_order.c:893
gboolean dt_ioppr_write_iop_order_list(GList *iop_order_list, const int32_t imgid)
Persist an order list to the DB for a given image.
Definition iop_order.c:1013
char * dt_ioppr_serialize_text_iop_order_list(GList *iop_order_list)
Serialize an order list to a text representation.
Definition iop_order.c:2533
GList * dt_ioppr_deserialize_text_iop_order_list(const char *buf)
Deserialize an order list from a text representation.
Definition iop_order.c:2588
dt_iop_order_t dt_ioppr_get_iop_order_version(const int32_t imgid)
Fetch the IOP order version stored for an image.
Definition iop_order.c:761
GList * dt_ioppr_get_iop_order_link(GList *iop_order_list, const char *op_name, const int multi_priority)
Find a list link matching an operation and instance.
Definition iop_order.c:830
dt_iop_order_t
Definition iop_order.h:143
@ DT_IOP_ORDER_ANSEL_RAW
Definition iop_order.h:148
@ DT_IOP_ORDER_LEGACY
Definition iop_order.h:145
@ DT_IOP_ORDER_CUSTOM
Definition iop_order.h:144
const int t
const float v
float *const restrict const size_t k
@ DT_MASKS_NON_CLONE
Definition masks.h:138
@ DT_MASKS_CLONE
Definition masks.h:134
@ DT_MASKS_GROUP
Definition masks.h:133
static void mat3mul(float *const __restrict__ dest, const float *const __restrict__ m1, const float *const __restrict__ m2)
Definition math.h:161
@ DT_METADATA_FLAG_HIDDEN
Definition metadata.h:74
@ DT_METADATA_FLAG_PRIVATE
Definition metadata.h:75
@ DT_METADATA_NUMBER
Definition metadata.h:52
@ DT_METADATA_TYPE_INTERNAL
Definition metadata.h:60
@ DT_META_HIERARCHICAL_TAG
@ DT_META_TAG
@ DT_META_EXIF
@ DT_META_METADATA
@ DT_META_DT_HISTORY
@ DT_META_GEOTAG
size_t size
Definition mipmap_cache.c:3
const float factor
Definition pdf.h:90
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:347
@ DT_SIGNAL_TAG_CHANGED
This signal is raised when a tag is added/deleted/changed
Definition signal.h:130
char * dt_variables_expand(dt_variables_params_t *params, gchar *source, gboolean iterate)
void dt_variables_params_destroy(dt_variables_params_t *params)
void dt_variables_params_init(dt_variables_params_t **params)
void dt_variables_set_tags_flags(dt_variables_params_t *params, uint32_t flags)
unsigned __int64 uint64_t
Definition strptime.c:75
dt_pthread_mutex_t exiv2_threadsafe
Definition darktable.h:800
const struct dt_database_t * db
Definition darktable.h:779
struct dt_control_signal_t * signals
Definition darktable.h:774
int32_t unmuted
Definition darktable.h:760
struct dt_image_cache_t * image_cache
Definition darktable.h:777
double latitude
Definition image.h:275
double elevation
Definition image.h:275
double longitude
Definition image.h:275
float exif_exposure
Definition image.h:285
int32_t height
Definition image.h:315
GTimeSpan export_timestamp
Definition image.h:333
uint64_t history_hash
Definition image.h:322
float exif_focus_distance
Definition image.h:290
dt_boundingbox_t usercrop
Definition image.h:365
float exif_exposure_bias
Definition image.h:286
float exif_iso
Definition image.h:288
int32_t exif_inited
Definition image.h:283
float exif_aperture
Definition image.h:287
dt_image_geoloc_t geoloc
Definition image.h:347
int32_t flags
Definition image.h:319
dt_image_orientation_t orientation
Definition image.h:284
int32_t width
Definition image.h:315
float exif_focal_length
Definition image.h:289
char exif_maker[64]
Definition image.h:292
GTimeSpan change_timestamp
Definition image.h:333
char exif_lens[128]
Definition image.h:294
GTimeSpan print_timestamp
Definition image.h:333
float d65_color_matrix[9]
Definition image.h:339
char exif_model[64]
Definition image.h:293
dt_image_colorspace_t colorspace
Definition image.h:342
dt_image_raw_parameters_t legacy_flip
Definition image.h:344
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:304
int32_t id
Definition image.h:319
float exif_crop
Definition image.h:291
Definition iop_order.h:154
char operation[20]
Definition iop_order.h:160
union dt_iop_order_entry_t::@8 o
double iop_order_f
Definition iop_order.h:156
int32_t instance
Definition iop_order.h:161
Definition exif.cc:2486
unsigned char * blendop_params
Definition exif.cc:2496
int blendop_params_len
Definition exif.cc:2497
int blendop_version
Definition exif.cc:2495
int modversion
Definition exif.cc:2489
double iop_order
Definition exif.cc:2499
int multi_priority
Definition exif.cc:2494
gboolean have_operation
Definition exif.cc:2502
gboolean enabled
Definition exif.cc:2488
char * multi_name
Definition exif.cc:2492
int num
Definition exif.cc:2498
gboolean have_params
Definition exif.cc:2502
gboolean have_modversion
Definition exif.cc:2502
unsigned char * params
Definition exif.cc:2490
int params_len
Definition exif.cc:2491
char * operation
Definition exif.cc:2487
Definition exif.cc:2507
int mask_type
Definition exif.cc:2509
int mask_id
Definition exif.cc:2508
int mask_nb
Definition exif.cc:2514
int mask_version
Definition exif.cc:2511
int mask_num
Definition exif.cc:2518
unsigned char * mask_points
Definition exif.cc:2512
char * mask_name
Definition exif.cc:2510
int version
Definition exif.cc:2519
int mask_src_len
Definition exif.cc:2516
int mask_points_len
Definition exif.cc:2513
gboolean already_added
Definition exif.cc:2517
unsigned char * mask_src
Definition exif.cc:2515
GList * dt_tag_get_list_export(int32_t imgid, int32_t flags)
Definition tags.c:963
gboolean dt_tag_attach(const guint tagid, const int32_t imgid, const gboolean undo_on, const gboolean group_on)
Definition tags.c:485
gboolean dt_tag_set_tags(const GList *tags, const GList *img, const gboolean ignore_dt_tags, const gboolean clear_on, const gboolean undo_on)
Definition tags.c:506
gboolean dt_tag_new(const char *name, guint *tagid)
Definition tags.c:179
GList * dt_tag_get_list(int32_t imgid)
Definition tags.c:850
GList * dt_tag_get_hierarchical_export(int32_t imgid, int32_t flags)
Definition tags.c:1043
GList * dt_tag_get_hierarchical(int32_t imgid)
Definition tags.c:894
typedef double((*spd)(unsigned long int wavelength, double TempK))
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
static const int mask_id
Definition useless.c:210
static const char * mask_name
Definition useless.c:211
gboolean dt_util_gps_elevation_to_number(const double r_1, const double r_2, char sign, double *result)
Definition utility.c:662
char * dt_read_file(const char *const filename, size_t *filesize)
Definition utility.c:893
double dt_util_gps_string_to_number(const gchar *input)
Definition utility.c:606
gboolean dt_util_gps_rationale_to_number(const double r0_1, const double r0_2, const double r1_1, const double r1_2, const double r2_1, const double r2_2, char sign, double *result)
Definition utility.c:624
gchar * dt_util_foo_to_utf8(const char *string)
Definition utility.c:392
gchar * dt_util_dstrcat(gchar *str, const gchar *format,...)
Definition utility.c:95