首先我們知道css3中增加了不少好用、好玩的css3樣式可以使用。今天我們要說到是遮罩。
它的使用方式也不復雜,和background使用方式差不多。使用mask-image就可以使用,這樣就可以通過圖片合成一張帶有形狀的合成圖了,不需要直接使用PS處理了。
CSS遮罩——如何在CSS中使用遮罩,這篇文章已經詳細說明了遮罩如何使用了,我這里就不贅述了。今天我這里想要說明的是,如何通過這個完成生成一個合成圖片的邏輯。
它通過兩種方式:前端JS+canvas,后端nodejs+canvas,完成基本思路是一樣的,但是兩種方式,后者的兼容性稍好一些。
基礎的圖片合成,整體的思路是:首先按照遮罩層的大小,生成一張圖片;其次把原圖片按照一定的規則按照遮罩層大小剪切(drawImage)一張圖片然后合成到遮罩層上面;最后一個非常重要設置是:globalCompositeOperation,設置圖片合成時,組合操作。
前端JS實現
utils.canvasMasking = function(img) {
var deferred = $.Deferred();
var newImg = document.createElement('img');
newImg.setAttribute('crossOrigin', 'Anonymous'); //解決跨域問題
newImg.src = img.src;
//源圖片加載失敗
newImg.onerror = function() {
deferred.reject('源圖片加載失敗');
};
//源圖片加載成功
newImg.onload = function() {
var imageWidth = img.width;
var imageHeight = img.height;
var mask = document.createElement('img');
mask.setAttribute('crossOrigin', 'Anonymous');
mask.src = img.getAttribute('data-mask');
//遮罩圖片加載失敗
mask.onerror = function() {
deferred.reject('遮罩圖片加載失敗');
};
//遮罩圖片加載成功
mask.onload = function() {
var maskCanvas = document.createElement('canvas');
var maskContext = maskCanvas.getContext('2d');
var maskWidth = mask.width;
var maskHeight = mask.height;
maskCanvas.width = maskWidth;
maskCanvas.height = maskHeight;
/**
* 合並mask與處理后的原始圖
*/
maskContext.drawImage(mask, 0, 0, maskWidth, maskHeight);
//將一個源(新的)圖像繪制到目標(已有)的圖像上
maskContext.globalCompositeOperation = 'source-in';
maskContext.drawImage(img, 0, 0, maskWidth, maskHeight);
img.src = maskCanvas.toDataURL();
deferred.resolve(maskCanvas);
};
};
return deferred.promise();
};
由於canvas是禁止跨域的,所以有兩個條件可以進行控制:
- 圖片的頭信息必須設置允許跨域的頭(Access-Control-Allow-Origin:*)
- 創建的image標簽必須也能允許跨域(img.setAttribute(‘crossOrigin’, 'Anonymous'))
大概實現過程如下:
后端node實現
后端實現的大致思路和前端js操作canvas基本上差不多。后端需要依賴node-canvas模塊,提供與瀏覽器幾乎完全一致的api,所以可以無縫切換。詳細的實現說明同上,這里就不詳細說明,主要說明的可能是node-canvas的安裝和正常使用。
因為是處理圖片,所以對安裝的環境有一些要求,相對比其它的模塊要求稍高一些。首先他依賴
Cairo。有一些依賴關系需要安裝,主要是處理圖片的庫,看具體需求,主要有處理三種圖片:png、jpeg、gif。
| OS | Command |
|---|---|
| OS X | brew install pkg-config cairo libpng jpeg giflib |
| Ubuntu | sudo apt-get install libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev build-essential g++ |
| Fedora | sudo yum install cairo cairo-devel cairomm-devel libjpeg-turbo-devel pango pango-devel pangomm pangomm-devel giflib-devel |
| Solaris | pkgin install cairo pkg-config xproto renderproto kbproto xextproto |
| Windows | Instructions on our wiki |
上表的信息來自
github。
這里我說明一下我踩過的坑:
- 第一次由於沒有安裝jpeg導致處理jpg圖片時,出現加載失敗的提示,遇到這種情況可以檢查自己的庫依賴是不是沒有安裝完全;
- 第二次安裝了jpeg的庫之后,發現依然不行,最后發現問題在於我的jpeg的庫是在我已經安裝完成node-canvas之后才安裝的
- 第三次把在mac安裝好的node-modules復制到centos的服務器上,發現canvas不可以用。原因是他們的圖片處理庫不一樣,必須重新安裝node-canvas
綜上所述:
安裝node-canvas的前提條件是安裝所有依賴的庫文件,不同的環境下,需要重新下載node-canvas進行安裝,原因是node-canvas每次都要編譯一遍。
另外一些題外的問題:
- 合成圖片的時候,如果需要移動、縮放或者旋轉怎么處理?可以使用使用canvas的tranlate、scale、rotate進行完成,這里需要注意的是網頁上的呈現效果和合成處理是否一致的問題。
- 前端合成多張遮罩圖片的時候,不同的手機的兼容性問題
- 微信里的頁面無法通過下載按鈕,下載生成的圖片;並且canvas.otDataURL()的圖片無法長按保存
- 使用html2canvas將dom生成圖片的時候,需要設置允許跨域,如果要使用proxy的話,可以參考進行實現。
- 另外html2canvas生成的canvas信息在上傳base64的時候,可能出現413,body實體太大的提示,這時候需要檢查服務器或者服務器語言的允許body的大小是否有限制。
我目前遇到一個問題:瀏覽器不同分辨率下展現的大小和我服務端生成的圖片不一致?正在解決。。。
2015-11-23 新增:效果頁面
參考資料:
