@@ -0,0 +1,1558 @@
+from operator import itemgetter%0A%0Afrom .. import Color%0A%0A%0Adef diff_rgb(a, b):%0A    return %5Bch_b - ch_a for ch_a, ch_b in zip(a, b)%5D%0A%0A%0Adef add_rgb(a, b):%0A    return %5Bch_b + ch_a for ch_a, ch_b in zip(a, b)%5D%0A%0A%0Adef manhattan_distance(a, b):%0A    return sum(abs(b_el - a_el) for a_el, b_el in zip(a, b))%0A%0A%0Adef closest(want_rgb, *available_rgb):%0A    # This is about the slowest approach imaginable for this%0A    distances = %5B(manhattan_distance(want_rgb, this_rgb), this_rgb)%0A                 for this_rgb in available_rgb%5D%0A    distances.sort(key=itemgetter(0))%0A    return distances%5B0%5D%5B1%5D%0A%0A%0Adef dithered_gradient(start_color, end_color, count):%0A    %22%22%22%0A    Make a dithering sequence which simulates a gradient between two colors%0A    across %60%60count%60%60 threads. Returns a list of length %60%60count%60%60 where each%0A    element is the color to be used for the corresponding thread.%0A    %22%22%22%0A    inc_rgb = %5Bfloat(ch2 - ch1) for ch1, ch2 in%0A               zip(start_color.rgb, end_color.rgb)%5D%0A    error_rgb = 0.0, 0.0, 0.0%0A    threads = %5B%5D%0A    for ii in range(count):%0A        dist = (ii + 0.5) / count%0A        ideal_rgb = %5B(inc_ch * dist) + start_ch for inc_ch, start_ch in%0A                     zip(inc_rgb, start_color.rgb)%5D%0A        with_error_rgb = %5Bideal_ch + error_ch%0A                          for ideal_ch, error_ch in%0A                          zip(ideal_rgb, error_rgb)%5D%0A        this_rgb = closest(with_error_rgb, start_color.rgb, end_color.rgb)%0A        threads.append(Color(this_rgb))%0A        error_rgb = add_rgb(error_rgb, diff_rgb(this_rgb, ideal_rgb))%0A%0A    return threads%0A

Add a basic linear dithered gradient generator