simple_pdf_generator 0.2.1
simple_pdf_generator: ^0.2.1 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
Features #
- Simple
SimplePdf.generateAPI - Multiple tables in a single PDF (
tables: List<PdfTable>) - Tables from structured data with optional
mapperfor dynamic or nested sources - Per-table summary sections (
summaryHeaders+summaryData) - Per-table styling:
- Table header styling (
PdfTableHeaderStyle) - Table cell styling (
PdfTableCellStyle) - Summary styling (
PdfSummaryStyle)
- Table header styling (
- Multilingual table text support (Unicode) with the package theme font
- Table body cells can mix text and images (
PdfTableCell, or shorthandString/Uint8Listin row maps) - Configurable header (
title,subtitle,extra) and optional footer - 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.0
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'),
);
Multilingual text + image cells in tables #
Tables are now designed for mixed content:
String/PdfTableCell.text(...)for normal Unicode text (multilingual)PdfTableCell.image(...)or rawUint8Listfor image cells in any column
Recommended canonical form: use PdfTableCell so each column’s intent is clear.
- Text (Unicode / multilingual):
PdfTableCell.text('...')or a plainString. 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: …). OmittingmaxWidth/maxHeightapplies defaults of 40×40 PDF points so rows stay compact.fitis a FlutterBoxFitand is mapped to thepdflayout engine (defaultcontain). - Shorthand: a raw
Uint8Listin 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(),
},
),
],
);
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.

Multi-table example with per-table summaries:

Multilingual table example (Unicode text in table cells):

More features are on the way—see Roadmap for planned work.
API summary #
| Type | Role |
|---|---|
SimplePdf |
generate(...) builds the PDF document |
PdfHeader |
title (required), optional subtitle, extra |
PdfTable |
headers, data, optional mapper, optional per-table summary + styling |
PdfTableCell |
text or image cell for mixed text/PNG (or String / Uint8List in maps) |
PdfFooter |
Optional text |
Roadmap #
- Multiple templates (invoice, receipt, and similar)
- 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.