前面讲解了如何使用 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);
}
}
如果自己想定制 字体颜色和文案位置,可以仔细阅读下上面源码注释,还有前面添加水印的文章中有字体颜色的注释