1package drawing 2 3import ( 4 "image" 5 "image/color" 6 7 "github.com/golang/freetype/truetype" 8) 9 10// StackGraphicContext is a context that does thngs. 11type StackGraphicContext struct { 12 current *ContextStack 13} 14 15// ContextStack is a graphic context implementation. 16type ContextStack struct { 17 Tr Matrix 18 Path *Path 19 LineWidth float64 20 Dash []float64 21 DashOffset float64 22 StrokeColor color.Color 23 FillColor color.Color 24 FillRule FillRule 25 Cap LineCap 26 Join LineJoin 27 28 FontSizePoints float64 29 Font *truetype.Font 30 31 Scale float64 32 33 Previous *ContextStack 34} 35 36// NewStackGraphicContext Create a new Graphic context from an image 37func NewStackGraphicContext() *StackGraphicContext { 38 gc := &StackGraphicContext{} 39 gc.current = new(ContextStack) 40 gc.current.Tr = NewIdentityMatrix() 41 gc.current.Path = new(Path) 42 gc.current.LineWidth = 1.0 43 gc.current.StrokeColor = image.Black 44 gc.current.FillColor = image.White 45 gc.current.Cap = RoundCap 46 gc.current.FillRule = FillRuleEvenOdd 47 gc.current.Join = RoundJoin 48 gc.current.FontSizePoints = 10 49 return gc 50} 51 52// GetMatrixTransform returns the matrix transform. 53func (gc *StackGraphicContext) GetMatrixTransform() Matrix { 54 return gc.current.Tr 55} 56 57// SetMatrixTransform sets the matrix transform. 58func (gc *StackGraphicContext) SetMatrixTransform(tr Matrix) { 59 gc.current.Tr = tr 60} 61 62// ComposeMatrixTransform composes a transform into the current transform. 63func (gc *StackGraphicContext) ComposeMatrixTransform(tr Matrix) { 64 gc.current.Tr.Compose(tr) 65} 66 67// Rotate rotates the matrix transform by an angle in degrees. 68func (gc *StackGraphicContext) Rotate(angle float64) { 69 gc.current.Tr.Rotate(angle) 70} 71 72// Translate translates a transform. 73func (gc *StackGraphicContext) Translate(tx, ty float64) { 74 gc.current.Tr.Translate(tx, ty) 75} 76 77// Scale scales a transform. 78func (gc *StackGraphicContext) Scale(sx, sy float64) { 79 gc.current.Tr.Scale(sx, sy) 80} 81 82// SetStrokeColor sets the stroke color. 83func (gc *StackGraphicContext) SetStrokeColor(c color.Color) { 84 gc.current.StrokeColor = c 85} 86 87// SetFillColor sets the fill color. 88func (gc *StackGraphicContext) SetFillColor(c color.Color) { 89 gc.current.FillColor = c 90} 91 92// SetFillRule sets the fill rule. 93func (gc *StackGraphicContext) SetFillRule(f FillRule) { 94 gc.current.FillRule = f 95} 96 97// SetLineWidth sets the line width. 98func (gc *StackGraphicContext) SetLineWidth(lineWidth float64) { 99 gc.current.LineWidth = lineWidth 100} 101 102// SetLineCap sets the line cap. 103func (gc *StackGraphicContext) SetLineCap(cap LineCap) { 104 gc.current.Cap = cap 105} 106 107// SetLineJoin sets the line join. 108func (gc *StackGraphicContext) SetLineJoin(join LineJoin) { 109 gc.current.Join = join 110} 111 112// SetLineDash sets the line dash. 113func (gc *StackGraphicContext) SetLineDash(dash []float64, dashOffset float64) { 114 gc.current.Dash = dash 115 gc.current.DashOffset = dashOffset 116} 117 118// SetFontSize sets the font size. 119func (gc *StackGraphicContext) SetFontSize(fontSizePoints float64) { 120 gc.current.FontSizePoints = fontSizePoints 121} 122 123// GetFontSize gets the font size. 124func (gc *StackGraphicContext) GetFontSize() float64 { 125 return gc.current.FontSizePoints 126} 127 128// SetFont sets the current font. 129func (gc *StackGraphicContext) SetFont(f *truetype.Font) { 130 gc.current.Font = f 131} 132 133// GetFont returns the font. 134func (gc *StackGraphicContext) GetFont() *truetype.Font { 135 return gc.current.Font 136} 137 138// BeginPath starts a new path. 139func (gc *StackGraphicContext) BeginPath() { 140 gc.current.Path.Clear() 141} 142 143// IsEmpty returns if the path is empty. 144func (gc *StackGraphicContext) IsEmpty() bool { 145 return gc.current.Path.IsEmpty() 146} 147 148// LastPoint returns the last point on the path. 149func (gc *StackGraphicContext) LastPoint() (x float64, y float64) { 150 return gc.current.Path.LastPoint() 151} 152 153// MoveTo moves the cursor for a path. 154func (gc *StackGraphicContext) MoveTo(x, y float64) { 155 gc.current.Path.MoveTo(x, y) 156} 157 158// LineTo draws a line. 159func (gc *StackGraphicContext) LineTo(x, y float64) { 160 gc.current.Path.LineTo(x, y) 161} 162 163// QuadCurveTo draws a quad curve. 164func (gc *StackGraphicContext) QuadCurveTo(cx, cy, x, y float64) { 165 gc.current.Path.QuadCurveTo(cx, cy, x, y) 166} 167 168// CubicCurveTo draws a cubic curve. 169func (gc *StackGraphicContext) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) { 170 gc.current.Path.CubicCurveTo(cx1, cy1, cx2, cy2, x, y) 171} 172 173// ArcTo draws an arc. 174func (gc *StackGraphicContext) ArcTo(cx, cy, rx, ry, startAngle, delta float64) { 175 gc.current.Path.ArcTo(cx, cy, rx, ry, startAngle, delta) 176} 177 178// Close closes a path. 179func (gc *StackGraphicContext) Close() { 180 gc.current.Path.Close() 181} 182 183// Save pushes a context onto the stack. 184func (gc *StackGraphicContext) Save() { 185 context := new(ContextStack) 186 context.FontSizePoints = gc.current.FontSizePoints 187 context.Font = gc.current.Font 188 context.LineWidth = gc.current.LineWidth 189 context.StrokeColor = gc.current.StrokeColor 190 context.FillColor = gc.current.FillColor 191 context.FillRule = gc.current.FillRule 192 context.Dash = gc.current.Dash 193 context.DashOffset = gc.current.DashOffset 194 context.Cap = gc.current.Cap 195 context.Join = gc.current.Join 196 context.Path = gc.current.Path.Copy() 197 context.Font = gc.current.Font 198 context.Scale = gc.current.Scale 199 copy(context.Tr[:], gc.current.Tr[:]) 200 context.Previous = gc.current 201 gc.current = context 202} 203 204// Restore restores the previous context. 205func (gc *StackGraphicContext) Restore() { 206 if gc.current.Previous != nil { 207 oldContext := gc.current 208 gc.current = gc.current.Previous 209 oldContext.Previous = nil 210 } 211} 212