上一张效果图:

第一步:配置合法域名
微信小程序绑定的微信号登录微信公众号,配置好uploadFile 域名,否则会报错说配置的uploadFile域名列表里没有你的域名.
第二步:把网络图片下载到微信本地
图片要提前下载完之后再绘图,不然图片显示不出来,用到的方法是:
wx.downloadFile({
url: imgUrl,
success:res=>{
if (res.statusCode === 200) {
this.data.tempSrc= res.tempFilePath; //下载成功返回结果
}
}
})第三步:绘制
//开始用canvas绘制分享海报
drawCanvas(fn) {
const ctx = wx.createCanvasContext('myCanvas'); //创建画布
wx.createSelectorQuery().select('#canvas-container').boundingClientRect(rect=>{
let width = rect.width;
let height = rect.height;
let right = rect.right;
let left = 20;
ctx.setFillStyle('#fff'); // 填充画布为白色
ctx.fillRect(0, 0, rect.width, height); // 画一个矩形 两个坐标
let posterHeight = 400; // 海报高度 总共600
let avatarWidth = width/7; // 头像宽度
let avatarHeight = avatarWidth; // 头像宽度
//海报
if (this.data.posterSrc) {
ctx.drawImage(this.data.posterSrc, 0, 0, width, posterHeight);
}
//姓名
if (this.data.Name) {
var name = this.data.Name
let maxNameWidth = width - avatarHeight
let maxNameLength = parseInt(maxNameWidth / 16) - 1
if (maxNameLength < name.length) {
name = name.substring(0, maxNameLength) + '...'
}
ctx.font = 'normal bold 16px sans-serif';
ctx.setFontSize(16);
ctx.setFillStyle('#000');
ctx.setTextAlign('left');
ctx.fillText(name, left + avatarWidth + 15, posterHeight + 38, width - avatarHeight - 40 - 15);
}
// 头像
if (this.data.avatarSrc) {
ctx.drawImage(this.data.avatarSrc, left, posterHeight + 20, avatarHeight, avatarHeight)
ctx.setFontSize(10);
ctx.setFillStyle('#000');
}
//职位
if (this.data.Position) {
var position = this.data.Position
let maxPositionWidth = width - 70
let maxPositionLength = parseInt(maxPositionWidth / 12) - 2
if (maxPositionLength < position.length) {
position = position.substring(0, maxPositionLength) + '...'
}
ctx.setFontSize(12);
ctx.setFillStyle('#676b6d');
ctx.setTextAlign('left');
ctx.fillText(position, left + avatarWidth + 15, posterHeight + 58);
}
//电话
if (this.data.Mobile) {
ctx.drawImage(this.data.phoneIconSrc, left, posterHeight + avatarHeight + 60, 15, 15);
ctx.setFontSize(12);
ctx.setFillStyle('#666');
ctx.setTextAlign('left');
ctx.fillText(this.data.Mobile, left + 20, posterHeight + avatarHeight + 73);
}
// 公司名称
if (this.data.Company) {
var companyName = this.data.Company
let maxCompanyNameWidth = width - 120
// console.log(maxCompanyNameWidth)
let maxCompanyNameLength = parseInt(maxCompanyNameWidth / 12) - 1
// console.log(maxCompanyNameLength)
const CONTENT_ROW_LENGTH = maxCompanyNameLength * 2; // 正文 单行显示字符长度
ctx.drawImage(this.data.addressIconSrc, left, posterHeight + avatarHeight + 85, 15, 15);
let [contentLeng, contentArray, contentRows] = this.textByteLength(this.data.Company, CONTENT_ROW_LENGTH);
ctx.setFontSize(12);
ctx.setFillStyle('#666');
ctx.setTextAlign('left');
let contentHh = 22 * 1;
for (let m = 0; m < contentArray.length; m++) {
ctx.fillText(contentArray[m], left + 20, posterHeight + avatarHeight + 100 + contentHh * m);
}
}
// 绘制二维码
if (this.data.qrSrc) {
ctx.drawImage(this.data.qrSrc, width - 90, posterHeight + avatarHeight + 30, 70, 70)
ctx.setFontSize(8);
ctx.setFillStyle('#6f7475');
ctx.fillText("扫一扫或长按识别", width - 88, posterHeight + avatarHeight + 115);
}
ctx.draw();
wx.hideLoading();
fn && fn()
}).exec()
},
/**
* 多行文字处理,每行显示数量
* @param text 为传入的文本
* @param num 为单行显示的字节长度
*/
textByteLength(text, num) {
let strLength = 0; // text byte length
let rows = 1;
let str = 0;
let arr = [];
for (let j = 0; j < text.length; j++) {
if (text.charCodeAt(j) > 255) {
strLength += 2;
if (strLength > rows * num) {
strLength++;
arr.push(text.slice(str, j));
str = j;
rows++;
}
} else {
strLength++;
if (strLength > rows * num) {
arr.push(text.slice(str, j));
str = j;
rows++;
}
}
}
arr.push(text.slice(str, text.length));
// console.log([strLength, arr, rows])
return [strLength, arr, rows] // [处理文字的总字节长度,每行显示内容的数组,行数]
}附上此效果图的全部代码:
wxml
ps:本人用的是colorUI,当然样式不重要,都是可以自己写出来的
<view class='poste_box' id='canvas-container'> <canvas canvas-id="myCanvas"> </canvas> </view> <view class="btn-container"> <button class="cu-btn block bg-mauve lg shadow-blur" catchtap="drawLasted">最新海报</button> <button class="cu-btn block bg-orange lg shadow-blur" catchtap="drawRandom">随机海报</button> <button class="cu-btn block bg-blue lg shadow-blur" catchtap="drawDefault">自定义海报</button> <button class="cu-btn block bg-green lg shadow-blur" catchtap="saveShareImg" >保存海报</button> </view>
wxss
page {
display: flex;
flex-direction: column;
}
.btn-container{
padding: 20rpx 30rpx 40rpx 30rpx;
display: flex;
justify-content: space-between;
}
.btn-container button{
width: 160rpx;
height: 60rpx!important;
line-height: 60rpx;
font-size: 24rpx!important;
padding: 0!important;
text-align: center;
border-radius: 32rpx;
}
canvas{
width:calc(100% - 30rpx);
height:1200rpx;
margin: 20rpx auto;
}js
const app = getApp()
Page({
data:{
avatar: '', //用户头像
qrCode: "", //需要https图片路径
Name: '', //姓名
Position: "", //职位
Mobile: "", //手机
Company: "", //公司
posterSrc: '', //海报图片
avatarSrc: '', //用户头像
phoneIconSrc: '', //电话图标
addressIconSrc: '', //地址图标
qrSrc: '', //二维码
token: "", //七牛云token
flag: true, //相机授权标识 默认授权 true
},
onLoad(options){
this.data.card_id = options.card_id
this.donwloadImg('https://pimg.llwangpu.com//1566886354972-8293', "phoneIconSrc")
this.donwloadImg('https://pimg.llwangpu.com//1566886425694-8615', "addressIconSrc")
app.apis.getQiniuToken().then(data => {this.data.token = data})
this.init()
},
init(){
wx.showLoading({ title: '生成中...', mask: true })
//初始化海报
this.initPosterInfo(1,()=>{
//初始化名片信息
this.initCardInfo(() => {
//初始化二维码信息
this.initQrInfo(() => {
wx.hideLoading()
//开始绘制海报
this.drawCanvas()
})
})
})
},
//初始化名片信息
initCardInfo(fn){
app.apis.getCardDetail(this.data.card_id).then(data => {
this.donwloadImg(decodeURI(data.card_info.avatar), "avatarSrc",()=>{
this.setData({
avatar: data.card_info.avatar,
Name: data.card_info.name,
Position: data.card_info.position,
Mobile: data.card_info.mobile_phone_number,
Company: data.card_info.company_name
})
fn && fn()
})
})
},
//初始化二维码
initQrInfo(fn){
app.apis.getQr(1, this.data.card_id).then(res => {
this.setData({ qrCode: res.url})
this.donwloadImg(res.url, "qrSrc",()=>{
fn && fn()
})
})
},
//初始化海报
initPosterInfo(type,fn){
app.apis.getPoster(type).then(res=>{
this.donwloadImg(res.image_url, "posterSrc",()=>{
fn && fn()
})
})
},
//初始化图片为本地图片
donwloadImg(imgUrl,resultSrc,callback) {
wx.downloadFile({
url: imgUrl,
success:res=>{
if (res.statusCode === 200) {
this.data[resultSrc] = res.tempFilePath; //下载成功返回结果
callback && callback()
}
}
})
},
//开始用canvas绘制分享海报
drawCanvas(fn) {
const ctx = wx.createCanvasContext('myCanvas'); //创建画布
wx.createSelectorQuery().select('#canvas-container').boundingClientRect(rect=>{
let width = rect.width;
let height = rect.height;
let right = rect.right;
let left = 20;
ctx.setFillStyle('#fff'); // 填充画布为白色
ctx.fillRect(0, 0, rect.width, height); // 画一个矩形 两个坐标
let posterHeight = 400; // 海报高度 总共600
let avatarWidth = width/7; // 头像宽度
let avatarHeight = avatarWidth; // 头像宽度
//海报
if (this.data.posterSrc) {
ctx.drawImage(this.data.posterSrc, 0, 0, width, posterHeight);
}
//姓名
if (this.data.Name) {
var name = this.data.Name
let maxNameWidth = width - avatarHeight
let maxNameLength = parseInt(maxNameWidth / 16) - 1
if (maxNameLength < name.length) {
name = name.substring(0, maxNameLength) + '...'
}
ctx.font = 'normal bold 16px sans-serif';
ctx.setFontSize(16);
ctx.setFillStyle('#000');
ctx.setTextAlign('left');
ctx.fillText(name, left + avatarWidth + 15, posterHeight + 38, width - avatarHeight - 40 - 15);
}
// 头像
if (this.data.avatarSrc) {
ctx.drawImage(this.data.avatarSrc, left, posterHeight + 20, avatarHeight, avatarHeight)
ctx.setFontSize(10);
ctx.setFillStyle('#000');
}
//职位
if (this.data.Position) {
var position = this.data.Position
let maxPositionWidth = width - 70
let maxPositionLength = parseInt(maxPositionWidth / 12) - 2
if (maxPositionLength < position.length) {
position = position.substring(0, maxPositionLength) + '...'
}
ctx.setFontSize(12);
ctx.setFillStyle('#676b6d');
ctx.setTextAlign('left');
ctx.fillText(position, left + avatarWidth + 15, posterHeight + 58);
}
//电话
if (this.data.Mobile) {
ctx.drawImage(this.data.phoneIconSrc, left, posterHeight + avatarHeight + 60, 15, 15);
ctx.setFontSize(12);
ctx.setFillStyle('#666');
ctx.setTextAlign('left');
ctx.fillText(this.data.Mobile, left + 20, posterHeight + avatarHeight + 73);
}
// 公司名称
if (this.data.Company) {
var companyName = this.data.Company
let maxCompanyNameWidth = width - 120
// console.log(maxCompanyNameWidth)
let maxCompanyNameLength = parseInt(maxCompanyNameWidth / 12) - 1
// console.log(maxCompanyNameLength)
const CONTENT_ROW_LENGTH = maxCompanyNameLength * 2; // 正文 单行显示字符长度
ctx.drawImage(this.data.addressIconSrc, left, posterHeight + avatarHeight + 85, 15, 15);
let [contentLeng, contentArray, contentRows] = this.textByteLength(this.data.Company, CONTENT_ROW_LENGTH);
ctx.setFontSize(12);
ctx.setFillStyle('#666');
ctx.setTextAlign('left');
let contentHh = 22 * 1;
for (let m = 0; m < contentArray.length; m++) {
ctx.fillText(contentArray[m], left + 20, posterHeight + avatarHeight + 100 + contentHh * m);
}
}
// 绘制二维码
if (this.data.qrSrc) {
ctx.drawImage(this.data.qrSrc, width - 90, posterHeight + avatarHeight + 30, 70, 70)
ctx.setFontSize(8);
ctx.setFillStyle('#6f7475');
ctx.fillText("扫一扫或长按识别", width - 88, posterHeight + avatarHeight + 115);
}
ctx.draw();
wx.hideLoading();
fn && fn()
}).exec()
},
/**
* 多行文字处理,每行显示数量
* @param text 为传入的文本
* @param num 为单行显示的字节长度
*/
textByteLength(text, num) {
let strLength = 0; // text byte length
let rows = 1;
let str = 0;
let arr = [];
for (let j = 0; j < text.length; j++) {
if (text.charCodeAt(j) > 255) {
strLength += 2;
if (strLength > rows * num) {
strLength++;
arr.push(text.slice(str, j));
str = j;
rows++;
}
} else {
strLength++;
if (strLength > rows * num) {
arr.push(text.slice(str, j));
str = j;
rows++;
}
}
}
arr.push(text.slice(str, text.length));
// console.log([strLength, arr, rows])
return [strLength, arr, rows] // [处理文字的总字节长度,每行显示内容的数组,行数]
},
//最新海报
drawLasted(){
wx.showLoading({ title: '生成中...', mask: true })
app.apis.getPoster(1).then(res => {
this.donwloadImg(decodeURI(res.image_url), "posterSrc",()=>{
this.drawCanvas(()=>{
wx.hideLoading()
})
})
})
},
//随机海报
drawRandom(){
wx.showLoading({ title: '生成中...', mask: true })
app.apis.getPoster(2).then(res => {
this.donwloadImg(decodeURI(res.image_url), "posterSrc", ()=>{
this.drawCanvas(()=>{
wx.hideLoading()
})
})
})
},
//自定义海报
drawDefault(){
app.tools.uploadImage(this.data.token).then(res => {
this.donwloadImg(res.imageURL, "posterSrc",()=>{
this.drawCanvas()
})
})
},
//保存海报
saveShareImg(){
if (this.data.flag){
wx.showLoading({title: '正在保存',mask: true})
wx.canvasToTempFilePath({
canvasId: 'myCanvas',
success: res => {
wx.hideLoading();
wx.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success:res => {
wx.showModal({
title:'提示',
content: '图片已保存到相册,赶紧晒一下吧~',
showCancel: false,
confirmText: '好的',
confirmColor: '#333',
success: function (res) {
if (res.confirm) { }
},
fail: function (res) { }
})
},
fail:res => {
wx.showToast({
title: '保存失败,再次点击授权',
icon: 'none',
duration: 2000
})
this.data.flag = false
}
})
}
});
}else{
wx.openSetting({
success: settingdata => {
// console.log(settingdata)
if (settingdata.authSetting['scope.writePhotosAlbum']) {
// console.log('获取权限成功,给出再次点击图片保存到相册的提示。')
this.data.flag = true
} else {
// console.log('获取权限失败,给出不给权限就无法正常使用的提示')
this.data.flag = false
}
}
})
}
}
})PS:
海报需要单个接口请求,头像、名字、职位、电话、公司需要一个接口初始化,二维码需要一个接口请求,由于个人项目实际情况,采用的是回调函数方式调用实现。
实现了最新海报、随机海报、自定义海报、保存海报(拒绝授权保存到相册的合理处理),app.tools.uploadImage 是封装的自定义上传海报,利用七牛云上传实现自定义上传

微信扫码查看本文
发表评论