動態生成二維碼和一維條形碼
最近那些事兒……
為了不耽誤大家的時間,這里首先說一下下邊文章中主要涉及的技術問題,如果有興趣,大家可以一起研究一下,如果不喜歡,請繞道。寫得不妥的地方,也希望大家指正。
本文主要說三個問題:
一、VS中跨工程調試,從一個工程進入另一個工程;
二、動態生成二維碼和一維條形碼;
三、前台頁面直接訪問圖片流文件。
老規矩,先來點題外話。最近在園子里閑逛的時候,發現很多人都聊到了加班這個話題。其中有一哥們兒說是在京東,然后每天按時上下班,無不良記錄,一個月后居然以工作不積極給開了……說到這里很多人就得有想法了,憑什么啊?說到程序員加班,似乎永遠是個談不完的話題,好像程序員就是為加班而生的。而這其中的辛酸血淚,也只有我們自己才知道。從去年進入公司以來,除了特殊情況(節假日,公司聚會),從來未按時下過班,大家都習慣磨磨蹭蹭,沒事兒也在那兒耗着。我也問過比我先來的同事,為什么下班了還不走,原因很簡單,上邊的人都沒走……
最近加班更是頻繁,周一到周四住在公司,每天回寢室都是下半夜。其中的苦楚,說不清,道不明。我想說的是,我們一起,按時下班吧。工作和生活需要分開!
——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
一、跨工程調試
之前工作時發現要將項目中一部分的功能加以改造移動到另外一個項目去,本着DRY的原則,決定將項目生成一下,然后直接把dll復制過去。當復制過去直接使用時,發現程序報了空指針異常。而檢查了一遍程也未發現有任何地方會導致空指針,唯一的辦法就是打斷點來調試一下,可是由於是引用的dll,所以沒辦法直接打斷點,只能通過其他的方式。好在我有dll的源碼,如何調試只是方法的問題了。這里說的跨工程調試,是指調試在不同的工程中的源代碼。在同一個工程不同項目的代碼是可以直接調試的。下面簡單的介紹一下如何跨工程進行調試。
首先,找到需要調試的CS文件,然后將文件直接拖到正在運行的工程窗口中,將斷點打在合適的位置上。再從原工程中找到此cs所在的項目的pdb文件,將pdb文件和dll一同復制到現工程的bin目錄下,然后直接F5,接着,奇跡就發生了。
二、生成二維碼和一維條形碼
隨着微信的興起,二維碼應用得越來越廣泛。之前我們有個賣水果的客戶說是要將二維碼貼在水果上,通過手機一掃就能知道水果的產地,生長環境等信息。網上也有很多生成二維碼的工具,但是希望大家慎用,有些會把您填寫的信息秘密發回服務器,當然了,大多數還是可以用的。
文中提到的生成二維碼和一維條形碼,是通過開源的項目Zxing來實現的,其Github地址:https://github.com/zxing/zxing/,這是一個開源的項目,可以生成各種碼。因為之前用了二維碼和條形碼,所以這里簡單的說一下。
生成二維碼和一維碼只有細微的差別,體現在程序里相當於使用了不同類型的枚舉。下面直接上代碼:
在這里做這個示例用的是最傳統的Web程序,直接添加了一個一般處理程序來處理這個生成二維碼和一維條形碼的邏輯。
首先通過context上下文獲取傳過來的一些參數:
獲取傳遞過來的參數
string content = context.Request.QueryString["content"];
if (string.IsNullOrWhiteSpace(content)) return;
content = HttpUtility.UrlDecode(content);
string level = context.Request.QueryString["level"];
level = string.IsNullOrWhiteSpace(level) ? "M" : level.ToUpper();
string format = context.Request.QueryString["format"];
format = string.IsNullOrWhiteSpace(format) ? "png" : format.ToLower();
int margin = Convert.ToInt32(context.Request.QueryString["margin"]);
int size = Convert.ToInt32(context.Request.QueryString["size"]);
獲取傳遞過來的參數
然后通過前台傳過來的參數生成相應的條碼類型,這里僅僅只是生成了一維碼和二維碼,別的類似:
ErrorCorrectionLevel errorCorrectionLevel;
ImageFormat imgFormat;
BarcodeFormat barcodeFormat = GetImageFormat(context.Request.QueryString["mod"]);
#region 獲取生成圖片類型
private static BarcodeFormat GetImageFormat(string mod)
{
switch (mod)
{
case "QR_CODE":
return BarcodeFormat.QR_CODE;
case "CODE_128":
return BarcodeFormat.CODE_128;
default:
return BarcodeFormat.CODE_128;
}
}
#endregion
設置生成條碼類型
ErrorCorrectionLevel errorCorrectionLevel; ImageFormat imgFormat; BarcodeFormat barcodeFormat = GetImageFormat(context.Request.QueryString["mod"]); #region 獲取生成圖片類型 private static BarcodeFormat GetImageFormat(string mod) { switch (mod) { case "QR_CODE": return BarcodeFormat.QR_CODE; case "CODE_128": return BarcodeFormat.CODE_128; default: return BarcodeFormat.CODE_128; } } #endregion
接着,再初始化一些參數:
#region ErrorCorrectionLevel
switch (level)
{
case "L":
errorCorrectionLevel = ErrorCorrectionLevel.L;
break;
case "M":
errorCorrectionLevel = ErrorCorrectionLevel.M;
break;
case "Q":
errorCorrectionLevel = ErrorCorrectionLevel.Q;
break;
case "H":
errorCorrectionLevel = ErrorCorrectionLevel.H;
break;
default:
errorCorrectionLevel = ErrorCorrectionLevel.M;
break;
}
#endregion
#region ImageFormat
switch (format)
{
case "jpeg":
imgFormat = ImageFormat.Jpeg;
break;
case "gif":
imgFormat = ImageFormat.Gif;
break;
case "bmp":
imgFormat = ImageFormat.Bmp;
break;
default:
imgFormat = ImageFormat.Png;
break;
}
#endregion
EncodingOptions options = new QrCodeEncodingOptions
{
DisableECI = true, //禁用ECI編碼段: use UTF-8 encoding and the ECI segment is omitted
CharacterSet = "UTF-8", //使用UTF-8編碼
Width = 200, //設置寬度
Height = 80, //設置高度
Margin = 20, //設置間隙
ErrorCorrection = errorCorrectionLevel,//容錯等級
PureBarcode = false//底部顯示內容
};
設置初始參數
#region ErrorCorrectionLevel switch (level) { case "L": errorCorrectionLevel = ErrorCorrectionLevel.L; break; case "M": errorCorrectionLevel = ErrorCorrectionLevel.M; break; case "Q": errorCorrectionLevel = ErrorCorrectionLevel.Q; break; case "H": errorCorrectionLevel = ErrorCorrectionLevel.H; break; default: errorCorrectionLevel = ErrorCorrectionLevel.M; break; } #endregion #region ImageFormat switch (format) { case "jpeg": imgFormat = ImageFormat.Jpeg; break; case "gif": imgFormat = ImageFormat.Gif; break; case "bmp": imgFormat = ImageFormat.Bmp; break; default: imgFormat = ImageFormat.Png; break; } #endregion EncodingOptions options = new QrCodeEncodingOptions { DisableECI = true, //禁用ECI編碼段: use UTF-8 encoding and the ECI segment is omitted CharacterSet = "UTF-8", //使用UTF-8編碼 Width = 200, //設置寬度 Height = 80, //設置高度 Margin = 20, //設置間隙 ErrorCorrection = errorCorrectionLevel,//容錯等級 PureBarcode = false//底部顯示內容 };
最后,直接生成二維碼或一維碼圖片:
BarcodeWriter writer = new BarcodeWriter();
writer.Format = barcodeFormat; //采用QR編碼
writer.Options = options;
context.Response.Clear();
context.Response.ContentType = imgFormat.GetMimeType(); //設置輸出流ContentType
using (Bitmap image = writer.Write(content)) //輸出二維碼圖像
{
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms, imgFormat);
ms.WriteTo(context.Response.OutputStream);
}
}
context.Response.Output.Flush();
context.Response.End();
生成條碼
BarcodeWriter writer = new BarcodeWriter(); writer.Format = barcodeFormat; //采用QR編碼 writer.Options = options; context.Response.Clear(); context.Response.ContentType = imgFormat.GetMimeType(); //設置輸出流ContentType using (Bitmap image = writer.Write(content)) //輸出二維碼圖像 { using (MemoryStream ms = new MemoryStream()) { image.Save(ms, imgFormat); ms.WriteTo(context.Response.OutputStream); } } context.Response.Output.Flush(); context.Response.End();
至此,生成一維碼或二維碼告一段落。
三、輸出圖片到前台
看完生成條碼的童鞋會發現,最后是將流輸出了,是的,這是為了直接將圖片輸出到前台。這樣,可以根據實時的動態請求,將需要生成的一維碼或者二維碼直接輸出到前台,而前台的頁面也非常簡單,只需寫一個<image>標簽,將src指向后台的一般處理程序即可。這樣就能將內容輸出到前台。如圖:當然了,您也可以根據自己的需要,在二維碼中間穿插上自己的一些Logo或者圖片信息,由於本文重在拋磚引玉,所以這里就不細說了。



