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. 21
      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
Cargo.lock
# Cache Directory
.hash_cache/

2
Cargo.toml

@ -9,4 +9,4 @@ rustc-serialize = "*"
image = "*"
complex = "*"
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>.
// 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::sha1::Sha1;
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
*/
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
*/
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
*/
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);
}
}
}

21
src/hash.rs

@ -16,6 +16,7 @@ use self::image::{
};
use self::dft::real;
use self::complex::*;
use cache;
/**
* 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 {
let image_path = path.to_str().unwrap();
// Check if we have the already converted image in a cache and use that if possible.
// Otherwise let's do that work now and store it.
let image = image::open(path).unwrap();
let small_image = image.resize_exact(size, size, FilterType::Lanczos3);
let grey_image = small_image.to_luma();
PreparedImage { orig_path: &*image_path, image: grey_image }
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.
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, &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 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 {
hash::get_perceptual_hashes(path, 8)
}

3
src/main.rs

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

Loading…
Cancel
Save