Java通过itext解析PDF中的关键字得到坐标进行插入印章图片或签名

发布时间 2023-10-12 11:52:03作者: changlinlo

需求

因需提高公司运转效率,提倡去无纸化操作,减少人力等前提;通过系统将审核通过后的pdf文档进行盖电子印章或电子签名等功能;
测试效果如下:

图1

图2

实现思路

因如上图1中,存在动态表格,所以文档的布局是随数据而变的,可能是多页,可能是一页,且内容上下浮动,所以得通过解析文档内容,通过关键字进行计算出关键字的坐标,再通过坐标进行实现电子印章图片的绝对定位;

代码实现

  1. 引入依赖
        <!-- itext5  -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.9</version>
        </dependency>
        <!-- itext支持  -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>
  1. PdfUtils定位工具类

import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfReaderContentParser;
import java.io.IOException;

/**
 * Pdf定位工具类
 */
public class PdfUtils
{

    /**
     * @Author lcl
     * @Date 11:24 2023/10/12
     * @Description 用于供外部类调用获取关键字所在PDF文件坐标
     * @param filepath 文件路径
     * @param keyWords 关键词
     * @return float[] 坐标
     */
    public static float[] getKeyWordsByPath(String filepath, String keyWords)
    {
        float[] coordinate = null;
        try
        {
            PdfReader pdfReader = new PdfReader(filepath);
            coordinate = getKeyWords(pdfReader, keyWords);
        } catch (IOException e)
        {
            e.printStackTrace();
        }
        return coordinate;
    }

    /**
     * @Author lcl
     * @Date 11:26 2023/10/12
     * @Description 获取关键字所在PDF坐标
     * @param pdfReader 流
     * @param keyWords 关键词
     * @return float[] 坐标
     */
    public static float[] getKeyWords(PdfReader pdfReader, String keyWords)
    {
        float[] coordinate = null;
        int page = 0;
        try
        {
            int pageNum = pdfReader.getNumberOfPages();
            PdfReaderContentParser pdfReaderContentParser = new PdfReaderContentParser(pdfReader);
            CustomRenderListener renderListener = new CustomRenderListener();
            renderListener.setKeyWord(keyWords);
            for (page = 1; page <= pageNum; page++)
            {
                renderListener.setPage(page);
                pdfReaderContentParser.processContent(page, renderListener);
                coordinate = renderListener.getPcoordinate();
                if (coordinate != null)
                {
                    break;
                }
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        return coordinate;
    }
}
  1. CustomRenderListener定位辅助类
import com.itextpdf.awt.geom.Rectangle2D.Float;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.RenderListener;
import com.itextpdf.text.pdf.parser.TextRenderInfo;

/**
 * @Author lcl
 * @Date 11:53 2023/10/12
 * @Description pdf关键词帮助类
 */
public class CustomRenderListener implements RenderListener
{

    private float[] pcoordinate = null;

    private String keyWord;

    private int page;

    public int getPage()
    {
        return page;
    }

    public void setPage(int page)
    {
        this.page = page;
    }

    public float[] getPcoordinate()
    {
        return pcoordinate;
    }

    public String getKeyWord()
    {
        return keyWord;
    }

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

    @Override
    public void beginTextBlock() {}

    @Override
    public void endTextBlock() {}

    @Override
    public void renderImage(ImageRenderInfo arg0) {}

    @Override
    public void renderText(TextRenderInfo textRenderInfo)
    {
        String text = textRenderInfo.getText();
        if (null != text && text.contains(keyWord)) {
            Float boundingRectange = textRenderInfo.getBaseline().getBoundingRectange();
            pcoordinate = new float[3];
            pcoordinate[0] = boundingRectange.x;
            pcoordinate[1] = boundingRectange.y;
            pcoordinate[2] = page;
        }
    }
}
  1. 测试
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import java.io.*;


public class TestUtils
{

    public static void main(String[] args) throws IOException, DocumentException
    {
        // 原文件
        File file = new File("C:\\Users\\Administrator\\Desktop\\JYX_QYZT\\test1.pdf");
        // 处理后的文件
        FileOutputStream outputStream = new     
        FileOutputStream("C:\\Users\\Administrator\\Desktop\\JYX_QYZT\\test2.pdf");
        // 读
        PdfReader reader = new PdfReader(new FileInputStream(file));
        // 获取关键词坐标
        float[] xyz = PdfUtils.getKeyWords(reader,"审核:");
        if (xyz == null)
        {
            return;
        }
        System.out.println("x:"+ xyz[0]);
        System.out.println("y:"+ xyz[1]);
        System.out.println("页码:"+ xyz[2]);
        PdfStamper stamper = new PdfStamper(reader, outputStream);
        // 将印章图片放在pdf文件的第?页
        PdfContentByte over = stamper.getOverContent((int) xyz[2]);
        // 需要插入的图片
        Image contractSealImg = Image.getInstance("http://192.168.8.116:9000/erp/bpm/scms/印章.png");
        // 保存状态
        over.saveState();
        // 图片处理
        PdfGState pdfGState = new PdfGState();
        // 给图片设置透明度,一般不需要
        pdfGState.setFillOpacity(0.8F);
        over.setGState(pdfGState);
        // 设置图片位置
        contractSealImg.setAbsolutePosition(xyz[0], xyz[1]);
        // 设置图片大小
        contractSealImg.scaleAbsolute(100, 100);
        // 将图片添加到pdf文件
        over.addImage(contractSealImg);
        over.restoreState();
        stamper.setFormFlattening(true);
        // 关闭流
        stamper.close();
        reader.close();
        outputStream.close();
    }
}

参考文章:https://www.cnblogs.com/alphajuns/p/12436332.html