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

Java如何移除PDF文件中的特定文本并保存修改后的文件

实现方案说明

首先明确两种初步方案的可行性:

  • 直接读取PDF字节数组删除目标文本的方案完全不可行:PDF是结构化二进制文档格式,可见文本的存储顺序和阅读顺序不一致,还嵌套了字体映射、内容流指令、偏移索引等结构,直接修改字节会直接导致文件损坏、内容错乱。
  • 使用第三方PDF处理类库是唯一可行的路径,你当前代码已经在用Apache PDFBox,直接基于它实现即可,不需要额外引入iText(iText新版本为AGPL协议,商用需要购买授权,限制较多)。
具体实现逻辑

你之前用的PDFTextStripper只能做纯文本提取,拿不到文本在页面的位置、对应绘制指令,无法完成删除操作。需要通过PDFBox的文本位置解析能力定位目标行,再通过覆盖/移除内容流的方式完成删除,优先推荐同色矩形覆盖的方案,实现简单、兼容性强,90%以上的常规PDF场景都适用:

  1. 遍历PDF每一页
  2. 解析页面内所有文本块的坐标、内容,定位到需要删除的目标行的边界(X/Y轴起始、结束位置)
  3. 在对应位置绘制和页面背景色一致的矩形(默认白底用白色即可)覆盖目标文本
  4. 保存修改后的文档

如果需要彻底移除内容流里的文本绘制指令(而不是视觉覆盖),可以用PDFContentStreamEditor重写页面内容流,过滤掉对应文本的绘制指令,但是这个方案对复杂排版、分栏、嵌套表单的PDF兼容性差,容易出现内容错位,非必要不推荐。

可运行代码示例(基于PDFBox 2.x)
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.pdfbox.text.TextPosition;
import org.apache.pdfbox.util.Matrix;
import java.io.File;
import java.io.IOException;
import java.util.List;

public class PdfTextRemover {
    // 自定义文本解析器,收集目标文本的坐标范围
    static class TargetTextLocator extends PDFTextStripper {
        private float minX = Float.MAX_VALUE;
        private float maxX = Float.MIN_VALUE;
        private float minY = Float.MAX_VALUE;
        private float maxY = Float.MIN_VALUE;
        private final String targetText;
        private boolean found = false;

        public TargetTextLocator(String targetText) throws IOException {
            super();
            this.targetText = targetText;
            // 按位置排序文本,保证解析顺序和阅读顺序一致
            setSortByPosition(true);
        }

        @Override
        protected void writeString(String text, List<TextPosition> textPositions) throws IOException {
            // 匹配到包含目标文本的行
            if (text.trim().contains(targetText) && !found) {
                found = true;
                for (TextPosition pos : textPositions) {
                    // 转换为PDF默认坐标系(原点在页面左下角)
                    Matrix textMatrix = pos.getTextMatrix();
                    float x = textMatrix.getTranslateX();
                    float y = textMatrix.getTranslateY();
                    float width = pos.getWidth();
                    float height = pos.getHeight();
                    // 更新文本边界,留2px冗余避免覆盖不全
                    minX = Math.min(minX, x) - 2;
                    maxX = Math.max(maxX, x + width) + 2;
                    minY = Math.min(minY, y) - 2;
                    maxY = Math.max(maxY, y + height) + 2;
                }
            }
            super.writeString(text, textPositions);
        }

        public boolean isFound() { return found; }
        public float getRectX() { return minX; }
        public float getRectY() { return minY; }
        public float getRectWidth() { return maxX - minX; }
        public float getRectHeight() { return maxY - minY; }
    }

    public static void removeTargetText(String inputPath, String outputPath, String targetTextPerPage) throws IOException {
        try (PDDocument document = PDDocument.load(new File(inputPath))) {
            int pageCount = document.getNumberOfPages();
            // 遍历所有页面
            for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) {
                PDPage page = document.getPage(pageIndex);
                // 定位当前页目标文本位置
                TargetTextLocator locator = new TargetTextLocator(targetTextPerPage);
                locator.setStartPage(pageIndex + 1);
                locator.setEndPage(pageIndex + 1);
                locator.getText(document);

                if (locator.isFound()) {
                    // 绘制同色矩形覆盖目标文本
                    try (PDPageContentStream contentStream = new PDPageContentStream(
                            document, page, PDPageContentStream.AppendMode.APPEND, true, true)) {
                        // 默认用白色填充,非白底PDF替换为对应背景RGB值即可
                        contentStream.setNonStrokingColor(255, 255, 255);
                        contentStream.addRect(locator.getRectX(), locator.getRectY(), 
                                locator.getRectWidth(), locator.getRectHeight());
                        contentStream.fill();
                    }
                }
            }
            // 保存修改后的文件
            document.save(outputPath);
        }
    }

    public static void main(String[] args) {
        try {
            // 传入输入文件路径、输出文件路径、每页要删除的目标文本
            removeTargetText("input.pdf", "output.pdf", "需要删除的那行文本内容");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
注意事项
  • 如果要删除的行是固定位置(比如页面顶部的页眉、底部的页脚),不需要匹配文本内容,可以直接跳过文本解析步骤,在固定坐标位置绘制覆盖矩形即可,处理效率更高。
  • 不推荐使用PDF转纯文本修改后再转回PDF的方案,会丢失原PDF的格式、图片、书签、签名等结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 14:48:21