package dithering import ( "image" "image/color" ) type grid struct { color.Gray } func (_ grid) ColorModel() color.Model { return color.RGBAModel } func (_ grid) Bounds() image.Rectangle { return image.Rect(0, 0, 8, 8) } func (g grid) At(x, y int) color.Color { n := g.Gray.Y / 4 if n == 0 { return color.Black } step := int(64 / n) if (y*8+x)%step == 0 { return color.White } return color.Black } type uniformGrid struct { image.Image } func (g uniformGrid) ColorModel() color.Model { return g.Image.ColorModel() } func (g uniformGrid) Bounds() image.Rectangle { // just need to return something return g.Image.Bounds() } func (g uniformGrid) At(x, y int) color.Color { dx, dy := g.Image.Bounds().Dx(), g.Image.Bounds().Dy() return g.Image.At(x%dx, y%dy) } type Dithering struct { image.Image } func (d Dithering) ColorModel() color.Model { return color.GrayModel } func (d Dithering) Bounds() image.Rectangle { return d.Image.Bounds() } func (d Dithering) At(x, y int) color.Color { c := color.GrayModel.Convert(d.Image.At(x, y)) return uniformGrid{grid{c.(color.Gray)}}. At(x, y) }