Обработка изображений на Rust: resize и crop
Rust — это современный системный язык программирования, который всё чаще применяется для задач, требующих высокой производительности и надёжности. Обработка изображений не исключение. В этой статье мы рассмотрим две ключевые операции — изменение размера (resize) и обрезку (crop) — с использованием экосистемы Rust. Основные библиотеки: image (загрузка, сохранение, базовые манипуляции) и imageproc (продвинутая обработка).
Почему Rust для работы с изображениями?
Rust предлагает:
- Безопасную работу с памятью — отсутствие утечек и гонок данных.
- Максимальную производительность — сравнимую с C/C++.
- Богатую экосистему — crate
imageподдерживает JPEG, PNG, GIF, BMP, WEBP и другие форматы. - Параллелизм — легко масштабировать обработку на многоядерных процессорах.
Установка зависимостей
Добавьте в Cargo.toml:
[dependencies]
image = "0.25"
imageproc = "0.25" # для продвинутых фильтров (опционально)
Актуальные версии уточняйте на crates.io.
Загрузка и сохранение изображения
Начнём с базового примера — открыть файл и сохранить его копию:
use image::{GenericImageView, ImageFormat};
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Загружаем изображение
let img = image::open("input.jpg")?;
// Выводим размеры
println!("Ширина: {}, Высота: {}", img.width(), img.height());
// Сохраняем в другом формате
img.save("output.png")?;
Ok(())
}
Метод image::open автоматически определяет формат по расширению или содержимому файла.
Изменение размера (resize)
Функция resize принимает новые ширину и высоту, а также фильтр интерполяции. Доступные фильтры: Nearest, Triangle, CatmullRom, Gaussian, Lanczos3 и другие.
use image::{imageops::FilterType, GenericImageView};
fn resize_image(path: &str, new_width: u32, new_height: u32) -> Result<(), Box<dyn std::error::Error>> {
let img = image::open(path)?;
// Изменяем размер с фильтром Lanczos3 (высокое качество)
let resized = img.resize(new_width, new_height, FilterType::Lanczos3);
// Сохраняем результат
resized.save("resized.jpg")?;
println!("Размер изменён: {}x{} → {}x{}", img.width(), img.height(), new_width, new_height);
Ok(())
}
Совет: Для быстрой обработки используйте FilterType::Nearest (нет интерполяции), для максимального качества — Lanczos3.
Пропорциональное изменение размера
Чтобы сохранить соотношение сторон, используйте resize_to_fill (заполняет область) или resize_to_fit (вписывает в прямоугольник):
use image::imageops::FilterType;
fn resize_proportional(path: &str, max_width: u32, max_height: u32) -> Result<(), Box<dyn std::error::Error>> {
let img = image::open(path)?;
// Вписать в прямоугольник (сохраняя пропорции)
let fitted = img.resize_to_fit(max_width, max_height, FilterType::Triangle);
fitted.save("fitted.jpg")?;
// Заполнить область (обрежет лишнее)
let filled = img.resize_to_fill(max_width, max_height, FilterType::Triangle);
filled.save("filled.jpg")?;
Ok(())
}
Обрезка изображения (crop)
Обрезка выполняется через метод crop, который принимает координаты верхнего левого угла (x, y) и размеры области:
use image::GenericImageView;
fn crop_image(path: &str, x: u32, y: u32, width: u32, height: u32) -> Result<(), Box<dyn std::error::Error>> {
let img = image::open(path)?;
// Обрезаем область (x, y, ширина, высота)
let cropped = img.crop(x, y, width, height);
// Сохраняем
cropped.save