Graphics drawstring UTF8 Chinese Characters - c#

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.

Related

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.

Bold Font is Rendered Wrong

When I try to render a Chinese string like 试标记好不好 Graphics.DrawString draws it
even if I change the Font Linking to SimSun. On the other hand TextRenderer works but it fails to render readable strings when bold fonts are used. It seems there is no correct way to render bold strings.
The issue is described in greater detail here. Am I doing something wrong or does Windows not support professional looking localizable applications with some bold strings in the UI?
The code to repro the issue is for a Windows Forms application with two PictureBoxes:
const string combined = "测试标记好不好This is a aber long";
private void cFontSize_ValueChanged(object sender, EventArgs e)
{
Bitmap bmp = new Bitmap(750, 140);
Font f = new Font("Arial", (float)cFontSize.Value, IsBold ? FontStyle.Bold : FontStyle.Regular);
using (var g = Graphics.FromImage(bmp))
{
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
// Rendering with a Background Color solves the issue but
// this would produce boxes of white or black color in the displayed image which looks even worse
TextRenderer.DrawText(g, combined, f, new Point(0, 0), FontColor);
}
cPictureBox.Image = bmp;
Bitmap bmp2 = new Bitmap(750, 140);
using (var g = Graphics.FromImage(bmp2))
{
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
g.DrawString(combined, f, FontBrush, 0, 0);
}
cPicture2.Image = bmp2;
}
Update 1:
When I add as Font Link Setting to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink
Arial Bold
SIMSUNB.TTC,SimSun Bold
MSGOTHIC.TTC,MS UI Gothic
then Graphics.DrawString looks ok now althogh TextRender now gets problems. After restarting the application now both outputs look font wise ok although TextRenderer still has the problem that bold fonts become unreadable due to anti aliasing with black. I will restart the machine to check out any caching effects.

DrawString() seems not to work

private static Bitmap[] renders = new Bitmap[characters];
public static void initBitmaps()
{
fontWidth = TextRenderer.MeasureText("c", font).Width;
fontHeight = TextRenderer.MeasureText("c", font).Height;
for (int i=0; i<characters; i++)
{
renders[i] = new Bitmap(fontWidth, fontHeight);
using (Graphics g = Graphics.FromImage(renders[i]))
{
g.DrawString(Convert.ToChar(i + 32).ToString(), font, new SolidBrush(Color.Black), new PointF(0, 0));
}
}
}
After executing this bit of code, all bitmaps are empty (RawData are null). What am I doing wrong?
(the font in question is fixed-width, so size shouldn't be a problem)
DrawString works fine and the bitmaps aren't empty, you just can't see the text because you are drawing with a black brush on a black background.
You'll need to initialize the bitmap; use g.Clear(Color.White). Also note that you are mixing TextRenderer with Graphics.DrawString, which is a bad idea. See DrawString vs. TextRenderer for more information.
If you try proportional fonts, you are going to be disappointed how W and M will fit because you're only measuring the dimensions of lower case c which (in most fonts) would be smaller than a upper case W.

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.
}

Point of Sale Application Receipt Printing

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

Categories