From 78466698fc2eface6ae3f087b2ef7f36b774b408 Mon Sep 17 00:00:00 2001 From: Niles Rogoff Date: Mon, 11 Jul 2016 11:15:59 -0400 Subject: [PATCH] Added dithering, added documentation for dithering and bits per color, vastly simplified test suite by abstracting control logic to another function, added tests for dithering, removed debug info --- 2bit.py | 25 ++++++++++++------------- README.md | 4 +++- test/run.py | 36 ++++++++++++++++++++++++++++-------- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/2bit.py b/2bit.py index 015e0ea..b6c7ecb 100644 --- a/2bit.py +++ b/2bit.py @@ -1,18 +1,21 @@ bits = 2 outfile = "out.png" -print_debug = False per_color = False +dither = False # End of the configuration section -import PIL.Image, sys +import PIL.Image, sys, random if len(sys.argv) >= 3: outfile = sys.argv[2] if len(sys.argv) >= 4: bits = int(sys.argv[3]) -per_color = "--per-color" in [f.lower() for f in sys.argv] -def debug(*args): - if print_debug: print(*args) +args = [f.lower() for f in sys.argv] +if "--dither" in args: + dither = float(args[args.index("--dither") + 1].replace("%","")) +if dither > 1: + dither /= 100 +per_color = "--per-color" in args def binprecision(start, bits, length): end = bin(int(start))[2:] while len(end) < bits: @@ -26,25 +29,21 @@ elif bits == 1: mode = "1" # 1x1 bit unsigned integer out = PIL.Image.new(mode,image.size) colors = [int(i*255.0/(2**bits-1)) for i in range(2**bits)] -debug(image.width, image.height) for x in range(image.width): for y in range(image.height): pos = (x,y) color = image.getpixel(pos) - debug(color) if len(color) == 4: color = color[:3] # Exclude alpha layer color = list(color) if not per_color: color = [float(sum(color))/len(color)] - debug(color) - for z in color: debug(bin(int(z))) for z in range(len(color)): + if dither: + color[z] += 255 * random.uniform(-dither,dither) + color[z] = min(color[z], 255) + color[z] = max(color[z], 0) index = int(binprecision(color[z], 8, bits), 2) - debug(index) color[z] = colors[index] out.putpixel(pos, tuple(color)) - debug() - debug("------------") - debug() out.save(outfile) diff --git a/README.md b/README.md index b3cdc6a..36e72d5 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ Inspired by [2bit](http://2bit.neocities.org/) -Usage: `python3 2bit.py infile.png [outfile.png] [bits]` +Usage: `python3 2bit.py infile.png [outfile.png] [bits] [--per-color] [--dither dither_value]` + +dither\_value can be like `50%`, `50` or `.5` Warning: Will probably turn transparency black diff --git a/test/run.py b/test/run.py index 10d3f3e..de57387 100644 --- a/test/run.py +++ b/test/run.py @@ -8,19 +8,39 @@ files = glob.glob("*") del files[files.index("run.py")] if not os.path.isdir("out"): os.mkdir("out") i = 0 -max_i = len(files) * (8+8) +max_i = len(files) * (16*3) + +def getparams(i): + percolor = dither = False + if i % 16 >= 8: + percolor = True + if i >= 16: + dither = '15' + if i >= 32: + dither = '50' + return percolor, dither + for f in files: if (os.path.isdir(f)): continue - for bits in range(8+8): + if (f[-3:]) == '.py': continue + for bits in range(16*3): bits += 1 - percolor = [] - pc = "" - if bits > 8: + percolor, dither = getparams(i) + if not percolor: + percolor = [] + pc = "" + else: percolor = ["--per-color"] - pc = "-per-color" + pc = "per-color-" + if not dither: + dither = [] + dc = "" + else: + dc = "dither-" + dither + "%-" + dither = ["--dither", dither] print(str(int(float(1000*i)/max_i)/10) + "% done") bits_formatted = str((bits-1)%8+1) - outfilename = "out/" + ".".join(f.split(".")[:-1]) + "-output" + pc + "-" + bits_formatted + "bits.png" + outfilename = "out/" + ".".join(f.split(".")[:-1]) + "-output-" + pc + dc + bits_formatted + "bits.png" print("On " + outfilename) - subprocess.call(["python3", "../2bit.py", f, outfilename, bits_formatted, *percolor]) + subprocess.call(["python3", "../2bit.py", f, outfilename, bits_formatted, *percolor, *dither]) i += 1