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

news2024/11/28 4:26:22

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


引言

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

提取图片资源的方法

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

主函数

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

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 文件中获取浮动图片:

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 文件中的图片数据,包括嵌入式图片和浮动式图片:

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获取到的图片资源



import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.XML;
import com.szjyrs.business.exhibition.product.domain.vo.ProductPlusImportLogVo;
import com.szjyrs.common.core.dev.method.MethodStatus;
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 org.springframework.web.multipart.MultipartFile;

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("D:\\" + 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 = cellImages.getJSONArray("etc:cellImage");
                if (cellImageArray == null) {
                    JSONObject cellImageObj = cellImages.getJSONObject("etc:cellImage");
                    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 = relationships.getJSONArray("Relationship");
            if (relationshipArray == null) {
                JSONObject relationshipObj = relationships.getJSONObject("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 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.coloradmin.cn/o/1631620.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

618科技嘉年华!五款极致科技产品,开启智能生活新篇章!

准备好迎接一年一度的618了吗&#xff1f;这不仅仅是一场购物的狂欢&#xff0c;更是一次科技的盛宴&#xff0c;一次智能生活的全新启航。今年&#xff0c;我们将带来五款令人瞩目的极致科技产品&#xff0c;它们将彻底颠覆你对智能生活的认知。从娱乐到工作&#xff0c;这些产…

逆向案例三十——webpack登录某游戏

网址&#xff1a;aHR0cHM6Ly93d3cuZ205OS5jb20v 步骤&#xff1a; 进行抓包分析&#xff0c;找到登录接口&#xff0c;发现密码有加密 跟栈分析&#xff0c;从第三个栈进入&#xff0c;打上断点&#xff0c;再次点击登录 明显找到password,它由o赋值&#xff0c;o由a.encode(…

RAGFlow:安装与体验

服务器需要有docker,或者直接访问官方提供的demo: https://demo.ragflow.io/ docker-compose安装 需要确保 vm.max_map_count 不小于 262144 【更多】:sysctl -w vm.max_map_count=262144 克隆仓库:$ git clone https://github.com/infiniflow/ragflow.git 进入 doc…

基于3D机器视觉的注塑缺陷检测解决方案

注塑检测是对注塑生产过程中的产品缺陷进行识别和检测的过程。这些缺陷可能包括色差、料流痕、黑点&#xff08;包括杂质&#xff09;等&#xff0c;它们可能是由多种因素引起&#xff0c;如原料未搅拌均匀、烘料时间过长、工业温度局部偏高、模具等问题造成的。不仅影响产品的…

STM32 SPI通信

一、SPI总线简介 1.1 SPI总线 串口外设接口&#xff08;Serial Peripheral Interface&#xff0c;SPI&#xff09;总线是一种同步串行外设接口&#xff0c;允许MCU与各种外围设备进行全双工、同步串行通信 SPI总线有四根通信线&#xff1a; ①SCK&#xff08;Serial Clock&a…

神经网络:手写数字图像识别

一、导入相关库函数 import matplotlib.pyplot as plt import tensorflow as tf import keras import numpy as np 二、载入mnist数据集 使用keras.中的mnist数据集 (train_images, train_labels), (test_images, test_labels)\ keras.datasets.mnist.load_data() 三、测…

【java9】java9新特性之接口的私有方法

在Java 9中&#xff0c;接口可以包含私有方法&#xff08;包括静态私有方法和实例私有方法&#xff09;。这允许接口的设计者创建一些辅助方法&#xff0c;这些方法只能被接口中的其他方法所使用&#xff0c;而不能被实现该接口的类直接访问。 Java7 Java7及之前 &#xff0c…

PyVista 3D数据可视化 Python 库 简介

Pyvista是一个用于科学可视化和分析的Python库 &#xff1b;我认为它适合做一些网格数据的处理&#xff1b; 它封装了VTK&#xff08;Visualization Toolkit&#xff09;之上&#xff0c;提供了一些高级接口&#xff0c; 3D数据可视化变得更加简单和易用。 1.安装 pyvista&…

嵌入式软件学习--linux(1)

一.文件系统 二.shell &#xff08;从环境变量中&#xff09;解析输入指令找到&#xff08;bin中&#xff09;对应命令。 三 ./执行是因为需要知道执行文件的路径&#xff0c; 同样可以使用绝对路径运行。 echo $PATH 查看环境变量 。若在&#xff0c;可执行 &#x…

Pycharm:常用插件安装和使用

简介&#xff1a;好用的插件可以美化界面或者提升效率&#xff0c;使工作事半功倍。 推荐插件&#xff1a; 1、CSV插件&#xff1a;美化csv数据展示 2、Translation&#xff1a;翻译的插件&#xff0c;可以进行中英互译 3、CodeGlance&#xff1a;代码小地图 4、Markdown …

GQA分组注意力机制

一、目录 定义demo 二、实现 定义 grouped query attention&#xff08;GQA&#xff09; 1 GQA 原理与优点&#xff1a;将query 进行分组&#xff0c;每组query 参数共享一份key,value, 从而使key, value 矩阵变小。 2. 优点&#xff1a; 降低内存读取模型权重的时间开销&am…

Llama 3 安装使用方法

Llama3简介&#xff1a; llama3是一种自回归语言模型&#xff0c;采用了transformer架构&#xff0c;目前开源了8b和70b参数的预训练和指令微调模型&#xff0c;400b正在训练中&#xff0c;性能非常强悍&#xff0c;并且在15万亿个标记的公开数据进行了预训练&#xff0c;比ll…

Java设计模式 _结构型模式_桥接模式

一、桥接模式 1、桥接模式 桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式。用于把一个类中多个维度的抽象化与实现化解耦&#xff0c;使得二者可以独立变化。 2、实现思路 使用桥接模式&#xff0c;一定要找到这个类中两个变化的维度&#xff1a;如支…

什么是中间件?中间件有哪些?

什么是中间件&#xff1f; 中间件&#xff08;Middleware&#xff09;是指在客户端和服务器之间的一层软件组件&#xff0c;用于处理请求和响应的过程。 中间件是指介于两个不同系统之间的软件组件&#xff0c;它可以在两个系统之间传递、处理、转换数据&#xff0c;以达到协…

[论文笔记]GAUSSIAN ERROR LINEAR UNITS (GELUS)

引言 今天来看一下GELU的原始论文。 作者提出了GELU(Gaussian Error Linear Unit,高斯误差线性单元)非线性激活函数&#xff1a; GELU x Φ ( x ) \text{GELU} x\Phi(x) GELUxΦ(x)&#xff0c;其中 Φ ( x ) \Phi(x) Φ(x)​是标准高斯累积分布函数。与ReLU激活函数通过输入…

Spring Web MVC入门(3)——响应

目录 一、返回静态页面 RestController 和 Controller之间的关联和区别 二、返回数据ResponseBody ResponseBody作用在类和方法的情况 三、返回HTML代码片段 响应中的Content-Type常见的取值&#xff1a; 四、返回JSON 五、设置状态码 六、设置Header 1、设置Content…

docker如何生成springboot镜像

1、在springboot的jar包所在的目录下创建Dockerfile文件&#xff0c;此案例的目录为/usr/java Dockerfile的文件内容如下&#xff1a; FROM openjdk:8 LABEL author"zengyanhui" LABEL email"1181159889qq.com" WORKDIR /usr/java/springbootdemo COPY s…

动漫渐显引导页HTML5单页源码

挺不错的动漫渐显引导页&#xff0c;记事本右键打开即可修改~ 动漫渐显引导页HTML5单页源码

重生之我是Nginx服务专家

nginx服务访问页面白色 问题描述 访问一个域名服务返回页面空白&#xff0c;非响应404。报错如下图。 排查问题 域名解析正常&#xff0c;网络通讯正常&#xff0c;绕过解析地址访问源站IP地址端口访问正常&#xff0c;nginx无异常报错。 在打开文件时&#xff0c;发现无法…

179. 最大数(LeetCode)

文章目录 前言一、题目讲解二、算法原理三、代码编写1.仿函数写法2.lambda表达式 四、验证五.总结 前言 在本篇文章中&#xff0c;我们将会带着大家采用贪心的方法解决LeetCode中最大数这道问题&#xff01;&#xff01;&#xff01; 一、题目讲解 一组非负整数&#xff0c;包…