-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathidenticon.go
138 lines (117 loc) · 2.83 KB
/
identicon.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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package identicon
import (
"crypto/md5"
"image"
"image/color"
"image/png"
"io"
"github.com/llgcode/draw2d/draw2dimg"
)
type point struct {
x, y int
}
type drawingPoint struct {
topLeft point
bottomRight point
}
type gridPoint struct {
value byte
index int
}
type Identicon struct {
Name string
hash [16]byte
color [3]byte
grid []byte
gridPoints []gridPoint
pixelMap []drawingPoint
}
// WriteTo writes the identicon image to the given writer
func (i Identicon) WriteImage(w io.Writer) error {
var img = image.NewRGBA(image.Rect(0, 0, 250, 250))
col := color.RGBA{R: i.color[0], G: i.color[1], B: i.color[2], A: 255}
for _, pixel := range i.pixelMap {
rect(img, col, float64(pixel.topLeft.x), float64(pixel.topLeft.y), float64(pixel.bottomRight.x), float64(pixel.bottomRight.y))
}
return png.Encode(w, img)
}
type applyFunc func(Identicon) Identicon
func Generate(input []byte) Identicon {
identiconPipe := []applyFunc{
pickColor, buildGrid, filterOddSquares, buildPixelMap,
}
identicon := hashInput(input)
for _, applyFunc := range identiconPipe {
identicon = applyFunc(identicon)
}
return identicon
}
func hashInput(input []byte) Identicon {
checkSum := md5.Sum(input)
return Identicon{
Name: string(input),
hash: checkSum,
}
}
func pickColor(identicon Identicon) Identicon {
rgb := [3]byte{}
copy(rgb[:], identicon.hash[:3])
identicon.color = rgb
return identicon
}
func buildGrid(identicon Identicon) Identicon {
var grid []byte
for i := 0; i < len(identicon.hash) && i+3 <= len(identicon.hash)-1; i += 3 {
chunk := make([]byte, 5)
copy(chunk, identicon.hash[i:i+3])
chunk[3] = chunk[1]
chunk[4] = chunk[0]
grid = append(grid, chunk...)
}
identicon.grid = grid
return identicon
}
func filterOddSquares(identicon Identicon) Identicon {
var grid []gridPoint
for i, code := range identicon.grid {
if code%2 == 0 {
point := gridPoint{
value: code,
index: i,
}
grid = append(grid, point)
}
}
identicon.gridPoints = grid
return identicon
}
func rect(img *image.RGBA, col color.Color, x1, y1, x2, y2 float64) {
gc := draw2dimg.NewGraphicContext(img)
gc.SetFillColor(col)
gc.MoveTo(x1, y1)
gc.LineTo(x1, y1)
gc.LineTo(x1, y2)
gc.MoveTo(x2, y1)
gc.LineTo(x2, y1)
gc.LineTo(x2, y2)
gc.SetLineWidth(0)
gc.FillStroke()
}
func buildPixelMap(identicon Identicon) Identicon {
var drawingPoints []drawingPoint
pixelFunc := func(p gridPoint) drawingPoint {
horizontal := (p.index % 5) * 50
vertical := (p.index / 5) * 50
topLeft := point{x: horizontal, y: vertical}
bottomRight := point{x: horizontal + 50, y: vertical + 50}
return drawingPoint{
topLeft,
bottomRight,
}
}
for _, gridPoint := range identicon.gridPoints {
drawingPoints = append(drawingPoints, pixelFunc(gridPoint))
}
identicon.pixelMap = drawingPoints
return identicon
}