用 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.imgur.com/xxxxxx.webp" />
    <img src="https://i.imgur.com/xxxxxx.jpg" alt="" />
</picture>

換完後來觀察看看...

Chrome 85 支援 AVIF

看到「How to Use AVIF: The New Next-Gen Image Compression Format」這篇在推銷用 AVIF 取代 JPEGWebP

首先是跑去 Can I Use 翻,發現 Google Chrome 85 之後支援了,另外在「Issue 960620: Support AVIF」這邊可以看到對應的 ticket,以及「AVIF Image Decode」這邊有狀態:

Enabled by default (tracking bug) in:
Chrome for desktop release 85

現在的 stabel channel 是 84,所以是下個 release 就會有了。以 Google Chrome 的市占率來說,推出來等於是支援度直接過半... 這點也的確有人批評,不過又是另外一個話題了。

對於不支援 AVIF 的瀏覽器,也有對應的 polyfill 可以上 (用 javascript 去補功能),不過因為是透過 AV1 codec,能夠向下支援的版本還是不多,除非連 AV1 都透過 polyfill 支援:「AVIF (AV1 Still Image File Format) polyfill for the browser」。

另外在寫「WebP 的檔案大小未必比 JPEG 小...」這篇時有提過 AVIF 其實也不是完美的,畢竟是從 video codec 演化來的演算法,對於演算法判斷不重要的部位會掉比較多細節...

用 Raspberry Pi 4 與 HDMI-to-USB 組出 KVM over IP 裝置

一樣是在 Hacker News Daily 上看到的專案,弄出便宜的 KVM over IP 裝置:「TinyPilot: Build a KVM Over IP for Under $100」。

主要是他在 Twitter 看到了這則,裡面提到了「Video Capture Cards, HDMI to USB 2.0, High Definition 1080p 30fps, Video Record via DSLR,Camcorder, Action Cam for Live Broadcasting, Live Streaming, Gaming, Teaching, Video Conference」這個產品:

而作者在 eBay 上面也找到了一樣的裝置,但是更便宜 (所以是「親,$11 包郵」?XDDD):

接下來是在接觸 pikvm 的時候發現了 µStreamer 這個專案:

µStreamer is a lightweight and very quick server to stream MJPG video from any V4L2 device to the net.

最後則是發現他使用的 HDMI-to-USB 裝置直接就是輸出 MJPG 格式,連 transcoding 都不用做了,大幅把 latency 降到 200ms:

其實從作者的文章可以知道,你想做的事情說不定在地球上已經有其他人做差不多了,重點是要找出來,而不需要自己硬幹 XD

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.imgur.com/$1.webp,接下來就可以拿 Safari 測試了,這樣有點 hack 但看起來還行...

又是 ImageMagick 出包...

ImageMagick 的 information leaking,然後 Yahoo! 很無奈的中獎,所以被稱為 Yahoobleed:「Yahoo! retires! bleeding! ImageMagick! to! kill! 0-day! vulnerability!」。發現問題的作者把問題寫在「*bleed continues: 18 byte file, $14k bounty, for leaking private Yahoo! Mail images」這邊。

作者利用 ImageMagick 的不當處理,取得 uninitialized memory 的資訊,藉以取得可能是上次轉檔的記憶體內容。而這個 jpeg 只有 18bytes (所以作者戲稱每個 byte 價值 USD$778):

A robust bounty of $14,000 was issued (for this combined with a similar issue, to be documented separately). $778 per byte -- lol!

目前的 workaround 也很簡單 (官方採用了),呼叫 ResetMagickMemory 避免 leaking (咦,這方法好像哪邊怪怪的):「Reset memory for RLE decoder (patch provided by scarybeasts)」。

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.

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

利用上傳的檔案跳過 CSP 限制

CSP 可以做到一些簡單的保護機制,但在設計不良的情況下還是有辦法繞過。

這次是上傳合法的 JPEG 檔案,但當作 javascript 檔案繞過去:「Bypassing CSP using polyglot JPEGs」。

開頭的「FF D8 FF E0」可以在「List of file signatures」這邊看到是「JPEG raw or in the JFIF or Exif file format」,而這四個字元在 javascript 不會出問題。接下來的「2F 2A」表示 JPEG header 長度,剛好就是「/*」,把後面的東西給包起來,後面再用類似的方式一直組合就打穿了...

這種攻擊要跳過的是「用 CSP 的 self 限制不能引用外部網站 javascript」的限制,但還是有些前提:

  • 允許使用者傳到同一個 domain 上面。
  • 網站上有 XSS 漏洞。

其中第一個問題常見的解法是另外開一個 domain 來放使用者上傳的檔案 (最好是連 top domain 都不一樣,完全隔開),才可以透過 CSP 降低風險...

另外一篇講文件掃描的...

在「Page dewarping」這篇看到講文件掃描的技術,以及 open source 的程式,對比之前提到的「Dropbox 的文件掃描功能」與「Dropbox 的 Document Detecting」的時間點,有種淡淡的惡意 XD

這篇作者是為了未婚妻的需求而寫出來的,本來是作者收到學生的作業時手動在跑,後來未婚妻也拿去用,但量愈來愈大,決定自動化處理:

A while back, I wrote a script to create PDFs from photos of hand-written text. It was nothing special – just adaptive thresholding and combining multiple images into a PDF – but it came in handy whenever a student emailed me their homework as a pile of JPEGs. After I demoed the program to my fiancée, she ended up asking me to run it from time to time on photos of archival documents for her linguistics research. This summer, she came back from the library with a number of images where the text was significantly warped due to curled pages.

So I decided to write a program that automatically turns pictures like the one on the left below to the one on the right:

程式都可以在 GitHub 上翻到:「Text page dewarping using a "cubic sheet" model」。跟 Dropbox 互別苗頭的感覺 XDDD

Dropbox 針對 JPEG 圖片再次「無損壓縮」的 Lepton

Dropbox 針對 JPEG 圖片再次無損壓縮所發展出來的 Lepton:「Lepton image compression: saving 22% losslessly from images at 15MB/s」。

直接用傳統壓縮方式對 JPEG 檔壓縮是沒有用的,他們針對 JPEG 裡的內容分析後再次無損壓縮,並且可以還原成原來的 JPEG:

Lepton achieves a 22% savings reduction for existing JPEG images, by predicting coefficients in JPEG blocks and feeding those predictions as context into an arithmetic coder. Lepton preserves the original file bit-for-bit perfectly.

當檔案夠大時的壓縮率大約就是 22%:

很可觀的數字... 另外 Dropbox 也透漏了至少有 160 億張 JPEG 圖片:

We have used Lepton to encode 16 billion images saved to Dropbox, and are rapidly recoding our older images.