Home > Software engineering >  How to make Firefox's canvas behave the same as in Chromium-based browsers?
How to make Firefox's canvas behave the same as in Chromium-based browsers?

Time:09-25

In Chromium-based browsers (I'm using brave), canvas is rendering this way:

enter image description here

But in Firefox, for some reason, it's rendering this way:

enter image description here

Here is the method I'm using:

context.drawImage(image, 100, 100, 100, 400);

I'm not using any CSS on the canvas element, just this:

html,
body {
  width: 100%;
  height: 100%;
  margin: 0;
  overflow: hidden;
}

And this to resize and append the canvas:

const canvas = document.createElement("canvas");
document.body.appendChild(canvas);

export const graphics = canvas.getContext("2d");

const adaptResolution = () => {
  canvas.width = innerWidth;
  canvas.height = innerHeight;
};

adaptResolution();
addEventListener("resize", adaptResolution);

Can I make the Firefox's canvas behave the same as in Chromium-based browsers? What is causing this difference and how can I fix it?


This is the SVG I'm trying to render on screen:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   width="768"
   height="576"
   viewBox="0 0 203.2 152.4"
   version="1.1"
   id="svg5"
   inkscape:version="1.1 (c68e22c387, 2021-05-23)"
   sodipodi:docname="box.svg"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg">
  <sodipodi:namedview
     id="namedview7"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageshadow="2"
     inkscape:pageopacity="0.0"
     inkscape:pagecheckerboard="0"
     inkscape:document-units="px"
     showgrid="false"
     units="px"
     inkscape:zoom="0.38752104"
     inkscape:cx="107.09096"
     inkscape:cy="187.08661"
     inkscape:window-width="1920"
     inkscape:window-height="1016"
     inkscape:window-x="0"
     inkscape:window-y="27"
     inkscape:window-maximized="1"
     inkscape:current-layer="layer1" />
  <defs
     id="defs2" />
  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1">
    <rect
       style="fill:#000000;stroke-width:0.387859"
       id="rect31"
       width="206.87587"
       height="153.6207"
       x="-1.7069"
       y="-1.7068989" />
  </g>
</svg>

CodePudding user response:

This is an interop issue that I already reported on the specs.
Unfortunately it didn't get much traction yet...

The issue is that it's currently unclear on which "image" drawImage's resizing options should act. Chrome considers that it should treat the input svg at its default size and stretch it, Firefox considers that the resizing options are the output box and will adapt the svg content to this box.

To get Chrome's behavior in Firefox, you can add a preserveAspectRatio="none" attribute to the root of your SVG image:

const svg = new Blob([`<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   preserveAspectRatio="none"
   width="768"
   height="576"
   viewBox="0 0 203.2 152.4"
   version="1.1"
   id="svg5"
   inkscape:version="1.1 (c68e22c387, 2021-05-23)"
   sodipodi:docname="box.svg"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:svg="http://www.w3.org/2000/svg">
  <sodipodi:namedview
     id="namedview7"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageshadow="2"
     inkscape:pageopacity="0.0"
     inkscape:pagecheckerboard="0"
     inkscape:document-units="px"
     showgrid="false"
     units="px"
     inkscape:zoom="0.38752104"
     inkscape:cx="107.09096"
     inkscape:cy="187.08661"
     inkscape:window-width="1920"
     inkscape:window-height="1016"
     inkscape:window-x="0"
     inkscape:window-y="27"
     inkscape:window-maximized="1"
     inkscape:current-layer="layer1" />
  <defs
     id="defs2" />
  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1">
    <rect
       style="fill:#000000;stroke-width:0.387859"
       id="rect31"
       width="206.87587"
       height="153.6207"
       x="-1.7069"
       y="-1.7068989" />
  </g>
</svg>`], { type:"image/svg xml"});
const img = new Image();
img.src = URL.createObjectURL(svg);
img.onload = e => document.querySelector("canvas").getContext("2d").drawImage(img, 0, 0, 100, 400);
<canvas width="500" height="500"></canvas>

  • Related