如何使用 HTML Canvas 创建像素完美的剪切区域?

对于我的应用程序,我试图将所有内容移动到任意垂直接缝线的右侧,向左移动一个像素。目前我正在使用 O(n^2) for 循环并手动编辑像素数据,但不幸的是这太慢了。


我有以下想法:将原始图像绘制到画布上,创建接缝Path2D,在接缝右侧创建所有内容的剪切区域,然后将该区域向左绘制一个像素。


不幸的是,这种剪切似乎不是像素完美的,而是在图像中引入了抗锯齿功能。


这是演示该问题的代码示例:


function getRandomInt(min, max) {

  min = Math.ceil(min);

  max = Math.floor(max);

  return Math.floor(Math.random() * (max - min) + min);

}


const canvas = document.getElementById('canvas');

const ctx = canvas.getContext('2d');


ctx.imageSmoothingEnabled = false;

ctx.beginPath();

ctx.strokeStyle = "#00000000";


ctx.moveTo(50, 0);

for (let i = 1; i < 200; i++) {

  ctx.lineTo(50 + getRandomInt(-1, 2), i);

}

ctx.lineTo(500, 200);

ctx.lineTo(500, 0);

ctx.lineTo(50, 0);

ctx.stroke();

ctx.clip();


ctx.fillStyle = 'blue';

ctx.fillRect(0, 0, canvas.width, canvas.height);

ctx.fillStyle = 'orange';

ctx.fillRect(0, 0, 100, 100);

<canvas id="canvas" width="300" height="300">

正如您所看到的,接缝在切口中引入了抗锯齿功能。有没有办法创建像素完美且不抗锯齿的剪切区域?

我还尝试添加image-rendering: pixelated;到样式表中,虽然它似乎有一点帮助,但仍然在进行抗锯齿处理。


互换的青春
浏览 94回答 1
1回答

九州编程

问题是您在每个针迹之间绘制斜线。让事情变得更加戏剧化,这就是你正在做的事情。function getRandomInt(min, max) {  min = Math.ceil(min);  max = Math.floor(max);  return Math.floor(Math.random() * (max - min) + min);}const canvas = document.getElementById('canvas');const ctx = canvas.getContext('2d');ctx.imageSmoothingEnabled = false;ctx.beginPath();ctx.strokeStyle = "#00000000";ctx.moveTo(50, 0);for (let i = 1; i < 200; i+= 10) {  ctx.lineTo(50 + getRandomInt(-5, 10), i);}ctx.lineTo(500, 200);ctx.lineTo(500, 0);ctx.lineTo(50, 0);ctx.stroke();ctx.clip();ctx.fillStyle = 'blue';ctx.fillRect(0, 0, canvas.width, canvas.height);ctx.fillStyle = 'orange';ctx.fillRect(0, 0, 100, 100);<canvas id="canvas" width="300" height="300">当渲染这些斜线时,浏览器将使用抗锯齿来平滑线条,因为这通常是人们想要的。但在您的情况下,您想要像素完美,因此解决方案是以阶梯形状围绕像素边界行走。这可以通过从最后一个 y 坐标到下一个 y 坐标绘制一条垂直线,然后绘制水平线来实现。function getRandomInt(min, max) {  min = Math.ceil(min);  max = Math.floor(max);  return Math.floor(Math.random() * (max - min) + min);}const canvas = document.getElementById('canvas');const ctx = canvas.getContext('2d');// for high-res monitors{  const dPR = window.devicePixelRatio;  canvas.width = canvas.height *= dPR  ctx.scale( dPR, dPR );}ctx.beginPath();ctx.strokeStyle = "#00000000";ctx.moveTo(50, 0);for (let i = 1; i < 200; i++) {  let rand = getRandomInt( -1, 2 );  ctx.lineTo( 50 + rand, i - 1 ); // from last y move horizontally  ctx.lineTo( 50 + rand, i ); // move vertically}ctx.lineTo(500, 200);ctx.lineTo(500, 0);ctx.lineTo(50, 0);ctx.clip();ctx.fillStyle = 'blue';ctx.fillRect(0, 0, canvas.width, canvas.height);ctx.fillStyle = 'orange';ctx.fillRect(0, 0, 100, 100);canvas { width: 300px; height: 300px }<canvas id="canvas" width="300" height="300">再次以更戏剧化的方式:function getRandomInt(min, max) {  min = Math.ceil(min);  max = Math.floor(max);  return Math.floor(Math.random() * (max - min) + min);}const canvas = document.getElementById('canvas');const ctx = canvas.getContext('2d');ctx.imageSmoothingEnabled = false;ctx.beginPath();ctx.strokeStyle = "#00000000";ctx.moveTo(50, 0);for (let i = 1; i < 200; i+= 10) {  const rand = getRandomInt(-5, 10);  ctx.lineTo(50 + rand, i-10);  ctx.lineTo(50 + rand, i);}ctx.lineTo(500, 200);ctx.lineTo(500, 0);ctx.lineTo(50, 0);ctx.stroke();ctx.clip();ctx.fillStyle = 'blue';ctx.fillRect(0, 0, canvas.width, canvas.height);ctx.fillStyle = 'orange';ctx.fillRect(0, 0, 100, 100);<canvas id="canvas" width="300" height="300">
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript