仓储物流的过程中往往少不了一些使用热敏打印机或者碳带打印机打印一些条码、信息贴在实物或者包裹上
最好的实现方式不过于直接使用热敏代码形成文本直接输出到打印机做打印
但是热敏代码也是一门需要特殊的语言,需要学习
故为了更快更方便的实现,就用到了画布绘制后形成image输出到打印机
而image也是有要求的,比如输出的格式、大小直接影响打印的质量
这里介绍下使用微软的报表布局绑定数据转image输出到打印机的方式
1、nuget上搜索Microsoft.ReportViewer.Common、Microsoft.ReportViewer.WebForms安装
2、创建rdlc报表,绘制指定打印输出的模板大小,对rdlc添加数据集,可以为对象,这里使用对象绑定(后台查询数据映射给对象)
可以为界面每个项的属性进行设置:字体、大小、数据绑定、对齐等,也可以动态使用表达式(数据源传入指定值)
3、打印入口,为报表绑定数据
DeviceInfo的详细说明见:
LocalReport.Render使用见
https://docs.microsoft.com/zh-cn/previous-versions/dd468075(v=vs.140)
注意:OutputFormat为EMF
PageWidth、PageHeight为rdlc的大小
如果需要使用到条码信息,则需要声明byte[] 接收使用BarcodeLib.Barcode相关条码类生成条码图片
rdlc模板上添加图像控件字段指向byte[]字段,mime选择image/png,大小显示为:调整为合适大小
测试时可以保存为图片,预览效果图
public string PrintOutPackage(string Consignee, string ContractCode,string ConsigneeAddress, int count, int cur, string printName, int type=1) { if (string.IsNullOrWhiteSpace(printName)) { return "没有选择打印机"; } using (LocalReport report = new LocalReport()) { report.ReportPath = System.Windows.Forms.Application.StartupPath + "/Content/OutPackage.rdlc"; report.DataSources.Clear(); var printModel = new OutPackagePrintModel() { Consignee = Consignee, ContractCode = ContractCode, ConsigneeAddress = ConsigneeAddress, PackageCount = count, CurPackageCount = cur, ConsigneeFontSize = Consignee.Length <= 3 ? "28pt" : Consignee.Length <= 12 ? "16pt" : "12px" }; var list = new List<OutPackagePrintModel>(); list.Add(printModel); ReportDataSource ds = new ReportDataSource("OutPackage", list);//绑定数据源 report.DataSources.Add(ds); report.Refresh(); string deviceInfo = "<DeviceInfo>" + " <OutputFormat>EMF</OutputFormat>" + " <PageWidth>8cm</PageWidth>" + " <PageHeight>5cm</PageHeight>" + "<PrintDpiX>300</PrintDpiX>" + "<PrintDpiY>300</PrintDpiY>" + " <MarginTop>0pt</MarginTop>" + " <MarginLeft>0pt</MarginLeft>" + " <MarginRight>0pt</MarginRight>" + " <MarginBottom>0pt</MarginBottom>" + "</DeviceInfo>"; Warning[] warnings; m_streams = new List<Stream>(); //将报表的内容按照deviceInfo指定的格式输出到CreateStream函数提供的Stream中。 report.Render("Image", deviceInfo, CreateStream, out warnings); } foreach (Stream stream in m_streams) { stream.Position = 0; } Image pageImage = Image.FromStream(m_streams[0]); if (type == 2) { //测试时保存图片 pageImage.Save(@"d:" + $"{cur}_{count}" + ".emf", ImageFormat.Tiff); return "已保存图片"; } //正式时调用打印机打印 var r = Printer.PrintImageData(pageImage, printName, "0", "0"); if (!r.IsSuccess) return r.Message; return ""; } private Stream CreateStream(string name, string fileNameExtension, Encoding encoding, string mimeType, bool willSeek) { //如果需要将报表输出的数据保存为文件,请使用FileStream对象。 Stream stream = new MemoryStream(); BillPrintSteam = stream; m_streams.Add(stream); return stream; }
4、生成的图片输出到打印机打印:
将生成的image在打印机端
可使用PrinterSettings.StringCollection listPrint = PrinterSettings.InstalledPrinters;获取所有打印机名称
public static PrintModel PrintImageData(Image pageImage,string PrinterName,string PaperSizeWidth,string PaperSizeHeight) { bool PrintIsSuccess=false; Exception PrintException=null; //声明PrintDocument对象用于数据的打印 PrintDocument printDoc = new PrintDocument(); printDoc.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0); //指定需要使用的打印机的名称,使用空字符串""来指定默认打印机 //传入打印机名称 则使用传入的,否则使用当前服务账户(登录为)的默认打印机 if (!string.IsNullOrWhiteSpace(PrinterName)) { printDoc.PrinterSettings.PrinterName = PrinterName; } //判断指定的打印机是否可用 if (!printDoc.PrinterSettings.IsValid) { return PrintModel.CreateFailedResult("未能找到默认的打印机!"); } if (!string.IsNullOrWhiteSpace(PaperSizeWidth) && PaperSizeWidth != "0" && !string.IsNullOrWhiteSpace(PaperSizeHeight) && PaperSizeHeight != "0") { var ps = new PaperSize("Your Paper Name", int.Parse(PaperSizeWidth), int.Parse(PaperSizeHeight)) { RawKind = 120 };//自定义纸张 printDoc.DefaultPageSettings.PaperSize = ps; } printDoc.PrintPage += new PrintPageEventHandler(delegate (object sender, PrintPageEventArgs ev) { try { ev.Graphics.PageUnit = GraphicsUnit.Document; //ev.Graphics.CompositingQuality = CompositingQuality.HighQuality; //ev.Graphics.PageScale = 1; if (pageImage == null) return; // Adjust rectangular area with printer margins. Rectangle adjustedRect = new Rectangle( ev.PageBounds.Left - (int)ev.PageSettings.HardMarginX, ev.PageBounds.Top - (int)ev.PageSettings.HardMarginY, ev.PageBounds.Width, ev.PageBounds.Height); Rectangle srcRect = new Rectangle(0, 0, pageImage.Width, pageImage.Height); // Draw a white background for the report //ev.Graphics.FillRectangle(Brushes.White, adjustedRect); // Draw the report content ev.Graphics.DrawImage(pageImage, srcRect);//, srcRect, GraphicsUnit.Pixel); ev.HasMorePages = false; } catch (Exception ex) { PrintException = ex; PrintIsSuccess = false; } }); try { if (pageImage == null) { PrintIsSuccess = false; } else { printDoc.Print(); PrintIsSuccess = true; } } catch (Exception ex) { PrintException = ex; PrintIsSuccess = false; } return PrintModel.Create(PrintIsSuccess, PrintIsSuccess ? "Print Success!" : "Print Fail!", PrintException); }
public static List<PrinterModel> GetPrinterList() { PrinterSettings ps = new PrinterSettings(); PrinterSettings.StringCollection listPrint = PrinterSettings.InstalledPrinters; List<PrinterModel> pList = new List<PrinterModel>(); for (int i = 0; i < listPrint.Count; i++) { PrinterModel pm = new PrinterModel(); ps.PrinterName = listPrint[i]; pm.PrinterName = ps.PrinterName; pm.IsDefaultPrinter = ps.IsDefaultPrinter; pm.OrderBy = pm.IsDefaultPrinter ? -1 : i; pList.Add(pm); } return pList.OrderBy(x => x.OrderBy).ToList(); }
以上cs结构下不需要特殊权限
如果为bs结构下或者需要ajax调取打印机的(电子称重同理可借鉴):
1、可以将打印图片的方法作为接口宿主到windowsservice上开放端口,安装在需要打印的电脑上。
接收的不是image改为图片的url,得到url后进行download后输出到打印机
可以增加接口判断打印服务是否可用
在app.config增加
<services> <service behaviorConfiguration="EnableMetadataBehaviors" name="Shangpin.Logistic.WindowsService.ClientPrintService.ServiceLibrary.PrintService"> <endpoint address="" binding="webHttpBinding" behaviorConfiguration="WebScriptBehavior" bindingConfiguration="HttpJsonpBinding" contract="Shangpin.Logistic.WindowsService.ClientPrintService.ServiceLibrary.IPrintService" /> <host> <baseAddresses> <add baseAddress="http://localhost:41943/PrintService" /> </baseAddresses> </host> </service>
2、形成图片的方法作为服务端接口可得到图片,接口url可匿名给打印服务获取图片
在网页的按钮上实现ajax跨域请求:
$.ajax({ url: "http://localhost:41943/PrintService/Print?jsoncallback=?", dataType: 'jsonp', data: { url: imageUrl, printerName: $("#PrinterList").find("option:selected").val(), paperSizeWidth: paperSizeWidth, paperSizeHeight: paperSizeHeight }, success: function (data) { if (!data.IsSuccess) { LG.showError("明细编号" + printArr[i] + "打印失败:" + data.Message, function () { JudgePrintAgain(printArr, i, url, paperSizeWidth, paperSizeHeight);//循环打印 }); } else { JudgePrintAgain(printArr, i, url, paperSizeWidth, paperSizeHeight); } }, error: function (result) { LG.tip('发现系统错误 <br />错误码:' + result.status); } });