1. 程式人生 > 實用技巧 >你想要的拍照,看這裡....

你想要的拍照,看這裡....

需求

市面上很多美顏相機,想用小程式現有的API,寫一個好用的美顏相機功能。

功能點包含如下:

  1. 簡單的相機功能,包含(前置/後置,閃光燈)

  2. 模版的選擇

  3. 濾鏡的選擇

  4. 可以上傳照片

  5. 上傳照片可以塗鴉和去除塗鴉的橡皮擦

  6. 上傳照片可以新增文字,文字可以改變顏色和字型大小

  7. 可以儲存至本地,且最終儲存的帶有動態的小程式碼

實現需求

簡單的相機功能,包含(前置/後置,閃光燈)

要實現相機的功能,需要使用微信小程式自帶的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

程式碼詳見我的倉庫,歡迎