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

使用Flutter的pdf与sunmi_printer_plus插件在Sunmi设备打印发票遇问题求助

问题描述

我使用 pdf: ^3.10.4 生成了发票PDF,希望通过 sunmi_printer_plus: ^2.1.01 在Sunmi设备上打印该发票。尝试将PDF转为图片打印时,发票输出效果异常。

PDF生成代码

class PdfInvoiceApi {
  static Future<Document> generate( Pump_Transactions pump) async {
    final pdf = Document();
    final font= await rootBundle.load("lib/fonts/HacenTunisia.ttf");
    final ttf= Font.ttf(font);
    double fontSize10=12;
    double fontSize12=14;

    pdf.addPage(Page(
        theme: ThemeData.withFont(
          base: ttf,
        ),
        pageFormat: PdfPageFormat.roll80,
        build: (Context context) {
          return Column(
            mainAxisAlignment: MainAxisAlignment.start,
                  crossAxisAlignment: CrossAxisAlignment.end,
                  children: [
                    Divider(),
                    if(pump.name != null && pump.name!.length>0)
                      Directionality(
                          textDirection: TextDirection.rtl,
                          child: Center(
                              child: Text(
                                  'فاتورة ضريبية ', style: TextStyle(
                                fontSize: fontSize12,
                              ))
                          )
                      ),
                    if(pump.name == null || pump.name!.isEmpty)
                    Directionality(
                        textDirection: TextDirection.rtl,
                        child: Center(
                            child: Text(
                                'فاتورة ضريبية مبسطة ', style: TextStyle(
                              fontSize: fontSize12,
                            ))
                        )
                    ),
                    Directionality(
                        textDirection: TextDirection.rtl,
                        child: Center(
                            child: Text(
                                CompanyData.companyData!.name!, style: TextStyle(
                              fontSize: fontSize12,
                            ))
                        )
                    ),
                    Directionality(
                        textDirection: TextDirection.rtl,
                        child: Center(
                            child: Text(
                                'رقم ضريبى : '+CompanyData.companyData!.taxNumber!, style: TextStyle(
                              fontSize: fontSize12,
                            ))
                        )
                    ),
                    Divider(),

                    Directionality(
                        textDirection: TextDirection.rtl,
                        child:  Text(
                            'رقم الفاتورة :'+ pump.bill!.transaction!.toString(), style: TextStyle(
                          fontSize: fontSize10,
                        )
                        )
                    ),
                    Directionality(
                        textDirection: TextDirection.rtl,
                        child:  Text(
                                'التاريخ :'+ pump.bill!.dateTime!, style: TextStyle(
                              fontSize: fontSize10,
                            )
                        )
                    ),
                    Directionality(
                        textDirection: TextDirection.rtl,
                        child:  Text(
                            'العنوان :'+CompanyData.companyData!.address!, style: TextStyle(
                          fontSize: fontSize10,
                        )
                        )
                    ),
                    Directionality(
                        textDirection: TextDirection.rtl,
                        child:  Text(
                            'الفرع :'+CompanyData.companyData!.branch!, style: TextStyle(
                          fontSize: fontSize10,
                        )
                        )
                    ),
                    Divider(),
                    if(pump.name != null && pump.name!.length>0)
                      Column(
                        mainAxisAlignment: MainAxisAlignment.start,
                        crossAxisAlignment:CrossAxisAlignment.end ,
                        children:
                          [
                            Directionality(
                                textDirection: TextDirection.rtl,
                                child:  Text(
                                    'اسم العميل :'+ pump.name!.toString(), style: TextStyle(
                                  fontSize: fontSize10,
                                )
                                )
                            ),
                            Directionality(
                                textDirection: TextDirection.rtl,
                                child:  Text(
                                    'العنوان :'+ pump.address!, style: TextStyle(
                                  fontSize: fontSize10,
                                )
                                )
                            ),
                            Directionality(
                                textDirection: TextDirection.rtl,
                                child:  Text(
                                    'الرقم الضريبي :'+pump.tax_number!, style: TextStyle(
                                  fontSize: fontSize10,
                                )
                                )
                            ),
                            Divider(),
                          ]
                      ),
                    Container(
                     // margin: EdgeInsets.fromLTRB(22, 5, 22, 5),
                      child: Directionality(
                        textDirection: TextDirection.rtl,
                        child: Table.fromTextArray(
                          headerStyle: TextStyle(
                              fontSize: 12
                          ),
                          headers: <dynamic>['الإجمالي', 'السعر' ,'الكمية باللتر ', 'الصنف'],
                          cellAlignment: Alignment.center,
                          cellStyle: TextStyle(
                              fontSize: 12
                          ),
                          data:  <List<dynamic>>[
                            <dynamic>[pump.bill!.amount!.toStringAsFixed(2), pump.bill!.price!.toStringAsFixed(2) ,pump.bill!.volume, pump.bill!.productName ],
                          ],
                        ),
                      ),
                    ),
                    Divider(),
                    Directionality(
                        textDirection: TextDirection.rtl,
                        child:  Text('الإجمالي : '+pump.bill!.amount!.toStringAsFixed(2)+" ريال ", style: TextStyle(
                              fontSize: fontSize10,
                            )
                        )
                    ),
                    Divider(),
                    Directionality(
                        textDirection: TextDirection.rtl,
                        child:  Text('الضريبة : '+(CompanyData.companyData!.tax!*100).toStringAsFixed(0)+"%  "+
          (  pump.bill!.amount!-  (pump.bill!.amount! / (1 + CompanyData.companyData!.tax!))).toStringAsFixed(2)+" ريال ", style: TextStyle(
                          fontSize: fontSize10,
                        )
                        ),

                    ),
                    Divider(),
                    Center(
                      child:
                      BarcodeWidget(
                          data: pump.qr!,
                          barcode: Barcode.qrCode(),
                        //  width: 200,
                          height: 150
                      ),
                    ),
                    SizedBox(height: 15.0)
                  ]
              )
          ;
        }
    ));
    return pdf;
  }
}

尝试的打印代码

方案1(输出效果异常)

final pdfFile = await PdfInvoiceApi.generate(pump);
Uint8List bytes=await pdfFile.save();
await SunmiPrinter.bindingPrinter();
await SunmiPrinter.initPrinter();
await SunmiPrinter.startTransactionPrint(true);
await SunmiPrinter.setAlignment(SunmiPrintAlign.CENTER);
await SunmiPrinter.printImage(bytes!);
await SunmiPrinter.lineWrap(10);
await SunmiPrinter.submitTransactionPrint();
await SunmiPrinter.exitTransactionPrint(true);

方案2(无输出)

final pdfFile = await PdfInvoiceApi.generate(pump);
await for (var page in Printing.raster(await pdfFile.save(), pages: [0, 1], dpi: 72)) {
  final image = await page.toPng();
  bytes=image; 
  await SunmiPrinter.bindingPrinter();
  await SunmiPrinter.initPrinter();               
  await SunmiPrinter.startTransactionPrint(true);
  await SunmiPrinter.setAlignment(SunmiPrintAlign.CENTER);
  await SunmiPrinter.printImage(bytes!);
  await SunmiPrinter.lineWrap(10);
  await SunmiPrinter.submitTransactionPrint();
  await SunmiPrinter.exitTransactionPrint(true);
}

解决方案

1. 优化PDF转图片参数,适配Sunmi打印机分辨率

Sunmi小票打印机默认分辨率为203DPI,80mm纸宽对应像素宽度约为576。转图时需匹配该参数,避免变形:

final pdfBytes = await pdfFile.save();
// 仅打印第一页,适配打印机分辨率和纸宽
await for (var page in Printing.raster(pdfBytes, pages: [0], dpi: 203, width: 576)) {
  final imageBytes = await page.toPng();
  // 简化打印流程
  await SunmiPrinter.bindingPrinter();
  await SunmiPrinter.initPrinter();
  await SunmiPrinter.setAlignment(SunmiPrintAlign.CENTER);
  await SunmiPrinter.printImage(imageBytes);
  await SunmiPrinter.lineWrap(2);
}

2. 跳过PDF生成,直接用Sunmi API构建打印内容(推荐)

转图片打印易出现模糊、排版问题,直接调用打印机API拼接内容更可靠:

await SunmiPrinter.bindingPrinter();
await SunmiPrinter.initPrinter();

// 打印标题
await SunmiPrinter.setAlignment(SunmiPrintAlign.CENTER);
await SunmiPrinter.setFontSize(16);
if(pump.name != null && pump.name!.length>0) {
  await SunmiPrinter.printText('فاتورة ضريبية');
} else {
  await SunmiPrinter.printText('فاتورة ضريبية مبسطة');
}
await SunmiPrinter.printText(CompanyData.companyData!.name!);
await SunmiPrinter.printText('رقم ضريبى : ${CompanyData.companyData!.taxNumber!}');
await SunmiPrinter.printLine();

// 打印发票基础信息
await SunmiPrinter.setFontSize(12);
await SunmiPrinter.setAlignment(SunmiPrintAlign.RIGHT);
await SunmiPrinter.printText('رقم الفاتورة : ${pump.bill!.transaction!}');
await SunmiPrinter.printText('التاريخ : ${pump.bill!.dateTime!}');
await SunmiPrinter.printText('العنوان : ${CompanyData.companyData!.address!}');
await SunmiPrinter.printText('الفرع : ${CompanyData.companyData!.branch!}');
await SunmiPrinter.printLine();

// 打印客户信息(如有)
if(pump.name != null && pump.name!.length>0) {
  await SunmiPrinter.printText('اسم العميل : ${pump.name!}');
  await SunmiPrinter.printText('العنوان : ${pump.address!}');
  await SunmiPrinter.printText('الرقم الضريبي : ${pump.tax_number!}');
  await SunmiPrinter.printLine();
}

// 打印商品表格
await SunmiPrinter.setAlignment(SunmiPrintAlign.CENTER);
await SunmiPrinter.printColumnsText(
  texts: ['الصنف', 'الكمية باللتر', 'السعر', 'الإجمالي'],
  columnWidths: [3, 2, 2, 2],
  columnAlignments: [SunmiPrintAlign.CENTER, SunmiPrintAlign.CENTER, SunmiPrintAlign.CENTER, SunmiPrintAlign.CENTER],
);
await SunmiPrinter.printLine();
await SunmiPrinter.printColumnsText(
  texts: [
    pump.bill!.productName!,
    pump.bill!.volume.toString(),
    pump.bill!.price!.toStringAsFixed(2),
    pump.bill!.amount!.toStringAsFixed(2)
  ],
  columnWidths: [3, 2, 2, 2],
  columnAlignments: [SunmiPrintAlign.CENTER, SunmiPrintAlign.CENTER, SunmiPrintAlign.CENTER, SunmiPrintAlign.CENTER],
);
await SunmiPrinter.printLine();

// 打印总计与税费
await SunmiPrinter.setAlignment(SunmiPrintAlign.RIGHT);
await SunmiPrinter.printText('الإجمالي : ${pump.bill!.amount!.toStringAsFixed(2)} ريال');
await SunmiPrinter.printLine();
final taxRate = (CompanyData.companyData!.tax! * 100).toStringAsFixed(0);
final taxAmount = (pump.bill!.amount! - (pump.bill!.amount! / (1 + CompanyData.companyData!.tax!))).toStringAsFixed(2);
await SunmiPrinter.printText('الضريبة : $taxRate%  $taxAmount ريال');
await SunmiPrinter.printLine();

// 打印二维码
await SunmiPrinter.setAlignment(SunmiPrintAlign.CENTER);
await SunmiPrinter.printQRCode(pump.qr!, size: 150);
await SunmiPrinter.lineWrap(2);

3. 检查字体兼容性

确保HacenTunisia.ttf字体能被打印机正确识别,若转图后字体模糊,可在PDF生成时增大字号,或更换为Sunmi设备内置的阿拉伯字体。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 07:17:35