Java PDF工具类(一)| 使用 itextpdf 填充PDF模板(文字和图片)
相关文章: Java PDF工具类(二)| 使用 wkhtmltox 实现 HTML转PDF(文字/图片/页眉页脚).
参考文章:https://www.cnblogs.com/wangpeng00700/p/8418594.html
这里主要使用到 itextpdf 的工具包
特点:
- 一对一,点对点的给对应的地方写值,比如模板里面放了个name标识,在程序里把“张三”赋给name,那么输出的pdf里面name的地方就变成了张三,准确方便快捷
- 支持中文,可以使用自己下载的字体。
- 支持图片:图片的大小范围可以在模板随意调,生成出来的图片不会超过范围。而且不需要根据坐标去算,程序里面自动计算的。
- 支持多页模板,即使是好几页的模板,只要每个变量对应的范围确定好了,生成出来的格式就不会错乱。
这里我下载了一个宋体的字体文件,大家可以下载进行参考(也可以使用不用字体文件的,后面看代码):
- 链接:https://pan.baidu.com/s/13i4t7R4gHOBUeh4lGzVZYg
- 提取码:s7un
效果图:
一、模板准备
1.下载编辑PDF软件(adobe_acrobat_pro),大家可自行下载,也可关注公众号:慌途L,回复:PDF编辑软件,即可拿到下载链接
下载成功,解压后双击运行安装:
2.根据work模板生成对应的PDF模板文件
1.新建一个work文档,并将其另存为为PDF格式:
2.将名称为 test2
的PDF文件用第一步安装的 Adobe Acrobat Pro
打开,进行表单的编辑和变量名的填充:
设置文本域的变量名,后期在代码中用于替换对应的值用:
也可以设置字体大小等,是否需要边框
设置图片,图片的地方没有文本域,在空白地方点击右键,选择文本域,然后就可以规定显示图片区域的大小了,最后的图片显示不会超出这个边框:
最后的结果,直接保存即可:
二、具体代码实现
1.在pom文件中引入 itextpdf
依赖
<!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
2.在F盘下放入test2.pdf文件和一张图片
3.PDFUtils:
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* PDF生成
*/
public class PDFUtil {
/** 模板路径 */
private static final String TEMPLATE_PATH = "F:\\test2.pdf";
/** 生成的新文件路径 */
private static final String NEW_PDF_PATH = "F:\\testOut1.pdf";
/**
* 判断当前系统是否是Windows系统
* @return true:Windows系统,false:Linux系统
*/
public static boolean isWindowsSystem(){
String property = System.getProperty("os.name").toLowerCase();
return property.contains("windows");
}
/**
* 填充PDF模板
* @param sourceMap 数据源Map
*/
public static void fillPDFTemplate(Map<String,Object> sourceMap) {
PdfReader reader = null;
FileOutputStream out = null;
ByteArrayOutputStream bos = null;
PdfStamper stamper;
try {
// 设置字体,解决中文问题1(推荐用第二种,不需要依赖字体文件)
// BaseFont bf = BaseFont.createFont("D:\\bb2360\\simsun.ttf" , BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
// 解决中文问题2
BaseFont bfChinese;
if(isWindowsSystem()){
bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
} else {
// 这里将simsun.ttf文件放在项目的resources/font下,也可以直接放到liunx上
bfChinese = BaseFont.createFont("font/simsun.ttf" , BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
}
Font fontText = new Font(bfChinese, 8, Font.NORMAL);
// 暂时没找到在哪里放入
// Font fontChinese = new Font(bf, 3, Font.NORMAL);
// Font font = new Font(bf, 32);
out = new FileOutputStream(NEW_PDF_PATH);// 输出流
reader = new PdfReader(TEMPLATE_PATH);// 读取pdf模板
bos = new ByteArrayOutputStream();
stamper = new PdfStamper(reader, bos);
AcroFields form = stamper.getAcroFields();
//文字类的内容处理
Map<String, String> dataMap = (Map<String,String>) sourceMap.get("dataMap");
form.addSubstitutionFont(bfChinese);
for(String key : dataMap.keySet()){
String value = dataMap.get(key);
form.setField(key, value);
}
//图片类的内容处理
Map<String, Object> imageMap = (Map<String,Object>) sourceMap.get("imageMap");
for(String key : imageMap.keySet()) {
String imgpath = imageMap.get(key).toString();
int pageNo = form.getFieldPositions(key).get(0).page;
Rectangle signRect = form.getFieldPositions(key).get(0).position;
float x = signRect.getLeft();
float y = signRect.getBottom();
//根据路径读取图片
Image image = Image.getInstance(imgpath);
//获取图片页面
PdfContentByte under = stamper.getOverContent(pageNo);
//图片大小自适应
image.scaleToFit(signRect.getWidth(), signRect.getHeight());
//添加图片
image.setAbsolutePosition(x, y);
under.addImage(image);
}
stamper.setFormFlattening(true);// 如果为false,生成的PDF文件可以编辑,如果为true,生成的PDF文件不可以编辑
stamper.close();
// 生成文件
Document doc = new Document();
PdfCopy copy = new PdfCopy(doc, out);
doc.open();
PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);
copy.addPage(importPage);
doc.close();
// 比上面生成的文件会大一点
// FileCopyUtils.copy(bos.toByteArray(), new FileOutputStream("D:\\test\\testOut2.pdf"));
} catch (IOException | DocumentException e) {
System.out.println("填充PDF异常.....");
System.out.println(e);
} finally {
try {
if(out != null){
out.close();
}
if(reader != null){
reader.close();
}
if(bos != null){
bos.close();
}
} catch (IOException e){
e.printStackTrace();
}
}
}
/**
* 填充PDF模板并返回字节流
* @param sourceMap 数据源Map
* @param inputStream PDF文件的字节流
* @return 返回填充好的PDF文件字节流
*/
public static byte[] fillPDFTemplate(Map<String,Object> sourceMap, ByteArrayInputStream inputStream) {
PdfReader reader = null;
ByteArrayOutputStream bos = null;
PdfStamper stamper;
try {
// 解决中文问题2
BaseFont bfChinese;
if(isWindowsSystem()){
bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
} else {
// 这里将simsun.ttf文件放在项目的resources/font下,也可以直接放到liunx上
bfChinese = BaseFont.createFont("font/simsun.ttf" , BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
}
Font fontText = new Font(bfChinese, 8, Font.NORMAL);
reader = new PdfReader(inputStream);// 读取pdf模板
bos = new ByteArrayOutputStream();
stamper = new PdfStamper(reader, bos);
AcroFields form = stamper.getAcroFields();
//文字类的内容处理
Map<String, String> dataMap = (Map<String,String>) sourceMap.get("dataMap");
form.addSubstitutionFont(bfChinese);
for(String key : dataMap.keySet()){
String value = dataMap.get(key);
form.setField(key, value);
}
//图片类的内容处理
Map<String, Object> imageMap = (Map<String,Object>) sourceMap.get("imageMap");
for(String key : imageMap.keySet()) {
String imgpath = imageMap.get(key).toString();
int pageNo = form.getFieldPositions(key).get(0).page;
Rectangle signRect = form.getFieldPositions(key).get(0).position;
float x = signRect.getLeft();
float y = signRect.getBottom();
//根据路径读取图片
Image image = Image.getInstance(imgpath);
//获取图片页面
PdfContentByte under = stamper.getOverContent(pageNo);
//图片大小自适应
image.scaleToFit(signRect.getWidth(), signRect.getHeight());
//添加图片
image.setAbsolutePosition(x, y);
under.addImage(image);
}
stamper.setFormFlattening(true);// 如果为false,生成的PDF文件可以编辑,如果为true,生成的PDF文件不可以编辑
stamper.close();
// 返回填充好的PDF文件字节流
return bos.toByteArray();
} catch (IOException | DocumentException e) {
System.out.println("填充PDF异常.....");
System.out.println(e);
return null;
} finally {
try {
if(reader != null){
reader.close();
}
if(bos != null){
bos.close();
}
} catch (IOException e){
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Map<String,Object> map = new HashMap<>();
map.put("name","张三");
map.put("idcard","430159189802156596");
Map<String,Object> map2 = new HashMap<>();
map2.put("image","F:\\test2.png");
Map<String,Object> formMap = new HashMap<>();
formMap.put("dataMap",map);
formMap.put("imageMap",map2);
fillPDFTemplate(formMap);
}
}
4.结果展示:
至此结束,更多的功能和优化,大家可以自行补充完整!希望能对大家有用!
注意:如果在Liunx上生成PDF后出现中文不显示,可参考以下方案
-
1.可将
simsun.ttf
字体文件放入/usr/share/fonts/
目前下 -
2.如代码里一样,将字体文件
/usr/share/fonts/
放入到项目中或者Liunx服务器上,指定文件路径即可
相关文章: Java PDF工具类(二)| 使用 wkhtmltox 实现 HTML转PDF(文字/图片/页眉页脚).
欢迎关注公众号:慌途L
后面会慢慢将文章迁移至公众号,也是方便在没有电脑的情况下可以进行翻阅,更新的话会两边同时更新,大家不用担心!