[{"data":1,"prerenderedAt":86},["ShallowReactive",2],{"tutorial-generare-documenti-pdf-in-flutter-con-i-pacchetti-pdf-e-printing":3,"comments-tutorial-generare-documenti-pdf-in-flutter-con-i-pacchetti-pdf-e-printing":85},{"id":4,"title":5,"slug":6,"excerpt":7,"intro":8,"cover_image":9,"cover_remote_url":10,"cover_credit":11,"video_url":15,"video":16,"difficulty":20,"estimated_minutes":21,"flutter_version":22,"status":23,"published_at":24,"meta_title":25,"meta_description":26,"category":27,"author":31,"steps":33},122,"Generare documenti PDF in Flutter con i pacchetti pdf e printing","generare-documenti-pdf-in-flutter-con-i-pacchetti-pdf-e-printing","Crea fatture PDF dinamiche in Flutter: layout multipagina con header e footer, tabelle, font e logo personalizzati, anteprima di stampa, salvataggio su file e condivisione.","Prima o poi ogni app gestionale, di e-commerce o di field service si scontra con la stessa richiesta: \"possiamo esportare questo in PDF?\". In Flutter la risposta è il duo **pdf** (per costruire il documento) e **printing** (per anteprima, stampa e condivisione), due pacchetti dello stesso autore che funzionano su Android, iOS, web, macOS, Windows e Linux.\n\nLa cosa più interessante è che il pacchetto `pdf` espone una libreria di widget dichiarativi molto simile a quella di Flutter: `Column`, `Row`, `Container`, `Table`, `Padding`... ma importata con il prefisso `pw` e con un proprio sistema di layout pensato per le pagine di carta. Chi conosce Flutter si trova subito a casa, a patto di tenere ben separati i due mondi: i widget di `package:flutter\u002Fwidgets.dart` **non** sono utilizzabili dentro un PDF e viceversa.\n\nIn questo tutorial costruiremo una **fattura PDF dinamica**: partiremo dal modello dati, genereremo un documento multipagina con intestazione, tabella delle righe, totali e numerazione delle pagine, aggiungeremo font e logo personalizzati, mostreremo l'anteprima di stampa e infine salveremo e condivideremo il file. Chiuderemo con alcune best practice su performance e isolate.\n\n> Prerequisiti: progetto Flutter 3.x funzionante, conoscenza di base di widget, `Future` e `async\u002Fawait`.","https:\u002F\u002Fflutter.it\u002Fstorage\u002Ftutorials\u002Ff8d9fff2-f511-4826-aeda-d1d4021927b3.jpg","https:\u002F\u002Fimages.unsplash.com\u002Fphoto-1731074803853-85bf47533599?crop=entropy&cs=tinysrgb&fit=max&fm=jpg&ixid=M3w5NzA2NTJ8MHwxfHJhbmRvbXx8fHx8fHx8fDE3OTE3Nzk1MTh8&ixlib=rb-4.1.0&q=80&w=1080",{"name":12,"author_url":13,"photo_url":14},"Brett Jordan","https:\u002F\u002Funsplash.com\u002F@brett_jordan","https:\u002F\u002Funsplash.com\u002Fphotos\u002Fa-close-up-of-an-open-book-with-text-on-it-0p4ptxByEyE","https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=M555As97d5M",{"youtube_id":17,"duration_seconds":18,"published_at":19},"M555As97d5M",153,"2026-10-12T12:35:18+00:00","intermediate",45,"3.x","published","2026-10-12T04:31:58+00:00","Generare PDF in Flutter con pdf e printing","Guida pratica per creare fatture PDF in Flutter: layout multipagina, tabelle, font e logo, anteprima di stampa, salvataggio su file e condivisione.",{"id":28,"name":29,"slug":30},1,"Guide","guide",{"id":28,"name":32},"Flutter Bot",[34,42,50,57,64,71,78],{"id":35,"position":28,"title":36,"body":37,"code_snippet":38,"code_language":39,"expected_result":40,"demo_url":41,"video_url":41},815,"Installare le dipendenze e preparare gli asset","Aggiungiamo al progetto i pacchetti necessari:\n\n- **pdf**: costruisce il documento (widget `pw.*`, salvataggio in `Uint8List`).\n- **printing**: anteprima, stampa, condivisione e accesso ai Google Fonts già pronti per il PDF.\n- **path_provider**: per ottenere una cartella dove salvare il file.\n- **share_plus**: per condividere il PDF con altre app (opzionale, `printing` offre già `Printing.sharePdf`).\n- **intl**: per formattare date e valute in italiano.\n\nEseguiamo dal terminale:\n\n```bash\nflutter pub add pdf printing path_provider share_plus intl\n```\n\nSe vuoi inserire un logo aziendale, copia l'immagine in `assets\u002Fimages\u002Flogo.png` e dichiarala nel `pubspec.yaml`.\n\n**Nota piattaforme**: su Android non serve alcun permesso se salvi nelle cartelle dell'app (`getApplicationDocumentsDirectory` o `getTemporaryDirectory`). Su Flutter Web la stampa apre il dialog del browser e il salvataggio avviene tramite download, quindi evita `dart:io` dietro a controlli di piattaforma.","# pubspec.yaml\ndependencies:\n  flutter:\n    sdk: flutter\n  pdf: ^3.11.1\n  printing: ^5.13.2\n  path_provider: ^2.1.4\n  share_plus: ^10.1.2\n  intl: ^0.19.0\n\nflutter:\n  assets:\n    - assets\u002Fimages\u002Flogo.png","yaml","`flutter pub get` termina senza errori e l'asset del logo è dichiarato nel pubspec.yaml.",null,{"id":43,"position":44,"title":45,"body":46,"code_snippet":47,"code_language":48,"expected_result":49,"demo_url":41,"video_url":41},816,2,"Definire il modello dati della fattura","Prima di disegnare il PDF conviene avere un modello dati pulito: il generatore del documento deve limitarsi a *rappresentare* i dati, non a calcolarli. Creiamo `lib\u002Fmodels\u002Finvoice.dart` con due classi immutabili e qualche getter per subtotale, IVA e totale.\n\nMantenere la logica di calcolo nel modello rende il codice testabile con normali unit test, senza dover generare un PDF per verificare che i totali siano corretti.","\u002F\u002F lib\u002Fmodels\u002Finvoice.dart\nclass InvoiceItem {\n  final String description;\n  final int quantity;\n  final double unitPrice;\n\n  const InvoiceItem({\n    required this.description,\n    required this.quantity,\n    required this.unitPrice,\n  });\n\n  double get total => quantity * unitPrice;\n}\n\nclass Invoice {\n  final String number;\n  final DateTime date;\n  final String customerName;\n  final String customerAddress;\n  final List\u003CInvoiceItem> items;\n  final double vatRate;\n\n  const Invoice({\n    required this.number,\n    required this.date,\n    required this.customerName,\n    required this.customerAddress,\n    required this.items,\n    this.vatRate = 0.22,\n  });\n\n  double get subtotal =>\n      items.fold(0.0, (sum, item) => sum + item.total);\n\n  double get vat => subtotal * vatRate;\n\n  double get total => subtotal + vat;\n}","dart","Il modello compila e `subtotal`, `vat` e `total` restituiscono i valori attesi per una lista di righe di esempio.",{"id":51,"position":52,"title":53,"body":54,"code_snippet":55,"code_language":48,"expected_result":56,"demo_url":41,"video_url":41},817,3,"Costruire il documento PDF multipagina con MultiPage","Ora il cuore del tutorial. Creiamo un servizio `InvoicePdfService` che restituisce i byte del PDF (`Uint8List`): questa firma è perfetta perché è esattamente ciò che si aspettano `Printing.layoutPdf`, `PdfPreview` e `File.writeAsBytes`.\n\nPunti chiave:\n\n- `pw.MultiPage` spezza automaticamente il contenuto su più pagine quando `build` restituisce una lista di widget troppo alta: ideale per fatture con molte righe.\n- `header` e `footer` sono callback invocate per **ogni** pagina e ricevono un `pw.Context` da cui leggere `pageNumber` e `pagesCount`.\n- `pw.TableHelper.fromTextArray` genera rapidamente una tabella con intestazione, allineamenti e stili per cella (in passato era `pw.Table.fromTextArray`, oggi deprecato).\n- Tutte le misure si esprimono in **punti PDF** (1 punto = 1\u002F72 di pollice); usa le costanti `PdfPageFormat.cm` e `PdfPageFormat.mm` per ragionare in unità familiari.\n\nAttenzione all'import: i widget del PDF vanno importati con il prefisso `pw` per non entrare in conflitto con quelli di Flutter.","\u002F\u002F lib\u002Fservices\u002Finvoice_pdf_service.dart\nimport 'dart:typed_data';\n\nimport 'package:intl\u002Fintl.dart';\nimport 'package:pdf\u002Fpdf.dart';\nimport 'package:pdf\u002Fwidgets.dart' as pw;\n\nimport '..\u002Fmodels\u002Finvoice.dart';\n\nclass InvoicePdfService {\n  final _currency = NumberFormat.currency(locale: 'it_IT', symbol: '€');\n  final _dateFormat = DateFormat('dd\u002FMM\u002Fyyyy', 'it_IT');\n\n  Future\u003CUint8List> build(Invoice invoice) async {\n    final doc = pw.Document(title: 'Fattura ${invoice.number}');\n\n    doc.addPage(\n      pw.MultiPage(\n        pageFormat: PdfPageFormat.a4,\n        margin: const pw.EdgeInsets.all(32),\n        header: (context) => _header(invoice),\n        footer: (context) => pw.Container(\n          alignment: pw.Alignment.centerRight,\n          child: pw.Text(\n            'Pagina ${context.pageNumber} di ${context.pagesCount}',\n            style: const pw.TextStyle(fontSize: 9, color: PdfColors.grey600),\n          ),\n        ),\n        build: (context) => [\n          _customerBox(invoice),\n          pw.SizedBox(height: 24),\n          _itemsTable(invoice),\n          pw.SizedBox(height: 16),\n          _totals(invoice),\n        ],\n      ),\n    );\n\n    return doc.save();\n  }\n\n  pw.Widget _header(Invoice invoice) => pw.Column(\n        crossAxisAlignment: pw.CrossAxisAlignment.start,\n        children: [\n          pw.Row(\n            mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,\n            children: [\n              pw.Text('Acme S.r.l.',\n                  style: pw.TextStyle(\n                      fontSize: 20, fontWeight: pw.FontWeight.bold)),\n              pw.Column(\n                crossAxisAlignment: pw.CrossAxisAlignment.end,\n                children: [\n                  pw.Text('Fattura n. ${invoice.number}'),\n                  pw.Text(_dateFormat.format(invoice.date),\n                      style: const pw.TextStyle(color: PdfColors.grey700)),\n                ],\n              ),\n            ],\n          ),\n          pw.Divider(thickness: 1, color: PdfColors.grey400),\n        ],\n      );\n\n  pw.Widget _customerBox(Invoice invoice) => pw.Container(\n        padding: const pw.EdgeInsets.all(12),\n        decoration: pw.BoxDecoration(\n          border: pw.Border.all(color: PdfColors.grey400),\n          borderRadius: pw.BorderRadius.circular(6),\n        ),\n        child: pw.Column(\n          crossAxisAlignment: pw.CrossAxisAlignment.start,\n          children: [\n            pw.Text('Destinatario',\n                style: pw.TextStyle(\n                    fontSize: 10,\n                    fontWeight: pw.FontWeight.bold,\n                    color: PdfColors.grey700)),\n            pw.SizedBox(height: 4),\n            pw.Text(invoice.customerName),\n            pw.Text(invoice.customerAddress),\n          ],\n        ),\n      );\n\n  pw.Widget _itemsTable(Invoice invoice) => pw.TableHelper.fromTextArray(\n        headers: ['Descrizione', 'Q.tà', 'Prezzo', 'Totale'],\n        data: invoice.items\n            .map((item) => [\n                  item.description,\n                  '${item.quantity}',\n                  _currency.format(item.unitPrice),\n                  _currency.format(item.total),\n                ])\n            .toList(),\n        headerStyle: pw.TextStyle(fontWeight: pw.FontWeight.bold),\n        headerDecoration: const pw.BoxDecoration(color: PdfColors.grey300),\n        cellAlignments: {\n          0: pw.Alignment.centerLeft,\n          1: pw.Alignment.center,\n          2: pw.Alignment.centerRight,\n          3: pw.Alignment.centerRight,\n        },\n        columnWidths: {\n          0: const pw.FlexColumnWidth(4),\n          1: const pw.FlexColumnWidth(1),\n          2: const pw.FlexColumnWidth(2),\n          3: const pw.FlexColumnWidth(2),\n        },\n      );\n\n  pw.Widget _totals(Invoice invoice) => pw.Align(\n        alignment: pw.Alignment.centerRight,\n        child: pw.SizedBox(\n          width: 220,\n          child: pw.Column(\n            children: [\n              _totalRow('Imponibile', _currency.format(invoice.subtotal)),\n              _totalRow('IVA ${(invoice.vatRate * 100).toStringAsFixed(0)}%',\n                  _currency.format(invoice.vat)),\n              pw.Divider(),\n              _totalRow('Totale', _currency.format(invoice.total), bold: true),\n            ],\n          ),\n        ),\n      );\n\n  pw.Widget _totalRow(String label, String value, {bool bold = false}) {\n    final style = pw.TextStyle(\n      fontWeight: bold ? pw.FontWeight.bold : pw.FontWeight.normal,\n      fontSize: bold ? 14 : 11,\n    );\n    return pw.Padding(\n      padding: const pw.EdgeInsets.symmetric(vertical: 2),\n      child: pw.Row(\n        mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,\n        children: [pw.Text(label, style: style), pw.Text(value, style: style)],\n      ),\n    );\n  }\n}","Il servizio compila e `build(invoice)` restituisce un `Uint8List` non vuoto contenente il PDF della fattura.",{"id":58,"position":59,"title":60,"body":61,"code_snippet":62,"code_language":48,"expected_result":63,"demo_url":41,"video_url":41},818,4,"Aggiungere font personalizzati, caratteri accentati e logo","I font Helvetica integrati nel PDF supportano i caratteri latini di base, ma possono creare problemi con simboli particolari (€ in alcuni contesti, emoji, alfabeti non latini) e offrono poca personalizzazione. Due strade:\n\n1. **Google Fonts già pronti** tramite `printing`: `PdfGoogleFonts.nunitoRegular()` scarica e memorizza in cache il font (richiede rete alla prima esecuzione).\n2. **Font locale negli asset**: più affidabile offline, basta caricare il `.ttf` con `rootBundle` e `pw.Font.ttf`.\n\nIl font si applica a tutto il documento tramite `pw.ThemeData.withFont(...)` passato a `pw.Document(theme: ...)` o al `pageTheme`. Il logo invece si carica come `pw.MemoryImage` a partire dai byte dell'asset.\n\nImportante: carica font e immagini **una sola volta** e passali al builder, evitando di rileggere il bundle a ogni pagina.","import 'package:flutter\u002Fservices.dart' show rootBundle;\nimport 'package:printing\u002Fprinting.dart';\n\n\u002F\u002F Dentro InvoicePdfService\nFuture\u003CUint8List> buildStyled(Invoice invoice) async {\n  \u002F\u002F 1. Font: da Google Fonts (rete) oppure dagli asset locali\n  final regular = await PdfGoogleFonts.nunitoRegular();\n  final bold = await PdfGoogleFonts.nunitoBold();\n  \u002F\u002F Alternativa offline:\n  \u002F\u002F final regular = pw.Font.ttf(await rootBundle.load('assets\u002Ffonts\u002FNunito-Regular.ttf'));\n\n  \u002F\u002F 2. Logo dagli asset\n  final logoBytes = await rootBundle.load('assets\u002Fimages\u002Flogo.png');\n  final logo = pw.MemoryImage(logoBytes.buffer.asUint8List());\n\n  final doc = pw.Document(\n    title: 'Fattura ${invoice.number}',\n    theme: pw.ThemeData.withFont(base: regular, bold: bold),\n  );\n\n  doc.addPage(\n    pw.MultiPage(\n      pageFormat: PdfPageFormat.a4,\n      margin: const pw.EdgeInsets.all(32),\n      header: (context) => pw.Row(\n        mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,\n        crossAxisAlignment: pw.CrossAxisAlignment.start,\n        children: [\n          pw.SizedBox(height: 48, width: 48, child: pw.Image(logo)),\n          pw.Text('Fattura n. ${invoice.number}',\n              style: pw.TextStyle(fontSize: 16, fontWeight: pw.FontWeight.bold)),\n        ],\n      ),\n      build: (context) => [\n        _customerBox(invoice),\n        pw.SizedBox(height: 24),\n        _itemsTable(invoice),\n        pw.SizedBox(height: 16),\n        _totals(invoice),\n      ],\n    ),\n  );\n\n  return doc.save();\n}","Il PDF mostra il logo in alto a sinistra e tutti i testi, accenti e simbolo euro inclusi, resi con il font scelto.",{"id":65,"position":66,"title":67,"body":68,"code_snippet":69,"code_language":48,"expected_result":70,"demo_url":41,"video_url":41},819,5,"Mostrare l'anteprima e stampare con il pacchetto printing","Il pacchetto `printing` offre due approcci complementari:\n\n- **`PdfPreview`**: un widget a schermo intero con zoom, scorrimento pagine e una barra azioni (stampa, condividi, salva). Perfetto per una schermata \"Anteprima documento\".\n- **`Printing.layoutPdf`**: apre direttamente il dialog di stampa di sistema, utile quando l'utente ha già visto i dati nella UI dell'app.\n\n`PdfPreview` richiede una callback `build` che riceve il `PdfPageFormat` scelto dall'utente e restituisce i byte: questo permette, se vuoi, di rigenerare il documento in A4 o Letter al volo. Attenzione a non ricostruire il PDF a ogni `setState`: usa `useActions`, `canChangePageFormat` e memorizza il risultato quando la generazione è costosa.","import 'package:flutter\u002Fmaterial.dart';\nimport 'package:printing\u002Fprinting.dart';\n\nimport '..\u002Fmodels\u002Finvoice.dart';\nimport '..\u002Fservices\u002Finvoice_pdf_service.dart';\n\nclass InvoicePreviewPage extends StatelessWidget {\n  const InvoicePreviewPage({super.key, required this.invoice});\n\n  final Invoice invoice;\n\n  @override\n  Widget build(BuildContext context) {\n    final service = InvoicePdfService();\n\n    return Scaffold(\n      appBar: AppBar(\n        title: Text('Fattura ${invoice.number}'),\n        actions: [\n          IconButton(\n            icon: const Icon(Icons.print),\n            tooltip: 'Stampa',\n            onPressed: () => Printing.layoutPdf(\n              name: 'fattura_${invoice.number}.pdf',\n              onLayout: (format) => service.build(invoice),\n            ),\n          ),\n        ],\n      ),\n      body: PdfPreview(\n        build: (format) => service.build(invoice),\n        canChangePageFormat: false,\n        canDebug: false,\n        pdfFileName: 'fattura_${invoice.number}.pdf',\n        loadingWidget: const Center(child: CircularProgressIndicator()),\n      ),\n    );\n  }\n}","Aprendo la pagina vedi l'anteprima scorrevole del PDF; toccando l'icona di stampa si apre il dialog di stampa del sistema operativo.",{"id":72,"position":73,"title":74,"body":75,"code_snippet":76,"code_language":48,"expected_result":77,"demo_url":41,"video_url":41},820,6,"Salvare il PDF su file e condividerlo","Per archiviare il documento o inviarlo via email\u002FWhatsApp serve scriverlo su disco. Usiamo `path_provider` per ottenere una directory valida su tutte le piattaforme mobile\u002Fdesktop:\n\n- `getTemporaryDirectory()` per file usa-e-getta da condividere subito (il sistema può ripulirli);\n- `getApplicationDocumentsDirectory()` per documenti che l'utente deve ritrovare nell'app.\n\nPer la condivisione hai due opzioni: `Printing.sharePdf` (zero configurazione, già inclusa) oppure `share_plus`, utile se devi condividere più file insieme o aggiungere testo e oggetto. Su Flutter Web evita `dart:io`: usa `Printing.sharePdf`, che gestisce il download del file dal browser.","import 'dart:io';\nimport 'dart:typed_data';\n\nimport 'package:flutter\u002Ffoundation.dart' show kIsWeb;\nimport 'package:path_provider\u002Fpath_provider.dart';\nimport 'package:printing\u002Fprinting.dart';\nimport 'package:share_plus\u002Fshare_plus.dart';\n\nFuture\u003CFile> savePdf(Uint8List bytes, String fileName) async {\n  final dir = await getApplicationDocumentsDirectory();\n  final file = File('${dir.path}\u002F$fileName');\n  return file.writeAsBytes(bytes, flush: true);\n}\n\nFuture\u003Cvoid> sharePdf(Uint8List bytes, String fileName) async {\n  if (kIsWeb) {\n    \u002F\u002F Sul web avvia il download \u002F la condivisione nativa del browser\n    await Printing.sharePdf(bytes: bytes, filename: fileName);\n    return;\n  }\n\n  final dir = await getTemporaryDirectory();\n  final file = File('${dir.path}\u002F$fileName');\n  await file.writeAsBytes(bytes, flush: true);\n\n  await Share.shareXFiles(\n    [XFile(file.path, mimeType: 'application\u002Fpdf')],\n    subject: 'Fattura',\n    text: 'In allegato la fattura in formato PDF.',\n  );\n}","Il file viene scritto nella cartella dell'app e il foglio di condivisione del sistema mostra il PDF allegato, apribile con un lettore esterno.",{"id":79,"position":80,"title":81,"body":82,"code_snippet":83,"code_language":48,"expected_result":84,"demo_url":41,"video_url":41},821,7,"Ottimizzare: generazione in isolate, caching e test","La generazione di un PDF con centinaia di righe o immagini pesanti può bloccare il thread UI. Alcune accortezze:\n\n**1. Sposta il lavoro su un isolate con `compute`.** La costruzione del documento è pura CPU: può girare fuori dal thread UI. Il vincolo è che `rootBundle` e la rete non sono direttamente disponibili in un isolate secondario, quindi **carica font e immagini sul main isolate** e passali come `Uint8List` nel payload.\n\n**2. Metti in cache i byte.** Se l'utente apre l'anteprima e poi stampa, non rigenerare: conserva il `Future\u003CUint8List>` o il risultato in memoria.\n\n**3. Comprimi le immagini** prima di inserirle: un JPEG a 1000 px di larghezza è più che sufficiente per la stampa di un logo o di una foto di report, mentre un PNG 4000×3000 fa esplodere la dimensione del file.\n\n**4. Testa il PDF.** Puoi scrivere unit test che generano il documento e verificano che i byte inizino con l'header `%PDF` e che la dimensione sia plausibile; per una verifica visiva usa `Printing.raster` per convertire le pagine in immagini e confrontarle con un golden test.\n\nCon queste basi puoi estendere il generatore a ricevute, report con grafici (renderizzando un widget Flutter in immagine con `RepaintBoundary` e inserendolo come `pw.MemoryImage`) o etichette per stampanti termiche.","import 'dart:typed_data';\nimport 'package:flutter\u002Ffoundation.dart';\nimport 'package:pdf\u002Fwidgets.dart' as pw;\n\nclass PdfPayload {\n  final Invoice invoice;\n  final Uint8List regularFont;\n  final Uint8List logo;\n\n  const PdfPayload(this.invoice, this.regularFont, this.logo);\n}\n\n\u002F\u002F Funzione top-level: requisito per compute()\nUint8List buildInvoiceSync(PdfPayload payload) {\n  final doc = pw.Document(\n    theme: pw.ThemeData.withFont(\n      base: pw.Font.ttf(payload.regularFont.buffer.asByteData()),\n    ),\n  );\n  final logo = pw.MemoryImage(payload.logo);\n\n  doc.addPage(\n    pw.MultiPage(\n      header: (_) => pw.SizedBox(height: 40, child: pw.Image(logo)),\n      build: (_) => [\n        pw.Text('Fattura n. ${payload.invoice.number}'),\n        \u002F\u002F ...resto del layout\n      ],\n    ),\n  );\n\n  return Uint8List.fromList(doc.save() as List\u003Cint>);\n}\n\n\u002F\u002F Nel widget: asset caricati sul main isolate, PDF generato fuori\nFuture\u003CUint8List> generateInBackground(Invoice invoice) async {\n  final fontData = await rootBundle.load('assets\u002Ffonts\u002FNunito-Regular.ttf');\n  final logoData = await rootBundle.load('assets\u002Fimages\u002Flogo.png');\n\n  return compute(\n    buildInvoiceSync,\n    PdfPayload(\n      invoice,\n      fontData.buffer.asUint8List(),\n      logoData.buffer.asUint8List(),\n    ),\n  );\n}","Anche con fatture molto lunghe l'interfaccia resta fluida durante la generazione e il PDF prodotto è identico a quello creato sul main isolate.",[],1792316904458]