현재 텔레스트레이션 게임 구현을 위해 리액트에서 canvas를 이용해 그림판을 구현 중에 있다. 그림판의 기능으로는 선 그리기, 지우기, 채우기, 초기화, 색상 변경을 목표로 하고 있는데 그 중에서 채우기 기능을 어떻게 구현해야 좋을지 고민이 있었다.
채우기 기능은 moveTo(), lineTo() 등을 이용해 그린 캔버스에서 border가 끊기지 않고 연결된 부분이 있다면 해당 흰색 공간을 선택한 색상으로 채워지는 기능을 의미한다.
getImageData()
를 통해 캔버스 내 픽셀 정보를 불러올 수 있다는 사실은 알았지만, 단순히 전체를 탐색해야 하는 것인가? 이건 아닐 것 같은데.. 라는 생각이 들었다. 이에 대한 구현 방법을 찾아보다가 flood fill
이라는 알고리즘을 보게 됐고, 해당 내용을 좀 더 공부해보고 캔버스에 적용해보려고 한다. 아이디어는 stackoverflow 를 참고했다.
우선 getImageData()가 어떤 값을 반환하는지 확인이 필요했고,
console.log(getImageData(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
음. 뭐가 좀 많음을 느껴 찾아봤다.
먼저 해당 함수를 이해하기 위해서 캔버스 내 이미지 개념을 확인할 필요가 있었다.
<aside>
✏️ getImageData(x, y, w, h)
: ImageData 객체를 리턴하며, data는 래스터 정보
이다.
래스터(Raster) : 이미지 내 픽셀 정보로, 래스트 정보는 한 점당 R, G, B, A 요소 각각에 대해 4바이트씩 값을 가지며 이런 픽셀 정보가 좌→우로, 위→아래로 나열된다. (참조 링크)
</aside>
즉, 우리가 보는 이미지는 2차원 배열이지만 ImageData의 정보는 1차원 배열로 얻게 되고, 일차원 배열의 길이는 w * h * 4
임을 알 수 있었다.
이 정보를 알고나니 위에서 CANVAS_WIDTH가 742이고, CANVAS_HEIGHT가 468였기 때문에 배열의 길이가 347,256이 되지 않을까 예상했지만 이보다 4배를 더한 1,389,024의 값이 어떻게 나오게 됐는지 알게 되었다.
픽셀 데이터를 어떻게 얻는지를 확인했으니 이제 어떤 식으로 구현해야 좋을지를 봐야한다.
플러드 필(flood fill)에 대한 정의는 다음과 같다. (참조 링크-위키백과)