image Rust library

repository·main·Indexed 27 days ago

https://github.com/image-rs/image

An image processing library for Rust (v0.25.9) providing tools for decoding, encoding, and manipulating various image formats. It features a high-level DynamicImage API and low-level pixel access via ImageBuffer. Supported formats include AVIF, BMP, EXR, FF, GIF, HDR, ICO, JPEG, PNG, PNM, QOI, TGA, TIFF, and WebP. The library includes the imageops module for operations like blurring, resizing, and rotating, as well as GenericImageView and GenericImage traits for generic image manipulation.

Tokens
3.5K
Snippets
12
Records
22
Agent score
90%

What's inside image

  1. Build and run AFL fuzz targets

    main

    Follow these steps to build a specific format's fuzz target and execute the fuzzer using input files from ./in/<format> and outputting results to ./out/<format>.

    1. Build the target: Use cargo afl build specifying the binary name fuzz_<format>.
    2. Prepare output directory: Create the output directory.
    3. Run the fuzzer: Use cargo afl fuzz pointing to the input directory, output directory, and the built binary.
    # Build fuzz target
    $ cargo afl build --bin fuzz_<format>
    
    # Run afl
    $ mkdir out/<format>
    $ cargo afl fuzz -i ./in/<format> -o ./out/<format> ./target/debug/fuzz_<format>
  2. Load and save images using the High-level API

    main

    Use ImageReader to load images from files or byte buffers, and use the save or write_to methods to persist them. ImageReader can automatically guess the format from the file extension or via .with_guessed_format() when working with raw bytes.

    use std::io::Cursor;
    use image::ImageReader;
    
    // Load from a file
    let img = ImageReader::open("myimage.png")?.decode()?;
    
    // Load from a byte buffer with format guessing
    let img2 = ImageReader::new(Cursor::new(bytes)).with_guessed_format()?.decode()?;
    
    // Save to a file
    img.save("empty.jpg")?;
    
    // Save to a buffer with a specific format
    let mut bytes: Vec<u8> = Vec::new();
    img2.write_to(&mut Cursor::new(&mut bytes), image::ImageFormat::Png)?;
  3. Set up fuzzing with libfuzzer

    main

    To perform fuzzing on the image crate using libfuzzer, you must first install cargo-fuzz and then run the specific fuzzer script corresponding to the image format you wish to test using a nightly Rust toolchain.

    For a more comprehensive and up-to-date guide, refer to the cargo-fuzz setup documentation.

    $ cargo install cargo-fuzz
    $ cargo +nightly fuzz run fuzzer_script_<format>
  4. Run benchmarks for the image crate

    main
    You can execute the benchmarks for the image crate using cargo bench. To run all available benchmarks, use the standard command. To run a specific benchmark suite, use the --bench flag followed by the benchmark name.
  5. Core image storage types

    main

    The library provides two primary ways to handle image data:

    • ImageBuffer: Holds statically typed image contents (e.g., RgbImage, RgbaImage, GrayImage).
    • DynamicImage: An enum over supported ImageBuffer formats, allowing for easy conversions between different color types and bit depths.
  6. Configure image crate via feature flags

    main

    The image crate uses feature flags to manage dependencies and format support. When building a library, it is recommended to set default-features = false and explicitly enable only the necessary format features to minimize the dependency tree and avoid unexpected multithreading behavior (e.g., in wasm targets).

    FeatureDescription
    default-formatsDefault. Supports AVIF, BMP, EXR, FF, GIF, HDR, ICO, JPEG, PNG, PNM, QOI, TGA, TIFF, and WebP
    rayonDefault. Enables multi-threading via rayon
    nasmEnables nasm build-time use for ravif (requires nasm installed)
    color_quantIncludes color_quant for imageops::ColorMap
    avif-nativeEnables non-Rust avif dependencies (mp4parse and dav1d)
    serdeEnables serde integration for structs and options
  7. Workaround for nightly Rust LLVM sanitizer issues

    main

    If you are using a nightly Rust build, you may encounter an error where the LLVM version rejects a sanitizer pass. To resolve this, set the RUSTFLAGS environment variable to disable the new LLVM pass manager when running afl.

    $ RUSTFLAGS="-Znew-llvm-pass-manager=no" cargo +nightly afl run …
  8. Understanding memory unsafety advisory regarding buffer reuse

    main

    The image library has identified that attempting to reuse allocations from decoders for ImageBuffer output via Vec::from_raw_parts is unsound. This is because decoding algorithms often change the representation type of color samples (e.g., from a pixel type like Rgb<u8> to a linear arrangement of u8 samples).

    If the output pixel type has a different size or alignment than the type used in the temporary decoding buffer, using Vec::from_raw_parts violates the requirement that the pointer's type T must have the same size and alignment as it was allocated with.

    Key Takeaway: Do not attempt to manually transmute or reuse Vec allocations between different pixel representations (e.g., from Rgb<T> to [u8]) as it can lead to undefined behavior depending on the allocator's handling of different type sizes.

  9. Open, inspect, and save an image

    main

    Use image::open to load an image from a path. The format is determined by the file extension. The returned DynamicImage can be used to inspect dimensions and color type before saving.

    use image::GenericImageView;
    
    // Use the open function to load an image from a Path.
    // `open` returns a `DynamicImage` on success.
    let img = image::open("tests/images/jpg/progressive/cat.jpg").unwrap();
    
    // The dimensions method returns the images width and height.
    println!("dimensions {:?}", img.dimensions());
    
    // The color method returns the image's `ColorType`.
    println!("{:?}", img.color());
    
    // Write the contents of this image to the Writer in PNG format.
    img.save("test.png").unwrap();
  10. Save a raw buffer to a file

    main

    If you have raw image data in a buffer and do not need the high-level DynamicImage interface, use image::save_buffer to write it directly to a file.

    let buffer: &[u8] = unimplemented!(); // Generate the image data
    
    // Save the buffer as "image.png"
    image::save_buffer("image.png", buffer, 800, 600, image::ExtendedColorType::Rgb8).unwrap()