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)
        }
相关推荐
Mh2 小时前
别再只会 `find` 了:Map 在前端业务里的真实用法
前端·javascript
陈随易2 小时前
FFmpeg 9.0 发布,代号 Lei,音视频处理再升级
前端·后端·程序员
爱丶狸3 小时前
Grafana_Zabbix_ImageRenderer_部署与前端操作手册
linux·前端·zabbix·grafana·kylin
用户059540174465 小时前
把AI对话记忆存储测试从手工改成Playwright+pytest,覆盖率从20%提到96%,回归时间缩短90%
前端·css
kyriewen5 小时前
别再这样写TypeScript了——Code Review中最常见的8个反模式
前端·javascript·typescript
名字还没想好☜6 小时前
Next.js ‘use client‘ 到底加在哪:Server/Client Components 边界与常见报错
开发语言·前端·javascript·react·next.js
午安~婉6 小时前
GitHub Token/ GitHub Stats统计显示图异常
前端·github·vercel·github token
码云之上6 小时前
AI Agent 工程化总览篇:从 Prompt 到 Harness
前端·人工智能
2501_926978336 小时前
以说明书 DNA 为模板——完整 AGI 的结构图景
前端·人工智能·经验分享·笔记·ai写作
IT_陈寒6 小时前
Vite静态资源引用这个坑我踩得有点疼
前端·人工智能·后端