Webp 圖片格式:比 JPG 還要小?

最近在想如何加快網頁圖片讀取速度
最簡單的方式應該就是降低圖片檔案大小了
但是總不可能縮小圖片尺寸來降低檔案大小
於是我把目標轉向了圖片格式…
WebP
Google 在 2010 年的時候公布了 WebP 格式,到目前為止,已經有 94% 的瀏覽器支援這個圖片格式了。
這個格式的主要目標是在減少網路上圖片的大小,來藉此加快網頁的載入速度。
根據 Google 開發人員的說明1,跟 PNG 檔案相比,不失真的圖片可以減少 28% 以上的檔案大小。
WebP 格式同時支援不失真的壓縮以及失真壓縮,另外也支援 Alpha 通道,所以可以有透明的背景,而且,也有支援動畫,可以取代 GIF,降低檔案大小。
比較
這邊我找了張風景照,原始圖片檔案是 JPG,檔案大小 668 KB,使用 80% 失真壓縮成 WebP 之後,檔案大小縮小成 378 KB,只有原本的 57% 左右。
以下圖片上方為原始圖片,下方為轉換後的圖片,不仔細看很難發現出差異,雖然我仔細看也看不出來。
JPG 格式
WebP 格式
搜尋圖片
由於圖片檔案分在資料夾各個不同的地方,因此我打算寫一個 Python 檔案,來找到這些圖片檔案,並將他們換成 WebP 格式。
要用 Python 轉換成 WebP 的話可以直接使用 Pillow
套件,沒有安裝過的可以執行以下指令:
pip install pillow
首先我們先找到所有圖片的路徑,這裡使用 glob
來找所有的 jpg 圖片。
由於我們要找尋資料夾內所有的子目錄,所以要加上 ** 和 recursive
= True。
import glob
import os
directory = "content"
for img_path in glob.glob(os.path.join(directory, "**", "*.jpg"), recursive=True):
print(img_path)
由於 glob.glob
是回傳 list
,如果檔案數量很多的話,會占用一部份的記憶體,因此可以改成用 glob.iglob
來得到 iterator,這樣就不會占用記憶體了。
另外,如果圖片檔案格式有很多個的話,我們可以把每個格式都搜尋一遍,並且使用 chain.from_iterable
將這些 iterator 都串起來。
import glob
import os
from itertools import chain
directory = "content"
extensions = ["png", "jpg"]
def multiple_file_types(path, patterns):
return chain.from_iterable( \
glob.iglob(os.path.join(path, f"*.{pattern}"), recursive=True) for pattern in patterns)
for img_path in multiple_file_types(os.path.join(directory, "**"), extensions):
print(img_path)
轉換
轉換的部分就比較簡單了,用 pillow
讀取圖片,儲存的時候以 WebP 的格式儲存即可。
fileName = "test.png"
newFileName = "test.webp"
im = Image.open(fileName)
im.save(newFileName)
最後 code 組合起來是這樣:
import glob
import os
from PIL import Image
from itertools import chain
def multiple_file_types(path, patterns):
return chain.from_iterable(glob.iglob(os.path.join(path, f"*.{pattern}"), recursive=True) for pattern in patterns)
def convert(directory, extensions):
for img_path in multiple_file_types(os.path.join(directory, "**"), extensions):
print(img_path, end=" ")
# 取得圖片名稱
filename = os.path.splitext(img_path)[0]
# 取得圖片原始檔案大小
orig_file_size = os.path.getsize(img_path)
# 轉成 webp
im = Image.open(img_path)
file_path_webp = f"{filename}.webp"
im.save(file_path_webp)
# 取得轉換後的檔案大小
webp_file_size = os.path.getsize(file_path_webp)
# 印出減少比例
print(f"{(webp_file_size/orig_file_size)*100:.0f}%")
if __name__ == '__main__':
convert("content", ["png", "jpg"])
convert("static", ["png", "jpg"])
Reference
如果你覺得這篇文章有用 可以考慮贊助飲料給大貓咪