4. Ένα σεμινάριο γραφής προσθέτου Python

Αυτό το σεμινάριο θα σας διδάξει τα βασικά σχετικά με τη σύνταξη ενός προσθέτου Python για το GIMP 3.0. Αναμένεται να έχετε ήδη κάποιες βασικές γνώσεις σχετικά με τη σύνταξη Python γενικά. Εάν όχι, υπάρχουν αρκετά μαθήματα Python στο διαδίκτυο, δεν πρόκειται να τα επαναλάβουμε εδώ.

Τα πρόσθετα Python στο GIMP (και άλλες γλώσσες επίσης) καλούνται από το GIMP, για να εκτελέσουν ορισμένες ενέργειες. Για να είναι σε θέση να γνωρίζει πώς να επικοινωνεί και να καλεί το πρόσθετο, το GIMP πρέπει να γνωρίζει με ποιο όνομα να το αποκαλεί και ποιες λειτουργίες υποστηρίζει.

There are certain requirements regarding a plug-in's filename and directory name, which have to be the same. For more details see Installing New Plug-Ins.

4.1. Τα βασικά στοιχεία ενός προσθέτου για το GIMP

Θα συζητήσουμε τα βασικά μέρη ενός προσθέτου που απαιτούνται, ή τουλάχιστον είναι πολύ συνηθισμένα για την εργασία με το GIMP.

  • Δεν απαιτείται, αλλά είναι κοινή πρακτική να ξεκινήσετε με ένα hashbang (#!), μια κωδικοποίηση και σημείωση πνευματικών δικαιωμάτων. Η πρώτη γραμμή είναι συνήθως ένα hashbang, το οποίο καθορίζει πώς μπορεί να εκτελεστεί αυτό το σενάριο. Η επόμενη γραμμή καθορίζει την κωδικοποίηση του αρχείου Python. Προτείνουμε το utf-8. Συνήθως αυτό ακολουθείται από πολλές γραμμές που καθορίζουν την άδεια με την οποία δημοσιεύετε το σενάριο και μια σύντομη περιγραφή του τι κάνει το σενάριο. Δεν θα εμβαθύνουμε σε αυτό, καθώς αυτό είναι κοινό για την Python γενικά.

  • Εισαγωγή απαιτούμενων λειτουργικών μονάδων για πρόσβαση σε συναρτήσεις GIMP και προαιρετικά GEGL.

  • Δηλώστε μια τάξη με πολλές προκαθορισμένες συναρτήσεις που πρέπει να προσαρμόσετε, ώστε το GIMP να γνωρίζει ποιες συναρτήσεις είναι διαθέσιμες στο πρόσθετό σας και ποιες λειτουργίες υποστηρίζουν. Θα πάμε σε περισσότερες λεπτομέρειες σχετικά με αυτό παρακάτω.

  • Μια κλήση που ξεκινά το πρόσθετο σας, ή θέτει ερωτήματα για τις δυνατότητές του, ανάλογα με τα ορίσματα που του αποστέλλονται από το GIMP.

4.1.1. Απαιτούμενες λειτουργικές μονάδες

Για να μπορέσουμε να προσπελάσουμε στις συναρτήσεις GIMP, ξεκινάμε με το import gi. Αυτή η ενότητα μπορεί να καταλάβει ποιες συναρτήσεις είναι διαθέσιμες σε κάθε ενότητα που ορίζεται μέσω της «ενδοσκόπησης αντικειμένου (object introspection)». Αυτό σημαίνει για εμάς, είναι ότι εισάγουμε όλες τις ενότητες που σχετίζονται με το 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.

Υπάρχουν και άλλες προαιρετικές λειτουργικές μονάδες που μπορείτε να χρησιμοποιήσετε, όπως το Gegl και το Glib μεταξύ πολλών άλλων, αλλά δεν θα αναφερθούμε σε αυτές εδώ.

4.1.2. Καθορίστε την κλάση του πρόσθετου

Το GIMP πρέπει να γνωρίζει ποιες συναρτήσεις είναι διαθέσιμες, ποιες λειτουργίες υποστηρίζει και ποια θέση μενού να χρησιμοποιήσει. Για αυτό ορίζουμε μια κλάση που προέρχεται από την κλάση Gimp.PlugIn.

Ένα ελάχιστο πρόσθετο χρειάζεται τουλάχιστον τις ακόλουθες λειτουργίες που ορίζονται σε αυτήν την κλάση:

  • Μια μέθοδος do_query_procedure, την οποία καλεί το GIMP για να ανακαλύψει τα ονόματα των διαδικασιών που μπορούν να κληθούν σε αυτό το πρόσθετο.

  • Μια μέθοδο do_set_i18n, την οποία καλεί το GIMP για να διαπιστώσει εάν το πρόσθετό σας υποστηρίζει μεταφράσεις.

  • Μια μέθοδος do_create_procedure, την οποία το GIMP καλεί για να ξεκινήσει μία από τις συναρτήσεις των προσθέτων σας. Όταν καλείται αυτή, θα πρέπει να αρχικοποιήσετε ορισμένες πληροφορίες για το GIMP. Ξεκινάτε δημιουργώντας μια διαδικασία που λέει στο GIMP το όνομα της συνάρτησης Python που πρέπει να καλέσει για να ξεκινήσει το πρόσθετό σας. Στη συνέχεια, παρέχετε πρόσθετες πληροφορίες, όπως ποιους τύπους εικόνων υποστηρίζει το πρόσθετό σας, πού στο μενού πρέπει να βρίσκεται το πρόσθετο και άλλες προαιρετικές ρυθμίσεις.

  • Η ενεργή συνάρτηση (που ονομάζεται διαδικασία από το 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, n_drawables, 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())
      

Ας ρίξουμε μια πιο προσεκτική ματιά στο do_create_procedures. Στη γραμμή return [ "jb-plug-in-first-try" ] λέμε στο GIMP ποιο είναι το όνομα της διαδικασίας μας: την ονομάζουμε "jb-plug-in-first-try". Αυτό είναι το όνομα που θα εμφανίζεται στο Πρόγραμμα περιήγησης διαδικασίας του GIMP.

Μπορείτε να ορίσετε περισσότερες από μία διαδικασίες σε ένα πρόσθετο. Σε αυτήν την περίπτωση, θα αναφέρετε όλα τα ονόματα, χωρισμένα με κόμμα.

Είναι καλή πρακτική να ξεκινάτε όλες τις διαδικασίες σας με τα αρχικά σας, ή κάποια άλλη αναγνωρίσιμη και μοναδική ετικέτα. Με αυτόν τον τρόπο, είναι λιγότερο πιθανό το όνομά σας να είναι ίδιο με το πρόσθετο κάποιου άλλου, γεγονός που μπορεί να προκαλέσει σύγχυση στο 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*", όπου το "*" εδώ σημαίνει ότι υποστηρίζουμε και τις δύο εκδόσεις με και χωρίς κανάλι ά(λφα).

    2. "INDEXED", το πρόσθετο λειτουργεί μόνο σε εικόνες με ευρετήριο, χωρίς κανάλι άλφα.

    3. "RGBA", το πρόσθετο λειτουργεί μόνο σε εικόνα RGB με κανάλι άλφα.

  3. Το να μπορείτε να ξεκινήσετε το πρόσθετό σας από το μενού του GIMP είναι συνήθως μια καλή ιδέα. Ξεκινάμε ορίζοντας μια περιγραφική ετικέτα για την καταχώρηση μενού: procedure.set_menu_label.

  4. Ακολουθεί ο καθορισμός της θέσης στο μενού που πρέπει να φανεί: procedure.add_menu_path. Σε αυτήν την περίπτωση, του λέμε να προσθέσει το πρόσθετό μας στο μενού Φίλτρα, στην κατηγορία Tutorial (υπομενού).

  5. Εάν θέλετε, μπορείτε επίσης να προσθέσετε μια επιπλέον συμβουλή βοήθειας, χρησιμοποιώντας procedure.set_documentation και μπορείτε να ορίσετε το όνομά σας ως συντάκτη του προσθέτου χρησιμοποιώντας το procedure.set_attribution .

  6. Η τελευταία γραμμή στη διαδικασία δημιουργίας είναι η return procedure, η οποία στέλνει τις πληροφορίες που προστέθηκαν παραπάνω πίσω στο GIMP. Μετά από αυτό, το GIMP θα καλέσει τη διαδικασία εκτέλεσης.

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, n_drawables, 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)