Библиотека image для Rust: полное руководство
Библиотека image — это основная и наиболее популярная библиотека для работы с изображениями в экосистеме Rust. Она предоставляет мощный, безопасный и высокопроизводительный инструментарий для загрузки, обработки, анализа и сохранения растровых изображений. В отличие от многих C/C++ аналогов, image написана на чистом Rust, что гарантирует безопасность памяти и отсутствие утечек, характерных для низкоуровневых библиотек.
Зачем нужна эта библиотека? В современном мире обработка изображений требуется повсеместно: от веб-сервисов (генерация превью, наложение водяных знаков) до десктопных приложений (фоторедакторы, просмотрщики) и даже встраиваемых систем (компьютерное зрение на Raspberry Pi). image позволяет решать эти задачи без привязки к внешним C-библиотекам (как libpng или libjpeg), что упрощает сборку проекта и делает его кроссплатформенным "из коробки".
Библиотека поддерживает десятки форматов (PNG, JPEG, GIF, BMP, TIFF, WebP, ICO и другие), предоставляет доступ к отдельным пикселям, умеет изменять размеры, обрезать, вращать, инвертировать цвета и применять фильтры. В основе лежит трейт GenericImageView, который позволяет единообразно работать с любым типом изображения. Благодаря дизайну Rust, вы получаете максимальную производительность без ущерба для безопасности.
Установка
Для добавления библиотеки image в проект на Rust необходимо добавить её в файл Cargo.toml:
[dependencies]
image = "0.25"
После этого выполните команду cargo build. Cargo автоматически загрузит библиотеку и все её зависимости. Для работы с конкретными форматами (например, WebP или AVIF) могут потребоваться дополнительные feature-флаги, но для базового использования достаточно стандартной конфигурации.
Быстрый старт
Минимальный рабочий пример — загрузить изображение, изменить его размер и сохранить:
use image::{GenericImageView, imageops};
fn main() -> Result<(), image::ImageError> {
// 1. Загружаем изображение из файла
let img = image::open("input.jpg")?;
// 2. Изменяем размер до 300x200 пикселей
let resized = imageops::resize(&img, 300, 200, imageops::FilterType::Lanczos3);
// 3. Сохраняем результат в PNG
resized.save("output.png")?;
println!("Изображение успешно обработано!");
Ok(())
}
Этот код открывает файл input.jpg, изменяет его размер до 300x200 пикселей с использованием фильтра Lanczos3 (один из самых качественных) и сохраняет результат как output.png. Обратите внимание на обработку ошибок через Result — это идиоматичный подход в Rust.
Основные методы и функции
1. image::open
Сигнатура: pub fn open<P: AsRef<Path>>(path: P) -> ImageResult<DynamicImage>
Описание: Загружает изображение из файла, автоматически определяя формат по расширению или содержимому. Возвращает DynamicImage — перечисление, которое может содержать изображение любого поддерживаемого типа (Rgb8, Rgba8, Gray8 и т.д.).
Пример:
match image::open("photo.png") {
Ok(img) => println!("Изображение загружено, размер: {}x{}", img.width(), img.height()),
Err(e) => eprintln!("Ошибка загрузки: {}", e),
}
2. DynamicImage::to_rgb8 и to_rgba8
Сигнатура: pub fn to_rgb8(&self) -> ImageBuffer<Rgb<u8>, Vec<u8>>
Описание: Конвертирует динамическое изображение в конкретный тип пикселей. to_rgb8 — в RGB (3 канала), to_rgba8 — в RGBA (4 канала с альфа-каналом). Это необходимо для доступа к пикселям или применения некоторых операций.
Пример:
let img = image::open("input.png").unwrap();
let rgb_img = img.to_rgb8();
let pixel = rgb_img.get_pixel(10, 20);
println!("Пиксель (10,20): R={}, G={}, B={}", pixel[0], pixel[1], pixel[2]);
3. GenericImageView::get_pixel
Сигнатура: fn get_pixel(&self, x: u32, y: u32) -> Self::Pixel
Описание: Возвращает значение пикселя по координатам (x, y). Координаты отсчитываются от верхнего левого угла. Тип пикселя зависит от типа изображения (например, Rgba<u8>).
Пример:
let img = image::open("photo.jpg").unwrap();
let pixel = img.get_pixel(0, 0); // Первый пиксель
println!("RGBA: {:?}", pixel.0); // Вывод: [R, G, B, A]
4. GenericImageView::width и height
Сигнатура: fn width(&self) -> u32 и fn height(&self) -> u32
Описание: Возвращают ширину и высоту изображения в пикселях. Полезно для итерации по всем пикселям или проверки размеров перед обработкой.
Пример:
let img = image::open("test.png").unwrap();
println!("Размер: {}x{}", img.width(), img.height());
5. imageops::resize
Сигнатура: pub fn resize<I: GenericImageView>(image: &I, nwidth: u32, nheight: u32, filter: FilterType) -> ImageBuffer<I::Pixel, Vec<I::Subpixel>>
Описание: Изменяет размер изображения до указанных ширины и высоты. Параметр filter определяет алгоритм интерполяции: Nearest (быстрый, но низкое качество), Triangle, CatmullRom, Lanczos3 (самый качественный, но медленный).
Пример:
use image::imageops;
let img = image::open("large.jpg").unwrap();
let thumbnail = imageops::resize(&img, 150, 150, imageops::FilterType::Nearest);
thumbnail.save("thumb.jpg").unwrap();
6. imageops::crop
Сигнатура: pub fn crop<I: GenericImageView>(image: &I, x: u32, y: u32, width: u32, height: u32) -> SubImage<&I>
Описание: Вырезает прямоугольную область из изображения, начиная с координат (x, y) и заданной ширины/высоты. Возвращает SubImage, который можно сохранить или преобразовать в ImageBuffer.
Пример:
let img = image::open("photo.jpg").unwrap();
let cropped = imageops::crop(&img, 100, 50, 200, 150);
cropped.to_image().save("cropped.png").unwrap();
7. imageops::rotate90, rotate180, rotate270
Сигнатура: pub fn rotate90<I: GenericImageView>(image: &I) -> ImageBuffer<I::Pixel, Vec<I::Subpixel>>
Описание: Поворачивают изображение на 90, 180 или 270 градусов соответственно. Работают без потери качества (не используют интерполяцию).
Пример:
let img = image::open("portrait.jpg").unwrap();
let rotated = imageops::rotate90(&img);
rotated.save("landscape.jpg").unwrap();
8. imageops::flip_horizontal и flip_vertical
Сигнатура: pub fn flip_horizontal<I: GenericImageView>(image: &I) -> ImageBuffer<I::Pixel, Vec<I::Subpixel>>
Описание: Отражают изображение по горизонтали (зеркально) или по вертикали. Полезно для создания симметричных эффектов или коррекции ориентации.
Пример:
let img = image::open("mirror.png").unwrap();
let flipped = imageops::flip_horizontal(&img);
flipped.save("flipped.png").unwrap();
9. imageops::grayscale
Сигнатура: pub fn grayscale<I: GenericImageView>(image: &I) -> GrayImage
Описание: Преобразует цветное изображение в оттенки серого. Использует стандартные коэффициенты яркости (0.299R + 0.587G + 0.114B).
Пример:
let img = image::open("colorful.jpg").unwrap();
let gray = imageops::grayscale(&img);
gray.save("black_and_white.jpg").unwrap();
10. imageops::blur
Сигнатура: pub fn blur<I: GenericImageView>(image: &I, sigma: f32) -> ImageBuffer<I::Pixel, Vec<I::Subpixel>>
Описание: Применяет гауссово размытие с заданным радиусом (sigma). Чем больше sigma, тем сильнее размытие. Используется для сглаживания, шумоподавления или создания эффекта "боке".
Пример:
let img = image::open("sharp.jpg").unwrap();
let blurred = imageops::blur(&img, 5.0);
blurred.save("blurred.jpg").unwrap();
11. imageops::contrast
Сигнатура: pub fn contrast<I: GenericImageView>(image: &I, contrast: f32) -> ImageBuffer<I::Pixel, Vec<I::Subpixel>>
Описание: Регулирует контрастность изображения. Значение contrast: 0.0 — полностью серое изображение, 1.0 — оригинал, >1.0 — увеличение контраста.
Пример:
let img = image::open("flat.jpg").unwrap();
let high_contrast = imageops::contrast(&img, 2.0);
high_contrast.save("contrast.jpg").unwrap();
12. ImageBuffer::save
Сигнатура: pub fn save<Q: AsRef<Path>>(&self, path: Q) -> ImageResult<()>
Описание: Сохраняет изображение в файл. Формат определяется по расширению файла. Поддерживаются PNG, JPEG, BMP, GIF, TIFF и другие.
Пример:
let img = image::open("source.png").unwrap();
img.save("copy.jpg").unwrap(); // Конвертация из PNG в JPEG
Реальный практический пример
Создадим утилиту для пакетной обработки изображений: изменение размера, добавление водяного знака и конвертация в черно-белый формат.
use image::{GenericImageView, imageops, Rgba};
use std::path::Path;
use std::fs;
/// Функция для наложения водяного знака (текстового) в правом нижнем углу
fn add_watermark(img: &image::DynamicImage, text: &str) -> image::DynamicImage {
let mut base = img.to_rgba8();
let (width, height) = base.dimensions();
// Простейшая реализация: рисуем прямоугольник с текстом (пиксельная манипуляция)
// В реальном проекте используйте библиотеку imageproc для рисования текста
let watermark_height = 30;
let watermark_y = height.saturating_sub(watermark_height + 10);
let watermark_x = 10;
for y in watermark_y..height {
for x in watermark_x..(watermark_x + text.len() as u32 * 8).min(width) {
let pixel = base.get_pixel_mut(x, y);
// Затемняем пиксель (имитация полупрозрачного фона)
*pixel = Rgba([
pixel[0].saturating_sub(30),
pixel[1].saturating_sub(30),
pixel[2].saturating_sub(30),
200, // Альфа-канал
]);
}
}
image::DynamicImage::ImageRgba8(base)
}
fn process_image(input_path: &Path, output_dir: &Path, max_width: u32) -> Result<(), Box<