#### 94 lines 2.4 KiB Python Raw Permalink Blame History

 ```"""Error diffusion dither patterns.""" ``` ``` ``` ```import numpy as np ``` ``` ``` ``` ``` ```class DitherPattern: ``` ``` PATTERN = None ``` ``` ORIGIN = None ``` ``` ``` ``` def __init__(self, error_fraction=1.0): ``` ``` self.PATTERN *= error_fraction ``` ``` ``` ``` ``` ```class NoDither(DitherPattern): ``` ``` """No dithering.""" ``` ``` PATTERN = np.array(((0, 0), (0, 0)), ``` ``` dtype=np.float32).reshape(2, 2) / np.float32(16) ``` ``` ORIGIN = (0, 1) ``` ``` ``` ``` ``` ```class FloydSteinbergDither(DitherPattern): ``` ``` """Floyd-Steinberg dither.""" ``` ``` # 0 * 7 ``` ``` # 3 5 1 ``` ``` PATTERN = np.array(((0, 0, 7), (3, 5, 1)), ``` ``` dtype=np.float32).reshape(2, 3) / np.float32(16) ``` ``` ORIGIN = (0, 1) ``` ``` ``` ``` ``` ```class FloydSteinbergDither2(DitherPattern): ``` ``` """Floyd-Steinberg dither.""" ``` ``` # 0 * 7 ``` ``` # 3 5 1 ``` ``` PATTERN = np.array( ``` ``` ((0, 0, 0, 0, 0, 7), ``` ``` (3, 5, 1, 0, 0, 0)), ``` ``` dtype=np.float32).reshape(2, 6) / np.float32(16) ``` ``` ORIGIN = (0, 2) ``` ``` ``` ``` ``` ```class BuckelsDither(DitherPattern): ``` ``` """Default dither from bmp2dhr.""" ``` ``` # 0 * 2 1 ``` ``` # 1 2 1 0 ``` ``` # 0 1 0 0 ``` ``` PATTERN = np.array(((0, 0, 2, 1), (1, 2, 1, 0), (0, 1, 0, 0)), ``` ``` dtype=np.float32).reshape(3, 4) / np.float32(8) ``` ``` ORIGIN = (0, 1) ``` ``` ``` ``` ``` ```class JarvisDither(DitherPattern): ``` ``` """Jarvis-Judice-Ninke dithering.""" ``` ``` ``` ``` # 0 0 X 7 5 ``` ``` # 3 5 7 5 3 ``` ``` # 1 3 5 3 1 ``` ``` PATTERN = np.array(((0, 0, 0, 7, 5), (3, 5, 7, 5, 3), (1, 3, 5, 3, 1)), ``` ``` dtype=np.float32).reshape(3, 5) / np.float32(48) ``` ``` ORIGIN = (0, 2) ``` ``` ``` ``` ``` ```class JarvisModifiedDither(DitherPattern): ``` ``` """Jarvis dithering, modified to diffuse errors to 4 forward x positions. ``` ``` ``` ``` This works well for double hi-res dithering, since the "best" colour ``` ``` match to a given pixel may only be accessible up to 4 x-positions further ``` ``` on. Standard Jarvis dithering only propagates errors for 2 x-positions ``` ``` in the forward direction, which means that errors may have diffused away ``` ``` before we get to the pixel that can best take advantage of it. ``` ``` """ ``` ``` ``` ``` # 0 0 X 7 5 ``` ``` # 3 5 7 5 3 ``` ``` # 1 3 5 3 1 ``` ``` PATTERN = np.array(( ``` ``` (0, 0, 0, 15, 11, 7, 3), ``` ``` (3, 5, 7, 5, 3, 1, 0), ``` ``` (1, 3, 5, 3, 1, 0, 0)), dtype=np.float32).reshape(3, 7) ``` ``` PATTERN /= np.sum(PATTERN) ``` ``` ORIGIN = (0, 2) ``` ``` ``` ``` ``` ```PATTERNS = { ``` ``` 'floyd': FloydSteinbergDither, ``` ``` 'floyd2': FloydSteinbergDither2, ``` ``` 'floyd-steinberg': FloydSteinbergDither, ``` ``` 'buckels': BuckelsDither, ``` ``` 'jarvis': JarvisDither, ``` ``` 'jarvis-mod': JarvisModifiedDither, ``` ``` 'none': NoDither, ``` ```} ``` ``` ``` ```DEFAULT_PATTERN = 'floyd' ```