Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
a688fee
Increase MSRV to 1.81
bushrat011899 May 8, 2025
8638a7b
Isolate a specific `std` feature
bushrat011899 May 8, 2025
18c5474
Added `libm` feature
bushrat011899 May 8, 2025
c84e905
Implement `no_std` support
bushrat011899 May 8, 2025
4f77832
Add Clippy lints for easier `no_std` maintenance
bushrat011899 May 8, 2025
8449f87
Respond to Clippy lints
bushrat011899 May 8, 2025
71d362a
Add `no_std` CI task
bushrat011899 May 8, 2025
112b846
Formatting
bushrat011899 May 8, 2025
a68e050
`dead_code`
bushrat011899 May 8, 2025
dbd5467
Leave `std` prelude for tests
bushrat011899 May 8, 2025
fefc0a3
Don't test without `std`
bushrat011899 May 8, 2025
a4f65ef
Bumped `image` to `0.26.0` for Sematic-Versioning
bushrat011899 May 8, 2025
46e026f
Fixed `avif` Clippy
bushrat011899 May 8, 2025
be6da92
Revert "Bumped `image` to `0.26.0` for Sematic-Versioning"
bushrat011899 May 8, 2025
9e5048a
Nightly Lints
bushrat011899 May 8, 2025
8712e32
Ensure `num-bigint` is at-least 0.4.2 to avoid `div_ceil` bug
bushrat011899 May 8, 2025
cfbd058
Bump major version
bushrat011899 May 8, 2025
1546c2c
Fix missing `f32`/`f64` ops
bushrat011899 May 9, 2025
a32ba19
`no_std` metadata.rs
bushrat011899 May 9, 2025
216db04
`no_std` `load_rect`
bushrat011899 May 9, 2025
05874ec
Add `no_std` alternative to `ImageFormat::from_extension`
bushrat011899 May 9, 2025
9b1160b
`no_std` `ImageReader`
bushrat011899 May 9, 2025
0746245
Fix `load_rect`
bushrat011899 May 9, 2025
bfee6a8
`no_std` TGA
bushrat011899 May 10, 2025
93ec7fa
`no_std` Qoi
bushrat011899 May 10, 2025
3f5714b
`no_std` BMP
bushrat011899 May 10, 2025
15281b4
`no_std` DDS
bushrat011899 May 10, 2025
e1cbdcd
Allow `color_quant` in `no_std`
bushrat011899 May 10, 2025
519a803
Update CI
bushrat011899 May 10, 2025
1161d27
`no_std` Farbfeld
bushrat011899 May 10, 2025
5754ac5
`no_std` HDR
bushrat011899 May 10, 2025
d554519
`no_std` PNM
bushrat011899 May 10, 2025
d7270fe
AutoBreak
bushrat011899 May 10, 2025
77f7991
Ensure `std` is active for tests
bushrat011899 May 10, 2025
d5facae
fmt
bushrat011899 May 10, 2025
30faf2b
Clippy
bushrat011899 May 12, 2025
b8311aa
Clippy
bushrat011899 May 12, 2025
a576e4b
Organise imports to reduce `std` gates
bushrat011899 May 12, 2025
ade419a
Proof of Concept for `no_std` in Qoi
bushrat011899 May 12, 2025
dfc76ca
Clippy
bushrat011899 May 12, 2025
36213e1
Avoid public/private
bushrat011899 May 12, 2025
c0f3e8d
Clippy
bushrat011899 May 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
strategy:
fail-fast: false
matrix:
features: ['', default, rayon, avif, bmp, dds, exr, ff, gif, hdr, ico, jpeg, png, pnm, qoi, tga, tiff, webp]
features: ["", default, rayon, avif, bmp, dds, exr, ff, gif, hdr, ico, jpeg, png, pnm, qoi, tga, tiff, webp]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
Expand All @@ -28,8 +28,8 @@ jobs:
FEATURES: ${{ matrix.features }}
- name: test
run: >
cargo test -v --no-default-features --features "$FEATURES" &&
cargo doc -v --no-default-features --features "$FEATURES"
cargo test -v --no-default-features --features "$FEATURES" --features std &&
cargo doc -v --no-default-features --features "$FEATURES" --features std
env:
FEATURES: ${{ matrix.features }}

Expand All @@ -38,14 +38,14 @@ jobs:
strategy:
fail-fast: false
matrix:
rust: ["1.70.0", nightly, beta]
rust: ["1.81.0", nightly, beta]
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@nightly
if: ${{ matrix.rust == '1.70.0' }}
if: ${{ matrix.rust == '1.81.0' }}
- name: Generate Cargo.lock with minimal-version dependencies
if: ${{ matrix.rust == '1.70.0' }}
if: ${{ matrix.rust == '1.81.0' }}
run: cargo -Zminimal-versions generate-lockfile

- uses: dtolnay/rust-toolchain@v1
Expand All @@ -58,7 +58,7 @@ jobs:
- name: build
run: cargo build -v
- name: test
if: ${{ matrix.rust != '1.70.0' }}
if: ${{ matrix.rust != '1.81.0' }}
run: cargo test -v && cargo doc -v

test_other_archs:
Expand Down Expand Up @@ -207,3 +207,15 @@ jobs:
with:
feature-group: default-features
release-type: minor

clippy_no_std:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
targets: "wasm32v1-none"
- run: cargo clippy --no-default-features --target wasm32v1-none --features serde,libm,tga,qoi,bmp,dds,ff,hdr,pnm -- -D warnings
env:
SYSTEM_DEPS_DAV1D_BUILD_INTERNAL: always
45 changes: 25 additions & 20 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
[package]
name = "image"
version = "0.25.6"
version = "0.26.0"
edition = "2021"
resolver = "2"

# note: when changed, also update test runner in `.github/workflows/rust.yml`
rust-version = "1.70.0"
rust-version = "1.81.0"

license = "MIT OR Apache-2.0"
description = "Imaging library. Provides basic image processing and encoders/decoders for common image formats."
Expand Down Expand Up @@ -36,25 +36,28 @@ rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
bytemuck = { version = "1.8.0", features = ["extern_crate_alloc"] } # includes cast_vec
byteorder-lite = "0.1.0"
num-traits = { version = "0.2.0" }
byteorder-lite = { version = "0.1.0", default-features = false }
num-traits = { version = "0.2.0", default-features = false }

# Optional dependencies
color_quant = { version = "1.1", optional = true }
dav1d = { version = "0.10.3", optional = true }
dav1d = { version = "0.10.4", optional = true }
exr = { version = "1.5.0", optional = true }
gif = { version = "0.13.1", optional = true }
image-webp = { version = "0.2.0", optional = true }
mp4parse = { version = "0.17.0", optional = true }
png = { version = "0.17.11", optional = true }
qoi = { version = "0.4", optional = true }
qoi = { version = "0.4", default-features = false, optional = true, features = ["alloc"] }
ravif = { version = "0.11.12", default-features = false, optional = true }
rayon = { version = "1.7.0", optional = true }
rgb = { version = "0.8.48", default-features = false, optional = true }
tiff = { version = "0.9.0", optional = true }
zune-core = { version = "0.4.12", default-features = false, optional = true }
zune-jpeg = { version = "0.4.13", optional = true }
serde = { version = "1.0.214", optional = true, features = ["derive"] }
serde = { version = "1.0.214", default-features = false, optional = true, features = ["derive"] }

# Patches
num-bigint = { version = "0.4.2", default-features = false, optional = true }

[dev-dependencies]
crc32fast = "1.2.0"
Expand All @@ -64,33 +67,35 @@ quickcheck = "1"
criterion = "0.5.0"

[features]
default = ["rayon", "default-formats"]
default = ["std", "rayon", "default-formats"]

# Format features
default-formats = ["avif", "bmp", "dds", "exr", "ff", "gif", "hdr", "ico", "jpeg", "png", "pnm", "qoi", "tga", "tiff", "webp"]
avif = ["dep:ravif", "dep:rgb"]
avif = ["dep:ravif", "dep:rgb", "std", "dep:num-bigint"]
bmp = []
dds = []
exr = ["dep:exr"]
exr = ["dep:exr", "std"]
ff = [] # Farbfeld image format
gif = ["dep:gif", "dep:color_quant"]
gif = ["dep:gif", "dep:color_quant", "std"]
hdr = []
ico = ["bmp", "png"]
jpeg = ["dep:zune-core", "dep:zune-jpeg"]
png = ["dep:png"]
ico = ["bmp", "png", "std"]
jpeg = ["dep:zune-core", "dep:zune-jpeg", "std"]
png = ["dep:png", "std"]
pnm = []
qoi = ["dep:qoi"]
tga = []
tiff = ["dep:tiff"]
webp = ["dep:image-webp"]
tiff = ["dep:tiff", "std"]
webp = ["dep:image-webp", "std"]

# Other features
rayon = ["dep:rayon", "ravif?/threading"] # Enables multi-threading
nasm = ["ravif?/asm"] # Enables use of nasm by rav1e (requires nasm to be installed)
rayon = ["dep:rayon", "ravif?/threading", "std"] # Enables multi-threading
nasm = ["ravif?/asm", "std"] # Enables use of nasm by rav1e (requires nasm to be installed)
color_quant = ["dep:color_quant"] # Enables color quantization
avif-native = ["dep:mp4parse", "dep:dav1d"] # Enable native dependency libdav1d
benchmarks = [] # Build some inline benchmarks. Useful only during development (requires nightly Rust)
avif-native = ["dep:mp4parse", "dep:dav1d", "std", "dep:num-bigint"] # Enable native dependency libdav1d
benchmarks = ["std"] # Build some inline benchmarks. Useful only during development (requires nightly Rust)
serde = ["dep:serde"]
std = ["byteorder-lite/std", "num-traits/std", "qoi?/std"]
libm = ["num-traits/libm"]

[[bench]]
path = "benches/decode.rs"
Expand Down
2 changes: 1 addition & 1 deletion benches/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type BenchGroup<'a> = criterion::BenchmarkGroup<'a, criterion::measurement::Wall
/// For compressed formats this is surely not representative of encoding a normal image but it's a
/// start for benchmarking.
fn encode_zeroed(group: &mut BenchGroup, with: &dyn Encoder, size: u32, color: ExtendedColorType) {
let im = vec![0; (color.bits_per_pixel() as usize * size as usize + 7) / 8 * size as usize];
let im = vec![0; (color.bits_per_pixel() as usize * size as usize).div_ceil(8) * size as usize];

group.bench_with_input(
BenchmarkId::new(format!("zero-{color:?}-rawvec"), size),
Expand Down
10 changes: 6 additions & 4 deletions src/animation.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::cmp::Ordering;
use std::time::Duration;
use alloc::boxed::Box;
use alloc::vec::Vec;
use core::cmp::Ordering;
use core::time::Duration;

use crate::error::ImageResult;
use crate::RgbaImage;
Expand Down Expand Up @@ -152,7 +154,7 @@ impl Delay {
/// # Examples
///
/// ```
/// use std::time::Duration;
/// use core::time::Duration;
/// use image::Delay;
///
/// let duration = Duration::from_millis(20);
Expand Down Expand Up @@ -206,7 +208,7 @@ impl Delay {
/// Note that `denom_bound` bounds nominator and denominator of all intermediate
/// approximations and the end result.
fn closest_bounded_fraction(denom_bound: u32, nom: u32, denom: u32) -> (u32, u32) {
use std::cmp::Ordering::*;
use core::cmp::Ordering::*;
assert!(0 < denom);
assert!(0 < denom_bound);
assert!(nom < denom);
Expand Down
28 changes: 20 additions & 8 deletions src/buffer.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
//! Contains the generic `ImageBuffer` struct.
use alloc::vec;
use alloc::vec::Vec;
use core::fmt;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut, Index, IndexMut, Range};
use core::slice::{ChunksExact, ChunksExactMut};
use num_traits::Zero;
use std::fmt;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut, Index, IndexMut, Range};
use std::path::Path;
use std::slice::{ChunksExact, ChunksExactMut};

use crate::color::{FromColor, Luma, LumaA, Rgb, Rgba};
use crate::dynimage::{save_buffer, save_buffer_with_format, write_buffer_with_format};
use crate::error::ImageResult;
use crate::flat::{FlatSamples, SampleLayout};
use crate::image::{GenericImage, GenericImageView, ImageEncoder, ImageFormat};
use crate::image::{GenericImage, GenericImageView, ImageEncoder};
use crate::math::Rect;
use crate::traits::{EncodableLayout, Pixel, PixelWithColorType};
use crate::utils::expand_packed;
use crate::DynamicImage;

#[cfg_attr(not(feature = "std"), expect(unused_imports))]
use crate::image::ImageFormat;

#[cfg(feature = "std")]
use {
crate::dynimage::{save_buffer, save_buffer_with_format, write_buffer_with_format},
std::path::Path,
};

/// Iterate over pixel refs.
pub struct Pixels<'a, P: Pixel + 'a>
where
Expand Down Expand Up @@ -993,6 +1002,7 @@ where
/// Saves the buffer to a file at the path specified.
///
/// The image format is derived from the file extension.
#[cfg(feature = "std")]
pub fn save<Q>(&self, path: Q) -> ImageResult<()>
where
Q: AsRef<Path>,
Expand All @@ -1019,6 +1029,7 @@ where
///
/// See [`save_buffer_with_format`](fn.save_buffer_with_format.html) for
/// supported types.
#[cfg(feature = "std")]
pub fn save_with_format<Q>(&self, path: Q, format: ImageFormat) -> ImageResult<()>
where
Q: AsRef<Path>,
Expand Down Expand Up @@ -1046,6 +1057,7 @@ where
///
/// Assumes the writer is buffered. In most cases, you should wrap your writer in a `BufWriter`
/// for best performance.
#[cfg(feature = "std")]
pub fn write_to<W>(&self, writer: &mut W, format: ImageFormat) -> ImageResult<()>
where
W: std::io::Write + std::io::Seek,
Expand Down Expand Up @@ -1715,7 +1727,7 @@ mod test {

#[test]
fn exact_size_iter_size_hint() {
// The docs for `std::iter::ExactSizeIterator` requires that the implementation of
// The docs for `core::iter::ExactSizeIterator` requires that the implementation of
// `size_hint` on the iterator returns the same value as the `len` implementation.

// This test should work for any size image.
Expand Down
11 changes: 6 additions & 5 deletions src/buffer_par.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use alloc::vec::Vec;
use core::fmt;
use core::ops::{Deref, DerefMut};
use rayon::iter::plumbing::*;
use rayon::iter::{IndexedParallelIterator, ParallelIterator};
use rayon::slice::{ChunksExact, ChunksExactMut, ParallelSlice, ParallelSliceMut};
use std::fmt;
use std::ops::{Deref, DerefMut};

use crate::traits::Pixel;
use crate::ImageBuffer;
Expand Down Expand Up @@ -430,7 +431,7 @@ mod test {
#[test]
fn iter_parity() {
let mut image1 = RgbImage::from_fn(17, 29, |x, y| {
Rgb(std::array::from_fn(|i| {
Rgb(core::array::from_fn(|i| {
((x + y * 98 + i as u32 * 27) % 255) as u8
}))
});
Expand Down Expand Up @@ -487,9 +488,9 @@ mod benchmarks {
}

fn pixel_func() -> Rgb<u8> {
use core::hash::{BuildHasher, Hasher};
use std::collections::hash_map::RandomState;
use std::hash::{BuildHasher, Hasher};
Rgb(std::array::from_fn(|_| {
Rgb(core::array::from_fn(|_| {
RandomState::new().build_hasher().finish() as u8
}))
}
Expand Down
Loading
Loading