你想要的拍照,看這裡....
需求
市面上很多美顏相機,想用小程式現有的API,寫一個好用的美顏相機功能。
功能點包含如下:
-
簡單的相機功能,包含(前置/後置,閃光燈)
-
模版的選擇
-
濾鏡的選擇
-
可以上傳照片
-
上傳照片可以塗鴉和去除塗鴉的橡皮擦
-
上傳照片可以新增文字,文字可以改變顏色和字型大小
-
可以儲存至本地,且最終儲存的帶有動態的小程式碼
實現需求
簡單的相機功能,包含(前置/後置,閃光燈)
要實現相機的功能,需要使用微信小程式自帶的api中的camera
,而前置/後置的鏡頭切換,使用device-position
這個屬性,閃光燈使用flash
這個屬性即可,具體程式碼如下:
<camera device-position="{{device}}" flash="{{isFlash}}"></camera>
-
device-position:front/back
,front表示前置,back表示後置 -
flash:auto/on/off/torch
,auto表示自動,on表示開啟,off表示關閉,torch表示常亮(版本>2.8.0)
模版的選擇
模版的展示,是需要在使用者選擇相應的模版模版後,在拍照的區域也展示相應的模版。由於小程式原生元件的限制,想要在camera進行覆蓋,需要使用canvas
進行繪畫。
-
確定camera的位置和長寬,再寫一個canvas跟camera的寬高位置跟camera一模一樣
程式碼如下:
//wxml <camera device-position="{{device}}" flash="{{isFlash}}" style="width:{{cameraWidth}}px;height:{{cameraHeight}}px;z-index:0;" class="camera-device" wx:if='{{isShowCamera}}'></camera> <canvas canvas-id="camera-id" style="left:{{cameraLeft}}px" class="canvas-camera" wx:if='{{isShowCamera}}' style="width:{{cameraWidth}}px;height:{{cameraHeight}}px"></canvas> //js this.data.showCanvas = wx.createCanvasContext('camera-id');//建立canvas
其中camera的主要功能是進行拍照,跟使用者互動,canvas是進行模版和最後呈像。
值得注意的是,不管是先選擇模版再拍照,還是先拍照再選模版,最終呈像均是拍的照片在底層,模版在拍的照片圖層上。
-
陳列所有的模版模版(我採用左右滑動的方式)
//wxml: <scroll-view scroll-x='true'> <view class="module"> <view wx:for='{{moduleList}}' wx:key='index' bindtap="chooseImg" data-index="{{index}}"> <view> <image src="{{item.imgDetail}}" mode="widthFix"></image> </view> </view> </view> </scroll-view>
-
選擇模版,並繪製在頁面上
程式碼如下:
this.data.showCanvas.drawImage(this.data.chooseImg, 0, 0, this.data.windowWidth, this.data.windowWidth);//chooseImg是選中的模版
this.data.showCanvas.draw()
濾鏡的選擇
濾鏡的選擇,其實跟模版選擇類似,只不過需要注意,是濾鏡的圖層是在最上面,也就是說,如果拍了照片,也選擇了模版,選擇了濾鏡,canvas圖層的繪畫過程是拍的照片-》模板-》濾鏡。
有2種方式去實現 1.在canvas上繪製圖片 2.在canvas上利用顏色的填充進行操作
- 在canvas上繪製圖片
過程跟模版的選擇邏輯一致,這裡不再過多的敘述
- 在canvas上利用顏色的填充進行操作
this.data.showCanvas.setGlobalAlpha(this.data.selectFilter.opacity);
this.data.showCanvas.setFillStyle(this.data.selectFilter.bgColor);
this.data.showCanvas.fillRect(0,0,this.data.windowWidth,this.data.windowHeight)
其中的selectFilter
是指選擇的濾鏡的透明度/背景色/需要繪製的範圍
可以上傳照片
當用戶不想拍照,直接使用本地照片時,需要支援上傳照片這個功能
使用微信小程式中api,wx.chooseImage
可以實現選擇本地照片的功能
let that = this;
wx.chooseImage({
count: 1,
sizeType: ['original', 'compressed'],
sourceType: ['album'],
success: function (res) {
},
fail: err => {
},
complete: function (err) {
}
})
引數:
-
count:表示最多可以選擇幾張照片
-
sizeType:表示所選圖片的尺寸,origin:原圖;compressed:壓縮圖
-
sourceType:表示圖片的來源,album:從相簿中選擇;camera:使用相機
從本地選擇完照片,選擇模版和濾鏡流程,跟之前流程一致,在這不做敘述。
上傳照片可以塗鴉和去除塗鴉的橡皮擦
- 塗鴉
塗鴉,其實也是一個canvas,可以調節寬度和顏色。使用者手指落筆和滑動都需要進行監聽。
程式碼如下:
//wxml:
<image src="{{chooseImg}}" mode="heightFix"></image>//選擇上傳的照片
<canvas canvas-id="showHasImage" bindtouchstart="touchStart" bindtouchmove="touchMove" style="width:{{windowWidth-1}}px;height:{{windowWidth-1}}px;"></canvas>//在圖片上傳進行繪畫的canvas
//js:
touchStart(e){
this.data.drawCanvas = wx.createCanvasContext("showHasImage");
this.data.drawCanvas.setLineWidth(this.data.lineWidth);
this.data.drawCanvas.setStrokeStyle(this.data.colorList[this.data.selectColor])
let { x, y } = e.changedTouches[0];
this.data.startX = x;
this.data.startY = y;
},
touchMove(e){
let { x, y } = e.changedTouches[0];
this.data.drawCanvas.moveTo(this.data.startX, this.data.startY);
this.data.drawCanvas.lineTo(x, y);
this.data.drawCanvas.setLineCap('round');
this.data.drawCanvas.setLineJoin('round')
this.data.startX = x;
this.data.startY = y
this.data.drawCanvas.stroke();
this.data.drawCanvas.draw(true)
},
將每次移動的位置跟之前的連線上,便會連成線,達到畫筆的效果
- 橡皮擦
原理跟塗鴉類似,這裡不做過多敘述。
上傳照片可以新增文字,文字可以改變顏色和字型大小
文字在輸入框中輸入,可以移動位置,確定完文字可以改變顏色和大小
程式碼如下:
//wxml
<input class="input" value="{{text}}" bindtouchstart="inputStart" bindtouchmove="inputMove" wx:if='{{!showText}}' bindblur="blurText" style="left:{{left}}px;top:{{top}}px;border:1px solid #000" confirm-type="done" bindconfirm="sureText"></input>
<text class="input-text" style="left:{{left}}px;top:{{top}}px" wx:if='{{showText}}'>{{text}}</text>
//js
inputStart(e) {
let { pageX, pageY } = e.changedTouches[0];
this.data.startX = pageX;
this.data.startY = pageY;
},
inputMove(e) {
let { pageX, pageY } = e.changedTouches[0];
this.setData({
left: pageX,
top: pageY
})
},
ctx.setFontSize(20);//字型大小
ctx.setFillStyle('red');//字型顏色
ctx.fillText(this.data.text, this.data.left, this.data.top);//字型的位置和內容
可以儲存至本地,且最終儲存的帶有動態的小程式碼
儲存至本地的圖片,其實重點在於儲存之前的呈像即canvas繪製的順序,正常的順序應該是拍的照片/上傳的照片->選擇的模版->選擇的濾鏡->塗鴉->小程式碼
著重說下小程式碼,需要後臺配合...
後端返回的是一串碼,我們需要進行轉換
const fsm = wx.getFileSystemManager();
const time = new Date().getTime(); //自定義檔名
const fileName = `${wx.env.USER_DATA_PATH}/${time}.png`;
fsm.writeFile({
filePath: fileName,
data: 'resCode',
encoding: 'binary',
success: res => { },
fail:err=>{}
})
其中
-
filePath:寫入的檔案路徑
-
data:是後端返回的小程式的碼
-
encoding:寫入檔案的字元編碼
最終小程式碼也是一張圖片,只要圖層不錯,就會達到你想要的效果。
關於下載至本地相簿,流程是,將canvas匯出生成圖片->下載至本地
微信小程式分別提供了api:
匯出:
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: that.data.cameraWidth,
height: that.data.cameraHeight,
destWidth: that.data.cameraWidth * 2,
destHeight: that.data.cameraHeight * 2,
quality: 1,
canvasId: canvasId,
success: res => {},
fail:err=>{}
})
其中:
-
x,y:在畫布上的橫/縱座標
-
width:畫布的寬度
-
height:畫布的高度
-
destWidth:輸出圖片的寬度
-
destHeight:輸出圖片的高度
-
canvasId:最終畫在畫布上的canvas的id
-
quality:圖片的質量,範圍是
(0,1]
儲存至本地:
wx.saveImageToPhotosAlbum({
filePath: photo,
success: res => { },
fail(err) {}
})
其中:
- filePath:圖片檔案的路徑
看看我的效果圖ba
程式碼詳見我的倉庫,歡迎