Html2canvas 图片模糊,可能的三种处理方法:
1、修改元素的宽高像素。 如果元素及其子元素的宽高变大了,截出的图片也会更大,更清晰。特别是对img或者带背景图的元素,其清晰度和原始宽高像素值直接相关。如果把图片元素的宽高放大并设置transform scale缩小,图片在页面的显示效果不变,但截图时图片分辨率会提高。
2、修改元素的transform: scale(2) 让截图根元素放大,并让截出的图片变大。大图片自动缩小后看,会显得清晰。但是在一些细节,比如文字阴影的偏移方面,显示会有偏差,没有进行相应的缩放。
let start = () => {
$('#rootNode').css('transform', ‘scale(2)'); // 截图时放大
};
let end = () => {
$('#rootNode').css('transform', ‘scale(.5)’); // 截图后恢复
};
3、html2canvas 的scale参数。这个效果上和方法2基本没有区别。scale参数默认值为 window.devicePixelRatio, mac的视网膜屏上,默认是2了(如果为1, 在视网膜屏幕上会糊),所以mac图片的像素大小是windows图片的2倍。如果要让截出的图大小统一,可以统一设置为2。
上述3种方法,1是最好的,特别是需要提高嵌入的图片的分辨率的时候。2,3差不多,但是3的细节方面要稳定些(比如文字阴影)。
综合来说, 效果 是 1 >2 >3, 实现成本是1 > 2 = 3。
要求不高的场合, 方法3足够好。
清晰度要求高的场合,需要三者结合:
A. 先采用1, 以放大2倍的方式,绘制需要截图的根元素下所有dom元素的宽高。并通过transform: scale(.5)缩小元素,在页面正常显示。这一步也可以不是2倍,而是其他倍数。
B. 截图前采用2,将transform scale(.5)移除, 恢复默认的2倍大小,同时可以规避html2canvas在处理transform过的元素时的各种bug和限制(如阴影偏移)。
C. 最后采用3,设置比例,调整最终的截图大小。
完整代码:
svgToImage(node){
// 截图前
let start = () => {
$(node).css('transform', ''); // 相当于scale(1)
// 截图时文字偏下修正
$('.editable').each( function () {
let $this = $(this);
var paddingTop = +$(this).css('paddingTop').split('px')[0];
$(this).css('paddingTop', paddingTop - 10 + 'px');
});
};
// 截图后
let end = () => {
$(node).css('transform', 'scale(.5)'); // 页面中默认scale
// 恢复文字偏下修正
$('.editable').each(function () {
let $this = $(this);
var paddingTop = +$(this).css('paddingTop').split('px')[0];
$(this).css('paddingTop', paddingTop + 10 + 'px');
});
};
start();
html2canvas(node, {
scale: 2 * .8, // scale 参数
allowTaint: true,
useCORS: true
// foreignObjectRendering: true
}).then(canvas => {
// 缩小成想要的比例
const w = 900;
const h = 383;
const elem = document.createElement('canvas');
elem.width = w;
elem.height = h;
const ctx = elem.getContext('2d');
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = "high";
ctx.drawImage(canvas, 0, 0, w, h);
canvas = elem;
var b64;
try {
b64 = canvas.toDataURL("image/png");
} catch (err) {
console.log(err);
end();
alert(err);
}
var a = document.createElement("a");
a.href = b64;
a.download = 'poster.png'; //设定下载名称
var evt = document.createEvent("MouseEvents");
evt.initEvent("click", true, true);
a.dispatchEvent(evt);
end();
});
}
如果要对最终图片的大小有明确要求,可以用上述3种方法将图片放大,然后再利用下述代码缩小。其中用到了imageSmoothingQuality属性,缩小后效果更平滑。注意这个办法更适合缩小而不适合放大,用这个方法放大的清晰度不如上述3种方法的结合。
// 缩小成想要的比例
const w = 900;
const h = 383;
const elem = document.createElement('canvas');
elem.width = w;
elem.height = h;
const ctx = elem.getContext('2d');
ctx.imageSmoothingQuality = "high”;
ctx.drawImage(canvas, 0, 0, w, h); // canvas为html2canvas导出的canvas
canvas = elem; // 用elem 替换原来的 canvas
截图中文字有时会有位移,偏下。可以用下述方法规避。 start为截图前的函数, end为截图后。
let start = () => {
// 截图时文字会偏下,所以先调成偏上
$('.editable').each( function () {
let $this = $(this);
var paddingTop = +$(this).css('paddingTop').split('px')[0];
$(this).css('paddingTop', paddingTop - 10 + 'px');
});
};
let end = () => {
// 恢复修正
$('.editable').each(function () {
let $this = $(this);
var paddingTop = +$(this).css('paddingTop').split('px')[0];
$(this).css('paddingTop', paddingTop + 10 + 'px');
});
};
html2canvas 原理和不支持的属性说明
The script traverses through the DOM of the page it is loaded on. It gathers information on all the elements there, which it then uses to build a representation of the page. In other words, it does not actually take a screenshot of the page, but builds a representation of it based on the properties it reads from the DOM.
As a result, it is only able to render correctly properties that it understands, meaning there are many CSS properties which do not work. For a full list of supported CSS properties, check out the supported features page.
不支持属性列表 尤其注意svg图片作为背景时,很可能出现乱码。尽量不要使用svg图片。
图片太大会影响性能,建议控制在1920 * 1080像素以内。
本文写作时用到的html2canvas版本是 1.0.0-rc.5, 相信随着越来越多的bug修正和特性完善,html2canvas的使用体验会越来越完善,不用再这么大费周折。
错误再所难免,希望大家指正。