十一、圖像數據與路徑 Image Data and URL
11.1圖像數據 Image Data
爲了獲得畫布上矩形區域的每個像素的圖像數據,可以使用畫布上下文的getImageData()方法獲得圖像數據對象,然後從data屬性訪問像素數據。圖像數據中的每個像素包含四個分量,即紅色、綠色、藍色和alpha分量。使用圖像數據對象訪問像素數據有三種常用技術。
1、遍歷從左上角到右下角的所有像素迭代;
2、基於X、Y座標的像素數據提取;
3、迭代所有像素,同時跟蹤每個像素的X,Y座標;
注意:getImageData()方法需要將圖像託管在Web服務器上,該Web服務器與執行代碼的域相同。如果不滿足此條件,將拋出SECURITY_ERR異常。
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="400"></canvas>
<script>
function drawImage(imageObj) {
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageX = 69;
var imageY = 50;
var imageWidth = imageObj.width;
var imageHeight = imageObj.height;
context.drawImage(imageObj, imageX, imageY);
var imageData = context.getImageData(imageX, imageY,
imageWidth, imageHeight);
var data = imageData.data;
// iterate over all pixels
for(var i = 0, n = data.length; i < n; i += 4) {
var red = data[i];
var green = data[i + 1];
var blue = data[i + 2];
var alpha = data[i + 3];
}
// pick out pixel data from x, y coordinate
var x = 20;
var y = 20;
var red = data[((imageWidth * y) + x) * 4];
var green = data[((imageWidth * y) + x) * 4 + 1];
var blue = data[((imageWidth * y) + x) * 4 + 2];
var alpha = data[((imageWidth * y) + x) * 4 + 3];
// iterate over all pixels based on x and y coordinates
for(var y = 0; y < imageHeight; y++) {
// loop through each column
for(var x = 0; x < imageWidth; x++) {
var red = data[((imageWidth * y) + x) * 4];
var green = data[((imageWidth * y) + x) * 4 + 1];
var blue = data[((imageWidth * y) + x) * 4 + 2];
var alpha = data[((imageWidth * y) + x) * 4 + 3];
}
}
}
var imageObj = new Image();
imageObj.onload = function() {
drawImage(this);
};
imageObj.src = 'darth-vader.jpg';
</script>
</body>
</html>
以上代碼演示了載入圖片數據,並通過不同方式遍歷圖片的像素數據。注意數據中包含了4個分量數據,遍歷時要選擇正確的分量。
11.2反相色彩 Invert Image Colors
爲了用HTML5畫布對圖像的顏色反相,我們可以迭代圖像中的所有像素,並通過從最大顏色值255中減去每個分量來反轉紅色、綠色和藍色分量,即用原顏色值的補色值替換原值。接下來,可以使用putImageData()方法使用更新後的圖像數據重新繪製反轉圖像,該方法需要圖像數據陣列和位置。
注意:getImageData()方法需要將圖像託管在Web服務器上,該Web服務器與執行代碼的域相同。如果不滿足此條件,將拋出SECURITY_ERR異常。
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="400"></canvas>
<script>
function drawImage(imageObj) {
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 69;
var y = 50;
context.drawImage(imageObj, x, y);
var imageData = context.getImageData(x, y,
imageObj.width, imageObj.height);
var data = imageData.data;
for(var i = 0; i < data.length; i += 4) {
// red
data[i] = 255 - data[i];
// green
data[i + 1] = 255 - data[i + 1];
// blue
data[i + 2] = 255 - data[i + 2];
}
// overwrite original image
context.putImageData(imageData, x, y);
}
var imageObj = new Image();
imageObj.onload = function() {
drawImage(this);
};
imageObj.src = 'darth-vader.jpg';
</script>
</body>
</html>
以上代碼演示了在畫布上用反相顏色繪製一張圖片。
11.3灰度色彩 Grayscale Image Colors
爲了用HTML5畫布對圖像的顏色進行灰度化,我們可以迭代圖像中的所有像素,計算每個像素的亮度,然後將紅色、綠色和藍色分量設置爲等於亮度。
注意:getImageData()方法需要將圖像託管在Web服務器上,該Web服務器與執行代碼的域相同。如果不滿足此條件,將拋出SECURITY_ERR異常。
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="400"></canvas>
<script>
function drawImage(imageObj) {
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 69;
var y = 50;
context.drawImage(imageObj, x, y);
var imageData = context.getImageData(x, y,
imageObj.width, imageObj.height);
var data = imageData.data;
for(var i = 0; i < data.length; i += 4) {
var brightness = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2];
// red
data[i] = brightness;
// green
data[i + 1] = brightness;
// blue
data[i + 2] = brightness;
}
// overwrite original image
context.putImageData(imageData, x, y);
}
var imageObj = new Image();
imageObj.onload = function() {
drawImage(this);
};
imageObj.src = 'darth-vader.jpg';
</script>
</body>
</html>
以上代碼演示了在畫布上用灰度色彩繪製一張圖片。
譯者注:請注意代碼對亮度值brightness的計算方法。
11.4獲取圖像數據路徑 Get Image Data URL
爲了獲得畫布的圖像數據URL,可以使用畫布對象的toDataURL()方法,該方法將畫布繪圖轉換爲64位編碼的PNG URL。如果希望圖像數據URL爲jpeg格式,則可以將image/jpeg作爲toDataURL()方法中的第一個參數傳遞。如果希望控制jpeg圖像的圖像質量,可以將從0到1的數字作爲第二個參數傳遞給toDataURL()方法。
注意:toDataURL()方法要求繪製到畫布上的任何圖像都託管在具有與所執行代碼相同域的Web服務器上。如果未滿足此條件,則拋出SECURITY_ERR異常。
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<img id="myImg" src="" />
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// draw cloud
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
context.closePath();
context.lineWidth = 5;
context.fillStyle = '#8ED6FF';
context.fill();
context.strokeStyle = '#0000ff';
context.stroke();
// save canvas image as data url (png format by default)
var dataURL = canvas.toDataURL();
var img = document.getElementById('myImg');
img.setAttribute('src', dataURL);
</script>
</body>
</html>
以上代碼演示了在畫布上繪製圖形,然後將圖形轉換爲數據URL,並將數據URL設置到圖片元素的過程。
11.5載入圖像數據路徑 Load Image Data URL
要用圖像數據URL加載畫布,可以通過調用AJAX以獲取數據URL,使用URL創建圖像對象,然後使用畫布上下文的drawImage()方法將圖像繪製到畫布上。
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"></canvas>
<script>
function loadCanvas(dataURL) {
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// load image from data url
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(this, 0, 0);
};
imageObj.src = dataURL;
}
// make ajax call to get image data url
var request = new XMLHttpRequest();
request.open('GET', 'dataURL.txt', true);
request.onreadystatechange = function() {
// Makes sure the document is ready to parse.
if(request.readyState == 4) {
// Makes sure it's found the file.
if(request.status == 200) {
loadCanvas(request.responseText);
}
}
};
request.send(null);
</script>
</body>
</html>
以上代碼演示了通過AJAX載入圖像數據路徑,並將其設置到一個臨時Image對象的src屬性,然後將該Image繪製到畫布上。
11.6保存繪製內容爲圖片 Save Drawing as an Image
爲了將畫布畫保存爲圖像,我們可以將Image對象的src屬性設置爲圖像數據URL。用戶可以右鍵單擊圖像以將其保存到本地計算機。另外,還可以直接打開一個帶有圖像數據URL的瀏覽器窗口,用戶可以從那裏保存這張圖片。
注意:toDataURL()方法要求繪製到畫布上的任何圖像都託管在具有與執行它的代碼相同的域的Web服務器上。如果未滿足此條件,則拋出SECURITY_ERR異常。
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="200"
style="display:none;"></canvas>
<img id="canvasImg" alt="Right click to save me!">
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// draw cloud
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.bezierCurveTo(430, 40, 370, 30, 340, 50);
context.bezierCurveTo(320, 5, 250, 20, 250, 50);
context.bezierCurveTo(200, 5, 150, 20, 170, 80);
context.closePath();
context.lineWidth = 5;
context.fillStyle = '#8ED6FF';
context.fill();
context.strokeStyle = '#0000ff';
context.stroke();
// save canvas image as data url (png format by default)
var dataURL = canvas.toDataURL();
// set canvasImg image src to dataURL
// so it can be saved as an image
document.getElementById('canvasImg').src = dataURL;
</script>
</body>
</html>
以上代碼演示了將畫布上繪製的內容轉換爲數據路徑,並將該數據路徑設置到Image元素的src屬性。