From 334d6ff788d39d11faa6734f6836c156287c9257 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Tue, 13 May 2025 14:44:35 +1000 Subject: [PATCH 1/5] Improving existing `no_std` support --- .github/workflows/no_std.yml | 22 ++++++----- crates/zune-bmp/Cargo.toml | 4 +- crates/zune-bmp/src/lib.rs | 6 +-- crates/zune-core/Cargo.toml | 2 +- crates/zune-core/src/bytestream/reader.rs | 2 +- .../src/bytestream/reader/std_readers.rs | 1 + crates/zune-core/src/lib.rs | 7 +++- crates/zune-core/src/options/decoder.rs | 10 ++--- crates/zune-farbfeld/src/lib.rs | 2 +- crates/zune-gif/src/decoder.rs | 2 + crates/zune-gif/src/errors.rs | 4 +- crates/zune-gif/src/lib.rs | 6 +++ crates/zune-hdr/Cargo.toml | 6 ++- crates/zune-hdr/src/encoder.rs | 39 +++++++++++++------ crates/zune-hdr/src/errors.rs | 4 +- crates/zune-hdr/src/lib.rs | 12 ++++-- crates/zune-inflate/Cargo.toml | 5 +-- crates/zune-inflate/src/errors.rs | 3 +- crates/zune-inflate/src/lib.rs | 3 +- crates/zune-jpeg/Cargo.toml | 4 +- crates/zune-jpeg/src/errors.rs | 3 +- crates/zune-jpeg/src/lib.rs | 5 ++- crates/zune-jpegxl/Cargo.toml | 3 +- crates/zune-jpegxl/src/errors.rs | 3 +- crates/zune-jpegxl/src/lib.rs | 7 +++- crates/zune-png/Cargo.toml | 3 +- crates/zune-png/src/apng.rs | 20 ++++++++-- crates/zune-png/src/error.rs | 3 +- crates/zune-png/src/filters/sse4.rs | 6 +-- crates/zune-png/src/lib.rs | 6 ++- crates/zune-png/src/utils.rs | 4 +- crates/zune-psd/src/lib.rs | 1 + crates/zune-qoi/Cargo.toml | 4 +- crates/zune-qoi/src/errors.rs | 6 +-- crates/zune-qoi/src/lib.rs | 4 +- 35 files changed, 138 insertions(+), 84 deletions(-) diff --git a/.github/workflows/no_std.yml b/.github/workflows/no_std.yml index d3d964bb..7ced4074 100644 --- a/.github/workflows/no_std.yml +++ b/.github/workflows/no_std.yml @@ -24,15 +24,17 @@ jobs: # Target below does not have a standard library - run: rustup target add x86_64-unknown-uefi # Below targets run in no-std environments - - run: cargo build -p zune-core --target x86_64-unknown-uefi --no-default-features - - run: cargo build -p zune-inflate --target x86_64-unknown-uefi --no-default-features - - run: cargo build -p zune-jpeg --target x86_64-unknown-uefi --no-default-features - - run: cargo build -p zune-png --target x86_64-unknown-uefi --no-default-features - - run: cargo build -p zune-ppm --target x86_64-unknown-uefi --no-default-features - - run: cargo build -p zune-qoi --target x86_64-unknown-uefi --no-default-features - - run: cargo build -p zune-farbfeld --target x86_64-unknown-uefi --no-default-features - - run: cargo build -p zune-psd --target x86_64-unknown-uefi --no-default-features - - run: cargo build -p zune-bmp --target x86_64-unknown-uefi --no-default-features - + - run: cargo build -p zune-core --target x86_64-unknown-uefi --no-default-features --features log,serde + - run: cargo build -p zune-inflate --target x86_64-unknown-uefi --no-default-features --features zlib,gzip + - run: cargo build -p zune-jpeg --target x86_64-unknown-uefi --no-default-features --features log,x86,neon + - run: cargo build -p zune-png --target x86_64-unknown-uefi --no-default-features --features log,libm + - run: cargo build -p zune-ppm --target x86_64-unknown-uefi --no-default-features --features log + - run: cargo build -p zune-qoi --target x86_64-unknown-uefi --no-default-features --features log + - run: cargo build -p zune-farbfeld --target x86_64-unknown-uefi --no-default-features --features log + - run: cargo build -p zune-psd --target x86_64-unknown-uefi --no-default-features --features log + - run: cargo build -p zune-bmp --target x86_64-unknown-uefi --no-default-features --features log,rgb_inverse + - run: cargo build -p zune-gif --target x86_64-unknown-uefi --no-default-features --features log + - run: cargo build -p zune-hdr --target x86_64-unknown-uefi --no-default-features --features log,libm + - run: cargo build -p zune-jpegxl --target x86_64-unknown-uefi --no-default-features --features log diff --git a/crates/zune-bmp/Cargo.toml b/crates/zune-bmp/Cargo.toml index c11a6ed8..c6132152 100644 --- a/crates/zune-bmp/Cargo.toml +++ b/crates/zune-bmp/Cargo.toml @@ -15,9 +15,11 @@ description = "A fast BMP decoder" [features] log = ["zune-core/log"] -std = ["zune-core/std"] rgb_inverse = [] [dependencies] zune-core = { version = "0.5.0-rc1", path = "../zune-core" } log = "0.4.21" + +[dev-dependencies] +zune-core = { version = "0.5.0-rc1", path = "../zune-core", features = ["std"] } \ No newline at end of file diff --git a/crates/zune-bmp/src/lib.rs b/crates/zune-bmp/src/lib.rs index 16c26e28..059fe3ae 100644 --- a/crates/zune-bmp/src/lib.rs +++ b/crates/zune-bmp/src/lib.rs @@ -54,9 +54,6 @@ //! use zune_bmp::BmpDecoder; //! // read from a file //! let source = BufReader::new(File::open("./image.bmp").unwrap()); -//! // only run when std is enabled, otherwise zune_core doesn't implement the ZByteReader trait -//! // on File since it doesn't exist in `no_std` land -//! #[cfg(feature = "std")] //! let decoder = BmpDecoder::new(source); //! //! ``` @@ -71,9 +68,8 @@ //! benchmark just in case you think it's slowing you down in any way. //! #![no_std] -#![macro_use] -extern crate alloc; +extern crate alloc; extern crate core; pub use zune_core; diff --git a/crates/zune-core/Cargo.toml b/crates/zune-core/Cargo.toml index 0349f68b..0cfceae3 100644 --- a/crates/zune-core/Cargo.toml +++ b/crates/zune-core/Cargo.toml @@ -19,4 +19,4 @@ std = [] [dependencies] log = { version = "0.4.17", optional = true } -serde = { version = "1.0.52", optional = true } +serde = { version = "1.0.52", optional = true, default-features = false } diff --git a/crates/zune-core/src/bytestream/reader.rs b/crates/zune-core/src/bytestream/reader.rs index 8d49c4bf..de5ad204 100644 --- a/crates/zune-core/src/bytestream/reader.rs +++ b/crates/zune-core/src/bytestream/reader.rs @@ -453,6 +453,6 @@ where fn read(&mut self, buf: &mut [u8]) -> std::io::Result { use std::io::ErrorKind; self.read_bytes(buf) - .map_err(|e| std::io::Error::new(ErrorKind::Other, format!("{:?}", e))) + .map_err(|e| std::io::Error::new(ErrorKind::Other, alloc::format!("{:?}", e))) } } diff --git a/crates/zune-core/src/bytestream/reader/std_readers.rs b/crates/zune-core/src/bytestream/reader/std_readers.rs index 014d0bd3..730dee26 100644 --- a/crates/zune-core/src/bytestream/reader/std_readers.rs +++ b/crates/zune-core/src/bytestream/reader/std_readers.rs @@ -1,5 +1,6 @@ #![cfg(feature = "std")] +use alloc::vec::Vec; use std::io; use std::io::SeekFrom; diff --git a/crates/zune-core/src/lib.rs b/crates/zune-core/src/lib.rs index 77355f93..4f745031 100644 --- a/crates/zune-core/src/lib.rs +++ b/crates/zune-core/src/lib.rs @@ -43,11 +43,14 @@ //! //! //! -#![cfg_attr(not(feature = "std"), no_std)] -#![macro_use] +#![no_std] + extern crate alloc; extern crate core; +#[cfg(feature = "std")] +extern crate std; + #[cfg(not(feature = "log"))] pub mod log; diff --git a/crates/zune-core/src/options/decoder.rs b/crates/zune-core/src/options/decoder.rs index 6093c70e..177957a2 100644 --- a/crates/zune-core/src/options/decoder.rs +++ b/crates/zune-core/src/options/decoder.rs @@ -450,7 +450,7 @@ impl DecoderOptions { // where we can do runtime check if feature is present #[cfg(feature = "std")] { - if is_x86_feature_detected!("sse2") { + if std::is_x86_feature_detected!("sse2") { return true; } } @@ -483,7 +483,7 @@ impl DecoderOptions { // where we can do runtime check if feature is present #[cfg(feature = "std")] { - if is_x86_feature_detected!("sse3") { + if std::is_x86_feature_detected!("sse3") { return true; } } @@ -515,7 +515,7 @@ impl DecoderOptions { // where we can do runtime check if feature is present #[cfg(feature = "std")] { - if is_x86_feature_detected!("sse4.1") { + if std::is_x86_feature_detected!("sse4.1") { return true; } } @@ -547,7 +547,7 @@ impl DecoderOptions { // where we can do runtime check if feature is present #[cfg(feature = "std")] { - if is_x86_feature_detected!("avx") { + if std::is_x86_feature_detected!("avx") { return true; } } @@ -579,7 +579,7 @@ impl DecoderOptions { // where we can do runtime check if feature is present #[cfg(feature = "std")] { - if is_x86_feature_detected!("avx2") { + if std::is_x86_feature_detected!("avx2") { return true; } } diff --git a/crates/zune-farbfeld/src/lib.rs b/crates/zune-farbfeld/src/lib.rs index 167be93c..01ffeb55 100644 --- a/crates/zune-farbfeld/src/lib.rs +++ b/crates/zune-farbfeld/src/lib.rs @@ -24,7 +24,7 @@ //! //! #![no_std] -#![macro_use] + extern crate alloc; pub use decoder::*; diff --git a/crates/zune-gif/src/decoder.rs b/crates/zune-gif/src/decoder.rs index f1d2e6e1..c0bd0965 100644 --- a/crates/zune-gif/src/decoder.rs +++ b/crates/zune-gif/src/decoder.rs @@ -1,3 +1,5 @@ +use alloc::vec::Vec; + use zune_core::bytestream::{ZByteReaderTrait, ZReader}; use zune_core::log::trace; use zune_core::options::DecoderOptions; diff --git a/crates/zune-gif/src/errors.rs b/crates/zune-gif/src/errors.rs index c2f713a8..0de97b1b 100644 --- a/crates/zune-gif/src/errors.rs +++ b/crates/zune-gif/src/errors.rs @@ -1,5 +1,5 @@ use core::fmt::Debug; -use std::fmt::Formatter; +use core::fmt::Formatter; use zune_core::bytestream::ZByteIoError; @@ -18,7 +18,7 @@ pub enum GifDecoderErrors { TooSmallSize(usize, usize) } impl Debug for GifDecoderErrors { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { match self { GifDecoderErrors::NotAGif => { writeln!(f, "Not a gif, magic bytes didn't match") diff --git a/crates/zune-gif/src/lib.rs b/crates/zune-gif/src/lib.rs index 622b298d..5f953b6d 100644 --- a/crates/zune-gif/src/lib.rs +++ b/crates/zune-gif/src/lib.rs @@ -1,3 +1,9 @@ +#![no_std] + +#[macro_use] +extern crate alloc; +extern crate core; + mod decoder; mod enums; mod errors; diff --git a/crates/zune-hdr/Cargo.toml b/crates/zune-hdr/Cargo.toml index 2cb35035..8b7078fd 100644 --- a/crates/zune-hdr/Cargo.toml +++ b/crates/zune-hdr/Cargo.toml @@ -8,10 +8,14 @@ homepage = "https://github.com/etemesi254/zune-image/tree/dev/crates/zune-hdr" keywords = ["image"] categories = ["multimedia::images", "multimedia::encoding", ] license = "MIT OR Apache-2.0 OR Zlib" +rust-version = "1.81.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] log = ["zune-core/log"] +std = [] +default = ["std"] [dependencies] -zune-core = { version = "0.5.0-rc0", path = "../zune-core", default-features = false, features = ["std"] } \ No newline at end of file +zune-core = { version = "0.5.0-rc0", path = "../zune-core", default-features = false } +libm = { version = "0.2", optional = true } \ No newline at end of file diff --git a/crates/zune-hdr/src/encoder.rs b/crates/zune-hdr/src/encoder.rs index 2bb9f414..9d57a85d 100644 --- a/crates/zune-hdr/src/encoder.rs +++ b/crates/zune-hdr/src/encoder.rs @@ -6,8 +6,7 @@ //! Radiance HDR encoder -use alloc::{format, vec}; -use std::collections::HashMap; +use alloc::{format, vec, string::String, vec::Vec}; use zune_core::bytestream::{ZByteIoError, ZByteWriterTrait, ZWriter}; use zune_core::colorspace::ColorSpace; @@ -21,7 +20,7 @@ use crate::errors::HdrEncodeErrors; /// `width*height*3` pub struct HdrEncoder<'a> { data: &'a [f32], - headers: Option<&'a HashMap>, + headers: Option>, options: EncoderOptions } @@ -45,9 +44,14 @@ impl<'a> HdrEncoder<'a> { /// otherwise it will have no effect. /// /// # Arguments: - /// - headers: A hashmap containing keys and values, the values will be encoded as key=value + /// - headers: An iterator containing keys and values, the values will be encoded as key=value /// in the hdr header before encoding - pub fn add_headers(&mut self, headers: &'a HashMap) { + pub fn add_headers(&mut self, headers: impl IntoIterator) { + let mut headers = headers.into_iter().collect::>(); + + headers.sort_by(|(a, _), (b, _)| a.cmp(b)); + headers.dedup_by(|(a, _), (b, _)| a.eq(&b)); + self.headers = Some(headers) } @@ -155,7 +159,7 @@ impl<'a> HdrEncoder<'a> { { writer.write_all(b"#?RADIANCE\n")?; writer.write_all(b"SOFTWARE=zune-hdr\n")?; - if let Some(headers) = self.headers { + if let Some(headers) = &self.headers { for (k, v) in headers { writer.write_all(format!("{}={}\n", k, v).as_bytes())?; } @@ -337,12 +341,25 @@ fn frexp(s: f32) -> (f32, i32) { } else { let lg = fast_log2(abs(s)); let lg_floor = floor(lg); - // Note: This is the only reason we need the standard library - // I haven't found a good exp2 function, fast_exp2 doesn't work - // and libm/musl exp2 introduces visible color distortions and is slow, so for - // now let's stick to whatever the platform provides - let x = (lg - lg_floor - 1.0).exp2(); + let x = exp2(lg - lg_floor - 1.0); let exp = lg_floor + 1.0; (signum(s) * x, exp as i32) } } + +fn exp2(x: f32) -> f32 { + // Note: This is the only reason we need the standard library + // I haven't found a good exp2 function, fast_exp2 doesn't work + // and libm/musl exp2 introduces visible color distortions and is slow, so for + // now let's stick to whatever the platform provides + #[cfg(all(feature = "std", not(feature = "libm")))] + { + f32::exp2(x) + } + + // For `no_std`, we allow users to select `libm`, even if it produces sub-par results. + #[cfg(feature = "libm")] + { + libm::exp2f(x) + } +} \ No newline at end of file diff --git a/crates/zune-hdr/src/errors.rs b/crates/zune-hdr/src/errors.rs index f37c99be..d40cb1be 100644 --- a/crates/zune-hdr/src/errors.rs +++ b/crates/zune-hdr/src/errors.rs @@ -82,7 +82,7 @@ impl Display for HdrDecodeErrors { writeln!(f, "{:?}", self) } } -impl std::error::Error for HdrDecodeErrors {} +impl core::error::Error for HdrDecodeErrors {} impl Display for HdrEncodeErrors { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { @@ -90,7 +90,7 @@ impl Display for HdrEncodeErrors { } } -impl std::error::Error for HdrEncodeErrors {} +impl core::error::Error for HdrEncodeErrors {} /// HDR encoding errrors pub enum HdrEncodeErrors { diff --git a/crates/zune-hdr/src/lib.rs b/crates/zune-hdr/src/lib.rs index ec0a0993..982077b7 100644 --- a/crates/zune-hdr/src/lib.rs +++ b/crates/zune-hdr/src/lib.rs @@ -29,18 +29,22 @@ //! color primaries, exposure,gamma e.t.c, //! -// CAE: No std doesn't work because we haven't implemented -// floor and exp2 for floats, which do not exist in no std land -// #![no_std] +#![no_std] #![forbid(unsafe_code)] -#![macro_use] + extern crate alloc; extern crate core; + +#[cfg(feature = "std")] +extern crate std; + pub extern crate zune_core; pub use decoder::HdrDecoder; +#[cfg(any(feature = "std", feature = "libm"))] pub use encoder::HdrEncoder; pub use errors::{HdrDecodeErrors, HdrEncodeErrors}; mod decoder; +#[cfg(any(feature = "std", feature = "libm"))] mod encoder; mod errors; diff --git a/crates/zune-inflate/Cargo.toml b/crates/zune-inflate/Cargo.toml index 8762ee1e..b92b87ad 100644 --- a/crates/zune-inflate/Cargo.toml +++ b/crates/zune-inflate/Cargo.toml @@ -9,15 +9,14 @@ homepage = "https://github.com/etemesi254/zune-image/tree/main/zune-inflate" keywords = ["compression", "inflate", "deflate"] categories = ["compression"] license = "MIT OR Apache-2.0 OR Zlib" +rust-version = "1.81.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] zlib = ["simd-adler32"] gzip = [] -std = ["simd-adler32/std"] - -default = ["zlib", "gzip", "std"] +default = ["zlib", "gzip"] [dependencies] simd-adler32 = { version = "0.3.4", optional = true, default-features = false } diff --git a/crates/zune-inflate/src/errors.rs b/crates/zune-inflate/src/errors.rs index 1711ab60..fd645213 100644 --- a/crates/zune-inflate/src/errors.rs +++ b/crates/zune-inflate/src/errors.rs @@ -114,5 +114,4 @@ impl Display for InflateDecodeErrors { } } -#[cfg(feature = "std")] -impl std::error::Error for InflateDecodeErrors {} +impl core::error::Error for InflateDecodeErrors {} diff --git a/crates/zune-inflate/src/lib.rs b/crates/zune-inflate/src/lib.rs index 6edc5895..7b2e68d1 100644 --- a/crates/zune-inflate/src/lib.rs +++ b/crates/zune-inflate/src/lib.rs @@ -86,7 +86,8 @@ //! [libdeflater]: https://github.com/adamkewley/libdeflater //! [flate2-rs]: https://github.com/rust-lang/flate2-rs //! -#![cfg_attr(not(feature = "std"), no_std)] +#![no_std] + extern crate alloc; pub use crate::decoder::{DeflateDecoder, DeflateOptions}; diff --git a/crates/zune-jpeg/Cargo.toml b/crates/zune-jpeg/Cargo.toml index fd8797e3..ccc97453 100644 --- a/crates/zune-jpeg/Cargo.toml +++ b/crates/zune-jpeg/Cargo.toml @@ -9,6 +9,7 @@ keywords = ["jpeg", "jpeg-decoder", "decoder"] categories = ["multimedia::images"] exclude = ["/benches/images/*", "/tests/*", "/.idea/*", "/.gradle/*", "/test-images/*", "fuzz/*"] description = "A fast, correct and safe jpeg decoder" +rust-version = "1.81.0" [lints.rust] # Disable feature checker for fuzzing since it's used and cargo doesn't @@ -20,9 +21,8 @@ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] } [features] x86 = [] neon = [] -std = ["zune-core/std"] log = ["zune-core/log"] -default = ["x86", "neon", "std"] +default = ["x86", "neon"] [dependencies] diff --git a/crates/zune-jpeg/src/errors.rs b/crates/zune-jpeg/src/errors.rs index 1410961e..461df425 100644 --- a/crates/zune-jpeg/src/errors.rs +++ b/crates/zune-jpeg/src/errors.rs @@ -53,8 +53,7 @@ pub enum DecodeErrors { IoErrors(ZByteIoError) } -#[cfg(feature = "std")] -impl std::error::Error for DecodeErrors {} +impl core::error::Error for DecodeErrors {} impl From<&'static str> for DecodeErrors { fn from(data: &'static str) -> Self { diff --git a/crates/zune-jpeg/src/lib.rs b/crates/zune-jpeg/src/lib.rs index 59143bec..c91605b2 100644 --- a/crates/zune-jpeg/src/lib.rs +++ b/crates/zune-jpeg/src/lib.rs @@ -102,8 +102,9 @@ // no_std compatibility #![deny(clippy::std_instead_of_alloc, clippy::alloc_instead_of_core)] #![cfg_attr(not(any(feature = "x86", feature = "neon")), forbid(unsafe_code))] -#![cfg_attr(not(feature = "std"), no_std)] -#![macro_use] +#![no_std] + +#[macro_use] extern crate alloc; extern crate core; diff --git a/crates/zune-jpegxl/Cargo.toml b/crates/zune-jpegxl/Cargo.toml index 8d51d404..dee9b8fd 100644 --- a/crates/zune-jpegxl/Cargo.toml +++ b/crates/zune-jpegxl/Cargo.toml @@ -9,6 +9,7 @@ keywords = ["jpeg-xl", "jpeg-xl-decoder", "decoder", "jxl"] categories = ["multimedia::images"] exclude = [] description = "A simple, fast and fully safe modular jxl encoder" +rust-version = "1.81.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -17,7 +18,7 @@ description = "A simple, fast and fully safe modular jxl encoder" zune-core = { version = "^0.5.0-rc0", path = "../zune-core" } [features] -threads = [] +threads = ["std"] std = [] log = ["zune-core/log"] default = ["threads", "std"] diff --git a/crates/zune-jpegxl/src/errors.rs b/crates/zune-jpegxl/src/errors.rs index ce4b5eea..84aa5820 100644 --- a/crates/zune-jpegxl/src/errors.rs +++ b/crates/zune-jpegxl/src/errors.rs @@ -90,5 +90,4 @@ impl core::fmt::Display for JxlEncodeErrors { } } -#[cfg(feature = "std")] -impl std::error::Error for JxlEncodeErrors {} +impl core::error::Error for JxlEncodeErrors {} diff --git a/crates/zune-jpegxl/src/lib.rs b/crates/zune-jpegxl/src/lib.rs index 7ce5855c..f7e658e4 100644 --- a/crates/zune-jpegxl/src/lib.rs +++ b/crates/zune-jpegxl/src/lib.rs @@ -81,11 +81,14 @@ //! ``` //! #![forbid(unsafe_code)] -#![cfg_attr(not(feature = "std"), no_std)] -#![macro_use] +#![no_std] + extern crate alloc; extern crate core; +#[cfg(feature = "std")] +extern crate std; + pub use encoder::JxlSimpleEncoder; pub use errors::JxlEncodeErrors; diff --git a/crates/zune-png/Cargo.toml b/crates/zune-png/Cargo.toml index 7f33cec6..919e20c4 100644 --- a/crates/zune-png/Cargo.toml +++ b/crates/zune-png/Cargo.toml @@ -21,10 +21,11 @@ portable-simd = [] default = ["sse", "std"] [dependencies] +libm = { version = "0.2.15", optional = true } zune-core = { path = "../zune-core", version = "^0.5.0-rc0" } zune-inflate = { path = "../zune-inflate", version = "0.2", default-features = false, features = ["zlib"] } [dev-dependencies] nanorand = { version = "0.7.0", default-features = false, features = ["wyrand"] } # testing purposes. png = "0.17.8-rc" -spng = "0.1.0" \ No newline at end of file +spng = "0.1.0" diff --git a/crates/zune-png/src/apng.rs b/crates/zune-png/src/apng.rs index 574c27c3..f01aeb87 100644 --- a/crates/zune-png/src/apng.rs +++ b/crates/zune-png/src/apng.rs @@ -222,11 +222,23 @@ impl SingleFrame { /// i += 1; /// } /// ``` -#[cfg(feature = "std")] +#[cfg(any(feature = "std", feature = "libm"))] pub fn post_process_image( info: &PngInfo, colorspace: ColorSpace, frame_info: &FrameInfo, current_frame: &[u8], prev_frame: Option<&[u8]>, output: &mut [u8], gamma: Option ) -> Result<(), PngDecodeErrors> { + fn powf(base: f32, exp: f32) -> f32 { + #[cfg(all(feature = "std", not(feature = "libm")))] + { + f32::powf(base, exp) + } + + #[cfg(feature = "libm")] + { + libm::powf(base, exp) + } + } + let nc = colorspace.num_components(); // // check invariants @@ -344,8 +356,8 @@ pub fn post_process_image( .enumerate() { let gam = (i as f32) / max_sample; - let linfg = f32::powf(gam, gamma_inv); - let inv_fg = f32::powf(gam, gamma_value); + let linfg = powf(gam, gamma_inv); + let inv_fg = powf(gam, gamma_value); *c = inv_fg; *item = linfg; } @@ -377,7 +389,7 @@ pub fn post_process_image( // NB: (cae): This function becomes quite expensive. // I'm not sure if memoization may help us here. // Anyone with tricks?? - let gamout = f32::powf(commpix, gamma_value); + let gamout = powf(commpix, gamma_value); // scale up and output to b let pix = (gamout * max_sample + 0.5) as u8; *b = pix; diff --git a/crates/zune-png/src/error.rs b/crates/zune-png/src/error.rs index 399c4f17..4566575f 100644 --- a/crates/zune-png/src/error.rs +++ b/crates/zune-png/src/error.rs @@ -39,8 +39,7 @@ impl Display for PngDecodeErrors { } } -#[cfg(feature = "std")] -impl std::error::Error for PngDecodeErrors {} +impl core::error::Error for PngDecodeErrors {} impl Debug for PngDecodeErrors { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { diff --git a/crates/zune-png/src/filters/sse4.rs b/crates/zune-png/src/filters/sse4.rs index e2bb0c98..2838d6db 100644 --- a/crates/zune-png/src/filters/sse4.rs +++ b/crates/zune-png/src/filters/sse4.rs @@ -191,7 +191,7 @@ unsafe fn de_filter_sub_generic_sse2(raw: &[u8], current: &mu pub fn de_filter_sub_sse2(raw: &[u8], current: &mut [u8]) { #[cfg(feature = "std")] { - if !is_x86_feature_detected!("sse2") { + if !std::is_x86_feature_detected!("sse2") { panic!("Internal error, calling platform specific function where not supported") } } @@ -268,7 +268,7 @@ unsafe fn de_filter_paeth_sse41_inner( pub fn de_filter_paeth_sse41(prev_row: &[u8], raw: &[u8], current: &mut [u8]) { #[cfg(feature = "std")] { - if !is_x86_feature_detected!("sse4.1") { + if !std::is_x86_feature_detected!("sse4.1") { panic!("Internal error, calling platform specific function where not supported") } } @@ -325,7 +325,7 @@ unsafe fn defilter_avg_sse2_inner( pub fn defilter_avg_sse(prev_row: &[u8], raw: &[u8], current: &mut [u8]) { #[cfg(feature = "std")] { - if !is_x86_feature_detected!("sse2") { + if !std::is_x86_feature_detected!("sse2") { panic!("Internal error, calling platform specific function where not supported") } } diff --git a/crates/zune-png/src/lib.rs b/crates/zune-png/src/lib.rs index 0b086744..db78fca9 100644 --- a/crates/zune-png/src/lib.rs +++ b/crates/zune-png/src/lib.rs @@ -160,12 +160,16 @@ //! //! //! -#![cfg_attr(not(feature = "std"), no_std)] +#![no_std] #![allow(clippy::op_ref, clippy::identity_op)] + extern crate alloc; extern crate core; #[cfg(feature = "std")] +extern crate std; + +#[cfg(any(feature = "std", feature = "libm"))] pub use apng::post_process_image; pub use apng::{BlendOp, DisposeOp}; pub use decoder::{ItxtChunk, PngDecoder, PngInfo, TextChunk, TimeInfo, ZtxtChunk}; diff --git a/crates/zune-png/src/utils.rs b/crates/zune-png/src/utils.rs index 1633e4dc..2419e796 100644 --- a/crates/zune-png/src/utils.rs +++ b/crates/zune-png/src/utils.rs @@ -36,12 +36,12 @@ fn convert_be_to_le_u16(out: &mut [u8], _use_sse4: bool) { #[cfg(feature = "std")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { - if _use_sse4 && is_x86_feature_detected!("avx2") { + if _use_sse4 && std::is_x86_feature_detected!("avx2") { unsafe { return avx::convert_be_to_ne_avx(out); }; } - if _use_sse4 && is_x86_feature_detected!("ssse3") { + if _use_sse4 && std::is_x86_feature_detected!("ssse3") { unsafe { return sse::convert_be_to_ne_sse4(out); } diff --git a/crates/zune-psd/src/lib.rs b/crates/zune-psd/src/lib.rs index da5e0124..e43ce188 100644 --- a/crates/zune-psd/src/lib.rs +++ b/crates/zune-psd/src/lib.rs @@ -38,6 +38,7 @@ //! //#![forbid(unsafe_code)] #![no_std] + extern crate alloc; pub extern crate zune_core; pub use decoder::PSDDecoder; diff --git a/crates/zune-qoi/Cargo.toml b/crates/zune-qoi/Cargo.toml index a95e2d89..1cc5046e 100644 --- a/crates/zune-qoi/Cargo.toml +++ b/crates/zune-qoi/Cargo.toml @@ -9,12 +9,12 @@ keywords = ["qoi", "qoi-decoder", "decoder", "qoi-encoder", "encoder"] categories = ["multimedia::images"] exclude = ["fuzz/*"] description = "Quite Ok Image (QOI) decoder and encoder part of the zune-image family" +rust-version = "1.81.0" [features] log = ["zune-core/log"] -std = ["zune-core/std"] -default = ["std", "log"] +default = ["log"] [dependencies] zune-core = { path = "../zune-core", version = "^0.5.0-rc0" } diff --git a/crates/zune-qoi/src/errors.rs b/crates/zune-qoi/src/errors.rs index 0b437e4b..9b0a12d7 100644 --- a/crates/zune-qoi/src/errors.rs +++ b/crates/zune-qoi/src/errors.rs @@ -147,11 +147,9 @@ impl Display for QoiErrors { } } -#[cfg(feature = "std")] -impl std::error::Error for QoiEncodeErrors {} +impl core::error::Error for QoiEncodeErrors {} -#[cfg(feature = "std")] -impl std::error::Error for QoiErrors {} +impl core::error::Error for QoiErrors {} impl From for QoiEncodeErrors { fn from(value: ZByteIoError) -> Self { diff --git a/crates/zune-qoi/src/lib.rs b/crates/zune-qoi/src/lib.rs index 6e687d54..707e8887 100644 --- a/crates/zune-qoi/src/lib.rs +++ b/crates/zune-qoi/src/lib.rs @@ -17,8 +17,8 @@ //! ## `no_std` //! You can use `no_std` with alloc feature to compile for `no_std` endpoints -#![cfg_attr(not(feature = "std"), no_std)] -#![macro_use] +#![no_std] + extern crate alloc; extern crate core; From aee2f089bc5a06fa95c39cff9e1c685cf90a506d Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Tue, 13 May 2025 17:01:43 +1000 Subject: [PATCH 2/5] Add `no_std` to `zune-image` --- .github/workflows/no_std.yml | 1 + crates/zune-image/Cargo.toml | 19 ++++++++----- crates/zune-image/src/channel.rs | 28 +++++++++---------- crates/zune-image/src/codecs.rs | 13 +++++++-- crates/zune-image/src/codecs/jpeg.rs | 4 +++ crates/zune-image/src/codecs/jpeg_xl.rs | 4 +-- crates/zune-image/src/codecs/png.rs | 18 ++++++++++-- .../colorspace/conversion_functions.rs | 2 ++ .../src/core_filters/colorspace/grayscale.rs | 4 +-- .../core_filters/colorspace/grayscale/avx2.rs | 4 +-- .../colorspace/grayscale/sse41.rs | 4 +-- .../src/core_filters/colorspace/rgb_to_hsl.rs | 14 +++++++++- .../src/core_filters/colorspace/rgb_to_hsv.rs | 14 +++++++++- .../src/core_filters/colorspace/tests.rs | 2 ++ crates/zune-image/src/deinterleave.rs | 6 ++-- .../src/deinterleave/deinterleave_impls.rs | 16 +++++------ crates/zune-image/src/deinterleave/sse2.rs | 4 +-- crates/zune-image/src/deinterleave/sse41.rs | 4 +-- crates/zune-image/src/errors.rs | 23 +++++++++------ crates/zune-image/src/frame.rs | 5 ++-- crates/zune-image/src/image.rs | 6 ++-- crates/zune-image/src/lib.rs | 7 +++++ crates/zune-image/src/metadata.rs | 2 ++ crates/zune-image/src/pipelines.rs | 26 +++++++++++++++-- crates/zune-image/src/serde.rs | 3 +- crates/zune-image/src/utils.rs | 10 +++++-- 26 files changed, 174 insertions(+), 69 deletions(-) diff --git a/.github/workflows/no_std.yml b/.github/workflows/no_std.yml index 7ced4074..36dd0d04 100644 --- a/.github/workflows/no_std.yml +++ b/.github/workflows/no_std.yml @@ -36,5 +36,6 @@ jobs: - run: cargo build -p zune-gif --target x86_64-unknown-uefi --no-default-features --features log - run: cargo build -p zune-hdr --target x86_64-unknown-uefi --no-default-features --features log,libm - run: cargo build -p zune-jpegxl --target x86_64-unknown-uefi --no-default-features --features log + - run: cargo build -p zune-image --target x86_64-unknown-uefi --no-default-features --features log,libm,serde-support,ppm,jpeg,png,psd,farbfeld,qoi,bmp,hdr diff --git a/crates/zune-image/Cargo.toml b/crates/zune-image/Cargo.toml index 26c1416b..be8d61ca 100644 --- a/crates/zune-image/Cargo.toml +++ b/crates/zune-image/Cargo.toml @@ -8,7 +8,10 @@ license = "MIT OR Apache-2.0 OR Zlib" keywords = ["image", "decoder", "encoder", "image-processing"] categories = ["multimedia::images"] description = "An image library, contiaining necessary capabilities to decode, manipulate and encode images" +rust-version = "1.81.0" + # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + [features] # Single based image decoders and encoders log = ["zune-core/log"] @@ -32,35 +35,37 @@ default = ["all"] # Whether to use threads or not for some operations threads = ["zune-jpegxl?/threads", "jxl-oxide?/rayon"] # Simd support -simd = ["zune-jpeg?/x86", "zune-png?/sse", "avx2", "sse41"] +simd = ["zune-jpeg?/x86", "zune-png?/sse", "avx2", "sse41", "jpeg-encoder?/simd"] benchmarks = [] avx2 = [] sse41 = [] +std = ["zune-core/std", "zune-png?/std", "jpeg-encoder?/std", "zune-hdr?/std"] +libm = ["zune-hdr?/libm", "zune-png?/libm"] docs = [] -all = ["image_formats", "serde-support", "metadata", "threads", "simd", "log"] +all = ["image_formats", "serde-support", "metadata", "threads", "simd", "log", "std", "libm"] [dependencies] #zune-imageprocs = { path = "../zune-imageprocs", optional = true } # Core primitives -zune-core = { path = "../zune-core", version = "^0.5.0-rc0", features = ["std"] } +zune-core = { path = "../zune-core", version = "^0.5.0-rc0" } # Images -zune-png = { path = "../zune-png", version = "^0.5.0-rc0", optional = true, features = ["std"] } +zune-png = { path = "../zune-png", version = "^0.5.0-rc0", optional = true, default-features = false } zune-jpeg = { path = "../zune-jpeg", version = "^0.5.0-rc0", optional = true } zune-ppm = { path = "../zune-ppm", version = "^0.5.0-rc0", optional = true } zune-psd = { path = "../zune-psd", version = "^0.5.0-rc0", optional = true } zune-farbfeld = { path = "../zune-farbfeld", version = "^0.5.0-rc0", optional = true } zune-qoi = { path = "../zune-qoi", version = "^0.5.0-rc0", optional = true } zune-jpegxl = { path = "../zune-jpegxl", version = "^0.5.0-rc0", optional = true } -zune-hdr = { path = "../zune-hdr", version = "^0.5.0-rc0", optional = true } +zune-hdr = { path = "../zune-hdr", version = "^0.5.0-rc0", optional = true, default-features = false } zune-bmp = { path = "../zune-bmp", version = "^0.5.0-rc0", optional = true } # Channel conversions in a safe way bytemuck = { version = "1.13", default-features = false } # Serializing info -serde = { version = "1.0.152", optional = true } +serde = { version = "1.0.152", optional = true, default-features = false } # External image APIs -jpeg-encoder = { version = "0.6.0", optional = true, features = ["simd", "std"] } +jpeg-encoder = { version = "0.6.0", optional = true, default-features = false } jxl-oxide = { version = "0.8.0", optional = true } # metadata kamadak-exif = { version = "0.5.5", optional = true } diff --git a/crates/zune-image/src/channel.rs b/crates/zune-image/src/channel.rs index 8ac3b840..bcd19d75 100644 --- a/crates/zune-image/src/channel.rs +++ b/crates/zune-image/src/channel.rs @@ -19,10 +19,10 @@ //! as separate bit depths. //! All are seen as u8 to it with the only difference being the latter is twice as big as the former. //! -use std::alloc::{alloc_zeroed, dealloc, realloc, Layout}; -use std::any::TypeId; -use std::fmt::{Debug, Formatter}; -use std::mem::size_of; +use alloc::alloc::{alloc_zeroed, dealloc, realloc, Layout}; +use core::any::TypeId; +use core::fmt::{Debug, Formatter}; +use core::mem::size_of; use bytemuck::{Pod, Zeroable}; use zune_core::bit_depth::BitType; @@ -54,7 +54,7 @@ pub enum ChannelErrors { } impl Debug for ChannelErrors { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { match self { ChannelErrors::UnalignedPointer(expected, found) => { writeln!(f, "Channel pointer {expected} is not aligned to {found}") @@ -148,11 +148,11 @@ impl PartialEq for Channel { } impl Debug for Channel { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { // safety. // all types can alias u8, // length points to the length spanning the ptr - let slice = unsafe { std::slice::from_raw_parts(self.ptr, self.length) }; + let slice = unsafe { core::slice::from_raw_parts(self.ptr, self.length) }; writeln!(f, "raw_bytes: {slice:?}") } } @@ -210,7 +210,7 @@ impl Channel { unsafe fn alloc(size: usize) -> (*mut u8, Layout) { let layout = Layout::from_size_align(size, MIN_ALIGNMENT).unwrap(); // Safety - // alloc zeroed == alloc + std::mem::zeroed() + // alloc zeroed == alloc + core::mem::zeroed() // and we are bound by the zeroed trait, hence we are sure that // for whatever type we are going to allocate for, // it can be represented with a bit-representation of zero. @@ -302,7 +302,7 @@ impl Channel { /// /// # Example /// ``` - /// use std::any::{Any, TypeId}; + /// use core::any::{Any, TypeId}; /// use zune_image::channel::Channel; /// let channel = Channel::new::(); /// @@ -446,7 +446,7 @@ impl Channel { /// Reinterpret a slice of `&[u8]` to another type /// /// # Safety - /// - Invariants for [`std::slice::from_raw_parts`] should be upheld + /// - Invariants for [`core::slice::from_raw_parts`] should be upheld /// - There should be no sloppy bytes at the end of the memory location /// /// # Returns @@ -457,7 +457,7 @@ impl Channel { // well aligned: You cannot have u8 having bad alignment as the least bit denomination // of alignment is a byte and u8==1 byte // - let new_slice = unsafe { std::slice::from_raw_parts_mut::(self.ptr, self.length) }; + let new_slice = unsafe { core::slice::from_raw_parts_mut::(self.ptr, self.length) }; let (a, b, c) = new_slice.align_to(); @@ -476,7 +476,7 @@ impl Channel { // validity: We own the data // well aligned: You cannot have u8 having bad alignment // - let new_slice = unsafe { std::slice::from_raw_parts_mut::(self.ptr, self.length) }; + let new_slice = unsafe { core::slice::from_raw_parts_mut::(self.ptr, self.length) }; let (a, b, c) = bytemuck::pod_align_to_mut(new_slice); @@ -592,7 +592,7 @@ impl Channel { /// This is unsafe just as a remainder that the memory is just /// a bag of bytes and may not be just `&[u8]`. pub unsafe fn alias(&self) -> &[u8] { - std::slice::from_raw_parts(self.ptr, self.length) + core::slice::from_raw_parts(self.ptr, self.length) } /// Return the raw memory layout of the channel as `mut &[u8]` @@ -601,7 +601,7 @@ impl Channel { /// This is unsafe just as a remainder that the memory is just /// a bag of bytes and may not be just `mut &[u8]`. pub unsafe fn alias_mut(&mut self) -> &mut [u8] { - std::slice::from_raw_parts_mut(self.ptr, self.length) + core::slice::from_raw_parts_mut(self.ptr, self.length) } } diff --git a/crates/zune-image/src/codecs.rs b/crates/zune-image/src/codecs.rs index cc41d842..1b2ada57 100644 --- a/crates/zune-image/src/codecs.rs +++ b/crates/zune-image/src/codecs.rs @@ -31,8 +31,7 @@ //! #![allow(unused_imports, unused_variables, non_camel_case_types, dead_code)] -use std::io::Cursor; -use std::path::Path; +use alloc::{boxed::Box, vec::Vec}; use zune_core::bytestream::{ZByteReaderTrait, ZByteWriterTrait, ZCursor, ZReader}; use zune_core::log::trace; @@ -44,6 +43,12 @@ use crate::errors::{ImageErrors, ImgEncodeErrors}; use crate::image::Image; use crate::traits::{DecoderTrait, EncoderTrait}; +#[cfg(feature = "std")] +use { + std::io::Cursor, + std::path::Path, +}; + pub mod bmp; mod exr; pub mod farbfeld; @@ -434,6 +439,7 @@ impl Image { /// // save to jpeg /// image.save("hello.jpg").unwrap(); /// ``` + #[cfg(feature = "std")] pub fn save>(&self, file: P) -> Result<(), ImageErrors> { return if let Some(ext) = file.as_ref().extension() { if let Some(format) = ImageFormat::encoder_for_extension(ext.to_string_lossy()) { @@ -484,6 +490,7 @@ impl Image { /// Ok(()) /// } /// ``` + #[cfg(feature = "std")] pub fn save_to>(&self, file: P, format: ImageFormat) -> Result<(), ImageErrors> { // open a file for which we will write directly to let mut file = std::io::BufWriter::new( @@ -589,6 +596,7 @@ impl Image { /// otherwise it's an error to try and decode /// /// See also [read](Self::read) for reading from memory + #[cfg(feature = "std")] pub fn open>(file: P) -> Result { Self::open_with_options(file, DecoderOptions::default()) } @@ -609,6 +617,7 @@ impl Image { /// let options = DecoderOptions::default().set_strict_mode(true).set_max_width(100); /// let image = Image::open_with_options("/a/file.jpeg",options).unwrap(); /// ``` + #[cfg(feature = "std")] pub fn open_with_options>( file: P, options: DecoderOptions ) -> Result { diff --git a/crates/zune-image/src/codecs/jpeg.rs b/crates/zune-image/src/codecs/jpeg.rs index 282ef519..eb64d120 100644 --- a/crates/zune-image/src/codecs/jpeg.rs +++ b/crates/zune-image/src/codecs/jpeg.rs @@ -14,6 +14,9 @@ //! //! The decoder and encoder both support metadata extraction and saving. //! + +use alloc::string::ToString; + use jpeg_encoder::{ColorType, EncodingError, JfifWrite}; use zune_core::bit_depth::BitDepth; use zune_core::bytestream::{ZByteIoError, ZByteReaderTrait, ZByteWriterTrait, ZWriter}; @@ -35,6 +38,7 @@ struct TempVt<'a, T: ZByteWriterTrait> { impl<'a, T: ZByteWriterTrait> JfifWrite for TempVt<'a, T> { fn write_all(&mut self, buf: &[u8]) -> Result<(), EncodingError> { self.inner.write_all(buf).map_err(|r| match r { + #[cfg(feature = "std")] ZByteIoError::StdIoError(e) => EncodingError::IoError(e), r => EncodingError::Write(format!("{:?}", r)) }) diff --git a/crates/zune-image/src/codecs/jpeg_xl.rs b/crates/zune-image/src/codecs/jpeg_xl.rs index 7d5d1f42..d27218ca 100644 --- a/crates/zune-image/src/codecs/jpeg_xl.rs +++ b/crates/zune-image/src/codecs/jpeg_xl.rs @@ -17,9 +17,9 @@ //! 16 bit images with no palette support //! use std::io::Read; -use std::mem::size_of; +use core::mem::size_of; use std::thread::sleep; -use std::time::Duration; +use core::time::Duration; pub use jxl_oxide; use jxl_oxide::{JxlImage, PixelFormat, RenderResult}; diff --git a/crates/zune-image/src/codecs/png.rs b/crates/zune-image/src/codecs/png.rs index 52914345..679785b5 100644 --- a/crates/zune-image/src/codecs/png.rs +++ b/crates/zune-image/src/codecs/png.rs @@ -10,7 +10,8 @@ #![allow(unused_variables)] //! Represents an png image decoder and encoder -use std::io::Cursor; + +use alloc::{borrow::ToOwned, string::ToString, vec::Vec}; use zune_core::bit_depth::BitDepth; use zune_core::bytestream::{ZByteReaderTrait, ZByteWriterTrait}; @@ -30,6 +31,9 @@ use crate::image::Image; use crate::metadata::ImageMetadata; use crate::traits::{DecodeInto, DecoderTrait, EncoderTrait}; +#[cfg(feature = "std")] +use std::io::Cursor; + impl DecoderTrait for PngDecoder where T: ZByteReaderTrait @@ -61,6 +65,7 @@ where } let pix = self.decode()?; match pix { + #[cfg(any(feature = "std", feature = "libm"))] DecodingResult::U8(pix) => { post_process_image( &info, @@ -76,7 +81,11 @@ where let im_frame = Frame::from_u8(&output, colorspace, usize::from(frame.delay_num),usize::from(frame.delay_denom)); output_frames.push(im_frame); } - _ => return Err(ImageDecodeErrors("The current image is an Animated PNG but has a depth of 16, such an image isn't supported".to_string())) + #[cfg(not(any(feature = "std", feature = "libm")))] + DecodingResult::U8(pix) => { + return Err(ImageDecodeErrors("The current image requires post-processing to decode, but that feature is only supported with `std` or `libm` enabled".to_string())) + } + _ => return Err(ImageDecodeErrors("The current image is an Animated PNG but has a depth of 16, such an image isn't supported".to_string())) } } let mut image = Image::new_frames(output_frames, depth, width, height, colorspace); @@ -182,7 +191,8 @@ impl EncoderTrait for PngEncoder { let mut encoder = zune_png::PngEncoder::new(frame, options); - #[allow(unused_mut)] + #[cfg(feature = "std")] + #[cfg_attr(not(feature = "metadata"), expect(unused_mut))] let mut buf: Cursor> = std::io::Cursor::new(vec![]); #[cfg(feature = "metadata")] @@ -262,6 +272,8 @@ where #[cfg(test)] mod tests { + use alloc::vec::Vec; + use zune_core::bytestream::ZCursor; use zune_core::colorspace::ColorSpace; use zune_png::PngDecoder; diff --git a/crates/zune-image/src/core_filters/colorspace/conversion_functions.rs b/crates/zune-image/src/core_filters/colorspace/conversion_functions.rs index 4e58ae0a..912c0c5a 100644 --- a/crates/zune-image/src/core_filters/colorspace/conversion_functions.rs +++ b/crates/zune-image/src/core_filters/colorspace/conversion_functions.rs @@ -1,3 +1,5 @@ +use alloc::borrow::ToOwned; + use zune_core::bit_depth::{BitDepth, BitType}; use zune_core::colorspace::ColorSpace; use zune_core::log::warn; diff --git a/crates/zune-image/src/core_filters/colorspace/grayscale.rs b/crates/zune-image/src/core_filters/colorspace/grayscale.rs index 4528407f..d21e9ebd 100644 --- a/crates/zune-image/src/core_filters/colorspace/grayscale.rs +++ b/crates/zune-image/src/core_filters/colorspace/grayscale.rs @@ -26,7 +26,7 @@ pub fn rgb_to_grayscale_u8(r: &[u8], g: &[u8], b: &[u8], out: &mut [u8], max_val { use crate::core_filters::colorspace::grayscale::avx2::convert_rgb_to_grayscale_u8_avx2; - if is_x86_feature_detected!("avx2") { + if std::is_x86_feature_detected!("avx2") { unsafe { return convert_rgb_to_grayscale_u8_avx2(r, g, b, out); } @@ -37,7 +37,7 @@ pub fn rgb_to_grayscale_u8(r: &[u8], g: &[u8], b: &[u8], out: &mut [u8], max_val { use crate::core_filters::colorspace::grayscale::sse41::convert_rgb_to_grayscale_u8_sse41; - if is_x86_feature_detected!("sse4.1") { + if std::is_x86_feature_detected!("sse4.1") { unsafe { return convert_rgb_to_grayscale_u8_sse41(r, g, b, out); } diff --git a/crates/zune-image/src/core_filters/colorspace/grayscale/avx2.rs b/crates/zune-image/src/core_filters/colorspace/grayscale/avx2.rs index b05e972f..14b8e8c9 100644 --- a/crates/zune-image/src/core_filters/colorspace/grayscale/avx2.rs +++ b/crates/zune-image/src/core_filters/colorspace/grayscale/avx2.rs @@ -10,9 +10,9 @@ #![cfg(feature = "avx2")] #[cfg(target_arch = "x86")] -use std::arch::x86::*; +use core::arch::x86::*; #[cfg(target_arch = "x86_64")] -use std::arch::x86_64::*; +use core::arch::x86_64::*; use crate::core_filters::colorspace::grayscale::scalar::convert_rgb_to_grayscale_scalar; diff --git a/crates/zune-image/src/core_filters/colorspace/grayscale/sse41.rs b/crates/zune-image/src/core_filters/colorspace/grayscale/sse41.rs index c7c76b7b..0ff15d2d 100644 --- a/crates/zune-image/src/core_filters/colorspace/grayscale/sse41.rs +++ b/crates/zune-image/src/core_filters/colorspace/grayscale/sse41.rs @@ -10,9 +10,9 @@ #![cfg(feature = "sse41")] #[cfg(target_arch = "x86")] -use std::arch::x86::*; +use core::arch::x86::*; #[cfg(target_arch = "x86_64")] -use std::arch::x86_64::*; +use core::arch::x86_64::*; use crate::core_filters::colorspace::grayscale::scalar::convert_rgb_to_grayscale_scalar; diff --git a/crates/zune-image/src/core_filters/colorspace/rgb_to_hsl.rs b/crates/zune-image/src/core_filters/colorspace/rgb_to_hsl.rs index 247d5f39..b4b2d7cb 100644 --- a/crates/zune-image/src/core_filters/colorspace/rgb_to_hsl.rs +++ b/crates/zune-image/src/core_filters/colorspace/rgb_to_hsl.rs @@ -9,12 +9,24 @@ const ONE_THIRD: f32 = 1.0 / 3.0; const ONE_SIXTH: f32 = 1.0 / 6.0; const TWO_THIRD: f32 = 2.0 / 3.0; +#[inline] +fn floor(x: f32) -> f32 { + let f = x % 1.; + if f.is_nan() || f == 0. || f == -0. { + x + } else if x < 0. { + x - f - 1. + } else { + x - f + } +} + #[inline] fn python_mod(n: f32, base: f32) -> f32 { // we based our code on python, we have to match it's mod // function // see https://stackoverflow.com/questions/3883004/how-does-the-modulo-operator-work-on-negative-numbers-in-python - n - (n / base).floor() * base + n - floor(n / base) * base } #[inline(always)] fn rgb_to_hsl_inner(r: f32, g: f32, b: f32) -> [f32; 3] { diff --git a/crates/zune-image/src/core_filters/colorspace/rgb_to_hsv.rs b/crates/zune-image/src/core_filters/colorspace/rgb_to_hsv.rs index cb1561ef..a5262823 100644 --- a/crates/zune-image/src/core_filters/colorspace/rgb_to_hsv.rs +++ b/crates/zune-image/src/core_filters/colorspace/rgb_to_hsv.rs @@ -1,5 +1,17 @@ +#[inline] +fn floor(x: f32) -> f32 { + let f = x % 1.; + if f.is_nan() || f == 0. || f == -0. { + x + } else if x < 0. { + x - f - 1. + } else { + x - f + } +} + fn python_mod(n: f32, base: f32) -> f32 { - n - (n / base).floor() * base + n - floor(n / base) * base } #[inline(always)] pub fn rgb_to_hsv_inner(r: f32, g: f32, b: f32) -> [f32; 3] { diff --git a/crates/zune-image/src/core_filters/colorspace/tests.rs b/crates/zune-image/src/core_filters/colorspace/tests.rs index dee50f82..13b65b3f 100644 --- a/crates/zune-image/src/core_filters/colorspace/tests.rs +++ b/crates/zune-image/src/core_filters/colorspace/tests.rs @@ -1,5 +1,7 @@ #![cfg(test)] +use alloc::boxed::Box; + use nanorand::Rng; use zune_core::bytestream::ZCursor; use zune_core::colorspace::ColorSpace; diff --git a/crates/zune-image/src/deinterleave.rs b/crates/zune-image/src/deinterleave.rs index b5083346..22d91a90 100644 --- a/crates/zune-image/src/deinterleave.rs +++ b/crates/zune-image/src/deinterleave.rs @@ -18,6 +18,8 @@ //!The latter representation makes it easier for processing and it allows multi-threaded //! post-processing for scenarios where processing is slow. +use alloc::vec::Vec; + use bytemuck::{Pod, Zeroable}; use zune_core::colorspace::ColorSpace; @@ -279,8 +281,8 @@ pub fn deinterleave_f32( #[cfg(test)] mod tests { - use std::array; - use std::num::NonZeroU32; + use core::array; + use core::num::NonZeroU32; use zune_core::colorspace::ColorSpace; diff --git a/crates/zune-image/src/deinterleave/deinterleave_impls.rs b/crates/zune-image/src/deinterleave/deinterleave_impls.rs index 781e275c..80d6aebd 100644 --- a/crates/zune-image/src/deinterleave/deinterleave_impls.rs +++ b/crates/zune-image/src/deinterleave/deinterleave_impls.rs @@ -15,7 +15,7 @@ pub fn de_interleave_three_channels_u8(source: &[u8], c1: &mut [u8], c2: &mut [u { use crate::deinterleave::avx2::de_interleave_three_channels_avx2; - if is_x86_feature_detected!("avx2") { + if std::is_x86_feature_detected!("avx2") { unsafe { return de_interleave_three_channels_avx2(source, c1, c2, c3); } @@ -25,7 +25,7 @@ pub fn de_interleave_three_channels_u8(source: &[u8], c1: &mut [u8], c2: &mut [u { use crate::deinterleave::sse41::de_interleave_three_channels_sse3_u8; - if is_x86_feature_detected!("sse3") { + if std::is_x86_feature_detected!("sse3") { unsafe { return de_interleave_three_channels_sse3_u8(source, c1, c2, c3); } @@ -35,7 +35,7 @@ pub fn de_interleave_three_channels_u8(source: &[u8], c1: &mut [u8], c2: &mut [u { use crate::deinterleave::sse2::de_interleave_three_channels_sse2; - if is_x86_feature_detected!("sse2") { + if std::is_x86_feature_detected!("sse2") { unsafe { return de_interleave_three_channels_sse2(source, c1, c2, c3); } @@ -54,7 +54,7 @@ pub fn de_interleave_three_channels_u16( { use crate::deinterleave::avx2::de_interleave_three_channels_avx2; - if is_x86_feature_detected!("avx2") { + if std::is_x86_feature_detected!("avx2") { unsafe { return de_interleave_three_channels_avx2(source, c1, c2, c3); } @@ -78,7 +78,7 @@ pub fn deinterleave_four_channels_u8( #[cfg(feature = "simd")] { use crate::deinterleave::avx2::de_interleave_four_channels_avx2; - if is_x86_feature_detected!("sse4.1") { + if std::is_x86_feature_detected!("sse4.1") { unsafe { return de_interleave_four_channels_avx2(source, c1, c2, c3, c4); } @@ -87,7 +87,7 @@ pub fn deinterleave_four_channels_u8( #[cfg(feature = "simd")] { use crate::deinterleave::sse41::de_interleave_four_channels_sse41; - if is_x86_feature_detected!("sse4.1") { + if std::is_x86_feature_detected!("sse4.1") { unsafe { return de_interleave_four_channels_sse41(source, c1, c2, c3, c4); } @@ -117,7 +117,7 @@ pub fn de_interleave_three_channels_f32( { use crate::deinterleave::avx2::de_interleave_three_channels_avx2; - if is_x86_feature_detected!("avx2") { + if std::is_x86_feature_detected!("avx2") { unsafe { return de_interleave_three_channels_avx2(source, c1, c2, c3); } @@ -136,7 +136,7 @@ pub fn de_interleave_four_channels_f32( { use crate::deinterleave::avx2::de_interleave_four_channels_avx2; - if is_x86_feature_detected!("avx2") { + if std::is_x86_feature_detected!("avx2") { unsafe { return de_interleave_four_channels_avx2(source, c1, c2, c3, c4); } diff --git a/crates/zune-image/src/deinterleave/sse2.rs b/crates/zune-image/src/deinterleave/sse2.rs index 996ee3c4..6f2c4585 100644 --- a/crates/zune-image/src/deinterleave/sse2.rs +++ b/crates/zune-image/src/deinterleave/sse2.rs @@ -10,9 +10,9 @@ #![cfg(feature = "simd")] #[cfg(target_arch = "x86")] -use std::arch::x86::*; +use core::arch::x86::*; #[cfg(target_arch = "x86_64")] -use std::arch::x86_64::*; +use core::arch::x86_64::*; use crate::deinterleave::scalar::de_interleave_three_channels_scalar; diff --git a/crates/zune-image/src/deinterleave/sse41.rs b/crates/zune-image/src/deinterleave/sse41.rs index e60eaf74..4e019b88 100644 --- a/crates/zune-image/src/deinterleave/sse41.rs +++ b/crates/zune-image/src/deinterleave/sse41.rs @@ -10,9 +10,9 @@ #![cfg(feature = "simd")] #[cfg(target_arch = "x86")] -use std::arch::x86::*; +use core::arch::x86::*; #[cfg(target_arch = "x86_64")] -use std::arch::x86_64::*; +use core::arch::x86_64::*; use crate::deinterleave::scalar::{ de_interleave_four_channels_scalar, de_interleave_three_channels_scalar diff --git a/crates/zune-image/src/errors.rs b/crates/zune-image/src/errors.rs index d5fd78ae..70b77fe6 100644 --- a/crates/zune-image/src/errors.rs +++ b/crates/zune-image/src/errors.rs @@ -7,9 +7,9 @@ */ //! Errors possible during image processing -use std::any::TypeId; -use std::fmt::{Debug, Display, Formatter}; -use std::io::Error; +use core::any::TypeId; +use core::fmt::{Debug, Display, Formatter}; +use alloc::string::String; use zune_core::bit_depth::BitType; use zune_core::colorspace::ColorSpace; @@ -17,10 +17,14 @@ use zune_core::colorspace::ColorSpace; use crate::channel::ChannelErrors; use crate::codecs::ImageFormat; +#[cfg(feature = "std")] +use std::io::Error; + /// All possible image errors that can occur. /// /// This is the grandfather of image errors and contains /// all decoding,processing and encoding errors possible +#[non_exhaustive] pub enum ImageErrors { ImageDecodeErrors(String), DimensionsMisMatch(usize, usize), @@ -36,6 +40,7 @@ pub enum ImageErrors { ChannelErrors(ChannelErrors), ImageDecoderNotIncluded(ImageFormat), ImageDecoderNotImplemented(ImageFormat), + #[cfg(feature = "std")] IoError(std::io::Error), ImageOperationNotImplemented(&'static str, BitType) } @@ -68,7 +73,7 @@ pub enum ImgEncodeErrors { } impl Debug for ImageErrors { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { match self { Self::ImageDecodeErrors(err) => { writeln!(f, "{err}") @@ -107,6 +112,7 @@ impl Debug for ImageErrors { "Expected type with ID of {expected:?} but found {found:?}" ) } + #[cfg(feature = "std")] ImageErrors::IoError(reason) => { writeln!(f, "IO error, {:?}", reason) } @@ -136,6 +142,7 @@ impl Debug for ImageErrors { } } +#[cfg(feature = "std")] impl From for ImageErrors { fn from(value: Error) -> Self { Self::IoError(value) @@ -155,7 +162,7 @@ impl From for ImageErrors { } impl Debug for ImageOperationsErrors { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { match self { Self::UnsupportedType(operation, depth) => { writeln!( @@ -201,7 +208,7 @@ impl From for ImageErrors { } impl Debug for ImgEncodeErrors { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { match self { Self::Generic(ref string) => writeln!(f, "{string}"), Self::GenericStatic(ref string) => writeln!(f, "{string}"), @@ -222,9 +229,9 @@ impl Debug for ImgEncodeErrors { } impl Display for ImageErrors { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { writeln!(f, "{:?}", self) } } -impl std::error::Error for ImageErrors {} +impl core::error::Error for ImageErrors {} diff --git a/crates/zune-image/src/frame.rs b/crates/zune-image/src/frame.rs index 5ca2b8ee..cff4d35c 100644 --- a/crates/zune-image/src/frame.rs +++ b/crates/zune-image/src/frame.rs @@ -11,7 +11,8 @@ #![allow(dead_code)] -use std::any::TypeId; +use alloc::vec::Vec; +use core::any::TypeId; use bytemuck::Pod; use zune_core::colorspace::ColorSpace; @@ -684,7 +685,7 @@ impl Frame { #[allow(unused_imports)] #[cfg(test)] mod tests { - use std::num::{NonZeroU32, NonZeroUsize}; + use core::num::{NonZeroU32, NonZeroUsize}; use zune_core::colorspace::ColorSpace; diff --git a/crates/zune-image/src/image.rs b/crates/zune-image/src/image.rs index 30944a25..4333fa73 100644 --- a/crates/zune-image/src/image.rs +++ b/crates/zune-image/src/image.rs @@ -10,8 +10,10 @@ //! Fully supported bit depths are 8 and 16 and float 32 which are expected to be in the range between 0.0 and 1.0, //! see [channel](crate::channel) documentation for how that happens //! -use std::fmt::Debug; -use std::mem::size_of; + +use alloc::vec::Vec; +use core::fmt::Debug; +use core::mem::size_of; use bytemuck::{Pod, Zeroable}; use zune_core::bit_depth::BitDepth; diff --git a/crates/zune-image/src/lib.rs b/crates/zune-image/src/lib.rs index 05b1d517..f7e87e22 100644 --- a/crates/zune-image/src/lib.rs +++ b/crates/zune-image/src/lib.rs @@ -95,8 +95,15 @@ )] #![cfg_attr(feature = "benchmarks", feature(test))] #![cfg_attr(feature = "docs", feature(doc_cfg))] +#![no_std] + +#[macro_use] +extern crate alloc; extern crate core; +#[cfg(feature = "std")] +extern crate std; + pub mod channel; pub mod codecs; pub mod core_filters; diff --git a/crates/zune-image/src/metadata.rs b/crates/zune-image/src/metadata.rs index babaa192..e14b9037 100644 --- a/crates/zune-image/src/metadata.rs +++ b/crates/zune-image/src/metadata.rs @@ -11,6 +11,8 @@ //! This module provides the ability to store image metadata and transfer it //! from one image to another +use alloc::vec::Vec; + use zune_core::bit_depth::BitDepth; use zune_core::colorspace::{ColorCharacteristics, ColorSpace}; diff --git a/crates/zune-image/src/pipelines.rs b/crates/zune-image/src/pipelines.rs index 435991fb..de526a2b 100644 --- a/crates/zune-image/src/pipelines.rs +++ b/crates/zune-image/src/pipelines.rs @@ -6,7 +6,8 @@ //! Pipelines, Batch image processing support //! #![allow(unused_variables)] -use std::time::Instant; +use alloc::boxed::Box; +use alloc::vec::Vec; use zune_core::log::Level::Trace; use zune_core::log::{log_enabled, trace}; @@ -16,6 +17,9 @@ use crate::errors::ImageErrors; use crate::image::Image; use crate::traits::{IntoImage, OperationsTrait}; +#[cfg(feature = "std")] +use std::time::Instant; + #[derive(Copy, Clone, Debug)] enum PipelineState { /// Initial state, the struct has been defined @@ -156,6 +160,7 @@ impl Pipeline { if let Some(state) = self.state { match state { PipelineState::Decode => { + #[cfg(feature = "std")] let start = Instant::now(); // do the actual decode if self.decode.is_none() { @@ -171,7 +176,8 @@ impl Pipeline { } if log_enabled!(Trace) { - println!(); + #[cfg(feature = "std")] + std::println!(); trace!("Current state: {:?}\n", state); } @@ -181,11 +187,16 @@ impl Pipeline { self.image.push(img); + #[cfg(feature = "std")] let stop = Instant::now(); self.state = state.next(); + #[cfg(feature = "std")] trace!("Finished decoding in {} ms", (stop - start).as_millis()); + + #[cfg(not(feature = "std"))] + trace!("Finished decoding"); } PipelineState::Operations => { if self.image.is_empty() { @@ -193,7 +204,8 @@ impl Pipeline { } if log_enabled!(Trace) && !self.operations.is_empty() { - println!(); + #[cfg(feature = "std")] + std::println!(); trace!("Current state: {:?}\n", state); } @@ -203,16 +215,24 @@ impl Pipeline { trace!("Running {}", operation_name); + #[cfg(feature = "std")] let start = Instant::now(); operation.execute(image)?; + #[cfg(feature = "std")] let stop = Instant::now(); + #[cfg(feature = "std")] trace!( "Finished running `{operation_name}` in {} ms", (stop - start).as_millis() ); + + #[cfg(not(feature = "std"))] + trace!( + "Finished running `{operation_name}`" + ); } self.state = state.next(); } diff --git a/crates/zune-image/src/serde.rs b/crates/zune-image/src/serde.rs index 75244fcf..aa084a72 100644 --- a/crates/zune-image/src/serde.rs +++ b/crates/zune-image/src/serde.rs @@ -8,7 +8,8 @@ #![cfg(feature = "serde-support")] -use std::collections::BTreeMap; +use alloc::string::{String, ToString}; +use alloc::collections::BTreeMap; use serde::ser::SerializeStruct; use serde::{Serialize, Serializer}; diff --git a/crates/zune-image/src/utils.rs b/crates/zune-image/src/utils.rs index 844264c0..204bead6 100644 --- a/crates/zune-image/src/utils.rs +++ b/crates/zune-image/src/utils.rs @@ -1,5 +1,7 @@ //! A set of miscellaneous functions that are good to have -use std::cmp::min; + +use core::cmp::min; +use alloc::vec::Vec; use zune_core::bytestream::ZByteReaderTrait; @@ -8,11 +10,12 @@ use crate::metadata::ImageMetadata; /// Swizzle three channels optionally using simd intrinsics where possible fn swizzle_three_channels(r: &[&[T]], y: &mut [T]) { + #[cfg(feature = "std")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { // Note that this `unsafe` block is safe because we're testing // that the `avx2` feature is indeed available on our CPU. - if is_x86_feature_detected!("avx2") { + if std::is_x86_feature_detected!("avx2") { return unsafe { swizzle_three_channels_avx(r, y) }; } } @@ -43,11 +46,12 @@ fn swizzle_three_channels_fallback(r: &[&[T]], y: &mut [T]) { } fn swizzle_four_channels(r: &[&[T]], y: &mut [T]) { + #[cfg(feature = "std")] #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { // Note that this `unsafe` block is safe because we're testing // that the `avx2` feature is indeed available on our CPU. - if is_x86_feature_detected!("avx2") { + if std::is_x86_feature_detected!("avx2") { return unsafe { swizzle_four_channels_avx(r, y) }; } } From c8ddb61a55da4aff2c2ad047ed973fe68d6e9204 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Tue, 13 May 2025 19:14:36 +1000 Subject: [PATCH 3/5] Add `no_std` to `zune-imageprocs` --- .github/workflows/no_std.yml | 27 +-- crates/zune-imageprocs/Cargo.toml | 7 +- .../zune-imageprocs/src/bilateral_filter.rs | 38 +++-- crates/zune-imageprocs/src/blend.rs | 20 +-- crates/zune-imageprocs/src/box_blur.rs | 32 ++-- crates/zune-imageprocs/src/brighten.rs | 12 +- crates/zune-imageprocs/src/color_matrix.rs | 16 +- crates/zune-imageprocs/src/composite.rs | 74 ++++----- crates/zune-imageprocs/src/contrast.rs | 6 +- crates/zune-imageprocs/src/convolve.rs | 56 ++++--- crates/zune-imageprocs/src/crop.rs | 20 +-- crates/zune-imageprocs/src/exposure.rs | 4 +- crates/zune-imageprocs/src/flip.rs | 16 +- crates/zune-imageprocs/src/gamma.rs | 9 +- crates/zune-imageprocs/src/gaussian_blur.rs | 53 +++--- crates/zune-imageprocs/src/histogram.rs | 4 +- crates/zune-imageprocs/src/hsv_adjust.rs | 23 +-- crates/zune-imageprocs/src/invert.rs | 12 +- crates/zune-imageprocs/src/lib.rs | 8 + crates/zune-imageprocs/src/mathops.rs | 154 ++++++++++++++++++ crates/zune-imageprocs/src/median.rs | 20 +-- crates/zune-imageprocs/src/mirror.rs | 12 +- crates/zune-imageprocs/src/pad.rs | 16 +- crates/zune-imageprocs/src/premul_alpha.rs | 26 +-- .../src/premul_alpha/std_simd.rs | 4 +- crates/zune-imageprocs/src/prewitt.rs | 13 +- crates/zune-imageprocs/src/resize.rs | 34 ++-- crates/zune-imageprocs/src/resize/bicubic.rs | 19 ++- crates/zune-imageprocs/src/resize/bilinear.rs | 10 +- crates/zune-imageprocs/src/rotate.rs | 12 +- crates/zune-imageprocs/src/scharr.rs | 32 ++-- crates/zune-imageprocs/src/sobel.rs | 21 +-- crates/zune-imageprocs/src/spatial.rs | 18 +- crates/zune-imageprocs/src/spatial_ops.rs | 31 ++-- .../zune-imageprocs/src/stretch_contrast.rs | 16 +- crates/zune-imageprocs/src/threshold.rs | 17 +- crates/zune-imageprocs/src/transpose.rs | 51 ++++-- .../zune-imageprocs/src/transpose/scalar.rs | 4 +- crates/zune-imageprocs/src/transpose/sse41.rs | 40 ++--- crates/zune-imageprocs/src/unsharpen.rs | 27 +-- crates/zune-imageprocs/src/utils.rs | 11 +- 41 files changed, 622 insertions(+), 403 deletions(-) diff --git a/.github/workflows/no_std.yml b/.github/workflows/no_std.yml index 36dd0d04..d93ded6f 100644 --- a/.github/workflows/no_std.yml +++ b/.github/workflows/no_std.yml @@ -24,18 +24,19 @@ jobs: # Target below does not have a standard library - run: rustup target add x86_64-unknown-uefi # Below targets run in no-std environments - - run: cargo build -p zune-core --target x86_64-unknown-uefi --no-default-features --features log,serde - - run: cargo build -p zune-inflate --target x86_64-unknown-uefi --no-default-features --features zlib,gzip - - run: cargo build -p zune-jpeg --target x86_64-unknown-uefi --no-default-features --features log,x86,neon - - run: cargo build -p zune-png --target x86_64-unknown-uefi --no-default-features --features log,libm - - run: cargo build -p zune-ppm --target x86_64-unknown-uefi --no-default-features --features log - - run: cargo build -p zune-qoi --target x86_64-unknown-uefi --no-default-features --features log - - run: cargo build -p zune-farbfeld --target x86_64-unknown-uefi --no-default-features --features log - - run: cargo build -p zune-psd --target x86_64-unknown-uefi --no-default-features --features log - - run: cargo build -p zune-bmp --target x86_64-unknown-uefi --no-default-features --features log,rgb_inverse - - run: cargo build -p zune-gif --target x86_64-unknown-uefi --no-default-features --features log - - run: cargo build -p zune-hdr --target x86_64-unknown-uefi --no-default-features --features log,libm - - run: cargo build -p zune-jpegxl --target x86_64-unknown-uefi --no-default-features --features log - - run: cargo build -p zune-image --target x86_64-unknown-uefi --no-default-features --features log,libm,serde-support,ppm,jpeg,png,psd,farbfeld,qoi,bmp,hdr + - run: cargo build -p zune-core --target x86_64-unknown-uefi --no-default-features --features log,serde + - run: cargo build -p zune-inflate --target x86_64-unknown-uefi --no-default-features --features zlib,gzip + - run: cargo build -p zune-jpeg --target x86_64-unknown-uefi --no-default-features --features log,x86,neon + - run: cargo build -p zune-png --target x86_64-unknown-uefi --no-default-features --features log,libm + - run: cargo build -p zune-ppm --target x86_64-unknown-uefi --no-default-features --features log + - run: cargo build -p zune-qoi --target x86_64-unknown-uefi --no-default-features --features log + - run: cargo build -p zune-farbfeld --target x86_64-unknown-uefi --no-default-features --features log + - run: cargo build -p zune-psd --target x86_64-unknown-uefi --no-default-features --features log + - run: cargo build -p zune-bmp --target x86_64-unknown-uefi --no-default-features --features log,rgb_inverse + - run: cargo build -p zune-gif --target x86_64-unknown-uefi --no-default-features --features log + - run: cargo build -p zune-hdr --target x86_64-unknown-uefi --no-default-features --features log,libm + - run: cargo build -p zune-jpegxl --target x86_64-unknown-uefi --no-default-features --features log + - run: cargo build -p zune-image --target x86_64-unknown-uefi --no-default-features --features log,libm,serde-support,ppm,jpeg,png,psd,farbfeld,qoi,bmp,hdr + - run: cargo build -p zune-imageprocs --target x86_64-unknown-uefi --no-default-features --features log,libm diff --git a/crates/zune-imageprocs/Cargo.toml b/crates/zune-imageprocs/Cargo.toml index 496f47a7..1f45c28e 100644 --- a/crates/zune-imageprocs/Cargo.toml +++ b/crates/zune-imageprocs/Cargo.toml @@ -14,6 +14,7 @@ description = "Common image processing routines for zune-image" [dependencies] zune-core = { path = "../zune-core", version = "^0.5.0-rc0" } kamadak-exif = { version = "0.5.5", optional = true } +libm = { version = "0.2", optional = true } [dependencies.zune-image] version = "^0.5.0-rc0" @@ -29,11 +30,13 @@ sse41 = [] ## Needs nightly, disabled by default benchmarks = [] ## Portable simd, disabled by default -portable-simd = [] +portable-simd = ["std"] log = ["zune-core/log"] exif = ["zune-image/metadata", "kamadak-exif"] threads = [] -default = ["avx2", "sse2", "sse3", "sse41", "threads"] +std = ["zune-image/std"] +libm = ["dep:libm", "zune-image/libm"] +default = ["avx2", "sse2", "sse3", "sse41", "threads", "std"] [dev-dependencies] diff --git a/crates/zune-imageprocs/src/bilateral_filter.rs b/crates/zune-imageprocs/src/bilateral_filter.rs index 6e7c2095..d0951af6 100644 --- a/crates/zune-imageprocs/src/bilateral_filter.rs +++ b/crates/zune-imageprocs/src/bilateral_filter.rs @@ -10,12 +10,16 @@ //! //! A description can be found [here](https://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html) //! + +use alloc::vec::Vec; + use zune_core::bit_depth::BitType; use zune_image::channel::Channel; use zune_image::errors::ImageErrors; use zune_image::image::Image; use zune_image::traits::OperationsTrait; +use crate::mathops::{exp_f64, round_f32, round_f64, sqrt_f64}; use crate::pad::{pad, PadMethod}; use crate::spatial::spatial; use crate::traits::NumOps; @@ -42,9 +46,9 @@ use crate::utils::execute_on; /// # Ok::<(),ImageErrors>(()) /// ``` pub struct BilateralFilter { - d: i32, + d: i32, sigma_color: f32, - sigma_space: f32 + sigma_space: f32, } impl BilateralFilter { @@ -65,7 +69,7 @@ impl BilateralFilter { BilateralFilter { d, sigma_color, - sigma_space + sigma_space, } } } @@ -87,7 +91,7 @@ impl OperationsTrait for BilateralFilter { self.d, self.sigma_color, self.sigma_space, - usize::from(depth.max_value()) + 1 + usize::from(depth.max_value()) + 1, ); let bilateral_fn = |channel: &mut Channel| { @@ -99,14 +103,14 @@ impl OperationsTrait for BilateralFilter { new_channel.reinterpret_as_mut()?, w, h, - &coeffs + &coeffs, ), BitType::U16 => bilateral_filter_int::( channel.reinterpret_as()?, new_channel.reinterpret_as_mut()?, w, h, - &coeffs + &coeffs, ), d => { @@ -128,13 +132,13 @@ impl OperationsTrait for BilateralFilter { struct BilateralCoeffs { color_weight: Vec, space_weight: Vec, - radius: usize, - makx: usize + radius: usize, + makx: usize, } #[allow(clippy::cast_possible_truncation, clippy::cast_precision_loss)] fn init_bilateral( - d: i32, sigma_color: f32, mut sigma_space: f32, color_range: usize + d: i32, sigma_color: f32, mut sigma_space: f32, color_range: usize, ) -> BilateralCoeffs { let gauss_color_coeff = f64::from(-0.5 / (sigma_color * sigma_color)); let gauss_space_coeff = f64::from(-0.5 / (sigma_space * sigma_space)); @@ -147,7 +151,7 @@ fn init_bilateral( sigma_space = 1.0; } - let radius: i32 = if d <= 0 { (sigma_space * 1.5).round() as _ } else { d / 2 }; + let radius: i32 = if d <= 0 { round_f32(sigma_space * 1.5) as _ } else { d / 2 }; let mut color_weight = vec![0.0_f64; cn * color_range]; let mut space_weight = vec![0.0_f64; (d * d).unsigned_abs() as usize]; @@ -155,17 +159,17 @@ fn init_bilateral( // initialize color-related bilateral filter coeffs for (i, item) in color_weight.iter_mut().enumerate().take(color_range) { let c = i as f64; - *item = (c * c * gauss_color_coeff).exp(); + *item = exp_f64(c * c * gauss_color_coeff); } let mut makx = 0; // initialize space-related bilateral coeffs for i in -radius..=radius { for j in -radius..=radius { - let r = f64::from((i * i) + (j * j)).sqrt(); + let r = sqrt_f64(f64::from((i * i) + (j * j))); if r > f64::from(radius) { continue; } - space_weight[makx] = (r * r * gauss_space_coeff).exp(); + space_weight[makx] = exp_f64(r * r * gauss_space_coeff); makx += 1; } } @@ -173,15 +177,15 @@ fn init_bilateral( color_weight, space_weight, radius: usize::try_from(radius).unwrap_or_default(), - makx + makx, }; } fn bilateral_filter_int( - src: &[T], dest: &mut [T], width: usize, height: usize, coeffs: &BilateralCoeffs + src: &[T], dest: &mut [T], width: usize, height: usize, coeffs: &BilateralCoeffs, ) where T: Copy + NumOps + Default, - i32: std::convert::From + i32: core::convert::From, { let radius = coeffs.radius; @@ -216,7 +220,7 @@ fn bilateral_filter_int( sum += f64::from(val) * w; wsum += w; } - return T::from_f64((sum / wsum).round()); + return T::from_f64(round_f64(sum / wsum)); }; spatial(&padded_input, dest, radius, width, height, bilateral_func); diff --git a/crates/zune-imageprocs/src/blend.rs b/crates/zune-imageprocs/src/blend.rs index d1c435a5..0886460d 100644 --- a/crates/zune-imageprocs/src/blend.rs +++ b/crates/zune-imageprocs/src/blend.rs @@ -51,7 +51,7 @@ use crate::traits::NumOps; /// pub struct Blend<'src> { image: &'src Image, - alpha: f32 + alpha: f32, } impl<'src> Blend<'src> { @@ -65,7 +65,7 @@ impl<'src> Blend<'src> { pub fn new(image: &'src Image, src_alpha: f32) -> Blend<'src> { Blend { image, - alpha: src_alpha + alpha: src_alpha, } } } @@ -82,18 +82,18 @@ impl<'src> OperationsTrait for Blend<'src> { } if image.dimensions() != self.image.dimensions() { return Err(ImageErrors::GenericStr( - "Image dimensions are incompatible for blend" + "Image dimensions are incompatible for blend", )); } if image.depth() != self.image.depth() { return Err(ImageErrors::GenericStr( - "Image depths do not match for blend" + "Image depths do not match for blend", )); } if image.colorspace() != self.image.colorspace() { return Err(ImageErrors::GenericStr( - "Image colorspace does not match for blend" + "Image colorspace does not match for blend", )); } @@ -109,17 +109,17 @@ impl<'src> OperationsTrait for Blend<'src> { BitType::U8 => blend_single_channel::( src_chan.reinterpret_as()?, d_chan.reinterpret_as_mut()?, - self.alpha + self.alpha, ), BitType::U16 => blend_single_channel::( src_chan.reinterpret_as()?, d_chan.reinterpret_as_mut()?, - self.alpha + self.alpha, ), BitType::F32 => blend_single_channel::( src_chan.reinterpret_as()?, d_chan.reinterpret_as_mut()?, - self.alpha + self.alpha, ), d => { @@ -137,8 +137,8 @@ impl<'src> OperationsTrait for Blend<'src> { pub fn blend_single_channel(src: &[T], dest: &mut [T], src_alpha: f32) where - f32: std::convert::From, - T: Copy + NumOps + f32: core::convert::From, + T: Copy + NumOps, { if src_alpha <= 0.0 { return; diff --git a/crates/zune-imageprocs/src/box_blur.rs b/crates/zune-imageprocs/src/box_blur.rs index 7dca2f34..13777e91 100644 --- a/crates/zune-imageprocs/src/box_blur.rs +++ b/crates/zune-imageprocs/src/box_blur.rs @@ -5,13 +5,15 @@ * * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license */ -/// Perfom a box blur filter on an image -/// -/// A box blur is a 2D filter that sums up all values -/// in it's window and divides it by the window size -/// -/// This approximates a `mean` of the window and sets it as the output -use std::f32; +//! Perfom a box blur filter on an image +//! +//! A box blur is a 2D filter that sums up all values +//! in it's window and divides it by the window size +//! +//! This approximates a `mean` of the window and sets it as the output + +use alloc::vec::Vec; +use core::f32; use zune_core::bit_depth::BitType; use zune_core::log::{trace, warn}; @@ -33,7 +35,7 @@ use crate::transpose; /// This operation is multithreaded capable #[derive(Default)] pub struct BoxBlur { - radius: usize + radius: usize, } impl BoxBlur { @@ -84,7 +86,7 @@ impl OperationsTrait for BoxBlur { box_blur_f32(data, &mut scratch_space, width, height, self.radius); Ok(()) } - d => return Err(ImageErrors::ImageOperationNotImplemented("box_blur", d)) + d => return Err(ImageErrors::ImageOperationNotImplemented("box_blur", d)), }); errors.push(result); } @@ -124,7 +126,7 @@ impl OperationsTrait for BoxBlur { box_blur_f32(data, &mut scratch_space, width, height, self.radius); } } - d => return Err(ImageErrors::ImageOperationNotImplemented("box_blur", d)) + d => return Err(ImageErrors::ImageOperationNotImplemented("box_blur", d)), } } @@ -137,7 +139,7 @@ impl OperationsTrait for BoxBlur { pub fn box_blur_u16( in_out_image: &mut [u16], scratch_space: &mut [u16], width: usize, height: usize, - mut radius: usize + mut radius: usize, ) { if width == 0 || radius <= 1 { warn!("Box blur with radius less than or equal to 1 does nothing"); @@ -154,7 +156,7 @@ pub fn box_blur_u16( pub fn box_blur_u8( in_out_image: &mut [u8], scratch_space: &mut [u8], width: usize, height: usize, - mut radius: usize + mut radius: usize, ) { if width == 0 || radius <= 1 { warn!("Box blur with radius less than or equal to 1 does nothing"); @@ -172,7 +174,7 @@ pub fn box_blur_u8( pub fn box_blur_f32( in_out_image: &mut [f32], scratch_space: &mut [f32], width: usize, height: usize, - mut radius: usize + mut radius: usize, ) { if width == 0 || radius <= 1 { warn!("Box blur with radius less than or equal to 1 does nothing"); @@ -191,7 +193,7 @@ pub fn box_blur_f32( pub(crate) fn box_blur_inner(in_image: &[T], out_image: &mut [T], width: usize, radius: usize) where T: Copy + NumOps, - u32: std::convert::From + u32: core::convert::From, { let diameter = (radius * 2) + 1; // 1D-Box blurs can be seen as the average of radius pixels iterating @@ -301,7 +303,7 @@ where clippy::cast_precision_loss )] pub(crate) fn box_blur_f32_inner( - in_image: &[f32], out_image: &mut [f32], width: usize, radius: usize + in_image: &[f32], out_image: &mut [f32], width: usize, radius: usize, ) { let diameter = (radius * 2) + 1; diff --git a/crates/zune-imageprocs/src/brighten.rs b/crates/zune-imageprocs/src/brighten.rs index dd0b394b..d55f6f35 100644 --- a/crates/zune-imageprocs/src/brighten.rs +++ b/crates/zune-imageprocs/src/brighten.rs @@ -54,7 +54,7 @@ use crate::utils::execute_on; /// ``` #[derive(Default)] pub struct Brighten { - value: f32 + value: f32, } impl Brighten { @@ -88,15 +88,15 @@ impl OperationsTrait for Brighten { BitType::U8 => brighten( channel.reinterpret_as_mut::()?, self.value, - u8::try_from(max_val.clamp(0, 255)).unwrap() + u8::try_from(max_val.clamp(0, 255)).unwrap(), ), BitType::U16 => brighten(channel.reinterpret_as_mut::()?, self.value, max_val), BitType::F32 => brighten_f32( channel.reinterpret_as_mut::()?, self.value, - f32::from(max_val) + f32::from(max_val), ), - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } Ok(()) }; @@ -107,7 +107,7 @@ impl OperationsTrait for Brighten { ColorSpace::RGBA, ColorSpace::RGB, ColorSpace::LumaA, - ColorSpace::Luma + ColorSpace::Luma, ] } @@ -128,7 +128,7 @@ impl OperationsTrait for Brighten { /// #[allow(clippy::cast_sign_loss, clippy::cast_possible_wrap)] pub fn brighten + Default>( - channel: &mut [T], value: f32, _max_value: T + channel: &mut [T], value: f32, _max_value: T, ) { let t_min = T::MIN_VAL.to_f32(); let t_max = T::MAX_VAL.to_f32(); diff --git a/crates/zune-imageprocs/src/color_matrix.rs b/crates/zune-imageprocs/src/color_matrix.rs index 6c60dec9..62267978 100644 --- a/crates/zune-imageprocs/src/color_matrix.rs +++ b/crates/zune-imageprocs/src/color_matrix.rs @@ -85,7 +85,7 @@ use crate::traits::NumOps; /// } /// ``` pub struct ColorMatrix { - matrix: [[f32; 5]; 4] + matrix: [[f32; 5]; 4], } impl ColorMatrix { @@ -141,23 +141,23 @@ impl OperationsTrait for ColorMatrix { g[0].reinterpret_as_mut()?, b[0].reinterpret_as_mut()?, a[0].reinterpret_as_mut()?, - &self.matrix + &self.matrix, ), BitType::U16 => color_matrix_component::( r[0].reinterpret_as_mut()?, g[0].reinterpret_as_mut()?, b[0].reinterpret_as_mut()?, a[0].reinterpret_as_mut()?, - &self.matrix + &self.matrix, ), BitType::F32 => color_matrix_component::( r[0].reinterpret_as_mut()?, g[0].reinterpret_as_mut()?, b[0].reinterpret_as_mut()?, a[0].reinterpret_as_mut()?, - &self.matrix + &self.matrix, ), - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } } // convert back to original color @@ -172,9 +172,9 @@ impl OperationsTrait for ColorMatrix { } fn color_matrix_component + Copy>( - c1: &mut [T], c2: &mut [T], c3: &mut [T], alpha: &mut [T], color_matrix: &[[f32; 5]; 4] + c1: &mut [T], c2: &mut [T], c3: &mut [T], alpha: &mut [T], color_matrix: &[[f32; 5]; 4], ) where - f32: From + f32: From, { let max_t = f32::from(T::MAX_VAL); // we need to multiply the first channel with the color matrix and then add the new offset only from the first row @@ -246,7 +246,7 @@ mod benchmarks { [0.2, 0.5, 0.3, 0.0, 0.0], [0.2, 0.5, 0.3, 0.0, 0.0], [0.2, 0.5, 0.3, 0.0, 0.0], - [0.0, 0.0, 0.0, 1.0, 0.0] + [0.0, 0.0, 0.0, 1.0, 0.0], ]); b.iter(|| { diff --git a/crates/zune-imageprocs/src/composite.rs b/crates/zune-imageprocs/src/composite.rs index e371d419..c9ce65ff 100644 --- a/crates/zune-imageprocs/src/composite.rs +++ b/crates/zune-imageprocs/src/composite.rs @@ -21,13 +21,13 @@ pub enum CompositeMethod { /// Does nothing compose Dst, /// Mask the background with shape - DstIn + DstIn, } #[derive(Copy, Clone, Debug, Eq, PartialEq)] enum CompositeMethodType { ChannelBased, - AlphaChannel + AlphaChannel, } impl CompositeMethod { fn composite_type(self) -> CompositeMethodType { @@ -35,16 +35,16 @@ impl CompositeMethod { CompositeMethod::Src | CompositeMethod::Dst | CompositeMethod::Over => { CompositeMethodType::ChannelBased } - CompositeMethod::DstIn => CompositeMethodType::AlphaChannel + CompositeMethod::DstIn => CompositeMethodType::AlphaChannel, } } } pub struct Composite<'a> { - geometry: Option<(usize, usize)>, - src_image: &'a Image, + geometry: Option<(usize, usize)>, + src_image: &'a Image, composite_method: CompositeMethod, - gravity: Option + gravity: Option, } impl<'a> Composite<'a> { @@ -60,13 +60,13 @@ impl<'a> Composite<'a> { /// See also [Self::new_gravity] if you don't want to manually calculate coordinates #[must_use] pub fn new( - image: &'a Image, composite_method: CompositeMethod, position: (usize, usize) + image: &'a Image, composite_method: CompositeMethod, position: (usize, usize), ) -> Composite<'a> { Composite { geometry: Some(position), src_image: image, composite_method, - gravity: None + gravity: None, } } /// Create a new filter that will composite `image` with the dest image placing it in the location @@ -81,13 +81,13 @@ impl<'a> Composite<'a> { /// See also [Self::new] if you want to use absolute coordinates #[must_use] pub fn new_gravity( - image: &'a Image, composite_method: CompositeMethod, gravity: Gravity + image: &'a Image, composite_method: CompositeMethod, gravity: Gravity, ) -> Composite<'a> { Composite { geometry: None, gravity: Some(gravity), src_image: image, - composite_method + composite_method, } } } @@ -111,7 +111,7 @@ impl<'a> OperationsTrait for Composite<'a> { // confirm compatibility if image.depth() != self.src_image.depth() { return Err(ImageErrors::GenericStr( - "Image depths do not match for composite" + "Image depths do not match for composite", )); } @@ -148,7 +148,7 @@ impl<'a> OperationsTrait for Composite<'a> { dims.1, src_width, dst_width, - self.composite_method + self.composite_method, ), BitType::U16 => composite_alpha::( src_chan.reinterpret_as()?, @@ -158,7 +158,7 @@ impl<'a> OperationsTrait for Composite<'a> { dims.1, src_width, dst_width, - self.composite_method + self.composite_method, ), BitType::F32 => composite_alpha::( src_chan.reinterpret_as()?, @@ -168,12 +168,12 @@ impl<'a> OperationsTrait for Composite<'a> { dims.1, src_width, dst_width, - self.composite_method + self.composite_method, ), d => { return Err(ImageErrors::ImageOperationNotImplemented( self.name(), - d + d, )); } } @@ -189,7 +189,7 @@ impl<'a> OperationsTrait for Composite<'a> { dims.1, src_width, dst_width, - self.composite_method + self.composite_method, ); } BitType::U16 => { @@ -200,7 +200,7 @@ impl<'a> OperationsTrait for Composite<'a> { dims.1, src_width, dst_width, - self.composite_method + self.composite_method, ); } BitType::F32 => { @@ -211,13 +211,13 @@ impl<'a> OperationsTrait for Composite<'a> { dims.1, src_width, dst_width, - self.composite_method + self.composite_method, ); } d => { return Err(ImageErrors::ImageOperationNotImplemented( self.name(), - d + d, )); } } @@ -237,7 +237,7 @@ impl<'a> OperationsTrait for Composite<'a> { dims.1, src_width, dst_width, - self.composite_method + self.composite_method, ), BitType::U16 => composite::( src_chan.reinterpret_as()?, @@ -246,7 +246,7 @@ impl<'a> OperationsTrait for Composite<'a> { dims.1, src_width, dst_width, - self.composite_method + self.composite_method, ), BitType::F32 => composite::( src_chan.reinterpret_as()?, @@ -255,12 +255,12 @@ impl<'a> OperationsTrait for Composite<'a> { dims.1, src_width, dst_width, - self.composite_method + self.composite_method, ), d => { return Err(ImageErrors::ImageOperationNotImplemented( self.name(), - d + d, )); } } @@ -282,14 +282,14 @@ impl<'a> OperationsTrait for Composite<'a> { #[allow(clippy::too_many_arguments)] fn composite_alpha( src: &[T], dest: &mut [T], src_alpha: &[T], start_x: usize, start_y: usize, width_src: usize, - width_dest: usize, method: CompositeMethod + width_dest: usize, method: CompositeMethod, ) where T: Copy + NumOps, - f32: From + f32: From, { if method == CompositeMethod::Over { composite_over_alpha( - src, dest, src_alpha, start_x, start_y, width_src, width_dest + src, dest, src_alpha, start_x, start_y, width_src, width_dest, ); } else { unreachable!() @@ -297,10 +297,10 @@ fn composite_alpha( } fn composite_alpha_channel( alpha_src: &[T], dst_alpha: &mut [T], start_x: usize, start_y: usize, width_src: usize, - width_dest: usize, method: CompositeMethod + width_dest: usize, method: CompositeMethod, ) where T: Copy + NumOps, - f32: From + f32: From, { if method == CompositeMethod::Over { let max_v = 1.0 / f32::from(T::MAX_VAL); @@ -320,7 +320,7 @@ fn composite_alpha_channel( let dst_alpha = 1.0 - src_normalized; *dst = T::from_f32( - (src_normalized * f32::from(*src_p)) + (dst_alpha * f32::from(*dst)) + (src_normalized * f32::from(*src_p)) + (dst_alpha * f32::from(*dst)), ); } } @@ -329,7 +329,7 @@ fn composite_alpha_channel( } fn composite>( src: &[T], dest: &mut [T], start_x: usize, start_y: usize, width_src: usize, width_dest: usize, - method: CompositeMethod + method: CompositeMethod, ) { match method { CompositeMethod::Over => composite_over(src, dest, start_x, start_y, width_src, width_dest), @@ -342,7 +342,7 @@ fn composite>( } fn composite_src>( - src: &[T], dest: &mut [T], start_x: usize, start_y: usize, width_src: usize, width_dest: usize + src: &[T], dest: &mut [T], start_x: usize, start_y: usize, width_src: usize, width_dest: usize, ) { // fill with max value, this whitens the output // or opaques the alpha channel @@ -350,7 +350,7 @@ fn composite_src>( composite_over(src, dest, start_x, start_y, width_src, width_dest); } fn composite_over( - src: &[T], dest: &mut [T], start_x: usize, start_y: usize, width_src: usize, width_dest: usize + src: &[T], dest: &mut [T], start_x: usize, start_y: usize, width_src: usize, width_dest: usize, ) { // for (dst_width, src_width) in dest @@ -369,10 +369,10 @@ fn composite_over( fn composite_over_alpha( src: &[T], dest: &mut [T], src_alpha: &[T], start_x: usize, start_y: usize, width_src: usize, - width_dest: usize + width_dest: usize, ) where T: Copy + NumOps, - f32: From + f32: From, { let max_v = 1.0 / f32::from(T::max_val()); @@ -394,7 +394,7 @@ fn composite_over_alpha( let src_normalized = (f32::from(*src_alpha) * max_v).clamp(0.0, 1.0); let dst_alpha = 1.0 - src_normalized; *dst = T::from_f32( - (src_normalized * f32::from(*src_p)) + (dst_alpha * f32::from(*dst)) + (src_normalized * f32::from(*src_p)) + (dst_alpha * f32::from(*dst)), ); } } @@ -419,7 +419,7 @@ mod tests { pixels[1] = 0u8; pixels[2] = 0u8; pixels[3] = 0u8; - } + }, ); let opaque_image = Image::from_fn( @@ -431,7 +431,7 @@ mod tests { pixels[1] = 0u8; pixels[2] = 0u8; pixels[3] = 0xffu8; - } + }, ); let composite = Composite::new(&opaque_image, CompositeMethod::Over, (0usize, 0usize)); diff --git a/crates/zune-imageprocs/src/contrast.rs b/crates/zune-imageprocs/src/contrast.rs index 050a4958..d9942f13 100644 --- a/crates/zune-imageprocs/src/contrast.rs +++ b/crates/zune-imageprocs/src/contrast.rs @@ -55,7 +55,7 @@ use zune_image::traits::OperationsTrait; /// ``` #[derive(Default)] pub struct Contrast { - contrast: f32 + contrast: f32, } impl Contrast { @@ -76,7 +76,7 @@ impl OperationsTrait for Contrast { for channel in image.channels_mut(true) { match depth.bit_type() { BitType::U8 => contrast_u8(channel.reinterpret_as_mut::()?, self.contrast), - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } } Ok(()) @@ -86,7 +86,7 @@ impl OperationsTrait for Contrast { ColorSpace::RGBA, ColorSpace::RGB, ColorSpace::LumaA, - ColorSpace::Luma + ColorSpace::Luma, ] } fn supported_types(&self) -> &'static [BitType] { diff --git a/crates/zune-imageprocs/src/convolve.rs b/crates/zune-imageprocs/src/convolve.rs index 9b67b222..4ed6ae21 100644 --- a/crates/zune-imageprocs/src/convolve.rs +++ b/crates/zune-imageprocs/src/convolve.rs @@ -14,6 +14,8 @@ //! The intermediate calculations are carried in `f32` //! +use alloc::vec::Vec; + use zune_core::bit_depth::BitType; use zune_image::channel::Channel; use zune_image::errors::ImageErrors; @@ -59,7 +61,7 @@ use crate::utils::{execute_on, z_prefetch}; #[derive(Default)] pub struct Convolve { weights: Vec, - scale: f32 + scale: f32, } impl Convolve { @@ -92,7 +94,7 @@ impl OperationsTrait for Convolve { width, height, &self.weights, - self.scale + self.scale, )?; } BitType::U16 => { @@ -102,7 +104,7 @@ impl OperationsTrait for Convolve { width, height, &self.weights, - self.scale + self.scale, )?; } BitType::F32 => { @@ -112,10 +114,10 @@ impl OperationsTrait for Convolve { width, height, &self.weights, - self.scale + self.scale, )?; } - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } *channel = out_channel; @@ -131,7 +133,7 @@ impl OperationsTrait for Convolve { fn convolve_3x3_inner(in_array: &[T; 9], weights: &[f32; 9], scale: f32) -> T where T: NumOps + Copy + Default, - f32: From + f32: From, { T::from_f32( in_array @@ -139,7 +141,7 @@ where .zip(weights) .map(|(x, weight)| f32::from(*x) * weight) .sum::() - * scale + * scale, ) .zclamp(T::min_val(), T::max_val()) } @@ -147,7 +149,7 @@ where fn convolve_5x5_inner(in_array: &[T; 25], weights: &[f32; 25], scale: f32) -> T where T: NumOps + Copy + Default, - f32: From + f32: From, { T::from_f32( in_array @@ -155,7 +157,7 @@ where .zip(weights) .map(|(x, weight)| f32::from(*x) * weight) .sum::() - * scale + * scale, ) .zclamp(T::MIN_VAL, T::MAX_VAL) } @@ -163,7 +165,7 @@ where fn convolve_7x7_inner(in_array: &[T; 49], weights: &[f32; 49], scale: f32) -> T where T: NumOps + Copy + Default, - f32: From + f32: From, { T::from_f32( in_array @@ -171,7 +173,7 @@ where .zip(weights) .map(|(x, weight)| f32::from(*x) * weight) .sum::() - * scale + * scale, ) .zclamp(T::min_val(), T::max_val()) } @@ -179,10 +181,10 @@ where /// Convolve a matrix pub fn convolve_3x3( in_channel: &[T], out_channel: &mut [T], width: usize, height: usize, weights: &[f32; 9], - scale: f32 + scale: f32, ) where T: NumOps + Copy + Default, - f32: From + f32: From, { // pad input //pad here @@ -195,16 +197,16 @@ pub fn convolve_3x3( height, convolve_3x3_inner, weights, - scale + scale, ); } pub fn convolve_5x5( in_channel: &[T], out_channel: &mut [T], width: usize, height: usize, weights: &[f32; 25], - scale: f32 + scale: f32, ) where T: NumOps + Copy + Default, - f32: From + f32: From, { // pad input //pad here @@ -217,16 +219,16 @@ pub fn convolve_5x5( height, convolve_5x5_inner, weights, - scale + scale, ); } pub fn convolve_7x7( in_channel: &[T], out_channel: &mut [T], width: usize, height: usize, weights: &[f32; 49], - scale: f32 + scale: f32, ) where T: NumOps + Copy + Default, - f32: From + f32: From, { // pad input //pad here @@ -239,18 +241,18 @@ pub fn convolve_7x7( height, convolve_7x7_inner, weights, - scale + scale, ); } /// Selects a convolve matrix pub fn convolve( in_channel: &[T], out_channel: &mut [T], width: usize, height: usize, weights: &[f32], - scale: f32 + scale: f32, ) -> Result<(), &'static str> where T: NumOps + Copy + Default, - f32: std::convert::From + f32: core::convert::From, { if weights.len() == 9 { convolve_3x3::( @@ -259,7 +261,7 @@ where width, height, weights.try_into().unwrap(), - scale + scale, ); } else if weights.len() == 25 { convolve_5x5::( @@ -268,7 +270,7 @@ where width, height, weights.try_into().unwrap(), - scale + scale, ); } else if weights.len() == 49 { convolve_7x7::( @@ -277,7 +279,7 @@ where width, height, weights.try_into().unwrap(), - scale + scale, ); } else { return Err("Not implemented, only works for 3x3, 5x5 and 7x7 arrays"); @@ -290,10 +292,10 @@ where #[allow(non_snake_case)] fn spatial_NxN( in_channel: &[T], out_channel: &mut [T], width: usize, height: usize, function: F, - values: &[f32; OUT_SIZE], scale: f32 + values: &[f32; OUT_SIZE], scale: f32, ) where T: Default + Copy, - F: Fn(&[T; OUT_SIZE], &[f32; OUT_SIZE], f32) -> T + F: Fn(&[T; OUT_SIZE], &[f32; OUT_SIZE], f32) -> T, { let old_width = width; let height = (RADIUS * 2) + height; diff --git a/crates/zune-imageprocs/src/crop.rs b/crates/zune-imageprocs/src/crop.rs index 5687c031..fd1f9afc 100644 --- a/crates/zune-imageprocs/src/crop.rs +++ b/crates/zune-imageprocs/src/crop.rs @@ -92,10 +92,10 @@ use crate::utils::execute_on; /// } /// ``` pub struct Crop { - x: usize, - y: usize, - width: usize, - height: usize + x: usize, + y: usize, + width: usize, + height: usize, } impl Crop { @@ -114,7 +114,7 @@ impl Crop { x, y, width, - height + height, } } } @@ -143,7 +143,7 @@ impl OperationsTrait for Crop { self.width, self.height, self.x, - self.y + self.y, ); } BitType::U16 => { @@ -154,7 +154,7 @@ impl OperationsTrait for Crop { self.width, self.height, self.x, - self.y + self.y, ); } BitType::F32 => { @@ -165,10 +165,10 @@ impl OperationsTrait for Crop { self.width, self.height, self.x, - self.y + self.y, ); } - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } *channel = new_vec; @@ -212,7 +212,7 @@ impl OperationsTrait for Crop { /// read->panic pub fn crop( in_image: &[T], in_width: usize, out_image: &mut [T], out_width: usize, out_height: usize, - x: usize, y: usize + x: usize, y: usize, ) { if in_width == 0 || out_width == 0 { // these generate panic paths for chunks_exact so just eliminate them diff --git a/crates/zune-imageprocs/src/exposure.rs b/crates/zune-imageprocs/src/exposure.rs index db8cf7ce..3d6afc31 100644 --- a/crates/zune-imageprocs/src/exposure.rs +++ b/crates/zune-imageprocs/src/exposure.rs @@ -53,7 +53,7 @@ use crate::utils::execute_on; /// pub struct Exposure { exposure: f32, - black: f32 + black: f32, } impl Exposure { @@ -109,7 +109,7 @@ impl OperationsTrait for Exposure { .iter_mut() .for_each(|x| *x = (*x - black) * self.exposure); } - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } Ok(()) }; diff --git a/crates/zune-imageprocs/src/flip.rs b/crates/zune-imageprocs/src/flip.rs index c6abebb2..f45137ad 100644 --- a/crates/zune-imageprocs/src/flip.rs +++ b/crates/zune-imageprocs/src/flip.rs @@ -51,12 +51,12 @@ pub enum FlipDirection { /// │f g h i j│ │e d c b a │ /// └─────────┘ └──────────┘ /// ``` - MirrorXAxis + MirrorXAxis, } /// Flip an image to a certain direction pub struct Flip { - flip_direction: FlipDirection + flip_direction: FlipDirection, } impl Flip { @@ -88,7 +88,7 @@ impl OperationsTrait for Flip { BitType::F32 => { flop(inp.reinterpret_as_mut::()?, width); } - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), }, FlipDirection::Vertical => match depth.bit_type() { BitType::U8 => { @@ -100,7 +100,7 @@ impl OperationsTrait for Flip { BitType::F32 => { vertical_flip(inp.reinterpret_as_mut::()?, width); } - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), }, FlipDirection::MirrorXAxis => match depth.bit_type() { BitType::U8 => { @@ -112,8 +112,8 @@ impl OperationsTrait for Flip { BitType::F32 => { flip(inp.reinterpret_as_mut::()?); } - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) - } + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), + }, } Ok(()) @@ -155,7 +155,7 @@ pub fn flip(in_out_image: &mut [T]) { let (in_img_top, in_img_bottom) = in_out_image.split_at_mut(length); for (in_dim, out_dim) in in_img_top.iter_mut().zip(in_img_bottom.iter_mut().rev()) { - std::mem::swap(in_dim, out_dim); + core::mem::swap(in_dim, out_dim); } } @@ -213,7 +213,7 @@ pub fn flop(in_out_image: &mut [T], width: usize) { // iterate and swap for (ltr, rtl) in left_to_right.iter_mut().zip(right_to_left.iter_mut().rev()) { - std::mem::swap(ltr, rtl); + core::mem::swap(ltr, rtl); } } } diff --git a/crates/zune-imageprocs/src/gamma.rs b/crates/zune-imageprocs/src/gamma.rs index 346f1c10..ac060bc5 100644 --- a/crates/zune-imageprocs/src/gamma.rs +++ b/crates/zune-imageprocs/src/gamma.rs @@ -29,6 +29,7 @@ use zune_image::errors::ImageErrors; use zune_image::image::Image; use zune_image::traits::OperationsTrait; +use crate::mathops::powf_f32; use crate::traits::NumOps; use crate::utils::execute_on; @@ -38,7 +39,7 @@ use crate::utils::execute_on; /// This operation is internally multithreaded, where supported #[derive(Default)] pub struct Gamma { - value: f32 + value: f32, } impl Gamma { @@ -74,7 +75,7 @@ impl OperationsTrait for Gamma { .reinterpret_as_mut::()? .iter_mut() .for_each(|x| { - *x = value_inv * x.powf(self.value); + *x = value_inv * powf_f32(*x, self.value); }); } @@ -100,7 +101,7 @@ impl OperationsTrait for Gamma { )] pub fn gamma(pixels: &mut [T], value: f32, max_value: u16) where - T: Copy + NumOps + Default + T: Copy + NumOps + Default, { // build a lookup table which we use for gamma correction in the next stage // it is faster to do it this way as calling pow in the inner loop is slow @@ -118,7 +119,7 @@ where for x in 0..=max_usize { let pixel_f32 = (x as f32) * value_inv; - let mut new_pix_val = max_value * pixel_f32.powf(value); + let mut new_pix_val = max_value * powf_f32(pixel_f32, value); if new_pix_val > max_value { new_pix_val = max_value; diff --git a/crates/zune-imageprocs/src/gaussian_blur.rs b/crates/zune-imageprocs/src/gaussian_blur.rs index 5263807b..5b0f1450 100644 --- a/crates/zune-imageprocs/src/gaussian_blur.rs +++ b/crates/zune-imageprocs/src/gaussian_blur.rs @@ -17,17 +17,20 @@ //! //! For the math behind it see +use alloc::vec::Vec; + use zune_core::bit_depth::BitType; use zune_core::log::trace; use zune_image::errors::ImageErrors; use zune_image::image::Image; use zune_image::traits::OperationsTrait; +use crate::mathops::{floor_f32, round_f32, sqrt_f32}; use crate::transpose; #[derive(Default)] pub struct GaussianBlur { - sigma: f32 + sigma: f32, } impl GaussianBlur { @@ -65,7 +68,7 @@ impl OperationsTrait for GaussianBlur { &mut temp, width, height, - self.sigma + self.sigma, ); } } @@ -78,7 +81,7 @@ impl OperationsTrait for GaussianBlur { &mut temp, width, height, - self.sigma + self.sigma, ); } } @@ -90,11 +93,11 @@ impl OperationsTrait for GaussianBlur { &mut temp, width, height, - self.sigma + self.sigma, ); } } - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } } @@ -114,7 +117,7 @@ impl OperationsTrait for GaussianBlur { &mut temp, width, height, - self.sigma + self.sigma, ); Ok(()) } @@ -126,7 +129,7 @@ impl OperationsTrait for GaussianBlur { &mut temp, width, height, - self.sigma + self.sigma, ); Ok(()) } @@ -138,11 +141,11 @@ impl OperationsTrait for GaussianBlur { &mut temp, width, height, - self.sigma + self.sigma, ); Ok(()) } - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), }); errors.push(result); } @@ -172,8 +175,8 @@ fn create_box_gauss(sigma: f32) -> [usize; 3] { let n_float = 3.0; // Ideal averaging filter width - let w_ideal = (12.0 * sigma * sigma / n_float).sqrt() + 1.0; - let mut wl: i32 = w_ideal.floor() as i32; + let w_ideal = sqrt_f32(12.0 * sigma * sigma / n_float) + 1.0; + let mut wl: i32 = floor_f32(w_ideal) as i32; if wl % 2 == 0 { wl -= 1; @@ -189,7 +192,7 @@ fn create_box_gauss(sigma: f32) -> [usize; 3] { - 3.0 * n_float) / (-4.0 * wl_float - 4.0); - let m: usize = m_ideal.round() as usize; + let m: usize = round_f32(m_ideal) as usize; for i in 0..3 { if i < m { @@ -213,7 +216,7 @@ fn create_box_gauss(sigma: f32) -> [usize; 3] { /// - width,height: Dimensions of the image /// - sigma: A measure of how much to blur the image by. pub fn gaussian_blur_u16( - in_out_image: &mut [u16], scratch_space: &mut [u16], width: usize, height: usize, sigma: f32 + in_out_image: &mut [u16], scratch_space: &mut [u16], width: usize, height: usize, sigma: f32, ) { // use the box blur implementation let blur_radii = create_box_gauss(sigma); @@ -225,7 +228,7 @@ pub fn gaussian_blur_u16( match pos % 2 { 0 => crate::box_blur::box_blur_inner(in_out_image, scratch_space, width, *blur_radius), 1 => crate::box_blur::box_blur_inner(scratch_space, in_out_image, width, *blur_radius), - _ => unreachable!() + _ => unreachable!(), }; } // transpose @@ -238,7 +241,7 @@ pub fn gaussian_blur_u16( match pos % 2 { 0 => crate::box_blur::box_blur_inner(in_out_image, scratch_space, height, *blur_radius), 1 => crate::box_blur::box_blur_inner(scratch_space, in_out_image, height, *blur_radius), - _ => unreachable!() + _ => unreachable!(), }; } // transpose back @@ -246,7 +249,7 @@ pub fn gaussian_blur_u16( } pub fn gaussian_blur_f32( - in_out_image: &mut [f32], scratch_space: &mut [f32], width: usize, height: usize, sigma: f32 + in_out_image: &mut [f32], scratch_space: &mut [f32], width: usize, height: usize, sigma: f32, ) { // use the box blur implementation let blur_radii = create_box_gauss(sigma); @@ -260,15 +263,15 @@ pub fn gaussian_blur_f32( in_out_image, scratch_space, width, - *blur_radius + *blur_radius, ), 1 => crate::box_blur::box_blur_f32_inner( scratch_space, in_out_image, width, - *blur_radius + *blur_radius, ), - _ => unreachable!() + _ => unreachable!(), }; } // transpose @@ -283,15 +286,15 @@ pub fn gaussian_blur_f32( in_out_image, scratch_space, height, - *blur_radius + *blur_radius, ), 1 => crate::box_blur::box_blur_f32_inner( scratch_space, in_out_image, height, - *blur_radius + *blur_radius, ), - _ => unreachable!() + _ => unreachable!(), }; } // transpose back @@ -308,7 +311,7 @@ pub fn gaussian_blur_f32( /// - width,height: Dimensions of the image /// - sigma: A measure of how much to blur the image by. pub fn gaussian_blur_u8( - in_out_image: &mut [u8], scratch_space: &mut [u8], width: usize, height: usize, sigma: f32 + in_out_image: &mut [u8], scratch_space: &mut [u8], width: usize, height: usize, sigma: f32, ) { // use the box blur implementation let blur_radii = create_box_gauss(sigma); @@ -345,7 +348,7 @@ pub fn gaussian_blur_u8( match pos % 2 { 0 => crate::box_blur::box_blur_inner(in_out_image, scratch_space, width, *blur_radius), 1 => crate::box_blur::box_blur_inner(scratch_space, in_out_image, width, *blur_radius), - _ => unreachable!() + _ => unreachable!(), }; } // transpose @@ -358,7 +361,7 @@ pub fn gaussian_blur_u8( match pos % 2 { 0 => crate::box_blur::box_blur_inner(in_out_image, scratch_space, height, *blur_radius), 1 => crate::box_blur::box_blur_inner(scratch_space, in_out_image, height, *blur_radius), - _ => unreachable!() + _ => unreachable!(), }; } // transpose back diff --git a/crates/zune-imageprocs/src/histogram.rs b/crates/zune-imageprocs/src/histogram.rs index 1e07b515..36162fcb 100644 --- a/crates/zune-imageprocs/src/histogram.rs +++ b/crates/zune-imageprocs/src/histogram.rs @@ -9,8 +9,8 @@ // //! way too many colors to properly histogram // //! // //! -// use std::cell::{BorrowError, Ref, RefCell}; -// use std::usize; +// use core::cell::{BorrowError, Ref, RefCell}; +// use core::usize; // // use zune_core::bit_depth::BitType; // use zune_image::errors::ImageErrors; diff --git a/crates/zune-imageprocs/src/hsv_adjust.rs b/crates/zune-imageprocs/src/hsv_adjust.rs index f89c5a17..e392221a 100644 --- a/crates/zune-imageprocs/src/hsv_adjust.rs +++ b/crates/zune-imageprocs/src/hsv_adjust.rs @@ -15,7 +15,7 @@ //! but the main gist is that instead of converting back and forth, use a simple matrix that allows such calculations //! this routine adapts that for use //! -use std::f32::consts::PI; +use core::f32::consts::PI; use zune_core::bit_depth::BitType; use zune_core::colorspace::ColorSpace; @@ -23,6 +23,7 @@ use zune_image::errors::ImageErrors; use zune_image::image::Image; use zune_image::traits::OperationsTrait; +use crate::mathops::{cos_f32, sin_f32}; use crate::traits::NumOps; /// Create a new HSV adjust filter that manipulates pixels in RGB space @@ -50,9 +51,9 @@ use crate::traits::NumOps; ///# Ok::<(),ImageErrors>(()) /// ``` pub struct HsvAdjust { - hue: f32, + hue: f32, saturation: f32, - lightness: f32 + lightness: f32, } impl HsvAdjust { @@ -73,7 +74,7 @@ impl HsvAdjust { HsvAdjust { hue, saturation, - lightness + lightness, } } } @@ -106,7 +107,7 @@ impl OperationsTrait for HsvAdjust { b[0].reinterpret_as_mut()?, self.hue, self.saturation, - self.lightness + self.lightness, ); } BitType::U16 => { @@ -116,7 +117,7 @@ impl OperationsTrait for HsvAdjust { b[0].reinterpret_as_mut()?, self.hue, self.saturation, - self.lightness + self.lightness, ); } BitType::F32 => { @@ -126,10 +127,10 @@ impl OperationsTrait for HsvAdjust { b[0].reinterpret_as_mut()?, self.hue, self.saturation, - self.lightness + self.lightness, ); } - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } } // convert to original color @@ -147,13 +148,13 @@ impl OperationsTrait for HsvAdjust { fn modulate_hsl(r: &mut [T], g: &mut [T], b: &mut [T], h: f32, s: f32, v: f32) where f32: From, - T: NumOps + Copy + T: NumOps + Copy, { // from https://beesbuzz.biz/code/16-hsv-color-transforms // whoever you are, thank you for keeping up the site for 20 years :) - let vsu = v * s * (h * PI / 180.0).cos(); - let vsw = v * s * (h * PI / 180.0).sin(); + let vsu = v * s * cos_f32(h * PI / 180.0); + let vsw = v * s * sin_f32(h * PI / 180.0); let min = T::MIN_VAL.to_f32(); let max = T::MAX_VAL.to_f32(); diff --git a/crates/zune-imageprocs/src/invert.rs b/crates/zune-imageprocs/src/invert.rs index 9ebb84fb..f768f288 100644 --- a/crates/zune-imageprocs/src/invert.rs +++ b/crates/zune-imageprocs/src/invert.rs @@ -14,7 +14,7 @@ //! //! pixel = max_value-pixel //! ``` -use std::ops::Sub; +use core::ops::Sub; use zune_core::bit_depth::BitType; use zune_core::colorspace::ColorSpace; @@ -55,7 +55,7 @@ impl OperationsTrait for Invert { BitType::U8 => invert(channel.reinterpret_as_mut::()?), BitType::U16 => invert(channel.reinterpret_as_mut::()?), BitType::F32 => invert(channel.reinterpret_as_mut::()?), - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } Ok(()) }; @@ -68,7 +68,7 @@ impl OperationsTrait for Invert { ColorSpace::RGB, ColorSpace::RGBA, ColorSpace::LumaA, - ColorSpace::Luma + ColorSpace::Luma, ] } fn supported_types(&self) -> &'static [BitType] { @@ -82,7 +82,7 @@ impl OperationsTrait for Invert { /// is `pixel[x,y] = 255-pixel[x,y]` pub fn invert(in_image: &mut [T]) where - T: NumOps + Sub + Copy + T: NumOps + Sub + Copy, { for pixel in in_image.iter_mut() { *pixel = T::MAX_VAL - *pixel; @@ -91,7 +91,7 @@ where #[cfg(test)] mod tests { - use std::num::NonZeroU32; + use core::num::NonZeroU32; use zune_core::colorspace::ColorSpace; use zune_image::image::Image; @@ -105,7 +105,7 @@ mod tests { 0_u8, ColorSpace::MultiBand(NonZeroU32::new(6).unwrap()), 100, - 100 + 100, ); Invert::new().execute(&mut image).unwrap(); } diff --git a/crates/zune-imageprocs/src/lib.rs b/crates/zune-imageprocs/src/lib.rs index f128ffe8..efac654e 100644 --- a/crates/zune-imageprocs/src/lib.rs +++ b/crates/zune-imageprocs/src/lib.rs @@ -47,6 +47,14 @@ clippy::missing_errors_doc, clippy::wildcard_imports )] +#![no_std] + +#[macro_use] +extern crate alloc; +extern crate core; + +#[cfg(feature = "std")] +extern crate std; pub use zune_image; diff --git a/crates/zune-imageprocs/src/mathops.rs b/crates/zune-imageprocs/src/mathops.rs index b7766c38..61782e17 100644 --- a/crates/zune-imageprocs/src/mathops.rs +++ b/crates/zune-imageprocs/src/mathops.rs @@ -53,3 +53,157 @@ fn test_u8_div() { assert_eq!(13459 / i, u64::from(divisor)); } } + +#[inline(always)] +#[must_use] +pub(crate) fn round_f32(x: f32) -> f32 { + #[cfg(feature = "libm")] + { + libm::roundf(x) + } + + #[cfg(all(not(feature = "libm"), feature = "std"))] + { + f32::round(x) + } +} + +#[inline(always)] +#[must_use] +pub(crate) fn round_f64(x: f64) -> f64 { + #[cfg(feature = "libm")] + { + libm::round(x) + } + + #[cfg(all(not(feature = "libm"), feature = "std"))] + { + f64::round(x) + } +} + +#[inline(always)] +#[must_use] +pub(crate) fn exp_f64(x: f64) -> f64 { + #[cfg(feature = "libm")] + { + libm::exp(x) + } + + #[cfg(all(not(feature = "libm"), feature = "std"))] + { + f64::exp(x) + } +} + +#[inline(always)] +#[must_use] +pub(crate) fn sqrt_f32(x: f32) -> f32 { + #[cfg(feature = "libm")] + { + libm::sqrtf(x) + } + + #[cfg(all(not(feature = "libm"), feature = "std"))] + { + f32::sqrt(x) + } +} + +#[inline(always)] +#[must_use] +pub(crate) fn sqrt_f64(x: f64) -> f64 { + #[cfg(feature = "libm")] + { + libm::sqrt(x) + } + + #[cfg(all(not(feature = "libm"), feature = "std"))] + { + f64::sqrt(x) + } +} + +#[inline(always)] +#[must_use] +pub(crate) fn powf_f32(base: f32, exp: f32) -> f32 { + #[cfg(feature = "libm")] + { + libm::powf(base, exp) + } + + #[cfg(all(not(feature = "libm"), feature = "std"))] + { + f32::powf(base, exp) + } +} + +#[inline(always)] +#[must_use] +pub(crate) fn sin_f32(x: f32) -> f32 { + #[cfg(feature = "libm")] + { + libm::sinf(x) + } + + #[cfg(all(not(feature = "libm"), feature = "std"))] + { + f32::sin(x) + } +} + +#[inline(always)] +#[must_use] +pub(crate) fn cos_f32(x: f32) -> f32 { + #[cfg(feature = "libm")] + { + libm::cosf(x) + } + + #[cfg(all(not(feature = "libm"), feature = "std"))] + { + f32::cos(x) + } +} + +#[inline(always)] +#[must_use] +pub(crate) fn powi_f32(base: f32, exp: i32) -> f32 { + #[cfg(feature = "libm")] + { + powf_f32(base, exp as f32) + } + + #[cfg(all(not(feature = "libm"), feature = "std"))] + { + f32::powi(base, exp) + } +} + +#[inline(always)] +#[must_use] +pub(crate) fn trunc_f32(x: f32) -> f32 { + #[cfg(feature = "libm")] + { + libm::truncf(x) + } + + #[cfg(all(not(feature = "libm"), feature = "std"))] + { + f32::trunc(x) + } +} + +#[inline(always)] +#[must_use] +pub(crate) fn floor_f32(x: f32) -> f32 { + #[cfg(feature = "libm")] + { + libm::floorf(x) + } + + #[cfg(all(not(feature = "libm"), feature = "std"))] + { + f32::floor(x) + } +} diff --git a/crates/zune-imageprocs/src/median.rs b/crates/zune-imageprocs/src/median.rs index 014c5bf5..e0925ee0 100644 --- a/crates/zune-imageprocs/src/median.rs +++ b/crates/zune-imageprocs/src/median.rs @@ -54,7 +54,7 @@ use crate::utils::{execute_on, z_prefetch}; /// for example a radius of R will result in a search window length of 2R+1 for each dimension. #[derive(Default)] pub struct Median { - radius: usize + radius: usize, } impl Median { @@ -86,16 +86,16 @@ impl OperationsTrait for Median { new_channel.reinterpret_as_mut::()?, self.radius, width, - height + height, ), BitType::U8 => median_u8( channel.reinterpret_as::()?, new_channel.reinterpret_as_mut::()?, self.radius, width, - height + height, ), - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } *channel = new_channel; Ok(()) @@ -109,7 +109,7 @@ impl OperationsTrait for Median { } #[allow(clippy::cast_possible_truncation)] pub fn median_u16( - in_channel: &[u16], out_channel: &mut [u16], radius: usize, width: usize, height: usize + in_channel: &[u16], out_channel: &mut [u16], radius: usize, width: usize, height: usize, ) { /* * Okay rico, we run a tight shift here @@ -195,13 +195,13 @@ pub fn median_u16( height, radius, radius, - PadMethod::Replicate + PadMethod::Replicate, ); spatial_median(&padded_input, out_channel, radius, width, height, func); } #[allow(clippy::cast_possible_truncation)] pub fn median_u8( - in_channel: &[u8], out_channel: &mut [u8], radius: usize, width: usize, height: usize + in_channel: &[u8], out_channel: &mut [u8], radius: usize, width: usize, height: usize, ) { // duplicated from above, but uses array instead of vec, and @@ -277,17 +277,17 @@ pub fn median_u8( height, radius, radius, - PadMethod::Replicate + PadMethod::Replicate, ); spatial_median(&padded_input, out_channel, radius, width, height, func); } pub fn spatial_median( in_channel: &[T], out_channel: &mut [T], radius: usize, width: usize, height: usize, - mut function: F + mut function: F, ) where T: Default + Copy, - F: FnMut(&[T]) -> T + F: FnMut(&[T]) -> T, { let old_width = width; let height = (radius * 2) + height; diff --git a/crates/zune-imageprocs/src/mirror.rs b/crates/zune-imageprocs/src/mirror.rs index 499ad559..8fc7cf21 100644 --- a/crates/zune-imageprocs/src/mirror.rs +++ b/crates/zune-imageprocs/src/mirror.rs @@ -53,7 +53,7 @@ pub enum MirrorMode { /// │f g h i j│ │j i h i j │ /// └─────────┘ └──────────┘ /// ``` - West + West, } /// Rearrange the pixels along a certain axis. @@ -62,7 +62,7 @@ pub enum MirrorMode { /// see the image [mirror-modes](crate::mirror::MirrorMode) documentation /// for each used mode pub struct Mirror { - mode: MirrorMode + mode: MirrorMode, } impl Mirror { @@ -89,7 +89,7 @@ impl OperationsTrait for Mirror { channel.reinterpret_as_mut::()?, width, height, - self.mode + self.mode, ); } @@ -98,7 +98,7 @@ impl OperationsTrait for Mirror { channel.reinterpret_as_mut::()?, width, height, - self.mode + self.mode, ); } BitType::F32 => { @@ -106,10 +106,10 @@ impl OperationsTrait for Mirror { channel.reinterpret_as_mut::()?, width, height, - self.mode + self.mode, ); } - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } Ok(()) }; diff --git a/crates/zune-imageprocs/src/pad.rs b/crates/zune-imageprocs/src/pad.rs index 2c34ac22..24748270 100644 --- a/crates/zune-imageprocs/src/pad.rs +++ b/crates/zune-imageprocs/src/pad.rs @@ -12,6 +12,8 @@ //! or replicating values across the border //! +use alloc::vec::Vec; + /// Padding method to use #[derive(Copy, Clone)] pub enum PadMethod { @@ -31,7 +33,7 @@ pub enum PadMethod { /// d d,e,f f /// d,e,f /// ``` - Replicate + Replicate, } /// Pad pixels creating a buffer around actual pixels @@ -76,16 +78,16 @@ pub enum PadMethod { /// # Returns: /// - A vec containing padded pixels. pub fn pad( - pixels: &[T], width: usize, height: usize, pad_x: usize, pad_y: usize, method: PadMethod + pixels: &[T], width: usize, height: usize, pad_x: usize, pad_y: usize, method: PadMethod, ) -> Vec { match method { PadMethod::Constant => no_fill(pixels, width, height, pad_x, pad_y), - PadMethod::Replicate => replicate(pixels, width, height, pad_x, pad_y) + PadMethod::Replicate => replicate(pixels, width, height, pad_x, pad_y), } } fn no_fill( - pixels: &[T], width: usize, height: usize, pad_x: usize, pad_y: usize + pixels: &[T], width: usize, height: usize, pad_x: usize, pad_y: usize, ) -> Vec { let padded_w = width + pad_x * 2; let padded_h = height + pad_y * 2; @@ -108,7 +110,7 @@ fn no_fill( } fn replicate( - pixels: &[T], width: usize, height: usize, pad_x: usize, pad_y: usize + pixels: &[T], width: usize, height: usize, pad_x: usize, pad_y: usize, ) -> Vec { let padded_w = width + pad_x * 2; let padded_h = height + pad_y * 2; @@ -193,7 +195,7 @@ mod benchmarks { height, new_width, new_height, - PadMethod::Replicate + PadMethod::Replicate, ) }); } @@ -213,7 +215,7 @@ mod benchmarks { height, new_width, new_height, - PadMethod::Constant + PadMethod::Constant, ) }); } diff --git a/crates/zune-imageprocs/src/premul_alpha.rs b/crates/zune-imageprocs/src/premul_alpha.rs index 4881b49d..cba75938 100644 --- a/crates/zune-imageprocs/src/premul_alpha.rs +++ b/crates/zune-imageprocs/src/premul_alpha.rs @@ -43,6 +43,8 @@ //! [`fastdiv_u32`] //! - +use alloc::vec::Vec; + use zune_core::bit_depth::{BitDepth, BitType}; use zune_core::colorspace::ColorSpace; use zune_core::log::warn; @@ -65,7 +67,7 @@ mod std_simd; /// be loss of image quality. #[derive(Copy, Clone)] pub struct PremultiplyAlpha { - to: AlphaState + to: AlphaState, } impl PremultiplyAlpha { @@ -134,24 +136,24 @@ impl OperationsTrait for PremultiplyAlpha { BitDepth::Eight => { premultiply_u8( channel.reinterpret_as_mut()?, - alpha[0].reinterpret_as()? + alpha[0].reinterpret_as()?, ); } BitDepth::Sixteen => { premultiply_u16( channel.reinterpret_as_mut()?, - alpha[0].reinterpret_as()? + alpha[0].reinterpret_as()?, ); } BitDepth::Float32 => premultiply_f32( channel.reinterpret_as_mut()?, - alpha[0].reinterpret_as()? + alpha[0].reinterpret_as()?, ), d => { return Err(ImageErrors::ImageOperationNotImplemented( self.name(), - d.bit_type() + d.bit_type(), )) } }, @@ -160,29 +162,29 @@ impl OperationsTrait for PremultiplyAlpha { unpremultiply_u8( channel.reinterpret_as_mut()?, alpha[0].reinterpret_as()?, - &u8_table + &u8_table, ); } BitDepth::Sixteen => { unpremultiply_u16( channel.reinterpret_as_mut()?, alpha[0].reinterpret_as()?, - &u16_table + &u16_table, ); } BitDepth::Float32 => unpremultiply_f32( channel.reinterpret_as_mut()?, - alpha[0].reinterpret_as()? + alpha[0].reinterpret_as()?, ), d => { return Err(ImageErrors::ImageOperationNotImplemented( self.name(), - d.bit_type() + d.bit_type(), )) } }, - (_, _) => return Err(ImageErrors::GenericStr("Could not pre-multiply alpha")) + (_, _) => return Err(ImageErrors::GenericStr("Could not pre-multiply alpha")), } } } @@ -281,7 +283,7 @@ pub fn unpremultiply_u8(input: &mut [u8], alpha: &[u8], premul_table: &[u128; 25 let associated_alpha = premul_table[usize::from(*al)]; *color = u8::try_from(fastdiv_u32( u32::from(*color) * MAX_VALUE + (u32::from(*al) / 2), - associated_alpha + associated_alpha, )) .unwrap_or(u8::MAX); }); @@ -317,7 +319,7 @@ pub fn unpremultiply_u16(input: &mut [u16], alpha: &[u16], premul_table: &[u128] *color = u16::try_from(fastdiv_u32( u32::from(*color) * MAX_VALUE + (u32::from(*al) / 2), - associated_alpha + associated_alpha, )) .unwrap_or(u16::MAX); }); diff --git a/crates/zune-imageprocs/src/premul_alpha/std_simd.rs b/crates/zune-imageprocs/src/premul_alpha/std_simd.rs index c70823ed..32290769 100644 --- a/crates/zune-imageprocs/src/premul_alpha/std_simd.rs +++ b/crates/zune-imageprocs/src/premul_alpha/std_simd.rs @@ -1,7 +1,7 @@ #![cfg(feature = "portable-simd")] +use core::mem::size_of; use core::simd::prelude::*; -use std::mem::size_of; use crate::premul_alpha::unpremultiply_f32_scalar; @@ -34,7 +34,7 @@ pub fn unpremultiply_std_simd(input: &mut [f32], alpha: &[f32]) { // handle remainder unpremultiply_f32_scalar( input.chunks_exact_mut(VECTOR_SIZE).into_remainder(), - alpha.chunks_exact(VECTOR_SIZE).remainder() + alpha.chunks_exact(VECTOR_SIZE).remainder(), ); } diff --git a/crates/zune-imageprocs/src/prewitt.rs b/crates/zune-imageprocs/src/prewitt.rs index 4d07d9ad..22504f85 100644 --- a/crates/zune-imageprocs/src/prewitt.rs +++ b/crates/zune-imageprocs/src/prewitt.rs @@ -4,6 +4,7 @@ * This software is free software; You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license */ #![allow(dead_code)] +use crate::mathops::{sqrt_f32, sqrt_f64}; use crate::pad::{pad, PadMethod}; use crate::spatial::spatial_NxN; use crate::traits::NumOps; @@ -17,7 +18,7 @@ use crate::traits::NumOps; fn prewitt_inner_f32(c: &[T; 9]) -> T where T: NumOps + Copy + Default, - f32: std::convert::From + f32: core::convert::From { // matrix // +1, 0, -1, @@ -38,7 +39,7 @@ fn prewitt_inner_f32(c: &[T; 9]) -> T sum_b += (f32::from(c[2]) * 1.) + (f32::from(c[6]) * -1.); sum_b += (f32::from(c[7]) * -1.) + (f32::from(c[8]) * -1.); - T::from_f32(((sum_a * sum_a) + (sum_b * sum_b)).sqrt()) + T::from_f32(sqrt_f32((sum_a * sum_a) + (sum_b * sum_b))) } /// Calculate prewitt for int images @@ -51,7 +52,7 @@ fn prewitt_inner_f32(c: &[T; 9]) -> T fn prewitt_inner_i32(c: &[T; 9]) -> T where T: NumOps + Copy + Default, - i32: std::convert::From + i32: core::convert::From { // Gx matrix // -3, 0, 3, @@ -72,7 +73,7 @@ fn prewitt_inner_i32(c: &[T; 9]) -> T sum_b += (i32::from(c[2]) * 1) + (i32::from(c[6]) * -1); sum_b += (i32::from(c[7]) * -1) + (i32::from(c[8]) * -1); - T::from_f64(f64::from((sum_a * sum_a) + (sum_b * sum_b)).sqrt()) + T::from_f64(sqrt_f64(f64::from((sum_a * sum_a) + (sum_b * sum_b)))) } /// Carry out the prewitt filter for a float channel @@ -87,7 +88,7 @@ fn prewitt_inner_i32(c: &[T; 9]) -> T pub fn prewitt_float(in_channel: &[T], out_channel: &mut [T], width: usize, height: usize) where T: Default + NumOps + Copy, - f32: std::convert::From + f32: core::convert::From, { //pad here let padded_input = pad(in_channel, width, height, 1, 1, PadMethod::Replicate); @@ -107,7 +108,7 @@ where pub fn prewitt_int(in_channel: &[T], out_channel: &mut [T], width: usize, height: usize) where T: Default + NumOps + Copy, - i32: std::convert::From + i32: core::convert::From, { //pad here let padded_input = pad(in_channel, width, height, 1, 1, PadMethod::Replicate); diff --git a/crates/zune-imageprocs/src/resize.rs b/crates/zune-imageprocs/src/resize.rs index 8951bd10..5d35a0ac 100644 --- a/crates/zune-imageprocs/src/resize.rs +++ b/crates/zune-imageprocs/src/resize.rs @@ -28,7 +28,7 @@ mod bilinear; #[derive(Copy, Clone, Debug)] pub enum ResizeMethod { Bilinear, - Bicubic + Bicubic, } // pub enum ResizeDimensions{ @@ -39,9 +39,9 @@ pub enum ResizeMethod { /// using the resize method specified #[derive(Copy, Clone)] pub struct Resize { - new_width: usize, + new_width: usize, new_height: usize, - method: ResizeMethod + method: ResizeMethod, } impl Resize { @@ -56,7 +56,7 @@ impl Resize { Resize { new_width, new_height, - method + method, } } } @@ -83,7 +83,7 @@ impl OperationsTrait for Resize { old_w, old_h, self.new_width, - self.new_height + self.new_height, ), BitType::U16 => resize::( channel.reinterpret_as()?, @@ -92,7 +92,7 @@ impl OperationsTrait for Resize { old_w, old_h, self.new_width, - self.new_height + self.new_height, ), BitType::F32 => { @@ -103,10 +103,10 @@ impl OperationsTrait for Resize { old_w, old_h, self.new_width, - self.new_height + self.new_height, ); } - d => return Err(ImageErrors::ImageOperationNotImplemented("resize", d)) + d => return Err(ImageErrors::ImageOperationNotImplemented("resize", d)), } *channel = new_channel; Ok(()) @@ -130,7 +130,7 @@ impl OperationsTrait for Resize { clippy::cast_sign_loss )] pub fn ratio_dimensions_smaller( - old_w: usize, old_h: usize, new_w: usize, new_h: usize + old_w: usize, old_h: usize, new_w: usize, new_h: usize, ) -> (usize, usize) { let ratio_w = old_w as f64 / new_w as f64; let ratio_h = old_h as f64 / new_h as f64; @@ -150,7 +150,7 @@ pub fn ratio_dimensions_smaller( clippy::cast_sign_loss )] pub fn ratio_dimensions_larger( - old_w: usize, old_h: usize, new_w: usize, new_h: usize + old_w: usize, old_h: usize, new_w: usize, new_h: usize, ) -> (usize, usize) { let ratio_w = old_w as f64 / new_w as f64; let ratio_h = old_h as f64 / new_h as f64; @@ -175,20 +175,20 @@ pub fn ratio_dimensions_larger( /// - `out_width*out_height` do not match `out_image.len()`. pub fn resize( in_image: &[T], out_image: &mut [T], method: ResizeMethod, in_width: usize, in_height: usize, - out_width: usize, out_height: usize + out_width: usize, out_height: usize, ) where T: Copy + NumOps + Default, - f32: std::convert::From + f32: core::convert::From, { match method { ResizeMethod::Bilinear => { bilinear::bilinear_impl( - in_image, out_image, in_width, in_height, out_width, out_height + in_image, out_image, in_width, in_height, out_width, out_height, ); } ResizeMethod::Bicubic => { bicubic::bicubic_resample( - in_image, out_image, in_width, in_height, out_width, out_height + in_image, out_image, in_width, in_height, out_width, out_height, ); } } @@ -224,7 +224,7 @@ mod benchmarks { width, height, new_width, - new_height + new_height, ); }); } @@ -251,7 +251,7 @@ mod benchmarks { width, height, new_width, - new_height + new_height, ); }); } @@ -282,7 +282,7 @@ mod tests { width, height, new_width, - new_height + new_height, ); } } diff --git a/crates/zune-imageprocs/src/resize/bicubic.rs b/crates/zune-imageprocs/src/resize/bicubic.rs index 078d71dd..82b9fd6f 100644 --- a/crates/zune-imageprocs/src/resize/bicubic.rs +++ b/crates/zune-imageprocs/src/resize/bicubic.rs @@ -1,6 +1,9 @@ #![allow(dead_code)] -use crate::traits::NumOps; +use crate::{ + mathops::{powi_f32, trunc_f32}, + traits::NumOps, +}; #[cfg(feature = "portable-simd")] mod std_simd { @@ -66,9 +69,9 @@ const A: f32 = -0.5; fn bicubic_kernel(x: f32) -> f32 { let x = x.abs(); if x <= 1.0 { - (A + 2.0) * x.powi(3) - (A + 3.0) * x.powi(2) + 1.0 + (A + 2.0) * powi_f32(x, 3) - (A + 3.0) * powi_f32(x, 2) + 1.0 } else if x < 2.0 { - A * x.powi(3) - 5.0 * A * x.powi(2) + 8.0 * A * x - 4.0 * A + A * powi_f32(x, 3) - 5.0 * A * powi_f32(x, 2) + 8.0 * A * x - 4.0 * A } else { 0.0 } @@ -111,10 +114,10 @@ fn bicubic_function(y0: isize, src_y: f32) -> [f32; 4] { } pub fn bicubic_resample( input: &[T], output: &mut [T], input_width: usize, input_height: usize, new_width: usize, - new_height: usize + new_height: usize, ) where T: Copy + NumOps, - f32: std::convert::From + f32: core::convert::From, { let scale_y = input_height as f32 / new_height as f32; let scale_x = input_width as f32 / new_width as f32; @@ -140,13 +143,13 @@ pub fn bicubic_resample( // the ideal one is src_y.floor(), but // trunk == floor for +ve values and // src_y can't be negative. - let y0 = src_y.trunc() as isize; + let y0 = trunc_f32(src_y) as isize; let y_coeffs = bicubic_function(y0, src_y); for (x, x_coeffs) in (0..new_width).zip(x_mega_coeffs.iter()) { let src_x = x as f32 * scale_x; - let x0 = src_x.trunc() as usize; + let x0 = trunc_f32(src_x) as usize; let mut sum = 0.0; let mut weight_sum = 0.0; @@ -212,7 +215,7 @@ pub fn bicubic_resample( mod benchmarks { extern crate test; - use std::hint::black_box; + use core::hint::black_box; use std::simd::f32x4; use nanorand::{Rng, WyRand}; diff --git a/crates/zune-imageprocs/src/resize/bilinear.rs b/crates/zune-imageprocs/src/resize/bilinear.rs index 610b5f68..11bdba06 100644 --- a/crates/zune-imageprocs/src/resize/bilinear.rs +++ b/crates/zune-imageprocs/src/resize/bilinear.rs @@ -1,4 +1,4 @@ -use crate::traits::NumOps; +use crate::{mathops::floor_f32, traits::NumOps}; /// Bilinear interpolation of a single channel, this interpolates a single channel, but not an image /// @@ -10,10 +10,10 @@ use crate::traits::NumOps; )] pub fn bilinear_impl( in_channel: &[T], out_channel: &mut [T], in_width: usize, in_height: usize, out_width: usize, - out_height: usize + out_height: usize, ) where T: Copy + NumOps, - f32: std::convert::From + f32: core::convert::From, { let w_ratio = 1.0 / out_width as f32 * in_width as f32; let h_ratio = 1.0 / out_height as f32 * in_height as f32; @@ -22,7 +22,7 @@ pub fn bilinear_impl( for y in 0..out_height { let new_y = y as f32 * h_ratio; - let mut y0 = new_y.floor() as usize; + let mut y0 = floor_f32(new_y) as usize; let y1 = (y0 + 1).min(in_height - 1); if smaller_image_to_larger { @@ -33,7 +33,7 @@ pub fn bilinear_impl( for x in 0..out_width { let new_x = x as f32 * w_ratio; // floor and truncate are slow due to handling overflow and such, so avoid them here - let mut x0 = new_x.floor() as usize; + let mut x0 = floor_f32(new_x) as usize; let x1 = (x0 + 1).min(in_width - 1); // PS: I'm not sure about the impact, but it cuts down on code executed diff --git a/crates/zune-imageprocs/src/rotate.rs b/crates/zune-imageprocs/src/rotate.rs index 1fec006c..3ea6a6ad 100644 --- a/crates/zune-imageprocs/src/rotate.rs +++ b/crates/zune-imageprocs/src/rotate.rs @@ -22,7 +22,7 @@ use zune_image::traits::OperationsTrait; use crate::utils::execute_on; pub struct Rotate { - angle: f32 + angle: f32, } impl Rotate { @@ -55,7 +55,7 @@ impl OperationsTrait for Rotate { width, height, channel.reinterpret_as()?, - new_channel.reinterpret_as_mut()? + new_channel.reinterpret_as_mut()?, ); } BitType::U16 => { @@ -64,7 +64,7 @@ impl OperationsTrait for Rotate { width, height, channel.reinterpret_as()?, - new_channel.reinterpret_as_mut()? + new_channel.reinterpret_as_mut()?, ); } BitType::F32 => rotate::( @@ -72,9 +72,9 @@ impl OperationsTrait for Rotate { width, height, channel.reinterpret_as()?, - new_channel.reinterpret_as_mut()? + new_channel.reinterpret_as_mut()?, ), - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), }; *channel = new_channel; Ok(()) @@ -104,7 +104,7 @@ fn change_image_dims(image: &mut Image, angle: f32) { } pub fn rotate( - angle: f32, width: usize, height: usize, in_image: &[T], out_image: &mut [T] + angle: f32, width: usize, height: usize, in_image: &[T], out_image: &mut [T], ) { let angle = angle % 360.0; diff --git a/crates/zune-imageprocs/src/scharr.rs b/crates/zune-imageprocs/src/scharr.rs index 1e762e58..bd7ae3b4 100644 --- a/crates/zune-imageprocs/src/scharr.rs +++ b/crates/zune-imageprocs/src/scharr.rs @@ -6,12 +6,16 @@ * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license */ //! Scharr derivative filter + +use alloc::vec::Vec; + use zune_core::bit_depth::BitType; use zune_image::channel::Channel; use zune_image::errors::ImageErrors; use zune_image::image::Image; use zune_image::traits::OperationsTrait; +use crate::mathops::{sqrt_f32, sqrt_f64}; use crate::pad::{pad, PadMethod}; use crate::spatial::spatial_NxN; use crate::traits::NumOps; @@ -67,21 +71,21 @@ impl OperationsTrait for Scharr { channel.reinterpret_as()?, out_channel.reinterpret_as_mut()?, width, - height + height, ), BitType::U16 => scharr_int::( channel.reinterpret_as()?, out_channel.reinterpret_as_mut()?, width, - height + height, ), BitType::F32 => scharr_float::( channel.reinterpret_as()?, out_channel.reinterpret_as_mut()?, width, - height + height, ), - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } *channel = out_channel; } @@ -98,24 +102,24 @@ impl OperationsTrait for Scharr { channel.reinterpret_as()?, out_channel.reinterpret_as_mut()?, width, - height + height, ), BitType::U16 => scharr_int::( channel.reinterpret_as()?, out_channel.reinterpret_as_mut()?, width, - height + height, ), BitType::F32 => scharr_float::( channel.reinterpret_as()?, out_channel.reinterpret_as_mut()?, width, - height + height, ), d => { return Err(ImageErrors::ImageOperationNotImplemented( self.name(), - d + d, )) } } @@ -148,7 +152,7 @@ impl OperationsTrait for Scharr { fn scharr_inner_f32(c: &[T; 9]) -> T where T: NumOps + Copy + Default, - f32: std::convert::From + f32: core::convert::From { // matrix // -3, 0, 3, @@ -169,7 +173,7 @@ fn scharr_inner_f32(c: &[T; 9]) -> T sum_b += (f32::from(c[2]) * -03.) + (f32::from(c[6]) * 03.); sum_b += (f32::from(c[7]) * 10.) + (f32::from(c[8]) * 03.); - T::from_f32(((sum_a * sum_a) + (sum_b * sum_b)).sqrt()) + T::from_f32(sqrt_f32((sum_a * sum_a) + (sum_b * sum_b))) } /// Calculate scharr for int images @@ -182,7 +186,7 @@ fn scharr_inner_f32(c: &[T; 9]) -> T fn scharr_inner_i32(c: &[T; 9]) -> T where T: NumOps + Copy + Default, - i32: std::convert::From + i32: core::convert::From { // Gx matrix // -3, 0, 3, @@ -203,7 +207,7 @@ fn scharr_inner_i32(c: &[T; 9]) -> T sum_b += (i32::from(c[2]) * -03) + (i32::from(c[6]) * 03); sum_b += (i32::from(c[7]) * 10) + (i32::from(c[8]) * 03); - T::from_f64(f64::from((sum_a * sum_a) + (sum_b * sum_b)).sqrt()) + T::from_f64(sqrt_f64(f64::from((sum_a * sum_a) + (sum_b * sum_b)))) } /// Carry out the scharr filter for a float channel @@ -218,7 +222,7 @@ fn scharr_inner_i32(c: &[T; 9]) -> T pub fn scharr_float(in_channel: &[T], out_channel: &mut [T], width: usize, height: usize) where T: Default + NumOps + Copy, - f32: std::convert::From + f32: core::convert::From, { //pad here let padded_input = pad(in_channel, width, height, 1, 1, PadMethod::Replicate); @@ -238,7 +242,7 @@ where pub fn scharr_int(in_channel: &[T], out_channel: &mut [T], width: usize, height: usize) where T: Default + NumOps + Copy, - i32: std::convert::From + i32: core::convert::From, { //pad here let padded_input = pad(in_channel, width, height, 1, 1, PadMethod::Replicate); diff --git a/crates/zune-imageprocs/src/sobel.rs b/crates/zune-imageprocs/src/sobel.rs index 663c5fe5..d9628794 100644 --- a/crates/zune-imageprocs/src/sobel.rs +++ b/crates/zune-imageprocs/src/sobel.rs @@ -13,6 +13,7 @@ use zune_image::errors::ImageErrors; use zune_image::image::Image; use zune_image::traits::OperationsTrait; +use crate::mathops::{sqrt_f32, sqrt_f64}; use crate::pad::{pad, PadMethod}; use crate::spatial::spatial_NxN; use crate::traits::NumOps; @@ -66,21 +67,21 @@ impl OperationsTrait for Sobel { channel.reinterpret_as()?, out_channel.reinterpret_as_mut()?, width, - height + height, ), BitType::U16 => sobel_int::( channel.reinterpret_as()?, out_channel.reinterpret_as_mut()?, width, - height + height, ), BitType::F32 => sobel_float::( channel.reinterpret_as()?, out_channel.reinterpret_as_mut()?, width, - height + height, ), - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } *channel = out_channel; Ok(()) @@ -102,7 +103,7 @@ impl OperationsTrait for Sobel { fn sobel_inner_f32(c: &[T; 9]) -> T where T: NumOps + Copy + Default, - f32: std::convert::From + f32: core::convert::From { // matrix // -1, 0, 1, @@ -123,7 +124,7 @@ fn sobel_inner_f32(c: &[T; 9]) -> T sum_b += (f32::from(c[2]) * -1.) + (f32::from(c[6]) * 1.); sum_b += (f32::from(c[7]) * 2.) + (f32::from(c[8]) * 1.); - T::from_f32(((sum_a * sum_a) + (sum_b * sum_b)).sqrt()) + T::from_f32(sqrt_f32((sum_a * sum_a) + (sum_b * sum_b))) } /// Calculate sobel for int images @@ -136,7 +137,7 @@ fn sobel_inner_f32(c: &[T; 9]) -> T fn sobel_inner_i32(c: &[T; 9]) -> T where T: NumOps + Copy + Default, - i32: std::convert::From + i32: core::convert::From { // matrix // -1, 0, 1, @@ -157,7 +158,7 @@ fn sobel_inner_i32(c: &[T; 9]) -> T sum_b += (i32::from(c[2]) * -1) + (i32::from(c[6]) * 1); sum_b += (i32::from(c[7]) * 2) + (i32::from(c[8]) * 1); - T::from_f64(f64::from((sum_a * sum_a) + (sum_b * sum_b)).sqrt()) + T::from_f64(sqrt_f64(f64::from((sum_a * sum_a) + (sum_b * sum_b)))) } /// Carry out the sobel filter for a float channel @@ -172,7 +173,7 @@ fn sobel_inner_i32(c: &[T; 9]) -> T pub fn sobel_float(in_channel: &[T], out_channel: &mut [T], width: usize, height: usize) where T: Default + NumOps + Copy, - f32: std::convert::From + f32: core::convert::From, { //pad here let padded_input = pad(in_channel, width, height, 1, 1, PadMethod::Replicate); @@ -192,7 +193,7 @@ where pub fn sobel_int(in_channel: &[T], out_channel: &mut [T], width: usize, height: usize) where T: Default + NumOps + Copy, - i32: std::convert::From + i32: core::convert::From, { //pad here let padded_input = pad(in_channel, width, height, 1, 1, PadMethod::Replicate); diff --git a/crates/zune-imageprocs/src/spatial.rs b/crates/zune-imageprocs/src/spatial.rs index 323e9b47..2fea98c7 100644 --- a/crates/zune-imageprocs/src/spatial.rs +++ b/crates/zune-imageprocs/src/spatial.rs @@ -23,8 +23,8 @@ /// /// for example a radius of R will result in a search window length of 2R+1 for each dimension. pub struct SpatialOps { - radius: usize, - operation: SpatialOperations + radius: usize, + operation: SpatialOperations, } impl SpatialOps { @@ -54,7 +54,7 @@ impl OperationsTrait for SpatialOps { self.radius, width, height, - self.operation + self.operation, ), BitType::U8 => spatial_ops( channel.reinterpret_as::()?, @@ -62,9 +62,9 @@ impl OperationsTrait for SpatialOps { self.radius, width, height, - self.operation + self.operation, ), - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } *channel = new_channel; Ok(()) @@ -105,10 +105,10 @@ use crate::utils::{execute_on, z_prefetch}; /// pub fn spatial( in_channel: &[T], out_channel: &mut [T], radius: usize, width: usize, height: usize, - function: F + function: F, ) where T: Default + Copy, - F: Fn(&[T]) -> T + F: Fn(&[T]) -> T, { let old_width = width; let height = (radius * 2) + height; @@ -151,10 +151,10 @@ pub fn spatial( /// speed up operations for convolve #[allow(non_snake_case)] pub(crate) fn spatial_NxN( - in_channel: &[T], out_channel: &mut [T], width: usize, height: usize, function: F + in_channel: &[T], out_channel: &mut [T], width: usize, height: usize, function: F, ) where T: Default + Copy, - F: Fn(&[T; OUT_SIZE]) -> T + F: Fn(&[T; OUT_SIZE]) -> T, { let old_width = width; let height = (RADIUS * 2) + height; diff --git a/crates/zune-imageprocs/src/spatial_ops.rs b/crates/zune-imageprocs/src/spatial_ops.rs index 687fdc35..84ec5ec8 100644 --- a/crates/zune-imageprocs/src/spatial_ops.rs +++ b/crates/zune-imageprocs/src/spatial_ops.rs @@ -6,8 +6,11 @@ * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license */ //! Simple spatial operations implemented for images -use std::fmt::Debug; -use std::ops::{Add, Div, Sub}; + +use alloc::string::{String, ToString}; + +use core::fmt::Debug; +use core::ops::{Add, Div, Sub}; use crate::pad::{pad, PadMethod}; use crate::spatial::spatial; @@ -25,7 +28,7 @@ pub enum SpatialOperations { /// min Minimum, /// sum(pix)/len - Mean + Mean, } impl SpatialOperations { @@ -57,9 +60,9 @@ fn find_min>(data: &[T]) -> T { } fn find_contrast< - T: PartialOrd + Default + Copy + NumOps + Sub + Add + Div + T: PartialOrd + Default + Copy + NumOps + Sub + Add + Div, >( - data: &[T] + data: &[T], ) -> T { let mut minimum = T::MAX_VAL; let mut maximum = T::MIN_VAL; @@ -79,9 +82,9 @@ fn find_contrast< } fn find_gradient< - T: PartialOrd + Default + Copy + NumOps + Sub + Add + Div + T: PartialOrd + Default + Copy + NumOps + Sub + Add + Div, >( - data: &[T] + data: &[T], ) -> T { let mut minimum = T::max_val(); let mut maximum = T::min_val(); @@ -114,7 +117,7 @@ fn find_max>(data: &[T]) -> T { fn find_mean(data: &[T]) -> T where T: Default + Copy + NumOps + Add + Div, - u32: std::convert::From + u32: core::convert::From, { //https://godbolt.org/z/6Y8ncehd5 let mut maximum = u32::default(); @@ -140,7 +143,7 @@ where /// pub fn spatial_ops( in_channel: &[T], out_channel: &mut [T], radius: usize, width: usize, height: usize, - operations: SpatialOperations + operations: SpatialOperations, ) where T: PartialOrd + Default @@ -149,7 +152,7 @@ pub fn spatial_ops( + Sub + Add + Div, - u32: std::convert::From + u32: core::convert::From, { //pad here let padded_input = pad( @@ -158,7 +161,7 @@ pub fn spatial_ops( height, radius, radius, - PadMethod::Replicate + PadMethod::Replicate, ); // Note: It's faster to do it like this, @@ -181,7 +184,7 @@ pub fn spatial_ops( SpatialOperations::Maximum => find_max::, SpatialOperations::Gradient => find_gradient::, SpatialOperations::Minimum => find_min::, - SpatialOperations::Mean => find_mean:: + SpatialOperations::Mean => find_mean::, }; spatial(&padded_input, out_channel, radius, width, height, ptr); @@ -212,7 +215,7 @@ mod benchmarks { radius, width, height, - SpatialOperations::Mean + SpatialOperations::Mean, ); }); } @@ -235,7 +238,7 @@ mod benchmarks { radius, width, height, - SpatialOperations::Minimum + SpatialOperations::Minimum, ); }); } diff --git a/crates/zune-imageprocs/src/stretch_contrast.rs b/crates/zune-imageprocs/src/stretch_contrast.rs index 69fd8cec..eac0ecf3 100644 --- a/crates/zune-imageprocs/src/stretch_contrast.rs +++ b/crates/zune-imageprocs/src/stretch_contrast.rs @@ -12,7 +12,7 @@ #[derive(Default)] pub struct StretchContrast { lower: f32, - upper: f32 + upper: f32, } impl StretchContrast { @@ -46,20 +46,20 @@ impl OperationsTrait for StretchContrast { channel.reinterpret_as_mut::()?, self.lower as u8, self.upper as u8, - u32::from(depth.max_value()) + u32::from(depth.max_value()), )?, BitType::U16 => stretch_contrast( channel.reinterpret_as_mut::()?, self.lower as _, self.upper as _, - u32::from(depth.max_value()) + u32::from(depth.max_value()), )?, BitType::F32 => stretch_contrast_f32( channel.reinterpret_as_mut::()?, self.lower as _, - self.upper as _ + self.upper as _, )?, - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } Ok(()) }; @@ -69,7 +69,7 @@ impl OperationsTrait for StretchContrast { &[BitType::U8, BitType::U16] } } -use std::ops::Sub; +use core::ops::Sub; use zune_core::bit_depth::BitType; use zune_image::channel::Channel; @@ -97,11 +97,11 @@ use crate::utils::execute_on; /// - Modifies array in place /// pub fn stretch_contrast( - image: &mut [T], lower: T, upper: T, maximum: u32 + image: &mut [T], lower: T, upper: T, maximum: u32, ) -> Result<(), &'static str> where T: Ord + Sub + NumOps + Copy, - u32: std::convert::From + u32: core::convert::From, { if upper < lower { return Err("upper must be strictly greater than lower"); diff --git a/crates/zune-imageprocs/src/threshold.rs b/crates/zune-imageprocs/src/threshold.rs index 5e7dd133..ab1b99d2 100644 --- a/crates/zune-imageprocs/src/threshold.rs +++ b/crates/zune-imageprocs/src/threshold.rs @@ -6,6 +6,9 @@ * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license */ //! Threshold filter: Binarize an image + +use alloc::string::{String, ToString}; + use zune_core::bit_depth::BitType; use zune_core::log::warn; use zune_image::channel::Channel; @@ -21,7 +24,7 @@ pub enum ThresholdMethod { Binary, BinaryInv, ThreshTrunc, - ThreshToZero + ThreshToZero, } impl ThresholdMethod { @@ -51,8 +54,8 @@ impl ThresholdMethod { /// /// See [Wikipedia Article on Thresholding](https://en.wikipedia.org/wiki/Thresholding_(image_processing)) pub struct Threshold { - method: ThresholdMethod, - threshold: f32 + method: ThresholdMethod, + threshold: f32, } impl Threshold { @@ -90,19 +93,19 @@ impl OperationsTrait for Threshold { BitType::U16 => threshold( channel.reinterpret_as_mut::()?, self.threshold.clamp(0., 65535.) as u16, - self.method + self.method, ), BitType::U8 => threshold( channel.reinterpret_as_mut::()?, self.threshold.clamp(0., 255.) as u8, - self.method + self.method, ), BitType::F32 => threshold( channel.reinterpret_as_mut::()?, self.threshold, - self.method + self.method, ), - d => return Err(ImageErrors::ImageOperationNotImplemented("threshold", d)) + d => return Err(ImageErrors::ImageOperationNotImplemented("threshold", d)), } Ok(()) }; diff --git a/crates/zune-imageprocs/src/transpose.rs b/crates/zune-imageprocs/src/transpose.rs index a0645e61..4d3af510 100644 --- a/crates/zune-imageprocs/src/transpose.rs +++ b/crates/zune-imageprocs/src/transpose.rs @@ -8,7 +8,8 @@ //! Interchange row and columns in an image //! -use std::sync::Once; + +use core::sync::atomic::AtomicBool; use zune_core::bit_depth::BitType; use zune_core::log::trace; @@ -24,7 +25,17 @@ pub(crate) mod scalar; pub(crate) mod sse41; mod tests; -static START: Once = Once::new(); +static START: AtomicBool = AtomicBool::new(true); + +fn once(f: impl FnOnce() -> T) -> Option { + use core::sync::atomic::Ordering; + + if let Ok(true) = START.compare_exchange(true, false, Ordering::Acquire, Ordering::Relaxed) { + Some(f()) + } else { + None + } +} /// Transpose an image /// @@ -62,7 +73,7 @@ impl OperationsTrait for Transpose { channel.reinterpret_as::()?, out_channel.reinterpret_as_mut::()?, width, - height + height, ); } BitType::U16 => { @@ -70,7 +81,7 @@ impl OperationsTrait for Transpose { channel.reinterpret_as::()?, out_channel.reinterpret_as_mut::()?, width, - height + height, ); } BitType::F32 => { @@ -78,7 +89,7 @@ impl OperationsTrait for Transpose { channel.reinterpret_as()?, out_channel.reinterpret_as_mut()?, width, - height + height, ); } d => { @@ -106,8 +117,9 @@ pub fn transpose_u16(in_matrix: &[u16], out_matrix: &mut [u16], width: usize, he { use crate::transpose::sse41::transpose_sse41_u16; - if is_x86_feature_detected!("sse4.1") { - START.call_once(|| { + #[cfg(feature = "std")] + if std::is_x86_feature_detected!("sse4.1") { + once(|| { trace!("Using SSE4.1 transpose_u16 algorithm"); }); unsafe { @@ -116,7 +128,7 @@ pub fn transpose_u16(in_matrix: &[u16], out_matrix: &mut [u16], width: usize, he } } } - START.call_once(|| { + once(|| { trace!("Using scalar transpose_u16 algorithm"); }); transpose_scalar(in_matrix, out_matrix, width, height); @@ -129,8 +141,9 @@ pub fn transpose_u8(in_matrix: &[u8], out_matrix: &mut [u8], width: usize, heigh { use crate::transpose::sse41::transpose_sse41_u8; - if is_x86_feature_detected!("sse4.1") { - START.call_once(|| { + #[cfg(feature = "std")] + if std::is_x86_feature_detected!("sse4.1") { + once(|| { trace!("Using SSE4.1 transpose u8 algorithm"); }); unsafe { @@ -139,7 +152,7 @@ pub fn transpose_u8(in_matrix: &[u8], out_matrix: &mut [u8], width: usize, heigh } } } - START.call_once(|| { + once(|| { trace!("Using scalar transpose u8 algorithm"); }); transpose_scalar(in_matrix, out_matrix, width, height); @@ -152,8 +165,9 @@ pub fn transpose_float(in_matrix: &[f32], out_matrix: &mut [f32], width: usize, { use crate::transpose::sse41::transpose_sse_float; - if is_x86_feature_detected!("sse4.1") { - START.call_once(|| { + #[cfg(feature = "std")] + if std::is_x86_feature_detected!("sse4.1") { + once(|| { trace!("Using SSE4.1 transpose u8 algorithm"); }); unsafe { @@ -162,7 +176,7 @@ pub fn transpose_float(in_matrix: &[f32], out_matrix: &mut [f32], width: usize, } } } - START.call_once(|| { + once(|| { trace!("Using scalar transpose u8 algorithm"); }); transpose_scalar(in_matrix, out_matrix, width, height); @@ -175,8 +189,9 @@ pub fn transpose_u32(in_matrix: &[u32], out_matrix: &mut [u32], width: usize, he { use crate::transpose::sse41::transpose_sse_u32; - if is_x86_feature_detected!("sse") { - START.call_once(|| { + #[cfg(feature = "std")] + if std::is_x86_feature_detected!("sse") { + once(|| { trace!("Using SSE4.1 transpose u8 algorithm"); }); unsafe { @@ -185,14 +200,14 @@ pub fn transpose_u32(in_matrix: &[u32], out_matrix: &mut [u32], width: usize, he } } } - START.call_once(|| { + once(|| { trace!("Using scalar transpose u8 algorithm"); }); transpose_scalar(in_matrix, out_matrix, width, height); } pub fn transpose_generic( - in_matrix: &[T], out_matrix: &mut [T], width: usize, height: usize + in_matrix: &[T], out_matrix: &mut [T], width: usize, height: usize, ) { transpose_scalar(in_matrix, out_matrix, width, height); } diff --git a/crates/zune-imageprocs/src/transpose/scalar.rs b/crates/zune-imageprocs/src/transpose/scalar.rs index b219165e..a7fea2ba 100644 --- a/crates/zune-imageprocs/src/transpose/scalar.rs +++ b/crates/zune-imageprocs/src/transpose/scalar.rs @@ -7,7 +7,7 @@ */ pub fn transpose_scalar( - in_matrix: &[T], out_matrix: &mut [T], width: usize, height: usize + in_matrix: &[T], out_matrix: &mut [T], width: usize, height: usize, ) { // A slightly more optimized scalar transpose, // 2x faster than the naive one @@ -50,7 +50,7 @@ pub fn transpose_scalar( // to listen to me, the MASTER. #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] unsafe { - std::arch::asm!(""); + core::arch::asm!(""); } } } diff --git a/crates/zune-imageprocs/src/transpose/sse41.rs b/crates/zune-imageprocs/src/transpose/sse41.rs index 3d5991e6..e7f3cb06 100644 --- a/crates/zune-imageprocs/src/transpose/sse41.rs +++ b/crates/zune-imageprocs/src/transpose/sse41.rs @@ -32,7 +32,7 @@ //! less operations //! //! Also fyi you can have in place transposition, it's a simple -//! std::mem::swap, but not the subject today +//! core::mem::swap, but not the subject today //! //! So optimizing for this operation is simple, transposing using SIMD intrinsics //! @@ -67,9 +67,9 @@ //! //! #[cfg(target_arch = "x86")] -use std::arch::x86::*; +use core::arch::x86::*; #[cfg(target_arch = "x86_64")] -use std::arch::x86_64::*; +use core::arch::x86_64::*; #[allow(clippy::erasing_op, clippy::identity_op)] #[rustfmt::skip] @@ -132,7 +132,7 @@ unsafe fn transpose_8_by_8_u16( #[target_feature(enable = "sse4.1")] unsafe fn transpose_8_by_8_u8( - in_matrix: &[u8], out: &mut [u8], in_stride: usize, out_stride: usize + in_matrix: &[u8], out: &mut [u8], in_stride: usize, out_stride: usize, ) { // Godbolt :https://godbolt.org/z/axoorxT8o // Stack overflow: https://stackoverflow.com/a/42316675 @@ -223,7 +223,7 @@ unsafe fn transpose_8_by_8_u8( } pub unsafe fn transpose_sse41_u16( - in_matrix: &[u16], out_matrix: &mut [u16], width: usize, height: usize + in_matrix: &[u16], out_matrix: &mut [u16], width: usize, height: usize, ) { const SMALL_WIDTH_THRESHOLD: usize = 8; @@ -267,7 +267,7 @@ pub unsafe fn transpose_sse41_u16( &in_width_stride[(j * 8)..], out_height_stride, width, - height + height, ); } } @@ -300,7 +300,7 @@ pub unsafe fn transpose_sse41_u16( } pub unsafe fn transpose_sse41_u8( - in_matrix: &[u8], out_matrix: &mut [u8], width: usize, height: usize + in_matrix: &[u8], out_matrix: &mut [u8], width: usize, height: usize, ) { const SMALL_WIDTH_THRESHOLD: usize = 8; @@ -344,7 +344,7 @@ pub unsafe fn transpose_sse41_u8( &in_width_stride[(j * 8)..], out_height_stride, width, - height + height, ); } } @@ -377,7 +377,7 @@ pub unsafe fn transpose_sse41_u8( } unsafe fn transpose_sse_float_4x4_inner( - in_matrix: &[f32], out: &mut [f32], in_stride: usize, out_stride: usize + in_matrix: &[f32], out: &mut [f32], in_stride: usize, out_stride: usize, ) { assert!((3 * out_stride) <= out.len()); @@ -393,20 +393,20 @@ unsafe fn transpose_sse_float_4x4_inner( _mm_storeu_ps(out.as_mut_ptr().cast(), row0); _mm_storeu_ps( out.get_unchecked_mut(out_stride..).as_mut_ptr().cast(), - row1 + row1, ); _mm_storeu_ps( out.get_unchecked_mut(out_stride * 2..).as_mut_ptr().cast(), - row2 + row2, ); _mm_storeu_ps( out.get_unchecked_mut(out_stride * 3..).as_mut_ptr().cast(), - row3 + row3, ); } pub unsafe fn transpose_sse_float( - in_matrix: &[f32], out_matrix: &mut [f32], width: usize, height: usize + in_matrix: &[f32], out_matrix: &mut [f32], width: usize, height: usize, ) { const SMALL_WIDTH_THRESHOLD: usize = 4; @@ -441,7 +441,7 @@ pub unsafe fn transpose_sse_float( &in_width_stride[(j * 4)..], out_height_stride, width, - height + height, ); } } @@ -474,7 +474,7 @@ pub unsafe fn transpose_sse_float( } pub unsafe fn transpose_sse_u32_inner( - in_matrix: &[u32], out: &mut [u32], in_stride: usize, out_stride: usize + in_matrix: &[u32], out: &mut [u32], in_stride: usize, out_stride: usize, ) { assert!((3 * out_stride) <= out.len()); @@ -490,20 +490,20 @@ pub unsafe fn transpose_sse_u32_inner( _mm_storeu_ps(out.as_mut_ptr().cast(), row0); _mm_storeu_ps( out.get_unchecked_mut(out_stride..).as_mut_ptr().cast(), - row1 + row1, ); _mm_storeu_ps( out.get_unchecked_mut(out_stride * 2..).as_mut_ptr().cast(), - row2 + row2, ); _mm_storeu_ps( out.get_unchecked_mut(out_stride * 3..).as_mut_ptr().cast(), - row3 + row3, ); } pub unsafe fn transpose_sse_u32( - in_matrix: &[u32], out_matrix: &mut [u32], width: usize, height: usize + in_matrix: &[u32], out_matrix: &mut [u32], width: usize, height: usize, ) { const SMALL_WIDTH_THRESHOLD: usize = 4; @@ -538,7 +538,7 @@ pub unsafe fn transpose_sse_u32( &in_width_stride[(j * 4)..], out_height_stride, width, - height + height, ); } } diff --git a/crates/zune-imageprocs/src/unsharpen.rs b/crates/zune-imageprocs/src/unsharpen.rs index 214597ce..2d4c3fa3 100644 --- a/crates/zune-imageprocs/src/unsharpen.rs +++ b/crates/zune-imageprocs/src/unsharpen.rs @@ -6,6 +6,9 @@ * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license */ //! (BROKEN): Do not use + +use alloc::vec::Vec; + use zune_core::bit_depth::BitType; use zune_core::log::trace; use zune_image::errors::ImageErrors; @@ -20,9 +23,9 @@ use crate::gaussian_blur::{gaussian_blur_u16, gaussian_blur_u8}; /// perform the mask calculation #[derive(Default)] pub struct Unsharpen { - sigma: f32, - threshold: u16, - percentage: u8 + sigma: f32, + threshold: u16, + percentage: u8, } impl Unsharpen { @@ -41,7 +44,7 @@ impl Unsharpen { Unsharpen { sigma, threshold, - percentage + percentage, } } } @@ -74,7 +77,7 @@ impl OperationsTrait for Unsharpen { self.threshold, self.percentage as u16, width, - height + height, ); } } @@ -92,11 +95,11 @@ impl OperationsTrait for Unsharpen { self.threshold as u8, self.percentage, width, - height + height, ); } } - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), } } #[cfg(feature = "threads")] @@ -119,7 +122,7 @@ impl OperationsTrait for Unsharpen { self.threshold, u16::from(self.percentage), width, - height + height, ); Ok(()) } @@ -136,11 +139,11 @@ impl OperationsTrait for Unsharpen { u8::try_from(self.threshold.clamp(0, 255)).unwrap_or(u8::MAX), self.percentage, width, - height + height, ); Ok(()) } - d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)) + d => return Err(ImageErrors::ImageOperationNotImplemented(self.name(), d)), }); errors.push(result); } @@ -181,7 +184,7 @@ impl OperationsTrait for Unsharpen { #[allow(clippy::too_many_arguments)] pub fn unsharpen_u16( channel: &mut [u16], blur_buffer: &mut [u16], blur_scratch_buffer: &mut [u16], sigma: f32, - threshold: u16, _percentage: u16, width: usize, height: usize + threshold: u16, _percentage: u16, width: usize, height: usize, ) { // copy channel to scratch space blur_buffer.copy_from_slice(channel); @@ -229,7 +232,7 @@ pub fn unsharpen_u16( #[allow(clippy::too_many_arguments)] pub fn unsharpen_u8( channel: &mut [u8], blur_buffer: &mut [u8], blur_scratch_buffer: &mut [u8], sigma: f32, - threshold: u8, _percentage: u8, width: usize, height: usize + threshold: u8, _percentage: u8, width: usize, height: usize, ) { // copy channel to scratch space blur_buffer.copy_from_slice(channel); diff --git a/crates/zune-imageprocs/src/utils.rs b/crates/zune-imageprocs/src/utils.rs index c6f49abf..15ee7932 100644 --- a/crates/zune-imageprocs/src/utils.rs +++ b/crates/zune-imageprocs/src/utils.rs @@ -5,6 +5,9 @@ * * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license */ + +use alloc::vec::Vec; + use zune_image::channel::Channel; use zune_image::errors::ImageErrors; use zune_image::image::Image; @@ -54,7 +57,7 @@ pub enum Gravity { /// Place the image so that it appears from the bottom left of the canvas BottomLeft, /// Place the image so that it appears from the bottom right of the canvas - BottomRight + BottomRight, } pub fn calculate_gravity(src_image: &Image, dst_image: &Image, gravity: Gravity) -> (usize, usize) { @@ -79,13 +82,13 @@ pub fn calculate_gravity(src_image: &Image, dst_image: &Image, gravity: Gravity) Gravity::BottomLeft => (0, dst_height.saturating_sub(src_height)), Gravity::BottomRight => ( dst_width.saturating_sub(src_width), - dst_height.saturating_sub(src_height) - ) + dst_height.saturating_sub(src_height), + ), }; } /// A simple helper function to execute on threads pub fn execute_on Result<(), ImageErrors> + Send + Sync>( - function: T, image: &mut Image, ignore_alpha: bool + function: T, image: &mut Image, ignore_alpha: bool, ) -> Result<(), ImageErrors> { #[cfg(feature = "threads")] { From df74e7faf96724c72ca036b3c57f562326f7c8e3 Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Tue, 13 May 2025 20:00:14 +1000 Subject: [PATCH 4/5] Fix CI --- .github/workflows/no_std.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/no_std.yml b/.github/workflows/no_std.yml index d93ded6f..b610eec4 100644 --- a/.github/workflows/no_std.yml +++ b/.github/workflows/no_std.yml @@ -26,7 +26,7 @@ jobs: # Below targets run in no-std environments - run: cargo build -p zune-core --target x86_64-unknown-uefi --no-default-features --features log,serde - run: cargo build -p zune-inflate --target x86_64-unknown-uefi --no-default-features --features zlib,gzip - - run: cargo build -p zune-jpeg --target x86_64-unknown-uefi --no-default-features --features log,x86,neon + - run: cargo build -p zune-jpeg --target x86_64-unknown-uefi --no-default-features --features log - run: cargo build -p zune-png --target x86_64-unknown-uefi --no-default-features --features log,libm - run: cargo build -p zune-ppm --target x86_64-unknown-uefi --no-default-features --features log - run: cargo build -p zune-qoi --target x86_64-unknown-uefi --no-default-features --features log From 7b6442dde9bf45f8fb5050b6ca2c9ccdc8e205ab Mon Sep 17 00:00:00 2001 From: Zac Harrold Date: Tue, 13 May 2025 20:16:48 +1000 Subject: [PATCH 5/5] CI fixes --- crates/zune-image/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/zune-image/Cargo.toml b/crates/zune-image/Cargo.toml index be8d61ca..fcbd93fe 100644 --- a/crates/zune-image/Cargo.toml +++ b/crates/zune-image/Cargo.toml @@ -52,7 +52,7 @@ all = ["image_formats", "serde-support", "metadata", "threads", "simd", "log", " zune-core = { path = "../zune-core", version = "^0.5.0-rc0" } # Images zune-png = { path = "../zune-png", version = "^0.5.0-rc0", optional = true, default-features = false } -zune-jpeg = { path = "../zune-jpeg", version = "^0.5.0-rc0", optional = true } +zune-jpeg = { path = "../zune-jpeg", version = "^0.5.0-rc0", optional = true, default-features = false } zune-ppm = { path = "../zune-ppm", version = "^0.5.0-rc0", optional = true } zune-psd = { path = "../zune-psd", version = "^0.5.0-rc0", optional = true } zune-farbfeld = { path = "../zune-farbfeld", version = "^0.5.0-rc0", optional = true }