Python基于OpenPyxl實(shí)現(xiàn)Excel轉(zhuǎn)PDF并精準(zhǔn)控制分頁(yè)
在 Python 自動(dòng)化辦公(RPA)的場(chǎng)景中,我們經(jīng)常需要自動(dòng)生成帶有圖表或圖片的 Excel 報(bào)表,并最終將其導(dǎo)出為 PDF。
但你是否遇到過(guò)這種情況:代碼跑得很歡,生成的 Excel 也很完美,但一轉(zhuǎn)成 PDF,精美的圖表剛好被切成了兩半,一半在第一頁(yè)頁(yè)腳,另一半在第二頁(yè)頁(yè)眉?
這不僅難看,還顯得非常不專業(yè)。今天,我們就來(lái)聊聊如何利用 openpyxl 中的 Break 對(duì)象,精準(zhǔn)控制分頁(yè),讓你的報(bào)表“指哪打哪”。
核心原理:手動(dòng)管理分頁(yè)符
Excel 本身是基于單元格(Grid)流式布局的,圖片是懸浮在單元格之上的層(Layer)。默認(rèn)情況下,Excel 的自動(dòng)分頁(yè)邏輯只看單元格高度,完全不管上面有沒(méi)有壓著圖片。
要解決這個(gè)問(wèn)題,我們需要“強(qiáng)行”告訴 Excel:“這里不僅是圖片結(jié)束的地方,也是這一頁(yè)結(jié)束的地方。”
這就需要用到 openpyxl.worksheet.pagebreak.Break。
簡(jiǎn)單來(lái)說(shuō),我們的策略是:在插入圖片之前和之后,分別插入一個(gè) Row Break(行分頁(yè)符),給圖片劃定一個(gè)獨(dú)立的“安全區(qū)”。
實(shí)戰(zhàn)代碼
我們需要用到 openpyxl 庫(kù)。如果你還沒(méi)有安裝,請(qǐng)執(zhí)行:
pip install openpyxl pillow
1. 基礎(chǔ)實(shí)現(xiàn):不跨頁(yè)的核心邏輯
下面的代碼演示了如何在一個(gè) Excel 中插入圖片,并確保每張圖片都獨(dú)占一頁(yè)(或者至少保證圖片頭部是從新的一頁(yè)開(kāi)始)。
from openpyxl import Workbook
from openpyxl.drawing.image import Image
from openpyxl.worksheet.pagebreak import Break
from openpyxl.utils import get_column_letter
def create_pdf_friendly_report():
wb = Workbook()
ws = wb.active
ws.title = "圖片不跨頁(yè)示例"
# 假設(shè)我們有一組圖片路徑
image_paths = ["chart1.png", "chart2.png", "chart3.png"] # 請(qǐng)確保目錄下有這些圖片,或替換為實(shí)際路徑
current_row = 1
for idx, img_path in enumerate(image_paths):
try:
img = Image(img_path)
except FileNotFoundError:
print(f"找不到圖片: {img_path},跳過(guò)")
continue
# --- 核心步驟 1: 插入前置分頁(yè)符 (Before Break) ---
# 如果不是第一張圖,我們?cè)趫D片開(kāi)始前強(qiáng)制換頁(yè),保證圖片從頁(yè)首開(kāi)始
if idx > 0:
# 注意:Break 的 id 對(duì)應(yīng)的是行索引。
# 在 current_row - 1 處打斷,意味著 current_row 將是新的一頁(yè)的開(kāi)始
page_break = Break(id=current_row - 1)
ws.row_breaks.append(page_break)
# --- 步驟 2: 放置圖片 ---
# 定位單元格,例如 A1, A20, A40...
cell_location = f"A{current_row}"
ws.add_image(img, cell_location)
# 添加一些描述文字(可選)
ws[cell_location] = f"圖表 {idx + 1}: 銷售數(shù)據(jù)分析"
# --- 步驟 3: 計(jì)算圖片占用的行數(shù) ---
# 這是一個(gè)估算。Excel默認(rèn)行高約 15 像素(20 units)。
# 我們需要根據(jù)圖片高度計(jì)算它大概跨越了多少行,以便更新 current_row
# img.height 是像素值
rows_to_skip = int(img.height / 20) + 2 # +2 是留一點(diǎn)余量
# --- 核心步驟 4: 插入后置分頁(yè)符 (After Break) ---
# 計(jì)算圖片結(jié)束的行
end_row = current_row + rows_to_skip
# 在圖片結(jié)束后強(qiáng)制換頁(yè)(如果你希望一頁(yè)只有一張圖)
# 如果你希望緊接著放文字,這步可以省略,只依賴“前置分頁(yè)符”即可
break_after = Break(id=end_row)
ws.row_breaks.append(break_after)
# 更新下一張圖的起始位置
current_row = end_row + 1
# 保存結(jié)果
wb.save("完美分頁(yè)報(bào)表.xlsx")
print("Excel 生成完畢,請(qǐng)打開(kāi)打印預(yù)覽查看分頁(yè)效果。")
if __name__ == "__main__":
# 為了演示,請(qǐng)先準(zhǔn)備幾張名為 chart1.png 等的圖片,或者修改代碼中的路徑
create_pdf_friendly_report()2. 代碼解析
1.from openpyxl.worksheet.pagebreak import Break: 這是主角。它是 OpenPyxl 用來(lái)標(biāo)記分頁(yè)符的類。
2.ws.row_breaks.append(...): 工作表對(duì)象有一個(gè) row_breaks 列表。我們將創(chuàng)建好的 Break 對(duì)象添加進(jìn)去即可。
注意: 還有一個(gè) col_breaks,那是用于橫向分頁(yè)的(列寬不夠時(shí)),但處理圖片跨頁(yè)通常使用的是行分頁(yè)。
3.Break(id=row_index): 這里的 id 是關(guān)鍵。
OpenPyxl 的邏輯是:當(dāng)你把 id 設(shè)為 10,Excel 會(huì)在第 10 行之后不僅是一條分界線,第 11 行將成為下一頁(yè)的第一行。
進(jìn)階技巧:動(dòng)態(tài)計(jì)算與流式布局
上面的代碼是“一頁(yè)一張圖”的暴力解法。如果你希望文字和圖片混排,僅在圖片即將跨頁(yè)時(shí)才插入分頁(yè)符,該怎么辦?
這就需要計(jì)算“當(dāng)前頁(yè)剩余高度”。但這在純 Python 端很難精確做到,因?yàn)?Excel 的渲染受打印機(jī)驅(qū)動(dòng)、頁(yè)邊距設(shè)置影響很大。
推薦的工程化方案:
不要去計(jì)算“能不能塞得下”,而是防御性分頁(yè)。
- 策略:將“標(biāo)題 + 圖片 + 圖片說(shuō)明”視為一個(gè)原子塊(Block)。
- 操作:在這個(gè)原子塊開(kāi)始之前,無(wú)條件插入一個(gè)
Break(除非它是文檔的開(kāi)頭)。雖然這可能會(huì)導(dǎo)致上一頁(yè)留有較多空白,但它能 100% 保證圖片完整展示。
def insert_atomic_block(ws, img_path, title, start_row):
"""
插入一個(gè)原子塊,并強(qiáng)制在塊之前分頁(yè)
"""
# 1. 強(qiáng)制分頁(yè)(開(kāi)啟新的一頁(yè))
if start_row > 1:
ws.row_breaks.append(Break(id=start_row - 1))
# 2. 寫(xiě)入標(biāo)題
ws.cell(row=start_row, column=1, value=title)
# 3. 插入圖片
img = Image(img_path)
ws.add_image(img, f"A{start_row + 1}")
# 4. 返回下一個(gè)可用的行號(hào)
# 估算高度:標(biāo)題1行 + 圖片高度/20 + 余量
height_rows = 1 + int(img.height / 20) + 2
return start_row + height_rows總結(jié)
利用 openpyxl.worksheet.pagebreak.Break,我們不再是被動(dòng)接受 Excel 的默認(rèn)打印行為,而是掌握了主動(dòng)權(quán)。
- 原理:
Break(id=row)也是對(duì)象,添加到ws.row_breaks列表。 - 技巧:在圖片插入前及插入后計(jì)算出的位置,分別通過(guò)代碼插入分頁(yè)符。
- 效果:生成的 Excel 在打印預(yù)覽或?qū)С?PDF 時(shí),圖片將擁有獨(dú)立且完整的頁(yè)面空間。
下次做自動(dòng)化報(bào)表時(shí),加上這幾行代碼,讓你的交付成果更加專業(yè)!
到此這篇關(guān)于Python基于OpenPyxl實(shí)現(xiàn)Excel轉(zhuǎn)PDF并精準(zhǔn)控制分頁(yè)的文章就介紹到這了,更多相關(guān)Python Excel轉(zhuǎn)PDF內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 從入門(mén)到實(shí)戰(zhàn)詳解Python如何將Excel工作表轉(zhuǎn)換為PDF
- Python使用Spire.XLS for Python輕松實(shí)現(xiàn)Excel轉(zhuǎn)PDF的完整指南
- Python自動(dòng)化辦公之Excel、Word和PDF操作指南
- 使用Python將PDF轉(zhuǎn)成Excel的代碼實(shí)現(xiàn)
- 使用Python高效實(shí)現(xiàn)Excel轉(zhuǎn)PDF
- 使用Python實(shí)現(xiàn)Office文檔(Word/Excel/PowerPoint)批量轉(zhuǎn)換為PDF
- 使用Python提取PDF表格到Excel文件的操作步驟
- Python將Office文檔(Word、Excel、PDF、PPT)轉(zhuǎn)為OFD格式的實(shí)現(xiàn)方法
相關(guān)文章
python使用sklearn實(shí)現(xiàn)決策樹(shù)的方法示例
這篇文章主要介紹了python使用sklearn實(shí)現(xiàn)決策樹(shù)的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
pycharm 如何跳出服務(wù)器證書(shū)不受信任的提示
這篇文章主要介紹了pycharm 跳出服務(wù)器證書(shū)不受信任的提示操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-03-03
Python使用flask作為web服務(wù)器的代碼實(shí)現(xiàn)
Python Flask 框架是一個(gè)輕量級(jí)的 Web 框架,它簡(jiǎn)單易用,靈活多變,非常適合用于構(gòu)建小型到中型規(guī)模的 Web 應(yīng)用程序,本文給大家介紹了Python使用flask作為web服務(wù)器的代碼實(shí)現(xiàn),需要的朋友可以參考下2024-06-06
Python使用keras和tensorflow遇到的問(wèn)題及解決
這篇文章主要介紹了Python使用keras和tensorflow遇到的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
解決List.append()?在?Python?中不起作用的問(wèn)題
在?Python?中,我們通常使用?List.append()?方法向列表末尾添加元素,然而,在某些情況下,你可能會(huì)遇到?List.append()?方法不起作用的問(wèn)題,本文將詳細(xì)討論這個(gè)問(wèn)題并提供解決方法,需要的朋友可以參考下2023-06-06
Python學(xué)習(xí)之列表常用方法總結(jié)
這篇文章主要為大家介紹了Python中列表的幾個(gè)常用方法總結(jié),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Python列表有一定幫助,需要的可以參考一下2022-03-03
python3+PyQt5實(shí)現(xiàn)自定義流體混合窗口部件
這篇文章主要為大家詳細(xì)介紹了python3+PyQt5實(shí)現(xiàn)自定義流體混合窗口部件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04

