自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

聊聊生成水印原理與插件編寫

開發(fā) 前端
今天分享一個(gè)小程序生成水印的小技巧——canvas繪制背景圖,接下來我會(huì)詳細(xì)介紹繪制的細(xì)節(jié)。希望開發(fā)過微信小程序的同學(xué)可以把文章收藏起來,這樣如果以后遇到類似的需求,可以翻出來作為參考。

[[407766]]

本文轉(zhuǎn)載自微信公眾號(hào)「前端Sharing」,作者前端Sharing。轉(zhuǎn)載本文請(qǐng)聯(lián)系前端Sharing公眾號(hào)。

一 前言

今天分享一個(gè)小程序生成水印的小技巧——canvas繪制背景圖,接下來我會(huì)詳細(xì)介紹繪制的細(xì)節(jié)。希望開發(fā)過微信小程序的同學(xué)可以把文章收藏起來,這樣如果以后遇到類似的需求,可以翻出來作為參考。

本文的插件同樣適用于Taro,uniapp,原生等構(gòu)建的小程序項(xiàng)目,項(xiàng)目demo是采用Taro-Vue構(gòu)建的。

我們先來看看demo效果。

二 原理實(shí)現(xiàn)

canvas繪制背景圖這個(gè)方案原理本質(zhì)上是非常簡單的,就如把大象放冰箱一共分成三步那樣簡單????。

  • 第一步冰箱門打開,因?yàn)檫@個(gè)功能是前端實(shí)現(xiàn)的,而且是canvas畫出來的,所以我們需要海報(bào)的基礎(chǔ)配置,比如canvas海報(bào)寬高,文字內(nèi)容,文字顏色,海報(bào)文字的旋轉(zhuǎn)角度等。
  • 第二步把大象??放進(jìn)去,canvas得到配置,繪制水印底圖。

那么問題來了,我們繪制的底圖是整張水印底圖嗎?

答案是否定的。我們只需要畫一個(gè)模版圖片就可以了,如下圖所示:

但是為了讓水印填充整個(gè)手機(jī)屏幕,我們需要將水印圖片作為背景圖片,然后設(shè)置background-repeat:repeat;就可以了。

  • 第三步把冰箱門關(guān)上,我們通過canvas生成的圖片,將圖片填充整個(gè)屏幕就可以了。

三 細(xì)節(jié)實(shí)現(xiàn)

demo樣板

canvas模版接下來我們開始實(shí)現(xiàn)具體的細(xì)節(jié),首先我們頁面放入一個(gè)

  1. <view 
  2.     class="markBox" 
  3.     :style="{ backgroundImage: `url(${url})` }" 
  4. >   
  5.     <canvas 
  6.       v-show="isShow" 
  7.       :id="settings.id" 
  8.       type="2d" 
  9.       :class="settings.id" 
  10.       :style="{ width:settings.width + 'px' , height : settings.height + 'px' }" 
  11.     /> 
  12. </view

 

  1. 這里有一點(diǎn)值得注意,就是我們?cè)O(shè)置的type = '2d'最好不要用canvasId方式來操作canvas,包括獲取canvas實(shí)例,調(diào)用canvasToTempFilePathapi等,不然可能會(huì)失效。這里采用的是通過id方式,來獲取canvas實(shí)例的。
  2. 當(dāng)我們繪制完成后,隱藏canvas,將view容器設(shè)置背景圖片,背景圖片就是canvas繪制形成的圖片。
  3. canvas寬度和高度是根據(jù)canvas的配置項(xiàng)添加的,所以我們要?jiǎng)討B(tài)用style屬性設(shè)置寬高。

配置項(xiàng)

  1. export default { 
  2.    /* 前端生成水印 */ 
  3.    name:"MakeWaterMark"
  4.    data(){ 
  5.        return { 
  6.            isShow:true
  7.            url:''
  8.            settings: { 
  9.                 'id''waterMark',                  /* canvas id */ 
  10.                 'content''我不是外星人',            /* 水印內(nèi)容 */ 
  11.                 'width': 200,                       /* 圖片/canvas 寬度 */ 
  12.                 'height': 200,                      /* 圖片/canvas 高度 */  
  13.                 'rotate': -45,                      /* 水印文案旋轉(zhuǎn)角度*/  
  14.                 'left':60,                          /* 水印文案相對(duì)圖片水平偏移量 */ 
  15.                 'top':80,                           /* 水印文案相對(duì)圖片垂直偏移量 */ 
  16.                 'fontSize''15px',                 /* 水印文字大小 */ 
  17.                 'fontFamily''Microsoft JhengHei', /* 水印文字樣式 */ 
  18.                 'bg''#fff',                       /* 圖片背景顏色 */  
  19.                 'color''#ccc',                    /* 水印文字顏色 */ 
  20.                 'fontWeight''normal',             /* 水印文字寬度 */ 
  21.             } 
  22.        } 
  23.    }, 

樣式處理

  1. .markBox{ 
  2.     position: fixed; 
  3.     left:0; 
  4.     right:0; 
  5.     bottom: 0; 
  6.     top:0; 
  7.     background-repeat:repeat ; 
  • 給外層容器設(shè)置樣式,能夠讓水印圖片平鋪整個(gè)頁面。

插件核心代碼

插件的核心功能就是生成水印圖片,除此之外還要滿足兩個(gè)要求:

  • 插件本身和頁面/組件低耦合。插件本身可以在任何組件中使用。
  • 插件不受構(gòu)建平臺(tái)的限制,就是既能在原生微信小程序中使用,也能在Taro,uniapp等構(gòu)建工具中使用。

接下來我們看一下具體細(xì)節(jié):

  1. function createPromise(callback){ 
  2.     return new Promise((resolve,reject)=>{ 
  3.         callback(resolve,reject) 
  4.     }) 
  5.  
  6. /** 
  7.  * 制作水印圖片 
  8.  */ 
  9. class MarkwaterMark{ 
  10.     constructor(options){ 
  11.         /* 初始化配置 */ 
  12.        this.platform  = null  
  13.        this.pixelRatio = null 
  14.        this.context = null 
  15.        this.options = options  
  16.        this.ready = createPromise(this._init.bind(this))    
  17.        /* 生成組件方法 */ 
  18.        this.make = (cb) => {  
  19.           if(this.context){ 
  20.              this._markPicture(cb) 
  21.           }else
  22.               this.ready.then(()=>{ 
  23.                  this.context && this._markPicture(cb) 
  24.               }) 
  25.           }     
  26.        } 
  27.     } 
  28.     /* 初始化方法 */ 
  29.     _init(next,fail){ 
  30.        const { platform , pixelRatio } = wx.getSystemInfoSync() 
  31.        this.platform = platform 
  32.        this.pixelRatio = pixelRatio 
  33.        const query = wx.createSelectorQuery() 
  34.        query.select('#' + this.options.id ).fields({ 
  35.         node: true
  36.         sizetrue 
  37.       }).exec((res)=>{ 
  38.         let { 
  39.             node, 
  40.         } = res[0] || {}  
  41.         if (!node) return fail && fail() 
  42.         this.context = node.getContext('2d')     
  43.         this.node = node 
  44.         next() 
  45.       }) 
  46.     } 
  47.     /* 制作水印圖片 */ 
  48.     _markPicture(cb){ 
  49.        const { width , height , bg ,color ,fontSize, fontFamily,fontWeight ,content , lefttop ,rotate } = this.options 
  50.        this.node.width = (width || 200) * this.pixelRatio 
  51.        this.node.height =( height || 200) * this.pixelRatio 
  52.        this.context.scale(this.pixelRatio,this.pixelRatio) 
  53.        this.context.fillStyle = bg || '#fff' 
  54.        this.context.fillRect(0, 0, width, height) 
  55.        this.context.fillStyle = color || '#000' 
  56.        this.context.save() 
  57.        this.context.translate(left,top
  58.        this.context.rotate(Math.PI * rotate / 180 ) 
  59.        this.context.font =  `${fontWeight} 400 ${fontSize} ${fontFamily}` 
  60.        this.context.fillText(content, 0, 0) 
  61.        this.context.restore()  
  62.        this._savePicture(cb) 
  63.     } 
  64.     /* 生成圖片 */ 
  65.     _savePicture(cb){ 
  66.      const { width , height  } = this.options 
  67.        wx.canvasToTempFilePath({ 
  68.           x:0, 
  69.           y:0, 
  70.           width, 
  71.           height, 
  72.           destWidth:width*1, 
  73.           destHeight:height*1, 
  74.           canvas:this.node, 
  75.           success:function(res){ 
  76.              cb && cb(res.tempFilePath) 
  77.           } 
  78.        }) 
  79.     } 
  80. /** 
  81.  *  
  82.  * @param {*} options 配置項(xiàng) 
  83.  */ 
  84. function makeWatermark(options){ 
  85.   if(!wx) return null 
  86.   return new MarkwaterMark(options)  
  87.  
  88. module.exports = makeWatermark 

核心功能流程分析:

  • 第一步:暴露makeWatermark接口,可以實(shí)例化一個(gè)MarkwaterMark對(duì)象,實(shí)例化過程中本身先進(jìn)行初始化配置,包裹一層Promise用于創(chuàng)建圖片。由于canvas操作中,很多方法都是異步的,所以用 createPromise 方法代理一層Promise。
  • 第二步:MarkwaterMark對(duì)象上,有make方法,會(huì)獲取canvas實(shí)例,然后設(shè)置canvas畫布的寬高和縮放比,繪制水印canvas。
  • 第三步:將canvas通過canvasToTempFilePath接口把canvas畫布轉(zhuǎn)化成臨時(shí)圖片,并把臨時(shí)圖片路徑通過callback形式,傳遞給業(yè)務(wù)組件或者頁面。

插件使用

在業(yè)務(wù)組件(上述demo)中,我們就可以使用上述插件了。具體參考如下:

  1. mounted(){  
  2.       Taro.nextTick(()=>{ 
  3.           /* 創(chuàng)建一個(gè)  makeWatermark 對(duì)象 */ 
  4.           const marker = makeWatermark(this.settings) 
  5.           /* 調(diào)用make,生成圖片 */ 
  6.           marker.make((url)=>{ 
  7.               /* url 為臨時(shí)路徑  */ 
  8.               const fileManage = Taro.getFileSystemManager() 
  9.               let base64 = 'data:image/jpg;base64,' + fileManage.readFileSync(url,'base64'); 
  10.               this.url = base64 
  11.               this.isShow  = false 
  12.           }) 
  13.       }) 
  14.   }, 

重要細(xì)節(jié):

這里還有一個(gè)比較重要細(xì)節(jié)就是,小程序中背景圖片一般都是網(wǎng)絡(luò)圖片或者base64圖片,對(duì)于臨時(shí)路徑的圖片在真機(jī)上是不顯示的。為了解決這個(gè)問題,我們需要把臨時(shí)圖片轉(zhuǎn)換成base64格式圖片。

  • 通過 getFileSystemManager 以 base64方式訪問剛生成的臨時(shí)圖片,然后返回base64格式,接下來就可以把 base64 圖片設(shè)置為背景圖片了。

效果:

大功告成!!!

四 總結(jié)

 

通過本文我們學(xué)習(xí)了微信小程序生成水印的方式和流程。還有一些開發(fā)中的細(xì)節(jié)問題。感興趣的同學(xué)可以收藏起來,以備不時(shí)之需。

 

責(zé)任編輯:武曉燕 來源: 前端Sharing
相關(guān)推薦

2024-12-30 14:47:02

2022-12-11 20:09:50

網(wǎng)絡(luò)編程通信

2021-02-08 21:40:04

SockmapBPF存儲(chǔ)

2024-09-13 16:47:06

模型量化AI

2012-06-12 15:43:22

PHP

2021-09-10 06:46:00

MySQL連接控制

2023-06-30 07:51:44

springboot初始化邏輯

2011-04-06 16:02:26

Nagios插件

2011-03-28 11:20:11

Nagios 插件

2011-06-27 17:24:37

Qt 插件

2022-02-06 22:13:47

VueVue3.0Vue項(xiàng)目

2022-06-21 07:51:06

Redis高可用哨兵進(jìn)程

2024-05-09 09:55:08

2024-08-05 11:14:45

2024-12-23 15:05:29

2023-11-07 08:13:53

分布式網(wǎng)絡(luò)

2023-09-21 08:05:49

Mybatis插件開發(fā)

2021-04-19 10:45:52

Webpack熱更新前端

2021-07-14 14:05:24

Fragment項(xiàng)目結(jié)構(gòu)

2022-07-26 07:14:52

Docker宿主命令
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)