MrShi
2026-01-29 8676f4cb37ef31fa9fcfe2a7faf5f4c4ea77cc1a
server/services/src/main/java/com/doumee/core/annotation/excel/ExcelPictureUtil.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,309 @@
package com.doumee.core.annotation.excel;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.XML;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.openxml4j.opc.PackagePartName;
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.xssf.usermodel.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
 * @author bianhl
 * @version 1.0
 * @description èŽ·å–å›¾ç‰‡èµ„æº
 * @date 2024å¹´4月28日08:44:42
 */
@Slf4j
public class ExcelPictureUtil {
    public static Map<String, XSSFPictureData> getExcelPictures(InputStream is) {
        try {
            byte[] fileData =  getFileStream(is);
            Map<String, XSSFPictureData> pictures = getPictures(fileData);
            pictures.forEach((id, xssfPictureData) -> {
                System.out.println("id:" + id);
                String fileName = xssfPictureData.getPackagePart().getPartName().getName();
                System.out.println("fileName:" + fileName);
            });
            return pictures;
        }catch (Exception e){
            return  null;
        }
    }
    /**
     * èŽ·å–æµ®åŠ¨å›¾ç‰‡ï¼Œä»¥ map å½¢å¼è¿”回,键为行列格式 x-y。
     *
     * @param xssfSheet WPS å·¥ä½œè¡¨
     * @return æµ®åŠ¨å›¾ç‰‡çš„ map
     */
    public static Map<String, XSSFPictureData> getFloatingPictures(XSSFSheet xssfSheet) {
        Map<String, XSSFPictureData> mapFloatingPictures = new HashMap<>();
        XSSFDrawing drawingPatriarch = xssfSheet.getDrawingPatriarch();
        if (drawingPatriarch != null) {
            List<XSSFShape> shapes = drawingPatriarch.getShapes();
            for (XSSFShape shape : shapes) {
                if (shape instanceof XSSFPicture ) {
                    XSSFPicture picture = (XSSFPicture)shape;
                    XSSFClientAnchor anchor = (XSSFClientAnchor) picture.getAnchor();
                    XSSFPictureData pictureData = picture.getPictureData();
                    String key = anchor.getRow1() + "-" + anchor.getCol1();
                    mapFloatingPictures.put(key, pictureData);
                }
            }
        }
        return mapFloatingPictures;
    }
    /**
     * å¤„理 WPS æ–‡ä»¶ä¸­çš„图片数据,返回图片信息 map。
     *
     * @param stream    è¾“入流
     * @param mapConfig é…ç½®æ˜ å°„
     * @return å›¾ç‰‡ä¿¡æ¯çš„ map
     * @throws IOException
     */
    private static Map<String, XSSFPictureData> processPictures(ByteArrayInputStream stream, Map<String, String> mapConfig) throws IOException {
        Map<String, XSSFPictureData> mapPictures = new HashedMap<>();
        Workbook workbook = WorkbookFactory.create(stream);
        List<XSSFPictureData> allPictures = (List<XSSFPictureData>) workbook.getAllPictures();
        for (XSSFPictureData pictureData : allPictures) {
            PackagePartName partName = pictureData.getPackagePart().getPartName();
            String uri = partName.getURI().toString();
            if (mapConfig.containsKey(uri)) {
                String strId = mapConfig.get(uri);
                mapPictures.put(strId, pictureData);
            }
        }
        return mapPictures;
    }
    /**
     * èŽ·å– WPS æ–‡æ¡£ä¸­çš„图片,包括嵌入式图片和浮动式图片。
     *
     * @param data äºŒè¿›åˆ¶æ•°æ®
     * @return å›¾ç‰‡ä¿¡æ¯çš„ map
     * @throws IOException
     */
    public static Map<String, XSSFPictureData> getPictures(byte[] data) {
        try {
            Map<String, String> mapConfig = processZipEntries(new ByteArrayInputStream(data));
            Map<String, XSSFPictureData> mapPictures = processPictures(new ByteArrayInputStream(data), mapConfig);
            Iterator<Sheet> sheetIterator = WorkbookFactory.create(new ByteArrayInputStream(data)).sheetIterator();
            while (sheetIterator.hasNext()) {
                mapPictures.putAll(getFloatingPictures((XSSFSheet) sheetIterator.next()));
            }
            return mapPictures;
        } catch (IOException e) {
            return new HashedMap<>();
        }
    }
    /**
     * å¤„理 Zip æ–‡ä»¶ä¸­çš„æ¡ç›®ï¼Œæ›´æ–°å›¾ç‰‡é…ç½®ä¿¡æ¯ã€‚
     *
     * @param stream Zip è¾“入流
     * @return é…ç½®ä¿¡æ¯çš„ map
     * @throws IOException
     */
    private static Map<String, String> processZipEntries(ByteArrayInputStream stream) throws IOException {
        Map<String, String> mapConfig = new HashedMap<>();
        ZipInputStream zipInputStream = new ZipInputStream(stream);
        ZipEntry zipEntry;
        while ((zipEntry = zipInputStream.getNextEntry()) != null) {
            try {
                final String fileName = zipEntry.getName();
                if ("xl/cellimages.xml".equals(fileName)) {
                    processCellImages(zipInputStream, mapConfig);
                } else if ("xl/_rels/cellimages.xml.rels".equals(fileName)) {
                    return processCellImagesRels(zipInputStream, mapConfig);
                }
            } finally {
                zipInputStream.closeEntry();
            }
        }
        return new HashedMap<>();
    }
    /**
     * å¤„理 Zip æ–‡ä»¶ä¸­çš„ cellimages.xml æ–‡ä»¶ï¼Œæ›´æ–°å›¾ç‰‡é…ç½®ä¿¡æ¯ã€‚
     *
     * @param zipInputStream Zip è¾“入流
     * @param mapConfig      é…ç½®ä¿¡æ¯çš„ map
     * @throws IOException
     */
    private static void processCellImages(ZipInputStream zipInputStream, Map<String, String> mapConfig) throws IOException {
        String content = IOUtils.toString(zipInputStream);
        JSONObject jsonObject = XML.toJSONObject(content);
        if (jsonObject != null) {
            JSONObject cellImages = jsonObject.getJSONObject("etc:cellImages");
            if (cellImages != null) {
                JSONArray cellImageArray = null;
                Object cellImage = cellImages.get("etc:cellImage");
                if (cellImage != null && cellImage instanceof JSONArray) {
                    cellImageArray = (JSONArray) cellImage;
                } else if (cellImage != null && cellImage instanceof JSONObject) {
                    JSONObject cellImageObj = (JSONObject) cellImage;
                    if (cellImageObj != null) {
                        cellImageArray = new JSONArray();
                        cellImageArray.add(cellImageObj);
                    }
                }
                if (cellImageArray != null) {
                    processImageItems(cellImageArray, mapConfig);
                }
            }
        }
    }
    /**
     * å¤„理 cellImageArray ä¸­çš„图片项,更新图片配置信息。
     *
     * @param cellImageArray å›¾ç‰‡é¡¹çš„ JSONArray
     * @param mapConfig      é…ç½®ä¿¡æ¯çš„ map
     */
    private static  void processImageItems(JSONArray cellImageArray, Map<String, String> mapConfig) {
        for (int i = 0; i < cellImageArray.size(); i++) {
            JSONObject imageItem = cellImageArray.getJSONObject(i);
            if (imageItem != null) {
                JSONObject pic = imageItem.getJSONObject("xdr:pic");
                if (pic != null) {
                    processPic(pic, mapConfig);
                }
            }
        }
    }
    /**
     * å¤„理 pic ä¸­çš„图片信息,更新图片配置信息。
     *
     * @param pic       å›¾ç‰‡çš„ JSONObject
     * @param mapConfig é…ç½®ä¿¡æ¯çš„ map
     */
    private static  void processPic(JSONObject pic, Map<String, String> mapConfig) {
        JSONObject nvPicPr = pic.getJSONObject("xdr:nvPicPr");
        if (nvPicPr != null) {
            JSONObject cNvPr = nvPicPr.getJSONObject("xdr:cNvPr");
            if (cNvPr != null) {
                String name = cNvPr.getStr("name");
                if (StringUtils.isNotEmpty(name)) {
                    String strImageEmbed = updateImageEmbed(pic);
                    if (strImageEmbed != null) {
                        mapConfig.put(strImageEmbed, name);
                    }
                }
            }
        }
    }
    /**
     * èŽ·å–åµŒå…¥å¼å›¾ç‰‡çš„ embed ä¿¡æ¯ã€‚
     *
     * @param pic å›¾ç‰‡çš„ JSONObject
     * @return embed ä¿¡æ¯
     */
    private  static String updateImageEmbed(JSONObject pic) {
        JSONObject blipFill = pic.getJSONObject("xdr:blipFill");
        if (blipFill != null) {
            JSONObject blip = blipFill.getJSONObject("a:blip");
            if (blip != null) {
                return blip.getStr("r:embed");
            }
        }
        return null;
    }
    /**
     * å¤„理 Zip æ–‡ä»¶ä¸­çš„ relationship æ¡ç›®ï¼Œæ›´æ–°é…ç½®ä¿¡æ¯ã€‚
     *
     * @param zipInputStream Zip è¾“入流
     * @param mapConfig      é…ç½®ä¿¡æ¯çš„ map
     * @return é…ç½®ä¿¡æ¯çš„ map
     * @throws IOException
     */
    private static Map<String, String> processCellImagesRels(ZipInputStream zipInputStream, Map<String, String> mapConfig) throws IOException {
        String content = IOUtils.toString(zipInputStream );
        JSONObject jsonObject = XML.toJSONObject(content);
        JSONObject relationships = jsonObject.getJSONObject("Relationships");
        if (relationships != null) {
            JSONArray relationshipArray = null;
            Object relationship = relationships.get("Relationship");
            if (relationship != null && relationship instanceof JSONArray) {
                relationshipArray = (JSONArray) relationship;
            } else if (relationship != null && relationship instanceof JSONObject  ) {
                JSONObject relationshipObj = (JSONObject) relationship;
                if (relationshipObj != null) {
                    relationshipArray = new JSONArray();
                    relationshipArray.add(relationshipObj);
                }
            }
            if (relationshipArray != null) {
                return processRelationships(relationshipArray, mapConfig);
            }
        }
        return null;
    }
    /**
     * å¤„理 relationshipArray ä¸­çš„关系项,更新配置信息。
     *
     * @param relationshipArray å…³ç³»é¡¹çš„ JSONArray
     * @param mapConfig         é…ç½®ä¿¡æ¯çš„ map
     * @return é…ç½®ä¿¡æ¯çš„ map
     */
    private static Map<String, String> processRelationships(JSONArray relationshipArray, Map<String, String> mapConfig) {
        Map<String, String> mapRelationships = new HashedMap<>();
        for (int i = 0; i < relationshipArray.size(); i++) {
            JSONObject relaItem = relationshipArray.getJSONObject(i);
            if (relaItem != null) {
                String id = relaItem.getStr("Id");
                String value = "/xl/" + relaItem.getStr("Target");
                if (mapConfig.containsKey(id)) {
                    String strImageId = mapConfig.get(id);
                    mapRelationships.put(value, strImageId);
                }
            }
        }
        return mapRelationships;
    }
    /**
     * @return {@link byte[]}
     * @description
     * @author bianhl
     * @date 2024/4/26 13:52
     */
    private static byte[] getFileStream(InputStream inputStream) {
            // åˆ›å»º ByteArrayOutputStream æ¥æš‚存流数据
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, length);
            }
            // å°† byteArrayOutputStream çš„内容获取为字节数组
            return byteArrayOutputStream.toByteArray();
        } catch (IOException e) {
            return null;
        }
    }
}