Flutter PDF文档渲染插件flutter_pdfium的使用
Flutter PDF文档渲染插件flutter_pdfium的使用
这个项目是一个Flutter插件,提供了PDFium库的绑定。PDFium是一个开源的PDF渲染引擎,被Chromium浏览器所使用。此FFI插件将库的本机绑定传递给Flutter,并支持每个平台动态加载库。需要注意的是,库文件并不包含在包中,而是在构建过程中下载。
注意: MacOS和iOS将在pod install
时下载库文件,其他平台则会在构建过程中通过cmake
下载相应的库。
所有PDFium头文件中的公共函数在这个库中都被重新映射。这允许库仅绑定所需的实际结构和元素。
使用
首先,你需要在你的Flutter项目中安装该包:flutter pub add flutter_pdfium
。安装完成后,你可以在项目中使用该库。二进制文件将在构建过程中下载(可以在相应的CMakeList.txt或podspec文件中查看)。
要使用该库,可以直接使用Pdfium
类(如果你希望手动加载库),或者使用提供的createInitializedLibrary()
函数,该函数会确定正确的库名称并加载相应的库。库初始化后即可使用。
请注意,在使用完毕后必须释放资源以销毁库。
import 'dart:ffi' as ffi;
import 'package:flutter_pdfium/flutter_pdfium.dart';
// 初始化PDFium库
final pdfium = createInitializedLibrary();
// 加载PDF文档
final doc = pdfium.LoadDocument(
'file_path'.toNativeUtf8().cast<ffi.Char>(),
'password'.toNativeUtf8().cast<ffi.Char>(),
);
// 检查是否成功加载文档
if (doc == ffi.nullptr) {
print('Failed to load document');
return;
}
// 获取页面数量
final pageCount = pdfium.GetPageCount(doc);
// 关闭文档
pdfium.CloseDocument(doc);
// 销毁库
pdfium.DestroyLibrary();
开发
要克隆并构建此仓库(及其包含的示例),需要本地生成头文件和源代码。对于已部署的包,头文件已经在包中生成并包含在内(在GitHub Actions步骤期间)。
你需要以下工具:
- clang
- just
- Python 3(至少3.12)
- curl
当你克隆了仓库后,可以运行just configure
。这将下载PDFium版本,创建绑定所需的AST,并生成相应的头文件。之后,FFIGEN将运行以生成Dart绑定。完成此步骤后,你可以通过flutter run
运行示例项目。与已部署的包一样,有效的库将在构建过程中下载。
示例代码
以下是完整的示例代码,展示了如何使用flutter_pdfium
插件来加载和显示PDF文档。
import 'dart:ffi' as ffi;
import 'package:ffi/ffi.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_pdfium/flutter_pdfium.dart';
void main() async {
runApp(const ExampleApp());
}
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
[@override](/user/override)
Widget build(BuildContext context) => MaterialApp(
title: 'PDFium 示例',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepOrange),
useMaterial3: true,
),
home: const Home(),
);
}
class Home extends StatefulWidget {
const Home({super.key});
[@override](/user/override)
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
late Pdfium pdfium;
FPDF_DOCUMENT? document;
[@override](/user/override)
void initState() {
pdfium = createInitializedLibrary();
super.initState();
}
[@override](/user/override)
void dispose() {
pdfium.DestroyLibrary();
super.dispose();
}
[@override](/user/override)
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(
title: const Text('Flutter PDFium 示例应用'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Icon(Icons.picture_as_pdf, color: Colors.deepOrange),
const Text('从内存加载PDF'),
if (document == null)
ElevatedButton(
onPressed: loadPdf, child: const Text('加载PDF')),
if (document != null) ...[
ElevatedButton(
onPressed: unloadPdf, child: const Text('卸载PDF')),
Text(
'文档有 ${pdfium.GetPageCount(document!)} 页.'),
Text('第一页大小为: ${getPageSize()}')
],
],
),
),
),
);
Future<void> loadPdf() async {
if (document != null) {
return;
}
final bytes = (await rootBundle.load('assets/sample.pdf')).buffer.asUint8List();
final newDoc = using((arena) {
final dataPointer = arena<ffi.Uint8>(bytes.length);
for (var i = 0; i < bytes.length; i++) {
dataPointer[i] = bytes[i];
}
final voidPointer = dataPointer.cast<ffi.Void>();
return pdfium.LoadMemDocument(
voidPointer, bytes.length, ''.toNativeUtf8().cast<ffi.Char>());
}, malloc);
setState(() {
document = newDoc;
});
}
void unloadPdf() {
if (document == null) {
return;
}
pdfium.CloseDocument(document!);
setState(() {
document = null;
});
}
Size getPageSize() {
if (document == null) {
return Size.zero;
}
final page = pdfium.LoadPage(document!, 0);
final size = using((arena) {
final sizePointer = arena<FS_SIZEF_>();
pdfium.GetPageSizeByIndexF(document!, 0, sizePointer);
return Size(sizePointer.ref.width, sizePointer.ref.height);
}, malloc);
pdfium.ClosePage(page);
return size;
}
}
更多关于Flutter PDF文档渲染插件flutter_pdfium的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html