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()
}
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
}
}
impl<const N: usize> 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
}
}
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_luma8()), 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)));
}