diff --git a/czkawka_cli/src/commands.rs b/czkawka_cli/src/commands.rs index 05734ab..144b2f8 100644 --- a/czkawka_cli/src/commands.rs +++ b/czkawka_cli/src/commands.rs @@ -1,5 +1,6 @@ use czkawka_core::duplicate::{CheckingMethod, DeleteMethod}; use czkawka_core::same_music::MusicSimilarity; +use czkawka_core::similar_images::Similarity; use std::path::PathBuf; use structopt::StructOpt; @@ -99,6 +100,8 @@ pub enum Commands { excluded_directories: ExcludedDirectories, #[structopt(short, long, parse(try_from_str = parse_minimal_file_size), default_value = "16384", help = "Minimum size in bytes", long_help = "Minimum size of checked files in bytes, assigning bigger value may speed up searching")] minimal_file_size: u64, + #[structopt(short, long, default_value = "High", parse(try_from_str = parse_similar_images_similarity), help = "Similairty level (VerySmall, Small, Medium, High, Very High)", long_help = "Methods to choose similarity level of images which will be considered as duplicated.")] + similarity: Similarity, #[structopt(flatten)] excluded_items: ExcludedItems, #[structopt(flatten)] @@ -218,6 +221,17 @@ fn parse_delete_method(src: &str) -> Result { } } +fn parse_similar_images_similarity(src: &str) -> Result { + match src.to_ascii_lowercase().replace('_', "").as_str() { + "verysmall" => Ok(Similarity::VerySmall), + "small" => Ok(Similarity::Small), + "medium" => Ok(Similarity::Medium), + "high" => Ok(Similarity::High), + "veryhigh" => Ok(Similarity::VeryHigh), + _ => Err("Couldn't parse the delete method (allowed: verysmall, small, medium, high, veryhigh)"), + } +} + fn parse_minimal_file_size(src: &str) -> Result { match src.parse::() { Ok(minimal_file_size) => { diff --git a/czkawka_cli/src/main.rs b/czkawka_cli/src/main.rs index 199d6bc..eae0c49 100644 --- a/czkawka_cli/src/main.rs +++ b/czkawka_cli/src/main.rs @@ -199,6 +199,7 @@ fn main() { excluded_items, file_to_save, minimal_file_size, + similarity, not_recursive, } => { let mut sf = SimilarImages::new(); @@ -208,6 +209,7 @@ fn main() { sf.set_excluded_items(path_list_to_str(excluded_items.excluded_items)); sf.set_minimal_file_size(minimal_file_size); sf.set_recursive_search(!not_recursive.not_recursive); + sf.set_similarity(similarity); sf.find_similar_images(None); diff --git a/czkawka_core/src/similar_images.rs b/czkawka_core/src/similar_images.rs index ec00e34..ea865c6 100644 --- a/czkawka_core/src/similar_images.rs +++ b/czkawka_core/src/similar_images.rs @@ -16,9 +16,10 @@ use std::io::Write; use std::path::PathBuf; use std::time::{SystemTime, UNIX_EPOCH}; -#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] pub enum Similarity { None, + VerySmall, Small, Medium, High, @@ -320,7 +321,8 @@ impl SimilarImages { Similarity::High => 1, Similarity::Medium => 2, Similarity::Small => 3, - _ => panic!("0-3 similarity levels are allowed, check if not added more."), + Similarity::VerySmall => 4, + _ => panic!("0-4 similarity levels are allowed, check if not added more."), }; // TODO @@ -336,6 +338,11 @@ impl SimilarImages { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { return false; } + if !hashes_to_check.contains_key(hash) { + continue; + } + hashes_to_check.remove(hash); + let vector_with_found_similar_hashes = self.bktree.find(hash, similarity).collect::>(); if vector_with_found_similar_hashes.len() == 1 && vec_file_entry.len() == 1 { // This one picture doesn't have similar pictures, so there is no go @@ -375,7 +382,8 @@ impl SimilarImages { 1 => Similarity::High, 2 => Similarity::Medium, 3 => Similarity::Small, - _ => panic!("0-3 similarity levels are allowed, check if not added more."), + 4 => Similarity::VerySmall, + _ => panic!("0-4 similarity levels are allowed, check if not added more."), }, }) .collect::>()), @@ -503,6 +511,7 @@ impl PrintResults for SimilarImages { fn get_string_from_similarity(similarity: &Similarity) -> &str { match similarity { + Similarity::VerySmall => "Very Small", Similarity::Small => "Small", Similarity::Medium => "Medium", Similarity::High => "High", diff --git a/czkawka_gui/czkawka.glade b/czkawka_gui/czkawka.glade index 9c6b9db..65ea0fd 100644 --- a/czkawka_gui/czkawka.glade +++ b/czkawka_gui/czkawka.glade @@ -1131,6 +1131,21 @@ Author: Rafał Mikrut 0 + + + Very Small + True + True + False + True + radio_button_similar_images_very_high + + + False + True + 1 + + Small @@ -1143,7 +1158,7 @@ Author: Rafał Mikrut False True - 1 + 2 @@ -1158,7 +1173,7 @@ Author: Rafał Mikrut False True - 2 + 3 @@ -1174,7 +1189,7 @@ Author: Rafał Mikrut False True - 3 + 4 @@ -1189,7 +1204,7 @@ Author: Rafał Mikrut False True - 4 + 5 diff --git a/czkawka_gui/src/connect_button_search.rs b/czkawka_gui/src/connect_button_search.rs index c0fc4a4..67a5ec5 100644 --- a/czkawka_gui/src/connect_button_search.rs +++ b/czkawka_gui/src/connect_button_search.rs @@ -32,6 +32,7 @@ pub fn connect_button_search(gui_data: &GuiData, sender: Sender) { let radio_button_duplicates_size = gui_data.radio_button_duplicates_size.clone(); let radio_button_duplicates_hashmb = gui_data.radio_button_duplicates_hashmb.clone(); let radio_button_duplicates_hash = gui_data.radio_button_duplicates_hash.clone(); + let radio_button_similar_images_very_small = gui_data.radio_button_similar_images_very_small.clone(); let radio_button_similar_images_small = gui_data.radio_button_similar_images_small.clone(); let radio_button_similar_images_medium = gui_data.radio_button_similar_images_medium.clone(); let radio_button_similar_images_high = gui_data.radio_button_similar_images_high.clone(); @@ -203,7 +204,9 @@ pub fn connect_button_search(gui_data: &GuiData, sender: Sender) { }; let similarity; - if radio_button_similar_images_small.get_active() { + if radio_button_similar_images_very_small.get_active() { + similarity = similar_images::Similarity::VerySmall; + } else if radio_button_similar_images_small.get_active() { similarity = similar_images::Similarity::Small; } else if radio_button_similar_images_medium.get_active() { similarity = similar_images::Similarity::Medium; diff --git a/czkawka_gui/src/gui_data.rs b/czkawka_gui/src/gui_data.rs index 0fbe15e..03e09fc 100644 --- a/czkawka_gui/src/gui_data.rs +++ b/czkawka_gui/src/gui_data.rs @@ -103,6 +103,7 @@ pub struct GuiData { pub radio_button_duplicates_hashmb: gtk::RadioButton, pub radio_button_duplicates_hash: gtk::RadioButton, + pub radio_button_similar_images_very_small: gtk::RadioButton, pub radio_button_similar_images_small: gtk::RadioButton, pub radio_button_similar_images_medium: gtk::RadioButton, pub radio_button_similar_images_high: gtk::RadioButton, @@ -286,6 +287,7 @@ impl GuiData { let radio_button_duplicates_hashmb: gtk::RadioButton = builder.get_object("radio_button_duplicates_hashmb").unwrap(); let radio_button_duplicates_hash: gtk::RadioButton = builder.get_object("radio_button_duplicates_hash").unwrap(); + let radio_button_similar_images_very_small: gtk::RadioButton = builder.get_object("radio_button_similar_images_very_small").unwrap(); let radio_button_similar_images_small: gtk::RadioButton = builder.get_object("radio_button_similar_images_small").unwrap(); let radio_button_similar_images_medium: gtk::RadioButton = builder.get_object("radio_button_similar_images_medium").unwrap(); let radio_button_similar_images_high: gtk::RadioButton = builder.get_object("radio_button_similar_images_high").unwrap(); @@ -391,6 +393,7 @@ impl GuiData { radio_button_duplicates_size, radio_button_duplicates_hashmb, radio_button_duplicates_hash, + radio_button_similar_images_very_small, radio_button_similar_images_small, radio_button_similar_images_medium, radio_button_similar_images_high, diff --git a/czkawka_gui/src/help_functions.rs b/czkawka_gui/src/help_functions.rs index 9cdbb30..b73a9dc 100644 --- a/czkawka_gui/src/help_functions.rs +++ b/czkawka_gui/src/help_functions.rs @@ -221,6 +221,7 @@ pub fn hide_all_buttons_except(except_name: &str, buttons_array: &[gtk::Button], pub fn get_text_from_similarity(similarity: &Similarity) -> &str { match similarity { Similarity::None => "Original", + Similarity::VerySmall => "Very Small", Similarity::Small => "Small", Similarity::Medium => "Medium", Similarity::High => "High",