由于win平台对cgo支持不是很友好,所以笔者将转换功能单独写成一个服务。可以通过docker进行快速运行,避免环境问题(PS:如果对您有帮助,欢迎star)
先看收益
由于用户在上传图片的时候不会进行压缩,所以会有一些大图片导致加载速度很慢
我们可以在上传的时候先进行图片格式转换,转换为webp格式,理论上能压缩50%-80%的体积,下面是压缩后首屏的对比。可以看到小图片基本体积减少50%,对于2MB以上的大图片,体积减少85%左右
成本收益
如何在项目中使用
转换服务image2webp使用很简单,可以通过docker进行运行
$ make help
Available commands:
make build - Build the Go binary
make run - Run the application locally
make docker-build - Build Docker image with default settings
make docker-build-env - Build Docker image using .env variables
make docker-run - Run Docker container
# run in docker
make docker-run
# test
$ curl -X POST http://localhost:10080/v1/upload -F "image=@test.png"
Warning: Binary output can mess up your terminal. Use "--output -" to tell
Warning: curl to output it to your terminal anyway, or consider "--output
Warning: <FILE>" to save to a file.
在项目中,笔者使用oss上传图片,只需要简单修改,在上传前进行压缩即可
func (*OssUploadStrategy) PutFromWeb(ctx jet.Ctx) (string, error) {
var (
logger = ctx.Logger()
)
// 获取上传的文件
file, err := ctx.FormFile("file")
if err != nil {
logger.Error("Error retrieving the file", fasthttp.StatusBadRequest)
return "", err
}
// 打开上传的文件
src, err := file.Open()
if err != nil {
logger.Error("Error opening the file", fasthttp.StatusInternalServerError)
return "", err
}
defer src.Close()
var finalFile io.Reader
if ossCfg.Image2WebpURI != "" {
// 启用压缩功能
// 先压缩图片到WebP格式
compressedImage, err := compressImageToWebP(src, file.Filename)
if err != nil {
logger.Errorf("Failed to compress image: %v", err)
// 如果压缩失败,回退到使用原始文件
if seeker, ok := src.(io.Seeker); ok {
seeker.Seek(0, io.SeekStart)
}
compressedImage = src
file.Filename = strings.TrimSuffix(file.Filename, filepath.Ext(file.Filename)) + ".webp"
} else {
defer compressedImage.Close()
file.Filename = strings.TrimSuffix(file.Filename, filepath.Ext(file.Filename)) + ".webp"
}
finalFile = compressedImage
} else {
finalFile = src
}
filePath := fmt.Sprintf("%s/%s", ossCfg.StoragePath, utils.GenerateFileName(file.Filename))
request := &oss.AppendObjectRequest{
Bucket: oss.Ptr(ossCfg.Bucket),
Key: oss.Ptr(filePath),
Position: oss.Ptr(int64(0)),
Body: finalFile,
}
result, err := client.AppendObject(todoCtx, request)
if err != nil {
logger.Errorf("AppendObject ERROR:%v", err)
return "", err
}
logger.Infof("append object result:%#v\n", result)
return BuildURL(filePath), nil
}
var (
compressImageLogger = xlog.NewWith("compressImageLogger")
)
// compressImageToWebP 调用WebP转换服务压缩图片
func compressImageToWebP(src multipart.File, filename string) (io.ReadCloser, error) {
defer utils.TraceElapsedWithPrefix(compressImageLogger, "compressImageLogger")()
// 重置文件读取位置
if seeker, ok := src.(io.Seeker); ok {
seeker.Seek(0, io.SeekStart)
}
// 读取文件内容到内存
fileData, err := io.ReadAll(src)
if err != nil {
return nil, fmt.Errorf("failed to read file: %w", err)
}
// 创建multipart表单数据
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
// 创建文件字段
part, err := writer.CreateFormFile("image", filename)
if err != nil {
return nil, fmt.Errorf("failed to create form file: %w", err)
}
// 写入文件数据
if _, err := part.Write(fileData); err != nil {
return nil, fmt.Errorf("failed to write file data: %w", err)
}
// 关闭writer
if err := writer.Close(); err != nil {
return nil, fmt.Errorf("failed to close writer: %w", err)
}
// 创建HTTP请求
req, err := http.NewRequest("POST", ossCfg.Image2WebpURI, body)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
// 设置请求头
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Accept", "*/*")
req.Header.Set("Connection", "keep-alive")
// 设置超时
httpClient := &http.Client{
Timeout: 30 * time.Second,
}
// 发送请求
resp, err := httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to send request to WebP service: %w", err)
}
// 检查响应状态
if resp.StatusCode != http.StatusOK {
resp.Body.Close()
return nil, fmt.Errorf("WebP service returned non-200 status: %d", resp.StatusCode)
}
// 返回响应体(WebP图片数据)
return resp.Body, nil
}
常见图片格式分析
常见的图片格式有:jpg、png、gif、psd、tif、bmp等格式
当然现在也出现了一些新的流行的格式,例如:WebP(2010年发布)、avif(2019年发布)
其中webp是现在支持性最好且压缩率最高的图片格式,常见对比如下:
对比如下:
- webp对比gif格式能节省大约
88%以上的空间 - 相比png可以减少
98%以上的空间 - 相比jpg可以减少
35%的空间 - 平均减少 70%
如果相对webp格式更加了解的可以看下面的文章