Python读取wps中的DISPIMG图片格式

需求:
读出excel的图片内容,这放在微软三件套是很容易的,但是由于wps的固有格式,会出现奇怪的问题,只能读出:类似于 =DISPIMG(“ID_2B83F9717AE1XXXX920xxxx644C80DB1”,1) 【该DISPIMG函数只有wps才拥有】

本文参考该多个作者的思路:
https://blog.csdn.net/maudboy/article/details/133145278 java读取Excel,(支持WPS嵌入式图片)
以及该github issus:
https://github.com/qax-os/excelize/issues/664 How to read pictures embedded in cells
当然该项目两个个月前用go 来读取wps中的图片格式:https://github.com/qax-os/excelize excelize

希望大家多多关注

github前几名的excel读取,python在后几名【这让我挺吃惊的,作为第一语言,支持库这么多,竟然没有对wps图片解析的python代码】,第一是Go写的。
在这里插入图片描述

首先明确,xlsx就是一个zip包,否则里面的图片根本没法读取。
下面是该代码的思路:

# xlsx本质就是zip,其解压文件夹为_rels xl docProps
# 代码思路:首先读取excel表,并提取DISPIMG_id列,保存在image_list中
# 根据xl/cellimages.xml 提取出rId与DISPIMG_id的关系,组成一个map1,{"DISPIMG_id":"rId"}
# 再根据xl/_rels/cellimages.xml.rels,根据rId 与 imgae_path的关系,组成一个map2 {"rId":"image_path"}
# 根据map1与map2对应的关系,组成一个新map3 : {"DISPIMG_id": "image_path"} 得出对应的关系
# 输出图片,根据xl/{image_path} 输出图片并把图片重命名为DISPIMG_id.png

代码思路,该代码可以优化,主要多次读取文件并且多次调用map了,不过处理几百条数据还是绰绰有余的。

import zipfile
import os
import xml.etree.ElementTree as ET
import openpyxl



image_list = []  # 存放从excel读出的DISPIMG_id


def read_excel_data(filename_path):
    # 加载 Excel 文件
    workbook = openpyxl.load_workbook(filename_path, data_only=False)
    sheet = workbook.active

    # 遍历数据和公式
    data = [] # data就是文本信息
    for row in sheet.iter_rows(min_row=1, values_only=False):
        row_data = []
        for cell in row:
            if cell.value and isinstance(cell.value, str) and '=_xlfn.DISPIMG(' in cell.value:
                # 提取嵌入的图片 ID
                formula = cell.value
                start = formula.find('"') + 1
                end = formula.find('"', start)
                image_id = formula[start:end]
                row_data.append(f"{image_id}")
                image_list.append(image_id)
                # print(image_id)
            else:
                # 其他数据直接添加
                row_data.append(cell.value)
        data.append(row_data)
    return data


def get_xml_id_image_map(xlsx_file_path):
    # 打开 XLSX 文件
    with zipfile.ZipFile(xlsx_file_path, 'r') as zfile:
        # 直接读取 XML 文件内容
        with zfile.open('xl/cellimages.xml') as file:
            xml_content = file.read()
        with zfile.open('xl/_rels/cellimages.xml.rels') as file:
            relxml_content = file.read()

    # 将读取的内容转换为 XML 树
    root = ET.fromstring(xml_content)

    # 初始化映射字典
    name_to_embed_map = {}

    # 命名空间
    namespaces = {
        'xdr': 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing',
        'a': 'http://schemas.openxmlformats.org/drawingml/2006/main'
    }

    # 遍历所有 pic 元素
    for pic in root.findall('.//xdr:pic', namespaces=namespaces):
        name = pic.find('.//xdr:cNvPr', namespaces=namespaces).attrib['name']
        embed = pic.find('.//a:blip', namespaces=namespaces).attrib[
            '{http://schemas.openxmlformats.org/officeDocument/2006/relationships}embed']
        name_to_embed_map[name] = embed

    # 打印结果
    # print(name_to_embed_map)

    root1 = ET.fromstring(relxml_content)

    # 命名空间字典,根据 XML 中定义的命名空间进行设置
    namespaces = {'r': 'http://schemas.openxmlformats.org/package/2006/relationships'}

    # 创建 ID 和 Target 的映射
    id_target_map = {child.attrib['Id']: child.attrib.get('Target', 'No Target Found') for child in
                     root1.findall('.//r:Relationship', namespaces=namespaces)}

    # print(id_target_map)

    # 使用字典推导构建新的映射表
    name_to_target_map = {name: id_target_map[embed] for name, embed in name_to_embed_map.items() if
                          embed in id_target_map}
    return name_to_target_map


def output_id_image(xlsx_file_path):
    read_excel_data(xlsx_file_path)
    name_to_target_map = get_xml_id_image_map(xlsx_file_path)
    # 构建id_image_对
    new_map = {key: name_to_target_map.get(key) for key in image_list if key in name_to_target_map}
    print(new_map)
    output_directory = './images' #保存的图片目录
    # 打开xlsx文件(即Zip文件)
    with zipfile.ZipFile(xlsx_file_path, 'r') as zfile:
        for key, image_path in new_map.items():
            # 构建实际的图片路径
            actual_image_path = f'xl/{image_path}'  # 假设图片在'xl/media/'目录下
            if actual_image_path in zfile.namelist():
                # 读取图片内容
                with zfile.open(actual_image_path) as image_file:
                    image_content = image_file.read()
                    # 保存图片到新的文件,使用key作为文件名
                    new_file_path = os.path.join(output_directory, f"{key}.png")
                    with open(new_file_path, 'wb') as new_file:
                        new_file.write(image_content)
            else:
                print(f"File {actual_image_path} not found in the archive.")

if __name__ == '__main__':
    output_id_image('/home/jacin/Downloads/英式货表.xlsx')
    # 输出的图片名字就是 xlsx表中的列的DISPIMG_id,保存在images文件夹下
    # 并会在控制台输出一个字典,key是DISPIMG_id,value是图片的路径,例如:{'ID_BE7EFF591B6C4978XXXXXX5266': 'media/image118.png'}
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用:在没有 Python 或 Haskell 的有限 Windows 环境工作一段时间并制作 Excel VBA 模块后,在 VBA 上进行一小段函数式编程以减轻开发痛苦不是很好吗?因此,借助的一点魔力和 Python 的灵感,这里是一个纯 VBA 的准...。 引用:写在前面的话:经过大量的采图实验,数据散落各处,设备也调整过,标定参数之类的也都不一致,以前整理数据都是用的C/C 傻乎乎地system(“cp str str”)虽然知道shell更简单,但是毕竟懒,现在发现PY真是一把利器。1.0按照指定的文件路径组织文件。 问题:请告诉我,python DISPIMG是什么意思? 根据提供的引用内容,没有提到"python DISPIMG"的信息。请提供更多相关的上下文或信息,以便我能更好地回答您的问题。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [xlfn:Excel VBA 的伪函数式编程库](https://download.csdn.net/download/weixin_42164685/19287102)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [使用Python整理数据集,规范化数据](https://blog.csdn.net/u013000248/article/details/91361684)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值