diff --git a/internal/controller/post_controller.go b/internal/controller/post_controller.go index a7668bd..a4d2a50 100644 --- a/internal/controller/post_controller.go +++ b/internal/controller/post_controller.go @@ -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}) }