@ -45,11 +45,6 @@ pub struct ProgressData {
pub images_to_check : usize ,
}
#[ derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Serialize, Deserialize) ]
pub enum Similarity {
Similar ( u32 ) ,
}
#[ derive(Clone, Debug, Serialize, Deserialize) ]
pub struct FileEntry {
pub path : PathBuf ,
@ -57,7 +52,7 @@ pub struct FileEntry {
pub dimensions : String ,
pub modified_date : u64 ,
pub hash : Vec < u8 > ,
pub similarity : Similarity ,
pub similarity : u32 ,
}
/// Used by CLI tool when we cannot use directly values
@ -100,7 +95,7 @@ pub struct SimilarImages {
maximal_file_size : u64 ,
image_hashes : HashMap < Vec < u8 > , Vec < FileEntry > > , // Hashmap with image hashes and Vector with names of files
stopped_search : bool ,
similarity : Similarity ,
similarity : u32 ,
images_to_check : HashMap < String , FileEntry > ,
hash_size : u8 ,
hash_alg : HashAlg ,
@ -109,7 +104,6 @@ pub struct SimilarImages {
delete_outdated_cache : bool ,
exclude_images_with_same_size : bool ,
use_reference_folders : bool ,
fast_comparing : bool ,
save_also_as_json : bool ,
}
@ -144,7 +138,7 @@ impl SimilarImages {
maximal_file_size : u64 ::MAX ,
image_hashes : Default ::default ( ) ,
stopped_search : false ,
similarity : Similarity ::Similar ( 1 ) ,
similarity : 0 ,
images_to_check : Default ::default ( ) ,
hash_size : 8 ,
hash_alg : HashAlg ::Gradient ,
@ -153,7 +147,6 @@ impl SimilarImages {
delete_outdated_cache : true ,
exclude_images_with_same_size : false ,
use_reference_folders : false ,
fast_comparing : false ,
save_also_as_json : false ,
}
}
@ -183,9 +176,6 @@ impl SimilarImages {
self . image_filter = image_filter ;
}
pub fn set_fast_comparing ( & mut self , fast_comparing : bool ) {
self . fast_comparing = fast_comparing ;
}
pub fn set_save_also_as_json ( & mut self , save_also_as_json : bool ) {
self . save_also_as_json = save_also_as_json ;
}
@ -243,7 +233,7 @@ impl SimilarImages {
t = > t ,
} ;
}
pub fn set_similarity ( & mut self , similarity : Similarity ) {
pub fn set_similarity ( & mut self , similarity : u32 ) {
self . similarity = similarity ;
}
@ -310,7 +300,7 @@ impl SimilarImages {
progress_send
. unbounded_send ( ProgressData {
current_stage : 0 ,
max_stage : 2 ,
max_stage : 3 ,
images_checked : atomic_file_counter . load ( Ordering ::Relaxed ) as usize ,
images_to_check : 0 ,
} )
@ -448,7 +438,7 @@ impl SimilarImages {
} ,
hash : Vec ::new ( ) ,
similarity : Similarity ::Similar ( 0 ) ,
similarity : 0 ,
} ;
fe_result . push ( ( current_file_name . to_string_lossy ( ) . to_string ( ) , fe ) ) ;
@ -540,7 +530,7 @@ impl SimilarImages {
progress_send
. unbounded_send ( ProgressData {
current_stage : 1 ,
max_stage : 2 ,
max_stage : 3 ,
images_checked : atomic_file_counter . load ( Ordering ::Relaxed ) as usize ,
images_to_check ,
} )
@ -684,195 +674,268 @@ impl SimilarImages {
fn find_similar_hashes ( & mut self , stop_receiver : Option < & Receiver < ( ) > > , progress_sender : Option < & futures ::channel ::mpsc ::UnboundedSender < ProgressData > > ) -> bool {
let hash_map_modification = SystemTime ::now ( ) ;
let Similarity::Similar ( similarity ) = self . similarity ;
let tolerance = self . similarity ;
// Results
let mut collected_similar_images : HashMap < Vec < u8 > , Vec < FileEntry > > = Default ::default ( ) ;
let mut temp_hash es = Default ::default ( ) ;
mem ::swap ( & mut temp_hash es, & mut self . image_hashes ) ;
let mut all_hashed_imag es = Default ::default ( ) ;
mem ::swap ( & mut all_hashed_imag es, & mut self . image_hashes ) ;
let mut this_time_check_hashes ; // Temporary variable which
let mut master_of_group : HashSet < Vec < u8 > > = Default ::default ( ) ; // Hashes which are "master of groups",
let all_hashes : Vec < _ > = all_hashed_images . keys ( ) . collect ( ) ;
let mut all_hashes_to_check : HashMap < Vec < u8 > , Vec < FileEntry > > = temp_hashes . clone ( ) ; // List of all hashes, which are or can be master of group
let mut available_hashes : HashMap < Vec < u8 > , Vec < FileEntry > > = Default ::default ( ) ; // List of hashes which can be used as similar images
for ( hash , vec_file_entry ) in temp_hashes {
// There exists 2 or more images with same hash
if vec_file_entry . len ( ) > = 2 {
master_of_group . insert ( hash . clone ( ) ) ;
collected_similar_images . insert ( hash , vec_file_entry ) ;
} else {
self . bktree . add ( hash . clone ( ) ) ;
available_hashes . insert ( hash , vec_file_entry ) ;
// Checking entries with tolerance 0 is really easy and fast, because only entries with same hashes needs to be checked
if tolerance = = 0 {
for ( hash , vec_file_entry ) in all_hashed_images . clone ( ) {
if vec_file_entry . len ( ) > = 2 {
collected_similar_images . insert ( hash , vec_file_entry ) ;
}
}
}
} else {
//// PROGRESS THREAD START
let check_was_stopped = AtomicBool ::new ( false ) ; // Used for breaking from GUI and ending check thread
let progress_thread_run = Arc ::new ( AtomicBool ::new ( true ) ) ;
let atomic_mode_counter = Arc ::new ( AtomicUsize ::new ( 0 ) ) ;
let progress_thread_handle = if let Some ( progress_sender ) = progress_sender {
let progress_send = progress_sender . clone ( ) ;
let progress_thread_run = progress_thread_run . clone ( ) ;
let atomic_mode_counter = atomic_mode_counter . clone ( ) ;
let all_combinations_to_check = all_hashes . len ( ) ;
thread ::spawn ( move | | loop {
progress_send
. unbounded_send ( ProgressData {
current_stage : 2 ,
max_stage : 2 ,
images_checked : atomic_mode_counter . load ( Ordering ::Relaxed ) as usize ,
images_to_check : all_combinations_to_check ,
} )
. unwrap ( ) ;
if ! progress_thread_run . load ( Ordering ::Relaxed ) {
break ;
}
sleep ( Duration ::from_millis ( LOOP_DURATION as u64 ) ) ;
} )
} else {
thread ::spawn ( | | { } )
} ;
//// PROGRESS THREAD END
//// PROGRESS THREAD START
let progress_thread_run = Arc ::new ( AtomicBool ::new ( true ) ) ;
for hash in & all_hashes {
self . bktree . add ( hash . to_vec ( ) ) ;
}
let atomic_mode_counter = Arc ::new ( AtomicUsize ::new ( 0 ) ) ;
let number_of_processors = num_cpus ::get ( ) ;
let chunks : Vec < _ > = all_hashes . chunks ( all_hashes . len ( ) / number_of_processors ) . collect ( ) ;
let parts : Vec < _ > = chunks
. into_par_iter ( )
. map ( | hashes_to_check | {
let mut hashes_parents : HashMap < & Vec < u8 > , u32 > = Default ::default ( ) ; // Hash used as parent, childrens
let mut hashes_similarity : HashMap < & Vec < u8 > , ( & Vec < u8 > , u32 ) > = Default ::default ( ) ; // Hash used as child, (parent_hash,similarity)
// Sprawdź czy hash nie jest użyty jako master gdzie indziej
// Jeśli tak to przejdź do sprawdzania kolejnego elementu
// Zweryfikuj czy sprawdzany element ma rodzica
// Jeśli ma to sprawdź czy similarity nowego rodzica jest mniejsze niż starego
// // Jeśli tak to zmniejsz ilość dzieci starego rodzica, dodaj ilość dzieci w nowym rodzicu i podmień rekord hashes_similarity
// // Jeśli nie to dodaj nowy rekord w hashes_similarity jak i hashes_parents z liczbą dzieci równą 1
for ( index , hash_to_check ) in hashes_to_check . iter ( ) . enumerate ( ) {
// Don't check for user stop too often
// Also don't add too ofter data to variables
const CYCLES_COUNTER : usize = 50 ;
if index % CYCLES_COUNTER = = 0 & & index ! = 0 {
atomic_mode_counter . fetch_add ( CYCLES_COUNTER , Ordering ::Relaxed ) ;
if stop_receiver . is_some ( ) & & stop_receiver . unwrap ( ) . try_recv ( ) . is_ok ( ) {
check_was_stopped . store ( true , Ordering ::Relaxed ) ;
return None ;
}
}
let progress_thread_handle = if let Some ( progress_sender ) = progress_sender {
let progress_send = progress_sender . clone ( ) ;
let progress_thread_run = progress_thread_run . clone ( ) ;
let atomic_mode_counter = atomic_mode_counter . clone ( ) ;
let all_images = match self . fast_comparing {
false = > similarity as usize * available_hashes . len ( ) ,
true = > available_hashes . len ( ) ,
} ;
thread ::spawn ( move | | loop {
progress_send
. unbounded_send ( ProgressData {
current_stage : 2 ,
max_stage : 2 ,
images_checked : atomic_mode_counter . load ( Ordering ::Relaxed ) as usize ,
images_to_check : all_images ,
} )
. unwrap ( ) ;
if ! progress_thread_run . load ( Ordering ::Relaxed ) {
break ;
}
sleep ( Duration ::from_millis ( LOOP_DURATION as u64 ) ) ;
} )
} else {
thread ::spawn ( | | { } )
} ;
//// PROGRESS THREAD END
if similarity > = 1 {
if self . fast_comparing {
this_time_check_hashes = all_hashes_to_check . clone ( ) ;
let mut found_items = self
. bktree
. find ( hash_to_check , tolerance )
. filter ( | ( similarity , _hash ) | * similarity ! = 0 )
. collect ::< Vec < _ > > ( ) ;
if stop_receiver . is_some ( ) & & stop_receiver . unwrap ( ) . try_recv ( ) . is_ok ( ) {
// End thread which send info to gui
progress_thread_run . store ( false , Ordering ::Relaxed ) ;
progress_thread_handle . join ( ) . unwrap ( ) ;
return false ;
}
found_items . sort_unstable_by_key ( | f | f . 0 ) ;
for ( hash , mut vec_file_entry ) in this_time_check_hashes . into_iter ( ) {
atomic_mode_counter . fetch_add ( 1 , Ordering ::Relaxed ) ;
for ( similarity , other_hash ) in found_items {
// SSSTART
// Cannot use hash if already is used as master record(have more than 0 children)
if let Some ( children_number ) = hashes_parents . get ( other_hash ) {
if * children_number > 0 {
continue ;
}
}
// It is not available, because in same iteration, was already taken out
if ! all_hashes_to_check . contains_key ( & hash ) {
continue ;
}
// If there is already record, with smaller sensitivity, then replace it
let mut need_to_add = false ;
let mut need_to_check = false ;
// Finds hashes with specific distance to original one
let vector_with_found_similar_hashes = self
. bktree
. find ( & hash , similarity )
. filter ( | ( similarity , hash ) | * similarity ! = 0 & & available_hashes . contains_key ( * hash ) )
. collect ::< Vec < _ > > ( ) ;
// TODO replace variables from above with closures
// If current checked hash, have parent, first we must check if similarity between them is lower than checked item
if let Some ( ( current_parent_hash , current_similarity_with_parent ) ) = hashes_similarity . get ( hash_to_check ) {
if * current_similarity_with_parent > similarity {
need_to_check = true ;
// Not found any hash with specific distance
if vector_with_found_similar_hashes . is_empty ( ) {
continue ;
}
* hashes_parents . get_mut ( current_parent_hash ) . unwrap ( ) - = 1 ;
hashes_similarity . remove ( hash_to_check ) . unwrap ( ) ;
}
} else {
need_to_check = true ;
}
// Current checked hash isn't in any group of similarity, so we create one, because found similar images
if ! master_of_group . contains ( & hash ) {
master_of_group . insert ( hash . clone ( ) ) ;
collected_similar_images . insert ( hash . clone ( ) , Vec ::new ( ) ) ;
let _ = available_hashes . remove ( & hash ) ; // Cannot be used anymore as non master
if need_to_check {
if let Some ( ( other_parent_hash , other_similarity ) ) = hashes_similarity . get ( other_hash ) {
if * other_similarity > similarity {
need_to_add = true ;
* hashes_parents . get_mut ( other_parent_hash ) . unwrap ( ) - = 1 ;
}
}
// But when there is no record, just add it
else {
need_to_add = true
}
}
collected_similar_images . get_mut ( & hash ) . unwrap ( ) . append ( & mut vec_file_entry ) ;
if need_to_add {
hashes_similarity . insert ( other_hash , ( hash_to_check , similarity ) ) ;
// This shouldn't be executed too much times, so it should be quite fast to check this
if stop_receiver . is_some ( ) & & stop_receiver . unwrap ( ) . try_recv ( ) . is_ok ( ) {
// End thread which send info to gui
progress_thread_run . store ( false , Ordering ::Relaxed ) ;
progress_thread_handle . join ( ) . unwrap ( ) ;
return false ;
if let Some ( number_of_children ) = hashes_parents . get_mut ( hash_to_check ) {
* number_of_children + = 1 ;
} else {
hashes_parents . insert ( hash_to_check , 1 ) ;
}
}
// ENND
}
}
vector_with_found_similar_hashes . iter ( ) . for_each ( | ( similarity , other_hash ) | {
let _ = all_hashes_to_check . remove ( * other_hash ) ; // Cannot be used anymore as master record
let mut vec_fe = available_hashes . remove ( * other_hash ) . unwrap ( ) ;
for fe in & mut vec_fe {
fe . similarity = Similarity ::Similar ( * similarity )
}
#[ cfg(debug_assertions) ]
debug_check_for_duplicated_things ( hashes_parents . clone ( ) , hashes_similarity . clone ( ) , all_hashed_images . clone ( ) , "BEFORE" ) ;
collected_similar_images . get_mut ( & hash ) . unwrap ( ) . append ( & mut vec_fe ) ;
} ) ;
}
} else {
for current_similarity in 1 ..= similarity {
this_time_check_hashes = all_hashes_to_check . clone ( ) ;
if stop_receiver . is_some ( ) & & stop_receiver . unwrap ( ) . try_recv ( ) . is_ok ( ) {
// End thread which send info to gui
progress_thread_run . store ( false , Ordering ::Relaxed ) ;
progress_thread_handle . join ( ) . unwrap ( ) ;
return false ;
}
Some ( ( hashes_parents , hashes_similarity ) )
} )
. while_some ( )
. collect ( ) ;
for ( hash , mut vec_file_entry ) in this_time_check_hashes . into_iter ( ) {
atomic_mode_counter . fetch_add ( 1 , Ordering ::Relaxed ) ;
// End thread which send info to gui
progress_thread_run . store ( false , Ordering ::Relaxed ) ;
progress_thread_handle . join ( ) . unwrap ( ) ;
// It is not available, because in same iteration, was already taken out
if ! all_hashes_to_check . contains_key ( & hash ) {
continue ;
}
if check_was_stopped . load ( Ordering ::Relaxed ) {
return false ;
}
// Finds hashes with specific distance to original one
let vector_with_found_similar_hashes = self
. bktree
. find ( & hash , similarity )
. filter ( | ( similarity , hash ) | ( * similarity = = current_similarity ) & & available_hashes . contains_key ( * hash ) )
. collect ::< Vec < _ > > ( ) ;
{
let mut hashes_parents : HashMap < & Vec < u8 > , u32 > = Default ::default ( ) ;
let mut hashes_similarity : HashMap < & Vec < u8 > , ( & Vec < u8 > , u32 ) > = Default ::default ( ) ;
let mut iter = parts . into_iter ( ) ;
// At start fill arrays with first item
// Normal algorithm would do exactly same thing, but slower, one record after one
if let Some ( ( first_hashes_parents , first_hashes_similarity ) ) = iter . next ( ) {
hashes_parents = first_hashes_parents ;
hashes_similarity = first_hashes_similarity ;
}
// Not found any hash with specific distance
if vector_with_found_similar_hashes . is_empty ( ) {
continue ;
for ( _partial_hashes_with_parents , partial_hashes_with_similarity ) in iter {
for ( hash_to_check , ( other_hash , similarity ) ) in partial_hashes_with_similarity {
// SSSTART
// Cannot use hash if already is used as master record(have more than 0 children)
if let Some ( children_number ) = hashes_parents . get ( other_hash ) {
if * children_number > 0 {
continue ;
}
}
// Current checked hash isn't in any group of similarity, so we create one, because found similar images
if ! master_of_group . contains ( & hash ) {
master_of_group . insert ( hash . clone ( ) ) ;
collected_similar_images . insert ( hash . clone ( ) , Vec ::new ( ) ) ;
let _ = available_hashes . remove ( & hash ) ; // Cannot be used anymore as non master
// If there is already record, with smaller sensitivity, then replace it
let mut need_to_add = false ;
let mut need_to_check = false ;
collected_similar_images . get_mut ( & hash ) . unwrap ( ) . append ( & mut vec_file_entry ) ;
// TODO replace variables from above with closures
// If current checked hash, have parent, first we must check if similarity between them is lower than checked item
if let Some ( ( current_parent_hash , current_similarity_with_parent ) ) = hashes_similarity . get ( hash_to_check ) {
if * current_similarity_with_parent > similarity {
need_to_check = true ;
// This shouldn't be executed too much times, so it should be quite fast to check this
if stop_receiver . is_some ( ) & & stop_receiver . unwrap ( ) . try_recv ( ) . is_ok ( ) {
// End thread which send info to gui
progress_thread_run . store ( false , Ordering ::Relaxed ) ;
progress_thread_handle . join ( ) . unwrap ( ) ;
return false ;
* hashes_parents . get_mut ( current_parent_hash ) . unwrap ( ) - = 1 ;
hashes_similarity . remove ( hash_to_check ) . unwrap ( ) ;
}
} else {
need_to_check = true ;
}
vector_with_found_similar_hashes . iter ( ) . for_each ( | ( similarity , other_hash ) | {
let _ = all_hashes_to_check . remove ( * other_hash ) ; // Cannot be used anymore as master record
let mut vec_fe = available_hashes . remove ( * other_hash ) . unwrap ( ) ;
for fe in & mut vec_fe {
fe . similarity = Similarity ::Similar ( * similarity )
if need_to_check {
if let Some ( ( other_parent_hash , other_similarity ) ) = hashes_similarity . get ( other_hash ) {
if * other_similarity > similarity {
need_to_add = true ;
* hashes_parents . get_mut ( other_parent_hash ) . unwrap ( ) - = 1 ;
}
}
// But when there is no record, just add it
else {
need_to_add = true
}
}
if need_to_add {
hashes_similarity . insert ( other_hash , ( hash_to_check , similarity ) ) ;
if let Some ( number_of_children ) = hashes_parents . get_mut ( hash_to_check ) {
* number_of_children + = 1 ;
} else {
hashes_parents . insert ( hash_to_check , 1 ) ;
}
}
// ENND
}
}
#[ cfg(debug_assertions) ]
debug_check_for_duplicated_things ( hashes_parents . clone ( ) , hashes_similarity . clone ( ) , all_hashed_images . clone ( ) , "LATTER" ) ;
// Collecting results
for ( parent_hash , child_number ) in hashes_parents {
if child_number > 0 {
let vec_fe = all_hashed_images . get ( parent_hash ) . unwrap ( ) . clone ( ) ;
collected_similar_images . insert ( parent_hash . clone ( ) , vec_fe ) ;
}
}
collected_similar_images . get_mut ( & hash ) . unwrap ( ) . append ( & mut vec_fe ) ;
} ) ;
for ( child_hash , ( parent_hash , similarity ) ) in hashes_similarity {
let mut vec_fe = all_hashed_images . get ( child_hash ) . unwrap ( ) . clone ( ) ;
for mut fe in & mut vec_fe {
fe . similarity = similarity ;
}
collected_similar_images . get_mut ( parent_hash ) . unwrap ( ) . append ( & mut vec_fe ) ;
}
}
}
progress_thread_run . store ( false , Ordering ::Relaxed ) ;
progress_thread_handle . join ( ) . unwrap ( ) ;
// Validating if group contains duplicated results
#[ cfg(debug_assertions) ]
{
let mut result_hashset : HashSet < String > = Default ::default ( ) ;
let mut found = false ;
for ( _hash , vec_file_entry ) in collected_similar_images . iter ( ) {
if vec_file_entry . is_empty ( ) {
println! ( "Empty Element {:?}" , vec_file_entry ) ;
found = true ;
continue ;
}
if vec_file_entry . len ( ) = = 1 {
println! ( "Single Element {:?}" , vec_file_entry ) ;
found = true ;
continue ;
}
for file_entry in vec_file_entry {
let st = file_entry . path . to_string_lossy ( ) . to_string ( ) ;
if result_hashset . contains ( & st ) {
found = true ;
println! ( "Invalid Element {}" , st ) ;
println! ( " Duplicate d Element {}", st ) ;
} else {
result_hashset . insert ( st ) ;
}
@ -1148,14 +1211,14 @@ pub fn load_hashes_from_file(
fn get_cache_file ( hash_size : & u8 , hash_alg : & HashAlg , image_filter : & FilterType ) -> String {
format! (
"cache_similar_images_{}_{}_{} .bin",
"cache_similar_images_{}_{}_{} _50 .bin",
hash_size ,
convert_algorithm_to_string ( hash_alg ) ,
convert_filters_to_string ( image_filter ) ,
)
}
pub fn get_string_from_similarity ( similarity : & Similarity , hash_size : u8 ) -> String {
pub fn get_string_from_similarity ( similarity : & u32 , hash_size : u8 ) -> String {
let index_preset = match hash_size {
8 = > 0 ,
16 = > 1 ,
@ -1164,52 +1227,44 @@ pub fn get_string_from_similarity(similarity: &Similarity, hash_size: u8) -> Str
_ = > panic! ( ) ,
} ;
match similarity {
// Similarity::None => {
// panic!()
// }
Similarity ::Similar ( h ) = > {
// #[cfg(debug_assertions)]
// {
// if *h <= SIMILAR_VALUES[index_preset][0] {
// format!("{} {}", flc!("core_similarity_very_high"), *h)
// } else if *h <= SIMILAR_VALUES[index_preset][1] {
// format!("{} {}", flc!("core_similarity_high"), *h)
// } else if *h <= SIMILAR_VALUES[index_preset][2] {
// format!("{} {}", flc!("core_similarity_medium"), *h)
// } else if *h <= SIMILAR_VALUES[index_preset][3] {
// format!("{} {}", flc!("core_similarity_small"), *h)
// } else if *h <= SIMILAR_VALUES[index_preset][4] {
// format!("{} {}", flc!("core_similarity_very_small"), *h)
// } else if *h <= SIMILAR_VALUES[index_preset][5] {
// format!("{} {}", flc!("core_similarity_minimal"), *h)
// } else {
// panic!();
// }
// }
// #[cfg(not(debug_assertions))]
{
if * h < = SIMILAR_VALUES [ index_preset ] [ 0 ] {
flc ! ( "core_similarity_very_high" )
} else if * h < = SIMILAR_VALUES [ index_preset ] [ 1 ] {
flc ! ( "core_similarity_high" )
} else if * h < = SIMILAR_VALUES [ index_preset ] [ 2 ] {
flc ! ( "core_similarity_medium" )
} else if * h < = SIMILAR_VALUES [ index_preset ] [ 3 ] {
flc ! ( "core_similarity_small" )
} else if * h < = SIMILAR_VALUES [ index_preset ] [ 4 ] {
flc ! ( "core_similarity_very_small" )
} else if * h < = SIMILAR_VALUES [ index_preset ] [ 5 ] {
flc ! ( "core_similarity_minimal" )
} else {
panic! ( ) ;
}
}
}
// #[cfg(debug_assertions)]
// {
// if *similarity <= SIMILAR_VALUES[index_preset][0] {
// format!("{} {}", flc!("core_similarity_very_high"), *similarity)
// } else if *similarity <= SIMILAR_VALUES[index_preset][1] {
// format!("{} {}", flc!("core_similarity_high"), *similarity)
// } else if *similarity <= SIMILAR_VALUES[index_preset][2] {
// format!("{} {}", flc!("core_similarity_medium"), *similarity)
// } else if *similarity <= SIMILAR_VALUES[index_preset][3] {
// format!("{} {}", flc!("core_similarity_small"), *similarity)
// } else if *similarity <= SIMILAR_VALUES[index_preset][4] {
// format!("{} {}", flc!("core_similarity_very_small"), *similarity)
// } else if *similarity <= SIMILAR_VALUES[index_preset][5] {
// format!("{} {}", flc!("core_similarity_minimal"), *similarity)
// } else {
// panic!();
// }
// }
// #[cfg(not(debug_assertions))]
if * similarity < = SIMILAR_VALUES [ index_preset ] [ 0 ] {
flc ! ( "core_similarity_very_high" )
} else if * similarity < = SIMILAR_VALUES [ index_preset ] [ 1 ] {
flc ! ( "core_similarity_high" )
} else if * similarity < = SIMILAR_VALUES [ index_preset ] [ 2 ] {
flc ! ( "core_similarity_medium" )
} else if * similarity < = SIMILAR_VALUES [ index_preset ] [ 3 ] {
flc ! ( "core_similarity_small" )
} else if * similarity < = SIMILAR_VALUES [ index_preset ] [ 4 ] {
flc ! ( "core_similarity_very_small" )
} else if * similarity < = SIMILAR_VALUES [ index_preset ] [ 5 ] {
flc ! ( "core_similarity_minimal" )
} else {
panic! ( ) ;
}
}
pub fn return_similarity_from_similarity_preset ( similarity_preset : & SimilarityPreset , hash_size : u8 ) -> Similarity {
pub fn return_similarity_from_similarity_preset ( similarity_preset : & SimilarityPreset , hash_size : u8 ) -> u32 {
let index_preset = match hash_size {
8 = > 0 ,
16 = > 1 ,
@ -1218,12 +1273,12 @@ pub fn return_similarity_from_similarity_preset(similarity_preset: &SimilarityPr
_ = > panic! ( ) ,
} ;
match similarity_preset {
SimilarityPreset ::VeryHigh = > S imilarity::Similar ( S IMILAR_VALUES[ index_preset ] [ 0 ] ) ,
SimilarityPreset ::High = > S imilarity::Similar ( S IMILAR_VALUES[ index_preset ] [ 1 ] ) ,
SimilarityPreset ::Medium = > S imilarity::Similar ( S IMILAR_VALUES[ index_preset ] [ 2 ] ) ,
SimilarityPreset ::Small = > S imilarity::Similar ( S IMILAR_VALUES[ index_preset ] [ 3 ] ) ,
SimilarityPreset ::VerySmall = > S imilarity::Similar ( S IMILAR_VALUES[ index_preset ] [ 4 ] ) ,
SimilarityPreset ::Minimal = > S imilarity::Similar ( S IMILAR_VALUES[ index_preset ] [ 5 ] ) ,
SimilarityPreset ::VeryHigh = > S IMILAR_VALUES[ index_preset ] [ 0 ] ,
SimilarityPreset ::High = > S IMILAR_VALUES[ index_preset ] [ 1 ] ,
SimilarityPreset ::Medium = > S IMILAR_VALUES[ index_preset ] [ 2 ] ,
SimilarityPreset ::Small = > S IMILAR_VALUES[ index_preset ] [ 3 ] ,
SimilarityPreset ::VerySmall = > S IMILAR_VALUES[ index_preset ] [ 4 ] ,
SimilarityPreset ::Minimal = > S IMILAR_VALUES[ index_preset ] [ 5 ] ,
SimilarityPreset ::None = > panic! ( "" ) ,
}
}
@ -1290,3 +1345,44 @@ pub fn test_image_conversion_speed() {
}
}
}
#[ allow(dead_code) ]
fn debug_check_for_duplicated_things (
hashes_parents : HashMap < & Vec < u8 > , u32 > ,
hashes_similarity : HashMap < & Vec < u8 > , ( & Vec < u8 > , u32 ) > ,
all_hashed_images : HashMap < Vec < u8 > , Vec < FileEntry > > ,
numm : & str ,
) {
let mut hashmap_hashes : HashSet < _ > = Default ::default ( ) ;
let mut hashmap_names : HashSet < _ > = Default ::default ( ) ;
for ( hash , number_of_children ) in & hashes_parents {
if * number_of_children > 0 {
if hashmap_hashes . contains ( * hash ) {
println! ( "------1--HASH--{} {:?}" , numm , all_hashed_images . get ( * hash ) . unwrap ( ) ) ;
}
hashmap_hashes . insert ( hash . to_vec ( ) ) ;
for i in all_hashed_images . get ( * hash ) . unwrap ( ) {
let name = i . path . to_string_lossy ( ) . to_string ( ) ;
if hashmap_names . contains ( & name ) {
println! ( "------1--NAME--{} {:?}" , numm , name ) ;
}
hashmap_names . insert ( name ) ;
}
}
}
for hash in hashes_similarity . keys ( ) {
if hashmap_hashes . contains ( * hash ) {
println! ( "------2--HASH--{} {:?}" , numm , all_hashed_images . get ( * hash ) . unwrap ( ) ) ;
}
hashmap_hashes . insert ( hash . to_vec ( ) ) ;
for i in all_hashed_images . get ( * hash ) . unwrap ( ) {
let name = i . path . to_string_lossy ( ) . to_string ( ) ;
if hashmap_names . contains ( & name ) {
println! ( "------2--NAME--{} {:?}" , numm , name ) ;
}
hashmap_names . insert ( name ) ;
}
}
}