mirror of
https://github.com/bend-n/fimg.git
synced 2024-12-22 02:28:19 -06:00
optimize repeat
This commit is contained in:
parent
3085edbed5
commit
1f71a8ab8b
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "fimg"
|
name = "fimg"
|
||||||
version = "0.4.31"
|
version = "0.4.32"
|
||||||
authors = ["bend-n <bend.n@outlook.com>"]
|
authors = ["bend-n <bend.n@outlook.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2023 bendn
|
Copyright (c) 2024 bendn
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
84
src/lib.rs
84
src/lib.rs
|
@ -48,6 +48,7 @@
|
||||||
//! without the `real-show` feature, [`Image::show`] will save itself to your temp directory, which you may not want.
|
//! without the `real-show` feature, [`Image::show`] will save itself to your temp directory, which you may not want.
|
||||||
//! - `default`: \[`save`, `scale`\].
|
//! - `default`: \[`save`, `scale`\].
|
||||||
#![feature(
|
#![feature(
|
||||||
|
maybe_uninit_write_slice,
|
||||||
slice_swap_unchecked,
|
slice_swap_unchecked,
|
||||||
generic_const_exprs,
|
generic_const_exprs,
|
||||||
slice_as_chunks,
|
slice_as_chunks,
|
||||||
|
@ -71,7 +72,7 @@
|
||||||
missing_docs
|
missing_docs
|
||||||
)]
|
)]
|
||||||
#![allow(clippy::zero_prefixed_literal, incomplete_features)]
|
#![allow(clippy::zero_prefixed_literal, incomplete_features)]
|
||||||
use std::{num::NonZeroU32, ops::Range};
|
use std::{mem::MaybeUninit, num::NonZeroU32, ops::Range};
|
||||||
|
|
||||||
mod affine;
|
mod affine;
|
||||||
#[cfg(feature = "blur")]
|
#[cfg(feature = "blur")]
|
||||||
|
@ -97,6 +98,28 @@ pub use cloner::ImageCloner;
|
||||||
pub use overlay::{BlendingOverlay, ClonerOverlay, ClonerOverlayAt, Overlay, OverlayAt};
|
pub use overlay::{BlendingOverlay, ClonerOverlay, ClonerOverlayAt, Overlay, OverlayAt};
|
||||||
pub use r#dyn::DynImage;
|
pub use r#dyn::DynImage;
|
||||||
|
|
||||||
|
trait CopyWithinUnchecked {
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// panicless version of [`[T]::copy_within`](`slice::copy_within`), where the slices cant overlap. this uses `memcpy`.
|
||||||
|
/// your slices must be in bounds.
|
||||||
|
/// this isnt a public function, so im not going to say exactly what "in bounds" meeans.
|
||||||
|
unsafe fn copy_within_unchecked(&mut self, src: Range<usize>, dest: usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> CopyWithinUnchecked for [T] {
|
||||||
|
unsafe fn copy_within_unchecked(&mut self, src: Range<usize>, dest: usize) {
|
||||||
|
let std::ops::Range { start, end } = src;
|
||||||
|
debug_assert!(dest <= self.len() - end - start, "dest is out of bounds");
|
||||||
|
#[allow(clippy::multiple_unsafe_ops_per_block)]
|
||||||
|
// SAFETY: the caller better be good
|
||||||
|
unsafe {
|
||||||
|
let ptr = self.as_mut_ptr();
|
||||||
|
std::ptr::copy_nonoverlapping(ptr.add(start), ptr.add(dest), end - start)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// like assert!(), but causes undefined behaviour at runtime when the condition is not met.
|
/// like assert!(), but causes undefined behaviour at runtime when the condition is not met.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
@ -129,7 +152,9 @@ impl Image<&[u8], 3> {
|
||||||
/// ```
|
/// ```
|
||||||
#[must_use = "function does not modify the original image"]
|
#[must_use = "function does not modify the original image"]
|
||||||
pub unsafe fn repeated(&self, out_width: u32, out_height: u32) -> Image<Vec<u8>, 3> {
|
pub unsafe fn repeated(&self, out_width: u32, out_height: u32) -> Image<Vec<u8>, 3> {
|
||||||
let mut img = Image::<_, 3>::alloc(out_width, out_height);
|
let mut img = Vec::with_capacity(3 * out_width as usize * out_height as usize);
|
||||||
|
debug_assert!(out_width % self.width() == 0);
|
||||||
|
debug_assert!(out_height % self.height() == 0);
|
||||||
for y in 0..self.height() {
|
for y in 0..self.height() {
|
||||||
// SAFETY: get one row of pixels
|
// SAFETY: get one row of pixels
|
||||||
let from = unsafe {
|
let from = unsafe {
|
||||||
|
@ -137,25 +162,43 @@ impl Image<&[u8], 3> {
|
||||||
.get_unchecked(self.at(0, y)..self.at(0, y) + (self.width() as usize * 3))
|
.get_unchecked(self.at(0, y)..self.at(0, y) + (self.width() as usize * 3))
|
||||||
};
|
};
|
||||||
debug_assert_eq!(from.len(), self.width() as usize * 3);
|
debug_assert_eq!(from.len(), self.width() as usize * 3);
|
||||||
let first = img.at(0, y)..img.at(self.width(), y);
|
let first =
|
||||||
|
((y * out_width) as usize * 3)..((y * out_width + self.width()) as usize * 3);
|
||||||
// SAFETY: put it in the output
|
// SAFETY: put it in the output
|
||||||
let to = unsafe { img.buffer.get_unchecked_mut(first.clone()) };
|
let to = unsafe { img.spare_capacity_mut().get_unchecked_mut(first.clone()) };
|
||||||
// copy it in
|
// copy it in
|
||||||
to.copy_from_slice(from);
|
unsafe { assert_unchecked!(to.len() == from.len()) };
|
||||||
|
MaybeUninit::write_slice(to, from);
|
||||||
|
|
||||||
for x in 1..(out_width / self.width()) {
|
for x in 1..(out_width / self.width()) {
|
||||||
let section = img.at(x * self.width(), y);
|
let section = (y * out_width + x * self.width()) as usize * 3;
|
||||||
// SAFETY: copy each row of the image one by one
|
// SAFETY: copy each row of the image one by one
|
||||||
unsafe { img.copy_within(first.clone(), section) };
|
unsafe {
|
||||||
|
img.spare_capacity_mut()
|
||||||
|
.copy_within_unchecked(first.clone(), section)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let first_row = 0..img.at(0, self.height());
|
let first_row = 0..(self.height() * out_width) as usize * 3;
|
||||||
for y in 1..(out_height / self.height()) {
|
for y in 1..(out_height / self.height()) {
|
||||||
let this_row = img.at(0, y * self.height());
|
let this_row = (y * self.height() * out_width) as usize * 3;
|
||||||
// SAFETY: copy entire blocks of image at a time
|
// SAFETY: copy entire blocks of image at a time
|
||||||
unsafe { img.copy_within(first_row.clone(), this_row) };
|
unsafe {
|
||||||
|
img.spare_capacity_mut()
|
||||||
|
.copy_within_unchecked(first_row.clone(), this_row)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// SAFETY: we init
|
||||||
|
unsafe { img.set_len(3 * out_width as usize * out_height as usize) };
|
||||||
|
// SAFETY: ok
|
||||||
|
unsafe {
|
||||||
|
Image::new(
|
||||||
|
out_width.try_into().unwrap(),
|
||||||
|
out_height.try_into().unwrap(),
|
||||||
|
img,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
img
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,25 +563,6 @@ impl<T: AsMut<[u8]> + AsRef<[u8]>, const CHANNELS: usize> Image<T, CHANNELS> {
|
||||||
unsafe { self.buffer.as_mut().as_chunks_unchecked_mut::<CHANNELS>() }
|
unsafe { self.buffer.as_mut().as_chunks_unchecked_mut::<CHANNELS>() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// # Safety
|
|
||||||
///
|
|
||||||
/// panicless version of [`[T]::copy_within`](`slice::copy_within`), where the slices cant overlap. this uses `memcpy`.
|
|
||||||
/// your slices must be in bounds.
|
|
||||||
/// this isnt a public function, so im not going to say exactly what "in bounds" meeans.
|
|
||||||
unsafe fn copy_within(&mut self, src: std::ops::Range<usize>, dest: usize) {
|
|
||||||
let std::ops::Range { start, end } = src;
|
|
||||||
debug_assert!(
|
|
||||||
dest <= self.bytes().len() - end - start,
|
|
||||||
"dest is out of bounds"
|
|
||||||
);
|
|
||||||
#[allow(clippy::multiple_unsafe_ops_per_block)]
|
|
||||||
// SAFETY: the caller better be good
|
|
||||||
unsafe {
|
|
||||||
let ptr = self.buffer.as_mut().as_mut_ptr();
|
|
||||||
std::ptr::copy_nonoverlapping(ptr.add(start), ptr.add(dest), end - start)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set the pixel at x, y
|
/// Set the pixel at x, y
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
|
|
Loading…
Reference in a new issue