Flutter中如何使用3英寸规格打印PDF文件?
实现3英寸蓝牙打印机的PDF打印(Flutter/Dart)
当然可以实现,核心解决两个问题:自定义PDF纸张尺寸和蓝牙打印机的通信适配,以下是具体思路和代码示例:
1. 用pdf包创建自定义尺寸的PDF
pdf 包并非只支持标准尺寸,你可以通过 PdfPageFormat.custom 自定义任意尺寸。首先明确单位:PDF的默认单位是点(pt),1英寸=72pt,所以3英寸宽度就是 72*3=216pt,高度可以根据需求设置(比如小票类打印可以设一个较大的值,比如1000pt,或者按需动态计算内容高度)。
示例代码:
import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; import 'dart:typed_data'; // 生成自定义尺寸的PDF Future<Uint8List> generateCustomPdf() async { final pdf = pw.Document(); // 定义3英寸宽度的纸张(可调整边距和高度) final customPage = PdfPageFormat.custom( width: 216, // 3*72pt height: 1000, // 自定义高度,按需调整 marginLeft: 8, marginRight: 8, marginTop: 8, marginBottom: 8, ); pdf.addPage( pw.Page( pageFormat: customPage, build: (context) { return pw.Column( crossAxisAlignment: pw.CrossAxisAlignment.start, children: [ pw.Text('订单编号: 20240520001', style: pw.TextStyle(fontSize: 16)), pw.SizedBox(height: 10), pw.Text('商品名称: 测试商品', style: pw.TextStyle(fontSize: 14)), pw.Text('数量: 1', style: pw.TextStyle(fontSize: 14)), pw.Text('总价: ¥99.00', style: pw.TextStyle(fontSize: 16, fontWeight: pw.FontWeight.bold)), ], ); }, ), ); return pdf.save(); }
2. 蓝牙打印机的通信与打印
接下来要把生成的PDF数据发送到蓝牙打印机,分两种场景处理:
场景A:打印机支持直接打印PDF
部分商用蓝牙打印机支持直接接收PDF字节流并打印,你可以用Flutter蓝牙插件(如flutter_blue)完成连接和数据传输:
import 'package:flutter_blue/flutter_blue.dart'; import 'dart:typed_data'; // 连接蓝牙打印机并发送PDF数据 Future<void> printPdfToBluetooth(Uint8List pdfBytes) async { FlutterBlue flutterBlue = FlutterBlue.instance; // 扫描蓝牙设备(替换成你的打印机名称关键词) final scanResults = await flutterBlue.scan(timeout: const Duration(seconds: 5)); BluetoothDevice? printer; for (var result in scanResults) { if (result.device.name.contains('PDF-Printer')) { printer = result.device; break; } } if (printer == null) { throw Exception('未找到目标打印机'); } // 连接打印机 await printer.connect(); // 发现服务并找到可写特征值(需参考打印机的蓝牙服务文档) final services = await printer.discoverServices(); for (var service in services) { for (var characteristic in service.characteristics) { if (characteristic.properties.write) { // 分块发送PDF数据(避免超出蓝牙单次传输限制) const chunkSize = 512; for (int i = 0; i < pdfBytes.length; i += chunkSize) { final end = (i + chunkSize < pdfBytes.length) ? i + chunkSize : pdfBytes.length; await characteristic.write(pdfBytes.sublist(i, end), withoutResponse: true); } break; } } } await printer.disconnect(); }
场景B:普通ESC/POS小票打印机(不支持PDF)
大部分3英寸小票打印机是ESC/POS指令集,不支持直接打印PDF,需要先把PDF转成图片,再转换成ESC/POS指令发送:
- 把PDF转成图片(用
pdf_render包):
import 'package:pdf_render/pdf_render.dart'; import 'dart:typed_data'; import 'dart:ui' as ui; Future<Uint8List> pdfToImage(Uint8List pdfBytes) async { final doc = await PdfDocument.openData(pdfBytes); final page = await doc.getPage(1); // 渲染图片,建议设置2倍分辨率提升打印清晰度 final image = await page.render( width: 216 * 2, height: 1000 * 2, format: PdfPageImageFormat.png, ); final byteData = await image!.toByteData(format: ui.ImageByteFormat.png); return byteData!.buffer.asUint8List(); }
- 用ESC/POS插件发送图片(如
esc_pos_bluetooth):
import 'package:esc_pos_bluetooth/esc_pos_bluetooth.dart'; import 'package:flutter/services.dart'; Future<void> printImageToEscPos(Uint8List imageBytes) async { final manager = PrinterBluetoothManager(); // 扫描并选择打印机(此处省略UI选择逻辑,可根据设备名称自动匹配) manager.startScan(Duration(seconds: 5)); // 示例:假设已选中打印机 // BluetoothDevice selectedPrinter = ...; // manager.selectPrinter(selectedPrinter); // 创建小票,设置接近3英寸的纸张(90mm≈3.54英寸,可自定义更精准的尺寸) final ticket = Ticket(PdfPageFormat.mm90); ticket.image(Image.fromBytes(imageBytes), align: PosAlign.center); ticket.cut(); await manager.printTicket(ticket); }
3. 关键注意事项
- 权限配置:Android需添加
BLUETOOTH_SCAN、BLUETOOTH_CONNECT权限;iOS需在Info.plist中添加NSBluetoothAlwaysUsageDescription权限。 - 打印机指令适配:不同品牌的ESC/POS打印机可能有细微差异,若打印异常,需参考打印机文档调整初始化指令(如设置打印浓度、行间距)。
- 数据分块:蓝牙单次传输数据有限,发送大文件时必须分块处理,避免丢包。
内容的提问来源于stack exchange,提问作者Sibi Kumar
相关产品推荐
相关产品推荐

