package imglib import ( "bytes" "encoding/base64" "fmt" "image" _ "image/jpeg" _ "image/png" "os" "strings" "time" "github.com/valyala/fasthttp" ) // ImageInput 统一图片输入源,支持三种加载方式 type ImageInput struct { FilePath string // 磁盘文件路径 URL string // 网络 URL(http/https) Base64 string // Base64 编码的图片数据(可带 data:image/xxx;base64, 前缀) } // NewImageInputFromFile 从文件路径创建输入源 func NewImageInputFromFile(path string) ImageInput { return ImageInput{FilePath: path} } // NewImageInputFromURL 从网络 URL 创建输入源 func NewImageInputFromURL(url string) ImageInput { return ImageInput{URL: url} } // NewImageInputFromBase64 从 Base64 字符串创建输入源 func NewImageInputFromBase64(b64 string) ImageInput { return ImageInput{Base64: b64} } // Load 加载图片,返回解码后的 image.Image 和格式名称 func (in ImageInput) Load() (image.Image, string, error) { switch { case in.Base64 != "": return loadImageFromBase64(in.Base64) case in.URL != "": return loadImageFromURL(in.URL, 120) case in.FilePath != "": return loadImageFromFile(in.FilePath) default: return nil, "", fmt.Errorf("ImageInput 未设置任何输入源(FilePath/URL/Base64 均为空)") } } // loadImageFromFile 从磁盘文件加载图片 func loadImageFromFile(path string) (image.Image, string, error) { file, err := os.Open(path) if err != nil { return nil, "", fmt.Errorf("打开图片文件失败: %v", err) } defer file.Close() img, format, err := image.Decode(file) if err != nil { return nil, "", fmt.Errorf("解码图片失败: %v", err) } return img, format, nil } // loadImageFromURL 从网络 URL 加载图片 func loadImageFromURL(url string, timeout int) (image.Image, string, error) { if timeout <= 0 { timeout = 120 } req := fasthttp.AcquireRequest() resp := fasthttp.AcquireResponse() defer fasthttp.ReleaseRequest(req) defer fasthttp.ReleaseResponse(resp) req.SetRequestURI(url) req.Header.SetMethod("GET") req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") req.Header.Set("Accept", "image/avif,image/webp,image/apng,image/*,*/*;q=0.8") client := &fasthttp.Client{ ReadTimeout: time.Duration(timeout) * time.Second, WriteTimeout: time.Duration(timeout) * time.Second, } err := client.Do(req, resp) if err != nil { return nil, "", fmt.Errorf("请求失败: %v", err) } body := resp.Body() imgData := make([]byte, len(body)) copy(imgData, body) img, format, err := image.Decode(bytes.NewReader(imgData)) if err != nil { return nil, "", fmt.Errorf("解码图片失败: %v", err) } return img, format, nil } // loadImageFromBase64 从 Base64 字符串加载图片 func loadImageFromBase64(b64 string) (image.Image, string, error) { b64 = strings.TrimPrefix(b64, "data:image/jpeg;base64,") b64 = strings.TrimPrefix(b64, "data:image/jpg;base64,") b64 = strings.TrimPrefix(b64, "data:image/png;base64,") b64 = strings.TrimPrefix(b64, "data:image/gif;base64,") b64 = strings.TrimPrefix(b64, "data:image/webp;base64,") imgData, err := base64.StdEncoding.DecodeString(b64) if err != nil { return nil, "", fmt.Errorf("解码 base64 失败: %v", err) } img, format, err := image.Decode(bytes.NewReader(imgData)) if err != nil { return nil, "", fmt.Errorf("解码 base64 图片失败: %v", err) } return img, format, nil }