-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathhandler.go
129 lines (100 loc) · 2.69 KB
/
handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package ppic
import (
"fmt"
"image"
"image/gif"
"image/jpeg"
"image/png"
"io"
"net/http"
"net/url"
"path"
"strconv"
"strings"
)
// imageWriter represents a function which can write an image to a writer.
type imageWriter func(io.Writer, image.Image) error
// getImageSize extracts an image size from a set of URL values.
func getImageSize(q url.Values) (int, error) {
ss := q.Get("size")
if len(ss) == 0 {
return 512, nil
}
s, err := strconv.Atoi(ss)
if err != nil {
return 0, err
}
return s, nil
}
// getImageWriter returns an imageWriter for the specified path.
func getImageWriter(p string) imageWriter {
ext := path.Ext(p)
switch strings.ToLower(ext) {
case ".gif":
return func(w io.Writer, i image.Image) error {
return gif.Encode(w, i, &gif.Options{NumColors: 2})
}
case ".jpg", ".jpeg":
return func(w io.Writer, i image.Image) error {
return jpeg.Encode(w, i, &jpeg.Options{Quality: 100})
}
case "", ".png":
return func(w io.Writer, i image.Image) error {
enc := png.Encoder{CompressionLevel: png.NoCompression}
return enc.Encode(w, i)
}
default:
return nil
}
}
// Handler serves HTTP requests with generated images.
func Handler(res http.ResponseWriter, req *http.Request) {
// We only support GETing images.
if req.Method != http.MethodGet {
res.Header().Set("Allow", http.MethodGet)
res.WriteHeader(http.StatusMethodNotAllowed)
return
}
writer := getImageWriter(req.URL.Path)
// If we couldn't find a writer then we couldn't understand the extension.
if writer == nil {
res.WriteHeader(http.StatusNotFound)
fmt.Fprintf(res, "error: unsupported file format")
return
}
q := req.URL.Query()
// Get the image size from the request.
size, err := getImageSize(q)
if err != nil {
res.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(res, "error: invalid size")
return
}
// Get the path without extension.
txt := strings.TrimSuffix(req.URL.Path[1:], path.Ext(req.URL.Path))
pal := DefaultPalette
// Generate a palette based on the source text if we're not in monochrome mode.
if _, mono := q["monochrome"]; !mono {
pal = GeneratePalette(txt)
}
// Generate the grid.
grid := Generate(txt, true, false)
// Generate the image.
img, err := GenerateImage(grid, size, pal)
// Check if an invalid size was specified.
if err == ErrInvalidSize {
res.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(res, "error: %s", err)
return
}
// Check if something else bad happened during generation.
if err != nil {
res.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(res, "error: %s", err)
return
}
// Write the image to the response.
if err = writer(res, img); err != nil {
fmt.Fprintf(res, "error: %s", err)
}
}