Files
remark42/backend/vendor/github.com/nullrocks/identicon/generator.go
T

171 lines
4.2 KiB
Go

package identicon
import (
"crypto/sha256"
"errors"
"image/color"
"math/rand"
"strconv"
"time"
)
// Generator represents a predefined set of configurations that can be reused to
// create multiple icons by passing a Text string only.
type Generator struct {
// Namespace that will be concatenated previous to the icon generation.
Namespace string
// Size is the number of blocks of the figure.
Size int
// Density * Size = times to iterate over the hash of Text:Namespace:Seed.
Density int
// hashFunction used to generate a fixed length array of bytes.
hashFunction func([]byte) []byte
// fillColorFunction used to pick a color to fill the squares of the figure.
fillColorFunction func([]byte) color.Color
// backgroundColorFunction used to pick a background color for the figure.
backgroundColorFunction func([]byte, color.Color) color.Color
// isRandom flag to decide whether the generated image will be randomized.
isRandom bool
// rand is the source of randomness.
rand *rand.Rand
}
// option Configuration functional approach
type option func(*Generator)
// New returns a pointer to a Generator with the desired configuration.
func New(
namespace string,
size int,
density int,
opts ...option,
) (*Generator, error) {
if size < MinSize {
// Smaller values will generate a meaningless Generator.
return nil, errors.New(
"Size cannot be less than " + strconv.Itoa(MinSize),
)
}
if density < 1 {
return nil, errors.New(
"Density cannot be less than 1",
)
}
g := Generator{
Size: size,
Namespace: namespace,
Density: density,
isRandom: false,
hashFunction: _sha256,
fillColorFunction: _fillColor,
backgroundColorFunction: _backgroundColor,
}
g.Option(opts...)
return &g, nil
}
// Draw returns a pointer to an IdentIcon with a generated figure and a color.
func (g Generator) Draw(text string) (*IdentIcon, error) {
var randomGenerator *rand.Rand
if g.isRandom {
// In order to generate a randomized Canvas, use UnixNano as the source
// of randomess. By doing this, random numbers won't be consistent.
randomGenerator = rand.New(rand.NewSource(time.Now().UnixNano()))
} else {
// rand will generate consistent values since the source is Size.
randomGenerator = rand.New(rand.NewSource(int64(g.Size)))
}
ii, err := newIdentIcon(
text,
g.Namespace,
g.Size,
g.Density,
g.isRandom,
randomGenerator,
g.hashFunction,
g.fillColorFunction,
g.backgroundColorFunction,
)
if err != nil {
return nil, err
}
// Generate Canvas
ii.Draw()
return ii, nil
}
// Option sets the options specified.
func (g *Generator) Option(opts ...option) {
for _, opt := range opts {
opt(g)
}
}
// SetHashFunction replaces the default hash function (Sha256).
func SetHashFunction(hf func([]byte) []byte) option {
return func(g *Generator) {
g.hashFunction = hf
}
}
// SetFillColorFunction replaces the default color generation function (HSL).
func SetFillColorFunction(fcf func([]byte) color.Color) option {
return func(g *Generator) {
g.fillColorFunction = fcf
}
}
// SetBackgroundColorFunction replaces the default background's color generation
// function (HSL).
func SetBackgroundColorFunction(bcf func([]byte, color.Color) color.Color) option {
return func(g *Generator) {
g.backgroundColorFunction = bcf
}
}
// SetRandom to append a random string to the generator text everytime Draw is
// called.
func SetRandom(r bool) option {
return func(g *Generator) {
g.isRandom = r
}
}
func _sha256(b []byte) []byte {
digest := sha256.Sum256(b)
return digest[:]
}
func _fillColor(hashBytes []byte) color.Color {
cb1, cb2 := uint32(hashBytes[0]), uint32(hashBytes[1])
h := (cb1 + cb2) % 360
s := (cb1 % 30) + 60
l := (cb2 % 20) + 40
// Some colors in the HSL color model are too bright and don't play well
// with the default background color. This is a naïve normalization method.
if (h >= 50 && h <= 85) || (h >= 170 && h <= 190) {
s = 80
l -= 20
} else if h > 85 && h < 170 {
l -= 10
}
return HSL{h, s, l}
}
func _backgroundColor(hashBytes []byte, fill color.Color) color.Color {
return color.NRGBA{R: 240, G: 240, B: 240, A: 255}
}