0

I am trying to print cyrillic letters on my thermal printer but i am unable to do with this example,

This code works well with latin letters, but as soon as i change to cyrillic, it prints only "????"

Also when i change 'Encoding.ASCII' to 'Encoding.Unicode' or 'Encoding.Utf8', it prints some random characters.

Note: Thermal printer prints cyrillic when i print from word document

Encoding e1 = Encoding.GetEncoding(1251);
PrinterUtility.EscPosEpsonCommands.EscPosEpson obj = new PrinterUtility.EscPosEpsonCommands.EscPosEpson();                 

var BytesValue = e1.GetBytes(string.Empty);
BytesValue = PrintExtensions.AddBytes(BytesValue, obj.CharSize.Nomarl());

BytesValue = PrintExtensions.AddBytes(BytesValue, obj.Alignment.Center());
BytesValue = PrintExtensions.AddBytes(BytesValue, obj.Separator());
BytesValue = PrintExtensions.AddBytes(BytesValue, obj.Alignment.Center());
BytesValue = PrintExtensions.AddBytes(BytesValue, obj.CharSize.DoubleWidth3());
BytesValue = PrintExtensions.AddBytes(BytesValue, e1.GetBytes("This works"));
BytesValue = PrintExtensions.AddBytes(BytesValue, obj.CharSize.Nomarl());
BytesValue = PrintExtensions.AddBytes(BytesValue, e1.GetBytes("Ћирилица\n"));
BytesValue = PrintExtensions.AddBytes(BytesValue, obj.Separator());
BytesValue = PrintExtensions.AddBytes(BytesValue, e1.GetBytes("This -> љњертзуиопшасдфгхјклчѕџцвбнм work now\n"));
BytesValue = PrintExtensions.AddBytes(BytesValue, obj.Alignment.Left());
BytesValue = PrintExtensions.AddBytes(BytesValue, e1.GetBytes("Ћирилица\n"));
BytesValue = PrintExtensions.AddBytes(BytesValue, e1.GetBytes("Ћирилица\n"));
BytesValue = PrintExtensions.AddBytes(BytesValue, obj.Separator());
BytesValue = PrintExtensions.AddBytes(BytesValue, obj.Alignment.Center());
BytesValue = PrintExtensions.AddBytes(BytesValue, obj.BarCode.Code128(barcode));
BytesValue = PrintExtensions.AddBytes(BytesValue, obj.Separator());
BytesValue = PrintExtensions.AddBytes(BytesValue, obj.CharSize.DoubleHeight3());
BytesValue = PrintExtensions.AddBytes(BytesValue, e1.GetBytes("-------------------Ћирилица-------------------\n"));
BytesValue = PrintExtensions.AddBytes(BytesValue, obj.Alignment.Left());
BytesValue = PrintExtensions.AddBytes(BytesValue, CutPage());

if (File.Exists(".\\tmpPrint.print"))
    File.Delete(".\\tmpPrint.print");

File.WriteAllBytes(".\\tmpPrint.print", BytesValue);

RawPrinterHelper.SendFileToPrinter("BIXOLON SRP-350III", ".\\tmpPrint.print");

try
{
    File.Delete(".\\tmpPrint.print");
}
catch
{
}

public class RawPrinterHelper
{
    // Structure and API declarations:
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    public class DOCINFOA
    {
        [MarshalAs(UnmanagedType.LPStr)]
        public string pDocName;
        [MarshalAs(UnmanagedType.LPStr)]
        public string pOutputFile;
        [MarshalAs(UnmanagedType.LPStr)]
        public string pDataType;
    }

    [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, ref IntPtr hPrinter, IntPtr pd);

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

    [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 = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool EndDocPrinter(IntPtr hPrinter);

    [DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool StartPagePrinter(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 = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
    public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, ref Int32 dwWritten);

    // SendBytesToPrinter()
    // When the function is given a printer name and an unmanaged array
    // of bytes, the function sends those bytes to the print queue.
    // Returns true on success, false on failure.
    public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount)
    {
        Int32 dwError = 0;
        Int32 dwWritten = 0;
        IntPtr hPrinter = new IntPtr(0);
        DOCINFOA di = new DOCINFOA();
        bool bSuccess = false;
        // Assume failure unless you specifically succeed.
        di.pDocName = "My C#.NET RAW Document";
        di.pDataType = "RAW";

        // Open the printer.
        if (OpenPrinter(szPrinterName.Normalize(), ref hPrinter, IntPtr.Zero))
        {
            // Start a document.
            if (StartDocPrinter(hPrinter, 1, di))
            {
                // Start a page.
                if (StartPagePrinter(hPrinter))
                {
                    // Write your bytes.
                    bSuccess = WritePrinter(hPrinter, pBytes, dwCount, ref dwWritten);
                    EndPagePrinter(hPrinter);
                }
                EndDocPrinter(hPrinter);
            }
            ClosePrinter(hPrinter);
        }

        // If you did not succeed, GetLastError may give more information
        // about why not.
        if (bSuccess == false)
        {
            dwError = Marshal.GetLastWin32Error();
        }
        return bSuccess;
    }

    public static bool SendFileToPrinter(string szPrinterName, string szFileName)
    {
        // Open the file.
        FileStream fs = new FileStream(szFileName, FileMode.Open);
        // Create a BinaryReader on the file.
        BinaryReader br = new BinaryReader(fs);
        // Dim an array of bytes big enough to hold the file's contents.
        Byte[] bytes = new Byte[fs.Length];
        bool bSuccess = false;
        // Your unmanaged pointer.
        IntPtr pUnmanagedBytes = new IntPtr(0);
        int nLength = 0;

        nLength = Convert.ToInt32(fs.Length);
        // Read the contents of the file into the array.
        bytes = br.ReadBytes(nLength);
        // Allocate some unmanaged memory for those bytes.
        pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
        // Copy the managed byte array into the unmanaged array.
        Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
        // Send the unmanaged bytes to the printer.
        bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
        // Free the unmanaged memory that you allocated earlier.
        Marshal.FreeCoTaskMem(pUnmanagedBytes);
        return bSuccess;
    }
    public static bool SendStringToPrinter(string szPrinterName, string szString)
    {
        IntPtr pBytes = default(IntPtr);
        Int32 dwCount = default(Int32);
        // How many characters are in the string?
        dwCount = szString.Length;
        // Assume that the printer is expecting ANSI text, and then convert
        // the string to ANSI text.
        pBytes = Marshal.StringToCoTaskMemAnsi(szString);
        // Send the converted ANSI string to the printer.
        SendBytesToPrinter(szPrinterName, pBytes, dwCount);
        Marshal.FreeCoTaskMem(pBytes);
        return true;
    }
}

'''

I managed to solve this by adding 'Encoding e1 = Encoding.GetEncoding(1251);' and replacing 'e1' with 'Encoding.ASCII'. Also, i had to set default code page for printer to Wpc1251 (Cyrillic). I made some screenshots with steps on how to do it

changing code page 1

changing code page 2

changing code page 3

changing code page 4

njuvbi
  • 1
  • 3

1 Answers1

1

The Encodings you are using will not support the ESC/POS Cyrillic code page.
For example, Encoding.ASCII only supports the range from 0x00 to 0x7F.

Encoding.ASCII Property

An encoding for the ASCII (7-bit) character set.
ASCII characters are limited to the lowest 128 Unicode characters, from U+0000 to U+007F.
The ASCIIEncoding object that is returned by this property might not have the appropriate behavior for your app. It uses replacement fallback to replace each string that it cannot encode and each byte that it cannot decode with a question mark ("?") character.


The following three EPSON materials support Cyrillic.
Page 17 [PC866: Cyrillic #2]
Page 34 [PC855: Cyrillic]
Page 46 [WPC1251: Cyrillic]

The following command switches the printer code page.
ESC t

Please check if it supports these, as it depends on the vendor/model of the printer you are using.


So instead of Encoding.ASCII.GetBytes, you will need to get and use one of the code pages(866/855/1251) supported by the printer with Encoding.GetEncoding Method.

Encoding Class

However, if you are using .NET Core/.NET 5.0 or higher, you will need to call the Encoding.RegisterProvider (EncodingProvider) Method to extend the supported Encoding types in advance.

This is because .NET Core/.NET 5.0 or higher only supports a limited number of types of Encoding.
EncodingProvider Class
CodePagesEncodingProvider Class


For note:
The reason why Cyrillic characters can be printed with Word document printing is:
Probably because everything is expanded to bit image data before printing.

kunif
  • 4,060
  • 2
  • 10
  • 30