svg.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. package render
  2. import (
  3. "bytes"
  4. "image"
  5. "image/draw"
  6. "io"
  7. "github.com/go-text/typesetting/opentype/api"
  8. "github.com/go-text/typesetting/shaping"
  9. "github.com/srwiley/oksvg"
  10. "github.com/srwiley/rasterx"
  11. )
  12. func (r *Renderer) drawSVG(g shaping.Glyph, svg api.GlyphSVG, img draw.Image, x, y float32) error {
  13. pixWidth := int(fixed266ToFloat(g.Width) * r.PixScale)
  14. pixHeight := int(fixed266ToFloat(-g.Height) * r.PixScale)
  15. pix, err := renderSVGStream(bytes.NewReader(svg.Source), pixWidth, pixHeight)
  16. if err != nil {
  17. return err
  18. }
  19. rect := image.Rect(int(fixed266ToFloat(g.XBearing)*r.PixScale), int(fixed266ToFloat(-g.YBearing)*r.PixScale),
  20. pixWidth, pixHeight)
  21. draw.Draw(img, rect.Add(image.Point{X: int(x), Y: int(y)}), pix, image.Point{}, draw.Over)
  22. // ignore the svg.Outline shapes, as they are a fallback which we won't use
  23. return nil
  24. }
  25. func renderSVGStream(stream io.Reader, width, height int) (*image.NRGBA, error) {
  26. icon, err := oksvg.ReadIconStream(stream)
  27. if err != nil {
  28. return nil, err
  29. }
  30. iconAspect := float32(icon.ViewBox.W / icon.ViewBox.H)
  31. viewAspect := float32(width) / float32(height)
  32. imgW, imgH := width, height
  33. if viewAspect > iconAspect {
  34. imgW = int(float32(height) * iconAspect)
  35. } else if viewAspect < iconAspect {
  36. imgH = int(float32(width) / iconAspect)
  37. }
  38. icon.SetTarget(icon.ViewBox.X, icon.ViewBox.Y, float64(imgW), float64(imgH))
  39. out := image.NewNRGBA(image.Rect(0, 0, imgW, imgH))
  40. scanner := rasterx.NewScannerGV(int(icon.ViewBox.W), int(icon.ViewBox.H), out, out.Bounds())
  41. raster := rasterx.NewDasher(width, height, scanner)
  42. icon.Draw(raster, 1)
  43. return out, nil
  44. }