gimp/plug-ins/python/palette-export-as-kpl.py

197 lines
7.6 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Allows exporting Krita's .kpl palettes
#
# 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('GimpUi', '3.0')
from gi.repository import GimpUi
from gi.repository import GObject
from gi.repository import GLib
from gi.repository import Gio
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
import os, sys, tempfile, zipfile
import xml.etree.ElementTree as ET
def N_(message): return message
def _(message): return GLib.dgettext(None, message)
# Taken from file-openraster.py
def write_file_str(zfile, fname, data):
# work around a permission bug in the zipfile library:
# http://bugs.python.org/issue3394
zi = zipfile.ZipInfo(fname)
zi.external_attr = int("100644", 8) << 16
zfile.writestr(zi, data)
def palette_kpl_export(procedure, config, data):
success = True
runmode = config.get_property("run-mode")
if runmode == Gimp.RunMode.INTERACTIVE:
GimpUi.init('python-fu-palette-export-as-kpl')
dialog = GimpUi.ProcedureDialog(procedure=procedure, config=config)
# Fill the dialog.
config.set_property("palette", None)
config.set_property("file", None)
dialog.get_label ("options-label", _("Options"), False, False)
hbox = dialog.fill_box ("options-box", ["comment", "read-only"])
dialog.fill_frame("options-frame", "options-label", False, "options-box")
dialog.fill (["palette", "file", "options-frame"])
dialog.set_ok_label (_("_Export"))
if not dialog.run():
dialog.destroy()
return procedure.new_return_values(Gimp.PDBStatusType.CANCEL, GLib.Error())
palette = config.get_property("palette")
file = config.get_property("file")
comment = config.get_property("comment")
read_only = config.get_property("read-only")
if file is None or file.peek_path() is None:
error = 'No file given'
return procedure.new_return_values(Gimp.PDBStatusType.CALLING_ERROR,
GLib.Error(error))
tempdir = tempfile.mkdtemp('python-fu-palette-export-as-kpl')
kplfile = zipfile.ZipFile(file.peek_path() + '.tmpsave', 'w', compression=zipfile.ZIP_STORED)
write_file_str(kplfile, 'mimetype', 'application/x-krita-palette') # must be the first file written
# Filling in palette
xml_palette = ET.Element('ColorSet')
a = xml_palette.attrib
if comment != "":
a['comment'] = comment
a['name'] = palette.get_name()
a['version'] = "1.0"
a['readonly'] = "true" if read_only == True else "false"
columns = palette.get_columns()
if columns == 0:
columns = 16
a['columns'] = str(columns)
count = palette.get_color_count()
row = 0
col = 0
for i in range(count):
entry = ET.Element('ColorSetEntry')
xml_palette.append(entry)
success, name = palette.get_entry_name(i)
if success:
a = entry.attrib
a['name'] = name
a['id'] = str(i + 1)
# TODO: Add options for different bit-depths
a['bitdepth'] = "F32"
a['spot'] = "false"
color = palette.get_entry_color(i)
# TODO: Allow for other color spaces
pal = ET.Element('RGB')
entry.append(pal)
a = pal.attrib
r, g, b, alpha = color.get_rgba()
a['r'] = str(r)
a['g'] = str(g)
a['b'] = str(b)
pos = ET.Element('Position')
entry.append(pos)
a = pos.attrib
a['row'] = str(row)
a['column'] = str(col)
col += 1
if col >= columns:
col = 0
row += 1
else:
break;
if success:
# Write everything to file
xml = ET.tostring(xml_palette, encoding='UTF-8')
write_file_str(kplfile, 'colorset.xml', xml)
kplfile.close()
os.rmdir(tempdir)
if os.path.exists(file.peek_path()):
os.remove(file.peek_path()) # win32 needs that
os.rename(file.peek_path() + '.tmpsave', file.peek_path())
return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())
else:
kplfile.close()
os.rmdir(tempdir)
return procedure.new_return_values(Gimp.PDBStatusType.EXECUTION_ERROR,
GLib.Error('File exporting failed: {}'.format(file.get_path())))
class PaletteExportAsKPL (Gimp.PlugIn):
## GimpPlugIn virtual methods ##
def do_set_i18n(self, procname):
return True, 'gimp30-python', None
def do_query_procedures(self):
return [ 'python-fu-palette-export-as-kpl' ]
def do_create_procedure(self, name):
procedure = Gimp.Procedure.new(self, name,
Gimp.PDBProcType.PLUGIN,
palette_kpl_export, None)
if name == 'python-fu-palette-export-as-kpl':
procedure.set_documentation (_("Export palette as Krita .kpl"),
_("Export palette as Krita .kpl"),
name)
procedure.set_menu_label(_("_Krita palette..."))
procedure.set_attribution("Alx Sa",
"(c) GPL V3.0 or later",
"2025")
procedure.add_menu_path('<Palettes>/Palettes Menu/Export as')
procedure.add_enum_argument ("run-mode", _("Run mode"),
_("The run mode"), Gimp.RunMode,
Gimp.RunMode.NONINTERACTIVE,
GObject.ParamFlags.READWRITE)
procedure.add_palette_argument ("palette", _("_Palette to export"),
"", True,
None, True, # Default to context.
GObject.ParamFlags.READWRITE)
procedure.add_file_argument ("file", _("_File (.kpl)"), "",
Gimp.FileChooserAction.SAVE,
False, None, GObject.ParamFlags.READWRITE)
procedure.add_string_argument ("comment", _("Commen_t"),
_("Optional comment"), "",
GObject.ParamFlags.READWRITE)
procedure.add_boolean_argument ("read-only",
_("Re_ad only"),
_("The palette will be locked on import"),
False, GObject.ParamFlags.READWRITE)
return procedure
Gimp.main(PaletteExportAsKPL.__gtype__, sys.argv)