brunch

You can make anything
by writing

C.S.Lewis

by 서준수 Aug 13. 2019

안드로이드 카메라 프리뷰 좌우 반전

여기서 사용되는 예제는 아래 카메라 예제를 기반으로 한다.


https://brunch.co.kr/@mystoryg/54

https://brunch.co.kr/@mystoryg/55


이전 및 여기서 다룰 내용이 모두 작업된 코드는 다음의 첨부파일을 참조하면 된다.


먼저 카메라 프리뷰 좌우 반전을 하기 전에 기존에 부족했던 부분을 약간 보완할 것이다.


1) 저장소 권한 동의 추가

2) 미디어 스캔을 통해 저장된 이미지 파일 즉시 확인

3) 카메라 프리뷰 좌우 반전하기


최초 예제의 기본 뼈대부터 직접 구현한 것이 아니라 코드 품질은 신경 쓰지 않고 단순히 기능 구현만 되도록 한 점에 주의!! 의식의 흐름대로 작성한 코드이다.


1) 저장소 권한 동의 추가

Preview.java

캡처 이미지가 확대하지 않으면 잘 보이지 않는다. 주요 변경 부분은 다음과 같다.


int permissionCamera = ContextCompat.checkSelfPermission(mContext, Manifest.permission.CAMERA);
int permissionStorage = ContextCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE);

if (permissionCamera == PackageManager.PERMISSION_DENIED) {
    ActivityCompat.requestPermissions((Activity) mContext, new String[]{Manifest.permission.CAMERA}, MainActivity.REQUEST_CAMERA);
} else if (permissionStorage == PackageManager.PERMISSION_DENIED) {
    ActivityCompat.requestPermissions((Activity) mContext, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, MainActivity.REQUEST_STORAGE);
} else {
    manager.openCamera(mCameraId, mStateCallback, null);
}


카메라 권한과 동일한 방식으로 저장소 권한을 얻지 못한 상태라면 권한 요청을 하도록 하는 코드이다.


MainActivity.java

권한 요청을 한 후에 호출되는 onRequestPermissionResult() 함수에서 실제로 결과를 처리하는 작업을 한다. 권한에 동의했으면 카메라를 실행하고 아니면 토스트 메시지를 띄우고 앱을 종료한다. (시나리오 고려 따위 없는 단순 처리...)


case REQUEST_STORAGE:
    for (int i = 0; i < permissions.length; i++) {
        String permission = permissions[i];
        int grantResult = grantResults[i];
        if (permission.equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            if (grantResult == PackageManager.PERMISSION_GRANTED) {
                Log.d(TAG, "REQUEST_STORAGE");
                mPreview.openCamera();
            } else {
                Toast.makeText(this, "Should have storage permission to run", Toast.LENGTH_LONG).show();
                finish();
            }
        }
    }
    break;


주요 변경점은 위와 같이 저장소에 대한 처리가 추가된 것이다.


2) 미디어 스캔을 통해 저장된 이미지 파일 즉시 확인

미디어 스캔을 하기 위해서 현재 구조상 Preview.java에서 캡처가 완료된 후에 callback을 통해서 MainActivity.java로 알려주는 방식을 사용한다.

CallbackInterface.java


Preview.java에서 하기와 같이 캡처가 완료되고 저장이 되면 onSave()를 호출한다.

Preview.java

public void setOnCallbackListener(CallbackInterface callbackListener) {
    mCallbackInterface = callbackListener;
}


MainActivity.java에서 콜백 리스너를 등록할 수 있도록 위와 함수를 추가해야 한다.


MainActivity.java에서는CallbackInterface를 꼭 implements 하고 mPreview.setOnCallbackListener(this);를 호출하는 것도 잊지 말자.

MainActivity.java

그 후 onSave()를 위와 같이 오버라이딩한다. 그러면 onSave() 콜백이 왔을 때 미디어 스캔을 위한 브로드 캐스트를 날려주게 된다.


3) 카메라 프리뷰 좌우 반전하기

기존 전면 카메라는 거울을 보는 것과 동일하다. 여기서는 그 화면을 좌우 반전하도록 할 것이다. 그러면 다른 사람이 나를 보는 모습과 동일하다.


전면 카메라에서 좌우 반전을 위해서는 다음과 같이 설정한다.


mCameraDirectionButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        onPause();
        if (mCameraId.equals("1")) {
            mCameraId = "0"; // 후면
            Matrix matrix = new Matrix();
            matrix.setScale(1, 1);
            mTextureView.setTransform(matrix);
        } else {
            mCameraId = "1"; // 전면
            Matrix matrix = new Matrix();
            matrix.setScale(-1, 1);
            matrix.postTranslate(mWidth, 0);
            mTextureView.setTransform(matrix);
        }
        openCamera();
    }
});



말로 설명하는 것보다 다음 그림과 같이 생각하면 이해하기 쉬울 듯하다. X축 스케일을 -1만큼 늘리고 width 만큼 이동(파란색 부분과 겹치게)시키면 좌우가 반전된다. 후면으로 전환하면 다시 원래대로 돌아와야 하므로 X축 스케일을 1로 하면 된다. 그러면 아래 그림에서 파란색 부분(화면에 보이는 영역)과 같이 되므로 별도의 이동은 필요 없다.


상하 반전을 원하면 Y축을 조정하면 된다.

여기까지 작업된 결과는 다음과 같다. 좌측이 후면, 우측이 전면 카메라 프리뷰의 모습이다.



매거진의 이전글 안드로이드 Handler 알고 쓰자
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari