1. 程式人生 > >小程式圖片裁剪功能簡易版,分享前裁剪

小程式圖片裁剪功能簡易版,分享前裁剪

該檔案主要執行分享前的裁剪
微信後臺的download安全域名別忘記設定,否則上線後不能剪下
小程式內是圖片是HTTP的要想辦法換成https

一.介紹使用

1.基本使用

以商品詳情為例:

<template>
  <view class="container">
    <!-- n個佈局 -->
    <view wx:if="{{cutData.imageInfor}}">
      <canvas style="width:{{cutData.imageInfor.width}}px;height:
{{cutData.imageInfor.height}}px;display:{{cutData.showCanvas ? 'block':'none'}};" canvas-id="cropper"></canvas> <!-- 為了看裁剪效果,實際可以沒有此元素 --> <!-- <image src="{{cutData.savedFilePath}}"></image> --> </view> </view> </template> <script>
import cut from '../../utils/cut'; export default class ProductDetail extends wepy.page { // 分享事件,暫時沒有做回撥事件 onShareAppMessage() { let info = wx.getStorageSync(USER_INFO); return { title: this.product.baseInfo.name, imageUrl: this.cutData.savedFilePath, path: "/pages/mine/white_page?pid="
+ this.product.baseInfo.productId + "&source=" + info.userId, success: function(res) { // 轉發成功 console.log('轉發成功'); }, fail: function(res) { // 轉發失敗 console.log('轉發失敗'); } }; } config = { navigationBarTitleText: "商品詳情" }; data = { product: {}, cutData:{ // 分享剪下處理 imageInfor:null, savedFilePath:'', showCanvas:true, // 初始顯示canvas,若初始不顯示canvas會裁剪報錯 } }; methods = { // 分享事件,顯示分享按鈕 handleShare() { console.log(1111); wx.showShareMenu({ withShareTicket: true }); }, }; // 頁面載入事件 onLoad(option) { // 前面n個操作 this.getData(); } async getData(pid , shop) { // 前面n個操作 let res = await getProductDetail(params); if (res.data.code == 200) { this.product = res.data.data; this.isError = false; // 執行裁剪 this._myCut(); } else if(res.data.code == 500) { // ... } else { this.isError = true; } this.$apply(); } // 參見方法,每次onload都執行 _myCut() { if (!this.product.headPics) { return ; } cut.cut(this.product.headPics[0].imgUrl,'cropper' ,imageInfor => { // 得到待分享圖片的資訊 this.cutData.imageInfor = imageInfor; this.$apply(); } ,savedFilePath => { // 獲取儲存到本地的圖片資訊 this.cutData.savedFilePath = savedFilePath; // 將canvas隱藏,不影響頁面佈局 this.cutData.showCanvas = false; this.$apply(); // 清除本地儲存的檔案列表,但是不包含本次生成的檔案 cut.clearSavedFileList(this.cutData.savedFilePath); } ); }; }
</script> <style lang="less"></style>

2.注意

  • 在_myCut函式中,得到本地儲存路徑後的回撥內應將canvas隱藏,防止被使用者看到
  • 放canvas的view應該放在頁面最底部,防止初始出現的時候被使用者看到
  • 在得到本地儲存路徑後的回撥內應將微信內儲存的其他savedFileList刪除,這裡如果自己存放了其他資源,可以選擇修改cut.js的clearSavedFileList方法.
  • 之所以不在onShareAppMessage方法內之間裁剪(也就是使用者點選了分享或者轉發才裁剪),是因為onShareAppMessage方法要求返回一個物件,cut.js採用回撥實現,cut中的cut方法中回撥的值不能被onShareAppMessage拿到,所以放在了getData方法中

二.介紹實現

1.實現

cut.js

export default {

  // 裁剪方法
  cut(url,canvasId,imageInforCB,savedFilePathCB) {
    let that = this;
    const ctx = wx.createCanvasContext('cropper');
    that._getImageInfor(url,ctx,canvasId,imageInforCB,savedFilePathCB);
  },

  // 刪除本地儲存資料
  clearSavedFileList(currSavedFilePath) {
    wx.getSavedFileList({
      success: function(res) {
        for (let i=0;i<res.fileList.length;i++) {
          if (currSavedFilePath !== res.fileList[i].filePath) {
            wx.removeSavedFile({
              filePath: res.fileList[i].filePath,
              complete: function(res) {
                console.log('本地圖片刪除結束',res);
              }
            });
          }
        }
      }
    });
  },

  // 獲取圖片資訊
  _getImageInfor(url,ctx,canvasId,imageInforCB,savedFilePathCB) {
    let that = this;
    wx.getImageInfo({
      src: url,
      success: function (imageInfor) {
        console.log('getImageInfo2',imageInfor);
        imageInforCB(imageInfor);
        // 將圖畫到canvas上
        that._drawImage(ctx,imageInfor,()=>{
          that._getTempFilePath(canvasId,imageInfor,savedFilePathCB);
        });
      },
      fail: function(res) {
        console.log('getImageInfo fail',res);
      },
      complete:function(res) {
        console.log('getImageInfo complete',res);
      }
    });
  },

  // 在canvas上畫圖
  _drawImage(ctx,imageInfor,cb) {
    ctx.drawImage(imageInfor.path,0,0,imageInfor.width,imageInfor.height);
    ctx.draw(false,()=>{
      console.log('繪製完成');
      cb();
    });
  },

  // 使用canvas剪裁,後獲取臨時本地路徑,
  _getTempFilePath(canvasId,imageInfor,savedFilePathCB) {
    let that = this;
    let cutData = that._computedCutData(imageInfor);
    console.log('cutData',cutData);
    wx.canvasToTempFilePath({
      x: cutData.x,
      y: cutData.y,
      width: imageInfor.width,
      height: imageInfor.height,
      destWidth: cutData.destWidth,
      destHeight: cutData.destHeight,
      canvasId: canvasId,
      success: function(res) {
        console.log('canvasToTempFilePath res',res);
        that._saveImage(res.tempFilePath,savedFilePathCB);
      },
      fail: function(res) {
        console.log('canvasToTempFilePath fail',res);
      },
      complete:function(res) {
        console.log('canvasToTempFilePath complete',res);
      }
    });
  },

  // 將_getTempFilePath得到的臨時路徑儲存到本地
  _saveImage(tempFilePath,savedFilePathCB) {
    wx.saveFile({
      tempFilePath: tempFilePath,
      success: function (res) {
        let savedFilePath = res.savedFilePath;
        console.log('savedFilePath',res);
        savedFilePathCB(savedFilePath);
      },
      fail:function() {
        console.log('saveFile,fail');
      },
      complete:function() {
        console.log('saveFile,complete');
      }
    });
  },

  // 計算裁剪資料,目前由長寬1:1裁成長寬比5:4的圖片,裁剪公式 (h-(w/5*4))/2
  _computedCutData(imageInfor) {
    let cutData = {
      x:0,          // canvas剪下左上角x座標
      y:0,          // canvas剪下左上角y座標
      destWidth:0,  // 圖片裁剪寬度 
      destHeight:0  // 圖片裁剪高度
    };
    let cutY = (imageInfor.height-(imageInfor.width/5*4))/2;
    cutData.y = cutY;
    cutData.x = 0;
    cutData.destWidth = imageInfor.width;
    cutData.destHeight = imageInfor.height - cutY*2;
    return cutData;
  }
}

2.注意

1.剪裁前要講圖片畫到canvas上,因為呼叫了canvas的canvasToTempFilePath方法
2.注意cut.js中clearSavedFileList方法是清除除了本次生成的圖片之外的所有微信小程式savedFileList,如不希望,可以修改此方法
3._computedCutData是計算裁剪資料,圖片將按照得到的結果裁剪,
4.本cut.js的_computedCutData裁剪尺寸是圖片寬度不變,高度上下各裁剪掉寬度的十分之一
5.wx.canvasToTempFilePath方法要在draw的回撥函式中執行才會正確得到結果
5.canvas的display:none;會觸發wx.canvasToTempFilePath失敗,因此應該首先canvas的display:block,當本地儲存路徑得到後再display:none即可

三.補充(2018/5/25)

上線之後發現圖片剪裁出現問題,當圖片寬高都超出2000的時候,不知道為何,小程式閃退,所以這裡做了修改,添加了如下方法:

此方法在_getImageInfor方法中呼叫,保證圖片在1000以下

// 重新設定圖片寬高比例,因為小程式一裁剪寬高2000左右的就閃退,這裡限制到1000以下
  _resetImageSize(imageInfor) {
    let result = imageInfor;
    while(result.width > 1000 && result.height > 1000) {
      result.width = result.width / 2;
      result.height = result.height / 2;
    }
    return result;
  }