canvas 顯示模糊問題

引子

近期的工做中,是繼 canvas 寬高問題 以後碰到的第二個問題。javascript

顯示模糊問題

在 PC 瀏覽器上顯示時,沒有發現明顯的模糊,還能夠接受。但在手機上就會有明顯的模糊。這是示例,掃描訪問二維碼以下。css

18-qrcode-canvas-image

示例中,用 css 控制 canvas 的寬高,裏面的圖片展現效果不一致。查詢資料,在 stackoverflow 中發現一樣的問題,經過實際測試發現:html

  • canvas 元素自身的屬性 widthheight,決定了多少像素能夠顯示在畫布上,若是不設置,width 默認值是 300,height 默認值是 150。
  • css 的屬性 widthheight,是指在屏幕上元素顯示的大小,若是沒有對 canvas 進行 css 設置,則會採用 canvas 的默認大小。
  • 若是設置了 css 屬性 widthheight,當在畫布裏面使用 drawImage 設置圖片寬高時,顯示的寬高值會根據必定比例進行轉換。例如在上面例子中,設置的圖片是寬 300 高 90, canvas 默認寬高渲染像素 300 和 150,(css 高度/canvas 自身屬性高度) * drawImage 設置的高度 = (90/150)* 90 = 54。

規範裏面還真沒看出來這些。html5

緣由

在 stackoverflow 上也找到相關的問題,在回答中有相關介紹的文章HTML5 Rocks。緣由是 canvas 繪製時獨立於設備像素比(devicePixelRatio)。受到 devicePixelRatio 影響,在高清顯示屏上,一個邏輯像素對應多個實際的設備物理像素。例如在 devicePixelRatio 爲 2 的設備上,css 設置的 100px,意味着設備上要填充 200px 物理像素,那麼當 canvas 繪製 100px 的區域時,實際是想在設備填充 100px 物理像素,但因爲 devicePixelRatio 的做用,設備要求顯示 200px 的物理像素,瀏覽器就智能的填充了像素之間的空格,以便以適當的大小顯示元素。java

在 Safari6 中支持一個屬性 backingStorePixelRatio,該屬性決定了瀏覽器在渲染 canvas 會用幾個像素來繪製畫布的信息。有些相似於 devicePixelRatio。Safari6 的值爲 2,因此在 Safari6 中 canvas 不會模糊,但後來去掉了,如今瀏覽器不支持這個屬性,具體見 Issue 277205git

解決方法

解決的思路就是經過檢測設備像素比,繪製對應倍數比例的 canvas 元素。方法以下:github

function createHDCanvas (w=300,h=150) {
  var ratio = window.devicePixelRatio || 1;
  var canvas = document.createElement('canvas');
  canvas.width = w * ratio; // 實際渲染像素
  canvas.height = h * ratio; // 實際渲染像素
  canvas.style.width = `${w}px`; // 控制顯示大小
  canvas.style.height = `${h}px`; // 控制顯示大小
  canvas.getContext('2d').setTransform(ratio, 0, 0, ratio, 0, 0);
  return canvas;
}
複製代碼

這是對比示例,掃描訪問二維碼以下。canvas

18-qrcode-canvas-image-hd

參考資料

相關文章
相關標籤/搜索