热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

小程序canvas绘图并保存到系统相册

开始实现之前先上个效果图tips网络图片需先配置download域名,可通过wx.getImageInfo转为临时路径;个人习惯问题,我习

开始实现之前先上个效果图

tips

  1. 网络图片需先配置download域名,可通过wx.getImageInfo转为临时路径;
  2. 个人习惯问题,我习惯使用async-await语法,所以需要引入regenerator这个库,使用方式可网上查。

一、封装通用微信api返回为Promise对象

/datas/common.js

// 封装获取微信图片信息。
export const getWxImageInfo = (imgPath) => {return new Promise((resolve, reject) => {wx.getImageInfo({src: imgPath,success: res => {resolve(res)},fail: res => {reject(res)}})})
}// 封装获取节点选择器信息
export const getSelectQurey = (queryStr) => {return new Promise(resolve => {var query = wx.createSelectorQuery();query.select(queryStr).boundingClientRect();query.exec(res => {resolve(res)})})
}// 封装把画布导出生成指定大小的图片
export const canvasToTempFilePath = (width, height, canvasId, fileType = 'jpg') => {return new Promise((resolve, reject) => {wx.canvasToTempFilePath({width,height,canvasId,fileType,success: res => {resolve(res)},fail: res => {reject(res)}})})
}// 封装保存图片到系统相册
export const saveImageToPhotosAlbum = (filePath) => {return new Promise((resolve, reject) => {wx.saveImageToPhotosAlbum({filePath,success: res => {resolve(res)},fail: res => {reject(res)}})})
}

二、视图的实现

.wxml


"icon-download" catchtap="getCanvas">点击生成图片
'shade' wx:if="{{isShowCanvas}}">'qr-code'>'qr-canvas' canvas-id="qrCanvas" id="qrCanvas">'qr-btn'>'qr-btn-save' catchtap='saveImageToPhotosAlbumFunc'>保存图片,分享到朋友圈'qr-btn-cancel' catchtap='hideCanvas'>取消

.wxss

/* 查看大图 */.shade {width: 100%;height: 100%;background-color: rgba(240, 235, 235, 0.5);position: fixed;z-index: 100;top: 0;left: 0;
}.qr-code {width: 600rpx;height: 1000rpx;background-color: #fff;position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%); /* margin: 30rpx auto; */
}.qr-canvas {display: block;background-color: #fff;margin: 0 auto;width: 600rpx;height: 900rpx;
}.qr-btn {width: 600rpx;height: 100rpx;line-height: 100rpx;margin: 0 auto;font-size: 28rpx;color: #fff;display: flex;background-color: #658dc5;
}.qr-btn-save {flex: 0 0 500rpx;text-align: center;border-right: 1rpx solid #fff;
}.qr-btn-cancel {text-align: center;flex: 0 0 100rpx;
}

三、创建canvas并保存到系统相册

tips

  1. 商品图是正方形的,所以这里商品图的宽高都用canvas的宽
  2. 文字不能换行,这里只是简单的处理了一下
  3. 注意: wx.canvasToTempFilePath(Object object, Object this) 这个的使用,文档有一句话需要注意的:“把当前画布指定区域的内容导出生成指定大小的图片。在 draw() 回调里调用该方法才能保证图片导出成功。”

const app = getApp()
const regeneratorRuntime = app.globalData.regeneratorRuntimeconst
const util = require('../../utils/util.js')
import {getSelectQurey,getWxImageInfo,canvasToTempFilePath,saveImageToPhotosAlbum
} from &#39;../../datas/common.js&#39;Page({data: {isShowCanvas: false, // 是否显示canvas wxaCode: &#39;https://xxx..jpg&#39;, // 商品小程序码goodsImageUrl: &#39;https://xxx..jpg&#39;, // 商品图片 canvasTempFilePath: &#39;&#39;, // canvas导出生成图片的临时路径 },// 点击显示要生成的canvas getCanvas(e) {if (!this.data.wxaCode) {util.showToast(&#39;二维码生成失败&#39;);return;}this.setData({isShowCanvas: true}, () &#61;> {this.createCanvas();})},// 隐藏canvas hideCanvas() {this.setData({isShowCanvas: false})},// 创建canvas async createCanvas() {wx.showLoading({title: &#39;图片生成中...&#39;})const _this &#61; this// 创建节点选择器 const res &#61; await getSelectQurey(&#39;#qrCanvas&#39;);// canvas的宽高 const cvWidth &#61; res[0].width;const cvHeight &#61; res[0].height;const cvSubValue &#61; cvHeight - cvWidthconst qrWidth &#61; cvSubValue / 1.5const qrMargin &#61; (cvSubValue - qrWidth) / 2const qrX &#61; cvWidth - qrWidth - qrMargin / 2const qrY &#61; cvWidth &#43; qrMarginconst shopNameY &#61; cvWidth &#43; cvSubValue - qrWidth// 二维码网络图片转临时路径 let qrImagePath &#61; &#39;&#39;;try {const wxaCode &#61; _this.data.wxaCode;const qrImage &#61; await getWxImageInfo(wxaCode);qrImagePath &#61; qrImage.path} catch (e) {wx.hideLoading();this.hideCanvas();util.showToast(&#39;二维码生成失败&#39;);return;}// 商品网络图片转临时路径 let goodsImagePath &#61; &#39;/images/default_goods.png&#39;;const goodsImage &#61; _this.data.goodsImageUrl;if (goodsImage) {const goodsImageRes &#61; await getWxImageInfo(goodsImage);goodsImagePath &#61; goodsImageRes.path;}// 创建canvas var ctx &#61; wx.createCanvasContext(&#39;qrCanvas&#39;, _this);// 设置背景 ctx.setFillStyle(&#39;#fff&#39;);ctx.fillRect(0, 0, cvWidth, cvHeight);// 设置商品图片 商品图宽高是一样的 ctx.drawImage(goodsImagePath, 0, 0, cvWidth, cvWidth);// 设置二维码图片 ctx.drawImage(qrImagePath, qrX, qrY, qrWidth, qrWidth);// 设置店铺名称 const shopName &#61; &#39;我是店铺名称&#39;;ctx.setFillStyle(&#39;black&#39;)ctx.setFontSize(16)ctx.setTextAlign(&#39;left&#39;)ctx.fillText(shopName, 10, shopNameY, cvWidth - qrWidth);// 设置商品名称 文字不能换行&#xff0c;这里只是简单的处理了一下 const goodsName &#61; &#39;一个名字很长很长的商品就问你怕不怕&#39;;let goodsName1 &#61; &#39;&#39;;let goodsName2 &#61; &#39;&#39;;ctx.setFillStyle(&#39;black&#39;)ctx.setFontSize(14)ctx.setTextAlign(&#39;left&#39;)if (goodsName.length <&#61; 10) {ctx.fillText(goodsName, 10, shopNameY &#43; 30, cvWidth - qrWidth);} elseif (goodsName.length > 10 && goodsName.length <&#61; 22) {goodsName1 &#61; goodsName.substring(0, 10);goodsName2 &#61; goodsName.substring(10);ctx.fillText(goodsName1, 10, shopNameY &#43; 30, cvWidth - qrWidth);ctx.fillText(goodsName2, 10, shopNameY &#43; 50, cvWidth - qrWidth);} else {goodsName1 &#61; goodsName.substring(0, 10);goodsName2 &#61; goodsName.substring(10, 22) &#43; &#39;...&#39;;ctx.fillText(goodsName1, 10, shopNameY &#43; 30, cvWidth - qrWidth);ctx.fillText(goodsName2, 10, shopNameY &#43; 50, cvWidth - qrWidth);}// 设置提示 const tipText &#61; &#39;长按识别小程序&#xff0c;马上下单&#xff01;&#39;;ctx.setFillStyle(&#39;gray&#39;)ctx.setFontSize(8)ctx.setTextAlign(&#39;center&#39;)ctx.fillText(tipText, cvWidth / 2, cvHeight - 10);// 完成 ctx.draw(false, () &#61;> {wx.hideLoading();_this.canvasToTempFilePathFunc(cvWidth, cvHeight, &#39;qrCanvas&#39;)});},// 把当前画布指定区域的内容导出生成指定大小的图片 async canvasToTempFilePathFunc(cvWidth, cvHeight, qrCanvas) {try {let res &#61; await canvasToTempFilePath(cvWidth, cvHeight, qrCanvas);this.setData({canvasTempFilePath: res.tempFilePath});} catch (error) {console.log(error);util.showToast(error.errMsg);}},// 保存图片到本地 async saveImageToPhotosAlbumFunc() {try {let res &#61; await saveImageToPhotosAlbum(this.data.canvasTempFilePath);console.log(res);this.hideCanvas();util.showToast(&#39;图片保存成功&#39;);} catch (err) {console.log(err);}}
})

写得比较简单&#xff0c;因为主要是方便自己做记录的&#xff0c;所以也没有考虑到过多的使用场景。


转:https://juejin.im/post/5d0ae2715188251ac11f70c1



推荐阅读
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 云函数与数据库API实现增删查改的对比
    本文将深入探讨使用云函数和数据库API实现数据操作(增删查改)的不同方法,通过详细的代码示例帮助读者更好地理解和掌握这些技术。文章不仅提供代码实现,还解释了每种方法的特点和适用场景。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 我有一个SpringRestController,它处理API调用的版本1。继承在SpringRestControllerpackagerest.v1;RestCon ... [详细]
  • 本文详细介绍了Grand Central Dispatch (GCD) 的核心概念和使用方法,探讨了任务队列、同步与异步执行以及常见的死锁问题。通过具体示例和代码片段,帮助开发者更好地理解和应用GCD进行多线程开发。 ... [详细]
  • 本文将详细介绍多个流行的 Android 视频处理开源框架,包括 ijkplayer、FFmpeg、Vitamio、ExoPlayer 等。每个框架都有其独特的优势和应用场景,帮助开发者更高效地进行视频处理和播放。 ... [详细]
  • 深入解析SpringMVC核心组件:DispatcherServlet的工作原理
    本文详细探讨了SpringMVC的核心组件——DispatcherServlet的运作机制,旨在帮助有一定Java和Spring基础的开发人员理解HTTP请求是如何被映射到Controller并执行的。文章将解答以下问题:1. HTTP请求如何映射到Controller;2. Controller是如何被执行的。 ... [详细]
  • 探讨 HDU 1536 题目,即 S-Nim 游戏的博弈策略。通过 SG 函数分析游戏胜负的关键,并介绍如何编程实现解决方案。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 本文介绍了如何在 C# 和 XNA 框架中实现一个自定义的 3x3 矩阵类(MMatrix33),旨在深入理解矩阵运算及其应用场景。该类参考了 AS3 Starling 和其他相关资源,以确保算法的准确性和高效性。 ... [详细]
  • 在尝试使用C# Windows Forms客户端通过SignalR连接到ASP.NET服务器时,遇到了内部服务器错误(500)。本文将详细探讨问题的原因及解决方案。 ... [详细]
  • yikesnews第11期:微软Office两个0day和一个提权0day
    点击阅读原文可点击链接根据法国大选被黑客干扰,发送了带漏洞的文档Trumps_Attack_on_Syria_English.docx而此漏洞与ESET&FireEy ... [详细]
  • ElasticSearch 集群监控与优化
    本文详细介绍了如何有效地监控 ElasticSearch 集群,涵盖了关键性能指标、集群健康状况、统计信息以及内存和垃圾回收的监控方法。 ... [详细]
  • 为了解决不同服务器间共享图片的需求,我们最初考虑建立一个FTP图片服务器。然而,考虑到项目是一个简单的CMS系统,为了简化流程,团队决定探索七牛云存储的解决方案。本文将详细介绍使用七牛云存储的过程和心得。 ... [详细]
  • ssm框架整合及工程分层1.先创建一个新的project1.1配置pom.xml ... [详细]
author-avatar
天若无雨666
这个菇凉很宅,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有