ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

C# 收银机打印

2021-08-17 21:31:43  阅读:270  来源: 互联网

标签:printer 收银机 C# PrintText 打印 paperWidth StringAlignment new NewLine


前两天领导说不用web端的打印插件(C-Lodop),想用C#来实现,让我研究一下调用打印机的方法,就有了这篇总结

.NET Core或.NET 5的话要引用一下NuGet包 System.Drawing.Common

获取打印机列表

PrinterSettings.InstalledPrinters.Cast<string>();

定义打印接口

public interface IPrinter
{
  /// <summary>
  /// 设置页面大小
  /// </summary>
  /// <param name="paperWidth"></param>
  /// <param name="paperHight"></param>
  void SetPageSize(double paperWidth, int? paperHight);

  /// <summary>
  /// 打印文字
  /// </summary>
  /// <param name="content"></param>
  /// <param name="fontSize"></param>
  /// <param name="stringAlignment"></param>
  /// <param name="width"></param>
  /// <param name="offset"></param>
  void PrintText(
      string content,
      FontSize fontSize = FontSize.Normal,
      StringAlignment stringAlignment = StringAlignment.Near,
      float width = 1,
      float offset = 0
      );

  /// <summary>
  /// 打印图片
  /// </summary>
  /// <param name="image"></param>
  /// <param name="stringAlignment"></param>
  void PrintImage(Image image, StringAlignment stringAlignment = StringAlignment.Near);

  /// <summary>
  /// 打印一行
  /// </summary>
  void PrintSolidLine();

  /// <summary>
  /// 打印一行虚线
  /// </summary>
  /// <param name="fontSize"></param>
  void PrintDottedLine();

  /// <summary>
  /// 新起一行
  /// </summary>
  void NewLine();

  /// <summary>
  /// 开始打印
  /// </summary>
  void Print();
}

打印接口的实现

public class Printer : IPrinter
    {

        #region fields
        private PrintDocument _printDoc = new PrintDocument();

        /// <summary>
        /// 打印对象打印宽度(根据英寸换算而来,paperWidth * 3.937)
        /// </summary>
        private int _paperWidth;
        private int _paperHight;
        private const float _charProportion = 0.7352f;
        private const float _lineHeightProportion = 1.6f;
        private const string _fontName = "SimHei";
        private int _printIndex = 0;
        /// <summary>
        /// 打印模式:1、自动分页模式  2、连续不分页模式
        /// </summary>
        private int _mode;
        private IList<Action<Graphics>> _printActions = new List<Action<Graphics>>();

        /// <summary>
        /// 当前的打印高度,当调用换行或者图片打印时会增加此字段值
        /// </summary>
        private float _currentHeight = 0;

        public float NewLineOffset { get; set; } = (int)FontSize.Normal * _lineHeightProportion;

        #endregion

        #region ctor

        /// <summary>
        /// 初始化机打印对象
        /// </summary>
        /// <param name="printerName">打印机名称</param>
        /// <param name="paperWidth">打印纸宽度</param>
        /// <param name="paperHight">打印纸高度</param>
        internal Printer(string printerName)
        {
            _printDoc.PrinterSettings.PrinterName = printerName;
            _printDoc.PrintPage += PrintPageDetails;

            //默认为58mm
            SetPageSize(58, null);            

            _printDoc.PrintController = new StandardPrintController();
        }


        #endregion

        #region eventHandler
        void PrintPageDetails(object sender, PrintPageEventArgs e)
        {
            while (_printIndex < _printActions.Count)
            {
                var originHeight = _currentHeight;
                _printActions[_printIndex](e.Graphics);
                _printIndex++;
                if (_currentHeight > e.PageBounds.Height - 20)
                {
                    if (_mode == 1)
                    {
                        _currentHeight = 0;
                        // HasMorePages 设置为true后,会继续触发PrintPage,因此_printIndex需要在外部进行定义
                        e.HasMorePages = true;
                        return;
                    }
                }
            }

            e.HasMorePages = false;
        }
        #endregion

        #region IPrinterImplement

        /// <summary>
        /// 设置页面大小
        /// </summary>
        /// <param name="paperWidth"></param>
        /// <param name="paperHight"></param>
        public void SetPageSize(double paperWidth, int? paperHight)
        {
            switch (paperWidth)
            {
                case 80:
                    //80打印纸扣去两边内距实际可打的宽度为72.1
                    paperWidth = 72.1;
                    break;
                case 76:
                    //76打印纸扣去两边内距实际可打的宽度为63.5
                    paperWidth = 63.5;
                    break;
                case 58:
                    //58打印纸扣去两边内距实际可打的宽度为48
                    paperWidth = 48;
                    break;
                default:
                    paperWidth = paperWidth - 10;
                    break;
            }

            _paperWidth = Convert.ToInt32(Math.Ceiling(paperWidth * 3.937));
            _mode = 1;
            if (!paperHight.HasValue)
            {
                paperHight = 297;
                _mode = 2; // 设置为连续不分页模式
            }

            _paperHight = Convert.ToInt32(Math.Ceiling(paperHight.Value * 3.937));
            _printDoc.DefaultPageSettings.PaperSize = new PaperSize("", _paperWidth, _paperHight);
        }

        /// <summary>
        /// 开始打印
        /// </summary>
        public void Print()
        {
            _printIndex = 0;
            _currentHeight = 0;
            _printDoc.EndPrint += (_, _) => Console.WriteLine("打印完成!");
            if (_mode == 2)
            {
                // 通过下面的方式计算出实际页面高度
                using (Bitmap img = new Bitmap(_paperWidth, _paperHight))
                {
                    var g = Graphics.FromImage(img);
                    foreach (var item in _printActions)
                    {
                        item(g);
                    }
                    _paperHight = Convert.ToInt32(Math.Ceiling(_currentHeight)) + 5;
                    _printDoc.DefaultPageSettings.PaperSize = new PaperSize("", _paperWidth, _paperHight);
                    _printIndex = 0;
                    _currentHeight = 0;
                }
            }
            _printDoc.Print();
            _printDoc.Dispose();
            _printDoc = new PrintDocument();
            _printActions.Clear();
        }

        /// <summary>
        /// 新起一行
        /// </summary>
        public void NewLine()
        {
            _printActions.Add(g =>
            {
                _currentHeight += NewLineOffset;
                NewLineOffset = (int)FontSize.Normal * _lineHeightProportion;
            });
        }

        /// <summary>
        /// 打印文字
        /// </summary>
        /// <param name="content"></param>
        /// <param name="fontSize"></param>
        /// <param name="alignment"></param>
        /// <param name="width"></param>
        /// <param name="offset"></param>
        public void PrintText(string content, FontSize fontSize = FontSize.Normal, StringAlignment alignment = StringAlignment.Near, float width = 1, float offset = 0)
        {
            _printActions.Add(g =>
            {
                float contentWidth = width == 1 ? _paperWidth * (1 - offset) : width * _paperWidth;
                string newContent = ContentWarp(content, fontSize, contentWidth, out var rowNum);
                var font = new Font(_fontName, (int)fontSize, FontStyle.Regular);
                var point = new PointF(offset * _paperWidth, _currentHeight);
                var size = new SizeF(contentWidth, (int)fontSize * _lineHeightProportion * rowNum);
                var layoutRectangle = new RectangleF(point, size);
                var format = new StringFormat
                {
                    Alignment = alignment,
                    FormatFlags = StringFormatFlags.NoWrap
                };
                g.DrawString(newContent, font, Brushes.Black, layoutRectangle, format);
                float thisHeightOffset = rowNum * (int)fontSize * _lineHeightProportion;
                if (thisHeightOffset > NewLineOffset) NewLineOffset = thisHeightOffset;
            });
        }

        /// <summary>
        /// 打印图片
        /// </summary>
        /// <param name="image"></param>
        /// <param name="stringAlignment"></param>
        public void PrintImage(Image image, StringAlignment stringAlignment = StringAlignment.Near)
        {
            _printActions.Add(g =>
            {
                int x = 0;
                switch (stringAlignment)
                {
                    case StringAlignment.Near:
                        break;
                    case StringAlignment.Center:
                        x = (_paperWidth - image.Width) / 2;
                        break;
                    case StringAlignment.Far:
                        x = _paperWidth - image.Width;
                        break;
                    default:
                        break;
                }
                var point = new Point(x, Convert.ToInt32(_currentHeight));
                var size = new Size(image.Width, image.Height);
                var rectangle = new Rectangle(point, size);
                g.DrawImage(image, rectangle);
                NewLineOffset = image.Height;
            });
        }

        /// <summary>
        /// 打印一行实线
        /// </summary>
        public void PrintSolidLine()
        {
            _printActions.Add(g =>
            {
                var pen = new Pen(new SolidBrush(Color.Black));
                pen.Width = 1f;
                g.DrawLine(pen, new Point(0, Convert.ToInt32(Math.Ceiling(_currentHeight))), new Point(_paperWidth, Convert.ToInt32(Math.Ceiling(_currentHeight))));
                _currentHeight += 3;
            });
        }

        /// <summary>
        /// 打印一行虚线
        /// </summary>
        public void PrintDottedLine()
        {
            var fontSize = FontSize.Normal;
            int charNum = (int)(_paperWidth / ((int)fontSize * _charProportion));
            var builder = new StringBuilder();
            for (int i = 0; i < charNum; i++)
            {
                builder.Append('-');
            }
            PrintText(builder.ToString(), fontSize, StringAlignment.Center);
        }
        #endregion

        #region methods
        /// <summary>
        /// 对内容进行分行,并返回行数
        /// </summary>
        /// <param name="content">内容</param>
        /// <param name="fontSize">文字大小</param>
        /// <param name="width">内容区宽度</param>
        /// <returns>行数</returns>
        private static string ContentWarp(string content, FontSize fontSize, float width, out int row)
        {
            content = content.Replace(Environment.NewLine, string.Empty);

            //0.7282 字符比例
            var builder = new StringBuilder();
            float nowWidth = 0;
            row = 1;
            foreach (char item in content)
            {
                int code = Convert.ToInt32(item);
                float charWidth = code < 128 ? _charProportion * (int)fontSize : _charProportion * (int)fontSize * 2;
                nowWidth += charWidth;
                if (nowWidth > width)
                {
                    builder.Append(Environment.NewLine);
                    nowWidth = charWidth;
                    row++;
                }
                builder.Append(item);
            }
            return builder.ToString();
        }

        #endregion
    }

创建打印机的工厂类

public static class PrinterFactory
{
    public static IEnumerable<string> GetAllPrints()
    {
        return PrinterSettings.InstalledPrinters.Cast<string>();
    }

    public static Printer GetPrinter(string printerName)
    {
        if (string.IsNullOrEmpty(printerName)) throw new ArgumentException(nameof(printerName));
        return new Printer(printerName);
    }
}

使用

static void Main(string[] args)
{
    // Microsoft XPS Document Writer 是测试时使用的,实际使用中,要替换成真正的打印机
    var printer = PrinterFactory.GetPrinter("Microsoft XPS Document Writer");
    printer.SetPageSize(80, null);
    printer.NewLine();
    var img = GetLogo();
    printer.PrintImage(img, StringAlignment.Center);
    printer.NewLine();
    printer.NewLine();
    printer.PrintText("永辉超市", FontSize.Large, alignment: StringAlignment.Center);
    printer.NewLine();
    printer.NewLine();
    printer.PrintText("单号:XD000269");
    printer.PrintText("流水号:000269", offset: 0.5f);
    printer.NewLine();
    printer.PrintText("收银员:***");
    printer.PrintText("日期:" + DateTime.Now.ToString("yyyy/MM/dd"), offset: 0.5f);
    printer.NewLine();
    printer.PrintText("VIP客户卡号:001");
    printer.NewLine();
    printer.PrintSolidLine();
    printer.NewLine();
    printer.PrintText("名称");
    printer.PrintText("单价", offset: 0.35f);
    printer.PrintText("数量", offset: 0.65f);
    printer.PrintText("金额", alignment: StringAlignment.Far);
    printer.NewLine();
    printer.PrintText("芹菜", width: 0.35f);
    printer.PrintText("2.9", width: 0.2f, offset: 0.35f);
    printer.PrintText("1", width: 0.2f, offset: 0.65F);
    printer.PrintText("2.9", alignment: StringAlignment.Far);
    printer.NewLine();
    printer.PrintDottedLine();
    printer.NewLine();
    printer.PrintText("合计");
    printer.PrintText("1", offset: 0.65f);
    printer.PrintText("2.90", alignment: StringAlignment.Far);
    printer.NewLine();
    printer.PrintText("满0.00减0.00折扣");
    printer.PrintText("-0.00", alignment: StringAlignment.Far);
    printer.NewLine();
    printer.PrintText("优惠金额:2.90");
    printer.PrintText("实收金额:0", offset: 0.5f);
    printer.NewLine();
    printer.PrintText("收款金额:0.00");
    printer.PrintText("找零金额:-2.90", offset: 0.5f);
    printer.NewLine();
    printer.PrintDottedLine();
    printer.NewLine();
    printer.PrintText("会员卡:001");
    printer.NewLine();
    printer.PrintText("本次积分:");
    printer.PrintText("会员余额:43.87", offset: 0.5f);
    printer.NewLine();
    printer.PrintText("可用积分:");
    printer.NewLine();
    printer.PrintSolidLine();
    printer.NewLine();
    printer.PrintText("永辉超市", FontSize.Large, alignment: StringAlignment.Center);
    printer.NewLine();
    printer.PrintText("欢迎光临,谢谢惠顾!", FontSize.Large, alignment: StringAlignment.Center);
    printer.NewLine();

    printer.Print();
    GC.Collect();
    
    Console.ReadKey();
}

private static Image GetLogo()
{
    var path = Path.Combine(Directory.GetCurrentDirectory(), "logo.jpg");
    using (var fileStream = File.OpenRead(path))
    {
        fileStream.Seek(0, SeekOrigin.Begin);
        return Image.FromStream(fileStream);
    }
}

效果如下

demo已上传至 github

标签:printer,收银机,C#,PrintText,打印,paperWidth,StringAlignment,new,NewLine
来源: https://www.cnblogs.com/JolyneStone/p/15154285.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有