linear gradient

This commit is contained in:
wsw 2016-11-21 11:01:12 +08:00
parent db5b86472e
commit 1aa57065bb
3 changed files with 186 additions and 1 deletions

View File

@ -0,0 +1,39 @@
package main
import (
"image/color"
"github.com/fogleman/gg"
)
func main() {
dc := gg.NewContext(500, 400)
grad := gg.NewLinearGradient(20, 320, 400, 20)
grad.AddColorStop(0, color.RGBA{0, 255, 0, 255})
grad.AddColorStop(1, color.RGBA{0, 0, 255, 255})
grad.AddColorStop(0.5, color.RGBA{255, 0, 0, 255})
dc.SetColor(color.White)
dc.DrawRectangle(20, 20, 400-20, 300)
dc.Stroke()
dc.SetStrokeStyle(grad)
dc.SetLineWidth(4)
dc.MoveTo(10, 10)
dc.LineTo(410, 10)
dc.LineTo(410, 100)
dc.LineTo(10, 100)
dc.ClosePath()
dc.Stroke()
dc.SetFillStyle(grad)
dc.MoveTo(10, 120)
dc.LineTo(410, 120)
dc.LineTo(410, 300)
dc.LineTo(10, 300)
dc.ClosePath()
dc.Fill()
dc.SavePNG("out.png")
}

View File

@ -1,12 +1,27 @@
package main
import "github.com/fogleman/gg"
import (
"fmt"
"math"
"github.com/fogleman/gg"
)
func main() {
im, err := gg.LoadPNG("examples/lenna.png")
if err != nil {
panic(err)
}
var x0, y0, x1, y1 float64 = 5, 5, 15, 15
a := math.Atan2(y1-y0, x1-x0)
d := a * 180 / math.Pi
fmt.Println(a, d)
a = (2*math.Pi - a)
d = a * 180 / math.Pi
fmt.Println(a, d)
m := gg.Translate(-x0, -y0).Rotate(a)
tx, ty := m.TransformPoint(5, 5)
fmt.Println(tx, ty)
pattern := gg.NewSurfacePattern(im, gg.RepeatBoth)
dc := gg.NewContext(600, 600)
dc.MoveTo(20, 20)

131
gradient.go Normal file
View File

@ -0,0 +1,131 @@
package gg
import (
"image/color"
"math"
"sort"
)
type stop struct {
pos float64
color color.Color
}
type stops []stop
// Len satisfies the Sort interface.
func (s stops) Len() int {
return len(s)
}
// Less satisfies the Sort interface.
func (s stops) Less(i, j int) bool {
return s[i].pos < s[j].pos
}
// Swap satisfies the Sort interface.
func (s stops) Swap(i, j int) {
s[i], s[j] = s[j], s[i]
}
type Gradient interface {
Pattern
AddColorStop(offset float64, color color.Color)
}
// Linear Gradient
type linearGradient struct {
x0, y0, x1, y1 float64
dx, dy float64
mag float64
px0, py0 float64
stops stops
}
func (g *linearGradient) ColorAt(x, y int) color.Color {
if len(g.stops) == 0 {
return color.Transparent
}
fx, fy := float64(x), float64(y)
x0, y0 := g.x0, g.y0
dx, dy := g.dx, g.dy
// Horizontal
if dy == 0 && dx != 0 {
return getColor((fx-x0)/dx, g.stops)
}
// Vertical
if dx == 0 && dy != 0 {
return getColor((fy-y0)/dy, g.stops)
}
px0, py0 := g.px0, g.py0
mag := g.mag
s0 := (px0-x0)*(fy-y0) - (py0-y0)*(fx-x0)
if s0 > 0 {
return g.stops[0].color
}
u := ((fx-x0)*(px0-x0) + (fy-y0)*(py0-y0)) / (mag * mag)
x2, y2 := x0+u*(px0-x0), y0+u*(py0-y0)
d := math.Hypot(fx-x2, fy-y2) / mag
return getColor(d, g.stops)
}
func (g *linearGradient) AddColorStop(offset float64, color color.Color) {
g.stops = append(g.stops, stop{pos: offset, color: color})
sort.Sort(g.stops)
}
func NewLinearGradient(x0, y0, x1, y1 float64) Gradient {
dx, dy := x1-x0, y1-y0
mag := math.Hypot(dx, dy)
px0, py0 := x0-dy, y0+dx
g := &linearGradient{
x0: x0, y0: y0,
x1: x1, y1: y1,
dx: dx, dy: dy,
px0: px0, py0: py0,
mag: mag,
}
return g
}
func getColor(pos float64, stops stops) color.Color {
if pos <= 0.0 || len(stops) == 1 {
return stops[0].color
}
last := stops[len(stops)-1]
if pos >= last.pos {
return last.color
}
for i, stop := range stops[1:] {
if pos < stop.pos {
pos = (pos - stops[i].pos) / (stop.pos - stops[i].pos)
return colorLerp(stops[i].color, stop.color, pos)
}
}
return last.color
}
func colorLerp(c0, c1 color.Color, t float64) color.Color {
r0, g0, b0, a0 := c0.RGBA()
r1, g1, b1, a1 := c1.RGBA()
return color.NRGBA{
lerp(r0, r1, t),
lerp(g0, g1, t),
lerp(b0, b1, t),
lerp(a0, a1, t),
}
}
func lerp(a, b uint32, t float64) uint8 {
return uint8(int32(float64(a)*(1.0-t)+float64(b)*t) >> 8)
}