diff --git a/.gitignore b/.gitignore index 0854752..9369b2a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # System Files .directory +*.swp # Compiled files *.o diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5a2473e..487a917 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,7 +5,9 @@ stages: test: stage: test script: - - cargo test --release + - rustc -V + - cargo -V + - cargo test only: - master tags: diff --git a/Cargo.toml b/Cargo.toml index 6b48640..b40ae0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pihash" -version = "0.1.1" +version = "0.2.0" authors = ["Drew Short "] description = "A simple library for generating perceptual hashes for images and comparing images based on their perceptual hashes." repository = "https://github.com/warricksothr/Perceptual-Image-Hashing/" diff --git a/README.md b/README.md index 3d777bd..5bf2303 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ The goal of this library is to offer a utility for calculating perceptual hashes of images for the purpose of comparing images for similarity + - [ ] Add DCT in addition to DFT and some additional wrappings around the perceptual hashing. + # Examples To Be Added diff --git a/src/cache.rs b/src/cache.rs index eaa97ce..7808d5c 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -10,7 +10,7 @@ use self::image::ImageBuffer; use self::sha1::Sha1; use std::path::Path; use std::fs::{File, create_dir_all, remove_dir_all}; -use std::io::{Read, Error}; +use std::io::{Read, Error, Write}; use std::option::Option; use std::result::Result; @@ -42,7 +42,7 @@ fn get_file_hash(path: &Path) -> Result { /** * Put an image buffer in the cache */ -pub fn put_in_cache(path: &Path, size: u32, image: &ImageBuffer, Vec>) { +pub fn put_image_in_cache(path: &Path, size: u32, image: &ImageBuffer, Vec>) { let hash = get_file_hash(&path); match hash { Ok(sha1) => { @@ -58,10 +58,39 @@ pub fn put_in_cache(path: &Path, size: u32, image: &ImageBuffer, } } +/** + * Expects a slice of slices that represents lines in the file + */ +pub fn put_matrix_in_cache(path: &Path, size: u32, extension: &str, file_contents: &Vec>) { + let hash = get_file_hash(&path); + match hash { + Ok(sha1) => { + let cache_path_str = format!("{}/{}x{}_{}.{}",CACHE_DIR, size, size, sha1, extension); + let cached_path = Path::new(&cache_path_str); + // Save the file into the cache + match File::create(&cached_path) { + Ok(mut file) => { + for row in file_contents { + let mut row_str = row.iter().fold(String::new(), |acc, &item| acc + &format!("{},",item)); + //remove the last comma + let desire_len = row_str.len()-1; + row_str.truncate(desire_len); + row_str.push_str("\n"); + file.write(&row_str.into_bytes()); + } + file.flush(); + }, + Err(_) => {}, + } + }, + Err(e) => println!("Error: {}", e), + } +} + /** * Get an image buffer out of the cache */ -pub fn get_from_cache(path: &Path, size: u32) -> Option, Vec>> { +pub fn get_image_from_cache(path: &Path, size: u32) -> Option, Vec>> { let hash = get_file_hash(&path); match hash { Ok(sha1) => { @@ -88,6 +117,42 @@ pub fn get_from_cache(path: &Path, size: u32) -> Option Option>> { + let hash = get_file_hash(&path); + match hash { + Ok(sha1) => { + // Check if the file exists in the cache + let cache_path_str = format!("{}/{}x{}_{}.{}",CACHE_DIR, size, size, sha1, extension); + let cached_path = Path::new(&cache_path_str); + // Try to open, if it does, then we can read the image in + match File::open(&cached_path) { + Ok(mut file) => { + let mut matrix: Vec> = Vec::new(); + let mut matrix_data: Vec = Vec::new(); + file.read_to_end(&mut matrix_data); + let matrix_data_str = String::from_utf8(matrix_data); + //convert the matrix + Some(matrix) + }, + // Don't really care here, it just means an existing cached + // file doesn't exist, or can't be read. + Err(_) => { + None + }, + } + }, + Err(e) => { + println!("Error: {}", e); + None + }, + } +} + + + #[test] fn test_get_file_hash() { let target = "test_images/sample_01_large.jpg"; diff --git a/src/hash.rs b/src/hash.rs index 6359aba..7ab739c 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -109,7 +109,7 @@ pub fn prepare_image<'a>(path: &'a Path, hash_type: &HashType, precision: &Preci _ => precision.get_size() }; // Check if we have the already converted image in a cache and use that if possible. - match cache::get_from_cache(&path, size) { + match cache::get_image_from_cache(&path, size) { Some(image) => { PreparedImage { orig_path: &*image_path, image: image } }, @@ -118,7 +118,7 @@ pub fn prepare_image<'a>(path: &'a Path, hash_type: &HashType, precision: &Preci let image = image::open(path).unwrap(); let small_image = image.resize_exact(size, size, FilterType::Lanczos3); let grey_image = small_image.to_luma(); - cache::put_in_cache(&path, size, &grey_image); + cache::put_image_in_cache(&path, size, &grey_image); PreparedImage { orig_path: &*image_path, image: grey_image } }, } @@ -297,6 +297,8 @@ impl<'a> PerceptualHash for PHash<'a> { // Perform the 2D DFT operation on our matrix calculate_2d_dft(&mut data_matrix); + // Store this DFT in the cache + cache::put_matrix_in_cache(&Path::new(self.prepared_image.orig_path),width as u32,&"dft",&data_matrix); // Only need the top left quadrant let target_width = (width / 4) as usize;