Flutter PDF处理插件pdfx的使用
Flutter PDF处理插件pdfx的使用
PDFx
Flutter
Render & show PDF documents on Web, MacOs 10.11+, Android 5.0+, iOS and Windows.
renderer
: Work with Pdf document, pages, render page to imageviewer
: Set of flutter widgets & controllers for show renderer result
Showcase
PdfViewPinch | PdfView |
---|---|
Getting Started
在你的Flutter项目中添加依赖:
flutter pub add pdfx
对于Web,运行工具以自动在index.html中添加pdfjs库(CDN):
flutter pub run pdfx:install_web
对于Windows,运行工具以自动在CMakeLists.txt文件中添加覆盖pdfium版本属性:
flutter pub run pdfx:install_windows
Usage Example
基本用法
import 'package:pdfx/pdfx.dart';
// 创建一个PdfControllerPinch实例,用于处理PDF文档
final pdfPinchController = PdfControllerPinch(
document: PdfDocument.openAsset('assets/sample.pdf'),
);
// 使用PdfViewPinch显示PDF文档,支持缩放而不失真(不支持Windows)
PdfViewPinch(
controller: pdfPinchController,
);
// 或者使用简单的PdfView显示PDF文档(缩放会失真)
final pdfController = PdfController(
document: PdfDocument.openAsset('assets/sample.pdf'),
);
PdfView(
controller: pdfController,
);
打开另一个文档
pdfController.openDocument(PdfDocument.openAsset('assets/sample.pdf'));
页面控制
// 跳转到指定页面
pdfController.jumpTo(3);
// 动画跳转到指定页面
_pdfController.animateToPage(3, duration: Duration(milliseconds: 250), curve: Curves.ease);
// 动画跳转到下一页
_pdfController.nextPage(duration: Duration(milliseconds: 250), curve: Curves.easeIn);
// 动画跳转到上一页
_pdfController.previousPage(duration: Duration(milliseconds: 250), curve: Curves.easeOut);
获取PDF信息
// 当前显示的页面
pdfController.page;
// 文档中的总页数
pdfController.pagesCount;
回调函数
PdfView(
controller: pdfController,
onDocumentLoaded: (document) {},
onPageChanged: (page) {},
);
显示当前页码和总页数
PdfPageNumber(
controller: _pdfController,
builder: (_, state, loadingState, pagesCount) => Container(
alignment: Alignment.center,
child: Text(
'$page/${pagesCount ?? 0}',
style: const TextStyle(fontSize: 22),
),
),
)
自定义渲染选项
PdfView(
controller: pdfController,
renderer: (PdfPage page) => page.render(
width: page.width * 2,
height: page.height * 2,
format: PdfPageImageFormat.jpeg,
backgroundColor: '#FFFFFF',
),
);
自定义构建器
class SomeWidget {
static Widget builder(
BuildContext context,
PdfViewPinchBuilders builders,
PdfLoadingState state,
WidgetBuilder loadedBuilder,
PdfDocument? document,
Exception? loadingError,
) {
final Widget content = () {
switch (state) {
case PdfLoadingState.loading:
return KeyedSubtree(
key: const Key('pdfx.root.loading'),
child: builders.documentLoaderBuilder?.call(context) ??
const SizedBox(),
);
case PdfLoadingState.error:
return KeyedSubtree(
key: const Key('pdfx.root.error'),
child: builders.errorBuilder?.call(context, loadingError!) ??
Center(child: Text(loadingError.toString())),
);
case PdfLoadingState.success:
return KeyedSubtree(
key: Key('pdfx.root.success.${document!.id}'),
child: loadedBuilder(context),
);
}
}();
final defaultBuilder =
builders as PdfViewPinchBuilders<DefaultBuilderOptions>;
final options = defaultBuilder.options;
return AnimatedSwitcher(
duration: options.loaderSwitchDuration,
transitionBuilder: options.transitionBuilder,
child: content,
);
}
static Widget transitionBuilder(Widget child, Animation<double> animation) =>
FadeTransition(opacity: animation, child: child);
static PhotoViewGalleryPageOptions pageBuilder(
BuildContext context,
Future<PdfPageImage> pageImage,
int index,
PdfDocument document,
) =>
PhotoViewGalleryPageOptions(
imageProvider: PdfPageImageProvider(
pageImage,
index,
document.id,
),
minScale: PhotoViewComputedScale.contained * 1,
maxScale: PhotoViewComputedScale.contained * 3.0,
initialScale: PhotoViewComputedScale.contained * 1.0,
heroAttributes: PhotoViewHeroAttributes(tag: '${document.id}-$index'),
);
}
PdfViewPinch(
controller: pdfPinchController,
builders: PdfViewPinchBuilders<DefaultBuilderOptions>(
options: const DefaultBuilderOptions(
loaderSwitchDuration: const Duration(seconds: 1),
transitionBuilder: SomeWidget.transitionBuilder,
),
documentLoaderBuilder: (_) =>
const Center(child: CircularProgressIndicator()),
pageLoaderBuilder: (_) =>
const Center(child: CircularProgressIndicator()),
errorBuilder: (_, error) => Center(child: Text(error.toString())),
builder: SomeWidget.builder,
),
)
PdfView(
controller: pdfController,
builders: PdfViewBuilders<DefaultBuilderOptions>(
// All from `PdfViewPinch` and:
pageBuilder: SomeWidget.pageBuilder,
),
);
Renderer API
PdfDocument
参数
Parameter | Description | Default |
---|---|---|
sourceName | Needed for toString method. Contains a method for opening a document (file, data or asset) | - |
id | Document unique id. Generated when opening document. | - |
pagesCount | All pages count in document. Starts from 1. | - |
isClosed | Is the document closed | - |
打开本地文档
// From assets (Android, Ios, MacOs, Web)
final document = await PdfDocument.openAsset('assets/sample.pdf');
// From file (Android, Ios, MacOs)
final document = await PdfDocument.openFile('path/to/file/on/device');
// From data (Android, Ios, MacOs, Web)
final document = await PdfDocument.openData((FutureOr<Uint8List>) data);
打开网络文档
安装[internet_file]包(支持所有平台):
flutter pub add internet_file
使用它:
import 'package:internet_file/internet_file.dart';
PdfDocument.openData(InternetFile.get('https://github.com/ScerIO/packages.flutter/raw/fd0c92ac83ee355255acb306251b1adfeb2f2fd6/packages/native_pdf_renderer/example/assets/sample.pdf'))
打开页面
final page = document.getPage(pageNumber); // Starts from 1
关闭文档
document.close();
PdfPage
参数
Parameter | Description | Default |
---|---|---|
document | Parent document | Parent |
id | Page unique id. Needed for rendering and closing page. Generated when opening page. | - |
width | Page source width in pixels, int | - |
height | Page source height in pixels, int | - |
isClosed | Is the page closed | false |
渲染图像
final pageImage = page.render(
width: page.width * 2,
height: page.height * 2,
format: PdfPageImageFormat.JPEG,
backgroundColor: '#ffffff',
cropRect: Rect.fromLTRB(left, top, right, bottom),
);
关闭页面
page.close();
PdfPageImage
参数
Parameter | Description | Default |
---|---|---|
id | Page unique id. Needed for rendering and closing page. Generated when render page. | - |
pageNumber | Page number. The first page is 1. | - |
width | Width of the rendered area in pixels, int | - |
height | Height of the rendered area in pixels, int | - |
bytes | Rendered image result, Uint8List | - |
format | Rendered image compression format, for web always PNG | PdfPageImageFormat.PNG |
Rendering Additional Info
On Web
此插件使用 PDF.js
On Android
此插件使用 Android native PdfRenderer
On iOS & MacOs
此插件使用 iOS & MacOs native CGPDFPage
On Windows
此插件使用 PDFium
示例代码
import 'package:flutter/material.dart';
import 'package:pdfx_example/pinch.dart';
import 'package:pdfx_example/simple.dart';
import 'package:universal_platform/universal_platform.dart';
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) => MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(primaryColor: Colors.white),
darkTheme: ThemeData.dark(),
home: UniversalPlatform.isWindows
? const SimplePage()
: const PinchPage(),
);
}
更多关于Flutter PDF处理插件pdfx的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter PDF处理插件pdfx的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
当然,以下是如何在Flutter项目中使用pdfx
插件来处理PDF文件的示例代码。pdfx
是一个用于在Flutter应用中读取和写入PDF文件的插件。
1. 添加依赖
首先,在你的pubspec.yaml
文件中添加pdfx
依赖:
dependencies:
flutter:
sdk: flutter
pdfx: ^x.y.z # 请替换为最新版本号
然后运行flutter pub get
来安装依赖。
2. 读取PDF文件
以下是一个读取PDF文件并显示其内容的示例:
import 'package:flutter/material.dart';
import 'package:pdfx/pdfx.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: PdfViewerScreen(),
);
}
}
class PdfViewerScreen extends StatefulWidget {
@override
_PdfViewerScreenState createState() => _PdfViewerScreenState();
}
class _PdfViewerScreenState extends State<PdfViewerScreen> {
late PdfDocument pdfDocument;
@override
void initState() {
super.initState();
_loadPdf();
}
Future<void> _loadPdf() async {
// 假设你有一个名为'sample.pdf'的文件在应用的assets目录中
final Uint8List pdfBytes = await rootBundle.load('assets/sample.pdf');
pdfDocument = await PdfDocument.fromData(pdfBytes);
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('PDF Viewer'),
),
body: pdfDocument.pageCount > 0
? PdfViewer(
document: pdfDocument,
// 初始页面索引
initialPage: 0,
// 页面改变回调
onPageChanged: (int page) {
print("Page changed to: $page");
},
)
: Center(child: CircularProgressIndicator()),
);
}
@override
void dispose() {
pdfDocument.dispose();
super.dispose();
}
}
3. 写入PDF文件
以下是一个创建并保存PDF文件的示例:
import 'package:flutter/material.dart';
import 'package:pdfx/pdfx.dart';
import 'dart:io';
import 'dart:typed_data';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: PdfCreatorScreen(),
);
}
}
class PdfCreatorScreen extends StatefulWidget {
@override
_PdfCreatorScreenState createState() => _PdfCreatorScreenState();
}
class _PdfCreatorScreenState extends State<PdfCreatorScreen> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('PDF Creator'),
),
body: Center(
child: ElevatedButton(
onPressed: _createPdf,
child: Text('Create PDF'),
),
),
);
}
Future<void> _createPdf() async {
final PdfDocument pdf = PdfDocument();
final PdfPage page = pdf.addPage();
final PdfCanvas canvas = page.getCanvas();
final PdfPaint paint = PdfPaint()
..color = PdfColor(red: 0, green: 0, blue: 0)
..fontSize = 24.0;
canvas.drawString('Hello, PDF!', 50.0, 700.0, paint);
final Uint8List pdfBytes = await pdf.save();
// 将PDF保存到设备存储
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/sample_created.pdf');
await file.writeAsBytes(pdfBytes);
print('PDF created and saved to ${file.path}');
}
}
注意事项
- 权限:在Android和iOS上保存文件时,需要处理文件存储权限。
- 错误处理:在实际应用中,请添加适当的错误处理逻辑。
- 插件版本:确保你使用的是最新版本的
pdfx
插件,因为API可能会随着版本更新而变化。
这些示例展示了如何使用pdfx
插件在Flutter应用中读取和写入PDF文件。根据你的具体需求,你可以进一步扩展这些示例。