diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d0a5d10064..58f78256fe 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,9 +2,10 @@ name: Rust CI on: push: - branches: [ master, next ] - pull_request: - branches: [ master, next ] + # TODO(interstellar) revert + # branches: [ master, next ] + # pull_request: + # branches: [ master, next ] jobs: build: @@ -13,7 +14,7 @@ jobs: strategy: matrix: rust: ["1.61.0", stable, beta, nightly] - features: [gif, jpeg, png, tiff, ico, pnm, tga, webp, bmp, hdr, dxt, dds, farbfeld, openexr, jpeg_rayon, webp-encoder, ''] + features: [gif, jpeg, png, tiff, ico, pnm, tga, webp, bmp, hdr, dxt, dds, farbfeld, openexr, jpeg_rayon, webp-encoder, std] steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 @@ -45,7 +46,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - features: [gif, jpeg, png, tiff, ico, pnm, tga, webp, bmp, hdr, dxt, dds, farbfeld, openexr, jpeg_rayon, webp-encoder, ''] + features: [gif, jpeg, png, tiff, ico, pnm, tga, webp, bmp, hdr, dxt, dds, farbfeld, openexr, jpeg_rayon, webp-encoder, std] # we are using the cross project for cross compilation to mips: # https://github.com/cross-rs/cross @@ -120,6 +121,19 @@ jobs: env: SYSTEM_DEPS_DAV1D_BUILD_INTERNAL: always + no_std_check: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + override: true + - name: build + run: | + cargo install cargo-no-std-check + cargo no-std-check --no-default-features --features=alloc + clippy: runs-on: ubuntu-20.04 steps: diff --git a/Cargo.toml b/Cargo.toml index bdd35bc862..684dc23c3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,10 +31,10 @@ path = "./src/lib.rs" [dependencies] bytemuck = { version = "1.7.0", features = ["extern_crate_alloc"] } # includes cast_vec -byteorder = "1.3.2" +byteorder = { version = "1.3.2", default-features = false } num-rational = { version = "0.4", default-features = false } -num-traits = "0.2.0" -gif = { version = "0.12", optional = true } +num-traits = { version = "0.2", default-features = false } +gif = { version = "0.12", optional = true, default-features = false } jpeg = { package = "jpeg-decoder", version = "0.3.0", default-features = false, optional = true } png = { version = "0.17.6", optional = true } scoped_threadpool = { version = "0.1", optional = true } @@ -44,7 +44,9 @@ rgb = { version = "0.8.25", optional = true } mp4parse = { version = "0.12.0", optional = true } dav1d = { version = "0.6.0", optional = true } dcv-color-primitives = { version = "0.4.0", optional = true } -color_quant = "1.1" +# TODO(interstellar) no_std not supported on crate.io; need a fork/patch +# NOTE: also an optional dependency of "gif" +color_quant = { version = "1.1", git = "https://github.com/Interstellar-Network/color_quant.git", branch = "sgx-nostd-compat", default-features = false, optional = true } exr = { version = "1.5.0", optional = true } qoi = { version = "0.4", optional = true } libwebp = { package = "webp", version = "0.2.2", default-features = false, optional = true } @@ -61,38 +63,47 @@ jpeg = { package = "jpeg-decoder", version = "0.3.0", default-features = false, [features] # TODO: Add "avif" to this list while preparing for 0.24.0 -default = ["gif", "jpeg", "ico", "png", "pnm", "tga", "tiff", "webp", "bmp", "hdr", "dxt", "dds", "farbfeld", "jpeg_rayon", "openexr", "qoi"] - -ico = ["bmp", "png"] -pnm = [] -tga = [] -bmp = [] -hdr = ["scoped_threadpool"] -dxt = [] +default = ["std", "gif", "jpeg", "ico", "png", "pnm", "tga", "tiff", "webp", "bmp", "hdr", "dxt", "dds", "farbfeld", "jpeg_rayon", "openexr", "qoi"] + +# MUST always compile with either "std" or "alloc" +# TODO(interstellar) add compile error in case of neither? +std = ["num-traits/std", "byteorder/std", "color_quant/std"] +alloc = ["num-traits/libm", "color_quant/num-traits"] + +gif = ["std", "gif/default"] +jpeg = ["std", "dep:jpeg"] +png = ["std", "dep:png"] +tiff = ["std", "dep:tiff"] +ico = ["std", "bmp", "png"] +pnm = ["std"] +tga = ["std"] +bmp = ["std"] +hdr = ["std", "scoped_threadpool"] +dxt = ["std"] dds = ["dxt"] -farbfeld = [] -openexr = ["exr"] -qoi = ["dep:qoi"] +farbfeld = ["std"] +openexr = ["std", "exr"] +qoi = ["std", "dep:qoi"] # Enables WebP decoder support. -webp = [] +webp = ["std"] # Non-default, not included in `webp`. Requires native dependency libwebp. -webp-encoder = ["libwebp"] +webp-encoder = ["std", "libwebp"] # Enables multi-threading. # Requires latest stable Rust. -jpeg_rayon = ["jpeg/rayon"] +jpeg_rayon = ["std", "jpeg/rayon"] # Non-default, enables avif support. # Requires latest stable Rust. -avif = ["avif-encoder"] +avif = ["std", "avif-encoder"] # Requires latest stable Rust and recent nasm (>= 2.14). -avif-encoder = ["ravif", "rgb"] +avif-encoder = ["std", "ravif", "rgb"] # Non-default, even in `avif`. Requires stable Rust and native dependency libdav1d. -avif-decoder = ["mp4parse", "dcv-color-primitives", "dav1d"] +avif-decoder = ["std", "mp4parse", "dcv-color-primitives", "dav1d"] # Build some inline benchmarks. Useful only during development. # Requires rustc nightly for feature test. -benchmarks = [] +benchmarks = ["std"] [[bench]] path = "benches/decode.rs" @@ -107,3 +118,39 @@ harness = false [[bench]] name = "copy_from" harness = false + +[[example]] +name = "tile" +required-features = ["std"] + +[[example]] +name = "fractal" +required-features = ["std"] + +[[example]] +name = "scaleup" +required-features = ["std"] + +[[example]] +name = "concat" +required-features = ["std"] + +[[example]] +name = "gradient" +required-features = ["std"] + +[[example]] +name = "opening" +required-features = ["std"] + +[[example]] +name = "decode" +required-features = ["std"] + +[[example]] +name = "scaledown" +required-features = ["std"] + +[[example]] +name = "convert" +required-features = ["std"] \ No newline at end of file diff --git a/README.md b/README.md index e1a921e9d3..921cf7659b 100644 --- a/README.md +++ b/README.md @@ -18,21 +18,21 @@ All image processing functions provided operate on types that implement the `Gen `image` provides implementations of common image format encoders and decoders. -| Format | Decoding | Encoding | -| ------ | -------- | -------- | -| PNG | All supported color types | Same as decoding | -| JPEG | Baseline and progressive | Baseline JPEG | -| GIF | Yes | Yes | -| BMP | Yes | Rgb8, Rgba8, Gray8, GrayA8 | -| ICO | Yes | Yes | -| TIFF | Baseline(no fax support) + LZW + PackBits | Rgb8, Rgba8, Gray8 | -| WebP | Yes | Rgb8, Rgba8 \* | -| AVIF | Only 8-bit \*\* | Lossy | -| PNM | PBM, PGM, PPM, standard PAM | Yes | -| DDS | DXT1, DXT3, DXT5 | No | -| TGA | Yes | Rgb8, Rgba8, Bgr8, Bgra8, Gray8, GrayA8 | -| OpenEXR | Rgb32F, Rgba32F (no dwa compression) | Rgb32F, Rgba32F (no dwa compression) | -| farbfeld | Yes | Yes | +| Format | Decoding | Encoding | +| -------- | ----------------------------------------- | --------------------------------------- | +| PNG | All supported color types | Same as decoding | +| JPEG | Baseline and progressive | Baseline JPEG | +| GIF | Yes | Yes | +| BMP | Yes | Rgb8, Rgba8, Gray8, GrayA8 | +| ICO | Yes | Yes | +| TIFF | Baseline(no fax support) + LZW + PackBits | Rgb8, Rgba8, Gray8 | +| WebP | Yes | Rgb8, Rgba8 \* | +| AVIF | Only 8-bit \*\* | Lossy | +| PNM | PBM, PGM, PPM, standard PAM | Yes | +| DDS | DXT1, DXT3, DXT5 | No | +| TGA | Yes | Rgb8, Rgba8, Bgr8, Bgra8, Gray8, GrayA8 | +| OpenEXR | Rgb32F, Rgba32F (no dwa compression) | Rgb32F, Rgba32F (no dwa compression) | +| farbfeld | Yes | Yes | - \* Requires the `webp-encoder` feature, uses the libwebp C library. - \*\* Requires the `avif-decoder` feature, uses the libdav1d C library. @@ -60,7 +60,7 @@ The most important methods for decoders are... All pixels are parameterised by their component type. ## Images -Individual pixels within images are indexed with (0,0) at the top left corner. +Individual pixels within images are indexed with (0,0) at the top left corner. ### The [`GenericImageView`](https://docs.rs/image/*/image/trait.GenericImageView.html) and [`GenericImage`](https://docs.rs/image/*/image/trait.GenericImage.html) Traits Traits that provide methods for inspecting (`GenericImageView`) and manipulating (`GenericImage`) images, parameterised over the image's pixel type. @@ -166,6 +166,7 @@ reader which offer some more control. ```rust,no_run use image::GenericImageView; +#[cfg(feature = "std")] fn main() { // Use the open function to load an image from a Path. // `open` returns a `DynamicImage` on success. @@ -180,6 +181,8 @@ fn main() { // Write the contents of this image to the Writer in PNG format. img.save("test.png").unwrap(); } +#[cfg(not(feature = "std"))] +fn main() {} ``` ### Generating Fractals @@ -225,6 +228,7 @@ fn main() { } // Save the image as “fractal.png”, the format is deduced from the path + #[cfg(feature = "std")] imgbuf.save("fractal.png").unwrap(); } ``` @@ -242,6 +246,7 @@ fn main() { let buffer: &[u8] = unimplemented!(); // Generate the image data // Save the buffer as "image.png" + #[cfg(feature = "std")] image::save_buffer("image.png", buffer, 800, 600, image::ColorType::Rgb8).unwrap() } ``` diff --git a/src/animation.rs b/src/animation.rs index aad57b4a5d..10ae375d04 100644 --- a/src/animation.rs +++ b/src/animation.rs @@ -1,5 +1,9 @@ -use std::iter::Iterator; -use std::time::Duration; +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::cmp::Ordering::Equal; +use core::cmp::Ordering::Less; +use core::iter::Iterator; +use core::time::Duration; use num_rational::Ratio; @@ -179,7 +183,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::{self, *}; + use core::cmp::Ordering::{self, *}; assert!(0 < denom); assert!(0 < denom_bound); assert!(nom < denom); diff --git a/src/buffer.rs b/src/buffer.rs index 7f79119e4f..9e93138726 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -1,12 +1,13 @@ //! Contains the generic `ImageBuffer` struct. +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}; +#[cfg(feature = "std")] use crate::dynimage::{save_buffer, save_buffer_with_format, write_buffer_with_format}; use crate::error::ImageResult; use crate::flat::{FlatSamples, SampleLayout}; @@ -629,6 +630,7 @@ where /// Overlays an image on top of a larger background raster. /// /// ```no_run +/// # #[cfg(feature = "std")] { /// use image::{GenericImage, GenericImageView, ImageBuffer, open}; /// /// let on_top = open("path/to/some.png").unwrap().into_rgb8(); @@ -641,15 +643,18 @@ where /// }); /// /// image::imageops::overlay(&mut img, &on_top, 128, 128); +/// } /// ``` /// /// Convert an RgbaImage to a GrayImage. /// /// ```no_run +/// # #[cfg(feature = "std")] { /// use image::{open, DynamicImage}; /// /// let rgba = open("path/to/some.png").unwrap().into_rgba8(); /// let gray = DynamicImage::ImageRgba8(rgba).into_luma8(); +/// } /// ``` #[derive(Debug, Hash, PartialEq, Eq)] pub struct ImageBuffer { @@ -979,6 +984,7 @@ where } } +#[cfg(feature = "std")] impl ImageBuffer where P: Pixel, @@ -990,7 +996,7 @@ where /// The image format is derived from the file extension. pub fn save(&self, path: Q) -> ImageResult<()> where - Q: AsRef, + Q: AsRef, P: PixelWithColorType, { save_buffer( @@ -1003,6 +1009,7 @@ where } } +#[cfg(feature = "std")] impl ImageBuffer where P: Pixel, @@ -1016,7 +1023,7 @@ where /// supported types. pub fn save_with_format(&self, path: Q, format: ImageFormat) -> ImageResult<()> where - Q: AsRef, + Q: AsRef, P: PixelWithColorType, { // This is valid as the subpixel is u8. @@ -1031,6 +1038,7 @@ where } } +#[cfg(feature = "std")] impl ImageBuffer where P: Pixel, @@ -1360,11 +1368,13 @@ where /// use image::GrayImage; /// /// let image_path = "examples/fractal.png"; + /// # #[cfg(feature = "std")] { /// let image = image::open(&image_path) /// .expect("Open file failed") /// .to_rgba8(); /// /// let gray_image: GrayImage = image.convert(); + /// } /// ``` fn convert(&self) -> ImageBuffer> { let mut buffer: ImageBuffer> = @@ -1407,6 +1417,7 @@ mod test { use crate::math::Rect; use crate::GenericImage as _; use crate::{color, Rgb}; + use alloc::vec::Vec; #[test] /// Tests if image buffers from slices work diff --git a/src/codecs/tga/encoder.rs b/src/codecs/tga/encoder.rs index cf3498421f..6544f0131e 100644 --- a/src/codecs/tga/encoder.rs +++ b/src/codecs/tga/encoder.rs @@ -101,6 +101,7 @@ impl ImageEncoder for TgaEncoder { mod tests { use super::{EncoderError, TgaEncoder}; use crate::{codecs::tga::TgaDecoder, ColorType, ImageDecoder, ImageError}; + use alloc::vec::Vec; use std::{error::Error, io::Cursor}; fn round_trip_image(image: &[u8], width: u32, height: u32, c: ColorType) -> Vec { diff --git a/src/codecs/webp/extended.rs b/src/codecs/webp/extended.rs index e7aacf9e09..6684baa218 100644 --- a/src/codecs/webp/extended.rs +++ b/src/codecs/webp/extended.rs @@ -1,3 +1,5 @@ +use alloc::boxed::Box; +use alloc::vec::Vec; use std::convert::TryInto; use std::io::{self, Cursor, Error, Read}; use std::{error, fmt}; diff --git a/src/codecs/webp/lossless.rs b/src/codecs/webp/lossless.rs index 7271eda902..a14e63a864 100644 --- a/src/codecs/webp/lossless.rs +++ b/src/codecs/webp/lossless.rs @@ -3,6 +3,7 @@ //! [Lossless spec](https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification) //! +use alloc::vec::Vec; use std::{ convert::TryFrom, convert::TryInto, diff --git a/src/codecs/webp/vp8.rs b/src/codecs/webp/vp8.rs index 334293b99f..a161465a6d 100644 --- a/src/codecs/webp/vp8.rs +++ b/src/codecs/webp/vp8.rs @@ -12,6 +12,8 @@ //! of the VP8 format //! +use alloc::borrow::ToOwned; +use alloc::vec::Vec; use byteorder::{LittleEndian, ReadBytesExt}; use std::convert::TryInto; use std::default::Default; @@ -2579,6 +2581,7 @@ fn predict_bhupred(a: &mut [u8], x0: usize, y0: usize, stride: usize) { #[cfg(test)] mod test { + use alloc::vec::Vec; #[cfg(feature = "benchmarks")] extern crate test; diff --git a/src/color.rs b/src/color.rs index 57a8511f2c..1bde9e3869 100644 --- a/src/color.rs +++ b/src/color.rs @@ -1,9 +1,12 @@ -use std::ops::{Index, IndexMut}; +use core::ops::{Index, IndexMut}; use num_traits::{NumCast, ToPrimitive, Zero}; use crate::traits::{Enlargeable, Pixel, Primitive}; +#[cfg(not(feature = "std"))] +use num_traits::float::FloatCore; + /// An enumeration over supported color types and bit depths #[derive(Copy, PartialEq, Eq, Debug, Clone, Hash)] #[non_exhaustive] diff --git a/src/dynimage.rs b/src/dynimage.rs index 3e0aeec6b9..1ab93b400b 100644 --- a/src/dynimage.rs +++ b/src/dynimage.rs @@ -1,7 +1,13 @@ +use alloc::borrow::ToOwned; +use alloc::vec::Vec; +use core::u32; + +#[cfg(feature = "std")] use std::io; +#[cfg(feature = "std")] use std::io::{Seek, Write}; +#[cfg(feature = "std")] use std::path::Path; -use std::u32; #[cfg(feature = "gif")] use crate::codecs::gif; @@ -19,16 +25,18 @@ use crate::error::{ImageError, ImageResult, ParameterError, ParameterErrorKind}; // FIXME: These imports exist because we don't support all of our own color types. use crate::error::{ImageFormatHint, UnsupportedError, UnsupportedErrorKind}; use crate::flat::FlatSamples; -use crate::image::{ - GenericImage, GenericImageView, ImageDecoder, ImageEncoder, ImageFormat, ImageOutputFormat, -}; +use crate::image::{GenericImage, GenericImageView, ImageEncoder, ImageFormat, ImageOutputFormat}; use crate::imageops; -use crate::io::free_functions; use crate::math::resize_dimensions; use crate::traits::Pixel; use crate::{image, Luma, LumaA}; use crate::{Rgb32FImage, Rgba32FImage}; +#[cfg(feature = "std")] +use crate::image::ImageDecoder; +#[cfg(feature = "std")] +use crate::io::free_functions; + /// A Dynamic Image /// /// This represents a _matrix_ of _pixels_ which are _convertible_ from and to an _RGBA_ @@ -173,6 +181,7 @@ impl DynamicImage { } /// Decodes an encoded image into a dynamic image. + #[cfg(feature = "std")] pub fn from_decoder<'a>(decoder: impl ImageDecoder<'a>) -> ImageResult { decoder_to_image(decoder) } @@ -811,6 +820,7 @@ impl DynamicImage { /// /// 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>( &self, w: &mut W, @@ -859,6 +869,7 @@ impl DynamicImage { /// 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(&self, path: Q) -> ImageResult<()> where Q: AsRef, @@ -871,6 +882,7 @@ impl DynamicImage { /// /// See [`save_buffer_with_format`](fn.save_buffer_with_format.html) for /// supported types. + #[cfg(feature = "std")] pub fn save_with_format(&self, path: Q, format: ImageFormat) -> ImageResult<()> where Q: AsRef, @@ -1021,6 +1033,7 @@ impl Default for DynamicImage { } /// Decodes an image and stores it into a dynamic image +#[cfg(feature = "std")] fn decoder_to_image<'a, I: ImageDecoder<'a>>(decoder: I) -> ImageResult { let (w, h) = decoder.dimensions(); let color_type = decoder.color_type(); @@ -1103,6 +1116,7 @@ fn decoder_to_image<'a, I: ImageDecoder<'a>>(decoder: I) -> ImageResult(path: P) -> ImageResult where P: AsRef, @@ -1118,6 +1132,7 @@ where /// content before its path or manually supplying the format. /// /// [`io::Reader`]: io/struct.Reader.html +#[cfg(feature = "std")] pub fn image_dimensions

(path: P) -> ImageResult<(u32, u32)> where P: AsRef, @@ -1133,6 +1148,7 @@ where /// /// This will lead to corrupted files if the buffer contains malformed data. Currently only /// jpeg, png, ico, pnm, bmp, exr and tiff files are supported. +#[cfg(feature = "std")] pub fn save_buffer

( path: P, buf: &[u8], @@ -1155,6 +1171,7 @@ where /// This will lead to corrupted files if the buffer contains /// malformed data. Currently only jpeg, png, ico, bmp, exr and /// tiff files are supported. +#[cfg(feature = "std")] pub fn save_buffer_with_format

( path: P, buf: &[u8], @@ -1182,6 +1199,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_buffer_with_format( buffered_writer: &mut W, buf: &[u8], @@ -1206,6 +1224,7 @@ where /// Try [`io::Reader`] for more advanced uses. /// /// [`io::Reader`]: io/struct.Reader.html +#[cfg(feature = "std")] pub fn load_from_memory(buffer: &[u8]) -> ImageResult { let format = free_functions::guess_format(buffer)?; load_from_memory_with_format(buffer, format) @@ -1220,6 +1239,7 @@ pub fn load_from_memory(buffer: &[u8]) -> ImageResult { /// /// [`load`]: fn.load.html /// [`io::Reader`]: io/struct.Reader.html +#[cfg(feature = "std")] #[inline(always)] pub fn load_from_memory_with_format(buf: &[u8], format: ImageFormat) -> ImageResult { let b = io::Cursor::new(buf); @@ -1242,6 +1262,9 @@ mod bench { #[cfg(test)] mod test { + use alloc::vec::Vec; + + #[cfg(feature = "std")] #[test] fn test_empty_file() { assert!(super::load_from_memory(b"").is_err()); @@ -1347,6 +1370,7 @@ mod test { let _ = super::DynamicImage::new_luma16(1, 1).into_bytes(); } + #[cfg(feature = "std")] #[test] fn issue_1705_can_turn_16bit_image_into_bytes() { let pixels = vec![65535u16; 64 * 64]; diff --git a/src/error.rs b/src/error.rs index 07ee275f21..fdd08b8dc6 100644 --- a/src/error.rs +++ b/src/error.rs @@ -13,8 +13,17 @@ //! //! [`ImageError`]: enum.ImageError.html +use alloc::boxed::Box; +use alloc::string::String; +use core::fmt; + +// TODO(interstellar) error_in_core; and re-add feature-gate +#[cfg(feature = "alloc")] +use core::error::Error; +#[cfg(feature = "std")] use std::error::Error; -use std::{fmt, io}; +#[cfg(feature = "std")] +use std::io; use crate::color::ExtendedColorType; use crate::image::ImageFormat; @@ -61,6 +70,7 @@ pub enum ImageError { Unsupported(UnsupportedError), /// An error occurred while interacting with the environment. + #[cfg(feature = "std")] IoError(io::Error), } @@ -183,6 +193,7 @@ pub enum ImageFormatHint { Name(String), /// A common path extension for the format is known. + #[cfg(feature = "std")] PathExtension(std::path::PathBuf), /// The format is not known or could not be determined. @@ -286,6 +297,7 @@ impl LimitError { } } +#[cfg(feature = "std")] impl From for ImageError { fn from(err: io::Error) -> ImageError { ImageError::IoError(err) @@ -298,6 +310,7 @@ impl From for ImageFormatHint { } } +#[cfg(feature = "std")] impl From<&'_ std::path::Path> for ImageFormatHint { fn from(path: &'_ std::path::Path) -> Self { match path.extension() { @@ -322,6 +335,7 @@ pub type ImageResult = Result; impl fmt::Display for ImageError { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { match self { + #[cfg(feature = "std")] ImageError::IoError(err) => err.fmt(fmt), ImageError::Decoding(err) => err.fmt(fmt), ImageError::Encoding(err) => err.fmt(fmt), @@ -335,6 +349,7 @@ impl fmt::Display for ImageError { impl Error for ImageError { fn source(&self) -> Option<&(dyn Error + 'static)> { match self { + #[cfg(feature = "std")] ImageError::IoError(err) => err.source(), ImageError::Decoding(err) => err.source(), ImageError::Encoding(err) => err.source(), @@ -351,6 +366,7 @@ impl fmt::Display for UnsupportedError { UnsupportedErrorKind::Format(ImageFormatHint::Unknown) => { write!(fmt, "The image format could not be determined",) } + #[cfg(feature = "std")] UnsupportedErrorKind::Format(format @ ImageFormatHint::PathExtension(_)) => write!( fmt, "The file extension {} was not recognized as an image format", @@ -482,6 +498,7 @@ impl fmt::Display for ImageFormatHint { match self { ImageFormatHint::Exact(format) => write!(fmt, "{:?}", format), ImageFormatHint::Name(name) => write!(fmt, "`{}`", name), + #[cfg(feature = "std")] ImageFormatHint::PathExtension(ext) => write!(fmt, "`.{:?}`", ext), ImageFormatHint::Unknown => write!(fmt, "`Unknown`"), } diff --git a/src/flat.rs b/src/flat.rs index 96644398a2..1602e54489 100644 --- a/src/flat.rs +++ b/src/flat.rs @@ -13,6 +13,7 @@ //! use image::flat::{FlatSamples, SampleLayout}; //! use image::imageops::thumbnail; //! +//! #[cfg(feature = "std")] //! #[no_mangle] //! pub extern "C" fn store_rgb8_compressed( //! data: *const u8, len: usize, @@ -41,12 +42,18 @@ //! } //! ``` //! -use std::marker::PhantomData; -use std::ops::{Deref, Index, IndexMut}; -use std::{cmp, error, fmt}; - +use alloc::vec::Vec; +use core::cmp; +use core::fmt; +use core::marker::PhantomData; +use core::ops::{Deref, Index, IndexMut}; use num_traits::Zero; +#[cfg(feature = "alloc")] +use core::error; +#[cfg(feature = "std")] +use std::error; + use crate::color::ColorType; use crate::error::{ DecodingError, ImageError, ImageFormatHint, ParameterError, ParameterErrorKind, diff --git a/src/image.rs b/src/image.rs index ae4cc65e6e..25a8a8f729 100644 --- a/src/image.rs +++ b/src/image.rs @@ -1,11 +1,14 @@ #![allow(clippy::too_many_arguments)] -use std::convert::TryFrom; -use std::ffi::OsStr; +use alloc::string::String; +use alloc::vec::Vec; +use core::convert::TryFrom; +use core::ops::{Deref, DerefMut}; +use core::usize; + +#[cfg(feature = "std")] use std::io; +#[cfg(feature = "std")] use std::io::Read; -use std::ops::{Deref, DerefMut}; -use std::path::Path; -use std::usize; use crate::color::{ColorType, ExtendedColorType}; use crate::error::{ @@ -83,13 +86,13 @@ impl ImageFormat { /// let format = ImageFormat::from_extension("jpg"); /// assert_eq!(format, Some(ImageFormat::Jpeg)); /// ``` - #[inline] + #[cfg(feature = "std")] pub fn from_extension(ext: S) -> Option where - S: AsRef, + S: AsRef, { // thin wrapper function to strip generics - fn inner(ext: &OsStr) -> Option { + fn inner(ext: &std::ffi::OsStr) -> Option { let ext = ext.to_str()?.to_ascii_lowercase(); Some(match ext.as_str() { @@ -127,13 +130,13 @@ impl ImageFormat { /// /// # Ok::<(), image::error::ImageError>(()) /// ``` - #[inline] + #[cfg(feature = "std")] pub fn from_path

(path: P) -> ImageResult where - P: AsRef, + P: AsRef, { // thin wrapper function to strip generics - fn inner(path: &Path) -> ImageResult { + fn inner(path: &std::path::Path) -> ImageResult { let exact_ext = path.extension(); exact_ext .and_then(ImageFormat::from_extension) @@ -393,11 +396,12 @@ impl ImageReadBuffer { } } + #[cfg(feature = "std")] #[allow(dead_code)] // When no image formats that use it are enabled - pub(crate) fn read(&mut self, buf: &mut [u8], mut read_scanline: F) -> io::Result + pub(crate) fn read(&mut self, buf: &mut [u8], mut read_scanline: F) -> std::io::Result where - F: FnMut(&mut [u8]) -> io::Result, + F: FnMut(&mut [u8]) -> std::io::Result, { if self.buffer.len() == self.consumed { if self.offset == self.total_bytes { @@ -440,6 +444,7 @@ impl ImageReadBuffer { /// Decodes a specific region of the image, represented by the rectangle /// starting from ```x``` and ```y``` and having ```length``` and ```width``` +#[cfg(feature = "std")] #[allow(dead_code)] // When no image formats that use it are enabled pub(crate) fn load_rect<'a, D, F, F1, F2, E>( @@ -456,7 +461,7 @@ pub(crate) fn load_rect<'a, D, F, F1, F2, E>( where D: ImageDecoder<'a>, F: Fn(Progress), - F1: FnMut(&mut D, u64) -> io::Result<()>, + F1: FnMut(&mut D, u64) -> std::io::Result<()>, F2: FnMut(&mut D, &mut [u8]) -> Result<(), E>, ImageError: From, { @@ -593,6 +598,7 @@ where /// of the output buffer is guaranteed. /// /// Panics if there isn't enough memory to decode the image. +#[cfg(feature = "std")] pub(crate) fn decoder_to_vec<'a, T>(decoder: impl ImageDecoder<'a>) -> ImageResult> where T: crate::traits::Primitive + bytemuck::Pod, @@ -604,7 +610,7 @@ where ))); } - let mut buf = vec![num_traits::Zero::zero(); total_bytes.unwrap() / std::mem::size_of::()]; + let mut buf = vec![num_traits::Zero::zero(); total_bytes.unwrap() / core::mem::size_of::()]; decoder.read_image(bytemuck::cast_slice_mut(buf.as_mut_slice()))?; Ok(buf) } @@ -645,9 +651,10 @@ impl Progress { } /// The trait that all decoders implement +#[cfg(feature = "std")] pub trait ImageDecoder<'a>: Sized { /// The type of reader produced by `into_reader`. - type Reader: Read + 'a; + type Reader: std::io::Read + 'a; /// Returns a tuple containing the width and height of the image fn dimensions(&self) -> (u32, u32); @@ -663,6 +670,7 @@ pub trait ImageDecoder<'a>: Sized { /// Returns a reader that can be used to obtain the bytes of the image. For the best /// performance, always try to read at least `scanline_bytes` from the reader at a time. Reading /// fewer bytes will cause the reader to perform internal buffering. + #[cfg(feature = "std")] fn into_reader(self) -> ImageResult; /// Returns the total number of bytes in the decoded image. @@ -705,12 +713,14 @@ pub trait ImageDecoder<'a>: Sized { /// buf /// } /// ``` + #[cfg(feature = "std")] fn read_image(self, buf: &mut [u8]) -> ImageResult<()> { self.read_image_with_progress(buf, |_| {}) } /// Same as `read_image` but periodically calls the provided callback to give updates on loading /// progress. + #[cfg(feature = "std")] fn read_image_with_progress( self, buf: &mut [u8], @@ -765,6 +775,7 @@ pub trait ImageDecoder<'a>: Sized { } /// Specialized image decoding not be supported by all formats +#[cfg(feature = "std")] pub trait ImageDecoderRect<'a>: ImageDecoder<'a> + Sized { /// Decode a rectangular section of the image; see [`read_rect_with_progress()`](#fn.read_rect_with_progress). fn read_rect( @@ -1318,16 +1329,18 @@ where #[cfg(test)] mod tests { - use std::io; - use std::path::Path; - - use super::{ - load_rect, ColorType, GenericImage, GenericImageView, ImageDecoder, ImageFormat, - ImageResult, - }; + use super::{ColorType, GenericImage, GenericImageView, ImageFormat, ImageResult}; use crate::color::Rgba; use crate::math::Rect; use crate::{GrayImage, ImageBuffer}; + use alloc::borrow::ToOwned; + use alloc::boxed::Box; + use alloc::vec::Vec; + use std::io; + use std::path::Path; + + #[cfg(feature = "std")] + use super::{load_rect, ImageDecoder}; #[test] #[allow(deprecated)] @@ -1456,6 +1469,7 @@ mod tests { view.to_image(); } + #[cfg(feature = "std")] #[test] fn test_load_rect() { struct MockDecoder { @@ -1576,6 +1590,7 @@ mod tests { } } + #[cfg(feature = "std")] #[test] fn test_load_rect_single_scanline() { const DATA: [u8; 25] = [ @@ -1630,6 +1645,7 @@ mod tests { assert_eq!(output[0..9], [6, 7, 11, 12, 16, 17, 21, 22, 0]); } + #[cfg(feature = "std")] #[test] fn test_image_format_from_path() { fn from_path(s: &str) -> ImageResult { @@ -1821,6 +1837,7 @@ mod tests { assert_eq!(&image.into_raw(), &expected); } + #[cfg(feature = "std")] #[test] fn image_formats_are_recognized() { use ImageFormat::*; @@ -1839,6 +1856,7 @@ mod tests { } } + #[cfg(feature = "std")] #[test] fn total_bytes_overflow() { struct D; diff --git a/src/imageops/affine.rs b/src/imageops/affine.rs index 548381c0bb..5831de3143 100644 --- a/src/imageops/affine.rs +++ b/src/imageops/affine.rs @@ -1,4 +1,4 @@ -//! Functions for performing affine transformations. +use alloc::vec::Vec; use crate::error::{ImageError, ParameterError, ParameterErrorKind}; use crate::image::{GenericImage, GenericImageView}; @@ -52,7 +52,7 @@ pub fn rotate90_in( where I: GenericImageView, I::Pixel: 'static, - Container: std::ops::DerefMut::Subpixel]>, + Container: core::ops::DerefMut::Subpixel]>, { let ((w0, h0), (w1, h1)) = (image.dimensions(), destination.dimensions()); if w0 != h1 || h0 != w1 { @@ -78,7 +78,7 @@ pub fn rotate180_in( where I: GenericImageView, I::Pixel: 'static, - Container: std::ops::DerefMut::Subpixel]>, + Container: core::ops::DerefMut::Subpixel]>, { let ((w0, h0), (w1, h1)) = (image.dimensions(), destination.dimensions()); if w0 != w1 || h0 != h1 { @@ -104,7 +104,7 @@ pub fn rotate270_in( where I: GenericImageView, I::Pixel: 'static, - Container: std::ops::DerefMut::Subpixel]>, + Container: core::ops::DerefMut::Subpixel]>, { let ((w0, h0), (w1, h1)) = (image.dimensions(), destination.dimensions()); if w0 != h1 || h0 != w1 { @@ -156,7 +156,7 @@ pub fn flip_horizontal_in( where I: GenericImageView, I::Pixel: 'static, - Container: std::ops::DerefMut::Subpixel]>, + Container: core::ops::DerefMut::Subpixel]>, { let ((w0, h0), (w1, h1)) = (image.dimensions(), destination.dimensions()); if w0 != w1 || h0 != h1 { @@ -182,7 +182,7 @@ pub fn flip_vertical_in( where I: GenericImageView, I::Pixel: 'static, - Container: std::ops::DerefMut::Subpixel]>, + Container: core::ops::DerefMut::Subpixel]>, { let ((w0, h0), (w1, h1)) = (image.dimensions(), destination.dimensions()); if w0 != w1 || h0 != h1 { @@ -270,6 +270,8 @@ mod test { use crate::image::GenericImage; use crate::traits::Pixel; use crate::{GrayImage, ImageBuffer}; + use alloc::string::ToString; + use alloc::vec::Vec; macro_rules! assert_pixels_eq { ($actual:expr, $expected:expr) => {{ diff --git a/src/imageops/colorops.rs b/src/imageops/colorops.rs index 085e5f44b5..5af3f03d7d 100644 --- a/src/imageops/colorops.rs +++ b/src/imageops/colorops.rs @@ -1,7 +1,10 @@ //! Functions for altering and converting the color of pixelbufs - +use alloc::vec::Vec; +use core::f64::consts::PI; use num_traits::NumCast; -use std::f64::consts::PI; + +#[cfg(not(feature = "std"))] +use num_traits::Float; use crate::color::{FromColor, IntoColor, Luma, LumaA, Rgba}; use crate::image::{GenericImage, GenericImageView}; @@ -543,9 +546,9 @@ where #[cfg(test)] mod test { - use super::*; use crate::{GrayImage, ImageBuffer}; + use alloc::string::ToString; macro_rules! assert_pixels_eq { ($actual:expr, $expected:expr) => {{ diff --git a/src/imageops/mod.rs b/src/imageops/mod.rs index 57761c4878..2e20fda0f2 100644 --- a/src/imageops/mod.rs +++ b/src/imageops/mod.rs @@ -1,5 +1,5 @@ //! Image Processing Functions -use std::cmp; +use core::cmp; use crate::image::{GenericImage, GenericImageView, SubImage}; use crate::traits::{Lerp, Pixel, Primitive}; @@ -242,10 +242,12 @@ where /// use image::{RgbaImage}; /// /// let mut img = RgbaImage::new(1920, 1080); +/// # #[cfg(feature = "std")] { /// let tile = image::open("tile.png").unwrap(); /// /// image::imageops::tile(&mut img, &tile); /// img.save("tiled_wallpaper.png").unwrap(); +/// } /// ``` pub fn tile(bottom: &mut I, top: &J) where @@ -272,6 +274,7 @@ where /// let end = Rgba::from_slice(&[255, 255, 255, 255]); /// /// image::imageops::vertical_gradient(&mut img, start, end); +/// #[cfg(feature = "std")] /// img.save("vertical_gradient.png").unwrap(); pub fn vertical_gradient(img: &mut I, start: &P, stop: &P) where @@ -305,6 +308,7 @@ where /// let end = Rgba::from_slice(&[255, 255, 255, 255]); /// /// image::imageops::horizontal_gradient(&mut img, start, end); +/// #[cfg(feature = "std")] /// img.save("horizontal_gradient.png").unwrap(); pub fn horizontal_gradient(img: &mut I, start: &P, stop: &P) where diff --git a/src/imageops/sample.rs b/src/imageops/sample.rs index 1aed9bb327..d1f9ed2b71 100644 --- a/src/imageops/sample.rs +++ b/src/imageops/sample.rs @@ -2,11 +2,15 @@ // See http://cs.brown.edu/courses/cs123/lectures/08_Image_Processing_IV.pdf // for some of the theory behind image scaling and convolution - -use std::f32; +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::f32; use num_traits::{NumCast, ToPrimitive, Zero}; +#[cfg(not(feature = "std"))] +use num_traits::Float; + use crate::image::{GenericImage, GenericImageView}; use crate::traits::{Enlargeable, Pixel, Primitive}; use crate::utils::clamp; diff --git a/src/io/free_functions.rs b/src/io/free_functions.rs index d6047d7fea..1a2d1cea14 100644 --- a/src/io/free_functions.rs +++ b/src/io/free_functions.rs @@ -1,7 +1,7 @@ +use core::u32; use std::fs::File; use std::io::{BufRead, BufReader, BufWriter, Seek}; use std::path::Path; -use std::u32; use crate::codecs::*; @@ -137,6 +137,7 @@ pub(crate) fn image_dimensions_with_format_impl( load_decoder(buffered_read, format, super::Limits::default(), DimVisitor) } +#[cfg(feature = "std")] #[allow(unused_variables)] // Most variables when no features are supported pub(crate) fn save_buffer_impl( @@ -150,6 +151,7 @@ pub(crate) fn save_buffer_impl( save_buffer_with_format_impl(path, buf, width, height, color, format) } +#[cfg(feature = "std")] #[allow(unused_variables)] // Most variables when no features are supported pub(crate) fn save_buffer_with_format_impl( diff --git a/src/io/mod.rs b/src/io/mod.rs index 160bd5580d..97c3a0b868 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -1,12 +1,15 @@ //! Input and output of images. -use std::convert::TryFrom; +use core::convert::TryFrom; use crate::{error, ImageError, ImageResult}; +#[cfg(feature = "std")] pub(crate) mod free_functions; +#[cfg(feature = "std")] mod reader; +#[cfg(feature = "std")] pub use self::reader::Reader; /// Set of supported strict limits for a decoder. @@ -86,8 +89,6 @@ impl Limits { Ok(()) } - /// This function checks the `max_image_width` and `max_image_height` limits given - /// the image width and height. pub fn check_dimensions(&self, width: u32, height: u32) -> ImageResult<()> { if let Some(max_width) = self.max_image_width { if width > max_width { diff --git a/src/io/reader.rs b/src/io/reader.rs index 7721a79311..0bfe9edca3 100644 --- a/src/io/reader.rs +++ b/src/io/reader.rs @@ -7,6 +7,7 @@ use crate::error::{ImageFormatHint, UnsupportedError, UnsupportedErrorKind}; use crate::image::ImageFormat; use crate::{ImageError, ImageResult}; +#[cfg(feature = "std")] use super::free_functions; /// A multi-format image reader. diff --git a/src/lib.rs b/src/lib.rs index 60a641f7bc..d4197674a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,14 +17,18 @@ //! //! ```rust,no_run //! use std::io::Cursor; -//! use image::io::Reader as ImageReader; +//! #[cfg(feature = "std")] //! # fn main() -> Result<(), image::ImageError> { +//! use image::io::Reader as ImageReader; //! # let bytes = vec![0u8]; //! //! let img = ImageReader::open("myimage.png")?.decode()?; //! let img2 = ImageReader::new(Cursor::new(bytes)).with_guessed_format()?.decode()?; //! # Ok(()) //! # } +//! +//! #[cfg(not(feature = "std"))] +//! fn main() {} //! ``` //! //! And save them using [`save`] or [`write_to`] methods: @@ -32,8 +36,9 @@ //! ```rust,no_run //! # use std::io::{Write, Cursor}; //! # use image::ImageOutputFormat; +//! #[cfg(all(feature = "png", feature = "std"))] //! # use image::DynamicImage; -//! # #[cfg(feature = "png")] +//! # #[cfg(all(feature = "png", feature = "std"))] //! # fn main() -> Result<(), image::ImageError> { //! # let img: DynamicImage = unimplemented!(); //! # let img2: DynamicImage = unimplemented!(); @@ -43,7 +48,7 @@ //! img2.write_to(&mut Cursor::new(&mut bytes), image::ImageOutputFormat::Png)?; //! # Ok(()) //! # } -//! # #[cfg(not(feature = "png"))] fn main() {} +//! # #[cfg(not(all(feature = "png", feature = "std")))] fn main() {} //! ``` //! //! With default features, the crate includes support for [many common image formats](codecs/index.html#supported-formats). @@ -83,6 +88,8 @@ //! [`ImageDecoderRect`]: trait.ImageDecoderRect.html //! [`ImageDecoder`]: trait.ImageDecoder.html //! [`ImageEncoder`]: trait.ImageEncoder.html +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(feature = "alloc", feature(error_in_core))] #![warn(missing_docs)] #![warn(unused_qualifications)] #![deny(unreachable_pub)] @@ -94,6 +101,13 @@ // it's a backwards compatibility break #![allow(clippy::wrong_self_convention, clippy::enum_variant_names)] +#[macro_use] +extern crate alloc; + +#[cfg(test)] +#[macro_use] +extern crate std; + #[cfg(all(test, feature = "benchmarks"))] extern crate test; @@ -111,8 +125,6 @@ pub use crate::image::{ AnimationDecoder, GenericImage, GenericImageView, - ImageDecoder, - ImageDecoderRect, ImageEncoder, ImageFormat, ImageOutputFormat, @@ -139,10 +151,14 @@ pub use crate::flat::FlatSamples; pub use crate::traits::{EncodableLayout, Pixel, PixelWithColorType, Primitive}; // Opening and loading images +#[cfg(feature = "std")] pub use crate::dynimage::{ image_dimensions, load_from_memory, load_from_memory_with_format, open, save_buffer, save_buffer_with_format, write_buffer_with_format, }; +#[cfg(feature = "std")] +pub use crate::image::{ImageDecoder, ImageDecoderRect}; +#[cfg(feature = "std")] pub use crate::io::free_functions::{guess_format, load}; pub use crate::dynimage::DynamicImage; diff --git a/src/math/utils.rs b/src/math/utils.rs index 3a1f121d45..5744697807 100644 --- a/src/math/utils.rs +++ b/src/math/utils.rs @@ -1,6 +1,9 @@ //! Shared mathematical utility functions. -use std::cmp::max; +use core::cmp::max; + +#[cfg(not(feature = "std"))] +use num_traits::Float; /// Calculates the width and height an image should be resized to. /// This preserves aspect ratio, and based on the `fill` parameter diff --git a/src/traits.rs b/src/traits.rs index 56daaa0ddf..430716d158 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -2,8 +2,8 @@ // Note copied from the stdlib under MIT license +use core::ops::AddAssign; use num_traits::{Bounded, Num, NumCast}; -use std::ops::AddAssign; use crate::color::{ColorType, Luma, LumaA, Rgb, Rgba}; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 92bb185148..bb844b0f90 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,6 +1,8 @@ //! Utilities +use alloc::borrow::ToOwned; +use alloc::vec::Vec; -use std::iter::repeat; +use core::iter::repeat; #[inline(always)] pub(crate) fn expand_packed(buf: &mut [u8], channels: usize, bit_depth: u8, mut func: F) @@ -66,7 +68,7 @@ pub(crate) fn expand_bits(bit_depth: u8, row_size: u32, buf: &[u8]) -> Vec { #[allow(dead_code)] // When no image formats that use it are enabled pub(crate) fn check_dimension_overflow(width: u32, height: u32, bytes_per_pixel: u8) -> bool { - width as u64 * height as u64 > std::u64::MAX / bytes_per_pixel as u64 + width as u64 * height as u64 > core::u64::MAX / bytes_per_pixel as u64 } #[allow(dead_code)] @@ -94,6 +96,8 @@ where #[cfg(test)] mod test { + use alloc::borrow::ToOwned; + #[test] fn gray_to_luma8_skip() { let check = |bit_depth, w, from, to| { diff --git a/tests/reference_images.rs b/tests/reference_images.rs index 9106b63a8c..c2ea120a81 100644 --- a/tests/reference_images.rs +++ b/tests/reference_images.rs @@ -5,6 +5,7 @@ use std::path::PathBuf; use std::u32; use crc32fast::Hasher as Crc32; +#[cfg(feature = "std")] use image::DynamicImage; const BASE_PATH: [&str; 2] = [".", "tests"]; @@ -149,6 +150,7 @@ fn parse_crc(src: &str) -> Option { u32::from_str_radix(src, 16).ok() } +#[cfg(feature = "std")] #[test] fn check_references() { process_images(REFERENCE_DIR, Some("png"), |base, path, decoder| { diff --git a/tests/regression.rs b/tests/regression.rs index 927447d7a2..52aabddcef 100644 --- a/tests/regression.rs +++ b/tests/regression.rs @@ -31,6 +31,7 @@ where } } +#[cfg(feature = "std")] #[test] fn check_regressions() { process_images(REGRESSION_DIR, None, |path| { @@ -41,6 +42,7 @@ fn check_regressions() { /// Check that BMP files with large values could cause OOM issues are rejected. /// /// The images are postfixed with `bad_bmp` to not be loaded by the other test. +#[cfg(feature = "std")] #[test] fn bad_bmps() { let path: PathBuf = BASE_PATH @@ -60,6 +62,7 @@ fn bad_bmps() { } } +#[cfg(feature = "std")] #[test] fn bad_gif_oom() { let data = [ diff --git a/tests/truncate_images.rs b/tests/truncate_images.rs index dafe5ac557..bcf242cfbb 100644 --- a/tests/truncate_images.rs +++ b/tests/truncate_images.rs @@ -37,6 +37,7 @@ where } } +#[cfg(feature = "std")] fn truncate_images(decoder: &str) { process_images(IMAGE_DIR, Some(decoder), |path| { println!("{:?}", path); @@ -50,51 +51,61 @@ fn truncate_images(decoder: &str) { }) } +#[cfg(feature = "std")] #[test] fn truncate_tga() { truncate_images("tga") } +#[cfg(feature = "std")] #[test] fn truncate_tiff() { truncate_images("tiff") } +#[cfg(feature = "std")] #[test] fn truncate_png() { truncate_images("png") } +#[cfg(feature = "std")] #[test] fn truncate_gif() { truncate_images("gif") } +#[cfg(feature = "std")] #[test] fn truncate_bmp() { truncate_images("bmp") } +#[cfg(feature = "std")] #[test] fn truncate_ico() { truncate_images("ico") } +#[cfg(feature = "std")] #[test] fn truncate_jpg() { truncate_images("jpg") } +#[cfg(feature = "std")] #[test] fn truncate_hdr() { truncate_images("hdr"); } +#[cfg(feature = "std")] #[test] fn truncate_farbfeld() { truncate_images("farbfeld"); } +#[cfg(feature = "std")] #[test] fn truncate_exr() { truncate_images("exr");