From aae0793f98d676338963bf6d67789dbed80ec5be Mon Sep 17 00:00:00 2001 From: "Christopher N. Hesse" Date: Wed, 1 Feb 2023 14:05:04 +0100 Subject: [PATCH] Get rid of image types They are not needed to accomplish the main task of this crate: converting between various pixelformats using arbitrary buffers. We now place the burden of choosing a suitable storage type onto the caller. The caller can then iterate through the collection and map each pixel individually (or multiple, in the case of macropixels). Signed-off-by: Christopher N. Hesse --- .github/workflows/ci.yml | 9 +- ffimage-yuv/Cargo.toml | 5 - ffimage-yuv/src/yuv422.rs | 92 ---------- ffimage/Cargo.toml | 4 - ffimage/src/convert.rs | 39 ----- ffimage/src/error.rs | 21 --- ffimage/src/lib.rs | 34 +--- ffimage/src/packed/convert/gold.rs | 28 --- ffimage/src/packed/convert/mod.rs | 7 - ffimage/src/packed/convert/rayon.rs | 35 ---- ffimage/src/packed/image.rs | 258 ---------------------------- ffimage/src/packed/iter.rs | 162 ----------------- ffimage/src/packed/matrix.rs | 175 ------------------- ffimage/src/packed/mod.rs | 14 -- ffimage/src/traits.rs | 23 --- 15 files changed, 10 insertions(+), 896 deletions(-) delete mode 100644 ffimage/src/convert.rs delete mode 100644 ffimage/src/error.rs delete mode 100644 ffimage/src/packed/convert/gold.rs delete mode 100644 ffimage/src/packed/convert/mod.rs delete mode 100644 ffimage/src/packed/convert/rayon.rs delete mode 100644 ffimage/src/packed/image.rs delete mode 100644 ffimage/src/packed/iter.rs delete mode 100644 ffimage/src/packed/matrix.rs delete mode 100644 ffimage/src/packed/mod.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7c172d8..c5508ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,13 +17,6 @@ jobs: check: name: check runs-on: ubuntu-20.04 - strategy: - matrix: - include: - - build: default - features: "" - - build: rayon - features: "--features rayon" steps: - name: Checkout repository uses: actions/checkout@v2 @@ -34,7 +27,7 @@ jobs: profile: minimal override: true - name: Check - run: cargo check --no-default-features ${{ matrix.features }} + run: cargo check test: name: test diff --git a/ffimage-yuv/Cargo.toml b/ffimage-yuv/Cargo.toml index 0ae6877..1b867b5 100644 --- a/ffimage-yuv/Cargo.toml +++ b/ffimage-yuv/Cargo.toml @@ -15,15 +15,10 @@ path = "../ffimage" [dependencies] num-traits = "0.2.14" -itertools = "0.10.3" [dev-dependencies] criterion = "0.3.4" -[features] -default = ["rayon"] -rayon = ["ffimage/rayon"] - [[bench]] name = "bench_main" harness = false diff --git a/ffimage-yuv/src/yuv422.rs b/ffimage-yuv/src/yuv422.rs index 03a4686..4587e65 100644 --- a/ffimage-yuv/src/yuv422.rs +++ b/ffimage-yuv/src/yuv422.rs @@ -1,10 +1,5 @@ use core::ops::{Deref, DerefMut}; -use itertools::Itertools; -use num_traits::{AsPrimitive, FromPrimitive}; - -use ffimage::color::Rgb; -use ffimage::convert::MapPixels; use ffimage::traits::Pixel; use crate::yuv::*; @@ -89,93 +84,6 @@ where } } -impl - MapPixels, Yuv> for Yuv422 -where - T: Copy, -{ - fn map_pixels<'a, I, O>(input: I, output: O) - where - I: IntoIterator>, - O: IntoIterator>, - T: 'a, - { - input - .into_iter() - .zip(output.into_iter().tuples()) - .for_each(|(t, (u1, u2))| { - let yuv = <[Yuv; 2]>::from(*t); - *u1 = yuv[0]; - *u2 = yuv[1]; - }) - } -} - -impl - MapPixels, Yuv422> for Yuv -where - T: Copy, -{ - fn map_pixels<'a, I, O>(input: I, output: O) - where - I: IntoIterator>, - O: IntoIterator>, - T: 'a, - { - input - .into_iter() - .tuples() - .zip(output.into_iter()) - .for_each(|((sp1, sp2), dp)| { - *dp = Yuv422::::from([*sp1, *sp2]); - }) - } -} - -impl - MapPixels, Rgb> for Yuv422 -where - T: Copy + Default + AsPrimitive + FromPrimitive, -{ - fn map_pixels<'a, I, O>(input: I, output: O) - where - I: IntoIterator>, - O: IntoIterator>, - T: 'a, - { - input - .into_iter() - .zip(output.into_iter().tuples()) - .for_each(|(t, (u1, u2))| { - let yuv = <[Yuv; 2]>::from(*t); - *u1 = Rgb::::from(yuv[0]); - *u2 = Rgb::::from(yuv[1]); - }) - } -} - -impl - MapPixels, Rgb> for Yuv422 -where - T: Copy + Default + AsPrimitive + FromPrimitive, -{ - fn map_pixels<'a, I, O>(input: I, output: O) - where - I: IntoIterator>, - O: IntoIterator>, - T: 'a, - { - input - .into_iter() - .zip(output.into_iter().tuples()) - .for_each(|(t, (u1, u2))| { - let yuv = <[Yuv; 2]>::from(*t); - *u1 = Rgb::::from(yuv[0]); - *u2 = Rgb::::from(yuv[1]); - }) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/ffimage/Cargo.toml b/ffimage/Cargo.toml index ed3ef11..e6577a5 100644 --- a/ffimage/Cargo.toml +++ b/ffimage/Cargo.toml @@ -12,14 +12,10 @@ repository= "https://github.com/raymanfx/ffimage" cfg-if = "1.0.0" num = "0.4.0" num-traits = "0.2.14" -rayon = { version = "1.5.0", optional = true } [dev-dependencies] criterion = "0.3.4" -[features] -default = ["rayon"] - [[bench]] name = "bench_main" harness = false diff --git a/ffimage/src/convert.rs b/ffimage/src/convert.rs deleted file mode 100644 index 696fd61..0000000 --- a/ffimage/src/convert.rs +++ /dev/null @@ -1,39 +0,0 @@ -/// Map pixels from one format to another in place -pub trait MapPixels { - /// Converts a number of pixels into a (possibly different) number of pixels with another format - fn map_pixels<'a, I, O: IntoIterator>(input: I, output: O) - where - I: IntoIterator, - O: IntoIterator, - T: 'a, - U: 'a; -} - -// Blanket implementation for pixel conversion. -// If we know how to convert a single pixel into another one, we can automatically convert between -// iterators of them as well. This obviously does not work for macropixels, where one pixel may -// transform into several, so you need to implement the trait yourself for those types. -impl MapPixels for T -where - T: Copy, - U: From, -{ - fn map_pixels<'a, I, O>(input: I, output: O) - where - I: IntoIterator, - O: IntoIterator, - T: 'a, - U: 'a, - { - input - .into_iter() - .zip(output.into_iter()) - .for_each(|(t, u)| *u = U::from(*t)) - } -} - -/// Convert between images -pub trait Convert { - /// Converts the buffer into another, possibly with a different format - fn convert(&self, output: &mut B); -} diff --git a/ffimage/src/error.rs b/ffimage/src/error.rs deleted file mode 100644 index fadd56c..0000000 --- a/ffimage/src/error.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::{error, fmt}; - -/// Error type for all fallible operations in this crate. -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum Error { - OutOfBounds, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Error::OutOfBounds => write!(f, "out of bounds"), - } - } -} - -impl error::Error for Error { - fn cause(&self) -> Option<&dyn std::error::Error> { - None - } -} diff --git a/ffimage/src/lib.rs b/ffimage/src/lib.rs index f6fa837..d01a2ef 100644 --- a/ffimage/src/lib.rs +++ b/ffimage/src/lib.rs @@ -25,37 +25,21 @@ //! Here is a very brief example of RGB -> Grayscale conversion of existing memory: //! //! ```no_run -//! use ffimage::packed::{ImageView, ImageBuffer}; //! use ffimage::color::{Rgb, Gray}; -//! use ffimage::convert::Convert; //! -//! // This is our grayscale image memory. +//! // This is our RGB image memory. //! // Usually, this will be allocated by a foreign function (e.g. kernel driver) and contain //! // read-only memory. -//! let mem: [u8; 12] = [0; 12]; -//! -//! // Create a statically typed view of the image, assuming it is RGB 24 bits per pixel. -//! // The u8 parameter denotes the internal storage type used by image pixels. In our case, each -//! // channel requires eight bits, which makes for a total of 3 * 8 = 24 bits per pixel. -//! // The length of the memory slice is validated and a None value is returned when constraints -//! // are violated. -//! let view = ImageView::>::from_buf(&mem, 2, 2).unwrap(); -//! -//! // Create a target buffer for the destination image. -//! // The dimensions should be equal to the source image, otherwise only as many pixels as the -//! // target buffer can hold will be converted. -//! let mut buf = ImageBuffer::>::new(2, 2, 0u8); -//! -//! // Perform the actual conversion. -//! // This cannot fail since the target buffer is resizable. -//! // If the pixel conversion between source and target image is not defined, the compiler will -//! // refuse to compile this line. -//! view.convert(&mut buf); +//! let rgb = vec![Rgb::([10, 10, 10]); 10]; +//! +//! // Convert the pixels into Grayscale pixels by mapping each one individually. +//! let gray: Vec> = rgb +//! .iter() +//! .copied() +//! .map(|rgb| Gray::::from(rgb)) +//! .collect(); //!``` -pub mod error; pub mod traits; pub mod color; -pub mod convert; -pub mod packed; diff --git a/ffimage/src/packed/convert/gold.rs b/ffimage/src/packed/convert/gold.rs deleted file mode 100644 index be08443..0000000 --- a/ffimage/src/packed/convert/gold.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::convert::{Convert, MapPixels}; -use crate::packed::Image; -use crate::traits::Pixel; - -fn _convert(input: &Image, output: &mut Image) -where - SP: Pixel + Copy + MapPixels, - DP: Pixel + Copy, - T: AsRef<[SP::T]>, - U: AsRef<[DP::T]> + AsMut<[DP::T]>, -{ - input - .rows() - .zip(output.rows_mut()) - .for_each(|(in_row, out_row)| SP::map_pixels(in_row, out_row)); -} - -impl Convert> for Image -where - SP: Pixel + Copy + MapPixels, - DP: Pixel + Copy, - T: AsRef<[SP::T]>, - U: AsRef<[DP::T]> + AsMut<[DP::T]>, -{ - fn convert(&self, output: &mut Image) { - _convert(self, output) - } -} diff --git a/ffimage/src/packed/convert/mod.rs b/ffimage/src/packed/convert/mod.rs deleted file mode 100644 index 853175f..0000000 --- a/ffimage/src/packed/convert/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -cfg_if::cfg_if! { - if #[cfg(feature = "rayon")] { - pub mod rayon; - } else { - pub mod gold; - } -} diff --git a/ffimage/src/packed/convert/rayon.rs b/ffimage/src/packed/convert/rayon.rs deleted file mode 100644 index 5b88043..0000000 --- a/ffimage/src/packed/convert/rayon.rs +++ /dev/null @@ -1,35 +0,0 @@ -use rayon::prelude::*; - -use crate::convert::{Convert, MapPixels}; -use crate::packed::Image; -use crate::traits::Pixel; - -fn _convert(input: &Image, output: &mut Image) -where - SP: Pixel + Copy + MapPixels + Sync, - DP: Pixel + Copy + Send, - SP::T: Sync, - DP::T: Send + Sync, - T: AsRef<[SP::T]> + Sync, - U: AsRef<[DP::T]> + AsMut<[DP::T]> + Send, -{ - input - .rows() - .zip(output.rows_mut()) - .par_bridge() - .for_each(|(in_row, out_row)| SP::map_pixels(in_row, out_row)); -} - -impl Convert> for Image -where - SP: Pixel + Copy + MapPixels + Sync, - DP: Pixel + Copy + Send, - SP::T: Sync, - DP::T: Send + Sync, - T: AsRef<[SP::T]> + Sync, - U: AsRef<[DP::T]> + AsMut<[DP::T]> + Send, -{ - fn convert(&self, output: &mut Image) { - _convert(self, output) - } -} diff --git a/ffimage/src/packed/image.rs b/ffimage/src/packed/image.rs deleted file mode 100644 index 0ead201..0000000 --- a/ffimage/src/packed/image.rs +++ /dev/null @@ -1,258 +0,0 @@ -use core::ops::{Index, IndexMut}; - -use std::marker::PhantomData; - -use crate::error::Error; -use crate::packed::iter::{PixelIter, RowIter}; -use crate::packed::Matrix; -use crate::traits::{GenericImage, GenericImageView, Pixel}; - -#[derive(Debug, Clone, Copy)] -/// Image view parametrized by its pixel type -pub struct Image { - raw: Matrix, - width: u32, - height: u32, - - marker: PhantomData, -} - -impl Image -where - T: Pixel, -{ - /// Decomposes the image and returns the backing buffer - pub fn into_buf(self) -> B { - self.raw.into_buf() - } - - /// Returns the length of one pixel row in bytes - pub fn stride(&self) -> usize { - self.raw.row_stride() - } - - /// Returns an iterator over the pixel rows - pub fn rows(&self) -> RowIter<&Self> { - let height = self.height; - RowIter { - img: self, - y: 0, - height, - } - } - - /// Returns an iterator that allows modifying each pixel row - pub fn rows_mut(&mut self) -> RowIter<&mut Self> { - let height = self.height; - RowIter { - img: self, - y: 0, - height, - } - } - - /// Returns an iterator over the pixels - /// - /// The order is: top -> down, left -> right - pub fn pixels(&self) -> PixelIter<&Self> { - let width = self.width; - let height = self.height; - PixelIter { - img: self, - x: 0, - y: 0, - width, - height, - } - } - - /// Returns an iterator that allows modifying each pixel - /// - /// The order is: top -> down, left -> right - pub fn pixels_mut(&mut self) -> PixelIter<&mut Self> { - let width = self.width; - let height = self.height; - PixelIter { - img: self, - x: 0, - y: 0, - width, - height, - } - } -} - -impl Image> -where - T: Pixel, - T::T: Clone, -{ - /// Returns a newly allocated image. - /// - /// # Arguments - /// - /// * `width` - Number of columns - /// * `height` - Number of rows - /// * `value` - Initial value for all channels - pub fn new(width: u32, height: u32, value: T::T) -> Self { - let stride = width / T::subpixels() as u32 * T::channels() as u32; - let raw = Matrix::new(height, stride, value); - - Image { - raw, - width, - height, - marker: PhantomData::default(), - } - } -} - -impl Image -where - T: Pixel, - B: AsRef<[T::T]>, -{ - /// Returns an image view with pixel accessors - /// - /// The backing memory storage must have the same element type as the underlying pixel type of - /// the image. - /// - /// # Arguments - /// - /// * `buf` - Raw memory region to interpret as typed image - /// * `width` - Width in pixels - /// * `height` - Height in pixels - pub fn from_buf(buf: B, width: u32, height: u32) -> Option { - let stride = width / T::subpixels() as u32 * T::channels() as u32; - let raw = Matrix::from_buf(buf, height, stride)?; - - Some(Image { - raw, - width, - height, - marker: PhantomData::default(), - }) - } - - /// Returns an image view with pixel accessors - /// - /// The backing memory storage must have the same element type as the underlying pixel type of - /// the image. - /// - /// # Arguments - /// - /// * `buf` - Raw memory region to interpret as typed image - /// * `width` - Width in pixels - /// * `height` - Height in pixels - /// * `stride` - Length of one pixel row in bytes - pub fn from_buf_with_stride(buf: B, width: u32, height: u32, stride: usize) -> Option { - let raw = Matrix::from_buf_with_stride(buf, height, stride, width * T::channels() as u32)?; - - Some(Image { - raw, - width, - height, - marker: PhantomData::default(), - }) - } -} - -impl AsRef<[T::T]> for Image -where - T: Pixel, - B: AsRef<[T::T]>, -{ - fn as_ref(&self) -> &[T::T] { - self.raw.as_ref() - } -} - -impl AsMut<[T::T]> for Image -where - T: Pixel, - B: AsMut<[T::T]>, -{ - fn as_mut(&mut self) -> &mut [T::T] { - self.raw.as_mut() - } -} - -impl GenericImageView for Image -where - T: Pixel + Copy, - B: AsRef<[T::T]>, -{ - type T = T; - - fn width(&self) -> u32 { - self.width - } - - fn height(&self) -> u32 { - self.height - } - - fn pixel(&self, x: u32, y: u32) -> Option { - if x >= self.width() || y >= self.height() { - return None; - } - - Some(self[y as usize][x as usize]) - } -} - -impl GenericImage for Image -where - T: Pixel + Copy, - B: AsRef<[T::T]> + AsMut<[T::T]>, -{ - fn set_pixel(&mut self, x: u32, y: u32, pix: &Self::T) -> Result<(), Error> { - if x >= self.width() || y >= self.height() { - return Err(Error::OutOfBounds); - } - - self[y as usize][x as usize] = *pix; - Ok(()) - } -} - -impl Index for Image -where - T: Pixel + Copy, - B: AsRef<[T::T]>, -{ - type Output = [T]; - - fn index(&self, index: usize) -> &Self::Output { - let row = &self.raw[index]; - let (head, body, _tail) = unsafe { row.align_to::() }; - assert!(head.is_empty(), "raw data is not aligned"); - assert_eq!( - body.len(), - (self.width() / T::subpixels() as u32) as usize, - "invalid number of row items" - ); - - body - } -} - -impl IndexMut for Image -where - T: Pixel + Copy, - B: AsRef<[T::T]> + AsMut<[T::T]>, -{ - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - let width = self.width(); - let row = &mut self.raw[index]; - let (head, body, _tail) = unsafe { row.align_to_mut::() }; - assert!(head.is_empty(), "raw data is not aligned"); - assert_eq!( - body.len(), - (width / T::subpixels() as u32) as usize, - "invalid number of row items" - ); - - body - } -} diff --git a/ffimage/src/packed/iter.rs b/ffimage/src/packed/iter.rs deleted file mode 100644 index a8bdf5f..0000000 --- a/ffimage/src/packed/iter.rs +++ /dev/null @@ -1,162 +0,0 @@ -use std::mem; - -use crate::packed::Image; -use crate::traits::{GenericImageView, Pixel}; - -#[derive(Debug)] -/// An iterator type for images to iterate through pixels -pub struct PixelIter { - pub img: T, - pub x: u32, - pub y: u32, - pub width: u32, - pub height: u32, -} - -impl<'a, T, B> Iterator for PixelIter<&'a Image> -where - T: Pixel + Copy, - B: AsRef<[T::T]>, -{ - type Item = &'a T; - - fn next(&mut self) -> Option { - if self.x >= self.width { - self.x = 0; - self.y += 1; - } - - if self.y >= self.height { - return None; - } - - let x = self.x; - self.x += 1; - - Some(&self.img[self.y as usize][x as usize]) - } -} - -impl<'a, T, B> IntoIterator for &'a Image -where - T: Pixel + Copy, - B: AsRef<[T::T]>, -{ - type Item = &'a T; - type IntoIter = PixelIter<&'a Image>; - - fn into_iter(self) -> Self::IntoIter { - let width = self.width(); - let height = self.height(); - - PixelIter { - img: self, - x: 0, - y: 0, - width, - height, - } - } -} - -impl<'a, T, B> Iterator for PixelIter<&'a mut Image> -where - T: Pixel + Copy, - B: AsRef<[T::T]> + AsMut<[T::T]>, -{ - type Item = &'a mut T; - - fn next(&mut self) -> Option { - if self.x >= self.width { - self.x = 0; - self.y += 1; - } - - if self.y >= self.height { - return None; - } - - let x = self.x; - self.x += 1; - - // This is safe because... - // (from http://stackoverflow.com/questions/25730586): - // The Rust compiler does not know that when you ask a mutable iterator for the next - // element, that you get a different reference every time and never the same reference - // twice. Of course, we know that such an iterator won't give you the same reference twice. - unsafe { Some(mem::transmute(&mut self.img[self.y as usize][x as usize])) } - } -} - -impl<'a, T, B> IntoIterator for &'a mut Image -where - T: Pixel + Copy, - B: AsRef<[T::T]> + AsMut<[T::T]>, -{ - type Item = &'a mut T; - type IntoIter = PixelIter<&'a mut Image>; - - fn into_iter(self) -> Self::IntoIter { - let width = self.width(); - let height = self.height(); - - PixelIter { - img: self, - x: 0, - y: 0, - width, - height, - } - } -} - -#[derive(Debug)] -/// An iterator type for images to iterate through pixel rows -pub struct RowIter { - pub img: T, - pub y: u32, - pub height: u32, -} - -impl<'a, T, B> Iterator for RowIter<&'a Image> -where - T: Pixel + Copy, - B: AsRef<[T::T]>, -{ - type Item = &'a [T]; - - fn next(&mut self) -> Option { - let row = self.y as usize; - - self.y += 1; - if self.y > self.height { - return None; - } - - Some(&self.img[row]) - } -} - -impl<'a, T, B> Iterator for RowIter<&'a mut Image> -where - T: Pixel + Copy, - B: AsRef<[T::T]> + AsMut<[T::T]>, -{ - type Item = &'a mut [T]; - - fn next(&mut self) -> Option { - let row = self.y as usize; - - self.y += 1; - if self.y > self.height { - return None; - } - - // This is safe because... - // (from http://stackoverflow.com/questions/25730586): - // The Rust compiler does not know that when you ask a mutable iterator for the next - // element, that you get a different reference every time and never the same reference - // twice. Of course, we know that such an iterator won't give you the same reference twice. - unsafe { Some(mem::transmute(&mut self.img[row])) } - } -} diff --git a/ffimage/src/packed/matrix.rs b/ffimage/src/packed/matrix.rs deleted file mode 100644 index cdee6d2..0000000 --- a/ffimage/src/packed/matrix.rs +++ /dev/null @@ -1,175 +0,0 @@ -use core::ops::{Index, IndexMut}; - -use std::marker::PhantomData; - -#[derive(Debug, Clone, Copy)] -/// 2D matrix in row-major order. -pub struct Matrix { - mem: B, - rows: u32, - row_stride: usize, - cols: u32, - - marker: PhantomData, -} - -impl Matrix { - /// Decomposes the matrix and returns the backing buffer - pub fn into_buf(self) -> B { - self.mem - } - - /// Returns the row count. - pub fn rows(&self) -> u32 { - self.rows - } - - /// Returns the column count. - pub fn cols(&self) -> u32 { - self.cols - } - - /// Returns the length of one row in size of T. - pub fn row_stride(&self) -> usize { - self.row_stride - } -} - -impl Matrix> -where - T: Clone, -{ - /// Returns a newly allocated matrix. - /// - /// # Arguments - /// - /// * `rows` - Number of rows - /// * `cols` - Number of columns - /// * `value` - Initial value for all cells - pub fn new(rows: u32, cols: u32, value: T) -> Self { - let mut mem = Vec::new(); - let row_stride = cols as usize; - let new_len = rows as usize * row_stride; - mem.resize(new_len, value); - - Matrix { - mem, - rows, - row_stride, - cols, - marker: PhantomData::default(), - } - } - - /// Returns a view to the pixel backing storage. - pub fn resize(&mut self, rows: u32, cols: u32, value: T) { - let row_stride = cols as usize; - let new_len = rows as usize * row_stride; - self.mem.resize(new_len, value); - self.rows = rows; - self.cols = cols; - self.row_stride = row_stride; - } -} - -impl Matrix -where - B: AsRef<[T]>, -{ - /// Returns a flat matrix backed by an existing buffer. - /// - /// In case of an inappropriate buffer length, None is returned. - /// - /// # Arguments - /// - /// * `buf` - Backing buffer - /// * `rows` - Number of rows - /// * `cols` - Number of columns - pub fn from_buf(buf: B, rows: u32, cols: u32) -> Option { - // validate bytes per line - let row_stride = cols as usize; - if buf.as_ref().len() < row_stride { - return None; - } - - Some(Matrix { - mem: buf, - rows, - row_stride, - cols, - marker: PhantomData::default(), - }) - } - - /// Returns a flat matrix backed by an existing buffer. - /// - /// In case of an inappropriate buffer length, None is returned. - /// - /// # Arguments - /// - /// * `buf` - Backing buffer - /// * `rows` - Number of rows - /// * `row_stride` - Length of one row in size of T - /// * `cols` - Number of columns - pub fn from_buf_with_stride(buf: B, rows: u32, row_stride: usize, cols: u32) -> Option { - // validate bytes per line - let min_stride = cols as usize; - if row_stride < min_stride || buf.as_ref().len() < rows as usize * min_stride { - return None; - } - - Some(Matrix { - mem: buf, - rows, - row_stride, - cols, - marker: PhantomData::default(), - }) - } -} - -impl AsRef<[T]> for Matrix -where - B: AsRef<[T]>, -{ - fn as_ref(&self) -> &[T] { - self.mem.as_ref() - } -} - -impl AsMut<[T]> for Matrix -where - B: AsMut<[T]>, -{ - fn as_mut(&mut self) -> &mut [T] { - self.mem.as_mut() - } -} - -impl Index for Matrix -where - B: AsRef<[T]>, -{ - type Output = [T]; - - fn index(&self, index: usize) -> &Self::Output { - // determine the offset in the raw buffer - let row_stride = self.row_stride(); - let offset = index * row_stride; - let mem = self.mem.as_ref(); - &mem[offset..offset + row_stride] - } -} - -impl IndexMut for Matrix -where - B: AsRef<[T]> + AsMut<[T]>, -{ - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - // determine the offset in the raw buffer - let row_stride = self.row_stride(); - let offset = index * row_stride; - let mem = self.mem.as_mut(); - &mut mem[offset..offset + row_stride] - } -} diff --git a/ffimage/src/packed/mod.rs b/ffimage/src/packed/mod.rs deleted file mode 100644 index 9f77394..0000000 --- a/ffimage/src/packed/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -pub mod matrix; -pub use matrix::Matrix; - -pub mod image; -pub use image::Image; - -pub mod convert; -pub mod iter; - -use crate::traits::Pixel; - -pub type ImageView<'a, T> = Image::T]>; -pub type ImageViewMut<'a, T> = Image::T]>; -pub type ImageBuffer<'a, T> = Image::T>>; diff --git a/ffimage/src/traits.rs b/ffimage/src/traits.rs index e8107af..1823c11 100644 --- a/ffimage/src/traits.rs +++ b/ffimage/src/traits.rs @@ -1,5 +1,3 @@ -use crate::error::Error; - /// Generic pixel container pub trait Pixel { /// Type of the container elements @@ -11,24 +9,3 @@ pub trait Pixel { /// Number of image pixels for this pixel fn subpixels() -> u8; } - -/// View into an image, provides read-only pixel access -pub trait GenericImageView { - /// Pixel type - type T: Pixel; - - /// Width in pixels - fn width(&self) -> u32; - - /// Height in pixels - fn height(&self) -> u32; - - /// Returns the pixel at the specified coordinates - fn pixel(&self, x: u32, y: u32) -> Option; -} - -/// Buffered image, provides read-write pixel access -pub trait GenericImage: GenericImageView { - /// Sets the pixel values at the specified coordinates - fn set_pixel(&mut self, x: u32, y: u32, pix: &Self::T) -> Result<(), Error>; -}