// NewImage returns a new image canvas // that draws to the given image. The // minimum point of the given image // should probably be 0,0. func NewImage(img draw.Image, name string) (*Canvas, error) { w := float64(img.Bounds().Max.X - img.Bounds().Min.X) h := float64(img.Bounds().Max.Y - img.Bounds().Min.Y) X, err := xgbutil.NewConn() if err != nil { return nil, err } keybind.Initialize(X) ximg := xgraphics.New(X, image.Rect(0, 0, int(w), int(h))) err = ximg.CreatePixmap() if err != nil { return nil, err } painter := NewPainter(ximg) gc := draw2d.NewGraphicContextWithPainter(ximg, painter) gc.SetDPI(dpi) gc.Scale(1, -1) gc.Translate(0, -h) wid := ximg.XShowExtra(name, true) go func() { xevent.Main(X) }() c := &Canvas{ Canvas: vgimg.NewWith(vgimg.UseImageWithContext(img, gc)), x: X, ximg: ximg, wid: wid, } vg.Initialize(c) return c, nil }
func New(w, h vg.Length) *Canvas { buf := new(bytes.Buffer) c := &Canvas{ svg: svgo.New(buf), w: w, h: h, buf: buf, ht: w.Points(), stk: []context{context{}}, } // This is like svg.Start, except it uses floats // and specifies the units. fmt.Fprintf(buf, `<?xml version="1.0"?> <!-- Generated by SVGo and Plotinum VG --> <svg width="%.*gin" height="%.*gin" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">`+"\n", pr, w/vg.Inch, pr, h/vg.Inch, ) // Swap the origin to the bottom left. // This must be matched with a </g> when saving, // before the closing </svg>. c.svg.Gtransform(fmt.Sprintf("scale(1, -1) translate(0, -%.*g)", pr, h.Dots(c))) vg.Initialize(c) return c }
func TestTextGrobs(t *testing.T) { // Output file, err := os.Create("text.png") if err != nil { t.Fatalf("%", err) } pngCanvas := vgimg.PngCanvas{Canvas: vgimg.New(10*vg.Inch, 8*vg.Inch)} vg.Initialize(pngCanvas) allVP := Viewport{ X0: 0, Y0: 0, Width: 10 * vg.Inch, Height: 8 * vg.Inch, Canvas: pngCanvas, } bg := GrobRect{xmin: 0, ymin: 0, xmax: 1, ymax: 1, fill: BuiltinColors["gray60"]} bg.Draw(allVP) gridVP := allVP.Sub(0.1, 0.1, 0.35, 0.35) drawTextGrid(gridVP, 0) gridVP = allVP.Sub(0.55, 0.1, 0.35, 0.35) drawTextGrid(gridVP, 45./180*math.Pi) gridVP = allVP.Sub(0.1, 0.55, 0.35, 0.35) drawTextGrid(gridVP, 135./180*math.Pi) gridVP = allVP.Sub(0.55, 0.55, 0.35, 0.35) drawTextGrid(gridVP, 90./180*math.Pi) pngCanvas.WriteTo(file) file.Close() }
// New creates a new PDF Canvas. func New(w, h vg.Length) *Canvas { c := &Canvas{ doc: pdf.New(), w: w, h: h, lineVisible: true, } c.page = c.doc.NewPage(unit(w), unit(h)) vg.Initialize(c) return c }
// NewTitle returns a new Canvas with the given title string. func NewTitle(w, h vg.Length, title string) *Canvas { c := &Canvas{ stk: []ctx{ctx{}}, w: w, h: h, buf: new(bytes.Buffer), } c.buf.WriteString("%%!PS-Adobe-3.0 EPSF-3.0\n") c.buf.WriteString("%%Creator github.com/gonum/plot/vg/vgeps\n") c.buf.WriteString("%%Title: " + title + "\n") c.buf.WriteString(fmt.Sprintf("%%%%BoundingBox: 0 0 %.*g %.*g\n", pr, w.Dots(DPI), pr, h.Dots(DPI))) c.buf.WriteString(fmt.Sprintf("%%%%CreationDate: %s\n", time.Now())) c.buf.WriteString("%%Orientation: Portrait\n") c.buf.WriteString("%%EndComments\n") c.buf.WriteString("\n") vg.Initialize(c) return c }
// NewWith returns a new image canvas created according to the specified // options. The currently accepted options are UseWH, // UseDPI, UseImage, and UseImageWithContext. // Each of the options specifies the size of the canvas (UseWH, UseImage), // the resolution of the canvas (UseDPI), or both (useImageWithContext). // If size or resolution are not specified, defaults are used. // It panics if size and resolution are overspecified (i.e., too many options are // passed). func NewWith(o ...option) *Canvas { c := new(Canvas) var g uint32 for _, opt := range o { f := opt(c) if g&f != 0 { panic("incompatible options") } g |= f } if c.dpi == 0 { c.dpi = DefaultDPI } if c.w == 0 { // h should also == 0. if c.img == nil { c.w = DefaultWidth c.h = DefaultHeight } else { w := float64(c.img.Bounds().Max.X - c.img.Bounds().Min.X) h := float64(c.img.Bounds().Max.Y - c.img.Bounds().Min.Y) c.w = vg.Length(w/float64(c.dpi)) * vg.Inch c.h = vg.Length(h/float64(c.dpi)) * vg.Inch } } if c.img == nil { w := c.w / vg.Inch * vg.Length(c.dpi) h := c.h / vg.Inch * vg.Length(c.dpi) c.img = draw.Image(image.NewRGBA(image.Rect(0, 0, int(w+0.5), int(h+0.5)))) } if c.gc == nil { h := float64(c.img.Bounds().Max.Y - c.img.Bounds().Min.Y) c.gc = draw2dimg.NewGraphicContext(c.img) c.gc.SetDPI(c.dpi) c.gc.Scale(1, -1) c.gc.Translate(0, -h) } draw.Draw(c.img, c.img.Bounds(), image.White, image.ZP, draw.Src) c.color = []color.Color{color.Black} vg.Initialize(c) return c }
func TestGraphicGrobs(t *testing.T) { // Output file, err := os.Create("grobs.png") if err != nil { t.Fatalf("%", err) } pngCanvas := vgimg.PngCanvas{Canvas: vgimg.New(10*vg.Inch, 8*vg.Inch)} vg.Initialize(pngCanvas) pngCanvas.Translate(-5*vg.Inch, -4*vg.Inch) dot := func(x, y float64) { pngCanvas.Push() pngCanvas.SetColor(BuiltinColors["red"]) pngCanvas.SetLineWidth(5) var p vg.Path xr := vg.Length(x) * vg.Inch yr := vg.Length(y) * vg.Inch p.Move(xr-5, yr-5) p.Line(xr-5, yr+5) p.Line(xr+5, yr+5) p.Line(xr+5, yr-5) p.Close() pngCanvas.Fill(p) pngCanvas.Pop() } dot(0, 0) dot(5, 0) dot(0, 4) allVP := Viewport{ X0: 0, Y0: 0, Width: 10 * vg.Inch, Height: 8 * vg.Inch, Canvas: pngCanvas, } innerVP := allVP.Sub(0.05, 0.05, 0.9, 0.9) bg := GrobRect{xmin: 0, ymin: 0, xmax: 1, ymax: 1, fill: BuiltinColors["gray80"]} bg.Draw(innerVP) cols := []string{"red", "green", "blue", "cyan", "magenta", "yellow", "white", "gray", "black"} // Draw points in all shapes, three sizes and all builtin colors. points := []Grob{} x, y := 0.1, 0.1 for shape := DotPoint; shape <= StarPoint; shape++ { for size := 2; size < 7; size += 2 { y = 0.05 for _, col := range cols { g := GrobPoint{ x: x, y: y, size: float64(size), shape: shape, color: BuiltinColors[col], } points = append(points, g) y += 0.035 } x += 0.021 } } x, y = 0.02, 0.05 for _, col := range cols { g := GrobText{ x: x, y: y, text: col, size: 10, color: BuiltinColors[col], vjust: 0.5, hjust: 0, } points = append(points, g) y += 0.035 } x, y = 0.121, 0.36 for shape := DotPoint; shape <= StarPoint; shape++ { dy := float64(shape%2) * 0.015 g := GrobText{ x: x, y: y + dy, text: shape.String(), size: 10, color: BuiltinColors["black"], vjust: 0.5, hjust: 0.5, } points = append(points, g) x += 3 * 0.021 } for _, grob := range points { grob.Draw(innerVP) } // Draw lines with different styles and widths. lines := []Grob{} x, y = 0.1, 0.45 for lt := SolidLine; lt <= TwodashLine; lt++ { x = 0.1 for size := 1; size < 8; size += 2 { g := GrobLine{ x0: x, y0: y, x1: x + 0.18, y1: y, size: float64(size), linetype: lt, color: BuiltinColors["black"], } lines = append(lines, g) x += 0.22 } y += 0.04 } for _, grob := range lines { grob.Draw(innerVP) } // Draw rectangles rectVP := innerVP.Sub(0.1, 0.7, 0.4, 0.3) rect := []Grob{} bgr := GrobRect{xmin: 0, ymin: 0, xmax: 1, ymax: 1, fill: BuiltinColors["gray40"]} bgr.Draw(rectVP) x, y = 0.0, 0.0 w, h := 0.5, 0.5 for _, col := range cols { g := GrobRect{ xmin: x, ymin: y, xmax: x + w, ymax: y + h, fill: BuiltinColors[col], } rect = append(rect, g) x += w y += h w /= 2 h /= 2 } for _, grob := range rect { grob.Draw(rectVP) } // Draw path pathVP := innerVP.Sub(0.55, 0.7, 0.4, 0.3) bgp := GrobRect{xmin: 0, ymin: 0, xmax: 1, ymax: 1, fill: BuiltinColors["gray"]} bgp.Draw(pathVP) sin := make([]struct{ x, y float64 }, 50) for i := range sin { k := float64(i) / float64(len(sin)-1) x = k * 2 * math.Pi println(float64(i)/float64(len(sin)), x, math.Sin(x)) y = 0.4 * math.Sin(x) sin[i].x = k sin[i].y = 0.55 + y } g := GrobPath{ points: sin, size: 4, linetype: SolidLine, color: BuiltinColors["white"], } g.Draw(pathVP) cos := make([]struct{ x, y float64 }, 25) for i := range cos { k := float64(i) / float64(len(cos)-1) x = k * 4 * math.Pi y = 0.3 * math.Cos(x) cos[i].x = k cos[i].y = 0.45 + y } g = GrobPath{ points: cos, size: 2, linetype: DottedLine, color: BuiltinColors["green"], } g.Draw(pathVP) pngCanvas.WriteTo(file) file.Close() }