Pull dithering into a function
@@ -117,21 +117,53 @@ def dither(
p = cutoff
choosecode = [x[0] * p + x[1] * (1.0 - p) for x in choosecode]
- def iterdither():
+ dithered_rows = run_dither(incode, choosecode, outcode, width, pixels)
+
+ info["bitdepth"] = bitdepth
+ info["gamma"] = 1.0 / targetdecode
+ w = png.Writer(**info)
+ w.write(out, dithered_rows)
+
+
+def build_decode_table(maxval, gamma):
+ """Build a lookup table for decoding;
+ table converts from pixel values to linear space.
+ """
+
+ assert maxval == int(maxval)
+ assert maxval > 0
+
+ f = 1.0 / maxval
+ table = [f * v for v in range(maxval + 1)]
+ if gamma != 1.0:
+ table = [v ** gamma for v in table]
+ return table
+
+
+def run_dither(incode, choosecode, outcode, width, rows):
+ """
+ Run an serpentine dither.
+ Using the incode and choosecode tables.
+ """
+
# Errors diffused downwards (into next row)
ed = [0.0] * width
flipped = False
- for row in pixels:
+ for row in rows:
+ # Convert to linear...
row = [incode[v] for v in row]
+ # Add errors...
row = [e + v for e, v in zip(ed, row)]
+
if flipped:
row = row[::-1]
targetrow = [0] * width
+
for i, v in enumerate(row):
# `it` will be the index of the chosen target colour;
it = bisect_left(choosecode, v)
- t = outcode[it]
targetrow[i] = it
+ t = outcode[it]
# err is the error that needs distributing.
err = v - t
@@ -146,32 +178,13 @@ def dither(
ed[i] = ef
if i:
ed[i - 1] += ef
+
if flipped:
ed = ed[::-1]
targetrow = targetrow[::-1]
yield targetrow
flipped = not flipped
- info["bitdepth"] = bitdepth
- info["gamma"] = 1.0 / targetdecode
- w = png.Writer(**info)
- w.write(out, iterdither())
-
-
-def build_decode_table(maxval, gamma):
- """Build a lookup table for decoding;
- table converts from pixel values to linear space.
- """
-
- assert maxval == int(maxval)
- assert maxval > 0
-
- f = 1.0 / maxval
- table = [f * v for v in range(maxval + 1)]
- if gamma != 1.0:
- table = [v ** gamma for v in table]
- return table
-
def main(argv=None):
import sys
