Search code examples
javascriptsvgdata-uri

Why do my SVG icons with viewBox and hex encoded colors fail to render when used as '.src' for javascript Image()


My previous question was closed as a duplicate, but I found now the real answer to the problem.

So the original question, I wanted to know why the hex colors and viewbox on my .SVG icons seemed to preventing them from showing. I had been using base64, and I decoded the base64 so that I could ask the question easier, including the following fiddle (code included below for completeness). The first icon shows, the second not.

It was suggested that the hex colors needed to be escaped with a %23. And the question was closed as being a duplicate for this reason. I could not work out how to remove the duplicate question marking, so I have created this new question to share my discovery with my own answer.

https://jsfiddle.net/pqh0n1mw/1/

var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
ctx.scale(2, 2);

var img1 = new Image();
img1.src = 'data:image/svg+xml;utf8,<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32"><rect stroke="none" fill="rgb(255, 38, 0)" x="0" y="0" width="32" height="32" /><path stroke="none" fill="rgb(250, 250, 250)" d="M 0,8 L 8,8 8,-0 12,-0 12,12 0,12 0,8 Z M 0,8" /><path stroke="rgb(255, 255, 255)" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" fill="none" d="M 1.5,1.5 L 17.5,17.5" /></svg>';

ctx.drawImage(img1, 10, 10);

var img2 = new Image();
img2.src = 'data:image/svg+xml;utf8,<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect fill="#FF2600" width="32" height="32"/><path fill="#FAFAFA" d="M0,8 8,8 8,-0 12,-0 12,12 0,12 Z"/><path stroke="#FFFFFF" stroke-width="3" stroke-linecap="round" stroke-miterlimit="10" fill="none" d="M1.5,1.5 17.5,17.5"/></svg>';
ctx.drawImage(img2, 42, 10);

Solution

  • So it turns out that encoding the # in the hex color as %23 made things worse, and the b64 encoded icon no longer showed. And anyway, I am not using the data-url as a url() in .css where I understood it might be seen as a selector.

    It was also suggested that using codepen would solve the issue. This also did not work, since codepen escapes the colors and even the angle brackets, something which should not be needed for .svg used in this way.

    So the problem turned out to be the solo use of 'viewBox'. Which worked fine on another platform where these icons were taken from, but not in javascript when used as a Image().src property.

    Anyway with the 'viewBox' replaced with 'width' and 'height' properties, the icons now display, including the using of the hex encoded colors, in the original base64 encoded format.

    I hope that helps someone else, or maybe my future self when I trip over the same problem again :)

    var img3 = new Image();
    img3.src = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjMyIiBoZWlnaHQ9IjMyIj48cmVjdCBmaWxsPSIjRkYyNjAwIiB3aWR0aD0iMzIiIGhlaWdodD0iMzIiLz48cGF0aCBmaWxsPSIjRkFGQUZBIiBkPSJNMCw4IDgsOCA4LC0wIDEyLC0wIDEyLDEyIDAsMTIgWiIvPjxwYXRoIHN0cm9rZT0iI0ZGRkZGRiIgc3Ryb2tlLXdpZHRoPSIzIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgZmlsbD0ibm9uZSIgZD0iTTEuNSwxLjUgMTcuNSwxNy41Ii8+PC9zdmc+";
    ctx.drawImage(img3, 74, 10);
    

    [update] I tested with latest firefox 78.3.0.esr and see similar behaviour. I also tested my icons in as CSS url() backgrounds, and they work fine with the original format of viewBox (no width & height) and hex colours when encoded as base64. So it seems like the processing via an Image().src is different.

    [update2] as pointed out below, I should be using an onload callback even for b64 encoded images since not all browsers make the image available immediately.

    safe way to access data url image