Skip to content

Commit

Permalink
Preliminary page rotation support.
Browse files Browse the repository at this point in the history
  • Loading branch information
espresso3389 committed Feb 1, 2024
1 parent f856945 commit deade72
Show file tree
Hide file tree
Showing 16 changed files with 2,345 additions and 69 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"microtask",
"nullptr",
"PAGELINK",
"PDFACTION",
"pdfium",
"Pdfjs",
"pdfrx",
Expand Down Expand Up @@ -142,4 +143,4 @@
"xloctime": "cpp",
"xstring": "cpp"
}
}
}
42 changes: 42 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,3 +390,45 @@ You can also cancel the background search:
```dart
textSearcher.resetTextSearch();
```

### PdfDocumentViewBuilder/PdfPageView

[PdfPageView](https://pub.dev/documentation/pdfrx/latest/pdfrx/PdfPageView-class.html) is just another PDF widget that shows only one page. It accepts [PdfDocument](https://pub.dev/documentation/pdfrx/latest/pdfrx/PdfDocument-class.html) and page number to show a page within the document.

[PdfDocumentViewBuilder](https://pub.dev/documentation/pdfrx/latest/pdfrx/PdfDocumentViewBuilder-class.html) is used to safely manage [PdfDocument](https://pub.dev/documentation/pdfrx/latest/pdfrx/PdfDocument-class.html) inside widget tree and it accepts `builder` parameter that creates child widgets.

The following fragment is a typical use of these widgets:

```dart
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 and sharing it between widgets

[PdfDocumentViewBuilder](https://pub.dev/documentation/pdfrx/latest/pdfrx/PdfDocumentViewBuilder-class.html) can accept [PdfDocumentRef](https://pub.dev/documentation/pdfrx/latest/pdfrx/PdfDocumentRef-class.html) from [PdfViewer](https://pub.dev/documentation/pdfrx/latest/pdfrx/PdfViewer-class.html) to safely share the same [PdfDocument](https://pub.dev/documentation/pdfrx/latest/pdfrx/PdfDocument-class.html) instance. For more information, see [example/lib/thumbnails_view.dart](example/lib/thumbnails_view.dart).
18 changes: 16 additions & 2 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class MainPage extends StatefulWidget {
}

class _MainPageState extends State<MainPage> {
final documentRef = ValueNotifier<PdfDocumentRef?>(null);
final controller = PdfViewerController();
final showLeftPane = ValueNotifier<bool>(false);
final outline = ValueNotifier<List<PdfOutlineNode>?>(null);
Expand All @@ -48,6 +49,7 @@ class _MainPageState extends State<MainPage> {
textSearcher.dispose();
showLeftPane.dispose();
outline.dispose();
documentRef.dispose();
super.dispose();
}

Expand Down Expand Up @@ -106,15 +108,25 @@ class _MainPageState extends State<MainPage> {
Expanded(
child: TabBarView(
children: [
TextSearchView(textSearcher: textSearcher),
// NOTE: documentRef is not explicitly used but it indicates that
// the document is changed.
ValueListenableBuilder(
valueListenable: documentRef,
builder: (context, documentRef, child) => child!,
child: TextSearchView(textSearcher: textSearcher),
),
ValueListenableBuilder(
valueListenable: outline,
builder: (context, outline, child) => OutlineView(
outline: outline,
controller: controller,
),
),
ThumbnailsView(controller: controller),
ValueListenableBuilder(
valueListenable: documentRef,
builder: (context, documentRef, child) => child!,
child: ThumbnailsView(controller: controller),
),
],
),
),
Expand Down Expand Up @@ -236,6 +248,8 @@ class _MainPageState extends State<MainPage> {
textSearcher.pageTextMatchPaintCallback
],
onDocumentChanged: (document) async {
documentRef.value =
controller.isReady ? controller.documentRef : null;
outline.value = await document?.loadOutline();
},
),
Expand Down
8 changes: 4 additions & 4 deletions example/lib/search_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class _TextSearchViewState extends State<TextSearchView> {
final focusNode = FocusNode();
final searchTextController = TextEditingController();
late final pageTextStore =
PdfPageTextStore(textSearcher: widget.textSearcher);
PdfPageTextCache(textSearcher: widget.textSearcher);
final scrollController = ScrollController();

@override
Expand Down Expand Up @@ -229,7 +229,7 @@ class SearchResultTile extends StatefulWidget {

final PdfTextMatch match;
final void Function() onTap;
final PdfPageTextStore pageTextStore;
final PdfPageTextCache pageTextStore;
final double height;
final bool isCurrent;

Expand Down Expand Up @@ -347,9 +347,9 @@ class _SearchResultTileState extends State<SearchResultTile> {
}

/// A helper class to cache loaded page texts.
class PdfPageTextStore {
class PdfPageTextCache {
final PdfTextSearcher textSearcher;
PdfPageTextStore({
PdfPageTextCache({
required this.textSearcher,
});

Expand Down
2 changes: 1 addition & 1 deletion example/lib/thumbnails_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class ThumbnailsView extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
color: Colors.grey,
child: controller?.documentRef == null
child: controller?.isReady != true || controller?.documentRef == null
? null
: PdfDocumentViewBuilder(
documentRef: controller!.documentRef,
Expand Down
65 changes: 56 additions & 9 deletions lib/src/pdf_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@ abstract class PdfPage {
/// PDF page height in points (height in pixels at 72 dpi) (rotated).
double get height;

/// PDF page rotation.
PdfPageRotation get rotation;

/// Render a sub-area or full image of specified PDF file.
/// Returned image should be disposed after use.
/// [x], [y], [width], [height] specify sub-area to render in pixels.
Expand Down Expand Up @@ -286,6 +289,13 @@ abstract class PdfPage {
Future<List<PdfLink>> loadLinks();
}

enum PdfPageRotation {
none,
clockwise90,
clockwise180,
clockwise270,
}

/// Annotation rendering mode.
/// - [none]: Do not render annotations.
/// - [annotation]: Render annotations.
Expand Down Expand Up @@ -616,15 +626,52 @@ class PdfRect {
/// Convert to [Rect] in Flutter coordinate. [height] specifies the height of the page (original size).
/// [scale] is used to scale the rectangle.
Rect toRect({
required double height,
double scale = 1.0,
}) =>
Rect.fromLTRB(
left * scale,
(height - top) * scale,
right * scale,
(height - bottom) * scale,
);
required PdfPage page,
Size? scaledTo,
int? rotation,
}) {
final rotated = rotate(rotation ?? page.rotation.index, page);
final scale = scaledTo == null ? 1.0 : scaledTo.height / page.height;
return Rect.fromLTRB(
rotated.left * scale,
(page.height - rotated.top) * scale,
rotated.right * scale,
(page.height - rotated.bottom) * scale,
);
}

PdfRect rotate(int rotation, PdfPage page) {
final swap = (page.rotation.index & 1) == 1;
final width = swap ? page.height : page.width;
final height = swap ? page.width : page.height;
switch (rotation & 3) {
case 0:
return this;
case 1:
return PdfRect(
bottom,
width - left,
top,
width - right,
);
case 2:
return PdfRect(
width - right,
height - bottom,
width - left,
height - top,
);
case 3:
return PdfRect(
height - top,
right,
height - bottom,
left,
);
default:
throw ArgumentError.value(rotate, 'rotate');
}
}

@override
bool operator ==(Object other) {
Expand Down
Loading

0 comments on commit deade72

Please sign in to comment.