You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Swift的PDFDocument.write保存PDF时内容损坏求助

解决PDFKit中PDFDocument.write保存后文本内容损坏的问题

问题描述

使用Swift的PDFDocument.write方法保存从arXiv下载的PDF论文后,加载回来的文档文本内容出现损坏:例如原文档中的"*"变为"ú","ff"被替换为"\0",保存前后文档第一页文本存在明显字符替换差异。通过对比PDFDocument.string发现保存前后文本内容不一致,复现代码如下:

import PDFKit

let originalDocument = PDFDocument(url: /* 目标PDF的URL */)!
            
let saveDirectory = FileManager.default.temporaryDirectory.appendingPathComponent("saved.pdf")
originalDocument.write(to: saveDirectory)
            
let savedDocument = PDFDocument(url: saveDirectory)!
            
if originalDocument.string != savedDocument.string {
    print("Textual content has changed!")
}

解决方案

方法1:直接复制原文件二进制数据(无修改需求时首选)

如果不需要对PDFDocument对象做任何编辑操作,直接复制原PDF的二进制数据是最可靠的方式,完全避开PDFKit解析重写带来的文本编码问题:

import Foundation
import PDFKit

guard let sourceURL = /* 目标PDF的URL */,
      let pdfData = try? Data(contentsOf: sourceURL) else {
    fatalError("无法加载原PDF文件")
}

let saveURL = FileManager.default.temporaryDirectory.appendingPathComponent("saved.pdf")
try? pdfData.write(to: saveURL, options: .atomic)

// 验证一致性
let originalDoc = PDFDocument(url: sourceURL)!
let savedDoc = PDFDocument(url: saveURL)!
print(originalDoc.string == savedDoc.string) // 输出应为true

方法2:使用dataRepresentation()获取PDF数据后写入

如果必须通过PDFDocument对象处理后再保存,优先使用dataRepresentation()方法获取PDF的二进制数据,再写入文件,该方法的重写逻辑比write(to:)更稳定:

import PDFKit

let originalDocument = PDFDocument(url: /* 目标PDF的URL */)!
            
let saveURL = FileManager.default.temporaryDirectory.appendingPathComponent("saved.pdf")
if let pdfData = originalDocument.dataRepresentation() {
    try? pdfData.write(to: saveURL, options: .atomic)
}
            
let savedDocument = PDFDocument(url: saveURL)!
print(originalDocument.string == savedDocument.string)

方法3:禁用PDFKit的元数据提取与布局优化

部分情况下,PDFKit的写入流程会默认优化文本布局、提取元数据,这可能破坏原文档的字符映射。可以尝试关闭相关选项后再保存:

import PDFKit

let originalDocument = PDFDocument(url: /* 目标PDF的URL */)!
// 禁用元数据提取
originalDocument.shouldAttemptToExtractMetaData = false
// 对所有页面禁用无障碍优化(避免文本重排)
for page in originalDocument.pages {
    page.disableAccessibility = true
}

let saveURL = FileManager.default.temporaryDirectory.appendingPathComponent("saved.pdf")
originalDocument.write(to: saveURL)
            
let savedDocument = PDFDocument(url: saveURL)!
print(originalDocument.string == savedDocument.string)

问题根源

PDFKit的write(to:)方法并非简单复制原PDF的二进制内容,而是会重新解析原文档的结构、字体、文本布局,再生成新的PDF文件。对于包含特殊嵌入字体、复合字形(如"ff"连字)或非标准字符编码的PDF,这个重写过程可能会错误映射字符编码,导致后续提取文本时出现错乱。

内容的提问来源于stack exchange,提问作者Khắc Hà

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 14:47:11