這個星期, 領導要我總結項目中用到的一些技術, 然後交付文檔. 嘿嘿, 奉命整理.
二維碼, 相信很多項目中都會要求生成這個, 然後由手機端去掃描, 或存儲一些詳情信息, 或存儲一條鏈接, 可以快捷訪問.
一、示例
public ActionResult QrCode() { var s = CreateQr("策士", "123456789", "男", DateTime.Now.AddYears(-20), "15112341234"); return File(s, "image/jpeg,image/png"); } /// <summary> /// 生成二維碼 /// </summary> /// <returns>二維碼相對路徑</returns> public string CreateQr(string name, string code, string sex, DateTime birthday, string phone) { var codeParams = CodeDescriptor.Init(HttpContext.Request); var fileName = code + ".png"; var path = Server.MapPath("~/QRCode/"); var fullFileName = path + fileName; string content = string.Format("姓名:{0}\n編號:{1}\n性別:{2}\n年齡:{3}\n聯系電話:{4}\n", name, code, sex, (birthday.Year > 1000 ? (DateTime.Now.Year - birthday.Year).ToString() : ""), phone); codeParams.Content = content; // Encode the content codeParams.TryEncode(); using (var ms = new MemoryStream()) { codeParams.Render(ms); #region 保存圖片 var img = Image.FromStream(ms); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } img.Save(fullFileName); #endregion } return fullFileName; }
對這個二維碼掃一掃, 就可以看到相關信息了.
二、參數解析
/// <summary> /// Parse QueryString that define the QR code properties /// </summary> /// <param name="request">HttpRequest containing HTTP GET data</param> /// <returns>A QR code descriptor object</returns> public static CodeDescriptor Init(HttpRequestBase request) { var cp = new CodeDescriptor(); // Error correction level if (!Enum.TryParse(request.QueryString["e"], out cp.Ecl)) cp.Ecl = ErrorCorrectionLevel.L; // Code content to encode cp.Content = request.QueryString["t"]; // Size of the quiet zone if (!Enum.TryParse(request.QueryString["q"], out cp.QuietZones)) cp.QuietZones = QuietZoneModules.Two; // Module size if (!int.TryParse(request.QueryString["s"], out cp.ModuleSize)) cp.ModuleSize = 6; return cp; }
1. 容錯率
二維碼的容錯率有四個級別, 不過我得先介紹一下什麼叫二維碼容錯率.
二維碼容錯率就是, 在二維碼編碼的時候, 進行冗余操作, 這種做法的目的, 就是希望二維碼在有部分被遮擋的情況下, 還能掃描出正確結果. 就像abc編碼成abcabc.
public enum ErrorCorrectionLevel { L = 0, //low 7%的字碼可以被修正 M = 1, //medium 15% Q = 2, //quartile 25% H = 3, //high 30% }
測試方法, 其實就是拿著掃一掃, 對二維碼掃描, 掃描的時候, 慢慢的將二維碼放入掃描匡, 會發現, 其實並不需要完全放入掃描匡, 就已經能出結果了.
容錯率越高, 越容易快速掃描, 代價就是, 二維碼編碼的內容增多, 增加了二維碼的復雜度.
默認情況下, 會選擇L.
2. 空白
public enum QuietZoneModules { Zero = 0, Two = 2, Four = 4, }
這個屬性, 表示二維碼邊上的空白區域的厚度, Zero表示沒有空白邊框, 最後的邊框厚度, 是Two * 2 得到的.
3. 尺寸
這裡的 ModuleSize 就是二維碼圖片的尺寸, 尺寸越大, 能容納信息越多.
4. 內容編碼
二維碼內容默認編碼為utf-8,
這裡還有一些別的屬性, 比如背景顏色, 繪制顏色之類的, 就不一一細說了
二維碼的內容長度限制, 在文檔中, 並沒有找到, Api文檔中說, 少到1個字符, 多到900個字符, 二維碼都是能正常顯示的. 當然, 二維碼存儲信息不易過多. The shorter the better.
如果內容過多, 可以通過二維碼提供鏈接的方式, 讓用戶去請求接口, 而不是通過掃描二維碼直接得到內容.
具體方法, 就是
codeParams.Content = "http://www.baidu.com";
這裡的http://是必須要的, 否則會將內容當做普通字符去解析
最後, 貼上完整的封裝:
/// <summary> /// Class containing the description of the QR code and wrapping encoding and rendering. /// </summary> public class CodeDescriptor { public ErrorCorrectionLevel Ecl; public string Content; public QuietZoneModules QuietZones; public int ModuleSize; public BitMatrix Matrix; public string ContentType; /// <summary> /// Parse QueryString that define the QR code properties /// </summary> /// <param name="request">HttpRequest containing HTTP GET data</param> /// <returns>A QR code descriptor object</returns> public static CodeDescriptor Init(HttpRequestBase request) { var cp = new CodeDescriptor(); // Error correction level if (!Enum.TryParse(request.QueryString["e"], out cp.Ecl)) cp.Ecl = ErrorCorrectionLevel.L; // Code content to encode cp.Content = request.QueryString["t"]; // Size of the quiet zone if (!Enum.TryParse(request.QueryString["q"], out cp.QuietZones)) cp.QuietZones = QuietZoneModules.Two; // Module size if (!int.TryParse(request.QueryString["s"], out cp.ModuleSize)) cp.ModuleSize = 6; return cp; } /// <summary> /// Parse QueryString that define the QR code properties /// </summary> /// <param name="request">HttpRequest containing HTTP GET data</param> /// <returns>A QR code descriptor object</returns> public static CodeDescriptor Init(HttpRequest request) { var cp = new CodeDescriptor(); // Error correction level if (!Enum.TryParse(request.QueryString["e"], out cp.Ecl)) cp.Ecl = ErrorCorrectionLevel.L; // Code content to encode cp.Content = request.QueryString["t"]; // Size of the quiet zone if (!Enum.TryParse(request.QueryString["q"], out cp.QuietZones)) cp.QuietZones = QuietZoneModules.Two; // Module size if (!int.TryParse(request.QueryString["s"], out cp.ModuleSize)) cp.ModuleSize = 6; return cp; } /// <summary> /// Encode the content with desired parameters and save the generated Matrix /// </summary> /// <returns>True if the encoding succeeded, false if the content is empty or too large to fit in a QR code</returns> public bool TryEncode() { var encoder = new QrEncoder(Ecl); QrCode qr; if (!encoder.TryEncode(Content, out qr)) return false; Matrix = qr.Matrix; return true; } /// <summary> /// Render the Matrix as a PNG image /// </summary> /// <param name="ms">MemoryStream to store the image bytes into</param> public void Render(MemoryStream ms) { var render = new GraphicsRenderer(new FixedModuleSize(ModuleSize, QuietZones)); render.WriteToStream(Matrix, ImageFormat.Png, ms); ContentType = "image/png"; } }二維碼
參考:
二維碼詳解
qrcodenet代碼中一些基礎的認識 幫助
api