Графический редактор GIMP предоставляет широкие возможности для создания расширений на языках программирования Scheme (функциональный язык, сходный с LISP) или Python. Для доступа к системным операциям и регистрации собственных действий используется общий реестр Procedural Database (PDB), через который можно выполнять любые действия со встроенными механизмами GIMP (например, создание изображения). В этой статье мы рассмотрим основы создания расширений на Python 3 и возможные подходы к тестированию расширений через PDB.

По умолчанию для создания расширений используется Scheme и компонент Script-Fu, который предоставляет методы для регистрации расширений. Список существующих процедур можно посмотреть в меню Help -> Procedure Browser, среди которых есть процедуры для выполнения действий внутри GIMP (например, с префиксом file для загрузки-выгрузке файлов, gimp для обработки изображений), для регистрации дополнительных пунктов меню (gimp-plugin-menu-register), регистрации генераторов миниатюр (gimp-register-thumbnail-loader) и др. Процедуры могут принимать значения (например, название дополнительного пункта меню) и, в некоторых случаях, названия процедур-обработчиков события (например, нажатия на пункт меню). Также процедуры могут возвращать значения (например, gimp-version возвращает версию GIMP). При описании процедуры указывается название, описание, метаданные об авторских правах, перечисление аргументов и результатов функции с уточнением типа данных.

Для использования python с целью создания расширений для GIMP необходимо установить модуль python-fu. GIMP версии 2.99 (и последующий GIMP3) будут поддерживать Python3 и мы будем использовать их в своей статье:

sudo apt update 
sudo apt install flatpak
flatpak install --user https://flathub.org/beta-repo/appstream/org.gimp.GIMP.flatpakref 
flatpak run org.gimp.GIMP//beta

Для более ранних версий GIMP поддержка существовала только для Python 2, но начиная для бета-версии уже доступен Python 3. После запуска GIMP перейдем в Filters -> Development -> Python Fu -> Python Console.

Для доступа к API GIMP будем использовать символ Gimp:

>>> Gimp.version()
'2.99.14'

Доступ ко встроенным действиям возможен через реестр Pdb:

>>> Gimp.get_pdb()
<Gimp.PDB object at 0x7fcf20523d40 (GimpPDB at 0x557496007ca0)>

Описание интерфейса может быть найдено на этой странице. Для доступа к процедуре можно использовать методы lookup_procedure(возвращает доступ к объекту процедуры для исследования и вызова, а также привязке пункта меню):

Gimp.get_pdb().lookup_procedure('gimp-plug-in-menu-branch-register')

или run_procedure:

>>> Gimp.get_pdb().run_procedure('gimp-version').index(0)
<enum GIMP_PDB_SUCCESS of type Gimp.PDBStatusType>
>>> Gimp.get_pdb().run_procedure('gimp-version').index(1)
'2.99.14'

Также можно передавать значения, например для выбора цвета переднего плана:

>>> Gimp.get_pdb().run_procedure('gimp-context-set-foreground', [Gimp.RGB(255,0,0)])

Для создания плагина будем расширять класс Gimp.Plugin и переопределять методы do_create_procedure и do_query_procedures, также дополнительно проверим корректность версии Gimp:

import gi
gi.require_version('Gimp', '3.0')
from gi.repository import Gimp
gi.require_version('GimpUi', '3.0')
from gi.repository import GimpUi
from gi.repository import Gio

class SamplePlugin(Gimp.PlugIn):

    def do_query_procedures(self):
        # получить список процедур
        self.set_translation_domain("gimp30-python",
                                    Gio.file_new_for_path(Gimp.locale_directory()))

        return [ 'python-fu-sample-plugin' ]


    def do_create_procedure(self, name):
        procedure = Gimp.Procedure.new(self, name,
                                            Gimp.PDBProcType.PLUGIN,
                                            self.sample_procedure, None, None)
        procedure.set_menu_label("Sample Plugin")
        procedure.set_attribution("Dmitrii Zolotov",
                                  "Dmitrii Zolotov",
                                  "2023")
        procedure.add_menu_path("<Image>/Filters/SamplePlugin")

        return procedure

    def sample_procedure(self, procedure, args, data):
        return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, "OK")
        
 
Gimp.main(SamplePlugin.__gtype__, sys.argv)

Для тестирования плагина после установки мы можем использовать обнаружение PDB для проверки сигнатуры или результата выполнения функции:

a = Gimp.get_pdb().lookup_procedure('python-fu-sample_plugin')
r = a.run([])
assert r.index(0)==Gimp.PDBStatusType.SUCCESS
assert r.index(1)=='OK'

В расширениях могут создаваться разных типы процедур:

  • Gimp.Procedure - базовый класс, определяет абстрактное действие с указанными аргументами (может возвращать результат);

  • Gimp.FileProcedure- процедура для модификации возможностей по работе с файлами;

  • Gimp.LoadProcedure - процедура для обработки изображения при загрузке (например, для поддержки других форматов файлов);

  • Gimp.SaveProcedure - обработка изображения при сохранении файла (для экспорта в другие форматы);

  • Gimp.ImageProcedure - обработка изображения (например, этот тип используется при создании фильтров);

  • Gimp.BatchProcedure - пакетная обработка;

  • Gimp.ThumbnailProcedure - подготовка миниатюры.

Для выполнения преобразований можно использовать возможности GEGL, либо подключать другие библиотеки для работы с изображениями (PIL, OpenCV и др.). Для тестирования преобразований изображения (например, фильтров) можно использовать сравнение снимков изображения по степени сходства на основе нескольких преобразований нескольких тестовых изображений (для проверки можно передавать название исходного изображения и путь для сохранения результата как аргументы процедуры), например так:

import cv2
import numpy as np

img1 = cv2.imread('source.jpg')
img2 = cv2.imread('target.jpg')

img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

def mse(img1, img2):
   h, w = img1.shape
   diff = cv2.subtract(img1, img2)
   err = np.sum(diff**2)
   mse = err/(float(h*w))
   return mse, diff

error, diff = mse(img1, img2)
assert mse<5

Также для использования в Python доступны все методы, опубликованные в классе Gimp для получения текущего контекста запущенного редактора и выбранных инструментов, операции с файлами, просмотра списка открытых изображений (list_images). Для манипуляции изображением возможно использовать методы Gimp.Image (в частности, через него можно выполнять изменение размера изображения, управление слоями, выделение и операции с фрагментами) и многое другое.

Пример плагин для GIMP 3 (2.99.14) можно посмотреть в этом проекте.

В завершение хочу пригласить вас на бесплатный урок, где мы познакомимся с системой автоматизации развёртывания и управления приложениями Docker, посмотрим как использовать некоторые базовые команды Docker CLI и попробуем "упаковать" тесты в Docker-контейнер.

Комментарии (1)


  1. U235a
    18.04.2023 05:39

    В коде вычисления mse ошибка. cv2.subtract делает вычитание с насыщением: 42-255=0. Нужно использовать cv2.absdiff. Или сразу cv2.PSNR для похожих целей.