HTML5 - 在 chrome 和 opera 中的 canvas 上绘制时缩放图像模糊

HTML5 - scaled image is blurry when drawn on canvas in chrome & opera

当我使用 drawImage() 函数在 canvas 上绘制缩放图像时,它在 Chrome & Opera 中看起来有点模糊,但是如果我先绘制全尺寸图像,然后再绘制缩放图像一个看起来很脆。模糊的原因是什么?我该如何解决?

原图如下:

这是 Chrome & Opera 中的结果:

const img = new Image();

const crisptCanvas = document.getElementById('crisp-canvas');
const crispContext = crisptCanvas.getContext('2d');

const blurryCanvas = document.getElementById('blurry-canvas');
const blurryContext = blurryCanvas.getContext('2d');

const sx = 0, sy = 0, sWidth = 1980, sHeight = 1251;
const dx = 0, dy = 0;
const scaleFactor = 0.4762626262626263;

// Draw an image on canvas
function scaleImage(scale, context)
{
 const dWidth = (sWidth*scale);
 const dHeight = (sHeight*scale);
 context.drawImage(img, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
};
        
// When image is loaded draw it on both canvases
img.onload = function(){

 // First draw the source image in full scale and then using the -scaleFactor
 setTimeout(()=> {
  scaleImage(1, crispContext);
  scaleImage(scaleFactor, crispContext);
 }, 0);

 // Draw the image using the -scaleFactor
 scaleImage(scaleFactor, blurryContext); 
}

img.src = "https://i.stack.imgur.com/eWDSw.png"
<canvas width="944" height="596" id="crisp-canvas" ></canvas>
<canvas width="944" height="596" id="blurry-canvas" ></canvas>

好吧,在尝试了一天我能想到的一切之后,当我在 canvas 上绘制缩放图像时,我无法找到解决方案。

以下是我尝试过的一些方法:
1) 我试过使用scale()方法,但结果是一样的。
2) 我试过设置 imageSmoothingEnabled 属性,这在像素化艺术游戏中效果很好,但对于高分辨率图像,质量很糟糕。
3) 我曾尝试使用 window.requestAnimationFrame() method than on the first request draw the full scale image, on hidden canvas and after that draw the scaled image on my main canvas. That work well, but when i change the tab(focus on another tab), after a few minutes the images on my main canvas became blurry again. Then i added a method to check when the user focus on my tab, using the Page Visibility API,并再次在隐藏的 canvas 上重新绘制全尺寸图像,但那没有用。只有隐藏的 canvas 上最后绘制的图像清晰,最后一个之前绘制的所有图像都模糊。所以唯一的解决方案是为每个图像创建隐藏的 canvases,但这不切实际,所以我不得不尝试另一种方法。

所以这是提出的解决方案:
1) 将 width and height canvas properties 设置为我的原始图像大小 1980x1251
2) 我缩放 canvas,使用它的 style width & height properties

请记住,使用此方法绘制在 canvas 上的所有内容(例如形状、文本、线条...)也将被缩放。因此,例如,如果您绘制一个矩形 (10x10) 像素。仅当 canvas 宽度和高度样式属性与 canvas 宽度和高度属性匹配时,它的宽度和高度均等于 10px。
canvas.style.width = canvas.width + 'px';
canvas.style.height = canvas.height + 'px';

const img = new Image();

const crispCanvas = document.getElementById('crisp-canvas');
const crispContext = crispCanvas.getContext('2d');

const sx = 0, sy = 0, sWidth = 1980, sHeight = 1251;
const dx = 0, dy = 0;
const scaleFactor = 0.4762626262626263;

// Set crisp canvas width & height properties to match the source image
crispCanvas.width = sWidth;
crispCanvas.height = sHeight;

// Scale the source canvas using width & height style properties 
function scaleCanvas(scale, canvas) {

 const dWidth =  (sWidth*scale);
 const dHeight =  (sHeight*scale);

 canvas.style.width = dWidth + 'px';
 canvas.style.height = dHeight + 'px';
}

// When image is loaded, scale the crisp canvas and draw the full size image
img.onload = function(){ 
 scaleCanvas(scaleFactor, crispCanvas);
 crispContext.drawImage(img, sx, sy);
}

img.src = "https://i.stack.imgur.com/eWDSw.png";
<canvas id="crisp-canvas" ></canvas>