微信小程式 海報生成踩坑記

使用者名稱已註冊發表於2018-09-23

最近有個需求是要生成分享海報,讓使用者可以將圖片儲存到本地然後分享到朋友圈。本來以為是一個很簡單的需求,可是萬萬沒想到,微信會這麼坑。
剛開始的思路是這樣的:

後臺根據小程式傳過來的引數獲取對應的小程式碼,然後與背景圖合成之後將base64格式的圖片傳給小程式,這樣就可以不用儲存圖片了。但是經過嘗試之後有兩個坑

  • 坑1:小程式對base64圖片支援不友好,模擬器上圖片可以顯示,真機無法顯示
  • 坑2:小程式canvas繪圖必須使用網路圖片或者本地圖片,但是如果直接在wx.drawImage傳入圖片連結,真機上面會顯示失敗

Google一番之後,算是把這倆坑填上了。在此記錄一下,有錯誤的地方還請大神輕噴。

首先是解決base64圖片的問題,既然小程式支援的不好,那我們就儲存在伺服器好了,下面是Laravel合成圖片的簡單程式碼:

public function getPoster(Request $request)
{
    $token = $request->input(`token`);
    $uid = MembersToken::getUidByToken($token);
    if (file_exists(public_path() . `/poster/` . $uid . `.png`)) {
        return response()->json([
            `status` => `success`,
            `data` => `/poster/` . $uid . `.png`
        ]);
    }

    $access_token = Cache::get(`access_token`);
    if (!$access_token) {
        $appid = config(`wechat.appid`);
        $secret = config(`wechat.secret`);
        $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$appid}&secret={$secret}";
        $data = curl_request($url);
        $data = json_decode($data,true);

        if (isset($data[`errcode`]) || empty($data)) {
            throw new ApiException(200,$data[`errmsg`],null,[],600001);
        }
        $access_token = $data[`access_token`];
        $expires_in = $data[`expires_in`];
        Cache::put(`access_token`,$access_token,120);
    }

    //獲取小程式碼
    $code_url = `https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=` . $access_token;
    $post = [
        "page" => "pages/maps/maps",
        "scene" => $uid,
    ];
    $data = curl_request($code_url, $post);
    $data = base64_encode($data);
    $data = Image::make($data)->resize(200, 200);

    //將二維碼插入背景圖
    $img = Image::make(public_path().`/img/book.png`);
    $img->insert($data, `bottom-right`, 0, 0);
    $res = $img->save(public_path() . `/poster/` . $uid . `.png`);
    return response()->json([
        `status` => `success`,
        `data` => `/poster/` . $uid . `.png`
    ]);

}

小程式獲取到圖片路徑之後,可以使用canvas繪圖的方式顯示圖片也可以直接使用image標籤的形式。為了防止以後可能對圖片進行別的處理,我使用了canvas的方式。

此時如果直接使用後臺傳過來的圖片路徑的話,就會遇到第二個坑:在真機上面圖片是顯示不出來的。因此我們需要先使用wx.downloadFile將圖片下載下來。嗯,程式碼差不多就是下面這樣:

/***********************************************/
/**呼叫介面獲取圖片路徑。。。程式碼太爛省略了。。。**/
/**********************************************/
wx.downloadFile({
  url: app.globalData.domain + res.data.data,
  success: function (res) {
    var path = res.tempFilePath
    var width = _this.data.windowW;
    var height = _this.data.windowH - 50;
    const ctx = wx.createCanvasContext(`poster`);
    ctx.drawImage(path, 0, 0, width, height);
    ctx.draw(true);
    wx.hideLoading();
  }, 
  fail: function (res) {
    /***/
  }
})

此時,圖片應該可以正常的在真機上面顯示了。接下來就是下載圖片到本地了,解決了上面兩個坑之後這塊就沒什麼大問題了,簡單貼一下程式碼:

saveImg: function () {
var _this = this;
var windowW = _this.data.windowW;
var windowH = _this.data.windowH - 50;
wx.canvasToTempFilePath({
  x: 0,
  y: 0,
  width: windowW,
  height: windowH,
  destWidth: windowW,
  destHeight: windowH,
  canvasId: `poster`,
  success: function (res) {
    wx.saveImageToPhotosAlbum({
      filePath: res.tempFilePath,
      success(res) {
        /***/
      },
      fail(res) {
        /***/
      },
      complete(res) {
        /***/
      }
    })
  }
});

相關文章