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

摘要:
1.跨域图像的问题是,当html被转换为画布时,图像被转换为图像地址ToDataURL(“image/png”)遇到错误:来自源“null”的对图像“ng”的访问被CORS策略阻止:跨源请求不支持协议方案:http、data、chrome

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: *;

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

这个需要 图片服务器 那边去设置,这个无法验证是否好用,因为我们服务端说 弄不了这个 所以 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最大,确保用户长按到图片

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

免责声明:文章转载自《用html2canvas转html为图片遇到的那些问题》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇VPS性能测试(3):磁盘IO读写速度、SSD硬盘速度测试ORACLE ERROR CODE代表的意思下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

java script btoa与atob的

javascript原生的api本来就支持,Base64,但是由于之前的javascript局限性,导致Base64基本中看不中用。当前html5标准正式化之际,Base64将有较大的转型空间,对于Html5 Api中出现的如FileReader Api, 拖拽上传,甚至是Canvas,Video截图都可以实现。 好了,前言说了一大堆,Base64转码和解...

Android 的窗口管理系统 (View, Canvas, WindowManager)

http://blog.csdn.net/ritterliu/article/details/39295271 From漫天尘沙 在图解Android - Zygote 和 System Server 启动分析一 文里,我们已经知道Android 应用程序是怎么创建出来的,大概的流程是 ActivityManagerService -> Zygote...

iOS常见加密方法

*普通加密方法是讲密码进行加密后保存到用户偏好设置中 *钥匙串是以明文形式保存,但是不知道存放的具体位置 (一 )base64加密 base64编码是现代密码学的基础 基本原理: 原本是8个bit一组表示数据,改为6个bit一组表示数据,不足部分补0,每两个0用一个=表示 用base64编码之后,数据长度会改变,曾加了大约1/3/作用.(8-6)/6 ba...

js使用crypto实现md5WithRSA加密及验签

最近使用node对接一家支付三方,对方使用的是java 要求使用RSA加密 使用的算法是 md5WithRSA  encoding是utf8 输出是base64 在使用crypto-js和node-rsa无果后 查阅了node官方文档的crypto找到了答案  createSign方法传入加密算法创建一个sign对象,当然算法不是全部都支持的   使用...

HTML5 canvas游戏工作原理

HTML5已经不是一个新名词。它看上去很cool,有很多feature,大多数人普遍看好它的发展。对于我来说,最感兴趣的是它的canvas标签,可以结合Javascript来绘制游戏画面。 我们可以在Javascript脚本中获得页面中的canvas对象,以及它的绘图上下文: var canvas = document.getElementById("ca...

如何给小程序页面加载一张背景图片

我们知道,在PC端,想在一个页面插入一张背景图,只需要如下属性即可。 background-image: url("../images/photo.png"); 在小程序里面,如此做法就行不通了,图片不但不会显示而且还会报错了 pages/index/index.wxss 中的本地资源图片无法通过 WXSS 获取,可以使用网络图片,或者 base64,...