Python实现Excel文件拷贝图片到另一个的Excel文件(保持原有图片比例)

Python实现Excel文件拷贝图片到另一个的Excel文件(保持原有图片比例)

  • 1、前言
    • 1.1 成功拷贝但是比例错误
    • 1.2 直接报错
  • 2、解决办法
  • 3、号外

1、前言

今天朋友给我一个需求,需要把xlsx文件中的图片拷贝到另一个xlsx中,但是试过网上比较普遍的几种方法,都不能达到很好的效果,比如下面几种方法:

1.1 成功拷贝但是比例错误

from openpyxl import Workbook
from openpyxl import load_workbook

# 加载工作簿和工作表
wb = load_workbook("test.xlsx")
ws = wb[wb.sheetnames[0]]

# 创建新的工作簿和工作表
new_wb = Workbook()
new_ws = new_wb.active

# 遍历原始工作表中的图片
for img in ws._images:
    new_ws.add_image(img)

# 保存新的工作簿
new_wb.save("output.xlsx")

源文件:

在这里插入图片描述
拷贝后的文件:

在这里插入图片描述

1.2 直接报错

from openpyxl import load_workbook
from openpyxl.drawing.image import Image

# 打开源文件和目标文件
source_file = "test.xlsx"
target_file = "output.xlsx"

# 加载源文件和目标文件
source_workbook = load_workbook(source_file)
target_workbook = load_workbook(target_file)

# 获取源文件和目标文件的第一个Sheet
source_sheet = source_workbook.active
target_sheet = target_workbook.active

# 遍历源Sheet中的图片,并拷贝到目标Sheet
for image in source_sheet._images:
    # 获取图片的坐标和文件路径
    image_coordinate = image.anchor
    image_path = image.filename

    # 从源文件中读取图片,然后在目标文件中插入图片
    with open(image_path, "rb") as f:
        img = Image(f)
        target_sheet.add_image(img, image_coordinate)

# 保存目标文件
target_workbook.save("output.xlsx")

报错如下:

Traceback (most recent call last):
  File "C:\Users\HUAWEI\Desktop\pythonProject\e.py", line 20, in <module>
    image_path = image.filename
AttributeError: 'Image' object has no attribute 'filename'

2、解决办法

网上查了很多方法,发现有一种方法大家很少提及,就是把xlsx文件转换为zip文件再进行解压提取照片,测试过是有效的,原理是这样的:

  1. 将待读取的excel文件后缀名改成zip,变成压缩文件。
  2. 再解压这个文件。
  3. 在解压后的文件夹中,就有excel中的图片。
  4. 这样读excel中的图片,就变成了读文件夹中的图片了,和普通文件一样,可以做各种处理。

解压后的压缩包如下,成功把图片提取出来了,后续插入新xlsx可以从这里提取操作:

在这里插入图片描述

代码如下:

import os
import zipfile


# 判断是否是文件和判断文件是否存在
def isfile_exist(file_path):
    if not os.path.isfile(file_path):
        print("It's not a file or no such file exist ! %s" % file_path)
        return False
    else:
        return True


# 修改指定目录下的文件类型名,将excel后缀名修改为.zip
def change_file_name(file_path, new_type='.zip'):
    if not isfile_exist(file_path):
        return ''
    extend = os.path.splitext(file_path)[1]  # 获取文件拓展名
    if extend != '.xlsx' and extend != '.xls':
        print("It's not a excel file! %s" % file_path)
        return False
    file_name = os.path.basename(file_path)  # 获取文件名
    new_name = str(file_name.split('.')[0]) + new_type  # 新的文件名,命名为:xxx.zip
    dir_path = os.path.dirname(file_path)  # 获取文件所在目录
    new_path = os.path.join(dir_path, new_name)  # 新的文件路径
    if os.path.exists(new_path):
        os.remove(new_path)
    os.rename(file_path, new_path)  # 保存新文件,旧文件会替换掉
    return new_path  # 返回新的文件路径,压缩包


# 解压文件
def unzip_file(zipfile_path):
    if not isfile_exist(zipfile_path):
        return False
    if os.path.splitext(zipfile_path)[1] != '.zip':
        print("It's not a zip file! %s" % zipfile_path)
        return False
    file_zip = zipfile.ZipFile(zipfile_path, 'r')
    file_name = os.path.basename(zipfile_path)  # 获取文件名
    zipdir = os.path.join(os.path.dirname(zipfile_path), str(file_name.split('.')[0]))  # 获取文件所在目录
    for files in file_zip.namelist():
        file_zip.extract(files, os.path.join(zipfile_path, zipdir))  # 解压到指定文件目录
    file_zip.close()
    return True


# 读取解压后的文件夹,打印图片路径
def read_img(zipfile_path):
    if not isfile_exist(zipfile_path):
        return False
    dir_path = os.path.dirname(zipfile_path)  # 获取文件所在目录
    file_name = os.path.basename(zipfile_path)  # 获取文件名
    pic_dir = 'xl' + os.sep + 'media'  # excel变成压缩包后,再解压,图片在media目录
    pic_path = os.path.join(dir_path, str(file_name.split('.')[0]), pic_dir)
    file_list = os.listdir(pic_path)
    for file in file_list:
        filepath = os.path.join(pic_path, file)
        print(filepath)


# 组合各个函数
def compenent(excel_file_path):
    zip_file_path = change_file_name(excel_file_path)
    if zip_file_path != '':
        if unzip_file(zip_file_path):
            read_img(zip_file_path)


# main
if __name__ == '__main__':
    compenent('C:/Users/HUAWEI/Desktop/pythonProject/test.xlsx')

3、号外

  1. 如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “👍点赞” “✍️评论” “💙收藏” 一键三连哦!
  2. 【👇🏻👇🏻👇🏻关注我| 获取更多源码 | 定制源码】大学生毕设模板、期末大作业模板 、Echarts大数据可视化等! 「一起探讨 ,互相学习」!(vx:python812146)
  3. 以上内容技术相关问题😈欢迎一起交流学习👇🏻👇🏻👇🏻🔥

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/37257.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[Lesson 01] TiDB数据库架构概述

目录 一 章节目标 二 TiDB 体系结构 1 TiDB Server 2.1 TiKV 2.2 TiFlash 3 PD 参考 一 章节目标 理解TiDB数据库整体架构了解TiDB Server TiKV tiFlash 和 PD的主要功能 二 TiDB 体系结构 了解这些体系结构是如何实现TiDB的核心功能的 1 TiDB Server TiDB Serve…

若依官方前端手册 小笔记

提供确认窗体信息 this.$modal.confirm(确认信息).then(function() {... }).then(() > {... }).catch(() > {}); 提供遮罩层信息 // 打开遮罩层 this.$modal.loading("正在导出数据&#xff0c;请稍后...");// 关闭遮罩层 this.$modal.closeLoading(); 验证…

pythonocc进阶学习:faces的inner wire与outer wire

总目录 >> PythonOCC入门进阶到实战(目前已更新入门篇、基础篇和进阶篇) 我们在这篇文章中绘制了带有holes的面&#xff0c; 本篇是在读取到外部文件如brep&#xff0c;igs&#xff0c;stp后获取面的性质&#xff0c;寻找面中的wires的正向与逆向 只显示外wire from O…

【LeetCode热题100】打卡第37天:岛屿数量反转链表

文章目录 【LeetCode热题100】打卡第37天&#xff1a;岛屿数量&反转链表⛅前言 岛屿数量&#x1f512;题目&#x1f511;题解 反转链表&#x1f512;题目&#x1f511;题解 【LeetCode热题100】打卡第37天&#xff1a;岛屿数量&反转链表 ⛅前言 大家好&#xff0c;我是…

【Spring core学习二】创建Spring 项目 Spring的存

目录 &#x1f31f;一、创建最原始的Spring-core项目。 &#x1f31f;二、怎么往Spring中存取对象&#xff1f; &#x1f337;1、在Spring中存对象 &#x1f337;2、通过getBean获取对象的三种方式 &#x1f337;3、通过factory方式获取对象 &#x1f31f;三、对存对象的…

用github的copilot;tmux中进去了> 怎么退出

1、首先要学籍认证 &#xff08;前提&#xff1a;(241条消息) Copilot使用的关卡——GitHub教育认证方法和注意事项_github教师认证_石去皿的博客-CSDN博客&#xff09; 网址&#xff1a;Are you a student? - GitHub Education (241条消息) GitHub学生认证&#xff0c;可…

微信小程序开发学习之页面导航(声明式导航和编程式导航)

微信小程序之页面导航&#xff08;声明式导航和编程式导航&#xff09; 1.0 页面导航1.1. 声明式导航1.1.1. 导航到tabBar页面1.1.2. 导航到非tabBar页面1.1.3. 后退导航 1.2. 编程式导航1.2.1. 导航到tabBar页面1.2.2. 导航到非tabBar页面1.2.3. 后退导航 1.3. 导航传参1.3.1.…

开发工具篇第25讲:阿里云MFA绑定Chrome浏览器Authenticator插件

开发工具篇第25讲&#xff1a;阿里云MFA绑定Chrome浏览器Authenticator插件 本文是开发工具篇第25讲&#xff0c;登录阿里云旗下产品时&#xff0c;需要使用mfa登录&#xff0c;每次如果要用手机看mfa码很麻烦&#xff0c; Chrome浏览器提供了一个快捷的登录方法&#xff0c;可…

Mac上提取应用APP的LOGO

1、找到想提取LOGO的应用&#xff0c;右键「显示包内容」 2、 双击【Contents】文件夹&#xff0c;再双击【Resources】文件夹 3、双击图标打开&#xff0c;选择最清晰的一帧&#xff0c;右键【导出为】 4、选择保存位置&#xff0c;格式注意选择常见格式&#xff0c;如png

通过git管理远程gitee仓库(push、pull)

通过git管理远程gitee仓库&#xff08;push、pull&#xff09; Git:是一种分布式版本控制系统&#xff0c;用于跟踪和管理软件开发项目的源代码和文件。它可以记录文件的修改历史&#xff0c;允许多人协同工作&#xff0c;并提供了撤销更改、分支管理、合并代码等功能。 Git最初…

一、对象的概念(2)

本章概要 复用继承 “是一个”与“像是一个”的关系 多态 复用 一个类经创建和测试后&#xff0c;理应是可复用的。然而很多时候&#xff0c;由于程序员没有足够的编程经验和远见&#xff0c;我们的代码复用性并不强。 代码和设计方案的复用性是面向对象程序设计的优点之一…

Spring Boot 中的 @Query 注解是什么,原理,如何使用

Spring Boot 中的 Query 注解是什么&#xff0c;原理&#xff0c;如何使用 在 Spring Boot 中&#xff0c;Query 注解是一个非常常用的注解&#xff0c;用于定义自定义查询语句。本文将介绍 Query 注解的作用、原理和使用方法。 1. Query 注解的作用 在 Spring Boot 中&#…

Linux——进程信号的发送

目录 一.信号发送的概念 首先来讲几个发送术语&#xff1a; 它有三种情况&#xff1a; 注意&#xff1a; 二.信号在内核中的表示示意图 三.信号捕捉 所以总结一下&#xff1a; 此时&#xff0c;会出现这样一个疑问&#xff1a;操作系统是如何得知现在被执行的进程是用户态…

【Spring Cloud Alibaba Seata 处理分布式事务】——每天一点小知识

&#x1f4a7; S p r i n g C l o u d A l i b a b a S e a t a 处理分布式事务 \color{#FF1493}{Spring Cloud Alibaba Seata 处理分布式事务} SpringCloudAlibabaSeata处理分布式事务&#x1f4a7; &#x1f337; 仰望天空&#xff0c;妳我亦是行人.✨ &#x1f98…

SpringCloud(4) Eureka 如何主动下线服务节点

目录 1.直接停掉客户端服务2.发送HTTP请求1&#xff09;调用DELETE接口2&#xff09;调用状态变更接口 3.客户端主动通知注册中心下线1&#xff09;代码示例2&#xff09;补充3&#xff09;测试 一共有三种从 Eureka 注册中心剔除服务的方式&#xff1a; 1.直接停掉客户端服务…

Unity Obfuscator

官方仓库 学习日期&#xff1a;2023-07-13&#xff08;防止后续仓库特性或功能更新无对比时间&#xff09; 目标&#xff1a;本文介绍使用此github库&#xff0c;混淆unity项目的代码&#xff0c;在ILSpy中无法正确反编译。 一、说明 官方说明 配置界面 Features: ControlFlow…

【Spring Boot】单元测试

单元测试 单元测试在日常项目开发中必不可少&#xff0c;Spring Boot提供了完善的单元测试框架和工具用于测试开发的应用。接下来介绍Spring Boot为单元测试提供了哪些支持&#xff0c;以及如何在Spring Boot项目中进行单元测试。 1.Spring Boot集成单元测试 单元测试主要用…

LabVIEW FPGA利用响应式数字电子板快速开发空间应用程序

LabVIEW FPGA利用响应式数字电子板快速开发空间应用程序 与传统的基于文本的语言相比&#xff0c;LabVIEW的编程和设计已被证明可以缩短开发时间。各种研究表明&#xff0c;生产率的提高在3到10倍之间。LabVIEW通过图形语言、集成开发环境和多个编译器的组合来实现这一点。 图…

Django_发送邮件

目录 一、开启SMTP服务并获取授权码 二、在Django的配置文件中添加邮箱服务配置 三、发送邮箱代码 源码等资料获取方法 使用django邮箱功能需要搭建smtp服务器&#xff0c;如果没有&#xff0c;可以使用第三方smtp服务器。 本文以第三方QQ邮箱服务器演示如何使用python的s…

接口的幂等性如何设计

前言 所谓幂等: 多次调用方法或者接口不会改变业务状态&#xff0c;可以保证重复调用的结果和单次调用的结果一致。 我们在开发中主要操作也就是CURD,其中读取操作和删除操作是天然幂等的&#xff0c;我们所关心的就是创建操作、更新操作。 创建操作一定是非幂等的因为要涉及…