模組五|發布與衍生物(Day 23–27)
昨天講封面套版,收在「排版要交給程式」。今天講程式排版出錯的那一次。
它很小。小到我原本沒打算寫。而它的 commit 序列太乾淨了,乾淨到可以當教材。
14:06 調整視覺樣式
14:08 重新設計卡片
14:11 更換圖片
14:14 修正文字對齊
14:14 修正文字對齊
14:18 以 textbbox 動態置中並重新產生
14:18 以 textbbox 動態置中並重新產生
問題是:導流卡上一行英文標籤沒有置中。
前四筆在猜座標。第五、六筆換了做法。

猜座標的寫法大概是這樣:
# 硬寫:假設這行字大約 200 像素寬
draw.text((W // 2 - 100, y), label, font=font)
那個 100 是估的。而它會在四種情況下失效:
最後一個最麻煩:中文字寬度跟 len(text) 沒有可靠關係。一個全形字約等於兩個半形字,但標點、數字、可變字重的拉丁字母全部不一樣。
所以「數字元個數再乘一個係數」這條路,在中文排版上從一開始就是錯的。
而我試了四次。

bbox = draw.textbbox((0, 0), label, font=font)
text_w = bbox[2] - bbox[0]
draw.text(((W - text_w) / 2, y), label, font=font)
textbbox 是量出來的。 它把這個字串、用這個字型、在這個字級下實際會佔多寬算給你。
換字串、換字型、換字級,全部自動正確。
從「假設它多寬」變成「問它多寬」。這是一行的差別,而它讓這個 bug 從「每次改文案都要重調」變成「不會再發生」。
三天前講多軌時鐘漂移,最後的解法是:放棄求一條全域曲線,改成在每個剪點各量一次。
今天的解法是:放棄估算文字寬度,改成在每次繪製時量一次。
同一個心法,不同尺度:量測比計算可靠。
而兩次的失敗模式也一樣:我都先試著找一個「規律」(一個常數平移、一個字寬係數),失敗了幾次,才回到「直接量」。
為什麼會有這個傾向?我想是因為計算看起來比較聰明。找到一個公式感覺像是理解了問題;而每次都去量一次感覺像是放棄了理解。
但在這兩個案例裡,「每次量一次」才是正確的理解:它承認了那個量本來就是隨情境變的。
我 grep 了全 repo 的排版、對齊、字型相關 commit:總共只有 11 筆,而其中 4 筆集中在這 12 分鐘。
另外兩筆字型相關的 commit 是不同時期的,而成因一模一樣:產圖腳本找不到字型檔,或算不準文字寬度。
也就是說:這一族問題總共佔了全 repo 排版類 commit 的一半以上,而它們全部來自同一個根因。
用 textbbox 之後,這一族問題就沒有再出現過。
既然講到產出,把影片那邊的參數也攤開,它比封面亂:
| 腳本 | fps | audio bitrate |
|---|---|---|
| 直式主渲染器 | 30 | 192k |
| 橫式輸出 | 1 | 320k |
| 直式(另一支) | 1 | 192k |
| 又另一支 | 2 | 192k |
四種 framerate、兩種 audio bitrate。
fps 的差異其實有道理:一張靜態圖配音訊,用 1 fps 可以把檔案壓得很小。而 30 fps 那支是因為有動態元素。
但 1 / 2 / 30 三個值並存,代表沒有人決定過「靜態影片該用幾 fps」,只是每次隨手寫。
-crf 更誇張:全 repo 只設過一次(值是 20),其餘全部走 x264 預設。
這些不會出事,但它們是 Day 23 那個「沒有 design token」在影片端的版本:每一個參數都是某一次隨手決定的,然後被複製下去。
看那六筆 commit 的時候,我發現一件事:
14:14 那兩筆的 diffstat 完全相同(3 個檔案、17 行新增、6 行刪除)。14:18 那兩筆也一樣。
不是我改了兩次同樣的東西,是同一份變更被兩套 commit 訊息各記了一次,來自平行分支後的合併。
這件事有統計上的後果:
git rev-list --count HEAD → 1,180
git rev-list --count --first-parent HEAD → 995
merge commits → 32
約 185 筆是從側枝併進來的雙記。
所以 Day 1 我說「兩個 repo 加起來 1,513 個 commit」,那個數字用的是 first-parent(995 + 285),是對的。但如果直接用 rev-list --count,會得到一個灌水 18% 的數字。
談工作量要用 first-parent。 這條我寫進了這個系列的數字口徑表,而且發布前檢查腳本會擋。如果哪一篇寫了未經修正的那個數字,它會噴錯。
這一篇的內容太小了。
一個置中的 bug,六筆 commit,12 分鐘。它撐不起一整天,如果不是因為它剛好示範了跟 Day 21 一樣的心法,我會把它併掉。
而我留著它,是因為小 bug 的 commit 序列比大事故乾淨:大事故的紀錄裡混雜太多東西,這個只有一條線。
第二個代價,比較實際:那四種 fps 跟兩種 bitrate 我沒有統一。 它們不會出事,所以永遠排在待辦的最後面。而它們正在讓「這個節目的影片」變成四種不同的東西。
量測比計算可靠。
任何「算出來的位置、大小、偏移量」,在輸入變化的時候都會錯。而「量出來的」不會。
具體的判斷方法:如果你在寫一個係數或魔術數字來估算某個量,先問:這個量能不能直接問出來?
textbbox
silencedetect
第二條,關於為什麼我們傾向計算:
找到公式感覺像理解了問題,每次都量感覺像放棄理解。 而在「那個量本來就隨情境變」的情況下,每次量一次才是正確的理解。
判斷標準:這個量有沒有一個穩定的規律? 有,用公式;沒有或不確定,量它。而「不確定」的時候選量,因為量的成本通常很低,猜錯的成本很高。
第三條,統計上的:
git rev-list --count 會把側枝的重複記錄算進去。 談工作量、談節奏、談「這個專案多活躍」的時候,用 --first-parent。我的差距是 18%,而 18% 足以讓一個論點站不住。
明天講一件比排版難堪得多的事:發布文案裡,有節目從來沒講過的話。