超快的PNG圖像解碼器!速度提升2.75倍,比老大哥libpng還安全
本文經AI新媒體量子位(公眾號ID:QbitAI)授權轉載,轉載請聯系出處。
提到PNG,大多數人都不會感到陌生。
這種位圖格式在圖像領域使用頻率僅次于JPEG。
然而在“解碼PNG”這件事上,23年來主流的工具是一個叫做libpng的標準庫。
但最近,一款號稱“世界上最快的PNG圖像解碼器”誕生了,速度是“老大哥”的1.22-2.75倍!

除了速度方面的優勢之外,更重要的一點,極其安全。
超快的PNG圖像解碼器
與用C語言為底層的libpng不同,這款PNG圖像解碼器采用的是Wuffs。
Wuffs是一種內存安全的編程語言(也是用這種語言編寫的標準庫),用于安全處理不受信任的文件格式。
包括解析、解碼和編碼圖像,音頻,視頻,字體等。
Wuffs不是一種通用編程語言。它是用來編寫庫的,完整的程序需要將Wuffs與另一種編程語言結合使用。
尤其是需要同時考慮性能和安全性的時候。
ps. 機智的你發現了嗎,Wuffs其實就是Wrangling Untrusted File Formats Safely的縮寫。
不過它以前叫Puffs,至于為什么將Puffs(parsing)改為Wuffs(wrangling),留給你們自己去想象~
那么,解碼速度快至2.75倍,怎么做到的?
Wuffs通過SIMD加速方案,8字節寬的輸入和復制,一次將整個圖像進行位扭曲和zlib解壓縮到一個大的中間緩沖區來實現高性能。此法替代了此前的一次一行(小塊重復壓縮)的方式。
這“一包帶走”的操作需要更多的中間存儲,但能解碼的圖像數量也更多了。
具體咋回事兒呢?
我們知道,PNG圖像格式編/解碼基于以下三方面:
- CRC-32和Adler-32兩種校驗和算法
- DEFLATE壓縮
- 二維過濾
Wuffs對這其中的每一步都進行了優化。
首先,對兩種校驗和算法施以SIMD加速技術。
SIMD是一種采用一個控制器來控制多個處理器,同時對一組數據中的每一個分別執行相同的操作從而實現空間上的并行性的技術。
其次,0.2版本Wuffs具有與zlib庫一樣的DEFLATE實現,而0.3版Wuffs為現代CPU(具有64位未對齊加載和存儲)添加了兩個重要的優化:8字節區塊輸入和8字節區塊輸出。
DEFLATE是同時使用了LZ77算法與哈夫曼編碼的一個無損數據壓縮算法。
對于Wuffs,8字節區塊輸入設計的每個內部循環一次讀取64位可使DEFLATE微基準加速多達1.3倍。
而8字節區塊輸出設計將副本長度舍入為8的倍數可以使DEFLATE微基準提高多達1.48倍。
此外,DEFLATE涉及寫入目標緩沖區和寫入緩沖區邊界的問題。
(經典的“緩沖區溢出”安全漏洞,類似于從懸崖上奔跑,如何不落入鯊魚口中)。
此方面,Wuffs使用和libpng相似的藍/紅雙重實現技術。
藍/紅雙重實現技術:一種快速的“藍色”解壓縮(在距緩沖區末端至少258個字節或更多字節 時)以及一種緩慢的“紅色”解壓縮(反之)技術。
以前面的從懸崖上奔跑做比喻,就是在離崖邊還遠時盡可能得快跑,離崖邊很近時減速剎車。

但同樣的技術,為什么Wuffs更快?
因為它能一次將幾乎所有內容(eg. 300×200 RGB圖像的像素的99%以上)解壓縮到一個大的中間緩沖區中,而不是一次只壓縮一行到一個小的、可重復使用的中間緩沖區中。
如圖所示,幾乎所有內容現在都在“藍色”區域中解碼。
這本身就比“紅色”區域快。
而且在藍色代碼和紅色代碼之間交替時,Wuffs也避免了任何指令高速緩存或分支預測變慢的情況。

最后,雖然Wuffs和libpng都具有PNG二維過濾的SIMD實現。
但是因為libpng將任何自分配的像素行緩沖區對齊到最適合SIMD的邊界時,對齊這步操作會影響SIMD指令的選擇和性能。
而Wuffs對緩沖區對齊的承諾較少,部分原因是Wuffs不具有分配內存的能力,但主要還是因為一次全部解壓縮時,zlib壓縮要求放棄例如每行開頭4字節的對齊。
為什么說最安全?
與Go或Rust不同,Wuffs的內存安全是在編譯時強制執行的,而不是通過插入運行時再檢查。
( ps.運行時安全檢查也可能會影響性能。)
此外,在處理不受信任的(第三方)PNG圖像時,沙盒和多進程體系結構可以提供額外的深度防御。
在上一節描述的三步優化技術也可用來給現有的libpng、Go/Rust PNG庫等打補丁。
然后就有網友說這樣一來Wuffs還是不是最快的就難說了……但開發者表示至少在安全性方面,Wuffs No.1沒得說。

最后,Wuffs版本0.3.0-beta.1剛剛發布,但從目前的功能來看,它還不支持顏色空間或伽馬校正。