5

I have an SVG displayed on a page that uses Google Fonts.

<text> node on the SVG inherits Google Font nicely.

Now, I'm trying to convert the SVG using Blob.

This works, except <text> is rendered using fallback "Verdana", which is installed on browser machine, not "Pacifico" which is a dynamically-loaded Google Font.

window.onload = function() {
  var width = 400;
  var height = 100;

  var DOMURL = self.URL || self.webkitURL || self;
  var data = new XMLSerializer().serializeToString(document.getElementById("test"));

  var svg = new Blob([data], { type: "image/svg+xml" });
  var url = DOMURL.createObjectURL(svg);

  var canvas = document.getElementById("result");
  canvas.width = width;
  canvas.height = height;
  var ctx = canvas.getContext("2d");

  var img = new Image(width, height);
  img.onload = function() {
    ctx.drawImage(img, 0, 0);
    DOMURL.revokeObjectURL(url);
  }
  img.src = url;
}
@import url('https://fonts.googleapis.com/css?family=Pacifico');
body {
  font-family: Pacifico, Verdana;
  font-size: 15px;
}
body * {
  font-family: Pacifico, Verdana;
}

#test, #result {
  border: 1px solid #eee;
}

h4 {
  margin: 2em 0 1em 0;
}
<h4>Source SVG</h4>
<svg id="test" width="400px" height="100px" style="font-family: 'Pacifico', 'Verdana'; font-size: 15px;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <g xmlns="http://www.w3.org/2000/svg">
    <rect fill="#67b7dc" transform="translate(-0.5,-0.5)" width="80" height="100" />
    <rect fill="#6794dc" transform="translate(80,0)" transform="translate(-0.5,-0.5)" width="80" height="100" />
    <rect fill="#6771dc" transform="translate(160,0)" transform="translate(-0.5,-0.5)" width="80" height="100" />
    <rect fill="#8067dc" transform="translate(240,0)" transform="translate(-0.5,-0.5)" width="80" height="100" />
    <rect fill="#a367dc" transform="translate(320,0)" transform="translate(-0.5,-0.5)" width="80" height="100" />
    <text fill="#fff" transform="translate(20,20)" font-size="25" dy="20">
      Some text using font</tspan>
    </text>
  </g>
</svg>
  
<h4>Result canvas</h4>
<canvas id="result" />

So far I haven't been able to find a way to make canvas text use custom font, and would appreciate any help with that.

P.S. For the record, I know about existence of 3rd party libs like fabric and canvg. They are able to convert SVG to Canvas without losing custom fonts. However, I'm trying to get away with not using any 3rd party libs, to keep it light.

P.P.S. Including Google Fonts' @import into <defs><style> section of the SVG does not help, even if we explicitly define @font-face. And frankly that would not be an option, since I don't yet know with what fonts the library will be used.

P.P.P.S Delaying export does not help, so it's probably not a timing issue, either.

martynasma
  • 8,542
  • 2
  • 28
  • 45
  • This looks promising, but addresses only part of the issue. I don't know particular font or its URL, or even if it is a Google Font. Would still appreciate a solution on how to go implement that. – martynasma Aug 06 '18 at 08:25

1 Answers1

1

You probably focusing all you energy on canvas, but the problem already starts on your image...

Here is your code, but just a very minimal example

<style>
  @import url('https://fonts.googleapis.com/css?family=Pacifico');
  body * { margin: 0; }
</style>

<h4>Source</h4>
<svg id="test" width="300px" height="30px" style="font-family: 'Pacifico', 'Verdana'; font-size: 15px;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <g xmlns="http://www.w3.org/2000/svg">
    <rect fill="#67b7dc" transform="translate(-0.5,-0.5)" width="300" height="50" />
    <text fill="#fff"  font-size="25" dy="20"> <tspan>Some text using font</tspan> </text>
  </g>
</svg>

<h4>Image</h4>
<img id="image" />

<script>
  window.onload = function() {
    var DOMURL = self.URL || self.webkitURL || self;
    var data = new XMLSerializer().serializeToString(document.getElementById("test"));

    var svg = new Blob([data], { type: "image/svg+xml" });
    var url = DOMURL.createObjectURL(svg);

    var img = document.getElementById("image");
    img.src = url;
  }
</script>

There is a lot of debate about this issue with SVG fonts, here is a good article to start:

https://github.com/JChemPaint/jchempaint/wiki/The-svg-font-problem-and-its-solution

Helder Sepulveda
  • 15,500
  • 4
  • 29
  • 56