【问题标题】:HTML5 - scaled image is blurry when drawn on canvas in chrome & operaHTML5 - 在 chrome 和 opera 中的画布上绘制时,缩放的图像模糊
【发布时间】:2019-02-10 01:25:31
【问题描述】:

当我使用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"
<canvas width="944" height="596" id="crisp-canvas" ></canvas>
<canvas width="944" height="596" id="blurry-canvas" ></canvas>

【问题讨论】:

  • 奇怪,当我在 Chrome 中运行你的 sn-p 时,我真的看不出任何区别。您确定两者的区别是 scale=1 的初始绘制,而不是时间?如果您将 blurryContext 绘制移动到 setInterval 中(并且只是为了踢,将间隔增加到 1000 毫秒),差异会消失吗?
  • 顺便说一下,我使用的是最新的 chrome 版本-“版本 69.0.3497.81 (Official Build) (64-bit)”,我的屏幕分辨率是 1366x768。我使用 setTimeout 的唯一原因是让时间先绘制模糊画布,然后再绘制清晰画布,因为一旦我绘制了全尺寸图像,问题就解决了,之后我可以绘制缩放图像就好了在每个画布上。
  • 是的,如果我在 setTimeout 中以 (1s -1000ms) 间隔设置我的 blurryContext 绘制,它可以解决问题,但这是预期的,因为我们在第一次绘制完整之后在 blurryContext 中绘制图像缩放图像。所以问题是为什么我首先需要以全比例绘制图像,以便在我想缩放它时获得清晰的图像。在 firefox 中没有模糊,但在 Opera 中也会出现这种效果,因为 opera 和 chrome 都使用相同的渲染引擎。

标签: html google-chrome opera blurry


【解决方案1】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多