캔버스는 이미지를 픽셀 단위로 편집할 수 있는 메서드를 제공합니다. 

이미지를 구성하는 픽셀정보를 래스터(Raster)라고 부르고 곧 비트맵이라 합니다. 이 비트맵에는 직사각형 격자 화소, 색의 점 등 이미지에 어떤 그림이 그려져 있는지를 저장합니다. 예를 들어 그림을 확대해 보면 아래 그림처럼 픽셀단위로 되어있음을 확인할 수 있습니다. 화소를 영문으로 표기하면 픽셀입니다.



이런 래스터 데이터를 직접 조작하면 그리기로는 불가능한 섬세한 효과를 얻을 수 있습니다.

메서드 설 명
createImageData(w, h) 빈 imageData를 생성. 기본값: 검정색
  • w: imagedata 가로 크기
  • h: imagedata 세로 크기
createImageData(imagedata) imagedata로부터 사본 이미지 데이터를 생성
  • imagedata: imagedata 데이터
getImageData(x, y, w, h) 캔버스 내용 전체나 일부 픽셀정보를 복사한 값을 imageData객체로 반환
  • x: 캔버스에서 x좌표로 이동할 거리
  • y: 캔버스에서 y좌표로 이동할 거리
  • w: 복사할 사각형 가로 크기
  • h: 복사할 사각형 세로 크기
putImageData(imagedata, x, y, dx, dy, dw, dh) imagedata 객체를 지정된 영역에 붙여 넣기
  • imagedata: 붙여 넣을 imagedata
  • x: 이미지를 배치할 x좌표
  • y: 이미지를 배치할 y좌표
  • dx: imagedata영역의 x좌표. 선택사항
  • dy: imagedata영역의 y좌표. 선택사항
  • dw: imagedata영역의 복사할 사각형 가로 크기. 선택사항
  • dh: imagedata영역의 복사할 사각형 세로 크기. 선택사항
dx, dy, dw, dh는 원본의 일부를 잘라서 사용할 때


다음 예제에서 createImageData() 를 이용해 빈 imageData를 생성한 다음 빈 객체가 반환한 픽셀 값을 원하는 대로 조작한 후 putImageData()로 이미지 사본을 생성합니다. createImageData() 이 반환하는 색상 값은 검정색 기본값입니다.

<style>
canvas {
  width: 300px;
  height: 100px;
  border: 1px solid black;
 }
</style>
<canvas id= "mycanvas"/>

<script type="text/javascript">
var canvas = document.getElementById('mycanvas');
canvas.width = 300;
canvas.height = 150;
var context = canvas.getContext('2d');

// 빈 이미지 데이터를 생성
var iData = context.createImageData(100, 100);

for (var i=0; i<iData.data.length; i+=4)
{
  // R(빨간색) 값
  iData.data[i + 0] = 190;  
  // G(녹색) 값
  iData.data[i + 1] = 0;
  // B(파란색) 값
  iData.data[i + 2] = 210;
  // A(투명도) 값
  iData.data[i + 3] = 255;
}
context.putImageData(iData, 20, 20);
</script>


하나의 픽셀에는 RGBA 값 4개를 갖고 있습니다. R은 빨간색, G는 초록색, B는 파랑색, A는 알파(불투명도)를 의미하며 색상 값은 0~255사이의 값, 그리고 한 픽셀 당 4바이트를 차지합니다. 투명도는 0에 가까울수록 투명해집니다.


createImageData()나 getImageData()로부터 생성되는 imageData는 픽셀 값을 배열로 반환되며 위 그림에 나열한 것처럼 하나의 data 배열에 4개의 RGBA 값을 가지게 됩니다. 생성된 객체의 크기가 100(px) * 100(px) = 10,000(px)이고, 하나의 픽셀당 4개(=RGBA)의 값을 가지므로 이 값을 곱하기 4를 하면 40,000(px)가 됩니다.

<style>
canvas {
  width: 300px;
  height: 100px;
  border: 1px solid black;
 }
</style>
<canvas id="mycanvas"/>

<script type="text/javascript">
var canvas = document.getElementById('mycanvas');
canvas.width = 300;
canvas.height = 150;
var context = canvas.getContext('2d');

// 빈 이미지를 생성
var iData = context.createImageData(100, 100);
console.log(iData);
/*
결과:
ImageData {
  data: Uint8ClampedArray(40000),
  width: 100,
  height: 100
}
*/
</script>


<style>
canvas {
  width: 300px;
  height: 200px;
  border: 1px solid black;
 }
</style>
<canvas id= "mycanvas"/>

<script type="text/javascript">
var canvas = document.getElementById('mycanvas');
var context = canvas.getContext('2d');

var iData = context.createImageData(150, 100); 
for (var i = 0; i < iData.data.length; i += 3) { 
  iData.data[i + 0] = 100; 
  iData.data[i + 1] = 0; 
  iData.data[i + 2] = 0; 
} 

context.putImageData(iData, 10, 10); 
</script>


다음은 getImageData()에 대한 예제입니다. 캔버스에 지정된 사각형의 픽셀 정보를 복사한 사본을 putImageData()를 이용해 지정된 위치에 붙여 넣습니다.

<style>canvas { border: 1px solid black; }</style>
<canvas id= "mycanvas"/>

<script type="text/javascript">
var canvas = document.getElementById('mycanvas');
canvas.width = 300;
canvas.height = 300;
var context = canvas.getContext('2d');

context.fillStyle = "red"; 
context.fillRect(55, 50, 200, 100); 

var iData = context.getImageData(55, 50, 200, 100); 
context.putImageData(iData, 55, 170);
</script>


<style>canvas { border: 1px solid black; }</style>
<canvas id= "mycanvas"/>

<script type="text/javascript">
var canvas = document.getElementById('mycanvas');
canvas.width = 200;
canvas.height = 200;
var context = canvas.getContext('2d');

context.fillStyle = "red";
context.fillRect(0,0,50,50);

context.fillStyle = "blue";
context.fillRect(10,10,30,30);

var iData = context.getImageData(0,0,50,50);
context.putImageData(iData,50,50,10,10,40,40);
</script>


캔버스에서 이미지를 픽셀단위로 편집하거나 다른 이미지로 만들기 위해서는 대상 이미지가 현재의 도메인과 동일해야 하며 만약 도메인이 다를 경우 이미지 데이터를 생성할 수 없습니다. 다음은 createImageData()를 이용해 현재 캔버스에서 다른 캔버스에 이미지를 복사해 보겠습니다.

<style>canvas { border: 1px solid black; }</style>
<canvas id="mycanvas"></canvas>
<canvas id="mycanvas2"></canvas>

<script type="text/javascript">
var canvas = document.getElementById('mycanvas');
var canvas2 = document.getElementById('mycanvas2');
canvas.width = canvas.height = 300;
canvas2.width = canvas2.height = 300;
var context = canvas.getContext('2d');
var context2 = canvas2.getContext('2d');

var img = new Image();
img.onload = function(){
  context.drawImage(img, 10, 30, canvas.width, 250);
  var iData = context.getImageData(0, 0, canvas.width, canvas.height);
  var iCopy = context.createImageData(iData);

  for(var i=0; i < iData.data.length; i++) {
    iCopy.data[i] = iData.data[i];
  }
  context2.putImageData(iCopy, 0, 0);
}
img.src = '8star.png';
</script>


다음 예제는 다른 캔버스에 조정된 이미지를 붙여 넣는 방법을 설명합니다.

<style>canvas { border: 1px solid black; }</style>
<canvas id="mycanvas"></canvas>
<canvas id="mycanvas2"></canvas>

<script type="text/javascript">
var canvas = document.getElementById('mycanvas');
var canvas2 = document.getElementById('mycanvas2');
canvas.width = canvas.height = 300;
canvas2.width = canvas2.height = 300;
var context = canvas.getContext('2d');
var context2 = canvas2.getContext('2d');

var img = new Image();
img.onload = function(){
  context.drawImage(img, 10, 30, canvas.width, 250);
  var iData = context.getImageData(0, 0, canvas.width, canvas.height);
// 이미지를 원하는 영역만 잘라서 다른 캔버스에 붙여 넣음
context2.putImageData(iData, 0, 0, 50, 0, 200, 300);
}
img.src = '8star.png';
</script>

위 예제와 같은 방법을 이용하면 이미지에 필터 효과를 넣을 수 있습니다.

// 데이터 복사
for(var i=0; i < iData.data.length; i++) {
  iCopy.data[i] = iData.data[i];
}

// 투명도 필터 적용.
for(var i=3; i < iData.data.length-4; i+=4) {
  iData.data[i] = iData.data[i]/2;
}

// 네거티브 필터 적용
for(var i=0; i < iData.data.length - 4; i+=4) {
  // 빨간 색상을 반전
  iData.data[i] = 255-iData.data[i];
  // 녹색 색상을 반전
  iData.data[i+1] = 255-iData.data[i+1];
  // 파란 색상을 반전
  iData.data[i+2] = 255-iData.data[i+2];
}

// 흑백 필터 적용
for(var i=0; i < iData.data.length - 4; i+=4) {
  // 픽셀 값 평균
  average = ( iData.data[i] + iData.data[i+1] + iData.data[i+2] ) / 3;
  // 평균 값 저장
  iData.data[i] = iData.data[i+1] = iData.data[i+2] = average;
}


아래 그림은 투명도를 적용한 결과입니다.


다음은 네거티브 필터를 적용한 결과입니다.


마지막으로 흑백을 적용한 결과입니다.


0 댓글