@ -5,138 +5,168 @@
extern crate libc ;
extern crate rustc_serialize ;
#[ cfg(feature = " bench " ) ]
extern crate test ;
pub mod hash ;
mod cache ;
pub mod cache ;
use std ::path ::Path ;
use std ::ffi ::CStr ;
use cache ::Cache ;
static LIB_CACHE : Cache < 'static > = Cache {
cache_dir : cache ::CACHE_DIR ,
use_cache : true ,
} ;
pub struct PIHash < 'a > {
cache : Option < Box < Cache < 'a > > >
}
/**
* Prepare the library for work .
*
* Not performing this step may cause parts to fail .
* /
#[ no_mangle ]
pub extern "C" fn init ( ) {
match LIB_CACHE . init ( ) {
Ok ( _ ) = > { }
Err ( e ) = > println ! ( "Error: {}" , e ) ,
}
impl < 'a > PIHash < 'a > {
/**
* Create a new pihash library , and initialize a cache of a path is passed . If none is passed then no cache is initialized or used with the library
* /
pub fn new ( cache_path : Option < & 'a str > ) -> PIHash < 'a > {
match cache_path {
Some ( path ) = > {
let cache = Cache { cache_dir : path , use_cache : true } ;
match cache . init ( ) {
Ok ( _ ) = > PIHash { cache : Some ( Box ::new ( cache ) ) } ,
Err ( e ) = > {
println ! ( "Error creating library with cache: {}" , e ) ;
PIHash { cache : None }
}
}
} ,
None = > PIHash { cache : None } ,
}
}
pub fn get_perceptual_hash ( & self , path : & Path , precision : & hash ::Precision , hash_type : & hash ::HashType ) -> u64 {
hash ::get_perceptual_hash ( & path , & precision , & hash_type , & self . cache )
}
pub fn get_phashes ( & self , path : & 'a Path ) -> hash ::PerceptualHashes {
hash ::get_perceptual_hashes ( path , & hash ::Precision ::Medium , & self . cache )
}
pub fn get_ahash ( & self , path : & Path ) -> u64 {
hash ::get_perceptual_hash ( & path ,
& hash ::Precision ::Medium ,
& hash ::HashType ::AHash ,
& self . cache )
}
pub fn get_dhash ( & self , path : & Path ) -> u64 {
hash ::get_perceptual_hash ( & path ,
& hash ::Precision ::Medium ,
& hash ::HashType ::DHash ,
& self . cache )
}
pub fn get_phash ( & self , path : & Path ) -> u64 {
hash ::get_perceptual_hash ( & path ,
& hash ::Precision ::Medium ,
& hash ::HashType ::DHash ,
& self . cache )
}
}
/**
* Teardown for the library
* Get the Hamming Distance between two hashes .
* Represents the absolute difference between two numbers .
* /
#[ no_mangle ]
pub extern "C" fn teardown ( ) {
match LIB_CACHE . clean ( ) {
Ok ( _ ) = > { }
Err ( e ) = > println ! ( "Error: {}" , e ) ,
}
}
pub fn get_phashes ( path : & Path ) -> hash ::PerceptualHashes {
hash ::get_perceptual_hashes ( path , & hash ::Precision ::Medium , & LIB_CACHE )
}
pub fn get_ahash ( path : & Path ) -> u64 {
hash ::get_perceptual_hash ( & path ,
& hash ::Precision ::Medium ,
& hash ::HashType ::AHash ,
& LIB_CACHE )
}
pub fn get_dhash ( path : & Path ) -> u64 {
hash ::get_perceptual_hash ( & path ,
& hash ::Precision ::Medium ,
& hash ::HashType ::DHash ,
& LIB_CACHE )
}
pub fn get_phash ( path : & Path ) -> u64 {
hash ::get_perceptual_hash ( & path ,
& hash ::Precision ::Medium ,
& hash ::HashType ::DHash ,
& LIB_CACHE )
}
pub fn get_hamming_distance ( hash1 : u64 , hash2 : u64 ) -> u64 {
hash ::calculate_hamming_distance ( hash1 , hash2 )
}
// External proxies for the get_*hash methods //
#[ no_mangle ]
pub extern "C" fn ext_get_ahash ( path_char : * const libc ::c_char ) -> libc ::uint64_t {
unsafe {
let path_str = CStr ::from_ptr ( path_char ) ;
let image_path = match path_str . to_str ( ) {
Ok ( result ) = > result ,
Err ( e ) = > {
println ! ( "Error: {}. Unable to parse '{}'" ,
e ,
to_hex_string ( path_str . to_bytes ( ) ) ) ;
panic ! ( "Unable to parse path" )
}
} ;
let path = Path ::new ( & image_path ) ;
get_ahash ( & path )
}
}
#[ no_mangle ]
pub extern "C" fn ext_get_dhash ( path_char : * const libc ::c_char ) -> libc ::uint64_t {
unsafe {
let path_str = CStr ::from_ptr ( path_char ) ;
let image_path = match path_str . to_str ( ) {
Ok ( result ) = > result ,
Err ( e ) = > {
println ! ( "Error: {}. Unable to parse '{}'" ,
e ,
to_hex_string ( path_str . to_bytes ( ) ) ) ;
panic ! ( "Unable to parse path" )
}
} ;
let path = Path ::new ( & image_path ) ;
get_dhash ( & path )
}
}
#[ no_mangle ]
pub extern "C" fn ext_get_phash ( path_char : * const libc ::c_char ) -> libc ::uint64_t {
unsafe {
let path_str = CStr ::from_ptr ( path_char ) ;
let image_path = match path_str . to_str ( ) {
Ok ( result ) = > result ,
Err ( e ) = > {
println ! ( "Error: {}. Unable to parse '{}'" ,
e ,
to_hex_string ( path_str . to_bytes ( ) ) ) ;
panic ! ( "Unable to parse path" )
}
} ;
let path = Path ::new ( & image_path ) ;
get_phash ( & path )
}
}
fn to_hex_string ( bytes : & [ u8 ] ) -> String {
println ! ( "length: {}" , bytes . len ( ) ) ;
let mut strs : Vec < String > = Vec ::new ( ) ;
for byte in bytes {
// println!("{:02x}", byte);
strs . push ( format ! ( "{:02x}" , byte ) ) ;
}
strs . join ( "\\x" )
}
// /**
// * Prepare the library for work.
// *
// * Not performing this step may cause parts to fail.
// */
// #[no_mangle]
// pub extern "C" fn init() {
// match LIB_CACHE.init() {
// Ok(_) => {}
// Err(e) => println!("Error: {}", e),
// }
// }
// /**
// * Teardown for the library
// */
// #[no_mangle]
// pub extern "C" fn teardown() {
// match LIB_CACHE.clean() {
// Ok(_) => {}
// Err(e) => println!("Error: {}", e),
// }
// }
// #[no_mangle]
// pub extern "C" fn ext_get_ahash(path_char: *const libc::c_char) -> libc::uint64_t {
// unsafe {
// let path_str = CStr::from_ptr(path_char);
// let image_path = match path_str.to_str() {
// Ok(result) => result,
// Err(e) => {
// println!("Error: {}. Unable to parse '{}'",
// e,
// to_hex_string(path_str.to_bytes()));
// panic!("Unable to parse path")
// }
// };
// let path = Path::new(&image_path);
// get_ahash(&path)
// }
// }
// #[no_mangle]
// pub extern "C" fn ext_get_dhash(path_char: *const libc::c_char) -> libc::uint64_t {
// unsafe {
// let path_str = CStr::from_ptr(path_char);
// let image_path = match path_str.to_str() {
// Ok(result) => result,
// Err(e) => {
// println!("Error: {}. Unable to parse '{}'",
// e,
// to_hex_string(path_str.to_bytes()));
// panic!("Unable to parse path")
// }
// };
// let path = Path::new(&image_path);
// get_dhash(&path)
// }
// }
// #[no_mangle]
// pub extern "C" fn ext_get_phash(path_char: *const libc::c_char) -> libc::uint64_t {
// unsafe {
// let path_str = CStr::from_ptr(path_char);
// let image_path = match path_str.to_str() {
// Ok(result) => result,
// Err(e) => {
// println!("Error: {}. Unable to parse '{}'",
// e,
// to_hex_string(path_str.to_bytes()));
// panic!("Unable to parse path")
// }
// };
// let path = Path::new(&image_path);
// get_phash(&path)
// }
// }
// fn to_hex_string(bytes: &[u8]) -> String {
// println!("length: {}", bytes.len());
// let mut strs: Vec<String> = Vec::new();
// for byte in bytes {
// // println!("{:02x}", byte);
// strs.push(format!("{:02x}", byte));
// }
// strs.join("\\x")
// }
// Module for the tests
//
@ -146,6 +176,10 @@ mod tests {
use std ::fs ;
use std ::path ::Path ;
use hash ;
use cache ;
use super ::PIHash ;
#[ cfg(feature = " bench " ) ]
use super ::test ::Bencher ;
#[ test ]
fn test_can_get_test_images ( ) {
@ -179,13 +213,13 @@ mod tests {
fn test_imageset_hash ( hash_type : hash ::HashType ,
hash_precision : hash ::Precision ,
image_paths : [ & Path ; 3 ] ,
image_hashes : [ u64 ; 3 ] ) {
image_hashes : [ u64 ; 3 ] ,
lib : & PIHash ) {
for index in 0 . . image_paths . len ( ) {
let image_path = image_paths [ index ] ;
let calculated_hash = hash ::get_perceptual_hash ( & image_path ,
let calculated_hash = lib . get_perceptual_hash ( & image_path ,
& hash_precision ,
& hash_type ,
& super ::LIB_CACHE ) ;
& hash_type ) ;
println ! ( "Image hashes for '{}': expected: {} actual: {}" ,
image_path . to_str ( ) . unwrap ( ) ,
image_hashes [ index ] ,
@ -196,8 +230,8 @@ mod tests {
#[ test ]
fn test_confirm_ahash_results ( ) {
// Prep_Cache
super ::init ( ) ;
// Prep_library
let lib = PIHash ::new ( Some ( cache ::DEFAULT_CACHE_DIR ) ) ;
// Sample_01 tests
let sample_01_images : [ & Path ; 3 ] = [ & Path ::new ( "./test_images/sample_01_large.jpg" ) ,
@ -207,7 +241,8 @@ mod tests {
test_imageset_hash ( hash ::HashType ::AHash ,
hash ::Precision ::Medium ,
sample_01_images ,
sample_01_hashes ) ;
sample_01_hashes ,
& lib ) ;
// Sample_02 tests
let sample_02_images : [ & Path ; 3 ] = [ & Path ::new ( "./test_images/sample_02_large.jpg" ) ,
@ -219,7 +254,8 @@ mod tests {
test_imageset_hash ( hash ::HashType ::AHash ,
hash ::Precision ::Medium ,
sample_02_images ,
sample_02_hashes ) ;
sample_02_hashes ,
& lib ) ;
// Sample_03 tests
let sample_03_images : [ & Path ; 3 ] = [ & Path ::new ( "./test_images/sample_03_large.jpg" ) ,
@ -231,7 +267,8 @@ mod tests {
test_imageset_hash ( hash ::HashType ::AHash ,
hash ::Precision ::Medium ,
sample_03_images ,
sample_03_hashes ) ;
sample_03_hashes ,
& lib ) ;
// Sample_04 tests
let sample_04_images : [ & Path ; 3 ] = [ & Path ::new ( "./test_images/sample_04_large.jpg" ) ,
@ -243,7 +280,8 @@ mod tests {
test_imageset_hash ( hash ::HashType ::AHash ,
hash ::Precision ::Medium ,
sample_04_images ,
sample_04_hashes ) ;
sample_04_hashes ,
& lib ) ;
// Clean_Cache
// super::teardown();
@ -251,8 +289,8 @@ mod tests {
#[ test ]
fn test_confirm_dhash_results ( ) {
// Prep_Cache
super ::init ( ) ;
// Prep_library
let lib = PIHash ::new ( Some ( cache ::DEFAULT_CACHE_DIR ) ) ;
// Sample_01 tests
let sample_01_images : [ & Path ; 3 ] = [ & Path ::new ( "./test_images/sample_01_large.jpg" ) ,
@ -264,7 +302,8 @@ mod tests {
test_imageset_hash ( hash ::HashType ::DHash ,
hash ::Precision ::Medium ,
sample_01_images ,
sample_01_hashes ) ;
sample_01_hashes ,
& lib ) ;
// Sample_02 tests
let sample_02_images : [ & Path ; 3 ] = [ & Path ::new ( "./test_images/sample_02_large.jpg" ) ,
@ -276,7 +315,8 @@ mod tests {
test_imageset_hash ( hash ::HashType ::DHash ,
hash ::Precision ::Medium ,
sample_02_images ,
sample_02_hashes ) ;
sample_02_hashes ,
& lib ) ;
// Sample_03 tests
let sample_03_images : [ & Path ; 3 ] = [ & Path ::new ( "./test_images/sample_03_large.jpg" ) ,
@ -288,7 +328,8 @@ mod tests {
test_imageset_hash ( hash ::HashType ::DHash ,
hash ::Precision ::Medium ,
sample_03_images ,
sample_03_hashes ) ;
sample_03_hashes ,
& lib ) ;
// Sample_04 tests
let sample_04_images : [ & Path ; 3 ] = [ & Path ::new ( "./test_images/sample_04_large.jpg" ) ,
@ -300,7 +341,8 @@ mod tests {
test_imageset_hash ( hash ::HashType ::DHash ,
hash ::Precision ::Medium ,
sample_04_images ,
sample_04_hashes ) ;
sample_04_hashes ,
& lib ) ;
// Clean_Cache
// super::teardown();
@ -308,8 +350,8 @@ mod tests {
#[ test ]
fn test_confirm_phash_results ( ) {
// Prep_Cache
super ::init ( ) ;
// Prep_library
let lib = PIHash ::new ( Some ( cache ::DEFAULT_CACHE_DIR ) ) ;
// Sample_01 tests
let sample_01_images : [ & Path ; 3 ] = [ & Path ::new ( "./test_images/sample_01_large.jpg" ) ,
@ -319,7 +361,8 @@ mod tests {
test_imageset_hash ( hash ::HashType ::PHash ,
hash ::Precision ::Medium ,
sample_01_images ,
sample_01_hashes ) ;
sample_01_hashes ,
& lib ) ;
// Sample_02 tests
let sample_02_images : [ & Path ; 3 ] = [ & Path ::new ( "./test_images/sample_02_large.jpg" ) ,
@ -331,7 +374,8 @@ mod tests {
test_imageset_hash ( hash ::HashType ::PHash ,
hash ::Precision ::Medium ,
sample_02_images ,
sample_02_hashes ) ;
sample_02_hashes ,
& lib ) ;
// Sample_03 tests
let sample_03_images : [ & Path ; 3 ] = [ & Path ::new ( "./test_images/sample_03_large.jpg" ) ,
@ -343,7 +387,8 @@ mod tests {
test_imageset_hash ( hash ::HashType ::PHash ,
hash ::Precision ::Medium ,
sample_03_images ,
sample_03_hashes ) ;
sample_03_hashes ,
& lib ) ;
// Sample_04 tests
let sample_04_images : [ & Path ; 3 ] = [ & Path ::new ( "./test_images/sample_04_large.jpg" ) ,
@ -355,9 +400,75 @@ mod tests {
test_imageset_hash ( hash ::HashType ::PHash ,
hash ::Precision ::Medium ,
sample_04_images ,
sample_04_hashes ) ;
sample_04_hashes ,
& lib ) ;
// Clean_Cache
// super::teardown();
}
#[ cfg(feature = " bench " ) ]
#[ bench ]
fn bench_with_cache ( bench : & mut Bencher ) -> ( ) {
// Prep_library
let lib = PIHash ::new ( Some ( cache ::DEFAULT_CACHE_DIR ) ) ;
// Setup the caches to make sure we're good to properly bench
// All phashes so that the matricies are pulled from cache as well
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_01_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::PHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_02_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::PHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_03_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::PHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_04_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::PHash ) ;
bench . iter ( | | {
// Sample_01 Bench
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_01_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::AHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_01_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::DHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_01_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::PHash ) ;
// Sample_02 Bench
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_02_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::AHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_02_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::DHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_02_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::PHash ) ;
// Sample_03 Bench
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_02_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::AHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_02_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::DHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_02_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::PHash ) ;
// Sample_04 Bench
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_04_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::AHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_04_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::DHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_04_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::PHash ) ;
} )
}
#[ cfg(feature = " bench " ) ]
#[ bench ]
fn bench_without_cache ( bench : & mut Bencher ) -> ( ) {
// Prep_library
let lib = PIHash ::new ( None ) ;
bench . iter ( | | {
// Sample_01 Bench
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_01_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::AHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_01_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::DHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_01_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::PHash ) ;
// Sample_02 Bench
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_02_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::AHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_02_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::DHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_02_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::PHash ) ;
// Sample_03 Bench
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_02_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::AHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_02_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::DHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_02_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::PHash ) ;
// Sample_04 Bench
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_04_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::AHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_04_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::DHash ) ;
lib . get_perceptual_hash ( & Path ::new ( "./test_images/sample_04_large.jpg" ) , & hash ::Precision ::Medium , & hash ::HashType ::PHash ) ;
} )
}
}