コード例 #1
0
def foggify(procedure, run_mode, image, drawable, args, data):
    name = args.index(0)
    turbulence = args.index(1)
    opacity = args.index(2)
    if run_mode == Gimp.RunMode.INTERACTIVE:
        # TODO: add a GUI. This first port works just with default
        # values.
        color = Gimp.RGB()
        color.set(240.0, 180.0, 70.0)

    Gimp.context_push()
    image.undo_group_start()

    if image.base_type() is Gimp.ImageBaseType.RGB:
        type = Gimp.ImageType.RGBA_IMAGE
    else:
        type = Gimp.ImageType.GRAYA_IMAGE
    fog = Gimp.Layer.new(image, name, drawable.width(), drawable.height(),
                         type, opacity, Gimp.LayerMode.NORMAL)
    fog.fill(Gimp.FillType.TRANSPARENT)
    image.insert_layer(fog, None, 0)

    Gimp.context_set_background(color)
    fog.edit_fill(Gimp.FillType.BACKGROUND)

    # create a layer mask for the new layer
    mask = fog.create_mask(0)
    fog.add_mask(mask)

    # add some clouds to the layer
    Gimp.get_pdb().run_procedure('plug-in-plasma', [
        GObject.Value(Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE),
        GObject.Value(Gimp.Image, image),
        GObject.Value(Gimp.Drawable, mask),
        GObject.Value(GObject.TYPE_INT, int(time.time())),
        GObject.Value(GObject.TYPE_DOUBLE, turbulence),
    ])

    # apply the clouds to the layer
    fog.remove_mask(Gimp.MaskApplyMode.APPLY)
    fog.set_visible(True)
    Gimp.displays_flush()

    image.undo_group_end()
    Gimp.context_pop()

    return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS,
                                       GLib.Error())
コード例 #2
0
 def _commit(self):
     Console._commit(self)
     Gimp.displays_flush()
コード例 #3
0
def foggify(procedure, run_mode, image, n_drawables, drawables, args, data):
    config = procedure.create_config()
    config.begin_run(image, run_mode, args)

    if run_mode == Gimp.RunMode.INTERACTIVE:
        GimpUi.init('python-fu-foggify')
        dialog = GimpUi.ProcedureDialog.new(procedure, config)
        dialog.get_color_widget('color', True, GimpUi.ColorAreaType.FLAT)
        dialog.fill(None)
        if not dialog.run():
            dialog.destroy()
            config.end_run(Gimp.PDBStatusType.CANCEL)
            return procedure.new_return_values(Gimp.PDBStatusType.CANCEL,
                                               GLib.Error())
        else:
            dialog.destroy()

    color = config.get_property('color')
    name = config.get_property('name')
    turbulence = config.get_property('turbulence')
    opacity = config.get_property('opacity')

    Gimp.context_push()
    image.undo_group_start()

    if image.get_base_type() is Gimp.ImageBaseType.RGB:
        type = Gimp.ImageType.RGBA_IMAGE
    else:
        type = Gimp.ImageType.GRAYA_IMAGE
    for drawable in drawables:
        fog = Gimp.Layer.new(image, name, drawable.get_width(),
                             drawable.get_height(), type, opacity,
                             Gimp.LayerMode.NORMAL)
        fog.fill(Gimp.FillType.TRANSPARENT)
        image.insert_layer(fog, drawable.get_parent(),
                           image.get_item_position(drawable))

        Gimp.context_set_background(color)
        fog.edit_fill(Gimp.FillType.BACKGROUND)

        # create a layer mask for the new layer
        mask = fog.create_mask(0)
        fog.add_mask(mask)

        # add some clouds to the layer
        Gimp.get_pdb().run_procedure('plug-in-plasma', [
            GObject.Value(Gimp.RunMode, Gimp.RunMode.NONINTERACTIVE),
            GObject.Value(Gimp.Image, image),
            GObject.Value(Gimp.Drawable, mask),
            GObject.Value(GObject.TYPE_INT, int(time.time())),
            GObject.Value(GObject.TYPE_DOUBLE, turbulence),
        ])

        # apply the clouds to the layer
        fog.remove_mask(Gimp.MaskApplyMode.APPLY)
        fog.set_visible(True)

    Gimp.displays_flush()

    image.undo_group_end()
    Gimp.context_pop()

    config.end_run(Gimp.PDBStatusType.SUCCESS)

    return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS,
                                       GLib.Error())
コード例 #4
0
    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())
コード例 #5
0
    def _run_procedure_in_mode(procedure, run_mode, image, list_all_args,
                               original_args, data):
        '''
        Understands run_mode.
        Different ways to invoke procedure batch, or interactive.

        Hides run_mode from Authors.
        I.E. their run_func signature does not have run_mode.

        require procedure is-a Gimp.Procedure.
        require original_args is-a Gimp.ValueArray.
        require list_all_args is a list of GValues
        '''
        list_wrapped_args = Marshal.wrap_args(list_all_args)

        # To know the Python name of a Gimp.Procedure method (e.g. gimp_procedure_get_name)
        # see gimp/libgimp/gimpprocedure.h, and then remove the prefix gimp_procedure_
        name = procedure.get_name()

        FuRunner.logger.info(
            f"_run_procedure_in_mode: {name}, {run_mode}, {list_wrapped_args}")
        '''
        list_wrapped_args are one-to-one with formal params.
        list_wrapped_args may include some args that are not guiable (i.e. image, drawable)
        '''

        fuProcedure = FuProcedures.get_by_name(name)

        isBatch = (run_mode == Gimp.RunMode.NONINTERACTIVE)
        '''
        Else so-called interactive mode, with GUI dialog of params.
        Note that the v2 mode RUN_WITH_LAST_VALS is obsolete
        since Gimp 3 persists settings, i.e. actual arg values can be from last invocation.
        If not from last invocation, they are the formal parameter defaults.
        '''

        func = fuProcedure.get_authors_function()
        """
        The ProcedureConfig should have length equal to ????
        original_args is-a GimpValueArray
        """
        # config = FuProcedureConfig(procedure, len(list_wrapped_args)-2 )
        config = FuProcedureConfig(fuProcedure, procedure,
                                   original_args.length())
        config.begin_run(image, run_mode, original_args)

        if isBatch:
            try:
                # invoke func with unpacked args.  Since Python3, apply() gone.
                # TODO is this the correct set of args? E.G. Gimp is handling RUN_WITH_LAST_VALS, etc. ???
                runfunc_result = func(*list_wrapped_args)
                final_result = FuResult.makeSuccess(procedure, runfunc_result)
            except Exception as err:
                # TODO print the Exception type
                err_message = f"In plugin: {name}, function: {func}, Exception: {err}"
                FuRunner.logger.warning(err_message)
                final_result = FuResult.makeException(procedure, err_message)
        else:
            '''
           Not enclosed in try:except: since then you don't get a good traceback.
           Any exceptions in showing a dialog are hard programming errors.
           Any exception in executing the run_func should be shown to user,
           either by calling our own dialog or by calling a Gimp.ErrorDialog (not exist)
           or by passing the exception string back to Gimp.
           '''
            was_canceled, runfunc_result = FuRunner._interact(
                procedure, list_wrapped_args, config)
            if was_canceled:
                final_result = FuResult.makeCancel(procedure)
                config.end_run(Gimp.PDBStatusType.CANCEL)
            else:
                final_result = FuResult.makeSuccess(procedure, runfunc_result)
                config.end_run(Gimp.PDBStatusType.SUCCESS)
            """
           OLD above was enclosed in try
           try:
           except Exception as err:
               '''
               Probably GimpFu module programming error (e.g. bad calls to GTK)
               According to GLib docs, should be a warning, since this is not recoverable.
               But it might be author programming code (e.g. invalid PARAMS)
               '''
               proceed(f"Exception opening plugin dialog: {err}")
               final_result = FuResult.make(Gimp.PDBStatusType.EXECUTION_ERROR, GLib.Error())
           """
        '''
        Make visible any alterations to user created images.
        GimpFu promises to hide the need for this.
        '''
        Gimp.displays_flush()  # !!! Gimp, not gimp

        did_suggest_or_deprecate = Suggest.summarize()
        did_suggest_or_deprecate = did_suggest_or_deprecate or Deprecation.summarize(
        )

        if did_suggest_or_deprecate:
            # TODO make this go to the status bar, not a dialog
            # Gimp.message("See console for suggestions and deprecations.")
            pass

        if summarize_proceed_errors():  # side effect is writing to console
            """ Gimpfu proceeded past earlier exceptions.
            Display GIMP dialog.
            """
            msg = "GimpFu detected errors.  See console for a summary."
            Gimp.message(msg)
            final_result = FuResult.makeException(procedure, msg)

            # Alternatively: raise Exception(msg) but that is confusing to Author

        FuRunner.logger.debug(
            f"Returning from: {name} with result:{final_result}")
        # ensure final_result is type GimpValueArray
        assert isinstance(final_result, Gimp.ValueArray)
        return final_result
コード例 #6
0
    def run(self, procedure, run_mode, image, drawable, args, run_data):
        if run_mode == 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

            GimpUi.ui_init("palette-offset.py")

            dialog = GimpUi.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:
                    url = "https://gitlab.gnome.org/GNOME/gimp/-/blob/master/plug-ins/goat-exercises/goat-exercise-py3.py"
                    Gio.app_info_launch_default_for_uri(url, None)
                    continue
                else:
                    dialog.destroy()
                    return procedure.new_return_values(
                        Gimp.PDBStatusType.CANCEL, GLib.Error())

        intersect, x, y, width, height = drawable.mask_intersect()
        if intersect:
            Gegl.init(None)

            buffer = drawable.get_buffer()
            shadow_buffer = drawable.get_shadow_buffer()

            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()

            drawable.merge_shadow(True)
            drawable.update(x, y, width, height)
            Gimp.displays_flush()

        return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS,
                                           GLib.Error())
コード例 #7
0
def benchmark(procedure, args, data):
    if args.length() != 3:
        error = 'Wrong parameters given'
        return procedure.new_return_values(Gimp.PDBStatusType.CALLING_ERROR,
                                           GLib.Error(error))
    run_mode = args.index(0)
    folder = args.index(1)
    save_output = args.index(2)

    folder = os.path.abspath(os.path.expanduser(folder))
    if not os.path.exists(folder):
        error = "Folder '" + folder + "' doesn't exist.\n"
        return procedure.new_return_values(Gimp.PDBStatusType.CALLING_ERROR,
                                           GLib.Error(error))

    total_unclassified = 0
    total_misclassified = 0
    total_time = 0.0

    images = os.path.join(folder, "images")
    for name in os.listdir(images):

        try:
            image_display.delete()
            mask_display.delete()
        except NameError:
            pass

        image_name = os.path.join(images, name)

        # Remove suffix, assuming it has three characters
        name = re.sub(r'\....$', '', name)

        mask_name = os.path.join(folder, "cm_bmp", name + '.png')
        truth_name = os.path.join(folder, "truth", name + '.bmp')

        image = Gimp.file_load(run_mode, Gio.file_new_for_path(image_name))
        image_layer = image.get_active_layer()

        mask = Gimp.file_load(run_mode, Gio.file_new_for_path(mask_name))
        convert_grayscale(mask)
        mask_layer = mask.get_active_layer()

        truth = Gimp.file_load(run_mode, Gio.file_new_for_path(truth_name))
        convert_grayscale(truth)
        truth_layer = truth.get_active_layer()

        unclassified = unclassified_pixels(mask_layer, truth_layer)

        sys.stderr.write(os.path.basename(image_name))

        start = time.time()
        image_layer.foreground_extract(Gimp.ForegroundExtractMode.MATTING,
                                       mask_layer)
        end = time.time()

        sys.stderr.write(" ")

        # This line was in the gimp 2 implementation, and probably isn't needed anymore.
        #  mask_layer.flush ()

        # Ignore errors when creating image displays;
        # allows us to be used without a display.
        try:
            image_display = Gimp.Display.new(image)
            mask_display = Gimp.Display.new(mask)

            Gimp.displays_flush()
            time.sleep(1.0)
        except:
            pass

        image.delete()

        misclassified = misclassified_pixels(mask_layer, truth_layer)

        sys.stderr.write("%d %d %.2f%% %.3fs\n" %
                         (unclassified, misclassified,
                          (misclassified * 100.0 / unclassified), end - start))

        total_unclassified += unclassified
        total_misclassified += misclassified
        total_time += end - start

        truth.delete()

        if save_output:
            filename = os.path.join(folder, "output", name + '.png')
            Gimp.file_save(Gimp.RunMode.NONINTERACTIVE, mask, mask_layer,
                           Gio.file_new_for_path(filename))

        mask.delete()

    # for loop ends

    try:
        image_display.delete()
        mask_display.delete()
    except NameError:
        pass

    sys.stderr.write(
        "Total: %d %d %.2f%% %.3fs\n" %
        (total_unclassified, total_misclassified,
         (total_misclassified * 100.0 / total_unclassified), total_time))

    return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS,
                                       GLib.Error())