ValueError: bad transparency mask — причины и решение ошибки в Pillow

Ошибка ValueError: bad transparency mask возникает в библиотеке Pillow (PIL) в тот момент, когда метод paste() получает маску прозрачности, размер или режим которой не совпадает со вставляемым изображением. Типичный сценарий: вы накладываете одну картинку на другую с учётом альфа-канала, передаёте третьим аргументом маску — и интерпретатор останавливается с этим исключением. Сбой относится не к файлам, а к несоответствию параметров внутри кода.

Проблема почти всегда воспроизводится при работе с изображениями в режимах RGBA, LA или P с прозрачностью, когда маска передана как отдельный объект. Ниже разберём, откуда берётся ошибка, как её диагностировать и какие способы исправления работают на практике.

Что означает ошибка bad transparency mask

Метод Image.paste(im, box, mask) принимает третьим аргументом маску — изображение, которое определяет, какие пиксели вставляемой картинки будут видны, а какие нет. Pillow требует, чтобы эта маска имела режим 1, L или RGBA и совпадала по размеру с вставляемым изображением. Если хотя бы одно условие нарушено, библиотека выбрасывает ValueError: bad transparency mask.

Отдельный случай — когда маской выступает само вставляемое изображение (приём base.paste(overlay, (0, 0), overlay)). Здесь ошибка появляется, если overlay находится в режиме RGB без альфа-канала: Pillow не может извлечь из него данные о прозрачности и считает маску некорректной.

Основные причины возникновения

Прежде чем править код, полезно понять, какой именно сценарий у вас. Чаще всего встречаются четыре варианта:

  • 🔍 Несовпадение размеров: маска меньше или больше вставляемого изображения даже на один пиксель.
  • 🎨 Неподходящий режим маски: передано изображение в RGB или CMYK, тогда как нужны 1, L или RGBA.
  • 🧩 Отсутствие альфа-канала: картинка используется сама как маска, но открыта в режиме без прозрачности.
  • 📦 Маска из другого источника: например, загружена отдельным файлом и не приведена к размеру накладываемого слоя.

Быстрая диагностика занимает пару строк. Выведите режим и размер обоих объектов прямо перед вызовом paste() — этого достаточно, чтобы увидеть несоответствие:

print(overlay.mode, overlay.size)

print(mask.mode, mask.size)

Решение 1: привести изображение к RGBA

Самый частый фикс — конвертировать вставляемую картинку в RGBA перед тем, как использовать её как маску. Тогда Pillow корректно прочитает альфа-канал:

overlay = overlay.convert("RGBA")

base.paste(overlay, (0, 0), overlay)

Если исходный файл — JPEG или PNG без прозрачности, после конвертации альфа-канал будет полностью непрозрачным, и вставка пройдёт без ошибки, хотя эффекта прозрачности не появится. Для реального наложения с прозрачностью нужен файл, где альфа-канал существует изначально, либо маска, созданная вручную.

⚠️ Внимание: конвертация в RGBA не добавляет настоящую прозрачность «из ниоткуда». Если нужно вырезать объект по контуру, потребуется отдельная маска или файл с готовым альфа-каналом.

Решение 2: подогнать размер и режим маски

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

mask = mask.convert("L")

mask = mask.resize(overlay.size)

base.paste(overlay, (0, 0), mask)

Режим L (градации серого) — самый предсказуемый вариант: белые пиксели маски означают полную видимость, чёрные — полную прозрачность. Если нужна жёсткая бинарная маска без полутонов, используйте режим 1.

☑️ Проверка перед вызовом paste()

Выполнено: 0 / 4

Решение 3: использовать alpha_composite вместо paste

Для наложения с прозрачностью часто удобнее метод Image.alpha_composite(). Он не требует отдельной маски, но обязывает оба изображения быть в RGBA и одинакового размера:

base = base.convert("RGBA")

overlay = overlay.convert("RGBA")

result = Image.alpha_composite(base, overlay)

Если размеры отличаются, сначала создайте холст нужного размера и поместите на него меньшее изображение через paste() без маски, а затем выполните композитинг. Этот подход снижает количество ручных проверок и уменьшает шанс снова столкнуться с bad transparency mask.

Сравнение способов наложения изображений

МетодНужна маскаТребования к режимамКогда использовать
paste() с маскойДаМаска: 1, L или RGBAГибкий контроль прозрачности
paste() без маскиНетЛюбые совместимыеПростая вставка без прозрачности
alpha_composite()НетОба изображения RGBA, один размерКорректное смешивание альфа-каналов
Image.composite()ДаОба изображения и маска одного размераСборка результата из двух источников

Типичные ошибки при исправлении

Первая ловушка — изменить объект маски, но не само вставляемое изображение, либо наоборот. Помните: Pillow сравнивает размер маски именно с тем объектом, который передан первым аргументом в paste().

Вторая — работа с изображениями в режиме P (палитровые PNG). У таких файлов прозрачность хранится в палитре, и прямая передача их в качестве маски может дать неожиданный результат. Надёжнее сразу конвертировать их в RGBA.

⚠️ Внимание: после resize() создаётся новый объект, а не меняется исходный. Присваивайте результат переменной, иначе маска останется прежнего размера и ошибка повторится.
Почему RGB нельзя использовать как маску

В режиме RGB у изображения три канала и нет альфа-канала. Pillow ожидает от маски данные о прозрачности, и трёхканальное изображение не соответствует ни одному из допустимых режимов (1, L, RGBA), поэтому выбрасывается ValueError.

Как предотвратить ошибку в будущем

Несколько привычек избавят от повторных столкновений с этим исключением:

  • 🛡️ Конвертируйте все входные файлы в единый режим (обычно RGBA) сразу после открытия.
  • 📐 Проверяйте .size у маски и изображения перед каждым наложением в циклах.
  • 🧪 Тестируйте код на файлах разных форматов: PNG с альфой, PNG без альфы, JPEG, палитровые GIF.
  • 📚 Сверяйтесь с документацией установленной версии Pillow — поведение отдельных методов может меняться между релизами.

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

Частые вопросы

Почему paste() с маской работает для одного PNG, но падает для другого?

Скорее всего, второй файл сохранён без альфа-канала или в палитровом режиме. Проверьте image.mode и при необходимости выполните convert("RGBA").

Можно ли использовать JPEG в качестве маски?

Да, но только после конвертации в L или 1: JPEG не поддерживает прозрачность, поэтому как источник альфа-канала он не подходит, а как полутоновая маска — вполне.

Размеры совпадают, режим L, а ошибка остаётся. Что проверить?

Убедитесь, что вы передаёте маску третьим аргументом, а не вторым, и что координаты вставки заданы кортежем. Также проверьте, не был ли объект маски закрыт или перезаписан ранее в коде.

Чем alpha_composite лучше paste с маской?

Он корректно смешивает полупрозрачные пиксели обоих слоёв и не требует отдельной маски, но требует одинаковых размеров и режима RGBA у обоих изображений.

Зависит ли ошибка от версии Pillow?

Текст сообщения и допустимые режимы маски могут отличаться между версиями. Если код переносится между окружениями, сверьтесь с документацией именно установленной версии библиотеки.