identicon

Profile Image Generator
git clone git://git.lair.cx/identicon
Log | Files | Refs | README | LICENSE

commit 9c387f9446bcaa297e19274cbf2ebef6dc47c3d5
Author: Yongbin Kim <iam@yongbin.kim>
Date:   Sun, 12 Sep 2021 03:43:25 +0900

First Commmit

Signed-off-by: Yongbin Kim <iam@yongbin.kim>

Diffstat:
AREADME | 6++++++
Aexamples/main.go | 27+++++++++++++++++++++++++++
Aexamples/result.png | 0
Ago.mod | 8++++++++
Ago.sum | 6++++++
Aidenticon.go | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 130 insertions(+), 0 deletions(-)

diff --git a/README b/README @@ -0,0 +1,6 @@ +go.lair.cx/identicon +==================== + +Profile image generator. + +See `examples/main.go` for usage. diff --git a/examples/main.go b/examples/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "image/png" + "os" + + "go.lair.cx/identicon" +) + +func main() { + factory := identicon.NewFactory() + generated, err := factory.Generate([]byte("Hello, World!")) + if err != nil { + panic(err) + } + + f, err := os.Create("result.png") + if err != nil { + panic(err) + } + defer f.Close() + + err = png.Encode(f, generated) + if err != nil { + panic(err) + } +} diff --git a/examples/result.png b/examples/result.png Binary files differ. diff --git a/go.mod b/go.mod @@ -0,0 +1,8 @@ +module go.lair.cx/identicon + +go 1.18 + +require ( + github.com/segmentio/fasthash v1.0.3 + golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 +) diff --git a/go.sum b/go.sum @@ -0,0 +1,6 @@ +github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM= +github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY= +golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY= +golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/identicon.go b/identicon.go @@ -0,0 +1,83 @@ +package identicon + +import ( + "image" + "image/color" + + "github.com/segmentio/fasthash/fnv1a" + "golang.org/x/image/draw" +) + +const ( + iconWidth = 5 + iconWidthHalf = 3 + iconHeight = 5 +) + +var defaultPalette = [...]color.RGBA{ + {0xFF, 0x40, 0x00, 0xFF}, + {0xFF, 0x93, 0x51, 0xFF}, + {0xFF, 0xE2, 0x72, 0xFF}, + {0x9D, 0xE1, 0x6F, 0xFF}, + {0x53, 0xAF, 0xFF, 0xFF}, + {0x41, 0x47, 0x96, 0xFF}, + {0xDE, 0x6F, 0xFF, 0xFF}, + {0xFF, 0x74, 0xBC, 0xFF}, +} + +type Factory struct { + // Palette + palette []color.RGBA +} + +func NewFactory() *Factory { + return &Factory{ + palette: defaultPalette[:], + } +} + +// SetPalette sets the palette. +func (f *Factory) SetPalette(palette []color.RGBA) { + f.palette = palette +} + +// Generate generates a identicon. +func (f *Factory) Generate(src []byte) (image.Image, error) { + // Hash the source. + hash := fnv1a.HashBytes64(src) + + // Choose color from palette. + markColor := f.palette[int(hash&0xFF)%len(f.palette)] + hash = hash >> 8 + + // Prepare canvas. + canvas := image.NewRGBA(image.Rect(0, 0, iconWidth, iconHeight)) + draw.Draw(canvas, canvas.Bounds(), &image.Uniform{C: color.White}, image.Point{}, draw.Src) + + // Draw to canvas. + for y := 0; y < iconHeight; y++ { + for x := 0; x < iconWidthHalf; x++ { + if hash>>(8*y+x)&1 > 0 { + canvas.SetRGBA(x, y, markColor) + canvas.SetRGBA(4-x, y, markColor) + } + } + } + + return canvas, nil +} + +func WrapImage(img image.Image, cw, ch, ix int) image.Image { + var ( + w = iconWidth * ix + h = iconHeight * ix + x1 = (cw - w) / 2 + y1 = (ch - h) / 2 + x2 = x1 + w + y2 = y1 + h + ) + wrapper := image.NewRGBA(image.Rect(0, 0, cw, ch)) + draw.Draw(wrapper, wrapper.Bounds(), &image.Uniform{C: color.White}, image.Point{}, draw.Src) + draw.NearestNeighbor.Scale(wrapper, image.Rect(x1, y1, x2, y2), img, img.Bounds(), draw.Src, nil) + return wrapper +}