Skip to content

Commit

Permalink
add: From trait impl for Bit, BinaryImage
Browse files Browse the repository at this point in the history
  • Loading branch information
salam99823 committed Dec 8, 2024
1 parent 85ef73e commit 7e4c1d9
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 38 deletions.
82 changes: 69 additions & 13 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<T>(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<T>(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 {
Expand All @@ -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) {
Expand All @@ -89,7 +110,42 @@ impl<I: image::GenericImageView<Pixel = Bit>> 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<image::DynamicImage> 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<Container, P> From<image::ImageBuffer<P, Container>> for BinaryImage
where
Container: std::ops::Deref<Target = [P::Subpixel]>,
P: image::Pixel,
Bit: From<P>,
{
fn from(image: image::ImageBuffer<P, Container>) -> 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
}
}
42 changes: 42 additions & 0 deletions src/pixel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,45 @@ impl image::Pixel for Bit {
Self(*(a | b | c | d))
}
}

impl<T: image::Primitive> From<image::Rgb<T>> for Bit {
fn from(pixel: image::Rgb<T>) -> Self {
Self(!pixel.0.iter().all(Zero::is_zero))
}
}
impl<T: image::Primitive> From<image::Luma<T>> for Bit {
fn from(pixel: image::Luma<T>) -> Self {
Self(!pixel.0[0].is_zero())
}
}
impl<T: image::Primitive> From<image::Rgba<T>> for Bit {
fn from(pixel: image::Rgba<T>) -> Self {
Self(!pixel.0[3].is_zero())
}
}
impl<T: image::Primitive> From<image::LumaA<T>> for Bit {
fn from(pixel: image::LumaA<T>) -> Self {
Self(!pixel.0[1].is_zero())
}
}

impl<T: image::Primitive> From<&image::Rgb<T>> for Bit {
fn from(pixel: &image::Rgb<T>) -> Self {
Self(!pixel.0.iter().all(Zero::is_zero))
}
}
impl<T: image::Primitive> From<&image::Luma<T>> for Bit {
fn from(pixel: &image::Luma<T>) -> Self {
Self(!pixel.0[0].is_zero())
}
}
impl<T: image::Primitive> From<&image::Rgba<T>> for Bit {
fn from(pixel: &image::Rgba<T>) -> Self {
Self(!pixel.0[3].is_zero())
}
}
impl<T: image::Primitive> From<&image::LumaA<T>> for Bit {
fn from(pixel: &image::LumaA<T>) -> Self {
Self(!pixel.0[1].is_zero())
}
}
33 changes: 8 additions & 25 deletions src/view.rs
Original file line number Diff line number Diff line change
@@ -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<Pixel = P>,
P: image::Pixel,
crate::Bit: From<P>,
{
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]
Expand Down

0 comments on commit 7e4c1d9

Please sign in to comment.