使用 CamanJS 构建自定义滤镜和混合模式图像编辑器

使用 CamanJS 构建自定义滤镜和混合模式图像编辑器

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

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

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

创建新的混合模式

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

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

下面是自定义混合模式的示例,如果父图层中相应像素的通道值超过 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() 等方法调用了 方法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 在基于画布的图像编辑方面提供的所有内容。您现在应该能够使用所有内置滤镜、创建新图层、在这些图层上应用混合模式以及定义您自己的混合模式和滤镜功能。

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

以上就是使用 CamanJS 构建自定义滤镜和混合模式图像编辑器的详细内容,更多请关注编程之家其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


kindeditor4.x代码高亮功能默认使用的是prettify插件,prettify是Google提供的一款源代码语法高亮着色器,它提供一种简单的形式来着色HTML页面上的程序代码,实现方式如下: 首先在编辑器里面插入javascript代码: 确定后会在编辑器插入这样的代码: <pre
这一篇我将介绍如何让kindeditor4.x整合SyntaxHighlighter代码高亮,因为SyntaxHighlighter的应用非常广泛,所以将kindeditor默认的prettify替换为SyntaxHighlighter代码高亮插件 上一篇“让kindeditor显示高亮代码”中已经
js如何实现弹出form提交表单?(图文+视频)
js怎么获取复选框选中的值
js如何实现倒计时跳转页面
如何用js控制图片放大缩小
JS怎么获取当前时间戳
JS如何判断对象是否为数组
JS怎么获取图片当前宽高
JS对象如何转为json格式字符串
JS怎么获取图片原始宽高
怎么在click事件中调用多个js函数
js如何往数组中添加新元素
js如何拆分字符串
JS怎么对数组内元素进行求和
JS如何判断屏幕大小
js怎么解析json数据
js如何实时获取浏览器窗口大小
原生JS实现别踩白块小游戏(五)
原生JS实现别踩白块小游戏(一)