十一、图像数据与路径 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属性。