Москва: проверенные б/у ноутбуки с гарантией и проверкой перед оплатой
+7 906 722-94-45

Главная → Статьи → Обработка изображений: ресайз, форматы и EXIF

Обработка изображений на сервере: ресайз, WebP и EXIF

Обработка изображений: Pillow, ресайз с сохранением пропорций, WebP и AVIF, удаление EXIF, защита от image bomb и вынос в очередь.

Прямой ответ

Обработка изображений на сервере решает три задачи: привести файл к нужному размеру, выбрать эффективный формат и удалить лишние метаданные. Все три выполняются одной библиотекой, но каждая имеет подводные камни.

Базовый ресайз на Pillow:

from PIL import Image, ImageOps

def make_thumbnail(src: str, dst: str, size: int = 512) -> None:
    with Image.open(src) as im:
        im = ImageOps.exif_transpose(im)        # учёт ориентации из EXIF
        im.thumbnail((size, size), Image.LANCZOS)
        if im.mode in ("RGBA", "P"):
            im = im.convert("RGB")
        im.save(dst, "WEBP", quality=82, method=6)

Три важных детали в этих строках:

  1. exif_transpose до ресайза. Камера часто хранит изображение повёрнутым, а поворот задаётся тегом ориентации. Без этой строки миниатюра получится боком, хотя в браузере оригинал выглядит нормально.
  2. thumbnail сохраняет пропорции. Метод resize с явными размерами растягивает изображение, если соотношение сторон не совпадает.
  3. Конвертация в RGB перед JPEG/WebP. Формат JPEG не поддерживает альфа-канал, и сохранение RGBA приводит к ошибке или чёрному фону.

Выбор формата:

Формат Когда применять
WebP Фотографии и графика для веба: заметно меньше JPEG при сопоставимом качестве
AVIF Ещё сильнее сжимает, но медленнее кодируется и поддерживается не везде
JPEG Совместимость по умолчанию, фотографии без прозрачности
PNG Графика с прозрачностью, скриншоты, логотипы
SVG Векторная графика, иконки

Список поддерживаемых браузерами форматов приведён в MDN.

EXIF нужно удалять. Метки времени, модель устройства и, что важнее, координаты GPS сохраняются в файле и уходят вместе с ним. Пересохранение изображения без копирования метаданных убирает их:

im.save(dst, "WEBP", quality=82)   # EXIF не переносится, если не передан явно

Практика: безопасная и предсказуемая обработка

1. Остерегайтесь image bomb. Небольшой по объёму файл может описывать изображение огромных размеров, и при распаковке память процесса исчерпывается. Pillow ограничивает это через MAX_IMAGE_PIXELS:

from PIL import Image
Image.MAX_IMAGE_PIXELS = 100_000_000      # 100 млн пикселей

При превышении Pillow выдаёт предупреждение DecompressionBombWarning, а при двукратном превышении — исключение. Проверять размеры нужно до открытия файла.

2. Проверяйте тип по содержимому, а не по расширению. Файл с именем photo.jpg может быть чем угодно. Определение реального формата даёт Image.open(...).format или проверка магических байтов — см. статью про безопасность загрузок.

3. Выносите обработку в очередь. Кодирование изображения — задача с высокой нагрузкой на CPU. Обработка в обработчике HTTP-запроса блокирует воркер; при нескольких одновременных загрузках задержка растёт у всех. Очередь разгружает приём — см. статью про надёжность очередей.

4. Учитывайте расход памяти. Изображение 8000×6000 пикселей в RGB занимает около 144 МБ в распакованном виде независимо от размера файла. Лимит памяти контейнера должен это учитывать — см. статью про requests и limits.

5. Не храните оригинал в публичном доступе. Пользователю нужна миниатюра; оригинал остаётся приватным и отдаётся по подписанной ссылке.

6. Сохраняйте несколько размеров сразу. Генерация миниатюры по требованию при каждом запросе тратит CPU; предварительная подготовка наборов размеров дешевле.

7. Фиксируйте качество кодирования. Значение quality влияет на объём сильнее, чем размер в пикселях. Диапазон 80–85 для WebP даёт хорошее соотношение.

Рекомендации:

  1. Нормализуйте вход. Приводите всё к одному формату и цветовому пространству, иначе результат зависит от того, чем снят оригинал.
  2. Обрабатывайте ошибки формата явно. Повреждённый файл должен давать понятный ответ 422, а не 500.
  3. Используйте LANCZOS для уменьшения. Метод влияет на резкость результата; NEAREST даёт заметные артефакты.
  4. Логируйте размеры и объём до и после. Это единственный способ заметить, что качество кодирования изменилось после обновления библиотеки.
  5. Проверяйте результат на реальных файлах. Тест на одном изображении не выявляет проблемы с CMYK, палитрой или анимированными форматами.

Практический сценарий: часть миниатюр получалась повёрнутой и с чёрным фоном

Контекст: сервис генерировал миниатюры загруженных фотографий. Пользователи жаловались, что часть изображений отображается боком, а часть имеет чёрный фон вместо белого.

  1. Диагностика поворота. Проблемные файлы имели тег ориентации EXIF, отличный от 1. Исходный код открывал изображение и сразу уменьшал его, поэтому поворот не применялся, а браузер при показе оригинала поворачивал его сам — отсюда расхождение.
  2. Диагностика фона. Файлы с альфа-каналом сохранялись в JPEG, и прозрачные области заполнялись чёрным.
  3. Действия. (а) Добавили ImageOps.exif_transpose до ресайза; (б) для форматов без поддержки прозрачности ввели наложение на белый фон вместо простого convert("RGB"); (в) перевели вывод на WebP, который поддерживает прозрачность; (г) установили Image.MAX_IMAGE_PIXELS и проверку размеров до обработки; (д) перенесли генерацию миниатюр в фоновую очередь, поскольку кодирование занимало до двух секунд и блокировало обработчик запросов.
  4. Результат. Поворот и фон стали корректными для всех проверенных форматов; время ответа на загрузку сократилось с двух секунд до 120 миллисекунд, потому что обработка перестала выполняться синхронно.

Вывод: проблемы обработки изображений почти всегда связаны с метаданными и цветовыми моделями, а не с самим алгоритмом ресайза. Ориентация из EXIF и альфа-канал требуют явной обработки, иначе результат зависит от исходного файла.

FAQ

Нужно ли хранить оригинал, если есть миниатюра? Да, если возможны повторная обработка или показ в большем размере. Миниатюра необратимо теряет данные.

Почему WebP лучше JPEG для веба? При сопоставимом визуальном качестве WebP даёт меньший объём, что сокращает время загрузки страницы. Поддержка в браузерах стала повсеместной.

Удаляет ли ресайз метаданные автоматически? Пересохранение без явной передачи метаданных их не копирует, поэтому координаты GPS исчезают. Полагаться на это стоит только после проверки конкретного формата.

Можно ли обрабатывать изображения без сервера? Да, часть операций выполняется на стороне клиента, но проверка содержимого и защита от вредоносных файлов остаются задачей сервера.

Источники: Pillow docs, MDN (image types), Exiv2 (теги EXIF) — ссылки в шапке.