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

求推荐Java中实现双PDF分别高亮差异并保留原文件的开源方案

Java实现独立高亮两个PDF差异并保留原文件的开源方案

方案一:PDFBox自定义改造

你提到PDFBox默认会合并双PDF,那可以跳过它的内置对比逻辑,自己拆分流程:

  • 分别加载两个原始PDF,用PDFTextStripper或PDFTextStripperByArea提取每页的文本及位置信息
  • 用第三方文本对比库(比如Apache Commons Text的DiffUtils)找出两段文本的差异片段
  • 对每个原始PDF的副本,通过PDPageContentStream在差异文本对应的BoundingBox上绘制半透明高亮矩形,完全保留原PDF内容
  • 将两个处理后的PDF(原内容+独立高亮)按顺序合并到输出文件,还可按需添加分隔页区分

示例代码片段:

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.commons.text.diff.DiffUtils;
import org.apache.commons.text.diff.Patch;

import java.io.File;
import java.awt.Color;
import java.util.Arrays;

public class PdfDiffHighlighter {
    public static void main(String[] args) throws Exception {
        // 加载原始PDF文档
        PDDocument doc1 = PDDocument.load(new File("original1.pdf"));
        PDDocument doc2 = PDDocument.load(new File("original2.pdf"));
        PDDocument outputDoc = new PDDocument();

        int pageCount = Math.min(doc1.getNumberOfPages(), doc2.getNumberOfPages());
        PDFTextStripper stripper = new PDFTextStripper();

        for (int i = 0; i < pageCount; i++) {
            PDPage page1 = doc1.getPage(i);
            PDPage page2 = doc2.getPage(i);

            // 提取每页文本
            stripper.setStartPage(i + 1);
            stripper.setEndPage(i + 1);
            String text1 = stripper.getText(doc1);
            String text2 = stripper.getText(doc2);

            // 对比文本差异
            Patch<String> patch = DiffUtils.diff(Arrays.asList(text1.split("\n")), Arrays.asList(text2.split("\n")));

            // 给doc1的页面添加高亮(这里需补充根据文本定位坐标的逻辑)
            PDPageContentStream cs1 = new PDPageContentStream(doc1, page1, PDPageContentStream.AppendMode.APPEND, true, true);
            cs1.setNonStrokingColor(new Color(255, 255, 0, 128));
            // 遍历差异片段,定位并绘制高亮矩形
            patch.getDeltas().forEach(delta -> {
                // 示例:假设已获取到差异区域的坐标x,y,width,height
                try {
                    cs1.addRect(100, 500, 200, 20);
                    cs1.fill();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
            cs1.close();

            // 同理处理doc2的页面高亮
            PDPageContentStream cs2 = new PDPageContentStream(doc2, page2, PDPageContentStream.AppendMode.APPEND, true, true);
            cs2.setNonStrokingColor(new Color(0, 255, 255, 128));
            // 绘制doc2的差异高亮
            cs2.close();
        }

        // 合并处理后的两个PDF到输出文件
        doc1.getPages().forEach(outputDoc::addPage);
        // 可选:添加分隔页
        outputDoc.addPage(new PDPage());
        doc2.getPages().forEach(outputDoc::addPage);

        outputDoc.save("highlighted_diff.pdf");
        // 关闭资源
        doc1.close();
        doc2.close();
        outputDoc.close();
    }
}

方案二:iText 7实现

iText 7的文本定位API更精准,适合处理复杂排版的PDF:

  • 使用PdfTextExtractor提取每个字符的位置和内容,精准定位差异区域
  • 对原始PDF副本,通过PdfCanvas绘制高亮批注
  • 合并两个带高亮的PDF到输出文件,保留各自原内容

核心优势是处理多列、图文混排的PDF时,文本定位准确率更高。

关键注意事项

  • 文本定位是核心:对于复杂布局,需要遍历TextRenderInfo获取每个字符的坐标,再映射到差异片段的位置
  • 依赖文本对比库:优先用Apache Commons Text的DiffUtils或Google的diff-match-patch,避免自己造轮子
  • 操作副本:务必对原始PDF的副本进行修改,防止破坏原文件

内容的提问来源于stack exchange,提问作者Aneek Biswas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 21:45:35