개발/안드로이드

Android Bitmap 특정 영역 리사이징

림쌍월 2021. 1. 28. 10:17

전체 포스팅에 대한 간략한 소개를 하자면 사용자의 서명정보를 받아서 이미지 문서로 저장을 하려고 하는데 실 사용자가 서명을 너무 작게 하였을 경우 서명된 이미지 영역을 인식하여 이미지를 확대 저장하기 위함입니다.

 

* 화면 레이아웃

<FrameLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/border_sign" />

    <!-- 서명 입력 View -->
    <com.divyanshu.draw.widget.DrawView
        android:id="@+id/draw_sign"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="5dp" />

    <!-- 서명 텍스트-->
    <TextView
        android:id="@+id/txt_dialog_gray_sign"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="5dp"
        android:gravity="center"
        android:text="서명해주세요."
        android:textColor="#a0a0a0"
        android:textSize="55sp"
        android:textStyle="bold" />
</FrameLayout>

 

* setBitmapSign :

   서명된 이미지 정보를 Android Bitmap 으로 가져온 후 서명된 영역만 추출 변경하고 반환하는 함수

    public ImageView setBitmapSign(Bitmap bitmap) {
        ImageView iv = ((ImageView) findViewById(allSignatureLayoutId.getImgSign()));
        
        // 추출 이미지 중앙정렬 및 영역추출
        Bitmap map = makeAutoFitableBitMap(bitmap);
        
        // bitmap 배경 투명처리
        map = makeTransparent(map);
        
        iv.setImageBitmap(map);
        
        return iv;
    }

전체 라이프사이클이 조금 다르게 구성이 되어져 있어서 단순하고 조금 수정을 진행하였습니다.

 

 

* makeTransparent

   서명된 영억 이외의 부분 배경 정보를 투명하게 처리

/*
* Bitmap 하얀색 배경을 투명하게 변환
*/
private Bitmap makeTransparent(Bitmap bit) {
  int width = bit.getWidth();
  int height = bit.getHeight();

  Bitmap myBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
  
  int[] allpixels = new int[myBitmap.getHeight() * myBitmap.getWidth()];
  
  bit.getPixels(allpixels, 0, myBitmap.getWidth(), 0, 0, myBitmap.getWidth(), myBitmap.getHeight());
  
  myBitmap.setPixels(allpixels, 0, width, 0, 0, width, height);

  for (int i = 0; i < myBitmap.getHeight() * myBitmap.getWidth(); i++) {
    if (allpixels[i] == Color.WHITE) { // 하얀색을 투명하게 변환
    	allpixels[i] = Color.alpha(Color.TRANSPARENT);
    }
  }
  
  myBitmap.setPixels(allpixels, 0, myBitmap.getWidth(), 0, 0, myBitmap.getWidth(), myBitmap.getHeight());
  
  return myBitmap;
}

 

 

* makeAutoFitableBitMap

   실제 서명이 완료된 이미지 bitmap에서 역영추출하여 새료운 bitmap 으로 재생성

/*
 * Bitmap 서명 자동 가운데 정렬 + 크기조절
 */
private Bitmap makeAutoFitableBitMap(Bitmap bit){

    int width = bit.getWidth();
    int height = bit.getHeight();

	//변경될 이미지를 담을 새로은 비트맵을 생성
    Bitmap myBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);   
    int[] allpixels = new int[myBitmap.getHeight() * myBitmap.getWidth()];

    bit.getPixels(allpixels, 0, myBitmap.getWidth(), 0, 0, myBitmap.getWidth(), myBitmap.getHeight());
    myBitmap.setPixels(allpixels, 0, width, 0, 0, width, height);

    // 1. 비트맵 서명부분만 가지고 와서 가운데 정렬 실행
    int minX = bit.getWidth();
    int minY = bit.getHeight();
    int maxX = 0;
    int maxY = 0;
    int currX = 0;
    int currY = 0;

    // 1-1. 서명이 있는 픽셀의 2차원 최소X, 최대X, 최소Y, 최대Y 좌표 구하기
    for (int i = 0; i < myBitmap.getHeight() * myBitmap.getWidth(); i++) {
    	// 서명정보가 있는 픽셀일 경우
        if (allpixels[i] != Color.WHITE) { 
            currY = i / bit.getWidth();
            currX = i - (currY * bit.getWidth());
            if(minX > currX){   // 서명의 최소 X좌표
                minX = currX;
            }
            if(maxX < currX){   // 서명의 최대 X좌표
                maxX = currX;
            }
            if(minY > currY){   // 서명의 최소 Y좌표
                minY = currY;
            }
            if(maxY < currY){   // 서명의 최대 Y좌표
                maxY = currY;
            }

            if(minX < 11) minX = 11;
            if(maxX < 11) maxX = 11;
        }
    }

    // 서명 주위에 들어갈 패딩
    int padding = 10;
    minX = minX - padding;
    maxX = maxX + padding;
    minY = minY - padding;
    maxY = maxY + padding;

    // 1-2. 서명이 새로 복사될 전체 2차원 width, height 크기 구하기
    int resWidth = bit.getWidth() - ( bit.getWidth() - maxX ) - minX;
    int resHeight = bit.getHeight() - ( bit.getHeight() - maxY ) - minY;

    int[] resPixels = new int[resWidth * resHeight];
    int resCpCnt = 0;

    // 1-3. 기존 픽셀에서 서명부분의 좌표의 픽셀들만 복사하기
    for (int i = 0; i < myBitmap.getHeight() * myBitmap.getWidth(); i++) {
        currY = i / bit.getWidth();
        currX = i - (currY * bit.getWidth());
        
        // 좌표가 최소Y ~ 최대Y && 최소X ~ 최대X 좌표 사이에 있는경우
        if(minY <= currY && maxY > currY){   
            if(minX <= currX && maxX > currX){
                resPixels[resCpCnt] = allpixels[i]; // 좌표안의 픽셀 복사
                resCpCnt++;
            }
        }
    }

    // 1-4. 복사한 서명부분의 픽셀들만 비트맵으로 만들기
    Bitmap resBitmap = Bitmap.createBitmap(resWidth, resHeight, Bitmap.Config.ARGB_8888);
    resBitmap.setPixels(resPixels, 0, resWidth, 0, 0, resWidth, resHeight);

    // 2. 비트맵 리사이징
    // maxResolution = 가로 또는 세로 비율에 맞추어 이미지 리사이징
    resBitmap = resizeBitmapImage(resBitmap, 250);
    return resBitmap;
}

 

참 아릅답게 잘 나왔다  ㅎㅎㅎㅎ