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 Copyright (C) 2026 Guillaume Stutin.
29
30 darktable is free software: you can redistribute it and/or modify
31 it under the terms of the GNU General Public License as published by
32 the Free Software Foundation, either version 3 of the License, or
33 (at your option) any later version.
34
35 darktable is distributed in the hope that it will be useful,
36 but WITHOUT ANY WARRANTY; without even the implied warranty of
37 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
38 GNU General Public License for more details.
39
40 You should have received a copy of the GNU General Public License
41 along with darktable. If not, see <http://www.gnu.org/licenses/>.
42*/
43
45#include "caches/image_cache.h"
46#include "system/macros.h"
47#include "system/mem_alloc.h"
48#include "common/hash.h"
49#include "common/logging.h"
50#include "common/paths.h"
51#include "common/image.h"
52#include "common/datetime.h"
53#include "control/control.h"
54#include "control/signal.h"
55#include "develop/supervisor.h"
56
57#include <inttypes.h>
58#include "colorprofiles/colorspaces.h" // dt_colorspaces_free_image_profile
59
60/* Set once by dt_image_cache_init(); see the header for why it is not read live. */
61static gboolean _verbose = FALSE;
62
63/* Statement-safe: a bare `if(_verbose) dt_print(...)` swallows a following `else`. */
64#define _cache_print(channel, ...) \
65 do { \
66 if(_verbose) dt_print((channel), __VA_ARGS__); \
67 } while(0)
68
69
70/* PRIVATE. Nothing outside this file reads a field of it -- the header exposes the
71 * type as an opaque handle so that it cannot. */
72typedef struct dt_image_cache_t
73{
75}
77
78
79/* The cache instance, owned HERE. It used to be calloc'd by darktable.c and hung off the
80 * application struct, so the accessor lived in the orchestrator and the struct was reachable
81 * from anything that included darktable.h. */
83
85{
87}
88
89
90
92{
93 if(IS_NULL_PTR(img) || img->id <= 0) return 0;
94
95 struct
96 {
97 dt_image_orientation_t orientation;
98 float exif_exposure;
99 float exif_exposure_bias;
100 float exif_aperture;
101 float exif_iso;
102 float exif_focal_length;
103 float exif_focus_distance;
104 float exif_crop;
105 char exif_maker[64];
106 char exif_model[64];
107 char exif_lens[128];
108 GTimeSpan exif_datetime_taken;
109 char filename[DT_MAX_FILENAME_LEN];
110 int32_t width, height;
111 int32_t crop_x, crop_y, crop_width, crop_height;
112 int32_t flags, film_id, id, group_id, version;
113 uint64_t history_hash;
114 float d65_color_matrix[9];
115 dt_image_colorspace_t colorspace;
116 dt_image_raw_parameters_t legacy_flip;
117 dt_image_geoloc_t geoloc;
118 uint16_t raw_black_level;
119 uint32_t raw_white_point;
120 int color_labels;
121 } persisted = { 0 };
122
123 /*
124 * Track only the dt_image_t fields that are explicitly written back to the database
125 * from dt_image_cache_write_release(), plus the history hash and color labels that
126 * are flushed through their own SQL paths right below it. Runtime-only fields such
127 * as cached ICC pointers, DNG gain-map lists, loader state or derived path strings
128 * must stay out of this hash, otherwise merely opening an image can look like an
129 * edit and spuriously bump change_timestamp.
130 */
131 persisted.orientation = img->orientation;
132 persisted.exif_exposure = img->exif_exposure;
133 persisted.exif_exposure_bias = img->exif_exposure_bias;
134 persisted.exif_aperture = img->exif_aperture;
135 persisted.exif_iso = img->exif_iso;
136 persisted.exif_focal_length = img->exif_focal_length;
137 persisted.exif_focus_distance = img->exif_focus_distance;
138 persisted.exif_crop = img->exif_crop;
139 memcpy(persisted.exif_maker, img->exif_maker, sizeof(persisted.exif_maker));
140 memcpy(persisted.exif_model, img->exif_model, sizeof(persisted.exif_model));
141 memcpy(persisted.exif_lens, img->exif_lens, sizeof(persisted.exif_lens));
142 persisted.exif_datetime_taken = img->exif_datetime_taken;
143 memcpy(persisted.filename, img->filename, sizeof(persisted.filename));
144 persisted.width = img->width;
145 persisted.height = img->height;
146 persisted.crop_x = img->crop_x;
147 persisted.crop_y = img->crop_y;
148 persisted.crop_width = img->crop_width;
149 persisted.crop_height = img->crop_height;
150 persisted.flags = img->flags;
151 persisted.film_id = img->film_id;
152 persisted.id = img->id;
153 persisted.group_id = img->group_id;
154 persisted.version = img->version;
155 persisted.history_hash = img->history_hash;
156 memcpy(persisted.d65_color_matrix, img->d65_color_matrix, sizeof(persisted.d65_color_matrix));
157 persisted.colorspace = img->colorspace;
158 persisted.legacy_flip = img->legacy_flip;
159 persisted.geoloc = img->geoloc;
160 persisted.raw_black_level = img->raw_black_level;
161 persisted.raw_white_point = img->raw_white_point;
162 persisted.color_labels = img->color_labels;
163
164 return dt_hash(5381, (const char *)&persisted, sizeof(persisted));
165}
166
167static inline void _image_cache_lock_init(dt_image_t *img)
168{
170}
171
172
173
174
175/* Fields the database does not store because they are computed from the ones it does:
176 * the rating, the monochrome and HDR predicates, the extension cross-check, makermodel.
177 * They live here rather than in database/image_repository.c because they need
178 * imageio/ and views/ symbols, and a row mapper reaching two layers up for them is exactly
179 * what kept this code in common/. Every path that produces a dt_image_t from a database row
180 * calls this next -- the repository's own load, and gui/dtgtk/thumbtable.c's bulk query. */
182{
183 if(IS_NULL_PTR(img)) return;
185 img->has_audio = (img->flags & DT_IMAGE_HAS_WAV);
186 int xmp_rating = dt_image_get_xmp_rating_from_flags(img->flags);
187 img->rating = (xmp_rating == -1) ? DT_VIEW_REJECT : xmp_rating;
190 img->is_hdr = dt_image_is_hdr(img);
191
192 // Instrumentation: the LDR/HDR flags are now pure flag predicates (no filename sniffing at read
193 // time). Historically the flag could have been mis-set at import, so cross-check the flags loaded
194 // from the DB against the unambiguous extension hint and log any contradiction. Containers whose
195 // dynamic range only the decoder can settle (TIFF/AVIF/HEIF/DNG ...) return 0 here and are skipped
196 // to avoid false positives. This surfaces stale/garbage flags persisted in the database.
197 {
198 const gchar *ext = g_strrstr(img->filename, ".");
199 const dt_image_flags_t ext_hint = ext ? dt_image_flags_from_extension(ext) : 0;
200 const gboolean db_hdr = (img->flags & DT_IMAGE_HDR) != 0;
201 const gboolean db_ldr = (img->flags & DT_IMAGE_LDR) != 0;
202
203 if(ext_hint == DT_IMAGE_HDR && !db_hdr)
205 "[image_cache] DB flag mismatch: id=%d filename='%s' has an HDR extension but stored "
206 "flags=0x%08x lack DT_IMAGE_HDR (ldr=%d hdr=%d)\n",
207 img->id, img->filename, (unsigned int)img->flags, db_ldr, db_hdr);
208 else if((ext_hint == DT_IMAGE_LDR || ext_hint == DT_IMAGE_RAW) && db_hdr)
210 "[image_cache] DB flag mismatch: id=%d filename='%s' has a %s extension but stored "
211 "flags=0x%08x carry DT_IMAGE_HDR (ldr=%d hdr=%d)\n",
212 img->id, img->filename, (ext_hint == DT_IMAGE_RAW) ? "RAW" : "LDR",
213 (unsigned int)img->flags, db_ldr, db_hdr);
214 }
215
217}
218
219static void _image_cache_reload_from_db(dt_image_t *img, const uint32_t imgid, const dt_sv_op_t sv_op)
220{
221 dt_image_repository_load((int32_t)imgid, img);
223
224 // The image's dt_image_t was just (re)loaded from the database: `create` on
225 // first allocation, `update` on a reload (get_reload / IMAGE_INFO_CHANGED).
226 // Notifying is the cache's job, not the repository's -- the repository does not
227 // know what a supervisor is.
228 if(dt_supervisor_active()) dt_supervisor_image(sv_op, (int32_t)imgid, img);
229}
230
232{
233 entry->cost = sizeof(dt_image_t);
234
235 // dt_alloc_align: dt_image_t embeds dt_aligned_pixel_t members (alignof 64); see #1212.
237 entry->data = img;
238 if(IS_NULL_PTR(img))
239 {
240 // dt_cache_get() frees the entry and answers NULL
241 fprintf(stderr, "[image_cache] could not allocate a cache entry for image %" PRId32 "\n", (int32_t)entry->key);
242 return;
243 }
244 dt_image_init(img);
245 _image_cache_reload_from_db(img, entry->key, DT_SV_CREATE); // emits the create event
246
247 img->cache_entry = entry; // init backref
248}
249
251{
252 dt_image_t *img = (dt_image_t *)entry->data;
253
254 if(dt_supervisor_active()) dt_supervisor_image(DT_SV_DELETE, (int32_t)entry->key, NULL);
255
256 dt_free(img->profile);
258 img->embedded_profile = NULL;
259 g_list_free_full(img->dng_gain_maps, dt_free_gpointer);
260 img->dng_gain_maps = NULL;
261 dt_free_align(img);
262}
263
264void dt_image_cache_init(const gboolean verbose)
265{
266 _verbose = verbose;
267 if(_image_cache) return;
268 _image_cache = (dt_image_cache_t *)calloc(1, sizeof(dt_image_cache_t));
269 if(IS_NULL_PTR(_image_cache)) return;
271 // the image cache does no serialization.
272 // (unsafe. data should be in db/xmp, not in any other additional cache,
273 // also, it should be relatively fast to get the image_t structs from sql.)
274 // TODO: actually an independent conf var?
275 // too large: dangerous and wasteful?
276 // can we get away with a fixed size?
277 const uint32_t size = 50;
278 const uint32_t max_mem = size * 1024 * 1024;
279 const uint32_t num = (uint32_t)(1.5f * max_mem / sizeof(dt_image_t));
280 dt_cache_init(&cache->cache, sizeof(dt_image_t), max_mem);
283
284 _cache_print(DT_DEBUG_CACHE, "[image_cache] has %d entries (%u MiB)\n", num, size);
285}
286
288{
290 if(IS_NULL_PTR(cache)) return;
292
293 dt_cache_cleanup(&cache->cache);
294
296 _image_cache = NULL;
297}
298
300{
301 const dt_image_cache_t *const cache = _image_cache;
302 printf("[image cache] fill %.2f/%.2f MB (%.2f%%)\n", cache->cache.cost / (1024.0 * 1024.0),
303 cache->cache.cost_quota / (1024.0 * 1024.0),
304 (float)cache->cache.cost / (float)cache->cache.cost_quota);
305}
306
307void dt_image_cache_get_usage(size_t *current, size_t *max)
308{
310 if(current) *current = 0;
311 if(max) *max = 0;
312 if(IS_NULL_PTR(cache)) return;
314 if(current) *current = cache->cache.cost;
315 if(max) *max = cache->cache.cost_quota;
317}
318
320{
322 GArray *out = g_array_new(FALSE, FALSE, sizeof(dt_image_cache_stats_entry_t));
323 if(IS_NULL_PTR(cache)) return out;
324
326 GHashTableIter it;
327 gpointer key, value;
328 g_hash_table_iter_init(&it, cache->cache.hashtable);
329 while(g_hash_table_iter_next(&it, &key, &value))
330 {
331 const dt_cache_entry_t *ce = (const dt_cache_entry_t *)value;
332 if(IS_NULL_PTR(ce)) continue;
334 s.imgid = (int32_t)ce->key;
335 s.size = ce->cost ? ce->cost : ce->data_size;
336 const dt_image_t *img = (const dt_image_t *)ce->data;
337 if(img && img->filename[0]) g_strlcpy(s.filename, img->filename, sizeof(s.filename));
338 g_array_append_val(out, s);
339 }
341 return out;
342}
343
344dt_image_t *dt_image_cache_get(const int32_t imgid, char mode)
345{
347 if(imgid <= 0) return NULL;
348 dt_cache_entry_t *entry = dt_cache_get(&cache->cache, (uint32_t)imgid, mode);
349 if(IS_NULL_PTR(entry)) return NULL; // the payload could not be allocated
350
352 dt_image_t *img = (dt_image_t *)entry->data;
353 img->cache_entry = entry;
354
355 if(dt_image_invalid(img))
356 {
357 dt_cache_release(&cache->cache, entry);
358 return NULL;
359 }
360
362 return img;
363}
364
365dt_image_t *dt_image_cache_testget(const int32_t imgid, char mode)
366{
368 if(imgid <= 0) return NULL;
369 dt_cache_entry_t *entry = dt_cache_testget(&cache->cache, (uint32_t)imgid, mode);
370 if(IS_NULL_PTR(entry)) return 0;
372 dt_image_t *img = (dt_image_t *)entry->data;
373 img->cache_entry = entry;
374
375 /* Same contract as dt_image_cache_get() and dt_image_cache_get_reload(): an entry whose row
376 * has gone stays in the cache with id == UNKNOWN_IMAGE, and handing it out LOCKED is how the
377 * lock leaks -- the caller has no way to release what it was told was not an image. */
378 if(dt_image_invalid(img))
379 {
380 dt_cache_release(&cache->cache, entry);
381 return NULL;
382 }
383
385 return img;
386}
387
388dt_image_t *dt_image_cache_get_existing(const int32_t imgid, char mode)
389{
391 if(imgid <= 0) return NULL;
392
393 // contains() answers "is there an entry" without taking the entry's lock, which is the one
394 // question testget() conflates with "is it free right now"
395 if(!dt_cache_contains(&cache->cache, (uint32_t)imgid)) return NULL;
396 return dt_image_cache_get(imgid, mode);
397}
398
399// Always reload the cache entry from DB before returning it.
400// This is critical for IMAGE_INFO_CHANGED: other handlers will read from the cache.
401dt_image_t *dt_image_cache_get_reload(const int32_t imgid, char mode)
402{
404 if(imgid <= 0) return NULL;
405
406 // We must take a write lock to reload in-place, then demote to read if requested.
407 dt_cache_entry_t *entry = dt_cache_get(&cache->cache, (uint32_t)imgid, 'w');
408 if(IS_NULL_PTR(entry)) return NULL; // the payload could not be allocated
409
411 dt_image_t *img = (dt_image_t *)entry->data;
412 _image_cache_reload_from_db(img, (uint32_t)imgid, DT_SV_UPDATE);
413
414 img->cache_entry = entry;
415
416 if(dt_image_invalid(img))
417 {
418 dt_cache_release(&cache->cache, entry);
419 return NULL;
420 }
421
422 if(mode == 'r')
423 {
424 // demote the lock to read mode (see mipmap cache for rationale)
425 entry->_lock_demoting = 1;
426 dt_cache_release(&cache->cache, entry);
427 entry = dt_cache_get(&cache->cache, (uint32_t)imgid, 'r');
428 entry->_lock_demoting = 0;
430 img = (dt_image_t *)entry->data;
431 img->cache_entry = entry;
432 }
433
435 return img;
436}
437
439{
440 return (IS_NULL_PTR(img) || img->id <= 0);
441}
442
444{
446 if(IS_NULL_PTR(cache) || dt_image_invalid(img)) return -1;
447
448 dt_image_t seeded = *img;
449
450 // Avoid ownership issues for pointers that the cache cleanup would free.
451 seeded.profile = NULL;
452 seeded.profile_size = 0;
453 seeded.dng_gain_maps = NULL;
454 seeded.cache_entry = NULL;
455
456 // dt_image_cache_deallocate() frees entry->data with dt_free_align(); dt_cache_seed()
457 // allocates with dt_alloc_align() and no longer offers any other option.
458 return dt_cache_seed(&cache->cache, (uint32_t)seeded.id, &seeded, sizeof(dt_image_t), sizeof(dt_image_t));
459}
460
461// This callback must run before any other DT_SIGNAL_IMAGE_INFO_CHANGED handler.
462// The signal notifies about DB changes, and most listeners read image info from the cache.
463// We therefore force a DB reload here so every subsequent handler sees up-to-date data.
464static void _image_cache_info_changed_reload_callback(gpointer instance, gpointer imgs, gpointer user_data)
465{
466 for(GList *l = g_list_first((GList *)imgs); l; l = g_list_next(l))
467 {
468 const int32_t imgid = GPOINTER_TO_INT(l->data);
469 if(imgid <= 0) continue;
470
471 dt_image_t *img = dt_image_cache_get_reload(imgid, 'r');
472 if(img)
474 }
475}
476
478{
479 // Must be connected early to run before any other handler.
482}
483
484// drops the read lock on an image struct
486{
488 if(IS_NULL_PTR(img)) return;
489
490 /* What is being returned is the LOCK, not the image, so an entry whose row has gone in the
491 * meantime is released like any other. The guard used to read `|| img->id <= 0` -- which is
492 * dt_image_invalid() spelled out -- and that silently skipped the release for exactly the
493 * entries most likely to have one outstanding, deadlocking the next writer for good. */
494 if(dt_image_invalid(img))
495 {
496 if(!IS_NULL_PTR(img->cache_entry)) dt_cache_release(&cache->cache, img->cache_entry);
497 return;
498 }
499
500 const uint64_t self_hash = _image_cache_self_hash(img);
501 if(self_hash != img->self_hash)
502 g_error("[image_cache] read lock modified image %d, you need to use a write lock\n", img->id);
503
504 // just force the dt_image_t struct to make sure it has been locked before.
505 dt_cache_release(&cache->cache, img->cache_entry);
506}
507
508// drops the write privileges on an image struct.
509// this triggers a write-through to sql, and optionally queues xmp sidecar writing.
511{
513 if(IS_NULL_PTR(img)) return;
514
515 // same as the read side: release the lock, write nothing back for a row that is gone
516 if(dt_image_invalid(img))
517 {
518 if(!IS_NULL_PTR(img->cache_entry)) dt_cache_release(&cache->cache, img->cache_entry);
519 return;
520 }
521
522 const uint64_t self_hash = _image_cache_self_hash(img);
523 const gboolean changed = (self_hash != img->self_hash);
524
525 if(changed)
527
528 // even if nothing changed, we might need to write export/print timestamps
529 // and mipmap hash, so we can't exit just yet.
530
531 if(mode == DT_IMAGE_CACHE_MINIMAL)
532 {
533 if(changed)
534 g_error("[image_cache] minimal write release modified image %d, you need to commit those changes to DB.\n", img->id);
535
536 dt_cache_release(&cache->cache, img->cache_entry);
537 return;
538 }
539
540 // Recompute full/local copy paths (and derived folder/filmroll/datetime) from possibly updated filename.
541 // Avoid SQL here; rely on the cached folder/fullpath, or leave fields empty if they can't be rebuilt.
542 char folder[DT_PATH_MAX] = { 0 };
543 if(img->folder[0])
544 {
545 g_strlcpy(folder, img->folder, sizeof(folder));
546 }
547 else if(img->fullpath[0])
548 {
549 gchar *dir = g_path_get_dirname(img->fullpath);
550 if(dir && dir[0] && strcmp(dir, "."))
551 g_strlcpy(folder, dir, sizeof(folder));
552 dt_free(dir);
553 }
554
555 if(img->filename[0] && folder[0])
556 {
557 g_snprintf(img->fullpath, sizeof(img->fullpath), "%s" G_DIR_SEPARATOR_S "%s", folder, img->filename);
558 g_strlcpy(img->folder, folder, sizeof(img->folder));
559 }
560 else
561 {
562 img->fullpath[0] = '\0';
563 img->folder[0] = '\0';
564 }
565 if(img->folder[0])
566 g_strlcpy(img->filmroll, dt_image_film_roll_name(img->folder), sizeof(img->filmroll));
567 else if(img->film_id < 0)
568 g_strlcpy(img->filmroll, _("orphaned image"), sizeof(img->filmroll));
569 else
570 img->filmroll[0] = '\0';
573 sizeof(img->local_copy_path), img->local_copy_legacy_path,
574 sizeof(img->local_copy_legacy_path));
575
577 img->has_audio = (img->flags & DT_IMAGE_HAS_WAV);
578 int xmp_rating = dt_image_get_xmp_rating_from_flags(img->flags);
579 img->rating = (xmp_rating == -1) ? DT_VIEW_REJECT : xmp_rating;
582 img->is_hdr = dt_image_is_hdr(img);
583
585
586 const int32_t imgid = img->id;
587 dt_cache_release(&cache->cache, img->cache_entry);
588
590 dt_control_save_xmp(imgid);
591
592 // The signal owns the list. `img` may be evicted once released, hence the saved id.
593 GList *imgs = g_list_prepend(NULL, GINT_TO_POINTER(imgid));
595}
596
597
598// remove the image from the cache
599void dt_image_cache_remove(const int32_t imgid)
600{
602 dt_cache_remove(&cache->cache, imgid);
603}
604
605void dt_image_cache_set_export_timestamp(const int32_t imgid)
606{
607 if(imgid <= 0) return;
608 dt_image_t *img = dt_image_cache_get(imgid, 'w');
609 if(IS_NULL_PTR(img)) return;
612}
613
614void dt_image_cache_set_print_timestamp(const int32_t imgid)
615{
616 if(imgid <= 0) return;
617 dt_image_t *img = dt_image_cache_get(imgid, 'w');
618 if(IS_NULL_PTR(img)) return;
621}
622
623// clang-format off
624// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
625// vim: shiftwidth=2 expandtab tabstop=2 cindent
626// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
627// clang-format on
#define FALSE
Definition ashift_lsd.c:158
#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_colorspaces_free_image_profile(struct dt_colorspaces_color_profile_t *profile)
Release a profile container owned by an image, closing the LCMS2 handle inside it if and only if the ...
The colour-profile module's API: which profiles exist, and how to apply one.
const float max
const dt_colormatrix_t dt_aligned_pixel_t out
dt_image_flags_t dt_image_flags_from_extension(const char *extension)
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_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)
void * dt_alloc_align(size_t size)
Allocate cacheline-aligned memory.
Definition darktable.c:511
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:178
GTimeSpan dt_datetime_now_to_gtimespan()
Definition datetime.c:237
GtkWidget * folder
destination folder chooser
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:127
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:117
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
Definition hash.h:55
dt_image_colorspace_t
Definition image.h:200
dt_image_orientation_t
Definition image.h:225
dt_image_flags_t
Definition image.h:113
@ DT_IMAGE_HAS_WAV
Definition image.h:147
@ DT_IMAGE_LOCAL_COPY
Definition image.h:143
@ DT_IMAGE_RAW
Definition image.h:133
@ DT_IMAGE_HDR
Definition image.h:135
@ DT_IMAGE_LDR
Definition image.h:131
@ DT_VIEW_REJECT
Definition image.h:364
static dt_image_cache_t * _image_cache
Definition image_cache.c:82
void dt_image_cache_set_print_timestamp(const int32_t imgid)
dt_image_t * dt_image_cache_get_existing(const int32_t imgid, char mode)
void dt_image_cache_write_release(dt_image_t *img, dt_image_cache_write_mode_t mode)
static uint64_t _image_cache_self_hash(const dt_image_t *img)
Definition image_cache.c:91
dt_image_t * dt_image_cache_testget(const int32_t imgid, char mode)
gboolean dt_image_cache_is_ready(void)
Has the image cache been initialised? Callers that run before dt_image_cache_init() or after its clea...
Definition image_cache.c:84
void dt_image_cache_get_usage(size_t *current, size_t *max)
GArray * dt_image_cache_get_entries_stats(void)
static gboolean _verbose
Definition image_cache.c:61
void dt_image_cache_set_export_timestamp(const int32_t imgid)
#define _cache_print(channel,...)
Definition image_cache.c:64
void dt_image_cache_allocate(void *data, dt_cache_entry_t *entry)
void dt_image_cache_init(const gboolean verbose)
Initialise the cache.
void dt_image_derive_fields(dt_image_t *img)
Compute the fields the database does not store: rating, monochrome and HDR predicates,...
dt_image_t * dt_image_cache_get(const int32_t imgid, char mode)
dt_image_t * dt_image_cache_get_reload(const int32_t imgid, char mode)
static void _image_cache_reload_from_db(dt_image_t *img, const uint32_t imgid, const dt_sv_op_t sv_op)
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)
int dt_image_invalid(const dt_image_t *img)
int dt_image_cache_seed(const dt_image_t *img)
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)
void dt_image_cache_print(void)
void dt_image_cache_remove(const int32_t imgid)
void dt_image_cache_read_release(const dt_image_t *img)
void dt_image_cache_cleanup(void)
dt_image_cache_write_mode_t
Definition image_cache.h:46
@ DT_IMAGE_CACHE_MINIMAL
Definition image_cache.h:53
@ DT_IMAGE_CACHE_SAFE
Definition image_cache.h:48
void dt_image_repository_cleanup(void)
Finalise the prepared statements. Called at shutdown, after the last cache release and before the dat...
gboolean dt_image_repository_load(const int32_t imgid, dt_image_t *img)
Fill img from the main.images row for imgid.
void dt_image_repository_store(const dt_image_t *img)
Write img back to main.images, plus its colour labels and history hash.
Reading and writing one dt_image_t to and from the library database. The SQL half of what used to be ...
@ DT_DEBUG_CACHE
Definition logging.h:51
@ DT_DEBUG_IMAGEIO
Definition logging.h:68
#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 macros.h:96
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
Definition mem_alloc.h:214
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
Definition mem_alloc.h:184
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
char * key
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
size_t size
Definition mipmap_cache.c:3
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
#define DT_MAX_FILENAME_LEN
Definition paths.h:35
void dt_control_signal_connect(const dt_control_signal_t *ctlsig, dt_signal_t signal, GCallback cb, gpointer user_data)
Definition signal.c:496
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:390
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:619
@ DT_SIGNAL_IMAGE_INFO_CHANGED
This signal is raised when any of image info has changed
Definition signal.h:148
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
int32_t dt_cache_contains(dt_cache_t *cache, const uint32_t key)
dt_cache_entry_t * dt_cache_testget(dt_cache_t *cache, const uint32_t key, char mode)
int dt_cache_seed(dt_cache_t *cache, const uint32_t key, const void *data, size_t data_size, size_t cost)
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)
unsigned __int64 uint64_t
Definition strptime.c:75
uint32_t key
size_t data_size
int _lock_demoting
void * data
size_t cost
size_t cost
size_t cost_quota
GHashTable * hashtable
dt_pthread_mutex_t lock
Definition image_cache.h:77
char filename[128]
Definition image_cache.h:80
size_t size
Definition image_cache.h:79
int32_t imgid
Definition image_cache.h:78
dt_cache_t cache
Definition image_cache.c:74
gboolean has_audio
Definition image.h:485
gboolean is_hdr
Definition image.h:488
float exif_exposure
Definition image.h:376
int32_t height
Definition image.h:406
GTimeSpan export_timestamp
Definition image.h:424
uint64_t history_hash
Definition image.h:413
float exif_focus_distance
Definition image.h:381
gboolean is_bw
Definition image.h:486
int32_t group_id
Definition image.h:410
float exif_exposure_bias
Definition image.h:377
uint16_t raw_black_level
Definition image.h:446
float exif_iso
Definition image.h:379
GList * dng_gain_maps
Definition image.h:473
uint32_t raw_white_point
Definition image.h:448
float exif_aperture
Definition image.h:378
char local_copy_path[DT_PATH_MAX]
Definition image.h:397
int32_t version
Definition image.h:410
int32_t crop_height
Definition image.h:407
dt_image_geoloc_t geoloc
Definition image.h:443
int32_t flags
Definition image.h:410
dt_image_orientation_t orientation
Definition image.h:375
int32_t width
Definition image.h:406
float exif_focal_length
Definition image.h:380
char exif_maker[64]
Definition image.h:383
GTimeSpan change_timestamp
Definition image.h:424
uint32_t profile_size
Definition image.h:432
int32_t crop_y
Definition image.h:407
int rating
Definition image.h:482
gboolean has_localcopy
Definition image.h:484
char exif_lens[128]
Definition image.h:385
GTimeSpan print_timestamp
Definition image.h:424
int32_t film_id
Definition image.h:410
char folder[DT_PATH_MAX]
Definition image.h:399
GTimeSpan exif_datetime_taken
Definition image.h:386
int32_t crop_x
Definition image.h:407
int color_labels
Definition image.h:481
float d65_color_matrix[9]
Definition image.h:430
char filmroll[DT_PATH_MAX]
Definition image.h:400
char exif_model[64]
Definition image.h:384
dt_image_colorspace_t colorspace
Definition image.h:438
struct dt_colorspaces_color_profile_t * embedded_profile
Definition image.h:437
uint8_t * profile
Definition image.h:431
char datetime[200]
Definition image.h:401
struct dt_cache_entry_t * cache_entry
Definition image.h:491
int32_t crop_width
Definition image.h:407
char local_copy_legacy_path[DT_PATH_MAX]
Definition image.h:398
dt_image_raw_parameters_t legacy_flip
Definition image.h:440
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:395
int32_t id
Definition image.h:410
uint64_t self_hash
Definition image.h:421
float exif_crop
Definition image.h:382
char fullpath[DT_PATH_MAX]
Definition image.h:396
gboolean is_bw_flow
Definition image.h:487
void dt_supervisor_image(const dt_sv_op_t op, const int32_t imgid, const dt_image_t *img)
dt_sv_op_t
Definition supervisor.h:77
@ DT_SV_UPDATE
Definition supervisor.h:79
@ DT_SV_CREATE
Definition supervisor.h:78
@ DT_SV_DELETE
Definition supervisor.h:81
static gboolean dt_supervisor_active(void)
Definition supervisor.h:95