圖片壓縮到底在壓掉什麼

有失真壓縮不是把檔案擠小,是有選擇地丟掉人眼比較不敏感的資訊。這篇說明色度次取樣與量化各砍在哪裡、為什麼紅色文字特別容易壓爛、「品質 80」那個數字其實不是百分比也不能跨工具比較,以及為什麼想壓到指定大小只能靠實測而不能靠公式算,還有哪幾種圖再怎麼壓都不會變小。

大部分人對壓縮的想像是「把檔案擠小」,好像資料被塞進更小的盒子裡。有失真壓縮不是這樣運作的。它是有選擇地丟掉一部分資訊,而且丟掉就回不來了。搞懂它丟的是什麼,你才會知道什麼時候該壓、壓到什麼程度、以及為什麼有些圖怎麼弄都壓不下去。

壓縮丟掉的是什麼

先區分兩件常被混在一起的事。ZIP 是無失真壓縮:它找出重複的樣式用更短的方式記下來,解開之後跟原本一模一樣,一個位元都不差。JPEG 和 WebP 的有失真模式則是有失真:它們刻意扔掉資料,換取小很多的檔案。

這也解釋了一件常見的困惑:為什麼把照片或影片包成 ZIP 幾乎沒效果。那些格式已經是有失真壓縮過的結果,剩下的資料接近隨機,ZIP 找不到可以歸納的重複樣式。

有失真壓縮的核心賭注是:人眼有一些看不太出來的地方,那些地方的資料可以丟。接下來兩節就是它下刀的兩個位置。

第一刀:顏色

人的視覺對明暗的敏感度遠高於對顏色。同樣的細微變化,發生在亮度上你看得見,發生在色相上你多半看不出來。編碼器利用了這一點。

做法是先把畫面從 RGB 換成「亮度 + 兩個色差」的表示法,然後只把色差的解析度砍半,亮度完整保留。這叫色度次取樣,常寫成 4:2:0,意思是每四個像素共用一組顏色資訊。

這一步就直接省掉約一半的資料量,而大多數照片你看不出差別。

但它有代價,而且很好認:紅色文字放在深色背景上會糊掉、邊緣會出現色暈。因為那是純色差資訊,正好是被砍掉的那一半。所以螢幕截圖裡的彩色文字特別容易壓爛,而風景照壓起來很漂亮,差別就在這裡。

第二刀:細節

第二刀砍在細節上,而且是有選擇的。

編碼器把畫面切成小方塊(JPEG 是 8×8),然後對每塊做一次頻率轉換。轉換之後,這個方塊被拆成「整體是什麼色調」加上一堆「有多少細微起伏」的係數。低頻代表大範圍的明暗,高頻代表細碎的紋理。

接著是關鍵動作:量化。每個係數都除以一張表上的對應數字再取整。高頻項目除的數字大,取整之後很多直接變成零,那些細節就此消失。而一整排的零非常好壓。

這解釋了 JPEG 壓過頭時為什麼會出現一格一格的方塊,還有銳利邊緣旁邊那圈像水波的雜訊。方塊來自 8×8 的切割,水波來自高頻被砍掉之後,邊緣沒辦法被準確重建。

「品質 80」其實不是百分比

這是最多人誤會的一點。你在工具裡拉的那個品質滑桿,不是「保留 80% 的畫質」,也不是任何比例。它是一個縮放係數,用來把整張量化表乘大或乘小。數字低,量化表的值就變大,被歸零的係數就更多。

重點在於:每個編碼器的量化表都不一樣。libjpeg 的 80 和 mozjpeg 的 80 不是同一件事,跟 WebP 的 80 更是完全兩回事。所以「我都設 80,為什麼這個工具壓出來比較大」不是誰做錯了,是那個數字本來就不可跨工具比較。

為什麼固定品質解決不了問題

你真正面對的通常不是「我想要品質 80」,而是「這個檔案一定要小於 4 MB,不然傳不上去」。這兩件事之間沒有公式可以換算。

同一張 3000×2000、都設品質 70壓出來大小為什麼
藍天與海面約 250 KB大片平順漸層,高頻幾乎為零
人像特寫約 900 KB皮膚紋理與髮絲屬中高頻
樹葉、草叢約 2.4 MB每個像素都跟鄰居不同,全是高頻

差距接近十倍,而你事先無從得知。這就是為什麼「選一個品質然後祈禱」在有硬性上限的場合行不通。你只能壓完看結果,不合再調,然後重來。

既然沒有公式,就用量的。做法是二分搜尋:

  1. 先試最高品質。如果已經小於目標,直接收工,不需要犧牲任何畫質。
  2. 否則在最低與最高品質之間取中間值,壓一次,量大小。
  3. 沒超過目標,代表還有餘裕,把下限往上提;超過了,就把上限往下壓。
  4. 重複到區間夠窄為止。

每一輪都把可能的範圍砍一半,所以六到十輪就能收斂到相當接近的品質值。代價是要真的編碼六到十次。在伺服器上這是成本,在瀏覽器裡跑就只是使用者機器的幾百毫秒。

如果連最低品質都還是超標,那就不是品質的問題了,是像素太多。這時候才需要動解析度,而不是一開始就把圖縮小。先耗盡品質空間,再動尺寸,這個順序會讓最終結果好很多。

壓縮幫不上忙的時候

有幾種情況,再怎麼壓都不會有好結果,早點認出來可以省下很多時間:

  • 畫面本身就是雜訊。底片顆粒、高 ISO 噪點、電視雪花,每個像素都跟鄰居無關,沒有可以歸納的樣式,也沒有可以丟的冗餘。
  • 已經壓過的檔案。該丟的第一次就丟了,再壓一次只會製造新的瑕疵,換來的空間卻很有限。
  • 需要無失真的內容。有透明背景的去背素材、要再進後製的原始檔、印刷用圖,這些不該用有失真壓縮處理。
  • 檔案大小主要來自長度而非畫質。這是影片的情況:位元率已經到底還是塞不進去,代表這個長度沒辦法在能看的畫質下達標,該做的是剪短而不是繼續降畫質。

回到實際操作

把上面幾件事收攏成三個可以直接用的判斷:

  1. 有硬性上限就設目標大小,不要選品質。品質數字跟結果大小之間沒有可靠關係,設目標讓工具自己找才是對的方向。
  2. 螢幕截圖優先用 WebP。彩色文字和銳利邊緣正好踩在色度次取樣的痛點上,而 WebP 的區塊預測在這類畫面上優勢最大。
  3. 原檔已經夠小就別再壓。每一次重新編碼都是一次不可逆的損失,沒有理由為了省幾十 KB 付這個代價。

常見問題

壓縮到底做了什麼?

有失真壓縮不是把檔案「擠小」,是有選擇地丟掉一部分資訊,丟的是人眼比較不敏感的那些。所以壓縮過的圖不可能還原成原檔,被丟掉的資料是真的不見了,不像 ZIP 那種可以完整還原的無失真壓縮。

品質 80 是什麼意思?

不是「保留 80% 的畫質」,也不是任何百分比。它是一個對應到量化表的縮放係數,而每個編碼器的量化表都不一樣。這就是為什麼同一張圖用不同工具都設 80,壓出來的檔案大小和畫質可以差很多,那個數字在不同工具之間根本不可比。

為什麼不能直接算出「要壓到 4 MB 該用品質幾」?

因為品質和檔案大小的關係取決於圖片內容,沒有通式。同樣品質 70,一張藍天照片可能 200 KB,一張樹葉特寫可能 2 MB,因為後者的高頻細節多太多。唯一可靠的做法是實際壓一次、量結果、再調整。

為什麼有些圖怎麼壓都壓不小?

因為它本來就沒有冗餘可以丟。雜訊、底片顆粒、細密的樹葉或人群,這些畫面每個像素都跟鄰居不一樣,預測不了也歸納不了。另外,已經壓過的 JPEG 再壓一次效果也很有限,該丟的第一次就丟掉了。

WebP 為什麼比 JPEG 小?

JPEG 每個區塊各自獨立處理,WebP 借用了影片編碼的區塊預測:它會先看鄰近區塊猜這一塊長什麼樣,只記錄猜錯的部分。要存的資訊少了,檔案自然小。平面色塊和銳利邊緣的畫面差距最明顯,細節雜亂的照片差距最小。

想直接動手?壓縮工具就在首頁,檔案不會上傳。

開始壓縮