Initial commit: FoFreeXit Phase 1 (Viewer) + Phase 2 (Annotate)
PDF viewer (render/search/text-select/thumbnails/outline) and annotation engine (Highlight/Underline/Strikeout/Square/FreeText/Note) over PDFium + lopdf, with Unicode font embedding for Vietnamese text and undo/redo.
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
# 01 — Nghiên cứu: Tính năng, Khó khăn, Thuật toán, Thư viện
|
||||
|
||||
## A. Tính năng của Foxit PDF Editor
|
||||
|
||||
Foxit có 3 dòng: **PDF Editor**, **PDF Editor Pro**, **PDF Editor Pro+** (subscription, kèm AI/cloud).
|
||||
Giá tham khảo (2025–2026): subscription từ ~$11.99/tháng; **lifetime/perpetual ~$159–$210**; Pro+ chỉ bán subscription. Enterprise báo giá riêng.
|
||||
|
||||
### Nhóm tính năng (theo mức độ quan trọng với người dùng)
|
||||
|
||||
#### 1. Xem & điều hướng (View) — *table stakes, miễn phí ở mọi reader*
|
||||
- Render PDF chính xác, mượt; zoom, fit, thumbnails, bookmarks/outline, search full-text.
|
||||
- Continuous scroll, two-page, reading mode, dark mode.
|
||||
- Mở file lớn nhanh (lazy load từng trang).
|
||||
|
||||
#### 2. Chú thích (Annotate / Comment) — *quan trọng, dùng hằng ngày*
|
||||
- Highlight, underline, strikethrough, squiggly.
|
||||
- Sticky notes, text box, callout, stamp, drawing (pencil/shapes), measure.
|
||||
- Reply/threads cho comment, import/export annotation (FDF/XFDF).
|
||||
|
||||
#### 3. **Chỉnh sửa nội dung (Edit) — TÍNH NĂNG "ĐÁNG TIỀN" SỐ 1** ⭐
|
||||
- **Sửa text trực tiếp** trên trang (reflow trong đoạn, đổi font/size/màu).
|
||||
- Thêm/xoá/di chuyển/đổi kích thước **ảnh** và **đối tượng** (object).
|
||||
- Edit cả paragraph, link/unlink text box, OCR rồi sửa text trên ảnh scan.
|
||||
- Đây là rào cản kỹ thuật lớn nhất và là lý do chính người dùng trả tiền — các reader miễn phí (đa số) **không** làm được.
|
||||
|
||||
#### 4. Tổ chức trang (Organize) — *quan trọng, đáng tiền*
|
||||
- Chèn/xoá/xoay/trích/thay/đảo trang, **merge & split**, crop, đánh số, header/footer, watermark, background.
|
||||
- Sắp xếp kéo-thả thumbnail.
|
||||
|
||||
#### 5. Chuyển đổi (Convert) — *rất đáng tiền* ⭐
|
||||
- PDF ↔ Word/Excel/PowerPoint, PDF → ảnh, ảnh/Office → PDF.
|
||||
- Chất lượng chuyển đổi (giữ layout) là điểm bán hàng then chốt.
|
||||
|
||||
#### 6. **OCR** — *rất đáng tiền* ⭐
|
||||
- Nhận dạng text trên scan (đa ngôn ngữ), tạo "searchable PDF".
|
||||
- Foxit 2025.2 quảng cáo OCR vượt Adobe ở chữ số/checkbox/handwriting.
|
||||
|
||||
#### 7. Form (AcroForm / XFA) — *đáng tiền với doanh nghiệp*
|
||||
- Điền form, **tạo form** (text field, checkbox, radio, dropdown, button), nhận dạng field tự động, import/export dữ liệu form.
|
||||
|
||||
#### 8. Bảo mật & chữ ký — *đáng tiền với doanh nghiệp* ⭐
|
||||
- Mật khẩu (mở/permission), **mã hoá AES**, redaction (bôi đen vĩnh viễn), xoá metadata ẩn.
|
||||
- **Chữ ký số** (digital signature/PKI), chứng thực, timestamp; **eSign** (cloud).
|
||||
|
||||
#### 9. So sánh & cộng tác
|
||||
- Compare 2 phiên bản PDF, shared review, cloud collaboration (Pro+).
|
||||
|
||||
#### 10. AI (Pro+) — *xu hướng mới*
|
||||
- Tóm tắt, hỏi-đáp tài liệu, dịch, chat với PDF.
|
||||
|
||||
### ➜ Kết luận: Tính năng khiến người dùng phải mua license
|
||||
Theo thứ tự "moat" (khó làm + người dùng sẵn sàng trả tiền):
|
||||
1. **Edit text/object trực tiếp** (rào cản kỹ thuật cao nhất).
|
||||
2. **Convert PDF→Office giữ layout** (Word/Excel).
|
||||
3. **OCR** chất lượng cao, đa ngôn ngữ.
|
||||
4. **Bảo mật**: redaction thật, mã hoá, chữ ký số.
|
||||
5. **Tạo & xử lý form** (AcroForm).
|
||||
6. **Organize**: merge/split/crop hàng loạt.
|
||||
|
||||
> Chiến lược FoFreeXit: chiếm các tính năng (1), (4), (6), (organize) trước — vốn có thể tự làm tốt trên nền engine mở. (2) Convert và (3) OCR sẽ tận dụng dự án mở khác (LibreOffice headless, Tesseract). AI để sau cùng.
|
||||
|
||||
---
|
||||
|
||||
## B. Khó khăn kỹ thuật (xếp theo độ khó)
|
||||
|
||||
### B1. Bản chất định dạng PDF
|
||||
- PDF **không phải định dạng để chỉnh sửa**: nó mô tả "vẽ gì ở toạ độ nào", không lưu cấu trúc đoạn/dòng/bảng như Word. Text là chuỗi lệnh `Tj/TJ` đặt glyph theo toạ độ → **không có khái niệm "đoạn văn"**.
|
||||
- Đặc tả PDF (ISO 32000) cực lớn; vô số file "hợp lệ một phần", file hỏng, file sinh bởi công cụ lạ → cần **độ bền (robustness)** rất cao.
|
||||
|
||||
### B2. Sửa text trực tiếp (khó nhất) ⭐
|
||||
- Phải **tái dựng dòng/đoạn** từ các glyph rời rạc (gom theo toạ độ, baseline, khoảng cách) → suy ra "text run".
|
||||
- Khi sửa: cần **đo lại chiều rộng glyph** theo font thật, **reflow** phần còn lại của dòng/đoạn, xử lý ligature, kerning, justification.
|
||||
- **Font**: file có thể nhúng font subset (chỉ chứa glyph đã dùng) → muốn gõ ký tự mới phải có glyph đó; nếu không, phải **substitute font** giống nhất rồi nhúng/subset lại. Encoding phức tạp (CID, CMap, Type0, Type3).
|
||||
- Văn bản phức tạp: RTL (Ả Rập/Do Thái), chữ Đông Á (CJK), **tiếng Việt dấu** (tổ hợp dấu), shaping (HarfBuzz).
|
||||
|
||||
### B3. Render chính xác
|
||||
- Render giống Acrobat: blend modes, transparency groups, soft mask, shading/gradient, pattern, overprint, ICC color management, CMYK.
|
||||
- Hiệu năng: file hàng nghìn trang, ảnh độ phân giải cao → cần cache, tile, đa luồng, GPU (tuỳ chọn).
|
||||
|
||||
### B4. OCR
|
||||
- Tích hợp engine (Tesseract), tiền xử lý ảnh (deskew, denoise, binarize), bố cục (layout analysis), khớp toạ độ text vào trang để tạo lớp text vô hình → searchable PDF.
|
||||
|
||||
### B5. Convert PDF → Office
|
||||
- "Bài toán ngược": từ glyph dựng lại đoạn/bảng/cột/heading của Word. **Rất khó giữ layout**. Đây là nơi cả Adobe lẫn Foxit đều chưa hoàn hảo.
|
||||
|
||||
### B6. Bảo mật làm đúng
|
||||
- **Redaction**: phải **xoá thật** nội dung khỏi content stream + metadata + ảnh, không chỉ vẽ hộp đen lên trên (lỗi này từng làm lộ tài liệu chính phủ).
|
||||
- Mã hoá RC4/AES, permission, public-key security handler; **chữ ký số** đúng chuẩn PAdES (byte range, /ByteRange, incremental update không phá chữ ký cũ).
|
||||
|
||||
### B7. Ghi file an toàn
|
||||
- **Incremental update** (ghi thêm cuối file, giữ chữ ký) vs **full rewrite** (gọn, tối ưu). Cần xử lý xref/xref-stream, object stream, linearization ("fast web view").
|
||||
- Không làm hỏng file gốc; undo/redo cho thao tác sửa.
|
||||
|
||||
### B8. UX desktop chất lượng cao
|
||||
- Tương tác mượt (chọn text qua nhiều trang, kéo object), đa nền tảng, in ấn đúng, accessibility, đa ngôn ngữ UI.
|
||||
|
||||
---
|
||||
|
||||
## C. Thuật toán & kiến trúc của Foxit / Adobe (học hỏi được gì)
|
||||
|
||||
> Foxit & Adobe là mã đóng; dưới đây là suy luận từ tài liệu SDK công khai, cấu trúc đặc tả PDF, và kiến trúc các engine mở tương đương. Mục tiêu: **học mô hình kiến trúc**, không sao chép.
|
||||
|
||||
### C1. Foxit
|
||||
- **Core engine viết bằng C++**; cung cấp SDK với binding C++, C#, C, Java, Python. Kiến trúc tách lớp rõ: **Core (parser + render + edit) → API → UI**.
|
||||
- Render engine riêng (không dùng PDFium công khai), tối ưu tốc độ & bộ nhớ — Foxit nổi tiếng "nhẹ và nhanh".
|
||||
- Mô hình edit dựa trên **page object model**: trang = tập object (text/path/image/form-xobject), edit = thao tác trên object rồi serialize lại content stream.
|
||||
|
||||
### C2. Adobe Acrobat
|
||||
- Lõi C/C++ lâu đời (PDF do Adobe phát minh). **PDFL (PDF Library)** + Acrobat core; tách "Cos layer" (Carousel Object System — model object thấp tầng: dict/array/stream) và "PD layer" (Page Description — trang, annotation, form).
|
||||
- Bài học quan trọng: **mô hình 2 tầng**:
|
||||
- *Tầng object thấp (COS)*: đọc/ghi cấu trúc PDF (dictionary, stream, xref) — tương ứng QPDF/pikepdf.
|
||||
- *Tầng tài liệu cao (PD)*: trang, annotation, form, content stream parsed thành object — tương ứng PDFium/MuPDF.
|
||||
- Liquid Mode (mobile reflow) của Adobe dùng ML để suy ra cấu trúc đọc → cho thấy hướng "tái dựng cấu trúc" là bài toán AI/heuristic.
|
||||
|
||||
### ➜ Bài học kiến trúc áp dụng cho FoFreeXit
|
||||
1. **Tách 2 tầng**: `cos` (cấu trúc) và `pdmodel` (trang/object/annotation) — đúng như Adobe/PDFBox làm.
|
||||
2. **Page Object Model** cho editing: parse content stream → cây object → sửa → serialize.
|
||||
3. **Undo/redo** ở tầng model bằng command pattern.
|
||||
4. Tách hẳn **engine** (không phụ thuộc UI) khỏi **UI**, để test tự động và tái dùng (CLI, server).
|
||||
|
||||
---
|
||||
|
||||
## D. Khảo sát thư viện PDF (mọi ngôn ngữ) & giấy phép
|
||||
|
||||
> Giấy phép là yếu tố sống còn: muốn phân phối tự do, **tránh AGPL** (MuPDF, iText) trừ khi chấp nhận copyleft hoặc mua license.
|
||||
|
||||
| Thư viện | Ngôn ngữ | Render | Edit text/obj | Cấu trúc/repair | Giấy phép | Ghi chú |
|
||||
|----------|----------|:------:|:------:|:------:|----------|------|
|
||||
| **PDFium** | C/C++ | ⭐ rất tốt | ✔ có API (`FPDFPageObj_*`, `FPDFText_*`) | một phần | **BSD-3 (permissive)** | Engine của Chrome; binary prebuilt sẵn (bblanchon/pdfium-binaries). Nền tảng lý tưởng. |
|
||||
| **QPDF** | C++ | ✘ | ✘ (cấu trúc) | ⭐ xuất sắc | Apache-2.0 | Repair, linearize, encrypt, object stream. Bổ trợ cho PDFium. |
|
||||
| pikepdf | Python | ✘ | ✘ | ⭐ (wrap QPDF) | MPL-2.0 | Bản Python của QPDF, tốt cho prototype. |
|
||||
| MuPDF | C | ⭐ | ✔ | ✔ | **AGPL/commercial** | Mạnh nhưng copyleft → tránh cho bản đóng. |
|
||||
| PyMuPDF | Python | ⭐ | ✔ | ✔ | **AGPL/commercial** | Tốt để prototype/nghiên cứu, không ship. |
|
||||
| iText | Java/.NET | một phần | ✔ tạo | ✔ | **AGPL/commercial $$$** | Tránh trừ khi mua. |
|
||||
| Apache PDFBox | Java | ✔ ok | ✔ | ✔ | **Apache-2.0** | Permissive, full-feature, tham khảo thuật toán rất tốt (mã đọc được). |
|
||||
| PDF.js | JS | ✔ (web) | ✘ (gần như render-only) | một phần | Apache-2.0 | Của Mozilla; tốt cho web viewer, không edit sâu. |
|
||||
| pdf-lib | JS/TS | ✘ | ✔ (tạo/sửa cơ bản) | ✔ | MIT | Thuần JS, tạo & sửa nhẹ. |
|
||||
| pdfcpu | Go | ✘ | thao tác trang | ✔ | Apache-2.0 | CLI mạnh cho organize/encrypt. |
|
||||
| lopdf / pdf-rs / printpdf | Rust | một phần | ✔ thấp tầng / tạo | ✔ | MIT/Apache | Ecosystem Rust đang lớn, chưa bằng PDFium. |
|
||||
| Tesseract | C++ | — | — (OCR) | — | Apache-2.0 | Engine OCR mở tốt nhất. |
|
||||
| HarfBuzz | C++ | — | text shaping | — | MIT | Bắt buộc cho shaping (Việt/CJK/RTL). |
|
||||
| FreeType | C | — | font rasterize | — | FTL/GPL | Đọc & render font. |
|
||||
| LibreOffice (headless) | C++ | — | convert | — | MPL-2.0 | Dùng `soffice --convert-to` cho PDF↔Office. |
|
||||
|
||||
### ➜ Tận dụng được gì
|
||||
- **Nền engine**: PDFium (render + edit object) + QPDF (cấu trúc/encrypt/repair) — cả hai permissive → **không phải viết parser/renderer từ đầu**.
|
||||
- **OCR**: Tesseract. **Shaping**: HarfBuzz. **Font**: FreeType. **Convert Office**: LibreOffice headless.
|
||||
- **Tham khảo thuật toán** (đọc mã được): Apache PDFBox (Java, permissive) cho cách dựng text run, content stream, form; pdf.js cho rendering model.
|
||||
- **Tránh**: MuPDF/PyMuPDF/iText cho bản phân phối (AGPL) — chỉ dùng để học/prototype.
|
||||
|
||||
## Nguồn tham khảo
|
||||
- [Foxit vs Adobe 2025](https://pdfpro.com/blog/general/foxit-vs-adobe) · [Foxit pricing](https://www.trustradius.com/products/foxit-pdf-editor/pricing) · [Foxit Editor blog](https://www.foxit.com/blog/the-new-foxit-pdf-editor-and-pdf-editor/)
|
||||
- [Foxit PDF SDK for C++](https://developers.foxit.com/developer-hub/document/developer-guide-pdf-sdk/)
|
||||
- [PDFium fpdf_edit.h](https://pdfium.googlesource.com/pdfium/+/refs/heads/main/public/fpdf_edit.h) · [PDFium LICENSE](https://pdfium.googlesource.com/pdfium/+/main/LICENSE)
|
||||
- [pikepdf](https://github.com/pikepdf/pikepdf) · [Survey of Open-Source PDF Solutions (PDFA)](https://pdfa.org/wp-content/uploads/2021/06/Survey-of-OpenSource-Solutions.pdf)
|
||||
- [Comparing open source PDF libraries (2025) — Joyfill](https://joyfill.io/blog/comparing-open-source-pdf-libraries-2025-edition) · [awesome-pdf](https://github.com/py-pdf/awesome-pdf)
|
||||
- [MuPDF license](https://mupdf.readthedocs.io/en/1.27.0/license.html)
|
||||
@@ -0,0 +1,93 @@
|
||||
# 02 — Lựa chọn ngôn ngữ, framework & engine
|
||||
|
||||
## Nguyên tắc quyết định
|
||||
1. **Permissive license** cho toàn bộ thành phần ship (BSD/Apache/MIT) → tránh AGPL.
|
||||
2. **Không viết lại engine PDF từ đầu** ở giai đoạn đầu → dùng PDFium + QPDF.
|
||||
3. Tách **Engine (không UI)** khỏi **App (UI)** để test & tái dùng.
|
||||
4. Tối ưu cho **Windows trước** (thị trường Foxit), nhưng giữ đường ra **đa nền tảng**.
|
||||
5. Dự án do AI hỗ trợ qua nhiều session → ưu tiên **ngôn ngữ có ecosystem PDF mạnh + tooling tốt + dễ test**, hơn là "ngôn ngữ dev người quen tay".
|
||||
|
||||
---
|
||||
|
||||
## Tầng ENGINE (lõi xử lý PDF) — quyết định gần như bắt buộc
|
||||
|
||||
**Chọn: PDFium (BSD-3) làm engine render + edit object, + QPDF (Apache-2.0) cho cấu trúc/mã hoá/repair.**
|
||||
|
||||
Lý do: cả hai permissive, trưởng thành, được hậu thuẫn lớn (Google/Chromium). PDFium chính là thứ Chrome/Edge dùng để hiển thị PDF → render chất lượng production. Có binary prebuilt (bblanchon/pdfium-binaries) → khỏi build từ nguồn (vốn rất khổ). PDFium là **C/C++** → FFI tự nhiên nhất từ C++; binding sẵn cho .NET (PDFiumCore/PdfiumViewer), Rust (pdfium-render), Python (pypdfium2).
|
||||
|
||||
Bổ trợ chuyên biệt: **Tesseract** (OCR), **HarfBuzz** (shaping), **FreeType** (font), **LibreOffice headless** (convert Office). Tham khảo thuật toán: **Apache PDFBox** (đọc mã được, permissive).
|
||||
|
||||
---
|
||||
|
||||
## ✅ QUYẾT ĐỊNH ĐÃ CHỐT (2026-06-16): **Rust + Tauri**
|
||||
|
||||
Tầng App/UI dùng **Rust + Tauri**; engine **PDFium (pdfium-render) + QPDF**; viewer có thể nhúng **PDF.js** trong webview cho tốc độ, dùng PDFium cho edit/save. Lý do chốt: an toàn bộ nhớ khi xử lý file không tin cậy, hiệu năng cao, license sạch, UI hiện đại phát triển nhanh, phù hợp dự án dài hơi nhiều session. Các lựa chọn A/C/D bên dưới giữ lại để tham khảo/đối chiếu.
|
||||
|
||||
## Tầng APP (ngôn ngữ + UI framework) — các lựa chọn đã cân nhắc
|
||||
|
||||
So sánh 4 lựa chọn khả thi:
|
||||
|
||||
### Lựa chọn A — C++ + Qt (giống Foxit/Adobe nhất)
|
||||
- **+** FFI với PDFium = 0 ma sát (cùng C++); hiệu năng tối đa; Qt là framework desktop mạnh nhất, đa nền tảng, in ấn/đồ hoạ tốt.
|
||||
- **+** Đây là con đường "đẳng cấp Foxit" thực sự.
|
||||
- **−** Tốc độ phát triển chậm, build phức tạp (CMake/vcpkg), quản lý bộ nhớ thủ công, refactor tốn công.
|
||||
- **License Qt:** LGPL (dùng được miễn phí nếu link động) hoặc thương mại.
|
||||
|
||||
### Lựa chọn B — Rust + Tauri (hiện đại, an toàn) ⭐ *khuyến nghị nếu muốn cân bằng*
|
||||
- **+** An toàn bộ nhớ (ít crash/CVE — rất hợp với phần mềm "đọc file lạ"). `pdfium-render` (binding PDFium) trưởng thành. Tauri = UI web (HTML/CSS/TS) nhẹ, bundle nhỏ.
|
||||
- **+** Có thể nhúng **PDF.js** trong webview cho viewer nhanh, dùng PDFium (Rust) cho edit/save.
|
||||
- **+** Cargo/tooling tuyệt vời, test dễ, cross-platform.
|
||||
- **−** Ecosystem PDF Rust non hơn C++; cần FFI sang PDFium (đã có sẵn binding).
|
||||
- **License:** Rust crates đa số MIT/Apache; Tauri MIT/Apache.
|
||||
|
||||
### Lựa chọn C — C# / .NET 8 + Avalonia (năng suất cao, Windows-first)
|
||||
- **+** Năng suất phát triển cao nhất; XAML/MVVM quen thuộc; Avalonia đa nền tảng (hoặc WPF nếu chỉ Windows). Binding PDFium .NET sẵn.
|
||||
- **+** Dễ tuyển/đọc code, dễ test (xUnit).
|
||||
- **−** FFI sang native qua P/Invoke (ổn nhưng có chi phí marshaling); GC pause với file rất lớn cần chú ý.
|
||||
- **License:** .NET & Avalonia MIT.
|
||||
|
||||
### Lựa chọn D — TypeScript + Electron + PDF.js (nhanh ra mắt, web-native)
|
||||
- **+** Dev UI nhanh nhất, hệ sinh thái khổng lồ, dễ làm bản web sau này.
|
||||
- **−** PDF.js gần như render-only → edit/save phải tự build hoặc nhúng native (pdfium qua WASM/node-addon); Electron nặng RAM; hiệu năng kém nhất với file lớn. **Yếu nhất cho tính năng EDIT** — điểm cốt lõi của dự án.
|
||||
|
||||
### Bảng tổng hợp
|
||||
|
||||
| Tiêu chí | A: C++/Qt | B: Rust/Tauri | C: C#/Avalonia | D: TS/Electron |
|
||||
|---|:--:|:--:|:--:|:--:|
|
||||
| Ma sát FFI PDFium | ⭐ | ✔ | ✔ | △ |
|
||||
| Hiệu năng / file lớn | ⭐ | ⭐ | ✔ | △ |
|
||||
| An toàn bộ nhớ | △ | ⭐ | ✔ | ✔ |
|
||||
| Tốc độ phát triển | △ | ✔ | ⭐ | ⭐ |
|
||||
| Sức mạnh tính năng EDIT | ⭐ | ⭐ | ✔ | △ |
|
||||
| Cross-platform | ⭐ | ⭐ | ⭐ | ⭐ |
|
||||
| Độ "đẳng cấp Foxit" | ⭐ | ✔ | ✔ | △ |
|
||||
|
||||
### ➜ Khuyến nghị
|
||||
- **Cân bằng tốt nhất (khuyến nghị chính): B — Rust + Tauri.** An toàn (quan trọng khi xử lý file không tin cậy), hiệu năng cao, binding PDFium tốt, UI hiện đại nhanh phát triển, license sạch. Phù hợp dự án dài hơi do AI hỗ trợ.
|
||||
- **Nếu ưu tiên "đúng chuẩn Foxit", chấp nhận chậm: A — C++/Qt.**
|
||||
- **Nếu ưu tiên ra tính năng nhanh trên Windows: C — C#/Avalonia.**
|
||||
- **Không khuyến nghị D** làm kiến trúc chính vì điểm yếu ở tính năng EDIT (lõi giá trị của dự án).
|
||||
|
||||
> **Điểm chung mọi lựa chọn:** Tầng *Engine* (PDFium + QPDF + Tesseract...) gần như không đổi. Lựa chọn ngôn ngữ chủ yếu ảnh hưởng tầng *App/UI*. Vì vậy nên **đóng gói Engine sau một API ổn định** (FFI/IPC) để có thể đổi UI mà không đập lõi.
|
||||
|
||||
---
|
||||
|
||||
## Kiến trúc đề xuất (độc lập với lựa chọn UI)
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────┐
|
||||
│ UI Layer │ (Qt / Tauri-web / Avalonia)
|
||||
│ Viewer · Annotate · Edit · Organize │
|
||||
├──────────────────────────────────────────┤
|
||||
│ App / Commands │ undo/redo, document state, MVVM
|
||||
├──────────────────────────────────────────┤
|
||||
│ FoFreeXit Core API (stable) │ ← biên giới ổn định (FFI/IPC)
|
||||
│ pdmodel: Page, TextRun, Image, Annot... │ ← tầng "PD" kiểu Adobe
|
||||
│ cos: Object, Dict, Stream, XRef │ ← tầng "COS" kiểu Adobe
|
||||
├──────────────────────────────────────────┤
|
||||
│ PDFium │ QPDF │ Tesseract │ HarfBuzz │ (engine permissive)
|
||||
│ render+edit│ struct │ OCR │ shaping │
|
||||
└──────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Chi tiết hoá tiếp ở [04-architecture.md](04-architecture.md) sau khi chốt stack.
|
||||
@@ -0,0 +1,91 @@
|
||||
# 03 — Lộ trình dự án (Roadmap)
|
||||
|
||||
## Mục tiêu tổng (North Star)
|
||||
Một ứng dụng desktop có thể **xem, chú thích, tổ chức trang, và chỉnh sửa text/ảnh trực tiếp** trên PDF, kèm bảo mật cơ bản — đủ để một người dùng Foxit phổ thông **bỏ Foxit** cho công việc hằng ngày.
|
||||
|
||||
## Phương pháp làm việc
|
||||
- **Engine-first, UI-second** trong mỗi tính năng: làm được ở tầng core + test CLI trước, rồi mới gắn UI.
|
||||
- Mỗi phase kết thúc bằng **bản chạy được (demo) + test tự động + cập nhật docs**.
|
||||
- **Bộ PDF mẫu** (test corpus) tích luỹ dần: file thường, file scan, file mã hoá, file hỏng, CJK/Việt/RTL, form, file nghìn trang.
|
||||
- Quy ước: nhánh/commit theo phase; mỗi tính năng có "DoD" (Definition of Done) checklist.
|
||||
- **Không** chuyển phase khi DoD chưa đạt và test chưa xanh.
|
||||
|
||||
---
|
||||
|
||||
## Phase 0 — Nghiên cứu & Kế hoạch ✅ (đang ở đây)
|
||||
**DoD:** docs 01–03 hoàn tất; chốt ngôn ngữ/framework; dựng skeleton repo.
|
||||
|
||||
## Phase 1 — Nền tảng & Viewer (MVP xem được)
|
||||
**Mục tiêu:** Mở và hiển thị PDF chính xác, mượt.
|
||||
- Tích hợp PDFium (prebuilt) qua FFI; dựng Core API tối thiểu (`open`, `pageCount`, `renderPage`).
|
||||
- Viewer: scroll liên tục, zoom/fit, thumbnails, outline/bookmarks, **tìm kiếm text**, chọn & copy text.
|
||||
- Mở file lớn (lazy render + cache tile).
|
||||
**DoD:** mở 20 file mẫu (gồm file 1000+ trang, CJK, Việt) không crash; render khớp mắt thường với Chrome; search & copy hoạt động; có test render-hash cho trang mẫu.
|
||||
|
||||
## Phase 2 — Chú thích (Annotate)
|
||||
**Mục tiêu:** Bộ comment dùng hằng ngày.
|
||||
- Highlight/underline/strikethrough, sticky note, text box, free draw, shapes, stamp.
|
||||
- Lưu annotation vào PDF (annotation dict), import/export **XFDF**.
|
||||
- Hiển thị & sửa/xoá annotation; danh sách comment ở sidebar.
|
||||
**DoD:** tạo/sửa/xoá mọi loại trên; lưu & mở lại giữ nguyên; Acrobat/Foxit đọc được annotation ta ghi; export/import XFDF round-trip.
|
||||
|
||||
## Phase 3 — Tổ chức trang (Organize) + Lưu file vững
|
||||
**Mục tiêu:** Quản lý trang & ghi file an toàn.
|
||||
- Chèn/xoá/xoay/trích/thay/đảo trang; **merge & split**; crop; đánh số; header/footer; watermark/background.
|
||||
- Engine ghi file: incremental update **và** full rewrite (qua QPDF); giữ không hỏng file; **undo/redo** toàn cục.
|
||||
**DoD:** mọi thao tác trang round-trip đúng; merge 50 file OK; ghi không làm hỏng file mã hoá; undo/redo ổn định; test so khớp cấu trúc trang.
|
||||
|
||||
## Phase 4 — ⭐ Chỉnh sửa nội dung (Edit) — TÍNH NĂNG LÕI
|
||||
**Mục tiêu:** Sửa text & object trực tiếp — moat chính.
|
||||
- **Page Object Model**: parse content stream → cây object (text/path/image/xobject).
|
||||
- Sửa **ảnh/object**: di chuyển, resize, xoá, thêm ảnh (dễ hơn → làm trước).
|
||||
- Sửa **text**: gom glyph → text run/line/paragraph (heuristic theo baseline & spacing); edit inline; đo lại width theo font (FreeType/HarfBuzz); **reflow** trong text box; xử lý font nhúng/subset + font substitution; hỗ trợ **tiếng Việt** (tổ hợp dấu) sớm, CJK/RTL sau.
|
||||
- Thêm text box mới, đổi font/size/màu.
|
||||
**DoD:** sửa được text 1 dòng & 1 đoạn trên ≥80% file mẫu thường; thêm/xoá/di chuyển ảnh; lưu mở lại đúng; tiếng Việt hiển thị & sửa đúng dấu; có test corpus chuyên cho edit.
|
||||
|
||||
## Phase 5 — Bảo mật & Chữ ký
|
||||
**Mục tiêu:** Tính năng đáng tiền cho doanh nghiệp.
|
||||
- Mật khẩu mở/permission; mã hoá **AES-256**; xoá mật khẩu.
|
||||
- **Redaction thật** (xoá nội dung + ảnh + metadata, không chỉ vẽ đè) + kiểm chứng đã xoá.
|
||||
- Xoá metadata/ẩn; **chữ ký số** (PAdES, byte range, incremental update giữ chữ ký).
|
||||
**DoD:** mã hoá/giải mã round-trip; redaction qua kiểm chứng không còn text bị bôi; ký số được Acrobat xác thực hợp lệ.
|
||||
|
||||
## Phase 6 — Form (AcroForm)
|
||||
**Mục tiêu:** Điền & tạo form.
|
||||
- Điền form có sẵn, lưu; flatten form.
|
||||
- Tạo field: text/checkbox/radio/dropdown/button; import/export dữ liệu (FDF/CSV).
|
||||
**DoD:** điền & lưu giữ dữ liệu; tạo form mới mở được ở Acrobat; export/import round-trip.
|
||||
|
||||
## Phase 7 — OCR & Convert
|
||||
**Mục tiêu:** Hai tính năng "đáng tiền" còn lại, qua dự án mở.
|
||||
- **OCR**: Tesseract + tiền xử lý ảnh + layout → tạo searchable PDF (lớp text vô hình khớp toạ độ). Đa ngôn ngữ gồm tiếng Việt.
|
||||
- **Convert**: PDF→ảnh (sẵn từ PDFium); Office↔PDF qua **LibreOffice headless**; PDF→Word/Excel (giữ layout — bài toán khó, làm bản "đủ dùng" trước).
|
||||
**DoD:** OCR scan tạo PDF search được (Việt + Anh); convert Office↔PDF ổn; PDF→Word giữ được text & bố cục cơ bản.
|
||||
|
||||
## Phase 8 — Hoàn thiện & Phát hành
|
||||
- So sánh 2 PDF (compare); in ấn đúng; preferences; đa ngôn ngữ UI (Việt/Anh); accessibility.
|
||||
- Installer (Windows MSI/winget; sau đó mac/Linux); auto-update; crash reporting.
|
||||
- Tối ưu hiệu năng & bộ nhớ; hardening bảo mật (fuzzing parser).
|
||||
**DoD:** cài đặt sạch trên máy mới; vượt bộ test hồi quy đầy đủ; tài liệu người dùng.
|
||||
|
||||
## Phase 9 (tuỳ chọn) — AI
|
||||
- Tóm tắt, hỏi-đáp tài liệu, dịch (dùng Claude API / model cục bộ). Làm sau cùng vì không phải lý do chính thay thế Foxit.
|
||||
|
||||
---
|
||||
|
||||
## Thứ tự ưu tiên giá trị (nếu phải cắt giảm)
|
||||
**1→2→3→4** là "core sản phẩm thay Foxit cho cá nhân". **5,6** thêm giá trị doanh nghiệp. **7** ngang hàng giá trị nhưng phụ thuộc dự án ngoài. **8** bắt buộc để phát hành. **9** là bonus.
|
||||
|
||||
## Rủi ro & giảm thiểu
|
||||
| Rủi ro | Giảm thiểu |
|
||||
|---|---|
|
||||
| Edit text quá khó (Phase 4) | Làm object/ảnh trước; text bắt đầu từ ca đơn giản; tận dụng PDFium edit API + PDFBox tham khảo |
|
||||
| Build/FFI PDFium phức tạp | Dùng binary prebuilt + binding có sẵn |
|
||||
| Convert PDF→Word kém | Hạ kỳ vọng: "đủ dùng" trước; dựa LibreOffice |
|
||||
| File lạ làm crash | Test corpus file hỏng + fuzzing; chọn ngôn ngữ an toàn bộ nhớ |
|
||||
| Phạm vi phình to | DoD nghiêm ngặt; không nhảy phase khi chưa xanh |
|
||||
|
||||
## Bộ chỉ số thành công sản phẩm
|
||||
- Mở đúng ≥99% file PDF đời thực trong corpus.
|
||||
- Người dùng Foxit phổ thông làm được: xem, comment, sắp trang, sửa text/ảnh, đặt mật khẩu — **không cần Foxit**.
|
||||
- Không thua Foxit rõ rệt về tốc độ mở & render.
|
||||
@@ -0,0 +1,63 @@
|
||||
# 04 — Kiến trúc kỹ thuật (khung — sẽ chi tiết hoá sau khi chốt stack)
|
||||
|
||||
> Tài liệu này sẽ được hoàn thiện ở đầu Phase 1, sau khi đã chốt ngôn ngữ/framework ở [02-tech-stack.md](02-tech-stack.md).
|
||||
|
||||
## Mô hình 2 tầng (học từ Adobe COS/PD và Apache PDFBox)
|
||||
|
||||
- **`cos` (Carousel Object System)** — tầng object thấp: `Object`, `Dictionary`, `Array`, `Stream`, `Name`, `Ref`, `XRef`. Đọc/ghi cấu trúc file PDF thô. (Chủ yếu tựa QPDF.)
|
||||
- **`pdmodel`** — tầng tài liệu cao: `Document`, `Page`, `Resources`, `ContentStream`, `TextRun`, `ImageObject`, `PathObject`, `Annotation`, `AcroForm`, `Field`. (Tựa PDFium + logic riêng.)
|
||||
|
||||
## Các module chính
|
||||
- `engine/render` — bọc PDFium render (tile, cache, đa luồng).
|
||||
- `engine/text` — gom glyph → run/line/paragraph; chọn/copy; tìm kiếm.
|
||||
- `engine/edit` — Page Object Model; sửa text/object; serialize content stream.
|
||||
- `engine/font` — FreeType + HarfBuzz: đo width, shaping, subset, substitution.
|
||||
- `engine/io` — mở/lưu (incremental + full rewrite via QPDF), repair, linearize, encrypt.
|
||||
- `engine/annot` — annotation CRUD + XFDF.
|
||||
- `engine/security` — mã hoá, redaction, chữ ký số (PAdES).
|
||||
- `engine/form` — AcroForm điền/tạo/flatten.
|
||||
- `engine/ocr` — Tesseract + tiền xử lý + tạo lớp text.
|
||||
- `engine/convert` — cầu nối LibreOffice headless; PDF→ảnh; PDF→Office.
|
||||
- `core-api` — biên giới ổn định (FFI/IPC) cho UI.
|
||||
- `app/*` — UI theo framework đã chọn.
|
||||
- `cli` — công cụ dòng lệnh cho test/automation (chạy mọi tính năng không cần UI).
|
||||
|
||||
## Nguyên tắc
|
||||
- Engine **không phụ thuộc UI**; mọi tính năng phải gọi được từ `cli` → test tự động.
|
||||
- Edit dùng **command pattern** → undo/redo.
|
||||
- Mọi thao tác ghi đều có đường **không phá file gốc** (atomic write / backup).
|
||||
|
||||
## Test strategy
|
||||
- Unit test cho `cos`/`pdmodel`.
|
||||
- Golden/render-hash test cho viewer.
|
||||
- Round-trip test cho annotate/organize/form/security.
|
||||
- Corpus test (file đời thực, file hỏng, đa ngôn ngữ) + fuzzing parser.
|
||||
|
||||
## Hạng mục cần quyết khi vào Phase 1
|
||||
- [x] Ngôn ngữ/UI: **Rust + Tauri** (chốt 2026-06-16).
|
||||
- [ ] Phân phối PDFium: dùng prebuilt `bblanchon/pdfium-binaries` qua crate `pdfium-render` (chốt version cụ thể đầu Phase 1).
|
||||
- [ ] Biên giới core-api: trong Tauri, engine Rust chạy cùng tiến trình; cân nhắc tách tiến trình parser để **sandbox** file không tin cậy (quyết định khi làm hardening).
|
||||
- [ ] Bố cục repo (mono-repo Cargo workspace, xem dưới).
|
||||
|
||||
## Bố cục repo dự kiến (Rust + Tauri, Cargo workspace)
|
||||
```
|
||||
FoFreeXit/
|
||||
├─ Cargo.toml # workspace
|
||||
├─ crates/
|
||||
│ ├─ ff-cos/ # tầng object thấp (cấu trúc PDF)
|
||||
│ ├─ ff-pdmodel/ # tầng tài liệu cao (page/text/annot/...)
|
||||
│ ├─ ff-engine/ # render/edit/io/font/ocr... (bọc PDFium/QPDF/Tesseract)
|
||||
│ └─ ff-cli/ # CLI chạy mọi tính năng không cần UI (để test)
|
||||
├─ app/ # Tauri app
|
||||
│ ├─ src-tauri/ # Rust backend (gọi ff-engine)
|
||||
│ └─ src/ # frontend (TS/HTML/CSS, PDF.js viewer)
|
||||
├─ tests/ # integration tests
|
||||
├─ corpus/ # PDF mẫu (thường/scan/mã hoá/hỏng/CJK/Việt/form)
|
||||
└─ docs/
|
||||
```
|
||||
|
||||
## Bước khởi động Phase 1 (gợi ý cho session sau)
|
||||
1. Khởi tạo Cargo workspace + crate `ff-cli`, `ff-engine`.
|
||||
2. Thêm `pdfium-render` + tải prebuilt PDFium; viết lệnh CLI `render <pdf> <page> <out.png>` → xác nhận engine chạy.
|
||||
3. Khởi tạo Tauri app, hiển thị 1 trang PDF render từ engine.
|
||||
4. Dựng `corpus/` ban đầu (vài file đa dạng) + test render-hash đầu tiên.
|
||||
@@ -0,0 +1,63 @@
|
||||
# 05 — Hướng dẫn build & chạy (dev)
|
||||
|
||||
> Cập nhật ở cuối Phase 1. Áp dụng cho Windows x64 (môi trường dev hiện tại).
|
||||
|
||||
## Yêu cầu môi trường
|
||||
- **Rust** (MSVC toolchain), cài qua rustup. Kiểm: `rustc --version` (hiện 1.96.0).
|
||||
- **Visual Studio Build Tools** + workload **Desktop development with C++** (cung cấp `cl.exe`/`link.exe` cho linker MSVC).
|
||||
- **WebView2 Runtime** (cho Tauri; Windows 11 thường có sẵn).
|
||||
- **PDFium**: `pdfium.dll` prebuilt — tải bằng `scripts/fetch-pdfium.ps1` (đặt vào gốc workspace + `pdfium/`).
|
||||
- (Tauri) Node không bắt buộc: app dùng frontend tĩnh, chạy thẳng bằng `cargo run`.
|
||||
|
||||
## Lấy PDFium
|
||||
```powershell
|
||||
# Tải pdfium.dll (bblanchon/pdfium-binaries) về gốc workspace
|
||||
powershell -File scripts/fetch-pdfium.ps1
|
||||
```
|
||||
Engine tìm `pdfium.dll` theo thứ tự: `FOFREEXIT_PDFIUM_PATH` → cwd → `./pdfium` → thư mục exe → thư viện hệ thống.
|
||||
|
||||
## Cấu trúc
|
||||
```
|
||||
crates/ff-cos # COS layer (khung)
|
||||
crates/ff-pdmodel # PD layer (khung)
|
||||
crates/ff-engine # render qua PDFium (Phase 1: render.rs)
|
||||
crates/ff-cli # CLI "ff" (info, render)
|
||||
app/src # frontend tĩnh (HTML/CSS/JS)
|
||||
app/src-tauri # backend Tauri (crate riêng, workspace tách)
|
||||
corpus/ # PDF mẫu để test
|
||||
scripts/ # tiện ích (fetch-pdfium)
|
||||
```
|
||||
|
||||
## CLI
|
||||
```powershell
|
||||
# Đếm trang
|
||||
cargo run -p ff-cli -- info corpus\hello.pdf
|
||||
# Render trang 0 ra PNG, rộng 800px
|
||||
cargo run -p ff-cli -- render corpus\hello.pdf out.png --page 0 --width 800
|
||||
# Kích thước mọi trang
|
||||
cargo run -p ff-cli -- pages corpus\sample-multipage.pdf
|
||||
# Trích text 1 trang
|
||||
cargo run -p ff-cli -- text corpus\sample-multipage.pdf --page 1
|
||||
# Tìm kiếm (in vị trí + toạ độ)
|
||||
cargo run -p ff-cli -- search corpus\sample-multipage.pdf content
|
||||
# Outline / bookmarks
|
||||
cargo run -p ff-cli -- outline corpus\sample-multipage.pdf
|
||||
```
|
||||
|
||||
## Test
|
||||
```powershell
|
||||
cargo test -p ff-engine # smoke test render (cần pdfium.dll)
|
||||
```
|
||||
|
||||
## Chạy app desktop (Tauri)
|
||||
```powershell
|
||||
cd app\src-tauri
|
||||
cargo run # mở cửa sổ, hiển thị corpus\hello.pdf
|
||||
```
|
||||
> App là một Cargo workspace **riêng** (có `[workspace]` trống trong `app/src-tauri/Cargo.toml`)
|
||||
> nên lệnh `cargo` ở gốc repo không build app, và ngược lại. Đây là chủ ý để tránh
|
||||
> xung đột profile build giữa thư viện và Tauri.
|
||||
|
||||
## Ghi chú
|
||||
- Bản dev set `FOFREEXIT_PDFIUM_PATH` tự động về gốc workspace (xem `app/src-tauri/src/main.rs`).
|
||||
Bản release sẽ bundle `pdfium.dll` như resource (việc của Phase 8).
|
||||
@@ -0,0 +1,50 @@
|
||||
# 06 — Tổng kết Phase 1 (Engine core + Viewer)
|
||||
|
||||
> Trạng thái: **HOÀN TẤT** các mục lõi. 10/10 test tự động xanh. Đã xác minh UI bằng screenshot & thao tác thực.
|
||||
|
||||
## 1. Đã xây dựng những gì
|
||||
|
||||
### Hạ tầng & toolchain
|
||||
- Cài Rust 1.96 (MSVC) + Visual Studio Build Tools 2026 (workload C++) + WebView2.
|
||||
- Tải PDFium prebuilt (`pdfium.dll`) qua [scripts/fetch-pdfium.ps1](../scripts/fetch-pdfium.ps1).
|
||||
- **Cargo workspace**: `crates/ff-cos`, `crates/ff-pdmodel`, `crates/ff-engine`, `crates/ff-cli`.
|
||||
- **App Tauri** tại `app/` (workspace tách riêng) — chạy bằng `cd app/src-tauri; cargo run`.
|
||||
|
||||
### Engine (`ff-engine`, dùng PDFium qua `pdfium-render`)
|
||||
| Hàm | Chức năng |
|
||||
|-----|-----------|
|
||||
| `bind_pdfium` | Nạp thư viện PDFium động |
|
||||
| `render_page` / `render_page_png` | Render trang ra ảnh (RGBA/PNG) theo chiều rộng |
|
||||
| `page_count`, `page_dims` | Số trang & kích thước từng trang |
|
||||
| `extract_text` | Trích text một trang |
|
||||
| `search` | Tìm chuỗi (có/không phân biệt hoa thường) + **toạ độ rect** từng kết quả |
|
||||
| `outline` | Đọc bookmarks + trang đích |
|
||||
| `page_char_boxes` | Hộp bao từng ký tự (cho text-layer chọn/copy) |
|
||||
|
||||
### CLI (`ff`) — chạy mọi tính năng không cần UI (phục vụ test)
|
||||
`info`, `render`, `pages`, `text`, `search`, `outline`.
|
||||
|
||||
### App desktop (Tauri + frontend tĩnh)
|
||||
- **Mở file** qua hộp thoại native (`📂 Mở`) — lọc *.pdf.
|
||||
- **Xem**: cuộn liên tục nhiều trang, **lazy render** (chỉ render trang trong tầm nhìn) → mở mượt file 1000+ trang.
|
||||
- **Zoom** −/+/Fit (re-render sắc nét theo devicePixelRatio).
|
||||
- **Thumbnails** sidebar (lazy-render, đánh dấu trang hiện tại).
|
||||
- **Outline** sidebar (click → nhảy trang).
|
||||
- **Tìm kiếm** + highlight chính xác từng kết quả, điều hướng ◀ x/y ▶, highlight bám đúng cả khi zoom.
|
||||
- **Chọn & copy text**: text-layer trong suốt phủ đúng từng glyph; chọn bằng chuột/Shift+Click + Ctrl+C, hoặc nút **Copy** (cả trang).
|
||||
|
||||
## 2. Test tự động (10/10 xanh) — `cargo test`
|
||||
- `render_smoke`: mở & render `hello.pdf`, trang không trắng trơn.
|
||||
- `viewer_features` (6): `page_dims`, `extract_text`, `search` (số lượng+vị trí), phân biệt hoa thường, `outline`, `char_boxes` (ghép ký tự = nội dung + hộp nằm trong khổ trang).
|
||||
- `big_doc` (3): file **1000 trang** — đúng số trang; render trang đầu/cuối < 5s & không trắng; search toàn tài liệu ra đúng 1 kết quả < 10s.
|
||||
|
||||
Hiệu năng đo thực tế trên `big-1000.pdf`: mở 55ms · render 1 trang 110ms · search toàn bộ 79ms.
|
||||
|
||||
## 3. Giới hạn đã biết của Phase 1 (sẽ tinh chỉnh)
|
||||
- ~~Double-click chọn 1 ký tự~~ → **ĐÃ SỬA**: text-layer gom ký tự thành "từ", double-click chọn cả từ; copy giữ khoảng trắng (chèn text node giữa các từ). Đã verify: double-click → chọn nguyên từ "FoFreeXit".
|
||||
- Chưa có: in ấn, xoay trang khi xem, nhớ file mở gần đây, kéo-thả file vào cửa sổ.
|
||||
- `render_page` nạp lại tài liệu mỗi lần gọi (chưa cache document trong bộ nhớ) — đủ nhanh hiện tại, sẽ tối ưu bằng cache khi cần.
|
||||
- Bản dev tìm `pdfium.dll` ở gốc workspace; bản phát hành (Phase 8) sẽ bundle.
|
||||
|
||||
## 4. Kiến trúc vẫn đúng định hướng
|
||||
2 tầng COS/PD đã đặt khung (`ff-cos`, `ff-pdmodel`); engine tách hẳn UI, gọi được qua CLI + Tauri. Sẵn sàng cho Phase 2 (Annotate).
|
||||
@@ -0,0 +1,76 @@
|
||||
# 07 — Checklist test thủ công cho Phase 1 (dành cho người dùng)
|
||||
|
||||
Mục tiêu: bạn tự kiểm tra viewer, ghi lại chỗ nào chưa ổn để cải thiện **trước khi sang Phase 2**.
|
||||
|
||||
## Cách chạy app
|
||||
```powershell
|
||||
cd c:\Project\FoFreeXit\app\src-tauri
|
||||
cargo run
|
||||
```
|
||||
(Lần đầu mở sẵn `corpus/sample-multipage.pdf`. Nếu thiếu `pdfium.dll`: chạy `scripts/fetch-pdfium.ps1`.)
|
||||
|
||||
## Bảng test — đánh dấu ✅/❌ và ghi chú
|
||||
|
||||
### A. Mở file
|
||||
| # | Thao tác | Kỳ vọng | KQ |
|
||||
|---|----------|---------|----|
|
||||
| A1 | Bấm **📂 Mở**, chọn 1 PDF thật của bạn | Mở & hiển thị đúng | |
|
||||
| A2 | Mở file **rất lớn** (vài trăm–1000+ trang) | Mở nhanh, không treo | |
|
||||
| A3 | Mở file **scan** (ảnh, không có text) | Hiển thị được (sẽ không chọn được text — đúng) | |
|
||||
| A4 | Mở file **tiếng Việt có dấu** | Chữ + dấu hiển thị đúng | |
|
||||
| A5 | Mở file **mã hoá/đặt mật khẩu** | (Dự kiến lỗi — Phase 5 mới hỗ trợ) ghi lại hiện tượng | |
|
||||
| A6 | Mở file **hỏng/khác thường** | Không crash; báo lỗi gọn | |
|
||||
|
||||
### B. Xem & điều hướng
|
||||
| # | Thao tác | Kỳ vọng | KQ |
|
||||
|---|----------|---------|----|
|
||||
| B1 | Cuộn lên/xuống nhiều trang | Mượt, trang hiện dần | |
|
||||
| B2 | Chỉ số "Trang x/y" khi cuộn | Cập nhật đúng trang đang xem | |
|
||||
| B3 | Bấm thumbnail | Nhảy đúng trang | |
|
||||
| B4 | Tab **Outline**, bấm mục | Nhảy đúng trang đích | |
|
||||
| B5 | So sánh hiển thị với Foxit/Chrome cùng file | Trông giống nhau | |
|
||||
|
||||
### C. Zoom
|
||||
| # | Thao tác | Kỳ vọng | KQ |
|
||||
|---|----------|---------|----|
|
||||
| C1 | Bấm + / − nhiều lần | Phóng to/thu nhỏ, chữ vẫn nét | |
|
||||
| C2 | Bấm **Fit** | Vừa bề rộng cửa sổ | |
|
||||
| C3 | Zoom rồi cuộn | Không vỡ layout, không lag nặng | |
|
||||
|
||||
### D. Tìm kiếm
|
||||
| # | Thao tác | Kỳ vọng | KQ |
|
||||
|---|----------|---------|----|
|
||||
| D1 | Gõ 1 từ có trong file | Hiện "k/n", nhảy tới kết quả, **ô vàng/cam đúng chỗ** | |
|
||||
| D2 | Bấm ◀ ▶ duyệt kết quả | Nhảy lần lượt, đổi highlight | |
|
||||
| D3 | Tìm từ tiếng Việt có dấu | Tìm đúng | |
|
||||
| D4 | Tìm từ không tồn tại | Hiện 0, không lỗi | |
|
||||
|
||||
### E. Chọn & copy text
|
||||
| # | Thao tác | Kỳ vọng | KQ |
|
||||
|---|----------|---------|----|
|
||||
| E1 | **Kéo chuột** chọn 1 đoạn text | Bôi xanh đúng vùng | |
|
||||
| E2 | Ctrl+C rồi dán ra Notepad | Đúng nội dung, đúng thứ tự | |
|
||||
| E3 | **Double-click** 1 từ | (Hiện chỉ chọn 1 ký tự — đã biết, sẽ sửa) | |
|
||||
| E4 | Nút **Copy** | Copy text cả trang hiện tại | |
|
||||
| E5 | Copy đoạn **tiếng Việt có dấu** | Dấu không bị mất/lỗi | |
|
||||
|
||||
### F. Ổn định & hiệu năng
|
||||
| # | Thao tác | Kỳ vọng | KQ |
|
||||
|---|----------|---------|----|
|
||||
| F1 | Mở/đóng/đổi nhiều file liên tiếp | Không rò bộ nhớ rõ rệt, không crash | |
|
||||
| F2 | Mở file lớn rồi cuộn nhanh | RAM/CPU chấp nhận được | |
|
||||
| F3 | Phóng to hết cỡ file lớn | Không treo | |
|
||||
|
||||
## Mẫu phản hồi gửi lại
|
||||
Với mỗi mục ❌ hoặc chưa hài lòng, ghi theo mẫu:
|
||||
```
|
||||
[Mã test] (vd D1) — File: <tên/loại file> — Hiện tượng: <mô tả> —
|
||||
Kỳ vọng: <bạn muốn gì> — Mức ưu tiên: cao/vừa/thấp
|
||||
```
|
||||
Ví dụ:
|
||||
```
|
||||
B5 — File: hop_dong.pdf — Hiện tượng: chữ mờ hơn Foxit khi zoom 100% —
|
||||
Kỳ vọng: nét như Foxit — Ưu tiên: vừa
|
||||
```
|
||||
|
||||
> Gửi danh sách phản hồi này lại, tôi sẽ sửa hết các điểm chưa đạt của Phase 1 **trước khi** bắt đầu Phase 2 (Annotate).
|
||||
@@ -0,0 +1,42 @@
|
||||
# 08 — Tổng kết Phase 2 (Annotate)
|
||||
|
||||
> Trạng thái: **lõi HOÀN TẤT**. 13/13 test tự động xanh. Đường GHI file (rủi ro nhất) đã round-trip + verify ảnh.
|
||||
|
||||
## 1. Đã làm
|
||||
|
||||
### Engine (`crates/ff-engine/src/annot.rs`)
|
||||
- `apply_annotations(input, output, specs)`: tạo annotation rồi **lưu sang file mới** (không sửa file gốc), qua `document.save_to_file`.
|
||||
- 6 loại: **Highlight, Underline, Strikeout** (text-markup, dùng QuadPoints), **Square** (khung), **FreeText** (hộp văn bản), **Note** (ghi chú dán).
|
||||
- `list_annotations` / `count_annotations`: đọc lại annotation (loại, vùng, nội dung).
|
||||
- Bài học: QuadPoints highlight phải theo thứ tự TL,TR,BL,BR (helper `quad_from_rect`) — `PdfQuadPoints::from_rect` của thư viện dùng thứ tự khác làm highlight bị xoắn.
|
||||
|
||||
### Tauri commands (`app/src-tauri/src/main.rs`)
|
||||
- `apply_annotations(input, output, specs)` — map DTO (JS) → engine.
|
||||
- `pick_save_pdf()` — hộp thoại Lưu.
|
||||
|
||||
### UI (`app/src`)
|
||||
- Thanh **Chú thích**: 6 công cụ (Tô sáng, Gạch chân, Gạch ngang, Khung, Text box, Ghi chú) + chọn **màu** + nút **Lưu chú thích (n)**.
|
||||
- **Vẽ bằng chuột**: kéo vùng trên trang → tạo chú thích, **preview tức thì** (lớp `.annotlayer`), toạ độ màn hình→điểm PDF chính xác (cùng phép biến đổi đã kiểm ở search/text-layer).
|
||||
- Tab **Chú thích** (sidebar): danh sách chú thích chưa lưu, click để nhảy trang, ✕ để xoá.
|
||||
- **Lưu**: nút → hộp thoại → ghi file mới (annotation thật) rồi mở lại để render.
|
||||
- CLI: `ff annots <pdf>` liệt kê annotation; `ff chars <pdf>` (debug).
|
||||
|
||||
## 2. Test tự động (13/13 xanh)
|
||||
- `annot_roundtrip` (3): Highlight+Square; Underline+Strikeout; FreeText+Note — ghi → mở lại → đúng loại/nội dung + render đúng màu.
|
||||
- Cùng các test Phase 1 (viewer_features 6, big_doc 3, render_smoke 1).
|
||||
|
||||
## 3. Đã kiểm bằng tay/ảnh
|
||||
- Round-trip render: highlight vàng phủ khít "content", khung đỏ (ảnh `tmp-out/annot-*.png`).
|
||||
- UI: vẽ highlight/underline/strikeout/box hiển thị preview đúng vị trí, đổi màu/đổi công cụ, đếm số chú thích (ảnh `tmp-out/annot-draw.png`).
|
||||
|
||||
> Ghi chú kỹ thuật: tự-động-hoá chuột Win32 KHÔNG mô phỏng được thao tác "kéo" trong WebView2 (mousemove giả lập bị lọc) — nên drag-vẽ và drag-chọn-text chỉ kiểm được bằng ảnh khi events lọt, hoặc bằng thao tác rời (click/shift-click). Với chuột thật của người dùng, kéo hoạt động bình thường.
|
||||
|
||||
## 4. Còn lại / follow-up (chưa làm)
|
||||
- **Ink** (vẽ tay tự do).
|
||||
- **Sửa/di chuyển/xoá** annotation đã lưu (hiện chỉ xoá cái *chưa* lưu).
|
||||
- Liệt kê annotation **đã lưu** trong tab Chú thích (hiện chỉ liệt kê cái chưa lưu).
|
||||
- **Import/Export XFDF**.
|
||||
- Độ trung thực cross-viewer (appearance stream) cho FreeText/Note ở Acrobat.
|
||||
|
||||
## 5. Cần người dùng xác nhận (vì kéo-chuột thật không tự test được)
|
||||
Xem checklist: [docs/09-phase2-user-tests.md](09-phase2-user-tests.md).
|
||||
@@ -0,0 +1,33 @@
|
||||
# 09 — Checklist test thủ công Phase 2 (Annotate)
|
||||
|
||||
Phần kéo-chuột không tự động test được trong WebView2 (xem ghi chú ở [08-phase2-summary.md](08-phase2-summary.md)), nên cần bạn thử bằng chuột thật.
|
||||
|
||||
## Chạy
|
||||
```powershell
|
||||
cd c:\Project\FoFreeXit\app\src-tauri
|
||||
cargo run
|
||||
```
|
||||
|
||||
## Bảng test
|
||||
| # | Thao tác | Kỳ vọng | KQ |
|
||||
|---|----------|---------|----|
|
||||
| G1 | Chọn **Tô sáng**, kéo qua một dòng chữ | Vệt vàng phủ đúng vùng kéo | |
|
||||
| G2 | Chọn **Gạch chân**, kéo qua chữ | Đường kẻ dưới chữ | |
|
||||
| G3 | Chọn **Gạch ngang**, kéo qua chữ | Đường kẻ giữa chữ | |
|
||||
| G4 | Chọn **Khung**, kéo một vùng | Khung chữ nhật | |
|
||||
| G5 | Đổi **Màu** rồi vẽ | Chú thích đúng màu mới | |
|
||||
| G6 | Chọn **Text box**, kéo vùng, gõ chữ | Hộp chữ hiện nội dung | |
|
||||
| G7 | Chọn **Ghi chú**, bấm lên trang, gõ chữ | Icon ghi chú 📝 (rê chuột thấy nội dung) | |
|
||||
| G8 | Tab **Chú thích** (sidebar) | Liệt kê các chú thích vừa vẽ; bấm để nhảy trang; ✕ để xoá | |
|
||||
| G9 | Bấm **Lưu chú thích**, chọn nơi lưu | Tạo file PDF mới; app mở lại file đó | |
|
||||
| G10 | Mở file vừa lưu bằng **Foxit/Adobe/Chrome** | Annotation hiển thị đúng ở phần mềm khác | |
|
||||
| G11 | Vẽ trên file **nhiều trang**, cuộn qua lại | Chú thích đúng trang, đúng vị trí khi cuộn/zoom | |
|
||||
| G12 | Vẽ rồi **zoom** in/out | Chú thích co giãn theo, vẫn đúng chỗ | |
|
||||
|
||||
## Mẫu phản hồi
|
||||
```
|
||||
[Mã] (vd G10) — Phần mềm mở: <Foxit/Adobe/Chrome> — Hiện tượng: <mô tả> —
|
||||
Kỳ vọng: <...> — Ưu tiên: cao/vừa/thấp
|
||||
```
|
||||
|
||||
> Đặc biệt cần biết **G10** (file lưu ra mở ở phần mềm khác có đúng không) và **G9** (lưu có thành công không), vì đó là đường GHI file. Engine đã test round-trip nội bộ, nhưng xác nhận cross-viewer của bạn rất giá trị.
|
||||
Reference in New Issue
Block a user