Java高效实现excel转pdf(支持带图片的转换)

 更新时间:2024年01月30日 10:13:34   作者:沉默的方三毛  
这篇文章主要为大家详细介绍了如何用java实现excel转pdf文件,并且支持excel单元格中带有图片的转换,文中的示例代码讲解详细,需要的可以参考下

本文用java实现excel转pdf文件,并且支持excel单元格中带有图片的转换,使用poi来读取excel文件数据,用itext来动态生成pdf文档,核心代码如下:

public static byte[] excelToPdf(String excelPath, String pdfPath) throws Exception{
        InputStream in = new FileInputStream(excelPath);
        
        Workbook workbook;
        if (excelPath.endsWith(".xlsx")){
            workbook = new XSSFWorkbook(in);
        } else {
            workbook = new HSSFWorkbook(in);
        } 
        
        Sheet sheet = workbook.getSheetAt(0);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        
        Document document = new Document(PageSize.A4);//此处根据excel大小设置pdf纸张大小
        PdfWriter writer = PdfWriter.getInstance(document, stream);
        document.setMargins(0, 0, 15, 15);//设置也边距
        document.open();
        float[] widths = getColWidth(sheet);
        
        PdfPTable table = new PdfPTable(widths);
        table.setWidthPercentage(90);
        int colCount = widths.length;
        BaseFont baseFont = BaseFont.createFont("C:\\Windows\\Fonts\\simsun.ttc,0", BaseFont.IDENTITY_H,
                BaseFont.EMBEDDED);//设置基本字体
        
        for (int r = sheet.getFirstRowNum(); r < sheet.getPhysicalNumberOfRows(); r++) {
            Row row = sheet.getRow(r);
            if (row != null) {
                for (int c = row.getFirstCellNum(); (c < row.getLastCellNum() || c < colCount) && c > -1; c++) {
                    if (c >= row.getPhysicalNumberOfCells()) {
                        PdfPCell pCell = new PdfPCell(new Phrase(""));
                        pCell.setBorder(0);
                        table.addCell(pCell);
                        continue;
                    }
                    Cell excelCell = row.getCell(c);
                    String value = "";
 
                    if (excelCell != null) {
                        value = excelCell.toString().trim();
                        if (value != null && value.length() != 0){
                            String dataFormat = excelCell.getCellStyle().getDataFormatString();//获取excel单元格数据显示样式
                            if (dataFormat != "General" && dataFormat != "@"){
                                try {
                                    String numStyle = getNumStyle(dataFormat);
                                    value = numFormat(numStyle, excelCell.getNumericCellValue());
                                } catch (Exception e) {
                                    
                                }
                            }
                        }
                    }
                    org.apache.poi.ss.usermodel.Font excelFont = getExcelFont(workbook, excelCell, excelPath);
                    
                    //HSSFFont excelFont = excelCell.getCellStyle().getFont(workbook);
                    Font pdFont = new Font(baseFont, excelFont.getFontHeightInPoints(),
                            excelFont.getBoldweight() == 700 ? Font.BOLD : Font.NORMAL, BaseColor.BLACK);//设置单元格字体
 
                    PdfPCell pCell = new PdfPCell(new Phrase(value, pdFont));
                 List<PicturesInfo> infos  = POIExtend.getAllPictureInfos(sheet, r, r, c, c, false);
                    if (!infos.isEmpty()){
                        pCell = new PdfPCell(Image.getInstance(infos.get(0).getPictureData()));
                        PicturesInfo info = infos.get(0);
                        System.out.println("最大行:" + info.getMaxRow() + "最小行:" + info.getMinRow() + "最大列:" + info.getMaxCol() + "最小列:" + info.getMinCol());;
                    }
                    
                    boolean hasBorder = hasBorder(excelCell);
                    if (!hasBorder){
                        pCell.setBorder(0);
                    }
                    pCell.setHorizontalAlignment(getHorAglin(excelCell.getCellStyle().getAlignment()));
                    pCell.setVerticalAlignment(getVerAglin(excelCell.getCellStyle().getVerticalAlignment()));
 
                    pCell.setMinimumHeight(row.getHeightInPoints());
                    if (isMergedRegion(sheet, r, c)) {
                        int[] span = getMergedSpan(sheet, r, c);
                        if (span[0] == 1 && span[1] == 1) {//忽略合并过的单元格
                            continue;
                        }
                        pCell.setRowspan(span[0]);
                        pCell.setColspan(span[1]);
                        c = c + span[1] - 1;//合并过的列直接跳过
                    }
 
                    table.addCell(pCell);
 
                }
            } else {
                PdfPCell pCell = new PdfPCell(new Phrase(""));
                pCell.setBorder(0);
                pCell.setMinimumHeight(13);
                table.addCell(pCell);
            }
        }
        document.add(table);
        document.close();
        
        byte[] pdfByte = stream.toByteArray();
        stream.flush();
        stream.reset();
        stream.close();
        
        FileOutputStream outputStream = new FileOutputStream(pdfPath);
        outputStream.write(pdfByte);
        outputStream.flush();
        outputStream.close();
        
        return pdfByte;
    }
//获取字体  
private static org.apache.poi.ss.usermodel.Font getExcelFont(Workbook workbook, Cell cell, String excelName){
        if (excelName.endsWith(".xls")){
            return ((HSSFCell)cell).getCellStyle().getFont(workbook);
        }
        return ((XSSFCell)cell).getCellStyle().getFont();
    }

判断excel单元格是否有边框

    /**
     * 判断excel单元格是否有边框
     * @param excelCell
     * @return
     */
    private static boolean hasBorder(Cell excelCell) {
        short top = excelCell.getCellStyle().getBorderTop();
        short bottom = excelCell.getCellStyle().getBorderBottom();
        short left = excelCell.getCellStyle().getBorderLeft();
        short right = excelCell.getCellStyle().getBorderRight();
        return top + bottom + left + right > 2;
    }

获取excel单元格数据显示格式

    /**
     * 获取excel单元格数据显示格式
     * @param dataFormat
     * @return
     * @throws Exception
     */
    private static String getNumStyle(String dataFormat) throws Exception {
        if (dataFormat == null || dataFormat.length() == 0){
            throw new Exception("");
        }
        if (dataFormat.indexOf("%") > -1){
            return dataFormat;
        } else{
            return dataFormat.substring(0, dataFormat.length()-2);
        }
        
    }

判断单元格是否是合并单元格

    /**
     * 判断单元格是否是合并单元格
     * @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中每列宽度的占比

  /**
     * 获取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中列数最多的行号

 /**
     * 获取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;
    }

excel垂直对齐方式映射到pdf对齐方式

 /**
     * excel垂直对齐方式映射到pdf对齐方式
     * @param aglin
     * @return
     */
    private static int getVerAglin(int aglin) {
        switch (aglin) {
        case 1:
            return com.itextpdf.text.Element.ALIGN_MIDDLE;
        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水平对齐方式

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

格式化数字

    /**
     * 格式化数字
     * @param pattern
     * @param num
     * @return
     */
    private static String numFormat(String pattern, double num){
        DecimalFormat format = new DecimalFormat(pattern);
        return format.format(num);
    }

以下代码是对excel转pdf时对excel中图片进行处理,实现图片在pdf中正常显示

//图片基本信息
public class PicturesInfo {
 
    private int minRow;
    private int maxRow;
    private int minCol;
    private int maxCol;
    private String ext;
    private byte[] pictureData;
    
    public PicturesInfo(int minRow, int maxRow, int minCol, int maxCol ,byte[] pictureData, String ext){
        this.minRow = minRow;
        this.maxRow = maxRow;
        this.minCol = minCol;
        this.maxCol = maxCol;
        this.ext = ext;
        this.pictureData = pictureData;
    }
    
    public byte[] getPictureData() {
        return pictureData;
    }
    public void setPictureData(byte[] pictureData) {
        this.pictureData = pictureData;
    }
    public int getMinRow() {
        return minRow;
    }
    public void setMinRow(int minRow) {
        this.minRow = minRow;
    }
    public int getMaxRow() {
        return maxRow;
    }
    public void setMaxRow(int maxRow) {
        this.maxRow = maxRow;
    }
    public int getMinCol() {
        return minCol;
    }
    public void setMinCol(int minCol) {
        this.minCol = minCol;
    }
    public int getMaxCol() {
        return maxCol;
    }
    public void setMaxCol(int maxCol) {
        this.maxCol = maxCol;
    }
    public String getExt() {
        return ext;
    }
    public void setExt(String ext) {
        this.ext = ext;
    }
    
    
}

以下是获取excel中图片数据以及位置信息代码:

import java.util.ArrayList;
import java.util.List;
 
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFPicture;
import org.apache.poi.hssf.usermodel.HSSFShape;
import org.apache.poi.hssf.usermodel.HSSFShapeContainer;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFPicture;
import org.apache.poi.xssf.usermodel.XSSFShape;
import org.apache.poi.xssf.usermodel.XSSFSheet;
 
public class POIExtend {
 
	public static List<PicturesInfo> getAllPictureInfos(Sheet sheet, boolean onlyInternal) throws Exception {
		return getAllPictureInfos(sheet, null, null, null, null, onlyInternal);
	}
 
	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()扩展方法!");
		}
	}
 
	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 (null != shapeContainer) {
			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)) {
						picturesInfoList.add(
								new PicturesInfo(anchor.getRow1(), anchor.getRow2(), anchor.getCol1(), anchor.getCol2(),
										picture.getPictureData().getData(), picture.getPictureData().getMimeType()));
					}
				}
			}
		}
 
		return picturesInfoList;
	}
 
	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)) {
							picturesInfoList.add(new PicturesInfo(anchor.getRow1(), anchor.getRow2(), anchor.getCol1(),
									anchor.getCol2(), picture.getPictureData().getData(),
									picture.getPictureData().getMimeType()));
						}
					}
				}
			}
		}
 
		return picturesInfoList;
	}
 
	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)));
		}
	}
}

以上就是Java高效实现excel转pdf(支持带图片的转换)的详细内容,更多关于Java excel转pdf的资料请关注脚本之家其它相关文章!

相关文章

  • spring boot 项目中使用thymeleaf模板的案例分析

    spring boot 项目中使用thymeleaf模板的案例分析

    这篇文章主要介绍了spring boot 项目中使用thymeleaf模板的案例分析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • Spring Boot(四)之使用JWT和Spring Security保护REST API

    Spring Boot(四)之使用JWT和Spring Security保护REST API

    这篇文章主要介绍了Spring Boot(四)之使用JWT和Spring Security保护REST API的相关知识,需要的朋友可以参考下
    2017-04-04
  • Java集合ArrayList、LinkedList、HashMap、HashSet最大容量

    Java集合ArrayList、LinkedList、HashMap、HashSet最大容量

    在开发中我们使用比较多的集合就是List、Set和Map了,并且我们也知道大部分用的基本上都是ArrayList、LinkedList、HashMap、HashSet或者TreeSet这几个集合,你知道他们的最大容量,感兴趣的可以了解一下
    2023-12-12
  • 启动Spring项目详细过程(小结)

    启动Spring项目详细过程(小结)

    这篇文章主要介绍了启动Spring项目详细过程(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • 说明Java的传递与回调机制的代码示例分享

    说明Java的传递与回调机制的代码示例分享

    这篇文章主要介绍了说明Java的传递与回调机制的代码示例分享,传递与回调机制是Java入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • 分享JPA的几个小技巧

    分享JPA的几个小技巧

    这篇文章主要分享了JPA的几个小技巧,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下
    2021-03-03
  • 利用Java实现调用http请求

    利用Java实现调用http请求

    在实际开发过程中,我们经常需要调用对方提供的接口或测试自己写的接口是否合适。本文就为大家准备了几个java调用http请求的几种常见方式,需要的可以参考一下
    2022-08-08
  • 精通Java泛型的使用与原理

    精通Java泛型的使用与原理

    针对利用继承来实现通用程序设计所产生的问题,泛型提供了更好的解决方案,本文详细的介绍了Java泛型的使用与原理,感兴趣的可以了解一下
    2022-03-03
  • spring boot整合redis实现RedisTemplate三分钟快速入门

    spring boot整合redis实现RedisTemplate三分钟快速入门

    这篇文章主要介绍了spring boot整合redis实现RedisTemplate三分钟快速入门,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • Java多态中动态绑定原理解析

    Java多态中动态绑定原理解析

    这篇文章主要介绍了Java多态中动态绑定原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12

最新评论