最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 「微信小程序」生成水印原理与插件编写

    正文概述 掘金(我不是外星人)   2021-06-28   515

    一 前言

    今天分享一个小程序生成水印的小技巧——canvas绘制背景图,接下来我会详细介绍绘制的细节。希望开发过微信小程序的同学可以把文章收藏起来,这样如果以后遇到类似的需求,可以翻出来作为参考。

    本文的插件同样适用于Taro,uniapp,原生等构建的小程序项目,项目demo是采用Taro-Vue构建的。

    我们先来看看demo效果。

    「微信小程序」生成水印原理与插件编写

    二 原理实现

    canvas绘制背景图这个方案原理本质上是非常简单的,就如把大象放冰箱一共分成三步那样简单??。

    • 第一步冰箱门打开,因为这个功能是前端实现的,而且是canvas画出来的,所以我们需要海报的基础配置,比如canvas海报宽高文字内容文字颜色海报文字的旋转角度等。

    • 第二步把大象?放进去,canvas得到配置,绘制水印底图。

    那么问题来了,我们绘制的底图是整张水印底图吗?

    答案是否定的。我们只需要画一个模版图片就可以了,如下图所示:

    「微信小程序」生成水印原理与插件编写

    但是为了让水印填充整个手机屏幕,我们需要将水印图片作为背景图片,然后设置background-repeat:repeat;就可以了。

    「微信小程序」生成水印原理与插件编写

    • 第三步把冰箱门关上,我们通过canvas生成的图片,将图片填充整个屏幕就可以了。

    三 细节实现

    demo样板

    canvas模版 接下来我们开始实现具体的细节,首先我们页面放入一个<canvas>

    <view
        class="markBox"
        :style="{ backgroundImage: `url(${url})` }"
    >  
        <canvas
          v-show="isShow"
          :id="settings.id"
          type="2d"
          :class="settings.id"
          :style="{ width:settings.width + 'px' , height : settings.height + 'px' }"
        />
    </view>
    
    • 这里有一点值得注意,就是我们设置的type = '2d'最好不要用canvasId方式来操作canvas,包括获取canvas实例,调用canvasToTempFilePathapi等,不然可能会失效。这里采用的是通过id方式,来获取canvas实例的。

    • 当我们绘制完成后,隐藏canvas,将view容器设置背景图片,背景图片就是canvas绘制形成的图片。

    • canvas宽度和高度是根据canvas的配置项添加的,所以我们要动态用style属性设置宽高。

    配置项

    export default {
       /* 前端生成水印 */
       name:"MakeWaterMark",
       data(){
           return {
               isShow:true,
               url:'',
               settings: {
                    'id': 'waterMark',                  /* canvas id */
                    'content': '我不是外星人',            /* 水印内容 */
                    'width': 200,                       /* 图片/canvas 宽度 */
                    'height': 200,                      /* 图片/canvas 高度 */ 
                    'rotate': -45,                      /* 水印文案旋转角度*/ 
                    'left':60,                          /* 水印文案相对图片水平偏移量 */
                    'top':80,                           /* 水印文案相对图片垂直偏移量 */
                    'fontSize': '15px',                 /* 水印文字大小 */
                    'fontFamily': 'Microsoft JhengHei', /* 水印文字样式 */
                    'bg': '#fff',                       /* 图片背景颜色 */ 
                    'color': '#ccc',                    /* 水印文字颜色 */
                    'fontWeight': 'normal',             /* 水印文字宽度 */
                }
           }
       },
    }
    

    样式处理

    .markBox{
        position: fixed;
        left:0;
        right:0;
        bottom: 0;
        top:0;
        background-repeat:repeat ;
    }
    
    • 给外层容器设置样式,能够让水印图片平铺整个页面。

    插件核心代码

    插件的核心功能就是生成水印图片,除此之外还要满足两个要求:

    • 插件本身和页面/组件低耦合。插件本身可以在任何组件中使用。
    • 插件不受构建平台的限制,就是既能在原生微信小程序中使用,也能在Tarouniapp等构建工具中使用。

    接下来我们看一下具体细节:

    function createPromise(callback){
        return new Promise((resolve,reject)=>{
            callback(resolve,reject)
        })
    }
    
    /**
     * 制作水印图片
     */
    class MarkwaterMark{
        constructor(options){
            /* 初始化配置 */
           this.platform  = null 
           this.pixelRatio = null
           this.context = null
           this.options = options 
           this.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(next,fail){
           const { platform , pixelRatio } = wx.getSystemInfoSync()
           this.platform = platform
           this.pixelRatio = pixelRatio
           const query = wx.createSelectorQuery()
           query.select('#' + this.options.id ).fields({
            node: true,
            size: true
          }).exec((res)=>{
            let {
                node,
            } = res[0] || {} 
            if (!node) return fail && fail()
            this.context = node.getContext('2d')    
            this.node = node
            next()
          })
        }
        /* 制作水印图片 */
        _markPicture(cb){
           const { width , height , bg ,color ,fontSize, fontFamily,fontWeight ,content , left, top ,rotate } = this.options
           this.node.width = (width || 200) * this.pixelRatio
           this.node.height =( height || 200) * this.pixelRatio
           this.context.scale(this.pixelRatio,this.pixelRatio)
           this.context.fillStyle = bg || '#fff'
           this.context.fillRect(0, 0, width, height)
           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.options
           wx.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 配置项
     */
    function makeWatermark(options){
      if(!wx) return null
      return new MarkwaterMark(options) 
    }
    
    module.exports = makeWatermark
    

    核心功能流程分析:

    • 第一步:暴露makeWatermark接口,可以实例化一个MarkwaterMark对象,实例化过程中本身先进行初识化配置,包裹一层Promise用于创建图片。由于canvas操作中,很多方法都是异步的,所以用 createPromise 方法代理一层Promise。

    • 第二步:MarkwaterMark对象上,有make方法,会获取canvas实例,然后设置canvas画布的宽高和缩放比,绘制水印canvas。

    • 第三步:将canvas通过canvasToTempFilePath接口把canvas画布转化成临时图片,并把临时图片路径通过callback形式,传递给业务组件或者页面。

    插件使用

    在业务组件(上述demo)中,我们就可以使用上述插件了。具体参考如下:

     mounted(){ 
           Taro.nextTick(()=>{
               /* 创建一个  makeWatermark 对象 */
               const marker = makeWatermark(this.settings)
               /* 调用make,生成图片 */
               marker.make((url)=>{
                   /* url 为临时路径  */
                   const fileManage = Taro.getFileSystemManager()
                   let base64 = 'data:image/jpg;base64,' + fileManage.readFileSync(url,'base64');
                   this.url = base64
                   this.isShow  = false
               })
           })
       },
    

    重要细节:

    这里还有一个比较重要细节就是,小程序中背景图片一般都是网络图片或者base64图片,对于临时路径的图片在真机上是不显示的。为了解决这个问题,我们需要把临时图片转换成base64格式图片

    • 通过 getFileSystemManagerbase64方式访问刚生成的临时图片,然后返回base64格式,接下来就可以把 base64 图片设置为背景图片了。

    效果:

    「微信小程序」生成水印原理与插件编写

    大功告成!!!

    四 总结

    通过本文我们学习了微信小程序生成水印的方式和流程。还有一些开发中的细节问题。感兴趣的同学可以收藏起来,以备不时之需。

    我写了一本深入系统学习React的小册

    为了让大家系统的学习React,进阶React,笔者最近写了一本《React进阶实践指南》的小册,本小册从基础进阶篇优化进阶篇原理进阶篇生态进阶篇实践进阶篇,五个方向详细探讨 React 使用指南 和 原理介绍。

    • 基础进阶篇里,将重新认识react中 state,props,ref,context等模块,详解其基本使用和高阶玩法。

    • 优化进阶篇里,将讲解 React性能调优和细节处理,让React写的更优雅。

    • 原理进阶篇里,将针对React几个核心模块原理进行阐述,一次性搞定面试遇到React原理问题。

    • 生态进阶篇里,将重温React重点生态的用法,从原理角度分析内部运行的机制。

    • 实践进阶篇里,将串联前几个模块,进行强化实践。

    至于小册为什么叫进阶实践指南,因为在讲解进阶玩法的同时,也包含了很多实践的小demo。还有一些面试中的问答环节,让读者从面试上脱颖而出。

    目前以及完成前22章节,小册马上上线啦,想要进阶React的可以看过来,关注小册最新动态。

    最后, 送人玫瑰,手留余香,觉得有收获的朋友可以给笔者点赞,关注一波 ,陆续更新前端超硬核文章。


    起源地下载网 » 「微信小程序」生成水印原理与插件编写

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元