当前位置: 首页 > article >正文

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)…

本案例仅供学习交流使用。


http://www.kler.cn/a/377991.html

相关文章:

  • fpga 常量无法改变
  • 提高文本处理效率:精通awk命令中的$NF
  • 建立maven项目常见问题解决办法
  • angular实现list列表和翻页效果
  • WPF使用Prism框架首页界面
  • 3105. 最长的严格递增或递减子数组
  • 【ARCGIS实验】地形特征线的提取
  • Spring Boot框架下校园社团信息管理的创新实践
  • 图像识别中的高斯滤波和椒盐滤波的适用场景与不同实现
  • SpringBoot 集成 Mybatis-Plus,LambdaQueryWrapper 使用方法
  • Git 本地操作(2)
  • Razor C# 逻辑
  • -XSS-
  • Qt的程序如何打包详细教学
  • React常用前端框架合集
  • Ubuntu下安装和配置MySQL5.7教程
  • C/C++中的基本数据类型
  • Qt——QWidget
  • Java类和对象(上篇)
  • Github 2024-10-30C开源项目日报 Top10
  • 正则表达式学习
  • 【系统架构设计师】2024年上半年真题论文: 论模型驱动架构设计方法及其应用(包括解题思路和素材)
  • 操作系统——计算机系统概述——1.4操作系统结构
  • 【2】Elasticsearch 查询从基础到高级
  • jsweb2
  • Java实现动态切换ubuntu壁纸功能