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.csdn.net/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.csdn.net/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.csdn.net/yaosir1993/article/details/76474080
以下截取部分作者思想,主要是用于解决了本次问题的地方:
useCORS:true 这个参数很重要,没有配置的话,依旧是不能解决问题的;
根据现有的解决方案大致有两种:
(1).在跨域的服务器上设置header设置为允许跨域请求。 在服务器上设置header设置允许跨域请求(采用nginx做静态资源映射)
(2).借助代理脚本获得外域图片的 base64 编码后的字符串
关于跨域和清晰度解决方案的讲解地址:https://lengxing.github.io/
设置header,实现跨域访问http://blog.csdn.net/enter89/article/details/51205752
解决建议:
域名反向代理,
图片允许跨域使用:Access-Control-Allow-Origin: *;
html2canvas+qrcode 截二维码被白底遮挡(有背景设置的元素截图后,背景色把图片盖住)
html2canvas执行截图-因为页面中有一处是qrcode执行的地址转二维码,每次截图后二维码都截不下来,那一块就是一个白块.
按理说二维码图片是base后的地址不应该啊。
后来把二维码img的外部div元素的背景色设置半透明,二维码就隐约能看出来了,原来是div的背景色盖住了img。
原理还是搞不明白,明明层级都设置了还不起作用,竟然被自己的爹给盖住也是醉了。
二维码处之所以为白色是因为外部结构的白色背景给覆盖了,最后是盛放二维码img的外部div结构不设置背景色就解决了
html2canvas截图时,背景音乐在IOS11下会重复播放
解决方法见博文:https://blog.csdn.net/lerayZhang/article/details/79207468
震惊!html2canvas截图,省略号失踪?!
2018-09-27 17:49:09
这种情况,之前同事遇到过,问我我说没遇到过,后来找产品协调不要省略号。然后也没当回事。
h5 一、有省略号无padding的正常情况
.box#targetEleId1
.text-box 1、为了出现省略号,我是一大段文字我为了出现省略号,我是一大段文字我
#btn1 点击我
h5 二、有省略号。加了padding的正常情况
.box#targetEleId2
.text-box.text-box2 2、为了出现省略号,我是一大段文字我为了出现省略号,我是一大段文字我
#btn2 点击我
h5 三、省略号用伪类模拟的情况
.box#targetEleId3
.text-box3 3、为了出现省略号我是一大段文字我为了出现省略号,我是一大段文字我
#btn3 点击我
style.
h5{
margin-top:30px;
}
.text-box{
margin-right: .2rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
background: #c3e2c3;
}
.text-box2{
padding: 1rem;
}
#targetEleId3{
background: #c3e2c3;
position: relative;
}
#targetEleId3:after{
content: "...";
position:absolute;
right: 0.1rem;
top: 0;
display: inline-block;
}
.text-box3{
overflow: hidden;
padding-right: .2rem;
margin-right: 0.3rem;
white-space: nowrap;
}
body{
padding-bottom: 1rem;
}
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 (持续更新中...)
html2canvas - 项目中遇到的那些坑点汇总(更新中...)的更多相关文章
- 网站开发进阶(二十二)HTML UI知识汇总(更新中...)
HTML知识汇总(更新中...) 1.<iframe> 标签 浏览器支持 所有浏览器都支持 <iframe> 标签. 定义和用法 iframe 元素会创建包含另外一个文档的内联 ...
- 在 Visual Studio 2013 中创建 ASP.NET Web 项目(0):专题导航 [持续更新中]
写在前面的话 随着 Visual Studio 2013 的正式推出,ASP.NET 和 Visual Studio Web 开发工具 也发布了各自的最新版本. 新版本在构建 One ASP.NET ...
- 小程序 - API 踩坑记录(更新中...)
API 小程序API结构导览图: 声明: 请尊重博客园原创精神,转载或使用图片请注明: 博主:xing.org1^ 出处:http://www.cnblogs.com/padding1015/
- dubbo初认知(dubbo和springCloud关系,在微服务架构中的作用等)(持续更新中)
一:dubbo是什么? dobbuo是阿里开源的一个高性能优秀的服务框架, 可通过高性能的 RPC 实现服务的输出和输入功能,使得应用可以和 高性能的rpc实现输入和输出的功能,可以了 Spring ...
- iOS中容易混淆的知识点(持续更新中)
1.成员变量和属性的区别 @interface Person : NSObject { NSString *_sex; } @property (nonatomic, copy) NSString * ...
- CEUtils---我在Unity中使用的一些小类库(不断更新中)
项目地址: http://git.oschina.net/eran/CEUtils
- Ubuntu小点汇总,更新中...
转自:http://blog.csdn.net/zxz_tsgx/article/details/39713627 昨天重装了Ubuntu14.04 64位版,又被一些基础操作/设置给搞怕了,以前安装 ...
- Java中的那些名词术语(不断更新中)
在工作和学习中,总会遇到各种术语.岁月不饶人,记忆力越来越下降.在这里记录下那些曾经关注过学习过的东西. POJO: Plain Old Java Object DI: Dependency Inje ...
- JS方法 - 字符串处理函数封装汇总 (更新中...)
一.计算一段字符串的字节长度 字符串的charCodeAt()方法, 可返回字符串固定位置的字符的Unicode编码,这个返回值是0-65535之间的整数,如果值<=255时为英文,反之为中文. ...
随机推荐
- CentOS 7系统查看系统版本和机器位数
前言 由于不经常使用linux,每当使用的时候就是安装软件,安装软件的时候就要选择安装包平台,是32位的还是64位的.这时候突然发现不知道怎么查,于是百度.虽然轻而易举百度出来,但仍旧没有自己的笔记看 ...
- 解决iredmail下postfix发送邮件时报错[need fully-qualified hostname]
iredmail配置好后,尝试从一客户端的OE中发送邮件,结果报错,在mail主机中查看tail /var/log/maillog,发现如下错误信息: Oct :: mail2 postfix/smt ...
- 一键切换hosts文件
1.新建文件host.bat 2.代码 @echo off cd.>C:\Windows\System32\drivers\etc\hosts echo .本地环境 .线上测试环境 ,切换Hos ...
- 【Jupyter notebook】access remotly
http://jupyter-notebook.readthedocs.io/en/latest/public_server.html
- JSP转发和重定向的区别
重定向: response.sendRedirect("地址"); a. 页面地址显示最终页面 b. 不可向后传递参数 c. 跳到外 ...
- kettle教程二
转载:http://www.cnblogs.com/limengqiang/archive/2013/01/16/KettleApply2.html 1.应用场景 这里简单概括一下几种具体的应用场景, ...
- oracle创建HR示例数据库脚本hr_main.sql分享
需求描述: 今天一同事想要在测试库上进行SQL练习,帮忙安装下这个示例数据库,在此记录下. 操作过程: 1.上传hr_main.sql脚本(10g 11g都可用) 脚本下载链接: https://pa ...
- BIOS、EFI与UEFI详解
https://blog.csdn.net/Scythe666/article/details/79708293
- 8 -- 深入使用Spring -- 4...1 为什么需要AOP
8.4.1 为什么需要AOP AOP专门用于处理系统中分布于各种模块(不同方法)中的交叉关注点的问题,在Java EE应用中,常常通过AOP来处理一些具有横切性质的系统级服务,如事务管理.安全检查.缓 ...
- flexbox父盒子flex-direction属性
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...