开发环境
| 名称 | 版本 |
|---|---|
| 操作系统 | Windows 10 X64 |
| JDK | JDK1.8(jdk-8u151-windows-x64) |
| IntelliJ IDEA | IntelliJ IDEA 2022.3 |
| Maven | Maven 3.9.4 |
参考及重要说明
因为 iText 有版权问题导致不能继续使用,所以使用 OpenPDF 来替换 iText 相关功能。
pom.xml
<!--Open PDF --><dependency><groupId>com.github.librepdf</groupId><artifactId>openpdf</artifactId><version>1.3.34</version></dependency><dependency><groupId>com.github.librepdf</groupId><artifactId>openpdf-fonts-extra</artifactId><version>1.3.34</version></dependency><!--PDF 加密--><dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-ext-jdk15on</artifactId><version>1.47</version></dependency>
PDF 参数类-PDFParamsDTO
PDF 工具类-PDFMakerUtil
package com.atguigu.boot3.actuator.util;import com.atguigu.boot3.actuator.dto.PDFParamsDTO;import com.lowagie.text.Element;import com.lowagie.text.Rectangle;import com.lowagie.text.pdf.*;import lombok.Data;import lombok.extern.slf4j.Slf4j;import javax.swing.*;import java.awt.*;import java.io.ByteArrayOutputStream;import java.io.FileOutputStream;import java.io.File;import java.io.InputStream;import io.micrometer.common.util.StringUtils;import java.nio.file.Files;import java.nio.file.Paths;/*** OpenPDF 生成类* - luoma - 2024年6月25日11:26:38*/@Data@Slf4jpublic class OpenPDFMakerUtil {/*** 使用 OpenPDF 给 PDF 文件添加水印,旋转,透明度,密码** @param pdfParams PDF 参数类* @return 添加水印后的 PDF 文件字节数组(添加到本地的情况为空)*/public static byte[] addWatermarkAuto(PDFParamsDTO pdfParams) {String methodName = "addWatermarkAuto >> OpenPDF 添加水印 >> ";//返回结果byte[] byteArray = null;try {log.info("{}开始调用 >> 入参:【pdfParams = {}】", methodName, pdfParams);//坐标float x = pdfParams.getX();float y = pdfParams.getY();float angle = pdfParams.getAngle();//文字颜色int r = pdfParams.getR();int g = pdfParams.getG();int b = pdfParams.getB();RGBColor fontColor = new RGBColor(r, g, b);//文字大小int fontSize = pdfParams.getDefaultFontSize();//文字内容// 使用"||"将内容进行分割String waterMarkName = pdfParams.getWatermark();String[] waterMarkContents = waterMarkName.split("\\|\\|");//获取水印文字的最大高度和宽度int textH = 0, textW = 0;for (String waterMarkContent : waterMarkContents) {JLabel label = new JLabel();label.setText(waterMarkContent);FontMetrics metrics = label.getFontMetrics(label.getFont());if (textH < metrics.getHeight()) {textH = metrics.getHeight();}if (textW < metrics.stringWidth(label.getText())) {textW = metrics.stringWidth(label.getText());}}//设置输入,输出PdfReader reader;PdfStamper stamper;ByteArrayOutputStream outputStream = new ByteArrayOutputStream();if (pdfParams.getGenerateToLocal()) {//输入目录String inputFile = pdfParams.getTemplatePath();//输出目录String outputFile = pdfParams.getFileDirectory();//设置输入,输出reader = new PdfReader(inputFile);stamper = new PdfStamper(reader, Files.newOutputStream(Paths.get(outputFile)));} else {//设置输入,输出InputStream inputStream = pdfParams.getInputStream();reader = new PdfReader(inputStream);stamper = new PdfStamper(reader, outputStream);}// 设置密码文件打开密码文件编辑密码byte[] arrUserPassword = null;byte[] arrOwnerPassword = null;if (StringUtils.isNotBlank(pdfParams.getUserPassword())) {arrUserPassword = pdfParams.getUserPassword().getBytes();}if (StringUtils.isNotBlank(pdfParams.getOwnerPassword())) {arrOwnerPassword = pdfParams.getOwnerPassword().getBytes();}if (StringUtils.isNotBlank(pdfParams.getUserPassword()) || StringUtils.isNotBlank(pdfParams.getOwnerPassword())) {stamper.setEncryption(arrUserPassword, arrOwnerPassword, PdfWriter.ALLOW_PRINTING, false);}//设置字体BaseFont baseFont = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);// 获取总页数 +1, 下面从1开始遍历int total = reader.getNumberOfPages() + 1;PdfContentByte under;for (int i = 1; i < total; i++) {// 在内容上方加水印under = stamper.getOverContent(i);// 在内容下方加水印//under = stamper.getUnderContent(i);under.saveState();under.beginText();under.setFontAndSize(baseFont, fontSize);//文字加粗//设置文本描边宽度//under.setLineWidth(0.3);//设置文本为描边模式, 会导致 setColorFill 颜色失效//under.setTextRenderingMode(PdfContentByte.TEXT_RENDER_MODE_FILL_STROKE);//字体颜色under.setColorFill(fontColor);// 设置透明度PdfGState gs = new PdfGState();gs.setFillOpacity(pdfParams.getFillOpacity());under.setGState(gs);//水印字体和大小Rectangle pageRect = reader.getPageSizeWithRotation(i);int width1 = (int) pageRect.getWidth();int height1 = (int) pageRect.getHeight();//fontSize = (width1 + height1) / pdfParams.getDefaultFontSize();x = (float) (width1) / 2;y = (float) height1 / 2;// 将分段的字段进行输出编写for (int z = 0; z < waterMarkContents.length; z++) {//文字String itemWaterMark = waterMarkContents[z];// 间隔距离(参数可调节)int interval = fontSize * z;under.showTextAligned(Element.ALIGN_CENTER, itemWaterMark, x, y - (interval + textH * z), angle);}// 添加水印文字under.endText();}stamper.close();reader.close();//outputStream 转换为 byteByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();outputStream.writeTo(byteArrayOutputStream);byteArray = byteArrayOutputStream.toByteArray();log.info("{}结束调用,返回结果:{}", methodName, "OK");} catch (Exception e) {log.error("{}调用异常 >> 入参:【pdfParams = {}】,e:", methodName, pdfParams, e);}return byteArray;}}
测试代码及结果
参考:测试代码及结果