using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; using Newtonsoft.Json; using System.Linq; using Newtonsoft.Json.Linq; using System.IO; using BarcodeLib; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; using QRCoder; namespace POSV.Printer { public enum RowFormat { None = 0, Line = 1, Column = 2, Grid = 3, Barcode = 4, QRCode = 5, Bitmap = 6 } [Serializable] [JsonObject(MemberSerialization.OptIn)] public class PrinterTemplate { [JsonProperty(PropertyName = "pager")] public PagerType PagerType { get; set; } /// /// 单行最大打印半角字符数量 /// [JsonProperty(PropertyName = "maxlength")] public int MaxLength { get; set; } private List _rows = new List(); [JsonProperty(PropertyName = "rows")] public List Rows { get { return _rows; } } public void AddRow(RowTemplate row) { this.Rows.Add(row); } public List Parse(PrinterObject pobject , List args, int headerLine = 0, int footerLine = 0) { if (pobject == null) { pobject = new PrinterObject(); } if (args == null) { args = new List(); } var result = new List(); EscPosCommand command = pobject.EscPosCommand; bool isInit = false; //钱箱指令 if (pobject.OpenCashbox) { result.Add(OpenCashbox(pobject)); isInit = true; } //退纸指令 if(pobject.FeedBackRow > 0) { var content = new PrintContent(); content.Format = RowFormat.Line; var bs = new StringBuilder(); if (!isInit) { bs.Append(ParseEscPosCommand(command.InitCommand)); isInit = true; } var rows = pobject.FeedBackRow; while (rows > 0) { //反向走纸 bs.Append(ParseEscPosCommand(command.FeedBackCommand.Replace('n', '1'))); rows--; } content.Content = bs; result.Add(content); } if(headerLine > 0) { var _header = new PrintContent(); _header.Format = RowFormat.Line; var bs = new StringBuilder(); if (!isInit) { bs.Append(ParseEscPosCommand(command.InitCommand)); isInit = true; } for (int i = 0; i < headerLine; i++) { bs.AppendLine(""); } _header.Content = bs; _header.AlignStyle = AlignStyle.居左; _header.FontStyle = FontStyle.正常字体; _header.BitmapFile = string.Empty; result.Add(_header); } foreach (var rows in this.Rows) { switch (rows.RowFormat) { case RowFormat.Line: { //行数据模版 var template = JSON.Deserialize(rows.Template.ToString()); //数据源参数,无论单行还是列表,数据源采用List方式,兼容单行选择集合数据源,重复行打印 var data = new List>(); //包含数据源参数,重置 if (args.Exists(x => x.Key == template.DataSourceKey)) { //当前数据源 var vars = args.FindLast(x => x.Key == template.DataSourceKey); //List集合数据 if (vars.DataType == DataType.List) { data = JSON.Deserialize>>(vars.Value.ToString()); } else { var row = JSON.Deserialize>(vars.Value.ToString()); data.Add(row); } } var content = new PrintContent(); content.Format = RowFormat.Line; var sb = new StringBuilder(); int inx = 0; //替换变量 foreach (var row in data) { //初始化 if (!isInit) { sb.Append(ParseEscPosCommand(command.InitCommand)); isInit = true; } //字体指令 sb.Append(ParseFontStyle(template.FontStyle , command)); //打印内容 sb.Append(ReplaceArgs(template.Content , row , this.MaxLength , template.AlignStyle , template.FontStyle , template.LineStyle)); if(data.Count > 1 && inx + 1 != data.Count) { sb.AppendLine(""); } inx++; } content.Content = sb; result.Add(content); } break; case RowFormat.Column: { var template = JSON.Deserialize>(rows.Template.ToString()); var lists = MergeLineTemplate(template[0] , template[1] , args , command); var content = new PrintContent(); content.Format = RowFormat.Column; var sb = new StringBuilder(); foreach (var str in lists) { sb.Append(str); } content.Content = sb; result.Add(content); } break; case RowFormat.Grid: { var template = JSON.Deserialize(rows.Template.ToString()); //数据源参数,必须为列表 var data = new List>(); //包含数据源参数,重置 if (args.Exists(x => x.Key == template.DataSourceKey)) { //当前数据源 var vars = args.FindLast(x => x.Key == template.DataSourceKey); //List集合数据 if (vars.DataType == DataType.List) { data = JSON.Deserialize>>(vars.Value.ToString()); } else { var row = JSON.Deserialize>(vars.Value.ToString()); data.Add(row); } } //判断是否符合打印条件 var notAllowEmpty = template.NotAllowEmpty; if (notAllowEmpty && data.Count == 0) { continue; } var content = new PrintContent(); content.Format = RowFormat.Grid; var sb = new StringBuilder(); //标题行添加下划线 string paddingChar = this.ParseLineType(template.LineStyle); var _columnWidth = new Dictionary(); int _column = 0; int _sum = 0; //判断是否打印表头 var notAllowHeader = template.NotAllowHeader; var fontStyle = FontStyle.正常字体; if (!notAllowHeader) { //初始化 if (!isInit) { sb.Append(ParseEscPosCommand(command.InitCommand)); isInit = true; } //表头采用正常字体打印 var notAllowHeaderFontStyle = template.HeaderFontStyle; if (!notAllowHeaderFontStyle) { fontStyle = template.FontStyle; } //字体指令 sb.Append(ParseFontStyle(fontStyle , command)); } foreach (ColumnTempate col in template.Columns) { _sum += col.Length; _columnWidth.Add(_column++ , _sum); var title = ReplaceArgs(col.Name , null , col.Length , col.AlignStyle , fontStyle , LineStyle.不填充); int titleLength = GetPrintStringLength(title , fontStyle); int titleDiff = col.Length - titleLength; if (!notAllowHeader) { sb.Append(title + ("".PadRight(titleDiff < 0 ? 0 : titleDiff , Convert.ToChar(" ")))); } } //提交标题行打印 if (!notAllowHeader) { sb.AppendLine(""); } //提交下划线打印 if (!string.IsNullOrEmpty(paddingChar.Trim())) { //初始化 if (!isInit) { sb.Append(ParseEscPosCommand(command.InitCommand)); isInit = true; } //字体指令 sb.Append(ParseFontStyle(FontStyle.正常字体 , command)); sb.AppendLine("".PadRight(this.MaxLength , Convert.ToChar(paddingChar))); } //模版数据 for (int row = 0; row < data.Count; row++) { //判断是否允许输出合计行,并且是最后一行 if (template.ContainsTotalRow && row + 1 == data.Count) { //不允许打印,结束本次循环 if (!template.OutputTotalRow) { continue; } //初始化 if (!isInit) { sb.Append(ParseEscPosCommand(command.InitCommand)); isInit = true; } //字体指令 sb.Append(ParseFontStyle(FontStyle.正常字体 , command)); //下划线,隔离合计行和明细 sb.AppendLine("".PadRight(this.MaxLength , Convert.ToChar(paddingChar))); } //初始化 if (!isInit) { sb.Append(ParseEscPosCommand(command.InitCommand)); isInit = true; } int cols = 0; var _offset = new Dictionary(); foreach (ColumnTempate col in template.Columns) { if (template.AllowNewLine) { var _content = ReplaceArgs(col.DataMember , template.AllowNewLine , data[row] , col.Length , col.AlignStyle , template.FontStyle , LineStyle.不填充); int len = GetPrintStringLength(_content, template.FontStyle); //长度超出,允许独占一行 if (len > col.Length) { _offset[cols] = _columnWidth[cols]; } else { _offset[cols] = 0; } //独占一行的内容 if (_offset[cols] > 0) { int width = cols == 0 ? 0 : _offset[cols - 1]; //字体指令 //独占一行的进行左对齐初始化,发现在打印图片后会导致这里居中显示 sb.Append(ParseEscPosCommand(command.AlignLeftCommand)); sb.Append(ParseFontStyle(template.FontStyle , command)); sb.AppendLine("".PadLeft(width , ' ') + _content); } else { int width = cols == 0 ? 0 : _offset[cols - 1]; //字体指令 sb.Append(ParseFontStyle(FontStyle.正常字体 , command)); sb.Append("".PadLeft(width , ' ')); int diff = col.Length - len; //字体指令 sb.Append(ParseFontStyle(template.FontStyle , command)); sb.Append(_content ); //字体指令 sb.Append(ParseFontStyle(FontStyle.正常字体 , command)); sb.Append("".PadRight(diff < 0 ? 0 : diff , ' ')); } } else { var _content = ReplaceArgs(col.DataMember , template.AllowNewLine , data[row] , col.Length , col.AlignStyle , template.FontStyle , LineStyle.不填充); int len = GetPrintStringLength(_content,template.FontStyle); int diff = col.Length - len; //字体指令 sb.Append(ParseFontStyle(template.FontStyle , command)); sb.Append(_content + ("".PadRight(diff < 0 ? 0 : diff , ' '))); } cols++; } //包含合计行,而且不允许输出 if (template.ContainsTotalRow && !template.OutputTotalRow) { if (row + 2 != data.Count) { sb.AppendLine(""); } } else { if (row + 1 != data.Count) { sb.AppendLine(""); } } } content.Content = sb; result.Add(content); } break; case RowFormat.Barcode: { //行数据模版 var template = JSON.Deserialize(rows.Template.ToString()); //数据源参数,无论单行还是列表,数据源采用List方式,兼容单行选择集合数据源,重复行打印 var data = new List>(); //包含数据源参数,重置 if (args.Exists(x => x.Key == template.DataSourceKey)) { //当前数据源 var vars = args.FindLast(x => x.Key == template.DataSourceKey); //List集合数据 if (vars.DataType == DataType.List) { data = JSON.Deserialize>>(vars.Value.ToString()); } else { var row = JSON.Deserialize>(vars.Value.ToString()); data.Add(row); } } //替换变量 foreach (var row in data) { //是否显示标签 var _barcodeShowLabel = template.ShowLable; //标签的内容 var _barcodeLabelontent = ReplaceArgs(template.LableContent , row , this.MaxLength , template.AlignStyle , template.FontStyle , LineStyle.不填充); //条码内容 var _barcodeContent = ReplaceArgs(template.Content , row , this.MaxLength , template.AlignStyle , template.FontStyle , LineStyle.不填充); //如果标签内容为空,视为不显示标签 if (string.IsNullOrEmpty(_barcodeLabelontent.Trim())) { _barcodeLabelontent = _barcodeContent.Trim(); } //内容为空或者非数字 if (string.IsNullOrEmpty(_barcodeContent.Trim()) || !this.IsNumber(_barcodeContent.Trim())) { continue; } var content = new PrintContent(); content.Format = RowFormat.Barcode; var sb = new StringBuilder(); //初始化 if (!isInit) { sb.Append(ParseEscPosCommand(command.InitCommand)); isInit = true; } //字体指令 sb.Append(ParseFontStyle(template.FontStyle, command)); switch (template.AlignStyle) { case AlignStyle.居左: { sb.Append(ParseEscPosCommand(command.AlignLeftCommand)); } break; case AlignStyle.居中: { sb.Append(ParseEscPosCommand(command.AlignCenterCommand)); } break; case AlignStyle.居右: { sb.Append(ParseEscPosCommand(command.AlignRightCommand)); } break; } sb.AppendLine(""); content.Content = sb; content.BitmapFile = BuilderBarcode(_barcodeContent.Trim() , _barcodeShowLabel , _barcodeLabelontent.Trim() , template.AlignStyle); result.Add(content); } } break; case RowFormat.QRCode: { //行数据模版 var template = JSON.Deserialize(rows.Template.ToString()); //数据源参数,无论单行还是列表,数据源采用List方式,兼容单行选择集合数据源,重复行打印 var data = new List>(); //包含数据源参数,重置 if (args.Exists(x => x.Key == template.DataSourceKey)) { //当前数据源 var vars = args.FindLast(x => x.Key == template.DataSourceKey); //List集合数据 if (vars.DataType == DataType.List) { data = JSON.Deserialize>>(vars.Value.ToString()); } else { var row = JSON.Deserialize>(vars.Value.ToString()); data.Add(row); } } //替换变量 foreach (var row in data) { //二维码内容 var _content = ReplaceArgs(template.Content , row , this.MaxLength , template.AlignStyle , template.FontStyle , LineStyle.不填充); //内容为空 if (string.IsNullOrEmpty(_content.Trim())) { continue; } var content = new PrintContent(); content.Format = RowFormat.QRCode; var sb = new StringBuilder(); //初始化 if (!isInit) { sb.Append(ParseEscPosCommand(command.InitCommand)); isInit = true; } //字体指令 sb.Append(ParseFontStyle(template.FontStyle , command)); switch (template.AlignStyle) { case AlignStyle.居左: { sb.Append(ParseEscPosCommand(command.AlignLeftCommand)); } break; case AlignStyle.居中: { sb.Append(ParseEscPosCommand(command.AlignCenterCommand)); } break; case AlignStyle.居右: { sb.Append(ParseEscPosCommand(command.AlignRightCommand)); } break; } sb.AppendLine(""); content.Content = sb; content.BitmapFile = BuilderQRCode(_content,template.SizeMode); result.Add(content); } } break; case RowFormat.Bitmap: { //行数据模版 var template = JSON.Deserialize(rows.Template.ToString()); //数据源参数,无论单行还是列表,数据源采用List方式,兼容单行选择集合数据源,重复行打印 var data = new List>(); //包含数据源参数,重置 if (args.Exists(x => x.Key == template.DataSourceKey)) { //当前数据源 var vars = args.FindLast(x => x.Key == template.DataSourceKey); //List集合数据 if (vars.DataType == DataType.List) { data = JSON.Deserialize>>(vars.Value.ToString()); } else { var row = JSON.Deserialize>(vars.Value.ToString()); data.Add(row); } } //替换变量 foreach (var row in data) { //位图路径 //var _bitmapFile = ReplaceArgs(template.Content , row , this.MaxLength , template.AlignStyle , template.FontStyle , LineStyle.不填充); var _bitmapFile = string.Empty; if (row.ContainsKey(template.Content)) { _bitmapFile = row[template.Content]; } //文件不存在 if (string.IsNullOrEmpty(_bitmapFile) || !File.Exists(_bitmapFile.Trim())) { continue; } var content = new PrintContent(); content.Format = RowFormat.Bitmap; var sb = new StringBuilder(); //初始化 if (!isInit) { sb.Append(ParseEscPosCommand(command.InitCommand)); isInit = true; } //字体指令 sb.Append(ParseFontStyle(template.FontStyle , command)); switch (template.AlignStyle) { case AlignStyle.居左: { sb.Append(ParseEscPosCommand(command.AlignLeftCommand)); } break; case AlignStyle.居中: { //sb.Append(ParseEscPosCommand(command.AlignCenterCommand)); sb.Append(ParseEscPosCommand("27,97,1")); } break; case AlignStyle.居右: { sb.Append(ParseEscPosCommand(command.AlignRightCommand)); } break; } sb.AppendLine(""); content.Content = sb; var bitmap = new Bitmap(Bitmap.FromFile(_bitmapFile.Trim())); content.BitmapFile = ConvertToBpp(bitmap); result.Add(content); } } break; } } if(footerLine > 0) { var _footer = new PrintContent(); _footer.Format = RowFormat.Line; var bs = new StringBuilder(); //打印图片后不初始化,会不打印后续内容 bs.Append(ParseEscPosCommand(command.InitCommand)); //if (!isInit) //{ // isInit = true; //} for (int i = 0; i < footerLine; i++) { bs.AppendLine(""); } _footer.Content = bs; _footer.AlignStyle = AlignStyle.居左; _footer.FontStyle = FontStyle.正常字体; _footer.BitmapFile = string.Empty; result.Add(_footer); } //切纸指令 if (pobject.CutPager) { result.Add(CutPager(pobject)); } //蜂鸣 if(pobject.Beep) { var content = new PrintContent(); content.Format = RowFormat.Line; content.Content = new StringBuilder().Append(ParseEscPosCommand("27,66,3,1")); result.Add(content); } return result; } //判断字符串是否为纯数字 public bool IsNumber(string str) { if (str == null || str.Length == 0) return false; ASCIIEncoding ascii = new ASCIIEncoding(); byte[] bytestr = ascii.GetBytes(str); foreach (byte c in bytestr) { if (c < 48 || c > 57) { return false; } } return true; } public PrintContent OpenCashbox(PrinterObject pobject) { EscPosCommand command = pobject.EscPosCommand; var content = new PrintContent(); content.Format = RowFormat.Line; var sb = new StringBuilder(); //初始化 sb.Append(ParseEscPosCommand(command.InitCommand)); //开钱箱 sb.Append(ParseEscPosCommand(command.CashboxCommand)); content.Content = sb; return content; } public PrintContent CutPager(PrinterObject pobject) { EscPosCommand command = pobject.EscPosCommand; var content = new PrintContent(); content.Format = RowFormat.Line; var sb = new StringBuilder(); //初始化 sb.Append(ParseEscPosCommand(command.InitCommand)); //切纸 sb.Append(ParseEscPosCommand(command.CutPageCommand)); content.Content = sb; return content; } private string BuilderQRCode(string content,QRCodeSizeMode size) { QRCodeGenerator.ECCLevel eccLevel = QRCodeGenerator.ECCLevel.Q; using (QRCodeGenerator qrGenerator = new QRCodeGenerator()) { using (QRCodeData qrCodeData = qrGenerator.CreateQrCode(content , eccLevel)) { using (QRCode qrCode = new QRCode(qrCodeData)) { Bitmap bitmap = null; switch (size) { case QRCodeSizeMode.大图: { bitmap = qrCode.GetGraphic(10 , Color.Black , Color.White , false); } break; case QRCodeSizeMode.小图: { bitmap = qrCode.GetGraphic(5 , Color.Black , Color.White , false); } break; case QRCodeSizeMode.默认: default: { bitmap = qrCode.GetGraphic(8 , Color.Black , Color.White , false); } break; } return ConvertToBpp(bitmap); } } } } private string BuilderBarcode(string content, bool showLabel , string lableContent, AlignStyle align) { Barcode barcode = new Barcode(); barcode.IncludeLabel = showLabel; barcode.LabelFont = new Font("Microsoft Sans Serif" , 15.75F , System.Drawing.FontStyle.Bold); barcode.AlternateLabel = lableContent; barcode.Height = 90; barcode.Width = Convert.ToInt16(45 * 8); switch (align) { case AlignStyle.居左: { barcode.Alignment = AlignmentPositions.LEFT; barcode.LabelPosition = LabelPositions.BOTTOMLEFT; } break; case AlignStyle.居中: { barcode.Alignment = AlignmentPositions.CENTER; barcode.LabelPosition = LabelPositions.BOTTOMCENTER; } break; case AlignStyle.居右: { barcode.Alignment = AlignmentPositions.RIGHT; barcode.LabelPosition = LabelPositions.BOTTOMRIGHT; } break; } barcode.ImageFormat = ImageFormat.Bmp; var bitmap = new Bitmap(barcode.Encode(TYPE.CODE128 , content)); return ConvertToBpp(bitmap); } /// /// 转换单色位图的方法 /// /// private Bitmap xxx(Bitmap img) { int w = img.Width; int h = img.Height; Bitmap bmp = new Bitmap(w , h , PixelFormat.Format1bppIndexed); BitmapData data = bmp.LockBits(new Rectangle(0 , 0 , w , h) , ImageLockMode.ReadWrite , PixelFormat.Format1bppIndexed); for (int y = 0; y < h; y++) { byte[] scan = new byte[(w + 7) / 8]; for (int x = 0; x < w; x++) { Color c = img.GetPixel(x , y); if (c.GetBrightness() >= 0.5) scan[x / 8] |= (byte)(0x80 >> (x % 8)); } Marshal.Copy(scan , 0 , (IntPtr)((int)data.Scan0 + data.Stride * y) , scan.Length); } bmp.Palette = CreateGrayscalePalette(); return bmp; } /// /// 创建单色灰度调色板 /// /// 返回调色板 private ColorPalette CreateGrayscalePalette() { ColorPalette palette = CreateColorPalette(PixelFormat.Format1bppIndexed); palette.Entries[0] = Color.FromArgb(0 , 0 , 0 , 0); palette.Entries[1] = Color.FromArgb(0 , 255 , 255 , 255); return palette; } /// /// 创建图像格式对应的调色板 /// /// 图像格式,只能是Format1bppIndexed,Format1bppIndexed,Format1bppIndexed /// 返回调色板;如果创建失败或者图像格式不支持,返回null。 private ColorPalette CreateColorPalette(PixelFormat pixelFormat) { ColorPalette palette = null; if (pixelFormat == PixelFormat.Format1bppIndexed || pixelFormat == PixelFormat.Format4bppIndexed || pixelFormat == PixelFormat.Format8bppIndexed) { //因为ColorPalette类没有构造函数,所以这里创建一个1x1的位图,然后抓取该位图的调色板 Bitmap temp = new Bitmap(1 , 1 , pixelFormat); palette = temp.Palette; temp.Dispose(); } return palette; } /// /// 转换为单色位图后,图像信息头中的位图使用的颜色数及指定重要的颜色数设置为0 /// /// /// private string ConvertToBpp(Bitmap bitMap) { //打开任一索引色的或者非索引色的图像 Bitmap bm = xxx(bitMap); MemoryStream ms = new MemoryStream(); bm.Save(ms , System.Drawing.Imaging.ImageFormat.Bmp); byte[] buffer = new byte[ms.Length]; //Image.Save()会改变MemoryStream的Position,需要重新Seek到Begin ms.Seek(0 , SeekOrigin.Begin); ms.Read(buffer , 0 , buffer.Length); byte[] bitLenght = new byte[4]; Array.Copy(buffer , 2 , bitLenght , 0 , 4); int ibitlen = BytesToInt(bitLenght , 0); Array.Copy(bitLenght , 0 , buffer , 34 , 4); byte[] bitmapBuffer = new byte[1]; bitmapBuffer[0] = 0; Array.Copy(bitmapBuffer , 0 , buffer , 46 , 1); Array.Copy(bitmapBuffer , 0 , buffer , 50 , 1); FileStream fs = null; string basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory , @"temp\"); if (!Directory.Exists(basePath)) { Directory.CreateDirectory(basePath); } string filename = DesignerObjectId.GenerateNewStringId() + ".bmp"; string file = Path.Combine(basePath,filename); //将待写的入数据从字符串转换为字节数组 fs = File.OpenWrite(file); //设定书写的开始位置为文件的末尾 fs.Position = 0;//fs.Length //将待写入内容追加到文件末尾 fs.Write(buffer , 0 , ibitlen); fs.Close(); bm.Dispose(); return file; } private int BytesToInt(byte[] ary , int offset) { int value; value = (int)((ary[offset] & 0xFF) | ((ary[offset + 1] << 8) & 0xFF00) | ((ary[offset + 2] << 16) & 0xFF0000) | ((ary[offset + 3] << 24) & 0xFF000000)); return value; } ///// ///// 构建打印字符串 ///// ///// 打印对象 ///// 模版参数 ///// 是否打开钱箱 ///// 是否切纸 ///// 是否生成预览文件 ///// //public StringBuilder Parse(PrinterObject pobject , List args , bool isPreview) //{ // if (pobject == null) // { // pobject = new PrinterObject(); // } // if (args == null) // { // args = new List(); // } // EscPosCommand command = pobject.EscPosCommand; // StringBuilder sb = new StringBuilder(); // //初始化指令 // if (!isPreview) // { // sb.Append(ParseEscPosCommand(command.InitCommand)); // //钱箱指令 // if (pobject.OpenCashbox) // { // sb.Append(ParseEscPosCommand(command.CashboxCommand)); // } // } // foreach (var rows in this.Rows) // { // switch (rows.RowFormat) // { // case RowFormat.Line: // { // //行数据模版 // var template = JSON.Deserialize(rows.Template.ToString()); // //数据源参数,无论单行还是列表,数据源采用List方式,兼容单行选择集合数据源,重复行打印 // var data = new List>(); // //包含数据源参数,重置 // if (args.Exists(x=>x.Key == template.DataSourceKey)) // { // //当前数据源 // var vars = args.FindLast(x=>x.Key == template.DataSourceKey); // //List集合数据 // if (vars.DataType == DataType.List) // { // data = JSON.Deserialize>>(vars.Value.ToString()); // } // else // { // var row = JSON.Deserialize>(vars.Value.ToString()); // data.Add(row); // } // } // //替换变量 // foreach(var row in data) // { // //字体指令 // if (isPreview) // { // sb.Append((int)template.FontStyle + ","); // } // else // { // sb.Append(ParseFontStyle(template.FontStyle , command)); // } // sb.AppendLine(ReplaceArgs(template.Content , row , this.MaxLength , template.AlignStyle , template.FontStyle , template.LineStyle)); // } // } // break; // case RowFormat.Column: // { // var template = JSON.Deserialize>(rows.Template.ToString()); // var result = MergeLineTemplate(template[0] , template[1] , args , command); // foreach (var str in result) // { // sb.Append(str); // } // } // break; // case RowFormat.Grid: // { // var template = JSON.Deserialize(rows.Template.ToString()); // //数据源参数,必须为列表 // var data = new List>(); // //包含数据源参数,重置 // if (args.Exists(x => x.Key == template.DataSourceKey)) // { // //当前数据源 // var vars = args.FindLast(x => x.Key == template.DataSourceKey); // //List集合数据 // if (vars.DataType == DataType.List) // { // data = JSON.Deserialize>>(vars.Value.ToString()); // } // else // { // var row = JSON.Deserialize>(vars.Value.ToString()); // data.Add(row); // } // } // //判断是否符合打印条件 // var notAllowEmpty = template.NotAllowEmpty; // if (notAllowEmpty && data.Count == 0) // { // continue; // } // //字体指令 // if (isPreview) // { // sb.Append((int)template.FontStyle + ","); // } // else // { // sb.Append(ParseFontStyle(template.FontStyle, command)); // } // //标题行添加下划线 // string paddingChar = this.ParseLineType(template.LineStyle); // var _columnWidth = new Dictionary(); // int _column = 0; // int _sum = 0; // foreach (ColumnTempate col in template.Columns) // { // _sum += col.Length; // _columnWidth.Add(_column++ , _sum); // var title = ReplaceArgs(col.Name , null , col.Length , col.AlignStyle , template.FontStyle , LineStyle.不填充); // int titleLength = GetPrintStringLength(title); // int titleDiff = col.Length - titleLength; // sb.Append(title + ("".PadRight(titleDiff < 0 ? 0 : titleDiff , Convert.ToChar(paddingChar)))); // } // //提交标题行打印 // sb.AppendLine(""); // //提交下划线打印 // if (!string.IsNullOrEmpty(paddingChar.Trim())) // { // //字体指令 // if (isPreview) // { // sb.Append((int)FontStyle.正常字体 + ","); // } // else // { // sb.Append(ParseFontStyle(FontStyle.正常字体, command)); // } // sb.AppendLine("".PadRight(this.MaxLength , Convert.ToChar(paddingChar))); // } // //模版数据 // for (int row = 0; row < data.Count; row++) // { // //判断是否允许输出合计行,并且是最后一行 // if(template.ContainsTotalRow && row + 1 == data.Count) // { // //不允许打印,结束本次循环 // if (!template.OutputTotalRow) // { // continue; // } // //字体指令 // if (isPreview) // { // sb.Append((int)FontStyle.正常字体 + ","); // } // else // { // sb.Append(ParseFontStyle(FontStyle.正常字体, command)); // } // sb.AppendLine("".PadRight(this.MaxLength , Convert.ToChar(paddingChar))); // } // //字体指令 // if (isPreview) // { // sb.Append((int)template.FontStyle + ","); // } // else // { // sb.Append(ParseFontStyle(template.FontStyle, command)); // } // int cols = 0; // var _offset = new Dictionary(); // foreach (ColumnTempate col in template.Columns) // { // if (template.AllowNewLine) // { // var content = ReplaceArgs(col.DataMember , template.AllowNewLine , data[row] , col.Length , col.AlignStyle , template.FontStyle , LineStyle.不填充); // int len = GetPrintStringLength(content); // //长度超出,允许独占一行 // if (len > col.Length) // { // _offset[cols] = _columnWidth[cols]; // } // else // { // _offset[cols] = 0; // } // if (_offset[cols] > 0) // { // int width = cols == 0 ? 0 : _offset[cols - 1]; // sb.AppendLine("".PadLeft(width , ' ') + content); // } // else // { // int width = cols == 0 ? 0 : _offset[cols - 1]; // sb.Append("".PadLeft(width , ' ')); // int diff = col.Length - len; // sb.Append(content + ("".PadRight(diff < 0 ? 0 : diff , ' '))); // } // } // else // { // var content = ReplaceArgs(col.DataMember , template.AllowNewLine , data[row] , col.Length , col.AlignStyle , template.FontStyle , LineStyle.不填充); // int len = GetPrintStringLength(content); // int diff = col.Length - len; // sb.Append(content + ("".PadRight(diff < 0 ? 0 : diff , ' '))); // } // cols++; // } // sb.AppendLine(""); // } // } // break; // } // } // //归位打印机字体 // if (!isPreview) // { // sb.Append(ParseEscPosCommand(command.NormalCommand)); // } // //切纸指令 // if (!isPreview && pobject.CutPager) // { // sb.Append(ParseEscPosCommand(command.CutPageCommand)); // } // //提交 // if (!isPreview) // { // sb.AppendLine(""); // } // return sb; //} /// /// 表格超出打印宽度特殊处理 /// /// /// /// /// /// /// /// /// private string ReplaceArgs(string content ,bool fullLine, Dictionary args , int maxLength , AlignStyle alignStyle , FontStyle fontStyle , LineStyle lineStyle) { if (args == null) { args = new Dictionary(); } foreach (var item in args) { var match = item.Key; var regex = new Regex(match , RegexOptions.IgnoreCase); if (item.Value is string) { content = regex.Replace(content , item.Value.ToString()); } } Tuple> res = GetPrintStringLength(content , fullLine , maxLength , fontStyle); int length = res.Item1; List str = res.Item2; string result = string.Empty; for (int i = 0; i < str.Count; i++) { var s = str[i]; int len = GetPrintStringLength(s , fontStyle); int fix = 0; switch (fontStyle) { case FontStyle.正常字体: case FontStyle.倍高字体: fix = 2; break; case FontStyle.倍宽倍高: case FontStyle.倍宽字体: fix = 4; break; default: fix = 2; break; } int diff = 0; string paddingChar = this.ParseLineType(lineStyle); switch (alignStyle) { case AlignStyle.居左: diff = (maxLength - len) / fix * 2; result += s + "".PadRight(diff < 0 ? 0 : diff , Convert.ToChar(paddingChar)); break; case AlignStyle.居中: diff = (maxLength - len) / fix; result += "".PadLeft(diff < 0 ? 0 : diff , Convert.ToChar(paddingChar)) + s + "".PadRight(diff < 0 ? 0 : diff , Convert.ToChar(paddingChar)); break; case AlignStyle.居右: diff = (maxLength - len) / fix * 2; result += "".PadLeft(diff < 0 ? 0 : diff , Convert.ToChar(paddingChar)) + s; break; } if (i + 1 != str.Count) { result += Environment.NewLine; } } //处理单独划线 if (string.IsNullOrEmpty(result)) { int fix = 0; switch (fontStyle) { case FontStyle.正常字体: case FontStyle.倍高字体: fix = 2; break; case FontStyle.倍宽倍高: case FontStyle.倍宽字体: fix = 4; break; default: fix = 2; break; } string paddingChar = this.ParseLineType(lineStyle); result = "".PadRight(maxLength / fix * 2 , Convert.ToChar(paddingChar)); } return result; } /// /// 表格超出打印宽度特殊处理 /// /// /// /// /// /// private Tuple> GetPrintStringLength(string str , bool fullLine , int maxLength , FontStyle fontStyle) { int valueLength = 0; List list = new List(); string tmpString = ""; string chinese = @"^[\u0391-\uFFE5]+$"; // 获取字段值的长度,如果含中文字符,则每个中文字符长度为2,否则为1 for (int i = 0; i < str.Length; i++) { // 获取一个字符 string temp = str[i].ToString(); // 判断是否为中文字符 if (Regex.IsMatch(temp , chinese)) { switch (fontStyle) { case FontStyle.正常字体: case FontStyle.倍高字体: valueLength += 2; break; case FontStyle.倍宽倍高: case FontStyle.倍宽字体: valueLength += 4; break; default: valueLength += 2; break; } } else { switch (fontStyle) { case FontStyle.正常字体: case FontStyle.倍高字体: valueLength += 1; break; case FontStyle.倍宽倍高: case FontStyle.倍宽字体: valueLength += 2; break; default: valueLength += 1; break; } } tmpString += temp; if (!fullLine) { if (valueLength % maxLength == 0) { list.Add(tmpString); tmpString = ""; } } } if (!string.IsNullOrEmpty(tmpString)) { list.Add(tmpString); } // 进位取整 return new Tuple>(valueLength , list); } /// /// 合并两列布局的数据为行数据 /// /// /// /// /// /// public List MergeLineTemplate(LineTemplate left , LineTemplate right , List args , EscPosCommand command) { //数据源参数 var data = new List>(); //包含数据源参数,重置 if (args.Exists(x => x.Key == left.DataSourceKey)) { //当前数据源 var vars = args.FindLast(x => x.Key == left.DataSourceKey); //List集合数据 if (vars.DataType == DataType.List) { data = JSON.Deserialize>>(vars.Value.ToString()); } else { var row = JSON.Deserialize>(vars.Value.ToString()); data.Add(row); } } //左标签的换行后字符串列表 List leftList = ReplaceArgsEx(left.Content , data , left.Length , left.AlignStyle , left.FontStyle , left.LineStyle); var leftDictionary = new Dictionary(); for(int i = 0; i < leftList.Count; i++) { leftDictionary.Add(i , leftList[i]); } //重置 data = new List>(); //包含数据源参数,重置 if (args.Exists(x => x.Key == right.DataSourceKey)) { //当前数据源 var vars = args.FindLast(x => x.Key == right.DataSourceKey); //List集合数据 if (vars.DataType == DataType.List) { data = JSON.Deserialize>>(vars.Value.ToString()); } else { var row = JSON.Deserialize>(vars.Value.ToString()); data.Add(row); } } //右标签的换行后字符串列表 List rightList = ReplaceArgsEx(right.Content , data , right.Length , right.AlignStyle , right.FontStyle , right.LineStyle); var rightDictionary = new Dictionary(); for (int i = 0; i < rightList.Count; i++) { rightDictionary.Add(i , rightList[i]); } var result = new List(); var diff = leftList.Count - rightList.Count; if (diff>0) { for(int i = 0; i < diff; i++) { rightList.Insert(0 , ""); } } else { for (int i = 0; i < Math.Abs(diff); i++) { leftList.Insert(0 , ""); } } for (int i = 0; i < leftList.Count; i++) { StringBuilder sb = new StringBuilder(); //字体指令 sb.Append(ParseFontStyle(left.FontStyle , command)); sb.Append(leftList[i]); sb.Append(rightList[i]); result.Add(sb.ToString()); } return result; } public List ReplaceArgsEx(string content , List> args , int maxLength , AlignStyle alignStyle , FontStyle fontStyle , LineStyle lineStyle) { List result = new List(); foreach(var data in args) { string str = ReplaceArgs(content , data , maxLength , alignStyle , fontStyle , lineStyle); if (str.Contains(Environment.NewLine)) { string[] array = str.Split(new string[] { Environment.NewLine } , StringSplitOptions.RemoveEmptyEntries); result.AddRange(array); } else { string paddingChar = this.ParseLineType(lineStyle); if (string.IsNullOrEmpty(str)) { str = "".PadLeft(maxLength , Convert.ToChar(paddingChar)); } result.Add(str); } } return result; } private string ReplaceArgs(string content , Dictionary args , int maxLength , AlignStyle alignStyle , FontStyle fontStyle,LineStyle lineStyle) { if (args == null) { args = new Dictionary(); } foreach (var item in args) { var match = item.Key; var regex = new Regex(match , RegexOptions.IgnoreCase); if (item.Value is string) { content = regex.Replace(content , item.Value.ToString()); } } Tuple> res = GetPrintStringLength(content , maxLength , fontStyle); int length = res.Item1; List str = res.Item2; string result = string.Empty; for (int i = 0; i < str.Count; i++) { var s = str[i]; int len = GetPrintStringLength(s , fontStyle); int fix = 0; switch (fontStyle) { case FontStyle.正常字体: case FontStyle.倍高字体: fix = 2; break; case FontStyle.倍宽倍高: case FontStyle.倍宽字体: fix = 4; break; default: fix = 2; break; } int diff = 0; string paddingChar = this.ParseLineType(lineStyle); switch (alignStyle) { case AlignStyle.居左: diff = (maxLength - len) * 2 / fix; result += s + "".PadRight(diff < 0 ? 0 : diff , Convert.ToChar(paddingChar)); break; case AlignStyle.居中: diff = (maxLength - len) / fix; result += "".PadLeft(diff < 0 ? 0 : diff , Convert.ToChar(paddingChar)) + s + "".PadRight(diff < 0 ? 0 : diff , Convert.ToChar(paddingChar)); break; case AlignStyle.居右: diff = (maxLength - len) * 2 / fix; result += "".PadLeft(diff < 0 ? 0 : diff , Convert.ToChar(paddingChar)) + s; break; } if (i + 1 != str.Count) { result += Environment.NewLine; } } //处理单独划线 if (string.IsNullOrEmpty(result)) { int fix = 0; switch (fontStyle) { case FontStyle.正常字体: case FontStyle.倍高字体: fix = 2; break; case FontStyle.倍宽倍高: case FontStyle.倍宽字体: fix = 4; break; default: fix = 2; break; } string paddingChar = this.ParseLineType(lineStyle); result = "".PadRight(maxLength * 2 / fix , Convert.ToChar(paddingChar)); } return result; } private static int GetPrintStringLength(string str , FontStyle fontStyle) { int valueLength = 0; string chinese = @"^[\u0391-\uFFE5]+$"; // 获取字段值的长度,如果含中文字符,则每个中文字符长度为2,否则为1 for (int i = 0; i < str.Length; i++) { // 获取一个字符 string temp = str[i].ToString(); // 判断是否为中文字符 if (Regex.IsMatch(temp , chinese)) { switch (fontStyle) { case FontStyle.正常字体: case FontStyle.倍高字体: valueLength += 2; break; case FontStyle.倍宽倍高: case FontStyle.倍宽字体: valueLength += 4; break; default: valueLength += 2; break; } } else { switch (fontStyle) { case FontStyle.正常字体: case FontStyle.倍高字体: valueLength += 1; break; case FontStyle.倍宽倍高: case FontStyle.倍宽字体: valueLength += 2; break; default: valueLength += 1; break; } } } // 进位取整 return valueLength; } private Tuple> GetPrintStringLength(string str , int maxLength , FontStyle fontStyle) { int valueLength = 0; List list = new List(); string tmpString = ""; string chinese = @"^[\u0391-\uFFE5]+$"; // 获取字段值的长度,如果含中文字符,则每个中文字符长度为2,否则为1 for (int i = 0; i < str.Length; i++) { // 获取一个字符 string temp = str[i].ToString(); // 判断是否为中文字符 if (Regex.IsMatch(temp , chinese)) { switch (fontStyle) { case FontStyle.正常字体: case FontStyle.倍高字体: valueLength += 2; break; case FontStyle.倍宽倍高: case FontStyle.倍宽字体: valueLength += 4; break; default: valueLength += 2; break; } } else { switch (fontStyle) { case FontStyle.正常字体: case FontStyle.倍高字体: valueLength += 1; break; case FontStyle.倍宽倍高: case FontStyle.倍宽字体: valueLength += 2; break; default: valueLength += 1; break; } } tmpString += temp; if (valueLength >= this.MaxLength) { list.Add(tmpString); tmpString = ""; valueLength = 0; } } if (!string.IsNullOrEmpty(tmpString)) { list.Add(tmpString); } // 进位取整 return new Tuple>(valueLength , list); } private string ParseEscPosCommand(string command) { string[] array = command.Split(','); List bytList = new List(); foreach (var s in array) { bytList.Add(Convert.ToByte(s.Trim())); } return Encoding.Default.GetString(bytList.ToArray()); } private string ParseLineType(LineStyle lineStyle) { string line = " "; switch (lineStyle) { case LineStyle.不填充: { line = " "; } break; case LineStyle.中划线: { line = "-"; } break; case LineStyle.双划线: { line = "="; } break; case LineStyle.井号线: { line = "#"; } break; case LineStyle.加号线: { line = "+"; } break; case LineStyle.星号线: { line = "*"; } break; case LineStyle.下划线: { line = "_"; } break; } return line; } private string ParseFontStyle(FontStyle fontStyle , EscPosCommand command) { string result = ParseEscPosCommand(command.NormalCommand); //27 , 33 , 48 (0,16,32,48) //28 , 33 , 12 (0,4,8,12 ) switch (fontStyle) { case FontStyle.正常字体: result = ParseEscPosCommand(command.NormalCommand); break; case FontStyle.倍宽字体: result = ParseEscPosCommand(command.DoubleWidthCommand); break; case FontStyle.倍高字体: result = ParseEscPosCommand(command.DoubleHeightCommand); break; case FontStyle.倍宽倍高: result = ParseEscPosCommand(command.DoubleWidthHeightCommand); break; } return result; } } /// /// 位图打印模版 /// [Serializable] [JsonObject(MemberSerialization.OptIn)] public class BitmapTemplate { /// /// 数据源 /// [JsonProperty(PropertyName = "data")] public string DataSourceKey { get; set; } /// /// 字体格式 /// [JsonProperty(PropertyName = "font")] public FontStyle FontStyle { get; set; } /// /// 对齐格式 /// [JsonProperty(PropertyName = "align")] public AlignStyle AlignStyle { get; set; } /// /// 位图路径 /// [JsonProperty(PropertyName = "content")] public string Content { get; set; } /// /// 字符串长度 /// [JsonProperty(PropertyName = "length")] public int Length { get; set; } } /// /// 二维码打印模版 /// [Serializable] [JsonObject(MemberSerialization.OptIn)] public class QRCodeTemplate { /// /// 数据源 /// [JsonProperty(PropertyName = "data")] public string DataSourceKey { get; set; } /// /// 字体格式 /// [JsonProperty(PropertyName = "font")] public FontStyle FontStyle { get; set; } /// /// 对齐格式 /// [JsonProperty(PropertyName = "align")] public AlignStyle AlignStyle { get; set; } /// /// 二维码大小 /// [JsonProperty(PropertyName = "size")] public QRCodeSizeMode SizeMode { get; set; } /// /// 条码标签生成内容 /// [JsonProperty(PropertyName = "content")] public string Content { get; set; } /// /// 字符串长度 /// [JsonProperty(PropertyName = "length")] public int Length { get; set; } } /// /// 条码打印模版 /// [Serializable] [JsonObject(MemberSerialization.OptIn)] public class BarcodeTemplate { /// /// 数据源 /// [JsonProperty(PropertyName = "data")] public string DataSourceKey { get; set; } /// /// 字体格式 /// [JsonProperty(PropertyName = "font")] public FontStyle FontStyle { get; set; } /// /// 对齐格式 /// [JsonProperty(PropertyName = "align")] public AlignStyle AlignStyle { get; set; } /// /// 条码标签生成内容 /// [JsonProperty(PropertyName = "content")] public string Content { get; set; } /// /// 字符串长度 /// [JsonProperty(PropertyName = "length")] public int Length { get; set; } /// /// 是否显示条码标签 /// [JsonProperty(PropertyName = "showLable")] public bool ShowLable { get; set; } = false; /// /// 条码标签生成内容 /// [JsonProperty(PropertyName = "lableContent")] public string LableContent { get; set; } } /// /// 行打印模版,单行和两列控件依赖 /// [Serializable] [JsonObject(MemberSerialization.OptIn)] public class LineTemplate { /// /// 数据源 /// [JsonProperty(PropertyName = "data")] public string DataSourceKey { get; set; } /// /// 字体格式 /// [JsonProperty(PropertyName = "font")] public FontStyle FontStyle { get; set; } /// /// 填充线条,主要解决划线 /// [JsonProperty(PropertyName = "line")] public LineStyle LineStyle { get; set; } /// /// 对齐格式 /// [JsonProperty(PropertyName = "align")] public AlignStyle AlignStyle { get; set; } /// /// 包含变量格式的内容 /// [JsonProperty(PropertyName = "content")] public string Content { get; set; } /// /// 字符串长度 /// [JsonProperty(PropertyName = "length")] public int Length { get; set; } } [Serializable] [JsonObject(MemberSerialization.OptIn)] public class RowTemplate { /// /// 行数据格式 /// [JsonProperty(PropertyName = "format")] public RowFormat RowFormat { get; set; } /// /// /// [JsonProperty(PropertyName = "template")] public object Template { get; set; } } [Serializable] [JsonObject(MemberSerialization.OptIn)] public class GridTemplate { [JsonProperty(PropertyName = "data")] public string DataSourceKey { get; set; } private List _columns = new List(); [JsonProperty(PropertyName = "columns")] public List Columns { get { return _columns; } } public void AddColumn(ColumnTempate column) { this.Columns.Add(column); } /// /// 表头下划线格式 /// [JsonProperty(PropertyName = "line")] public LineStyle LineStyle { get; set; } /// /// 表格的字体 /// [JsonProperty(PropertyName = "font")] public FontStyle FontStyle { get; set; } /// /// 是否包含合计行 /// [JsonProperty(PropertyName = "contains")] public bool ContainsTotalRow { get; set; } /// /// 是否输出打印合计行 /// [JsonProperty(PropertyName = "output")] public bool OutputTotalRow { get; set; } /// /// 超出打印字符长度,独占一行 /// [JsonProperty(PropertyName = "newline")] public bool AllowNewLine { get; set; } /// /// 如果记录集为空不打印 /// [JsonProperty(PropertyName = "empty")] public bool NotAllowEmpty { get; set; } /// /// 禁止打印表头 /// [JsonProperty(PropertyName = "header")] public bool NotAllowHeader { get; set; } = false; /// /// 表头采用正常字体打印 /// [JsonProperty(PropertyName = "headerFont")] public bool HeaderFontStyle { get; set; } = false; } [Serializable] [JsonObject(MemberSerialization.OptIn)] public class ColumnTempate { public ColumnTempate(string name , AlignStyle alignStyle , string dataMember , int length) { this.Name = name; this.AlignStyle = alignStyle; this.DataMember = dataMember; this.Length = length; } [JsonProperty(PropertyName = "name")] public string Name { get; set; } [JsonProperty(PropertyName = "align")] public AlignStyle AlignStyle { get; set; } [JsonProperty(PropertyName = "vars")] public string DataMember { get; set; } [JsonProperty(PropertyName = "length")] public int Length { get; set; } } }