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 10 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