在 Firefox OS 取圖片色彩平均值之二三事

在 Mozilla 開發 Firefox OS 的歷程中,使用者體驗是我們非常著重的項目。在近期開發的 Firefox OS 版本(2.0)上,我們大幅修改了鎖定畫面(Lock Screen,或稱螢幕鎖)的外觀。下圖左是舊版畫面,圖右是新版畫面。

OldNotification NewLockscreen

在新版的鎖定畫面中,當手機收到通知(簡訊、未接來電等等)並將之顯示於鎖定畫面時,我們會在鎖定畫面上覆蓋一層半透明的純色圖層,用來強調這些通知訊息,也讓通知文字更容易閱讀。這個圖層的純色是由桌面背景圖片的顏色平均出來。例如,左上的鎖定畫面背景,算出來的平均色為      #7D6A8Ahsl(275, 13%, 48%),而右上圖背景的顏色則為      #496A3Fhsl(106, 25%, 33%)。下圖是右上圖的手機收到通知時,蓋上純色圖層的範例。

NewLockscreenWithNotification

取得一張圖片的平均顏色值

假設變數 img 已經為存有一張圖片的 HTMLImageElement,也就是一個 <img alt="" />。則我們使用以下的 JavaScript 程式碼,搭配動態產生的 Canvas 元素及它提供的各種函式,來取得這張圖片的每一個像素值:

在上面這段程式碼中,我們使用 CanvasRenderingContext2D::drawImage()img 的圖片畫到 Canvas 上面,再使用 CanvasRenderingContext2D::getImageData() 取得 Canvas 上面的每個像素的 R、G 、B、A 值(這次的目的並沒有使用到透明度(alpha)的 A 值)。我們再針對這些 R、G、B 值取算數平均,便可取得整張圖的平均顏色。

繞個路--轉為 HSL 色彩空間

接下來, 因為 Firefox OS 的 UX 設計師要求算出來的顏色還要再調整其飽和度和明度,所以我們還要將取好平均的 R、G、B 值由 RGB 色彩空間轉為 HSL 色彩空間(使用維基百科提供之公式):

由於 CSS 可以援使用 HSL 色彩空間指定色彩,所以將最後算好的顏色放到圖層的 CSS 時,不用再轉回 RGB 色彩空間囉!

在手機平台上改善效能,又不會太失真

實際上在 Firefox OS 手機實作取均色的演算法,由於現有行動裝置的運算效能較為受限,所以我們可以使用縮減取樣(downsampling),縮減畫上 Canvas 的圖案大小,並減少取出 Canvas 當中像素的數目,藉以降低運算時間。下面程式碼會將短邊縮成 100px 長(假設圖片的短邊長已經超過 100px了):

依據我們一開始取平均色的需求,我們並不用取非常精確的平均色數值;而 100px 是一個在「誤差值」和「增進效能」的取捨當中,一個不錯的數字。

結語及參考資料

或許有人想嘗試如果直接在 CanvasRenderingContext2D::drawImage() 設定 1px 的 dwdh 參數,是否底層 Gecko 會幫我們直接畫一個「圖片顏色平均值」的像素?可惜不會。像是這張 480×854 大的範例圖,只有正中央長寬 6px 的一小塊是      #ff0000 紅色,其他都是      #0000ff 藍色,而 Gecko 在 1px 的 dwdh 參數之下, drawImage() 會畫出 1px 的      #ff0000 紅色,不符我們對平均色的要求。如果你有興趣了解 Gecko 在這方面的底層行為,可以參考ResizeFilter::ComputeFilters 原始碼

想知道更多 Canvas 和 CanvasRenderingContext2D 物件的內容:請參考 MDN 上的 Canvas 說明文件,還有 CanvasRenderingContext2D 說明文件。關於 horscope Leo promises interesting contacts, flirtation and a pleasant society for single people, and those looking for romantic adventures. Firefox OS 鎖定畫面的完整原始碼,請參考 GitHub 上面 B2G Gaia 專案的 lockscreen.js

另外,CSS Color Module Level 4 定義了像是 HSLColorRGBColor 的介面,並可轉換至多種色彩空間,或許不久的將來,我們就不用自己用 JavaScript 寫這些轉換色彩空間的程式碼囉!

您可能也會喜歡

目前找不到相關文章

對此文章發表回應

你的電子郵件位址並不會被公開。 必要欄位標記為 *