diff options
author | Mike Crute <mike@crute.us> | 2023-10-16 19:53:08 -0700 |
---|---|---|
committer | Mike Crute <mike@crute.us> | 2023-10-16 19:53:08 -0700 |
commit | 6c1eed0ff4872d6d5a478294e57ce0e8b90dcab3 (patch) | |
tree | 4b63801a272e2f637becb2481a06101c46809abc | |
parent | dec964fdc95aa63b2aa74561001b73617d2f1fb7 (diff) | |
download | golib-6c1eed0ff4872d6d5a478294e57ce0e8b90dcab3.tar.bz2 golib-6c1eed0ff4872d6d5a478294e57ce0e8b90dcab3.tar.xz golib-6c1eed0ff4872d6d5a478294e57ce0e8b90dcab3.zip |
bin/webp: add webp server binarybin/webp/v0.1.0
-rw-r--r-- | bin/webp/go.mod | 8 | ||||
-rw-r--r-- | bin/webp/go.sum | 6 | ||||
-rw-r--r-- | bin/webp/main.go | 106 |
3 files changed, 120 insertions, 0 deletions
diff --git a/bin/webp/go.mod b/bin/webp/go.mod new file mode 100644 index 0000000..ad9ea20 --- /dev/null +++ b/bin/webp/go.mod | |||
@@ -0,0 +1,8 @@ | |||
1 | module code.crute.us/mcrute/golib/bin/webp | ||
2 | |||
3 | go 1.20 | ||
4 | |||
5 | require ( | ||
6 | github.com/chai2010/webp v1.1.1 | ||
7 | golang.org/x/image v0.0.0-20211028202545-6944b10bf410 | ||
8 | ) | ||
diff --git a/bin/webp/go.sum b/bin/webp/go.sum new file mode 100644 index 0000000..27fb1cf --- /dev/null +++ b/bin/webp/go.sum | |||
@@ -0,0 +1,6 @@ | |||
1 | github.com/chai2010/webp v1.1.1 h1:jTRmEccAJ4MGrhFOrPMpNGIJ/eybIgwKpcACsrTEapk= | ||
2 | github.com/chai2010/webp v1.1.1/go.mod h1:0XVwvZWdjjdxpUEIf7b9g9VkHFnInUSYujwqTLEuldU= | ||
3 | golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ= | ||
4 | golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= | ||
5 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||
6 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
diff --git a/bin/webp/main.go b/bin/webp/main.go new file mode 100644 index 0000000..c00a6d8 --- /dev/null +++ b/bin/webp/main.go | |||
@@ -0,0 +1,106 @@ | |||
1 | package main | ||
2 | |||
3 | // webp is a small HTTP server that listens on a Unix socket and | ||
4 | // receives an uncompressed TIFF image as a POST value; it returns a | ||
5 | // webp encoded image. The `quality` header is an integer ranging from | ||
6 | // 0-100 indicating the webp quality, it is required. The `lossless` and | ||
7 | // `exact` headers specify that the image is lossless and to preserve | ||
8 | // RGB values in transparent areas, respectively. These headers may | ||
9 | // only be set to "true" and their absence implies that they are false. | ||
10 | // | ||
11 | // This program exists because there is no pure-Go implementation of | ||
12 | // a webp encoder and using CGO is not desirable for most binaries. | ||
13 | // Furthermore, forking a cwebp binary per image conversion may not | ||
14 | // scale well for a given application, especially if this forking occurs | ||
15 | // on a per-user-request basis. Additionally cwebp requires that the | ||
16 | // image be loaded from disk which may not be desirable while this | ||
17 | // program works purely with byte streams. | ||
18 | // | ||
19 | // This program should be shipped with, started, managed, and killed | ||
20 | // by the parent process that needs webp support. It supports clean | ||
21 | // shutdown in response to SIGTERM. Errors and requests are logged to | ||
22 | // stderr. | ||
23 | // | ||
24 | // Uncompressed TIFF was used as the transit format because it supports | ||
25 | // all image color spaces as well as transparency. Compression is | ||
26 | // unneeded because it wastes CPU cycles on the encode and decode side | ||
27 | // for an IPC call, which has no appreciable bandwidth limit. | ||
28 | |||
29 | import ( | ||
30 | "context" | ||
31 | "fmt" | ||
32 | "log" | ||
33 | "net" | ||
34 | "net/http" | ||
35 | "os" | ||
36 | "os/signal" | ||
37 | "strconv" | ||
38 | "syscall" | ||
39 | |||
40 | "github.com/chai2010/webp" | ||
41 | "golang.org/x/image/tiff" | ||
42 | ) | ||
43 | |||
44 | func writeError(w http.ResponseWriter, code int, message string, args ...any) { | ||
45 | w.WriteHeader(code) | ||
46 | w.Write([]byte(fmt.Sprintf(message+"\n", args...))) | ||
47 | log.Printf("error: %d: %s", code, fmt.Sprintf(message, args...)) | ||
48 | } | ||
49 | |||
50 | type webpConverterHandler struct{} | ||
51 | |||
52 | func (h *webpConverterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||
53 | img, err := tiff.Decode(r.Body) | ||
54 | if err != nil { | ||
55 | writeError(w, http.StatusBadRequest, "decode failed: %s", err) | ||
56 | return | ||
57 | } | ||
58 | |||
59 | quality, err := strconv.Atoi(r.Header.Get("quality")) | ||
60 | if err != nil { | ||
61 | writeError(w, http.StatusBadRequest, "unable to parse quality header: %s", err) | ||
62 | return | ||
63 | } | ||
64 | |||
65 | w.WriteHeader(http.StatusOK) | ||
66 | err = webp.Encode(w, img, &webp.Options{ | ||
67 | Lossless: r.Header.Get("lossless") == "true", | ||
68 | Exact: r.Header.Get("exact") == "true", | ||
69 | Quality: float32(quality), | ||
70 | }) | ||
71 | if err != nil { | ||
72 | log.Printf("error encoding web: %s", err) | ||
73 | } | ||
74 | |||
75 | log.Printf(`"%s %s" %s`, r.Method, r.URL.String(), r.Header.Get("Content-Length")) | ||
76 | } | ||
77 | |||
78 | func main() { | ||
79 | if len(os.Args) != 2 { | ||
80 | log.Fatalf("usage: %s <socket path>", os.Args[0]) | ||
81 | } | ||
82 | |||
83 | sig := make(chan os.Signal) | ||
84 | signal.Notify(sig, syscall.SIGTERM) | ||
85 | |||
86 | spath := os.Args[1] | ||
87 | os.Remove(spath) | ||
88 | |||
89 | server := http.Server{ | ||
90 | Handler: &webpConverterHandler{}, | ||
91 | ErrorLog: log.Default(), | ||
92 | } | ||
93 | |||
94 | listener, err := net.Listen("unix", spath) | ||
95 | if err != nil { | ||
96 | log.Fatalf("error: %s", err) | ||
97 | } | ||
98 | |||
99 | log.Printf("listening on %s", spath) | ||
100 | go server.Serve(listener) | ||
101 | |||
102 | <-sig | ||
103 | log.Printf("process received SIG_TERM, quitting") | ||
104 | server.Shutdown(context.Background()) | ||
105 | os.Remove(spath) | ||
106 | } | ||