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

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指令发送:

  1. 把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();
}
  1. 用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 17:25:30