Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <h2>Cause</h2> <p>Some images are just very hard to down-sample and <em>interpolate</em> such as this one with curves when you want to go from a large size to a small.</p> <p>Browsers appear to typically use bi-linear (2x2 sampling) interpolation with the canvas element rather than bi-cubic (4x4 sampling) for (likely) performance reasons.</p> <p>If the step is too huge then there are simply not enough pixels to sample from which is reflected in the result.</p> <p>From a signal/DSP perspective you could see this as a low-pass filter's threshold value set too high, which may result in aliasing if there are many high frequencies (details) in the signal.</p> <h2>Solution</h2> <p><strong>Update 2017:</strong> There is now a <a href="https://devdocs.io/dom/canvasrenderingcontext2d/imagesmoothingquality" rel="noreferrer">new property</a> defined in the specs for setting resampling quality:</p> <pre><code>context.imageSmoothingQuality = "low|medium|high" </code></pre> <p>It's currently only supported in Chrome. The actual methods used per level is left to the vendor to decide, but it's reasonable to assume Lanczos for "high" or something equivalent in quality. This means step-down may be skipped altogether, or larger steps can be used with fewer redraws, depending on the image size and browser. Until then..:<br> <strong><em>End of transmission</em></strong></p> <p>The solution is to use <em>step-down</em> to get a proper result. Step-down means you reduce the size in steps to allow the limited interpolation range to cover enough pixels for sampling.</p> <p>This will allow good results also with bi-linear interpolation (it actually behaves much like bi-cubic when doing this) and the overhead is minimal as there are less pixels to sample in each step.</p> <p>The ideal step is to go to <em>half the resolution</em> in each step until you would set the target size (thanks to Joe Mabel for mentioning this!).</p> <p><strong><a href="http://jsfiddle.net/AbdiasSoftware/MLGr4/49/" rel="noreferrer">Modified fiddle</a></strong></p> <p><strong>Using direct scaling as in original question:</strong></p> <p><img src="https://i.stack.imgur.com/WuSiu.png" alt="NORMAL DOWN-SCALED IMAGE"></p> <p><strong>Using step-down as shown below:</strong></p> <p><img src="https://i.stack.imgur.com/0zt7z.png" alt="DOWN-STEPPED IMAGE"></p> <p>In this case you will need to step down in 3 steps:</p> <p>In step 1 we reduce the image to half by using an off-screen canvas:</p> <pre class="lang-js prettyprint-override"><code>/// step 1 - create off-screen canvas var oc = document.createElement('canvas'), octx = oc.getContext('2d'); oc.width = img.width * 0.5; oc.height = img.height * 0.5; octx.drawImage(img, 0, 0, oc.width, oc.height); </code></pre> <p>Step 2 reuses the off-screen canvas and draws the image reduced to half again:</p> <pre class="lang-js prettyprint-override"><code>/// step 2 octx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5); </code></pre> <p>And we draw once more to main canvas, again reduced <strike>to half</strike> but to the final size:</p> <pre class="lang-js prettyprint-override"><code>/// step 3 ctx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5, 0, 0, canvas.width, canvas.height); </code></pre> <h2>Tip:</h2> <p>You can calculate total number of steps needed, using this formula (it includes the final step to set target size):</p> <pre class="lang-js prettyprint-override"><code>steps = Math.ceil(Math.log(sourceWidth / targetWidth) / Math.log(2)) </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload