1

I have a canvas with a 400x300px coordinates system (set with width and height attributes of the <canvas> DOM element)

Sometimes it has to be resized to a bigger size with the CSS scaling system.

How to change the image upscaling/downscaling algorithm? (bicubic, spline, nearest neighbour, etc.)

I have tested image-rendering: optimizeQuality, image-rendering: crisp-edges, image-rendering: -webkit-optimize-contrast, image-rendering: optimize-contrast, interpolation-mode: nearest-neighbor without success.

Is there nowadays a direct CSS way, without JS low-level image modification (like in HTML5 Canvas Resize (Downscale) Image High Quality?)?

Example with default algorithm (is there a way to change this default algorithm?):

ctx = document.querySelector("canvas").getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(0, 0, 100, 100);
ctx.fillStyle = "#00FF00";
ctx.fillRect(100, 100, 100, 100);
ctx.fillStyle = "#0000FF";
ctx.fillRect(200, 200, 100, 100);
ctx.fillStyle = "#000000";
ctx.fillRect(300, 0, 100, 100);
ctx.font = "50px sans-serif";
ctx.fillText("Hello world", 50, 50);
.canvas-wrapper {
  width: 852px;
}

canvas {
  width: 100%;
  background-color: #ccc;
}
<div class="canvas-wrapper">
  <canvas width="400" height="300"></canvas>
</div>
Christoph Rackwitz
  • 11,317
  • 4
  • 27
  • 36
Basj
  • 41,386
  • 99
  • 383
  • 673

1 Answers1

1

image-rendering should be the way. It's quite unfortunate that most browsers still don't support more than pixelated & auto values, but that's what's supposed to be used here (with a mention to Firefox that does expose smooth, but which apparently is just the same as auto.

const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "#FF0000";
ctx.fillRect(0, 0, 100, 100);
ctx.fillStyle = "#00FF00";
ctx.fillRect(100, 100, 100, 100);
ctx.fillStyle = "#0000FF";
ctx.fillRect(200, 200, 100, 100);
ctx.fillStyle = "#000000";
ctx.fillRect(300, 0, 100, 100);
ctx.font = "50px sans-serif";
ctx.fillText("Hello world", 50, 50);

const select = document.querySelector("select");
select.onchange = () => {
    document.body.style.setProperty("--ir-value", select.value);
};
// display only the "supported" values
["smooth", "high-quality", "crisp-edges", "pixelated", "-webkit-optimize-contrast"].forEach((val) =>
{
    canvas.style.imageRendering = val;
  if (getComputedStyle(canvas).imageRendering !== "auto") {
    select.append(new Option(val));
  }
  canvas.style.imageRendering = "";
});
.canvas-wrapper {
  width: 852px;
}
canvas {
  width: 100%;
  background-color: #ccc;
  image-rendering: var(--ir-value);
}
<select>
  <option>auto</option>
</select>
<div class="canvas-wrapper">
  <canvas width="400" height="300"></canvas>
</div>

Note that since the linked question has been posted the canvas API also has been updated and now includes an imageSmoothingQuality setting, which is still not supported in Firefox:

const canvas1 = document.createElement("canvas");
canvas1.width = 400;
canvas1.height = 300;
{
  const ctx = canvas1.getContext("2d");
  ctx.fillStyle = "#FF0000";
  ctx.fillRect(0, 0, 100, 100);
  ctx.fillStyle = "#00FF00";
  ctx.fillRect(100, 100, 100, 100);
  ctx.fillStyle = "#0000FF";
  ctx.fillRect(200, 200, 100, 100);
  ctx.fillStyle = "#000000";
  ctx.fillRect(300, 0, 100, 100);
  ctx.font = "50px sans-serif";
  ctx.fillText("Hello world", 50, 50);
}

const select = document.querySelector("select");
const draw = () => {
  const canvas = document.querySelector("canvas");
  const width = canvas.offsetWidth;
  const height = canvas.offsetHeight;
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext("2d");
  ctx.imageSmoothingQuality = select.value;
  ctx.drawImage(canvas1, 0, 0, canvas.width, canvas.height);
}
select.onchange = draw;
draw();

if(!("imageSmoothingQuality" in CanvasRenderingContext2D.prototype)) {
  console.error("your browser doesn't support imageSmoothingQuality");
}
.canvas-wrapper {
  width: 852px;
}
canvas {
  width: 100%;
  background-color: #ccc;
}
<select>
  <option>low</option>
  <option>medium</option>
  <option>high</option>
</select>
<div class="canvas-wrapper">
  <canvas width="400" height="300"></canvas>
</div>
Kaiido
  • 123,334
  • 13
  • 219
  • 285