为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

互换的青春 2023-10-20 15:33:33
对于我的应用程序,我试图将所有内容移动到任意垂直接缝线的右侧,向左移动一个像素。目前我正在使用 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;到样式表中,虽然它似乎有一点帮助,但仍然在进行抗锯齿处理。
查看完整描述

1 回答

?
九州编程

TA贡献1785条经验 获得超4个赞

问题是您在每个针迹之间绘制斜线。

让事情变得更加戏剧化,这就是你正在做的事情。

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">


查看完整回答
反对 回复 2023-10-20
  • 1 回答
  • 0 关注
  • 60 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信