小程序分享朋友圈目前的做法一般都是保存一個帶有小程序二維碼的海報到本地,網上也有不少相關文章,但是別人的不如自己的,這里記錄一下自己生成海報保存到本地的方法。
本來一開始打算使用離屏 canvas 的,結果搞了半天發現小程序的離屏 canvas 和 通過 canvas 標簽獲取的有很多不同,簡直就是大坑,最后使用了 canvas 標簽,然后定位到很遠的地方就行。
二維碼設計的圓形,實現也很簡單,畫一個圓到二維碼的位置,然后 clip 一下,再畫二維碼就行。
<Canvas
className={styles.shareCanvas}
canvasId="share"
id="share"
style={{ width: w, height: h }}
></Canvas>
// 分享海報長度坐標等定義
// 海報的寬高
const w = 750;
const h = 1232;
// 二維碼的邊長
const qrCodeSide = 234;
// 二維碼圓心位置
const qrCenter = {
x: 381,
y: 962
};
// base64 圖片保存本地並獲取 url
const base64src = function (base64data: string): Promise<string> {
return new Promise((resolve, reject) => {
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || [];
if (!format) {
reject(new Error('ERROR_BASE64SRC_PARSE'));
}
const filePath: string = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`;
const buffer = wx.base64ToArrayBuffer(bodyData);
fsm.writeFile({
filePath,
data: buffer,
encoding: 'binary',
success() {
resolve(filePath);
},
fail() {
reject(new Error('ERROR_BASE64SRC_WRITE'));
}
});
});
};
// 保存圖片,使用 canvas 繪制
const saveImg = async () => {
// 創建canvas對象
const cxt = Taro.createCanvasContext('share');
// 繪制背景
cxt.drawImage(posterImg, 0, 0, w, h);
// 繪制圓形
cxt.arc(qrCenter.x, qrCenter.y, qrCodeSide / 2, 0, 2 * Math.PI);
// 設置裁剪,下面繪制二維碼就會裁剪在圓形上
cxt.clip();
// 繪制二維碼
cxt.drawImage(qrCode, 264, 845, qrCodeSide, qrCodeSide);
cxt.draw();
// 延遲執行才能繪制成功
setTimeout(() => {
Taro.canvasToTempFilePath({
x: 0,
y: 0,
width: w,
canvasId: 'share',
fileType: 'jpg',
success(res) {
setTimeout(() => {
Taro.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success() {
showToast('已保存到本地相冊');
}
});
}, 300);
}
});
}, 300);
};
注意事項:
- 二維碼是 base64 字符串,則需要使用 base64src 函數保存到本地后得到 url,因為 drawImage 不能繪制 base64。(開發者工具上可以,真機上不行。)
- 使用 ctx.drawImage 不能直接使用網絡圖片,需要使用 getImageInfo 獲取圖片信息。網絡圖片需先配置download域名才能生效。:
// getImageInfo 會加載網絡圖片保存到本地緩存中
Taro.getImageInfo({
src: url, // 圖片線上地址
success(res) {
// 創建canvas對象
const cxt = Taro.createCanvasContext('share');
// 使用 res.path 獲取本地路徑
cxt.drawImage(res.path, 0, 0, w, h);
}
}
