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

网页另存为图片和高清截图的优化-Canvas跨域图片配置

时间:2023-03-30 23:19:35 CSS

本次技术研究来源于H5项目中一个重要的功能需求:实现微信长按保存网页截图。举个栗子(请用微信打开,长按图片保存):3分钟探索你的知识边界将整个网页保存为图片是一个很有意思的功能,经常在文末分享H5活动页面。以下是项目中的研究和陷阱的一些总结和总结。1、将HTML网页保存为图片1.1已知可行的方案现有已知的可以将网页保存为图片的方案有:方案一:将DOM重写成canvas,然后使用canvas的toDataURL方法输出DOM以包含图片显示方案二:使用html2canvas.js实现(canvas2Image.js可选,将网页保存为图片)方案三:使用rasterizeHTML.js实现1.2解决方案方案一:需要手动计算每个DOM元素的ComputedStyle,以及然后需要计算元素在画布上的大小和位置等属性。方案一难点:相当于完全重写了整个页面的布局样式,增加了工作量。由于canvas中没有对象概念,对于元素丰富、布局复杂的页面,重构所有DOM元素并重写到canvas中并不容易,会带来一些困难,例如:难以支持响应性,图像元素清晰度差以及文字点击区域Identificationissues等。解决方案2:该类型的功能中,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属性。MDN:toDataURL()API详解二:使用第三方库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进阶清屏优化方案以上设置可以解决常见的截图效果不清晰的问题,但是探索还远未结束。其实在我们的项目中,即使做了Section中的设置之后2.1,模糊成大果粒的渲染结果,清晰的错觉依然是0分,这里有3种进一步的优化策略:将百分比布局改为px布局(如果是原来的百分比布局)关闭默认反-canvas的aliasing设置将blur元素的宽高设置为材质原来的宽高,然后通过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(函数(可以vas){varcontext=canvas.getContext('2d');context.mozImageSmoothingEnabled=false;context.webkitImageSmoothingEnabled=false;context.msImageSmoothingEnabled=false;context.imageSmoothingEnabled=false;varimg=Canvas2Image.convertToJPEG(宽度,canvas.height);文档.body.appendChild(img);$(img).css({"width":canvas.width/2+"px","height":canvas.height/2+"px",//'border':'10pxsolid#000'}).addClass('f-full');$('#j-sec-end').remove();});}示例:DOM元素样式:.targetElem{width:54px;height:142px;margin-top:2px;margin-left:17px;transform:scale(0.5)}3.包含跨域图片的配置由于canvas对图片资源的同源限制,如果canvas包含跨域图片资源,会污染canvas,导致生成图片样式混乱或者html2canvas方法不执行。主要问题如下解决两类跨域图片资源:包括已配置CORS的CDN中的图片资源和微信用户头像图片资源。3.1CDN中图片的配置,要求CDN中的图片配置CORS。CDN配置完成后,可以通过chrome开发者工具在响应头中看到Access-Control-Allow-Origin字段。开启html2canvas的useCORS配置项。即进行以下设置:useCORS:true}html2canvas(element,options);注意:如果没有开启html2canvas的useCORS配置项,html2canvas会正常执行,不会报错,但不会输出对应的CDN图片(即在同一个页面,可以测试同时包含CDN图片和本地图片的页面图片资源,但只有本地图片可以正常渲染)3.2微信用户头像配置如果需要将微信平台的用户头像保存为图片,3.1程序无能为力。可以通过配置代理转发来实现,这里不再赘述。其他注意事项(1)Margin遮挡问题在微信中,长按保存图片菜单要求长按对象直接为元素。如果元素上方有遮挡,则不会调用菜单。其实造成遮挡的不仅是非元素,还有margin属性。例如:如果为页面底部的绝对定位元素设置了较大的margin-top,则长按菜单无法调出margin-top涉及的区域。解决办法:把margin-top改成top。(2)安卓版微信保存图片失败。canvas2img默认保存的图片格式为png。安卓版微信生成的图片虽然可以长按调出保存图片的菜单,但是无法正确保存到本地相册。解决方法:将canvas2img的生成图片格式配置项设置为jpeg即可。(3)JPEG黑屏问题如果将canvas2img输出格式设置为jpeg,有一定几率生成的图像会包含大量黑块。可能的解决方案:减小图像元素的大小和背景图像的大小。(4)不能保持动画效果在转换图像之前,必须在停止或删除动画效果后正确渲染图像,否则生成的图像会被破坏。参考CanvasRenderingContext2D.drawImage()添加自定义分辨率的dpi/scale选项html5高倍屏下Canvas模糊Canvas实现保存图片到本地html2canvas截图如何解决跨域问题