Canvas에서 Pixel 이용하기

이 글은 Mozilla Evangelism팀의 Paul Rouget이 쓴 글이며 그는 프랑스 파리에 살면서 open video on the web이라는 작업을 진행했습니다.

Canvas는 간단하게 HTML 페이지 내에 비트맵 데이터를 넣을 수 있는 방법입니다. 즉, 이를 통해 사각형, 곡선, 다각형 등 다양한 개체를 표현할 수 있습니다. 그러나 어떤 측면에서는 픽셀 데이터 즉 이미지를 이용할 필요가 있습니다. Firefox 3.5에서는 canvas 요소에 createImageData라는 기능을 추가했습니다. createImageData는 canvas 위에 동작하는 픽셀을 추가하여 호출 할 수 있는 메소드입니다. 단일 호출에 대해 이야기하고 있기 때문에 전체 문맥 중에 createImageData를 넣고 캔버스에서 픽셀을 직접적으로 업데이트하거나 다룰 수 있는 호출을 할 수 있습니다.

픽셀 데이터 가져오기
캔버스에서 픽셀을 바로 처리할 수 없습니다. 이를 위해 먼저 데이터를 바깥으로 복사를 한 후 변경 한 다음 캔버스 안으로 다시 집어 넣어야 합니다. getImageData를 호출하면 캔버스 밖으로 사각형을 복사할 수 있습니다. 간단한 소스 코드는 아래와 같습니다.

var canvas = document.getElementById('myCanvasElt');

var ctx = canvas.getContext('2d');
var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);

canvasData 객체는 픽셀 데이터를 포함하며 다음과 같은 구성을 가지고 있습니다.

canvasData {
    width: unsigned long, // the width of the canvas

    height: unsigned long, // the height of the canvas
    data: CanvasPixelArray // the values of the pixels
}

데이터는 간단한 배열로 구성되어 있고 각 픽셀 항목에 하나의 값을 가지고 있으며 왼쪽에서 오른쪽으로 위에서 아래로 RGBA 값순서로 표시합니다. 예를 들어 2×2 캔버스의 경우 4개의 픽셀이 16개의 값을 가지게 됩니다.

0,0  0,1  1,0  1,1
RGBA RGBA RGBA RGBA

따라서 여러분은 width * height * 4와 같은 공식으로 배열의 크기를 계산할 수 있습니다. 매우 큰 캔버스의 경우 x=20, y=20인 파란색 픽셀의 배열 크기는 다음과 같은 코드로 알아 낼 수 있습니다.

var x = 10;
var y = 10;
var blue = canvasData.data[(y * width + x) * 4 + 2];

각 RGB 값은 0..255 사이의 값을 가지고 0은 투명 하고 255는 불투명 합니다.

새로운 픽셀 세트 만들기
긁은 자국으로 부터 새로운 매트릭스를 만들려고 한다면 createImageData를 호출하면 되는데 이 때 두가지 인자인 height와 매트릭스의 width를 넘기면 됩니다. 이 때 createImageData 호출은 현재 캔버스 밖으로 픽셀을 복사하는 게 아니라 투명한 검은색인 (255,255,255,0) 값을 가진 빈 픽셀 매트릭스를 생성합니다. 아래는 캔버스 사이즈에 맞는 픽셀 세트를 만드는 코드 입니다.

var canvas = document.getElementById('myCanvasElt');

var ctx = canvas.getContext('2d');
var canvasData = ctx.createImageData(canvas.width, canvas.height);

이 메소드는 픽셀 데이터를 만들때만 사용해야 합니다. 이전 버전의 파이어폭스에서는 JavaScript 객체 밖으로 canvasData 객체를 만들 거나 나중에 캔버스 데이터를 업데이트하는데 호출하는데 사용하기도 했습니다. 이 기능은 일반적 자바스크립트 객체 대신 특별한 객체를 사용하기 위해 웹킷과 함께 호환성을 유지 합니다.

픽셀 업데이트
일단 canvasData 객체를 만들었으면 여러분은 배열을 통해 픽셀 값을 바꿀 수 있습니다. 아래에 배열을 읽어서 그 값을 바꾸는 샘플 코드가 있습니다.

for (var x = 0; x < canvasData.width; x++)  {

    for (var y = 0; y < canvasData.height; y++)  {

 
        // Index of the pixel in the array
        var idx = (x + y * width) * 4;

 
        // If you want to know the values of the pixel
        var r = canvasData.data[idx + 0];

        var g = canvasData.data[idx + 1];
        var b = canvasData.data[idx + 2];

        var a = canvasData.data[idx + 3];
 

        //[...] do what you want with these values
 
        // If you want to update the values of the pixel
        canvasData.data[idx + 0] = ...; // Red channel

        canvasData.data[idx + 1] = ...; // Green channel

        canvasData.data[idx + 2] = ...; // Blue channel

        canvasData.data[idx + 3] = ...; // Alpha channel

    }
}

캔버스 데이터 변경
이제 픽셀 데이터를 변경했으면 간단한 putImageData 기능을 호출합니다. 이는 canvasData 객체를 가져와서 캔버스 안으로 사각형 픽셀 데이터를 가져와 원하는 x,y 위치에 그리게 됩니다.

var canvas = document.getElementById('myCanvasElt');

var ctx = canvas.getContext('2d');
var canvasData = ctx.putImageData(canvasData, 0, 0);

getImageData 샘플 코드
아래에는 칼라 이미지를 회색조로 바꾸는 샘플 코드 입니다. 이 기능의 실제 데모를 구동해 보실 수 있습니다.

var canvas = document.getElementById('myCanvasElt');

var ctx = canvas.getContext('2d');
var canvasData = ctx.getImageData(0, 0, canvas.width, canvas.height);

for (var x = 0; x < canvasData.width; x++) {

    for (var y = 0; y < canvasData.height; y++) {

        // Index of the pixel in the array
        var idx = (x + y * canvas.width) * 4;

 
        // The RGB values
        var r = canvasData.data[idx + 0];

        var g = canvasData.data[idx + 1];
        var b = canvasData.data[idx + 2];

 
        // Update the values of the pixel;
        var gray = (r + g + b) / 3;

        canvasData.data[idx + 0] = gray;
        canvasData.data[idx + 1] = gray;

        canvasData.data[idx + 2] = gray;
    }

}
ctx.putImageData(canvasData, 0, 0);

createImageData 샘플 코드
아래 코드는 캔버스 안으로 프랙탈 도형을 그리는 샘플 코드입니다. 이 코드 역시 데모 사이트에서 확인 가능합니다.

var canvas = document.getElementById('myCanvasElt');

var ctx = canvas.getContext('2d');
var canvasData = ctx.createImageData(canvas.width, canvas.height);

 
// Mandelbrot
function computeColor(x, y) {
    x = 2.5 * (x/canvas.width - 0.5);

    y = 2 * (y/canvas.height - 0.5);

    var x0 = x;
    var y0 = y;

 
    var iteration = 0;
    var max_iteration = 100;

 
    while (x * x + y * y <= 4 && iteration < max_iteration ) {

        var xtemp = x*x - y*y + x0;

        y = 2*x*y + y0;
        x = xtemp;

        iteration++;
    }
 
    return Math.round(255 * iteration / max_iteration);

}
 
for (var x = 0; x < canvasData.width; x++) {

    for (var y = 0; y < canvasData.height; y++) {

        var color = computeColor(x, y);
 
        // Index of the pixel in the array

        var idx = (x + y * canvas.width) * 4;

 
        // Update the values of the pixel;
        canvasData.data[idx + 0] = color;

        canvasData.data[idx + 1] = color;
        canvasData.data[idx + 2] = color;

        canvasData.data[idx + 3] = 255;
    }

}
 
ctx.putImageData(canvasData, 0, 0);

참고 문헌
Canvas에 대해 더 알고 싶으시다면 Mozilla 개발자 센터 문서를 자세히 살펴 보시기 바랍니다.

작성자: Channy Yun

Channy Yun가 작성한 문서들…


댓글이 없습니다.

댓글 쓰기