Krita Palette Sorter

My comic has a limited palette, roughly inspired by the copic warm gray set.

Roughly inspired though means there are a lot of values missing, and a lot of tweaking to fill it in. I've been making use of Krita's lovely blending eyedropper to get the intermediary colors, and then have them set to automatically be added to this palette.

As you can imagine though, this makes a huge mess of my palette. But turns out Krita's .kpl format is just a zip file, with a colorset.xml to specify the order of the colors. I wrote a little script to dedup the colors and sort by value. You might find it useful to sort by something else, in which case this code is probably a good place to start.

import sys
import xml.etree.ElementTree as ET
import zipfile

def get_hsv(entry):
    rgb = entry[0]
    r, g, b = (float(rgb.get(x)) for x in ['r', 'g', 'b'])
    h, s, v = colorsys.rgb_to_hsv(r, g, b)
    return h, s, v

def sort_colorset(xmlf):
    tree = ET.parse(xmlf)
    root = tree.getroot()
    columns = 8 if len(sys.argv) < 4 else int(sys.argv[3])
    by_value = sorted(root, key=lambda x: get_hsv(x)[2])
    existing_colors = set()

    for entry in by_value:
        position = entry[1]
        hsv = get_hsv(entry)
        if (hsv in existing_colors):
            root.remove(entry)
            continue
        idx = len(existing_colors)
        position.set('column', str(idx % columns))
        position.set('row', str(idx // columns))
        existing_colors.add(hsv)
    return tree

def main():
    if len(sys.argv) < 3:
        print('usage: sort.py in.kpl out.kpl [num_cols]')
        return
    srcfile = sys.argv[1]
    dstfile = sys.argv[2]
    with zipfile.ZipFile(srcfile) as inzip, zipfile.ZipFile(dstfile, "w") as outzip:
        for inzipinfo in inzip.infolist():
            with inzip.open(inzipinfo) as infile:
                if inzipinfo.filename == "colorset.xml":
                    with outzip.open(inzipinfo.filename, mode='w') as outfile:
                        sort_colorset(infile).write(outfile)
                else:
                    outzip.writestr(inzipinfo.filename, infile.read())

main()
code art_tools