Pull to refresh

Как написать дополнение для GIMP на языке Python

Reading time 11 min
Views 18K

Или Script-Fu — это так называемый «фильтр массовости»? Далеко не каждый может с ним разобраться и большинство даже не пытаются делать какие-то плагины к GIMP.

RPG


Введение


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

В качестве языков, на которых можно писать дополнения, годятся Scheme и Python. Существует возможность писать дополения и на других языках (Perl, Tcl/Tk и т.д.), но модули, которые реализуют эту возможность, плохо поддерживаются либо вовсе не работают со свежими версиями GIMP.

Избрав языком для написания дополнения Scheme, вы автоматически оказываетесь в выигрыше, так как не существует в мире такой сборки GIMP-а, в которую бы интерпретатор Scheme не входил, и написаное вами дополнение гарантировано будет работать на всех платформах «из коробки», однако, писать на Scheme — то ещё удовольствие… Scheme является диалектом LISP. LISP — это аббревиатура, расшифровывается как LISt Processing, то есть, язык для обработки списков. Существует и другая расшифровка: Language of Idiotic Silly Parentheses (язык идиотских глупых скобок), спорное, но не лишенное смысла утверждение, — несоблюдение баланса скобок — один из главных источников ошибок программы, написанной на LISP и ему подобных. Далеко не каждый может разобраться с непростым синтаксисом этого языка, и большинство даже не пытаются писать какие-то дополнения для GIMP. Но сложный синтаксис — это мелочь по сравнению с отсутствием ряда возможностей. Например, нельзя использовать свой графический интерфейс, сохранить настройки дополнения в конфигурационный файл, подключить некий внешний модуль с дополнительными функциями и т.д. и т.п. Но есть язык, лишённый большинства недостатков Scheme и обладающий рядом достоинств. Этот язык — Python. О нём и пойдёт речь.


PDB и «Браузер процедур»


GIMP предоставляет нам API, в котором отражены все аспекты управления им. На любое действие, которое можно выполнить мышкой и клавиатурой, имеется соответствующая API функция. Совокупность API функций, которую предоставляет GIMP, образует так называемую процедурную базу данных PDB (The Procedural Database). Для просмотра PDB необходимо воспользоваться специальным инструментом, который называется «Браузер процедур» и вызывается кнопкой «Просмотр...» из окна ФильтрыPython-FuКонсоль.



Окно «Браузера процедур» разделено на две части: в левой части представлен список доступных функций, в правой — информация о выделенной в данный момент функции (имя, краткое описание выполняемых действий, перечень входных и выходных параметров, данные об авторе, времени создания и копирайте). Список достаточно велик (как я упоминал выше, GIMP — мощный графический редактор), но для облегчения жизни предусмотрена возможность фильтрации по имени (части имени) функции, по её краткому описанию и по ряду иных параметров, которые можно выбрать из выпадающего списка, расположенного справа от строки поиска.

Основные модули


Для того, чтобы наш Python-скрипт научился управлять GIMP-ом, дергать за ниточки его API, необходимо подключить к нему соответствующие модули:
  • gimpfu — это основной модуль, который содержит в себе функции register() (регистрирует дополнение в PDB) и main() (запускает дополнение), необходимые константы и переменные окружения, а также подключает ряд модулей, необходимых для работы
  • gimp — здесь собраны основные процедуры, функции и структуры данных, включая объекты Image, Layer и переменную pdb для доступа к The Procedural Database. Модуль автоматически подключается при подключении модуля gimpfu
  • gimpenums — полезные констранты, модуль автоматически подключается при подключении модуля gimpfu
  • gimpui — этот модуль включает в себя элементы UI, содержащиеся в библиотеке libgimpui, и помогает работать с элементами графического интерфейса
  • gimpshelf — позволяет дополнению запоминать какие-либо данные на время работы с изображением и хранить их до закрытия окна GIMP (этакие сеансовые cookie только для GIMP)
  • gimpplugin — альтернативный модуль, предоставляющий больше гибкости, но меньше возможностей, чем стандартный gimpfu. Если представить, что gimpfu — это конструктор лего, набор заранее подготовленых инструментов, из которых следует строить дополнение, то gimpplugin — это пластичная глина, из которой можно вылепить все, что угодно, но и всю грязную работу, соответственно, придётся делать самому

Исходный код этих модулей можно найти в файлах, расположенных по адресу: /usr/lib/gimp/2.0/python — если вы работаете в среде GNU/Linux, или C:\Program Files\Gimp-2.7.5\lib\gimp\2.0\python — если вы работаете в среде Windows.

Попробуем?


Итак, о «Браузере процедур» и основных модулях я рассказал, давайте теперь попробуем поуправлять GIMP-ом посредством Python-a. Для начала запустите консоль Python-Fu (напомню: ФильтрыPython-FuКонсоль).
Перед вами откроется вот такое окно:



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



Будьте готовы к тому, что действия, которые производят функции, не всегда эквивалентны действиям, выполняющимся в интерактивном режиме. При вызове соответствующей команды через меню, например, чтобы создать новое изображение, потребуется четыре шага, а в интерактивном режиме это делается за один клик (естественно, выполняются те же четыре шага, только они скрыты от пользователя).

Функция, предназначенная для создания нового изображения, называется gimp_image_new. Браузер процедур говорит нам о том, что она имеет три входных параметра:
  • width — ширина изображения в пикселях (целое число)
  • height — высота изображения в пикселях (целое число)
  • type — тип изображения (целое число)

Для типа изображения приведен перечень возможных значений и имена предопределенных констант, которые можно использовать вместо чисел для лучшей читаемости программ:
  • RGB — соответствует 0 (будет создано цветное изображение в режиме RGB)
  • GRAY — соответствует 1 (будет создано изображение в градациях серого)
  • INDEXED — соответствует 2 (будет создано индексированное изображение)

Возвращает эта функция один параметр — идентификационный номер (ID) вновь созданного изображения (указатель на изображение, если вам угодно). Попробуем создать новое RGB изображение размером 640х480 пикселей. Для этого введите в командную строку следующее:

>>> image = pdb.gimp_image_new(640, 480, RGB)
>>>


(На самом деле, вводить не обязательно, достаточно дважды кликнуть по имени необходимой функции в окне браузера процедур либо выделить её и нажать кнопку «Применить», после чего шаблон функции будет вставлен в консоль, и вам останется лишь вписать необходимые параметры).

Если после выполнения команды ничего не было выведено, значит, GIMP успешно создал требуемое изображение, и теперь мы можем обращаться к нему через переменную image.

В данный момент изображение состоит только из пустого «холста» и не содержит в себе ни одного слоя. Браузер процедур говорит нам о том, что создать новый слой можно при помощи функции gimp_layer_new, которая имеет следующие входные параметры:
  • image — ID изображения, в котором создается слой
  • width — ширина слоя в пикселях
  • heidht — высота слоя в пикселях (да, в GIMP размеры слоев могут отличаться от размеров изображения)
  • type — тип слоя
  • name — имя слоя
  • opacity — прозрачность слоя (число в пределах от 0 до 100, причем, 100 означает полную непрозрачность)
  • mode — режим наложения нового слоя на существующие слои. Обычно этот параметр имеет значение NORMAL

Параметр «тип слоя» (type) может принимать следующие значения:
  • RGB_IMAGE — цветной слой в режиме RGB
  • RGBA_IMAGE — цветной слой, содержащий альфа-канал
  • GRAY_IMAGE — слой в градациях серого
  • GRAYA_IMAGE — слой в градациях серого, содержащий альфа-канал
  • INDEXED_IMAGE — слой, содержащий индексированные цвета
  • INDEXEDA_IMAGE — слой, содержащий индексированные цвета и альфа-канал

Возвращает эта функция ID созданного слоя. Создадим новый слой:

>>> layer = pdb.gimp_layer_new(image, 640, 480, RGB_IMAGE, "Фон", 100, NORMAL_MODE)
>>>


Если ничего не было выведено, значит, новый слой с именем «Фон» успешно создан, и мы можем обращаться к нему через переменную layer.

Теперь слой нужно встроить в изображение. Это делается при помощи функции gimp_image_insert_layer. По данным браузера процедур, эта функция имеет четыре входных параметра:
  • image — ID изображения
  • layer — ID слоя
  • parent — группа слоев, в которую необходимо добавить слой. Если parent равен None, слой будет добавлен в основной стек, вне какой-либо группы
  • position — определяет местоположение слоя в основном стеке слоёв или группе (если идентификатор группы, переданный в параметре parent, действителен). Чем больше цифра, тем выше располагается слой в стеке. Счет начинается с 0. Если position равен -1, то новый слой будет вставлен над активным в данный момент слоем.

Важно помнить о том, что тип слоя должен соответствовать типу изображения, иными словами, не надо пытаться в RGB изображение вставлять GRAY слой.

В нашем случае, нужно встроить слой layer в изображение image, поместив его на нижний (нулевой) уровень:

>>> pdb.gimp_image_insert_layer(image, layer, None, 0)
>>>


Теперь для того, чтобы новый слой приобрел цвет фона, его необходимо очистить (если этого не сделать, то слой будет цвета переднего плана) при помощи функции gimp-edit-clear, имеющей только один входной параметр:
drawable — доступная для рисования область.
drawable — это довольно интересный параметр. В отличии от image, который всегда изображение, или width, который всегда ширина, drawable может быть слоем, выделенной областью или каналом, в зависимости от того, с каким именно объектом работает та или иная функция, в данном случае, gimp-edit-clear в качестве параметра следует передать указатель на слой).

Эффект, производимый функцией gimp_edit_clear, зависит от типа слоя: слой, содержащий альфа-канал, в результате очистки станет прозрачным, а RGB слой будет залит цветом фона.

Очистим слой layer:

>>> pdb.gimp_edit_clear(layer)
>>>


Новое изображение готово, теперь можно его вывести на дисплей:

>>> display = pdb.gimp_display_new(image)
>>>


Функция gimp_display_new создает на экране новое окно и выводит в нем изображение, ID которого передан ей в качестве параметра. Возвращает эта функция ID окна.
В результате проделанных манипуляций, на экране должна появиться вкладка, содержащая RGB изображение, размером 640х480 пикселей, состоящее из одного слоя, который заполнен цветом фона.



Итак. Управлять GIMP-ом посредством API функций мы теперь умеем. Каким же образом эти манипуляции оформить в виде Python-скрипта? Об этом ниже.

«Скелет» дополнения


Типичное дополнение, написанное с использованием модуля gimpfu, выглядит следующим образом:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Импортируем необходимые модули
from gimpfu import *

# Объявляем функцию
def plugin_func(image, drawable, args):
  #
  # Здесь код вашего дополнения:
  # всякие функции из браузера процедур
  #

# Регистрируем функцию в PDB
register(
          "python-fu-plugin-func", # Имя регистрируемой функции
          "Такое-то очень функциональное дополнение", # Информация о дополнении
          "Делает то-то и то-то, так-то и так-то", # Короткое описание выполняемых скриптом действий
          "Автор авторов", # Информация об авторе
          "Автор авторов (author@server.ru)", # Информация о копирайте (копилефте?)
          "8.01.2012", # Дата изготовления
          "Крутой фильтр", # Название пункта меню, с помощью которого дополнение будет запускаться
          "*", # Типы изображений, с которыми может работать дополнение
          [
              (PF_IMAGE, "image", "Исходное изображение", None), # Параметры, которые будут переданы дополнению
              (PF_DRAWABLE, "drawable", "Исходный слой", None),# Всякие указатели на изображение, слои и т.д.
              (PF_STRING, "arg", "The argument", "default-value")
          ],
          [], # Список переменных, которые вернет дополнение
          plugin_func, menu="<Image>/Фильтры/") # Имя исходной функции и меню, в которое будет помещён пункт, запускающий дополнение

# Запускаем скрипт
main()

Остановимся подробнее на функции, регистрирующей наше дополнеие в PDB. Обратите внимание на префикс python-fu. Вообще, это правило хорошего тона — давать имена функциям по принадлежности и по выполняемому ими действию, чтобы по имени функции было понятно, чего от нее ждать. Если имя функции начинается со слова «gimp» — это «родная» функция GIMP, «plug-in» — это обычно компилируемые дополнения, написанные на С (скорее всего, фильтры), «script-fu» — расширения, написанные на Scheme, «python-fu» — как вы, наверное, уже догадались — расширения, написанные на Python-e.

Имена также содержат указание на объект, с которым функция работает, например, если вам необходимо что-то сделать со слоями, искать необходимую функцию в PDB следует, указав в строке поиска «layer», чтобы найти функции, работающие с выделенными областями — «select» и т.д. К тому же, если не указать префикс «python-fu» в начале функции, то она не будет зарегистрирована (по-моему, это только для Python-скриптов такое ограничение, и оно к лучшему, я считаю).

Также обратите внимание на то, что все нижние подчеркивания «_» в имени регистрируемой функции необходимо заменить на знак «-» — эта неоднозначная особенность попортила мне много крови, когда я начал осваивать написание дополнений на Pythone. Не до конца понимаю, зачем это сделано, но иначе дополнение просто не заработает…

Параметр функции register(), отвечающий за указание типа изображения, с которым будет работать дополнение, может принимать следующие значения: RGB, RGBA, GRAY, GRAYA, INDEXED. Для указания всех типов RGB и оттенков серого можно использовать «*» вот так: RGB*, GRAY*. Если дополнение для всех типов изображений, то можно просто указать «*». Этот параметр также влияет на активность пункта меню, запускающего дополнение. Например, если ваше дополнение работает только с RGB изображениями, а у вас открыто изображение, представляющее из себя лишь оттенки серого, то меню будет неактивным. В свою очередь, если указать в качестве типа изображения «*», то меню будет активным, даже если никакого изображения в данный момент не открыто (полезный хак, когда возникает потребность в генерации изображения с нуля, а не в редактировании готового).

Меньше слов, больше кода


Перейдём от слов к делу. Напишем простое демонстрационное дополнение, которое будет рисовать вокруг изображения рамку заданного размера и цвета. Для этого возьмем упомянутый выше скелет дополнения и впишем в него необходимый код.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Импортируем необходимые модули
from gimpfu import *

def add_colored_border(image, drawable, border_width, border_color):
  pdb.gimp_context_push()
  # Запрещаем запись информации для отмены действий,
  # что бы все выполненные скриптом операции можно было отменить одим махом
  # нажав Ctrl + Z или выбрав из меню "Правка" пункт "Отменить действие"
  pdb.gimp_image_undo_group_start(image)

  # Увеличиваем размер холста и смещаем на необходимое расстояние
  pdb.gimp_image_resize(image,
                        pdb.gimp_image_width(image)  + border_width,
                        pdb.gimp_image_height(image)  + border_width,
                        border_width / 2,
                        border_width / 2)
  # Запоминаем цвет фона.
  # Это тоже правило хорошего тона:
  # оставь после себя все в исходном состоянии
  old_background = pdb.gimp_context_get_background()
  # Меняем цвет фона
  pdb.gimp_context_set_background(border_color)
  # Сводим изображение
  pdb.gimp_image_flatten(image)
  # Возвращаем в исходное состояние цвет фона
  pdb.gimp_context_set_background(old_background)
  # Обновляем изоборажение на дисплее
  pdb.gimp_displays_flush()

  # Разрешаем запись информации для отмены действий
  pdb.gimp_image_undo_group_end(image)
  pdb.gimp_context_pop()

# Регистрируем функцию в PDB
register(
          "python-fu-add-colored-border", # Имя регистрируемой функции
          "Добавление цветной рамки к изображению", # Информация о дополнении
          "Рисует вокруг изображения рамку заданного цвета и заданной ширины", # Короткое описание выполняемых скриптом действий
          "Александр Карабанов", # Информация об авторе
          "Александр Карабанов (zend.karabanov@gmail.com)", # Информация о копирайте (копилефте?)
          "8.01.2012", # Дата изготовления
          "Добавить рамку", # Название пункта меню, с помощью которого дополнение будет запускаться
          "*", # Типы изображений с которыми может работать дополнение
          [
              (PF_IMAGE, "image", "Исходное изображение", None), # Указатель на изображение
              (PF_DRAWABLE, "drawable", "Исходный слой", None), # Указатель на слой
              (PF_INT, "border_width", "Ширана рамки", "10"), # Ширана рамки
              (PF_COLOR, "border_color",  "Цвет рамки", (39,221,65)) # Цвет рамки
              
          ],
          [], # Список переменных которые вернет дополнение
          add_colored_border, menu="<Image>/ТЕСТ/") # Имя исходной функции и меню в которое будет помещён пункт запускающий дополнение

# Запускаем скрипт
main()


Теперь сохраните этот код в файл add_colored_border.py, например, и скопируйте его в папку с дополнениями.
Если вы работаете в среде GNU/Linux, то этой папкой будет ~/.gimp-2.x.x/plug-ins/ (не забудьте дать вашему скрипту права на выполнение).

Пользователям Windows необходимо поместить дополнение в папку %USERPROFILE%\.gimp-2.x.x\plug-ins\ (Подробнее об установке дополнений вы можете узнать на официальном русскоязычном сайте свободного графического редактора GIMP из статьи «Установка дополнений в GIMP»).

Запустите GIMP и посмотрите на строку меню. Если вы все сделали правильно, то рядом с меню «Фильтры» появилось меню «ТЕСТ», из которого можно будет запускать наше дополнение.



А в PDB появилась новая процедура python-fu-add-colored-border.



Попробуйте дополнение в действии. Для этого создайте новое изображение, вызовите наше дополнение из меню ТЕСТДобавить рамку. Появится примерно такой диалог:



Как видите, GIMP сам позаботился о графическом интерфейсе, и нам не пришлось делать грязную работу, расставляя текстовые поля и кнопки на форме диалогового окна, но и повлиять на внешний вид этого диалога мы не в состоянии. В следующий раз я расскажу, как избавиться от подобных недостатков и раскыть всю мощь Python-a по отношению к дополнениям для GIMP-a.

А пока выберите ширину рамки, её цвет и нажмите «OK». Наше дополнение отработает, и вы увидете приблизительно такой результат:



Полезные ссылки


Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
+60
Comments 22
Comments Comments 22

Articles