如何使用 openpyxl 處理 Excel 影像?Image 物件介紹
訂閱 375
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
物件。
原始碼
src/zh-hant/openpyxl/images·codebeatme/office-programming·GitHub