使用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à
相关产品推荐
相关产品推荐

