refactoring

This commit is contained in:
Michael Fogleman 2016-02-19 11:07:25 -05:00
parent 80f52004a0
commit 805bc68eed
7 changed files with 131 additions and 64 deletions

View File

@ -42,17 +42,24 @@ type Context struct {
path raster.Path path raster.Path
start fixed.Point26_6 start fixed.Point26_6
lineWidth float64 lineWidth float64
capper raster.Capper lineCap LineCap
joiner raster.Joiner lineJoin LineJoin
fillRule FillRule fillRule FillRule
fontFace font.Face fontFace font.Face
} }
func NewContext(width, height int) *Context { func NewContext(width, height int) *Context {
im := image.NewRGBA(image.Rect(0, 0, width, height)) return NewContextForRGBA(image.NewRGBA(image.Rect(0, 0, width, height)))
}
func NewContextForImage(im image.Image) *Context {
return NewContextForRGBA(imageToRGBA(im))
}
func NewContextForRGBA(im *image.RGBA) *Context {
return &Context{ return &Context{
width: width, width: im.Bounds().Size().X,
height: height, height: im.Bounds().Size().Y,
im: im, im: im,
color: color.Transparent, color: color.Transparent,
lineWidth: 1, lineWidth: 1,
@ -77,11 +84,42 @@ func (dc *Context) WriteToPNG(path string) error {
return writeToPNG(path, dc.im) return writeToPNG(path, dc.im)
} }
func (dc *Context) Paint() { func (dc *Context) SetLineWidth(lineWidth float64) {
draw.Draw(dc.im, dc.im.Bounds(), image.NewUniform(dc.color), image.ZP, draw.Src) dc.lineWidth = lineWidth
} }
func (dc *Context) SetSourceRGBA(r, g, b, a float64) { func (dc *Context) SetLineCap(lineCap LineCap) {
dc.lineCap = lineCap
}
func (dc *Context) SetLineJoin(lineJoin LineJoin) {
dc.lineJoin = lineJoin
}
func (dc *Context) SetFillRule(fillRule FillRule) {
dc.fillRule = fillRule
}
// Color Setters
func (dc *Context) SetColor(c color.Color) {
dc.color = c
}
func (dc *Context) SetHexColor(x string) {
r, g, b := parseHexColor(x)
dc.SetRGB255(r, g, b)
}
func (dc *Context) SetRGBA255(r, g, b, a int) {
dc.color = color.NRGBA{uint8(r), uint8(g), uint8(b), uint8(a)}
}
func (dc *Context) SetRGB255(r, g, b int) {
dc.SetRGBA255(r, g, b, 255)
}
func (dc *Context) SetRGBA(r, g, b, a float64) {
dc.color = color.NRGBA{ dc.color = color.NRGBA{
uint8(r * 255), uint8(r * 255),
uint8(g * 255), uint8(g * 255),
@ -90,37 +128,11 @@ func (dc *Context) SetSourceRGBA(r, g, b, a float64) {
} }
} }
func (dc *Context) SetSourceRGB(r, g, b float64) { func (dc *Context) SetRGB(r, g, b float64) {
dc.SetSourceRGBA(r, g, b, 1) dc.SetRGBA(r, g, b, 1)
} }
func (dc *Context) SetLineWidth(lineWidth float64) { // Path Manipulation
dc.lineWidth = lineWidth
}
func (dc *Context) SetLineCap(lineCap LineCap) {
switch lineCap {
case LineCapButt:
dc.capper = raster.ButtCapper
case LineCapRound:
dc.capper = raster.RoundCapper
case LineCapSquare:
dc.capper = raster.SquareCapper
}
}
func (dc *Context) SetLineJoin(lineJoin LineJoin) {
switch lineJoin {
case LineJoinBevel:
dc.joiner = raster.BevelJoiner
case LineJoinRound:
dc.joiner = raster.RoundJoiner
}
}
func (dc *Context) SetFillRule(fillRule FillRule) {
dc.fillRule = fillRule
}
func (dc *Context) MoveTo(x, y float64) { func (dc *Context) MoveTo(x, y float64) {
dc.start = fp(x, y) dc.start = fp(x, y)
@ -149,22 +161,40 @@ func (dc *Context) ClosePath() {
} }
} }
func (dc *Context) NewPath() { func (dc *Context) ClearPath() {
dc.path.Clear() dc.path.Clear()
} }
// Path Drawing
func (dc *Context) StrokePreserve() { func (dc *Context) StrokePreserve() {
var capper raster.Capper
switch dc.lineCap {
case LineCapButt:
capper = raster.ButtCapper
case LineCapRound:
capper = raster.RoundCapper
case LineCapSquare:
capper = raster.SquareCapper
}
var joiner raster.Joiner
switch dc.lineJoin {
case LineJoinBevel:
joiner = raster.BevelJoiner
case LineJoinRound:
joiner = raster.RoundJoiner
}
painter := raster.NewRGBAPainter(dc.im) painter := raster.NewRGBAPainter(dc.im)
painter.SetColor(dc.color) painter.SetColor(dc.color)
r := raster.NewRasterizer(dc.width, dc.height) r := raster.NewRasterizer(dc.width, dc.height)
r.UseNonZeroWinding = true r.UseNonZeroWinding = true
r.AddStroke(dc.path, fi(dc.lineWidth), dc.capper, dc.joiner) r.AddStroke(dc.path, fi(dc.lineWidth), capper, joiner)
r.Rasterize(painter) r.Rasterize(painter)
} }
func (dc *Context) Stroke() { func (dc *Context) Stroke() {
dc.StrokePreserve() dc.StrokePreserve()
dc.NewPath() dc.ClearPath()
} }
func (dc *Context) FillPreserve() { func (dc *Context) FillPreserve() {
@ -182,17 +212,29 @@ func (dc *Context) FillPreserve() {
func (dc *Context) Fill() { func (dc *Context) Fill() {
dc.FillPreserve() dc.FillPreserve()
dc.NewPath() dc.ClearPath()
} }
// Convenient Drawing Functions // Convenient Drawing Functions
func (dc *Context) Clear() {
draw.Draw(dc.im, dc.im.Bounds(), image.NewUniform(dc.color), image.ZP, draw.Src)
}
func (dc *Context) DrawLine(x1, y1, x2, y2 float64) { func (dc *Context) DrawLine(x1, y1, x2, y2 float64) {
dc.MoveTo(x1, y1) dc.MoveTo(x1, y1)
dc.LineTo(x2, y2) dc.LineTo(x2, y2)
} }
func (dc *Context) DrawEllipseArc(x, y, rx, ry, angle1, angle2 float64) { func (dc *Context) DrawRectangle(x, y, w, h float64) {
dc.MoveTo(x, y)
dc.LineTo(x+w, y)
dc.LineTo(x+w, y+h)
dc.LineTo(x, y+h)
dc.LineTo(x, y)
}
func (dc *Context) DrawEllipticalArc(x, y, rx, ry, angle1, angle2 float64) {
const n = 16 const n = 16
for i := 0; i <= n; i++ { for i := 0; i <= n; i++ {
p1 := float64(i+0) / n p1 := float64(i+0) / n
@ -215,15 +257,15 @@ func (dc *Context) DrawEllipseArc(x, y, rx, ry, angle1, angle2 float64) {
} }
func (dc *Context) DrawEllipse(x, y, rx, ry float64) { func (dc *Context) DrawEllipse(x, y, rx, ry float64) {
dc.DrawEllipseArc(x, y, rx, ry, 0, 2*math.Pi) dc.DrawEllipticalArc(x, y, rx, ry, 0, 2*math.Pi)
} }
func (dc *Context) DrawArc(x, y, r, angle1, angle2 float64) { func (dc *Context) DrawArc(x, y, r, angle1, angle2 float64) {
dc.DrawEllipseArc(x, y, r, r, angle1, angle2) dc.DrawEllipticalArc(x, y, r, r, angle1, angle2)
} }
func (dc *Context) DrawCircle(x, y, r float64) { func (dc *Context) DrawCircle(x, y, r float64) {
dc.DrawEllipseArc(x, y, r, r, 0, 2*math.Pi) dc.DrawEllipticalArc(x, y, r, r, 0, 2*math.Pi)
} }
// Text Functions // Text Functions

View File

@ -4,12 +4,12 @@ import "github.com/fogleman/gg"
func main() { func main() {
dc := gg.NewContext(1000, 1000) dc := gg.NewContext(1000, 1000)
dc.SetSourceRGB(1, 1, 1) dc.SetRGB(1, 1, 1)
dc.Paint() dc.Clear()
dc.DrawCircle(500, 500, 400) dc.DrawCircle(500, 500, 400)
dc.SetSourceRGBA(0, 0, 0, 0.25) dc.SetRGBA(0, 0, 0, 0.25)
dc.FillPreserve() dc.FillPreserve()
dc.SetSourceRGB(0, 0, 0.5) dc.SetRGB(0, 0, 0.5)
dc.SetLineWidth(8) dc.SetLineWidth(8)
dc.Stroke() dc.Stroke()
dc.WriteToPNG("out.png") dc.WriteToPNG("out.png")

View File

@ -4,16 +4,16 @@ import "github.com/fogleman/gg"
func main() { func main() {
dc := gg.NewContext(256, 256) dc := gg.NewContext(256, 256)
dc.SetSourceRGBA(1, 0, 0, 0.3) dc.SetRGBA(1, 0, 0, 0.3)
dc.Paint() dc.Clear()
dc.MoveTo(20, 20) dc.MoveTo(20, 20)
dc.LineTo(236, 236) dc.LineTo(236, 236)
dc.LineTo(236, 128) dc.LineTo(236, 128)
dc.LineTo(20, 128) dc.LineTo(20, 128)
dc.QuadraticTo(0, 64, 120, 20) dc.QuadraticTo(0, 64, 120, 20)
dc.SetSourceRGBA(1, 0, 0, 0.8) dc.SetRGBA(1, 0, 0, 0.8)
dc.FillPreserve() dc.FillPreserve()
dc.SetSourceRGB(0, 0, 0) dc.SetRGB(0, 0, 0)
dc.SetLineWidth(8) dc.SetLineWidth(8)
dc.Stroke() dc.Stroke()
dc.WriteToPNG("out.png") dc.WriteToPNG("out.png")

View File

@ -10,8 +10,8 @@ func main() {
const W = 1024 const W = 1024
const H = 1024 const H = 1024
dc := gg.NewContext(W, H) dc := gg.NewContext(W, H)
dc.SetSourceRGB(0, 0, 0) dc.SetRGB(0, 0, 0)
dc.Paint() dc.Clear()
for i := 0; i < 1000; i++ { for i := 0; i < 1000; i++ {
x1 := rand.Float64() * W x1 := rand.Float64() * W
y1 := rand.Float64() * H y1 := rand.Float64() * H
@ -22,10 +22,10 @@ func main() {
b := rand.Float64() b := rand.Float64()
a := rand.Float64()*0.5 + 0.5 a := rand.Float64()*0.5 + 0.5
w := rand.Float64()*4 + 1 w := rand.Float64()*4 + 1
dc.SetSourceRGBA(r, g, b, a) dc.SetRGBA(r, g, b, a)
dc.SetLineWidth(w) dc.SetLineWidth(w)
dc.Stroke()
dc.DrawLine(x1, y1, x2, y2) dc.DrawLine(x1, y1, x2, y2)
dc.Stroke()
} }
dc.WriteToPNG("out.png") dc.WriteToPNG("out.png")
} }

View File

@ -23,17 +23,17 @@ func main() {
n := 5 n := 5
points := Polygon(n, 512, 512, 400) points := Polygon(n, 512, 512, 400)
dc := gg.NewContext(1024, 1024) dc := gg.NewContext(1024, 1024)
dc.SetSourceRGB(1, 1, 1) dc.SetHexColor("fff")
dc.Paint() dc.Clear()
for i := 0; i < n+1; i++ { for i := 0; i < n+1; i++ {
index := (i * 2) % n index := (i * 2) % n
p := points[index] p := points[index]
dc.LineTo(p.X, p.Y) dc.LineTo(p.X, p.Y)
} }
dc.SetSourceRGBA(0, 0.5, 0, 1) dc.SetRGBA(0, 0.5, 0, 1)
dc.SetFillRule(gg.FillRuleEvenOdd) dc.SetFillRule(gg.FillRuleEvenOdd)
dc.FillPreserve() dc.FillPreserve()
dc.SetSourceRGBA(0, 1, 0, 0.5) dc.SetRGBA(0, 1, 0, 0.5)
dc.SetLineWidth(16) dc.SetLineWidth(16)
dc.Stroke() dc.Stroke()
dc.WriteToPNG("out.png") dc.WriteToPNG("out.png")

View File

@ -4,9 +4,9 @@ import "github.com/fogleman/gg"
func main() { func main() {
dc := gg.NewContext(1000, 1000) dc := gg.NewContext(1000, 1000)
dc.SetSourceRGB(1, 1, 1) dc.SetRGB(1, 1, 1)
dc.Paint() dc.Clear()
dc.SetSourceRGB(0, 0, 0) dc.SetRGB(0, 0, 0)
dc.LoadFontFace("/Library/Fonts/Impact.ttf", 96) dc.LoadFontFace("/Library/Fonts/Impact.ttf", 96)
s := "Hello, world!" s := "Hello, world!"
w := dc.MeasureString(s) w := dc.MeasureString(s)

25
util.go
View File

@ -1,10 +1,13 @@
package gg package gg
import ( import (
"fmt"
"image" "image"
"image/draw"
"image/png" "image/png"
"io/ioutil" "io/ioutil"
"os" "os"
"strings"
"github.com/golang/freetype/truetype" "github.com/golang/freetype/truetype"
@ -21,6 +24,28 @@ func writeToPNG(path string, im image.Image) error {
return png.Encode(file, im) return png.Encode(file, im)
} }
func imageToRGBA(src image.Image) *image.RGBA {
dst := image.NewRGBA(src.Bounds())
draw.Draw(dst, dst.Rect, src, image.ZP, draw.Src)
return dst
}
func parseHexColor(x string) (r, g, b int) {
x = strings.TrimPrefix(x, "#")
if len(x) == 3 {
format := "%1x%1x%1x"
fmt.Sscanf(x, format, &r, &g, &b)
r |= r << 4
g |= g << 4
b |= b << 4
}
if len(x) == 6 {
format := "%02x%02x%02x"
fmt.Sscanf(x, format, &r, &g, &b)
}
return
}
func fp(x, y float64) fixed.Point26_6 { func fp(x, y float64) fixed.Point26_6 {
return fixed.Point26_6{fixed.Int26_6(x * 64), fixed.Int26_6(y * 64)} return fixed.Point26_6{fixed.Int26_6(x * 64), fixed.Int26_6(y * 64)}
} }