4. En handledning i att skriva Python-insticksmoduler

Denna handledning kommer lära dig grunderna om att skriva en insticksmodul i Python för GIMP 3.0. Du förväntas redan ha viss grundläggande kunskap om att skriva Python i allmänhet. Om inte så finns det redan tillräckligt med Python-kurser på nätet, så vi kommer inte att kopiera det här.

GIMP-insticksmoduler i Python (och även andra språk) anropas inifrån GIMP för att utföra specifika åtgärder. För att kunna veta hur det ska kommunicera med och anropa insticksmodulen behöver GIMP veta med vilket namn den ska anropas och vilka funktioner den stöder.

Det finns vissa krav vad gäller en insticksmoduls filnamn och katalognamn, vilka behöver vara desamma. För mer detaljer, se Installera nya insticksmoduler.

4.1. De grundläggande elementen för en insticksmodul i GIMP

Vi kommer diskutera de grundläggande delar av en insticksmodul som krävs, eller i alla fall är väldigt vanliga för arbete med GIMP.

  • På Linux och macOS krävs, och det är även vanligt förekommande på Windows, att starta med en så kallad shebang eller hashbang, en kodning, och en upphovsrättsnotis. Den första raden är en shebang, vilken anger hur detta skript kan köras. Nästa rad anger kodningen för Python-filen. Vi rekommenderar UTF-8. Vanligen följs detta av flera rader som anger licensen som du publicerar skriptet under och en kort beskrivning av vad skriptet gör. Vi kommer inte gå djupare in på detta då det är gemensamt med Python i allmänhet.

  • Importera moduler som krävs för att få åtkomst till GIMP-funktioner och valfritt även GEGL-funktioner.

  • Deklarera en klass med flera fördefinierade funktioner som du behöver justera, så att GIMP vet vilka funktioner som är tillgängliga i din insticksmodul, och vilken funktionalitet de stöder. Vi kommer gå igenom detta i mer detalj nedan.

  • Ett anrop som startar din insticksmodul, eller efterfrågar dess förmågor, beroende på de argument som skickas till den av GIMP.

4.1.1. Moduler som krävs

För att kunna komma åt GIMP-funktioner startar vi med import gi. Denna modul kan avgöra vilka funktioner som är tillgängliga i varje modul som definieras genom objektintrospektion. Vad detta betyder för oss är att vi importerar alla GIMP-relaterade moduler som vi kan behöva genom anrop till gi.repository.

För grundläggande funktionalitet kan modulerna Gimp och GimpUi vara tillräckligt. Om du vill köra din insticksmodul från kommandoraden behöver du inte ens GimpUi. Låt oss börja med ett exempel.

#!/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
      

Vi börjar med att importera sys, vilket vi behöver i slutet för åtkomst till sys.argv, efter det säger import gi till Python att det behöver läsa in modulen gi. Denna modul används för att aktivera åtkomst till GIMP-specifika funktioner genom objektintrospektion.

På nästa rad säger vi till gi att vi kräver att GIMPs API-version ska vara version 3.0. (Denna insticksmodul kommer inte fungera med äldre versioner av GIMP.) Raden efter begär att importera all funktioner, klasser och så vidare från modulen Gimp.

De följande två raderna gör samma sak för GimpUi. GimpUi innehåller alla gränssnittsrelaterade element för GIMP. Om du planerar att göra en insticksmodul som endast kommer anropas från kommandoraden så behöver du inte detta. Vi avslutar med att importera GLib vilket vi kommer behöva senare för åtkomst till GLib.Error.

Det finns andra valfria moduler som du också kan använda, såsom Gegl och många andra, men vi kommer inte gå in på det här.

4.1.2. Definiera klassen för din insticksmodul

GIMP behöver veta vilka funktioner som finns tillgängliga, vilken funktionalitet de stöder, och vilken menyplats att använda. För det definierar vi en klass som härleds från klassen Gimp.PlugIn.

En minimal insticksmodul behöver att åtminstone följande funktioner är definierade i denna klass:

  • En metod do_query_procedure, som GIMP anropar för att få reda på namnen på procedurerna som kan anropas i denna insticksmodul.

  • En metod do_set_i18n som GIMP anropar för att få reda på om din insticksmodul stöder översättningar.

  • En metod do_create_procedure som GIMP anropar för att starta en av din insticksmoduls funktioner. När denna anropas bör du initiera viss information för GIMP. Du börjar med att skapa en procedur som meddelar GIMP namnet på Python-funktionen att anropa för att starta din insticksmodul. Sedan tillhandahåller du ytterligare information, som vilka bildtyper din insticksmodul stöder, var i menyn din insticksmodul ska hittas, och andra valfria inställningar.

  • Den faktiska funktionen (proceduren som anropas av GIMP) som du angav ovan. Vi kallar ofta denna run, men den kan ha vilket namn som helst som tillåts av Python. Denna funktion är var du kommer lägga till din egen kod för att tillämpa dina önskade effekter.

Vi kommer nu gå in i lite djupare detalj. Vad som inte visas nedan är den första delen av Python-koden som visades ovan. Detta visar endast den grundläggande layouten för din klass.

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())
      

Låt oss ta en närmare titt på do_create_procedures. På raden return [ "jb-plug-in-first-try" ] säger vi till GIMP vad namnet på vår procedur är: vi kallar den "jb-plug-in-first-try". Detta är namnet som kommer visas i GIMPs procedurbläddrare.

Du kan ha mer än en procedur definierad i en insticksmodul. I det fallet skulle du lista alla namn, separerade av ett kommatecken.

Det är god sed att börja alla dina procedurer med dina initialer eller någon annan igenkännbar och unik tagg. På detta sätt är det mindre troligt att ditt namn kommer vara detsamma som någon annans insticksmodul, vilket kan förvirra GIMP. Förutom det är du fri att kalla den vad du vill.

Härnäst säger vi till GIMP att vi inte stöder översättningar genom att returnera False i anropen till do_set_i18n. Vad du ska göra när du vill att din insticksmodul ska översättas är utanför omfånget av denna handledning.

Metoden do_create_procedure är var det mesta initierandet för GIMP görs.

Procedur 13.1. Konfigurera do_create_procedure

  1. Om du definierar mer än en procedur i din insticksmodul behöver du först kontrollera parametern "name" för att se vilken procedur som anropas av GIMP. Vi kommer här inte gå in på det.

    För att initiera din insticksmoduls procedur behöver vi först skapa den och fylla i namnet på vår Python-funktion som kommer göra det faktiska arbetet. Vi gör det genom att anropa Gimp.ImageProcedure.new.

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

    I det här fallet definierar vi namnet på vår insticksmodul som self.run. När vi modifierar vår funktion med "self." så betyder det att det är en metod i vår klass. Om du föredrar kan du också definiera den som en vanlig funktion utanför din klass, i det fallet skulle du utelämna "self.". Att namnge den "run" krävs inte, den kan ha vilket namn som helst som Python accepterar.

  2. Härnäst kommer vi säga till GIMP vilka bildtyper denna insticksmodul kan arbeta med genom att anropa procedure.set_image_types. Ifall bildtypen inte spelar någon roll använder vi "*", vilket betyder alla typer som stöds av GIMP. Andra exempel:

    1. "RGB*,GRAY*", där "*" betyder att vi stöder både versionerna med och utan A(lfa)-kanal.

    2. "INDEXED", insticksmodulen fungerar endast på indexerade bilder, utan alfakanal.

    3. "RGBA", insticksmodulen fungerar endast på RGB-bilder med alfakanal.

  3. Att kunna starta din insticksmodul från GIMPs meny är vanligen en god idé. Vi börjar med att definiera en beskrivande etikett för menyobjektet: procedure.set_menu_label.

  4. Följt av att ange var i menyn det ska visas: procedure.add_menu_path. I det här fallet säger vi till det att lägga till vår insticksmodul i menyn Filter, i kategorin (undermenyn) Tutorial.

  5. Om du vill kan du också lägga till ett extra hjälptips genom att använda procedure.set_documentation, och du kan ställa in ditt namn som författare för insticksmodulen genom att använda procedure.set_attribution.

  6. Den sista raden i do_create_procedure är return procedure, vilket skickar informationen som lagts till ovan tillbaka till GIMP. Efter detta kommer GIMP anropa din run-procedur.

4.1.3. Lägga till den huvudsakliga ingångspunkten för din insticksmodul

Varje insticksmodul startas av ett anrop till Gimp.main.

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

Det enda du behöver ändra i denna rad för din insticksmodul är namnet på insticksmodulens klass, här kallad MyFirstPlugin.

4.1.4. Den kompletta Python-insticksmodulen

Nedan presenterar vi hela Python-skriptet, vilket bör köra, förutsatt att det ges rätt namn i en katalog med samma namn på en plats som GIMP känner till. Det kommer visa meddelandet Hello world! i felkonsolen eller i en poppuppdialog.

#!/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)