作者:addy osmani
譯者:波比小金剛
翻譯水平有限,若有錯誤請指出
前言
自動化壓縮影象
影象優化應該是自動化的。因為它很容易被遺忘,且最佳實踐容易發生改變,而且沒有通過構建管道的內容容易丟失。為了實現自動化,你可以使用 imagemin 或者 libvips 構建程式,當然,這不是唯一的,依然存在很多的替代方案。
大多數 CDN(比如 Akamai)以及第三方解決方案(Cloudinary,imgix,Fastly’s Image Optimizer,Instart Logic’s SmartVision ,ImageOptim API)都提供全面的、專業的自動影象優化解決方案。
談錢不傷感情,你花在閱讀部落格或者調整專案配置上的花費大於三方服務的月費(Cloudinary 有一個免費套餐)。如果因為成本或者延遲問題不想外包該項工作,那麼上面提到的開源專案是可靠的選擇。Imageflow,thumbor等專案都提供自託管替代方案。
高效的壓縮影象
至少應該使用 ImageOptim。它可以在保持視覺質量的同時顯著減小影象的大小。 Windows 和 Linux 替代品也可用。
更具體的說,就是通過 MozJPEG (q = 80 或更低,適用於Web內容) 來執行 JPEG 並且考慮支援漸進式JPEG,PNG 圖片通過 pngquant,SVG 則通過 SVGO 進行優化。通過明確的刪除後設資料(--strip for pngquant)來縮小檔案的體積。不要使用體積巨大的動畫 GIF,使用 H.264 視訊(或者 Chrome, Firefox 和 Opera 都支援的 WebM)替代。如果不能,請至少使用 giflossy 進行優化。如果你可以分出額外的 CPU 週期並且能夠忍受過慢的編碼時間,在需要高於網路平均質量的場景,你可以嘗試 Guetzli。
一些瀏覽器通過 Accept 請求頭展示其對不同格式圖片的支援度,這可用於實現針對不同瀏覽器提供不同的影象格式:比如對基於 Blink 的瀏覽器提供有損 WebP 圖片,對其他的提供 JPEG/PNG,進而實現優化的目的。
你可以進一步優化,有很多生成和提供 srcset 斷點的工具,結合 Client Hints 可以在基於 Blink 的瀏覽器上實現資源的自動選擇。並且通過 Save-Data 可以向選擇 'data savings' 的使用者傳送更少的資料。
譯者注:關於 Client Hints,Save-Data 的知識點可以細讀文章末尾的更多參考。 思考:結合 Service Worker 實現圖片優化處理。
實際上,ServiceWorker 是在瀏覽器中執行的客戶端代理。它攔截所有傳出的請求,並允許您檢查,重寫,快取甚至合成響應。影象沒有區別,在啟用 Client Hints 的情況下,ServiceWorker 可以識別影象請求,檢查提供的客戶端提示,並定義自己的處理邏輯。更多內容
影象檔案的大小越小,網路體驗就會更好 -- 特別是在移動裝置上。在這篇文章中,我們將探討通過現代壓縮技術縮小影象尺寸的方法,同時將對圖片質量的影響降至最低。
正文
介紹
影象依然是頭號效能殺手
影象一般檔案體積較大,因而會佔用大量的頻寬。根據 HTTP Archive 的資料顯示,獲取一個網頁所傳輸的資料中有 60% 都是 JPEG,PNG 和 GIF 組成的影象。截至2017年7月,平均 3.0MB 網站內容中影象佔 1.7MB。
根據 Tammy Everts 的研究,新增圖片到頁面或者使現有圖片更大一點可以提高轉化率。影象是網頁必不可少的部分,所以制定一個有效的壓縮策略顯得尤為重要。
譯者注:這裡的轉化率,指的是轉換為活躍客戶的網站訪問者百分比
減少影象檔案的體積只是影象優化眾多度量中的一種,它最終取決於實際需要的視覺保真度。
影象優化:選擇正確的格式,仔細壓縮並優先處理關鍵影象,而不是那些可以延遲載入的影象。
常見的影象優化包括壓縮,使用<picture>
/ <img srcset>
根據螢幕大小響應地優雅降低,並調整它們的大小以降低影象解碼成本。
根據 HTTP Archive 的資料顯示,第95%位的每張影象節省了30kb
所以,我們有足夠的空間來優化影象。
ImageOptim 是免費的,通過現代壓縮技術剝離不必要的 EXIF 後設資料來減少影象大小。
所以,如果你是一個設計師,請安裝一個 ImageOptim plugin for Sketch,在匯出影象時優化大小,這樣會節省大量時間。
如何判斷我的影象是否需要優化?
這裡提供一個效能測試的網站,可以高亮提醒你圖片優化的方向!
WebPageTest 的報告列出了哪些可以被更有效壓縮優化的圖片列表以及預估的優化體積
Lighthouse 是一個很酷的工具,提供效能優化的各種最佳實踐,包括了對圖片的優化:建議哪些圖片可以被進一步壓縮或者哪些螢幕外的圖片可以被延遲載入。
從 Chrome 60 開始,Lighthouse 在 Chrome DevTools 中的 Audits 皮膚中被支援:
你可能還熟悉其他效能稽核工具,如 PageSpeed Insights 或 Cloudinary Test by Cloudinary。
如何選擇影象格式?
正如 Ilya Grigorik 在其 影象優化指南 中指出的一樣,正確的"影象格式"是視覺效果需求和功能要求的組合。你在使用向量影象或者光柵影象嗎?
光柵影象通過對矩形畫素網格內的每個畫素的值進行編碼來表示影象。光柵影象沒有與解析度或縮放無關這麼好的屬性,當你放大光柵影象時,圖形會出現鋸齒並且模糊不清。因此,你可能需要在不同解析度下儲存多個版本的光柵影象,以便為使用者提供最佳體驗。在追求"照片級寫實"場景下,應該使用光柵影象格式(例如 GIF、PNG、JPEG 或 JPEG-XR 和 WebP 等某種較新的格式)。
向量影象使用線、點和多邊形來表示影象。向量影象最適用於包含簡單幾何形狀(例如徽標、文字、圖示等)的影象,能夠在任何解析度和縮放設定下呈現清晰的效果。
低調的 JPEG
JPEG 可能是世界上使用最廣泛的影象格式,之前提到的 HTTP Archive 抓取的網站上有 45% 的圖片是 JPEG。你的手機、單反、攝像頭...都支援這種格式。它是一種古老的格式,於 1992 年被首次提出,之後的時間裡被不斷優化和改進。
JPEG 是一種有失真壓縮標準方法,在保證視覺還原度的同時,盡力的丟棄一些資訊以節省空間。
譯者注: 1. 關於有失真壓縮和無失真壓縮 2. JPEG 不支援動畫、不支援透明度,每個畫素 24 位(也就是說最多可以表示
Math.pow(2, 24)
種顏色),所以在視覺保真上表現優秀,常用在 banner 圖,輪播圖上。
選擇你能接受的圖片質量
JPEG 這種型別的影象格式最適合有多個顏色區域的圖片,在壓縮的時候需注意過度的壓縮會導致光暈、色塊丟失等。
所以在進行壓縮的時候,需要結合實際的功能要求和視覺需求制定方案。影象質量需求高於對效能、頻寬的要求的時候選擇高質量的壓縮方案。
JPEG 壓縮模式
JPEG 有多種不同的壓縮模式,最流行的三種分別是 baseline (sequential), Progressive JPEG (PJPEG) 和 lossless。(線性、漸進式、無損)
漸進式與線性的區別
線性 JPEG (大多數圖片編輯和優化工具的預設設定)以相對簡單的方式進行編碼和解碼:從上到下。所以在影象載入較慢或者連線不穩定的時候,使用者看到的是從上到下逐漸載入的。無損型別的與之lei s
漸進式 JPEG 則是把圖片分成多個"掃描",第一次"掃描"會先載入模糊、低質量的圖片,後續的"掃描"會提高圖片的質量。這個過程你可以想象為逐步的改進圖片,不斷的增添細節,最終呈現一個全畫質的影象。
無損 JPEG 優化通過刪除數碼相機或編輯器新增的 EXIF 資料,優化影象的霍夫曼表或重新掃描影象實現。jpegtran 之類的工具是通過重新排列壓縮資料而不會降低影象質量來實現無失真壓縮。jpegrescan,jpegoptim,mozjpeg 也都支援無損 JPEG 壓縮。
漸進式 JPEG 的優點
PJPEG 載入的時候提供的低解析度"預覽"功能提高了感知效能。使用者會感覺載入更快一點。在較慢的 3G 連線上使用者可以模糊的看到圖片內容從而決策下一步的計劃,比從上到下載入有更好的使用者體驗。
對於超過 10KB 的影象,PJPEG 與線性 JPEG 相比,頻寬減少2-10%。 PJPEG 的壓縮比更高,這得益於 JPEG 中的每次掃描都能夠擁有自己專用的可選霍夫曼表。 現代 JPEG 編碼器(例如 libjpeg-turbo,MozJPEG 等)利用 PJPEG 的靈活性來更好地打包資料。
注意:為什麼 PJPEG 壓縮得更好? 線性 JPEG 一次編碼一個塊。 利用 PJPEG,可以將跨越多個塊的類似離散餘弦變換系數編碼在一起,從而實現更好的壓縮。
誰在生產環境使用了 PJPEG?
1. Twitter.com ships Progressive JPEGs
2. Facebook ships Progressive JPEGs for their iOS app
3. Yelp switched to Progressive JPEGs
很多具有密集影象的網站都使用了漸進式 JPEG。比如 Pinterest
漸進式 JPEG 的缺點
漸進式 JPEG 的解碼速度比線性 JPEG 更慢 - 有時長達3倍。這在具有強大 CPU 的 PC 上可能不是太大的問題,但是在動力有限的移動裝置上則是個問題了。顯示不完整的圖層需要多次解碼,這些多次傳遞會佔用 CPU 週期。
漸進式 JPEG 也不總是更小。 對於非常小的影象(如縮圖),漸進式 JPEG 可能比其線性對應的大。 而且,對於這樣的小縮圖,漸進式渲染可能不會真正提供那麼多的價值。
譯者注:效能優化實際就是在矛盾中尋找平衡點。對漸進式 JPEG 的使用也是在圖片大小、CPU、網路情況等各種要求中找到一個最佳的平衡點。
注意:PJPEG(和所有 JPEG )有時可以在移動裝置上進行硬體解碼。 它沒有改善 RAM 影響,但它可以消除一些 CPU 問題。 並非所有 Android 裝置都支援硬體加速,但高階裝置支援,所有 iOS 裝置也是如此。
如何建立漸進式 JPEG
ImageMagick, libjpeg, jpegtran, jpeg-recompress 和 imagemin 都支援漸進式 JPEG 格式圖片的匯出。
很容易融合到我們的自動化構建中:
const gulp = require('gulp')
const imagemin = require('gulp-imagemin')
gulp.task('images', function(){
return gulp.src('images/*.jpg')
.pipe(imagemin({ progressive: true }))
.pipe(gulp.dest('dist'))
})
複製程式碼
你也可以通過圖片編輯工具實現生成漸進式 JPEG。
色度(或顏色)取樣
人類的眼睛對顏色細節的丟失比對亮度丟失要更寬容一點。利用這一點,在進行色度取樣的壓縮方式的時候,降低其顏色精度可以有效的優化檔案體積,在某些情況下可以達到 15%-17%的體積減少。而且不會對影象質量產生影響,並且可以用於 JPEG,還可以減少影象記憶體使用量。
由於對比度負責形成我們在影象中看到的形狀,因此定義它的亮度顯得非常重要。比如老舊或過濾的黑白照片可能不包含顏色,但由於亮度,還是可以像它們的顏色對應物一樣詳細的表述內容。因此可以看出色度(顏色)對視覺感知的影響較小。
上圖展示了子取樣的常見樣本。4:4:4,4:2:2 和 4:2:0。
1. 4:4:4 沒有壓縮,因此顏色和亮度完全被傳輸。
2. 4:2:2 水平半取樣,垂直全取樣。
3. 4:2:0 取樣第一行畫素的一半,並忽略第二行。
複製程式碼
通過減少色度分量中的畫素,可以顯著減小顏色分量的大小,最終減小位元組大小。
可以看出在質量為 80 的情況下,色度取樣策略帶來的體積減少,而且在視覺上並無違和感
色度取樣也並不是適用於所有場景,比如醫學影象,其色度和亮度一樣很重要。包含字型的影象也會受到影響(見下圖),因為文字的不良子取樣會降低其易讀性。使用 JPEG 更難以壓縮銳利的邊緣,因為它旨在更好地處理具有更柔和過渡的攝影場景。
在 JPEG 規範中沒有指定色度子取樣的確切方法,因此不同的解碼器處理它的方式不同。
比如在 PS 中使用 'Save for web' 的時候就會自動進行色度取樣。當影象質量設定在 51-100 之間時,根本不使用子取樣(4:4:4)。 當質量低於此值時,將使用 4:2:0 子取樣。 這是將質量從 51 切換到 50 時可以觀察到更大的檔案大小減少的一個原因。
現狀
我們現在經常做的就是為不同的瀏覽器提供不同格式的圖片!
這裡有一個新玩意兒的列表:
JPEG2000 (2000) 改進版 JPEG,瀏覽器支援:Safari desktop + iOS
JPEG XR (2009) 支援 HDR 和寬色域空間的 JPEG 和 JPEG 2000 的替代品。 以稍慢的編碼/解碼速度生成比 JPEG 更小的檔案。 瀏覽器支援:Edge + IE。
WebP (2010) 谷歌釋出的基於塊預測的影象格式,支援有損和無失真壓縮。 提供與 JPEG 相關的位元組節省,支援透明度。缺乏色度子取樣配置和漸進載入。解碼時間也比 JPEG 慢。 瀏覽器支援:Chrome + Opera。Safari 和 Firefox 實驗性支援。
FLIF (2015) 聲稱優於上面提到的所有影象格式,瀏覽器支援:無。 請注意,有一個JS瀏覽器內解碼器。
BPG (2015) 由於許可問題而不太可能獲得廣泛的牽引力。 瀏覽器支援:無。 請注意,有一個JS瀏覽器內解碼器。
HEIF (2016) Apple 在 WWDC 上宣佈他們將探索在 iOS 上使用 JPEG 切換到 HEIF,理由是檔案大小可節省 2 倍。 瀏覽器支援:在撰寫本文時沒有。 最終,Safari 桌面和iOS 11 支援。
之所以提到這些不同的圖片格式,因為為不同的瀏覽器提供其支援的最優格式的圖片已經是一種常用的優化方式。
接下來,讓我們談談當您無法有條件地提供不同影象格式時的選項:優化 JPEG 編碼器。
優化 JPEG 編碼器
現代 JPEG 編碼器嘗試生成更小,更高保真度的 JPEG 檔案,同時保持與現有瀏覽器和影象處理應用程式的相容性。它們避免了在生態系統中引入新影象格式或變化的需要,以便實現壓縮增益。這樣的兩個編碼就是 MozJPEG 和 Guetzli。
如何選擇合適的編碼器:
1. 一般網路資源使用 MozJPEG
2. 重視質量,不在乎編碼時間的話選擇 Guetzli
複製程式碼
如果需要可配置的話:
- JPEGRecompress
- jpegmini 它與Guetzli類似 - 自動選擇最佳質量。 它不像Guetzli那樣技術複雜,但速度更快,目標是更適合網路的質量範圍。
- ImageOptim API 在顏色處理上獨一無二!
關於 MozJPEG
Mozilla 的親兒子,號稱可以減少 10% 的 JPEG 檔案體積。其一些特性比如逐行掃描優化、網格量化等可以利用建立高 DPI 的影象。
const gulp = require('gulp');
const imagemin = require('gulp-imagemin');
const imageminMozjpeg = require('imagemin-mozjpeg');
gulp.task('mozjpeg', () =>
gulp.src('src/*.jpg')
.pipe(imagemin([imageminMozjpeg({
quality: 85
})]))
.pipe(gulp.dest('dist'))
);
複製程式碼
可以看到還是有效的減少了檔案體積。
SSIM 是一種用於測量兩個影象之間的相似性的方法,其中 SSIM 得分是一個影象的質量度量,假定目標影象(被比較的)是“完美的”。
根據我的經驗,MozJPEG 是以高視覺質量壓縮網路影象同時減少檔案大小的一個很好的選擇。對於中小尺寸的影象,我發現 MozJPEG(質量= 80-85)可以節省 30-40% 的檔案大小,同時保持可接受的 SSIM。 它的編碼成本比基線 JPEG 慢,但這不是你拒絕他的理由。
關於 Guetzli
const gulp = require('gulp');
const imagemin = require('gulp-imagemin');
const imageminGuetzli = require('imagemin-guetzli');
gulp.task('guetzli', () =>
gulp.src('src/*.jpg')
.pipe(imagemin([
imageminGuetzli({
quality: 85
})
]))
.pipe(gulp.dest('dist'))
);
複製程式碼
同樣帶來顯著的體積優化效果