当前位置: 首页 > Web前端 > HTML

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

时间:2023-04-02 18:01:36 HTML

2019.12更新:《高质量前端快照方案:来自页面的「自拍」》2019.12更新:《高质量前端快照方案:来自页面的「自拍」》2019.12更新:《高质量前端快照方案:来自页面的「自拍」》新作见上文~一个重要的功能需求:实现微信长按网页另存为截图。举个栗子(请用微信打开,长按图片保存):3分钟探索你的知识边界将整个网页保存为图片是一个很有意思的功能,经常在文末分享H5活动页面。以下是项目中的研究和陷阱的一些总结和总结。1.将HTML页面保存为图片1.1已知可行方案现有已知的可以将网页保存为图片的方案有:方案一:将DOM重写成canvas,然后使用canvas的toDataURL方法输出DOM以包含图片显示方案二:使用html2canvas.js来实现(canvas2Image.js是可选的,可以将网页另存为图片)方案三:使用rasterizeHTML.js实现1.2方案方案方案一:需要手动计算每个DOM元素的ComputedStyle,然后需要计算元素在画布上的大小和位置以及其他属性。方案一难点:相当于完全重写了整个页面的布局样式,增加了工作量。由于canvas中没有对象的概念,重构元素丰富、布局复杂的页面并不容易。将所有DOM元素重写到canvas中会带来一些困难,例如难以支持响应性、图像元素的清晰度差、文本点击区域的识别等。解决方案二:这类功能中,Github上star最多(至今还在维护),StackOverflow上也有丰富的讨论。直接调用html2canvas方法,设置配置项即可。解决方案3:此解决方案有很多限制。目前,它只支持3种可以转换为canvas的目标格式:页面url、html字符串和文档对象。总结:html2canvas是目前实现网页保存为图片功能最好的综合选择。1.3html2canvas官方GitHub的使用方法:https://github.com/niklasvh/h...以下说明针对html2canvas版本0.5.0-beta41.3.1第一步存为图片:将html转换成canvasbased在html2canvas上.js可以将元素渲染为画布,只需调用html2canvas(element[,options]);以下html2canvas方法将返回包含元素的承诺:html2canvas(document.body).then(function(canvas){document.body.appendChild(canvas);});第二步:画布转图片上一步生成的画布就是包含目标元素的元素对象。要达到保存图片的目的,只需要将canvas转为image即可。这里有两种转换方案:方案一:基于原生canvas的toDataURL方法,将canvas输出为data:URI图片地址,然后将图片地址赋值给元素的src属性。方案二:使用第一个三方库Canvas2Image.js,调用其convertToImage方法即可(GitHub)。其实Canvas2Image.js也是基于对canvas.toDataURL的封装。与原来的canvasAPI相比,转换为图片的功能更加具体(未压缩包大小为7.4KB),适合项目使用。2.生成图片的分辨率优化方案2.1基本分辨率优化方案最终图片的分辨率取决于第一步html转换成的canvas的分辨率。现有解决方案参考;如何处理html5canvas在高倍屏下的模糊问题。将canvas的CSS样式宽度和高度设置为原始尺寸的两倍。例如:如果想让在html中实际显示的宽高分别为160px和90px,可以这样设置具体用例参考上述文档如下;convert2canvas(){varshareContent=YourTargetElem;varwidth=shareContent.offsetWidth;varheight=shareContent.offsetHeight;varcanvas=document.createElement("canvas");变量比例=2;canvas.width=宽度*比例;canvas.height=高度*比例;canvas.getContext("2d").scale(scale,scale);varopts={scale:scale,canvas:canvas,logging:true,width:width,height:height};html2canvas(shareContent,opts).then(function(canvas){varcontext=canvas.getContext('2d');varimg=Canvas2Image.convertToImage(canvas,canvas.width,canvas.height);document.body.appendChild(img);$(img).css({"宽度":canvas.width/2+"px","高度":canvas.height/2+"px",})});}2.2高级清晰度优化方案以上设置一般情况下可以解决图片不清晰的问题,但是探索并没有结束。其实在我们的项目中,即使做了2.1节的设置之后,大水果的整体渲染效果还是很尴尬,这里有3种进一步的优化策略:将百分比布局改为px布局(如果原来的百分比布局是这样的话)关闭canvas默认的抗锯齿设置,设置宽高将模糊后的元素变成材质原来的宽高,然后通过transform:scale进行缩放,这里scale的值由具体需求决定。基本原理如果你使用百分比设置元素的宽高,请将宽高改为px,避免样式二次计算造成模糊(MDN:imageSmoothingEnabled)另外canvas可以放大2倍width和height再缩放到原来的width和height以提高清晰度,对于DOM中的其他元素,也可以使用css样式的scale实现同样的缩放示例:html2canvas配置convert2canvas(){varcntElem=$('#j秒结束')[0];varshareContent=cntElem;//需要截图的包的(原生)DOM对象varwidth=shareContent.offsetWidth;//获取dom宽度varheight=shareContent.offsetHeight;//获取dom高度varcanvas=document.createElement("canvas");//创建画布节点varscale=2;//定义任何放大倍数以支持小数canvas.width=width*scale;//定义画布宽度*比例canvas.height=height*scale;//定义画布高度*比例canvas.getContext("2d").scale(scale,scale);//获取上下文,设置scalevaropts={scale:scale,//添加scale参数canvas:canvas,//customcanvas//logging:true,//log开关,方便查看html2canvaswidth的内部执行过程:width,//dom原始宽度height:height,useCORS:true//【重要】开启跨域配置};html2canvas(shareContent,opts).then(function(canvas){varcontext=canvas.getContext('2d');//[重要]关闭抗锯齿context.mozImageSmoothingEnabled=false;context.webkitImageSmoothingEnabled=false;context.msImageSmoothingEnabled=false;context.imageSmoothingEnabled=false;//【重要】默认转换格式为png,也可以设置为其他格式varimg=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;高度:142px;边距顶部:2px;左边距:17px;transform:scale(0.5)}3.由于canvas对图片资源的同源限制,跨域图片的配置如果canvas包含跨域图片资源,会污染canvas,导致生成的图片混乱样式或无法执行html2canvas方法。下面主要解决两类跨域图片资源:包括配置了CORS的CDN中的图片资源和微信用户头像图片资源。3.1CDN中图片的配置,要求CDN中的图片配置CORS。CDN配置完成后,可以通过chrome开发者工具在响应头中看到Access-Control-Allow-Origin字段。开启html2canvas的useCORS配置项。即,进行以下设置:varopts={useCORS:true};html2canvas(element,opts);注意:如果不开启html2canvas的useCORS配置项,html2canvas会正常执行,不会报错,但不会输出对应的CDN图片(已测试同时包含CDN图片和本地图片资源的页面,但只有本地图片可以可以正常渲染)3.2微信用户头像的配置如果需要将微信平台的用户头像保存为图片,3.1的方案无能为力。可以通过配置服务器端代理转发(forward)来实现,这里不再赘述。其他说明1.margin遮挡问题微信中长按菜单保存图片要求长按对象直接为元素。如果元素上方有遮挡,则不会调用菜单。其实造成遮挡的不仅是非元素,还有margin属性。例如:如果为页面底部的绝对定位元素设置了较大的margin-top,则长按菜单无法调出margin-top涉及的区域。解决办法:把margin-top改成top。2、安卓版微信保存图片失败。canvas2img默认保存图片格式为png,安卓版微信生成的图片可以长按调出保存图片菜单,但无法正确保存到本地相册。解决方法:将canvas2img的生成图片格式配置项设置为jpeg即可。3.JPEG黑屏问题如果将canvas2img输出格式设置为jpeg,有一定几率生成的图像会包含大量黑块。可能的解决方案:减少一些图像元素的体积和大小。4.不能保留动画效果在转换图像之前,必须在停止或删除动画效果后正确渲染图像,否则生成的图像会被破坏。参考CanvasRenderingContext2D.drawImage()添加自定义分辨率的dpi/scale选项HTMLCanvasElement.toDataURL()如何处理高倍屏下html5canvas变模糊Canvas实现保存图片到本地html2canvas截图如何解决跨域问题