itext7 获取pdf关键字坐标并进行替换

最近项目中有个需求,那就是对pdf文档中的关键字内容进行随意替换,百度跟谷歌上面查了一些资料,已经有大佬给出了该需求的解决方案,目前市面上操作pdf文件使用的比较多的就是itextpdfbox,而且解决的方案都是一样的。

说什么itext本身不提供内容替换功能,其实itext7是提供了内容替换功能的,只是我在做的时候遇到了一些问题,就是文档上面没有的字符替换后会以空格的方式展现出来,有兴趣的同学可以去看看。下面这个就是itext7内容替换的例子。

https://itextpdf.com/en/resources/examples/itext-7/replacing-pdf-objects

需要用到背景遮盖,然后再背景上面继续填写要替换的内容,具体解决方案分为下面这几步

  • 找到关键字的坐标位置
  • 将关键字坐标设置白色的背景,因为pdf的背景都是白色的
  • 将需要替换的关键字填充到白色背景上面

通过上面这几步我们就达到了所谓的替换功能。下面给个效果图

源文件

itext7 获取pdf关键字坐标并进行替换_第1张图片

替换后的文件

itext7 获取pdf关键字坐标并进行替换_第2张图片

核心代码

public class ReplaceUtils {

    public static void doOverText(OverTextDTO overTextDTO) throws IOException {

        Map<String,String> keyMap = new HashMap<String, String>();

        //为key自动加上占位符并转义
        for(String key : overTextDTO.getReplaceMap().keySet()) {
            keyMap.put(key,"\\$\\{" + key + "\\}");
        }
        List<List<OverAreaDTO>> lists =
                getTextPosition(overTextDTO.getSourceFilePath(),overTextDTO.getFinishFilePath(),keyMap,overTextDTO.getReplaceMap());

        overText(overTextDTO.getSourceFilePath(),overTextDTO.getFinishFilePath(),lists,overTextDTO.getFont());
    }

    /**
     * 获取关键字的坐标
     * @param keyMap
     * @return
     */
    public static  List<List<OverAreaDTO>> getTextPosition(String sourcePath,String finishPath, Map<String,String> keyMap,Map<String,String> replaceMap) throws IOException {

        PdfReader reader = new PdfReader(sourcePath);
        PdfDocument pdfDocument = new PdfDocument(reader, new PdfWriter(finishPath));

        List<List<OverAreaDTO>> list = new ArrayList<List<OverAreaDTO>>();

        for (int i = 1; i <= pdfDocument.getNumberOfPages(); i++) {


            List<OverAreaDTO> overAreaDTOS = new ArrayList<OverAreaDTO>();

            for (String key  : keyMap.keySet()) {

                PdfPage page = pdfDocument.getPage(i);

                RegexBasedLocationExtractionStrategy strategy = new RegexBasedLocationExtractionStrategy(keyMap.get(key));
                PdfCanvasProcessor canvasProcessor = new PdfCanvasProcessor(strategy);
                canvasProcessor.processPageContent(page);
                Collection<IPdfTextLocation> resultantLocations = strategy.getResultantLocations();
                PdfCanvas pdfCanvas = new PdfCanvas(page);
                pdfCanvas.setLineWidth(0.5f);

                for (IPdfTextLocation location : resultantLocations) {
                    Rectangle rectangle = location.getRectangle();
                    pdfCanvas.rectangle(rectangle);
                    pdfCanvas.setStrokeColor(ColorConstants.RED);
                    pdfCanvas.stroke();

                    OverAreaDTO overAreaDTO = new OverAreaDTO();
                    overAreaDTO.setPageNum(location.getPageNumber());
                    overAreaDTO.setX(rectangle.getX());
                    overAreaDTO.setY(rectangle.getY());
                    overAreaDTO.setWidth(rectangle.getWidth());
                    overAreaDTO.setHeight(rectangle.getHeight());
                    overAreaDTO.setKey(key);
                    overAreaDTO.setValue(replaceMap.get(key));
                    overAreaDTOS.add(overAreaDTO);
                }
            }

            list.add(overAreaDTOS);
        }
        pdfDocument.close();

        return list;
    }

    /**
     * 覆盖原有的内容 并填充新内容
     *
     * @param sourcePath 源文件
     * @param finishPath 替换后的文件
     * @param list
     */
    public static void overText(String sourcePath,String finishPath,List<List<OverAreaDTO>> list,PdfFont font) throws IOException {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(sourcePath), new PdfWriter(finishPath));
        //pdfDoc.getFirstPage().newContentStreamAfter() 会覆盖掉字体
        //pdfDoc.getFirstPage().newContentStreamBefore() 只会在字体的下层添加一个背景色
        for (int i = 1; i <= pdfDoc.getNumberOfPages(); i++) {
            PdfCanvas canvas = new PdfCanvas(pdfDoc.getPage(i).newContentStreamAfter(),
                    pdfDoc.getPage(i).getResources(), pdfDoc);

            canvas.saveState();
            List<OverAreaDTO> overAreaDTOS = list.get(i-1);
            //用白色背景覆盖原本的字体
            for (OverAreaDTO overArea :overAreaDTOS) {
                canvas.setFillColor(ColorConstants.WHITE);
                //覆盖的时候y + 0.35   填充字体的时候 + 1.5 主要就是避免覆盖占位符下面的线
                canvas.rectangle(overArea.getX(), overArea.getY() + 0.35, overArea.getWidth(), overArea.getHeight());
            }
            canvas.fill();
            canvas.restoreState();

            //填充新内容
            canvas.beginText();
            for (OverAreaDTO overArea :overAreaDTOS) {
                canvas.setFontAndSize(font,overArea.getHeight());
                canvas.setTextMatrix(overArea.getX(),overArea.getY() + 1.5f);
                canvas.newlineShowText(overArea.getValue());
            }
            canvas.endText();
        }

        pdfDoc.close();

    }
}

项目源码:https://github.com/niezhiliang/itext-pdf-replace

你可能感兴趣的:(java,itext7)