web端canvas绘制海报下载分享的相关问题

大家好,我是南游。

最近遇到了使用canvas绘制分享海报的需求,在这里对开发过程中遇到的一些问题进行了整理。

1.图片的绘制是异步的,要在图片上进行内容绘制需要在背景图片绘制完成后进行绘制,即在回调里面执行。

scss 复制代码
        img.onload = () => {
            ctx.drawImage(img, 0, 0)
            //do something
        }

2.海报绘制完成时保存下载图片报错(跨域)的问题。

ini 复制代码
   <div className="poster-wrap">
       <canvas  className="canvas" id="canvas" width="375" height="820" > </canvas>
   </div>

如果使用跨域的资源画到canvas中,并且资源没有使用CORS去请求,canvas会被认为是被污染了, canvas可以正常展示,但是没办法使用[toDataURL()]或者[toBlob()])导出数据。

详情见 Allowing cross-origin use of images and canvas

因此需要在img标签上设置crossorigin,启用CORS,属性值为anonymous

ini 复制代码
        const canvas = document.getElementById('canvas')
        const ctx = canvas.getContext('2d')
        const img = new Image()
        img.crossOrigin = 'anonymous'
        img.src = 'xxxxxxx'
        img.onload = () => {
            ctx.drawImage(img, 0, 0)
        }

添加crossOrigin="anonymous"允许跨域后图片却无法显示了,依然报错跨域,此时需要在服务端配置跨域设置

因为我的图片是放在阿里云上的,因此需要在阿里云的oss跨域设置里进行配置,允许 *.test.com 跨域。详情见

设置成功后可以在f12上看请求静态资源的响应头,如果响应头里面带了Access-Control-Allow-Origin域名,那么浏览器就允许跨域访问。

图片已经通过img标签加载过,浏览器默认会缓存下来,下次使用js方式再去请求,直接返回缓存的图片,如果缓存中的图片不是通过CORS请求或者响应头中不存在Access-Control-Allow-Origin,都会导致报错。使用js方式请求图片资源, 需要避免使用缓存,设置url后加上时间戳,或者http头设置Cache-Control为no-cache。

ini 复制代码
  let img = new Image()
  img.crossOrigin = 'anonymous'
  img.src = url + '?time=' + new Date().valueOf()
  img.onload = () => {
    // ... do something
  }
  img.onerror = (err) => {
    console.log(err)
  }

最后就是根据需求画好海报并下载。

ini 复制代码
        ctx.fillStyle = '#ffffff'
        ctx.font = 'bold 20px sans-serif'
        ctx.fillText('hello world', 15, 24)
        ctx.font = 'bold 10px sans-serif'
        ctx.fillText('hello', 30, 24)
javascript 复制代码
        function downloadPoster() {
            let imgSrc = canvas.toDataURL('image/png', 0.9)
            let imgName = '海报'
            let elem = document.createElement('a')
            elem.setAttribute('href', imgSrc)
            elem.setAttribute('download', imgName)
            document.body.appendChild(elem)
            elem.click()
            document.body.removeChild(elem)
        }
相关推荐
小白学习日记40 分钟前
【复习】HTML常用标签<table>
前端·html
丁总学Java1 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
yanlele1 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范
懒羊羊大王呀2 小时前
CSS——属性值计算
前端·css
xgq2 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试
用户3157476081352 小时前
前端之路-了解原型和原型链
前端
永远不打烊2 小时前
librtmp 原生API做直播推流
前端
北极小狐2 小时前
浏览器事件处理机制:从硬件中断到事件驱动
前端
无咎.lsy2 小时前
vue之vuex的使用及举例
前端·javascript·vue.js
fishmemory7sec2 小时前
Electron 主进程与渲染进程、预加载preload.js
前端·javascript·electron