Skip to content

Latest commit

 

History

History
151 lines (89 loc) · 19.6 KB

README.RU.md

File metadata and controls

151 lines (89 loc) · 19.6 KB
〖EN〗 【RU】

PyPNM - модуль чтения и записи графических форматов PPM и PGM на чистом Python

PyPI - Downloads

Обзор и предпосылки

Графические форматы PPM (Portable Pixel Map) и PGM (Portable Gray Map) (частные случаи группы форматов PNM) представляют собой простейшие открытые форматы хранения изображений в пространствах RGB и L (серый), соответственно. Как ни странно, эта простота приводит к нежелательным побочным явлениям:

  • Отсутствие чёткой официальной спецификации. Вместо этого описание формата изобилует словами типа "обычно". Не нужно быть пророком, чтобы предсказать, что кто-нибудь в рамках этой расплывчатости напишет файлы ненаказуемым, но извращённым способом.

  • Явное нежелание многих фирменных разработчиков включать поддержку открытого простого формата в свои продукты. От разработчиков Adobe Photoshop потребовались годы, чтобы заметить, что народ качает третьесторонние плагины, то есть зачем-то народу этот формат нужен, после чего, наконец-то взявшись за дело, разработчики незамедлительно поступили вышеуказанным способом, напхав в заголовок схему разделителей, которую не использует больше никто. Что касается поддержки PNM в Python, например, таких популярных библиотек, как Pillow, ситуация может быть стабильно описана как "ни в сказке сказать, ни при дамах произнести".

По всей видимости, профессиональные программисты считают, что задача слишком проста, чтобы руки марать. Что ж, пусть считают и дальше. Спасение утопающих - дело рук самих утопающих; поскольку мне нужны модули для чтения и записи графических форматов, желательно не использующие третьесторонних библиотек с их собственными глюками и конфликтами версий, пришлось написать этот небольшой модуль на чистом Python, обеспечивающий чтение и запись изображений 16 бит/канал и 8 бит/канал в пространствах RGB (Portable Pixel Map), серый (L) (Portable Gray Map), а также чтение однобитового формата (Portable Bit Map). Для простоты сведения о совместимости сведены в таблицу ниже.

Совместимость форматов

Текущая версия модуля PyPNM обеспечивает чтение и запись следующих версий форматов группы Netpbm:

Image format File format Read Write
16 бит/канал RGB P6 двоичный PPM
16 бит/канал RGB P3 текстовый PPM
8 бит/канал RGB P6 двоичный PPM
8 бит/канал RGB P3 текстовый PPM
16 бит/канал L P5 двоичный PGM
16 бит/канал L P2 текстовый PGM
8 бит/канал L P5 двоичный PGM
8 бит/канал L P2 текстовый PGM
1 бит (краска есть/нет) P4 двоичный PBM
1 бит (краска есть/нет) P1 текстовый PBM

Совместимость с Python

Текущая версия протестирована под 3.10 и выше. Однако существует версия PyPNM для Python 3.4, успешно протестированная с Python 3.4 под Windows XP.

Представление изображения

Поскольку целью данного модуля является не передвигание битов по диску, а обеспечение возможности работы с изображениями, например, их редактирования, модуль должен выдавать и принимать данные в виде какой-то логичным образом устроенной структуры. Представляется логичным представлять, например, RGB-изображение в виде трёхмерной структуры - картинки из рядов из пикселей из цветовых каналов. Поскольку в Python практически единственной изменяемой структурой данных для этого является список, предполагается представлять изображения в формате list(list(list(int))). Таким образом, модуль должен превращать данные из не пойми чего на диске в трёхмерные вложенные списки в памяти.

Заметим, что и для серых картинок структурой остаётся list(list(list(int))), при этом внутренний список состоит из одного элемента. С точки зрения профессиональных программистов это безобразие, но людям обыкновенным даёт возможность обрабатывать картинки в любом пространстве одним и тем же вложенным циклом по Y, X, Z, просто указывая количество каналов Z.

Заметим также, что, поскольку конечной целью является всё-таки обработка изображений, данный модуль обеспечивает поддержку 1-битовых форматов PBM только на чтение, при этом масштабирует цвет из 1 бита "краска есть/краски нет" в обычный яркостный L, т.е. инвертирует исходный сигнал (т.к. "краска есть" соответствует "яркости нет"), и умножает на 255.

Установка

В случае использования pip:

pip install PyPNM

после чего:

from pypnm import pnmlpnm

и далее используйте функции, как описано в разделе "pnmlpnm.py" ниже.

В случае, если вы скачали файл pnmlpnm.py в качестве отдельно стоящего, без упаковки, просто поместите его в рабочую директорию вашей программы и используйте import pnmlpnm.

pnmlpnm.py

Модуль pnmlpnm.py содержит 100% чистую реализацию на Python всего, что может понадобиться для работы с файлами PGM и PPM. Ввод/вывод реализован в форме максимально простых в обращении функций, использование которых описано ниже. Также использование функций описано в docstrings, так что потерять инструкцию к модулю у вас вряд ли получится.

  • pnm2list - читает RGB PPM, или L PGM, или 1-бит PBM-файл, и возвращает данные в форме вложенного трёхмерного списка целых чисел.
  • list2bin - получает изображение в форме вложенного трёхмерного списка целых чисел, и создаёт в памяти байтовую структуру типа PPM (P6) или PGM (P5). Полученная структура может быть легко использована для визуализации изображений с помощью Tkinter.
  • list2pnm - получает изображение в форме вложенного трёхмерного списка целых чисел, и записывает на диск бинарный PPM (P6) или PGM (P5) файл.
  • list2pnmascii - альтернативная функция для записи текстовых PPM (P3) или PGM (P2) в файл.
  • create_image - создаёт вложенный трёхмерный список нулей заданного размера X, Y, Z. Для данного конкретного модуля функция не нужна, но часто полезна для программ, для которых полезен этот модуль, и, чтобы не писать её каждый раз на новом месте, она засунута сюда.

Подробное описание аргументов функций приведено ниже,а также в docstring-ах модуля.

pnm2list

X, Y, Z, maxcolors, image3D = pnmlpnm.pnm2list(in_filename)

чтение данных из файла PPM/PGM, где:

  • X, Y, Z - размеры изображения, int;
  • maxcolors - количество цветов на канал, int;
  • image3D - собственно данные пикселей, list(list(list(int)));
  • in_filename - имя файла PPM/PGM, str.

list2bin

image_bytes = pnmlpnm.list2bin(image3D, maxcolors, show_chessboard)

Превращает изображение в форме вложенного трёхмерного списка целых чисел в байтовый объект типа PPM (P6) или PGM (P5) в памяти:

  • image3D - Y*X*Z список (изображение) списков (рядов) списков (пикселей) целых чисел (каналов);
  • maxcolors - количество цветов на канал, int;
  • show_chessboard - bool, при установке True генерирует превью LA и RGBA-картинок на фоне шахматной паттерны; False или отсутствие переменной приводит к простому игнорированию альфа-канала. Значение по умолчанию False для задней совместимости;
  • image_bytes - байты PNM.

Полученный объект image_bytes совместим с методом Tkinter PhotoImage(data=...) и предназначен для визуализации любых данных, похожих на картинку в виде 3D-списка.

Note

В случае списков с 2 или 4 каналами свежая версия list2bin может считать их LA или RGBA картинками, и генерировать для них превью на фоне шахматной паттерны (как Photoshop или GIMP). Поскольку форматы PNM не поддерживают прозрачности, данная картинка на самом деле имеет структуру L или RGB, а паттерну генерирует и подмешивает на лету сама функция list2bin. Данное поведение контролируется переменной show_chessboard; текущая установка False (просто выбрасывает альфа-канал) для совместимости со старыми версиями PyPNM, в которых такой опции не было.

list2pnm

pnmlpnm.list2pnm(out_filename, image3D, maxcolors)

Запись файла типа PPM (P6) или PGM (P5) на диск из данных списка image3D:

  • image3D - Y*X*Z список (изображение) списков (рядов) списков (пикселей) целых чисел (каналов);
  • maxcolors - количество цветов на канал, int;
  • out_filename - имя файла PNM.

list2pnmascii

Аналогична list2pnm выше, но создаёт текстовый pnm-файл вместо двоичного.

pnmlpnm.list2pnmтекстовый(out_filename, image3D, maxcolors) where:

  • image3D - Y*X*Z список (изображение) списков (рядов) списков (пикселей) целых чисел (каналов);
  • maxcolors - количество цветов на канал, int;
  • out_filename - имя файла PNM.

create_image

image3D = create_image(X, Y, Z)

Создаёт пустой трёхмерный список размеров X*Y*Z.

viewer.py

Программа viewer.py представляет собой небольшой иллюстративный пример использования PyPNM: с помощью pnmlpnm она читает разные форматы файлов PGM и PPM, и позволяет сохранять их в другом формате PGM/PNM, например, позволяет прочитать текстовый PPM и записать изображение в двоичный PPM, или наоборот. Также эта программа отодражает изображения с помощью pnmlpnm и Tkinter. Это не ошибка - программа не скармливает PPM-файл Tkinter напрямую; вместо этого с помощью pnmlpnm она раскрывает изображение в трёхмерный список, затем с помощью pnmlpnm генерирует из этого списка байты PNM preview_data = pnmlpnm.list2bin(image3D, maxcolors), а только после этого передаёт эти байты в Tkinter preview = PhotoImage(data=preview_data) (именно data=, а не file=). Таким образом программа отображает, например, текстовые PNM, которые сам Tkinter не поддерживает.

Пример отрисовки текстового ppm с помощью viewer.py

Аналогичным образом, вы можете использовать pnmlpnm и Tkinter для визуализации любых данных, которые можно представить в виде RGB или L, без использования больших и сложных внешних библиотек.

Ссылки

  1. Описание форматов Netpbm.

  2. PyPNM на PyPI - установка PyPN с помощью pip. Не включает примеров и т.п., только голый пакет ввода/вывода, зато pip обеспечивает автоматизацию обновлений.

  3. PyPNM для Python 3.4 на PyPI - установка PyPN с помощью pip. Не включает примеров и т.п., только голый пакет ввода/вывода, зато pip обеспечивает автоматизацию обновлений. Данная особая версия была создана специально для обладателей старых версий Python, и прошла валидацию под Python 3.4 под Windows XP.

  4. PyPNM на Github - содержит пример приложения для просмотра, иллюстрирующий применение list2bin для визуализации данных с помощью Tkinter `PhotoImage(data=...), и конверсию изображений между форматами.

  5. PyPNM для Python 3.4 на Github - содержит пример приложения для просмотра, иллюстрирующий применение list2bin для визуализации данных с помощью Tkinter `PhotoImage(data=...), и конверсию изображений между форматами. Данная особая версия была создана специально для обладателей старых версий Python, и прошла валидацию под Python 3.4 под Windows XP. Поскольку в комплект поставки входит PyPNG, вы получаете универсальное смотрело и конвертер для PNG и разнообразных версий PGM и PPM на чистом Python.

  6. PixelArtScaling - пример применения, масштабирование изображений методами Scale2x и Scale3x на чистом Python, ввод/вывод PNG основан на PyPNG, а PNM - на PyPNM, что делает приложения кросс-платформенными.

  7. POVRay Thread: Linen and Stitch - пример применения, содержит программу фильтрования изображений «Averager», превью "до и после" основано на статически внедрённом коде PyPNM list2bin и на классе Tkinter PhotoImage(data=...). Таким образом, представлено небольшое, но полноценное интерактивное приложение для фильтрования изображений, реализованное исключительно на Python.

  8. img2mesh - пример применения, программа конверсии 2D изображений в качестве карт высот в 3D сетку. Модуль построения 3D сетки принимает данные x, y, z в том же формате, которые выводит PyPNM, что делает создание программы для 2D➔3D конверсии вопросом переливания данных из одного модуля в другой.