Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
image_cache.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2012, 2014 johannes hanika.
4 Copyright (C) 2010-2011 Henrik Andersson.
5 Copyright (C) 2010-2014, 2016 Tobias Ellinghaus.
6 Copyright (C) 2011 Robert Bieber.
7 Copyright (C) 2011 Rostyslav Pidgornyi.
8 Copyright (C) 2012 Richard Wonka.
9 Copyright (C) 2013 Simon Spannagel.
10 Copyright (C) 2013 Ulrich Pegelow.
11 Copyright (C) 2014-2015 Pedro Côrte-Real.
12 Copyright (C) 2014-2016 Roman Lebedev.
13 Copyright (C) 2018 Edgardo Hoszowski.
14 Copyright (C) 2019 Andreas Schneider.
15 Copyright (C) 2019 August Schwerdfeger.
16 Copyright (C) 2019 Bill Ferguson.
17 Copyright (C) 2019-2020 Hanno Schwalm.
18 Copyright (C) 2019-2022 Pascal Obry.
19 Copyright (C) 2020 Heiko Bauke.
20 Copyright (C) 2020 JP Verrue.
21 Copyright (C) 2020, 2022 Philippe Weyland.
22 Copyright (C) 2021 Aldric Renaudin.
23 Copyright (C) 2021 Vincent THOMAS.
24 Copyright (C) 2022 Martin Bařinka.
25 Copyright (C) 2022 paolodepetrillo.
26 Copyright (C) 2022 Philipp Lutz.
27 Copyright (C) 2025-2026 Aurélien PIERRE.
28
29 darktable is free software: you can redistribute it and/or modify
30 it under the terms of the GNU General Public License as published by
31 the Free Software Foundation, either version 3 of the License, or
32 (at your option) any later version.
33
34 darktable is distributed in the hope that it will be useful,
35 but WITHOUT ANY WARRANTY; without even the implied warranty of
36 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 GNU General Public License for more details.
38
39 You should have received a copy of the GNU General Public License
40 along with darktable. If not, see <http://www.gnu.org/licenses/>.
41*/
42
43#include "common/image_cache.h"
44#include "common/colorlabels.h"
45#include "common/darktable.h"
46#include "common/debug.h"
47#include "common/exif.h"
48#include "common/image.h"
49#include "common/imageio.h"
50#include "common/datetime.h"
51#include "control/conf.h"
52#include "control/control.h"
53#include "control/jobs.h"
54#include "control/signal.h"
55#include "develop/develop.h"
56
57#include <sqlite3.h>
58#include <inttypes.h>
59#include <math.h>
60
61static sqlite3_stmt *_image_cache_load_stmt = NULL;
62static sqlite3_stmt *_image_cache_write_history_hash_stmt = NULL;
63static dt_pthread_mutex_t _image_cache_stmt_mutex;
65
66static inline void _image_cache_stmt_mutex_ensure(void)
67{
68 if(g_once_init_enter(&_image_cache_stmt_mutex_inited))
69 {
71 g_once_init_leave(&_image_cache_stmt_mutex_inited, 1);
72 }
73}
74
76{
77 struct
78 {
79 dt_image_orientation_t orientation;
80 float exif_exposure;
81 float exif_exposure_bias;
82 float exif_aperture;
83 float exif_iso;
84 float exif_focal_length;
85 float exif_focus_distance;
86 float exif_crop;
87 char exif_maker[64];
88 char exif_model[64];
89 char exif_lens[128];
90 GTimeSpan exif_datetime_taken;
91 char filename[DT_MAX_FILENAME_LEN];
92 int32_t width, height;
93 int32_t crop_x, crop_y, crop_width, crop_height;
94 int32_t flags, film_id, id, group_id, version;
95 uint64_t history_hash;
96 float d65_color_matrix[9];
97 dt_image_colorspace_t colorspace;
98 dt_image_raw_parameters_t legacy_flip;
99 dt_image_geoloc_t geoloc;
100 uint16_t raw_black_level;
101 uint32_t raw_white_point;
102 int color_labels;
103 } persisted = { 0 };
104
105 /*
106 * Track only the dt_image_t fields that are explicitly written back to the database
107 * from dt_image_cache_write_release(), plus the history hash and color labels that
108 * are flushed through their own SQL paths right below it. Runtime-only fields such
109 * as cached ICC pointers, DNG gain-map lists, loader state or derived path strings
110 * must stay out of this hash, otherwise merely opening an image can look like an
111 * edit and spuriously bump change_timestamp.
112 */
113 persisted.orientation = img->orientation;
114 persisted.exif_exposure = img->exif_exposure;
115 persisted.exif_exposure_bias = img->exif_exposure_bias;
116 persisted.exif_aperture = img->exif_aperture;
117 persisted.exif_iso = img->exif_iso;
118 persisted.exif_focal_length = img->exif_focal_length;
119 persisted.exif_focus_distance = img->exif_focus_distance;
120 persisted.exif_crop = img->exif_crop;
121 memcpy(persisted.exif_maker, img->exif_maker, sizeof(persisted.exif_maker));
122 memcpy(persisted.exif_model, img->exif_model, sizeof(persisted.exif_model));
123 memcpy(persisted.exif_lens, img->exif_lens, sizeof(persisted.exif_lens));
124 persisted.exif_datetime_taken = img->exif_datetime_taken;
125 memcpy(persisted.filename, img->filename, sizeof(persisted.filename));
126 persisted.width = img->width;
127 persisted.height = img->height;
128 persisted.crop_x = img->crop_x;
129 persisted.crop_y = img->crop_y;
130 persisted.crop_width = img->crop_width;
131 persisted.crop_height = img->crop_height;
132 persisted.flags = img->flags;
133 persisted.film_id = img->film_id;
134 persisted.id = img->id;
135 persisted.group_id = img->group_id;
136 persisted.version = img->version;
137 persisted.history_hash = img->history_hash;
138 memcpy(persisted.d65_color_matrix, img->d65_color_matrix, sizeof(persisted.d65_color_matrix));
139 persisted.colorspace = img->colorspace;
140 persisted.legacy_flip = img->legacy_flip;
141 persisted.geoloc = img->geoloc;
142 persisted.raw_black_level = img->raw_black_level;
143 persisted.raw_white_point = img->raw_white_point;
144 persisted.color_labels = img->color_labels;
145
146 return dt_hash(5381, (const char *)&persisted, sizeof(persisted));
147}
148
149static inline void _image_cache_lock_init(dt_image_t *img)
150{
152}
153
155{
156 if(IS_NULL_PTR(img) || img->id <= 0) return;
157
161 {
162 // clang-format off
165 "INSERT INTO main.history_hash (imgid, current_hash, basic_hash, auto_hash, mipmap_hash)"
166 " VALUES (?1, ?2, NULL, NULL, ?3)"
167 " ON CONFLICT (imgid)"
168 " DO UPDATE SET current_hash = ?2, basic_hash = NULL, auto_hash = NULL, mipmap_hash = ?3",
170 // clang-format on
171 }
172 sqlite3_stmt *stmt = _image_cache_write_history_hash_stmt;
173 sqlite3_reset(stmt);
174 sqlite3_clear_bindings(stmt);
175 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, img->id);
176 DT_DEBUG_SQLITE3_BIND_INT64(stmt, 2, (sqlite3_int64)img->history_hash);
177 DT_DEBUG_SQLITE3_BIND_INT64(stmt, 3, (sqlite3_int64)img->mipmap_hash);
178 sqlite3_step(stmt);
180}
181
182static sqlite3_stmt *_image_cache_get_stmt(void)
183{
185 {
186 // clang-format off
189 "SELECT i.id, i.group_id, "
190 " (SELECT COUNT(id) FROM main.images WHERE group_id = i.group_id), "
191 " (SELECT COUNT(imgid) FROM main.history WHERE imgid = i.id), "
192 " COALESCE((SELECT current_hash FROM main.history_hash WHERE imgid = i.id), -1), "
193 " COALESCE((SELECT mipmap_hash FROM main.history_hash WHERE imgid = i.id), -1), "
194 " i.film_id, i.version, i.width, i.height, i.orientation, i.flags, "
195 " i.import_timestamp, i.change_timestamp, i.export_timestamp, i.print_timestamp, "
196 " i.exposure, i.exposure_bias, i.aperture, i.iso, i.focal_length, i.focus_distance, "
197 " i.datetime_taken, i.longitude, i.latitude, i.altitude, "
198 " i.filename, f.folder || '" G_DIR_SEPARATOR_S "' || i.filename, "
199 " i.maker, i.model, i.lens, f.folder, "
200 " COALESCE((SELECT SUM(1 << color) FROM main.color_labels WHERE imgid=i.id), 0), "
201 " i.crop, i.raw_parameters, i.color_matrix, i.colorspace, "
202 " i.raw_black, i.raw_maximum, i.aspect_ratio, i.output_width, i.output_height"
203 " FROM main.images AS i"
204 " LEFT JOIN main.film_rolls AS f ON f.id = i.film_id"
205 " WHERE i.id = ?1",
206 -1, &_image_cache_load_stmt, NULL);
207 // clang-format on
208 }
209
210 sqlite3_reset(_image_cache_load_stmt);
211 sqlite3_clear_bindings(_image_cache_load_stmt);
213}
214
215void dt_image_from_stmt(dt_image_t *img, sqlite3_stmt *stmt)
216{
217 if(sqlite3_column_type(stmt, 0) != SQLITE_NULL) img->id = sqlite3_column_int(stmt, 0);
218 if(sqlite3_column_type(stmt, 1) != SQLITE_NULL) img->group_id = sqlite3_column_int(stmt, 1);
219 if(sqlite3_column_type(stmt, 2) != SQLITE_NULL) img->group_members = (uint32_t)sqlite3_column_int(stmt, 2);
220 if(sqlite3_column_type(stmt, 3) != SQLITE_NULL) img->history_items = (uint32_t)sqlite3_column_int(stmt, 3);
221 if(sqlite3_column_type(stmt, 4) != SQLITE_NULL) img->history_hash = sqlite3_column_int64(stmt, 4);
222 if(sqlite3_column_type(stmt, 5) != SQLITE_NULL) img->mipmap_hash = sqlite3_column_int64(stmt, 5);
223 if(sqlite3_column_type(stmt, 6) != SQLITE_NULL) img->film_id = sqlite3_column_int(stmt, 6);
224 if(sqlite3_column_type(stmt, 7) != SQLITE_NULL) img->version = sqlite3_column_int(stmt, 7);
225 if(sqlite3_column_type(stmt, 8) != SQLITE_NULL) img->width = sqlite3_column_int(stmt, 8);
226 if(sqlite3_column_type(stmt, 9) != SQLITE_NULL) img->height = sqlite3_column_int(stmt, 9);
227 if(sqlite3_column_type(stmt, 10) != SQLITE_NULL) img->orientation = sqlite3_column_int(stmt, 10);
228 if(sqlite3_column_type(stmt, 11) != SQLITE_NULL) img->flags = sqlite3_column_int(stmt, 11);
229 if(sqlite3_column_type(stmt, 12) != SQLITE_NULL) img->import_timestamp = sqlite3_column_int64(stmt, 12);
230 if(sqlite3_column_type(stmt, 13) != SQLITE_NULL) img->change_timestamp = sqlite3_column_int64(stmt, 13);
231 if(sqlite3_column_type(stmt, 14) != SQLITE_NULL) img->export_timestamp = sqlite3_column_int64(stmt, 14);
232 if(sqlite3_column_type(stmt, 15) != SQLITE_NULL) img->print_timestamp = sqlite3_column_int64(stmt, 15);
233 if(sqlite3_column_type(stmt, 16) != SQLITE_NULL) img->exif_exposure = sqlite3_column_double(stmt, 16);
234 if(sqlite3_column_type(stmt, 17) != SQLITE_NULL) img->exif_exposure_bias = sqlite3_column_double(stmt, 17);
235 if(sqlite3_column_type(stmt, 18) != SQLITE_NULL) img->exif_aperture = sqlite3_column_double(stmt, 18);
236 if(sqlite3_column_type(stmt, 19) != SQLITE_NULL) img->exif_iso = sqlite3_column_double(stmt, 19);
237 if(sqlite3_column_type(stmt, 20) != SQLITE_NULL) img->exif_focal_length = sqlite3_column_double(stmt, 20);
238 if(sqlite3_column_type(stmt, 21) != SQLITE_NULL) img->exif_focus_distance = sqlite3_column_double(stmt, 21);
239 if(sqlite3_column_type(stmt, 22) != SQLITE_NULL) img->exif_datetime_taken = sqlite3_column_int64(stmt, 22);
240 if(sqlite3_column_type(stmt, 23) != SQLITE_NULL) img->geoloc.longitude = sqlite3_column_double(stmt, 23);
241 if(sqlite3_column_type(stmt, 24) != SQLITE_NULL) img->geoloc.latitude = sqlite3_column_double(stmt, 24);
242 if(sqlite3_column_type(stmt, 25) != SQLITE_NULL) img->geoloc.elevation = sqlite3_column_double(stmt, 25);
243
244 const char *filename = (const char *)sqlite3_column_text(stmt, 26);
245 if(filename) g_strlcpy(img->filename, filename, sizeof(img->filename));
246 const char *fullpath = (const char *)sqlite3_column_text(stmt, 27);
247 if(fullpath) g_strlcpy(img->fullpath, fullpath, sizeof(img->fullpath));
248 const char *maker = (const char *)sqlite3_column_text(stmt, 28);
249 if(maker) g_strlcpy(img->exif_maker, maker, sizeof(img->exif_maker));
250 const char *model = (const char *)sqlite3_column_text(stmt, 29);
251 if(model) g_strlcpy(img->exif_model, model, sizeof(img->exif_model));
252 const char *lens = (const char *)sqlite3_column_text(stmt, 30);
253 if(lens) g_strlcpy(img->exif_lens, lens, sizeof(img->exif_lens));
254 const char *folder = (const char *)sqlite3_column_text(stmt, 31);
255 if(folder) g_strlcpy(img->folder, folder, sizeof(img->folder));
256
257 if(sqlite3_column_type(stmt, 32) != SQLITE_NULL) img->color_labels = sqlite3_column_int(stmt, 32);
258
259 if(sqlite3_column_type(stmt, 33) != SQLITE_NULL) img->exif_crop = sqlite3_column_double(stmt, 33);
260 if(sqlite3_column_type(stmt, 34) != SQLITE_NULL)
261 {
262 uint32_t tmp = sqlite3_column_int(stmt, 34);
263 memcpy(&img->legacy_flip, &tmp, sizeof(dt_image_raw_parameters_t));
264 }
265 const void *color_matrix = sqlite3_column_blob(stmt, 35);
266 if(color_matrix) memcpy(img->d65_color_matrix, color_matrix, sizeof(img->d65_color_matrix));
267 if(sqlite3_column_type(stmt, 36) != SQLITE_NULL) img->colorspace = sqlite3_column_int(stmt, 36);
268 if(sqlite3_column_type(stmt, 37) != SQLITE_NULL) img->raw_black_level = sqlite3_column_int(stmt, 37);
269 if(sqlite3_column_type(stmt, 38) != SQLITE_NULL) img->raw_white_point = sqlite3_column_int(stmt, 38);
270
271 if(img->fullpath[0])
273 sizeof(img->local_copy_path), img->local_copy_legacy_path,
274 sizeof(img->local_copy_legacy_path));
275
276 img->exif_inited = (img->exif_focus_distance >= 0 && img->orientation >= 0);
277
278 if(img->folder[0])
279 g_strlcpy(img->filmroll, dt_image_film_roll_name(img->folder), sizeof(img->filmroll));
280
282
283 // img->dsc are written by imageio drivers : never (re)set them from DB,
284 // they are not saved anyway. Until the codec decodes the file, seed a provisional
285 // descriptor from the (extension-derived) pipeline class so the image can be reasoned
286 // about and the first pipeline stage has a usable contract even before decoding.
288
290 img->has_audio = (img->flags & DT_IMAGE_HAS_WAV);
291 int xmp_rating = dt_image_get_xmp_rating_from_flags(img->flags);
292 img->rating = (xmp_rating == -1) ? DT_VIEW_REJECT : xmp_rating;
295 img->is_hdr = dt_image_is_hdr(img);
296
297 // Instrumentation: the LDR/HDR flags are now pure flag predicates (no filename sniffing at read
298 // time). Historically the flag could have been mis-set at import, so cross-check the flags loaded
299 // from the DB against the unambiguous extension hint and log any contradiction. Containers whose
300 // dynamic range only the decoder can settle (TIFF/AVIF/HEIF/DNG ...) return 0 here and are skipped
301 // to avoid false positives. This surfaces stale/garbage flags persisted in the database.
302 {
303 const gchar *ext = g_strrstr(img->filename, ".");
304 const dt_image_flags_t ext_hint = ext ? dt_imageio_get_type_from_extension(ext) : 0;
305 const gboolean db_hdr = (img->flags & DT_IMAGE_HDR) != 0;
306 const gboolean db_ldr = (img->flags & DT_IMAGE_LDR) != 0;
307
308 if(ext_hint == DT_IMAGE_HDR && !db_hdr)
310 "[image_cache] DB flag mismatch: id=%d filename='%s' has an HDR extension but stored "
311 "flags=0x%08x lack DT_IMAGE_HDR (ldr=%d hdr=%d)\n",
312 img->id, img->filename, (unsigned int)img->flags, db_ldr, db_hdr);
313 else if((ext_hint == DT_IMAGE_LDR || ext_hint == DT_IMAGE_RAW) && db_hdr)
315 "[image_cache] DB flag mismatch: id=%d filename='%s' has a %s extension but stored "
316 "flags=0x%08x carry DT_IMAGE_HDR (ldr=%d hdr=%d)\n",
317 img->id, img->filename, (ext_hint == DT_IMAGE_RAW) ? "RAW" : "LDR",
318 (unsigned int)img->flags, db_ldr, db_hdr);
319 }
320
322}
323
324static void _image_cache_reload_from_db(dt_image_t *img, const uint32_t imgid)
325{
328
329 sqlite3_stmt *stmt = _image_cache_get_stmt();
330 sqlite3_reset(stmt);
331 sqlite3_clear_bindings(stmt);
332 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
333 if(sqlite3_step(stmt) == SQLITE_ROW)
334 {
335 dt_image_from_stmt(img, stmt);
336
337 /* Deprecated:
338 if(sqlite3_column_type(stmt, 37) == SQLITE_FLOAT)
339 img->aspect_ratio = sqlite3_column_double(stmt, 37);
340 else
341 img->aspect_ratio = 0.0;
342 */
343
344 /* Deprecated:
345 img->final_width = sqlite3_column_int(stmt, 33);
346 img->final_height = sqlite3_column_int(stmt, 34);
347 */
348 }
349 else
350 {
351 img->id = -1;
352 fprintf(stderr, "[image_cache_reload] failed to open image %" PRIu32 " from database: %s\n", imgid,
353 sqlite3_errmsg(dt_database_get(darktable.db)));
354 }
355
357}
358
360{
361 entry->cost = sizeof(dt_image_t);
362
363 dt_image_t *img = (dt_image_t *)g_malloc(sizeof(dt_image_t));
364 entry->data = img;
365 dt_image_init(img);
366 _image_cache_reload_from_db(img, entry->key);
367
368 img->cache_entry = entry; // init backref
369}
370
372{
373 dt_image_t *img = (dt_image_t *)entry->data;
374 dt_free(img->profile);
375 g_list_free_full(img->dng_gain_maps, dt_free_gpointer);
376 img->dng_gain_maps = NULL;
377 dt_free(img);
378}
379
381{
382 // the image cache does no serialization.
383 // (unsafe. data should be in db/xmp, not in any other additional cache,
384 // also, it should be relatively fast to get the image_t structs from sql.)
385 // TODO: actually an independent conf var?
386 // too large: dangerous and wasteful?
387 // can we get away with a fixed size?
388 const uint32_t size = 50;
389 const uint32_t max_mem = size * 1024 * 1024;
390 const uint32_t num = (uint32_t)(1.5f * max_mem / sizeof(dt_image_t));
391 dt_cache_init(&cache->cache, sizeof(dt_image_t), max_mem);
394
395 dt_print(DT_DEBUG_CACHE, "[image_cache] has %d entries (%u MiB)\n", num, size);
396}
397
418
420{
421 printf("[image cache] fill %.2f/%.2f MB (%.2f%%)\n", cache->cache.cost / (1024.0 * 1024.0),
422 cache->cache.cost_quota / (1024.0 * 1024.0),
423 (float)cache->cache.cost / (float)cache->cache.cost_quota);
424}
425
426dt_image_t *dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
427{
428 if(imgid <= 0) return NULL;
429 dt_cache_entry_t *entry = dt_cache_get(&cache->cache, (uint32_t)imgid, mode);
431 dt_image_t *img = (dt_image_t *)entry->data;
432 img->cache_entry = entry;
433
434 if(dt_image_invalid(img))
435 {
436 dt_cache_release(&cache->cache, entry);
437 return NULL;
438 }
439
441 return img;
442}
443
444dt_image_t *dt_image_cache_testget(dt_image_cache_t *cache, const int32_t imgid, char mode)
445{
446 if(imgid <= 0) return NULL;
447 dt_cache_entry_t *entry = dt_cache_testget(&cache->cache, (uint32_t)imgid, mode);
448 if(IS_NULL_PTR(entry)) return 0;
450 dt_image_t *img = (dt_image_t *)entry->data;
451 img->cache_entry = entry;
453 return img;
454}
455
456// Always reload the cache entry from DB before returning it.
457// This is critical for IMAGE_INFO_CHANGED: other handlers will read from the cache.
458dt_image_t *dt_image_cache_get_reload(dt_image_cache_t *cache, const int32_t imgid, char mode)
459{
460 if(imgid <= 0) return NULL;
461
462 // We must take a write lock to reload in-place, then demote to read if requested.
463 dt_cache_entry_t *entry = dt_cache_get(&cache->cache, (uint32_t)imgid, 'w');
465 dt_image_t *img = (dt_image_t *)entry->data;
466 _image_cache_reload_from_db(img, (uint32_t)imgid);
467
468 img->cache_entry = entry;
469
470 if(dt_image_invalid(img))
471 {
472 dt_cache_release(&cache->cache, entry);
473 return NULL;
474 }
475
476 if(mode == 'r')
477 {
478 // demote the lock to read mode (see mipmap cache for rationale)
479 entry->_lock_demoting = 1;
480 dt_cache_release(&cache->cache, entry);
481 entry = dt_cache_get(&cache->cache, (uint32_t)imgid, 'r');
482 entry->_lock_demoting = 0;
484 img = (dt_image_t *)entry->data;
485 img->cache_entry = entry;
486 }
487
489 return img;
490}
491
493{
494 return (IS_NULL_PTR(img) || img->id <= 0);
495}
496
498{
499 if(IS_NULL_PTR(cache) || dt_image_invalid(img)) return -1;
500
501 dt_image_t seeded = *img;
502
503 // Avoid ownership issues for pointers that the cache cleanup would free.
504 seeded.profile = NULL;
505 seeded.profile_size = 0;
506 seeded.dng_gain_maps = NULL;
507 seeded.cache_entry = NULL;
508
509 return dt_cache_seed(&cache->cache, (uint32_t)seeded.id, &seeded, sizeof(dt_image_t), sizeof(dt_image_t), FALSE);
510}
511
512// This callback must run before any other DT_SIGNAL_IMAGE_INFO_CHANGED handler.
513// The signal notifies about DB changes, and most listeners read image info from the cache.
514// We therefore force a DB reload here so every subsequent handler sees up-to-date data.
515static void _image_cache_info_changed_reload_callback(gpointer instance, gpointer imgs, gpointer user_data)
516{
517 for(GList *l = g_list_first((GList *)imgs); l; l = g_list_next(l))
518 {
519 const int32_t imgid = GPOINTER_TO_INT(l->data);
520 if(imgid <= 0) continue;
521
523 if(img)
525 }
526}
527
529{
530 // Must be connected early to run before any other handler.
533}
534
535// drops the read lock on an image struct
537{
538 if(IS_NULL_PTR(img) || img->id <= 0) return;
539 const uint64_t self_hash = _image_cache_self_hash(img);
540 if(self_hash != img->self_hash)
541 g_error("[image_cache] read lock modified image %d, you need to use a write lock\n", img->id);
542
543 // just force the dt_image_t struct to make sure it has been locked before.
544 dt_cache_release(&cache->cache, img->cache_entry);
545}
546
547// drops the write privileges on an image struct.
548// this triggers a write-through to sql, and optionally queues xmp sidecar writing.
550{
551 union {
553 uint32_t u;
554 } flip;
555 if(img->id <= 0) return;
556
557 const uint64_t self_hash = _image_cache_self_hash(img);
558 const gboolean changed = (self_hash != img->self_hash);
559
560 if(changed)
562
563 // even if nothing changed, we might need to write export/print timestamps
564 // and mipmap hash, so we can't exit just yet.
565
566 if(mode == DT_IMAGE_CACHE_MINIMAL)
567 {
568 if(changed)
569 g_error("[image_cache] minimal write release modified image %d, you need to commit those changes to DB.\n", img->id);
570
571 dt_cache_release(&cache->cache, img->cache_entry);
572 return;
573 }
574
575 // Recompute full/local copy paths (and derived folder/filmroll/datetime) from possibly updated filename.
576 // Avoid SQL here; rely on the cached folder/fullpath, or leave fields empty if they can't be rebuilt.
577 char folder[PATH_MAX] = { 0 };
578 if(img->folder[0])
579 {
580 g_strlcpy(folder, img->folder, sizeof(folder));
581 }
582 else if(img->fullpath[0])
583 {
584 gchar *dir = g_path_get_dirname(img->fullpath);
585 if(dir && dir[0] && strcmp(dir, "."))
586 g_strlcpy(folder, dir, sizeof(folder));
587 dt_free(dir);
588 }
589
590 if(img->filename[0] && folder[0])
591 {
592 g_snprintf(img->fullpath, sizeof(img->fullpath), "%s" G_DIR_SEPARATOR_S "%s", folder, img->filename);
593 g_strlcpy(img->folder, folder, sizeof(img->folder));
594 }
595 else
596 {
597 img->fullpath[0] = '\0';
598 img->folder[0] = '\0';
599 }
600 if(img->folder[0])
601 g_strlcpy(img->filmroll, dt_image_film_roll_name(img->folder), sizeof(img->filmroll));
602 else if(img->film_id < 0)
603 g_strlcpy(img->filmroll, _("orphaned image"), sizeof(img->filmroll));
604 else
605 img->filmroll[0] = '\0';
608 sizeof(img->local_copy_path), img->local_copy_legacy_path,
609 sizeof(img->local_copy_legacy_path));
610
612 img->has_audio = (img->flags & DT_IMAGE_HAS_WAV);
613 int xmp_rating = dt_image_get_xmp_rating_from_flags(img->flags);
614 img->rating = (xmp_rating == -1) ? DT_VIEW_REJECT : xmp_rating;
617 img->is_hdr = dt_image_is_hdr(img);
618
619 sqlite3_stmt *stmt;
620 // clang-format off
622 "UPDATE main.images"
623 " SET width = ?1, height = ?2, filename = ?3, maker = ?4, model = ?5,"
624 " lens = ?6, exposure = ?7, aperture = ?8, iso = ?9, focal_length = ?10,"
625 " focus_distance = ?11, film_id = ?12, datetime_taken = ?13, flags = ?14,"
626 " crop = ?15, orientation = ?16, raw_parameters = ?17, group_id = ?18,"
627 " longitude = ?19, latitude = ?20, altitude = ?21, color_matrix = ?22,"
628 " colorspace = ?23, raw_black = ?24, raw_maximum = ?25,"
629 " aspect_ratio = ROUND(?26,1), exposure_bias = ?27,"
630 " import_timestamp = ?28, change_timestamp = ?29, export_timestamp = ?30,"
631 " print_timestamp = ?31, output_width = ?32, output_height = ?33"
632 " WHERE id = ?34",
633 -1, &stmt, NULL);
634 // clang-format on
635 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, img->width);
636 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, img->height);
637 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 3, img->filename, -1, SQLITE_STATIC);
638 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 4, img->exif_maker, -1, SQLITE_STATIC);
639 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 5, img->exif_model, -1, SQLITE_STATIC);
640 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 6, img->exif_lens, -1, SQLITE_STATIC);
646 DT_DEBUG_SQLITE3_BIND_INT(stmt, 12, img->film_id);
647 if(img->exif_datetime_taken)
649 DT_DEBUG_SQLITE3_BIND_INT(stmt, 14, img->flags);
652 flip.s = img->legacy_flip;
653 DT_DEBUG_SQLITE3_BIND_INT(stmt, 17, flip.u);
654 DT_DEBUG_SQLITE3_BIND_INT(stmt, 18, img->group_id);
658 DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 22, &img->d65_color_matrix, sizeof(img->d65_color_matrix), SQLITE_STATIC);
662 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 26, 0.); // img->aspect_ratio deprecated
664 if(img->import_timestamp)
666 if(img->change_timestamp)
668 if(img->export_timestamp)
670 if(img->print_timestamp)
672 DT_DEBUG_SQLITE3_BIND_INT(stmt, 32, 0); // img->final_width deprecated
673 DT_DEBUG_SQLITE3_BIND_INT(stmt, 33, 0); // img->final_height deprecated
674 DT_DEBUG_SQLITE3_BIND_INT(stmt, 34, img->id);
675 const int rc = sqlite3_step(stmt);
676 if(rc != SQLITE_DONE) fprintf(stderr, "[image_cache_write_release] sqlite3 error %d\n", rc);
677 sqlite3_finalize(stmt);
678
681
682 const int32_t imgid = img->id;
683 dt_cache_release(&cache->cache, img->cache_entry);
684
686 dt_control_save_xmp(imgid);
687
688 // FIXME: that a memory leak ?
689 GList *imgs = NULL;
690 imgs = g_list_prepend(imgs, GINT_TO_POINTER(img->id));
692}
693
694
695// remove the image from the cache
696void dt_image_cache_remove(dt_image_cache_t *cache, const int32_t imgid)
697{
698 dt_cache_remove(&cache->cache, imgid);
699}
700
702{
703 if(imgid <= 0) return;
704 dt_image_t *img = dt_image_cache_get(cache, imgid, 'w');
705 if(IS_NULL_PTR(img)) return;
708}
709
711{
712 if(imgid <= 0) return;
713 dt_image_t *img = dt_image_cache_get(cache, imgid, 'w');
714 if(IS_NULL_PTR(img)) return;
717}
718
719// clang-format off
720// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
721// vim: shiftwidth=2 expandtab tabstop=2 cindent
722// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
723// clang-format on
#define FALSE
Definition ashift_lsd.c:158
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
void dt_colorlabels_set_labels(const int32_t imgid, const int colors)
#define dt_cache_release(A, B)
#define dt_cache_get(A, B, C)
static void dt_cache_set_cleanup_callback(dt_cache_t *cache, dt_cache_cleanup_t cleanup_cb, void *cleanup_data)
static void dt_cache_set_allocate_callback(dt_cache_t *cache, dt_cache_allocate_t allocate_cb, void *allocate_data)
void dt_image_refresh_makermodel(dt_image_t *img)
int dt_image_monochrome_flags(const dt_image_t *img)
gboolean dt_image_is_hdr(const dt_image_t *img)
void dt_image_init(dt_image_t *img)
const char * dt_image_film_roll_name(const char *path)
gboolean dt_image_use_monochrome_workflow(const 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_provisional_dsc(dt_image_t *img)
void dt_image_local_copy_paths_from_fullpath(const char *fullpath, int32_t imgid, char *local_copy_path, size_t local_copy_len, char *local_copy_legacy_path, size_t local_copy_legacy_len)
#define ASAN_UNPOISON_MEMORY_REGION(addr, size)
void dt_control_save_xmp(const int32_t imgid)
darktable_t darktable
Definition darktable.c:181
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
@ DT_DEBUG_CACHE
Definition darktable.h:715
@ DT_DEBUG_IMAGEIO
Definition darktable.h:733
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:463
#define dt_free(ptr)
Definition darktable.h:456
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
Definition darktable.h:1043
#define DT_MAX_FILENAME_LEN
Definition darktable.h:1052
#define PATH_MAX
Definition darktable.h:1062
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:281
sqlite3 * dt_database_get(const dt_database_t *db)
Definition database.c:3646
gboolean dt_datetime_gtimespan_to_local(char *local, const size_t local_size, const GTimeSpan gts, const gboolean msec, const gboolean tz)
Definition datetime.c:157
GTimeSpan dt_datetime_now_to_gtimespan()
Definition datetime.c:216
#define DT_DEBUG_SQLITE3_BIND_BLOB(a, b, c, d, e)
Definition debug.h:119
#define DT_DEBUG_SQLITE3_PREPARE_V2(a, b, c, d, e)
Definition debug.h:107
#define DT_DEBUG_SQLITE3_BIND_TEXT(a, b, c, d, e)
Definition debug.h:118
#define DT_DEBUG_SQLITE3_BIND_INT(a, b, c)
Definition debug.h:115
#define DT_DEBUG_SQLITE3_BIND_INT64(a, b, c)
Definition debug.h:116
#define DT_DEBUG_SQLITE3_BIND_DOUBLE(a, b, c)
Definition debug.h:117
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:374
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Definition dtpthread.h:359
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:379
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:364
dt_image_colorspace_t
Definition image.h:178
dt_image_orientation_t
Definition image.h:203
dt_image_flags_t
Definition image.h:91
@ DT_IMAGE_HAS_WAV
Definition image.h:125
@ DT_IMAGE_LOCAL_COPY
Definition image.h:121
@ DT_IMAGE_RAW
Definition image.h:111
@ DT_IMAGE_HDR
Definition image.h:113
@ DT_IMAGE_LDR
Definition image.h:109
static dt_pthread_mutex_t _image_cache_stmt_mutex
Definition image_cache.c:63
void dt_image_cache_cleanup(dt_image_cache_t *cache)
void dt_image_cache_init(dt_image_cache_t *cache)
static sqlite3_stmt * _image_cache_write_history_hash_stmt
Definition image_cache.c:62
static uint64_t _image_cache_self_hash(const dt_image_t *img)
Definition image_cache.c:75
static void _image_cache_write_history_hash(const dt_image_t *img)
static gsize _image_cache_stmt_mutex_inited
Definition image_cache.c:64
void dt_image_cache_read_release(dt_image_cache_t *cache, const dt_image_t *img)
dt_image_t * dt_image_cache_get_reload(dt_image_cache_t *cache, const int32_t imgid, char mode)
void dt_image_cache_allocate(void *data, dt_cache_entry_t *entry)
static sqlite3_stmt * _image_cache_load_stmt
Definition image_cache.c:61
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
int dt_image_cache_seed(dt_image_cache_t *cache, const dt_image_t *img)
static void _image_cache_lock_init(dt_image_t *img)
static void _image_cache_info_changed_reload_callback(gpointer instance, gpointer imgs, gpointer user_data)
void dt_image_cache_set_export_timestamp(dt_image_cache_t *cache, const int32_t imgid)
int dt_image_invalid(const dt_image_t *img)
void dt_image_cache_write_release(dt_image_cache_t *cache, dt_image_t *img, dt_image_cache_write_mode_t mode)
void dt_image_cache_remove(dt_image_cache_t *cache, const int32_t imgid)
void dt_image_from_stmt(dt_image_t *img, sqlite3_stmt *stmt)
void dt_image_cache_deallocate(void *data, dt_cache_entry_t *entry)
void dt_image_cache_connect_info_changed_first(const struct dt_control_signal_t *ctlsig)
dt_image_t * dt_image_cache_testget(dt_image_cache_t *cache, const int32_t imgid, char mode)
static sqlite3_stmt * _image_cache_get_stmt(void)
static void _image_cache_reload_from_db(dt_image_t *img, const uint32_t imgid)
void dt_image_cache_set_print_timestamp(dt_image_cache_t *cache, const int32_t imgid)
static void _image_cache_stmt_mutex_ensure(void)
Definition image_cache.c:66
void dt_image_cache_print(dt_image_cache_t *cache)
dt_image_cache_write_mode_t
Definition image_cache.h:47
@ DT_IMAGE_CACHE_MINIMAL
Definition image_cache.h:54
@ DT_IMAGE_CACHE_SAFE
Definition image_cache.h:49
dt_image_flags_t dt_imageio_get_type_from_extension(const char *extension)
Map Exiv2 preview MIME types to decoder format identifiers.
Definition imageio.c:180
const char * maker
const char * model
size_t size
Definition mipmap_cache.c:3
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
void dt_control_signal_connect(const dt_control_signal_t *ctlsig, dt_signal_t signal, GCallback cb, gpointer user_data)
Definition signal.c:454
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:347
@ DT_SIGNAL_IMAGE_INFO_CHANGED
This signal is raised when any of image info has changed
Definition signal.h:144
int dt_cache_seed(dt_cache_t *cache, const uint32_t key, const void *data, size_t data_size, size_t cost, gboolean aligned_alloc)
dt_cache_entry_t * dt_cache_testget(dt_cache_t *cache, const uint32_t key, char mode)
void dt_cache_init(dt_cache_t *cache, size_t entry_size, size_t cost_quota)
int dt_cache_remove(dt_cache_t *cache, const uint32_t key)
void dt_cache_cleanup(dt_cache_t *cache)
const float const int flip
unsigned __int64 uint64_t
Definition strptime.c:75
const struct dt_database_t * db
Definition darktable.h:779
struct dt_control_signal_t * signals
Definition darktable.h:774
struct dt_image_cache_t * image_cache
Definition darktable.h:777
uint32_t key
int _lock_demoting
void * data
size_t cost
size_t cost
size_t cost_quota
dt_cache_t cache
Definition image_cache.h:40
double latitude
Definition image.h:275
double elevation
Definition image.h:275
double longitude
Definition image.h:275
gboolean has_audio
Definition image.h:375
gboolean is_hdr
Definition image.h:378
float exif_exposure
Definition image.h:285
int32_t height
Definition image.h:315
GTimeSpan export_timestamp
Definition image.h:333
uint64_t history_hash
Definition image.h:322
float exif_focus_distance
Definition image.h:290
GTimeSpan import_timestamp
Definition image.h:333
gboolean is_bw
Definition image.h:376
int32_t group_id
Definition image.h:319
float exif_exposure_bias
Definition image.h:286
uint16_t raw_black_level
Definition image.h:350
float exif_iso
Definition image.h:288
GList * dng_gain_maps
Definition image.h:368
uint32_t raw_white_point
Definition image.h:352
int32_t exif_inited
Definition image.h:283
float exif_aperture
Definition image.h:287
int32_t version
Definition image.h:319
int32_t crop_height
Definition image.h:316
uint64_t mipmap_hash
Definition image.h:329
char fullpath[PATH_MAX]
Definition image.h:305
dt_image_geoloc_t geoloc
Definition image.h:347
int32_t flags
Definition image.h:319
dt_image_orientation_t orientation
Definition image.h:284
int32_t width
Definition image.h:315
float exif_focal_length
Definition image.h:289
char exif_maker[64]
Definition image.h:292
GTimeSpan change_timestamp
Definition image.h:333
uint32_t profile_size
Definition image.h:341
int32_t crop_y
Definition image.h:316
uint32_t history_items
Definition image.h:321
int rating
Definition image.h:372
gboolean has_localcopy
Definition image.h:374
char exif_lens[128]
Definition image.h:294
char local_copy_path[PATH_MAX]
Definition image.h:306
GTimeSpan print_timestamp
Definition image.h:333
int32_t film_id
Definition image.h:319
GTimeSpan exif_datetime_taken
Definition image.h:295
int32_t crop_x
Definition image.h:316
int color_labels
Definition image.h:371
float d65_color_matrix[9]
Definition image.h:339
char exif_model[64]
Definition image.h:293
dt_image_colorspace_t colorspace
Definition image.h:342
uint8_t * profile
Definition image.h:340
char datetime[200]
Definition image.h:310
struct dt_cache_entry_t * cache_entry
Definition image.h:381
int32_t crop_width
Definition image.h:316
uint32_t group_members
Definition image.h:320
dt_image_raw_parameters_t legacy_flip
Definition image.h:344
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:304
char folder[PATH_MAX]
Definition image.h:308
int32_t id
Definition image.h:319
char filmroll[PATH_MAX]
Definition image.h:309
uint64_t self_hash
Definition image.h:330
char local_copy_legacy_path[PATH_MAX]
Definition image.h:307
float exif_crop
Definition image.h:291
gboolean is_bw_flow
Definition image.h:377
@ DT_VIEW_REJECT
Definition view.h:174