[gimp] plug-ins: add a goat-exercise-py3.py.



commit 9ed4dd5dde733ef5a092627f5083461517cf723d
Author: Jehan <jehan girinstud io>
Date:   Fri Aug 9 14:47:13 2019 +0200

    plug-ins: add a goat-exercise-py3.py.
    
    Right now it is not working, always because of the same bug about not
    being able to create GParamSpec (pygobject#227). As a consequence, I
    tried a workaround by creating object properties and using their spec
    instead. But it turns out that in pygobject, I cannot create random
    properties for custom types (well I could for boxed types or GObject
    subclasses, not for GimpImageID or GimpDrawableID). Cf. pygobject#357.
    So I am stuck again.
    
    Anyway I still push this demo file which would just work as it is, if we
    coult at least got the image/drawable ID.
    I comment out the Makefile.am part for now until we can get the issues
    sorted out.

 plug-ins/goat-exercises/Makefile.am          |   7 +
 plug-ins/goat-exercises/goat-exercise-py3.py | 210 +++++++++++++++++++++++++++
 2 files changed, 217 insertions(+)
---
diff --git a/plug-ins/goat-exercises/Makefile.am b/plug-ins/goat-exercises/Makefile.am
index f91c138d27..1c7a549f7f 100644
--- a/plug-ins/goat-exercises/Makefile.am
+++ b/plug-ins/goat-exercises/Makefile.am
@@ -64,3 +64,10 @@ goat_exercise_LDADD = \
 
 goat_exercise_gjsdir = $(gimpplugindir)/plug-ins/goat-exercise-gjs
 goat_exercise_gjs_SCRIPTS = goat-exercise-gjs.js
+
+# Python 3 (pygobject) version.
+
+# Commented out for now until we figure out the GParamSpec issues.
+
+#goat_exercise_py3dir = $(gimpplugindir)/plug-ins/goat-exercise-py3
+#goat_exercise_py3_SCRIPTS = goat-exercise-py3.py
diff --git a/plug-ins/goat-exercises/goat-exercise-py3.py b/plug-ins/goat-exercises/goat-exercise-py3.py
new file mode 100755
index 0000000000..a237781e38
--- /dev/null
+++ b/plug-ins/goat-exercises/goat-exercise-py3.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#    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 gi
+gi.require_version('Gimp', '3.0')
+from gi.repository import Gimp
+gi.require_version('Gegl', '0.4')
+from gi.repository import Gegl
+from gi.repository import GObject
+from gi.repository import GLib
+from gi.repository import Gio
+import sys, os
+
+import gettext
+_ = gettext.gettext
+def N_(message): return message
+
+class Goat (Gimp.PlugIn):
+    ## Parameter: run-mode ##
+    @GObject.Property(type=Gimp.RunMode,
+                      default=Gimp.RunMode.NONINTERACTIVE,
+                      nick="Run mode", blurb="The run mode")
+    def run_mode(self):
+        """Read-write integer property."""
+        return self._run_mode
+
+    @run_mode.setter
+    def run_mode(self, run_mode):
+        self._run_mode = run_mode
+
+    ## Parameter: image ##
+    #@GObject.Property(type=Gimp.ImageID.__gtype__,
+    @GObject.Property(type=int,
+                      default=0,
+                      nick= _("Image"),
+                      blurb= _("The input image"))
+    def image(self):
+        return self._image
+
+    @image.setter
+    def image(self, image):
+        self._image = image
+
+    ## Parameter: drawable ##
+    #@GObject.Property(type=Gimp.DrawableID.__gtype__,
+    @GObject.Property(type=int,
+                      default=0,
+                      nick= _("Drawable"),
+                      blurb= _("The input drawable"))
+    def drawable(self):
+        return self._drawable
+
+    @drawable.setter
+    def drawable(self, drawable):
+        self._drawable = drawable
+
+    ## GimpPlugIn virtual methods ##
+    def do_query_procedures(self):
+        # Localization
+        self.set_translation_domain("gimp30-python",
+                                    Gio.file_new_for_path(Gimp.locale_directory()))
+
+        return [ "goat-exercise-python" ]
+
+    def do_create_procedure(self, name):
+        procedure = Gimp.Procedure.new(self, name,
+                                       Gimp.PDBProcType.PLUGIN,
+                                       self.run, None)
+        procedure.set_image_types("RGB*, INDEXED*, GRAY*");
+        procedure.set_menu_label("Exercise a goat and a python");
+        procedure.set_documentation("Exercise a goat in the Python 3 language",
+                                    "Takes a goat for a walk in Python 3",
+                                    "");
+        procedure.add_menu_path('<Image>/Filters/Development/Goat exercises/');
+        procedure.set_attribution("Jehan", "Jehan", "2019");
+        procedure.add_argument_from_property(self, "run-mode")
+        procedure.add_argument_from_property(self, "image")
+        procedure.add_argument_from_property(self, "drawable")
+
+        return procedure
+
+    def run(self, procedure, args, data):
+        runmode = args.index(0)
+
+        if runmode == Gimp.RunMode.INTERACTIVE:
+            gi.require_version('Gtk', '3.0')
+            from gi.repository import Gtk
+            gi.require_version('Gdk', '3.0')
+            from gi.repository import Gdk
+
+            Gimp.ui_init("palette-offset.py", False)
+
+            dialog = Gimp.Dialog(use_header_bar=True,
+                                 title=_("Exercise a goat (Python 3)"),
+                                 role="goat-exercise-Python3")
+
+            dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL)
+            dialog.add_button("_Source", Gtk.ResponseType.APPLY)
+            dialog.add_button("_OK", Gtk.ResponseType.OK)
+
+            geometry = Gdk.Geometry();
+            geometry.min_aspect = 0.5;
+            geometry.max_aspect = 1.0;
+            dialog.set_geometry_hints(None, geometry, Gdk.WindowHints.ASPECT);
+
+            box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=2)
+            dialog.get_content_area().add(box)
+            box.show()
+
+            # XXX We use printf-style string for sharing the localized
+            # string. You may just use recommended Python format() or
+            # any style you like in your plug-ins.
+            head_text=("This plug-in is an exercise in '%s' to "
+                       "demo plug-in creation.\nCheck out the last "
+                       "version of the source code online by clicking "
+                       "the \"Source\" button." % ("Python 3"))
+            label = Gtk.Label(label=head_text)
+            box.pack_start(label, False, False, 1)
+            label.show()
+
+            contents = None
+            # Get the file contents Python-style instead of using
+            # GLib.file_get_contents() which returns bytes result, and
+            # when converting to string, get newlines as text contents.
+            # Rather than wasting time to figure this out, use Python
+            # core API!
+            with open(os.path.realpath(__file__), 'r') as f:
+                contents = f.read()
+
+            if contents is not None:
+                scrolled = Gtk.ScrolledWindow()
+                scrolled.set_vexpand (True)
+                box.pack_start(scrolled, True, True, 1)
+                scrolled.show()
+
+                view = Gtk.TextView()
+                view.set_wrap_mode(Gtk.WrapMode.WORD)
+                view.set_editable(False)
+                buffer = view.get_buffer()
+                buffer.set_text(contents, -1)
+                scrolled.add(view)
+                view.show()
+
+            while (True):
+                response = dialog.run()
+                if response == Gtk.ResponseType.OK:
+                    dialog.destroy()
+                    break
+                elif response == Gtk.ResponseType.APPLY:
+                    Gio.app_info_launch_default_for_uri(url, None)
+                    continue
+                else:
+                    dialog.destroy()
+                    return procedure.new_return_values(Gimp.PDBStatusType.CANCEL,
+                                                       GLib.Error())
+
+        # Parameters are not working fine yet because properties should
+        # be Gimp.ImageID/Gimp.DrawableID but we can't make these with
+        # pygobject. Until I figure out how to make it work, you could
+        # uncomment the following lines instead of using the args value.
+        #images = Gimp.image_list()
+        #image_id = images[0]
+        #drawable_id = Gimp.image_get_active_drawable(image_id)
+        drawable_id = args.index(2)
+
+        success, x, y, width, height = Gimp.drawable_mask_intersect(drawable_id);
+        if success:
+            Gegl.init(None);
+
+            buffer = Gimp.drawable_get_buffer(drawable_id)
+            shadow_buffer = Gimp.drawable_get_shadow_buffer(drawable_id)
+
+            graph = Gegl.Node()
+            input = graph.create_child("gegl:buffer-source")
+            input.set_property("buffer", buffer)
+            invert = graph.create_child("gegl:invert")
+            output = graph.create_child("gegl:write-buffer")
+            output.set_property("buffer", shadow_buffer)
+            input.link(invert)
+            invert.link(output)
+            output.process()
+
+            # This is extremely important in bindings, since we don't
+            # unref buffers. If we don't explicitly flush a buffer, we
+            # may left hanging forever. This step is usually done
+            # during an unref().
+            shadow_buffer.flush()
+
+            Gimp.drawable_merge_shadow(drawable_id, True)
+            Gimp.drawable_update(drawable_id, x, y, width, height)
+            Gimp.displays_flush()
+        else:
+            retval = procedure.new_return_values(Gimp.PDBStatusType.CALLING_ERROR,
+                                                 GLib.Error("No pixels to process in the selected area."))
+
+        return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())
+
+Gimp.main(Goat.__gtype__, sys.argv)


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]