微信小程序:截圖組件welCropper,實現原理及其使用

封面

截圖

最近作項目的時候,須要作一個截圖功能。用了一個別人寫的截圖工具,發現截出的圖質量降低了,可是咱們圖片要用來作識別, 須要保證截出的圖質量不降低。並且也不支持經過拖動來調整截圖框的大小。因此這個截圖工具沒法知足需求。由於因此,就本身動手寫了一個截圖組件。git

下面介紹一下實現原理和使用方法。github

實現原理

組件wxml的層次結構圖以下:json

hierarchy.png

  • original canvas 用來繪製原圖大小的圖片,這樣能保證截圖後的質量不會降低,這個canvas是隱藏的。
  • movable-areamovable-view的容器,是官方提供的拖拽移動組件,用來移動截取框的四個角。這個組件支持多個點同時移動。
  • scale canvas用來繪製適應屏幕比例大小的圖片(aspectFit),由於一般原圖大小是超過屏幕長寬的。(一開始白線框和圖片都在這一層,但後來發現每次移動都要繪製一次圖片,這樣會形成卡頓、性能降低。因此就想到經過增長一個move canvas來專門繪製白線框來下降繪製圖片帶來的資源消耗,由於圖片是靜止的,不須要重複繪製。)
  • move canvas是根據四個movable-view的位置繪製出截圖框。

最後截圖,經過四個點的位置計算出截圖框的位置,而後放大對應原圖大小的位置,獲得在原圖中的(x, y, width, height),最後經過官方提供的canvas接口截圖。canvas

wx.canvasToTempFilePath({
  x: x,
  y: y,
  width: w,
  height: h,
  destWidth: w,
  destHeight: h,
  canvasId: 'originalCanvas',
  success: function (res) {
  }
)}

旋轉原理

設置旋轉圓點
旋轉

特色

  • 保證截圖質量不會被壓縮(也能夠選擇壓縮圖)
  • 截圖框可以經過拖拽四個角來調整選區大小

使用

假設咱們的應用文件結構以下:app

./
├── app.js
├── app.json
├── app.wxss
├── pages
│   └── index
│       ├── index.js
│       ├── index.json
│       ├── index.wxml
│       └── index.wxss
└── welCropper
    ├── welCropper.js
    ├── welCropper.wxml
    └── welCropper.wxss

調用組件時,須要傳入cropperDatacropperMovableItemscropperChangableData,由於數據和事件都是綁定在Page上的,因此要避免使用組件裏面已經被佔用的命名。
/pages/index/index.wxmlxss

<!-- 引入組件 -->
<import src="/welCropper/welCropper.wxml" />

<!-- 調用組件 -->
<template is="welCropper" data="{{data:cropperData, cropperMovableItems:cropperMovableItems, cropperChangableData:cropperChangableData}}"></template>

<!-- 用於選擇圖片,傳入cropper中 -->
<button bindtap='selectTap'>select image</button>

/pages/index/index.jside

// 獲取顯示區域長寬
const device = wx.getSystemInfoSync()
const W = device.windowWidth
const H = device.windowHeight - 50

let cropper = require('../../welCropper/welCropper.js');

console.log(device)

Page({
    data: {
    },
    onLoad: function () {
        var that = this
        // 初始化組件數據和綁定事件
        cropper.init.apply(that, [W, H]);
    },
    selectTap() {
        var that = this

        wx.chooseImage({
            count: 1, // 默認9
            sizeType: ['original', 'compressed'], // 能夠指定是原圖仍是壓縮圖,默認兩者都有
            sourceType: ['album', 'camera'], // 能夠指定來源是相冊仍是相機,默認兩者都有
            success(res) {
                const tempFilePath = res.tempFilePaths[0]
                console.log(tempFilePath)
                
                // 將選取圖片傳入cropper,並顯示cropper
                // mode=rectangle 返回圖片path
                // mode=quadrangle 返回4個點的座標,並不返回圖片。這個模式須要配合後臺使用,用於perspective correction
                let modes = ["rectangle", "quadrangle"]
                let mode = modes[0]   //rectangle, quadrangle
                that.showCropper({
                    src: tempFilePath,
                    mode: mode,
                    sizeType: ['original', 'compressed'],   //'original'(default) | 'compressed'
                    callback: (res) => {
                        if (mode == 'rectangle') {
                            console.log("crop callback:" + res)
                            wx.previewImage({
                                current: '',
                                urls: [res]
                            })
                        }
                        else {
                            wx.showModal({
                                title: '',
                                content: JSON.stringify(res),
                            })

                            console.log(res)
                        }

                        // that.hideCropper() //隱藏,我在項目裏是點擊完成就上傳,因此若是回調是上傳,那麼隱藏掉就好了,不用previewImage
                    }
                })
            }
        })
    }
})

最後引入組件的樣式
/pages/index/index.wxss工具

@import "/welCropper/welCropper.wxss";

注意

  • 由於wx.canvasToTempFilePath輸出的是.png圖片,截出來的圖有可能遠遠大於原圖(好比3通道圖變成4通道的圖)

源代碼

若是出現什麼bug、問題或者建議能夠告訴我,我會盡可能改進。

效果圖

效果動圖mode=rectangle

效果動圖mode=quadrangle

效果圖mode=rectangle

若是將movable-view顯示出來是這樣的:

顯示movable-view後

mode=quadrangle

相關文章
相關標籤/搜索