본문 바로가기
프로그래밍 놀이터/안드로이드, Java

[android] camera take and crop ( 사진 찍으면서 crop 까지 하기 )

by 돼지왕 왕돼지 2013. 8. 5.
반응형


 안드로이드, 사진 찍으면서 crop 까지 하기

 

[android] camera take and crop ( 사진 찍으면서 crop 까지 하기 )



Camera 로 사진을 찍으면서 Crop 까지 하는 sample code.


private static final int REQUEST_CODE_PROFILE_IMAGE_CAPTURE = 545;

private static final int REQUEST_CODE_PROFILE_IMAGE_CROP = 2103;


private static final String TYPE_IMAGE = "image/*";

private static final int PROFILE_IMAGE_ASPECT_X = 3;

private static final int PROFILE_IMAGE_ASPECT_Y = 1;

private static final int PROFILE_IMAGE_OUTPUT_X = 600;

private static final int PROFILE_IMAGE_OUTPUT_Y = 200;

private static final String TEMP_FILE_NAME = "tempFile.jpg";


private Uri mTempImageUri;


@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);


findViewById( R.id.btn ).setOnClickListener( new OnClickListener() {

@Override

public void onClick(View v) {

Intent intent = new Intent( MediaStore.ACTION_IMAGE_CAPTURE, null);

startActivityForResult( intent, REQUEST_CODE_PROFILE_IMAGE_CAPTURE );

}

});

}


private File getTempFile(){

File file = new File( Environment.getExternalStorageDirectory(), TEMP_FILE_NAME );

try{

file.createNewFile();

}

catch( Exception e ){

Log.e("cklee", "fileCreation fail" );

}

return file;

}


private Uri getJustTakenPictureUri(){

Cursor cursor = getContentResolver().query( Images.Media.EXTERNAL_CONTENT_URI, new String[]{ Images.ImageColumns.DATA }, null, null, null );

if ( cursor == null ) return null;

String fileName = null;

if ( cursor.moveToLast() )

fileName = cursor.getString( 0 );

cursor.close();

if ( TextUtils.isEmpty( fileName ) ) return null;

return Uri.fromFile( new File( fileName ) );

}


private void doCrop(){

Uri justTakenPictureUri = getJustTakenPictureUri(); 

mTempImageUri = Uri.fromFile( getTempFile() );

Intent intent = new Intent( "com.android.camera.action.CROP" );

intent.setDataAndType( justTakenPictureUri, TYPE_IMAGE );

intent.putExtra( "scale", true );

intent.putExtra( "aspectX", PROFILE_IMAGE_ASPECT_X );  

intent.putExtra( "aspectY", PROFILE_IMAGE_ASPECT_Y );  

intent.putExtra( "outputX", PROFILE_IMAGE_OUTPUT_X);  

intent.putExtra( "outputY", PROFILE_IMAGE_OUTPUT_Y);

intent.putExtra( MediaStore.EXTRA_OUTPUT, mTempImageUri );

startActivityForResult( intent,  REQUEST_CODE_PROFILE_IMAGE_CROP );

}


@Override

protected void onActivityResult(int requestCode, int resultCode, Intent data) {

super.onActivityResult(requestCode, resultCode, data);

switch (requestCode) {

case REQUEST_CODE_PROFILE_IMAGE_CAPTURE:

doCrop();

break;

case REQUEST_CODE_PROFILE_IMAGE_CROP:

File tempFile2 = getTempFile();

if ( tempFile2.exists() )

((ImageView)findViewById( R.id.img )).setImageBitmap( BitmapFactory.decodeFile( tempFile2.toString() ) );

break;

}







onActivityResult 를 통하지 않고 한큐에 crop 까지 하는 방법은 없는가?


카메라 앱을 실행하면서 crop 옵션을 주면, 찍으면서 바로 crop 도 가능하다. 하지만, 이 경우에는 return-data 의 형태로 crop 된 data 가 bitmap 으로 전달되는데, bundle 의 용량제한 문제로 IBinder 에러가 날 수 있다. 즉 큰 사이즈의 crop 된 이미지에는 적용하기가 어렵다. 작은 사이즈라면 crop 옵션을 주는 방향으로 처리하는 것이 좋다.


하지만!! 이도 문제가 있는데, 카메라 앱에 따라서 crop 옵션을 무시하는 경우도 있고, output 옵션을 무시하는 경우도 허다하다. 제대로 구현된 카메라앱의 경우는 모든 extra 옵션을 충실히 따르지만, 어느 정도 유명한 모 회사의 카메라 앱에서조차 이전버전에서는 crop 옵션을 무시하곤 했다. output 의 경우 현재 대부분의 카메라가 제대로 지원을 안 해준다. 이런 경우에는 반드시 onActivityResult 를 통해서 crop 과정을 한번 더 거쳐야 한다. 결국 안드로이드는 고려사항이 정말 많다는 것.






Cursor 저건 뭐하는 거야?


output 옵션이 제대로 먹으면 좋으련만, MediaStore.ACTION_IMAGE_CAPTURE 의 경우 output 옵션을 제대로 먹지 않는 경우가 대부분이었다. 이런 경우에는 가장 최근에 찍힌 이미지의 주소를 가져와서 그 녀석을 crop 하도록 유도하는 방법으로 우회해서 구현한 것이다. 이 부분은 치명적 결함이 있는데, 특정상황에서 사진찍는 것과 이미지 다운로드 등의 과정이 동시에 일어난다면, 자신이 찍은 사진이 아니라 다운로드한 이미지가 crop 대상으로 등장할 수 있다. 


요 녀석을 어떻게 해결해야 할지.. 아시는 분은 댓글좀.. 아이디어라도...






반응형

댓글