如何使用 openpyxl 处理 Excel 图像?Image 对象介绍
关注 1800
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
格式:pngImage 对象的其他特性
以下是Image对象的其他相关特性。
- ref 变量
Image对象的ref变量表示图像的来源,他可能是表示图像文件路径的字符串,也可能是包含图像数据的对象,比如一个_io.BytesIO对象。