【发布时间】:2019-03-11 23:41:58
【问题描述】:
在尝试处理特定的画布绘图案例时,我发现了一些奇怪的行为。我有一些要绘制的区域(“遮罩区域”),定义为任意多边形。我有一些图像/形状/等,然后我想绘制,剪裁为仅绘制到蒙版区域。
我想我可以通过以下方式实现:
- 用
(0, 0, 0, 0)填充画布(使用方便的clearRect方法) - 用
(1, 1, 1, 1)填充遮罩区域 - 将
context的globalCompositeOperation设置为"multiply" - 绘制内容
(对于那些熟悉的人,我正在尝试完成类似于 GIMP 的“图层蒙版”工具(填充全白)的效果。)
我知道我可以使用画布剪辑来处理这种特定情况,但是如果没有它,我希望使用它的任务会变得更加简单,而且我认为使用乘法来完成它应该是可能的。我想要实现的相反效果(绘制内容然后消隐像素)很容易用类似的想法来实现,无论如何使用globalCompositeOperation = "destination-out"。
代码如下:
<html>
<head><style>
html { width: 100%; height: 100%; }
body { margin: 0; width: 100%;
height: 100%; background: #777; }
canvas { border: 1px solid black;
margin: 10px auto; display: block; }
</style></head>
<body><canvas id="can" width="1800" height="900"></canvas></body>
<script>
const img = new Image;
img.onload = () => requestAnimationFrame(drawFrame);
img.src = "square.png";
const canvas = document.getElementById("can");
const ctx = canvas.getContext("2d");
let then = 0;
function drawFrame (now) {
const deltaTime = now - then;
then = now;
// fill canvas with 0 in all channels
ctx.clearRect(0, 0, canvas.width, canvas.height);
// draw FPS
ctx.fillStyle = "black";
ctx.font = "16px serif";
ctx.fillText(`FPS: ${Math.round(1 / (deltaTime / 1000))}`, 0, 16);
// fill mask area with 1 in all channels
ctx.fillStyle = "#01010101";
ctx.fillRect(100, 100, 400, 400);
// further draws should multiply current canvas values
ctx.globalCompositeOperation = "multiply";
// draw image (100*100 resolution image; half the image should be visible)
// Each channel of each pixel **should** multiply together
// "0"'d regions: 0 in all channels
// "1"'d regions: 1 * imgChannelValue = imgChannelValue
ctx.drawImage(img, 50, 100);
// draw a box, which should have its top-left corner blanked
ctx.strokeStyle = "#ff0000";
ctx.strokeRect(300, 300, 500, 300);
// (reset compositing)
ctx.globalCompositeOperation = "source-over";
requestAnimationFrame(drawFrame);
}
</script>
</html>
这是我的高质量square.png 测试图像:
【问题讨论】: