用C#WPF书写精美收据,以便在热敏打印机POS上打印

用C#WPF书写精美收据,以便在热敏打印机POS上打印,c#,wpf,printing,C#,Wpf,Printing,我试图在我的一个项目上实现打印功能,但我在这方面的工作做得不太好 我已经连接了热敏打印机,并编写/打印了相同的样本。 现在我正试图找到一些方法来设计我的收据,使之看起来像附件中的收据 我有一些想法,但我不确定它们是否适合这类工作,其中之一是尝试将我的收据格式化为html格式,并将其呈现为类似于位图(图像)的html格式,然后将其打印出来,我已经尝试过这一点,但看起来我的质量有所下降 如果有人对我如何使收据看起来像图片上的其他想法,请与我共享此信息,我将非常感谢 这是我在打印一些示例时所做的,我使

我试图在我的一个项目上实现打印功能,但我在这方面的工作做得不太好

我已经连接了热敏打印机,并编写/打印了相同的样本。 现在我正试图找到一些方法来设计我的收据,使之看起来像附件中的收据

我有一些想法,但我不确定它们是否适合这类工作,其中之一是尝试将我的收据格式化为html格式,并将其呈现为类似于位图(图像)的html格式,然后将其打印出来,我已经尝试过这一点,但看起来我的质量有所下降

如果有人对我如何使收据看起来像图片上的其他想法,请与我共享此信息,我将非常感谢

这是我在打印一些示例时所做的,我使用了
graphics.DrawString
进行格式化,但我认为我不能用它完成太多的工作

public void Print()
{
    var doc = new PrintDocument();
    doc.PrintPage += new PrintPageEventHandler(ProvideContent);
    doc.Print();
}

public void ProvideContent(object sender, PrintPageEventArgs e)
{
    Graphics graphics = e.Graphics;
    Font font = new Font("Courier New", 10);

    float fontHeight = font.GetHeight();

    int startX = 0;
    int startY = 0;
    int Offset = 20;

    e.PageSettings.PaperSize.Width = 50;
    graphics.DrawString("Welcome to MSST", new Font("Courier New", 8),
                        new SolidBrush(Color.Black), startX, startY + Offset);
    Offset = Offset + 20;

    graphics.DrawString("Ticket No:" + "4525554654545",
                new Font("Courier New", 14),
                new SolidBrush(Color.Black), startX, startY + Offset);
    Offset = Offset + 20;


    graphics.DrawString("Ticket Date :" + "21/12/215",
                new Font("Courier New", 14),
                new SolidBrush(Color.Black), startX, startY + Offset);

    Offset = Offset + 20;
    String underLine = "------------------------------------------";

    graphics.DrawString(underLine, new Font("Courier New", 14),
                new SolidBrush(Color.Black), startX, startY + Offset);

    Offset = Offset + 20;
    String Grosstotal = "Total Amount to Pay = " + "2566";

    Offset = Offset + 20;
    underLine = "------------------------------------------";
    graphics.DrawString(underLine, new Font("Courier New", 14),
                new SolidBrush(Color.Black), startX, startY + Offset);
    Offset = Offset + 20;

    graphics.DrawString(Grosstotal, new Font("Courier New", 14),
                new SolidBrush(Color.Black), startX, startY + Offset);

}

我假设您不是在热敏打印机上打印输出,而是在普通的高分辨率位图打印机上打印输出?如果是这样的话,您的问题基本上需要生成位图/pdf或其他图形描述,然后发送到打印机。由于您提供的示例图像仅包含文本,因此您的任务只是使用坐标和字体大小来布局文本。然而,你将面临的问题是寻找正确的字体,并获得绝对正确的间距和字距等。这将是我的出发点。看看你是否能找到一种与图片中的字体相似的字体。在photoshop/gimp或类似软件中进行测试。将termal打印的照片设置为背景层,然后查看是否可以使前景保持相同。一旦你可以复制到那里,就去完成软件。从photoshop模型中选择文本坐标

在过去,当我这样做时,我会将收据分成不同的部分,使用不同的字体或对齐方式,如页眉、正文、页脚

我使用下面的类布局来封装我的打印文本定义。 (字体的来源和使用寿命由您决定)

公共类PrintText
{
公共打印文本(字符串文本,字体):此(文本,字体,新StringFormat()){}
公共打印文本(字符串文本、字体、字符串格式)
{
文本=文本;
字体=字体;
StringFormat=StringFormat;
}
公共字符串文本{get;set;}
公共字体{get;set;}
///默认设置为水平字符串格式
公共StringFormat StringFormat{get;set;}
}
当有较长的文本列表使用相同的字体和填充时,使用stringbuilder来构建文本会使您的生活变得简单,这样您就可以通过查看代码来直观地了解文本的外观

如果您有静态文本,则可以将其组合在一起:

var sb=new StringBuilder();
sb.附加行(“收货开始”);
某人加上一行(“===============================”);
sb.附录行(“第1项”);
sb.附录行(“第2项”);
某人加上一行(“===============================”);
或者,如果数据在某个对象中是位动态传递,则可以迭代并附加格式化文本:

私有类ReceiptItem
{
公共字符串名称{get;set;}
公共十进制成本{get;set;}
公共整数金额{get;set;}
公共整数折扣{get;set;}
公共十进制总数{get{返回成本*金额;}}
}
const int FIRST\u COL\u PAD=20;
第二列的常数=7;
第三列的常数=20;
var sb=新的StringBuilder();
sb.附加行(“收货开始”);
某人加上一行(“===============================”);
foreach(收据项目中的var项目)
{
sb.追加(项目名称PadRight(第一栏));
var细分=项目。金额>0?项目。金额+“x”+项目。成本:字符串。空;
某人追加(分解PadRight(第二列PAD));
sb.AppendLine(string.Format(“{0:0.00}A”,item.Total.PadLeft(THIRD_COL_PAD));
如果(项目折扣>0)
{
sb.Append(string.Format(“折扣{0:D2}%”,item.DISCOUNT).PadRight(第一列+第二列));
sb.Append(string.Format(“{0:0.00}A”,-(item.Total/100*item.Discount)).PadLeft(THIRD_COL_PAD));
(某人);
}
}
某人加上一行(“===============================”);
输出将如下所示:

Start of receipt
================
Joes Food           1x10      10.00 A
DISCOUNT 10%                  -1.00 A
Fun Facts           1x20      20.00 A
DISCOUNT 15%                  -3.00 A
Bag of Sand         7x40     280.00 A
================
使用前面的PrintText类,我们可以存储格式良好的字符串生成器输出

var printText = new PrintText(sb.ToString(), new Font("Monospace Please...", 8));
最后,在尝试绘制字符串时使用它

var layoutArea = new SizeF(AvailableWidth, 0);
SizeF stringSize = g.MeasureString(printText.Text, printText.Font, layoutArea, printText.StringFormat);

RectangleF rectf = new RectangleF(new PointF(), new SizeF(AvailableWidth, stringSize.Height));

g.DrawString(printText.Text, printText.Font, Brushes.Black, rectf, printText.StringFormat);
如果文本打印不正确,您还可以使用一些不同的图形调整,例如:

g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;

您可以将收据转换为位图图像并使用XPSDocumentGenerator类。或者使用开源库,如MigraDocs,将其转换为PDF并发送到打印机

我设计了一个简单而流畅的收据设计,希望它能对您有所帮助

public class PrintJob
{
    private PrintDocument PrintDocument;
    private Graphics graphics;
    private Order order { set; get; }
    private Shop shop { set; get; }
    private int InitialHeight = 360;
    public PrintJob(Order order, Shop shop)
    {
        this.order = order;
        this.shop = shop;
        AdjustHeight();
    }
    private void AdjustHeight()
    {
        var capacity = 5 * order.ItemTransactions.Capacity;
        InitialHeight += capacity;

        capacity = 5 * order.DealTransactions.Capacity;
        InitialHeight += capacity;
    }
    public void Print(string printername)
    {
        PrintDocument = new PrintDocument();
        PrintDocument.PrinterSettings.PrinterName = printername;

        PrintDocument.PrintPage += new PrintPageEventHandler(FormatPage);
        PrintDocument.Print();
    }
    void DrawAtStart(string text, int Offset)
    {
        int startX = 10;
        int startY = 5;
        Font minifont = new Font("Arial", 5);

        graphics.DrawString(text, minifont,
                 new SolidBrush(Color.Black), startX + 5, startY + Offset);
    }
    void InsertItem(string key, string value, int Offset)
    {
        Font minifont = new Font("Arial", 5);
        int startX = 10;
        int startY = 5;

        graphics.DrawString(key, minifont,
                     new SolidBrush(Color.Black), startX + 5, startY + Offset);

        graphics.DrawString(value, minifont,
                 new SolidBrush(Color.Black), startX + 130, startY + Offset);
    }
    void InsertHeaderStyleItem(string key, string value, int Offset)
    {
        int startX = 10;
        int startY = 5;
        Font itemfont = new Font("Arial", 6, FontStyle.Bold);

        graphics.DrawString(key, itemfont,
                     new SolidBrush(Color.Black), startX + 5, startY + Offset);

        graphics.DrawString(value, itemfont,
                 new SolidBrush(Color.Black), startX + 130, startY + Offset);
    }
    void DrawLine(string text, Font font, int Offset, int xOffset)
    {
        int startX = 10;
        int startY = 5;
        graphics.DrawString(text, font,
                 new SolidBrush(Color.Black), startX + xOffset, startY + Offset);
    }
    void DrawSimpleString(string text, Font font, int Offset, int xOffset)
    {
        int startX = 10;
        int startY = 5;
        graphics.DrawString(text, font,
                 new SolidBrush(Color.Black), startX + xOffset, startY + Offset);
    }
    private void FormatPage(object sender, PrintPageEventArgs e)
    {
        graphics = e.Graphics;
        Font minifont = new Font("Arial", 5);
        Font itemfont = new Font("Arial", 6);
        Font smallfont = new Font("Arial", 8);
        Font mediumfont = new Font("Arial", 10);
        Font largefont = new Font("Arial", 12);
        int Offset = 10;
        int smallinc = 10, mediuminc = 12, largeinc = 15;

        //Image image = Resources.logo;
        //e.Graphics.DrawImage(image, startX + 50, startY + Offset, 100, 30);

        //graphics.DrawString("Welcome to HOT AND CRISPY", smallfont,
        //      new SolidBrush(Color.Black), startX + 22, startY + Offset);

        Offset = Offset + largeinc + 10;

        String underLine = "-------------------------------------";
        DrawLine(underLine, largefont, Offset, 0);

        Offset = Offset + mediuminc;
        DrawAtStart("Invoice Number: " + order.Invoice, Offset);

        if (!String.Equals(order.Customer.Address, "N/A"))
        {
            Offset = Offset + mediuminc;
            DrawAtStart("Address: " + order.Customer.Address, Offset);
        }

        if (!String.Equals(order.Customer.Phone, "N/A"))
        {
            Offset = Offset + mediuminc;
            DrawAtStart("Phone # : " + order.Customer.Phone, Offset);
        }

        Offset = Offset + mediuminc;
        DrawAtStart("Date: " + order.Date, Offset);

        Offset = Offset + smallinc;
        underLine = "-------------------------";
        DrawLine(underLine, largefont, Offset, 30);

        Offset = Offset + largeinc;

        InsertHeaderStyleItem("Name. ", "Price. ", Offset);

        Offset = Offset + largeinc;
        foreach (var itran in order.ItemTransactions)
        {
            InsertItem(itran.Item.Name + " x " + itran.Quantity, itran.Total.CValue, Offset);
            Offset = Offset + smallinc;
        }
        foreach (var dtran in order.DealTransactions)
        {
            InsertItem(dtran.Deal.Name, dtran.Total.CValue, Offset);
            Offset = Offset + smallinc;

            foreach (var di in dtran.Deal.DealItems)
            {
                InsertItem(di.Item.Name + " x " + (dtran.Quantity * di.Quantity), "", Offset);
                Offset = Offset + smallinc;
            }
        }

        underLine = "-------------------------";
        DrawLine(underLine, largefont, Offset, 30);

        Offset = Offset + largeinc;
        InsertItem(" Net. Total: ", order.Total.CValue, Offset);

        if (!order.Cash.Discount.IsZero())
        {
            Offset = Offset + smallinc;
            InsertItem(" Discount: ", order.Cash.Discount.CValue, Offset);
        }

        Offset = Offset + smallinc;
        InsertHeaderStyleItem(" Amount Payable: ", order.GrossTotal.CValue, Offset);

        Offset = Offset + largeinc;
        String address = shop.Address;
        DrawSimpleString("Address: " + address, minifont, Offset, 15);

        Offset = Offset + smallinc;
        String number = "Tel: " + shop.Phone1 + " - OR - " + shop.Phone2;
        DrawSimpleString(number, minifont, Offset, 35);

        Offset = Offset + 7;
        underLine = "-------------------------------------";
        DrawLine(underLine, largefont, Offset, 0);

        Offset = Offset + mediuminc;
        String greetings = "Thanks for visiting us.";
        DrawSimpleString(greetings, mediumfont, Offset, 28);

        Offset = Offset + mediuminc;
        underLine = "-------------------------------------";
        DrawLine(underLine, largefont, Offset, 0);

        Offset += (2 * mediuminc);
        string tip = "TIP: -----------------------------";
        InsertItem(tip, "", Offset);

        Offset = Offset + largeinc;
        string DrawnBy = "Meganos Softwares: 0312-0459491 - OR - 0321-6228321";
        DrawSimpleString(DrawnBy, minifont, Offset, 15);
    }
}
由于我们的要求,一些用于添加图像的代码已经在这里进行了注释,您可以在标题处添加您的徽标,正如您在第二张图像中所看到的。

字体对我来说并不重要,我的目标是找到最好/最简单的方法为热敏打印机编写一个好的收件人,我遇到的问题是如何将文本格式化/排列到收件人中,比如设置纸张大小、将文本排列在纸张的左侧或右侧,等等……在您的示例中使用DrawString函数有什么问题?您在查找放置文本的正确坐标时遇到问题吗?如果是这样的话,我会尝试一下找出纸张的宽度,我认为这不是最好的方法,但如果你能证明我对此非常满意。回答这个问题可能需要一些时间,假设你只是打电话,你可以毫不费力地做到这一点。简而言之,您需要创建自己的DocumentPaginator。overrode print函数将为收据创建一个UserControl,您将打印控件的DataContext设置为某种ReceiptViewModel。令人惊讶的是,可以将生成的图像打印到收据打印机上吗?对不起,我在哪里可以下载Monosp