文章目录

  • 前言
  • 配置
    • 1.maven依赖
    • 2.PDFUtils
  • 使用
    • 1.Adobe Acrobat Pro DC
    • 2. 测试
    • 3. 合并

前言

最近项目需要用到有关PDF的操作,网上查了很多资料,觉得itext7比较符合我的需求,在此做一下简单地记录。

itext7相对于itext5做了很多改动,所以如果使用itext5的话本文并不适用。不过官网有着非常详细的API文档以及演示,具体可以去官网查看。

官网链接

配置

1.maven依赖

我是使用maven引入的,并且是全家桶,因为第一次使用,这样比较方便。

<!-- PDF操作,itext7全家桶 -->
<dependency><groupId>com.itextpdf</groupId><artifactId>itext7-core</artifactId><version>7.1.11</version><type>pom</type></dependency>

2.PDFUtils

封装的PDF工具类,导包直接选中itext相关的就好,注意IOException不要导itext的(第一次无脑导的后果…)

public class PDFUtils {/*** * @Title: getDefaultFont * @Description: 获取系统自带字体,如未安装可先安装或引入 * @return PdfFont* @author yanghainan* @date 2020年7月8日上午10:46:39*/public static PdfFont getDefaultFont() {try {//          return PdfFontFactory.createFont("C://windows//fonts//simsun.ttc,1", PdfEncodings.IDENTITY_H, false);// 引用系统字体return PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H", false);// 使用itext字体} catch (IOException e) {// 记录日志e.printStackTrace();}return null;}/*** * @Title: getImportFont * @Description: 获取引入的其他字体 (支持Linux系统)* @return PdfFont* @author yanghainan* @date 2020年7月8日上午10:13:01*/public static PdfFont getImportFont(String fontName) {// 获取resource下文件夹路径String path = "/template/";String fontPath = path + fontName;try {// 处理中文乱码(支持Linux系统)FontProgram fontProgram = FontProgramFactory.createFont(fontPath, false);PdfFont font = PdfFontFactory.createFont(fontProgram, PdfEncodings.IDENTITY_H, false);return font;} catch (IOException e) {// 记录日志e.printStackTrace();}return null;}/*** 替换PDF文本表单域变量* * @param templatePdfPath*            要替换的pdf全路径* @param params*            替换参数* @param destPdfPath*            替换后保存的PDF全路径* * @throws FileNotFoundException* @throws IOException*/public static final void replaceTextFieldPdf(String templatePdfPath, String destPdfPath,Map<String, String> params) {PdfDocument pdf = null;try {// 判断文件是否存在File file = new File(destPdfPath);if (!file.getParentFile().exists()) {file.getParentFile().mkdirs();}// 有参数才替换if (params != null && !params.isEmpty()) {pdf = new PdfDocument(new PdfReader(templatePdfPath), new PdfWriter(destPdfPath));PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);Map<String, PdfFormField> fields = form.getFormFields(); // 获取所有的表单域for (String param : params.keySet()) {PdfFormField formField = fields.get(param); // 获取某个表单域if (formField != null) {formField.setFont(getImportFont("SourceHanSansCN-Regular.ttf")).setValue(params.get(param)); // 替换值
//                      formField.setFont(getDefaultFont()).setValue(params.get(param)); // 替换值}}form.flattenFields();// 锁定表单,不让修改}} catch (IOException e) {e.printStackTrace();} finally {if (pdf != null) {pdf.close();}}}/*** 替换PDF图片表单域(文本)变量,1、获取表单域的大小;2、根据表单域的位置,确定图片的位置;3、如果图片的宽或者高大于表单域,则等比压缩图片。* * @param templatePdfPath*            要替换的pdf全路径* @param params*            替换参数* @param destPdfPath*            替换后保存的PDF全路径* * @throws FileNotFoundException* @throws IOException*/public static final void replaceImageFieldPdf(String templatePdfPath, String destPdfPath,Map<String, String> params) throws FileNotFoundException, IOException {PdfDocument pdf = new PdfDocument(new PdfReader(templatePdfPath), new PdfWriter(destPdfPath));if (params != null && !params.isEmpty()) {// 有参数才替换PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true);Map<String, PdfFormField> fields = form.getFormFields(); // 获取所有的表单域for (String param : params.keySet()) {PdfFormField formField = fields.get(param);if (formField != null) {replaceFieldImage(params, pdf, param, formField); // 替换图片}}form.flattenFields();// 锁定表单,不让修改}pdf.close();}/*** 替换域中的图片* * @param params* @param pdf* @param param* @param formField* @throws MalformedURLException*/private static final void replaceFieldImage(Map<String, String> params, PdfDocument pdf, String param,PdfFormField formField) throws MalformedURLException {String value = params.get(param);String[] values = value.split("\\|");Rectangle rectangle = formField.getWidgets().get(0).getRectangle().toRectangle(); // 获取表单域的xy坐标PdfCanvas canvas = new PdfCanvas(pdf.getPage(Integer.parseInt(values[0])));ImageData image = ImageDataFactory.create(values[1]);float imageWidth = image.getWidth();float imageHeight = image.getHeight();float rectangleWidth = rectangle.getWidth();float rectangleHeight = rectangle.getHeight();float tempWidth = 0;float tempHeight = 0;int result = 1; // 压缩宽度if (imageWidth > rectangleWidth) {tempHeight = imageHeight * rectangleWidth / imageWidth;if (tempHeight > rectangleHeight) {tempHeight = rectangleHeight;result = 2; // 压缩高度} else {tempWidth = rectangleWidth;tempHeight = imageHeight * rectangleWidth / imageWidth;}} else {if (imageHeight > rectangleHeight) {tempHeight = rectangleHeight;result = 2;} else {result = 3;}}float y = 0;if (result == 1) { // 压缩宽度y = rectangleHeight - tempHeight;} else if (result == 3) { // 不压缩y = rectangleHeight - imageHeight;}// y/=2; // 如果想要图片在表单域的上下对齐,这个值除以2就行。同理可以计算x的偏移if (result == 1) {canvas.addImage(image, rectangle.getX(), rectangle.getY() + y, tempWidth, false);} else if (result == 2) {canvas.addImage(image, rectangle.getX(), rectangle.getY(), tempHeight, false, false);} else if (result == 3) {canvas.addImage(image, rectangle.getX(), rectangle.getY() + y, false);}}/*** * @Title: addWatermark * @Description: 添加文字水印 * @param srcPdfPath 原文件路径* @param destPdfPath 替换后保存的PDF全路径* @param watermarkText 水印* @throws FileNotFoundException* @throws IOException void* @author yanghainan* @date 2020年7月8日上午8:48:15*/@SuppressWarnings("resource")public static final void addWatermark(String srcPdfPath, String destPdfPath, String watermarkText)throws FileNotFoundException, IOException {// 判断文件是否存在File f1 = new File(srcPdfPath);if (!f1.exists()) {return;}// 判断文件是否存在File f2 = new File(destPdfPath);if (!f2.getParentFile().exists()) {f2.getParentFile().mkdirs();}PdfDocument pdfDoc = new PdfDocument(new PdfReader(srcPdfPath), new PdfWriter(destPdfPath));pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, new IEventHandler() {@Overridepublic void handleEvent(Event event) {PdfDocumentEvent docEvent = (PdfDocumentEvent) event;PdfDocument pdfDoc = docEvent.getDocument();PdfPage page = docEvent.getPage();PdfFont font = null;font = getImportFont("STSong.ttf"); // 要显示中文水印的话,需要设置中文字体PdfCanvas canvas = new PdfCanvas(page);PdfExtGState gs1 = new PdfExtGState();gs1.setFillOpacity(0.7f); // 水印透明度canvas.setExtGState(gs1);new Canvas(canvas, pdfDoc, page.getPageSize()).setFontColor(ColorConstants.LIGHT_GRAY) // 颜色.setFontSize(60) // 字体大小.setFont(font) // 字体的格式 即导入的字体包// 水印的内容(中英文都支持) 坐标(例如:298f, 421f) 当前页数 最后的值为倾斜度(170).showTextAligned(new Paragraph(watermarkText), 298, 421, pdfDoc.getPageNumber(page),TextAlignment.CENTER, VerticalAlignment.MIDDLE, 45);}});pdfDoc.close();}/*** * @Title: pdfMerger * @Description: PDF合并 * @param paths 需要合并的所有文件路径(路径+名称)* @param outputPath 合并后的文件路径(路径+名称)*   void* @author yanghainan* @date 2020年7月3日下午3:21:00*/public static boolean pdfMerger(List<String> paths, String outputPath) {if (paths == null || paths.isEmpty() || StringUtils.isBlank(outputPath)) {return false;}// 首页与其他页创建方式不同,所以需要创建两个PdfDocument firstSourcePdf = null;PdfDocument secondSourcePdf = null;// 合并需要的工具类PdfMerger merger = null;try {for (int i = 0; i < paths.size(); i++) {if (i == 0) {PdfWriter pdfWriter = new PdfWriter(outputPath);// 启用完全压缩
//                  pdfWriter.isFullCompression();firstSourcePdf = new PdfDocument(new PdfReader(paths.get(i)), pdfWriter);merger = new PdfMerger(firstSourcePdf);continue;}secondSourcePdf = new PdfDocument(new PdfReader(paths.get(i)));merger.merge(secondSourcePdf, 1, secondSourcePdf.getNumberOfPages());secondSourcePdf.close();}return true;} catch (Exception e) {e.printStackTrace();} finally {// 关闭流if (firstSourcePdf != null) {firstSourcePdf.close();}if (secondSourcePdf != null) {secondSourcePdf.close();}if (merger != null) {merger.close();}}return false;}/*** * @Title: downPdf * @Description: 文件下载 * @param response* @param reviewName* @param outputFilePath* @return String* @author yanghainan* @date 2020年7月6日下午4:52:48*/public static String downPdf(HttpServletResponse response, String reviewName, String outputFilePath) {File file = new File(outputFilePath);if (!file.exists()) {return "下载文件不存在";}// 设置格式try {response.reset();response.setContentType("application/octet-stream");response.setCharacterEncoding("utf-8");response.setContentLength((int) file.length());response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(reviewName, "UTF-8"));} catch (UnsupportedEncodingException e1) {e1.printStackTrace();}// 文件写出try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));) {byte[] buff = new byte[1024];OutputStream os = response.getOutputStream();int i = 0;while ((i = bis.read(buff)) != -1) {os.write(buff, 0, i);os.flush();}} catch (Exception e) {return "下载失败";} finally {// 删除服务器文件forceDelete(file);}return "下载成功";}/*** * @Title: forceDelete * @Description: 强制删除文件 * @param f* @return boolean* @author yanghainan* @date 2020年7月7日下午3:05:14*/public static boolean forceDelete(File f) {boolean result = false;int tryCount = 0;while (!result && tryCount++ < 10) {//          System.gc();result = f.delete();}return result;}/*** * @Title: forceBatchDelete * @Description: 强制删除文件(批量) * @param paths* @return int* @author yanghainan* @date 2020年7月7日下午3:09:37*/public static int forceBatchDelete(List<String> paths) {if (paths == null || paths.isEmpty()) {return 0;}int result = 0;for (int i = 0; i < paths.size(); i++) {boolean delete = forceDelete(new File(paths.get(i)));if (delete) {result++;}}return result;}}

使用

1.Adobe Acrobat Pro DC

使用Adobe Acrobat Pro DC 可以很方便的设置PDF模板,这样我们只需要将数据填充进去就可以了。如果没有安装可以去我的云盘下载:

下载链接

访问码:ynj6

如下是项目中用到的一个模板:

光有模板是不够的,还需要对模板进行表单设置:

默认选择就好,成功后会变成这样:

双击字段可以修改属性:

注意这里的名称就是javaBean的属性,需要按照相对应的设置。本文工具类里使用的是Map集合,设置对应的key就好。

2. 测试

public static void main(String[] args) throws FileNotFoundException, IOException {String templatePdfPath = "F:\\PDFtemplate\\模板.pdf";String destPdfPath = "F:\\PDFtemplate\\测试.pdf";Map<String, String> params = new HashedMap();params.put("fill_5", "111");try {PDFUtils.replaceTextFieldPdf(templatePdfPath, destPdfPath, params);} catch (IOException e) {e.printStackTrace();}
}

运行后:

3. 合并

刚搞好了数据填充生成PDF,又加了个合并PDF的需求,不过好在很简单.

  • 官网Demo
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.utils.PdfMerger;import java.io.IOException;public class PdfMerge {private static final String FILE1 = "/uploads/first.pdf";private static final String FILE2 = "/uploads/second.pdf";private static final String OUTPUT_FOLDER = "/myfiles/";public static void main(String args[]) throws IOException {PdfDocument pdfDocument = new PdfDocument(new PdfReader(FILE1), new PdfWriter(OUTPUT_FOLDER + "merged.pdf"));PdfDocument pdfDocument2 = new PdfDocument(new PdfReader(FILE2));PdfMerger merger = new PdfMerger(pdfDocument);merger.merge(pdfDocument2, 1, pdfDocument2.getNumberOfPages());pdfDocument2.close();pdfDocument.close();}
}
  • 我自己写的小Demo
 private static final String FILE1 = "F:\\PDFtemplate\\测试1.pdf";private static final String FILE2 = "F:\\PDFtemplate\\测试2.pdf";private static final String FILE3 = "F:\\PDFtemplate\\测试3.pdf";private static final String OUTPUT_FOLDER = "F:\\PDFtemplate\\";public static void main(String[] args) throws FileNotFoundException, IOException {List<String> paths = new ArrayList<String>();paths.add(FILE1);paths.add(FILE2);paths.add(FILE3);PDFUtils.pdfMerger(paths, OUTPUT_FOLDER + "测试.pdf");}

具体效果就是合并为一个文件,就不再演示了。
本人也是初学,如有错漏欢迎批评指正。

在Java通过使用itext7来操作PDF相关推荐

  1. iText操作PDF之学习笔记

    iText是Java中用于创建和操作PDF文件的开源库.通过iText不仅可以生成PDF或rtf的文档,而且可以将XML.Html文件转化为PDF文件.iText的安装非常方便,下载iText.jar ...

  2. Java 使用itextPdf7操作pdf,写入照片这一篇就够了

    Java 使用itextPdf7操作pdf,写入照片这一篇就够了 1. 效果图 1.1 M*N列图片(无边界&有边界) 1.2 图片重叠 1.3 文字背景图片 1.4 图片与文字相邻 & ...

  3. java pdf 套打_itext生成发票套打(操作PDF)

    1.用Adobe Acrobat操作pdf 首先用Adobe Acrobat 在文件上添加文本域,表单>添加或编辑域>文本域,如图添加了两个文本域,名称分别是city,name java代 ...

  4. java pdf库_Java中常用的操作PDF的类库

    iText iText是一个能够快速产生PDF文件的java类库.iText的java类对于那些要产生包含文本,表格,图形的只读文档是很有用的.它的类库尤其与java Servlet有很好的给合.使用 ...

  5. java操作office和pdf文件java读取word,excel和pdf文档内容

    在平常应用程序中,对office和pdf文档进行读取数据是比较常见的功能,尤其在很多web应用程序中.所以今天我们就简单来看一下Java对word.excel.pdf文件的读取.本篇博客只是讲解简单应 ...

  6. JAVA操作pdf——创建表格

    JAVA操作pdf--创建表格 一.前言 在实习的时候遇到了需要将查询到的数据构建成为PDF的情况,于是在网上查找到了相关的Java操作pdf的教程,看到大部分的文章都是使用ITextPdf操作的,于 ...

  7. 【Java 代码实例 13】Java操作pdf的工具类itext

    目录 一.什么是iText? 二.引入jar 1.项目要使用iText,必须引入jar包 2.输出中文,还要引入下面```itext-asian.jar```包 3.设置pdf文件密码,还要引入下面` ...

  8. java 操作 PDF

    近来收到一个需求, 制作 PDF 制作发票. 类似于制作这样的发票 技术选型我选择java 在网上寻找了一些操作PDF的框架决定用iText制作, 因为它比较活跃, 而且后期做签章和插入图片二维码都有 ...

  9. java 修改pdf_Java 操作PDF书签详解 - 添加、修改、读取和删除

    目录前言 Free Spire.PDF for Java库概述和安装 给PDF文档添加书签 修改现有书签 设置PDF文档打开时展开或折叠书签 读取书签标题 从PDF文档中删除书签 前言 书签在一些PD ...

最新文章

  1. ASP.NET 3.5揭秘-读书笔记1
  2. 拨号用户如何使用局域网上的LinuxSamba服务器
  3. RMB77元实现全身VR跟踪,来自配合微软Kinect的Driver4VR
  4. 分析函数RANK的使用
  5. 图像处理理论(六)——Harris, Eigenface
  6. 吉首大学2019年程序设计竞赛-F 天花乱坠
  7. React组件-事件、状态和生命周期
  8. 排序算法(二)--选择排序法
  9. 想转行数据分析,看完这篇再做决定
  10. 即使到了 2020 年,编程语言之争仍未休!
  11. 笔记-返回到前一个页面时显示前一个页面中ajax获取的数据
  12. 【BERT】BERT中CLS效果真的好嘛?这篇文章告诉你答案
  13. 明明是旅游小程序却做起了内容电商?
  14. Android下载安装Apk
  15. C语言:数组排序(选择法排序)
  16. xtrabackup全量+增量备份
  17. NetCDF数据处理
  18. 下载人脸认证助手_认证助手最新版app_认证助手怎样认证步骤_下载人脸认证助手-多特软件站安卓网...
  19. 谷歌学术、中国知网生成参考文献
  20. 哪里才能下载到好用的CAD建筑练习图纸?

热门文章

  1. CPU,多核,多线程,并发,并行,计算效率
  2. app测试员究竟测些什么呢?
  3. 2022年的CSR和SSR
  4. Adaptive AUTOSAR (AP) 平台设计(9)——Persistency
  5. 威联通QNAP Nas同步复制文件到另外一台NAS
  6. linux安装压缩文件的工具,centos上安装rar工具
  7. 联想笔记本怎么把f1到12设置正常
  8. 如何做好开始游戏选择英雄界面[不是标题党]
  9. 第八章 定位网页元素
  10. 【产品】原型设计之Axure如何通过动态面板实现弹框