自动识别 Excel 样式,转为 PDF 样式,可添加水印
import com.itextpdf.text.Font;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.interfaces.PdfViewerPreferences;
import com.itextpdf.text.pdf.internal.PdfViewerPreferencesImp;
import lombok.SneakyThrows;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.util.List;
public class ExcelToPdf {
/**
* 转换 Excel 为 PDF 文件
*
* @param workbook excel 文档
* @param outputStream pdf 输出流
* @param watermarkText1 水印文本1
* @param watermarkText2 水印文本2
*/
public static void convertExcelToPDF(XSSFWorkbook workbook, OutputStream outputStream, String watermarkText1, String watermarkText2) throws IOException, DocumentException {
if (workbook.getNumberOfSheets() <= 0) {
Document document = new Document();
PdfWriter instance = PdfWriter.getInstance(document, outputStream);
instance.setPageEvent(new WatermarkPageEvent(watermarkText1, watermarkText2));
document.open();
document.add(new Paragraph(" "));
document.close();
workbook.close();
return;
}
// 获取 Excel 列宽度(假设第一列的宽度为 PDF 页面宽度)
float excelColumnWidth = workbook.getSheetAt(0).getColumnWidth(0);
Document document = new Document(new Rectangle(excelColumnWidth, 842));
PdfWriter instance = PdfWriter.getInstance(document, outputStream);
instance.setPageEvent(new WatermarkPageEvent(watermarkText1, watermarkText2));
document.open();
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
XSSFSheet worksheet = workbook.getSheetAt(i);
// sheet 去除密码保护
worksheet.protectSheet("****");
worksheet.protectSheet(null);
createAndAddTable(worksheet, document);
if (i < workbook.getNumberOfSheets() - 1) {
document.newPage();
}
}
document.close();
workbook.close();
}
/**
* 新增表格
*
* @param worksheet Excel 工作簿
* @param document PDF 文档
*/
private static void createAndAddTable(XSSFSheet worksheet, Document document) throws DocumentException, IOException {
if (worksheet.getRow(0) == null) {
document.newPage();
document.add(new Paragraph(" "));
return;
}
// 创建表格,根据 Excel 的第一行,获取需要创建的列数
PdfPTable table = new PdfPTable(worksheet.getRow(0).getPhysicalNumberOfCells());
// 设置表格宽度
table.setWidthPercentage(100);
table.setLockedWidth(false);
// 添加表格数据
addTableData(worksheet, table);
// 合并单元格
mergeTableCell(worksheet, table);
// 将表格加入 PDF 文档
document.add(table);
}
// 合并单元格
private static void mergeTableCell(XSSFSheet worksheet, PdfPTable table) {
List<CellRangeAddress> mergedRegions = worksheet.getMergedRegions();
for (CellRangeAddress mergedRegion : mergedRegions) {
PdfPRow row = table.getRow(mergedRegion.getFirstRow());
int mergeCell = mergedRegion.getLastColumn() - mergedRegion.getFirstColumn();
// +1 是因为起始单元格占 1 个格子
row.getCells()[mergedRegion.getFirstColumn()].setColspan(mergeCell + 1);
}
}
// 获取 Excel 单元格内容
public static String getCellText(Cell cell) {
if (cell == null) {
return "";
}
String cellValue;
switch (cell.getCellTypeEnum()) {
case STRING:
cellValue = cell.getStringCellValue();
break;
case NUMERIC:
cellValue = String.valueOf(BigDecimal.valueOf(cell.getNumericCellValue()));
break;
case BLANK:
default:
cellValue = "";
break;
}
return cellValue;
}
// 添加表格数据
private static void addTableData(XSSFSheet worksheet, PdfPTable table) throws DocumentException, IOException {
for (Row row : worksheet) {
for (int i = 0; i < row.getPhysicalNumberOfCells(); i++) {
Cell cell = row.getCell(i);
if (cell == null) {
continue;
}
String cellValue = getCellText(cell);
// 创建单元格,填充文本和字体相关样式
PdfPCell cellPdf = new PdfPCell(new Phrase(cellValue, getCellStyle(cell)));
// 设置单元格背景色
setBackgroundColor(cell, cellPdf);
// 设置单元格中内容对齐方式
setCellAlignment(cell, cellPdf);
// 将单元格加入 PDF 中
table.addCell(cellPdf);
}
}
}
// 设置背景
private static void setBackgroundColor(Cell cell, PdfPCell cellPdf) {
short bgColorIndex = cell.getCellStyle().getFillForegroundColor();
// 是否自动背景色
if (bgColorIndex != IndexedColors.AUTOMATIC.getIndex()) {
XSSFColor bgColor = (XSSFColor) cell.getCellStyle().getFillForegroundColorColor();
if (bgColor != null) {
String argbHex = bgColor.getARGBHex();
int argb = (int) Long.parseLong(argbHex.substring(1), 16); // 将 hex 颜色转为 rgb
int red = (argb >> 16) & 0xFF; // 提取红色部分
int green = (argb >> 8) & 0xFF; // 提取绿色部分
int blue = argb & 0xFF; // 提取蓝色部分
cellPdf.setBackgroundColor(new BaseColor(red, green, blue));
}
}
}
// 设置单元格对齐方式
private static void setCellAlignment(Cell cell, PdfPCell cellPdf) {
CellStyle cellStyle = cell.getCellStyle();
HorizontalAlignment horizontalAlignment = cellStyle.getAlignmentEnum();
VerticalAlignment verticalAlignment = cellStyle.getVerticalAlignmentEnum();
switch (horizontalAlignment) {
case LEFT:
cellPdf.setHorizontalAlignment(Element.ALIGN_LEFT);
break;
case CENTER:
cellPdf.setHorizontalAlignment(Element.ALIGN_CENTER);
break;
case JUSTIFY:
case FILL:
cellPdf.setVerticalAlignment(Element.ALIGN_JUSTIFIED);
break;
case RIGHT:
cellPdf.setHorizontalAlignment(Element.ALIGN_RIGHT);
break;
}
switch (verticalAlignment) {
case TOP:
cellPdf.setVerticalAlignment(Element.ALIGN_TOP);
break;
case CENTER:
cellPdf.setVerticalAlignment(Element.ALIGN_MIDDLE);
break;
case JUSTIFY:
cellPdf.setVerticalAlignment(Element.ALIGN_JUSTIFIED);
break;
case BOTTOM:
cellPdf.setVerticalAlignment(Element.ALIGN_BOTTOM);
break;
}
}
// 获取单元格内容样式
private static Font getCellStyle(Cell cell) throws DocumentException, IOException {
Font font = new Font(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", true));
CellStyle cellStyle = cell.getCellStyle();
org.apache.poi.ss.usermodel.Font cellFont = cell.getSheet()
.getWorkbook()
.getFontAt(cellStyle.getFontIndex());
// 字体颜色
short fontColorIndex = cellFont.getColor();
if (fontColorIndex != IndexedColors.AUTOMATIC.getIndex() && cellFont instanceof XSSFFont) {
XSSFColor fontColor = ((XSSFFont) cellFont).getXSSFColor();
if (fontColor != null) {
byte[] rgb = fontColor.getRGB();
if (rgb != null && rgb.length == 3) {
font.setColor(new BaseColor(rgb[0] & 0xFF, rgb[1] & 0xFF, rgb[2] & 0xFF));
}
}
}
if (cellFont.getItalic()) {
font.setStyle(Font.ITALIC);
}
if (cellFont.getStrikeout()) {
font.setStyle(Font.STRIKETHRU);
}
if (cellFont.getUnderline() == 1) {
font.setStyle(Font.UNDERLINE);
}
// 设置字体大小
short fontSize = cellFont.getFontHeightInPoints();
font.setSize(fontSize);
if (cellFont.getBold()) {
font.setStyle(Font.BOLD);
}
// 设置字体
String fontName = cellFont.getFontName();
if (FontFactory.isRegistered(fontName)) {
font.setFamily(fontName);
} else {
font.setFamily("Helvetica");
}
return font;
}
}
WatermarkPageEvent 水印
import cn.hutool.core.util.StrUtil;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import lombok.SneakyThrows;
public class WatermarkPageEvent extends PdfPageEventHelper {
/**
* 水印1
*/
Phrase watermark1;
/**
* 水印2
*/
Phrase watermark2;
Font font;
@SneakyThrows
public WatermarkPageEvent(String watermarkText1, String watermarkText2) {
font = new Font(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", true), 15);
font.setColor(new BaseColor(192, 192, 192, 255));
if (StrUtil.isNotBlank(watermarkText1)) {
watermark1 = new Phrase(watermarkText1, font);
}
if (StrUtil.isNotBlank(watermarkText2)) {
watermark2 = new Phrase(watermarkText2, font);
}
}
@Override
public void onEndPage(PdfWriter writer, Document document) {
float height = document.getPageSize().getHeight();
float width = document.getPageSize().getWidth();
PdfContentByte directContentUnder = writer.getDirectContentUnder();
if (watermark1 != null) {
for (int y = 200; y <= height; y += 400) {
for (int x = 100; x <= width; x += 200) {
ColumnText.showTextAligned(directContentUnder, Element.ALIGN_CENTER, watermark1, x, y, 45);
ColumnText.showTextAligned(directContentUnder, Element.ALIGN_CENTER, watermark1, x, y, 45);
ColumnText.showTextAligned(directContentUnder, Element.ALIGN_CENTER, watermark1, x, y, 45);
}
}
}
if (watermark2 != null) {
for (int y = 180; y <= height; y += 400) {
for (int x = 110; x <= width; x += 200) {
ColumnText.showTextAligned(directContentUnder, Element.ALIGN_CENTER, watermark2, x, y, 45);
ColumnText.showTextAligned(directContentUnder, Element.ALIGN_CENTER, watermark2, x, y, 45);
ColumnText.showTextAligned(directContentUnder, Element.ALIGN_CENTER, watermark2, x, y, 45);
}
}
}
}
}