-->

C# ESC/POS Print Vietnamese

2020-04-10 00:09发布

问题:

I have an application which print the receipt to receipt printer using ESC/POS. It needs to support multi-languages. Currently, I've tested with Chinese characters (both traditional and simplified) and Thai language. They all are working fine.

However, when I tried to print Vietnamese, some of the characters are being replace by "?".

Here is my code:

public static readonly string ESC = "\u001B";
...
...
...
Encoding enc = Encoding.GetEncoding(1258); //vietnamese code page
string content = "Cơm chiên với các loại gia vị truyền thống làm cho lưỡi của bạn";
string toPrint = ESC + "t" + char.ConvertFromUtf32(94) + "\n" + Encoding.GetEncoding("Latin1").GetString(enc.GetBytes(str));  //code page 94 is for vietnamese (WPC1258). It is get from printer

In the print out, some of the characters has been replaced with "?" (see attached image). Any idea?

UPDATE

Base on Panagiotis Kanavos comment, I've tried the following:

Encoding enc = Encoding.GetEncoding(1258); //vietnamese code page
string content = "Cơm chiên với các loại gia vị truyền thống làm cho lưỡi của bạn";
string newStr = Encoding.GetEncoding("Latin1").GetString(enc.GetBytes(content));
string origStr = enc.GetString(Encoding.GetEncoding("Latin1").GetBytes(newStr));

The origStr contains ?. I confirm in Chinese and Thai, the origStr will be equal to content. But NOT for Vietnamese. Any idea?

UPDATE 2

I decided to Panagiotis Kanavos code which is bytesToPrint = enc.GetBytes("\x1Bt\x5E\n" + content);, but it gave me the exact same result which contains ? instead of the actual characters.

This is how I sent the content (either string or bytes) to printer.

[DllImport("Winspool.drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);

[DllImport("Winspool.drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);

[DllImport("Winspool.drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);

[DllImport("Winspool.drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)] string szPrinter, out IntPtr hPrinter, IntPtr pd);

[DllImport("Winspool.drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In, MarshalAs(UnmanagedType.LPStruct)] DOCINFOA di);

[DllImport("Winspool.drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);

[DllImport("Winspool.drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, out Int32 dwWritten);

public static bool SendBytesToPrinter(string printerName, IntPtr pBytes, int dwCount, string docName = null, string dataType = "RAW")
{
    DOCINFOA di = new DOCINFOA();
    di.pDocName = string.IsNullOrWhiteSpace(docName) ? string.Empty : docName;
    di.pDataType = string.IsNullOrWhiteSpace(dataType) ? "RAW" : dataType;

    IntPtr hPrinter = new IntPtr(0); int dwError = 0, dwWritten = 0; bool bSuccess = false;
    if (OpenPrinter(printerName.Normalize(), out hPrinter, IntPtr.Zero))
    {
        if (StartDocPrinter(hPrinter, 1, di))
        {
            if (StartPagePrinter(hPrinter))
            {
                bSuccess = WritePrinter(hPrinter, pBytes, dwCount, out dwWritten);
                EndPagePrinter(hPrinter);
            }
            EndDocPrinter(hPrinter);
        }
        ClosePrinter(hPrinter);
    }

    if (bSuccess == false)
        dwError = Marshal.GetLastWin32Error();
    return bSuccess;
}

public static bool SendBytesToPrinter(string printerName, byte[] bytes, string docName)
{
    int dwCount = bytes.Length;
    IntPtr ptrBytes = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(byte)) * bytes.Length);
    try
    {
        Marshal.Copy(bytes, 0, ptrBytes, bytes.Length);
        SendBytesToPrinter(printerName, ptrBytes, dwCount, docName);
    }
    finally { Marshal.FreeCoTaskMem(ptrBytes); }
    return true;
}

public static bool SendStringToPrinter(string printerName, string str, string docName)
{
    int dwCount = str.Length;
    IntPtr ptrBytes = Marshal.StringToCoTaskMemAnsi(str);
    try { SendBytesToPrinter(printerName, ptrBytes, dwCount, docName); }
    finally { Marshal.FreeCoTaskMem(ptrBytes); }
    return true;
}

回答1:

I found the answer! It is not my code, but limitation of CodePage 1258 (see Convert text to Latin encoding and decode back problem for Vietnamese).

The question still remains, how to print in Vietnamese?

There is a guy name HICURIN that managed to solve the problem (see Print Unicode Characters to POS printer). Hopefully, he will be kindly to share his code with us.

Cheers, Sam



回答2:

This is all you need to be able to correctly print out Vietnamese characters on your printouts using C#

edit your code to this

public static readonly string ESC = "\u001B";
...
...
...
//Encoding enc = Encoding.GetEncoding(1258); //vietnamese code page
string content = "Cơm chiên với các loại gia vị truyền thống làm cho lưỡi của bạn";
string toPrint = ESC + "t" + char.ConvertFromUtf32(94) + "\n"; 
// First you need to convert the vietnamese string to utf-8 bytes.
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(content); 
// Convert utf-8 bytes to a string.
toPrint += System.Text.Encoding.UTF8.GetString(utf8Bytes);

Try the above code and let me know if you still get funny characters...