GIF 製作:一格最多 256 色,影片轉 GIF 先抓調色盤,再調 fps 與寬度壓檔案

GIF 製作最容易踩的坑,是把 1280×720 的影片直接轉成 GIF:GIF 每一格最多只能用 256 種顏色,畫面又沒有 MP4 那種完整的影格間壓縮,結果檔案又大、漸層又髒。比較穩的做法是用 ffmpeg 先替整段影片算出一張調色盤,再縮小寬度、降低 fps、只截需要的幾秒,這樣畫質和檔案大小才抓得住。
哈囉!又到了快樂的教學時光。這篇從 GIF 格式本身的限制講起,接著給你可以直接複製的 ffmpeg 指令,最後講透明背景 GIF 與「到底該不該用 GIF」。指令與參數說明都對照 FFmpeg 官方文件,格式限制對照 GIF89a 規格。
GIF 到底限制了什麼:256 色、整數百分秒、一格一個調色盤
先搞懂格式,後面調參數才不會亂槍打鳥。根據 W3C 保存的 GIF89a 規格與 MDN 的說明,GIF 有幾個直接影響成品的特性:
- 每個像素只存一個 8 位元索引:MDN 寫到,GIF 用 LZW 無損壓縮 8 位元索引色,每個像素是指向調色盤的索引,調色盤裡的顏色是 24 位元 RGB。所以一張圖最多只有 256 種顏色,要模擬更多顏色得靠抖動(dithering)。
- 調色盤可以是全域,也可以每格自己一份:規格說明 Global Color Table 管整個資料流,Local Color Table 只管緊接著的那一張圖,而且 Local 會取代 Global。能不能善用這點,取決於你用的工具。
- 每格停留時間的單位是百分之一秒:規格的 Delay Time 欄位以 1/100 秒為單位。FFmpeg 的 GIF muxer 文件也提醒,格與格之間的延遲不能小於一厘秒。
- 透明只有「有」或「沒有」:規格的 Graphic Control Extension 只有一個透明色索引與一個旗標,沒有半透明這回事。
美國國會圖書館的格式說明也把 GIF 歸類為 LZW 壓縮、調色盤式色彩(256 色或更少)的點陣圖格式,並說它可以在單一檔案裡放多張圖與控制資料做成短動畫。換句話說,GIF 生來就是給「小尺寸、色塊明確、很短」的動畫用的。

先算檔案會多大:長度、fps、寬度三個數字
多數人轉 GIF 會卡在「檔案怎麼這麼大」。原因很單純:GIF 的檔案大小大致跟「格數 × 每格像素數」成正比,所以最有效的是砍這三個數字,而不是一直換軟體。
縮小寬度:像素數是平方在掉
| 寬度(16:9) | 每格像素數 | 相對 1280 寬 |
|---|---|---|
| 1280×720 | 921,600 | 100% |
| 960×540 | 518,400 | 約 56% |
| 640×360 | 230,400 | 25% |
| 480×270 | 129,600 | 約 14% |
| 320×180 | 57,600 | 約 6% |
如果以「每個像素 1 位元組索引」粗估壓縮前的資料量,3 秒、30 fps、1280×720 是 90 格 × 921,600 ≈ 83 MB;同樣 3 秒改成 15 fps、480 寬,只剩 45 格 × 129,600 ≈ 5.8 MB。這是壓縮前的理論值,實際檔案會因為 LZW 與畫面內容差很多,但砍的方向不會錯。
降低 fps:格數直接減半
格數就是 fps 乘以秒數:3 秒 10 fps 是 30 格、15 fps 是 45 格、24 fps 是 72 格、30 fps 是 90 格。大部分的表情包、操作示範,10~15 fps 已經夠看;快速的運動才值得拉到 20 fps 以上。
還有一個冷知識:因為延遲單位是百分之一秒,fps 要能整除 100 才會剛好。
| fps | 每格延遲(百分之一秒) | 能不能精準表示 |
|---|---|---|
| 10 | 10 | 可以 |
| 20 | 5 | 可以 |
| 25 | 4 | 可以 |
| 50 | 2 | 可以 |
| 15 | 6.67 | 不行,只能 6 與 7 交錯 |
| 30 | 3.33 | 不行,只能 3 與 4 交錯 |
這不是壞掉,是格式本身的取捨。想檢查輸出檔,可以用 ffprobe -v error -show_entries packet=duration_time -of csv=p=0 output.gif 看每一格的實際停留時間;如果你想要每格節奏完全一致,就挑 10、20、25 這類能整除的 fps。

ffmpeg 影片轉 GIF:先算調色盤,再上色
FFmpeg 官方文件把這件事拆成兩個濾鏡:palettegen 針對整段影片產生一張調色盤,paletteuse 再用這張調色盤把影片降成 256 色。少了這一步,輸出的 GIF 就沒有針對你這段影片挑過的調色盤,常見色帶與雜點。
一行指令版
ffmpeg -ss 1 -t 3 -i input.mp4 \
-vf "fps=15,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \
-loop 0 output.gif
逐段拆開:
-ss 1 -t 3:從第 1 秒開始,只取 3 秒。GIF 越短越好,先剪好再轉。fps=15:輸出 15 fps(官方 fps 濾鏡會用複製或丟棄影格的方式轉成固定幀率)。scale=480:-1:flags=lanczos:寬度 480、高度依比例自動算,縮小時用 lanczos 縮放演算法。split[s0][s1]:把處理過的影像分成兩份,一份拿去算調色盤,一份拿去上色。palettegen與paletteuse:先產生調色盤,再套用。-loop 0:無限循環。官方 GIF muxer 的預設就是 0,-1是不循環。
兩步驟版:調色盤存成圖片
ffmpeg -ss 1 -t 3 -i input.mp4 -vf "fps=15,scale=480:-1:flags=lanczos,palettegen" palette.png
ffmpeg -ss 1 -t 3 -i input.mp4 -i palette.png -lavfi "fps=15,scale=480:-1:flags=lanczos[x];[x][1:v]paletteuse" -loop 0 output.gif
兩步驟的好處是你可以打開 palette.png 看一眼:官方文件說調色盤是一張 256 像素的圖,顏色太雜、關鍵色(例如品牌色)沒進去,就可以回頭調整。
三個最常調的選項
- palettegen 的 stats_mode:預設
full統計整個畫面;改成diff只看與前一格不同的部分,文件說當背景固定、動的只有一小塊時,可以讓移動的主體分到更多顏色。 - paletteuse 的 dither:預設是
sierra2_4a。想要乾淨、檔案又小的話可以改dither=bayer:bayer_scale=5;官方說明 bayer_scale 值小時圖樣明顯但色帶少,值大時圖樣不明顯但色帶多,範圍是 0 到 5。要完全不抖動就是dither=none。 - paletteuse 的 diff_mode:設成
rectangle時,只重新處理有變動的矩形範圍,文件說這類似 GIF 的裁切與位移壓縮機制,背景靜止的畫面通常讓 GIF 更好壓、雜訊更少。
合在一起的範例:
ffmpeg -ss 1 -t 3 -i input.mp4 \
-vf "fps=12,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen=stats_mode=diff[p];[s1][p]paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle" \
-loop 0 -final_delay 100 output.gif
最後那個 -final_delay 100 是官方 GIF muxer 的選項,單位是百分之一秒,所以 100 代表最後一格多停 1 秒再循環,適合做「看完停一下」的示範動畫。
如果你是在 After Effects 裡輸出,站內舊文《AE輸出攻略》有整理透明背景、GIF 與 HTML 的輸出路徑,可以對照看;想先把素材壓小再轉,也可以參考我們寫過的影片壓縮與影片轉檔兩篇;更多同類內容放在影片後製分類。
透明背景 GIF:只有全透明或全不透明
需要去背的貼圖或動態 Logo,常會想做成透明 GIF。前面講過,GIF 的透明是用一個「透明色索引」完成,一個像素要嘛透明、要嘛不透明,沒有半透明。所以陰影、羽化邊緣、半透明玻璃,轉成 GIF 之後都會被硬切成一圈鋸齒邊。
用 ffmpeg 轉帶透明通道的素材時,官方文件有兩個相關選項:
palettegen的reserve_transparent:預設開啟,只用 255 色,把最後一色保留給透明,文件說這對 GIF 最佳化有幫助。paletteuse的alpha_threshold:範圍 0~255,預設 128;高於門檻視為完全不透明,低於則視為完全透明。
ffmpeg -i input_alpha.mov \
-vf "split[s0][s1];[s0]palettegen=reserve_transparent=1[p];[s1][p]paletteuse=alpha_threshold=128" \
-loop 0 output.gif
想讓邊緣沒有白邊,素材本身最好在輸出時就把背景設成跟最後使用場景接近的顏色,或乾脆放棄透明、直接把 GIF 做成跟背景同色的版本。需要完整半透明時,改用支援 alpha 的影片或圖片格式,不要硬用 GIF。
六指淵的建議:網頁上能用影片就別用 GIF
我們的立場很簡單:GIF 適合丟進 LINE 群組、論壇、留言區這些「只認圖片」的地方;如果是放在自己的網頁上,我們建議改用 <video>。理由來自 Google 的 web.dev 文件:他們的範例裡,同一段動畫的 GIF 是 3.7 MB,轉成 MP4 是 551 KB,WebM 只有 341 KB。
web.dev 也列出 GIF 的三個特徵,以及用 video 元素重現的寫法:
<video autoplay loop muted playsinline>
<source src="my-animation.webm" type="video/webm">
<source src="my-animation.mp4" type="video/mp4">
</video>
文件還提醒,瀏覽器會照 source 的順序挑第一個能播的,所以想優先用 WebM 就要放前面。順手提醒一個容易卡關的地方:照 web.dev 的 ffmpeg 指令把 GIF 轉成 VP9 的 WebM 時,如果你的 ffmpeg 版本回報 Pixel format 'gbrap' is not widely supported,補上 -pix_fmt yuv420p 就能順利輸出。完整指令如下:
ffmpeg -i my-animation.gif -c:v libvpx-vp9 -b:v 0 -crf 41 -pix_fmt yuv420p my-animation.webm
ffmpeg -i my-animation.gif -b:v 0 -crf 25 -f mp4 -vcodec libx264 -pix_fmt yuv420p my-animation.mp4
什麼情況不建議用 GIF?照片感很重、漸層很多的畫面(256 色撐不住)、超過 5 到 6 秒的長片段、要半透明的效果。這幾種硬做 GIF,只會得到又大又髒的檔案,改用 MP4、WebM 反而省事。
常見問題排除
畫面有色帶或一堆雜點
先確認有沒有走 palettegen/paletteuse。已經有走的話,試著把 stats_mode=diff、dither=bayer:bayer_scale=5 分別加上去比較;有大片漸層的畫面,本來就是 GIF 的弱項。
檔案還是太大
照影響大小排序:先縮寬度,再縮秒數,最後才降 fps。例如 480 寬降到 320 寬,每格像素數只剩 44%(57,600 ÷ 129,600)。
播放速度不對
確認 fps 能不能整除 100,不能整除的 fps 會在相鄰兩個延遲值之間交錯。也別把 fps 拉太高:FFmpeg 讀取 GIF 的 min_delay 預設是 2 個百分之一秒,更短的延遲不算有效值。
不會循環,或循環前沒有停頓
-loop 0 是無限循環,-loop -1 是不循環,官方範例的 -loop 10 則是循環 10 次;需要停頓就用 -final_delay。
透明邊緣有白邊
這是前面講的 1 位元透明的副作用,半透明像素被切成透明或不透明。調整 alpha_threshold 可以改變邊緣吃進多少,但根本解法還是讓素材邊緣更俐落。
如果你在公司要處理大量影音素材,想把影音與設計流程接上自動化,也可以約 30 分鐘免費諮詢,先聊聊該從哪一段開始。
參考資料
- W3C:Graphics Interchange Format (GIF89a) 規格
- FFmpeg Filters Documentation(fps、scale、palettegen、paletteuse)
- FFmpeg Formats Documentation(GIF muxer 與 demuxer)
- web.dev:Replace animated GIFs with video for faster page loads
- MDN:Image file type and format guide(GIF)
- Library of Congress:GIF, Version 89a 格式說明
企業 AI 導入諮詢
公司想導入 AI 卻不知道從哪開始?約 30 分鐘免費諮詢
留下聯絡方式,顧問會先了解你們的團隊與流程,再一起找出最值得先用 AI 改善的環節。方便的話,在下方寫上公司名稱與產業。
六指淵特效教學網編輯團隊,2015 年起以友善的中文教學分享 After Effects、Premiere、Photoshop、特效合成與 MG 動態設計,讓特效沒有距離。









