Point of Sale Application Receipt Printing - c#

I am working on a small project for a Retail Management Software, which will be using a POS printer (I think that's what we call it). I need a create a bill for it in the end. But i am stuck here, and not able to proceed. So suppose if I generate my bill in a separate form with appropriate dimensions (of width of POS bills), will i be able to print it properly?
I am using C# and .NET 4.0 framework. I don't have much knowledge about POS devices. I am working for really a small local client which needs a basic model of software. I am also a fresher so please help me out.
If my question is not clear, let me know i will try to elaborate my thought.

I know this is an old post, but for those still looking for a solution, I can tell you what I did.
After spending many hours messing with OPOS and POS for .Net, I ended up just abandoning those and just using the built-in System.Drawing.Printing libraries. The OPOS and POS for .Net ended up being a pain to get working and ultimately didn't work as well as the built-in libraries.
I'm using an Epson TM-T20II receipt printer.
Here's some code that worked well for me.
public static void PrintReceiptForTransaction()
{
PrintDocument recordDoc = new PrintDocument();
recordDoc.DocumentName = "Customer Receipt";
recordDoc.PrintPage += new PrintPageEventHandler(ReceiptPrinter.PrintReceiptPage); // function below
recordDoc.PrintController = new StandardPrintController(); // hides status dialog popup
// Comment if debugging
PrinterSettings ps = new PrinterSettings();
ps.PrinterName = "EPSON TM-T20II Receipt";
recordDoc.PrinterSettings = ps;
recordDoc.Print();
// --------------------------------------
// Uncomment if debugging - shows dialog instead
//PrintPreviewDialog printPrvDlg = new PrintPreviewDialog();
//printPrvDlg.Document = recordDoc;
//printPrvDlg.Width = 1200;
//printPrvDlg.Height = 800;
//printPrvDlg.ShowDialog();
// --------------------------------------
recordDoc.Dispose();
}
private static void PrintReceiptPage(object sender, PrintPageEventArgs e)
{
float x = 10;
float y = 5;
float width = 270.0F; // max width I found through trial and error
float height = 0F;
Font drawFontArial12Bold = new Font("Arial", 12, FontStyle.Bold);
Font drawFontArial10Regular = new Font("Arial", 10, FontStyle.Regular);
SolidBrush drawBrush = new SolidBrush(Color.Black);
// Set format of string.
StringFormat drawFormatCenter = new StringFormat();
drawFormatCenter.Alignment = StringAlignment.Center;
StringFormat drawFormatLeft = new StringFormat();
drawFormatLeft.Alignment = StringAlignment.Near;
StringFormat drawFormatRight = new StringFormat();
drawFormatRight.Alignment = StringAlignment.Far;
// Draw string to screen.
string text = "Company Name";
e.Graphics.DrawString(text, drawFontArial12Bold, drawBrush, new RectangleF(x, y, width, height), drawFormatCenter);
y += e.Graphics.MeasureString(text, drawFontArial12Bold).Height;
text = "Address";
e.Graphics.DrawString(text, drawFontArial10Regular, drawBrush, new RectangleF(x, y, width, height), drawFormatCenter);
y += e.Graphics.MeasureString(text, drawFontArial10Regular).Height;
// ... and so on
}
Hopefully it helps someone skip all the messing around with custom drivers. :)

Well I designed a POS application (in Delphi) and altough there are many little issues with printing a receipt or a bill it´s not rocket science. I just print a receipt by simply, well, printing like any other printer, the difference is that you send lines of 30-38 characters long (depending on the printer driver, font and size). To start, you could print using 2 methods: Sending Ascii characters and sending printer commands (to set the font style, color, etc) for that specific printer or the second method is to set the font, size, etc using C# like printing to any other normal/desktop printer.
You could try printing following the example of the page and my suggestions:
http://ondotnet.com/pub/a/dotnet/2002/06/24/printing.html

Related

Converting OpenCVSharp4 Rectangle to IronOCR CropRectangle(System.Drawing.Rectangle)

I have a project in which I'm using IronOCR to read an area define by OpenCVSharp4 but the problem I'm encountering is IronOCrs CropRectangle method, it uses System.drawing.rectangle and for some reason my OpenCvSharp.Rect cannot be converted to it, by this I mean when I Finally uses IronOCRs Input.Add(Image, ContentArea) the results I get are not what is expected.
Below the code I have attached a picture of what the code currently produces.
Don't worry about IronOCR not getting the correct letters I believe it has to do with it creating a weird box and some letters getting cut off, it works if I made the area larger for crop rectangle width and height
var Ocr = new IronTesseract();
String[] splitText;
using (var Input = new OcrInput())
{
//OpenCv
OpenCvSharp.Rect rect = new OpenCvSharp.Rect(55, 107, 219, 264);
//IronOCR
Rectangle ContentArea = new Rectangle() { X = rect.TopLeft.X, Y = rect.TopLeft.Y, Height = rect.Height, Width = rect.Width };
CropRectangle r = new CropRectangle(ContentArea);
CordBox.Text = r.Rectangle.ToString();
//OpenCv
resizedMat.Rectangle(rect.TopLeft, rect.BottomRight, Scalar.Blue, 3);
resizedMat.Rectangle(new OpenCvSharp.Point(55, 107), new OpenCvSharp.Point(219, 264), Scalar.Brown, 3);
Cv2.ImShow("resizedMat", resizedMat);
//IronOCR
Input.Add(#"C:\Projects\AnExperiment\WpfApp1\Images\TestSave.PNG", r);
Input.EnhanceResolution();
var Result = Ocr.Read(Input);
ResultBox.Text = Result.Text;
splitText = ResultBox.Text.Split('\n');
}
SO here is the solution I came up with.
This problem is a OpenCvSharp4 one where OpenCvSharp4.Rectangle for some reason does have matching coordinates to System.Drawing.Rectangle. I have posted this on the gitHub for OpenCvSHarp4 and he says its fine, but its not.
So I switched over to Emgu NuGet package its better for C# applications and is a OpenCv Wrapper made for C# (I was just scared of giving it a try before because i never really understood it.)
Emgu uses System.Drawing.Rectangle by default instead of something like OpenCvSharp4.Rectangle so everything matches up nicely.
Mat testMat = new Mat();
System.Drawing.Rectangle roi = CvInvoke.SelectROI("main", testMat );
After finding this out the rest was pretty easy so the final code is below on how it was transformed. (For reference Emgu.CV.CVInvoke is how its called and Emgu.CV.BitmapExtension is its own separate NuGet package)
// Get the original Image
fullPage = CvInvoke.Imread(#"C:\Projects\AnExperiment\WpfApp1\Images\TestImageFinalFilled.png");
// Resize it so it works with the cordinates stored previously in a json file
CvInvoke.Resize(fullPage, resizedMat, EmguSetResolution(fullPage, dpi));
// Save the small version so iron ocr doesnt mess up
var bitmap = Emgu.CV.BitmapExtension.ToBitmap(resizedMat);
bitmap.Save(#"C:\Projects\AnExperiment\WpfApp1\Images\Test.PNG");
// Let user select box
System.Drawing.Rectangle roi = CvInvoke.SelectROI("main", resizedMat);
CvInvoke.DestroyWindow("main");
// Draw Rect for debugging
CvInvoke.Rectangle(resizedMat, roi, new MCvScalar(0, 0, 255), 2);
// Read section we highlighted by pulling the saved resuze imag as a reference
var Ocr = new IronTesseract();
IronOcr.OcrResult ocrResult;
Ocr.UseCustomTesseractLanguageFile(#"C:\Projects\AnExperiment\WpfApp1\tessdata_best-main\eng.traineddata");
using (var Input = new OcrInput())
{
CvInvoke.Rectangle(resizedMat, roi, new MCvScalar(0, 0, 255), 2);
IronOcr.CropRectangle contentArea = new CropRectangle(roi);
Input.AddImage(#"C:\Projects\AnExperiment\WpfApp1\Images\Test.PNG", contentArea);
Input.EnhanceResolution();
Input.Sharpen();
Input.Contrast();
ocrResult = Ocr.Read(Input);
}
File.Delete(#"C:\Projects\AnExperiment\WpfApp1\Images\Test.PNG");
CvInvoke.Imshow("m", resizedMat);
After all this I have some functions that spit the ocrResult.Text into the textbox and separate certain things I needed from it.

Graphics drawstring UTF8 Chinese Characters

Preface: We sell machines that tell you the quality of the air. We have a touch screen display that we recently upgraded to support Chinese. I wrote a C# application that connects to the device serially and attempts to draw the screen so users can connect to their device remotely and control it. This works great until you put the device into Chinese, then my C# app draws all the symbols as their ASCII equivalent (not Chinese symbols).
I use the Graphics library to do all my drawing, in which I call the DrawString method to draw text on the screen. I have a picturebox in which I am doing the graphics drawing on. How do I draw the Chinese correctly?
Code:
private Bitmap image;
private Color gForeColor;
private Color gBackColor;
private Font gFont;
private int gTextsize;
private int gLineSize;
private StringFormat gTextAlign;
private void Initialize()
{
gForeColor = Color.Black;
gTextsize = 14;
gLineSize = 1;
gFont = new Font("Microsoft Sans Serif", gTextsize, FontStyle.Regular);
gTextAlign = new StringFormat();
gTextAlign.LineAlignment = StringAlignment.Center;
gTextAlign.Alignment = StringAlignment.Near;
gTextAlign.FormatFlags = StringFormatFlags.MeasureTrailingSpaces;
image = new Bitmap(pictureBox1.ClientSize.Width, pictureBox1.ClientSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
}
private void DrawText(string Text, int X1, int Y1)
{
using (Graphics g = Graphics.FromImage(image))
{
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
SolidBrush sb = new SolidBrush(gForeColor); //Foreground
SolidBrush bb = new SolidBrush(gBackColor); //Background
g.DrawString(Text, gFont, sb, X1, Y1, gTextAlign);
pictureBox1.Invalidate(); //refresh
gTextAlign.Alignment = StringAlignment.Near; //horizontal alignment reverts to Left after a text display command is issued
}
}
I tried adding this line
Text = Encoding.UTF8.GetString(Encoding.Default.GetBytes(Text)); To try and decode the text properly but now it prints '??????' instead of the ASCII letters or Chinese symbols.
Example:
English
Chinese
Edit: It seems the ReadExisting() from the SerialPort was converting all the bytes into '??????'. I stopped using ReadExisting and switched to Read which keeps the raw bytes. So now I'm getting the correct ASCII, but still not Chinese. I re-added my line Text = Encoding.UTF8.GetString(Encoding.Default.GetBytes(Text)); and now I'm getting Chinese with some extra symbols that aren't correct. Am I using the wrong encoding?
Are you sure, that you can use Microsoft Sans Serif with Chinese? I highly doubt.

Some Unicode characters are not drawn using DrawString method

This is one of the strange behavior of csharp code under my testing.
I use DrawString method to draw some unicode character under Times New Roman Font. However, I can draw some characters and but some characters are just drawn as blank square (i.e. unsupported character.
To elaborate more, I can draw 42 (*) and 43 (+) without any problem using DrawString method.
But I can not draw 9978 and 9900. Both 9978 and 9900 are the supported characters by Times New Roman. Check the font map here.
https://www.martinstoeckli.ch/fontmap/fontmap.html
For your information, when I try to print the same characters in the text box window control, everything works fine. Textbox show all the supported characters including 9978 and 9900.
However, just this DrawString method is inconsistent under my testing. Why I can not draw these supported characters under the font using DrawString method ?
int unicodeIndex = 10728;
this._provider = new CultureInfo("en-us");
string unicodeString = ((char)unicodeIndex).ToString(_provider);
this.Font = new Font("Times New Roman", 10);
int x = 200;
int y = 200;
SizeF sizef = g.MeasureString(unicodeString+"W", this.Font, new PointF(x, y), _sformat);
int w = Convert.ToInt32(sizef.Width) + 2;
int h = Convert.ToInt32(sizef.Height) + 2;
RectangleF rectf = new RectangleF(x, y-h/2, w, h);
g.DrawString(unicodeString, this.Font, myBrush, rectf, myFormat);
Some more clue here as this seems tough problem.
I am currently using East Asian Language pack installed on my Window.
Is there any possibility that East Asian Language pack installed on my window can cause this problem ? For example, in localized window with Chinese and Japanese language, "Times New Roman" font might be not called correctly ? Just guess though.
I changed your code a bit and It's working well now:
private void Form1_Paint(object sender, PaintEventArgs g)
{
CultureInfo _provider = new CultureInfo("en-us");
String drawString = ((char)9900).ToString(_provider);
Font drawFont = new Font("Times New Roman", 16);
SolidBrush drawBrush = new SolidBrush(Color.Black);
float x = 150.0F;
float y = 50.0F;
StringFormat drawFormat = new StringFormat();
g.Graphics.DrawString(drawString, drawFont, drawBrush, x, y, drawFormat);
}
Times New Roman (any version, I'm quite sure) actually does not have the characters in question.
The second sentence on https://www.martinstoeckli.ch/fontmap/fontmap.html says:
What you see on this page is all declared as font Arial, though the operating system and the browser can substitute missing characters with characters from other fonts.
What you're seeing on that webpage is font substitution.

Graphis.DrawString always uses the default font

I have a project in which I create an image with rotated text around an invisible circle.
The drawing in itself is working just fine. However, it seems that no matter the font I use, I always get the same result, which is I assume some low quality default font.
Here is the code :
Bitmap objBmpImage = new Bitmap(1000, 1000);
System.Drawing.Text.InstalledFontCollection installedFontCollection = new System.Drawing.Text.InstalledFontCollection();
FontFamily[] fontFamilies = installedFontCollection.Families;
System.Drawing.Font objFont = new System.Drawing.Font(fontFamilies.Where(x => x.Name == "Arial").FirstOrDefault(),10);
Graphics objGraphics = Graphics.FromImage(objBmpImage);
objGraphics.Clear(Color.Transparent);
float angle = (float)360.0 / (float)competences.Count();
objGraphics.TranslateTransform(500, 450);
objGraphics.RotateTransform(-90 - (angle / 3));
int nbComptetence = competences.Count();
int indexCompetence = 0;
foreach (T_Ref_Competence competence in competences)
{
byte r, g, b;
HexToInt(competence.T_Ref_CompetenceNiveau2.T_Ref_CompetenceNiveau1.Couleur, out r, out g, out b);
Brush brush = new System.Drawing.SolidBrush(Color.FromArgb(255,r,g,b));
if (indexCompetence * 2 < nbComptetence)
{
objGraphics.DrawString(competence.Nom, objFont, brush, 255, 0);
objGraphics.RotateTransform(angle);
}
else
{
objGraphics.RotateTransform(180);
objGraphics.RotateTransform(angle/2);
float textSize = objGraphics.MeasureString(competence.Nom, objFont).Width;
objGraphics.DrawString(competence.Nom, objFont, brush, -253 - textSize, 0);
objGraphics.RotateTransform(angle);
objGraphics.RotateTransform(-180);
objGraphics.RotateTransform(-angle / 2);
}
indexCompetence++;
}
I get the font using the installed families like this
System.Drawing.Text.InstalledFontCollection installedFontCollection = new System.Drawing.Text.InstalledFontCollection();
FontFamily[] fontFamilies = installedFontCollection.Families;
System.Drawing.Font objFont = new System.Drawing.Font(fontFamilies.Where(x => x.Name == "Arial").FirstOrDefault(),10);
I tried using other font but the result is always the same. Is there anything I am missing ? If not, what could be the reason ?
Thanks,
EDIT : To answer the question, what is it that I want exactly, consider this :
This image is a screenshot of a web site I am making. The chart in the middle was generated using charts.js, but its limitation force me to draw the text as a background image. It actually takes most of my screen so it can't really get much bigger than this. As you can see, the text font is pretty blurry and I would simply want it to be easier to read. I though the font was the problem, but I don't really know.
I am not really familiar with the whole image drawing part of C#, so if there are is better way to draw my text (which can change depending of many variables), I will gladly try other things.
Option 1: change text rendering
objGraphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixel
Option 2: change the mode of anti aliasing
objGraphics.InterpolationMode=InterpolationMode.NearestNeighbor;
Option 3: change the DPI of the image
You'll get the best result if you scale the input image and then draw the text in higher DPI.
The default DPI for a Bitmap are 96. Probably the JS library exported with that setting.
If you want a smoother rendering of the font, you need to increase the DPI, e.g.
objBmpImage.SetResolution(1200,1200);
If you do so, you probably need to increase the number of pixels your Bitmap has.
If the "ugly" text just fitted the 1000x1000 picture, you now need 1000*1200/96=12500 pixels.
Before the change (using Arial 10 pt):
After the change (still using Arial 10 pt):
Note that the size in centimeters doesn't change. So it will still print well.

Generate barcode with Free 3 of 9 font

public Bitmap CreateBarcode(string data)
{
data = "55536";
string barcodeData = "*" + data + "*";
Bitmap barcode = new Bitmap(1, 1);
Font threeOfNine = new Font("Free 3 of 9 Extended", 31, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
Font arial = new Font("Arial", 13,
System.Drawing.FontStyle.Regular,
System.Drawing.GraphicsUnit.Point);
Graphics graphics = Graphics.FromImage(barcode);
SizeF dataSize = graphics.MeasureString(barcodeData, threeOfNine);
dataSize.Height = 70;
barcode = new Bitmap(barcode, dataSize.ToSize());
graphics = Graphics.FromImage(barcode);
graphics.Clear(Color.White);
graphics.TextRenderingHint = TextRenderingHint.SingleBitPerPixel;
graphics.DrawString(barcodeData, threeOfNine, new SolidBrush(Color.Black), 0, 0);
graphics.DrawString(data, arial, new SolidBrush(Color.Black), 50, 40);
graphics.Flush();
threeOfNine.Dispose();
graphics.Dispose();
return barcode;
}
I generate barcode with the above code, but my scanner can not read the barcode generated (for 55536).
BUT if I switch the data value to "1111" or "2222", then the barcode be read very well.
so I think it is not a scanner problem, anybody know, what's the wrong with that code?
please advice.
If you are using only numbers, you could try the 3 of 9 basic font (without the extended). Print the same barcode from Write and compare them to see if your solution is building the complete barcode or if it is getting truncated.
1.If you're using the supported characters surrounded by the "*" stop and start characters, chances are the problem is either the size of the barcode or the resolution of the printing.
2.Make sure that the size of each character is the same font size. Mixed sizes will not work.
3.When experimenting with changing the color of the bars, remember that darker colors are better. Pastels are not so good. Red is a no-no.
Here's a reference for you: asp.net barcode generator using 3 of 9 font.
try to prefix and suffix :
why are you passing the data within the
public Bitmap CreateBarcode(string data)
{
data="55536"; //dont pass the data from here pass it from outside method for eg. call it from the button click or whatever control you are using.
}

Categories