A:前端增加资料库页面

This commit is contained in:
jimmy committed 2025-06-17 07:12:11 +08:00
1 parent af259666b0
commit 4681084d98
5 files changed
+523

No files matched your search

+146
View File
@@ -0,0 +1,146 @@
package tools
import (
"context"
"encoding/json"
"fmt"
"rear/internal/utils"
"strings"
)
// ExifData EXIF 数据
type ExifData map[string]interface{}
// GetExifData 获取 EXIF 数据
func GetExifData(ctx context.Context, input string) (ExifData, error) {
if err := utils.EnsureInitialized(); err != nil {
return nil, err
}
result, err := utils.ExecuteCommand(ctx, utils.ExifToolPath, "-j", "-n", input)
if err != nil {
return nil, fmt.Errorf("exiftool failed: %w, stderr: %s", err, string(result.Stderr))
}
// 解析 JSON 输出
var data []ExifData
if err := json.Unmarshal(result.Stdout, &data); err != nil {
return nil, fmt.Errorf("failed to parse exif data: %w", err)
}
if len(data) == 0 {
return nil, fmt.Errorf("no exif data found")
}
return data[0], nil
}
// GetExifField 获取特定的 EXIF 字段
func GetExifField(ctx context.Context, input string, fields ...string) (map[string]string, error) {
if err := utils.EnsureInitialized(); err != nil {
return nil, err
}
args := []string{"-s", "-s", "-s"}
for _, field := range fields {
args = append(args, "-"+field)
}
args = append(args, input)
result, err := utils.ExecuteCommand(ctx, utils.ExifToolPath, args...)
if err != nil {
return nil, fmt.Errorf("exiftool failed: %w, stderr: %s", err, string(result.Stderr))
}
// 解析输出
data := make(map[string]string)
lines := strings.Split(string(result.Stdout), "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if line != "" {
// 简单解析,假设最后一个字段是值
parts := strings.Fields(line)
if len(parts) > 0 {
field := fields[len(data)]
data[field] = parts[len(parts)-1]
}
}
}
return data, nil
}
// RemoveExifData 移除 EXIF 数据
func RemoveExifData(ctx context.Context, input string, backup bool) error {
if err := utils.EnsureInitialized(); err != nil {
return err
}
args := []string{"-all="}
if !backup {
args = append(args, "-overwrite_original")
}
args = append(args, input)
result, err := utils.ExecuteCommand(ctx, utils.ExifToolPath, args...)
if err != nil {
return fmt.Errorf("remove exif failed: %w, stderr: %s", err, string(result.Stderr))
}
return nil
}
// CopyExifData 复制 EXIF 数据从一个文件到另一个文件
func CopyExifData(ctx context.Context, source, target string) error {
if err := utils.EnsureInitialized(); err != nil {
return err
}
args := []string{
"-TagsFromFile", source,
"-all:all",
"-overwrite_original",
target,
}
result, err := utils.ExecuteCommand(ctx, utils.ExifToolPath, args...)
if err != nil {
return fmt.Errorf("copy exif failed: %w, stderr: %s", err, string(result.Stderr))
}
return nil
}
// SetExifField 设置 EXIF 字段
func SetExifField(ctx context.Context, input string, fields map[string]string) error {
if err := utils.EnsureInitialized(); err != nil {
return err
}
args := []string{}
for key, value := range fields {
args = append(args, fmt.Sprintf("-%s=%s", key, value))
}
args = append(args, "-overwrite_original", input)
result, err := utils.ExecuteCommand(ctx, utils.ExifToolPath, args...)
if err != nil {
return fmt.Errorf("set exif failed: %w, stderr: %s", err, string(result.Stderr))
}
return nil
}
// IsExifToolAvailable 检查 ExifTool 是否可用
func IsExifToolAvailable() bool {
if err := utils.EnsureInitialized(); err != nil {
return false
}
return utils.ExifToolPath != ""
}
// GetToolPaths 获取工具路径(用于调试)
func GetToolPaths() (imageMagick, exifTool string) {
utils.EnsureInitialized()
return utils.ImageMagickPath, utils.ExifToolPath
}
+65
View File
@@ -0,0 +1,65 @@
package tools
import (
"context"
"fmt"
"rear/internal/utils"
)
// ImageInfo 图片信息
type ImageInfo struct {
Format string
Width int
Height int
ColorSpace string
FileSize string
}
// ConvertImage 使用 ImageMagick 转换图片
// 示例: ConvertImage(ctx, "input.jpg", "output.png", "-quality", "90")
func ConvertImage(ctx context.Context, input, output string, options ...string) error {
if err := utils.EnsureInitialized(); err != nil {
return err
}
args := append([]string{input}, options...)
args = append(args, output)
result, err := utils.ExecuteCommand(ctx, utils.ImageMagickPath, args...)
if err != nil {
return fmt.Errorf("convert failed: %w, stderr: %s", err, string(result.Stderr))
}
return nil
}
// ResizeImage 调整图片大小
func ResizeImage(ctx context.Context, input, output string, width, height int) error {
size := fmt.Sprintf("%dx%d", width, height)
return ConvertImage(ctx, input, output, "-resize", size)
}
// ResizeImageKeepAspect 按比例调整图片大小(保持宽高比)
func ResizeImageKeepAspect(ctx context.Context, input, output string, maxWidth, maxHeight int) error {
size := fmt.Sprintf("%dx%d>", maxWidth, maxHeight)
return ConvertImage(ctx, input, output, "-resize", size)
}
// CropImage 裁剪图片
func CropImage(ctx context.Context, input, output string, width, height, x, y int) error {
crop := fmt.Sprintf("%dx%d+%d+%d", width, height, x, y)
return ConvertImage(ctx, input, output, "-crop", crop)
}
// RotateImage 旋转图片
func RotateImage(ctx context.Context, input, output string, degrees float64) error {
return ConvertImage(ctx, input, output, "-rotate", fmt.Sprintf("%.2f", degrees))
}
// IsImageMagickAvailable 检查 ImageMagick 是否可用
func IsImageMagickAvailable() bool {
if err := utils.EnsureInitialized(); err != nil {
return false
}
return utils.ImageMagickPath != ""
}
+56
View File
@@ -0,0 +1,56 @@
package tools
import (
"context"
"fmt"
"sync"
"time"
)
// ========== 使用示例 ==========
func Example() {
ctx := context.Background()
// 1. 简单的图片处理
err := ResizeImage(ctx, "input.jpg", "output.jpg", 800, 600)
if err != nil {
fmt.Printf("Resize failed: %v\n", err)
}
// 2. 获取图片信息
//info, err := GetImageInfo(ctx, "photo.jpg")
//if err != nil {
// fmt.Printf("Get info failed: %v\n", err)
//}
//fmt.Printf("Image: %dx%d, Format: %s\n", info.Width, info.Height, info.Format)
// 3. 处理 EXIF
exifData, err := GetExifData(ctx, "photo.jpg")
if err != nil {
fmt.Printf("Get EXIF failed: %v\n", err)
}
fmt.Printf("EXIF: %v\n", exifData)
// 4. 在 goroutine 中使用(并发安全)
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(index int) {
defer wg.Done()
// 每个 goroutine 可以安全地调用这些函数
input := fmt.Sprintf("img%d.jpg", index)
output := fmt.Sprintf("thumb%d.jpg", index)
// 使用带超时的 context
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := ResizeImage(ctx, input, output, 200, 200); err != nil {
fmt.Printf("Error processing %s: %v\n", input, err)
}
}(i)
}
wg.Wait()
}