支付寶小程序開發練習,顯示自定義二維碼(四)

之前用了幾種方式

1.後端生成二維碼需要加密的字符竄,小程序前端利用二維碼組件渲染canvas畫出二維碼,由於支付寶小程序沒有這樣的組件,於是去找微信小程序的解決方案,把微信小程序的二維碼前端組件搬過來用,調試到不報錯了,結果二維碼顯示不出來,原因很難找,宣告失敗!

2.後端生成圖片,並把圖片的地址URL發到小程序前端,前端調用my.downloadFile 成功,但後端卻要生成大量圖片,並且二維碼都是臨時拿來用的,用完就扔,缺點太明顯,後端要產生大量垃圾文件和IO操作,使用碼的客戶端多了,對服務器端有很大壓力

3.後端生成圖片的Base64字符串,小程序前端直接顯示二維碼

我最後使用的是第三種方式

要生成二維碼,首先是使用.net core 版本的QRCode,然後我們的需求是二維碼中間加入一個logo,下面是一個工具類,可實現這個需求

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using QRCoder;

namespace SchoolWebApi.Utility
{
    public class RaffQRCode : IQRCode
    {
        public byte[] StreamToBytes(Stream stream)
        {
            byte[] bytes = new byte[stream.Length];
            stream.Position = 0;
            stream.Read(bytes, 0, bytes.Length);
            stream.Close();
            return bytes;
        }

        /// <summary>
        /// 生成二維碼圖片
        /// </summary>
        /// <param name="logoPath"></param>
        /// <param name="content"></param>
        /// <param name="pixel">像素大小</param>
        /// <returns></returns>
        public byte[] GetQRCode(string logoPath, string content, int pixel)
        {
            var generator = new QRCodeGenerator();
            var codeData = generator.CreateQrCode(content, QRCodeGenerator.ECCLevel.M, true);
            var qrcode = new QRCode(codeData);
            var qrImage = qrcode.GetGraphic(pixel, Color.Black, Color.White, true);

            using (MemoryStream ms = new MemoryStream())
            {
                qrImage.Save(ms, ImageFormat.Png);
                using (MemoryStream ms1 = new MemoryStream())
                {
                    //把logo圖片放到二維碼圖片正中心
                    var newImage = CombinImage(qrImage, logoPath);
                    newImage.Save(ms1, ImageFormat.Png);
                    return StreamToBytes(ms1);
                }            
            }          
        }

        /// <summary>   
        /// 調用此函數後使此兩種圖片合併,類似相冊,有個   
        /// 背景圖,中間貼自己的目標圖片   
        /// </summary>   
        /// <param name="imgBack">粘貼的源圖片</param>   
        /// <param name="destImg">粘貼的目標圖片</param>   
        public static Image CombinImage(Image imgBack, string destImg)
        {
            Image img = Image.FromFile(destImg);        //照片圖片     
            if (img.Height != 65 || img.Width != 65)
            {
                img = KiResizeImage(img, 65, 65, 0);
            }
            Graphics g = Graphics.FromImage(imgBack);

            g.DrawImage(imgBack, 0, 0, imgBack.Width, imgBack.Height);      //g.DrawImage(imgBack, 0, 0, 相框寬, 相框高);    

            //g.FillRectangle(System.Drawing.Brushes.White, imgBack.Width / 2 - img.Width / 2 - 1, imgBack.Width / 2 - img.Width / 2 - 1,1,1);//相片四周刷一層黑色邊框   
            //g.DrawImage(img, 照片與相框的左邊距, 照片與相框的上邊距, 照片寬, 照片高);   

            g.DrawImage(img, imgBack.Width / 2 - img.Width / 2, imgBack.Width / 2 - img.Width / 2, img.Width, img.Height);
            GC.Collect();
            return imgBack;
        }

        /// <summary>   
        /// Resize圖片   
        /// </summary>   
        /// <param name="bmp">原始Bitmap</param>   
        /// <param name="newW">新的寬度</param>   
        /// <param name="newH">新的高度</param>   
        /// <param name="Mode">保留着,暫時未用</param>   
        /// <returns>處理以後的圖片</returns>   
        public static Image KiResizeImage(Image bmp, int newW, int newH, int Mode)
        {
            try
            {
                Image b = new Bitmap(newW, newH);
                Graphics g = Graphics.FromImage(b);
                // 插值算法的質量   
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.DrawImage(bmp, new Rectangle(0, 0, newW, newH), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
                g.Dispose();
                return b;
            }
            catch
            {
                return null;
            }
        }
    }
}

 上面自定義了一個接口 IQRCode

    public interface IQRCode
    {
        byte[] GetQRCode(string logoPath,string url, int pixel);
    }

方便在StartUp中註冊

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IQRCode, RaffQRCode>();
            ......

 然後可以在Controller的構造函數中注入了

        private IQRCode _iQRCode;
        public GenerateQRCodeController(
          IQRCode iQRCode)
        {
            _iQRCode = iQRCode;
        }

 接着寫出返回圖片Base64字符串的方法,並在支付寶客戶端調用

        /// <summary>
        /// 返回二維碼圖片的base64字符竄
        /// </summary>
        /// <param name="ali_user_id"></param>
        /// <returns></returns>
        [HttpGet]
        [Route("GetGRCodeGenrateImage")]
        public ActionResult GetGRCodeGenrateImage(string ali_user_id)
        {
            try
            {
                //根據支付寶賬號查詢用戶表
                var findUser = _tb_school_user.FindByClause(t => t.ali_user_id == ali_user_id);
                if (findUser != null)
                {
                    var qrCodeFullStr = GetQrCodeString(ali_user_id, findUser);
                    var logoPath = host.WebRootPath + @"\images\logo.jpg";
                    var byteData = _iQRCode.GetQRCode(logoPath, qrCodeFullStr, 4);

                    //創建一個文件流
                    //using (FileStream fs = new FileStream(@"c:\666666666666.png", FileMode.Create))
                    //{
                    //    //將byte數組寫入文件中
                    //    fs.Write(byteData, 0, byteData.Length);
                    //}

                    //處理返回提前臺image圖片
                    //FileContentResult img = new FileContentResult(byteData, "images/png");
                    //return img;

                    return Content(Convert.ToBase64String(byteData));
                }
                return Content(string.Empty);
            }
            catch (Exception ex)
            {
                log.Error("錯誤:" + ex);
                return Content("圖片生成出錯");
            }
        }

 支付寶小程序前端的代碼

const app = getApp();

Page({
  data: {
    src: '',
    username: '',
    studentid: '',
    QRCodeSrc: '',
    setInter:'',
  },
  GetQRCode : function(){
      var that = this;
      my.httpRequest({
         url: app.globalData.apiurl + '/api/GenerateQRCode/GetGRCodeGenrateImage',
         method: 'GET',
         dataType : 'text',
         data: {
            ali_user_id: app.globalData.aliuserid 
         },
         header: {
            'content-type': 'application/octet-stream',
         },
         success: function(res) {
            var data = res.data                
            if (res.status == 200) {
                that.setData ({
                    QRCodeSrc: 'data:image/png;base64,' + data,  //data 爲接口返回的base64字符串
                })
            }
         },
         fail: function(res) {
            console.log(JSON.stringify(res));
            my.showToast({
              type: 'fail',
              content: '獲取二維碼失敗',
              duration: 1000
            });
         },
         complete: function(res) {
            my.hideLoading();
         }
      })
  },
  //定時刷新二維碼
  refreshQRCode : function(){
     var that = this;
     //每分鐘刷新
     that.data.setInter = setInterval(function(){
       that.GetQRCode();
     },60000);
  },
  imageError: function (e) {
    console.log('image 發生錯誤', e.detail.errMsg)
  },
  imageLoad: function (e) {
    console.log('image 加載成功', e);
  },
  clearTimeInterval: function (that) {
    var interval = that.data.interval;
    clearInterval(interval)
  },
  onLoad(query) {
    var that = this
    // 頁面加載
    app.getUserInfo().then(
      user => {
            console.info(user);
            //設置頭像
            if (user.avatar.length > 0) {
               this.setData({src: user.avatar});
            }
            else {
               this.setData({src: '/images/tou.png'});
            } 
            //設置用戶名    
            if (app.globalData.username) {
               this.setData({username: app.globalData.username});
            }
            else {
               this.setData({username: user.nickName});
            }
            //設置StudentId
            if(app.globalData.studentid) {               
               this.setData({studentid: app.globalData.studentid}); 
            }

            //頁面加載獲取二維碼
            this.GetQRCode();
            //開啓定時刷新獲取二維碼
            this.refreshQRCode();
        }
    );
  },
  onShow() {
    // 頁面顯示   
    my.onUserCaptureScreen(function() {
       my.alert({content: '收到用戶截屏事件'});
    });
  },
  onReady() {    
  },
  onUnload: function () {
      var that = this;
      //清除計時器  即清除setInter
      clearInterval(that.data.setInter)
  },
});

 重點看GetQRCode 這個方法就可以了,如何在前端接收Base64格式並顯示圖片

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章