36#include <glib/gstdio.h>
54 if(g_mkdir_with_parents(path, 0755) == -1)
56 fprintf(stderr,
"failed to create directory %s.\n", path);
57 dt_control_log(_(
"Impossible to create directory %s.\nThe target may be full or read-only.\n"), path);
84 params->filename = filename;
85 params->sequence = index;
86 params->jobcode = data->
jobcode;
100 gchar *dir = g_build_path(G_DIR_SEPARATOR_S, data->
base_folder, path, (
char *) NULL);
102 gchar *
res = g_build_path(G_DIR_SEPARATOR_S, data->
target_dir, file, (
char *) NULL);
121 return !
IS_NULL_PTR(dest_file_path) && dest_file_path[0] && g_file_test(dest_file_path, G_FILE_TEST_EXISTS);
131gboolean
_copy_file(
const char *filename,
const char *dest_file_path)
133 GFile *in = g_file_new_for_path(filename);
134 GFile *
out = g_file_new_for_path(dest_file_path);
136 gboolean
res = g_file_copy(in,
out, G_FILE_COPY_NONE, 0, 0, 0, NULL);
157 const int32_t filmid =
dt_film_new(&film, dirname);
182 char *ext = norm_dest_file +
safe_strlen(norm_dest_file);
183 while(*ext !=
'.' && ext > norm_dest_file) ext--;
187 g_snprintf(xmp_dest_name,
DT_PATH_MAX,
"%s.xmp", norm_dest_file);
189 g_snprintf(xmp_dest_name,
DT_PATH_MAX,
"%.*s_%.2d%s.xmp", (
int)name_len, norm_dest_file, counter, ext);
208 if(g_list_length(xmp_files) > 0)
210 for(GList *current_xmp = xmp_files; current_xmp; current_xmp = g_list_next(current_xmp))
212 char *xmp_source = g_strdup((
char*) current_xmp->data);
217 int success =
_copy_file(xmp_source, xmp_dest_name);
219 (success) ?
"succeeded" :
"failed");
220 if(success) xmp_cntr++;
224 g_list_free(xmp_files);
241 (success) ?
"succeeded" :
"failed");
246 return success ? 1 : 0;
270 dt_print(
DT_DEBUG_IMPORT,
"[Import] EXIF will be read for %s because the pattern needs it (performance penalty)\n", filename);
287 const char *dot = strrchr(dest_file_path,
'.');
288 const int stem_len = dot ? (int)(dot - dest_file_path) : (int)strlen(dest_file_path);
289 const char *ext = dot ? dot :
"";
291 for(
int seq = 1; seq < 10000; seq++)
294 unique = g_strdup_printf(
"%.*s_%02d%s", stem_len, dest_file_path, seq, ext);
298 dest_file_path = unique;
306 g_unlink(dest_file_path);
320 fprintf(stdout,
"[Import] Unable to create the target folder %s.\n", data->
target_dir);
328 fprintf(stdout,
"[Import] Not allowed to write in the %s folder.\n", data->
target_dir);
337 g_strlcpy(img_path_to_db, dest_file_path, pathname_len);
339 fprintf(stderr,
"[Import] Unable to copy the file %s to %s.\n", img_path_to_db, dest_file_path);
344 *discarded = g_list_prepend(*discarded, g_strdup(filename));
345 g_strlcpy(img_path_to_db, dest_file_path, pathname_len);
346 dt_print(
DT_DEBUG_IMPORT,
"[Import] File copy skipped, the target file %s already exists on the destination.\n", dest_file_path);
364 GError *
error = NULL;
365 GFile *gfile = g_file_new_for_path(filename);
366 GFileInfo *info = g_file_query_info(gfile,
367 G_FILE_ATTRIBUTE_STANDARD_NAME
","
368 G_FILE_ATTRIBUTE_TIME_MODIFIED,
369 G_FILE_QUERY_INFO_NONE, NULL, &
error);
370 const char *fn = g_file_info_get_name(info);
372 const time_t datetime = g_file_info_get_attribute_uint64(info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
375 const char *
id = g_strconcat(fn,
"-", dt_txt, NULL);
377 g_object_unref(info);
378 g_object_unref(gfile);
379 g_clear_error(&
error);
392 const char *filename = (
const char*) img->data;
395 gboolean process_error =
FALSE;
402 copy_status =
_import_copy_file(filename, index + 1, data, img_path_to_db,
sizeof(img_path_to_db), discarded);
403 process_error = copy_status < 0;
407 g_strlcpy(img_path_to_db, filename,
sizeof(img_path_to_db));
411 else if(img_path_to_db[0] == 0)
412 fprintf(stderr,
"[Import] Could not import file from disk: empty file path\n");
419 dt_control_log(_(
"Error importing file in collection: %s"), img_path_to_db);
420 fprintf(stderr,
"[Import] Error importing file in collection: %s", img_path_to_db);
433 gboolean identical =
FALSE;
434 GStatBuf source_stat;
435 GStatBuf destination_stat;
436 if(g_stat(filename, &source_stat) == 0
437 && g_stat(img_path_to_db, &destination_stat) == 0
438 && source_stat.st_size == destination_stat.st_size)
440 FILE *source = g_fopen(filename,
"rb");
441 FILE *destination = g_fopen(img_path_to_db,
"rb");
444 const size_t buffer_size = 64 * 1024;
445 unsigned char *source_buffer = malloc(buffer_size);
446 unsigned char *destination_buffer = malloc(buffer_size);
451 const size_t source_read = fread(source_buffer, 1, buffer_size, source);
452 const size_t destination_read = fread(destination_buffer, 1, buffer_size, destination);
453 if(source_read != destination_read
454 || memcmp(source_buffer, destination_buffer, source_read))
457 if(source_read < buffer_size)
459 if(ferror(source) || ferror(destination)) identical =
FALSE;
474 if(g_unlink(filename) != 0)
475 dt_control_log(_(
"The imported file was verified but the original could not be deleted: %s"), filename);
478 dt_control_log(_(
"The imported file differs from the original, which was not deleted: %s"), filename);
487 for(GList *s = data->
styles; s; s = g_list_next(s))
489 const char *style_name = (
const char *)s->data;
491 if(style_id <= 0)
continue;
510 const gboolean folder_survey)
512 gchar message[128] = { 0 };
513 double fraction = (
double)index / (
double)elements;
515 snprintf(message,
sizeof(message),
516 ngettext(
"Capture: importing %i/%i image",
"Capture: importing %i/%i images", index),
519 snprintf(message,
sizeof(message),
520 ngettext(
"Importing %i/%i image",
"Importing %i/%i images", index),
535 gint64 last_collection_refresh = 0;
548 for(GList *img = g_list_first(data->
imgs); img; img = g_list_next(img))
586 fprintf(stderr,
"No image imported!\n\n");
594 if(index == 1 && xmps <= 1)
604 ? ngettext(
"Capture: imported %d image.",
"Capture: imported %d images.", index)
605 : ngettext(
"Imported %d image",
"Imported %d images", index), index);
606 fprintf(stdout,
"%d files imported in database.\n\n", index);
700 params->index = NULL;
712 for(GList *img = g_list_first(data.
imgs); img; img = g_list_next(img))
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
static void error(char *msg)
void dt_collection_update_query(const dt_collection_t *collection, dt_collection_change_t query_change, dt_collection_properties_t changed_property, GList *list)
dt_collection_t * dt_collection_get_global(void)
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
@ DT_COLLECTION_CHANGE_NEW_QUERY
dt_collection_import_view_t
@ DT_COLLECTION_IMPORT_VIEW_KEEP
@ DT_COLLECTION_IMPORT_VIEW_GRID
@ DT_COLLECTION_IMPORT_VIEW_IMAGE
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,...)
struct dt_control_t * dt_control_get_global(void)
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.
gboolean dt_datetime_unix_to_exif(char *exif, const size_t exif_size, const time_t *unix)
#define DT_DATETIME_EXIF_LENGTH
int dt_exif_read(dt_image_t *img, const char *path)
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)
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
int _import_copy_file(const char *const filename, const int index, 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.
static void * _control_import_alloc()
int _import_copy_xmp(const char *const filename, gchar *dest_file_path)
Attempt to find all sidecar XMP files along an image file and import (copy) it to destination.
gboolean _create_dir(const char *path)
Creates folders from path. Returns TRUE if success.
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.
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 int index, 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.
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.
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
@ DT_IMPORT_ONCONFLICT_OVERWRITE
void(* dt_control_import_discarded_handler_t)(struct dt_control_image_enumerator_t *params)
dt_job_t * dt_control_job_create(dt_job_execute_callback execute, const char *msg,...)
int dt_control_add_job(dt_control_t *control, dt_job_queue_t queue_id, _dt_job_t *job)
void * dt_control_job_get_params(const _dt_job_t *job)
void dt_control_job_set_progress(dt_job_t *job, double value)
void dt_control_job_add_progress(dt_job_t *job, const char *message, gboolean cancellable)
void dt_control_job_set_progress_message(dt_job_t *job, const char *message)
void dt_control_job_set_params(_dt_job_t *job, void *params, dt_job_destroy_callback callback)
void dt_control_job_dispose(_dt_job_t *job)
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...
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
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
GDestroyNotify callback_data_free
void(* file_imported)(const char *source, gboolean success, gpointer user_data)
Optional per-file completion method.
char * target_file_pattern
char * target_subfolder_pattern
typedef double((*spd)(unsigned long int wavelength, double TempK))
gchar * dt_cleanup_separators(gchar *string)
gboolean dt_util_dir_exist(const char *dir)
gchar * dt_util_path_get_dirname(const gchar *filename)
gchar * dt_util_normalize_path(const gchar *_input)
size_t safe_strlen(const char *str)
check if the string is empty or NULL before calling strlen()
gboolean dt_util_test_writable_dir(const char *path)
gchar * dt_util_remove_whitespace(const gchar *path)