fixed dependencies
This commit is contained in:
423
vendor/gonum.org/v1/plot/vg/vgimg/vgimg.go
generated
vendored
Normal file
423
vendor/gonum.org/v1/plot/vg/vgimg/vgimg.go
generated
vendored
Normal file
@@ -0,0 +1,423 @@
|
||||
// Copyright ©2015 The Gonum Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package vgimg implements the vg.Canvas interface using
|
||||
// git.sr.ht/~sbinet/gg as a backend to output raster images.
|
||||
package vgimg // import "gonum.org/v1/plot/vg/vgimg"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
"image/jpeg"
|
||||
"image/png"
|
||||
"io"
|
||||
|
||||
"git.sr.ht/~sbinet/gg"
|
||||
"golang.org/x/image/tiff"
|
||||
|
||||
"gonum.org/v1/plot/font"
|
||||
"gonum.org/v1/plot/vg"
|
||||
vgdraw "gonum.org/v1/plot/vg/draw"
|
||||
)
|
||||
|
||||
func init() {
|
||||
vgdraw.RegisterFormat("png", func(w, h vg.Length) vg.CanvasWriterTo {
|
||||
return PngCanvas{Canvas: New(w, h)}
|
||||
})
|
||||
|
||||
vgdraw.RegisterFormat("jpg", func(w, h vg.Length) vg.CanvasWriterTo {
|
||||
return JpegCanvas{Canvas: New(w, h)}
|
||||
})
|
||||
|
||||
vgdraw.RegisterFormat("jpeg", func(w, h vg.Length) vg.CanvasWriterTo {
|
||||
return JpegCanvas{Canvas: New(w, h)}
|
||||
})
|
||||
|
||||
vgdraw.RegisterFormat("tif", func(w, h vg.Length) vg.CanvasWriterTo {
|
||||
return TiffCanvas{Canvas: New(w, h)}
|
||||
})
|
||||
|
||||
vgdraw.RegisterFormat("tiff", func(w, h vg.Length) vg.CanvasWriterTo {
|
||||
return TiffCanvas{Canvas: New(w, h)}
|
||||
})
|
||||
}
|
||||
|
||||
// Canvas implements the vg.Canvas interface,
|
||||
// drawing to an image.Image using draw2d.
|
||||
type Canvas struct {
|
||||
ctx *gg.Context
|
||||
img draw.Image
|
||||
w, h vg.Length
|
||||
color []color.Color
|
||||
|
||||
// dpi is the number of dots per inch for this canvas.
|
||||
dpi int
|
||||
|
||||
// width is the current line width.
|
||||
width vg.Length
|
||||
|
||||
// backgroundColor is the background color, set by
|
||||
// UseBackgroundColor.
|
||||
backgroundColor color.Color
|
||||
}
|
||||
|
||||
const (
|
||||
// DefaultDPI is the default dot resolution for image
|
||||
// drawing in dots per inch.
|
||||
DefaultDPI = 96
|
||||
|
||||
// DefaultWidth and DefaultHeight are the default canvas
|
||||
// dimensions.
|
||||
DefaultWidth = 4 * vg.Inch
|
||||
DefaultHeight = 4 * vg.Inch
|
||||
)
|
||||
|
||||
// New returns a new image canvas.
|
||||
func New(w, h vg.Length) *Canvas {
|
||||
return NewWith(UseWH(w, h), UseBackgroundColor(color.White))
|
||||
}
|
||||
|
||||
// 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)
|
||||
c.backgroundColor = color.White
|
||||
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.ctx == nil {
|
||||
c.ctx = gg.NewContextForImage(c.img)
|
||||
c.ctx.SetLineCapButt()
|
||||
c.img = c.ctx.Image().(draw.Image)
|
||||
c.ctx.InvertY()
|
||||
}
|
||||
draw.Draw(c.img, c.img.Bounds(), &image.Uniform{c.backgroundColor}, image.Point{}, draw.Src)
|
||||
c.color = []color.Color{color.Black}
|
||||
vg.Initialize(c)
|
||||
return c
|
||||
}
|
||||
|
||||
// These constants are used to ensure that the options
|
||||
// used when initializing a canvas are compatible with
|
||||
// each other.
|
||||
const (
|
||||
setsDPI uint32 = 1 << iota
|
||||
setsSize
|
||||
setsBackground
|
||||
)
|
||||
|
||||
type option func(*Canvas) uint32
|
||||
|
||||
// UseWH specifies the width and height of the canvas.
|
||||
// The size is rounded up to the nearest pixel.
|
||||
func UseWH(w, h vg.Length) option {
|
||||
return func(c *Canvas) uint32 {
|
||||
if w <= 0 || h <= 0 {
|
||||
panic("w and h must both be > 0.")
|
||||
}
|
||||
c.w, c.h = w, h
|
||||
return setsSize
|
||||
}
|
||||
}
|
||||
|
||||
// UseDPI sets the dots per inch of a canvas. It should only be
|
||||
// used as an option argument when initializing a new canvas.
|
||||
func UseDPI(dpi int) option {
|
||||
if dpi <= 0 {
|
||||
panic("DPI must be > 0.")
|
||||
}
|
||||
return func(c *Canvas) uint32 {
|
||||
c.dpi = dpi
|
||||
return setsDPI
|
||||
}
|
||||
}
|
||||
|
||||
// UseImage specifies an image to create
|
||||
// the canvas from. The
|
||||
// minimum point of the given image
|
||||
// should probably be 0,0.
|
||||
//
|
||||
// Note that a copy of the input image is performed.
|
||||
// This means that modifications applied to the canvas are not reflected
|
||||
// on the original image.
|
||||
func UseImage(img draw.Image) option {
|
||||
return func(c *Canvas) uint32 {
|
||||
c.img = img
|
||||
return setsSize | setsBackground
|
||||
}
|
||||
}
|
||||
|
||||
// UseImageWithContext specifies both an image
|
||||
// and a graphic context to create the canvas from.
|
||||
// The minimum point of the given image
|
||||
// should probably be 0,0.
|
||||
func UseImageWithContext(img draw.Image, ctx *gg.Context) option {
|
||||
return func(c *Canvas) uint32 {
|
||||
c.img = img
|
||||
c.ctx = ctx
|
||||
return setsSize | setsBackground
|
||||
}
|
||||
}
|
||||
|
||||
// UseBackgroundColor specifies the image background color.
|
||||
// Without UseBackgroundColor, the default color is white.
|
||||
func UseBackgroundColor(c color.Color) option {
|
||||
return func(canvas *Canvas) uint32 {
|
||||
canvas.backgroundColor = c
|
||||
return setsBackground
|
||||
}
|
||||
}
|
||||
|
||||
// Image returns the image the canvas is drawing to.
|
||||
//
|
||||
// The dimensions of the returned image must not be modified.
|
||||
func (c *Canvas) Image() draw.Image {
|
||||
return c.img
|
||||
}
|
||||
|
||||
func (c *Canvas) Size() (w, h vg.Length) {
|
||||
return c.w, c.h
|
||||
}
|
||||
|
||||
func (c *Canvas) SetLineWidth(w vg.Length) {
|
||||
c.width = w
|
||||
c.ctx.SetLineWidth(w.Dots(c.DPI()))
|
||||
}
|
||||
|
||||
func (c *Canvas) SetLineDash(ds []vg.Length, offs vg.Length) {
|
||||
dashes := make([]float64, len(ds))
|
||||
for i, d := range ds {
|
||||
dashes[i] = d.Dots(c.DPI())
|
||||
}
|
||||
c.ctx.SetDashOffset(offs.Dots(c.DPI()))
|
||||
c.ctx.SetDash(dashes...)
|
||||
}
|
||||
|
||||
func (c *Canvas) SetColor(clr color.Color) {
|
||||
if clr == nil {
|
||||
clr = color.Black
|
||||
}
|
||||
c.ctx.SetColor(clr)
|
||||
c.color[len(c.color)-1] = clr
|
||||
}
|
||||
|
||||
func (c *Canvas) Rotate(t float64) {
|
||||
c.ctx.Rotate(t)
|
||||
}
|
||||
|
||||
func (c *Canvas) Translate(pt vg.Point) {
|
||||
c.ctx.Translate(pt.X.Dots(c.DPI()), pt.Y.Dots(c.DPI()))
|
||||
}
|
||||
|
||||
func (c *Canvas) Scale(x, y float64) {
|
||||
c.ctx.Scale(x, y)
|
||||
}
|
||||
|
||||
func (c *Canvas) Push() {
|
||||
c.color = append(c.color, c.color[len(c.color)-1])
|
||||
c.ctx.Push()
|
||||
}
|
||||
|
||||
func (c *Canvas) Pop() {
|
||||
c.color = c.color[:len(c.color)-1]
|
||||
c.ctx.Pop()
|
||||
}
|
||||
|
||||
func (c *Canvas) Stroke(p vg.Path) {
|
||||
if c.width <= 0 {
|
||||
return
|
||||
}
|
||||
c.outline(p)
|
||||
c.ctx.Stroke()
|
||||
}
|
||||
|
||||
func (c *Canvas) Fill(p vg.Path) {
|
||||
c.outline(p)
|
||||
c.ctx.Fill()
|
||||
}
|
||||
|
||||
func (c *Canvas) outline(p vg.Path) {
|
||||
for _, comp := range p {
|
||||
switch comp.Type {
|
||||
case vg.MoveComp:
|
||||
c.ctx.MoveTo(comp.Pos.X.Dots(c.DPI()), comp.Pos.Y.Dots(c.DPI()))
|
||||
|
||||
case vg.LineComp:
|
||||
c.ctx.LineTo(comp.Pos.X.Dots(c.DPI()), comp.Pos.Y.Dots(c.DPI()))
|
||||
|
||||
case vg.ArcComp:
|
||||
c.ctx.DrawArc(comp.Pos.X.Dots(c.DPI()), comp.Pos.Y.Dots(c.DPI()),
|
||||
comp.Radius.Dots(c.DPI()),
|
||||
comp.Start, comp.Start+comp.Angle,
|
||||
)
|
||||
|
||||
case vg.CurveComp:
|
||||
switch len(comp.Control) {
|
||||
case 1:
|
||||
c.ctx.QuadraticTo(
|
||||
comp.Control[0].X.Dots(c.DPI()), comp.Control[0].Y.Dots(c.DPI()),
|
||||
comp.Pos.X.Dots(c.DPI()), comp.Pos.Y.Dots(c.DPI()),
|
||||
)
|
||||
case 2:
|
||||
c.ctx.CubicTo(
|
||||
comp.Control[0].X.Dots(c.DPI()), comp.Control[0].Y.Dots(c.DPI()),
|
||||
comp.Control[1].X.Dots(c.DPI()), comp.Control[1].Y.Dots(c.DPI()),
|
||||
comp.Pos.X.Dots(c.DPI()), comp.Pos.Y.Dots(c.DPI()),
|
||||
)
|
||||
default:
|
||||
panic("vgimg: invalid number of control points")
|
||||
}
|
||||
|
||||
case vg.CloseComp:
|
||||
c.ctx.ClosePath()
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown path component: %d", comp.Type))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DPI returns the resolution of the receiver in pixels per inch.
|
||||
func (c *Canvas) DPI() float64 {
|
||||
return float64(c.dpi)
|
||||
}
|
||||
|
||||
func (c *Canvas) FillString(font font.Face, pt vg.Point, str string) {
|
||||
if font.Font.Size == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
c.ctx.Push()
|
||||
defer c.ctx.Pop()
|
||||
|
||||
face := font.FontFace(c.DPI())
|
||||
defer face.Close()
|
||||
|
||||
c.ctx.SetFontFace(face)
|
||||
|
||||
x := pt.X.Dots(c.DPI())
|
||||
y := pt.Y.Dots(c.DPI())
|
||||
h := c.h.Dots(c.DPI())
|
||||
|
||||
c.ctx.InvertY()
|
||||
c.ctx.DrawString(str, x, h-y)
|
||||
}
|
||||
|
||||
// DrawImage implements the vg.Canvas.DrawImage method.
|
||||
func (c *Canvas) DrawImage(rect vg.Rectangle, img image.Image) {
|
||||
var (
|
||||
dpi = c.DPI()
|
||||
min = rect.Min
|
||||
xmin = min.X.Dots(dpi)
|
||||
ymin = min.Y.Dots(dpi)
|
||||
rsz = rect.Size()
|
||||
width = rsz.X.Dots(dpi)
|
||||
height = rsz.Y.Dots(dpi)
|
||||
dx = float64(img.Bounds().Dx())
|
||||
dy = float64(img.Bounds().Dy())
|
||||
)
|
||||
c.ctx.Push()
|
||||
c.ctx.Scale(1, -1)
|
||||
c.ctx.Translate(xmin, -ymin-height)
|
||||
c.ctx.Scale(width/dx, height/dy)
|
||||
c.ctx.DrawImage(img, 0, 0)
|
||||
c.ctx.Pop()
|
||||
}
|
||||
|
||||
// WriterCounter implements the io.Writer interface, and counts
|
||||
// the total number of bytes written.
|
||||
type writerCounter struct {
|
||||
io.Writer
|
||||
n int64
|
||||
}
|
||||
|
||||
func (w *writerCounter) Write(p []byte) (int, error) {
|
||||
n, err := w.Writer.Write(p)
|
||||
w.n += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// A JpegCanvas is an image canvas with a WriteTo method
|
||||
// that writes a jpeg image.
|
||||
type JpegCanvas struct {
|
||||
*Canvas
|
||||
}
|
||||
|
||||
// WriteTo implements the io.WriterTo interface, writing a jpeg image.
|
||||
func (c JpegCanvas) WriteTo(w io.Writer) (int64, error) {
|
||||
wc := writerCounter{Writer: w}
|
||||
b := bufio.NewWriter(&wc)
|
||||
if err := jpeg.Encode(b, c.img, nil); err != nil {
|
||||
return wc.n, err
|
||||
}
|
||||
err := b.Flush()
|
||||
return wc.n, err
|
||||
}
|
||||
|
||||
// A PngCanvas is an image canvas with a WriteTo method that
|
||||
// writes a png image.
|
||||
type PngCanvas struct {
|
||||
*Canvas
|
||||
}
|
||||
|
||||
// WriteTo implements the io.WriterTo interface, writing a png image.
|
||||
func (c PngCanvas) WriteTo(w io.Writer) (int64, error) {
|
||||
wc := writerCounter{Writer: w}
|
||||
b := bufio.NewWriter(&wc)
|
||||
if err := png.Encode(b, c.img); err != nil {
|
||||
return wc.n, err
|
||||
}
|
||||
err := b.Flush()
|
||||
return wc.n, err
|
||||
}
|
||||
|
||||
// A TiffCanvas is an image canvas with a WriteTo method that
|
||||
// writes a tiff image.
|
||||
type TiffCanvas struct {
|
||||
*Canvas
|
||||
}
|
||||
|
||||
// WriteTo implements the io.WriterTo interface, writing a tiff image.
|
||||
func (c TiffCanvas) WriteTo(w io.Writer) (int64, error) {
|
||||
wc := writerCounter{Writer: w}
|
||||
b := bufio.NewWriter(&wc)
|
||||
if err := tiff.Encode(b, c.img, nil); err != nil {
|
||||
return wc.n, err
|
||||
}
|
||||
err := b.Flush()
|
||||
return wc.n, err
|
||||
}
|
||||
Reference in New Issue
Block a user