73#define __STDC_FORMAT_MACROS
98#include <exiv2/exiv2.hpp>
100#if defined(_WIN32) && defined(EXV_UNICODE_PATH)
101 #define WIDEN(s) pugi::as_wide(s)
106#include <pugixml.hpp>
135#define DT_XMP_EXIF_VERSION 5
137#if EXIV2_TEST_VERSION(0,28,0)
138#define AnyError Error
139#define toLong toInt64
212 const Exiv2::XmpPropertyInfo *pl = Exiv2::XmpProperties::propertyList(prefix);
215 for (
int i = 0; pl[
i].name_ != 0; ++
i)
218 *taglist = g_list_prepend(*taglist, tag);
272 const Exiv2::GroupInfo *groupList = Exiv2::ExifTags::groupList();
275 while(groupList->tagList_)
277 const std::string groupName(groupList->groupName_);
278 if(groupName.substr(0, 3) !=
"Sub" &&
279 groupName !=
"Image2" &&
280 groupName !=
"Image3" &&
281 groupName !=
"Thumbnail"
284 const Exiv2::TagInfo *tagInfo = groupList->tagList_();
285 while(tagInfo->tag_ != 0xFFFF)
296 const Exiv2::DataSet *iptcEnvelopeList = Exiv2::IptcDataSets::envelopeRecordList();
297 while(iptcEnvelopeList->number_ != 0xFFFF)
299 char *tag =
dt_util_dstrcat(NULL,
"Iptc.Envelope.%s,%s%s", iptcEnvelopeList->name_,
301 iptcEnvelopeList->repeatable_ ?
"-R" :
"");
306 const Exiv2::DataSet *iptcApplication2List = Exiv2::IptcDataSets::application2RecordList();
307 while(iptcApplication2List->number_ != 0xFFFF)
309 char *tag =
dt_util_dstrcat(NULL,
"Iptc.Application2.%s,%s%s", iptcApplication2List->name_,
311 iptcApplication2List->repeatable_ ?
"-R" :
"");
313 iptcApplication2List++;
349 catch (Exiv2::AnyError& e)
351 std::string s(e.what());
352 std::cerr <<
"[exiv2 taglist] " << s << std::endl;
368 char *
t = (
char *)tag->data;
369 if(g_str_has_prefix(
t, tagname) &&
t[strlen(tagname)] ==
',')
372 t += strlen(tagname) + 1;
389#define read_metadata_threadsafe(image) \
392 image->readMetadata(); \
400 = {
"Xmp.dc.subject",
"Xmp.lr.hierarchicalSubject",
"Xmp.darktable.colorlabels",
"Xmp.darktable.history",
401 "Xmp.darktable.history_modversion",
"Xmp.darktable.history_enabled",
"Xmp.darktable.history_end",
402 "Xmp.darktable.iop_order_version",
"Xmp.darktable.iop_order_list",
403 "Xmp.darktable.history_operation",
"Xmp.darktable.history_params",
"Xmp.darktable.blendop_params",
404 "Xmp.darktable.blendop_version",
"Xmp.darktable.multi_priority",
"Xmp.darktable.multi_name",
405 "Xmp.darktable.iop_order",
406 "Xmp.darktable.xmp_version",
"Xmp.darktable.raw_params",
"Xmp.darktable.auto_presets_applied",
407 "Xmp.darktable.mask_id",
"Xmp.darktable.mask_type",
"Xmp.darktable.mask_name",
408 "Xmp.darktable.masks_history",
"Xmp.darktable.mask_num",
"Xmp.darktable.mask_points",
409 "Xmp.darktable.mask_version",
"Xmp.darktable.mask",
"Xmp.darktable.mask_nb",
"Xmp.darktable.mask_src",
410 "Xmp.darktable.history_basic_hash",
"Xmp.darktable.history_auto_hash",
"Xmp.darktable.history_current_hash",
411 "Xmp.darktable.import_timestamp",
"Xmp.darktable.change_timestamp",
412 "Xmp.darktable.export_timestamp",
"Xmp.darktable.print_timestamp",
413 "Xmp.acdsee.notes",
"Xmp.darktable.version_name",
414 "Xmp.dc.creator",
"Xmp.dc.publisher",
"Xmp.dc.title",
"Xmp.dc.description",
"Xmp.dc.rights",
415 "Xmp.xmpMM.DerivedFrom" };
422 Exiv2::ExifData &exifData)
424 std::string str = pos->print(&exifData);
426 char *s = g_locale_to_utf8(str.c_str(), str.length(), NULL, NULL, NULL);
429 g_strlcpy(dest, s, dest_max);
434 g_strlcpy(dest, str.c_str(), dest_max);
445 Exiv2::XmpData::iterator pos = xmp.findKey(Exiv2::XmpKey(
dt_xmp_keys[
i]));
447 while(pos != xmp.end())
449 std::string
key = pos->key();
450 const char *ckey =
key.c_str();
451 size_t len =
key.size();
453 if(!(g_str_has_prefix(ckey,
dt_xmp_keys[
i]) && (ckey[len] ==
'[' || ckey[len] ==
'\0')))
455 pos = xmp.erase(pos);
462 for(
unsigned int i = 0;
i < n_keys;
i++)
466 Exiv2::ExifData::iterator pos;
467 while((pos = exif.findKey(Exiv2::ExifKey(keys[
i]))) != exif.end())
470 catch(Exiv2::AnyError &e)
482 for(
unsigned int i = 0;
i < n_keys;
i++)
486 Exiv2::XmpData::iterator pos;
487 while((pos = xmp.findKey(Exiv2::XmpKey(keys[
i]))) != xmp.end())
490 catch(Exiv2::AnyError &e)
504 return (*pos = xmpData.findKey(Exiv2::XmpKey(
key))) != xmpData.end() && (*pos)->size();
506 catch(Exiv2::AnyError &e)
508 std::string s(e.what());
509 std::cerr <<
"[exiv2 read_xmp_tag] " << s << std::endl;
513#define FIND_XMP_TAG(key) dt_exif_read_xmp_tag(xmpData, &pos, key)
524 imgs = g_list_prepend(imgs, GINT_TO_POINTER(img->
id));
527 Exiv2::XmpData::iterator pos;
533 if(version == -1 || version > 0)
541 char *
value = strdup(pos->toString().c_str());
544 while(!strncmp(
value,
"lang=", 5) || !strncmp(
value,
"charset=", 8))
557 const int stars = pos->toLong();
566 std::string label = pos->toString();
569 else if(label ==
"Yellow")
571 else if(label ==
"Green")
573 else if(label ==
"Blue")
575 else if(label ==
"Purple")
582 const int cnt = pos->count();
583 for(
int i = 0;
i < cnt;
i++)
614 Exiv2::XmpData::const_iterator ref = xmpData.findKey(Exiv2::XmpKey(
"Xmp.exif.GPSAltitudeRef"));
615 if(ref != xmpData.end() && ref->size())
617 std::string sign_str = ref->toString();
618 const char *
sign = sign_str.c_str();
619 double elevation = 0.0;
629 char *lens = strdup(pos->toString().c_str());
631 if(strncmp(lens,
"lang=", 5) == 0)
633 lens = strchr(lens,
' ');
645 char *datetime = strdup(pos->toString().c_str());
658 catch(Exiv2::AnyError &e)
666 std::string s(e.what());
667 std::cerr <<
"[exiv2 _exif_decode_xmp_data] " << img->
filename <<
": " << s << std::endl;
676 return (*pos = iptcData.findKey(Exiv2::IptcKey(
key))) != iptcData.end() && (*pos)->size();
678 catch(Exiv2::AnyError &e)
680 std::string s(e.what());
681 std::cerr <<
"[exiv2 read_iptc_tag] " << s << std::endl;
685#define FIND_IPTC_TAG(key) dt_exif_read_iptc_tag(iptcData, &pos, key)
694 Exiv2::IptcData::const_iterator pos;
695 iptcData.sortByKey();
697 if((pos = iptcData.findKey(Exiv2::IptcKey(
"Iptc.Application2.Keywords"))) != iptcData.end())
699 while(pos != iptcData.end())
701 std::string
key = pos->key();
702 if(g_strcmp0(
key.c_str(),
"Iptc.Application2.Keywords"))
break;
703 std::string str = pos->print();
715 std::string str = pos->print();
720 std::string str = pos->print();
725 std::string str = pos->print();
730 std::string str = pos->print();
735 std::string str = pos->print();
741 GString *datetime = g_string_new(pos->toString().c_str());
743 datetime = g_string_append(datetime,
"T");
746 gchar *time = g_strdup(pos->toString().c_str());
747 datetime = g_string_append(datetime, time);
751 datetime = g_string_append(datetime,
"00:00:00");
754 g_string_free(datetime,
TRUE);
759 catch(Exiv2::AnyError &e)
761 std::string s(e.what());
762 std::cerr <<
"[exiv2 _exif_decode_iptc_data] " << img->
filename <<
": " << s << std::endl;
768 Exiv2::ExifData::const_iterator *pos,
string key)
772 return (*pos = exifData.findKey(Exiv2::ExifKey(
key)))
773 != exifData.end() && (*pos)->size();
775 catch(Exiv2::AnyError &e)
777 std::string s(e.what());
778 std::cerr <<
"[exiv2 read_exif_tag] " << s << std::endl;
782#define FIND_EXIF_TAG(key) _exif_read_exif_tag(exifData, &pos, key)
790 Exiv2::ExifData::const_iterator pos =
791 exifData.findKey(Exiv2::ExifKey(
"Exif.SubImage1.0xc7b5"));
794 if(pos == exifData.end())
795 pos = exifData.findKey(Exiv2::ExifKey(
"Exif.Image.0xc7b5"));
796 if(pos != exifData.end() && pos->count() == 4 && pos->size())
799 for(
int i = 0;
i < 4;
i++) crop[
i] = pos->toFloat(
i);
804 && (crop[2] - crop[0] > 0.05f)
805 && (crop[3] - crop[1] > 0.05f))
816 gboolean has_opcodes =
FALSE;
817 Exiv2::ExifData::const_iterator pos = exifData.findKey(Exiv2::ExifKey(
"Exif.SubImage1.OpcodeList2"));
819 if(pos == exifData.end())
820 pos = exifData.findKey(Exiv2::ExifKey(
"Exif.Image.OpcodeList2"));
821 if(pos != exifData.end())
823 uint8_t *data = (uint8_t *)g_malloc(pos->size());
824 pos->copy(data, Exiv2::invalidByteOrder);
840 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(
WIDEN(filename)));
841 assert(image.get() != 0);
843 Exiv2::ExifData &exifData = image->exifData();
844 if(!exifData.empty())
852 catch(Exiv2::AnyError &e)
854 std::string s(e.what());
855 std::cerr <<
"[exiv2 reading DefaultUserCrop] " << filename <<
": " << s << std::endl;
861 Exiv2::ExifData::const_iterator pos,
862 char *exif_datetime_taken)
878 *exif_datetime_taken =
'\0';
883 Exiv2::ExifData::const_iterator pos,
897 for(
char *c =
maker + m_size - 1; c >
maker; c--)
898 if(*c !=
' ' && *c !=
'\0')
906 Exiv2::ExifData::const_iterator pos,
919 for(
char *c =
model + m_size - 1; c >
model; c--)
920 if(*c !=
' ' && *c !=
'\0')
932 Exiv2::ExifData::const_iterator pos;
941 if((pos = Exiv2::exposureTime(exifData)) != exifData.end() && pos->size())
958 if((pos = Exiv2::fNumber(exifData)) != exifData.end() && pos->size())
968 if((pos = Exiv2::isoSpeed(exifData)) != exifData.end() && pos->size())
971 if(strcmp(pos->key().c_str(),
"Exif.Photo.ISOSpeedRatings") == 0)
973 int isofield = pos->count() > 1 ? 1 : 0;
974 img->
exif_iso = pos->toFloat(isofield);
978 std::string str = pos->print();
979 img->
exif_iso = (float)std::atof(str.c_str());
987 std::string str = pos->print();
988 img->
exif_iso = (float)std::atof(str.c_str());
998 if((pos = Exiv2::focalLength(exifData)) != exifData.end() && pos->size())
1002 if (pos->key() ==
"Exif.Canon.FocalLength" && pos->count() == 4)
1011 const float focal_length_35mm = pos->toFloat();
1022 float x_resolution = pos->toFloat();
1023 float y_resolution = 0.0f;
1025 y_resolution = pos->toFloat();
1028 res_unit = pos->toLong();
1031 x_resolution /= 25.4f;
1032 y_resolution /= 25.4f;
1037 x_resolution /= 10.0f;
1038 y_resolution /= 10.0f;
1040 guint image_width = 0;
1041 guint image_height = 0;
1051 image_width = pos->toLong();
1053 image_height = pos->toLong();
1058 if(image_width == 0 &&
FIND_EXIF_TAG(
"Exif.SubImage1.NewSubfileType"))
1060 if(pos->toLong() == 0)
1063 image_width = pos->toLong();
1065 image_height = pos->toLong();
1071 if(image_width == 0)
1074 image_width = pos->toLong();
1076 image_height = pos->toLong();
1079 const float x_size_mm = (float)image_width / x_resolution;
1080 const float y_size_mm = (float)image_height / y_resolution;
1081 if(image_width && image_height)
1083 const float sensor_diagonal = dt_fast_hypotf(x_size_mm, y_size_mm);
1084 const float fullframe_diagonal = dt_fast_hypotf(36.0f, 24.0f);
1085 img->
exif_crop = fullframe_diagonal / sensor_diagonal;
1096 snprintf(tagname,
sizeof(tagname),
"darktable|mode|exif-crop");
1109 if(Exiv2::testVersion(0, 27, 4) &&
FIND_EXIF_TAG(
"Exif.NikonLd4.LensID") && pos->toLong() != 0)
1113#if EXIV2_TEST_VERSION(0, 28, 0)
1116 float value = pos->toFloat();
1117 if(Exiv2::testVersion(0, 28, 1))
value /= 256.0f;
1119 pos = exifData.end();
1120 for(
auto it = exifData.begin(); it != exifData.end(); it++)
1122 if(it->key() ==
"Exif.NikonLd4.FocusDistance") pos = it;
1124 if(pos != exifData.end() && pos->size())
1126 float value = pos->toFloat();
1132 || (Exiv2::testVersion(0, 27, 4) &&
FIND_EXIF_TAG(
"Exif.NikonLd4.FocusDistance")))
1134 float value = pos->toFloat();
1155 int nominator = pos->toRational(0).first;
1160 const float FocusDistanceUpper = pos->toFloat();
1161 if(FocusDistanceUpper <= 0.0f || (
int)FocusDistanceUpper >= 0xffff)
1170 const float FocusDistanceLower = pos->toFloat();
1171 if(FocusDistanceLower > 0.0f && (
int)FocusDistanceLower < 0xffff)
1183 else if((pos = Exiv2::subjectDistance(exifData)) != exifData.end() && pos->size())
1187 else if(Exiv2::testVersion(0,27,2) &&
FIND_EXIF_TAG(
"Exif.Sony2Fp.FocusPosition2"))
1189 const float focus_position = pos->toFloat();
1191 if (focus_position &&
FIND_EXIF_TAG(
"Exif.Photo.FocalLengthIn35mmFilm")) {
1192 const float focal_length_35mm = pos->toFloat();
1195 img->
exif_focus_distance = (pow(2, focus_position / 16 - 5) + 1) * focal_length_35mm / 1000;
1211 if(
FIND_EXIF_TAG(
"Exif.Thumbnail.PhotometricInterpretation") && (32803 == pos->toLong())
1220 Exiv2::ExifData::const_iterator ref = exifData.findKey(Exiv2::ExifKey(
"Exif.GPSInfo.GPSLatitudeRef"));
1221 if(ref != exifData.end() && ref->size() && pos->count() == 3)
1223 std::string sign_str = ref->toString();
1224 const char *
sign = sign_str.c_str();
1225 double latitude = 0.0;
1227 pos->toRational(1).first, pos->toRational(1).second,
1228 pos->toRational(2).first, pos->toRational(2).second,
sign[0], &latitude))
1235 Exiv2::ExifData::const_iterator ref = exifData.findKey(Exiv2::ExifKey(
"Exif.GPSInfo.GPSLongitudeRef"));
1236 if(ref != exifData.end() && ref->size() && pos->count() == 3)
1238 std::string sign_str = ref->toString();
1239 const char *
sign = sign_str.c_str();
1240 double longitude = 0.0;
1242 pos->toRational(1).first, pos->toRational(1).second,
1243 pos->toRational(2).first, pos->toRational(2).second,
sign[0], &longitude))
1250 Exiv2::ExifData::const_iterator ref = exifData.findKey(Exiv2::ExifKey(
"Exif.GPSInfo.GPSAltitudeRef"));
1251 if(ref != exifData.end() && ref->size())
1253 std::string sign_str = ref->toString();
1254 const char *
sign = sign_str.c_str();
1255 double elevation = 0.0;
1263 && pos->toLong() != 61182
1264 && pos->toLong() != 0
1265 && pos->toLong() != 65535)
1286 if(std::string::npos == lens.find_first_not_of(
" 1234567890"))
1300 fprintf(stderr,
"[exif] Warning: lens \"%s\" unknown as \"%s\"\n", img->
exif_lens, lens.c_str());
1303 else if(Exiv2::testVersion(0,27,4) &&
FIND_EXIF_TAG(
"Exif.NikonLd4.LensID") && pos->toLong() == 0)
1311 else if((pos = Exiv2::lensName(exifData)) != exifData.end() && pos->size())
1317 if(g_str_has_prefix(img->
exif_lens,
"RF"))
1321 pretty = g_strconcat(
"Canon RF-S ", &img->
exif_lens[4], (
char *)NULL);
1323 pretty = g_strconcat(
"Canon RF ", &img->
exif_lens[2], (
char *)NULL);
1329 if(g_str_has_prefix(img->
exif_lens,
"NIKKOR") || g_str_has_prefix(img->
exif_lens,
"TAMRON"))
1331 for(
size_t i = 1;
i <= 5; ++
i)
1339 if(std::string::npos == lens.find_first_not_of(
" (1234567890)")
1347 if ( (pos=exifData.findKey(Exiv2::ExifKey(
"Exif.Photo.Flash")))
1348 != exifData.end() && pos->size())
1350 uf_strlcpy_to_utf8(uf->conf->flashText, max_name, pos, exifData);
1353 if ( (pos=exifData.findKey(Exiv2::ExifKey(
"Exif.Photo.WhiteBalance")))
1354 != exifData.end() && pos->size())
1356 uf_strlcpy_to_utf8(uf->conf->whiteBalanceText, max_name, pos, exifData);
1366 std::string str = pos->print(&exifData);
1371 std::string str = pos->print(&exifData);
1378 std::string str = pos->print(&exifData);
1379 Exiv2::CommentValue
value(str);
1380 std::string str2 =
value.comment();
1381 if(str2 !=
"binary comment")
1386 std::string str = pos->print(&exifData);
1392 std::string str = pos->print(&exifData);
1398 const int stars = pos->toLong();
1403 const int stars = pos->toLong() * 5. / 100;
1411 float colmatrix[3][12];
1412 colmatrix[0][0] = colmatrix[1][0] = colmatrix[2][0] = NAN;
1421 const float correctmat[13][9] = {
1422 { 0.9555766, -0.0230393, 0.0631636, -0.0282895, 1.0099416, 0.0210077, 0.0122982, -0.0204830,
1424 { 0.9726856, -0.0135482, 0.0361731, -0.0167463, 1.0049102, 0.0120598, 0.0070026, -0.0116372,
1426 { 1.0206905, 0.0091588, -0.0228796, 0.0115005, 0.9984917, -0.0076762, -0.0043619, 0.0072053,
1428 { 0.8446965, -0.1179225, 0.3948108, -0.1366303, 1.1041226, 0.1291718, 0.0798489, -0.1348999,
1430 { 0.9415037, -0.0321240, 0.0584672, -0.0428238, 1.0250998, 0.0203309, 0.0101511, -0.0161170,
1432 { 0.9904476, -0.0071683, -0.0116156, -0.0123712, 1.0155950, -0.0029282, -0.0035635, 0.0067697,
1434 { 0.9212269, -0.0449128, 0.1211620, -0.0553723, 1.0277243, 0.0403563, 0.0235086, -0.0391019,
1438 { 0.8663030, -0.0913083, 0.2771784, -0.1090504, 1.0746895, 0.0913841, 0.0550856, -0.0924636,
1440 { 1.0096114, 0.0061501, 0.0068113, 0.0102539, 0.9888663, 0.0015575, 0.0023119, -0.0044823,
1442 { 0.9554129, -0.0231280, 0.0637169, -0.0283629, 1.0099053, 0.0211824, 0.0124188, -0.0206922,
1444 { 0.9147843, -0.0492842, 0.1202810, -0.0622085, 1.034984, 0.0404480, 0.0228014, -0.0375807,
1446 { 0.8805388, -0.0774890, 0.2293784, -0.0932136, 1.0589267, 0.0757827, 0.0453660, -0.0760107,
1448 { 0.8488316, -0.1107439, 0.3471428, -0.1310107, 1.0986874, 0.1141548, 0.0694025, -0.1167541,
1452 Exiv2::ExifData::const_iterator cm1_pos = exifData.findKey(Exiv2::ExifKey(
"Exif.Image.ColorMatrix1"));
1453 if((cm1_pos != exifData.end()) && (cm1_pos->count() == 9))
1455 for(
int i = 0;
i < 9;
i++) colmatrix[0][
i] = cm1_pos->toFloat(
i);
1460 Exiv2::ExifData::const_iterator cm2_pos = exifData.findKey(Exiv2::ExifKey(
"Exif.Image.ColorMatrix2"));
1461 if((cm2_pos != exifData.end()) && (cm2_pos->count() == 9))
1463 for(
int i = 0;
i < 9;
i++) colmatrix[1][
i] = cm2_pos->toFloat(
i);
1469#if EXIV2_TEST_VERSION(0,27,4)
1470 Exiv2::ExifData::const_iterator cm3_pos = exifData.findKey(Exiv2::ExifKey(
"Exif.Image.ColorMatrix3"));
1471 if((cm3_pos != exifData.end()) && (cm3_pos->count() == 9))
1473 for(
int i = 0;
i < 9;
i++) colmatrix[2][
i] = cm3_pos->toFloat(
i);
1482 int delta_min = D65temp;
1485 for(
int i = 0;
i < 3; ++
i)
1488 int delta_cur = abs(temp_cur - D65temp);
1489 if((temp_cur > sel_temp) && (delta_cur <= delta_min))
1492 sel_temp = temp_cur;
1493 delta_min = delta_cur;
1500 for(
int i = 0;
i < 3; ++
i)
1512 fprintf(stderr,
"[exif] `%s` dng illuminant %i (%iK) selected from ", img->
filename, illu[sel_illu], sel_temp);
1513 for(
int i = 0;
i < 3;
i++)
1514 fprintf(stderr,
" -- [%i] %i (%iK)",
i + 1, illu[
i],
_illu_to_temp(illu[
i]));
1515 fprintf(stderr,
"\n");
1525 switch(illu[sel_illu])
1578 fprintf(stderr,
"[exif] did not find a proper dng correction matrix for illuminant %i\n", illu[sel_illu]);
1593 format = pos->toLong();
1595 format = pos->toLong();
1598 bps = pos->toLong();
1600 bps = pos->toLong();
1603 spp = pos->toLong();
1605 spp = pos->toLong();
1607 if(
FIND_EXIF_TAG(
"Exif.SubImage1.PhotometricInterpretation"))
1608 phi = pos->toLong();
1609 else if(
FIND_EXIF_TAG(
"Exif.Image.PhotometricInterpretation"))
1610 phi = pos->toLong();
1612 if((format == 3) && (bps >= 16) && ((phi == 32803) || (phi == 34892)))
1615 if((spp == 1) && (phi == 34892))
1632 int colorspace = pos->toLong();
1633 if(colorspace == 0x01)
1635 else if(colorspace == 0x02)
1637 else if(colorspace == 0xffff)
1641 std::string interop_index = pos->toString();
1642 if(interop_index ==
"R03")
1644 else if(interop_index ==
"R98")
1651 if(
FIND_EXIF_TAG(
"Exif.Sony2.LensID") && pos->toLong() != 65535 && pos->print().find(
'|') == std::string::npos)
1665 std::string str = pos->print(&exifData);
1673 catch(Exiv2::AnyError &e)
1675 std::string s(e.what());
1676 std::cerr <<
"[exiv2 _exif_decode_exif_data] " << img->
filename <<
": " << s << std::endl;
1686 Exiv2::ExifData exifData;
1687 Exiv2::ExifParser::decode(exifData, blob,
size);
1691 catch(Exiv2::AnyError &e)
1693 std::string s(e.what());
1694 std::cerr <<
"[exiv2 dt_exif_read_from_blob] " << img->
filename <<
": " << s << std::endl;
1706 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(
WIDEN(path)));
1707 assert(image.get() != 0);
1712 Exiv2::PreviewManager loader(*image);
1713 Exiv2::PreviewPropertiesList list = loader.getPreviewProperties();
1721 Exiv2::PreviewProperties selected = list.back();
1724 Exiv2::PreviewImage preview = loader.getPreviewImage(selected);
1725 const unsigned char *tmp = preview.pData();
1726 size_t _size = preview.size();
1729 *
width = preview.width();
1730 *
height = preview.height();
1731 *mime_type = strdup(preview.mimeType().c_str());
1732 *buffer = (uint8_t *)malloc(_size);
1734 std::cerr <<
"[exiv2 dt_exif_get_thumbnail] couldn't allocate memory for thumbnail for " << path << std::endl;
1738 memcpy(*buffer, tmp, _size);
1742 catch(Exiv2::AnyError &e)
1744 std::string s(e.what());
1745 std::cerr <<
"[exiv2 dt_exif_get_thumbnail] " << path <<
": " << s << std::endl;
1762 const char *ext = g_strrstr(path,
".");
1768 struct stat statbuf;
1770 if(!stat(path, &statbuf))
1777 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(
WIDEN(path)));
1778 assert(image.get() != 0);
1783 Exiv2::ExifData &exifData = image->exifData();
1784 if(!exifData.empty())
1792 Exiv2::IptcData &iptcData = image->iptcData();
1796 Exiv2::XmpData &xmpData = image->xmpData();
1797 if(!xmpData.empty())
1803 img->
height = image->pixelHeight();
1804 img->
width = image->pixelWidth();
1808 catch(Exiv2::AnyError &e)
1810 std::string s(e.what());
1811 std::cerr <<
"[exiv2 dt_exif_read] " << path <<
": " << s << std::endl;
1820 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(
WIDEN(path)));
1821 assert(image.get() != 0);
1823 Exiv2::ExifData &imgExifData = image->exifData();
1824 Exiv2::ExifData blobExifData;
1825 Exiv2::ExifParser::decode(blobExifData, blob,
size);
1826 Exiv2::ExifData::const_iterator end = blobExifData.end();
1827 Exiv2::ExifData::iterator it;
1828 for(Exiv2::ExifData::const_iterator
i = blobExifData.begin();
i != end; ++
i)
1831 Exiv2::ExifKey
key(
i->key());
1832 if((it = imgExifData.findKey(
key)) != imgExifData.end()) imgExifData.erase(it);
1834 imgExifData.add(Exiv2::ExifKey(
i->key()), &
i->value());
1839 static const char *keys[] = {
1840 "Exif.Thumbnail.Compression",
1841 "Exif.Thumbnail.XResolution",
1842 "Exif.Thumbnail.YResolution",
1843 "Exif.Thumbnail.ResolutionUnit",
1844 "Exif.Thumbnail.JPEGInterchangeFormat",
1845 "Exif.Thumbnail.JPEGInterchangeFormatLength"
1847 static const guint n_keys = G_N_ELEMENTS(keys);
1854 static const char *keys[] = {
1855 "Exif.Photo.PixelXDimension",
1856 "Exif.Photo.PixelYDimension"
1858 static const guint n_keys = G_N_ELEMENTS(keys);
1862 imgExifData.sortByTag();
1863 image->writeMetadata();
1865 catch(Exiv2::AnyError &e)
1867 std::string s(e.what());
1868 std::cerr <<
"[exiv2 dt_exif_write_blob] " << path <<
": " << s << std::endl;
1876 static const char *keys[] =
1878 "Exif.GPSInfo.GPSLatitude",
1879 "Exif.GPSInfo.GPSLongitude",
1880 "Exif.GPSInfo.GPSAltitude",
1881 "Exif.GPSInfo.GPSLatitudeRef",
1882 "Exif.GPSInfo.GPSLongitudeRef",
1883 "Exif.GPSInfo.GPSAltitudeRef",
1884 "Exif.GPSInfo.GPSVersionID"
1886 static const guint n_keys = G_N_ELEMENTS(keys);
1891 const int out_height,
const int dng_mode)
1896 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(
WIDEN(path)));
1897 assert(image.get() != 0);
1899 Exiv2::ExifData &exifData = image->exifData();
1902 Exiv2::ExifThumb(exifData).erase();
1903 Exiv2::ExifData::const_iterator pos;
1906 static const char *keys[] = {
1907 "Exif.Image.ImageWidth",
1908 "Exif.Image.ImageLength",
1909 "Exif.Image.BitsPerSample",
1910 "Exif.Image.Compression",
1911 "Exif.Image.PhotometricInterpretation",
1912 "Exif.Image.FillOrder",
1913 "Exif.Image.SamplesPerPixel",
1914 "Exif.Image.StripOffsets",
1915 "Exif.Image.RowsPerStrip",
1916 "Exif.Image.StripByteCounts",
1917 "Exif.Image.TileWidth",
1918 "Exif.Image.TileLength",
1919 "Exif.Image.TileOffsets",
1920 "Exif.Image.TileByteCounts",
1921 "Exif.Image.PlanarConfiguration"
1923 static const guint n_keys = G_N_ELEMENTS(keys);
1930 for(Exiv2::ExifData::iterator
i = exifData.begin();
i != exifData.end();)
1932 static const std::string needle =
"Exif.SubImage";
1933 if(
i->key().compare(0, needle.length(), needle) == 0)
1934 i = exifData.erase(
i);
1940 static const char *keys[] = {
1942 "Exif.Canon.ColorSpace",
1943 "Exif.Canon.ColorData",
1946 "Exif.Nikon3.Preview",
1947 "Exif.NikonPreview.JPEGInterchangeFormat",
1950 "Exif.Image.CFARepeatPatternDim",
1951 "Exif.Image.CFAPattern",
1952 "Exif.Image.InterColorProfile",
1953 "Exif.Image.SpectralSensitivity",
1955 "Exif.Image.SpatialFrequencyResponse",
1957 "Exif.Image.SensingMethod",
1958 "Exif.Image.TIFFEPStandardID",
1959 "Exif.Photo.SpectralSensitivity",
1961 "Exif.Photo.SpatialFrequencyResponse",
1962 "Exif.Photo.SensingMethod",
1963 "Exif.Photo.CFAPattern",
1966 "Exif.Image.DNGVersion",
1967 "Exif.Image.DNGBackwardVersion",
1968 "Exif.Image.DNGPrivateData",
1969 "Exif.Image.DefaultBlackRender",
1970 "Exif.Image.DefaultCropOrigin",
1971 "Exif.Image.DefaultCropSize",
1972 "Exif.Image.RawDataUniqueID",
1973 "Exif.Image.OriginalRawFileName",
1974 "Exif.Image.OriginalRawFileData",
1975 "Exif.Image.ActiveArea",
1976 "Exif.Image.MaskedAreas",
1977 "Exif.Image.AsShotICCProfile",
1978 "Exif.Image.OpcodeList1",
1979 "Exif.Image.OpcodeList2",
1980 "Exif.Image.OpcodeList3",
1981 "Exif.Image.AsShotNeutral",
1982 "Exif.Image.AsShotWhiteXY",
1983 "Exif.Image.BaselineExposure",
1984 "Exif.Image.BaselineNoise",
1985 "Exif.Image.BaselineSharpness",
1986 "Exif.Image.LinearResponseLimit",
1987 "Exif.Image.ShadowScale",
1988 "Exif.Image.PreviewApplicationName",
1989 "Exif.Image.PreviewApplicationVersion",
1990 "Exif.Image.PreviewSettingsDigest",
1991 "Exif.Image.PreviewColorSpace",
1992 "Exif.Image.PreviewDateTime",
1993 "Exif.Image.NoiseProfile",
1994 "Exif.Image.NewRawImageDigest",
1995 "Exif.Image.RawImageDigest",
1997 "Exif.Photo.MakerNote",
2000 "Exif.Pentax.PreviewResolution",
2001 "Exif.Pentax.PreviewLength",
2002 "Exif.Pentax.PreviewOffset",
2003 "Exif.PentaxDng.PreviewResolution",
2004 "Exif.PentaxDng.PreviewLength",
2005 "Exif.PentaxDng.PreviewOffset",
2007 "Exif.PentaxDng.ColorInfo",
2010 "Exif.Minolta.Thumbnail",
2011 "Exif.Minolta.ThumbnailOffset",
2012 "Exif.Minolta.ThumbnailLength",
2015 "Exif.SonyMinolta.ThumbnailOffset",
2016 "Exif.SonyMinolta.ThumbnailLength",
2019 "Exif.Olympus.Thumbnail",
2020 "Exif.Olympus.ThumbnailOffset",
2021 "Exif.Olympus.ThumbnailLength",
2023 "Exif.Image.BaselineExposureOffset",
2027 "Exif.Samsung2.SensorAreas",
2028 "Exif.Samsung2.ColorSpace",
2029 "Exif.Samsung2.EncryptionKey",
2030 "Exif.Samsung2.WB_RGGBLevelsUncorrected",
2031 "Exif.Samsung2.WB_RGGBLevelsAuto",
2032 "Exif.Samsung2.WB_RGGBLevelsIlluminator1",
2033 "Exif.Samsung2.WB_RGGBLevelsIlluminator2",
2034 "Exif.Samsung2.WB_RGGBLevelsBlack",
2035 "Exif.Samsung2.ColorMatrix",
2036 "Exif.Samsung2.ColorMatrixSRGB",
2037 "Exif.Samsung2.ColorMatrixAdobeRGB",
2038 "Exif.Samsung2.ToneCurve1",
2039 "Exif.Samsung2.ToneCurve2",
2040 "Exif.Samsung2.ToneCurve3",
2041 "Exif.Samsung2.ToneCurve4"
2043 static const guint n_keys = G_N_ELEMENTS(keys);
2047 static const char *dngkeys[] = {
2049 "Exif.Image.ColorMatrix1",
2050 "Exif.Image.ColorMatrix2",
2051 "Exif.Image.CameraCalibration1",
2052 "Exif.Image.CameraCalibration2",
2053 "Exif.Image.ReductionMatrix1",
2054 "Exif.Image.ReductionMatrix2",
2055 "Exif.Image.AnalogBalance",
2056 "Exif.Image.CalibrationIlluminant1",
2057 "Exif.Image.CalibrationIlluminant2",
2058 "Exif.Image.CameraCalibrationSignature",
2059 "Exif.Image.ProfileCalibrationSignature",
2060 "Exif.Image.ExtraCameraProfiles",
2061 "Exif.Image.AsShotProfileName",
2062 "Exif.Image.ProfileName",
2063 "Exif.Image.ProfileHueSatMapDims",
2064 "Exif.Image.ProfileHueSatMapData1",
2065 "Exif.Image.ProfileHueSatMapData2",
2066 "Exif.Image.ProfileToneCurve",
2067 "Exif.Image.ProfileEmbedPolicy",
2068 "Exif.Image.ProfileCopyright",
2069 "Exif.Image.ForwardMatrix1",
2070 "Exif.Image.ForwardMatrix2",
2071 "Exif.Image.ProfileLookTableDims",
2072 "Exif.Image.ProfileLookTableData",
2073 "Exif.Image.ProfileLookTableEncoding",
2074 "Exif.Image.ProfileHueSatMapEncoding"
2076 static const guint n_dngkeys = G_N_ELEMENTS(dngkeys);
2081 exifData[
"Exif.Photo.ColorSpace"] = uint16_t(1);
2083 exifData[
"Exif.Photo.ColorSpace"] = uint16_t(0xFFFF);
2087 if(!dng_mode) exifData[
"Exif.Image.Orientation"] = uint16_t(1);
2091 if(out_width > 0) exifData[
"Exif.Photo.PixelXDimension"] = (uint32_t)out_width;
2092 if(out_height > 0) exifData[
"Exif.Photo.PixelYDimension"] = (uint32_t)out_height;
2095 exifData[
"Exif.Image.XResolution"] = Exiv2::Rational(resolution, 1);
2096 exifData[
"Exif.Image.YResolution"] = Exiv2::Rational(resolution, 1);
2097 exifData[
"Exif.Image.ResolutionUnit"] = uint16_t(2);
2107 static const char * keys[] = {
2108 "Exif.Image.Artist",
2109 "Exif.Image.ImageDescription",
2110 "Exif.Photo.UserComment",
2111 "Exif.Image.Copyright",
2112 "Exif.Image.Rating",
2113 "Exif.Image.RatingPercent",
2114 "Exif.Photo.SubSecTimeOriginal",
2115 "Exif.GPSInfo.GPSVersionID",
2116 "Exif.GPSInfo.GPSLongitudeRef",
2117 "Exif.GPSInfo.GPSLatitudeRef",
2118 "Exif.GPSInfo.GPSLongitude",
2119 "Exif.GPSInfo.GPSLatitude",
2120 "Exif.GPSInfo.GPSAltitudeRef",
2121 "Exif.GPSInfo.GPSAltitude"
2123 static const guint n_keys = G_N_ELEMENTS(keys);
2129 exifData[
"Exif.Image.Artist"] = (
char *)res->data;
2137 char *desc = (
char *)res->data;
2138 if(g_str_is_ascii(desc))
2139 exifData[
"Exif.Image.ImageDescription"] = desc;
2141 exifData[
"Exif.Photo.UserComment"] = desc;
2145#if EXIV2_TEST_VERSION(0,27,4)
2149 exifData[
"Exif.Image.ImageDescription"] =
"";
2155 exifData[
"Exif.Image.Copyright"] = (
char *)res->data;
2159#if EXIV2_TEST_VERSION(0,27,4)
2163 exifData[
"Exif.Image.Copyright"] =
"";
2169 const int rating = GPOINTER_TO_INT(res->data) + 1;
2170 exifData[
"Exif.Image.Rating"] = rating;
2180 exifData[
"Exif.GPSInfo.GPSVersionID"] =
"02 02 00 00";
2181 exifData[
"Exif.GPSInfo.GPSLongitudeRef"] = (cimg->
geoloc.
longitude < 0) ?
"W" :
"E";
2182 exifData[
"Exif.GPSInfo.GPSLatitudeRef"] = (cimg->
geoloc.
latitude < 0) ?
"S" :
"N";
2188 gchar *long_str = g_strdup_printf(
"%ld/1 %ld/1000000 0/1", long_deg, long_min);
2189 gchar *lat_str = g_strdup_printf(
"%ld/1 %ld/1000000 0/1", lat_deg, lat_min);
2190 exifData[
"Exif.GPSInfo.GPSLongitude"] = long_str;
2191 exifData[
"Exif.GPSInfo.GPSLatitude"] = lat_str;
2197 exifData[
"Exif.GPSInfo.GPSVersionID"] =
"02 02 00 00";
2198 exifData[
"Exif.GPSInfo.GPSAltitudeRef"] = (cimg->
geoloc.
elevation < 0) ?
"1" :
"0";
2201 gchar *ele_str = g_strdup_printf(
"%ld/10", ele_dm);
2202 exifData[
"Exif.GPSInfo.GPSAltitude"] = ele_str;
2212 exifData[
"Exif.Image.DateTime"] = new_datetime;
2216 exifData[
"Exif.Image.DateTimeOriginal"] = datetime;
2217 exifData[
"Exif.Photo.DateTimeOriginal"] = datetime;
2225 Exiv2::ExifParser::encode(blob, Exiv2::bigEndian, exifData);
2226 const size_t length = blob.size();
2227 *buf = (uint8_t *)malloc(length);
2232 memcpy(*buf, &(blob[0]), length);
2235 catch(Exiv2::AnyError &e)
2238 std::string s(e.what());
2239 std::cerr <<
"[exiv2 dt_exif_read_blob] " << path <<
": " << s << std::endl;
2248#define COMPRESS_THRESHOLD 100
2250 gboolean do_compress =
FALSE;
2258 if(!strcmp(config,
"always"))
2263 do_compress =
FALSE;
2269#undef COMPRESS_THRESHOLD
2274 char *output = NULL;
2279 uLongf destLen = compressBound(len);
2280 unsigned char *buffer1 = (
unsigned char *)malloc(destLen);
2282 result = compress(buffer1, &destLen, input, len);
2291 const int factor =
MIN(len / destLen + 1, 99);
2293 char *buffer2 = (
char *)g_base64_encode(buffer1, destLen);
2297 int outlen = strlen(buffer2) + 5;
2298 output = (
char *)malloc(outlen);
2307 output[2] =
factor / 10 +
'0';
2308 output[3] =
factor % 10 +
'0';
2309 g_strlcpy(output + 4, buffer2, outlen);
2312 if(output_len) *output_len = outlen;
2316 const char hex[16] = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'a',
'b',
'c',
'd',
'e',
'f' };
2318 output = (
char *)malloc(2 * len + 1);
2321 if(output_len) *output_len = 2 * len + 1;
2323 for(
int i = 0;
i < len;
i++)
2325 const int hi = input[
i] >> 4;
2326 const int lo = input[
i] & 15;
2327 output[2 *
i] = hex[hi];
2328 output[2 *
i + 1] = hex[lo];
2330 output[2 * len] =
'\0';
2339 unsigned char *output = NULL;
2342 if(!strncmp(input,
"gz", 2))
2347 const float factor = 10 * (input[2] -
'0') + (input[3] -
'0');
2350 unsigned char *buffer = (
unsigned char *)strdup(input + 4);
2354 gsize compressed_size;
2355 g_base64_decode_inplace((
char *)buffer, &compressed_size);
2358 int result = Z_BUF_ERROR;
2359 uLongf bufLen =
factor * compressed_size;
2370 output = (
unsigned char *)malloc(bufLen);
2375 result = uncompress(output, &destLen, buffer, compressed_size);
2379 }
while(result == Z_BUF_ERROR);
2393 if(output_len) *output_len = destLen;
2402#define TO_BINARY(a) (a > 57 ? a - 97 + 10 : a - 48)
2405 if(strspn(input,
"0123456789abcdef") != strlen(input))
return NULL;
2407 output = (
unsigned char *)malloc(len / 2);
2410 if(output_len) *output_len = len / 2;
2412 for(
int i = 0;
i < len / 2;
i++)
2416 output[
i] = (hi << 4) | lo;
2427 const int cnt = pos->count();
2429 sqlite3_stmt *stmt_sel_id, *stmt_ins_tags, *stmt_ins_tagged;
2431 &stmt_sel_id, NULL);
2433 -1, &stmt_ins_tags, NULL);
2436 "INSERT INTO main.tagged_images (tagid, imgid, position)"
2438 " (SELECT (IFNULL(MAX(position),0) & 0xFFFFFFFF00000000) + (1 << 32)"
2439 " FROM main.tagged_images))",
2440 -1, &stmt_ins_tagged, NULL);
2442 for(
int i = 0;
i < cnt;
i++)
2445 std::string pos_str = pos->toString(
i);
2446 g_strlcpy(tagbuf, pos_str.c_str(),
sizeof(tagbuf));
2451 char *next_tag = strstr(tag,
",");
2452 if(next_tag) *(next_tag++) = 0;
2454 for(
int k = 0;
k < 2;
k++)
2457 if(sqlite3_step(stmt_sel_id) == SQLITE_ROW) tagid = sqlite3_column_int(stmt_sel_id, 0);
2458 sqlite3_reset(stmt_sel_id);
2459 sqlite3_clear_bindings(stmt_sel_id);
2461 if(tagid > 0)
break;
2463 fprintf(stderr,
"[xmp_import] creating tag: %s\n", tag);
2466 sqlite3_step(stmt_ins_tags);
2467 sqlite3_reset(stmt_ins_tags);
2468 sqlite3_clear_bindings(stmt_ins_tags);
2473 sqlite3_step(stmt_ins_tagged);
2474 sqlite3_reset(stmt_ins_tagged);
2475 sqlite3_clear_bindings(stmt_ins_tagged);
2480 sqlite3_finalize(stmt_sel_id);
2481 sqlite3_finalize(stmt_ins_tags);
2482 sqlite3_finalize(stmt_ins_tagged);
2527 std::cout <<
"malformed entry" << std::endl;
2531 std::cout << entry->
operation << std::endl;
2532 std::cout <<
" modversion :" << entry->
modversion << std::endl;
2533 std::cout <<
" enabled :" << entry->
enabled << std::endl;
2534 std::cout <<
" params :" << (entry->
params ?
"<found>" :
"<missing>") << std::endl;
2535 std::cout <<
" multi_name :" << (entry->
multi_name ? entry->
multi_name :
"<missing>") << std::endl;
2536 std::cout <<
" multi_priority :" << entry->
multi_priority << std::endl;
2537 std::cout <<
" iop_order :" << entry->
iop_order << std::endl;
2538 std::cout <<
" blendop_version :" << entry->
blendop_version << std::endl;
2539 std::cout <<
" blendop_params :" << (entry->
blendop_params ?
"<found>" :
"<missing>") << std::endl;
2540 std::cout << std::endl;
2556static GList *
read_history_v1(
const std::string &xmpPacket,
const char *filename,
const int superold)
2558 GList *history_entries = NULL;
2560 pugi::xml_document doc;
2561#if defined(PUGIXML_VERSION) && PUGIXML_VERSION >= 150
2562 pugi::xml_parse_result result = doc.load_string(xmpPacket.c_str());
2564 pugi::xml_parse_result result = doc.load(xmpPacket.c_str());
2569 std::cerr <<
"XML '" << filename <<
"' parsed with errors" << std::endl;
2570 std::cerr <<
"Error description: " << result.description() << std::endl;
2571 std::cerr <<
"Error offset: " << result.offset << std::endl;
2577#if defined(PUGIXML_VERSION) && PUGIXML_VERSION >= 150
2578 pugi::xpath_node modversion = superold ?
2579 doc.select_node(
"//darktable:history_modversion/rdf:Bag"):
2580 doc.select_node(
"//darktable:history_modversion/rdf:Seq");
2581 pugi::xpath_node enabled = superold ?
2582 doc.select_node(
"//darktable:history_enabled/rdf:Bag"):
2583 doc.select_node(
"//darktable:history_enabled/rdf:Seq");
2584 pugi::xpath_node operation = superold ?
2585 doc.select_node(
"//darktable:history_operation/rdf:Bag"):
2586 doc.select_node(
"//darktable:history_operation/rdf:Seq");
2587 pugi::xpath_node params = superold ?
2588 doc.select_node(
"//darktable:history_params/rdf:Bag"):
2589 doc.select_node(
"//darktable:history_params/rdf:Seq");
2590 pugi::xpath_node blendop_params = superold ?
2591 doc.select_node(
"//darktable:blendop_params/rdf:Bag"):
2592 doc.select_node(
"//darktable:blendop_params/rdf:Seq");
2593 pugi::xpath_node blendop_version = superold ?
2594 doc.select_node(
"//darktable:blendop_version/rdf:Bag"):
2595 doc.select_node(
"//darktable:blendop_version/rdf:Seq");
2596 pugi::xpath_node multi_priority = superold ?
2597 doc.select_node(
"//darktable:multi_priority/rdf:Bag"):
2598 doc.select_node(
"//darktable:multi_priority/rdf:Seq");
2599 pugi::xpath_node multi_name = superold ?
2600 doc.select_node(
"//darktable:multi_name/rdf:Bag"):
2601 doc.select_node(
"//darktable:multi_name/rdf:Seq");
2603 pugi::xpath_node modversion = superold ?
2604 doc.select_single_node(
"//darktable:history_modversion/rdf:Bag"):
2605 doc.select_single_node(
"//darktable:history_modversion/rdf:Seq");
2606 pugi::xpath_node enabled = superold ?
2607 doc.select_single_node(
"//darktable:history_enabled/rdf:Bag"):
2608 doc.select_single_node(
"//darktable:history_enabled/rdf:Seq");
2609 pugi::xpath_node operation = superold ?
2610 doc.select_single_node(
"//darktable:history_operation/rdf:Bag"):
2611 doc.select_single_node(
"//darktable:history_operation/rdf:Seq");
2612 pugi::xpath_node params = superold ?
2613 doc.select_single_node(
"//darktable:history_params/rdf:Bag"):
2614 doc.select_single_node(
"//darktable:history_params/rdf:Seq");
2615 pugi::xpath_node blendop_params = superold ?
2616 doc.select_single_node(
"//darktable:blendop_params/rdf:Bag"):
2617 doc.select_single_node(
"//darktable:blendop_params/rdf:Seq");
2618 pugi::xpath_node blendop_version = superold ?
2619 doc.select_single_node(
"//darktable:blendop_version/rdf:Bag"):
2620 doc.select_single_node(
"//darktable:blendop_version/rdf:Seq");
2621 pugi::xpath_node multi_priority = superold ?
2622 doc.select_single_node(
"//darktable:multi_priority/rdf:Bag"):
2623 doc.select_single_node(
"//darktable:multi_priority/rdf:Seq");
2624 pugi::xpath_node multi_name = superold ?
2625 doc.select_single_node(
"//darktable:multi_name/rdf:Bag"):
2626 doc.select_single_node(
"//darktable:multi_name/rdf:Seq");
2631 auto modversion_iter = modversion.node().children().begin();
2632 auto enabled_iter = enabled.node().children().begin();
2633 auto params_iter = params.node().children().begin();
2634 auto blendop_params_iter = blendop_params.node().children().begin();
2635 auto blendop_version_iter = blendop_version.node().children().begin();
2636 auto multi_priority_iter = multi_priority.node().children().begin();
2637 auto multi_name_iter = multi_name.node().children().begin();
2639 for(pugi::xml_node operation_iter: operation.node().children())
2643 history_entries = g_list_append(history_entries, current_entry);
2645 current_entry->
operation = g_strdup(operation_iter.child_value());
2647 current_entry->
enabled = g_strcmp0(enabled_iter->child_value(),
"0") != 0;
2649 current_entry->
modversion = atoi(modversion_iter->child_value());
2654 if(multi_name && multi_name_iter != multi_name.node().children().end())
2656 current_entry->
multi_name = g_strdup(multi_name_iter->child_value());
2660 if(multi_priority && multi_priority_iter != multi_priority.node().children().end())
2662 current_entry->
multi_priority = atoi(multi_priority_iter->child_value());
2663 multi_priority_iter++;
2666 if(blendop_version && blendop_version_iter != blendop_version.node().children().end())
2668 current_entry->
blendop_version = atoi(blendop_version_iter->child_value());
2669 blendop_version_iter++;
2672 if(blendop_params && blendop_params_iter != blendop_params.node().children().end())
2675 strlen(blendop_params_iter->child_value()),
2677 blendop_params_iter++;
2687 return history_entries;
2692 GList *history_entries = NULL;
2695 for(
auto history = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.history")); history != xmpData.end(); history++)
2701 std::string key_item = history->key();
2702 char *
key = g_strdup(key_item.c_str());
2703 char *key_iter =
key;
2704 if(g_str_has_prefix(
key,
"Xmp.darktable.history["))
2706 key_iter += strlen(
"Xmp.darktable.history[");
2708 unsigned int n = strtol(key_iter, &key_iter, 10);
2711 std::cerr <<
"error reading history from '" <<
key <<
"' (" << filename <<
")" << std::endl;
2713 history_entries = NULL;
2719 if(*(key_iter++) !=
']')
2721 std::cerr <<
"error reading history from '"
2722 <<
key <<
"' (" << filename <<
")" << std::endl;
2724 history_entries = NULL;
2728 if(*(key_iter++) !=
'/')
goto skip;
2729 if(*key_iter ==
'?') key_iter++;
2732 unsigned int length = g_list_length(history_entries);
2738 history_entries = g_list_append(history_entries, current_entry);
2745 current_entry = (
history_entry_t *)g_list_nth_data(history_entries,
n - 1);
2749 if(g_str_has_prefix(key_iter,
"darktable:operation"))
2752 std::string value_item = history->toString();
2753 current_entry->
operation = g_strdup(value_item.c_str());
2755 else if(g_str_has_prefix(key_iter,
"darktable:num"))
2757 current_entry->
num = history->toLong();
2759 else if(g_str_has_prefix(key_iter,
"darktable:enabled"))
2761 current_entry->
enabled = history->toLong() == 1;
2763 else if(g_str_has_prefix(key_iter,
"darktable:modversion"))
2766 current_entry->
modversion = history->toLong();
2768 else if(g_str_has_prefix(key_iter,
"darktable:params"))
2771 std::string value_item = history->toString();
2782 else if(g_str_has_prefix(key_iter,
"darktable:multi_name"))
2784 std::string value_item = history->toString();
2785 current_entry->
multi_name = g_strdup(value_item.c_str());
2787 else if(g_str_has_prefix(key_iter,
"darktable:multi_priority"))
2791 else if(g_str_has_prefix(key_iter,
"darktable:iop_order"))
2794 std::string value_item = history->toString();
2795 string str = g_strdup(value_item.c_str());
2796 static const std::locale& c_locale = std::locale(
"C");
2797 std::istringstream istring(str);
2798 istring.imbue(c_locale);
2801 else if(g_str_has_prefix(key_iter,
"darktable:blendop_version"))
2805 else if(g_str_has_prefix(key_iter,
"darktable:blendop_params"))
2807 std::string value_item = history->toString();
2819 for(GList *iter = history_entries; iter; iter = g_list_next(iter))
2824 std::cerr <<
"[exif] error: reading history from '" << filename <<
"' failed due to missing tags" << std::endl;
2826 history_entries = NULL;
2831 return history_entries;
2843static GHashTable *
read_masks(Exiv2::XmpData &xmpData,
const char *filename,
const int version)
2845 GHashTable *mask_entries = g_hash_table_new_full(g_int_hash, g_int_equal, NULL,
free_mask_entry);
2848 Exiv2::XmpData::iterator mask;
2850 Exiv2::XmpData::iterator mask_type;
2851 Exiv2::XmpData::iterator mask_version;
2852 Exiv2::XmpData::iterator
mask_id;
2853 Exiv2::XmpData::iterator mask_nb;
2854 Exiv2::XmpData::iterator mask_src;
2855 if((mask = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.mask"))) != xmpData.end()
2856 && (mask_src = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.mask_src"))) != xmpData.end()
2857 && (
mask_name = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.mask_name"))) != xmpData.end()
2858 && (mask_type = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.mask_type"))) != xmpData.end()
2859 && (mask_version = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.mask_version"))) != xmpData.end()
2860 && (
mask_id = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.mask_id"))) != xmpData.end()
2861 && (mask_nb = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.mask_nb"))) != xmpData.end())
2864 const size_t cnt = (size_t)mask->count();
2865 const size_t mask_src_cnt = (size_t)mask_src->count();
2866 const size_t mask_name_cnt = (size_t)
mask_name->count();
2867 const size_t mask_type_cnt = (size_t)mask_type->count();
2868 const size_t mask_version_cnt = (size_t)mask_version->count();
2869 const size_t mask_id_cnt = (size_t)
mask_id->count();
2870 const size_t mask_nb_cnt = (size_t)mask_nb->count();
2871 if(cnt == mask_src_cnt && cnt == mask_name_cnt && cnt == mask_type_cnt
2872 && cnt == mask_version_cnt && cnt == mask_id_cnt && cnt == mask_nb_cnt)
2874 for(
size_t i = 0;
i < cnt;
i++)
2881 std::string mask_name_str =
mask_name->toString(
i);
2882 if(mask_name_str.c_str() != NULL)
2883 entry->
mask_name = g_strdup(mask_name_str.c_str());
2889 std::string mask_str = mask->toString(
i);
2890 const char *mask_c = mask_str.c_str();
2891 const size_t mask_c_len = strlen(mask_c);
2894 entry->
mask_nb = mask_nb->toLong(
i);
2896 std::string mask_src_str = mask_src->toString(
i);
2897 const char *mask_src_c = mask_src_str.c_str();
2898 const size_t mask_src_c_len = strlen(mask_src_c);
2901 g_hash_table_insert(mask_entries, &entry->
mask_id, (gpointer)entry);
2906 return mask_entries;
2909static GList *
read_masks_v3(Exiv2::XmpData &xmpData,
const char *filename,
const int version)
2911 GList *history_entries = NULL;
2914 for(
auto history = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.masks_history")); history != xmpData.end(); history++)
2920 std::string key_item = history->key();
2921 char *
key = g_strdup(key_item.c_str());
2922 char *key_iter =
key;
2923 if(g_str_has_prefix(
key,
"Xmp.darktable.masks_history["))
2925 key_iter += strlen(
"Xmp.darktable.masks_history[");
2927 unsigned int n = strtol(key_iter, &key_iter, 10);
2930 std::cerr <<
"error reading masks history from '" <<
key <<
"' (" << filename <<
")" << std::endl;
2932 history_entries = NULL;
2938 if(*(key_iter++) !=
']')
2940 std::cerr <<
"error reading masks history from '" <<
key <<
"' (" << filename <<
")" << std::endl;
2942 history_entries = NULL;
2946 if(*(key_iter++) !=
'/')
goto skip;
2947 if(*key_iter ==
'?') key_iter++;
2950 unsigned int length = g_list_length(history_entries);
2954 current_entry->
version = version;
2955 history_entries = g_list_append(history_entries, current_entry);
2962 current_entry = (
mask_entry_t *)g_list_nth_data(history_entries,
n - 1);
2966 if(g_str_has_prefix(key_iter,
"darktable:mask_num"))
2968 current_entry->
mask_num = history->toLong();
2970 else if(g_str_has_prefix(key_iter,
"darktable:mask_id"))
2972 current_entry->
mask_id = history->toLong();
2974 else if(g_str_has_prefix(key_iter,
"darktable:mask_type"))
2976 current_entry->
mask_type = history->toLong();
2978 else if(g_str_has_prefix(key_iter,
"darktable:mask_name"))
2980 std::string value_item = history->toString();
2981 current_entry->
mask_name = g_strdup(value_item.c_str());
2983 else if(g_str_has_prefix(key_iter,
"darktable:mask_version"))
2987 else if(g_str_has_prefix(key_iter,
"darktable:mask_points"))
2989 std::string value_item = history->toString();
2994 else if(g_str_has_prefix(key_iter,
"darktable:mask_nb"))
2996 current_entry->
mask_nb = history->toLong();
2998 else if(g_str_has_prefix(key_iter,
"darktable:mask_src"))
3000 std::string value_item = history->toString();
3011 return history_entries;
3020 const int mask_num = 0;
3026 "INSERT INTO main.masks_history (imgid, num, formid, form, name, version, points, points_count, source) "
3027 "VALUES (?1, ?9, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",
3046 int prepare_result = sqlite3_step(stmt);
3047 sqlite3_finalize(stmt);
3050 if(prepare_result == SQLITE_OK)
3058 int32_t imgid = *(
int *)user_data;
3078 fprintf(stderr,
"[masks] error loading masks from xmp file, bad binary blob size.\n");
3093 for(GList *iter = history; iter; iter = g_list_next(iter))
3097 if(!strcmp(entry->
operation, operation))
3108 const char *c = filename + strlen(filename) - 4;
3109 if(c >= filename && !strcmp(c,
".pfm"))
return 1;
3113 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(
WIDEN(filename)));
3114 assert(image.get() != 0);
3116 Exiv2::XmpData &xmpData = image->xmpData();
3120 Exiv2::XmpData::iterator pos;
3122 int xmp_version = 0;
3123 GList *iop_order_list = NULL;
3127 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.xmp_version"))) != xmpData.end())
3128 xmp_version = pos->toLong();
3133 const size_t ns_pos = image->xmpPacket().find(
"xmlns:darktable=\"http://darktable.sf.net/\"");
3134 const bool is_a_dt_xmp = (ns_pos != std::string::npos);
3140 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.raw_params"))) != xmpData.end())
3146 raw_params.in = pos->toLong();
3147 const int32_t user_flip = raw_params.out.
user_flip;
3152 int32_t preset_applied = 0;
3154 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.auto_presets_applied"))) != xmpData.end())
3156 preset_applied = pos->toLong();
3161 else if(xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.xmp_version")) == xmpData.end())
3170 img->
flags &= ~DT_IMAGE_NO_LEGACY_PRESETS;
3173 img->
flags &= ~DT_IMAGE_REMOVE;
3175 if(xmp_version == 4 || xmp_version == 5)
3177 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.iop_order_version"))) != xmpData.end())
3182 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.iop_order_list"))) != xmpData.end())
3189 else if(xmp_version == 3)
3193 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.iop_order_version"))) != xmpData.end())
3210 GHashTable *mask_entries = NULL;
3211 GList *mask_entries_v3 = NULL;
3218 mask_entries =
read_masks(xmpData, filename, xmp_version);
3220 mask_entries_v3 =
read_masks_v3(xmpData, filename, xmp_version);
3232 for(GList *m_entries = g_list_first(mask_entries_v3); m_entries; m_entries = g_list_next(m_entries))
3244 gboolean all_ok =
TRUE;
3245 GList *history_entries = NULL;
3249 std::string &xmpPacket = image->xmpPacket();
3251 if(!history_entries)
3254 else if(xmp_version == 2 || xmp_version == 3 || xmp_version == 4 || xmp_version == 5 )
3258 std::cerr <<
"error: Xmp schema version " << xmp_version <<
" in " << filename <<
" not supported" << std::endl;
3259 g_hash_table_destroy(mask_entries);
3267 fprintf(stderr,
"[exif] error deleting history for image %d\n", img->
id);
3273 for(GList *iter = history_entries; iter; iter = g_list_next(iter))
3276 const int db_num = (xmp_version < 3) ? num : entry->
num;
3295 fprintf(stderr,
"[exif] error adding history entry for image %d\n", img->
id);
3311 for(GList *iter = history_entries; iter; iter = g_list_next(iter))
3331 "[exif] cannot get iop-order for module '%s', XMP may be corrupted\n",
3334 iop_order_list = NULL;
3336 history_entries = NULL;
3338 mask_entries_v3 = NULL;
3339 if(mask_entries) g_hash_table_destroy(mask_entries);
3354 if(link) iop_order_list = g_list_delete_link(iop_order_list, link);
3356 iop_order_list = g_list_append(iop_order_list, e);
3368 "SELECT COUNT(*) FROM main.masks_history WHERE imgid = ?1", -1,
3371 if(sqlite3_step(stmt) == SQLITE_ROW)
3372 num_masks = sqlite3_column_int(stmt, 0);
3373 sqlite3_finalize(stmt);
3380 fprintf(stderr,
"[exif] error shifting history nums for image %d\n", img->
id);
3385 if(!
dt_history_db_write_history_item(img->
id, 0,
"mask_manager", NULL, 0, 1, 0, NULL, 0, 0, 0,
""))
3387 fprintf(stderr,
"[exif] error adding mask history entry for image %d\n", img->
id);
3398 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.history_end"))) != xmpData.end() && num > 0)
3400 int history_end =
MIN(pos->toLong(), num);
3401 if(num_masks > 0) history_end++;
3402 if((history_end < 1) && preset_applied) preset_applied = -1;
3405 fprintf(stderr,
"[exif] error writing history_end for image %d\n", img->
id);
3413 if(preset_applied) preset_applied = -1;
3417 fprintf(stderr,
"[exif] error writing history_end for image %d\n", img->
id);
3425 fprintf(stderr,
"[exif] error writing iop_list for image %d\n", img->
id);
3437 if(preset_applied > 0)
3444 img->
flags &= ~DT_IMAGE_AUTO_PRESETS_APPLIED;
3446 if(preset_applied < 0)
3448 fprintf(stderr,
"[exif] dt_exif_xmp_read for %s, id %i found auto_presets_applied but there was no history\n",filename,img->
id);
3453 iop_order_list = NULL;
3455 history_entries = NULL;
3457 mask_entries_v3 = NULL;
3458 if(mask_entries) g_hash_table_destroy(mask_entries);
3465 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.history_current_hash"))) != xmpData.end())
3468 unsigned char *decoded =
dt_exif_xmp_decode(pos->toString().c_str(), strlen(pos->toString().c_str()),
3470 if(decoded && hash_len == (
int)
sizeof(
uint64_t))
3473 memcpy(&be_hash, decoded,
sizeof(be_hash));
3481 std::cerr <<
"[exif] error reading history from '" << filename <<
"'" << std::endl;
3487 catch(Exiv2::AnyError &e)
3509 Exiv2::XmpTextValue tvm(
"");
3510 tvm.setXmpArrayType(Exiv2::XmpValue::xaSeq);
3511 xmpData.add(Exiv2::XmpKey(
"Xmp.darktable.masks_history"), &tvm);
3515 "SELECT imgid, formid, form, name, version, points, points_count, source, num"
3516 " FROM main.masks_history"
3522 while(sqlite3_step(stmt) == SQLITE_ROW)
3524 const int32_t mask_num = sqlite3_column_int(stmt, 8);
3525 const int32_t
mask_id = sqlite3_column_int(stmt, 1);
3526 const int32_t mask_type = sqlite3_column_int(stmt, 2);
3527 const char *
mask_name = (
const char *)sqlite3_column_text(stmt, 3);
3528 const int32_t mask_version = sqlite3_column_int(stmt, 4);
3529 int32_t len = sqlite3_column_bytes(stmt, 5);
3530 char *mask_d =
dt_exif_xmp_encode((
const unsigned char *)sqlite3_column_blob(stmt, 5), len, NULL);
3531 const int32_t mask_nb = sqlite3_column_int(stmt, 6);
3532 len = sqlite3_column_bytes(stmt, 7);
3533 char *mask_src =
dt_exif_xmp_encode((
const unsigned char *)sqlite3_column_blob(stmt, 7), len, NULL);
3535 snprintf(
key,
sizeof(
key),
"Xmp.darktable.masks_history[%d]/darktable:mask_num", num);
3536 xmpData[
key] = mask_num;
3537 snprintf(
key,
sizeof(
key),
"Xmp.darktable.masks_history[%d]/darktable:mask_id", num);
3539 snprintf(
key,
sizeof(
key),
"Xmp.darktable.masks_history[%d]/darktable:mask_type", num);
3540 xmpData[
key] = mask_type;
3541 snprintf(
key,
sizeof(
key),
"Xmp.darktable.masks_history[%d]/darktable:mask_name", num);
3543 snprintf(
key,
sizeof(
key),
"Xmp.darktable.masks_history[%d]/darktable:mask_version", num);
3544 xmpData[
key] = mask_version;
3545 snprintf(
key,
sizeof(
key),
"Xmp.darktable.masks_history[%d]/darktable:mask_points", num);
3546 xmpData[
key] = mask_d;
3547 snprintf(
key,
sizeof(
key),
"Xmp.darktable.masks_history[%d]/darktable:mask_nb", num);
3548 xmpData[
key] = mask_nb;
3549 snprintf(
key,
sizeof(
key),
"Xmp.darktable.masks_history[%d]/darktable:mask_src", num);
3550 xmpData[
key] = mask_src;
3557 sqlite3_finalize(stmt);
3563 Exiv2::XmpTextValue tv(
"");
3564 tv.setXmpArrayType(Exiv2::XmpValue::xaSeq);
3565 xmpData.add(Exiv2::XmpKey(
"Xmp.darktable.history"), &tv);
3569 "SELECT module, operation, op_params, enabled, blendop_params, "
3570 " blendop_version, multi_priority, multi_name, num"
3571 " FROM main.history"
3577 while(sqlite3_step(stmt) == SQLITE_ROW)
3579 int32_t modversion = sqlite3_column_int(stmt, 0);
3580 const char *operation = (
const char *)sqlite3_column_text(stmt, 1);
3581 int32_t params_len = sqlite3_column_bytes(stmt, 2);
3582 const void *params_blob = sqlite3_column_blob(stmt, 2);
3583 const int32_t enabled = sqlite3_column_int(stmt, 3);
3584 const void *blendop_blob = sqlite3_column_blob(stmt, 4);
3585 int32_t blendop_params_len = sqlite3_column_bytes(stmt, 4);
3586 int32_t blendop_version = sqlite3_column_int(stmt, 5);
3587 int32_t multi_priority = sqlite3_column_int(stmt, 6);
3588 const char *multi_name = (
const char *)sqlite3_column_text(stmt, 7);
3589 int32_t hist_num = sqlite3_column_int(stmt, 8);
3593 char *params =
dt_exif_xmp_encode((
const unsigned char *)params_blob, params_len, NULL);
3595 snprintf(
key,
sizeof(
key),
"Xmp.darktable.history[%d]/darktable:num", num);
3596 xmpData[
key] = hist_num;
3597 snprintf(
key,
sizeof(
key),
"Xmp.darktable.history[%d]/darktable:operation", num);
3598 xmpData[
key] = operation;
3599 snprintf(
key,
sizeof(
key),
"Xmp.darktable.history[%d]/darktable:enabled", num);
3600 xmpData[
key] = enabled;
3601 snprintf(
key,
sizeof(
key),
"Xmp.darktable.history[%d]/darktable:modversion", num);
3602 xmpData[
key] = modversion;
3603 snprintf(
key,
sizeof(
key),
"Xmp.darktable.history[%d]/darktable:params", num);
3604 xmpData[
key] = params;
3605 snprintf(
key,
sizeof(
key),
"Xmp.darktable.history[%d]/darktable:multi_name", num);
3606 xmpData[
key] = multi_name ? multi_name :
"";
3607 snprintf(
key,
sizeof(
key),
"Xmp.darktable.history[%d]/darktable:multi_priority", num);
3608 xmpData[
key] = multi_priority;
3614 char *blendop_params =
dt_exif_xmp_encode((
const unsigned char *)blendop_blob, blendop_params_len, NULL);
3615 snprintf(
key,
sizeof(
key),
"Xmp.darktable.history[%d]/darktable:blendop_version", num);
3616 xmpData[
key] = blendop_version;
3617 snprintf(
key,
sizeof(
key),
"Xmp.darktable.history[%d]/darktable:blendop_params", num);
3618 xmpData[
key] = blendop_params;
3627 sqlite3_finalize(stmt);
3628 if(history_end == -1) history_end = num - 1;
3629 else history_end =
MIN(history_end, num - 1);
3630 xmpData[
"Xmp.darktable.history_end"] = history_end;
3636 static const char *keys[] =
3638 "Xmp.darktable.import_timestamp",
3639 "Xmp.darktable.change_timestamp",
3640 "Xmp.darktable.export_timestamp",
3641 "Xmp.darktable.print_timestamp"
3643 static const guint n_keys = G_N_ELEMENTS(keys);
3650 "SELECT import_timestamp, change_timestamp, export_timestamp, print_timestamp"
3657 if(sqlite3_step(stmt) == SQLITE_ROW)
3659 if(sqlite3_column_type(stmt, 0) != SQLITE_NULL)
3660 xmpData[
"Xmp.darktable.import_timestamp"] = sqlite3_column_int64(stmt, 0);
3661 if(sqlite3_column_type(stmt, 1) != SQLITE_NULL)
3662 xmpData[
"Xmp.darktable.change_timestamp"] = sqlite3_column_int64(stmt, 1);
3663 if(sqlite3_column_type(stmt, 2) != SQLITE_NULL)
3664 xmpData[
"Xmp.darktable.export_timestamp"] = sqlite3_column_int64(stmt, 2);
3665 if(sqlite3_column_type(stmt, 3) != SQLITE_NULL)
3666 xmpData[
"Xmp.darktable.print_timestamp"] = sqlite3_column_int64(stmt, 3);
3668 sqlite3_finalize(stmt);
3673 GDateTime *gdt = g_date_time_new_from_unix_utc(unix);
3677 g_date_time_unref(gdt);
3686 Exiv2::XmpData::iterator pos;
3689 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.change_timestamp"))) != xmpData.end())
3693 else if(pos->toLong() >= 1)
3696 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.export_timestamp"))) != xmpData.end())
3700 else if(pos->toLong() >= 1)
3703 if((pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.darktable.print_timestamp"))) != xmpData.end())
3707 else if(pos->toLong() >= 1)
3714 static const char *keys[] =
3716 "Xmp.exif.GPSVersionID",
3717 "Xmp.exif.GPSLongitude",
3718 "Xmp.exif.GPSLatitude",
3719 "Xmp.exif.GPSAltitudeRef",
3720 "Xmp.exif.GPSAltitude"
3722 static const guint n_keys = G_N_ELEMENTS(keys);
3729 if(!isnan(longitude) && !isnan(latitude))
3731 char long_dir =
'E', lat_dir =
'N';
3732 if(longitude < 0) long_dir =
'W';
3733 if(latitude < 0) lat_dir =
'S';
3735 longitude = fabs(longitude);
3736 latitude = fabs(latitude);
3738 int long_deg = (int)floor(longitude);
3739 int lat_deg = (int)floor(latitude);
3740 double long_min = (longitude - (
double)long_deg) * 60.0;
3741 double lat_min = (latitude - (
double)lat_deg) * 60.0;
3743 char *str = (
char *)g_malloc(G_ASCII_DTOSTR_BUF_SIZE);
3745 g_ascii_formatd(str, G_ASCII_DTOSTR_BUF_SIZE,
"%08f", long_min);
3746 gchar *long_str = g_strdup_printf(
"%d,%s%c", long_deg, str, long_dir);
3747 g_ascii_formatd(str, G_ASCII_DTOSTR_BUF_SIZE,
"%08f", lat_min);
3748 gchar *lat_str = g_strdup_printf(
"%d,%s%c", lat_deg, str, lat_dir);
3750 xmpData[
"Xmp.exif.GPSVersionID"] =
"2.2.0.0";
3751 xmpData[
"Xmp.exif.GPSLongitude"] = long_str;
3752 xmpData[
"Xmp.exif.GPSLatitude"] = lat_str;
3757 if(!isnan(altitude))
3759 xmpData[
"Xmp.exif.GPSAltitudeRef"] = (altitude < 0) ?
"1" :
"0";
3761 long ele_dm = (int)floor(fabs(10.0 * altitude));
3762 gchar *ele_str = g_strdup_printf(
"%ld/10", ele_dm);
3763 xmpData[
"Xmp.exif.GPSAltitude"] = ele_str;
3775 while(sqlite3_step(stmt) == SQLITE_ROW)
3777 int keyid = sqlite3_column_int(stmt, 0);
3790 sqlite3_finalize(stmt);
3794 std::unique_ptr<Exiv2::Value>
v(Exiv2::Value::create(Exiv2::xmpSeq));
3800 while(sqlite3_step(stmt) == SQLITE_ROW)
3802 snprintf(val,
sizeof(val),
"%d", sqlite3_column_int(stmt, 0));
3805 sqlite3_finalize(stmt);
3806 if(
v->count() > 0) xmpData.add(Exiv2::XmpKey(
"Xmp.darktable.colorlabels"),
v.get());
3825 xmpData[
"Xmp.darktable.history_current_hash"] =
value;
3837 int stars = 1, raw_params = 0, history_end = -1;
3838 double longitude = NAN, latitude = NAN, altitude = NAN;
3839 gchar *filename = NULL;
3840 gchar *iop_order_list = NULL;
3847 "SELECT filename, flags, raw_parameters, "
3848 " longitude, latitude, altitude, history_end, datetime_taken"
3854 if(sqlite3_step(stmt) == SQLITE_ROW)
3856 filename = (gchar *)sqlite3_column_text(stmt, 0);
3857 stars = sqlite3_column_int(stmt, 1);
3858 raw_params = sqlite3_column_int(stmt, 2);
3859 if(sqlite3_column_type(stmt, 3) == SQLITE_FLOAT) longitude = sqlite3_column_double(stmt, 3);
3860 if(sqlite3_column_type(stmt, 4) == SQLITE_FLOAT) latitude = sqlite3_column_double(stmt, 4);
3861 if(sqlite3_column_type(stmt, 5) == SQLITE_FLOAT) altitude = sqlite3_column_double(stmt, 5);
3862 history_end = sqlite3_column_int(stmt, 6);
3863 gts = sqlite3_column_int64(stmt, 7);
3886 xmpData[
"Xmp.exif.DateTimeOriginal"] = exif_datetime;
3889 Exiv2::XmpData::iterator pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.xmp.Rating"));
3890 if(pos != xmpData.end()) xmpData.erase(pos);
3894 if(filename) xmpData[
"Xmp.xmpMM.DerivedFrom"] = filename;
3906 std::unique_ptr<Exiv2::Value> v1(Exiv2::Value::create(Exiv2::xmpBag));
3908 std::unique_ptr<Exiv2::Value> v2(Exiv2::Value::create(Exiv2::xmpBag));
3913 for(GList *tag = tags; tag; tag = g_list_next(tag))
3915 v1->read((
char *)tag->data);
3923 if(v1->count() > 0) xmpData.add(Exiv2::XmpKey(
"Xmp.dc.subject"), v1.get());
3930 for(GList *hier = hierarchical; hier; hier = g_list_next(hier))
3932 v2->read((
char *)hier->data);
3940 if(v2->count() > 0) xmpData.add(Exiv2::XmpKey(
"Xmp.lr.hierarchicalSubject"), v2.get());
3942 hierarchical = NULL;
3945 xmpData[
"Xmp.darktable.xmp_version"] = xmp_version;
3946 xmpData[
"Xmp.darktable.raw_params"] = raw_params;
3948 xmpData[
"Xmp.darktable.auto_presets_applied"] = 1;
3950 xmpData[
"Xmp.darktable.auto_presets_applied"] = 0;
3955 xmpData[
"Xmp.darktable.iop_order_version"] = iop_order_version;
3956 if(iop_order_list) xmpData[
"Xmp.darktable.iop_order_list"] = iop_order_list;
3961 sqlite3_finalize(stmt);
3969 int stars = 1, raw_params = 0, history_end = -1;
3970 double longitude = NAN, latitude = NAN, altitude = NAN;
3971 gchar *filename = NULL;
3973 gchar *iop_order_list = NULL;
3979 "SELECT filename, flags, raw_parameters, "
3980 " longitude, latitude, altitude, history_end, datetime_taken"
3986 if(sqlite3_step(stmt) == SQLITE_ROW)
3988 filename = (gchar *)sqlite3_column_text(stmt, 0);
3989 stars = sqlite3_column_int(stmt, 1);
3990 raw_params = sqlite3_column_int(stmt, 2);
3991 if(sqlite3_column_type(stmt, 3) == SQLITE_FLOAT) longitude = sqlite3_column_double(stmt, 3);
3992 if(sqlite3_column_type(stmt, 4) == SQLITE_FLOAT) latitude = sqlite3_column_double(stmt, 4);
3993 if(sqlite3_column_type(stmt, 5) == SQLITE_FLOAT) altitude = sqlite3_column_double(stmt, 5);
3994 history_end = sqlite3_column_int(stmt, 6);
3995 gts = sqlite3_column_int64(stmt, 7);
4022 xmpData[
"Xmp.exif.DateTimeOriginal"] = exif_datetime;
4025 Exiv2::XmpData::iterator pos = xmpData.findKey(Exiv2::XmpKey(
"Xmp.xmp.Rating"));
4026 if(pos != xmpData.end()) xmpData.erase(pos);
4030 if(filename) xmpData[
"Xmp.xmpMM.DerivedFrom"] = filename;
4048 std::unique_ptr<Exiv2::Value> v1(Exiv2::Value::create(Exiv2::xmpBag));
4052 for(GList *tag = tags; tag; tag = g_list_next(tag))
4054 v1->read((
char *)tag->data);
4062 if(v1->count() > 0) xmpData.add(Exiv2::XmpKey(
"Xmp.dc.subject"), v1.get());
4069 std::unique_ptr<Exiv2::Value> v2(Exiv2::Value::create(Exiv2::xmpBag));
4073 for(GList *hier = hierarchical; hier; hier = g_list_next(hier))
4075 v2->read((
char *)hier->data);
4083 if(v2->count() > 0) xmpData.add(Exiv2::XmpKey(
"Xmp.lr.hierarchicalSubject"), v2.get());
4085 hierarchical = NULL;
4090 xmpData[
"Xmp.darktable.xmp_version"] = xmp_version;
4091 xmpData[
"Xmp.darktable.raw_params"] = raw_params;
4093 xmpData[
"Xmp.darktable.auto_presets_applied"] = 1;
4095 xmpData[
"Xmp.darktable.auto_presets_applied"] = 0;
4100 xmpData[
"Xmp.darktable.iop_order_version"] = iop_order_version;
4101 if(iop_order_list) xmpData[
"Xmp.darktable.iop_order_list"] = iop_order_list;
4106 sqlite3_finalize(stmt);
4110#if EXIV2_TEST_VERSION(0,27,0)
4111#define ERROR_CODE(a) (static_cast<Exiv2::ErrorCode>((a)))
4113#define ERROR_CODE(a) (a)
4120 char input_filename[
PATH_MAX] = { 0 };
4121 gboolean from_cache =
FALSE;
4122 dt_image_full_path(imgid, input_filename,
sizeof(input_filename), &from_cache, __FUNCTION__);
4125 Exiv2::XmpData xmpData;
4126 if(g_file_test(input_filename, G_FILE_TEST_EXISTS))
4128 std::string xmpPacket;
4130 Exiv2::DataBuf buf = Exiv2::readFile(
WIDEN(input_filename));
4131#if EXIV2_TEST_VERSION(0,28,0)
4132 xmpPacket.assign(buf.c_str(), buf.size());
4134 xmpPacket.assign(
reinterpret_cast<char *
>(buf.pData_), buf.size_);
4136 Exiv2::XmpParser::decode(xmpData, xmpPacket);
4144 g_strlcat(input_filename,
".xmp",
sizeof(input_filename));
4145 if(g_file_test(input_filename, G_FILE_TEST_EXISTS))
4147 Exiv2::XmpData sidecarXmpData;
4148 std::string xmpPacket;
4150 Exiv2::DataBuf buf = Exiv2::readFile(
WIDEN(input_filename));
4151#if EXIV2_TEST_VERSION(0,28,0)
4152 xmpPacket.assign(buf.c_str(), buf.size());
4154 xmpPacket.assign(
reinterpret_cast<char *
>(buf.pData_), buf.size_);
4156 Exiv2::XmpParser::decode(sidecarXmpData, xmpPacket);
4158 for(Exiv2::XmpData::const_iterator it = sidecarXmpData.begin(); it != sidecarXmpData.end(); ++it)
4169 std::string xmpPacket;
4170 if(Exiv2::XmpParser::encode(xmpPacket, xmpData,
4171 Exiv2::XmpParser::useCompactFormat | Exiv2::XmpParser::omitPacketWrapper) != 0)
4173 throw Exiv2::Error(
ERROR_CODE(1),
"[xmp_write] failed to serialize xmp data");
4175 return g_strdup(xmpPacket.c_str());
4177 catch(Exiv2::AnyError &e)
4179 std::cerr <<
"[xmp_read_blob] caught exiv2 exception '" << e <<
"'\n";
4188 Exiv2::XmpData::iterator pos = xmp.findKey(Exiv2::XmpKey(
key));
4189 if (pos != xmp.end())
4192 catch(Exiv2::AnyError &e)
4201 const std::string needle =
key;
4202 for(Exiv2::XmpData::iterator
i = xmpData.begin();
i != xmpData.end();)
4204 if(
i->key().compare(0, needle.length(), needle) == 0)
4205 i = xmpData.erase(
i);
4210 catch(Exiv2::AnyError &e)
4219 Exiv2::ExifData::iterator pos = exif.findKey(Exiv2::ExifKey(
key));
4220 if (pos != exif.end())
4223 catch(Exiv2::AnyError &e)
4232 Exiv2::IptcData::iterator pos;
4233 while((pos = iptc.findKey(Exiv2::IptcKey(
key))) != iptc.end())
4236 catch(Exiv2::AnyError &e)
4246 char input_filename[
PATH_MAX] = { 0 };
4247 gboolean from_cache =
TRUE;
4248 dt_image_full_path(imgid, input_filename,
sizeof(input_filename), &from_cache, __FUNCTION__);
4250 std::unique_ptr<Exiv2::Image> img(Exiv2::ImageFactory::open(
WIDEN(filename)));
4259 std::unique_ptr<Exiv2::Image> input_image(Exiv2::ImageFactory::open(
WIDEN(input_filename)));
4260 if(input_image.get() != 0)
4263 img->setIptcData(input_image->iptcData());
4264 img->setXmpData(input_image->xmpData());
4267 catch(Exiv2::AnyError &e)
4269 std::cerr <<
"[xmp_attach] " << input_filename <<
": caught exiv2 exception '" << e <<
"'\n";
4272 Exiv2::XmpData &xmpData = img->xmpData();
4276 g_strlcat(input_filename,
".xmp",
sizeof(input_filename));
4277 if(g_file_test(input_filename, G_FILE_TEST_EXISTS))
4279 Exiv2::XmpData sidecarXmpData;
4280 std::string xmpPacket;
4282 Exiv2::DataBuf buf = Exiv2::readFile(
WIDEN(input_filename));
4283#if EXIV2_TEST_VERSION(0,28,0)
4284 xmpPacket.assign(buf.c_str(), buf.size());
4286 xmpPacket.assign(
reinterpret_cast<char *
>(buf.pData_), buf.size_);
4288 Exiv2::XmpParser::decode(sidecarXmpData, xmpPacket);
4290 for(Exiv2::XmpData::const_iterator it = sidecarXmpData.begin(); it != sidecarXmpData.end(); ++it)
4299 static const char *keys[] = {
4300 "Xmp.tiff.Orientation"
4302 static const guint n_keys = G_N_ELEMENTS(keys);
4311 Exiv2::ExifData exifOldData;
4312 Exiv2::ExifData &exifData = img->exifData();
4315 for(Exiv2::ExifData::const_iterator
i = exifData.begin();
i != exifData.end() ; ++
i)
4317 exifOldData[
i->key()] =
i->value();
4319 img->clearExifData();
4324 Exiv2::IptcData &iptcData = img->iptcData();
4331 params->filename = input_filename;
4332 params->jobcode =
"infos";
4333 params->sequence = 0;
4334 params->imgid = imgid;
4337 for (GList *tags =
m->list; tags; tags = g_list_next(tags))
4339 gchar *tagname = (gchar *)tags->data;
4340 tags = g_list_next(tags);
4342 gchar *formula = (gchar *)tags->data;
4345 if(!(
m->flags &
DT_META_EXIF) && (formula[0] ==
'=') && g_str_has_prefix(tagname,
"Exif."))
4348 Exiv2::ExifData::const_iterator pos;
4351 exifData[tagname] = pos->value();
4357 if(result && result[0])
4359 if(g_str_has_prefix(tagname,
"Xmp."))
4364 if(!g_strcmp0(
type,
"XmpBag") || !g_strcmp0(
type,
"XmpSeq"))
4366 char *tuple = g_strrstr(result,
",");
4371 xmpData[tagname] = tuple;
4372 tuple = g_strrstr(result,
",");
4375 xmpData[tagname] = result;
4377 else if(g_str_has_prefix(tagname,
"Iptc."))
4380 if(!g_strcmp0(
type,
"String-R"))
4386 Exiv2::IptcKey
key(tagname);
4387 Exiv2::Iptcdatum id(
key);
4388 gchar **values = g_strsplit(result,
", ", 0);
4391 gchar **entry = values;
4394 char *e = g_strstrip(*entry);
4405 else iptcData[tagname] = result;
4407 else if(g_str_has_prefix(tagname,
"Exif."))
4410 if((!g_strcmp0(
type,
"Rational") || !g_strcmp0(
type,
"SRational")) &&
4411 (g_strstr_len(result, strlen(result),
"/") == NULL))
4413 float float_value = (float)std::atof(result);
4414 if(!isnan(float_value))
4417 int int_value = (int)float_value;
4419 while(fabs(float_value - int_value) > 0.000001)
4422 float_value *= 10.0;
4423 int_value = (int)float_value;
4425 result = g_strdup_printf(
"%d/%d", (
int)float_value, divisor);
4428 exifData[tagname] = result;
4436 if (g_str_has_prefix(tagname,
"Xmp."))
4438 else if (g_str_has_prefix(tagname,
"Exif."))
4440 else if (g_str_has_prefix(tagname,
"Iptc."))
4449 img->writeMetadata();
4451 catch(Exiv2::AnyError &e)
4453#if EXIV2_TEST_VERSION(0,27,0)
4454 if(e.code() == Exiv2::ErrorCode::kerTooLargeJpegSegment)
4465 img->writeMetadata();
4467 catch(Exiv2::AnyError &e2)
4469 std::cerr <<
"[dt_exif_xmp_attach_export] without history " << filename <<
": caught exiv2 exception '" << e2 <<
"'\n";
4478 catch(Exiv2::AnyError &e)
4480 std::cerr <<
"[dt_exif_xmp_attach_export] " << filename <<
": caught exiv2 exception '" << e <<
"'\n";
4487 const char *imgpath)
4492 if(!g_file_test(imgpath, G_FILE_TEST_IS_REGULAR))
return 1;
4493 const int32_t imgid = image->
id;
4497 Exiv2::XmpData xmpData;
4498 std::string xmpPacket;
4499 char *checksum_old = NULL;
4500 if(g_file_test(filename, G_FILE_TEST_EXISTS))
4507 unsigned char *content = (
unsigned char*)
dt_read_file(filename, &end);
4512 dt_control_log(_(
"The XMP file \n'%s'\n weighs %.2f MB. Writing it will take some time."), filename, (
float)end / 1000000);
4513 fprintf(stdout,
"The XMP file '%s' weighs %.2f MB. Writing it will take some time.\n", filename, (
float)end / 1000000);
4516 checksum_old = g_compute_checksum_for_data(G_CHECKSUM_MD5, content, end);
4521 fprintf(stderr,
"cannot read xmp file '%s': '%s'\n", filename, strerror(errno));
4522 dt_control_log(_(
"cannot read xmp file '%s': '%s'"), filename, strerror(errno));
4525 Exiv2::DataBuf buf = Exiv2::readFile(
WIDEN(filename));
4526#if EXIV2_TEST_VERSION(0,28,0)
4527 xmpPacket.assign(buf.c_str(), buf.size());
4529 xmpPacket.assign(
reinterpret_cast<char *
>(buf.pData_), buf.size_);
4531 Exiv2::XmpParser::decode(xmpData, xmpPacket);
4541 if(Exiv2::XmpParser::encode(xmpPacket, xmpData,
4542 Exiv2::XmpParser::useCompactFormat | Exiv2::XmpParser::omitPacketWrapper) != 0)
4544 throw Exiv2::Error(
ERROR_CODE(1),
"[xmp_write] failed to serialize xmp data");
4548 const char *xml_header =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
4549 gboolean write_sidecar =
TRUE;
4552 GChecksum *checksum = g_checksum_new(G_CHECKSUM_MD5);
4555 g_checksum_update(checksum, (
unsigned char*)xml_header, -1);
4556 g_checksum_update(checksum, (
unsigned char*)xmpPacket.c_str(), -1);
4557 const char *checksum_new = g_checksum_get_string(checksum);
4558 write_sidecar = g_strcmp0(checksum_old, checksum_new) != 0;
4559 g_checksum_free(checksum);
4568 FILE *fout = g_fopen(filename,
"wb");
4571 fprintf(fout,
"%s", xml_header);
4572 fprintf(fout,
"%s", xmpPacket.c_str());
4577 fprintf(stderr,
"cannot write xmp file '%s': '%s'\n", filename, strerror(errno));
4578 dt_control_log(_(
"cannot write xmp file '%s': '%s'"), filename, strerror(errno));
4585 catch(Exiv2::AnyError &e)
4587 std::cerr <<
"[dt_exif_xmp_write] " << filename <<
": caught exiv2 exception '" << e <<
"'\n";
4596 Exiv2::ExifData::const_iterator pos;
4597 Exiv2::ExifData exifData;
4598 Exiv2::ExifParser::decode(exifData, data,
size);
4606 if((pos = exifData.findKey(Exiv2::ExifKey(
"Exif.Photo.ColorSpace"))) != exifData.end() && pos->size())
4608 int colorspace = pos->toLong();
4609 if(colorspace == 0x01)
4611 else if(colorspace == 0x02)
4613 else if(colorspace == 0xffff)
4615 if((pos = exifData.findKey(Exiv2::ExifKey(
"Exif.Iop.InteroperabilityIndex"))) != exifData.end()
4618 std::string interop_index = pos->toString();
4619 if(interop_index ==
"R03")
4621 else if(interop_index ==
"R98")
4629 catch(Exiv2::AnyError &e)
4631 std::string s(e.what());
4632 std::cerr <<
"[exiv2 dt_exif_get_color_space] " << s << std::endl;
4641 Exiv2::ExifData::const_iterator pos;
4642 std::unique_ptr<Exiv2::Image> image(Exiv2::ImageFactory::open(data,
size));
4644 Exiv2::ExifData &exifData = image->exifData();
4648 catch(Exiv2::AnyError &e)
4650 std::string s(e.what());
4651 std::cerr <<
"[exiv2 dt_exif_get_datetime_taken] " << s << std::endl;
4657 if(log_level >= Exiv2::LogMsg::level())
4672 #if !EXIV2_TEST_VERSION(0,28,0)
4673 #ifdef HAVE_LIBEXIV2_WITH_ISOBMFF
4674 Exiv2::enableBMFF();
4679 #if !EXIV2_TEST_VERSION(0,28,0)
4680 Exiv2::XmpParser::initialize();
4683 Exiv2::XmpProperties::registerNs(
"http://darktable.sf.net/",
"darktable");
4687 Exiv2::XmpProperties::propertyList(
"lr");
4689 catch(Exiv2::AnyError &e)
4692 Exiv2::XmpProperties::registerNs(
"http://ns.adobe.com/lightroom/1.0/",
"lr");
4696 Exiv2::XmpProperties::propertyList(
"exifEX");
4698 catch(Exiv2::AnyError &e)
4701 Exiv2::XmpProperties::registerNs(
"http://cipa.jp/exif/1.0/",
"exifEX");
4708 #if !EXIV2_TEST_VERSION(0,28,0)
4709 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,...)