Search code examples
htmlcsshtml5-canvas

Why does the HTML Canvas image appear pixelated?


Problem

I've placed the same image (Netflix) using simple HTML vs using Canvas, and the Canvas version is a lot more pixelated that the simple tag version.

What I've tried

  • I've tried changing the scale of the Canvas and setting the window.pixelDeviceRatio = 2 and it does improve it slightly, but still seems pixelated.
  • I've also tried setting context.imageSmoothingEnabled= false, but that didn't change anything.
  • Setting the context.smoothImageQuality = high, check the photo below to see how that looks

Please let me know if you have any idea how I could fit it!

window.onload = () => {
  var dpi = window.devicePixelRatio;
  var canvas = document.getElementById("myCanvas");
  var context = canvas.getContext("2d");
  var imgLogo = document.getElementById("logo");
  context.imageSmoothingEnabled = false;
  context.drawImage(imgLogo, 0, 0, 175, 98.438);
}
.hidden {
  display: none;
}
<img class = "hidden" id = "logo" src = "https://assets.stickpng.com/images/580b57fcd9996e24bc43c529.png" width="200"/>


<canvas id = "myCanvas" height = "150" width = "500">
 </canvas>
 
 
<div class="blend1">
  <div id="logoContainer">
    <img src="https://assets.stickpng.com/images/580b57fcd9996e24bc43c529.png" width="175" />
  </div>
</div>


Solution

  • After quite some research, I finally came across a very simple solution. I wonder why it was so hard to find. It's as simple as this:

    context.imageSmoothingQuality = "high";
    

    So with the following, you should get two equally smooth logos:

    window.onload = () => {
      var canvas = document.getElementById("myCanvas");
      var context = canvas.getContext("2d");
      var imgLogo = document.getElementById("logo");
    
      // Only set this value
      var valueX = 256;
    
      var valueY = valueX / 16 * 9;
      imgLogo.width = valueX;
      canvas.width = valueX;
      canvas.height = valueY;
      context.imageSmoothingQuality = "high"; // or "low" or "medium"
      context.drawImage(imgLogo, 0, 0, valueX, valueY);
    }
    .hidden {
      display: none;
    }
    <img class = "hidden" id = "logo" src = "https://assets.stickpng.com/images/580b57fcd9996e24bc43c529.png" width="200"/>
    
    
    <canvas id = "myCanvas" height = "150" width = "500">
     </canvas>
     
     
    <div class="blend1">
      <div id="logoContainer">
        <img src="https://assets.stickpng.com/images/580b57fcd9996e24bc43c529.png" width="175" />
      </div>
    </div>

    Source.

    Some also recommend drawing in a hidden bigger canvas and then re-drawing each time halving the picture, but I think this solution is already good enough, and obviously much more simple.

    PS 1: apparently it only works on Chromium-based browsers. If you want to support other browsers, you might need to do what the link above details.

    PS 2: Check browser support for imageSmoothingQuality.