How to print Asian languages to a thermal printer from Flutter?

Issue

I am using the Flutter package esc_pos_printer 1.5.0 to print to a thermal printer. It all works fine if I print Latin characters. I have tried using the mutilingual code page but it always fails when trying to print Thai characters. I need to be able to print in English, Thai, Burmese, Khmer and Vietnamese. None of the available code pages in this package appear to support non Latin Asian languages. This is a show stopper for me and possibly many others.

II sent an ESC command to the printer to change the code page and then printed the new code page which was in Thai and Latin characters as expected. However, my app crashes when I try to print Thai characters.

I am getting this error from the debugger:

E/flutter (29402): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: Invalid argument (string): Contains invalid characters.: "ยินดีต้อนรับ"
E/flutter (29402): #0      _UnicodeSubsetEncoder.convert  (dart:convert/ascii.dart:88:9)
E/flutter (29402): #1      Latin1Codec.encode  (dart:convert/latin1.dart:42:46)

Here is my code:

void _printReceipt(BuildContext context) {

  String ip = '192.168.1.100'; 

  Printer.connect(ip, port: 9100).then((printer) {

  printer.sendRaw([27, 116, 255]);

  printer.printCodeTable();

  printer.println('Welcome');

  printer.println('ยินดีต้อนรับ');

  printer.cut();
  printer.disconnect();
}
);
}

edit: I attempted to encode the string as bytes and print like this

_bytes = utf8.encode("ยินดีต้อนรับ");

printer.sendRaw(_bytes);

but I got this

result from above commands

I used the package suggested below which works well for Thai. My ESC/POS printer supports code pages 96 and 255 for Thai. 96 gets it wrong but 255 got the job done. The bottom alignment mismatch will be because printing Thai characters require 3 passes and this string contains no bottom pass characters.

enter image description here

Solution

Unfortunetely, I think there are two issues with the esc_pos_printer package at this moment:

  • it miss many character code tables and it doesn’t really allow you to pass your own using PosCodeTable constuctor since it’s private, but you can set character table manually by using sendRaw

  • you can pass only characters that can be encoded using Latin1Codec or GBK codec since only these are supported, to my knowledge – Thai characters can’t be encoded using these – this why the error is thrown

The problem really comes down to encoding. For Thai, printers will probably expect the data to come in format of TIS-620. Fe. ๐ is 240, ๑ is 241.

// Manually set PosCodeTable - 26 here is the Thai Character Code 18
printer.sendRaw([
  27,
  116,
  26
]);
 
printer.sendRaw([240, 241]); // Should print ๐ and ๑

Remember that you do need to set the character code table. I used Thai Character Code 18 with number 26, because that is what my printer supports. To find right charset codes you may look for ESC t command in your printer manual – manufacturers usually put table there or just browse the internet.

So how do we fix it?

  1. We can fork&fix/workaround setting character code tables

  2. Use proper encoder, like GBK for Chinese, but it is not built-in since Dart support only handful amount of encodings and using Encoding.getByName("csTIS620") will get you null. You may need to do character mapping yourself – I didn’t found codec for Dart that would suit your needs. There is also a package charset_converter that uses platform code to convert the charsets.

Important updates since original answer

esc_pos_printer now supports raw byte streams on Tickets by textEncoded method. This can be used with charset_converter to print right characters.

Also character code tables were expanded i.e. CP1250. This is set in PosStyles as codeTable parameter. Those are mapped to printer ids in ecs_pos_utils project with this map.

Answered By – pr0gramist

Answer Checked By – Marilyn (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.