1

I am styling an SVG image using CSS in a separate file. Then I am rendering the SVG onto a canvas that can be saved as a PNG.

The SVG receives the CSS styles properly when it is just an SVG element on an HTML page, and renders as expected. However, when the SVG is rendered in a canvas element, the styles are not applied.

Is it possible to use external CSS to style an SVG and save that to a canvas without losing the styles? I cannot use inline CSS due to Content Security Policy in the browser.

Here is a sample.

index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>svg to png</title>
  <link rel="stylesheet" href="./style.css">
</head>

<body>
  <button>svg to png</button>
  <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200" height="200">

    <path d="M10 40, C20 20, 50 20, 70 30, 70 30, 110 50, 160 20" id="path-1" fill="#CCCCCC" />

    <text class="text-red">
      <textpath xlink:href="#path-1" startOffset="50%" text-anchor="middle">Sample Path Text</textpath>
    </text>

    <rect x="10" y="14" width="10" height="10" />

    <text x="0" y="100" class="text-primary">Text Style 1</text>
    <text x="0" y="150" class="text-secondary">Text Style 2</text>
  </svg>

  <canvas id="canvas"></canvas>
  <script src="./script.js"></script>

</body>

</html>

style.css

.text-primary {
  font-size: 24px;
  font-family: calibri;
}

.text-secondary {
  font-size: 12px;
  font-family: arial;
}

.text-red {
  fill: #ff0000;
}

script.js

var btn = document.querySelector("button");
var svg = document.querySelector("svg");
var canvas = document.querySelector("canvas");

btn.addEventListener("click", function () {
  var canvas = document.getElementById("canvas");
  var ctx = canvas.getContext("2d");
  var data = new XMLSerializer().serializeToString(svg);
  var DOMURL = window.URL || window.webkitURL || window;

  var img = new Image();
  var svgBlob = new Blob([data], { type: "image/svg+xml;charset=utf-8" });
  var url = DOMURL.createObjectURL(svgBlob);

  img.onload = function () {
    ctx.drawImage(img, 0, 0);
    DOMURL.revokeObjectURL(url);

    var imgURI = canvas
      .toDataURL("image/png")
      .replace("image/png", "image/octet-stream");
  };

  img.src = url;
});

Here is a render of the basic example, svg on the left and canvas on the right.

css styles applied to svg on left, css styles not applied to svg on canvas on right

  • Where is it that you connect the styles to the SVG? There's no – Robert Longson Apr 10 '21 at 07:34
  • I think you'll have to write the styles direct into the SVG text elements. Or pick them up from the class and write them in at run time - does this help? [link]https://stackoverflow.com/questions/29675279/how-to-style-canvas-elements-with-css – A Haworth Apr 10 '21 at 11:38
  • Are the stylesheets accessible as same-origin? With this CSP you'd have to fetch them as text and reinject them in the svg file as text too, which is dirty... – Kaiido Apr 10 '21 at 11:43

0 Answers0