Flutter Render and show PDF documents
PDFx
Flutter
Render & show PDF documents on Web, MacOs 10.11+, Android 5.0+, iOS and Windows.
Includes 2 api:
renderer
Work with Pdf document, pages, render page to imageviewer
Set of flutter widgets & controllers for show renderer result
Showcase
PdfViewPinch | PdfView |
---|---|
Getting Started
In your flutter project add the dependency:
flutter pub add pdfx
For web run tool for automatically add pdfjs library (CDN) in index.html:
flutter pub run pdfx:install_web
For windows run tool automatically add override for pdfium version property in CMakeLists.txt file:
flutter pub run pdfx:install_windows
Usage example
import 'package:pdf_view/pdfx.dart';
final pdfPinchController = PdfControllerPinch(
document: PdfDocument.openAsset('assets/sample.pdf'),
);
// Pdf view with re-render pdf texture on zoom (not loose quality on zoom)
// Not supported on windows
PdfViewPinch(
controller: pdfPinchController,
);
//-- or --//
final pdfController = PdfController(
document: PdfDocument.openAsset('assets/sample.pdf'),
);
// Simple Pdf view with one render of page (loose quality on zoom)
PdfView(
controller: pdfController,
);
Viewer Api
PdfController & PdfControllerPinch
Parameter | Description | Default |
---|---|---|
document | The document to be displayed | – |
initialPage | The page to show when first creating the [PdfView] | 1 |
viewportFraction | The fraction of the viewport that each page should occupy. | 1.0 |
PdfView & PdfViewPinch
Parameter | Description | PdfViewPinch / PdfView |
---|---|---|
controller | Pages control. See page control and additional pdf info | + / + |
onPageChanged | Called whenever the page in the center of the viewport changes. See Document callbacks | + / + |
onDocumentLoaded | Called when a document is loaded. See Document callbacks | + / + |
onDocumentError | Called when a document loading error. Exception is passed in the attributes | + / + |
builders | Set of pdf view builders. See Custom builders | + / + |
scrollDirection | Page turning direction | + / + |
renderer | Custom PdfRenderer options. See custom renderer options | – / + |
pageSnapping | Set to false for mouse wheel scroll on web | – / + |
physics | How the widgets should respond to user input | – / + |
padding | Padding for the every page. | + / – |
PdfViewBuilders & PdfViewPinchBuilders
Parameter | Description | PdfViewPinchBuilders / PdfViewBuilders |
---|---|---|
options | Additional options for builder | + / + |
documentLoaderBuilder | Widget showing when pdf document loading | + / + |
pageLoaderBuilder | Widget showing when pdf page loading | + / + |
errorBuilder | Show document loading error message | + / + |
builder | Root view builder for animate pdf loading state | + / + |
pageBuilder | Callback called to render a widget for each page. See custom page builder | – / + |
Additional examples
Open another document
pdfController.openDocument(PdfDocument.openAsset('assets/sample.pdf'));
Page control:
// Jump to specified page
pdfController.jumpTo(3);
// Animate to specified page
_pdfController.animateToPage(3, duration: Duration(milliseconds: 250), curve: Curves.ease);
// Animate to next page
_pdfController.nextPage(duration: Duration(milliseconds: 250), curve: Curves.easeIn);
// Animate to previous page
_pdfController.previousPage(duration: Duration(milliseconds: 250), curve: Curves.easeOut);
Additional pdf info:
// Actual showed page
pdfController.page;
// Count of all pages in document
pdfController.pagesCount;
Document callbacks
PdfView(
controller: pdfController,
onDocumentLoaded: (document) {},
onPageChanged: (page) {},
);
Show actual page number & all pages count
PdfPageNumber(
controller: _pdfController,
// When `loadingState != PdfLoadingState.success` `pagesCount` equals null_
builder: (_, state, loadingState, pagesCount) => Container(
alignment: Alignment.center,
child: Text(
'$page/${pagesCount ?? 0}',
style: const TextStyle(fontSize: 22),
),
),
)
Custom renderer options
PdfView(
controller: pdfController,
renderer: (PdfPage page) => page.render(
width: page.width * 2,
height: page.height * 2,
format: PdfPageImageFormat.jpeg,
backgroundColor: '#FFFFFF',
),
);
Custom builders
// Need static methods for builders arguments
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 | – |
Local document open:
// 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)
Network document open:
Install [network_file] package (supports all platforms):
flutter pub add internet_file
And use it
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'))
Open page:
final page = document.getPage(pageNumber); // Starts from 1
Close document:
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 |
Render image:
final pageImage = page.render(
// rendered image width resolution, required
width: page.width * 2,
// rendered image height resolution, required
height: page.height * 2,
// Rendered image compression format, also can be PNG, WEBP*
// Optional, default: PdfPageImageFormat.PNG
// Web not supported
format: PdfPageImageFormat.JPEG,
// Image background fill color for JPEG
// Optional, default '#ffffff'
// Web not supported
backgroundColor: '#ffffff',
// Crop rect in image for render
// Optional, default null
// Web not supported
cropRect: Rect.fromLTRB(left, top, right, bottom),
);
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 |
Close page:
Before open new page android asks to close the past. If this is not done, the application may crash with an error
page.close();
* PdfPageImageFormat.WEBP support only on android
Rendering additional info
On Web
This plugin uses the PDF.js
On Android
This plugin uses the Android native PdfRenderer
On Ios & MacOs
This plugin uses the iOS & MacOs native CGPDFPage
On Windows
This plugin uses PDFium