Working with Images in Rust: Overview of Libraries and Practical Examples
Rust is a modern systems programming language that is gaining popularity in areas requiring high performance and reliability. Image processing is no exception: the Rust ecosystem offers several mature libraries for loading, processing, converting, and analyzing images. In this article, we will look at the main tools: image, fast_image_resize, and photon-rs, and also provide code examples for typical tasks.
The Main Library: image
The image crate (version 0.25.x) is the de facto standard for working with images in Rust. It supports reading and writing many formats: PNG, JPEG, BMP, GIF, TIFF, WebP, and others. The library provides convenient data structures for representing images (DynamicImage, RgbImage, GrayImage) and a wide range of operations: resizing, cropping, rotating, filters, color space conversion.
Example of loading and saving an image with resizing:
use image::{DynamicImage, GenericImageView, imageops::FilterType};
fn resize_image(input_path: &str, output_path: &str, new_width: u32, new_height: u32) { let img = image::open(input_path).expect("Failed to open image"); let resized = img.resize_exact(new_width, new_height, FilterType::Lanczos3); resized.save(output_path).expect("Failed to save image"); println!("Image resized and saved to {}", output_path);}
fn main() { resize_image("input.jpg", "output.png", 800, 600);}The image library also supports working with pixels directly. For example, you can access each pixel and change its color:
use image::{GenericImage, Rgba};
fn invert_colors(path: &str) { let mut img = image::open(path).expect("Error opening image"); for (x, y, pixel) in img.enumerate_pixels_mut() { let inverted = Rgba([ 255 - pixel[0], 255 - pixel[1], 255 - pixel[2], pixel[3], ]); img.put_pixel(x, y, inverted); } img.save("inverted.png").unwrap();}High-Performance Resizing: fast_image_resize
If your task is to repeatedly resize images with maximum speed, check out the fast_image_resize crate. It uses SIMD instructions (SSE, AVX2, NEON) and optimized algorithms (Lanczos, Catmull-Rom, Mitchell). The library works directly with raw pixel arrays, minimizing overhead.
Example of using fast_image_resize:
use fast_image_resize as fr;use image::GenericImageView;
fn resize_fast(input_path: &str, output_path: &str, new_width: u32, new_height: u32) { // Load image via image let img = image::open(input_path).expect("Error opening image"); let (width, height) = img.dimensions(); let rgba = img.to_rgba8();
// Create a view for fast_image_resize let src_view = fr::ImageView::new(&rgba, width, height, fr::PixelType::U8x4); let mut dst_image = fr::Image::new(new_width, new_height, fr::PixelType::U8x4); let mut dst_view = dst_image.view_mut();
// Configure the resizer let mut resizer = fr::Resizer::new(fr::ResizeAlg::Convolution(fr::FilterType::Lanczos3)); resizer.resize(&src_view, &mut dst_view).expect("Resize error");
// Save the result via image let result_img = image::RgbaImage::from_raw(new_width, new_height, dst_image.into_vec()).unwrap(); result_img.save(output_path).unwrap();}According to benchmarks, fast_image_resize can be 2-5 times faster than standard resizing