mirror of
https://github.com/bend-n/fimg.git
synced 2024-12-22 10:28:21 -06:00
make functions more generic
This commit is contained in:
parent
4eb9c336b0
commit
2e0b8fd7d6
|
@ -1,16 +1,8 @@
|
||||||
//! Manages the affine image transformations.
|
//! Manages the affine image transformations.
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use crate::{cloner::ImageCloner, Image};
|
use crate::{cloner::ImageCloner, Image};
|
||||||
|
|
||||||
impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
|
|
||||||
/// Flip an image horizontally.
|
|
||||||
pub fn flip_h(&mut self) {
|
|
||||||
self.as_mut().flip_h();
|
|
||||||
}
|
|
||||||
/// Flip an image vertically.
|
|
||||||
pub fn flip_v(&mut self) {
|
|
||||||
self.as_mut().flip_v();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
|
impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
|
||||||
/// Flip an image vertically.
|
/// Flip an image vertically.
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -53,7 +45,7 @@ impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
|
impl<const CHANNELS: usize, T: Deref<Target = [u8]> + DerefMut<Target = [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 {
|
||||||
|
@ -89,31 +81,6 @@ impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const CHANNELS: usize> Image<Vec<u8>, CHANNELS> {
|
|
||||||
/// Rotate an image 180 degrees clockwise.
|
|
||||||
pub fn rot_180(&mut self) {
|
|
||||||
self.as_mut().rot_180();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Rotate an image 90 degrees clockwise.
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// UB if the image is not square
|
|
||||||
pub unsafe fn rot_90(&mut self) {
|
|
||||||
// SAFETY: make sure to keep the safety docs linked
|
|
||||||
unsafe { self.as_mut().rot_90() }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Rotate an image 270 degrees clockwise, or 90 degrees anti clockwise.
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// UB if the image is not square
|
|
||||||
pub unsafe fn rot_270(&mut self) {
|
|
||||||
// SAFETY: idk this is just a convenience impl
|
|
||||||
unsafe { self.as_mut().rot_270() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
|
impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
|
||||||
/// Rotate an image 180 degrees clockwise.
|
/// Rotate an image 180 degrees clockwise.
|
||||||
///
|
///
|
||||||
|
@ -164,7 +131,7 @@ impl<const CHANNELS: usize> ImageCloner<'_, CHANNELS> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
|
impl<const CHANNELS: usize, T: Deref<Target = [u8]> + DerefMut<Target = [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();
|
||||||
|
@ -199,7 +166,9 @@ impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// UB if supplied image rectangular
|
/// UB if supplied image rectangular
|
||||||
unsafe fn transpose<const CHANNELS: usize>(img: &mut Image<&mut [u8], CHANNELS>) {
|
unsafe fn transpose<const CHANNELS: usize, T: Deref<Target = [u8]> + DerefMut<Target = [u8]>>(
|
||||||
|
img: &mut Image<T, CHANNELS>,
|
||||||
|
) {
|
||||||
debug_assert_eq!(img.width(), img.height());
|
debug_assert_eq!(img.width(), img.height());
|
||||||
if img.width().is_power_of_two() {
|
if img.width().is_power_of_two() {
|
||||||
// SAFETY: caller gurantees
|
// SAFETY: caller gurantees
|
||||||
|
@ -215,7 +184,12 @@ unsafe fn transpose<const CHANNELS: usize>(img: &mut Image<&mut [u8], CHANNELS>)
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// UB if image not square
|
/// UB if image not square
|
||||||
unsafe fn transpose_non_power_of_two<const CHANNELS: usize>(img: &mut Image<&mut [u8], CHANNELS>) {
|
unsafe fn transpose_non_power_of_two<
|
||||||
|
const CHANNELS: usize,
|
||||||
|
T: Deref<Target = [u8]> + DerefMut<Target = [u8]>,
|
||||||
|
>(
|
||||||
|
img: &mut 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();
|
||||||
|
@ -234,8 +208,11 @@ const TILE: usize = 4;
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// be careful
|
/// be careful
|
||||||
unsafe fn transpose_tile<const CHANNELS: usize>(
|
unsafe fn transpose_tile<
|
||||||
img: &mut Image<&mut [u8], CHANNELS>,
|
const CHANNELS: usize,
|
||||||
|
T: Deref<Target = [u8]> + DerefMut<Target = [u8]>,
|
||||||
|
>(
|
||||||
|
img: &mut Image<T, CHANNELS>,
|
||||||
row: usize,
|
row: usize,
|
||||||
col: usize,
|
col: usize,
|
||||||
size: usize,
|
size: usize,
|
||||||
|
@ -270,8 +247,11 @@ unsafe fn transpose_tile<const CHANNELS: usize>(
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// be careful
|
/// be careful
|
||||||
unsafe fn transpose_diag<const CHANNELS: usize>(
|
unsafe fn transpose_diag<
|
||||||
img: &mut Image<&mut [u8], CHANNELS>,
|
const CHANNELS: usize,
|
||||||
|
T: Deref<Target = [u8]> + DerefMut<Target = [u8]>,
|
||||||
|
>(
|
||||||
|
img: &mut Image<T, CHANNELS>,
|
||||||
pos: usize,
|
pos: usize,
|
||||||
size: usize,
|
size: usize,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -12,7 +12,8 @@ impl<B: buf::Buffer, const C: usize> Image<B, C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Safe [Image] builder.
|
/// Safe [`Image`] builder.
|
||||||
|
#[must_use = "builder must be consumed"]
|
||||||
pub struct Builder<B, const C: usize> {
|
pub struct Builder<B, const C: usize> {
|
||||||
/// the width in a zeroable type. zeroable so as to make the check in [`buf`] easier.
|
/// the width in a zeroable type. zeroable so as to make the check in [`buf`] easier.
|
||||||
width: u32,
|
width: u32,
|
||||||
|
@ -33,6 +34,7 @@ impl<B: buf::Buffer, const C: usize> Builder<B, C> {
|
||||||
|
|
||||||
/// apply a buffer, and build
|
/// apply a buffer, and build
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
#[must_use = "what is it going to do?"]
|
||||||
pub fn buf(self, buffer: B) -> Image<B, C> {
|
pub fn buf(self, buffer: B) -> Image<B, C> {
|
||||||
let len = C as u32 * self.width * self.height;
|
let len = C as u32 * self.width * self.height;
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -53,6 +55,7 @@ impl<B: buf::Buffer, const C: usize> Builder<B, C> {
|
||||||
|
|
||||||
impl<const C: usize> Builder<Vec<u8>, C> {
|
impl<const C: usize> Builder<Vec<u8>, C> {
|
||||||
/// allocate this image
|
/// allocate this image
|
||||||
|
#[must_use = "what is it going to do?"]
|
||||||
pub fn alloc(self) -> Image<Vec<u8>, C> {
|
pub fn alloc(self) -> Image<Vec<u8>, C> {
|
||||||
Image::alloc(self.width, self.height)
|
Image::alloc(self.width, self.height)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
//! `Box<cat>`
|
//! `Box<cat>`
|
||||||
use std::ops::Range;
|
use std::ops::{Deref, DerefMut, Range};
|
||||||
|
|
||||||
use crate::Image;
|
use crate::Image;
|
||||||
|
|
||||||
impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
|
impl<T: Deref<Target = [u8]> + DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
||||||
/// Draw a bordered box
|
/// Draw a bordered box
|
||||||
/// ```
|
/// ```
|
||||||
/// # use fimg::Image;
|
/// # use fimg::Image;
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
//! 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;
|
use std::{
|
||||||
|
iter::Iterator,
|
||||||
|
ops::{Deref, DerefMut},
|
||||||
|
};
|
||||||
|
|
||||||
/// taken from https://github.com/mbr/bresenham-rs/
|
/// taken from [bresenham-rs](https://github.com/mbr/bresenham-rs)
|
||||||
pub struct Bresenham {
|
pub struct Bresenham {
|
||||||
x: i32,
|
x: i32,
|
||||||
y: i32,
|
y: i32,
|
||||||
|
@ -19,7 +22,7 @@ struct Octant(u8);
|
||||||
|
|
||||||
impl Octant {
|
impl Octant {
|
||||||
#[inline]
|
#[inline]
|
||||||
const fn from_points(start: (i32, i32), end: (i32, i32)) -> Octant {
|
const fn from_points(start: (i32, i32), end: (i32, i32)) -> Self {
|
||||||
let mut dx = end.0 - start.0;
|
let mut dx = end.0 - start.0;
|
||||||
let mut dy = end.1 - start.1;
|
let mut dy = end.1 - start.1;
|
||||||
|
|
||||||
|
@ -35,11 +38,11 @@ impl Octant {
|
||||||
let tmp = dx;
|
let tmp = dx;
|
||||||
dx = dy;
|
dx = dy;
|
||||||
dy = -tmp;
|
dy = -tmp;
|
||||||
octant += 2
|
octant += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if dx < dy {
|
if dx < dy {
|
||||||
octant += 1
|
octant += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Octant(octant)
|
Octant(octant)
|
||||||
|
@ -127,7 +130,7 @@ impl Iterator for Bresenham {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
|
impl<T: Deref<Target = [u8]> + DerefMut<Target = [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.
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
//! trongle drawing
|
//! trongle drawing
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
use crate::Image;
|
use crate::Image;
|
||||||
|
|
||||||
impl<const CHANNELS: usize> Image<&mut [u8], CHANNELS> {
|
impl<T: Deref<Target = [u8]> + DerefMut<Target = [u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
||||||
/// Draw a (filled) triangle
|
/// Draw a (filled) triangle
|
||||||
/// ```
|
/// ```
|
||||||
/// # use fimg::*;
|
/// # use fimg::*;
|
||||||
|
|
|
@ -60,6 +60,7 @@ impl Image<&[u8], 3> {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// UB if self's width is not a multiple of x, or self's height is not a multiple of y
|
/// UB if self's width is not a multiple of x, or self's height is not a multiple of y
|
||||||
|
#[must_use = "function does not modify the original image"]
|
||||||
pub unsafe fn repeated(&self, x: u32, y: u32) -> Image<Vec<u8>, 3> {
|
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
|
let mut img = Image::alloc(x, y); // could probably optimize this a ton but eh
|
||||||
for x in 0..(x / self.width()) {
|
for x in 0..(x / self.width()) {
|
||||||
|
@ -448,6 +449,6 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn repeat() {
|
fn repeat() {
|
||||||
let x: Image<&[u8], 3> = Image::build(8, 8).buf(include_bytes!("../benches/3_8x8.imgbuf"));
|
let x: Image<&[u8], 3> = Image::build(8, 8).buf(include_bytes!("../benches/3_8x8.imgbuf"));
|
||||||
unsafe { x.repeated(128, 128) }; // repeat 16 times
|
let _ = unsafe { x.repeated(128, 128) }; // repeat 16 times
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,8 @@
|
||||||
use crate::cloner::ImageCloner;
|
use crate::cloner::ImageCloner;
|
||||||
|
|
||||||
use super::{assert_unchecked, really_unsafe_index, Image};
|
use super::{assert_unchecked, really_unsafe_index, Image};
|
||||||
use std::simd::SimdInt;
|
use std::ops::{Deref, DerefMut};
|
||||||
use std::simd::SimdPartialOrd;
|
use std::simd::{simd_swizzle, Simd, SimdInt, SimdPartialOrd};
|
||||||
use std::simd::{simd_swizzle, Simd};
|
|
||||||
|
|
||||||
/// 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.
|
||||||
pub trait OverlayAt<W> {
|
pub trait OverlayAt<W> {
|
||||||
|
@ -101,9 +100,11 @@ unsafe fn blit(rgb: &mut [u8], rgba: &[u8]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Overlay<Image<&[u8], 4>> for Image<&mut [u8], 4> {
|
impl<T: Deref<Target = [u8]> + DerefMut<Target = [u8]>, U: Deref<Target = [u8]>>
|
||||||
|
Overlay<Image<U, 4>> for Image<T, 4>
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn overlay(&mut self, with: &Image<&[u8], 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, other_pixels) in with.chunked().enumerate() {
|
for (i, other_pixels) in with.chunked().enumerate() {
|
||||||
|
@ -128,9 +129,11 @@ impl ClonerOverlay<4, 4> for ImageCloner<'_, 4> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OverlayAt<Image<&[u8], 4>> for Image<&mut [u8], 3> {
|
impl<T: Deref<Target = [u8]> + DerefMut<Target = [u8]>, U: Deref<Target = [u8]>>
|
||||||
|
OverlayAt<Image<U, 4>> for Image<T, 3>
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn overlay_at(&mut self, with: &Image<&[u8], 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
|
||||||
unsafe { assert_unchecked!(x + with.width() <= self.width()) };
|
unsafe { assert_unchecked!(x + with.width() <= self.width()) };
|
||||||
debug_assert!(y + with.height() <= self.height());
|
debug_assert!(y + with.height() <= self.height());
|
||||||
|
@ -164,7 +167,9 @@ impl ClonerOverlayAt<4, 3> for ImageCloner<'_, 3> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OverlayAt<Image<&[u8], 3>> for Image<&mut [u8], 3> {
|
impl<T: Deref<Target = [u8]> + DerefMut<Target = [u8]>, U: Deref<Target = [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.
|
||||||
|
@ -173,7 +178,7 @@ impl OverlayAt<Image<&[u8], 3>> for Image<&mut [u8], 3> {
|
||||||
///
|
///
|
||||||
/// UB if x, y is out of bounds
|
/// UB if x, y is out of bounds
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn overlay_at(&mut self, with: &Image<&[u8], 3>, x: u32, y: u32) -> &mut Self {
|
unsafe fn overlay_at(&mut self, with: &Image<U, 3>, x: u32, y: u32) -> &mut Self {
|
||||||
/// helper macro for defining rgb=>rgb overlays. allows unrolling
|
/// helper macro for defining rgb=>rgb overlays. allows unrolling
|
||||||
macro_rules! o3x3 {
|
macro_rules! o3x3 {
|
||||||
($n:expr) => {{
|
($n:expr) => {{
|
||||||
|
@ -203,9 +208,11 @@ impl OverlayAt<Image<&[u8], 3>> for Image<&mut [u8], 3> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Overlay<Image<&[u8], 4>> for Image<&mut [u8], 3> {
|
impl<T: Deref<Target = [u8]> + DerefMut<Target = [u8]>, U: Deref<Target = [u8]>>
|
||||||
|
Overlay<Image<U, 4>> for Image<T, 3>
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn overlay(&mut self, with: &Image<&[u8], 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
|
||||||
|
@ -237,7 +244,9 @@ impl ClonerOverlay<4, 3> for ImageCloner<'_, 3> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OverlayAt<Image<&[u8], 4>> for Image<&mut [u8], 4> {
|
impl<T: Deref<Target = [u8]> + DerefMut<Target = [u8]>, U: Deref<Target = [u8]>>
|
||||||
|
OverlayAt<Image<U, 4>> for Image<T, 4>
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Overlay with => self at coordinates x, y, without blending
|
/// Overlay with => self at coordinates x, y, without blending
|
||||||
///
|
///
|
||||||
|
@ -245,7 +254,7 @@ impl OverlayAt<Image<&[u8], 4>> for Image<&mut [u8], 4> {
|
||||||
/// - UB if x, y is out of bounds
|
/// - UB if x, y is out of bounds
|
||||||
/// - UB if x + with.width() > [`u32::MAX`]
|
/// - UB if x + with.width() > [`u32::MAX`]
|
||||||
/// - UB if y + with.height() > [`u32::MAX`]
|
/// - UB if y + with.height() > [`u32::MAX`]
|
||||||
unsafe fn overlay_at(&mut self, with: &Image<&[u8], 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() {
|
||||||
for i in 0..with.width() {
|
for i in 0..with.width() {
|
||||||
// SAFETY: i, j is in bounds.
|
// SAFETY: i, j is in bounds.
|
||||||
|
|
|
@ -9,6 +9,7 @@ impl Nearest {
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// `image` must be as big or bigger than `width`, `height.
|
/// `image` must be as big or bigger than `width`, `height.
|
||||||
|
#[must_use = "function does not modify the original image"]
|
||||||
pub unsafe fn scale<const N: usize>(
|
pub unsafe fn scale<const N: usize>(
|
||||||
image: Image<&[u8], N>,
|
image: Image<&[u8], N>,
|
||||||
width: u32,
|
width: u32,
|
||||||
|
|
Loading…
Reference in a new issue