Skip to content

Commit 82618be

Browse files
committed
perf: only parse pdf once, and dispose it properly
1 parent a85d951 commit 82618be

File tree

4 files changed

+51
-3
lines changed

4 files changed

+51
-3
lines changed

lib/components/canvas/_asset_cache.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:collection/collection.dart';
55
import 'package:flutter/painting.dart';
66
import 'package:logging/logging.dart';
77
import 'package:saber/components/canvas/image/editor_image.dart';
8+
import 'package:saber/components/canvas/image/pdf_document_cache.dart';
89

910
/// A cache for assets that are loaded from disk.
1011
///
@@ -18,6 +19,8 @@ class AssetCache {
1819

1920
final log = Logger('AssetCache');
2021

22+
final pdfDocumentCache = PdfDocumentCache();
23+
2124
/// Maps a file path to its value.
2225
final Map<String, Object> _cache = {};
2326

@@ -73,6 +76,7 @@ class AssetCache {
7376
void dispose() {
7477
_images.clear();
7578
_cache.clear();
79+
pdfDocumentCache.dispose();
7680
}
7781
}
7882

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import 'dart:async';
2+
import 'dart:typed_data';
3+
4+
import 'package:pdfrx/pdfrx.dart';
5+
6+
class PdfDocumentCache {
7+
final Map<String, FutureOr<PdfDocument>> _cache = {};
8+
9+
/// Loads a PDF document from [filePath].
10+
/// If the bytes are provided, they are used instead of reading from disk.
11+
FutureOr<PdfDocument> load(String filePath, {Uint8List? pdfBytes}) {
12+
return _cache[filePath] ??= _loadCacheMiss(filePath, pdfBytes: pdfBytes);
13+
}
14+
15+
Future<PdfDocument> _loadCacheMiss(
16+
String filePath, {
17+
Uint8List? pdfBytes,
18+
}) async {
19+
final document = pdfBytes == null
20+
? PdfDocument.openFile(filePath)
21+
: PdfDocument.openData(pdfBytes);
22+
_cache[filePath] = document;
23+
return document;
24+
}
25+
26+
void dispose() {
27+
for (final documentFuture in _cache.values) {
28+
Future.value(documentFuture).then((document) => document.dispose());
29+
}
30+
_cache.clear();
31+
}
32+
}

lib/components/canvas/image/pdf_editor_image.dart

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,9 +126,11 @@ class PdfEditorImage extends EditorImage {
126126
dstRect = dstRect.topLeft & dstSize;
127127
}
128128

129-
_pdfDocument.value ??= pdfFile != null
130-
? await PdfDocument.openFile(pdfFile!.path)
131-
: await PdfDocument.openData(pdfBytes!);
129+
assert(id != -1, 'id must be set before firstLoad is called');
130+
_pdfDocument.value ??= await assetCache.pdfDocumentCache.load(
131+
pdfFile?.path ?? 'inline_pdf_$id.pdf',
132+
pdfBytes: pdfBytes,
133+
);
132134
}
133135

134136
@override
@@ -199,4 +201,11 @@ class PdfEditorImage extends EditorImage {
199201
naturalSize: naturalSize,
200202
isThumbnail: isThumbnail,
201203
);
204+
205+
@override
206+
void dispose() {
207+
pdfBytes = null;
208+
_pdfDocument.dispose();
209+
super.dispose();
210+
}
202211
}

lib/data/editor/page.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,9 @@ class EditorPage extends ChangeNotifier implements HasSize {
288288
quill.dispose();
289289
_pencilShader?.dispose();
290290
isRendered = false;
291+
for (final image in images) {
292+
image.dispose();
293+
}
291294
backgroundImage?.dispose();
292295
super.dispose();
293296
}

0 commit comments

Comments
 (0)