diff --git a/src/affine.rs b/src/affine.rs index 7404293..b125389 100644 --- a/src/affine.rs +++ b/src/affine.rs @@ -1,3 +1,4 @@ +//! Manages the affine image transformations. use crate::Image; impl Image, CHANNELS> { diff --git a/src/lib.rs b/src/lib.rs index 59cd542..c45bde2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,6 @@ +//! # fimg +//! +//! Provides fast image operations, such as rotation, flipping, and overlaying. #![feature( slice_swap_unchecked, slice_as_chunks, @@ -7,12 +10,13 @@ test )] #![warn( + clippy::missing_docs_in_private_items, clippy::multiple_unsafe_ops_per_block, clippy::missing_const_for_fn, clippy::missing_safety_doc, unsafe_op_in_unsafe_fn, clippy::dbg_macro, - clippy::perf + missing_docs )] #![allow(clippy::zero_prefixed_literal)] @@ -22,6 +26,10 @@ mod affine; mod overlay; pub use overlay::{Overlay, OverlayAt}; +/// like assert!(), but causes undefined behaviour at runtime when the condition is not met. +/// +/// # Safety +/// UB if condition is false. macro_rules! assert_unchecked { ($cond:expr) => {{ if !$cond { @@ -54,6 +62,7 @@ impl Image<&[u8], 3> { } } +/// calculates a column major index, with unchecked math #[inline] unsafe fn really_unsafe_index(x: u32, y: u32, w: u32) -> usize { // y * w + x @@ -98,7 +107,7 @@ impl Image { #[inline] /// create a new image pub const fn new(width: NonZeroU32, height: NonZeroU32, buffer: T) -> Self { - Image { + Self { buffer, width, height, @@ -229,13 +238,15 @@ impl Image, CHANNELS> { /// if width || height == 0 #[must_use] pub fn alloc(width: u32, height: u32) -> Self { - Image { + Self { width: width.try_into().unwrap(), height: height.try_into().unwrap(), buffer: vec![0; CHANNELS * width as usize * height as usize], } } } + +/// helper macro for defining the save() method. macro_rules! save { ($channels:literal == $clr:ident ($clrhuman:literal)) => { impl Image, $channels> { diff --git a/src/overlay.rs b/src/overlay.rs index f28d820..1a059e1 100644 --- a/src/overlay.rs +++ b/src/overlay.rs @@ -1,3 +1,4 @@ +//! Handles image overlay use super::{assert_unchecked, really_unsafe_index, Image}; use std::simd::SimdInt; use std::simd::SimdPartialOrd; @@ -22,11 +23,10 @@ pub trait Overlay { } #[inline] +/// SIMD accelerated rgba => rgb overlay. +/// +/// See [blit](https://en.wikipedia.org/wiki/Bit_blit) unsafe fn blit(rgb: &mut [u8], rgba: &[u8]) { - const LAST4: Simd = Simd::from_array([ - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, - ]); - let mut srci = 0; let mut dsti = 0; while dsti + 16 <= rgb.len() { @@ -38,7 +38,9 @@ unsafe fn blit(rgb: &mut [u8], rgba: &[u8]) { threshold, [3, 3, 3, 7, 7, 7, 11, 11, 11, 15, 15, 15, 0, 0, 0, 0] ); - mask &= LAST4; + mask &= Simd::from_array([ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, + ]); let new_rgb = simd_swizzle!(new, [0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0, 0, 0, 0]); let blended = (new_rgb & mask) | (old & !mask); @@ -106,8 +108,16 @@ impl OverlayAt> for Image<&mut [u8], 3> { } impl OverlayAt> for Image<&mut [u8], 3> { + /// Overlay a RGB image(with) => self at coordinates x, y. + /// As this is a `RGBxRGB` operation, blending is unnecessary, + /// and this is simply a copy. + /// + /// # Safety + /// + /// UB if x, y is out of bounds #[inline] unsafe fn overlay_at(&mut self, with: &Image<&[u8], 3>, x: u32, y: u32) -> &mut Self { + /// helper macro for defining rgb=>rgb overlays. allows unrolling macro_rules! o3x3 { ($n:expr) => {{ for j in 0..($n as usize) {