def run(self, procedure, args, data): palette = None amount = 1 # Get the parameters if args.length() < 1: error = 'No parameters given' return procedure.new_return_values( Gimp.PDBStatusType.CALLING_ERROR, GLib.Error(error)) runmode = args.index(0) if args.length() > 1: palette = args.index(1) if palette == '' or palette is None: palette = Gimp.context_get_palette() (exists, num_colors) = Gimp.palette_get_info(palette) if not exists: error = 'Unknown palette: {}'.format(palette) return procedure.new_return_values( Gimp.PDBStatusType.CALLING_ERROR, GLib.Error(error)) if args.length() > 2: amount = args.index(2) if runmode == Gimp.RunMode.INTERACTIVE: gi.require_version('Gtk', '3.0') from gi.repository import Gtk Gimp.ui_init("palette-offset.py") use_header_bar = Gtk.Settings.get_default().get_property( "gtk-dialogs-use-header") dialog = Gimp.Dialog(use_header_bar=use_header_bar, title=_("Offset Palette...")) dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL) dialog.add_button("_OK", Gtk.ResponseType.OK) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, homogeneous=False, spacing=12) dialog.get_content_area().add(box) box.show() label = Gtk.Label.new_with_mnemonic("Off_set") box.pack_start(label, False, False, 1) label.show() amount = self.set_property("amount", amount) spin = Gimp.prop_spin_button_new(self, "amount", 1.0, 5.0, 0) spin.set_activates_default(True) box.pack_end(spin, False, False, 1) spin.show() dialog.show() if dialog.run() != Gtk.ResponseType.OK: return procedure.new_return_values(Gimp.PDBStatusType.CANCEL, GLib.Error()) amount = self.get_property("amount") #If palette is read only, work on a copy: editable = Gimp.palette_is_editable(palette) if not editable: palette = Gimp.palette_duplicate(palette) tmp_entry_array = [] for i in range(num_colors): tmp_entry_array.append((Gimp.palette_entry_get_name(palette, i)[1], Gimp.palette_entry_get_color(palette, i)[1])) for i in range(num_colors): target_index = i + amount if target_index >= num_colors: target_index -= num_colors elif target_index < 0: target_index += num_colors Gimp.palette_entry_set_name(palette, target_index, tmp_entry_array[i][0]) Gimp.palette_entry_set_color(palette, target_index, tmp_entry_array[i][1]) retval = procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error()) value = GObject.Value(GObject.TYPE_STRING, palette) retval.remove(1) retval.insert(1, value) return retval
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())