# PDFDirGenerator2 **Repository Path**: iam002/pdfdir-generator2 ## Basic Information - **Project Name**: PDFDirGenerator2 - **Description**: 基于 wxpython 和 PyPDF2 开发的一个简易的 GUI 程序 , 主要功能是给未添加书签的 PDF 添加目录书签。 - **Primary Language**: Python - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2022-10-05 - **Last Updated**: 2022-10-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README - [PDF Dir Generator](#pdf-dir-generator) - [安装必要的模块](#安装必要的模块) - [运行前的准备](#运行前的准备) - [运行命令行](#运行命令行) - [运行 GUI 界面](#运行-gui-界面) - [工程目录说明](#工程目录说明) # PDF Dir Generator **P**DF **D**ir(ectory) **G**enerator,PDF 目录生成器, 是基于 wxpython 和 PyPDF2 开发的一个简易的 GUI 程序,主要功能是给未添加书签的 PDF 添加目录书签。 --- ### 安装必要的模块 首先必须保证 Python 运行版本不低于 3.7, 推荐使用的 Python 版本为 3.9.12. 运行本程序需要使用两个模块: [PyPDF2](https://pypi.org/project/PyPDF2/) 和 [wxpython](https://pypi.org/project/wxPython/), 我们可以通过 `pip` 进行安装. 如果你不需要 GUI 界面,可以只安装 `PyPDF2`. ```bash pip install PyPDF2 pip install wxPython ``` 安装完 PyPDF2 需要对 `_writer.py` 的 `get_outline_roor()` 函数进行修改, 不然运行时可能会如下报错: ```bash File "C:\Users\q2799\.conda\envs\py36\lib\site-packages\PyPDF2\_writer.py", line 1195, in addBookmark title, pagenum, parent, color, bold, italic, fit, *args File "C:\Users\q2799\.conda\envs\py36\lib\site-packages\PyPDF2\_writer.py", line 1174, in add_bookmark parent = self.get_outline_root() File "C:\Users\q2799\.conda\envs\py36\lib\site-packages\PyPDF2\_writer.py", line 1008, in get_outline_root idnum = self._objects.index(outline) + 1 ValueError: {'/Type': '/Outlines', '/First': IndirectObject(1006, 0, 3019818315728), '/Count': 493, '/Last': IndirectObject(1498, 0, 3019818315728)} is not in list ``` 根据报错信息,找到 `_writer.py` 的 `get_outline_roor()` 的位置(不同版本的 PyPDF2 可能的位置不一样),修改如下: ```python def get_outline_root(self) -> TreeObject: if CO.OUTLINES in self._root_object: # TABLE 3.25 Entries in the catalog dictionary outline = cast(TreeObject, self._root_object[CO.OUTLINES]) try: idnum = self._objects.index(outline) + 1 except ValueError: if not isinstance(outline, TreeObject): def _walk(node): node.__class__ = TreeObject for child in node.children(): _walk(child) _walk(outline) outline_ref = self._add_object(outline) self._add_object(outline_ref.get_object()) self._root_object[NameObject('/Outlines')] = outline_ref idnum = self._objects.index(outline) + 1 outline_ref = IndirectObject(idnum, 0, self) assert outline_ref.get_object() == outline else: outline = TreeObject() outline.update({}) outline_ref = self._add_object(outline) self._root_object[NameObject(CO.OUTLINES)] = outline_ref return outline ``` --- ### 运行前的准备 运行之前,推荐先阅读这篇[博客](https://blog.csdn.net/weixin_44252933/article/details/127174469), 在运行之前我们需要准备好: 1. 待添加书签的 PDF 2. 包含书签目录信息的 txt 3. 目录页的偏移页数 `Offset`(一般是目录页的最后一页的页码) --- ### 运行命令行 1. 格式化目录 ```bash python .\dirFormat.py [<-option> ] ``` | 参数 | 选项 | 说明 | |-----------------|------|-------------------| | DIR_INPUT_PATH | 必需参数 | 目录文件的路径 | | DIR_FORMAT_PATH | -o | 格式化目录的输出文件夹 | | DIR_LOG_PATH | -l | 格式化目录文件的输出日志存放文件夹 | | DELIMITER | -d | 单词分隔符 | | PREFIX | -p | 目录文件每行的前缀 | | PRE_LEVEL | -pl | 预定义级别 | | PRE_TITLE | -pt | 预定义标题, 使用 `;` 隔开 | 【**例子**】 ```bash python .\dirFormator.py test/test_dir.txt -pl 2 -pt 参考文献 ``` 输出结果: ```bash ---------------------------- Format Dir ----------------------------------- 运行时间: 2022-10-05 15:45:33 目录源文件路径: test/test_dir.txt 格式化目录路径: 日志路径: 单词分隔符: 级别标志符: . 前缀: 预定义级别: 2 预定义标题: 参考文献 --------------------------------------------------------------------------- [Line 29] 缩略语对照表 395 ==> 无法判断级别信息 [Line 30] 符号表 398 ==> 无法判断级别信息 [Line 31] 参考书目 401 ==> 无法判断级别信息 [Line 32] 索引 415 ==> 无法判断级别信息 --------------------------------------------------------------------------- Dir-log Path : test/test_dir.log Dir format Path : test/test_dir_format.txt ---------------------------------- Done! ---------------------------------- ``` 2. 修改目录 格式程序的同时会进行简单的检查,并输出日志信息. 可以根据这些信息对格式化后的目录进一步的修改. 3. 生成目录 修改完后的目录文件,作为这一步的输入目录文件;同时需要删除待添加书签的 PDF 原先的书签。 然后执行指令: ```bash python .\pdfDirGenerator.py [<-option> ] ``` | 参数 | 选项 | 说明 | |-----------------|------|-------------| | DIR_INPUT_PATH | 必需参数 | 目录文件的路径 | | PDF_INPUT_PATH | 必须参数 | 待添加书签的PDF路径 | | PDF_OUTPUT_PATH | -o | PDF输出目录 | | DELIMITER | -d | 单词分隔符 | | PREFIX | -p | 目录文件每行的前缀 | | OFFSET | -O | 页码偏移量 | 【**例子**】 ```bash python .\pdfDirGenerator.py test\format\pdg_normal_dir.txt test\pdg_test.pdf -O 5 ``` 输出结果: ```bash --------------------------- Adding the bookmark --------------------------- PDF input path: test\pdg_test.pdf PDF output path: Dir path: test\format\pdg_normal_dir.txt Offset: 5 Prefix: Delimiter: --------------------------------------------------------------------------- [ 1/ 23 finished] level: 0, title: 第1章 计算机网络概论, page: 6 [ 2/ 23 finished] level: 1, title: 1.1 计算机网络的形成与发展, page: 6 [ 3/ 23 finished] level: 2, title: 1.1.1 分组交换技术的研究, page: 6 [ 4/ 23 finished] level: 2, title: 1.1.2 互联网的形成, page: 9 [ 5/ 23 finished] level: 2, title: 1.1.3 互联网的高速发展, page: 13 [ 6/ 23 finished] level: 2, title: 1.1.4 移动互联网的发展 , page: 14 [ 7/ 23 finished] level: 1, title: 1.2 计算机网络定义与分类, page: 17 [ 8/ 23 finished] level: 1, title: 1.3 各种类型网络 y 的特点, page: 20 [ 9/ 23 finished] level: 2, title: 1.3.1 广域网, page: 20 [ 10/ 23 finished] level: 2, title: 1.3.2 城域网, page: 23 [ 11/ 23 finished] level: 2, title: 1.3.3 局域网, page: 25 [ 12/ 23 finished] level: 0, title: 小结, page: 26 [ 13/ 23 finished] level: 1, title: 习题, page: 26 [ 14/ 23 finished] level: 0, title: 第2章 物理层, page: 27 [ 18/ 23 finished] level: 1, title: 2.2 数据通信 x 的基本概念 , page: 31 [ 19/ 23 finished] level: 2, title: 2.2.1 测试, page: 32 [ 20/ 23 finished] level: 3, title: 2.2.1.1 测试, page: 33 [ 21/ 23 finished] level: 0, title: 小结, page: 34 [ 22/ 23 finished] level: 1, title: 习题, page: 34 [ 23/ 23 finished] level: 0, title: 附录, page: 35 --------------------------------------------------------------------------- Save: test\pdg_test(书签).pdf ---------------------------------- Done! ---------------------------------- ``` --- ### 运行 GUI 界面 运行 `main.py` 启动 GUI 界面 ``` python .\main.py ``` **演示**
**主界面**
**参数设置**
**参数说明** - **Offset** 页码偏移量,书签对应的页数 = 目录文件的page + offset, 一般这个值等于目录页最后一页所在的页码; - **Prefix** 目录文件每行的前缀, 生成书签时用于判断书签的级别 - **DELIMITER** 单词分隔符, 通常是空格, 不建议修改 - **LEVEL_MARKER** 级别标志符, 格式化书签时用于判断书签的级别 - **Pre-level** 预定义级别 - **Pre-title** 预定义标题, 注意使用“;”隔开,不要有多余的空格 - **PDF Output Path** PDF输出目录, 留空会根据输入PDF名自动生成 - **Dir-Log Path** 格式化目录文件的输出日志存放文件夹目录,留空则与原目录在同一文件夹 - **Dir-format Path** 格式化目录的输出文件夹,留空则与原目录在同一文件夹 这里通常需要设置的是 **Offset** 以及 **Pre-title**,设置完成后记得点击 `Finish`。 除了这种设置方式外,还支持直接导入配置文件(文件后缀名为 `.conf`):
**配置文件** ```python ########################################################################### # # 这是一个配置文件, 以行为基本单元, 可以分为注释行, 赋值行和空行. # # 注释行以字符 '#' 开头, 程序会忽略以'#'开头的行; 行首直接回车,则是空行; 注释行 # 和空行可以提高配置文件的可读性. # # 赋值行的格式为: 字段名 = 值: # 1. "值"可以修改, 但不要修改"字段名"; # 2. "="两边的空格可有可无, 数量没有限制; # ########################################################################### # str, 待添加书签的PDF路径 PDF_INPUT_PATH = "C:\Users\q2799\Project\PDFDirGenerator2\test\pdg_test.pdf" # str, 目录文件的路径 DIR_INPUT_PATH = "C:\Users\q2799\Project\PDFDirGenerator2\test\pdg_normal_dir.txt" # int, 页码偏移量, 通常是PDF目录页最后一页的页码 OFFSET = 5 # char, 目录文件每行的前缀, 生成书签时用于判断书签的级别 PREFIX = "\t" # char, 单词分隔符, 通常是空格, 不建议修改 DELIMITER = " " # char, 级别标志符, 格式化书签时用于判断书签的级别 LEVEL_MARKER = "." # int, 预定义级别 PRE_LEVEL = 2 # str, 预定义标题, 使用';'隔开 PRE_TITLE = "本章小结;习题" # str, 格式化目录文件的输出日志存放文件夹,留空则与原目录在同一文件夹 DIR_LOG_PATH = "C:\Users\q2799\Project\PDFDirGenerator2\test\log" # str, 格式化目录的输出文件夹,留空则与原目录在同一文件夹 DIR_FORMAT_PATH = "C:\Users\q2799\Project\PDFDirGenerator2\test\format" # PDF输出目录, 留空会根据输入PDF名自动生成 PDF_OUTPUT_PATH = "C:\Users\q2799\Project\PDFDirGenerator2\test\outpdf" # int, 是否只显示目录日志 IS_PRINT_ACTICE_ONLY = 0 # int, 生成日志前默认先进行格式化 IS_FORMAT_DIR_FIRST = 1 # int, 是否打印生成书签过程中的信息 IS_PRINT_PROCESS = 1 ``` ### 工程目录说明 - `dirFormator.py` 格式化目录脚本 - `pdfDirGenerator` PDF 目录生成脚本 - `main.py` GUI 运行脚本 - `utils.py` 存放一些公共函数和全局变量 - `wxb_*.py` 通过 [wxFormBuilder](https://github.com/wxFormBuilder/wxFormBuilder) 自动生成的脚本(用于图像界面的设计) - `mainFrame.py` 主窗口 - `runningDialog.py` 运行弹窗 - `settingsDialog.py` 设置弹窗 - `aboutDialog` 关于弹窗 - `assets\` 存放一些图片等附件 - `design_gui\` 存放 [wxFormBuilder](https://github.com/wxFormBuilder/wxFormBuilder) 工程文件,可用 [wxFormBuilder](https://github.com/wxFormBuilder/wxFormBuilder) 打开 - `test\` 存放一些测试数据 - `conf\` 包含一个配置文件 `pdg_settings.conf` - `format\` 包含一个格式化目录 `pdg_normal_dir.txt` - `log\` 包含格式化目录的日志信息 `pdg_normal_dir.log` - `outpdf\` 存放运行结果 `pdg_test(书签).pdf` - `pdg_test.pdf` 测试 PDF - `*_dir.txt` 测试目录文件 ```Tree PDFDirGenerator2 ├─ aboutDialog.py ├─ assets ├─ blog.md ├─ design_gui │ ├─ noname.cpp │ ├─ noname.h │ └─ pdg2.fbp ├─ dirFormator.py ├─ main.py ├─ mainFrame.py ├─ pdfDirGenerator.py ├─ README.md ├─ runningDialog.py ├─ settingsDialog.py ├─ test │ ├─ conf │ │ └─ pdg_settings.conf │ ├─ format │ │ └─ pdg_normal_dir.txt │ ├─ log │ │ └─ pdg_normal_dir.log │ ├─ outpdf │ │ └─ pdg_test(书签).pdf │ ├─ pdg_invalidnum_dir.txt │ ├─ pdg_normal_dir.txt │ ├─ pdg_test.pdf │ └─ test_dir.txt ├─ utils.py ├─ wxb_mainFrame.py ├─ wxb_runningDialog.py └─ wxb_settingsDialog.py