|
|
|
@ -27,23 +27,47 @@ from gi.repository import Gio
|
|
|
|
|
|
|
|
|
|
gi.require_version('Gtk', '3.0')
|
|
|
|
|
from gi.repository import Gtk
|
|
|
|
|
|
|
|
|
|
import gettext
|
|
|
|
|
import subprocess
|
|
|
|
|
import pickle
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
|
|
_ = gettext.gettext
|
|
|
|
|
image_paths = {"colorpalette": os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'colorpalette',
|
|
|
|
|
'color_palette.png'),
|
|
|
|
|
"logo": os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'images',
|
|
|
|
|
'plugin_logo.png'),
|
|
|
|
|
"error": os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'images',
|
|
|
|
|
'error_icon.png')}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def N_(message): return message
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import subprocess
|
|
|
|
|
import pickle
|
|
|
|
|
import os
|
|
|
|
|
def show_dialog(message, title, icon="logo"):
|
|
|
|
|
use_header_bar = Gtk.Settings.get_default().get_property("gtk-dialogs-use-header")
|
|
|
|
|
dialog = GimpUi.Dialog(use_header_bar=use_header_bar, title=_(title))
|
|
|
|
|
# Add buttons
|
|
|
|
|
dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL)
|
|
|
|
|
dialog.add_button("_OK", Gtk.ResponseType.APPLY)
|
|
|
|
|
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, homogeneous=False, spacing=10)
|
|
|
|
|
dialog.get_content_area().add(vbox)
|
|
|
|
|
vbox.show()
|
|
|
|
|
# Show Logo
|
|
|
|
|
logo = Gtk.Image.new_from_file(image_paths[icon])
|
|
|
|
|
vbox.pack_start(logo, False, False, 1)
|
|
|
|
|
logo.show()
|
|
|
|
|
# Show message
|
|
|
|
|
label = Gtk.Label(label=_(message))
|
|
|
|
|
vbox.pack_start(label, False, False, 1)
|
|
|
|
|
label.show()
|
|
|
|
|
dialog.show()
|
|
|
|
|
dialog.run()
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def coloring(procedure, image, n_drawables, drawables, force_cpu, progress_bar):
|
|
|
|
|
# layers = Gimp.Image.get_selected_layers(image)
|
|
|
|
|
# Gimp.get_pdb().run_procedure('gimp-message', [GObject.Value(GObject.TYPE_STRING, "Error")])
|
|
|
|
|
# Save inference parameters and layers
|
|
|
|
|
config_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "..", "tools")
|
|
|
|
|
with open(os.path.join(config_path, 'gimp_ml_config.pkl'), 'rb') as file:
|
|
|
|
|
data_output = pickle.load(file)
|
|
|
|
@ -73,10 +97,10 @@ def coloring(procedure, image, n_drawables, drawables, force_cpu, progress_bar):
|
|
|
|
|
])
|
|
|
|
|
|
|
|
|
|
with open(os.path.join(weight_path, '..', 'gimp_ml_run.pkl'), 'wb') as file:
|
|
|
|
|
pickle.dump({"force_cpu": bool(force_cpu)}, file)
|
|
|
|
|
pickle.dump({"force_cpu": bool(force_cpu), "n_drawables": n_drawables}, file)
|
|
|
|
|
|
|
|
|
|
# Run inference
|
|
|
|
|
subprocess.call([python_path, plugin_path])
|
|
|
|
|
|
|
|
|
|
result = Gimp.file_load(Gimp.RunMode.NONINTERACTIVE,
|
|
|
|
|
Gio.file_new_for_path(os.path.join(weight_path, '..', 'cache.png')))
|
|
|
|
|
result_layer = result.get_active_layer()
|
|
|
|
@ -84,42 +108,45 @@ def coloring(procedure, image, n_drawables, drawables, force_cpu, progress_bar):
|
|
|
|
|
copy.set_name("Coloring")
|
|
|
|
|
copy.set_mode(Gimp.LayerMode.NORMAL_LEGACY) # DIFFERENCE_LEGACY
|
|
|
|
|
image.insert_layer(copy, None, -1)
|
|
|
|
|
|
|
|
|
|
image.undo_group_end()
|
|
|
|
|
Gimp.context_pop()
|
|
|
|
|
|
|
|
|
|
# Remove temporary layers that were saved
|
|
|
|
|
my_dir = os.path.join(weight_path, '..')
|
|
|
|
|
for f_name in os.listdir(my_dir):
|
|
|
|
|
if f_name.startswith("cache"):
|
|
|
|
|
os.remove(os.path.join(my_dir, f_name))
|
|
|
|
|
|
|
|
|
|
return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def run(procedure, run_mode, image, n_drawables, layer, args, data):
|
|
|
|
|
# gio_file = args.index(0)
|
|
|
|
|
# bucket_size = args.index(0)
|
|
|
|
|
force_cpu = args.index(1)
|
|
|
|
|
# output_format = args.index(2)
|
|
|
|
|
|
|
|
|
|
progress_bar = None
|
|
|
|
|
config = None
|
|
|
|
|
|
|
|
|
|
if run_mode == Gimp.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("force_cpu", force_cpu)
|
|
|
|
|
# config.set_property("output_format", output_format)
|
|
|
|
|
config.begin_run(image, run_mode, args)
|
|
|
|
|
|
|
|
|
|
GimpUi.init("coloring.py")
|
|
|
|
|
use_header_bar = Gtk.Settings.get_default().get_property("gtk-dialogs-use-header")
|
|
|
|
|
dialog = GimpUi.Dialog(use_header_bar=use_header_bar,
|
|
|
|
|
title=_("Coloring..."))
|
|
|
|
|
|
|
|
|
|
# Check number of selected layers
|
|
|
|
|
if n_drawables > 2:
|
|
|
|
|
show_dialog("Please select only greyscale image and color mask layer.", "Error !", "error")
|
|
|
|
|
return procedure.new_return_values(Gimp.PDBStatusType.CANCEL, GLib.Error())
|
|
|
|
|
elif n_drawables == 1:
|
|
|
|
|
n_drawables_text = _("| No Color Mask Selected")
|
|
|
|
|
elif n_drawables == 2:
|
|
|
|
|
n_drawables_text = _("| Color Mask Selected")
|
|
|
|
|
|
|
|
|
|
dialog = GimpUi.Dialog(use_header_bar=use_header_bar, title=_("Coloring..."))
|
|
|
|
|
dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL)
|
|
|
|
|
dialog.add_button("_OK", Gtk.ResponseType.OK)
|
|
|
|
|
dialog.add_button("_Help", Gtk.ResponseType.APPLY)
|
|
|
|
|
dialog.add_button("_Color Palette", Gtk.ResponseType.YES)
|
|
|
|
|
dialog.add_button("_Run Inference", Gtk.ResponseType.OK)
|
|
|
|
|
|
|
|
|
|
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL,
|
|
|
|
|
homogeneous=False, spacing=10)
|
|
|
|
|
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, homogeneous=False, spacing=10)
|
|
|
|
|
dialog.get_content_area().add(vbox)
|
|
|
|
|
vbox.show()
|
|
|
|
|
|
|
|
|
@ -132,84 +159,78 @@ def run(procedure, run_mode, image, n_drawables, layer, args, data):
|
|
|
|
|
vbox.add(grid)
|
|
|
|
|
grid.show()
|
|
|
|
|
|
|
|
|
|
# # Bucket size parameter
|
|
|
|
|
# label = Gtk.Label.new_with_mnemonic(_("_Bucket Size"))
|
|
|
|
|
# grid.attach(label, 0, 1, 1, 1)
|
|
|
|
|
# label.show()
|
|
|
|
|
# spin = GimpUi.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()
|
|
|
|
|
# Show Logo
|
|
|
|
|
logo = Gtk.Image.new_from_file(image_paths["logo"])
|
|
|
|
|
# grid.attach(logo, 0, 0, 1, 1)
|
|
|
|
|
vbox.pack_start(logo, False, False, 1)
|
|
|
|
|
logo.show()
|
|
|
|
|
|
|
|
|
|
# Show License
|
|
|
|
|
license_text = _("PLUGIN LICENSE : MIT")
|
|
|
|
|
label = Gtk.Label(label=license_text)
|
|
|
|
|
# grid.attach(label, 1, 1, 1, 1)
|
|
|
|
|
vbox.pack_start(label, False, False, 1)
|
|
|
|
|
label.show()
|
|
|
|
|
|
|
|
|
|
# Force CPU parameter
|
|
|
|
|
spin = GimpUi.prop_check_button_new(config, "force_cpu", _("Force _CPU"))
|
|
|
|
|
spin.set_tooltip_text(_("If checked, CPU is used for model inference."
|
|
|
|
|
" Otherwise, GPU will be used if available."))
|
|
|
|
|
grid.attach(spin, 1, 2, 1, 1)
|
|
|
|
|
grid.attach(spin, 0, 0, 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 = GimpUi.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()
|
|
|
|
|
# Show n_drawables text
|
|
|
|
|
label = Gtk.Label(label=n_drawables_text)
|
|
|
|
|
grid.attach(label, 1, 0, 1, 1)
|
|
|
|
|
# vbox.pack_start(label, False, False, 1)
|
|
|
|
|
label.show()
|
|
|
|
|
|
|
|
|
|
progress_bar = Gtk.ProgressBar()
|
|
|
|
|
vbox.add(progress_bar)
|
|
|
|
|
progress_bar.show()
|
|
|
|
|
|
|
|
|
|
dialog.show()
|
|
|
|
|
if dialog.run() != Gtk.ResponseType.OK:
|
|
|
|
|
return procedure.new_return_values(Gimp.PDBStatusType.CANCEL,
|
|
|
|
|
GLib.Error())
|
|
|
|
|
|
|
|
|
|
result = coloring(procedure, image, n_drawables, layer, force_cpu, progress_bar)
|
|
|
|
|
|
|
|
|
|
# If the execution was successful, save parameters so they will be restored next time we show dialog.
|
|
|
|
|
if result.index(0) == Gimp.PDBStatusType.SUCCESS and config is not None:
|
|
|
|
|
config.end_run(Gimp.PDBStatusType.SUCCESS)
|
|
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
while True:
|
|
|
|
|
response = dialog.run()
|
|
|
|
|
if response == Gtk.ResponseType.OK:
|
|
|
|
|
result = coloring(procedure, image, n_drawables, layer, force_cpu, progress_bar)
|
|
|
|
|
# If the execution was successful, save parameters so they will be restored next time we show dialog.
|
|
|
|
|
if result.index(0) == Gimp.PDBStatusType.SUCCESS and config is not None:
|
|
|
|
|
config.end_run(Gimp.PDBStatusType.SUCCESS)
|
|
|
|
|
return result
|
|
|
|
|
elif response == Gtk.ResponseType.APPLY:
|
|
|
|
|
url = "https://github.com/kritiksoman/GIMP-ML/blob/GIMP3-ML/docs/MANUAL.md"
|
|
|
|
|
Gio.app_info_launch_default_for_uri(url, None)
|
|
|
|
|
continue
|
|
|
|
|
elif response == Gtk.ResponseType.YES:
|
|
|
|
|
image_new = Gimp.Image.new(1200, 675, 0) # 0 for RGB
|
|
|
|
|
display = Gimp.Display.new(image_new)
|
|
|
|
|
result = Gimp.file_load(Gimp.RunMode.NONINTERACTIVE, Gio.file_new_for_path(image_paths["colorpalette"]))
|
|
|
|
|
result_layer = result.get_active_layer()
|
|
|
|
|
copy = Gimp.Layer.new_from_drawable(result_layer, image_new)
|
|
|
|
|
copy.set_name("Color Palette")
|
|
|
|
|
copy.set_mode(Gimp.LayerMode.NORMAL_LEGACY) # DIFFERENCE_LEGACY
|
|
|
|
|
image_new.insert_layer(copy, None, -1)
|
|
|
|
|
Gimp.displays_flush()
|
|
|
|
|
continue
|
|
|
|
|
else:
|
|
|
|
|
dialog.destroy()
|
|
|
|
|
return procedure.new_return_values(Gimp.PDBStatusType.CANCEL, GLib.Error())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Coloring(Gimp.PlugIn):
|
|
|
|
|
## Parameters ##
|
|
|
|
|
# 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.
|
|
|
|
|
# # Gimp.ConfigPath,
|
|
|
|
|
# _("Histogram _File"),
|
|
|
|
|
# _("Histogram _File"),
|
|
|
|
|
# "coloring.csv",
|
|
|
|
|
# # Gimp.ConfigPathType.FILE,
|
|
|
|
|
# GObject.ParamFlags.READWRITE),
|
|
|
|
|
# "file": (Gio.File,
|
|
|
|
|
# _("Histogram _File"),
|
|
|
|
|
# "Histogram export file",
|
|
|
|
|
# GObject.ParamFlags.READWRITE),
|
|
|
|
|
# "bucket_size": (float,
|
|
|
|
|
# _("_Bucket Size"),
|
|
|
|
|
# "Bucket Size",
|
|
|
|
|
# 0.001, 1.0, 0.01,
|
|
|
|
|
# GObject.ParamFlags.READWRITE),
|
|
|
|
|
"force_cpu": (bool,
|
|
|
|
|
_("Force _CPU"),
|
|
|
|
|
"Force CPU",
|
|
|
|
|
False,
|
|
|
|
|
GObject.ParamFlags.READWRITE),
|
|
|
|
|
# "output_format": (str,
|
|
|
|
|
# _("Output format"),
|
|
|
|
|
# "Output format: 'pixel count', 'normalized', 'percent'",
|
|
|
|
|
# "pixel count",
|
|
|
|
|
# GObject.ParamFlags.READWRITE),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
## GimpPlugIn virtual methods ##
|
|
|
|
|
# GimpPlugIn virtual methods #
|
|
|
|
|
def do_query_procedures(self):
|
|
|
|
|
self.set_translation_domain("gimp30-python",
|
|
|
|
|
Gio.file_new_for_path(Gimp.locale_directory()))
|
|
|
|
|
self.set_translation_domain("gimp30-python", Gio.file_new_for_path(Gimp.locale_directory()))
|
|
|
|
|
return ['coloring']
|
|
|
|
|
|
|
|
|
|
def do_create_procedure(self, name):
|
|
|
|
@ -228,12 +249,7 @@ class Coloring(Gimp.PlugIn):
|
|
|
|
|
"GIMP-ML",
|
|
|
|
|
"2021")
|
|
|
|
|
procedure.add_menu_path("<Image>/Layer/GIMP-ML/")
|
|
|
|
|
|
|
|
|
|
# procedure.add_argument_from_property(self, "file")
|
|
|
|
|
# procedure.add_argument_from_property(self, "bucket_size")
|
|
|
|
|
procedure.add_argument_from_property(self, "force_cpu")
|
|
|
|
|
# procedure.add_argument_from_property(self, "output_format")
|
|
|
|
|
|
|
|
|
|
return procedure
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|