在项目中经常会有一种需求,给定一个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<String,String> 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<String, PdfFormField> fieldMap = form.getFormFields();for(Map.Entry<String,String> 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<String,String> 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<String,String> item : data.entrySet()){//查找页中的匹配文字,并定位到位置。RegexBasedLocationExtractionStrategy strategy = new RegexBasedLocationExtractionStrategy(item.getKey());PdfCanvasProcessor processor = new PdfCanvasProcessor(strategy);processor.processPageContent(page);Collection<IPdfTextLocation> 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编辑器也是值得的;若对文档要求不高,或仅做展现,用覆盖的方法也可以解决。