Updated with upstream update

This commit is contained in:
2023-10-30 15:55:30 -07:00
parent 098531073c
commit 3bbdd873ef
584 changed files with 91827 additions and 70362 deletions

View File

@ -68,11 +68,11 @@ fmt_from_bpp = {
12: 'III'
}
def save_colorxhtml(procedure, run_mode, image, n_layers, layers, file, args, data):
source_file = args.index(0)
characters = args.index(1)
size = args.index(2)
separate = args.index(3)
def save_colorxhtml(procedure, run_mode, image, n_layers, layers, file, metadata, config, data):
source_file = config.get_property("source-file")
characters = config.get_property("characters")
size = config.get_property("font-size");
separate = config.get_property("separate")
if file is None:
error = 'No file given'
@ -240,6 +240,8 @@ def save_colorxhtml(procedure, run_mode, image, n_layers, layers, file, args, da
chars[0:0] = data
for x in range(0, width):
# pika_drawable_get_pixel() was removed mistakenly in commit
# 89c359ce47. This must get fixed.
pixel_bytes = layer.get_pixel(x, y)
pixel_tuple = struct.unpack(fmt, pixel_bytes)
if bpp > 3:
@ -313,8 +315,8 @@ class ColorXhtml(Pika.PlugIn):
procedure = None
if name == 'file-colorxhtml-save':
procedure = Pika.SaveProcedure.new(self, name,
Pika.PDBProcType.PLUGIN,
save_colorxhtml, None)
Pika.PDBProcType.PLUGIN,
False, save_colorxhtml, None)
procedure.set_image_types("RGB")
procedure.set_documentation (
_("Save as colored HTML text"),

View File

@ -165,10 +165,11 @@ def thumbnail_ora(procedure, file, thumb_size, args, data):
fid.write(orafile.read('Thumbnails/thumbnail.png'))
thumb_file = Gio.file_new_for_path(tmp)
result = Pika.get_pdb().run_procedure('file-png-load', [
GObject.Value(Pika.RunMode, Pika.RunMode.NONINTERACTIVE),
GObject.Value(Gio.File, thumb_file),
])
pdb_proc = Pika.get_pdb().lookup_procedure('file-png-load')
pdb_config = pdb_proc.create_config()
pdb_config.set_property('run-mode', Pika.RunMode.NONINTERACTIVE)
pdb_config.set_property('file', thumb_file)
result = pdb_proc.run(pdb_config)
os.remove(tmp)
os.rmdir(tempdir)
@ -190,7 +191,7 @@ def thumbnail_ora(procedure, file, thumb_size, args, data):
# We would expect the n_drawables parameter to not be there with introspection but
# currently that isn't working, see issue #5312. Until that is resolved we keep
# this parameter here or else saving would fail.
def save_ora(procedure, run_mode, image, n_drawables, drawables, file, args, data):
def save_ora(procedure, run_mode, image, n_drawables, drawables, file, metadata, config, data):
def write_file_str(zfile, fname, data):
# work around a permission bug in the zipfile library:
# http://bugs.python.org/issue3394
@ -218,22 +219,22 @@ def save_ora(procedure, run_mode, image, n_drawables, drawables, file, args, dat
tmp = os.path.join(tempdir, 'tmp.png')
interlace, compression = 0, 2
Pika.get_pdb().run_procedure('file-png-save', [
GObject.Value(Pika.RunMode, Pika.RunMode.NONINTERACTIVE),
GObject.Value(Pika.Image, image),
GObject.Value(GObject.TYPE_INT, 1),
GObject.Value(Pika.ObjectArray, Pika.ObjectArray.new(Pika.Drawable, [drawable], False)),
GObject.Value(Gio.File, Gio.File.new_for_path(tmp)),
GObject.Value(GObject.TYPE_BOOLEAN, interlace),
GObject.Value(GObject.TYPE_INT, compression),
# write all PNG chunks except oFFs(ets)
GObject.Value(GObject.TYPE_BOOLEAN, True), # Save background color (bKGD chunk)
GObject.Value(GObject.TYPE_BOOLEAN, False), # Save layer offset (oFFs chunk)
GObject.Value(GObject.TYPE_BOOLEAN, True), # Save resolution (pHYs chunk)
GObject.Value(GObject.TYPE_BOOLEAN, True), # Save creation time (tIME chunk)
# Other settings
GObject.Value(GObject.TYPE_BOOLEAN, True), # Save color values from transparent pixels
])
pdb_proc = Pika.get_pdb().lookup_procedure('file-png-save')
pdb_config = pdb_proc.create_config()
pdb_config.set_property('run-mode', Pika.RunMode.NONINTERACTIVE)
pdb_config.set_property('image', image)
pdb_config.set_property('num-drawables', 1)
pdb_config.set_property('drawables', Pika.ObjectArray.new(Pika.Drawable, [drawable], False))
pdb_config.set_property('file', Gio.File.new_for_path(tmp))
pdb_config.set_property('interlaced', interlace)
pdb_config.set_property('compression', compression)
# write all PNG chunks except oFFs(ets)
pdb_config.set_property('bkgd', True)
pdb_config.set_property('offs', False)
pdb_config.set_property('phys', True)
pdb_config.set_property('time', True)
pdb_config.set_property('save-transparent', True)
pdb_proc.run(pdb_config)
if (os.path.exists(tmp)):
orafile.write(tmp, path)
os.remove(tmp)
@ -350,7 +351,7 @@ def save_ora(procedure, run_mode, image, n_drawables, drawables, file, args, dat
GObject.Value(Pika.PDBStatusType, Pika.PDBStatusType.SUCCESS)
])
def load_ora(procedure, run_mode, file, args, data):
def load_ora(procedure, run_mode, file, metadata, flags, config, data):
tempdir = tempfile.mkdtemp('pika-plugin-file-openraster')
orafile = zipfile.ZipFile(file.peek_path())
stack, w, h = get_image_attributes(orafile)
@ -358,7 +359,6 @@ def load_ora(procedure, run_mode, file, args, data):
Pika.progress_init("Loading openraster image")
img = Pika.Image.new(w, h, Pika.ImageBaseType.RGB)
img.set_file (file)
def get_layers(root):
"""iterates over layers and nested stacks"""
@ -410,13 +410,14 @@ def load_ora(procedure, run_mode, file, args, data):
fid.write(data)
# import layer, set attributes and add to image
result = pika_layer = Pika.get_pdb().run_procedure('pika-file-load-layer', [
GObject.Value(Pika.RunMode, Pika.RunMode.NONINTERACTIVE),
GObject.Value(Pika.Image, img),
GObject.Value(Gio.File, Gio.File.new_for_path(tmp)),
])
pdb_proc = Pika.get_pdb().lookup_procedure('pika-file-load-layer')
pdb_config = pdb_proc.create_config()
pdb_config.set_property('run-mode', Pika.RunMode.NONINTERACTIVE)
pdb_config.set_property('image', img)
pdb_config.set_property('file', Gio.File.new_for_path(tmp))
result = pdb_proc.run(pdb_config)
if (result.index(0) == Pika.PDBStatusType.SUCCESS):
pika_layer = pika_layer.index(1)
pika_layer = result.index(1)
os.remove(tmp)
else:
print("Error loading layer from openraster image.")
@ -448,7 +449,7 @@ def load_ora(procedure, run_mode, file, args, data):
return Pika.ValueArray.new_from_values([
GObject.Value(Pika.PDBStatusType, Pika.PDBStatusType.SUCCESS),
GObject.Value(Pika.Image, img),
])
]), flags
class FileOpenRaster (Pika.PlugIn):
@ -465,7 +466,7 @@ class FileOpenRaster (Pika.PlugIn):
if name == 'file-openraster-save':
procedure = Pika.SaveProcedure.new(self, name,
Pika.PDBProcType.PLUGIN,
save_ora, None)
False, save_ora, None)
procedure.set_image_types("*");
procedure.set_documentation ('save an OpenRaster (.ora) file',
'save an OpenRaster (.ora) file',

View File

@ -29,10 +29,7 @@ def N_(message): return message
def _(message): return GLib.dgettext(None, message)
def foggify(procedure, run_mode, image, n_drawables, drawables, args, data):
config = procedure.create_config()
config.begin_run(image, run_mode, args)
def foggify(procedure, run_mode, image, n_drawables, drawables, config, data):
if run_mode == Pika.RunMode.INTERACTIVE:
PikaUi.init('python-fu-foggify')
dialog = PikaUi.ProcedureDialog(procedure=procedure, config=config)
@ -73,13 +70,14 @@ def foggify(procedure, run_mode, image, n_drawables, drawables, args, data):
fog.add_mask(mask)
# add some clouds to the layer
Pika.get_pdb().run_procedure('plug-in-plasma', [
GObject.Value(Pika.RunMode, Pika.RunMode.NONINTERACTIVE),
GObject.Value(Pika.Image, image),
GObject.Value(Pika.Drawable, mask),
GObject.Value(GObject.TYPE_INT, int(time.time())),
GObject.Value(GObject.TYPE_DOUBLE, turbulence),
])
pdb_proc = Pika.get_pdb().lookup_procedure('plug-in-plasma')
pdb_config = pdb_proc.create_config()
pdb_config.set_property('run-mode', Pika.RunMode.NONINTERACTIVE)
pdb_config.set_property('image', image)
pdb_config.set_property('drawable', mask)
pdb_config.set_property('seed', int(time.time()))
pdb_config.set_property('turbulence', turbulence)
pdb_proc.run(pdb_config)
# apply the clouds to the layer
fog.remove_mask(Pika.MaskApplyMode.APPLY)
@ -90,8 +88,6 @@ def foggify(procedure, run_mode, image, n_drawables, drawables, args, data):
image.undo_group_end()
Pika.context_pop()
config.end_run(Pika.PDBStatusType.SUCCESS)
return procedure.new_return_values(Pika.PDBStatusType.SUCCESS, GLib.Error())
_color = Pika.RGB()

View File

@ -61,21 +61,13 @@ def format_text(text):
return ",".join(new_text)
def gradient_css_save(procedure, args, data):
if args.length() != 3:
error = 'Wrong parameters given'
return procedure.new_return_values(Pika.PDBStatusType.CALLING_ERROR,
GLib.Error(error))
runmode = args.index(0)
gradient = args.index(1)
file = args.index(2)
config = procedure.create_config()
config.begin_run(None, Pika.RunMode.INTERACTIVE, args)
def gradient_css_save(procedure, config, data):
runmode = config.get_property("run-mode")
if runmode == Pika.RunMode.INTERACTIVE:
PikaUi.init('python-fu-gradient-save-as-css')
dialog = PikaUi.ProcedureDialog(procedure=procedure, config=config)
file = None
# Add gradient button
dialog.fill (["gradient"])
@ -137,20 +129,19 @@ def gradient_css_save(procedure, args, data):
if not dialog.run():
dialog.destroy()
config.end_run(Pika.PDBStatusType.CANCEL)
return procedure.new_return_values(Pika.PDBStatusType.CANCEL, GLib.Error())
else:
gradient = config.get_property("gradient")
file = Gio.file_new_for_path(file_entry.get_text())
#Save configs for non-connected UI element
config.set_property ("file", file)
dialog.destroy()
gradient = config.get_property("gradient")
file = config.get_property("file")
if file is None:
error = 'No file given'
config.end_run(Pika.PDBStatusType.CALLING_ERROR)
return procedure.new_return_values(Pika.PDBStatusType.CALLING_ERROR,
GLib.Error(error))
@ -187,10 +178,8 @@ def gradient_css_save(procedure, args, data):
flags=Gio.FileCreateFlags.REPLACE_DESTINATION,
cancellable=None)
if success:
config.end_run(Pika.PDBStatusType.SUCCESS)
return procedure.new_return_values(Pika.PDBStatusType.SUCCESS, GLib.Error())
else:
config.end_run(Pika.PDBStatusType.EXECUTION_ERROR)
return procedure.new_return_values(Pika.PDBStatusType.EXECUTION_ERROR,
GLib.Error('File saving failed: {}'.format(file.get_path())))
@ -225,7 +214,7 @@ class GradientsSaveAsCSS (Pika.PlugIn):
procedure.set_documentation (_("Creates a new palette from a given gradient"),
_("Creates a new palette from a given gradient"),
name)
procedure.set_menu_label(_("Save as CSS..."))
procedure.set_menu_label(_("Save Gradient as CSS..."))
procedure.set_attribution("Joao S. O. Bueno",
"(c) GPL V3.0 or later",
"2011")

View File

@ -96,9 +96,8 @@ output_format_enum = StringEnum(
def histogram_export(procedure, img, layers, gio_file,
bucket_size, sample_average, output_format,
progress_bar):
layers = img.get_selected_layers()
bucket_size, sample_average, output_format):
layers = img.list_selected_layers()
layer = layers[0]
if sample_average:
new_img = img.duplicate()
@ -117,6 +116,9 @@ def histogram_export(procedure, img, layers, gio_file,
try:
with open(gio_file.get_path(), "wt") as hfile:
writer = csv.writer(hfile)
histo_proc = Pika.get_pdb().lookup_procedure('pika-drawable-histogram')
histo_config = histo_proc.create_config()
histo_config.set_property('drawable', layer)
# Write headers:
writer.writerow(["Range start"] + channels_txt)
@ -130,15 +132,12 @@ def histogram_export(procedure, img, layers, gio_file,
if start_range >= 1.0:
break
histo_config.set_property('start-range', float(start_range))
histo_config.set_property('end-range', float(min(start_range + bucket_size, 1.0)))
row = [start_range]
for channel in channels_pika:
result = Pika.get_pdb().run_procedure('pika-drawable-histogram',
[ GObject.Value(Pika.Drawable, layer),
GObject.Value(Pika.HistogramChannel, channel),
GObject.Value(GObject.TYPE_DOUBLE,
float(start_range)),
GObject.Value(GObject.TYPE_DOUBLE,
float(min(start_range + bucket_size, 1.0))) ])
histo_config.set_property('channel', channel)
result = histo_proc.run(histo_config)
if output_format == output_format_enum.pixel_count:
count = int(result.index(5))
@ -151,16 +150,12 @@ def histogram_export(procedure, img, layers, gio_file,
writer.writerow(row)
# Update progress bar
if progress_bar:
fraction = i / max_index
# Only update the progress bar if it changed at least 1% .
new_percent = math.floor(fraction * 100)
if new_percent != progress_bar_int_percent:
progress_bar_int_percent = new_percent
progress_bar.set_fraction(fraction)
# Make sure the progress bar gets drawn on screen.
while Gtk.events_pending():
Gtk.main_iteration()
fraction = i / max_index
# Only update the progress bar if it changed at least 1% .
new_percent = math.floor(fraction * 100)
if new_percent != progress_bar_int_percent:
progress_bar_int_percent = new_percent
Pika.progress_update(fraction)
except IsADirectoryError:
return procedure.new_return_values(Pika.PDBStatusType.EXECUTION_ERROR,
GLib.Error(_("File is either a directory or file name is empty.")))
@ -177,112 +172,21 @@ def histogram_export(procedure, img, layers, gio_file,
return procedure.new_return_values(Pika.PDBStatusType.SUCCESS, GLib.Error())
def run(procedure, run_mode, image, n_layers, layers, args, data):
gio_file = args.index(0)
bucket_size = args.index(1)
sample_average = args.index(2)
output_format = args.index(3)
progress_bar = None
config = None
def run(procedure, run_mode, image, n_layers, layers, config, data):
if run_mode == Pika.RunMode.INTERACTIVE:
config = procedure.create_config()
# Set properties from arguments. These properties will be changed by the UI.
#config.set_property("file", gio_file)
#config.set_property("bucket_size", bucket_size)
#config.set_property("sample_average", sample_average)
#config.set_property("output_format", output_format)
config.begin_run(image, run_mode, args)
PikaUi.init("histogram-export.py")
use_header_bar = Gtk.Settings.get_default().get_property("gtk-dialogs-use-header")
dialog = PikaUi.Dialog(use_header_bar=use_header_bar,
title=_("Histogram Export..."))
dialog.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL)
dialog.add_button(_("_OK"), Gtk.ResponseType.OK)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
homogeneous=False, spacing=10)
dialog.get_content_area().add(vbox)
vbox.show()
dialog = PikaUi.ProcedureDialog.new(procedure, config, _("Histogram Export..."))
dialog.fill(None)
# Create grid to set all the properties inside.
grid = Gtk.Grid()
grid.set_column_homogeneous(False)
grid.set_border_width(10)
grid.set_column_spacing(10)
grid.set_row_spacing(10)
vbox.add(grid)
grid.show()
# UI for the file parameter
def choose_file(widget):
if file_chooser_dialog.run() == Gtk.ResponseType.OK:
if file_chooser_dialog.get_file() is not None:
config.set_property("file", file_chooser_dialog.get_file())
file_entry.set_text(file_chooser_dialog.get_file().get_path())
file_chooser_dialog.hide()
file_chooser_button = Gtk.Button.new_with_mnemonic(label=_("_File..."))
grid.attach(file_chooser_button, 0, 0, 1, 1)
file_chooser_button.show()
file_chooser_button.connect("clicked", choose_file)
file_entry = Gtk.Entry.new()
grid.attach(file_entry, 1, 0, 1, 1)
file_entry.set_width_chars(40)
file_entry.set_placeholder_text(_("Choose export file..."))
if gio_file is not None:
file_entry.set_text(gio_file.get_path())
file_entry.show()
file_chooser_dialog = Gtk.FileChooserDialog(use_header_bar=use_header_bar,
title=_("Histogram Export file..."),
action=Gtk.FileChooserAction.SAVE)
file_chooser_dialog.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL)
file_chooser_dialog.add_button(_("_OK"), Gtk.ResponseType.OK)
# Bucket size parameter
label = Gtk.Label.new_with_mnemonic(_("_Bucket Size"))
grid.attach(label, 0, 1, 1, 1)
label.show()
spin = PikaUi.prop_spin_button_new(config, "bucket_size", step_increment=0.001, page_increment=0.1, digits=3)
grid.attach(spin, 1, 1, 1, 1)
spin.show()
# Sample average parameter
spin = PikaUi.prop_check_button_new(config, "sample_average", _("Sample _Average"))
spin.set_tooltip_text(_("If checked, the histogram is generated from merging all visible layers."
" Otherwise, the histogram is only for the current layer."))
grid.attach(spin, 1, 2, 1, 1)
spin.show()
# Output format parameter
label = Gtk.Label.new_with_mnemonic(_("_Output Format"))
grid.attach(label, 0, 3, 1, 1)
label.show()
combo = PikaUi.prop_string_combo_box_new(config, "output_format", output_format_enum.get_tree_model(), 0, 1)
grid.attach(combo, 1, 3, 1, 1)
combo.show()
progress_bar = Gtk.ProgressBar()
vbox.add(progress_bar)
progress_bar.show()
dialog.show()
if dialog.run() != Gtk.ResponseType.OK:
if not dialog.run():
return procedure.new_return_values(Pika.PDBStatusType.CANCEL,
GLib.Error())
# Extract values from UI
gio_file = Gio.file_new_for_path(file_entry.get_text()) # config.get_property("file")
bucket_size = config.get_property("bucket_size")
sample_average = config.get_property("sample_average")
output_format = config.get_property("output_format")
gio_file = config.get_property('file')
bucket_size = config.get_property("bucket-size")
sample_average = config.get_property("sample-average")
output_format = config.get_property("output-format")
if gio_file is None:
error = 'No file given'
@ -290,11 +194,7 @@ def run(procedure, run_mode, image, n_layers, layers, args, data):
GLib.Error(error))
result = histogram_export(procedure, image, layers, gio_file,
bucket_size, sample_average, output_format, progress_bar)
# If the execution was successful, save parameters so they will be restored next time we show dialog.
if result.index(0) == Pika.PDBStatusType.SUCCESS and config is not None:
config.end_run(Pika.PDBStatusType.SUCCESS)
bucket_size, sample_average, output_format)
return result
@ -303,31 +203,24 @@ class HistogramExport(Pika.PlugIn):
## Parameters ##
__gproperties__ = {
# "filename": (str,
# # TODO: I wanted this property to be a path (and not just str) , so I could use
# # prop_file_chooser_button_new to open a file dialog. However, it fails without an error message.
# # Pika.ConfigPath,
# _("Histogram _File"),
# _("Histogram _File"),
# "histogram_export.csv",
# # Pika.ConfigPathType.FILE,
# GObject.ParamFlags.READWRITE),
# TODO: GFile props still don't have labels + only load existing files
# (here we likely want to create a new file).
"file": (Gio.File,
_("Histogram _File"),
"Histogram export file",
GObject.ParamFlags.READWRITE),
"bucket_size": (float,
"bucket-size": (float,
_("_Bucket Size"),
"Bucket Size",
0.001, 1.0, 0.01,
GObject.ParamFlags.READWRITE),
"sample_average": (bool,
"sample-average": (bool,
_("Sample _Average"),
"Sample Average",
False,
GObject.ParamFlags.READWRITE),
"output_format": (str,
_("Output format"),
"output-format": (str,
_("Output _format"),
"Output format: 'pixel count', 'normalized', 'percent'",
"pixel count",
GObject.ParamFlags.READWRITE),
@ -359,9 +252,9 @@ class HistogramExport(Pika.PlugIn):
procedure.add_menu_path("<Image>/Colors/Info/")
procedure.add_argument_from_property(self, "file")
procedure.add_argument_from_property(self, "bucket_size")
procedure.add_argument_from_property(self, "sample_average")
procedure.add_argument_from_property(self, "output_format")
procedure.add_argument_from_property(self, "bucket-size")
procedure.add_argument_from_property(self, "sample-average")
procedure.add_argument_from_property(self, "output-format")
return procedure

View File

@ -108,30 +108,20 @@ class PaletteOffset (Pika.PlugIn):
return procedure
def run(self, procedure, args, data):
palette = None
amount = 1
def run(self, procedure, config, data):
runmode = config.get_property("run-mode")
palette = config.get_property("palette")
amount = config.get_property("amount")
# Get the parameters
if args.length() < 1:
error = 'No parameters given'
return procedure.new_return_values(Pika.PDBStatusType.CALLING_ERROR,
GLib.Error(error))
runmode = args.index(0)
if args.length() > 1:
palette = args.index(1)
if palette is None:
palette = Pika.context_get_palette()
config.set_property("palette", palette)
if not palette.is_valid():
error = f'Invalid palette ID: {palette.get_id()}'
return procedure.new_return_values(Pika.PDBStatusType.CALLING_ERROR,
GLib.Error(error))
if args.length() > 2:
amount = args.index(2)
if runmode == Pika.RunMode.INTERACTIVE:
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
@ -140,7 +130,7 @@ class PaletteOffset (Pika.PlugIn):
use_header_bar = Gtk.Settings.get_default().get_property("gtk-dialogs-use-header")
dialog = PikaUi.Dialog(use_header_bar=use_header_bar,
title=_("Offset Palette..."))
title=_("Offset Palette..."))
dialog.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL)
dialog.add_button(_("_OK"), Gtk.ResponseType.OK)
@ -162,10 +152,10 @@ class PaletteOffset (Pika.PlugIn):
dialog.show()
if dialog.run() != Gtk.ResponseType.OK:
print ("Canceled")
return procedure.new_return_values(Pika.PDBStatusType.CANCEL,
GLib.Error("Canceled"))
amount = self.get_property("amount")
config.set_property("amount", amount)
#If palette is read only, work on a copy:
editable = palette.is_editable()

View File

@ -444,21 +444,9 @@ class PaletteSort (Pika.PlugIn):
return procedure
def run(self, procedure, args, data):
config = procedure.create_config()
config.begin_run(None, Pika.RunMode.INTERACTIVE, args)
run_mode = args.index(0)
palette = args.index(1)
selection = args.index(2)
slice_expr = args.index(3)
channel1 = args.index(4)
ascending1 = args.index(5)
channel2 = args.index(6)
ascending2 = args.index(7)
quantize = args.index(8)
pchannel = args.index(9)
pquantize = args.index(10)
def run(self, procedure, config, data):
run_mode = config.get_property("run-mode")
palette = config.get_property("palette")
if palette is None or not palette.is_valid():
if palette is not None:
@ -466,6 +454,7 @@ class PaletteSort (Pika.PlugIn):
sys.stderr.write('This should not happen. Please report to PIKA project.\n')
sys.stderr.write('Falling back to context palette instead.\n')
palette = Pika.context_get_palette()
config.set_property("palette", palette)
if not palette.is_valid():
palette_name = palette.get_id()
@ -489,22 +478,20 @@ class PaletteSort (Pika.PlugIn):
if not dialog.run():
dialog.destroy()
config.end_run(Pika.PDBStatusType.CANCEL)
return procedure.new_return_values(Pika.PDBStatusType.CANCEL, GLib.Error())
else:
palette = config.get_property("palette")
selection = config.get_property("selections")
slice_expr = config.get_property ("slice_expr")
channel1 = config.get_property("channel1")
ascending1 = config.get_property ("ascending1")
channel2 = config.get_property("channel2")
ascending2 = config.get_property ("ascending2")
quantize = config.get_property ("quantize")
pchannel = config.get_property("pchannel")
pquantize = config.get_property ("pquantize")
dialog.destroy()
dialog.destroy()
palette = config.get_property("palette")
selection = config.get_property("selections")
slice_expr = config.get_property ("slice_expr")
channel1 = config.get_property("channel1")
ascending1 = config.get_property ("ascending1")
channel2 = config.get_property("channel2")
ascending2 = config.get_property ("ascending2")
quantize = config.get_property ("quantize")
pchannel = config.get_property("pchannel")
pquantize = config.get_property ("pquantize")
try:
new_palette = palette_sort(palette, selection, slice_expr, channel1, ascending1,
channel2, ascending2, quantize, pchannel, pquantize)
@ -512,13 +499,10 @@ class PaletteSort (Pika.PlugIn):
return procedure.new_return_values(Pika.PDBStatusType.EXECUTION_ERROR,
GLib.Error(str(err)))
config.end_run(Pika.PDBStatusType.SUCCESS)
return_val = procedure.new_return_values(Pika.PDBStatusType.SUCCESS, GLib.Error())
value = GObject.Value(Pika.Palette, new_palette)
return_val.remove(1)
return_val.insert(1, value)
return return_val
Pika.main(PaletteSort.__gtype__, sys.argv)

View File

@ -33,7 +33,7 @@ def make_gradient(palette, num_segments, num_colors):
# name the gradient same as the source palette
# For now, the name of a resource is the same as the ID
palette_name = palette.get_id()
palette_name = palette.get_name()
gradient = Pika.Gradient.new(palette_name)
# assert gradient is valid but is has only one segment
assert gradient.get_number_of_segments() == 1
@ -56,13 +56,9 @@ def make_gradient(palette, num_segments, num_colors):
Pika.context_set_gradient(gradient)
return gradient
def run(procedure, args, data):
config = procedure.create_config()
config.begin_run(None, Pika.RunMode.INTERACTIVE, args)
def run(procedure, config, data):
# Get the parameters
run_mode = args.index(0)
palette = args.index(1)
run_mode = config.get_property("run-mode")
if run_mode == Pika.RunMode.INTERACTIVE:
PikaUi.init(procedure.get_name())
@ -73,19 +69,18 @@ def run(procedure, args, data):
if not dialog.run():
dialog.destroy()
config.end_run(Pika.PDBStatusType.CANCEL)
return procedure.new_return_values(Pika.PDBStatusType.CANCEL, GLib.Error())
else:
palette = config.get_property("palette")
dialog.destroy()
dialog.destroy()
palette = config.get_property("palette")
if palette is None or not palette.is_valid():
if palette is not None:
sys.stderr.write(f'Invalid palette id: {palette.get_id()}\n')
sys.stderr.write('This should not happen. Please report to PIKA project.\n')
sys.stderr.write('Falling back to context palette instead.\n')
palette = Pika.context_get_palette()
config.set_property("palette", palette)
num_colors = palette.get_color_count()
@ -95,7 +90,6 @@ def run(procedure, args, data):
num_segments = num_colors
gradient = make_gradient(palette, num_segments, num_colors)
config.end_run(Pika.PDBStatusType.SUCCESS)
# XXX: for the error parameter, we want to return None.
# Unfortunately even though the argument is (nullable), pygobject
# looks like it may have a bug. So workaround is to just set a
@ -132,7 +126,7 @@ class PaletteToGradient (Pika.PlugIn):
## Parameter: palette ##
@GObject.Property(type=Pika.Palette,
default=None,
nick= _("Palette"))
nick= _("_Palette"))
def palette(self):
'''Palette or None for the currently selected palette'''
return self.palette

View File

@ -41,7 +41,7 @@ PROC_NAME = 'python-fu-console'
RESPONSE_BROWSE, RESPONSE_CLEAR, RESPONSE_SAVE = range(3)
def run(procedure, args, data):
def run(procedure, config, data):
PikaUi.init ("python-console.py")
namespace = {'__builtins__': __builtins__,
@ -51,6 +51,7 @@ def run(procedure, args, data):
'Gdk': gi.repository.Gdk,
'Gegl': gi.repository.Gegl,
'Pika': gi.repository.Pika,
'PikaUi': gi.repository.PikaUi,
'Gio': gi.repository.Gio,
'Gtk': gi.repository.Gtk,
'GdkPixbuf': gi.repository.GdkPixbuf,
@ -160,71 +161,30 @@ def run(procedure, args, data):
if proc is None:
return None
cmd = ''
return_values = proc.get_return_values()
# assert is list of GParamSpec
param_specs = proc.get_arguments()
'''
Cat str of variable names to which unpack return values
Variable names same as return value name, mangled
Str like: 'retval_1, ret_val_2 = '
'''
cmd = f"procedure = Pika.get_pdb().lookup_procedure('{proc_name}'); "
cmd += f"config = procedure.create_config(); "
for arg in param_specs:
if arg.name == 'run-mode':
# Special handling for run mode.
cmd += "config.set_property('" + arg.name + "', Pika.RunMode.INTERACTIVE); "
else:
cmd += "config.set_property('" + arg.name + "', " + arg.name.replace('-', '_') + "); "
cmd += f"result = procedure.run(config); "
cmd += f"success = result.index(0)"
if len(return_values) > 0:
cmd += ', '.join(x.name.replace('-', '_') for x in return_values)
cmd += ' = '
# else is a void PDB procedure
'''
Cat prefix of str for a call to procedure name
Prefix like: Pika.get_pdb().run_procedure('<foo>',
Note:
- proc name is quoted, run_procedure wants a string.
- proc name has hyphens. Not a Python name. Matches name in PDB.
- trailing comma, another arg to follow:
run_procedure takes two args: string name, and GValueArray of args
'''
cmd += f"Pika.get_pdb().run_procedure('{proc_name}', "
'''
Assemble argument string.
Using names of formal args, which might not match names already
defined in the browsing environment (the REPL).
Args are passed to a PDB procedure in a GValueArray.
Assemble a string like '[arg_1, arg_2]'.
When eval'd, the Python binding will convert to a GValueArray.
'''
param_specs = proc.get_arguments()
cmd += '[ '
'''
Special handling for run mode.
PIKA v2: PikaFu had different handling for run mode.
Insure run mode interactive, i.e. called procedure may open a GUI.
This assumes that procedures use the same formal name for runmode arg.
There might be rare other cases, especially for third party plugins?
E.G. See formal signature of file-gex-load
There is no other way to distinguish the run mode formal argument,
as its formal type is PikaParamEnum, a generic enum.
'''
if len(param_specs) > 0 and param_specs[0].name == 'run-mode':
cmd += 'Pika.RunMode.INTERACTIVE, '
param_specs = param_specs[1:]
# else doesn't take a run mode arg
# Cat string of arg names to a call
# Like: 'arg_1, arg_2' where formal names arg-1 and arg-2
cmd += ', '.join(x.name.replace('-', '_') for x in param_specs)
# terminate the arg array, and close parens the call
cmd += '])'
i = 1
for retval in return_values:
cmd += '; {} = result.index({})'.format(retval.name.replace('-', '_'), i)
i += 1
return cmd
def browse_response(self, dlg, response_id):
if response_id != Gtk.ResponseType.APPLY:
Gtk.Widget.hide(dlg)

View File

@ -26,13 +26,12 @@ from gi.repository import Gio
import sys
def code_eval(procedure, run_mode, code, args, data):
def code_eval(procedure, run_mode, code, config, data):
if code == '-':
code = sys.stdin.read()
exec(code, globals())
return procedure.new_return_values(Pika.PDBStatusType.SUCCESS, GLib.Error())
class PythonEval (Pika.PlugIn):
## PikaPlugIn virtual methods ##
def do_set_i18n(self, procname):

View File

@ -375,15 +375,10 @@ class SelectionToPath:
else:
selection_was_empty = False
result = Pika.get_pdb().run_procedure('plug-in-sel2path', [
GObject.Value(Pika.RunMode, Pika.RunMode.NONINTERACTIVE),
GObject.Value(Pika.Image, self.image),
GObject.Value(GObject.TYPE_INT, 0),
# XXX: I could use self.image.list_selected_layers() but for
# this call, it doesn't matter anyway.
GObject.Value(Pika.ObjectArray,
Pika.ObjectArray.new(Pika.Drawable, [], False)),
])
proc = Pika.get_pdb().lookup_procedure('plug-in-sel2path')
config = proc.create_config()
config.set_property('image', self.image)
result = proc.run(config)
self.path = self.image.list_vectors()[0]
self.stroke_ids = self.path.get_strokes()
@ -2212,7 +2207,7 @@ class SpyropikaPlusPlugin(Pika.PlugIn):
## Parameters ##
__gproperties__ = {
"curve_type" : (int,
"curve-type" : (int,
_("The curve type { Spyrograph (0), Epitrochoid (1), Sine (2), Lissajous(3) }"),
_("The curve type { Spyrograph (0), Epitrochoid (1), Sine (2), Lissajous(3) }"),
0, 3, 0,
@ -2232,17 +2227,17 @@ class SpyropikaPlusPlugin(Pika.PlugIn):
_("Morph shape of fixed gear, between 0 and 1. Only used by some shapes."),
0.0, 1.0, 0.0,
GObject.ParamFlags.READWRITE),
"fixed_teeth": (int,
"fixed-teeth": (int,
_("Number of teeth for fixed gear"),
_("Number of teeth for fixed gear"),
0, GLib.MAXINT, 96,
GObject.ParamFlags.READWRITE),
"moving_teeth": (int,
"moving-teeth": (int,
_("Number of teeth for moving gear"),
_("Number of teeth for moving gear"),
0, GLib.MAXINT, 36,
GObject.ParamFlags.READWRITE),
"hole_percent": (float,
"hole-percent": (float,
_("Location of hole in moving gear in percent, where 100 means that "
"the hole is at the edge of the gear, and 0 means the hole is at the center"),
_("Location of hole in moving gear in percent, where 100 means that "
@ -2254,17 +2249,17 @@ class SpyropikaPlusPlugin(Pika.PlugIn):
_("Margin from selection, in pixels"),
0, GLib.MAXINT, 0,
GObject.ParamFlags.READWRITE),
"equal_w_h": (bool,
"equal-w-h": (bool,
_("Make height and width equal"),
_("Make height and width equal"),
False,
GObject.ParamFlags.READWRITE),
"pattern_rotation": (float,
"pattern-rotation": (float,
_("Pattern rotation, in degrees"),
_("Pattern rotation, in degrees"),
-360.0, 360.0, 0.0,
GObject.ParamFlags.READWRITE),
"shape_rotation": (float,
"shape-rotation": (float,
_("Shape rotation of fixed gear, in degrees"),
_("Shape rotation of fixed gear, in degrees"),
-360.0, 360.0, 0.0,
@ -2274,7 +2269,7 @@ class SpyropikaPlusPlugin(Pika.PlugIn):
_("Tool to use for drawing the pattern."),
0, GLib.MAXINT, 1,
GObject.ParamFlags.READWRITE),
"long_gradient" : (bool,
"long-gradient" : (bool,
_("Whether to apply a long gradient to match the length of the pattern. "
"Only applicable to some of the tools."),
_("Whether to apply a long gradient to match the length of the pattern. "
@ -2307,37 +2302,37 @@ class SpyropikaPlusPlugin(Pika.PlugIn):
"2018")
procedure.add_menu_path ("<Image>/Filters/Render/")
procedure.add_argument_from_property(self, "curve_type")
procedure.add_argument_from_property(self, "curve-type")
procedure.add_argument_from_property(self, "shape")
procedure.add_argument_from_property(self, "sides")
procedure.add_argument_from_property(self, "morph")
procedure.add_argument_from_property(self, "fixed_teeth")
procedure.add_argument_from_property(self, "moving_teeth")
procedure.add_argument_from_property(self, "fixed-teeth")
procedure.add_argument_from_property(self, "moving-teeth")
procedure.add_argument_from_property(self, "hole_percent")
procedure.add_argument_from_property(self, "margin")
procedure.add_argument_from_property(self, "equal_w_h")
procedure.add_argument_from_property(self, "pattern_rotation")
procedure.add_argument_from_property(self, "shape_rotation")
procedure.add_argument_from_property(self, "equal-w-h")
procedure.add_argument_from_property(self, "pattern-rotation")
procedure.add_argument_from_property(self, "shape-rotation")
procedure.add_argument_from_property(self, "tool")
procedure.add_argument_from_property(self, "long_gradient")
procedure.add_argument_from_property(self, "long-gradient")
return procedure
# Implementation of plugin.
def plug_in_spyropika(self, procedure, run_mode, image, n_layers, layers, args, data):
curve_type=args.index(0)
shape=args.index(1)
sides=args.index(2)
morph=args.index(3)
fixed_teeth=args.index(4)
moving_teeth=args.index(5)
hole_percent=args.index(6)
margin=args.index(7)
equal_w_h=args.index(8)
pattern_rotation=args.index(9)
shape_rotation=args.index(10)
tool=args.index(11)
long_gradient=args.index(12)
def plug_in_spyropika(self, procedure, run_mode, image, n_layers, layers, config, data):
curve_type=config.get_property('curve-type')
shape=config.get_property('shape')
sides=config.get_property('sides')
morph=config.get_property('morph')
fixed_teeth=config.get_property('fixed-teeth')
moving_teeth=config.get_property('moving-teeth')
hole_percent=config.get_property('hole-percent')
margin=config.get_property('margin')
equal_w_h=config.get_property('equal-w-h')
pattern_rotation=config.get_property('pattern-rotation')
shape_rotation=config.get_property('shape-rotation')
tool=config.get_property('tool')
long_gradient=config.get_property('long-gradient')
if run_mode == Pika.RunMode.NONINTERACTIVE:
pp = PatternParameters()

View File

@ -18,6 +18,8 @@ gi.require_version('Pika', '3.0')
from gi.repository import Pika
gi.require_version('PikaUi', '3.0')
from gi.repository import PikaUi
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
@ -90,15 +92,13 @@ def process_args(brush, font, gradient, palette, pattern):
return
def test_dialog(procedure, run_mode, image, n_drawables, drawables, args, data):
def test_dialog(procedure, run_mode, image, n_drawables, drawables, config, data):
'''
Just a standard shell for a plugin.
'''
config = procedure.create_config()
config.begin_run(image, run_mode, args)
if run_mode == Pika.RunMode.INTERACTIVE:
PikaUi.init('python-fu-test-dialog')
Gegl.init(None)
dialog = PikaUi.ProcedureDialog(procedure=procedure, config=config)
dialog.fill(None)
if not dialog.run():
@ -122,8 +122,6 @@ def test_dialog(procedure, run_mode, image, n_drawables, drawables, args, data):
Pika.context_pop()
config.end_run(Pika.PDBStatusType.SUCCESS)
return procedure.new_return_values(Pika.PDBStatusType.SUCCESS, GLib.Error())