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)
        }
相关推荐
Lupino9 分钟前
被 React “玩弄”的 24 小时:为了修一个不存在的 Bug,我给大模型送了顿火锅钱
前端·react.js
米丘15 分钟前
了解 Javascript 模块化,更好地掌握 Vite 、Webpack、Rollup 等打包工具
前端
Heo17 分钟前
深入 React19 Diff 算法
前端·javascript·面试
滕青山18 分钟前
个人所得税计算器 在线工具核心JS实现
前端·javascript·vue.js
小怪点点18 分钟前
手写promise
前端·promise
国思RDIF框架27 分钟前
RDIFramework.NET Web 敏捷开发框架 V6.3 发布 (.NET8+、Framework 双引擎)
前端
Mintopia28 分钟前
如何在有限的时间里,活出几倍的人生
前端
炫饭第一名29 分钟前
速通Canvas指北🦮——变形、渐变与阴影篇
前端·javascript·程序员
Neptune130 分钟前
让我带你迅速吃透React组件通信:从入门到精通(上篇)
前端·javascript
阿懂在掘金30 分钟前
Vue 表单避坑(一):为什么 v-model 绑定对象属性会偷偷修改父组件数据?
前端·vue.js