在我們的 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 <p>您應該嘗試創建自己的混合模式進行練習。</p> <h2>創建新的基于像素的過濾器</h2> <p>CamanJS 中有兩大類過濾器。您可以一次對整個圖像進行一個像素操作,也可以使用卷積核修改圖像。卷積核是一個矩陣,它根據某個像素周圍的像素來確定該像素的顏色。在本節中,我們將重點關注基于像素的濾波器。內核操作將在下一節中介紹。</p> <p>基于像素的濾鏡一次給出一個像素的 RGB 通道值。該特定像素的最終 RGB 值不受周圍像素的影響。您可以使用 Caman.Filter.register("filter_name", callback); 創建自己的過濾器。您創建的任何過濾器都必須調用 process() 方法。此方法接受過濾器名稱和回調函數作為參數。</p> <p>以下代碼片段向您展示如何創建基于像素的過濾器,將圖像變成灰度。這是通過計算每個像素的發光,然后將各個通道的值設置為等于計算的發光來完成的。</p> <pre class="brush:javascript;toolbal:false;">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 <p>更正代碼后,您現在應該能夠創建依賴于 putPixelRelative() 的過濾器,沒有任何問題。這是我創建的一個這樣的過濾器。</p> <pre class="brush:javascript;toolbal:false;">Caman.Filter.register("erased", function (adjust) { this.process("erased", function (rgba) { if(Math.random() <p>此過濾器將當前像素向上兩行和右側兩列的像素值隨機設置為白色。這會擦除部分圖像。這就是過濾器名稱的由來。</p> <h2>創建新的基于內核操作的過濾器</h2> <p>正如我之前提到的,CamanJS 允許您創建自定義濾鏡,其中當前像素的顏色由其周圍的像素決定。基本上,這些濾鏡會遍歷您正在編輯的圖像中的每個像素。圖像中的一個像素將被其他八個像素包圍。圖像中這九個像素的值乘以卷積矩陣的相應條目。然后將所有這些乘積加在一起以獲得像素的最終顏色值。您可以在 GIMP 文檔中更詳細地了解該過程。</p> <p>就像基于像素的過濾器一樣,您可以使用 Caman.Filter.register("filter_name", callback); 定義自己的內核操作過濾器。唯一的區別是您現在將在回調函數內調用 processKernel()。</p> <p>這是使用內核操作創建浮雕過濾器的示例。</p> <pre class="brush:javascript;toolbal:false;">Caman.Filter.register("emboss", function () { this.processKernel("emboss", [ -2, -1, 0, -1, 1, 1, 0, 1, 2 ]); });
以下 CodePen 演示將展示我們在本教程中創建的所有過濾器的實際操作。
最終想法
在本系列中,我幾乎涵蓋了 CamanJS 在基于畫布的圖像編輯方面提供的所有內容。您現在應該能夠使用所有內置濾鏡、創建新圖層、在這些圖層上應用混合模式以及定義您自己的混合模式和濾鏡功能。
您還可以瀏覽 CamanJS 網站上的指南,以了解我可能錯過的任何內容。我還建議您閱讀該庫的源代碼,以了解有關圖像處理的更多信息。這也將幫助您發現庫中的任何其他錯誤。