How to print a text file on thermal printer using PrintDocument?
If you send a plain string to your printPage(object sender, PrintEventArgs e)
method, it will just print plain text in all the same font which looks 'messy' (as you named it)
If you want it to be printed well formatted with different fonts (bold, regular), you have to do it all manually:
List<string> itemList = new List<string>()
{
"201", //fill from somewhere in your code
"202"
};
private void printPage( object sender, PrintPageEventArgs e )
{
Graphics graphics = e.Graphics;
Font regular = new Font( FontFamily.GenericSansSerif, 10.0f, FontStyle.Regular );
Font bold = new Font( FontFamily.GenericSansSerif, 10.0f, FontStyle.Bold );
//print header
graphics.DrawString( "FERREIRA MATERIALS PARA CONSTRUCAO LTDA", bold, Brushes.Black, 20, 10 );
graphics.DrawString( "EST ENGENHEIRO MARCILAC, 116, SAO PAOLO - SP", regular, Brushes.Black, 30, 30 );
graphics.DrawString( "Telefone: (11)5921-3826", regular, Brushes.Black, 110, 50 );
graphics.DrawLine( Pens.Black, 80, 70, 320, 70 );
graphics.DrawString( "CUPOM NAO FISCAL", bold, Brushes.Black, 110, 80 );
graphics.DrawLine( Pens.Black, 80, 100, 320, 100 );
//print items
graphics.DrawString( "COD | DESCRICAO | QTY | X | Vir Unit | Vir Total |", bold, Brushes.Black, 10, 120 );
graphics.DrawLine( Pens.Black, 10, 140, 430, 140 );
for( int i = 0; i < itemList.Count; i++ )
{
graphics.DrawString( itemList[i].ToString(), regular, Brushes.Black, 20, 150 + i * 20 );
}
//print footer
//...
regular.Dispose();
bold.Dispose();
// Check to see if more pages are to be printed.
e.HasMorePages = ( itemList.Count > 20 );
}
Possible improvements on my example:
- Centering the header strings could better be done using
graphics.MeasureString()
. - List of items should better be a list of a business class insted of a plain string
Because this all is a lot of work, you should really consider using RDLC or some third party software to design your documents.
How to send cut command in Thermal Printer using PrintDocument in c#
I have tried a combination of below two code blocks
PrintDocument printDocument = new PrintDocument();
printDocument.PrintPage += PrintDocumentOnPrintPage;
printDocument.PrinterSettings.PrinterName = "TestPrinter";
printDocument.Print();
printDocument.Dispose();
and at the end, I am sending below commands it's working fine for me
string GS = Convert.ToString((char)29);
string ESC = Convert.ToString((char)27);
string documentName ="x"
string COMMAND = this.textBox.T`ext;
COMMAND = ESC + "@";
COMMAND += GS + "V" + (char)1;
RawPrinterHelper.SendStringToPrinter(this.textBox1.Text, COMMAND,documentName);
Writing nice receipt in C# WPF for printing on thermal printer POS
In the past when doing this I split up the receipt into separate parts that used different fonts or alignments such as Header, Body, Footer.
I used the following class layout to encapsulate my printed text definition.
(where you get the Font from and how you manage its lifetime is up to you)
public class PrintText
{
public PrintText(string text, Font font) : this(text, font, new StringFormat()) {}
public PrintText(string text, Font font, StringFormat stringFormat)
{
Text = text;
Font = font;
StringFormat = stringFormat;
}
public string Text { get; set; }
public Font Font { get; set; }
/// <summary> Default is horizontal string formatting </summary>
public StringFormat StringFormat { get; set; }
}
When there are longer lists of texts using the same font & padding then using a stringbuilder to build up your text makes life easy so you get a visual of how it will look just from inspecting your code.
If you had static text you can fit it all together as so:
var sb = new StringBuilder();
sb.AppendLine("Start of receipt");
sb.AppendLine("================");
sb.AppendLine("Item 1");
sb.AppendLine("Item 2");
sb.AppendLine("================");
Or if the data is a bit dynamic pass in some object you can iterate over and append your formatted text:
private class ReceiptItem
{
public string Name { get; set; }
public decimal Cost { get; set; }
public int Amount { get; set; }
public int Discount { get; set; }
public decimal Total { get { return Cost * Amount; } }
}
const int FIRST_COL_PAD = 20;
const int SECOND_COL_PAD = 7;
const int THIRD_COL_PAD = 20;
var sb = new StringBuilder();
sb.AppendLine("Start of receipt");
sb.AppendLine("================");
foreach (var item in receiptItems)
{
sb.Append(item.Name.PadRight(FIRST_COL_PAD));
var breakDown = item.Amount > 0 ? item.Amount + "x" + item.Cost : string.Empty;
sb.Append(breakDown.PadRight(SECOND_COL_PAD));
sb.AppendLine(string.Format("{0:0.00} A", item.Total).PadLeft(THIRD_COL_PAD));
if (item.Discount > 0)
{
sb.Append(string.Format("DISCOUNT {0:D2}%", item.Discount).PadRight(FIRST_COL_PAD + SECOND_COL_PAD));
sb.Append(string.Format("{0:0.00} A", -(item.Total / 100 * item.Discount)).PadLeft(THIRD_COL_PAD));
sb.AppendLine();
}
}
sb.AppendLine("================");
The output will look like:
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
================
Using the PrintText class earlier we can store our nicely formatted string builder output
var printText = new PrintText(sb.ToString(), new Font("Monospace Please...", 8));
Then finally use that when attempting to draw the string
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);
You can also play around with a few different graphical tweaks if the text doesn't print quite right such as:
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
Printing to receipt printer with PrintDocument does not print all content
Read this article on MSDN: How to: Print a Multi-Page Text File in Windows Forms.
Since your task is very similar to printing of a text file, I believe this should help.
How to print invoice in a particular format on a thermal printer
You have to manually check string length and do text wrapping.
Example:
string columnName = "...";
if(columnName.Length > 60)
{
graphic.DrawString(columnName_part1, new Font("Times New Roman", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX, startY);
startY += 50;
graphic.DrawString(columnName_part2, new Font("Times New Roman", 10, FontStyle.Bold), new SolidBrush(Color.Black), startX, startY);
}
Print raw data to a thermal-printer using .NET
Okay, the reason for all that stuff is just the fact that I use an adapter because my computer does not has an old lpt port. I copied my application to an old computer running windows xp and everything works fine.
Now I have to hope that some other lpt2usb adaters I bought do their work correctly.
Edit 20.04.2010
With another lpt2usb adapter everything works fine now. If anyone is intersted in all the code I am using now, please contact me or comment here.
Related Topics
How to Parse String with Hours Greater Than 24 to Timespan
How to Catch Exceptions from a Threadpool.Queueuserworkitem
C# Property and Ref Parameter, Why No Sugar
Canadian Postal Code Validation
Regular Expression to Get the Src of Images in C#
Uniquely Identifying Reference Types in the Debugger
Unity Eventmanager with Delegate Instead of Unityevent
How to Pass Objects into an Attribute Constructor
Server.Mappath - Physical Path Given, Virtual Path Expected
Piping in a File on the Command-Line Using System.Diagnostics.Process
How Can User Resize Control at Runtime in Winforms
C# Open File, Path Starting with %Userprofile%
Get List<> Element Position in C# Using Linq
Get All Types Implementing Specific Open Generic Type