commit
cec365b96a
28 changed files with 6336 additions and 39 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -20,3 +20,4 @@ _test*
|
|||
**/*.dll
|
||||
**/core*[0-9]
|
||||
.private
|
||||
output
|
||||
|
|
15
README.md
15
README.md
|
@ -10,6 +10,8 @@ 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).
|
||||
|
||||
Package draw2d follows the conventions of the [HTML Canvas 2D Context](http://www.w3.org/TR/2dcontext/) for coordinate system, angles, etc...
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
|
@ -72,6 +74,19 @@ There are more examples here: https://github.com/llgcode/draw2d.samples
|
|||
|
||||
Drawing on opengl is provided by the draw2dgl package.
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
The samples are run as tests from the root package folder `draw2d` by:
|
||||
```
|
||||
go test ./...
|
||||
```
|
||||
Or if you want to run with test coverage:
|
||||
```
|
||||
go test -cover ./... | grep -v "no test"
|
||||
```
|
||||
This will generate output by the different backends in the output folder.
|
||||
|
||||
Acknowledgments
|
||||
---------------
|
||||
|
||||
|
|
12
draw2d.go
12
draw2d.go
|
@ -13,6 +13,8 @@
|
|||
// All drawing operations can be transformed by affine transformations
|
||||
// (scale, rotation, translation).
|
||||
//
|
||||
// Package draw2d follows the conventions of http://www.w3.org/TR/2dcontext for coordinate system, angles, etc...
|
||||
//
|
||||
// Installation
|
||||
//
|
||||
// To install or update the package draw2d on your system, run:
|
||||
|
@ -49,6 +51,16 @@
|
|||
// Drawing on opengl is provided by the draw2dgl package.
|
||||
// See subdirectories at the bottom of this page.
|
||||
//
|
||||
// Testing
|
||||
//
|
||||
// The samples are run as tests from the root package folder `draw2d` by:
|
||||
// go test ./...
|
||||
//
|
||||
// Or if you want to run with test coverage:
|
||||
// go test -cover ./... | grep -v "no test"
|
||||
//
|
||||
// This will generate output by the different backends in the output folder.
|
||||
//
|
||||
// Acknowledgments
|
||||
//
|
||||
// Laurent Le Goff wrote this library, inspired by Postscript and
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"code.google.com/p/freetype-go/freetype/truetype"
|
||||
|
@ -240,8 +239,7 @@ func (gc *GraphicContext) SetFontData(fontData draw2d.FontData) {
|
|||
}
|
||||
fn := draw2d.FontFileName(fontData)
|
||||
fn = fn[:len(fn)-4]
|
||||
jfn := filepath.Join(draw2d.GetFontFolder(), fn+".json")
|
||||
gc.pdf.AddFont(fn, style, jfn)
|
||||
gc.pdf.AddFont(fn, style, fn+".json")
|
||||
}
|
||||
|
||||
// SetFontSize sets the font size in points (as in ``a 12 point font'').
|
||||
|
|
|
@ -6,14 +6,13 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d.samples"
|
||||
"github.com/llgcode/draw2d.samples/android"
|
||||
"github.com/llgcode/draw2d.samples/frameimage"
|
||||
"github.com/llgcode/draw2d.samples/gopher"
|
||||
"github.com/llgcode/draw2d.samples/helloworld"
|
||||
"github.com/llgcode/draw2d.samples/line"
|
||||
"github.com/llgcode/draw2d.samples/linecapjoin"
|
||||
"github.com/llgcode/draw2d.samples/postscript"
|
||||
"github.com/llgcode/draw2d/samples/android"
|
||||
"github.com/llgcode/draw2d/samples/frameimage"
|
||||
"github.com/llgcode/draw2d/samples/gopher"
|
||||
"github.com/llgcode/draw2d/samples/helloworld"
|
||||
"github.com/llgcode/draw2d/samples/line"
|
||||
"github.com/llgcode/draw2d/samples/linecapjoin"
|
||||
"github.com/llgcode/draw2d/samples/postscript"
|
||||
)
|
||||
|
||||
func TestSampleAndroid(t *testing.T) {
|
||||
|
@ -26,9 +25,9 @@ func TestSampleGopher(t *testing.T) {
|
|||
|
||||
func TestSampleHelloWorld(t *testing.T) {
|
||||
// Set the global folder for searching fonts
|
||||
// The pdf backend needs for every ttf file its corresponding json
|
||||
// file which is generated by gofpdf/makefont.
|
||||
draw2d.SetFontFolder(samples.Dir("helloworld", "../"))
|
||||
// The pdf backend needs for every ttf file its corresponding
|
||||
// json/.z file which is generated by gofpdf/makefont.
|
||||
draw2d.SetFontFolder("../resource/font")
|
||||
test(t, helloworld.Main)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
package draw2dpdf_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/llgcode/draw2d"
|
||||
|
@ -18,18 +17,20 @@ func test(t *testing.T, draw sample) {
|
|||
dest := draw2dpdf.NewPdf("L", "mm", "A4")
|
||||
gc := draw2dpdf.NewGraphicContext(dest)
|
||||
// Draw sample
|
||||
fn, err := draw(gc, "pdf")
|
||||
output, err := draw(gc, "pdf")
|
||||
if err != nil {
|
||||
t.Errorf("Drawing %q failed: %v", fn, err)
|
||||
t.Errorf("Drawing %q failed: %v", output, err)
|
||||
return
|
||||
}
|
||||
// Save to pdf only if it doesn't exist because of git
|
||||
if _, err = os.Stat(fn); err == nil {
|
||||
t.Skipf("Saving %q skipped, as it exists already. (Git would consider it modified.)", fn)
|
||||
return
|
||||
}
|
||||
err = draw2dpdf.SaveToPdfFile(fn, dest)
|
||||
/*
|
||||
// Save to pdf only if it doesn't exist because of git
|
||||
if _, err = os.Stat(output); err == nil {
|
||||
t.Skipf("Saving %q skipped, as it exists already. (Git would consider it modified.)", output)
|
||||
return
|
||||
}
|
||||
*/
|
||||
err = draw2dpdf.SaveToPdfFile(output, dest)
|
||||
if err != nil {
|
||||
t.Errorf("Saving %q failed: %v", fn, err)
|
||||
t.Errorf("Saving %q failed: %v", output, err)
|
||||
}
|
||||
}
|
||||
|
|
3
font.go
3
font.go
|
@ -7,6 +7,7 @@ import (
|
|||
"io/ioutil"
|
||||
"log"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"code.google.com/p/freetype-go/freetype/truetype"
|
||||
)
|
||||
|
@ -80,7 +81,7 @@ func GetFontFolder() string {
|
|||
}
|
||||
|
||||
func SetFontFolder(folder string) {
|
||||
fontFolder = folder
|
||||
fontFolder = filepath.Clean(folder)
|
||||
}
|
||||
|
||||
func loadFont(fontFileName string) *truetype.Font {
|
||||
|
|
0
output/.empty
Normal file
0
output/.empty
Normal file
1
resource/font/luximbi.json
Normal file
1
resource/font/luximbi.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"Tp":"TrueType","Name":"LuxiMono-BoldOblique","Desc":{"Ascent":783,"Descent":-205,"CapHeight":783,"Flags":97,"FontBBox":{"Xmin":-29,"Ymin":-211,"Xmax":764,"Ymax":1012},"ItalicAngle":-8,"StemV":120,"MissingWidth":600},"Up":0,"Ut":0,"Cw":[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,653,600,653,600,600,653,600,653,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600],"Enc":"cp1252","Diff":"","File":"luximbi.z","Size1":0,"Size2":0,"OriginalSize":69872,"I":0,"N":0,"DiffN":0}
|
BIN
resource/font/luximbi.z
Normal file
BIN
resource/font/luximbi.z
Normal file
Binary file not shown.
BIN
resource/image/gopher.png
Normal file
BIN
resource/image/gopher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
2733
resource/image/tiger.ps
Normal file
2733
resource/image/tiger.ps
Normal file
File diff suppressed because it is too large
Load diff
88
samples/README.md
Normal file
88
samples/README.md
Normal file
|
@ -0,0 +1,88 @@
|
|||
draw2d samples
|
||||
==============
|
||||
|
||||
Various Samples to using draw2d
|
||||
|
||||
Using the image backend
|
||||
-----------------------
|
||||
|
||||
The following Go code draws the android sample on a png image:
|
||||
|
||||
```
|
||||
import (
|
||||
"image"
|
||||
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d/samples/android"
|
||||
)
|
||||
|
||||
function main(){}
|
||||
// Initialize the graphic context on an RGBA image
|
||||
dest := image.NewRGBA(image.Rect(0, 0, 297, 210.0))
|
||||
gc := draw2d.NewGraphicContext(dest)
|
||||
// Draw Android logo
|
||||
fn, err := android.Main(gc, "png")
|
||||
if err != nil {
|
||||
t.Errorf("Drawing %q failed: %v", fn, err)
|
||||
return
|
||||
}
|
||||
// Save to png
|
||||
err = draw2d.SaveToPngFile(fn, dest)
|
||||
if err != nil {
|
||||
t.Errorf("Saving %q failed: %v", fn, err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Using the pdf backend
|
||||
---------------------
|
||||
|
||||
The following Go code draws the android sample on a pdf document:
|
||||
|
||||
```
|
||||
import (
|
||||
"image"
|
||||
|
||||
"github.com/llgcode/draw2d/draw2dpdf"
|
||||
"github.com/llgcode/draw2d/samples/android"
|
||||
)
|
||||
|
||||
function main(){}
|
||||
// Initialize the graphic context on a pdf document
|
||||
dest := draw2dpdf.NewPdf("L", "mm", "A4")
|
||||
gc := draw2dpdf.NewGraphicContext(dest)
|
||||
// Draw Android logo
|
||||
fn, err := android.Main(gc, "png")
|
||||
if err != nil {
|
||||
t.Errorf("Drawing %q failed: %v", fn, err)
|
||||
return
|
||||
}
|
||||
// Save to pdf
|
||||
err = draw2dpdf.SaveToPdfFile(fn, dest)
|
||||
if err != nil {
|
||||
t.Errorf("Saving %q failed: %v", fn, err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
These samples are run as tests from the root package folder `draw2d` by:
|
||||
```
|
||||
go test ./...
|
||||
```
|
||||
Or if you want to run with test coverage:
|
||||
```
|
||||
go test -cover ./... | grep -v "no test"
|
||||
```
|
||||
The following files are responsible to run the image tests:
|
||||
```
|
||||
draw2d/test_test.go
|
||||
draw2d/samples_test.go
|
||||
```
|
||||
The following files are responsible to run the pdf tests:
|
||||
```
|
||||
draw2d/pdf/test_test.go
|
||||
draw2dpdf/samples_test.go
|
||||
```
|
75
samples/android/android.go
Normal file
75
samples/android/android.go
Normal file
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||
// created: 21/11/2010 by Laurent Le Goff
|
||||
|
||||
// Package android draws an android avatar.
|
||||
package android
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"math"
|
||||
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d/samples"
|
||||
)
|
||||
|
||||
// Main draws a droid and returns the filename. This should only be
|
||||
// used during testing.
|
||||
func Main(gc draw2d.GraphicContext, ext string) (string, error) {
|
||||
// Draw the droid
|
||||
Draw(gc, 65, 0)
|
||||
|
||||
// Return the output filename
|
||||
return samples.Output("android", ext), nil
|
||||
}
|
||||
|
||||
// Draw the droid on a certain position.
|
||||
func Draw(gc draw2d.GraphicContext, x, y float64) {
|
||||
// set the fill and stroke color of the droid
|
||||
gc.SetFillColor(color.RGBA{0x44, 0xff, 0x44, 0xff})
|
||||
gc.SetStrokeColor(color.RGBA{0x44, 0x44, 0x44, 0xff})
|
||||
|
||||
// set line properties
|
||||
gc.SetLineCap(draw2d.RoundCap)
|
||||
gc.SetLineWidth(5)
|
||||
|
||||
// head
|
||||
gc.MoveTo(x+30, y+70)
|
||||
gc.ArcTo(x+80, y+70, 50, 50, 180*(math.Pi/180), 180*(math.Pi/180))
|
||||
gc.Close()
|
||||
gc.FillStroke()
|
||||
gc.MoveTo(x+60, y+25)
|
||||
gc.LineTo(x+50, y+10)
|
||||
gc.MoveTo(x+100, y+25)
|
||||
gc.LineTo(x+110, y+10)
|
||||
gc.Stroke()
|
||||
|
||||
// left eye
|
||||
draw2d.Circle(gc, x+60, y+45, 5)
|
||||
gc.FillStroke()
|
||||
|
||||
// right eye
|
||||
draw2d.Circle(gc, x+100, y+45, 5)
|
||||
gc.FillStroke()
|
||||
|
||||
// body
|
||||
draw2d.RoundRect(gc, x+30, y+75, x+30+100, y+75+90, 10, 10)
|
||||
gc.FillStroke()
|
||||
draw2d.Rect(gc, x+30, y+75, x+30+100, y+75+80)
|
||||
gc.FillStroke()
|
||||
|
||||
// left arm
|
||||
draw2d.RoundRect(gc, x+5, y+80, x+5+20, y+80+70, 10, 10)
|
||||
gc.FillStroke()
|
||||
|
||||
// right arm
|
||||
draw2d.RoundRect(gc, x+135, y+80, x+135+20, y+80+70, 10, 10)
|
||||
gc.FillStroke()
|
||||
|
||||
// left leg
|
||||
draw2d.RoundRect(gc, x+50, y+150, x+50+20, y+150+50, 10, 10)
|
||||
gc.FillStroke()
|
||||
|
||||
// right leg
|
||||
draw2d.RoundRect(gc, x+90, y+150, x+90+20, y+150+50, 10, 10)
|
||||
gc.FillStroke()
|
||||
}
|
8
samples/appengine/app.yaml
Normal file
8
samples/appengine/app.yaml
Normal file
|
@ -0,0 +1,8 @@
|
|||
application: draw2d-test
|
||||
version: 1
|
||||
runtime: go
|
||||
api_version: go1
|
||||
|
||||
handlers:
|
||||
- url: /.*
|
||||
script: _go_app
|
73
samples/appengine/server.go
Normal file
73
samples/appengine/server.go
Normal file
|
@ -0,0 +1,73 @@
|
|||
// +build appengine
|
||||
|
||||
// Package gae demonstrates draw2d on a Google appengine server.
|
||||
package gae
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/png"
|
||||
"net/http"
|
||||
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d/draw2dpdf"
|
||||
"github.com/llgcode/draw2d/samples/android"
|
||||
|
||||
"appengine"
|
||||
)
|
||||
|
||||
type appError struct {
|
||||
Error error
|
||||
Message string
|
||||
Code int
|
||||
}
|
||||
|
||||
type appHandler func(http.ResponseWriter, *http.Request) *appError
|
||||
|
||||
func (fn appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if e := fn(w, r); e != nil { // e is *appError, not os.Error.
|
||||
c := appengine.NewContext(r)
|
||||
c.Errorf("%v", e.Error)
|
||||
http.Error(w, e.Message, e.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
http.Handle("/pdf", appHandler(pdf))
|
||||
http.Handle("/png", appHandler(imgPng))
|
||||
}
|
||||
|
||||
func pdf(w http.ResponseWriter, r *http.Request) *appError {
|
||||
w.Header().Set("Content-type", "application/pdf")
|
||||
|
||||
// Initialize the graphic context on an pdf document
|
||||
dest := draw2dpdf.NewPdf("L", "mm", "A4")
|
||||
gc := draw2dpdf.NewGraphicContext(dest)
|
||||
|
||||
// Draw sample
|
||||
android.Draw(gc, 65, 0)
|
||||
|
||||
err := dest.Output(w)
|
||||
if err != nil {
|
||||
return &appError{err, fmt.Sprintf("Can't write: %s", err), 500}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func imgPng(w http.ResponseWriter, r *http.Request) *appError {
|
||||
w.Header().Set("Content-type", "image/png")
|
||||
|
||||
// Initialize the graphic context on an RGBA image
|
||||
dest := image.NewRGBA(image.Rect(0, 0, 297, 210.0))
|
||||
gc := draw2d.NewGraphicContext(dest)
|
||||
|
||||
// Draw sample
|
||||
android.Draw(gc, 65, 0)
|
||||
|
||||
err := png.Encode(w, dest)
|
||||
if err != nil {
|
||||
return &appError{err, fmt.Sprintf("Can't encode: %s", err), 500}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
59
samples/frameimage/frameimage.go
Normal file
59
samples/frameimage/frameimage.go
Normal file
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||
// created: 21/11/2010 by Laurent Le Goff, Stani Michiels
|
||||
|
||||
// Package frameimage centers a png image and rotates it.
|
||||
package frameimage
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d/samples"
|
||||
)
|
||||
|
||||
// Main draws the image frame and returns the filename.
|
||||
// This should only be used during testing.
|
||||
func Main(gc draw2d.GraphicContext, ext string) (string, error) {
|
||||
// Margin between the image and the frame
|
||||
const margin = 30
|
||||
// Line width od the frame
|
||||
const lineWidth = 3
|
||||
|
||||
// Gopher image
|
||||
gopher := samples.Resource("image", "gopher.png", ext)
|
||||
|
||||
// Draw gopher
|
||||
err := Draw(gc, gopher, 297, 210, margin, lineWidth)
|
||||
|
||||
// Return the output filename
|
||||
return samples.Output("frameimage", ext), err
|
||||
}
|
||||
|
||||
// Draw the image frame with certain parameters.
|
||||
func Draw(gc draw2d.GraphicContext, png string,
|
||||
dw, dh, margin, lineWidth float64) error {
|
||||
// Draw frame
|
||||
draw2d.RoundRect(gc, lineWidth, lineWidth,
|
||||
dw-lineWidth, dh-lineWidth, 100, 100)
|
||||
gc.SetLineWidth(lineWidth)
|
||||
gc.FillStroke()
|
||||
|
||||
// load the source image
|
||||
source, err := draw2d.LoadFromPngFile(png)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Size of source image
|
||||
sw, sh := float64(source.Bounds().Dx()), float64(source.Bounds().Dy())
|
||||
// Draw image to fit in the frame
|
||||
// TODO Seems to have a transform bug here on draw image
|
||||
scale := math.Min((dw-margin*2)/sw, (dh-margin*2)/sh)
|
||||
gc.Save()
|
||||
gc.Translate((dw-sw*scale)/2, (dh-sh*scale)/2)
|
||||
gc.Scale(scale, scale)
|
||||
gc.Rotate(0.2)
|
||||
|
||||
gc.DrawImage(source)
|
||||
gc.Restore()
|
||||
return nil
|
||||
}
|
63
samples/gopher/gopher.go
Normal file
63
samples/gopher/gopher.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||
// created: 21/11/2010 by Laurent Le Goff
|
||||
|
||||
// Package gopher draws a gopher avatar based on a svg of:
|
||||
// https://github.com/golang-samples/gopher-vector/
|
||||
package gopher
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d/samples"
|
||||
)
|
||||
|
||||
// Main draws a left hand and ear of a gopher. Afterwards it returns
|
||||
// the filename. This should only be during testing.
|
||||
func Main(gc draw2d.GraphicContext, ext string) (string, error) {
|
||||
gc.Save()
|
||||
gc.Scale(0.5, 0.5)
|
||||
// Draw a (partial) gopher
|
||||
Draw(gc)
|
||||
gc.Restore()
|
||||
|
||||
// Return the output filename
|
||||
return samples.Output("gopher", ext), nil
|
||||
}
|
||||
|
||||
// Draw a left hand and ear of a gopher using a gc thanks to
|
||||
// https://github.com/golang-samples/gopher-vector/
|
||||
func Draw(gc draw2d.GraphicContext) {
|
||||
// Initialize Stroke Attribute
|
||||
gc.SetLineWidth(3)
|
||||
gc.SetLineCap(draw2d.RoundCap)
|
||||
gc.SetStrokeColor(color.Black)
|
||||
|
||||
// Left hand
|
||||
// <path fill-rule="evenodd" clip-rule="evenodd" fill="#F6D2A2" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
|
||||
// M10.634,300.493c0.764,15.751,16.499,8.463,23.626,3.539c6.765-4.675,8.743-0.789,9.337-10.015
|
||||
// c0.389-6.064,1.088-12.128,0.744-18.216c-10.23-0.927-21.357,1.509-29.744,7.602C10.277,286.542,2.177,296.561,10.634,300.493"/>
|
||||
gc.SetFillColor(color.RGBA{0xF6, 0xD2, 0xA2, 0xff})
|
||||
gc.MoveTo(10.634, 300.493)
|
||||
gc.RCubicCurveTo(0.764, 15.751, 16.499, 8.463, 23.626, 3.539)
|
||||
gc.RCubicCurveTo(6.765, -4.675, 8.743, -0.789, 9.337, -10.015)
|
||||
gc.RCubicCurveTo(0.389, -6.064, 1.088, -12.128, 0.744, -18.216)
|
||||
gc.RCubicCurveTo(-10.23, -0.927, -21.357, 1.509, -29.744, 7.602)
|
||||
gc.CubicCurveTo(10.277, 286.542, 2.177, 296.561, 10.634, 300.493)
|
||||
gc.FillStroke()
|
||||
|
||||
// <path fill-rule="evenodd" clip-rule="evenodd" fill="#C6B198" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
|
||||
// M10.634,300.493c2.29-0.852,4.717-1.457,6.271-3.528"/>
|
||||
gc.MoveTo(10.634, 300.493)
|
||||
gc.RCubicCurveTo(2.29, -0.852, 4.717, -1.457, 6.271, -3.528)
|
||||
gc.Stroke()
|
||||
|
||||
// Left Ear
|
||||
// <path fill-rule="evenodd" clip-rule="evenodd" fill="#6AD7E5" stroke="#000000" stroke-width="3" stroke-linecap="round" d="
|
||||
// M46.997,112.853C-13.3,95.897,31.536,19.189,79.956,50.74L46.997,112.853z"/>
|
||||
gc.MoveTo(46.997, 112.853)
|
||||
gc.CubicCurveTo(-13.3, 95.897, 31.536, 19.189, 79.956, 50.74)
|
||||
gc.LineTo(46.997, 112.853)
|
||||
gc.Close()
|
||||
gc.Stroke()
|
||||
}
|
51
samples/helloworld/helloworld.go
Normal file
51
samples/helloworld/helloworld.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||
// created: 21/11/2010 by Laurent Le Goff, Stani Michiels
|
||||
|
||||
// Package helloworld displays "Hello World" twice (one rotated) in a
|
||||
// rounded rectangle.
|
||||
package helloworld
|
||||
|
||||
import (
|
||||
"image"
|
||||
"image/color"
|
||||
"math"
|
||||
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d/samples"
|
||||
)
|
||||
|
||||
// Main draws "Hello World" and returns the filename. This should only be
|
||||
// used during testing.
|
||||
func Main(gc draw2d.GraphicContext, ext string) (string, error) {
|
||||
// Draw hello world
|
||||
Draw(gc)
|
||||
|
||||
// Return the output filename
|
||||
return samples.Output("helloworld", ext), nil
|
||||
}
|
||||
|
||||
// Draw "Hello World"
|
||||
func Draw(gc draw2d.GraphicContext) {
|
||||
// Draw a rounded rectangle using default colors
|
||||
draw2d.RoundRect(gc, 5, 5, 292, 205, 10, 10)
|
||||
gc.FillStroke()
|
||||
|
||||
// Set the font luximbi.ttf
|
||||
gc.SetFontData(draw2d.FontData{
|
||||
Name: "luxi",
|
||||
Family: draw2d.FontFamilyMono,
|
||||
Style: draw2d.FontStyleBold | draw2d.FontStyleItalic})
|
||||
// Set the fill text color to black
|
||||
gc.SetFillColor(image.Black)
|
||||
gc.SetDPI(72)
|
||||
gc.SetFontSize(14)
|
||||
// Display Hello World
|
||||
gc.FillStringAt("Hello World", 8, 52)
|
||||
|
||||
gc.Save()
|
||||
gc.SetFillColor(color.NRGBA{0xFF, 0x33, 0x33, 0xFF})
|
||||
gc.Translate(145, 105)
|
||||
gc.Rotate(math.Pi / 4)
|
||||
gc.FillStringAt("Hello World", 0, 0)
|
||||
gc.Restore()
|
||||
}
|
116
samples/helloworldgl/helloworldgl.go
Normal file
116
samples/helloworldgl/helloworldgl.go
Normal file
|
@ -0,0 +1,116 @@
|
|||
// Open an OpenGl window and display a rectangle using a OpenGl GraphicContext
|
||||
package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"log"
|
||||
"runtime"
|
||||
|
||||
"github.com/go-gl/gl/v2.1/gl"
|
||||
"github.com/go-gl/glfw/v3.1/glfw"
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d/draw2dgl"
|
||||
)
|
||||
|
||||
var (
|
||||
// global rotation
|
||||
rotate int
|
||||
width, height int
|
||||
redraw = true
|
||||
font draw2d.FontData
|
||||
)
|
||||
|
||||
func reshape(window *glfw.Window, w, h int) {
|
||||
gl.ClearColor(1, 1, 1, 1)
|
||||
/* Establish viewing area to cover entire window. */
|
||||
gl.Viewport(0, 0, int32(w), int32(h))
|
||||
/* PROJECTION Matrix mode. */
|
||||
gl.MatrixMode(gl.PROJECTION)
|
||||
/* Reset project matrix. */
|
||||
gl.LoadIdentity()
|
||||
/* Map abstract coords directly to window coords. */
|
||||
gl.Ortho(0, float64(w), 0, float64(h), -1, 1)
|
||||
/* Invert Y axis so increasing Y goes down. */
|
||||
gl.Scalef(1, -1, 1)
|
||||
/* Shift origin up to upper-left corner. */
|
||||
gl.Translatef(0, float32(-h), 0)
|
||||
gl.Enable(gl.BLEND)
|
||||
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
||||
gl.Disable(gl.DEPTH_TEST)
|
||||
width, height = w, h
|
||||
redraw = true
|
||||
}
|
||||
|
||||
// Ask to refresh
|
||||
func invalidate() {
|
||||
redraw = true
|
||||
}
|
||||
|
||||
func display() {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||
|
||||
gl.LineWidth(1)
|
||||
gc := draw2dgl.NewGraphicContext(width, height)
|
||||
gc.SetFontData(draw2d.FontData{
|
||||
Name: "luxi",
|
||||
Family: draw2d.FontFamilyMono,
|
||||
Style: draw2d.FontStyleBold | draw2d.FontStyleItalic})
|
||||
|
||||
gc.BeginPath()
|
||||
draw2d.RoundRect(gc, 200, 200, 600, 600, 100, 100)
|
||||
|
||||
gc.SetFillColor(color.RGBA{0, 0, 0, 0xff})
|
||||
gc.Fill()
|
||||
|
||||
gl.Flush() /* Single buffered, so needs a flush. */
|
||||
}
|
||||
|
||||
func init() {
|
||||
runtime.LockOSThread()
|
||||
}
|
||||
|
||||
func main() {
|
||||
err := glfw.Init()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer glfw.Terminate()
|
||||
width, height = 800, 800
|
||||
window, err := glfw.CreateWindow(width, height, "Show RoundedRect", nil, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
window.MakeContextCurrent()
|
||||
window.SetSizeCallback(reshape)
|
||||
window.SetKeyCallback(onKey)
|
||||
window.SetCharCallback(onChar)
|
||||
|
||||
glfw.SwapInterval(1)
|
||||
|
||||
err = gl.Init()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
reshape(window, width, height)
|
||||
for !window.ShouldClose() {
|
||||
if redraw {
|
||||
display()
|
||||
window.SwapBuffers()
|
||||
redraw = false
|
||||
}
|
||||
glfw.PollEvents()
|
||||
// time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
func onChar(w *glfw.Window, char rune) {
|
||||
log.Println(char)
|
||||
}
|
||||
func onKey(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
|
||||
switch {
|
||||
case key == glfw.KeyEscape && action == glfw.Press,
|
||||
key == glfw.KeyQ && action == glfw.Press:
|
||||
w.SetShouldClose(true)
|
||||
}
|
||||
}
|
30
samples/line/line.go
Normal file
30
samples/line/line.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||
// created: 21/11/2010 by Laurent Le Goff, Stani Michiels
|
||||
|
||||
// Package line draws vertically spaced lines.
|
||||
package line
|
||||
|
||||
import (
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d/samples"
|
||||
)
|
||||
|
||||
// Main draws vertically spaced lines and returns the filename.
|
||||
// This should only be used during testing.
|
||||
func Main(gc draw2d.GraphicContext, ext string) (string, error) {
|
||||
// Draw the line
|
||||
for x := 5.0; x < 297; x += 10 {
|
||||
Draw(gc, x, 0, x, 210)
|
||||
}
|
||||
|
||||
// Return the output filename
|
||||
return samples.Output("line", ext), nil
|
||||
}
|
||||
|
||||
// Draw vertically spaced lines
|
||||
func Draw(gc draw2d.GraphicContext, x0, y0, x1, y1 float64) {
|
||||
// Draw a line
|
||||
gc.MoveTo(x0, y0)
|
||||
gc.LineTo(x1, y1)
|
||||
gc.Stroke()
|
||||
}
|
54
samples/linecapjoin/linecapjoin.go
Normal file
54
samples/linecapjoin/linecapjoin.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||
// created: 21/11/2010 by Laurent Le Goff
|
||||
|
||||
// Package linecapjoin demonstrates the different line caps and joins.
|
||||
package linecapjoin
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d/samples"
|
||||
)
|
||||
|
||||
// Main draws the different line caps and joins.
|
||||
// This should only be used during testing.
|
||||
func Main(gc draw2d.GraphicContext, ext string) (string, error) {
|
||||
// Draw the line
|
||||
const offset = 75.0
|
||||
x := 35.0
|
||||
caps := []draw2d.Cap{draw2d.ButtCap, draw2d.SquareCap, draw2d.RoundCap}
|
||||
joins := []draw2d.Join{draw2d.BevelJoin, draw2d.MiterJoin, draw2d.RoundJoin}
|
||||
for i := range caps {
|
||||
Draw(gc, caps[i], joins[i], x, 50, x, 160, offset)
|
||||
x += offset
|
||||
}
|
||||
|
||||
// Return the output filename
|
||||
return samples.Output("linecapjoin", ext), nil
|
||||
}
|
||||
|
||||
// Draw a line with an angle with specified line cap and join
|
||||
func Draw(gc draw2d.GraphicContext, cap draw2d.Cap, join draw2d.Join,
|
||||
x0, y0, x1, y1, offset float64) {
|
||||
gc.Save() // pdf: save & restore needed to isolate caps and joins
|
||||
gc.SetLineCap(cap)
|
||||
gc.SetLineJoin(join)
|
||||
|
||||
// Draw thick line
|
||||
gc.SetStrokeColor(color.NRGBA{0x33, 0x33, 0x33, 0xFF})
|
||||
gc.SetLineWidth(30.0)
|
||||
gc.MoveTo(x0, y0)
|
||||
gc.LineTo((x0+x1)/2+offset, (y0+y1)/2)
|
||||
gc.LineTo(x1, y1)
|
||||
gc.Stroke()
|
||||
|
||||
// Draw thin helping line
|
||||
gc.SetStrokeColor(color.NRGBA{0xFF, 0x33, 0x33, 0xFF})
|
||||
gc.SetLineWidth(2.56)
|
||||
gc.MoveTo(x0, y0)
|
||||
gc.LineTo((x0+x1)/2+offset, (y0+y1)/2)
|
||||
gc.LineTo(x1, y1)
|
||||
gc.Stroke()
|
||||
gc.Restore()
|
||||
}
|
49
samples/postscript/postscript.go
Normal file
49
samples/postscript/postscript.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
// Package postscript reads the tiger.ps file and draws it to a backend.
|
||||
package postscript
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/llgcode/ps"
|
||||
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d/samples"
|
||||
)
|
||||
|
||||
// Main draws the tiger
|
||||
func Main(gc draw2d.GraphicContext, ext string) (string, error) {
|
||||
gc.Save()
|
||||
|
||||
// flip the image
|
||||
gc.Translate(0, 200)
|
||||
gc.Scale(0.35, -0.35)
|
||||
gc.Translate(70, -200)
|
||||
|
||||
// Tiger postscript drawing
|
||||
tiger := samples.Resource("image", "tiger.ps", ext)
|
||||
|
||||
// Draw tiger
|
||||
Draw(gc, tiger)
|
||||
gc.Restore()
|
||||
|
||||
// Return the output filename
|
||||
return samples.Output("postscript", ext), nil
|
||||
}
|
||||
|
||||
// Draw a tiger
|
||||
func Draw(gc draw2d.GraphicContext, filename string) {
|
||||
// Open the postscript
|
||||
src, err := os.OpenFile(filename, 0, 0)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer src.Close()
|
||||
bytes, err := ioutil.ReadAll(src)
|
||||
reader := strings.NewReader(string(bytes))
|
||||
|
||||
// Initialize and interpret the postscript
|
||||
interpreter := ps.NewInterpreter(gc)
|
||||
interpreter.Execute(reader)
|
||||
}
|
114
samples/postscriptgl/postscriptgl.go
Normal file
114
samples/postscriptgl/postscriptgl.go
Normal file
|
@ -0,0 +1,114 @@
|
|||
// Open a OpenGL window and display a tiger interpreting a postscript file
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-gl/gl/v2.1/gl"
|
||||
"github.com/go-gl/glfw/v3.1/glfw"
|
||||
"github.com/llgcode/draw2d/draw2dgl"
|
||||
"github.com/llgcode/ps"
|
||||
)
|
||||
|
||||
var postscriptContent string
|
||||
|
||||
var (
|
||||
width, height int
|
||||
rotate int
|
||||
window *glfw.Window
|
||||
)
|
||||
|
||||
func reshape(window *glfw.Window, w, h int) {
|
||||
gl.ClearColor(1, 1, 1, 1)
|
||||
//fmt.Println(gl.GetString(gl.EXTENSIONS))
|
||||
gl.Viewport(0, 0, int32(w), int32(h)) /* Establish viewing area to cover entire window. */
|
||||
gl.MatrixMode(gl.PROJECTION) /* Start modifying the projection matrix. */
|
||||
gl.LoadIdentity() /* Reset project matrix. */
|
||||
gl.Ortho(0, float64(w), 0, float64(h), -1, 1) /* Map abstract coords directly to window coords. */
|
||||
gl.Scalef(1, -1, 1) /* Invert Y axis so increasing Y goes down. */
|
||||
gl.Translatef(0, float32(-h), 0) /* Shift origin up to upper-left corner. */
|
||||
gl.Enable(gl.BLEND)
|
||||
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
|
||||
gl.Disable(gl.DEPTH_TEST)
|
||||
width, height = w, h
|
||||
}
|
||||
|
||||
func display() {
|
||||
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||
|
||||
lastTime := time.Now()
|
||||
gl.LineWidth(1)
|
||||
gc := draw2dgl.NewGraphicContext(width, height)
|
||||
|
||||
gc.Translate(380, 400)
|
||||
gc.Scale(1, -1)
|
||||
rotate = (rotate + 1) % 360
|
||||
gc.Rotate(float64(rotate) * math.Pi / 180)
|
||||
gc.Translate(-380, -400)
|
||||
|
||||
interpreter := ps.NewInterpreter(gc)
|
||||
reader := strings.NewReader(postscriptContent)
|
||||
|
||||
interpreter.Execute(reader)
|
||||
dt := time.Now().Sub(lastTime)
|
||||
log.Printf("Redraw in : %f ms\n", float64(dt)*1e-6)
|
||||
gl.Flush() /* Single buffered, so needs a flush. */
|
||||
}
|
||||
|
||||
func main() {
|
||||
src, err := os.OpenFile("tiger.ps", 0, 0)
|
||||
if err != nil {
|
||||
log.Println("can't find postscript file.")
|
||||
return
|
||||
}
|
||||
defer src.Close()
|
||||
bytes, err := ioutil.ReadAll(src)
|
||||
postscriptContent = string(bytes)
|
||||
err = glfw.Init()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer glfw.Terminate()
|
||||
|
||||
window, err = glfw.CreateWindow(800, 800, "Show Tiger in OpenGL", nil, nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
window.MakeContextCurrent()
|
||||
window.SetSizeCallback(reshape)
|
||||
window.SetKeyCallback(onKey)
|
||||
|
||||
glfw.SwapInterval(1)
|
||||
|
||||
err = gl.Init()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
reshape(window, 800, 800)
|
||||
for !window.ShouldClose() {
|
||||
display()
|
||||
window.SwapBuffers()
|
||||
glfw.PollEvents()
|
||||
// time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func onKey(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
|
||||
switch {
|
||||
case key == glfw.KeyEscape && action == glfw.Press,
|
||||
key == glfw.KeyQ && action == glfw.Press:
|
||||
w.SetShouldClose(true)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
runtime.LockOSThread()
|
||||
}
|
2733
samples/postscriptgl/tiger.ps
Normal file
2733
samples/postscriptgl/tiger.ps
Normal file
File diff suppressed because it is too large
Load diff
24
samples/samples.go
Normal file
24
samples/samples.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Package samples provides examples which can be used with different
|
||||
// backends. They are also used for testing and coverage of the
|
||||
// draw2d package.
|
||||
package samples
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Resource returns a resource filename for testing.
|
||||
func Resource(folder, filename, ext string) string {
|
||||
var root string
|
||||
if ext == "pdf" {
|
||||
root = "../"
|
||||
}
|
||||
return fmt.Sprintf("%sresource/%s/%s", root, folder, filename)
|
||||
}
|
||||
|
||||
// Output returns the output filename for testing.
|
||||
func Output(name, ext string) string {
|
||||
var root string
|
||||
if ext == "pdf" {
|
||||
root = "../"
|
||||
}
|
||||
return fmt.Sprintf("%soutput/%s.%s", root, name, ext)
|
||||
}
|
|
@ -6,14 +6,13 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/llgcode/draw2d"
|
||||
"github.com/llgcode/draw2d.samples"
|
||||
"github.com/llgcode/draw2d.samples/android"
|
||||
"github.com/llgcode/draw2d.samples/frameimage"
|
||||
"github.com/llgcode/draw2d.samples/gopher"
|
||||
"github.com/llgcode/draw2d.samples/helloworld"
|
||||
"github.com/llgcode/draw2d.samples/line"
|
||||
"github.com/llgcode/draw2d.samples/linecapjoin"
|
||||
"github.com/llgcode/draw2d.samples/postscript"
|
||||
"github.com/llgcode/draw2d/samples/android"
|
||||
"github.com/llgcode/draw2d/samples/frameimage"
|
||||
"github.com/llgcode/draw2d/samples/gopher"
|
||||
"github.com/llgcode/draw2d/samples/helloworld"
|
||||
"github.com/llgcode/draw2d/samples/line"
|
||||
"github.com/llgcode/draw2d/samples/linecapjoin"
|
||||
"github.com/llgcode/draw2d/samples/postscript"
|
||||
)
|
||||
|
||||
func TestSampleAndroid(t *testing.T) {
|
||||
|
@ -26,7 +25,7 @@ func TestSampleGopher(t *testing.T) {
|
|||
|
||||
func TestSampleHelloWorld(t *testing.T) {
|
||||
// Set the global folder for searching fonts
|
||||
draw2d.SetFontFolder(samples.Dir("helloworld", ""))
|
||||
draw2d.SetFontFolder("resource/font")
|
||||
test(t, helloworld.Main)
|
||||
}
|
||||
|
||||
|
@ -38,7 +37,7 @@ func TestSampleLine(t *testing.T) {
|
|||
test(t, line.Main)
|
||||
}
|
||||
|
||||
func TestSampleLineCap(t *testing.T) {
|
||||
func TestSampleLineCapJoin(t *testing.T) {
|
||||
test(t, linecapjoin.Main)
|
||||
}
|
||||
|
||||
|
|
|
@ -16,14 +16,14 @@ func test(t *testing.T, draw sample) {
|
|||
dest := image.NewRGBA(image.Rect(0, 0, 297, 210.0))
|
||||
gc := draw2d.NewGraphicContext(dest)
|
||||
// Draw Android logo
|
||||
fn, err := draw(gc, "png")
|
||||
output, err := draw(gc, "png")
|
||||
if err != nil {
|
||||
t.Errorf("Drawing %q failed: %v", fn, err)
|
||||
t.Errorf("Drawing %q failed: %v", output, err)
|
||||
return
|
||||
}
|
||||
// Save to png
|
||||
err = draw2d.SaveToPngFile(fn, dest)
|
||||
err = draw2d.SaveToPngFile(output, dest)
|
||||
if err != nil {
|
||||
t.Errorf("Saving %q failed: %v", fn, err)
|
||||
t.Errorf("Saving %q failed: %v", output, err)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue