Browse Source

Working simple caching of the images used to hash. Needs some additional work, but much better than on dry runs.

develop
Drew Short 9 years ago
parent
commit
5ef33aef97
  1. 3
      .gitignore
  2. 2
      Cargo.toml
  3. 83
      src/cache.rs
  4. 11
      src/hash.rs
  5. 12
      src/lib.rs
  6. 3
      src/main.rs

3
.gitignore

@ -12,3 +12,6 @@
# Building a library, so ignore the lock file # Building a library, so ignore the lock file
Cargo.lock Cargo.lock
# Cache Directory
.hash_cache/

2
Cargo.toml

@ -9,4 +9,4 @@ rustc-serialize = "*"
image = "*" image = "*"
complex = "*" complex = "*"
dft = "*" dft = "*"
rust-crypto = "*"
sha1 = "*"

83
src/cache.rs

@ -3,28 +3,99 @@
// Licensed under the MIT license<LICENSE-MIT or http://opensource.org/licenses/MIT>. // Licensed under the MIT license<LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed except according to those terms. // This file may not be copied, modified, or distributed except according to those terms.
extern image;
extern crate image;
extern crate sha1;
use self::image::ImageBuffer; use self::image::ImageBuffer;
use self::sha1::Sha1;
use std::path::Path; use std::path::Path;
use std::fs::{File, create_dir_all};
use std::io::{Read, Error};
use std::option::Option;
use std::result::Result;
const CACHE_DIR: &'static str = "./.hash_cache";
const CACHE_FILE_EXT: &'static str = "png";
// Creates the required directories
pub fn prep_cache() -> Result<(), Error> {
create_dir_all(CACHE_DIR)
}
/** /**
* Get the hash of the desired file and return it as a hex string * Get the hash of the desired file and return it as a hex string
*/ */
fn get_file_hash(path: &Path) -> String {
fn get_file_hash(path: &Path) -> Result<String, Error> {
let mut source = try!(File::open(&path));
let mut buf: Vec<u8> = Vec::new();
try!(source.read_to_end(&mut buf));
let mut sha1 = Sha1::new();
sha1.update(&buf);
// Return the hex result of the hash
Ok(sha1.hexdigest())
} }
/** /**
* Put an image buffer in the cache * Put an image buffer in the cache
*/ */
pub fn put_in_cache(path: &Path, image: &ImageBuffer) {
pub fn put_in_cache(path: &Path, image: &ImageBuffer<image::Luma<u8>, Vec<u8>>) {
let hash = get_file_hash(&path);
match hash {
Ok(sha1) => {
let cache_path_str = format!("{}/{}.{}",CACHE_DIR, sha1, CACHE_FILE_EXT);
let cached_path = Path::new(&cache_path_str);
// Save the file into the cache
match image.save(cached_path) {
Ok(_) => {},
Err(e) => println!("Error: {}", e),
}
},
Err(e) => println!("Error: {}", e),
}
} }
/** /**
* Get an image buffer out of the cache * Get an image buffer out of the cache
*/ */
pub fn get_from_cache(path: &Path) -> Some(ImageBuffer) {
pub fn get_from_cache(path: &Path) -> Option<ImageBuffer<image::Luma<u8>, Vec<u8>>> {
let hash = get_file_hash(&path);
match hash {
Ok(sha1) => {
// Check if the file exists in the cache
let cache_path_str = format!("{}/{}.{}",CACHE_DIR, sha1, CACHE_FILE_EXT);
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(_) => {
let image = image::open(&cached_path).unwrap();
Some(image.to_luma())
},
Err(e) => {
println!("Error: {}", e);
None
},
}
},
Err(e) => {
println!("Error: {}", e);
None
},
}
}
#[test]
fn test_get_file_hash() {
let target = "test_images/sample_01_large.jpg";
let target_path = Path::new(target);
let hash = get_file_hash(&target_path);
match hash {
Ok(v) => {
println!("Hash: {}", v);
assert!(v == "4beb6f2d852b75a313863916a1803ebad13a3196");
}
Err(e) => {
println!("Error: {:?}", e);
assert!(false);
}
}
} }

11
src/hash.rs

@ -16,6 +16,7 @@ use self::image::{
}; };
use self::dft::real; use self::dft::real;
use self::complex::*; use self::complex::*;
use cache;
/** /**
* Prepared image that can be used to generate hashes * Prepared image that can be used to generate hashes
@ -52,13 +53,19 @@ pub struct PerceptualHashes<'a> {
pub fn prepare_image(path: &Path, size: u32) -> PreparedImage { pub fn prepare_image(path: &Path, size: u32) -> PreparedImage {
let image_path = path.to_str().unwrap(); let image_path = path.to_str().unwrap();
// 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::get_from_cache(&path) {
Some(image) => {
PreparedImage { orig_path: &*image_path, image: image }
},
None => {
// Otherwise let's do that work now and store it. // Otherwise let's do that work now and store it.
let image = image::open(path).unwrap(); let image = image::open(path).unwrap();
let small_image = image.resize_exact(size, size, FilterType::Lanczos3); let small_image = image.resize_exact(size, size, FilterType::Lanczos3);
let grey_image = small_image.to_luma(); let grey_image = small_image.to_luma();
cache::put_in_cache(&path, &grey_image);
PreparedImage { orig_path: &*image_path, image: grey_image } PreparedImage { orig_path: &*image_path, image: grey_image }
},
}
} }
/** /**

12
src/lib.rs

@ -8,6 +8,18 @@ use std::path::Path;
mod hash; mod hash;
mod cache; mod cache;
/**
* Prepare the library for work.
*
* Not performing this step may cause parts to fail.
*/
pub fn init() {
match cache::prep_cache() {
Ok(_) => {},
Err(e) => println!("Error: {}", e),
}
}
pub fn get_phashes(path: &Path) -> hash::PerceptualHashes { pub fn get_phashes(path: &Path) -> hash::PerceptualHashes {
hash::get_perceptual_hashes(path, 8) hash::get_perceptual_hashes(path, 8)
} }

3
src/main.rs

@ -38,6 +38,9 @@ fn main() {
let args: Args = Docopt::new(USAGE) let args: Args = Docopt::new(USAGE)
.and_then(|d| d.decode()) .and_then(|d| d.decode())
.unwrap_or_else(|e| e.exit()); .unwrap_or_else(|e| e.exit());
// Init the hashing library
pihash::init();
//println!("{:?}", args); //println!("{:?}", args);
// All flags set or, no flags set // All flags set or, no flags set
if (args.flag_ahash && args.flag_dhash && args.flag_phash) if (args.flag_ahash && args.flag_dhash && args.flag_phash)

Loading…
Cancel
Save