一、制作正常显示海报,生成二倍海报隐藏 代码如下
<!--index.wxml--> <view class="container"> <view class="show"> <image src="{{cardPath}}" alt="" class="card"></image> <text class="name">{{sendName}}</text> <image src="{{headPath}}" class="header"></image> </view> <view class="btn" bindtap="saveImage">保存图片</view> <view class="canvasBox" style="width:0;height:0;overflow: hidden;opacity:0;position:absolute;left:-750px;top:0;"> <canvas canvas-id=\'myCanvas\' style=\'width:750px;height:1000px;\'></canvas> </view> </view>
/*css*/ .btn { width: 300rpx; height: 90rpx; line-height: 90rpx; text-align: center; color: #fff; font-size: 38rpx; border-radius: 10rpx; background: #f9c22e; } /* */ .show{ width:750rpx; height:1000rpx; background: #fff; border:1px solid red; position: relative; } .show .card{ display: block; width:690rpx; height: 940rpx; margin:20rpx auto 0; } .show .name,.show .header{ position: absolute; } .show .name{ width:100%; text-align: center; color:red; top:26rpx; } .show .header{ width:100rpx; height: 100rpx; border-radius: 100%; top:500rpx; left:100rpx; }
二、canvas 画二倍图 文字居中 实际展示正常海报为375*470 绘制中生成图模糊(文字有锯齿边,图片模糊)。绘制过程中绘制二倍图大小750*940 并保存,则能解决该问题
let x = ctx.width / 2;//canvas宽的一半
//画图 drawCanvas: function () { let that = this; let ctx = wx.createCanvasContext(\'myCanvas\'); let ctxW = 750; let ctxH = 1000; ctx.width = 750; ctx.height = 1000; let x = ctx.width / 2; // 垂直渐变 const grd = ctx.createLinearGradient(0, 0, 0, ctxH); grd.addColorStop(0, \'#ffffff\'); grd.addColorStop(1, \'#ffffff\'); ctx.setFillStyle(grd); ctx.fillRect(0, 0, ctxW, ctxH); wx.getImageInfo({ src: that.data.cardPath, success: (res) => { ctx.drawImage(res.path, 0, 0, 750, 1000); //card ctx.setFontSize(32) //字体大小 ctx.setFillStyle(\'red\') //字体颜色 ctx.textAlign = "center"; //文字居中 ctx.fillText(that.data.sendName, x, 34) ctx.stroke(); wx.getImageInfo({ src: that.data.headPath, success: (res) => { ctx.save(); ctx.beginPath(); //开始绘制 ctx.arc(150,358,50, 0, 2 * Math.PI) ctx.fill() ctx.clip(); //剪切 ctx.drawImage(res.path,100, 308, 100, 100); //userHeader // 推进去图片必须是https ctx.restore(); //恢复之前保存的绘图上下文 继续绘制 /**/ ctx.save(); ctx.draw(); } }) } }) },
三、下载保存图片
// 保存图片 saveImage: function (e) { wx.canvasToTempFilePath({ x: 0, //指定的画布区域的左上角横坐标 y: 0, //指定的画布区域的左上角纵坐标 width: 750, //指定的画布区域的宽度 height: 940, //指定的画布区域的高度 destWidth: 750, //输出的图片的宽度 destHeight: 940, //输出的图片的高度 canvasId: \'myCanvas\', fileType: \'jpg\', //图片的质量,目前仅对 jpg 有效。取值范围为 (0, 1],不在范围内时当作 1.0 处理。 quality: 1, success: function (res) { wx.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success(result) { wx.showToast({ title: \'图片保存成功\', icon: \'success\', duration: 2000 }) } }) } }) },
结果对比:左图文字明显有锯齿,右图没有,用户头像右图更清晰。保存下来看效果更明显。
tips:该文档解决两个问题
(1)文字居中显示
(2)生成图模糊
(3)圆形头像绘制,另一篇文档实际上线项目中手机端头像保存为空,此版本优化。
(4)页面加载完成绘制图形,实际项目中页面加载完成但接口数据不一定返回,所以绘图过程需在接口数据成功返回中调用,避免用户头像为空,绘图为空
(5)优化上一版本大量无用代码,全程使用线上数据代码
(6)canva绘制海报时可添加透明背景。
// 垂直渐变 const grd = ctx.createLinearGradient(0, 0, 0, ctxH); grd.addColorStop(0, \'transparent\'); grd.addColorStop(1, \'transparent\'); ctx.setFillStyle(grd);
(7)手机端保存图片 当用户拒绝保存申请时下次点击按钮无法自动调用新的授权申请,点击按钮无反应
此问题已解决网上有各种教程解决方法,当前随笔未更新,只记录图片模糊问题,下个随笔增加拒绝授权至重新授权过程
-------- 注意:鉴于有网友反映该功能无效,声明更新下记录,以下附上全部代码,请测试使用
tap1:该项目为18年开发,请选择低版本库,基础库版本太高会导致报错原因未知,但是报错不影响图片的保存;有知道原因的的兄弟姐妹可以留言回复,谢谢。
若出现以下错误请回调基础库(注该报错依然能保存图片)
tap2:(1)测试1:图片为百度域名下,因此需要忽略域名校验;开发工具可以保存,手机端保存空白。
(2)测试2:使用公司域名且小程序后台已配置dowload合法域名则不需要忽略域名校验(手机端测试需使用合法域名才能进行图片的保存)
tap3:此前百度地址图片没有了,打开为空,找不到图片导致保存为空
完整代码:
<!--index.wxml--> <view class="container"> <view class="show"> <image src="{{cardPath}}" alt="" class="card"></image> <text class="name">{{sendName}}</text> <image src="{{headPath}}" class="header"></image> </view> <view class="btn" bindtap="saveImage">保存图片</view> <view class="canvasBox"> <view class="canvasBox" style="width:0;height:0;overflow: hidden;opacity:0;position:absolute;left:-750px;top:0;"> <canvas canvas-id=\'myCanvas\' style=\'width:750px;height:1000px;\'></canvas> </view> </view> </view>
/*css*/ .btn { width: 300rpx; height: 90rpx; line-height: 90rpx; text-align: center; color: #fff; font-size: 38rpx; border-radius: 10rpx; background: #f9c22e; } /* */ .show { width: 750rpx; height: 1000rpx; background: #fff; border: 1px solid red; position: relative; } .show .card { display: block; width: 690rpx; height: 940rpx; margin: 20rpx auto 0; } .show .name, .show .header { position: absolute; } .show .name { width: 100%; text-align: center; color: red; top: 26rpx; } .show .header { width: 100rpx; height: 100rpx; border-radius: 100%; top: 100rpx; left: 100rpx; }
//index.js const app = getApp() Page({ data: { cardPath: \'https://www.cnblogs.com/skins/mountainink/images/top.jpg\', headPath: \'https://www.cnblogs.com/skins/mountainink/images/top.jpg\', sendName: \'姓名姓名姓名\' }, onLoad: function (options) { var that = this; that.drawCanvas(); }, /*画图*/ drawCanvas: function () { let that = this; let ctx = wx.createCanvasContext(\'myCanvas\'); let ctxW = 750; let ctxH = 940; ctx.width = 750; ctx.height = 940; let x = ctx.width / 2; // 垂直渐变 const grd = ctx.createLinearGradient(0, 0, 0, ctxH); grd.addColorStop(0, \'#ffffff\'); grd.addColorStop(1, \'#ffffff\'); ctx.setFillStyle(grd); ctx.fillRect(0, 0, ctxW, ctxH); wx.getImageInfo({ src: that.data.cardPath, success: (res) => { ctx.drawImage(res.path, 0, 0, 750, 940); //card ctx.setFontSize(32) //字体大小 ctx.setFillStyle(\'red\') //字体颜色 ctx.textAlign = "center"; //文字居中 ctx.fillText(that.data.sendName, x, 34) ctx.stroke(); wx.getImageInfo({ src: that.data.headPath, success: (res) => { ctx.save(); ctx.beginPath(); //开始绘制 ctx.arc(150,358,50, 0, 2 * Math.PI) ctx.fill() ctx.clip(); //剪切 ctx.drawImage(res.path,100, 308, 100, 100); //userHeader // 推进去图片必须是https ctx.restore(); //恢复之前保存的绘图上下文 继续绘制 /**/ ctx.save(); ctx.draw(); } }) } }) }, /* 保存图片 */ saveImage: function (e) { wx.canvasToTempFilePath({ x: 0, //指定的画布区域的左上角横坐标 y: 0, //指定的画布区域的左上角纵坐标 width: 750, //指定的画布区域的宽度 height: 940, //指定的画布区域的高度 destWidth: 750, //输出的图片的宽度 destHeight: 940, //输出的图片的高度 canvasId: \'myCanvas\', fileType: \'jpg\', //图片的质量,目前仅对 jpg 有效。取值范围为 (0, 1],不在范围内时当作 1.0 处理。 quality: 1, success: function (res) { wx.saveImageToPhotosAlbum({ filePath: res.tempFilePath, success(result) { wx.showToast({ title: \'图片保存成功\', icon: \'success\', duration: 2000 }) } }) } }) }, })
以下appid使用xxxx代码,请使用自己的appid,不是自己的appid没有权限登陆。
{ "description": "项目配置文件。", "packOptions": { "ignore": [] }, "setting": { "urlCheck": false, "es6": true, "enhance": false, "postcss": true, "preloadBackgroundData": false, "minified": true, "newFeature": true, "coverView": true, "nodeModules": false, "autoAudits": false, "showShadowRootInWxmlPanel": true, "scopeDataCheck": false, "uglifyFileName": false, "checkInvalidKey": true, "checkSiteMap": true, "uploadWithSourceMap": true, "compileHotReLoad": false, "babelSetting": { "ignore": [], "disablePlugins": [], "outputPath": "" }, "useIsolateContext": true, "useCompilerModule": false, "userConfirmedUseCompilerModuleSwitch": false }, "compileType": "miniprogram", "libVersion": "2.15.0", "appid": "XXXXXX", "projectname": "canvas", "isGameTourist": false, "simulatorType": "wechat", "simulatorPluginLibVersion": {}, "condition": { "search": { "current": -1, "list": [] }, "conversation": { "current": -1, "list": [] }, "game": { "currentL": -1, "list": [] }, "miniprogram": { "current": -1, "list": [] } } }