Fotografie & Bildbearbeitung

Gimp: Batch-Verarbeitung im Terminal – Beispiel: Cropping

Manche Aufgaben in Gimp sind für alle Bilder gleich - da macht es keinen Sinn, das Prozedere für jedes Bild einzeln durchzuführen. Für die Stapelverarbeitung gibt es mehrere Möglichkeiten, die Standardvariante geht über die Kommandozeile. Als Beispiel seht Ihr hier, wie Ihr alle Bilder eines Ordners mit Zealous Crop automatisch beschneiden lassen könnt.

Etwas mehr ...

Leider macht das Ganze einmalig etwas mehr Arbeit: Gimp kann nicht einfach über etwas wie gimp -batch -zealous-crop *.png aufgerufen werden - leider. Es muss ein Skript her, bei Gimp folglich über das integrierte Script-Fu für Erweiterungen. Das liegt wohl vor allem daran, dass Gimp mehrere Aufgaben ausführen muss: Bild öffnen, aktive Ebene auswählen, beschneiden und dann auch noch speichern, genauer gesagt überschreiben. Zudem muss das Skript dann auch noch korrekt aufgerufen werden.

Im Folgenden erstellt Ihr nun also ein Skript für das Cropping mehrerer Dateien und den Terminal-Befehl für dessen Aufruf. Ihr habt danach aber auch eine Vorlage: Das hier erstellte Beispielskript besteht aus den Bausteinen Dateien öffnen, Datei bearbeiten, Datei speichern - und da Öffnen und Speichern immer gleich ablaufen, könnt Ihr Cropping relativ einfach durch andere Funktionen aus Gimp ersetzen.

Was genau das Zealous Cropping macht, zeigen wir hier im Detail. Kurz: Es schneidet ein Bild auf den eigentlichen Inhalt zu.

1. Skript erstellen

Erstellt zunächst eine Datei namens beispielsweise mein-zealous.scm und speichert sie im Skript-Ordner von Gimp: Unter Linux standardmäßig etwa ~/.gimp-2.8/scripts und unter Windows C:\Users\NUTZERNAME\AppData\Roaming\GIMP\2.10\scripts.

Und hier der Inhalt:

(define (mein-zealous-zeugs pattern ) (let* ((filelist (cadr (file-glob pattern 1)))) (while (not (null? filelist)) (let* ((filename (car filelist)) (image (car (gimp-file-load RUN-NONINTERACTIVE filename filename))) (drawable (car (gimp-image-get-active-layer image)))) (plug-in-zealouscrop RUN-NONINTERACTIVE image drawable) (gimp-file-save RUN-NONINTERACTIVE image drawable filename filename) (gimp-image-delete image)) (set! filelist (cdr filelist)))))

Über define wird zunächst ein Name für die Funktion vergeben. Dann wird die Variable pattern festgelegt, in der von Euch beim Skriptaufruf übergebene Parameter landen.

let heißt jeweils einfach, dass die Variablen für den folgenden (Klammern-)Block gelten.

Zu Beginn wird von filelist die Liste der beim Aufruf des Skripts von Euch übergebenen Dateien geladen. Innerhalb der while-Schleife werden dann die einzelnen Bilder der Liste zunächst per gimp-file-load geladen. Dann wird über gimp-image-get-active-layer die aktive Ebene "geladen". Die Befehle car, cdr und cadr sprechen die einzelnen Elemente der Dateiliste an. Der Rest ist Syntyx-Beiwerk ;)

Die eigentliche Funktion folgt nun über plug-in-zealouscrop, der drei Parameter übergeben werden: Lauf-Modus, Dateiname und Ebene. Wichtig: Im define-Aufruf in der ersten Zeile wurde hier nur pattern übergeben, da die Zealous-Crop-Funktion selbst keinerlei Parameter benötigt. Wenn Ihr stattdessen etwa jedes Seite manuell um einen gewissen Pixelwert croppen wolltet, müsstet Ihr der entsprechenden Funktion auch mindestens diese vier über den define-Aufruf zur Verfügung stellen (Beispiel folgt im Schritt Andere Funktionen erstellen am Ende).

Nach der Verarbeitung wird über gimp-file-save und gimp-image-delete gespeichert und bereinigt - und letztlich aktualisiert set die Liste und die while-Schleife läuft weiter.

2. Skript aufrufen

Beim Aufruf müsst Ihr zwei Dinge erledigen: Die Dateien übergeben und Gimp nach Erledigung wieder schließen. Ruft das Skript in folgender Art auf - hier in Bash:

gimp -i -b '(mein-zealous-zeugs "*.png")' -b '(gimp-quit 0)'

Und hier der Aufruf für CMD:

"C:\Program Files\GIMP 2\bin\gimp-2.10.exe" -i -b "(mein-zealous-zeugs \"*.png\")" -b "(gimp-quit 0)"

i verhindert die grafische Gimp-Oberfläche und b leitet den Batch-Modus ein. Achtung: Nun wird die Funktion über den definierten Namen mein-zealous-zeugs und nicht über den Dateinamen aufgerufen. Es folgt das Muster für PNG-Dateien, hier einfach im aktuellen Ordner. Das zweite Batch-Kommando schließt Gimp. Es sollten Erfolgsmeldungen für jedes Bild kommen oder Hinweise, dass es nichts zu croppen gab.

Und damit ist Euer Batch-Cropper auch schon fertig. Natürlich ließe sich noch einiges anpassen, beispielsweise das Speichern als Kopie, statt das Bild zu überschreiben, komplexere Muster und so weiter. Aber das Grundgerüst steht - speichert es als Vorlage.

3. Andere Funktionen erstellen

Im Grunde müsst Ihr Euch im obigen Code nur um zwei Zeilen kümmern, um eine ganz andere Funktion umzusetzen. Hier mal aus dem Beispiel der offiziellen Dokumentation nur die unterschiedlichen Zeilen:

(define (simple-unsharp-mask filename radius amount threshold)
...
(plug-in-unsharp-mask RUN-NONINTERACTIVE image drawable radius amount threshold)
...

Wie oben bereits erwähnt, benötigen andere Funktionen mehr Parameter im define-Aufruf, hier eben radius, amount und threshold für die Funktion Unsharp Mask (Unscharf Maskieren). Entsprechend werden die Parameter dann auch im eigentlichen Funktionsaufruf hinter plug-in-unsharp-mask übergeben - die ersten drei Parameter (Lauf-Modus, Dateiname, Ebene) sind wieder dieselben wie beim obigen Zealous-Beispiel.

Der Aufrufe könnte dann entsprechend zum Beispiel

gimp -i -b '(mein-unscharf-zeugs "*.png" 5.0 0.5 0)' -b '(gimp-quit 0)'

lauten.

Ihr findet die verfügbaren Funktionen samt benötigter Parameter im Menü unter Filters/Script-Fu/Console/Browse.

script-fu-browser-screenshot
Funktionen samt Parametern im Script-Fu-Browser.

Für Batch-Skripte müsst Ihr also - nochmals zur Vereinfachung - immer folgende drei Dinge tun:

  1. define-Aufruf Eurer Vorlage mit Namen und Parametern versorgen.
  2. Funktionsaufruf mit Namen und Parametern versorgen.
  3. Skriptaufruf - Ihr ahnt es - mit Namen und Parametern versorgen.

Und schon sieht der ganze Scripting-Wust etwas einfacher aus. Hoffe ich. Klar ist das erst der Anfang, aber wenn Ihr das Grundkonzept jetzt einmal intus habt, ist alles weitere "nur" die übliche Skriptzusammenbastelei, mehr Fleißarbeit als sonstwas ;)

Mehr zu Gimp haben wir hier, mehr Terminal-Spielereien hier.

Mirco Lang

Freier Journalist, Exil-Sauerländer, (ziemlich alter) Skateboarder, Dipl.-Inf.-Wirt, Einzelhandelskaufmann, Open-Source-Nerd, Checkmk-Handbuchschreiber. Ex-Saturn'ler, Ex-Data-Becker'ler, Ex-BSI'ler. Computer-Erstkontakt: ca. 1982 - der C64 des großen Bruders eines Freunds. Wenn Ihr hier mehr über Open Source, Linux und Bastelkram lesen und Tutonaut unterstützen möchtet: Über Kaffeesponsoring via Paypal.freue ich mich immer. Schon mal im Voraus: Danke! Nicht verpassen: cli.help und VoltAmpereWatt.de. Neu: Mastodon

16 Kommentare

  1. Zitat aus deinem gestern korrigierten Beitrag: „(hier in Bash-Notation in der Windows-CMD müssten die Anführungszeichen um das png noch per \ escaped werden):“

    Wie bereits angedeutet reicht dies nicht und so muss es mindestens lauten: „(na in Bash-Notation, in der Windows-CMD müssen die Anführungszeichen um das png noch per \ escaped werden und alle einfachen Anführungszeichen durch doppelten ersetzt werden):“

  2. ah, duuuu, gerade so entschuldigt. Was für eine Kleinigkeit und was für eine Zeitverschwendung, aber so lernen wir halt. :-).

    Bitte korrigiere noch den letzten Teil meiner letzten Code-Zeile – das Argument muss ebenso mit doppelten Anführungszeichen umrahmt sein, also: „(gimp-quit 0)“.

  3. doch verbose ist dafür verantwortlich. Das Blöde dabei waren allerdings die folgenden Umständen: 1. dieser Parameter wird nur als „–verbose“ akzeptiert (keine abgekürzte Formen wie „-v“ bzw. „–v“) „-verbose“ (mit nur einem Bindestrich davor) bewirkt dagegen was völlig ganz anders. 2. Der Parameter darf nicht nach dem Parameter „-b“ stehen (die ausführliche Ausgabe wird zwar dann eingeschaltet, jedoch scheitert der Skript am Ende mit einem Fehler – sicherlich ist dies ein Bug).

    Diese Umstände führen nämlich dazu, dass es nicht auf Anhieb funktioniert.

  4. HINWEISE: Die Hyperlinks „Abonnieren bestätigen“, „Registriere ein WordPress.com Benutzerkonto“ sowie „Abonnement-Optionen“ lassen sich nicht aufrufen. Deren URL wird zwar in der Vorschau (etwa wie QuickInfo) angezeigt, jedoch beim Bearbeiten ist sowohl deren URL-Feld noch das QuickInfo leer! (Getestet sowohl in MS Outlook als auch MS Word 2007) Scheint nach irgendeine neue HTML-Struktur zu sein, welche mir auf dieser Art zum ersten Mal begegnet wird. Erst nachdem ich den Textinhalt aus der E-Mail in die aktuelle LibreOffice-Version eingefügt habe, gelang mir den URL-Inhalt zu kopieren und das Abonnieren zu bestätigen. Es scheint so zu sein, also ob diese HTML-Struktur bzw. diese neue Art der Hyperlink-Einbettung so von MS Office nicht unterstützt wird. Also bitte prüft es, was da los ist, weil kaum einer von MS Office Anwender sich diese Mühe machen wird über andere Wege zu versuchen an diese URL zu gelangen und bleibt somit nicht abonniert.

      1. Ach, das liegt bloß an der URL-Länge! Nachdem sie um zwei-drei Zeilen gekürzt wird, lassen sich diese dann doch beim Klick ausführen. Sowohl in MS Outlook (wenn die E-Mail in Bearbeitungsmodus versetzt wird, über die Option „Nachricht bearbeiten“) als auch in Word (wenn der Inhalt aus der E-Mail einfach dorthin kopiert wird) lässt sich mittels Alt+F9 der Inhalt von URLs bei allen Hyperlinks anzeigen und wieder ausblenden und dies klappt im Gegensatz problemlos, egal wie lang deren URL ist. Dieser Inhalt lässt sich ansonsten auf dem gewöhnlichen Weg via „Hyperlink bearbeiten“ also nicht anzeigen und die Hyperlinks reagieren dann auf Klicks nicht, auch wenn sie als solche existieren, egal wie oft versucht wird drauf zu klicken, da in MS Office offensichtlich ein Limit an maximaler Zeichenlänge herrscht. Also dies bedarf dann zwangsläufig eurerseits eine Korrektur die URL-Verschlüsselung auf unter der von Microsoft limitierten Länge zu minimieren, wenn ihr Abonnenten und Kommentare wollt :-), da Microsoft es hier sicherlich aus gutem Grund nicht machen wird die URL-Länge zu erweitern, sodass nach einem Update in der Hinsicht vergeblich gewartet wird.

  5. Hallo Mirco,

    danke für deinen Beitrag.

    Beim Ausführen des Batch-Skriptes erhalte ich in der Konsole lediglich „batch command executed successfully“ und sonst nicht mehr und kein der *.png Bilder werden im Batch-Verzeichnis verarbeitet obwohl alle diese mit großen weißen Rändern sind.

    Der Batch-Skript ist wie folgt aufgebaut, also mit expliziter Verweisung des Arbeitsverzeichnisses (im Falle durch „PushD %~dp0“ = also Verzeichnis des Batch-Skriptes, wo auch die PNGs liegen):

    PushD %~dp0
    
    :HINWEISE: Bei angegebenen Erweiterungstypen wird zw. Groß-Kleinschreibung unterschieden
    
    set "gimp=%ProgramFiles%\GIMP 2\bin\gimp-2.10.exe"
    
    "%gimp%" -i -b '(batch-zealous-crop "*.png")' -b '(gimp-quit 0)'
    
    timeout /t 3 &>nul
    

    Woran könnte es liegen? Vielleicht lässt sich eine ausführliche Ausgabe der Prozedur (zw. Protokollierung) aktivieren, um mehr in der Konsole zu sehen?

    Es ist bei mir so, dass das Batch-Skript gimp-2.10.exe ausführt, sodass die Ausgabe „batch command executed successfully“ nicht innerhalb der Windows-CMD erfolgt, sondern nämlich in der Konsole gimp-2.10.exe, welche jeweils als separates Fenster auftaucht.

    Tipps: Bei mir öffnete sich die GIMP-Konsole störend auf die gesamte Bildschirmhöhe voll maximiert, jedoch lässt sich die Größe über die Eigenschaften (wie CMD üblich über Rechtsklick in der Titelleiste) auf einen anderen Standard-Wert anpassen, der dann erhalten bleibt.

    Seltsam, das sich das Fenster nur durch Schließen und zusätzliches Drücken einer beliebigen Taste schließen lässt (für mich unnötig doppelt gemoppelt) – ala „timeout /t 3 >nul“ nützt hier also nicht, da sie ja als separates Prozess außerhalb der CMD läuft.

    start "" /MIN /B ... 
    

    schafft hier zwar etwas Abhilfe, jedoch wiederum ganz maximiert ist es mir aktuell zu früh, da die GIMP-Konsole im Vordergrund aktuell nützlicher ist, um den Ablaufstatus schnell in Übersicht zu haben, zumindest bis die Sache anläuft (ein kleines Fensterchen ist optimal).

    Gruß

    1. Also der Batch-Code sieht für mich soweit korrekt aus. Ich würde es wohl ohne pushd-Anweisung versuchen und alles im selben Ordner laufen lassen, um Pfad-Probleme auszuschließen – gerade nochmal getestet, funktioniert. Ansonsten fällt mir dazu gerade aber auch nichts Spezielles ein.

      Wenn es das nicht ist und das Gimp-Skript selbst funktioniert, würde ich auf Probleme mit den Bildern tippen. Einfach mal ein Testbild nehmen, in der Mitte über die ganze Breite irgendwas ausschneiden und dann zealous-coppen.

      1. ja, über den den Befehl im GUI-Menü funktioniert es einwandfrei, jedoch nicht über Skript.

        Wüstest du vielleicht wie sich die ausführliche Ausgabe der Gimp-Konsole erzwingen lässt (also ohne @echo off)? So könnte ich dann auf die Spur kommen, aber so blind bleibt es solange ein Rätsel. Ansonsten melde ich mich im Gimp-Forum. Ich dachte mir halt es wäre hier passend, da ich ja dasselbe Vorhaben habe.

      2. doch verbose ist dafür verantwortlich. Das Blöde dabei waren allerdings die folgenden Umständen: 1. dieser Parameter wird nur als „–verbose“ akzeptiert (keine abgekürzte Formen wie „-v“ bzw. „–v“) „-verbose“ (mit nur einem Bindestrich davor) bewirkt dagegen was völlig ganz anders. 2. Der Parameter darf nicht nach dem Parameter „-b“ stehen (die ausführliche Ausgabe wird zwar dann eingeschaltet, jedoch scheitert der Skript am Ende mit einem Fehler – sicherlich ist dies ein Bug).

        Diese Umstände führen nämlich dazu, dass es nicht auf Anhieb funktioniert.

      3. sorry, ich meine nicht dass „-verbose“ was völlig ganz anders bewirkt (das wird so gar nicht unterstützt), sondern „-v“ (zeigt die Versionen der aktuellen Module an).

      4. nein, für Windows OS ist es so nicht korrekt und anbei die Lösung:

        '%gimp%' -i --verbose -b '(batch-crop-to-content \"*.png\")' -b '(gimp-quit 0)'
        

        In Windows Batch-Skripts muss ja jedes doppelte Anführungszeichen eines innenliegenden Paares maskiert sein (was meist mit „\“ geschieht) und obwohl ich es eigentlich wusste, hab ich mich leider zu arg an die Korrektheit der vielen Anleitungen, wie auch hier als auch an vielen anderen Stellen, zu blind verlassen, sodass ich den Fehler primär in den weiteren Instanzen gesucht habe, obwohl dieser die ganze Zeit bloß in der ersten Instanz lag.

      5. Ah, sorry, mein Fehler, ich hatte das CMD überlesen … Das funktioniert so unter Windows schon, aber in der Bash. CMD versuche ich wie der Teufel zu meiden, skripten in Bash ist wesentlich angenehmer. Ich habe mal einen Hinweis im Text hinterlassen.

      6. bitte korrigiere die Anführungszeichen in einfache einfache Anführungszeichen, welche hier automatisch in typographische Anführungszeichen umgewandelt werden (und formatiere die Befehlszeile lieber als Code). Danke

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Schaltfläche "Zurück zum Anfang"