Flutter PDF处理插件pdfx的使用

发布于 1周前 作者 zlyuanteng 来自 Flutter

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 image
  • viewer: Set of flutter widgets & controllers for show renderer result

pub package

Showcase

PdfViewPinch PdfView
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

1 回复

更多关于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}');
  }
}

注意事项

  1. 权限:在Android和iOS上保存文件时,需要处理文件存储权限。
  2. 错误处理:在实际应用中,请添加适当的错误处理逻辑。
  3. 插件版本:确保你使用的是最新版本的pdfx插件,因为API可能会随着版本更新而变化。

这些示例展示了如何使用pdfx插件在Flutter应用中读取和写入PDF文件。根据你的具体需求,你可以进一步扩展这些示例。

回到顶部