linear gradient
This commit is contained in:
parent
db5b86472e
commit
1aa57065bb
39
examples/gradient-linear.go
Normal file
39
examples/gradient-linear.go
Normal 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")
|
||||
}
|
@ -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
131
gradient.go
Normal 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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user