JAVA读取从WPS在Excel中嵌入的图片资源

ops/2025/2/16 6:45:45/

读取从WPS在Excel中嵌入的图片资源


引言

许多数据文件中可能包含嵌入式图片,这些图片对于数据分析和可视化非常重要。然而,从 WPS 在 Excel 中读取这些图片可能会有一些技术挑战。在本文中,我将展示如何从 WPS Excel 文件中读取嵌入的图片,并提供代码示例。

提取图片资源的方法

以下是用于从 WPS Excel 文件中读取图片资源的方法。我们使用了 Apache POI 库来处理 Excel 文件,并使用了 cn.hutool.json 库来处理 XML 数据。这些库可以帮助我们解析 Excel 文件中的嵌入式图片。
在这里插入图片描述

主函数

首先,我们定义了主函数 main,用于测试图片提取功能:

java">public static void main(String[] args) {PicturesUtils picturesUtils = new PicturesUtils();byte[] fileData = picturesUtils.getFileStream(new File("你的文件路径"));Map<String, XSSFPictureData> pictures = picturesUtils.getPictures(fileData);pictures.forEach((id, xssfPictureData) -> {System.out.println("id:" + id);String fileName = xssfPictureData.getPackagePart().getPartName().getName();System.out.println("fileName:" + fileName);File file = new File("D:\\" + fileName);File dir = file.getParentFile();dir.mkdirs();try {Files.write(Path.of(file.getPath()), xssfPictureData.getData());} catch (IOException e) {e.printStackTrace();}});
}

在这个函数中,我们创建了一个 PicturesUtils 实例,并从文件路径中获取文件数据。然后,我们调用 getPictures 方法来提取图片资源,并遍历结果将图片写入本地文件。

获取浮动图片

接下来,我们展示了如何从 Excel 文件中获取浮动图片:

java">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 picture) {XSSFClientAnchor anchor = (XSSFClientAnchor) picture.getAnchor();XSSFPictureData pictureData = picture.getPictureData();String key = anchor.getRow1() + "-" + anchor.getCol1();mapFloatingPictures.put(key, pictureData);}}}return mapFloatingPictures;
}

该方法接收一个 XSSFSheet 对象,并返回一个包含浮动图片的映射。它遍历工作表中的所有形状,并将图片数据存储在映射中。

处理图片数据

最后,我们展示了如何处理 Excel 文件中的图片数据,包括嵌入式图片和浮动式图片:

java">public 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<>();}
}

在该方法中,我们使用 processZipEntries 和 processPictures 方法来处理 Zip 文件中的条目和图片数据。然后,通过遍历 Excel 文件中的所有工作表,获取浮动图片。

完整代码示例

实际在程序中读取的内容为=DISPIMG(“ID_03BC802DDAB24510A9883DB157EAC0F8”,1)公式
将公式中的id提取出来ID_03BC802DDAB24510A9883DB157EAC0F8,最后就可以使用下面方法拿到当前id获取到的图片资源 jdk版本17

java">
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.nio.file.Files;
import java.nio.file.Path;
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 PicturesUtils {public static void main(String[] args) {PicturesUtils picturesUtils = new PicturesUtils();byte[] fileData = picturesUtils.getFileStream(new File("你的文件路径"));Map<String, XSSFPictureData> pictures = picturesUtils.getPictures(fileData);pictures.forEach((id, xssfPictureData) -> {System.out.println("id:" + id);String fileName = xssfPictureData.getPackagePart().getPartName().getName();System.out.println("fileName:" + fileName);File file = new File("C:\\Users\\XXX\\Desktop\\" + fileName);File dir = file.getParentFile();dir.mkdirs();try {Files.write(Path.of(file.getPath()), xssfPictureData.getData());} catch (IOException e) {e.printStackTrace();}});}/*** 获取浮动图片,以 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 picture) {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 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 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 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 void processCellImages(ZipInputStream zipInputStream, Map<String, String> mapConfig) throws IOException {String content = IOUtils.toString(zipInputStream, StandardCharsets.UTF_8);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 cellImageObj) {if (cellImageObj != null) {cellImageArray = new JSONArray();cellImageArray.add(cellImageObj);}}if (cellImageArray != null) {processImageItems(cellImageArray, mapConfig);}}}}/*** 处理 cellImageArray 中的图片项,更新图片配置信息。** @param cellImageArray 图片项的 JSONArray* @param mapConfig      配置信息的 map*/private 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 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 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 Map<String, String> processCellImagesRels(ZipInputStream zipInputStream, Map<String, String> mapConfig) throws IOException {String content = IOUtils.toString(zipInputStream, StandardCharsets.UTF_8);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 relationshipObj) {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 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;}/*** @param file 数据文件* @return {@link byte[]}* @description* @author bianhl* @date 2024/4/26 13:52*/private byte[] getFileStream(File file) {try (InputStream inputStream = new FileInputStream(file)) {// 创建 ByteArrayOutputStream 来暂存流数据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;}}}

输出结果:
在这里插入图片描述
拿到的图片数据
在这里插入图片描述


http://www.ppmy.cn/ops/26827.html

相关文章

明德扬逻辑设计基本功修炼课考试体会_我的FPGA成长篇

本文为明德扬原创文章&#xff0c;转载请注明出处&#xff01;作者&#xff1a;明德扬学员&#xff1a;考试酷账号&#xff1a;11167760 大家好&#xff0c;我是基本功修炼班的学员。从2023年8月开始&#xff0c;我参加了考试酷&#xff0c;并且已经获得了全套项目课程奖励&am…

qt嵌入并控制外部程序

一、流程 1、调用Window接口模拟鼠标&#xff0c;键盘事件 POINT point; LPPOINT lpppoint &point; GetCursorPos(lpppoint);//获取鼠标位置 SetCursorPos(point.x, point.y);//设置鼠标位置//鼠标左键按下 mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, poi…

go语言获取变量类型的4种方式

在go语言中我们常常需要获取某个变量的类型&#xff0c;其他语言如python可以使用 type(x), javascript中可以使用 typeof x 获取变量类型&#xff0c; Go 语言中我们也可以通过一下4种方式获取变量的类型。 1. 通过 fmt.Printf 的 %T 打印变量的类型&#xff1b; var x flo…

Podman与Docker有何不同?

Podman与Docker在安全性、守护进程和兼容性方面存在显著差异。具体如下&#xff1a; 安全性&#xff1a; Docker需要root权限才能运行守护进程&#xff0c;这可能导致安全风险&#xff0c;因为配置不当的容器可能会获得对主机文件系统的无限制访问。Podman允许以非特权用户启…

前端科举八股文-CSS篇

前端科举面经-CSS篇 Css选择器的优先级css盒模型行内元素和块级元素的区别?link标签和import标签的区别讲一下弹性盒子布局的常见属性flex是哪三个属性的简写什么是BFC&#xff1f; 有什么作用垂直居中的方法?visibilityhidden, opacity0&#xff0c;display:none的区别清除浮…

数据结构——二叉树(堆)

二叉树顺序结构以及实现 普通的二叉树是不适合用数组来存储的&#xff0c;因为可能会存在大量的空间浪费&#xff0c;因此完全二叉树更适合使用顺序结构来存储。 二叉树一般有两种结构存储: 顺序结构和链式结构。 顺序结构也就是顺序表(数组)来存储&#xff0c;一般只有完全二…

[论文笔记]SEARCHING FOR ACTIVATION FUNCTIONS

引言 今天带来另一篇激活函数论文SEARCHING FOR ACTIVATION FUNCTIONS的笔记。 作者利用自动搜索技术来发现新的激活函数。通过结合详尽的搜索和基于强化学习的搜索&#xff0c;通过实验发现最佳的激活函数 f ( x ) x ⋅ sigmoid ( β x ) f(x) x \cdot \text{sigmoid}(βx…

创建SpringBoot和RabbitMQ的整合项目

文章目录 创建SpringBoot和RabbitMQ的整合项目首先快速创建一个maven项目引入SpringBoot整合rabbitMQ的依赖在src/main目录下创建resources目录并引入配置文件写消息发送者MessageSender写消息接收者MessageReceiver写RabbitMQConfig配置类写SpringBoot启动主类CommandLineRunn…