diff --git a/README.md b/README.md index 6a3255d..e8e09b7 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,20 @@ draw2d ====== -This package (written in [go](http://golang.org)) provides an API to draw 2d vector forms on [images](http://golang.org/pkg/image). +Package draw2d is a pure [go](http://golang.org) 2D vector graphics library with support for multiple output devices such as [images](http://golang.org/pkg/image) (draw2d), pdf documents (draw2dpdf) and opengl (draw2dopengl), which can also be used on the google app engine. This library is inspired by [postscript](http://www.tailrecursive.org/postscript) and [HTML5 canvas](http://www.w3.org/TR/2dcontext/). +See the [documentation](http://godoc.org/github.com/llgcode/draw2d) for more details. + The package depends on [freetype-go](http://code.google.com/p/freetype-go) package for its rasterization algorithm. +Installation +------------ -Using ------ - -Install [golang](http://golang.org/doc/install) and get `draw2d` +Install [golang](http://golang.org/doc/install). To install or update the package draw2d on your system, run: ``` -go get github.com/llgcode/draw2d +go get -u github.com/llgcode/draw2d ``` and start coding using one of the [Samples](https://github.com/llgcode/draw2d.samples). diff --git a/advanced_path.go b/advanced_path.go index 2610bb8..9569cea 100644 --- a/advanced_path.go +++ b/advanced_path.go @@ -1,14 +1,15 @@ // Copyright 2010 The draw2d Authors. All rights reserved. // created: 13/12/2010 by Laurent Le Goff +//high level path creation + package draw2d import ( "math" ) -//high level path creation - +// Rect draws a rectangle between (x1,y1) and (x2,y2) func Rect(path Path, x1, y1, x2, y2 float64) { path.MoveTo(x1, y1) path.LineTo(x2, y1) @@ -17,6 +18,7 @@ func Rect(path Path, x1, y1, x2, y2 float64) { path.Close() } +// RoundRect draws a rectangle between (x1,y1) and (x2,y2) with rounded corners func RoundRect(path Path, x1, y1, x2, y2, arcWidth, arcHeight float64) { arcWidth = arcWidth / 2 arcHeight = arcHeight / 2 @@ -31,12 +33,14 @@ func RoundRect(path Path, x1, y1, x2, y2, arcWidth, arcHeight float64) { path.Close() } +// Ellipse is drawn with center (cx,cy) and radius (rx,ry) func Ellipse(path Path, cx, cy, rx, ry float64) { path.MoveTo(cx-rx, cy) path.ArcTo(cx, cy, rx, ry, 0, -math.Pi*2) path.Close() } +// Circle is drawn with center (cx,cy) and radius func Circle(path Path, cx, cy, radius float64) { path.MoveTo(cx-radius, cy) path.ArcTo(cx, cy, radius, radius, 0, -math.Pi*2) diff --git a/draw2d.go b/draw2d.go index 424abf4..44c7689 100644 --- a/draw2d.go +++ b/draw2d.go @@ -1,5 +1,68 @@ // Copyright 2010 The draw2d Authors. All rights reserved. // created: 13/12/2010 by Laurent Le Goff -// Package draw2d provides a Graphic Context that can draw vector form on canvas. +// Package draw2d is a pure go 2D vector graphics library with support +// for multiple output devices such as images (draw2d), pdf documents +// (draw2dpdf) and opengl (draw2dopengl), which can also be used on the +// google app engine. +// +// Features +// +// Operations in draw2d include stroking and filling polygons, arcs, +// Bézier curves, drawing images and text rendering with truetype fonts. +// All drawing operations can be transformed by affine transformations +// (scale, rotation, translation). +// +// Installation +// +// To install or update the package draw2d on your system, run: +// go get -u github.com/llgcode/draw2d +// +// Quick Start +// +// Package draw2d itself provides a graphic context that can draw vector +// graphics and text on an image canvas. The following Go code +// generates a simple drawing and saves it to an image file: +// // Initialize the graphic context on an RGBA image +// dest := image.NewRGBA(image.Rect(0, 0, 297, 210.0)) +// gc := draw2d.NewGraphicContext(dest) +// +// // Set some properties +// gc.SetFillColor(color.RGBA{0x44, 0xff, 0x44, 0xff}) +// gc.SetStrokeColor(color.RGBA{0x44, 0x44, 0x44, 0xff}) +// gc.SetLineWidth(5) +// +// // Draw a closed shape +// gc.MoveTo(10, 10) // should always be called first for a new path +// gc.LineTo(100, 50) +// gc.QuadCurveTo(100, 10, 10, 10) +// gc.Close() +// gc.FillStroke() +// +// // Save to file +// draw2d.SaveToPngFile(fn, dest) +// +// There are more examples here: +// https://github.com/llgcode/draw2d.samples +// +// Drawing on pdf documents is provided by the draw2dpdf package. +// Drawing on opengl is provided by the draw2dgl package. +// See subdirectories at the bottom of this page. +// +// Acknowledgments +// +// Laurent Le Goff wrote this library, inspired by postscript and +// HTML5 canvas. He implemented the image and opengl backend. Also +// he created a pure go Postscripter interpreter which can draw to a +// draw2d graphic context (https://github.com/llgcode/ps). Stani +// Michiels implemented the pdf backend. +// +// The package depends on freetype-go package for its rasterization +// algorithm. +// +// Packages using draw2d +// +// - https://github.com/llgcode/ps +// +// - https://github.com/gonum/plot package draw2d diff --git a/draw2dgl/doc.go b/draw2dgl/doc.go new file mode 100644 index 0000000..0d7128a --- /dev/null +++ b/draw2dgl/doc.go @@ -0,0 +1,3 @@ +// Package draw2dgl provides a graphic context that can draw vector +// graphics and text on OpenGL. +package draw2dgl diff --git a/draw2dpdf/doc.go b/draw2dpdf/doc.go index f019d31..b8ccdb4 100644 --- a/draw2dpdf/doc.go +++ b/draw2dpdf/doc.go @@ -1,5 +1,39 @@ // Copyright 2015 The draw2d Authors. All rights reserved. // created: 26/06/2015 by Stani Michiels -// Package draw2dpdf provides a Graphic Context that can draw vector form on pdf file. +// Package draw2dpdf provides a graphic context that can draw vector +// graphics and text on pdf file. +// +// Quick Start +// +// The following Go code generates a simple drawing and saves it to a +// pdf document: +// // Initialize the graphic context on an RGBA image +// dest := draw2dpdf.NewPdf("L", "mm", "A4") +// gc := draw2d.NewGraphicContext(dest) +// +// // Set some properties +// gc.SetFillColor(color.RGBA{0x44, 0xff, 0x44, 0xff}) +// gc.SetStrokeColor(color.RGBA{0x44, 0x44, 0x44, 0xff}) +// gc.SetLineWidth(5) +// +// // Draw a closed shape +// gc.MoveTo(10, 10) // should always be called first for a new path +// gc.LineTo(100, 50) +// gc.QuadCurveTo(100, 10, 10, 10) +// gc.Close() +// gc.FillStroke() +// +// // Save to file +// draw2dpdf.SaveToPdfFile(fn, dest) +// +// There are more examples here: +// https://github.com/llgcode/draw2d.samples +// +// Drawing on images is provided by the draw2d package. +// Drawing on opengl is provided by the draw2dgl package. +// +// Acknowledgments +// +// The pdf backend uses https://github.com/jung-kurt/gofpdf package draw2dpdf diff --git a/draw2dpdf/graphiccontext.go b/draw2dpdf/gc.go similarity index 98% rename from draw2dpdf/graphiccontext.go rename to draw2dpdf/gc.go index f2d196c..ed159de 100644 --- a/draw2dpdf/graphiccontext.go +++ b/draw2dpdf/gc.go @@ -17,14 +17,14 @@ import ( "code.google.com/p/freetype-go/freetype/truetype" - "github.com/llgcode/draw2d" "github.com/jung-kurt/gofpdf" + "github.com/llgcode/draw2d" ) const ( - c255 = 255.0 / 65535.0 // DPI of a pdf document is fixed at 72. - DPI = 72 + DPI = 72 + c255 = 255.0 / 65535.0 ) var ( @@ -89,6 +89,7 @@ func NewGraphicContext(pdf *gofpdf.Fpdf) *GraphicContext { // TODO: add type (tp) as parameter to argument list? func (gc *GraphicContext) DrawImage(image image.Image) { name := strconv.Itoa(int(imageCount)) + imageCount += 1 tp := "PNG" // "JPG", "JPEG", "PNG" and "GIF" b := &bytes.Buffer{} png.Encode(b, image) @@ -168,12 +169,12 @@ func (gc *GraphicContext) StrokeStringAt(text string, x, y float64) (cursor floa return gc.CreateStringPath(text, x, y) } -// Stroke strokes the paths +// Stroke strokes the paths with the color specified by SetStrokeColor func (gc *GraphicContext) Stroke(paths ...*draw2d.PathStorage) { gc.draw("D", paths...) } -// Fill strokes the paths +// Fill fills the paths with the color specified by SetFillColor func (gc *GraphicContext) Fill(paths ...*draw2d.PathStorage) { gc.draw("F", paths...) } diff --git a/draw2dpdf/graphiccontext_test.go b/draw2dpdf/graphiccontext_test.go deleted file mode 100644 index 949f18f..0000000 --- a/draw2dpdf/graphiccontext_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package draw2dpdf - -import ( - "fmt" - "image/color" - - "github.com/llgcode/draw2d" - "github.com/jung-kurt/gofpdf" -) - -func ExampleGraphicContext() { - // Initialize the graphic context on a pdf document - pdf := gofpdf.New("P", "mm", "A4", "../font") - pdf.AddPage() - gc := NewGraphicContext(pdf) - - // some properties - gc.SetFillColor(color.RGBA{0x44, 0xff, 0x44, 0xff}) - gc.SetStrokeColor(color.RGBA{0x44, 0x44, 0x44, 0xff}) - gc.SetLineCap(draw2d.RoundCap) - gc.SetLineWidth(5) - - // draw something - gc.MoveTo(10, 10) // should always be called first for a new path - gc.LineTo(100, 50) - gc.QuadCurveTo(100, 10, 10, 10) - gc.Close() - gc.FillStroke() - fmt.Println(gc.LastPoint()) - - // draw2dpdf.SaveToPdfFile("example.pdf", pdf) - - // Output: - // 10 10 -} diff --git a/draw2dpdf/test_test.go b/draw2dpdf/test_test.go index 923f021..a763c59 100644 --- a/draw2dpdf/test_test.go +++ b/draw2dpdf/test_test.go @@ -11,12 +11,14 @@ import ( "github.com/llgcode/draw2d/draw2dpdf" ) -func test(t *testing.T, sample draw2d.Sample) { +type sample func(gc draw2d.GraphicContext, ext string) (string, error) + +func test(t *testing.T, draw sample) { // Initialize the graphic context on an pdf document dest := draw2dpdf.NewPdf("L", "mm", "A4") gc := draw2dpdf.NewGraphicContext(dest) // Draw sample - fn, err := sample(gc, "pdf") + fn, err := draw(gc, "pdf") if err != nil { t.Errorf("Drawing %q failed: %v", fn, err) return diff --git a/gc.go b/gc.go index 8248cdc..ea1f21f 100644 --- a/gc.go +++ b/gc.go @@ -8,15 +8,17 @@ import ( "image/color" ) +// FillRule defines the type for fill rules type FillRule int const ( + // FillRuleEvenOdd defines the even odd filling rule FillRuleEvenOdd FillRule = iota + // FillRuleWinding defines the non zero winding rule FillRuleWinding ) -type Sample func(gc GraphicContext, ext string) (string, error) - +// GraphicContext describes the interface for the various backends (images, pdf, opengl, ...) type GraphicContext interface { Path // Create a new path diff --git a/image.go b/image.go index 9e50d32..bc4d403 100644 --- a/image.go +++ b/image.go @@ -34,9 +34,7 @@ type ImageGraphicContext struct { DPI int } -/** - * Create a new Graphic context from an image - */ +// NewGraphicContext creates a new Graphic context from an image. func NewGraphicContext(img draw.Image) *ImageGraphicContext { var painter Painter switch selectImage := img.(type) { @@ -48,7 +46,7 @@ func NewGraphicContext(img draw.Image) *ImageGraphicContext { return NewGraphicContextWithPainter(img, painter) } -// Create a new Graphic context from an image and a Painter (see Freetype-go) +// NewGraphicContextWithPainter creates a new Graphic context from an image and a Painter (see Freetype-go) func NewGraphicContextWithPainter(img draw.Image, painter Painter) *ImageGraphicContext { width, height := img.Bounds().Dx(), img.Bounds().Dy() dpi := 92 @@ -274,7 +272,7 @@ func (gc *ImageGraphicContext) paint(rasterizer *raster.Rasterizer, color color. gc.Current.Path.Clear() } -/**** second method ****/ +// Stroke strokes the paths with the color specified by SetStrokeColor func (gc *ImageGraphicContext) Stroke(paths ...*PathStorage) { paths = append(paths, gc.Current.Path) gc.strokeRasterizer.UseNonZeroWinding = true @@ -294,7 +292,7 @@ func (gc *ImageGraphicContext) Stroke(paths ...*PathStorage) { gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor) } -/**** second method ****/ +// Fill fills the paths with the color specified by SetFillColor func (gc *ImageGraphicContext) Fill(paths ...*PathStorage) { paths = append(paths, gc.Current.Path) gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding() @@ -307,7 +305,7 @@ func (gc *ImageGraphicContext) Fill(paths ...*PathStorage) { gc.paint(gc.fillRasterizer, gc.Current.FillColor) } -/* second method */ +// FillStroke first fills the paths and than strokes them func (gc *ImageGraphicContext) FillStroke(paths ...*PathStorage) { gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding() gc.strokeRasterizer.UseNonZeroWinding = true diff --git a/path.go b/path.go index 7167a7c..3a14ab2 100644 --- a/path.go +++ b/path.go @@ -3,25 +3,37 @@ package draw2d +// Path describes the interface for path drawing. type Path interface { - // Return the current point of the path + // LastPoint returns the current point of the path LastPoint() (x, y float64) - // Create a new subpath that start at the specified point + // MoveTo creates a new subpath that start at the specified point MoveTo(x, y float64) - // Create a new subpath that start at the specified point + // RMoveTo creates a new subpath that start at the specified point // relative to the current point RMoveTo(dx, dy float64) - // Add a line to the current subpath + // LineTo adds a line to the current subpath LineTo(x, y float64) - // Add a line to the current subpath + // RLineTo adds a line to the current subpath // relative to the current point RLineTo(dx, dy float64) - + // QuadCurveTo adds a quadratic Bézier curve to the current subpath QuadCurveTo(cx, cy, x, y float64) + // QuadCurveTo adds a quadratic Bézier curve to the current subpath + // relative to the current point RQuadCurveTo(dcx, dcy, dx, dy float64) + // CubicCurveTo adds a cubic Bézier curve to the current subpath CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) + // RCubicCurveTo adds a cubic Bézier curve to the current subpath + // relative to the current point RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float64) + // ArcTo adds an arc to the current subpath ArcTo(cx, cy, rx, ry, startAngle, angle float64) + // RArcTo adds an arc to the current subpath + // relative to the current point RArcTo(dcx, dcy, rx, ry, startAngle, angle float64) + // Close creates a line from the current point to the last MoveTo + // point (if not the same) and mark the path as closed so the + // first and last lines join nicely. Close() } diff --git a/test_test.go b/test_test.go index 33cbfac..ca58f79 100644 --- a/test_test.go +++ b/test_test.go @@ -9,7 +9,9 @@ import ( "github.com/llgcode/draw2d" ) -func test(t *testing.T, draw draw2d.Sample) { +type sample func(gc draw2d.GraphicContext, ext string) (string, error) + +func test(t *testing.T, draw sample) { // Initialize the graphic context on an RGBA image dest := image.NewRGBA(image.Rect(0, 0, 297, 210.0)) gc := draw2d.NewGraphicContext(dest)