PPTX 建立、編輯與分析
.pptx 是本 ZIP 壓縮的 XML 檔案。請根據任務選擇方法:
| 任務 | 方法 |
|---|---|
| 建立 新簡報 | 撰寫 pptxgenjs 腳本 — 請參考下方的注意事項 |
| 編輯 現有簡報,或從範本建立 | 解壓縮 → 編輯 ppt/slides/slideN.xml → 壓縮 |
| 讀取 內容 | markitdown deck.pptx(每個投影片一個區塊,介於 <!-- Slide number: N --> 標記之間);視覺網格:python scripts/thumbnail.py deck.pptx |
腳本
路徑是相對於此技能目錄的。其他一切都是純 Python、node 或 shell。
| 腳本 | 功能 |
|---|---|
scripts/thumbnail.py deck.pptx [prefix] | 每個投影片的標籤式網格,用於選擇範本版面。僅適用 .pptx。傳遞 prefix — 預設為 thumbnails,這會覆蓋同一目錄中任何其他簡報的網格 |
scripts/add_slide.py unpacked/ slide2.xml [--after slideN.xml] | 複製一個投影片(或 slideLayoutN.xml),並處理所有套件管理。也可以直接接受 .pptx 並搭配 -o out.pptx |
scripts/clean.py unpacked/ | 刪除不再被參照的投影片、媒體和關係檔案。在 <p:sldIdLst> 最終確定後執行 |
scripts/office/validate.py deck.pptx [--original src.pptx] | 進行結構描述、關係、內容類型、圖表和投影片檢查;每個失敗都會指出其修正方法。傳遞 --original 用於任何從範本衍生的簡報 — 它會將結構描述檢查與範本進行基準比對,這樣範本本身的 XSD 錯誤就不會算成你的錯誤 |
scripts/office/soffice.py --headless --convert-to pdf deck.pptx | LibreOffice 包裝器 — 在此沙箱中,單純的 soffice 會掛起 |
使用 pptxgenjs 建立 — 注意事項
pptxgenjs 已預先安裝 — 請勿先執行 npm install;直接撰寫腳本並使用 require('pptxgenjs')。僅在該 require 失敗時才執行:npm install pptxgenjs。模型知道 API;以下是常見陷阱:
- 在新增投影片之前先設定
pres.layout。 預設畫布是LAYOUT_16x9= 10" × 5.625",不是 13.3" 寬。超出邊緣的座標會被寫入,但不會被限制 — 形狀只是不在投影片上。(LAYOUT_WIDE是 13.3" × 7.5"。) - 十六進位顏色:永遠不要使用
#,永遠不要 8 位數。 使用color: "FF0000"。"#FF0000"和內嵌在十六進位中的 alpha("00000020")都會損壞檔案。若要實現半透明:在填色和圖片上使用transparency: 0-100,在陰影上使用opacity: 0.0-1.0— 每個屬性在錯誤的對象上都會被靜默忽略。 - pptxgenjs 會原地修改選項物件(在首次使用時將值轉換為 EMU)。永遠不要在兩個
add*呼叫之間共用一個shadow/選項物件 — 每次都建立一個新的物件。 - 陰影
offset必須 ≥ 0 — 負數的偏移會損壞檔案。若要將陰影向上投射,請使用angle: 270並搭配正數的偏移。 letterSpacing會被靜默忽略 — 實際的選項是charSpacing。- 列表: 每個項目上使用
bullet: true,永遠不要使用字面意義的•(會導致雙重項目符號)。在除了最後一個之外的每個陣列項目上設定breakLine: true。使用paraSpaceAfter來間隔帶項目符號的段落,而不是lineSpacing(會產生巨大間距)。 - 每個輸出檔案使用一個
new pptxgen()— 永遠不要重複使用同一個實例。 rectRadius僅適用於ROUNDED_RECTANGLE,不適用於RECTANGLE。- 不支援漸層填色 — 請改用漸層圖片作為背景。
- 文字方塊有內建的內部邊距 — 每當文字需要與相同 x 位置的形狀、線條或圖示對齊時,請設定
margin: 0。 - 備忘稿應放入
slide.addNotes("...")(純文字,每個投影片一次),永遠不要放在投影片上的文字方塊中。 - 保持圖表為原生格式。 對於 PowerPoint 可以圖表化的所有內容,使用
addChart()(傳遞一個{type, data, options}陣列來組合圖表)。對於函式庫未公開的 PowerPoint 原生功能(趨勢線、誤差線),請自行計算額外的數列,或後處理生成的 OOXML — 不要退而使用渲染圖片。只有 PowerPoint 沒有原生形式的圖表類型(Sankey、網路、和弦圖)才能以圖片形式放入。 - 預設圖表渲染得很簡陋 — 沒有標題、沒有資料標籤、使用過時的調色盤。請設定
showTitle+title、showValue: true+dataLabelPosition、從你的調色盤設定chartColors: [...],並讓框架安靜(catAxisLabelColor/valAxisLabelColor、valGridLine: { color, size }、catGridLine: { style: "none" }、如果是單一數列則設showLegend: false)。 - 在堆疊長條圖或柱狀圖上,
dataLabelPosition必須是ctr、inEnd或inBase。outEnd會損壞檔案。 - 使用
secondaryValAxis/secondaryCatAxis的組合圖表數列需要在圖表選項中同時提供valAxes和catAxes,各兩個條目。 沒有它們,pptxgenjs 會寫入從未宣告的軸 id,而 PowerPoint 會丟棄該圖表並報告檔案已損壞。僅提供valAxes是不夠的。 - 在
writeFile()之後,執行python scripts/office/validate.py deck.pptx。 它會報告上述兩個圖表錯誤以及 PowerPoint 會拒絕的投影片 XML 缺陷,並為每個錯誤指出修正方法。請在你的生成器中修正它們,而不是手動編輯壓縮後的 XML。 - 永遠不要重新排序
<p:presentation>的子元素。 pptxgenjs 在<p:sldIdLst>之後立即寫入<p:notesMasterIdLst>,並將兩個母版指向同一個主題部分。PowerPoint 可以愉快地讀取這個 — 移動該元素後,同一個簡報就無法開啟了。 - 圖示: 將
react-icons渲染為 SVG(使用ReactDOMServer.renderToStaticMarkup),用sharp以 ≥256px 解析度進行柵格化,並透過addImage({ data: "image/png;base64," + buf.toString("base64") })插入 —image/png;base64,前綴是必需的(react-icons、react、react-dom和sharp已預先安裝 — 僅在 require 失敗時才執行npm install react-icons react react-dom sharp)。
編輯現有簡報和範本
首先選擇版面:python scripts/thumbnail.py template.pptx template-thumbs 會寫出每個投影片的標籤式網格,並列印其所建立的檔案 — template-thumbs.jpg,如果超過 12 張投影片則會分割成 template-thumbs-N.jpg。始終傳遞第二個引數,並以其簡報命名。 它預設為 thumbnails,因此如果兩個簡報在一個目錄中縮圖,它們會靜默地互相覆蓋對方的網格 — 第一個簡報的網格就這麼消失了(僅供範本分析 — 視覺 QA 需要使用轉換為圖片中的全解析度渲染;它只接受 .pptx,所以先將 .potx 複製為 .pptx 名稱)。將其與 markitdown 一起使用,將每個內容區塊映射到一個範本投影片上,並變化版面 — 不要將每個區塊都放在同一個標題和項目符號投影片上。
python3 -c "import sys,zipfile; zipfile.ZipFile(sys.argv[1]).extractall('unpacked')" deck.pptx
python scripts/add_slide.py unpacked/ slide2.xml --after slide2.xml # 複製一個投影片(或 slideLayoutN.xml);列印新投影片的路徑
# 重新排序 / 刪除投影片 = 編輯 ppt/presentation.xml 中的 <p:sldIdLst>
python scripts/clean.py unpacked/ # 刪除後:移除孤立投影片、媒體、關係檔案
# 在 ppt/slides/slideN.xml 中編輯投影片內容
(cd unpacked && rm -f ../out.pptx && zip -Xr ../out.pptx .) # 在目錄內部進行壓縮;先 rm,否則已刪除的部分會殘留
python scripts/office/validate.py out.pptx --original deck.pptx
- 在編輯任何投影片內容之前,先完成所有結構性工作 — 新增、刪除、重新排序。
add_slide.py會逐字複製投影片檔案,因此如果你在編輯後複製,就會克隆已編輯的內容;而clean.py會刪除<p:sldIdLst>中缺失的任何投影片,包括你剛寫入的那個。 - 永遠不要手動複製投影片檔案 —
add_slide.py會執行新投影片所需的所有註冊,並報告它建立的內容(Created ppt/slides/slide17.xml from slide2.xml)。它也可以直接對檔案運作:add_slide.py deck.pptx slide2.xml -o out.pptx— 請傳遞-o,否則它會原地改寫輸入的簡報。 重複的投影片仍然參照其來源的圖表/SmartArt/內嵌物件部分,而不是克隆它們,因此編輯一個投影片的圖表會改變另一個投影片的。 - 如果你使用
python-pptx,它有三件做不到的事:複製投影片(它唯一的進入點是add_slide(layout))、透過text_frame.text = "..."保留格式(這會將段落摺疊成單一無樣式的執行 — 請改用run.text進行指派),或讀取大多數範本插圖使用的 SVG/EMF(add_picture會拋出UnidentifiedImageError)。 - 舊版
.ppt必須先轉換:python scripts/office/soffice.py --headless --convert-to pptx file.ppt。.potx範本的解壓縮和壓縮方式完全相同 — 在輸出上保留.potx副檔名。 - 若要重複使用範本圖示或圖片,請複製一個已包含它的投影片或版面。
在填入範本時:
- 如果你編寫 XML 轉換,請使用
defusedxml.minidom進行解析 — 透過xml.etree.ElementTree來回處理 OOXML 會改寫命名空間前綴並損壞簡報。 - 範本插槽 ≠ 來源項目。 如果範本顯示 4 個團隊成員,而你只有 3 個,請刪除第 4 個成員的整個群組(圖片 + 文字方塊),而不僅僅是文字 — 然後在 QA 中檢查是否有孤立的視覺元素。
- 每個列表項目使用一個
<a:p>— 永遠不要將項目串聯到單一段落中。複製兄弟元素<a:pPr>以保留間距,並在標題、章節標題和內聯標籤(Status:、Owner:)的<a:rPr>上設定b="1"。 - 讓項目符號從版面繼承;僅在需要覆蓋時新增
<a:buChar>、<a:buAutoNum>(編號)或<a:buNone>— 永遠不要在文字中使用字面意義的•。 - 帶有前導或尾隨空格的文字需要在其
<a:t>上設定xml:space="preserve"。
設計想法
不要製作無聊的投影片。 白色背景上的純項目符號不會給任何人留下深刻印象。請考慮從此列表中為每個投影片尋找靈感。
開始之前
- 選擇一個大膽且與內容相關的顏色調色盤:調色盤應該讓人感覺是為這個主題特別設計的。如果將你的顏色換到一個完全不同的簡報中仍然「適用」,那表示你沒有做出足夠具體的選擇。
- 支配地位高於平等:一種顏色應佔主導地位(60-70% 的視覺重量),搭配 1-2 種輔助色調和一種銳利的強調色。永遠不要給所有顏色相同的權重。
- 深色/淺色對比:標題和結論投影片使用深色背景,內容投影片使用淺色(「三明治」結構)。或者全部使用深色以獲得高級感。
- 致力於一個視覺主題:選擇一個獨特的元素並重複使用它 — 圓角圖片框架、彩色圓圈中的圖示。在每個投影片中貫徹使用。不要使用色條或強調條作為你的主題(請參閱避免清單)。
顏色調色盤
選擇與你的主題相匹配的顏色 — 不要預設使用通用的藍色。將這些調色盤作為靈感:
| 主題 | 主要 | 次要 | 強調 |
|---|---|---|---|
| 午夜執行 | 1E2761 (海軍藍) | CADCFC (冰藍) | FFFFFF (白色) |
| 森林與苔蘚 | 2C5F2D (森林) | 97BC62 (苔蘚) | F5F5F5 (奶油色) |
| 珊瑚能量 | F96167 (珊瑚) | F9E795 (金色) | 2F3C7E (海軍藍) |
| 溫暖陶土 | B85042 (陶土) | E7E8D1 (沙色) | A7BEAE (鼠尾草) |
| 海洋漸層 | 065A82 (深藍) | 1C7293 (藍綠) | 21295C (午夜) |
| 炭灰極簡 | 36454F (炭灰) | F2F2F2 (米白) | 212121 (黑色) |
| 藍綠信任 | 028090 (藍綠) | 00A896 (海沫) | 02C39A (薄荷) |
| 莓果與奶油 | 6D2E46 (莓果) | A26769 (塵土玫瑰) | ECE2D0 (奶油色) |
| 鼠尾草平靜 | 84B59F (鼠尾草) | 69A297 (尤加利) | 50808E (石板) |
| 櫻桃大膽 | 990011 (櫻桃) | FCF6F5 (米白) | 2F3C7E (海軍藍) |
針對每個投影片
每個投影片都需要一個視覺元素 — 圖片、圖表、圖示或形狀。純文字投影片是容易被遺忘的。
版面選項:
- 兩欄式(文字在左,插圖在右)
- 圖示 + 文字行(彩色圓圈中的圖示、粗體標題、下方描述)
- 2x2 或 2x3 網格(一邊是圖片,另一邊是內容區塊網格)
- 半出血圖片(整個左側或右側)搭配內容疊加
資料呈現:
- 大型統計數字強調(大數字 60-72pt,下方搭配小標籤)
- 比較欄(之前/之後、優點/缺點、並排選項)
- 時間軸或流程圖(編號步驟、箭頭)
視覺修飾:
- 在章節標題旁邊的小彩色圓圈中放置圖示
- 斜體強調文字,用於關鍵統計數字或標語
排版
你寫入 .pptx 的字體名稱是由使用者的 PowerPoint 渲染,而不是由這個環境渲染。 你的視覺 QA 是透過 LibreOffice 渲染的,它會替換它沒有的字體 — 而且對於某些字體,替代字體具有不同的寬度,因此你的 QA 預覽可能顯示文字溢出(或剛好適合),而實際的簡報不會有這個問題。為了讓你的 QA 值得信賴:
- 安全字體(在 QA 中渲染寬度與實際一致,並且隨 Office 一起提供):Arial、Calibri、Cambria、Times New Roman、Courier New、Bookman Old Style、Century Schoolbook。將這些用於正文文字和任何對大小吻合很重要的內容。
- 零 QA 風險的有個性標題:將安全清單中的襯線標題字體(Cambria、Bookman Old Style、Century Schoolbook)與安全清單中的無襯線正文字體(Calibri 或 Arial)配對。這樣可以在不犧牲可靠的溢出檢查的情況下獲得視覺對比。
- 如果使用者要求使用安全清單以外的字體(例如 Georgia 或 Trebuchet MS):在使用者要求的地方使用它,但要為這些容器預留額外空間(約 10%),並且不要相信這些元素的 QA 文字吻合度 — 該字體的預覽是近似的。如果使用者沒有指定,正文文字建議使用安全清單中的字體。
- QA 不可靠的字體(替代字體具有不同的寬度 — 溢出檢查可能錯誤):Georgia、Trebuchet MS、Impact、Arial Black、Garamond、Consolas、Palatino Linotype。Calibri Light 的替代字體因環境而異;將其視為 QA 不可靠。適用於有空間的標題/強調文字;不要相信這些字體的 QA 文字吻合度。
- 永遠不要預設使用 Aptos — Office 2023 年後的預設字體在這裡沒有計量相容的替代字體,而且舊版 Office 安裝中沒有它,因此在兩端都不可靠。
| 元素 | 大小 |
|---|---|
| 投影片標題 | 36-44pt 粗體 |
| 章節標題 | 20-24pt 粗體 |
| 正文文字 | 14-16pt |
| 標題 | 10-12pt 柔和 |