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 回复

图像是否允许了跨域访问?

更多关于uni-app canvas生成海报问题的实战教程也可以访问 https://www.itying.com/category-93-b0.html


图片是允许跨域的,图片没允许跨域之前,浏览器端模拟手机测试也会报错

这是一个典型的H5 canvas跨域问题。在uni-app的H5端,当canvas中包含跨域图片时,调用toDataURL()toBlob()方法会触发安全限制。

问题核心在于:虽然uni.getImageInfo能获取到跨域图片信息,但浏览器在将canvas转换为图片时会检查画布是否"被污染"(tainted)。

解决方案:

  1. 为图片添加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()
    })
}
  1. 确保图片服务器支持CORS: 图片服务器需要设置正确的CORS头:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
  1. 使用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
    }
}
  1. 在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)
    })
}
回到顶部