fast image operations
-rw-r--r--Cargo.toml2
-rw-r--r--src/affine.rs73
-rw-r--r--src/lib.rs57
-rw-r--r--src/overlay.rs4
4 files changed, 66 insertions, 70 deletions
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 <[email protected]>"]
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<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
/// Flip a image horizontally.
- fn flip_h(&mut self);
-}
-
-impl<const CHANNELS: usize> Flips for Image<Vec<u8>, 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<const CHANNELS: usize> Flips for Image<&mut [u8], CHANNELS> {
- fn flip_v(&mut self) {
+impl<const CHANNELS: usize> 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<const CHANNELS: usize> 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<const CHANNELS: usize> Flips for Image<&mut [u8], CHANNELS> {
}
}
-impl<const CHANNELS: usize> Rotations for Image<Vec<u8>, CHANNELS> {
- fn rot_180(&mut self) {
+impl<const CHANNELS: usize> Image<Vec<u8>, 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<const CHANNELS: usize> Rotations for Image<&mut [u8], CHANNELS> {
- fn rot_180(&mut self) {
+impl<const CHANNELS: usize> 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<const CHANNELS: usize> 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<Vec<u8>, 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<Vec<u8>, 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<T, const CHANNELS: usize> {
+ /// 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<const CHANNELS: usize> Default for Image<&'static [u8], CHANNELS> {
impl<T, const CHANNELS: usize> Image<T, CHANNELS> {
#[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<T, const CHANNELS: usize> Image<T, CHANNELS> {
impl<const CHANNELS: usize> 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<T: std::ops::DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANN
}
}
-pub trait FromRef<const CHANNELS: usize> {
- /// Reference the buffer
- fn as_ref(&self) -> Image<&[u8], CHANNELS>;
-}
-
-pub trait FromRefMut<const CHANNELS: usize> {
- /// Reference the buffer, mutably
- fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS>;
-}
-
-impl<const CHANNELS: usize> FromRef<CHANNELS> for Image<&mut [u8], CHANNELS> {
- fn as_ref(&self) -> Image<&[u8], CHANNELS> {
+impl<const CHANNELS: usize> 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<const CHANNELS: usize> FromRefMut<CHANNELS> for Image<&mut [u8], CHANNELS> {
- fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> {
+impl<const CHANNELS: usize> 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<const CHANNELS: usize> FromRef<CHANNELS> for Image<Vec<u8>, CHANNELS> {
- fn as_ref(&self) -> Image<&[u8], CHANNELS> {
+impl<const CHANNELS: usize> Image<Vec<u8>, 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<const CHANNELS: usize> FromRefMut<CHANNELS> for Image<Vec<u8>, CHANNELS> {
- fn as_mut(&mut self) -> Image<&mut [u8], CHANNELS> {
+impl<const CHANNELS: usize> Image<Vec<u8>, 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<W> {
/// Overlay with => self at coordinates x, y, without blending
/// # Safety
@@ -10,7 +11,8 @@ pub trait OverlayAt<W> {
/// 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<W> {
/// Overlay with => self (does not blend)
/// # Safety