替换pdf中的文字

在项目中经常会有一种需求,给定一个pdf模板,向里面空格中填充文字。若文字长度是固定的或长度变化不大,可以直接使用pdf模板来替换;若需要替换的新文字长度变动比较大,最好的办法是先做好一个word版的目标,替换文字后再转换为pdf文件(请参考:实现Word转Pdf文件)。

下面介绍pdf文件中的文字替换的两种方法。

1.通过表单来制作pdf文档,并通过代码替换。

制作包含表单的的pdf文档需要具有编辑pdf功能的编辑软件来制作,例如祈福pdf编辑器,adobe pdf编辑器,万兴pdf编辑器等都有添加表单的功能,只是一般需要付费或开通会员,才能使用。具体制作方法可以在网上搜索或参考官方文档,这里不做介绍。下面是表单字段替换的代码,仅供参考:

    /**
     * 填充表单中的数据
     * @param template 带表单字段的pdf模板输入流
     * @param data 要填充的数据
     * @param output 填充值后的pdf输出流
     * @throws IOException 可能抛出的异常类型。
     */
    public static void fillForm(InputStream template, Map data, OutputStream output) throws IOException {
        try(PdfDocument doc = new PdfDocument(new PdfReader(template), new PdfWriter(output))){
            //设置支持汉字的字体,否则汉字不显示。
            PdfFont font = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H", false);
            //获取pdf中的表单
            PdfAcroForm form = PdfAcroForm.getAcroForm(doc,true);
            //匹配表单字段并填充对应的值
            Map fieldMap =  form.getFormFields();
            for(Map.Entry item : data.entrySet()){
                if(fieldMap.containsKey(item.getKey())){
                    fieldMap.get(item.getKey()).setFont(font).setValue(item.getValue());
                }
            }
            //使设置生效
            form.flattenFields();
        }
    }

2.通过查询文件位置来覆盖文字

这种方法比较粗暴,直接获取原文件位置,并用背景色覆盖,再在原有位置填充新文字。但原的文字并没有消失,而是被背景色隐藏了,像变色龙。而新文字就像在上面的一个图层,若选中文字并复制,会发现复制的文字还是旧文字,而不是新文字。 代码如下:

    /**
     * 替换pdf中的文本
     * @param input 原始pdf文件输入流
     * @param data 要替换的数据
     * @param output 替换后的pdf输出流
     * @throws IOException 可能抛出的异常
     */
    public static void replaceText(InputStream input, Map data, OutputStream output) throws IOException {
        try(PdfDocument pdfDocument = new PdfDocument(new PdfReader(input), new PdfWriter(output))){
            //遍历每一页
            int count =pdfDocument.getNumberOfPages();
            for(int i = 1; i <= count; i++){
                PdfPage page = pdfDocument.getPage(i);
                PdfCanvas pdfCanvas = new PdfCanvas(page);
                for(Map.Entry item : data.entrySet()){
                    //查找页中的匹配文字,并定位到位置。
                    RegexBasedLocationExtractionStrategy strategy = new RegexBasedLocationExtractionStrategy(item.getKey());
                    PdfCanvasProcessor processor = new PdfCanvasProcessor(strategy);
                    processor.processPageContent(page);
                    Collection locations = strategy.getResultantLocations();

                    for(IPdfTextLocation location : locations){
                        //用背景色覆盖原来的文字,其实是文字与背景同色,但文字还在。
                        pdfCanvas.saveState();
                        pdfCanvas.setFillColor(DeviceRgb.WHITE);
                        pdfCanvas.rectangle(location.getRectangle());
                        pdfCanvas.fill();
                        pdfCanvas.restoreState();
                        //在定位的位置填上替换的新文字,必须指定位置和字体,否则汉字不显示或显示在最底部。
                        pdfCanvas.beginText();
                        pdfCanvas.setTextMatrix(location.getRectangle().getX(), location.getRectangle().getY()+4);
                        pdfCanvas.setFontAndSize(getDefaultFont(),13);
                        pdfCanvas.showText(item.getValue());
                        pdfCanvas.endText();
                        //这是通过控件的方式替换文字,与上面方法效果一样。
//                        Canvas canvas = new Canvas(pdfCanvas,location.getRectangle());
//                        canvas.setFont(getDefaultFont());
//                        Text text = new Text(item.getValue());
//                        Paragraph paragraph = new Paragraph(text);
//                        canvas.add(paragraph);
//                        canvas.flush();
//                        canvas.close();
                    }
                }
            }
        }
    }

3.总结

这两种方法根据不同需求来选中,若对文档质量要求比较高,在商业领域最好使用表单模式,花钱买个pdf编辑器也是值得的;若对文档要求不高,或仅做展现,用覆盖的方法也可以解决。

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