参考文档https://segmentfault.com/a/1190000011478657?utm_source=tag-newest
将整个网页保存为图片是一个十分有趣的功能,常见于H5活动页的结尾页分享。以下则是项目中调研和踩坑的一些小结和汇总。
本次我使用的是html2canvas的使用方法
1 实现保存为图片的第一步:html转为canvas
基于html2canvas.js可将一个元素渲染为canvas,只需要简单的调用html2canvas(element[, options]);即可。下列html2canvas方法会返回一个包含有<canvas>元素的promise:
html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);
});
2 实现保存为图片的第二步:canvas转image
上一步生成的canvas即为包含目标元素的<canvas>元素对象。实现保存图片的目标只需要将canvas转image即可。
这里的转换方案有2种:
- 方案1:基于原生canvas的toDataURL方法将canvas输出为data: URI类型的图片地址,再将该图片地址赋值给<image>元素的src属性即可
- 方案2:使用第三方库Canvas2Image.js,调用其convertToImage方法即可(GitHub)
实际上,Canvas2Image.js也是基于canvas.toDataURL的封装,相比原生的canvas API对于转为图片的功能上考虑更为具体(未压缩的包大小为7.4KB),适合项目使用。
1 基础的清晰度优化方案
基本原理为:
将canvas的属性width和height属性放大为2倍(或者设置为devicePixelRatio倍),最后将canvas的CSS样式width和height设置为原先1倍的大小。
例如:希望在html中实际显示的<canvas>宽高分别为160px,90px则可作如下设置
<canvas width="320" height="180" style="width:160px;height:90px;"></canvas>
参考上述文档具体的使用案例如下;
convert2canvas() {
var shareContent = YourTargetElem;
var width = shareContent.offsetWidth;
var height = shareContent.offsetHeight;
var canvas = document.createElement("canvas");
var scale = 2;
canvas.width = width * scale;
canvas.height = height * scale;
canvas.getContext("2d").scale(scale, scale);
var opts = {
scale: scale,
canvas: canvas,
logging: true,
width: width,
height: height
};
html2canvas(shareContent, opts).then(function (canvas) {
var context = canvas.getContext('2d');
var img = Canvas2Image.convertToImage(canvas, canvas.width, canvas.height);
document.body.appendChild(img);
$(img).css({
"width": canvas.width / 2 + "px",
"height": canvas.height / 2 + "px",
})
});
}
2 进阶的清晰度优化方案
上述设置可以解决通常情况下图片不清晰的问题,不过探索并没有结束。
实际在我们的项目中,即使作出的设置后,大果粒一般的渲染结果依然尴尬。
下面直接给出3条进一步的优化策略:
- 更改百分比布局为px布局(如果原先是百分比布局的话)
- 关闭canvas默认的抗锯齿设置
- 设置模糊元素的width和height为素材原有宽高,然后通过transform: scale进行缩放。这里scale的数值由具体需求决定。
基本原理
- 如果原来使用百分比设置元素宽高,请更改为px为单位的宽高,避免样式二次计算导致的模糊
- 默认情况下,canvas的抗锯齿是开启的,需要关闭抗锯齿来实现图像的锐化(MDN: imageSmoothingEnabled )
- 除了canvas可以通过扩大2倍宽高然后缩放至原有宽高来提高清晰度,对于DOM中其他的元素也可以使用css样式的scale来实现同样的缩放
例: html2canvas配置
convert2canvas() {
var cntElem = $('#j-sec-end')[0];
var shareContent = cntElem;//需要截图的包裹的(原生的)DOM 对象
var width = shareContent.offsetWidth; //获取dom 宽度
var height = shareContent.offsetHeight; //获取dom 高度
var canvas = document.createElement("canvas"); //创建一个canvas节点
var scale = 2; //定义任意放大倍数 支持小数
canvas.width = width * scale; //定义canvas 宽度 * 缩放
canvas.height = height * scale; //定义canvas高度 *缩放
canvas.getContext("2d").scale(scale, scale); //获取context,设置scale
var opts = {
scale: scale, // 添加的scale 参数
canvas: canvas, //自定义 canvas
// logging: true, //日志开关,便于查看html2canvas的内部执行流程
width: width, //dom 原始宽度
height: height,
useCORS: true // 【重要】开启跨域配置
};
html2canvas(shareContent, opts).then(function (canvas) {
var context = canvas.getContext('2d');
// 【重要】关闭抗锯齿
context.mozImageSmoothingEnabled = false;
context.webkitImageSmoothingEnabled = false;
context.msImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
// 【重要】默认转化的格式为png,也可设置为其他格式
var img = Canvas2Image.convertToJPEG(canvas, canvas.width, canvas.height);
document.body.appendChild(img);
$(img).css({
"width": canvas.width / 2 + "px",
"height": canvas.height / 2 + "px",
}).addClass('f-full');
});
}
3 含有跨域图片的配置
由于canvas对于图片资源的同源限制,如果画布中包含跨域的图片资源则会污染画布,造成生成图片样式混乱或者html2canvas方法不执行等问题。
以下主要解决两类跨域的图片资源:包括已配置过CORS的CDN中的图片资源和微信用户头像图片资源。
3.1 针对CDN中的图片的配置
- 要求CDN的图片配置好CORS。CDN配置好后,通过chrome开发者工具可以看到响应头中应含有Access-Control-Allow-Origin的字段。
- 开启html2canvas的useCORS配置项。即作如下设置:
var opts = {useCORS: true};
html2canvas(element, opts);
注意:
如果没有开启html2canvas的useCORS配置项,html2canvas会正常执行且不会报错,但是不会输出对应的CDN图片
(已测试同时包含CDN的图片和本地图片的资源的页面,但是只有本地图片能够被正常渲染出来)
<style type="text/css">
body{
background-color:#fff;
padding:0;
margin:0;
}
#canvas{
width:100%;
height:300px;
background-color:#018fe9;
text-align:center;
}
.text{
font-size:40px;
line-height:72px;
}
.o-img{
width:100%;
}
</style>
<body>
<div class="content" id="content">
<div id="canvas">
<div class="text">这是文字</div>
<img src="" id="shareImg">
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.5.0-beta4/html2canvas.js"></script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
$(function(){
let resultUrl = 'https://file.iviewui.com/dist/e1cf12c07bf6458992569e67927d767e.png'
getCanvasBase64(resultUrl).then(function (base64) {
$("#shareImg").attr("src",base64);
getImg();//将html转换为图片
}, function (err) {
$(".loader").hide();
});
function getCanvasBase64(img) {
var image = new Image();
//至关重要
image.crossOrigin = '';
image.src = img;
//至关重要
var deferred = $.Deferred();
if (img) {
image.onload = function () {
deferred.resolve(getBase64Image(image));
}
return deferred.promise();
}
}
function getImg(){
var canvas2 = document.createElement("canvas");
let _canvas = document.querySelector('#canvas');
var w = parseInt(window.getComputedStyle(_canvas).width);
var h = parseInt(window.getComputedStyle(_canvas).height);
canvas2.width = w * 2;
canvas2.height = h * 2;
canvas2.style.width = w + "px";
canvas2.style.height = h + "px";
var context = canvas2.getContext("2d");
context.scale(2, 2);
html2canvas(document.querySelector('#canvas'), { canvas: canvas2 }).then(function(imgUrl) {
let oImg = document.createElement('img');
oImg.id = 'oImg';
oImg.className = 'o-img';
oImg.src= imgUrl.toDataURL();//imgUrl是html2canvas返回的截图的base64码
$("#download").attr("href",imgUrl.toDataURL());
document.getElementById("content").appendChild(oImg);//将生成的截图放到页面中
$("#canvas").hide();
// $(".loader").hide();
});
};
function getBase64Image(img, width, height) {
var canvas = document.createElement("canvas");
canvas.width = width ? width : img.width;
canvas.height = height ? height : img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
var dataURL = canvas.toDataURL();
return dataURL;
}
})
</script>
95

被折叠的 条评论
为什么被折叠?



