題目描述
一個 100 * 100 Canvas 佔用內存多大,它的大小的決定因素是什麼?這裏我們只考慮存儲這麼多像素的內存,不考慮運算過程中使用的內存。
感性認識
我們知道 Canvas 給了我們前端像素級別控制的能力,我們可以精確到像素,因此多了 更多的靈活性和複雜度。可以說 Canvas 的模型和傳統的 DOM 模型有很大的不同。
那麼要回答這個問題,我們其實只要知道 1 * 1 像素佔用多大內存就好了。
那麼 1 * 1 像素的 Canvas 佔用多大像素呢?我們來感性思考一下,我們現在前端在寫顏色的時候,
很多都是用RGBA或者#(六位十六進制)的形式
, 對於 RGBA 我們可以怎麼存儲?A 的話,我們平時的取值範圍 0 - 1 的小數,步長爲 0.01,因此 100 個數字就夠了,7Bit 就可以搞定。
那麼 RGB 呢?如果你用過 RGB 或者 RGBA 的話,應該知道我們通常使用的範圍是 0-255 的範圍, 因此 RGB 的存儲空間應該是 8*3 = 24 Bit,也就是 3Byte。
如果使用十六進制表示呢?一個十六進制需要 4 個 bit,那麼 6 個十六進制就是 24 個 bit,也就是 3Byte,和 RGBA 是一樣的。
因此一個像素的 Canvas 佔據空間理論上是 31Bit。那麼事實上是這樣麼?
什麼是 ImageData
回答這個問題之前,我先來介紹一個 Canvas 的 API getImageData
, 這個
方法會返回一個 ImageData,它用來描述"canvas"元素的一個隱含像素數據的區域。使用 ImageData() 構造函數創建或者使用和 canvas 在一起的 CanvasRenderingContext2D 對象的創建方法:createImageData() 和 getImageData()。我們這次就使用getImageData()
.
我們來實際測試一下
先說結果,結果是一個像素的 Canvas 佔內存是4Byte
。
我做了一個實驗,具體是怎麼做的呢?我們一起來看一下。
下面是我寫的一個HTML結構,裏面放了一個Canvas和一個button,點擊button會打印出來一個像素的信息。
這裏是代碼:
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="300" height="150">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = "rgba(200,2,2,0.8)";
ctx.fillRect(10, 10, 50, 50);
function getImageData() {
var imgData = ctx.getImageData(10, 10, 1, 1);
console.log(imgData);
return imgData;
}
</script>
<button onclick="getImageData()">獲取1像素信息</button>
</body>
</html>
這裏是渲染結果:
點擊之後,控制檯的顯示結果:
204 就是 255 * 0.8 算出來的
可以看出其實像素信息使用 Uint8 來存儲的,數組長度爲 4, Uint8 佔用內存爲 1 個字節,
因此一共是 4 個字節,所以答案就是一個像素的 Canvas 佔內存是4Byte
。這個和我們的猜測31Bit
相差了1Bit,其實多這1bit也是爲了方便操作。
這道題還沒有完~
RGB,RGBA 等等表示法有什麼本質區別
我們剛纔的推測以及實驗都是基於特定的顏色表示方法,比如 RGBA 或者#(六位十六進制)的形式,
如果我們採用別的方式呢?比如之前的 24 位,即 RGB 表示法。那結果就是100 * 100 *3
,
如果一個顏色不用一個字節,而是更多或者更少的字節呢?這些都會影響到結果。
因此上面我們的猜測以及“結論”都不確切,更確切地說佔用多少內存完全取決於你如何對像素進行編碼和解碼,只有掌握這個根本點,才能無往而不利。
總結
我們先從感性認識來“猜測”了一下問題的答案,然後通過 Canvas 的內置 API 實際地檢測了一下我們的猜想, 但是這個猜想似乎並不是很嚴謹,換句話說我們的猜想以及驗證結果是有一定的前提條件的。
其實答案不重要,重要的是你看到這種問題的思維過程,這種題目很容易看出一個人的知識廣度和深度, 甚至思維能力。本文完~