user@elrise.io:~/fast-image-converter
· 4 min

Конвертация изображений: почему Rust в 8.5× быстрее bash на той же libwebp

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 учитывается
jpgwebp (по умолчанию) да
pngwebp да
webpjpg да
pngjpg да
webppng (без потерь) нет
jpgpng (без потерь) нет

Контроль качества--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).