Pillow в Python: первые шаги с обработкой изображений
За полчаса вы научитесь открывать, изменять размер, обрезать, поворачивать и сохранять изображения в Python с помощью библиотеки Pillow — и поймёте, где новичок теряет качество.

К концу этого руководства у вас будет рабочий скрипт, который открывает изображение, уменьшает его до нужного размера, обрезает лишнее, поворачивает и сохраняет в JPEG или PNG. На это уйдёт минут двадцать-тридцать, если Python уже установлен. Работаем с Pillow 10.x — это активно поддерживаемый форк старой библиотеки PIL, которую саму по себе ставить не нужно и уже нельзя.
Что нужно иметь до начала
- Python 3.8 или новее. Проверьте командой
python --version(на некоторых системахpython3 --version). Pillow 10.x требует Python 3.8+. - Установленный Pillow. Ставится через pip:
pip install Pillow. Важно: пакет называется именноPillowс большой буквы, а импортируется какPIL— это наследие старой библиотеки. - Одно-два тестовых изображения в той же папке, где лежит скрипт. Пусть будет, например,
photo.jpg.
Проверьте, что установка прошла. Запустите в терминале Python и выполните:
import PIL
print(PIL.__version__)Если вывелся номер версии вроде 10.4.0 и не появилось ошибки ModuleNotFoundError — всё готово.
Шаг 1. Открыть изображение и узнать его свойства
Всё в Pillow начинается с объекта Image. Функция Image.open() не читает весь файл сразу — она откладывает загрузку пикселей до момента, когда они реально понадобятся.
from PIL import Image
# Открываем файл из текущей папки
image = Image.open("photo.jpg")
# Смотрим базовые свойства
print(image.size) # кортеж (ширина, высота) в пикселях
print(image.format) # 'JPEG'
print(image.mode) # 'RGB' — цветовая модельПроверка: в консоли должны появиться размеры вроде (1920, 1080), формат и режим. Если вместо этого вы видите FileNotFoundError, значит скрипт запущен не из той папки, где лежит photo.jpg.
Что такое mode
Mode — цветовая модель изображения. Самые частые: RGB (три канала: красный, зелёный, синий), RGBA (те же плюс альфа-канал прозрачности), L (оттенки серого, один канал). От режима зависит, какие операции допустимы: например, сохранить RGBA в JPEG нельзя — JPEG не поддерживает прозрачность.
Шаг 2. Изменить размер
Метод resize() принимает кортеж (ширина, высота) и возвращает новое изображение — исходное не меняется. Если задать размеры на глаз, картинка растянется. Чтобы сохранить пропорции, считайте вторую сторону сами или используйте thumbnail().
from PIL import Image
image = Image.open("photo.jpg")
# Точный размер — пропорции могут исказиться
resized = image.resize((800, 600))
resized.save("resized.jpg")
# thumbnail меняет изображение на месте и сохраняет пропорции
# 800x600 здесь — максимальная рамка, а не жёсткий размер
thumb = Image.open("photo.jpg")
thumb.thumbnail((800, 600))
thumb.save("thumb.jpg")Проверка: рядом появятся файлы resized.jpg и thumb.jpg. У второго хотя бы одна сторона будет ровно 800 или 600, а пропорции — как у оригинала.
Главное различие, о которое спотыкаются новички:resize()возвращает новый объект и растягивает картинку под заданный размер, аthumbnail()меняет объект на месте, ничего не возвращает и вписывает изображение в рамку, не искажая пропорций.
Шаг 3. Обрезать область
Метод crop() принимает кортеж из четырёх чисел — координаты прямоугольника (left, upper, right, lower). Отсчёт идёт от левого верхнего угла, ось Y направлена вниз.
from PIL import Image
image = Image.open("photo.jpg")
# Вырезаем прямоугольник: левый край 100, верх 50,
# правый край 500, низ 400
cropped = image.crop((100, 50, 500, 400))
cropped.save("cropped.jpg")Проверка: файл cropped.jpg будет размером ровно 400×350 пикселей (500−100 и 400−50). Если координаты выходят за границы изображения, Pillow не ошибётся, а дополнит область пустыми пикселями — учитывайте это.
Шаг 4. Повернуть и отразить
Поворот на 90, 180, 270 градусов делается через rotate(). По умолчанию углы отсчитываются против часовой стрелки, а холст остаётся прежнего размера — углы картинки при произвольном угле обрежутся. Чтобы они не обрезались, передайте expand=True.
from PIL import Image
image = Image.open("photo.jpg")
# Поворот на 90 градусов против часовой, холст расширяется
rotated = image.rotate(90, expand=True)
rotated.save("rotated.jpg")
# Зеркальное отражение по горизонтали
flipped = image.transpose(Image.Transpose.FLIP_LEFT_RIGHT)
flipped.save("flipped.jpg")Проверка: rotated.jpg окажется повёрнутым, а его ширина и высота поменяются местами относительно оригинала. В Pillow 10.x константы отражения живут в перечислении Image.Transpose; в старом коде вы встретите просто Image.FLIP_LEFT_RIGHT — это устаревший вариант, работавший до версии 9.1.
Шаг 5. Сохранить в нужном формате и с нужным качеством
Формат Pillow определяет по расширению в имени файла. Для JPEG можно задать степень сжатия параметром quality (от 1 до 95; выше 95 смысла нет, а 100 отключает часть оптимизаций).
from PIL import Image
image = Image.open("photo.png")
# PNG с альфа-каналом нельзя сохранить в JPEG напрямую —
# сначала убираем прозрачность, переводя в RGB
if image.mode in ("RGBA", "P"):
image = image.convert("RGB")
image.save("output.jpg", quality=85, optimize=True)Проверка: появится output.jpg. Если исходник был PNG с прозрачностью и вы пропустили convert("RGB"), получите ошибку OSError: cannot write mode RGBA as JPEG.
Собираем всё в один скрипт
from PIL import Image
def process(source_path, target_path):
image = Image.open(source_path)
# Вписываем в рамку 1200x1200 без искажений
image.thumbnail((1200, 1200))
# Поворачиваем на 90 градусов
image = image.rotate(90, expand=True)
# Готовим под JPEG
if image.mode in ("RGBA", "P"):
image = image.convert("RGB")
image.save(target_path, quality=85, optimize=True)
print(f"Готово: {target_path}, размер {image.size}")
process("photo.jpg", "result.jpg")Если не получилось
ModuleNotFoundError: No module named 'PIL'— Pillow не установлен в том окружении, где запускается скрипт. Проверьте, чтоpip install Pillowвыполнялся в той же виртуальной среде или тем же интерпретатором, что и запуск.FileNotFoundError: [Errno 2] No such file or directory: 'photo.jpg'— файла нет по указанному пути. Скрипт ищет относительно текущей рабочей директории, а не относительно самого файла скрипта. Укажите полный путь или запускайте из нужной папки.OSError: cannot write mode RGBA as JPEG— вы пытаетесь сохранить прозрачное изображение в JPEG. Добавьтеimage = image.convert("RGB")перед сохранением.AttributeError: module 'PIL.Image' has no attribute 'ANTIALIAS'— константаANTIALIASудалена в Pillow 10. ИспользуйтеImage.Resampling.LANCZOSв параметреresampleметодаresize().- Картинка сохранилась, но пустая или чёрная — частая причина в том, что вы сохранили исходный объект, а не тот, к которому применяли операции.
resize(),crop(),rotate()возвращают новый объект, и результат надо присвоить переменной.
Что делать дальше
Базовые операции освоены. Следующий шаг зависит от задачи: для наложения текста и рисования фигур смотрите модуль ImageDraw, для фильтров вроде размытия и повышения резкости — ImageFilter, для регулировки яркости и контраста — ImageEnhance. Все они входят в тот же пакет Pillow и импортируются из PIL. Пакетная обработка папки с сотнями файлов — отдельная тема; здесь важно помнить только одно: закрывайте изображения через with Image.open(...) as image:, чтобы не держать открытыми файловые дескрипторы в цикле.
Редактор изображений: Убрать лишнее, заменить фон, добавить объект, расширить кадр — на вашем изображении.
Спросить за 20 ₽Источники: Pillow (PIL Fork) — официальная документация, Pillow — Image module reference
Частые вопросы
Чем Pillow отличается от PIL и что ставить?
У меня Pillow 9.x, а в статье примеры для 10.x — что сломается?
Почему после resize изображение осталось прежним?
Как изменить размер без потери пропорций?
Картинка после уменьшения выглядит зернистой, что не так?
Можно ли обрабатывать много файлов в цикле, не упираясь в память?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.