fast image operations
-rw-r--r--Cargo.toml2
-rw-r--r--src/blur.rs8
-rw-r--r--src/convert.rs36
-rw-r--r--src/drawing/text.rs8
-rw-r--r--src/lib.rs2
-rw-r--r--src/pack.rs55
-rw-r--r--src/show.rs4
7 files changed, 73 insertions, 42 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 52a69ab..6594107 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "fimg"
-version = "0.4.25"
+version = "0.4.26"
authors = ["bend-n <[email protected]>"]
license = "MIT"
edition = "2021"
diff --git a/src/blur.rs b/src/blur.rs
index 62ec9fa..7f00b8f 100644
--- a/src/blur.rs
+++ b/src/blur.rs
@@ -1,6 +1,6 @@
use stackblur_iter::imgref::ImgRefMut;
-use crate::{pixels::convert::PFrom, Image};
+use crate::Image;
impl<T: AsMut<[u32]> + AsRef<[u32]>> Image<T, 1> {
/// Blur a image of packed 32 bit integers, `[0xAARRGGBB]`.
@@ -13,8 +13,7 @@ impl<T: AsMut<[u32]> + AsRef<[u32]>> Image<T, 1> {
impl<const N: usize> Image<Box<[u8]>, N>
where
- [u8; 4]: PFrom<N>,
- [u8; N]: PFrom<4>,
+ [u8; N]: crate::Pack,
{
/// Blur a image.
/// ```
@@ -38,8 +37,7 @@ where
impl<const N: usize> Image<&[u8], N>
where
- [u8; 4]: PFrom<N>,
- [u8; N]: PFrom<4>,
+ [u8; N]: crate::Pack,
{
/// Blur a image.
pub fn blur(self, radius: usize) -> Image<Box<[u8]>, N> {
diff --git a/src/convert.rs b/src/convert.rs
index 3c6c54f..2b0d192 100644
--- a/src/convert.rs
+++ b/src/convert.rs
@@ -1,6 +1,6 @@
//! define From's for images.
//! these conversions are defined by [`PFrom`].
-use crate::{pixels::convert::PFrom, Image};
+use crate::{pixels::convert::PFrom, Image, Pack};
fn map<const A: usize, const B: usize>(image: Image<&[u8], A>) -> Image<Box<[u8]>, B>
where
@@ -64,33 +64,13 @@ boxconv!(4 => 1);
boxconv!(4 => 2);
boxconv!(4 => 3);
-#[inline]
-pub const fn pack([r, g, b, a]: [u8; 4]) -> u32 {
- ((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32)
-}
-
-#[inline]
-pub const fn unpack(n: u32) -> [u8; 4] {
- [
- ((n >> 16) & 0xFF) as u8,
- ((n >> 8) & 0xFF) as u8,
- (n & 0xFF) as u8,
- ((n >> 24) & 0xFF) as u8,
- ]
-}
-
impl<const N: usize> From<Image<&[u8], N>> for Image<Box<[u32]>, 1>
where
- [u8; 4]: PFrom<N>,
+ [u8; N]: Pack,
{
/// Pack into ARGB.
fn from(value: Image<&[u8], N>) -> Self {
- let buf = value
- .chunked()
- .copied()
- .map(PFrom::pfrom)
- .map(pack)
- .collect();
+ let buf = value.chunked().map(Pack::pack).collect();
// SAFETY: ctor
unsafe { Self::new(value.width, value.height, buf) }
}
@@ -98,18 +78,14 @@ where
pub fn unpack_all<const N: usize>(buffer: &[u32]) -> impl Iterator<Item = u8> + '_
where
- [u8; N]: PFrom<4>,
+ [u8; N]: Pack,
{
- buffer
- .iter()
- .copied()
- .map(unpack)
- .flat_map(<[u8; N] as PFrom<4>>::pfrom)
+ buffer.iter().copied().flat_map(<[u8; N]>::unpack)
}
impl<const N: usize> From<Image<&[u32], 1>> for Image<Box<[u8]>, N>
where
- [u8; N]: PFrom<4>,
+ [u8; N]: Pack,
{
fn from(value: Image<&[u32], 1>) -> Self {
let buf = unpack_all(value.buffer).collect();
diff --git a/src/drawing/text.rs b/src/drawing/text.rs
index 192230a..b0b8da2 100644
--- a/src/drawing/text.rs
+++ b/src/drawing/text.rs
@@ -1,9 +1,8 @@
//! text raster
use crate::{
- convert::{pack, unpack},
pixels::{float, Wam},
- Image,
+ Image, Pack,
};
use fontdue::{layout::TextStyle, Font};
use umath::{generic_float::Constructors, FF32};
@@ -37,11 +36,12 @@ impl Image<&mut [u32], 1> {
// SAFETY: the rasterizer kinda promises that metrics width and height are in bounds
let fill = unsafe { float(*bitmap.get_unchecked(j * metrics.width + i)) };
// SAFETY: we clampin
- let bg = unsafe { unpack(*self.buffer.get_unchecked(self.at(x, y))) };
+ let bg: [u8; 4] =
+ unsafe { Pack::unpack(*self.buffer.get_unchecked(self.at(x, y))) };
// SAFETY: see above
*unsafe { self.buffer.get_unchecked_mut(self.at(x, y)) } =
// SAFETY: fill is 0..=1
- pack(unsafe { bg.wam(color, FF32::one() - fill, fill) });
+ Pack::pack(unsafe { &bg.wam(color, FF32::one() - fill, fill) });
}
}
}
diff --git a/src/lib.rs b/src/lib.rs
index f4317a2..46dc7d6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -84,6 +84,8 @@ mod drawing;
mod r#dyn;
pub(crate) mod math;
mod overlay;
+mod pack;
+pub use pack::Pack;
pub mod pixels;
#[cfg(feature = "scale")]
pub mod scale;
diff --git a/src/pack.rs b/src/pack.rs
new file mode 100644
index 0000000..82d41bb
--- /dev/null
+++ b/src/pack.rs
@@ -0,0 +1,55 @@
+//! trait for packing pixels
+
+use crate::pixels::convert::{PFrom, RGB, RGBA, Y, YA};
+
+#[inline]
+pub const fn pack([r, g, b, a]: [u8; 4]) -> u32 {
+ ((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32)
+}
+
+#[inline]
+pub const fn unpack(n: u32) -> [u8; 4] {
+ [
+ ((n >> 16) & 0xFF) as u8,
+ ((n >> 8) & 0xFF) as u8,
+ (n & 0xFF) as u8,
+ ((n >> 24) & 0xFF) as u8,
+ ]
+}
+
+/// packs and unpacks this pixel
+/// note that `unpack(pack(p))` may not equal `p`
+pub trait Pack<P = u32> {
+ /// pack this pixel
+ fn pack(&self) -> P;
+ /// unpacks this pixel
+ fn unpack(from: P) -> Self;
+}
+
+macro_rules! simple {
+ ($p:ident) => {
+ impl Pack for $p {
+ fn pack(&self) -> u32 {
+ pack(PFrom::pfrom(*self))
+ }
+
+ fn unpack(from: u32) -> $p {
+ PFrom::pfrom(unpack(from))
+ }
+ }
+ };
+}
+simple!(RGBA);
+simple!(RGB);
+simple!(YA);
+simple!(Y);
+
+impl Pack<u8> for Y {
+ fn pack(&self) -> u8 {
+ self[0]
+ }
+
+ fn unpack(from: u8) -> Self {
+ [from]
+ }
+}
diff --git a/src/show.rs b/src/show.rs
index 25040cb..f38dbc3 100644
--- a/src/show.rs
+++ b/src/show.rs
@@ -2,12 +2,12 @@ use crate::Image;
#[cfg(feature = "real-show")]
mod real {
- use crate::{pixels::convert::PFrom, Image};
+ use crate::Image;
use minifb::{Key, Window};
pub fn show<const CHANNELS: usize>(i: Image<&[u8], CHANNELS>)
where
- [u8; 4]: PFrom<CHANNELS>,
+ [u8; CHANNELS]: crate::Pack,
{
let mut win = Window::new(
"show",