• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

使用CamanJS创建图像编辑器:创建自定义过滤器和混合模式

在我们的 CamanJS 图像编辑器系列的第一个教程中,我们只使用内置过滤器来编辑我们的图像这将我们限制在一些基本效果,如亮度、对比度和 18 个其他更复杂的滤镜,如 Vintage、Sunrise 等。它们都很容易应用,但我们无法完全控制我们想要的图像的单个像素编辑。

在第二个教程中,我们了解了图层和混合模式,这让我们可以更好地控制正在编辑的图像。例如,您可以在画布上添加一个新图层,用颜色或图像填充它,然后将其放置在父图层上并应用混合模式。但是,我们仍然没有创建自己的过滤器,我们可以应用的混合模式仅限于 CamanJS 已经提供的模式。

本教程的目的是教您如何创建自己的混合模式和过滤器。我们还将解决库中存在的一些错误,以及在您自己的项目中使用 CamanJS 时如何修补它们。 

创建新的混合模式

默认情况下,CamanJS 提供十种混合模式。这些是正常、乘法、加网、叠加、差异、加法、排除、柔光、变亮和变暗。该库还允许您注册自己的混合模式。这样,您可以控制当前图层和父图层的相应像素如何混合在一起以产生最终结果。

您可以使用创建新的混合模式 这里 是您要使用的名称,以识别您正在创建的混合模式。回调函数接受两个参数,其中包含当前图层上不同像素和父图层上相应像素的 RGB 值。该函数返回一个具有通道最终值的对象。Caman.blender.register("blend_mode", callback);blend_modergb

这是自定义混合模式的示例,如果父图层中相应像素的通道值超过 128,则将像素的各个通道的值设置为 255。如果值低于 128,则最终通道值是父通道值减去当前层通道值的结果。这种混合模式的名称是maxrgb

Caman.Blender.register("maxrgb", function(rgbaLayer, rgbaParent) {
    return {
        r: rgbaParent.r > 128 ? 255 : rgbaParent.r - rgbaLayer.r,
        g: rgbaParent.g > 128 ? 255 : rgbaParent.g - rgbaLayer.g,
        b: rgbaParent.b > 128 ? 255: rgbaParent.b - rgbaLayer.b
    };
});

让我们以类似的方式创建另一个混合模式。这一次,如果父层对应像素的通道值大于128,则最终通道值将设置为0。如果父层的通道值小于128,则最终结果将是相加特定像素的当前层和父层的通道值。这种混合模式被命名为minrgb.

Caman.Blender.register("minrgb", function(rgbaLayer, rgbaParent) {
    return {
        r: rgbaParent.r < 128 ? rgbaParent.r + rgbaLayer.r : 0,
        g: rgbaParent.g < 128 ? rgbaParent.g + rgbaLayer.r : 0,
        b: rgbaParent.b < 128 ? rgbaParent.r + rgbaLayer.r : 0
    };
});

您应该尝试创建自己的混合模式以进行练习。

创建新的基于像素的过滤器

CamanJS 中有两大类过滤器。您可以一次对整个图像进行一个像素操作,也可以使用卷积核修改图像。卷积核是一个矩阵,它根据周围的像素确定某个像素的颜色。在本节中,我们将重点介绍基于像素的过滤器。内核操作将在下一节中介绍。

基于像素的过滤器一次获得一个像素的 RGB 通道值。该特定像素的最终 RGB 值不受周围像素的影响。您可以使用创建自己的过滤器 Caman.Filter.register("filter_name", callback);您创建的任何过滤器都必须调用该process()方法。此方法接受过滤器名称和回调函数作为参数。

以下代码片段向您展示了如何创建一个基于像素的过滤器,它将图像变为灰度。这是通过计算每个像素的发光度,然后将各个通道的值设置为等于计算出的发光度来完成的。

Caman.Filter.register("grayscale", function () {
    this.process("grayscale", function (rgba) {
        var lumin = (0.2126 * rgba.r) + (0.7152 * rgba.g) + (0.0722 * rgba.b);
        rgba.r = lumin;
        rgba.g = lumin;
        rgba.b = lumin;
    });
    return this;
});

您可以以类似的方式创建阈值过滤器。这一次,我们将允许用户通过一个阈值。如果特定像素的亮度高于用户提供的限制,则该像素将变为白色。如果特定像素的亮度低于用户提供的限制,则该像素将变为黑色。

Caman.Filter.register("threshold", function (limit) {
    this.process("threshold", function (rgba) {
        var lumin = (0.2126 * rgba.r) + (0.7152 * rgba.g) + (0.0722 * rgba.b);
        rgba.r = lumin > limit ? 255 : 0;
        rgba.g = lumin > limit ? 255 : 0;
        rgba.b = lumin > limit ? 255 : 0;
    });
    return this;
});

作为练习,您应该尝试创建自己的基于像素的过滤器,例如,增加所有像素上特定通道的值。

除了操纵当前像素的颜色,CamanJS 还允许您为绝对和相对位置的像素设置颜色。不幸的是,这种行为有点错误,所以我们将不得不重写一些方法。如果您查看库的源代码,您会注意到方法喜欢getPixel()putPixel()调用方法 coordinatesToLocation()和 locationToCoordinates()on this但是,这些方法不是在原型上定义的,而是在类本身上定义的。

该库的另一个问题是该putPixelRelative()方法使用变量名nowLoc而不是newLoc在两个不同的地方。您可以通过在脚本中添加以下代码来解决这两个问题。

Caman.Pixel.prototype.coordinatesToLocation = Caman.Pixel.coordinatesToLocation
Caman.Pixel.prototype.locationToCoordinates = Caman.Pixel.locationToCoordinates

Caman.Pixel.prototype.putPixelRelative = function (horiz, vert, rgba) {
    var newLoc;
    if (this.c == null) {
        throw "requires a CamanJS context";
    }
    newLoc = this.loc + (this.c.dimensions.width * 4 * (vert * -1)) + (4 * horiz);
    if (newLoc > this.c.pixeldata.length || newLoc < 0) {
        return;
    }
    this.c.pixelData[newLoc] = rgba.r;
    this.c.pixelData[newLoc + 1] = rgba.g;
    this.c.pixelData[newLoc + 2] = rgba.b;
    this.c.pixelData[newLoc + 3] = rgba.a;
    return true;
};

更正代码后,您现在应该能够创建一个依赖于putPixelRelative()没有任何问题的过滤器。这是我创建的一个这样的过滤器。

Caman.Filter.register("erased", function (adjust) {
    this.process("erased", function (rgba) {
        if(Math.random() < 0.25) {
        rgba.putPixelRelative(2, 2, {
            r: 255,
            g: 255,
            b: 255,
            a: 255
        });
        }
    });
    return this;
});

此过滤器随机将当前像素右侧两行和两列的像素值设置为白色。这会擦除部分图像。因此过滤器的名称。

创建新的基于内核操作的过滤器

正如我之前提到的,CamanJS 允许您创建自定义过滤器,其中当前像素的颜色由其周围的像素决定。基本上,这些过滤器会检查您正在编辑的图像中的每个像素。图像中的一个像素将被其他八个像素包围。图像中这九个像素的值乘以卷积矩阵的相应条目。然后将所有这些产品加在一起以获得像素的最终颜色值。您可以在GIMP 文档中更详细地了解该过程 

就像基于像素的过滤器一样,您可以使用 Caman.Filter.register("filter_name", callback);唯一的区别是您现在将 processKernel()在回调函数内部调用。

这是使用内核操作创建浮雕过滤器的示例。

Caman.Filter.register("emboss", function () {
    this.processKernel("emboss", [
        -2, -1, 0,
        -1, 1, 1,
        0, 1, 2
    ]);
});

下面的 CodePen 演示将展示我们在本教程中创建的所有过滤器。

使用CamanJS创建图像编辑器:创建自定义过滤器和混合模式  第1张

最后的想法

在本系列中,我几乎涵盖了 CamanJS 在基于画布的图像编辑方面必须提供的所有内容。您现在应该能够使用所有内置过滤器,创建新图层,在这些图层上应用混合模式,并定义您自己的混合模式和过滤器功能。

您还可以浏览 CamanJS 网站上的指南,以了解我可能错过的任何内容。我还建议您阅读该库的源代码,以了解有关图像处理的更多信息。这也将帮助您发现库中的任何其他错误。


文章目录
  • 创建新的混合模式
  • 创建新的基于像素的过滤器
  • 创建新的基于内核操作的过滤器
  • 最后的想法