HTML5 - 在 Chrome 和 Opera 中在画布上绘制时缩放图像模糊

sla*_*boy 3 html opera google-chrome blurry

当我使用drawImage()函数在画布上绘制缩放图像时,它在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"
Run Code Online (Sandbox Code Playgroud)
<canvas width="944" height="596" id="crisp-canvas" ></canvas>
<canvas width="944" height="596" id="blurry-canvas" ></canvas>
Run Code Online (Sandbox Code Playgroud)

sla*_*boy 6

经过一天尝试我能想到的一切之后,当我在画布上绘制缩放图像时,我无法找到解决方案。

以下是我尝试过的一些事情:
1)我尝试使用scale()方法,但结果是相同的。
2)我尝试设置imageSmoothingEnabled属性,该属性适用于像素化艺术游戏,但对于高分辨率图像,质量很糟糕。
3)我尝试使用window.requestAnimationFrame()方法,而不是在第一个请求上在隐藏画布上绘制全尺寸图像,然后在主画布上绘制缩放图像。这很好用,但是当我更改选项卡(关注另一个选项卡)时,几分钟后我的主画布上的图像再次变得模糊。然后,我添加了一种方法来检查用户何时将注意力集中在我的选项卡上,使用Page Visibility API,并再次在隐藏画布上重新绘制全尺寸图像,但这不起作用。只有隐藏画布上最后绘制的图像是清晰的,而在最后绘制的图像之前绘制的所有图像都是模糊的。所以唯一的解决方案是为每个图像创建隐藏的画布,但这是不切实际的,所以我不得不尝试另一种方法。

所以这里是提出的解决方案:
1)将宽度和高度画布属性设置为我的原始图像尺寸 1980x1251 2)我使用其样式宽度和高度属性
缩放画布

请记住,使用此方法,画布上绘制的所有内容(例如形状、文本、线条...)也将被缩放。例如,如果您绘制一个矩形 (10x10) 像素。仅当画布宽度和高度样式属性与画布宽度和高度属性匹配时,它的宽度和高度都等于 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";
Run Code Online (Sandbox Code Playgroud)
<canvas id="crisp-canvas" ></canvas>
Run Code Online (Sandbox Code Playgroud)