1. 程式人生 > >解決 canvas 繪圖在高清屏中的模糊問題

解決 canvas 繪圖在高清屏中的模糊問題

解決 canvas 繪圖在高清屏中的模糊問題

為什麼模糊

我們知道,CSS 畫素是一個抽象單位(1 px),瀏覽器根據某種規則將 css 畫素轉化為螢幕需要的實際畫素值。

在高清屏之前,螢幕上顯示一個畫素點需要 1 x 1 個 css 畫素。高清屏出現後,同樣大小的螢幕上要顯示一個點,就需要 n x 1 個 css 畫素。這裡的 n 就是裝置畫素比 devicePixelRatio >= 2.

也就是說,同樣大小的區域,高清屏需要更多的 css 畫素:css 畫素不夠,則會放大內容——變得模糊;css 畫素足夠,則會縮小內容——變得清晰。

比如說 iPhone 4s,它的 devicePixelRatio 為 2,假設螢幕上有塊區域大小為 100px x 100px,上面有張 100px x 100px大小的圖片,那麼這張圖片會被放大 2 倍後渲染到這塊區域,所以看起來就模糊了。

canvas 繪圖在高清屏中模糊

canvas 屬於點陣圖,繪製在它上面的文字、圖片、線條也屬於點陣圖,經放大後就失真、顯得模糊了。要解決這個問題,我們就需要 canvas 擁有更多的 css 畫素,即讓 canvas 足夠大。多大才夠呢?太大會不會浪費資源/效能?我們需要因地制宜,根據 devicePixelRatio 來決定畫布的大小。

function setupCanvas(canvas) {
  var dpr = window.devicePixelRatio || 1
  var rect = canvas.getBoundingClientRect()

  canvas.width = rect.width * dpr
  canvas.height = rect.height * dpr

  var ctx = canvas.getContext('2d')
  ctx.scale(dpr, dpr)

  return ctx
}

// 現在我們只需要根據 UI 設計圖繪製需要的內容
// 由於使用了 setupCanvas,繪製的內容在各種高清屏中表現清晰、一致
var ctx = setupCanvas(document.querySelector('.my-canvas'));
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(200, 200);
ctx.stroke();

在 setupCanvas 函式中,我們根據螢幕的 devicePixelRatio 對 canvas 畫布本身進行放大,然後使用 ctx.scale() 放大 canvas 單位,這樣在 ctx 上下文繪製的內容就會被放大,使得最後生成的圖片清晰的顯示在對應的螢幕上。

在實際工作中,我們還要兼顧不同大小不同解析度的螢幕。一般設計師會給我們寬度為 375px 的設計圖,這需要我們根據螢幕大小進行縮放:

function setupCanvas(canvas) {
  const UI_WIDTH = 375
  const DOC_WIDTH = document.documentElement.clientWidth
  const DPR = window.devicePixelRatio || 1
  let scale = (DPR * DOC_WIDTH / UI_WIDTH).toFIxed(2)
  let rect = canvas.getBoundingClientRect()

  canvas.width = rect.width * scale
  canvas.height = rect.height * scale

  let ctx = canvas.getContext('2d')
  ctx.scale(scale, scale)

  return ctx
}

術語

device pixel

裝置畫素(又稱物理畫素、螢幕畫素)是顯示屏的最小物理單元,是我們在螢幕上能看到的最小點。

device-independent pixel

裝置無關畫素(又稱密度無關畫素,DIP)是一個抽象單位,表示計算機中的一個虛擬點,由系統轉為一個裝置畫素點。

devicePixelRatio

裝置畫素比,它的值等於裝置畫素/裝置無關畫素,devicePixelRatio = DP/DIP

css pixel

css 畫素是瀏覽器使用的抽象單位,屬於裝置無關畫素(DIP)。我們看到的內容,是瀏覽器將 css 畫素轉化為裝置畫素後的結果。

向量圖

向量圖是根據幾何特性來繪製圖形,向量可以是一個點或一條線,向量圖只能靠軟體生成,檔案佔用內在空間較小,因為這種型別的影象檔案包含獨立的分離影象,可以自由無限制的重新組合。它的特點是放大後圖像不會失真。

點陣圖

點陣圖影象(bitmap),亦稱為點陣影象或繪製圖像,是由稱作畫素(圖片元素)的單個點組成的。當放大點陣圖時,影象就失真、模糊了。

引用