Browse Source

Remove lifetimes and internalize copies of strings

* Broke testing out into more distinct tests
master
Drew Short 5 years ago
parent
commit
8076a5281f
  1. 3
      FFI-tests/ffi_test.py
  2. 37
      src/cache.rs
  3. 10
      src/hash/ahash.rs
  4. 10
      src/hash/dhash.rs
  5. 49
      src/hash/mod.rs
  6. 14
      src/hash/phash.rs
  7. 252
      src/lib.rs
  8. 22
      src/main.rs

3
FFI-tests/ffi_test.py

@ -51,6 +51,7 @@ class PIHashes(Structure):
# Setting the ctypes return type references for the foreign functions # Setting the ctypes return type references for the foreign functions
# returns a pointer to the library that we'll need to pass to all function calls # returns a pointer to the library that we'll need to pass to all function calls
lib.ext_init.restype = c_void_p lib.ext_init.restype = c_void_p
lib.ext_init.argtypes = [c_char_p]
# Returns a longlong hash, takes a pointer and a string # Returns a longlong hash, takes a pointer and a string
lib.ext_get_ahash.restype = c_ulonglong lib.ext_get_ahash.restype = c_ulonglong
lib.ext_get_ahash.argtypes = [c_void_p, c_char_p] lib.ext_get_ahash.argtypes = [c_void_p, c_char_p]
@ -65,7 +66,7 @@ lib.ext_free_phashes.argtypes = [c_void_p]
lib.ext_free.argtypes = [c_void_p] lib.ext_free.argtypes = [c_void_p]
#initialize the library #initialize the library
lib_struct = lib.ext_init("./.hash_cache".encode(encoding="utf-8"))
lib_struct = lib.ext_init("./.hash_cache".encode('utf-8'))
#print("Pointer to lib_struct: ", lib_struct) #print("Pointer to lib_struct: ", lib_struct)

37
src/cache.rs

@ -58,26 +58,26 @@ impl PartialEq<CacheMetadata> for CacheMetadata {
* Structure to hold implementation of the cache * Structure to hold implementation of the cache
*/ */
#[repr(C)] #[repr(C)]
pub struct Cache<'a> {
pub cache_dir: &'a str,
pub struct Cache {
pub cache_dir: String,
pub use_cache: bool, pub use_cache: bool,
} }
impl<'a> Default for Cache<'a> {
fn default() -> Cache<'a> {
impl Default for Cache {
fn default() -> Cache {
Cache { Cache {
cache_dir: DEFAULT_CACHE_DIR,
cache_dir: String::from(DEFAULT_CACHE_DIR),
use_cache: true, use_cache: true,
} }
} }
} }
impl<'a> Cache<'a> {
impl Cache {
/** /**
* Create the required directories for the cache * Create the required directories for the cache
*/ */
pub fn init(&self) -> Result<(), Error> { pub fn init(&self) -> Result<(), Error> {
match create_dir_all(self.cache_dir) {
match create_dir_all(&self.cache_dir) {
Ok(_) => { Ok(_) => {
let metadata_path_str = format!("{}/{}", self.cache_dir, CACHE_METADATA_FILE); let metadata_path_str = format!("{}/{}", self.cache_dir, CACHE_METADATA_FILE);
let metadata_path = Path::new(&metadata_path_str); let metadata_path = Path::new(&metadata_path_str);
@ -97,8 +97,8 @@ impl<'a> Cache<'a> {
// If they match, continue // If they match, continue
if current_metadata != loaded_metadata { if current_metadata != loaded_metadata {
// If they don't wipe the cache to start new // If they don't wipe the cache to start new
match remove_dir_all(self.cache_dir) {
Ok(_) => match create_dir_all(self.cache_dir) {
match remove_dir_all(&self.cache_dir) {
Ok(_) => match create_dir_all(&self.cache_dir) {
Ok(_) => (), Ok(_) => (),
Err(e) => println!("Error: {}", e), Err(e) => println!("Error: {}", e),
}, },
@ -130,7 +130,7 @@ impl<'a> Cache<'a> {
* Clean the cache directory completely * Clean the cache directory completely
*/ */
pub fn clean(&self) -> Result<(), Error> { pub fn clean(&self) -> Result<(), Error> {
remove_dir_all(self.cache_dir)
remove_dir_all(&self.cache_dir)
} }
/** /**
@ -170,8 +170,11 @@ impl<'a> Cache<'a> {
); );
let cache_dir_str = let cache_dir_str =
format!("{}/image/{}x{}/{}", self.cache_dir, size, size, &sha1[..10]); format!("{}/image/{}x{}/{}", self.cache_dir, size, size, &sha1[..10]);
// println!("Saving: {}", cache_path_str);
match create_dir_all(cache_dir_str) {
println!("Test");
println!("{}", DEFAULT_CACHE_DIR);
println!("{}", &self.cache_dir);
// println!("Saving: {}", &cache_path_str);
match create_dir_all(&cache_dir_str) {
Ok(_) => { Ok(_) => {
let file_path = Path::new(&cache_path_str); let file_path = Path::new(&cache_path_str);
match File::create(file_path) { match File::create(file_path) {
@ -185,10 +188,16 @@ impl<'a> Cache<'a> {
} }
} }
} }
Err(e) => return Err(e),
Err(e) => {
println!("Unable to create file {:?}", file_path);
return Err(e);
}
} }
} }
Err(e) => return Err(e),
Err(e) => {
println!("Unable to create directory {:?}", &cache_dir_str);
return Err(e);
}
} }
} }
Err(e) => { Err(e) => {

10
src/hash/ahash.rs

@ -11,19 +11,19 @@ use super::{HashType, PerceptualHash, Precision, PreparedImage};
use super::image::GenericImageView; use super::image::GenericImageView;
pub struct AHash<'a> {
prepared_image: Box<PreparedImage<'a>>,
pub struct AHash {
prepared_image: Box<PreparedImage>,
} }
impl<'a> AHash<'a> {
pub fn new(path: &'a Path, precision: &Precision, cache: &Option<Cache>) -> Self {
impl AHash {
pub fn new(path: &Path, precision: &Precision, cache: &Option<Cache>) -> Self {
AHash { AHash {
prepared_image: Box::new(prepare_image(&path, &HashType::AHash, &precision, cache)), prepared_image: Box::new(prepare_image(&path, &HashType::AHash, &precision, cache)),
} }
} }
} }
impl<'a> PerceptualHash for AHash<'a> {
impl PerceptualHash for AHash {
/** /**
* Calculate the ahash of the provided prepared image. * Calculate the ahash of the provided prepared image.
* *

10
src/hash/dhash.rs

@ -11,19 +11,19 @@ use super::{HashType, PerceptualHash, Precision, PreparedImage};
use super::image::GenericImageView; use super::image::GenericImageView;
pub struct DHash<'a> {
prepared_image: Box<PreparedImage<'a>>,
pub struct DHash {
prepared_image: Box<PreparedImage>,
} }
impl<'a> DHash<'a> {
pub fn new(path: &'a Path, precision: &Precision, cache: &Option<Cache>) -> Self {
impl DHash {
pub fn new(path: &Path, precision: &Precision, cache: &Option<Cache>) -> Self {
DHash { DHash {
prepared_image: Box::new(prepare_image(&path, &HashType::DHash, &precision, cache)), prepared_image: Box::new(prepare_image(&path, &HashType::DHash, &precision, cache)),
} }
} }
} }
impl<'a> PerceptualHash for DHash<'a> {
impl PerceptualHash for DHash {
/** /**
* Calculate the dhash of the provided prepared image * Calculate the dhash of the provided prepared image
* *

49
src/hash/mod.rs

@ -6,12 +6,14 @@
extern crate dft; extern crate dft;
extern crate image; extern crate image;
use self::image::FilterType;
use cache::Cache;
use std::f64; use std::f64;
use std::fmt; use std::fmt;
use std::path::Path; use std::path::Path;
use cache::Cache;
use self::image::FilterType;
mod ahash; mod ahash;
mod dhash; mod dhash;
mod phash; mod phash;
@ -42,23 +44,23 @@ const HAMMING_DISTANCE_SIMILARITY_LIMIT: u64 = 5u64;
/** /**
* Prepared image that can be used to generate hashes * Prepared image that can be used to generate hashes
*/ */
pub struct PreparedImage<'a> {
orig_path: &'a str,
pub struct PreparedImage {
orig_path: String,
image: Option<image::DynamicImage>, image: Option<image::DynamicImage>,
} }
/** /**
* Wraps the various perceptual hashes * Wraps the various perceptual hashes
*/ */
pub struct PerceptualHashes<'a> {
pub orig_path: &'a str,
pub struct PerceptualHashes {
pub orig_path: String,
pub ahash: u64, pub ahash: u64,
pub dhash: u64, pub dhash: u64,
pub phash: u64, pub phash: u64,
} }
impl<'a> PerceptualHashes<'a> {
pub fn similar(&self, other: &'a PerceptualHashes<'a>) -> bool {
impl PerceptualHashes {
pub fn similar(&self, other: &PerceptualHashes) -> bool {
if self.orig_path != other.orig_path if self.orig_path != other.orig_path
&& calculate_hamming_distance(self.ahash, other.ahash) && calculate_hamming_distance(self.ahash, other.ahash)
<= HAMMING_DISTANCE_SIMILARITY_LIMIT <= HAMMING_DISTANCE_SIMILARITY_LIMIT
@ -82,6 +84,7 @@ impl<'a> PerceptualHashes<'a> {
* High aims for 128 bit precision * High aims for 128 bit precision
*/ */
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Copy, Clone)]
pub enum Precision { pub enum Precision {
Low, Low,
Medium, Medium,
@ -89,7 +92,6 @@ pub enum Precision {
} }
// Get the size of the required image // Get the size of the required image
//
impl Precision { impl Precision {
fn get_size(&self) -> u32 { fn get_size(&self) -> u32 {
match *self { match *self {
@ -103,6 +105,7 @@ impl Precision {
/** /**
* Types of hashes supported * Types of hashes supported
*/ */
#[derive(Copy, Clone)]
pub enum HashType { pub enum HashType {
AHash, AHash,
DHash, DHash,
@ -141,12 +144,12 @@ pub trait PerceptualHash {
* A PreparedImage struct with the required information for performing hashing * A PreparedImage struct with the required information for performing hashing
* *
*/ */
pub fn prepare_image<'a>(
path: &'a Path,
pub fn prepare_image(
path: &Path,
hash_type: &HashType, hash_type: &HashType,
precision: &Precision, precision: &Precision,
cache: &Option<Cache>, cache: &Option<Cache>,
) -> PreparedImage<'a> {
) -> PreparedImage {
let image_path = path.to_str().unwrap(); let image_path = path.to_str().unwrap();
let size: u32 = match *hash_type { let size: u32 = match *hash_type {
HashType::PHash => precision.get_size() * 4, HashType::PHash => precision.get_size() * 4,
@ -154,10 +157,10 @@ pub fn prepare_image<'a>(
}; };
// Check if we have the already converted image in a cache and use that if possible. // Check if we have the already converted image in a cache and use that if possible.
match *cache { match *cache {
Some(ref c) => {
match c.get_image_from_cache(&path, size) {
Some(ref cache) => {
match cache.get_image_from_cache(&path, size) {
Some(image) => PreparedImage { Some(image) => PreparedImage {
orig_path: &*image_path,
orig_path: String::from(&*image_path),
image: Some(image), image: Some(image),
}, },
None => { None => {
@ -165,7 +168,7 @@ pub fn prepare_image<'a>(
// Oh, and save it in a cache // Oh, and save it in a cache
match processed_image.image { match processed_image.image {
Some(ref image) => { Some(ref image) => {
match c.put_image_in_cache(&path, size, &image) {
match cache.put_image_in_cache(&path, size, &image) {
Ok(_) => {} Ok(_) => {}
Err(e) => println!("Unable to store image in cache. {}", e), Err(e) => println!("Unable to store image in cache. {}", e),
}; };
@ -197,7 +200,7 @@ fn process_image(image_path: &str, size: u32) -> PreparedImage {
} }
}; };
PreparedImage { PreparedImage {
orig_path: &*image_path,
orig_path: String::from(&*image_path),
image, image,
} }
} }
@ -205,8 +208,8 @@ fn process_image(image_path: &str, size: u32) -> PreparedImage {
/** /**
* Get a specific HashType hash * Get a specific HashType hash
*/ */
pub fn get_perceptual_hash<'a>(
path: &'a Path,
pub fn get_perceptual_hash(
path: &Path,
precision: &Precision, precision: &Precision,
hash_type: &HashType, hash_type: &HashType,
cache: &Option<Cache>, cache: &Option<Cache>,
@ -221,17 +224,17 @@ pub fn get_perceptual_hash<'a>(
/** /**
* Get all perceptual hashes for an image * Get all perceptual hashes for an image
*/ */
pub fn get_perceptual_hashes<'a>(
path: &'a Path,
pub fn get_perceptual_hashes(
path: &Path,
precision: &Precision, precision: &Precision,
cache: &Option<Cache>, cache: &Option<Cache>,
) -> PerceptualHashes<'a> {
) -> PerceptualHashes {
let image_path = path.to_str().unwrap(); let image_path = path.to_str().unwrap();
let ahash = ahash::AHash::new(&path, &precision, &cache).get_hash(&cache); let ahash = ahash::AHash::new(&path, &precision, &cache).get_hash(&cache);
let dhash = dhash::DHash::new(&path, &precision, &cache).get_hash(&cache); let dhash = dhash::DHash::new(&path, &precision, &cache).get_hash(&cache);
let phash = phash::PHash::new(&path, &precision, &cache).get_hash(&cache); let phash = phash::PHash::new(&path, &precision, &cache).get_hash(&cache);
PerceptualHashes { PerceptualHashes {
orig_path: &*image_path,
orig_path: String::from(&*image_path),
ahash: ahash, ahash: ahash,
dhash: dhash, dhash: dhash,
phash: phash, phash: phash,

14
src/hash/phash.rs

@ -12,19 +12,19 @@ use super::image::{DynamicImage, GenericImageView, Pixel};
use super::prepare_image; use super::prepare_image;
use super::{HashType, PerceptualHash, Precision, PreparedImage}; use super::{HashType, PerceptualHash, Precision, PreparedImage};
pub struct PHash<'a> {
prepared_image: Box<PreparedImage<'a>>,
pub struct PHash {
prepared_image: Box<PreparedImage>,
} }
impl<'a> PHash<'a> {
pub fn new(path: &'a Path, precision: &Precision, cache: &Option<Cache>) -> Self {
impl PHash {
pub fn new(path: &Path, precision: &Precision, cache: &Option<Cache>) -> Self {
PHash { PHash {
prepared_image: Box::new(prepare_image(&path, &HashType::PHash, &precision, cache)), prepared_image: Box::new(prepare_image(&path, &HashType::PHash, &precision, cache)),
} }
} }
} }
impl<'a> PerceptualHash for PHash<'a> {
impl PerceptualHash for PHash {
/** /**
* Calculate the phash of the provided prepared image * Calculate the phash of the provided prepared image
* *
@ -45,14 +45,14 @@ impl<'a> PerceptualHash for PHash<'a> {
let data_matrix: Vec<Vec<f64>> = match *cache { let data_matrix: Vec<Vec<f64>> = match *cache {
Some(ref c) => { Some(ref c) => {
match c.get_matrix_from_cache( match c.get_matrix_from_cache(
&Path::new(self.prepared_image.orig_path),
&Path::new(&self.prepared_image.orig_path),
width as u32, width as u32,
) { ) {
Some(matrix) => matrix, Some(matrix) => matrix,
None => { None => {
let matrix = create_data_matrix(width, height, &image); let matrix = create_data_matrix(width, height, &image);
match c.put_matrix_in_cache( match c.put_matrix_in_cache(
&Path::new(self.prepared_image.orig_path),
&Path::new(&self.prepared_image.orig_path),
width as u32, width as u32,
&matrix, &matrix,
) { ) {

252
src/lib.rs

@ -20,20 +20,20 @@ pub mod cache;
pub mod hash; pub mod hash;
#[repr(C)] #[repr(C)]
pub struct PIHash<'a> {
cache: Option<Cache<'a>>,
pub struct PIHash {
cache: Option<Cache>,
} }
impl<'a> PIHash<'a> {
impl PIHash {
/** /**
* Create a new pihash library, and initialize a cache of a path is passed. * 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 * If none is passed then no cache is initialized or used with the library
*/ */
pub fn new(cache_path: Option<&'a str>) -> PIHash<'a> {
pub fn new(cache_path: Option<&str>) -> PIHash {
match cache_path { match cache_path {
Some(path) => { Some(path) => {
let cache = Cache { let cache = Cache {
cache_dir: path,
cache_dir: String::from(path),
use_cache: true, use_cache: true,
}; };
match cache.init() { match cache.init() {
@ -57,7 +57,7 @@ impl<'a> PIHash<'a> {
hash::get_perceptual_hash(&path, &precision, &hash_type, &self.cache) hash::get_perceptual_hash(&path, &precision, &hash_type, &self.cache)
} }
pub fn get_phashes(&self, path: &'a Path) -> hash::PerceptualHashes {
pub fn get_phashes(&self, path: &Path) -> hash::PerceptualHashes {
hash::get_perceptual_hashes(&path, &hash::Precision::Medium, &self.cache) hash::get_perceptual_hashes(&path, &hash::Precision::Medium, &self.cache)
} }
@ -218,6 +218,9 @@ mod tests {
use super::test::Bencher; use super::test::Bencher;
use super::PIHash; use super::PIHash;
thread_local!(static LIB: PIHash = PIHash::new(Some(cache::DEFAULT_CACHE_DIR)));
thread_local!(static NO_CACHE_LIB: PIHash = PIHash::new(None));
#[test] #[test]
fn test_can_get_test_images() { fn test_can_get_test_images() {
let paths = fs::read_dir(&Path::new("./test_images")).unwrap(); let paths = fs::read_dir(&Path::new("./test_images")).unwrap();
@ -288,37 +291,57 @@ mod tests {
} }
} }
#[test]
fn test_confirm_ahash_results() {
// Prep_library
let lib = PIHash::new(Some(cache::DEFAULT_CACHE_DIR));
let no_cache_lib = PIHash::new(None);
/**
* Test image set with and without caching
*/
fn test_image_set(
hash_type: hash::HashType,
hash_precision: hash::Precision,
max_hamming_distance: u64,
image_paths: [&Path; 3],
image_hashes: [u64; 3],
) {
LIB.with(|lib| {
test_imageset_hash(
hash_type,
hash_precision,
max_hamming_distance,
image_paths,
image_hashes,
lib,
);
});
NO_CACHE_LIB.with(|lib| {
test_imageset_hash(
hash_type,
hash_precision,
max_hamming_distance,
image_paths,
image_hashes,
lib,
);
});
}
// Sample_01 tests
#[test]
fn test_confirm_ahash_results_sample_01() {
let sample_01_images: [&Path; 3] = [ let sample_01_images: [&Path; 3] = [
&Path::new("./test_images/sample_01_large.jpg"), &Path::new("./test_images/sample_01_large.jpg"),
&Path::new("./test_images/sample_01_medium.jpg"), &Path::new("./test_images/sample_01_medium.jpg"),
&Path::new("./test_images/sample_01_small.jpg"), &Path::new("./test_images/sample_01_small.jpg"),
]; ];
let sample_01_hashes: [u64; 3] = [857051991849750, 857051991849750, 857051991849750]; let sample_01_hashes: [u64; 3] = [857051991849750, 857051991849750, 857051991849750];
test_imageset_hash(
test_image_set(
hash::HashType::AHash, hash::HashType::AHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
sample_01_images, sample_01_images,
sample_01_hashes, sample_01_hashes,
&lib,
);
test_imageset_hash(
hash::HashType::AHash,
hash::Precision::Medium,
0u64,
sample_01_images,
sample_01_hashes,
&no_cache_lib,
); );
}
// Sample_02 tests
#[test]
fn test_confirm_ahash_results_sample_02() {
let sample_02_images: [&Path; 3] = [ let sample_02_images: [&Path; 3] = [
&Path::new("./test_images/sample_02_large.jpg"), &Path::new("./test_images/sample_02_large.jpg"),
&Path::new("./test_images/sample_02_medium.jpg"), &Path::new("./test_images/sample_02_medium.jpg"),
@ -329,24 +352,17 @@ mod tests {
18446744073441116160, 18446744073441116160,
18446744073441116160, 18446744073441116160,
]; ];
test_imageset_hash(
test_image_set(
hash::HashType::AHash, hash::HashType::AHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
sample_02_images, sample_02_images,
sample_02_hashes, sample_02_hashes,
&lib,
);
test_imageset_hash(
hash::HashType::AHash,
hash::Precision::Medium,
0u64,
sample_02_images,
sample_02_hashes,
&no_cache_lib,
); );
}
// Sample_03 tests
#[test]
fn test_confirm_ahash_results_sample_03() {
let sample_03_images: [&Path; 3] = [ let sample_03_images: [&Path; 3] = [
&Path::new("./test_images/sample_03_large.jpg"), &Path::new("./test_images/sample_03_large.jpg"),
&Path::new("./test_images/sample_03_medium.jpg"), &Path::new("./test_images/sample_03_medium.jpg"),
@ -354,24 +370,17 @@ mod tests {
]; ];
let sample_03_hashes: [u64; 3] = let sample_03_hashes: [u64; 3] =
[135670932300497406, 135670932300497406, 135670932300497406]; [135670932300497406, 135670932300497406, 135670932300497406];
test_imageset_hash(
test_image_set(
hash::HashType::AHash, hash::HashType::AHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
sample_03_images, sample_03_images,
sample_03_hashes, sample_03_hashes,
&lib,
);
test_imageset_hash(
hash::HashType::AHash,
hash::Precision::Medium,
0u64,
sample_03_images,
sample_03_hashes,
&no_cache_lib,
); );
}
// Sample_04 tests
#[test]
fn test_confirm_ahash_results_sample_04() {
let sample_04_images: [&Path; 3] = [ let sample_04_images: [&Path; 3] = [
&Path::new("./test_images/sample_04_large.jpg"), &Path::new("./test_images/sample_04_large.jpg"),
&Path::new("./test_images/sample_04_medium.jpg"), &Path::new("./test_images/sample_04_medium.jpg"),
@ -382,34 +391,20 @@ mod tests {
18446460933225054208, 18446460933225054208,
18446460933225054208, 18446460933225054208,
]; ];
LIB.with(|lib| {
test_imageset_hash( test_imageset_hash(
hash::HashType::AHash, hash::HashType::AHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
sample_04_images, sample_04_images,
sample_04_hashes, sample_04_hashes,
&lib,
);
test_imageset_hash(
hash::HashType::AHash,
hash::Precision::Medium,
0u64,
sample_04_images,
sample_04_hashes,
&no_cache_lib,
lib,
); );
// Clean_Cache
// super::teardown();
});
} }
#[test] #[test]
fn test_confirm_dhash_results() {
// Prep_library
let lib = PIHash::new(Some(cache::DEFAULT_CACHE_DIR));
let no_cache_lib = PIHash::new(None);
// Sample_01 tests
fn test_confirm_dhash_results_sample_01() {
let sample_01_images: [&Path; 3] = [ let sample_01_images: [&Path; 3] = [
&Path::new("./test_images/sample_01_large.jpg"), &Path::new("./test_images/sample_01_large.jpg"),
&Path::new("./test_images/sample_01_medium.jpg"), &Path::new("./test_images/sample_01_medium.jpg"),
@ -420,24 +415,20 @@ mod tests {
3404580580803739582, 3404580580803739582,
3404580580803739582, 3404580580803739582,
]; ];
LIB.with(|lib| {
test_imageset_hash( test_imageset_hash(
hash::HashType::DHash, hash::HashType::DHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
sample_01_images, sample_01_images,
sample_01_hashes, sample_01_hashes,
&lib,
);
test_imageset_hash(
hash::HashType::DHash,
hash::Precision::Medium,
0u64,
sample_01_images,
sample_01_hashes,
&no_cache_lib,
lib,
); );
});
}
// Sample_02 tests
#[test]
fn test_confirm_dhash_results_sample_02() {
let sample_02_images: [&Path; 3] = [ let sample_02_images: [&Path; 3] = [
&Path::new("./test_images/sample_02_large.jpg"), &Path::new("./test_images/sample_02_large.jpg"),
&Path::new("./test_images/sample_02_medium.jpg"), &Path::new("./test_images/sample_02_medium.jpg"),
@ -448,24 +439,20 @@ mod tests {
14726771606135242753, 14726771606135242753,
14726771606135242753, 14726771606135242753,
]; ];
LIB.with(|lib| {
test_imageset_hash( test_imageset_hash(
hash::HashType::DHash, hash::HashType::DHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
sample_02_images, sample_02_images,
sample_02_hashes, sample_02_hashes,
&lib,
);
test_imageset_hash(
hash::HashType::DHash,
hash::Precision::Medium,
0u64,
sample_02_images,
sample_02_hashes,
&no_cache_lib,
lib,
); );
});
}
// Sample_03 tests
#[test]
fn test_confirm_dhash_results_sample_03() {
let sample_03_images: [&Path; 3] = [ let sample_03_images: [&Path; 3] = [
&Path::new("./test_images/sample_03_large.jpg"), &Path::new("./test_images/sample_03_large.jpg"),
&Path::new("./test_images/sample_03_medium.jpg"), &Path::new("./test_images/sample_03_medium.jpg"),
@ -473,24 +460,20 @@ mod tests {
]; ];
let sample_03_hashes: [u64; 3] = let sample_03_hashes: [u64; 3] =
[144115181601817086, 144115181601817086, 144115181601817086]; [144115181601817086, 144115181601817086, 144115181601817086];
LIB.with(|lib| {
test_imageset_hash( test_imageset_hash(
hash::HashType::DHash, hash::HashType::DHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
sample_03_images, sample_03_images,
sample_03_hashes, sample_03_hashes,
&lib,
);
test_imageset_hash(
hash::HashType::DHash,
hash::Precision::Medium,
0u64,
sample_03_images,
sample_03_hashes,
&no_cache_lib,
lib,
); );
});
}
// Sample_04 tests
#[test]
fn test_confirm_dhash_results_sample_04() {
let sample_04_images: [&Path; 3] = [ let sample_04_images: [&Path; 3] = [
&Path::new("./test_images/sample_04_large.jpg"), &Path::new("./test_images/sample_04_large.jpg"),
&Path::new("./test_images/sample_04_medium.jpg"), &Path::new("./test_images/sample_04_medium.jpg"),
@ -501,58 +484,37 @@ mod tests {
18374262188442386433, 18374262188442386433,
18374262188442386433, 18374262188442386433,
]; ];
LIB.with(|lib| {
test_imageset_hash( test_imageset_hash(
hash::HashType::DHash, hash::HashType::DHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
sample_04_images, sample_04_images,
sample_04_hashes, sample_04_hashes,
&lib,
lib,
); );
test_imageset_hash(
hash::HashType::DHash,
hash::Precision::Medium,
0u64,
sample_04_images,
sample_04_hashes,
&no_cache_lib,
);
// Clean_Cache
// super::teardown();
});
} }
#[test] #[test]
fn test_confirm_phash_results() {
// Prep_library
let lib = PIHash::new(Some(cache::DEFAULT_CACHE_DIR));
let no_cache_lib = PIHash::new(None);
// Sample_01 tests
fn test_confirm_phash_results_sample_01() {
let sample_01_images: [&Path; 3] = [ let sample_01_images: [&Path; 3] = [
&Path::new("./test_images/sample_01_large.jpg"), &Path::new("./test_images/sample_01_large.jpg"),
&Path::new("./test_images/sample_01_medium.jpg"), &Path::new("./test_images/sample_01_medium.jpg"),
&Path::new("./test_images/sample_01_small.jpg"), &Path::new("./test_images/sample_01_small.jpg"),
]; ];
let sample_01_hashes: [u64; 3] = [72357778504597504, 72357778504597504, 72357778504597504]; let sample_01_hashes: [u64; 3] = [72357778504597504, 72357778504597504, 72357778504597504];
test_imageset_hash(
test_image_set(
hash::HashType::PHash, hash::HashType::PHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
sample_01_images, sample_01_images,
sample_01_hashes, sample_01_hashes,
&lib,
);
test_imageset_hash(
hash::HashType::PHash,
hash::Precision::Medium,
0u64,
sample_01_images,
sample_01_hashes,
&no_cache_lib,
); );
}
// Sample_02 tests
#[test]
fn test_confirm_phash_results_sample_02() {
let sample_02_images: [&Path; 3] = [ let sample_02_images: [&Path; 3] = [
&Path::new("./test_images/sample_02_large.jpg"), &Path::new("./test_images/sample_02_large.jpg"),
&Path::new("./test_images/sample_02_medium.jpg"), &Path::new("./test_images/sample_02_medium.jpg"),
@ -563,24 +525,17 @@ mod tests {
5332332327550844928, 5332332327550844928,
5332332327550844928, 5332332327550844928,
]; ];
test_imageset_hash(
test_image_set(
hash::HashType::PHash, hash::HashType::PHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
sample_02_images, sample_02_images,
sample_02_hashes, sample_02_hashes,
&lib,
);
test_imageset_hash(
hash::HashType::PHash,
hash::Precision::Medium,
0u64,
sample_02_images,
sample_02_hashes,
&no_cache_lib,
); );
}
// Sample_03 tests
#[test]
fn test_confirm_phash_results_sample_03() {
let sample_03_images: [&Path; 3] = [ let sample_03_images: [&Path; 3] = [
&Path::new("./test_images/sample_03_large.jpg"), &Path::new("./test_images/sample_03_large.jpg"),
&Path::new("./test_images/sample_03_medium.jpg"), &Path::new("./test_images/sample_03_medium.jpg"),
@ -591,24 +546,17 @@ mod tests {
6917529027641081856, 6917529027641081856,
6917529027641081856, 6917529027641081856,
]; ];
test_imageset_hash(
hash::HashType::PHash,
hash::Precision::Medium,
0u64,
sample_03_images,
sample_03_hashes,
&lib,
);
test_imageset_hash(
test_image_set(
hash::HashType::PHash, hash::HashType::PHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
sample_03_images, sample_03_images,
sample_03_hashes, sample_03_hashes,
&no_cache_lib,
); );
}
// Sample_04 tests
#[test]
fn test_confirm_phash_results_sample_04() {
let sample_04_images: [&Path; 3] = [ let sample_04_images: [&Path; 3] = [
&Path::new("./test_images/sample_04_large.jpg"), &Path::new("./test_images/sample_04_large.jpg"),
&Path::new("./test_images/sample_04_medium.jpg"), &Path::new("./test_images/sample_04_medium.jpg"),
@ -619,25 +567,13 @@ mod tests {
10997931646002397184, 10997931646002397184,
10997931646002397184, 10997931646002397184,
]; ];
test_imageset_hash(
test_image_set(
hash::HashType::PHash, hash::HashType::PHash,
hash::Precision::Medium, hash::Precision::Medium,
0u64, 0u64,
sample_04_images, sample_04_images,
sample_04_hashes, sample_04_hashes,
&lib,
); );
test_imageset_hash(
hash::HashType::PHash,
hash::Precision::Medium,
0u64,
sample_04_images,
sample_04_hashes,
&no_cache_lib,
);
// Clean_Cache
// super::teardown();
} }
#[cfg(feature = "bench")] #[cfg(feature = "bench")]
@ -655,7 +591,6 @@ mod tests {
); );
bench.iter(|| { bench.iter(|| {
// Sample_01 Bench
lib.get_perceptual_hash( lib.get_perceptual_hash(
&Path::new("./test_images/sample_01_large.jpg"), &Path::new("./test_images/sample_01_large.jpg"),
&hash::Precision::Medium, &hash::Precision::Medium,
@ -671,7 +606,6 @@ mod tests {
let lib = PIHash::new(None); let lib = PIHash::new(None);
bench.iter(|| { bench.iter(|| {
// Sample_01 Bench
lib.get_perceptual_hash( lib.get_perceptual_hash(
&Path::new("./test_images/sample_01_large.jpg"), &Path::new("./test_images/sample_01_large.jpg"),
&hash::Precision::Medium, &hash::Precision::Medium,

22
src/main.rs

@ -32,6 +32,7 @@ Options:
-a, --ahash Include an ahash calculation. -a, --ahash Include an ahash calculation.
-d, --dhash Include an dhash calculation. -d, --dhash Include an dhash calculation.
-p, --phash Include an phash calculation. -p, --phash Include an phash calculation.
-n, --nocache Disable caching behavior.
"; ";
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@ -42,6 +43,7 @@ struct Args {
flag_phash: bool, flag_phash: bool,
arg_path: String, arg_path: String,
arg_comparison: Vec<String>, arg_comparison: Vec<String>,
flag_nocache: bool,
} }
fn main() { fn main() {
@ -55,8 +57,14 @@ fn main() {
std::process::exit(0); std::process::exit(0);
} }
let cache = if args.flag_nocache {
None
} else {
Some(pihash::cache::DEFAULT_CACHE_DIR)
};
// Init the hashing library // Init the hashing library
let lib = pihash::PIHash::new(Some(pihash::cache::DEFAULT_CACHE_DIR));
let lib = pihash::PIHash::new(cache);
// println!("{:?}", args); // println!("{:?}", args);
if args.arg_comparison.len() > 0 { if args.arg_comparison.len() > 0 {
@ -72,10 +80,10 @@ fn main() {
)); ));
} }
let mut similar_images: Vec<&str> = Vec::new();
let mut similar_images: Vec<String> = Vec::new();
for comparison_hash in comparison_hashes { for comparison_hash in comparison_hashes {
if base_hash.similar(&comparison_hash) { if base_hash.similar(&comparison_hash) {
similar_images.push(&comparison_hash.orig_path);
similar_images.push(String::from(&comparison_hash.orig_path));
} }
} }
@ -106,11 +114,11 @@ fn flags_get_all_perceptual_hashes(args: &Args) -> bool {
|| (!args.flag_ahash && !args.flag_dhash && !args.flag_phash) || (!args.flag_ahash && !args.flag_dhash && !args.flag_phash)
} }
fn get_requested_perceptual_hashes<'a>(
fn get_requested_perceptual_hashes(
lib: &pihash::PIHash, lib: &pihash::PIHash,
image_path: &'a Path,
image_path: &Path,
args: &Args, args: &Args,
) -> pihash::hash::PerceptualHashes<'a> {
) -> pihash::hash::PerceptualHashes {
let ahash = if args.flag_ahash || flags_get_all_perceptual_hashes(&args) { let ahash = if args.flag_ahash || flags_get_all_perceptual_hashes(&args) {
lib.get_ahash(&image_path) lib.get_ahash(&image_path)
} else { } else {
@ -130,7 +138,7 @@ fn get_requested_perceptual_hashes<'a>(
}; };
pihash::hash::PerceptualHashes { pihash::hash::PerceptualHashes {
orig_path: image_path.to_str().unwrap(),
orig_path: String::from(image_path.to_str().unwrap()),
ahash: ahash, ahash: ahash,
dhash: dhash, dhash: dhash,
phash: phash, phash: phash,

Loading…
Cancel
Save