canvas生成海报图片并下载

canvas生成海报图片并下载_第1张图片
生成海报

最近接到一个需求,需要将页面链接生成二维码,当用户点击分享海报时自动生成一张图片,并且下载到本地。

页面主页功能在三个地方

  • 当前链接生成二维码
  • 需要页面的图片onload之后,确保所有图片都加载完成
  • 页面转图片
  • 下载图片
  • canvas把图片转成base64时的空白(跨域)问题

当前链接生成二维码

当前有很多封装好的js库可以将文本生成二维码,我使用到的是jquery.qrcode.js。有兴趣的百度一下。主体代码

页面转成图片(JS截屏)以及下载

emememem....第一步直接想到了canvas,不过要是用原生方法直接画完整个页面,非常耗时耗力。非常推荐一个好用的canvas工具库html2cavas。其主要功能在于将页面转为canvas,减少了画canvas的复杂度,直接用html布局好转成canvas就好,亲民易用。
展示主体代码
npm install --save html2canvas或者yarn add html2canvas
HTML部分


内容部分
下载海报
import html2canvas from "html2canvas";
let oA = document.querySelector("#downLoadBtn");
// 将`body`节点截取变为canvas
html2canvas(document.querySelector("body"), {
    dpi: window.devicePixelRatio * 2, // 对应屏幕的dpi,适配高清屏,解决canvas模糊问题
    scale: 2, // 缩放
    allowTaint: true, // 是否使用图片跨域
    useCORS: true, // 是否使用图片跨域
    // y: window.scrollY // 根据滚动条来截取--主要用于截取某一个区域
}).then(canvas =>{
    // canvas参数为生成的canvas的dom节点,可以对其进行dom操作

    // 下载功能
    // 设置a标签的download属性,点击a标签变为下载
    oA.download = '文件名',  // 设置下载的文件名
    let url = canvas.toDataURL("image/png"); // canvas转png(base64)
    oA.href = url; // a标签的url对应图片base64
});

 document.querySelector("#downLoadBtn").click(); // 点击a标签,下载

如果用script引入,可以到html2cavas官网下载js文件,需要注意的是,使用方法需要修改为:

html2canvas(document.querySelector("body"), {
    dpi: window.devicePixelRatio * 2, // 对应屏幕的dpi,适配高清屏,解决canvas模糊问题
    scale: 2, // 缩放
    allowTaint: true, // 是否使用图片跨域
    useCORS: true, // 是否使用图片跨域
    // y: window.scrollY // 根据滚动条来截取--主要用于截取某一个区域
    onrendered: function(canvas) {
        // 返回canvas节点
    }
});

更多参数看这里html2cavas参数文档

canvas内包含其他域名下的图片时(满足跨域条件),可能会出现以下问题

  • canvas在转换成base64图片时,会出现空白部分,这其实是canvas中图片的跨域问题(What,图片还能跨域!!!),跨域图片会默认转成空白

canvas在执行canvas.toDataURL时会判断图片是否跨域(本质和ajax跨域相同),如果跨域则会报出下列错误:巴拉巴拉xxxxx图片污染了canvas之类的,这是浏览器的保护机制,防止图片携带危险信息

Uncaught SecurityError: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

解决办法:

1.如果使用到了html2canvas,那么html2canvas内有一个参数allowTaint(是否允许画跨域图片),为true时,canvas会尝试请求跨域图片(如果改为false,就不会尝试,直接生成空白图片)。如果没有使用html2canvas插件,直接用原生canvas转图片时,默认跨域。
2.需要跨域请求的图片属性配置,img标签有一个不常用的属性crossOrigin,需要设置为Anonymous,表示允许跨域请求图片。要了解这个属性,可以看张鑫旭的博客

// 可以直接写在标签上



// 如果你是动态添加的图片
var img = new Image();
img.src='xxxxxx图片地址';
img.crossOrigin = "Anonymous";
// 添加img节点到页面上
body.appendChild(img);
// 如果采用原生canvas来画图片,需要在设置好crossOrigin属性和onload之后再画
img.src = 'xxx';
img.onload = function(){
  var canvas = document.querySelector("#myCanvas");
  var context = canvas.getContext("2d");
  context.drawImage(this, 0, 0);
}

3.现在图片一般储存在腾讯、阿里、七牛等OSS储存中,可以去修改对应的管理配置,除了配置对应的请求方式外,重点就是CORS的Allow-Headers配置了,可以配置允许请求的域名(配置的域名才能访问到),或者直接配置为*(允许所有源访问,不推荐)

canvas生成海报图片并下载_第2张图片
CORS配置

如果图片是存在自己本地服务器上就更简单了,找后台同学,配置好CORS就行了。
关于CORS的问题,开发中经常会遇到这个问题,需要了解的同学可以查看我的另一篇文章 web前端跨域的一些解决方案。

4.一些第三方的用户头像(微信,qq,微博等)一般都是默认允许跨域访问的

canvas绘制跨域图片可能会出现的一些其他状况

不管是用插件还是用原生canvas绘制图片,如果使用跨域图片绘制,然后生成海报图片时,会出现有时成功有时失败的问题(第一次成功,之后会失败的问题)。或者pc端浏览器调试没问题,发到线上就出现问题了。为什么呢?

使用网络图片时,浏览器会自动缓存图片,当刷新页面时绘制canvas时,使用的图片还是缓存中的图片,调用canvas转图片的方法就会失败,并且没有任何提示哦。至于pc端浏览器调试没问题,原因是浏览器端调试模式下,你可能勾选了禁用缓存这个东西,所以不受缓存图片的影响!!!!!

canvas生成海报图片并下载_第3张图片
image.png

怎么解决呢?不让浏览器使用缓存图片就ok了。
在绘制时,使用到的跨域图片路径后面加上?v=时间戳就ok了。


使用原生canvas也是同样的道理

context.drawImage(imgSrc + new Date().getTime(), x, y);

ememem,有问题留言回复就好了哦。

你可能感兴趣的:(canvas生成海报图片并下载)