[공유] 특정 모양의 Bitmap 이미지 자르기

출처 WorkSpace | windLike
원문 http://windhunt97.blog.me/20162613977

 

 

직소 퍼즐 같은 게임을 만들때 가장 고민하는 부분 중의 하나가 이미지를 사각형이 아닌 직소 퍼즐 모양으로 어떻게 잘라야하는가~ 입니다. 저도 이번에 안드로이드 직소 퍼즐 게임을 만들면서 이 부분에서 많은 고민을 했고 또한 여러차례 시행 착오를 거쳐 결국 원하는 결과를 얻어낼 수 있었습니다...

 

여러 삽질끝에 얻어낸 결과인지라 이 방식이 효율적이고 완벽하다라고 말씀드릴 수는 절대 없습니다, 또한 다른 더 좋은 방식이 있을 수도 있습니다만 조금이라도 도움이 되었으면 하는 마음에서 이 글을 작성합니다. 

 

설명이 잘 이해가 안된다 싶으실때 덧글 주시면 시간날때 답글 달아 드리겠습니다. ^^a 

 

 

원본 이미지를 직소 퍼즐 조각 모양으로 잘라내기의 핵심은 이미지의 알파값을 이용하여 필요없는 부분은 화면에 표시되지 않도록 하는것 입니다.  

 

기본적으로 이미지는 사각형을 기준으로만 자를 수 있습니다(맞지요?). 사각형으로 자른 이미지를 원하는 모양의 이미지로 가공하기 위해서 기준이되는 이미지(아래 이미지 참고)를 별도로 준비합니다. 직소 퍼즐 게임의 경우 각 직소 펴즐의 조각 이미지가 되겠지요. 

 

 

예제 이미지의 빨간색 부분은 원래 투명 부분입니다. 흰색으로 기준 이미지를 만들다 보니 바탕색과 구별이 안되어 투명 배경을 빨간색으로 표시한 것이니 참고하시구요~ 기준이 되는 이미지의 색상은 어떤 색상을 쓰시더라도 상관 없습니다(빨간색, 검정색, 흰색, 노란색 등등). 단, alpha 값을 이용하여 필요없는 부분이 화면에 표시되지 않도록 하는 방식이므로 반드시 필요없는 부분은 투명으로 만들어 주셔야 합니다. 그러므로 기준 이미지는 png 파일로 저장해서 사용하시면 됩니다. 

 

 

먼저, 원본 이미지에서 원하는 부분만 사각형으로 잘라내는 코드는 다음과 같습니다.

 

 

// 원본 이미지를 불러오고 

Bitmap mSource = BitmapFactory.decodeFile("이미지 경로/이미지 파일 이름.jpg");

 

// 잘라낼 가로 픽셀 크기 

int nWidth  = 100;

// 잘라낼 세로 픽셀 크기
int nHeight = 100;

// 원본 이미지에서 잘라낸 비트맵 이미지 영역의 색상값을 저장할 배열 

int[] nPixels = new int[nWidth * nHeight];

 

// 원본 이미지의 좌측 상단을 기준으로

// 가로 50, 세로 50 지점에서 가로 100, 세로 100 크기의 생상값을 가져와

// nPixels 배열에 저장한다.
mSource.getPixels(nPixels, 0, nWidth, 50, 50, nWidth, nHeight); 

 

// 잘라낸 이미지를 저장할 새로운 비트맵 이미지를 생성한다.

Bitmap mJigsaw = Bitmap.createBitmap(nWidth, nHeight, Bitmap.Config.ARGB_8888);

// 생성된 비트맵 이미지에 색상값을 저장한다. 

mJigsaw.setPixels(nPixels, 0, nWidth, 0, 0, nWidth, nHeight);

 

 

위의 코드대로 적용하면 원본 이미지의 좌측 상단을 기준으로 가로 50픽셀, 세로 50픽셀 지점에서 가로 100픽셀, 세로 100픽셀 크기의 이미지가 mJigsaw 비트맵 이미지에 저장됩니다. 여기까지 사각형으로 잘라내기는 완성입니다.  

 

이제 잘라낸 이미지를 어떻게 가공해야 원하는 모양의 직소 조각을 만들어 낼수 있을지를 설명하겠습니다. 위 코드에서 잘라낸 이미지 색상값을 mJigsaw 비트맵 이미지 인스턴스에 setPixel로 저장하기 전에 다음 코드를 추가합니다.  

 

 

// 직소 조각 모양의 레이아웃 비트맵 로드
Bitmap mLayout = BitmapFactory.decodeFile("이미지 경로/직소 조각 기준 이미지 파일 이름.png");
 

// mLayout 비트맵 이미지의 alpha 값을  

// 잘라낸 mJigsaw 비트맵 이지지에 적용될 nPixels 배열의 alpha 값으로 대체한다.
for (int i = 0; i < nPixels.length; i++) {

    // nPixels 배열의 각 컬러값에서 alpha 값을 제거한다.
    nPixels[i] &= 0x00ffffff;

    // 제거된 alpha 값을 mLayout의 alpha 값으로 대체한다. 

    nPixels[i] |= mLayout.getPixel(i % nWidth, i / nWidth) & 0xff000000;
}

 

// 생성된 비트맵 이미지에 색상값을 저장한다. 

mJigsaw.setPixels(nPixels, 0, nWidth, 0, 0, nWidth, nHeight);

 

 

완성된 mJigsaw 비트맵 이미지를 Canvas 나 ImageView 에 표시해보면 원하는 직소 조각 모양으로 표시되는 것을 확인할 수 있습니다. 

 

굳이 기준 이미지를 사용하지 않더라도 원하는 모양의 alpha 값을 배열로 만들어서 적용이 가능하시다면 그렇게 사용하셔도 결과는 같습니다. 

 

위 코드는 단순히 직소 퍼즐 조각에만 적용되지는 않습니다. 원하는 모양의 어떤 이미지라도 만들어 낼 수 있습니다.

 

참고 주소 : http://windhunt97.blog.me/20162613977

 

퍼즐 만들때 이미지 투명처리 하는게 막막했었는데 좋은 참고가 됨