📄 dupe.c
字号:
} if (mask & DUPE_MATCH_SUM) { if (!a->md5sum) a->md5sum = md5_text_from_file_utf8(a->path, ""); if (!b->md5sum) b->md5sum = md5_text_from_file_utf8(b->path, ""); if (a->md5sum[0] == '\0' || b->md5sum[0] == '\0' || strcmp(a->md5sum, b->md5sum) != 0) return FALSE; } if (mask & DUPE_MATCH_DIM) { if (a->width == 0) image_load_dimensions(a->path, &a->width, &a->height); if (b->width == 0) image_load_dimensions(b->path, &b->width, &b->height); if (a->width != b->width || a->height != b->height) return FALSE; } if (mask & DUPE_MATCH_SIM_HIGH || mask & DUPE_MATCH_SIM_MED || mask & DUPE_MATCH_SIM_LOW || mask & DUPE_MATCH_SIM_CUSTOM) { gdouble f; gdouble m; if (mask & DUPE_MATCH_SIM_HIGH) m = 0.95; else if (mask & DUPE_MATCH_SIM_MED) m = 0.90; else if (mask & DUPE_MATCH_SIM_CUSTOM) m = (gdouble)dupe_custom_threshold / 100.0; else m = 0.85; if (fast) { f = image_sim_compare_fast(a->simd, b->simd, m); } else { f = image_sim_compare(a->simd, b->simd); } *rank = f * 100.0; if (f < m) return FALSE; if (debug > 2) printf("similar: %32s %32s = %f\n", a->name, b->name, f); } return TRUE;}static void dupe_list_check_match(DupeWindow *dw, DupeItem *needle, GList *start){ GList *work; if (dw->second_set) { work = dw->second_list; } else if (start) { work = start; } else { work = g_list_last(dw->list); } while (work) { DupeItem *di = work->data; /* speed opt: forward for second set, back for simple compare */ if (dw->second_set) work = work->next; else work = work->prev; if (!dupe_match_link_exists(needle, di)) { gdouble rank; if (dupe_match(di, needle, dw->match_mask, &rank, TRUE)) { dupe_match_link(di, needle, rank); } } }}/* * ------------------------------------------------------------------ * Thumbnail handling * ------------------------------------------------------------------ */static void dupe_listview_set_thumb(DupeWindow *dw, DupeItem *di, GtkTreeIter *iter){ GtkListStore *store; GtkTreeIter iter_n; store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(dw->listview))); if (!iter) { if (dupe_listview_find_item(store, di, &iter_n) >= 0) { iter = &iter_n; } } if (iter) gtk_list_store_set(store, iter, DUPE_COLUMN_THUMB, di->pixbuf, -1);}static void dupe_thumb_do(DupeWindow *dw){ DupeItem *di; if (!dw->thumb_loader || !dw->thumb_item) return; di = dw->thumb_item; if (di->pixbuf) g_object_unref(di->pixbuf); di->pixbuf = thumb_loader_get_pixbuf(dw->thumb_loader, TRUE); dupe_listview_set_thumb(dw, di, NULL);}static void dupe_thumb_error_cb(ThumbLoader *tl, gpointer data){ DupeWindow *dw = data; dupe_thumb_do(dw); dupe_thumb_step(dw);}static void dupe_thumb_done_cb(ThumbLoader *tl, gpointer data){ DupeWindow *dw = data; dupe_thumb_do(dw); dupe_thumb_step(dw);}static void dupe_thumb_step(DupeWindow *dw){ GtkTreeModel *store; GtkTreeIter iter; DupeItem *di = NULL; gint valid; gint row = 0; gint length = 0; store = gtk_tree_view_get_model(GTK_TREE_VIEW(dw->listview)); valid = gtk_tree_model_get_iter_first(store, &iter); while (!di && valid) { GdkPixbuf *pixbuf; length++; gtk_tree_model_get(store, &iter, DUPE_COLUMN_POINTER, &di, DUPE_COLUMN_THUMB, &pixbuf, -1); if (pixbuf || di->pixbuf) { if (!pixbuf) gtk_list_store_set(GTK_LIST_STORE(store), &iter, DUPE_COLUMN_THUMB, di->pixbuf, -1); row++; di = NULL; } valid = gtk_tree_model_iter_next(store, &iter); } if (valid) { while (gtk_tree_model_iter_next(store, &iter)) length++; } if (!di) { dw->thumb_item = NULL; thumb_loader_free(dw->thumb_loader); dw->thumb_loader = NULL; dupe_window_update_progress(dw, NULL, 0.0, FALSE); return; } dupe_window_update_progress(dw, _("Loading thumbs..."), length == 0 ? 0.0 : (gdouble)(row) / length, FALSE); dw->thumb_item = di; thumb_loader_free(dw->thumb_loader); dw->thumb_loader = thumb_loader_new(thumb_max_width, thumb_max_height); thumb_loader_set_callbacks(dw->thumb_loader, dupe_thumb_done_cb, dupe_thumb_error_cb, NULL, dw); /* start it */ if (!thumb_loader_start(dw->thumb_loader, di->path)) { /* error, handle it, do next */ if (debug) printf("error loading thumb for %s\n", di->path); dupe_thumb_do(dw); dupe_thumb_step(dw); }}/* * ------------------------------------------------------------------ * Dupe checking loop * ------------------------------------------------------------------ */static void dupe_check_stop(DupeWindow *dw){ if (dw->idle_id != -1 || dw->img_loader || dw->thumb_loader) { g_source_remove(dw->idle_id); dw->idle_id = -1; dupe_window_update_progress(dw, NULL, 0.0, FALSE); widget_set_cursor(dw->listview, -1); } thumb_loader_free(dw->thumb_loader); dw->thumb_loader = NULL; image_loader_free(dw->img_loader); dw->img_loader = NULL;}static void dupe_loader_done_cb(ImageLoader *il, gpointer data){ DupeWindow *dw = data; GdkPixbuf *pixbuf; pixbuf = image_loader_get_pixbuf(il); if (dw->setup_point) { DupeItem *di = dw->setup_point->data; if (!di->simd) { di->simd = image_sim_new_from_pixbuf(pixbuf); } else { image_sim_fill_data(di->simd, pixbuf); } if (di->width == 0 && di->height == 0) { di->width = gdk_pixbuf_get_width(pixbuf); di->height = gdk_pixbuf_get_height(pixbuf); } if (enable_thumb_caching) { dupe_item_write_cache(di); } image_sim_alternate_processing(di->simd); } image_loader_free(dw->img_loader); dw->img_loader = NULL; dw->idle_id = g_idle_add(dupe_check_cb, dw);}static void dupe_setup_reset(DupeWindow *dw){ dw->setup_point = NULL; dw->setup_n = 0; dw->setup_time = msec_time(); dw->setup_time_count = 0;}static GList *dupe_setup_point_step(DupeWindow *dw, GList *p){ if (!p) return NULL; if (p->next) return p->next; if (dw->second_set && g_list_first(p) == dw->list) return dw->second_list; return NULL;}static gint dupe_check_cb(gpointer data){ DupeWindow *dw = data; if (dw->idle_id == -1) return FALSE; if (!dw->setup_done) { if ((dw->match_mask & DUPE_MATCH_SUM) && !(dw->setup_mask & DUPE_MATCH_SUM) ) { if (!dw->setup_point) dw->setup_point = dw->list; while (dw->setup_point) { DupeItem *di = dw->setup_point->data; dw->setup_point = dupe_setup_point_step(dw, dw->setup_point); dw->setup_n++; if (!di->md5sum) { dupe_window_update_progress(dw, _("Reading checksums..."), dw->setup_count == 0 ? 0.0 : (gdouble)(dw->setup_n - 1) / dw->setup_count, FALSE); if (enable_thumb_caching) { dupe_item_read_cache(di); if (di->md5sum) return TRUE; } di->md5sum = md5_text_from_file_utf8(di->path, ""); if (enable_thumb_caching) { dupe_item_write_cache(di); } return TRUE; } } dw->setup_mask |= DUPE_MATCH_SUM; dupe_setup_reset(dw); } if ((dw->match_mask & DUPE_MATCH_DIM) && !(dw->setup_mask & DUPE_MATCH_DIM) ) { if (!dw->setup_point) dw->setup_point = dw->list; while (dw->setup_point) { DupeItem *di = dw->setup_point->data; dw->setup_point = dupe_setup_point_step(dw, dw->setup_point); dw->setup_n++; if (di->width == 0 && di->height == 0) { dupe_window_update_progress(dw, _("Reading dimensions..."), dw->setup_count == 0 ? 0.0 : (gdouble)(dw->setup_n - 1) / dw->setup_count, FALSE); if (enable_thumb_caching) { dupe_item_read_cache(di); if (di->width != 0 || di->height != 0) return TRUE; } image_load_dimensions(di->path, &di->width, &di->height); if (enable_thumb_caching) { dupe_item_write_cache(di); } return TRUE; } } dw->setup_mask |= DUPE_MATCH_DIM; dupe_setup_reset(dw); } if ((dw->match_mask & DUPE_MATCH_SIM_HIGH || dw->match_mask & DUPE_MATCH_SIM_MED || dw->match_mask & DUPE_MATCH_SIM_LOW || dw->match_mask & DUPE_MATCH_SIM_CUSTOM) && !(dw->setup_mask & DUPE_MATCH_SIM_MED) ) { if (!dw->setup_point) dw->setup_point = dw->list; while (dw->setup_point) { DupeItem *di = dw->setup_point->data; if (!di->simd) { dupe_window_update_progress(dw, _("Reading similarity data..."), dw->setup_count == 0 ? 0.0 : (gdouble)dw->setup_n / dw->setup_count, FALSE); if (enable_thumb_caching) { dupe_item_read_cache(di); if (cache_sim_data_filled(di->simd)) { image_sim_alternate_processing(di->simd); return TRUE; } } dw->img_loader = image_loader_new(di->path); image_loader_set_buffer_size(dw->img_loader, 8); image_loader_set_error_func(dw->img_loader, dupe_loader_done_cb, dw); if (!image_loader_start(dw->img_loader, dupe_loader_done_cb, dw)) { image_sim_free(di->simd); di->simd = image_sim_new(); image_loader_free(dw->img_loader); dw->img_loader = NULL; return TRUE; } dw->idle_id = -1; return FALSE; } dw->setup_point = dupe_setup_point_step(dw, dw->setup_point); dw->setup_n++; } dw->setup_mask |= DUPE_MATCH_SIM_MED; dupe_setup_reset(dw); } dupe_window_update_progress(dw, _("Comparing..."), 0.0, FALSE); dw->setup_done = TRUE; dupe_setup_reset(dw); dw->setup_count = g_list_length(dw->list); } if (!dw->working) { if (dw->setup_count > 0) { dw->setup_count = 0; dupe_window_update_progress(dw, _("Sorting..."), 1.0, TRUE); return TRUE; } dw->idle_id = -1; dupe_window_update_progress(dw, NULL, 0.0, FALSE); dupe_match_rank(dw); dupe_window_update_count(dw, FALSE); dupe_listview_populate(dw); /* check thumbs */ if (dw->show_thumbs) dupe_thumb_step(dw); widget_set_cursor(dw->listview, -1); return FALSE; } dupe_list_check_match(dw, (DupeItem *)dw->working->data, dw->working); dupe_window_update_progress(dw, _("Comparing..."), dw->setup_count == 0 ? 0.0 : (gdouble) dw->setup_n / dw->setup_count, FALSE); dw->setup_n++; dw->working = dw->working->prev; return TRUE;}static void dupe_check_start(DupeWindow *dw){ dw->setup_done = FALSE; dw->setup_count = g_list_length(dw->list); if (dw->second_set) dw->setup_count += g_list_length(dw->second_list); dw->setup_mask = 0; dupe_setup_reset(dw); dw->working = g_list_last(dw->list); dupe_window_update_count(dw, TRUE); widget_set_cursor(dw->listview, GDK_WATCH); if (dw->idle_id != -1) return; dw->idle_id = g_idle_add(dupe_check_cb, dw);}/* * ------------------------------------------------------------------ * Item addition, removal * ------------------------------------------------------------------ */static void dupe_item_remove(DupeWindow *dw, DupeItem *di){ if (!di) return; /* handle things that may be in progress... */ if (dw->working && dw->working->data == di) { dw->working = dw->working->prev; } if (dw->thumb_loader && dw->thumb_item == di) { dupe_thumb_step(dw); } if (dw->setup_point && dw->setup_point->data == di) { dw->setup_point = dupe_setup_point_step(dw, dw->setup_point); if (dw->img_loader) { image_loader_free(dw->img_loader); dw->img_loader = NULL; dw->idle_id = g_idle_add(dupe_check_cb, dw); } } if (di->group && dw->dupes) { /* is a dupe, must remove from group/reset children if a parent */ DupeItem *parent; parent = dupe_match_find_parent(dw, di); if (di == parent) { if (g_list_length(parent->group) < 2) { DupeItem *child; child = dupe_match_highest_rank(parent); dupe_match_link_clear(child, TRUE); dupe_listview_remove(dw, child); dupe_match_link_clear(parent, TRUE); dupe_listview_remove(dw, parent); dw->dupes = g_list_remove(dw->dupes, parent); } else { DupeItem *new_parent; DupeMatch *dm; dm = parent->group->data; new_parent = dm->di; dupe_match_reparent(dw, parent, new_parent); dupe_listview_remove(dw, parent); } } else { if (g_list_length(parent->group) < 2) { dupe_match_link_clear(parent, TRUE); dupe_listview_remove(dw, parent); dw->dupes = g_list_remove(dw->dupes, parent); } dupe_match_link_clear(di, TRUE); dupe_listview_remove(dw, di); } } else { /* not a dupe, or not sorted yet, simply reset */ dupe_match_link_clear(di, TRUE); } if (dw->second_list && g_list_find(dw->second_list, di)) { dupe_second_remove(dw, di); } else { dw->list = g_list_remove(dw->list, di); } dupe_item_free(di); dupe_window_update_count(dw, FALSE);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -