需求场景:客户根据前台界面列表所选择的数据,根据需要的信息批量生成二维码并形成一张图片,并且每张图片显示的二维码数量是固定的,需要分页(即总共生成的二维码图片超出每页显示的需另起一页生成),并下载到客户端。
实现思路与技术:
主要用到技术:Qrcode.net(生成二维码的库)
SharpZipLib(压缩库)
.NET GDI绘图
总体思路:根据相关的信息用Qrcode.net 与GDI绘图先绘制成单张二维码图片(如图1),然后再把多个单张生成的二维码按照每页需显示的个数再绘制到一张图上,可生成多张(如:图二),然后服务器再把类似多张(图二)的图片打包到一起,形成一个压缩文件(图三),下载到客户端。
(图1) (图二) (图三)
服务器端主要代码:
//生成二维码
public JsonResult MakeQrcodeImage([Json]List<EquipmentLedger_SheBei> list) { string virtual_Path="~/upload/EquipmentImage_Temp/"+Guid.NewGuid().ToString(); string folderName = Server.MapPath(virtual_Path); Directory.CreateDirectory(folderName); foreach (var li in list) { DrawQrCode(li, folderName); } int pageIndex = 1; int pageSize = 45; decimal totalCount =Convert.ToDecimal(list.Count); decimal pages =Math.Ceiling(totalCount / pageSize); List<string> fildes = new List<string>(); for (int i = 1; i <= pages; i++) { var list_new = (from s in list orderby s.Id descending select s).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList<EquipmentLedger_SheBei>(); CombineImage(list_new, pageIndex, folderName); pageIndex++; } for (int j = 1; j <= pages; j++){ fildes.Add(folderName + "/QrCodes-Page" + j + ".bmp"); } string saveFile = folderName + "/QrCodesTest.zip"; Zip(fildes.ToArray(),saveFile); return Json(new MyJsonResult() { success = true, data = virtual_Path + "/QrCodesTest" }, null, null); } public FilePathResult DownLoadImage(string fieldName) { return File(Server.MapPath(fieldName) + ".zip", "application/octet-stream", "EquipmentLedgerQrCodes.zip"); }
//删除临时文件夹 public JsonResult DleteTempMakeQrcodeImage(string fieldName) { Directory.Delete(Server.MapPath(fieldName.Replace("/QrCodesTest","")),true); return Json(new MyJsonResult() { success = true }, null, null); } //绘制二维码 private void DrawQrCode(EquipmentLedger_SheBei eq,string folderName){ byte[] bytes = Encoding.Default.GetBytes(eq.Id.ToString()); string content = Convert.ToBase64String(bytes); ; int moduleSize = 30; var encoder = new QrEncoder(ErrorCorrectionLevel.M); QrCode qrCode = encoder.Encode(content); GraphicsRenderer render = new GraphicsRenderer(new FixedModuleSize(moduleSize, QuietZoneModules.Four), Brushes.Black, Brushes.White); DrawingSize dSize = render.SizeCalculator.GetSize(qrCode.Matrix.Width); RectangleF Rec_Top = new Rectangle(new Point(0, 0), new Size(dSize.CodeWidth, 120));//顶部文字框 RectangleF Rec_botom_Num = new Rectangle(new Point(0, dSize.CodeWidth - 120), new Size(dSize.CodeWidth, 120));//底部文字框 //创建画布 using (Bitmap map = new Bitmap(dSize.CodeWidth, dSize.CodeWidth)) { Graphics g = Graphics.FromImage(map); g.Clear(Color.White); Font drawFont = new Font("宋体", 60, FontStyle.Bold); SolidBrush drawBrush = new SolidBrush(Color.Red); render.Draw(g, qrCode.Matrix, new Point(0, 0)); StringFormat sf = new StringFormat(); sf.Alignment = StringAlignment.Center; sf.LineAlignment = StringAlignment.Center; g.DrawString(eq.Name, drawFont, drawBrush, Rec_Top, sf); g.DrawString(eq.Number, drawFont, drawBrush, Rec_botom_Num, sf); map.Save(folderName + "/" + eq.Id + ".bmp", ImageFormat.Bmp);//fileName为存放的图片路径 g.Dispose(); map.Dispose();//释放bmp文件资源 } }
private void Zip(string[] files, string ZipedFileName) { Zip(files, ZipedFileName, string.Empty); } private void Zip(string[] files, string ZipedFileName, string Password) { files = files.Where(f => System.IO.File.Exists(f)).ToArray(); if (files.Length != 0) { ZipOutputStream s = new ZipOutputStream(System.IO.File.Create(ZipedFileName)); s.SetLevel(6); if (!string.IsNullOrEmpty(Password.Trim())) s.Password = Password.Trim(); ZipFileDictory(files, s); s.Finish(); s.Close(); } } /// <summary> /// 压缩多个文件 /// </summary> /// <param name="files">文件名</param> /// <param name="ZipedFileName">压缩包文件名</param> /// <returns></returns> private void ZipFileDictory(string[] files, ZipOutputStream s) { ZipEntry entry = null; FileStream fs = null; Crc32 crc = new Crc32(); try { //创建当前文件夹 entry = new ZipEntry("/"); s.PutNextEntry(entry); s.Flush(); foreach (string file in files) { //打开压缩文件 fs = System.IO.File.OpenRead(file); byte[] buffer = new byte[fs.Length]; fs.Read(buffer, 0, buffer.Length); entry = new ZipEntry("/" + Path.GetFileName(file)); entry.DateTime = DateTime.Now; entry.Size = fs.Length; fs.Close(); crc.Reset(); crc.Update(buffer); entry.Crc = crc.Value; s.PutNextEntry(entry); s.Write(buffer, 0, buffer.Length); } } finally { if (fs != null) { fs.Close(); fs = null; } if (entry != null) entry = null; GC.Collect(); } } //生成每页多张二维码的图片 private void CombineImage(List<EquipmentLedger_SheBei> list,int pageNum,string folderName) { int rows = 5; int cols = 9; int height = 330; int width = 330; int currentIndex = 1; using (Bitmap bt1 = new Bitmap(2970, 2100)) { List<Rectangle> recs = new List<Rectangle>(); Graphics g = Graphics.FromImage(bt1); g.Clear(Color.White); for (int col = 0; col < cols; col++) { for (int row = 0; row < rows; row++) { if (list.Count >= currentIndex) { using (Bitmap bm = new Bitmap(folderName + "/" + list[currentIndex - 1].Id + ".bmp")) { Rectangle rg = new Rectangle(col * height, row * width + row * 100+20, width, height); g.DrawImage(bm, rg); currentIndex++; } } } } //要绘制到的位图 bt1.Save(folderName + "/QrCodes-Page" + pageNum + ".bmp", ImageFormat.Bmp);//fileName为存放的图片路径 g.Dispose(); bt1.Dispose();//释放bmp文件资源 } }
前端Extjs代码:
makeQrcodeImage: function () { var me = this; var record = me.getList().getSelectionModel().getSelection()[0]; if (record == null) { Ext.Msg.alert("系统提示", "请选择要生成二维码图片的设备"); return; } else { var maiView = Ext.ComponentQuery.query('MainView')[0]; me.PicMask = new Ext.LoadMask(maiView, { msg: "图片生成中,请稍后..." }); me.PicMask.show(); var records = me.getList().getSelectionModel().getSelection(); var list = []; for (var i = 0; i < records.length; i++) { list.push(records[i].data); } Ext.Ajax.request({ url: "../../EquipmentLedgerSheBei/MakeQrcodeImage", async: true, scope: this, params: { list: Ext.util.base64.encode(Ext.JSON.encode(list)), }, success: function (Response) { var flag = Ext.JSON.decode(Response.responseText).success; if (flag) { //下载文件 window.open("../../EquipmentLedgerSheBei/DownLoadImage?fieldName=" + Ext.JSON.decode(Response.responseText).data, "_blank"); me.PicMask.hide(); Ext.Ajax.request({ url: "../../EquipmentLedgerSheBei/DleteTempMakeQrcodeImage", async: true, scope: this, params: { fieldName: Ext.JSON.decode(Response.responseText).data, } }); } } }) } }