This commit is contained in:
2023-04-06 12:37:38 +08:00
parent ae68eb0764
commit 95c273d0b8
5 changed files with 214 additions and 0 deletions

1
.gitignore vendored
View File

@@ -21,3 +21,4 @@
# Go workspace file # Go workspace file
go.work go.work
data/

99
bin/main.go Normal file
View File

@@ -0,0 +1,99 @@
package main
import (
"image"
"image/gif"
"log"
"net/http"
"os"
"regexp"
"strconv"
"github.com/chai2010/webp"
"github.com/disintegration/imaging"
)
// 实现一个 web api 服务(获取指定尺寸的图片)
func main() {
http.HandleFunc("/img/", func(w http.ResponseWriter, r *http.Request) {
// URL 格式: /img/{id}-{version}@{倍图}{宽度}.{格式}
reg := regexp.MustCompile(`^/img/([0-9a-zA-Z]+)-([0-9a-zA-Z]+)@([0-9]{1,4})x([0-9]{1,4}).(jpg|jpeg|png|webp)$`)
matches := reg.FindStringSubmatch(r.URL.Path)
if len(matches) != 6 {
log.Println("URL 格式错误", matches)
w.WriteHeader(http.StatusBadRequest)
return
}
// 正则表达式获取参数
id, version, multiple_str, width_str, format := matches[1], matches[2], matches[3], matches[4], matches[5]
multiple, err := strconv.Atoi(multiple_str)
if err != nil {
log.Println("倍图参数错误", multiple_str)
w.WriteHeader(http.StatusBadRequest)
return
}
width, err := strconv.Atoi(width_str)
if err != nil {
log.Println("宽度参数错误", width_str)
w.WriteHeader(http.StatusBadRequest)
return
}
log.Println(id, version, multiple, width, format)
// 打開輸入文件
file, err := os.Open("data/test.gif")
if err != nil {
log.Println("打开文件失败", err)
w.WriteHeader(http.StatusBadRequest)
return
}
defer file.Close()
// 將輸入文件解碼為 image.Image
img, ext, err := image.Decode(file)
if err != nil {
log.Println("解码图像失败", err)
w.WriteHeader(http.StatusBadRequest)
return
}
// 如果是 GIF 格式的动态图片,直接返回
if ext == "gif" {
giffile, err := os.Open("data/test.gif")
if err != nil {
log.Println("打开文件失败", err)
w.WriteHeader(http.StatusBadRequest)
return
}
defer giffile.Close()
gifimg, err := gif.DecodeAll(giffile)
if err != nil {
log.Println("解码图像失败", err)
w.WriteHeader(http.StatusBadRequest)
return
}
gif.EncodeAll(w, gifimg)
return
}
// 將圖像轉換為 RGBA 格式(如果尚未採用該格式)
if _, ok := img.(*image.RGBA); !ok {
img = imaging.Clone(img)
}
// 將圖像調整為指定宽度的 WebP 格式並將其寫入輸出到瀏覽器(高度自适应)
if err = webp.Encode(w, imaging.Resize(img, multiple*width, 0, imaging.Lanczos), &webp.Options{Quality: 80}); err != nil {
log.Println("编码图像失败", err.Error())
w.WriteHeader(http.StatusBadRequest)
return
}
})
log.Println("Server is running at http://localhost:6001")
http.ListenAndServe(":6001", nil)
}

12
go.mod Normal file
View File

@@ -0,0 +1,12 @@
module git.satori.love/gameui/webp
go 1.18
require github.com/disintegration/imaging v1.6.2
require github.com/sizeofint/webpanimation v0.0.0-20210809145948-1d2b32119882 // indirect
require (
github.com/chai2010/webp v1.1.1
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect
)

13
go.sum Normal file
View File

@@ -0,0 +1,13 @@
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/sizeofint/webpanimation v0.0.0-20210809145948-1d2b32119882 h1:A7o8tOERTtpD/poS+2VoassCjXpjHn916luXbf5QKD0=
github.com/sizeofint/webpanimation v0.0.0-20210809145948-1d2b32119882/go.mod h1:5IwJoz9Pw7JsrCN4/skkxUtSWT7myuUPLhCgv6Q5vvQ=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 h1:hVwzHzIUGRjiF7EcUjqNxk3NCfkPxbDKRdnNE1Rpg0U=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

89
webp.go Normal file
View File

@@ -0,0 +1,89 @@
package webp
import (
"image"
"os"
"github.com/chai2010/webp"
"github.com/disintegration/imaging"
)
// EncodeFile encodes the specified image file to WebP format with the given width and height.
// The output file name is constructed by adding the .webp extension to the input file name.
func EncodeFile(filename string, width, height int) error {
// Open the input file
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
// Decode the input file into an image.Image
img, format, err := image.Decode(file)
if err != nil {
return err
}
// Convert the image to RGBA format if it's not already in that format
if _, ok := img.(*image.RGBA); !ok {
img = imaging.Clone(img)
}
// Resize the image to the specified dimensions
resizedImg := imaging.Resize(img, width, height, imaging.Lanczos)
// Create a new file for writing the output
outFilename := filename[:len(filename)-len(format)] + "webp"
outFile, err := os.Create(outFilename)
if err != nil {
return err
}
defer outFile.Close()
// Encode the resized image to WebP format and write it to the output file
err = webp.Encode(outFile, resizedImg, &webp.Options{Quality: 80})
if err != nil {
return err
}
return nil
}
//// Encode encodes the specified image to WebP format with the given width and height.
//// The output data is returned as a byte slice.
//func Encode(data []byte, width, height int) ([]byte, error) {
// // Decode the input data into an image.Image
// img, format, err := image.Decode(ioutil.NopCloser(bytes.NewReader(data)))
// if err != nil {
// return nil, err
// }
//
// // Convert the image to RGBA format if it's not already in that format
// if _, ok := img.(*image.RGBA); !ok {
// img = imaging.Clone(img)
// }
//
// // Resize the image to the specified dimensions
// resizedImg := imaging.Resize(img, width, height, imaging.Lanczos)
//
// // Encode the resized image to WebP format and return it as a byte slice
// var buf bytes.Buffer
// err = webp.Encode(&buf, resizedImg, &webp.Options{Quality: 80})
// if err != nil {
// return nil, err
// }
//
// return buf.Bytes(), nil
//}
//
//// Decode decodes the specified WebP data into an image.Image.
//func Decode(data []byte) (image.Image, error) {
// return webp.Decode(bytes.NewReader(data))
//}
//
//// IsWebP returns true if the specified data is a WebP image.
//func IsWebP(data []byte) bool {
// return webp.IsWebP(data)
//}
//
//// IsPNG returns true if the specified