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

This commit is contained in:
Niles Rogoff 2016-07-11 11:15:59 -04:00
parent 246635ba26
commit 78466698fc
3 changed files with 43 additions and 22 deletions

25
2bit.py
View File

@ -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)

View File

@ -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

View File

@ -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