javascript - HTML5 画布 | 替换颜色 | 去除颜色
问题描述
创建没有绿色或使绿色透明或从左上角 100X100 px 删除绿色的图像的最快方法是什么
在这种情况下,我必须检查每个像素值吗?这个过程太慢了,例如:对于 100X100px,检查所有 rgba 值需要 40000 次循环
解决方案
在支持它的浏览器中,您可以使用 svg 过滤器来做到这一点:
这是另一个 Q/A,它展示了一种有趣的方法来为固定颜色执行此操作。
在这里,我创建了一个简单的辅助函数,它将为我们设置所需tableValues
的公差,并删除了<feFill>
使所选颜色变为透明的(<feFill>
会污染 Chrome 中的画布)。如果您想替换颜色,您仍然可以使用画布的合成选项来实现它(下面的代码片段中的注释代码)。
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = e => {
canvas.width = img.width;
canvas.height = img.height;
// update our filter
updateChroma([76, 237, 0], 8);
// if you wish to replace the color, uncomment followings
// ctx.fillStyle = "your_replaceColor";
// ctx.fillRect(0,0,img.width,img.height);
ctx.filter = 'url(#chroma)';
ctx.drawImage(img, 0, 0);
ctx.filter = 'none';
// ctx.globalCompositeOperation = 'destination-in';
// ctx.drawImage(img, 0,0);
};
img.src = "https://i.stack.imgur.com/hZm8o.png";
function updateChroma(rgb, tolerance) {
const sels = ['R', 'G', 'B'];
rgb.forEach((value, ind) => {
const fe = document.querySelector('#chroma feFunc' + sels[ind]);
let vals = '';
if (!value) {
vals = '0'
} else {
for (let i = 0; i < 256; i++) {
vals += (Math.abs(value - i) <= tolerance) ? '1 ' : '0 ';
}
}
fe.setAttribute('tableValues', vals);
});
}
canvas {
background: ivory
}
<svg width="0" height="0" style="position:absolute;visibility:hidden">
<filter id="chroma" color-interpolation-filters="sRGB"x="0" y="0" height="100%" width="100%">
<feComponentTransfer>
<feFuncR type="discrete"/>
<feFuncG type="discrete"/>
<feFuncB type="discrete"/>
</feComponentTransfer>
<feColorMatrix type="matrix" values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
1 1 1 1 -1" result="selected"/>
<feComposite in="SourceGraphic" in2="selected" operator="out"/>
</filter>
</svg>
<canvas id="canvas"></canvas>
我没有在许多设备上进行广泛的测试,但是在启用硬件加速的情况下,这可能比任何像素循环执行得更好,因为它应该全部在 GPU 上完成。
但是浏览器支持仍然不是那么好......
所以无论如何你可能需要回退到像素操作。
在这里,根据您正在处理的色度,您可能需要牺牲一些质量来换取速度。
例如,在视频上,您可以在缩小的画布上执行色度,然后在主画布上合成,然后在每帧中赢得几次迭代。有关示例,请参见之前的 Q/A 。
推荐阅读
- c# - 如何使用 C# 在 Unity 中引用对象?
- c# - 仅在启动时调用的 C# 静态方法
- php - 如何在 Wordpress 中使用 LOAD DATA LOCAL INFILE fro csv import 作为自定义插件
- typescript - CyberSource 卡号加密 (RSA-OAEP-256)
- python - 如何在 android studio 上运行 python 脚本
- c# - 在私有委托方法中测试异常
- google-sheets - 不显示吉祥物名称的 NCAAB 球队的清理列表(更多详细信息在描述中)
- r - 如何根据土地覆盖计算R中的散点图?
- android - 使用 gradle.startParameter 获取当前风味不起作用
- javascript - EJS函数参数未定义