You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中使用蓝牙热敏打印机打印阿拉伯文账单的方案求助

解决Flutter蓝牙热敏打印机打印阿拉伯文账单的方案

方案1:切换打印机代码页直接发送阿拉伯文字节

多数热敏打印机(包括MP210)支持通过切换代码页打印非英文字符,阿拉伯文常用Windows-1256编码(对应代码页编号需查MP210手册,通常为十进制17)。操作步骤如下:

  1. 连接打印机后,发送切换代码页的ESC指令
  2. 将阿拉伯文编码为对应代码页的字节流
  3. 直接发送字节流替代原generator.text方法
// 需在pubspec.yaml添加依赖:charset_converter: ^2.0.0
import 'package:charset_converter/charset_converter.dart';

// 保留原连接逻辑
bool isConnected = await PrintBluetoothThermal.connectionStatus;
if (!isConnected) {
  await PrintBluetoothThermal.connect(
    macPrinterAddress: selectedPrinter!.macAdress,
  );
}

// 发送切换到Windows-1256代码页的ESC指令(ESC t 17,0x11是十进制17)
const switchCodePage = [0x1B, 0x74, 0x11];
await PrintBluetoothThermal.writeBytes(switchCodePage);

// 转换阿拉伯文为Windows-1256编码字节
String arabicText = 'مرحبا';
List<int> arabicBytes = await CharsetConverter.encode('windows-1256', arabicText);

// 发送居中对齐指令+阿拉伯文字节
const centerAlign = [0x1B, 0x61, 0x01];
await PrintBluetoothThermal.writeBytes(centerAlign);
await PrintBluetoothThermal.writeBytes(arabicBytes);

// 发送换行和切纸指令
await PrintBluetoothThermal.writeBytes([0x0A, 0x0A]);
await PrintBluetoothThermal.writeBytes([0x1B, 0x69]);

// 断开连接
await PrintBluetoothThermal.disconnect;

注意:务必查阅MP210官方手册确认支持的阿拉伯文代码页编号,避免指令错误。

方案2:用Canvas绘制账单为图片后打印

如果代码页方案不可行,直接用Flutter Canvas绘制完整账单(支持阿拉伯文RTL排版),转成适配打印机纸张的图片,再通过ESC/POS指令打印,完美控制排版避免乱码。

import 'dart:ui' as ui;
import 'dart:typed_data';
import 'package:flutter/material.dart';

// 保留原连接逻辑
bool isConnected = await PrintBluetoothThermal.connectionStatus;
if (!isConnected) {
  await PrintBluetoothThermal.connect(
    macPrinterAddress: selectedPrinter!.macAdress,
  );
}

// 1. 绘制账单内容
final recorder = ui.PictureRecorder();
final paperWidth = is58mm ? 58 * 8 : 80 * 8; // 热敏打印机分辨率通常为8点/mm
final canvas = Canvas(recorder, Rect.fromLTWH(0, 0, paperWidth.toDouble(), 1000));

// 设置阿拉伯文绘制样式
final textStyle = TextStyle(
  fontSize: 16,
  color: Colors.black,
  fontFamily: 'NotoNaskhArabic', // 确保项目引入支持阿拉伯文的字体
);
final textPainter = TextPainter(
  text: TextSpan(text: 'مرحبا', style: textStyle),
  textDirection: TextDirection.rtl, // 阿拉伯文从右到左排版
  textAlign: TextAlign.center,
);
textPainter.layout(maxWidth: paperWidth.toDouble());
textPainter.paint(canvas, Offset(0, 20));

// 可添加更多账单元素:明细、金额、logo等

// 2. 将绘制内容转为Bitmap
final picture = recorder.endRecording();
final image = await picture.toImage(paperWidth, 300); // 高度按需调整
final byteData = await image.toByteData(format: ui.ImageByteFormat.png);
final pngBytes = byteData!.buffer.asUint8List();

// 3. 转成ESC/POS图片指令并发送
final profile = await CapabilityProfile.load();
final generator = Generator(is58mm ? PaperSize.mm58 : PaperSize.mm80, profile);
List<int> imageBytes = generator.image(Image.memory(pngBytes));

await PrintBluetoothThermal.writeBytes(imageBytes);
await PrintBluetoothThermal.writeBytes(generator.cut());

// 断开连接
await PrintBluetoothThermal.disconnect;

注意:需将支持阿拉伯文的字体文件放入项目,在pubspec.yaml中配置字体路径,避免设备缺失字体导致排版异常。

方案3:更换支持多字体的ESC/POS库

若上述方案仍有问题,可尝试替换为支持自定义TTF字体的打印库(如部分分支版本的esc_pos_printer),直接加载阿拉伯字体生成打印内容:

// 加载项目中的阿拉伯字体文件
final fontBytes = await rootBundle.load('fonts/arabic_font.ttf');
final ttfFont = TtfFont(fontBytes);

final profile = await CapabilityProfile.load();
final generator = Generator(is58mm ? PaperSize.mm58 : PaperSize.mm80, profile);

// 直接用自定义字体打印阿拉伯文
List<int> bytes = [];
bytes += generator.text(
  'مرحبا',
  styles: const PosStyles(
    bold: true,
    align: PosAlign.center,
  ),
  font: ttfFont,
);
bytes += generator.cut();

await PrintBluetoothThermal.writeBytes(bytes);
await PrintBluetoothThermal.disconnect;

注意:需确认库版本是否支持自定义字体,部分库可能需要自行编译修改。

内容的提问来源于stack exchange,提问作者Samii

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 11:58:19