Encoding and decoding images in Rust

Overview

Image

crates.io Documentation Build Status Gitter

Maintainers: @HeroicKatora, @fintelia

How to contribute

An Image Processing Library

This crate provides basic image processing functions and methods for converting to and from various image formats.

All image processing functions provided operate on types that implement the GenericImageView and GenericImage traits and return an ImageBuffer.

Supported Image Formats

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 RGB(8), RGBA(8), Gray(8), GrayA(8)
ICO Yes Yes
TIFF Baseline(no fax support) + LZW + PackBits RGB(8), RGBA(8), Gray(8)
WebP Lossy(Luma channel only) No
AVIF Only 8-bit Lossy
PNM PBM, PGM, PPM, standard PAM Yes
DDS DXT1, DXT3, DXT5 No
TGA Yes RGB(8), RGBA(8), BGR(8), BGRA(8), Gray(8), GrayA(8)
farbfeld Yes Yes

The ImageDecoder and ImageDecoderExt Traits

All image format decoders implement the ImageDecoder trait which provide basic methods for getting image metadata and decoding images. Some formats additionally provide ImageDecoderExt implementations which allow for decoding only part of an image at once.

The most important methods for decoders are...

  • dimensions: Return a tuple containing the width and height of the image.
  • color_type: Return the color type of the image data produced by this decoder.
  • read_image: Decode the entire image into a slice of bytes.

Pixels

image provides the following pixel types:

  • Rgb: RGB pixel
  • Rgba: RGBA pixel
  • Luma: Grayscale pixel
  • LumaA: Grayscale with alpha

All pixels are parameterised by their component type.

Images

Individual pixels within images are indexed with (0,0) at the top left corner.

The GenericImageView and GenericImage Traits

Traits that provide methods for inspecting (GenericImageView) and manipulating (GenericImage) images, parameterised over the image's pixel type.

Some of these methods for GenericImageView are...

  • dimensions: Return a tuple containing the width and height of the image.
  • get_pixel: Returns the pixel located at (x, y).
  • pixels: Returns an Iterator over the pixels of this image.

While some of the methods for GenericImage are...

  • put_pixel: Put a pixel at location (x, y).
  • copy_from: Copies all of the pixels from another image into this image.

Representation of Images

image provides two main ways of representing image data:

ImageBuffer

An image parameterised by its Pixel types, represented by a width and height and a vector of pixels. It provides direct access to its pixels and implements the GenericImageView and GenericImage traits.

extern crate image;

use image::{GenericImage, GenericImageView, ImageBuffer, RgbImage};

// Construct a new RGB ImageBuffer with the specified width and height.
let img: RgbImage = ImageBuffer::new(512, 512);

// Construct a new by repeated calls to the supplied closure.
let mut img = ImageBuffer::from_fn(512, 512, |x, y| {
    if x % 2 == 0 {
        image::Luma([0u8])
    } else {
        image::Luma([255u8])
    }
});

// Obtain the image's width and height.
let (width, height) = img.dimensions();

// Access the pixel at coordinate (100, 100).
let pixel = img[(100, 100)];

// Or use the `get_pixel` method from the `GenericImage` trait.
let pixel = *img.get_pixel(100, 100);

// Put a pixel at coordinate (100, 100).
img.put_pixel(100, 100, pixel);

// Iterate over all pixels in the image.
for pixel in img.pixels() {
    // Do something with pixel.
}

DynamicImage

A DynamicImage is an enumeration over all supported ImageBuffer<P> types. Its exact image type is determined at runtime. It is the type returned when opening an image. For convenience DynamicImage reimplements all image processing functions.

DynamicImage implement the GenericImageView and GenericImage traits for RGBA pixels.

SubImage

A view into another image, delimited by the coordinates of a rectangle. The coordinates given set the position of the top left corner of the rectangle. This is used to perform image processing functions on a subregion of an image.

extern crate image;

use image::{GenericImageView, ImageBuffer, RgbImage, imageops};

let mut img: RgbImage = ImageBuffer::new(512, 512);
let subimg = imageops::crop(&mut img, 0, 0, 100, 100);

assert!(subimg.dimensions() == (100, 100));

Image Processing Functions

These are the functions defined in the imageops module. All functions operate on types that implement the GenericImage trait. Note that some of the functions are very slow in debug mode. Make sure to use release mode if you experience any performance issues.

  • blur: Performs a Gaussian blur on the supplied image.
  • brighten: Brighten the supplied image.
  • huerotate: Hue rotate the supplied image by degrees.
  • contrast: Adjust the contrast of the supplied image.
  • crop: Return a mutable view into an image.
  • filter3x3: Perform a 3x3 box filter on the supplied image.
  • flip_horizontal: Flip an image horizontally.
  • flip_vertical: Flip an image vertically.
  • grayscale: Convert the supplied image to grayscale.
  • invert: Invert each pixel within the supplied image This function operates in place.
  • resize: Resize the supplied image to the specified dimensions.
  • rotate180: Rotate an image 180 degrees clockwise.
  • rotate270: Rotate an image 270 degrees clockwise.
  • rotate90: Rotate an image 90 degrees clockwise.
  • unsharpen: Performs an unsharpen mask on the supplied image.

For more options, see the imageproc crate.

Examples

Opening and Saving Images

image provides the open function for opening images from a path. The image format is determined from the path's file extension. An io module provides a reader which offer some more control.

extern crate image;

use image::GenericImageView;

fn main() {
    // 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();
}

Generating Fractals

//! An example of generating julia fractals.
extern crate image;
extern crate num_complex;

fn main() {
    let imgx = 800;
    let imgy = 800;

    let scalex = 3.0 / imgx as f32;
    let scaley = 3.0 / imgy as f32;

    // Create a new ImgBuf with width: imgx and height: imgy
    let mut imgbuf = image::ImageBuffer::new(imgx, imgy);

    // Iterate over the coordinates and pixels of the image
    for (x, y, pixel) in imgbuf.enumerate_pixels_mut() {
        let r = (0.3 * x as f32) as u8;
        let b = (0.3 * y as f32) as u8;
        *pixel = image::Rgb([r, 0, b]);
    }

    // A redundant loop to demonstrate reading image data
    for x in 0..imgx {
        for y in 0..imgy {
            let cx = y as f32 * scalex - 1.5;
            let cy = x as f32 * scaley - 1.5;

            let c = num_complex::Complex::new(-0.4, 0.6);
            let mut z = num_complex::Complex::new(cx, cy);

            let mut i = 0;
            while i < 255 && z.norm() <= 2.0 {
                z = z * z + c;
                i += 1;
            }

            let pixel = imgbuf.get_pixel_mut(x, y);
            let image::Rgb(data) = *pixel;
            *pixel = image::Rgb([data[0], i as u8, data[2]]);
        }
    }

    // Save the image as “fractal.png”, the format is deduced from the path
    imgbuf.save("fractal.png").unwrap();
}

Example output:

A Julia Fractal, c: -0.4 + 0.6i

Writing raw buffers

If the high level interface is not needed because the image was obtained by other means, image provides the function save_buffer to save a buffer to a file.

extern crate image;

fn main() {

    let buffer: &[u8] = unimplemented!(); // Generate the image data

    // Save the buffer as "image.png"
    image::save_buffer("image.png", buffer, 800, 600, image::ColorType::Rgb8).unwrap()
}
Comments
  • Moving image libraries to separate open source organization

    Moving image libraries to separate open source organization

    @PistonDevelopers/pistoncollaborator @PistonDevelopers/admins

    I think it's time to consider moving image libraries to a separate open source organization.

    Once the transition is made, I plan to reduce my own access.

    discussion 
    opened by bvssvni 44
  • OpenEXR support desired?

    OpenEXR support desired?

    Hi! Im the creator of the pure Rust implementation of the OpenEXR format. Would you be interested in having EXR support? I'd be happy to implement that and would create a PR if this is valuable :)

    The EXR crate already supports most images. Only one compression method and a few special features are still on the roadmap. Simple RGBA images already have great support, and can be read and written.

    OpenEXR is a popular image format, especially in VFX workflows, as it stores real floating-point pixels which can be compressed losslessly or lossy. Pixels can contain any type of channels, for example RGBA, LAB, CMYK, XYZ, or even depth and motion vectors. Arbitrary meta data can be added to any image. Most software already supports exr.

    opened by johannesvollmer 37
  • OpenEXR basic support

    OpenEXR basic support

    Hi! Just experimented with adding OpenEXR support. Does not compile yet, work in progress.

    Here's a list of things to do:

    • [x] Solve sendable Read/Write (exrs only supports sendable stuff due to multi threading for now, might be able to relax this in exrs)
    • [x] Reduce memcpy calls (requires exrs refactor)
    • [x] Try f32 support (using u16, clamping 0-1, for now)
    • [x] Use exr meta information more precisely (do not allocate alpha channel if none was in the file etc)
    • [x] Basic tests
    • [x] Try seekable writer if possible (kind of checked: this change must be done in the next branch)
    • [x] Not ignore data window position and display window (allocate transparent display window instead of data window, and load only display window blocks?). Reason: Auto cropped images should not be tiny.
    • [x] Investigate color conversion linearrgb/srgb

    Current limitations:

    • only pixel type Rgba32F and Rgba16F are supported
    • only non-deep rgb/rgba files supported, no conversion from/to YCbCr or similar
    • only the first non-deep rgb layer is used
    • only the largest mip map level is used
    • pixels outside display window are lost
    • meta data is lost
    • dwaa/dwab compressed images not supported yet by the exr library
    • (chroma) subsampling not supported yet by the exr library

    I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.

    opened by johannesvollmer 29
  • Finalize ColorType enum

    Finalize ColorType enum

    The ColorType enum is used to represent the meaning of subcomponents of Pixels and Decoders. However it has a few issues:

    • Many values of it are completely ridiculous and almost surely never used in practice. Why would anyone have an image with 157 bits per pixel BGR?
    • Parts of the library are unimplemented for certain color types. At very least it should be possible to convert between any pair of color types (filling any missing values with some reasonable default).
    • Adding enum variants would be a breaking change to the library, yet some relatively useful/common formats (like floating point RGBA) are missing. This needs to be resolved before a 1.0 release.

    One option is to replace the enum with the something similar to the following (based on the supported modes in the Pillow library):

    enum ColorType {
        // 8-bits per channel
        Palette,
        Luminance,
        LuminanceAlpha,
        RGB,
        RGBA,
    
        // Reversed channel order
        BGR,
        BGRA,
    
        // Exotic single channel bit depths
        U1,
        I32,
        F32,
    
        // High bit depth color images
        RGBA16,
        RGBA32F,
    }
    

    Questions

    [ ] Do we want to include BGR / BGRA formats? [ ] Should we include U1 (packed 1 bit per pixel, 8 pixels per byte)? [ ] Should we define a smaller set of "core" types, say Luminance + RGB + RGBA + RGBA32F, and then focus on conversions to and between them?

    discussion 
    opened by fintelia 29
  • Pure Rust lib for zlib

    Pure Rust lib for zlib

    There are many people interested in this, so I'm opening this issue for discussion. The PR https://github.com/PistonDevelopers/image/pull/418 replaces the Rust implementation, which currently has some bugs, with flate2.

    discussion 
    opened by bvssvni 25
  • PNG with zero sized IDAT is loading successfully as black image

    PNG with zero sized IDAT is loading successfully as black image

    Expected

    Program should panic at image::load_from_memory(bad_png).unwrap(). Loading invalid image should fail. If there is no IDAT or size of decompressed data is too small to fill whole image then loading fails but not with zero sized IDAT.

    Actual behaviour

    Program runs successfully. image::load_from_memory(bad_png) returns Ok. And resulting image is black. Raw bytes are all zero and maybe actually undefined.

    Reproduction steps

    extern crate image;
    
    fn main()
    {
    	let bad_png = b"\
    		\x89PNG\x0D\x0A\x1A\x0A\
    		\x00\x00\x00\x0D\
    			IHDR\
    			\x00\x00\x04\x00\
    			\x00\x00\x05\xA9\
    			\x08\x02\x00\x00\x00\
    			\x68\x1B\xF7\x46\
    		\x00\x00\x00\x00\
    			IDAT\
    			\x35\xAF\x06\x1E\
    		\x00\x00\x00\x00\
    			IEND\
    			\xAE\x42\x60\x82\
    	";
    	let img = image::load_from_memory(bad_png).unwrap();
    	let data = img.as_rgb8().unwrap().iter().copied();
    	let zeros = std::iter::repeat(0u8).take(1024 * 1449 * 3);
    	assert!(data.eq(zeros), "Are they zero or undefined?");
    }
    
    kind: bug 
    opened by misos1 24
  • General restructurisation of repository

    General restructurisation of repository

    It would be great if we split all formats into separate libraries (without additional repo). Original repo should work only as a glue between all packages.

    .
    ├── Cargo.toml
    ├── color // color related structs
    ├── formats
    │   ├── format // generic format (all common traits should be here)
    │   ├── gif
    │   ├── jpeg
    │   ├── png
    │   ├── ppm
    │   ├── tga
    │   ├── tiff
    │   └── webp
    ├── lzw // I'm not sure if it shouldn't be extracted to separate repo as it isn't strictly bounded to image processing
    ├── src
    └── tests
    

    Also I'm working on extracting math::nq to separate repo.

    Todo

    • [ ] extract image formats to formats/*
    • [ ] extract generic traits to .
    • [ ] remove unneded Zero/One/Primitive traits and replace them with num equivalents
    • [ ] extract non-image processing related components into separate projects
    • [ ] rewrite image as a metapackage with some glue between newly created components
    discussion draft 
    opened by hauleth 22
  • Support AVIF (AV1 Image FIle Format)

    Support AVIF (AV1 Image FIle Format)

    Spec at https://aomediacodec.github.io/av1-avif/

    Since there is already a PR for FLIF support, it probably makes sense to have at least a tracking issue for AVIF as well.

    kind: enhancement 
    opened by jansol 21
  • Fix cmyk_to_rgb causing off by one rounding errors.

    Fix cmyk_to_rgb causing off by one rounding errors.

    Running cmyk_to_rgb(&[0, 0, 0, 254]) produces the RGB color [0, 0, 0] when it should in fact produce RGB [1, 1, 1]: R = 255 * (1 - C/255) * (1-K/255) R = 255 * (1-0/255) * (1-254/255) R = 255 * 1 * 1/ 255 = 1.

    This bug occurs with a range of other values as well - 159 / 255 of the values [0, 0, 0, 0..255] are affected. The fix involves reducing the number of multiplications and divisions, and also yields a ~15-25% speedup (results are from randomly generated images, using cargo build --release).

    250 px
    Orig took 0.0000020s
    Fast took 0.0000015s
    2500 px
    Orig took 0.0000154s
    Fast took 0.0000121s
    25000 px
    Orig took 0.0002961s
    Fast took 0.0002334s
    250000 px
    Orig took 0.0017928s
    Fast took 0.0014527s
    2500000 px
    Orig took 0.0255831s
    Fast took 0.0213677s
    

    I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.

    (Resubmitted PR against next branch, not master - it's not specified which branch to specify pull requests against.)

    opened by philippeitis 19
  • Better API design

    Better API design

    I really don't like our current API. I has a lot of code-duplication because of this DynamicImage enum and is not very ergonomic. At the moment this is ok but just image what would happen if we finally add 16bit and CYMK image types. This would blow up our enum to at least 20 variants.

    Could a trait + associated type help with this?

    kind: enhancement discussion 
    opened by nwin 19
  • Decoding api

    Decoding api

    Sequential Decoding

    This is a proposed trait that all image decoders will implement:

    trait ImageDecoder {
            //Return a tuple containing the width and height of the image
            fn dimensions(&mut self) -> ImageResult<(u32, u32)>;
    
            //Return the color type of the image e.g RGB(8) (8bit RGB)
            fn colortype(&mut self) -> ImageResult<ColorType>;
    
            //Returns the length in bytes of one decoded row of the image
            fn row_len(&mut self) -> ImageResult<uint>;
    
            //Read one row from the image into buf
            //Returns the row index
            fn read_scanline(&mut self, buf: &mut [u8]) -> ImageResult<u32>;
    
            //Decode the entire image and return it as a Vector
            fn read_image(&mut self) -> ImageResult<Vec<u8>>;
    }
    

    Where the ImageResult is the type:

            type ImageResult<T> = Result<T, ImageError>;
    

    And ImageError is an enumeration of common errors that can occur while decoding.

    discussion 
    opened by ccgn 19
  • AVIF encoder changes.

    AVIF encoder changes.

    As noted in #1760, AVIF encoding is very slow. In looking at why, I noticed that the default encoder settings are very different from what the cavif CLI provided by upstream uses - in particular, upstream documentation suggests that a quality setting of 100 is not a useful configuration.

    The majority of the changes here are to upgrade the ravif dependency. The images I was using for testing appear to compress significantly better using the new version.

    The project requests this statement to be made:

    I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to choose either at their option.

    I would like to add that I do not believe the changes in question to be significant enough to warrant copyright.

    opened by anarchodin 1
  • Support ICO files with dimensions larger than 256

    Support ICO files with dimensions larger than 256

    Wikipedia claims that a value of 0 for the width or height in an image directory means 256 or more. This crate previously assumed it meant exactly 256. If anyone knows of a more definitive spec reference, that would be nice to include.

    Fixes #1836

    opened by fintelia 0
  • Some modern ico-formats will be rejected

    Some modern ico-formats will be rejected

    Hello,

    when i try to load: let img = image::open(&Path::new(&iconPath)).unwrap(); and the ico is an 512x512 or with an png in the stack it comes:

    thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Decoding(DecodingError { format: Exact(Ico), underlying: Some(ImageEntryDimensionMismatch { format: Png, entry: (256, 256), image: (512, 512) }) })', src\EXE.rs:40:54
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
    

    the PNG entry and the image entry are correct modern ico-spezifications

    thx

    opened by cyberpunkbln 5
  • Fails to decode tga image with

    Fails to decode tga image with "Image is too large" error

    Expected

    The image I've attached should load

    Actual behaviour

    I'm getting an error: "Image is too large"

    Reproduction steps

    Simply load the attached image with image.

    Crossbow_Ao.tga.zip

    opened by FredrikNoren 2
  • Access ICC profile data

    Access ICC profile data

    I would like to be able to convert images to sRGB (or other profiles in the future.) The specific png and jpeg-decoder crates support accessing icc_profile() that I can use with the lcms2 crate but, they do not support DynamicImage. The image crate does not support accessing the color profile information but supports DynamicImage.

    My specific use case for this functionality is writing a new image viewer for GNOME.

    This might be more generally applicable to other features like EXIF block data or background colors (bKGD).

    Draft

    1. Add those features to ImageDecoder returning None if not applicable.
    2. Add DynamicImage support to the specific crates. Webp already has that.
    3. Add those features to the format-specific decoders like image::codecs::png::PngDecoder. However, not sure if that's possible for EXIF where the end of the file is relevant?
    opened by sophie-h 1
  • Implement compression control in other formats

    Implement compression control in other formats

    I would like to be able to write JPGs with adjustable compression. #1208 enables this for PNG, other formats that support compression as a tweakable parameter should have the same API.

    opened by ror6ax 0
Owner
image-rs
Image libraries for Rust
image-rs
PNG decoding and encoding library in pure Rust

PNG Decoder/Encoder PNG decoder/encoder in pure Rust. It contains all features required to handle the entirety of the PngSuite by Willem van Schack. p

image-rs 247 Dec 25, 2022
Rust library to get image size and format without loading/decoding

imageinfo-rs Rust library to get image size and format without loading/decoding. The imageinfo don't get image format by file ext name, but infer by f

xiaozhuai, Weihang Ding 47 Dec 30, 2022
Takes a folder of images (as a palette), and an image, and figures out how to tile the palette to resemble the image!

Takes a folder of images (as a palette), and an image, and figures out how to tile the palette to resemble the image!

Jacob 258 Dec 30, 2022
CLI and utilities for converting media files (images/videos) to ascii outputs (output media file or print to console)

CLI and utilities for converting media files (images/videos) to ascii outputs (output media file or print to console). Supports most standard image formats, and some video formats.

Michael 30 Jan 1, 2023
A Rust library for calculating perceptual hash values of images

img_hash Now builds on stable Rust! (But needs nightly to bench.) A library for getting perceptual hash values of images. Thanks to Dr. Neal Krawetz f

Austin Bonander 264 Dec 9, 2022
Zero dependency images (of chaos) in Rust

bifurcate-rs Zero dependency images (of chaos) in Rust To run: time cargo run --release > img.pgm To convert from PGM to PNG using Image Magick: conve

Stephen Merity 32 Nov 17, 2021
tai (Terminal Ascii Image) tool to convert images to ascii written in Rust

TAI Terminal Ascii Image A tool to convert images to ascii art written in Rust ?? Notes This tool is still in development stage. Contributions All Con

Mustafa Salih 258 Dec 5, 2022
Converts images into textual line art.

img2utf Transform images to textual line art! Images require pre-processing to come out nice. It's expected that users will do the following: Apply ga

Lee 149 Dec 10, 2022
Automated image compression for efficiently distributing images on the web.

Imager Apparently this project made it into the GitHub Archive Program. About Imager is a tool for automated image compression, and can competitively

Imager IO 487 Dec 25, 2022
Convert Sketchbook Tiff Files to Open Raster Images

SketchbookTiffConverter Convert Sketchbook Tiff Files to Open Raster Images and retain layer information. This is a command line program that will con

Phil Spindler 3 Nov 2, 2021
Fetch original quality URLs for images posted to a Twitter account

twitter-images Fetches the last tweets of a given account, then prints original quality URLs for all image tweets. Useful for archiving image content

Harsh Shandilya 6 Dec 23, 2022
Simple CLI program to generate zoomable tiled images

zoomtiler Simple CLI program to generate deepzoom zoomable tiled images. The input can either be a single image or multiple images of the same height,

Matthieu Pizenberg 3 Mar 14, 2022
😱 Dead fast thumbnail library for browser and NodeJs! Built with Rust 🦀 and WebAssembly 🕸

thumbo-core ?? Dead fast thumbnail library for browser and NodeJs Built with Rust ?? & WebAssembly ?? ?? About thumbo-core is a thubnail library for b

Victor Aremu 12 Dec 2, 2022
Classical Rainbow Triangle using Rust and Vulkan via vulkano bindings

Vulkano Rainbow Triangle Classical Rainbow Triangle using Rust and Vulkan via vulkano bindings. Based on the vulkano triangle example Quick Start $ ca

Tsoding 14 Dec 30, 2022
A simple command-line utility (and Rust crate!) for converting from a conventional image file (e.g. a PNG file) into a pixel-art version constructed with emoji

EmojiPix This is a simple command-line utility (and Rust crate!) for converting from a conventional image file (e.g. a PNG file) into a pixel-art vers

Michael Milton 22 Dec 6, 2022
@Buildspace project creating a Web3 Solana Dapp with React and Rust

buildspace Solana GIF Portal Project Welcome ?? To get started with this course, clone this repo and follow these commands: Run npm install at the roo

Nick Fragakis 2 Jul 22, 2022
Rust Lean Image Viewer - Fast and configurable image viewer inspired by JPEGView by David Kleiner

Rust Lean Image Viewer - Fast and configurable image viewer inspired by JPEGView by David Kleiner

3top1a 4 Apr 9, 2022
A collection of mapping suites and useful algorithms, implemented in pure Rust

Unstable API Note that this crate is in early development, breaking API changes are to be expected. Usage Add this to your Cargo.toml: [dependencies]

Emily Matheys 7 Aug 31, 2023
Convert and save photomode screenshots from Red Dead Redemption 2 to JPEG format.

RDR2 Screenshot converter Convert and save photomode screenshots from Red Dead Redemption 2 to JPEG format. QuickStart Just download the executable fi

Timofey Gelazoniya 12 Sep 29, 2022