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.
- {repdf-0.1.0 → repdf-0.1.2}/PKG-INFO +24 -6
- {repdf-0.1.0 → repdf-0.1.2}/README.md +22 -4
- {repdf-0.1.0 → repdf-0.1.2}/pyproject.toml +2 -2
- {repdf-0.1.0 → repdf-0.1.2}/pyproject.toml.orig +2 -2
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/app.py +39 -2
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/icons.py +12 -1
- repdf-0.1.2/src/repdf/navigation.py +397 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/ocr.py +112 -24
- repdf-0.1.2/src/repdf/ocr_languages.py +219 -0
- repdf-0.1.2/src/repdf/ocr_models.py +82 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/packaging_smoke.py +39 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/page_view.py +14 -0
- repdf-0.1.2/src/repdf/pdf_annotations.py +92 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/pdf_navigation.py +8 -1
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/preview.py +4 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/render_worker.py +33 -8
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/renderer.py +4 -2
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/strings.py +54 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/theme.py +8 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/toolbar.py +39 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/widgets.py +26 -2
- repdf-0.1.0/src/repdf/navigation.py +0 -235
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/__init__.py +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/__main__.py +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/assets/check-dark.svg +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/assets/check.svg +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/assets/partial-dark.svg +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/assets/partial.svg +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/assets/repdf.ico +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/assets/repdf.png +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/core.py +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/entrypoint.py +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/images.py +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/preferences.py +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/print_preview.py +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/printing.py +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/search.py +0 -0
- {repdf-0.1.0 → repdf-0.1.2}/src/repdf/search_panel.py +0 -0
- {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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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 ==
|
|
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))
|