feat!: convert all images to webp and simplify everything

This commit is contained in:
Gustavo "Guz" L. de Mello
2024-06-13 11:10:21 -03:00
parent eee1503855
commit 85ea7ddbd0
4 changed files with 57 additions and 144 deletions

View File

@@ -1,14 +1,29 @@
package api
import (
"bytes"
"errors"
"image"
"io"
"net/http"
"net/url"
"strconv"
"www/internals"
"github.com/chai2010/webp"
"github.com/sunshineplan/imgconv"
)
func ImgOptimize(i image.Image, threshold int) image.Image {
w := i.Bounds().Max.X
if threshold >= w {
return i
}
d := w / threshold
return imgconv.Resize(i, &imgconv.ResizeOption{Width: w / d})
}
func errorHelper(w http.ResponseWriter) func(msg string, err error, status int) bool {
return func(msg string, err error, status int) bool {
if err != nil {
@@ -76,19 +91,19 @@ func Image(w http.ResponseWriter, r *http.Request) {
return
}
img, err := internals.NewImage(data)
img, err := imgconv.Decode(bytes.NewReader(data))
if error("Error trying to decode the image", err, http.StatusInternalServerError) {
return
}
img.Optimize(threshold)
img = ImgOptimize(img, threshold)
err = img.Encode(w)
err = webp.Encode(w, img, &webp.Options{Lossless: true})
if error("Error trying to encode the image", err, http.StatusInternalServerError) {
return
}
w.Header().Add("Cache-Control", "max-age=604800, stale-while-revalidate=86400, stale-if-error=86400")
w.Header().Add("CDN-Cache-Control", "max-age=604800")
w.Header().Add("Content-Type", img.GetMime())
w.Header().Add("Content-Type", "image/webp")
}

17
go.mod
View File

@@ -2,10 +2,21 @@ module www
go 1.22.2
require github.com/a-h/templ v0.2.697
require (
github.com/a-h/templ v0.2.697
github.com/chai2010/webp v1.1.1
github.com/sunshineplan/imgconv v1.1.10
)
require (
github.com/chai2010/webp v1.1.1 // indirect
github.com/disintegration/imaging v1.6.2 // indirect
github.com/hhrutter/lzw v1.0.0 // indirect
github.com/hhrutter/tiff v1.0.1 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/pdfcpu/pdfcpu v0.8.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/sunshineplan/pdf v1.0.7 // indirect
golang.org/x/image v0.17.0 // indirect
golang.org/x/text v0.16.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

27
go.sum
View File

@@ -2,11 +2,30 @@ github.com/a-h/templ v0.2.697 h1:OILxtWvD0NRJaoCOiZCopRDPW8paroKlGsrAiHLykNE=
github.com/a-h/templ v0.2.697/go.mod h1:5cqsugkq9IerRNucNsI4DEamdHPsoGMQy99DzydLhM8=
github.com/chai2010/webp v1.1.1 h1:jTRmEccAJ4MGrhFOrPMpNGIJ/eybIgwKpcACsrTEapk=
github.com/chai2010/webp v1.1.1/go.mod h1:0XVwvZWdjjdxpUEIf7b9g9VkHFnInUSYujwqTLEuldU=
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
github.com/hhrutter/lzw v1.0.0 h1:laL89Llp86W3rRs83LvKbwYRx6INE8gDn0XNb1oXtm0=
github.com/hhrutter/lzw v1.0.0/go.mod h1:2HC6DJSn/n6iAZfgM3Pg+cP1KxeWc3ezG8bBqW5+WEo=
github.com/hhrutter/tiff v1.0.1 h1:MIus8caHU5U6823gx7C6jrfoEvfSTGtEFRiM8/LOzC0=
github.com/hhrutter/tiff v1.0.1/go.mod h1:zU/dNgDm0cMIa8y8YwcYBeuEEveI4B0owqHyiPpJPHc=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/pdfcpu/pdfcpu v0.8.0 h1:SuEB4uVsPFz1nb802r38YpFpj9TtZh/oB0bGG34IRZw=
github.com/pdfcpu/pdfcpu v0.8.0/go.mod h1:jj03y/KKrwigt5xCi8t7px2mATcKuOzkIOoCX62yMho=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/sunshineplan/imgconv v1.1.10 h1:EJZVXLwmvmKgEA1KIJpNSzSssjGaZMdtOLycGFyzxQA=
github.com/sunshineplan/imgconv v1.1.10/go.mod h1:de9NsLFCMW2JVom3mjRZu3GceLFwkEIEkf1EGS5rDX4=
github.com/sunshineplan/pdf v1.0.7 h1:62xlc079jh4tGLDjiihyyhwVFkn0IsxLyDpHplbG9Ew=
github.com/sunshineplan/pdf v1.0.7/go.mod h1:QsEmZCWBE3uFK8PCrM0pua1WDWLNU77YusiDEcY56OQ=
golang.org/x/image v0.17.0 h1:nTRVVdajgB8zCMZVsViyzhnMKPwYeroEERRC64JuLco=
golang.org/x/image v0.17.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

View File

@@ -1,132 +0,0 @@
package internals
import (
"bytes"
"errors"
"image"
"image/gif"
"image/jpeg"
"image/png"
"io"
"math"
"net/http"
"github.com/chai2010/webp"
"github.com/disintegration/imaging"
)
type Image struct {
img image.Image
mime string
JpegOptions jpeg.Options
GifOptions gif.Options
WebpOptions webp.Options
}
func NewImage(b []byte) (Image, error) {
m := http.DetectContentType(b)
r := bytes.NewReader(b)
var img image.Image
var err error
switch m {
case "image/png":
img, err = png.Decode(r)
case "image/jpeg":
img, err = jpeg.Decode(r)
case "image/gif":
img, err = gif.Decode(r)
case "image/webp":
img, err = webp.Decode(r)
default:
err = errors.ErrUnsupported
}
if err != nil {
return Image{}, err
}
return Image{
img: img,
mime: m,
JpegOptions: jpeg.Options{
Quality: 70,
},
GifOptions: gif.Options{
NumColors: 256,
},
WebpOptions: webp.Options{
Lossless: true,
Quality: 70.0,
Exact: true,
},
}, nil
}
func (i *Image) Decode(b []byte) error {
img, err := NewImage(b)
*i = img
return err
}
func (i *Image) Encode(w io.Writer) error {
var err error
switch i.mime {
case "image/png":
err = png.Encode(w, i.img)
case "image/jpeg":
err = jpeg.Encode(w, i.img, &jpeg.Options{Quality: 70})
case "image/gif":
err = gif.Encode(w, i.img, &gif.Options{NumColors: 256})
case "image/webp":
err = webp.Encode(w, i.img, &webp.Options{Lossless: true})
default:
err = errors.ErrUnsupported
}
if err != nil {
return err
}
return nil
}
func (i *Image) Quality(q float64) {
i.WebpOptions.Quality = float32(q)
i.JpegOptions.Quality = int(math.Round(q))
}
func (i *Image) Optimize(threshold int) {
w := i.img.Bounds().Max.X
if threshold >= w {
return
}
d := w / threshold
i.Scale(d * -1)
}
func (i *Image) Scale(s int) {
r := i.img.Bounds()
w, h := r.Max.X, r.Max.Y
var nw, nh int
if s < 0 {
s = s * -1
nw, nh = w/s, h/s
} else if s > 0 {
s = s * -1
nw, nh = w*s, h*s
} else {
nw, nh = w, h
}
i.img = imaging.Resize(i.img, nw, nh, imaging.CatmullRom)
}
func (i *Image) GetMime() string {
return i.mime
}