uni-app canvas生成海报问题
uni-app canvas生成海报问题
| 产品分类 | 开发环境 | 版本号 | 项目创建方式 |
|---|---|---|---|
| uniapp/H5 | Windows | window 10 | CLI |
示例代码:
<template>
<view>
<view class="aaaa" @click="addCanvas">点击生成海报</view>
<view class="aaaa" @click="saveCanvas">点击保存海报</view>
<canvas style="width: 300px; height: 300px;" canvas-id="firstCanvas"></canvas>
<image :src="image" v-if="image" width="300" height="300"></image>
</view>
</template>
<style>
.aaaa {
height: 40px;
margin-bottom: 20px;
background-color: blue;
color: #fff;
}
</style>
<script type="text/javascript">
export default {
data () {
return {
ctx: null,
image: null
}
},
mounted () {
this.ctx = uni.createCanvasContext('firstCanvas', this)
},
methods: {
// 读取图片信息
setImg (img) {
return new Promise ( (resolve, reject) => {
uni.getImageInfo({
src: img.url,
success: function(image) {
resolve(image)
},
fail: function(err) {
console.log(err,'获取图片错误')
reject(err)
}
});
})
},
addCanvas () {
const _this = this;
_this.setImg({
url: 'https://img.trlpw.com/images/common/2021/10/11/202110116163b74541444.png'
}).then ((avatar) => {
console.log(avatar)
_this.ctx.drawImage(avatar.path, 0, 0, 300, 300)
_this.ctx.draw();
})
},
saveCanvas () {
const _this = this
uni.canvasToTempFilePath({
x: 0,
y: 0,
width: 300,
height: 300,
destWidth: 300,
destHeight: 300,
fileType: 'jpg',
canvasId: 'firstCanvas',
success: function(res) {
console.log(res)
_this.image = res.tempFilePath
},
fail: function(err) {
uni.showToast({
title: `海报生成失败,${err.errMsg}`,
icon: 'none'
})
},
complete: function() {
uni.hideLoading();
}
}, this)
}
}
}
</script>
操作步骤:
同示例代码
预期结果:
微信浏览器内、手机自带浏览器能正常生成图片
实际结果:
实际目前结果微信浏览器内、手机自带浏览器报跨域了
bug描述:
使用 uni.getImageInfo 处理过的图片,能够正常话进canvas里面,但是在H5端,使用 uni.canvasToTempFilePath 把canvas转化为图片时,确报跨域问题
SecurityError: Failed to execute ‘toDataURL’ on ‘HTMLCanvasElement’: Tainted canvases may not be exported
测试结果
本地在chrome浏览器下模拟手机访问测试是正常的,可以正常生成图片,在微信内置浏览器访问、手机自带浏览器访问在保存海报生成图片的时候却报跨域问题
更多关于uni-app canvas生成海报问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html
3 回复
图片是允许跨域的,图片没允许跨域之前,浏览器端模拟手机测试也会报错
这是一个典型的H5 canvas跨域问题。在uni-app的H5端,当canvas中包含跨域图片时,调用toDataURL()或toBlob()方法会触发安全限制。
问题核心在于:虽然uni.getImageInfo能获取到跨域图片信息,但浏览器在将canvas转换为图片时会检查画布是否"被污染"(tainted)。
解决方案:
- 为图片添加crossOrigin属性:
// 修改setImg方法
setImg (img) {
return new Promise ( (resolve, reject) => {
// 创建Image对象并设置crossOrigin
const image = new Image()
image.crossOrigin = 'anonymous' // 关键:允许跨域
image.onload = () => {
resolve({
path: img.url,
width: image.width,
height: image.height
})
}
image.onerror = (err) => {
console.log(err,'获取图片错误')
reject(err)
}
image.src = img.url + (img.url.indexOf('?') > -1 ? '&' : '?') + 't=' + Date.now()
})
}
- 确保图片服务器支持CORS: 图片服务器需要设置正确的CORS头:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
- 使用uni.downloadFile下载图片到本地(备选方案):
async setImg(img) {
try {
const res = await uni.downloadFile({
url: img.url
})
return {
path: res.tempFilePath,
width: 0,
height: 0
}
} catch(err) {
console.log(err)
throw err
}
}
- 在drawImage后添加延迟:
addCanvas () {
const _this = this;
_this.setImg({
url: 'https://img.trlpw.com/images/common/2021/10/11/202110116163b74541444.png'
}).then ((avatar) => {
console.log(avatar)
_this.ctx.drawImage(avatar.path, 0, 0, 300, 300)
_this.ctx.draw();
// H5端需要等待图片完全加载
setTimeout(() => {
_this.saveCanvas()
}, 100)
})
}

