zhixi-document-runtime/docs/pdf-strategy.md
wangdl bae6ef5726 feat: M3 completion — event buffer, FFI search/anchor, PDF strategy, quality fixes
Rust Core:
- events: global Mutex-buffered event queue (push/export/clear/update_position)
- image_meta: use ImageReader::format() for real decoded format instead of extension
- search: change match_start/match_end usize→u64 for FFI compatibility
- epub/pdf: module-level placeholder comments

FFI (UDL exposed, 12 total functions):
- Added: search_markdown_blocks, search_text_content, create_note_anchor
- Added: push_reading_event, update_reading_position, export_pending_events,
  clear_exported_events

Docs:
- README: synced DocumentBlock model (Table.headers + HorizontalRule),
  simplified dependency recommendations, removed nonexistent doc references
- docs/pdf-strategy.md: PDFKit vs PDFium vs MuPDF evaluation, 5 decisions,
  platform strategy matrix, roadmap

Build:
- .cargo/config.toml: cargo xtask alias
- xtask: CLI implementation (test/build-ios/fixtures commands)
- fixtures: markdown/sample.md (9 block types), text/sample.txt
- XCFramework rebuilt, Swift bindings regenerated (1977 lines)

58 tests pass, zero warnings.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 21:23:26 +08:00

185 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PDF 阅读方案评估
## 概述
PDF 是知习支持的核心文件格式之一。本文档明确 PDF 在各平台的处理策略、技术选型边界和后续路线图。
## 核心结论
1. **iOS 第一版继续使用 PDFKit / QuickLook** — 系统内置,无需额外依赖
2. **Rust 暂不接入 PDFium** — 增加包体但不创造足够价值
3. **文本选择由平台能力承担** — PDFKitiOS、PdfRendererAndroid
4. **PDF 搜索后置** — 待文本提取方案确定后再做
5. **扫描 PDF / OCR 暂缓** — 明确不在第一版范围
---
## 方案对比
### 候选方案
| 方案 | 二进制大小 | 平台支持 | 文本提取 | 搜索 | 标注 | 成熟度 |
|------|----------|---------|---------|------|------|--------|
| **QuickLook (iOS/macOS)** | 0系统内置 | Apple only | 否 | 否 | 否 | 高 |
| **PDFKit (iOS/macOS)** | 0系统内置 | Apple only | 是 | 是 | 是 | 高 |
| **Android PdfRenderer** | 0系统内置 | Android only | 部分 | 否 | 否 | 中 |
| **pdfium-render (Rust)** | ~15MB/平台 | 全平台 | 是 | 可自建 | 否 | 中 |
| **MuPDF (C)** | ~8MB/平台 | 全平台 | 是 | 可自建 | 部分 | 高 |
### 评估维度
| 维度 | QuickLook (iOS) | PDFKit (iOS) | pdfium-render (Rust) |
|------|----------------|-------------|---------------------|
| 集成成本 | 极低QLPreviewController | 低(原生 API | 高交叉编译、binding |
| 包体影响 | 0 | 0 | ~15MB × 平台数 |
| 页面渲染 | ✅ | ✅ | ✅(需要 bitmap pipeline |
| 文本提取 | ❌ | ✅ | ✅ |
| 文本选择 | ❌(只能看不选) | ✅ | 需自建 UI |
| 搜索 | ❌ | ✅ | 可自建 |
| 阅读位置 | App 侧维护 | App 侧 + delegate | Rust 侧统一 |
| 统一数据模型 | ❌ | ❌ | ✅ |
| 跨平台复用 | ❌ | ❌ | ✅ |
---
## 各平台策略
### iOS / macOS
**当前M3-M4PDFKit**
```
MaterialReaderView
→ PreviewMode.platformPreview
→ QuickLook sheet (QLPreviewController)
→ App 侧监听页码变化
→ 生成 ReadingPosition::Pdf { pageNumber, pageProgress, overallProgress }
→ pushReadingEvent
```
优势:
- 零依赖,系统自带
- 渲染质量高
- 支持系统级文本选择、搜索
- 用户熟悉的交互
局限:
- QuickLook 不暴露页码变化回调(需要 PDFKit 的 PDFView 才能精确跟踪)
- 无法提取文本传给 Rust 做统一搜索
- App 侧需用 PDFView delegate 替代 QLPreviewController 以获得页码回调
**后续增强**:如果需要文本提取/搜索,把 QuickLook sheet 替换为 PDFView + PDFDocument通过 `PDFDocument.string` 提取全文传给 Rust `search_text`
### Android
**当前策略:系统预览 / 外部 App**
Android 有 `PdfRenderer`API 21+),可渲染页面为 Bitmap。但第一版不做内置 PDF 阅读器。
```
MaterialReaderView (Android)
→ PreviewMode.platformPreview
→ Intent.ACTION_VIEW + content:// URI
→ 系统 PDF 阅读器 / Chrome
→ 回到 App 后手动记录阅读时长
```
后续可选:`PdfRenderer` + `RecyclerView` 自建阅读器,用 Rust `ReadingPosition::Pdf` 统一位置模型。
### 鸿蒙 / Windows / Web
均优先走系统预览或浏览器内置 PDF 阅读器。Rust 只统一 `ReadingPosition::Pdf` 模型。
---
## 阅读位置模型
Rust 已定义统一的 `ReadingPosition::Pdf`
```rust
ReadingPosition::Pdf {
page_number: u32, // 1-based 页码
page_progress: f32, // 0.0 ~ 1.0,该页内滚动比例
overall_progress: f32, // 0.0 ~ 1.0,全书进度
}
```
App 侧职责:
- iOSPDFView.pageChange delegate → 更新位置
- Android监听页面变化 → 更新位置
- 所有平台:用同一套 `ReadingPosition::Pdf` 模型,不重复造轮子
---
## Rust 侧职责边界
### 当前M3-M4
- `MaterialType::Pdf` — 文件类型识别 ✅
- `ReadingPosition::Pdf` — 统一位置模型 ✅
- `PreviewMode::PlatformPreview` — 预览模式映射 ✅
- `pdf.rs` — 模块占位(注释说明走平台预览)✅
### 不做的
- 不集成 PDFium
- 不做 PDF 渲染bitmap 生成)
- 不做 PDF 文本提取
- 不做 PDF 标注
- 不做 OCR
### 后续评估M5+
如果以下条件满足 **3 项以上**,重新评估 PDFium 集成:
1. Android 需要内置 PDF 阅读器
2. 搜索需要在 PDF 中定位
3. 需要跨平台统一的文本提取
4. 用户量大到平台差异成为维护负担
5. PDFium 交叉编译经验积累充分
---
## 搜索策略
| 阶段 | 方案 | 能力 |
|------|------|------|
| M3-M4 | 不搜索 PDF | 用户在平台预览器中手动使用系统搜索 |
| M5+ | 平台提取 + Rust 搜索 | PDFKit.string / PdfRenderer → 传给 Rust `search_text` |
| 远期 | PDFium 提取 + Tantivy | 全文索引,支持 PDF 内定位 |
---
## 扫描 PDF / OCR
**明确不进入知习范围**。理由:
- OCR 是独立技术领域,与"阅读内核"定位不符
- 高精度 OCR 需要专门模型Tesseract / Apple Vision / ML Kit
- 绝大多数学习资料是原生电子文档,非扫描件
- 扫描件场景可由用户自行 OCR 后导入
---
## 后续路线图
```
M3 ✅ — QuickLook sheet + ReadingPosition::Pdf
M4 ● — pdf-strategy.md本文档
M5 ○ — iOS 迁移至 PDFView获得文本提取和页码回调
— Rust 接收 PDF 全文做 search_text
M6+ ○ — 评估 PDFiumAndroid 自建阅读器需求驱动)
— 如集成 PDFium文本提取 + bitmap 渲染 + 搜索定位
```
---
## 验收确认
- [x] iOS 第一版继续使用 PDFKit / QuickLook
- [x] Rust 暂不接 PDFium
- [x] PDF 文本选择由平台能力承担
- [x] PDF 搜索后置
- [x] 扫描 PDF / OCR 暂缓
- [x] 文档存在,方案决策明确,有后续路线图