package main import ( "image/color" "math/rand" ) var bwpallette = color.Palette{ color.Black, color.White, } var sixteencolors = color.Palette{ color.RGBA{0, 0, 0, 255}, // black color.RGBA{0, 0, 127, 255}, // navy color.RGBA{0, 0, 255, 255}, // blue color.RGBA{0, 127, 0, 255}, // green color.RGBA{0, 255, 0, 255}, // lime color.RGBA{127, 0, 0, 255}, // maroon color.RGBA{255, 0, 0, 255}, // red color.RGBA{0, 127, 127, 255}, // teal color.RGBA{127, 0, 127, 255}, // purple color.RGBA{127, 127, 0, 255}, // olive color.RGBA{0, 255, 255, 255}, // aqua color.RGBA{255, 0, 255, 255}, // fuchsia color.RGBA{255, 255, 0, 255}, // yellow color.RGBA{127, 127, 127, 255}, // gray color.RGBA{192, 192, 192, 255}, // silver color.RGBA{255, 255, 255, 255}, // white } func permuteColor(c color.Color, i uint8) color.Color { r, g, b, a := c.RGBA() return color.RGBA{ uint8(r>>8) + i, uint8(g>>8) + i, uint8(b>>8) + i, uint8(a >> 8), } } // naivePalette smashes each pixel to its closest color in the pallette. func naivePalette(p color.Palette) quantizerFunction { return func(_, _ int, c color.Color) color.Color { return p[p.Index(c)] } } // randomNoisePalette injects random noise into the quantization step func randomNoisePalette(p color.Palette) quantizerFunction { return func(_, _ int, c color.Color) color.Color { // the randomization here is tuned for the sixteen-color palette for now. // I think the proper theory here is probably "only try and randomize within one palette swatch in either direction". // it might be possible to instead permute the color selected _from the palette_ (i.e. modify the result of p.Index(c))... // ...but I think for that to work you'd need a proper "ordering" for the colors. noise := rand.Intn(64) - 32 if noise < 0 { noise = 0 } rc := permuteColor(c, uint8(noise)) return p[p.Index(rc)] } } // color permutation algo: https://en.wikipedia.org/wiki/Ordered_dithering#Algorithm func colorBayer(level int, p color.Palette) quantizerFunction { b := newBayer(level) r := len(p) return func(x, y int, c color.Color) color.Color { v := float64(r) * (b.valueAt(x, y) - 0.5) rc := permuteColor(c, uint8(v)) return p[p.Index(rc)] } }