최초작성 : 17.04.13
최종수정 : 17.12.17
- rotate함수 추가 (17.08.16)
- 권한 요청 포스팅 링크 추가 (17.12.17)
- 카메라로 사진 가져올시 7.0 대응 (17.12.17)
앱을 만들다 보면 사진을 사용하여 이미지뷰에 뿌려주거나 업로드하는 경우가 종종 있습니다. 카메라나 기기 갤러리의 접근하기 위해서는 권한이 필요합니다. 권한 포스팅을 참고해주세요. 권한 요청 포스팅 보기 |
가져온 이미지 리사이즈는 아래 포스팅을 참고해주세요
권한 설정
카메라와 갤러리 사진을 가져오기 위해 권한이 필요합니다. 권한에 대한 자세한 내용은 본 블로그에 권한 체크하기를 참고해주세요 |
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
카메라로 찍은 사진을 가져오는 경우
인텐트를 통해 카메라를 호출합니다. 'CAMERA_CODE'는 requestCode 선택한 사진에 대한 요청 값을 구분하는 용도입니다. |
private final int CAMERA_CODE = 1111;
private void selectPhoto() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, CAMERA_CODE);
}
7.0 이슈 대응
-코드 수정
7.0 이전 버전은 상위의 코드처럼 간단하게 수행이 가능했지만 보안상의 이슈로 'FileProvider.getUriForFile()'을 통해 사진의 uri를 가져오는데 이를 수행하기 위해선 'AndroidMenifest.xml'에 명시해야합니다. 7.0 버전에 대한 상세한 이슈는 추후 포스팅으로 다루겠습니다. |
private Uri photoUri;
private String currentPhotoPath;//실제 사진 파일 경로
String mImageCaptureName;//이미지 이름
private void selectPhoto() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (intent.resolveActivity(getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
}
if (photoFile != null) {
photoUri = FileProvider.getUriForFile(this, getPackageName(), photoFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
startActivityForResult(intent, CAMERA_CODE);
}
}
}
}
-AndroidManifest.xml 파일 수정
authorities에는 프로젝트의 패키지명을 작성함으로써 상단 'FileProvider.getUriForFile()'가 정상작동합니다. 그리고 res폴더 하위에 xml폴더를 생성하고 'file_path' 이름의 xml파일을 생성해야합니다. |
<application
.....>
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="패키지명"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_path" />
</provider>
<activity
...>
-file_path.xml 파일
파일의 경로를 명시해주는 파일로 path에 해당하는 값은 추후 'Enviroment.getExternalStorageDirectory()' 다음에 사용될 경로 이름이므로 자유롭게 사용하되 카메라 사진을 가져올때 경로 이름과 일치해야한다.
|
<paths xmlns:android = "http://schemas.android.com/apk/res/android">
<external-path name="hidden" path="path"/>
</paths>
-파일 생성
카메라로 찍은 사진을 실제 파일로 생성하는 코드입니다. 상단에 지정한 path이름과 일치해야 에러없이 해당 기능을 수행합니다. |
private File createImageFile() throws IOException {
File dir = new File(Environment.getExternalStorageDirectory() + "/path/");
if (!dir.exists()) {
dir.mkdirs();
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
mImageCaptureName = timeStamp + ".png";
File storageDir = new File(Environment.getExternalStorageDirectory().getAbsoluteFile() + "/path/"+ mImageCaptureName);
currentPhotoPath = storageDir.getAbsolutePath();
return storageDir;
}
카메라로 찍은 사진 적용
private void getPictureForPhoto() {
Bitmap bitmap = BitmapFactory.decodeFile(currentPhotoPath);
ExifInterface exif = null;
try {
exif = new ExifInterface(currentPhotoPath);
} catch (IOException e) {
e.printStackTrace();
}
int exifOrientation;
int exifDegree;
if (exif != null) {
exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
exifDegree = exifOrientationToDegrees(exifOrientation);
} else {
exifDegree = 0;
}
ivImage.setImageBitmap(rotate(bitmap, exifDegree));//이미지 뷰에 비트맵 넣기
}
갤러리에서 사진을 가져오는 경우
인텐트를 통해 갤러리를 호출합니다 . 'GALLERY_CODE'는 requestCode 선택한 사진에 대한 요청 값을 구분하는 용도입니다. setType 에 대한 내용은 해당 포스팅 마지막에 나열하겠습니다. |
private final int GALLERY_CODE=1112;
private void selectGallery() {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setData(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
startActivityForResult(intent, GALLERY_CODE);
}
선택한 사진 데이터 처리
카메라로 사진을 찍거나 갤러리에서 사진 선택에 대한 사용자가 응답을 할경우 'onActivityResult'가 실행되는데 사진을 선택했을 경우 resultCode값은 'RESULT_OK' 가 취소 했을때는 'RESULT_CANCEL' 입니다. 사진 데이터는 intent 타입으로 반환됩니다. |
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case GALLERY_CODE:
sendPicture(data.getData()); //갤러리에서 가져오기
break;
case CAMERA_CODE:
getPictureForPhoto(); //카메라에서 가져오기
break;
default:
break;
}
}
}
private void sendPicture(Uri imgUri) {
String imagePath = getRealPathFromURI(imgUri); // path 경로
ExifInterface exif = null;
try {
exif = new ExifInterface(imagePath);
} catch (IOException e) {
e.printStackTrace();
}
int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int exifDegree = exifOrientationToDegrees(exifOrientation);
Bitmap bitmap = BitmapFactory.decodeFile(imagePath);//경로를 통해 비트맵으로 전환
ivImage.setImageBitmap(rotate(bitmap, exifDegree));//이미지 뷰에 비트맵 넣기
}
사진의 회전값 가져오기
사진의 회전값을 처리하지 않으면 사진을 찍은 방향대로 이미지뷰에 처리되지 않습니다. |
private int exifOrientationToDegrees(int exifOrientation) {
if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
return 90;
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
return 180;
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
return 270;
}
return 0;
}
사진을 정방향대로 회전하기
private Bitmap rotate(Bitmap src, float degree) {
// Matrix 객체 생성
Matrix matrix = new Matrix();
// 회전 각도 셋팅
matrix.postRotate(degree);
// 이미지와 Matrix 를 셋팅해서 Bitmap 객체 생성
return Bitmap.createBitmap(src, 0, 0, src.getWidth(),
src.getHeight(), matrix, true);
}
사진의 절대경로 구하기
사진이 저장된 절대 경로를 가져옵니다. |
private String getRealPathFromURI(Uri contentUri) {
int column_index=0;
String[] proj = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(contentUri, proj, null, null, null);
if(cursor.moveToFirst()){
column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
}
return cursor.getString(column_index);
}
이상 갤러리와 카메라에서 이미지를 가져오는 방법이였습니다.
그 외에 사진 및 파일을 탐색할때 인텐트의 타입의 따라 보여지는 파일들과 뷰가 달라질 수 있습니다.
모든 type의 파일들을 호출 하려면
- intent.setType("*/*"); |
이미지 파일을 호출 하려면
- intent.setType("image/*"); |
비디오 파일을 호출 하려면
- intent.setType("video/*"); |
위에 나온것 외에도 자신이 원하는 파일의 경로나 타입을 통해 sort해서 보여줄 수 있습니다.
※필자 본인을 위한 포스팅으로써 다소 미흡할 수 있습니다. 그래도 궁금하신점이 있으시다면 최대한 도움을 드리도록 하겠습니다.※
출처: http://superwony.tistory.com/5 [개발자 키우기]
출처: http://superwony.tistory.com/5 [개발자 키우기]
'Android' 카테고리의 다른 글
서비스 종료 하기 (0) | 2018.06.14 |
---|---|
다른 엑티비티에서 이전 엑티비티 종료하기 (0) | 2018.06.14 |
안드로이드 엑티비티 배경 투명하게 (0) | 2018.06.12 |
리사이클러뷰 마지막 아이템 위치로 스크롤 하기 (0) | 2018.06.05 |
안드로이드 - PC 소캣통신 유튜브 동영상 (0) | 2018.06.03 |