功能很简单 但是有坑
废话不多说直接上代码
html
canvas 定义画板 构造海报 .preview 生成海报图浏览 模板框
<canvas canvas-id="shareImg" class="canvas-exp"></canvas>
<view hidden='{{previewHidden}}' class='preview'>
<image src='{{preurl}}' mode='widthFix' class='previewImg'></image>
<button type='primary' bindtap='save' style="background:#0A655A">保存到本地</button>
</view>
<button class='shares' type='primary' bindtap='share'>生成成绩单</button>
css
.shares{
position: absolute;
bottom: 100rpx;
width: 70%;
left: 15%;
height: 100rpx;
line-height: 100rpx;
}
.canvas-exp{
width:100%;height:606px;background:#fff;
}
.preview {
width: 100%;
height: 100%;
background: rgba(0,0,0,1);
position:fixed;
top: 0;
left: 0;
z-index: 2;
}
.previewImg{
width: 88%;
position: absolute;
top: 100rpx;
left: 6%;
z-index: 3;
border: 1px solid #000;
border-radius: 5px;
max-height: 800rpx;
}
.preview button{
width: 78%;
position: absolute;
top: 960rpx;
left: 11%;
border-radius: 2px;
}
.preview .cler{
width: 64rpx;
height: 64rpx;
position: absolute;
top: 1100rpx;
left: 50%;
margin-left: -32rpx;
}
核心代码 js
// pages/all/index.js
Page({
/**
* 页面的初始数据
*/
data: {
currentLineHeight: 0,
previewHidden: true
},
onLoad(){
this.createCanvasContext()
},
createCanvasContext() {
let that =this
var expiration = wx.getStorageSync("index_data_expiration"); //拿到过期时间
var timestamp = Date.parse(new Date()); //拿到现在时间
// access_token 过期时间
if (wx.getStorageSync('access_token') && expiration > timestamp) {
console.log(wx.getStorageSync('access_token'))
that.accessToken(wx.getStorageSync('access_token'))
} else {
wx.request({
url: 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=appid&secret=secret',
method: 'get',
success: function (ress) {
wx.setStorageSync("access_token", ress.data.access_token)
var timestamp = Date.parse(new Date());
var expiration = timestamp + ress.data.expires_in
console.log(ress.data.access_token)
wx.setStorageSync("expires_in", expiration)
that.accessToken(ress.data.access_token)
},
fail: function (res) {
console.log(res)
}
})
}
},
accessToken(access_token) {
let that = this
let winWidth = wx.getSystemInfoSync().windowWidth; // 获取当前设备的可视宽度
let winHeight = wx.getSystemInfoSync().windowHeight; // 获取当前设备的可视高度
that.setData({
winWidth: winWidth,
winHeight: winHeight
})
let data = {
page: 'pages/hotinfo/hotinfo',
scene: '12'
}
wx.request({
url: 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=' + access_token,
method: 'POST',
data: data,
// dataType: 'json',
responseType: 'arraybuffer', //将返回数据 按文本解析修改为arraybuffer
success: function (res) {
console.log(res)
// 利用writeFile bese64图片存本地文件使用
var imgPath = wx.env.USER_DATA_PATH + '/tabhome' + 'ewm' + '.png';
var fs = wx.getFileSystemManager();
fs.writeFileSync(imgPath, res.data, "base64");
const ctx = wx.createCanvasContext('shareImg')
var Rpx = (winWidth / 375).toFixed(2);
ctx.setFillStyle('#fff')
ctx.fillRect(0, 0, winWidth, 800)
ctx.drawImage('../../' + res[0].path, 0, 0, winWidth, 228 * Rpx)
var currentLineHeight = 228 * Rpx + 10;
ctx.setTextAlign('left')
ctx.setFillStyle('#2E2F2F')
ctx.setTextAlign('left')
let contentTitle = '这世界,来过,爱过,奋斗过,何惧解决如何---悟空!这世界,来过,爱过,奋斗过,何惧解决如何---悟空!'
var chr = contentTitle.split(""); //这个方法是将一个字符串分割成字符串数组
var temp = "";
var row = [];
for (var a = 0; a < chr.length; a++) {
if (ctx.measureText(temp).width < winWidth / 2 - 10) {
temp += chr[a];
} else {
a--;
row.push(temp);
temp = "";
}
}
row.push(temp);
//如果数组长度大于2 则截取前两个
if (row.length > 2) {
var rowCut = row.slice(0, 2);
var rowPart = rowCut[1];
var test = "";
var empty = [];
for (var a = 0; a < rowPart.length; a++) {
if (ctx.measureText(test).width < winWidth / 2 - 10) {
test += rowPart[a];
} else {
break;
}
}
empty.push(test);
var group = empty[0] + "..." //这里只显示两行,超出的用...表示
rowCut.splice(1, 1, group);
row = rowCut;
}
ctx.font = 'normal bold 18px sans-serif';
for (var b = 0; b < row.length; b++) {
currentLineHeight += Rpx * 30;
ctx.fillText(row[b], 15, currentLineHeight);
}
currentLineHeight += 80 * Rpx
ctx.drawImage('../../' + 'assets/coupon_gold.png', 20, currentLineHeight, 60 * Rpx, 60 * Rpx)
currentLineHeight += 35 * Rpx
ctx.fillText('健健康康', 90 * Rpx, currentLineHeight);
ctx.drawImage(imgPath, winWidth - 120 * Rpx, currentLineHeight - 70, 100 * Rpx, 100 * Rpx)
currentLineHeight += 100 - 40 * Rpx
ctx.stroke()
ctx.draw()
that.setData({
currentLineHeight: currentLineHeight
})
})
}
},
save: function () {
var that = this;
//获取相册授权
wx.getSetting({
success(res) {
if (!res.authSetting['scope.writePhotosAlbum']) {
wx.authorize({
scope: 'scope.writePhotosAlbum',
success() {
that.savaImageToPhoto();
}
})
} else {
that.savaImageToPhoto();
}
}
})
},
/**
* 生成分享图
*/
share: function () {
var that = this
wx.showLoading({
title: '努力生成中...'
})
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: this.data.winWidth,
height: this.data.currentLineHeight,
destWidth: this.data.winWidth,
destHeight: this.data.currentLineHeight,
canvasId: 'shareImg',
success: function (res) {
console.log(res.tempFilePath);
that.setData({
preurl: res.tempFilePath,
previewHidden: false,
})
wx.hideLoading()
},
fail: function (res) {
console.log(res)
}
})
},
savaImageToPhoto: function () {
let that = this;
wx.showLoading({
title: '努力生成中...'
})
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: that.data.winWidth,
height: that.data.winHeight - 70,
destWidth: that.data.winWidth,
destHeight: that.data.winHeight - 70,
canvasId: 'shareImg',
success: function (res) {
console.log(res)
wx.hideLoading()
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success(res) {
wx.showModal({
content: '图片已保存到相册',
showCancel: false,
confirmText: '知道啦',
confirmColor: '#72B9C3',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定');
that.setData({
hidden: true
})
}
}
})
}
})
},
fail: function (res) {
console.log(res)
}
})
},
})
https://api.weixin.qq.com只能用后端请求获取 前端只可供体验参考 不然线上会出问题
1.通过小程序api 接口 https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=appid&secret=secret (get)
获取 token值 时效两个小时
2.再通过api 接口 https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=access_token 获取自定义参数的小程序码 (POST)
01.scene 为要携带的参数 最高32位 具体看小程序api文档 接口返回的格式为 arraybuffer
02.请求是注意 参数修改 responseType: 'arraybuffer', //将返回数据 按文本解析修改为arraybuffer
03.通过api wx.arrayBufferToBase64() 将数据转为bese64 例:
let URL ='data:image/png;base64,' + wx.arrayBufferToBase64(res.data)
04.小程序canvas bese64图片 模拟器可正常显示 真机操作则无效 因canvas图片不支持base64
处理方法为利用writeFile bese64图片存本地文件使用 例:
var imgPath = wx.env.USER_DATA_PATH + '/tabhome' + 'ewm' + '.png';
var fs = wx.getFileSystemManager();
fs.writeFileSync(imgPath, res.data, "base64");
wx.env.USER_DATA_PATH 为微信提供无需在意 '/tabhome' 为本页面路径 ewm为自定义
writeFileSync内的imgPath为自定义的文件路径 (本地路径)
writeFileSync内的res.data 为获取到的arraybuffer值
writeFileSync内的base64 为数据类型
imgPath拿到的 就是本地的图片路径 可直接使用到项目中
3.利用wx.createCanvasContext创建画板 进行绘画 文字太多 自动换行两行省略处理 图片路径一定要正确 不然只会看到空白的canvas
4.利用wx.canvasToTempFilePath() 将canvas截取生成图片 区域可自定义 具体请看官方文档
5.wx.saveImageToPhotosAlbum 保存图片到手机相册
流程:
通过canvas提前绘制海报
再通过wx.canvasToTempFilePath() 截取绘制好的海报
最后通过wx.saveImageToPhotosAlbum 保存图片到手机相册
这样就大功告成了