html2canvas库使用中出现的问题及解决方案
来源:互联网 发布:2017大数据的发展现状 编辑:程序博客网 时间:2024/03/29 21:35
注
- 本人使用的html2canvas是从github上下载的,版本为0.5.0-beta3。
本文会继续更新,以后html2canvas库发现的所有问题都会更新在本文中。- html2canvas问题太多,不再使用了,使用phantomjs替代。(2017-10-19)
1.1 文本设置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"]
1.2. 文本阴影效果没有显示(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;};
2. 没有跨域,ios上的图片截图却无法显示(2017-09-28)
现象及原因
现象:
编写微信公众号页面,页面上有一张LOGO图片和一张二维码图片,在Android和iOS上这两张图片都能够正常显示。截图的时候Android能够正常截图,iOS上截的图却没有LOGO图片,只有二维码图片。
原因:
经过比较,发现LOGO图片的样式如下:
width: auto;height: 100%;
二维码图片的样式如下所示:
width: 100%;height: 100%;
解决方案
在用户点击保存图片的时候,给LOGO图片设置固定的宽度和高度。
经过实验,iOS上的截图也能够正常显示LOGO图片了。
因为时间紧张,今天就不查html2canvas究竟是那部分代码出了bug,有时间再查。
3. 竖版文本显示不全(2017-10-17)
现象及原因
现象:
页面用到了竖版文本,使用的是宽度固定(宽度仅能容纳一个汉字),然后每个文字后面加上< br />换行,Android上保存图片没问题,但是iOS上保存之后文本显示不全,文本仍然是按照横向渲染的。
原因:
没调查具体的原因,渲染过程中文本是按照横向渲染的,导致文本显示不全。
解决方案
不再使用< br />换行,使用css样式
-webkit-writing-mode: vertical-lr; writing-mode: vertical-lr;
因为在微信中使用,场景为mobile,兼容性应该没问题。
资料扩展
- MDNwriting-mode解释的挺详细,国内好多博客都是抄的这篇文章。
- 张鑫旭大神对writing-mode有深入的解析改变CSS世界纵横规则的writing-mode属性
4.1. 下划线没有显示(2017-10-17)
现象及原因
现象:
给文本设置了下划线,但是截图中没有显示。
原因:
查看源码2255行(因为文件被我修改了,不一定精确地是这一行),发现了如下代码
this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size));
调用的是第2262行:
NodeParser.prototype.renderTextDecoration = function(container, bounds, metrics) { switch(container.css("textDecoration").split(" ")[0]) { case "underline": // Draws a line at the baseline of the font // TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size this.renderer.rectangle(bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 1, container.color("color")); break; case "overline": this.renderer.rectangle(bounds.left, Math.round(bounds.top), bounds.width, 1, container.color("color")); break; case "line-through": // TODO try and find exact position for line-through this.renderer.rectangle(bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 1, container.color("color")); break; }};
html2canvas查找的文本节点的父节点上的样式,而项目中设置的下划线却是在某个固定的祖先元素上,对代码调整一下就好了。
解决方案
调整后的代码如下所示:
NodeParser.prototype.renderTextDecoration = function(container, bounds, metrics) { switch(container.parent.parent.css("textDecoration").split(" ")[0]) { case "underline": ... }}
其实就是找到有这个属性的节点,然后从这个节点上获取属性。
也可以修改HTML结构,将这个属性放到包裹文本节点的那一层,这样就不用修改源码了。
4.2. underline太细(2017-10-19)
现象及原因
现象:
下划线截图后比较细。
原因:
查阅代码发现,html2canvas使用的是固定值,而不是跟随文本样式变化而变化。
NodeParser.prototype.renderTextDecoration = function(container, bounds, metrics) { switch(container.parent.parent.css("textDecoration").split(" ")[0]) { case "underline": // Draws a line at the baseline of the font // TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size this.renderer.rectangle(bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, 2, container.color("color")); break; case "overline":
CanvasRenderer.prototype.rectangle = function(left, top, width, height, color) { this.setFillStyle(color).fillRect(left, top, width, height);};
可以看出,第三个参数就是宽度,html2canvas设定的是固定值1,。
解决方案
添加了lineWidth变量,设置为文本的1/10,大小基本合适,可以按照现实显示的情况进行调整。
NodeParser.prototype.renderTextDecoration = function(container, bounds, metrics) { var fontSize = container.parent.parent.css('fontSize'); var lineWidth = parseFloat(fontSize) / 10; lineWidth = lineWidth > 2 ? lineWidth : 2; switch(container.parent.parent.css("textDecoration").split(" ")[0]) { case "underline": // Draws a line at the baseline of the font // TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size this.renderer.rectangle(bounds.left, Math.round(bounds.top + metrics.baseline + metrics.lineWidth), bounds.width, lineWidth, container.color("color")); break; case "overline": this.renderer.rectangle(bounds.left, Math.round(bounds.top), bounds.width, lineWidth, container.color("color")); break; case "line-through": // TODO try and find exact position for line-through this.renderer.rectangle(bounds.left, Math.ceil((bounds.top + bounds.bottom) / 2 + metrics.lineWidth), bounds.width, lineWidth, container.color("color")); break; }};
4.3. line-through部分文本效果偏下(2017-10-19)
现象及原因
现象:
给文本设置line-through,部分文本删除线偏下。
原因:
经查阅代码
this.renderer.rectangle(bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 2, container.color("color"));
可以发现,html2canvas使用Math.ceil(bounds.top + metrics.middle + metrics.lineWidth)来计算top值,但是打印log发现,metrics.middle值并不在是文本的一半。
解决方案
使用(bounds.top + bounds.bottom) / 2来计算中间值,效果还可以。
case "line-through": // TODO try and find exact position for line-through // this.renderer.rectangle(bounds.left, Math.ceil(bounds.top + metrics.middle + metrics.lineWidth), bounds.width, 2, container.color("color")); this.renderer.rectangle(bounds.left, Math.ceil((bounds.top + bounds.bottom) / 2 + metrics.lineWidth), bounds.width, 2, container.color("color")); break;
5.1. 文本描边效果没有显示(2017-10-18)
现象及原因
现象:
一些文本做了文本描边效果,但是截图后发现该效果并没有显示出来。
原因:
经查阅源代码,发现html2canvas库并没有处理文本描边效果的代码
解决方案
仿照其他的代码,自己写响应的代码:
首先在第2251行添加处理文本描边效果的代码
this.renderer.clip(container.parent.clip, function() { textList.map(this.parseTextBounds(container), this).forEach(function(bounds, index) { if (bounds) { this.renderer.text(textList[index], bounds.left, bounds.bottom); this.renderTextDecoration(container.parent, bounds, this.fontMetrics.getMetrics(family, size)); this.renderTextStroke(textList[index], container.parent, bounds, this.fontMetrics.getMetrics(family, size)); // 这一行是新添加的 } }, this); }, this);
完成renderTextStroke函数(仿照renderTextDecoration函数写的)(我写在了2079行,renderTextDecoration函数的后面):
NodeParser.prototype.renderTextStroke = function(text, container, bounds, metrics) { var width = container.parent.parent.css("-webkit-text-stroke-width"); width = parseFloat(width); var color = container.parent.parent.css('-webkit-text-stroke-color'); if (width !== 0) { this.renderer.textStroke(text, bounds.left, bounds.bottom, width, color); }};
里面使用了新的函数textStroke,仿照text函数完成该函数(我写在了3078行,text函数的后面):
CanvasRenderer.prototype.textStroke = function(text, left, bottom, width, color) { this.ctx.lineWidth = width; this.ctx.strokeStyle = color; this.ctx.strokeText(text, left, bottom);};
5.2. 文本描边和阴影同时显示时显示不正常(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)
联系我
如果您有更好的解决方案,或者
您有任何疑问或本文侵犯了您的著作权,请联系我。 mail to kylin
- html2canvas库使用中出现的问题及解决方案
- tensorflow基本使用中出现的问题及解决方案
- ios9中出现的问题及解决方案
- studio中出现的问题及解决方案
- 使用 linux 出现的问题及解决方案
- 最近在DEMO中使用Teechart出现的问题及解决方案总结
- Mysql在Linux下安装和使用过程中出现的问题及解决方案
- 使用H-ui前端框架中表格改变列数出现的问题及解决方案
- 关于VS2013中出现的一些问题及解决方案
- 安装caffe过程中出现的问题及解决方案
- 出现问题及解决方案||centos 中oracle
- Android中jar包封装及调用中出现的问题及解决方案
- html2canvas不能识别svg的解决方案
- 在WPF中使用WindowsFormsHost带来的问题及解决方案
- Maven使用过程中遇到的问题及解决方案
- Qt使用中遇到的问题及解决方案
- 使用phpedit/cakephp中出现的乱码问题及解决
- php中使用setcookie出现的问题及解决
- spark2.1源码分析4:spark-network-common模块的设计原理
- ububtu16.04安装Opencv3.1 包含contrib部分
- 对于rhel 6.6 内核2.6.32-504.el6安装asmlib问题
- 阿里免费教你学习前端开发CSS基础
- 项目A 引入到项目B 在maven中引入另一个项目 项目A 的方法引入到项目B
- html2canvas库使用中出现的问题及解决方案
- 【Qt】Qt程序编译成功,执行时报错:程序异常结束,crashed
- 回顾大一·C语言编程3.4(4)
- 笔记:关于Gradle error Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256m的解决方案
- Unary Code
- MS SQLServer 批量附加数据库
- Arch Linux fcitx 新世纪五笔配置
- python的meshgrid的用法及灰度图像的显示
- jsp获取随机数并跳转到相应的jsp