feat: 文章图片上传 JPEG/PNG 自动转 WebP 压缩存储
- JPEG/PNG 上传后自动转为 WebP quality 80 存储,保留原尺寸不 resize - 仅当 WebP 比原文件小时才采用,否则回退原格式 - GIF/WebP 保持不变直存 - 移除对 common.SaveUploadedFile 的依赖,改用 io.ReadAll + os.WriteFile
This commit is contained in:
@ -1,8 +1,14 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
_ "image/gif"
|
||||
_ "image/jpeg"
|
||||
_ "image/png"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@ -14,6 +20,7 @@ import (
|
||||
"metazone.cc/metalab/internal/model"
|
||||
"metazone.cc/metalab/internal/service"
|
||||
|
||||
"github.com/chai2010/webp"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
@ -358,6 +365,7 @@ var allowedImageExt = map[string]bool{
|
||||
}
|
||||
|
||||
// UploadImage 上传帖子图片(需登录,multipart/form-data)
|
||||
// JPEG/PNG 自动转 WebP quality 80 存储,保留原尺寸不 resize
|
||||
func (ctrl *PostController) UploadImage(c *gin.Context) {
|
||||
uid, _, ok := common.GetGinUser(c)
|
||||
if !ok {
|
||||
@ -386,6 +394,13 @@ func (ctrl *PostController) UploadImage(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 读取全部数据(后续 WebP 转换需要)
|
||||
data, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
common.Error(c, http.StatusInternalServerError, "读取文件失败")
|
||||
return
|
||||
}
|
||||
|
||||
// 存储路径
|
||||
storageDir := "storage/uploads/posts"
|
||||
if err := os.MkdirAll(storageDir, 0755); err != nil {
|
||||
@ -393,17 +408,38 @@ func (ctrl *PostController) UploadImage(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
// 唯一文件名:uid_timestamp.ext
|
||||
ts := time.Now().UnixMilli()
|
||||
filename := fmt.Sprintf("%d_%d%s", uid, ts, ext)
|
||||
savePath := filepath.Join(storageDir, filename)
|
||||
var savePath, url string
|
||||
|
||||
if err := common.SaveUploadedFile(file, savePath); err != nil {
|
||||
common.Error(c, http.StatusInternalServerError, "保存图片失败")
|
||||
return
|
||||
// JPEG/PNG → WebP 压缩存储(保留原尺寸,quality 80)
|
||||
if ext == ".jpg" || ext == ".jpeg" || ext == ".png" {
|
||||
img, _, err := image.Decode(bytes.NewReader(data))
|
||||
if err == nil {
|
||||
var buf bytes.Buffer
|
||||
if err := webp.Encode(&buf, img, &webp.Options{Quality: 80}); err == nil {
|
||||
// 仅当 WebP 比原文件小时才采用,否则回退原格式
|
||||
if buf.Len() > 0 && buf.Len() < len(data) {
|
||||
filename := fmt.Sprintf("%d_%d.webp", uid, ts)
|
||||
savePath = filepath.Join(storageDir, filename)
|
||||
if err := os.WriteFile(savePath, buf.Bytes(), 0644); err == nil {
|
||||
url = "/uploads/posts/" + filename
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 回退:GIF / WebP / 转换失败 / 转换后反而更大 → 原样存储
|
||||
if savePath == "" {
|
||||
filename := fmt.Sprintf("%d_%d%s", uid, ts, ext)
|
||||
savePath = filepath.Join(storageDir, filename)
|
||||
if err := os.WriteFile(savePath, data, 0644); err != nil {
|
||||
common.Error(c, http.StatusInternalServerError, "保存图片失败")
|
||||
return
|
||||
}
|
||||
url = "/uploads/posts/" + filename
|
||||
}
|
||||
|
||||
url := "/uploads/posts/" + filename
|
||||
common.VditorUploadOk(c, map[string]string{header.Filename: url})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user