Flutter USB ESC指令打印机控制插件usb_esc_printer_windows的使用
Flutter USB ESC指令打印机控制插件usb_esc_printer_windows的使用
简介
usb_esc_printer_windows
是一个用于在Windows平台上通过ESC/POS指令控制USB打印机的Flutter插件。该插件使用Dart FFI(Foreign Function Interface)来调用本地代码。
使用步骤
项目结构
该项目的结构如下:
src
: 包含本地源代码以及Cmake文件,用于构建动态库。lib
: 包含定义插件API的Dart代码,并调用本地代码。- 平台文件夹 (
android
,ios
,windows
等): 包含构建和捆绑本地代码库所需的构建文件。
构建和捆绑本地代码
pubspec.yaml
文件配置如下:
plugin:
platforms:
some_platform:
ffiPlugin: true
这会为各个目标平台调用本地构建系统并捆绑二进制文件到Flutter应用中。
绑定到本地代码
为了使用本地代码,需要在Dart中生成绑定。这些绑定由package:ffigen
从src/usb_esc_printer_windows.h
头文件生成。可以通过运行以下命令重新生成绑定:
flutter pub run ffigen --config ffigen.yaml
调用本地代码
对于短时间运行的本地函数,可以直接从任何隔离中调用。例如,查看lib/usb_esc_printer_windows.dart
中的sum
函数。
对于长时间运行的函数,应该在一个辅助隔离中调用以避免在Flutter应用中丢帧。例如,查看lib/usb_esc_printer_windows.dart
中的sumAsync
函数。
完整示例代码
以下是完整的示例代码,展示了如何使用usb_esc_printer_windows
插件进行打印操作:
import 'package:esc_pos_utils_plus/esc_pos_utils_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:image/image.dart' as img;
import 'package:usb_esc_printer_windows/usb_esc_printer_windows.dart' as usb_esc_printer_windows;
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final String _printerName = "EPSON";
late Future<CapabilityProfile> _profile;
[@override](/user/override)
initState() {
_profile = CapabilityProfile.load();
super.initState();
}
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Fluter ESC/POS Printer Pakage For Windows Platform Only'),
),
body: SingleChildScrollView(
child: Container(
padding: const EdgeInsets.all(10),
child: Column(
children: [
ElevatedButton(
onPressed: printReq,
child: const Text("Demo Print"),
)
],
),
),
),
),
);
}
Future<Uint8List> loadImageFromAssets(String path) async {
final ByteData data = await rootBundle.load(path);
return data.buffer.asUint8List();
}
printReq() async {
List<int> bytes = [];
final profile = await _profile;
final generator = Generator(PaperSize.mm80, profile);
// LOGO
final Uint8List data = await loadImageFromAssets('assets/images/logo.png');
img.Image originalImage = img.decodeImage(data)!;
bytes += generator.imageRaster(originalImage, align: PosAlign.center);
bytes += generator.feed(1);
// GENERATE BARCODE
String invoiceNo = "322123000000";
List<int> barData = invoiceNo.split('').map((String digit) => int.parse(digit)).toList();
bytes += generator.barcode(
Barcode.itf(barData),
height: 100,
textPos: BarcodeText.none,
);
bytes += generator.feed(1);
bytes += generator.text(
'INV #322123000000',
styles: const PosStyles(
align: PosAlign.center,
height: PosTextSize.size2,
width: PosTextSize.size2,
),
);
bytes += generator.text('Reprinted at : 06-11-2023 07:32:52 AM');
bytes += generator.feed(1);
bytes += generator.text(
'PAID(IN)',
styles: const PosStyles(
align: PosAlign.center,
height: PosTextSize.size2,
width: PosTextSize.size2,
),
);
bytes += generator.feed(1);
bytes += generator.text('Walk in');
bytes += generator.text('Tel : 0000000000');
bytes += generator.text('Date\\Time : Sun, 10 Sep 2023 06:24 PM');
bytes += generator.text('Associate : 5552');
bytes += generator.text('Promised On : Sun, 10 Sep 2023 06:24 PM');
bytes += generator.feed(1);
bytes += [27, 97, 0];
bytes += generator.row([
PosColumn(
text: 'QTY',
width: 1,
styles: const PosStyles(
align: PosAlign.left,
bold: true,
),
),
PosColumn(
text: 'S/T/DESCRIPTION',
width: 8,
styles: const PosStyles(
align: PosAlign.left,
bold: true,
),
),
PosColumn(
text: 'TOTAL',
width: 3,
styles: const PosStyles(
align: PosAlign.left,
bold: true,
),
),
]);
bytes += [27, 97, 1];
bytes += generator.text('-----------------------------------------');
bytes += [27, 97, 0];
bytes += generator.text(
' 1x Pants (IN) \$ 133.40',
styles: const PosStyles(
align: PosAlign.left,
reverse: true,
bold: true,
),
);
bytes += generator.feed(1);
bytes += [27, 97, 1];
// GENERATE BARCODE
bytes += generator.barcode(
Barcode.itf(
"32212300000000".split('').map((String digit) => int.parse(digit)).toList(),
),
height: 50,
textPos: BarcodeText.none,
);
bytes += generator.text("32212300000000");
bytes += generator.feed(1);
bytes += [27, 97, 0];
bytes += generator.row([
PosColumn(
text: '1x',
width: 1,
styles: const PosStyles(
align: PosAlign.left,
),
),
PosColumn(
text: '(\$13.40 Growth Hem)',
width: 11,
styles: const PosStyles(
align: PosAlign.left,
),
),
]);
bytes += [27, 97, 0];
bytes += generator.row([
PosColumn(
text: '',
width: 1,
styles: const PosStyles(
align: PosAlign.left,
),
),
PosColumn(
text: '(Tag : (1x) Lengthen : Lengthen \$ 0.00',
width: 11,
styles: const PosStyles(
align: PosAlign.left,
),
),
]);
bytes += [27, 97, 0];
bytes += generator.row([
PosColumn(
text: '',
width: 1,
styles: const PosStyles(
align: PosAlign.left,
),
),
PosColumn(
text: '| (1x) Lengthen : Polo Hem \$ 0.00) |',
width: 11,
styles: const PosStyles(
align: PosAlign.left,
),
),
]);
bytes += [27, 97, 0];
bytes += generator.row([
PosColumn(
text: '',
width: 1,
styles: const PosStyles(
align: PosAlign.left,
),
),
PosColumn(
text: 'Dept Hem',
width: 11,
styles: const PosStyles(
align: PosAlign.left,
bold: true,
),
),
]);
bytes += generator.feed(1);
bytes += [27, 97, 0];
bytes += generator.text(
' 1x Pants (IN) \$ 133.40',
styles: const PosStyles(
align: PosAlign.left,
reverse: true,
bold: true,
),
);
bytes += generator.feed(1);
bytes += [27, 97, 1];
// GENERATE BARCODE
bytes += generator.barcode(
Barcode.itf(
"32212300000000".split('').map((String digit) => int.parse(digit)).toList(),
),
height: 50,
textPos: BarcodeText.none,
);
bytes += generator.text("32212300000000");
bytes += generator.feed(1);
bytes += [27, 97, 0];
bytes += generator.row([
PosColumn(
text: '1x',
width: 1,
styles: const PosStyles(
align: PosAlign.left,
),
),
PosColumn(
text: '(\$13.40 Growth Hem)',
width: 11,
styles: const PosStyles(
align: PosAlign.left,
),
),
]);
bytes += [27, 97, 0];
bytes += generator.row([
PosColumn(
text: '',
width: 1,
styles: const PosStyles(
align: PosAlign.left,
),
),
PosColumn(
text: '(Tag : (1x) Lengthen : Lengthen \$ 0.00',
width: 11,
styles: const PosStyles(
align: PosAlign.left,
),
),
]);
bytes += [27, 97, 0];
bytes += generator.row([
PosColumn(
text: '',
width: 1,
styles: const PosStyles(
align: PosAlign.left,
),
),
PosColumn(
text: '| (1x) Lengthen : Polo Hem \$ 0.00) |',
width: 11,
styles: const PosStyles(
align: PosAlign.left,
),
),
]);
bytes += [27, 97, 0];
bytes += generator.row([
PosColumn(
text: '',
width: 1,
styles: const PosStyles(
align: PosAlign.left,
),
),
PosColumn(
text: 'Dept Hem',
width: 11,
styles: const PosStyles(
align: PosAlign.left,
bold: true,
),
),
]);
bytes += generator.feed(1);
bytes += [27, 97, 1];
bytes += generator.text('-----------------------------------------');
bytes += [27, 97, 0];
bytes += generator.text(
'HST # : R877439000',
styles: const PosStyles(
height: PosTextSize.size1,
),
);
bytes += [27, 97, 2];
bytes += generator.text('Sub Total \$ 13.40');
bytes += [27, 97, 0];
bytes += generator.text('Total Disc \$ 0.00');
bytes += [27, 97, 2];
bytes += generator.text('HST (13%) \$ 1.74');
bytes += generator.feed(1);
bytes += [27, 97, 2];
bytes += generator.text(
'Total \$ 15.14',
styles: const PosStyles(
height: PosTextSize.size2,
bold: true,
),
);
bytes += generator.text(
'Balance Owing \$ 0.00',
styles: const PosStyles(
height: PosTextSize.size2,
bold: true,
),
);
bytes += generator.feed(1);
bytes += [27, 97, 1];
bytes += generator.text('Transaction details');
bytes += generator.text('*****************************************');
bytes += [27, 97, 0];
bytes += generator.text('Tender Type : Cash(INV)');
bytes += generator.text('Amount : \$ 0.00');
bytes += [27, 97, 2];
bytes += generator.text('Total Tendered \$ 13.40');
bytes += generator.text('Total Charge \$ 0.00');
bytes += generator.text('Total Round Off \$ 0.01');
bytes += [27, 97, 0];
bytes += generator.text('Items : 1');
bytes += [27, 97, 1];
bytes += generator.text(
'Production : Sun, 10 Sep 2023 09:00 AM',
styles: const PosStyles(
height: PosTextSize.size2,
bold: true,
),
);
bytes += generator.feed(1);
bytes += [27, 97, 2];
bytes += generator.text('Points Earned Before This Visit : \$ 739.85');
bytes += generator.text('Total Points Earned : \$ 0.57');
// 0 = left, center = 1 right = 2
bytes += [27, 97, 1];
bytes += generator.text('*** Store Copy ***');
bytes += generator.feed(1);
bytes += generator.cut();
final res = await usb_esc_printer_windows.sendPrintRequest(bytes, _printerName);
String msg = "";
if (res == "success") {
msg = "Printed Successfully";
} else {
msg = "Failed to generate a print please make sure to use the correct printer name";
}
print(msg);
}
}
更多关于Flutter USB ESC指令打印机控制插件usb_esc_printer_windows的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter USB ESC指令打印机控制插件usb_esc_printer_windows的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter应用中使用usb_esc_printer_windows
插件来控制USB ESC指令打印机的示例代码。这个插件允许你在Windows平台上通过USB接口发送ESC/POS指令来控制打印机。
首先,确保你已经在pubspec.yaml
文件中添加了usb_esc_printer_windows
依赖:
dependencies:
flutter:
sdk: flutter
usb_esc_printer_windows: ^最新版本号 # 替换为实际最新版本号
然后,运行flutter pub get
来安装依赖。
接下来,在Flutter项目中,你可以使用以下代码来初始化插件并发送打印指令。
1. 导入插件
在你的Dart文件中导入插件:
import 'package:usb_esc_printer_windows/usb_esc_printer_windows.dart';
2. 初始化插件并搜索打印机
你需要先初始化插件并搜索连接的USB打印机:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
UsbEscPrinterWindows printer = UsbEscPrinterWindows();
// 搜索连接的USB打印机
List<UsbDevice> devices = await printer.listDevices();
print('Found devices: $devices');
// 假设我们选择了第一个设备(实际应用中,你可能需要让用户选择设备)
if (devices.isNotEmpty) {
UsbDevice selectedDevice = devices.first;
await printer.openDevice(selectedDevice);
// 在这里发送打印指令
await sendPrintCommand(printer);
// 关闭设备连接
await printer.closeDevice();
} else {
print('No USB ESC/POS printer found.');
}
runApp(MyApp());
}
3. 发送打印指令
定义一个函数来发送ESC/POS指令到打印机:
Future<void> sendPrintCommand(UsbEscPrinterWindows printer) async {
// 示例ESC/POS指令:初始化打印机,打印文本,并切纸
List<int> escPosCommands = [
// 初始化打印机
0x1B, 0x40, // 初始化指令
// 设置对齐方式为居中
0x1B, 0x61, 0x01, // 对齐中心
// 打印文本
0x1B, 0x21, 33, // 设置字体大小为A(宽度33),高度也是33(默认)
0x48, 0x65, 0x6C, 0x6C, 0x6F, // 'Hello'的ASCII码
0x0A, // 换行
// 切纸
0x1B, 0x66, 0x01 // 切纸指令
];
// 发送指令到打印机
await printer.write(escPosCommands);
}
4. 完整示例
将上述代码整合到一个完整的Flutter应用中:
import 'package:flutter/material.dart';
import 'package:usb_esc_printer_windows/usb_esc_printer_windows.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
UsbEscPrinterWindows printer = UsbEscPrinterWindows();
List<UsbDevice> devices = await printer.listDevices();
print('Found devices: $devices');
if (devices.isNotEmpty) {
UsbDevice selectedDevice = devices.first;
await printer.openDevice(selectedDevice);
runApp(MyApp(printer: printer));
} else {
print('No USB ESC/POS printer found.');
runApp(MyApp(printer: null));
}
}
class MyApp extends StatelessWidget {
final UsbEscPrinterWindows? printer;
MyApp({this.printer});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('USB ESC/POS Printer Control'),
),
body: Center(
child: printer != null
? ElevatedButton(
onPressed: () async {
await sendPrintCommand(printer!);
},
child: Text('Print'),
)
: Text('No printer found.'),
),
),
);
}
}
Future<void> sendPrintCommand(UsbEscPrinterWindows printer) async {
List<int> escPosCommands = [
0x1B, 0x40,
0x1B, 0x61, 0x01,
0x1B, 0x21, 33,
0x48, 0x65, 0x6C, 0x6C, 0x6F,
0x0A,
0x1B, 0x66, 0x01
];
await printer.write(escPosCommands);
}
在这个示例中,我们搜索USB设备,选择第一个设备(实际应用中,你可能需要让用户从列表中选择设备),并在点击按钮时发送打印指令。请确保在实际应用中处理错误和异常情况,并根据需要调整ESC/POS指令。