59 lines
1.3 KiB
Go
59 lines
1.3 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"image"
|
|
"image/color"
|
|
)
|
|
|
|
var errOutOfBounds error = errors.New("downscale: out of bounds")
|
|
|
|
type Downscaled struct {
|
|
image.Image
|
|
Factor int
|
|
}
|
|
|
|
func isOutOfBounds(pt image.Point, img image.Image) bool {
|
|
x, y := img.Bounds().Dx(), img.Bounds().Dy()
|
|
if pt.X > x || pt.Y > y {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func meanColor(palette color.Palette) color.Color {
|
|
var r, g, b int
|
|
for _, v := range palette {
|
|
c := color.RGBAModel.Convert(v).(color.RGBA)
|
|
r += int(c.R)
|
|
g += int(c.G)
|
|
b += int(c.B)
|
|
}
|
|
r, g, b = r/len(palette), g/len(palette), b/len(palette)
|
|
return color.RGBA{uint8(r), uint8(g), uint8(b), 0xff}
|
|
}
|
|
|
|
func (d Downscaled) ColorModel() color.Model { return d.Image.ColorModel() }
|
|
func (d Downscaled) Bounds() image.Rectangle {
|
|
return image.Rect(0, 0, d.Image.Bounds().Dx()/d.Factor, d.Image.Bounds().Dy()/d.Factor)
|
|
}
|
|
func (d Downscaled) At(x, y int) color.Color {
|
|
palette := color.Palette{}
|
|
pt := image.Point{x * d.Factor, y * d.Factor}
|
|
if isOutOfBounds(pt, d.Image) {
|
|
panic(errOutOfBounds)
|
|
}
|
|
for i := 0; i < d.Factor; i++ {
|
|
for j := 0; j < d.Factor; j++ {
|
|
currentPt := image.Point{pt.X + i, pt.Y + j}
|
|
if i > 0 || j > 0 {
|
|
if isOutOfBounds(currentPt, d.Image) {
|
|
continue
|
|
}
|
|
}
|
|
palette = append(palette, d.Image.At(currentPt.X, currentPt.Y))
|
|
}
|
|
}
|
|
return palette.Convert(meanColor(palette))
|
|
}
|