gboolean dt_styles_create_from_image (const char *name,const char *description,int32_t imgid,GList *filter) { int id=0; sqlite3_stmt *stmt; /* first create the style header */ if (!dt_styles_create_style_header(name,description) ) return FALSE; if ((id=dt_styles_get_id_by_name(name)) != 0) { /* create the style_items from source image history stack */ 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",(glong)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 history where imgid=?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 history where imgid=?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step (stmt); sqlite3_finalize (stmt); _dt_style_cleanup_multi_instance(id); /* 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(name,stylesdir,FALSE); char tmp_accel[1024]; gchar* tmp_name = g_strdup(name); // freed by _destroy_style_shortcut_callback snprintf(tmp_accel,1024,C_("accel", "styles/apply %s"),name); 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); return TRUE; } return FALSE; }
void dt_similarity_match_image(uint32_t imgid,dt_similarity_t *data) { sqlite3_stmt *stmt; gboolean all_ok_for_match = TRUE; dt_similarity_histogram_t orginal_histogram,test_histogram; dt_similarity_lightmap_t orginal_lightmap,test_lightmap; /* create temporary mem table for matches */ DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "create temporary table if not exists similar_images (id integer,score real)", NULL, NULL, NULL); DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "delete from similar_images", NULL, NULL, NULL); /* * get the histogram and lightmap data for image to match against */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select histogram,lightmap from images where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); if (sqlite3_step(stmt) == SQLITE_ROW) { /* get the histogram data */ uint32_t size = sqlite3_column_bytes(stmt,0); if (size!=sizeof(dt_similarity_histogram_t)) { all_ok_for_match = FALSE; dt_control_log(_("this image has not been indexed yet.")); } else memcpy(&orginal_histogram, sqlite3_column_blob(stmt, 0), sizeof(dt_similarity_histogram_t)); /* get the lightmap data */ size = sqlite3_column_bytes(stmt,1); if (size!=sizeof(dt_similarity_lightmap_t)) { all_ok_for_match = FALSE; dt_control_log(_("this image has not been indexed yet.")); } else memcpy(&orginal_lightmap, sqlite3_column_blob(stmt, 1), sizeof(dt_similarity_lightmap_t)); } else { all_ok_for_match = FALSE; dt_control_log(_("this image has not been indexed yet.")); } sqlite3_reset(stmt); sqlite3_clear_bindings(stmt); /* * if all ok lets begin matching */ if (all_ok_for_match) { char query[4096]={0}; /* add target image with 100.0 in score into result to ensure it always shown in top */ sprintf(query,"insert into similar_images(id,score) values(%d,%f)",imgid,100.0); DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), query, NULL, NULL, NULL); /* set an extended collection query for viewing the result of match */ dt_collection_set_extended_where(darktable.collection, ", similar_images where images.id = similar_images.id order by similar_images.score desc"); dt_collection_set_query_flags( darktable.collection, dt_collection_get_query_flags(darktable.collection) | COLLECTION_QUERY_USE_ONLY_WHERE_EXT); dt_collection_update(darktable.collection); dt_control_signal_raise(darktable.signals, DT_SIGNAL_COLLECTION_CHANGED); /* loop thru images and generate score table */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id,histogram,lightmap from images", -1, &stmt, NULL); while (sqlite3_step(stmt) == SQLITE_ROW) { float score_histogram=0, score_lightmap=0, score_colormap=0; /* verify size of histogram and lightmap blob of test image */ if ( (sqlite3_column_bytes(stmt,1) == sizeof(dt_similarity_histogram_t)) && (sqlite3_column_bytes(stmt,2) == sizeof(dt_similarity_lightmap_t)) ) { /* * Get the histogram blob and calculate the similarity score */ memcpy(&test_histogram, sqlite3_column_blob(stmt, 1), sizeof(dt_similarity_histogram_t)); score_histogram = _similarity_match_histogram_rgb(data, &orginal_histogram, &test_histogram); /* * Get the lightmap blob and calculate the similarity score * 1.08 is a tuned constant that works well with threshold */ memcpy(&test_lightmap, sqlite3_column_blob(stmt, 2), sizeof(dt_similarity_lightmap_t)); score_lightmap = _similarity_match_lightmap(data, &orginal_lightmap, &test_lightmap); /* * then calculate the colormap similarity score */ score_colormap = _similarity_match_colormap(data, &orginal_lightmap, &test_lightmap); /* * calculate the similarity score */ float score = (pow(score_histogram, data->histogram_weight) * pow(score_lightmap, data->lightmap_weight) * pow(score_colormap, data->redmap_weight)); // fprintf(stderr,"score: %f, histo: %f, light: %f, color: %f\n",score,score_histogram,score_lightmap,score_colormap); /* * If current images scored, lets add it to similar_images table */ if(score >= 0.92) { sprintf(query,"insert into similar_images(id,score) values(%d,%f)",sqlite3_column_int(stmt, 0),score); DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), query, NULL, NULL, NULL); /* lets redraw the view */ dt_control_queue_redraw_center(); } } else fprintf(stderr,"Image has inconsisten similarity matching data..\n"); } } sqlite3_finalize (stmt); }
static void _lib_tag_gui_update (gpointer instance,gpointer self) { dt_lib_module_t *dm = (dt_lib_module_t *)self; dt_lib_keywords_t *d = (dt_lib_keywords_t*)dm->data; GtkTreeStore *store = gtk_tree_store_new(1, G_TYPE_STRING); /* intialize the tree store with known tags */ sqlite3_stmt *stmt; GtkTreeIter uncategorized, temp; memset(&uncategorized,0,sizeof(GtkTreeIter)); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT name,icon,description FROM tags ORDER BY UPPER(name) DESC", -1, &stmt, NULL); gtk_tree_store_clear(store); while (sqlite3_step(stmt) == SQLITE_ROW) { if(strchr((const char *)sqlite3_column_text(stmt, 0),'|')==0) { /* add uncategorized root iter if not exists */ if (!uncategorized.stamp) { gtk_tree_store_insert(store, &uncategorized, NULL,0); gtk_tree_store_set(store, &uncategorized, 0, _(UNCATEGORIZED_TAG), -1); } /* adding a uncategorized tag */ gtk_tree_store_insert(store, &temp, &uncategorized,0); gtk_tree_store_set(store, &temp, 0, sqlite3_column_text(stmt, 0), -1); } else { int level = 0; char *value; GtkTreeIter current,iter; char **pch = g_strsplit((char *)sqlite3_column_text(stmt, 0),"|", -1); if (pch != NULL) { int j = 0; while (pch[j] != NULL) { gboolean found=FALSE; int children = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store),level>0?¤t:NULL); /* find child with name, if not found create and continue */ for (int k=0; k<children; k++) { if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, level>0?¤t:NULL, k)) { gtk_tree_model_get (GTK_TREE_MODEL(store), &iter, 0, &value, -1); if (strcmp(value, pch[j])==0) { current = iter; found = TRUE; break; } } } /* lets add new keyword and assign current */ if (!found) { gtk_tree_store_insert(store, &iter, level>0?¤t:NULL,0); gtk_tree_store_set(store, &iter, 0, pch[j], -1); current = iter; } level++; j++; } g_strfreev(pch); } } } gtk_tree_view_set_model(d->view, GTK_TREE_MODEL(store)); /* free store, treeview has its own storage now */ g_object_unref(store); }
gboolean dt_styles_create_from_image(const char *name, const char *description, int32_t imgid, GList *filter) { int id = 0; sqlite3_stmt *stmt; /* first create the style header */ if(!dt_styles_create_style_header(name, description)) return FALSE; if((id = dt_styles_get_id_by_name(name)) != 0) { /* create the style_items from source image history stack */ if(filter) { GList *list = filter; char tmp[64]; char include[2048] = { 0 }; g_strlcat(include, "num IN (", sizeof(include)); do { if(list != g_list_first(list)) g_strlcat(include, ",", sizeof(include)); snprintf(tmp, sizeof(tmp), "%d", GPOINTER_TO_INT(list->data)); g_strlcat(include, tmp, sizeof(include)); } while((list = g_list_next(list))); g_strlcat(include, ")", sizeof(include)); char query[4096] = { 0 }; snprintf(query, sizeof(query), "INSERT INTO data.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 main.history WHERE imgid=?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 data.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 main.history WHERE imgid=?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step(stmt); sqlite3_finalize(stmt); _dt_style_cleanup_multi_instance(id); /* backup style to disk */ char stylesdir[PATH_MAX] = { 0 }; dt_loc_get_user_config_dir(stylesdir, sizeof(stylesdir)); g_strlcat(stylesdir, "/styles", sizeof(stylesdir)); g_mkdir_with_parents(stylesdir, 00755); dt_styles_save_to_file(name, stylesdir, FALSE); char tmp_accel[1024]; gchar *tmp_name = g_strdup(name); // freed by _destroy_style_shortcut_callback snprintf(tmp_accel, sizeof(tmp_accel), C_("accel", "styles/apply %s"), name); 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_signal_raise(darktable.signals, DT_SIGNAL_STYLE_CHANGED); return TRUE; } return FALSE; }
GList *dt_styles_get_item_list(const char *name, gboolean params, int imgid) { GList *result = NULL; sqlite3_stmt *stmt; int id = 0; if((id = dt_styles_get_id_by_name(name)) != 0) { if(params) DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT num, module, operation, enabled, op_params, blendop_params, " "multi_name FROM data.style_items WHERE styleid=?1 ORDER BY num DESC", -1, &stmt, NULL); else if(imgid != -1) { // get all items from the style // UNION // get all items from history, not in the style : select only the last operation, that is max(num) DT_DEBUG_SQLITE3_PREPARE_V2( dt_database_get(darktable.db), "SELECT num, module, operation, enabled, (SELECT MAX(num) FROM main.history WHERE imgid=?2 AND " "operation=data.style_items.operation GROUP BY multi_priority),multi_name FROM data.style_items WHERE " "styleid=?1 UNION SELECT -1,main.history.module,main.history.operation,main.history.enabled, " "main.history.num,multi_name FROM main.history WHERE imgid=?2 AND main.history.enabled=1 AND " "(main.history.operation NOT IN (SELECT operation FROM data.style_items WHERE styleid=?1) OR " "(main.history.op_params NOT IN (SELECT op_params FROM data.style_items WHERE styleid=?1 AND " "operation=main.history.operation)) OR (main.history.blendop_params NOT IN (SELECT blendop_params FROM " "data.style_items WHERE styleid=?1 AND operation=main.history.operation))) GROUP BY operation HAVING " "MAX(num) ORDER BY num DESC", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); } else DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT num, module, operation, enabled, 0, " "multi_name FROM data.style_items WHERE " "styleid=?1 ORDER BY num DESC", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); while(sqlite3_step(stmt) == SQLITE_ROW) { // name of current item of style char iname[512] = { 0 }; dt_style_item_t *item = calloc(1, sizeof(dt_style_item_t)); if(sqlite3_column_type(stmt, 0) == SQLITE_NULL) item->num = -1; else item->num = sqlite3_column_int(stmt, 0); item->selimg_num = -1; item->module_version = sqlite3_column_int(stmt, 1); item->enabled = sqlite3_column_int(stmt, 3); if(params) { // when we get the parameters we do not want to get the operation localized as this // is used to compare against the internal module name. const char *multi_name = (const char *)sqlite3_column_text(stmt, 6); if(!(multi_name && *multi_name)) g_snprintf(iname, sizeof(iname), "%s", sqlite3_column_text(stmt, 2)); else g_snprintf(iname, sizeof(iname), "%s %s", sqlite3_column_text(stmt, 2), multi_name); const unsigned char *op_blob = sqlite3_column_blob(stmt, 4); const int32_t op_len = sqlite3_column_bytes(stmt, 4); const unsigned char *bop_blob = sqlite3_column_blob(stmt, 5); const int32_t bop_len = sqlite3_column_bytes(stmt, 5); item->params = malloc(op_len); memcpy(item->params, op_blob, op_len); item->blendop_params = malloc(bop_len); memcpy(item->blendop_params, bop_blob, bop_len); } else { const char *multi_name = (const char *)sqlite3_column_text(stmt, 5); gboolean has_multi_name = FALSE; if(multi_name && *multi_name && strcmp(multi_name, "0") != 0) has_multi_name = TRUE; if(has_multi_name) g_snprintf(iname, sizeof(iname), "%s %s (%s)", dt_iop_get_localized_name((gchar *)sqlite3_column_text(stmt, 2)), multi_name, (sqlite3_column_int(stmt, 3) != 0) ? _("on") : _("off")); else g_snprintf(iname, sizeof(iname), "%s (%s)", dt_iop_get_localized_name((gchar *)sqlite3_column_text(stmt, 2)), (sqlite3_column_int(stmt, 3) != 0) ? _("on") : _("off")); item->params = NULL; item->blendop_params = NULL; if(imgid != -1 && sqlite3_column_type(stmt, 4) != SQLITE_NULL) item->selimg_num = sqlite3_column_int(stmt, 4); } item->name = g_strdup(iname); result = g_list_append(result, item); } sqlite3_finalize(stmt); } return result; }
void dt_dev_read_history(dt_develop_t *dev) { if(!dev->image_storage.id) return; 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 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 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); 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; while(opname && modules) { dt_iop_module_t *module = (dt_iop_module_t *)modules->data; if(!strcmp(module->op, opname)) { hist->module = module; break; } modules = g_list_next(modules); } if(!hist->module) { 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)); 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); }
static void _dt_style_cleanup_multi_instance(int id) { sqlite3_stmt *stmt; GList *list = NULL; struct _data { int rowid; int mi; }; char last_operation[128] = { 0 }; int last_mi = 0; /* let's clean-up the style multi-instance. What we want to do is have a unique multi_priority value for each iop. Furthermore this value must start to 0 and increment one by one for each multi-instance of the same module. On SQLite there is no notion of ROW_NUMBER, so we use rather resource consuming SQL statement, but as a style has never a huge number of items that's not a real issue. */ /* 1. read all data for the style and record multi_instance value. */ DT_DEBUG_SQLITE3_PREPARE_V2( dt_database_get(darktable.db), "SELECT rowid,operation FROM data.style_items WHERE styleid=?1 ORDER BY operation, multi_priority ASC", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); while(sqlite3_step(stmt) == SQLITE_ROW) { struct _data *d = malloc(sizeof(struct _data)); const char *operation = (const char *)sqlite3_column_text(stmt, 1); if(strncmp(last_operation, operation, 128) != 0) { last_mi = 0; g_strlcpy(last_operation, operation, sizeof(last_operation)); } else last_mi++; d->rowid = sqlite3_column_int(stmt, 0); d->mi = last_mi; list = g_list_append(list, d); } sqlite3_finalize(stmt); /* 2. now update all multi_instance values previously recorded */ list = g_list_first(list); while(list) { struct _data *d = (struct _data *)list->data; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "UPDATE data.style_items SET multi_priority=?1 WHERE rowid=?2", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, d->mi); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, d->rowid); sqlite3_step(stmt); sqlite3_finalize(stmt); list = g_list_next(list); } g_list_free_full(list, free); }
int dt_history_copy_and_paste_on_image (int32_t imgid, int32_t dest_imgid, gboolean merge, GList *ops) { sqlite3_stmt *stmt; if(imgid==dest_imgid) return 1; if(imgid==-1) { dt_control_log(_("you need to copy history from an image before you paste it onto another")); return 1; } /* if merge onto history stack, lets find history offest in destination image */ int32_t offs = 0; if (merge) { /* apply on top of history stack */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT MAX(num)+1 FROM history WHERE imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_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, dest_imgid); sqlite3_step (stmt); } sqlite3_finalize (stmt); // prepare SQL request char req[2048]; strcpy (req, "insert into history (imgid, num, module, operation, op_params, enabled, blendop_params, blendop_version, multi_name, multi_priority) select ?1, num+?2, module, operation, op_params, enabled, blendop_params, blendop_version, multi_name, multi_priority from history where imgid = ?3"); // Add ops selection if any format: ... and num in (val1, val2) if (ops) { GList *l = ops; int first = 1; strcat (req, " and num in ("); while (l) { unsigned int value = GPOINTER_TO_UINT(l->data); char v[30]; if (!first) strcat (req, ","); snprintf (v, 30, "%u", value); strcat (req, v); first=0; l = g_list_next(l); } strcat (req, ")"); } /* add the history items to stack offest */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), req, -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, offs); DT_DEBUG_SQLITE3_BIND_INT(stmt, 3, imgid); sqlite3_step (stmt); sqlite3_finalize (stmt); if (merge && ops) _dt_history_cleanup_multi_instance(dest_imgid, offs); //we have to copy masks too //what to do with existing masks ? if (merge) { //there's very little chance that we will have same shapes id. //but we may want to handle this case anyway //and it's not trivial at all ! } else { //let's remove all existing shapes DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "delete from mask where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); sqlite3_step (stmt); sqlite3_finalize (stmt); } //let's copy now strcpy (req, "insert into mask (imgid, formid, form, name, version, points, points_count, source) select ?1, formid, form, name, version, points, points_count, source from mask where imgid = ?2"); DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), req, -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, dest_imgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); sqlite3_step (stmt); sqlite3_finalize (stmt); /* if current image in develop reload history */ if (dt_dev_is_current_image(darktable.develop, dest_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(dest_imgid); dt_mipmap_cache_remove(darktable.mipmap_cache, dest_imgid); return 0; }
void dt_selection_select_single(dt_selection_t *selection, uint32_t imgid) { selection->last_single_id = imgid; DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "DELETE FROM main.selected_images", NULL, NULL, NULL); dt_selection_select(selection, imgid); }
/* update all values to reflect mouse over image id or no data at all */ static void _metadata_view_update_values(dt_lib_module_t *self) { dt_lib_metadata_view_t *d = (dt_lib_metadata_view_t *)self->data; int32_t mouse_over_id = dt_control_get_mouse_over_id(); if (mouse_over_id == -1) { const dt_view_t *cv = dt_view_manager_get_current_view(darktable.view_manager); if(cv->view((dt_view_t*)cv) == DT_VIEW_DARKROOM) { mouse_over_id = darktable.develop->image_storage.id; } else { sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select imgid from selected_images limit 1", -1, &stmt, NULL); if(sqlite3_step(stmt) == SQLITE_ROW) mouse_over_id = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); } } if(mouse_over_id >= 0) { char value[512]; char pathname[PATH_MAX]; const dt_image_t *img = dt_image_cache_read_get(darktable.image_cache, mouse_over_id); if(!img) goto fill_minuses; if(img->film_id == -1) { dt_image_cache_read_release(darktable.image_cache, img); goto fill_minuses; } /* update all metadata */ dt_image_film_roll(img, value, sizeof(value)); _metadata_update_value(d->metadata[md_internal_filmroll], value); const int tp = 512; char tooltip[tp]; snprintf(tooltip, tp, _("double click to jump to film roll\n%s"), value); g_object_set(G_OBJECT(d->metadata[md_internal_filmroll]), "tooltip-text", tooltip, (char *)NULL); snprintf(value,sizeof(value),"%d", img->id); _metadata_update_value(d->metadata[md_internal_imgid], value); snprintf(value,sizeof(value),"%d", img->group_id); _metadata_update_value(d->metadata[md_internal_groupid], value); _metadata_update_value(d->metadata[md_internal_filename], img->filename); snprintf(value,sizeof(value),"%d", img->version); _metadata_update_value(d->metadata[md_internal_version], value); gboolean from_cache = FALSE; dt_image_full_path(img->id, pathname, sizeof(pathname), &from_cache); _metadata_update_value(d->metadata[md_internal_fullpath], pathname); snprintf(value, sizeof(value), "%s", (img->flags & DT_IMAGE_LOCAL_COPY)?_("yes"):_("no")); _metadata_update_value(d->metadata[md_internal_local_copy], value); // TODO: decide if this should be removed for a release. maybe #ifdef'ing to only add it to git compiles? // the bits of the flags { #define EMPTY_FIELD '.' #define FALSE_FIELD '.' #define TRUE_FIELD '!' char *tooltip = NULL; char *flag_descriptions[] = { N_("unused"), N_("unused/deprecated"), N_("ldr"), N_("raw"), N_("hdr"), N_("marked for deletion"), N_("auto-applying presets applied"), N_("legacy flag. set for all new images"), N_("local copy"), N_("has .txt"), N_("has .wav") }; char *tooltip_parts[13] = { 0 }; int next_tooltip_part = 0; memset(value, EMPTY_FIELD, sizeof(value)); int stars = img->flags & 0x7; char *star_string = NULL; if(stars == 6) { value[0] = 'x'; tooltip_parts[next_tooltip_part++] = _("image rejected"); } else { value[0] = '0' + stars; tooltip_parts[next_tooltip_part++] = star_string = g_strdup_printf(ngettext("image has %d star", "image has %d stars", stars), stars); } if(img->flags & 8) { value[1] = TRUE_FIELD; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[0]); } else value[1] = FALSE_FIELD; if(img->flags & DT_IMAGE_THUMBNAIL_DEPRECATED) { value[2] = TRUE_FIELD; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[1]); } else value[2] = FALSE_FIELD; if(img->flags & DT_IMAGE_LDR) { value[3] = 'l'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[2]); } if(img->flags & DT_IMAGE_RAW) { value[4] = 'r'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[3]); } if(img->flags & DT_IMAGE_HDR) { value[5] = 'h'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[4]); } if(img->flags & DT_IMAGE_REMOVE) { value[6] = 'd'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[5]); } if(img->flags & DT_IMAGE_AUTO_PRESETS_APPLIED) { value[7] = 'a'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[6]); } if(img->flags & DT_IMAGE_NO_LEGACY_PRESETS) { value[8] = 'p'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[7]); } if(img->flags & DT_IMAGE_LOCAL_COPY) { value[9] = 'c'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[8]); } if(img->flags & DT_IMAGE_HAS_TXT) { value[10] = 't'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[9]); } if(img->flags & DT_IMAGE_HAS_WAV) { value[11] = 'w'; tooltip_parts[next_tooltip_part++] = _(flag_descriptions[10]); } value[12] = '\0'; tooltip = g_strjoinv("\n", tooltip_parts); _metadata_update_value(d->metadata[md_internal_flags], value); g_object_set(G_OBJECT(d->metadata[md_internal_flags]), "tooltip-text", tooltip, (char *)NULL); g_free(star_string); g_free(tooltip); #undef EMPTY_FIELD #undef FALSE_FIELD #undef TRUE_FIELD } /* EXIF */ _metadata_update_value_end(d->metadata[md_exif_model], img->exif_model); _metadata_update_value_end(d->metadata[md_exif_lens], img->exif_lens); _metadata_update_value_end(d->metadata[md_exif_maker], img->exif_maker); snprintf(value, sizeof(value), "F/%.1f", img->exif_aperture); _metadata_update_value(d->metadata[md_exif_aperture], value); if(img->exif_exposure <= 0.5) snprintf(value, sizeof(value), "1/%.0f", 1.0/img->exif_exposure); else snprintf(value, sizeof(value), "%.1f''", img->exif_exposure); _metadata_update_value(d->metadata[md_exif_exposure], value); snprintf(value, sizeof(value), "%.0f mm", img->exif_focal_length); _metadata_update_value(d->metadata[md_exif_focal_length], value); if (isnan(img->exif_focus_distance) || fpclassify(img->exif_focus_distance) == FP_ZERO) { _metadata_update_value(d->metadata[md_exif_focus_distance], NODATA_STRING); } else { snprintf(value, sizeof(value), "%.2f m", img->exif_focus_distance); _metadata_update_value(d->metadata[md_exif_focus_distance], value); } snprintf(value, sizeof(value), "%.0f", img->exif_iso); _metadata_update_value(d->metadata[md_exif_iso], value); _metadata_update_value(d->metadata[md_exif_datetime], img->exif_datetime_taken); snprintf(value, sizeof(value), "%d", img->height); _metadata_update_value(d->metadata[md_exif_height], value); snprintf(value, sizeof(value), "%d", img->width); _metadata_update_value(d->metadata[md_exif_width], value); /* XMP */ GList *res; if((res = dt_metadata_get(img->id, "Xmp.dc.title", NULL))!=NULL) { snprintf(value, sizeof(value), "%s", (char*)res->data); _filter_non_printable(value, sizeof(value)); g_list_free_full(res, &g_free); } else snprintf(value, sizeof(value), NODATA_STRING); _metadata_update_value(d->metadata[md_xmp_title], value); if((res = dt_metadata_get(img->id, "Xmp.dc.creator", NULL))!=NULL) { snprintf(value, sizeof(value), "%s", (char*)res->data); _filter_non_printable(value, sizeof(value)); g_list_free_full(res, &g_free); } else snprintf(value, sizeof(value), NODATA_STRING); _metadata_update_value(d->metadata[md_xmp_creator], value); if((res = dt_metadata_get(img->id, "Xmp.dc.rights", NULL))!=NULL) { snprintf(value, sizeof(value), "%s", (char*)res->data); _filter_non_printable(value, sizeof(value)); g_list_free_full(res, &g_free); } else snprintf(value, sizeof(value), NODATA_STRING); _metadata_update_value(d->metadata[md_xmp_rights], value); /* geotagging */ /* latitude */ if(isnan(img->latitude)) { _metadata_update_value(d->metadata[md_geotagging_lat], NODATA_STRING); } else { #ifdef HAVE_MAP if(dt_conf_get_bool("plugins/lighttable/metadata_view/pretty_location")) { gchar *latitude = osd_latitude_str(img->latitude); _metadata_update_value(d->metadata[md_geotagging_lat], latitude); g_free(latitude); } else { #endif gchar NS = img->latitude<0?'S':'N'; snprintf(value, sizeof(value), "%c %09.6f", NS, fabs(img->latitude)); _metadata_update_value(d->metadata[md_geotagging_lat], value); #ifdef HAVE_MAP } #endif } /* longitude */ if(isnan(img->longitude)) { _metadata_update_value(d->metadata[md_geotagging_lon], NODATA_STRING); } else { #ifdef HAVE_MAP if(dt_conf_get_bool("plugins/lighttable/metadata_view/pretty_location")) { gchar *longitude = osd_longitude_str(img->longitude); _metadata_update_value(d->metadata[md_geotagging_lon], longitude); g_free(longitude); } else { #endif gchar EW = img->longitude<0?'W':'E'; snprintf(value, sizeof(value), "%c %010.6f", EW, fabs(img->longitude)); _metadata_update_value(d->metadata[md_geotagging_lon], value); #ifdef HAVE_MAP } #endif } /* release img */ dt_image_cache_read_release(darktable.image_cache, img); } return; /* reset */ fill_minuses: for(int k=0; k<md_size; k++) _metadata_update_value(d->metadata[k],NODATA_STRING); }
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); gtk_widget_set_hexpand(frame, TRUE); GtkWidget *event_box = gtk_event_box_new(); gtk_widget_set_margin_start(event_box, DT_PIXEL_APPLY_DPI(8)); gtk_widget_set_margin_end(event_box, DT_PIXEL_APPLY_DPI(8)); gtk_widget_set_margin_top(event_box, DT_PIXEL_APPLY_DPI(8)); gtk_widget_set_margin_bottom(event_box, DT_PIXEL_APPLY_DPI(8)); gtk_container_add(GTK_CONTAINER(frame), event_box); gtk_container_add(GTK_CONTAINER(event_box), expander); GtkWidget *extra; extra = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_container_add(GTK_CONTAINER(expander), extra); gtk_widget_set_margin_start(extra, DT_PIXEL_APPLY_DPI(8)); gtk_widget_set_margin_end(extra, DT_PIXEL_APPLY_DPI(8)); gtk_widget_set_margin_top(extra, DT_PIXEL_APPLY_DPI(8)); gtk_widget_set_margin_bottom(extra, DT_PIXEL_APPLY_DPI(8)); 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 *grid, *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); g_value_unset(&value); grid = gtk_grid_new(); gtk_grid_set_row_spacing(GTK_GRID(grid), DT_PIXEL_APPLY_DPI(5)); gtk_grid_set_column_spacing(GTK_GRID(grid), DT_PIXEL_APPLY_DPI(10)); gtk_widget_set_margin_start(grid, 2 * (indicator_spacing + indicator_size)); gtk_box_pack_start(GTK_BOX(extra), grid, FALSE, FALSE, 0); creator = gtk_entry_new(); gtk_widget_set_size_request(creator, DT_PIXEL_APPLY_DPI(300), -1); gchar *str = dt_conf_get_string("ui_last/import_last_creator"); gtk_entry_set_text(GTK_ENTRY(creator), str); g_free(str); publisher = gtk_entry_new(); str = dt_conf_get_string("ui_last/import_last_publisher"); gtk_entry_set_text(GTK_ENTRY(publisher), str); g_free(str); rights = gtk_entry_new(); str = dt_conf_get_string("ui_last/import_last_rights"); gtk_entry_set_text(GTK_ENTRY(rights), str); g_free(str); tags = gtk_entry_new(); str = dt_conf_get_string("ui_last/import_last_tags"); g_object_set(tags, "tooltip-text", _("comma separated list of tags"), NULL); gtk_entry_set_text(GTK_ENTRY(tags), str); g_free(str); // 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_widget_set_halign(label, GTK_ALIGN_START); gtk_grid_attach(GTK_GRID(grid), label, 0, line++, 1, 1); gtk_grid_attach_next_to(GTK_GRID(grid), presets, label, GTK_POS_RIGHT, 1, 1); label = gtk_label_new(_("creator")); gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_grid_attach(GTK_GRID(grid), label, 0, line++, 1, 1); gtk_grid_attach_next_to(GTK_GRID(grid), creator, label, GTK_POS_RIGHT, 1, 1); label = gtk_label_new(_("publisher")); gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_grid_attach(GTK_GRID(grid), label, 0, line++, 1, 1); gtk_grid_attach_next_to(GTK_GRID(grid), publisher, label, GTK_POS_RIGHT, 1, 1); label = gtk_label_new(_("rights")); gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_grid_attach(GTK_GRID(grid), label, 0, line++, 1, 1); gtk_grid_attach_next_to(GTK_GRID(grid), rights, label, GTK_POS_RIGHT, 1, 1); label = gtk_label_new(_("tags")); gtk_widget_set_halign(label, GTK_ALIGN_START); gtk_grid_attach(GTK_GRID(grid), label, 0, line, 1, 1); gtk_grid_attach_next_to(GTK_GRID(grid), tags, label, GTK_POS_RIGHT, 1, 1); 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), grid); // needed since the apply_metadata starts being turned off, and setting it to off doesn't emit the 'toggled' signal ... _lib_import_apply_metadata_toggled(apply_metadata, grid); 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; }
} gboolean dt_tag_new_from_gui(const char *name, guint *tagid) { gboolean ret = dt_tag_new(name, tagid); /* if everything went fine, raise signal of tags change to refresh keywords module in GUI */ if(ret) dt_control_signal_raise(darktable.signals, DT_SIGNAL_TAG_CHANGED); return ret; } guint dt_tag_remove(const guint tagid, gboolean final) { int rv, count = -1; sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT COUNT(*) FROM main.tagged_images WHERE tagid=?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, tagid); rv = sqlite3_step(stmt); if(rv == SQLITE_ROW) count = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); if(final == TRUE) { // let's actually remove the tag DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM data.tags WHERE id=?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, tagid); sqlite3_step(stmt); sqlite3_finalize(stmt);
void dt_colorlabels_remove_labels_selection () { DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "delete from color_labels where imgid in (select imgid from selected_images)", NULL, NULL, NULL); }
GList * dt_styles_get_item_list (const char *name, gboolean params, int imgid) { GList *result=NULL; sqlite3_stmt *stmt; int id=0; if ((id=dt_styles_get_id_by_name(name)) != 0) { if (params) DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select num, operation, enabled, op_params, blendop_params, multi_name from style_items where styleid=?1 order by num desc", -1, &stmt, NULL); else if (imgid != -1) { // get all items from the style // UNION // get all items from history, not in the style : select only the last operation, that is max(num) DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select num, operation, enabled, (select max(num) from history where imgid=?2 and operation=style_items.operation group by multi_priority),multi_name from style_items where styleid=?1 UNION select -1,history.operation,history.enabled,history.num,multi_name from history where imgid=?2 and history.enabled=1 and (history.operation not in (select operation from style_items where styleid=?1) or (history.op_params not in (select op_params from style_items where styleid=?1 and operation=history.operation)) or (history.blendop_params not in (select blendop_params from style_items where styleid=?1 and operation=history.operation))) group by operation having max(num) order by num desc", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, imgid); } else DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select num, operation, enabled, 0, multi_name from style_items where styleid=?1 order by num desc", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); while (sqlite3_step(stmt) == SQLITE_ROW) { char name[512]= {0}; dt_style_item_t *item=g_malloc (sizeof (dt_style_item_t)); if (sqlite3_column_type(stmt,0)==SQLITE_NULL) item->num = -1; else item->num = sqlite3_column_int (stmt, 0); item->selimg_num = -1; if (params) { // when we get the parameters we do not want to get the operation localized as this // is used to compare against the internal module name. const char *multi_name = (const char *)sqlite3_column_text (stmt, 5); if (!multi_name || strlen(multi_name)) g_snprintf(name,512,"%s",sqlite3_column_text (stmt, 1)); else g_snprintf(name,512,"%s %s",sqlite3_column_text (stmt, 1), multi_name); const unsigned char *op_blob = sqlite3_column_blob(stmt, 3); const int32_t op_len = sqlite3_column_bytes(stmt, 3); const unsigned char *bop_blob = sqlite3_column_blob(stmt, 4); const int32_t bop_len = sqlite3_column_bytes(stmt, 4); item->params = malloc(op_len); memcpy(item->params, op_blob, op_len); item->blendop_params = malloc(bop_len); memcpy(item->blendop_params, bop_blob, bop_len); } else { const char *multi_name = (const char *)sqlite3_column_text (stmt, 4); gboolean has_multi_name = FALSE; if (multi_name && strlen(multi_name)>0 && strcmp(multi_name,"0")!=0) has_multi_name = TRUE; if (has_multi_name) g_snprintf(name,512,"%s %s (%s)",dt_iop_get_localized_name((gchar *)sqlite3_column_text (stmt, 1)),multi_name,(sqlite3_column_int (stmt, 2)!=0)?_("on"):_("off")); else g_snprintf(name,512,"%s (%s)",dt_iop_get_localized_name((gchar *)sqlite3_column_text (stmt, 1)),(sqlite3_column_int (stmt, 2)!=0)?_("on"):_("off")); item->params = NULL; item->blendop_params = NULL; if (imgid != -1 && sqlite3_column_type(stmt,4)!=SQLITE_NULL) item->selimg_num = sqlite3_column_int (stmt, 4); } item->name = g_strdup (name); result = g_list_append (result,item); } sqlite3_finalize(stmt); } return result; }
static void _lib_filmstrip_dnd_begin_callback(GtkWidget *widget, GdkDragContext *context, gpointer user_data) { const int ts = 64; dt_lib_module_t *self = (dt_lib_module_t *)user_data; dt_lib_filmstrip_t *strip = (dt_lib_filmstrip_t *)self->data; int imgid = strip->mouse_over_id; // imgid part of selection -> do nothing // otherwise -> select the current image strip->select = DT_LIB_FILMSTRIP_SELECT_NONE; sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select imgid from selected_images where imgid=?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); if(sqlite3_step(stmt) != SQLITE_ROW) { dt_selection_select_single(darktable.selection, imgid); /* redraw filmstrip */ if(darktable.view_manager->proxy.filmstrip.module) gtk_widget_queue_draw(darktable.view_manager->proxy.filmstrip.module->widget); } sqlite3_finalize(stmt); // if we are dragging a single image -> use the thumbnail of that image // otherwise use the generic d&d icon // TODO: have something pretty in the 2nd case, too. if(dt_collection_get_selected_count(NULL) == 1) { dt_mipmap_buffer_t buf; dt_mipmap_size_t mip = dt_mipmap_cache_get_matching_size(darktable.mipmap_cache, ts, ts); dt_mipmap_cache_read_get(darktable.mipmap_cache, &buf, imgid, mip, DT_MIPMAP_BLOCKING); if(buf.buf) { uint8_t *scratchmem = dt_mipmap_cache_alloc_scratchmem(darktable.mipmap_cache); uint8_t *buf_decompressed = dt_mipmap_cache_decompress(&buf, scratchmem); uint8_t *rgbbuf = g_malloc((buf.width+2)*(buf.height+2)*3); memset(rgbbuf, 64, (buf.width+2)*(buf.height+2)*3); for(int i=1; i<=buf.height; i++) for(int j=1; j<=buf.width; j++) for(int k=0; k<3; k++) rgbbuf[(i*(buf.width+2)+j)*3+k] = buf_decompressed[((i-1)*buf.width+j-1)*4+2-k]; int w=ts, h=ts; if(buf.width < buf.height) w = (buf.width*ts)/buf.height; // portrait else h = (buf.height*ts)/buf.width; // landscape GdkPixbuf *source = gdk_pixbuf_new_from_data(rgbbuf, GDK_COLORSPACE_RGB, FALSE, 8, (buf.width+2), (buf.height+2), (buf.width+2)*3, NULL, NULL); GdkPixbuf *scaled = gdk_pixbuf_scale_simple(source, w, h, GDK_INTERP_HYPER); gtk_drag_set_icon_pixbuf(context, scaled, 0, 0); if(source) g_object_unref(source); if(scaled) g_object_unref(scaled); free(scratchmem); g_free(rgbbuf); } dt_mipmap_cache_read_release(darktable.mipmap_cache, &buf); } }
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, sizeof(confname), "plugins/lighttable/collect/item%1d", i); const int property = dt_conf_get_int(confname); snprintf(confname, sizeof(confname), "plugins/lighttable/collect/string%1d", i); gchar *text = dt_conf_get_string(confname); if(!text) break; snprintf(confname, sizeof(confname), "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, sizeof(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); }
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; GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); int32_t width = allocation.width; int32_t height = 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(gtk_widget_get_window(widget)); /* 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; int max_cols = (int)(width/(float)wd) + 2; if (max_cols%2 == 0) max_cols += 1; const int col_start = max_cols/2 - strip->offset; const int empty_edge = (width - (max_cols * wd))/2; int step_res = SQLITE_ROW; sqlite3_stmt *stmt = NULL; /* mouse over image position in filmstrip */ pointerx -= empty_edge; 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; /* get the count of current collection */ strip->collection_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 > strip->collection_count-1) strip->offset = offset = strip->collection_count-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 - max_cols/2); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, max_cols); cairo_save(cr); cairo_translate(cr, empty_edge, 0.0f); for(int col = 0; col < max_cols; col++) { if(col < col_start) { cairo_translate(cr, wd, 0.0f); continue; } if(step_res != SQLITE_DONE) { step_res = sqlite3_step(stmt); } if(step_res == 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, FALSE); cairo_restore(cr); } else if (step_res == SQLITE_DONE) { /* do nothing, just add some empty thumb frames */ } 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; }
cmsHPROFILE dt_colorspaces_create_output_profile(const int imgid) { char profile[1024]; profile[0] = '\0'; // db lookup colorout params, and dt_conf_() for override gchar *overprofile = dt_conf_get_string("plugins/lighttable/export/iccprofile"); if(!overprofile || !strcmp(overprofile, "image")) { const dt_iop_colorout_params_t *params; // sqlite: sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select op_params from history where imgid=?1 and operation='colorout'", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); if(sqlite3_step(stmt) == SQLITE_ROW) { params = sqlite3_column_blob(stmt, 0); g_strlcpy(profile, params->iccprofile, 1024); } sqlite3_finalize(stmt); } if(!overprofile && profile[0] == '\0') { g_strlcpy(profile, "sRGB", 1024); } else if(profile[0] == '\0') { g_strlcpy(profile, overprofile, 1024); } if(overprofile) { g_free(overprofile); } cmsHPROFILE output = NULL; if(!strcmp(profile, "sRGB")) output = dt_colorspaces_create_srgb_profile(); else if(!strcmp(profile, "linear_rgb")) output = dt_colorspaces_create_linear_rgb_profile(); else if(!strcmp(profile, "XYZ")) output = dt_colorspaces_create_xyz_profile(); else if(!strcmp(profile, "adobergb")) output = dt_colorspaces_create_adobergb_profile(); else if(!strcmp(profile, "X profile")) { pthread_rwlock_rdlock(&darktable.control->xprofile_lock); if(darktable.control->xprofile_data) output = cmsOpenProfileFromMem(darktable.control->xprofile_data, darktable.control->xprofile_size); pthread_rwlock_unlock(&darktable.control->xprofile_lock); } else { // else: load file name char filename[DT_MAX_PATH_LEN]; dt_colorspaces_find_profile(filename, DT_MAX_PATH_LEN, profile, "out"); output = cmsOpenProfileFromFile(filename, "r"); } if(!output) output = dt_colorspaces_create_srgb_profile(); return output; }
static void _lib_geotagging_calculate_offset_callback(GtkWidget *widget, dt_lib_module_t *self) { dt_lib_geotagging_t *d = (dt_lib_geotagging_t *)self->data; const gchar *gps_time = gtk_entry_get_text(GTK_ENTRY(d->floating_window_entry)); if(gps_time) { gchar **tokens = g_strsplit(gps_time, ":", 0); if(tokens[0] != '\0' && tokens[1] != '\0' && tokens[2] != '\0') { if(g_ascii_isdigit(tokens[0][0]) && g_ascii_isdigit(tokens[0][1]) && tokens[0][2] == '\0' && g_ascii_isdigit(tokens[1][0]) && g_ascii_isdigit(tokens[1][1]) && tokens[1][2] == '\0' && g_ascii_isdigit(tokens[2][0]) && g_ascii_isdigit(tokens[2][1]) && tokens[2][2] == '\0') { int h, m, s; h = (tokens[0][0] - '0') * 10 + tokens[0][1] - '0'; m = (tokens[1][0] - '0') * 10 + tokens[1][1] - '0'; s = (tokens[2][0] - '0') * 10 + tokens[2][1] - '0'; if(h < 24 && m < 60 && s < 60) { // finally a valid time // get imgid int32_t imgid = -1; sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select imgid from selected_images order by imgid asc limit 1", -1, &stmt, NULL); if(sqlite3_step(stmt) == SQLITE_ROW) imgid = sqlite3_column_int(stmt, 0); else // no selection is used, use mouse over id imgid = dt_control_get_mouse_over_id(); sqlite3_finalize(stmt); if(imgid > 0) { const dt_image_t *cimg = dt_image_cache_get(darktable.image_cache, imgid, 'r'); // get the exif_datetime_taken and parse it gint year; gint month; gint day; gint hour; gint minute; gint second; if(sscanf(cimg->exif_datetime_taken, "%d:%d:%d %d:%d:%d", (int *)&year, (int *)&month, (int *)&day, (int *)&hour, (int *)&minute, (int *)&second) == 6) { // calculate the offset long int exif_seconds = hour * 60 * 60 + minute * 60 + second; long int gps_seconds = h * 60 * 60 + m * 60 + s; long int offset = gps_seconds - exif_seconds; // transform the offset back into a string gchar sign = (offset < 0) ? '-' : '+'; offset = labs(offset); gint offset_h = offset / (60 * 60); offset -= offset_h * 60 * 60; gint offset_m = offset / 60; offset -= offset_m * 60; gchar *offset_str = g_strdup_printf("%c%02d:%02d:%02ld", sign, offset_h, offset_m, offset); // write the offset into d->offset_entry gtk_entry_set_text(GTK_ENTRY(d->offset_entry), offset_str); g_free(offset_str); } dt_image_cache_read_release(darktable.image_cache, cimg); } } } } g_strfreev(tokens); } gtk_widget_destroy(d->floating_window); }
static int generate_thumbnail_cache(const dt_mipmap_size_t max_mip) { fprintf(stderr, _("creating cache directories\n")); for(dt_mipmap_size_t k = DT_MIPMAP_0; k <= max_mip; k++) { char dirname[PATH_MAX] = { 0 }; snprintf(dirname, sizeof(dirname), "%s.d/%d", darktable.mipmap_cache->cachedir, k); fprintf(stderr, _("creating cache directory '%s'\n"), dirname); if(g_mkdir_with_parents(dirname, 0750)) { fprintf(stderr, _("could not create directory '%s'!\n"), dirname); return 1; } } // some progress counter sqlite3_stmt *stmt; size_t image_count = 0, counter = 0; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select count(id) from images", -1, &stmt, 0); if(sqlite3_step(stmt) == SQLITE_ROW) { image_count = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); } else { return 1; } // go through all images: DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select id from images", -1, &stmt, 0); while(sqlite3_step(stmt) == SQLITE_ROW) { const uint32_t imgid = sqlite3_column_int(stmt, 0); for(int k = max_mip; k >= DT_MIPMAP_0; k--) { char filename[PATH_MAX] = { 0 }; snprintf(filename, sizeof(filename), "%s.d/%d/%d.jpg", darktable.mipmap_cache->cachedir, k, imgid); // if the thumbnail is already on disc - do nothing if(!access(filename, R_OK)) continue; // else, generate thumbnail and store in mipmap cache. dt_mipmap_buffer_t buf; dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, k, DT_MIPMAP_BLOCKING, 'r'); dt_mipmap_cache_release(darktable.mipmap_cache, &buf); } // and immediately write thumbs to disc and remove from mipmap cache. dt_mimap_cache_evict(darktable.mipmap_cache, imgid); counter++; fprintf(stderr, "image %zu/%zu (%.02f%%)\n", counter, image_count, 100.0 * counter / (float)image_count); } sqlite3_finalize(stmt); fprintf(stderr, "done\n"); return 0; }
void dt_styles_update(const char *name, const char *newname, const char *newdescription, GList *filter, int imgid, GList *update) { 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 data.styles SET name=?1, description=?2 WHERE id=?3", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 1, newname, -1, SQLITE_STATIC); DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 2, newdescription, -1, 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 (", sizeof(include)); do { if(list != g_list_first(list)) g_strlcat(include, ",", sizeof(include)); snprintf(tmp, sizeof(tmp), "%d", GPOINTER_TO_INT(list->data)); g_strlcat(include, tmp, sizeof(include)); } while((list = g_list_next(list))); g_strlcat(include, ")", sizeof(include)); char query[4096] = { 0 }; snprintf(query, sizeof(query), "DELETE FROM data.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); } _dt_style_update_from_image(id, imgid, filter, update); _dt_style_cleanup_multi_instance(id); /* backup style to disk */ char stylesdir[PATH_MAX] = { 0 }; dt_loc_get_user_config_dir(stylesdir, sizeof(stylesdir)); g_strlcat(stylesdir, "/styles", sizeof(stylesdir)); g_mkdir_with_parents(stylesdir, 00755); dt_styles_save_to_file(newname, stylesdir, TRUE); /* delete old accelerator and create a new one */ // TODO: should 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, sizeof(tmp_accel), C_("accel", "styles/apply %s"), name); dt_accel_deregister_global(tmp_accel); gchar *tmp_name = g_strdup(newname); // freed by _destroy_style_shortcut_callback snprintf(tmp_accel, sizeof(tmp_accel), C_("accel", "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_signal_raise(darktable.signals, DT_SIGNAL_STYLE_CHANGED); g_free(desc); }
/* Dear Mister Dijkstra, I hereby make a formal apology for using goto statements in the following function. While I am fully aware that I will rot in the deepest hells for this ultimate sin and that I'm not worth to be called a "programmer" from now on, I have one excuse to bring up: I never did so before, and this way the code gets a lot smaller and less repetitive. And since you are dead while I am not (yet) I will stick with my gotos. See you in hell houz */ static GList *dt_metadata_get_exif(int id, const char *key, uint32_t *count) { GList *result = NULL; sqlite3_stmt *stmt; uint32_t local_count = 0; // the doubles if(strncmp(key, "Exif.Photo.ExposureTime", 23) == 0) { if(id == -1) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select exposure from images where id in " "(select imgid from selected_images)", -1, &stmt, NULL); } else // single image under mouse cursor { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select exposure from images where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); } } else if(strncmp(key, "Exif.Photo.ApertureValue", 24) == 0) { if(id == -1) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select aperture from images where id in " "(select imgid from selected_images)", -1, &stmt, NULL); } else // single image under mouse cursor { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select aperture from images where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); } } else if(strncmp(key, "Exif.Photo.ISOSpeedRatings", 26) == 0) { if(id == -1) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select iso from images where id in (select imgid from selected_images)", -1, &stmt, NULL); } else // single image under mouse cursor { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select iso from images where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); } } else if(strncmp(key, "Exif.Photo.FocalLength", 22) == 0) { if(id == -1) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select focal_length from images where id in " "(select imgid from selected_images)", -1, &stmt, NULL); } else // single image under mouse cursor { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select focal_length from images where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); } } else { // the strings if(strncmp(key, "Exif.Photo.DateTimeOriginal", 27) == 0) { if(id == -1) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select datetime_taken from images where id in " "(select imgid from selected_images)", -1, &stmt, NULL); } else // single image under mouse cursor { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select datetime_taken from images where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); } } else if(strncmp(key, "Exif.Image.Make", 15) == 0) { if(id == -1) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select maker from images where id in " "(select imgid from selected_images)", -1, &stmt, NULL); } else // single image under mouse cursor { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select maker from images where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); } } else if(strncmp(key, "Exif.Image.Model", 16) == 0) { if(id == -1) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select model from images where id in " "(select imgid from selected_images)", -1, &stmt, NULL); } else // single image under mouse cursor { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select model from images where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); } } else { goto END; } while(sqlite3_step(stmt) == SQLITE_ROW) { local_count++; result = g_list_append(result, g_strdup((char *)sqlite3_column_text(stmt, 0))); } sqlite3_finalize(stmt); goto END; } // the double queries while(sqlite3_step(stmt) == SQLITE_ROW) { local_count++; double *tmp = (double *)malloc(sizeof(double)); *tmp = sqlite3_column_double(stmt, 0); result = g_list_append(result, tmp); } sqlite3_finalize(stmt); END: if(count != NULL) *count = local_count; return result; }
void dt_styles_apply_to_image(const char *name, gboolean duplicate, int32_t imgid) { int id = 0; sqlite3_stmt *stmt; int32_t newimgid; if((id = dt_styles_get_id_by_name(name)) != 0) { /* check if we should make a duplicate before applying style */ if(duplicate) { newimgid = dt_image_duplicate(imgid); if(newimgid != -1) dt_history_copy_and_paste_on_image(imgid, newimgid, FALSE, NULL); } else newimgid = imgid; /* merge onto history stack, let's find history offest in destination image */ /* first trim the stack to get rid of whatever is above the selected entry */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "DELETE FROM main.history WHERE imgid = ?1 AND num >= (SELECT history_end " "FROM main.images WHERE id = imgid)", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newimgid); sqlite3_step(stmt); sqlite3_finalize(stmt); /* in sqlite ROWID starts at 1, while our num column starts at 0 */ int32_t offs = -1; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT IFNULL(MAX(num), -1) FROM main.history WHERE imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newimgid); if(sqlite3_step(stmt) == SQLITE_ROW) offs = sqlite3_column_int(stmt, 0); sqlite3_finalize(stmt); /* delete all items from the temp styles_items, this table is used only to get a ROWNUM of the results */ DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "DELETE FROM memory.style_items", NULL, NULL, NULL); /* copy history items from styles onto temp table */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "INSERT INTO memory.style_items SELECT * FROM " "data.style_items WHERE styleid=?1 ORDER BY " "multi_priority DESC", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); sqlite3_step(stmt); sqlite3_finalize(stmt); /* copy the style items into the history */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "INSERT INTO main.history " "(imgid,num,module,operation,op_params,enabled,blendop_params,blendop_" "version,multi_priority,multi_name) SELECT " "?1,?2+rowid,module,operation,op_params,enabled,blendop_params,blendop_" "version,multi_priority,multi_name FROM memory.style_items", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newimgid); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, offs); sqlite3_step(stmt); sqlite3_finalize(stmt); /* always make the whole stack active */ DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "UPDATE main.images SET history_end = (SELECT MAX(num) + 1 FROM main.history " "WHERE imgid = ?1) WHERE id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, newimgid); sqlite3_step(stmt); sqlite3_finalize(stmt); /* add tag */ guint tagid = 0; gchar ntag[512] = { 0 }; g_snprintf(ntag, sizeof(ntag), "darktable|style|%s", name); if(dt_tag_new(ntag, &tagid)) dt_tag_attach(tagid, newimgid); if(dt_tag_new("darktable|changed", &tagid)) dt_tag_attach(tagid, newimgid); /* if current image in develop reload history */ if(dt_dev_is_current_image(darktable.develop, newimgid)) { 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(newimgid); /* remove old obsolete thumbnails */ dt_mipmap_cache_remove(darktable.mipmap_cache, newimgid); /* if we have created a duplicate, reset collected images */ if(duplicate) dt_control_signal_raise(darktable.signals, DT_SIGNAL_COLLECTION_CHANGED); /* redraw center view to update visible mipmaps */ dt_control_queue_redraw_center(); } }
static GList *dt_metadata_get_xmp(int id, const char *key, uint32_t *count) { GList *result = NULL; sqlite3_stmt *stmt; uint32_t local_count = 0; int keyid = dt_metadata_get_keyid(key); // key not found in db. Maybe it's one of our "special" keys (rating, tags and colorlabels)? if(keyid == -1) { if(strncmp(key, "Xmp.xmp.Rating", 14) == 0) { if(id == -1) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select flags from images where id in " "(select imgid from selected_images)", -1, &stmt, NULL); } else // single image under mouse cursor { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select flags from images where id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); } while(sqlite3_step(stmt) == SQLITE_ROW) { local_count++; int stars = sqlite3_column_int(stmt, 0); stars = (stars & 0x7) - 1; result = g_list_append(result, GINT_TO_POINTER(stars)); } sqlite3_finalize(stmt); } else if(strncmp(key, "Xmp.dc.subject", 14) == 0) { if(id == -1) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select name from tags join tagged_images on " "tagged_images.tagid = tags.id where imgid in " "(select imgid from selected_images)", -1, &stmt, NULL); } else // single image under mouse cursor { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select name from tags join tagged_images on " "tagged_images.tagid = tags.id where imgid = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); } while(sqlite3_step(stmt) == SQLITE_ROW) { local_count++; result = g_list_append(result, g_strdup((char *)sqlite3_column_text(stmt, 0))); } sqlite3_finalize(stmt); } else if(strncmp(key, "Xmp.darktable.colorlabels", 25) == 0) { if(id == -1) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select color from color_labels where imgid in " "(select imgid from selected_images)", -1, &stmt, NULL); } else // single image under mouse cursor { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select color from color_labels where imgid=?1 order by color", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); } while(sqlite3_step(stmt) == SQLITE_ROW) { local_count++; result = g_list_append(result, GINT_TO_POINTER(sqlite3_column_int(stmt, 0))); } sqlite3_finalize(stmt); } if(count != NULL) *count = local_count; return result; } // So we got this far -- it has to be a generic key-value entry from meta_data if(id == -1) { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select value from meta_data where id in " "(select imgid from selected_images) and key = ?1 order by value", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, keyid); } else // single image under mouse cursor { DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "select value from meta_data where id = ?1 and key = ?2 order by value", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, id); DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, keyid); } while(sqlite3_step(stmt) == SQLITE_ROW) { local_count++; result = g_list_append(result, g_strdup((char *)sqlite3_column_text(stmt, 0))); } sqlite3_finalize(stmt); if(count != NULL) *count = local_count; return result; }
void dt_styles_save_to_file(const char *style_name, const char *filedir, gboolean overwrite) { int rc = 0; char stylename[520]; sqlite3_stmt *stmt; // generate filename based on name of style // convert all characters to underscore which are not allowed in filenames char *filename = g_strdup(style_name); snprintf(stylename, sizeof(stylename), "%s/%s.dtstyle", filedir, g_strdelimit(filename, "/<>:\"\\|*?[]", '_')); g_free(filename); // 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, "UTF-8", 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 data.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); }
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); }
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 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); }
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; if(multi_name && strcmp(module->multi_name, multi_name)) snprintf(module->multi_name, 128, "%s", multi_name); 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; } if(hist->module->flags() & IOP_FLAGS_NO_HISTORY_STACK) { 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; 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)); } 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); } // make sure that always-on modules are always on. duh. if(hist->module->default_enabled == 1 && hist->module->hide_enable_button == 1) { hist->enabled = 1; } // 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); }
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(); dt_control_queue_redraw_center(); return 0; }
void dt_styles_update (const char *name, const char *newname, const char *newdescription, GList *filter, int imgid, GList *update) { 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", (glong)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); } _dt_style_update_from_image(id,imgid,filter,update); _dt_style_cleanup_multi_instance(id); /* 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: should 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, C_("accel", "styles/apply %s"), name); dt_accel_deregister_global(tmp_accel); gchar* tmp_name = g_strdup(newname); // freed by _destroy_style_shortcut_callback snprintf(tmp_accel, 1024, C_("accel", "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); }