Yesterday, 11:26 AM
Hello GIMP Community,
I am facing an issue in a GIMP 3.0 Python plugin: reliably closing the program and the last active image when the sequential workflow is finished.
My script is running in the GUI Mode, and I need to perform two actions in order:
Here is my script so far (German annotations):
Does anyone have an idea whether what I am trying to do is possible?
I am facing an issue in a GIMP 3.0 Python plugin: reliably closing the program and the last active image when the sequential workflow is finished.
My script is running in the GUI Mode, and I need to perform two actions in order:
- Close the last open image container.
- Force GIMP to quit the application entirely.
Here is my script so far (German annotations):
Code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
import gi
gi.require_version('Gimp', '3.0')
gi.require_version('GimpUi', '3.0')
from gi.repository import Gimp, GimpUi, GObject, GLib, Gio
import os
import json
import tempfile
import traceback
# Pfad für die temporäre Konfigurationsdatei
CONFIG_PATH = os.path.join(tempfile.gettempdir(), 'gimp_spore_workflow_config.json')
class ExportAndNextWorkflow(Gimp.PlugIn):
def do_query_procedures(self):
return ['python-fu-export-and-next']
def do_set_i18n(self, procname):
return False, 'gimp30-python', None
def do_create_procedure(self, name):
procedure = Gimp.ImageProcedure.new(
self, name,
Gimp.PDBProcType.PLUGIN,
self.run, None
)
procedure.set_image_types("*")
procedure.set_sensitivity_mask(Gimp.ProcedureSensitivityMask.DRAWABLE)
procedure.set_menu_label("1. Exportieren & Nächstes Bild")
procedure.add_menu_path('<Image>/Auswahl/')
procedure.set_documentation(
"Exportiert die Auswahl, speichert W/H und lädt das nächste Bild.",
"Exportiert die aktuelle Auswahl und bereitet den nächsten Schritt vor.",
name
)
procedure.set_attribution("Author", "Author", "2024")
return procedure
# --- HILFSFUNKTIONEN ---
def load_config(self):
if os.path.exists(CONFIG_PATH):
try:
with open(CONFIG_PATH, 'r') as f:
return json.load(f)
except:
pass
return None
def save_config(self, width, height, current_path=None):
data = {'width': int(width), 'height': int(height)}
try:
existing_data = self.load_config()
if existing_data:
data.update(existing_data)
if current_path is not None:
data['last_path'] = current_path
with open(CONFIG_PATH, 'w') as f:
json.dump(data, f, indent=4)
except Exception as e:
pass
def get_next_file(self, current_path):
directory = os.path.dirname(current_path)
basename = os.path.basename(current_path)
extensions = ('.jpg', '.jpeg', '.png', '.tif', '.tiff', '.xcf')
files = [f for f in os.listdir(directory) if f.lower().endswith(extensions)]
files.sort()
try:
index = files.index(basename)
if index + 1 < len(files):
return os.path.join(directory, files[index + 1])
except ValueError:
pass
return None
# --- HAUPT-RUN-FUNKTION ---
def run(self, procedure, run_mode, image, n_drawables, drawables, config, run_data=None):
# 0. Initialisierung & Auswahlprüfung
selection = image.get_selection()
success, non_empty, x1, y1, x2, y2 = selection.bounds(image)
if not non_empty:
error = GLib.Error.new_literal(Gimp.PlugIn.error_quark(), "Keine Auswahl vorhanden.", 0)
return procedure.new_return_values(Gimp.PDBStatusType.CALLING_ERROR, error)
target_w = x2 - x1
target_h = y2 - y1
# 1. Pfad ermitteln
current_path = None
current_file = image.get_file()
if current_file is not None:
current_path = current_file.get_path()
else:
config_data = self.load_config()
if config_data and 'last_path' in config_data:
current_path = config_data['last_path']
if current_path is None:
error = GLib.Error.new_literal(Gimp.PlugIn.error_quark(),
"Bild hat keinen Dateipfad (Konfiguration leer).", 0)
return procedure.new_return_values(Gimp.PDBStatusType.EXECUTION_ERROR, error)
directory = os.path.dirname(current_path)
basename = os.path.splitext(os.path.basename(current_path))[0]
# Zielordner für Exporte definieren
target_dir = os.path.join(directory, "Auswahlen")
# --- TEIL A: EXPORTIEREN ---
try:
# 2. Zielordner erstellen (falls nicht vorhanden)
if not os.path.exists(target_dir):
os.makedirs(target_dir)
# 3. Nächste freie Export-Nummer finden (suche im Zielordner)
number = 1
while True:
new_filename = f"[{number}] {basename}.jpg"
new_filepath = os.path.join(target_dir, new_filename)
if not os.path.exists(new_filepath):
break
number += 1
# 4. Auswahl kopieren, neues Bild erstellen, speichern
drawable = image.get_layers()[-1]
Gimp.edit_copy([drawable])
new_image = Gimp.edit_paste_as_new_image()
# Speichere direkt in den Auswahlen-Ordner
new_file = Gio.file_new_for_path(new_filepath)
Gimp.file_save(Gimp.RunMode.NONINTERACTIVE, new_image, new_file)
new_image.delete()
# 5. Auswahlgröße speichern (für Script 2)
self.save_config(target_w, target_h)
except Exception as e:
if 'new_image' in locals():
try: new_image.delete()
except: pass
error_msg = f"Fehler beim Export: {str(e)}\n{traceback.format_exc()}"
error = GLib.Error.new_literal(Gimp.PlugIn.error_quark(), error_msg, 0)
return procedure.new_return_values(Gimp.PDBStatusType.EXECUTION_ERROR, error)
# --- TEIL B: NÄCHSTES BILD LADEN (MIT ENDPRÜFUNG) ---
# 6. Nächstes Bild ermitteln
next_path = self.get_next_file(current_path)
if not next_path:
# ENDE DER SEQUENZ ERREICHT!
# Letzten Pfad zurücksetzen.
self.save_config(target_w, target_h, current_path=None)
# Aktuelles Bild aus der Anzeige entfernen
image.delete()
# GIMP 3.0 Methode zum Aufruf der PDB-Prozedur "gimp-quit"
try:
# Korrektur: Verwendung von Gimp.TYPE_INT anstelle von GObject.TYPE_INT
Gimp.plug_in_manager_run(
"gimp-quit",
Gimp.RunMode.NONINTERACTIVE,
GObject.Value.new(Gimp.TYPE_INT, 0)
)
except Exception as e:
Gimp.message(f"WARNUNG: GIMP 3.0 Quit-Aufruf fehlgeschlagen: {str(e)}")
# Korrigierter Rückgabestatus:
return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, None)
try:
# 7. Normaler Ablauf: Bild laden und Pfad speichern
new_gfile = Gio.file_new_for_path(next_path)
new_image = Gimp.file_load(Gimp.RunMode.NONINTERACTIVE, new_gfile)
self.save_config(target_w, target_h, current_path=next_path)
# 8. Anzeige erstellen und altes Bild schließen
Gimp.Display.new(new_image)
image.delete()
Gimp.displays_flush()
except Exception as e:
error_msg = f"Fehler beim Wechseln: {str(e)}\n{traceback.format_exc()}"
error = GLib.Error.new_literal(Gimp.PlugIn.error_quark(), error_msg, 0)
return procedure.new_return_values(Gimp.PDBStatusType.EXECUTION_ERROR, error)
# Korrigierter Rückgabestatus:
return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, None)
Gimp.main(ExportAndNextWorkflow.__gtype__, sys.argv)Does anyone have an idea whether what I am trying to do is possible?
