package probe import ( "fmt" "image" "os" "path/filepath" "strings" ) // supportImageTypes 支持的标准图片扩展名(大小写不敏感) var supportImageTypes = []string{ ".bmp", ".gif", ".jpg", ".jpeg", ".jpe", ".png", ".webp", ".psb", ".jfif", } // IsSupportImage 判断扩展名是否属于支持的图片格式 func IsSupportImage(ext string) bool { for _, t := range supportImageTypes { if strings.EqualFold(t, ext) { return true } } return false } // ProbeImage 统一探测图片尺寸: // 1. 特殊格式(webp/bmp/psd/psb)走专用解码器,失败后用 ffprobe 兜底 // 2. 其余白名单格式走 Go 标准库 image.DecodeConfig // 3. 标准库失败时用 ffprobe 兜底(ffmpeg 支持的图片格式更广,如 tiff/svg 等) // // ffprobePath 为空表示不启用 ffprobe 兜底;非白名单扩展名(如 tiff)在 ffprobe 可用时兜底探测。 func ProbeImage(filePath, ffprobePath string) (*ProbeResult, error) { ext := strings.ToLower(filepath.Ext(filePath)) switch ext { case ".webp": if res, err := probeWebp(filePath); err == nil { return res, nil } case ".bmp": if res, err := probeBmp(filePath); err == nil { return res, nil } case ".psd", ".psb": if res, err := probePsd(filePath); err == nil { return res, nil } } if !IsSupportImage(ext) { // 非白名单扩展名(tiff/svg 等):ffprobe 可用时兜底探测,否则视为不支持 if res, err := probeByFFprobe(ffprobePath, filePath); err == nil { return res, nil } return nil, fmt.Errorf("不支持的图片格式: %s", ext) } if w, h, err := decodeConfig(filePath); err == nil { return &ProbeResult{Width: w, Height: h}, nil } if res, err := probeByFFprobe(ffprobePath, filePath); err == nil { return res, nil } return nil, fmt.Errorf("无法读取图片尺寸: %s", filePath) } // probeByFFprobe 用 ffprobe 兜底探测图片尺寸;ffprobePath 为空或探测失败时返回错误 func probeByFFprobe(ffprobePath, filePath string) (*ProbeResult, error) { if ffprobePath == "" { return nil, fmt.Errorf("未启用 ffprobe 兜底") } if res, err := ProbeMediaFile(ffprobePath, filePath); err == nil && res.HasVideo { return res, nil } return nil, fmt.Errorf("ffprobe 兜底失败: %s", filePath) } // decodeConfig 用 Go 标准库读取图片宽高 func decodeConfig(filePath string) (int, int, error) { f, err := os.Open(filePath) if err != nil { return 0, 0, err } defer f.Close() cfg, _, err := image.DecodeConfig(f) if err != nil { return 0, 0, err } return cfg.Width, cfg.Height, nil }