网页保存为图片及高清截图的优化 | canvas跨域图片配置

本次技术调研来源于H5项目中的一个重要功能需求:实现微信长按网页保存为截图

这里有个栗子(请用微信打开,长按图片即可保存):3分钟探索你的知识边界

将整个网页保存为图片是一个十分有趣的功能,常见于H5活动页的结尾页分享。以下则是项目中调研和踩坑的一些小结和汇总。


一、实现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属性即可

MDN:toDataURL() API 详解

  • 方案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节的设置后,模糊成大果粒的渲染结果依然给清晰的幻想打了0分。

下面直接给出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;

        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",
            // ‘border‘: ‘10px solid #000‘
        }).addClass(‘f-full‘);

        $(‘#j-sec-end‘).remove();
    });
}

例: DOM元素样式:

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

<!--## 2.3 优化结果对比
(mac中有截图,可以对比)-->

三、含有跨域图片的配置

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

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

3.1 针对CDN中的图片的配置

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

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

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

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

其他注意事项

(1) margin的遮挡问题

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

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

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

(3) JPEG的黑屏问题

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

(4) 不能保留动效

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

参考文献

原文地址:https://www.cnblogs.com/homehtml/p/12207860.html

时间: 2024-08-06 07:14:41

网页保存为图片及高清截图的优化 | canvas跨域图片配置的相关文章

美女直播的网页Flash推流进行网络高清直播

全民都在直播:每个人都可以通过直播平台分享出去让更多的看到,关注到.尤其目前美女直播秀场的应用,可以说是热火朝天.很多平台都在进行美女秀场直播,打出的口号都各有千秋,又都万变不离其宗.那么看下主流的直播秀场平台: 六间房:超火的娱乐直播平台 秀色直播网:真人视频聊天室 千帆直播:海量性感女主播平台 酷我秀场直播:真人女主播视频直播 爱奇艺奇秀:在线互动娱乐社区:最高清的真人视频直播平台 新浪秀场:最大真人视频直播社区 通过这些口号,不乏总结出来这些平台的特点:娱乐,直播,美女,互动,真人,社区.

HTML5第7次课堂笔记(图片验证码的应用,xmlhttprequest对象的使用,跨域)

HTML5第7次课堂笔记 1.  图片验证码的应用:(1)服务端Content-type的控制:(2)客户端防止缓存(仅对GET) 服务器端使用的是jsp 点击图片,实现刷新验证码 有时拿不到服务器的数据  没有请求出去  浏览器的问题,请求缓存起来 对同一个地址不断请求,会缓存起来,一定是get请求 可以看到每次请求地址都不一样,这样就避免了缓存 总结:通过fiddler查看http的请求和响应可以看出很多有用的信息,对排查错误,查看数据很有帮助 2.  xmlhttprequest对象的使用

【原】保存一下之前spring-session的redis单点登录配置文件【跨域】

由于先前在调试项目的时候需要做单点,但是项目是基于spring-session老版本做的单点登录,没有实现跨域登录,因为只是针对相同域名下的用户缓存进行存储而已,例如 http://127.0.0.1/wap 和 http://127.0.0.1/wap2 ,这样的话只要在 第一个域名登录后再去第二2个域名进行用户登录,则无需重复登录,但是如果是 http://127.0.0.1/wap 和 http://192.168.1/wap2 这样就没办法找到session. <?xml version

apache跨域图片配置

修改httpd.conf 1 找到 网站目录设置 <Directory "/var/www"> AllowOverride ALL # Allow open access: Require all granted Header set Access-Control-Allow-Origin *</Directory> 把红色的给加上 2 加载扩展开启apache头信息自定义模块 #LoadModule headers_module modules/mod_hea

nginx 图片,js,css等文件允许跨域

location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ { #允许跨域请求 add_header Access-Control-Allow-Origin '*'; add_header Access-Control-Allow-Headers X-Requested-With; add_header Access-Control-Allow-Methods GET,POST,OPTIONS; expires 30d; access_log o

基于html2canvas实现网页保存为图片及图片清晰度优化

本次技术调研来源于H5项目中的一个重要功能需求:实现微信长按网页保存为截图. 这里有个栗子(请用微信打开,长按图片即可保存):3分钟探索你的知识边界 将整个网页保存为图片是一个十分有趣的功能,常见于H5活动页的结尾页分享.以下则是项目中调研和踩坑的一些小结和汇总. 一.实现HTML页面保存为图片 1.1 已知可行方案 现有已知能够实现网页保存为图片的方案包括: 方案1:将DOM改写为canvas,然后利用canvas的toDataURL方法实现将DOM输出为包含图片展示的data URI 方案2

高楼大厦素材高清图片

这个作品的设计我还是非常喜欢的.收藏一下! 高楼大厦素材高清图片 高楼大厦高清,高楼大厦素材,高楼大厦,城市建筑,高楼,城市高楼,都市建筑,城市建筑群,高层建筑,大楼,高层写字楼,优美风景,摄影,自然景观,建筑景观,摩天大厦,城市建筑,都市建筑,PSD分层图层,72DPI 素材地址:高楼大厦素材高清图片

Cocos2D iOS之旅:如何写一个敲地鼠游戏(二):Cocos2D中的高清支持

大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 免责申明:本博客提供的所有翻译文章原稿均来自互联网,仅供学习交流之用,请勿进行商业用途.同时,转载时不要移除本申明.如产生任何纠纷,均与本博客所有人.发表该翻译稿之人无任何关系.谢谢合作! 高清显示和Cocos2D 好吧,有一个好消息 - 在最新版本的Cocos2D中包括了高清屏的完整支持,你可以用下面1-2-3步就可简单搞定! 在调用CCDirector的en

C#生成高清缩略图 (装在自OPEN经验库)

来源 http://www.open-open.com/lib/view/open1389943861320.html 代码如下实现图片的高清缩略图 /// <summary> /// 为图片生成缩略图 /// </summary> /// <param name="phyPath">原图片的路径</param> /// <param name="width">缩略图宽</param> ///