示例图:
文献参考:
参考文档:https://zhuanlan.zhihu.com/p/597629702
uni-app官网:uni.createSelectorQuery() | uni-app官网
微信小程序官网:canvas | 微信开放文档
海报内容准备:
1、背景图片
2、二维码
3、用户头像,用户名称
4、简短的描述文案
PS:
1、若使用<canvas type="2d" id="myCanvas"></canvas>
则报错canvasToTempFilePath:fail fail canvas is empty。
2、若canvas不设置canvas-id,则报错<canvas>: canvas-id attribute is undefined(env: Windows,mp,1.06.2308310; lib: 2.25.3)。
3、若只设置canvas-id,则节点信息为null。
const query = uni.createSelectorQuery().in(this); query.select('#canvas').boundingClientRect(data => { console.log("节点信息" + JSON.stringify(data)); // null }).exec();
4、canvas绘制的图片不支持网络图片,因此使用网络需使用uni.getImageInfo
获取图片信息。
实现
HTML页面
// 触发按钮
<view data-event-opts="{{[['tap',[['handleClick']]]]}}" bindtap="__e">生成海报</view>
// 海报容器
<canvas canvas-id="canvass" id="canvas" style="width:100%; height: 1000rpx;" />
// 生成的海报图片
<image src="{{imgAddRess}}" style="width:100%; height: 1000rpx;"></image>
JS页面
// 单网图
data: {
return {
imgAddRess: "",
shareBg: "https://img2.baidu.com/it/u=3334525604,928778682&fm=253&app=138&size=w931&n=0&f=JPEG&fmt=auto?sec=1703955600&t=c88ebba9f3d8aeee92c6afd219945f9a",
memberCount: 100,
userImage:"/static/img/code/kong-img.png",
userName: "快乐星球",
shareQrImageUrl: "/static/img/code/kong-img.png"
}
}
// 生成海报
handleClick() {
const _this = this;
// 因shareBg图片为线上图片,需做转换uni.getImageInfo({ src: this.shareBg })
// 单个图片处理
uni.getImageInfo({ src: this.shareBg }).then(res => {
this.shareBg = res[1].path; // 获取转换后的图片路径
this.createdCanvas().then(()=>{
// 绘制需要延迟,不然第一次加载为空白
setTimeout(() => {
// 将生成的canvas图片,转为真实图片-地址
uni.canvasToTempFilePath({
x: 0,
y: 0,
canvasId: "canvass",
success: res => {
_this.imgAddRess = res.tempFilePath;
console.log('真实图片>>>>>>', res);
},
fail: (err) => { console.log('error', err) }
},this);
}, 500);
});
});
},
handleClick2() {
const _this = this;
// 多张图片处理
const Images = [this.shareBg, this.shareQrImageUrl, this.userImage];
Promise.all(Images.map(img => uni.getImageInfo({ src: img }))).then(
imageInfos => {
console.log('Images then>>>>>>', imageInfos);
this.shareBg = imageInfos[0][1].path;
this.shareQrImageUrl = imageInfos[1][1].path;
this.userImage = imageInfos[2][1].path;
//根据参数开始绘图
this.createdCanvas().then(()=>{
// 绘制需要延迟,不然第一次加载为空白
setTimeout(() => {
// 将生成的canvas图片,转为真实图片-地址
uni.canvasToTempFilePath({
x: 0,
y: 0,
canvasId: "canvass",
success: res => {
_this.imgAddRess = res.tempFilePath;
console.log('真实图片>>>>>>', res);
},
fail: (err) => { console.log('error', err) }
},this);
}, 500);
})
}
);
}
createdCanvas(){
const _this = this;
return new Promise((resolve, reject) => {
//绘图上下文
const ctx = uni.createCanvasContext('canvass', this);
uni.createSelectorQuery()
.in(this)
.select('#canvas')
.boundingClientRect(rect => {
if(!rect) return
var width = rect.width;
var height = rect.height;
// 背景图
ctx.drawImage( _this.shareBg, 0, 0, width, height);
// 文案:百位超能大神带你飞
ctx.font = "bold 31px 'DINAlternate-Bold, DINAlternate'"
ctx.setFillStyle('#ff9900');
ctx.setTextAlign('left');
ctx.fillText(_this.memberCount, Math.ceil(width*0.32), Math.ceil(height*0.103*2)+6);
ctx.setFillStyle('#ff9900');
ctx.setTextAlign('left');
ctx.font = "16px 'PingFangSC-Medium, PingFang SC'"
ctx.fillText('位超能大神带你飞', Math.ceil(width*0.32)+66, Math.ceil(height*0.103*2));
// 二维码区背景背景
ctx.beginPath();
// r:8 ,
// 起始点
ctx.moveTo(12, height - 92 + 8);
// 左上角
ctx.arcTo(12, height - 92, 12 + 8, height - 92, 8);
// 右上角
ctx.arcTo(width - 12, height - 92, width - 12, height - 92 + 8, 8);
// 右下角
ctx.arcTo(width - 12, height - 12, width - 12 - 8, height - 12, 8);
// 左下角
ctx.arcTo(12, height - 12, 12, height - 12 - 8, 8);
ctx.fillStyle = '#ffffff';
ctx.closePath();
ctx.fill();
//用户头像+用户名
let avatarurl_width = 50; //绘制的头像宽度
let avatarurl_heigth = 50; //绘制的头像高度
let avatarurl_x = 22; //绘制的头像在画布上的位置
let avatarurl_y = height - 77; //绘制的头像在画布上的位置
ctx.save(); // 保存绘图上下文
ctx.beginPath(); // 开始创建一个路径
ctx.arc(
avatarurl_width / 2 + avatarurl_x,
avatarurl_heigth / 2 + avatarurl_y,
avatarurl_width / 2,
0,
Math.PI * 2,
false
); // 画一个圆形裁剪区域
ctx.clip(); // 裁剪
ctx.drawImage(
this.userImage,
avatarurl_x,
avatarurl_y,
avatarurl_width,
avatarurl_heigth
); // //分享人头像-绘制图片x,y轴
ctx.restore(); // 恢复之前保存的绘图上下文
// 分享userName
ctx.setFillStyle('#141414');
ctx.setTextAlign('left');
ctx.font = "bold 16px 'PingFangSC-Medium, PingFang SC'"
let title = _this.userName;
if(title.length>14){
title =title.substr(0,14)+'...'
}
ctx.fillText(title, 80, height - 55) ;
// 分享描述
ctx.setFillStyle('#666666');
ctx.setTextAlign('center');
ctx.font = "11px 'PingFangSC-Regular, PingFang SC'"
ctx.fillText('欢迎来到快乐星球根据地', 140, height - 33);ht - 33);
// 二维码图片
ctx.drawImage(_this.shareQrImageUrl, width - 84, height - 84, 64, 64 );
ctx.draw();
}).exec()
//获取节点
resolve()
})
}
多网图
data: {
return {
imgAddRess: "",
shareBg:"https://img0.baidu.com/it/u=2868999810,2001254139&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=714",
shareQrImageUrl: "https://img1.baidu.com/it/u=206225810,1732683717&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
avater: "https://img2.baidu.com/it/u=1979438230,3745650916&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500"
}
}
// 生成海报
handleSetImage() {
const _this = this;
const Images = [this.shareBg, this.shareQrImageUrl, this.avater];
let aa = Images.map(img => uni.getImageInfo({ src: img }));
Promise.all(Images.map(img => uni.getImageInfo({ src: img }))).then(
imageInfos => {
console.log('Images then>>>>>>', imageInfos);
this.shareBg = imageInfos[0][1].path;
this.shareQrImageUrl = imageInfos[1][1].path;
this.avater = imageInfos[2][1].path;
//根据参数开始绘图
this.createdCanvas().then(()=>{
// 绘制需要延迟,不然第一次加载为空白
setTimeout(() => {
wx.canvasToTempFilePath({
x: 0,
y: 0,
canvasId: "mc",
success: res => {
_this.imgAddRess = res.tempFilePath;
console.log('真实图片>>>>>>', res);
},
fail:(error)=>{
console.log('error',error)
uni.showToast({
title: error.errMsg,
icon:'none',
duration:2000,
});
}
},this);
}, 500);
})
}
);
},
// 海报绘图
createdCanvas() {
const _this = this;
const query = wx.createSelectorQuery().in(this);
query.select('#mc').boundingClientRect(data => {
console.log("得到布局位置信息" + JSON.stringify(data));
}).exec();
return new Promise((resolve, reject) => {
//绘图上下文
const ctx = wx.createCanvasContext('mc', this);
wx.createSelectorQuery()
.in(this)
.select('#mc')
.boundingClientRect(rect => {
console.log('rect111',rect)
if(!rect) return
var width = rect.width;
var height = rect.height;
let qrw = (width-200) / 2;
let qrh = ((height - 200) / 2 + 80);
// 背景图
ctx.drawImage( _this.shareBg, 0, 0, width, height);
// 头像
ctx.drawImage(_this.avater, (width - 80) / 2 , 50 , 80, 80 );
// 文案
ctx.setFillStyle('#ffffff');
ctx.setTextAlign('center');
ctx.font = "bold 26px 'PingFangSC-Medium, PingFang SC'"
ctx.fillText('超能小飞侠', 180, 170, width);
ctx.font = "bold 16px 'DINAlternate-Bold, DINAlternate'"
ctx.setFillStyle('#000000');
ctx.setTextAlign('center');
ctx.fillText("诚邀您参与超能封神", 185, 205, width); // (文本,X坐标,Y坐标, 最大宽度)
// 二维码:(图片,X坐标,Y坐标, 图宽,图高)
ctx.drawImage(_this.shareQrImageUrl, qrw , qrh , 200, 200 );
//二维码图片
ctx.draw();
}).exec()
//获取节点
resolve()
})
},