【问题标题】:How to print Asian languages to a thermal printer from Flutter?如何从 Flutter 将亚洲语言打印到热敏打印机?
【发布时间】:2020-04-15 22:33:24
【问题描述】:

我正在使用Flutteresc_pos_printer 1.5.0 打印到热敏打印机。如果我打印拉丁字符,一切正常。我曾尝试使用多语言代码页,但在尝试打印泰语字符时总是失败。我需要能够用英语、泰语、缅甸语、高棉语和越南语打印。此包中的可用代码页似乎都不支持非拉丁语语言。这对我和其他许多人来说都是一场表演。

II 向打印机发送 ESC 命令以更改代码页,然后按预期打印新的泰文和拉丁字符的代码页。但是,当我尝试打印泰语字符时,我的应用程序崩溃了。

我从调试器收到此错误:

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)

这是我的代码:

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();
}
);
}

编辑:我尝试将字符串编码为字节并像这样打印

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

printer.sendRaw(_bytes);

但我得到了这个

我使用了package suggested below,它适用于泰语。我的 ESC/POS 打印机支持泰语的代码页 96 和 255。 96 做错了,但 255 完成了工作。底部对齐不匹配将是因为打印泰语字符需要 3 遍,并且此字符串不包含底部遍字符。

【问题讨论】:

  • 你解决了这个问题@markhorrocks 吗?如果可以,可以分享一下怎么做吗?

标签: flutter thermal-printer codepages


【解决方案1】:

您的打印机的供应商和型号是什么?
泰语代码页规范的参数是否正确?
EPSON材料中似乎有20-26而不是255的多种模式。

ESC t Select character code table

20 页 20 Thai Character Code 42
21 页 21 Thai Character Code 11
22 页 22 Thai Character Code 13
23 页 23 Thai Character Code 14
24 页 24 Thai Character Code 16
25 页 25 Thai Character Code 17
26 页 26 Thai Character Code 18

International Character Sets

并且是否支持泰语是根据打印机的型号和更详细的目的地来划分的。
Support Information for Each Model: Code Pages

然后尝试将打印请求作为二进制数据数组,而不是编码字符串。


另外:
例如,如果您有像 iconv - npmiconv-lite - npm 这样的库在浏览器中运行,您将能够执行各种编码/解码。请寻找它。

如果这样的库可以转换为字节数组,是否可以按照问题文章中的描述使用printer.sendRaw() 发送?


原来有huaji249/flutter_iconv这样的库,但是创建者好像只支持自己使用(GBK转UTF-8)。
参考this尝试创建自己的。

还有其他文章介绍如何使用 JavaScript 库。
Flutter and Openlayers - including js libraries in flutter


在 UTF-8 中,泰文字符将在此范围内。
U+0E00...U+0E7F:Thai

这是典型的 MBCS Thai 代码页。
ISO/IEC 8859-11 - Wikipedia

有了这些字符数,创建一个专用函数来使用转换表一次转换一个字符似乎很容易。
最好创建一个仅具有您需要的功能的专用函数,而不是寻找或创建通用转换库。

转换目标应该是您的打印机支持的泰语字符表。


进一步补充:

我找到了这样一篇文章。要打印泰语字符,请将它们打印成三行。
根据您的打印机可以支持的功能,本文可能是替代品。
Print Thai language

泰语被称为三通语言。这意味着分别打印顶线、中间线和底线。
例如รื่有顶部和中间字符,你必须在每一行打印它们,从你的图片中这些打印在底部,因此作为顶行。
另一个例子ดั้,有双顶字符,你需要在代码页中查找字符。
还有其他底部字符,这些将打印在顶部,因此作为底线。
做一些测试,你会得到它。

还有,还有一篇这样的文章。
Thai characters printing #51
Thai character problem of the printer model TM-T88IV #701
Epson TM-T82II Thai language support #409


您需要将其制作成 PDF 吗?
例如,如果您将画布直接转换为图像并打印出来,是否需要耗时的文件创建和读取?

How to save a Flutter canvas as a bitmap image?

  1. 创建一个 PictureRecorder。
  2. 使用您的 PictureRecorder 创建画布并绘制内容。
  3. 在 PictureRecorder 上调用 endRecording() 以获取图片。
  4. 在图片上调用 toImage()。
  5. 在图像上调用 toByteData()。糟糕,这还没有实现。我提出了一个问题。

Flutter dart:ui Picture toImage method

esc_pos_printer package documentation

打印图片:

import 'dart:io';
import 'package:image/image.dart';

const String filename = './logo.png';
final Image image = decodeImage(File(filename).readAsBytesSync());
// Using (ESC *) command
printer.printImage(image);
// Using an alternative obsolette (GS v 0) command
printer.printImageRaster(image);

Flutter image Decoder decodeImage abstract method

【讨论】:

  • 对于不支持的语言,如何将字符串转换为二进制?泰语每个字符可以打印 3 行。
  • 打印机是通用的,但有 2 个泰语代码页,96 和 255。它还有一个越南语代码页 27,但没有高棉语或缅甸语。问题似乎是 Flutter 包不支持那些代码页
  • 这在 Dart 中必须是可行的。对这种功能的需求一定是巨大的。
  • 这个应用是 Android 上的 Flutter,而不是 Flutter web。
  • flutter_iconv 似乎只是调用了 libiconv.so。如何更改参数以从 UTF-8 转换为泰语?如果是这种情况,您也许可以使用 Flutter android 应用程序。如果这不起作用,您需要找到一个与使用原生 Dart 创建的 iconv 兼容的库,或者创建自己的库。
【解决方案2】:

不幸的是,我认为此时esc_pos_printer 包存在两个问题:

  • 它错过了许多字符代码表,并且它实际上不允许您使用 PosCodeTable 构造函数传递自己的代码表,因为它是私有的,但您可以使用 sendRaw 手动设置字符表

  • 您只能传递可以使用 Latin1CodecGBK codec 编码的字符,因为据我所知,仅支持这些字符 - 泰语字符无法使用这些字符进行编码 - 这就是引发错误的原因

问题实际上归结为编码。对于泰语,打印机可能希望数据以TIS-620 的格式出现。铁。 ๐是240,๑是241。

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

请记住,您确实需要设置字符代码表。我使用了带有数字 26 的泰语字符代码 18,因为这是我的打印机支持的。要找到正确的字符集代码,您可以在打印机手册中查找 ESC t 命令 - 制造商通常将表格放在那里或只是 browse the internet

那么我们该如何解决呢?

  1. 我们可以fork&fix/workaround设置字符码表

  2. 使用正确的编码器,例如中文的 GBK,但它不是内置的,因为 Dart 仅支持少量编码,使用 Encoding.getByName("csTIS620") 会得到 null。您可能需要自己进行字符映射 - 我没有找到适合您需要的 Dart 编解码器。还有一个包charset_converter,它使用平台代码来转换字符集。

自原始答案以来的重要更新

esc_pos_printer 现在通过textEncoded 方法支持票证上的原始字节流。这可以与charset_converter 一起使用以打印正确的字符。

还扩展了字符代码表,即 CP1250。这在PosStyles 中设置为codeTable 参数。这些将映射到 ecs_pos_utils 项目中的打印机 ID,并带有此 map

【讨论】:

  • 我的打印机在 96 和 255 处有泰语的代码页。即使我可以识别字符串中的每个字符,它也无法帮助我打印上下字符。我不相信 Dart 中有泰语编解码器
  • 你可以尝试获取平台代码的编解码器(因此 Android 的 Kotlin/Java)并使用通道与 Dart 通信,甚至使用真正的 libiconv 和 dart:ffi
  • 下面的答案提到pub.dev/packages/flutter_iconv 使用 dart:ffi 从 C 加载 iconv 但它不会编译,因为它看起来界面最近发生了变化,我不知道如何更新它。
  • 关于字符集 - 如果你的用例是 Android(即将推出 iOS 支持)我刚刚发布了一个包,你可以试试 pub.dev/packages/charset_converter - 检查源代码示例 - 我在那里使用了 TIS620
  • 我怎样才能找出所有这些编码所代表的语言?我在网上找不到它们。我专门寻找高棉语和缅甸语。
猜你喜欢
  • 1970-01-01
  • 2019-08-27
  • 1970-01-01
  • 2022-08-03
  • 2013-03-20
  • 2013-03-16
  • 1970-01-01
  • 2019-11-23
  • 2012-10-05
相关资源
最近更新 更多