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>
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>