mirror of
https://github.com/bend-n/fimg.git
synced 2024-12-22 02:28:19 -06:00
use AsRef instead of Deref
This commit is contained in:
parent
101ca55d29
commit
f465e25077
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "fimg"
|
name = "fimg"
|
||||||
version = "0.4.13"
|
version = "0.4.14"
|
||||||
authors = ["bend-n <bend.n@outlook.com>"]
|
authors = ["bend-n <bend.n@outlook.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
|
@ -3,12 +3,13 @@ use fimg::*;
|
||||||
macro_rules! bench {
|
macro_rules! bench {
|
||||||
(fn $name: ident() { run $fn: ident() } $($namec:ident)?) => {
|
(fn $name: ident() { run $fn: ident() } $($namec:ident)?) => {
|
||||||
fn $name() {
|
fn $name() {
|
||||||
|
let mut bytes = *include_bytes!("4_128x128.imgbuf");
|
||||||
let mut img: Image<_, 4> =
|
let mut img: Image<_, 4> =
|
||||||
Image::build(128, 128).buf(include_bytes!("4_128x128.imgbuf").to_vec());
|
Image::build(128, 128).buf(&mut bytes);
|
||||||
for _ in 0..256 {
|
for _ in 0..256 {
|
||||||
#[allow(unused_unsafe)]
|
#[allow(unused_unsafe)]
|
||||||
unsafe {
|
unsafe {
|
||||||
img.$fn()
|
img.as_mut().$fn()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use fimg::*;
|
use fimg::*;
|
||||||
fn tri() {
|
fn tri() {
|
||||||
let mut b = [0u8; 1000 * 1000 * 4];
|
let mut i: Image<_, 4> = fimg::make!(4 channels 1000 x 1000);
|
||||||
let mut i = Image::<&mut [u8], 4>::build(1000, 1000).buf(&mut b);
|
i.as_mut()
|
||||||
i.tri((0., 0.), (1000., 500.), (0., 999.), [255, 255, 255, 255]);
|
.tri((0., 0.), (1000., 500.), (0., 999.), [255, 255, 255, 255]);
|
||||||
}
|
}
|
||||||
iai::main!(tri);
|
iai::main!(tri);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use fimg::*;
|
use fimg::*;
|
||||||
|
|
||||||
fn overlay_3on3at() {
|
fn overlay_3on3at() {
|
||||||
let mut a: Image<_, 3> = Image::alloc(128, 128);
|
let mut a = fimg::make!(3 channels 128 x 128);
|
||||||
let b: Image<&[u8], 3> = Image::build(8, 8).buf(include_bytes!("3_8x8.imgbuf"));
|
let b: Image<&[u8], 3> = Image::build(8, 8).buf(include_bytes!("3_8x8.imgbuf"));
|
||||||
for x in 0..16 {
|
for x in 0..16 {
|
||||||
for y in 0..16 {
|
for y in 0..16 {
|
||||||
|
@ -11,7 +11,7 @@ fn overlay_3on3at() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overlay_4on3at() {
|
fn overlay_4on3at() {
|
||||||
let mut a: Image<_, 3> = Image::alloc(128, 128);
|
let mut a = fimg::make!(3 channels 128 x 128);
|
||||||
let b: Image<&[u8], 4> = Image::build(8, 8).buf(include_bytes!("4_8x8.imgbuf"));
|
let b: Image<&[u8], 4> = Image::build(8, 8).buf(include_bytes!("4_8x8.imgbuf"));
|
||||||
for x in 0..16 {
|
for x in 0..16 {
|
||||||
for y in 0..16 {
|
for y in 0..16 {
|
||||||
|
@ -21,7 +21,7 @@ fn overlay_4on3at() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overlay_4on4at() {
|
fn overlay_4on4at() {
|
||||||
let mut a: Image<_, 4> = Image::alloc(128, 128);
|
let mut a = fimg::make!(4 channels 128 x 128);
|
||||||
let b: Image<&[u8], 4> = Image::build(8, 8).buf(include_bytes!("4_8x8.imgbuf"));
|
let b: Image<&[u8], 4> = Image::build(8, 8).buf(include_bytes!("4_8x8.imgbuf"));
|
||||||
for x in 0..16 {
|
for x in 0..16 {
|
||||||
for y in 0..16 {
|
for y in 0..16 {
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
//! Manages the affine image transformations.
|
//! Manages the affine image transformations.
|
||||||
use std::ops::DerefMut;
|
|
||||||
|
|
||||||
use crate::{cloner::ImageCloner, Image};
|
use crate::{cloner::ImageCloner, Image};
|
||||||
|
|
||||||
impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
|
impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
|
||||||
|
@ -45,7 +43,7 @@ impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const CHANNELS: usize, T: DerefMut<Target = [u8]>> Image<T, CHANNELS> {
|
impl<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>> Image<T, CHANNELS> {
|
||||||
/// Flip an image vertically.
|
/// Flip an image vertically.
|
||||||
pub fn flip_v(&mut self) {
|
pub fn flip_v(&mut self) {
|
||||||
for y in 0..self.height() / 2 {
|
for y in 0..self.height() / 2 {
|
||||||
|
@ -127,7 +125,7 @@ impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const CHANNELS: usize, T: DerefMut<Target = [u8]>> Image<T, CHANNELS> {
|
impl<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>> Image<T, CHANNELS> {
|
||||||
/// Rotate an image 180 degrees clockwise.
|
/// Rotate an image 180 degrees clockwise.
|
||||||
pub fn rot_180(&mut self) {
|
pub fn rot_180(&mut self) {
|
||||||
self.flatten_mut().reverse();
|
self.flatten_mut().reverse();
|
||||||
|
@ -162,7 +160,7 @@ impl<const CHANNELS: usize, T: DerefMut<Target = [u8]>> Image<T, CHANNELS> {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// UB if supplied image not square
|
/// UB if supplied image not square
|
||||||
unsafe fn crev<const CHANNELS: usize, T: DerefMut<Target = [u8]>>(mut img: Image<T, CHANNELS>) {
|
unsafe fn crev<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>>(mut img: Image<T, CHANNELS>) {
|
||||||
debug_assert_eq!(img.width(), img.height());
|
debug_assert_eq!(img.width(), img.height());
|
||||||
let size = img.width() as usize;
|
let size = img.width() as usize;
|
||||||
let b = img.flatten_mut();
|
let b = img.flatten_mut();
|
||||||
|
@ -202,7 +200,7 @@ unsafe fn transpose_out<const CHANNELS: usize>(
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// UB if supplied image rectangular
|
/// UB if supplied image rectangular
|
||||||
unsafe fn transpose<const CHANNELS: usize, T: DerefMut<Target = [u8]>>(
|
unsafe fn transpose<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>>(
|
||||||
img: &mut Image<T, CHANNELS>,
|
img: &mut Image<T, CHANNELS>,
|
||||||
) {
|
) {
|
||||||
debug_assert_eq!(img.width(), img.height());
|
debug_assert_eq!(img.width(), img.height());
|
||||||
|
@ -220,7 +218,7 @@ unsafe fn transpose<const CHANNELS: usize, T: DerefMut<Target = [u8]>>(
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// UB if image not square
|
/// UB if image not square
|
||||||
unsafe fn transpose_non_power_of_two<const CHANNELS: usize, T: DerefMut<Target = [u8]>>(
|
unsafe fn transpose_non_power_of_two<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>>(
|
||||||
img: &mut Image<T, CHANNELS>,
|
img: &mut Image<T, CHANNELS>,
|
||||||
) {
|
) {
|
||||||
debug_assert_eq!(img.width(), img.height());
|
debug_assert_eq!(img.width(), img.height());
|
||||||
|
@ -239,7 +237,7 @@ const TILE: usize = 4;
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// be careful
|
/// be careful
|
||||||
unsafe fn transpose_tile<const CHANNELS: usize, T: DerefMut<Target = [u8]>>(
|
unsafe fn transpose_tile<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>>(
|
||||||
img: &mut Image<T, CHANNELS>,
|
img: &mut Image<T, CHANNELS>,
|
||||||
row: usize,
|
row: usize,
|
||||||
col: usize,
|
col: usize,
|
||||||
|
@ -275,7 +273,7 @@ unsafe fn transpose_tile<const CHANNELS: usize, T: DerefMut<Target = [u8]>>(
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// be careful
|
/// be careful
|
||||||
unsafe fn transpose_diag<const CHANNELS: usize, T: DerefMut<Target = [u8]>>(
|
unsafe fn transpose_diag<const CHANNELS: usize, T: AsMut<[u8]> + AsRef<[u8]>>(
|
||||||
img: &mut Image<T, CHANNELS>,
|
img: &mut Image<T, CHANNELS>,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
size: usize,
|
size: usize,
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//! `Box<cat>`
|
//! `Box<cat>`
|
||||||
use std::ops::{DerefMut, Range};
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::Image;
|
use crate::Image;
|
||||||
|
|
||||||
impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
||||||
/// Draw a bordered box
|
/// Draw a bordered box
|
||||||
/// ```
|
/// ```
|
||||||
/// # use fimg::Image;
|
/// # use fimg::Image;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
//! draw 2d circles
|
//! draw 2d circles
|
||||||
use crate::Image;
|
use crate::Image;
|
||||||
use std::ops::DerefMut;
|
|
||||||
|
|
||||||
impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
|
||||||
|
impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
||||||
/// Draws a circle, using the [Bresenham's circle](https://en.wikipedia.org/wiki/Midpoint_circle_algorithm) algorithm.
|
/// Draws a circle, using the [Bresenham's circle](https://en.wikipedia.org/wiki/Midpoint_circle_algorithm) algorithm.
|
||||||
/// ```
|
/// ```
|
||||||
/// # use fimg::Image;
|
/// # use fimg::Image;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! adds a `line` function to Image
|
//! adds a `line` function to Image
|
||||||
#![allow(clippy::missing_docs_in_private_items)]
|
#![allow(clippy::missing_docs_in_private_items)]
|
||||||
use crate::Image;
|
use crate::Image;
|
||||||
use std::{iter::Iterator, ops::DerefMut};
|
use std::iter::Iterator;
|
||||||
|
|
||||||
/// taken from [bresenham-rs](https://github.com/mbr/bresenham-rs)
|
/// taken from [bresenham-rs](https://github.com/mbr/bresenham-rs)
|
||||||
pub struct Bresenham {
|
pub struct Bresenham {
|
||||||
|
@ -127,7 +127,7 @@ impl Iterator for Bresenham {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
||||||
/// Draw a line from point a to point b.
|
/// Draw a line from point a to point b.
|
||||||
///
|
///
|
||||||
/// Points not in bounds will not be included.
|
/// Points not in bounds will not be included.
|
||||||
|
|
|
@ -2,12 +2,11 @@
|
||||||
use std::{
|
use std::{
|
||||||
cmp::{max, min},
|
cmp::{max, min},
|
||||||
f32::consts::TAU,
|
f32::consts::TAU,
|
||||||
ops::DerefMut,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Image;
|
use crate::Image;
|
||||||
|
|
||||||
impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
||||||
/// Draws a filled polygon from a slice of points. Please close your poly. (first == last)
|
/// Draws a filled polygon from a slice of points. Please close your poly. (first == last)
|
||||||
///
|
///
|
||||||
/// Borrowed from [imageproc](https://docs.rs/imageproc/latest/src/imageproc/drawing/polygon.rs.html#31), modified for less allocations.
|
/// Borrowed from [imageproc](https://docs.rs/imageproc/latest/src/imageproc/drawing/polygon.rs.html#31), modified for less allocations.
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//! trongle drawing
|
//! trongle drawing
|
||||||
use std::ops::DerefMut;
|
|
||||||
|
|
||||||
use crate::Image;
|
use crate::Image;
|
||||||
|
|
||||||
impl<T: DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
||||||
/// Draw a (filled) triangle
|
/// Draw a (filled) triangle
|
||||||
/// ```
|
/// ```
|
||||||
/// # use fimg::*;
|
/// # use fimg::*;
|
||||||
|
|
81
src/lib.rs
81
src/lib.rs
|
@ -233,7 +233,7 @@ impl<const CHANNELS: usize> Image<&[u8], CHANNELS> {
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn make<'a, const WIDTH: u32, const HEIGHT: u32>() -> Image<&'a [u8], CHANNELS>
|
pub const fn make<'a, const WIDTH: u32, const HEIGHT: u32>() -> Image<&'a [u8], CHANNELS>
|
||||||
where
|
where
|
||||||
[(); CHANNELS * WIDTH as usize * HEIGHT as usize]: Sized,
|
[(); CHANNELS * WIDTH as usize * HEIGHT as usize]:,
|
||||||
{
|
{
|
||||||
Image {
|
Image {
|
||||||
width: NonZeroU32::new(WIDTH).expect("passed zero width to builder"),
|
width: NonZeroU32::new(WIDTH).expect("passed zero width to builder"),
|
||||||
|
@ -243,7 +243,40 @@ impl<const CHANNELS: usize> Image<&[u8], CHANNELS> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
#[macro_export]
|
||||||
|
/// Create a <code>[Image]<[[u8]; N], C></code> with ease. If your looking for a <code>[Image]<&'static [[u8]]></code>, try [`Image::make`].
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// let mut i = fimg::make!(4 channels 128 x 128);
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Implementation note:
|
||||||
|
/// This is doable with a const generic fn, but it returns a `fimg::Image<[u8; fimg::::{impl#7}::array::{constant#1}], _>` which means you cant actually type it, so its useless.
|
||||||
|
macro_rules! make {
|
||||||
|
($channels:literal channels $w:literal x $h: literal) => {
|
||||||
|
unsafe {
|
||||||
|
Image::<_, $channels>::new(
|
||||||
|
match ::core::num::NonZeroU32::new($w) {
|
||||||
|
Some(n) => n,
|
||||||
|
None => panic!("width is 0"),
|
||||||
|
},
|
||||||
|
match ::core::num::NonZeroU32::new($h) {
|
||||||
|
::core::option::Option::Some(n) => n,
|
||||||
|
::core::option::Option::None => panic!("height is 0"),
|
||||||
|
},
|
||||||
|
[0_u8; $channels * $w * $h],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
||||||
|
/// The size of the underlying buffer.
|
||||||
|
#[allow(clippy::len_without_is_empty)]
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.buffer.as_ref().len()
|
||||||
|
}
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// the output index is not guranteed to be in bounds
|
/// the output index is not guranteed to be in bounds
|
||||||
|
@ -271,7 +304,7 @@ impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS
|
||||||
};
|
};
|
||||||
// SAFETY: 🧐 is unsound? 😖
|
// SAFETY: 🧐 is unsound? 😖
|
||||||
let index = unsafe { index.unchecked_mul(CHANNELS) };
|
let index = unsafe { index.unchecked_mul(CHANNELS) };
|
||||||
debug_assert!(self.buffer.len() > index);
|
debug_assert!(self.len() > index);
|
||||||
index
|
index
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,24 +317,24 @@ impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS
|
||||||
/// Reference this image.
|
/// Reference this image.
|
||||||
pub fn as_ref(&self) -> Image<&[u8], CHANNELS> {
|
pub fn as_ref(&self) -> Image<&[u8], CHANNELS> {
|
||||||
// SAFETY: we got constructed okay, parameters must be valid
|
// SAFETY: we got constructed okay, parameters must be valid
|
||||||
unsafe { Image::new(self.width, self.height, &*self.buffer) }
|
unsafe { Image::new(self.width, self.height, self.buffer.as_ref()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Returns a iterator over every pixel
|
/// Returns a iterator over every pixel
|
||||||
pub fn chunked(&self) -> impl DoubleEndedIterator<Item = &[u8; CHANNELS]> {
|
pub fn chunked(&self) -> impl DoubleEndedIterator<Item = &[u8; CHANNELS]> {
|
||||||
// SAFETY: 0 sized images illegal
|
// SAFETY: 0 sized images illegal
|
||||||
unsafe { assert_unchecked!(self.buffer.len() > CHANNELS) };
|
unsafe { assert_unchecked!(self.len() > CHANNELS) };
|
||||||
// SAFETY: no half pixels!
|
// SAFETY: no half pixels!
|
||||||
unsafe { assert_unchecked!(self.buffer.len() % CHANNELS == 0) };
|
unsafe { assert_unchecked!(self.len() % CHANNELS == 0) };
|
||||||
self.buffer.array_chunks::<CHANNELS>()
|
self.buffer.as_ref().array_chunks::<CHANNELS>()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Flatten the chunks of this image into a slice of slices.
|
/// Flatten the chunks of this image into a slice of slices.
|
||||||
pub fn flatten(&self) -> &[[u8; CHANNELS]] {
|
pub fn flatten(&self) -> &[[u8; CHANNELS]] {
|
||||||
// SAFETY: buffer cannot have half pixels
|
// SAFETY: buffer cannot have half pixels
|
||||||
unsafe { self.buffer.as_chunks_unchecked::<CHANNELS>() }
|
unsafe { self.buffer.as_ref().as_chunks_unchecked::<CHANNELS>() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a pixel at (x, y).
|
/// Return a pixel at (x, y).
|
||||||
|
@ -312,13 +345,19 @@ impl<T: std::ops::Deref<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS
|
||||||
#[inline]
|
#[inline]
|
||||||
pub unsafe fn pixel(&self, x: u32, y: u32) -> [u8; CHANNELS] {
|
pub unsafe fn pixel(&self, x: u32, y: u32) -> [u8; CHANNELS] {
|
||||||
// SAFETY: x and y in bounds, slice is okay
|
// SAFETY: x and y in bounds, slice is okay
|
||||||
let ptr = unsafe { self.buffer.get_unchecked(self.slice(x, y)).as_ptr().cast() };
|
let ptr = unsafe {
|
||||||
|
self.buffer
|
||||||
|
.as_ref()
|
||||||
|
.get_unchecked(self.slice(x, y))
|
||||||
|
.as_ptr()
|
||||||
|
.cast()
|
||||||
|
};
|
||||||
// SAFETY: slice always returns a length of `CHANNELS`, so we `cast()` it for convenience.
|
// SAFETY: slice always returns a length of `CHANNELS`, so we `cast()` it for convenience.
|
||||||
unsafe { *ptr }
|
unsafe { *ptr }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: std::ops::DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
||||||
/// Return a mutable reference to a pixel at (x, y).
|
/// Return a mutable reference to a pixel at (x, y).
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
@ -329,30 +368,30 @@ impl<T: std::ops::DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANN
|
||||||
// SAFETY: we have been told x, y is in bounds.
|
// SAFETY: we have been told x, y is in bounds.
|
||||||
let idx = self.slice(x, y);
|
let idx = self.slice(x, y);
|
||||||
// SAFETY: slice should always return a valid index
|
// SAFETY: slice should always return a valid index
|
||||||
unsafe { self.buffer.get_unchecked_mut(idx) }
|
unsafe { self.buffer.as_mut().get_unchecked_mut(idx) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Returns a iterator over every pixel, mutably
|
/// Returns a iterator over every pixel, mutably
|
||||||
pub fn chunked_mut(&mut self) -> impl Iterator<Item = &mut [u8; CHANNELS]> {
|
pub fn chunked_mut(&mut self) -> impl Iterator<Item = &mut [u8; CHANNELS]> {
|
||||||
// SAFETY: 0 sized images are not allowed
|
// SAFETY: 0 sized images are not allowed
|
||||||
unsafe { assert_unchecked!(self.buffer.len() > CHANNELS) };
|
unsafe { assert_unchecked!(self.len() > CHANNELS) };
|
||||||
// SAFETY: buffer cannot have half pixels
|
// SAFETY: buffer cannot have half pixels
|
||||||
unsafe { assert_unchecked!(self.buffer.len() % CHANNELS == 0) };
|
unsafe { assert_unchecked!(self.len() % CHANNELS == 0) };
|
||||||
self.buffer.array_chunks_mut::<CHANNELS>()
|
self.buffer.as_mut().array_chunks_mut::<CHANNELS>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a mutref to this image
|
/// Create a mutref to this image
|
||||||
pub fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> {
|
pub fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> {
|
||||||
// SAFETY: construction went okay
|
// SAFETY: construction went okay
|
||||||
unsafe { Image::new(self.width, self.height, &mut self.buffer) }
|
unsafe { Image::new(self.width, self.height, self.buffer.as_mut()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Flatten the chunks of this image into a mutable slice of slices.
|
/// Flatten the chunks of this image into a mutable slice of slices.
|
||||||
pub fn flatten_mut(&mut self) -> &mut [[u8; CHANNELS]] {
|
pub fn flatten_mut(&mut self) -> &mut [[u8; CHANNELS]] {
|
||||||
// SAFETY: buffer cannot have half pixels
|
// SAFETY: buffer cannot have half pixels
|
||||||
unsafe { self.buffer.as_chunks_unchecked_mut::<CHANNELS>() }
|
unsafe { self.buffer.as_mut().as_chunks_unchecked_mut::<CHANNELS>() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
@ -363,13 +402,13 @@ impl<T: std::ops::DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANN
|
||||||
unsafe fn copy_within(&mut self, src: std::ops::Range<usize>, dest: usize) {
|
unsafe fn copy_within(&mut self, src: std::ops::Range<usize>, dest: usize) {
|
||||||
let std::ops::Range { start, end } = src;
|
let std::ops::Range { start, end } = src;
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
dest <= self.buffer.len() - end - start,
|
dest <= self.buffer.as_ref().len() - end - start,
|
||||||
"dest is out of bounds"
|
"dest is out of bounds"
|
||||||
);
|
);
|
||||||
#[allow(clippy::multiple_unsafe_ops_per_block)]
|
#[allow(clippy::multiple_unsafe_ops_per_block)]
|
||||||
// SAFETY: the caller better be good
|
// SAFETY: the caller better be good
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = self.buffer.as_mut_ptr();
|
let ptr = self.buffer.as_mut().as_mut_ptr();
|
||||||
std::ptr::copy_nonoverlapping(ptr.add(start), ptr.add(dest), end - start)
|
std::ptr::copy_nonoverlapping(ptr.add(start), ptr.add(dest), end - start)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -399,7 +438,7 @@ impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
|
impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
|
||||||
/// Allocates a new image
|
/// Allocates a new image. If `width` and `height` are constant, try using [`make`].
|
||||||
///
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
|
@ -417,7 +456,7 @@ impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
|
||||||
/// helper macro for defining the save() method.
|
/// helper macro for defining the save() method.
|
||||||
macro_rules! save {
|
macro_rules! save {
|
||||||
($channels:literal == $clr:ident ($clrhuman:literal)) => {
|
($channels:literal == $clr:ident ($clrhuman:literal)) => {
|
||||||
impl<T: std::ops::Deref<Target = [u8]>> Image<T, $channels> {
|
impl<T: AsRef<[u8]>> Image<T, $channels> {
|
||||||
#[cfg(feature = "save")]
|
#[cfg(feature = "save")]
|
||||||
#[doc = "Save this "]
|
#[doc = "Save this "]
|
||||||
#[doc = $clrhuman]
|
#[doc = $clrhuman]
|
||||||
|
@ -436,7 +475,7 @@ macro_rules! save {
|
||||||
(0.15000, 0.06000),
|
(0.15000, 0.06000),
|
||||||
));
|
));
|
||||||
let mut writer = enc.write_header().unwrap();
|
let mut writer = enc.write_header().unwrap();
|
||||||
writer.write_image_data(&self.buffer).unwrap();
|
writer.write_image_data(self.buffer.as_ref()).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
use crate::cloner::ImageCloner;
|
use crate::cloner::ImageCloner;
|
||||||
|
|
||||||
use super::{assert_unchecked, Image};
|
use super::{assert_unchecked, Image};
|
||||||
use std::ops::{Deref, DerefMut};
|
|
||||||
use std::simd::{simd_swizzle, Simd, SimdInt, SimdPartialOrd};
|
use std::simd::{simd_swizzle, Simd, SimdInt, SimdPartialOrd};
|
||||||
|
|
||||||
/// Trait for layering a image ontop of another, with a offset to the second image.
|
/// Trait for layering a image ontop of another, with a offset to the second image.
|
||||||
|
@ -100,7 +99,7 @@ unsafe fn blit(rgb: &mut [u8], rgba: &[u8]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> Overlay<Image<U, 4>> for Image<T, 4> {
|
impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> Overlay<Image<U, 4>> for Image<T, 4> {
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn overlay(&mut self, with: &Image<U, 4>) -> &mut Self {
|
unsafe fn overlay(&mut self, with: &Image<U, 4>) -> &mut Self {
|
||||||
debug_assert!(self.width() == with.width());
|
debug_assert!(self.width() == with.width());
|
||||||
|
@ -108,7 +107,8 @@ impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> Overlay<Image<U, 4>> f
|
||||||
for (i, other_pixels) in with.chunked().enumerate() {
|
for (i, other_pixels) in with.chunked().enumerate() {
|
||||||
if other_pixels[3] >= 128 {
|
if other_pixels[3] >= 128 {
|
||||||
// SAFETY: outside are bounds of index from slice
|
// SAFETY: outside are bounds of index from slice
|
||||||
let own_pixels = unsafe { self.buffer.get_unchecked_mut(i * 4..i * 4 + 4) };
|
let own_pixels =
|
||||||
|
unsafe { self.buffer.as_mut().get_unchecked_mut(i * 4..i * 4 + 4) };
|
||||||
own_pixels.copy_from_slice(other_pixels);
|
own_pixels.copy_from_slice(other_pixels);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ impl ClonerOverlay<4, 4> for ImageCloner<'_, 4> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> OverlayAt<Image<U, 4>> for Image<T, 3> {
|
impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 4>> for Image<T, 3> {
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn overlay_at(&mut self, with: &Image<U, 4>, x: u32, y: u32) -> &mut Self {
|
unsafe fn overlay_at(&mut self, with: &Image<U, 4>, x: u32, y: u32) -> &mut Self {
|
||||||
// SAFETY: caller upholds this
|
// SAFETY: caller upholds this
|
||||||
|
@ -142,9 +142,9 @@ impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> OverlayAt<Image<U, 4>>
|
||||||
+ with.width() as usize)
|
+ with.width() as usize)
|
||||||
* 3;
|
* 3;
|
||||||
// SAFETY: index is in bounds
|
// SAFETY: index is in bounds
|
||||||
let rgb = unsafe { self.buffer.get_unchecked_mut(o_x) };
|
let rgb = unsafe { self.buffer.as_mut().get_unchecked_mut(o_x) };
|
||||||
// SAFETY: bounds are outside index
|
// SAFETY: bounds are outside index
|
||||||
let rgba = unsafe { with.buffer.get_unchecked(i_x) };
|
let rgba = unsafe { with.buffer.as_ref().get_unchecked(i_x) };
|
||||||
// SAFETY: arguments are 🟢
|
// SAFETY: arguments are 🟢
|
||||||
unsafe { blit(rgb, rgba) }
|
unsafe { blit(rgb, rgba) }
|
||||||
}
|
}
|
||||||
|
@ -163,7 +163,7 @@ impl ClonerOverlayAt<4, 3> for ImageCloner<'_, 3> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> OverlayAt<Image<U, 3>> for Image<T, 3> {
|
impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 3>> for Image<T, 3> {
|
||||||
/// Overlay a RGB image(with) => self at coordinates x, y.
|
/// Overlay a RGB image(with) => self at coordinates x, y.
|
||||||
/// As this is a `RGBxRGB` operation, blending is unnecessary,
|
/// As this is a `RGBxRGB` operation, blending is unnecessary,
|
||||||
/// and this is simply a copy.
|
/// and this is simply a copy.
|
||||||
|
@ -182,12 +182,12 @@ impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> OverlayAt<Image<U, 3>>
|
||||||
..((j + y as usize) * self.width() as usize + x as usize + ($n as usize))
|
..((j + y as usize) * self.width() as usize + x as usize + ($n as usize))
|
||||||
* 3;
|
* 3;
|
||||||
// <= because ".." range
|
// <= because ".." range
|
||||||
debug_assert!(o_x.end <= self.buffer().len());
|
debug_assert!(o_x.end <= self.buffer().as_ref().len());
|
||||||
debug_assert!(i_x.end <= with.buffer().len());
|
debug_assert!(i_x.end <= with.buffer().as_ref().len());
|
||||||
// SAFETY: bounds are ✅
|
// SAFETY: bounds are ✅
|
||||||
let a = unsafe { self.buffer.get_unchecked_mut(o_x) };
|
let a = unsafe { self.buffer.as_mut().get_unchecked_mut(o_x) };
|
||||||
// SAFETY: we are in ⬜!
|
// SAFETY: we are in ⬜!
|
||||||
let b = unsafe { with.buffer.get_unchecked(i_x) };
|
let b = unsafe { with.buffer.as_ref().get_unchecked(i_x) };
|
||||||
a.copy_from_slice(b);
|
a.copy_from_slice(b);
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
|
@ -202,19 +202,20 @@ impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> OverlayAt<Image<U, 3>>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> Overlay<Image<U, 4>> for Image<T, 3> {
|
impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> Overlay<Image<U, 4>> for Image<T, 3> {
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn overlay(&mut self, with: &Image<U, 4>) -> &mut Self {
|
unsafe fn overlay(&mut self, with: &Image<U, 4>) -> &mut Self {
|
||||||
debug_assert!(self.width() == with.width());
|
debug_assert!(self.width() == with.width());
|
||||||
debug_assert!(self.height() == with.height());
|
debug_assert!(self.height() == with.height());
|
||||||
for (i, chunk) in with
|
for (i, chunk) in with
|
||||||
.buffer
|
.buffer
|
||||||
|
.as_ref()
|
||||||
.chunks_exact(with.width() as usize * 4)
|
.chunks_exact(with.width() as usize * 4)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
// SAFETY: all the bounds are good
|
// SAFETY: all the bounds are good
|
||||||
let rgb = unsafe {
|
let rgb = unsafe {
|
||||||
self.buffer.get_unchecked_mut(
|
self.buffer.as_mut().get_unchecked_mut(
|
||||||
i * with.width() as usize * 3..(i + 1) * with.width() as usize * 3,
|
i * with.width() as usize * 3..(i + 1) * with.width() as usize * 3,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -236,7 +237,7 @@ impl ClonerOverlay<4, 3> for ImageCloner<'_, 3> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: DerefMut<Target = [u8]>, U: Deref<Target = [u8]>> OverlayAt<Image<U, 4>> for Image<T, 4> {
|
impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 4>> for Image<T, 4> {
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn overlay_at(&mut self, with: &Image<U, 4>, x: u32, y: u32) -> &mut Self {
|
unsafe fn overlay_at(&mut self, with: &Image<U, 4>, x: u32, y: u32) -> &mut Self {
|
||||||
for j in 0..with.height() {
|
for j in 0..with.height() {
|
||||||
|
|
Loading…
Reference in a new issue