Skip to content

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Latest commit

 

History

21 Commits

Folders and files

Repository files navigation

Bookmarkify - PDF 自动书签工具

一键为扫描版/文字版 PDF 添加目录书签的跨平台桌面工具。

版本: v1.2.0 | 平台: macOS / Windows | 语言: Python 3.10+ | 许可: MIT

使用Claude Code构建


功能特性

  • 便于使用: 选择 PDF → 编辑目录 → 生成书签
  • 自动识别目录: 文字版 PDF 直接提取文字识别;扫描版 PDF 通过 MinerU OCR 识别
  • 灵活编辑: 支持层级目录(Tab 缩进)、撤销/重做、查找替换、语法高亮
  • 页码偏移: 识别到的目录页码可自动匹配 PDF 实际页码
  • 多级书签: 支持无限层级嵌套书签
  • 暗色/亮色主题: 自动跟随系统主题,可手动切换
  • 加密 PDF 处理支持: 输入密码后可处理加密文件(不修改原密码)
  • 跨平台: macOS 和 Windows 原生体验

安装与运行

方式一:从源码运行

# 1. 克隆项目
git clone <repo-url>
cd Bookmarkify-main

# 2. 创建虚拟环境
python3 -m venv .venv
source .venv/bin/activate  # macOS
# .venv\Scripts\activate   # Windows

# 3. 安装依赖
pip install -r requirements.txt

# 4. 运行
python main.py

# 可选:直接打开指定 PDF
python main.py /path/to/file.pdf

方式二:运行打包版本

下载 Release 页面中的 .dmg(macOS)或 .exe(Windows),直接安装/运行。


使用指南

完整工作流

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│  第一步          │    │  第二步          │    │  第三步          │
│  选择 PDF 文件   │ -> │  编辑目录        │ -> │  设置偏移并生成  │
│                 │    │                 │    │                 │
│  · 浏览文件      │    │  · 编辑书签条目   │    │  · 页码偏移      │
│  · 设置目录页范围 │    │  · 调整层级      │    │  · 输出路径      │
│  · 选择识别方式   │    │  · 查找替换      │    │  · 开始生成      │
│  · 自动/手动输入  │    │  · 导入/导出     │    │                 │
└─────────────────┘    └─────────────────┘    └─────────────────┘

手动输入目录

第一章 绪论@@1
	第一节 研究背景@@3
	第二节 研究方法@@8
第二章 理论基础@@12
	第一节 基本概念@@12
		一、定义与分类@@15
  • 使用 Tab 缩进表示层级关系
  • 标题与页码之间用 @@ 分隔
  • 支持无限层级嵌套

自动识别目录

  1. 选择 PDF 文件后,工具会自动检测文件类型(文字版/扫描版)
  2. 设置目录所在页码范围
  3. 点击「开始识别」
    • 文字版 PDF: 直接从 PDF 中提取文字并解析
    • 扫描版 PDF: 调用 MinerU Cloud API 进行 OCR 识别
      • Flash 模式: 免费,适用于 ≤20 页、≤10MB 的文件
      • 精准模式: 需要从 mineru.net 获取 API Token

⚠️ 注意: 使用 OCR 识别前请关闭代理工具(如 Clash、V2Ray 等)并关闭系统代理,避免 SSL 连接错误。


项目结构

main/
├── main.py                    # 应用入口
├── requirements.txt           # Python 依赖
├── build.spec                 # PyInstaller 打包配置
├── build.sh                   # macOS 构建脚本
├── build.bat                  # Windows 构建脚本
├── scripts/
│   └── generate_icon.py       # 应用图标生成脚本
└── app/
    ├── assets/                # 图标资源(PNG / ICNS / ICO)
    ├── core/                  # 核心业务逻辑
    │   ├── toc_parser.py      # 目录解析与序列化
    │   ├── pdf_ops.py         # PDF 操作封装(PyMuPDF)
    │   ├── mineru_client.py   # MinerU OCR API 客户端
    │   └── toc_auto.py        # 自动目录识别
    ├── gui/                   # 图形界面组件
    │   ├── main_window.py     # 主窗口(工作流协调器)
    │   ├── file_panel.py      # 第一步:文件选择面板
    │   ├── toc_editor.py      # 第二步:目录编辑器
    │   ├── offset_panel.py    # 第三步:偏移与生成面板
    │   ├── find_replace.py    # 查找/替换对话框
    │   └── progress_dialog.py # OCR 进度对话框
    └── utils/                 # 工具模块
        ├── constants.py       # UI 字符串常量(中文)
        ├── config.py          # 持久化配置管理
        └── theme_manager.py   # 主题管理器(暗色/亮色)

架构说明

整体架构

应用采用 三层架构,清晰分离界面、业务逻辑和工具模块:

┌──────────────────────────────────────────────────┐
│                    GUI (app/gui/)                 │
│  MainWindow · FilePanel · TOCEditor · OffsetPanel│
├──────────────────────────────────────────────────┤
│                   Core (app/core/)                │
│  toc_parser · pdf_ops · mineru_client · toc_auto │
├──────────────────────────────────────────────────┤
│                  Utils (app/utils/)               │
│  constants · config · theme_manager              │
└──────────────────────────────────────────────────┘
  • GUI 层不直接调用 fitz/mineru_sdk,全部通过 Core 层中转
  • Core 层为纯逻辑,无 GUI 依赖,可独立测试
  • Utils 层提供跨模块共享的配置、主题和常量

入口函数与启动流程

文件 入口/关键函数 职责
main.py main() 应用启动入口:日志初始化、主题检测、窗口创建、事件循环
main.py get_asset_path() 资源路径解析(兼容开发与 PyInstaller 打包)
app/gui/main_window.py MainWindow.__init__() 主窗口初始化:三步面板创建、菜单栏、状态栏、信号连接
app/gui/main_window.py MainWindow._open_pdf() PDF 打开流程:检测加密、判断类型、提取已有目录
app/gui/main_window.py MainWindow._on_recognize() 识别触发:启动后台 OCR 线程
app/gui/main_window.py MainWindow._on_generate() 生成触发:应用偏移、写入书签、保存 PDF
app/gui/main_window.py MainWindow._auto_detect_offset() 自动偏移:搜索第一条目录标题在 PDF 中的位置

Core 层模块详解

toc_parser.py — 目录解析器

text ──► parse_toc_text() ──► [TOCEntry, ...] ──► toc_to_text() ──► text
                                     │
                              validate_toc() ──► 警告列表
                                     │
                     format_toc_with_offset() ──► PyMuPDF TOC 格式
函数 说明
parse_toc_text(text) 将 Tab 缩进文本解析为 TOCEntry 列表
toc_to_text(entries) 将 TOCEntry 列表序列化为文本
validate_toc(entries) 验证目录合法性(空标题、无效页码)
format_toc_with_offset(entries, offset, total) 应用页码偏移,输出 PyMuPDF 兼容格式

pdf_ops.py — PDF 操作封装

函数 说明
open_pdf(path, password) 打开 PDF(自动处理加密)
create_decrypted_copy(doc) 创建解密临时副本
get_page_count(doc) 获取总页数
detect_pdf_type(doc) 检测 PDF 类型("scanned" / "text")
get_existing_toc(doc) 读取已有书签
add_bookmarks(doc, toc_list, output_path) 写入书签并保存
search_text_in_pages(doc, text, ...) 在页面范围内搜索文字

mineru_client.py — MinerU OCR 客户端

函数 说明
check_mineru_available() 检查 SDK 是否已安装
flash_extract(pdf_path) 免费 OCR(≤20 页,≤10MB),自动重试
precision_extract(pdf_path, api_token) 付费 OCR(需 API Token)
extract_toc_pages(pdf_path, api_token, start, end) 提取目录页 → OCR 识别

toc_auto.py — 自动目录识别

函数 说明
auto_recognize(doc, ...) 调度入口:根据 PDF 类型分发
_recognize_text_pdf(doc, start, end) 文字版 PDF 目录提取
_recognize_scanned_pdf(pdf_path, ...) 扫描版 PDF 调用 OCR
_parse_markdown_toc(markdown) OCR 结果 → 目录文本
_parse_line(content) 单行解析(支持多种格式)

GUI 层组件详解

main_window.py — 主窗口(工作流协调器)

MainWindow 是所有 GUI 组件的容器和协调器。它:

  • 拥有 fitz.Document 对象,控制 PDF 生命周期
  • 管理三个步骤面板的创建和信号连接
  • 通过线程 + 操作 ID 机制管理后台 OCR,防止过期回调
  • 协调自动偏移检测(识别完成后自动触发)
  • 提供菜单栏(文件、设置、帮助)和状态栏

关键属性:

  • doc — 当前打开的 fitz.Document(None 表示未打开)
  • _ocr_op_id — OCR 操作 ID,每次新识别递增,回调中校验以丢弃过期结果
  • _decrypted_temp_path — 加密 PDF 解密后的临时文件路径

关键设计:

  • 后台 OCR 使用 threading.Thread(target=..., daemon=True) 启动
  • 回调通过 root.after(0, callback) 回到主线程更新 UI
  • 操作 ID 机制确保多次快速点击识别时,只有最后一次的结果生效

file_panel.py — 文件选择面板

  • 可折叠的 ttk.LabelFrame,折叠时显示摘要
  • 文件浏览(记忆上次目录)
  • PDF 类型自动检测 + 用户可覆盖
  • 页码范围选择(Spinbox)
  • 手动/自动模式切换
  • OCR 模式选择(Flash / 精准)
  • API Token 输入(带显示/隐藏切换)

toc_editor.py — 目录编辑器

核心编辑组件,提供:

  • 工具栏: 提升/降低层级、撤销/重做、查找替换、导入/导出
  • 文本编辑器: 基于 tk.Text,支持撤销/重做栈、等宽字体
  • 语法高亮: 4 级标题颜色区分 + 页码高亮,200ms 防抖更新
  • 状态栏: 书签计数、最大层级、验证警告
  • 主题感知: 注册为 ThemeManager 观察者,主题切换时实时更新配色
  • 占位文本: 未聚焦时显示格式提示

offset_panel.py — 偏移与生成面板

  • 联动 Spinbox:左侧为目录页码,右侧为 PDF 实际页码
  • 实时计算并显示偏移量
  • 输出路径浏览
  • 「覆盖原文件」复选框
  • 「开始添加书签」按钮

find_replace.py — 查找替换对话框

  • 支持区分大小写和正则表达式
  • 查找下一个 / 替换 / 全部替换
  • 到末尾自动回到开头继续搜索
  • 关闭时清除高亮

progress_dialog.py — OCR 进度对话框

  • 模态对话框,OCR 期间阻止交互
  • 5 阶段进度:初始化 → 上传 → 处理 → 下载 → 解析
  • Unicode 盲文字符旋转动画
  • 取消按钮可终止 OCR
  • 完成后 800ms 自动关闭

Utils 层详解

constants.py — UI 字符串常量

所有用户可见的中文字符串集中定义在此,便于:

  • 国际化改造(替换常量文件即可)
  • 文案统一修改
  • 避免硬编码字符串散落各处

config.py — 持久化配置

  • 存储位置: ~/.pdf_bookmark_config.json
  • 当前配置项: last_directory, mineru_api_token, ocr_mode, window_width, window_height, default_offset
  • 每次 set() 自动写入磁盘
  • 损坏文件自动降级(重置为默认值)

theme_manager.py — 主题管理器

  • 单例模式: 全局唯一实例
  • 系统检测: 使用 darkdetect 监听系统主题变化
  • 配色方案: Catppuccin Mocha 风格暗色主题 + 专业亮色主题
  • 配色项目: 文本背景/前景、4 级标题色、页码色、警告色、匹配高亮色
  • 观察者模式: 组件可注册回调,主题切换时自动通知更新

使用方式:

tm = ThemeManager()
tm.register_observer(my_callback)  # 注册观察者
tm.toggle_theme()                   # 切换主题

开发与维护

环境要求

运行与调试

# 开发模式运行
python main.py

# 查看日志
tail -f ~/.pdf_bookmark_tool.log

# 查看配置文件
cat ~/.pdf_bookmark_config.json

日志

日志文件位于 ~/.pdf_bookmark_tool.log,记录 DEBUG 级别日志。控制台仅输出 WARNING 及以上级别。

打包发布

macOS

bash build.sh              # 基础打包
bash build.sh --sign "Developer ID"  # 带签名
bash build.sh --dmg        # 打包 DMG
bash build.sh --sign "ID" --dmg  # 签名 + DMG

Windows

build.bat

打包配置参见 build.spec,已排除 numpy、scipy、pandas、PyQt、torch 等大型库以减小体积。

关键设计决策

决策 理由
@@ 作为目录分隔符 比传统 PdgCntEditor 的 Tab 分隔格式更直观、不易混淆
PyMuPDF (fitz) 而非 PyPDF2 更好的性能、加密 PDF 支持、书签读写 API
ttkbootstrap 而非 PyQt 更轻量、打包体积小、对 tkinter 生态友好
MinerU Cloud API 而非本地 OCR 免去大型 OCR 模型部署,降低使用门槛
操作 ID 机制 防止快速点击识别时过期结果覆盖新结果
加密 PDF 解密副本 避免要求用户提供原始密码进行保存操作
单例 ThemeManager + 观察者 全局主题统一管理,组件自动响应切换

添加新功能的指南

  1. 添加新的 UI 字符串: 在 constants.py 中添加,不要硬编码到 GUI 文件
  2. 添加新的 PDF 操作: 在 pdf_ops.py 中添加,不要直接在 GUI 层调用 fitz
  3. 添加新配置项: 在 config.py 的 DEFAULTS 字典中添加
  4. 添加新主题颜色: 在 theme_manager.py 的 dark_colors/light_colors 中添加
  5. GUI 组件开发: 继承 ttk 控件,通过 ThemeManager 获取主题色,通过 Config 读写持久化设置

常见问题

Q: OCR 识别失败,提示 SSL 错误?
A: 关闭系统代理和代理工具(Clash、V2Ray 等)。这是 macOS + Python 3.14 + OpenSSL 3.6 0-RTT 模式下的已知兼容性问题。

Q: 识别结果不准确?
A: 尝试缩小目录页码范围,确保只包含目录页。扫描版 PDF 的质量也会影响 OCR 准确度。

Q: 加密 PDF 如何处理?
A: 工具会弹出密码输入框,输入正确密码后会创建解密临时副本进行操作,原文件不会被修改。


技术栈

组件 技术
语言 Python 3.10+
GUI 框架 tkinter + ttkbootstrap
PDF 处理 PyMuPDF (fitz)
OCR 引擎 MinerU Cloud API
图片处理 Pillow (PIL)
系统主题检测 darkdetect
打包 PyInstaller

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages