Java使用Pdfbox做文本替换

背景

	最近研究电子合同的签约。遇到了Pdf模板的文字替换的问题。因为是标准合同,所以只需要替换其中的文本就可以。

思路

	首先找到相关的关键字,在关键字上先放一个蒙层。再用新的内容盖住旧的文字。

引入PDFBox

implementation 'org.apache.pdfbox:pdfbox:3.0.1'

第二步

需要找到我们要替换的文字的位置。这里需要扩展 PDFTextStripper

import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;
import org.apache.pdfbox.util.Matrix;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class SearchPositionPDFTextStripper extends PDFTextStripper {

    private final List<String> keyWordList;
    private final List<SearchResult> list = new ArrayList<>();

    public SearchPositionPDFTextStripper(List<String> keyWordList) throws IOException {
        this.keyWordList = keyWordList;
    }

    @Override
    protected void writeString(String text, List<TextPosition> positions) {
        for (String keyWord : keyWordList) {
            int index = text.indexOf(keyWord);
            if(index>=0) {
                SearchResult entity = new SearchResult();
                entity.setKeyWord(keyWord);
                TextPosition startPosition = positions.get(index);
                TextPosition endPosition = positions.get(index+keyWord.length()-1);
                Matrix matrix = startPosition.getTextMatrix();
                float x = matrix.getTranslateX();
                float y = matrix.getTranslateY();
                // 获取结束字符坐标
                Matrix endMatrix = endPosition.getTextMatrix();
                float x2 = endMatrix.getTranslateX();
                // 获取字体大小
                float fontSizeInPt = startPosition.getFontSizeInPt();
                entity.setFont(startPosition.getFont());
                entity.setX(x);
                entity.setFontSize(startPosition.getFontSize());
                entity.setY(y - fontSizeInPt / 5);
                float width =  x2 - x + startPosition.getFontSizeInPt();
                entity.setWidth(width);
                entity.setHeight(fontSizeInPt);
                this.getKeyWordEntityList().add(entity);
            }
        }
    }

    public List<SearchResult> getSearchResult() {
        return list;
    }
}

这个类用于结果的保存

import org.apache.pdfbox.pdmodel.font.PDFont;

public class SearchResult {
    private String keyWord;

    private float x; //记录查找到的文本所在的x坐标点
    private float y; //记录查找到的文本所在的y坐标点
    private float width; //记录查找到的文本的宽
    private float height; //记录查找到的文本的高

    private PDFont font;

    private float fontSize;

    public float getFontSize() {
        return fontSize;
    }

    public void setFontSize(float fontSize) {
        this.fontSize = fontSize;
    }

    public PDFont getFont() {
        return font;
    }

    public void setFont(PDFont font) {
        this.font = font;
    }

    public String getKeyWord() {
        return keyWord;
    }

    public void setKeyWord(String keyWord) {
        this.keyWord = keyWord;
    }

    public float getX() {
        return x;
    }

    public void setX(float x) {
        this.x = x;
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
    }

    public float getWidth() {
        return width;
    }

    public void setWidth(float width) {
        this.width = width;
    }

    public float getHeight() {
        return height;
    }

    public void setHeight(float height) {
        this.height = height;
    }
}

有了这两个类,我们就可以在PDF文档里查找文字了。我们用下边这个方法来查找。

        File file = new File("1.pdf");
        try(PDDocument document = Loader.loadPDF(file)) {
            SearchPositionPDFTextStripper stripper = new SearchPositionPDFTextStripper();
            stripper.setSortByPosition(true);
            stripper.getText(document);
            List<SearchResult> list = stripper.getSearchResult();
            //在这里做替换
            //1. 先把字体加进来
            ClassPathResource resource = new ClassPathResource("SimSun.ttf");
            PDFont font = PDType0Font.load(document, resource.getInputStream(),true);
            PDPage page = document.getPage(0);
            //2. 新建一个内容流
            PDPageContentStream stream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true);
            for (SearchResult item : list) {
                //3. 这里是做了一个填图型的遮盖。如果只是把文字抹去,这里看上去是空白的,还可以把原来的文字内容拷出去。所以一定要重新写过替换的内容
                stream.setNonStrokingColor(Color.WHITE);
                stream.addRect(item.getX(), page.getArtBox().getHeight() - item.getY() - item.getHeight(), item.getWidth(), item.getHeight());
                stream.fill();
                //4. 这里就开始做文字替换了
                stream.setNonStrokingColor(Color.BLACK);
                String replace = "";
                for(int i=0;i<item.getKeyWord.length;i++) {
                	replace = replace + "*"
                }
                writeText(stream,replace,font,item.getX(), page.getArtBox().getHeight() - item.getY() - item.getHeight(), item.getFontSize());
            }
            //5. 都替换完成了。这里把结果保存成另外一个PDF就完成了
            stream.close();
            document.save("3.pdf");
        } catch (IOException e) {
        	throw new RuntimeException(e);
        }

writeText方法的代码

    private void writeText(PDPageContentStream contents, String text, PDFont font, float x, float y,float fontSize) throws IOException {
        contents.moveTo(x, y);
        contents.beginText();
        contents.setFont(font, 12);
        contents.newLineAtOffset(x, y);
        contents.showText(text);
        contents.endText();
    }

待解决的问题

  1. 当引用原有字体时,会产生下边的错误
java.lang.IllegalArgumentException: No glyph for U+0020 ( ) in font MLJNAR+simsun
  1. 这个方法,只能做同样数量的字符替换,另外当字符串宽度不一致的时候也可能会出现问题。
  • 10
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用PDFBox进行PDF文本替换的示例代码: ```java import java.io.File; import java.io.IOException; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.PDPageContentStream; import org.apache.pdfbox.pdmodel.font.PDType1Font; public class PDFTextReplacement { public static void main(String[] args) { try { // 加载PDF文档 PDDocument document = PDDocument.load(new File("input.pdf")); // 获取第一页 PDPage page = document.getPage(0); // 创建内容流 PDPageContentStream contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true); // 设置字体和字号 contentStream.setFont(PDType1Font.HELVETICA_BOLD, 12); // 替换文本 contentStream.beginText(); contentStream.newLineAtOffset(100, 700); // 设置文本位置 contentStream.showText("替换后的文本"); // 替换为你想要的文本 contentStream.endText(); // 关闭内容流 contentStream.close(); // 保存修改后的PDF文档 document.save(new File("output.pdf")); // 关闭文档 document.close(); System.out.println("文本替换成功!"); } catch (IOException e) { e.printStackTrace(); } } } ``` 请注意,上述示例代码是使用Java编写的,需要将PDFBox库添加到项目中。你需要将"input.pdf"替换为你要替换文本PDF文件路径,并将"替换后的文本"替换为你想要替换文本内容。执行代码后,将生成一个名为"output.pdf"的新PDF文件,其中的文本已被替换
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值