前言:
對於小程序大家可能都非常熟悉了,隨着小程序的不斷普及越來越多的公司都開始推廣使用起來了。今天接到一個需求就是生成小程序碼,並且與運營給的推廣圖片合並在一起做成一張漂亮美觀的推廣二維碼,掃碼這種二維碼就可以進入小程序。為了節省服務器內存資源,我想的就是成功調用通微信生成小程序碼的接口后直接把微信返回過來的圖片二進制內容(返回的圖片 Buffer)轉化為二進制byte[]文件流,然后再轉成Image這樣就不需要在保存到本地直接讀取本地的背景圖片通過GDI+(Graphics)繪制圖片。廢話不多說直接上碼,各位同學假如有什么小程序的開發問題都歡迎評論區,或者qq私聊我有時間都可以一起學習探索。
選擇小程序碼生成方式:
首先微信小程序官方文檔提供了三種生成小程序碼的方法,如下所示(本文采用的是第三種,需要的碼數量極多的業務場景):
1、createwxaqrcode獲取小程序二維碼,適用於需要的碼數量較少的業務場景。通過該接口生成的小程序碼,永久有效,有數量限制。
2、getwxacode獲取小程序碼,適用於需要的碼數量較少的業務場景。通過該接口生成的小程序碼,永久有效,有數量限制。
3、getwxacodeunlimit獲取小程序碼,適用於需要的碼數量極多的業務場景。通過該接口生成的小程序碼,永久有效,數量暫無限制。
獲取小程序全局唯一后台接口調用憑據(access_token):
對接開發過微信相關的業務的同學應該都清楚,調用微信接口很多情況下都會需要使用到access_token接口調用憑證。一般來說access_token的有效時長為2小時,為了不頻繁調用該接口我們可以通過緩存的方法把調用憑證存起來並設置合理的過期時間(redis,cookie,memorycache都是非常不錯的選擇)。
請求地址:
GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
請求參數:
屬性 | 類型 | 默認值 | 必填 | 說明 |
---|---|---|---|---|
grant_type |
string |
是 | 填寫 client_credential | |
appid |
string |
是 | 小程序唯一憑證,即 AppID,可在「微信公眾平台 - 設置 - 開發設置」頁中獲得。(需要已經成為開發者,且帳號沒有異常狀態) | |
secret |
string |
是 | 小程序唯一憑證密鑰,即 AppSecret,獲取方式同 appid |
返回值(JSON 數據包):
屬性 | 類型 | 說明 |
---|---|---|
access_token |
string |
獲取到的憑證 |
expires_in |
number |
憑證有效時間,單位:秒。目前是7200秒之內的值。 |
errcode |
number |
錯誤碼 |
errmsg |
string |
錯誤信息 |
請求代碼:
/// <summary> /// 獲取小程序全局唯一后台接口調用憑據(access_token) /// </summary> /// <returns></returns> public string GetWechatAccessToken() { var appId = "你的小程序AppID";//小程序唯一憑證,即 AppID var secret = "你的小程序AppSecret"; //小程序唯一憑證密鑰,即 AppSecret string Url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={0}&secret={1}", appId, secret); string Result = HttpWebRequest(Url, "GET", "", Encoding.UTF8); var obj = JsonConvert.DeserializeObject<AccessToken>(Result); if (obj != null && obj.access_token != null) { return obj.access_token; } else { return ""; } } /// <summary> /// WebRequest網絡請求 /// </summary> /// <param name="requestUrl">請求地址</param> /// <param name="method">請求方式(GET/POST)</param> /// <param name="data">請求參數(method="POST"需要攜帶)</param> /// <param name="encoding">字符編碼</param> /// <param name="contentType">請求數據的內容類型</param> /// <returns></returns> public string HttpWebRequest(string requestUrl, string method, string data, Encoding encoding,string contentType="application/json;charset=UTF-8") { WebRequest webRequest = WebRequest.Create(requestUrl); webRequest.Method = method; if (method == "POST") { byte[] bytes = Encoding.Default.GetBytes(data); webRequest.ContentType = contentType; webRequest.ContentLength = bytes.Length; Stream requestStream = webRequest.GetRequestStream(); requestStream.Write(bytes, 0, bytes.Length); requestStream.Close(); } WebResponse response = webRequest.GetResponse(); Stream responseStream = response.GetResponseStream(); if (responseStream == null) { return ""; } StreamReader streamReader = new StreamReader(responseStream, encoding); string result = streamReader.ReadToEnd(); responseStream.Close(); streamReader.Close(); return result; } /// <summary> /// 響應模型 /// </summary> public class AccessToken { /// <summary> /// 獲取到的憑證 /// </summary> public string access_token { get; set; } /// <summary> /// 憑證有效時間,單位:秒。目前是7200秒之內的值 /// </summary> public int expires_in { get; set; } /// <summary> /// 錯誤碼 /// </summary> public int errcode { get; set; } /// <summary> /// 錯誤信息 /// </summary> public string errmsg { get; set; } }
小程序碼獲取:
請求地址:
POST https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
請求參數
屬性 | 類型 | 默認值 | 必填 | 說明 |
---|---|---|---|---|
access_token |
string |
是 | 接口調用憑證 | |
scene |
string |
是 | 最大32個可見字符,只支持數字,大小寫英文以及部分特殊字符:!#$&'()*+,/:;=?@-._~ ,其它字符請自行編碼為合法字符(因不支持% ,中文無法使用 urlencode 處理,請使用其他編碼方式) |
|
page |
string |
主頁 | 否 | 必須是已經發布的小程序存在的頁面(否則報錯),例如 pages/index/index , 根路徑前不要填加 / ,不能攜帶參數(參數請放在scene字段里),如果不填寫這個字段,默認跳主頁面 |
width |
number |
430 | 否 | 二維碼的寬度,單位 px,最小 280px,最大 1280px |
auto_color |
boolean |
false | 否 | 自動配置線條顏色,如果顏色依然是黑色,則說明不建議配置主色調,默認 false |
line_color |
Object |
{"r":0,"g":0,"b":0} | 否 | auto_color 為 false 時生效,使用 rgb 設置顏色 例如 {"r":"xxx","g":"xxx","b":"xxx"} 十進制表示 |
is_hyaline |
boolean |
false | 否 | 是否需要透明底色,為 true 時,生成透明底色的小程序 |
請求成功返回值:
返回的圖片 Buffer(如果調用成功,會直接返回圖片二進制內容(圖片文件流),如果請求失敗,會返回 JSON 格式的數據。)
請求異常返回值:
屬性 | 類型 | 說明 |
---|---|---|
errcode |
number |
錯誤碼 |
errmsg |
string |
錯誤信息 |
請求代碼:
注意:這個與前面獲取授權憑證的網絡請求不同的是因為要接收請求返回過來的圖片二進制內容(buffer),然后需要把二進制文件流轉化為byte[]二進制字節流,然后在轉化Image。
/// <summary> /// 獲取小程序碼圖片 /// </summary> /// <param name="access_token">接口調用憑據</param> /// <param name="param">攜帶參數</param> private Image GetWetchatAppletQRCodeImage(string access_token, string param) { string requestData = "{\"scene\":\"" + param + "\"}"; string requestUrl = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + access_token; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl); request.Method = "POST"; request.ContentType = "application/json;charset=UTF-8"; byte[] payload = System.Text.Encoding.UTF8.GetBytes(requestData); request.ContentLength = payload.Length; Stream writer = request.GetRequestStream(); writer.Write(payload, 0, payload.Length); writer.Close(); HttpWebResponse response; response = (HttpWebResponse)request.GetResponse(); Stream stream = response.GetResponseStream();//獲取返回的圖片 Buffer(文件流) byte[] imageBuffer = StreamToBytes(stream); return ByteArrayConvertToImage(imageBuffer); } /// <summary> /// 將文件數據流轉為二進制byte[]字節流 /// </summary> /// <param name="stream">文件流</param> /// <returns></returns> private byte[] StreamToBytes(Stream stream) { List<byte> bytes = new List<byte>(); int temp = stream.ReadByte(); while (temp != -1) { bytes.Add((byte)temp); temp = stream.ReadByte(); } return bytes.ToArray(); } /// <summary> /// byte [] 轉化為Iamge /// </summary> /// <param name="buffer"></param> /// <returns></returns> public static Image ByteArrayConvertToImage(byte[] buffer) { using (MemoryStream ms = new MemoryStream(buffer)) { // 直接調用Image庫類中自帶的方法使用MemoryStream實例對象獲取Image return Image.FromStream(ms); } }
小程序碼和背景圖合並:
/// <summary> /// 小程序推廣二維碼獲取 /// </summary> /// <param name="userId">小程序碼攜帶的用戶參數</param> /// <returns></returns> public JsonResult GetCompositePictureUrl(int userId) { //圖片存放物理路徑 var savePhysicalPath = HttpContext.Request.MapPath("~/qrcode/"); var imgBack = Image.FromFile(savePhysicalPath + "ewm.jpg");//合成背景圖片 var wechatQrcodeImg = GetWetchatAppletQRCodeImage(GetWechatAccessToken(),userId.ToString());//獲取小程序碼圖片 var compositePictureUrl = CompositePicture(imgBack, wechatQrcodeImg, savePhysicalPath, 232, 719, 290, 290); return Json(new { code = 0, compositePictureUrl = compositePictureUrl }); } /// <summary> /// 合成圖片 /// </summary> /// <param name="backgroundImage">背景圖</param> /// <param name="qrCodeImg">二維碼圖片</param> /// <param name="savePhysicalPath">圖片存放物理路徑</param> /// <param name="xDeviation">繪制圖像X軸偏差</param> /// <param name="yDeviation">繪制圖像Y軸偏差</param> /// <param name="width">繪制圖像寬</param> /// <param name="height">繪制圖像高</param> /// <returns></returns> public string CompositePicture(Image backgroundImage, Image qrCodeImg, string savePhysicalPath, int xDeviation = 0, int yDeviation = 0, int width = 0, int height = 0) { Bitmap bitmap = new Bitmap(backgroundImage.Width, backgroundImage.Height); Graphics graphics = Graphics.FromImage(bitmap);//繪圖 graphics.Clear(Color.White); SolidBrush surush = new SolidBrush(Color.White); graphics.DrawImage(backgroundImage, 0, 0, backgroundImage.Width, backgroundImage.Height); graphics.DrawImage(qrCodeImg, xDeviation, yDeviation, width, height); GC.Collect();//垃圾清理 string compositePictureUrl = savePhysicalPath + Guid.NewGuid().ToString() + ".jpg"; //合成圖片保存 bitmap.Save(compositePictureUrl, System.Drawing.Imaging.ImageFormat.Jpeg); return compositePictureUrl; }
合成效果圖: