web浏览器端怎么实现
导读:本文共6596字符,通常情况下阅读需要22分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要: 浏览器端实现方案开发:大事件长图和专辑详情页大事件tab的视觉效果基本一致,如果能复用可以减少开发时间。开发:怎么复用呢?于是便有了下面在浏览器端尝试dom转图片的两种方案:html2canvashtml2canvas一个在浏览器端通过JS对整个或部分页面进行“截屏”的库。html2canvas使用方法简单,截屏的核心代码如下:letimgBase64;htm... ...
目录
(为您整理了一些要点),点击可以直达。浏览器端实现方案
开发:大事件长图和专辑详情页大事件tab的视觉效果基本一致,如果能复用可以减少开发时间。
开发:怎么复用呢?
于是便有了下面在浏览器端尝试dom转图片的两种方案:
html2canvas
html2canvas一个在浏览器端通过JS对整个或部分页面进行“截屏”的库。
html2canvas使用方法简单,截屏的核心代码如下:
letimgBase64;html2canvas(htm,{onrendered:function(canvas){//生成base64图片数据imgBase64=canvas.toDataURL();});
使用简单,但是坑不少,遇到的坑及解决方案:
1.截图模糊
主要解决思路:
1)将canvas的width和height属性放大为2倍。
2)将canvas的CSS样式width和height设置为原先1倍的大小。
<canvaswidth="200"height="100"style="width:100px;height:50px;"></canvas>
2.截图不全
源码获取dom高度不准确,修改源码,获取高度后手动传,修改方式如下:
源码:
returnrenderDocument(node.ownerDocument,options,node.ownerDocument.defaultView.innerWidth,node.ownerDocument.defaultView.innerHeight,index).then(function(canvas){if(typeof(options.onrendered)==="function"){log("options.onrenderedisdeprecated,html2canvasreturnsaPromisecontainingthecanvas");options.onrendered(canvas);}returncanvas;});
修改后
//添加自定义高度宽度varwidth=options.width!=null?options.width:node.ownerDocument.defaultView.innerWidth;varheight=options.height!=null?options.height:node.ownerDocument.defaultView.innerHeight;returnrenderDocument(node.ownerDocument,options,width,height,index).then(function(canvas){if(typeof(options.onrendered)==="function"){log("options.onrenderedisdeprecated,html2canvasreturnsaPromisecontainingthecanvas");options.onrendered(canvas);}returncanvas;});
3.截图慢
截图慢得从html2canvas的原理说起,html2canvas并不是真正的截图,而是遍历加载的页面DOM,收集所有元素的信息,然后基于从DOM读取的属性使用canvas来绘制。
基于这个截图原理,慢的问题优化空间不大,而且html2canvas还有些CSS的限制,它只能正确地呈现它支持的CSS属性,完整的CSS属性支持列表,可以在官网查看。
关于慢,最简单的解决方案是在用户操作前提前生成截图。
4.crash
html2canvas截图后,将图片的base64传到客户端的分享组件,当base64超过500k可能导致客户端卡死或crash,如果慢的问题还能忍,那这个问题是真的没法接受的。
svg
除了html2canvas网上也有更轻量更快的库,这些库是基于svg的,尝试了下确实比html2canvas快很多。
svg方案的尝试:
//要转成图片的domlethtm='<svgxmlns="http://www.w3.org/2000/svg"width="100%"height="auto"><foreignObjectwidth="100%"height="100%"><divxmlns="http://www.w3.org/1999/xhtml"><div>这里是页面内容...</div></div></foreignObject></svg>';letDOMURL=window.URL||window.webkitURL||window;letcanvas=document.createElement('canvas');letctx=canvas.getContext('2d');letimg=newImage();letsvg=newBlob([htm],{type:'image/svg+xml;charset=utf-8'});leturl=DOMURL.createObjectURL(svg);letimgBase64;img.onload=function(){ctx.drawImage(img,0,0);imgBase64=canvas.toDataURL();}img.src=url;
svg方案没法绕过的坑:
1.ios下不支持跨域图片
由于安全限制,ios下跨域图片加crossOrigin
属性也没法绕过跨域问题。
2.crash
和html2canvas一样,svg转图片后最终也是转base64传分享组件,base64超过500K可能导致的卡死和crash问题也存在。
服务器端实现方案
开发:浏览器端的方案crash问题不能忍,不如在服务器端生成图片,传图片URL到分享组件?
本着最大限度复用代码的初衷,首选了无头浏览器phantomjs截图的方案。
PhantomJS
PhantomJS是基于WebKit内核的无头浏览器,提供浏览器环境的命令行接口,我们可以进行网页截图、抓取网页数据等操作,更多详情可以去PhantomJS官网查看。
安装PhantomJS时,注意安装以下依赖:
sudoyum-yinstallgccgcc-c++makeflexbisongperfrubyopenssl-develfreetype-develfontconfig-devellibicu-develsqlite-devellibpng-devellibjpeg-devel
服务器端方案选择的是phantomjs-node库,实现截图的核心代码如下
varsitepage=null;varphInstance=null;phantom.create().then(instance=>{phInstance=instance;returninstance.createPage();}).then(page=>{lethtm=['<!DOCTYPEhtml>','<html>','<head>','<metacharset="utf-8">','</head>','<bodystyle="background:#fff">','<div>'+newDate()+'</div>','</body>','</html>'].join("");page.property('content',htm);page.render('./test.png').then((err)=>{phInstance.exit()}).catch(err=>{phInstance.exit();})}).catch(error=>{phInstance.exit();});
PhantomJS遇到的坑也不少,主要是环境问题:
1.没截图生成
开发:在mac上和windows上生成截图正常,部署到测试环境后不能生成截图,打印PhantomJS日志,没有明确的报错信息。linux下权限问题?
查看PhantomJS和目录权限,PhantomJS没有写权限,修复权限问题,图片仍然不能生成。
开发:字母命名的截图正常生成,不支持图片文件名包含数字?
一番验证,截图名包含数字phantomjs-node不能正常生成图片文件。
2.截图空白
开发:颜色和图案均能够渲染到截图中,只有文字不能渲染,字体有问题?
确认测试机中字体目录为空,更新字体,文字终于能正常渲染到截图中。
3.截图模糊
又是模糊问题…
css使用相对rem单位,PhantomJS截图是设置缩放参数:
//csshtml{font-size:100px;}.owner_avatar{width:.30rem;height:.30rem;border-radius:.30rem;margin-right:.10rem;}.events_img{width:.50rem;height:.50rem;}//phantomjs缩放处理page.property('viewportSize',{width:828,height:736});page.property('zoomFactor',2)page.property('content',htm);
4.截图加载慢
模糊问题设置2倍图后,图片大小暴涨到6M+,导致加载慢,设置截图质量:
page.render(fileName,{quality:85}).then((err)=>{phInstance.exit();})
5.截图慢
PhantomJS生成一个最简单的截图,耗时2S左右,这个速度显然是不能接受的,暂时没找到比较好的优化方式。
node canvas
node canvas扩展了canvas API以提供与节点的接口,例如流式传输PNG数据,转换为Buffer实例等,更多介绍可以去node canvas官网查看。
node canvas的环境搭建比较麻烦,依赖库与PhantomJS类似,这里就不列举了。
绘制图片的核心代码:
const{createCanvas,loadImage}=require('canvas');constcanvas=createCanvas(200,200);constctx=canvas.getContext('2d');ctx.font='30px';ctx.fillText('test',50,100);loadImage('test.jpg').then((image)=>{ctx.drawImage(image,0,0,70,70);})
node canvas与下面imagemagick的方案对比,imagemagick的性能更好,node canvas没再深入只实现了简单demo,踩坑不多。
ImageMagick 与 GraphicsMagick
ImageMagick是一套功能强大、稳定而且免费的工具集和开发包,可以用来读、写和处理超过90种的图片文件,包括流行的TIFF、JPEG、GIF、 PNG、PDF以及PhotoCD等格式。
ImageMagick可以根据web应用程序的需要动态生成图片, 还可以对一个(或一组)图片进行改变大小、旋转、锐化、减色或增加特效等操作,并将操作的结果以相同格式或其它格式保存,对图片的操作,即可以通过命令行进行,也可以用C/C++、Perl、Java、PHP、Python或Ruby编程来完成。更多详情可在ImageMagick官网查看。
GraphicsMagick是从 ImageMagick 5.5.2 分支出来的,据说它变得更稳定和优秀,更多详情可在GraphicsMagick官网查看。
看起来GraphicsMagick是更好的选择,但是由于node gm这个库没有实现GraphicsMagick的半透明和圆角支持,而且针对专辑的大事件长图做了一些性能对比两者差异不大,所以选择使用ImageMagick。
node gm切换ImageMagick的方式非常简单,只要加以下设置:
vargm=require('gm');varimageMagick=gm.subClass({imageMagick:true});
不可避免的,使用ImageMagick也遇到一些坑:
1.半透明遮罩
设计:专辑封面背景使用白透明遮罩,遮罩的颜色根据封面图来定,深色封面图用白色文字,浅色封面图用黑色文字。
开发:OK,先canvas获取封面图颜色信息,再判断颜色深浅
//RGB与YUV互转,Y>=128为浅色Y'=0.299*R'+0.587*G'+0.114*B'U'=-0.147*R'-0.289*G'+0.436*B'=0.492*(B'-Y')V'=0.615*R'-0.515*G'-0.100*B'=0.877*(R'-Y')R'=Y'+1.140*V'G'=Y'-0.394*U'-0.581*V'B'=Y'+2.032*U'//ImageMagick设置透明色.fill("rgba(0,0,0,.5)")
2.头像圆角
设计:这些头像要用圆角哦。
开发:OK(还好ImageMagick支持圆角)
.fill("avatar.jpg").drawCircle(80,120,30,120)
ImageMagick圆角图片实现方式与canvas类似,画一个圆,然后用头像图片去填充来实现头像圆角。
3.昵称emoji表情
ImageMagick绘制昵称中的表情图比较麻烦,使用支持emoji的字体,尝试过Twitter的彩色emoji字体,但是ImageMagick有BUG,不能还原为彩色的。
最终解决方案:
1)使用等宽字体,方便计算精确的emoji位置
2)ImageMagick绘制昵称中的表情图片
.draw("imageOver"+size+""+url)
ImageMagick性能优化:
ImageMagick生成单张图片耗时100ms左右,但是并发请求多了平均耗时就暴涨到3S+,这个速度显然是不能接受的,经过一番优化后将平均耗时降到1S左右,主要优化点如下:
1.gm代码拼接,VM中执行
多次调用gm多次操作图片,严重影响性能,将图片操作代码拼接成字符串,在VM中执行,只调用一次gm,核心代码如下:
letsandbox={gm:imageMagick,start:Date.now()}//计算图片高度letoffset=getOffset();letqrcodeStr=getQrcodeStr();lettitleStr=(function(){return['.fontSize(24)','.fill("gray")','.drawText(164,152,"我是标题")'];})();letstr='gm(828,'+offset.height+',"#fff").font("'+FONTS+'",48)'+titleStr+qrcodeStr+'.quality(90).write("test.jpg",function(err){console.log(err||Date.now()-start)})';letscript=newvm.Script(str);letcontext=vm.createContext(sandbox);script.runInContext(context);
2.mpc格式
mpc是ImageMagick提供的一种持久高速缓存格式,减少对图像格式进行解码和编码像素的开销。
mpc生成两个文件:
1)一个扩展名.mpc保留了与图像或图像序列相关的所有属性(例如宽度,高度,色彩空间等)。
2)一个扩展名.cache,是本地原始格式的像素缓存。
读取mpc图像文件时,ImageMagick读取图像属性,并将内存映射到磁盘上的像素缓存,无需解码图像像素,不过mpc的文件大小比其他图像格式大。
mpc图像文件适用于一次写入,多次读取模式,使用mpc将图像直接映射到内存,而不是每次重新读取和解压源图像。
3.Q8版本
ImageMagick Q16版本允许在不缩放的情况下读写16位图像,但像素缓存消耗的资源是Q8版本的两倍,Q8版本的执行速度通常比Q16版本要快。
像素缓存消耗=宽度*高度*位深度/8*通道Q8位深=8Q16位深=16通道=红+绿+蓝+阿尔法强度
</div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
web浏览器端怎么实现的详细内容,希望对您有所帮助,信息来源于网络。