【问题标题】:Canvas splitting image into rgba components画布将图像拆分为 rgba 组件
【发布时间】:2020-07-11 05:46:07
【问题描述】:

我正在尝试将黑白图像拆分为其 RGB 组件并偏移每个图层以将其设置为叠加。我们的想法是让英雄图像稍微不合时宜并随机移动它。

我想知道这实际上是否是解决此问题的正确方法。

如果我敢在函数中添加控制台日志以查看哪里出错,我倾向于使浏览器崩溃。

有没有人在浏览器中做过这种操作,可行吗?

https://github.com/Julieslv/image-shift/blob/master/index.js

【问题讨论】:

    标签: javascript image-processing canvas html5-canvas


    【解决方案1】:

    ##将图像分割成RGBA通道

    首先请注意,您不能将通道与图像分开。您只能将不需要的频道设置为零。但是,将 Alpha 通道设置为零将自动将所有通道归零。因此,您必须保留 Alpha 通道。

    ###复制图片

    要复制图像,请创建第二个画布并将原始图像绘制到上面。

    下面的函数会做到这一点

    function copyToCanvas(image) {
        const can = document.createElement("canvas");
        can.width = image.naturalWidth || image.width;
        can.height = image.naturalHeight || image.height;
        can.ctx = can.getContext("2d");
        can.ctx.drawImage(image, 0, 0);
        return can;
    }
    

    ###删除频道数据

    从前一种方法复制的图像中删除不需要的通道数据需要两个步骤。

    1. 使用复合操作"multiply" 删除不需要的频道数据。
    2. 上述步骤会将 Alpha 通道设置为 255。要恢复 Alpha,请使用复合操作 "destination-in" 并将原始图像绘制在新图像上。

    以下函数将复制图像,删除不需要的通道数据并保持 alpha 通道完整。

    const channels = {
       red: "#F00",
       green: "#0F0",
       blue: "#00F",
    };
    
    function getChannel(channelName, image) {
        const copy = copToCanvas(image);
        const ctx = copy.ctx;
        ctx.fillStyle = channels[channelName];
        ctx.globalCompositeOperation = "multiply";
        ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
        ctx.globalCompositeOperation = "destination-in";
        ctx.drawImage(image, 0, 0);
        ctx.globalCompositeOperation = "source-over";
        return copy;
    }
    

    ###获取 RGB 通道

    由于保留了 Alpha 通道,您只需分离出红绿通道和蓝色通道。

    使用前面的函数,下面将创建一个保存原始图像和 3 个通道的对象

     function seperateRGB(image) {
         return {
             red: getChannel("red", image),
             green: getChannel("green", image),
             blue: getChannel("blue", image),
         };
     }
    

    ###重新组合频道

    现在通道已被分离,您可以重新组合通道,方法是首先制作一个与原始图像大小相同的新画布,加上您在重新组合图像时添加的任何偏移量(如果您不添加回 alpha)。

    function createCanvas(w, h) {
        const can = document.createElement("canvas");
        can.width = w;
        can.height = h;
        can.ctx = can.getContext("2d");
        return can;
    }
    

    然后将第一个通道(可以是三个通道中的任何一个)绘制到新画布上。然后使用复合操作"lighter" 绘制其他两个通道。然后使用复合操作"destination-in"恢复alpha

    const RGB = seperateRGB(image);
    const recombined = createCanvas(RGB.red.width, RGB.red.height);
    const ctx = recombined.ctx;
    
    ctx.drawImage(RGB.red, -2, -2);
    ctx.globalCompositeOperation = "lighter";
    ctx.drawImage(RGB.green, 0, 0);
    ctx.drawImage(RGB.blue, 2, 2);
    ctx.globalCompositeOperation = "destination-in";
    ctx.drawImage(image, 0, 0);
    ctx.globalCompositeOperation = "source-over";
    

    ##全部完成

    canvas 元素recombined 保存重新组合的图像,其中绿色和蓝色通道偏移 2 个像素并恢复原始 alpha。

    请注意,您不需要恢复 alpha。如果某些通道发生偏移,则恢复 alpha 将删除一些不重叠的像素。

    【讨论】:

    • 哇!感谢您提供如此有力的答案……您让它看起来如此简单。我不认为我会自己想出这个。不是我所追求的,但肯定给了我一些可以使用的东西。副本仍然是灰度的,但我相信我可以从我之前所做的事情中弄清楚。再次非常感谢。
    • 很好的解决方案,Blindman67! getChannel 中有一个错字:globalCompositeOperation → globalCompositeOperation。
    猜你喜欢
    • 1970-01-01
    • 2022-10-25
    • 2013-12-09
    • 1970-01-01
    • 2021-12-17
    • 2013-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多