news 2026/10/8 3:54:21

Windows下编译pdf2htmlex实现PDF转HTML中文完美支持

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Windows下编译pdf2htmlex实现PDF转HTML中文完美支持

简介:本资源为Windows平台专用的PDF2HTMLEx开源工具完整安装包,面向开发者、技术文档工程师及需将PDF在线发布的教育/企业用户,解决PDF文档难以在网页端保持排版 fidelity 与交互性的核心问题。压缩包共22个文件,7.1MB,含核心可执行文件pdf2htmlEX.exe、多套CSS样式(base.min.css/fancy.css等)与JS脚本(pdf2htmlEX.min.js/compatibility.min.js),支撑HTML渲染与主题定制;另含LICENSE、README.md、ChangeLog、AUTHORS等开源元信息文件及build_sh构建脚本,体现完整工程结构。已有637人学习下载,开箱即用,无需编译——直接运行exe或调用命令行即可完成PDF到高保真、可选文本、带书签与超链接的HTML转换,同时支持图片分离导出与参数自定义,适配学术论文、技术手册、课件等复杂PDF内容的网页化部署需求。

1. Windows 版 pdf2htmlex:不是“装个exe就完事”的PDF转HTML工具,而是要亲手编译、绕过MSVC版本锁、处理中文字体嵌入失败的黑匣子

你搜“windows pdf2htmlex”,十有八九点进的是 GitHub 上那个早已归档(archived)的官方仓库,或者某个年份模糊的第三方打包版。但真正用过的人知道:它根本不是“下载安装包双击运行”那种工具——你在 Windows 上跑pdf2htmlEX.exe --help,可能连基础参数都报错;生成的 HTML 页面中文乱码、公式错位、页眉页脚消失、目录链接全断;更别说用 Python 脚本批量调用时,进程莫名卡死、临时文件残留满 C 盘、甚至触发 Windows Defender 误报。这不是软件不行,而是 pdf2htmlex 本质是一个重度依赖底层图形栈(Poppler + Cairo + Fontconfig + FreeType)的命令行转换器,在 Linux 上靠 apt 一键拉齐依赖链,在 Windows 上却要你手动拼凑 MSVC 运行时、静态链接 Cairo、硬编码字体路径、甚至 patch 源码才能让中文字体正确 subset 嵌入。它适合三类人:需要把 PDF 手册/论文/技术文档转成可搜索、可响应式、带目录锚点的 Web 页面的文档工程师;要集成进 CI/CD 流水线做自动化文档发布的技术 writer;以及正在为老旧 PDF 文档做无障碍改造(WCAG 2.1 合规)的前端团队。如果你只是想“快速转一个 PDF”,用 Edge 打印为 HTML 或在线转换网站更省心;但如果你要可控、可复现、可嵌入自定义 CSS、支持中文宋体/思源黑体/方正书宋且不漏字——那 pdf2htmlex 是目前 Windows 下唯一能扛住 500 页带矢量图+数学公式的 PDF 的开源方案。下面,我带你从零编译、配置、调参、排坑,全程基于 VS2022 + Windows 10/11 x64,不依赖任何“绿色版”或“免安装包”。


2. 编译前必须搞清的四层依赖关系:为什么不能直接下 release 包,而要自己拉源码+选对 MSVC 工具链

pdf2htmlex 在 Windows 上的编译不是“cmake && make”那么简单。它的构建链条像俄罗斯套娃:最外层是 pdf2htmlex 自身(C++),但它重度依赖 Poppler(PDF 解析)、Cairo(矢量渲染)、Fontconfig(字体发现)、FreeType(字体解析)、libpng / zlib(图像解码)。而这些库在 Windows 上没有统一包管理器(不像 Ubuntu 的 apt),每个库又各自有编译约束。比如:

  • Poppler 必须用 MSVC 编译,且版本需与 pdf2htmlex commit hash 对齐:官方 repo 的master分支已停更,但dev分支仍活跃;2023 年后多数 PR 都要求 Poppler ≥ 22.12.0,否则TextPage::visit()会 segfault;
  • Cairo 必须静态链接,且禁用 Win32 backend:Windows 默认的cairo-win32backend 不支持 PDF 输出流重定向,会导致--embed-external-font失效;必须强制用cairo-png+cairo-pdf组合,并通过-DCAIRO_HAS_WIN32_SURFACE=OFF关闭;
  • Fontconfig 在 Windows 上几乎不可用:它依赖 Unix-like 的/etc/fonts/fonts.conf和fc-cache,Windows 无对应机制;实际做法是完全绕过 Fontconfig,改用硬编码字体路径 + FreeType 直接加载,这也是中文支持的关键突破口;
  • MSVC 工具链版本决定一切:VS2019 编译的库无法被 VS2022 项目链接(CRT ABI 不兼容);而 pdf2htmlex 官方 CMakeLists.txt 默认只适配 VS2017;必须手动修改CMakeLists.txt中的CMAKE_GENERATOR_TOOLSET和CMAKE_MSVC_RUNTIME_LIBRARY。

提示:不要尝试用 vcpkg 或 conan 安装 pdf2htmlex —— 它们的 portfile 均已过期(vcpkg 最新版仍指向 2021 年的 commit),且默认关闭了--enable-cid-fonts,导致中文字体 CID 映射失败,生成 HTML 后所有汉字变方框。

2.1 下载并验证四个核心源码仓库的 commit 兼容性

我们采用“锁定 commit + 子模块嵌套”方式确保可复现。以下组合经实测(Windows 10 22H2 + VS2022 17.8.4)稳定运行:

库名推荐仓库推荐 commit关键 patch 是否需手动应用
pdf2htmlexhttps://github.com/coolwanglu/pdf2htmlexa3e7b8c(2023-09-15)否(该 commit 已合并 CID font fix)
popplerhttps://gitlab.freedesktop.org/poppler/popplerd4f9a21(poppler-23.08.0 tag)否(但需在 cmake 时加-DENABLE_ZLIB=ON -DENABLE_LIBPNG=ON)
cairohttps://gitlab.freedesktop.org/cairo/cairob8c1d0f(1.18.0 tag)是(需 patchsrc/cairo-ft-font.c第 1234 行,将FT_Set_Char_Size改为FT_Set_Pixel_Sizes,否则小字号汉字模糊)
freetypehttps://gitlab.freedesktop.org/freetype/freetypee9f7b5a(freetype-2.13.2 tag)否
# 创建工作目录 mkdir pdf2html-win-build && cd pdf2html-win-build # 克隆主项目(含子模块声明) git clone https://github.com/coolwanglu/pdf2htmlex.git cd pdf2htmlex # 初始化并更新子模块(注意:官方子模块指向旧版 poppler,需手动切) git submodule update --init --recursive # 切换 poppler 子模块到兼容 commit cd thirdparty/poppler git fetch origin d4f9a21 git checkout d4f9a21 cd ../.. # 切换 cairo 子模块(官方未包含,需手动添加) cd thirdparty git clone https://gitlab.freedesktop.org/cairo/cairo.git cd cairo git checkout b8c1d0f # 应用 freetype 渲染 patch(见下节) cd ../..

2.2 用 VS2022 Developer Command Prompt 编译 Cairo(关键:禁用 win32 backend)

Cairo 是整个链条中最易翻车的一环。Windows 下默认启用win32surface,但 pdf2htmlex 需要pdf+pngsurface 来生成内联 base64 图片和矢量文本。必须彻底禁用 win32。

# 在 VS2022 Developer Command Prompt 中执行(非普通 cmd!) cd thirdparty/cairo # 创建构建目录 mkdir build && cd build # 配置 CMake(重点参数:禁用 win32,强制静态链接,指定 freetype 路径) cmake -G "Visual Studio 17 2022" ^ -A x64 ^ -DCMAKE_BUILD_TYPE=Release ^ -DCAIRO_HAS_WIN32_SURFACE=OFF ^ -DCAIRO_HAS_QUARTZ_SURFACE=OFF ^ -DCAIRO_HAS_QUARTZ_FONT=OFF ^ -DCAIRO_HAS_FC_FONT=OFF ^ # 关键!禁用 fontconfig -DCAIRO_HAS_FT_FONT=ON ^ -DFREETYPE_INCLUDE_DIRS="C:/path/to/freetype/include" ^ -DFREETYPE_LIBRARY="C:/path/to/freetype/lib/freetype.lib" ^ -DCMAKE_MSVC_RUNTIME_LIBRARY="MultiThreaded$<$<CONFIG:Debug>:Debug>" ^ .. # 编译(/m:4 表示 4 线程,避免内存溢出) cmake --build . --config Release --target install --parallel 4

参数说明:-DCAIRO_HAS_FC_FONT=OFF强制 Cairo 不调用 Fontconfig,转而由 pdf2htmlex 自己通过 FreeType 加载字体;CMAKE_MSVC_RUNTIME_LIBRARY="MultiThreaded"确保生成静态 CRT 链接的.lib,避免部署时缺vcruntime140.dll;--parallel 4是必须项,Cairo 编译单线程耗时超 25 分钟且常因内存不足中断。

2.3 编译 Poppler:必须开启 CID 字体支持,否则中文 PDF 直接变空白

Poppler 是 PDF 解析引擎,对中文支持取决于是否启用 CID 字体(Chinese Ideographic Dictionary)。Windows 下默认关闭,必须显式打开。

cd ../poppler mkdir build && cd build cmake -G "Visual Studio 17 2022" ^ -A x64 ^ -DCMAKE_BUILD_TYPE=Release ^ -DBUILD_GLIB=OFF ^ -DBUILD_QT5=OFF ^ -DBUILD_QT6=OFF ^ -DENABLE_ZLIB=ON ^ -DENABLE_LIBPNG=ON ^ -DENABLE_CMS=OFF ^ -DENABLE_DCTDECODER=ON ^ -DENABLE_JPEG=ON ^ -DENABLE_TIFF=ON ^ -DENABLE_CID_FONT=ON ^ # 关键!没有它,中文字符不解析 -DENABLE_UNSTABLE_API_ABI_HEADERS=ON ^ -DFREETYPE_INCLUDE_DIRS="C:/path/to/freetype/include" ^ -DFREETYPE_LIBRARY="C:/path/to/freetype/lib/freetype.lib" ^ -DCMAKE_INSTALL_PREFIX="C:/opt/poppler" ^ .. cmake --build . --config Release --target install --parallel 4

注意:-DENABLE_CID_FONT=ON是中文支持的生命线。若遗漏,pdf2htmlex 会跳过所有 CID 字符(即绝大多数 GB2312/GBK 编码的 PDF),输出 HTML 中<span class="c1"></span>占位符。实测某国标 PDF(GB/T 1.1-2020)在未开启此选项时,正文识别率为 0%;开启后达 99.2%(漏字仅出现在极少数嵌入 Type3 字体的扫描件中)。


3. 编译 pdf2htmlex 主程序:修改 CMakeLists.txt 绕过 Fontconfig,硬编码中文字体路径

pdf2htmlex 官方 CMakeLists.txt 默认启用 Fontconfig 查找字体,这在 Windows 上必然失败(找不到fonts.conf)。我们必须将其改为“FreeType 直接加载字体文件”模式,并指定宋体、黑体、楷体的绝对路径。这是让中文正常显示的最后也是最关键一步。

3.1 修改CMakeLists.txt:关闭 Fontconfig,启用 FreeType 字体加载

打开pdf2htmlex/CMakeLists.txt,定位到find_package(Fontconfig REQUIRED)行(通常在第 120 行左右),整段注释掉:

# find_package(Fontconfig REQUIRED) # include_directories(${FONTCONFIG_INCLUDE_DIRS}) # link_directories(${FONTCONFIG_LIBRARY_DIRS}) # set(PDF2HTMLEX_LIBS ${PDF2HTMLEX_LIBS} ${FONTCONFIG_LIBRARIES})

然后在include_directories(...)后添加 FreeType 包含路径:

# Add FreeType includes explicitly include_directories("C:/path/to/freetype/include") include_directories("C:/path/to/freetype/include/freetype") include_directories("C:/path/to/freetype/include/freetype/config")

再找到target_link_libraries(pdf2htmlEX ...)行,在末尾追加 FreeType 库:

target_link_libraries(pdf2htmlEX ... ${FREETYPE_LIBRARY} ${CAIRO_LIBRARY} ${POPPLER_LIBRARY} )

3.2 修改src/utils/font_utils.cc:实现 Windows 字体硬编码加载

原版代码依赖 Fontconfig 的FcFontSetSort查找字体。我们要替换为 Windows API + FreeType 直接加载:

// src/utils/font_utils.cc 第 45 行附近,替换整个 load_font() 函数 #include <ft2build.h> #include FT_FREETYPE_H #include FT_GLYPH_H // 全局字体映射表(Windows 路径) static const std::map<std::string, std::string> WINDOWS_FONT_MAP = { {"SimSun", "C:/Windows/Fonts/simsun.ttc"}, // 宋体 {"NSimSun", "C:/Windows/Fonts/simfang.ttf"}, // 新宋体 {"SimHei", "C:/Windows/Fonts/simhei.ttf"}, // 黑体 {"KaiTi", "C:/Windows/Fonts/kaiu.ttf"}, // 楷体 {"Microsoft YaHei", "C:/Windows/Fonts/msyh.ttc"} // 微软雅黑 }; bool load_font(const std::string& font_name, FT_Face* face) { auto it = WINDOWS_FONT_MAP.find(font_name); if (it == WINDOWS_FONT_MAP.end()) { fprintf(stderr, "Warning: font '%s' not found in Windows font map\n", font_name.c_str()); return false; } FT_Error error = FT_New_Face(*library, it->second.c_str(), 0, face); if (error) { fprintf(stderr, "Error loading font %s: %s\n", it->second.c_str(), error == FT_Err_Unknown_File_Format ? "unsupported font format" : "other error"); return false; } return true; }

逻辑说明:该函数不再调用FcFontSetSort,而是查表获取 Windows 系统字体路径,用 FreeTypeFT_New_Face直接加载。simsun.ttc是宋体 TTC 合集(含 Regular/Bold/Italic),simhei.ttf是黑体 TrueType;路径必须用正斜杠/(Windows API 兼容),且确保字体文件真实存在(可通过dir C:\Windows\Fonts\*.ttc验证)。

3.3 构建并安装 pdf2htmlex

cd ../.. # 回到 pdf2htmlex 根目录 mkdir build && cd build cmake -G "Visual Studio 17 2022" ^ -A x64 ^ -DCMAKE_BUILD_TYPE=Release ^ -DCMAKE_INSTALL_PREFIX="C:/opt/pdf2htmlEX" ^ -DPOPPLER_INCLUDE_DIR="C:/opt/poppler/include" ^ -DPOPPLER_LIBRARY="C:/opt/poppler/lib/poppler.lib" ^ -DCAIRO_INCLUDE_DIR="C:/opt/cairo/include" ^ -DCAIRO_LIBRARY="C:/opt/cairo/lib/cairo.lib" ^ -DFREETYPE_INCLUDE_DIR="C:/path/to/freetype/include" ^ -DFREETYPE_LIBRARY="C:/path/to/freetype/lib/freetype.lib" ^ .. cmake --build . --config Release --target install --parallel 4

成功后,C:/opt/pdf2htmlEX/bin/pdf2htmlEX.exe即为可用二进制。验证:

C:/opt/pdf2htmlEX/bin/pdf2htmlEX.exe --version # 输出应为:pdf2htmlEX 0.18.10-dev (a3e7b8c)

4. 中文 PDF 转 HTML 的 5 个必调参数:从乱码到完美排版的实操清单

编译成功只是开始。pdf2htmlex 默认参数对中文极不友好。以下是我在处理 2000+ 份国标、ISO、IEEE PDF 后总结的最小可行参数集,每一条都对应一个具体排版问题:

参数作用不设后果实测值推荐
--zoom 1.4控制 HTML 中字体渲染缩放比小于 1.2 时宋体小字号(10pt)笔画粘连;大于 1.6 时行高过大破坏版心1.4(兼顾清晰度与密度)
--override-fstype忽略 PDF 内嵌字体许可限制某些商业 PDF(如 Springer)因fstype=2被拒绝渲染字体,全页空白必加
--embedding启用字体子集嵌入(subset)不加则 HTML 依赖用户本地字体,跨设备显示为 Times New Roman必加
--process-outline解析 PDF 书签生成 HTML 目录不加则无左侧导航栏,失去文档结构性必加
--font-format woff2指定嵌入字体格式为 WOFF2默认woff体积大 40%,加载慢;woff2压缩率高且现代浏览器全支持woff2
# 完整命令示例(处理一份含中文目录的国标 PDF) C:/opt/pdf2htmlEX/bin/pdf2htmlEX.exe ^ --zoom 1.4 ^ --override-fstype ^ --embedding ^ --process-outline ^ --font-format woff2 ^ --dest-dir "output" ^ "GB_T_1.1-2020.pdf"

参数说明:--dest-dir指定输出目录(自动创建);--zoom 1.4是玄学经验值——实测在 1366x768 屏幕上,1.4 倍缩放使 10.5pt 宋体刚好达到视网膜屏清晰阈值;--override-fstype绕过 PDF 字体许可证检查(某些 PDF 设置fstype=2表示“禁止嵌入”,但 pdf2htmlex 作为转换工具需忽略);--embedding触发 FreeType 的 subset 功能,只提取 PDF 中实际用到的汉字(如一篇文档只用 300 个汉字,则 WOFF2 文件仅含这 300 字,体积 < 50KB)。

4.1 验证字体嵌入是否成功:检查 output 目录下的fonts/子目录

成功执行后,output/fonts/目录应包含:

  • SimSun-0000.woff2(宋体子集,含文档中所有用到的汉字)
  • SimHei-0001.woff2(黑体子集)
  • stylesheet.css中应有:
    @font-face { font-family: "SimSun"; src: url("fonts/SimSun-0000.woff2") format("woff2"); font-weight: normal; font-style: normal; }

若fonts/为空,或 CSS 中src: url(...)指向不存在的文件,则说明--embedding未生效,常见原因:FreeType 加载字体失败(路径错误)、PDF 使用 Type3 位图字体(无法 subset)、或--override-fstype缺失导致字体被拒。

4.2 处理公式与矢量图:用--svg-node替代默认--png-node

pdf2htmlex 默认将矢量图(如 LaTeX 公式、Visio 流程图)转为 PNG,导致缩放失真。启用 SVG 可保持矢量精度:

# 替换 --png-node 为 --svg-node(注意:需 Cairo 编译时启用 svg backend) C:/opt/pdf2htmlEX/bin/pdf2htmlEX.exe ^ --zoom 1.4 ^ --override-fstype ^ --embedding ^ --process-outline ^ --font-format woff2 ^ --svg-node ^ # 关键!让公式/图表输出为 SVG --dest-dir "output" ^ "paper_with_equations.pdf"

注意:--svg-node要求 Cairo 编译时启用CAIRO_HAS_SVG_SURFACE(默认关闭)。若未启用,命令会静默忽略该参数并回退到 PNG。验证方法:查看output/下是否有.svg文件;若有,说明生效。


5. 避坑:Windows 下 pdf2htmlex 的 4 个血泪经验,每一条都让我重编译过 3 次

这些坑不是文档里写的,是我在连续 72 小时调试中踩出来的。它们不会报错,但会让你的输出 HTML “看起来差不多,实际全是错的”。

5.1 现象:HTML 中中文显示为方框(□□□),但英文正常

原因:FreeType 加载字体时路径错误,或字体文件权限不足(尤其simsun.ttc在 Windows 10/11 中默认只读)
解决:

  • 用icacls "C:\Windows\Fonts\simsun.ttc" /grant Everyone:F赋予读取权限
  • 在font_utils.cc中打印it->second路径,确认是否为C:/Windows/Fonts/simsun.ttc(注意是ttc不是ttf)
  • 用ftdump -a simsun.ttc命令验证字体是否可被 FreeType 解析(需先装freetype-tools)

5.2 现象:生成的 HTML 页面加载极慢(>10 秒),Network 面板显示大量data:URL 卡住

原因:--zoom值过大(如2.0)导致 PNG/SVG 渲染尺寸爆炸,单页 HTML > 50MB
解决:

  • 严格控制--zoom≤1.4
  • 对含大量图片的 PDF,加--hdpi 150 --vdpi 150(默认 300,减半可降体积 60%)
  • 用--no-drm禁用 DRM 检查(某些 PDF 的 DRM 元数据会触发额外解析)

5.3 现象:目录(Outline)生成为空,HTML 左侧无导航栏

原因:PDF 书签结构损坏,或--process-outline未与--embed-external-font配合使用
解决:

  • 先用pdfinfo -meta input.pdf检查Tagged和Outline字段是否为yes
  • 若为no,用pdftk input.pdf dump_data查看 outline 条目;若为空,说明 PDF 本身无书签
  • 必须同时使用--process-outline和--embedding,否则 outline 节点字体无法匹配

5.4 现象:命令行无报错,但output/目录下只有index.html,无pages/子目录和fonts/

原因:--dest-dir路径含中文或空格,CMake 构建时未处理路径转义
解决:

  • --dest-dir必须为纯英文路径(如C:/tmp/out)
  • 若需中文路径,先用mklink /D C:\out C:\我的输出创建符号链接,再用--dest-dir C:/out
  • 检查output/index.html中<script>是否引用pages/1.html;若引用pages/1.htm(少个 l),说明构建时 CMake 生成了错误扩展名,需重编译并确认CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=ON

提示:所有坑的根因都指向同一个事实——pdf2htmlex 在 Windows 上不是“开箱即用”,而是“开箱即调试”。它的日志极其简陋(--debug只输出 3 行),所以必须养成习惯:每次运行后立刻检查output/目录结构、index.html源码、浏览器 Console 错误。一个成功的转换,output/必有pages/、fonts/、stylesheet.css、index.html四个要素,缺一不可。


6. 进阶技巧:用 Python 脚本批量处理 PDF,自动修复目录层级、注入自定义 CSS、生成 PWA 离线包

编译和单次转换只是起点。真实工作流中,你需要把它变成可调度、可监控、可审计的管道。以下是我每天处理 200+ PDF 的 Python 脚本核心逻辑,已去平台化,可直接复用。

6.1 批量转换脚本:带进度、失败重试、日志归档

# batch_pdf2html.py import subprocess import os import time import logging from pathlib import Path # 配置 PDF2HTMLEX_PATH = r"C:\opt\pdf2htmlEX\bin\pdf2htmlEX.exe" INPUT_DIR = Path(r"C:\pdf_in") OUTPUT_ROOT = Path(r"C:\html_out") LOG_FILE = Path(r"C:\logs\pdf2html.log") logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s", handlers=[logging.FileHandler(LOG_FILE), logging.StreamHandler()] ) def convert_pdf(pdf_path: Path, output_dir: Path): """执行单次转换,带重试""" cmd = [ str(PDF2HTMLEX_PATH), "--zoom", "1.4", "--override-fstype", "--embedding", "--process-outline", "--font-format", "woff2", "--svg-node", "--dest-dir", str(output_dir), str(pdf_path) ] for attempt in range(3): try: result = subprocess.run( cmd, capture_output=True, text=True, timeout=600 # 10 分钟超时 ) if result.returncode == 0: logging.info(f"✅ Success: {pdf_path.name}") return True else: logging.warning(f"⚠️ Attempt {attempt+1} failed for {pdf_path.name}: {result.stderr[:200]}") time.sleep(2 ** attempt) # 指数退避 except subprocess.TimeoutExpired: logging.error(f"❌ Timeout on {pdf_path.name}, attempt {attempt+1}") time.sleep(2 ** attempt) logging.error(f"💥 Failed after 3 attempts: {pdf_path.name}") return False def main(): pdf_files = list(INPUT_DIR.glob("*.pdf")) logging.info(f"Found {len(pdf_files)} PDF files") success_count = 0 for i, pdf in enumerate(pdf_files, 1): output_dir = OUTPUT_ROOT / pdf.stem output_dir.mkdir(exist_ok=True) logging.info(f"[{i}/{len(pdf_files)}] Converting {pdf.name}") if convert_pdf(pdf, output_dir): success_count += 1 logging.info(f"🎉 Batch done. Success: {success_count}/{len(pdf_files)}") if __name__ == "__main__": main()

逻辑说明:subprocess.run带timeout=600防止卡死;3 次重试 + 指数退避应对临时资源争用;日志同时输出到文件和控制台,便于排查;output_dir.mkdir(exist_ok=True)确保目录存在,避免因权限问题失败。

6.2 自动修复目录层级:用 BeautifulSoup 修正 HTML 中的<h1><h2>嵌套

pdf2htmlex 生成的目录有时层级错乱(如<h2>出现在<h1>前)。我们用 BS4 重写 heading 标签:

# fix_outline.py from bs4 import BeautifulSoup import re def fix_headings(html_path: str): with open(html_path, 'r', encoding='utf-8') as f: soup = BeautifulSoup(f, 'html.parser') # 找到所有 h1-h6,按出现顺序编号 headings = soup.find_all(re.compile(r'^h[1-6]$')) level_stack = [0] # 栈顶为当前最大层级 for i, h in enumerate(headings): level = int(h.name[1]) # 如果新 heading 层级 > 栈顶+1,降级到栈顶+1 if level > level_stack[-1] + 1: level = level_stack[-1] + 1 h.name = f'h{level}' # 更新栈 if len(level_stack) == 1 or level > level_stack[-1]: level_stack.append(level) else: while level_stack and level_stack[-1] >= level: level_stack.pop() level_stack.append(level) with open(html_path, 'w', encoding='utf-8') as f: f.write(str(soup)) # 调用 fix_headings(r"C:\html_out\doc\index.html")

6.3 注入自定义 CSS 与 PWA 支持:让 HTML 成为真正的 Web 应用

在output/index.html的<head>中插入:

<!-- 自定义 CSS --> <link rel="stylesheet" href="custom.css"> <!-- PWA manifest --> <link rel="manifest" href="manifest.json"> <meta name="theme-color" content="#2196F3"> <!-- Service Worker 注册 --> <script> if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('sw.js'); }); } </script>

manifest.json示例:

{ "name": "PDF Document", "short_name": "Doc", "description": "Offline PDF viewer", "start_url": ".", "display": "standalone", "background_color": "#ffffff", "theme_color": "#2196F3", "icons": [{ "src": "icon-192.png", "sizes": "192x192", "type": "image/png" }] }

技巧:sw.js可缓存pages/下所有 HTML 和fonts/下所有 WOFF2,实现离线阅读。这比 Electron 封装轻量 10 倍,且天然支持深色模式、字体缩放、全文搜索(用window.find())。

我坚持不用任何 GUI 封装或在线服务,因为 pdf2htmlex 的价值恰恰在于它的“原始感”——你清楚知道每一行 HTML 怎么来,每一个字体怎么嵌,每一个目录节点怎么生成。当客户说“这个 PDF 转出来目录少了三级”,我能立刻grep -n "Outline" output/index.html定位;当运维问“为什么首页加载慢”,我能打开 Chrome DevTools 看是fonts/还是pages/1.html在阻塞。这种掌控感,是点几下鼠标换不来的。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/8 3:53:24

Spring Boot核心原理与实战:从自动配置到部署全解析

1. 核心原理拆解&#xff1a;到底什么让 Spring Boot 变得“好用”先说结论&#xff1a;Spring Boot 解决的最大问题不是“写代码”&#xff0c;而是“配置地狱”和“启动复杂度”。如果你经历过 SSH&#xff08;Spring Struts Hibernate&#xff09;时代&#xff0c;或者早几…

作者头像 李华
网站建设 2026/10/8 3:53:24

半年没打开VSCode:AI让我从写代码变成监工

整理电脑的时候翻到VSCode&#xff0c;这才发现它已经半年没被我打开过了。两年前这是不可想象的&#xff0c;那时候我每天的工作就是从启动VSCode开始&#xff0c;装插件、配主题、调快捷键&#xff0c;光是Python和C环境来回切换就能折腾一个下午。今年AI编程工具的变化实在太…

作者头像 李华
网站建设 2026/10/8 3:53:24

WorkBuddy:面向办公场景的可落地AI Agent实践指南

1. 项目概述&#xff1a;WorkBuddy不是另一个“AI玩具”&#xff0c;而是你办公桌边能真正干活的数字同事我第一次在腾讯云控制台看到WorkBuddy的入口时&#xff0c;下意识点开以为是又一个“智能助手”弹窗——结果三分钟内&#xff0c;它自动读取了我刚上传的销售周报PDF&…

作者头像 李华
网站建设 2026/10/8 3:53:22

本地AI编程环境配置:Claude与Qwen混合调度实战

1. 这套Claude Code的模型配置既聪明又省钱&#xff1a;不是玄学&#xff0c;是工程权衡的结果“这套Claude Code的模型配置既聪明又省钱”——这句话在开发者群、技术论坛和VS Code插件讨论区里反复刷屏&#xff0c;但它绝不是一句营销话术。我用它跑了三个月的真实项目&#…

作者头像 李华
网站建设 2026/10/8 3:53:19

SECS-II/HSMS调试工具实战:模拟器搭建与高频踩坑指南

简介&#xff1a;面向半导体及制造业MES系统开发与调试人员&#xff0c;提供SECS-II/HSMS通信链路的模拟验证工具。该模拟器可灵活切换为服务端或客户端模式&#xff0c;用于确认上位机与设备间交互数据是否符合SECS-II标准及客户规范&#xff0c;避免因协议偏差导致联调返工。…

作者头像 李华
网站建设 2026/10/8 3:53:01

Altium Designer 24自动布线全流程:规则配置与实战技巧

很多工程师第一次接触 Altium Designer 的自动布线功能时&#xff0c;心里想的大多是同一件事&#xff1a;点一个按钮&#xff0c;软件把整块板子的线全部布完&#xff0c;自己只需要坐下喝茶。这个期望几乎必然会落空。真正把自动布线用好的人会有相反的感受&#xff1a;自动布…

作者头像 李华