int32_t dt_image_duplicate(const int32_t imgid) { sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into images " "(id, group_id, film_id, width, height, filename, maker, model, lens, exposure, " "aperture, iso, focal_length, focus_distance, datetime_taken, flags, " "output_width, output_height, crop, raw_parameters, raw_denoise_threshold, " "raw_auto_bright_threshold, raw_black, raw_maximum, " "caption, description, license, sha1sum, orientation, histogram, lightmap, " "longitude, latitude, color_matrix, colorspace) " "select null, group_id, film_id, width, height, filename, maker, model, lens, " "exposure, aperture, iso, focal_length, focus_distance, datetime_taken, " "flags, width, height, crop, raw_parameters, raw_denoise_threshold, " "raw_auto_bright_threshold, raw_black, raw_maximum, " "caption, description, license, sha1sum, orientation, histogram, lightmap, " "longitude, latitude, color_matrix, colorspace " "from images where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select a.id from images as a join images as b where " "a.film_id = b.film_id and a.filename = b.filename and " "b.id = ?1 order by a.id desc", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); int32_t newid = -1; if(sqlite3_step(stmt) == SQLITE_ROW) newid = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); if(newid != -1) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into color_labels (imgid, color) select ?1, color from " "color_labels where imgid = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into meta_data (id, key, value) select ?1, key, value " "from meta_data where id = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into tagged_images (imgid, tagid) select ?1, tagid from " "tagged_images where imgid = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "update tagxtag set count = count + 1 where " "(id1 in (select tagid from tagged_images where imgid = ?1)) or " "(id2 in (select tagid from tagged_images where imgid = ?1))", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newid); sqlite3_step(stmt); sqlite3_finalize(stmt); if(darktable.gui && darktable.gui->grouping) { const dt_image_t *img = dt_image_cache_read_get(darktable.image_cache, newid); darktable.gui->expanded_group_id = img->group_id; dt_image_cache_read_release(darktable.image_cache, img); dt_collection_update_query(darktable.collection); } } return newid; }
/* do the real migration steps, returns the version the db was converted to */ static int _upgrade_schema_step(dt_database_t *db, int version) { sqlite3_stmt *stmt; int new_version = version; if(version == CURRENT_DATABASE_VERSION) return version; else if(version == 0) { // this can't happen, we started with 1, but it's a good example how this function works // <do some magic to the db> new_version = 1; // the version we transformed the db to. this way it might be possible to roll back or add fast paths } else if(version == 1) { // 1 -> 2 added write_timestamp sqlite3_exec(db->handle, "BEGIN TRANSACTION", NULL, NULL, NULL); if(sqlite3_exec(db->handle, "ALTER TABLE images ADD COLUMN write_timestamp INTEGER", NULL, NULL, NULL) != SQLITE_OK) { fprintf(stderr, "[init] can't add `write_timestamp' column to database\n"); fprintf(stderr, "[init] %s\n", sqlite3_errmsg(db->handle)); sqlite3_exec(db->handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); return version; } if(sqlite3_exec(db->handle, "UPDATE images SET write_timestamp = STRFTIME('%s', 'now') WHERE write_timestamp IS NULL", NULL, NULL, NULL) != SQLITE_OK) { fprintf(stderr, "[init] can't initialize `write_timestamp' with current point in time\n"); // let alone space fprintf(stderr, "[init] %s\n", sqlite3_errmsg(db->handle)); sqlite3_exec(db->handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); return version; } sqlite3_exec(db->handle, "COMMIT", NULL, NULL, NULL); new_version = 2; } else if(version == 2) { // 2 -> 3 reset raw_black and raw_maximum. in theory we should change the columns from REAL to INTEGER, but sqlite doesn't care about types so whatever sqlite3_exec(db->handle, "BEGIN TRANSACTION", NULL, NULL, NULL); if(sqlite3_exec(db->handle, "UPDATE images SET raw_black = 0, raw_maximum = 16384", NULL, NULL, NULL) != SQLITE_OK) { fprintf(stderr, "[init] can't reset raw_black and raw_maximum\n"); // let alone space fprintf(stderr, "[init] %s\n", sqlite3_errmsg(db->handle)); sqlite3_exec(db->handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); return version; } sqlite3_exec(db->handle, "COMMIT", NULL, NULL, NULL); new_version = 3; } else if(version == 3) { sqlite3_exec(db->handle, "BEGIN TRANSACTION", NULL, NULL, NULL); if (sqlite3_exec(db->handle, "CREATE TRIGGER insert_tag AFTER INSERT ON tags" " BEGIN" " INSERT INTO tagxtag SELECT id, new.id, 0 FROM TAGS;" " UPDATE tagxtag SET count = 1000000 WHERE id1=new.id AND id2=new.id;" " END", NULL, NULL, NULL) != SQLITE_OK) { fprintf(stderr, "[init] can't create insert_tag trigger\n"); fprintf(stderr, "[init] %s\n", sqlite3_errmsg(db->handle)); sqlite3_exec(db->handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); return version; } if (sqlite3_exec(db->handle, "CREATE TRIGGER delete_tag BEFORE DELETE on tags" " BEGIN" " DELETE FROM tagxtag WHERE id1=old.id OR id2=old.id;" " DELETE FROM tagged_images WHERE tagid=old.id;" " END", NULL, NULL, NULL) != SQLITE_OK) { fprintf(stderr, "[init] can't create delete_tag trigger\n"); fprintf(stderr, "[init] %s\n", sqlite3_errmsg(db->handle)); sqlite3_exec(db->handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); return version; } if (sqlite3_exec(db->handle, "CREATE TRIGGER attach_tag AFTER INSERT ON tagged_images" " BEGIN" " UPDATE tagxtag" " SET count = count + 1" " WHERE (id1=new.tagid AND id2 IN (SELECT tagid FROM tagged_images WHERE imgid=new.imgid))" " OR (id2=new.tagid AND id1 IN (SELECT tagid FROM tagged_images WHERE imgid=new.imgid));" " END", NULL, NULL, NULL) != SQLITE_OK) { fprintf(stderr, "[init] can't create attach_tag trigger\n"); fprintf(stderr, "[init] %s\n", sqlite3_errmsg(db->handle)); sqlite3_exec(db->handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); return version; } if (sqlite3_exec(db->handle, "CREATE TRIGGER detach_tag BEFORE DELETE ON tagged_images" " BEGIN" " UPDATE tagxtag" " SET count = count - 1" " WHERE (id1=old.tagid AND id2 IN (SELECT tagid FROM tagged_images WHERE imgid=old.imgid))" " OR (id2=old.tagid AND id1 IN (SELECT tagid FROM tagged_images WHERE imgid=old.imgid));" " END", NULL, NULL, NULL) != SQLITE_OK) { fprintf(stderr, "[init] can't create detach_tag trigger\n"); fprintf(stderr, "[init] %s\n", sqlite3_errmsg(db->handle)); sqlite3_exec(db->handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); return version; } sqlite3_exec(db->handle, "COMMIT", NULL, NULL, NULL); new_version = 4; } else if(version == 4) { sqlite3_exec(db->handle, "BEGIN TRANSACTION", NULL, NULL, NULL); if (sqlite3_exec(db->handle, "ALTER TABLE presets RENAME TO tmp_presets", NULL, NULL, NULL) != SQLITE_OK) { fprintf(stderr, "[init] can't rename table presets\n"); fprintf(stderr, "[init] %s\n", sqlite3_errmsg(db->handle)); sqlite3_exec(db->handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); return version; } if (sqlite3_exec(db->handle, "CREATE TABLE presets (name VARCHAR, description VARCHAR, operation VARCHAR, op_params BLOB," "enabled INTEGER, blendop_params BLOB, model VARCHAR, maker VARCHAR, lens VARCHAR," "iso_min REAL, iso_max REAL, exposure_min REAL, exposure_max REAL, aperture_min REAL," "aperture_max REAL, focal_length_min REAL, focal_length_max REAL, writeprotect INTEGER," "autoapply INTEGER, filter INTEGER, def INTEGER, format INTEGER, op_version INTEGER," "blendop_version INTEGER, multi_priority INTEGER, multi_name VARCHAR(256))", NULL, NULL, NULL) != SQLITE_OK) { fprintf(stderr, "[init] can't create new presets table\n"); fprintf(stderr, "[init] %s\n", sqlite3_errmsg(db->handle)); sqlite3_exec(db->handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); return version; } if (sqlite3_exec(db->handle, "INSERT INTO presets (name, description, operation, op_params, enabled, blendop_params, model, maker, lens," " iso_min, iso_max, exposure_min, exposure_max, aperture_min, aperture_max," " focal_length_min, focal_length_max, writeprotect, autoapply, filter, def, format," " op_version, blendop_version, multi_priority, multi_name)" " SELECT name, description, operation, op_params, enabled, blendop_params, model, maker, lens," " iso_min, iso_max, exposure_min, exposure_max, aperture_min, aperture_max," " focal_length_min, focal_length_max, writeprotect, autoapply, filter, def, isldr," " op_version, blendop_version, multi_priority, multi_name" " FROM tmp_presets", NULL, NULL, NULL) != SQLITE_OK) { fprintf(stderr, "[init] can't populate presets table from tmp_presets\n"); fprintf(stderr, "[init] %s\n", sqlite3_errmsg(db->handle)); sqlite3_exec(db->handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); return version; } if (sqlite3_exec(db->handle, "DROP TABLE tmp_presets", NULL, NULL, NULL) != SQLITE_OK) { fprintf(stderr, "[init] can't delete table tmp_presets\n"); fprintf(stderr, "[init] %s\n", sqlite3_errmsg(db->handle)); sqlite3_exec(db->handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); return version; } sqlite3_exec(db->handle, "COMMIT", NULL, NULL, NULL); new_version = 5; } else if(version == 5) { sqlite3_exec(db->handle, "BEGIN TRANSACTION", NULL, NULL, NULL); if(sqlite3_exec(db->handle, "CREATE INDEX images_filename_index ON images (filename)", NULL, NULL, NULL) != SQLITE_OK) { fprintf(stderr, "[init] can't create index on image filename\n"); fprintf(stderr, "[init] %s\n", sqlite3_errmsg(db->handle)); sqlite3_exec(db->handle, "ROLLBACK TRANSACTION", NULL, NULL, NULL); return version; } sqlite3_exec(db->handle, "COMMIT", NULL, NULL, NULL); new_version = 6; }// maybe in the future, see commented out code elsewhere // else if(version == XXX) // { // sqlite3_exec(db->handle, "ALTER TABLE film_rolls ADD COLUMN external_drive VARCHAR(1024)", NULL, NULL, NULL); // } else new_version = version; // should be the fallback so that calling code sees that we are in an infinite loop // write the new version to db DT_DEBUG_SQLITE3_PREPARE_V2(db->handle, "INSERT OR REPLACE INTO db_info (key, value) VALUES ('version', ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, new_version); sqlite3_step(stmt); sqlite3_finalize(stmt); return new_version; }
int dt_film_import(const char *dirname) { int rc; sqlite3_stmt *stmt; /* initialize a film object*/ dt_film_t *film = (dt_film_t *)malloc(sizeof(dt_film_t)); dt_film_init(film); film->id = -1; /* lookup if film exists and reuse id */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id from film_rolls where folder = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, dirname, strlen(dirname), SQLITE_STATIC); if(sqlite3_step(stmt) == SQLITE_ROW) film->id = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); /* if we didn't find a id, lets instansiate a new filmroll */ if(film->id <= 0) { char datetime[20]; dt_gettime(datetime); /* insert a new film roll into database */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into film_rolls (id, datetime_accessed, folder) values " "(null, ?1, ?2)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, datetime, strlen(datetime), SQLITE_STATIC); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, dirname, strlen(dirname), SQLITE_STATIC); rc = sqlite3_step(stmt); if(rc != SQLITE_DONE) fprintf(stderr, "[film_import] failed to insert film roll! %s\n", sqlite3_errmsg(dt_database_get(darktable.db))); sqlite3_finalize(stmt); /* requery for filmroll and fetch new id */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id from film_rolls where folder=?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, dirname, strlen(dirname), SQLITE_STATIC); if(sqlite3_step(stmt) == SQLITE_ROW) film->id = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); } /* bail out if we got troubles */ if(film->id <= 0) { // if the film is empty => remove it again. if(dt_film_is_empty(film->id)) { dt_film_remove(film->id); } dt_film_cleanup(film); free(film); return 0; } /* at last put import film job on queue */ dt_job_t j; film->last_loaded = 0; g_strlcpy(film->dirname, dirname, sizeof(film->dirname)); film->dir = g_dir_open(film->dirname, 0, NULL); dt_film_import1_init(&j, film); dt_control_add_job(darktable.control, &j); return film->id; }
void dt_styles_update (const char *name, const char *newname, const char *newdescription, GList *filter) { sqlite3_stmt *stmt; int id=0; gchar *desc = NULL; id = dt_styles_get_id_by_name(name); if(id == 0) return; desc = dt_styles_get_description (name); if ((g_strcmp0(name, newname)) || (g_strcmp0(desc, newdescription))) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "update styles set name=?1, description=?2 where rowid=?3", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, newname, strlen (newname), SQLITE_STATIC); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, newdescription, strlen (newdescription), SQLITE_STATIC); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, id); sqlite3_step(stmt); sqlite3_finalize(stmt); } if (filter) { GList *list=filter; char tmp[64]; char include[2048] = {0}; g_strlcat(include,"num not in (", 2048); do { if(list!=g_list_first(list)) g_strlcat(include, ",", 2048); sprintf(tmp, "%ld", (long int)list->data); g_strlcat(include, tmp, 2048); } while ((list=g_list_next(list))); g_strlcat(include,")", 2048); char query[4096]= {0}; sprintf(query,"delete from style_items where styleid=?1 and %s", include); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); } /* backup style to disk */ char stylesdir[1024]; dt_loc_get_user_config_dir(stylesdir, 1024); g_strlcat(stylesdir,"/styles",1024); g_mkdir_with_parents(stylesdir,00755); dt_styles_save_to_file(newname,stylesdir,TRUE); /* delete old accelerator and create a new one */ //TODO: sould better use dt_accel_rename_global() to keep the old accel_key untouched, but it seems to be buggy if (g_strcmp0(name, newname)) { char tmp_accel[1024]; snprintf(tmp_accel, 1024, "styles/Apply %s", name); dt_accel_deregister_global(tmp_accel); gchar* tmp_name = g_strdup(newname); // freed by _destro_style_shortcut_callback snprintf(tmp_accel, 1024, "styles/Apply %s", newname); dt_accel_register_global( tmp_accel, 0, 0); GClosure *closure; closure = g_cclosure_new( G_CALLBACK(_apply_style_shortcut_callback), tmp_name, _destroy_style_shortcut_callback); dt_accel_connect_global(tmp_accel, closure); } g_free(desc); }
void dt_styles_apply_to_image(const char *name,gboolean duplicate, int32_t imgid) { int id=0; sqlite3_stmt *stmt; if ((id=dt_styles_get_id_by_name(name)) != 0) { /* check if we should make a duplicate before applying style */ if (duplicate) imgid = dt_image_duplicate (imgid); /* if merge onto history stack, lets find history offest in destination image */ int32_t offs = 0; #if 1 { /* apply on top of history stack */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select count(num) from history where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); if (sqlite3_step (stmt) == SQLITE_ROW) offs = sqlite3_column_int (stmt, 0); } #else { /* replace history stack */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from history where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); sqlite3_step (stmt); } #endif sqlite3_finalize (stmt); /* copy history items from styles onto image */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into history (imgid,num,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name) select ?1, num+?2,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name from style_items where styleid=?3", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, offs); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, id); sqlite3_step (stmt); sqlite3_finalize (stmt); /* add tag */ guint tagid=0; gchar ntag[512]= {0}; g_snprintf(ntag,512,"darktable|style|%s",name); if (dt_tag_new(ntag,&tagid)) dt_tag_attach(tagid,imgid); /* if current image in develop reload history */ if (dt_dev_is_current_image(darktable.develop, imgid)) { dt_dev_reload_history_items (darktable.develop); dt_dev_modulegroups_set(darktable.develop, dt_dev_modulegroups_get(darktable.develop)); } /* update xmp file */ dt_image_synch_xmp(imgid); /* remove old obsolete thumbnails */ dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); /* redraw center view to update visible mipmaps */ dt_control_queue_redraw_center(); } }
void init(dt_view_t *self) { self->data = malloc(sizeof(dt_map_t)); memset(self->data,0,sizeof(dt_map_t)); dt_map_t *lib = (dt_map_t *)self->data; OsmGpsMapSource_t map_source = OSM_GPS_MAP_SOURCE_OPENSTREETMAP; const gchar *old_map_source = dt_conf_get_string("plugins/map/map_source"); if(old_map_source && old_map_source[0] != '\0') { // find the number of the stored map_source for(int i=0; i<=OSM_GPS_MAP_SOURCE_LAST; i++) { const gchar *new_map_source = osm_gps_map_source_get_friendly_name(i); if(!g_strcmp0(old_map_source, new_map_source)) { if(osm_gps_map_source_is_valid(i)) map_source = i; break; } } } else // open street map should be a nice default ... dt_conf_set_string("plugins/map/map_source", osm_gps_map_source_get_friendly_name(OSM_GPS_MAP_SOURCE_OPENSTREETMAP)); lib->map = g_object_new (OSM_TYPE_GPS_MAP, "map-source", map_source, "proxy-uri",g_getenv("http_proxy"), NULL); GtkWidget *parent = gtk_widget_get_parent(dt_ui_center(darktable.gui->ui)); gtk_box_pack_start(GTK_BOX(parent), GTK_WIDGET(lib->map) ,TRUE, TRUE, 0); lib->osd = g_object_new (OSM_TYPE_GPS_MAP_OSD, "show-scale",TRUE, "show-coordinates",TRUE, "show-dpad",TRUE, "show-zoom",TRUE, NULL); if(dt_conf_get_bool("plugins/map/show_map_osd")) { osm_gps_map_layer_add(OSM_GPS_MAP(lib->map), lib->osd); } /* build the query string */ int max_images_drawn = dt_conf_get_int("plugins/map/max_images_drawn"); if(max_images_drawn == 0) max_images_drawn = 100; char *geo_query = g_strdup_printf("select * from (select id from images where \ longitude >= ?1 and longitude <= ?2 and latitude <= ?3 and latitude >= ?4 \ and longitude not NULL and latitude not NULL order by abs(latitude - ?5), abs(longitude - ?6) \ limit 0, %d) order by id", max_images_drawn); /* prepare the main query statement */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), geo_query, -1, &lib->statements.main_query, NULL); g_free(geo_query); /* allow drag&drop of images from filmstrip */ gtk_drag_dest_set(GTK_WIDGET(lib->map), GTK_DEST_DEFAULT_ALL, target_list_internal, n_targets_internal, GDK_ACTION_COPY); g_signal_connect(GTK_WIDGET(lib->map), "drag-data-received", G_CALLBACK(drag_and_drop_received), self); g_signal_connect(GTK_WIDGET(lib->map), "changed", G_CALLBACK(_view_map_changed_callback), self); g_signal_connect(G_OBJECT(lib->map), "button-press-event", G_CALLBACK(_view_map_button_press_callback), self); g_signal_connect (G_OBJECT(lib->map), "motion-notify-event", G_CALLBACK(_view_map_motion_notify_callback), self); /* allow drag&drop of images from the map, too */ g_signal_connect(GTK_WIDGET(lib->map), "drag-data-get", G_CALLBACK(_view_map_dnd_get_callback), self); g_signal_connect(GTK_WIDGET(lib->map), "drag-failed", G_CALLBACK(_view_map_dnd_failed_callback), self); }
int32_t dt_control_indexer_job_run(dt_job_t *job) { // if no indexing was requested, bail out: if(!dt_conf_get_bool("run_similarity_indexer")) return 0; /* * First pass run thru ALL images and collect the ones who needs to update * \TODO in the future lets have a indexer table with ids filed with images * thats need some kind of reindexing.. all mark dirty functions adds image * to this table-- */ // temp memory for uncompressed images: uint8_t *scratchmem = dt_mipmap_cache_alloc_scratchmem(darktable.mipmap_cache); GList *images=NULL; sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select images.id,film_rolls.folder||'/'||images.filename,images.histogram,images.lightmap from images,film_rolls where film_rolls.id = images.film_id", -1, &stmt, NULL); while(sqlite3_step(stmt) == SQLITE_ROW) { _control_indexer_img_t *idximg=g_malloc(sizeof( _control_indexer_img_t)); memset(idximg,0,sizeof(_control_indexer_img_t)); idximg->id = sqlite3_column_int(stmt,0); /* first check if image file exists on disk */ const char *filename = (const char *)sqlite3_column_text(stmt, 1); if (filename && !g_file_test(filename, G_FILE_TEST_IS_REGULAR)) idximg->flags |= _INDEXER_IMAGE_FILE_REMOVED; /* check if histogram should be updated */ if (sqlite3_column_bytes(stmt, 2) != sizeof(dt_similarity_histogram_t)) idximg->flags |= _INDEXER_UPDATE_HISTOGRAM; /* check if lightmap should be updated */ if (sqlite3_column_bytes(stmt, 3) != sizeof(dt_similarity_lightmap_t)) idximg->flags |= _INDEXER_UPDATE_LIGHTMAP; /* if image is flagged add to collection */ if (idximg->flags != 0) images = g_list_append(images, idximg); else g_free(idximg); } sqlite3_finalize(stmt); /* * Second pass, run thru collected images thats * need reindexing... */ GList *imgitem = g_list_first(images); if(imgitem) { char message[512]= {0}; double fraction=0; int total = g_list_length(images); guint *jid = NULL; /* background job plate only if more then one image is reindexed */ if (total > 1) { snprintf(message, 512, ngettext ("re-indexing %d image", "re-indexing %d images", total), total ); jid = (guint *)dt_control_backgroundjobs_create(darktable.control, 0, message); } do { // bail out if we're shutting down: if(!dt_control_running()) break; // if indexer was switched off during runtime, respect that as soon as we can: if(!dt_conf_get_bool("run_similarity_indexer")) break; /* get the _control_indexer_img_t pointer */ _control_indexer_img_t *idximg = imgitem->data; /* * Check if image has been delete from disk */ if ((idximg->flags&_INDEXER_IMAGE_FILE_REMOVED)) { /* file does not exist on disk lets delete image reference from database */ //char query[512]={0}; // \TODO dont delete move to an temp table and let user to revalidate /*sprintf(query,"delete from history where imgid=%d",idximg->id); DT_DEBUG_SQLITE3_EXEC(darktable.db, query, NULL, NULL, NULL); sprintf(query,"delete from tagged_images where imgid=%d",idximg->id); DT_DEBUG_SQLITE3_EXEC(darktable.db, query, NULL, NULL, NULL); sprintf(query,"delete from images where id=%d",idximg->id); DT_DEBUG_SQLITE3_EXEC(darktable.db, query, NULL, NULL, NULL);*/ /* no need to additional work */ continue; } /* * Check if image histogram or lightmap should be updated. * those indexing that involves a image pipe should fall into this */ if ( (idximg->flags&_INDEXER_UPDATE_HISTOGRAM) || (idximg->flags&_INDEXER_UPDATE_LIGHTMAP) ) { /* get a mipmap of image to analyse */ dt_mipmap_buffer_t buf; dt_mipmap_cache_read_get(darktable.mipmap_cache, &buf, idximg->id, DT_MIPMAP_2, DT_MIPMAP_BLOCKING); // pointer owned by the cache or == scratchmem, no need to free this one: uint8_t *buf_decompressed = dt_mipmap_cache_decompress(&buf, scratchmem); if (!(buf.width * buf.height)) continue; /* * Generate similarity histogram data if requested */ if ( (idximg->flags&_INDEXER_UPDATE_HISTOGRAM) ) { dt_similarity_histogram_t histogram; float bucketscale = (float)DT_SIMILARITY_HISTOGRAM_BUCKETS/(float)0xff; for(int j=0; j<(4*buf.width*buf.height); j+=4) { /* swap rgb and scale to bucket index */ uint8_t rgb[3]; for(int k=0; k<3; k++) rgb[k] = (int)((buf_decompressed[j+2-k]/(float)0xff) * bucketscale); /* distribute rgb into buckets */ for(int k=0; k<3; k++) histogram.rgbl[rgb[k]][k]++; /* distribute lum into buckets */ uint8_t lum = MAX(MAX(rgb[0], rgb[1]), rgb[2]); histogram.rgbl[lum][3]++; } for(int k=0; k<DT_SIMILARITY_HISTOGRAM_BUCKETS; k++) for (int j=0; j<4; j++) histogram.rgbl[k][j] /= (buf.width*buf.height); /* store the histogram data */ dt_similarity_histogram_store(idximg->id, &histogram); } /* * Generate scaledowned similarity lightness map if requested */ if ( (idximg->flags&_INDEXER_UPDATE_LIGHTMAP) ) { dt_similarity_lightmap_t lightmap; memset(&lightmap,0,sizeof(dt_similarity_lightmap_t)); /* * create a pixbuf out of the image for downscaling */ /* first of setup a standard rgb buffer, swap bgr in same routine */ uint8_t *rgbbuf = g_malloc(buf.width*buf.height*3); for(int j=0; j<(buf.width*buf.height); j++) for(int k=0; k<3; k++) rgbbuf[3*j+k] = buf_decompressed[4*j+2-k]; /* then create pixbuf and scale down to lightmap size */ GdkPixbuf *source = gdk_pixbuf_new_from_data(rgbbuf,GDK_COLORSPACE_RGB,FALSE,8,buf.width,buf.height,(buf.width*3),NULL,NULL); GdkPixbuf *scaled = gdk_pixbuf_scale_simple(source,DT_SIMILARITY_LIGHTMAP_SIZE,DT_SIMILARITY_LIGHTMAP_SIZE,GDK_INTERP_HYPER); /* copy scaled data into lightmap */ uint8_t min=0xff,max=0; uint8_t *spixels = gdk_pixbuf_get_pixels(scaled); for(int j=0; j<(DT_SIMILARITY_LIGHTMAP_SIZE*DT_SIMILARITY_LIGHTMAP_SIZE); j++) { /* copy rgb */ for(int k=0; k<3; k++) lightmap.pixels[4*j+k] = spixels[3*j+k]; /* average intensity into 4th channel */ lightmap.pixels[4*j+3] = (lightmap.pixels[4*j+0]+ lightmap.pixels[4*j+1]+ lightmap.pixels[4*j+2])/3.0; min = MIN(min, lightmap.pixels[4*j+3]); max = MAX(max, lightmap.pixels[4*j+3]); } /* contrast stretch each channel in lightmap * TODO: do we want this... */ float scale=0; int range = max-min; if(range==0) scale = 1.0; else scale = 0xff/range; for(int j=0; j<(DT_SIMILARITY_LIGHTMAP_SIZE*DT_SIMILARITY_LIGHTMAP_SIZE); j++) { for(int k=0; k<4; k++) lightmap.pixels[4*j+k] = (lightmap.pixels[4*j+k]-min)*scale; } /* free some resources */ g_object_unref(scaled); g_object_unref(source); g_free(rgbbuf); /* store the lightmap */ dt_similarity_lightmap_store(idximg->id, &lightmap); } /* no use for buffer anymore release the mipmap */ dt_mipmap_cache_read_release(darktable.mipmap_cache, &buf); } /* update background progress */ if (jid) { fraction+=1.0/total; dt_control_backgroundjobs_progress(darktable.control, jid, fraction); } } while ((imgitem=g_list_next(imgitem)) && dt_control_job_get_state(job) != DT_JOB_STATE_CANCELLED); /* cleanup */ if (jid) dt_control_backgroundjobs_destroy(darktable.control, jid); } free(scratchmem); /* * Indexing opertions finished, lets reschedule the indexer * unless control is shutting down... */ if(dt_control_running()) dt_control_start_indexer(); return 0; }
static void edit_preset (const char *name_in, dt_lib_module_info_t *minfo) { gchar *name = NULL; if(name_in == NULL) { name = get_active_preset_name(minfo); if(name == NULL) return; } else name = g_strdup(name_in); GtkWidget *dialog; /* Create the widgets */ char title[1024]; GtkWidget *window = dt_ui_main_window(darktable.gui->ui); snprintf(title, 1024, _("edit `%s'"), name); dialog = gtk_dialog_new_with_buttons (title, GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL); GtkContainer *content_area = GTK_CONTAINER(gtk_dialog_get_content_area (GTK_DIALOG (dialog))); GtkWidget *alignment = gtk_alignment_new(0.5, 0.5, 1.0, 1.0); gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 5, 5, 5, 5); gtk_container_add (content_area, alignment); GtkBox *box = GTK_BOX(gtk_vbox_new(FALSE, 5)); gtk_container_add (GTK_CONTAINER(alignment), GTK_WIDGET(box)); dt_lib_presets_edit_dialog_t *g = (dt_lib_presets_edit_dialog_t *)g_malloc0(sizeof(dt_lib_presets_edit_dialog_t)); g->old_id = -1; g_strlcpy(g->plugin_name, minfo->plugin_name, 128); g->version = minfo->version; g->params_size = minfo->params_size; g->params = minfo->params; g->name = GTK_ENTRY(gtk_entry_new()); g->module = minfo->module; g->original_name = name; gtk_entry_set_text(g->name, name); gtk_box_pack_start(box, GTK_WIDGET(g->name), FALSE, FALSE, 0); g_object_set(G_OBJECT(g->name), "tooltip-text", _("name of the preset"), (char *)NULL); g->description = GTK_ENTRY(gtk_entry_new()); gtk_box_pack_start(box, GTK_WIDGET(g->description), FALSE, FALSE, 0); g_object_set(G_OBJECT(g->description), "tooltip-text", _("description or further information"), (char *)NULL); sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select rowid, description from presets where name = ?1 and operation = ?2 and op_version = ?3", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, name, strlen(name), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, minfo->plugin_name, strlen(minfo->plugin_name), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, minfo->version); if(sqlite3_step(stmt) == SQLITE_ROW) { g->old_id = sqlite3_column_int(stmt, 0); gtk_entry_set_text(g->description, (const char *)sqlite3_column_text(stmt, 1)); } sqlite3_finalize(stmt); g_signal_connect (dialog, "response", G_CALLBACK (edit_preset_response), g); gtk_widget_show_all (dialog); }
static void dt_lib_presets_popup_menu_show(dt_lib_module_info_t *minfo) { GtkMenu *menu = darktable.gui->presets_popup_menu; if(menu) gtk_widget_destroy(GTK_WIDGET(menu)); darktable.gui->presets_popup_menu = GTK_MENU(gtk_menu_new()); menu = darktable.gui->presets_popup_menu; GtkWidget *mi; int active_preset = -1, cnt = 0, writeprotect = 0; sqlite3_stmt *stmt; // order: get shipped defaults first DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select name, op_params, writeprotect, description from presets where operation=?1 and op_version=?2 order by writeprotect desc, rowid", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, minfo->plugin_name, strlen(minfo->plugin_name), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, minfo->version); // collect all presets for op from db int found = 0; while(sqlite3_step(stmt) == SQLITE_ROW) { void *op_params = (void *)sqlite3_column_blob(stmt, 1); int32_t op_params_size = sqlite3_column_bytes(stmt, 1); const char *name = (char *)sqlite3_column_text(stmt, 0); if (darktable.gui->last_preset && strcmp(darktable.gui->last_preset, name)==0) found = 1; // selected in bold: // printf("comparing %d bytes to %d\n", op_params_size, minfo->params_size); // for(int k=0;k<op_params_size && !memcmp(minfo->params, op_params, k);k++) printf("compare [%c %c] %d: %d\n", // ((const char*)(minfo->params))[k], // ((const char*)(op_params))[k], // k, memcmp(minfo->params, op_params, k)); if(op_params_size == minfo->params_size && !memcmp(minfo->params, op_params, op_params_size)) { active_preset = cnt; writeprotect = sqlite3_column_int(stmt, 2); char *markup; mi = gtk_menu_item_new_with_label(""); markup = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>", name); gtk_label_set_markup (GTK_LABEL (gtk_bin_get_child(GTK_BIN(mi))), markup); g_free (markup); } else { mi = gtk_menu_item_new_with_label((const char *)name); } g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(pick_callback), minfo); g_object_set(G_OBJECT(mi), "tooltip-text", sqlite3_column_text(stmt, 3), (char *)NULL); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); cnt ++; } sqlite3_finalize(stmt); if(cnt > 0) gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new()); // FIXME: this doesn't seem to work. if(active_preset >= 0) { if(!writeprotect) { mi = gtk_menu_item_new_with_label(_("edit this preset..")); g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_edit_preset), minfo); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); mi = gtk_menu_item_new_with_label(_("delete this preset")); g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_delete_preset), minfo); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); } } else { mi = gtk_menu_item_new_with_label(_("store new preset..")); g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_new_preset), minfo); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); if (darktable.gui->last_preset && found) { char label[60]; strcpy (label, _("update preset")); strcat (label, " <span weight=\"bold\">%s</span>"); char *markup = g_markup_printf_escaped (label, darktable.gui->last_preset); mi = gtk_menu_item_new_with_label(""); gtk_label_set_markup (GTK_LABEL (gtk_bin_get_child(GTK_BIN(mi))), markup); g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_update_preset), minfo); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); g_free (markup); } } }
void dt_image_cache_allocate(void *data, dt_cache_entry_t *entry) { entry->cost = sizeof(dt_image_t); dt_image_t *img = (dt_image_t *)g_malloc(sizeof(dt_image_t)); dt_image_init(img); entry->data = img; // load stuff from db and store in cache: char *str; sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2( dt_database_get(darktable.db), "SELECT id, group_id, film_id, width, height, filename, maker, model, lens, exposure, " "aperture, iso, focal_length, datetime_taken, flags, crop, orientation, focus_distance, " "raw_parameters, longitude, latitude, color_matrix, colorspace, version, raw_black, raw_maximum FROM " "images WHERE id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, entry->key); if(sqlite3_step(stmt) == SQLITE_ROW) { img->id = sqlite3_column_int(stmt, 0); img->group_id = sqlite3_column_int(stmt, 1); img->film_id = sqlite3_column_int(stmt, 2); img->width = sqlite3_column_int(stmt, 3); img->height = sqlite3_column_int(stmt, 4); img->crop_x = img->crop_y = img->crop_width = img->crop_height = 0; img->filename[0] = img->exif_maker[0] = img->exif_model[0] = img->exif_lens[0] = img->exif_datetime_taken[0] = '\0'; str = (char *)sqlite3_column_text(stmt, 5); if(str) g_strlcpy(img->filename, str, sizeof(img->filename)); str = (char *)sqlite3_column_text(stmt, 6); if(str) g_strlcpy(img->exif_maker, str, sizeof(img->exif_maker)); str = (char *)sqlite3_column_text(stmt, 7); if(str) g_strlcpy(img->exif_model, str, sizeof(img->exif_model)); str = (char *)sqlite3_column_text(stmt, 8); if(str) g_strlcpy(img->exif_lens, str, sizeof(img->exif_lens)); img->exif_exposure = sqlite3_column_double(stmt, 9); img->exif_aperture = sqlite3_column_double(stmt, 10); img->exif_iso = sqlite3_column_double(stmt, 11); img->exif_focal_length = sqlite3_column_double(stmt, 12); str = (char *)sqlite3_column_text(stmt, 13); if(str) g_strlcpy(img->exif_datetime_taken, str, sizeof(img->exif_datetime_taken)); img->flags = sqlite3_column_int(stmt, 14); img->exif_crop = sqlite3_column_double(stmt, 15); img->orientation = sqlite3_column_int(stmt, 16); img->exif_focus_distance = sqlite3_column_double(stmt, 17); if(img->exif_focus_distance >= 0 && img->orientation >= 0) img->exif_inited = 1; uint32_t tmp = sqlite3_column_int(stmt, 18); memcpy(&img->legacy_flip, &tmp, sizeof(dt_image_raw_parameters_t)); if(sqlite3_column_type(stmt, 19) == SQLITE_FLOAT) img->longitude = sqlite3_column_double(stmt, 19); else img->longitude = NAN; if(sqlite3_column_type(stmt, 20) == SQLITE_FLOAT) img->latitude = sqlite3_column_double(stmt, 20); else img->latitude = NAN; const void *color_matrix = sqlite3_column_blob(stmt, 21); if(color_matrix) memcpy(img->d65_color_matrix, color_matrix, sizeof(img->d65_color_matrix)); else img->d65_color_matrix[0] = NAN; g_free(img->profile); img->profile = NULL; img->profile_size = 0; img->colorspace = sqlite3_column_int(stmt, 22); img->version = sqlite3_column_int(stmt, 23); img->raw_black_level = sqlite3_column_int(stmt, 24); for(uint8_t i = 0; i < 4; i++) img->raw_black_level_separate[i] = 0; img->raw_white_point = sqlite3_column_int(stmt, 25); // buffer size? if(img->flags & DT_IMAGE_LDR) img->bpp = 4 * sizeof(float); else if(img->flags & DT_IMAGE_HDR) { if(img->flags & DT_IMAGE_RAW) img->bpp = sizeof(float); else img->bpp = 4 * sizeof(float); } else // raw img->bpp = sizeof(uint16_t); } else { img->id = -1; fprintf(stderr, "[image_cache_allocate] failed to open image %d from database: %s\n", entry->key, sqlite3_errmsg(dt_database_get(darktable.db))); } sqlite3_finalize(stmt); img->cache_entry = entry; // init backref // could downgrade lock write->read on entry->lock if we were using concurrencykit.. }
static void edit_preset_response(GtkDialog *dialog, gint response_id, dt_lib_presets_edit_dialog_t *g) { gint dlg_ret; gint is_new = 0; if(response_id == GTK_RESPONSE_ACCEPT) { sqlite3_stmt *stmt; // now delete preset, so we can re-insert the new values: DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from presets where name=?1 and operation=?2 and op_version=?3", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, g->original_name, -1, SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, g->plugin_name, -1, SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, g->version); sqlite3_step(stmt); sqlite3_finalize(stmt); if ( ((g->old_id >= 0) && (strcmp(g->original_name, gtk_entry_get_text(g->name)) != 0)) || (g->old_id < 0) ) { // editing existing preset with different name or store new preset -> check for a preset with the same name: DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select name from presets where name = ?1 and operation=?2 and op_version=?3", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, gtk_entry_get_text(g->name), strlen(gtk_entry_get_text(g->name)), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, g->plugin_name, strlen(g->plugin_name), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, g->version); if(sqlite3_step(stmt) == SQLITE_ROW) { sqlite3_finalize(stmt); GtkWidget *window = dt_ui_main_window(darktable.gui->ui); GtkWidget *dlg_overwrite = gtk_message_dialog_new (GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("preset `%s' already exists.\ndo you want to overwrite?"), gtk_entry_get_text(g->name) ); gtk_window_set_title(GTK_WINDOW (dlg_overwrite), _("overwrite preset?")); dlg_ret = gtk_dialog_run (GTK_DIALOG (dlg_overwrite)); gtk_widget_destroy (dlg_overwrite); // if result is BUTTON_NO exit without destroy dialog, to permit other name if (dlg_ret == GTK_RESPONSE_NO) return; } else { is_new = 1; sqlite3_finalize(stmt); } } if (is_new == 0) { // delete preset, so we can re-insert the new values: DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from presets where name=?1 and operation=?2 and op_version=?3", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, gtk_entry_get_text(g->name), strlen(gtk_entry_get_text(g->name)), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, g->plugin_name, strlen(g->plugin_name), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, g->version); sqlite3_step(stmt); sqlite3_finalize(stmt); } // commit all the user input fields char path[1024]; snprintf(path,1024,"preset/%s",g->original_name); dt_accel_rename_preset_lib(g->module,path,gtk_entry_get_text(g->name)); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into presets (name, description, operation, op_version, op_params, blendop_params, blendop_version, enabled, model, maker, lens, " "iso_min, iso_max, exposure_min, exposure_max, aperture_min, aperture_max, focal_length_min, focal_length_max, writeprotect, " "autoapply, filter, def, isldr) values (?1, ?2, ?3, ?4, ?5, null, 0, 1, '%', '%', '%', 0, 51200, 0, 100000000, 0, 100000000, 0, 1000, 0, 0, 0, 0, 0)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, gtk_entry_get_text(g->name), strlen(gtk_entry_get_text(g->name)), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, gtk_entry_get_text(g->description), strlen(gtk_entry_get_text(g->description)), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 3, g->plugin_name, strlen(g->plugin_name), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_INT(stmt, 4, g->version); DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 5, g->params, g->params_size, SQLITE_TRANSIENT); sqlite3_step(stmt); sqlite3_finalize(stmt); dt_gui_store_last_preset (gtk_entry_get_text(g->name)); } gtk_widget_destroy(GTK_WIDGET(dialog)); g_free(g->original_name); free(g); }
int32_t dt_image_copy(const int32_t imgid, const int32_t filmid) { int32_t newid = -1; sqlite3_stmt *stmt; gchar srcpath[DT_MAX_PATH_LEN] = {0}; gchar *newdir = NULL; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select folder from film_rolls where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, filmid); if(sqlite3_step(stmt) == SQLITE_ROW) newdir = g_strdup((gchar *) sqlite3_column_text(stmt, 0)); sqlite3_finalize(stmt); if(newdir) { dt_image_full_path(imgid, srcpath, DT_MAX_PATH_LEN); gchar *imgbname = g_path_get_basename(srcpath); gchar *destpath = g_build_filename(newdir, imgbname, NULL); GFile *src = g_file_new_for_path(srcpath); GFile *dest = g_file_new_for_path(destpath); g_free(imgbname); imgbname = NULL; g_free(newdir); newdir = NULL; g_free(destpath); destpath = NULL; // copy image to new folder // if image file already exists, continue GError *gerror = NULL; g_file_copy(src, dest, G_FILE_COPY_NONE, NULL, NULL, NULL, &gerror); if((gerror == NULL) || (gerror != NULL && gerror->code == G_IO_ERROR_EXISTS)) { // update database DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into images " "(id, group_id, film_id, width, height, filename, maker, model, lens, exposure, " "aperture, iso, focal_length, focus_distance, datetime_taken, flags, " "output_width, output_height, crop, raw_parameters, raw_denoise_threshold, " "raw_auto_bright_threshold, raw_black, raw_maximum, " "caption, description, license, sha1sum, orientation, histogram, lightmap, " "longitude, latitude, color_matrix, colorspace) " "select null, group_id, ?1 as film_id, width, height, filename, maker, model, lens, " "exposure, aperture, iso, focal_length, focus_distance, datetime_taken, " "flags, width, height, crop, raw_parameters, raw_denoise_threshold, " "raw_auto_bright_threshold, raw_black, raw_maximum, " "caption, description, license, sha1sum, orientation, histogram, lightmap, " "longitude, latitude, color_matrix, colorspace " "from images where id = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, filmid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select a.id from images as a join images as b where " "a.film_id = ?1 and a.filename = b.filename and " "b.id = ?2 order by a.id desc", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, filmid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); if(sqlite3_step(stmt) == SQLITE_ROW) newid = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); if(newid != -1) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into color_labels (imgid, color) select ?1, color from " "color_labels where imgid = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into meta_data (id, key, value) select ?1, key, value " "from meta_data where id = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into tagged_images (imgid, tagid) select ?1, tagid from " "tagged_images where imgid = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "update tagxtag set count = count + 1 where " "(id1 in (select tagid from tagged_images where imgid = ?1)) or " "(id2 in (select tagid from tagged_images where imgid = ?1))", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newid); sqlite3_step(stmt); sqlite3_finalize(stmt); // write xmp file dt_image_write_sidecar_file(newid); } } else { fprintf(stderr, "Failed to copy image %s: %s\n", srcpath, gerror->message); } g_object_unref(dest); g_object_unref(src); g_clear_error(&gerror); } return newid; }
int32_t dt_image_move(const int32_t imgid, const int32_t filmid) { //TODO: several places where string truncation could occur unnoticed int32_t result = -1; gchar oldimg[DT_MAX_PATH_LEN] = {0}; gchar newimg[DT_MAX_PATH_LEN] = {0}; dt_image_full_path(imgid, oldimg, DT_MAX_PATH_LEN); gchar *newdir = NULL; sqlite3_stmt *film_stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select folder from film_rolls where id = ?1", -1, &film_stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(film_stmt, 1, filmid); if(sqlite3_step(film_stmt) == SQLITE_ROW) newdir = g_strdup((gchar *) sqlite3_column_text(film_stmt, 0)); sqlite3_finalize(film_stmt); if(newdir) { gchar *imgbname = g_path_get_basename(oldimg); g_snprintf(newimg, DT_MAX_PATH_LEN, "%s%c%s", newdir, G_DIR_SEPARATOR, imgbname); g_free(imgbname); g_free(newdir); // statement for getting ids of the image to be moved and it's duplicates sqlite3_stmt *duplicates_stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id from images where filename in (select filename from images " "where id = ?1) and film_id in (select film_id from images where id = ?1)", -1, &duplicates_stmt, NULL); // move image // TODO: Use gio's' g_file_move instead of g_rename? if (!g_file_test(newimg, G_FILE_TEST_EXISTS) && (g_rename(oldimg, newimg) == 0)) { // first move xmp files of image and duplicates GList *dup_list = NULL; DT_DEBUG_SQLITE3_BIND_INT(duplicates_stmt, 1, imgid); while (sqlite3_step(duplicates_stmt) == SQLITE_ROW) { int32_t id = sqlite3_column_int(duplicates_stmt, 0); dup_list = g_list_append(dup_list, GINT_TO_POINTER(id)); gchar oldxmp[512], newxmp[512]; g_strlcpy(oldxmp, oldimg, 512); g_strlcpy(newxmp, newimg, 512); dt_image_path_append_version(id, oldxmp, 512); dt_image_path_append_version(id, newxmp, 512); g_strlcat(oldxmp, ".xmp", 512); g_strlcat(newxmp, ".xmp", 512); if (g_file_test(oldxmp, G_FILE_TEST_EXISTS)) (void)g_rename(oldxmp, newxmp); } sqlite3_reset(duplicates_stmt); sqlite3_clear_bindings(duplicates_stmt); // then update database and cache // if update was performed in above loop, dt_image_path_append_version() // would return wrong version! while (dup_list) { long int id = GPOINTER_TO_INT(dup_list->data); const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, id); dt_image_t *img = dt_image_cache_write_get(darktable.image_cache, cimg); img->film_id = filmid; // write through to db, but not to xmp dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); dt_image_cache_read_release(darktable.image_cache, img); dup_list = g_list_delete_link(dup_list, dup_list); } g_list_free(dup_list); result = 0; } } return result; }
uint32_t dt_image_import(const int32_t film_id, const char *filename, gboolean override_ignore_jpegs) { if(!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) return 0; const char *cc = filename + strlen(filename); for(; *cc!='.'&&cc>filename; cc--); if(!strcmp(cc, ".dt")) return 0; if(!strcmp(cc, ".dttags")) return 0; if(!strcmp(cc, ".xmp")) return 0; char *ext = g_ascii_strdown(cc+1, -1); if(override_ignore_jpegs == FALSE && (!strcmp(ext, "jpg") || !strcmp(ext, "jpeg")) && dt_conf_get_bool("ui_last/import_ignore_jpegs")) return 0; int supported = 0; char **extensions = g_strsplit(dt_supported_extensions, ",", 100); for(char **i=extensions; *i!=NULL; i++) if(!strcmp(ext, *i)) { supported = 1; break; } g_strfreev(extensions); if(!supported) { g_free(ext); return 0; } int rc; uint32_t id = 0; // select from images; if found => return gchar *imgfname; imgfname = g_path_get_basename((const gchar*)filename); sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id from images where film_id = ?1 and filename = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, film_id); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, imgfname, strlen(imgfname), SQLITE_STATIC); if(sqlite3_step(stmt) == SQLITE_ROW) { id = sqlite3_column_int(stmt, 0); g_free(imgfname); sqlite3_finalize(stmt); g_free(ext); const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, id); dt_image_t *img = dt_image_cache_write_get(darktable.image_cache, cimg); img->flags &= ~DT_IMAGE_REMOVE; dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); dt_image_cache_read_release(darktable.image_cache, img); return id; } sqlite3_finalize(stmt); // also need to set the no-legacy bit, to make sure we get the right presets (new ones) uint32_t flags = dt_conf_get_int("ui_last/import_initial_rating"); if(flags > 5) { flags = 1; dt_conf_set_int("ui_last/import_initial_rating", 1); } flags |= DT_IMAGE_NO_LEGACY_PRESETS; // insert dummy image entry in database DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into images (id, film_id, filename, caption, description, " "license, sha1sum, flags) values (null, ?1, ?2, '', '', '', '', ?3)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, film_id); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, imgfname, strlen(imgfname), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, flags); rc = sqlite3_step(stmt); if (rc != SQLITE_DONE) fprintf(stderr, "sqlite3 error %d\n", rc); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id from images where film_id = ?1 and filename = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, film_id); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, imgfname, strlen(imgfname), SQLITE_STATIC); if(sqlite3_step(stmt) == SQLITE_ROW) id = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); // Try to find out if this should be grouped already. gchar *basename = g_strdup(imgfname); gchar *cc2 = basename + strlen(basename); for(; *cc2!='.'&&cc2>basename; cc2--); *cc2='\0'; gchar *sql_pattern = g_strconcat(basename, ".%", NULL); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select group_id from images where film_id = ?1 and filename like ?2 and id != ?3", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, film_id); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, sql_pattern, -1, SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, id); int group_id; if(sqlite3_step(stmt) == SQLITE_ROW) group_id = sqlite3_column_int(stmt, 0); else group_id = id; sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "update images set group_id = ?1 where id = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, group_id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, id); sqlite3_step(stmt); sqlite3_finalize(stmt); // printf("[image_import] importing `%s' to img id %d\n", imgfname, id); // lock as shortly as possible: const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, id); dt_image_t *img = dt_image_cache_write_get(darktable.image_cache, cimg); img->group_id = group_id; // read dttags and exif for database queries! (void) dt_exif_read(img, filename); char dtfilename[DT_MAX_PATH_LEN]; g_strlcpy(dtfilename, filename, DT_MAX_PATH_LEN); dt_image_path_append_version(id, dtfilename, DT_MAX_PATH_LEN); char *c = dtfilename + strlen(dtfilename); sprintf(c, ".xmp"); (void)dt_exif_xmp_read(img, dtfilename, 0); // write through to db, but not to xmp. dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); dt_image_cache_read_release(darktable.image_cache, img); // add a tag with the file extension guint tagid = 0; char tagname[512]; snprintf(tagname, 512, "darktable|format|%s", ext); g_free(ext); dt_tag_new(tagname, &tagid); dt_tag_attach(tagid,id); // Search for sidecar files and import them if found. glob_t *globbuf = g_malloc(sizeof(glob_t)); // Add version wildcard gchar *fname = g_strdup(filename); gchar pattern[DT_MAX_PATH_LEN]; g_snprintf(pattern, DT_MAX_PATH_LEN, "%s", filename); char *c1 = pattern + strlen(pattern); while(*c1 != '.' && c1 > pattern) c1--; snprintf(c1, pattern + DT_MAX_PATH_LEN - c1, "_*"); char *c2 = fname + strlen(fname); while(*c2 != '.' && c2 > fname) c2--; snprintf(c1+2, pattern + DT_MAX_PATH_LEN - c1 - 2, "%s.xmp", c2); if (!glob(pattern, 0, NULL, globbuf)) { for (int i=0; i < globbuf->gl_pathc; i++) { int newid = -1; newid = dt_image_duplicate(id); const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, newid); dt_image_t *img = dt_image_cache_write_get(darktable.image_cache, cimg); (void)dt_exif_xmp_read(img, globbuf->gl_pathv[i], 0); dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); dt_image_cache_read_release(darktable.image_cache, img); } globfree(globbuf); } g_free(imgfname); g_free(fname); g_free(basename); g_free(sql_pattern); g_free(globbuf); dt_control_signal_raise(darktable.signals,DT_SIGNAL_IMAGE_IMPORT,id); return id; }
void dt_collection_update_query(const dt_collection_t *collection) { char query[1024], confname[200]; gchar *complete_query = NULL; const int _n_r = dt_conf_get_int("plugins/lighttable/collect/num_rules"); const int num_rules = CLAMP(_n_r, 1, 10); char *conj[] = {"and", "or", "and not"}; complete_query = dt_util_dstrcat(complete_query, "("); for(int i=0; i<num_rules; i++) { snprintf(confname, 200, "plugins/lighttable/collect/item%1d", i); const int property = dt_conf_get_int(confname); snprintf(confname, 200, "plugins/lighttable/collect/string%1d", i); gchar *text = dt_conf_get_string(confname); if(!text) break; snprintf(confname, 200, "plugins/lighttable/collect/mode%1d", i); const int mode = dt_conf_get_int(confname); gchar *escaped_text = dt_util_str_replace(text, "'", "''"); get_query_string(property, escaped_text, query); if(i > 0) complete_query = dt_util_dstrcat(complete_query, " %s %s", conj[mode], query); else complete_query = dt_util_dstrcat(complete_query, "%s", query); g_free(escaped_text); g_free(text); } complete_query = dt_util_dstrcat(complete_query, ")"); // printf("complete query: `%s'\n", complete_query); /* set the extended where and the use of it in the query */ dt_collection_set_extended_where (collection, complete_query); dt_collection_set_query_flags (collection, (dt_collection_get_query_flags (collection) | COLLECTION_QUERY_USE_WHERE_EXT)); /* remove film id from default filter */ dt_collection_set_filter_flags (collection, (dt_collection_get_filter_flags (collection) & ~COLLECTION_FILTER_FILM_ID)); /* update query and at last the visual */ dt_collection_update (collection); /* free string */ g_free(complete_query); // remove from selected images where not in this query. sqlite3_stmt *stmt = NULL; const gchar *cquery = dt_collection_get_query(collection); complete_query = NULL; if(cquery && cquery[0] != '\0') { complete_query = dt_util_dstrcat(complete_query, "delete from selected_images where imgid not in (%s)", cquery); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), complete_query, -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, 0); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, -1); sqlite3_step(stmt); sqlite3_finalize(stmt); /* free allocated strings */ g_free(complete_query); } /* raise signal of collection change, only if this is an original */ if (!collection->clone) dt_control_signal_raise(darktable.signals, DT_SIGNAL_COLLECTION_CHANGED); }
// FIXME: we can't rely on darktable to avoid file overwriting -- it doesn't know the filename (extension). int write_image(dt_imageio_module_data_t *ppm, const char *filename, const void *in, void *exif, int exif_len, int imgid, int num, int total) { int status = 1; char *sourcefile = NULL; char *targetfile = NULL; char *xmpfile = NULL; char *content = NULL; FILE *fin = NULL; FILE *fout = NULL; sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2( dt_database_get(darktable.db), "select folder, filename from images, film_rolls where images.id = ?1 and film_id = film_rolls.id;", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); if(sqlite3_step(stmt) != SQLITE_ROW) goto END; const char *sfolder = (char *)sqlite3_column_text(stmt, 0); const char *sfilename = (char *)sqlite3_column_text(stmt, 1); sourcefile = g_build_filename(sfolder, sfilename, NULL); char *extension = g_strrstr(sourcefile, "."); if(extension == NULL) goto END; targetfile = g_strconcat(filename, ++extension, NULL); if(!strcmp(sourcefile, targetfile)) goto END; fin = fopen(sourcefile, "rb"); fout = fopen(targetfile, "wb"); if(fin == NULL || fout == NULL) goto END; fseek(fin, 0, SEEK_END); size_t end = ftell(fin); rewind(fin); content = (char *)g_malloc_n(end, sizeof(char)); if(content == NULL) goto END; if(fread(content, sizeof(char), end, fin) != end) goto END; if(fwrite(content, sizeof(char), end, fout) != end) goto END; // we got a copy of the file, now write the xmp data xmpfile = g_strconcat(targetfile, ".xmp", NULL); if(dt_exif_xmp_write(imgid, xmpfile) != 0) { // something went wrong, unlink the copied image. g_unlink(targetfile); goto END; } status = 0; END: sqlite3_finalize(stmt); g_free(sourcefile); g_free(targetfile); g_free(xmpfile); g_free(content); if(fin) fclose(fin); if(fout) fclose(fout); return status; }
int32_t dt_control_remove_images_job_run(dt_job_t *job) { long int imgid = -1; dt_control_image_enumerator_t *t1 = (dt_control_image_enumerator_t *)job->param; GList *t = t1->index; int total = g_list_length(t); char message[512]= {0}; double fraction=0; snprintf(message, 512, ngettext ("removing %d image", "removing %d images", total), total ); const guint *jid = dt_control_backgroundjobs_create(darktable.control, 0, message); sqlite3_stmt *stmt = NULL; // check that we can safely remove the image char query[1024]; gboolean remove_ok = TRUE; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM images WHERE id IN (SELECT imgid FROM selected_images) AND flags&?1=?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, DT_IMAGE_LOCAL_COPY); while(sqlite3_step(stmt) == SQLITE_ROW) { int imgid = sqlite3_column_int(stmt, 0); if (!dt_image_safe_remove(imgid)) { remove_ok = FALSE; break; } } sqlite3_finalize(stmt); if (!remove_ok) { dt_control_log(_("cannot remove local copy when the original file is not accessible.")); dt_control_backgroundjobs_destroy(darktable.control, jid); return 0; } // update remove status sprintf(query, "update images set flags = (flags | %d) where id in (select imgid from selected_images)",DT_IMAGE_REMOVE); DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), query, NULL, NULL, NULL); dt_collection_update(darktable.collection); // We need a list of files to regenerate .xmp files if there are duplicates GList *list = NULL; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select distinct folder || '/' || filename from images, film_rolls where images.film_id = film_rolls.id and images.id in (select imgid from selected_images)", -1, &stmt, NULL); while(sqlite3_step(stmt) == SQLITE_ROW) { list = g_list_append(list, g_strdup((const gchar *)sqlite3_column_text(stmt, 0))); } sqlite3_finalize(stmt); while(t) { imgid = (long int)t->data; dt_image_remove(imgid); t = g_list_delete_link(t, t); fraction=1.0/total; dt_control_backgroundjobs_progress(darktable.control, jid, fraction); } char *imgname; while(list) { imgname = (char *)list->data; dt_image_synch_all_xmp(imgname); list = g_list_delete_link(list, list); } dt_control_backgroundjobs_destroy(darktable.control, jid); dt_film_remove_empty(); dt_control_queue_redraw_center(); return 0; }
void dt_collection_get_makermodel(const gchar *filter, GList **sanitized, GList **exif) { sqlite3_stmt *stmt; gchar *needle = NULL; GHashTable *names = NULL; if (sanitized) names = g_hash_table_new(g_str_hash, g_str_equal); if (filter && filter[0] != '\0') needle = g_utf8_strdown(filter, -1); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select maker, model from images group by maker, model", -1, &stmt, NULL); while(sqlite3_step(stmt) == SQLITE_ROW) { char *exif_maker = (char *)sqlite3_column_text(stmt, 0); char *exif_model = (char *)sqlite3_column_text(stmt, 1); char maker[64]; char model[64]; char alias[64]; maker[0] = model[0] = alias[0] = '\0'; dt_rawspeed_lookup_makermodel(exif_maker, exif_model, maker, sizeof(maker), model, sizeof(model), alias, sizeof(alias)); // Create the makermodel by concatenation char makermodel[128]; g_strlcpy(makermodel, maker, sizeof(makermodel)); int maker_len = strlen(maker); makermodel[maker_len] = ' '; g_strlcpy(makermodel+maker_len+1, model, sizeof(makermodel)-maker_len-1); gchar *haystack = g_utf8_strdown(makermodel, -1); if (!needle || g_strrstr(haystack, needle) != NULL) { if (exif) { // Append a two element list with maker and model GList *inner_list = NULL; inner_list = g_list_append(inner_list, g_strdup(exif_maker)); inner_list = g_list_append(inner_list, g_strdup(exif_model)); *exif = g_list_append(*exif, inner_list); } if (sanitized) { gchar *key = g_strdup(makermodel); g_hash_table_add(names, key); } } g_free(haystack); } sqlite3_finalize(stmt); if(needle) g_free(needle); if(sanitized) { *sanitized = g_list_sort(g_hash_table_get_keys(names), (GCompareFunc) strcmp); g_hash_table_destroy(names); } }
int32_t dt_control_delete_images_job_run(dt_job_t *job) { long int imgid = -1; dt_control_image_enumerator_t *t1 = (dt_control_image_enumerator_t *)job->param; GList *t = t1->index; int total = g_list_length(t); char message[512]= {0}; double fraction=0; snprintf(message, 512, ngettext ("deleting %d image", "deleting %d images", total), total ); const guint *jid = dt_control_backgroundjobs_create(darktable.control, 0, message); sqlite3_stmt *stmt; char query[1024]; sprintf(query, "update images set flags = (flags | %d) where id in (select imgid from selected_images)",DT_IMAGE_REMOVE); DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), query, NULL, NULL, NULL); dt_collection_update(darktable.collection); // We need a list of files to regenerate .xmp files if there are duplicates GList *list = NULL; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select distinct folder || '/' || filename from images, film_rolls where images.film_id = film_rolls.id and images.id in (select imgid from selected_images)", -1, &stmt, NULL); if(sqlite3_step(stmt) == SQLITE_ROW) { list = g_list_append(list, g_strdup((const gchar *)sqlite3_column_text(stmt, 0))); } sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select count(id) from images where filename in (select filename from images where id = ?1) and film_id in (select film_id from images where id = ?1)", -1, &stmt, NULL); while(t) { imgid = (long int)t->data; char filename[DT_MAX_PATH_LEN]; dt_image_full_path(imgid, filename, DT_MAX_PATH_LEN); int duplicates = 0; DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); if(sqlite3_step(stmt) == SQLITE_ROW) duplicates = sqlite3_column_int(stmt, 0); sqlite3_reset(stmt); sqlite3_clear_bindings(stmt); // remove from disk: if(duplicates == 1) // don't remove the actual data if there are (other) duplicates using it (void)g_unlink(filename); dt_image_path_append_version(imgid, filename, DT_MAX_PATH_LEN); char *c = filename + strlen(filename); sprintf(c, ".xmp"); (void)g_unlink(filename); dt_image_remove(imgid); t = g_list_delete_link(t, t); fraction=1.0/total; dt_control_backgroundjobs_progress(darktable.control, jid, fraction); } sqlite3_finalize(stmt); char *imgname; while(list) { imgname = (char *)list->data; dt_image_synch_all_xmp(imgname); list = g_list_delete_link(list, list); } g_list_free(list); dt_control_backgroundjobs_destroy(darktable.control, jid); dt_film_remove_empty(); return 0; }
static void delete_button_clicked(GtkButton *button, gpointer user_data) { dt_lib_module_t *self = (dt_lib_module_t *)user_data; dt_lib_tagging_t *d = (dt_lib_tagging_t *)self->data; int res = GTK_RESPONSE_YES; guint tagid; GtkTreeIter iter; GtkTreeModel *model = NULL; GtkTreeView *view = d->related; GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view)); if(!gtk_tree_selection_get_selected(selection, &model, &iter)) return; gtk_tree_model_get(model, &iter, DT_LIB_TAGGING_COL_ID, &tagid, -1); // First check how many images are affected by the remove int count = dt_tag_remove(tagid, FALSE); if(count > 0 && dt_conf_get_bool("plugins/lighttable/tagging/ask_before_delete_tag")) { GtkWidget *dialog; GtkWidget *win = dt_ui_main_window(darktable.gui->ui); gchar *tagname = dt_tag_get_name(tagid); dialog = gtk_message_dialog_new( GTK_WINDOW(win), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, ngettext("do you really want to delete the tag `%s'?\n%d image is assigned this tag!", "do you really want to delete the tag `%s'?\n%d images are assigned this tag!", count), tagname, count); gtk_window_set_title(GTK_WINDOW(dialog), _("delete tag?")); res = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); free(tagname); } if(res != GTK_RESPONSE_YES) return; GList *tagged_images = NULL; sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT imgid FROM main.tagged_images WHERE tagid=?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, tagid); while(sqlite3_step(stmt) == SQLITE_ROW) { tagged_images = g_list_append(tagged_images, GINT_TO_POINTER(sqlite3_column_int(stmt, 0))); } sqlite3_finalize(stmt); dt_tag_remove(tagid, TRUE); GList *list_iter; if((list_iter = g_list_first(tagged_images)) != NULL) { do { dt_image_synch_xmp(GPOINTER_TO_INT(list_iter->data)); } while((list_iter = g_list_next(list_iter)) != NULL); } g_list_free(g_list_first(tagged_images)); update(self, 0); update(self, 1); dt_control_signal_raise(darktable.signals, DT_SIGNAL_TAG_CHANGED); }
static GtkWidget* _lib_import_get_extra_widget(dt_lib_import_metadata_t *data, gboolean import_folder) { // add extra lines to 'extra'. don't forget to destroy the widgets later. GtkWidget *expander = gtk_expander_new(_("import options")); gtk_expander_set_expanded(GTK_EXPANDER(expander), dt_conf_get_bool("ui_last/import_options_expanded")); GtkWidget *frame = gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame),GTK_SHADOW_IN); GtkWidget *alignment = gtk_alignment_new(1.0, 1.0, 1.0, 1.0); gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 8, 8, 8, 8); GtkWidget *event_box = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(frame), event_box); gtk_container_add(GTK_CONTAINER(event_box), alignment); gtk_container_add(GTK_CONTAINER(alignment), expander); GtkWidget *extra; extra = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(expander), extra); GtkWidget *recursive = NULL, *ignore_jpeg = NULL; if(import_folder == TRUE) { // recursive opening. recursive = gtk_check_button_new_with_label (_("import directories recursively")); g_object_set(recursive, "tooltip-text", _("recursively import subdirectories. each directory goes into a new film roll."), NULL); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (recursive), dt_conf_get_bool("ui_last/import_recursive")); gtk_box_pack_start(GTK_BOX (extra), recursive, FALSE, FALSE, 0); // ignoring of jpegs. hack while we don't handle raw+jpeg in the same directories. ignore_jpeg = gtk_check_button_new_with_label (_("ignore jpeg files")); g_object_set(ignore_jpeg, "tooltip-text", _("do not load files with an extension of .jpg or .jpeg. this can be useful when there are raw+jpeg in a directory."), NULL); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (ignore_jpeg), dt_conf_get_bool("ui_last/import_ignore_jpegs")); gtk_box_pack_start(GTK_BOX (extra), ignore_jpeg, FALSE, FALSE, 0); } // default metadata GtkWidget *apply_metadata; GtkWidget *table, *label, *creator, *publisher, *rights, *tags; apply_metadata = gtk_check_button_new_with_label (_("apply metadata on import")); g_object_set(apply_metadata, "tooltip-text", _("apply some metadata to all newly imported images."), NULL); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (apply_metadata), dt_conf_get_bool("ui_last/import_apply_metadata")); gtk_box_pack_start(GTK_BOX (extra), apply_metadata, FALSE, FALSE, 0); GValue value = {0, }; g_value_init(&value, G_TYPE_INT); gtk_widget_style_get_property(apply_metadata, "indicator-size", &value); gint indicator_size = g_value_get_int(&value); // gtk_widget_style_get_property(apply_metadata, "indicator-spacing", &value); // gint indicator_spacing = g_value_get_int(&value); table = gtk_table_new(6, 3, FALSE); gtk_table_set_row_spacings(GTK_TABLE(table), 5); gtk_table_set_col_spacings(GTK_TABLE(table), 5); alignment = gtk_alignment_new(0, 0, 1, 1); gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 2*indicator_size, 0); gtk_container_add(GTK_CONTAINER(alignment), table); gtk_box_pack_start(GTK_BOX (extra), alignment, FALSE, FALSE, 0); creator = gtk_entry_new(); gtk_widget_set_size_request(creator, 300, -1); gtk_entry_set_text(GTK_ENTRY(creator), dt_conf_get_string("ui_last/import_last_creator")); publisher = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(publisher), dt_conf_get_string("ui_last/import_last_publisher")); rights = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(rights), dt_conf_get_string("ui_last/import_last_rights")); tags = gtk_entry_new(); g_object_set(tags, "tooltip-text", _("comma separated list of tags"), NULL); gtk_entry_set_text(GTK_ENTRY(tags), dt_conf_get_string("ui_last/import_last_tags")); // presets from the metadata plugin GtkCellRenderer *renderer; GtkTreeIter iter; GtkListStore *model = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING /*name*/, G_TYPE_STRING /*creator*/, G_TYPE_STRING /*publisher*/, G_TYPE_STRING /*rights*/); GtkWidget *presets = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model)); renderer = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(presets), renderer, FALSE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(presets), renderer, "text", NAME_COLUMN, NULL); sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select name, op_params from presets where operation = \"metadata\"", -1, &stmt, NULL); while(sqlite3_step(stmt) == SQLITE_ROW) { void *op_params = (void *)sqlite3_column_blob(stmt, 1); int32_t op_params_size = sqlite3_column_bytes(stmt, 1); char *buf = (char* )op_params; char *title = buf; buf += strlen(title) + 1; char *description = buf; buf += strlen(description) + 1; char *rights = buf; buf += strlen(rights) + 1; char *creator = buf; buf += strlen(creator) + 1; char *publisher = buf; if(op_params_size == strlen(title) + strlen(description) + strlen(rights) + strlen(creator) + strlen(publisher) + 5) { gtk_list_store_append(model, &iter); gtk_list_store_set (model, &iter, NAME_COLUMN, (char *)sqlite3_column_text(stmt, 0), CREATOR_COLUMN, creator, PUBLISHER_COLUMN, publisher, RIGHTS_COLUMN, rights, -1); } } sqlite3_finalize(stmt); g_object_unref(model); int line = 0; label = gtk_label_new(_("preset")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, line, line+1, GTK_FILL, 0, 0, 0); gtk_table_attach(GTK_TABLE(table), presets, 1, 2, line, line+1, GTK_FILL, 0, 0, 0); line++; label = gtk_label_new(_("creator")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, line, line+1, GTK_FILL, 0, 0, 0); gtk_table_attach(GTK_TABLE(table), creator, 1, 2, line, line+1, GTK_FILL, 0, 0, 0); line++; label = gtk_label_new(_("publisher")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, line, line+1, GTK_FILL, 0, 0, 0); gtk_table_attach(GTK_TABLE(table), publisher, 1, 2, line, line+1, GTK_FILL, 0, 0, 0); line++; label = gtk_label_new(_("rights")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, line, line+1, GTK_FILL, 0, 0, 0); gtk_table_attach(GTK_TABLE(table), rights, 1, 2, line, line+1, GTK_FILL, 0, 0, 0); line++; label = gtk_label_new(_("tags")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 1, line, line+1, GTK_FILL, 0, 0, 0); gtk_table_attach(GTK_TABLE(table), tags, 1, 2, line, line+1, GTK_FILL, 0, 0, 0); gtk_widget_show_all(frame); if(data != NULL) { data->frame = frame; data->recursive = recursive; data->ignore_jpeg = ignore_jpeg; data->expander = expander; data->apply_metadata = apply_metadata; data->presets = presets; data->creator = creator; data->publisher = publisher; data->rights = rights; data->tags = tags; } g_signal_connect(apply_metadata, "toggled", G_CALLBACK (_lib_import_apply_metadata_toggled), table); _lib_import_apply_metadata_toggled(apply_metadata, table); // needed since the apply_metadata starts being turned off, // and setting it to off doesn't emit the 'toggled' signal ... g_signal_connect(presets, "changed", G_CALLBACK(_lib_import_presets_changed), data); g_signal_connect(GTK_ENTRY(creator), "changed", G_CALLBACK (_lib_import_metadata_changed), presets); g_signal_connect(GTK_ENTRY(publisher), "changed", G_CALLBACK (_lib_import_metadata_changed), presets); g_signal_connect(GTK_ENTRY(rights), "changed", G_CALLBACK (_lib_import_metadata_changed), presets); return frame; }
static int image_index(lua_State *L) { const char* membername = lua_tostring(L, -1); const dt_image_t * my_image=checkreadimage(L,-2); if(luaA_struct_has_member_name(L,dt_image_t,membername)) { const int result = luaA_struct_push_member_name(L, dt_image_t, my_image, membername); releasereadimage(L,my_image); return result; } switch(luaL_checkoption(L,-1,NULL,image_fields_name)) { case PATH: { sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select folder from images, film_rolls where " "images.film_id = film_rolls.id and images.id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, my_image->id); if(sqlite3_step(stmt) == SQLITE_ROW) { lua_pushstring(L,(char *)sqlite3_column_text(stmt, 0)); } else { sqlite3_finalize(stmt); releasereadimage(L,my_image); return luaL_error(L,"should never happen"); } sqlite3_finalize(stmt); break; } case DUP_INDEX: { // get duplicate suffix int version = 0; sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select count(id) from images where filename in " "(select filename from images where id = ?1) and film_id in " "(select film_id from images where id = ?1) and id < ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, my_image->id); if(sqlite3_step(stmt) == SQLITE_ROW) version = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); lua_pushinteger(L,version); break; } case IS_LDR: lua_pushboolean(L,dt_image_is_ldr(my_image)); break; case IS_HDR: lua_pushboolean(L,dt_image_is_hdr(my_image)); break; case IS_RAW: lua_pushboolean(L,dt_image_is_raw(my_image)); break; case RATING: { int score = my_image->flags & 0x7; if(score >6) score=5; if(score ==6) score=-1; lua_pushinteger(L,score); break; } case ID: lua_pushinteger(L,my_image->id); break; case CREATOR: { sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),"select value from meta_data where id = ?1 and key = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, my_image->id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, DT_METADATA_XMP_DC_CREATOR); if(sqlite3_step(stmt) != SQLITE_ROW) { lua_pushstring(L,""); } else { lua_pushstring(L,(char *)sqlite3_column_text(stmt, 0)); } sqlite3_finalize(stmt); break; } case PUBLISHER: { sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),"select value from meta_data where id = ?1 and key = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, my_image->id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, DT_METADATA_XMP_DC_PUBLISHER); if(sqlite3_step(stmt) != SQLITE_ROW) { lua_pushstring(L,""); } else { lua_pushstring(L,(char *)sqlite3_column_text(stmt, 0)); } sqlite3_finalize(stmt); break; } case TITLE: { sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),"select value from meta_data where id = ?1 and key = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, my_image->id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, DT_METADATA_XMP_DC_TITLE); if(sqlite3_step(stmt) != SQLITE_ROW) { lua_pushstring(L,""); } else { lua_pushstring(L,(char *)sqlite3_column_text(stmt, 0)); } sqlite3_finalize(stmt); break; } case DESCRIPTION: { sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),"select value from meta_data where id = ?1 and key = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, my_image->id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, DT_METADATA_XMP_DC_DESCRIPTION); if(sqlite3_step(stmt) != SQLITE_ROW) { lua_pushstring(L,""); } else { lua_pushstring(L,(char *)sqlite3_column_text(stmt, 0)); } sqlite3_finalize(stmt); break; } case RIGHTS: { sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db),"select value from meta_data where id = ?1 and key = ?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, my_image->id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, DT_METADATA_XMP_DC_RIGHTS); if(sqlite3_step(stmt) != SQLITE_ROW) { lua_pushstring(L,""); } else { lua_pushstring(L,(char *)sqlite3_column_text(stmt, 0)); } sqlite3_finalize(stmt); break; } case GROUP_LEADER: { luaA_push(L,dt_lua_image_t,&(my_image->group_id)); break; } default: releasereadimage(L,my_image); return luaL_error(L,"should never happen %s",lua_tostring(L,-1)); } releasereadimage(L,my_image); return 1; }
void dt_styles_create_from_style (const char *name, const char *newname, const char *description, GList *filter) { sqlite3_stmt *stmt; int id=0; int oldid=0; oldid = dt_styles_get_id_by_name(name); if(oldid == 0) return; /* create the style header */ if (!dt_styles_create_style_header(newname, description)) return; if ((id=dt_styles_get_id_by_name(newname)) != 0) { if (filter) { GList *list=filter; char tmp[64]; char include[2048]= {0}; g_strlcat(include,"num in (", 2048); do { if(list!=g_list_first(list)) g_strlcat(include,",", 2048); sprintf(tmp,"%ld",(long int)list->data); g_strlcat(include,tmp, 2048); } while ((list=g_list_next(list))); g_strlcat(include,")", 2048); char query[4096]= {0}; sprintf(query,"insert into style_items (styleid,num,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name) select ?1, num,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name from style_items where styleid=?2 and %s",include); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL); } else DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into style_items (styleid,num,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name) select ?1, num,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name from style_items where style_id=?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, oldid); sqlite3_step (stmt); sqlite3_finalize (stmt); /* backup style to disk */ char stylesdir[1024]; dt_loc_get_user_config_dir(stylesdir, 1024); g_strlcat(stylesdir,"/styles",1024); g_mkdir_with_parents(stylesdir,00755); dt_styles_save_to_file(newname,stylesdir,FALSE); char tmp_accel[1024]; gchar* tmp_name = g_strdup(newname); // freed by _destro_style_shortcut_callback snprintf(tmp_accel,1024,"styles/Apply %s",newname); dt_accel_register_global( tmp_accel, 0, 0); GClosure *closure; closure = g_cclosure_new( G_CALLBACK(_apply_style_shortcut_callback), tmp_name, _destroy_style_shortcut_callback); dt_accel_connect_global(tmp_accel, closure); dt_control_log(_("style named '%s' successfully created"),newname); } }
static void auto_apply_presets(dt_develop_t *dev) { const int imgid = dev->image_storage.id; if(imgid <= 0) return; int run = 0; const dt_image_t *cimg = dt_image_cache_read_get(darktable.image_cache, imgid); if(!(cimg->flags & DT_IMAGE_AUTO_PRESETS_APPLIED)) run = 1; // flag was already set? only apply presets once in the lifetime of a history stack. // (the flag will be cleared when removing it) if(!run || cimg->id <= 0) { dt_image_cache_read_release(darktable.image_cache, cimg); return; } // keep locked, we want to be alone messing with the history of the poor fellow: dt_image_t *image = dt_image_cache_write_get(darktable.image_cache, cimg); // be extra sure that we don't mess up history in separate threads: dt_pthread_mutex_lock(&darktable.db_insert); // cleanup DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "delete from memory.history", NULL, NULL, NULL); const char *preset_table[2] = {"presets", "legacy_presets"}; const int legacy = (image->flags & DT_IMAGE_NO_LEGACY_PRESETS) ? 0 : 1; char query[1024]; snprintf(query, 1024, "insert into memory.history select ?1, 0, op_version, operation, op_params, enabled, blendop_params, blendop_version, multi_priority, multi_name " "from %s where autoapply=1 and " "?2 like model and ?3 like maker and ?4 like lens and " "?5 between iso_min and iso_max and " "?6 between exposure_min and exposure_max and " "?7 between aperture_min and aperture_max and " "?8 between focal_length_min and focal_length_max and " "(isldr = 0 or isldr=?9) order by writeprotect desc, " "length(model), length(maker), length(lens)", preset_table[legacy]); // query for all modules at once: sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, cimg->exif_model, strlen(cimg->exif_model), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 3, cimg->exif_maker, strlen(cimg->exif_maker), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 4, cimg->exif_lens, strlen(cimg->exif_lens), SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 5, fmaxf(0.0f, fminf(1000000, cimg->exif_iso))); DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 6, fmaxf(0.0f, fminf(1000000, cimg->exif_exposure))); DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 7, fmaxf(0.0f, fminf(1000000, cimg->exif_aperture))); DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 8, fmaxf(0.0f, fminf(1000000, cimg->exif_focal_length))); // 0: dontcare, 1: ldr, 2: raw DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 9, 2-dt_image_is_ldr(cimg)); if(sqlite3_step(stmt) == SQLITE_DONE) { sqlite3_finalize(stmt); int cnt = 0; // count what we found: DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select count(*) from memory.history", -1, &stmt, NULL); if(sqlite3_step(stmt) == SQLITE_ROW) { // if there is anything.. cnt = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); // fprintf(stderr, "[auto_apply_presets] imageid %d found %d matching presets (legacy %d)\n", imgid, cnt, legacy); // advance the current history by that amount: DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "update history set num=num+?1 where imgid=?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, cnt); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); if(sqlite3_step(stmt) == SQLITE_DONE) { // and finally prepend the rest with increasing numbers (starting at 0) sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "insert into history select imgid, rowid-1, module, operation, op_params, enabled, " "blendop_params, blendop_version, multi_priority, multi_name from memory.history", -1, &stmt, NULL); sqlite3_step(stmt); } } } sqlite3_finalize(stmt); // first time we are loading the image, try to import lightroom .xmp if any if (dev->image_loading) dt_lightroom_import(dev->image_storage.id, dev, TRUE); image->flags |= DT_IMAGE_AUTO_PRESETS_APPLIED | DT_IMAGE_NO_LEGACY_PRESETS; dt_pthread_mutex_unlock(&darktable.db_insert); // make sure these end up in the image_cache + xmp (sync through here if we set the flag) dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_SAFE); dt_image_cache_read_release(darktable.image_cache, cimg); }
void dt_styles_save_to_file(const char *style_name,const char *filedir,gboolean overwrite) { int rc = 0; char stylename[520]; sqlite3_stmt *stmt; snprintf(stylename,512,"%s/%s.dtstyle",filedir,style_name); // check if file exists if( g_file_test(stylename, G_FILE_TEST_EXISTS) == TRUE ) { if(overwrite) { if(unlink(stylename)) { dt_control_log(_("failed to overwrite style file for %s"),style_name); return; } } else { dt_control_log(_("style file for %s exists"),style_name); return; } } if ( !dt_styles_exists (style_name) ) return; xmlTextWriterPtr writer = xmlNewTextWriterFilename(stylename, 0); if (writer == NULL) { fprintf(stderr,"[dt_styles_save_to_file] Error creating the xml writer\n, path: %s", stylename); return; } rc = xmlTextWriterStartDocument(writer, NULL, "ISO-8859-1", NULL); if (rc < 0) { fprintf(stderr,"[dt_styles_save_to_file]: Error on encoding setting"); return; } xmlTextWriterStartElement(writer, BAD_CAST "darktable_style"); xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "1.0"); xmlTextWriterStartElement(writer, BAD_CAST "info"); xmlTextWriterWriteFormatElement(writer, BAD_CAST "name", "%s", style_name); xmlTextWriterWriteFormatElement(writer, BAD_CAST "description", "%s", dt_styles_get_description(style_name)); xmlTextWriterEndElement(writer); xmlTextWriterStartElement(writer, BAD_CAST "style"); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select num,module,operation,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name from style_items where styleid =?1",-1, &stmt,NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt,1,dt_styles_get_id_by_name(style_name)); while (sqlite3_step (stmt) == SQLITE_ROW) { xmlTextWriterStartElement(writer, BAD_CAST "plugin"); xmlTextWriterWriteFormatElement(writer, BAD_CAST "num", "%d", sqlite3_column_int(stmt,0)); xmlTextWriterWriteFormatElement(writer, BAD_CAST "module", "%d", sqlite3_column_int(stmt,1)); xmlTextWriterWriteFormatElement(writer, BAD_CAST "operation", "%s", sqlite3_column_text(stmt,2)); xmlTextWriterWriteFormatElement(writer, BAD_CAST "op_params", "%s", dt_style_encode(stmt,3)); xmlTextWriterWriteFormatElement(writer, BAD_CAST "enabled", "%d", sqlite3_column_int(stmt,4)); xmlTextWriterWriteFormatElement(writer, BAD_CAST "blendop_params", "%s", dt_style_encode(stmt,5)); xmlTextWriterWriteFormatElement(writer, BAD_CAST "blendop_version", "%d", sqlite3_column_int(stmt,6)); xmlTextWriterWriteFormatElement(writer, BAD_CAST "multi_priority", "%d", sqlite3_column_int(stmt,7)); xmlTextWriterWriteFormatElement(writer, BAD_CAST "multi_name", "%s", sqlite3_column_text(stmt,8)); xmlTextWriterEndElement(writer); } sqlite3_finalize(stmt); xmlTextWriterEndDocument(writer); xmlFreeTextWriter(writer); dt_control_log(_("style %s was successfully saved"),style_name); }
void dt_dev_read_history(dt_develop_t *dev) { if(dev->image_storage.id <= 0) return; if(!dev->iop) return; // maybe prepend auto-presets to history before loading it: auto_apply_presets(dev); sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select imgid, num, module, operation, op_params, enabled, blendop_params, blendop_version, multi_priority, multi_name from history where imgid = ?1 order by num", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dev->image_storage.id); dev->history_end = 0; while(sqlite3_step(stmt) == SQLITE_ROW) { // db record: // 0-img, 1-num, 2-module_instance, 3-operation char, 4-params blob, 5-enabled, 6-blend_params, 7-blendop_version, 8 multi_priority, 9 multi_name dt_dev_history_item_t *hist = (dt_dev_history_item_t *)malloc(sizeof(dt_dev_history_item_t)); hist->enabled = sqlite3_column_int(stmt, 5); GList *modules = dev->iop; const char *opname = (const char *)sqlite3_column_text(stmt, 3); int multi_priority = sqlite3_column_int(stmt, 8); const char *multi_name = (const char *)sqlite3_column_text(stmt, 9); if(!opname) { fprintf(stderr, "[dev_read_history] database history for image `%s' seems to be corrupted!\n", dev->image_storage.filename); free(hist); continue; } hist->module = NULL; dt_iop_module_t *find_op = NULL; while(opname && modules) { dt_iop_module_t *module = (dt_iop_module_t *)modules->data; if(!strcmp(module->op, opname)) { if (module->multi_priority == multi_priority) { hist->module = module; break; } else if (multi_priority > 0) { //we just say that we find the name, so we just have to add new instance of this module find_op = module; } } modules = g_list_next(modules); } if (!hist->module && find_op) { //we have to add a new instance of this module and set index to modindex dt_iop_module_t *new_module = (dt_iop_module_t *)malloc(sizeof(dt_iop_module_t)); if (!dt_iop_load_module(new_module, find_op->so, dev)) { new_module->multi_priority = multi_priority; snprintf(new_module->multi_name,128,"%s",multi_name); dev->iop = g_list_insert_sorted(dev->iop, new_module, sort_plugins); new_module->instance = find_op->instance; hist->module = new_module; } } if(!hist->module && opname) { fprintf(stderr, "[dev_read_history] the module `%s' requested by image `%s' is not installed on this computer!\n", opname, dev->image_storage.filename); free(hist); continue; } int modversion = sqlite3_column_int(stmt, 2); assert(strcmp((char *)sqlite3_column_text(stmt, 3), hist->module->op) == 0); hist->params = malloc(hist->module->params_size); hist->blend_params = malloc(sizeof(dt_develop_blend_params_t)); snprintf(hist->multi_name,128,"%s",multi_name); hist->multi_priority = multi_priority; if(hist->module->version() != modversion || hist->module->params_size != sqlite3_column_bytes(stmt, 4) || strcmp((char *)sqlite3_column_text(stmt, 3), hist->module->op)) { if(!hist->module->legacy_params || hist->module->legacy_params(hist->module, sqlite3_column_blob(stmt, 4), labs(modversion), hist->params, labs(hist->module->version()))) { free(hist->params); free(hist->blend_params); fprintf(stderr, "[dev_read_history] module `%s' version mismatch: history is %d, dt %d.\n", hist->module->op, modversion, hist->module->version()); const char *fname = dev->image_storage.filename + strlen(dev->image_storage.filename); while(fname > dev->image_storage.filename && *fname != '/') fname --; if(fname > dev->image_storage.filename) fname++; dt_control_log(_("%s: module `%s' version mismatch: %d != %d"), fname, hist->module->op, hist->module->version(), modversion); free(hist); continue; } } else { memcpy(hist->params, sqlite3_column_blob(stmt, 4), hist->module->params_size); } const void *blendop_params = sqlite3_column_blob(stmt, 6); int bl_length = sqlite3_column_bytes(stmt, 6); int blendop_version = sqlite3_column_int(stmt, 7); if (blendop_params && (blendop_version == dt_develop_blend_version()) && (bl_length == sizeof(dt_develop_blend_params_t))) { memcpy(hist->blend_params, blendop_params, sizeof(dt_develop_blend_params_t)); } else if (blendop_params && dt_develop_blend_legacy_params(hist->module, blendop_params, blendop_version, hist->blend_params, dt_develop_blend_version(), bl_length) == 0) { // do nothing } else { memcpy(hist->blend_params, hist->module->default_blendop_params, sizeof(dt_develop_blend_params_t)); } // memcpy(hist->module->params, hist->params, hist->module->params_size); // hist->module->enabled = hist->enabled; // printf("[dev read history] img %d number %d for operation %d - %s params %f %f\n", sqlite3_column_int(stmt, 0), sqlite3_column_int(stmt, 1), instance, hist->module->op, *(float *)hist->params, *(((float*)hist->params)+1)); dev->history = g_list_append(dev->history, hist); dev->history_end ++; } if(dev->gui_attached) { dev->pipe->changed |= DT_DEV_PIPE_SYNCH; dev->preview_pipe->changed |= DT_DEV_PIPE_SYNCH; // again, fixed topology for now. dt_dev_invalidate_all(dev); /* signal history changed */ dt_control_signal_raise(darktable.signals,DT_SIGNAL_DEVELOP_HISTORY_CHANGE); } sqlite3_finalize (stmt); }
/* create the current database schema and set the version in db_info accordingly */ static void _create_schema(dt_database_t *db) { sqlite3_stmt *stmt; ////////////////////////////// db_info DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE db_info (key VARCHAR PRIMARY KEY, value VARCHAR)", NULL, NULL, NULL); DT_DEBUG_SQLITE3_PREPARE_V2(db->handle, "INSERT OR REPLACE INTO db_info (key, value) VALUES ('version', ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, CURRENT_DATABASE_VERSION); sqlite3_step(stmt); sqlite3_finalize(stmt); ////////////////////////////// film_rolls DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE film_rolls " "(id INTEGER PRIMARY KEY, datetime_accessed CHAR(20), " // "folder VARCHAR(1024), external_drive VARCHAR(1024))", // FIXME: make sure to bump CURRENT_DATABASE_VERSION and add a case to _upgrade_schema_step when adding this! "folder VARCHAR(1024))", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE INDEX film_rolls_folder_index ON film_rolls (folder)", NULL, NULL, NULL); ////////////////////////////// images DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE images (id INTEGER PRIMARY KEY AUTOINCREMENT, group_id INTEGER, film_id INTEGER, " "width INTEGER, height INTEGER, filename VARCHAR, maker VARCHAR, model VARCHAR, " "lens VARCHAR, exposure REAL, aperture REAL, iso REAL, focal_length REAL, " "focus_distance REAL, datetime_taken CHAR(20), flags INTEGER, " "output_width INTEGER, output_height INTEGER, crop REAL, " "raw_parameters INTEGER, raw_denoise_threshold REAL, " "raw_auto_bright_threshold REAL, raw_black INTEGER, raw_maximum INTEGER, " "caption VARCHAR, description VARCHAR, license VARCHAR, sha1sum CHAR(40), " "orientation INTEGER, histogram BLOB, lightmap BLOB, longitude REAL, " "latitude REAL, color_matrix BLOB, colorspace INTEGER, version INTEGER, max_version INTEGER, write_timestamp INTEGER)", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE INDEX images_group_id_index ON images (group_id)", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE INDEX images_film_id_index ON images (film_id)", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE INDEX images_filename_index ON images (filename)", NULL, NULL, NULL); ////////////////////////////// selected_images DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE selected_images (imgid INTEGER PRIMARY KEY)", NULL, NULL, NULL); ////////////////////////////// history DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE history (imgid INTEGER, num INTEGER, module INTEGER, " "operation VARCHAR(256), op_params BLOB, enabled INTEGER, " "blendop_params BLOB, blendop_version INTEGER, multi_priority INTEGER, multi_name VARCHAR(256))", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE INDEX history_imgid_index ON history (imgid)", NULL, NULL, NULL); ////////////////////////////// mask DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE mask (imgid INTEGER, formid INTEGER, form INTEGER, name VARCHAR(256), " "version INTEGER, points BLOB, points_count INTEGER, source BLOB)", NULL, NULL, NULL); ////////////////////////////// tags DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE tags (id INTEGER PRIMARY KEY, name VARCHAR, icon BLOB, " "description VARCHAR, flags INTEGER)", NULL, NULL, NULL); ////////////////////////////// tagged_images DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE tagged_images (imgid INTEGER, tagid INTEGER, " "PRIMARY KEY (imgid, tagid))", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE INDEX tagged_images_tagid_index ON tagged_images (tagid)", NULL, NULL, NULL); ////////////////////////////// tagxtag DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE tagxtag (id1 INTEGER, id2 INTEGER, count INTEGER, " "PRIMARY KEY (id1, id2))", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TRIGGER insert_tag AFTER INSERT ON tags" " BEGIN" " INSERT INTO tagxtag SELECT id, new.id, 0 FROM TAGS;" " UPDATE tagxtag SET count = 1000000 WHERE id1=new.id AND id2=new.id;" " END", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TRIGGER delete_tag BEFORE DELETE on tags" " BEGIN" " DELETE FROM tagxtag WHERE id1=old.id OR id2=old.id;" " DELETE FROM tagged_images WHERE tagid=old.id;" " END", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TRIGGER attach_tag AFTER INSERT ON tagged_images" " BEGIN" " UPDATE tagxtag" " SET count = count + 1" " WHERE (id1=new.tagid AND id2 IN (SELECT tagid FROM tagged_images WHERE imgid=new.imgid))" " OR (id2=new.tagid AND id1 IN (SELECT tagid FROM tagged_images WHERE imgid=new.imgid));" " END", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TRIGGER detach_tag BEFORE DELETE ON tagged_images" " BEGIN" " UPDATE tagxtag" " SET count = count - 1" " WHERE (id1=old.tagid AND id2 IN (SELECT tagid FROM tagged_images WHERE imgid=old.imgid))" " OR (id2=old.tagid AND id1 IN (SELECT tagid FROM tagged_images WHERE imgid=old.imgid));" " END", NULL, NULL, NULL); ////////////////////////////// styles DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE styles (id INTEGER, name VARCHAR, description VARCHAR)", NULL, NULL, NULL); ////////////////////////////// style_items DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE style_items (styleid INTEGER, num INTEGER, module INTEGER, " "operation VARCHAR(256), op_params BLOB, enabled INTEGER, " "blendop_params BLOB, blendop_version INTEGER, multi_priority INTEGER, multi_name VARCHAR(256))", NULL, NULL, NULL); ////////////////////////////// color_labels DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE color_labels (imgid INTEGER, color INTEGER)", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE UNIQUE INDEX color_labels_idx ON color_labels (imgid, color)", NULL, NULL, NULL); ////////////////////////////// meta_data DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE meta_data (id INTEGER, key INTEGER, value VARCHAR)", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE INDEX metadata_index ON meta_data (id, key)", NULL, NULL, NULL); ////////////////////////////// presets DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE TABLE presets (name VARCHAR, description VARCHAR, operation VARCHAR, op_version INTEGER, op_params BLOB, " "enabled INTEGER, blendop_params BLOB, blendop_version INTEGER, multi_priority INTEGER, multi_name VARCHAR(256), " "model VARCHAR, maker VARCHAR, lens VARCHAR, iso_min REAL, iso_max REAL, exposure_min REAL, exposure_max REAL, " "aperture_min REAL, aperture_max REAL, focal_length_min REAL, focal_length_max REAL, writeprotect INTEGER, " "autoapply INTEGER, filter INTEGER, def INTEGER, format INTEGER)", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(db->handle, "CREATE UNIQUE INDEX presets_idx ON presets(name, operation, op_version)", NULL, NULL, NULL); }
static gboolean _lib_filmstrip_expose_callback(GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { dt_lib_module_t *self = (dt_lib_module_t *)user_data; dt_lib_filmstrip_t *strip = (dt_lib_filmstrip_t *)self->data; int32_t width = widget->allocation.width; int32_t height = widget->allocation.height; gdouble pointerx = strip->pointerx; gdouble pointery = strip->pointery; if(darktable.gui->center_tooltip == 1) darktable.gui->center_tooltip++; strip->image_over = DT_VIEW_DESERT; DT_CTL_SET_GLOBAL(lib_image_mouse_over_id, -1); /* create cairo surface */ cairo_t *cr = gdk_cairo_create(widget->window); /* fill background */ cairo_set_source_rgb (cr, .2, .2, .2); cairo_paint(cr); int offset = strip->offset; const float wd = height; const float ht = height; /* mouse over image position in filmstrip */ const int seli = (pointery > 0 && pointery <= ht) ? pointerx / (float)wd : -1; const int img_pointerx = (int)fmodf(pointerx, wd); const int img_pointery = (int)pointery; const int max_cols = (int)(1+width/(float)wd); sqlite3_stmt *stmt = NULL; /* get the count of current collection */ int count = dt_collection_get_count (darktable.collection); /* get the collection query */ const gchar *query=dt_collection_get_query (darktable.collection); if(!query) return FALSE; if(offset < 0) strip->offset = offset = 0; if(offset > count-max_cols+1) strip->offset = offset = count-max_cols+1; // dt_view_set_scrollbar(self, offset, count, max_cols, 0, 1, 1); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), query, -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, offset); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, max_cols); cairo_save(cr); for(int col = 0; col < max_cols; col++) { if(sqlite3_step(stmt) == SQLITE_ROW) { int id = sqlite3_column_int(stmt, 0); // set mouse over id if(seli == col) { strip->mouse_over_id = id; DT_CTL_SET_GLOBAL(lib_image_mouse_over_id, strip->mouse_over_id); } cairo_save(cr); // FIXME find out where the y translation is done, how big the value is and use it directly instead of getting it from the matrix ... cairo_matrix_t m; cairo_get_matrix(cr, &m); dt_view_image_expose(&(strip->image_over), id, cr, wd, ht, max_cols, img_pointerx, img_pointery); cairo_restore(cr); } else goto failure; cairo_translate(cr, wd, 0.0f); } failure: cairo_restore(cr); sqlite3_finalize(stmt); if(darktable.gui->center_tooltip == 1) // set in this round { char* tooltip = dt_history_get_items_as_string(strip->mouse_over_id); if(tooltip != NULL) { g_object_set(G_OBJECT(strip->filmstrip), "tooltip-text", tooltip, (char *)NULL); g_free(tooltip); } } else if(darktable.gui->center_tooltip == 2) // not set in this round { darktable.gui->center_tooltip = 0; g_object_set(G_OBJECT(strip->filmstrip), "tooltip-text", "", (char *)NULL); } #ifdef _DEBUG if(darktable.unmuted & DT_DEBUG_CACHE) dt_mipmap_cache_print(darktable.mipmap_cache); #endif /* cleanup */ cairo_destroy(cr); return TRUE; }
// This is basically the same as dt_image_remove() from common/image.c. // It just does the iteration over all images in the SQL statement void dt_film_remove(const int id) { // only allowed if local copies have their original accessible sqlite3_stmt *stmt; gboolean remove_ok = TRUE; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM images WHERE film_id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); while(sqlite3_step(stmt) == SQLITE_ROW) { int imgid = sqlite3_column_int(stmt, 0); if (!dt_image_safe_remove(imgid)) { remove_ok = FALSE; break; } } sqlite3_finalize(stmt); if (!remove_ok) { dt_control_log(_("cannot remove film roll having local copies with non accessible originals")); return; } DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from tagged_images where imgid in " "(select id from images where film_id = ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from history where imgid in " "(select id from images where film_id = ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from color_labels where imgid in " "(select id from images where film_id = ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from meta_data where id in " "(select id from images where film_id = ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from selected_images where imgid in " "(select id from images where film_id = ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id from images where film_id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); while(sqlite3_step(stmt) == SQLITE_ROW) { const uint32_t imgid = sqlite3_column_int(stmt, 0); dt_image_local_copy_reset(imgid); dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); dt_image_cache_remove (darktable.image_cache, imgid); } sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from images where id in " "(select id from images where film_id = ?1)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from film_rolls where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); // dt_control_update_recent_films(); dt_control_signal_raise(darktable.signals , DT_SIGNAL_FILMROLLS_CHANGED); }
static void dt_gui_presets_popup_menu_show_internal(dt_dev_operation_t op, int32_t version, dt_iop_params_t *params, int32_t params_size, dt_develop_blend_params_t *bl_params, dt_iop_module_t *module, const dt_image_t *image, void (*pick_callback)(GtkMenuItem *, void *), void *callback_data) { GtkMenu *menu = darktable.gui->presets_popup_menu; if(menu) gtk_widget_destroy(GTK_WIDGET(menu)); darktable.gui->presets_popup_menu = GTK_MENU(gtk_menu_new()); menu = darktable.gui->presets_popup_menu; GtkWidget *mi; int active_preset = -1, cnt = 0, writeprotect = 0; //, selected_default = 0; sqlite3_stmt *stmt; // order: get shipped defaults first if(image) { // only matching if filter is on: DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select name, op_params, writeprotect, description, blendop_params, " "op_version, enabled from presets where operation=?1 and " "(filter=0 or ( " "((?2 like model and ?3 like maker) or (?4 like model and ?5 like maker)) and " "?6 like lens and " "?7 between iso_min and iso_max and " "?8 between exposure_min and exposure_max and " "?9 between aperture_min and aperture_max and " "?10 between focal_length_min and focal_length_max and " "(format = 0 or format&?9!=0)" " ) )" "order by writeprotect desc, lower(name), rowid", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, op, -1, SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, image->exif_model, -1, SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 3, image->exif_maker, -1, SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 4, image->camera_alias, -1, SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 5, image->camera_maker, -1, SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 6, image->exif_lens, -1, SQLITE_TRANSIENT); DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 7, image->exif_iso); DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 8, image->exif_exposure); DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 9, image->exif_aperture); DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 10, image->exif_focal_length); int ldr = dt_image_is_ldr(image) ? FOR_LDR : (dt_image_is_raw(image) ? FOR_RAW : FOR_HDR); DT_DEBUG_SQLITE3_BIND_INT(stmt, 9, ldr); } else { // don't know for which image. show all we got: DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select name, op_params, writeprotect, " "description, blendop_params, op_version, " "enabled from presets where operation=?1 " "order by writeprotect desc, lower(name), rowid", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, op, -1, SQLITE_TRANSIENT); } // collect all presets for op from db int found = 0; while(sqlite3_step(stmt) == SQLITE_ROW) { void *op_params = (void *)sqlite3_column_blob(stmt, 1); int32_t op_params_size = sqlite3_column_bytes(stmt, 1); void *blendop_params = (void *)sqlite3_column_blob(stmt, 4); int32_t bl_params_size = sqlite3_column_bytes(stmt, 4); int32_t preset_version = sqlite3_column_int(stmt, 5); int32_t enabled = sqlite3_column_int(stmt, 6); int32_t isdefault = 0; int32_t isdisabled = (preset_version == version ? 0 : 1); const char *name = (char *)sqlite3_column_text(stmt, 0); if(darktable.gui->last_preset && strcmp(darktable.gui->last_preset, name) == 0) found = 1; if(module && !memcmp(module->default_params, op_params, MIN(op_params_size, module->params_size)) && !memcmp(module->default_blendop_params, blendop_params, MIN(bl_params_size, sizeof(dt_develop_blend_params_t)))) isdefault = 1; if(module && !memcmp(params, op_params, MIN(op_params_size, params_size)) && !memcmp(bl_params, blendop_params, MIN(bl_params_size, sizeof(dt_develop_blend_params_t))) && module->enabled == enabled) { active_preset = cnt; writeprotect = sqlite3_column_int(stmt, 2); char *markup; mi = gtk_menu_item_new_with_label(""); if(isdefault) { markup = g_markup_printf_escaped("<span weight=\"bold\">%s %s</span>", name, _("(default)")); } else markup = g_markup_printf_escaped("<span weight=\"bold\">%s</span>", name); gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(mi))), markup); g_free(markup); } else { if(isdefault) { char *markup; mi = gtk_menu_item_new_with_label(""); markup = g_markup_printf_escaped("%s %s", name, _("(default)")); gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(mi))), markup); g_free(markup); } else mi = gtk_menu_item_new_with_label((const char *)name); } if(isdisabled) { gtk_widget_set_sensitive(mi, 0); gtk_widget_set_tooltip_text(mi, _("disabled: wrong module version")); } else { if(module) g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_pick_preset), module); else if(pick_callback) g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(pick_callback), callback_data); gtk_widget_set_tooltip_text(mi, (const char *)sqlite3_column_text(stmt, 3)); } gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); cnt++; } sqlite3_finalize(stmt); if(cnt > 0) gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new()); if(module) { if(active_preset >= 0 && !writeprotect) { mi = gtk_menu_item_new_with_label(_("edit this preset..")); g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_edit_preset), module); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); mi = gtk_menu_item_new_with_label(_("delete this preset")); g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_delete_preset), module); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); } else { mi = gtk_menu_item_new_with_label(_("store new preset..")); g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_new_preset), module); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); if(darktable.gui->last_preset && found) { char *markup = g_markup_printf_escaped("%s <span weight=\"bold\">%s</span>", _("update preset"), darktable.gui->last_preset); mi = gtk_menu_item_new_with_label(""); gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(mi))), markup); g_signal_connect(G_OBJECT(mi), "activate", G_CALLBACK(menuitem_update_preset), module); gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi); g_free(markup); } } } }