52 if(g_mkdir_with_parents(path, 0755) == -1)
54 fprintf(stderr,
"failed to create directory %s.\n", path);
55 dt_control_log(_(
"Impossible to create directory %s.\nThe target may be full or read-only.\n"), path);
82 params->filename = filename;
83 params->sequence = index;
84 params->jobcode = data->
jobcode;
98 gchar *dir = g_build_path(G_DIR_SEPARATOR_S, data->
base_folder, path, (
char *) NULL);
100 gchar *res = g_build_path(G_DIR_SEPARATOR_S, data->
target_dir, file, (
char *) NULL);
119 return !
IS_NULL_PTR(dest_file_path) && dest_file_path[0] && g_file_test(dest_file_path, G_FILE_TEST_EXISTS);
129gboolean
_copy_file(
const char *filename,
const char *dest_file_path)
131 GFile *in = g_file_new_for_path(filename);
132 GFile *
out = g_file_new_for_path(dest_file_path);
134 gboolean res = g_file_copy(in,
out, G_FILE_COPY_NONE, 0, 0, 0, NULL);
155 const int32_t filmid =
dt_film_new(&film, dirname);
180 char *ext = norm_dest_file +
safe_strlen(norm_dest_file);
181 while(*ext !=
'.' && ext > norm_dest_file) ext--;
185 g_snprintf(xmp_dest_name,
PATH_MAX,
"%s.xmp", norm_dest_file);
187 g_snprintf(xmp_dest_name,
PATH_MAX,
"%.*s_%.2d%s.xmp", (
int)name_len, norm_dest_file, counter, ext);
206 if(g_list_length(xmp_files) > 0)
208 for(GList *current_xmp = xmp_files; current_xmp; current_xmp = g_list_next(current_xmp))
210 char *xmp_source = g_strdup((
char*) current_xmp->data);
211 gchar xmp_dest_name[
PATH_MAX] = { 0 };
215 int success =
_copy_file(xmp_source, xmp_dest_name);
217 (success) ?
"succeeded" :
"failed");
218 if(success) xmp_cntr++;
222 g_list_free(xmp_files);
239 (success) ?
"succeeded" :
"failed");
244 return success ? 1 : 0;
268 dt_print(
DT_DEBUG_IMPORT,
"[Import] EXIF will be read for %s because the pattern needs it (performance penalty)\n", filename);
285 const char *dot = strrchr(dest_file_path,
'.');
286 const int stem_len = dot ? (int)(dot - dest_file_path) : (int)strlen(dest_file_path);
287 const char *ext = dot ? dot :
"";
289 for(
int seq = 1; seq < 10000; seq++)
292 unique = g_strdup_printf(
"%.*s_%02d%s", stem_len, dest_file_path, seq, ext);
296 dest_file_path = unique;
304 g_unlink(dest_file_path);
318 fprintf(stdout,
"[Import] Unable to create the target folder %s.\n", data->
target_dir);
326 fprintf(stdout,
"[Import] Not allowed to write in the %s folder.\n", data->
target_dir);
335 g_strlcpy(img_path_to_db, dest_file_path, pathname_len);
337 fprintf(stderr,
"[Import] Unable to copy the file %s to %s.\n", img_path_to_db, dest_file_path);
342 *discarded = g_list_prepend(*discarded, g_strdup(filename));
343 g_strlcpy(img_path_to_db, dest_file_path, pathname_len);
344 dt_print(
DT_DEBUG_IMPORT,
"[Import] File copy skipped, the target file %s already exists on the destination.\n", dest_file_path);
362 GError *
error = NULL;
363 GFile *gfile = g_file_new_for_path(filename);
364 GFileInfo *info = g_file_query_info(gfile,
365 G_FILE_ATTRIBUTE_STANDARD_NAME
","
366 G_FILE_ATTRIBUTE_TIME_MODIFIED,
367 G_FILE_QUERY_INFO_NONE, NULL, &
error);
368 const char *fn = g_file_info_get_name(info);
370 const time_t datetime = g_file_info_get_attribute_uint64(info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
373 const char *
id = g_strconcat(fn,
"-", dt_txt, NULL);
375 g_object_unref(info);
376 g_object_unref(gfile);
377 g_clear_error(&
error);
390 const char *filename = (
const char*) img->data;
392 gchar img_path_to_db[
PATH_MAX] = { 0 };
393 gboolean process_error =
FALSE;
400 copy_status =
_import_copy_file(filename, index, data, img_path_to_db,
sizeof(img_path_to_db), discarded);
401 process_error = copy_status < 0;
405 g_strlcpy(img_path_to_db, filename,
sizeof(img_path_to_db));
409 else if(img_path_to_db[0] == 0)
410 fprintf(stderr,
"[Import] Could not import file from disk: empty file path\n");
417 dt_control_log(_(
"Error importing file in collection: %s"), img_path_to_db);
418 fprintf(stderr,
"[Import] Error importing file in collection: %s", img_path_to_db);
431 gboolean identical =
FALSE;
432 GStatBuf source_stat;
433 GStatBuf destination_stat;
434 if(g_stat(filename, &source_stat) == 0
435 && g_stat(img_path_to_db, &destination_stat) == 0
436 && source_stat.st_size == destination_stat.st_size)
438 FILE *source = g_fopen(filename,
"rb");
439 FILE *destination = g_fopen(img_path_to_db,
"rb");
442 const size_t buffer_size = 64 * 1024;
443 unsigned char *source_buffer = malloc(buffer_size);
444 unsigned char *destination_buffer = malloc(buffer_size);
449 const size_t source_read = fread(source_buffer, 1, buffer_size, source);
450 const size_t destination_read = fread(destination_buffer, 1, buffer_size, destination);
451 if(source_read != destination_read
452 || memcmp(source_buffer, destination_buffer, source_read))
455 if(source_read < buffer_size)
457 if(ferror(source) || ferror(destination)) identical =
FALSE;
472 if(g_unlink(filename) != 0)
473 dt_control_log(_(
"The imported file was verified but the original could not be deleted: %s"), filename);
476 dt_control_log(_(
"The imported file differs from the original, which was not deleted: %s"), filename);
485 for(GList *s = data->
styles; s; s = g_list_next(s))
487 const char *style_name = (
const char *)s->data;
489 if(style_id <= 0)
continue;
508 const gboolean folder_survey)
510 gchar message[128] = { 0 };
511 double fraction = (
double)index / (
double)elements;
513 snprintf(message,
sizeof(message),
514 ngettext(
"Capture: importing %i/%i image",
"Capture: importing %i/%i images", index),
517 snprintf(message,
sizeof(message),
518 ngettext(
"Importing %i/%i image",
"Importing %i/%i images", index),
533 gint64 last_collection_refresh = 0;
535 for(GList *img = g_list_first(data->
imgs); img; img = g_list_next(img))
562 const gint64 now = g_get_monotonic_time();
563 if(now - last_collection_refresh > 250000)
566 last_collection_refresh = now;
583 fprintf(stderr,
"No image imported!\n\n");
586 else if(index == 1 && xmps == 1)
596 "Capture: imported %d images.", index), index);
598 dt_control_log(ngettext(
"Imported %d image",
"Imported %d images", index), index);
599 fprintf(stdout,
"%d files imported in database.\n\n", index);
604 return index >= 1 ? 0 : 1;
642 GtkWidget *dialog = gtk_dialog_new_with_buttons(
"Message",
644 GTK_DIALOG_DESTROY_WITH_PARENT,
648 gtk_window_set_title(GTK_WINDOW(dialog), _(
"Some files have not been copied"));
652 GtkWidget *label = gtk_label_new(_(
"The following source files have not been copied "
653 "because similarly-named files already exist on the destination. "
654 "This may be because the files have already been imported "
655 "or the naming pattern leads to non-unique file names."));
656 gtk_label_set_line_wrap(GTK_LABEL(label),
TRUE);
659 GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
660 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC,
661 GTK_POLICY_AUTOMATIC);
662 gtk_scrolled_window_set_propagate_natural_height(GTK_SCROLLED_WINDOW(scrolled_window),
TRUE);
665 GtkListStore *
store = gtk_list_store_new(1, G_TYPE_STRING);
667 for(GList *file = g_list_first(data->
discarded); file; file = g_list_next(file))
671 gtk_list_store_append(
store, &iter);
672 gtk_list_store_set(
store, &iter, 0, (
char *)file->data, -1);
678 GtkTreeViewColumn *col = gtk_tree_view_column_new();
679 gtk_tree_view_column_set_title(col, _(
"Origin path"));
680 GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
681 gtk_tree_view_column_pack_start(col, renderer,
TRUE);
682 gtk_tree_view_column_set_attributes(col, renderer,
"text", 0, NULL);
683 gtk_tree_view_append_column(GTK_TREE_VIEW(
view), col);
684 g_object_unref(
store);
688 gtk_box_pack_start(GTK_BOX(box), label,
TRUE,
TRUE, 0);
689 gtk_box_pack_start(GTK_BOX(box), scrolled_window,
TRUE,
TRUE, 0);
691 gtk_container_add(GTK_CONTAINER(scrolled_window),
view);
694 GtkWidget *content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
695 gtk_container_add(GTK_CONTAINER(content_area), box);
696 gtk_widget_show_all(dialog);
698#ifdef GDK_WINDOWING_QUARTZ
702 gtk_dialog_run(GTK_DIALOG(dialog));
703 gtk_widget_destroy(dialog);
756 params->index = NULL;
768 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)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
void dt_collection_load_filmroll(dt_collection_t *collection, const int32_t imgid, gboolean open_single_image)
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_PROP_UNDEF
@ DT_COLLECTION_CHANGE_NEW_QUERY
const dt_colormatrix_t dt_aligned_pixel_t out
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_conf_set_int(const char *name, int val)
void dt_control_log(const char *msg,...)
void * dt_control_image_enumerator_alloc()
void dt_control_image_enumerator_cleanup(void *p)
uint32_t view(const dt_view_t *self)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
static void dt_free_gpointer(gpointer ptr)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
gboolean dt_datetime_unix_to_exif(char *exif, const size_t exif_size, const time_t *unix)
#define DT_DATETIME_EXIF_LENGTH
int store(dt_imageio_module_storage_t *self, dt_imageio_module_data_t *sdata, const int32_t imgid, dt_imageio_module_format_t *format, dt_imageio_module_data_t *fdata, const int num, const int total, const gboolean high_quality, const gboolean export_masks, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, dt_export_metadata_t *metadata)
int dt_exif_read(dt_image_t *img, const char *path)
int dt_film_new(dt_film_t *film, const char *directory)
void dt_gui_add_class(GtkWidget *widget, const gchar *class_name)
GtkWidget * dt_ui_main_window(dt_ui_t *ui)
get the main window widget
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
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.
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 ...
static int _discarded_files_popup(dt_control_image_enumerator_t *params)
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.
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
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_osx_disallow_fullscreen(GtkWidget *widget)
struct _GtkWidget GtkWidget
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)
struct dt_gui_gtk_t * gui
struct dt_collection_t * collection
struct dt_control_t * control
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)