identicon.go (1815B)
1 package identicon 2 3 import ( 4 "image" 5 "image/color" 6 7 "github.com/segmentio/fasthash/fnv1a" 8 "golang.org/x/image/draw" 9 ) 10 11 const ( 12 iconWidth = 5 13 iconWidthHalf = 3 14 iconHeight = 5 15 ) 16 17 var defaultPalette = [...]color.RGBA{ 18 {0xFF, 0x40, 0x00, 0xFF}, 19 {0xFF, 0x93, 0x51, 0xFF}, 20 {0xFF, 0xE2, 0x72, 0xFF}, 21 {0x9D, 0xE1, 0x6F, 0xFF}, 22 {0x53, 0xAF, 0xFF, 0xFF}, 23 {0x41, 0x47, 0x96, 0xFF}, 24 {0xDE, 0x6F, 0xFF, 0xFF}, 25 {0xFF, 0x74, 0xBC, 0xFF}, 26 } 27 28 type Factory struct { 29 // Palette 30 palette []color.RGBA 31 } 32 33 func NewFactory() *Factory { 34 return &Factory{ 35 palette: defaultPalette[:], 36 } 37 } 38 39 // SetPalette sets the palette. 40 func (f *Factory) SetPalette(palette []color.RGBA) { 41 f.palette = palette 42 } 43 44 // Generate generates a identicon. 45 func (f *Factory) Generate(src []byte) (image.Image, error) { 46 // Hash the source. 47 hash := fnv1a.HashBytes64(src) 48 49 // Choose color from palette. 50 markColor := f.palette[int(hash&0xFF)%len(f.palette)] 51 hash = hash >> 8 52 53 // Prepare canvas. 54 canvas := image.NewRGBA(image.Rect(0, 0, iconWidth, iconHeight)) 55 draw.Draw(canvas, canvas.Bounds(), &image.Uniform{C: color.White}, image.Point{}, draw.Src) 56 57 // Draw to canvas. 58 for y := 0; y < iconHeight; y++ { 59 for x := 0; x < iconWidthHalf; x++ { 60 if hash>>(8*y+x)&1 > 0 { 61 canvas.SetRGBA(x, y, markColor) 62 canvas.SetRGBA(4-x, y, markColor) 63 } 64 } 65 } 66 67 return canvas, nil 68 } 69 70 func WrapImage(img image.Image, cw, ch, ix int) image.Image { 71 var ( 72 w = iconWidth * ix 73 h = iconHeight * ix 74 x1 = (cw - w) / 2 75 y1 = (ch - h) / 2 76 x2 = x1 + w 77 y2 = y1 + h 78 ) 79 wrapper := image.NewRGBA(image.Rect(0, 0, cw, ch)) 80 draw.Draw(wrapper, wrapper.Bounds(), &image.Uniform{C: color.White}, image.Point{}, draw.Src) 81 draw.NearestNeighbor.Scale(wrapper, image.Rect(x1, y1, x2, y2), img, img.Bounds(), draw.Src, nil) 82 return wrapper 83 }