toolgarden.xyz
EN
浏览器工具开发PDF 转 Wordpdf.jsOpen XML文档工程

怎么用 pdf.js 在浏览器把 PDF 转成 Word

使用 pdf.js 提取带坐标的 PDF 文本,重建可读行、保留分页,并在浏览器中生成最小可编辑 DOCX。

ToolGarden 推荐的工具优先在浏览器本地运行,文件和文本不必上传到服务器,适合更注重安全隐私的日常处理。

发布于 2026年7月22日约 10 分钟阅读作者 ToolGarden

PDF 和 Word 解决的是相反布局问题:PDF 保存固定视觉页面,Word 保存可编辑文档结构。浏览器转换器可以可靠地把文本层恢复成干净 DOCX,但仅靠坐标无法推断所有表格、分栏、字体和图片关系。

这套实现明确以“可读、可编辑文本”为目标。pdf.js 提取文字和 transform,坐标启发式重建行,XML 转义保护文档,fflate 再把最小 Open XML Word 包与分页符打包出来。

先缩小并说明转换承诺

带文本层的 PDF 包含字形字符串和位置 transform,并不包含语义段落;扫描件甚至可能完全没有文字项。应明确结果是带分页的可编辑提取文本,不是源设计的像素级复刻。

这个边界让工具适合引用、报告、笔记和文案恢复,同时不会对复杂宣传册、表单、公式和多栏排版作出错误承诺。

源 PDF 能力这套流水线的结果
可选择文本提取为 Word 段落
原始分页通过分页符保留
纯扫描图片页需要先做 OCR
表格和分栏可能被压平成阅读顺序文本
图片和精确字体不重建

加载 pdf.js 并提取带坐标文字

动态 import pdf.js legacy browser build,并把 GlobalWorkerOptions.workerSrc 指向打包的 worker。选择的 File 读取成 Uint8Array,开启系统字体加载文档,再按顺序处理每一页。

每个文本项提供字符串和 transform,第五、第六个值可以作为轻量重建所需的 x、y 位置。规范空白,并忽略空字符串和非文本项。

const page = await pdf.getPage(pageNumber);
const content = await page.getTextContent();

const positioned = content.items.flatMap(item => {
  if (!isTextItem(item) || !item.str.trim()) return [];
  return [{
    text: normalizeText(item.str),
    x: Number(item.transform[4] ?? 0),
    y: Number(item.transform[5] ?? 0),
  }];
});

const lines = groupByNearbyY(positioned)
  .map(line => line.sort((a, b) => a.x - b.x))
  .map(line => line.map(item => item.text).join(' '));

用坐标容差重建文本行

先按 y 从上到下、x 从左到右排序。y 值差小于容差的文本项进入同一行,每行再按 x 排序并拼接。普通单栏文本不需要布局模型也能得到较好结果。

容差只是启发式。上标、旋转文字、竖排、分栏、表格和定位标签可能产生意外顺序。更高级方案要先做 block segmentation 与分栏检测。

  • 限制每页最大文本项,约束异常输入。
  • 某页没有可用文字时仍然保留页序。
  • 整份文档段落数为零时返回 empty_text。
  • 返回页数和段落数,让 UI 描述结果。

生成最小有效 DOCX 包

DOCX 是 Open XML ZIP。最小包需要 [Content_Types].xml、根关系、核心与应用属性、word/document.xml。每一条重建文本行成为 w:p,第一页之后的每个源页面前插入 Word 分页符。

用户文本写入 XML 前要去除非法控制字符并转义 &、尖括号、引号和单引号。xml:space="preserve" 可以防止 Word 丢掉预期空格。

const entries = {
  '[Content_Types].xml': strToU8(contentTypesXml),
  '_rels/.rels': strToU8(packageRelationshipsXml),
  'docProps/core.xml': strToU8(corePropertiesXml),
  'docProps/app.xml': strToU8(appPropertiesXml),
  'word/document.xml': strToU8(buildDocumentXml(pages)),
};

const zipped = zipSync(entries, { level: 6 });
return new Blob([zipped], {
  type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
});

扫描 PDF 应走单独 OCR 流程

pdf.js 没有返回可用文字时,页面可能是扫描图,或文字编码无法被提取。静默生成空 Word 比返回 empty_text 更糟。

扫描转 Word 需要先把每页渲染成图片,运行 OCR,把识别块映射回阅读顺序,再生成 DOCX。这是另一条带模型下载、图片限制、语言选择和更低确定性的流水线。

校验输入并释放输出资源

import pdf.js 前先检查空文件、PDF 类型和最大字节数。加密、损坏或不支持的 PDF 统一作为加载失败处理。UI 为结果创建一个 Object URL,并在选择新文件或组件卸载时 revoke 旧 URL。

用 Word、LibreOffice 和网页查看器测试输出。语法有效的 Open XML 包仍可能出现只有真实文档应用才能发现的顺序或 Unicode 问题。

总结

聚焦文本的 PDF 转 Word 可以既小又诚实:提取带位置文字、用明确启发式分行、保留分页、转义 XML,再生成最小 DOCX。扫描件和高保真版式恢复属于另一条更复杂的流水线。

常见问题

Q.为什么 Word 结果和 PDF 版式不完全一样?

PDF 保存固定坐标内容,Word 需要流式文档结构。这套转换优先恢复可编辑文本与分页,不重建字体、分栏、图片和精确几何。

Q.为什么扫描 PDF 转换后没有文字?

扫描件通常只有页面图片,没有可选择文本层。pdf.js 可以渲染图片,但不会凭空产生文字,必须先运行 OCR。

Q.为什么不直接使用大型 DOCX 库?

纯文本结果需要的 Open XML 包很小且可预测。需要样式、表格、图片、页眉、编号和复杂布局时,完整文档库更有价值。

Q.PDF 会离开浏览器吗?

这条转换路径不会。pdf.js 在页面中读取文件字节,DOCX 作为本地 Blob 生成;应用和 worker 资源仍需要由站点交付到浏览器。