AVIF 與 WebP 的懶人包設定?

看到「AVIF and WebP encoding quality settings」這包,看起來是 AVIFWebP 的懶人包設定。

一分鐘版的懶人包設定是基於一般 JPEG 的 quality 設定為 60 時的畫質,與 AVIF 的 50,WebP 的 65 差不多:

If you usually encode JPEGs with quality setting 60, then encode AVIF with quality setting 50 and WebP with quality setting 65. You should expect your AVIF files to be on average 36% smaller and your WebP images 15% smaller than the equivalent JPEG image.

後面給的複雜一點,包括了 JPEG quality 在 50/60/70/80 的情況。

作者用的是 DSSim 判斷圖片壓縮後的品質,看了維基百科裡面的說明,讓我想到 2016 年時 Netflix 公開的 VMAF,針對影片的品質分析:「Netflix 評估影片品質的方法」。

不過沒碰太多這塊的東西,不確定 DDSim 目前是否有被認可... 留下來當作參考。

用 picture + source + img 替代本來的 JavaScript 替換

目前我在 blog 上使用 Imgur 的圖檔主要是用 WebP 格式,然後針對不支援 WebP 的瀏覽器 (主要就是蘋果家的 Safari) 是用 JavaScript 換回 JPEG 格式...

昨天早上看到「AVIF has landed」這篇,提醒我有 <picture> 這個原生支援的方式可以用,翻了一下 Can I Use 上面的支援程度,看起來除了 IE11 以外幾乎都支援了 (參考「Picture element」),而且 IE11 應該也會因為語法的關係走到正確的 JPEG fallback,大概是這樣:

<picture>
    <source type="image/webp" srcset="https://i.gslin.com/imgur/xxxxxx.webp" />
    <img src="https://i.gslin.com/imgur/xxxxxx.jpg" alt="" />
</picture>

換完後來觀察看看...

WebP 的檔案大小未必比 JPEG 小...

在「Is WebP really better than JPEG?」這邊發現在差不多的條件需求下,WebP 壓出來的檔案大小未必會比 JPEG 小。

先講結論:提供服務的人可以先確認自家的 JPEG 壓縮是不是有先用 MozJPEG (壓縮率更好),然後再考慮要不要支援 WebP。

Google 在推 WebP 這個格式的時候,宣稱失真壓縮的部份可以比 JPEG 小 25%~34%:(出自「A new image format for the Web」)

WebP lossless images are 26% smaller in size compared to PNGs. WebP lossy images are 25-34% smaller than comparable JPEG images at equivalent SSIM quality index.

但作者發現 Google 之所以可以達到 25%~34% 這個數字,是因為比較的對象是 Independent JPEG Group 所釋出的 cjpeg,而如果拿 MozJPEG 相比的話應該得不到這個結果,另外也把 AV1 的 AVIF 拉進來一起測試了:

I think Google’s result of 25-34% smaller files is mostly caused by the fact that they compared their WebP encoder to the JPEG reference implementation, Independent JPEG Group’s cjpeg, not Mozilla’s improved MozJPEG encoder. I decided to run some tests to see how cjpeg, MozJPEG and WebP compare. I also tested the new AVIF format, based on the open AV1 video codec. AVIF support is already in Firefox behind a flag and should be coming soon to Chrome if this ticket is to be believed.

這邊作者測試用的圖集是 Kodak Lossless True Color Image Suite,測試的結果發現 WebP 的確比 libjpeg (cjpeg) 好一些,但沒有像 Google 講的那麼多 (這邊就不知道是不是現在的 libjpeg 又有改善),而 WebP 與 MozJPEG 相比的話就沒有明顯優勢了:

WebP seems to have about 10% better compression compared to libjpeg in most cases, except with 1500px images where the compression is about equal.

However, when compared to MozJPEG, WebP only performs better with small 500px images. With other image sizes the compression is equal or worse.

I think MozJPEG is the clear winner here with consistently about 10% better compression than libjpeg.

另外也提到了 AVIF 的壓縮率很好,不過要注意演算法會把非重點部位的細節吃掉:

I think AVIF is a really exciting development and compared to WebP it seems like a true next-generation codec with about 30% better compression ratio compared to libjpeg. Only concern I have is the excessive blurring of low detail areas. It remains to be seen if this can be improved when more advanced tooling becomes available.

對網頁的應用來說,WebP 另外一個痛點是在 Safari 上的支援度,在 caniuse.com 的「WebP image format」這邊可以看到目前各瀏覽器都支援了,就剩下 Safari 還不支援,所以目前在 iOS 上得降回 JPEG:

不過這點之後也改變了,在 iOS 14 beta 裡的 Safari 可以看到支援 WebP 了:「Safari 14 Beta Release Notes」。

Media
New Features
Added WebP image support.

所以這個狀況變得有點微妙了...

把 Blog 上的 PNG 圖片換成 WebP 格式

WebP 格式的大小比起 JPEG 或是 PNG 都小不少,支援度也都還行,但 Safari 不支援是個大問題,因為在行動裝置裡面 iOS 還是大宗...

目前想到的方法是只對 Imgur 的圖片使用 WebP (.webp),當遇到不支援的 WebP 的平台時透過 JavaScript 改用 PNG (.png)。

這邊有判斷有沒有支援 WebP 的程式碼出自「Detect WEBP Support with JavaScript」,用 createImageBitmap() 建看看有沒有成功:

(() => {
  let supportsWebP = async () => {
    if (!self.createImageBitmap) return false;
    const webpData = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=';
    const blob = await fetch(webpData).then(r => r.blob());
    return createImageBitmap(blob).then(() => true, () => false);
  };

  (async () => {
    if (!await supportsWebP()) {
      document.addEventListener('DOMContentLoaded', () => {
        for (let el of document.getElementsByTagName('img')) {
          let src = el.getAttribute('src');
          if (src.match(/\.webp/)) {
            el.setAttribute('src', src.replace(/\.webp/, '.png'));
          }
        }
      });
    }
  })();
})();

這邊比較有趣的是網路上的文件 (MDNCanIuse) 都說 Safari 不支援 createImageBitmap(),但實際上好像沒問題 :o

然後再用 WordPress 的延伸套件「Search Regex」把所有文章理出現 /https:\/\/i\.imgur\.com/(\w+)\.png/ 的字串換成 https://i.gslin.com/imgur/$1.webp,接下來就可以拿 Safari 測試了,這樣有點 hack 但看起來還行...

Google 的 Guetzli,對 JPEG 的壓縮演算法

Google Research Europe 推出的演算法,在不動 decoder 的情況下,要怎麼樣壓出又小又清晰的 JPEG 圖片:「Announcing Guetzli: A New Open Source JPEG Encoder」,論文可以在「Guetzli: Perceptually Guided JPEG Encoder」這邊下載,程式碼則可以在 GitHub 上的 google/guetzli 取得。

othree 也寫了一篇「Guetzli: A New Open Source JPEG Encoder」介紹 Guetzli。

Guetzli 在同樣的品質下,比現有的壓縮法可以再壓榨出 29%~45% 的空間,這算是非常驚人的數字:

We reach a 29-45% reduction in data size for a given perceptual distance, according to Butteraugli, in comparison to other compressors we tried.

但代價是需要極為大量的 CPU resource 計算,這使得他沒辦法用在太動態的環境裡:

Guetzli's computation is currently extremely slow, which limits its applicability to compressing static content and serving as a proof- of-concept that we can achieve significant reductions in size by combining advanced psychovisual models with lossy compression techniques.

但只要是在批次處理產生的過程 (不需要太在意要等很久),都可以考慮用這個工具...

使用 PNG 對圖片失真壓縮...

PNG 是無失真影像壓縮格式,但我們仍然可以修改 pixel (失真) 讓 PNG 壓縮率更好。今天在「PNG can be a lossy format」看到的 Mac OS X 應用程式就是這個用途。

雖然是應用程式,但作者還是有說明 algorithm 是哪些,分別是從哪裡來。其中兩個是:

文章最後,作者對 GIF 很感冒... XD

GIF has antiquated compression and it's a complete waste of bandwidth. Even lossy GIF is worse than lossless optimized PNG.

另外,JPEG/WebP 還是比較小,不過 JPEG 有很多格式,瀏覽器與作業系統的支援度還是很大的阻礙:

Whether lossy PNG gives better results than JPEG depends on the image. JPEG often gives smaller files, except when image has sharp edges (e.g. text) or any transparency (which JPEG does not support at all).

Optimized lossy PNG is still a bit larger than lossy JPEG-XR/WebP/JPEG-2K, but unlike these formats it's supported by all browsers and operating systems without any fuss or hacks.

最後發現 lossypng 是 Go 寫的,程式碼也不長,看起來頗好玩的... (也許包成 ports?)