mirror of
https://github.com/keven1024/015.git
synced 2026-05-26 07:08:02 +00:00
feat(worker): add image conversion functionality with Magick and support for additional formats
This commit is contained in:
@@ -3,8 +3,20 @@ package services
|
||||
import (
|
||||
"errors"
|
||||
"worker/internal/utils"
|
||||
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnsupportedMimeType = errors.New("UnsupportedMimeType")
|
||||
)
|
||||
|
||||
// 支持的图片扩展名列表
|
||||
var supportedImageExts = []string{
|
||||
".jpg", ".jpeg", ".png", ".gif", ".webp",
|
||||
// ".bmp", ".tiff", ".tif", ".svg", ".ico",
|
||||
}
|
||||
|
||||
func CompressImage(filePath string, mimeType string) (string, error) {
|
||||
compressedPath := filePath + "_compressed"
|
||||
switch mimeType {
|
||||
@@ -23,7 +35,23 @@ func CompressImage(filePath string, mimeType string) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
default:
|
||||
return "", errors.New("不支持的文件类型")
|
||||
return "", ErrUnsupportedMimeType
|
||||
}
|
||||
return compressedPath, nil
|
||||
}
|
||||
|
||||
func ConvertImageWithMagick(filePath, mimeType, targetExt string) (string, error) {
|
||||
// 验证目标扩展名是否合法
|
||||
if !lo.Contains(supportedImageExts, targetExt) {
|
||||
return "", ErrUnsupportedMimeType
|
||||
}
|
||||
|
||||
outputPath := filePath + "_converted" + targetExt
|
||||
|
||||
_, err := utils.RunCommand("magick", filePath, outputPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return outputPath, nil
|
||||
}
|
||||
|
||||
@@ -21,9 +21,19 @@ func RemoveFile(ctx context.Context, task *asynq.Task) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if fileInfo == nil || fileInfo.FileType == models.FileTypeUpload {
|
||||
if fileInfo == nil {
|
||||
return nil
|
||||
}
|
||||
// 如果文件是上传文件,则需要检查是否还有分享,考虑到比如文件转换这些一次性任务产生的文件需要销毁
|
||||
if fileInfo.FileType == models.FileTypeUpload {
|
||||
shareIDs, err := models.GetRedisFileShareRelational(payload.FileId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(shareIDs) > 0 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
rdb, rctx := u.GetRedisClient()
|
||||
uploadPath, err := utils.GetUploadDirPath()
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"mime"
|
||||
"path/filepath"
|
||||
"pkg/models"
|
||||
"worker/internal/services"
|
||||
@@ -19,7 +20,7 @@ func CompressImage(ctx context.Context, task *asynq.Task) error {
|
||||
}
|
||||
originalFileInfo, _ := models.GetRedisFileInfo(payload.FileId)
|
||||
if originalFileInfo == nil || originalFileInfo.FileType != models.FileTypeUpload {
|
||||
return errors.New("文件不存在")
|
||||
return ErrNotFoundFile
|
||||
}
|
||||
uploadPath, err := utils.GetUploadDirPath()
|
||||
if err != nil {
|
||||
|
||||
@@ -64,3 +64,49 @@ func TestCompressJPEGHappyPath(t *testing.T) {
|
||||
assert.NotEqual(t, origInfo.Size(), compInfo.Size())
|
||||
fmt.Printf("原图: %d | 压缩后: %d | 压缩率: %f%%\n", origInfo.Size(), compInfo.Size(), float64(compInfo.Size())/float64(origInfo.Size())*100)
|
||||
}
|
||||
|
||||
func TestConvertImageWithMagickPNGToJPG(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
filePath := filepath.Join(tmp, "test.png")
|
||||
// 从 test/resource 复制真实 PNG
|
||||
_, self, _, _ := runtime.Caller(0)
|
||||
srcPath := filepath.Join(filepath.Dir(self), "..", "resource", "test.png")
|
||||
err := utils.CopyFile(srcPath, filePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 测试 PNG 转 JPEG
|
||||
got, err := services.ConvertImageWithMagick(filePath, "image/png", ".jpg")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 验证输出文件路径
|
||||
assert.Equal(t, got, filePath+"_converted.jpg")
|
||||
|
||||
// 验证输出文件存在
|
||||
info, err := os.Stat(got)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.True(t, info.Size() > 0, "转换后的文件应该有内容")
|
||||
|
||||
fmt.Printf("PNG 转 JPEG 成功: %s (大小: %d bytes)\n", got, info.Size())
|
||||
}
|
||||
|
||||
func TestConvertImageWithMagickInvalidExt(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
filePath := filepath.Join(tmp, "test.png")
|
||||
_, self, _, _ := runtime.Caller(0)
|
||||
srcPath := filepath.Join(filepath.Dir(self), "..", "resource", "test.png")
|
||||
err := utils.CopyFile(srcPath, filePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// 测试非法扩展名(防止注入)
|
||||
_, err = services.ConvertImageWithMagick(filePath, "image/png", ".exe")
|
||||
assert.Error(t, err, "应该返回错误")
|
||||
assert.Equal(t, services.ErrInvalidImageExt, err, "应该返回 ErrInvalidImageExt 错误")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user