- commit
- 3b65668
- parent
- 7136be1
- author
- Eric Bower
- date
- 2023-03-15 04:18:10 +0000 UTC
fix(imgs): do not convert svg to webp We never actually tested svg images before "supporting" it.
5 files changed,
+74,
-46
+1,
-1
1@@ -51,7 +51,7 @@ func main() {
2
3 opt := shared.NewImgOptimizer(cfg.Logger, "")
4 contents := &bytes.Buffer{}
5- img, err := opt.GetImage(reader, post.MimeType)
6+ img, err := shared.GetImageForOptimization(reader, post.MimeType)
7 if err != nil {
8 cfg.Logger.Error(err)
9 continue
+3,
-0
1@@ -230,6 +230,9 @@ func (h *UploadImgHandler) Write(s ssh.Session, entry *utils.FileEntry) (string,
2 // DetectContentType does not detect markdown
3 if ext == ".md" {
4 nextPost.MimeType = "text/markdown; charset=UTF-8"
5+ // DetectContentType does not detect image/svg
6+ } else if ext == ".svg" {
7+ nextPost.MimeType = "image/svg+xml"
8 }
9
10 post, err := h.DBPool.FindPostWithFilename(
+10,
-4
1@@ -54,6 +54,8 @@ func (h *UploadImgHandler) metaImg(data *PostMetaData) error {
2 reader := bytes.NewReader([]byte(data.Text))
3 tee := bytes.NewReader([]byte(data.Text))
4
5+ // we want to keep the original file so people can use that
6+ // if our webp optimizer doesn't work properly
7 fname, err := h.Storage.PutFile(
8 bucket,
9 data.Filename,
10@@ -77,12 +79,16 @@ func (h *UploadImgHandler) metaImg(data *PostMetaData) error {
11 var webpReader *bytes.Reader
12 contents := &bytes.Buffer{}
13
14- img, err := opt.GetImage(tee, data.MimeType)
15- if errors.Is(err, shared.AlreadyWebP) {
16+ img, err := shared.GetImageForOptimization(tee, data.MimeType)
17+ finalName := data.Filename
18+ if errors.Is(err, shared.AlreadyWebPError) {
19 h.Cfg.Logger.Infof("(%s) is already webp, skipping encoding", data.Filename)
20+ finalName = fmt.Sprintf("%s.webp", shared.SanitizeFileExt(finalName))
21 webpReader = tee
22 } else if err != nil {
23- return err
24+ h.Cfg.Logger.Infof("(%s) is a file format (%s) that we cannot convert to webp, skipping encoding", data.Filename, data.MimeType)
25+ finalName = shared.SanitizeFileExt(finalName)
26+ webpReader = tee
27 } else {
28 err = opt.EncodeWebp(contents, img)
29 if err != nil {
30@@ -98,7 +104,7 @@ func (h *UploadImgHandler) metaImg(data *PostMetaData) error {
31
32 _, err = h.Storage.PutFile(
33 bucket,
34- fmt.Sprintf("%s.webp", shared.SanitizeFileExt(data.Filename)),
35+ finalName,
36 storage.NopReaderAtCloser(webpReader),
37 )
38 if err != nil {
+27,
-22
1@@ -189,7 +189,10 @@ type ImgHandler struct {
2 Storage storage.ObjectStorage
3 Logger *zap.SugaredLogger
4 Img *shared.ImgOptimizer
5- Optimized bool
6+ // We should try to use the optimized image if it's available
7+ // not all images are optimized so this flag isn't enough
8+ // because we also need to check the mime type
9+ UseOptimized bool
10 }
11
12 func imgHandler(w http.ResponseWriter, h *ImgHandler) {
13@@ -221,14 +224,16 @@ func imgHandler(w http.ResponseWriter, h *ImgHandler) {
14
15 contentType := post.MimeType
16 fname := post.Filename
17- if h.Optimized {
18+ isWebOptimized := shared.IsWebOptimized(contentType)
19+
20+ if h.UseOptimized && isWebOptimized {
21 contentType = "image/webp"
22 fname = fmt.Sprintf("%s.webp", shared.SanitizeFileExt(post.Filename))
23 }
24
25 contents, err := h.Storage.GetFile(bucket, fname)
26 if err != nil {
27- h.Logger.Infof("file not found %s/%s", h.Username, post.Filename)
28+ h.Logger.Infof("file not found in storage %s/%s", h.Username, post.Filename)
29 http.Error(w, err.Error(), http.StatusInternalServerError)
30 return
31 }
32@@ -238,7 +243,7 @@ func imgHandler(w http.ResponseWriter, h *ImgHandler) {
33
34 resizeImg := h.Img.Width != 0 || h.Img.Height != 0
35
36- if h.Optimized && resizeImg {
37+ if h.UseOptimized && resizeImg && isWebOptimized {
38 // when resizing an image we don't want to mess with quality
39 // since that was already applied when converting to webp
40 h.Img.Quality = 100
41@@ -274,15 +279,15 @@ func imgRequestOriginal(w http.ResponseWriter, r *http.Request) {
42 logger := shared.GetLogger(r)
43
44 imgHandler(w, &ImgHandler{
45- Username: username,
46- Subdomain: subdomain,
47- Slug: slug,
48- Cfg: cfg,
49- Dbpool: dbpool,
50- Storage: st,
51- Logger: logger,
52- Img: shared.NewImgOptimizer(logger, ""),
53- Optimized: false,
54+ Username: username,
55+ Subdomain: subdomain,
56+ Slug: slug,
57+ Cfg: cfg,
58+ Dbpool: dbpool,
59+ Storage: st,
60+ Logger: logger,
61+ Img: shared.NewImgOptimizer(logger, ""),
62+ UseOptimized: false,
63 })
64 }
65
66@@ -310,15 +315,15 @@ func imgRequest(w http.ResponseWriter, r *http.Request) {
67 logger := shared.GetLogger(r)
68
69 imgHandler(w, &ImgHandler{
70- Username: username,
71- Subdomain: subdomain,
72- Slug: slug,
73- Cfg: cfg,
74- Dbpool: dbpool,
75- Storage: st,
76- Logger: logger,
77- Img: shared.NewImgOptimizer(logger, dimes),
78- Optimized: true,
79+ Username: username,
80+ Subdomain: subdomain,
81+ Slug: slug,
82+ Cfg: cfg,
83+ Dbpool: dbpool,
84+ Storage: st,
85+ Logger: logger,
86+ Img: shared.NewImgOptimizer(logger, dimes),
87+ UseOptimized: true,
88 })
89 }
90
1@@ -40,6 +40,39 @@ type Ratio struct {
2 Height int
3 }
4
5+var AlreadyWebPError = errors.New("image is already webp")
6+var IsSvgError = errors.New("image is an svg")
7+
8+func GetImageForOptimization(r io.Reader, mimeType string) (image.Image, error) {
9+ switch mimeType {
10+ case "image/png":
11+ return png.Decode(r)
12+ case "image/jpeg":
13+ return jpeg.Decode(r)
14+ case "image/jpg":
15+ return jpeg.Decode(r)
16+ case "image/gif":
17+ return gif.Decode(r)
18+ case "image/webp":
19+ return nil, AlreadyWebPError
20+ }
21+
22+ return nil, fmt.Errorf("(%s) not supported for optimization", mimeType)
23+}
24+
25+func IsWebOptimized(mimeType string) bool {
26+ switch mimeType {
27+ case "image/png":
28+ case "image/jpeg":
29+ case "image/jpg":
30+ case "image/gif":
31+ case "image/webp":
32+ return true
33+ }
34+
35+ return false
36+}
37+
38 func CreateImgURL(linkify Linkify) func([]byte) []byte {
39 return func(url []byte) []byte {
40 if url[0] == '/' {
41@@ -100,25 +133,6 @@ func GetRatio(dimes string) (*Ratio, error) {
42 return ratio, nil
43 }
44
45-var AlreadyWebP = errors.New("image is already webp")
46-
47-func (h *ImgOptimizer) GetImage(r io.Reader, mimeType string) (image.Image, error) {
48- switch mimeType {
49- case "image/png":
50- return png.Decode(r)
51- case "image/jpeg":
52- return jpeg.Decode(r)
53- case "image/jpg":
54- return jpeg.Decode(r)
55- case "image/gif":
56- return gif.Decode(r)
57- case "image/webp":
58- return nil, AlreadyWebP
59- }
60-
61- return nil, fmt.Errorf("(%s) not supported for optimization", mimeType)
62-}
63-
64 func (h *ImgOptimizer) DecodeWebp(r io.Reader) (image.Image, error) {
65 opt := decoder.Options{}
66 img, err := webp.Decode(r, &opt)