simple_pdf_generator 0.2.4 copy "simple_pdf_generator: ^0.2.4" to clipboard
simple_pdf_generator: ^0.2.4 copied to clipboard

A lightweight Flutter package to generate PDFs from structured data.

simple_pdf_generator #

A lightweight Flutter package for generating PDFs from structured data with minimal boilerplate.

Overview #

Building PDFs in Flutter often means a lot of repetitive layout code: tables, alignment, row formatting, headers, and footers. This package focuses on that workflow so you can pass structured data (for example maps or API models) and get a usable PDF with a small, readable API.

What it helps with #

  • Less repetitive PDF layout code
  • Tables built from lists and optional column mapping
  • Consistent header and footer blocks
  • Faster reporting, billing, and export features
  • Built-in minimal invoice PDFs (SimplePdf.invoice)

Features #

  • Simple SimplePdf.generate API plus SimplePdf.invoice for structured invoices (reuses the same engine)
  • Multiple tables in a single PDF (tables: List<PdfTable>), or mixed layout via sections: List<PdfSection> (PdfTable, PdfPlainTextBlock for borderless text blocks, and PdfTableRow for side‑by‑side tables)
  • Tables from structured data with optional mapper for dynamic or nested sources
  • Per-table summary sections (summaryHeaders + summaryData)
  • Per-table styling:
    • Table header styling (PdfTableHeaderStyle)
    • Table cell styling (PdfTableCellStyle)
    • Summary styling (PdfSummaryStyle)
  • Multilingual table text support (Unicode) with the package theme font
  • Table body cells can mix text and images (PdfTableCell, or shorthand String / Uint8List in row maps)
  • Page orientation support: portrait (default) and landscape
  • Configurable header (title, subtitle, extra) and optional footer (PdfFooter: text plus optional trailingLines for stacked notes)
  • Small surface area and a thin dependency on pdf

Installation #

Add simple_pdf_generator to your pubspec.yaml.

From pub.dev:

dependencies:
  simple_pdf_generator: ^0.2.4

Run flutter pub get.

Usage #

Import the library:

import 'package:simple_pdf_generator/simple_pdf_generator.dart';

Basic example #

When your rows are already maps whose keys match the column headers:

final pdf = await SimplePdf.generate(
  header: PdfHeader(
    title: 'My Organization',
    subtitle: 'Summary Report',
    extra: '01/01/2026 – 10/01/2026',
  ),
  tables: [
    PdfTable(
      headers: ['Name', 'Age'],
      data: [
        {'Name': 'John', 'Age': 28},
        {'Name': 'Alice', 'Age': 24},
      ],
    ),
  ],
  footer: PdfFooter(text: 'Generated by simple_pdf_generator'),
);

Invoices (SimplePdf.invoice) #

Use SimplePdf.invoice when you want a minimal, predictable invoice without hand-building PdfTable rows. It calls the same pipeline as generate internally: document header, a plain-text “Bill To” block (no table borders), a single line-items table (Description, Quantity, Price, Amount), then a compact footer.

Models: InvoiceData and InvoiceItem (exported from this library).

Field Notes
Required companyName, customerName, items (InvoiceItem: name, quantity, price)
Optional invoiceNumber, date
Customer (optional) customerAddress (supports \n for multiple lines), customerPhone
Footer (optional) amountInWords — shown below the numeric total as Amount in words: …
footerNotes — free text (e.g. office locations, tagline); use \n for multiple lines

Also in generate: you can use PdfPlainTextBlock in sections anywhere you need paragraph-style copy without table chrome. PdfFooter supports trailingLines for any document, not only invoices.

final pdf = await SimplePdf.invoice(
  data: InvoiceData(
    companyName: 'Acme Ltd',
    customerName: 'Jane Buyer',
    customerAddress: '12 High St\nLondon EC1',
    customerPhone: '+44 20 0000 0000',
    invoiceNumber: 'INV-1042',
    date: DateTime.now(),
    amountInWords: 'One thousand two hundred only',
    footerNotes: 'Acme Ltd — London & Manchester\nwww.example.com',
    items: const [
      InvoiceItem(name: 'Consulting (hours)', quantity: 8, price: 150),
      InvoiceItem(name: 'License', quantity: 1, price: 0),
    ],
  ),
);
final bytes = await pdf.save();

invoice accepts the same optional theme, pageLandscape, and pageFormat arguments as generate. Invalid data (empty items, bad quantities/prices, blank required strings) throws ArgumentError.

Coming soon: richer invoice and receipt layouts (tax lines, discounts, logos, stronger styling) and other advanced templates—see Roadmap.

Multilingual text + image cells in tables #

Tables are now designed for mixed content:

  • String / PdfTableCell.text(...) for normal Unicode text (multilingual)
  • PdfTableCell.image(...) or raw Uint8List for image cells in any column

Recommended canonical form: use PdfTableCell so each column’s intent is clear.

  • Text (Unicode / multilingual): PdfTableCell.text('...') or a plain String. Text uses the same document theme as today (bundled Noto by default), so multilingual content renders as normal text in tables.
  • Images: PdfTableCell.image(uint8List, maxWidth: …, maxHeight: …, fit: …). Omitting maxWidth / maxHeight applies defaults of 40×40 PDF points so rows stay compact. fit is a Flutter BoxFit and is mapped to the pdf layout engine (default contain).
  • Shorthand: a raw Uint8List in the row map is treated as image bytes with those same default bounds.

Example with mixed columns (Label, Photo, Amount):

final logoPng = await File('logo.png').readAsBytes();

final pdf = await SimplePdf.generate(
  header: PdfHeader(title: 'Report'),
  tables: [
    PdfTable(
      headers: ['Label', 'Photo', 'Amount'],
      data: [
        {
          'Label': 'Line item',
          'Photo': PdfTableCell.image(logoPng, maxWidth: 32, maxHeight: 32),
          'Amount': r'$10.00',
        },
        {
          'Label': 'Another row',
          'Photo': logoPng, // same as image cell with default 40×40 max size
          'Amount': '5.00',
        },
      ],
    ),
  ],
);

String-only tables are unchanged and still use the existing fast text-table path.

In short: existing string tables keep working without changes, and now the same table can also include image cells when needed.

Using a mapper #

Use mapper when your source data does not match header names (for example API or database records):

final pdf = await SimplePdf.generate(
  header: PdfHeader(title: 'Report'),
  tables: [
    PdfTable(
      headers: ['Date', 'Amount'],
      data: apiResponse,
      mapper: (item) => {
        'Date': item['date'].toString(),
        'Amount': item['amount'].toString(),
      },
    ),
  ],
);

Page orientation (portrait / landscape) #

SimplePdf.generate supports both portrait and landscape pages:

  • Portrait (default): no extra flag needed
  • Landscape: set pageLandscape: true
  • Custom page format: pass pageFormat; when provided, it overrides pageLandscape
final pdf = await SimplePdf.generate(
  header: PdfHeader(title: 'Landscape report'),
  tables: [
    PdfTable(
      headers: ['Name', 'Address', 'Present', 'Total Days', 'Attd.'],
      data: rows,
    ),
  ],
  pageLandscape: true, // A4 landscape
);

Side-by-side tables (PdfTableRow) #

Use sections when you need a full-width table and then several tables on one horizontal row (equal width per table, with gaps). Each PdfTable still owns its own headerStyle, cellStyle, and summary.

  • Pass sections: [ ... ] where each element is a PdfTable or a PdfTableRow.
  • If sections is non-null and not empty, it is used and tables / table are ignored.
  • PdfTableRow options: horizontalGap, verticalPaddingBefore, verticalPaddingAfter (defaults: 8 / 12 / 12 pt). Normal vertical spacing between sections still applies (kSimplePdfTableSpacing).
  • Validation: before layout, each table’s estimated minimum width is compared to its share of the page body width (pageFormat.availableWidth). If any table does not fit, generation throws StateError with:
    Tables exceed available width in PdfTableRow. Reduce columns or number of tables.
  • Tables inside a row cannot use startOnNewPage: true.
final pdf = await SimplePdf.generate(
  header: PdfHeader(title: 'Dashboard'),
  sections: [
    PdfTable(
      headers: ['Metric', 'Value'],
      data: const [
        {'Metric': 'Total', 'Value': '100'},
      ],
    ),
    PdfTableRow(
      tables: [
        PdfTable(headers: ['A'], data: const [{'A': '1'}]),
        PdfTable(headers: ['B'], data: const [{'B': '2'}]),
      ],
    ),
    PdfTable(
      headers: ['Note'],
      data: const [{'Note': 'Full width again'}],
    ),
  ],
);

Sample PDF mixing full-width tables with 2-up and 3-up PdfTableRow sections:

Sample PDF: PdfTableRow side-by-side tables demo

Multiple tables + per-table summary #

final pdf = await SimplePdf.generate(
  header: PdfHeader(title: 'Daily Report'),
  tables: [
    PdfTable(
      headers: ['Date', 'Qty'],
      data: dailyRows,
    ),
    PdfTable(
      headers: ['Item', 'Amount'],
      data: billingRows,
      summaryHeaders: const ['Label', 'Value'],
      summaryData: const [
        ['Subtotal', '4500'],
        ['Tax', '225'],
        ['Total', '4725'],
      ],
    ),
  ],
);

Multi-table report example (with per-table summaries) #

final pdf = await SimplePdf.generate(
  header: PdfHeader(
    title: 'Springfield School',
    subtitle: 'Students Report',
    extra: 'Term 1 - 2026',
  ),
  tables: [
    PdfTable(
      headers: ['Student', 'Math', 'Science', 'English', 'Total'],
      data: marksRows,
      summaryHeaders: const ['Metric', 'Value'],
      summaryData: const [
        ['Students', '2'],
        ['Avg Math', '86.5'],
        ['Avg Science', '80.0'],
        ['Avg English', '83.5'],
        ['Avg Total / Student', '250.0'],
      ],
    ),
    PdfTable(
      headers: ['Student', 'Present', 'Total Days', 'Attendance %'],
      data: attendanceRows,
      summaryHeaders: const ['Metric', 'Value'],
      summaryData: const [
        ['Students', '2'],
        ['Total Present Days', '82'],
        ['Total School Days', '90'],
        ['Overall Attendance %', '91.1%'],
      ],
    ),
  ],
  footer: PdfFooter(text: 'Generated by simple_pdf_generator'),
);

Styling (header, cells, and summary) #

final pdf = await SimplePdf.generate(
  header: PdfHeader(title: 'Styled Report'),
  tables: [
    PdfTable(
      headers: ['A', 'B'],
      data: rows,
      headerStyle: const PdfTableHeaderStyle(
        backgroundColor: SimplePdfColor.blue100,
        textColor: SimplePdfColor.blue900,
      ),
      cellStyle: const PdfTableCellStyle(
        fontSize: 12,
        textColor: SimplePdfColor.grey900,
        fontFamily: PdfFontFamily.poppins,
      ),
      summaryHeaders: const ['Label', 'Value'],
      summaryData: const [
        ['Total', '5000'],
        ['Tax', '250'],
      ],
      summaryStyle: const PdfSummaryStyle(
        headerStyle: PdfSummaryHeaderStyle(
          backgroundColor: SimplePdfColor.grey100,
          textColor: SimplePdfColor.grey700,
        ),
        cellStyle: PdfSummaryCellStyle(
          labelColor: SimplePdfColor.grey800,
          valueColor: SimplePdfColor.blue900,
        ),
        backgroundColor: SimplePdfColor.grey50,
        fontFamily: PdfFontFamily.lato,
      ),
    ),
  ],
);

generate returns a Document from the pdf package. Persist it with save():

import 'dart:io';

// ...

final bytes = await pdf.save();
final file = File('${directory.path}/report.pdf');
await file.writeAsBytes(bytes);

To open the file on device, you can use packages such as path_provider and open_file_safe. See the example/ app in this repository for a full flow.

Example output #

The following sample was generated with the example app: header, tabular data (with a mapper), and footer.

Sample PDF: summary report with table

Multi-table example with per-table summaries:

Sample PDF: multi table with summaries

Multilingual table example (Unicode text in table cells):

Sample PDF: multilingual table text

PdfTableRow demo (full-width tables plus side-by-side tables in one row):

Sample PDF: PdfTableRow demo

More advanced formats and templates are on the way—see Roadmap.

API summary #

Type Role
SimplePdf generate(...) builds general PDFs; invoice(...) builds a minimal invoice from InvoiceData
InvoiceData / InvoiceItem Structured input for SimplePdf.invoice
PdfHeader title (required), optional subtitle, extra
PdfSection Base type: PdfTable, PdfPlainTextBlock, or PdfTableRow for sections
PdfPlainTextBlock Optional title + lines: borderless stacked text (e.g. “Bill To”)
PdfTable headers, data, optional mapper, optional per-table summary + styling
PdfTableRow tables: several PdfTables in one horizontal row (equal width)
PdfTableCell text or image cell for mixed text/PNG (or String / Uint8List in maps)
PdfFooter Optional text; optional trailingLines (extra stacked lines)

Roadmap #

  • Advanced formats (coming soon): richer invoices and receipts (tax, discounts, logos, layout presets), plus more document templates beyond the current minimal invoice
  • Sorting and richer formatting
  • Multi-language support
  • More layout options (alignment, spacing, section layouts)

Contributing #

Issues and pull requests are welcome.

License #

MIT License. See LICENSE.

4
likes
150
points
419
downloads

Documentation

API reference

Publisher

verified publishermohsinpatel.online

Weekly Downloads

A lightweight Flutter package to generate PDFs from structured data.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, pdf

More

Packages that depend on simple_pdf_generator