天天看點

nodejs項目(基于Express)——為上傳的圖檔貼上國旗圖示(使用gm)并傳回圖檔位置介紹小程式服務端nodejs源碼

文章目錄

  • 介紹
  • 小程式
    • 上傳使用者頭像
    • 從伺服器下載下傳圖檔
  • 服務端nodejs
    • Express搭建web應用
    • gm處理圖檔
    • 支援https
  • 源碼

介紹

前幾天微信朋友圈又開始一年一度的騙人小把戲,去年是“@微信官方,給我一頂聖誕帽”,當時太傻,還中招了。現在又開始“@微信官方,給我一面國旗”。

這個項目純屬娛樂:微信小程式擷取使用者頭像,上傳至伺服器,伺服器使用gm進行圖像處理,給頭像貼上四面紅旗,效果如下圖。有點醜,哈哈,但是達到了裝逼的效果,可以用四面紅旗碾壓你的好友。

nodejs項目(基于Express)——為上傳的圖檔貼上國旗圖示(使用gm)并傳回圖檔位置介紹小程式服務端nodejs源碼

服務端用的nodejs,使用Express搭建web服務,gm進行圖檔處理,formidable接收上傳圖檔。

本文從0開始,講述如何完成的項目。

小程式

目标效果:使用者打開小程式後,即能看到頭像标上四面國旗的樣子,點選按鈕就能儲存到相冊。(圖檔好大?将就看吧)

nodejs項目(基于Express)——為上傳的圖檔貼上國旗圖示(使用gm)并傳回圖檔位置介紹小程式服務端nodejs源碼

上傳使用者頭像

首先說上傳圖檔,微信提供的API:wx.uploadFile可以輕松的實作此功能。官方的介紹寫的是:“将本地資源上傳到伺服器。用戶端發起一個 HTTPS POST 請求,其中 content-type 為 multipart/form-data。”是以實際上是對HTTPS POST 請求再次封裝,使用更加簡易。使用方法如下:(選擇本地圖檔上傳至伺服器)

wx.chooseImage({
  success (res) {
    const tempFilePaths = res.tempFilePaths
    wx.uploadFile({
      url: 'https://example.weixin.qq.com/upload', //僅為示例,非真實的接口位址
      filePath: tempFilePaths[0],                  //标記1
      name: 'file',
      formData: {
        'user': 'test'
      },
      success (res){
        const data = res.data
        //do something
      }
    })
  }
})
           

但我的目标是上傳使用者頭像,為了簡化使用者操作,我打算直接使用微信的接口擷取使用者頭像,而不是讓使用者主動上傳儲存在本地的頭像,以此減少使用者主動操作。

現在建立微信小程式,在app.js和index.js都預設有擷取使用者資訊(頭像和昵稱)的代碼。并且頭像的資訊是以src的形式儲存的(如下src="{{userInfo.avatarUrl}}")。這個位址是網絡位址,我試過,列印出來用浏覽器能打開。

一開始我的做法是直接将這個網絡位址填入wx.uploadFile的filePath,即第一段代碼的“标記一”處。結果就報錯了。後來自己想了想确實不太合理,怎麼能夠把一張網絡圖檔“上傳”到我自己的伺服器裡呢?

是以打算先把我的頭像使用wx.downloadFile下載下傳下來,注意這裡的下載下傳并不是直接就把檔案放入本地了,而是放入了一個臨時的檔案路徑(tempFilePath)。小程式文檔對臨時檔案路徑的解釋是:“本地臨時檔案隻能通過調用特定接口産生,不能直接寫入内容。本地臨時檔案産生後,僅在目前生命周期内有效,重新開機之後即不可用。”

現在将這個臨時檔案路徑填入上述的wx.uploadFile的filePath,就能向伺服器上傳啦。(現在就去伺服器部署接收了,建議先跳過下面部分直接到nodejs部分,一會兒再回來看)

源碼在在最下面。

從伺服器下載下傳圖檔

因為需要使用者自主選擇是否儲存圖檔到相冊,是以做了個按鈕(如上面的效果圖所示),如果直接自動儲存到相冊感覺像是流氓軟體一樣,體驗極差。

點選按鈕後執行downLoadImage,如下:

downLoadImage(){
   //console.log(11)
   wx.downloadFile({
     url: this.data.imageSrc,   //将伺服器傳回的圖檔位址放入data的imageSrc
     success: function (res) {
       console.log(res);
       //圖檔儲存到本地
       wx.saveImageToPhotosAlbum({
         filePath: res.tempFilePath,  //res.tempFilePath即上面提到的臨時檔案位址
         success: function (data) {
           wx.showToast({
             title: '儲存成功',
             icon: 'success',
             duration: 2000
           })
         },
         fail: function (err) {
           console.log(err);
           if (err.errMsg === "saveImageToPhotosAlbum:fail auth denied") {
             console.log("當初使用者拒絕,再次發起授權")
             wx.openSetting({
               success(settingdata) {
                 console.log(settingdata)
                 if (settingdata.authSetting['scope.writePhotosAlbum']) {
                   console.log('擷取權限成功,給出再次點選圖檔儲存到相冊的提示。')
                 } else {
                   console.log('擷取權限失敗,給出不給權限就無法正常使用的提示')
                 }
               }
             })
           }
         },
         complete(res) {
           console.log(res);
         }
       })
     }
   })
 }
           

儲存圖檔到相冊需要使用者授權,加到app.js裡:

wx.getSetting({
  success(res) {
    if (!res.authSetting['scope.writePhotosAlbum']) {
      wx.authorize({
        scope: 'scope.writePhotosAlbum',
        success() {
          console.log('授權成功')
        }
      })
    }
  }
})
           

服務端nodejs

nodejs上手很容易,當然,要求有js基礎。我開始做的時候連nodejs是什麼都不知道。看看菜鳥教程的nodejs教程相信可以很快上手。nodejs的安裝前面這個連結裡也有。

Express搭建web應用

菜鳥教程的Node.js Express 架構介紹得非常詳細了,牆裂建議看一看。

下面是部分代碼

app.use('/public', express.static('../../../public')); //釋出的靜态檔案位址,類似web伺服器的網站釋出頁
                                                      //前面是url格式,通路如www.XXX.cn:8083/public/檔案名, 後面是檔案夾的本地位址
app.listen("8083",function () {  //監聽8083端口,成功則執行回調
    console.log(12)
});
app.post("/image",function (req,res) {
    //console.log(2);  調試用 
    var form = new formidable.IncomingForm();
    //console.log(form);
    form.encoding = 'utf-8';
    form.uploadDir = path.join(__dirname + "../../../../public");//在此,圖檔已經成功儲存,
                                                                //檔案夾随便放哪,我放在nodejs的根目錄
    form.keepExtensions = true;//保留字尾
    console.log(3);
    form.maxFieldsSize = 2 * 1024 * 1024;
           

這段代碼定義了上傳圖檔的 接口,用戶端通路http//:www.domain.com:8083/image,在伺服器的自己定義的檔案夾内就能看到上傳的圖檔。

gm處理圖檔

也就是用了幾個很常用的API,想稍深入了解的可以官網走一波。

我的操作很傻,就是把小紅旗摳下來,然後XY方向鏡像一下,貼到四個角上。

代碼片段:

gm('../../../public/'+avatarName).resize(500,500)
        .write('../../../public/'+avatarName, function (err) {
        if (err) console.log(err);
         });  //将上傳的圖檔大小調整至(500px,500px),然後重新寫入原來的位址,覆寫掉上傳的頭像
        gm()
        .in('-page', '+0+0') // 放置位置
        .in('../../../public/'+avatarName)
        .in('-page', '+0+0')
        .in('../../../public/qi.png')
        .in('-page', '+0+0')
        .in('../../../public/left-top.png')
        .in('-page', '+337+0')
        .in('../../../public/right-top.png')
        .in('-page', '+0+337')
        .in('../../../public/left-butt.png')
        .mosaic()
        .write('../../../public/'+'OK'+avatarName, function (err) {
        if (err) console.log(err);
         });//這段代碼就是在進行圖檔合并
        res.send("/public/"+"OK"+avatarName)//向用戶端發送最終生成的圖檔路徑
    })
           

支援https

也是比較煩的,如果隻是為了學習、調試着玩的話,這一步也沒必要了。

因為微信的安全要求,要想小程式上線,nodejs的接口必須搞成https,在網上搜了一番,找到了一個部落客的部落格,很有用。Nodejs配置Https服務,最後就在我的JS檔案内加了幾行,解決了問題。(結果最後還是沒有過審,算了)

/*這幾行注釋掉
app.listen("8083",function () {  
    console.log(12)
});
*/
const httpsOption = {
    key : fs.readFileSync("../../../https/XXX.key"),
    cert: fs.readFileSync("../../../https/XXX.crt")
}
var https =require("https");
https.createServer(httpsOption, app).listen(8083);
           

源碼

嘻嘻,以前按照慣例是給個免費連結的,為了賺賺積分,現在用csdn的下載下傳連結。

小程式index.js的完整代碼,我就注釋了我的伺服器,其它沒變。。

nodejs的js完整代碼,我放在了nodejs\node_modules\npm\node_modules下,是以前文裡的代碼裡有很多個傳回上級目錄

注:本人也是菜鳥,部落格也是拼拼湊湊查了很多資料,有錯誤和改進的地方還請指點。

繼續閱讀