Dart PDF
最后修改日期:2024 年 1 月 28 日
在本文中,我们将展示如何在 Dart 语言中创建 PDF 文档。
便携式文档格式 (PDF) 是 Adobe 创建的一种多功能文件格式,它为人们提供了一种简单可靠的方式来展示和交换文档。
$ dart pub add pdf
要在 Dart 中生成 PDF 文件,我们使用 pdf 包。
Dart PDF 简单示例
以下是一个简单的 Dart 示例,用于生成 PDF 文档。
import 'dart:io';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
void main() async {
final pdf = pw.Document();
pdf.addPage(pw.Page(
pageFormat: PdfPageFormat.a4,
build: (pw.Context context) {
return pw.Center(
child: pw.Text("An old falcon"),
);
}));
final file = File('simple.pdf');
await file.writeAsBytes(await pdf.save());
}
该程序创建一个新的 PDF 文件并将其写入磁盘。它包含居中文本。
import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw;
我们导入所需的包。
final pdf = pw.Document();
创建一个新的空文档。
pdf.addPage(pw.Page(
pageFormat: PdfPageFormat.a4,
build: (pw.Context context) {
return pw.Center(
child: pw.Text("An old falcon"),
);
}));
使用 addPage 添加一页。我们提供页面格式和内容。内容由一个 Text 小部件组成,该小部件使用 Center 在页面上居中。
final file = File('simple.pdf');
await file.writeAsBytes(await pdf.save());
文档被写入文件。
Dart PDF 页眉
使用 Header 创建文档页眉。
import 'dart:io';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
void main() async {
final txt = '''
The Battle of Thermopylae was fought between an alliance of Greek city-states,
led by King Leonidas of Sparta, and the Persian Empire of Xerxes I over the
course of three days, during the second Persian invasion of Greece.
''';
final pdf = pw.Document();
pdf.addPage(pw.Page(
pageFormat: PdfPageFormat.a4,
build: (pw.Context context) {
return pw.Column(children: [
pw.Header(level: 0, text: 'The Battle of Thermopylae'),
pw.Paragraph(text: txt)
]);
},
));
final file = File('header.pdf');
await file.writeAsBytes(await pdf.save());
}
文档包含页眉和一段文本。
pdf.addPage(pw.Page(
pageFormat: PdfPageFormat.a4,
build: (pw.Context context) {
return pw.Column(children: [
pw.Header(level: 0, text: 'The Battle of Thermopylae'),
pw.Paragraph(text: txt)
]);
},
));
页眉和段落被添加到列小部件中。我们为页眉指定级别和文本,为段落指定文本。
Dart PDF 列表项
使用 Bullet 小部件创建列表项。
import 'dart:io';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
void main() async {
final pdf = pw.Document();
pdf.addPage(pw.Page(
pageFormat: PdfPageFormat.a4,
build: (pw.Context context) {
return pw.Column(children: [
pw.Header(level: 1, text: 'Programming languages'),
pw.Bullet(text: 'Dart'),
pw.Bullet(text: 'F#'),
pw.Bullet(text: 'Clojure'),
pw.Bullet(text: 'Go'),
pw.Bullet(text: 'Groovy'),
pw.Bullet(text: 'Raku'),
pw.Bullet(text: 'Python'),
]);
}));
final file = File('bullets.pdf');
await file.writeAsBytes(await pdf.save());
}
我们有一个页眉和一系列编程语言。每种语言都显示为一个列表项。
Dart PDF 矩形
使用 Rectangle 创建一个矩形。
import 'dart:io';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
void main() async {
final pdf = pw.Document();
pdf.addPage(pw.Page(
pageFormat: PdfPageFormat.a4,
build: (pw.Context context) {
return pw.Row(children: [
pw.SizedBox(
width: 80,
height: 80,
child: pw.Rectangle(fillColor: PdfColors.grey),
),
pw.Spacer(flex: 1),
pw.SizedBox(
width: 80,
height: 80,
child: pw.Rectangle(fillColor: PdfColors.amber300),
),
pw.Spacer(flex: 1),
pw.SizedBox(
width: 80,
height: 80,
child: pw.Rectangle(fillColor: PdfColors.green500),
),
pw.Spacer(flex: 1),
pw.SizedBox(
width: 80,
height: 80,
child: pw.Rectangle(fillColor: PdfColors.blue600),
),
]);
})); // Pa
final file = File('rectangles.pdf');
await file.writeAsBytes(await pdf.save());
}
我们创建了一系列 SizedBox 小部件。在框中,我们放置了矩形小部件。
pw.SizedBox( width: 80, height: 80, child: pw.Rectangle(fillColor: PdfColors.grey), ),
对于每个矩形,我们都定义了填充颜色。
Dart PDF 页脚
在下一个示例中,我们将页脚添加到我们的页面。
import 'dart:io';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
void main() async {
final pdf = pw.Document(pageMode: PdfPageMode.outlines);
final title = pw.LoremText();
pdf.addPage(
pw.MultiPage(
footer: _buildFooter,
build: (context) => [
pw.Header(level: 1, text: title.sentence(1)),
pw.SizedBox(height: 20),
pw.Lorem(length: 50),
pw.SizedBox(height: 20),
pw.Lorem(length: 70),
pw.SizedBox(height: 20),
pw.Lorem(length: 150),
pw.SizedBox(height: 20),
pw.Lorem(length: 250),
pw.SizedBox(height: 20),
pw.Lorem(length: 350),
],
),
);
final file = File('footer.pdf');
await file.writeAsBytes(await pdf.save());
}
pw.Widget _buildFooter(pw.Context context) {
return pw.Row(
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
crossAxisAlignment: pw.CrossAxisAlignment.end,
children: [
pw.Text(
'Page ${context.pageNumber}/${context.pagesCount}',
style: const pw.TextStyle(
fontSize: 12,
color: PdfColors.blue700,
),
)
],
);
}
页脚由一个包含当前页码和总页码的行组成。
final title = pw.LoremText();
lorem 方法为文档提供了一些填充文本。这是桌面排版在测试时的常见做法。
pdf.addPage(
pw.MultiPage(
footer: _buildFooter,
build: (context) => [
pw.Header(level: 1, text: title.sentence(1)),
pw.SizedBox(height: 20),
pw.Lorem(length: 50),
pw.SizedBox(height: 20),
pw.Lorem(length: 70),
pw.SizedBox(height: 20),
pw.Lorem(length: 150),
pw.SizedBox(height: 20),
pw.Lorem(length: 250),
pw.SizedBox(height: 20),
pw.Lorem(length: 350),
],
),
);
我们有一个多页文档。页脚的创建委托给 _buildFooter 函数。
pw.SizedBox(height: 20), pw.Lorem(length: 50),
我们使用 SizedBox 添加一些空白。Lorem 方法添加 50 个拉丁文本字符。
pw.Widget _buildFooter(pw.Context context) {
return pw.Row(
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
crossAxisAlignment: pw.CrossAxisAlignment.end,
children: [
pw.Text(
'Page ${context.pageNumber}/${context.pagesCount}',
style: const pw.TextStyle(
fontSize: 12,
color: PdfColors.blue700,
),
)
],
);
}
这构建了页脚。它是一个包含 Text 小部件的行。它包含当前页码和所有页面的总数。此外,我们还对文本进行了样式设置:我们定义了它的大小和颜色。
Dart PDF 表格
使用 Table 小部件创建表格。这是一个具有许多选项的复杂小部件。
import 'dart:io';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
class User {
late String name;
late String occupation;
User(String name, String occupation) {
this.name = name;
this.occupation = occupation;
}
String getIndex(int idx) {
switch (idx) {
case 0:
return name;
case 1:
return occupation;
}
return '';
}
}
final users = <User>[
User("John Doe", "gardener"),
User("Roder Roe", "driver"),
User("Joe Smith", "teacher"),
];
void main() async {
final pdf = pw.Document();
pdf.addPage(pw.Page(
pageFormat: PdfPageFormat.a4,
build: (pw.Context ctx) {
return genTable(ctx);
}));
final file = File('table.pdf');
await file.writeAsBytes(await pdf.save());
}
pw.Widget genTable(pw.Context ctx) {
const headers = [
'Name',
'Occupation',
];
return pw.Table.fromTextArray(
border: null,
cellAlignment: pw.Alignment.centerLeft,
headerDecoration: pw.BoxDecoration(
borderRadius: const pw.BorderRadius.all(pw.Radius.circular(1)),
color: PdfColors.blue500,
),
headerHeight: 25,
cellHeight: 40,
cellAlignments: {
0: pw.Alignment.centerLeft,
1: pw.Alignment.centerLeft,
},
headerStyle: pw.TextStyle(
color: PdfColors.white,
fontSize: 10,
fontWeight: pw.FontWeight.bold,
),
cellStyle: const pw.TextStyle(
color: PdfColors.blueGrey800,
fontSize: 10,
),
rowDecoration: pw.BoxDecoration(
border: pw.Border(
bottom: pw.BorderSide(
color: PdfColors.blueGrey900,
width: .5,
),
),
),
headers: List<String>.generate(
headers.length,
(col) => headers[col],
),
data: List<List<String>>.generate(
users.length,
(row) => List<String>.generate(
headers.length,
(col) => users[row].getIndex(col),
),
),
);
}
我们在表格中显示用户。
class User {
late String name;
late String occupation;
User(String name, String occupation) {
this.name = name;
this.occupation = occupation;
}
String getIndex(int idx) {
switch (idx) {
case 0:
return name;
case 1:
return occupation;
}
return '';
}
}
表格显示用户。getIndex 方法由表格的数据函数调用。它返回相应的字段。
final users = <User>[
User("John Doe", "gardener"),
User("Roder Roe", "driver"),
User("Joe Smith", "teacher"),
];
表格的数据源是用户列表。
headerHeight: 25,
cellHeight: 40,
cellAlignments: {
0: pw.Alignment.centerLeft,
1: pw.Alignment.centerLeft,
},
我们有定义表格外观的选项。在这里,我们定义了页眉和单元格的高度以及单元格对齐方式。
rowDecoration: pw.BoxDecoration(
border: pw.Border(
bottom: pw.BorderSide(
color: PdfColors.blueGrey900,
width: .5,
),
),
),
我们定义了表格底边框。我们设置了边框颜色和大小。
headers: List<String>.generate( headers.length, (col) => headers[col], ),
我们为表格设置了页眉。
data: List<List<String>>.generate(
users.length,
(row) => List<String>.generate(
headers.length,
(col) => users[row].getIndex(col),
),
),
表格已填充数据。
来源
在本文中,我们展示了如何在 Dart 中生成 PDF 文档。
作者
列出 所有 Dart 教程。