Fri Jun 26 2026 20:00:00 GMT-0400 (北美东部夏令时间)
Сжатие изображений в Python: Pillow, WebP и mozjpeg
Сжимайте изображения JPEG, PNG и WebP в Python с помощью Pillow, cwebp и mozjpeg. Настройте качество, используйте циклы для целевого размера и быстрый пакетный скрипт.

Последнее обновление: June 27, 2026
У вас есть папка с JPEG размером с камеру, этап сборки, который отправляет их пользователям, и бюджет веса страницы, который постоянно растет. Сжатие этих файлов вручную в редакторе изображений не масштабируется. Это руководство показывает точный Python, который вам нужен для уменьшения размера файлов JPEG, PNG и WebP по расписанию, в CI-задаче или внутри обработчика загрузки.
Краткий ответ: как сжать изображения в Python?
Откройте изображение с помощью Pillow, а затем сохраните его с правильными флагами формата. Для фотографий сохраняйте в формате JPEG с параметрами quality=80, optimize=True и progressive=True. Для получения самых маленьких современных файлов сохраняйте в WebP с параметрами quality=80, method=6. Для плоской графики и скриншотов используйте PNG и передайте параметр optimize=True.
from PIL import Image
def compress_jpeg(src, dst, quality=80):
img = Image.open(src)
if img.mode in ("RGBA", "P"):
img = img.convert("RGB")
img.save(dst, "JPEG", quality=quality, optimize=True, progressive=True)
Эта функция из четырех строк уже сокращает большинство JPEG-файлов с телефонов и DSLR на 40–70 процентов. Остальная часть этого руководства добавляет цели по размеру, поддержку WebP, mozjpeg и пакетный обработчик, чтобы вы могли указать его на каталог и забыть о нем.
Что вам понадобится перед началом работы?
Вам потребуется Python 3.9 или новее и Pillow — поддержикованная форк PIL. Pillow обрабатывает JPEG, PNG и WebP "из коробки" на каждой распространенной платформе.
pip install Pillow
Для получения минимального объема вы также захотите использовать два командных кодировщика, которые может вызвать Python: cwebp из libwebp и cjpeg из mozjpeg.
brew install webp mozjpeg # macOS; Linux: apt install webp, build mozjpeg
Проверьте назначение каждой части перед написанием кода:
- Pillow считывает и записывает каждый формат и выполняет изменение размера.
- cwebp создает самые компактные файлы WebP и предоставляет больше настроек, чем Pillow.
- mozjpeg перекодирует JPEG, делая их меньше стандартных libjpeg, используемых Pillow.
- Вспомогательный инструмент для отчетности, чтобы каждый запуск выводил количество сэкономленных байт.
Вот вспомогательный инструмент, используемый на протяжении всего этого руководства:
import os
def report(src, dst):
before, after = os.path.getsize(src), os.path.getsize(dst)
saved = (1 - after / before) * 100
print(f"{before/1024:.0f} KB -> {after/1024:.0f} KB ({saved:.0f}% smaller)")
Если вам нужна только одноразовая компрессия и вы не хотите ничего устанавливать, браузерный image compressor выполнит ту же работу для небольшого количества файлов.
Как сжать JPEG с помощью Pillow?
Три флага, которые важны для JPEG: quality, optimize и progressive. quality контролирует, сколько деталей отбрасывает кодировщик. optimize=True выполняет второй проход для создания меньшей таблицы Хаффмана (Huffman table). progressive=True переупорядочивает файл таким образом, что он рисуется сверху вниз с низким разрешением в первую очередь, что кажется быстрее при медленном соединении и обычно немного уменьшает размер файла.

Выбирайте значение качества в зависимости от места использования изображения, а не по единому глобальному числу:
| Quality value | Typical use | What to expect |
|---|---|---|
| 90-95 | Hero images, print proofs | Near-original, noticeably larger files |
| 75-85 | Most web photos | The safe default, large savings |
| 60-70 | Thumbnails and previews | Visible softening on fine detail |
| Below 50 | Avoid for photos | Blocky artifacts around edges |
Одна ловушка сбивает почти всех: у JPEG нет альфа-канала. Если вы открываете скриншот PNG с прозрачностью и сохраняете его напрямую в JPEG, Pillow выдает ошибку cannot write mode RGBA as JPEG. Вызов convert("RGB") в предыдущей функции сначала "выравнивает" прозрачность на сплошном фоне, поэтому он выполняется перед каждым сохранением JPEG.
Сжатие PNG и преобразование в WebP
PNG является алгоритмом без потерь (lossless), поэтому вы не можете обменять качество на размер так, как это делаете с JPEG. Что вы можете сделать, так это запустить оптимизатор Pillow и, для всего, что действительно является фотографией, полностью изменить формат.
def compress_png(src, dst):
Image.open(src).save(dst, "PNG", optimize=True, compress_level=9)
def to_webp(src, dst, quality=80):
img = Image.open(src)
img.save(dst, "WEBP", quality=quality, method=6)
method=6 указывает кодировщику WebP потратить больше времени на поиск меньшего файла. Это медленнее для каждого изображения, но стоит того на этапе сборки (build step). Для фотографии, которая начиналась как PNG размером 2 MB, WebP при качестве 80 обычно составляет менее 200 KB, выглядя при этом идентично в нормальном размере просмотра. По собственным измерениям Google, WebP примерно на 25–35% меньше, чем сопоставимый JPEG, согласно документации WebP.
Используйте эту таблицу, чтобы выбрать формат, а не угадывать:
| Содержимое источника | Лучший формат | Почему |
|---|---|---|
| Фотография | WebP или JPEG | Плавные градиенты хорошо сжимаются в режиме потерь (lossy) |
| Логотип, иконка, плоский UI | PNG или WebP lossless | Резкие края остаются четкими |
| Скриншот с текстом | PNG или lossless WebP | Избегает размытого текста от проходов с потерями |
| Изображение, требующее прозрачности | WebP или PNG | JPEG не может хранить альфа-канал |
Если вы все еще решаете между форматами для всего сайта, подробный обзор в WebP vs JPEG vs PNG освещает поддержку браузерами и компромиссы более глубоко.
Достижение целевого размера файла в цикле
«Сделать размер меньше 200 KB» — это распространенное требование от инструментов для электронной почты, маркетплейсов и лимитов загрузки CMS. Вы не можете выбрать число качества, которое достигнет заданного объема байт с первой попытки, потому что одно и то же качество дает очень разные размеры для сложной фотографии по сравнению с простой. Проходите циклом вниз от высокого качества до тех пор, пока не попадете в заданный лимит:
def compress_to_target(src, dst, target_kb=200, q=90, floor=35):
img = Image.open(src).convert("RGB")
while q >= floor:
img.save(dst, "JPEG", quality=q, optimize=True, progressive=True)
if os.path.getsize(dst) <= target_kb * 1024:
return q
q -= 5
return q
Аргумент floor останавливает цикл до того, как качество упадет в область смазывания. Если изображение не может достичь целевого значения выше этого предела, функция все равно возвращает результат, чтобы вы могли записать это и изменить размер изображения вместо более сильного сжатия. Для фиксированных бюджетов байт, таких как 100 KB или 50 KB, работает тот же цикл; в руководстве по сжатию изображений без потери качества объясняется, когда изменение размера превосходит понижение качества.
Как сделать JPEG меньше с помощью mozjpeg и cwebp?
Pillow сохраняет JPEG с помощью стандартного кодировщика libjpeg. mozjpeg — это drop-in кодировщик от Mozilla, который создает более мелкие файлы при том же визуальном качестве, обычно на 5–15 процентов. Поскольку Pillow не включает его в себя, вызовите бинарник cjpeg через subprocess. cjpeg от mozjpeg надежно считывает PPM, поэтому сначала выровняйте изображение с помощью Pillow:
import subprocess
def mozjpeg(src, dst, quality=80):
Image.open(src).convert("RGB").save("_tmp.ppm")
subprocess.run(["cjpeg", "-quality", str(quality), "-progressive",
"-optimize", "-outfile", dst, "_tmp.ppm"], check=True)
os.remove("_tmp.ppm")
Для WebP прямой вызов cwebp дает вам возможности, которые не предоставляет Pillow, такие как -m 6 для максимального усилия и -sharp_yuv для более чистых цветовых краев:
def cwebp(src, dst, quality=82):
subprocess.run(["cwebp", "-q", str(quality), "-m", "6",
"-sharp_yuv", src, "-o", dst], check=True)
Вот как сравниваются эти опции, чтобы вы могли решить, что установить:
| Tool | Best for | Trade-off |
|---|---|---|
| Pillow | Общее скриптование, любой формат | Не самый маленький JPEG |
| mozjpeg | Самый маленький прогрессивный JPEG | Дополнительный бинарник, цикл PPM |
| cwebp (libwebp) | Наиболее точный контроль WebP | Отдельный бинарник для установки |
| pillow-simd | Более быстрое изменение размера на x86 серверах | Сложнее в сборке и закреплении |
Проект mozjpeg документирует свой кодировщик и эталонные тесты в репозитории mozjpeg repository, а полный список опций сохранения Pillow находится в Pillow image file formats reference.
Как быстро выполнить пакетное сжатие папки?
Одно изображение — это легко. Настоящая задача — каталог из сотен файлов. Измените размер всего, что шире, чем требует ваш макет, затем сжимайте и выполняйте работу по потокам (threads), чтобы папка из 500 изображений обрабатывалась за секунды, а не минуты.

from pathlib import Path
from concurrent.futures import ThreadPoolExecutor
def batch(in_dir, out_dir, quality=80, max_width=1920):
out = Path(out_dir); out.mkdir(parents=True, exist_ok=True)
files = [p for p in Path(in_dir).iterdir()
if p.suffix.lower() in {".jpg", ".jpeg", ".png"}]
def work(p):
img = Image.open(p)
if img.width > max_width:
h = round(img.height * max_width / img.width)
img = img.resize((max_width, h), Image.LANCZOS)
img.convert("RGB").save(out / f"{p.stem}.jpg", "JPEG",
quality=quality, optimize=True, progressive=True)
with ThreadPoolExecutor() as pool:
list(pool.map(work, files))
return len(files)
Несколько практических замечаний по использованию этого в продакшене:
- Измените размер, прежде чем сжимать. Подача фотографии 6000 px в колонку шириной 1200 px приводит к потере байтов, которую никакие настройки качества не могут восстановить.
- Pillow освобождает GIL во время кодирования, поэтому здесь потоки обеспечивают реальное ускорение; для большинства папок вам не нужно использовать multiprocessing.
- Пишите в отдельную выходную директорию, чтобы неудачный запуск никогда не перезаписал ваши оригиналы.
- Используйте
Image.LANCZOSдля уменьшения масштаба; он лучше сохраняет резкость краев, чем фильтр по умолчанию. - Логируйте каждый файл с помощью вспомогательной функции
reportи сохраняйте оригиналы, пока не просмотрите образец визуально.
Если ваша задача повторяющаяся, а не разовая, шаблоны в batch image processing охватывают очереди, повторные попытки и правила именования. Для запуска без кода над zip-архивом файлов batch tool и image converter обрабатывают изменения формата без скрипта.
Какой подход следует выбрать?
Подбирайте метод под задачу, а не всегда хватайтесь за самый мощный инструмент:
- Изображения Web в процессе сборки: Pillow WebP с качеством 80 или cwebp с
-m 6, если вам нужны последние проценты. - Строгий бюджет байтов: цикл
compress_to_target, который переходит к изменению размера при достижении лимита. - Устаревшие конвейеры JPEG, которые нельзя изменить: перекодируйте вывод с помощью mozjpeg для бесплатной экономии.
- Скриншоты и диаграммы: используйте PNG с
optimize=Trueили без потерь WebP, если ваши браузеры это поддерживают.
Теория того, почему эти настройки работают, изложена в руководстве по сжатию изображений, где объясняется разница между lossy и lossless и то, как таблицы квантования влияют на результат.
Распространенные ошибки и способы их устранения
Несколько исключений вызывают большинство неудачных запусков:
cannot write mode RGBA as JPEG— вызовитеimg.convert("RGB")перед сохранением в JPEG.Image.DecompressionBombError— Pillow защищает от очень больших изображений; повышайте лимит только для файлов, которым вы доверяете, с помощьюImage.MAX_IMAGE_PIXELS = 200_000_000.OSError: broken data stream— исходный файл обрублен; установитеImageFile.LOAD_TRUNCATED_IMAGES = True, чтобы спасти его, а затем воспользуйтесь возможностью повторной загрузки.- Выходной файл больше входного — вы снова сохранили уже сжатый JPEG; сжимайте из оригинала, а не из предыдущего экспорта.
- Цвета выглядят блеклыми — источник CMYK был сохранен без преобразования; сначала вызовите
convert("RGB").
from PIL import Image, ImageFile
Image.MAX_IMAGE_PIXELS = 200_000_000
ImageFile.LOAD_TRUNCATED_IMAGES = True

Основной вывод
Pillow обрабатывает 90 percent сжатия изображений в Python с использованием трёх флагов JPEG и сохранения WebP. Используйте mozjpeg и cwebp, когда вам нужны максимально маленькие файлы; оборачивайте всё в цикл target-size, если задан бюджет байтов; и запускайте папку через потоковую пакетную функцию, когда увеличивается объем. Сохраняйте оригиналы, изменяйте размер перед сжатием и выводите экономию при каждом запуске, чтобы всегда знать, что на самом деле делает конвейер.
Используйте бесплатные инструменты, следуя руководству.
Продолжить чтение

Wed Mar 18 2026 20:00:00 GMT-0400 (北美东部夏令时间)
WebP Converter: Как преобразовать изображения в WebP (с реальными размерами)
Преобразуйте изображения JPEG и PNG в WebP для уменьшения размера веб-файлов. Мы предлагаем реальные размеры, команду cwebp, методы на Python и в браузере, а также стратегию резервного копирования JPEG/PNG.

Tue Mar 17 2026 20:00:00 GMT-0400 (北美东部夏令时间)
PNG в WebP: Как конвертировать и уменьшить размер изображений PNG
Конвертируйте PNG в WebP для уменьшения размера веб-файлов. Когда выигрывает lossless WebP, когда lossy, реальные размеры и команды cwebp/Pillow с резервным вариантом PNG.

Tue Mar 10 2026 20:00:00 GMT-0400 (北美东部夏令时间)
Оптимизация изображений для SEO: Практический чек-лист на 2026 год
Практический чек-лист по SEO для изображений на 2026 год: alt text, имена файлов, форматы, сжатие, Core Web Vitals, структурированные данные и измерение.