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

前端海报生成的不同方案及优缺点

时间:2023-04-05 02:06:36 HTML5

1.后台工作中,做了很多海报生成功能。针对不同的需求和场景,采用了多种方案,各有优缺点。一直想整理一下,但是这个过程中的思考和遇到的问题一直没有记录下来,比如图片的跨域问题,文本的问题,完成后没有记录,也没有痕迹找不到,所以很难下手。最近查阅了一下,整理了一份文档。可能有遗漏和不准确之处。欢迎交流。2.业务应用pc:1.分享海报H5应用:1??.分享优惠券2.年费账单3.分享海报3.实现方法及兼容性问题第三方库1.html2canvas版本1.0.0rc7https://github.com/niklasvh/h...star:22k时间2021-01-06首页测试演示:https://html2canvas.hertzen.com/兼容性测试Android?6.0koobee?5.0.2vovoY51AAndroid微信版-内置?7.0.3?7.0.22ios?14.2?11.2.1ios微信内置?7.0.20?7.0.1优点:兼容性更好,官方描述如下:Firefox3.5+GoogleChromeOpera12+IE9+Safari6+由于每个CSS属性都需要手动构建才能支持,所以还有一些属性还不支持。缺点:有些属性不支持转换:比如伪类,border不支持dash,不支持text-shadow,(就是还原度需要和设计沟通,或者考虑用图片等formstoreplacedisplayelements)features:https://html2canvas.hertzen.c...备注ios代已经出现rc5无法解决图片问题,恢复为rc4即可。https://github.com/niklasvh/h...在issue中看到微信在某些版本的ios下失败,暂时没有复现。2dom-to-imgversion2.6.0https://github.com/tsayen/dom...star:6.9k优点元素齐全,还原度高缺点不兼容Safari,建议只用Chrome下无维护更新兼容性问题1.作者明确表示不支持safari是因为foreignObject的安全问题(明明说不支持,我仔细看了文档=>白作工)链接:https://github.com/tsayen/dom...https://html.spec.whatwg.org/...SVG在Web攻击中的应用:https://www.anquanke.com/post..。2.iOS14.2下,图片丢失的问题其实是在测试的时候。发现在ios14.2下生成的图片第一次总是会出现图片丢失。第二种或第三种正常解决方法,调用2到3次,取最后一次(看issue,部分机型还不支持)3.在低端安卓手机上会出现故障,主要是文字问题(这里有一个旧记录我写的,不是很确定)适用于PC或Android清晰度问题:(看到很多人说要改源码,其实大可不必,作者已经提供了参数)放大DPR倍数设备通过规模letelm=document.getElementById('my-node')constscale=window.devicePixelRatiothis.loader.open()awaitthis.$nextTick()domtoimage.toBlob(elm,{quantity:1,width:elm.offsetWidth*scale,//画布放大高度:elm.offsetHeight*scale,style:{transform:`scale(${scale})`,//元素缩放transformOrigin:'00',},}).then(this.upload)//处理result.catch(function(error){this.loader.close()console.error('糟糕,出错了!',error)})前端画布绘制0.canvasletcanvasBox=document.createElement('canvas')letctx=canvasBox.getContext('2d')asCanvasRenderingContext2D1.imgletbgImag=''ctx.drawImage(bgImg,0,0)1.2解决图片跨域问题:1)使用crossOrigin属性解决canvas图片getImageData,toDataURL的跨域问题2)图片本身也需要允许跨域3)设置useCORS:true,原理一样,但是使用上面的跨域方法,如果设置allowTaint:true同时,画布仍会被认为是被污染的不可用;2.Text2.2TextWrap核心:计算所有文本,根据每行所能显示的最大宽度拆分成每行进行渲染。参考:https://www.zhangxinxu.com/wordpress/2018/02/canvas-text-break-line-letter-spacing-vertical/2.2字体类型2.2.1。只使用默认字体或少量自定义字体(Fontmin获取特定字体的字体,硬编码数据,如果换行需要计算换行问题-空格回车等怪异问题)-==@font-face,这样使用涉及到版权问题,请确保你拥有字体的版权==@font-face{font-family:"DINCondensed";//prettier-ignoresrc:url("~@/assets/fonts/DIN-Condensed-Bold.woff")format("woff"),url("~@/assets/fonts/DIN-Condensed-Bold.ttf")format("ttf");}@font-face{font-family:"PingFangSCBold";//prettier-ignoresrc:url("~@/assets/fonts/PingFang-SC-Bold.ttf")format("ttf"),url("~@/assets/fonts/PingFang-SC-Bold.woff")format("woff");}ctx.fillText('20pxPingFangSCBold',x,y)ctx.fillText('20px',x,y)2.2.2(在一定字体的情况下必须complete:动态变化数据,需要接口支持)svgtoimgdirectdomtoSvg也有Android失败的问题letsvg=interfacetogetsvg(参考年度账单)letsvgBase64:string='data:image/svg+xml;base64,'+window.btoa(unescape(encodeURIComponent(svg)))awaitthis.loadImg(svgBase64).then(img=>{ctxC.drawImage(img,~~(20*this.scale),~~(186*this.scale))})3.手机上的比例计算//尽量使用整数//devicePixelRatioprotectedimgQuality=window.devicePixelRatio//设计稿与设计稿宽度的比例为640getscale(){return(document.body.clientWidth*this.imgQuality)/640}//画布宽高,避免生成图片模糊canvasBox.width=Math.ceil(document.body.clientWidth*this.imgQuality)canvasBox.height=Math.ceil(980*this.scale)//二维码的宽度getqrCodeSize(){return~~(155*this.scale)//rpx*scale}4.常用元素/线/圆/圆角Rectangle//画布与画布的比例设计稿750scale=(document.body.clientWidth*this.imgQuality)/750lines:***drawline*/exportfunctiondrawLine(ctx:CanvasRenderingContext2D,data:{x:numbery:numberwidth:numberheight:numberstrokeStyle:string},scale:数字){letx=data.x*scalelety=data.y*scaleletdx=(data.x+data.width)*scaleletdy=data.y*scale//开始一个新的绘图路径ctx.beginPath()//定义直线的起点坐标为(10,10)ctx.moveTo(x,y)//定义直线的终点坐标为(50,10)ctx.lineTo(dx,dy)//Colorctx.strokeStyle=data.strokeStyle//沿坐标点顺序的路径绘制直线ctx.stroke()//关闭当前绘制路径ctx.closePath()}Circle:/***绘制圆*/exportfunctiondrawCircle(ctx:CanvasRenderingContext2D,data:{x:number//圆心y:numbersize:number//radiusfillStyle:string},scale:number){ctx.save()ctx.beginPath()ctx.arc(~~(data.x*scale),~~(data.y*scale),~~(data.size*scale),0,~~(data.size*scale*Math.PI))ctx。fillStyle=data.fillStylectx.fill()ctx.restore()}Rectangle:/***画一个圆角矩形*/exportfunctiondrawRoundRect(ctx:CanvasRenderingContext2D,data:{x:numbery:numberwidth:numberrheight:numberradius:numberfillStyle:string},scale:number){letwidth=~~(data.width*scale)letheight=~~(data.height*scale)letradius=~~(data.radius*scale)letfillStyle=data.fillStylectx.save()ctx.translate(~~(data.x*scale),~~(data.y*scale))ctx.beginPath()//从右下顺时针方向绘制,从0到1/2PI的弧度ctx.arc(width-radius,height-radius,radius,0,Math.PI/2)//矩形的底线ctx.lineTo(radius,height)//arcatthe左下角,弧度从1/2PI到PIctx.arc(radius,height-radius,radius,Math.PI/2,Math.PI)//矩形的左线ctx.lineTo(0,radius)//左上弧,从PI到3/2PI的弧度ctx.arc(radius,radius,radius,Math.PI,(Math.PI*3)/2)//上线ctx.lineTo(width-radius,0)//右上圆弧ctx.arc(width-radius,radius,radius,(Math.PI*3)/2,Math.PI*2)//右上线ctx.lineTo(width,height-radius)ctx.closePath()ctx。fillStyle=fillStylectx.fill()ctx.restore()}5.canvasBox.toBlobcanvasBox.toBlob(asyncdata=>{if(data){//上传到7niuthis.url=awaituploadFile(data)}})6.保存图片PCimport{saveAs}from'file-saver'saveAs(blob,filename)H5长按保存外壳的H5可以直接下载,但是为了交互的一致性,还是使用长按界面生成元素、位置等信息生成界面,直接生成返回图片的接口需要后端实现。(具体性能和用例欢迎讨论。)优点不需要考虑兼容性等问题缺点不支持过多的文字或字体类型,服务器压力较大(见具体实施方案),元素越多,界面越慢这个方案其实后台逻辑也是用来实现绘制元素和输出图片的(过程中遇到的问题:比如需要计算字体的高度(同一个字体的宽度中英文不同),换行情况下后续元素的相对位置发生变化)4.图片如果有跨域图片无法下载,请仔细阅读以下文字:来源:https://segmentfault.com/q/10...5.总结如果没有特殊情况,在PC下使用dom-to-image。至于h5,自己回顾了一下画海报的实现过程:1.第三方库(兼容性问题,太老记不清是怎么回事了,只记得这个方案被否决了)2.界面绘制(服务器过载性能问题,速度太慢)3.前端canvas绘制(+部分元素界面绘制返回图片或svg,基本没有兼容性问题)(太慢)4.第三方库(html2canvas,测试了兼容性一些版本的环境,但是项目还没有上线,需要观察)目前最优方案好像是html2canvas,但是有些效果达不到,需要在还原和性能上做一个权衡.6.更好的解决方案?一些常用APP的海报生成速度更快,体验更好。我想知道是否有更好的解决方案?还是h5的限制?欢迎留言~7.参考【JS】节点截图dom-to-image和html2canvas最终解决方案:https://blog.csdn.net/Mcky_Lo...手机H5页面截图:https://cloud.tencent.com/dev...从DOM节点生成base64图片:https://www.jianshu.com/p/c5c...更优雅的基于canvas在前端绘制海报:https://juejin.cn/post/684490...canvas文字绘制自动换行、字间距、竖排等https://www.zhangxinxu.com/wo...图片跨域问题:https://segmentfault.com/q/1010000008648867

猜你喜欢