From 5af2d1264c0e8303dda31add9e978bbab56777e9 Mon Sep 17 00:00:00 2001 From: Michael Fogleman Date: Thu, 18 Feb 2016 16:02:57 -0500 Subject: [PATCH] initial commit --- context.go | 157 +++++++++++++++++++++++++++++++++++++++++++ examples/example0.go | 22 ++++++ util.go | 26 +++++++ 3 files changed, 205 insertions(+) create mode 100644 context.go create mode 100644 examples/example0.go create mode 100644 util.go diff --git a/context.go b/context.go new file mode 100644 index 0000000..98ec5e3 --- /dev/null +++ b/context.go @@ -0,0 +1,157 @@ +package dd + +import ( + "image" + "image/color" + "image/draw" + + "github.com/golang/freetype/raster" + "golang.org/x/image/math/fixed" +) + +type LineCap int + +const ( + LineCapRound LineCap = iota + LineCapButt + LineCapSquare +) + +type LineJoin int + +const ( + LineJoinRound LineJoin = iota + LineJoinBevel +) + +type Context struct { + width int + height int + im *image.RGBA + color color.Color + path raster.Path + start fixed.Point26_6 + lineWidth float64 + capper raster.Capper + joiner raster.Joiner +} + +func NewContext(width, height int) *Context { + im := image.NewRGBA(image.Rect(0, 0, width, height)) + return &Context{ + width: width, + height: height, + im: im, + color: color.Transparent, + lineWidth: 1, + } +} + +func (c *Context) Image() image.Image { + return c.im +} + +func (c *Context) Width() int { + return c.width +} + +func (c *Context) Height() int { + return c.height +} + +func (c *Context) WriteToPNG(path string) error { + return writeToPNG(path, c.im) +} + +func (c *Context) Paint() { + draw.Draw(c.im, c.im.Bounds(), image.NewUniform(c.color), image.ZP, draw.Src) +} + +func (c *Context) SetSourceRGBA(r, g, b, a float64) { + c.color = color.RGBA{ + uint8(r * 255), + uint8(g * 255), + uint8(b * 255), + uint8(a * 255), + } +} + +func (c *Context) SetSourceRGB(r, g, b float64) { + c.SetSourceRGBA(r, g, b, 1) +} + +func (c *Context) SetLineWidth(lineWidth float64) { + c.lineWidth = lineWidth +} + +func (c *Context) SetLineCap(lineCap LineCap) { + switch lineCap { + case LineCapButt: + c.capper = raster.ButtCapper + case LineCapRound: + c.capper = raster.RoundCapper + case LineCapSquare: + c.capper = raster.SquareCapper + } +} + +func (c *Context) SetLineJoin(lineJoin LineJoin) { + switch lineJoin { + case LineJoinBevel: + c.joiner = raster.BevelJoiner + case LineJoinRound: + c.joiner = raster.RoundJoiner + } +} + +func (c *Context) MoveTo(x, y float64) { + c.start = fp(x, y) + c.path.Start(c.start) +} + +func (c *Context) LineTo(x, y float64) { + c.path.Add1(fp(x, y)) +} + +func (c *Context) QuadraticTo(x1, y1, x2, y2 float64) { + c.path.Add2(fp(x1, y1), fp(x2, y2)) +} + +func (c *Context) ClosePath() { + c.path.Add1(c.start) +} + +func (c *Context) NewPath() { + c.path.Clear() +} + +func (c *Context) StrokePreserve() { + painter := raster.NewRGBAPainter(c.im) + painter.SetColor(c.color) + r := raster.NewRasterizer(c.width, c.height) + r.UseNonZeroWinding = true + r.AddStroke(c.path, fi(c.lineWidth), c.capper, c.joiner) + r.Rasterize(painter) +} + +func (c *Context) Stroke() { + c.StrokePreserve() + c.NewPath() +} + +func (c *Context) FillPreserve() { + // make sure the path is closed + path := make(raster.Path, len(c.path)) + copy(path, c.path) + path.Add1(c.start) + painter := raster.NewRGBAPainter(c.im) + painter.SetColor(c.color) + r := raster.NewRasterizer(c.width, c.height) + r.AddPath(path) + r.Rasterize(painter) +} + +func (c *Context) Fill() { + c.FillPreserve() + c.NewPath() +} diff --git a/examples/example0.go b/examples/example0.go new file mode 100644 index 0000000..848bb3c --- /dev/null +++ b/examples/example0.go @@ -0,0 +1,22 @@ +package main + +import "github.com/fogleman/dd" + +func main() { + dc := dd.NewContext(256, 256) + dc.SetSourceRGBA(1, 0, 0, 0.3) + dc.Paint() + dc.MoveTo(20, 20) + dc.LineTo(236, 236) + dc.LineTo(236, 128) + dc.LineTo(20, 128) + dc.QuadraticTo(0, 64, 120, 20) + dc.SetSourceRGBA(1, 0, 0, 0.8) + dc.FillPreserve() + dc.SetSourceRGB(0, 0, 0) + dc.SetLineWidth(8) + // dc.SetLineCap(dd.LineCapButt) + // dc.SetLineJoin(dd.LineJoinBevel) + dc.Stroke() + dc.WriteToPNG("out.png") +} diff --git a/util.go b/util.go new file mode 100644 index 0000000..0d9611e --- /dev/null +++ b/util.go @@ -0,0 +1,26 @@ +package dd + +import ( + "image" + "image/png" + "os" + + "golang.org/x/image/math/fixed" +) + +func writeToPNG(path string, im image.Image) error { + file, err := os.Create(path) + if err != nil { + return err + } + defer file.Close() + return png.Encode(file, im) +} + +func fp(x, y float64) fixed.Point26_6 { + return fixed.Point26_6{fixed.Int26_6(x * 64), fixed.Int26_6(y * 64)} +} + +func fi(x float64) fixed.Int26_6 { + return fixed.Int26_6(x * 64) +}