自动识别 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); } } } } }