zoukankan      html  css  js  c++  java
  • 用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);                
    
                    }
                },
                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最大,确保用户长按到图片

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

  • 相关阅读:
    关于做项目
    不一样的Android studio
    你认为一些军事方面的软件系统采用什么样的开发模型比较合适?
    关于Android studio
    面向对象建模所用图的简单总结
    浅谈Android 01
    用例图与类图的联系与区别
    面向过程(或者叫结构化)分析方法与面向对象分析方法到底区别在哪里?请根据自己的理解简明扼要的回答。
    你认为一些军事方面的软件系统采用什么样的开发模型比较合适?
    项目答辩后的感想
  • 原文地址:https://www.cnblogs.com/GoTing/p/12343482.html
Copyright © 2011-2022 走看看