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