apache pdfbox 设置PDF表单域,Java生成PDF模板简单案例。
1. 编辑模板PDF
1.1 编辑内容
描述:打开用WPS打开需要编辑的PDF模板,编辑内容。
1.2 编辑表单
1.3 添加表单域
描述:添加表单域,并给各个表单域命名,本案例表单域命名为x1,x2,x3,读者可以自行修改,退出编辑保存即可。
1.4 存在水印
描述:由于没有WPS会员,所以存在试用水印,通过java工具去掉即可。
2. 项目结构
2.1 pom.xml
<!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>3.0.2</version>
</dependency>
2.2 ClearWaterMarksUtils.java
package org.liberx;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.io.RandomAccessReadBuffer;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* 清除 PDF 文件中的水印的工具类。
* 此类使用 Apache PDFBox 库加载 PDF 文档并移除其水印。
* 水印通过用空白图像替换原有图像来清除。
*/
public class ClearWaterMarksUtils {
/**
* 程序的入口点。
* 加载指定路径的 PDF 文件,清除水印并保存为新的 PDF 文件。
*
* @param args 命令行参数,当前未使用
*/
public static void main(String[] args) {
try {
// 加载 PDF 文档
RandomAccessReadBuffer readPdf = new RandomAccessReadBuffer(ClearWaterMarksUtils.class.getResourceAsStream("/edit.pdf"));
PDDocument document = Loader.loadPDF(readPdf);
// 清除水印
checkTextWatermark(document);
// 保存修改后的 PDF路径
document.save("无水印.pdf");
document.close();
} catch (IOException e) {
// 处理 IO 异常
throw new RuntimeException(e);
}
}
/**
* 检查并移除 PDF 文档中的文本水印。
* 此方法会遍历 PDF 文档的每一页,并用空白图像替换所有图像对象,
* 从而有效地去除水印。
*
* @param document 需要处理的 PDF 文档
* @throws IOException 如果在处理文档时发生 IO 异常
*/
private static void checkTextWatermark(PDDocument document) throws IOException {
// 在内存中创建一个空白图像并验证其创建
BufferedImage emptyImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
if (emptyImage.getWidth() != 1 || emptyImage.getHeight() != 1) {
throw new IOException("未能创建内存图像。");
}
// 将空白图像写入字节数组输出流
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(emptyImage, "png", byteArrayOutputStream);
byte[] imageData = byteArrayOutputStream.toByteArray();
// 验证图像数据长度
if (imageData.length == 0) {
throw new IOException("图像数据为空,未能创建内存图像。");
}
// 从内存图像数据创建 PDImageXObject
PDImageXObject blankImageXObject = PDImageXObject.createFromByteArray(document, imageData, "empty");
if (blankImageXObject.getWidth() == 0 || blankImageXObject.getHeight() == 0) {
throw new IOException("未能从内存图像数据创建 PDImageXObject。");
}
// 用空白图像替换 PDF 页面中的每个图像
for (PDPage page : document.getPages()) {
PDResources resources = page.getResources();
for (COSName name : resources.getXObjectNames()) {
resources.put(name, blankImageXObject); // 替换图像
System.out.println("在页面上用空白图像替换了图像。");
}
}
}
}
2.3 去除水印
操作: 运行ClearWaterMarksUtils的main方法,会生成如下无水印文件。
2.4 验证水印是否去除成功
描述:通过WPS打开无水印.pdf发现水印已经消失。
2.5 移动无水印.pdf位置
描述:移动到resources根目录下,因为我都是通过类加载pdf和font文件。
2.6 ModifyPDFForm.java
package org.liberx;
import org.apache.fontbox.ttf.OTFParser;
import org.apache.fontbox.ttf.OpenTypeFont;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.io.RandomAccessRead;
import org.apache.pdfbox.io.RandomAccessReadBuffer;
import org.apache.pdfbox.pdfwriter.compress.CompressParameters;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDField;
import org.apache.pdfbox.pdmodel.interactive.form.PDTextField;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 修改 PDF 表单中的字段内容的工具类。
* 此类使用 Apache PDFBox 库加载 PDF 文档,修改表单字段的内容,并嵌入自定义字体。
*/
public class ModifyPDFForm {
public static void dealPdf(String readPath, String outputPath,String fontPath,Map<String,String>fieldContentMap) {
// 尝试加载 PDF 文档并修改表单字段
try (
// 使用随机访问读取 PDF 文件
RandomAccessRead readPdf = new RandomAccessReadBuffer(ModifyPDFForm.class.getResourceAsStream(readPath));
PDDocument document = Loader.loadPDF(readPdf) // 加载 PDF 文档
) {
// 获取 PDF 表单
PDAcroForm pdfForm = document.getDocumentCatalog().getAcroForm();
if (pdfForm != null) {
// 加载并嵌入字体
try (RandomAccessRead readFont = new RandomAccessReadBuffer(ModifyPDFForm.class.getResourceAsStream(fontPath))) {
/* OpenTypeFont otfFont = new OTFParser().parse(readFont); // 解析 OTF 字体
PDFont font = PDType0Font.load(document, otfFont, false); // 加载 OTF 字体*/
PDFont font = PDType0Font.load(document,readFont, false,false); //加载ttf
// 设置默认字体资源
PDResources resources = new PDResources();
resources.put(COSName.getPDFName("F1"), font); // 将字体添加到资源中
pdfForm.setDefaultResources(resources); // 设置 PDF 表单的默认字体资源
// 遍历所有表单字段并设置新内容
for (PDField field : pdfForm.getFields()) {
// 检查字段是否在定义的内容映射中
if (fieldContentMap.containsKey(field.getFullyQualifiedName())) {
if (field instanceof PDTextField) { // 确保字段是文本字段
PDTextField textField = (PDTextField) field;
// 设置文本字段的外观和内容
textField.setDefaultAppearance("/F1 12 Tf 0 g"); // 设置字体和字号
textField.setValue(fieldContentMap.get(field.getFullyQualifiedName())); // 设置字段值
textField.setReadOnly(true); // 将字段设置为只读
}
}
}
} catch (IOException e) {
System.err.println("加载字体时出错: " + e.getMessage()); // 输出字体加载错误信息
}
} else {
System.out.println("PDF 表单未找到!"); // 如果没有找到表单
}
// 保存修改后的 PDF
document.save(outputPath, CompressParameters.NO_COMPRESSION); // 不压缩保存 PDF
System.out.println("PDF 保存成功!"); // 输出保存成功信息
} catch (IOException e) {
System.out.println(e.getMessage()); // 输出 IO 异常信息
}
}
public static void main(String[] args) {
String filePath = "/无水印.pdf"; // PDF 文件路径
String outputPath = "填充.pdf"; // 输出文件路径
String fontPath = "/fonts/SourceHanSans-Regular.ttf";
// 定义表单字段和对应的新内容
Map<String, String> fieldContentMap = new HashMap<>();
fieldContentMap.put("x1", "测试一下"); // 中文内容
fieldContentMap.put("x2", "テスト"); // 日文内容
fieldContentMap.put("x3", "대한민국English123456789"); // 韩文、英文、数字内容
dealPdf(filePath,outputPath,fontPath,fieldContentMap);
}
}
2.7 查看填充表单域结果
描述:填充表单域文件。
描述:通过WPS查看填充结果。
3 字体
source-han-sans-ttf
NotoSansCJKkr-Regular.otf
描述:字体只是测试字体,还是需要自行查找合适的字体,比较容易出现下面的错误。
Exception in thread “main” java.lang.IllegalArgumentException: No glyph for U+B300 (대) in font SourceHanSansCN-Regular
at org.apache.pdfbox.pdmodel.font.PDCIDFontType2.encode(PDCIDFontType2.java:404)…
本案例仅供学习交流使用。