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