与 img 标签相比,drawImage 生成的质量较差

Ruo*_*eng 1 html canvas image

当我使用 drawImage 将图像放在画布上时,它看起来总是不如使用标签的相同图像那么清晰。我已经搜索了许多解决方案,例如下采样、smoothingEnabled,但都没有帮助。如何提高drawImage的质量?

<html>
<head>
</head>
<body>
    <img src="test.png" width="550" height="405">
    <canvas id="image"></canvas>
</body>
<script type="text/javascript">
    var canvas = document.getElementById('image');
    var ctx = canvas.getContext('2d');
    ctx.mozImageSmoothingEnabled = false;
    ctx.webkitImageSmoothingEnabled = false;
    ctx.msImageSmoothingEnabled = false;
    ctx.imageSmoothingEnabled = false;
    canvas.width = 550;
    canvas.height = 405;
    canvas.style.width  = canvas.width.toString() + "px";
    canvas.style.height = canvas.height.toString() + "px";

    var img = new Image();
    img.onload = function() {
        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
    };
    img.src = 'test.png';
</script>
Run Code Online (Sandbox Code Playgroud)

您可以清楚地看出它们的质量差异

Kai*_*ido 7

你似乎在一个类似视网膜的显示器上。这可以通过查看屏幕截图的大小 (2264?×?886) 来确认。

这些显示器确实具有更高的像素密度。为了使网页的大小与作者的意图保持一致,他们会自动放大页面的所有内容。

这意味着您的<img>标签实际上是以 1100x810 像素绘制的,您的画布也是如此。
但是,这种自动化仅在表示级别 (CSS) 上完成。您的画布上下文仍然只包含 550x405 像素。因此,当在表示级别通过时,它必须通过 CSS 对其进行升级,这会导致质量下降。

没有防弹方法可以知道屏幕的 PPI(每英寸像素数)比率,但由于该window.devicePixelRatio属性,您仍然可以尝试获得它。如果您的用户经常使用浏览器的缩放级别,这可能不准确,但在 90% 的情况下,它可以正常工作。

一旦你有了这个,你可以手动为画布做浏览器为<img>它做的事情:放大它的内容并缩小它的展示。

var canvas = document.getElementById('image');
var ctx = canvas.getContext('2d');
// upscale the canvas content
canvas.width = 550 * devicePixelRatio;
canvas.height = 405 * devicePixelRatio;
// downscale the presentation
canvas.style.width = (canvas.width / devicePixelRatio).toString() + "px";
canvas.style.height = (canvas.height / devicePixelRatio).toString() + "px";

var img = new Image();
img.onload = function() {
  ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
};
img.src = 'https://i.stack.imgur.com/s15bD.png';
Run Code Online (Sandbox Code Playgroud)
<img width="550" height="405" src="https://i.stack.imgur.com/s15bD.png" />
<canvas id="image"></canvas>
Run Code Online (Sandbox Code Playgroud)