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

如何使用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字符:
    • 优先读取字体的ToUnicode CMap(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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 09:45:23