## 4. Инструкция по написанию расширений на Python

This tutorial will teach you the basics about writing a Python plug-in for GIMP 3.0. You are expected to already have some basic knowledge about writing Python in general. If not, there are enough Python courses online, we are not going to duplicate them here.

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

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

### 4.1. Основные элементы расширения для GIMP

Мы рассмотрим основные части расширения, которые необходимы, или, по крайней мере, очень распространены для работы с GIMP.

- В Linux и macOS обязательно, а в Windows принято начинать с так называемого шебанга, кодировки и уведомления об авторских правах. Первая строка — это шебанг,который указывает, как можно выполнить этот сценарий. Следующая строка указывает кодировку файла Python. Мы рекомендуем utf-8. Обычно за этим следует несколько строк, указывающих лицензию, под которой вы публикуете сценарий, и краткое описание того, что он делает. Мы не будем углубляться в это, так как это общее для Python в целом.

- Импорт необходимых модулей для доступа к функциям GIMP и GEGL (опционально).

- Объявите класс с несколькими предопределёнными функциями, которые необходимо настроить, чтобы GIMP знал, какие функции доступны в вашем расширении и какие возможности они поддерживают. Мы более подробно рассмотрим это ниже.

- Вызов, который запускает ваше расширение или запрашивает его возможности, в зависимости от аргументов, отправленных ему GIMP.

#### 4.1.1. Необходимые модули

Чтобы получить доступ к функциям GIMP, мы начинаем с `import gi`. Этот модуль может определить, какие функции доступны в каждом модуле, определённом посредством «интроспекции объектов». Для нас это означает, что мы импортируем все связанные с GIMP модули, которые могут нам понадобиться, через вызовы `gi.repository`.

Для базовой функциональности может быть достаточно только модулей Gimp и GimpUi. Если необходимо запускать расширение из командной строки, вам даже не потребуется GimpUi. Начнём с примера.

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    #
    #   GIMP - The GNU Image Manipulation Program
    #   Copyright (C) 1995 Spencer Kimball and Peter Mattis
    #
    #   gimp-tutorial-plug-in.py
    #   sample plug-in to illustrate the Python plug-in writing tutorial
    #   Copyright (C) 2023 Jacob Boerema
    #
    #   This program is free software: you can redistribute it and/or modify
    #   it under the terms of the GNU General Public License as published by
    #   the Free Software Foundation; either version 3 of the License, or
    #   (at your option) any later version.
    #
    #   This program is distributed in the hope that it will be useful,
    #   but WITHOUT ANY WARRANTY; without even the implied warranty of
    #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #   GNU General Public License for more details.
    #
    #   You should have received a copy of the GNU General Public License
    #   along with this program.  If not, see <https://www.gnu.org/licenses/>.

    import sys

    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 GLib

Мы начинаем с импорта sys, который нам понадобится в конце для доступа к `sys.argv`, после чего `import gi` сообщает Python, что ему нужно загрузить модуль gi. Этот модуль используется для доступа к специальным функциям GIMP через «интроспекцию объектов».

В следующей строке мы сообщаем gi, что нам требуется версия API GIMP 3.0 (это расширение не будет работать с более старыми версиями GIMP). Следующая строка запрашивает импорт всех функций, классов и т. д. из модуля Gimp.

Следующие две строки делают то же самое для GimpUi. GimpUi содержит все элементы, связанные с интерфейсом GIMP. Если вы планируете создать расширение, которое будет вызываться только из командной строки, то вам это не понадобится. Мы завершаем импорт GLib, который нам понадобится позже для доступа к GLib.Error.

There are other optional modules that you can use, too, like Gegl and many others, but we won't go into that here.

#### 4.1.2. Определение класса расширения

GIMP должен знать, какие функции доступны, какие возможности они поддерживают и какое место в меню использовать. Для этого мы определяем класс, производный от класса `Gimp.PlugIn`.

A minimal plug-in needs at least the following functions defined in this class:

- A `do_query_procedure` method, which GIMP calls to find out the names of the procedures that can be called in this plug-in.

- A `do_set_i18n` method, which GIMP calls to find out if your plug-in supports translations.

- A `do_create_procedure` method, which GIMP calls to start one of your plug-ins functions. When this is called you should initialize certain information for GIMP. You start by creating a procedure that tells GIMP the name of the Python function to call to start your plug-in. Then you supply additional information, like what types of images your plug-in supports, where in the menu should your plug-in be found, and other optional settings.

- Фактическая функция (называемая GIMP процедурой), которую вы указали выше. Мы часто называем её `run`, но она может иметь любое имя, разрешённое Python. В эту функцию вы добавите свой собственный код для применения желаемых эффектов.

Теперь рассмотрим это подробнее. Ниже не приведена первая часть кода Python, показанная выше. Здесь показана только базовая структура вашего класса.

    class MyFirstPlugin (Gimp.PlugIn):
        def do_query_procedures(self):
            return [ "jb-plug-in-first-try" ]

        def do_set_i18n (self, name):
            return False

        def do_create_procedure(self, name):
            procedure = Gimp.ImageProcedure.new(self, name,
                                                Gimp.PDBProcType.PLUGIN,
                                                self.run, None)

            procedure.set_image_types("*")

            procedure.set_menu_label("My first Python plug-in")
            procedure.add_menu_path('<Image>/Filters/Tutorial/')

            procedure.set_documentation("My first Python plug-in tryout",
                                        "My first Python 3 plug-in for GIMP 3",
                                        name)
            procedure.set_attribution("Your name", "Your name", "2023")

            return procedure

        def run(self, procedure, run_mode, image, drawables, config, run_data):
            Gimp.message("Hello world!")
            # do what you want to do, then, in case of success, return:
            return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())

Let's take a closer look at `do_query_procedures`. In the line `return [ "jb-plug-in-first-try" ]` we tell GIMP what the name of our procedure is: we call it "jb-plug-in-first-try". This is the name that will be shown in GIMP's Procedure Browser.

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

Рекомендуется начинать все процедуры с ваших инициалов или какой-либо другой узнаваемой или уникальной метки. Таким образом, меньше вероятность, что ваше имя будет совпадать с именем расширения кого-то другого, что может сбить GIMP с толку. Кроме того, вы можете назвать его так, как вам нравится.

Далее мы сообщаем GIMP, что не поддерживаем переводы, возвращая False в вызове `do_set_i18n`. Действия, выполняемые при необходимости перевода расширения, выходят за рамки этого руководства.

Функция `do_create_procedure` — это место, где выполняется большая часть инициализации для GIMP.

Процедура 13.1. Настройка do_create_procedure

1. Если вы определяете более одной процедуры в расширении, сначала нужно проверить параметр «name», чтобы увидеть, какая процедура вызывается GIMP. Мы не будем здесь на этом останавливаться.

   Чтобы инициализировать процедуру расширения, сначала нужно создать её и ввести имя функции Python, которая будет выполнять фактическую работу. Для этого мы вызываем Gimp.ImageProcedure.new.

           procedure = Gimp.ImageProcedure.new(self, name,
                                               Gimp.PDBProcType.PLUGIN,
                                               self.run, None)

   В данном случае мы определяем имя нашего расширения как `self.run`. Когда мы квалифицируем нашу функцию с помощью «self.», это означает, что она является методом внутри нашего класса. При желании вы также можете определить её как обычную функцию вне вашего класса, в этом случае вы опустите «self.». Называть её «run» не обязательно, можно дать ей любое имя, которое принимает Python.

2. Далее мы сообщим GIMP, с какими типами изображений может работать это расширение, вызвав procedure.set_image_types. Если тип изображения не имеет значения, мы используем «*», что означает все типы, поддерживаемые GIMP. Другие примеры:

   1. «RGB*,GRAY*», где «*» означает, что мы поддерживаем как версии с каналом A(lpha), так и без него.

   2. «INDEXED» — расширение работает только с индексированными изображениями без альфа-канала.

   3. «RGBA» — расширение работает только с изображением RGB без альфа-канала.

3. Возможность запускать расширение из меню GIMP обычно является хорошей идеей. Мы начинаем с определения описательной метки для пункта меню: procedure.set_menu_label.

4. Затем указываем, где в меню он должен появиться: procedure.add_menu_path. В этом случае мы указываем, что расширение должно быть добавлено в меню «Фильтры» в категории «Инструкция» (подменю).

5. При желании можно также добавить дополнительную подсказку, используя procedure.set_documentation, а также можете указать своё имя в качестве автора расширения, используя procedure.set_attribution.

6. Последняя строка в процедуре — `return procedure`, которая отправляет добавленную выше информацию обратно в GIMP. После этого GIMP вызовет вашу процедуру run.

#### 4.1.3. Добавление главной точки входа в расширение

Каждое расширение запускается вызовом `Gimp.main`.

            Gimp.main(MyFirstPlugin.__gtype__, sys.argv)

Единственное, что нужно изменить в этой строке для вашего расширения — имя класса расширения, здесь называемого «MyFirstPlugin».

#### 4.1.4. Полное расширение для Python

Ниже мы представляем весь сценарий на языке Python, который должен запускаться, если ему дано правильное имя в каталоге с таким же именем в месте, которое известно GIMP. Он покажет сообщение «Hello world!» в консоли ошибок или во всплывающем диалоговом окне.

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    #
    #   GIMP - The GNU Image Manipulation Program
    #   Copyright (C) 1995 Spencer Kimball and Peter Mattis
    #
    #   gimp-tutorial-plug-in.py
    #   sample plug-in to illustrate the Python plug-in writing tutorial
    #   Copyright (C) 2023 Jacob Boerema
    #
    #   This program is free software: you can redistribute it and/or modify
    #   it under the terms of the GNU General Public License as published by
    #   the Free Software Foundation; either version 3 of the License, or
    #   (at your option) any later version.
    #
    #   This program is distributed in the hope that it will be useful,
    #   but WITHOUT ANY WARRANTY; without even the implied warranty of
    #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    #   GNU General Public License for more details.
    #
    #   You should have received a copy of the GNU General Public License
    #   along with this program.  If not, see <https://www.gnu.org/licenses/>.

    import sys

    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 GLib

    class MyFirstPlugin (Gimp.PlugIn):
        def do_query_procedures(self):
            return [ "jb-plug-in-first-try" ]

        def do_set_i18n (self, name):
            return False

        def do_create_procedure(self, name):
            procedure = Gimp.ImageProcedure.new(self, name,
                                                Gimp.PDBProcType.PLUGIN,
                                                self.run, None)

            procedure.set_image_types("*")

            procedure.set_menu_label("My first Python plug-in")
            procedure.add_menu_path('<Image>/Filters/Tutorial/')

            procedure.set_documentation("My first Python plug-in tryout",
                                        "My first Python 3 plug-in for GIMP 3.0",
                                        name)
            procedure.set_attribution("Your name", "Your name", "2023")

            return procedure

        def run(self, procedure, run_mode, image, drawables, config, run_data):
            Gimp.message("Hello world!")
            # do what you want to do, then, in case of success, return:
            return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())

    Gimp.main(MyFirstPlugin.__gtype__, sys.argv)

3.7. Ваш сценарий и его работа |  | Часть III. Справочник по функциям

Report a bug in GIMP Сообщите об ошибке в нашем баг-трекере