用html2canvas转html为图片遇到的那些问题

1.图片跨域问题

在html转化为canvas在转化成图片地址的 时候 canvas.toDataURL("image/png")

遇到报错:

Access to image at 'png' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.

或者

Access to image at 'www.baidu.com/GT/github/hotelAdmin/img/tempalte-top.png' from origin 'null' has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https.

报错原因 就是 图片 跨域 污染了画布,导致画布不能导出img的地址

在网上找方法 

设置:

            useCORS: true, //(图片跨域相关)
            allowTaint: false, //允许跨域(图片跨域相关

$('#div').click(function () {
        html2canvas(template, {
            onrendered: function (canvas) {
              
                    exportCanvasAsPNG(canvas, 'invoice.png')
              
            },
            useCORS: true, //(图片跨域相关)
            allowTaint: false, //允许跨域(图片跨域相关)
            x: 0,
            y: window.pageYOffset,
            windowWidth: document.body.scrollWidth,
            windowHeight: document.body.scrolHeight,
        });
    })

  但是并没有效果

追其根本 是图片跨域的问题

跨域怎么解决

1.设置请求头 Access-Control-Allow-Origin: *;

 

这个需要 图片服务器 那边去设置,这个无法验证是否好用,因为我们服务端说 弄不了这个 所以 pass

2.既然跨域,那我统一域名就可以了 ,再激进一点把文件直接写进代码里

   将图片源码转成blob文件对象,然后用URL.createObjectURL()方法转换成img src可用的地址,然后再绘制在canvas上,在和html一起导出toDataURL,转成图片

怎么做

1.获取图片源码

我这里两张图片是静态图片,不涉及动态,所以 我直接在线转了base64码   在线转base64

2.将跨域的图片转成blob文件对象

 

    //将base64转换为文件对象
    function dataURLtoFile(dataurl, filename) {
        var arr = dataurl.split(',');
        var mime = arr[0].match(/:(.*?);/)[1];
        var bstr = atob(arr[1]);
        var n = bstr.length;
        var u8arr = new Uint8Array(n);
        while (n--) {
            u8arr[n] = bstr.charCodeAt(n);
        }
        //转换成file对象
        // return new File([u8arr], filename, { type: mime });
        //转换成成blob对象
        return new Blob([u8arr], { type: mime });
    }

3.将blob图片对象通过URL.createObjectURL(‘图片blob对象’)转化成图片地址,赋值在img的src上

   $('.top-img').attr('src',URL.createObjectURL(imgfile))
4.进行绘制canvas,此时canvas不会在报错 能够完整绘制整个html
html2canvas(template, {
            onrendered: function (canvas) {
                  
                  var imgURL = canvas.toDataURL( "image/png"); 
这个时候就可以正常执行toDataURL方法了
                   // 导出图片
                    exportCanvasAsPNG(canvas, 'invoice.png')
              
            },
            useCORS: true, //(图片跨域相关)
            allowTaint: false, //允许跨域(图片跨域相关)
            x: 0,
            y: window.pageYOffset,
            windowWidth: document.body.scrollWidth,
            windowHeight: document.body.scrolHeight,
        });

2.绘制出来是空白区域(不可见内容不可绘制)

有很多时候,我们所要绘制的内容是不能展示出来的,需求是需要直接导出,不需要让用户看到绘制的画布以及内容

这时候 一般做的处理 将所需要描述的内容区隐藏起来,但是一旦隐藏以后,就会发现,绘制出来时是一片空白,这是由于不可见内容不可绘制

什么情况下,是不能绘制的不可见内容:

  1.display:none

  2.opacity:0

但是由于需要隐藏 该怎么弄呢 解决方案

  1.将需要绘制的div fixed定位,注意要定位在 top:0, left:0,保证内容区能在可是区域内容,

  2.然后利用z-index来隐藏,这样需要上层有一个遮罩层,需要带背景的层来遮罩住下面的内容

3.超过屏幕的内容绘制出来的部分为空白

 解决:设置windowHeight的高度等于页面包含滚动条的高度,这样滚动中的内容也会被截取出来

 html2canvas(template, {
            onrendered: function (canvas) {
              
                    exportCanvasAsPNG(canvas, 'invoice.png')
              
            },
            useCORS: true, //(图片跨域相关)
            allowTaint: false, //允许跨域(图片跨域相关)
            x: 0,//页面在横向方向上的滚动距离  横向上没有超过 所以设置为0
            y: window.pageYOffset,//页面在垂直方向上的滚动距离 设置了以后 超过一屏幕的内容也可以截取
            windowWidth: document.body.scrollWidth,//获取在x轴上滚动条中内容
            windowHeight: document.body.scrolHeight,//获取在y轴上滚动条中内容
        });

 

 

不设置设置width、height,就是默认template (被截取的dom元素)$(dom) 的宽高

4.背景图片虚化,模糊

当要截图的dom中,有元素有背景图,截取完以后 就会发现 背景图比较模糊,和正常img标签的图片清晰度要差很多

解决办法:将背景图,换成img标签,定位显示出来 

5.文字阴影  text-shadow没有正常显示的问题

解决方案:https://blog.csdn.net/SDUST_JSJ/article/details/78122610

这篇文章还讲述了 文字描边,下划线的问题,在这里就不进行试验和重复讲述了,直接附上地址,方便以后查找

6.html2canvas截图时,背景音乐在IOS11下会重复播放

  解决方法见博文:https://blog.csdn.net/lerayZhang/article/details/79207468

7.关于使用svg解决一下样式上不兼容的问题 利用box-shadow不支持的问题

这里有个博客有写到,因为我没有这个需求 所以 只是找了解决方案,并没有实际性操作:https://www.cnblogs.com/aigeileshei/p/9111925.html 中下篇的位置

8.清晰度问题

一般情况下,清晰度不够的情况下,一般采用绘制2倍图,就是绘制的内容 放大两倍,移动端一般转换的时候需要

 

设置屏幕像素比()

 var c_width = $('.box').outerWidth();//如果box设置了padding,需要获取outerWidth和outerHeight来赋给canvas;
        var c_height =$('.box').outerHeight();

        var canvas = document.createElement("canvas");
        var context = canvas.getContext("2d");

    //以下代码是获取根据屏幕分辨率,来设置canvas的宽高以获得高清图片
        // 屏幕的设备像素比
        var devicePixelRatio = window.devicePixelRatio || 2;

        // 浏览器在渲染canvas之前存储画布信息的像素比
        var backingStoreRatio = context.webkitBackingStorePixelRatio ||
            context.mozBackingStorePixelRatio ||
            context.msBackingStorePixelRatio ||
            context.oBackingStorePixelRatio ||
            context.backingStorePixelRatio || 1;

        // canvas的实际渲染倍率
        var ratio = devicePixelRatio/backingStoreRatio;

        canvas.width = c_width * ratio;
        canvas.height = c_height * ratio;
        canvas.style.width = c_width + "px";
        canvas.style.height = c_height + "px";
      
        var transTop = $(document).scrollTop() - $('.card_box').offset().top;//获取div垂直方向的位置
    
        context.scale(ratio,ratio);
        context.translate((c_width-$(window).width())/2,transTop) //canvas的位置要保证与div位置相同。

    //高清图设置完成
    
   //解决跨域,将跨域图片路径转为base64格式
    var img = new Image();
    var canvas2 = document.createElement('canvas');
    var ctx = canvas2.getContext('2d');
    img.crossOrigin = 'Anonymous';
    img.src=$('#ossImg').attr('src);
    img.onload = function () {
        canvas2.height = img.height;
        canvas2.width = img.width;
        ctx.drawImage(img, 0, 0);
        var dataURL = canvas2.toDataURL('image/png');
        $('#ossImg').attr('src',dataURL);
        canvas2 = null;

       //重新给img赋值成功后,执行截图方法
        getCard()

    }

    function getCard(){
      html2canvas($(".box"),{
            allowTaint:true,
            useCORS:true,
            canvas:canvas,
            onrendered:function(canvas){
                dataURL =canvas.toDataURL("image/png");
                var img = new Image();
                img.src=dataURL;
                img.className = 'cardImg';
                img.onload = function () {           
                    $(".card").append(img);                

                }
            },
            width:c_width,
            height:c_height
        })
   } 

  关于清晰度 这里是深入讲解方法:https://www.cnblogs.com/GoTing/p/12850029.html

额外补充:

  base64码限制

    在微信中或者可以说在移动端浏览器里,canvas.toDataURL不成功。canvas.toDataURL() 得到空的 data:base64码的长度有个限制,可以换清晰度,图片大小小一点的图片转换

  微信里的长按存图功能
    先用html2canvas拿到一个html转为canvas的base64码,

    再在页面建立一个img元素,src=图片base64码,opacity设置为0,设置z-index最大,确保用户长按到图片

    这样长按保存的图片就是覆盖在上面的那个图片

 9.图片出现白边

一般出现这个问题是 1.0版本出现的,1.0绘制出来的图片会清晰很多,应该是绘制了二倍图,在进行缩放,所以导致了白边的出现。

解决:

1.添加属性 

backgroundColor: null,

  使用这个可以使绘制出来的图片白边的地方,变成透明,实际还是有因为缩放导致的位移偏移,但是图片看不出来

2.微调

  对宽高,位移进行像素移动

height: template.offsetHeight-1,
width: template.offsetWidth-1,

 

posted @ 2020-02-21 22:31  明媚下雨天  阅读(8342)  评论(0编辑  收藏  举报