fast image operations
-rw-r--r--Cargo.toml1
-rw-r--r--src/convert.rs5
-rw-r--r--src/drawing/text.rs10
-rw-r--r--src/lib.rs8
-rw-r--r--src/overlay.rs3
-rw-r--r--src/show.rs6
6 files changed, 14 insertions, 19 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 19c8ac5..e06a7cd 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,6 +29,7 @@ qwant = { version = "1.0.0", optional = true }
libc = "0.2.154"
hinted = { version = "0.0.2", features = ["nightly"] }
lower = "0.2.0"
+array_chunks = "1.0.0"
[target.'cfg(windows)'.dependencies]
windows = { version = "0.53.0", features = [
diff --git a/src/convert.rs b/src/convert.rs
index 4086ebc..daa04fb 100644
--- a/src/convert.rs
+++ b/src/convert.rs
@@ -1,10 +1,11 @@
//! define From's for images.
//! these conversions are defined by [`PFrom`].
-use crate::{pixels::convert::PFrom, Image, Pack};
+use crate::{Image, Pack, pixels::convert::PFrom};
+use array_chunks::*;
use core::intrinsics::{fmul_algebraic, fsub_algebraic, transmute_unchecked as transmute};
use std::{
mem::MaybeUninit as MU,
- simd::{prelude::*, SimdElement, StdFloat},
+ simd::{SimdElement, StdFloat, prelude::*},
};
fn map<const A: usize, const B: usize>(image: Image<&[u8], A>) -> Image<Box<[u8]>, B>
diff --git a/src/drawing/text.rs b/src/drawing/text.rs
index 7c03101..00a2d65 100644
--- a/src/drawing/text.rs
+++ b/src/drawing/text.rs
@@ -1,11 +1,11 @@
//! text raster
use crate::{
- pixels::{float, Wam},
Image, Pack,
+ pixels::{Wam, float},
};
-use fontdue::{layout::TextStyle, Font};
-use umath::{generic_float::Constructors, FF32};
+use fontdue::{Font, layout::TextStyle};
+use umath::{FF32, generic_float::Constructors};
/// note: `N` may != channels
pub trait Text<const N: usize> {
@@ -37,7 +37,7 @@ impl<T: AsMut<[u32]> + AsRef<[u32]>> Text<4> for Image<T, 1> {
// SAFETY: see above
*(&mut unsafe { self.pixel_mut(x, y) }[0]) =
// SAFETY: fill is 0..=1
- Pack::pack(unsafe { &bg.wam(color, FF32::one() - fill, fill) });
+ Pack::pack(& bg.wam(color, 1.0 - fill, fill));
}
}
}
@@ -67,7 +67,7 @@ impl<const N: usize, T: AsMut<[u8]> + AsRef<[u8]>> Text<N> for Image<T, N> {
// SAFETY: we clampin
let bg = unsafe { &mut *(self.pixel_mut(x, y).as_mut_ptr() as *mut [u8; N]) };
// SAFETY: fill is 0..=1
- *bg = unsafe { bg.wam(color, FF32::one() - fill, fill) };
+ *bg = unsafe { bg.wam(color, *(FF32::one() - fill), fill) };
}
}
}
diff --git a/src/lib.rs b/src/lib.rs
index ebc35cb..8f48516 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -63,9 +63,7 @@
portable_simd,
array_windows,
doc_auto_cfg,
- array_chunks,
iter_chain,
- let_chains,
try_blocks,
test
)]
@@ -86,6 +84,7 @@
confusable_idents,
internal_features
)]
+use array_chunks::*;
use hinted::HintExt;
use std::{hint::assert_unchecked, intrinsics::transmute_unchecked, num::NonZeroU32, ops::Range};
@@ -149,11 +148,8 @@ trait At {
}
impl At for (u32, u32) {
- #[cfg_attr(debug_assertions, track_caller)]
#[inline]
fn at<const C: usize>(self, x: u32, y: u32) -> usize {
- debug_assert!(x < self.0, "x out of bounds");
- debug_assert!(y < self.1, "y out of bounds");
#[allow(clippy::multiple_unsafe_ops_per_block)]
// SAFETY: me when uncheck math: 😧 (FIXME)
let index = unsafe {
@@ -476,13 +472,11 @@ impl<T, const CHANNELS: usize> Image<T, CHANNELS> {
///
/// the output index is not guaranteed to be in bounds
#[inline]
- #[cfg_attr(debug_assertions, track_caller)]
fn slice<U>(&self, x: u32, y: u32) -> Range<usize>
where
T: AsRef<[U]>,
{
let index = self.at(x, y);
- debug_assert!(self.len() > index);
// SAFETY: as long as the buffer isnt wrong, this is 😄
index..unsafe { index.unchecked_add(CHANNELS) }
}
diff --git a/src/overlay.rs b/src/overlay.rs
index 2ab451b..08f3caf 100644
--- a/src/overlay.rs
+++ b/src/overlay.rs
@@ -188,7 +188,6 @@ impl<T: AsMut<[u8]> + AsRef<[u8]>> Image<T, 3> {
impl ClonerOverlay<4, 4> for ImageCloner<'_, 4> {
#[inline]
- #[must_use = "function does not modify the original image"]
unsafe fn overlay(&self, with: &Image<&[u8], 4>) -> Image<Vec<u8>, 4> {
let mut out = self.dup();
// SAFETY: same
@@ -363,7 +362,6 @@ impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> Overlay<Image<U, 4>> for Imag
impl ClonerOverlay<4, 3> for ImageCloner<'_, 3> {
#[inline]
- #[must_use = "function does not modify the original image"]
unsafe fn overlay(&self, with: &Image<&[u8], 4>) -> Image<Vec<u8>, 3> {
let mut out = self.dup();
// SAFETY: same
@@ -393,7 +391,6 @@ impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 4>> for Im
impl ClonerOverlayAt<4, 4> for ImageCloner<'_, 4> {
#[inline]
- #[must_use = "function does not modify the original image"]
unsafe fn overlay_at(&self, with: &Image<&[u8], 4>, x: u32, y: u32) -> Image<Vec<u8>, 4> {
let mut out = self.dup();
// SAFETY: same
diff --git a/src/show.rs b/src/show.rs
index 2a220f4..21b73a3 100644
--- a/src/show.rs
+++ b/src/show.rs
@@ -3,7 +3,7 @@ use crate::Image;
#[cfg(feature = "real-show")]
mod real {
use crate::Image;
- use minifb::{Key, Window};
+ use minifb::{Key, Window, WindowOptions};
pub fn show<const CHANNELS: usize>(i: Image<&[u8], CHANNELS>)
where
@@ -16,6 +16,7 @@ mod real {
Default::default(),
)
.unwrap();
+ win.set_title("image viewer");
let font = fontdue::Font::from_bytes(
&include_bytes!("../data/CascadiaCode.ttf")[..],
fontdue::FontSettings {
@@ -34,6 +35,7 @@ mod real {
.map(|(x, y)| (x.min(i.width()), y.min(i.height())))
{
// SAFETY: ctor
+ let pix = unsafe { i.pixel(x, y) };
unsafe { Image::new(buf.width, buf.height, &mut *buf.buffer) }.text(
5,
i.height() - 20,
@@ -42,7 +44,7 @@ mod real {
&format!(
"P ({x}, {y}), {}",
// SAFETY: clampd
- match unsafe { &i.pixel(x, y)[..] } {
+ match &pix[..] {
[y] => format!("(Y {y})"),
[y, a] => format!("(Y {y} A {a})"),
[r, g, b] => format!("(R {r} G {g} B {b})"),