diff options
Diffstat (limited to 'avatar.go')
| -rw-r--r-- | avatar.go | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/avatar.go b/avatar.go new file mode 100644 index 0000000..4342890 --- /dev/null +++ b/avatar.go @@ -0,0 +1,45 @@ +package main + +import ( + "crypto/sha256" + "fmt" + "net/http" + "strings" +) + +// An avatar is drawn from the name alone: fetching one tells somewhere else +// who reads what, and an upload needs a parser. +func avatarSVG(name string) []byte { + sum := sha256.Sum256([]byte(name)) + // Fixed saturation and lightness, so every one is readable. + hue := int(sum[0]) * 360 / 256 + var b strings.Builder + fmt.Fprintf(&b, `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 5 5" width="20" height="20" role="img" aria-label="%s">`, name) + fmt.Fprintf(&b, `<rect width="5" height="5" fill="#eee"/>`) + fmt.Fprintf(&b, `<g fill="hsl(%d,45%%,35%%)">`, hue) + // Three columns mirrored into five. + for x := range 3 { + for y := range 5 { + if sum[1+x*5+y]&1 == 0 { + continue + } + fmt.Fprintf(&b, `<rect x="%d" y="%d" width="1" height="1"/>`, x, y) + if x < 2 { + fmt.Fprintf(&b, `<rect x="%d" y="%d" width="1" height="1"/>`, 4-x, y) + } + } + } + b.WriteString(`</g></svg>`) + return []byte(b.String()) +} + +func (f *Forge) handleAvatar(w http.ResponseWriter, r *http.Request) { + name := r.PathValue("name") + if !accountNameRE.MatchString(name) { + http.NotFound(w, r) + return + } + w.Header().Set("Content-Type", "image/svg+xml") + w.Header().Set("Cache-Control", "max-age=86400") + w.Write(avatarSVG(name)) +} |