go-hep.org/x/hep@v0.38.1/hplot/vgop/ops.go (about) 1 // Copyright ©2023 The go-hep Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package vgop // import "go-hep.org/x/hep/hplot/vgop" 6 7 import ( 8 "bytes" 9 "encoding/base64" 10 "encoding/json" 11 "fmt" 12 "image" 13 "image/color" 14 "image/png" 15 16 "gonum.org/v1/plot/font" 17 "gonum.org/v1/plot/vg" 18 ) 19 20 // op is a vector graphics operation as defined by the vg.Canvas interface. 21 // Each method of vg.Canvas has a corresponding vgop.op. 22 type op interface { 23 op(ctx fontCtx, c vg.Canvas) error 24 } 25 26 // opSetLineWidth corresponds to the vg.Canvas.SetWidth method. 27 type opSetLineWidth struct { 28 Width vg.Length `json:"width"` 29 } 30 31 func (op opSetLineWidth) op(ctx fontCtx, c vg.Canvas) error { 32 c.SetLineWidth(op.Width) 33 return nil 34 } 35 36 // opSetLineDash corresponds to the vg.Canvas.SetLineDash method. 37 type opSetLineDash struct { 38 Dashes []vg.Length `json:"dashes"` 39 Offsets vg.Length `json:"offsets"` 40 } 41 42 func (op opSetLineDash) op(ctx fontCtx, c vg.Canvas) error { 43 c.SetLineDash(op.Dashes, op.Offsets) 44 return nil 45 } 46 47 // opSetColor corresponds to the vg.Canvas.SetColor method. 48 type opSetColor struct { 49 Color color.Color 50 } 51 52 func (op opSetColor) MarshalJSON() ([]byte, error) { 53 var ctx struct { 54 C struct { 55 R uint32 `json:"r"` 56 G uint32 `json:"g"` 57 B uint32 `json:"b"` 58 A uint32 `json:"a"` 59 } `json:"color"` 60 } 61 62 ctx.C.R, ctx.C.G, ctx.C.B, ctx.C.A = op.Color.RGBA() 63 return json.Marshal(ctx) 64 } 65 66 func (op *opSetColor) UnmarshalJSON(p []byte) error { 67 var ctx struct { 68 C struct { 69 R uint32 `json:"r"` 70 G uint32 `json:"g"` 71 B uint32 `json:"b"` 72 A uint32 `json:"a"` 73 } `json:"color"` 74 } 75 76 err := json.Unmarshal(p, &ctx) 77 if err != nil { 78 return err 79 } 80 op.Color = &color.RGBA{ 81 R: uint8(ctx.C.R), 82 G: uint8(ctx.C.G), 83 B: uint8(ctx.C.B), 84 A: uint8(ctx.C.A), 85 } 86 return nil 87 } 88 89 func (op opSetColor) op(ctx fontCtx, c vg.Canvas) error { 90 c.SetColor(op.Color) 91 return nil 92 } 93 94 // opRotate corresponds to the vg.Canvas.Rotate method. 95 type opRotate struct { 96 Angle float64 `json:"angle"` 97 } 98 99 func (op opRotate) op(ctx fontCtx, c vg.Canvas) error { 100 c.Rotate(op.Angle) 101 return nil 102 } 103 104 // opTranslate corresponds to the vg.Canvas.Translate method. 105 type opTranslate struct { 106 Point vg.Point 107 } 108 109 func (op opTranslate) MarshalJSON() ([]byte, error) { 110 var v struct { 111 P jsonPoint `json:"point"` 112 } 113 v.P = jsonPointFrom(op.Point) 114 115 return json.Marshal(v) 116 } 117 118 func (op *opTranslate) UnmarshalJSON(p []byte) error { 119 var v struct { 120 P jsonPoint `json:"point"` 121 } 122 err := json.Unmarshal(p, &v) 123 if err != nil { 124 return err 125 } 126 op.Point = v.P.cnv() 127 128 return nil 129 } 130 131 func (op opTranslate) op(ctx fontCtx, c vg.Canvas) error { 132 c.Translate(op.Point) 133 return nil 134 } 135 136 // opScale corresponds to the vg.Canvas.Scale method. 137 type opScale struct { 138 X float64 `json:"x"` 139 Y float64 `json:"y"` 140 } 141 142 func (op opScale) op(ctx fontCtx, c vg.Canvas) error { 143 c.Scale(op.X, op.Y) 144 return nil 145 } 146 147 // opPush corresponds to the vg.Canvas.Push method. 148 type opPush struct{} 149 150 func (op opPush) op(ctx fontCtx, c vg.Canvas) error { 151 c.Push() 152 return nil 153 } 154 155 // opPop corresponds to the vg.Canvas.Pop method. 156 type opPop struct{} 157 158 func (op opPop) op(ctx fontCtx, c vg.Canvas) error { 159 c.Pop() 160 return nil 161 } 162 163 // opStroke corresponds to the vg.Canvas.Stroke method. 164 type opStroke struct { 165 Path vg.Path 166 } 167 168 func (op opStroke) MarshalJSON() ([]byte, error) { 169 var v struct { 170 P jsonPath `json:"path"` 171 } 172 v.P = jsonPathFrom(op.Path) 173 174 return json.Marshal(v) 175 } 176 177 func (op *opStroke) UnmarshalJSON(p []byte) error { 178 var v struct { 179 P jsonPath `json:"path"` 180 } 181 err := json.Unmarshal(p, &v) 182 if err != nil { 183 return err 184 } 185 op.Path = v.P.cnv() 186 187 return nil 188 } 189 190 func (op opStroke) op(ctx fontCtx, c vg.Canvas) error { 191 c.Stroke(op.Path) 192 return nil 193 } 194 195 // opFill corresponds to the vg.Canvas.Fill method. 196 type opFill struct { 197 Path vg.Path 198 } 199 200 func (op opFill) MarshalJSON() ([]byte, error) { 201 var v struct { 202 P jsonPath `json:"path"` 203 } 204 v.P = jsonPathFrom(op.Path) 205 206 return json.Marshal(v) 207 } 208 209 func (op *opFill) UnmarshalJSON(p []byte) error { 210 var v struct { 211 P jsonPath `json:"path"` 212 } 213 err := json.Unmarshal(p, &v) 214 if err != nil { 215 return err 216 } 217 op.Path = v.P.cnv() 218 219 return nil 220 } 221 222 func (op opFill) op(ctx fontCtx, c vg.Canvas) error { 223 c.Fill(op.Path) 224 return nil 225 } 226 227 // opFillString corresponds to the vg.Canvas.FillString method. 228 type opFillString struct { 229 Font font.Font 230 Point vg.Point 231 String string 232 } 233 234 func (op opFillString) MarshalJSON() ([]byte, error) { 235 var v struct { 236 ID fontID `json:"font"` 237 Pt jsonPoint `json:"point"` 238 Str string `json:"string"` 239 } 240 v.ID = fontID(op.Font) 241 v.Pt = jsonPointFrom(op.Point) 242 v.Str = op.String 243 244 return json.Marshal(v) 245 } 246 247 func (op *opFillString) UnmarshalJSON(p []byte) error { 248 var v struct { 249 ID fontID `json:"font"` 250 Pt jsonPoint `json:"point"` 251 Str string `json:"string"` 252 } 253 err := json.Unmarshal(p, &v) 254 if err != nil { 255 return err 256 } 257 op.Font = font.Font(v.ID) 258 op.Point = v.Pt.cnv() 259 op.String = v.Str 260 261 return nil 262 } 263 264 func (op opFillString) op(ctx fontCtx, c vg.Canvas) error { 265 id := fontID(op.Font) 266 face, ok := ctx.fonts[id] 267 if !ok { 268 return fmt.Errorf("unknown font name=%q, size=%v", op.Font.Name(), op.Font.Size) 269 } 270 c.FillString(face, op.Point, op.String) 271 return nil 272 } 273 274 // opDrawImage corresponds to the vg.Canvas.DrawImage method 275 type opDrawImage struct { 276 Rect vg.Rectangle 277 Image image.Image 278 } 279 280 func (op opDrawImage) MarshalJSON() ([]byte, error) { 281 var v struct { 282 Rect struct { 283 Min jsonPoint `json:"min"` 284 Max jsonPoint `json:"max"` 285 } 286 Image []byte `json:"data"` 287 } 288 v.Rect.Min = jsonPointFrom(op.Rect.Min) 289 v.Rect.Max = jsonPointFrom(op.Rect.Max) 290 291 var buf bytes.Buffer 292 err := png.Encode(&buf, op.Image) 293 if err != nil { 294 return nil, fmt.Errorf("could not encode image to PNG: %w", err) 295 } 296 v.Image = []byte(base64.StdEncoding.EncodeToString(buf.Bytes())) 297 298 return json.Marshal(v) 299 } 300 301 func (op *opDrawImage) UnmarshalJSON(p []byte) error { 302 var v struct { 303 Rect struct { 304 Min jsonPoint `json:"min"` 305 Max jsonPoint `json:"max"` 306 } 307 Image []byte `json:"data"` 308 } 309 err := json.Unmarshal(p, &v) 310 if err != nil { 311 return err 312 } 313 op.Rect.Min = v.Rect.Min.cnv() 314 op.Rect.Max = v.Rect.Max.cnv() 315 316 buf, err := base64.StdEncoding.DecodeString(string(v.Image)) 317 if err != nil { 318 return err 319 } 320 img, err := png.Decode(bytes.NewReader(buf)) 321 if err != nil { 322 return err 323 } 324 op.Image = img 325 326 return nil 327 } 328 329 func (op opDrawImage) op(ctx fontCtx, c vg.Canvas) error { 330 c.DrawImage(op.Rect, op.Image) 331 return nil 332 }