package compositor import ( "fmt" "image" "image/color" "image/png" "net/http" "strings" "time" _ "image/jpeg" ) var httpClient = &http.Client{ Timeout: 30 * time.Second, } // DownloadImage 从 URL 下载并解码图片,返回 image.Image func DownloadImage(url string) (image.Image, error) { url = strings.TrimSpace(url) if url == "" { return nil, fmt.Errorf("empty URL") } resp, err := httpClient.Get(url) if err != nil { return nil, fmt.Errorf("download failed: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("download returned HTTP %d", resp.StatusCode) } img, _, err := image.Decode(resp.Body) if err != nil { return nil, fmt.Errorf("decode failed: %w", err) } return img, nil } // DownloadDecodePNG 下载并强制解码为 PNG(获取 alpha 通道) func DownloadDecodePNG(url string) (image.Image, error) { url = strings.TrimSpace(url) if url == "" { return nil, fmt.Errorf("empty URL") } resp, err := httpClient.Get(url) if err != nil { return nil, fmt.Errorf("download failed: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("download returned HTTP %d", resp.StatusCode) } img, err := png.Decode(resp.Body) if err != nil { return DownloadImage(url) } return img, nil } // ExtractAlpha 将白色/浅灰背景转换为透明,保留非白色像素 func ExtractAlpha(img image.Image) *image.NRGBA { bounds := img.Bounds() result := image.NewNRGBA(bounds) for y := bounds.Min.Y; y < bounds.Max.Y; y++ { for x := bounds.Min.X; x < bounds.Max.X; x++ { r, g, b, a := img.At(x, y).RGBA() rf := float64(r) / 65535.0 gf := float64(g) / 65535.0 bf := float64(b) / 65535.0 // 亮度 > 90% 的视为白色/浅灰背景,设为透明 luminance := (rf + gf + bf) / 3.0 if luminance > 0.90 { result.SetNRGBA(x, y, color.NRGBA{R: 0, G: 0, B: 0, A: 0}) } else { result.SetNRGBA(x, y, color.NRGBA{ R: uint8(r >> 8), G: uint8(g >> 8), B: uint8(b >> 8), A: uint8(a >> 8), }) } } } return result }