UrsaKit 封面圖:PNG 體積與 JPEG、WebP 的實測對比

png 檔案太大,通常既不是損壞,也不是設定錯誤。png 壓縮之所以常常看起來沒有效果,是因為 PNG 是無失真格式,而只要內容不再平塗,無失真的代價就會立刻顯現。

判斷自己的檔案屬於哪一種情況,方法是看它實際裝了什麼。照片、截圖、標誌各自撞到不同的上限,也各自有不同的解法。

01PNG 為每個像素存了什麼

PNG 為每個像素保存 24 位元色彩加上 8 位元透明通道,接著先套用把平緩列變成大量連續零值的濾鏡,再用 DEFLATE 壓縮(W3C PNG 規格)。這個過程之前不會丟掉任何東西,所以編碼器完全只能倚賴重複性。

這樣的設計在平塗圖形上很划算。我們倉庫裡那個 1161x389、帶透明背景的標誌只要 98,032 位元組,因為大面積同色區域會塌縮到幾乎不存在。而照片雜訊沒有任何對應的技巧可用。

最常被誤解的是濾鏡這一段。PNG 並不是「未壓縮」,它用的是一個完全不知道什麼叫圖片的通用壓縮算法。它沒辦法把漸變抹平,也沒辦法丟掉看不出來的細節,只能發現同樣的位元組又出現了一次。

02同一張照片,四種編碼的實測

我們拿一張 1408x768 的照片(public/design/image-compressor-sample.jpg,磁碟上 272,551 位元組),在 Python 3.9.6 / macOS 26.5.1 上用 Pillow 11.3.0 重新編碼。下面每個數字都可以用這段程式碼複現,2026-10-09 重跑過:

from PIL import Image
import io

im = Image.open("public/design/image-compressor-sample.jpg").convert("RGB")

def size(fmt, **kw):
    buf = io.BytesIO()
    im.save(buf, fmt, **kw)
    return buf.tell()

size("PNG", optimize=True)               # 1,733,498
size("JPEG", quality=80, optimize=True)  # 236,333
size("WEBP", quality=80, method=4)       # 186,492
size("AVIF", quality=50)                 # 117,794

同一次執行的結果寫出來就是:

input  image-compressor-sample.jpg   1408x768   272,551 B

PNG   lossless, optimize           1,733,498 B   是輸入檔的 6.4 倍
JPEG  quality 80, optimize           236,333 B   基準
WebP  quality 80, method 4           186,492 B   比 JPEG 少 21%
AVIF  quality 50                     117,794 B   比 JPEG 少 50%

PNG 比 JPEG 大了 7.3 倍,比 WebP 大了 9.3 倍。除了容器之外,圖片本身什麼都沒變——這就是完整的診斷。

PNG 很大,是檔案在告訴你內容是什麼。

無失真儲存對圖形是正確選擇,對照片則是錯誤選擇。換掉編碼器就能解決症狀,而且不會動到用戶看得見的畫質。

03原因一:PNG 在設計上就是無失真

你看過的每一張 JPEG、WebP 或 AVIF 都已經丟掉過資訊。重新存成 PNG 只是把那份損傷原樣保留,它沒辦法找回細節,只能保證之後不再遺失。

這個保證正是標誌需要的:往後幾年要不斷縮放、改色、重新輸出。對照片而言它卻是負擔,因為被丟掉的那些細節,恰好就是讓檔案變小的原因。

把 JPG 轉成 PNG 不會提升畫質。

我們把測試 JPG 重新編碼成 PNG 後逐像素比對:沒有任何一個畫素改變。檔案從 272,551 位元組長到 1,733,498,視覺上完全沒有差別。

04原因二:每個通道都佔 8 位元

PNG 給紅、綠、藍三個通道各 8 位元,如果還有透明就再多 8 位元。因此一張 1408x768 的圖在開始壓縮之前,就已經預留了超過 320 萬位元組。

這筆固定成本解釋了為什麼小圖仍然很小:一張 512x512 的純白方塊大約只要 1,878 位元組,因為輸入幾乎全部都是重複;同一塊 512x512 的照片區域則接近不可壓縮的雜訊。

色盤模式是逃生出口。把圖片縮到 256 色之後,我們的照片從 1,733,498 位元組降到 633,866,只有原來的 37%,但每個像素的顏色都被改寫,天空與膚色出現肉眼可見的斷階。

05原因三:DEFLATE 只壓縮重複

DEFLATE(RFC 1951)就是 ZIP 檔案裡用的同一個算法。它找出重複的位元組序列並用參照取代,所以對平塗色塊、均勻背景與重複的介面元件特別有效。

照片裡幾乎沒有完全相同的重複。感光雜訊讓每個像素都和鄰居略有不同,濾鏡處理完之後位元組流近乎隨機,DEFLATE 幾乎無從下手。這就是 PNG 照片膨脹最大的單一原因。

Retina 截圖則以另一種方式撞上同一道牆。以 2x 擷取 2880x1800 的畫面,像素量是 1440x900 的四倍,而 PNG 忠實保存每一個像素,包括每個反鋸齒文字的次像素。

06先確認你到底需不需要 PNG

在去找更小的編碼器之前,先回答三個問題,因為正確的解法取決於答案。

問題是否
這是一張照片嗎?改用 WebP 或 JPEGPNG 還算合理
需要透明背景嗎?PNG 或 WebPJPEG 開始變成選項
之後還會再編輯嗎?保留無失真母檔直接壓縮輸出檔

真正該留在 PNG 的,只有需要維持無失真的平塗圖形:圖標、介面素材、示意圖、標誌。其他內容都有更便宜的住處。

07四個真正能把 PNG 縮小的做法

做法一,重新編碼成無失真 WebP。需要逐像素相同輸出時,這是最划算的一步。我們的標誌從 PNG 的 98,032 位元組變成無失真 WebP 的 36,116 位元組,少了 63%,畫素沒變,透明通道也完整保留。

做法二,縮圖比換編碼器更有效。像素數量決定一切。長寬各砍一半後,我們照片的 PNG 從 1,733,498 位元組降到 502,066,也就是用 25% 的像素換到 29% 的位元組數,因為縮圖同時把打敗 DEFLATE 的雜訊抹平了。

做法三,把照片轉成 WebP 或 JPEG。如果內容是照片、又不需要透明,PNG 就是錯誤的容器,轉一次就能把檔案降到原本的一小部分。

做法四,色盤縮減只用於平塗圖形。對只有幾種顏色的圖標來說它是真的優化,對任何帶漸變的內容則是一場賭注。請實際確認結果,不要只看位元組數。

對大多數人來說,答案就是轉一次檔。

無失真 WebP 保留畫素又砍掉位元組,所以 PNG 轉 WebP 一個步驟就能同時處理圖形與照片類的 PNG。

08在瀏覽器裡把 PNG 縮小

圖片壓縮工具 用 Canvas API 在本機重新編碼 PNG,檔案不會離開你的裝置,也不必等待上傳。專用的 PNG 轉 WebP 頁面則在切換容器的同時保留透明通道。

  1. 把 PNG 拖進拖放區,或點擊瀏覽並選檔。
  2. 佇列會顯示每個檔案的原始體積與尺寸。
  3. 在專用頁按 Convert,或在整合頁按 Compress。
  4. 查看報告:它會列出每個檔案省下的百分比與預估輸出體積。
  5. 按 Download all 一次存下整批,或逐一儲存。

如果目標系統拒收 WebP,WebP 轉 PNG 可以回到無失真容器,PNG 轉 JPG 則把透明壓平到白底,換得更小的照片檔案。

09資料來源

常見問題

為什麼我的 PNG 比原檔還大?

PNG 會逐像素原樣保存、只壓縮重複內容,所以照片類內容可能讓體積膨脹好幾倍。我們的測試照片從相機 JPEG 的 272,551 位元組變成 PNG 的 1,733,498 位元組。

怎麼在不損失畫質的前提下縮小 PNG?

重新編碼成無失真 WebP,我們的標誌因此從 98,032 位元組降到 36,116 且逐像素相同;或者直接縮圖,因為長寬各砍一半後,我們的照片只剩原始位元組數的 29%。

色盤縮減是無失真的嗎?

不是。縮到 256 色色盤等於改寫每個像素的顏色,所以我們的照片雖然降到 633,866 位元組,天空與膚色也出現了明顯斷階。它適合平塗圖形,不適合照片。

那我直接把 PNG 轉成 JPG 就好了嗎?

只有在內容是照片、而且不需要透明時才可以。JPG 沒有透明通道,帶透明背景的標誌轉過去會變成壓在白底上的方塊。

PNG 變小就代表畫質變差嗎?

不一定。無失真工具與無失真 WebP 只改變編碼方式,不動畫素;真正會改變儲存內容的是縮圖與色盤縮減這類「減少像素資訊」的做法。

使用這個工具時 PNG 會被上傳嗎?

不會。編碼在你的瀏覽器裡完成,檔案留在你的裝置上,也不必等待上傳。

返回文章列表

相關文章

相關工具