.NET生成小程式碼,併合自定義背景圖生成推廣小程式二維碼

追逐時光者發表於2021-05-11

前言:

  對於小程式大家可能都非常熟悉了,隨著小程式的不斷普及越來越多的公司都開始推廣使用起來了。今天接到一個需求就是生成小程式碼,並且於運營給的推廣圖片合併在一起做成一張漂亮美觀的推廣二維碼,掃碼這種二維碼就可以進入小程式。為了節省伺服器記憶體資源,我想的就是成功呼叫通微信生成小程式碼的介面後直接把微信返回過來的圖片二進位制內容(返回的圖片 Buffer)轉化為二進位制byte[]檔案流,然後再轉成Image這樣就不需要在儲存到本地直接讀取本地的背景圖片通過GDI+(Graphics)繪製圖片。廢話不多說直接上碼,各位同學假如有什麼小程式的開發問題都歡迎評論區,或者qq私聊我有時間都可以一起學習探索。

選擇小程式碼生成方式:

首先微信小程式官方文件提供了三種生成小程式碼的方法,如下所示(本文采用的是第三種,需要的碼數量極多的業務場景):

文件詳情地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/qr-code/wxacode.getUnlimited.html

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;
        }

合成效果圖:

 

相關文章