You've already forked VptPassiveAdapter
- 新增 CompressionConfig、ThumbnailConfig 和 ImageProcessingConfig 结构体用于图像处理配置 - 实现 GetEffectiveConfig 方法提供图像处理配置的默认值 - 在 UploadConfig 中添加 ImageProcessing 字段传递服务器配置 - 移除客户端本地缩略图生成功能,改用服务器端处理 - 添加 UploadFaceDataWithProcessing 函数实现带图像处理的上传流程 - 实现 configToImageOptions 函数将服务器配置转换为图像处理选项 - 在 util/image.go 中添加完整的图像处理功能,支持裁切和缩放模式 - 更新依赖添加 golang.org/x/image 用于高质量图像缩放 - 添加 .claude 到 .gitignore 文件
172 lines
5.4 KiB
Go
172 lines
5.4 KiB
Go
package api
|
|
|
|
import (
|
|
"ZhenTuLocalPassiveAdapter/logger"
|
|
"ZhenTuLocalPassiveAdapter/util"
|
|
"context"
|
|
"fmt"
|
|
|
|
"go.uber.org/zap"
|
|
"golang.org/x/sync/errgroup"
|
|
)
|
|
|
|
// UploadFaceDataWithProcessing 带图像处理的上传流程
|
|
// 根据服务器返回的配置处理图像后上传
|
|
func UploadFaceDataWithProcessing(ctx context.Context, scenicId int64, deviceNo string, faceImg, srcImg []byte, faceRect [4]int, facePos FacePositionInfo) error {
|
|
// 1. 获取上传配置(包含图像处理配置)
|
|
uploadConfig, err := GetUploadConfig(ctx, scenicId, deviceNo)
|
|
if err != nil {
|
|
logger.Error("获取上传配置失败", zap.String("deviceNo", deviceNo), zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
logger.Info("获取到VIID任务ID",
|
|
zap.Int64("taskId", uploadConfig.TaskID),
|
|
zap.Bool("hasImageProcessing", uploadConfig.ImageProcessing != nil))
|
|
|
|
// 2. 将服务器配置转换为图像处理选项
|
|
imgOpts := configToImageOptions(uploadConfig.ImageProcessing)
|
|
|
|
// 3. 处理图像
|
|
processedImages, err := util.ProcessImages(faceImg, srcImg, faceRect, imgOpts)
|
|
if err != nil {
|
|
SubmitFailure(ctx, uploadConfig.TaskID, "IMAGE_PROCESSING_FAILED", err.Error())
|
|
logger.Error("图像处理失败", zap.Int64("taskId", uploadConfig.TaskID), zap.Error(err))
|
|
return fmt.Errorf("image processing failed: %w", err)
|
|
}
|
|
|
|
logger.Debug("图像处理完成",
|
|
zap.Int64("taskId", uploadConfig.TaskID),
|
|
zap.Int("faceSize", len(processedImages.FaceData)),
|
|
zap.Int("thumbSize", len(processedImages.ThumbData)),
|
|
zap.Int("sourceSize", len(processedImages.SourceData)))
|
|
|
|
// 4. 并行上传到OSS
|
|
g, subCtx := errgroup.WithContext(ctx)
|
|
|
|
// 上传人脸图
|
|
g.Go(func() error {
|
|
if len(processedImages.FaceData) > 0 {
|
|
if err := UploadFileToOSS(subCtx, uploadConfig.FaceUploadURL, processedImages.FaceData, "image/jpeg"); err != nil {
|
|
return fmt.Errorf("upload face image failed: %w", err)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
// 上传缩略图
|
|
g.Go(func() error {
|
|
if len(processedImages.ThumbData) > 0 {
|
|
if err := UploadFileToOSS(subCtx, uploadConfig.ThumbnailUploadURL, processedImages.ThumbData, "image/jpeg"); err != nil {
|
|
return fmt.Errorf("upload thumbnail image failed: %w", err)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
// 上传原图
|
|
g.Go(func() error {
|
|
if len(processedImages.SourceData) > 0 {
|
|
if err := UploadFileToOSS(subCtx, uploadConfig.SourceUploadURL, processedImages.SourceData, "image/jpeg"); err != nil {
|
|
return fmt.Errorf("upload source image failed: %w", err)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if err := g.Wait(); err != nil {
|
|
SubmitFailure(ctx, uploadConfig.TaskID, "UPLOAD_FAILED", err.Error())
|
|
logger.Error("文件上传失败", zap.Int64("taskId", uploadConfig.TaskID), zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
// 5. 提交结果
|
|
if err := SubmitResult(ctx, uploadConfig.TaskID, facePos); err != nil {
|
|
logger.Error("提交结果失败", zap.Int64("taskId", uploadConfig.TaskID), zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
logger.Info("VIID任务完成", zap.Int64("taskId", uploadConfig.TaskID))
|
|
return nil
|
|
}
|
|
|
|
// configToImageOptions 将服务器配置转换为图像处理选项
|
|
func configToImageOptions(config *ImageProcessingConfig) *util.ImageProcessingOptions {
|
|
// 应用默认值
|
|
effectiveConfig := config.GetEffectiveConfig()
|
|
|
|
opts := &util.ImageProcessingOptions{
|
|
// 原图压缩配置
|
|
SourceCompressionEnabled: effectiveConfig.SourceCompression.Enabled,
|
|
SourceQuality: effectiveConfig.SourceCompression.Quality,
|
|
|
|
// 缩略图配置
|
|
ThumbnailMode: effectiveConfig.Thumbnail.Mode,
|
|
ThumbnailShrinkRatio: effectiveConfig.Thumbnail.ShrinkRatio,
|
|
ThumbnailQuality: effectiveConfig.Thumbnail.Quality,
|
|
}
|
|
|
|
return opts
|
|
}
|
|
|
|
// UploadFaceData 已有的上传流程(向后兼容)
|
|
// 已废弃:请使用 UploadFaceDataWithProcessing
|
|
func UploadFaceData(ctx context.Context, scenicId int64, deviceNo string, faceImg, thumbImg, srcImg []byte, facePos FacePositionInfo) error {
|
|
// 1. 获取上传配置
|
|
uploadConfig, err := GetUploadConfig(ctx, scenicId, deviceNo)
|
|
if err != nil {
|
|
logger.Error("获取上传配置失败", zap.String("deviceNo", deviceNo), zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
logger.Info("获取到VIID任务ID", zap.Int64("taskId", uploadConfig.TaskID))
|
|
|
|
// 2. 并行上传到OSS
|
|
g, subCtx := errgroup.WithContext(ctx)
|
|
|
|
// 上传人脸图
|
|
g.Go(func() error {
|
|
if len(faceImg) > 0 {
|
|
if err := UploadFileToOSS(subCtx, uploadConfig.FaceUploadURL, faceImg, "image/jpeg"); err != nil {
|
|
return fmt.Errorf("upload face image failed: %w", err)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
// 上传缩略图
|
|
g.Go(func() error {
|
|
if len(thumbImg) > 0 {
|
|
if err := UploadFileToOSS(subCtx, uploadConfig.ThumbnailUploadURL, thumbImg, "image/jpeg"); err != nil {
|
|
return fmt.Errorf("upload thumbnail image failed: %w", err)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
// 上传原图
|
|
g.Go(func() error {
|
|
if len(srcImg) > 0 {
|
|
if err := UploadFileToOSS(subCtx, uploadConfig.SourceUploadURL, srcImg, "image/jpeg"); err != nil {
|
|
return fmt.Errorf("upload source image failed: %w", err)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if err := g.Wait(); err != nil {
|
|
SubmitFailure(ctx, uploadConfig.TaskID, "UPLOAD_FAILED", err.Error())
|
|
logger.Error("文件上传失败", zap.Int64("taskId", uploadConfig.TaskID), zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
// 3. 提交结果
|
|
if err := SubmitResult(ctx, uploadConfig.TaskID, facePos); err != nil {
|
|
logger.Error("提交结果失败", zap.Int64("taskId", uploadConfig.TaskID), zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
logger.Info("VIID任务完成", zap.Int64("taskId", uploadConfig.TaskID))
|
|
return nil
|
|
}
|