HTML 投影片 -> 原生、可編輯的 PPTX
此技能強制的規則:切勿將投影片圖片貼入 PowerPoint。 每一個正方形、長條、圓點、膠囊、線條與文字區塊都必須是使用者能移動、重新著色與重新輸入文字的實際 PowerPoint 物件。轉換器讀取的是渲染後的頁面(使用 Playwright 搭配瀏覽器本身的計算佈局),而非重新猜測 CSS,然後以 python-pptx 在完全相同的座標上繪製形狀。
執行方式
python scripts/html_to_pptx.py <deck.html> <out.pptx> [all | 1,3,5]
需要:pip install -r requirements.txt 與 playwright install chromium。
投影片是符合 .slide 的元素(1280x720 像素)。將 .html 檔案放置於圖片內嵌(data: URI)或旁邊的磁碟位置。examples/sample-deck.html 是一個可供先行測試的小型投影片。
擷取頁面時所需條件(腳本會自動處理):從 <html> 中移除 anim class、關閉 CSS 動畫/轉場、觸發 window 的 beforeprint 事件(許多投影片會在列印時顯示圖表)、套用列印媒體、縮放比例設為 1、隱藏帶有 .mode 或 .jump class 的元素(如主題切換、投影片導航)。若投影片有淺色/深色主題切換,轉換將以當前顯示的主題進行——請確保該主題為使用者想要的版本。
轉換對照表
| 在 HTML 中 | 在 PPTX 中 |
|---|---|
| 帶有背景、邊框、圓角的 div / 卡片 | 矩形 / 圓角矩形(半徑對應為角落調整) |
| 線性漸層背景 | 原生漸層填滿 |
| 單側邊框(強調條) | 細長矩形;極細/虛線邊框 -> 真實線條 |
帶有 border-radius:999px 的膠囊、圓形 | 膠囊 / 橢圓 |
文字(任何區塊,包含粗體/顏色區段、<br>、連結) | 每個區塊一個文字方塊,保留字型與超連結 |
<li> | 真實 PowerPoint 項目符號(保留標記顏色) |
| 內聯 SVG 的 rect/circle/line/polyline/path/text | 矩形、橢圓、連接線(保留箭頭)、帶有真實貝茲曲線的任意多邊形、文字方塊 |
SVG <textPath>(沿曲線排列的文字) | PowerPoint 曲線文字(上弧/下弧變形) |
CSS clip-path: polygon(...)(例如 V 形、斜角切割) | 任意多邊形形狀;若內部有相片,則裁剪至多邊形範圍 |
<img>、照片、圖示 PNG | 圖片(這些是點陣圖——屬正常情況) |
text-transform、letter-spacing、刪除線、透明度/Alpha | 套用至文字區段/填滿 |
雙檢視切換(.vtog 帶有 data-view=code 與 data-view=time 按鈕) | 為另一種檢視產生第二張投影片 |
| JS 動畫 | 僅保留最終靜止狀態 |
重要規則(每個都耗費不少時間——請務必保留)
- 文字位置經過校準,請勿憑「目視」修改。 PowerPoint 100% 行距 = 字型大小 × 1.2(Arial 與 Arial Black 皆同)。文字方塊的 top 應設為
rangeTop + (ascent-cap)*fs - lineHeight + K*fs,其中(ascent-cap, K)對於 Arial 為(0.189, 0.95),對於 Arial Black 為(0.385, 1.0),而line_spacing = cssLineHeight / (1.2*fs)。單行文字使用 100% 行距與wrap=none,並預留 slack 以避免重新換行。 - Windows 上的 Chrome 將
font-family: Arial搭配粗細 800/900 顯示為 ARIAL BLACK。 轉換器將其對應為 Arial Black(而非粗體)。若無此規則,每個粗體標題看起來會太細且寬度錯誤。 - 切勿將 inline-block 子元素合併至文字區塊。 只有
display:inline的子元素會合併成一個文字方塊;inline-block/flex 子元素需分別處理。 - 就地測量文字節點(對節點使用 Range)。將節點包裹在暫存的
<span>中會改變 grid/flex 佈局。 - 在 PowerPoint 中開啟結果以驗證其有效性。 python-pptx 可能寫出 PowerPoint 拒絕開啟的檔案(「PowerPoint 無法開啟檔案」)。已知原因包括:負值/NaN 形狀尺寸(收斂至最小值、移除 NaN 點)以及
clip-path中的calc()(需預先計算)。請以對半刪除形狀的方式逐步除錯並重新開啟。 - 帶有自訂幾何圖形的圖片,其填滿範圍是路徑的邊界框,而非圖片的框架。 若要將照片裁剪至多邊形,請將圖片尺寸設為多邊形的邊界框,並使用來源裁剪(
srcRect)處理其餘部分。 - 請勿截圖形狀(「將特殊形狀點陣化」)。改用自由形狀轉換標誌的 SVG 路徑與 clip-path 多邊形。
raster分支為最後手段。 - 跳過被裁剪的幽靈文字(大型淡色數字被其卡片切斷)——PowerPoint 無法裁剪文字方塊。
- PowerPoint 的
a:ln在spPr中位於 fill 之後;刪除主題p:style否則形狀會帶有陰影。 - 切勿覆蓋使用者已開啟的 .pptx——請改用新檔案名稱。
驗證(務必執行——絕不在未經檢查的情況下交付)
在已安裝 PowerPoint 的 Windows 上:
powershell -NoProfile -File scripts/render_pptx.ps1 -pptx <out.pptx> -outdir <png_dir> # PowerPoint 匯出為 PNG
python scripts/compare.py <deck.html> <png_dir> 1,2,3 <out.png> # HTML | PPTX 並排比較
python scripts/compare.py <deck.html> <png_dir> 6:6,7:8 <out.png> # 當投影片編號不同時:html:pptx
render_pptx.ps1 若使用者原本已開啟 PowerPoint,則不會關閉它。若無 PowerPoint,請以其他方式(例如 LibreOffice 無頭模式)將 .pptx 渲染為 PNG,命名為 s1.png、s2.png… 然後執行 compare.py。
閱讀比較 PNG 結果,修正後重新建置。典型執行後的清理工作:PowerPoint 中的文字略寬(字距調整所致),無結構性問題。
已知限制(請告知使用者)
- 文字位置針對 Arial 與 Arial Black 校準。其他字型可轉換,但在校準完成前(請在 PowerPoint 中測量字型頂部高度與行距),文字可能上下偏移數像素。
- 照片、圖示與標誌若為點陣圖則保持為圖片。文字則位於其卡片上方的獨立文字方塊中(非群組)。
- 動畫/切換效果被攤平為一個影格(切換中的第二種檢視會變成額外投影片)。
- 輻射漸層與個別角落的半徑為近似值;盒狀陰影則被忽略。
- 投影片尺寸固定為 1280x720 像素 -> 13.333 x 7.5 吋。
致謝
由 Impera Business Services 開發。MIT 授權——請參閱 LICENSE。