结合网上各路大神代码汇总而来,如果需要将pdf统一格式,可将pdf转成图片后重新转为pdf合并至一起,使用itext的PdfCanvas未成功解决该问题,主要也是因为我菜且时间紧没空查文档了。对于itext7中的添加水印的方法也没有看完,故也尝试了itext5中的合并pdf及添加水印功能。
一些小问题:
1.RandomAccessSource not opened
itext5的pdf-copy功能存在某些文件复制进pdf后进行pdfDocument.close()时出现RandomAccessSource not opened的异常提示,切换至itext7的合并尝试后,并没有出现该问题。
2.PdfReader is not opened with owner password
该问题的出现是因为pdf被加密保护,如果需要继续读取则需要加上跳过密码对应的代码
itext5:
PdfReader.unethicalreading = true;
itext7:
PdfReader reader = new PdfReader(sourceFile);
reader.setUnethicalReading(true);
一. itext7版
1.依赖
其中,itext7用于pdf合并,aspose-cells用于将excel转换为pdf,最后一个则为使用liberoffice将word、ppt、txt转换为pdf使用。
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext7-core</artifactId>
<version>7.2.4</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>com.luhuiguo</groupId>
<artifactId>aspose-cells</artifactId>
<version>23.1</version>
</dependency>
<dependency>
<groupId>com.liumapp.workable.converter</groupId>
<artifactId>workable-converter</artifactId>
<version>v1.2.0</version>
</dependency>
2.文件格式转换及合并pdf
import com.aspose.cells.License;
import com.aspose.cells.PdfSaveOptions;
import com.aspose.cells.Workbook;
import com.hfzx.web.controller.common.config.HfzxConfig;
import com.hfzx.web.controller.common.exception.CustomException;
import com.hfzx.web.controller.common.utils.StringUtils;
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.geom.PageSize;
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.pdf.canvas.PdfCanvas;
import com.itextpdf.kernel.pdf.xobject.PdfFormXObject;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.VerticalAlignment;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfGState;
import com.itextpdf.text.pdf.PdfStamper;
import com.liumapp.workable.converter.WorkableConverter;
import com.liumapp.workable.converter.core.ConvertPattern;
import com.liumapp.workable.converter.exceptions.ConvertFailedException;
import com.liumapp.workable.converter.factory.CommonConverterManager;
import com.liumapp.workable.converter.factory.ConvertPatternManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.jodconverter.document.DefaultDocumentFormatRegistry;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
/**
* 合并pdf并加上水印
* @date 2023-03-07
*/
@Slf4j
public class MergePdfUtil {
/**
* doc docx ppt pptx转pdf
*
* @param inputFile 源文件
* @param pdfFile 输出文件
*/
public static void word2PDF(String inputFile, String pdfFile) {
File file = new File(inputFile);
if (!file.exists()) {
log.error("文件不存在");
return;
}
FileInputStream is = null;
FileOutputStream os = null;
try {
WorkableConverter converter = new WorkableConverter();
ConvertPattern pattern = ConvertPatternManager.getInstance();
is = new FileInputStream(file);
os = new FileOutputStream(pdfFile);
// 处理网络文件
pattern.streamToStream(is, os);
pattern.setSrcFilePrefix(DefaultDocumentFormatRegistry.DOCX);
pattern.setDestFilePrefix(DefaultDocumentFormatRegistry.PDF);
converter.setConverterType(CommonConverterManager.getInstance());
converter.convert(pattern.getParameter());
} catch (ConvertFailedException e) {
log.error("文件:{},转换失败:{}", inputFile, e.getMessage());
} catch (FileNotFoundException e) {
log.error("文件:{}不存在或liceroffice未安装", inputFile);
} finally {
try {
is.close();
os.close();
} catch (IOException e) {
log.error("文件流关闭失败");
}
}
}
/**
* excel转pdf
*/
public static void excel2PDF(String excelPath, String pdfPath) {
File file = new File(excelPath);
if (!file.exists()) {
throw new CustomException("文件不存在");
}
// 验证License
if (!getLicense()) {
return;
}
FileInputStream fileInputStream;
try {
fileInputStream = new FileInputStream(file);
Workbook workbook = new Workbook(fileInputStream);
File pdfFile = new File(pdfPath);
PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
//把excel所有内容放在一张PDF 页面上;
pdfSaveOptions.setOnePagePerSheet(false);
//把excel所有表头放在一张pdf上
pdfSaveOptions.setAllColumnsInOnePagePerSheet(true);
FileOutputStream fileOS = new FileOutputStream(pdfFile);
workbook.save(fileOS, pdfSaveOptions);
fileInputStream.close();
fileOS.close();
} catch (Exception e) {
throw new CustomException(e.getMessage());
}
}
/***
* 图片转pdf
* @param source
* @param target
*/
public static void img2Pdf(String source, String target) {
File file = new File(source);
if (!file.exists()) {
log.error("文件不存在");
return;
}
Document document;
try {
PdfWriter writer = new PdfWriter(target);
PdfDocument pdf = new PdfDocument(writer);
document = new Document(pdf);
Image image = new Image(ImageDataFactory.create(source));
image.setAutoScale(true);
image.setAutoScaleHeight(true);
image.setAutoScaleWidth(true);
Paragraph p = new Paragraph().add(image);
document.add(p);
//关闭文档
document.close();
writer.close();
} catch (Exception e) {
log.error("图片:{},转pdf失败:{}", source, e.getMessage());
}
}
/***
* PDF文件转PNG图片,全部页数
*
* @param pdfFilePath pdf完整路径
* @param dpi dpi越大转换后越清晰,相对转换速度越慢
*/
public static List<String> pdf2Image(String pdfFilePath, int dpi) {
File file = new File(pdfFilePath);
PDDocument pdDocument = null;
List<String> imgList = new ArrayList<>();
try {
String imgPdfPath = file.getParent();
int dot = file.getName().lastIndexOf('.');
// 获取图片文件名
String imagePdfName = file.getName().substring(0, dot);
pdDocument = PDDocument.load(file);
PDFRenderer renderer = new PDFRenderer(pdDocument);
/* dpi越大转换后越清晰,相对转换速度越慢 */
StringBuffer imgFilePath;
PdfReader reader = new PdfReader(pdfFilePath);
int pages = pdDocument.getNumberOfPages();
for (int i = 0; i < pages; i++) {
String imgFilePathPrefix = imgPdfPath + File.separator + imagePdfName;
imgFilePath = new StringBuffer();
imgFilePath.append(imgFilePathPrefix);
imgFilePath.append("_");
imgFilePath.append((i + 1));
imgFilePath.append(".png");
File dstFile = new File(imgFilePath.toString());
BufferedImage image = renderer.renderImageWithDPI(i, dpi);
ImageIO.write(image, "png", dstFile);
imgList.add(imgFilePath.toString());
}
pdDocument.close();
return imgList;
} catch (IOException e) {
log.error("pdf转换图片异常:{}", e.getMessage());
}
}
/**
* 统一格式pdf
*
* @param savePath
* @param readPath
* @throws IOException
*/
public static void setPageStyle(String savePath, String readPath) {
PdfReader pdfReader = null;
PdfDocument pdfDocument = null;
PdfWriter pdfWriter = null;
PdfDocument outPDfDoc = null;
try {
pdfReader = new PdfReader(readPath);
pdfDocument = new PdfDocument(pdfReader);
pdfWriter = new PdfWriter(savePath);
outPDfDoc = new PdfDocument(pdfWriter);
outPDfDoc.setDefaultPageSize(PageSize.A4);
for (int i = 1; i < pdfDocument.getNumberOfPages() + 1; i++) {
PdfPage page = pdfDocument.getPage(i);
PdfFormXObject formXObject = page.copyAsFormXObject(outPDfDoc);
float xPercent = PageSize.A4.getWidth() / page.getPageSize().getWidth();
float yPercent = PageSize.A4.getHeight() / page.getPageSize().getHeight();
PdfCanvas pdfCanvas = new PdfCanvas(outPDfDoc.addNewPage());
pdfCanvas.addXObjectWithTransformationMatrix(formXObject, xPercent, 0, 0, yPercent, 0, 0);
}
pdfWriter.flush();
} catch (Exception e) {
log.error("转换异常:{}", e.getMessage());
} finally {
try {
if (pdfReader != null) {
pdfReader.close();
}
if (pdfDocument != null) {
pdfDocument.close();
}
if (outPDfDoc != null) {
outPDfDoc.close();
}
if (pdfWriter != null) {
pdfWriter.close();
}
} catch (IOException e) {
log.error("IO流关闭失败");
}
}
}
/***
* 合并pdf并加上水印
* @param sourceFileList 待合并文件
* @param destinationPath 合并文件输出地址
* @throws IOException
*/
public static void mergePdf(String[] sourceFileList, String destinationPath) {
File file = new File(destinationPath);
//获取父目录
File fileParent = file.getParentFile();
if (!fileParent.exists()) {
// 创建父目录文件夹
fileParent.mkdirs();
}
try {
PdfWriter writer = new PdfWriter(destinationPath);
PdfDocument writerDoc = new PdfDocument(writer);
//合并pdf
for (String sourceFile : sourceFileList) {
File readFile = new File(sourceFile);
if (!readFile.exists()) {
log.error("文件不存在:" + sourceFile);
continue;
}
PdfReader reader = new PdfReader(sourceFile);
//忽略pdf密码进行读取
reader.setUnethicalReading(true);
log.info("项目文书-读取文件:" + sourceFile);
PdfDocument readerDoc = new PdfDocument(reader);
for (int i = 1; i <= readerDoc.getNumberOfPages(); i++) {
//copy功能
PdfPage readerPage = readerDoc.getPage(i);
writerDoc.addPage(readerPage.copyTo(writerDoc));
/*//写入pdf并统一样式为A4 暂不使用
PdfPage page = readerDoc.getPage(i);
PdfFormXObject formXObject = page.copyAsFormXObject(writerDoc);
float xPercent = PageSize.A4.getWidth() / page.getPageSize().getWidth();
float yPercent = PageSize.A4.getHeight() / page.getPageSize().getHeight();
PdfCanvas pdfCanvas = new PdfCanvas(writerDoc.addNewPage());
pdfCanvas.addXObjectWithTransformationMatrix(formXObject, xPercent, 0, 0, yPercent, 0, 0);*/
}
/*//合并
PdfMerger merger = new PdfMerger(writerDoc);
merger.merge(readerDoc, 1, readerDoc.getNumberOfPages());*/
readerDoc.close();
reader.close();
}
writerDoc.close();
} catch (FileNotFoundException e) {
log.error("文件生成失败:{}", e.getMessage());
} catch (IOException e) {
log.error("文件生成失败:{}", e.getMessage());
}
}
/**
* 验证License
*
* @return
*/
private static boolean getLicense() {
boolean result = false;
try {
// license路径
InputStream license = Files.newInputStream("D:\\resource\\license.xml").toPath());
License asposeLic = new License();
asposeLic.setLicense(license);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* pdf添加水印
*
* @param inputFile 需要添加水印的文件
* @param outputFile 添加完水印的文件存放路径
* @param waterMarkName 需要添加的水印文字
* @param imgWaterMarkUrl 水印图片
* @param lastWaterMarkName 水印文字(暂定页脚左下角)
* @param pageHeader 页眉
* @param skipFirstPage 是否跳过首页
* @return
*/
public static boolean addWaterMark(String inputFile, String outputFile, String pageHeader, String waterMarkName
, String lastWaterMarkName, String imgWaterMarkUrl, boolean skipFirstPage) {
File file = new File(inputFile);
if (!file.exists()) {
return false;
}
PdfFont pdfFont = null;
try {
pdfFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H");
} catch (IOException e) {
log.error("pdf水印字体获取失败");
return false;
}
try {
FileOutputStream outputStream = new FileOutputStream(new File(outputFile));
PdfWriter pdfWriter = new PdfWriter(outputStream);
PdfDocument outDocument = new PdfDocument(pdfWriter);
PdfReader pdfReader = new PdfReader(inputFile);
PdfDocument redDocument = new PdfDocument(pdfReader);
// 添加事件,该事件拥有添加水印
outDocument.addEventHandler(PdfDocumentEvent.INSERT_PAGE, new PdfPageMarker(pdfFont, skipFirstPage));
outDocument.addEventHandler(PdfDocumentEvent.INSERT_PAGE,
new PdfWaterMarker(pdfFont, lastWaterMarkName, waterMarkName, imgWaterMarkUrl));
outDocument.addEventHandler(PdfDocumentEvent.INSERT_PAGE,
new PdfHeaderMarker(pdfFont, pageHeader, skipFirstPage));
//获取总页数
int numberOfPages = redDocument.getNumberOfPages();
for (int i = 1; i <= numberOfPages; i++) {
PdfPage page = redDocument.getPage(i);
//复制每页内容添加到新的文件中
outDocument.addPage(page.copyTo(outDocument));
}
outDocument.close();
redDocument.close();
pdfReader.close();
log.info("水印添加成功");
return true;
} catch (IOException e) {
log.error("水印生成失败");
return false;
}
}
public static void main(String[] args) {
addWaterMark("D:\\test1.pdf", "D:\\test2.pdf", "页眉", "全页水印长长长", "页尾水印", null, true);
}
}
3.添加页眉、页脚、水印,该事件不建议加在合并文件时使用,可能会出现一些文件加上水印、一些文件没加上水印的问题(我是懒狗)
对应copy来源:SpringBoot + Itext7 html转pdf 解决分页,表格被分割留出空白,水印,页眉页脚页码。_持伞走过故人路的博客-优快云博客
- 页眉
import com.hfzx.web.controller.common.utils.StringUtils;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.properties.TextAlignment;
/**
* PDF页眉
*
*/
public class PdfHeaderMarker implements IEventHandler {
private PdfFont pdfFont;
private String title;
private boolean skipFirstPage;
public PdfHeaderMarker(PdfFont pdfFont, String title, boolean skipFirstPage) {
this.pdfFont = pdfFont;
this.title = title;
this.skipFirstPage = skipFirstPage;
}
@Override
public void handleEvent(Event event) {
if (StringUtils.isNotEmpty(title)) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdf = docEvent.getDocument();
PdfPage page = docEvent.getPage();
int pageNumber = pdf.getPageNumber(page);
// 封面不展示页眉页脚
if (skipFirstPage ? pageNumber != 1 : true) {
Rectangle pageSize = page.getPageSize();
PdfCanvas pdfCanvas = new PdfCanvas(page.getLastContentStream(), page.getResources(), pdf);
Canvas canvas = new Canvas(pdfCanvas, pageSize);
float x = (pageSize.getLeft() + pageSize.getRight()) / 2;
float y = pageSize.getTop() - 25;
Paragraph p = new Paragraph(title)
.setFontSize(12)
.setFont(pdfFont);
// 顶部中间位置
canvas.showTextAligned(p, x, y, TextAlignment.CENTER);
canvas.close();
}
}
}
}
-页脚
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.properties.TextAlignment;
/**
* pdf 页脚
*
*/
public class PdfFooterMarker implements IEventHandler {
private PdfFont pdfFont;
private boolean skipFirstPage;
public PdfFooterMarker(PdfFont pdfFont, boolean skipFirstPage) {
this.pdfFont = pdfFont;
this.skipFirstPage = skipFirstPage;
}
@Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdf = docEvent.getDocument();
PdfPage page = docEvent.getPage();
int pageNumber = pdf.getPageNumber(page);
// 封面不展示页眉页脚
if (skipFirstPage ? pageNumber != 1 : true) {
pageNumber = skipFirstPage ? pageNumber - 1 : pageNumber;
Rectangle pageSize = page.getPageSize();
PdfCanvas pdfCanvas = new PdfCanvas(page.getLastContentStream(), page.getResources(), pdf);
Canvas canvas = new Canvas(pdfCanvas, pageSize);
float x = (pageSize.getLeft() + pageSize.getRight()) / 2;
float y = pageSize.getBottom() + 15;
Paragraph p = new Paragraph("第" + pageNumber + "页")
.setFontSize(12)
.setFont(pdfFont);
// 底部中间位置
canvas.showTextAligned(p, x, y, TextAlignment.CENTER);
canvas.close();
}
}
}
-水印
import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.events.Event;
import com.itextpdf.kernel.events.IEventHandler;
import com.itextpdf.kernel.events.PdfDocumentEvent;
import com.itextpdf.kernel.font.PdfFont;
import com.itextpdf.kernel.geom.Rectangle;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;
import com.itextpdf.layout.Canvas;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.VerticalAlignment;
import org.apache.commons.lang3.StringUtils;
import java.io.*;
/***
* pdf 水印
*/
public class PdfWaterMarker implements IEventHandler {
private PdfFont pdfFont;
private String waterContent;
private String waterAllContent;
private String waterImgPath;
/**
* 全页水印字体大小
*/
private static final int WATER_ALL_FONT_SIZE = 30;
/**
* 全页水印字体透明度
*/
private static float OPACITY = 0.2f;
/**
* 全页水印倾斜角度(0-360)
*/
private static int ANGLE = 120;
/**
* 数值越大每页竖向水印越少
*/
private static int HEIGHT_DENSITY = 6;
/**
* 高度倍数
*/
private static float HEIGHT_MULTIPLE = 2;
/**
* 数值越大每页横向水印越少
*/
private static int WIDTH_DENSITY = 3;
/**
* 宽度倍数
*/
private static float WIDTH_MULTIPLE = 1.5f;
public PdfWaterMarker(PdfFont pdfFont, String waterContent, String waterAllContent, String waterImgPath) {
this.pdfFont = pdfFont;
this.waterContent = waterContent;
this.waterAllContent = waterAllContent;
this.waterImgPath = waterImgPath;
}
@Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdf = docEvent.getDocument();
PdfPage page = docEvent.getPage();
Rectangle pageSize = page.getPageSize();
PdfCanvas pdfCanvas = new PdfCanvas(page.getLastContentStream(), page.getResources(), pdf);
Canvas canvas = new Canvas(pdfCanvas, pageSize);
int pageNumber = pdf.getPageNumber(page);
//页脚水印
if (StringUtils.isNotBlank(waterContent)) {
Paragraph waterMarker = new Paragraph(waterContent)
.setFont(pdfFont)
.setOpacity(.5f)
.setFontSize(13);
// 右下角位置
canvas.showTextAligned(waterMarker, pageSize.getRight() - 150,
pageSize.getBottom() + 15, pdf.getNumberOfPages(),
TextAlignment.LEFT, VerticalAlignment.BOTTOM, 0);
}
//全页水印
if (StringUtils.isNotBlank(waterAllContent)) {
Paragraph waterMarker = new Paragraph(waterAllContent)
.setFont(pdfFont)
.setOpacity(OPACITY)
.setFontSize(WATER_ALL_FONT_SIZE);
float textH = WATER_ALL_FONT_SIZE;
float textW = WATER_ALL_FONT_SIZE * waterAllContent.length();
for (float height = textH; height < page.getPageSize().getHeight() * HEIGHT_MULTIPLE;
height = height + textH * HEIGHT_DENSITY) {
for (float width = textW; width < page.getPageSize().getWidth() * WIDTH_MULTIPLE + textW;
width = width + textW * WIDTH_DENSITY) {
//第一行贴左展示
canvas.showTextAligned(waterMarker, width - textW + 5, height - textH, pdf.getNumberOfPages(),
TextAlignment.LEFT, VerticalAlignment.BOTTOM, ANGLE);
//第二行跨行展示
canvas.showTextAligned(waterMarker, width, height - textH, pdf.getNumberOfPages(),
TextAlignment.LEFT, VerticalAlignment.BOTTOM, ANGLE);
}
}
}
// 水印图片
Image waterImg = null;
if (StringUtils.isNotBlank(waterImgPath)) {
try {
InputStream inputStream = returnInputStream(waterImgPath);
if (inputStream != null) {
ImageData waterImgData = ImageDataFactory.create(toByteArray(inputStream));
waterImg = new Image(waterImgData);
}
} catch (IOException e) {
e.printStackTrace();
}
}
// 图片水印
if (waterImg != null) {
int length = waterContent.length();
// 设置坐标 X Y
waterImg.setFixedPosition(pdf.getNumberOfPages(), pageSize.getRight() - (168 + length),
pageSize.getBottom() + 30);
// 设置等比缩放
;// 自定义大小
waterImg.scaleAbsolute(100, 100);
// 写入图片水印
canvas.add(waterImg);
}
canvas.close();
}
public static byte[] toByteArray(InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
}
return output.toByteArray();
}
public static InputStream returnInputStream(String filePath) throws IOException {
File file = new File(filePath);
if (!file.exists()) {
return null;
}
InputStream inputStream = new FileInputStream(file);
return inputStream;
}
}
二、 itext5
就附个代码了,合并和水印网上都有
import com.aspose.cells.License;
import com.aspose.cells.PdfSaveOptions;
import com.aspose.cells.Workbook;
import com.hfzx.web.controller.common.config.HfzxConfig;
import com.hfzx.web.controller.common.exception.CustomException;
import com.hfzx.web.controller.common.utils.StringUtils;
import com.hfzx.web.controller.common.utils.file.FileUtils;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.liumapp.workable.converter.WorkableConverter;
import com.liumapp.workable.converter.core.ConvertPattern;
import com.liumapp.workable.converter.exceptions.ConvertFailedException;
import com.liumapp.workable.converter.factory.CommonConverterManager;
import com.liumapp.workable.converter.factory.ConvertPatternManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.jodconverter.document.DefaultDocumentFormatRegistry;
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
/**
* 合并pdf并加上水印
*
*/
@Slf4j
public class MergePDFUtilTmp {
//水印字体透明度
private static float opacity = 0.2f;
//水印字体大小
private static int fontsize = 30;
//水印倾斜角度(0-360)
private static int angle = 30;
//数值越大每页竖向水印越少
private static int heightDensity = 12;
//数值越大每页横向水印越少
private static int widthDensity = 6;
/***
* 图片
*/
public static String[] PHOTO = new String[]{
"bmp", "jpg", "jpeg", "png", "tif", "gif", "psd", "pcx", "tga", "exif", "fpx", "svg", "ai", "eps", "ufo", "dxf", "pcd", "cdr",
"raw", "wmf", "webp", "avif"};
/***
* 文档
*/
public static String[] WORD = new String[]{"doc", "docx", "txt"};
/**
* excel
*/
public static String[] EXCEL = new String[]{"xls", "xlsx"};
/**
* ppt
*/
public static String[] PPT = new String[]{"ppt", "pptx"};
public static void trans(String filePath, String pdfPath, String type) {
toPdf(filePath, pdfPath, type);
}
//转换
private static void toPdf(String filePath, String pdfPath, String type) {
if ("word".equals(type)) {
word2PDF(filePath, pdfPath);
} else if ("excel".equals(type)) {
excel2PDF(filePath, pdfPath);
} else if ("ppt".equals(type)) {
word2PDF(filePath, pdfPath);
} else if ("photo".equals(type)) {
convert(filePath, pdfPath);
}
}
private static void word2PDF(String inputFile, String pdfFile) {
File file = new File(inputFile);
if (!file.exists()) {
return;
}
FileInputStream is = null;
FileOutputStream os = null;
try {
WorkableConverter converter = new WorkableConverter();
ConvertPattern pattern = ConvertPatternManager.getInstance();
is = new FileInputStream(file);
os = new FileOutputStream(pdfFile);
// 处理网络文件
pattern.streamToStream(is, os);
pattern.setSrcFilePrefix(DefaultDocumentFormatRegistry.DOCX);
pattern.setDestFilePrefix(DefaultDocumentFormatRegistry.PDF);
converter.setConverterType(CommonConverterManager.getInstance());
boolean result = converter.convert(pattern.getParameter());
} catch (ConvertFailedException e) {
log.error("文件转换失败");
} catch (FileNotFoundException e) {
log.error("文件不存在或liberoffice不存在");
} finally {
try {
is.close();
os.close();
} catch (IOException e) {
log.error("文件流关闭失败");
}
}
}
public static void excelFirstHandel(String excelPath, String pdfPath) {
// 获取图片文件名
String tempPdfPath = pdfPath.substring(0, pdfPath.lastIndexOf(".")) + "temp.pdf";
excel2PDF(excelPath, tempPdfPath);
String img = pdf2Image(tempPdfPath, 100);
if (StringUtils.isNotEmpty(img)) {
convert(img, pdfPath);
FileUtils.deleteFile(img);
}
}
public static void excel2PDF(String excelPath, String pdfPath) {
File file = new File(excelPath);
if (!file.exists()) {
return;
}
// 验证License
if (!getLicense()) {
return;
}
FileInputStream fileInputStream;
try {
fileInputStream = new FileInputStream(file);
Workbook workbook = new Workbook(fileInputStream);
File pdfFile = new File(pdfPath);
PdfSaveOptions pdfSaveOptions = new PdfSaveOptions();
//把excel所有内容放在一张PDF 页面上;
pdfSaveOptions.setOnePagePerSheet(false);
//把excel所有表头放在一张pdf上
pdfSaveOptions.setAllColumnsInOnePagePerSheet(true);
FileOutputStream fileOS = new FileOutputStream(pdfFile);
workbook.save(fileOS, pdfSaveOptions);
fileInputStream.close();
fileOS.close();
} catch (Exception e) {
log.error(e.getMessage());
}
}
/***
* PDF文件转PNG图片,全部页数
*
* @param pdfFilePath pdf完整路径
* @param dpi dpi越大转换后越清晰,相对转换速度越慢
*/
public static String pdf2Image(String pdfFilePath, int dpi) {
File file = new File(pdfFilePath);
PDDocument pdDocument = null;
try {
String imgPdfPath = file.getParent();
int dot = file.getName().lastIndexOf('.');
// 获取图片文件名
String imagePdfName = file.getName().substring(0, dot);
pdDocument = PDDocument.load(file);
PDFRenderer renderer = new PDFRenderer(pdDocument);
/* dpi越大转换后越清晰,相对转换速度越慢 */
StringBuffer imgFilePath;
// PdfReader reader = new PdfReader(pdfFilePath);
// int pages = reader.getNumberOfPages();
// for (int i = 0; i < pages; i++) {
// String imgFilePathPrefix = imgPdfPath + File.separator + imagePdfName;
// imgFilePath = new StringBuffer();
// imgFilePath.append(imgFilePathPrefix);
// imgFilePath.append("_");
// imgFilePath.append((i + 1));
// imgFilePath.append(".png");
// File dstFile = new File(imgFilePath.toString());
// BufferedImage image = renderer.renderImageWithDPI(i, dpi);
// ImageIO.write(image, "png", dstFile);
// }
String imgFilePathPrefix = imgPdfPath + File.separator + imagePdfName;
imgFilePath = new StringBuffer();
imgFilePath.append(imgFilePathPrefix);
imgFilePath.append(".png");
File dstFile = new File(imgFilePath.toString());
BufferedImage image = renderer.renderImageWithDPI(0, dpi);
ImageIO.write(image, "png", dstFile);
pdDocument.close();
return imgFilePath.toString();
} catch (IOException e) {
throw new CustomException(e.getMessage());
}
}
private static boolean getLicense() {
boolean result = false;
try {
// license路径
InputStream license = Files.newInputStream(new File(HfzxConfig.getDownloadPath() + "resource/license.xml").toPath());
License aposeLic = new License();
aposeLic.setLicense(license);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
//图片转pdf
public static void convert(String source, String target) {
File file = new File(source);
if (!file.exists()) {
return;
}
Document document = new Document();
//设置文档页边距
document.setMargins(40, 57, 5, 57);
FileOutputStream fos = null;
try {
fos = new FileOutputStream(target);
PdfWriter.getInstance(document, fos);
//打开文档
document.open();
//获取图片的宽高
Image image = Image.getInstance(source);
float imageHeight = image.getScaledHeight();
float imageWidth = image.getScaledWidth();
// 设置图片自适应页面宽高
Rectangle pageSize = document.getPageSize();
float width = pageSize.getWidth();
float height = pageSize.getHeight();
float wSize = imageWidth / width;
if (wSize > 1f) {
image.scaleAbsolute(imageWidth / wSize, imageHeight / wSize);
}
float hSize = image.getScaledHeight()/height;
if (hSize > 1f) {
image.scaleAbsolute(image.getScaledWidth() / hSize, image.getScaledHeight() / hSize);
}
//图片居中
image.setAlignment(Image.ALIGN_CENTER);
//新建一页添加图片
document.newPage();
document.add(image);
} catch (Exception ioe) {
log.error("图片不存在");
} finally {
//关闭文档
document.close();
try {
fos.flush();
fos.close();
} catch (IOException e) {
log.error("文件流关闭失败");
}
}
}
public static boolean mergePdfFiles(String[] files, String newfile) {
boolean retValue = false;
Document document = null;
PdfReader first = null;
//跳过密码
PdfReader.unethicalreading = true;
// 临时生成文件路径
File f = new File(newfile);
//获取父目录
File fileParent = f.getParentFile();
if (!fileParent.exists()) {
// 创建父目录文件夹
fileParent.mkdirs();
}
try {
first = new PdfReader(files[0]);
document = new Document(first.getPageSize(1));
PdfCopy copy = new PdfCopy(document, new FileOutputStream(newfile));
document.open();
for (int i = 0; i < files.length; i++) {
File c = new File(files[i]);
if (!c.exists()) {
log.error("文件不存在:" + files[i]);
continue;
}
PdfReader reader = null;
try {
reader = new PdfReader(files[i]);
int n = reader.getNumberOfPages();
for (int j = 1; j <= n; j++) {
document.newPage();
PdfImportedPage page = copy.getImportedPage(reader, j);
copy.addPage(page);
}
log.info("文件合并成功:" + files[i]);
reader.close();
} catch (IOException e) {
e.printStackTrace();
log.error("存在无法复制文件:{},对应文件目录:{}", e.getMessage(), files[i]);
} finally {
if (null != reader) {
reader.close();
}
if (null != first) {
first.close();
}
}
}
retValue = true;
} catch (Exception e) {
log.error("合并文件失败:" + e.getMessage());
} finally {
if (null != document) {
document.close();
}
if (null != first) {
first.close();
}
}
return retValue;
}
/**
* pdf添加水印
*
* @param inputFile 需要添加水印的文件
* @param outputFile 添加完水印的文件存放路径
* @param waterMarkName 需要添加的水印文字
* @param cover 是否覆盖
* @return
*/
public static boolean addWaterMark(String inputFile, String outputFile, String waterMarkName, boolean cover) {
if (!cover) {
File file = new File(outputFile);
if (file.exists()) {
return true;
}
}
File file = new File(inputFile);
if (!file.exists()) {
return false;
}
PdfReader reader = null;
PdfStamper stamper = null;
try {
reader = new PdfReader(inputFile);
stamper = new PdfStamper(reader, new FileOutputStream(outputFile));
BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
Rectangle pageRect = null;
PdfGState gs = new PdfGState();
//这里是透明度设置
gs.setFillOpacity(opacity);
//这里是条纹不透明度
gs.setStrokeOpacity(0.2f);
int total = reader.getNumberOfPages() + 1;
System.out.println("Pdf页数:" + reader.getNumberOfPages());
JLabel label = new JLabel();
FontMetrics metrics;
int textH = 0;
int textW = 0;
label.setText(waterMarkName);
metrics = label.getFontMetrics(label.getFont());
//字符串的高, 只和字体有关
textH = metrics.getHeight();
//字符串的宽
textW = metrics.stringWidth(label.getText());
PdfContentByte under;
//循环PDF,每页添加水印
for (int i = 1; i < total; i++) {
pageRect = reader.getPageSizeWithRotation(i);
//在内容上方添加水印
under = stamper.getOverContent(i);
under.saveState();
under.setGState(gs);
under.beginText();
//这里是水印字体大小
under.setFontAndSize(base, fontsize);
for (int height = textH; height < pageRect.getHeight() * 2; height = height + textH * heightDensity) {
for (int width = textW; width < pageRect.getWidth() * 1.5 + textW; width = width + textW * widthDensity) {
// rotation:倾斜角度
under.showTextAligned(Element.ALIGN_LEFT, waterMarkName, width - textW, height - textH, angle);
}
}
//添加水印文字
under.endText();
}
System.out.println("添加水印成功!");
return true;
} catch (IOException e) {
log.error("添加水印失败!错误信息为: " + e);
return false;
} catch (DocumentException e) {
log.error("添加水印失败!错误信息为: " + e);
return false;
} finally {
//关闭流
if (stamper != null) {
try {
stamper.close();
} catch (DocumentException e) {
log.error("文件流关闭失败");
} catch (IOException e) {
log.error("文件流关闭失败");
}
}
if (reader != null) {
reader.close();
}
}
}
}