1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/dither.py Fri Oct 02 19:22:17 2015 +0200
1.3 @@ -0,0 +1,24 @@
1.4 +#!/usr/bin/env python
1.5 +
1.6 +import PIL.Image
1.7 +import sys
1.8 +
1.9 +def get_palette():
1.10 + l = []
1.11 + for i in range(0, 8):
1.12 + r = ((i / 4) % 2) * 255; g = ((i / 2) % 2) * 255; b = (i % 2) * 255
1.13 + for j in range(0, 32):
1.14 + l.extend((r, g, b))
1.15 +
1.16 + imp = PIL.Image.new("P", (1, 1))
1.17 + imp.putpalette(l)
1.18 + return imp
1.19 +
1.20 +def dither(im, imp=None):
1.21 + return im.quantize(palette=imp or get_palette())
1.22 +
1.23 +im = PIL.Image.open(sys.argv[1])
1.24 +im2 = dither(im)
1.25 +im2.save(sys.argv[2])
1.26 +
1.27 +# vim: tabstop=4 expandtab shiftwidth=4
2.1 --- a/optimiser.py Fri Oct 02 13:37:29 2015 +0200
2.2 +++ b/optimiser.py Fri Oct 02 19:22:17 2015 +0200
2.3 @@ -1,9 +1,11 @@
2.4 #!/usr/bin/env python
2.5
2.6 +from dither import dither
2.7 from random import random
2.8 -from os.path import extsep, splitext
2.9 +from os.path import splitext
2.10 import EXIF
2.11 import PIL.Image
2.12 +import itertools
2.13 import math
2.14 import sys
2.15
2.16 @@ -17,10 +19,10 @@
2.17 r2, g2, b2 = rgb2
2.18 return math.sqrt(pow(r1 - r2, 2) + pow(g1 - g2, 2) + pow(b1 - b2, 2))
2.19
2.20 -def distribution(rgb, points):
2.21 +def distribution(rgb, values=None):
2.22 l = []
2.23 total = 0
2.24 - for c in points:
2.25 + for c in values or corners:
2.26 d = distance(rgb, c)
2.27 if d == 0:
2.28 return [(1, c)]
2.29 @@ -51,6 +53,22 @@
2.30 def saturate_value(x, exp):
2.31 return int(127.5 + sign(x - 127.5) * 127.5 * pow(abs(x - 127.5) / 127.5, exp))
2.32
2.33 +def get_best(im, width, y, colours):
2.34 + best = 0
2.35 + best_values = None
2.36 +
2.37 + for values in itertools.combinations([value for n, value in colours], 4):
2.38 + current = 0
2.39 + for x in range(0, width):
2.40 + rgb = im.getpixel((x, y))
2.41 + for f, value in distribution(rgb, values):
2.42 + current += f
2.43 + if current >= best:
2.44 + best_values = values
2.45 + best = current
2.46 +
2.47 + return best_values
2.48 +
2.49 def test():
2.50 size = 512
2.51 for r in (0, 63, 127, 191, 255):
2.52 @@ -94,21 +112,23 @@
2.53
2.54 input_filename, output_filename = sys.argv[1:3]
2.55 basename, ext = splitext(output_filename)
2.56 - preview_filename = extsep.join([basename + "_preview", ext])
2.57
2.58 - preview = "-p" in sys.argv[3:]
2.59 rotate = "-r" in sys.argv[3:]
2.60 saturate = sys.argv[3:].count("-s")
2.61 desaturate = sys.argv[3:].count("-d")
2.62 + best = "-b" in sys.argv[3:]
2.63 + dithering = "-d" in sys.argv[3:]
2.64
2.65 x = EXIF.process_file(open(input_filename))
2.66 im = PIL.Image.open(input_filename).convert("RGB")
2.67 im = rotate_and_scale(im, width, height, rotate)
2.68
2.69 - if preview:
2.70 - im_preview = im.copy()
2.71 + width, height = im.size
2.72
2.73 - width, height = im.size
2.74 + im_original = im
2.75 +
2.76 + if dithering:
2.77 + im = dither(im).convert("RGB")
2.78
2.79 colours = []
2.80
2.81 @@ -123,28 +143,25 @@
2.82 rgb = saturate_rgb(rgb, saturate and math.pow(0.5, saturate) or math.pow(2, desaturate))
2.83 im.putpixel((x, y), rgb)
2.84
2.85 - # Count the number of requested colours.
2.86 + # Sum the colour probabilities.
2.87
2.88 - value = get_value(rgb)
2.89 - if not c.has_key(value):
2.90 - c[value] = 1
2.91 - else:
2.92 - c[value] += 1
2.93 -
2.94 - if preview:
2.95 - im_preview.putpixel((x, y), value)
2.96 + for f, value in distribution(rgb):
2.97 + if not c.has_key(value):
2.98 + c[value] = f
2.99 + else:
2.100 + c[value] += f
2.101
2.102 c = [(n, value) for value, n in c.items()]
2.103 c.sort(reverse=True)
2.104 colours.append(c)
2.105
2.106 - if preview:
2.107 - im_preview.save(preview_filename)
2.108 -
2.109 for y, c in enumerate(colours):
2.110 most = [value for n, value in c[:4]]
2.111 least = [value for n, value in c[4:]]
2.112
2.113 + if least and best:
2.114 + most = get_best(im_original, width, y, c)
2.115 +
2.116 for x in range(0, width):
2.117 rgb = im.getpixel((x, y))
2.118
2.119 @@ -153,7 +170,9 @@
2.120
2.121 value = get_value(rgb)
2.122 if value in least:
2.123 + rgb = im_original.getpixel((x, y))
2.124 value = get_value(rgb, most)
2.125 +
2.126 im.putpixel((x, y), value)
2.127
2.128 im.save(output_filename)