如何使用 openpyxl 处理 Excel 图像?Image 对象介绍
关注 1421
openpyxl Excel 图像对象 Image
openpyxl
包的Image
类,属于模块openpyxl.drawing.image
,表示 Microsoft Excel 工作表中的图像。Image
对象一般存储在 Excel 工作表对象中,而不是单元格对象,虽然图像可以将锚点设置到某一个单元格。
Image 类依赖于 pillow 包
要让Image
类正常工作,需要安装包pillow
,否则,openpyxl
将无法读取工作表中的图像,也无法添加图像至工作表。
创建 Excel 图像
如果你希望为 Excel 工作表添加图像,那么需要首先创建Image
对象,然后通过工作表对象的相关方法执行添加操作。
Image(img)
- img 参数
img
参数一般是一个表示图像文件路径的字符串,或一个实现了抽象基类os.PathLike
的对象。
from openpyxl.drawing.image import Image
# 创建一个 Image 对象
print(Image('python.png'))
<openpyxl.drawing.image.Image object at …>
为 Excel 工作表添加图像
Worksheet
和WriteOnlyWorksheet
对象的add_image
方法,可用于为 Excel 工作表添加图像,当然,这需要一个有效的Image
对象。
worksheet|writeonlyworksheet.add_image(img, anchor=None)
- img 参数
img
参数是一个Image
对象,其对应的图像将被添加至工作表。- anchor 参数
anchor
参数是一个表示单元格地址的字符串,相关的单元格将作为被添加图像的锚点(图像将被定位至单元格的左上角)。
在下面的示例中,我们将图像添加至工作表Images
,并设置其锚点为单元格B2
。
# 创建只写工作簿,并添加工作表 Images
from openpyxl import Workbook
wb = Workbook(True)
ws = wb.create_sheet('Images')
from openpyxl.drawing.image import Image
# 将图像 python.png 添加至工作表,锚点为 B2
img = Image('python.png')
ws.add_image(img, 'B2')
wb.save('Add.xlsx')
将同一个 Image 对象重复添加至同一个工作表对象可能会导致警告
如果一个Image
对象已经存在于某个工作表对象中,那么再次将其添加至该工作表可能会产生警告,但这些警告不会影响图像的添加。
如果你为同一个图像文件创建多个Image
对象,那么将这些Image
对象添加至某个工作表不会导致警告的出现,但可能导致保存后的文件过大,因为每个图像都会被存储,即使他们是一样的。
在下面的示例中,我们反复将Image
对象添加到工作表Images
,这导致了警告的产生。
# 创建只写工作簿,并添加工作表 Images
from openpyxl import Workbook
wb = Workbook(True)
ws = wb.create_sheet('Images')
from openpyxl.drawing.image import Image
# 创建一个 Image 对象,并添加至 Images
img = Image('python.png')
ws.add_image(img, 'A1')
# 重复添加会产生警告,但不影响添加
ws.add_image(img, 'B2')
ws.add_image(img, 'C3')
wb.save('Again.xlsx')
zipfile\__init__.py:…: UserWarning: Duplicate name: 'xl/media/image3.png'
不要将同一个 Image 对象添加至不同的工作表对象
如果将同一个Image
对象添加到不同的工作表对象中,那么该Image
对象所对应的图像仅能在一个工作表中正常显示,其他工作表将无法加载该Image
对象对应的图像。
并且,在保存 Excel 文件之后,再次以非只读方式读取保存的 Excel 文件,可能会导致异常KeyError: "There is no item named 'xl/media/…' in the archive"
。
在下面的示例中,我们首先将Image
对象添加至工作表Images1
,然后又将其添加至工作表Images2
,这会导致工作表Images1
中的图像无法正常加载。
# 创建只写工作簿,并添加工作表 Images1,Images2
from openpyxl import Workbook
wb = Workbook(True)
ws1 = wb.create_sheet('Images1')
ws2 = wb.create_sheet('Images2')
from openpyxl.drawing.image import Image
# 创建一个 Image 对象,并添加至 Images1
img = Image('python.png')
ws1.add_image(img, 'A1')
# 将 Image 对象添加至 Images2
ws2.add_image(img, 'B2')
wb.save('Diff.xlsx')
from openpyxl import load_workbook
# ERROR 不能以非只读方式读取 Diff.xlsx
wb = load_workbook('Diff.xlsx')
zipfile\__init__.py:…: UserWarning: Duplicate name: 'xl/media/image2.png'
…
KeyError: "There is no item named 'xl/media/image1.png' in the archive"
获取,替换,删除 Excel 工作表中的图像
openpyxl
包的设计者似乎不希望开发人员可以获取或设置 Excel 工作表中的图像,因此,Worksheet
和WriteOnlyWorksheet
对象拥有一个以_
开头的变量_images
,该变量是一个包含Image
对象的 Python 列表,每一个Image
对象对应工作表中的一个图像。
事实上,为Worksheet
或WriteOnlyWorksheet
对象的_images
列表添加Image
对象,或者替换或删除_images
列表中的Image
对象,等同于为工作表添加图像,或者替换或删除工作表中的图像。当然,你可以将一个新的 Python 列表直接赋值给Worksheet
或WriteOnlyWorksheet
对象的_images
变量,这将替换工作表中的所有图像。
worksheet|writeonlyworksheet._images
worksheet|writeonlyworksheet._images = images
- images 值
images
是一个 Python 列表,列表中的元素应该是Image
对象。
在下面的示例中,我们通过Worksheet
对象的_images
列表,对工作表中的图像进行了替换,删除和添加。
# 读取 Excel 文件 Img.xlsx 中的工作表 Images
from openpyxl import load_workbook
wb = load_workbook('Img.xlsx')
ws = wb['Images']
from openpyxl.drawing.image import Image
# 获取 Excel 工作表中的图像
print(f'一共 {len(ws._images)} 个图像')
# 替换第一个图像
ws._images[0] = Image('imac-icon.png')
# 删除第二个图像
del ws._images[1]
# 添加一个图像
ws._images.append(Image('python.png'))
wb.save('NewImg.xlsx')
一共 2 个图像
获取和设置 Excel 图像的锚点
Image
对象的anchor
变量,表示Image
对象对应的 Excel 图像的锚点,该变量可能是一个字符串,表示作为锚点的单元格的地址,也可能是openpyxl
包的TwoCellAnchor
对象,表示图像的显示区域。当你希望设置图像在工作表中的锚点时,可将表示单元格地址的字符串赋值给Image
对象的anchor
变量。
image.anchor
image.anchor = anchor
- anchor 值
anchor
可以是表示单元格地址的字符串。
TwoCellAnchor 对象
上述TwoCellAnchor
对象,可被Image
对象用于表示图像的显示区域。TwoCellAnchor
对象的_from
特性的col
和row
变量,是图像锚点所对应的单元格的列索引和行索引,0
表示第一列或第一行。
# 读取 Excel 文件 Img.xlsx 中的工作表 Images
from openpyxl import load_workbook
wb = load_workbook('Img.xlsx')
ws = wb['Images']
for i in ws._images:
# 获取 Excel 工作表中的图像的锚点
a = i.anchor
print(type(a))
print(f'锚点:{a._from.col},{a._from.row}')
# 设置新的锚点
i.anchor = 'E5'
wb.save('Anchor.xlsx')
<class 'openpyxl.drawing.spreadsheet_drawing.TwoCellAnchor'>
锚点:0,0
<class 'openpyxl.drawing.spreadsheet_drawing.TwoCellAnchor'>
锚点:2,1
获取 Excel 图像的原始大小
Image
对象的width
和height
变量,表示Image
对象对应的 Excel 图像的原始宽度和高度,这可能与图像在工作表中的实际显示大小不同。
image.width
image.height
在 Excel 文件Img.xlsx
中,工作表Images
包含两个显示大小不同的图像,但其原始大小一致。
# 读取 Excel 文件 Img.xlsx 中的工作表 Images
from openpyxl import load_workbook
wb = load_workbook('Img.xlsx')
ws = wb['Images']
# 获取 Excel 工作表中的图像的原始大小
for i in ws._images:
print(f'原始大小:{i.width}x{i.height}')
原始大小:128x128
原始大小:128x128
获取 Excel 图像的格式
Image
对象的format
变量是一个字符串,表示Image
对象对应的 Excel 图像的格式,如果无法得知图像的格式,那么format
变量保持其默认值png
。
image.format
在 Excel 文件Img.xlsx
中,工作表Chat
包含两个图像,他们的格式分别为png
和svg
,但格式为svg
的图像被识别为png
格式。
# 读取 Excel 文件 Img.xlsx 中的工作表 Chat
from openpyxl import load_workbook
wb = load_workbook('Img.xlsx')
ws = wb['Chat']
# 获取 Excel 工作表中的图像的格式
for i in ws._images:
print(f'格式:{i.format}')
格式:png
格式:png
Image 对象的其他特性
以下是Image
对象的其他相关特性。
- ref 变量
Image
对象的ref
变量表示图像的来源,他可能是表示图像文件路径的字符串,也可能是包含图像数据的对象,比如一个_io.BytesIO
对象。