一、实现HTML页面保存为图片

1.1 已知可行方案

现有已知能够实现网页保存为图片的方案包括:

  • 方案1:将DOM改写为canvas,然后利用canvas的toDataURL方法实现将DOM输出为包含图片展示的data URI
  • 方案2:使用html2canvas.js实现(可选搭配Canvas2Image.js实现网页保存为图片)
  • 方案3:使用rasterizeHTML.js实现

1.2 解决方案的选择

  • 方案1:需要手动计算每个DOM元素的Computed Style,然后需要计算好元素在canvas的大小位置等属性。

    方案1难点

    1. 相当于完全重写了整个页面的布局样式,增加了工作量。
    2. 由于canvas中没有的对象概念,对于元素丰富、布局复杂的页面,不易重构。
    3. 所有DOM元素改写进canvas会带来一些困难,例如:难以支持响应式,图片元素清晰度不佳和文字点击区域识别问题等。
  • 方案2:该类功能中Github上stars最多(至今仍在维护),Stack Overflow亦有丰富的讨论。只需简单调用html2canvas方法并设定配置项即可。
  • 方案3:该方案的限制较多,目前仅支持3类可转为canvas的目标格式: 页面url,html字符串和document对象。

小结: html2canvas是目前实现网页保存为图片功能的综合最佳选择。

1.3 html2canvas的使用方法

官方GitHub:https://github.com/niklasvh/h...

以下描述针对html2canvas版本是0.5.0-beta4

1.3.1 实现保存为图片的第一步:html转为canvas

基于html2canvas.js可将一个元素渲染为canvas,只需要简单的调用html2canvas(element[, options]);即可。下列html2canvas方法会返回一个包含有<canvas>元素的promise

html2canvas(document.body).then(function(canvas) {
document.body.appendChild(canvas);
});

1.3.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),适合项目使用。

二、生成图片的清晰度优化方案

2.1 基础的清晰度优化方案

最终图片的清晰度取决于第一步中html转换成的canvas的清晰度。

现有解决方案参考;

其基本原理为:
canvas的属性widthheight属性放大为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.2 进阶的清晰度优化方案

上述设置可以解决通常情况下图片不清晰的问题,不过探索并没有结束。

实际在我们的项目中,即使作出2.1节的设置后,大果粒一般的渲染结果依然尴尬。

下面直接给出3条进一步的优化策略:

  1. 更改百分比布局px布局(如果原先是百分比布局的话)
  2. 关闭canvas默认的抗锯齿设
  3. 设置模糊元素的widthheight为素材原有宽高,然后通过transform: scale进行缩放。这里scale的数值由具体需求决定。

基本原理

  1. 如果原来使用百分比设置元素宽高,请更改为px为单位的宽高,避免样式二次计算导致的模糊
  2. 默认情况下,canvas的抗锯齿是开启的,需要关闭抗锯齿来实现图像的锐化(MDN: imageSmoothingEnabled )
  3. 除了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');
});
}

例: DOM元素样式:


.targetElem {width: 54px;height: 142px;margin-top:2px;margin-left:17px;transform: scale(0.5)}

三、含有跨域图片的配置

由于canvas对于图片资源的同源限制,如果画布中包含跨域的图片资源则会污染画布,造成生成图片样式混乱或者html2canvas方法不执行等问题。

以下主要解决两类跨域的图片资源:包括已配置过CORS的CDN中的图片资源和微信用户头像图片资源。

3.1 针对CDN中的图片的配置

  1. 要求CDN的图片配置好CORSCDN配置好后,通过chrome开发者工具可以看到响应头中应含有Access-Control-Allow-Origin的字段。
  2. 开启html2canvasuseCORS配置项。即作如下设置:

var opts = {useCORS: true};
html2canvas(element, opts);

注意
如果没有开启html2canvasuseCORS配置项,html2canvas会正常执行且不会报错,但是不会输出对应的CDN图片
(已测试同时包含CDN的图片本地图片的资源的页面,但是只有本地图片能够被正常渲染出来)

3.2 针对微信用户头像的配置

如果需要将微信平台中的用户头像一并保存为图片,3.1的方案无能为力。可通过配置服务端代理转发(forward)实现,此处不赘述。

其他注意事项

1. margin的遮挡问题

微信中,唤出长按保存图片的菜单要求长按的对象直接是<image>元素,如果<image>元素上方存在遮挡,则不会唤出菜单。
而事实上,引发遮挡的并不只是非<image>元素,还可能是margin属性。例如:若在页面底部,对一个绝对定位的元素设置了数值很大的margin-top,则margin-top所涉及的区域,均无法长按唤出菜单。解决方案:将margin-top改用为top即可。

2. 安卓版微信保存图片失败的问题

canvas2img默认保存图片的格式为png,而在安卓版微信中所生成的图片尽管能长按唤出保存图片的菜单,但是无法正确保存到本地相册。 解决方案:设置canvas2img的生成图片格式配置项为jpeg即可。

3. JPEG的黑屏问题

设置canvas2img输出格式为jpeg,会有一定几率导致生成的图片包含大量的黑色块。可能的解决方案:缩减部分图片元素的体积和尺寸大小。

4. 不能保留动效

在图片的转化前,必须停止或者删除动效后才能正确渲染出图片,否则生成的图片是破裂的。

基于html2canvas实现网页保存为图片及图片清晰度优化的更多相关文章

  1. html2canvas 把h5网页保存为图片 区域保存

    html2canvas 把h5网页保存为图片 想把一个网页得某些元素,绘制成图片保存,有些数据是接口动态加载的,所以不能UI给到图片,需要我们把api的数据也绘制到图片上 html2canvas这个插 ...

  2. 如何实现批量截取整个网页完整长截图,批量将网页保存成图片web2pic/webshot/screencapture/html2picture

    如何实现批量截取整个网页完整长截图,批量将网页保存成图片web2pic/webshot/screencapture [困扰?疑问?]: 您是否正受到:如何将网页保存为图片的困扰?网页很高很长截图截不全 ...

  3. 减少HTTP请求之将图片转成二进制并生成Base64编码,可以在网页中通过url查看图片(大型网站优化技术)

    在网站开发过程中,对于页面的加载效率一般都想尽办法求快.那么,怎么让才能更快呢?减少页面请求 是一个优化页面加载速度很好的方法.上一篇博文我们讲解了 “利用将小图标合成一张背景图来减少HTTP请求”, ...

  4. 如何将网页保存为PDF文件

    怎样将网页保存为PDF文件... 问题: 很多时候我们需要将网页上的内容,在排版不变的情况下完整的保存下来,那么用pdf格式是最好的效果了,还图文并茂,效果与真实的网页很相似,如果另存为网页的话,会下 ...

  5. 使用html2canvas实现网页截图,并嵌入到PDF

    使用html2canvas实现网页截图并嵌入到PDF 以前我们只能通过截图工具进行截取图像.这使得在业务生产中,变得越来越不方便.目前的浏览器功能越来越强大,H5也逐渐普及,浏览器也可以实现截图了.这 ...

  6. 基于flask的网页聊天室(三)

    基于flask的网页聊天室(三) 前言 继续上一次的内容,今天完成了csrf防御的添加,用户头像的存储以及用户的登录状态 具体内容 首先是添加csrf的防御,为整个app添加防御: from flas ...

  7. 基于flask的网页聊天室(二)

    基于flask的网页聊天室(二) 前言 接上一次的内容继续完善,今天完成的内容不是很多,只是简单的用户注册登录,内容具体如下 具体内容 这次要加入与数据哭交互的操作,所以首先要建立相关表结构,这里使用 ...

  8. 基于.NetCore开发博客项目 StarBlog - (9) 图片批量导入

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  9. 【matlab】用matlab 保存带标记图像、图片的方法总结

    最近看了一些用matlab对图形图片进行保存的帖子和资源,关于图像保存的方法给大家分享一下这些方法是大家所使用方法的一个总结. 如今常用的方法有三种printf,imwrite,saveas下面分别介 ...

随机推荐

  1. 漫谈php框架之中间件

    市面上常见的php框架有很多,最近因为有技术需求,所以对常见的php框架的中间件进行了一些了解.各个框架尽管在目标上对php框架的定义大同小异,但是在实现方式上却各有不同,且看下文: 定义 首先什么是 ...

  2. CSUST 1011 神秘群岛 (Dijkstra+LCA)

    神秘群岛   Description 小J继续着周游世界的旅程,这次他来到了一个神奇的群岛.这片群岛有n个岛屿,同时这些岛屿被标上了1-n的编号. 每个岛屿上面都有神奇的传送门,传送门可以把小J从当前 ...

  3. icmpsh解决运行报错

    运行./run.sh报错 sysctl -w net.ipv4.icmp_echo_ignore_all=1 >/dev/null python icmpsh_m.py 攻击机ip 目标机ip ...

  4. 苹果笔记本适合什么人 中国Mac电脑用户的8个事实

    报告由腾讯 ISUX 研究中心收集了全国 7946 名 Mac 电脑用户的问卷整理而成.并且,参考了苹果公司的历年财报,以及百度.StatCounter 等第三方市场统计数据. 你是 iPhone 用 ...

  5. OS + Linux RedHat 7 / redhat 7 configuration

    s redhat 7.2 tracker-store CPU消耗高的问题 http://www.cnblogs.com/exiahan/archive/2013/07/08/3177971.html ...

  6. Linux记录-linux系统监控命令汇总

    命令 功能应用 用法举例     free 查看内存使用情况,包括物理内存和虚拟内存 free -h或free -m     vmstat 对系统的整体情况进行统计,包括内核进程.虚拟内存.磁盘.陷阱 ...

  7. Program License Agreement updated/The updated Apple Developer Program License Agreement needs to be reviewed.

    Apple APP添加新APP时提示The updated Apple Developer Program License Agreement needs to be reviewed. 解决办法 登 ...

  8. Golang基础语法1

    打开cmd命令窗口 保存,编译,执行: 1.保存到一个×××.go的文件(我这里保存到  E:\GoTest\hello.go   下) 2.编译,在命令提示符中执行命令: go build -o E ...

  9. 原生JavaScript运动功能系列(三):多物体多值运动

    多物体同时出发运动函数实现 多属性同步运动变化实现 一.多物同时触发运动函数实现 前面两个动画示例基本理解了动画的核心:位置变化和速度变化,操作的核心就是定时器分段叠加属性值.但是动画还是基于单个元素 ...

  10. JavaSrcipt的数字(number):深入理解内部机制

    一.数字的语法 JavaScript中的数字字面量一般用十进制表示.在JavaScript中表示数字的数据类型只有一种Number,这种天使与魔鬼同体的数据类型也就只有js了. //同时表达整数和浮点 ...