diff --git a/Cargo.toml b/Cargo.toml index 1c85e52..52eff39 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fimg" -version = "0.1.0" +version = "0.2.0" authors = ["bend-n "] license = "MIT" edition = "2021" diff --git a/src/affine.rs b/src/affine.rs index 91d8e5c..f50ba30 100644 --- a/src/affine.rs +++ b/src/affine.rs @@ -1,39 +1,19 @@ -use crate::{FromRefMut, Image}; - -pub trait Rotations { - /// Rotate a image 180 degrees clockwise. - fn rot_180(&mut self); - /// Rotate a image 90 degrees clockwise. - /// # Safety - /// - /// UB if the image is not square - unsafe fn rot_90(&mut self); - /// Rotate a image 270 degrees clockwise, or 90 degrees anti clockwise. - /// # Safety - /// - /// UB if the image is not square - unsafe fn rot_270(&mut self); -} - -pub trait Flips { - /// Flip a image vertically. - fn flip_v(&mut self); +use crate::Image; +impl Image, CHANNELS> { /// Flip a image horizontally. - fn flip_h(&mut self); -} - -impl Flips for Image, CHANNELS> { - fn flip_h(&mut self) { + pub fn flip_h(&mut self) { self.as_mut().flip_h(); } - fn flip_v(&mut self) { + /// Flip a image vertically. + pub fn flip_v(&mut self) { self.as_mut().flip_v(); } } -impl Flips for Image<&mut [u8], CHANNELS> { - fn flip_v(&mut self) { +impl Image<&mut [u8], CHANNELS> { + /// Flip a image vertically. + pub fn flip_v(&mut self) { for y in 0..self.height() / 2 { for x in 0..self.width() { let y2 = self.height() - y - 1; @@ -46,6 +26,7 @@ impl Flips for Image<&mut [u8], CHANNELS> { } } + /// Flip a image horizontally. fn flip_h(&mut self) { for y in 0..self.height() { for x in 0..self.width() / 2 { @@ -59,22 +40,32 @@ impl Flips for Image<&mut [u8], CHANNELS> { } } -impl Rotations for Image, CHANNELS> { - fn rot_180(&mut self) { +impl Image, CHANNELS> { + /// Rotate a image 180 degrees clockwise. + pub fn rot_180(&mut self) { self.as_mut().rot_180(); } - unsafe fn rot_90(&mut self) { + /// Rotate a image 90 degrees clockwise. + /// # Safety + /// + /// UB if the image is not square + pub unsafe fn rot_90(&mut self) { unsafe { self.as_mut().rot_90() } } - unsafe fn rot_270(&mut self) { + /// Rotate a image 270 degrees clockwise, or 90 degrees anti clockwise. + /// # Safety + /// + /// UB if the image is not square + pub unsafe fn rot_270(&mut self) { unsafe { self.as_mut().rot_270() } } } -impl Rotations for Image<&mut [u8], CHANNELS> { - fn rot_180(&mut self) { +impl Image<&mut [u8], CHANNELS> { + /// Rotate a image 180 degrees clockwise. + pub fn rot_180(&mut self) { for y in 0..self.height() / 2 { for x in 0..self.width() { let p = unsafe { self.pixel(x, y) }; @@ -99,17 +90,25 @@ impl Rotations for Image<&mut [u8], CHANNELS> { } } + /// Rotate a image 90 degrees clockwise. + /// # Safety + /// + /// UB if the image is not square #[inline] - unsafe fn rot_90(&mut self) { + pub unsafe fn rot_90(&mut self) { // This is done by first flipping self.flip_v(); - // Then transposing the image, to save allocations. + // Then transposing the image, as to not allocate. // SAFETY: caller ensures square unsafe { transpose(self) }; } + /// Rotate a image 270 degrees clockwise, or 90 degrees anti clockwise. + /// # Safety + /// + /// UB if the image is not square #[inline] - unsafe fn rot_270(&mut self) { + pub unsafe fn rot_270(&mut self) { self.flip_h(); // SAFETY: caller ensures squareness unsafe { transpose(self) }; diff --git a/src/lib.rs b/src/lib.rs index d64c02c..c8a2e34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,18 +20,8 @@ use std::{num::NonZeroU32, slice::SliceIndex}; mod affine; mod overlay; -pub use affine::{Flips, Rotations}; pub use overlay::{Overlay, OverlayAt}; -pub trait RepeatNew { - type Output; - /// Repeat self till it fills a new image of size x, y - /// # Safety - /// - /// UB if self's width is not a multiple of x, or self's height is not a multiple of y - unsafe fn repeated(&self, x: u32, y: u32) -> Self::Output; -} - macro_rules! assert_unchecked { ($cond:expr) => {{ if !$cond { @@ -46,9 +36,12 @@ macro_rules! assert_unchecked { } use assert_unchecked; -impl RepeatNew for Image<&[u8], 3> { - type Output = Image, 3>; - unsafe fn repeated(&self, x: u32, y: u32) -> Self::Output { +impl Image<&[u8], 3> { + /// Repeat self till it fills a new image of size x, y + /// # Safety + /// + /// UB if self's width is not a multiple of x, or self's height is not a multiple of y + pub unsafe fn repeated(&self, x: u32, y: u32) -> Image, 3> { let mut img = Image::alloc(x, y); // could probably optimize this a ton but eh for x in 0..(x / self.width()) { for y in 0..(y / self.height()) { @@ -68,10 +61,14 @@ unsafe fn really_unsafe_index(x: u32, y: u32, w: u32) -> usize { unsafe { tmp.unchecked_add(x as usize) } } +/// A image with a variable number of channels, and a nonzero size. #[derive(Clone, Debug, PartialEq, Eq)] pub struct Image { + /// column order 2d slice/vec pub buffer: T, + /// image horizontal size pub width: NonZeroU32, + /// image vertical size pub height: NonZeroU32, } @@ -87,16 +84,19 @@ impl Default for Image<&'static [u8], CHANNELS> { impl Image { #[inline] + /// get the height as a [`u32`] pub fn height(&self) -> u32 { self.height.into() } #[inline] + /// get the width as a [`u32`] pub fn width(&self) -> u32 { self.width.into() } #[inline] + /// create a new image pub const fn new(width: NonZeroU32, height: NonZeroU32, buffer: T) -> Self { Image { buffer, @@ -109,6 +109,7 @@ impl Image { impl Image<&[u8], CHANNELS> { #[inline] #[must_use] + /// Copy this ref image pub const fn copy(&self) -> Self { Self { width: self.width, @@ -192,36 +193,30 @@ impl, const CHANNELS: usize> Image { - /// Reference the buffer - fn as_ref(&self) -> Image<&[u8], CHANNELS>; -} - -pub trait FromRefMut { - /// Reference the buffer, mutably - fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS>; -} - -impl FromRef for Image<&mut [u8], CHANNELS> { - fn as_ref(&self) -> Image<&[u8], CHANNELS> { +impl Image<&mut [u8], CHANNELS> { + /// Downcast the mutable reference + pub fn as_ref(&self) -> Image<&[u8], CHANNELS> { Image::new(self.width, self.height, self.buffer) } } -impl FromRefMut for Image<&mut [u8], CHANNELS> { - fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> { +impl Image<&mut [u8], CHANNELS> { + /// Copy this ref image + pub fn copy(&mut self) -> Image<&mut [u8], CHANNELS> { Image::new(self.width, self.height, self.buffer) } } -impl FromRef for Image, CHANNELS> { - fn as_ref(&self) -> Image<&[u8], CHANNELS> { +impl Image, CHANNELS> { + /// Create a reference to this owned image + pub fn as_ref(&self) -> Image<&[u8], CHANNELS> { Image::new(self.width, self.height, &self.buffer) } } -impl FromRefMut for Image, CHANNELS> { - fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> { +impl Image, CHANNELS> { + /// Create a mutable reference to this owned image + pub fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> { Image::new(self.width, self.height, &mut self.buffer) } } diff --git a/src/overlay.rs b/src/overlay.rs index d1211a9..f28d820 100644 --- a/src/overlay.rs +++ b/src/overlay.rs @@ -3,6 +3,7 @@ use std::simd::SimdInt; use std::simd::SimdPartialOrd; use std::simd::{simd_swizzle, Simd}; +/// Trait for layering a image ontop of another, with a offset to the second image. pub trait OverlayAt { /// Overlay with => self at coordinates x, y, without blending /// # Safety @@ -10,7 +11,8 @@ pub trait OverlayAt { /// UB if x, y is out of bounds unsafe fn overlay_at(&mut self, with: &W, x: u32, y: u32) -> &mut Self; } - +/// Trait for layering images ontop of each other. +/// Think `magick a b -layers flatten a` pub trait Overlay { /// Overlay with => self (does not blend) /// # Safety