Bilder vom Band
Mit dem Perl-Modul für Gimp lassen sich viele Arbeiten zur Verschönerung von Web-Seiten beschleunigen und automatisieren: Knöpfe gleicher Größe und mit konsistentem Layout erfordern kaum noch mühsame Handarbeit.
- Marc Lehmann
Homepages verwenden oft zahlreiche ähnliche Grafiken für Icons. Diese lassen sich mit dem freien Gimp zwar herstellen, aber das ist mit viel und vor allem stupider Arbeit verbunden - vor allem, wenn man sich nach der Hälfte der Icons entscheidet, das Design etwas zu verändern. Doch auch dafür gibt es eine Lösung: Script-Fu, die in Gimp eingebaute Skriptsprache, die auf Scheme basiert. Ihre Syntax ist jedoch gewöhnungsbedürftig, und nicht jeder beschäftigt sich gerne damit, Klammern zu zählen. Deshalb habe ich eine Perl-Schnittstelle für Gimp entwickelt; Gimp-Perl ist inzwischen Teil von Gimp 1.1.
Es unterscheidet sich in einigen Aspekten von Skript-Fu: Die zugrundeliegende Sprache ist Perl; die Programme kann man direkt von der Kommandozeile starten, was besonders beim Testen hilfreich ist; CGI-Skripte sind leicht zu erstellen und Versionsunterschiede zwischen Gimp 1.0 und der aktuellen Entwicklungsversion 1.1 fängt das Modul weitgehend ab.
Gimps Programmierschnittstelle ist für alle Skriptsprachen ähnlich und auf den ersten Blick rein prozedural: der Gimp-Kern definiert einige hundert Funktionen, zusammen mit Filtern und Erweiterungen sind es weit über 700. Damit man nicht den Überblick verliert, sind diese Funktionen in der prozeduralen Datenbank (PDB) von Gimp registriert. Sie speichert Informationen über den Namen des Autors, Typ, Anzahl und Namen der Parameter sowie Rückgabewerte. Hilfetexte zu jeder Funktion und jedem Parameter erleichtern die Arbeit. Diese Datenbank kann man interaktiv mit den Plug-ins ‘DB Browser’ oder ‘PDB Explorer’ erkunden, beide im ‘Xtns’-Menü zu finden.
Um etwa die Größe einer Ebene zu ändern, benutzt man die Funktion gimp_layer_resize:
gimp_layer_resize (LAYER ebene,
INT32 neue_breite, INT32 neue_hoehe,
INT32 x_offset, INT32 y_offset);
Ihr erster Parameter bezeichnet die zu ändernde Ebene, die nächsten beiden geben die neue Breite und Höhe in Pixeln an. Die letzten schreiben vor, wie viele Pixel links und oben anzufügen sind. Bei Vergrößerungen wird der zusätzliche Raum normalerweise rechts und unterhalb der Ebene plaziert. Möchte man einen Teil des Platzes links oder oben anfügen, muß man diese Parameter entsprechend setzen.
Listing 1 ist ein einfaches aber dennoch nützliches Skript aus der Gimp-Distribution, das gimp_layer_resize() benutzt: Oft kommt es vor, daß man eine einzelne Ebene auf die gleiche Größe wie das Gesamtbild bringen möchte. Per Hand geht dies nur relativ umständlich, deshalb existiert der Menüpunkt ‘Image/Layers/Layer to Image Size’, hinter dem sich dieses Skript verbirgt.
LISTING 1
# Einfaches Beispiel zur Nutzung von Gimp-Perl
# Paßt Größe eines Layers an Bildgröße an
use Gimp;
use Gimp::Fu;
Gimp::set_trace(TRACE_NAME);
register "layer_to_image_size", # Funktionsname
"Layer to Imagesize", # Kurzhilfe
"Expands layer to image size",
# Hilfetext
"Seth Burgess", # Autor
"Seth Burgess <sjburges\@gimp.org>",
# Copyright
"1.0", # Version/Datum
"<Image>/Layers/Layer to Image Size",
# Menüpfad
"*", # Bildtypen
[], # Eingabeparameter
sub { # Perl-Code
my ($image, $layer) = @_;
$layer->layer or
die "This function works only with layers\n";
$layer->resize($image->width, $image->height,
$layer->offsets);
();
};
exit main;
Dokumentation im Plug-in
Da das Skript im wesentlichen aus einem Funktionsaufruf mit zahlreichen Parametern besteht, sieht es auf den ersten Blick etwas kompliziert aus. Die meisten Gimp-Perl-Programme benutzen lediglich Gimp::Fu::register, um eine Funktion und einen Menüpunkt zu registrieren, und springen dann per exit main in die Hauptschleife, ähnlich einem Tk- oder Gtk-Programm.
Die ersten acht Parameter von register() sind einfache Zeichenketten. Dem Funktionsnamen stellt das Modul beim Registrieren im Gimp automatisch perl_fu_ voran; andere Plug-ins in beliebigen Sprachen oder Gimp selbst können sie dann unter diesem Namen benutzen. Der zweite Parameter sollte die Funktion kurz beschreiben. Dieser Text erscheint beim Arbeiten mit Gimp an vielen Stellen unaufgefordert. Der Hilfetext dagegen kann ausführlicher sein. Bei komplexen Plug-ins kann und sollte die Beschreibung mehrere Seiten umfassen. Um dies zu unterstützen, wird auch die in das Skript eingebettete Pod-Dokumentation (Plain Old Documentation) ausgewertet, ein Druck auf den ‘Help’-Button zeigt sie automatisch mit an.
Was man genau bei Autor und Copyright angibt, ist Ermessenssache, mindestens ein Feld sollte aber die EMail-Adresse eines Ansprechpartners enthalten. Ähnlich sieht es mit dem Versionsfeld aus. Erwünscht ist hier das Datum der letzten Änderung, viele Autoren geben aber auch eine Versionsnummer an. Wichtig ist nur, daß eine neuere Version des Skripts eine größere höhere Ziffer hat.
Bedeutsamer ist der Menüpfad, denn Gimp um eigene Funktionen zu erweitern hilft wenig, wenn der Benutzer sie nicht ausführen kann. Mit diesem Argument kann man deshalb angeben, wo das Programm die Funktion in seine Menüs einbinden soll. Untermenüs sind durch ‘/’ voneinander getrennt. Soll das Plug-in in das Menü der Toolbox aufgenommen werden, muß der Menüpfad mit ‘<Toolbox>’ beginnen, ähnlich sorgt ‘<Image>’ am Anfang des Menüpfades dafür, daß der Filter im Kontextmenü landet. Das Skript in Listing 1 erscheint also im Untermenü ‘Layers’ des Kontextmenüs. Mit dem drittletzten Parameter kann man festlegen, daß nur bestimmte Typen von Bildern erlaubt sind. Ein ‘*’ an dieser Stelle akzeptiert alles. Mit ‘RGB’ könnte man die Auswahl auf Echtfarbbilder beschränken, bei anderen Bildtypen ist der Menüpunkt dann inaktiv.
Gimp kann diese Menüpunkte nur zeigen, wenn ihm das Skript bekannt ist. Das läßt sich durch Kopieren in ein festgelegtes Verzeichnis erledigen, das er beim Start nach neuen Programmen durchsucht. Dazu kann man den Befehl gimptool benutzen:
gimptool -install-bin <skriptname>
installiert das Skript im Standardverzeichnis für benutzereigene Filter;
gimptool -install-admin-bin <skriptname>
kopiert es in das systemweite Plug-in-Verzeichnis. Dafür sind Administratorrechte nötig. Diese Methode bietet sich besonders für ‘fertige’ Filter an, die man sich beispielsweise aus dem Internet besorgt hat. Da Gimp nach jeder Installation neu zu starten ist, wäre das ständige Kopieren des Skripts beim Entwickeln ziemlich hinderlich.
Gimp-Server für Batch-Betrieb
Dafür gibt es ein zweites Verfahren: Gimp-Perl kommt mit dem speziellen Plug-in Perl-Server im Xtns-Menü. Wenn es durch Anklicken in Gang gebracht ist, können andere Gimp-Perl-Skripts von der Kommandozeile gestartet werden. Bei dieser Methode zeigt Gimp keinen Menüpunkt an.
Findet ein so aufgerufenes Skript keinen Perl-Server, etwa weil Gimp gar nicht läuft, startet es das Programm kurzerhand selbst, allerdings ohne Fenster. Dies ist hilfreich, wenn man Bilder im Batch-Betrieb manipulieren möchte. Wenn das Skript ein Bild als Rückgabewert hat, kann man dieses mit dem Parameter -o <dateiname> speichern.
Leere Klammern [] im vorletzten Parameter des register()-Aufrufs geben an, daß das Skript keine Eingabeparameter erwartet. Weil das Plug-in in Listing 1 im Kontextmenü untergebracht ist, übergibt ihm Gimp trotzdem zwei Argumente: Als erstes das Bild, auf das der Filter wirken soll, als zweites die zum Zeichnen zu benutzende Ebene oder den Kanal.
Als letzter Parameter des register()-Aufrufs kommt das eigentliche Skript als Codereferenz. Um sie zu erzeugen, kann man entweder die Perl-Funktion als namenloses sub { … } direkt angeben, oder man definiert eine normale Routine und nimmt deren Referenz: \&perl_funktion.
Weil sich kaum jemand diese vielen Argumente merken kann, schreibt man Gimp-Perl-Skripts üblicherweise nicht von neuem, sondern geht von einem bestehenden aus. examples/example-fu.pl aus der Gimp-Distribution dient genau diesem Zweck: man kopiert es, streicht das heraus, was man nicht braucht, ersetzt den Namen das Autors und kann dann loslegen.
Das eigentliche Skript besteht aus vier Zeilen, von denen zwei Gimp-Funktionen aufrufen. Das my in der ersten Zeile speichert lediglich Bild und Ebene/Kanal in den lokalen Variablen $image und $layer. Das bedeutet allerdings noch nicht, daß sich in $layer tatsächlich eine Ebene befindet. Prüfen kann man das mit der Methode layer. Liefert sie false, beendet sich das Skript durch Aufruf von die mit einer Fehlermeldung. Bei interaktivem Einsatz öffnet sich dann ein kleines Meldungsfenster, und das Skript wird abgebrochen, eigene Dialogfenster braucht man also nicht zu programmieren.
In der nächsten Zeile geschieht die eigentliche Arbeit: Sie ruft die Objektmethode resize mit den Argumenten $image->width, $image->height und $layer->offsets auf. Letztere Methode liefert die Koordinaten der linken oberen Ecke. Die resize-Methode fügt dann genauso viele Pixel am oberen und am linken Rand hinzu.
Der ‘Smiley’ (); am Ende des Skripts gibt eine leere Liste zurück. Dasselbe hätte man mit return; erreichen können, aber das sähe längst nicht so schön aus. Eine leere Liste muß man zurückgeben, sonst würde das Gimp::Fu-Modul versuchen, diese Rückgabewerte zu interpretieren, was oft hilfreich ist, hier aber stört.
Hinter der resize-Methode steckt Gimps gimp_layer_resize(). Genauso ist width nichts anderes als die Funktion gimp_image_width() unter anderem Namen. Die langen Funktionsnamen sind jeweils in der PDB dokumentiert, aber woher weiß man, welche Methoden zu welchen Objekten passen?
Abkürzungen für Methoden
Grundsätzlich kann man alle Funktionen der PDB benutzen, indem man ihnen ein Gimp-> voranstellt und so eine statische Methode des Gimp-Moduls aufruft:
Gimp->gimp_image_width($image);
dafür bietet das Gimp-Modul einige Abkürzungen, die im Kasten ‘Sparsame Aufrufe’ näher erläutert werden. Selbst wenn man alle diese Features benutzt, treten hin und wieder Fehler auf. Scheme-Programmierer verwenden häufig die Konstanten TRUE und FALSE, die Perl nicht kennt. Nicht einmal der -w-Schalter des Perl-Interpreters meldet diesen Fehler, ein use strict am Anfang des Skripts (oder die neueren Versionen des Gimp-Moduls) dagegen schon. Selbst wenn die Syntax stimmt, bedeutet das noch lange nicht, daß die Parameter alle im korrekten Wertebereich liegen. Gimp kennt dabei nur eine Fehlermeldung:
procedural database execution failed \
at <dateiname> line <zeilennummer>.
Sparsame Aufrufe
Wenn der Aufruf über eine der vordefinierten statischen Klassen erfolgt (Gimp, Layer, Image und so weiter) kann man einen Teil des Namens weglassen. Layer->new($image,…) ist eine Abkürzung für Gimp->gimp_layer_new($image,…), ebenso wie new Layer($image,…)
Dasselbe gilt für Methodenaufrufe, die Objekte benutzen. Statt gimp_layer_new ($image,600,300,RGB) kann man $image->layer_new(600,300,RGB) schreiben. Viele Funktionen (besonders in Version 1.0 von Gimp) verlangen zusätzlich zur Ebene oder zum Kanal ein redundantes Bildobjekt, das Perl-Programmierer weglassen können. Dadurch läuft ein Skript ohne Änderungen auch mit den neueren Versionen von Gimp. Aus dem langen Gimp->layer_shear ($image,$layer,…) wird Gimp->layer_shear ($layer,…) oder noch kürzer $layer->shear(…)
Andere Filterfunktionen erwarten im allgemeinen als erstes Argument eine Konstante, die angibt, ob sie interaktiv laufen sollen oder nicht (RUN_INTERACTIVE/RUN_NONINTERACTIVE). Weil man aus einem Skript in fast allen Fällen einen nicht-interaktiven Aufruf wünscht, benutzt man standardmäßig RUN_NONINTERACTIVE. In Kombination mit den anderen Regeln spart das viel Platz. Ein
Gimp->plug_in_gauss_rle \
(RUN_NONINTERACTIVE,$image,$layer,8,1,1)
verkürzt sich dadurch letztlich zu
$layer->gauss_rle (8,1,1)
Die Zeilennummer sagt immerhin, wo der Fehler aufgetreten ist, warum die Ausführung fehlschlug, erfährt man jedoch nicht. Dabei hilft die Ablaufverfolgung des Gimp-Moduls. Dazu fügt man einfach irgendwo im Skript, vorzugsweise am Anfang, einen Aufruf der Funktion set_trace() ein:
Gimp::set_trace(TRACE_NAME);
Während der Ausführung gibt Gimp dadurch alle Befehle mit ihren Parametern aus. Beim ersten Beispiel sähe das so aus:
gimp_drawable_layer(drawable=3) = (layer=1)
gimp_image_width(image=0) = (width=256)
gimp_image_height(image=0) = (height=256)
gimp_drawable_offsets(drawable=3)
= (offset_x=51, offset_y=63)
gimp_layer_resize(layer=3,
new_width=256, new_height=256,
offx=51, offy=63) = ()
Das erste Beispiel ist zwar für die praktische Arbeit nützlich, aber nicht sonderlich spektakulär. Das zweite, längere in Listing 2 zeigt deshalb meinen Beitrag zur Zufallskunst: Das Programm erzeugt ein neues, leeres Bild und wählt wiederholt ein zufälliges, abgerundetes Polygon aus, das es mit einem zufälligen Gradienten aus zufälligen Farben füllt. Trotz so vieler Zufälle kommen dabei ansehnliche Muster heraus, die an eingefärbte Schlieren oder Spiegelungen erinnern.
LISTING 2
# Zufallskunst mit Gimp-Perl: zufällige Polygone
# mit runden Ecken werden mit zufälligen Farben gefüllt
use Gimp;
use Gimp::Fu;
# Definiere die Konstante "pi mal zwei"
use constant PIx2 => 8 * atan2 1,1;
register "random_art", # Funktionsname
"Creates a Random Image", # Kurzhilfe
"Create an image by repeatedly drawing colourful polygones.",
# Hilfetext
"Marc Lehmann", # Autor
"Marc Lehmann <pcg\@goof.com",
# Copyright
"0.2", # Version/Datum
"<Toolbox>/Xtns/Render/Random Art",
# Menüpfad
"", # Bildtypen
[
[PF_INT32, ’size’, ’Image Size’, 300],
[PF_INT32, ’num_poly’, ’Number of Polygons’, 20],
],
sub {
my ($size,$num_poly)=@_;
my $image = new Image($size,$size,RGB);
my $layer = $image->layer_new($size,$size,
RGBA_IMAGE, "Random Art",100,
NORMAL_MODE);
$image->add_layer($layer,0);
Palette->set_background(’white’);
$layer->fill(BG_IMAGE_FILL);
for (1..$num_poly) {
my @ecken;
for (0..9) {
my $r = rand($size*0.4)+$size*0.1;
push(@ecken, $size/2+sin($_*PIx2/10)*$r,
$size/2+cos($_*PIx2/10)*$r);
}
$image->free_select(\@ecken, SELECTION_REPLACE,
1, 1, 30);
Palette->set_foreground([rand(256),
rand(256),rand(256)]);
Palette->set_background([rand(256),
rand(256),rand(256)]);
$layer->blend (FG_BG_HSV, DIFFERENCE_MODE,
LINEAR, 100,
0, REPEAT_TRIANGULAR,
1, 2, 3,
$size/2, $size/2,
rand($size*0.6), rand($size*0.6));
$layer->channel_ops_offset (1,0,rand($size),rand($size));
}
$image;
};
exit main;
Ein wichtiger Unterschied zum ersten Beispiel besteht darin, daß diesmal zwei Parameter ins Spiel kommen: Der erste gibt die Bildgröße an, der zweite legt fest, wie viele Polygone ausgewählt, gefüllt und verschoben werden sollen.
Damit Gimp beziehungsweise Gimp-Perl das bemerkt, muß dies im neunten (vorletzten) Argument dokumentiert sein. Im ersten Beispiel stand dort lediglich ein leeres Feld. Jetzt sind es zwei Parameterbeschreibungen. Jede besteht wiederum aus einem Feld mit mindestens drei Elementen: Typ, Parametername, Beschreibung und (optional) eine Voreinstellung.
Typ ist ein normaler (PF_COLOUR, PF_INT32 et cetera) oder ein erweiterter Datentyp aus dem Gimp::Fu-Modul (zum Beispiel PF_SLIDER, PF_FILE). Der Name sollte kurz und prägnant sein, da er unter anderem für die Kommandozeilenargumente benutzt wird. Die Beschreibung kann dafür schon etwas länger sein. Diese zusätzlichen Parameter bekommt das Skript ganz normal übergeben. Da es nicht auf ein vorhandenes Bild wirkt (der Menüpfad fängt mit ‘<Toolbox>’ und nicht mit ‘<Image>’ an), erhält es keine zusätzlichen Argumente.
Zunächst erzeugt das Programm ein neues Bild mit dem new-Konstruktor der Image-Klasse. Seine ersten beiden Parameter geben Breite und Höhe an, der dritte den Typ, hier RGB für ein Echtfarbbild. Weil das Bild noch leer ist, muß eine Ebene erzeugt und hinzugefügt werden. Ersteres erledigt die Funktion gimp_layer_new(). Ihre Argumente geben die Größe und den Typ an, zudem den Namen, die Deckung (hier 100 %) und einen Modus (NORMAL_MODE). Der folgende Aufruf von gimp_image_add_layer fügt diese dann an der Stelle ‘0’ (als erstes) in das Bild ein.
Zeichnen nur im Polygon
Palette->set_background (’white’) setzt die aktuelle Hintergrundfarbe auf weiß, anschließend löscht gimp_drawable_fill die neu erzeugte Ebene, die sonst Datenmüll enthielte. In der for-Schleife entsteht der eigentliche Effekt: Als erstes werden die Ecken eines (relativ runden) Polygons erzeugt. gimp_free_select() wählt dieses Polygon dann aus. Nachfolgende Zeichenoperationen wirken nur auf diesen Teil des Bildes.
Für die Fülloperation bestimmt das Skript zwei zufällige Farben. Außer durch Farbnamen kann man eine Farbe durch Rot-, Grün- und Blauwert angeben, Rot wäre zum Beispiel [255,0,0]. Die Fülloperation selbst (gimp_blend) benötigt sehr viele Parameter, deren Bedeutung man dem PDB entnehmen kann. Die merkwürdig klingende Funktion gimp_channel_ops_offset dient lediglich dazu, das Bild zufällig etwas zu verschieben. Sie entspricht dem Menüpunkt ‘Image/Channel Ops/Offset’. Damit das neue Bild, das bisher unsichtbar war, erscheint, gibt die Funktion es am Ende als Ergebnis zurück. Wird das Skript von der Kommandozeile aus gestartet, erscheint übrigens kein Fenster, statt dessen kann man das Bild mit dem Kommandozeilenparameter -o <dateiname> gleich speichern.
Wenn sich die erzeugten Bilder ähneln, so liegt das unter anderem daran, daß viele Parameter (wie Polygonradius oder Art des Farbverlaufes) ‘festverdrahtet’ sind und man nur zwei Eingabeparameter verändern kann.
MARC LEHMANN
ist Mitglied im GCC Steering Committee und Autor der Gimp-Perl-Schnittstelle. Er studiert Informatik an der Uni Karlsruhe.
iX-TRACT
- Gimp-Perl ist ein Perl-Modul, das den Zugriff auf alle Gimp-Funktionen bietet.
- Mit seiner Hilfe lassen sich programmatisch Bilder erstellen und bearbeiten, etwa einheitliche Knöpfe für Web-Seiten.
- Das Modul startet Gimp gegebenenfalls selbst und speichert das erzeugte Bild in einer Datei.
Erforderliche Software
Perl: Minimal: 5.004_04, empfohlen: 5.005_03.
Gimp: Mindestens 1.0.2, empfohlen 1.0.4 (stabil) oder 1.1.x (Entwicklerversion). Gimp-1.1.x enthält das Perl-Modul bereits. Gimp benötigt glib und gtk+, alle diese Pakete bei http://www.gimp.org/
Gimp-Perl: Verfügbar auf jedem CPAN-Mirror, die Homepage (mit Tutorials, Manpages et cetera) ist http://gimp.pages.de/
Optionale Perl-Module
Gtk: Empfohlen: 0.5120 oder die gnome-perl-Version. Dieses Modul ist zwar optional, ohne es werden aber keine Dialogfenster angezeigt.
Data::Dumper: Dieses Modul ist Teil der Standardinstallation von Perl-5.005, Perl-5.004-Nutzer sollten es nachinstallieren.
PDL: Minimal: 1.998, empfohlen: 2.0 Die Perl Data Language ist nur notwendig für Skripte, die Pixeldaten direkt manipulieren wollen.
Parse::RecDescent: Dieses Modul wird lediglich vom Script-Fu => Perl-Konverter benutzt.
Alle Module sind auf dem CPAN erhältlich, in Deutschland unter anderem bei:
(ck)