all repos — honk @ a7f7156f267b1100265803ac322481a7b31a59b3

my fork of honk

avatar.go (view raw)

  1//
  2// Copyright (c) 2019 Ted Unangst <tedu@tedunangst.com>
  3//
  4// Permission to use, copy, modify, and distribute this software for any
  5// purpose with or without fee is hereby granted, provided that the above
  6// copyright notice and this permission notice appear in all copies.
  7//
  8// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 10// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 11// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 12// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 13// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 14// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 15
 16package main
 17
 18import (
 19	"bufio"
 20	"bytes"
 21	"crypto/sha512"
 22	"fmt"
 23	"image"
 24	"image/png"
 25	"net/http"
 26	"net/url"
 27	"regexp"
 28	"strconv"
 29	"strings"
 30
 31	"github.com/gorilla/mux"
 32)
 33
 34var avatarcolors = [4][4]byte{
 35	{16, 0, 48, 255},
 36	{48, 0, 96, 255},
 37	{72, 0, 144, 255},
 38	{96, 0, 192, 255},
 39}
 40
 41func loadAvatarColors() {
 42	var colors string
 43	getconfig("avatarcolors", &colors)
 44	if colors == "" {
 45		return
 46	}
 47	r := bufio.NewReader(strings.NewReader(colors))
 48	for i := 0; i < 4; i++ {
 49		l, _ := r.ReadString(' ')
 50		for l == " " {
 51			l, _ = r.ReadString(' ')
 52		}
 53		l = strings.Trim(l, "# \n")
 54		if len(l) == 6 {
 55			l = l + "ff"
 56		}
 57		c, err := strconv.ParseUint(l, 16, 32)
 58		if err != nil {
 59			elog.Printf("error reading avatar color %d: %s", i, err)
 60			continue
 61		}
 62		avatarcolors[i][0] = byte(c >> 24 & 0xff)
 63		avatarcolors[i][1] = byte(c >> 16 & 0xff)
 64		avatarcolors[i][2] = byte(c >> 8 & 0xff)
 65		avatarcolors[i][3] = byte(c >> 0 & 0xff)
 66	}
 67}
 68
 69func genAvatar(name string) []byte {
 70	h := sha512.New()
 71	h.Write([]byte(name))
 72	s := h.Sum(nil)
 73	img := image.NewNRGBA(image.Rect(0, 0, 64, 64))
 74	for i := 0; i < 64; i++ {
 75		for j := 0; j < 64; j++ {
 76			p := i*img.Stride + j*4
 77			xx := i/16*16 + j/16
 78			x := s[xx]
 79			if x < 64 {
 80				img.Pix[p+0] = avatarcolors[0][0]
 81				img.Pix[p+1] = avatarcolors[0][1]
 82				img.Pix[p+2] = avatarcolors[0][2]
 83				img.Pix[p+3] = avatarcolors[0][3]
 84			} else if x < 128 {
 85				img.Pix[p+0] = avatarcolors[1][0]
 86				img.Pix[p+1] = avatarcolors[1][1]
 87				img.Pix[p+2] = avatarcolors[1][2]
 88				img.Pix[p+3] = avatarcolors[1][3]
 89			} else if x < 192 {
 90				img.Pix[p+0] = avatarcolors[2][0]
 91				img.Pix[p+1] = avatarcolors[2][1]
 92				img.Pix[p+2] = avatarcolors[2][2]
 93				img.Pix[p+3] = avatarcolors[2][3]
 94			} else {
 95				img.Pix[p+0] = avatarcolors[3][0]
 96				img.Pix[p+1] = avatarcolors[3][1]
 97				img.Pix[p+2] = avatarcolors[3][2]
 98				img.Pix[p+3] = avatarcolors[3][3]
 99			}
100		}
101	}
102	var buf bytes.Buffer
103	png.Encode(&buf, img)
104	return buf.Bytes()
105}
106
107func avatarURL(user *WhatAbout) string {
108	if ava := user.Options.Avatar; ava != "" {
109		return ava
110	}
111	return fmt.Sprintf("https://%s/a?a=%s", serverName, url.QueryEscape(user.URL))
112}
113
114func showflag(writer http.ResponseWriter, req *http.Request) {
115	code := mux.Vars(req)["code"]
116	colors := strings.Split(code, ",")
117	numcolors := len(colors)
118	vert := false
119	if colors[0] == "vert" {
120		vert = true
121		colors = colors[1:]
122		numcolors--
123		if numcolors == 0 {
124			http.Error(writer, "bad flag", 400)
125			return
126		}
127	}
128	pixels := make([][4]byte, numcolors)
129	for i := 0; i < numcolors; i++ {
130		hex := colors[i]
131		if len(hex) == 3 {
132			hex = fmt.Sprintf("%c%c%c%c%c%c",
133				hex[0], hex[0], hex[1], hex[1], hex[2], hex[2])
134		}
135		c, _ := strconv.ParseUint(hex, 16, 32)
136		r := byte(c >> 16 & 0xff)
137		g := byte(c >> 8 & 0xff)
138		b := byte(c >> 0 & 0xff)
139		pixels[i][0] = r
140		pixels[i][1] = g
141		pixels[i][2] = b
142		pixels[i][3] = 255
143	}
144
145	h := 128
146	w := h * 3 / 2
147	img := image.NewRGBA(image.Rect(0, 0, w, h))
148	if vert {
149		for j := 0; j < w; j++ {
150			pix := pixels[j*numcolors/w][:]
151			for i := 0; i < h; i++ {
152				p := i*img.Stride + j*4
153				copy(img.Pix[p:], pix)
154			}
155		}
156	} else {
157		for i := 0; i < h; i++ {
158			pix := pixels[i*numcolors/h][:]
159			for j := 0; j < w; j++ {
160				p := i*img.Stride + j*4
161				copy(img.Pix[p:], pix)
162			}
163		}
164	}
165
166	writer.Header().Set("Cache-Control", "max-age="+somedays())
167	png.Encode(writer, img)
168}
169
170var re_flags = regexp.MustCompile("flag:[[:alnum:],]+")
171
172func fixupflags(h *Honk) []Emu {
173	var emus []Emu
174	count := 0
175	h.Noise = re_flags.ReplaceAllStringFunc(h.Noise, func(m string) string {
176		count++
177		var e Emu
178		e.Name = fmt.Sprintf(":flag%d:", count)
179		e.ID = fmt.Sprintf("https://%s/flag/%s", serverName, m[5:])
180		emus = append(emus, e)
181		return e.Name
182	})
183	return emus
184}
185
186func renderflags(h *Honk) {
187	h.Noise = re_flags.ReplaceAllStringFunc(h.Noise, func(m string) string {
188		code := m[5:]
189		src := fmt.Sprintf("https://%s/flag/%s", serverName, code)
190		return fmt.Sprintf(`<img class="emu" title="%s" src="%s">`, "flag", src)
191	})
192}