summaryrefslogtreecommitdiff
path: root/vendor/github.com/fogleman/gg
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/fogleman/gg')
-rw-r--r--vendor/github.com/fogleman/gg/.gitignore2
-rw-r--r--vendor/github.com/fogleman/gg/README.md220
-rw-r--r--vendor/github.com/fogleman/gg/context.go136
-rw-r--r--vendor/github.com/fogleman/gg/examples/gradient-linear.go39
-rw-r--r--vendor/github.com/fogleman/gg/examples/gradient-radial.go27
-rw-r--r--vendor/github.com/fogleman/gg/examples/pattern-fill.go20
-rw-r--r--vendor/github.com/fogleman/gg/gradient.go202
-rw-r--r--vendor/github.com/fogleman/gg/pattern.go123
-rw-r--r--vendor/github.com/fogleman/gg/util.go3
9 files changed, 718 insertions, 54 deletions
diff --git a/vendor/github.com/fogleman/gg/.gitignore b/vendor/github.com/fogleman/gg/.gitignore
new file mode 100644
index 0000000..2fa80d6
--- /dev/null
+++ b/vendor/github.com/fogleman/gg/.gitignore
@@ -0,0 +1,2 @@
+*.png
+
diff --git a/vendor/github.com/fogleman/gg/README.md b/vendor/github.com/fogleman/gg/README.md
new file mode 100644
index 0000000..24441ad
--- /dev/null
+++ b/vendor/github.com/fogleman/gg/README.md
@@ -0,0 +1,220 @@
+# Go Graphics
+
+`gg` is a library for rendering 2D graphics in pure Go.
+
+![Stars](http://i.imgur.com/CylQIJt.png)
+
+## Installation
+
+ go get github.com/fogleman/gg
+
+## GoDoc
+
+https://godoc.org/github.com/fogleman/gg
+
+## Hello, Circle!
+
+Look how easy!
+
+```go
+package main
+
+import "github.com/fogleman/gg"
+
+func main() {
+ dc := gg.NewContext(1000, 1000)
+ dc.DrawCircle(500, 500, 400)
+ dc.SetRGB(0, 0, 0)
+ dc.Fill()
+ dc.SavePNG("out.png")
+}
+```
+
+## Examples
+
+There are [lots of examples](https://github.com/fogleman/gg/tree/master/examples) included. They're mostly for testing the code, but they're good for learning, too.
+
+![Examples](http://i.imgur.com/tMFoyzu.png)
+
+## Creating Contexts
+
+There are a few ways of creating a context.
+
+```go
+NewContext(width, height int) *Context
+NewContextForImage(im image.Image) *Context
+NewContextForRGBA(im *image.RGBA) *Context
+```
+
+## Drawing Functions
+
+Ever used a graphics library that didn't have functions for drawing rectangles
+or circles? What a pain!
+
+```go
+DrawPoint(x, y, r float64)
+DrawLine(x1, y1, x2, y2 float64)
+DrawRectangle(x, y, w, h float64)
+DrawRoundedRectangle(x, y, w, h, r float64)
+DrawCircle(x, y, r float64)
+DrawArc(x, y, r, angle1, angle2 float64)
+DrawEllipse(x, y, rx, ry float64)
+DrawEllipticalArc(x, y, rx, ry, angle1, angle2 float64)
+DrawRegularPolygon(n int, x, y, r, rotation float64)
+DrawImage(im image.Image, x, y int)
+DrawImageAnchored(im image.Image, x, y int, ax, ay float64)
+SetPixel(x, y int)
+
+MoveTo(x, y float64)
+LineTo(x, y float64)
+QuadraticTo(x1, y1, x2, y2 float64)
+CubicTo(x1, y1, x2, y2, x3, y3 float64)
+ClosePath()
+ClearPath()
+NewSubPath()
+
+Clear()
+Stroke()
+Fill()
+StrokePreserve()
+FillPreserve()
+```
+
+It is often desired to center an image at a point. Use `DrawImageAnchored` with `ax` and `ay` set to 0.5 to do this. Use 0 to left or top align. Use 1 to right or bottom align. `DrawStringAnchored` does the same for text, so you don't need to call `MeasureString` yourself.
+
+## Text Functions
+
+It will even do word wrap for you!
+
+```go
+DrawString(s string, x, y float64)
+DrawStringAnchored(s string, x, y, ax, ay float64)
+DrawStringWrapped(s string, x, y, ax, ay, width, lineSpacing float64, align Align)
+MeasureString(s string) (w, h float64)
+WordWrap(s string, w float64) []string
+SetFontFace(fontFace font.Face)
+LoadFontFace(path string, points float64) error
+```
+
+## Color Functions
+
+Colors can be set in several different ways for your convenience.
+
+```go
+SetRGB(r, g, b float64)
+SetRGBA(r, g, b, a float64)
+SetRGB255(r, g, b int)
+SetRGBA255(r, g, b, a int)
+SetColor(c color.Color)
+SetHexColor(x string)
+```
+
+## Stroke & Fill Options
+
+```go
+SetLineWidth(lineWidth float64)
+SetLineCap(lineCap LineCap)
+SetLineJoin(lineJoin LineJoin)
+SetDash(dashes ...float64)
+SetFillRule(fillRule FillRule)
+```
+
+## Gradients & Patterns
+
+`gg` supports linear and radial gradients and surface patterns. You can also implement your own patterns.
+
+```go
+SetFillStyle(pattern Pattern)
+SetStrokeStyle(pattern Pattern)
+NewSolidPattern(color color.Color)
+NewLinearGradient(x0, y0, x1, y1 float64)
+NewRadialGradient(x0, y0, r0, x1, y1, r1 float64)
+NewSurfacePattern(im image.Image, op RepeatOp)
+```
+
+## Transformation Functions
+
+```go
+Identity()
+Translate(x, y float64)
+Scale(x, y float64)
+Rotate(angle float64)
+Shear(x, y float64)
+ScaleAbout(sx, sy, x, y float64)
+RotateAbout(angle, x, y float64)
+ShearAbout(sx, sy, x, y float64)
+TransformPoint(x, y float64) (tx, ty float64)
+InvertY()
+```
+
+It is often desired to rotate or scale about a point that is not the origin. The functions `RotateAbout`, `ScaleAbout`, `ShearAbout` are provided as a convenience.
+
+`InvertY` is provided in case Y should increase from bottom to top vs. the default top to bottom.
+
+Note: transforms do not currently affect `DrawImage` or `DrawString`.
+
+## Stack Functions
+
+Save and restore the state of the context. These can be nested.
+
+```go
+Push()
+Pop()
+```
+
+## Clipping Functions
+
+Use clipping regions to restrict drawing operations to an area that you
+defined using paths.
+
+```go
+Clip()
+ClipPreserve()
+ResetClip()
+```
+
+## Helper Functions
+
+Sometimes you just don't want to write these yourself.
+
+```go
+Radians(degrees float64) float64
+Degrees(radians float64) float64
+LoadImage(path string) (image.Image, error)
+LoadPNG(path string) (image.Image, error)
+SavePNG(path string, im image.Image) error
+```
+
+![Separator](http://i.imgur.com/fsUvnPB.png)
+
+## How Do it Do?
+
+`gg` is mostly a wrapper around `github.com/golang/freetype/raster`. The goal
+is to provide some more functionality and a nicer API that will suffice for
+most use cases.
+
+## Another Example
+
+See the output of this example below.
+
+```go
+package main
+
+import "github.com/fogleman/gg"
+
+func main() {
+ const S = 1024
+ dc := gg.NewContext(S, S)
+ dc.SetRGBA(0, 0, 0, 0.1)
+ for i := 0; i < 360; i += 15 {
+ dc.Push()
+ dc.RotateAbout(gg.Radians(float64(i)), S/2, S/2)
+ dc.DrawEllipse(S/2, S/2, S*7/16, S/8)
+ dc.Fill()
+ dc.Pop()
+ }
+ dc.SavePNG("out.png")
+}
+```
+
+![Ellipses](http://i.imgur.com/J9CBZef.png)
diff --git a/vendor/github.com/fogleman/gg/context.go b/vendor/github.com/fogleman/gg/context.go
index e186027..c3b44f2 100644
--- a/vendor/github.com/fogleman/gg/context.go
+++ b/vendor/github.com/fogleman/gg/context.go
@@ -44,26 +44,33 @@ const (
AlignRight
)
+var (
+ defaultFillStyle = NewSolidPattern(color.White)
+ defaultStrokeStyle = NewSolidPattern(color.Black)
+)
+
type Context struct {
- width int
- height int
- im *image.RGBA
- mask *image.Alpha
- color color.Color
- strokePath raster.Path
- fillPath raster.Path
- start Point
- current Point
- hasCurrent bool
- dashes []float64
- lineWidth float64
- lineCap LineCap
- lineJoin LineJoin
- fillRule FillRule
- fontFace font.Face
- fontHeight float64
- matrix Matrix
- stack []*Context
+ width int
+ height int
+ im *image.RGBA
+ mask *image.Alpha
+ color color.Color
+ fillPattern Pattern
+ strokePattern Pattern
+ strokePath raster.Path
+ fillPath raster.Path
+ start Point
+ current Point
+ hasCurrent bool
+ dashes []float64
+ lineWidth float64
+ lineCap LineCap
+ lineJoin LineJoin
+ fillRule FillRule
+ fontFace font.Face
+ fontHeight float64
+ matrix Matrix
+ stack []*Context
}
// NewContext creates a new image.RGBA with the specified width and height
@@ -82,15 +89,17 @@ func NewContextForImage(im image.Image) *Context {
// No copy is made.
func NewContextForRGBA(im *image.RGBA) *Context {
return &Context{
- width: im.Bounds().Size().X,
- height: im.Bounds().Size().Y,
- im: im,
- color: color.Transparent,
- lineWidth: 1,
- fillRule: FillRuleWinding,
- fontFace: basicfont.Face7x13,
- fontHeight: 13,
- matrix: Identity(),
+ width: im.Bounds().Size().X,
+ height: im.Bounds().Size().Y,
+ im: im,
+ color: color.Transparent,
+ fillPattern: defaultFillStyle,
+ strokePattern: defaultStrokeStyle,
+ lineWidth: 1,
+ fillRule: FillRuleWinding,
+ fontFace: basicfont.Face7x13,
+ fontHeight: 13,
+ matrix: Identity(),
}
}
@@ -172,9 +181,29 @@ func (dc *Context) SetFillRuleEvenOdd() {
// Color Setters
-// SetColor sets the current color.
-func (dc *Context) SetColor(c color.Color) {
+func (dc *Context) setFillAndStrokeColor(c color.Color) {
dc.color = c
+ dc.fillPattern = NewSolidPattern(c)
+ dc.strokePattern = NewSolidPattern(c)
+}
+
+// SetFillStyle sets current fill style
+func (dc *Context) SetFillStyle(pattern Pattern) {
+ // if pattern is SolidPattern, also change dc.color(for dc.Clear, dc.drawString)
+ if fillStyle, ok := pattern.(*solidPattern); ok {
+ dc.color = fillStyle.color
+ }
+ dc.fillPattern = pattern
+}
+
+// SetStrokeStyle sets current stroke style
+func (dc *Context) SetStrokeStyle(pattern Pattern) {
+ dc.strokePattern = pattern
+}
+
+// SetColor sets the current color(for both fill and stroke).
+func (dc *Context) SetColor(c color.Color) {
+ dc.setFillAndStrokeColor(c)
}
// SetHexColor sets the current color using a hex string. The leading pound
@@ -189,6 +218,7 @@ func (dc *Context) SetHexColor(x string) {
// 255, inclusive.
func (dc *Context) SetRGBA255(r, g, b, a int) {
dc.color = color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(a)}
+ dc.setFillAndStrokeColor(dc.color)
}
// SetRGB255 sets the current color. r, g, b values should be between 0 and 255,
@@ -206,6 +236,7 @@ func (dc *Context) SetRGBA(r, g, b, a float64) {
uint8(b * 255),
uint8(a * 255),
}
+ dc.setFillAndStrokeColor(dc.color)
}
// SetRGB sets the current color. r, g, b values should be between 0 and 1,
@@ -371,17 +402,8 @@ func (dc *Context) fill(painter raster.Painter) {
// line cap, line join and dash settings. The path is preserved after this
// operation.
func (dc *Context) StrokePreserve() {
- if dc.mask == nil {
- painter := raster.NewRGBAPainter(dc.im)
- painter.SetColor(dc.color)
- dc.stroke(painter)
- } else {
- im := image.NewRGBA(image.Rect(0, 0, dc.width, dc.height))
- painter := raster.NewRGBAPainter(im)
- painter.SetColor(dc.color)
- dc.stroke(painter)
- draw.DrawMask(dc.im, dc.im.Bounds(), im, image.ZP, dc.mask, image.ZP, draw.Over)
- }
+ painter := newPatternPainter(dc.im, dc.mask, dc.strokePattern)
+ dc.stroke(painter)
}
// Stroke strokes the current path with the current color, line width,
@@ -395,17 +417,8 @@ func (dc *Context) Stroke() {
// FillPreserve fills the current path with the current color. Open subpaths
// are implicity closed. The path is preserved after this operation.
func (dc *Context) FillPreserve() {
- if dc.mask == nil {
- painter := raster.NewRGBAPainter(dc.im)
- painter.SetColor(dc.color)
- dc.fill(painter)
- } else {
- im := image.NewRGBA(image.Rect(0, 0, dc.width, dc.height))
- painter := raster.NewRGBAPainter(im)
- painter.SetColor(dc.color)
- dc.fill(painter)
- draw.DrawMask(dc.im, dc.im.Bounds(), im, image.ZP, dc.mask, image.ZP, draw.Over)
- }
+ painter := newPatternPainter(dc.im, dc.mask, dc.fillPattern)
+ dc.fill(painter)
}
// Fill fills the current path with the current color. Open subpaths
@@ -452,6 +465,22 @@ func (dc *Context) Clear() {
draw.Draw(dc.im, dc.im.Bounds(), src, image.ZP, draw.Src)
}
+// SetPixel sets the color of the specified pixel using the current color.
+func (dc *Context) SetPixel(x, y int) {
+ dc.im.Set(x, y, dc.color)
+}
+
+// DrawPoint is like DrawCircle but ensures that a circle of the specified
+// size is drawn regardless of the current transformation matrix. The position
+// is still transformed, but not the shape of the point.
+func (dc *Context) DrawPoint(x, y, r float64) {
+ dc.Push()
+ tx, ty := dc.TransformPoint(x, y)
+ dc.Identity()
+ dc.DrawCircle(tx, ty, r)
+ dc.Pop()
+}
+
func (dc *Context) DrawLine(x1, y1, x2, y2 float64) {
dc.MoveTo(x1, y1)
dc.LineTo(x2, y2)
@@ -560,10 +589,11 @@ func (dc *Context) DrawImageAnchored(im image.Image, x, y int, ax, ay float64) {
func (dc *Context) SetFontFace(fontFace font.Face) {
dc.fontFace = fontFace
+ dc.fontHeight = float64(fontFace.Metrics().Height) / 64
}
func (dc *Context) LoadFontFace(path string, points float64) error {
- face, err := loadFontFace(path, points)
+ face, err := LoadFontFace(path, points)
if err == nil {
dc.fontFace = face
dc.fontHeight = points * 72 / 96
diff --git a/vendor/github.com/fogleman/gg/examples/gradient-linear.go b/vendor/github.com/fogleman/gg/examples/gradient-linear.go
new file mode 100644
index 0000000..5f1ceec
--- /dev/null
+++ b/vendor/github.com/fogleman/gg/examples/gradient-linear.go
@@ -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")
+}
diff --git a/vendor/github.com/fogleman/gg/examples/gradient-radial.go b/vendor/github.com/fogleman/gg/examples/gradient-radial.go
new file mode 100644
index 0000000..d336135
--- /dev/null
+++ b/vendor/github.com/fogleman/gg/examples/gradient-radial.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+ "image/color"
+
+ "github.com/fogleman/gg"
+)
+
+func main() {
+ dc := gg.NewContext(400, 200)
+
+ grad := gg.NewRadialGradient(100, 100, 10, 100, 120, 80)
+ grad.AddColorStop(0, color.RGBA{0, 255, 0, 255})
+ grad.AddColorStop(1, color.RGBA{0, 0, 255, 255})
+
+ dc.SetFillStyle(grad)
+ dc.DrawRectangle(0, 0, 200, 200)
+ dc.Fill()
+
+ dc.SetColor(color.White)
+ dc.DrawCircle(100, 100, 10)
+ dc.Stroke()
+ dc.DrawCircle(100, 120, 80)
+ dc.Stroke()
+
+ dc.SavePNG("out.png")
+}
diff --git a/vendor/github.com/fogleman/gg/examples/pattern-fill.go b/vendor/github.com/fogleman/gg/examples/pattern-fill.go
new file mode 100644
index 0000000..4500350
--- /dev/null
+++ b/vendor/github.com/fogleman/gg/examples/pattern-fill.go
@@ -0,0 +1,20 @@
+package main
+
+import "github.com/fogleman/gg"
+
+func main() {
+ im, err := gg.LoadPNG("examples/lenna.png")
+ if err != nil {
+ panic(err)
+ }
+ pattern := gg.NewSurfacePattern(im, gg.RepeatBoth)
+ dc := gg.NewContext(600, 600)
+ dc.MoveTo(20, 20)
+ dc.LineTo(590, 20)
+ dc.LineTo(590, 590)
+ dc.LineTo(20, 590)
+ dc.ClosePath()
+ dc.SetFillStyle(pattern)
+ dc.Fill()
+ dc.SavePNG("out.png")
+}
diff --git a/vendor/github.com/fogleman/gg/gradient.go b/vendor/github.com/fogleman/gg/gradient.go
new file mode 100644
index 0000000..1625520
--- /dev/null
+++ b/vendor/github.com/fogleman/gg/gradient.go
@@ -0,0 +1,202 @@
+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
+ 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, x1, y1 := g.x0, g.y0, g.x1, g.y1
+ dx, dy := x1-x0, y1-y0
+
+ // 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)
+ }
+
+ // Dot product
+ s0 := dx*(fx-x0) + dy*(fy-y0)
+ if s0 < 0 {
+ return g.stops[0].color
+ }
+ // Calculate distance to (x0,y0) alone (x0,y0)->(x1,y1)
+ mag := math.Hypot(dx, dy)
+ u := ((fx-x0)*-dy + (fy-y0)*dx) / (mag * mag)
+ x2, y2 := x0+u*-dy, y0+u*dx
+ 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 {
+ g := &linearGradient{
+ x0: x0, y0: y0,
+ x1: x1, y1: y1,
+ }
+ return g
+}
+
+// Radial Gradient
+type circle struct {
+ x, y, r float64
+}
+
+type radialGradient struct {
+ c0, c1, cd circle
+ a, inva float64
+ mindr float64
+ stops stops
+}
+
+func dot3(x0, y0, z0, x1, y1, z1 float64) float64 {
+ return x0*x1 + y0*y1 + z0*z1
+}
+
+func (g *radialGradient) ColorAt(x, y int) color.Color {
+ if len(g.stops) == 0 {
+ return color.Transparent
+ }
+
+ // copy from pixman's pixman-radial-gradient.c
+
+ dx, dy := float64(x)+0.5-g.c0.x, float64(y)+0.5-g.c0.y
+ b := dot3(dx, dy, g.c0.r, g.cd.x, g.cd.y, g.cd.r)
+ c := dot3(dx, dy, -g.c0.r, dx, dy, g.c0.r)
+
+ if g.a == 0 {
+ if b == 0 {
+ return color.Transparent
+ }
+ t := 0.5 * c / b
+ if t*g.cd.r >= g.mindr {
+ return getColor(t, g.stops)
+ }
+ return color.Transparent
+ }
+
+ discr := dot3(b, g.a, 0, b, -c, 0)
+ if discr >= 0 {
+ sqrtdiscr := math.Sqrt(discr)
+ t0 := (b + sqrtdiscr) * g.inva
+ t1 := (b - sqrtdiscr) * g.inva
+
+ if t0*g.cd.r >= g.mindr {
+ return getColor(t0, g.stops)
+ } else if t1*g.cd.r >= g.mindr {
+ return getColor(t1, g.stops)
+ }
+ }
+
+ return color.Transparent
+}
+
+func (g *radialGradient) AddColorStop(offset float64, color color.Color) {
+ g.stops = append(g.stops, stop{pos: offset, color: color})
+ sort.Sort(g.stops)
+}
+
+func NewRadialGradient(x0, y0, r0, x1, y1, r1 float64) Gradient {
+ c0 := circle{x0, y0, r0}
+ c1 := circle{x1, y1, r1}
+ cd := circle{x1 - x0, y1 - y0, r1 - r0}
+ a := dot3(cd.x, cd.y, -cd.r, cd.x, cd.y, cd.r)
+ var inva float64
+ if a != 0 {
+ inva = 1.0 / a
+ }
+ mindr := -c0.r
+ g := &radialGradient{
+ c0: c0,
+ c1: c1,
+ cd: cd,
+ a: a,
+ inva: inva,
+ mindr: mindr,
+ }
+ 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)
+}
diff --git a/vendor/github.com/fogleman/gg/pattern.go b/vendor/github.com/fogleman/gg/pattern.go
new file mode 100644
index 0000000..6b396ec
--- /dev/null
+++ b/vendor/github.com/fogleman/gg/pattern.go
@@ -0,0 +1,123 @@
+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 {
+ im *image.RGBA
+ mask *image.Alpha
+ p Pattern
+}
+
+// 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 {
+ ma := s.Alpha
+ if r.mask != nil {
+ ma = ma * uint32(r.mask.AlphaAt(x, y).A) / 255
+ if ma == 0 {
+ continue
+ }
+ }
+ 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)
+ }
+ }
+}
+
+func newPatternPainter(im *image.RGBA, mask *image.Alpha, p Pattern) *patternPainter {
+ return &patternPainter{im, mask, p}
+}
diff --git a/vendor/github.com/fogleman/gg/util.go b/vendor/github.com/fogleman/gg/util.go
index 62577f5..a530fcb 100644
--- a/vendor/github.com/fogleman/gg/util.go
+++ b/vendor/github.com/fogleman/gg/util.go
@@ -4,6 +4,7 @@ import (
"fmt"
"image"
"image/draw"
+ _ "image/jpeg"
"image/png"
"io/ioutil"
"math"
@@ -99,7 +100,7 @@ func unfix(x fixed.Int26_6) float64 {
return 0
}
-func loadFontFace(path string, points float64) (font.Face, error) {
+func LoadFontFace(path string, points float64) (font.Face, error) {
fontBytes, err := ioutil.ReadFile(path)
if err != nil {
return nil, err