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(DPI))) vg.Initialize(c) return c }
// 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 := draw2dimg.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 }
// 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/skiesel/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 }