Canvas繪制、合并、保存圖像以及存在的問題

最近幫學校官方微信做了一個頭像合成的小頁面,用戶可以自己選擇本地照片,上傳并裁剪后,與學校logo合成最終圖片,用戶可以長按保存到本地,同樣,我也把他放到了GitHub,效果大概下面這個樣子。因為有官方微信的推廣,點擊量分分鐘過5千,雖然是個很一般的東西,自己寫的代碼也很一般,都是看著朋友圈很多人用著通過自己寫的制作器做的頭像,感覺很棒哦。

test.gif

這個頁面全部在前端完成,因為HTML5的強大,我沒寫一句后臺代碼,此外非常感謝這么優秀的開源項目Cropper.js,為我們提供了這么好的裁剪插件。但是在做的過程中,還是遇到了不少問題,特別是canvas繪的圖在手機等高分辨率設備上,會變模糊的問題,所以還是有必要總結一下。

Canvas繪圖API使用

關于canvas的其他知識自行查閱API,今天直接上手canvas繪制圖像。你需要知道
1.canvas的width和height 和css 的width和height不是一回事

image.png

image.png

可以看出canvas的css width,height分別為400px,畫布width,height為200,200是把css像素分成了200份,所以填充寬度為100,卻占了csswidth的1/2.
結論(假設cx指畫布長度單位)

  1. canvas畫布的默認寬高300*150
  2. css width和height決定你在屏幕上占多大空間,在你不設置的時候,默認和畫布大小一致
  3. 當你的css寬高和畫布寬高不一樣時,會有一個兌換關系,這會導致一些奇怪的問題。比如說css width:450px;height:300px; 畫布沒有設置的話。默認300cx150cx,所以水平方向1cx=450/300=1.5px 垂直方向1cx=300/150=2px 。所以你這個時候畫一個100100的正方形,畫出來的是1.5100,2100的長方形,人家本來是我們數學里學的標準坐標軸,你強行讓人家單位長度不同了。所以如果沒有必要,不要修改canvas的css width和height,這時候1cx=1px,而且水平方向和垂直方向是一樣的,如果你非要改,起碼讓他們比例一樣,即水平方向1cx等于幾個px,在垂直方向保持一致
  4. 在canvas里繪圖,用到的所有長度單位都是指cx.默認情況下,1cx=1px.

2.看繪圖上下文提供的相關API

  1. context.drawImage(image,x,y)
    x,y為畫布中畫圖的起始坐標,用此方法繪制出的圖像與原圖大小一致,即如果圖片尺寸為640320,那么即640cx320cx,默認cx=px

  2. context.drawImage(image,x,y,w,h)
    w,h指繪制出來的圖像的寬度與高度,比例與原圖寬高最好一致,圖像不會變形。

  3. context.drawImage(image,sx,sy,sw,sh,dx,dy,dw,dh);
    此方法可用于繪制圖像的局部區域,sx,sy為局部區域的起始點坐標,sw,sh為局部區域的寬高。(sx,sy,sw,sh) 與(dx,dy,dw,dh)沒有關系,前者表示從哪里截取,取多大,后者表示你要在哪里放,在多大的地方放,可以放大或者縮小。如可以用于局部放大,實現特寫效果
    上述方法中的image 均指image對象

    var img=new Image();
    img.src="" //指定url
    img.onload=function(){
       //繪制圖像
    }
    

3.實現圖像組合
用canvas實現圖像組合也很簡單,可以通過設置圖形上下文的globalCompositeOperation 屬性來決定圖像組合模式
如我實現這個圖像合成的效果,我想要的logo不動,然后用戶圖像繪制在其下方。

image.png

其他模式還有很多,請自行查閱API
4.如何將canvas繪制的圖形保存成圖片
其實canvas繪制的任何東西都可以保存為圖片,代碼也很簡單

var oCanvas=document.getElementById("myCanvas");
var src=oCanvas.toDataURL("image/png") ;
//然后你就可以隨便怎么利用,你可以利用HTML5 a標簽 download屬性,也可以將其通過img標簽展示到
//頁面,然后長按/右鍵保存到本地

利用canvas在高清屏繪制圖像的大坑

一開始沒有發現這個問題,但是發給別人頭像制作器的鏈接,別人跟我說生成的頭像太模糊了,我自己試了下,的確很模糊,于是就百度了下,還好這是一個有目共睹的坑,所以一百度就找到了解決辦法。
出現這個問題的原因就是,在手機等高清屏設備上,存在一個devicePixelRatio,這個東西對于搞移動端web開發還是比較重要的,你在開發移動端網頁是,開頭常常會寫一個name為viewport的標簽也與這個東西有關。詳情請看我的移動端開發必須知道的viewport
解決辦法也很簡單,先通過hidpi-canvas-polyfill提供的函數獲得PixelRatio

var getPixelRatio = function(context) {
var backingStore = context.backingStorePixelRatio ||
    context.webkitBackingStorePixelRatio ||
    context.mozBackingStorePixelRatio ||
    context.msBackingStorePixelRatio ||
    context.oBackingStorePixelRatio ||
    context.backingStorePixelRatio || 1;
    return (window.devicePixelRatio || 1) / backingStore;
};

然后,將canvas畫布寬高先擴大PixelRatio 倍,然后再用css將寬高縮小到原來的寬高。經測試,當原圖比畫布大小大時,此方法比不用此方法清晰的多,當原圖大小與canvas大小一樣時,這個問題不是很明顯。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 一:canvas簡介 1.1什么是canvas? ①:canvas是HTML5提供的一種新標簽 ②:HTML5 ...
    GreenHand1閱讀 4,719評論 2 32
  • 一、圖形的組合方式 globalAlpha是一個介于0和1之間的值(包括0和1),用于指定所有繪制的透明度。默認值...
    空谷悠閱讀 1,324評論 0 0
  • 本文首發于我的個人博客:http://cherryblog.site/github項目地址:https://git...
    sunshine小小倩閱讀 2,022評論 1 8
  • 一、canvas簡介 1.1 什么是canvas?(了解) 是HTML5提供的一種新標簽 Canvas是一個矩形區...
    Looog閱讀 3,972評論 3 40
  • 昨天時間有限,臨摹了一副@冰兒蕭蕭的小圖,構圖比較簡單,上色也快,顏色看起來清新自然。沒有咖色的勾線筆,就只能直接...
    熊胖胖手繪yiping閱讀 378評論 1 2