From 7e4c1d930d473ed0ab7f32b639724d1c12286d1f Mon Sep 17 00:00:00 2001 From: salam Date: Mon, 9 Dec 2024 08:42:23 +0900 Subject: [PATCH] add: From trait impl for Bit, BinaryImage --- src/lib.rs | 82 +++++++++++++++++++++++++++++++++++++++++++--------- src/pixel.rs | 42 +++++++++++++++++++++++++++ src/view.rs | 33 +++++---------------- 3 files changed, 119 insertions(+), 38 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5b99ea0..89ca6d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![doc = include_str!("../README.md")] -use image::GenericImageView; +use bit_vec::BitVec; +use image::{GenericImage, GenericImageView}; pub use neigbors::Neighbors; pub use pixel::Bit; @@ -12,40 +13,60 @@ mod pixel; mod tests; mod view; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct BinaryImage { - height: u32, width: u32, - data: bit_vec::BitVec, + height: u32, + buf: bit_vec::BitVec, } impl BinaryImage { #[must_use] - pub fn from_raw(height: u32, width: u32, data: &[T]) -> Self + pub fn new(width: u32, height: u32) -> Self { + Self { + width, + height, + buf: BitVec::with_capacity((width * height) as usize), + } + } + + #[must_use] + pub fn from_raw(width: u32, height: u32, buf: &[T]) -> Self where T: num_traits::Zero, { + let image_size = (width * height) as usize; debug_assert!( - data.len() >= (height * width) as usize, - "Data must not be smaller than image dimensions" + buf.len() >= image_size, + "Buffer must not be smaller than image dimensions" ); - let compress_step = data.len() / (height * width) as usize; + let compress_step = buf.len() / image_size; Self { - data: data + buf: buf .chunks(compress_step) - .map(|pixel| pixel.iter().any(|channel| !channel.is_zero())) + .map(|pixel| !pixel.iter().any(num_traits::Zero::is_zero)) .collect(), height, width, } } + + #[must_use] + pub fn from_bitvec(width: u32, height: u32, buf: bit_vec::BitVec) -> Self { + let image_size = (width * height) as usize; + debug_assert!( + buf.len() >= image_size, + "Buffer must not be smaller than image dimensions" + ); + Self { width, height, buf } + } } impl image::GenericImageView for BinaryImage { type Pixel = pixel::Bit; #[inline] unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> Self::Pixel { - Bit::from(self.data.get_unchecked((y * self.width + x) as usize)) + Bit::from(self.buf.get_unchecked((y * self.width + x) as usize)) } #[inline] fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel { @@ -69,7 +90,7 @@ impl image::GenericImageView for BinaryImage { impl image::GenericImage for BinaryImage { #[inline] unsafe fn unsafe_put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) { - self.data.set((y * self.width + x) as usize, *pixel); + self.buf.set((y * self.width + x) as usize, *pixel); } #[inline] fn put_pixel(&mut self, x: u32, y: u32, pixel: Self::Pixel) { @@ -89,7 +110,42 @@ impl> From<&I> for BinaryImage { BinaryImage { height: view.height(), width: view.width(), - data: view.pixels().map(|(_, _, pixel)| *pixel).collect(), + buf: view.pixels().map(|(_, _, pixel)| *pixel).collect(), + } + } +} + +impl From for BinaryImage { + fn from(image: image::DynamicImage) -> Self { + match image { + image::DynamicImage::ImageRgb8(image) => Self::from(image), + image::DynamicImage::ImageLuma8(image) => Self::from(image), + image::DynamicImage::ImageRgba8(image) => Self::from(image), + image::DynamicImage::ImageRgb16(image) => Self::from(image), + image::DynamicImage::ImageLumaA8(image) => Self::from(image), + image::DynamicImage::ImageLuma16(image) => Self::from(image), + image::DynamicImage::ImageRgba16(image) => Self::from(image), + image::DynamicImage::ImageRgb32F(image) => Self::from(image), + image::DynamicImage::ImageLumaA16(image) => Self::from(image), + image::DynamicImage::ImageRgba32F(image) => Self::from(image), + _ => unimplemented!(), + } + } +} + +impl From> for BinaryImage +where + Container: std::ops::Deref, + P: image::Pixel, + Bit: From

, +{ + fn from(image: image::ImageBuffer) -> Self { + let mut new = Self::new(image.width(), image.height()); + for x in 0..image.width() { + for y in 0..image.height() { + new.put_pixel(x, y, Bit::from(*image.get_pixel(x, y))); + } } + new } } diff --git a/src/pixel.rs b/src/pixel.rs index 255a97c..66fee93 100644 --- a/src/pixel.rs +++ b/src/pixel.rs @@ -264,3 +264,45 @@ impl image::Pixel for Bit { Self(*(a | b | c | d)) } } + +impl From> for Bit { + fn from(pixel: image::Rgb) -> Self { + Self(!pixel.0.iter().all(Zero::is_zero)) + } +} +impl From> for Bit { + fn from(pixel: image::Luma) -> Self { + Self(!pixel.0[0].is_zero()) + } +} +impl From> for Bit { + fn from(pixel: image::Rgba) -> Self { + Self(!pixel.0[3].is_zero()) + } +} +impl From> for Bit { + fn from(pixel: image::LumaA) -> Self { + Self(!pixel.0[1].is_zero()) + } +} + +impl From<&image::Rgb> for Bit { + fn from(pixel: &image::Rgb) -> Self { + Self(!pixel.0.iter().all(Zero::is_zero)) + } +} +impl From<&image::Luma> for Bit { + fn from(pixel: &image::Luma) -> Self { + Self(!pixel.0[0].is_zero()) + } +} +impl From<&image::Rgba> for Bit { + fn from(pixel: &image::Rgba) -> Self { + Self(!pixel.0[3].is_zero()) + } +} +impl From<&image::LumaA> for Bit { + fn from(pixel: &image::LumaA) -> Self { + Self(!pixel.0[1].is_zero()) + } +} diff --git a/src/view.rs b/src/view.rs index 465b20d..c89e927 100644 --- a/src/view.rs +++ b/src/view.rs @@ -1,40 +1,23 @@ #![allow(clippy::module_name_repetitions)] use derive_more::{Constructor, Deref, DerefMut, From}; -use image::{GenericImageView, Pixel}; -use num_traits::Zero; - -use crate::pixel::Bit; #[derive(Debug, Clone, DerefMut, Deref, From, Constructor)] -pub struct BinaryView<'a, I>(pub &'a I) -where - I: GenericImageView; +pub struct BinaryView<'a, I: image::GenericImageView>(pub &'a I); -impl<'a, I> GenericImageView for BinaryView<'a, I> +impl<'a, I, P> image::GenericImageView for BinaryView<'a, I> where - I: GenericImageView, + I: image::GenericImageView, + P: image::Pixel, + crate::Bit: From

, { - type Pixel = Bit; + type Pixel = crate::Bit; #[inline] unsafe fn unsafe_get_pixel(&self, x: u32, y: u32) -> Self::Pixel { - let pixel = self.0.unsafe_get_pixel(x, y); - let (mut channels, mut alphas, mut alpha_exist) = (false, false, false); - pixel.map_with_alpha( - |channel| { - channels |= !channel.is_zero(); - channel - }, - |alpha| { - alpha_exist = true; - alphas |= !alpha.is_zero(); - alpha - }, - ); - Bit(if alpha_exist { alphas } else { channels }) + crate::Bit::from(self.0.unsafe_get_pixel(x, y)) } #[inline] fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel { - debug_assert!(self.0.in_bounds(x, y)); + debug_assert!(self.0.in_bounds(x, y), "Pixel out of bounds"); unsafe { self.unsafe_get_pixel(x, y) } } #[inline]