-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from michaelr0/develop
Refactor into library?
- Loading branch information
Showing
5 changed files
with
132 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,94 +1,119 @@ | ||
use clap::ArgMatches; | ||
use image::{DynamicImage, GenericImageView, Pixels}; | ||
use rayon::prelude::*; | ||
use ring::digest::{self}; | ||
use std::{fs::File, io::Read, process::exit}; | ||
|
||
/// Check if images use the same path | ||
pub fn get_image_names(cli: &ArgMatches) -> Vec<String> { | ||
vec![ | ||
cli.value_of("IMAGE_1") | ||
.expect("first image is required") | ||
.to_string(), | ||
cli.value_of("IMAGE_2") | ||
.expect("second image is required") | ||
.to_string(), | ||
] | ||
} | ||
use std::{collections::HashMap, fs::File, io::Read}; | ||
|
||
/// Open images and read bytes | ||
pub fn open_images(images: Vec<String>) -> Vec<Vec<u8>> { | ||
images | ||
.par_iter() | ||
.map(|i| { | ||
let mut buf = Vec::new(); | ||
|
||
File::open(i) | ||
.expect("Unable to open file") | ||
.read_to_end(&mut buf) | ||
.unwrap(); | ||
|
||
buf | ||
}) | ||
.collect::<Vec<Vec<u8>>>() | ||
pub struct Compare<'a> { | ||
images: [String; 2], | ||
checks: HashMap<&'a str, bool>, | ||
} | ||
|
||
/// Generate hashes | ||
pub fn get_hashes(images: &Vec<Vec<u8>>) -> Vec<Vec<u8>> { | ||
images | ||
.par_iter() | ||
.map(|i| digest::digest(&digest::SHA512, i).as_ref().to_owned()) | ||
.collect::<Vec<Vec<u8>>>() | ||
} | ||
impl Compare<'_> { | ||
pub fn new(image_1: String, image_2: String) -> Self { | ||
let mut compare = Compare { | ||
images: [image_1, image_2], | ||
checks: HashMap::new(), | ||
}; | ||
|
||
/// Check if images use the same path | ||
pub fn check_image_same_path(images: &Vec<String>) { | ||
if images.first() == images.last() { | ||
println!("Images are the same file"); | ||
exit(0); | ||
compare.checks.insert("images_have_same_path", false); | ||
compare.checks.insert("image_hashes_match", false); | ||
compare.checks.insert("image_dimensions_match", false); | ||
compare.checks.insert("image_pixels_match", false); | ||
|
||
compare | ||
} | ||
} | ||
|
||
/// Check if images have matching hashes | ||
pub fn check_image_hashes(hashes: Vec<Vec<u8>>) { | ||
if hashes.first().eq(&hashes.last()) { | ||
println!("Images are the same file"); | ||
exit(0); | ||
pub fn enable_check(&mut self, check: &'static str) -> &mut Self { | ||
self.checks.insert(check, true); | ||
|
||
self | ||
} | ||
} | ||
|
||
/// Compare images dimensions and pixels | ||
pub fn compare_image_as_images(images: &Vec<Vec<u8>>) { | ||
let images = images | ||
.par_iter() | ||
.map(|i| image::load_from_memory(i).expect("Could not read image")) | ||
.collect::<Vec<DynamicImage>>(); | ||
|
||
// Compare images dimensions | ||
if !image_dimensions_match(&images) { | ||
println!("Images aren't the same dimensions"); | ||
exit(0); | ||
pub fn enable_check_images_have_same_path(&mut self) -> &mut Self { | ||
self.enable_check("images_have_same_path") | ||
} | ||
|
||
let images = images | ||
.par_iter() | ||
.map(|i| i.pixels()) | ||
.collect::<Vec<Pixels<DynamicImage>>>(); | ||
pub fn enable_check_image_hashes_match(&mut self) -> &mut Self { | ||
self.enable_check("image_hashes_match") | ||
} | ||
|
||
let image1 = images.first().unwrap().to_owned(); | ||
let image2 = images.last().unwrap().to_owned(); | ||
pub fn enable_check_images_dimensions_match(&mut self) -> &mut Self { | ||
self.enable_check("image_dimensions_match") | ||
} | ||
|
||
// Compare images pixels | ||
if image1.ne(image2) { | ||
println!("Images are not a match"); | ||
exit(0); | ||
pub fn enable_check_images_pixels_match(&mut self) -> &mut Self { | ||
self.enable_check("image_pixels_match") | ||
} | ||
} | ||
|
||
/// Compare images dimensions | ||
pub fn image_dimensions_match(images: &Vec<DynamicImage>) -> bool { | ||
let image1_dimensions = images.first().unwrap().dimensions(); | ||
let image2_dimensions = images.last().unwrap().dimensions(); | ||
fn is_check_enabled(&self, check: &'static str) -> bool { | ||
*self.checks.get(check).unwrap_or(&false) | ||
} | ||
|
||
pub fn are_match(&self) -> bool { | ||
if self.is_check_enabled("images_have_same_path") | ||
&& self.images.first() == self.images.last() | ||
{ | ||
return true; | ||
} | ||
|
||
let images = self | ||
.images | ||
.par_iter() | ||
.map(|i| { | ||
let mut buf = Vec::new(); | ||
|
||
File::open(i) | ||
.expect("Unable to open file") | ||
.read_to_end(&mut buf) | ||
.unwrap(); | ||
|
||
image1_dimensions.eq(&image2_dimensions) | ||
buf | ||
}) | ||
.collect::<Vec<Vec<u8>>>(); | ||
|
||
if self.is_check_enabled("image_hashes_match") { | ||
let hashes = images | ||
.par_iter() | ||
.map(|i| digest::digest(&digest::SHA512, i).as_ref().to_owned()) | ||
.collect::<Vec<Vec<u8>>>(); | ||
|
||
if hashes.first().eq(&hashes.last()) { | ||
return true; | ||
} | ||
} | ||
|
||
let images = images | ||
.par_iter() | ||
.map(|i| image::load_from_memory(i).expect("Could not read image")) | ||
.collect::<Vec<DynamicImage>>(); | ||
|
||
if self.is_check_enabled("image_dimensions_match") { | ||
let image1_dimensions = images.first().unwrap().dimensions(); | ||
let image2_dimensions = images.last().unwrap().dimensions(); | ||
|
||
if image1_dimensions.ne(&image2_dimensions) { | ||
return false; | ||
} | ||
} | ||
|
||
if self.is_check_enabled("image_pixels_match") { | ||
let images = images | ||
.par_iter() | ||
.map(|i| i.pixels()) | ||
.collect::<Vec<Pixels<DynamicImage>>>(); | ||
|
||
let image1 = images.first().unwrap().to_owned(); | ||
let image2 = images.last().unwrap().to_owned(); | ||
|
||
if image1.eq(image2) { | ||
return true; | ||
} | ||
} | ||
|
||
false | ||
} | ||
|
||
pub fn arent_match(&self) -> bool { | ||
!self.are_match() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,30 @@ | ||
use clap::{load_yaml, App}; | ||
|
||
fn main() { | ||
// Init APP/CLI | ||
let config = load_yaml!("main.yml"); | ||
let app = App::from_yaml(config); | ||
let cli = app.get_matches(); | ||
|
||
// Get image paths from CLI | ||
let images = imeq::get_image_names(&cli); | ||
|
||
// Check if images use the same path | ||
imeq::check_image_same_path(&images); | ||
|
||
// Open images and read bytes | ||
let images = imeq::open_images(images); | ||
|
||
// Generate hashes | ||
let hashes = imeq::get_hashes(&images); | ||
|
||
// Check if images have matching hashes | ||
imeq::check_image_hashes(hashes); | ||
|
||
// Compare images dimensions and pixels | ||
imeq::compare_image_as_images(&images); | ||
|
||
// Everything else has led to this moment! | ||
// The images appear to match! | ||
println!("Images are a match"); | ||
let image_1 = cli | ||
.value_of("IMAGE_1") | ||
.expect("first image is required") | ||
.to_string(); | ||
|
||
let image_2 = cli | ||
.value_of("IMAGE_2") | ||
.expect("second image is required") | ||
.to_string(); | ||
|
||
let images_match = imeq::Compare::new(image_1, image_2) | ||
.enable_check_images_have_same_path() | ||
.enable_check_image_hashes_match() | ||
.enable_check_images_dimensions_match() | ||
.enable_check_images_pixels_match() | ||
.are_match(); | ||
|
||
if images_match { | ||
println!("Images are a match"); | ||
} else { | ||
println!("Images are not a match"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters