-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathcameron.go
72 lines (63 loc) · 1.44 KB
/
cameron.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
/*
Package cameron implements an avatar generator for Go.
*/
package cameron
import (
"bytes"
"image"
"image/color"
"github.com/cespare/xxhash/v2"
)
// Identicon returns an identicon avatar based on the data with the length and
// blockLength.
func Identicon(data []byte, length, blockLength int) image.Image {
digest := xxhash.Sum64(data)
img := image.NewPaletted(
image.Rect(0, 0, length, length),
color.Palette{
color.NRGBA{
R: byte(digest),
G: byte(digest >> 8),
B: byte(digest >> 16),
A: 0xff,
},
color.NRGBA{
R: 0xff ^ byte(digest),
G: 0xff ^ byte(digest>>8),
B: 0xff ^ byte(digest>>16),
A: 0xff,
},
},
)
if blockLength > length {
blockLength = length
}
columnsCount := length / blockLength
padding := blockLength / 2
if length%blockLength != 0 {
padding = (length - blockLength*columnsCount) / 2
} else if columnsCount > 1 {
columnsCount--
} else {
padding = 0
}
filled := columnsCount == 1
pixels := bytes.Repeat([]byte{1}, blockLength)
for i, ri, ci := 0, 0, 0; i < columnsCount*(columnsCount+1)/2; i++ {
if filled || digest>>uint(i%64)&1 == 1 {
for i := 0; i < blockLength; i++ {
x := padding + ri*blockLength
y := padding + ci*blockLength + i
copy(img.Pix[img.PixOffset(x, y):], pixels)
x = padding + (columnsCount-1-ri)*blockLength
copy(img.Pix[img.PixOffset(x, y):], pixels)
}
}
ci++
if ci == columnsCount {
ci = 0
ri++
}
}
return img
}