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)
        }
相关推荐
喜欢你,还有大家24 分钟前
FTP文件传输服务
linux·运维·服务器·前端
该用户已不存在28 分钟前
你没有听说过的7个Windows开发必备工具
前端·windows·后端
Bi39 分钟前
Dokploy安装和部署项目流程
运维·前端
普通网友41 分钟前
前端安全攻防:XSS, CSRF 等防范与检测
前端·安全·xss
携欢44 分钟前
PortSwigger靶场之Reflected XSS into attribute with angle brackets HTML-encoded通关秘籍
前端·xss
小爱同学_1 小时前
React知识:useState和useRef的使用
前端·react.js
再学一点就睡1 小时前
双 Token 认证机制:从原理到实践的完整实现
前端·javascript·后端
wallflower20201 小时前
滑动窗口算法在前端开发中的探索与应用
前端·算法
蚂蚁绊大象1 小时前
flutter第二话题-布局约束
前端
龙在天1 小时前
我是前端,scss颜色函数你用过吗?
前端