昨天用 pandoc 加上 Word COM 產出了 Word 與 PDF,但也留下一個不太舒服的限制:目錄頁碼跟 PDF 都得靠 Word,所以整條產線被綁在「裝有 Office 的 Windows」上。
今天換個方向想:如果不是每次都需要 Word,還能怎麼交付?
在 Day 03 我把「要有 Word 檔」列為硬需求。但這只是我的情況,每個人的需求都不太一樣,或許移除 Word 這個限制後,在後續的應用上會有更多彈性。
除了 Word 之外,常見的格式還有:
而且,如果不需要 Word,也有其他手段可以做出 PDF。
manual.md 開始昨天的 build 分成兩段,第一段把五章合併成一份 output/manual.md (legend 已經換成文字、截圖已經展開成圖與表格、保護區標記也拿掉了),第二段把這份 manual.md 轉成 Word (透過 Pandoc) 與 PDF。
基於這個邏輯,其實我們可以把第二段進行調整,改成轉換成我們需要的其他格式。當然,Pandoc 這個工具依然可以是一個考慮的選項,它支援很多種不同的格式,可以幫我們轉換成 HTML、PDF、PPT 等。
讓我們先從 HTML 與 PDF 開始討論。
範例專案的 build 多了一個 --to 參數:
npm run build -- --to html # output/manual.html
npm run build -- --to html --pdf # 再印成 output/manual-html.pdf,不需要 Office
其實用 pandoc 把 markdown 轉 HTML 的做法與轉 Word 差不多,只是變成由 CSS 來扮演 reference.docx 的腳色。
pandoc output/manual.md -o output/manual.html \
--standalone --embed-resources --css=templates/manual.css \
--toc --toc-depth=1 --resource-path=.
跟產 Word 的指令幾乎一樣,差別只有中間那一行:
--standalone:輸出完整的 HTML 頁面,封面(title / subtitle / date)與目錄都會產生。--embed-resources:把截圖轉成 base64 直接內嵌進 HTML。產出的是單一檔案,大約 1.8 MB,可以直接丟上網、寄出去,不用擔心圖片路徑。--css=templates/manual.css:樣式來源。templates/manual.css 的角色跟 reference.docx 完全一樣:內容來自 Markdown,它只管長相。昨天在 reference.docx 裡調的那些樣式,這裡都有對應的寫法:
| reference.docx | manual.css |
|---|---|
| Heading 1 段落前分頁 | h1 { break-before: page; } |
| Captioned Figure 置中、圖與圖說不拆開 | figure { text-align: center; break-inside: avoid; } |
| Table 加框線 | th, td { border: 1px solid var(--border); } |
| Block Text 左側色條 | blockquote { border-left: 4px solid var(--accent); } |
比較不一樣的是,同一份 CSS 要同時服務兩種用途:在瀏覽器裡直接看,以及印成 PDF。所以分頁相關的規則都放在 @media print 裡:
@media print {
/* 封面、目錄、每一章都從新的一頁開始 */
#title-block-header { padding-top: 30vh; break-after: page; }
nav#TOC { break-after: page; }
h1 { break-before: page; margin-top: 0; }
}
不會 CSS 也沒關係,反正可以直接請 AI Agent 修改。(我就是這樣做的XD)
在瀏覽器裡看的時候,整本手冊就是一頁可以一路往下捲的網頁,目錄是可以點的連結,手機上也能正常閱讀。
我把 HTML 網頁放上 Github Pages 了,大家可以點進去看一下成果~
pandoc 其實可以直接 -o manual.pdf,但它預設是先轉成 LaTeX,再交給 LaTeX 排版。這條路有兩個麻煩:
xelatex 並指定中文字型。因此,通常 markdown 轉 PDF 都是先轉成其他格式再印。昨天是 markdown -> docx -> PDF,今天改成 markdown -> HTML -> PDF。HTML 就沿用前面那一段的成果就好了。
轉 PDF 的工具很多,但這條產線本來就裝了 Playwright,它的 page.pdf() 用的就是 Chromium 的列印功能,不需要再多裝任何東西:
const browser = await chromium.launch()
const page = await browser.newPage()
await page.goto(pathToFileURL(outFile).href)
await page.pdf({
path: pdfFile,
format: 'A4',
margin: { top: '2.5cm', bottom: '2.5cm', left: '2.5cm', right: '2.5cm' },
printBackground: true,
outline: true, // 標題轉成 PDF 書籤
tagged: true, // outline 需要它
displayHeaderFooter: true,
headerTemplate: '<span></span>',
footerTemplate: '<div style="width:100%;text-align:center;font-size:9pt"><span class="pageNumber"></span></div>',
})
幾個參數說明一下:
printBackground:沒有它,blockquote 的淺灰底色會被拿掉。outline:把 h1、h2 轉成 PDF 書籤,跟昨天 Word 轉出的 PDF 一樣可以從側邊欄跳章節。比較不一樣的是,封面標題與「目錄」也會變成書籤。tagged:產生帶有文件結構的 PDF (tagged PDF)。outline 的書籤是從這份結構產生的,少了它,outline: true 也不會有任何書籤,而且不會有任何錯誤訊息。footerTemplate:頁碼。pageNumber 是 Chromium 認得的特殊 class,列印時會被換成當頁的頁碼。這些參數不會寫也沒關係,可以請 AI Agent 協助XD
實際執行的輸出:
$ npm run build -- --to html --pdf
合併 5 章 -> output/manual.md
pandoc -> output/manual.html
Chromium -> output/manual-html.pdf
跟昨天一樣,產出的範例檔案我有放在 範例專案的 Release,大家有興趣的話可以下載來看看。
現在同一份 manual.md 有兩條路可以印出 PDF:
Word 轉出 (manual.pdf) |
Chromium 印出 (manual-html.pdf) |
|
|---|---|---|
| 執行環境 | Windows + Word | 任何能跑 Playwright 的地方 |
| 樣式來源 | reference.docx |
manual.css |
| 目錄頁碼 | 有 | 沒有,只有章節名稱 |
| 封面頁碼 | 不印 | 會印 |
| 頁數 | 13 頁 | 12 頁 |
差異主要在頁碼這部分:
目錄沒有頁碼
瀏覽器在排版之前,不知道每一章會落在第幾頁。CSS 規格裡其實有 target-counter() 可以做到,但 Chromium 沒有實作,要改用 Paged.js 或 WeasyPrint 這類專門處理列印排版的工具。
封面會印頁碼
footerTemplate 會套用到每一頁,沒辦法單獨跳過第一頁。我沒找到簡單又可靠的做法,所以就先接受了。
頁數不同則是因為兩個排版引擎斷頁的位置不一樣,內容本身是相同的。
這幾點對「只要看、要歸檔」的讀者來說影響不大,畢竟有書籤可以跳章節。但如果客戶很在意目錄頁碼,那還是走回 Word 那條路。
除了 HTML 與 PDF,Google Docs 與 PPT 理論上也都走得通。
如果讀者需要多人線上共編、直接在文件上留言,Google Docs 會比傳來傳去的 Word 檔方便很多。
要轉成 Google Docs 最簡單的做法,就是把昨天產出的 manual.docx 上傳到 Google 雲端硬碟,用 Google 文件開啟就好。想要自動化的話,再用 Google Drive API 上傳,並指定轉換成 Google 文件格式 (application/vnd.google-apps.document)。
PPT 就比較麻煩了。手冊是「一步一步照著做」的長文件,簡報則是「一頁講一個重點」,兩者的排版邏輯差異很大。
pandoc 可以直接把 Markdown 轉成 .pptx:
pandoc output/manual.md -o output/manual.pptx --resource-path=.
但以目前手冊的寫法,轉出來的效果很差:截圖跟 legend 表格會被拆到不同張投影片,長一點的段落也會直接超出投影片的下緣。
真的有簡報需求,通常要另外寫一份摘要版的內容 (i.e. 另外準備一個新的 markdown,而不是繼續用 manual.md),而不是把手冊正文直接塞進投影片。
今天以昨天的 manual.md 為起點,把交付格式從 Word 再多延伸出去一點點。到這裡,手冊已經可以產出、也可以交付了。
接下來,就是其他補充議題了,看看還有什麼可以加強的地方,來讓我們這條「AI 自動化使用手冊產線」更完善、更方便使用。