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


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

為什么模糊

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

在高清屏之前,屏幕上顯示一個像素點需要 1 x 1 個 css 像素。在高清屏,同樣大小的屏幕上要顯示一個點,就需要 n x 1 個 css 像素。這里的 n 就是設備像素比 devicePixelRatio >= 2.

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

比如說 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 = canvas.width * scale
  canvas.height = canvas.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),亦稱為點陣圖像或繪制圖像,是由稱作像素(圖片元素)的單個點組成的。當放大位圖時,圖像就失真、模糊了。

引用


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM