如何使用Apache PDFBox编辑PDF文本,保留格式并实现自定义加密替换
使用Apache PDFBox实现PDF文本加密替换(保留字体与位置)
需求概述
可以通过Apache PDFBox实现该需求:将PDF中指定文本(如HELLO WORLD)通过自定义加密算法转换为目标文本(如GDKKN VNQKC),同时完全保留原文本的字体、字号、页面位置等格式属性。
当前问题解析
你遇到的COSString.getString()返回乱码的问题,本质是PDF中存储的文本并非直接的Unicode字符,而是字体编码后的字节序列——不同字体有自己的编码规则(如WinAnsiEncoding、自定义CMap),直接调用字符串方法自然无法解析出正确内容。
核心解决步骤
要完成文本替换,需实现「编码字节→真实字符→加密后字符→新编码字节」的转换闭环,关键步骤如下:
- 遍历PDF页面的ContentStream,定位所有
TJ(文本显示)运算符及对应的文本片段(COSString对象) - 结合当前上下文的字体对象,将
COSString的字节数据转换为真实Unicode字符:- 优先读取字体的
ToUnicodeCMap(PDF标准的编码映射表),通过PDFont.encode(...)或自定义映射逻辑完成解码 - 若没有
ToUnicode表,需根据字体的内置编码(如WinAnsi)进行字节到字符的映射
- 优先读取字体的
- 对解码后的真实字符应用自定义加密算法,生成目标字符
- 将目标字符转回对应字体的编码字节,替换原
COSString中的内容 - 保留
TJ运算符的其他参数(如位置偏移数组),确保文本位置不变
关键代码示例
以下是核心逻辑的简化实现:
// 1. 加载PDF文档 PDDocument document = PDDocument.load(new File("input.pdf")); for (PDPage page : document.getPages()) { // 2. 获取并解析页面ContentStream PDStream stream = page.getContents(); try (InputStream is = stream.createInputStream()) { ContentStreamParser parser = new ContentStreamParser(is); List<Object> tokens = parser.parse(); for (int i = 0; i < tokens.size(); i++) { Object token = tokens.get(i); // 3. 定位TJ运算符 if ("TJ".equals(token)) { // 获取TJ的操作数(包含COSString和偏移量的数组) COSArray tjArray = (COSArray) tokens.get(i - 1); for (int j = 0; j < tjArray.size(); j++) { COSBase base = tjArray.getObject(j); if (base instanceof COSString) { COSString cosStr = (COSString) base; // 获取当前上下文的字体(需跟踪ContentStream中的BT/ET块及字体设置) PDont currentFont = ...; // 需提前解析字体状态 // 4. 解码:编码字节→真实字符 String originalText = currentFont.decode(cosStr.getBytes()); // 5. 应用自定义加密算法 String encryptedText = customEncrypt(originalText); // 6. 编码:加密后字符→新编码字节 byte[] encryptedBytes = currentFont.encode(encryptedText); // 7. 替换原COSString内容 cosStr.setValue(encryptedBytes); } } } } } // 8. 更新页面ContentStream page.setContents(new PDStream(document, new ByteArrayInputStream(ContentStreamWriter.writeTokens(tokens)))); } // 保存修改后的PDF document.save("output.pdf"); document.close();
注意事项
- 需严格跟踪ContentStream中的
BT(文本块开始)和ET(文本块结束)指令,确保获取当前文本块对应的字体、字号等状态 - 部分字体可能没有
ToUnicode表,需额外处理编码映射(如利用PDFBox的WinAnsiEncoding等内置编码类) - 对于包含复合字体(如CID字体)的PDF,需处理更复杂的CMap映射逻辑
内容的提问来源于stack exchange,提问作者omkar vanjare
相关产品推荐
相关产品推荐

