Download raw (3.1 KB)
#!/usr/bin/env python # -*- coding: utf-8 -*- from PIL import Image, ImagePalette import re def color (color): if type(color) is str: m = re.match(r'(\d+),\s*(\d+),\s*(\d+)', color) if m: return (int(m.group(1)), int(m.group(2)), int(m.group(3))) else: return (0,0,0) else: return color def alpha_dither (file_in, file_out, threshold=125, color=(0,0,0,255), scale=1, postscale=1, colormap=None): im = Image.open(file_in).convert('L') im = im.resize((int(im.size[0]*scale), int(im.size[1]*scale)), resample=Image.BICUBIC) if colormap: im_out = Image.open(colormap).resize((im.size[0], im.size[1]), resample=Image.BICUBIC).convert('RGBA') else: im_out = Image.new(mode='RGBA', size=(im.size[0], im.size[1]), color=color) px_in = im.load() px_out = im_out.load() neighbours = ((1,0), (2,0), (-1,1), (0,1), (1,1), (0,2)) for y in range(im.size[1]): for x in range(im.size[0]): old = px_in[x, y] new = 255 if old > threshold else 0 err = (old - new) >> 3 if new == 255: px_out[x,y] = (color[0], color[1], color[2], 0) for c in neighbours: try: px_in[x+c[0], y+c[1]] += err except IndexError: pass if postscale > 1: im_out = im_out.resize((im_out.size[0]*postscale, im_out.size[1]*postscale), resample=Image.NEAREST) im_out.save(file_out) if __name__ == '__main__': #dither('assets/images/dave.png', 'assets/images/dave-dithered.png', 80, (255,255,0), (255,255,255)) import argparse parser = argparse.ArgumentParser() parser.add_argument('-o', '--output', dest='output', help="Destination of the dithered image. If none is given the original image is over-written", default=None) parser.add_argument('-c', '--color', dest='color', default=(0,0,0), type=color, help="Color to dither the image.\n\nIn the format of a comma-separated list \d+,\d+,\d+ Defaults to black ( 0,0,0 ).") parser.add_argument('-t', '--threshold', dest='threshold', default=128, type=int, help="Threshold after which a pixel is either turned on or of.") parser.add_argument('-s', '--scale', dest='scale', default=1.0, type=float, help="Sets the amount the source-image is scaled before dithering") parser.add_argument('-ps', '--post-scale', dest='postscale', default=1, type=int, help="Sets the amount of scaling performed after the dithering. Given in integers. Uses neirest neighbour for the scaling") parser.add_argument('-cm', '--color-map', dest='colormap', default=None, type=str, help="Take colors from given image to color the the dithering pixels") parser.add_argument('source', help="The location of the image to dither.") args = parser.parse_args() alpha_dither(args.source, args.output if args.output <> None else args.source, threshold=args.threshold, color=args.color, scale=args.scale, postscale=args.postscale, colormap=args.colormap)