package svg import ( "bytes" "encoding/hex" "encoding/xml" "errors" "fmt" "image" "image/color" "io" "path/filepath" "strconv" "strings" "github.com/srwiley/oksvg" "github.com/srwiley/rasterx" "fyne.io/fyne/v2" col "fyne.io/fyne/v2/internal/color" ) // Colorize creates a new SVG from a given one by replacing all fill colors by the given color. func Colorize(src []byte, clr color.Color) []byte { rdr := bytes.NewReader(src) s, err := svgFromXML(rdr) if err != nil { fyne.LogError("could not load SVG, falling back to static content:", err) return src } if err := s.replaceFillColor(clr); err != nil { fyne.LogError("could not replace fill color, falling back to static content:", err) return src } colorized, err := xml.Marshal(s) if err != nil { fyne.LogError("could not marshal svg, falling back to static content:", err) return src } return colorized } type Decoder struct { icon *oksvg.SvgIcon } type Config struct { Width int Height int Aspect float32 } func NewDecoder(stream io.Reader) (*Decoder, error) { icon, err := oksvg.ReadIconStream(stream) if err != nil { return nil, err } return &Decoder{ icon: icon, }, nil } func (d *Decoder) Config() Config { return Config{ int(d.icon.ViewBox.W), int(d.icon.ViewBox.H), float32(d.icon.ViewBox.W / d.icon.ViewBox.H), } } func (d *Decoder) Draw(width, height int) (*image.NRGBA, error) { config := d.Config() viewAspect := float32(width) / float32(height) imgW, imgH := width, height if viewAspect > config.Aspect { imgW = int(float32(height) * config.Aspect) } else if viewAspect < config.Aspect { imgH = int(float32(width) / config.Aspect) } d.icon.SetTarget(0, 0, float64(imgW), float64(imgH)) img := image.NewNRGBA(image.Rect(0, 0, imgW, imgH)) scanner := rasterx.NewScannerGV(config.Width, config.Height, img, img.Bounds()) raster := rasterx.NewDasher(width, height, scanner) err := drawSVGSafely(d.icon, raster) if err != nil { err = fmt.Errorf("SVG render error: %w", err) return nil, err } return img, nil } func IsFileSVG(path string) bool { return strings.ToLower(filepath.Ext(path)) == ".svg" } // IsResourceSVG checks if the resource is an SVG or not. func IsResourceSVG(res fyne.Resource) bool { if strings.ToLower(filepath.Ext(res.Name())) == ".svg" { return true } if len(res.Content()) < 5 { return false } switch strings.ToLower(string(res.Content()[:5])) { case "