Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
import_jobs.c
Go to the documentation of this file.
1/*
2 This file is part of the Ansel project.
3 Copyright (C) 2025-2026 Aurélien PIERRE.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18#include "system/mem_alloc.h"
19#include "common/paths.h" // DT_PATH_MAX
20#include "common/conf.h"
21#include "import_jobs.h"
22#include "import_sequence.h"
23#include "common/collection.h"
24#include "common/datetime.h"
25#include "metadata/exif.h"
27#include "metadata/metadata.h"
28#include "common/styles.h"
29#include "control/control.h"
30#include "common/film.h"
31#include "common/image.h"
33
34#ifndef _WIN32
35#endif
36#include <string.h>
37#include <glib/gstdio.h>
38#include "common/utility.h"
39#ifdef __APPLE__
40#include "osx/osx.h"
41#endif
42#ifdef _WIN32
43#endif
44
45
53gboolean _create_dir(const char *path)
54{
55 if(g_mkdir_with_parents(path, 0755) == -1)
56 {
57 fprintf(stderr, "failed to create directory %s.\n", path);
58 dt_control_log(_("Impossible to create directory %s.\nThe target may be full or read-only.\n"), path);
59 return TRUE;
60 }
61 return FALSE;
62}
63
71gchar *_path_cleanup(gchar *path_in)
72{
76 return path_out;
77}
78
79gchar *dt_build_filename_from_pattern(const char *const filename, const int index, dt_image_t *img, dt_control_import_t *data)
80{
83 // Borrowed references, like every other dt_variables_params_t caller (see iop/watermark.c):
84 // dt_variables_params_destroy() does not own/free filename or jobcode.
85 params->filename = filename;
86 params->sequence = index;
87 params->jobcode = data->jobcode;
88 params->imgid = UNKNOWN_IMAGE;
89 params->img = img;
91
94 {
96 return NULL;
97 }
98
102 {
106 return NULL;
107 }
108
109 // remove this if we decide to do the correction on user's settings directly
110 gchar *file = _path_cleanup(file_expand);
111 gchar *path = _path_cleanup(path_expand);
114 if(IS_NULL_PTR(file) || IS_NULL_PTR(path))
115 {
116 dt_free(file);
117 dt_free(path);
119 return NULL;
120 }
121
122 gchar *dir = g_build_path(G_DIR_SEPARATOR_S, data->base_folder, path, (char *) NULL);
123 gchar *target_dir = IS_NULL_PTR(dir) ? NULL : dt_util_normalize_path(dir);
124 gchar *res = IS_NULL_PTR(target_dir) ? NULL : g_build_path(G_DIR_SEPARATOR_S, target_dir, file, (char *) NULL);
125
126 if(!IS_NULL_PTR(res))
127 {
128 data->target_dir = target_dir;
129 target_dir = NULL;
130 dt_print(DT_DEBUG_PRINT, "[Import] Importing file to %s\n", res);
131 }
132
133 dt_free(file);
134 dt_free(path);
135 dt_free(dir);
136 dt_free(target_dir);
138 return res;
139}
140
151
159gboolean _copy_file(const char *filename, const char *dest_file_path)
160{
161 GFile *in = g_file_new_for_path(filename);
163
164 gboolean res = g_file_copy(in, out, G_FILE_COPY_NONE, 0, 0, 0, NULL);
165 if(!res) dt_print(DT_DEBUG_IMPORT, "[Import] Could not copy the file %s to %s\n", filename, dest_file_path);
166
167 g_object_unref(in);
169
170 return res;
171}
172
181{
183
184 dt_film_t film;
185 const int32_t filmid = dt_film_new(&film, dirname);
186 // Regular imports skip the per-file DT_SIGNAL_IMAGE_IMPORT (large batches
187 // would otherwise raise it hundreds of times). Folder survey imports one or
188 // a few files at a time, and Studio Capture needs that signal to know which
189 // image to display as soon as it lands, so raise it for that case only.
190 const int32_t imgid = dt_image_import(filmid, img_path_to_db, data->folder_survey);
191 dt_free(dirname);
192 return imgid;
193}
194
207void dt_import_duplicate_get_dest_name(char *xmp_dest_name, const char *dest_file_path, const int counter)
208{
211 while(*ext != '.' && ext > norm_dest_file) ext--;
213
214 if(counter == 0)
216 else
217 g_snprintf(xmp_dest_name, DT_PATH_MAX, "%.*s_%.2d%s.xmp", (int)name_len, norm_dest_file, counter, ext);
218
219 dt_print(DT_DEBUG_IMPORT, "[Import] XMP destination name: %s\n", xmp_dest_name);
220
222}
223
231int _import_copy_xmp(const char *const filename, const gchar *dest_file_path)
232{
233 int xmp_cntr = 0;
234
235 GList *xmp_files = dt_image_find_xmps(filename); // the first xmp will be the original
236 if(g_list_length(xmp_files) > 0)
237 {
239 {
240 char *xmp_source = g_strdup((char*) current_xmp->data);
241 gchar xmp_dest_name[DT_PATH_MAX] = { 0 };
243
244 // folder already created and writable, just copy.
245 int success = _copy_file(xmp_source, xmp_dest_name);
246 dt_print(DT_DEBUG_IMPORT, "[Import] copying %s to %s %s\n", xmp_source, xmp_dest_name,
247 (success) ? "succeeded" : "failed");
248 if(success) xmp_cntr++;
250 }
251 }
253 xmp_files = NULL;
254 return xmp_cntr;
255}
256
257int _import_copy_txt(const char *const filename, const char *dest_file_path)
258{
260 if(IS_NULL_PTR(txt_source)) return 0;
261
263 int success = 0;
264
266 {
267 success = _copy_file(txt_source, txt_dest);
268 dt_print(DT_DEBUG_IMPORT, "[Import] copying %s to %s %s\n", txt_source, txt_dest,
269 (success) ? "succeeded" : "failed");
270 }
271
274 return success ? 1 : 0;
275}
276
288int _import_copy_file(const char *const filename, const char *const dest_file_path, dt_control_import_t *data,
289 gchar *img_path_to_db, size_t pathname_len, GList **discarded)
290{
291 dt_print(DT_DEBUG_IMPORT, "[Import] Image %s will be copied into %s\n", filename, dest_file_path);
292
293 int copied = -1;
294 char *unique_destination = NULL;
295 const char *copy_destination = dest_file_path;
296
298
299 // Resolve a name collision according to the requested policy. UNIQUE rewrites
300 // the destination to a free "<stem>_NN.<ext>" so the copy proceeds normally.
302 {
303 const char *dot = strrchr(copy_destination, '.');
304 const int stem_len = dot ? (int)(dot - copy_destination) : (int)strlen(copy_destination);
305 const char *ext = dot ? dot : "";
306 for(int seq = 1; seq < 10000; seq++)
307 {
311 }
313 exists = FALSE;
314 }
315
316 // OVERWRITE deletes the stale destination so g_file_copy() (G_FILE_COPY_NONE)
317 // does not fail on an existing target.
319 {
321 exists = FALSE;
322 }
323
324 if(exists)
325 {
326 *discarded = g_list_prepend(*discarded, g_strdup(filename));
328 dt_print(DT_DEBUG_IMPORT, "[Import] File copy skipped, the target file %s already exists on the destination.\n", copy_destination);
329 copied = 0;
330 goto cleanup;
331 }
332
334 dt_print(DT_DEBUG_PRINT, "[Import] target folder %s already exists. Nothing to do.\n", data->target_dir);
335 else if(_create_dir(data->target_dir))
336 {
337 fprintf(stdout, "[Import] Unable to create the target folder %s.\n", data->target_dir);
338 goto cleanup;
339 }
340
342 {
343 fprintf(stdout, "[Import] Not allowed to write in the %s folder.\n", data->target_dir);
344 goto cleanup;
345 }
346
347 if(!_copy_file(filename, copy_destination))
348 {
349 fprintf(stderr, "[Import] Unable to copy the file %s to %s.\n", filename, copy_destination);
350 goto cleanup;
351 }
352
356 copied = 1;
357
358cleanup:
360 return copied;
361}
362
363void _write_xmp_id(const char *filename, int32_t imgid)
364{
365 GList *res = dt_metadata_get(imgid, "Xmp.darktable.image_id", NULL);
366 if(!IS_NULL_PTR(res))
367 {
368 // Image ID is already set in metadata, don't overwrite it
370 res = NULL;
371 return;
372 }
373 // else : init it
374 GError *error = NULL;
375 GFile *gfile = g_file_new_for_path(filename);
380 const char *fn = g_file_info_get_name(info);
381
384 dt_datetime_unix_to_exif(dt_txt, sizeof(dt_txt), &datetime);
385 const char *id = g_strconcat(fn, "-", dt_txt, NULL);
386 dt_metadata_set(imgid, "Xmp.darktable.image_id", id, FALSE);
387 g_object_unref(info);
390}
391
405int32_t _import_image(const GList *img, dt_control_import_t *data, const char *final_destination, GList **discarded, int *xmps)
406{
407 const char *filename = (const char*) img->data;
408
409 gchar img_path_to_db[DT_PATH_MAX] = { 0 };
410 int copy_status = 0;
411
412 if(data->copy)
413 {
414 copy_status = _import_copy_file(filename, final_destination, data, img_path_to_db, sizeof(img_path_to_db), discarded);
415 if(copy_status < 0) return UNKNOWN_IMAGE;
416 }
417 else
418 // destination = origin, nothing to do
419 g_strlcpy(img_path_to_db, filename, sizeof(img_path_to_db));
420
421 if(img_path_to_db[0] == 0)
422 {
423 fprintf(stderr, "[Import] Could not import file from disk: empty file path\n");
424 return UNKNOWN_IMAGE;
425 }
426
427 const int32_t imgid = _import_job(data, img_path_to_db);
428 if(imgid <= 0)
429 {
430 dt_control_log(_("Error importing file in collection: %s"), img_path_to_db);
431 fprintf(stderr, "[Import] Error importing file in collection: %s", img_path_to_db);
432 return UNKNOWN_IMAGE;
433 }
434
436 dt_print(DT_DEBUG_IMPORT, "[Import] Found and imported %i XMP for %s.\n", *xmps, img_path_to_db);
437 dt_print(DT_DEBUG_IMPORT, "[Import] successfully imported %s in DB at imgid %i\n", img_path_to_db, imgid);
438
439 if(!data->delete_source || copy_status != 1) goto apply_styles;
440
441 int identical = 0;
444 if(g_stat(filename, &source_stat) == 0
446 && source_stat.st_size == destination_stat.st_size)
447 {
448 FILE *source = g_fopen(filename, "rb");
449 FILE *destination = g_fopen(img_path_to_db, "rb");
450 if(!IS_NULL_PTR(source) && !IS_NULL_PTR(destination))
451 identical = dt_util_streams_equal(source, destination);
452 if(!IS_NULL_PTR(source)) fclose(source);
453 if(!IS_NULL_PTR(destination)) fclose(destination);
454 }
455
456 if(identical != 1)
457 dt_control_log(_("The imported file differs from the original, which was not deleted: %s"), filename);
458 else if(g_unlink(filename) != 0)
459 dt_control_log(_("The imported file was verified but the original could not be deleted: %s"), filename);
460
462 if(IS_NULL_PTR(data->styles)) return imgid;
463
464 dt_hm_batch_state_t batch = { 0 };
465 for(GList *s = data->styles; s; s = g_list_next(s))
466 {
467 const char *style_name = (const char *)s->data;
468 const int32_t style_id = dt_styles_get_id_by_name(style_name);
469 if(style_id <= 0) continue;
471 }
474
475 return imgid;
476}
477
481static void _refresh_progress_counter(dt_job_t *job, const int elements, const int index,
482 const gboolean folder_survey)
483{
484 gchar message[128] = { 0 };
485 double fraction = (double)index / (double)elements;
486 if(folder_survey)
487 snprintf(message, sizeof(message),
488 ngettext("Capture: importing %i/%i image", "Capture: importing %i/%i images", index),
489 index, elements);
490 else
491 snprintf(message, sizeof(message),
492 ngettext("Importing %i/%i image", "Importing %i/%i images", index),
493 index, elements);
496 g_usleep(100);
497}
498
500{
502 dt_control_import_t *data = params->data;
503
504 int index = 0;
505 int xmps = 0; // number of xmps imported in db.
506 int32_t imgid = UNKNOWN_IMAGE;
507 int32_t last_imgid = UNKNOWN_IMAGE;
508 gint64 last_collection_refresh = 0;
512 };
513
514 // What this import may do to the view the user is in, decided once from what the import IS. An
515 // automatic (folder survey) one never moves them: Studio Capture displays the capture itself,
516 // from DT_SIGNAL_IMAGE_IMPORT, and the survey outlives its atelier. A requested one shows the
517 // grid as images arrive, and opens the darkroom instead if it turns out to have imported one.
520 const char *no_image_message = _("No image imported!");
521 if(data->folder_survey)
522 {
525 no_image_message = _("Capture: No image imported!");
526 }
527
539 for(GList *img = g_list_first(data->imgs); img; img = g_list_next(img))
540 {
541 const char *filename = (const char *)img->data;
542 int capture_sequence = 0;
543 gboolean import_ready = !data->copy;
544 gchar *destination = NULL;
546 imgid = UNKNOWN_IMAGE;
547
548 dt_print(DT_DEBUG_IMPORT, "[Import] starting import of image #%i...\n", index);
549
550 _refresh_progress_counter(job, data->elements, index, data->folder_survey);
551 if(!data->copy) goto import_image;
552
553 capture_sequence = dt_import_sequence_assign(&sequences, filename);
557
558 if(!IS_NULL_PTR(strstr(data->target_file_pattern, "$(EXIF"))
559 || !IS_NULL_PTR(strstr(data->target_subfolder_pattern, "$(EXIF")))
560 dt_exif_read(expansion_image, filename);
561
562 const dt_import_destination_t request = { filename, expansion_image, data, capture_sequence };
563 destination = dt_import_sequence_destination(&sequences, &request);
564 import_ready = !IS_NULL_PTR(destination);
565
567 if(import_ready) imgid = _import_image(img, data, destination, &data->discarded, &xmps);
569 dt_free(destination)
571 if(!IS_NULL_PTR(data->file_imported))
572 data->file_imported((const char *)img->data, imgid > UNKNOWN_IMAGE, data->callback_data);
573
574 if(imgid <= UNKNOWN_IMAGE) continue;
575 last_imgid = imgid;
576
577 // On the first image, try to switch the current filmroll to the imported image's folder.
578 // dt_collection_load_filmroll() silently declines to do anything (no collection refresh)
579 // when it cannot switch folders, e.g. the collect module is not on the "Folders" tab. In
580 // that case a single imported image would never show up until the user reloads the
581 // collection by hand (issue #860). So always run a collection update afterwards: it
582 // re-runs the current query and makes newly-imported matching images appear.
583 if(index == 0)
585
586 // known_image_folder is NULL: in copy mode the image's final DB location can be a
587 // completely different, pattern-generated folder from its original source path, which is
588 // all this loop has at hand -- dt_collection_notify_imported() must resolve it fresh.
590
591 index++;
592 }
593
594 g_hash_table_destroy(sequences.destinations);
596
597 if(index == 0)
598 {
599 dt_conf_set_int("ui_last/nb_imported", index);
601 fprintf(stderr, "No image imported!\n\n");
602 return 1;
603 }
604
605 // Guarantee the final state is reflected even if the last few images landed inside the throttle window.
607 dt_conf_set_int("ui_last/nb_imported", index);
608
609 // Don't open the picture in darkroom if more than 1 xmp (= duplicates) has been imported: the
610 // single file then stands for several images in the DB and none of them is the obvious one to
611 // open. Zero xmp is the ordinary case of a file with no sidecar (and of a library configured
612 // not to write any), still exactly one image: open it like any other single import.
613 if(index == 1 && xmps <= 1)
614 {
615 // A requested single image opens in the darkroom, which is announcement enough -- only the
616 // survey, which stays where it is, says anything.
617 if(data->folder_survey) dt_control_log(_("Capture: imported 1 image."));
619 return 0;
620 }
621
623 ? ngettext("Capture: imported %d image.", "Capture: imported %d images.", index)
624 : ngettext("Imported %d image", "Imported %d images", index), index);
625 fprintf(stdout, "%d files imported in database.\n\n", index);
626
627 return 0;
628}
629
631{
633 dt_free(data->jobcode);
634 dt_free(data->base_folder);
637 dt_free(data->target_dir);
638 if(data->styles)
639 {
641 data->styles = NULL;
642 }
645 data->callback_data = NULL;
646
647 // GList of pathes stored as *char. We need to free the list and the *char
648 if(data->discarded)
649 {
651 data->discarded = NULL;
652 }
653 if(data->imgs)
654 {
656 data->imgs = NULL;
657 }
658}
659
660/* Installed by the GUI at startup; absent under ansel-cli, where the discarded list is
661 * simply freed with the rest -- a headless import has nobody to show a dialog to. */
663
668
669/* The discarded-files recap dialog lives in gui/import.c now: it was the only GUI
670 * code in this job file, and the only reason a control-layer TU included
671 * widgets/ and gui/ headers. The job reaches it through the handler below. */
672
674{
676 dt_control_import_t *data = params->data;
677
678 // Display a recap of files that weren't copied
680 {
681 // Called on THIS worker thread: getting onto the GUI main loop is the handler's
682 // business (g_main_context_invoke is GTK machinery, not a job's). The handler owns
683 // freeing data and params, whenever it is done with them.
685 }
686 else
687 {
689 dt_free(data);
691 }
692}
693
695{
697 if(IS_NULL_PTR(params)) return NULL;
698
699 params->data = g_malloc0(sizeof(dt_control_import_t));
700 if(IS_NULL_PTR(params->data))
701 {
703 return NULL;
704 }
705 return params;
706}
707
709{
711 if(IS_NULL_PTR(job)) return NULL;
714 {
716 return NULL;
717 }
718 memcpy(params->data, &data, sizeof(dt_control_import_t));
719 params->index = NULL;
720 dt_control_job_add_progress(job, _("import"), FALSE);
722 return job;
723}
724
726{
728 if(IS_NULL_PTR(job))
729 {
730 // Report every source as failed so asynchronous clients can release their queued state.
731 for(GList *img = g_list_first(data.imgs); img; img = g_list_next(img))
732 if(!IS_NULL_PTR(data.file_imported))
733 data.file_imported((const char *)img->data, FALSE, data.callback_data);
734
736 return 1;
737 }
738
740}
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void cleanup(dt_imageio_module_format_t *self)
Definition avif.c:170
void dt_collection_update_query(const dt_collection_t *collection, dt_collection_change_t query_change, dt_collection_properties_t changed_property, GList *list)
Definition collection.c:837
dt_collection_t * dt_collection_get_global(void)
Definition collection.c:138
void dt_collection_notify_imported(const int32_t imgid, const gchar *known_image_folder, gint64 *last_refresh_us)
void dt_collection_load_filmroll(dt_collection_t *collection, const int32_t imgid, dt_collection_import_view_t view_policy, gboolean set_mouse_over)
@ DT_COLLECTION_PROP_UNDEF
Definition collection.h:155
@ DT_COLLECTION_CHANGE_NEW_QUERY
Definition collection.h:162
dt_collection_import_view_t
Definition collection.h:269
@ DT_COLLECTION_IMPORT_VIEW_KEEP
Definition collection.h:273
@ DT_COLLECTION_IMPORT_VIEW_GRID
Definition collection.h:275
@ DT_COLLECTION_IMPORT_VIEW_IMAGE
Definition collection.h:277
const dt_colormatrix_t dt_aligned_pixel_t out
void dt_conf_set_int(const char *name, int val)
int32_t dt_image_import(const int32_t film_id, const char *filename, gboolean raise_signals)
char * dt_image_get_text_path_from_path(const char *image_path)
void dt_image_init(dt_image_t *img)
GList * dt_image_find_xmps(const char *filename)
int dt_image_read_duplicates(const uint32_t id, const char *filename, const gboolean clear_selection)
char * dt_image_build_text_path_from_path(const char *image_path)
void dt_image_history_changed(const int32_t imgid, const gboolean refresh_filmstrip)
void dt_control_log(const char *msg,...)
Definition control.c:839
struct dt_control_t * dt_control_get_global(void)
Definition darktable.c:651
void * dt_control_image_enumerator_alloc()
void dt_control_image_enumerator_cleanup(void *p)
void * dt_alloc_align(size_t size)
Allocate cacheline-aligned memory.
Definition darktable.c:508
gboolean dt_datetime_unix_to_exif(char *exif, const size_t exif_size, const time_t *unix)
Definition datetime.c:212
#define DT_DATETIME_EXIF_LENGTH
Definition datetime.h:39
const int res
Definition dtpthread.h:351
int dt_exif_read(dt_image_t *img, const char *path)
Definition exif.cc:1994
What a photograph says about itself: the EXIF, IPTC and XMP tags a camera and a cataloguer write,...
int dt_film_new(dt_film_t *film, const char *directory)
Definition film.c:129
void dt_hm_batch_state_cleanup(dt_hm_batch_state_t *batch)
Release resources held by a batch state (the cached order). Safe to call on a zeroed state.
@ DT_HISTORY_MERGE_APPEND
#define UNKNOWN_IMAGE
Definition image.h:78
static void * _control_import_alloc()
gboolean _create_dir(const char *path)
Creates folders from path. Returns TRUE if success.
Definition import_jobs.c:53
static void _control_import_job_cleanup(void *p)
gchar * dt_build_filename_from_pattern(const char *const filename, const int index, dt_image_t *img, dt_control_import_t *data)
Build a full path for a given image file, given a pattern.
Definition import_jobs.c:79
gboolean _copy_file(const char *filename, const char *dest_file_path)
Just copy a file. Returns 1 if success.
static dt_control_import_discarded_handler_t _discarded_files_handler
void dt_import_duplicate_get_dest_name(char *xmp_dest_name, const char *dest_file_path, const int counter)
Gets the computed xmp file name with apropriate number for import copy. It computes a duplicate name ...
int32_t _import_image(const GList *img, dt_control_import_t *data, const char *final_destination, GList **discarded, int *xmps)
process to copy (or not) and import an image to database.
int dt_control_import(dt_control_import_t data)
Process a list of images to import with or without copying the files on an arbitrary hard-drive.
static int32_t _control_import_job_run(dt_job_t *job)
static dt_job_t * _control_import_job_create(dt_control_import_t data)
static void _refresh_progress_counter(dt_job_t *job, const int elements, const int index, const gboolean folder_survey)
Update import progress with wording matching the import origin.
gboolean _file_exist(const char *dest_file_path)
Tests if file exist. Returns 1 if so.
const int32_t _import_job(dt_control_import_t *data, gchar *img_path_to_db)
Add an image entry in the database and returns its imgID.
int _import_copy_xmp(const char *const filename, const gchar *dest_file_path)
Attempt to find all sidecar XMP files along an image file and import (copy) it to destination.
int _import_copy_file(const char *const filename, const char *const dest_file_path, dt_control_import_t *data, gchar *img_path_to_db, size_t pathname_len, GList **discarded)
copy a file to a destination path after checking if everything is allright.
void _write_xmp_id(const char *filename, int32_t imgid)
gchar * _path_cleanup(gchar *path_in)
Replaces separator depending of the current OS and removes whitespaces.
Definition import_jobs.c:71
void dt_control_import_set_discarded_files_handler(dt_control_import_discarded_handler_t handler)
int _import_copy_txt(const char *const filename, const char *dest_file_path)
void dt_control_import_data_free(dt_control_import_t *data)
@ DT_IMPORT_ONCONFLICT_UNIQUE
Definition import_jobs.h:39
@ DT_IMPORT_ONCONFLICT_OVERWRITE
Definition import_jobs.h:38
void(* dt_control_import_discarded_handler_t)(struct dt_control_image_enumerator_t *params)
char * dt_import_sequence_destination(dt_import_sequence_t *sequences, const dt_import_destination_t *request)
Expand and reserve a destination, retrying a sibling collision exactly once.
int dt_import_sequence_assign(dt_import_sequence_t *sequences, const char *filename)
Assign a capture number, retaining it even when subsequent expansion fails.
dt_job_t * dt_control_job_create(dt_job_execute_callback execute, const char *msg,...)
Definition jobs.c:138
int dt_control_add_job(dt_control_t *control, dt_job_queue_t queue_id, _dt_job_t *job)
Definition jobs.c:419
void * dt_control_job_get_params(const _dt_job_t *job)
Definition jobs.c:132
void dt_control_job_set_progress(dt_job_t *job, double value)
Definition jobs.c:701
void dt_control_job_add_progress(dt_job_t *job, const char *message, gboolean cancellable)
Definition jobs.c:687
void dt_control_job_set_progress_message(dt_job_t *job, const char *message)
Definition jobs.c:695
void dt_control_job_set_params(_dt_job_t *job, void *params, dt_job_destroy_callback callback)
Definition jobs.c:115
void dt_control_job_dispose(_dt_job_t *job)
Definition jobs.c:156
@ DT_JOB_QUEUE_USER_FG
Definition jobs.h:55
static const dt_iop_drawlayer_params_t * params
Definition layers.h:80
@ DT_DEBUG_PRINT
Definition logging.h:65
@ DT_DEBUG_IMPORT
Definition logging.h:77
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
#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
void dt_metadata_set(const int32_t imgid, const char *key, const char *value, const gboolean undo_on)
GList * dt_metadata_get(const int id, const char *key, uint32_t *count)
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
int dt_styles_apply_to_image_merge(const char *name, const int style_id, const int32_t newimgid, const dt_history_merge_strategy_t mode, dt_hm_batch_state_t *batch)
int32_t dt_styles_get_id_by_name(const char *name)
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_datetime(dt_variables_params_t *params, GDateTime *datetime)
dt_import_onconflict_t on_conflict
Definition import_jobs.h:51
GDateTime * datetime
Definition import_jobs.h:45
GDestroyNotify callback_data_free
Definition import_jobs.h:89
void(* file_imported)(const char *source, gboolean success, gpointer user_data)
Optional per-file completion method.
Definition import_jobs.h:87
char * target_subfolder_pattern
Definition import_jobs.h:65
Borrowed inputs for one destination expansion.
Job-local numbering and reservation state; table lifetime belongs to the worker.
typedef double((*spd)(unsigned long int wavelength, double TempK))
gchar * dt_cleanup_separators(gchar *string)
Definition utility.c:1091
gboolean dt_util_dir_exist(const char *dir)
Definition utility.c:394
int dt_util_streams_equal(FILE *first, FILE *second)
Compare the remaining bytes of two borrowed binary streams.
Definition utility.c:94
gchar * dt_util_path_get_dirname(const gchar *filename)
Definition utility.c:800
gchar * dt_util_normalize_path(const gchar *_input)
Definition utility.c:706
size_t safe_strlen(const char *str)
check if the string is empty or NULL before calling strlen()
Definition utility.c:117
gboolean dt_util_test_writable_dir(const char *path)
Definition utility.c:371
gchar * dt_util_remove_whitespace(const gchar *path)
Definition utility.c:1102