use image::{imageops, DynamicImage, GenericImageView, GrayImage, ImageBuffer, Pixel};
use std::borrow::Cow;
use std::ops;
pub trait HashBytes {
fn from_iter<I: Iterator<Item = u8>>(iter: I) -> Self where Self: Sized;
fn max_bits() -> usize;
fn as_slice(&self) -> &[u8];
}
impl HashBytes for Box<[u8]> {
fn from_iter<I: Iterator<Item = u8>>(iter: I) -> Self {
iter.collect::<Vec<u8>>().into_boxed_slice()
}
fn max_bits() -> usize {
usize::max_value()
}
fn as_slice(&self) -> &[u8] { self }
}
impl HashBytes for Vec<u8> {
fn from_iter<I: Iterator<Item=u8>>(iter: I) -> Self {
iter.collect()
}
fn max_bits() -> usize {
usize::max_value()
}
fn as_slice(&self) -> &[u8] { self }
}
macro_rules! hash_bytes_array {
($($n:expr),*) => {$(
impl HashBytes for [u8; $n] {
fn from_iter<I: Iterator<Item=u8>>(mut iter: I) -> Self {
let mut out = [0; $n];
for (src, dest) in iter.by_ref().zip(out.as_mut()) {
*dest = src;
}
out
}
fn max_bits() -> usize {
$n * 8
}
fn as_slice(&self) -> &[u8] { self }
}
)*}
}
hash_bytes_array!(8, 16, 24, 32, 40, 48, 56, 64);
struct BoolsToBytes<I> {
iter: I,
}
impl<I> Iterator for BoolsToBytes<I> where I: Iterator<Item=bool> {
type Item = u8;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
self.iter.by_ref().take(8).enumerate().fold(None, |accum, (n, val)| {
accum.or(Some(0)).map(|accum| accum | ((val as u8) << n))
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let (lower, upper) = self.iter.size_hint();
(
lower / 8,
upper.map(|upper| if upper % 8 == 0 { upper / 8 } else { upper / 8 + 1})
)
}
}
pub(crate) trait BitSet: HashBytes {
fn from_bools<I: Iterator<Item = bool>>(iter: I) -> Self where Self: Sized {
Self::from_iter(BoolsToBytes { iter })
}
fn hamming(&self, other: &Self) -> u32 {
self.as_slice().iter().zip(other.as_slice()).map(|(l, r)| (l ^ r).count_ones()).sum()
}
}
impl<T: HashBytes> BitSet for T {}
pub trait Image: GenericImageView + 'static {
type Buf: Image + DiffImage;
fn to_grayscale(&self) -> Cow<GrayImage>;
fn blur(&self, sigma: f32) -> Self::Buf;
fn foreach_pixel8<F>(&self, foreach: F) where F: FnMut(u32, u32, &[u8]);
}
pub trait DiffImage {
fn diff_inplace(&mut self, other: &Self);
}
#[cfg(not(feature = "nightly"))]
impl<P: 'static, C: 'static> Image for ImageBuffer<P, C>
where P: Pixel<Subpixel = u8>, C: ops::Deref<Target=[u8]> {
type Buf = ImageBuffer<P, Vec<u8>>;
fn to_grayscale(&self) -> Cow<GrayImage> {
Cow::Owned(imageops::grayscale(self))
}
fn blur(&self, sigma: f32) -> Self::Buf { imageops::blur(self, sigma) }
fn foreach_pixel8<F>(&self, mut foreach: F) where F: FnMut(u32, u32, &[u8]) {
self.enumerate_pixels().for_each(|(x, y, px)| foreach(x, y, px.channels()))
}
}
#[cfg(feature = "nightly")]
impl<P: 'static, C: 'static> Image for ImageBuffer<P, C>
where P: Pixel<Subpixel = u8>, C: ops::Deref<Target=[u8]> {
type Buf = ImageBuffer<P, Vec<u8>>;
default fn to_grayscale(&self) -> Cow<GrayImage> {
Cow::Owned(imageops::grayscale(self))
}
default fn blur(&self, sigma: f32) -> Self::Buf { imageops::blur(self, sigma) }
default fn foreach_pixel8<F>(&self, mut foreach: F) where F: FnMut(u32, u32, &[u8]) {
self.enumerate_pixels().for_each(|(x, y, px)| foreach(x, y, px.channels()))
}
}
impl<P: 'static> DiffImage for ImageBuffer<P, Vec<u8>> where P: Pixel<Subpixel = u8> {
fn diff_inplace(&mut self, other: &Self) {
self.iter_mut().zip(other.iter()).for_each(|(l, r)| *l -= r);
}
}
impl Image for DynamicImage {
type Buf = image::RgbaImage;
fn to_grayscale(&self) -> Cow<GrayImage> {
self.as_luma8().map_or_else(|| Cow::Owned(self.to_luma()), Cow::Borrowed)
}
fn blur(&self, sigma: f32) -> Self::Buf { imageops::blur(self, sigma) }
fn foreach_pixel8<F>(&self, mut foreach: F) where F: FnMut(u32, u32, &[u8]) {
self.pixels().for_each(|(x, y, px)| foreach(x, y, px.channels()))
}
}
#[cfg(feature = "nightly")]
impl Image for GrayImage {
fn to_grayscale(&self) -> Cow<GrayImage> {
Cow::Borrowed(self)
}
}
#[test]
fn test_bools_to_bytes() {
let bools = (0 .. 16).map(|x| x & 1 == 0);
let bytes = Vec::from_bools(bools.clone());
assert_eq!(*bytes, [0b01010101; 2]);
let bools_to_bytes = BoolsToBytes { iter: bools };
assert_eq!(bools_to_bytes.size_hint(), (2, Some(2)));
}