repdf 0.1.0__tar.gz → 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. {repdf-0.1.0 → repdf-0.1.2}/PKG-INFO +24 -6
  2. {repdf-0.1.0 → repdf-0.1.2}/README.md +22 -4
  3. {repdf-0.1.0 → repdf-0.1.2}/pyproject.toml +2 -2
  4. {repdf-0.1.0 → repdf-0.1.2}/pyproject.toml.orig +2 -2
  5. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/app.py +39 -2
  6. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/icons.py +12 -1
  7. repdf-0.1.2/src/repdf/navigation.py +397 -0
  8. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/ocr.py +112 -24
  9. repdf-0.1.2/src/repdf/ocr_languages.py +219 -0
  10. repdf-0.1.2/src/repdf/ocr_models.py +82 -0
  11. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/packaging_smoke.py +39 -0
  12. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/page_view.py +14 -0
  13. repdf-0.1.2/src/repdf/pdf_annotations.py +92 -0
  14. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/pdf_navigation.py +8 -1
  15. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/preview.py +4 -0
  16. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/render_worker.py +33 -8
  17. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/renderer.py +4 -2
  18. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/strings.py +54 -0
  19. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/theme.py +8 -0
  20. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/toolbar.py +39 -0
  21. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/widgets.py +26 -2
  22. repdf-0.1.0/src/repdf/navigation.py +0 -235
  23. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/__init__.py +0 -0
  24. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/__main__.py +0 -0
  25. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/assets/check-dark.svg +0 -0
  26. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/assets/check.svg +0 -0
  27. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/assets/partial-dark.svg +0 -0
  28. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/assets/partial.svg +0 -0
  29. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/assets/repdf.ico +0 -0
  30. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/assets/repdf.png +0 -0
  31. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/core.py +0 -0
  32. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/entrypoint.py +0 -0
  33. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/images.py +0 -0
  34. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/preferences.py +0 -0
  35. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/print_preview.py +0 -0
  36. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/printing.py +0 -0
  37. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/search.py +0 -0
  38. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/search_panel.py +0 -0
  39. {repdf-0.1.0 → repdf-0.1.2}/src/repdf/workers.py +0 -0
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: repdf
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: RePDF (Read the PDF): a desktop PDF reader with printing, search, bookmarks, OCR and page rearrangement.
5
5
  Requires-Dist: onnxruntime>=1.31.0,<2
6
6
  Requires-Dist: pillow>=11.0,<13
7
7
  Requires-Dist: pypdf[crypto]>=5.0,<7
8
8
  Requires-Dist: pypdfium2>=4.30,<6
9
9
  Requires-Dist: pyside6>=6.8,<7
10
- Requires-Dist: rapidocr==3.10.0
10
+ Requires-Dist: rapidocr[rtl]==3.10.0
11
11
  Requires-Dist: regex>=2024.11.6
12
12
  Requires-Python: >=3.11
13
13
  Project-URL: Homepage, https://github.com/codemee/repdf
@@ -19,7 +19,7 @@ Description-Content-Type: text/markdown
19
19
 
20
20
  [繁體中文](README.md) | [English](README.en.md)
21
21
 
22
- RePDF 代表 **Read the PDF**,命令與 Python 套件名稱為 `repdf`。這是一套桌面 PDF 閱讀器,支援多標籤閱讀、列印、書籤與目錄跳頁、文字搜尋、選字複製、OCR 及圖片擷取,也可勾選頁面,依標籤與頁面排列順序重組或拆分輸出。重組與拆分保留原始頁面品質。
22
+ RePDF 代表 **Read the PDF**,命令與 Python 套件名稱為 `repdf`。這是一套桌面 PDF 閱讀器,支援多標籤閱讀、列印、書籤與目錄跳頁、註解清單、文字搜尋、選字複製、OCR 及圖片擷取,也可勾選頁面,依標籤與頁面排列順序重組或拆分輸出。重組與拆分保留原始頁面品質。
23
23
 
24
24
  ## 重點特色
25
25
 
@@ -36,7 +36,7 @@ RePDF 代表 **Read the PDF**,命令與 Python 套件名稱為 `repdf`。這
36
36
  - **macOS Apple Silicon(arm64)**:下載 `repdf-<版本>-macos-arm64.dmg`,開啟後將 `RePDF.app` 拖入 Applications,再從 Applications 啟動。
37
37
 
38
38
  - Release 同時提供 SHA256 校驗檔。
39
- - 桌面套件已包含 OCR 執行環境與模型,不需要額外安裝。
39
+ - 桌面套件已包含 OCR 執行環境與內建多語言模型;其他語言可在首次選用時下載,之後離線辨識。
40
40
  - 目前未設定 Windows 程式碼簽章或 macOS Developer ID 簽章/公證,下載後可能出現系統安全提示。
41
41
 
42
42
  ### 2. 使用 uv tool 安裝
@@ -68,6 +68,7 @@ repdf
68
68
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-ocr-region-dark.png"><img src="docs/images/toolbar-ocr-region.png" width="24" alt="區域 OCR 圖示"></picture> | 區域 OCR | 拖曳矩形框選頁面或圖片,放開滑鼠後辨識並複製文字。 | — |
69
69
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-extract-image-dark.png"><img src="docs/images/toolbar-extract-image.png" width="24" alt="擷取圖片圖示"></picture> | 擷取圖片 | 啟用後點選內嵌點陣圖片,再選擇位置另存為 PNG。 | — |
70
70
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-bookmarks-dark.png"><img src="docs/images/toolbar-bookmarks.png" width="24" alt="書籤圖示"></picture> | 書籤 | 在左側章節樹展開或收合書籤,點選章節即可跳頁。 | — |
71
+ | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-annotations-dark.png"><img src="docs/images/toolbar-annotations.png" width="24" alt="註解圖示"></picture> | 註解 | 在左側列出註解,點選即可跳至對應頁面。 | — |
71
72
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-search-dark.png"><img src="docs/images/toolbar-search.png" width="24" alt="搜尋文字圖示"></picture> | 搜尋文字 | 在右側窗格搜尋文字,上方選檔案、下方選命中段落,單擊即可跳頁並高亮。 | Windows/Linux:<kbd>Ctrl</kbd>+<kbd>F</kbd>;macOS:<kbd>⌘</kbd>+<kbd>F</kbd> |
72
73
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-zoom-dark.png"><img src="docs/images/toolbar-zoom.png" width="160" alt="顯示比例與縮放滑桿"></picture> | 顯示比例 | 滑桿調整 25%–200%;點擊比例回到 100%。鍵盤縮放每次調整 25 個百分點。 | 放大:<kbd>Ctrl</kbd>+<kbd>+</kbd>/<kbd>Ctrl</kbd>+<kbd>=</kbd>;縮小:<kbd>Ctrl</kbd>+<kbd>-</kbd>;100%:<kbd>Ctrl</kbd>+<kbd>0</kbd> |
73
74
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-fit-dark.png"><img src="docs/images/toolbar-fit.png" width="24" alt="Fit 圖示"></picture> | Fit | 將目前單頁等比例縮放至預覽區;調整視窗大小時自動適應。拖動滑桿或使用縮放快捷鍵會回到手動比例。 | — |
@@ -153,11 +154,25 @@ repdf
153
154
  - 書籤跟隨目前標籤頁切換;沒有內建書籤的文件會顯示提示。
154
155
  - 一般預覽與全螢幕都可直接點選 PDF 頁內的目錄連結;滑鼠移到可跳頁區域時會顯示手指游標與目的頁碼。
155
156
  - 跳頁保留目前縮放/Fit 模式。頁面已重新排序時,仍會找到目的章節所屬的原始頁面。
156
- - 視窗縮窄時,書籤與 PDF 以單一窗格切換;點選章節後返回 PDF,再點「書籤」可返回目錄。搜尋與書籤窗格可透過各自的工具按鈕切換。
157
+ - 視窗縮窄時,書籤與 PDF 以單一窗格切換;點選章節後返回 PDF,再點「書籤」可返回目錄。書籤、註解與搜尋窗格可透過各自的工具按鈕切換。
157
158
  - 啟用複製文字、區域 OCR 或圖片擷取模式時,頁內連結暫停點選;停用後即可跳頁,拖曳頁面仍可排序。
158
159
  - 一般預覽與全螢幕可點選 PDF 內建的 HTTP/HTTPS 超連結,以系統預設瀏覽器開啟;滑鼠停留可查看網址。
159
160
  - 此功能使用 PDF 已有的書籤與連結;純文字或掃描圖片形式的目錄、網址不會自動變成連結。電子郵件、外部文件與其他動作不在支援範圍。
160
161
 
162
+ ### 註解清單
163
+
164
+ - 點工具列的「註解」對話框圖示,開啟目前標籤頁的左側註解清單。
165
+ - 清單依 PDF 原始頁序分組,每頁顯示註解數量,預設收合;展開後查看個別註解的類型與摘要。切換標籤、書籤或介面語言後會保留展開狀態。滑鼠停留可查看完整內容、作者、主旨及修改時間(若文件有提供)。
166
+ - 點選頁碼群組即可跳到該頁清單中的第一個註解,並標示其範圍;點選個別註解會跳到對應位置,並以半透明底色與外框標示註解範圍。保留目前縮放/Fit 模式,頁面重新排列後仍會找到原始目標頁。
167
+ - 選取含文字的註解時,會自動將註解文字複製到剪貼簿;頁碼群組會複製第一個註解的文字。無文字的註解不會覆蓋剪貼簿內容。
168
+ - 關閉註解窗格或切換至其他側欄時,會取消框選;重新開啟清單不會自動複製文字或恢復框選。
169
+ - 框選會跟隨縮放與全螢幕顯示;點選另一註解或頁碼群組會更新標示,點選書籤或搜尋結果則清除標示。文件未提供有效註解範圍時,仍可跳頁。
170
+ - 支援備註、文字方塊、螢光標示、底線、刪除線、手繪及形狀等註解。文字標示若沒有附註內容,會嘗試顯示標示的原文。
171
+ - 在一般閱讀模式可直接點選頁面上的註解,框選其範圍並同步選取左側清單、展開對應頁面群組;全螢幕也可使用。選字、區域 OCR 與圖片擷取模式保留各自操作。窄視窗點選後維持 PDF 顯示,再按「註解」即可查看清單中的選取項目。
172
+ - 註解跟隨標籤頁切換;沒有註解時顯示提示。書籤、註解與搜尋窗格透過各自的按鈕切換。
173
+ - 視窗較窄時,點選後返回 PDF;再點「註解」可返回清單。
174
+ - 完整註解清單只在開啟窗格時於背景讀取;頁面點選範圍則隨目前需要顯示的頁面讀取,不會在開檔時掃描整份文件;此功能提供檢視與跳頁,不編輯註解或執行附件內容。
175
+
161
176
  ### 搜尋文字
162
177
 
163
178
  1. 點「搜尋文字」或按 <kbd>Ctrl</kbd>+<kbd>F</kbd>(macOS:<kbd>⌘</kbd>+<kbd>F</kbd>),開啟右側窗格。
@@ -214,7 +229,10 @@ repdf
214
229
  - 輸出完整內嵌圖片,不套用頁面上的旋轉或裁切,也不包含周圍文字與向量圖形。
215
230
  - 點到空白處會顯示提示;同一位置有多張圖片時,選取最後繪製的圖片。
216
231
  - 掃描頁面通常會擷取整張掃描圖,無法從中直接分離照片或圖表。
217
- - OCR 支援繁體中文、簡體中文、英文、日文及多種拉丁字母語言,不支援韓文;辨識後請校對結果。完整操作與限制見 [OCR 說明](docs/OCR.md)。
232
+ - OCR 預設支援繁體中文、簡體中文、英文、日文及多種拉丁字母語言。點「區域 OCR」旁的箭頭,可選韓文、泰文、俄文/烏克蘭文、阿拉伯文與印地文/尼泊爾文;另提供希臘文、泰米爾文與泰盧固文。
233
+ - 選「自動+已下載模型」可共用內建與已下載模型,逐行選擇辨識結果,不會自行下載其他模型。
234
+ - 語言選單以分隔線區分自動選項、已下載與未下載三組,不顯示群組標題;已下載的模型名稱後會標記「已下載」。模型下載、遺失或損壞後,分組與標記會自動更新。
235
+ - 額外模型會先顯示下載確認,下載完成才切換語言;取消或失敗保留原設定。語言設定會記住,並套用於區域 OCR 及損壞文字備援。辨識後請校對結果。完整操作與限制見 [OCR 說明](docs/OCR.md)。
218
236
 
219
237
  ## 語言與配色
220
238
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  [繁體中文](README.md) | [English](README.en.md)
4
4
 
5
- RePDF 代表 **Read the PDF**,命令與 Python 套件名稱為 `repdf`。這是一套桌面 PDF 閱讀器,支援多標籤閱讀、列印、書籤與目錄跳頁、文字搜尋、選字複製、OCR 及圖片擷取,也可勾選頁面,依標籤與頁面排列順序重組或拆分輸出。重組與拆分保留原始頁面品質。
5
+ RePDF 代表 **Read the PDF**,命令與 Python 套件名稱為 `repdf`。這是一套桌面 PDF 閱讀器,支援多標籤閱讀、列印、書籤與目錄跳頁、註解清單、文字搜尋、選字複製、OCR 及圖片擷取,也可勾選頁面,依標籤與頁面排列順序重組或拆分輸出。重組與拆分保留原始頁面品質。
6
6
 
7
7
  ## 重點特色
8
8
 
@@ -19,7 +19,7 @@ RePDF 代表 **Read the PDF**,命令與 Python 套件名稱為 `repdf`。這
19
19
  - **macOS Apple Silicon(arm64)**:下載 `repdf-<版本>-macos-arm64.dmg`,開啟後將 `RePDF.app` 拖入 Applications,再從 Applications 啟動。
20
20
 
21
21
  - Release 同時提供 SHA256 校驗檔。
22
- - 桌面套件已包含 OCR 執行環境與模型,不需要額外安裝。
22
+ - 桌面套件已包含 OCR 執行環境與內建多語言模型;其他語言可在首次選用時下載,之後離線辨識。
23
23
  - 目前未設定 Windows 程式碼簽章或 macOS Developer ID 簽章/公證,下載後可能出現系統安全提示。
24
24
 
25
25
  ### 2. 使用 uv tool 安裝
@@ -51,6 +51,7 @@ repdf
51
51
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-ocr-region-dark.png"><img src="docs/images/toolbar-ocr-region.png" width="24" alt="區域 OCR 圖示"></picture> | 區域 OCR | 拖曳矩形框選頁面或圖片,放開滑鼠後辨識並複製文字。 | — |
52
52
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-extract-image-dark.png"><img src="docs/images/toolbar-extract-image.png" width="24" alt="擷取圖片圖示"></picture> | 擷取圖片 | 啟用後點選內嵌點陣圖片,再選擇位置另存為 PNG。 | — |
53
53
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-bookmarks-dark.png"><img src="docs/images/toolbar-bookmarks.png" width="24" alt="書籤圖示"></picture> | 書籤 | 在左側章節樹展開或收合書籤,點選章節即可跳頁。 | — |
54
+ | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-annotations-dark.png"><img src="docs/images/toolbar-annotations.png" width="24" alt="註解圖示"></picture> | 註解 | 在左側列出註解,點選即可跳至對應頁面。 | — |
54
55
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-search-dark.png"><img src="docs/images/toolbar-search.png" width="24" alt="搜尋文字圖示"></picture> | 搜尋文字 | 在右側窗格搜尋文字,上方選檔案、下方選命中段落,單擊即可跳頁並高亮。 | Windows/Linux:<kbd>Ctrl</kbd>+<kbd>F</kbd>;macOS:<kbd>⌘</kbd>+<kbd>F</kbd> |
55
56
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-zoom-dark.png"><img src="docs/images/toolbar-zoom.png" width="160" alt="顯示比例與縮放滑桿"></picture> | 顯示比例 | 滑桿調整 25%–200%;點擊比例回到 100%。鍵盤縮放每次調整 25 個百分點。 | 放大:<kbd>Ctrl</kbd>+<kbd>+</kbd>/<kbd>Ctrl</kbd>+<kbd>=</kbd>;縮小:<kbd>Ctrl</kbd>+<kbd>-</kbd>;100%:<kbd>Ctrl</kbd>+<kbd>0</kbd> |
56
57
  | <picture><source media="(prefers-color-scheme: dark)" srcset="docs/images/toolbar-fit-dark.png"><img src="docs/images/toolbar-fit.png" width="24" alt="Fit 圖示"></picture> | Fit | 將目前單頁等比例縮放至預覽區;調整視窗大小時自動適應。拖動滑桿或使用縮放快捷鍵會回到手動比例。 | — |
@@ -136,11 +137,25 @@ repdf
136
137
  - 書籤跟隨目前標籤頁切換;沒有內建書籤的文件會顯示提示。
137
138
  - 一般預覽與全螢幕都可直接點選 PDF 頁內的目錄連結;滑鼠移到可跳頁區域時會顯示手指游標與目的頁碼。
138
139
  - 跳頁保留目前縮放/Fit 模式。頁面已重新排序時,仍會找到目的章節所屬的原始頁面。
139
- - 視窗縮窄時,書籤與 PDF 以單一窗格切換;點選章節後返回 PDF,再點「書籤」可返回目錄。搜尋與書籤窗格可透過各自的工具按鈕切換。
140
+ - 視窗縮窄時,書籤與 PDF 以單一窗格切換;點選章節後返回 PDF,再點「書籤」可返回目錄。書籤、註解與搜尋窗格可透過各自的工具按鈕切換。
140
141
  - 啟用複製文字、區域 OCR 或圖片擷取模式時,頁內連結暫停點選;停用後即可跳頁,拖曳頁面仍可排序。
141
142
  - 一般預覽與全螢幕可點選 PDF 內建的 HTTP/HTTPS 超連結,以系統預設瀏覽器開啟;滑鼠停留可查看網址。
142
143
  - 此功能使用 PDF 已有的書籤與連結;純文字或掃描圖片形式的目錄、網址不會自動變成連結。電子郵件、外部文件與其他動作不在支援範圍。
143
144
 
145
+ ### 註解清單
146
+
147
+ - 點工具列的「註解」對話框圖示,開啟目前標籤頁的左側註解清單。
148
+ - 清單依 PDF 原始頁序分組,每頁顯示註解數量,預設收合;展開後查看個別註解的類型與摘要。切換標籤、書籤或介面語言後會保留展開狀態。滑鼠停留可查看完整內容、作者、主旨及修改時間(若文件有提供)。
149
+ - 點選頁碼群組即可跳到該頁清單中的第一個註解,並標示其範圍;點選個別註解會跳到對應位置,並以半透明底色與外框標示註解範圍。保留目前縮放/Fit 模式,頁面重新排列後仍會找到原始目標頁。
150
+ - 選取含文字的註解時,會自動將註解文字複製到剪貼簿;頁碼群組會複製第一個註解的文字。無文字的註解不會覆蓋剪貼簿內容。
151
+ - 關閉註解窗格或切換至其他側欄時,會取消框選;重新開啟清單不會自動複製文字或恢復框選。
152
+ - 框選會跟隨縮放與全螢幕顯示;點選另一註解或頁碼群組會更新標示,點選書籤或搜尋結果則清除標示。文件未提供有效註解範圍時,仍可跳頁。
153
+ - 支援備註、文字方塊、螢光標示、底線、刪除線、手繪及形狀等註解。文字標示若沒有附註內容,會嘗試顯示標示的原文。
154
+ - 在一般閱讀模式可直接點選頁面上的註解,框選其範圍並同步選取左側清單、展開對應頁面群組;全螢幕也可使用。選字、區域 OCR 與圖片擷取模式保留各自操作。窄視窗點選後維持 PDF 顯示,再按「註解」即可查看清單中的選取項目。
155
+ - 註解跟隨標籤頁切換;沒有註解時顯示提示。書籤、註解與搜尋窗格透過各自的按鈕切換。
156
+ - 視窗較窄時,點選後返回 PDF;再點「註解」可返回清單。
157
+ - 完整註解清單只在開啟窗格時於背景讀取;頁面點選範圍則隨目前需要顯示的頁面讀取,不會在開檔時掃描整份文件;此功能提供檢視與跳頁,不編輯註解或執行附件內容。
158
+
144
159
  ### 搜尋文字
145
160
 
146
161
  1. 點「搜尋文字」或按 <kbd>Ctrl</kbd>+<kbd>F</kbd>(macOS:<kbd>⌘</kbd>+<kbd>F</kbd>),開啟右側窗格。
@@ -197,7 +212,10 @@ repdf
197
212
  - 輸出完整內嵌圖片,不套用頁面上的旋轉或裁切,也不包含周圍文字與向量圖形。
198
213
  - 點到空白處會顯示提示;同一位置有多張圖片時,選取最後繪製的圖片。
199
214
  - 掃描頁面通常會擷取整張掃描圖,無法從中直接分離照片或圖表。
200
- - OCR 支援繁體中文、簡體中文、英文、日文及多種拉丁字母語言,不支援韓文;辨識後請校對結果。完整操作與限制見 [OCR 說明](docs/OCR.md)。
215
+ - OCR 預設支援繁體中文、簡體中文、英文、日文及多種拉丁字母語言。點「區域 OCR」旁的箭頭,可選韓文、泰文、俄文/烏克蘭文、阿拉伯文與印地文/尼泊爾文;另提供希臘文、泰米爾文與泰盧固文。
216
+ - 選「自動+已下載模型」可共用內建與已下載模型,逐行選擇辨識結果,不會自行下載其他模型。
217
+ - 語言選單以分隔線區分自動選項、已下載與未下載三組,不顯示群組標題;已下載的模型名稱後會標記「已下載」。模型下載、遺失或損壞後,分組與標記會自動更新。
218
+ - 額外模型會先顯示下載確認,下載完成才切換語言;取消或失敗保留原設定。語言設定會記住,並套用於區域 OCR 及損壞文字備援。辨識後請校對結果。完整操作與限制見 [OCR 說明](docs/OCR.md)。
201
219
 
202
220
  ## 語言與配色
203
221
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "repdf"
3
- version = "0.1.0"
3
+ version = "0.1.2"
4
4
  description = "RePDF (Read the PDF): a desktop PDF reader with printing, search, bookmarks, OCR and page rearrangement."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -10,7 +10,7 @@ dependencies = [
10
10
  "pypdf[crypto]>=5.0,<7",
11
11
  "pypdfium2>=4.30,<6",
12
12
  "pyside6>=6.8,<7",
13
- "rapidocr==3.10.0",
13
+ "rapidocr[rtl]==3.10.0",
14
14
  "regex>=2024.11.6",
15
15
  ]
16
16
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "repdf"
3
- version = "0.1.0"
3
+ version = "0.1.2"
4
4
  description = "RePDF (Read the PDF): a desktop PDF reader with printing, search, bookmarks, OCR and page rearrangement."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -11,7 +11,7 @@ dependencies = [
11
11
  "pypdf[crypto]>=5.0,<7",
12
12
  "pypdfium2>=4.30,<6",
13
13
  "pyside6>=6.8,<7",
14
- "rapidocr==3.10.0",
14
+ "rapidocr[rtl]==3.10.0",
15
15
  "regex>=2024.11.6",
16
16
  ]
17
17
 
@@ -10,7 +10,7 @@ from importlib.resources import files
10
10
  from pathlib import Path
11
11
  from shiboken6 import isValid
12
12
 
13
- from PySide6.QtCore import QEvent, QSettings, QSize, Qt, QThreadPool, QTimer, Slot
13
+ from PySide6.QtCore import QEvent, QPointF, QSettings, QSize, Qt, QThreadPool, QTimer, Slot
14
14
  from PySide6.QtGui import (
15
15
  QCloseEvent,
16
16
  QAction,
@@ -66,6 +66,7 @@ from repdf.search_panel import SearchController
66
66
  from repdf.page_view import PageViewport, PreviewCache
67
67
  from repdf.navigation import NavigationController
68
68
  from repdf.printing import PrintController
69
+ from repdf.ocr_languages import OcrLanguageController
69
70
 
70
71
 
71
72
  class DocumentView(QWidget):
@@ -89,8 +90,10 @@ class DocumentView(QWidget):
89
90
  self.focused_page = None
90
91
  self.page_sizes = {}
91
92
  self.page_links = {}
93
+ self.page_annotations = {}
92
94
  self.page_labels = {}
93
95
  self.bookmarks = None
96
+ self.annotations = None
94
97
  self.ready = False
95
98
  self._search_navigation = None
96
99
  self.password: str | None = None
@@ -177,6 +180,7 @@ class DocumentView(QWidget):
177
180
  self.owner._copy_text_selection(self, index, preview, start, end, copy=False))
178
181
  self.pages.prepare_card(card)
179
182
  card.preview.set_links(self.page_links.get(page_index, []))
183
+ card.preview.set_annotations(self.page_annotations.get(page_index, []))
180
184
  card.preview.link_activated.connect(lambda destination: self.owner.navigation.activate(self, destination))
181
185
  self.pages.chrome = max(1, card.sizeHint().height() - card.preview.height())
182
186
  return card
@@ -383,6 +387,7 @@ class MainWindow(QMainWindow):
383
387
  self._next_generation = 0
384
388
  self._render_documents = {}
385
389
  self._text_requests = {}
390
+ self._ocr_generations = {}
386
391
  self._image_requests = {}
387
392
  self._active_tasks = set()
388
393
  self._load_batches = {}
@@ -714,8 +719,11 @@ class MainWindow(QMainWindow):
714
719
  self.region_ocr_action.setCheckable(True)
715
720
  self.region_ocr_action.setToolTip(tr('區域 OCR:框選頁面或圖片中的區域,放開滑鼠後辨識並複製文字。'))
716
721
  self.region_ocr_action.toggled.connect(self._set_region_ocr_mode)
717
- self.toolbar.addAction(self.region_ocr_action)
722
+ self.ocr_languages = OcrLanguageController(self)
723
+ self.ocr_language_button = self.toolbar.add_action_menu_group(self.region_ocr_action, self.ocr_languages.menu)
718
724
  self.toolbar.widgetForAction(self.region_ocr_action).setObjectName('regionOcrTool')
725
+ self.ocr_language_button.setToolTip(tr('OCR 辨識語言'))
726
+ self.ocr_language_button.setAccessibleName(tr('OCR 辨識語言'))
719
727
  self.extract_image_action = QAction(tr('擷取圖片'), self)
720
728
  self.extract_image_action.setCheckable(True)
721
729
  self.extract_image_action.setEnabled(False)
@@ -729,6 +737,12 @@ class MainWindow(QMainWindow):
729
737
  self.bookmark_action.triggered.connect(lambda: self.navigation.toggle())
730
738
  self.toolbar.addAction(self.bookmark_action)
731
739
  self.toolbar.widgetForAction(self.bookmark_action).setObjectName('bookmarksTool')
740
+ self.annotation_action = QAction(tr('註解'), self)
741
+ self.annotation_action.setCheckable(True)
742
+ self.annotation_action.setToolTip(tr('註解:開啟註解清單,點選即可跳至對應頁面'))
743
+ self.annotation_action.triggered.connect(lambda: self.navigation.toggle('annotations'))
744
+ self.toolbar.addAction(self.annotation_action)
745
+ self.toolbar.widgetForAction(self.annotation_action).setObjectName('annotationsTool')
732
746
  self.search_action = QAction(tr('搜尋文字'), self)
733
747
  self.search_action.setShortcuts(QKeySequence.keyBindings(QKeySequence.StandardKey.Find))
734
748
  self.search_action.setToolTip(tr('搜尋文字({p0}):在右側窗格搜尋目前、勾選或所有標籤頁',
@@ -808,6 +822,8 @@ class MainWindow(QMainWindow):
808
822
  button.setFixedSize(34, 34)
809
823
 
810
824
  def _refresh_toolbar_icons(self) -> None:
825
+ if hasattr(self, 'ocr_language_button'):
826
+ self.ocr_language_button.setIcon(toolbar_icon('chevron_down'))
811
827
  for action, kind in ((self.open_action, "open"), (self.export_action, "export"),
812
828
  (self.split_action, "split"), (self.copy_text_action, "copy_text"),
813
829
  (self.region_ocr_action, "ocr_region"),
@@ -815,6 +831,7 @@ class MainWindow(QMainWindow):
815
831
  (self.search_action, "search"),
816
832
  (self.print_action, "print"),
817
833
  (self.bookmark_action, "bookmarks"),
834
+ (self.annotation_action, "annotations"),
818
835
  (self.fit_action, "fit"),
819
836
  (self.fullscreen_action, "fullscreen"),
820
837
  (self.spread_action, "fullscreen_spread"),
@@ -868,6 +885,7 @@ class MainWindow(QMainWindow):
868
885
  self._update_preference_actions()
869
886
  self.search_controller.retranslate()
870
887
  self.navigation.retranslate()
888
+ self.ocr_languages.refresh()
871
889
 
872
890
  def changeEvent(self, event: QEvent) -> None:
873
891
  super().changeEvent(event)
@@ -930,6 +948,7 @@ class MainWindow(QMainWindow):
930
948
  for label in self._fullscreen_preview.labels.values():
931
949
  label.set_text_mode(enabled, region=region, image=image)
932
950
  self._text_requests.clear()
951
+ self._ocr_generations.clear()
933
952
  self._image_requests.clear()
934
953
 
935
954
  def _copy_text_selection(self, doc, page_index, label, start, end, *, copy=True) -> None:
@@ -950,12 +969,14 @@ class MainWindow(QMainWindow):
950
969
  if document_id == doc.document_id:
951
970
  self._text_requests.pop(previous)
952
971
  self._text_requests[generation] = (doc.document_id, label, copy)
972
+ self._ocr_generations[doc.document_id] = generation
953
973
  self.render_service.request_text(
954
974
  doc.source_path, page_index,
955
975
  (start.x() / label.width(), start.y() / label.height()),
956
976
  (end.x() / label.width(), end.y() / label.height()),
957
977
  generation, -1_000_000 - doc.document_id,
958
978
  allow_ocr=copy, region_ocr=region, password=doc.password,
979
+ ocr_profile=self.ocr_languages.profile,
959
980
  )
960
981
  if copy:
961
982
  self.statusBar().showMessage(tr('正在辨識選取區域…') if region else tr('正在擷取文字…'))
@@ -1305,6 +1326,7 @@ class MainWindow(QMainWindow):
1305
1326
  if document_id == doc.document_id:
1306
1327
  self._render_documents.pop(generation)
1307
1328
  self.documents.pop(doc.document_id, None)
1329
+ self._ocr_generations.pop(doc.document_id, None)
1308
1330
  self.search_controller.remove_document(doc.document_id)
1309
1331
  self.navigation.remove_document(doc)
1310
1332
  self.tabs.removeTab(index)
@@ -1340,6 +1362,19 @@ class MainWindow(QMainWindow):
1340
1362
  if generation in self._text_requests:
1341
1363
  document_id, label, copy = self._text_requests[generation]
1342
1364
  if document_id in self.documents and not self._closing:
1365
+ retry = payload.get('ocr_retry')
1366
+ if payload.get('ocr_model_missing') and copy and retry:
1367
+ def retry_selection(document_id=document_id, label=label, retry=retry, generation=generation):
1368
+ doc = self.documents.get(document_id)
1369
+ if (doc is None or not isValid(label) or self._closing or not label.text_mode
1370
+ or self._ocr_generations.get(document_id) != generation
1371
+ or self.ocr_languages.profile != retry['ocr_profile']
1372
+ or label.region_mode != (retry['type'] == 'ocr_region')):
1373
+ return
1374
+ self._copy_text_selection(doc, retry['page'], label,
1375
+ QPointF(retry['start'][0] * label.width(), retry['start'][1] * label.height()),
1376
+ QPointF(retry['end'][0] * label.width(), retry['end'][1] * label.height()))
1377
+ self.ocr_languages.ensure(retry['ocr_profile'], retry_selection)
1343
1378
  if payload.get('type') == 'ocr' and copy:
1344
1379
  self.statusBar().showMessage(tr('選取文字疑似損壞,正在進行 OCR…'))
1345
1380
  elif payload.get('type') == 'text':
@@ -1478,6 +1513,8 @@ class MainWindow(QMainWindow):
1478
1513
 
1479
1514
  def closeEvent(self, event: QCloseEvent) -> None:
1480
1515
  self._closing = True
1516
+ self.navigation.shutdown()
1517
+ self.ocr_languages.close()
1481
1518
  self.print_controller.close()
1482
1519
  self.search_controller.stop()
1483
1520
  self._password_queue.clear()
@@ -20,7 +20,18 @@ def toolbar_icon(kind: str) -> QIcon:
20
20
  painter.setPen(QPen(QApplication.palette().color(group, role),
21
21
  1.0, Qt.PenStyle.SolidLine, Qt.PenCapStyle.RoundCap,
22
22
  Qt.PenJoinStyle.RoundJoin))
23
- if kind == "more":
23
+ if kind == 'annotations':
24
+ painter.drawPolyline(QPolygonF([QPointF(4, 3), QPointF(21, 3), QPointF(21, 17),
25
+ QPointF(11, 17), QPointF(6, 21), QPointF(6, 17),
26
+ QPointF(4, 17), QPointF(4, 3)]))
27
+ painter.drawLine(8, 8, 17, 8)
28
+ painter.drawLine(8, 12, 15, 12)
29
+ elif kind == 'chevron_down':
30
+ pen = painter.pen()
31
+ pen.setWidthF(2)
32
+ painter.setPen(pen)
33
+ painter.drawPolyline(QPolygonF([QPointF(6, 9), QPointF(12, 15), QPointF(18, 9)]))
34
+ elif kind == "more":
24
35
  painter.setBrush(painter.pen().color())
25
36
  for x in (5, 12, 19):
26
37
  painter.drawEllipse(QRectF(x - 1, 11, 2, 2))