repos / pico

pico services - prose.sh, pastes.sh, imgs.sh, feeds.sh, pgs.sh
git clone https://github.com/picosh/pico.git

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
M cmd/scripts/webp/webp.go
+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
M filehandlers/imgs/handler.go
+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(
M filehandlers/imgs/img.go
+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 {
M imgs/api.go
+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 
M shared/img.go
+33, -19
 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)