摘要:通過這套流程,我們便能添加任意的圖片圖層并合成圖片。下篇文章,我們會繼續介紹下文字的合成和幾何圖片的合成,敬請期待
JavaScript中的圖片處理與合成(二) 引言
本系列分成以下4個部分:
基礎類型圖片處理技術之縮放、裁剪與旋轉(傳送門);
基礎類型圖片處理技術之圖片合成;
基礎類型圖片處理技術之文字合成;
算法類型圖片處理技術;
上篇文章,我們介紹了圖片的裁剪/旋轉與縮放,接下來本文主要介紹 圖片的合成 ,這是基礎類圖片處理中比較實用且復雜的一部分,可以算第一篇文章內容的實踐。
通過這些積累,我封裝了幾個項目中常用的功能:
圖片合成 ??? 圖片裁剪 ??? 人像摳除 圖片的合成圖片的合成在實際項目中運用也是十分的廣泛,大家可以試試這個demo(僅支持移動端): ???
小狗貼紙圖片的合成原理其實類似于photoshop的理念,通過 圖層的疊加 ,最后合成并導出,相比于裁剪和縮放,其實基本原理是一致的,但是它涉及了更多的計算和比較復雜的流程,我們先一起來梳理下合成的整個邏輯。
相信大家對 photoshop都是較為了解的,我們可以借鑒它的思維方式:
新建 psd 文件, 設置寬高;
設置背景圖;
從底部到頂部一層層添加所需要的圖層;
最后直接將整個文件導出成一張圖片;
以需要合成下圖為?:
1、首先我們需要創建一個與原圖一樣大小的畫布;
2、加載背景圖并 添加背景圖層 ,也就是這個美女啦~
3、加載貓耳朵圖并添加美女頭上的 貓耳朵圖層 ( 2/3順序不可逆,否則耳朵會被美女蓋在下面哦。因此圖片的加載控制十分重要 );
4、將整個畫布 導出圖片 ;
合成部分,主要以封裝的插件為栗子哈。這樣能盡可能的完整,避免遺漏點。在開始之前,為了確保圖片異步繪制的順序,我們需要先來構建一套隊列系統。
隊列系統;圖片的加載時間是 異步且未知 的,而圖片的合成需要嚴格保證繪制 順序 ,越后繪制的圖片會置于越頂層,因此我們需要一套嚴格機制來控制圖片的加載與繪制,否則我們將無法避免的寫出 回調地獄 ,這里我使用到了簡單的隊列系統;
隊列系統的原理其實也很簡單,主要是為了我們能確保圖層從底到頂一層一層的繪制。我設計的使用方式如下, 隊列方式主要來確保add函數的按順序繪制:
</>復制代碼
// 創建畫布;
let mc = new MCanvas();
// 添加圖層;
mc.add(image-1).add(image-2);
// 繪制并導出圖片;
mc.draw();
這樣我們就明白了,這個隊列系統需要下面幾個點:
queue隊列: 用于存放圖層繪制函數;
next函數: 用于表示當前圖層已繪制完畢,執行下一圖層的繪制;
add函數: 作為統一添加圖層的方法,將繪制邏輯存入函數棧quene,并包裹next函數;
draw函數: 作為繪制啟動函數,表示所有圖層素材已經準備完畢,可以按順序開始繪制;
</>復制代碼
MCanvas.queue = [];
MCanvas.prototype.add = function(){
this.queue.push(()=>{
// 繪制邏輯,之后詳解;
...
// 執行下個圖層繪制;
this.next();
});
}
MCanvas.prototype.next = function(){
if(this.queue.length > 0){
// 當隊列中還有繪制任務時,則推出并執行;
this.queue.shift()();
}else{
// 當繪制完成后,調用成功事件,并傳出結果圖;
this.fn.success();
}
};
MCanvas.prototype.draw = function(){
// 導出邏輯;
...
// 設置成功事件,用于導出結果圖;
this.fn.success = () => {
// 使用 setTimeout 能略微提升性能表現;
// 且隊列函數中都為真正的異步,因此此處不會影響邏輯;
setTimeout(()=>{
b64 = this.canvas.toDataURL(`image/jpeg}`, 0.9);
...
},0);
};
// 啟動隊列執行;
this.next();
}
此時,queue、add、next與draw便組成了一整套隊列系統,可確保圖片的順序加載和繪制,準備好素材和隊列后,我們便可以開始真正的合成圖片咯~~
創建畫布</>復制代碼
MCanvas.prototype._init = function(){
this.canvas = document.createElement("canvas");
this.ctx = this.canvas.getContext("2d");
};
繪制背景圖
設置畫布大小并繪制美女背景圖。
通過調整背景圖的dx,dy,dw,dh參數,可以繪制出多種模式,類似于css中的background-size的contain/cover等效果。
這里主要以上面使用到的場景為例子,既原圖模式。
</>復制代碼
// 原圖/效果圖尺寸保持一致;
MCanvas.prototype.background = function(image, bgOps){
// 推入隊列系統;
this.queue.push(() => {
let { iw, ih } = this._getSize(img);
// 圖片與canvas的長寬比;
let iRatio = iw / ih;
// 背景繪制參數;
let dx,dy,dwidth,dheight;
// 設置畫布與背景圖尺寸一致;
this.canvas.width = iw;
this.canvas.height = ih;
dx = dy = 0;
dwidth = this.canvas.width;
dheight = this.canvas.height;
// 繪制背景圖;
this.ctx.drawImage(img,dx,dy,dwidth,dheight);
this._next();
});
return this;
};
繪制貓耳朵貼紙
相信大家都玩過貼紙,其最大的特點,就是貼紙與背景圖的匹配。也就是用戶可以修改貼紙的 大小,位置,旋轉角度,通過手勢操作將貓耳朵完美地貼在照片人物的頭上。因此也就是說add這個方法,需要設置縮放,旋轉與位置等參數。
這里先模擬出一份使用參數, 實際真實情況會根據不同的背景圖,用戶會調整出不同的位置參數。
</>復制代碼
{
// 圖片路徑;
image:"./images/ear.png",
options:{
// 貼紙寬度;
width:482,
pos:{
// 貼紙左上點坐標;
x:150,
y:58,
// 貼紙放大系數;
scale:1,
// 貼紙旋轉系數;
rotate:35,
},
},
}
add函數
接下里我們便來在add函數中解析下各個參數的使用姿勢:
繪制小畫布來處理旋轉:
</>復制代碼
// 創建小畫布;
let lcvs = document.createElement("canvas"),
lctx = lcvs.getContext("2d");
// 貼紙圖原始大小;
let { iw, ih } = this._getSize(img);
// 繪制參數;
let ldx, ldy, ldw, ldh;
// 貼紙原始尺寸;
ldw = iw;
ldh = ih;
// 繪制起始點;
ldx = - Math.round(ldw / 2);
ldy = - Math.round(ldh / 2);
// 上篇文章我們說過旋轉裁剪的問題,這里就需要用到;
// 需要擴大小畫布的容器,以避免旋轉造成的裁剪;最大值為放大5倍;
let _ratio = iw > ih ? iw / ih : ih / iw;
let lctxScale = _ratio * 1.4 > 5 ? 5 : _ratio * 1.4;
lcvs.width = ldw * lctxScale;
lcvs.height = ldh * lctxScale;
// 調整繪制基點;
lctx.translate(lcvs.width/2,lcvs.height/2);
// 旋轉畫板;
lctx.rotate(ops.pos.rotate);
// 繪制貼紙;
lctx.drawImage(img,ldx,ldy,ldw,ldh);
此時我們會得到一個小畫布,中心繪制這貓耳朵貼紙:
接下來我們便是將貼紙繪制到背景圖上,需要注意的點就是,放大會增加貼紙畫布的空白區域,需要考慮到這部分區域,才能計算出最后真實的dx,dy值:
</>復制代碼
// 繪制參數;
let cratio = iw / ih;
let cdx, cdy, cdw, cdh;
// ops.width 為最終畫到大畫布上時的寬度;
// 由于小畫布進行了放大,因此最終寬度也需要等倍放大;
// 并乘以配置中還需要縮放的系數;
cdw = ops.width * lctxScale * ops.pos.scale;
cdh = cdw / cratio * ops.pos.scale;
// 放大后增加的空白區域;
spaceX = (lctxScale - 1) * ops.width / 2;
spaceY = spaceX / cratio;
// 獲取素材的最終位置;
// 配置的位置 - 配置放大系數的影響 - 小畫布放大倍數的影響;
cdx = ops.pos.x + cdw * ( 1 - ops.pos.scale )/2 - spaceX;
cdy = ops.pos.y + cdh * ( 1 - ops.pos.scale )/2 - spaceY;
this.ctx.drawImage(lcvs,cdx,cdy,cdw,cdh);
lcvs = lctx = null;
這樣便能得到合成后的結果圖了,紅色邊框代表小畫布,黑色邊框代表大畫布:
</>復制代碼
MCanvas.prototype.add = function(img, options){
this.queue.push(()=>{
// 繪制貼紙小畫布;
...
// 繪制貼紙到大畫布上;
...
this._next();
});
return this;
}
這樣我們便完成了一系列方法,構建了一套完整的合成流程。通過這套流程,我們便能添加任意的圖片圖層并合成圖片。
結語本文主要講解了圖片合成上的方法原理和一些需要填的坑,這整套流程也是經過了很長一段時間的打磨,填了許多坑后總結出來的,算比較成熟的方案,已經work在多個線上項目中,期望能對大家有所幫助!?。
下篇文章,我們會繼續介紹下文字的合成和幾何圖片的合成,敬請期待~~??
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/93183.html
摘要:中的圖片處理與合成一引言圖片處理現在已經成為了我們生活中的剛需,想必大家也經常有這方面的需求。實際前端業務中,也經常會有很多的項目需要用到圖片加工和處理。 JavaScript中的圖片處理與合成(一) 引言: 圖片處理現在已經成為了我們生活中的剛需,想必大家也經常有這方面的需求。實際前端業務中,也經常會有很多的項目需要用到圖片加工和處理。由于過去一段時間公司的業務需求,讓我在這方面積累...
摘要:算法性能提升圖片算法處理實質原理其實是遍歷像素點,對像素點的值進行改造。而像素點的數量與圖片的大小尺寸成正向指數級增長,因此適當的縮放圖片源后再去處理,對性能的提升十分巨大。 引言: 本系列現在構思成以下4個部分: 基礎類型圖片處理技術之縮放、裁剪與旋轉(傳送門); 基礎類型圖片處理技術之圖片合成(傳送門); 基礎類型圖片處理技術之文字合成(傳送門); 算法類型圖片處理技術(傳送門)...
摘要:網頁的渲染方式主要有兩種軟件渲染和硬件加速渲染。而使用合成化的渲染技術,以使用軟件繪圖的合成化渲染為例,對于使用繪制的層,其結果保存在內存中,之后傳輸到中進行合成。 Webkit 渲染基礎與硬件加速 當瀏覽器加載一個 html 文件并對它進行解析完畢后,內核就會生成一個極為重要的數據結構即 DOM 樹,樹上每一個節點都對應著網頁里面的某一個元素,并且開發人員也可以通過 JavaScri...
閱讀 3527·2021-10-08 10:04
閱讀 873·2019-08-30 15:54
閱讀 2189·2019-08-29 16:09
閱讀 1354·2019-08-29 15:41
閱讀 2285·2019-08-29 11:01
閱讀 1745·2019-08-26 13:51
閱讀 1035·2019-08-26 13:25
閱讀 1836·2019-08-26 13:24
极致性价比!云服务器续费无忧!
Tesla A100/A800、Tesla V100S等多种GPU云主机特惠2折起,不限台数,续费同价。
NVIDIA RTX 40系,高性价比推理显卡,满足AI应用场景需要。
乌兰察布+上海青浦,满足东推西训AI场景需要