HTML5

CANVAS 다루기 - 이미지

아거스 2011. 1. 17. 16:05
캔바스 관련 강좌 2회차 입니다.

지난 강좌에서는 CANVAS에 대한 기본적인 이해와 간단히 W3C의 샘플코드를 살펴보는 시간을 가졌습니다.
꽤나 많은 속성과 메서드를 가지고 있는 것을 볼 수 있었는데요. 아래 치트시트 정도는 출력해서 모니터 옆에 붙여놓는건 어떨까 싶습니다.

CANVAS 치트시트(PDF, PNG, HTML)


금번 강좌 내용은 포스팅 제목과 같은 캔바스에서 이미지를 다루는 방법에 대하여 얘기할까 합니다.
캔바스는 이미지나 비디오 혹은 또다른 캔바스로부터 이미지 캡쳐 및 리드로우가 가능합니다.

createPattern 메서드

먼저 createPattern 메서드에 대해서 간단히 알아보겠습니다.
(http://msdn.microsoft.com/en-us/library/ff975412(v=VS.85).aspx 참고)


일반적으로 createPattern메서드의 반환값을 fillStyle프로퍼티에 할당하는 방식으로 사용하며
CSS의 background-image 프로퍼티와 비슷한 기능을 한다고 생각하면 됩니다.

<canvas width="372" height="182"></canvas>

<script>
var 
	canvas = document.getElementsByTagName( "canvas" )[0],
	ctx,
	img = new Image();

img.src = "http://img-contents.daum-img.net/2010ci/daumlogo.gif";
if ( canvas.getContext ) {
	ctx = canvas.getContext( "2d" );
	img.onload = function() {
		var pat = ctx.createPattern(img, "repeat");
		ctx.fillStyle = pat;
		ctx.fillRect(0, 0, canvas.width, canvas.height);
	}
}
</script>

위 예제는 하나의 이미지를 캔바스 크기만큼 수평, 수직방향으로 반복 패턴형태로 채우는 예제입니다.


drawImage 메서드


캔바스에는 위에서 본 이미지 캡쳐외에도 여러 방식으로 이미지를 활용할 수 있는데요. 지금 말씀드릴  drawImage 메서드는 이런경우 유용하게 사용이 됩니다.

drawImage 메서드는 아래와 같이 3가지 방식의 파라미터를 지원합니다.

  • drawImage( imageResource, dx, dy )
  • drawImage( imageResource, dx, dy, dw, dh )
  • drawImage( imageResource, sx, sy, sw, sh, dx, dy, dw, dh )

여기서 d는 최종 캔바스 영역을 말하고 s는 원본 이미지를 말합니다.
(x, y, w, h는 다 아실꺼라 생각합니다^^)

아래의 도식을 보시면 조금 더 쉽게 이해할 수 있습니다.



이제 예제를 하나 만들어 보겠습니다.
<canvas width="400" height="150"></canvas>
<script>
	var
		ctx = document.getElementsByTagName( "canvas" )[0].getContext( "2d" ),
		img = new Image();

	img.src = "http://img-contents.daum-img.net/2010ci/daumlogo.gif";
	img.onload = function() {
		for ( var i = 0; i < 4; ++i ) {
			for ( var j = 0; j < 3; ++j ){
				ctx.drawImage( img, j * 100, i * 100, 100 , 50 );
			}
		}
	};
</script>

drawImage 메서드의 2번째 방식을 활용하여 이미지의 크기를 변경하고 해당 이미지를 4 X 3형태로 배치한 예제입니다.

물론 3번째 방식을 활용하면 원본 이미지의 일정부분을 슬라이싱하여 활용할 수 도 있습니다.


ctx.drawImage( img, 25, 0, 16, 17, j * 100, i * 30, 30 , 30 );

중첩된 for문안의 drawImage 메서드의 파라미터를 위와 같이 변경하면 원본 이미지의 일정 부분을 자른 후 캔바스에는 조금 더 크게 확대하여 4 X 3으로 배치시킨 것을 확인할 수 있습니다.


getImageData / putImageData 메서드


SVG와 캔바스의 차이점 중 하나가 바로 푸싱 픽셀(pushing pixels)입니다.
캔바스에서는 getImageData메서드를 활용하여 RGBA 형식의 픽셀 정보를 받아 올 수 있습니다.

<canvas></canvas> 

<script> 
var ctx = document.getElementsByTagName( "canvas" )[0].getContext( "2d" ),
    img = new Image();
img.src = "imageData.png";
img.onload = function () {
  ctx.canvas.width = img.width;  
  ctx.canvas.height = img.height;
  ctx.drawImage( img, 0, 0 );
  var pixels = ctx.getImageData( 0, 0, img.width, img.height );
  
  console.log( pixels.data );
};
</script> 

※ 위 예제에 사용된 이미지는 <이미지 다운받기>에서 받으시면 됩니다.
(아래는 확대한 이미지의 캡쳐입니다.)


※ getImageData / putImageData 메서드는 자바스크립트와 같은 동일근원정책(sam origin rule)을 따릅니다.

위 예제를 실행시켜보면 아래와 같이 픽셀정보를 담은 배열을 리턴합니다.

[
255, 0, 0, 255,
0, 255, 0, 255,
0, 0, 255, 255,
255, 255, 255, 255,
0, 0, 0, 255,
51, 51, 51, 255,
102, 102, 102, 255,
153, 153, 153, 255,
0, 0, 0, 255,
0, 0, 0, 191,
0, 0, 0, 128,
0, 0, 0, 64
]

아래처럼 픽셀정보는 하나의 픽셀당 4개의 아이템으로 구성이 되는 것을 확인할 수 있습니다.

[
r1, g1, b1, a1,
r2, g2, b2, a2,
r3, g3, b3, a3,
...
]

이렇게 픽셀정보를 다룰수 있기 때문에 많은 곳에 활용이 가능한 것을 알 수 있습니다.
대표적인 푸싱 픽셀 예제인 X-Ray기법도 쉽게 구현이 가능합니다.


<canvas></canvas> 

<script> 
var 
	ctx = document.getElementsByTagName( "canvas" )[0].getContext( "2d" ),
	img = new Image(); 

img.src = "test.jpeg";
img.onload = function () {
  ctx.canvas.width = img.width;  
  ctx.canvas.height = img.height;
  ctx.drawImage( img, 0, 0 );
  var pixels = ctx.getImageData( 0, 0, img.width, img.height );
  
  for (var i = 0, len = pixels.data.length; i < len; i += 4) {
    pixels.data[i + 0] = 255 - pixels.data[i + 0];
    pixels.data[i + 1] = 255 - pixels.data[i + 1];
    pixels.data[i + 2] = 255 - pixels.data[i + 2];
  }

  ctx.putImageData( pixels, 0, 0 );
};
</script> 


각 픽셀 정보 색상값(RGB)을 최대값인 255에서 빼 준 후 해당 픽셀정보로 이미지를 삽입하는 방식입니다.
쉽게 "반전효과"를 줄 수 있습니다.

오늘은 캔바스의 특징 중 이미지를 다루는 메서드들에 대하여 얘기했습니다.
쉽고 재미있는 캔바스로 오늘은 사진 놀이를 해보는 것은 어떨까요?