Wen Chen
Published on

實測 PIL 壓縮圖片(WebP、Jpeg)之差異

Authors
  • avatar
    Name
    Wen Chen

前言

繼上一篇寫了:用python批次將圖片轉檔成webp並壓縮 後,寫完的當下突然想到,當初單純想試試用WebP作為 Blog 主要的圖片格式,實際上卻沒有實際測試過 JPG 與 WebP 壓縮過後的差異,於是便產生了這篇文章。

這篇主要還是會透過上次寫出來的程式碼,使用 Pillow 做轉檔,裡面只會最簡單的對 quality 做設定,其他都保持 default ,來粗糙測試兩者壓縮出來檔案的差異。


WebP 是啥?

先提提什麼是 WebP , 底下擷取幾段從維基百科獲取的內容:

WebP最初在2010年9月釋出,其支援庫於2018年4月發布1.0版本。截至2021年5月,已有94%的瀏覽器支援此格式。
WebP的無失真壓縮比網路上找到的PNG檔少了45%的檔案大小,即使這些PNG檔在使用pngcrush和PNGOUT處理過,WebP還是可以減少28%的檔案大小。

維基百科內只有提到無損壓縮,可以比 PNG 減少 45% 的檔案大小,然而有損壓縮部分,透過在網路上查到的數據,大概可以比 jpg 減少 20% 左右的檔案大小。

無損壓縮? 有損壓縮?

提一下兩者差異,畢竟本篇主要還是實測。

  • 有損壓縮:犧牲部分信息來壓縮圖片,壓縮後不可逆 (JPG),每次壓縮會越壓畫質越差。
  • 無損壓縮:壓縮後不影響圖片品質 (PNG),如果有頻繁更動照片的需求,使用 PNG。

再來說說我自己的使用情境,我的照片調整完不會有頻繁更動的需求,所以基本上都是有損壓縮,且雖然有損壓縮聽起來可怕,但從各裝置上來看,除非真的放大比較,不然肉眼上根本看不出差異。

實測

無損壓縮

因為在離開影視產業後,我拍照幾乎都直接拍 jpg 檔,因為已經經過一次相機壓縮,所以主要測試對照,我上 Signature Edits 找了免費的 Raw 檔透過 LR 直出成 PNG 做測試。

先上程式碼:

import glob
from PIL import Image

png = glob.glob('./raw/*.[pP][nN][gG]')

for i in png:
    print(i)
    im = Image.open(i)
    name = i.lower().split('/')[::-1][0]
    webp = name.replace('png', 'webp')
    # png => WebP
    im.save(f'./converted/{webp}', "WebP", lossless=True)
    # png => png
    im.save(f'./converted/{name}')

基本上就是從原本的程式碼修改一下,WebP 存檔時加入 lossless=True 來無損壓縮,png 則是直接再存成 png 一次,其他均為 default。

我們先看下結果:

無損
  • 原圖透過 Lr 直出 PNG 檔案大小為 28.6MB
  • Pillow 轉存成 PNG 檔案大小為 32MB
  • Pillow 轉存成 WebP 檔案大小為 19.9MB

Pillow 轉存成 Png 檔案還比原始圖大,原因來自於 Lr 跟 Pillow 本身 default 設定還是有差異,不過就還是比較給各位參考。

也就得到了以下結果:

  1. WebP 無損壓縮對比原始 PNG 約減少了 30.4%
  2. WebP 無損壓縮對比同用 Pillow 轉存成 PNG 的檔案約減少了 37.8%

總體來說算是接近維基百科上的數據了。

有損壓縮

接著回到有損壓縮,也是我個人會使用的情境,這次會各轉成 Jpeg 與 有損 WebP 各一張,我們一樣先跑一次 default 看看結果:

程式碼:

import glob
from PIL import Image

png = glob.glob('./raw/*.[pP][nN][gG]')

for i in png:
    print(i)
    im = Image.open(i)
    name = i.lower().split('/')[::-1][0]
    webp = name.replace('png', 'webp')
    jpg = name.replace('png', 'jpg')
    # png => WebP
    im.save(f'./converted/{webp}')
    # png => jpg
    im.save(f'./converted/{jpg}')

結果如下:

有損

這次的差異就比較明顯了:

  • JPG: 1.9MB
  • WebP: 956kb

減少了將近 50% 的大小,當然,我相信並不是所有圖片壓縮後都能有這樣子的效果,不過 WebP 壓縮相較於 Jpeg 會比較小這件事是可以確定的!

最後放一張三者對比圖,在不特別標記的情況下,不曉得各位認為差距大不大呢? (這張圖截圖已經壓縮過)

compare

文章最後會有 Google 雲端連結,保留所有原圖

我個人覺得,在預設參數下,放大非常多倍數的情況下,Jpeg 版本保留的細節比較多,但換個角度想:

假如加入 options 強制把 Jpeg 壓到 956 kb 左右,那畫質上 WebP 便會取勝。

實際情境

剛剛上面的測試是透過 Raw File 直出成 PNG 去轉檔的,那實際情境呢?

前面提到過,我個人拍照時相機都是拍 JPG 直出,本身已經經過一次相機壓縮,但對於我期望的檔案大小還是過大,所以在調整完色調後,我會再壓縮一次轉成 WebP,期望每張圖片大小可以壓在 500kb 以下。

於是我找了一張之前拍的照片,原始大小為 1.8MB 的 JPEG:

sample

前一篇文有提到我的 quality 大概都設在 40 ~ 50 之間,這參數是我針對我相機拍出來的照片,可接受的畫質範圍,檔案大幅瘦身,畫質也不至於太差。

某些文件顯示,設在 75~80 可以取得較好的容量畫質平衡

這次我先將我的 quality 設在 50,轉存一次 WebP :

im.save(f'./converted/{webp}', quality=50)

壓縮過後的WebP檔案大小為 465Kb

基於此標準經過幾次測試,要達到接近的大小水平,Jpeg 檔必須把 quality 設在 15 左右,而此時產出的Jpeg 檔案大小為 479Kb

# raw 為 jpg file
im.save(f'./converted/{raw}', quality=15)

假如同樣設在 quality=50 的話 Jpeg 的大小為 1.2MB

就如同先前推測的一般,當 Jpeg 的檔案壓縮至與 WebP 相同時,畫質會有明顯的差距,且是肉眼即可看出的差距,接著我們來看下差異:

compare

透過大圖,我們其實就可以看出,Jpeg 的版本已經開始有點模糊,白色的部分也開始失真。

接著我們放大白色的部分,而放大後就更明顯了:

compare

結論

從實測結果來看,確實 WebP 在壓縮過後,可以得到更小的容量,且在最後的實測,從 1.8MB 的 Jpeg 壓縮至 465Kb 的 WebP 後,再不特別放大的情況下,肉眼幾乎無法辨別差異。

總結來說,這次的實測一部分也算是驗證網路上提到那些優點,下次在專案中不妨試著嘗試使用 WebP 哦!

本文所有用到的圖片

(放心,連結是google drive 沒有毒)