티스토리 뷰



안드로이드/Android 사진, 갤러리 Image Crop 후  MMS 전송 하기

▒ ▒  ▒  ▒  ▒  ▒  ▒  전체 소스 입니다.  ▒ ▒  ▒  ▒  ▒  ▒  ▒  
public class TestImageCropActivity extends Activity {

	private static final String TAG = "TestImageCropActivity";

	private static final int PICK_FROM_CAMERA = 0;
	private static final int PICK_FROM_ALBUM = 1;
	private static final int CROP_FROM_CAMERA = 2;

	private Uri mImageCaptureUri;
	private AlertDialog mDialog;


	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		setLayout();
		
	}

	/** 
	 Button Click 
	 */
	public void onButtonClick(View v){
		switch (v.getId()) {
		case R.id.btn_sns:
			sendSMS("01000000000" , "hi nice to meet you");
			break;
		case R.id.btn_mms:
			Log.e(TAG, "mImageCaptureUri = " + mImageCaptureUri);
			sendMMS(mImageCaptureUri);
//			sendMMSG();
			break;
		case R.id.btn_image_crop:
			mDialog = createDialog();
			mDialog.show();
			break;
		}
	}

	/** 
	 * 다이얼로그 생성
	 */
	private AlertDialog createDialog() {
		final View innerView = getLayoutInflater().inflate(R.layout.image_crop_row, null);

		Button camera = (Button)innerView.findViewById(R.id.btn_camera_crop);
		Button gellary = (Button)innerView.findViewById(R.id.btn_gellary_crop);

		camera.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				doTakePhotoAction();
				setDismiss(mDialog);
			}
		});

		gellary.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				doTakeAlbumAction();
				setDismiss(mDialog);
			}
		});

		AlertDialog.Builder ab = new AlertDialog.Builder(this);
		ab.setTitle("이미지 Crop");
		ab.setView(innerView);

		return  ab.create();
	}

	/** 
	 * 다이얼로그 종료 
	 */
	private void setDismiss(AlertDialog dialog){
		if(dialog!=null&&dialog.isShowing()){
			dialog.dismiss();
		}
	}

	/** 
	 * SMS 발송	 
	 */
	private void sendSMS(String reciver , String content){
		Uri uri = Uri.parse("smsto:"+reciver);   
		Intent it = new Intent(Intent.ACTION_SENDTO, uri);   
		it.putExtra("sms_body", content);   
		startActivity(it);  
	}
	
	/** 
	 * MMS 발송	(APP TAB BOX) 
	 */
	private void sendMMS(Uri uri){
		uri = Uri.parse(""+uri);   
		Intent it = new Intent(Intent.ACTION_SEND);   
		it.putExtra("sms_body", "some text");   
		it.putExtra(Intent.EXTRA_STREAM, uri);   
		it.setType("image/*");
		// 삼성 단말에서만 허용 ( 앱 선택 박스 없이 호출 )
//		it.setComponent(new ComponentName("com.sec.mms", "com.sec.mms.Mms"));
		startActivity(it); 
	}
	
	/**
	 * MMS 발송 ( 첨부 파일 없음 )
	 */
	private void sendMMSG(){
		Uri mmsUri = Uri.parse("mmsto:");
		Intent sendIntent = new Intent(Intent.ACTION_VIEW, mmsUri);  
		sendIntent.addCategory("android.intent.category.DEFAULT");
		sendIntent.addCategory("android.intent.category.BROWSABLE");
		sendIntent.putExtra("address", "01000000000");
		sendIntent.putExtra("exit_on_sent", true);
		sendIntent.putExtra("subject", "dfdfdf");
		sendIntent.putExtra("sms_body", "dfdfsdf");
		Uri dataUri = Uri.parse(""+mImageCaptureUri);
		sendIntent.putExtra(Intent.EXTRA_STREAM, dataUri);

		startActivity(sendIntent); 
	}
	

	/**
	 * 카메라 호출 하기
	 */
	private void doTakePhotoAction()
	{
		Log.i(TAG, "doTakePhotoAction()");
		Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
		// Crop된 이미지를 저장할 파일의 경로를 생성
		mImageCaptureUri = createSaveCropFile();
		intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, mImageCaptureUri);
		startActivityForResult(intent, PICK_FROM_CAMERA);
	}

	/**
	 * 앨범 호출 하기
	 */
	private void doTakeAlbumAction()
	{
		Log.i(TAG, "doTakeAlbumAction()");
		// 앨범 호출
		Intent intent = new Intent(Intent.ACTION_PICK);
		intent.setType(android.provider.MediaStore.Images.Media.CONTENT_TYPE);
		startActivityForResult(intent, PICK_FROM_ALBUM);
	}

	/**
	 * Result Code
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data)
	{
		Log.d(TAG, "onActivityResult");
		if(resultCode != RESULT_OK)
		{
			return;
		}

		switch(requestCode)
		{
		case PICK_FROM_ALBUM:
		{
			Log.d(TAG, "PICK_FROM_ALBUM");
			
			// 이후의 처리가 카메라와 같으므로 일단  break없이 진행합니다.
			// 실제 코드에서는 좀더 합리적인 방법을 선택하시기 바랍니다.
			mImageCaptureUri = data.getData();
			File original_file = getImageFile(mImageCaptureUri);
			
			mImageCaptureUri = createSaveCropFile();
			File cpoy_file = new File(mImageCaptureUri.getPath()); 

			// SD카드에 저장된 파일을 이미지 Crop을 위해 복사한다.
			copyFile(original_file , cpoy_file);
		}

		case PICK_FROM_CAMERA:
		{
			Log.d(TAG, "PICK_FROM_CAMERA"); 

			// 이미지를 가져온 이후의 리사이즈할 이미지 크기를 결정합니다.
			// 이후에 이미지 크롭 어플리케이션을 호출하게 됩니다.

			Intent intent = new Intent("com.android.camera.action.CROP");
			intent.setDataAndType(mImageCaptureUri, "image/*"); 
			
			// Crop한 이미지를 저장할 Path
			intent.putExtra("output", mImageCaptureUri);
			
			// Return Data를 사용하면 번들 용량 제한으로 크기가 큰 이미지는
			// 넘겨 줄 수 없다.
//			intent.putExtra("return-data", true); 
			startActivityForResult(intent, CROP_FROM_CAMERA);

			break;
		}
		
		case CROP_FROM_CAMERA:
		{
			Log.w(TAG, "CROP_FROM_CAMERA");
			
			// Crop 된 이미지를 넘겨 받습니다.
			Log.w(TAG, "mImageCaptureUri = " + mImageCaptureUri);

			String full_path = mImageCaptureUri.getPath();
			String photo_path = full_path.substring(4, full_path.length());
			
			Log.w(TAG, "비트맵 Image path = "+photo_path);
			
			Bitmap photo = BitmapFactory.decodeFile(photo_path);
			mPhotoImageView.setImageBitmap(photo);

			break;
		}
		}
	}
	
	/**
	 * Crop된 이미지가 저장될 파일을 만든다.
	 * @return Uri
	 */
	private Uri createSaveCropFile(){
		Uri uri;
		String url = "tmp_" + String.valueOf(System.currentTimeMillis()) + ".jpg";
		uri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), url));
		return uri;
	}


	/**
	 * 선택된 uri의 사진 Path를 가져온다.
	 * uri 가 null 경우 마지막에 저장된 사진을 가져온다.
	 * @param uri
	 * @return
	 */
	private File getImageFile(Uri uri) {
		String[] projection = { MediaStore.Images.Media.DATA };
		if (uri == null) {
			uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
		}

		Cursor mCursor = getContentResolver().query(uri, projection, null, null, 
				MediaStore.Images.Media.DATE_MODIFIED + " desc");
		if(mCursor == null || mCursor.getCount() < 1) {
			return null; // no cursor or no record
		}
		int column_index = mCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
		mCursor.moveToFirst();

		String path = mCursor.getString(column_index);

		if (mCursor !=null ) {
			mCursor.close();
			mCursor = null;
		}

		return new File(path);
	}

	/**
	 * 파일 복사
	 * @param srcFile : 복사할 File
	 * @param destFile : 복사될 File
	 * @return
	 */
	public static boolean copyFile(File srcFile, File destFile) {
		boolean result = false;
		try {
			InputStream in = new FileInputStream(srcFile);
			try {
				result = copyToFile(in, destFile);
			} finally  {
				in.close();
			}
		} catch (IOException e) {
			result = false;
		}
		return result;
	}

	/**
	 * Copy data from a source stream to destFile.
	 * Return true if succeed, return false if failed.
	 */
	private static boolean copyToFile(InputStream inputStream, File destFile) {
		try {
			OutputStream out = new FileOutputStream(destFile);
			try {
				byte[] buffer = new byte[4096];
				int bytesRead;
				while ((bytesRead = inputStream.read(buffer)) >= 0) {
					out.write(buffer, 0, bytesRead);
				}
			} finally {
				out.close();
			}
			return true;
		} catch (IOException e) {
			return false;
		}
	}

	/*
	 * Layout
	 */
	private ImageView mPhotoImageView;

	private void setLayout(){
		mPhotoImageView = (ImageView)findViewById(R.id.img_bitmap);
	}
}


▒ ▒  ▒  ▒  ▒  ▒  ▒  디테일 설명 입니다.  ▒ ▒  ▒  ▒  ▒  ▒  ▒  

▒ 1.  
참고사이트 : http://theeye.pe.kr/entry/example-of-image-crop-with-camera-and-album-picker-on-android

아이군님의 블로그의 Crop소스 를 참고였습니다. 참 설명이 잘 되있어서 보기 편했는데요. 바뀐점이 있다면 Crop후 이미지를 넘기는 과정에서 번들은 사용해서 넘기셨기대문에 고화질의 사진을 Crop할 경우 Return Data를 넘기지 못하는 현상이 발생하였습니다. 그래서 Crop이 정상 작동 하지 않는 경우가 생기게 되어, 일단 File을 생성 후 그 파일을 Crop한 후 저장하는 형식으로 수정 하 였습니다. 전체적인 틀은 비슷하게 가고 나머지 부분은 약간씩 수정 되었구요. SMS와 Crop한 이미지를 전송하는 MMS 기능을 추가 하였습니다.


▒ 2. 
case PICK_FROM_CAMERA:
		{
			Log.d(TAG, "PICK_FROM_CAMERA"); 

			// 이미지를 가져온 이후의 리사이즈할 이미지 크기를 결정합니다.
			// 이후에 이미지 크롭 어플리케이션을 호출하게 됩니다.

			Intent intent = new Intent("com.android.camera.action.CROP");
			intent.setDataAndType(mImageCaptureUri, "image/*"); 
			
			// Crop한 이미지를 저장할 Path
			intent.putExtra("output", mImageCaptureUri);
			
			// Return Data를 사용하면 번들 용량 제한으로 크기가 큰 이미지는
			// 넘겨 줄 수 없다.
//			intent.putExtra("return-data", true); 
			startActivityForResult(intent, CROP_FROM_CAMERA);

			break;
		}

intent.putExtra("output", mImageCaptureUri);
아웃풋 경로 지정함으로써 Crop 된 이미지가 해당 UriRuturn 되도록 설정 하였습니다.


▒ 3.   
    /**
     * Crop된 이미지가 저장될 파일을 만든다.
     * @return Uri
     */
    private Uri createSaveCropFile(){
        Uri uri;
        String url = "tmp_" + String.valueOf(System.currentTimeMillis()) + ".jpg";
        uri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), url));
        return uri;
    }

Crop이 완료된 파일은 해당 기기의 SDcard에 저장 됩니다.
 




▒ 4. 파일첨부 및 스크린샷.    

TestImageCrop.zip








댓글
  • 이전 댓글 더보기
  • 프로필사진 안녕하세요 위에 막시무스님과 같은문제입니다. crop버튼을 누르면 원래화면으로 되돌아가고 사용할 수 없는 파일입니다라는 토스트가 나타납니다.
    단말기 기종은 갤럭시s호핀(2.3.6)이고 파일은 이미지(jpg)입니다.ㅠㅠ
    2012.08.08 09:52
  • 프로필사진 안녕하세요 문제해결했습니다
    메니페스트에 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 이걸넣었어야되는군요 ㅠㅠ ㅋ
    2012.08.09 10:16
  • 프로필사진 아라비안왕자 다행이시네요^^ 좋은 정보 감사 드립니다. 2012.08.09 15:21 신고
  • 프로필사진 감사합니다. 정말로 감사드립니다.
    덕분에 쉽게 해결했습니다.
    복많이받으세요~^^
    정말 감사합니다.
    2012.09.13 17:21
  • 프로필사진 아라비안왕자 ^^ 다행이네요 열코딩!! 2012.09.14 00:43 신고
  • 프로필사진 지나가던오리 부왘 찾아다니던 정보! 감사합니다! 2012.10.01 20:50
  • 프로필사진 아라비안왕자 넵!! 잘 사용하세요~! 2012.10.13 10:12 신고
  • 프로필사진 나이값하기 제가 작업하려던 내용인데 노력의 결과물을 이렇게 공유해주셔서 정말 감사드립니다.
    건강하시고 복 많이받으십셔!
    2012.11.01 11:04
  • 프로필사진 아라비안왕자 네^^ 답변이 늦었지만 나이님도 복많이 받으세요~!! 2012.11.28 19:40 신고
  • 프로필사진 뽀오 항상 좋은 설명 감사합니다. :-) 2013.05.14 16:53
  • 프로필사진 아이우에오 여기서 mms 보낼때 전송 버튼 없이 바로 보내는 방법은 없는가요?ㅠ 2013.05.27 18:21
  • 프로필사진 mstst 많은 도움 됬습니다~ 감사합니다 ^^
    그런데 갤러리어플을 열었을 때 보이는 폴더 말고 이렇게 여기 사진 앨범을 클릭하면
    더 많은 폴더가 보이던데요.. 기존 갤러리에서 보이지 않는 다른 폴더에서 사진을 불러오면
    "사진을 불러 올 수 없습니다"라는 토스트가 뜨는데 왜 이럴까요? ㅜ
    카톡에서 프로필 사진 설정할때는 다른 폴더에서 선택해도 잘 되던데.. 혹시 방법을 알고 계시나 해서 여쭤 봅니다~
    2013.09.15 02:15
  • 프로필사진 파라라 사진 크롭받은걸 다른 액티비티의 이미지뷰에 사진이 뜨게하는법을 잘모르겠네요 어떻게 해야할까요? 2013.10.28 07:49
  • 프로필사진 안녕하세요 갤러리를 통해 크롭하는건 제대로 작동하는데, 카메라를 통해 사진을 찍은 후 크롭하게 되면 "항목을 찾을 수 없습니다'라는 토스트가 발생합니다.

    해결할려면 어떻게 해야할까요?
    2013.12.19 23:19
  • 프로필사진 예쁜꽃이피었으면 와 완전 정리 잘 되어있어요~ 감사합니다.
    담아갈게요~
    2014.08.28 17:55 신고
  • 프로필사진 yonoo88 혹시 캣캣에서 문제없나요? 저도 아이군님 블로그 보고 만들었었는데 킷캣에서 문제가 있다고 합니다.
    카메라를 불러오기 하면 그냥 카메라 불러오기 화면이 꺼져 버린다고 하네요. 앱이 죽는 현상은 아니고 그 카메라 불러오는 화면만 꺼진다고 합니다.
    키캣에서 수정해줘야할 코드가 잇나요?
    2014.11.19 20:47 신고
  • 프로필사진 김병희 이렇게 잘 정리된 페이지를 기대하지 않고 ... 구글링하다가 우연히 발견해서 받아 일단 돌려 보고 ...
    소스 잠깐 들여다 보았는데 환상적입니다.
    찬찬히 배우고 다듬어 잘 쓰겠습니다.
    감사합니다.
    2017.04.06 18:08
  • 프로필사진 김병희 혹시 도와주실 수 있을까요?

    <질문> 삼성 갤럭시폰에서 파일도 존재하고 파일크기도 0이 아닌데 FileNotFoundException 에러 나타나는 문제

    구글링해도 제 힘으로 답을 구하지 못해 도움을 청합니다.

    도와주시면 정말로 감사하겠습니다.

    1. 테스트 환경 : 폰(삼성 갤럭시S3/갤럭시S5), 파일(MMS에 첨부된 .vcf 주소록파일), 안드로이드 스튜디오 2.3, 윈7(64비트)

    아래 코드의 실행 결과 : "파일 OK/2025bytes/주소록 내용을 읽을 수 없습니다."

    즉 exists 메소드로 검사하면 파일도 존재하고, length 메소드로 검사하면 파일크기도 0이 아니므로 분명 존재하는 파일입니다.

    그런데 BufferedReader/readLine으로 파일을 읽으면 FileNotFoundException 에러를 내고 파일 내용을 읽지 못합니다.

    다른 테스트 폰 엘지 G2에서는 정상으로 읽힙니다.

    // 주소록 보이기
    public void viewVcf(final String filePath) {
    File vcfFile = new File(filePath);
    if (vcfFile.exists()) {
    long lFileSize = vcfFile.length();
    tv_unique.setText("파일 OK/"+lFileSize+"bytes";);
    String content = readFile(filePath);
    if (content.isEmpty())
    tv_unique.setText(tv_unique.getText().toString()+"/주소록 내용을 읽을 수 없습니다.";);
    else {
    ...
    }
    }
    else {
    report10sec("주소록 파일이 없습니다.";);
    }
    }

    2. 테스트 환경 : 폰(삼성 갤럭시S3/갤럭시S5), 파일(MMS에 첨부된 .mp4 동영상파일), 안드로이드 스튜디오 2.3, 윈7(64비트)

    동영상 파일의 경우도 위와 비슷합니다.

    "파일 OK/707989bytes"

    // 비디오 재생
    public void viewVideo(final String filePath) {
    File videoFile = new File(filePath);
    if (videoFile.exists()) {
    long lFileSize = videoFile.length();
    tv_unique.setText("파일 OK/"+lFileSize+"bytes";);
    ...
    }
    else {
    report10sec("비디오 파일이 없습니다.";);
    }
    }

    위 ... 부분의 코드에 따라서 2가지 테스트 결과입니다.

    1) startActivity(intent);

    삼성폰, 엘지폰 모두 비디오가 재생되지 않습니다.

    (엘지) java.lang.NullPointerException: Attempt to invoke virtual method 'android.app.ActivityThread$ApplicationThread android.app.ActivityThread.getApplicationThread()' on a null object reference

    (삼성) java.lang.NullPointerException

    2) videoView.start();

    엘지폰에서는 정상으로 재생이 됩니다.

    삼성폰에서는 에러 로그는 없으나, "재생할 수 없는 동영상입니다./확인" 메시지가 뜨고 비디오가 재생되지 않습니다.

    읽어 주셔서 고맙습니다.
    2017.04.08 16:02
  • 프로필사진 김병희 <답변> 존재하고 크기도 있는 파일의 FileNotFoundException = 권한 없음/[Android] http://blog.daum.net/andro_java/1121 2017.04.11 01:43
  • 프로필사진 김병희 case CROP_FROM_CAMERA: 코드 - 이미지뷰에 보이지 않아 고쳐 보았습니다.

    case CROP_FROM_CAMERA: {
    Log.w(TAG, "CROP_FROM_CAMERA";);
    // Crop 된 이미지를 넘겨 받습니다.
    Log.w(TAG, "mImageCaptureUri = " + mImageCaptureUri);
    String full_path = mImageCaptureUri.getPath();
    Bitmap photo = BitmapFactory.decodeFile(full_path);
    mPhotoImageView.setImageBitmap(photo);
    break;
    }

    이제 보입니다.
    2017.04.19 15:54
  • 프로필사진 김민수 xml 전체소스좀 알려주시면 감사하겠습니다 ㅠㅠ
    2017.05.23 13:45
  • 프로필사진 아라비안왕자 현재 코드가 없어서요ㅜ 죄송합니다 2017.05.23 15:25 신고
  • 프로필사진 안슥 에러는 없는데 앨범에서 사진을 눌렀는데 사진이 안불러와 지네여... 무슨 문제가 있을까요?? 2017.06.13 01:12
  • 프로필사진 핫스 이미지를 짤랐는데 엉청 깨져서 저장이 되는 방안이 있나요>?? 2017.06.13 02:33
  • 프로필사진 tttt 혹시 갤러리에서 사진을 불러오거나 사진 촬영후 이미지를 가로로 정렬하고 싶은데 어떤 기술을 사용하면 되나요? 2017.07.09 14:36
댓글쓰기 폼


Total
4,111,066
Today
441
Yesterday
1,213
링크
글 보관함
«   2019/06   »
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30