uniapp 画布Canvas绘制失败
在开发者工具中保存图片成功没有问题,真机调试就不行,打印到console.log('开始绘制');后面的ctx.draw就不执行了,这是什么原因导致的,该怎么解决。
const downloadPoster = async () => {
uni.showLoading({ title: '生成中', mask: true })
try {
const ctx = uni.createCanvasContext('myCanvas', proxy)
if (!ctx) {
return uni.showToast({ title: 'canvas 未初始化', icon: 'none' })
}
const scale = 2; // 设计稿转canvas的比例
const poster = state.posterList[state.selectPoster];
const components = JSON.parse(poster?.pageComponents || '[]');
const [bgInfo, avatarImg, levelIconImg, qrcodeImg] = await Promise.all([
getImageInfoAsync(poster?.picUrl),
getImageInfoAsync(info.value.avatar),
getImageInfoAsync(state.member.picUrl),
getImageInfoAsync(state.qrcode),
]) as any
ctx.drawImage(bgInfo.path, 0, 0, 554, 970);// 背景图
for (const comp of components) {
if (comp.type === 1) {
const avatarSize = 65;
const avatarRadius = avatarSize / 2;
const nickname = info.value.nickname || '匿名';
const gradeText = info.value.memberName || '游客';
// 用户信息组件的起点位置
const startX = comp.x * scale;
const startY = comp.y * scale;
// 头像绘制
const avatarX = startX;
const avatarY = startY + 6;
ctx.save();
ctx.beginPath();
ctx.arc(avatarX + avatarRadius, avatarY + avatarRadius, avatarRadius, 0, 2 * Math.PI);
ctx.clip();
ctx.drawImage(avatarImg.path, avatarX, avatarY, avatarSize, avatarSize);
ctx.restore();
// 昵称绘制
const nameX = avatarX + avatarSize + 8; // 头像右侧间距
const nameY = avatarY + 4;
ctx.setFontSize(24);
ctx.setFillStyle('#804500');
ctx.setTextAlign('left');
ctx.setTextBaseline('top');
ctx.fillText(nickname, nameX, nameY);
// 等级背景 + 图标 + 文字绘制
const iconWidth = 28;
const iconHeight = 28;
const iconMarginRight = 4;
const paddingX = 6;
const paddingY = 6;
ctx.setFontSize(20);
const textWidth = ctx.measureText(gradeText).width;
const gradeWidth = iconWidth + iconMarginRight + textWidth + paddingX * 2;
const gradeHeight = 20 + paddingY * 2;
const gradeX = nameX;
const gradeY = nameY + 30;
const radius = 18;
ctx.beginPath();
ctx.setFillStyle(state.member?.labelColor);
// 左上角圆角
ctx.moveTo(gradeX + radius, gradeY);
ctx.quadraticCurveTo(gradeX, gradeY, gradeX, gradeY + radius);
// 左边
ctx.lineTo(gradeX, gradeY + gradeHeight - radius);
// 左下角(直角)
ctx.lineTo(gradeX, gradeY + gradeHeight);
ctx.lineTo(gradeX + gradeWidth - radius, gradeY + gradeHeight);
// 右下角圆角
ctx.quadraticCurveTo(gradeX + gradeWidth, gradeY + gradeHeight, gradeX + gradeWidth, gradeY + gradeHeight - radius);
// 右边
ctx.lineTo(gradeX + gradeWidth, gradeY + radius);
// 右上角(直角)
ctx.lineTo(gradeX + gradeWidth, gradeY);
ctx.lineTo(gradeX + radius, gradeY); // 顶部回到起点
ctx.closePath();
ctx.fill();
// 等级图标绘制(垂直居中)
const iconX = gradeX + paddingX;
const iconY = gradeY + (gradeHeight - iconHeight) / 2;
ctx.drawImage(levelIconImg.path, iconX, iconY, iconWidth, iconHeight);
// 等级文字绘制
const textX = iconX + iconWidth + iconMarginRight;
const textY = gradeY + gradeHeight / 2;
ctx.setFillStyle(state.member.fontColor);
ctx.setTextAlign('left');
ctx.setTextBaseline('middle');
ctx.fillText(gradeText, textX, textY);
}
// 二维码
if (comp.type === 2) {
ctx.drawImage(qrcodeImg?.path, comp.x * scale, comp.y * scale, 170, 170);
}
}
console.log('开始绘制');
// 确保所有绘制完成再导出
ctx.draw(true, () => {
console.log('draw 完成,开始导出')
uni.canvasToTempFilePath({
canvasId: 'myCanvas',
destWidth: 554 * scale,
destHeight: 970 * scale,
success: res => {
state.previewImgUrl = res.tempFilePath
uni.hideLoading()
if (process.env.UNI_PLATFORM === 'h5') {
state.showImgUrl = true
uni.showToast({ title: '请长按图片保存', icon: 'none' })
} else {
saveToAlbum(res.tempFilePath)
}
},
fail: err => {
console.error('导出失败', err);
uni.hideLoading();
uni.showToast({ title: '导出失败' + err, icon: 'none' });
},
complete() {
}
}, proxy)
})
} catch (e) {
console.error('生成出错', e)
uni.showToast({ title: '生成失败', icon: 'none' })
} finally {
uni.hideLoading()
}
}