java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java Excel转Pdf的多种方式

Java多种方式实现Excel转Pdf的保姆级教程

作者:暗武逢天

在企业级系统使用或日常使用中,我们经常使用excel表格数据进行浏览数据,但有时候我们会想要将excel转换成pdf进行预览使用,本篇博文以java进行编写多种实现方式实现多sheet页excel转换一个pdf的需求,需要的朋友可以参考下

需求介绍

在企业级系统使用或日常使用中,我们经常使用excel表格数据进行浏览数据,但有时候我们会想要将excel转换成pdf进行预览使用,这时就需要进行程序编写实现这个需求,本篇博文以java进行编写多种实现方式实现多sheet页excel转换一个pdf的需求

itextpdf实现

引入maven依赖

引入所需依赖,下面五个是主要依赖

        <dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>4.1.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>4.1.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml-schemas</artifactId>
			<version>4.1.0</version>
		</dependency>
		<dependency>
			<groupId>com.itextpdf</groupId>
			<artifactId>itextpdf</artifactId>
			<version>5.5.13</version>
		</dependency>
		<dependency>
			<groupId>com.itextpdf</groupId>
			<artifactId>itext-asian</artifactId>
			<version>5.2.0</version>
		</dependency>

具体哪几个博主忘了,如果上面依赖导入后写代码还有缺失的,可以直接把下面完整的都copy下

        <dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
		</dependency>
		<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
			<version>1.10</version>
		</dependency>
		<dependency>
			<groupId>commons-io</groupId>
			<artifactId>commons-io</artifactId>
			<version>2.4</version>
		</dependency>
		<dependency>
			<groupId>dom4j</groupId>
			<artifactId>dom4j</artifactId>
			<version>1.6.1</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>4.1.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>4.1.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml-schemas</artifactId>
			<version>4.1.0</version>
		</dependency>
		<dependency>
			<groupId>com.itextpdf</groupId>
			<artifactId>itextpdf</artifactId>
			<version>5.5.13</version>
		</dependency>
		<dependency>
			<groupId>com.itextpdf</groupId>
			<artifactId>itext-asian</artifactId>
			<version>5.2.0</version>
		</dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.27</version>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
            <scope>provided</scope>
        </dependency>

代码实现

由于在使用时,有时候excel里会插入图片,所以我们在转换时候需要考虑到图片的业务

先对图片类型进行建模处理

import java.io.Serializable;

/**
 * 图片信息
 */
public class PicturesInfo implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 最小行
     */
    private int minRow;

    /**
     * 最大行
     */
    private int maxRow;

    /**
     * 最小列
     */
    private int minCol;

    /**
     * 最大列
     */
    private int maxCol;

    /**
     * 扩展
     */
    private String ext;

    /**
     * 图片数据
     */
    private byte[] pictureData;

    public int getMinRow() {
        return minRow;
    }

    public PicturesInfo setMinRow(int minRow) {
        this.minRow = minRow;
        return this;
    }

    public int getMaxRow() {
        return maxRow;
    }

    public PicturesInfo setMaxRow(int maxRow) {
        this.maxRow = maxRow;
        return this;
    }

    public int getMinCol() {
        return minCol;
    }

    public PicturesInfo setMinCol(int minCol) {
        this.minCol = minCol;
        return this;
    }

    public int getMaxCol() {
        return maxCol;
    }

    public PicturesInfo setMaxCol(int maxCol) {
        this.maxCol = maxCol;
        return this;
    }

    public String getExt() {
        return ext;
    }

    public PicturesInfo setExt(String ext) {
        this.ext = ext;
        return this;
    }

    public byte[] getPictureData() {
        return pictureData;
    }

    public PicturesInfo setPictureData(byte[] pictureData) {
        this.pictureData = pictureData;
        return this;
    }
}

书写转换工具类

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.List;

/**
 * Excel转PDF
 * @author 廖航
 * @date 2024-08-29 10:52
 */
//@UtilityClass
//@Slf4j
public class ExcelToPdfUtil {

    /**
     * 日志输出
     */
//    private static final log log = log.getlog(ExcelToPdfUtil.class);

    /**
     * 单元格队列
     */
    static Set<String> cellSet = new HashSet<>();

    /**
     * Excel转PDF
     *
     * @param excelPath Excel文件路径
     * @param pdfPath PDF文件路径
     * @param excelSuffix Excel文件后缀
     */
    public static void excelToPdf(String excelPath, String pdfPath, String excelSuffix) {
        try (InputStream in = Files.newInputStream(Paths.get(excelPath));
             OutputStream out = Files.newOutputStream(Paths.get(pdfPath))) {
            ExcelToPdfUtil.excelToPdf(in, out, excelSuffix);
        } catch (Exception e) {

        }
    }

    /**
     * Excel转PDF并写入输出流
     *
     * @param inStream    Excel输入流
     * @param outStream   PDF输出流
     * @param excelSuffix Excel类型 .xls 和 .xlsx
     * @throws Exception 异常信息
     */
    public static void excelToPdf(InputStream inStream, OutputStream outStream, String excelSuffix) throws Exception {


        // 输入流转workbook,获取sheet  读取Excel文件
        Workbook workbook = getPoiWorkbookByFileStream(inStream, excelSuffix);
        //设置pdf纸张大小 PageSize.A4 A4横向
//        Document document = new Document(PageSize.B0);
        Document document = new Document(PageSize.A2.rotate());
//        绑定PDF写入器到输出流
        PdfWriter.getInstance(document, outStream);
        // 设置页面四周边距
        document.setMargins(50, 50, 30, 30);
        document.open(); // 准备开始写入内容
        //设置基本字体
        BaseFont baseFont = BaseFont.createFont("C:\\Windows\\Fonts\\simsun.ttc,0", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
        for (int j = 0; j < workbook.getNumberOfSheets(); j++) {
            if(j != 0) {
                document.newPage(); // 新的Sheet开始新的一页
            }
            //获取sheet
            Sheet sheet = workbook.getSheetAt(j);

            // 获取列宽度占比
            float[] widths = getColWidth(sheet);
            PdfPTable table = new PdfPTable(widths);
            // 设置表格宽度为页面内容区域的百分比
            table.setWidthPercentage(100);

            int colCount = widths.length;
            // 遍历行
            for (int rowIndex = sheet.getFirstRowNum(); rowIndex <= sheet.getLastRowNum(); rowIndex++) {
                Row row = sheet.getRow(rowIndex);
                if (Objects.isNull(row)) {
                    // 插入空对象
                    for (int i = 0; i < colCount; i++) {
                        table.addCell(createPdfPCell(null, 0, 11f, null));
                    }
                } else {
                    // 遍历单元格
                    for (int columnIndex = 0; (columnIndex < row.getLastCellNum() || columnIndex < colCount) && columnIndex > -1; columnIndex++) {
                        PdfPCell pCell = excelCellToPdfCell(sheet, row.getCell(columnIndex), baseFont);
                        // 是否合并单元格
                        if (isMergedRegion(sheet, rowIndex, columnIndex)) {
                            int[] span = getMergedSpan(sheet, rowIndex, columnIndex);
                            //忽略合并过的单元格
                            boolean mergedCell = span[0] == 1 && span[1] == 1;
                            if (mergedCell) {
                                continue;
                            }
                            pCell.setRowspan(span[0]);
                            pCell.setColspan(span[1]);
                        }

                        table.addCell(pCell);
                    }
                }
            }

            document.add(table);
        }
        document.close();

    }


    protected static CellRangeAddress getColspanRowspanByExcel(int rowIndex, int colIndex,Sheet sheet) {
        CellRangeAddress result = null;
        int num = sheet.getNumMergedRegions();
        for (int i = 0; i < num; i++) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            if (range.getFirstColumn() == colIndex && range.getFirstRow() == rowIndex) {
                result = range;
            }
        }
        return result;
    }

    // 获取Workbook对象
    public static Workbook getPoiWorkbookByFileStream(InputStream inputStream, String excelSuffix) throws IOException {
        if (excelSuffix.endsWith(".xlsx")) {
            return new XSSFWorkbook(inputStream);
        } else {
            return new HSSFWorkbook(inputStream);
        }
    }

    /**
     * 单元格转换,poi cell 转换为 itext cell
     *
     * @param sheet     poi sheet页
     * @param excelCell poi 单元格
     * @param baseFont  基础字体
     * @return PDF单元格
     */
    private static PdfPCell excelCellToPdfCell(Sheet sheet, Cell excelCell, BaseFont baseFont) throws Exception {
        if (Objects.isNull(excelCell)) {
            return createPdfPCell(null, 0, 11f, null);
        }
        int rowIndex = excelCell.getRowIndex();
        int columnIndex = excelCell.getColumnIndex();
        // 图片信息
        List<PicturesInfo> infos = getAllPictureInfos(sheet, rowIndex, rowIndex, columnIndex, columnIndex, false);
        PdfPCell pCell;
        if (infos != null && !infos.isEmpty()) {
            Image image = Image.getInstance(infos.get(0).getPictureData());
            // 调整图片大小
            image.scaleAbsolute(527, 215);
            pCell = new PdfPCell(image);
        } else {
            Font excelFont = getExcelFont(sheet, excelCell);
            //设置单元格字体
            com.itextpdf.text.Font pdFont = new com.itextpdf.text.Font(baseFont, excelFont.getFontHeightInPoints(), excelFont.getBold() ? 1 : 0, BaseColor.BLACK);
            Integer border = hasBorder(excelCell) ? null : 0;
            String excelCellValue = getExcelCellValue(excelCell);
            pCell = createPdfPCell(excelCellValue, border, excelCell.getRow().getHeightInPoints(), pdFont);
        }
        // 水平居中
        pCell.setHorizontalAlignment(getHorAlign(excelCell.getCellStyle().getAlignment().getCode()));
        // 垂直对齐
        pCell.setVerticalAlignment(getVerAlign(excelCell.getCellStyle().getVerticalAlignment().getCode()));
        return pCell;
    }


    /**
     * 创建itext pdf 单元格
     *
     * @param content       单元格内容
     * @param border        边框
     * @param minimumHeight 高度
     * @param pdFont        字体
     * @return pdf cell
     */
    private static PdfPCell createPdfPCell(String content, Integer border, Float minimumHeight, com.itextpdf.text.Font pdFont) {
        String contentValue = content == null ? "" : content;
        com.itextpdf.text.Font pdFontNew = pdFont == null ? new com.itextpdf.text.Font() : pdFont;
        PdfPCell pCell = new PdfPCell(new Phrase(contentValue, pdFontNew));
        if (Objects.nonNull(border)) {
            pCell.setBorder(border);
        }
        if (Objects.nonNull(minimumHeight)) {
            //设置单元格的最小高度
            pCell.setMinimumHeight(minimumHeight);

        }

        return pCell;
    }

    /**
     * excel垂直对齐方式映射到pdf对齐方式
     *
     * @param align 对齐
     * @return 结果
     */
    private static int getVerAlign(int align) {
        switch (align) {
            case 2:
                return com.itextpdf.text.Element.ALIGN_BOTTOM;
            case 3:
                return com.itextpdf.text.Element.ALIGN_TOP;
            default:
                return com.itextpdf.text.Element.ALIGN_MIDDLE;
        }
    }

    /**
     * excel水平对齐方式映射到pdf水平对齐方式
     *
     * @param align 对齐
     * @return 结果
     */
    private static int getHorAlign(int align) {
        switch (align) {
            case 1:
                return com.itextpdf.text.Element.ALIGN_LEFT;
            case 3:
                return com.itextpdf.text.Element.ALIGN_RIGHT;
            default:
                return com.itextpdf.text.Element.ALIGN_CENTER;
        }
    }

    /*============================================== POI获取图片及文本内容工具方法 ==============================================*/

    /**
     * 获取字体
     *
     * @param sheet excel 转换的sheet页
     * @param cell  单元格
     * @return 字体
     */
    private static Font getExcelFont(Sheet sheet, Cell cell) {
        // xls
        if (sheet instanceof HSSFSheet) {
            Workbook workbook = sheet.getWorkbook();
            return ((HSSFCell) cell).getCellStyle().getFont(workbook);
        }
        // xlsx
        return ((XSSFCell) cell).getCellStyle().getFont();
    }

    /**
     * 判断excel单元格是否有边框
     *
     * @param excelCell 单元格
     * @return 结果
     */
    private static boolean hasBorder(Cell excelCell) {
        CellStyle style = excelCell.getCellStyle();

        BorderStyle top = style.getBorderTop();
        BorderStyle bottom = style.getBorderBottom();
        BorderStyle left = style.getBorderLeft();
        BorderStyle right = style.getBorderRight();

        return top != BorderStyle.NONE ||
                bottom != BorderStyle.NONE ||
                left != BorderStyle.NONE ||
                right != BorderStyle.NONE;
    }

    /**
     * 判断单元格是否是合并单元格
     *
     * @param sheet 表
     * @param row 行
     * @param column 列
     * @return 结果
     */
    private static boolean isMergedRegion(Sheet sheet, int row, int column) {
        int sheetMergeCount = sheet.getNumMergedRegions();
        for (int i = 0; i < sheetMergeCount; i++) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            int firstColumn = range.getFirstColumn();
            int lastColumn = range.getLastColumn();
            int firstRow = range.getFirstRow();
            int lastRow = range.getLastRow();
            if (row >= firstRow && row <= lastRow) {
                if (column >= firstColumn && column <= lastColumn) {
                    return true;
                }
            }
        }
        return false;
    }



    /**
     * 计算合并单元格合并的跨行跨列数
     *
     * @param sheet 表
     * @param row 行
     * @param column 列
     * @return 结果
     */
    private static int[] getMergedSpan(Sheet sheet, int row, int column) {
        int sheetMergeCount = sheet.getNumMergedRegions();
        int[] span = {1, 1};
        for (int i = 0; i < sheetMergeCount; i++) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            int firstColumn = range.getFirstColumn();
            int lastColumn = range.getLastColumn();
            int firstRow = range.getFirstRow();
            int lastRow = range.getLastRow();
            if (firstColumn == column && firstRow == row) {
                span[0] = lastRow - firstRow + 1;
                span[1] = lastColumn - firstColumn + 1;
                break;
            }
        }
        return span;
    }

    /**
     * 获取excel中每列宽度的占比
     *
     * @param sheet 表
     * @return 结果
     */
    private static float[] getColWidth(Sheet sheet) {
        int rowNum = getMaxColRowNum(sheet);
        Row row = sheet.getRow(rowNum);
        int cellCount = row.getPhysicalNumberOfCells();
        int[] colWidths = new int[cellCount];
        int sum = 0;

        for (int i = row.getFirstCellNum(); i < cellCount; i++) {
            Cell cell = row.getCell(i);
            if (cell != null) {
                colWidths[i] = sheet.getColumnWidth(i);
                sum += sheet.getColumnWidth(i);
            }
        }

        float[] colWidthPer = new float[cellCount];
        for (int i = row.getFirstCellNum(); i < cellCount; i++) {
            colWidthPer[i] = (float) colWidths[i] / sum * 100;
        }
        return colWidthPer;
    }

    /**
     * 获取excel中列数最多的行号
     *
     * @param sheet 表
     * @return 结果
     */
    private static int getMaxColRowNum(Sheet sheet) {
        int rowNum = 0;
        int maxCol = 0;
        for (int r = sheet.getFirstRowNum(); r < sheet.getPhysicalNumberOfRows(); r++) {
            Row row = sheet.getRow(r);
            if (row != null && maxCol < row.getPhysicalNumberOfCells()) {
                maxCol = row.getPhysicalNumberOfCells();
                rowNum = r;
            }
        }
        return rowNum;
    }

    /**
     * poi 根据单元格类型获取单元格内容
     *
     * @param excelCell poi单元格
     * @return 单元格内容文本
     */
    public static String getExcelCellValue(Cell excelCell) {
//        if (excelCell == null) {
//            return "";
//        }
//        // 判断数据的类型
//        CellType cellType = excelCell.getCellType();
//
//        if (cellType == CellType.STRING) {
//            return excelCell.getStringCellValue();
//        }
//        if (cellType == CellType.BOOLEAN) {
//            return String.valueOf(excelCell.getBooleanCellValue());
//        }
//        if (cellType == CellType.FORMULA) {
//            return excelCell.getCellFormula();
//        }
//        if (cellType == CellType.NUMERIC) {
//            // 处理日期格式、时间格式
//            if (DateUtil.isCellDateFormatted(excelCell)) {
//                SimpleDateFormat sdf;
//                // 验证short值
//                if (excelCell.getCellStyle().getDataFormat() == 14) {
//                    sdf = new SimpleDateFormat("yyyy/MM/dd");
//                } else if (excelCell.getCellStyle().getDataFormat() == 21) {
//                    sdf = new SimpleDateFormat("HH:mm:ss");
//                } else if (excelCell.getCellStyle().getDataFormat() == 22) {
//                    sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
//                } else {
//                    throw new RuntimeException("日期格式错误!!!");
//                }
//                Date date = excelCell.getDateCellValue();
//                return sdf.format(date);
//            } else if (excelCell.getCellStyle().getDataFormat() == 0) {
//                //处理数值格式
//                DataFormatter formatter = new DataFormatter();
//                return formatter.formatCellValue(excelCell);
//            }
//        }
//        if (cellType == CellType.ERROR) {
//            return "非法字符";
//        }
//        return "";
        if (excelCell == null) {
            return "";
        }

        DataFormatter formatter = new DataFormatter();
        return formatter.formatCellValue(excelCell);
    }


    /**
     * 根据sheet和单元格信息获取图片
     *
     * @param sheet        sheet表
     * @param minRow       最小行
     * @param maxRow       最大行
     * @param minCol       最小列
     * @param maxCol       最大列
     * @param onlyInternal 是否内部
     * @return 图片集合
     * @throws Exception 异常
     */
    public static List<PicturesInfo> getAllPictureInfos(Sheet sheet, Integer minRow, Integer maxRow, Integer minCol,
                                                        Integer maxCol, boolean onlyInternal) throws Exception {
        if (sheet instanceof HSSFSheet) {
            return getXLSAllPictureInfos((HSSFSheet) sheet, minRow, maxRow, minCol, maxCol, onlyInternal);
        } else if (sheet instanceof XSSFSheet) {
            return getXLSXAllPictureInfos((XSSFSheet) sheet, minRow, maxRow, minCol, maxCol, onlyInternal);
        } else {
            throw new Exception("未处理类型,没有为该类型添加:GetAllPicturesInfos()扩展方法!");
        }
    }

    /**
     * 获取XLS图片信息
     *
     * @param sheet 表
     * @param minRow 最小行
     * @param maxRow 最大行
     * @param minCol 最小列
     * @param maxCol 最大列
     * @param onlyInternal 只在内部
     * @return 图片信息列表
     */
    private static List<PicturesInfo> getXLSAllPictureInfos(HSSFSheet sheet, Integer minRow, Integer maxRow,
                                                            Integer minCol, Integer maxCol, Boolean onlyInternal) {
        List<PicturesInfo> picturesInfoList = new ArrayList<>();
        HSSFShapeContainer shapeContainer = sheet.getDrawingPatriarch();
        if (shapeContainer == null) {
            return picturesInfoList;
        }
        List<HSSFShape> shapeList = shapeContainer.getChildren();
        for (HSSFShape shape : shapeList) {
            if (shape instanceof HSSFPicture && shape.getAnchor() instanceof HSSFClientAnchor) {
                HSSFPicture picture = (HSSFPicture) shape;
                HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();

                if (isInternalOrIntersect(minRow, maxRow, minCol, maxCol, anchor.getRow1(), anchor.getRow2(),
                        anchor.getCol1(), anchor.getCol2(), onlyInternal)) {
//                    String item = StrUtil.format("{},{},{},{}", anchor.getRow1(), anchor.getRow2(), anchor.getCol1(), anchor.getCol2());
                    String item = String.format("%d,%d,%d,%d",
                            anchor.getRow1(),
                            anchor.getRow2(),
                            anchor.getCol1(),
                            anchor.getCol2());
                    if (cellSet.contains(item)) {
                        continue;
                    }
                    cellSet.add(item);
                    HSSFPictureData pictureData = picture.getPictureData();
                    picturesInfoList.add(new PicturesInfo()
                            .setMinRow(anchor.getRow1())
                            .setMaxRow(anchor.getRow2())
                            .setMinCol(anchor.getCol1())
                            .setMaxCol(anchor.getCol2())
                            .setPictureData(pictureData.getData())
                            .setExt(pictureData.getMimeType()));
                }
            }
        }
        return picturesInfoList;
    }

    /**
     * 获取XLSX图片信息
     *
     * @param sheet 表
     * @param minRow 最小行
     * @param maxRow 最大行
     * @param minCol 最小列
     * @param maxCol 最大列
     * @param onlyInternal 只在内部
     * @return 图片信息列表
     */
    private static List<PicturesInfo> getXLSXAllPictureInfos(XSSFSheet sheet, Integer minRow, Integer maxRow,
                                                             Integer minCol, Integer maxCol, Boolean onlyInternal) {
        List<PicturesInfo> picturesInfoList = new ArrayList<>();

        List<POIXMLDocumentPart> documentPartList = sheet.getRelations();
        for (POIXMLDocumentPart documentPart : documentPartList) {
            if (documentPart instanceof XSSFDrawing) {
                XSSFDrawing drawing = (XSSFDrawing) documentPart;
                List<XSSFShape> shapes = drawing.getShapes();
                for (XSSFShape shape : shapes) {
                    if (shape instanceof XSSFPicture) {
                        XSSFPicture picture = (XSSFPicture) shape;
                        XSSFClientAnchor anchor = picture.getPreferredSize();

                        if (isInternalOrIntersect(minRow, maxRow, minCol, maxCol, anchor.getRow1(), anchor.getRow2(),
                                anchor.getCol1(), anchor.getCol2(), onlyInternal)) {
//                            String item = StrUtil.format("{},{},{},{}", anchor.getRow1(), anchor.getRow2(), anchor.getCol1(), anchor.getCol2());
                            String item = String.format("%d,%d,%d,%d",
                                    anchor.getRow1(),
                                    anchor.getRow2(),
                                    anchor.getCol1(),
                                    anchor.getCol2());
                            if (cellSet.contains(item)) {
                                continue;
                            }
                            cellSet.add(item);
                            XSSFPictureData pictureData = picture.getPictureData();
                            picturesInfoList.add(new PicturesInfo()
                                    .setMinRow(anchor.getRow1())
                                    .setMaxRow(anchor.getRow2())
                                    .setMinCol(anchor.getCol1())
                                    .setMaxCol(anchor.getCol2())
                                    .setPictureData(pictureData.getData())
                                    .setExt(pictureData.getMimeType()));
                        }
                    }
                }
            }
        }

        return picturesInfoList;
    }

    /**
     * 是内部的或相交的
     *
     * @param rangeMinRow 最小行范围
     * @param rangeMaxRow 最大行范围
     * @param rangeMinCol 最小列范围
     * @param rangeMaxCol 最大列范围
     * @param pictureMinRow 图片最小行
     * @param pictureMaxRow 图片最大行
     * @param pictureMinCol 图片最小列
     * @param pictureMaxCol 图片最大列
     * @param onlyInternal 只在内部
     * @return 结果
     */
    private static boolean isInternalOrIntersect(Integer rangeMinRow, Integer rangeMaxRow, Integer rangeMinCol,
                                                 Integer rangeMaxCol, int pictureMinRow, int pictureMaxRow, int pictureMinCol, int pictureMaxCol,
                                                 Boolean onlyInternal) {
        int _rangeMinRow = rangeMinRow == null ? pictureMinRow : rangeMinRow;
        int _rangeMaxRow = rangeMaxRow == null ? pictureMaxRow : rangeMaxRow;
        int _rangeMinCol = rangeMinCol == null ? pictureMinCol : rangeMinCol;
        int _rangeMaxCol = rangeMaxCol == null ? pictureMaxCol : rangeMaxCol;

        if (onlyInternal) {
            return (_rangeMinRow <= pictureMinRow && _rangeMaxRow >= pictureMaxRow && _rangeMinCol <= pictureMinCol
                    && _rangeMaxCol >= pictureMaxCol);
        } else {
            return ((Math.abs(_rangeMaxRow - _rangeMinRow) + Math.abs(pictureMaxRow - pictureMinRow) >= Math
                    .abs(_rangeMaxRow + _rangeMinRow - pictureMaxRow - pictureMinRow))
                    && (Math.abs(_rangeMaxCol - _rangeMinCol) + Math.abs(pictureMaxCol - pictureMinCol) >= Math
                    .abs(_rangeMaxCol + _rangeMinCol - pictureMaxCol - pictureMinCol)));
        }
    }


    public static void main(String[] args) {
        ExcelToPdfUtil.excelToPdf("原excel文件路径.xlsx",
                "转换后输出pdf路径.pdf", ".xlsx");

    }
}

测试时直接创建一个多sheet页的excel表格,并填入一些测试数据进行测试,查看转换后的结果

在主方法里更改路径进行测试

等待程序执行完后在导出路径查看转换后的pdf

点击查看

可以看到转换后的效果还是不错的,表格内容宽度自动使用pdf页面的宽度,每个sheet页都另起新的页面,多个sheet页拼接在一个pdf里,后续纸张大小参数等都可以在代码里进行灵活调整

aspose-cell实现

简介

Aspose.Cells for Java 是一款功能强大的 Java 库,专门用于操作 Microsoft Excel 文件而无需依赖 Microsoft Office。提供了丰富的API来创建、修改、转换和打印Excel文档。

主要功能包括但不限于:

特别亮点

注意该jar包是收费的,收费版本试用时候会有水印和行数多少限制,一旦达到一定数据量可能会导致程序报错,可以进行破解使用

下载jar包

该jar包在国内镜像源里是拉取不到的,可以在官网直接下载jar包,后导入到本地使用

aspose官网链接

在官网里找到对应版本依赖,如果是国外镜像源或者其他源库可以尝试拉取试试,如果没有也可以直接下载jar包到本地后安装到本地使用

点击后下载

 输入下面命令进行安装到本地

mvn install:install-file "-Dfile=jar包所在路径\jar包名.jar" "-DgroupId=com.aspose" "-DartifactId=aspose-cells" "-Dversion=版本号" "-Dpackaging=jar"

修改对应的jar包路径和包名后在idea命令行里执行安装jar包

没有报错说明安装成功,在pom文件里书写下对应的依赖刷新下maven即可

刷新下maven即可然后书写测试类尝试转换

执行转换 

可以看到导出后的效果还是不错的,但是有水印

crack使用 

这里以aspose-cells-20.7 去除水印及次数限制破解作为示例

反编译jar包

使用 jd-gui.exe 反编译查看jar包,直接搜索 License

1.修改

  public static boolean isLicenseSet() {
    return (a != null);
  }

 改为

  public static boolean isLicenseSet() {
    return true;
  }

2.修改

  public void setLicense(InputStream stream) {
    Document document = null;
    if (stream != null)
      try {
        DocumentBuilder documentBuilder = zad.b();
        document = documentBuilder.parse(stream);
      } catch (Exception exception) {
        throw new CellsException(9, zf.a(new byte[] { 
                -20, 93, -23, 54, -20, -49, -59, 86, -9, -86, 
                49, 44, -59, 71, -52, -86, -90, 6, -90, -25, 
                -86, 1, -1, -92, -91, -126, 7, 113, -66, -95, 
                -121, 16, -122, -126, 7, 104, -40, -70, -10, -37, 
                126, 7, -111, -121, -121 }) + exception.getMessage());
      }  
    a(document);
  }

改成

  public void setLicense(InputStream paramInputStream){
    a = new License();
    zbiw.a();
  }

3.修改

  private static Date k(String paramString) {
    if (paramString == null || paramString.length() < 8)
      return null; 
    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(zf.a(new byte[] { 
            79, 89, 33, -52, 79, -121, -125, 33, 71, -126, 
            105, -121 }));
    try {
      return simpleDateFormat.parse(paramString);
    } catch (ParseException parseException) {
      throw new IllegalArgumentException(zf.a(new byte[] { 
              -21, -113, -77, 13, -115, 27, Byte.MIN_VALUE, 35, 103, -52, 
              -20, -106, 71, 95, 31, -73, -76, -38, 13, 31, 
              -91, -97, -102, 85, -68, -33, -19, -87, -127, -14, 
              78, -23, 6, -25, -94, 1, -97, -95, -57, -121 }));
    } 
  }

改成

  private static Date k(String paramString){
    return new Date(Long.MAX_VALUE);
  }

修改完后使用jdi保存所有的文件为另存

生成 aspose-cells-20.7-crack.jar

修改 class 这里使用 javassist:
新建一个 Spring boot 项目:
pom 文件中引用 javassist

引入破解所需依赖

     <dependency><!--aspose的jar破解工具-->
            <groupId>org.javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.20.0-GA</version>
        </dependency>

指定目录生成修改后的License.class文件

    public static void crackAspose(String JarPath) throws Exception {
        // 这个是得到反编译的池
        ClassPool pool = ClassPool.getDefault();

        // 取得需要反编译的jar文件,设定路径
        pool.insertClassPath(JarPath);

        CtClass cc_License = pool.get("com.aspose.cells.License");

        CtMethod method_isLicenseSet = cc_License.getDeclaredMethod("isLicenseSet");
        method_isLicenseSet.setBody("return true;");

        CtClass cc_License2 = pool.get("com.aspose.cells.License");
        CtMethod method_setLicense = cc_License2.getDeclaredMethod("setLicense");
        method_setLicense.setBody("{    a = new com.aspose.cells.License();\n" +
                "    com.aspose.cells.zbiw.a();}");

        CtMethod method_k = cc_License.getDeclaredMethod("k");
        method_k.setBody("return new java.util.Date(Long.MAX_VALUE);");


        cc_License.writeFile("输出目录路径");
    }

执行该方法

在指定目录下可以看到生成后的编译文件

复制一个 aspose-cells-20.7.jar 改名为 aspose-cells-20.7-crack.zip 然后解压

把刚才生成的 License.class 文件 替换到解压的源代码中。

造一个 License xml 文件,这里文件名为 com.aspose.cells.lic_2999.xml, 位置直接放源代码解压的根目录

文件内容为:

<License>
  <Data>
    <Products>
      <Product>Aspose.Cells for Java</Product>
    </Products>
    <EditionType>Enterprise</EditionType>
    <SubscriptionExpiry>29991231</SubscriptionExpiry>
    <LicenseExpiry>29991231</LicenseExpiry>
    <SerialNumber>evilrule</SerialNumber>
  </Data>
  <Signature>evilrule</Signature>
</License>

防止文件指纹校验,我们需要删除掉源代码解压包中的 META_INF 文件夹。
最后的根目录:

压缩源代码(注意要是 zip 格式)

然后重命名后缀为:jar

测试 aspose-cells-20.7-crack.jar 使用

封装一个 License 验证方法:

public static boolean authrolizeLicense() {
    boolean result = false;
    try {
        InputStream is = com.aspose.cells.License.class.getResourceAsStream("/com.aspose.cells.lic_2999.xml");
        License asposeLicense = new License();
        asposeLicense.setLicense(is);
        is.close();
        result = true;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return result;
}

修改 main 方法测试使用:

    public static void main(String[] args) {



        // 测试破解后的 aspose-cells-20.7-crack.jar
        boolean auth = authrolizeLicense();
        if (!auth) {
            System.out.println("aspose 许可无效!");
            return;
        }


        System.out.println("aspose 已就绪!");


        try{
            Workbook wb = new Workbook("F:\\aaa123.xlsx");
            Worksheet ws = wb.getWorksheets().get(0);

            ImageOrPrintOptions imgOptions = new ImageOrPrintOptions();
            imgOptions.setImageFormat(ImageFormat.getPng());
            imgOptions.setCellAutoFit(true);
            imgOptions.setOnePagePerSheet(true);
            SheetRender render = new SheetRender(ws, imgOptions);

            render.toImage(0, "F:\\aaa\\123.png");

        }
        catch (Exception e){
            e.printStackTrace();
        }
    }

这里图片和excel可以随便搞一个尝试测试使用

先生成图片再转pdf

前面的破解工作都做好后就可以尝试测试了,aspose可以先将excel转成图片后再转成pdf

 public static void main(String[] args) {
        // 授权检查(假设你已经破解)
        boolean auth = authrolizeLicense();
        if (!auth) {
            System.out.println("aspose 许可无效!");
            return;
        }

        System.out.println("aspose 已就绪!");

        try {
            Workbook wb = new Workbook("C:\\Users\\d\\Desktop\\excelToPdf\\奥特曼.xlsx");
            ImageOrPrintOptions imgOptions = new ImageOrPrintOptions();
            imgOptions.setImageFormat(ImageFormat.getPng());
            imgOptions.setCellAutoFit(true);
            imgOptions.setOnePagePerSheet(true);

            String outputPdfPath = "C:\\Users\\d\\Desktop\\excelToPdf\\奥特曼Aspose导出图片版.pdf";

            // 创建一个无边距的文档
            Document document = new Document(PageSize.A4);  // 使用 A4 纸张尺寸
            PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(outputPdfPath));

            // 设置页面无边距(非常重要)
            document.setMargins(0, 0, 0, 0);  // 左、右、上、下全部为 0
            document.open();

            for (int i = 0; i < wb.getWorksheets().getCount(); i++) {
                Worksheet ws = wb.getWorksheets().get(i);
                SheetRender render = new SheetRender(ws, imgOptions);
                String imageFilePath = "C:\\Users\\d\\Desktop\\excelToPdf\\sheet_" + i + ".png";
                render.toImage(0, imageFilePath);

                Image img = Image.getInstance(imageFilePath);

                // 自动缩放图片以适配页面宽度和高度
                img.scaleToFit(document.getPageSize().getWidth(), document.getPageSize().getHeight());

                // 居中显示(iText 默认就是居中的,但我们可以更明确地设置)
                img.setAlignment(Image.ALIGN_CENTER);

                // 新增一页
                document.newPage();

                // 插入图片到当前页面
                document.add(img);
            }

            document.close();
            writer.close();

            System.out.println("✅ PDF 文件已生成: " + outputPdfPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

执行测试

查看生成的效果

可以看到原有的水印都没了

直接转换

aspose也可以直接进行转换

    public static void main(String[] args) throws Exception {
//        // 授权检查(假设你已经破解)
//        boolean auth = authrolizeLicense();
//        if (!auth) {
//            System.out.println("aspose 许可无效!");
//            return;
//        }
//
//        System.out.println("aspose 已就绪!");
//
//        try {
//            Workbook wb = new Workbook("C:\\Users\\d\\Desktop\\excelToPdf\\奥特曼.xlsx");
//            ImageOrPrintOptions imgOptions = new ImageOrPrintOptions();
//            imgOptions.setImageFormat(ImageFormat.getPng());
//            imgOptions.setCellAutoFit(true);
//            imgOptions.setOnePagePerSheet(true);
//
//            String outputPdfPath = "C:\\Users\\d\\Desktop\\excelToPdf\\奥特曼aspose导出图片版.pdf";
//
//            // 创建一个无边距的文档
//            Document document = new Document(PageSize.A4);  // 使用 A4 纸张尺寸
//            PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(outputPdfPath));
//
//            // 设置页面无边距(非常重要)
//            document.setMargins(0, 0, 0, 0);  // 左、右、上、下全部为 0
//            document.open();
//
//            for (int i = 0; i < wb.getWorksheets().getCount(); i++) {
//                Worksheet ws = wb.getWorksheets().get(i);
//                SheetRender render = new SheetRender(ws, imgOptions);
//                String imageFilePath = "C:\\Users\\d\\Desktop\\excelToPdf\\sheet_" + i + ".png";
//                render.toImage(0, imageFilePath);
//
//                Image img = Image.getInstance(imageFilePath);
//
//                // 自动缩放图片以适配页面宽度和高度
//                img.scaleToFit(document.getPageSize().getWidth(), document.getPageSize().getHeight());
//
//                // 居中显示(iText 默认就是居中的,但我们可以更明确地设置)
//                img.setAlignment(Image.ALIGN_CENTER);
//
//                // 新增一页
//                document.newPage();
//
//                // 插入图片到当前页面
//                document.add(img);
//            }
//
//            document.close();
//            writer.close();
//
//            System.out.println("✅ PDF 文件已生成: " + outputPdfPath);
//        } catch (Exception e) {
//            e.printStackTrace();
//        }


        // 加载 Excel 文件
        Workbook workbook = new Workbook("C:\\Users\\d\\Desktop\\excelToPdf\\奥特曼.xlsx");

        // 设置 PDF 导出选项
        PdfSaveOptions saveOpts = new PdfSaveOptions();

        // 设置页面尺寸为 A2(单位是 像素 或 毫米,这里使用像素)
        // A2 尺寸:4961 x 7016 像素(分辨率为 300 DPI)
        PageSetup pageSetup = workbook.getWorksheets().get(0).getPageSetup();
        pageSetup.setPaperSize(PaperSizeType.PAPER_A_3); // 设置为 A2 纸张
        pageSetup.setOrientation(PageOrientationType.LANDSCAPE); // 设置为横向

        // 如果你想对所有 sheet 都生效,可以循环设置每个 sheet 的页面属性
        for (int i = 0; i < workbook.getWorksheets().getCount(); i++) {
            Worksheet sheet = workbook.getWorksheets().get(i);
            sheet.getPageSetup().setPaperSize(PaperSizeType.PAPER_A_3);
            sheet.getPageSetup().setOrientation(PageOrientationType.LANDSCAPE);
        }

        // 设置每张工作表输出为一页 PDF
        saveOpts.setOnePagePerSheet(true);

        // 导出为 PDF
        String outputPdfPath = "C:\\Users\\d\\Desktop\\excelToPdf\\奥特曼aspose导出.pdf";
        workbook.save(outputPdfPath, saveOpts);

        System.out.println("✅ 已成功导出 A2 横向 PDF: " + outputPdfPath);
    }

查看效果

这种方式虽然可直接转换,但是还是会有水印,所以还是推荐先转图片后再转pdf的方式

以上就是Java多种方式实现Excel转Pdf的保姆级教程的详细内容,更多关于Java Excel转Pdf的多种方式的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文