1. 개요
Canvas API(캔버스)는 웹 페이지에서 실시간으로 이미지를 생성하는 데 사용되며, 기본적으로 JavaScript로 조작할 수 있는 비트맵입니다. 이를 사용하기 전에 먼저 새로운
<canvas id="myCanvas" width="400" height="200"> 您的浏览器不支持canvas!</canvas>
위 코드에서 브라우저가 이 API를 지원하지 않으면
각 캔버스 노드에는 해당 컨텍스트 개체(컨텍스트 개체)가 있습니다. Canvas API는 이 컨텍스트 개체에 정의되므로 getContext 메서드를 사용하여 이 개체를 가져와야 합니다.
var canvas = document.getElementById('myCanvas'); if (canvas.getContext) { var ctx = canvas.getContext('2d'); }
위 코드에서 getContext 메소드는 매개변수 2d를 지정합니다. 이는 캔버스 노드가 2D 패턴(예: 플랫 패턴)을 생성하는 데 사용된다는 의미입니다. 매개변수가 webgl이면 3D 이미지(즉, 3차원 패턴)를 생성하는 데 사용된다는 의미입니다. 이 부분은 실제로는 WebGL API만 호출합니다.
2. 그리기 방법
캔버스 캔버스는 그림을 그릴 수 있는 평면적인 공간을 제공합니다. 공간의 각 점은 가로 좌표를 나타내고 y는 세로 좌표를 나타냅니다. 원점(0, 0)은 이미지의 왼쪽 상단에 위치합니다. x축의 양의 방향은 원점의 오른쪽이고, y축의 양의 방향은 원점에서 아래쪽입니다.
(1) 경로 그리기
beginPath 메소드는 경로 그리기 시작을 나타내고, moveTo(x, y) 메소드는 선분의 시작점을 설정하고, lineTo(x, y) 메소드는 선분의 끝점을 설정합니다. 획 방법 투명한 선분을 색칠하는데 사용됩니다.
ctx.beginPath(); // 开始路径绘制 ctx.moveTo(20, 20); // 设置路径起点,坐标为(20,20) ctx.lineTo(200, 20); // 绘制一条到(200,20)的直线 ctx.lineWidth = 1.0; // 设置线宽 ctx.strokeStyle = '#CC0000'; // 设置线的颜色 ctx.stroke(); // 进行线的着色,这时整条线才变得可见
moveto 및 lineto 메소드는 여러 번 사용할 수 있습니다. 마지막으로 closePath 메소드를 사용하면 현재 점에서 시작점까지 자동으로 직선을 그려 닫힌 도형을 형성할 수 있으므로 lineto 메소드를 한 번 사용할 필요가 없습니다.
(2) 직사각형 그리기
fillRect(x, y, width, height) 메소드는 4개의 매개변수로 왼쪽 상단의 x 좌표와 y 좌표를 사용합니다. 직사각형의 모서리 꼭지점, 직사각형의 너비 및 높이. fillStyle 속성은 사각형의 채우기 색상을 설정하는 데 사용됩니다.
ctx.fillStyle = 'yellow'; ctx.fillRect(50, 50, 200, 100);
StrokeRect 메소드는 속이 빈 직사각형을 그리는 데 사용되는 fillRect와 유사합니다.
ctx.strokeRect(10,10,200,100);
clearRect 메소드는 직사각형 영역의 내용을 지우는 데 사용됩니다.
ctx.clearRect(100,50,50,50);
(3) 텍스트 그리기
fillText(string, x, y)는 텍스트 내용, 시작점의 x 좌표, 그리고 y 좌표. 사용하기 전에 글꼴을 사용하여 글꼴, 크기, 스타일을 설정해야 합니다(작성 방법은 CSS의 글꼴 속성과 유사합니다). 이와 유사하게 속이 빈 단어를 추가하는 데 사용되는 스트로크텍스트 메서드가 있습니다.
ctx.font = "Bold 20px Arial"; // 设置字体 ctx.textAlign = "left";// 设置对齐方式 ctx.fillStyle = "#008600"; // 设置填充颜色 ctx.fillText("Hello!", 10, 50); // 设置字体内容,以及在画布上的位置 ctx.strokeText("Hello!", 10, 100); // 绘制空心字
fillText 메소드는 텍스트 줄 바꿈을 지원하지 않습니다. 즉, 모든 텍스트가 한 줄에 표시됩니다. 따라서 여러 줄의 텍스트를 생성하려면 fillText 메서드를 여러 번만 호출하면 됩니다.
(4) 원과 섹터 그리기
원호 방식을 사용하여 섹터를 그립니다.
ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise);
arc 메서드의 x 및 y 매개변수는 원 중심의 좌표이고, radius는 반경, startAngle 및 endAngle은 섹터의 시작 각도와 끝 각도입니다(라디안으로 표시). ), 시계 반대 방향은 그림을 반대로 그려야 함을 의미합니다. 시계 방향(true)으로 그릴지 시계 방향(false)으로 그릴지 여부입니다.
속이 빈 원을 그리는 방법은 다음과 같습니다.
ctx.beginPath(); ctx.arc(60, 60, 50, 0, Math.PI*2, true); ctx.fillStyle = "#000000"; ctx.fill();
속이 빈 원을 그리는 예:
ctx.beginPath(); ctx.arc(60, 60, 50, 0, Math.PI*2, true); ctx.lineWidth = 1.0; ctx.strokeStyle = "#000"; ctx.stroke();
(5) 그라데이션 색상을 설정합니다
그라디언트 색상을 설정하려면 createLinearGradient 메소드를 사용합니다.
var myGradient = ctx.createLinearGradient(0, 0, 0, 160); myGradient.addColorStop(0, "#BABABA"); myGradient.addColorStop(1, "#636363");
createLinearGradient 메소드의 매개변수는 (x1, y1, x2, y2)입니다. 여기서 x1과 y1은 시작점 좌표이고 x2와 y2는 끝점 좌표입니다. 다양한 좌표값을 통해 위에서 아래로, 왼쪽에서 오른쪽으로 등의 그라데이션을 생성할 수 있습니다. 사용방법은 다음과 같습니다.
ctx.fillStyle = myGradient; ctx.fillRect(10,10,200,100);
(6) 그림자 설정
그림자 관련 일련의 방법을 사용하여 그림자를 설정할 수 있습니다.
ctx.shadowOffsetX = 10; // 设置水平位移 ctx.shadowOffsetY = 10; // 设置垂直位移 ctx.shadowBlur = 5; // 设置模糊度 ctx.shadowColor = "rgba(0,0,0,0.5)"; // 设置阴影颜色 ctx.fillStyle = "#CC0000"; ctx.fillRect(10,10,200,100);
3. 이미지 처리 방법
drawImage 메서드
Canvas API를 사용하면 이미지 파일을 캔버스에 삽입하고 drawImage 메서드를 사용할 수 있습니다. 캔버스에서 다시 그리기를 수행합니다.
var img = new Image(); img.src = 'image.png'; ctx.drawImage(img, 0, 0); // 设置对应的图像对象,以及它在画布上的位置
위 코드는 PNG 이미지를 캔버스에 로드합니다. drawImage() 메소드는 세 개의 매개변수를 허용합니다. 첫 번째 매개변수는 이미지 파일의 DOM 요소(예: 노드)입니다. 두 번째 및 세 번째 매개변수는 캔버스에 있는 이미지의 왼쪽 상단 모서리의 좌표입니다. 위의 예 (0, 0)은 이미지의 왼쪽 위 모서리를 캔버스의 왼쪽 위 모서리에 배치하는 것을 의미합니다.
이미지 로딩에 시간이 걸리기 때문에 이미지 로딩이 완료된 후에만 drawImage 메소드를 호출할 수 있으므로 위의 코드를 다시 작성해야 합니다.
var image = new Image(); image.onload = function() { var canvas = document.createElement('canvas'); canvas.width = image.width; canvas.height = image.height; canvas.getContext('2d').drawImage(image, 0, 0); // 插入页面底部 document.body.appendChild(image); return canvas; } image.src = 'image.png';
getImageData 메소드, putImageData 메소드
getImageData 메소드는 Canvas의 내용을 읽고 각 픽셀에 대한 정보가 포함된 객체를 반환하는 데 사용할 수 있습니다.
var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
imageData 객체는 data 속성을 가지며, 그 값은 1차원 배열입니다. 이 배열의 값은 순서대로 각 픽셀의 빨강, 녹색, 파랑, 알파 채널 값이므로 배열의 길이는 이미지의 픽셀 너비 x 이미지의 픽셀 높이 x 4와 같고, 각 값의 범위는 0~255입니다. 이 배열은 읽기만 가능한 것이 아니라 쓰기도 가능하므로 이 배열의 값을 조작함으로써 이미지 조작 목적을 달성할 수 있습니다. 이 배열을 수정한 후 putImageData 메서드를 사용하여 캔버스에 배열 내용을 다시 그립니다.
context.putImageData(imageData, 0, 0);
toDataURL 메소드
이미지 데이터를 수정한 후 toDataURL 메소드를 사용하면 Canvas 데이터를 일반 이미지 파일 형식으로 다시 변환할 수 있습니다.
function convertCanvasToImage(canvas) { var image = new Image(); image.src = canvas.toDataURL('image/png'); return image; }
위 코드는 Canvas 데이터를 PNG 데이터 URI로 변환합니다.
저장 방법, 복원 방법
save 방법은 컨텍스트를 저장하는 데 사용되며, 복원 방법은 마지막으로 저장된 컨텍스트를 복원하는 데 사용됩니다.
ctx.save(); ctx.shadowOffsetX = 10; ctx.shadowOffsetY = 10; ctx.shadowBlur = 5; ctx.shadowColor = 'rgba(0,0,0,0.5)'; ctx.fillStyle = '#CC0000'; ctx.fillRect(10,10,150,100); ctx.restore(); ctx.fillStyle = '#000000'; ctx.fillRect(180,10,150,100);
上面代码先用save方法,保存了当前设置,然后绘制了一个有阴影的矩形。接着,使用restore方法,恢复了保存前的设置,绘制了一个没有阴影的矩形。
4.动画
利用JavaScript,可以在canvas元素上很容易地产生动画效果。
var posX = 20, posY = 100; setInterval(function() { context.fillStyle = "black"; context.fillRect(0,0,canvas.width, canvas.height); posX += 1; posY += 0.25; context.beginPath(); context.fillStyle = "white"; context.arc(posX, posY, 10, 0, Math.PI*2, true); context.closePath(); context.fill(); }, 30);
上面代码会产生一个小圆点,每隔30毫秒就向右下方移动的效果。setInterval函数的一开始,之所以要将画布重新渲染黑色底色,是为了抹去上一步的小圆点。
通过设置圆心坐标,可以产生各种运动轨迹。
先上升后下降。
var vx = 10, vy = -10, gravity = 1; setInterval(function() { posX += vx; posY += vy; vy += gravity; // ... });
上面代码中,x坐标始终增大,表示持续向右运动。y坐标先变小,然后在重力作用下,不断增大,表示先上升后下降。小球不断反弹后,逐步趋于静止。
var vx = 10, vy = -10, gravity = 1; setInterval(function() { posX += vx; posY += vy; if (posY > canvas.height * 0.75) { vy *= -0.6; vx *= 0.75; posY = canvas.height * 0.75; } vy += gravity; // ... });
上面代码表示,一旦小球的y坐标处于屏幕下方75%的位置,向x轴移动的速度变为原来的75%,而向y轴反弹上一次反弹高度的40%。
5.像素处理
通过getImageData方法和putImageData方法,可以处理每个像素,进而操作图像内容。假定filter是一个处理像素的函数,那么整个对Canvas的处理流程,可以用下面的代码表示。
if (canvas.width > 0 && canvas.height > 0) { var imageData = context.getImageData(0, 0, canvas.width, canvas.height); filter(imageData); context.putImageData(imageData, 0, 0); }
以下是几种常见的处理方法:
灰度效果
灰度图(grayscale)就是取红、绿、蓝三个像素值的算术平均值,这实际上将图像转成了黑白形式。假定d[i]是像素数组中一个象素的红色值,则d[i+1]为绿色值,d[i+2]为蓝色值,d[i+3]就是alpha通道值。转成灰度的算法,就是将红、绿、蓝三个值相加后除以3,再将结果写回数组。
grayscale = function (pixels) { var d = pixels.data; for (var i = 0; i < d.length; i += 4) { var r = d[i]; var g = d[i + 1]; var b = d[i + 2]; d[i] = d[i + 1] = d[i + 2] = (r+g+b)/3; } return pixels; };
复古效果
复古效果(sepia)则是将红、绿、蓝三个像素,分别取这三个值的某种加权平均值,使得图像有一种古旧的效果。
sepia = function (pixels) { var d = pixels.data; for (var i = 0; i < d.length; i += 4) { var r = d[i]; var g = d[i + 1]; var b = d[i + 2]; d[i] = (r * 0.393)+(g * 0.769)+(b * 0.189); // red d[i + 1] = (r * 0.349)+(g * 0.686)+(b * 0.168); // green d[i + 2] = (r * 0.272)+(g * 0.534)+(b * 0.131); // blue } return pixels; };
红色蒙版效果
红色蒙版指的是,让图像呈现一种偏红的效果。算法是将红色通道设为红、绿、蓝三个值的平均值,而将绿色通道和蓝色通道都设为0。
red = function (pixels) { var d = pixels.data; for (var i = 0; i < d.length; i += 4) { var r = d[i]; var g = d[i + 1]; var b = d[i + 2]; d[i] = (r+g+b)/3; // 红色通道取平均值 d[i + 1] = d[i + 2] = 0; // 绿色通道和蓝色通道都设为0 } return pixels; };
亮度效果
亮度效果(brightness)是指让图像变得更亮或更暗。算法将红色通道、绿色通道、蓝色通道,同时加上一个正值或负值。
brightness = function (pixels, delta) { var d = pixels.data; for (var i = 0; i < d.length; i += 4) { d[i] += delta; // red d[i + 1] += delta; // green d[i + 2] += delta; // blue } return pixels; };
反转效果
反转效果(invert)是指图片呈现一种色彩颠倒的效果。算法为红、绿、蓝通道都取各自的相反值(255-原值)。
invert = function (pixels) { var d = pixels.data; for (var i = 0; i < d.length; i += 4) { d[i] = 255 - d[i]; d[i+1] = 255 - d[i + 1]; d[i+2] = 255 - d[i + 2]; } return pixels; };