/
svg.go
92 lines (76 loc) · 2.13 KB
/
svg.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package identicon
import (
"image/color"
"io"
"strconv"
"text/template"
)
type svgRect struct {
X int
Y int
Width int
Height int
FillColor string
}
type svgTmpl struct {
Pixels int
BackgroundColor string
FillColor string
Rects []svgRect
}
const svgTemplate = `
<!-- <?xml version="1.0"?> -->
<svg version="1.1" baseprofile="full" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ev="http://www.w3.org/2001/xml-events" width="{{.Pixels}}" height="{{.Pixels}}" viewBox="0 0 {{.Pixels}} {{.Pixels}}" >
<rect width="100%" height="100%" fill="{{.BackgroundColor}}"/>
{{range $index, $r := .Rects}}
<rect x="{{$r.X}}" y="{{$r.Y}}" width="{{$r.Width}}" height="{{$r.Height}}" fill="{{$r.FillColor}}"/>{{end}}
</svg>`
func colorToRGBAString(c color.Color) string {
r, g, b, a := c.RGBA()
r >>= 8
g >>= 8
b >>= 8
a >>= 8
rs := strconv.Itoa(int(r))
gs := strconv.Itoa(int(g))
bs := strconv.Itoa(int(b))
as := strconv.Itoa(int(a))
return "rgba(" + rs + "," + gs + "," + bs + "," + as + ")"
}
// Encode an IdentIcon to SVG
func svgEncode(w io.Writer, ii *IdentIcon, pixels int) error {
// Padding is relative to the number of blocks.
padding := pixels / (ii.Size * MinSize)
drawableArea := pixels - (padding * 2)
blockSize := drawableArea / ii.Size
// Add the residue (pixels that won't be filled) to the padding.
// Try to center the figure regardless when the drawable area is not
// divisible by the block pixels.
padding += (drawableArea % ii.Size) / 2
fillColor := colorToRGBAString(ii.FillColor)
backgroundColor := colorToRGBAString(ii.BackgroundColor)
b, err := template.New("svg").Parse(svgTemplate)
if err != nil {
return err
}
t := svgTmpl{
Pixels: pixels,
BackgroundColor: backgroundColor,
FillColor: fillColor,
Rects: make([]svgRect, ii.Canvas.FilledPoints),
}
i := 0
for y, mapX := range ii.Canvas.PointsMap {
for x := range mapX {
t.Rects[i] = svgRect{
blockSize*x + padding,
blockSize*y + padding,
blockSize,
blockSize,
fillColor,
}
i++
}
}
return b.Execute(w, t)
}