73#define __STDC_FORMAT_MACROS
97#include <exiv2/exiv2.hpp>
99#if defined(_WIN32) && defined(EXV_UNICODE_PATH)
100 #define WIDEN(s) pugi::as_wide(s)
105#include <pugixml.hpp>
134#define DT_XMP_EXIF_VERSION 5
136#if EXIV2_TEST_VERSION(0,28,0)
137#define AnyError Error
138#define toLong toInt64
211 const Exiv2::XmpPropertyInfo *pl = Exiv2::XmpProperties::propertyList(prefix);
214 for (
int i = 0; pl[
i].name_ != 0; ++
i)
217 *taglist = g_list_prepend(*taglist, tag);
271 const Exiv2::GroupInfo *groupList = Exiv2::ExifTags::groupList();
274 while(groupList->tagList_)
276 const std::string groupName(groupList->groupName_);
277 if(groupName.substr(0, 3) !=
"Sub" &&
278 groupName !=
"Image2" &&
279 groupName !=
"Image3" &&
280 groupName !=
"Thumbnail"
283 const Exiv2::TagInfo *tagInfo = groupList->tagList_();
284 while(tagInfo->tag_ != 0xFFFF)
295 const Exiv2::DataSet *iptcEnvelopeList = Exiv2::IptcDataSets::envelopeRecordList();
296 while(iptcEnvelopeList->number_ != 0xFFFF)
298 char *tag =
dt_util_dstrcat(NULL,
"Iptc.Envelope.%s,%s%s", iptcEnvelopeList->name_,
300 iptcEnvelopeList->repeatable_ ?
"-R" :
"");
305 const Exiv2::DataSet *iptcApplication2List = Exiv2::IptcDataSets::application2RecordList();
306 while(iptcApplication2List->number_ != 0xFFFF)
308 char *tag =
dt_util_dstrcat(NULL,
"Iptc.Application2.%s,%s%s", iptcApplication2List->name_,
310 iptcApplication2List->repeatable_ ?
"-R" :
"");
312 iptcApplication2List++;
348 catch (Exiv2::AnyError& e)
350 std::string s(e.what());
351 std::cerr <<
"[exiv2 taglist] " << s << std::endl;
367 char *
t = (
char *)tag->data;
368 if(g_str_has_prefix(
t, tagname) &&
t[strlen(tagname)] ==
',')
371 t += strlen(tagname) + 1;
388#define read_metadata_threadsafe(image) \
391 image->readMetadata(); \
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" };
421 Exiv2::ExifData &exifData)
423 std::string str = pos->print(&exifData);
425 char *s = g_locale_to_utf8(str.c_str(), str.length(), NULL, NULL, NULL);
428 g_strlcpy(dest, s, dest_max);
433 g_strlcpy(dest, str.c_str(), dest_max);
444 Exiv2::XmpData::iterator pos = xmp.findKey(Exiv2::XmpKey(
dt_xmp_keys[
i]));
446 while(pos != xmp.end())
448 std::string
key = pos->key();
449 const char *ckey =
key.c_str();
450 size_t len =
key.size();
452 if(!(g_str_has_prefix(ckey,
dt_xmp_keys[
i]) && (ckey[len] ==
'[' || ckey[len] ==
'\0')))
454 pos = xmp.erase(pos);
461 for(
unsigned int i = 0;
i < n_keys;
i++)
465 Exiv2::ExifData::iterator pos;
466 while((pos = exif.findKey(Exiv2::ExifKey(keys[
i]))) != exif.end())
469 catch(
const std::exception &e)
481 for(
unsigned int i = 0;
i < n_keys;
i++)
485 Exiv2::XmpData::iterator pos;
486 while((pos = xmp.findKey(Exiv2::XmpKey(keys[
i]))) != xmp.end())
489 catch(
const std::exception &e)
503 return (*pos = xmpData.findKey(Exiv2::XmpKey(
key))) != xmpData.end() && (*pos)->size();
505 catch(
const std::exception &e)
507 std::string s(e.what());
508 std::cerr <<
"[exiv2 read_xmp_tag] " << s << std::endl;
512#define FIND_XMP_TAG(key) dt_exif_read_xmp_tag(xmpData, &pos, key)
523 imgs = g_list_prepend(imgs, GINT_TO_POINTER(img->
id));
526 Exiv2::XmpData::iterator pos;
532 if(version == -1 || version > 0)
540 char *
value = strdup(pos->toString().c_str());
543 while(!strncmp(
value,
"lang=", 5) || !strncmp(
value,
"charset=", 8))
556 const int stars = pos->toLong();
565 std::string label = pos->toString();
568 else if(label ==
"Yellow")
570 else if(label ==
"Green")
572 else if(label ==
"Blue")
574 else if(label ==
"Purple")
581 const int cnt = pos->count();
582 for(
int i = 0;
i < cnt;
i++)
613 Exiv2::XmpData::const_iterator ref = xmpData.findKey(Exiv2::XmpKey(
"Xmp.exif.GPSAltitudeRef"));
614 if(ref != xmpData.end() && ref->size())
616 std::string sign_str = ref->toString();
617 const char *
sign = sign_str.c_str();
618 double elevation = 0.0;
628 char *lens = strdup(pos->toString().c_str());
630 if(strncmp(lens,
"lang=", 5) == 0)
632 lens = strchr(lens,
' ');
644 char *datetime = strdup(pos->toString().c_str());
657 catch(
const std::exception &e)
665 std::string s(e.what());
666 std::cerr <<
"[exiv2 _exif_decode_xmp_data] " << img->
filename <<
": " << s << std::endl;
675 return (*pos = iptcData.findKey(Exiv2::IptcKey(
key))) != iptcData.end() && (*pos)->size();
677 catch(
const std::exception &e)
679 std::string s(e.what());
680 std::cerr <<
"[exiv2 read_iptc_tag] " << s << std::endl;
684#define FIND_IPTC_TAG(key) dt_exif_read_iptc_tag(iptcData, &pos, key)
693 Exiv2::IptcData::const_iterator pos;
694 iptcData.sortByKey();
696 if((pos = iptcData.findKey(Exiv2::IptcKey(
"Iptc.Application2.Keywords"))) != iptcData.end())
698 while(pos != iptcData.end())
700 std::string
key = pos->key();
701 if(g_strcmp0(
key.c_str(),
"Iptc.Application2.Keywords"))
break;
702 std::string str = pos->print();
714 std::string str = pos->print();
719 std::string str = pos->print();
724 std::string str = pos->print();
729 std::string str = pos->print();
734 std::string str = pos->print();
740 GString *datetime = g_string_new(pos->toString().c_str());
742 datetime = g_string_append(datetime,
"T");
745 gchar *time = g_strdup(pos->toString().c_str());
746 datetime = g_string_append(datetime, time);
750 datetime = g_string_append(datetime,
"00:00:00");
753 g_string_free(datetime,
TRUE);
758 catch(
const std::exception &e)
760 std::string s(e.what());
761 std::cerr <<
"[exiv2 _exif_decode_iptc_data] " << img->
filename <<
": " << s << std::endl;
767 Exiv2::ExifData::const_iterator *pos,
string key)
771 return (*pos = exifData.findKey(Exiv2::ExifKey(
key)))
772 != exifData.end() && (*pos)->size();
774 catch(
const std::exception &e)
776 std::string s(e.what());
777 std::cerr <<
"[exiv2 read_exif_tag] " << s << std::endl;
781#define FIND_EXIF_TAG(key) _exif_read_exif_tag(exifData, &pos, key)
789 Exiv2::ExifData::const_iterator pos =
790 exifData.findKey(Exiv2::ExifKey(
"Exif.SubImage1.0xc7b5"));
793 if(pos == exifData.end())
794 pos = exifData.findKey(Exiv2::ExifKey(
"Exif.Image.0xc7b5"));
795 if(pos != exifData.end() && pos->count() == 4 && pos->size())
798 for(
int i = 0;
i < 4;
i++) crop[
i] = pos->toFloat(
i);
803 && (crop[2] - crop[0] > 0.05f)
804 && (crop[3] - crop[1] > 0.05f))
815 gboolean has_opcodes =
FALSE;
816 Exiv2::ExifData::const_iterator pos = exifData.findKey(Exiv2::ExifKey(
"Exif.SubImage1.OpcodeList2"));
818 if(pos == exifData.end())
819 pos = exifData.findKey(Exiv2::ExifKey(
"Exif.Image.OpcodeList2"));
820 if(pos != exifData.end())
822 uint8_t *data = (uint8_t *)g_malloc(pos->size());
823 pos->copy(data, Exiv2::invalidByteOrder);
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())
851 catch(
const std::exception &e)
853 std::string s(e.what());
854 std::cerr <<
"[exiv2 reading DefaultUserCrop] " << filename <<
": " << s << std::endl;
860 Exiv2::ExifData::const_iterator pos,
861 char *exif_datetime_taken)
877 *exif_datetime_taken =
'\0';
882 Exiv2::ExifData::const_iterator pos,
896 for(
char *c =
maker + m_size - 1; c >
maker; c--)
897 if(*c !=
' ' && *c !=
'\0')
905 Exiv2::ExifData::const_iterator pos,
918 for(
char *c =
model + m_size - 1; c >
model; c--)
919 if(*c !=
' ' && *c !=
'\0')
931 Exiv2::ExifData::const_iterator pos;
940 if((pos = Exiv2::exposureTime(exifData)) != exifData.end() && pos->size())
957 if((pos = Exiv2::fNumber(exifData)) != exifData.end() && pos->size())
967 if((pos = Exiv2::isoSpeed(exifData)) != exifData.end() && pos->size())
970 if(strcmp(pos->key().c_str(),
"Exif.Photo.ISOSpeedRatings") == 0)
972 int isofield = pos->count() > 1 ? 1 : 0;
973 img->
exif_iso = pos->toFloat(isofield);
977 std::string str = pos->print();
978 img->
exif_iso = (float)std::atof(str.c_str());
986 std::string str = pos->print();
987 img->
exif_iso = (float)std::atof(str.c_str());
997 if((pos = Exiv2::focalLength(exifData)) != exifData.end() && pos->size())
1001 if (pos->key() ==
"Exif.Canon.FocalLength" && pos->count() == 4)
1010 const float focal_length_35mm = pos->toFloat();
1021 float x_resolution = pos->toFloat();
1022 float y_resolution = 0.0f;
1024 y_resolution = pos->toFloat();
1027 res_unit = pos->toLong();
1030 x_resolution /= 25.4f;
1031 y_resolution /= 25.4f;
1036 x_resolution /= 10.0f;
1037 y_resolution /= 10.0f;
1039 guint image_width = 0;
1040 guint image_height = 0;
1050 image_width = pos->toLong();
1052 image_height = pos->toLong();
1057 if(image_width == 0 &&
FIND_EXIF_TAG(
"Exif.SubImage1.NewSubfileType"))
1059 if(pos->toLong() == 0)
1062 image_width = pos->toLong();
1064 image_height = pos->toLong();
1070 if(image_width == 0)
1073 image_width = pos->toLong();
1075 image_height = pos->toLong();
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)
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;
1095 snprintf(tagname,
sizeof(tagname),
"darktable|mode|exif-crop");
1108 if(Exiv2::testVersion(0, 27, 4) &&
FIND_EXIF_TAG(
"Exif.NikonLd4.LensID") && pos->toLong() != 0)
1112#if EXIV2_TEST_VERSION(0, 28, 0)
1115 float value = pos->toFloat();
1116 if(Exiv2::testVersion(0, 28, 1))
value /= 256.0f;
1118 pos = exifData.end();
1119 for(
auto it = exifData.begin(); it != exifData.end(); it++)
1121 if(it->key() ==
"Exif.NikonLd4.FocusDistance") pos = it;
1123 if(pos != exifData.end() && pos->size())
1125 float value = pos->toFloat();
1131 || (Exiv2::testVersion(0, 27, 4) &&
FIND_EXIF_TAG(
"Exif.NikonLd4.FocusDistance")))
1133 float value = pos->toFloat();
1154 int nominator = pos->toRational(0).first;
1159 const float FocusDistanceUpper = pos->toFloat();
1160 if(FocusDistanceUpper <= 0.0f || (
int)FocusDistanceUpper >= 0xffff)
1169 const float FocusDistanceLower = pos->toFloat();
1170 if(FocusDistanceLower > 0.0f && (
int)FocusDistanceLower < 0xffff)
1182 else if((pos = Exiv2::subjectDistance(exifData)) != exifData.end() && pos->size())
1186 else if(Exiv2::testVersion(0,27,2) &&
FIND_EXIF_TAG(
"Exif.Sony2Fp.FocusPosition2"))
1188 const float focus_position = pos->toFloat();
1190 if (focus_position &&
FIND_EXIF_TAG(
"Exif.Photo.FocalLengthIn35mmFilm")) {
1191 const float focal_length_35mm = pos->toFloat();
1194 img->
exif_focus_distance = (pow(2, focus_position / 16 - 5) + 1) * focal_length_35mm / 1000;
1210 if(
FIND_EXIF_TAG(
"Exif.Thumbnail.PhotometricInterpretation") && (32803 == pos->toLong())
1219 Exiv2::ExifData::const_iterator ref = exifData.findKey(Exiv2::ExifKey(
"Exif.GPSInfo.GPSLatitudeRef"));
1220 if(ref != exifData.end() && ref->size() && pos->count() == 3)
1222 std::string sign_str = ref->toString();
1223 const char *
sign = sign_str.c_str();
1224 double latitude = 0.0;
1226 pos->toRational(1).first, pos->toRational(1).second,
1227 pos->toRational(2).first, pos->toRational(2).second,
sign[0], &latitude))
1234 Exiv2::ExifData::const_iterator ref = exifData.findKey(Exiv2::ExifKey(
"Exif.GPSInfo.GPSLongitudeRef"));
1235 if(ref != exifData.end() && ref->size() && pos->count() == 3)
1237 std::string sign_str = ref->toString();
1238 const char *
sign = sign_str.c_str();
1239 double longitude = 0.0;
1241 pos->toRational(1).first, pos->toRational(1).second,
1242 pos->toRational(2).first, pos->toRational(2).second,
sign[0], &longitude))
1249 Exiv2::ExifData::const_iterator ref = exifData.findKey(Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitudeRef"));
1250 if(ref != exifData.end() && ref->size())
1252 std::string sign_str = ref->toString();
1253 const char *
sign = sign_str.c_str();
1254 double elevation = 0.0;
1262 && pos->toLong() != 61182
1263 && pos->toLong() != 0
1264 && pos->toLong() != 65535)
1285 if(std::string::npos == lens.find_first_not_of(
" 1234567890"))
1299 fprintf(stderr,
"[exif] Warning: lens \"%s\" unknown as \"%s\"\n", img->
exif_lens, lens.c_str());
1302 else if(Exiv2::testVersion(0,27,4) &&
FIND_EXIF_TAG(
"Exif.NikonLd4.LensID") && pos->toLong() == 0)
1310 else if((pos = Exiv2::lensName(exifData)) != exifData.end() && pos->size())
1316 if(g_str_has_prefix(img->
exif_lens,
"RF"))
1320 pretty = g_strconcat(
"Canon RF-S ", &img->
exif_lens[4], (
char *)NULL);
1322 pretty = g_strconcat(
"Canon RF ", &img->
exif_lens[2], (
char *)NULL);
1328 if(g_str_has_prefix(img->
exif_lens,
"NIKKOR") || g_str_has_prefix(img->
exif_lens,
"TAMRON"))
1330 for(
size_t i = 1;
i <= 5; ++
i)
1338 if(std::string::npos == lens.find_first_not_of(
" (1234567890)")
1346 if ( (pos=exifData.findKey(Exiv2::ExifKey(
"Exif.Photo.Flash")))
1347 != exifData.end() && pos->size())
1349 uf_strlcpy_to_utf8(uf->conf->flashText, max_name, pos, exifData);
1352 if ( (pos=exifData.findKey(Exiv2::ExifKey(
"Exif.Photo.WhiteBalance")))
1353 != exifData.end() && pos->size())
1355 uf_strlcpy_to_utf8(uf->conf->whiteBalanceText, max_name, pos, exifData);
1365 std::string str = pos->print(&exifData);
1370 std::string str = pos->print(&exifData);
1377 std::string str = pos->print(&exifData);
1378 Exiv2::CommentValue
value(str);
1379 std::string str2 =
value.comment();
1380 if(str2 !=
"binary comment")
1385 std::string str = pos->print(&exifData);
1391 std::string str = pos->print(&exifData);
1397 const int stars = pos->toLong();
1402 const int stars = pos->toLong() * 5. / 100;
1410 float colmatrix[3][12];
1411 colmatrix[0][0] = colmatrix[1][0] = colmatrix[2][0] = NAN;
1420 const float correctmat[13][9] = {
1421 { 0.9555766, -0.0230393, 0.0631636, -0.0282895, 1.0099416, 0.0210077, 0.0122982, -0.0204830,
1423 { 0.9726856, -0.0135482, 0.0361731, -0.0167463, 1.0049102, 0.0120598, 0.0070026, -0.0116372,
1425 { 1.0206905, 0.0091588, -0.0228796, 0.0115005, 0.9984917, -0.0076762, -0.0043619, 0.0072053,
1427 { 0.8446965, -0.1179225, 0.3948108, -0.1366303, 1.1041226, 0.1291718, 0.0798489, -0.1348999,
1429 { 0.9415037, -0.0321240, 0.0584672, -0.0428238, 1.0250998, 0.0203309, 0.0101511, -0.0161170,
1431 { 0.9904476, -0.0071683, -0.0116156, -0.0123712, 1.0155950, -0.0029282, -0.0035635, 0.0067697,
1433 { 0.9212269, -0.0449128, 0.1211620, -0.0553723, 1.0277243, 0.0403563, 0.0235086, -0.0391019,
1437 { 0.8663030, -0.0913083, 0.2771784, -0.1090504, 1.0746895, 0.0913841, 0.0550856, -0.0924636,
1439 { 1.0096114, 0.0061501, 0.0068113, 0.0102539, 0.9888663, 0.0015575, 0.0023119, -0.0044823,
1441 { 0.9554129, -0.0231280, 0.0637169, -0.0283629, 1.0099053, 0.0211824, 0.0124188, -0.0206922,
1443 { 0.9147843, -0.0492842, 0.1202810, -0.0622085, 1.034984, 0.0404480, 0.0228014, -0.0375807,
1445 { 0.8805388, -0.0774890, 0.2293784, -0.0932136, 1.0589267, 0.0757827, 0.0453660, -0.0760107,
1447 { 0.8488316, -0.1107439, 0.3471428, -0.1310107, 1.0986874, 0.1141548, 0.0694025, -0.1167541,
1451 Exiv2::ExifData::const_iterator cm1_pos = exifData.findKey(Exiv2::ExifKey(
"Exif.Image.ColorMatrix1"));
1452 if((cm1_pos != exifData.end()) && (cm1_pos->count() == 9))
1454 for(
int i = 0;
i < 9;
i++) colmatrix[0][
i] = cm1_pos->toFloat(
i);
1459 Exiv2::ExifData::const_iterator cm2_pos = exifData.findKey(Exiv2::ExifKey(
"Exif.Image.ColorMatrix2"));
1460 if((cm2_pos != exifData.end()) && (cm2_pos->count() == 9))
1462 for(
int i = 0;
i < 9;
i++) colmatrix[1][
i] = cm2_pos->toFloat(
i);
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))
1472 for(
int i = 0;
i < 9;
i++) colmatrix[2][
i] = cm3_pos->toFloat(
i);
1481 int delta_min = D65temp;
1484 for(
int i = 0;
i < 3; ++
i)
1487 int delta_cur = abs(temp_cur - D65temp);
1488 if((temp_cur > sel_temp) && (delta_cur <= delta_min))
1491 sel_temp = temp_cur;
1492 delta_min = delta_cur;
1499 for(
int i = 0;
i < 3; ++
i)
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");
1524 switch(illu[sel_illu])
1577 fprintf(stderr,
"[exif] did not find a proper dng correction matrix for illuminant %i\n", illu[sel_illu]);
1592 format = pos->toLong();
1594 format = pos->toLong();
1597 bps = pos->toLong();
1599 bps = pos->toLong();
1602 spp = pos->toLong();
1604 spp = pos->toLong();
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();
1611 if((format == 3) && (bps >= 16) && ((phi == 32803) || (phi == 34892)))
1614 if((spp == 1) && (phi == 34892))
1631 int colorspace = pos->toLong();
1632 if(colorspace == 0x01)
1634 else if(colorspace == 0x02)
1636 else if(colorspace == 0xffff)
1640 std::string interop_index = pos->toString();
1641 if(interop_index ==
"R03")
1643 else if(interop_index ==
"R98")
1650 if(
FIND_EXIF_TAG(
"Exif.Sony2.LensID") && pos->toLong() != 65535 && pos->print().find(
'|') == std::string::npos)
1664 std::string str = pos->print(&exifData);
1672 catch(
const std::exception &e)
1674 std::string s(e.what());
1675 std::cerr <<
"[exiv2 _exif_decode_exif_data] " << img->
filename <<
": " << s << std::endl;
1685 Exiv2::ExifData exifData;
1686 Exiv2::ExifParser::decode(exifData, blob,
size);
1690 catch(
const std::exception &e)
1692 std::string s(e.what());
1693 std::cerr <<
"[exiv2 dt_exif_read_from_blob] " << img->
filename <<
": " << s << std::endl;
1705 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(
WIDEN(path)));
1706 if(!image.get())
return 1;
1711 Exiv2::PreviewManager loader(*image);
1712 Exiv2::PreviewPropertiesList list = loader.getPreviewProperties();
1720 Exiv2::PreviewProperties selected = list.back();
1723 Exiv2::PreviewImage preview = loader.getPreviewImage(selected);
1724 const unsigned char *tmp = preview.pData();
1725 size_t _size = preview.size();
1728 *
width = preview.width();
1729 *
height = preview.height();
1730 *mime_type = strdup(preview.mimeType().c_str());
1731 *buffer = (uint8_t *)malloc(_size);
1733 std::cerr <<
"[exiv2 dt_exif_get_thumbnail] couldn't allocate memory for thumbnail for " << path << std::endl;
1737 memcpy(*buffer, tmp, _size);
1741 catch(
const std::exception &e)
1743 std::string s(e.what());
1744 std::cerr <<
"[exiv2 dt_exif_get_thumbnail] " << path <<
": " << s << std::endl;
1761 const char *ext = g_strrstr(path,
".");
1767 struct stat statbuf;
1769 if(!stat(path, &statbuf))
1776 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(
WIDEN(path)));
1777 if(!image.get())
return 1;
1782 Exiv2::ExifData &exifData = image->exifData();
1783 if(!exifData.empty())
1791 Exiv2::IptcData &iptcData = image->iptcData();
1795 Exiv2::XmpData &xmpData = image->xmpData();
1796 if(!xmpData.empty())
1802 img->
height = image->pixelHeight();
1803 img->
width = image->pixelWidth();
1807 catch(
const std::exception &e)
1809 std::string s(e.what());
1810 std::cerr <<
"[exiv2 dt_exif_read] " << path <<
": " << s << std::endl;
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)
1835 Exiv2::ExifKey
key(
i->key());
1836 if((it = imgExifData.findKey(
key)) != imgExifData.end()) imgExifData.erase(it);
1838 imgExifData.add(Exiv2::ExifKey(
i->key()), &
i->value());
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"
1851 static const guint n_keys = G_N_ELEMENTS(keys);
1858 static const char *keys[] = {
1859 "Exif.Photo.PixelXDimension",
1860 "Exif.Photo.PixelYDimension"
1862 static const guint n_keys = G_N_ELEMENTS(keys);
1866 imgExifData.sortByTag();
1867 image->writeMetadata();
1869 catch(
const std::exception &e)
1871 std::string s(e.what());
1872 std::cerr <<
"[exiv2 dt_exif_write_blob] " << path <<
": " << s << std::endl;
1880 static const char *keys[] =
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"
1890 static const guint n_keys = G_N_ELEMENTS(keys);
1895 const int out_height,
const int dng_mode)
1900 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(
WIDEN(path)));
1901 if(!image.get())
return 1;
1903 Exiv2::ExifData &exifData = image->exifData();
1906 Exiv2::ExifThumb(exifData).erase();
1907 Exiv2::ExifData::const_iterator pos;
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"
1927 static const guint n_keys = G_N_ELEMENTS(keys);
1934 for(Exiv2::ExifData::iterator
i = exifData.begin();
i != exifData.end();)
1936 static const std::string needle =
"Exif.SubImage";
1937 if(
i->key().compare(0, needle.length(), needle) == 0)
1938 i = exifData.erase(
i);
1944 static const char *keys[] = {
1946 "Exif.Canon.ColorSpace",
1947 "Exif.Canon.ColorData",
1950 "Exif.Nikon3.Preview",
1951 "Exif.NikonPreview.JPEGInterchangeFormat",
1954 "Exif.Image.CFARepeatPatternDim",
1955 "Exif.Image.CFAPattern",
1956 "Exif.Image.InterColorProfile",
1957 "Exif.Image.SpectralSensitivity",
1959 "Exif.Image.SpatialFrequencyResponse",
1961 "Exif.Image.SensingMethod",
1962 "Exif.Image.TIFFEPStandardID",
1963 "Exif.Photo.SpectralSensitivity",
1965 "Exif.Photo.SpatialFrequencyResponse",
1966 "Exif.Photo.SensingMethod",
1967 "Exif.Photo.CFAPattern",
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",
2001 "Exif.Photo.MakerNote",
2004 "Exif.Pentax.PreviewResolution",
2005 "Exif.Pentax.PreviewLength",
2006 "Exif.Pentax.PreviewOffset",
2007 "Exif.PentaxDng.PreviewResolution",
2008 "Exif.PentaxDng.PreviewLength",
2009 "Exif.PentaxDng.PreviewOffset",
2011 "Exif.PentaxDng.ColorInfo",
2014 "Exif.Minolta.Thumbnail",
2015 "Exif.Minolta.ThumbnailOffset",
2016 "Exif.Minolta.ThumbnailLength",
2019 "Exif.SonyMinolta.ThumbnailOffset",
2020 "Exif.SonyMinolta.ThumbnailLength",
2023 "Exif.Olympus.Thumbnail",
2024 "Exif.Olympus.ThumbnailOffset",
2025 "Exif.Olympus.ThumbnailLength",
2027 "Exif.Image.BaselineExposureOffset",
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"
2047 static const guint n_keys = G_N_ELEMENTS(keys);
2051 static const char *dngkeys[] = {
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"
2080 static const guint n_dngkeys = G_N_ELEMENTS(dngkeys);
2085 exifData[
"Exif.Photo.ColorSpace"] = uint16_t(1);
2087 exifData[
"Exif.Photo.ColorSpace"] = uint16_t(0xFFFF);
2091 if(!dng_mode) exifData[
"Exif.Image.Orientation"] = uint16_t(1);
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;
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);
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"
2127 static const guint n_keys = G_N_ELEMENTS(keys);
2133 exifData[
"Exif.Image.Artist"] = (
char *)res->data;
2141 char *desc = (
char *)res->data;
2142 if(g_str_is_ascii(desc))
2143 exifData[
"Exif.Image.ImageDescription"] = desc;
2145 exifData[
"Exif.Photo.UserComment"] = desc;
2149#if EXIV2_TEST_VERSION(0,27,4)
2153 exifData[
"Exif.Image.ImageDescription"] =
"";
2159 exifData[
"Exif.Image.Copyright"] = (
char *)res->data;
2163#if EXIV2_TEST_VERSION(0,27,4)
2167 exifData[
"Exif.Image.Copyright"] =
"";
2173 const int rating = GPOINTER_TO_INT(res->data) + 1;
2174 exifData[
"Exif.Image.Rating"] = rating;
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";
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;
2201 exifData[
"Exif.GPSInfo.GPSVersionID"] =
"02 02 00 00";
2202 exifData[
"Exif.GPSInfo.GPSAltitudeRef"] = (cimg->
geoloc.
elevation < 0) ?
"1" :
"0";
2205 gchar *ele_str = g_strdup_printf(
"%ld/10", ele_dm);
2206 exifData[
"Exif.GPSInfo.GPSAltitude"] = ele_str;
2216 exifData[
"Exif.Image.DateTime"] = new_datetime;
2220 exifData[
"Exif.Image.DateTimeOriginal"] = datetime;
2221 exifData[
"Exif.Photo.DateTimeOriginal"] = datetime;
2229 Exiv2::ExifParser::encode(blob, Exiv2::bigEndian, exifData);
2230 const size_t length = blob.size();
2231 *buf = (uint8_t *)malloc(length);
2236 memcpy(*buf, &(blob[0]), length);
2239 catch(
const std::exception &e)
2242 std::string s(e.what());
2243 std::cerr <<
"[exiv2 dt_exif_read_blob] " << path <<
": " << s << std::endl;
2252#define COMPRESS_THRESHOLD 100
2254 gboolean do_compress =
FALSE;
2262 if(!strcmp(config,
"always"))
2267 do_compress =
FALSE;
2273#undef COMPRESS_THRESHOLD
2278 char *output = NULL;
2283 uLongf destLen = compressBound(len);
2284 unsigned char *buffer1 = (
unsigned char *)malloc(destLen);
2286 result = compress(buffer1, &destLen, input, len);
2295 const int factor =
MIN(len / destLen + 1, 99);
2297 char *buffer2 = (
char *)g_base64_encode(buffer1, destLen);
2301 int outlen = strlen(buffer2) + 5;
2302 output = (
char *)malloc(outlen);
2311 output[2] =
factor / 10 +
'0';
2312 output[3] =
factor % 10 +
'0';
2313 g_strlcpy(output + 4, buffer2, outlen);
2316 if(output_len) *output_len = outlen;
2320 const char hex[16] = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'a',
'b',
'c',
'd',
'e',
'f' };
2322 output = (
char *)malloc(2 * len + 1);
2325 if(output_len) *output_len = 2 * len + 1;
2327 for(
int i = 0;
i < len;
i++)
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];
2334 output[2 * len] =
'\0';
2343 unsigned char *output = NULL;
2346 if(!strncmp(input,
"gz", 2))
2351 const float factor = 10 * (input[2] -
'0') + (input[3] -
'0');
2354 unsigned char *buffer = (
unsigned char *)strdup(input + 4);
2358 gsize compressed_size;
2359 g_base64_decode_inplace((
char *)buffer, &compressed_size);
2362 int result = Z_BUF_ERROR;
2363 uLongf bufLen =
factor * compressed_size;
2374 output = (
unsigned char *)malloc(bufLen);
2379 result = uncompress(output, &destLen, buffer, compressed_size);
2383 }
while(result == Z_BUF_ERROR);
2397 if(output_len) *output_len = destLen;
2406#define TO_BINARY(a) (a > 57 ? a - 97 + 10 : a - 48)
2409 if(strspn(input,
"0123456789abcdef") != strlen(input))
return NULL;
2411 output = (
unsigned char *)malloc(len / 2);
2414 if(output_len) *output_len = len / 2;
2416 for(
int i = 0;
i < len / 2;
i++)
2420 output[
i] = (hi << 4) | lo;
2431 const int cnt = pos->count();
2433 sqlite3_stmt *stmt_sel_id, *stmt_ins_tags, *stmt_ins_tagged;
2435 &stmt_sel_id, NULL);
2437 -1, &stmt_ins_tags, NULL);
2440 "INSERT INTO main.tagged_images (tagid, imgid, position)"
2442 " (SELECT (IFNULL(MAX(position),0) & 0xFFFFFFFF00000000) + (1 << 32)"
2443 " FROM main.tagged_images))",
2444 -1, &stmt_ins_tagged, NULL);
2446 for(
int i = 0;
i < cnt;
i++)
2449 std::string pos_str = pos->toString(
i);
2450 g_strlcpy(tagbuf, pos_str.c_str(),
sizeof(tagbuf));
2455 char *next_tag = strstr(tag,
",");
2456 if(next_tag) *(next_tag++) = 0;
2458 for(
int k = 0;
k < 2;
k++)
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);
2465 if(tagid > 0)
break;
2467 fprintf(stderr,
"[xmp_import] creating tag: %s\n", tag);
2470 sqlite3_step(stmt_ins_tags);
2471 sqlite3_reset(stmt_ins_tags);
2472 sqlite3_clear_bindings(stmt_ins_tags);
2477 sqlite3_step(stmt_ins_tagged);
2478 sqlite3_reset(stmt_ins_tagged);
2479 sqlite3_clear_bindings(stmt_ins_tagged);
2484 sqlite3_finalize(stmt_sel_id);
2485 sqlite3_finalize(stmt_ins_tags);
2486 sqlite3_finalize(stmt_ins_tagged);
2531 std::cout <<
"malformed entry" << std::endl;
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;
2560static GList *
read_history_v1(
const std::string &xmpPacket,
const char *filename,
const int superold)
2562 GList *history_entries = NULL;
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());
2568 pugi::xml_parse_result result = doc.load(xmpPacket.c_str());
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;
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");
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");
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();
2643 for(pugi::xml_node operation_iter: operation.node().children())
2647 history_entries = g_list_append(history_entries, current_entry);
2649 current_entry->
operation = g_strdup(operation_iter.child_value());
2651 current_entry->
enabled = g_strcmp0(enabled_iter->child_value(),
"0") != 0;
2653 current_entry->
modversion = atoi(modversion_iter->child_value());
2658 if(multi_name && multi_name_iter != multi_name.node().children().end())
2660 current_entry->
multi_name = g_strdup(multi_name_iter->child_value());
2664 if(multi_priority && multi_priority_iter != multi_priority.node().children().end())
2666 current_entry->
multi_priority = atoi(multi_priority_iter->child_value());
2667 multi_priority_iter++;
2670 if(blendop_version && blendop_version_iter != blendop_version.node().children().end())
2672 current_entry->
blendop_version = atoi(blendop_version_iter->child_value());
2673 blendop_version_iter++;
2676 if(blendop_params && blendop_params_iter != blendop_params.node().children().end())
2679 strlen(blendop_params_iter->child_value()),
2681 blendop_params_iter++;
2691 return history_entries;
2696 GList *history_entries = NULL;
2699 for(
auto history = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.history")); history != xmpData.end(); history++)
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["))
2710 key_iter += strlen(
"Xmp.darktable.history[");
2712 unsigned int n = strtol(key_iter, &key_iter, 10);
2715 std::cerr <<
"error reading history from '" <<
key <<
"' (" << filename <<
")" << std::endl;
2717 history_entries = NULL;
2723 if(*(key_iter++) !=
']')
2725 std::cerr <<
"error reading history from '"
2726 <<
key <<
"' (" << filename <<
")" << std::endl;
2728 history_entries = NULL;
2732 if(*(key_iter++) !=
'/')
goto skip;
2733 if(*key_iter ==
'?') key_iter++;
2736 unsigned int length = g_list_length(history_entries);
2742 history_entries = g_list_append(history_entries, current_entry);
2749 current_entry = (
history_entry_t *)g_list_nth_data(history_entries,
n - 1);
2753 if(g_str_has_prefix(key_iter,
"darktable:operation"))
2756 std::string value_item = history->toString();
2757 current_entry->
operation = g_strdup(value_item.c_str());
2759 else if(g_str_has_prefix(key_iter,
"darktable:num"))
2761 current_entry->
num = history->toLong();
2763 else if(g_str_has_prefix(key_iter,
"darktable:enabled"))
2765 current_entry->
enabled = history->toLong() == 1;
2767 else if(g_str_has_prefix(key_iter,
"darktable:modversion"))
2770 current_entry->
modversion = history->toLong();
2772 else if(g_str_has_prefix(key_iter,
"darktable:params"))
2775 std::string value_item = history->toString();
2786 else if(g_str_has_prefix(key_iter,
"darktable:multi_name"))
2788 std::string value_item = history->toString();
2789 current_entry->
multi_name = g_strdup(value_item.c_str());
2791 else if(g_str_has_prefix(key_iter,
"darktable:multi_priority"))
2795 else if(g_str_has_prefix(key_iter,
"darktable:iop_order"))
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);
2805 else if(g_str_has_prefix(key_iter,
"darktable:blendop_version"))
2809 else if(g_str_has_prefix(key_iter,
"darktable:blendop_params"))
2811 std::string value_item = history->toString();
2823 for(GList *iter = history_entries; iter; iter = g_list_next(iter))
2828 std::cerr <<
"[exif] error: reading history from '" << filename <<
"' failed due to missing tags" << std::endl;
2830 history_entries = NULL;
2835 return history_entries;
2847static GHashTable *
read_masks(Exiv2::XmpData &xmpData,
const char *filename,
const int version)
2849 GHashTable *mask_entries = g_hash_table_new_full(g_int_hash, g_int_equal, NULL,
free_mask_entry);
2852 Exiv2::XmpData::iterator mask;
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())
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)
2878 for(
size_t i = 0;
i < cnt;
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());
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);
2898 entry->
mask_nb = mask_nb->toLong(
i);
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);
2905 g_hash_table_insert(mask_entries, &entry->
mask_id, (gpointer)entry);
2910 return mask_entries;
2913static GList *
read_masks_v3(Exiv2::XmpData &xmpData,
const char *filename,
const int version)
2915 GList *history_entries = NULL;
2918 for(
auto history = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.masks_history")); history != xmpData.end(); history++)
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["))
2929 key_iter += strlen(
"Xmp.darktable.masks_history[");
2931 unsigned int n = strtol(key_iter, &key_iter, 10);
2934 std::cerr <<
"error reading masks history from '" <<
key <<
"' (" << filename <<
")" << std::endl;
2936 history_entries = NULL;
2942 if(*(key_iter++) !=
']')
2944 std::cerr <<
"error reading masks history from '" <<
key <<
"' (" << filename <<
")" << std::endl;
2946 history_entries = NULL;
2950 if(*(key_iter++) !=
'/')
goto skip;
2951 if(*key_iter ==
'?') key_iter++;
2954 unsigned int length = g_list_length(history_entries);
2958 current_entry->
version = version;
2959 history_entries = g_list_append(history_entries, current_entry);
2966 current_entry = (
mask_entry_t *)g_list_nth_data(history_entries,
n - 1);
2970 if(g_str_has_prefix(key_iter,
"darktable:mask_num"))
2972 current_entry->
mask_num = history->toLong();
2974 else if(g_str_has_prefix(key_iter,
"darktable:mask_id"))
2976 current_entry->
mask_id = history->toLong();
2978 else if(g_str_has_prefix(key_iter,
"darktable:mask_type"))
2980 current_entry->
mask_type = history->toLong();
2982 else if(g_str_has_prefix(key_iter,
"darktable:mask_name"))
2984 std::string value_item = history->toString();
2985 current_entry->
mask_name = g_strdup(value_item.c_str());
2987 else if(g_str_has_prefix(key_iter,
"darktable:mask_version"))
2991 else if(g_str_has_prefix(key_iter,
"darktable:mask_points"))
2993 std::string value_item = history->toString();
2998 else if(g_str_has_prefix(key_iter,
"darktable:mask_nb"))
3000 current_entry->
mask_nb = history->toLong();
3002 else if(g_str_has_prefix(key_iter,
"darktable:mask_src"))
3004 std::string value_item = history->toString();
3015 return history_entries;
3024 const int mask_num = 0;
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)",
3050 int prepare_result = sqlite3_step(stmt);
3051 sqlite3_finalize(stmt);
3054 if(prepare_result == SQLITE_OK)
3062 int32_t imgid = *(
int *)user_data;
3082 fprintf(stderr,
"[masks] error loading masks from xmp file, bad binary blob size.\n");
3097 for(GList *iter = history; iter; iter = g_list_next(iter))
3101 if(!strcmp(entry->
operation, operation))
3112 const char *c = filename + strlen(filename) - 4;
3113 if(c >= filename && !strcmp(c,
".pfm"))
return 1;
3117 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(
WIDEN(filename)));
3118 if(!image.get())
return 1;
3120 Exiv2::XmpData &xmpData = image->xmpData();
3124 Exiv2::XmpData::iterator pos;
3126 int xmp_version = 0;
3127 GList *iop_order_list = NULL;
3131 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.xmp_version"))) != xmpData.end())
3132 xmp_version = pos->toLong();
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);
3144 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.raw_params"))) != xmpData.end())
3150 raw_params.in = pos->toLong();
3151 const int32_t user_flip = raw_params.out.
user_flip;
3156 int32_t preset_applied = 0;
3158 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.auto_presets_applied"))) != xmpData.end())
3160 preset_applied = pos->toLong();
3165 else if(xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.xmp_version")) == xmpData.end())
3174 img->
flags &= ~DT_IMAGE_NO_LEGACY_PRESETS;
3177 img->
flags &= ~DT_IMAGE_REMOVE;
3179 if(xmp_version == 4 || xmp_version == 5)
3181 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.iop_order_version"))) != xmpData.end())
3186 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.iop_order_list"))) != xmpData.end())
3193 else if(xmp_version == 3)
3197 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.iop_order_version"))) != xmpData.end())
3214 GHashTable *mask_entries = NULL;
3215 GList *mask_entries_v3 = NULL;
3222 mask_entries =
read_masks(xmpData, filename, xmp_version);
3224 mask_entries_v3 =
read_masks_v3(xmpData, filename, xmp_version);
3236 for(GList *m_entries = g_list_first(mask_entries_v3); m_entries; m_entries = g_list_next(m_entries))
3248 gboolean all_ok =
TRUE;
3249 GList *history_entries = NULL;
3253 std::string &xmpPacket = image->xmpPacket();
3255 if(!history_entries)
3258 else if(xmp_version == 2 || xmp_version == 3 || xmp_version == 4 || xmp_version == 5 )
3262 std::cerr <<
"error: Xmp schema version " << xmp_version <<
" in " << filename <<
" not supported" << std::endl;
3263 g_hash_table_destroy(mask_entries);
3271 fprintf(stderr,
"[exif] error deleting history for image %d\n", img->
id);
3277 for(GList *iter = history_entries; iter; iter = g_list_next(iter))
3280 const int db_num = (xmp_version < 3) ? num : entry->
num;
3299 fprintf(stderr,
"[exif] error adding history entry for image %d\n", img->
id);
3315 for(GList *iter = history_entries; iter; iter = g_list_next(iter))
3335 "[exif] cannot get iop-order for module '%s', XMP may be corrupted\n",
3338 iop_order_list = NULL;
3340 history_entries = NULL;
3342 mask_entries_v3 = NULL;
3343 if(mask_entries) g_hash_table_destroy(mask_entries);
3358 if(link) iop_order_list = g_list_delete_link(iop_order_list, link);
3360 iop_order_list = g_list_append(iop_order_list, e);
3372 "SELECT COUNT(*) FROM main.masks_history WHERE imgid = ?1", -1,
3375 if(sqlite3_step(stmt) == SQLITE_ROW)
3376 num_masks = sqlite3_column_int(stmt, 0);
3377 sqlite3_finalize(stmt);
3384 fprintf(stderr,
"[exif] error shifting history nums for image %d\n", img->
id);
3389 if(!
dt_history_db_write_history_item(img->
id, 0,
"mask_manager", NULL, 0, 1, 0, NULL, 0, 0, 0,
""))
3391 fprintf(stderr,
"[exif] error adding mask history entry for image %d\n", img->
id);
3402 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.history_end"))) != xmpData.end() && num > 0)
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;
3409 fprintf(stderr,
"[exif] error writing history_end for image %d\n", img->
id);
3417 if(preset_applied) preset_applied = -1;
3421 fprintf(stderr,
"[exif] error writing history_end for image %d\n", img->
id);
3429 fprintf(stderr,
"[exif] error writing iop_list for image %d\n", img->
id);
3441 if(preset_applied > 0)
3448 img->
flags &= ~DT_IMAGE_AUTO_PRESETS_APPLIED;
3450 if(preset_applied < 0)
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);
3457 iop_order_list = NULL;
3459 history_entries = NULL;
3461 mask_entries_v3 = NULL;
3462 if(mask_entries) g_hash_table_destroy(mask_entries);
3469 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.history_current_hash"))) != xmpData.end())
3472 unsigned char *decoded =
dt_exif_xmp_decode(pos->toString().c_str(), strlen(pos->toString().c_str()),
3474 if(decoded && hash_len == (
int)
sizeof(
uint64_t))
3477 memcpy(&be_hash, decoded,
sizeof(be_hash));
3485 std::cerr <<
"[exif] error reading history from '" << filename <<
"'" << std::endl;
3491 catch(
const std::exception &e)
3513 Exiv2::XmpTextValue tvm(
"");
3514 tvm.setXmpArrayType(Exiv2::XmpValue::xaSeq);
3515 xmpData.add(Exiv2::XmpKey(
"Xmp.darktable.masks_history"), &tvm);
3519 "SELECT imgid, formid, form, name, version, points, points_count, source, num"
3520 " FROM main.masks_history"
3526 while(sqlite3_step(stmt) == SQLITE_ROW)
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);
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);
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);
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;
3561 sqlite3_finalize(stmt);
3567 Exiv2::XmpTextValue tv(
"");
3568 tv.setXmpArrayType(Exiv2::XmpValue::xaSeq);
3569 xmpData.add(Exiv2::XmpKey(
"Xmp.darktable.history"), &tv);
3573 "SELECT module, operation, op_params, enabled, blendop_params, "
3574 " blendop_version, multi_priority, multi_name, num"
3575 " FROM main.history"
3581 while(sqlite3_step(stmt) == SQLITE_ROW)
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);
3597 char *params =
dt_exif_xmp_encode((
const unsigned char *)params_blob, params_len, NULL);
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;
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;
3631 sqlite3_finalize(stmt);
3632 if(history_end == -1) history_end = num - 1;
3633 else history_end =
MIN(history_end, num - 1);
3634 xmpData[
"Xmp.darktable.history_end"] = history_end;
3640 static const char *keys[] =
3642 "Xmp.darktable.import_timestamp",
3643 "Xmp.darktable.change_timestamp",
3644 "Xmp.darktable.export_timestamp",
3645 "Xmp.darktable.print_timestamp"
3647 static const guint n_keys = G_N_ELEMENTS(keys);
3654 "SELECT import_timestamp, change_timestamp, export_timestamp, print_timestamp"
3661 if(sqlite3_step(stmt) == SQLITE_ROW)
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);
3672 sqlite3_finalize(stmt);
3677 GDateTime *gdt = g_date_time_new_from_unix_utc(unix);
3681 g_date_time_unref(gdt);
3690 Exiv2::XmpData::iterator pos;
3693 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.change_timestamp"))) != xmpData.end())
3697 else if(pos->toLong() >= 1)
3700 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.export_timestamp"))) != xmpData.end())
3704 else if(pos->toLong() >= 1)
3707 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.print_timestamp"))) != xmpData.end())
3711 else if(pos->toLong() >= 1)
3718 static const char *keys[] =
3720 "Xmp.exif.GPSVersionID",
3721 "Xmp.exif.GPSLongitude",
3722 "Xmp.exif.GPSLatitude",
3723 "Xmp.exif.GPSAltitudeRef",
3724 "Xmp.exif.GPSAltitude"
3726 static const guint n_keys = G_N_ELEMENTS(keys);
3733 if(!isnan(longitude) && !isnan(latitude))
3735 char long_dir =
'E', lat_dir =
'N';
3736 if(longitude < 0) long_dir =
'W';
3737 if(latitude < 0) lat_dir =
'S';
3739 longitude = fabs(longitude);
3740 latitude = fabs(latitude);
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;
3747 char *str = (
char *)g_malloc(G_ASCII_DTOSTR_BUF_SIZE);
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);
3754 xmpData[
"Xmp.exif.GPSVersionID"] =
"2.2.0.0";
3755 xmpData[
"Xmp.exif.GPSLongitude"] = long_str;
3756 xmpData[
"Xmp.exif.GPSLatitude"] = lat_str;
3761 if(!isnan(altitude))
3763 xmpData[
"Xmp.exif.GPSAltitudeRef"] = (altitude < 0) ?
"1" :
"0";
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;
3779 while(sqlite3_step(stmt) == SQLITE_ROW)
3781 int keyid = sqlite3_column_int(stmt, 0);
3794 sqlite3_finalize(stmt);
3798 std::unique_ptr<Exiv2::Value>
v(Exiv2::Value::create(Exiv2::xmpSeq));
3804 while(sqlite3_step(stmt) == SQLITE_ROW)
3806 snprintf(val,
sizeof(val),
"%d", sqlite3_column_int(stmt, 0));
3809 sqlite3_finalize(stmt);
3810 if(
v->count() > 0) xmpData.add(Exiv2::XmpKey(
"Xmp.darktable.colorlabels"),
v.get());
3829 xmpData[
"Xmp.darktable.history_current_hash"] =
value;
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;
3851 "SELECT filename, flags, raw_parameters, "
3852 " longitude, latitude, altitude, history_end, datetime_taken"
3858 if(sqlite3_step(stmt) == SQLITE_ROW)
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);
3890 xmpData[
"Xmp.exif.DateTimeOriginal"] = exif_datetime;
3893 Exiv2::XmpData::iterator pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.xmp.Rating"));
3894 if(pos != xmpData.end()) xmpData.erase(pos);
3898 if(filename) xmpData[
"Xmp.xmpMM.DerivedFrom"] = filename;
3910 std::unique_ptr<Exiv2::Value> v1(Exiv2::Value::create(Exiv2::xmpBag));
3912 std::unique_ptr<Exiv2::Value> v2(Exiv2::Value::create(Exiv2::xmpBag));
3917 for(GList *tag = tags; tag; tag = g_list_next(tag))
3919 v1->read((
char *)tag->data);
3927 if(v1->count() > 0) xmpData.add(Exiv2::XmpKey(
"Xmp.dc.subject"), v1.get());
3934 for(GList *hier = hierarchical; hier; hier = g_list_next(hier))
3936 v2->read((
char *)hier->data);
3944 if(v2->count() > 0) xmpData.add(Exiv2::XmpKey(
"Xmp.lr.hierarchicalSubject"), v2.get());
3946 hierarchical = NULL;
3949 xmpData[
"Xmp.darktable.xmp_version"] = xmp_version;
3950 xmpData[
"Xmp.darktable.raw_params"] = raw_params;
3952 xmpData[
"Xmp.darktable.auto_presets_applied"] = 1;
3954 xmpData[
"Xmp.darktable.auto_presets_applied"] = 0;
3959 xmpData[
"Xmp.darktable.iop_order_version"] = iop_order_version;
3960 if(iop_order_list) xmpData[
"Xmp.darktable.iop_order_list"] = iop_order_list;
3965 sqlite3_finalize(stmt);
3973 int stars = 1, raw_params = 0, history_end = -1;
3974 double longitude = NAN, latitude = NAN, altitude = NAN;
3975 gchar *filename = NULL;
3977 gchar *iop_order_list = NULL;
3983 "SELECT filename, flags, raw_parameters, "
3984 " longitude, latitude, altitude, history_end, datetime_taken"
3990 if(sqlite3_step(stmt) == SQLITE_ROW)
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);
4026 xmpData[
"Xmp.exif.DateTimeOriginal"] = exif_datetime;
4029 Exiv2::XmpData::iterator pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.xmp.Rating"));
4030 if(pos != xmpData.end()) xmpData.erase(pos);
4034 if(filename) xmpData[
"Xmp.xmpMM.DerivedFrom"] = filename;
4052 std::unique_ptr<Exiv2::Value> v1(Exiv2::Value::create(Exiv2::xmpBag));
4056 for(GList *tag = tags; tag; tag = g_list_next(tag))
4058 v1->read((
char *)tag->data);
4066 if(v1->count() > 0) xmpData.add(Exiv2::XmpKey(
"Xmp.dc.subject"), v1.get());
4073 std::unique_ptr<Exiv2::Value> v2(Exiv2::Value::create(Exiv2::xmpBag));
4077 for(GList *hier = hierarchical; hier; hier = g_list_next(hier))
4079 v2->read((
char *)hier->data);
4087 if(v2->count() > 0) xmpData.add(Exiv2::XmpKey(
"Xmp.lr.hierarchicalSubject"), v2.get());
4089 hierarchical = NULL;
4094 xmpData[
"Xmp.darktable.xmp_version"] = xmp_version;
4095 xmpData[
"Xmp.darktable.raw_params"] = raw_params;
4097 xmpData[
"Xmp.darktable.auto_presets_applied"] = 1;
4099 xmpData[
"Xmp.darktable.auto_presets_applied"] = 0;
4104 xmpData[
"Xmp.darktable.iop_order_version"] = iop_order_version;
4105 if(iop_order_list) xmpData[
"Xmp.darktable.iop_order_list"] = iop_order_list;
4110 sqlite3_finalize(stmt);
4114#if EXIV2_TEST_VERSION(0,27,0)
4115#define ERROR_CODE(a) (static_cast<Exiv2::ErrorCode>((a)))
4117#define ERROR_CODE(a) (a)
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__);
4133 Exiv2::XmpData xmpData;
4134 if(g_file_test(input_filename, G_FILE_TEST_EXISTS))
4136 std::string xmpPacket;
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());
4142 xmpPacket.assign(
reinterpret_cast<char *
>(buf.pData_), buf.size_);
4144 Exiv2::XmpParser::decode(xmpData, xmpPacket);
4152 g_strlcat(input_filename,
".xmp",
sizeof(input_filename));
4153 if(g_file_test(input_filename, G_FILE_TEST_EXISTS))
4155 Exiv2::XmpData sidecarXmpData;
4156 std::string xmpPacket;
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());
4162 xmpPacket.assign(
reinterpret_cast<char *
>(buf.pData_), buf.size_);
4164 Exiv2::XmpParser::decode(sidecarXmpData, xmpPacket);
4166 for(Exiv2::XmpData::const_iterator it = sidecarXmpData.begin(); it != sidecarXmpData.end(); ++it)
4177 std::string xmpPacket;
4178 if(Exiv2::XmpParser::encode(xmpPacket, xmpData,
4179 Exiv2::XmpParser::useCompactFormat | Exiv2::XmpParser::omitPacketWrapper) != 0)
4181 throw Exiv2::Error(
ERROR_CODE(1),
"[xmp_write] failed to serialize xmp data");
4183 return g_strdup(xmpPacket.c_str());
4185 catch(
const std::exception &e)
4187 std::cerr <<
"[xmp_read_blob] caught exiv2 exception '" << e.what() <<
"'\n";
4196 Exiv2::XmpData::iterator pos = xmp.findKey(Exiv2::XmpKey(
key));
4197 if (pos != xmp.end())
4200 catch(
const std::exception &e)
4209 const std::string needle =
key;
4210 for(Exiv2::XmpData::iterator
i = xmpData.begin();
i != xmpData.end();)
4212 if(
i->key().compare(0, needle.length(), needle) == 0)
4213 i = xmpData.erase(
i);
4218 catch(
const std::exception &e)
4227 Exiv2::ExifData::iterator pos = exif.findKey(Exiv2::ExifKey(
key));
4228 if (pos != exif.end())
4231 catch(
const std::exception &e)
4240 Exiv2::IptcData::iterator pos;
4241 while((pos = iptc.findKey(Exiv2::IptcKey(
key))) != iptc.end())
4244 catch(
const std::exception &e)
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__);
4265 std::unique_ptr<Exiv2::Image> img(Exiv2::ImageFactory::open(
WIDEN(filename)));
4274 std::unique_ptr<Exiv2::Image> input_image(Exiv2::ImageFactory::open(
WIDEN(input_filename)));
4275 if(input_image.get() != 0)
4278 img->setIptcData(input_image->iptcData());
4279 img->setXmpData(input_image->xmpData());
4282 catch(
const std::exception &e)
4284 std::cerr <<
"[xmp_attach] " << input_filename <<
": caught exiv2 exception '" << e.what() <<
"'\n";
4287 Exiv2::XmpData &xmpData = img->xmpData();
4291 g_strlcat(input_filename,
".xmp",
sizeof(input_filename));
4292 if(g_file_test(input_filename, G_FILE_TEST_EXISTS))
4294 Exiv2::XmpData sidecarXmpData;
4295 std::string xmpPacket;
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());
4301 xmpPacket.assign(
reinterpret_cast<char *
>(buf.pData_), buf.size_);
4303 Exiv2::XmpParser::decode(sidecarXmpData, xmpPacket);
4305 for(Exiv2::XmpData::const_iterator it = sidecarXmpData.begin(); it != sidecarXmpData.end(); ++it)
4314 static const char *keys[] = {
4315 "Xmp.tiff.Orientation"
4317 static const guint n_keys = G_N_ELEMENTS(keys);
4326 Exiv2::ExifData exifOldData;
4327 Exiv2::ExifData &exifData = img->exifData();
4330 for(Exiv2::ExifData::const_iterator
i = exifData.begin();
i != exifData.end() ; ++
i)
4332 exifOldData[
i->key()] =
i->value();
4334 img->clearExifData();
4339 Exiv2::IptcData &iptcData = img->iptcData();
4346 params->filename = input_filename;
4347 params->jobcode =
"infos";
4348 params->sequence = 0;
4349 params->imgid = imgid;
4352 for (GList *tags =
m->list; tags; tags = g_list_next(tags))
4354 gchar *tagname = (gchar *)tags->data;
4355 tags = g_list_next(tags);
4357 gchar *formula = (gchar *)tags->data;
4360 if(!(
m->flags &
DT_META_EXIF) && (formula[0] ==
'=') && g_str_has_prefix(tagname,
"Exif."))
4363 Exiv2::ExifData::const_iterator pos;
4366 exifData[tagname] = pos->value();
4372 if(result && result[0])
4374 if(g_str_has_prefix(tagname,
"Xmp."))
4379 if(!g_strcmp0(
type,
"XmpBag") || !g_strcmp0(
type,
"XmpSeq"))
4381 char *tuple = g_strrstr(result,
",");
4386 xmpData[tagname] = tuple;
4387 tuple = g_strrstr(result,
",");
4390 xmpData[tagname] = result;
4392 else if(g_str_has_prefix(tagname,
"Iptc."))
4395 if(!g_strcmp0(
type,
"String-R"))
4401 Exiv2::IptcKey
key(tagname);
4402 Exiv2::Iptcdatum id(
key);
4403 gchar **values = g_strsplit(result,
", ", 0);
4406 gchar **entry = values;
4409 char *e = g_strstrip(*entry);
4420 else iptcData[tagname] = result;
4422 else if(g_str_has_prefix(tagname,
"Exif."))
4425 if((!g_strcmp0(
type,
"Rational") || !g_strcmp0(
type,
"SRational")) &&
4426 (g_strstr_len(result, strlen(result),
"/") == NULL))
4428 float float_value = (float)std::atof(result);
4429 if(!isnan(float_value))
4432 int int_value = (int)float_value;
4434 while(fabs(float_value - int_value) > 0.000001)
4437 float_value *= 10.0;
4438 int_value = (int)float_value;
4440 result = g_strdup_printf(
"%d/%d", (
int)float_value, divisor);
4443 exifData[tagname] = result;
4451 if (g_str_has_prefix(tagname,
"Xmp."))
4453 else if (g_str_has_prefix(tagname,
"Exif."))
4455 else if (g_str_has_prefix(tagname,
"Iptc."))
4464 img->writeMetadata();
4466 catch(Exiv2::AnyError &e)
4468#if EXIV2_TEST_VERSION(0,27,0)
4469 if(e.code() == Exiv2::ErrorCode::kerTooLargeJpegSegment)
4480 img->writeMetadata();
4482 catch(
const std::exception &e2)
4484 std::cerr <<
"[dt_exif_xmp_attach_export] without history " << filename <<
": caught exiv2 exception '" << e2.what() <<
"'\n";
4491 catch(
const std::exception &e)
4493 std::cerr <<
"[dt_exif_xmp_attach_export] " << filename <<
": caught exception '" << e.what() <<
"'\n";
4498 catch(
const std::exception &e)
4500 std::cerr <<
"[dt_exif_xmp_attach_export] " << filename <<
": caught exiv2 exception '" << e.what() <<
"'\n";
4507 const char *imgpath)
4512 if(!g_file_test(imgpath, G_FILE_TEST_IS_REGULAR))
return 1;
4513 const int32_t imgid = image->
id;
4524 Exiv2::XmpData xmpData;
4525 std::string xmpPacket;
4526 char *checksum_old = NULL;
4527 if(g_file_test(filename, G_FILE_TEST_EXISTS))
4534 unsigned char *content = (
unsigned char*)
dt_read_file(filename, &end);
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);
4543 checksum_old = g_compute_checksum_for_data(G_CHECKSUM_MD5, content, end);
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));
4552 Exiv2::DataBuf buf = Exiv2::readFile(
WIDEN(filename));
4553#if EXIV2_TEST_VERSION(0,28,0)
4554 xmpPacket.assign(buf.c_str(), buf.size());
4556 xmpPacket.assign(
reinterpret_cast<char *
>(buf.pData_), buf.size_);
4558 Exiv2::XmpParser::decode(xmpData, xmpPacket);
4568 if(Exiv2::XmpParser::encode(xmpPacket, xmpData,
4569 Exiv2::XmpParser::useCompactFormat | Exiv2::XmpParser::omitPacketWrapper) != 0)
4571 throw Exiv2::Error(
ERROR_CODE(1),
"[xmp_write] failed to serialize xmp data");
4575 const char *xml_header =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
4576 gboolean write_sidecar =
TRUE;
4579 GChecksum *checksum = g_checksum_new(G_CHECKSUM_MD5);
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);
4595 FILE *fout = g_fopen(filename,
"wb");
4598 fprintf(fout,
"%s", xml_header);
4599 fprintf(fout,
"%s", xmpPacket.c_str());
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));
4612 catch(
const std::exception &e)
4614 std::cerr <<
"[dt_exif_xmp_write] " << filename <<
": caught exiv2 exception '" << e.what() <<
"'\n";
4623 Exiv2::ExifData::const_iterator pos;
4624 Exiv2::ExifData exifData;
4625 Exiv2::ExifParser::decode(exifData, data,
size);
4633 if((pos = exifData.findKey(Exiv2::ExifKey(
"Exif.Photo.ColorSpace"))) != exifData.end() && pos->size())
4635 int colorspace = pos->toLong();
4636 if(colorspace == 0x01)
4638 else if(colorspace == 0x02)
4640 else if(colorspace == 0xffff)
4642 if((pos = exifData.findKey(Exiv2::ExifKey(
"Exif.Iop.InteroperabilityIndex"))) != exifData.end()
4645 std::string interop_index = pos->toString();
4646 if(interop_index ==
"R03")
4648 else if(interop_index ==
"R98")
4656 catch(
const std::exception &e)
4658 std::string s(e.what());
4659 std::cerr <<
"[exiv2 dt_exif_get_color_space] " << s << std::endl;
4668 Exiv2::ExifData::const_iterator pos;
4669 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(data,
size));
4671 Exiv2::ExifData &exifData = image->exifData();
4675 catch(
const std::exception &e)
4677 std::string s(e.what());
4678 std::cerr <<
"[exiv2 dt_exif_get_datetime_taken] " << s << std::endl;
4684 if(log_level >= Exiv2::LogMsg::level())
4699 #if !EXIV2_TEST_VERSION(0,28,0)
4700 #ifdef HAVE_LIBEXIV2_WITH_ISOBMFF
4701 Exiv2::enableBMFF();
4706 #if !EXIV2_TEST_VERSION(0,28,0)
4707 Exiv2::XmpParser::initialize();
4710 Exiv2::XmpProperties::registerNs(
"http://darktable.sf.net/",
"darktable");
4714 Exiv2::XmpProperties::propertyList(
"lr");
4716 catch(
const std::exception &e)
4719 Exiv2::XmpProperties::registerNs(
"http://ns.adobe.com/lightroom/1.0/",
"lr");
4723 Exiv2::XmpProperties::propertyList(
"exifEX");
4725 catch(
const std::exception &e)
4728 Exiv2::XmpProperties::registerNs(
"http://cipa.jp/exif/1.0/",
"exifEX");
4735 #if !EXIV2_TEST_VERSION(0,28,0)
4736 Exiv2::XmpParser::terminate();
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
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.
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,...)
void dt_vprint(dt_debug_thread_t thread, const char *msg,...)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
@ DT_DEBUG_CAMERA_SUPPORT
float dt_boundingbox_t[4]
static void dt_free_gpointer(gpointer ptr)
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...
static const dt_aligned_pixel_simd_t sign
static const dt_aligned_pixel_simd_t value
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
sqlite3 * dt_database_get(const dt_database_t *db)
void dt_database_rollback_transaction(const struct dt_database_t *db)
#define dt_database_start_transaction(db)
#define dt_database_release_transaction(db)
gboolean dt_datetime_img_to_exif(char *exif, const size_t exif_size, const dt_image_t *img)
void dt_datetime_now_to_exif(char *exif)
void dt_datetime_add_subsec_to_exif(char *exif, const size_t exif_size, const char *subsec)
gboolean dt_datetime_unix_to_img(dt_image_t *img, const time_t *unix)
gboolean dt_datetime_gtimespan_to_exif(char *sdt, const size_t sdt_size, const GTimeSpan gts)
GTimeSpan dt_datetime_gdatetime_to_gtimespan(GDateTime *gdt)
void dt_datetime_exif_to_img(dt_image_t *img, const char *exif)
#define DT_DATETIME_LENGTH
#define DT_DATETIME_EXIF_LENGTH
#define DT_DEBUG_SQLITE3_BIND_BLOB(a, b, c, d, e)
#define DT_DEBUG_SQLITE3_PREPARE_V2(a, b, c, d, e)
#define DT_DEBUG_SQLITE3_BIND_TEXT(a, b, c, d, e)
#define DT_DEBUG_SQLITE3_BIND_INT(a, b, c)
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)
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
static const char * _exif_get_exiv2_tag_type(const char *tagname)
unsigned char * dt_exif_xmp_decode(const char *input, const int len, int *output_len)
int dt_exif_xmp_attach_export(const int32_t imgid, const char *filename, void *metadata)
static void dt_remove_xmp_key(Exiv2::XmpData &xmp, const char *key)
dt_colorspaces_color_profile_type_t dt_exif_get_color_space(const uint8_t *data, size_t size)
int dt_exif_read_from_blob(dt_image_t *img, uint8_t *blob, const int size)
static void dt_remove_known_keys(Exiv2::XmpData &xmp)
static void free_history_entry(gpointer data)
void dt_exif_get_datetime_taken(const uint8_t *data, size_t size, char *datetime_taken)
#define FIND_IPTC_TAG(key)
#define FIND_XMP_TAG(key)
static void read_xmp_timestamps(Exiv2::XmpData &xmpData, dt_image_t *img, const int xmp_version)
static void dt_set_xmp_exif_geotag(Exiv2::XmpData &xmpData, double longitude, double latitude, double altitude)
static void dt_set_xmp_dt_history(Exiv2::XmpData &xmpData, const int32_t imgid, int history_end)
static void dt_remove_xmp_keys(Exiv2::XmpData &xmp, const char *keys[], unsigned int n_keys)
void dt_exif_set_exiv2_taglist()
static GList * read_masks_v3(Exiv2::XmpData &xmpData, const char *filename, const int version)
static int _illu_to_temp(dt_dng_illuminant_t illu)
int dt_exif_xmp_write_with_imgpath(const dt_image_t *image, const char *filename, const char *imgpath)
int dt_exif_read(dt_image_t *img, const char *path)
GTimeSpan _convert_unix_to_gtimespan(const time_t unix)
static void dt_exif_log_handler(int log_level, const char *message)
#define read_metadata_threadsafe(image)
static void _get_xmp_tags(const char *prefix, GList **taglist)
static GList * read_history_v1(const std::string &xmpPacket, const char *filename, const int superold)
static bool _check_usercrop(Exiv2::ExifData &exifData, dt_image_t *img)
char * dt_exif_xmp_encode_internal(const unsigned char *input, const int len, int *output_len, gboolean do_compress)
static void print_history_entry(history_entry_t *entry) __attribute__((unused))
#define FIND_EXIF_TAG(key)
int dt_exif_xmp_read(dt_image_t *img, const char *filename, const int history_only)
static bool dt_exif_read_xmp_tag(Exiv2::XmpData &xmpData, Exiv2::XmpData::iterator *pos, string key)
static bool _exif_decode_exif_data(dt_image_t *img, Exiv2::ExifData &exifData)
static const char * _get_exiv2_type(const int type)
char * dt_exif_xmp_encode(const unsigned char *input, const int len, int *output_len)
static gboolean _check_dng_opcodes(Exiv2::ExifData &exifData, dt_image_t *img)
static void dt_remove_xmp_exif_geotag(Exiv2::XmpData &xmpData)
int dt_exif_get_thumbnail(const char *path, uint8_t **buffer, size_t *size, char **mime_type, int *width, int *height, int min_width)
void dt_exif_img_check_additional_tags(dt_image_t *img, const char *filename)
static void _find_exif_model(Exiv2::ExifData &exifData, Exiv2::ExifData::const_iterator pos, char *model, const size_t m_size)
static void add_mask_entry_to_db(int32_t imgid, mask_entry_t *entry)
static void dt_strlcpy_to_utf8(char *dest, size_t dest_max, Exiv2::ExifData::const_iterator &pos, Exiv2::ExifData &exifData)
static bool _exif_read_exif_tag(Exiv2::ExifData &exifData, Exiv2::ExifData::const_iterator *pos, string key)
#define DT_XMP_EXIF_VERSION
static void _remove_xmp_keys(Exiv2::XmpData &xmpData, const char *key)
const char * dt_xmp_keys[]
static void _find_exif_maker(Exiv2::ExifData &exifData, Exiv2::ExifData::const_iterator pos, char *maker, const size_t m_size)
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)
static void dt_remove_exif_key(Exiv2::ExifData &exif, const char *key)
static bool dt_exif_read_iptc_tag(Exiv2::IptcData &iptcData, Exiv2::IptcData::const_iterator *pos, string key)
static void dt_remove_exif_keys(Exiv2::ExifData &exif, const char *keys[], unsigned int n_keys)
char * dt_exif_xmp_read_string(const int32_t imgid)
static void _exif_xmp_read_data_export(Exiv2::XmpData &xmpData, const int32_t imgid, dt_export_metadata_t *metadata)
static GList * exiv2_taglist
static bool _exif_decode_xmp_data(dt_image_t *img, Exiv2::XmpData &xmpData, int version, bool exif_read)
static void _find_datetime_taken(Exiv2::ExifData &exifData, Exiv2::ExifData::const_iterator pos, char *exif_datetime_taken)
static void _exif_import_tags(dt_image_t *img, Exiv2::XmpData::iterator &pos)
int _get_max_multi_priority(GList *history, const char *operation)
static void _exif_xmp_append_history_hash(Exiv2::XmpData &xmpData, const int32_t imgid, const dt_image_t *image)
static void dt_remove_iptc_key(Exiv2::IptcData &iptc, const char *key)
static GList * read_history_v2(Exiv2::XmpData &xmpData, const char *filename)
static GHashTable * read_masks(Exiv2::XmpData &xmpData, const char *filename, const int version)
static void add_non_clone_mask_entries_to_db(gpointer key, gpointer value, gpointer user_data)
const GList * dt_exif_get_exiv2_taglist()
int dt_exif_write_blob(uint8_t *blob, uint32_t size, const char *path, const int compressed)
#define COMPRESS_THRESHOLD
static void _exif_xmp_read_data(Exiv2::XmpData &xmpData, const int32_t imgid, const dt_image_t *image)
static bool _exif_decode_iptc_data(dt_image_t *img, Exiv2::IptcData &iptcData)
void free_mask_entry(gpointer data)
static const guint dt_xmp_keys_n
static void set_xmp_timestamps(Exiv2::XmpData &xmpData, const int32_t imgid)
static void dt_set_xmp_dt_metadata(Exiv2::XmpData &xmpData, const int32_t imgid, const gboolean export_flag)
static void add_mask_entries_to_db(int32_t imgid, GHashTable *mask_entries, int mask_id)
static void dt_remove_exif_geotag(Exiv2::ExifData &exifData)
@ DT_LS_DayWhiteFluorescent
@ DT_LS_CoolWhiteFluorescent
@ DT_LS_WarmWhiteFluorescent
@ DT_LS_DaylightFluorescent
@ DT_LS_ISOStudioTungsten
@ DT_IMAGE_COLORSPACE_ADOBE_RGB
@ DT_IMAGE_COLORSPACE_SRGB
static dt_image_orientation_t dt_image_orientation_to_flip_bits(const int orient)
@ DT_IMAGE_NO_LEGACY_PRESETS
@ DT_IMAGE_HAS_ADDITIONAL_DNG_TAGS
@ DT_IMAGE_AUTO_PRESETS_APPLIED
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.
GList * dt_ioppr_get_iop_order_list(int32_t imgid, gboolean sorted)
Load the order list for an image from the DB.
gboolean dt_ioppr_has_multiple_instances(GList *iop_order_list)
Detect whether multiple instances are grouped for a non-custom order.
GList * dt_ioppr_get_iop_order_list_version(dt_iop_order_t version)
Return the built-in order list for a given version.
gint dt_sort_iop_list_by_order_f(gconstpointer a, gconstpointer b)
Compare two list nodes holding modules by iop_order.
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.
char * dt_ioppr_serialize_text_iop_order_list(GList *iop_order_list)
Serialize an order list to a text representation.
GList * dt_ioppr_deserialize_text_iop_order_list(const char *buf)
Deserialize an order list from a text representation.
dt_iop_order_t dt_ioppr_get_iop_order_version(const int32_t imgid)
Fetch the IOP order version stored for an image.
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.
float *const restrict const size_t k
static void mat3mul(float *const __restrict__ dest, const float *const __restrict__ m1, const float *const __restrict__ m2)
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
@ DT_SIGNAL_TAG_CHANGED
This signal is raised when a tag is added/deleted/changed
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
dt_pthread_mutex_t exiv2_threadsafe
const struct dt_database_t * db
struct dt_control_signal_t * signals
struct dt_image_cache_t * image_cache
GTimeSpan export_timestamp
float exif_focus_distance
dt_boundingbox_t usercrop
dt_image_orientation_t orientation
GTimeSpan change_timestamp
GTimeSpan print_timestamp
float d65_color_matrix[9]
dt_image_colorspace_t colorspace
dt_image_raw_parameters_t legacy_flip
char filename[DT_MAX_FILENAME_LEN]
union dt_iop_order_entry_t::@8 o
unsigned char * blendop_params
unsigned char * mask_points
typedef double((*spd)(unsigned long int wavelength, double TempK))
static const char * mask_name
gboolean dt_util_gps_elevation_to_number(const double r_1, const double r_2, char sign, double *result)
char * dt_read_file(const char *const filename, size_t *filesize)
double dt_util_gps_string_to_number(const gchar *input)
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)
gchar * dt_util_foo_to_utf8(const char *string)
gchar * dt_util_dstrcat(gchar *str, const gchar *format,...)