微信小程序:截圖組件welCropper,實(shí)現(xiàn)原理及其使用

封面
截圖

最近做項(xiàng)目的時(shí)候,需要做一個(gè)截圖功能。用了一個(gè)別人寫(xiě)的截圖工具,發(fā)現(xiàn)截出的圖質(zhì)量下降了,但是我們圖片要用來(lái)做識(shí)別, 需要保證截出的圖質(zhì)量不下降。而且也不支持通過(guò)拖動(dòng)來(lái)調(diào)整截圖框的大小。所以這個(gè)截圖工具無(wú)法滿足需求。因?yàn)樗裕妥约簞?dòng)手寫(xiě)了一個(gè)截圖組件。

下面介紹一下實(shí)現(xiàn)原理和使用方法。

實(shí)現(xiàn)原理

組件wxml的層次結(jié)構(gòu)圖如下:

hierarchy.png
  • original canvas 用來(lái)繪制原圖大小的圖片,這樣能保證截圖后的質(zhì)量不會(huì)下降,這個(gè)canvas是隱藏的。
  • movable-areamovable-view的容器,是官方提供的拖拽移動(dòng)組件,用來(lái)移動(dòng)截取框的四個(gè)角。這個(gè)組件支持多個(gè)點(diǎn)同時(shí)移動(dòng)。
  • scale canvas用來(lái)繪制適應(yīng)屏幕比例大小的圖片(aspectFit),因?yàn)橥ǔT瓐D大小是超過(guò)屏幕長(zhǎng)寬的。(一開(kāi)始白線框和圖片都在這一層,但后來(lái)發(fā)現(xiàn)每次移動(dòng)都要繪制一次圖片,這樣會(huì)造成卡頓、性能下降。所以就想到通過(guò)增加一個(gè)move canvas來(lái)專門(mén)繪制白線框來(lái)降低繪制圖片帶來(lái)的資源消耗,因?yàn)閳D片是靜止的,不需要重復(fù)繪制。)
  • move canvas是根據(jù)四個(gè)movable-view的位置繪制出截圖框。

最后截圖,通過(guò)四個(gè)點(diǎn)的位置計(jì)算出截圖框的位置,然后放大對(duì)應(yīng)原圖大小的位置,得到在原圖中的(x, y, width, height),最后通過(guò)官方提供的canvas接口截圖。

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

旋轉(zhuǎn)原理

設(shè)置旋轉(zhuǎn)圓點(diǎn)

旋轉(zhuǎn)

特點(diǎn)

  • 保證截圖質(zhì)量不會(huì)被壓縮(也可以選擇壓縮圖)
  • 截圖框能夠通過(guò)拖拽四個(gè)角來(lái)調(diào)整選區(qū)大小

使用

假設(shè)我們的應(yīng)用文件結(jié)構(gòu)如下:


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

調(diào)用組件時(shí),需要傳入cropperDatacropperMovableItemscropperChangableData,因?yàn)閿?shù)據(jù)和事件都是綁定在Page上的,所以要避免使用組件里面已經(jīng)被占用的命名。
/pages/index/index.wxml

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

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

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

/pages/index/index.js

// 獲取顯示區(qū)域長(zhǎng)寬
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
        // 初始化組件數(shù)據(jù)和綁定事件
        cropper.init.apply(that, [W, H]);
    },
    selectTap() {
        var that = this

        wx.chooseImage({
            count: 1, // 默認(rèn)9
            sizeType: ['original', 'compressed'], // 可以指定是原圖還是壓縮圖,默認(rèn)二者都有
            sourceType: ['album', 'camera'], // 可以指定來(lái)源是相冊(cè)還是相機(jī),默認(rèn)二者都有
            success(res) {
                const tempFilePath = res.tempFilePaths[0]
                console.log(tempFilePath)
                
                // 將選取圖片傳入cropper,并顯示cropper
                // mode=rectangle 返回圖片path
                // mode=quadrangle 返回4個(gè)點(diǎn)的坐標(biāo),并不返回圖片。這個(gè)模式需要配合后臺(tái)使用,用于perspective correction
                // maxLength=1000 默認(rèn)2000,允許最大長(zhǎng)寬,避免分辨率過(guò)大導(dǎo)致崩潰
                let modes = ["rectangle", "quadrangle"]
                let mode = modes[0]   //rectangle, quadrangle
                that.showCropper({
                    src: tempFilePath,
                    mode: mode,
                    sizeType: ['original', 'compressed'],   //'original'(default) | 'compressed'
                    maxLength: 1000,
                    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() //隱藏,我在項(xiàng)目里是點(diǎn)擊完成就上傳,所以如果回調(diào)是上傳,那么隱藏掉就行了,不用previewImage
                    }
                })
            }
        })
    }
})

最后引入組件的樣式
/pages/index/index.wxss

@import "/welCropper/welCropper.wxss";

注意

  • 因?yàn)?code>wx.canvasToTempFilePath輸出的是.png圖片,截出來(lái)的圖有可能遠(yuǎn)遠(yuǎn)大于原圖(比如3通道圖變成4通道的圖)

源代碼

如果出現(xiàn)什么bug、問(wèn)題或者建議可以告訴我,我會(huì)盡量改進(jìn)。

效果圖

效果動(dòng)圖mode=rectangle
效果動(dòng)圖mode=quadrangle
效果圖mode=rectangle

如果將movable-view顯示出來(lái)是這樣的:

顯示movable-view后
mode=quadrangle
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,732評(píng)論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,214評(píng)論 3 426
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 177,781評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,588評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,315評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,699評(píng)論 1 327
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,698評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,882評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,441評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,189評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,388評(píng)論 1 372
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,933評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,613評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,023評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,310評(píng)論 1 293
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,112評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,334評(píng)論 2 377

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,706評(píng)論 25 708
  • ¥開(kāi)啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開(kāi)一個(gè)線程,因...
    小菜c閱讀 6,489評(píng)論 0 17
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,162評(píng)論 4 61
  • 1996年,這是我出生的年份。 有時(shí)候我真的很想知道,到底是性格決定命運(yùn)?還是命由天定? 小時(shí)候的我很皮,用現(xiàn)在的...
    看窗外的雨閱讀 282評(píng)論 0 0
  • 南海,南海 南海屬中秦漢始, 自古一詞可根溯。 東西中南眾沙島, U 型線內(nèi)口袋藏。 事實(shí)早立世界公, 卻生波瀾強(qiáng)...
    南溪向南北歌流海閱讀 267評(píng)論 0 1