Bina penapis tersuai dan editor imej mod gabungan dengan CamanJS

PHPz
Lepaskan: 2023-09-04 10:41:02
asal
1514 orang telah melayarinya

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

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.

Buat mod campuran baharu

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
    };
});
Salin selepas log masuk

让我们以类似的方式创建另一个混合模式。这次,如果父层对应像素的通道值大于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
    };
});
Salin selepas log masuk

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

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

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;
});
Salin selepas log masuk

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

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;
});
Salin selepas log masuk

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

CamanJS 还允许您设置绝对和相对位置像素的颜色,而不是操纵当前像素的颜色。不幸的是,这种行为有点错误,所以我们必须重写一些方法。如果您查看该库的源代码,您会注意到 getPixel()putPixel() 等方法调用了 方法<code class="inline">this 上的 和 上的 和 。但是,这些方法不是在原型上定义的,而是在类本身上定义的。

该库的另一个问题是 putPixelRelative() 方法在两个不同的地方使用变量名称 nowLoc 而不是 newLoc

Berikut ialah contoh mod gabungan tersuai yang menetapkan nilai setiap saluran piksel kepada 255 jika nilai saluran piksel yang sepadan dalam lapisan induk melebihi 128. Jika nilai lebih rendah daripada 128, nilai saluran akhir ialah nilai saluran induk tolak nilai saluran lapisan semasa. Nama mod campuran ialah 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;
};
Salin selepas log masuk
Salin selepas log masuk
🎜Mari cipta satu lagi mod campuran dengan cara yang sama. Kali ini, jika nilai saluran piksel yang sepadan dalam lapisan induk lebih besar daripada 128, nilai saluran akhir akan ditetapkan kepada 0. Jika nilai saluran lapisan induk kurang daripada 128, hasil akhirnya ialah penambahan nilai saluran lapisan semasa dan lapisan induk untuk piksel tertentu. Mod campuran ini telah dinamakan 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;
});
Salin selepas log masuk
Salin selepas log masuk
🎜Anda harus cuba mencipta mod gabungan anda sendiri untuk berlatih. 🎜 🎜Buat penapis berasaskan piksel baharu🎜 🎜Terdapat dua jenis penapis utama dalam CamanJS. Anda boleh mengendalikan keseluruhan imej satu piksel pada satu masa, atau anda boleh menggunakan kernel konvolusi untuk mengubah suai imej. Kernel lilitan ialah matriks yang menentukan warna piksel berdasarkan piksel yang mengelilinginya. Dalam bahagian ini kita akan menumpukan pada penapis berasaskan piksel. Operasi kernel diliputi dalam bahagian seterusnya. 🎜 🎜Penapis berasaskan piksel memberikan nilai saluran RGB satu piksel pada satu masa. Nilai RGB akhir piksel tertentu itu tidak dipengaruhi oleh piksel sekeliling. Anda boleh membuat penapis anda sendiri menggunakan 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
    ]);
});
Salin selepas log masuk
Salin selepas log masuk
🎜Anda boleh membuat penapis ambang dengan cara yang sama. Kali ini, kami akan membenarkan pengguna melepasi ambang. Jika kecerahan piksel tertentu lebih tinggi daripada had yang dibekalkan pengguna, piksel akan menjadi putih. Jika kecerahan piksel tertentu jatuh di bawah had yang dibekalkan pengguna, piksel itu akan menjadi hitam. 🎜 rrreee 🎜Sebagai latihan, anda harus cuba mencipta penapis berasaskan piksel anda sendiri, contohnya, meningkatkan nilai saluran tertentu pada semua piksel. 🎜 🎜CamanJS juga membolehkan anda menetapkan warna piksel yang diposisikan secara mutlak dan relatif dan bukannya memanipulasi warna piksel semasa. Malangnya, tingkah laku ini agak buggy, jadi kita perlu mengatasi beberapa kaedah. Jika anda melihat pada kod sumber pustaka, anda akan melihat bahawa kaedah seperti 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;
};
Salin selepas log masuk
Salin selepas log masuk

更正代码后,您现在应该能够创建依赖于 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;
});
Salin selepas log masuk
Salin selepas log masuk

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

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

正如我之前提到的,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
    ]);
});
Salin selepas log masuk
Salin selepas log masuk

以下 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!

sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan
Tentang kita Penafian Sitemap
Laman web PHP Cina:Latihan PHP dalam talian kebajikan awam,Bantu pelajar PHP berkembang dengan cepat!