2016-11-20 13:31:05 +01:00
|
|
|
package gg
|
|
|
|
|
|
|
|
import (
|
|
|
|
"image"
|
|
|
|
"image/color"
|
|
|
|
|
|
|
|
"github.com/golang/freetype/raster"
|
|
|
|
)
|
|
|
|
|
|
|
|
type RepeatOp int
|
|
|
|
|
|
|
|
const (
|
|
|
|
RepeatBoth RepeatOp = iota
|
|
|
|
RepeatX
|
|
|
|
RepeatY
|
|
|
|
RepeatNone
|
|
|
|
)
|
|
|
|
|
|
|
|
type Pattern interface {
|
|
|
|
ColorAt(x, y int) color.Color
|
|
|
|
}
|
|
|
|
|
|
|
|
// Solid Pattern
|
|
|
|
type solidPattern struct {
|
|
|
|
color color.Color
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *solidPattern) ColorAt(x, y int) color.Color {
|
|
|
|
return p.color
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewSolidPattern(color color.Color) Pattern {
|
|
|
|
return &solidPattern{color: color}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Surface Pattern
|
|
|
|
type surfacePattern struct {
|
|
|
|
im image.Image
|
|
|
|
op RepeatOp
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *surfacePattern) ColorAt(x, y int) color.Color {
|
|
|
|
b := p.im.Bounds()
|
|
|
|
switch p.op {
|
|
|
|
case RepeatX:
|
|
|
|
if y >= b.Dy() {
|
|
|
|
return color.Transparent
|
|
|
|
}
|
|
|
|
case RepeatY:
|
|
|
|
if x >= b.Dx() {
|
|
|
|
return color.Transparent
|
|
|
|
}
|
|
|
|
case RepeatNone:
|
|
|
|
if x >= b.Dx() || y >= b.Dy() {
|
|
|
|
return color.Transparent
|
|
|
|
}
|
|
|
|
}
|
|
|
|
x = x%b.Dx() + b.Min.X
|
|
|
|
y = y%b.Dy() + b.Min.Y
|
|
|
|
return p.im.At(x, y)
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewSurfacePattern(im image.Image, op RepeatOp) Pattern {
|
|
|
|
return &surfacePattern{im: im, op: op}
|
|
|
|
}
|
|
|
|
|
|
|
|
type patternPainter struct {
|
2016-12-14 23:06:16 +01:00
|
|
|
im *image.RGBA
|
|
|
|
mask *image.Alpha
|
|
|
|
p Pattern
|
2016-11-20 13:31:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Paint satisfies the Painter interface.
|
|
|
|
func (r *patternPainter) Paint(ss []raster.Span, done bool) {
|
|
|
|
b := r.im.Bounds()
|
|
|
|
for _, s := range ss {
|
|
|
|
if s.Y < b.Min.Y {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if s.Y >= b.Max.Y {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if s.X0 < b.Min.X {
|
|
|
|
s.X0 = b.Min.X
|
|
|
|
}
|
|
|
|
if s.X1 > b.Max.X {
|
|
|
|
s.X1 = b.Max.X
|
|
|
|
}
|
|
|
|
if s.X0 >= s.X1 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
const m = 1<<16 - 1
|
|
|
|
y := s.Y - r.im.Rect.Min.Y
|
|
|
|
x0 := s.X0 - r.im.Rect.Min.X
|
|
|
|
// RGBAPainter.Paint() in $GOPATH/src/github.com/golang/freetype/raster/paint.go
|
|
|
|
i0 := (s.Y-r.im.Rect.Min.Y)*r.im.Stride + (s.X0-r.im.Rect.Min.X)*4
|
|
|
|
i1 := i0 + (s.X1-s.X0)*4
|
|
|
|
for i, x := i0, x0; i < i1; i, x = i+4, x+1 {
|
2016-12-14 23:06:16 +01:00
|
|
|
ma := s.Alpha
|
|
|
|
if r.mask != nil {
|
|
|
|
ma = ma * uint32(r.mask.AlphaAt(x, y).A) / 255
|
|
|
|
if ma == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
2016-11-20 13:31:05 +01:00
|
|
|
c := r.p.ColorAt(x, y)
|
|
|
|
cr, cg, cb, ca := c.RGBA()
|
|
|
|
dr := uint32(r.im.Pix[i+0])
|
|
|
|
dg := uint32(r.im.Pix[i+1])
|
|
|
|
db := uint32(r.im.Pix[i+2])
|
|
|
|
da := uint32(r.im.Pix[i+3])
|
|
|
|
a := (m - (ca * ma / m)) * 0x101
|
|
|
|
r.im.Pix[i+0] = uint8((dr*a + cr*ma) / m >> 8)
|
|
|
|
r.im.Pix[i+1] = uint8((dg*a + cg*ma) / m >> 8)
|
|
|
|
r.im.Pix[i+2] = uint8((db*a + cb*ma) / m >> 8)
|
|
|
|
r.im.Pix[i+3] = uint8((da*a + ca*ma) / m >> 8)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-14 23:06:16 +01:00
|
|
|
func newPatternPainter(im *image.RGBA, mask *image.Alpha, p Pattern) *patternPainter {
|
|
|
|
return &patternPainter{im, mask, p}
|
2016-11-20 13:31:05 +01:00
|
|
|
}
|