16
"github.com/go-chi/chi/v5"
17
"xelbot.com/reprogl/container"
18
"xelbot.com/reprogl/models"
19
"xelbot.com/reprogl/utils/avatar"
20
"xelbot.com/reprogl/utils/hashid"
23
func AvatarGenerator(app *container.Application) http.HandlerFunc {
24
return func(w http.ResponseWriter, r *http.Request) {
25
hash := chi.URLParam(r, "hash")
27
writeAvatar(w, app, hash, 80)
31
func AvatarGeneratorWithSize(app *container.Application) http.HandlerFunc {
32
return func(w http.ResponseWriter, r *http.Request) {
33
hash := chi.URLParam(r, "hash")
34
sizeStr := chi.URLParam(r, "size")
36
size, err := strconv.Atoi(sizeStr)
42
writeAvatar(w, app, hash, size)
46
func writeAvatar(w http.ResponseWriter, app *container.Application, hash string, size int) {
47
hashModel, err := hashid.Decode(hash, true)
53
img, err := avatar.GenerateAvatar(hashModel, app, size)
55
if errors.Is(err, models.RecordNotFound) || errors.Is(err, avatar.InvalidSize) {
58
app.ServerError(w, err)
64
expires := time.Now().Add(container.AvatarTTL * time.Second)
66
cacheControl(w, container.AvatarTTL)
67
setExpires(w, expires)
68
w.Header().Set("Content-Type", "image/png")
70
rawImage, err := pngquantPipe(img)
75
saveToFile(hash, size, rawImage)
77
_, err = w.Write(rawImage)
79
app.ServerError(w, err)
83
func pngquantPipe(avatarImage image.Image) ([]byte, error) {
84
buf := new(bytes.Buffer)
85
err := png.Encode(buf, avatarImage)
90
quantBuf := new(bytes.Buffer)
92
cmd := exec.Command("/usr/bin/pngquant", "-s1", "--quality=60-80", "-")
93
cmd.Stdin = bufio.NewReader(buf)
94
cmd.Stderr = os.Stderr
102
return quantBuf.Bytes(), nil
105
func saveToFile(hash string, size int, rawImage []byte) {
108
postfix = ".w" + strconv.Itoa(size)
111
filename := "public/images/avatar/" + hash + postfix + ".png"
112
f, err := os.Open(filename)
113
if errors.Is(err, fs.ErrNotExist) {
114
_ = os.WriteFile(filename, rawImage, 0644)