From ee3494c26e192bc91773246bc95e7375ad6559b9 Mon Sep 17 00:00:00 2001 From: Takashi Kawasaki Date: Fri, 26 Jan 2024 12:52:08 +0900 Subject: [PATCH] 0.4.25 --- CHANGELOG.md | 4 ++ README.md | 2 +- example/pubspec.lock | 2 +- lib/src/pdf_api.dart | 71 +++++++++++++++++++++++++ lib/src/widgets/pdf_viewer.dart | 91 ++++++--------------------------- pubspec.yaml | 2 +- 6 files changed, 95 insertions(+), 77 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 028c1ad..5660880 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.4.25 + +- FIXED: Able to scroll outside document area + # 0.4.24 - Huge refactoring on PdfViewerController; it's no longer TransformationController but just a ValueListenable diff --git a/README.md b/README.md index a900f44..a3272aa 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Add this to your package's `pubspec.yaml` file and execute `flutter pub get`: ```yaml dependencies: - pdfrx: ^0.4.24 + pdfrx: ^0.4.25 ``` ### Windows diff --git a/example/pubspec.lock b/example/pubspec.lock index bf3bb84..8b92444 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -214,7 +214,7 @@ packages: path: ".." relative: true source: path - version: "0.4.24" + version: "0.4.25" platform: dependency: transitive description: diff --git a/lib/src/pdf_api.dart b/lib/src/pdf_api.dart index 147a3e5..a01b4ba 100644 --- a/lib/src/pdf_api.dart +++ b/lib/src/pdf_api.dart @@ -369,6 +369,14 @@ abstract class PdfPageText { /// Find text fragment index for the specified text index. int getFragmentIndexForTextIndex(int textIndex) => fragments.lowerBound( _PdfPageTextFragmentForSearch(textIndex), (a, b) => a.index - b.index); + + /// Search text with [pattern]. + Stream search(Pattern pattern) async* { + final matches = pattern.allMatches(fullText); + for (final match in matches) { + yield PdfTextSearchResult.fromTextRange(this, match.start, match.end); + } + } } /// Text fragment in PDF page. @@ -417,6 +425,69 @@ class _PdfPageTextFragmentForSearch extends PdfPageTextFragment { List? get charRects => null; } +class PdfTextSearchResult { + PdfTextSearchResult(this.fragments, this.start, this.end, this.bounds); + + final List fragments; + final int start; + final int end; + final PdfRect bounds; + + static PdfTextSearchResult fromTextRange(PdfPageText pageText, int a, int b) { + // basically a should be less than or equal to b, but we anyway swap them if not + if (a > b) { + final temp = a; + a = b; + b = temp; + } + final s = pageText.getFragmentIndexForTextIndex(a); + final e = pageText.getFragmentIndexForTextIndex(b); + final sf = pageText.fragments[s]; + if (s == e) { + if (sf.charRects == null) { + return PdfTextSearchResult( + pageText.fragments.sublist(s, e), + a - sf.index, + b - sf.index, + sf.bounds, + ); + } else { + return PdfTextSearchResult( + pageText.fragments.sublist(s, e), + a - sf.index, + b - sf.index, + sf.charRects!.skip(a - sf.index).take(b - a).boundingRect(), + ); + } + } + + var bounds = sf.charRects != null + ? sf.charRects!.skip(a - sf.index).boundingRect() + : sf.bounds; + for (int i = s + 1; i < e; i++) { + bounds = bounds.merge(pageText.fragments[i].bounds); + } + final ef = pageText.fragments[e]; + bounds = bounds.merge(ef.charRects != null + ? ef.charRects!.take(b - ef.index).boundingRect() + : ef.bounds); + + return PdfTextSearchResult( + pageText.fragments.sublist(s, e), s - sf.index, e - ef.index, bounds); + } +} + +/// Extension to provide search over document feature. +extension PdfDocumentSearchExt on PdfDocument { + /// Search text with [pattern]. + Stream search(Pattern pattern) async* { + for (final page in pages) { + final text = await page.loadText(); + yield* text.search(pattern); + } + } +} + /// Rectangle in PDF page coordinates. /// /// Please note that PDF page coordinates is different from Flutter's coordinate. diff --git a/lib/src/widgets/pdf_viewer.dart b/lib/src/widgets/pdf_viewer.dart index c440bdc..28f5a2f 100644 --- a/lib/src/widgets/pdf_viewer.dart +++ b/lib/src/widgets/pdf_viewer.dart @@ -147,7 +147,8 @@ class PdfViewer extends StatefulWidget { class _PdfViewerState extends State with SingleTickerProviderStateMixin { PdfViewerController? _controller; - final TransformationController _txController = TransformationController(); + late final TransformationController _txController = + _PdfViewerTransformationController(this); late final AnimationController _animController; Animation? _animGoTo; int _animationResettingGuard = 0; @@ -1149,6 +1150,17 @@ class _PdfViewerState extends State .translate(_txController.value.xZoomed, _txController.value.yZoomed)); } +class _PdfViewerTransformationController extends TransformationController { + _PdfViewerTransformationController(this._state); + + final _PdfViewerState _state; + + @override + set value(Matrix4 newValue) { + super.value = _state._makeMatrixInSafeRange(newValue); + } +} + /// Defines page layout. class PdfPageLayout { PdfPageLayout({required this.pageLayouts, required this.documentSize}); @@ -1375,7 +1387,7 @@ class PdfViewerController extends ValueListenable { } } -extension Matrix4Ext on Matrix4 { +extension PdfMatrix4Ext on Matrix4 { /// Zoom ratio of the matrix. double get zoom => storage[0]; @@ -1409,7 +1421,7 @@ extension Matrix4Ext on Matrix4 { height: (viewSize.height - margin * 2) / zoom); } -extension RangeDouble on T { +extension _RangeDouble on T { /// Identical to [num.clamp] but it does nothing if [a] is larger or equal to [b]. T range(T a, T b) => a < b ? clamp(a, b) as T : (a + b) / 2 as T; } @@ -1417,6 +1429,7 @@ extension RangeDouble on T { extension RectExt on Rect { Rect operator *(double operand) => Rect.fromLTRB( left * operand, top * operand, right * operand, bottom * operand); + Rect operator /(double operand) => Rect.fromLTRB( left / operand, top / operand, right / operand, bottom / operand); @@ -1444,77 +1457,7 @@ class _CustomPainter extends CustomPainter { bool shouldRepaint(covariant CustomPainter oldDelegate) => true; } -class PdfPageTextSearcher { - PdfPageTextSearcher._(this._state); - final _PdfViewerState _state; - - Stream search(RegExp pattern) async* { - final pages = _state._document!.pages; - for (int i = 0; i < pages.length; i++) { - final page = pages[i]; - final pageText = await page.loadText(); - final matches = pattern.allMatches(pageText.fullText); - for (final match in matches) { - yield PdfTextSearchResult.fromTextRange( - pageText, match.start, match.end); - } - } - } -} - -class PdfTextSearchResult { - PdfTextSearchResult(this.fragments, this.start, this.end, this.bounds); - - final List fragments; - final int start; - final int end; - final PdfRect bounds; - - static PdfTextSearchResult fromTextRange(PdfPageText pageText, int a, int b) { - // basically a should be less than or equal to b, but we anyway swap them if not - if (a > b) { - final temp = a; - a = b; - b = temp; - } - final s = pageText.getFragmentIndexForTextIndex(a); - final e = pageText.getFragmentIndexForTextIndex(b); - final sf = pageText.fragments[s]; - if (s == e) { - if (sf.charRects == null) { - return PdfTextSearchResult( - pageText.fragments.sublist(s, e), - a - sf.index, - b - sf.index, - sf.bounds, - ); - } else { - return PdfTextSearchResult( - pageText.fragments.sublist(s, e), - a - sf.index, - b - sf.index, - sf.charRects!.skip(a - sf.index).take(b - a).boundingRect(), - ); - } - } - - var bounds = sf.charRects != null - ? sf.charRects!.skip(a - sf.index).boundingRect() - : sf.bounds; - for (int i = s + 1; i < e; i++) { - bounds = bounds.merge(pageText.fragments[i].bounds); - } - final ef = pageText.fragments[e]; - bounds = bounds.merge(ef.charRects != null - ? ef.charRects!.take(b - ef.index).boundingRect() - : ef.bounds); - - return PdfTextSearchResult( - pageText.fragments.sublist(s, e), s - sf.index, e - ef.index, bounds); - } -} - -extension RawKeyEventExt on RawKeyEvent { +extension _RawKeyEventExt on RawKeyEvent { /// Key pressing state of ⌘ or Control depending on the platform. bool get isCommandKeyPressed => Platform.isMacOS || Platform.isIOS ? isMetaPressed : isControlPressed; diff --git a/pubspec.yaml b/pubspec.yaml index c381667..cca094c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: pdfrx description: High speed zooming/scrolling PDF viewer implementation that supports mobile, desktop, and Web. -version: 0.4.24 +version: 0.4.25 homepage: https://github.com/espresso3389/pdfrx environment: