最近有個需求是要生成分享海報,讓使用者可以將圖片儲存到本地然後分享到朋友圈。本來以為是一個很簡單的需求,可是萬萬沒想到,微信會這麼坑。
剛開始的思路是這樣的:
後臺根據小程式傳過來的引數獲取對應的小程式碼,然後與背景圖合成之後將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) {
/***/
}
})
}
});