【问题标题】:How can I do a threshold effect with canvas?如何用画布做阈值效果?
【发布时间】:2021-01-01 17:22:53
【问题描述】:

我发现本指南展示了使用画布和 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);
}

I want to replicate this effectdiv(带有 CSS background-image 属性)、imgcanvas 元素上,只要它有效就没有关系。

【问题讨论】:

    标签: javascript canvas filter effect threshold


    【解决方案1】:

    过滤器适用于图像数据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% }
    &lt;div id="att" class="hide"&gt;By Rmhermen - Transferred from en.wikipedia to Commons., CC BY-SA 3.0, &lt;a href="https://commons.wikimedia.org/w/index.php?curid=468996"&gt;image source&lt;/a&gt;&lt;/div&gt;

    【讨论】:

    • 出色的阈值转换,非常有帮助,谢谢!
    【解决方案2】:

    如果您想在 HTML &lt;div&gt; 上应用此过滤器,那么画布解决方案并不是最好的。

    请查看CSS filters 了解简单的情况,或查看SVG filters 了解更复杂的情况。

    你想要的很简单,只能用 CSS 过滤器来实现:

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

    【讨论】:

    • 这是一个非常聪明的解决方案。它只是简化了整个过程,而无需使用 JavaScript。我刚刚实现了它,它就像一个魅力,即使在父元素上使用其他嵌套过滤器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-19
    • 2012-05-04
    • 1970-01-01
    • 2012-02-15
    • 1970-01-01
    • 2017-04-12
    相关资源
    最近更新 更多