Конвертация изображений: почему Rust в 8.5× быстрее bash на той же libwebp
Rust-утилита для конвертации между jpg, png и webp — заменяет bash + ImageMagick, не требует сети, работает в single-file режиме для встраивания в pipeline.
Rust-утилита для конвертации между jpg, png и webp — заменяет bash + ImageMagick, не требует сети, работает в single-file режиме для встраивания в pipeline.
Все имена хостов, баз, топиков и учётные данные в примерах — вымышленные. Совпадения с реальными системами случайны.
Bash + ImageMagick конвертирует 50 JPG в WebP за 10.09 секунды — через ~100 процессов (один identify на файл, один magick на файл, плюс шеллы для grep/sort/rm). Rust-бинарь делает ту же работу за 1.18 секунды — через 1 процесс с параллелизацией по ядрам. Это не 8.5× магия, это отсутствие накладных расходов на запуск ~99 процессов.
fast-image-converter — это автономный Rust CLI для конвертации изображений между jpg, png и webp. Заменяет bash + ImageMagick там, где 100 процессов на 50 файлов перестали быть незаметными, и не делает вид, что решает задачи вне своей зоны — анимацию, ICC-трансформации, сетевые источники.
Шесть пайплайнов — все комбинации между тремя форматами. По умолчанию (без флагов) работает jpg → webp.
| Пайплайн | Quality учитывается |
|---|---|
jpg → webp (по умолчанию) |
да |
png → webp |
да |
webp → jpg |
да |
png → jpg |
да |
webp → png (без потерь) |
нет |
jpg → png (без потерь) |
нет |
Контроль качества — --quality <1..100> для lossy-пайплайнов (по умолчанию 85). Lossless-пайплайны игнорируют.
Политики изменения размера — --resize принимает четыре формы:
| Форма | Что делает |
|---|---|
none |
без изменения размера |
cap=<W> |
масштабирует более широкую сторону до ≤ <W> px, сохраняя соотношение сторон |
auto:portrait=<W>,landscape=<H> |
лимиты по ориентации (v0 baseline: 800/1000) |
fit=<mode> long-edge=<N> |
contain / cover / stretch под заданный размер |
Два режима работы:
| Режим | Что делает |
|---|---|
| Batch | Берёт директорию, конвертирует все файлы в ней. По умолчанию удаляет исходники после успешной конверсии; флаг --keep-source оставляет |
| Single-file | Читает один файл из stdin, пишет результат в stdout — для встраивания в другие пайплайны |
Минимальный пример:
# partial — фрагмент CLI-инвокации, runnable на собранном бинаре.
cat input.jpg | ./target/release/fast-image-converter \
--single-file --output-format webp \
> output.webp
Бинарь — один автономный файл, ~2.4 MiB stripped, без сетевых вызовов, без телеметрии, без внешних сервисов. Линкуется с libwebp напрямую и со статической MozJPEG, чтобы deploy не зависел от системных библиотек.
Совпадение выхода — закодированные байты совпадают с эталонным энкодером libwebp до 0.1% допуска. Это обеспечивается golden-batch регрессионным тестом в репозитории (tests/golden_v0.rs), не «примерно одинаково».
Полный список флагов — --help. Полный контракт (коды выхода, каналы, граничные случаи) — в docs/integration-contract.md репозитория.
50 файлов / 3 МБ JPG смешанной ориентации на 12-ядерном хосте с libwebp 1.6.0:
| Пайплайн | bash + ImageMagick | fast-image-converter | Ускорение |
|---|---|---|---|
jpg → webp (по умолчанию) |
10.09 s | 1.18 s | 8.5× |
Выходные байты совпадают с эталонным энкодером libwebp до 0.1% допуска — обеспечивается golden-batch регрессионным тестом (tests/golden_v0.rs), не «примерно одинаково».
От чего зависят цифры:
От чего не зависят: накладные расходы на запуск процессов. Их больше нет в принципе — это и есть основная причина ускорения.
Перемеряйте на своём хосте:
time ./target/release/fast-image-converter /path/to/your/jpg-batch
На 500 файлах и 10к файлах цифры будут другие, но порядок сохранится: один процесс с параллелизацией выигрывает у цепочки identify + magick на каждом файле.
Демо — image-converter.elrise.io: тот же бинарь под веб-обёрткой. Можно пощупать пайплайны и resize без сборки.
Репозиторий — github.com/elriseio/fast-image-converter.
Что внутри репо, если решите использовать:
| Документ | Зачем |
|---|---|
README.md |
Быстрый старт, CLI-флаги, prereqs, устранение неполадок |
docs/integration-contract.md |
Контракт для серверных вызывающих: stdin/stdout, коды выхода, мэппинг моделей отказов |
docs/RUNBOOK.md |
Триаж в первые 30 минут, ошибки сборки, инциденты на продакшене |
docs/architecture.md |
C4-обзор архитектуры для тех, кто хочет понять как устроено внутри |
tests/golden_v0.rs |
Golden-batch регрессия: 10 эталонных файлов, пере-записываются при смене libwebp |
Сборка (Rust 1.75+ и libwebp dev headers):
# partial — фрагмент CLI-команд; runnable на Ubuntu/Debian/Arch/macOS хосте.
git clone https://github.com/elriseio/fast-image-converter
cd fast-image-converter
cargo build --release
# → target/release/fast-image-converter
Что инструмент не делает (чтобы не тратить время на оценку): GIF/TIFF/AVIF (Wave 2 в Roadmap, не реализовано), distributed batch (single-host multi-core), in-process library API (бинарь — единственная публичная поверхность), анимированный GIF/APNG (только первый кадр), явные ICC-трансформации (проходят через image crate defaults).