feat(search): index PDF text, OCR scanned PDFs on import
All checks were successful
CI / Windows build (push) Successful in 15m50s

Search now covers handwriting, the PDF text layer, AND scanned
(rasterized) PDFs.

- PdfTextIndexer runs at import: sums the embedded text layer across
  pages; if present it stores that as the document body, otherwise the
  PDF is rasterized and its rendered pages are OCR'd in the background.
  The result lands in the sidecar `pageText` field (distinct from
  `ocrText`, the handwriting OCR). Idempotent (skips a sidecar that
  already has pageText); degrades gracefully with no OCR engine.
- pdfrx_page_text_source abstracts text/render so it's testable.
- VaultSearchIndex now harvests title + typed text + handwriting OCR +
  PDF pageText, so search finds notes, typed PDFs and scanned PDFs.

analyze clean, 409 tests green.
This commit is contained in:
2026-06-25 00:23:19 +08:00
parent 20add27a30
commit e939759458
10 changed files with 668 additions and 16 deletions

View File

@@ -183,6 +183,18 @@ class SidecarRepository {
/// The OCR text loaded from the sidecar, or null.
String? get loadedOcrText => _sidecar.ocrText;
/// Replace the document-body search text (PDF embedded text layer, or
/// background OCR of a rasterized PDF — see [PdfTextIndexer]) and schedule a
/// save. No-op if unchanged. An empty string is normalized to null.
void schedulePageTextSave(String? pageText) {
final next = (pageText != null && pageText.isEmpty) ? null : pageText;
if (_sidecar.pageText == next) return;
_replace(pageText: next, clearPageText: next == null);
}
/// The document-body search text loaded from the sidecar, or null.
String? get loadedPageText => _sidecar.pageText;
/// Replace the committed strokes for [pageIndex] and schedule a save.
void scheduleStrokeSave(int pageIndex, List<EditorStroke> strokes) {
final next = Map<int, List<EditorStroke>>.from(_sidecar.strokes);
@@ -321,6 +333,8 @@ class SidecarRepository {
List<SidecarScratchLink>? scratchLinks,
String? ocrText,
bool clearOcrText = false,
String? pageText,
bool clearPageText = false,
String? background,
}) {
if (_disposed) return;
@@ -339,6 +353,7 @@ class SidecarRepository {
bookmarks: bookmarks ?? _sidecar.bookmarks,
scratchLinks: scratchLinks ?? _sidecar.scratchLinks,
ocrText: clearOcrText ? null : (ocrText ?? _sidecar.ocrText),
pageText: clearPageText ? null : (pageText ?? _sidecar.pageText),
background: background ?? _sidecar.background,
);
_timer?.cancel();