// Copyright 2015 Drew Short . // // Licensed under the MIT license. // This file may not be copied, modified, or distributed except according to those terms. extern crate docopt; extern crate pihash; extern crate rustc_serialize; #[macro_use] extern crate serde_derive; use std::path::Path; use docopt::Docopt; // Getting the version information from cargo during compile time const VERSION: &'static str = env!("CARGO_PKG_VERSION"); // The usage description const USAGE: &'static str = " Perceptual Image Hashing (pihash) Calculate the perceptual hash values for an input or compare the input file to a set of other images and return a list of the similar images. Usage: pihash [options] [...] pihash (--help | --version) Options: -h, --help Show this screen. -V, --version Print version. -a, --ahash Include an ahash calculation. -d, --dhash Include an dhash calculation. -p, --phash Include an phash calculation. -n, --nocache Disable caching behavior. "; #[derive(Debug, Deserialize)] struct Args { flag_version: bool, flag_ahash: bool, flag_dhash: bool, flag_phash: bool, arg_path: String, arg_comparison: Vec, flag_nocache: bool, } fn main() { let args: Args = Docopt::new(USAGE) .and_then(|d| d.deserialize()) .unwrap_or_else(|e| e.exit()); // Print version information and exit if args.flag_version { println!("Perceptual Image Hashing: v{}", VERSION); std::process::exit(0); } let cache = if args.flag_nocache { None } else { Some(pihash::cache::DEFAULT_CACHE_DIR) }; // Init the hashing library let lib = pihash::PIHash::new(cache); // println!("{:?}", args); if args.arg_comparison.len() > 0 { let base_image_path = Path::new(&args.arg_path); let base_hash = get_requested_perceptual_hashes(&lib, &base_image_path, &args); let mut comparison_hashes: Vec = Vec::new(); for index in 0..args.arg_comparison.len() { comparison_hashes.push(get_requested_perceptual_hashes( &lib, &Path::new(&args.arg_comparison[index]), &args, )); } let mut similar_images: Vec = Vec::new(); for comparison_hash in comparison_hashes { if base_hash.similar(&comparison_hash) { similar_images.push(String::from(&comparison_hash.orig_path)); } } println!("Base Image:"); println!("{}", base_image_path.to_str().unwrap()); println!("Similar Images:"); for similar_image in similar_images { println!("{}", similar_image); } } else { let image_path = Path::new(&args.arg_path); let hashes = get_requested_perceptual_hashes(&lib, &image_path, &args); let hash_result = format!( r#" file: {} ahash: {} dhash: {} phash: {} "#, hashes.orig_path, hashes.ahash, hashes.dhash, hashes.phash ); println!("{}", hash_result); } } 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( lib: &pihash::PIHash, image_path: &Path, args: &Args, ) -> pihash::hash::PerceptualHashes { let ahash = if args.flag_ahash || flags_get_all_perceptual_hashes(&args) { lib.get_ahash(&image_path) } else { 0u64 }; let dhash = if args.flag_dhash || flags_get_all_perceptual_hashes(&args) { lib.get_dhash(&image_path) } else { 0u64 }; let phash = if args.flag_phash || flags_get_all_perceptual_hashes(&args) { lib.get_phash(&image_path) } else { 0u64 }; pihash::hash::PerceptualHashes { orig_path: String::from(image_path.to_str().unwrap()), ahash, dhash, phash, } }