小程序開發-利用canvas實現保存二維碼海報到本機

場景及需求

在小程序開發過程中,經常需要實現保存某個頁面為帶小程序碼的二維碼海報圖片到本地,然后用于分享或者發朋友圈等操作。

主要技術點及小程序相關api

技術注意事項

  • 小程序的canvas與H5 canvas使用api大部分一致,但由于小程序中沒有DOM節點的概念,所以不能使用很多現成的工具庫
  • 小程序canvas默認寬度300px、高度225px
  • 小程序canvas相關的api中單位為px,并非rpx,所以在業務實現過程中需要處理適配
  • 小程序canvas對跨域圖片不支持,需要先將圖片緩存到本地

技術點

  • wx.getImageInfo()
  • wx.getSystemInfo()
  • wx.canvasToTempFilePath()
  • wx.saveImageToPhotosAlbum()
  • canvas渲染相關api

整體流程

1.先獲取所有圖片資源,線上圖片需要緩存到本地,使用圖片的本地路徑做渲染

2.獲取設備信息,根據設備寬度計算出寬度因子x

3.繪制canvas

4.將canvas轉化為圖片,將圖片保存到本機

實現

寬度因子x及元素寬度的尺寸計算

rpx(responsive pixel): 可以根據屏幕寬度進行自適應。規定屏幕寬為750rpx。如在 iPhone6 上,屏幕寬度為375px,共有750個物理像素,則750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。

參考文檔: 小程序-WXSS-尺寸單位

由文檔可以看出不同的設備,寬度是不同數值的px,但是均為750rpx,由此可以利用750rpx計算出寬度因子x:

設備寬度 / 750

以設計稿寬度750rpx為例,則在不同設備下,設計稿寬度y在不同設備下的px寬度均為:

Y = y * x

Y = y * (設備寬度 / 750)

由此,在實現中,canvas標簽寬高需要設置為變量,且使用微信提供的 wx.getSystemInfo() 接口獲取設備寬度信息后,進行計算

<canvas canvas-id="qrcode-canvas" :style="{width: canvas.width + 'px', height: canvas.height + 'px'}"></canvas>
復制代碼
// wx.js
// 獲取設備基本信息
export function wxGetSystemInfo () {return new Promise(async function (resolve, reject) {wx.getSystemInfo({success: function (res) {resolve(res);},fail: function (err) {reject(err);}})});
}
// demo.vue
// 獲取手機基本信息
async getPhoneSystemInfo () {let _this = this;let systemInfoRes = await wxGetSystemInfo();_this.canvas.width = systemInfoRes.screenWidth;// 設計稿寬高為 750 * 912_this.canvas.height = 912 / 750 * _this.canvas.width;_this.storageQrcode();
},
復制代碼

獲取遠程圖片緩存到本地使用

  • api
    • wx.getImageInfo()
    • 參考文檔: wx.getImageInfo()

注意:如果是本地圖片,即'static'文件夾中的圖片,如'/static/logo.png'經過wx.getImageInfo返回的path會省去開頭的'/',即'static/logo.png',這會導致拿不到資源,所以本地圖片不需要調用wx.getImageInfo()進行本地緩存

// wx.js
// 獲取圖片基本信息
export function wxGetImgInfo (imgUrl) {return new Promise(async function (resolve, reject) {wx.getImageInfo({src: imgUrl,success: function (res) {resolve(res);},fail: function (err) {reject(err);}})});
}
// demo.vue
// 緩存遠程圖片
async storageQrcode () {let _this = this;// 背景圖url轉path// let bgRes = await wxGetImgInfo(_this.bgImg);// _this.imgPath.bgImg = bgRes.path;// Logo url轉path// let logoRes = await wxGetImgInfo(_this.logo);// _this.imgPath.logo = logoRes.path;// 頭像 url轉path// let headerImgRes = await wxGetImgInfo(_this.cardDetail.header);// _this.imgPath.headerImg = headerImgRes.path;// 二維碼 url轉pathlet qrCodeRes = await wxGetImgInfo(_this.qrCode);_this.imgPath.qrCode = qrCodeRes.path;console.log(_this.imgPath);// _this.initCanvas(_this.canvas.width);
},
復制代碼

繪制canvas

canvas繪制主要用到了圖片繪制、文字繪制,圖片繪制及文字繪制的時候,需要引入上文說到的寬度因子x進行計算

圖片繪制

  • canvasContext.drawImage
    • 參考文檔: canvasContext.drawImage

這里的圖片繪制之前先計算寬度因子

  let _this = this;// variableVal即為上文拿到的設備寬度const variableNum = variableVal / 750; // 根據設備寬度算出一個rpx為多少pxconst ctx = wx.createCanvasContext('qrcode-canvas');// 清除畫布上矩形的內容ctx.clearRect(0, 0, 0, 0);// 繪制上部card背景圖const bgImgDesc = {url: _this.imgPath.bgImg,left: 0,top: 0,width: 750 * variableNum,height: 912 * variableNum};ctx.drawImage(bgImgDesc.url, bgImgDesc.left, bgImgDesc.top, bgImgDesc.width, bgImgDesc.height);ctx.draw();
復制代碼

文字的繪制

  • canvasContext.setFillStyle - 設置顏色
  • canvasContext.setFontSize - 設置大小
  • canvasContext.fillText - 填充文本
const nameDesc = {text: _this.cardDetail.name,fontSize: 36 * variableNum,color: '#4F5E6F',left: 102 * variableNum,top: 200 * variableNum
};
ctx.setFillStyle(nameDesc.color);
ctx.setFontSize(nameDesc.fontSize);
ctx.fillText(nameDesc.text, nameDesc.left, nameDesc.top);
ctx.draw();
復制代碼

canvas轉圖片并保存到本地

  • wx.canvasToTempFilePath - canvas轉圖片
    • 參考文檔: wx.canvasToTempFilePath
  • wx.saveImageToPhotosAlbum - 保存圖片到本地
    • 參考文檔: wx.saveImageToPhotosAlbum

注意點

tip: wx.canvasToTempFilePath() 在 draw 回調里調用該方法才能保證圖片導出成功。

由于導出圖片需要在canvas繪制圖片的draw()方法回調中使用才能,所以我們在繪制canvas的時候直接轉canvas為圖片,然后將路徑存下來,點擊下載的時候,再直接拿圖片路徑進行下載操作。

// wx.js
// canvas畫布轉圖片
export function wxCanvasToTempFilePath (canvasObj) {return new Promise(async function (resolve, reject) {wx.canvasToTempFilePath({x: canvasObj.x,y: canvasObj.y,width: canvasObj.width,height: canvasObj.height,destWidth: canvasObj.destWidth,destHeight: canvasObj.destHeight,canvasId: canvasObj.canvasId,fileType: canvasObj.fileType ? canvasObj.fileType : 'png',success: function (res) {resolve(res);},fail: function (err) {reject(err);}})});
}
// demo.vue
// 繪制canvas
initCanvas () {let _this = this;// 繪制canvas......ctx.draw(false, function () {_this.saveImg();});
},
// 將canvas轉為圖片
async saveImg () {let _this = this;const canvasObj = {x: 0,y: 0,width: _this.canvas.width,height: _this.canvas.height,destWidth: _this.canvas.width * 4,destHeight: _this.canvas.height * 4,canvasId: 'qrcode-canvas',fileType: 'png'};let imgRes = await wxCanvasToTempFilePath(canvasObj);_this.qrCodeImgPath = imgRes.tempFilePath;
},
復制代碼

下載圖片到本地

<canvas canvas-id="qrcode-canvas" :style="{width: canvas.width + 'px', height: canvas.height + 'px'}"></canvas>
<button type="primary" plain="true" @click="downLoadImg"> 保存二維碼 </button>
復制代碼
// wx.js
// 保存圖片到本地
export function wxSaveImageToPhotosAlbum (filePath) {return new Promise(async function (resolve, reject) {wx.saveImageToPhotosAlbum({filePath: filePath,success: function (res) {resolve(res);},fail: function (err) {reject(err);}})});
}
// demo.vue
// 保存圖片到本機
async downLoadImg () {let _this = this;let saveRes = await wxSaveImageToPhotosAlbum(_this.qrCodeImgPath);if (saveRes.errMsg === 'saveImageToPhotosAlbum:ok') {wx.showToast({duration: 3000,icon: 'none',title: '保存圖片成功!',mask: true});} else {wx.showToast({duration: 3000,icon: 'none',title: '保存圖片失敗,請重試!',mask: true});}
},
復制代碼

demo代碼已經放在 './demo' 文件夾,歡迎交流

總結

在業務實現中,我們只要把業務流程進行分割,然后一步一步去實現,捋明白流程之后各個擊破很多第一反應去查找已有的庫來實現的功能自己實現起來也很簡單。

在某種意義上,自己弄明白原理之后去實現反而更加輕松,更加得心應手。

-- LucaLJX: github:https://github.com/LucaLJX

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/253566.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/253566.shtml
英文地址,請注明出處:http://en.pswp.cn/news/253566.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Docker系統六:Docker網絡管理

Docker網絡 I. Docer的通信方式 默認情況下&#xff0c;Docker使用網橋&#xff08;brige&#xff09; NAT的通信模型. Docker啟動時會自動創建網橋Docker0&#xff0c;并配置ip 172.17.0.1/16 ifconfig docker0 docker0 Link encap:Ethernet HWaddr 02:42:e0:31:ac:10inet …

pthread_cond_wait

1. 首先pthread_cond_wait 的定義是這樣的 The pthread_cond_wait() andpthread_cond_timedwait() functions are used to block on a condition variable. They are called withmutex locked by the calling thread or undefined behaviour will result. These functions ato…

HDU 1525 Euclid's Game

題目大意&#xff1a; 題目給出了兩個正數a.b 每次操作&#xff0c;大的數減掉小的數的整數倍。一個數變為0 的時候結束。 誰先先把其中一個數減為0的獲勝。問誰可以贏。Stan是先手。 題目思路&#xff1a; 無論a,b的值為多少&#xff0c;局面&#xff1a;[a%b&#xff0c;b] 一…

SRAM BIST技術學習

MBIST 方法是目前大容量存儲器測試的主流技術&#xff0c;該技術利用芯片內部專門設計的BIST 電路進行自動化測試&#xff0c;能夠對嵌入式存儲器這種具有復雜電路結構的嵌入式模塊進行全面的測試。MBIST 電路將產生測試向量的電路模塊以及檢測測試結果的比較模塊都置于芯片的內…

【Zigbee技術入門教程-02】一圖讀懂ZStack協議棧的核心思想與工作機理

【Zigbee技術入門教程-02】一圖讀懂ZStack協議棧的核心思想與工作機理 廣東職業技術學院 歐浩源 Z-Stack協議棧是一個基于任務輪詢方式的操作系統&#xff0c;其任務調度和資源分配由操作系統抽象層OSAL管理著。 你可以理解為&#xff1a;Z-Stack協議棧 OSAL操作系統 CC25…

CMOS圖像傳感器——SmartSens

近年來CIS發展成為增量市場,國產CIS廠商也踴躍布局,給業界帶來許多驚喜。思特威(上海)電子科技股份有限公司(SmartSens)正是國產CIS中亮眼的一家廠商。數據顯示,2020年思特威安防監控市場的CIS芯片出貨量為1.46億顆,繼續位居全球出貨量TOP1的位置;同年,思特威的新興領…

Servlet第二篇【Servlet調用圖、Servlet細節、ServletConfig、ServletContext】

Servlet的調用圖 前面我們已經學過了Servlet的生命周期了&#xff0c;我們根據Servlet的生命周期畫出Servlet的調用圖加深理解 Servlet的細節 一個已經注冊的Servlet可以被多次映射 同一個Servlet可以被映射到多個URL上。 <servlet><servlet-name>Demo1</servle…

vue響應式原理

vue響應式原理 initState new Vue() > _init() > initState: function initState (vm: Component) {vm._watchers []const opts vm.$optionsif (opts.props) initProps(vm, opts.props)if (opts.methods) initMethods(vm, opts.methods)if (opts.data) {initData(vm)} …

Oracle數據庫管理與開發pdf

下載地址&#xff1a;網盤下載基本介紹編輯內容簡介Oracle是一個適合于大中型企事業的數據庫管理系統&#xff0c;在銀行、電信、移動通信、航空、保險、金融、氣象、鐵路、跨國公司和電子商務等諸多領域得到了廣泛的應用。據統計&#xff0c;在所有數據庫管理系統中&#xff0…

DVS/DVR區別

一、DVS &#xff08;Digital Video Server&#xff09;網絡視頻服務器的簡稱。DVS(網絡視頻服務器)的原理網絡視頻服務器主要實現模擬視音頻信號的IP 化。經數字化的視音頻信號MPEG-4 視頻壓縮算法和G.729/ADPCM 音頻壓縮算法進行壓縮編碼&#xff0c;然后通過IP 網將低碼率的…

自動對焦方法學習

實現自動對焦的方法有很多種,可以根據不同的工作原理,將自動對焦技術分成不同種類。 按照系統是否自帶信號發射系統,可以分為主動式與被動式兩種類型。 主動式對焦方法是由成像系統中的發射裝置發出信號,然后再由接收裝置接收從被攝景物所反射回來的反饋信號并利用通過計算…

微粒化運營:升級內容產業消費體驗(附視頻版)

那些最受歡迎的內容平臺做對了什么&#xff1f; Facebook和Google是全球互聯網廣告產業中最早開始微粒化運營的代表&#xff0c;Google的互聯網精準廣告的思路與微粒化運營是完全相同的&#xff0c;這兩家公司也因此獲得了全球超過20%的互聯網廣告的收入。 以Facebook為例&…

mycat讀寫分離

只需要讀寫分離的功能&#xff0c;分庫分表的都不需要。 涉及到的配置文件&#xff1a; 1.conf/server.xml 主要配置的是mycat的用戶名和密碼&#xff0c;mycat的用戶名和密碼和mysql的用戶名密碼是分開的&#xff0c;應用連接mycat就用這個用戶名和密碼。 <?xml version&q…

chisel快速入門(一)

一、概述 Chisel&#xff08;Constructing Hardware In a Scala Embedded Language&#xff09;是一種嵌入在高級編程語言Scala的硬件構建語言。Chisel實際上只是一些特殊的類定義&#xff0c;預定義對象的集合&#xff0c;使用Scala的用法&#xff0c;所以在寫Chisel程序時實際…

DVS/DVR常見的監控名詞

英文名詞 說明BNC 全稱Bayonet Nut Connector&#xff0c;一種用于同軸電纜的連接器DHCP 動態主機配置協議&#xff0c;用于動態地指派配置信息DNS 域名系統&#xff0c;以用戶友好的方式將名字轉換為…

導出數據生成excel

前臺&#xff1a; <asp:Button ID"btnMoney" runat"server" Text"經費使用總結表" CssClass"admin_cx marginleft" Height"25" OnClick"btnMoney_Click" /> 后臺&#xff1a; protected void btnMoney_Cli…

U盤基本處理,U盤與移動固態硬盤

一、辨別 USB2.0 和 USB3.0 1、從USB外觀上來看&#xff0c;USB2.0通常是白色或黑色&#xff0c;而USB3.0則改觀為“高大上”的藍色接口。 目前&#xff0c;部分筆記本電腦USB接口&#xff0c;已同時提供對USB2.0及USB3.0的支持&#xff0c;我們可以通過接口顏色來區別。 2、從…

UWP_小說在線閱讀器:功能要求與技術要求

注&#xff1a;2017年2月23日正式提上日程 學了WP開發也有一年了&#xff0c;也沒做過什么軟件的。17年進發UWP&#xff0c;鍛煉自己一下。做一個開源的小說閱讀器吧。 既然開發一個軟件。所以要設計一下吧。 功能要求&#xff1a; 可能要用到的技術&#xff0c;這個嗎&#xf…

chisel快速入門(二)

上一篇見此&#xff1a; chisel快速入門&#xff08;一&#xff09;_滄海一升的博客-CSDN博客簡單介紹了chisel&#xff0c;使硬件開發者能快速上手chisel。https://blog.csdn.net/qq_21842097/article/details/121415341 十、運行和測試 現在我們已經定義了模塊&#xff0c;…

【WPF】設置TextBox內容為空時的提示文字

原文:【WPF】設置TextBox內容為空時的提示文字<TextBox Width"150" Margin"5"><TextBox.Resources><VisualBrush x:Key"HintText" TileMode"None" Opacity"0.5" Stretch"None" AlignmentX"Le…