using POSV.Printer; using System; using System.Collections.Generic; using System.Drawing.Printing; using System.Linq; using System.Text; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Drawing; using POSV.Designer; using QRCoder; using BarcodeLib; using System.IO; using NLog; namespace POSV.Helper { public class WinPrint { public WinPrint() { } static NLog.Logger logger = null; public static Logger Logger { get { if (logger == null) { logger = NLog.LogManager.GetLogger("winPrint"); return logger; } else { return logger; } } set { Logger = value; } } #region 驱动名称 private static string printName = "Fax"; /// /// 驱动名称 /// public static string PrintName { get => printName; set => printName = value; } #endregion #region 驱动打印组件 /// /// 打印机对象 /// private static PrintDocument m_WinPrint = new PrintDocument(); #endregion #region 打印任务队列 public static Queue m_PrintQueue = new Queue(); private static DesignerSurface skipsurface = null; private static JArray skipjArray = null; #endregion #region 正在执队列 /// /// 正在执队列 /// private static bool m_Underway = false; #endregion public static bool Print(string printname, DesignerSurface surface, List args) { //加入队列 var _data = new { surface, args }; m_PrintQueue.Enqueue(JsonConvert.SerializeObject(_data)); Initialize(printname); if (!m_Underway) { m_WinPrint.Print(); } return true; } /// /// 初始化打印机组件 /// /// private static void Initialize(string printname) { m_WinPrint.PrinterSettings.PrinterName = printname; if (!m_WinPrint.DocumentName.Equals("巨为餐饮小票")) { PrinterSettings printerSettings = new PrinterSettings(); m_WinPrint.DefaultPageSettings.Landscape = true; m_WinPrint.PrinterSettings = printerSettings; m_WinPrint.DocumentName = "巨为餐饮小票"; m_WinPrint.PrinterSettings.PrinterName = printname; m_WinPrint.PrintPage += M_WinPrint_PrintPage; m_WinPrint.EndPrint += M_WinPrint_EndPrint; m_WinPrint.PrintController = new StandardPrintController(); } } #region 打印事件 private static void M_WinPrint_EndPrint(object sender, PrintEventArgs e) { //删除队列 m_PrintQueue.Dequeue(); //判断是否还有队列 if (m_PrintQueue.Count > 0) { System.Threading.Tasks.Task.Factory.StartNew(() => { m_WinPrint.Print(); }); } } private static void M_WinPrint_PrintPage(object sender, PrintPageEventArgs e) { try { if (Logger == null) { Logger = NLog.LogManager.GetLogger("打印"); } Logger.Info("-------------------------------------------进入打印-------------------------------------------"); m_Underway = true; var _json = m_PrintQueue.Peek(); JObject jObject = JObject.Parse(_json); DesignerSurface surface = JsonConvert.DeserializeObject(jObject["surface"].ToString()); List args = JsonConvert.DeserializeObject>(jObject["args"].ToString()); if (skipsurface != null) { surface = skipsurface; } Font _font = new System.Drawing.Font("宋体", 12); SolidBrush _brush = new SolidBrush(Color.Black); int _y = 1; int _skip = 0; int _charAmount = 32; switch (surface.Width) { case 80: _charAmount = 38; break; case 76: _charAmount = 32; break; case 58: _charAmount = 28; break; } foreach (DesignerControls ctrls in surface.DesignerControls) { //换页标识 _skip++; //if (e.PageSettings.PaperSize.Height < _y) //{ // e.HasMorePages = true; // skipsurface = new DesignerSurface(); // skipsurface.DesignerControls = surface.DesignerControls.Skip(_skip).ToList(); // return; //} //else //{ // e.HasMorePages = false; // skipsurface = null; //} switch (ctrls.ControlType) { case ControlType.None: break; case ControlType.单行模版: { var parameter = JSON.Deserialize(ctrls.Template); string str = ""; #region list var _data = args.FirstOrDefault(f => f.Key == parameter.Template.Item1.DataSourceKey); if (_data == null) { continue; } if (_data.DataType == DataType.List) { JArray jArray = (JArray)JsonConvert.DeserializeObject(_data.Value.ToString()); try { foreach (var item in jArray) { JObject o = (JObject)item; //字号 _font = ToFont(parameter.FontStyle); //前缀 str += parameter.Template.Item1.Prefix; //变量属性 str += o[parameter.Template.Item1.Var1.Value]?.ToString(); //中间内容 str += parameter.Template.Item1.Middle; //变量属性 str += o[parameter.Template.Item1.Var2.Value]?.ToString(); //后缀内容 str += parameter.Template.Item1.Suffix; var _Liststrs = PrintStrAlign(str, _charAmount, parameter.AlignStyle, parameter.LineStyle, _font); foreach (var _itemStr in _Liststrs) { e.Graphics.DrawString(_itemStr, _font, _brush, 0, _y); _y = _y + (int)_font.Size + 7; str = ""; } } } catch { } continue; } #endregion #region 单项 if (GetDataSource(args, parameter.Template.Item1.DataSourceKey, parameter.Template.Item1.Condition.Value).ToLower().Equals("false")) { continue; } //前缀 str += parameter.Template.Item1.Prefix; //变量属性 str += GetDataSource(args, parameter.Template.Item1.DataSourceKey, parameter.Template.Item1.Var1.Value); //中间内容 str += parameter.Template.Item1.Middle; //变量属性 str += GetDataSource(args, parameter.Template.Item1.DataSourceKey, parameter.Template.Item1.Var2.Value); //后缀内容 str += parameter.Template.Item1.Suffix; //颜色 _brush = new SolidBrush(Color.Black); //字号 _font = ToFont(parameter.FontStyle); var _strs = PrintStrAlign(str, _charAmount, parameter.AlignStyle, parameter.LineStyle, _font); foreach (var item in _strs) { e.Graphics.DrawString(item, _font, _brush, 0, _y); _y = _y + (int)_font.Size + 7; } #endregion break; } case ControlType.表格模版: { var template = JSON.Deserialize(ctrls.Template); //字号 _font = ToFont(template.FontStyle); var _str = ""; if (skipjArray == null) { foreach (var cols in template.Template.Columns) { var r = template.Template.RowTemplates[cols.Index]; if (cols.Index == 0) { _str += PrintStrAlign(cols.Name, cols.Length, AlignStyle.居左, LineStyle.不填充, new Font("宋体", 10))[0]; } else { _str += PrintStrAlign(cols.Name, cols.Length, AlignStyle.居右, LineStyle.不填充, new Font("宋体", 10))[0]; } } e.Graphics.DrawString(PrintStrAlign("", _charAmount, AlignStyle.居右, LineStyle.中划线, new Font("宋体", 10))[0], new Font("宋体", 10), _brush, 0, _y); _y = _y + (int)new Font("宋体", 10).Size; e.Graphics.DrawString(_str, new Font("宋体", 10), _brush, 0, _y); _y = _y + (int)_font.Size; } var _data = args.FirstOrDefault(f => f.Key == template.Template.DataSourceKey); if (_data == null) { continue; } _str = ""; JArray jArray = null; if (skipjArray == null) { jArray = (JArray)JsonConvert.DeserializeObject(_data.Value.ToString()); e.Graphics.DrawString(PrintStrAlign("", _charAmount, AlignStyle.居右, LineStyle.中划线, new Font("宋体", 10))[0], new Font("宋体", 10), _brush, 0, _y); _y = _y + (int)new Font("宋体", 10).Size + 5; } else { jArray = skipjArray; skipjArray = null; } int skip = 0; foreach (var item in jArray) { skip++; if (e.PageSettings.PaperSize.Height < _y) { e.HasMorePages = true; skipsurface = new DesignerSurface(); skipsurface.DesignerControls = surface.DesignerControls.Skip(_skip - 1).ToList(); skipjArray = JArray.Parse(JSON.Serialize(jArray.Skip(skip))); return; } else { e.HasMorePages = false; skipsurface = null; skipjArray = null; } List _aStr = new List(); foreach (var cols in template.Template.Columns) { var r = template.Template.RowTemplates[cols.Index]; JObject o = (JObject)item; var data = o[r.Content].ToString(); if (data.Equals("合计")) { if (Global.Instance.Worker.TenantId.Equals("771188")) { _str = ""; _y = _y - ((int)_font.Size + 7); break; } } //索引等于0说明是项目名称 if (cols.Index == 0) { _aStr = PrintStrAlign(data, cols.Length, AlignStyle.居左, LineStyle.不填充, _font).ToList(); _str += _aStr[0]; } else { _str += PrintStrAlign(data, cols.Length, AlignStyle.居右, LineStyle.不填充, _font)[0]; } } e.Graphics.DrawString(_str, _font, _brush, 0, _y); _y = _y + (int)_font.Size + 7; if (!Global.Instance.GlobalConfigBoolValue(ConfigConstant.PERIPHERAL_CASHIER_CASHIER_TICKET_BEYOND_NEWLINE, false)) //项目名超出继续打印 if (_aStr.Count > 1) { for (int i = 1; i < _aStr.Count; i++) { e.Graphics.DrawString(_aStr[i], _font, _brush, 0, _y); _y = _y + (int)_font.Size + 7; } } _str = ""; } //e.Graphics.DrawString(PrintStrAlign("", _charAmount, AlignStyle.居右, LineStyle.中划线, new Font("宋体", 10))[0], new Font("宋体", 10), _brush, 0, _y = _y + (int)_font.Size + 7); } break; case ControlType.两列模版: { var parameter = JSON.Deserialize(ctrls.Template); var _left = parameter.Template.Item1; var _right = parameter.Template.Item2; //判断是否符合打印条件 var leftCondition = ParseCondition(_left.Condition, _left.DataSourceKey, args); var rightCondition = ParseCondition(_right.Condition, _right.DataSourceKey, args); if (!rightCondition || !leftCondition) { continue; } //字号 _font = ToFont(parameter.FontStyle); var _leftWi = (_charAmount * _left.Percent / 100); string _leftStr = ""; string _rightStr = ""; _leftStr += _left.Prefix; _leftStr += GetDataSource(args, _left.DataSourceKey, _left.Var1.Value); _leftStr += _left.Middle; _leftStr += GetDataSource(args, _left.DataSourceKey, _left.Var2.Value); _leftStr += _left.Suffix; _rightStr += _right.Prefix; _rightStr += GetDataSource(args, _right.DataSourceKey, _right.Var1.Value); _rightStr += _right.Middle; _rightStr += GetDataSource(args, _right.DataSourceKey, _right.Var2.Value); _rightStr += _right.Suffix; _leftStr = PrintStrAlign(_leftStr, (int)_leftWi, AlignStyle.居左, parameter.LineStyle, _font)[0]; _rightStr = PrintStrAlign(_rightStr, _charAmount - (int)_leftWi, AlignStyle.居右, parameter.LineStyle, _font)[0]; e.Graphics.DrawString(_leftStr + _rightStr, _font, _brush, 0, _y); _y = _y + (int)_font.Size + 7; } break; case ControlType.条码模版: { var parameter = JSON.Deserialize(ctrls.Template); if (parameter.Template.Item1.ShowLabel) { continue; } BarCodeXTemplate template = parameter.Template.Item1; //判断是否符合打印条件 var condition = ParseCondition(template.Condition, template.DataSourceKey, args); if (!condition) { continue; } Barcode b = new Barcode(); b.IncludeLabel = parameter.Template.Item1.ShowLabel; if (b.IncludeLabel) { b.Height = 20; } else { b.Height = 40; } b.Width = m_WinPrint.PrinterSettings.DefaultPageSettings.PaperSize.Width - 6; b.Alignment = AlignmentPositions.CENTER; var Encodestr = GetDataSource(args, parameter.Template.Item1.DataSourceKey, parameter.Template.Item1.Var1.Value); if (string.IsNullOrEmpty(Encodestr)) { return; } var _Image = b.Encode(TYPE.CODE128, Encodestr); int x = m_WinPrint.PrinterSettings.DefaultPageSettings.PaperSize.Width;//打印机默认纸张大小 e.Graphics.DrawImage(_Image, 0, _y + 15); _y = _y + _Image.Height + 10; } break; case ControlType.二维码模版: { var parameter = JSON.Deserialize(ctrls.Template); var _str = GetDataSource(args, parameter.Template.Item1.DataSourceKey, parameter.Template.Item1.Var1.Value); var condition = ParseCondition(parameter.Template.Item1.Condition, parameter.Template.Item1.DataSourceKey, args); if (!condition) { continue; } try { Bitmap bitmap = null; QRCodeGenerator.ECCLevel eccLevel = QRCodeGenerator.ECCLevel.Q; using (QRCodeGenerator qrGenerator = new QRCodeGenerator()) { using (QRCodeData qrCodeData = qrGenerator.CreateQrCode(_str, eccLevel)) { using (QRCode qrCode = new QRCode(qrCodeData)) { bitmap = qrCode.GetGraphic(6, Color.Black, Color.White, false); } } } if (bitmap != null) { int x = m_WinPrint.PrinterSettings.DefaultPageSettings.PaperSize.Width;//打印机默认纸张大小 //bitmap.Width = // e.Graphics.DrawString(_leftStr + _rightStr, _font, _brush, 0, _y = _y + (int)_font.Size + 5); var _width = x - bitmap.Width; e.Graphics.DrawImage(bitmap, (_width / 2) - 20, _y + 15); _y = _y + bitmap.Height + 10; } } catch (Exception) { } } break; case ControlType.位图模版: { var parameter = JSON.Deserialize(ctrls.Template); var condition = ParseCondition(parameter.Template.Item1.Condition, parameter.Template.Item1.Condition.Value, args); if (!condition) { continue; } var _str = GetDataSource(args, parameter.Template.Item1.DataSourceKey, parameter.Template.Item1.Var1.Value); if (!File.Exists(_str)) { continue; } int x = m_WinPrint.PrinterSettings.DefaultPageSettings.PaperSize.Width;//打印机默认纸张大小 Image img = Image.FromFile(_str); e.Graphics.DrawImage(img, 0, img.Height + 15); _y = _y + img.Height + 15; } break; default: break; } } m_Underway = false; } catch (Exception ex) { Logger.Info("-------------------------------------------" + ex.Message + "-------------------------------------------"); Logger.Error(ex); m_Underway = false; } } #endregion private static bool ParseCondition(VariableItem var, string dataSourceKey, List args) { bool result = true; //数据源参数,无论单行还是列表,数据源采用List方式,兼容单行选择集合数据源,重复行打印 var data = new List>(); //包含数据源参数,重置 if (args.Exists(x => x.Key == dataSourceKey)) { //当前数据源 var vars = args.FindLast(x => x.Key == dataSourceKey); //List集合数据 if (vars.DataType == DataType.List) { data = JSON.Deserialize>>(vars.Value.ToString()); foreach (var item in data) { if (item.Values.FirstOrDefault(f => f == "false") != null) { return false; } } } else { var row = JSON.Deserialize>(vars.Value.ToString()); data.Add(row); } } //参数中是否包含条件参数,如果包含,取值,如果不包含,忽略,继续打印 if (var != null && data.Exists(x => x.ContainsKey(var.Value))) { //取第一个值 var _value = data[0][var.Value]; if ("false".Equals(_value.ToLower())) { result = false; } } return result; } /// /// 字符对齐 /// /// 位置 /// 字符串 /// 字符总数 /// public static string[] PrintStrAlign(string str, int intLen, AlignStyle alignStyle, LineStyle lineStyle, Font font) { int fontSize = 0; switch (font.Size) { case 12: intLen = (int)(intLen / 1.1); break; case 14: intLen = (int)(intLen / 1.4); break; case 16: intLen = (int)(intLen / 1.5); break; default: break; } int tempLen = 0; int intStrLen = Encoding.Default.GetByteCount(str) + fontSize; int intOriLen = str.Length; List strs = new List(); switch (alignStyle) { case AlignStyle.居左: { if (intStrLen <= intLen) { tempLen = intLen - intStrLen + intOriLen; str = str.PadRight(tempLen < 0 ? 0 : tempLen, Convert.ToChar(DesignerUtils.GetPaddingCharByLineStyle(lineStyle))); } else { //截断标识 int truncation = 0; for (int i = 0; i < intStrLen / (intLen - fontSize); i++) { string _Bytestr = SubstringByte(str, (i * intLen) - truncation, intLen); while (_Bytestr.Contains('?')) { if (_Bytestr.Substring(_Bytestr.Length - 1, 1).Equals("?")) { _Bytestr = SubstringByte(str, (i * intLen), intLen - truncation); truncation++; continue; } if (_Bytestr.Contains('?')) { _Bytestr = _Bytestr.Replace('?',' '); } } strs.Add(_Bytestr); } strs.Add(str.Substring(strs.Sum(f => f.Length), str.Length - strs.Sum(f => f.Length)).PadRight(tempLen < 0 ? 0 : tempLen, Convert.ToChar(DesignerUtils.GetPaddingCharByLineStyle(lineStyle)))); if (intLen - Encoding.Default.GetByteCount(strs[0]) > 0) { strs[0] = strs[0].PadRight(strs[0].Length + (intLen - Encoding.Default.GetByteCount(strs[0])), ' '); } return strs.ToArray(); } } break; case AlignStyle.居中: { var diff = intLen - intStrLen; if (diff < 0) { //截断标识 int truncation = 0; for (int i = 0; i < intStrLen / intLen; i++) { string _Bytestr = SubstringByte(str, (i * intLen) - truncation, intLen); int q = 0; while (_Bytestr.Contains('?')) { if (_Bytestr.Substring(_Bytestr.Length - 1, 1).Equals("?")) { _Bytestr = SubstringByte(str, (i * intLen), intLen - truncation); truncation++; continue; } if (_Bytestr.Contains('?')) { _Bytestr = _Bytestr.Replace('?', ' '); } // _Bytestr = SubstringByte(str, i * intLen, intLen - (Encoding.Default.GetByteCount(_Bytestr) - 1)); } strs.Add(_Bytestr); } string endstr = str.Substring(strs.Sum(f => f.Length), str.Length - strs.Sum(f => f.Length)); strs.Add(string.Format("{0}{1}{2}", "".PadRight((intLen - Encoding.Default.GetByteCount(endstr)) / 2, Convert.ToChar(DesignerUtils.GetPaddingCharByLineStyle(lineStyle))), endstr, "".PadRight((intLen - Encoding.Default.GetByteCount(endstr)) / 2, Convert.ToChar(DesignerUtils.GetPaddingCharByLineStyle(lineStyle))))); return strs.ToArray(); } else { str = string.Format("{0}{1}{2}", "".PadRight((diff / 2), Convert.ToChar(DesignerUtils.GetPaddingCharByLineStyle(lineStyle))), str, "".PadRight(diff / 2, Convert.ToChar(DesignerUtils.GetPaddingCharByLineStyle(lineStyle)))); } } break; case AlignStyle.居右: { if (intStrLen <= intLen) { tempLen = intLen - intStrLen + intOriLen; str = str.PadLeft(tempLen < 0 ? 0 : tempLen, ToLineStyle(lineStyle)); } else { //截断标识 int truncation = 0; for (int i = 0; i < intStrLen / intLen; i++) { string _Bytestr = SubstringByte(str, (i * intLen) - truncation, intLen); while (_Bytestr.Contains('?')) { if (_Bytestr.Substring(_Bytestr.Length - 1, 1).Equals("?")) { _Bytestr = SubstringByte(str, (i * intLen), intLen - truncation); truncation++; continue; } if (_Bytestr.Contains('?')) { _Bytestr = _Bytestr.Replace('?', ' '); } } strs.Add(_Bytestr); } strs.Add(str.Substring(strs.Sum(f => f.Length), str.Length - strs.Sum(f => f.Length)).PadLeft(tempLen < 0 ? 0 : tempLen, ToLineStyle(lineStyle))); return strs.ToArray(); } } break; default: break; } strs.Add(str); return strs.ToArray(); } /// /// 获取空字符串 /// /// public static string GetEmptyChar(int count) { string strTemp = string.Empty; for (int i = 0; i < count; i++) { strTemp += " "; } return strTemp; } public static char ToLineStyle(LineStyle lineStyle) { switch (lineStyle) { case LineStyle.不填充: return ' '; case LineStyle.中划线: return '-'; case LineStyle.双划线: return '='; case LineStyle.星号线: return '*'; case LineStyle.井号线: return '#'; case LineStyle.加号线: return '+'; case LineStyle.下划线: return '_'; default: return ' '; } } public static Font ToFont(Printer.FontStyle _fontStyle) { Font _font = new Font("宋体", 10); switch (_fontStyle) { case Printer.FontStyle.正常字体: _font = new Font("宋体", 10); break; case Printer.FontStyle.倍宽字体: _font = new Font("宋体", 12); break; case Printer.FontStyle.倍高字体: _font = new Font("宋体", 14); break; case Printer.FontStyle.倍宽倍高: _font = new Font("宋体", 16); break; default: break; } return _font; } public static string GetDataSource(List args, string DataSourceKey, string Value) { var _data = args.FirstOrDefault(f => f.Key == DataSourceKey); if (_data == null) { return ""; } try { var _Source = JSON.Deserialize>(_data.Value.ToString()); var _dataSource = _Source.FirstOrDefault(f => f.Key == Value); if (_dataSource.Key == null) { return ""; } return _dataSource.Value?.ToString(); } catch { JArray jArray = (JArray)JsonConvert.DeserializeObject(_data.Value.ToString()); foreach (var item in jArray) { JObject o = (JObject)item; return o[Value]?.ToString(); } return ""; } finally { } } public static string GetListDataSource(List args, string DataSourceKey, string Value) { var _data = args.FirstOrDefault(f => f.Key == DataSourceKey); if (_data == null) { return ""; } JArray jArray = JArray.Parse(_data.Value.ToString()); var _Source = JSON.Deserialize>(_data.Value.ToString()); var _dataSource = _Source.FirstOrDefault(f => f.Key == Value); if (_dataSource.Key == null) { return ""; } return _dataSource.Value.ToString(); } private static Encoding _encoding = System.Text.Encoding.GetEncoding("GB2312"); //第一种方法 private static string SubstringByte(string text, int startIndex, int length) { byte[] bytes = _encoding.GetBytes(text); return _encoding.GetString(bytes, startIndex, length); } /// 转全角的函数(SBC case) /// ///任意字符串 ///全角字符串 /// ///全角空格为12288,半角空格为32 ///其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248 /// public static string ToSBC(string input) { // 半角转全角: char[] c = input.ToCharArray(); for (int i = 0; i < c.Length; i++) { if (c[i] == 32) { c[i] = (char)12288; continue; } if (c[i] < 127) c[i] = (char)(c[i] + 65248); } return new String(c); } /// /// 转半角的函数(DBC case) /// ///任意字符串 ///半角字符串 /// ///全角空格为12288,半角空格为32 ///其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248 /// public static string ToDBC(String input) { char[] c = input.ToCharArray(); for (int i = 0; i < c.Length; i++) { if (c[i] == 12288) { c[i] = (char)32; continue; } if (c[i] > 65280 && c[i] < 65375) c[i] = (char)(c[i] - 65248); } return new String(c); } } }