안녕하세요. 블랙진입니다.!!
카메라와 갤러리에서 이미지 가져오기를 단계별로 포스팅을 진행하고 있습니다.
1. 카메라와 갤러리에서 이미지 가져오기
2. Nougat(Android OS 7) 대응하기
3. 카메라회전 각도를 고려한 이미지 가져오기
4. 가져온 이미지 크롭(Crop) 하기
이전 포스팅에 이어 카메라 회전 각도에 맞춰 이미지 가져오는 법을 포스팅 하겠습니다.
Chapter 3. 카메라회전 각도를 고려한 이미지 가져오기
이슈
안드로이드 기종에 따라 카메라 회전각도가 달라 촬영한 이미지의 방향이 다를 경우가 발생
해결방안
카메라 회전 각도를 가져와 이미지를 변형해 줍니다.
0. Package
1. ImageResizeUtils 기능
ImageResizeUtils.class 는 2가지 기능을 가지고 있습니다.
첫번째. 이미지의 사이즈를 커스텀마이징 할 수 있습니다.
두번째. 카메라 촬영일 경우 회전 각도를 가져와 이미지를 회전시킵니다.
그럼 ImageResizeUtils 에 대해 살펴보겠습니다.
public class ImageResizeUtils {
public static void resizeFile(File file, File newFile, int newWidth, Boolean isCamera) {
//...
}
}
위와 같이 4개의 변수를 받아옵니다.
1). FIle
- 내가 변형시키고 싶은 파일
2). newFile
- 변형시킨 파일을 저장할 파일
3). newWidth
- 리사이징 할 크기 (이미지의 가로와 세로를 비교해서 더 긴쪽의 사이즈를 newWidth 값으로 변형해줍니다.)
4). isCamera
- 카메라에서 온 이미지인 경우 회전각도를 반영
위와 같은 4가지 변수를 가지고 있습니다.
아래는 ImageResizeUtils 의 전체 코드입니다. 자세한 설명은 주석을 보시면 충분히 이해하실 수 있을 겁니다.
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.util.Log;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ImageResizeUtils {
/**
* 이미지의 너비를 변경한다.
* @param file
* @param newFile
* @param newWidth
* @param isCamera
*/
public static void resizeFile(File file, File newFile, int newWidth, Boolean isCamera) {
String TAG = "blackjin";
Bitmap originalBm = null;
Bitmap resizedBitmap = null;
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPurgeable = true;
options.inDither = true;
originalBm = BitmapFactory.decodeFile(file.getAbsolutePath(), options);
if(isCamera) {
// 카메라인 경우 이미지를 상황에 맞게 회전시킨다
try {
ExifInterface exif = new ExifInterface(file.getAbsolutePath());
int exifOrientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int exifDegree = exifOrientationToDegrees(exifOrientation);
Log.d(TAG,"exifDegree : " + exifDegree);
originalBm = rotate(originalBm, exifDegree);
} catch (IOException e) {
e.printStackTrace();
}
}
if(originalBm == null) {
Log.e(TAG,("파일 에러"));
return;
}
int width = originalBm.getWidth();
int height = originalBm.getHeight();
float aspect, scaleWidth, scaleHeight;
if(width > height) {
if(width <= newWidth) return;
aspect = (float) width / height;
scaleWidth = newWidth;
scaleHeight = scaleWidth / aspect;
} else {
if(height <= newWidth) return;
aspect = (float) height / width;
scaleHeight = newWidth;
scaleWidth = scaleHeight / aspect;
}
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bitmap
matrix.postScale(scaleWidth / width, scaleHeight / height);
// recreate the new Bitmap
resizedBitmap = Bitmap.createBitmap(originalBm, 0, 0, width, height, matrix, true);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
resizedBitmap.compress(CompressFormat.JPEG, 80, new FileOutputStream(newFile));
} else {
resizedBitmap.compress(CompressFormat.PNG, 80, new FileOutputStream(newFile));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if(originalBm != null){
originalBm.recycle();
}
if (resizedBitmap != null){
resizedBitmap.recycle();
}
}
}
/**
* EXIF 정보를 회전각도로 변환하는 메서드
*
* @param exifOrientation EXIF 회전각
* @return 실제 각도
*/
public static 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;
}
/**
* 이미지를 회전시킵니다.
*
* @param bitmap 비트맵 이미지
* @param degrees 회전 각도
* @return 회전된 이미지
*/
public static Bitmap rotate(Bitmap bitmap, int degrees)
{
if(degrees != 0 && bitmap != null)
{
Matrix m = new Matrix();
m.setRotate(degrees, (float) bitmap.getWidth() / 2,
(float) bitmap.getHeight() / 2);
try
{
Bitmap converted = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(), m, true);
if(bitmap != converted)
{
bitmap.recycle();
bitmap = converted;
}
}
catch(OutOfMemoryError ex)
{
// 메모리가 부족하여 회전을 시키지 못할 경우 그냥 원본을 반환합니다.
}
}
return bitmap;
}
}
2. 프로젝트에 적용하기
전역변수에 isCamera 를 선언 해줍니다.
private Boolean isCamera = false;
이는 이미지를 리사이징 하는 단계에서 카메라에서 온 화면인지 앨범에서 온 화면인지 구분할 용도입니다.
private void goToAlbum() {
isCamera = false;
...
}
private void takePhoto() {
isCamera = true;
...
}
goToAlbum, takePhoto 함수에서 isCamera 의 변수를 설정해 줍니다.
private void setImage() {
ImageView imageView = findViewById(R.id.imageVeiew);
ImageResizeUtils.resizeFile(tempFile, tempFile, 1280, isCamera);
BitmapFactory.Options options = new BitmapFactory.Options();
Bitmap originalBm = BitmapFactory.decodeFile(tempFile.getAbsolutePath(), options);
Log.d(TAG, "setImage : " + tempFile.getAbsolutePath());
imageView.setImageBitmap(originalBm);
}
setImage 단계에서 최종 파일인 tempFile을 리사이징 해줍니다.
ImageResizeUtils.resizeFile(tempFile, tempFile, 1280, isCamera);
첫 번째 파라미터에 변형시킬 tempFile 을 넣었습니다.
두 번째 파라미터에는 변형시킨 파일을 다시 tempFile에 저장해 줍니다.
세 번째 파라미터는 이미지의 긴 부분을 1280 사이즈로 리사이징 하라는 의미입니다.
네 번째 파라미터를 통해 카메라에서 가져온 이미지인 경우 카메라의 회전각도를 적용해 줍니다.(앨범에서 가져온 경우에는 회전각도를 적용 시킬 필요가 없겠죠?)
Chapter3. 깃허브
관련 포스팅
1. 카메라와 갤러리에서 이미지 가져오기
2. Nougat(Android OS 7) 대응하기
3. 카메라회전 각도를 고려한 이미지 가져오기
4. 가져온 이미지 크롭(Crop) 하기