1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
|
package gift
import (
"image"
"image/draw"
)
type pixelateFilter struct {
size int
}
func (p *pixelateFilter) Bounds(srcBounds image.Rectangle) (dstBounds image.Rectangle) {
dstBounds = image.Rect(0, 0, srcBounds.Dx(), srcBounds.Dy())
return
}
func (p *pixelateFilter) Draw(dst draw.Image, src image.Image, options *Options) {
if options == nil {
options = &defaultOptions
}
blockSize := p.size
if blockSize <= 1 {
copyimage(dst, src, options)
return
}
srcb := src.Bounds()
dstb := dst.Bounds()
numBlocksX := srcb.Dx() / blockSize
if srcb.Dx()%blockSize > 0 {
numBlocksX++
}
numBlocksY := srcb.Dy() / blockSize
if srcb.Dy()%blockSize > 0 {
numBlocksY++
}
pixGetter := newPixelGetter(src)
pixSetter := newPixelSetter(dst)
parallelize(options.Parallelization, 0, numBlocksY, func(start, stop int) {
for by := start; by < stop; by++ {
for bx := 0; bx < numBlocksX; bx++ {
// Calculate the block bounds.
bb := image.Rect(bx*blockSize, by*blockSize, (bx+1)*blockSize, (by+1)*blockSize)
bbSrc := bb.Add(srcb.Min).Intersect(srcb)
bbDst := bbSrc.Sub(srcb.Min).Add(dstb.Min).Intersect(dstb)
// Calculate the average color of the block.
var r, g, b, a float32
var cnt float32
for y := bbSrc.Min.Y; y < bbSrc.Max.Y; y++ {
for x := bbSrc.Min.X; x < bbSrc.Max.X; x++ {
px := pixGetter.getPixel(x, y)
r += px.r
g += px.g
b += px.b
a += px.a
cnt++
}
}
if cnt > 0 {
r /= cnt
g /= cnt
b /= cnt
a /= cnt
}
// Set the calculated color for all pixels in the block.
for y := bbDst.Min.Y; y < bbDst.Max.Y; y++ {
for x := bbDst.Min.X; x < bbDst.Max.X; x++ {
pixSetter.setPixel(x, y, pixel{r, g, b, a})
}
}
}
}
})
}
// Pixelate creates a filter that applies a pixelation effect to an image.
func Pixelate(size int) Filter {
return &pixelateFilter{
size: size,
}
}
|