当前位置: 首页 > 科技观察

说说水印生成原理和插件编写

时间:2023-03-20 23:29:48 科技观察

本文转载自微信公众号《前端分享》,作者前端分享。转载本文请联系前端分享♂。一、前言今天分享一个小程序生成水印的小技巧——canvas绘制背景图。接下来,我将详细介绍绘图的细节。希望有开发过微信小程序的同学把文章收藏起来,方便以后遇到类似需求的时候转出来作为参考。本文插件同样适用于Taro、uniapp、native等搭建的小程序项目,项目demo使用Taro-Vue搭建。我们先来看看演示效果。2原理实现canvas绘制背景图这个方案的原理本质上很简单,就像把大象放进冰箱一样简单分三步????。第一步打开冰箱门,因为这个功能是前端实现的,由canvas绘制的,所以我们需要海报的基本配置,比如canvas海报的宽高,文字内容,text颜色,海报文字的旋转角度等。第二步是放大象??中,配置画布,绘制水印底图。那么问题来了,我们绘制的底图是不是整个水印底图呢?答案是不。我们只需要画一个模板图,如下图:但是为了让水印充满整个手机屏幕,我们需要将水印图作为背景图,然后设置background-repeat:repeat;.第三步,关上冰箱门,我们就可以用canvas生成的图片填满整个屏幕。实现demo模板canvas模板的三个细节接下来,我们开始实现具体的细节。首先,我们放一个这里值得注意的是我们设置了type='2d',最好不要使用canvasId方法操作画布,包括获取画布实例,调用canvasToTempFilePathapi等,否则可能会失败。这里我们使用id方法来获取画布实例。当我们绘制完成后,隐藏画布,并设置视图容器的背景图片,也就是画布绘制形成的图像。画布的宽高是根据画布的配置项添加的,所以我们需要通过style属性动态设置宽高。配置项exportdefault{/*前端生成水印*/name:"MakeWaterMark",data(){return{isShow:true,url:'',settings:{'id':'waterMark',/*canvasid*/'content':'我不是外星人',/*水印内容*/'width':200,/*image/canvaswidth*/'height':200,/*image/canvasheight*/'rotate':-45,/*水印副本的旋转角度*/'left':60,/*水印副本相对于图像的水平偏移量*/'top':80,/*水印副本相对于图像的垂直偏移量*/'fontSize':'15px',/*水印文字大小*/'fontFamily':'MicrosoftJhengHei',/*水印文字样式*/'bg':'#fff',/*图片背景颜色*/'color':'#ccc',/*水印文字颜色*/'fontWeight':'normal',/*水印文字宽度*/}}},}styleprocessing.markBox{position:fixed;left:0;right:0;bottom:0;top:0;background-repeat:repeat;}设置外层容器的样式,使水印图片平铺整个页面。插件核心代码插件的核心功能是生成水印图片。此外,必须满足两个要求:插件本身与页面/组件低耦合。插件本身可以在任何组件中使用。该插件不受构建平台限制,即不仅可以在原生微信小程序中使用,还可以在Taro、uniapp等构建工具中使用。接下来我们看细节:functioncreatePromise(callback){returnnewPromise((resolve,reject)=>{callback(resolve,reject)})}/***制作水印图片*/classMarkwaterMark{constructor(options){/*初始化配置*/this.platform=nullthis.pixelRatio=nullthis.context=nullthis.options=optionsthis.ready=createPromise(this._init.bind(this))/*生成组件方法*/this.make=(cb)=>{if(this.context){this._markPicture(cb)}else{this.ready.then(()=>{this.context&&this._markPicture(cb)})}}}/*初始化方法*/_init(接下来,失败){const{platform,pixelRatio}=wx.getSystemInfoSync()this.platform=platformthis.pixelRatio=pixelRatioconstquery=wx.createSelectorQuery()query.select('#'+this.options.id).fields({node:true,size:true}).exec((res)=>{let{node,}=res[0]||{}if(!node)returnfail&&fail()this.context=node.getContext('2d')this.node=nodenext()})}/*制作水印图片*/_markPicture(cb){const{width,height,bg,color,fontSize,fontFamily,fontWeight,content,left,top,rotate}=这个.optionsthis.node.width=(width||200)*this.pixelRatiothis.node.height=(height||200)*this.pixelRatiothis.context.scale(this.pixelRatio,this.pixelRatio)this.context.fillStyle=bg||'#fff'this.context.fillRect(0,0,宽度,高度)this.context.fillStyle=color||'#000'this.context.save()this.context.translate(left,top)this.context.rotate(Math.PI*rotate/180)this.context.font=`${fontWeight}400${fontSize}${fontFamily}`this.context.fillText(content,0,0)this.context.restore()this._savePicture(cb)}/*生成图片*/_savePicture(cb){const{width,height}=this.optionsswx.canvasToTempFilePath({x:0,y:0,width,height,destWidth:width*1,destHeight:height*1,canvas:this.node,success:function(res){cb&&cb(res.tempFilePath)}})}}/****@param{*}options配置项*/functionmakeWatermark(options){if(!wx)returnnullreturnnewMarkwaterMark(options)}module.exports=makeWatermark核心函数流程分析:第一步:暴露makeWatermark接口,可以实例化一个MarkwaterMark对象。在实例化过程中,首先进行初始化配置,再包裹一层Promise来创建图片。由于canvas操作,有很多方法,它们都是异步的,所以使用createPromise方法代理了一层Promise。第二步:MarkwaterMark对象上有一个make方法,会获取canvas实例,然后设置canvas的宽高和缩放比例,绘制水印canvas。第三步:通过canvasToTempFilePath接口将canvas画布转换为临时图片,并通过回调形式将临时图片路径传递给业务组件或页面。插件是在业务组件中使用的(上面的demo),我们可以使用上面的插件。具体参考如下:mounted(){Taro.nextTick(()=>{/*创建makeWatermark对象*/constmarker=makeWatermark(this.settings)/*调用make生成图片*/marker.make((url)=>{/*url是临时路径*/constfileManage=Taro.getFileSystemManager()letbase64='data:image/jpg;base64,'+fileManage.readFileSync(url,'base64');this.url=base64this.isShow=false})})},Importantdetails:这里还有一个很重要的细节,就是小程序中的背景图片一般都是网络图片或者base64图片,临时路径的图片不会显示在真机。为了解决这个问题,我们需要将临时图片转换成base64格式的图片。通过getFileSystemManager访问新生成的base64临时图片,然后返回base64格式,然后设置base64图片为背景图片。效果:大功告成!!!四、总结通过本文,我们了解了微信小程序生成水印的方法和过程。还有一些细节在开发中。有兴趣的同学可以收藏起来以备不时之需。