mirror of
https://github.com/bend-n/fimg.git
synced 2024-12-22 02:28:19 -06:00
blur
This commit is contained in:
parent
24898eb1cd
commit
c02376b96b
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "fimg"
|
name = "fimg"
|
||||||
version = "0.4.22"
|
version = "0.4.23"
|
||||||
authors = ["bend-n <bend.n@outlook.com>"]
|
authors = ["bend-n <bend.n@outlook.com>"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
@ -17,6 +17,7 @@ fontdue = { version = "0.7.3", optional = true }
|
||||||
vecto = "0.1.0"
|
vecto = "0.1.0"
|
||||||
umath = "0.0.7"
|
umath = "0.0.7"
|
||||||
fr = { version = "0.1.1", package = "fer", optional = true }
|
fr = { version = "0.1.1", package = "fer", optional = true }
|
||||||
|
stackblur-iter = { version = "0.2.0", features = ["simd"], optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
iai = { git = "https://github.com/bend-n/iai.git" }
|
iai = { git = "https://github.com/bend-n/iai.git" }
|
||||||
|
@ -50,6 +51,7 @@ harness = false
|
||||||
scale = ["fr"]
|
scale = ["fr"]
|
||||||
save = ["png"]
|
save = ["png"]
|
||||||
text = ["fontdue"]
|
text = ["fontdue"]
|
||||||
|
blur = ["stackblur-iter"]
|
||||||
default = ["save", "scale"]
|
default = ["save", "scale"]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
|
|
|
@ -15,3 +15,4 @@ quick simple image operations
|
||||||
- [x] polygon drawing
|
- [x] polygon drawing
|
||||||
- [x] circle drawing
|
- [x] circle drawing
|
||||||
- [x] text drawing
|
- [x] text drawing
|
||||||
|
- [x] blur
|
51
src/blur.rs
Normal file
51
src/blur.rs
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
use stackblur_iter::imgref::ImgRefMut;
|
||||||
|
|
||||||
|
use crate::{pixels::convert::PFrom, Image};
|
||||||
|
|
||||||
|
impl<T: AsMut<[u32]> + AsRef<[u32]>> Image<T, 1> {
|
||||||
|
/// Blur a image of packed 32 bit integers, `[0xAARRGGBB]`.
|
||||||
|
pub fn blur_argb(&mut self, radius: usize) {
|
||||||
|
let w = self.width() as usize;
|
||||||
|
let h = self.height() as usize;
|
||||||
|
stackblur_iter::simd_blur_argb::<4>(&mut ImgRefMut::new(self.buffer.as_mut(), w, h), radius)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> Image<Box<[u8]>, N>
|
||||||
|
where
|
||||||
|
[u8; 4]: PFrom<N>,
|
||||||
|
[u8; N]: PFrom<4>,
|
||||||
|
{
|
||||||
|
/// Blur a image.
|
||||||
|
/// ```
|
||||||
|
/// # use fimg::Image;
|
||||||
|
/// let mut i = Image::alloc(300, 300).boxed();
|
||||||
|
/// // draw a lil pentagon
|
||||||
|
/// i.poly((150., 150.), 5, 100.0, 0.0, [255]);
|
||||||
|
/// // give it some blur
|
||||||
|
/// i.blur(25);
|
||||||
|
/// assert_eq!(include_bytes!("../tdata/blurred_pentagon.imgbuf"), i.bytes())
|
||||||
|
/// ```
|
||||||
|
pub fn blur(&mut self, radius: usize) {
|
||||||
|
// you know, i optimized blurslice a fair bit, and yet, despite all the extra bit twiddling stackblur-iter is faster.
|
||||||
|
let mut argb = Image::<Box<[u32]>, 1>::from(self.as_ref());
|
||||||
|
argb.blur_argb(radius);
|
||||||
|
for (i, n) in crate::convert::unpack_all(&argb.buffer).enumerate() {
|
||||||
|
*unsafe { self.buffer.get_unchecked_mut(i) } = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> Image<&[u8], N>
|
||||||
|
where
|
||||||
|
[u8; 4]: PFrom<N>,
|
||||||
|
[u8; N]: PFrom<4>,
|
||||||
|
{
|
||||||
|
/// Blur a image.
|
||||||
|
pub fn blur(self, radius: usize) -> Image<Box<[u8]>, N> {
|
||||||
|
let mut argb = Image::<Box<[u32]>, 1>::from(self);
|
||||||
|
argb.blur_argb(radius);
|
||||||
|
// SAFETY: ctor
|
||||||
|
unsafe { Image::new(argb.width, argb.height, &**argb.buffer()) }.into()
|
||||||
|
}
|
||||||
|
}
|
|
@ -62,3 +62,57 @@ boxconv!(3 => 4);
|
||||||
boxconv!(4 => 1);
|
boxconv!(4 => 1);
|
||||||
boxconv!(4 => 2);
|
boxconv!(4 => 2);
|
||||||
boxconv!(4 => 3);
|
boxconv!(4 => 3);
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
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]
|
||||||
|
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>,
|
||||||
|
{
|
||||||
|
/// Pack into ARGB.
|
||||||
|
fn from(value: Image<&[u8], N>) -> Self {
|
||||||
|
let buf = value
|
||||||
|
.chunked()
|
||||||
|
.copied()
|
||||||
|
.map(PFrom::pfrom)
|
||||||
|
.map(pack)
|
||||||
|
.collect();
|
||||||
|
// SAFETY: ctor
|
||||||
|
unsafe { Self::new(value.width, value.height, buf) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unpack_all<const N: usize>(buffer: &[u32]) -> impl Iterator<Item = u8> + '_
|
||||||
|
where
|
||||||
|
[u8; N]: PFrom<4>,
|
||||||
|
{
|
||||||
|
buffer
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(unpack)
|
||||||
|
.flat_map(<[u8; N] as PFrom<4>>::pfrom)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> From<Image<&[u32], 1>> for Image<Box<[u8]>, N>
|
||||||
|
where
|
||||||
|
[u8; N]: PFrom<4>,
|
||||||
|
{
|
||||||
|
fn from(value: Image<&[u32], 1>) -> Self {
|
||||||
|
let buf = unpack_all(value.buffer).collect();
|
||||||
|
// SAFETY: ctor
|
||||||
|
unsafe { Self::new(value.width, value.height, buf) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
//! Misc image ops:
|
//! Misc image ops:
|
||||||
//! - [`Image::repeated`]
|
//! - [`Image::repeated`]
|
||||||
//! - [`Image::overlay`](Overlay), [`Image::overlay_at`](OverlayAt), [`Image::overlay_blended`](BlendingOverlay)
|
//! - [`Image::overlay`](Overlay), [`Image::overlay_at`](OverlayAt), [`Image::overlay_blended`](BlendingOverlay)
|
||||||
|
//! - [`Image::blur`]
|
||||||
#![feature(
|
#![feature(
|
||||||
slice_swap_unchecked,
|
slice_swap_unchecked,
|
||||||
generic_const_exprs,
|
generic_const_exprs,
|
||||||
|
@ -60,6 +61,8 @@
|
||||||
use std::{num::NonZeroU32, slice::SliceIndex};
|
use std::{num::NonZeroU32, slice::SliceIndex};
|
||||||
|
|
||||||
mod affine;
|
mod affine;
|
||||||
|
#[cfg(feature = "blur")]
|
||||||
|
mod blur;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod builder;
|
pub mod builder;
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|
|
@ -24,7 +24,7 @@ impl PFrom<2> for Y {
|
||||||
|
|
||||||
impl PFrom<3> for Y {
|
impl PFrom<3> for Y {
|
||||||
fn pfrom([r, g, b]: RGB) -> Self {
|
fn pfrom([r, g, b]: RGB) -> Self {
|
||||||
[((2126 * r as u16 + 7152 * g as u16 + 722 * b as u16) / 10000) as u8]
|
[((2126 * r as u32 + 7152 * g as u32 + 722 * b as u32) / 10000) as u8]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
BIN
tdata/blurred_pentagon.imgbuf
Normal file
BIN
tdata/blurred_pentagon.imgbuf
Normal file
Binary file not shown.
Loading…
Reference in a new issue