如何使用画布进行阈值效果



我发现这本指南展示了使用画布和JavaScript的图像过滤器/效果:https://www.html5rocks.com/en/tutorials/canvas/imagefilters

不过,我不知道如何实现它。我不擅长JavaScript(我是一名平面设计师(,所以我甚至不理解语法。我从页面中提取了这段代码,但我不知道它是否完整,也不知道如何使用:

Filters = {};
Filters.threshold = function(pixels, threshold) {
var d = pixels.data;
for (var i=0; i<d.length; i+=4) {
var r = d[i];
var g = d[i+1];
var b = d[i+2];
var v = (0.2126*r + 0.7152*g + 0.0722*b >= threshold) ? 255 : 0;
d[i] = d[i+1] = d[i+2] = v
}
return pixels;
};
threshold = function() {
runFilter('threshold', Filters.threshold, 128);
}

我想在div(具有CSSbackground-image属性(、imgcanvas元素上复制这种效果,只要它有效,就没关系。

过滤器适用于图像数据ImageData。图像数据无法显示,因此需要转换为某种可显示的形式,例如画布。

此外,您还需要从图像中获取图像数据。标准图像无法访问像素,因此您需要将图像转换为画布才能获得像素。

注意不安全的图像(跨域、本地文件存储(可能无法访问像素。如果您在请求中提供了正确的CORS头,并且服务器接受了请求,则某些跨域映像将允许访问(如下例所示(。

示例

我在Filter对象中添加了一些辅助函数,这些函数将从各种类似图像的源中复制、创建和获取像素。

示例中的Filter对术语图像进行了抽象。就示例而言,图像是类似图像的对象,并且可以是CSSImageValueHTMLImageElementSVGImageElementHTMLVideoElementHTMLCanvasElementImageBitmapOffscreenCanvasImageData中的任何一个。

const image = new Image;
image.src = "https://upload.wikimedia.org/wikipedia/commons/1/15/Late_model_Ford_Model_T.jpg";
image.crossOrigin = "Anonymous"; // CORS 
image.addEventListener("load", () => applyFilter(image), {once: true});
const Filters = {
createImage(w, h) {
const can = document.createElement("canvas");
can.width = w;
can.height= h;  
return can;
},
copyImage(img) {
const image = this.createImage(img.width, img.height);
const ctx = image.getContext("2d");
if (img instanceof ImageData) { ctx.putImageData(img, 0, 0) }
else { ctx.drawImage(img, 0, 0, img.width, img.height) }
return image;
},
getPixels(img) {
if (!(img instanceof HTMLCanvasElement)) { img = this.copyImage(img) }
const ctx = img.getContext("2d");
return ctx.getImageData(0, 0, img.width, img.height);
},
threshold(pixels, threshold, light = [255,255,255], dark = [0,0,0]) { // light, dark arrays of RGB
var d = pixels.data, i = 0, l = d.length;
while (l-- > 0) {
const v = d[i] * 0.2126 + d[i+1] * 0.7152 + d[i+2] * 0.0722;
[d[i], d[i+1], d[i+2]] = v >= threshold ? light : dark;
i += 4;
}
return pixels;
}
};
function applyFilter(image) {
const pixels = Filters.getPixels(image);
Filters.threshold(pixels, 100);
const thresholdImage = Filters.copyImage(pixels);
att.classList.remove("hide"); // Image can be seen so show attribution
document.body.appendChild(image); // add original to page
document.body.appendChild(thresholdImage); // add filtered to page 
}
/* Image source 
By Rmhermen - Transferred from en.wikipedia to Commons., CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=468996 
*/
.hide {display: none}
div { font-size: x-small }
canvas { width: 46% }
img { width: 46% }
<div id="att" class="hide">By Rmhermen - Transferred from en.wikipedia to Commons., CC BY-SA 3.0, <a href="https://commons.wikimedia.org/w/index.php?curid=468996">image source</a></div>

如果您想在HTML<div>上应用此筛选器,那么画布解决方案不是最好的。

相反,对于简单的情况,可以查看CSS过滤器,对于更复杂的情况,则可以查看SVG过滤器。

你想要的是一个简单的,并且只能通过CSS过滤器实现:

#target {
background-image: url(https://i.stack.imgur.com/5Md7Z.jpg);
width: 600px;
height: 600px;
filter: brightness(115%) grayscale(100%) contrast(5000%);
}
<div id="target"></div>

最新更新