canvas系列教程03 —— 线的样式、绘制文本、操作图片(图片的渲染、缩放、裁剪、切割、平铺、特效)、变换元素(平移、缩放、旋转)(一):https://developer.aliyun.com/article/1558608
调整亮度(变亮变暗)
实现算法:
将红、绿、蓝三个通道值,分别同时加上一个正值或负值。
var image = new Image(); image.src = "images/princess.png"; image.onload = function () { cxt.drawImage(image, 10, 10); var imgData = cxt.getImageData(10, 10, 120, 120); var data = imgData.data; //遍历每个像素 for (var i = 0; i < data.length; i += 4) { var a = 50; data[i + 0] += a; data[i + 1] += a; data[i + 2] += a; } //在指定位置输出图片 cxt.putImageData(imgData, 140, 10); }
a = 50 变亮的效果:
a = -50 变暗的效果:
调整透明度
cxt.globalAlpha用于调整整个Canvas的透明度,这里只是希望将图片透明化
实现算法:
将每一个像素的透明度乘以n,n的取值范围为0.0~1.0
var image = new Image(); image.src = "images/princess.png"; image.onload = function () { cxt.drawImage(image, 10, 10); var imgData = cxt.getImageData(10, 10, 120, 120); var data = imgData.data; //遍历每个像素 for (var i = 0; i < data.length; i += 4) { data[i + 3] = data[i + 3] * 0.3; } //在指定位置输出图片 cxt.putImageData(imgData, 140, 10); }
颜色反转(底片)
即图片颜色颠倒,效果类似相机的底片。
实现算法:
红、绿、蓝这三个通道的像素取各自的相反值,也就是(255-原值)
var image = new Image(); image.src = "images/princess.png"; image.onload = function () { cxt.drawImage(image, 10, 10); var imgData = cxt.getImageData(10, 10, 120, 120); var data = imgData.data; //遍历每个像素 for (var i = 0; i < data.length; i += 4) { data[i + 0] = 255 - data[i + 0]; data[i + 1] = 255 - data[i + 1]; data[i + 2] = 255 - data[i + 2]; } //在指定位置输出图片 cxt.putImageData(imgData, 140, 10); }
黑白效果(灰度图)
指将彩色图片转换成黑白图片。
实现算法:
首先取红、绿、蓝三个通道的平均值,也就是(data[i+0]+data[i+1]+data[i+2])/3。然后data[i+0]、data[i+1]和data[i+2]全部保存为这个平均值。
var image = new Image(); image.src = "images/princess.png"; image.onload = function () { cxt.drawImage(image, 10, 10); var imgData = cxt.getImageData(10, 10, 120, 120); var data = imgData.data; //遍历每个像素 for (var i = 0; i < data.length; i += 4) { var average = (data[i + 0] + data[i + 1] + data[i + 2] + data[i + 3]) / 3; data[i + 0] = average; //红 data[i + 1] = average; //绿 data[i + 2] = average; //蓝 } //在指定位置输出图片 cxt.putImageData(imgData, 140, 10); }
效果优化——加权平均
var image = new Image(); image.src = "images/princess.png"; image.onload = function () { cxt.drawImage(image, 10, 10); var imgData = cxt.getImageData(10, 10, 120, 120); var data = imgData.data; //遍历每个像素 for (var i = 0; i < data.length; i += 4) { var grayscale = data[i] * 0.3 + data[i + 1] * 0.6 + data[i + 2] * 0.1; data[i + 0] = grayscale; //红 data[i + 1] = grayscale; //绿 data[i + 2] = grayscale; //蓝 } //在指定位置输出图片 cxt.putImageData(imgData, 140, 10); }
复古
使得图片有一种古旧效果。
实现算法:
将红、绿、蓝三个通道,分别取这三个值的某种加权平均值。
var image = new Image(); image.src = "images/princess.png"; image.onload = function () { cxt.drawImage(image, 10, 10); var imgData = cxt.getImageData(10, 10, 120, 120); var data = imgData.data; //遍历每个像素 for (var i = 0; i < data.length; i += 4) { var r = data[i + 0]; var g = data[i + 1]; var b = data[i + 2]; data[i + 0] = r * 0.39 + g * 0.76 + b * 0.18; data[i + 1] = r * 0.35 + g * 0.68 + b * 0.16; data[i + 2] = r * 0.27 + g * 0.53 + b * 0.13; } //在指定位置输出图片 cxt.putImageData(imgData, 140, 10); }
红色蒙版
让图片呈现一种偏红的效果
实现算法:
将红通道(r)赋值为红、绿、蓝这三个的平均值,并且将绿通道、蓝通道都赋值为0。
同样的方式可以实现类似效果的绿色蒙版、蓝色蒙版等。
var image = new Image(); image.src = "images/princess.png"; image.onload = function () { cxt.drawImage(image, 10, 10); var imgData = cxt.getImageData(10, 10, 120, 120); var data = imgData.data; //遍历每个像素 for (var i = 0; i < data.length; i += 4) { var r = data[i + 0]; var g = data[i + 1]; var b = data[i + 2]; var average = (r + g + b) / 3; data[i + 0] = average; data[i + 1] = 0; data[i + 2] = 0; } //在指定位置输出图片 cxt.putImageData(imgData, 140, 10); }
创建像素区域 createImageData()
cxt.createImageData(sw,sh); //第1种格式
sw,sh 为像素区域的宽和高
cxt.createImageData(imageData); //第2种格式
imageData为一个像素对象,最终像素区域的宽高和这个像素对象相同
createImageData()和putImageData()配合使用是对一个区域进行像素操作的。只有使用createImageData()创建了一个区域,才可以对该区域进行相应的像素操作。
var imgData = cxt.createImageData(100, 100); var data = imgData.data; for (var i = 0; i < 100 * 100 * 4; i += 4) { data[i + 0] = 0; data[i + 1] = 0; data[i + 2] = 255; data[i + 3] = 255; } cxt.putImageData(imgData, 20, 20);
var image = new Image(); image.src = "images/princess.png"; image.onload = function () { cxt.drawImage(image, 0, 0, 60, 60); //获取一个图片的imgData var imgData1 = cxt.getImageData(0, 0, 60, 60); //利用这个图片的imgData作为参数 var imgData2 = cxt.createImageData(imgData1); var data = imgData2.data; for (var i = 0; i < imgData2.width * imgData2.height * 4; i += 4) { data[i + 0] = 0; data[i + 1] = 0; data[i + 2] = 255; data[i + 3] = 255; } cxt.putImageData(imgData2, 80, 0); }
变换元素
变换可用于图形,也可以用于图片和文字。
变换的本质都是通过“变换矩阵transform()”实现的,涉及到线性代数,平时并不会用,不必深究,简单了解即可:
- translate(e,f)等价于transform(1,0,0,1,e,f)。
- scale(a,d)等价于transform(a,0,0,d,0,0)。
- rotate(θ)等价于transform(cosθ,sinθ,-sinθ,cosθ,0,0)。
setTransform() 与 transform() 用法相同,只是transform() 是在变换后的基础上继续变换,而setTransform() 会重置图形的状态,再进行变换。
var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); cxt.fillStyle = "yellow"; cxt.fillRect(0, 0, 100, 50) cxt.setTransform(1, 0.5, -0.5, 1, 30, 10); cxt.fillStyle = "red"; cxt.fillRect(0, 0, 100, 50); cxt.setTransform(1, 0.5, -0.5, 1, 30, 10); cxt.fillStyle = "blue"; cxt.fillRect(0, 0, 100, 50);
将 setTransform 改为 transform 后效果为
平移 translate()
本质是移动了整个坐标轴
cxt.translate(x,y);
- x 为x轴方向的移动距离,单位px,为正,则是向右移动,为负,则向左移动
- y 为y轴方向的移动距离,单位px,为正,则是向下移动,为负,则向上移动
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); //绘制初始图形 cxt.fillStyle = "HotPink"; cxt.fillRect(30, 30, 50, 50); $$("btn").onclick = function () { // 清空canvas cxt.clearRect(0, 0, cnv.width, cnv.height); cxt.translate(10, 10); cxt.fillStyle = "HotPink"; // 重绘 cxt.fillRect(30, 30, 50, 50); } } </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border:1px dashed gray;"></canvas><br /> <input id="btn" type="button" value="移动"/> </body> </html>
缩放 scale ()
cxt.scale(x,y);
- x 为x轴方向的缩放倍数
- y 为y轴方向的缩放倍数
- x,y 的值为0~1时为缩小,大于1时为放大,也可以为负,但基本不用。
使用 scale 缩放时,图形的左上角坐标、宽度和高度、线条宽度都会同步缩放,若不是预期效果,记得进行相应的处理!
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> <meta charset="utf-8" /> <script type="text/javascript"> function $$(id) { return document.getElementById(id); } window.onload = function () { var cnv = $$("canvas"); var cxt = cnv.getContext("2d"); //绘制初始图形 cxt.fillStyle = "HotPink"; cxt.fillRect(30, 30, 50, 50); //图形放大 $$("btn-big").onclick = function () { // 清空canvas cxt.clearRect(0, 0, cnv.width, cnv.height); cxt.scale(1.5, 1.5); cxt.fillStyle = "HotPink"; // 添加平移,抵消左上角坐标的放大 cxt.translate(-10, -10); cxt.fillRect(30, 30, 50, 50); }; //图形缩小 $$("btn-small").onclick = function () { // 清空canvas cxt.clearRect(0, 0, cnv.width, cnv.height); cxt.scale(0.5, 0.5); cxt.fillStyle = "HotPink"; // 反向平移,抵消左上角坐标的縮小 cxt.translate(30, 30); cxt.fillRect(30, 30, 50, 50); }; }; </script> </head> <body> <canvas id="canvas" width="200" height="150" style="border: 1px dashed gray" ></canvas ><br /> <input id="btn-big" type="button" value="放大" /> <input id="btn-small" type="button" value="缩小" /> </body> </html>
旋转 rotate()
cxt.rotate(angle);
- angle 为图形旋转的角度,取值为-Math.PI2~Math.PI2。当angle>0时,图形顺时针旋转;当angel<0时,图形逆时针旋转。
120*Math.PI/180 //120° 150*Math.PI/180 //150°
默认情况下,rotate()方法的旋转中心就是原点坐标(0,0)
cxt.fillStyle = "HotPink"; cxt.fillRect(30, 30, 50, 50); $$("btn").onclick = function () { cxt.rotate(-30 * Math.PI / 180); //逆时针旋转30° cxt.fillStyle = "LightSkyBlue "; cxt.fillRect(30, 30, 50, 50); //注意,这里仍然是fillRect(30, 30, 50, 50) }
改变旋转中心
先使用translate(x,y),然后再使用rotate()方法
var i = 0; var rectWidth = 100; var rectHeight = 50; setInterval(function () { i++; cxt.clearRect(0, 0, cnv.width, cnv.height); cxt.save(); cxt.translate(cnv.width / 2, cnv.height / 2); //将坐标移动到中心 cxt.rotate(Math.PI * (i / 100)); //累进旋转 cxt.fillStyle = "HotPink"; cxt.fillRect(-rectWidth / 2, -rectHeight / 2, rectWidth, rectHeight); //填充矩形 cxt.restore(); }, 10);
使用translate()方法结合图形的长宽将旋转中心移动到图形中心上。
本例中,将矩形的中心与画布的中心重合,是为了方便操作。
实战范例 1 —— 内卷花纹
cxt.translate(150, 0); cxt.fillStyle = "rgba(255,0,0,0.25)"; for (var i = 0; i < 50; i++) { cxt.translate(25, 25); //图形平移 cxt.scale(0.95, 0.95); //图形缩放 cxt.rotate(Math.PI / 10); //图形旋转 cxt.fillRect(0, 0, 100, 50); }
实战范例 2 —— 彩虹
//定义数组,存储7种颜色 var colors = ["red", "orange", "yellow", "green", "blue", "navy", "purple"]; cxt.lineWidth = 12; cxt.translate(50,0); //循环绘制圆弧 for (var i = 0; i < colors.length; i++) { //每次向下移动10px cxt. translate(0,10); //定义颜色 cxt.strokeStyle = colors[i]; //绘制圆弧 cxt.beginPath(); cxt.arc(50, 100, 100, 0, 180 * Math.PI / 180, true); cxt.stroke(); } ```![在这里插入图片描述](https://ucc.alicdn.com/images/user-upload-01/00258c688cd24e07be5544a4429c24be.png)