Dalam tutorial pertama siri editor imej CamanJS kami, kami mengedit imej menggunakan penapis terbina dalam sahaja. Ini mengehadkan kami kepada beberapa kesan asas seperti Kecerahan, Kontras dan 18 penapis lain yang lebih kompleks (dengan nama seperti Vintaj, Matahari Terbit, dll.). Kesemuanya mudah digunakan, tetapi kami tidak mempunyai kawalan penuh ke atas piksel individu imej yang ingin kami edit.
Dalam tutorial kedua ini, kami mempelajari tentang lapisan dan mod pengadunan, yang memberi kami lebih kawalan ke atas imej yang sedang kami edit. Sebagai contoh, anda boleh menambah lapisan baharu pada kanvas, mengisinya dengan warna atau imej, kemudian meletakkannya pada lapisan induk dan menggunakan mod pengadunan. Walau bagaimanapun, kami masih belum mencipta penapis kami sendiri, dan mod adunan yang boleh kami gunakan adalah terhad kepada yang telah disediakan oleh CamanJS.
Tujuan tutorial ini adalah untuk mengajar anda cara membuat mod adunan dan penapis anda sendiri. Kami juga akan menangani beberapa pepijat yang terdapat dalam perpustakaan dan cara menampalnya apabila menggunakan CamanJS dalam projek anda sendiri.
Secara lalai, CamanJS menyediakan sepuluh mod pengadunan. Ia adalah Normal, Multiply, Mask, Add, Difference, Add, Exclude, Soft Light, Lighten dan Darken. Perpustakaan ini juga membenarkan anda mendaftarkan mod campuran anda sendiri. Dengan cara ini, anda boleh mengawal cara piksel yang sepadan bagi lapisan semasa dan lapisan induk digabungkan bersama untuk menghasilkan hasil akhir.
Anda boleh menggunakan Caman.Blender.register("blend_mode", callback);
untuk mencipta mod campuran baharu. Di sini, blend_mode
ialah nama yang anda mahu gunakan untuk mengenal pasti mod campuran yang anda cipta. Fungsi panggil balik menerima dua parameter, yang mengandungi nilai RGB piksel berbeza pada lapisan semasa dan piksel sepadan pada lapisan induk. Fungsi ini mengembalikan objek yang mengandungi nilai akhir saluran rgb
. 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()
等方法调用了 方法<code class="inline">this
上的 和 上的 和 。但是,这些方法不是在原型上定义的,而是在类本身上定义的。
该库的另一个问题是 putPixelRelative()
方法在两个不同的地方使用变量名称 nowLoc
而不是 newLoc
maxrgb
. 🎜
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; };
minrgb
. 🎜
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; });
Caman.Filter.register("filter_name", callback);
. Mana-mana penapis yang anda buat mesti memanggil kaedah process()
. Kaedah ini menerima nama penapis dan fungsi panggil balik sebagai parameter. 🎜
🎜Coretan kod berikut menunjukkan kepada anda cara membuat penapis berasaskan piksel yang menukar imej kepada skala kelabu. Ini dilakukan dengan mengira luminescence setiap piksel dan kemudian menetapkan nilai saluran individu sama dengan luminescence yang dikira. 🎜
Caman.Filter.register("emboss", function () { this.processKernel("emboss", [ -2, -1, 0, -1, 1, 1, 0, 1, 2 ]); });
getPixel()
dan putPixel()
memanggil Kaedah
dan pada ini
dan pada . Walau bagaimanapun, kaedah ini tidak ditakrifkan pada prototaip, tetapi pada kelas itu sendiri. 🎜
🎜Satu lagi masalah dengan perpustakaan ini ialah kaedah putPixelRelative()
menggunakan nama pembolehubah nowLoc
dan bukannya dalam dua berbeza places class="inline">newLoc
. Anda boleh menyelesaikan kedua-dua isu dengan menambahkan kod berikut pada skrip anda. 🎜
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 网站上的指南,以了解我可能错过的任何内容。我还建议您阅读该库的源代码,以了解有关图像处理的更多信息。这也将帮助您发现库中的任何其他错误。
Atas ialah kandungan terperinci Bina penapis tersuai dan editor imej mod gabungan dengan CamanJS. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!