在 Rust 中修复损坏的 PDF — 从头重建 XREF 表
发布: (2026年4月28日 GMT+8 10:34)
3 分钟阅读
原文: Dev.to
Source: Dev.to
问题
有些 PDF 无法打开,并不是因为内容缺失,而是因为指示阅读器在哪里找到内容的索引损坏了。
这个索引就是 XREF 表,它可以被重新构建。
XREF 表的样子
xref
0 6
0000000000 65535 f
0000000009 00000 n
0000000058 00000 n
0000000115 00000 n
0000000266 00000 n
0000000496 00000 n
当阅读器打开 PDF 时,会首先读取这个表。如果它缺失或损坏,PDF “无法打开”。内容对象仍然在文件中;我们只需要定位它们并重建索引。
在 Rust 中重建 XREF 表
pub fn rebuild_xref(data: &[u8]) -> Result {
// lopdf can attempt recovery on malformed files
let doc = Document::load_mem(data)
.or_else(|_| recover_document(data))?;
Ok(doc)
}
扫描对象
pub fn recover_document(data: &[u8]) -> Result {
// Scan the raw bytes for object markers
// Pattern: "N 0 obj" where N is the object number
let mut offsets: Vec = Vec::new();
let obj_pattern = b" 0 obj";
for (i, window) in data.windows(obj_pattern.len()).enumerate() {
if window == obj_pattern {
// Walk back to find the object number
if let Some(num) = extract_obj_num(data, i) {
offsets.push((num, 0, i - num.to_string().len()));
}
}
}
// Reconstruct document from found objects
rebuild_from_offsets(data, offsets)
}
重建有帮助的典型场景
- PDF 在写入过程中被截断(例如,保存时断电)
- PDF 进行增量更新后导致 XREF 链断裂
- 老文件的 XREF 被手动错误编辑过
- 扫描仪输出的结构异常的 PDF
如果内容流本身已损坏——实际页面数据丢失——则任何 XREF 重建都无济于事。结构性的复原仅在对象仍在但索引损坏时有效。
大约 80 % 的“无法打开”PDF 我测试过都是 XREF 问题。内容本身是完整的,只需要一个新的索引。
资源
- Hiyoko PDF Vault – https://hiyokoko.gumroad.com/l/HiyokoPDFVault
- Twitter:
@hiyoyok