html2canvas - 项目中遇到的那些坑点汇总(更新中...)

 截图模糊

    原理就是讲canvas画布的width和height放大两倍。

  后来学习canvas的时候,才了解到这种写法不同于css的宽高设置,

  因为css里的只是展示画布显示的大小,不像这样是canvas真正的内里图画分辨率的大小。

/*图片跨域及截图模糊处理*/
      let shareContent = domObj,//需要截图的包裹的(原生的)DOM 对象
          width = shareContent.clientWidth,//shareContent.offsetWidth; //获取dom 宽度
          height = shareContent.clientHeight,//shareContent.offsetHeight; //获取dom 高度
          canvas = document.createElement("canvas"), //创建一个canvas节点
          scale = 2; //定义任意放大倍数 支持小数
      canvas.width = width * scale; //定义canvas 宽度 * 缩放
      canvas.height = height * scale; //定义canvas高度 *缩放
      canvas.style.width = shareContent.clientWidth * scale + "px";
      canvas.style.height = shareContent.clientHeight * scale + "px";
      canvas.getContext("2d").scale(scale, scale); //获取context,设置scale 
      let opts = {
          scale: scale, // 添加的scale 参数
          canvas: canvas, //自定义 canvas
          logging: false, //日志开关,便于查看html2canvas的内部执行流程
          width: width, //dom 原始宽度
          height: height,
          useCORS: true // 【重要】开启跨域配置
      };
html2canvas(shareContent,opts).then() 

  

元素设置文字阴影,截图后阴影错乱,所有元素都会有阴影

  起初以为是v1.0.0-alpha.12 最新版本的问题,后来改成5也不行,把文字阴影去掉就可以了。

  这个问题在大神的博文中有解决方案:https://blog.youkuaiyun.com/SDUST_JSJ/article/details/78122610

  

以下为针对本问题的部分摘录: 

 文本设置text-shadow截图后却没有文本阴影(2017-09-28)

  bug原因

  查看了源码,html2canvas确实处理了text-shadow,但是没有正确的处理小数,导致最后文本阴影没有显示出来。 
  具体的代码为第1762行

NodeContainer.prototype.TEXT_SHADOW_PROPERTY = /((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g;
NodeContainer.prototype.TEXT_SHADOW_VALUES = /(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g;
  解决方案

  针对这两行的正则表达式,我添加了针对小数的判断,修改后的代码如下:

NodeContainer.prototype.TEXT_SHADOW_PROPERTY = /((rgba|rgb)\([^\)]+\)(\s-?\d+(?:\.\d+)?px){0,})/g;
NodeContainer.prototype.TEXT_SHADOW_VALUES = /(-?\d+(?:\.\d+)?px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g;

  测试:

// html2canvas正则匹配
'rgb(102, 102, 102) 11.924px 11.924px 0px'.match(/((rgba|rgb)\([^\)]+\)(\s-?\d+px){0,})/g); // ["rgb(102, 102, 102)"]
"rgb(102, 102, 102) 11.924px 11.924px 0px".match(/(-?\d+px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g); // ["rgb(102, 102, 102)", "924px", "924px", "0px"]

// 修改后的正则匹配
'rgb(102, 102, 102) 11.924px 11.924px 0px'.match(/((rgba|rgb)\([^\)]+\)(\s-?\d+(?:\.\d+)?px){0,})/g); // ["rgb(102, 102, 102) 11.924px 11.924px 0px"]
"rgb(102, 102, 102) 11.924px 11.924px 0px".match(/(-?\d+(?:\.\d+)?px)|(#.+)|(rgb\(.+\))|(rgba\(.+\))/g); // ["rgb(102, 102, 102)", "11.924px", "11.924px", "0px"]

 文本阴影效果没有显示(2017-10-18)

  现象及原因

  现象: 
    部分文本设置了阴影效果,但是截图后并没有显示出来。 
  原因: 
    html2canvas库确实解析了阴影样式,但是并没有绘制,只是当做变量存起来了。 
  第2245行,解析的值是正确的:

this.renderer.fontShadow(shadows[0].color, shadows[0].offsetX, shadows[0].offsetY, shadows[0].blur);

  第3044行可以看出,只是存起来了,并没有绘制:

 this.setVariable("shadowColor", color.toString())
     .setVariable("shadowOffsetY", offsetX)
     .setVariable("shadowOffsetX", offsetY)
     .setVariable("shadowBlur", blur);
  解决方案

  使用canvas context提供的阴影方法绘制阴影: 
  第3044行,将fontShadow 函数改为如下所示:

CanvasRenderer.prototype.fontShadow = function(color, offsetX, offsetY, blur) {
  this.ctx.shadowOffsetX = offsetX;
  this.ctx.shadowOffsetY = offsetY;
  this.ctx.shadowColor = color;
  this.ctx.shadowBlur = blur;
};

CanvasRenderer.prototype.clearShadow = function() {
    this.ctx.shadowOffsetX = 0;
    this.ctx.shadowOffsetY = 0;
    this.ctx.shadowBlur = 0;
};

  

文本描边和阴影同时显示时显示不正常(2017-10-18)

  现象及原因

  现象: 
    阴影特别严重,甚至看起来有点模糊。 
  原因: 
    和canvas context何时调用strokeText方法有关。具体原因在解决方案中描述。

  解决方案(2017-10-19修改)

  第2251行第2242行改为如下所示代码:

this.renderer.font(container.parent.color('color'), container.parent.css('fontStyle'), container.parent.css('fontVariant'), weight, size, family);
    // if (shadows.length) {
    //     // TODO: support multiple text shadows
    //     this.renderer.fontShadow(shadows[0].color, shadows[0].offsetX, shadows[0].offsetY, shadows[0].blur);
    // } else {
    //     this.renderer.clearShadow();
    // }

    this.renderer.clip(container.parent.clip, function() {
        textList.map(this.parseTextBounds(container), this).forEach(function(bounds, index) {
            if (bounds) {
                if (shadows.length) {
                  this.renderer.fontShadow(shadows[0].color, shadows[0].offsetX, shadows[0].offsetY, shadows[0].blur);
                  this.renderer.text(textList[index], bounds.left, bounds.bottom);
                  this.renderer.clearShadow();
                  this.renderTextStroke(textList[index], container.parent, bounds, this.fontMetrics.getMetrics(family, size));
                  this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size));
                } else {
                  this.renderer.text(textList[index], bounds.left, bounds.bottom);
                  this.renderTextStroke(textList[index], container.parent, bounds, this.fontMetrics.getMetrics(family, size));
                  this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size));
                }
            }
        }, this);
    }, this);

  如果有阴影,一开始就渲染stroke,之后的内容会覆盖一部分stroke的内容;如果没有阴影,最后渲染stroke,stroke会覆盖filltext函数渲染的内容。 
  先渲染text,如果有阴影,同时渲染阴影,然后将阴影效果去掉;如果有描边,渲染描边效果。经确认,这种写法比之前的写法要好。(2017-10-19)

  以上摘自:

  csdn   https://blog.youkuaiyun.com/SDUST_JSJ/article/details/78122610

  作者: kylin_zdd1993

 

水平居中的元素截图后向左跑偏

  明明是水平居中的代码,截图出来的会偏左,结构是左图片右文字,有时候是图片自己跑到最左边,有时候是整体偏左一点点
  这个问题也不是经常遇到,场景是父div元素text-align=center;内部两个子元素设为display:inline-block的模式。然后画图就会出现左边的div偏左靠或直接在左边的情况。
  问题未解决,出现时也没研究因为啥,等有时间的时候就不出现了。。。

 

靠背景图露脸的dom们会有底线。即如果元素使用背景图呈现,那么截图完毕会有一条下边线
  截图时,如果有一个dom元素是用背景图填充的,里边没有任何结构,那么截图出来的底部会有一条和背景图底部一致的一条线

  像是背景图y轴重叠,然后差那么一像素没铺满的感觉。

   比如这样一张图:

  

  截出来长这样:

   

  项目暂时解决方法,蓝色背景用颜色不用整块的图片显示。

  这种图片普遍有一个规律就是,有投影,图片的正常高度要高于有颜色区域的高度

  如这张图:

 

  底部部分:

 

  有时候靠拉伸/压缩一点点dom元素的高度解决了,有时候又不行。

 

背景图做的元素,截图出来图也是很模糊的,设置倍数也没用。

 在iphone 7plus中,即使没有背景图截出来的还是有一条边线...

 

下边是黑色背景色+小点点,就这样的布局,一个背景色都没有,为什么截图下来还是有条线?而且还是部分手机中的ip7!

 

the operation is insecure
    canvas.toDataURL 报错 the operation is insecure
  canvas.toDataURL(type, encoderOptions);语法
  配置如:canvas.toDataURL("image/png", 0.7);
  参数type指定图片类型,如果指定的类型不被支持则以默认值image/png替代;
  encoderOptions(第二个参数)可以为image/jpeg或image/webp类型的图片设置图片质量,取值0-1,超出则以默认值0.92替代。


html2canvas在微信中base64码为空
    在微信中或者可以说在移动端浏览器里,canvas.toDataURL不成功。canvas.toDataURL(type) 得到空的 data:;
  折腾了半天。。。
  同事说如果base64码的长度有个限制,忘了超过多少就不行了,后来我尝试把放大四倍改成放大两倍,问题竟然解决了!!
  不要笑话我放大了四倍,为了清晰哈哈哈。但是改成两倍后和四倍比也没差。反倒是挖了个坑自己填了半天!

 

不可见的元素截图后是空白
    没法截图看不见的,比如opacity为0的东西,或者visibility为hidden的,更别说display:none了。都不行,
  截出来的一样是白色的,可想而知,毕竟没截上东西当然就是白色了。
  解决方法是让canvas部分隐藏到后边。最终选择方案,层级设为-1,上一层的把他盖住。

  前提是上一层要又一个可以设置的背景色,能把他盖住不被世人看到

 

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

  再在页面建立一个img元素,src=base64码,插入dom中,盖在所有元素的最上方(或者需要用户长按保存的地方),opacity设置为0。

  然后用户就长按保存,存下来的就是事先准备好的覆盖在那里的那个不可见得透明图。
  事实证明,图片透明不可见覆盖在页面上边,微信里是可以存图的。

  而很多市面上的h5,结果页和最后存下来的图不一样的,估计都是这么搞得,毕竟看不见代码

 

html2canvas+jsbridge同时存两张图
    html2canvas和jsbridge的存图功能协作时,会触发同时存两张图的现象。

  第一次存图很完美,如果不关掉页面第二次存图,就会存两张,以后也会存两张。只有第一次使用存图是好的。
  就是jsbridge调了两次,第二次自动调起的原因目前猜测是html2canvas引起的, 

  因为一层层定位,只有在html2canvas返回base64码后会有问题。具体原因暂没有找到。
  最后解决方法是:配合sessionStore,第一次截完图后,将图片地址存入sessionstore,

  之后判断,sessionstore里有base64码就不用html2canvas生成码了,直接取数据存图,

 

html2canvas触发时重新加载页面的所有静态资源(除js)
  css和img图像,这一点是在和Wdatapicker组合使用时发现的问题。

  本来没什么,爱加载几次加载几次,但是datapicker的样式是写在iframe里的,重新加载dom还把人家的样式给丢了。这事儿就大了
  大归大,问题根本原因没解决,还是治标不治本的在每次触发html2canvas截图保存pdf的时候,重新给datapicker绘制样式,就是这么任性!

 

html2canvas 截图跨域

  图片跨域时报错现象

  

 

  这个时候你要去看图片的header头有没有这个:

  看图片本身是否允许跨域访问:

  

  上边这个是一个允许的图片。

  下边这个不允许,就截取不到。

  

  

    这篇博文对于html2canvas跨域讲解很细致: https://blog.youkuaiyun.com/yaosir1993/article/details/76474080

  以下截取部分作者思想,主要是用于解决了本次问题的地方:
  useCORS:true 这个参数很重要,没有配置的话,依旧是不能解决问题的;
  根据现有的解决方案大致有两种:
  (1).在跨域的服务器上设置header设置为允许跨域请求。 在服务器上设置header设置允许跨域请求(采用nginx做静态资源映射) 
  (2).借助代理脚本获得外域图片的 base64 编码后的字符串
  
  关于跨域和清晰度解决方案的讲解地址:https://lengxing.github.io/
  设置header,实现跨域访问http://blog.youkuaiyun.com/enter89/article/details/51205752 

 

  解决建议:

  域名反向代理,

  图片允许跨域使用:Access-Control-Allow-Origin: *;

 

html2canvas+qrcode 截二维码被白底遮挡(有背景设置的元素截图后,背景色把图片盖住)

  html2canvas执行截图-因为页面中有一处是qrcode执行的地址转二维码,每次截图后二维码都截不下来,那一块就是一个白块.

  按理说二维码图片是base后的地址不应该啊。

  后来把二维码img的外部div元素的背景色设置半透明,二维码就隐约能看出来了,原来是div的背景色盖住了img。
  原理还是搞不明白,明明层级都设置了还不起作用,竟然被自己的爹给盖住也是醉了。
  二维码处之所以为白色是因为外部结构的白色背景给覆盖了,最后是盛放二维码img的外部div结构不设置背景色就解决了


html2canvas截图时,背景音乐在IOS11下会重复播放
  解决方法见博文:https://blog.youkuaiyun.com/lerayZhang/article/details/79207468

 

震惊!html2canvas截图,省略号失踪?!

     2018-09-27 17:49:09

  这种情况,之前同事遇到过,问我我说没遇到过,后来找产品协调不要省略号。然后也没当回事。

    最近又被博友问起,我刚好在做类似项目,就顺手模拟了一下效果,如下:

   

  然后不出意料的出现了几个堪比车祸现场的问题:
  请看三种的依次截图效果:
  

  

  

 

  其一当然是本问题主题,即 省略号丢失的问题
  其二请观察图二,你会发现, 用了padding的元素,他的截图中,左padding还在,右padding没了,而是被文字给填充了.
 
  先说回省略号的问题,我猜想和canvas机制有关,
  因为毕竟canvas里边绘制文字不会换行,
  然后html2canvas可能是获取文本进行的fillText/strokeText()的绘制,而省略号并不是实际dom结构中的文本。所以获取不到?
 
  突发奇想, 那伪类里边的content的内容他可以拿到吗?答案是可以。
  在图三中,我将省略号作为伪类的内容, 利用伪类模拟超出显示省略号的效果进行截图,最后省略号截了下来.
  加上以往经验可以说明,内容放在伪类中也是可以被拿到的。所以我刚才  对于伪类不能被截下来的设想可以消灭。放心大胆的用伪类吧!
 
  但是但是,问题还是没解决额, 这种模拟的效果太脆弱了吧!
  稍微文字多一个少一个标点,最后边文字会因为 overflow:hidden;被截成半块。你看

  

  所以在这里只是为了抛转引玉,
  有了这个模拟省略号的思路后,不知道各位看官大佬们还有更好的方法解决这个问题嘛?
  可以做到既不让省略号消失,也不让实际文字内容被劈成两半?
  
  抛砖引玉的代码:
 1 h5 一、有省略号无padding的正常情况
 2         .box#targetEleId1
 3           .text-box 1、为了出现省略号,我是一大段文字我为了出现省略号,我是一大段文字我
 4         #btn1 点击我
 5         h5 二、有省略号。加了padding的正常情况
 6         .box#targetEleId2
 7           .text-box.text-box2 2、为了出现省略号,我是一大段文字我为了出现省略号,我是一大段文字我
 8         #btn2 点击我
 9         h5 三、省略号用伪类模拟的情况
10         .box#targetEleId3
11           .text-box3 3、为了出现省略号我是一大段文字我为了出现省略号,我是一大段文字我
12         #btn3 点击我
13         style.
14           h5{
15             margin-top:30px;
16           }
17           .text-box{
18             margin-right: .2rem;
19             overflow: hidden;
20             text-overflow: ellipsis;
21             white-space: nowrap;
22             background: #c3e2c3;
23           }
24           .text-box2{
25             padding: 1rem;
26           }
27           #targetEleId3{
28             background: #c3e2c3;
29             position: relative;
30           }
31           #targetEleId3:after{
32             content: "...";
33             position:absolute;
34             right: 0.1rem;
35             top: 0;
36             display: inline-block;
37           }
38           .text-box3{
39             overflow: hidden;
40             padding-right: .2rem;
41             margin-right: 0.3rem;
42             white-space: nowrap;
43           }
44           body{
45             padding-bottom: 1rem;
46           }
html+css

   随便写的js:

import {html2img} from '../html2img' 
// 引入html2canvas封装代码:html2img
const oBtn1 = document.getElementById('btn1');
const  targetEleId1 = document.getElementById('targetEleId1');
const oBtn2 = document.getElementById('btn2');
const  targetEleId2 = document.getElementById('targetEleId2');
const oBtn3 = document.getElementById('btn3');
const  targetEleId3 = document.getElementById('targetEleId3');
oBtn1.onclick = function(){
  html2img({
    targetEleId: targetEleId1,
    imgType: 'jpg',
    titleStr: '自定义图片名称_当前时间戳'
  },false)
  .then((imgUrl)=>{
  // 拿到返回值:base64后的图片地址:imgUrl。执行其他逻辑
    var myImg = document.createElement('img');
    myImg.src=imgUrl;
    myImg.style.marginBottom=100+'px';
    myImg.style.marginLeft=10+'px';
    document.body.appendChild(myImg)
  })
};
oBtn2.onclick = function(){
  html2img({
    targetEleId: targetEleId2,
    imgType: 'jpg',
    titleStr: '自定义图片名称_当前时间戳'
  },false)
  .then((imgUrl)=>{
  // 拿到返回值:base64后的图片地址:imgUrl。执行其他逻辑
    var myImg = document.createElement('img');
    myImg.src=imgUrl;
    myImg.style.marginBottom=100+'px';
    myImg.style.marginLeft=10+'px';
    document.body.appendChild(myImg)
  })
};
oBtn3.onclick = function(){
  html2img({
    targetEleId: targetEleId3,
    imgType: 'jpg',
    titleStr: '自定义图片名称_当前时间戳'
  },false)
  .then((imgUrl)=>{
  // 拿到返回值:base64后的图片地址:imgUrl。执行其他逻辑
    var myImg = document.createElement('img');
    myImg.src=imgUrl;
    myImg.style.marginBottom=100+'px';
    myImg.style.marginLeft=10+'px';
    document.body.appendChild(myImg)
  })
};

  

 

 

  

 

 

 

 

 

重点说明:

  经过这几次的html2canvas填坑记,我发现,使用html2canvas@1.0.0-alpha.5版本,配套上我们自己封装的html2img,总算坑可以少点了。正常的需求还是可以实现了。

  另外,我是女的,加QQ别上来就喊哥们儿了[捂脸]。虽然我比较汉子,但我不想真汉哈哈哈~

  2018-06-25  17:54:43  (持续更新中...)

转载于:https://www.cnblogs.com/padding1015/p/9225517.html

JavaScript HTML renderer The script allows you to take "screenshots" of webpages or parts of it, directly on the users browser. The screenshot is based on the DOM and as such may not be 100% accurate to the real representation as it does not make an actual screenshot, but builds the screenshot based on the information available on the page. How does it work? The script renders the current page as a canvas image, by reading the DOM and the different styles applied to the elements. It does not require any rendering from the server, as the whole image is created on the clients browser. However, as it is heavily dependent on the browser, this library is not suitable to be used in nodejs. It doesn't magically circumvent any browser content policy restrictions either, so rendering cross-origin content will require a proxy to get the content to the same origin. The script is still in a very experimental state, so I don't recommend using it in a production environment nor start building applications with it yet, as there will be still major changes made. Browser compatibility The script should work fine on the following browsers: Firefox 3.5+ Google Chrome Opera 12+ IE9+ Safari 6+ As each CSS property needs to be manually built to be supported, there are a number of properties that are not yet supported. Usage Note! These instructions are for using the current dev version of 0.5, for the latest release version (0.4.1), checkout the old readme. To render an element with html2canvas, simply call: html2canvas(element[, options]); The function returns a Promise containing the <canvas> element. Simply add a promise fullfillment handler to the promise using then: html2canvas(document.body).then(function(canvas) { document.body.appendChild(canvas); }); Building The library uses grunt for building. Alternatively, you can download the latest build from here. Clone git repository with submodules: $ git clone --recursive git://github.com/niklasvh/html2canvas.git Install Grunt and uglifyjs: $ npm install -g grunt-cli uglify-js Run the full build process (including lint, qunit and webdriver tests): $ grunt Skip lint and tests and simply build from source: $ grunt build Running tests The library has two sets of tests. The first set is a number of qunit tests that check that different values parsed by browsers are correctly converted in html2canvas. To run these tests with grunt you'll need phantomjs. The other set of tests run Firefox, Chrome and Internet Explorer with webdriver. The selenium standalone server (runs on Java) is required for these tests and can be downloaded from here. They capture an actual screenshot from the test pages and compare the image to the screenshot created by html2canvas and calculate the percentage differences. These tests generally aren't expected to provide 100% matches, but while commiting changes, these should generally not go decrease from the baseline values. Start by downloading the dependencies: $ npm install Run qunit tests: $ grunt test Examples For more information and examples, please visit the homepage or try the test console. Contributing If you wish to contribute to the project, please send the pull requests to the develop branch. Before submitting any changes, try and test that the changes work with all the support browsers. If some CSS property isn't supported or is incomplete, please create appropriate tests for it as well before submitting any code changes.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值