前面讲解了如何使用 itextpdf7 给 PDF 添加水印,本次如何合并多个 PDF 文件为一个,在 itextpdf7 中代码非常简单
// ~ pdf ==========================implementation 'com.itextpdf:itext7-core:7.1.16'implementation 'cn.hutool:hutool-all:5.5.4'
合并 PDF 文件
package cn.mrcode;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.FileNotFoundException;import java.io.IOException;import java.util.ArrayList;import java.util.List;/*** @author mrcode* @date 2022/1/21 20:28*/public class Pdf7Demo {public static void main(String[] args) throws IOException {final List<String> list = new ArrayList<>();list.add("C:/pdf/1.pdf");list.add("C:/pdf/2.pdf");final String toFile = "C:/pdf/result.pdf";mergePdfFiles(list, toFile);}/*** 合并多个 PDF 文件为一个* @param list 要合并的 PDF 文件绝对路径列表* @param toFile 合并后的 PDF 文件绝对路径* @throws IOException*/public static void mergePdfFiles(List<String> list, String toFile) throws IOException {final PdfDocument toPdf = new PdfDocument(new PdfWriter(toFile));PdfMerger merger = new PdfMerger(toPdf);for (String file : list) {final PdfDocument pdfDocument = new PdfDocument(new PdfReader(file));merger.merge(pdfDocument, 1, pdfDocument.getNumberOfPages());pdfDocument.close();}merger.close();toPdf.close();}}
给 pdf 添加页码
前面合并代码很简单,但是添加页码就要稍微复杂点了,其实在前面添加水印的时候已经使用过这个功能了,添加页面无非就是需要自己计算一些信息:
- 当前页
- 总页数
- 生成页码文案,比如 1/100
- 将文案添加到 PDF 指定位置
从这个流程来看,前面添加水印的时候其实已经做过了第 4 个步骤。所以这就简单了,自己使用水印的代码改一改就可以了
package cn.mrcode.pdf;import com.itextpdf.io.font.PdfEncodings;import com.itextpdf.io.font.constants.StandardFonts;import com.itextpdf.kernel.font.PdfFont;import com.itextpdf.kernel.font.PdfFontFactory;import com.itextpdf.kernel.geom.Rectangle;import com.itextpdf.kernel.pdf.PdfDocument;import com.itextpdf.kernel.pdf.PdfPage;import com.itextpdf.kernel.pdf.PdfReader;import com.itextpdf.kernel.pdf.PdfWriter;import com.itextpdf.layout.Document;import com.itextpdf.layout.element.Paragraph;import com.itextpdf.layout.property.TextAlignment;import com.itextpdf.layout.property.VerticalAlignment;import java.io.IOException;import cn.hutool.core.util.StrUtil;/*** @author mrcode* @date 2022/1/21 20:27*/public class PDFUtil {/*** 添加页码; 在右下角添加** @param fontSize 文字大小,一般为 15 比较合适* @param srcPath 原始 PDF 文件绝对路径* @param destPath 添加完水印后的 PDF 存放路径*/public static void addPageNumber(int fontSize, String srcPath, String destPath) throws IOException {PdfDocument pdfDoc = new PdfDocument(new PdfReader(srcPath), new PdfWriter(destPath));Document doc = new Document(pdfDoc);PdfFont font = getPdfFont(null);// 文字高度则是字体大小final float textHeight = fontSize;final int numberOfPages = pdfDoc.getNumberOfPages();for (int i = 1; i <= numberOfPages; i++) {PdfPage pdfPage = pdfDoc.getPage(i);// 获取页面大小,考虑页面旋转Rectangle pageSize = pdfPage.getPageSizeWithRotation();// 当页面有旋转时,内容自动旋转pdfPage.setIgnorePageRotationForContent(true);// 构建页码final String text = StrUtil.format("{}/{}", i, numberOfPages);Paragraph paragraph = new Paragraph(text).setFont(font).setFontSize(fontSize);// 获取文字宽度final float textWidth = font.getWidth(text, fontSize);// 计算添加的位置坐标// 定位到水平垂直居中// float x = (pageSize.getLeft() + pageSize.getRight()) / 2;// 定位到右侧:根据文字宽度减少宽度,能动态的根据文字宽度调整,让文字不会超出屏幕外面float x = pageSize.getRight() - textWidth;// bottom 是 0,+ 20 就是底部往上 20// 定位到底部:根据文字高度动态往上调整,不会超出屏幕外面;float y = pageSize.getBottom() + textHeight + 10;// 参数分别为:文本、x 坐标、y 坐标、添加到底几页、文本水平对齐方式、文本垂直对齐方式、旋转弧度doc.showTextAligned(paragraph,x, // 文本所在 x y 坐标,文字将围绕这个点进行对齐或则旋转y,i, // 添加到 PDF 第几页TextAlignment.CENTER, // 文本水平对齐方式VerticalAlignment.TOP, // 文本垂直对齐方式// 将 角度 转换为 弧度(float) Math.toRadians(0));}doc.close();}/*** 获取字体,支持 afm、pfm、ttf、otf、woff、woff2 字体,ttc 目前直接报错** @param fontPath 字体文件绝对路径,如果为空则返回默认的英文字体* @return*/private static PdfFont getPdfFont(String fontPath) throws IOException {if (fontPath == null) {return PdfFontFactory.createFont(StandardFonts.HELVETICA);}return PdfFontFactory.createFont(fontPath,// 水平书写PdfEncodings.IDENTITY_H,// 是否将字体嵌入到目标文档中: 如果可能,嵌入字体PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);}}
生成效果
最终工具类
package cn.mrcode.pdf;import com.itextpdf.io.font.PdfEncodings;import com.itextpdf.io.font.constants.StandardFonts;import com.itextpdf.kernel.font.PdfFont;import com.itextpdf.kernel.font.PdfFontFactory;import com.itextpdf.kernel.geom.Rectangle;import com.itextpdf.kernel.pdf.PdfDocument;import com.itextpdf.kernel.pdf.PdfPage;import com.itextpdf.kernel.pdf.PdfReader;import com.itextpdf.kernel.pdf.PdfWriter;import com.itextpdf.kernel.utils.PdfMerger;import com.itextpdf.layout.Document;import com.itextpdf.layout.element.Paragraph;import com.itextpdf.layout.property.TextAlignment;import com.itextpdf.layout.property.VerticalAlignment;import java.io.IOException;import java.util.List;import cn.hutool.core.util.StrUtil;/*** @author mrcode* @date 2022/1/21 20:27*/public class PDFUtil {/*** 合并多个 PDF 文件为一个** @param list 要合并的 PDF 文件绝对路径列表* @param toFile 合并后的 PDF 文件绝对路径* @throws IOException*/public static void merge(List<String> list, String toFile) throws IOException {final PdfDocument toPdf = new PdfDocument(new PdfWriter(toFile));PdfMerger merger = new PdfMerger(toPdf);for (String file : list) {final PdfDocument pdfDocument = new PdfDocument(new PdfReader(file));merger.merge(pdfDocument, 1, pdfDocument.getNumberOfPages());pdfDocument.close();}merger.close();toPdf.close();}/*** 添加页码; 在右下角添加** @param fontSize 文字大小,一般为 15 比较合适* @param srcPath 原始 PDF 文件绝对路径* @param destPath 添加完水印后的 PDF 存放路径*/public static void addPageNumber(int fontSize, String srcPath, String destPath) throws IOException {PdfDocument pdfDoc = new PdfDocument(new PdfReader(srcPath), new PdfWriter(destPath));Document doc = new Document(pdfDoc);PdfFont font = getPdfFont(null);// 文字高度则是字体大小final float textHeight = fontSize;final int numberOfPages = pdfDoc.getNumberOfPages();for (int i = 1; i <= numberOfPages; i++) {PdfPage pdfPage = pdfDoc.getPage(i);// 获取页面大小,考虑页面旋转Rectangle pageSize = pdfPage.getPageSizeWithRotation();// 当页面有旋转时,内容自动旋转pdfPage.setIgnorePageRotationForContent(true);// 构建页码final String text = StrUtil.format("{}/{}", i, numberOfPages);Paragraph paragraph = new Paragraph(text).setFont(font).setFontSize(fontSize);// 获取文字宽度final float textWidth = font.getWidth(text, fontSize);// 计算添加的位置坐标// 定位到水平垂直居中// float x = (pageSize.getLeft() + pageSize.getRight()) / 2;// 定位到右侧:根据文字宽度减少宽度,能动态的根据文字宽度调整,让文字不会超出屏幕外面float x = pageSize.getRight() - textWidth;// bottom 是 0,+ 20 就是底部往上 20// 定位到底部:根据文字高度动态往上调整,不会超出屏幕外面;float y = pageSize.getBottom() + textHeight + 10;// 参数分别为:文本、x 坐标、y 坐标、添加到底几页、文本水平对齐方式、文本垂直对齐方式、旋转弧度doc.showTextAligned(paragraph,x, // 文本所在 x y 坐标,文字将围绕这个点进行对齐或则旋转y,i, // 添加到 PDF 第几页TextAlignment.CENTER, // 文本水平对齐方式VerticalAlignment.TOP, // 文本垂直对齐方式// 将 角度 转换为 弧度(float) Math.toRadians(0));}doc.close();}/*** 获取字体,支持 afm、pfm、ttf、otf、woff、woff2 字体,ttc 目前直接报错** @param fontPath 字体文件绝对路径,如果为空则返回默认的英文字体* @return*/private static PdfFont getPdfFont(String fontPath) throws IOException {if (fontPath == null) {return PdfFontFactory.createFont(StandardFonts.HELVETICA);}return PdfFontFactory.createFont(fontPath,// 水平书写PdfEncodings.IDENTITY_H,// 是否将字体嵌入到目标文档中: 如果可能,嵌入字体PdfFontFactory.EmbeddingStrategy.PREFER_EMBEDDED);}}
如果自己想定制 字体颜色和文案位置,可以仔细阅读下上面源码注释,还有前面添加水印的文章中有字体颜色的注释
