title: HTML5 Canvas Resize (Downscale) Image High Quality?
body: <p>I use html5 canvas elements to resize images im my browser. It turns out that the quality is very low. I found this: <a href="https://stackoverflow.com/questions/7615009/disable-interpolation-when-scaling-a-canvas">Disable Interpolation when Scaling a &lt;canvas&gt;</a> but it does not help to increase the quality.</p>
  
  <p>Below is my css and js code as well as the image scalled with Photoshop and scaled in the canvas API. </p>
  
  <p><strong>What do I have to do to get optimal quality when scaling an image in the browser?</strong></p>
  
  <p>Note: I want to scale down a large image to a small one, modify color in a canvas and send the result from the canvas to the server.</p>
  
  <p>CSS: </p>
  
  <pre><code>canvas, img {
      image-rendering: optimizeQuality;
      image-rendering: -moz-crisp-edges;
      image-rendering: -webkit-optimize-contrast;
      image-rendering: optimize-contrast;
      -ms-interpolation-mode: nearest-neighbor;
  }
  </code></pre>
  
  <p>JS: </p>
  
  <pre><code>var $img = $('&lt;img&gt;');
  var $originalCanvas = $('&lt;canvas&gt;');
  $img.load(function() {
  
  
     var originalContext = $originalCanvas[0].getContext('2d');   
     originalContext.imageSmoothingEnabled = false;
     originalContext.webkitImageSmoothingEnabled = false;
     originalContext.mozImageSmoothingEnabled = false;
     originalContext.drawImage(this, 0, 0, 379, 500);
  });
  </code></pre>
  
  <p>The image resized with photoshop:</p>
  
  <p><img src="https://i.stack.imgur.com/Vt7KT.jpg" alt="enter image description here"></p>
  
  <p>The image resized on canvas:</p>
  
  <p><img src="https://i.stack.imgur.com/HJhLY.jpg" alt="enter image description here"></p>
  
  <p>Edit: </p>
  
  <p>I tried to make downscaling in more than one steps as proposed in:</p>
  
  <p><a href="https://stackoverflow.com/questions/2303690/resizing-an-image-in-an-html5-canvas">Resizing an image in an HTML5 canvas</a> and
  <a href="https://stackoverflow.com/questions/17861447/html5-canvas-drawimage-how-to-apply-antialiasing">Html5 canvas drawImage: how to apply antialiasing</a></p>
  
  <p>This is the function I have used: </p>
  
  <pre><code>function resizeCanvasImage(img, canvas, maxWidth, maxHeight) {
      var imgWidth = img.width, 
          imgHeight = img.height;
  
      var ratio = 1, ratio1 = 1, ratio2 = 1;
      ratio1 = maxWidth / imgWidth;
      ratio2 = maxHeight / imgHeight;
  
      // Use the smallest ratio that the image best fit into the maxWidth x maxHeight box.
      if (ratio1 &lt; ratio2) {
          ratio = ratio1;
      }
      else {
          ratio = ratio2;
      }
  
      var canvasContext = canvas.getContext("2d");
      var canvasCopy = document.createElement("canvas");
      var copyContext = canvasCopy.getContext("2d");
      var canvasCopy2 = document.createElement("canvas");
      var copyContext2 = canvasCopy2.getContext("2d");
      canvasCopy.width = imgWidth;
      canvasCopy.height = imgHeight;  
      copyContext.drawImage(img, 0, 0);
  
      // init
      canvasCopy2.width = imgWidth;
      canvasCopy2.height = imgHeight;        
      copyContext2.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvasCopy2.width, canvasCopy2.height);
  
  
      var rounds = 2;
      var roundRatio = ratio * rounds;
      for (var i = 1; i &lt;= rounds; i++) {
          console.log("Step: "+i);
  
          // tmp
          canvasCopy.width = imgWidth * roundRatio / i;
          canvasCopy.height = imgHeight * roundRatio / i;
  
          copyContext.drawImage(canvasCopy2, 0, 0, canvasCopy2.width, canvasCopy2.height, 0, 0, canvasCopy.width, canvasCopy.height);
  
          // copy back
          canvasCopy2.width = imgWidth * roundRatio / i;
          canvasCopy2.height = imgHeight * roundRatio / i;
          copyContext2.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvasCopy2.width, canvasCopy2.height);
  
      } // end for
  
  
      // copy back to canvas
      canvas.width = imgWidth * roundRatio / rounds;
      canvas.height = imgHeight * roundRatio / rounds;
      canvasContext.drawImage(canvasCopy2, 0, 0, canvasCopy2.width, canvasCopy2.height, 0, 0, canvas.width, canvas.height);
  
  
  }
  </code></pre>
  
  <p>Here is the result if I use a 2 step down sizing: </p>
  
  <p><img src="https://i.stack.imgur.com/eH3Oe.png" alt="enter image description here"></p>
  
  <p>Here is the result if I use a 3 step down sizing: </p>
  
  <p><img src="https://i.stack.imgur.com/Y1qXz.png" alt="enter image description here"></p>
  
  <p>Here is the result if I use a 4 step down sizing: </p>
  
  <p><img src="https://i.stack.imgur.com/OW5bw.png" alt="enter image description here"></p>
  
  <p>Here is the result if I use a 20 step down sizing: </p>
  
  <p><img src="https://i.stack.imgur.com/XTN9v.png" alt="enter image description here"></p>
  
  <p>Note: It turns out that from 1 step to 2 steps there is a large improvement in image quality but the more steps you add to the process the more fuzzy the image becomes.</p>
  
  <p><strong>Is there a way to solve the problem that the image gets more fuzzy the more steps you add?</strong>  </p>
  
  <p>Edit 2013-10-04: I tried the algorithm of GameAlchemist. Here is the result compared to Photoshop.</p>
  
  <p>PhotoShop Image: </p>
  
  <p><img src="https://i.stack.imgur.com/VaO8s.jpg" alt="PhotoShop Image">  </p>
  
  <p>GameAlchemist's Algorithm:</p>
  
  <p><img src="https://i.stack.imgur.com/YOsTL.jpg" alt="GameAlchemist&#39;s Algorithm"></p>