【Apache poi】读取【Excel】内图片及所在位置

5 篇文章 0 订阅
2 篇文章 0 订阅

需求是这样的,给你固定一个excel,里面有id和插入的图片,大概200M-1G左右。

读取后将图片写入文件存储服务器内,获取静态地址,再将静态地址更新到对应id上。

难点:这个你很难定位到图片的横纵坐标,因为图片并不是真的在单元格内(业务那边给定的模板就是如此)。

excel结构大概为:

 找了网上的代码,简单修修改改。

package com.main.util;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.POIXMLDocumentPart;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
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.XSSFWorkbook;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * created by rock-ayl on 2022-2-23
 * 解析excel内的图片所在单元格
 */
public class ExcelImageUtils {

    private final static Logger LOG = LoggerFactory.getLogger(ExcelImageUtils.class);

    /**
     * 根据文件解析excel内图片
     *
     * @param file       文件对象
     * @param sheetIndex 第几个sheet
     * @return
     */
    public static Map<String, Map<Integer, PictureData>> parseSheetPic(File file, int sheetIndex) {
        try {
            //文件流
            InputStream input = new FileInputStream(file);
            //文件后缀
            String fileExt = FilenameUtils.getExtension(file.getName());
            //实现并返回
            return parseSheetPic(input, fileExt, sheetIndex);
        } catch (Exception e) {
            LOG.error("parseSheetPic fail , file error={}", e);
        }
        //默认
        return new HashMap<>();
    }

    /**
     * 根据文件流及文件类型解析excel内图片
     *
     * @param inputStream 文件流
     * @param fileExt     文件后缀 xls,xlsx
     * @param sheetIndex  第几个sheet
     * @return
     */
    public static Map<String, Map<Integer, PictureData>> parseSheetPic(InputStream inputStream, String fileExt, int sheetIndex) {
        try {
            //初始化
            Workbook workbook = WorkbookFactory.create(inputStream);
            //获取sheet
            Sheet sheet = workbook.getSheetAt(sheetIndex);
            //第一行作为key
            Map<Integer, String> keyMap = new HashMap<>();
            //第一行的迭代器
            Iterator<Cell> iterator = sheet.getRow(0).cellIterator();
            //指针
            int p = 0;
            //如果存在
            while (iterator.hasNext()) {
                //获取值
                String value = iterator.next().getStringCellValue();
                //如果存在
                if (StringUtils.isNotBlank(value)) {
                    //记录该key
                    keyMap.put(p, value);
                }
                //无论如何+1o
                p++;
            }
            //根据类型解析
            switch (fileExt) {
                case "xls":
                    return parseSheetPicForXLS((HSSFWorkbook) workbook, sheetIndex, keyMap);
                case "xlsx":
                    return parseSheetPicForXLSX((XSSFWorkbook) workbook, sheetIndex, keyMap);
            }
        } catch (Exception e) {
            LOG.error("parseSheetPic fail , inputStream error={}", e);
        }
        //默认
        return new HashMap<>();
    }

    /**
     * 解析XLS的图片
     *
     * @param workbook   workbook
     * @param sheetIndex 第几页sheet的图片
     * @return
     */
    private static Map<String, Map<Integer, PictureData>> parseSheetPicForXLS(HSSFWorkbook workbook, int sheetIndex, Map<Integer, String> keyMap) {
        //初始化结果
        Map<String, Map<Integer, PictureData>> result = new HashMap<>();
        //获取workbook所有图片列表
        List<HSSFPictureData> pictures = workbook.getAllPictures();
        //获取对应sheet
        HSSFSheet sheet = workbook.getSheetAt(sheetIndex);
        //如果存在图片
        if (pictures.size() > 0) {
            //获取列表
            List<HSSFShape> children = sheet.getDrawingPatriarch().getChildren();
            //循环
            for (HSSFShape shape : children) {
                //获取并强转
                HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();
                //如果是
                if (shape instanceof HSSFPicture) {
                    //强转
                    HSSFPicture pic = (HSSFPicture) shape;
                    //从workbook所有图片中找到该图片
                    HSSFPictureData picData = pictures.get(pic.getPictureIndex() - 1);
                    //如果存在改key
                    if (keyMap.containsKey(anchor.getCol1())) {
                        //获取key
                        String key = keyMap.get(anchor.getCol1());
                        //尝试获取mep
                        Map<Integer, PictureData> map = result.getOrDefault(key, new HashMap<>());
                        //组装
                        map.put(anchor.getRow1() - 1, picData);
                        result.put(key, map);
                    }
                }
            }

        }
        //返回
        return result;
    }

    /**
     * 解析XLSX图片
     *
     * @return
     */
    private static Map<String, Map<Integer, PictureData>> parseSheetPicForXLSX(XSSFWorkbook workbook, int sheetIndex, Map<Integer, String> keyMap) {
        //初始化结果
        Map<String, Map<Integer, PictureData>> result = new HashMap<>();
        //获取列表
        List<POIXMLDocumentPart> relationList = workbook.getSheetAt(sheetIndex).getRelations();
        //循环1
        for (POIXMLDocumentPart dr : relationList) {
            //如果是类型
            if (dr instanceof XSSFDrawing) {
                //强转
                XSSFDrawing drawing = (XSSFDrawing) dr;
                //获取列表
                List<XSSFShape> shapeList = drawing.getShapes();
                //循环2
                for (XSSFShape shape : shapeList) {
                    //强转
                    XSSFPicture pic = (XSSFPicture) shape;
                    //获取其可能的表格
                    CTMarker ctMarker = pic.getPreferredSize().getFrom();
                    //如果存在改key
                    if (keyMap.containsKey(ctMarker.getCol())) {
                        //获取key
                        String key = keyMap.get(ctMarker.getCol());
                        //尝试获取结果map
                        Map<Integer, PictureData> map = result.getOrDefault(key, new HashMap<>());
                        //组装
                        map.put(ctMarker.getRow() - 1, pic.getPictureData());
                        result.put(key, map);
                    }
                }
            }
        }
        //返回
        return result;
    }

}

代码测试结果:

准确定位的概率大概是90%左右,小部分会定位到其他key上,精度不高,无法采用。

至此,该需求经过讨论,废弃。

由于需求废弃并改为了其他方式,未提交这部分代码,简单记录下,防止以后用到。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
可以使用Apache POI库来读取Excel数据并提取图片。以下是一个简单的示例代码: ```java import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.apache.poi.util.IOUtils; import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFPicture; import org.apache.poi.xssf.usermodel.XSSFPictureData; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class ReadExcelWithImage { public static void main(String[] args) throws IOException { String filePath = "path/to/excel/file.xlsx"; InputStream inputStream = new FileInputStream(filePath); Workbook workbook = WorkbookFactory.create(inputStream); int sheetCount = workbook.getNumberOfSheets(); for (int i = 0; i < sheetCount; i++) { Sheet sheet = workbook.getSheetAt(i); if (sheet instanceof XSSFSheet) { XSSFSheet xssfSheet = (XSSFSheet) sheet; for (Row row : xssfSheet) { for (Cell cell : row) { switch (cell.getCellType()) { case STRING: System.out.print(cell.getStringCellValue() + "\t"); break; case NUMERIC: System.out.print(cell.getNumericCellValue() + "\t"); break; case BOOLEAN: System.out.print(cell.getBooleanCellValue() + "\t"); break; case FORMULA: System.out.print(cell.getCellFormula() + "\t"); break; default: System.out.print(" " + "\t"); } if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) { switch (cell.getCachedFormulaResultType()) { case Cell.CELL_TYPE_NUMERIC: System.out.print(cell.getNumericCellValue() + "\t"); break; case Cell.CELL_TYPE_STRING: System.out.print(cell.getStringCellValue() + "\t"); break; } } if (cell.getCellType() == Cell.CELL_TYPE_BLANK) { System.out.print(" " + "\t"); } if (cell.getCellType() == Cell.CELL_TYPE_ERROR) { System.out.print(cell.getErrorCellValue() + "\t"); } if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) { System.out.print(cell.getBooleanCellValue() + "\t"); } if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) { System.out.print(cell.getNumericCellValue() + "\t"); } if (cell.getCellType() == Cell.CELL_TYPE_STRING) { System.out.print(cell.getStringCellValue() + "\t"); } if (cell.getCellType() == Cell.CELL_TYPE_BLANK) { System.out.print("" + "\t"); } if (cell.getCellType() == Cell.CELL_TYPE_FORMULA && cell.getCachedFormulaResultType() == Cell.CELL_TYPE_NUMERIC) { System.out.print(cell.getNumericCellValue() + "\t"); } if (cell.getCellType() == Cell.CELL_TYPE_FORMULA && cell.getCachedFormulaResultType() == Cell.CELL_TYPE_STRING) { System.out.print(cell.getStringCellValue() + "\t"); } // get image from cell if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) { if (xssfSheet.getDrawingPatriarch() != null) { for (XSSFPicture picture : xssfSheet.getDrawingPatriarch().getShapes().getPictures()) { XSSFClientAnchor anchor = picture.getClientAnchor(); if (anchor.getRow1() == row.getRowNum() && anchor.getCol1() == cell.getColumnIndex()) { XSSFPictureData pictureData = picture.getPictureData(); byte[] bytes = pictureData.getData(); String extension = pictureData.suggestFileExtension(); String fileName = "image" + row.getRowNum() + "_" + cell.getColumnIndex() + "." + extension; IOUtils.write(bytes, new FileOutputStream(fileName)); } } } } } System.out.println(""); } } } } } ``` 在这个例子中,我们遍历每个单元格,并根据其类型打印出其内容。如果单元格包含图片,我们使用Apache POI的XSSFDrawing对象来提取图像并将其保存到文件中。 请注意,上面的代码仅适用于XLSX格式的Excel文件。如果您的Excel文件是旧的XLS格式,您需要使用HSSFWorkbook和HSSFPicture类来读取图像。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值