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