From 77eaae1a96b2c6a0a23bafbacf39806acd1980b6 Mon Sep 17 00:00:00 2001
From: doum <doum>
Date: 星期四, 29 一月 2026 09:29:06 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'
---
server/services/src/main/java/com/doumee/core/annotation/excel/ExcelPictureUtil.java | 305 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 305 insertions(+), 0 deletions(-)
diff --git a/server/services/src/main/java/com/doumee/core/annotation/excel/ExcelPictureUtil.java b/server/services/src/main/java/com/doumee/core/annotation/excel/ExcelPictureUtil.java
new file mode 100644
index 0000000..08b073c
--- /dev/null
+++ b/server/services/src/main/java/com/doumee/core/annotation/excel/ExcelPictureUtil.java
@@ -0,0 +1,305 @@
+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) {
+ 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;
+ }
+
+ /**
+ * 鑾峰彇娴姩鍥剧墖锛屼互 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();
+ // 灏� inputStream 璇诲彇鍒� 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;
+ }
+ }
+
+}
\ No newline at end of file
--
Gitblit v1.9.3