前幾天貼文提到,WebP 格式在相同畫質下,WebP 體積比 JPEG 小約 25-34%,HEIC 檔案更小,通常只有 JPEG 的一半。 WebP 支援透明層及動畫,壓縮率雖然不如 HEIC 小,但勝在支援度廣(現代瀏覽器都支援,HEIC 應用仍以 Apple 設備為主)且採 BSD 授權無權利金問題,應會是近期的主流。

圖表沒納入的還有 AVIF,跟 WebP 一樣採開放標準且無專利授權問題,壓縮率更高(但顯示也更耗資源,需待設備內建硬體加速改善),但普及率又比 WebP 再低一點,會不會及何時能取代 WebP 未知。

為了克服不同裝置圖檔格式支援度不一問題,HTML 規範有個 <picture> Picture 元素,網站可為同一張圖片分別準備 AVIF、WebP、JPG 格式檔案,讓瀏覽器可視狀況優先選擇 AVIF,若不支援改用 WebP,再不行則用 JPG。每張圖要準備三種格式,HTML 圖檔寫法也要特調挺搞剛的,想追求傳輸量最小化又想保持相容性的朋友可以試試!

<picture>
  <source srcset="image.avif" type="image/avif">
  <source srcset="image.webp" type="image/webp">
  <img src="image.jpg" alt="Description">
</picture>

回到前端攻城獅的角度,這篇來試試現有 JPG/PNG 圖檔轉成 WebP 跟 AVIF,看看體積差多少。以下以 .NET 為例實測轉成 WebP 與 AVIF 的速度與減少資料庫。

先挑選程式庫,以下是 AI 給的分析與建議:

程式庫效能記憶體AVIF 支援授權方式 (License)建議對象與場景
Magick.NET快中等成熟支援Apache 2.0功能最完整
適合大量格式轉換、影像處理功能或穩定 AVIF 支援的商業專案
NetVips極快極低優秀
需 libheif/libavif
MIT(Wrapper)+
LGPL(libvips)
效能首選
適合高併發服務、大量批次轉檔、超大圖片處理
SkiaSharp極快低基本支援MIT渲染與 WebP 首選
適合縮圖、圖片顯示、WebP 轉換;
若 AVIF 是核心需求,優先考慮 Magick.NET 或 NetVips
ImageSharp中上低良好
需 AVIF 套件
Six Labors Split License部署首選。
純 C# 實作、跨平台部署最簡單;
企業商業使用需留意授權條款。

若是單純的 JPG/PNG 轉 WebP,封裝 Google Skia 圖形引擎的 SkiaSharp 速度快採 MIT 授權商用限制少是首選,但 AVIF 支援偏弱;Magick.NET 是 ImageMagick 的 .NET 版本,支援超過 100 種格式及一些圖像處理函式,功能最完整。NetVips 採 MIT + LGPL 授權,依賴 libvips 執行,速度最快;ImageSharp 不依賴原生程式庫,部署最方便,但中大型企業(年營收超過 1M USD)需付費,這二者在商業應用時需留意授權問題。
註:依賴原生程式庫有時是件麻煩事,想起這幾個程式庫我之前交手過,也吃過苦頭。

我測試了 Magick.NET、SkiaSharp 與 ImageSharp,花了點時間找到三種程式庫轉 WebP 及 AVIF 的做法。先簡單記錄過程遇到的小問題:

  • ImageSharp 現在需要授權碼才能使用,個人用途可到網站填寫資料索取 sixlabors.lic 檔案,有效期一年,存在專案目錄即可正常執行。
    No Six Labors license found. Set $(SixLaborsLicenseKey), set $(SixLaborsLicenseFile), 
    or add a 'sixlabors.lic' file to the project/workspace.
    Please obtain a license from https://sixlabors.com/pricing/
    
  • AVIF 普及度仍落後 WebP,除了 Magick.NET 直接支援,SkiaSharp 可顯示不能製作 AVIF,故 SkiaSharp 與 ImageSharp 需要自己找第三方原生程式庫提供 AVIF 轉換。
  • PNG 轉 AVIF 可能遇到色彩空間不相容問題
    INFO: legacy PNG color space information found in file {png-path} not matching any CICP value.   
    libavif is generating an ICC profile for it. Use --ignore-profile to ignore color space information instead (may affect the colors of the encoded AVIF image).
    

綜合以上,我覺得現階段使用 AVIF 會比 WebP 麻煩一點。最後我選擇使用 MagicK.NET 作為我的主要工具,理由有三:

  1. Magick.NET-Q8-x64 套件直接支援 windows/linux/linux-musl/macOS,不需另外安裝對應平台的原生程式庫
  2. ImageMagick 的圖檔格式支援、轉檔與圖形處理功能完整,可成為專案開發圖形處理的重要工具
  3. ImageMagick 有 magick CLI 工具,可直接轉檔與程式轉換結果對照

以下是簡單的轉檔測試,除了使用 Magick.NET 程式庫,另外會直接呼叫 magick CLI 轉換相同品質的 WebP/AVIF 對照結果是否正確:

using ImageMagick;
// dotnet package add Magick.NET-Q8-x64
// Q8 8-bit per channel, x64 含 windows/linux/linux-musl/macOS 版本
public class ImageMagickTest
{
    static void ConvertByMagickCli(string inputPath, string outputPath, uint quality, string losslessFlag = "")
    {
        // https://imagemagick.org/webp/
        var process = new System.Diagnostics.Process();
        process.StartInfo.FileName = "magick";
        process.StartInfo.Arguments = $"\"{inputPath}\" -quality {quality} {losslessFlag} \"{outputPath}\"";
        process.StartInfo.UseShellExecute = false;
        process.StartInfo.CreateNoWindow = true;
        process.Start();
        process.WaitForExit();
    }

    public static void ConvertToWebp(string inputPath, string outputPath, uint quality = 75)
    {
        bool lossless = quality > 100;
        if (lossless) quality = 100; 
        using (var image = new MagickImage(inputPath))
        {
            // 可以設定 WebP 專屬參數
            // image.Settings.SetDefine(MagickFormat.WebP, "lossless", false);
            if (lossless)
            {
                image.Settings.SetDefine(MagickFormat.WebP, "lossless", true);
            }
            image.Quality = quality;
            image.Write(outputPath, MagickFormat.WebP);
            // 呼叫 magick CLI 轉換
            var cliChkPath = outputPath.Replace(".webp", ".cli.webp");
            ConvertByMagickCli(inputPath, cliChkPath, quality, lossless ? "-define webp:lossless=true" : "");
        }
    }

    public static void ConvertToAvif(string inputPath, string outputPath, uint quality)
    {
        // 關於 AVIF 是否真的 lossless 的討論
        // https://github.com/ImageMagick/ImageMagick/discussions/6591
        bool lossless = quality > 100;
        if (lossless) quality = 100;
        using (var image = new MagickImage(inputPath))
        {
            if (lossless)
            {
                image.Settings.SetDefine(MagickFormat.Avif, "lossless", true);
                // AOM encoder error: Invalid parameter - Only --enable_chroma_deltaq=0 can be used with --lossless=1. (8.2005) 
                image.Quality = 99;
            }
            else {
                image.Quality = quality;
            }
            image.Write(outputPath, MagickFormat.Avif);
            // 呼叫 magick CLI 轉換
            var cliChkPath = outputPath.Replace(".avif", ".cli.avif");
            ConvertByMagickCli(inputPath, cliChkPath, quality, lossless ? "-define avif:lossless=true" : "");
        }
    }
}

我自己圖檔應用的最大宗是部落格上的電腦畫面擷圖,目前怕 JPEG 有損壓縮讓文字模糊,都是用 PNG,說真的有點偏肥。WebP/AVIF 都支援無損壓縮,而且體積比 PNG 小 26%,而高畫質有損壓縮時,對文字的保護也比傳統 JPEG 好,是我最想試試的部分。

爬文查到一篇參考數據,1920x1080 文字為主擷圖:

  • PNG (32-bit RGBA): 150-400KB
  • PNG (indexed via pngquant): 40-120KB
  • JPEG (quality 85): 120-250KB (with visible artifacts around text)
  • WebP (lossless): 100-300KB
  • WebP (lossy, quality 90): 60-150KB (minimal visible artifacts)

但,參考文章濃濃的 AI 味,自從前幾天踩到技術 AI 文的坑,我現在十年怕井繩。

Google 的 WebP 範例文件可信度高多了,實測 PNG 轉 WebP 無損壓縮約可節省 28% ~ 40%。

總之,這篇也會來實測一下,為人類手寫技術文保留一縷香煙...

我選了兩張圖片當測試範例,一個是 VSCode 的操作畫面擷圖 (Screenshot),一個則是照片範例 (Photo),用 iStock 圖庫網站查詢畫面當例子:

實測超乎我的預期:

QualityScreenshot
WebP
Screenshot
AVIF
Photo
WebP
Photo
AVIF
PNG206 KB206 KB1118 KB1118 KB
Lossless57 KB113 KB753 KB359 KB
100%57 KB—753 KB—
99%229 KB113 KB307 KB359 KB
95%194 KB94 KB235 KB250 KB
90%160 KB79 KB169 KB184 KB
85%136 KB70 KB135 KB149 KB
80%119 KB65 KB114 KB133 KB
75%105 KB60 KB97 KB116 KB
70%100 KB56 KB91 KB103 KB
65%96 KB52 KB86 KB87 KB
60%93 KB50 KB81 KB78 KB
55%90 KB47 KB78 KB66 KB
50%86 KB45 KB74 KB57 KB

VSCode 操作畫面擷圖的 PNG 轉為 WebP 無損壓縮,檔案由 206K 變成 57K,足足減少了 73%。有趣的是,若使用有損壓縮且設定高品質水準,體積反而比無損壓縮大!

原因是 WebP 無損與有損使用的是不同的編碼器,Lossless 使用 VP8L,Lossy 使用 VP8 是兩套不同演算法。VP8L 非常適合有大片純色背景、重複圖案及銳利文字的畫面擷圖場景,能發揮極高的壓縮率。而有損編碼器需要額外儲存壓縮用的係數資料、Metadata... 等,有固定成本,當要求高品質低細節損失,這些固定成本增加的資料量低於省略細節所減少的資料量,才造成檔案大小不減反增。

而遇到相片性質影像,WebP 無損壓縮的表現就沒這麼突出了。而在 AVIF,畫面擷圖的無損壓縮圖檔可以減少 55% 大小,也比 PNG 好很多。

我做了拼貼圖片一次比較不同壓縮品質的效果:

  1. 畫面擷圖 WebP

  2. 畫面擷圖 AVIF

  3. 照片影像 WebP

  4. 照片影像 AVIF

另外,我叫 AI 寫一個互動式線上對照檢視,大家可以實際操作看看。

我眼睛不怎麼銳利,甚至覺得 50% 品質好像也沒差到哪裡去。但以畫面擷圖來說,使用 WebP 無損壓縮應是最佳選擇。

做完實驗,我最大的心得是:過去我部落格文章的擷圖為了怕轉 JPG 變模糊而一律存 PNG,無形中浪費了許多空間與頻寬,其實只要改用 WebP 無損壓縮,甚至能縮小 70% 以上的體積,WebP 出來這麼多年,我今天才正式感受到威力。

而經過這次實測,發現開發端對的 AVIF 的支援不如 WebP 成熟,而我常用畫面擷圖,WebP 無損壓縮的表現非常出色,減少的資料量超乎預期。所以我打算過陣子調整我的部落格平台,確保可以完整支援 WebP 格式,正式進入 WebP 時代。

Tests converting PNG/JPEG images to WebP and AVIF with .NET libraries, comparing support, licensing, performance, and file sizes. Results show WebP lossless greatly reduces screenshot size, making it a practical upgrade for blog images.


Comments

# by yoyo

不過這篇文章的圖片還是用PNG跟JPG XD

# by guest

文字為主的截圖可以考慮64索引色png喔!(206.7k->68.2k)

# by guest

圖1(常見圖片格式那張)也可縮小(247.9k->49.5k)

Post a comment