diff --git a/main.go b/main.go index 2854327..92f76f5 100644 --- a/main.go +++ b/main.go @@ -72,18 +72,49 @@ func LinearCongruentialGenerator(seed uint64) *LCG { return g } -type COLOR struct { +type RGB struct { r uint8 g uint8 b uint8 } -func Color(s string) *COLOR { - c := new(COLOR) +type HSV struct { + h float32 + s float32 + v float32 +} + +func rgb(r, g, b float32) *RGB { + c := new(RGB) + c.r = uint8(r * 1.0 / 255) + c.g = uint8(g * 1.0 / 255) + c.b = uint8(b * 1.0 / 255) + return c +} + +func s2rgb(s string) *RGB { + c := new(RGB) fmt.Sscanf(s, "#%02x%02x%02x", c.r, c.g, c.b) return c } +func (c *HSV) to_rgb() *RGB { + h := int(floor(c.h / 60)) + f := c.h / 60 - h + p := c.v * (1 - c.s) + q := c.v * (1 - c.s * f) + t := c.v * (1 - c.s * (1 - f)) + switch (h) { + case 6: + case 0: return rgb(C.V, t, p) + case 1: return rgb(q, C.V, p) + case 2: return rgb(p, C.V, t) + case 3: return rgb(p, q, C.V) + case 4: return rgb(t, p, C.V) + case 5: return rgb(C.V, p, q) + } +} + func add255(x uint8, y uint8) uint8 { if x < 255-y { return x + y @@ -98,7 +129,7 @@ func sub255(x uint8, y uint8) uint8 { return 0 } -func (c *COLOR) brighterOrDarkerThan(ref COLOR, delta uint8) string { +func (c *RGB) brighterOrDarkerThan(ref RGB, delta uint8) string { /* XXX FIXME: THIS IS PROBABLY NOT CORRECT. Need to look into original implementation. */ if true { return fmt.Sprintf("#%02x%02x%02x", add255(c.r, delta), add255(c.g, delta), add255(c.b, delta)) @@ -106,26 +137,26 @@ func (c *COLOR) brighterOrDarkerThan(ref COLOR, delta uint8) string { return ref.darkerThan(ref, delta) } -func (c *COLOR) darkerThan(ref COLOR, delta uint8) string { +func (c *RGB) darkerThan(ref RGB, delta uint8) string { /* XXX FIXME: THIS IS NOT CORRECT. The original implementation does darkening in HSV space. * cf. https://github.com/DiceBear/avatars/blob/master/packages/avatars/src/color.ts */ return fmt.Sprintf("#%02x%02x%02x", sub255(c.r, delta), sub255(c.g, delta), sub255(c.b, delta)) } -func (c COLOR) withAlpha(alpha float32) string { +func (c RGB) withAlpha(alpha float32) string { return fmt.Sprintf("#%02x%02x%02x", c.r, c.g, c.b, uint8(255*alpha)) } func maleAvatar(seed uint64) string { var g = LinearCongruentialGenerator(seed) var skinColor = g.pickOne([]string{"#FFDBAC", "#F5CFA0", "#EAC393", "#E0B687", "#CB9E6E", "#B68655", "#A26D3D", "#8D5524"}) - var hairColor = Color(g.pickOne([]string{"#090806", "#2c222b", "#71635a", "#b7a69e", "#b89778", "#a56b46", "#b55239", "#8d4a43", - "#91553d", "#533d32", "#3b3024", "#554838", "#4e433f", "#504444", "#6a4e42", "#a7856a", "#977961"})).brighterOrDarkerThan(*Color(skinColor), 17) + var hairColor = rgb(g.pickOne([]string{"#090806", "#2c222b", "#71635a", "#b7a69e", "#b89778", "#a56b46", "#b55239", "#8d4a43", + "#91553d", "#533d32", "#3b3024", "#554838", "#4e433f", "#504444", "#6a4e42", "#a7856a", "#977961"})).brighterOrDarkerThan(*rgb(skinColor), 17) var eyesColor = g.pickOne([]string{"#76778b", "#697b94", "#647b90", "#5b7c8b", "#588387"}) - var eyebrowsColor = Color(Color(hairColor).darkerThan(*Color(skinColor), 7)).darkerThan(*Color(hairColor), 10) - var mustacheColor = Color(Color(hairColor).darkerThan(*Color(skinColor), 7)).withAlpha(g.pickOneFloat([]float32{1, 0.75, 0.5})) - var mouthColor = Color(g.pickOne([]string{"#eec1ad", "#dbac98", "#d29985"})).brighterOrDarkerThan(*Color(skinColor), 10) + var eyebrowsColor = rgb(rgb(hairColor).darkerThan(*rgb(skinColor), 7)).darkerThan(*rgb(hairColor), 10) + var mustacheColor = rgb(rgb(hairColor).darkerThan(*rgb(skinColor), 7)).withAlpha(g.pickOneFloat([]float32{1, 0.75, 0.5})) + var mouthColor = rgb(g.pickOne([]string{"#eec1ad", "#dbac98", "#d29985"})).brighterOrDarkerThan(*rgb(skinColor), 10) var glassesColor = g.pickOne([]string{"#5f705c", "#43677d", "#5e172d", "#ffb67a", "#a04b5d", "#191919", "#323232", "#4b4b4b"}) var clothesColor = g.pickOne([]string{"#5bc0de", "#5cb85c", "#428bca", "#03396c", "#005b96", "#6497b1", "#1b85b8", "#5a5255", "#559e83", "#ae5a41", "#c3cb71", "#666547", "#ffe28a"}) var hatColor = g.pickOne([]string{"#18293b", "#2e1e05", "#989789", "#3d6ba7", "#517459", "#a62116"}) @@ -281,13 +312,13 @@ func femaleAvatar(seed uint64) string { var g = LinearCongruentialGenerator(seed) var skinColor = g.pickOne([]string{"#FFDBAC", "#F5CFA0", "#EAC393", "#E0B687", "#CB9E6E", "#B68655", "#A26D3D", "#8D5524"}) - var hairColor = Color(g.pickOne([]string{"#090806", "#2c222b", "#71635a", "#b7a69e", "#d6c4c2", "#cabfb1", "#dcd0ba", "#fff5e1", + var hairColor = rgb(g.pickOne([]string{"#090806", "#2c222b", "#71635a", "#b7a69e", "#d6c4c2", "#cabfb1", "#dcd0ba", "#fff5e1", "#e6cea8", "#e5c8a8", "#debc99", "#b89778", "#a56b46", "#b55239", "#8d4a43", "#91553d", - "#533d32", "#3b3024", "#554838", "#4e433f", "#504444", "#6a4e42", "#a7856a", "#977961"})).brighterOrDarkerThan(*Color(skinColor), 17) + "#533d32", "#3b3024", "#554838", "#4e433f", "#504444", "#6a4e42", "#a7856a", "#977961"})).brighterOrDarkerThan(*rgb(skinColor), 17) var eyesColor = g.pickOne([]string{"#76778b", "#697b94", "#647b90", "#5b7c8b", "#588387"}) - var eyebrowsColor = Color(Color(hairColor).darkerThan(*Color(skinColor), 7)).darkerThan(*Color(hairColor), 10) + var eyebrowsColor = rgb(rgb(hairColor).darkerThan(*rgb(skinColor), 7)).darkerThan(*rgb(hairColor), 10) var accessoriesColor = g.pickOne([]string{"#daa520", "#ffd700", "#eee8aa", "#fafad2", "#d3d3d3", "#a9a9a9"}) - var mouthColor = Color(g.pickOne([]string{"#dbac98", "#d29985", "#c98276", "#e35d6a", "#e32153", "#de0f0d"})).brighterOrDarkerThan(*Color(skinColor), 10) + var mouthColor = rgb(g.pickOne([]string{"#dbac98", "#d29985", "#c98276", "#e35d6a", "#e32153", "#de0f0d"})).brighterOrDarkerThan(*rgb(skinColor), 10) var glassesColor = g.pickOne([]string{"#5f705c", "#43677d", "#5e172d", "#ffb67a", "#a04b5d", "#191919", "#323232", "#4b4b4b"}) var clothesColor = g.pickOne([]string{"#d11141", "#00b159", "#00aedb", "#f37735", "#ffc425", "#740001", "#ae0001", "#eeba30", "#96ceb4", "#ffeead", "#ff6f69", "#ffcc5c", "#88d8b0"})