从excel中提取嵌入式图片的解决方法

这篇具有很好参考价值的文章主要介绍了从excel中提取嵌入式图片的解决方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1  发现问题

我的excel中有浮动图片和嵌入式图片,但是openpyxl的_image对象只提取到了浮动图片,通过阅读其源码发现,这是因为openpyxl只解析了drawing文件导致的,所以确定需要自己解析

2  解决思路

1、解析出media资源

2、解析出xml,这可以得到资源的rNvpr-rId-image target的关系

3、从xlrd或openpyxl中得到单元格cNvpr,定位到图片

3  解析xlsx

先把xlsx解压出来,得到的文件如下,其中xl文件夹是我们需要的

从excel中提取嵌入式图片的解决方法,excel,python

我分析了里面的所有文件,发现这两个文件存储了嵌入式图片的关键信息

  • xl/cellimages.xml
  • xl/_rels/cellimages.xml

打开这两个文件看看,到底存储了什么?

3.1  xl/cellimages.xml

从excel中提取嵌入式图片的解决方法,excel,python

有效信息在cellImage对象中

  • cellImage.pic.nvPicPr.cNvPr.name:记录了函数名
  • cellImage.pic.blipFill.blip.embed:记录了rId

记录这个关系,并建立映射关系 { ID_xxx: rId }

3.2  xl/_rels/cellimages.xml

从excel中提取嵌入式图片的解决方法,excel,python

有效信息在Relationship对象中

  • Relationship.id:文件rId
  • Relationship.target:图片地址

建立这个映射关系 { rId: target }

到这一步我们已经可以从函数名定位到图片资源了,剩下一步建立excel单元格和图片的关系,接下来解析excel文件

{ ID_xxx: rId } + { rId: target } = ID_xxx -> target

4  代码实现

接下来简单的代码实现,有问题可以评论区留言,看到会回复

此实现基于openpyxl文章来源地址https://www.toymoban.com/news/detail-626675.html

from xml.etree.ElementTree import fromstring
from io import BytesIO
from zipfile import ZipFile

from openpyxl import load_workbook
from openpyxl.packaging.relationship import get_rels_path, get_dependents
from openpyxl.xml.constants import SHEET_DRAWING_NS, REL_NS, IMAGE_NS
from openpyxl.drawing.image import Image, PILImage


def parse_element(element):
    """
    将XML解析为 {ID_XXX: rId}
    :param element:
        <etc:cellImage>
            <xdr:pic>
                <xdr:nvPicPr>
                    <xdr:cNvPr id="2" name="ID_CBD7CEBC94B44923A5B447F3F21C1995" descr="upload_post_object_v2_167528160"/><xdr:cNvPicPr/>
                </xdr:nvPicPr>
                <xdr:blipFill>
                    <a:blip r:embed="rId1"/>
                    <a:stretch><a:fillRect/></a:stretch>
                </xdr:blipFill>
                <xdr:spPr>
                    <a:xfrm>
                    <a:off x="0" y="0"/>
                    <a:ext cx="9144000" cy="4796155"/>
                </a:xfrm>
                <a:prstGeom prst="rect">
                    <a:avLst/>
                </a:prstGeom>
                </xdr:spPr>
            </xdr:pic>
        </etc:cellImage>
    :return:
    """
    data = {}
    xdr_namespace = "{%s}" % SHEET_DRAWING_NS
    targets = level_order_traversal(element, xdr_namespace + "nvPicPr")

    for target in targets:
        # 是一个cellimage
        cNvPr = embed = ""
        for child in target:
            if child.tag == xdr_namespace + "nvPicPr":
                cNvPr = child[0].attrib["name"]
            elif child.tag == xdr_namespace + "blipFill":
                _rel_embed = "{%s}embed" % REL_NS
                embed = child[0].attrib[_rel_embed]

        if cNvPr:
            data[cNvPr] = embed

    return data


def level_order_traversal(root, flag):
    """层次遍历,查找目标节点"""
    queue = [root]
    targets = []
    while queue:
        node = queue.pop(0)
        children = [child.tag for child in node]
        if flag in children:
            targets.append(node)
            continue

        for child in node:
            queue.append(child)

    return targets



def handle_images(deps, archive) -> []:
    """
    将图片二进制内容封装为Image对象
    """
    images = []
    if not PILImage:  # Pillow not installed, drop images
        return images

    for dep in deps:
        if dep.Type != IMAGE_NS:
            msg = "{0} image format is not supported so the image is being dropped".format(dep.Type)
            print(msg)
            continue

        try:
            image_io = archive.read(dep.target)
            image = Image(BytesIO(image_io))
        except OSError:
            msg = "The image {0} will be removed because it cannot be read".format(dep.target)
            print(msg)
            continue
        if image.format.upper() == "WMF":  # cannot save
            msg = "{0} image format is not supported so the image is being dropped".format(image.format)
            print(msg)
            continue
        image.embed = dep.id         # 文件rId
        image.target = dep.target    # 文件地址
        images.append(image)

    return images

def main():
    CELLIMAGE_PATH = "xl/cellimages.xml"
    PARSE_FILE_PATH = 'C:/Users/user/Downloads/测试文件.xlsx'

    archive = ZipFile(PARSE_FILE_PATH, "r")
    wb = load_workbook(PARSE_FILE_PATH)

    src = archive.read(CELLIMAGE_PATH)                              # 打开cellImage.xml文件
    deps = get_dependents(archive, get_rels_path(CELLIMAGE_PATH))   # 解析cellImage.xml._rel文件
    image_rels = handle_images(deps=deps.Relationship, archive=archive)

    node = fromstring(src)
    cellimages_xml = parse_element(node)
    cellimages_rel = {}
    for image in image_rels:
        cellimages_rel[image.embed] = image

    for cnvpr, embed in cellimages_xml.items():
        cellimages_xml[cnvpr] = cellimages_rel.get(embed)


    archive.close()  # 关闭压缩文件对象,防止内存泄漏
    print(cellimages_xml)


if __name__ == '__main__':
    main()

到了这里,关于从excel中提取嵌入式图片的解决方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Nodejs移植到嵌入式ARM板方法

    Nodejs移植到嵌入式ARM板有3种方法: 在上位机虚拟机软件上安装ARM的交叉编译链,下载nodejs源码,使用交叉编译软件编译nodejs,得到ARM板上可执行的文件,并放到ARM板上,通过node xxx.js文件的方式执行。注意还需要移植依赖库到ARM板上。该方式适合小型的nodejs程序,例如一个小

    2024年02月04日
    浏览(40)
  • 嵌入式Linux交叉编译过程中遇到”cannot execute ‘cc1plus‘:execvp:No such file or directory“问题的解决方法

    今天又是遇到问题的一天,耗时两小时(因为找解决方法的过程中遇到了较多麻烦)。 问题的起因是我在编译T113-S3_100ask开发板驱动程序的过程中,突然中断报错了,错误如下图所示。 由于我也是刚接触嵌入式linux驱动编写,所以,对于一些问题看得不是很懂。所以,我选择

    2024年02月07日
    浏览(55)
  • 【嵌入式开发 Linux 常用命令系列 7 -- awk 常用方法】

    上篇文章:嵌入式开发 Linux 常用命令系列 6 – 字符提取 cut 命令使用 下篇文章:嵌入式开发 Linux 常用命令系列 8 – 二进制转为16进制常用命令 AWK是一种强大的文本分析工具,最初是由 Aho, Weinberger 和 Kernighan 设计和实现的,AWK 的名称就来源于他们三人的姓氏首字母。在Lin

    2024年02月15日
    浏览(60)
  • 嵌入式中详解 ARM 几个常见的寄存器方法

    大家好,今天来聊聊对于ARM几个特殊寄存器的理解,FP、SP和LR。 1、介绍 FP:栈顶指针,指向一个栈帧的顶部,当函数发生跳转时,会记录当时的栈的起始位置。 SP:栈指针(也称为栈底指针),指向栈当前的位置, LR:链接寄存器,保存函数返回的地址。 关于gcc就有一个关

    2024年02月20日
    浏览(42)
  • python+嵌入式——串口通信篇(收发解包)

    这几年,自己也做了一些嵌入式机器人。在整个开发的过程中,调通信通常会花费一段比较长的时间,串口通信就是这样的一个部分。 而现在在百度上进行搜索,发现对python串口通信的博客讲解,都有点太笼统了,这其中,应该与python在处理硬件底层速度较慢导致用的人少有

    2024年02月07日
    浏览(50)
  • 嵌入式奇妙之旅:Python与树莓派编程深度探索

    💂 个人网站:【 海拥】【神级代码资源网站】【办公神器】 🤟 基于Web端打造的:👉轻量化工具创作平台 💅 想寻找共同学习交流的小伙伴,请点击【全栈技术交流群】 在这个数字化的时代,嵌入式系统的应用越来越广泛,而树莓派作为一款强大的微型计算机,为我们提供

    2024年02月04日
    浏览(40)
  • STM32声源定位:实现声源定位的嵌入式解决方案

    声源定位是一项重要的技术,可以帮助我们确定声音的来源位置。在嵌入式系统中,使用STM32微控制器可以实现精确的声源定位。本文将介绍如何使用STM32实现声源定位,并提供相关的源代码。 声源定位的基本原理是通过多个麦克风阵列接收到的声音信号来计算声源的位置。

    2024年04月16日
    浏览(46)
  • 全志V3S嵌入式驱动开发(屏幕花屏问题的解决)

    【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】         之前我们测试过lcd屏幕驱动以及触控驱动时,当时确实是成功的。但是由于这个屏幕是直接从旗舰店买的,价格略贵,有点超出成本。后来,陆陆续续从其他店家买了3块lcd,测试的时

    2024年02月09日
    浏览(58)
  • 嵌入式Linux 开发经验:platform_driver_register 的使用方法

    嵌入式Linux 设备驱动开发时,经常遇到平台驱动 platform_driver_register 的注册,最近深入了看了驱动开发为何使用平台驱动 开发一个设备驱动时,为了实现 设备的 打开、关闭、控制等操作,可以注册为 Linux misc 设备,不过在这之前,可以先使用 platform_driver_register 注册平台驱动

    2024年01月15日
    浏览(41)
  • FANUC机器人嵌入式TCP/IP以太网通讯的具体方法

    在工业自动化领域中,FANUC机器人是广泛应用的一种先进设备。为了实现机器人与其他设备之间的通信,TCP/IP以太网是一种常用的通信协议。本文将介绍如何在FANUC机器人中实现嵌入式TCP/IP以太网通讯,并提供相应的源代码。 配置网络参数 首先,我们需要在FANUC机器人上配置

    2024年02月04日
    浏览(73)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包