127 lines
2.3 KiB
Go
127 lines
2.3 KiB
Go
package canvas
|
|
|
|
import (
|
|
"image"
|
|
"image/color"
|
|
)
|
|
|
|
// 应用全局透明度
|
|
func (c *Context) applyAlpha(col color.Color) color.Color {
|
|
if c.state.globalAlpha >= 1.0 {
|
|
return col
|
|
}
|
|
|
|
r, g, b, a := col.RGBA()
|
|
a = uint32(float64(a) * c.state.globalAlpha)
|
|
return color.NRGBA64{
|
|
R: uint16(r),
|
|
G: uint16(g),
|
|
B: uint16(b),
|
|
A: uint16(a),
|
|
}
|
|
}
|
|
|
|
// 颜色插值
|
|
func interpolateColor(c1, c2 color.Color, t float64) color.Color {
|
|
r1, g1, b1, a1 := c1.RGBA()
|
|
r2, g2, b2, a2 := c2.RGBA()
|
|
|
|
return color.RGBA64{
|
|
R: uint16(float64(r1)*(1-t) + float64(r2)*t),
|
|
G: uint16(float64(g1)*(1-t) + float64(g2)*t),
|
|
B: uint16(float64(b1)*(1-t) + float64(b2)*t),
|
|
A: uint16(float64(a1)*(1-t) + float64(a2)*t),
|
|
}
|
|
}
|
|
|
|
// 渐变图像
|
|
type gradientImage struct {
|
|
grad Gradient
|
|
alpha float64
|
|
}
|
|
|
|
func (g *gradientImage) ColorModel() color.Model {
|
|
return color.RGBAModel
|
|
}
|
|
|
|
func (g *gradientImage) Bounds() image.Rectangle {
|
|
return image.Rect(-1e9, -1e9, 1e9, 1e9)
|
|
}
|
|
|
|
func (g *gradientImage) At(x, y int) color.Color {
|
|
c := g.grad.At(x, y)
|
|
if g.alpha < 1.0 {
|
|
r, gr, b, a := c.RGBA()
|
|
a = uint32(float64(a) * g.alpha)
|
|
return color.NRGBA64{
|
|
R: uint16(r),
|
|
G: uint16(gr),
|
|
B: uint16(b),
|
|
A: uint16(a),
|
|
}
|
|
}
|
|
return c
|
|
}
|
|
|
|
// 填充多边形
|
|
type filledPolygon struct {
|
|
points []image.Point
|
|
}
|
|
|
|
func (p *filledPolygon) ColorModel() color.Model {
|
|
return color.AlphaModel
|
|
}
|
|
|
|
func (p *filledPolygon) Bounds() image.Rectangle {
|
|
if len(p.points) == 0 {
|
|
return image.Rectangle{}
|
|
}
|
|
|
|
minX, minY := p.points[0].X, p.points[0].Y
|
|
maxX, maxY := minX, minY
|
|
|
|
for _, pt := range p.points {
|
|
if pt.X < minX {
|
|
minX = pt.X
|
|
}
|
|
if pt.X > maxX {
|
|
maxX = pt.X
|
|
}
|
|
if pt.Y < minY {
|
|
minY = pt.Y
|
|
}
|
|
if pt.Y > maxY {
|
|
maxY = pt.Y
|
|
}
|
|
}
|
|
|
|
return image.Rect(minX, minY, maxX+1, maxY+1)
|
|
}
|
|
|
|
func (p *filledPolygon) At(x, y int) color.Color {
|
|
if pointInPolygon(image.Pt(x, y), p.points) {
|
|
return color.Alpha{A: 255}
|
|
}
|
|
return color.Alpha{A: 0}
|
|
}
|
|
|
|
// 判断点是否在多边形内
|
|
func pointInPolygon(pt image.Point, poly []image.Point) bool {
|
|
if len(poly) < 3 {
|
|
return false
|
|
}
|
|
|
|
inside := false
|
|
j := len(poly) - 1
|
|
|
|
for i := 0; i < len(poly); i++ {
|
|
if (poly[i].Y > pt.Y) != (poly[j].Y > pt.Y) &&
|
|
(pt.X < poly[i].X+(poly[j].X-poly[i].X)*(pt.Y-poly[i].Y)/(poly[j].Y-poly[i].Y)) {
|
|
inside = !inside
|
|
}
|
|
j = i
|
|
}
|
|
|
|
return inside
|
|
}
|