Giter VIP home page Giter VIP logo

pdfrx's Introduction

pdfrx

pdfrx is a rich and fast PDF viewer implementation built on the top of PDFium. The plugin supports Android, iOS, Windows, macOS, Linux, and Web.

Interactive Demo

A demo site using Flutter Web

pdfrx

Main Features

Example Code

The following fragment illustrates the easiest way to show a PDF file in assets:

import 'package:pdfrx/pdfrx.dart';

...

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Pdfrx example'),
        ),
        body: PdfViewer.asset('assets/hello.pdf'),
      ),
    );
  }
}

Anyway, please follow the instructions below to install on your environment.

Getting Started

Installation

Add this to your package's pubspec.yaml file and execute flutter pub get:

dependencies:
  pdfrx: ^1.0.82

Note for Windows

Ensure your Windows installation enables Developer Mode.

The build process internally uses symbolic link and it requires Developer Mode to be enabled. Without this, you may encounter errors like this.

Open PDF File

PdfViewer supports following functions to open PDF file on specific medium:

Deal with Password Protected PDF Files

To support password protected PDF files, use passwordProvider to supply passwords interactively:

PdfViewer.asset(
  'assets/test.pdf',
  // Set password provider to show password dialog
  passwordProvider: _passwordDialog,

  ...
),

And, _passwordDialog function is defined like this:

Future<String?> _passwordDialog() async {
  final textController = TextEditingController();
  return await showDialog<String?>(
    context: context,
    barrierDismissible: false,
    builder: (context) {
      return AlertDialog(
        title: const Text('Enter password'),
        content: TextField(
          controller: textController,
          autofocus: true,
          keyboardType: TextInputType.visiblePassword,
          obscureText: true,
          onSubmitted: (value) => Navigator.of(context).pop(value),
        ),
        actions: [
          TextButton(
            onPressed: () => Navigator.of(context).pop(null),
            child: const Text('Cancel'),
          ),
          TextButton(
            onPressed: () => Navigator.of(context).pop(textController.text),
            child: const Text('OK'),
          ),
        ],
      );
    },
  );
}

When PdfViewer tries to open a password protected document, it calls the function passed to passwordProvider (except the first attempt; see below) repeatedly to get a new password until the document is successfully opened. And if the function returns null, the viewer will give up the password trials and the function is no longer called.

firstAttemptByEmptyPassword

By default, the first password attempt uses empty password. This is because encrypted PDF files frequently use empty password for viewing purpose. It's normally useful but if you want to use authoring password, it can be disabled by setting firstAttemptByEmptyPassword to false.

Customizations

You can customize the behaviour and visual by configuring PdfViewerParams.

Text Selection

Text selection feature is still experimental but you can easily enable it like the following fragment:

PdfViewer.asset(
  'assets/test.pdf',
  enableTextSelection: true,
  ...
),

There are still several limitations and issues on text selection feature:

  • Pan-to-scroll does not work on Desktop (#8)
  • Pan-to-scroll does not work on Flutter Web on mobile devices (#180)
  • Selecting text sometimes throws exception (#185)
    • Text selection suddenly gets cleared in certain situation

PDF Link Handling

To enable Link in PDF file, you should set PdfViewerParams.linkHandlerParams.

The following fragment handles user's tap on link:

linkHandlerParams: PdfLinkHandlerParams(
  onLinkTap: (link) {
    // handle URL or Dest
    if (link.url != null) {
      // TODO: implement your own isSecureUrl by yourself...
      if (await isSecureUrl(link.url!)) {
        launchUrl(link.url!);
      }
    } else if (link.dest != null) {
      controller.goToDest(link.dest);
    }
  },
),

Note for Link Validation

For URIs, you should check the validity of the URIs before opening the URI; the example code just show dialog to ask whether to open the URL or not.

For destinations, you can use PdfViewerController.goToDest to go to the destination. Or you can use PdfViewerController.calcMatrixForDest to get the matrix for it.

Link Appearance

For link appearance, you can change its color using PdfLinkHandlerParams.linkColor.

For more further customization, you can use PdfLinkHandlerParams.customPainter:

customPainter: (canvas, pageRect, page, links) {
  final paint = Paint()
    ..color = Colors.red.withOpacity(0.2)
    ..style = PaintingStyle.fill;
  for (final link in links) {
    // you can customize here to make your own link appearance
    final rect = link.rect.toRectInPageRect(page: page, pageRect: pageRect);
    canvas.drawRect(rect, paint);
  }
}

Document Outline (a.k.a Bookmarks)

PDF defines document outline (PdfOutlineNode), which is sometimes called as bookmarks or index. And you can access it by PdfDocument.loadOutline.

The following fragment obtains it on PdfViewerParams.onViewerReady:

onViewerReady: (document, controller) async {
  outline.value = await document.loadOutline();
},

PdfOutlineNode is tree structured data and for more information, see the usage on example code.

Horizontal Scroll View

By default, the pages are layed out vertically. You can customize the layout logic by PdfViewerParams.layoutPages:

layoutPages: (pages, params) {
  final height =
      pages.fold(0.0, (prev, page) => max(prev, page.height)) +
          params.margin * 2;
  final pageLayouts = <Rect>[];
  double x = params.margin;
  for (var page in pages) {
    pageLayouts.add(
      Rect.fromLTWH(
        x,
        (height - page.height) / 2, // center vertically
        page.width,
        page.height,
      ),
    );
    x += page.width + params.margin;
  }
  return PdfPageLayout(
    pageLayouts: pageLayouts,
    documentSize: Size(x, height),
  );
},

Facing Pages

The following code will show pages in "facing-sequential-layout" that is often used in PDF viewer apps:

/// Page reading order; true to L-to-R that is commonly used by books like manga or such
var isRightToLeftReadingOrder = false;
/// Use the first page as cover page
var needCoverPage = true;

...

layoutPages: (pages, params) {
  final width = pages.fold(
      0.0, (prev, page) => max(prev, page.width));

  final pageLayouts = <Rect>[];
  final offset = needCoverPage ? 1 : 0;
  double y = params.margin;
  for (int i = 0; i < pages.length; i++) {
    final page = pages[i];
    final pos = i + offset;
    final isLeft = isRightToLeftReadingOrder
        ? (pos & 1) == 1
        : (pos & 1) == 0;

    final otherSide = (pos ^ 1) - offset;
    final h = 0 <= otherSide && otherSide < pages.length
        ? max(page.height, pages[otherSide].height)
        : page.height;

    pageLayouts.add(
      Rect.fromLTWH(
        isLeft
            ? width + params.margin - page.width
            : params.margin * 2 + width,
        y + (h - page.height) / 2,
        page.width,
        page.height,
      ),
    );
    if (pos & 1 == 1 || i + 1 == pages.length) {
      y += h + params.margin;
    }
  }
  return PdfPageLayout(
    pageLayouts: pageLayouts,
    documentSize: Size(
      (params.margin + width) * 2 + params.margin,
      y,
    ),
  );
},

Showing Scroll Thumbs

By default, the viewer does never show any scroll bars nor scroll thumbs. You can add scroll thumbs by using PdfViewerParams.viewerOverlayBuilder:

viewerOverlayBuilder: (context, size, handleLinkTap) => [
  // Add vertical scroll thumb on viewer's right side
  PdfViewerScrollThumb(
    controller: controller,
    orientation: ScrollbarOrientation.right,
    thumbSize: const Size(40, 25),
    thumbBuilder:
        (context, thumbSize, pageNumber, controller) =>
            Container(
      color: Colors.black,
      // Show page number on the thumb
      child: Center(
        child: Text(
          pageNumber.toString(),
          style: const TextStyle(color: Colors.white),
        ),
      ),
    ),
  ),
  // Add horizontal scroll thumb on viewer's bottom
  PdfViewerScrollThumb(
    controller: controller,
    orientation: ScrollbarOrientation.bottom,
    thumbSize: const Size(80, 30),
    thumbBuilder:
        (context, thumbSize, pageNumber, controller) =>
            Container(
      color: Colors.red,
    ),
  ),
],

Basically, PdfViewerParams.viewerOverlayBuilder can be used to insert any widgets under viewer's internal Stack.

But if you want to place many visual objects that does not interact with user, you'd better use PdfViewerParams.pagePaintCallback.

Double-tap to Zoom

You can implement double-tap-to-zoom feature using PdfViewerParams.viewerOverlayBuilder with PdfViewerScrollThumb:

viewerOverlayBuilder: (context, size, handleLinkTap) => [
  GestureDetector(
    behavior: HitTestBehavior.translucent,
    // Your code here:
    onDoubleTap: () {
      controller.zoomUp(loop: true);
    },
    // If you use GestureDetector on viewerOverlayBuilder, it breaks link-tap handling
    // and you should manually handle it using onTapUp callback
    onTapUp: (details) {
      handleLinkTap(details.localPosition);
    },
    // Make the GestureDetector covers all the viewer widget's area
    // but also make the event go through to the viewer.
    child: IgnorePointer(
      child:
          SizedBox(width: size.width, height: size.height),
    ),
  ),
  ...
],

If you want to use PdfViewerScrollThumb with double-tap-to-zoom enabled, place the double-tap-to-zoom code before PdfViewerScrollThumb.

Adding Page Number on Page Bottom

If you want to add page number on each page, you can do that by PdfViewerParams.pageOverlaysBuilder:

pageOverlaysBuilder: (context, pageRect, page) {
  return Align(
    alignment: Alignment.bottomCenter,
    child: Text(page.pageNumber.toString(),
    style: const TextStyle(color: Colors.red)));33
},

Loading Indicator

PdfViewer.uri may take long time to download PDF file and you want to show some loading indicator. You can do that by PdfViewerParams.loadingBannerBuilder:

loadingBannerBuilder: (context, bytesDownloaded, totalBytes) {
  return Center(
    child: CircularProgressIndicator(
      // totalBytes may not be available on certain case
      value: totalBytes != null ? bytesDownloaded / totalBytes : null,
      backgroundColor: Colors.grey,
    ),
  );
}

Dark/Night Mode Support

PdfViewer does not have any native dark (or night) mode support but it can be easily implemented using ColorFiltered widget:

ColorFiltered(
  colorFilter: ColorFilter.mode(Colors.white, darkMode ? BlendMode.difference : BlendMode.dst),
  child: PdfViewer.file(filePath, ...),
),

The trick is originally introduced by pckimlong.

Other Features

Text Search

TextSearcher is just a helper class that helps you to implement text searching feature on your app.

The following fragment illustrates the overall structure of the TextSearcher:

class _MainPageState extends State<MainPage> {
  final controller = PdfViewerController();
  // create a PdfTextSearcher and add a listener to update the GUI on search result changes
  late final textSearcher = PdfTextSearcher(controller)..addListener(_update);

  void _update() {
    if (mounted) {
      setState(() {});
    }
  }

  @override
  void dispose() {
    // dispose the PdfTextSearcher
    textSearcher.removeListener(_update);
    textSearcher.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Pdfrx example'),
      ),
      body: PdfViewer.asset(
        'assets/hello.pdf',
        controller: controller,
        params: PdfViewerParams(
          // add pageTextMatchPaintCallback that paints search hit highlights
          pagePaintCallbacks: [
            textSearcher.pageTextMatchPaintCallback
          ],
        ),
      )
    );
  }
  ...
}

On the fragment above, it does:

Then, you can use TextSearcher.startTextSearch to search text in the PDF document:

textSearcher.startTextSearch('hello', caseInsensitive: true);

The search starts running in background and the search progress is notified by the listener.

There are several functions that helps you to navigate user to the search matches:

You can get the search result (even during the search running) in the list of PdfTextRange by PdfTextSearcher.matches:

for (final match in textSearcher.matches) {
  print(match.pageNumber);
  ...
}

You can also cancel the background search:

textSearcher.resetTextSearch();

PdfDocumentViewBuilder/PdfPageView

PdfPageView is just another PDF widget that shows only one page. It accepts PdfDocument and page number to show a page within the document.

PdfDocumentViewBuilder is used to safely manage PdfDocument inside widget tree and it accepts builder parameter that creates child widgets.

The following fragment is a typical use of these widgets:

PdfDocumentViewBuilder.asset(
  'asset/test.pdf',
  builder: (context, document) => ListView.builder(
    itemCount: document?.pages.length ?? 0,
    itemBuilder: (context, index) {
      return Container(
        margin: const EdgeInsets.all(8),
        height: 240,
        child: Column(
          children: [
            SizedBox(
              height: 220,
              child: PdfPageView(
                document: document,
                pageNumber: index + 1,
                alignment: Alignment.center,
              ),
            ),
            Text(
              '${index + 1}',
            ),
          ],
        ),
      );
    },
  ),
),

PdfDocument Management

PdfDocumentViewBuilder can accept PdfDocumentRef from PdfViewer to safely share the same PdfDocument instance. For more information, see example/viewer/lib/thumbnails_view.dart.

pdfrx's People

Contributors

devstakat avatar espresso3389 avatar heropolisda2ny avatar n1kl4s avatar raldhafiri avatar timu-jesse-ezell avatar yhyh0 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pdfrx's Issues

Get uncaught null check error when trying to modify widget tree

As an example

class Example extends StatefulWidget {
  const Example({super.key, required this.path});

  final String path;

  @override
  State<Example> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  final controller = PdfViewerController();
  bool darkMode = false;

  @override
  Widget build(BuildContext context) {
    Widget pdfWidget = PdfViewer.file(widget.path, controller: controller);

    if (darkMode) {
      pdfWidget = ColorFiltered(
        colorFilter: const ColorFilter.mode(Colors.white, BlendMode.difference),
        child: pdfWidget,
      );
    }

    return Scaffold(
      appBar: AppBar(
        title: const Text('TEST'),
        actions: [
          IconButton(
            onPressed: () => setState(() => darkMode = !darkMode),
            icon: const Icon(Icons.dark_mode),
          ),
        ],
      ),
      body: pdfWidget,
    );
  }
}

This is the error:
E/flutter (30841): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Null check operator used on a null value E/flutter (30841): #0 PdfViewerController.goToPage (package:pdfrx/src/widgets/pdf_viewer.dart:1020:19) E/flutter (30841): #1 _PdfViewerState.build.<anonymous closure>.<anonymous closure> (package:pdfrx/src/widgets/pdf_viewer.dart:372:26) E/flutter (30841): #2 new Future.microtask.<anonymous closure> (dart:async/future.dart:280:37) E/flutter (30841): #3 _microtaskLoop (dart:async/schedule_microtask.dart:40:21) E/flutter (30841): #4 _startMicrotaskLoop (dart:async/schedule_microtask.dart:49:5) E/flutter (30841): I/flutter (30841): ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── I/flutter (30841): │ Null check operator used on a null value I/flutter (30841): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ I/flutter (30841): │ 08:18:00.958 (+0:00:21.649522) I/flutter (30841): ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ I/flutter (30841): │ ⛔ Uncaught flutter error I/flutter (30841): └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── I/flutter (30841): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════ I/flutter (30841): The following _TypeError was thrown during paint(): I/flutter (30841): Null check operator used on a null value I/flutter (30841): I/flutter (30841): The relevant error-causing widget was: I/flutter (30841): PdfViewer I/flutter (30841): PdfViewer:file:///Users/kim/Development/projects/freelance/books_5000/lib/src/presentation/modules/book/viewer/book_viewer_page.dart:116:34 I/flutter (30841): I/flutter (30841): When the exception was thrown, this was the stack: I/flutter (30841): #0 PdfViewerController.viewSize (package:pdfrx/src/widgets/pdf_viewer.dart:874:30) I/flutter (30841): #1 PdfViewerController.visibleRect (package:pdfrx/src/widgets/pdf_viewer.dart:887:49) I/flutter (30841): #2 _PdfViewerState._getCacheExtentRect (package:pdfrx/src/widgets/pdf_viewer.dart:666:38) I/flutter (30841): #3 _PdfViewerState._customPaint (package:pdfrx/src/widgets/pdf_viewer.dart:707:24) I/flutter (30841): #4 _CustomPainter.paint (package:pdfrx/src/widgets/pdf_viewer.dart:1296:62) I/flutter (30841): #5 RenderCustomPaint._paintWithPainter (package:flutter/src/rendering/custom_paint.dart:588:13) I/flutter (30841): #6 RenderCustomPaint.paint (package:flutter/src/rendering/custom_paint.dart:635:7) I/flutter (30841): #7 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3208:7) I/flutter (30841): #8 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:250:13) I/flutter (30841): #9 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:129:13) I/flutter (30841): #10 PaintingContext.pushTransform (package:flutter/src/rendering/object.dart:687:14) I/flutter (30841): #11 RenderTransform.paint (package:flutter/src/rendering/proxy_box.dart:2529:27) I/flutter (30841): #12 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3208:7) I/flutter (30841): #13 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:250:13) I/flutter (30841): #14 RenderShiftedBox.paint (package:flutter/src/rendering/shifted_box.dart:74:15) I/flutter (30841): #15 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3208:7) I/flutter (30841): #16 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:250:13) I/flutter (30841): #17 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:129:13) I/flutter (30841): #18 PaintingContext.pushClipRect.<anonymous closure> (package:flutter/src/rendering/object.dart:549:83) I/flutter (30841): #19 ClipContext._clipAndPaint (package:flutter/src/painting/clip.dart:25:12) I/flutter (30841): #20 ClipContext.clipRectAndPaint (package:flutter/src/painting/clip.dart:53:5) I/flutter (30841): #21 PaintingContext.pushClipRect (package:flutter/src/rendering/object.dart:549:7) I/flutter (30841): #22 RenderClipRect.paint (package:flutter/src/rendering/proxy_box.dart:1532:25) I/flutter (30841): #23 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3208:7) I/flutter (30841): #24 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:250:13) I/flutter (30841): #25 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:129:13) I/flutter (30841): #26 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3208:7) I/flutter (30841): #27 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:250:13) I/flutter (30841): #28 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:129:13) I/flutter (30841): #29 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3208:7) I/flutter (30841): #30 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:250:13) I/flutter (30841): #31 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:129:13) I/flutter (30841): #32 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3208:7) I/flutter (30841): #33 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:250:13) I/flutter (30841): #34 RenderBoxContainerDefaultsMixin.defaultPaint (package:flutter/src/rendering/box.dart:2882:15) I/flutter (30841): #35 RenderStack.paintStack (package:flutter/src/rendering/stack.dart:640:5) I/flutter (30841): #36 RenderStack.paint (package:flutter/src/rendering/stack.dart:656:7) I/flutter (30841): #37 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3208:7) I/flutter (30841): #38 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:250:13) I/flutter (30841): #39 RenderProxyBoxMixin.paint (package:flutter/src/rendering/proxy_box.dart:129:13) I/flutter (30841): #40 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3208:7) I/flutter (30841): #41 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:250:13) I/flutter (30841): #42 _RenderColoredBox.paint (package:flutter/src/widgets/basic.dart:7813:15) I/flutter (30841): #43 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3208:7) I/flutter (30841): #44 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:250:13) I/flutter (30841): #45 _RenderLayoutBuilder.paint (package:flutter/src/widgets/layout_builder.dart:333:15) I/flutter (30841): #46 RenderObject._paintWithContext (package:flutter/src/rendering/object.dart:3208:7) I/flutter (30841): #47 PaintingContext.paintChild (package:flutter/src/rendering/object.dart:250:13)

Noted that this error occurred only when using controller, If I don't apply controller, it'll worked just fine

Opening video files inside of opened PDF files (by click/ tap on widget)

Hey @espresso3389
Do you have any plans for adding a feature to open a video file from inside the PDF view?

I have been using flutter_pdfview before this and in it, if you click on an item inside a PDF file (e.g. a video embedded inside of a PDF), the video is passed to the default video player.

If you're already working on it, could you tell me about an expected timeline for the feature?

In either case, would love to hear your comments on how to implement the same? I'm guessing this can be handled somewhere in pdf_widgets.dart, in the _buildPageOverlayWidgets function?

Is text selection possible on PDF?

I'm interested in using the [pdfrx] for my Android application. I would like to know if it supports text selection functionality. Specifically, I would like to implement a feature where users can long-press on a PDF document and select/highlight text.

I've explored the documentation and codebase, but I couldn't find any specific information regarding text selection. Could you please clarify if this feature is supported or provide any guidance on how to achieve it?

Thank you for your assistance!

Android build broken? Cannot find libpdfium.so error

The Android example build from commit 706da7c can't show any pdf. It sometimes gives 'null PdfViewerController' error, sometimes 'cannot find libpdfium.so dynamic lib' error. I checked, the .so libs are in the path like android/.cxx/Debug/2a416433/arm64-v8a/pdfium/chromium%2F6150/lib/${arch}.

But the old commit 286caf0 is fine.

Could it be that the following change causing it?

set(PDFIUM_LIBS_DIR ${CMAKE_SOURCE_DIR}/.lib/${PDFIUM_RELEASE})

iOS run Cocoapods issue

When running on iOS, I have this error :

    Fetching external sources
    -> Fetching podspec for `Flutter` from `Flutter`
    -> Fetching podspec for `path_provider_foundation` from `.symlinks/plugins/path_provider_foundation/darwin`
    -> Fetching podspec for `pdfrx` from `.symlinks/plugins/pdfrx/darwin`

    Resolving dependencies of `Podfile`
      CDN: trunk Relative path: CocoaPods-version.yml exists! Returning local because checking is only performed in repo update
      CDN: trunk Relative path: all_pods_versions_4_2_c.txt exists! Returning local because checking is only performed in repo update
      CDN: trunk Relative path: Specs/4/2/c/FlutterMacOS/3.16.0/FlutterMacOS.podspec.json exists! Returning local because checking is only performed in repo update
    [!] CocoaPods could not find compatible versions for pod "pdfrx":
      In Podfile:
        pdfrx (from `.symlinks/plugins/pdfrx/darwin`)

    Specs satisfying the `pdfrx (from `.symlinks/plugins/pdfrx/darwin`)` dependency were found, but they required a higher minimum deployment target.

    /Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolution.rb:317:in `raise_error_unless_state'
    /Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolution.rb:299:in `block in unwind_for_conflict'
    /Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolution.rb:297:in `tap'
    /Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolution.rb:297:in `unwind_for_conflict'
    /Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolution.rb:682:in `attempt_to_activate'
    /Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolution.rb:254:in `process_topmost_state'
    /Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolution.rb:182:in `resolve'
    /Library/Ruby/Gems/2.6.0/gems/molinillo-0.8.0/lib/molinillo/resolver.rb:43:in `resolve'
    /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.12.1/lib/cocoapods/resolver.rb:94:in `resolve'
    /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.12.1/lib/cocoapods/installer/analyzer.rb:1082:in `block in resolve_dependencies'
    /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.12.1/lib/cocoapods/user_interface.rb:64:in `section'
    /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.12.1/lib/cocoapods/installer/analyzer.rb:1080:in `resolve_dependencies'
    /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.12.1/lib/cocoapods/installer/analyzer.rb:125:in `analyze'
    /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.12.1/lib/cocoapods/installer.rb:422:in `analyze'
    /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.12.1/lib/cocoapods/installer.rb:244:in `block in resolve_dependencies'
    /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.12.1/lib/cocoapods/user_interface.rb:64:in `section'
    /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.12.1/lib/cocoapods/installer.rb:243:in `resolve_dependencies'
    /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.12.1/lib/cocoapods/installer.rb:162:in `install!'
    /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.12.1/lib/cocoapods/command/install.rb:52:in `run'
    /Library/Ruby/Gems/2.6.0/gems/claide-1.1.0/lib/claide/command.rb:334:in `run'
    /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.12.1/lib/cocoapods/command.rb:52:in `run'
    /Library/Ruby/Gems/2.6.0/gems/cocoapods-1.12.1/bin/pod:55:in `<top (required)>'
    /usr/local/bin/pod:23:in `load'
    /usr/local/bin/pod:23:in `<main>'

Error output from CocoaPods:
↳

    [!] Automatically assigning platform `iOS` with version `12.0` on target `Runner` because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.

Error running pod install
Error launching application on iPhone SE (3rd generation).

My flutter doctor output :

fabien@branchel test_pdfrx % flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.16.7, on macOS 14.2.1 23C71 darwin-arm64, locale fr-FR)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 15.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2022.2)
[✓] VS Code (version 1.85.1)
[✓] Connected device (4 available)
[✓] Network resources

• No issues found!

Render performance is terrible on many page documents

Excellent work but underlying philosophy regarding rendering/caching/rasterizing pages is a problem.
Rendering a very basic many-page PDF file full of basic text shows very bad performance and long delays waiting for pages to render. Also pages that have already been rendered are disposed and not cached. For example, scrolling to the bottom of a long document and then to the top and back to the bottom sees the bottom pages needing to re-render with a long delay.

PdfViewer Uint8List

Is it possible to display data (Uint8List) in PdfViewer without first saving to temp file? Viewing directly from data (Uint8List) returned from a rest call. Thanks!

PdfDocumentReference is disposed too aggressively / PdfViewer should support viewing a PdfDocument.

If you have a PdfDocument in memory, there is not a good way to use it with the PdfViewer.

PdfViewer should support direct rendering a PdfDocument rather than forcing the use of a PdfDocumentRef + PdfStore.

You can use the PdfStore.load method to return a PdfDocument as a PdfDocumentRef, but the magic dispose of PdfDocumentRef will get in the way and prevent you from reusing the PdfDocument:

  @override
  void removeListener(VoidCallback listener) {
    _listeners.remove(listener);
    if (_listeners.isEmpty) {
      dispose();
    }
  }

As soon as the viewer disposes, the reference will dispose itself, breaking the PdfDocument. Dispose should not be automatically called by the removeListener call, the reference should only be disposed when dispose is called manually. If you use PdfStore.load to try to manage the lifecycle of the document on your own, this forces you to add a dummy listener just to prevent it from being disposed if you need to reuse the reference later.

During Android build, CMake '3.18.1' was not found in SDK

Gradle task assembleAppRelease failed with exit code 1

[CXX1300] CMake '3.18.1' was not found in SDK, PATH, or by cmake.dir property.
[CXX1301] - CMake '3.22.1' found in SDK did not satisfy requested version.

FAILURE: Build failed with an exception.

  • What went wrong:
    A problem occurred configuring project ':pdfrx'.

java.lang.NullPointerException (no error message)

  • Try:

Run with --stacktrace option to get the stack trace.
Run with --info or --debug option to get more log output.
Run with --scan to get full insights.

BUILD FAILED in 2s
Running Gradle task 'assemblePadRelease'...
Gradle task assemblePadRelease failed with exit code 1

flutter doctor --verbose
[✓] Flutter (Channel stable, 3.16.5, on macOS 13.4 22F66 darwin-arm64 (Rosetta), locale zh-Hans-CN)
• Flutter version 3.16.5 on channel stable at /Users/spring/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision 78666c8dc5 (5 weeks ago), 2023-12-19 16:14:14 -0800
• Engine revision 3f3e560236
• Dart version 3.2.3
• DevTools version 2.28.4
• Pub download mirror https://pub.flutter-io.cn
• Flutter download mirror https://storage.flutter-io.cn

Apple M2

not be able to run

pdfium binary download failure during build process

hello, I saw the readme document saying that pdfrx is a PDF viewer implementation built on the top of pdfium.

I have never used pdfium and I don’t quite understand what it is. Do I need to do anything?

When I run the example code(Flutter 3.16.3), it works normally on the web side, but cannot be used on windows. The prompt is as follows,Thanks

CMake Error at flutter/ephemeral/.plugin_symlinks/pdfrx/windows/CMakeLists.txt:53 (file):
file COPY cannot find
"E:/code/pdfrx/example/build/windows/x64/pdfium/chromium%2F6124/bin/pdfium.dll":
No error.

CMake Error at flutter/ephemeral/.plugin_symlinks/pdfrx/windows/CMakeLists.txt:57 (file):
file COPY cannot find
"E:/code/pdfrx/example/build/windows/x64/pdfium/chromium%2F6124/lib/pdfium.dll.lib":
No error.

CMake Error at flutter/ephemeral/.plugin_symlinks/pdfrx/windows/CMakeLists.txt:62 (file):
file COPY cannot find
"E:/code/pdfrx/example/build/windows/x64/pdfium/chromium%2F6124/include":
No error.

Desktop: scroll by mouse-wheel

Currently, PdfViewer does not support scroll by mouse-wheel on desktop platforms.
We'd better support scroll by mouse-wheel but we should investigate the way to implement it.

According to flutter/flutter#121961, they don't want to implement scroll by mouse-wheel on InteractiveViewer anyway.

So, the approach may be one of

  • Forking InteractiveViewer to implement our own scroll by mouse-wheel feature
  • Switching the container to TwoDimensionalScrollable

The non-abstract class '_PdfTextRenderBox' is missing implementations for these members: - Selectable.boundingBoxes

Launching lib/main.dart on Linux in debug mode...
ERROR: ../.pub-cache/hosted/pub.dev/pdfrx-0.4.10/lib/src/widgets/pdf_page_text_overlay.dart:95:7: Error: The non-abstract class '_PdfTextRenderBox' is missing implementations for these members:
ERROR:  - Selectable.boundingBoxes
ERROR: Try to either
ERROR:  - provide an implementation,
ERROR:  - inherit an implementation from a superclass or mixin,
ERROR:  - mark the class as abstract, or
ERROR:  - provide a 'noSuchMethod' implementation.
ERROR: class _PdfTextRenderBox extends RenderBox with Selectable, SelectionRegistrant {
ERROR:       ^^^^^^^^^^^^^^^^^
ERROR: ../flutter/packages/flutter/lib/src/rendering/selection.dart:147:18: Context: 'Selectable.boundingBoxes' is defined here.
ERROR:   List<Rect> get boundingBoxes;
ERROR:                  ^^^^^^^^^^^^^
ERROR: Target kernel_snapshot failed: Exception
Building Linux application...
Error: Build process failed

How to solve this error comes in linux build?

Flutter 3.19.0-13.0.pre.32 • channel master • https://github.com/flutter/flutter.git
Framework • revision ccb2b4439a (5 hours ago) • 2024-01-30 14:59:24 +0800
Engine • revision 438e9b4d7d
Tools • Dart 3.4.0 (build 3.4.0-82.0.dev) • DevTools 2.31.0```

Execution failed for task ':pdfrx:mergeReleaseNativeLibs'. > A failure occurred while executing com.android.build.gradle.internal.tasks.MergeNativeLibsTask$MergeNativeLibsTaskWorkAction

I have trouble build the apk with pdfrx install.

Below is error I got

FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':pdfrx:mergeReleaseNativeLibs'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.MergeNativeLibsTask$MergeNativeLibsTaskWorkAction
   > 2 files found with path 'lib/arm64-v8a/libpdfium.so' from inputs:
      - /opt/atlassian/pipelines/agent/build/build/pdfrx/intermediates/merged_jni_libs/release/out/arm64-v8a/libpdfium.so
      - /opt/atlassian/pipelines/agent/build/build/pdfrx/intermediates/cxx/RelWithDebInfo/1o3w592y/obj/arm64-v8a/libpdfium.so
     If you are using jniLibs and CMake IMPORTED targets, see
     https://developer.android.com/r/tools/jniLibs-vs-imported-targets

I have try to add packagingOptions like so in app level build.gradle but not working also.

android {
    
    packagingOptions {
        pickFirst 'lib/x86/libpdfium.so'
        pickFirst 'lib/x86_64/libpdfium.so'
        pickFirst 'lib/armeabi-v7a/libpdfium.so'
        pickFirst 'lib/arm64-v8a/libpdfium.so'
    }
//rest of flavors, compile, etc...
}

Render one page at a time (pageFling) instead of continuous rendering of pages

The current version renders the pages in continuous mode. i.e. you can have the bottom of page 1 above and the top of page 2 below. AndroidPdfViewer instead allows flinging a single page at a time (with pageFling property).

 /** Spacing between pages, in px */
    private int spacingPx = 0;

    /** Add dynamic spacing to fit each page separately on the screen. */
    private boolean autoSpacing = false;

    /** Fling a single page at a time */
    private boolean pageFling = true;

See this class:
https://github.com/barteksc/AndroidPdfViewer/blob/master/android-pdf-viewer/src/main/java/com/github/barteksc/pdfviewer/PDFView.java

Can you add such a feature too?

PdfViewer could not be scrollable when nested inside SingleChildScrollView

Issue Description:
I have embedded a PDF viewer widget inside a SingleChildScrollView in my Flutter application. However, I've encountered an issue where the PDF viewer becomes non-scrollable when nested in this way.

Expected Behavior:
The expected behavior is that the PDF viewer should remain scrollable even when placed inside a SingleChildScrollView.

Actual Behavior:
The PDF viewer loses its scrolling functionality when nested inside a SingleChildScrollView.

Steps to Reproduce:

  1. Place a PDF viewer widget inside a SingleChildScrollView.
  2. Attempt to scroll through the PDF content.

Flutter Environment:

  • Flutter version: 3.16.7
  • Platform: (web-desktop) not tested on mobile

Additional Context:
I am looking for a solution or workaround that allows the PDF viewer to be scrollable while still being a child of SingleChildScrollView. Any suggestions or insights into why this behavior occurs would be greatly appreciated.

Error in build web assembly flutter channel master

../../../../AppData/Local/Pub/Cache/hosted/pub.dev/pdfrx-0.4.10/lib/src/widgets/pdf_page_text_overlay.dart(95,7): error G76B49859: The non-abstract class '_PdfTextRenderBox' is missing implementations for these members

Generate thumbnail from pdf

Hello,

I'm trying to switch from pdf_render over to pdfrx but having some troubles doing this.

My "old" thumbnail generation was something like this

import 'package:pdf_render/pdf_render.dart';

Future<Uint8List?> createPdfThumbnail(Uint8List fileData) async {
  final PdfDocument doc = await PdfDocument.openData(fileData);
  final PdfPage page = await doc.getPage(1);

  PdfPageImage pageImage;

  if (page.width > page.height) {
    pageImage = await page.render(
      fullWidth: maxSideSize,
      fullHeight: (page.height * maxSideSize / page.width),
    );
  } else {
    pageImage = await page.render(
      fullHeight: maxSideSize,
      fullWidth: (page.width * maxSideSize / page.height),
    );
  }

  // Convert PdfPageImage to ui.Image
  final ui.Image uiImage = await pageImage.createImageIfNotAvailable();

  // Convert ui.Image to img.Image for further processing
  final img.Image finalImage = await convertUiImageToImgImage(uiImage);

  doc.dispose();

  return img.encodeJpg(finalImage);
}

Changing to pdfrx it will be

import 'package:pdfrx/pdfrx.dart';

Future<Uint8List?> createPdfThumbnail(Uint8List fileData) async {
  final PdfDocument doc = await PdfDocument.openData(fileData);
  final PdfPage page = await doc.getPage(1);

  PdfImage pageImage;

  if (page.width > page.height) {
    pageImage = await page.render(
      fullWidth: maxSideSize,
      fullHeight: (page.height * maxSideSize / page.width),
    );
  } else {
    pageImage = await page.render(
      fullHeight: maxSideSize,
      fullWidth: (page.width * maxSideSize / page.height),
    );
  }

  // Convert PdfPageImage to ui.Image
  final ui.Image uiImage = await pageImage.createImage();

  // Convert ui.Image to img.Image for further processing
  final img.Image finalImage = await convertUiImageToImgImage(uiImage);

  doc.dispose();

  return img.encodeJpg(finalImage);
}

And getting this error (but only in flutter for web, working fine on MacOS build)

TypeError: Cannot perform %TypedArray%.prototype.set on a detached ArrayBuffer
dart-sdk/lib/_internal/js_dev_runtime/private/native_typed_data.dart 691:31  [_setRangeFast]
dart-sdk/lib/_internal/js_dev_runtime/private/native_typed_data.dart 735:7   setRange
dart-sdk/lib/convert/byte_conversion.dart 81:5                               add
dart-sdk/lib/async/zone.dart 1594:9                                          runUnaryGuarded
dart-sdk/lib/async/stream_impl.dart 339:5                                    [_sendData]
dart-sdk/lib/async/stream_impl.dart 271:7                                    [_add]
dart-sdk/lib/async/stream_transformers.dart 63:11                            [_add]
dart-sdk/lib/async/stream_transformers.dart 13:5                             add
packages/dio/src/progress_stream/browser_progress_stream.dart 33:15          <fn>
dart-sdk/lib/async/stream_transformers.dart 209:7                            add
dart-sdk/lib/async/stream_transformers.dart 111:7                            [_handleData]
dart-sdk/lib/async/zone.dart 1594:9                                          runUnaryGuarded
dart-sdk/lib/async/stream_impl.dart 339:5                                    [_sendData]
dart-sdk/lib/async/stream_impl.dart 515:13                                   perform
dart-sdk/lib/async/stream_impl.dart 620:10                                   handleNext
dart-sdk/lib/async/stream_impl.dart 591:7                                    callback
dart-sdk/lib/async/schedule_microtask.dart 40:11                             _microtaskLoop
dart-sdk/lib/async/schedule_microtask.dart 49:5                              _startMicrotaskLoop
dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 181:7           <fn>

The method 'uri' isn't defined for the type 'PdfViewer'.

The method 'uri' isn't defined for the type 'PdfViewer'.

The method 'PdfViewerParams' isn't defined for the type '_ContentPDFPageState'.

Sample below
final pdfpage = PdfViewer.uri(
Uri.parse(current.url),
controller: controller,
displayParams: PdfViewerParams(
maxScale: 8,
enableTextSelection: !_isDesktop,
),
);

Linux - libpdfium.so: error adding symbols: file in wrong format - ARM64

When building for linux on an ARM Processor (i have used a Raspberry), I'm getting the following output and the build fails:

[+2799 ms] Building Linux application...
[+1371 ms] executing: [build/linux/arm64/release/] cmake -G Ninja -DCMAKE_BUILD_TYPE=Release
-DFLUTTER_TARGET_PLATFORM=linux-arm64 /workspace/pdf_viewer/linux
[+5113 ms] -- The CXX compiler identification is Clang 11.0.1
[ +116 ms] -- Detecting CXX compiler ABI info
[+4969 ms] -- Detecting CXX compiler ABI info - done
[ +180 ms] -- Check for working CXX compiler: /usr/bin/clang++ - skipped
[  +10 ms] -- Detecting CXX compile features
[   +7 ms] -- Detecting CXX compile features - done
[ +298 ms] -- Found PkgConfig: /usr/bin/pkg-config (found version "0.29.2") 
[  +30 ms] -- Checking for module 'gtk+-3.0'
[+1181 ms] --   Found gtk+-3.0, version 3.24.24
[+4721 ms] -- Checking for module 'glib-2.0'
[+1070 ms] --   Found glib-2.0, version 2.66.8
[+2607 ms] -- Checking for module 'gio-2.0'
[ +992 ms] --   Found gio-2.0, version 2.66.8
[+7520 ms] -- Configuring done
[+1859 ms] -- Generating done
[ +817 ms] -- Build files have been written to:
/workspace/pdf_viewer/linux/build/linux/arm64/release
[ +321 ms] executing: ninja -C build/linux/arm64/release install
[ +306 ms] ninja: Entering directory `build/linux/arm64/release'
[+11948 ms] [1/22] Building CXX object plugins/pdfrx/shared/CMakeFiles/pdfrx.dir/pdfium_interop.cpp.o
[+1432 ms] [2/22] Linking CXX shared library plugins/pdfrx/shared/libpdfrx.so
[   +3 ms] FAILED: plugins/pdfrx/shared/libpdfrx.so 
[   +7 ms] : && /usr/bin/clang++ -fPIC -O3 -DNDEBUG   -shared -Wl,-soname,libpdfrx.so -o plugins/pdfrx/shared/libpdfrx.so
plugins/pdfrx/shared/CMakeFiles/pdfrx.dir/pdfium_interop.cpp.o
-Wl,-rpath,/workspace/pdf_viewer/linux/build/linux/arm64/release/.lib/x64  .lib/x64/libpdfium.so &&
:
[  +16 ms] /usr/bin/ld: .lib/x64/libpdfium.so: error adding symbols: file in wrong format
[  +15 ms] clang: error: linker command failed with exit code 1 (use -v to see invocation)

FAILURE: Build hang up.

  • What went wrong:
    A problem occurred when cmake tries to link 'pdfium' dependency.

usr/bin/ld: .lib/x64/libpdfium.so: error adding symbols: file in wrong format

  • Flutter Doctor:
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.16.7, on Debian GNU/Linux 11 (bullseye) 5.10.0-27-arm64, locale en_US.UTF-8)
[✓] Linux toolchain - develop for Linux desktop
[!] Flutter IDE Support (No supported IDEs installed)
[✓] Connected device (1 available)
[✓] Network resources
  • Reproduce:

Run flutter build linux -v.

It works fine on my linux x86_64 system. I think thats because of the hard-coded PDFIUM_LINUX_ABI in the file linux/CMakeLists.txt. When i change the variable value to "arm64" the build works fine, so a more dynamic CPU Family selection might be a solution.

bug when loading certain documents using PdfViewer.uri()

I get the following error when loading some test pdf files from uri.

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: RangeError (index): Invalid value: Valid value range is empty: 0
#0      List.[] (dart:core-patch/growable_array.dart:264:36)
#1      PdfDocumentPdfium.getPage (package:pdfrx/src/pdfium/pdfrx_pdfium.dart:271:58)
#2      _PdfViewerState._onDocumentChanged (package:pdfrx/src/pdfrx_widgets.dart:363:24)
#3      PdfDocumentRef.notifyListeners (package:pdfrx/src/pdfrx_widgets.dart:53:15)
#4      PdfDocumentStore.load.<anonymous closure> (package:pdfrx/src/pdfrx_widgets.dart:108:14)
<asynchronous suspension>
#5      objectSynchronized.<anonymous closure> (package:synchronized/src/extension_impl.dart:37:18)
<asynchronous suspension>
#6      BasicLock.synchronized (package:synchronized/src/basic_lock.dart:33:16)
<asynchronous suspension>
#7      objectSynchronized (package:synchronized/src/extension_impl.dart:34:12)
<asynchronous suspension>
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: RangeError (end): Invalid value: Not in inclusive range 262144..393532: 655676
#0      RangeError.checkValidRange (dart:core/errors.dart:365:9)
#1      _TypedListBase.setRange (dart:typed_data-patch/typed_data_patch.dart:109:18)
#2      _IntListMixin.setRange (dart:typed_data-patch/typed_data_patch.dart)
#3      PdfFileCacheMemory.read (package:pdfrx/src/pdfrx_downloader.dart:104:12)
#4      pdfDocumentFromUri.<anonymous closure> (package:pdfrx/src/pdfrx_downloader.dart:198:21)
<asynchronous suspension>

code to reproduce:

import 'package:flutter/material.dart';
import 'package:pdfrx/pdfrx.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Center(
        child: PdfViewer.uri(
          Uri.parse(
              'https://upload.wikimedia.org/wikipedia/commons/3/31/LEVEL_11_FLOOR_PLAN.pdf'),
        ),
      ),
    );
  }
}

the same pdf loads without error if dowloaded to assets and displayed using PdfViewer.asset()

the problem was present on android and ios. Web didn't display the pdf but didn't throw the error.

PdfViewer.uri is broken on web for non relative paths

PdfViewer.uri doesn't work with absolute URLs because it throws out everything but the path:

 @override
  Future<PdfDocument> openUri(
    Uri uri, {
    String? password,
    PdfPasswordProvider? passwordProvider,
    PdfDownloadProgressCallback? progressCallback,
  }) =>
      openFile(
        uri.path,
        password: password,
        passwordProvider: passwordProvider,
      );

  static bool _isPasswordError(dynamic e) =>
      e.toString().startsWith('PasswordException:');
}

if your URI requires the host / scheme, etc. you can't view the document. We were loading PDFs with pdf_render via remote URLs before, but those don't work with Pdfrx because of this.

Because of #36 we can't manually load the pdfs and pass them to the viewer with http.get either.

Search

Hi, this looks like a great promising library. Does searching for text work?
Thanks!

Andoird - CMake '3.22.1' was not found in SDK, PATH, or by cmake.dir property.

When building for android, I'm getting the following output and the build fails:

[CXX1301] - CMake '3.18.1' found in SDK did not satisfy requested version.
[CXX1300] CMake '3.22.1' was not found in SDK, PATH, or by cmake.dir property.
[CXX1301] - CMake '3.18.1' found in SDK did not satisfy requested version.
[CXX1300] CMake '3.22.1' was not found in SDK, PATH, or by cmake.dir property.
[CXX1301] - CMake '3.18.1' found in SDK did not satisfy requested version.
[CXX1300] CMake '3.22.1' was not found in SDK, PATH, or by cmake.dir property.
[CXX1301] - CMake '3.18.1' found in SDK did not satisfy requested version.

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring project ':pdfrx'.
> com.android.builder.errors.EvalIssueException: [CXX1300] CMake '3.22.1' was not found in SDK, PATH, or by cmake.dir property.

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

It works fine on iOS, macos and web. I'm on an M1 Mac mini.

Feature Request: control page alignment

Currently, either one of the horizontal/vertical directions can be easily "fit" into view and therefore centered. But another direction could not be centered easily (or impossible??)

Currently, pages are normally "centered" but we want to customize the layout.

Execution failed for task ':pdfrx:configureCMakeDebug[armeabi-v7a]'. > [CXX1405] error when building with cmake using C:\Users\miraj\AppData\Local\Pub\Cache\hosted\pub.dev\pdfrx-0.4.10\android\CMakeLists.txt: Build command failed

After using this package while I am build my Project It is showing build exception.
The error says
-- Check for working CXX compiler: C:/Users/miraj/AppData/Local/Android/Sdk/ndk/21.4.7075529/toolchains/llvm/prebuilt/windows-x86_64/bin/clang++.exe - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring incomplete, errors occurred!
See also "C:/Users/miraj/AppData/Local/Pub/Cache/hosted/pub.dev/pdfrx-0.4.10/android/.cxx/Debug/2m4q6j72/armeabi-v7a/CMakeFiles/CMakeOutput.log".

CMake Error at CMakeLists.txt:62 (file):
file Failed to create link
'C:/Users/miraj/AppData/Local/Pub/Cache/hosted/pub.dev/pdfrx-0.4.10/android/.lib/latest'
because existing path cannot be removed: File exists
3

CMake Warning (dev) at CMakeLists.txt:66 (set):
Cannot set "pdfrx_bundled_libraries": current scope has no parent.
This warning is for project developers. Use -Wno-dev to suppress it.
3

  • Try:

Run with --stacktrace option to get the stack trace.
Run with --info or --debug option to get more log output.
Run with --scan to get full insights.

BUILD FAILED in 31s
Exception: Gradle task assembleDebug failed with exit code 1

Debug running error while building Android project.

The error message is as follows:

../pdfrx-0.2.1/lib/src/pdfium/pdfium_interop.dart:59:56: Error: listener expects a static function as parameter. dart:ffi only supports calling static Dart functions from native code. Closures and tear-offs are not supported because they can capture context.
    _nativeCallable = _NativeFileReadCallable.listener(readNative);
                                                       ^
Target kernel_snapshot failed: Exception


FAILURE: Build failed with an exception.

And a deprecated splash screen error while using Android Studio for a Flutter project. The error message is as follows:

A splash screen was provided to Flutter, but this is deprecated. See flutter.dev/go/android-splash-migration for migration steps.

I followed the provided link (flutter.dev/go/android-splash-migration) to review the migration steps, but I'm still unsure about how to resolve this issue.
Flutter version:3.13.9

Precompiled binary for iOS/macOS

Because I should customize the building process too much, I should build xcframeworks by my hand.
And, it's not good for casual users to build the binary on their own machine. They should be easily downloadable from some site.

Bug: Tests fail due to null operator check on PdfViewerController

Hi @espresso3389

I'm writing a few tests to verify the plugin works, and the tests fail, because PdfViewerController is not properly initialized:

// https://github.com/espresso3389/pdfrx/blob/master/lib/src/widgets/pdf_viewer.dart#L146
// current
PdfViewerController? _controller;
// should be
PdfViewerController? _controller = PdfViewerController();

Might be better to handle the above in the initState instead.

Sample test file where bug exists:

testWidgets('Test PDF Viewer', (WidgetTester tester) async {
    final String testPDFPath = 'test.pdf';
    PdfViewerController _controller = MockPDFViewController();
        final MaterialApp materialApp = MaterialApp(
          home: Scaffold(
            body: PdfViewer.file(
              testPDFPath,
              controller: _controller,
        ),
      ),
    );
    await tester.pumpWidget(materialApp);
    expect(find.byWidgetPredicate((pdfView) => pdfView is PdfViewer), findsOneWidget);
  });

Log from the test run:

00:02 +2: Test PDF Viewer                                                                                                                                                                                                           
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following _TypeError was thrown while finalizing the widget tree:
Null check operator used on a null value

When the exception was thrown, this was the stack:
#0      _PdfViewerState.dispose (package:pdfrx/src/widgets/pdf_viewer.dart:296:16)
#1      StatefulElement.unmount (package:flutter/src/widgets/framework.dart:5680:11)
#2      _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2067:13)
#3      _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#4      SingleChildRenderObjectElement.visitChildren (package:flutter/src/widgets/framework.dart:6722:14)
#5      _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#6      _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#7      ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)
#8      _InactiveElements._unmount (package:flutter/src/widgets/framework.dart:2063:13)
#9      _InactiveElements._unmount.<anonymous closure> (package:flutter/src/widgets/framework.dart:2065:7)
#10     ComponentElement.visitChildren (package:flutter/src/widgets/framework.dart:5523:14)

...

════════════════════════════════════════════════════════════════════════════════════════════════════
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following message was thrown:
Multiple exceptions (2) were detected during the running of the current test, and at least one was
unexpected.
════════════════════════════════════════════════════════════════════════════════════════════════════
00:02 +2 -1: Test PDF Viewer [E]                                                                                                                                                                                                    
  Test failed. See exception logs above.
  The test description was: Test PDF Viewer with completed download

I'd be grateful if you could patch this up and release a hotfix - I'm trying a few things with your library and it seems fun so far! Thanks a ton for all the effort.

Allow horizontal pages

I'm still pretty new to pdfrx, so I might just be missing something, but is there a way to lay pages out horizontally?

If not, that would be a nice feature to have.

Uint8List

The package no longer supports Uint8List data

Rendered text is soft

Windows (Left is rendered on Edge, Right is on Flutter Windows debug screen)
aliasing

Web (Left is rendered on Edge, Right is on Flutter Web on Edge)
aliasing2

It's not as noticeable on Flutter Windows, but in both cases, Flutter seems to have softer text. I'm wondering if this is caused by render options PDFium and pdf.js or if Flutter is applying some anti-aliasing on the component. Any pointers for sharpening up the text would be helpful.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.