Android : 갤러리에서로드 된 비트 맵이 ImageView에서 회전 됨


138

미디어 갤러리의 이미지를 비트 맵에로드하면 휴대폰을 세로로 잡고 카메라로 촬영 한 사진이 회전되어 세로로 표시 되더라도 항상 가로 사진을 볼 수 있다는 점을 제외하면 모든 것이 제대로 작동합니다. 갤러리. 그 이유는 무엇이며 올바르게로드하려면 어떻게해야합니까?


답변:


40

이미지의 EXIF ​​데이터를 보셨습니까? 사진을 촬영할 때 카메라의 방향을 알 수 있습니다.


2
당신이 옳습니다, 물론 해결책이었습니다. 나중에 별도의 답변으로 예제로 코드를 게시 할 것입니다.하지만 올바른 경로로 이동했기 때문에이 코드를 수락 된 것으로 표시합니다.
마누엘

182

예를 들어 ...

먼저 ExifInterface를 만들어야합니다.

ExifInterface exif = new ExifInterface(filename);

그런 다음 이미지의 방향을 잡을 수 있습니다.

orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);

방향 값의 의미는 다음과 같습니다. http://sylvana.net/jpegcrop/exif_orientation.html

따라서 가장 중요한 값은 3, 6 및 8 ExifInterface.ORIENTATION_ROTATE_90입니다. 예를 들어 방향 이 6 인 경우 이미지를 다음과 같이 회전 할 수 있습니다.

Matrix matrix = new Matrix();
matrix.postRotate(90);
rotatedBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(), matrix, true);

그래도 간단한 예일뿐입니다. 실제 회전을 수행하는 다른 방법이 있다고 확신합니다. 그러나 StackOverflow에서도 찾을 수 있습니다.


5
다른 방향에 대한 모든 회전 값은 다음과 같습니다. 3 : 180, 6:90, 8 : 270
표시 이름

103
명명 된 상수를 사용할 수있는 경우 마법 번호를 사용하지 마십시오 : ExifInterface.ORIENTATION_NORMAL, ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_ROTATE_180, ExifInterface.ORIENTATION_ROTATE_270.
d60402

29
의 조심 OutOfMemoryError동시에 메모리에 두 개의 비트 맵을 누르고있는이 방법을 사용하는 경우.
Alex Bonel

또 다른 완전한 예 ... stackoverflow.com/questions/14066038/…
CGR

64

이것은 완전한 솔루션입니다 (Facebook SDK의 Hackbook 예제에 있음). 파일 자체에 액세스 할 필요가 없다는 이점이 있습니다. 콘텐츠 리졸버에서 이미지를로드 할 때 (예 : 앱이 공유 사진 의도에 응답하는 경우) 매우 유용합니다.

public static int getOrientation(Context context, Uri photoUri) {
    /* it's on the external media. */
    Cursor cursor = context.getContentResolver().query(photoUri,
            new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);

    if (cursor.getCount() != 1) {
        return -1;
    }

    cursor.moveToFirst();
    return cursor.getInt(0);
}

그리고 다음과 같이 회전 된 비트 맵을 얻을 수 있습니다. 이 코드는 이미지를 불행히도 MAX_IMAGE_DIMENSION으로 축소합니다. 그렇지 않으면 메모리가 부족할 수 있습니다.

public static Bitmap getCorrectlyOrientedImage(Context context, Uri photoUri) throws IOException {
    InputStream is = context.getContentResolver().openInputStream(photoUri);
    BitmapFactory.Options dbo = new BitmapFactory.Options();
    dbo.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(is, null, dbo);
    is.close();

    int rotatedWidth, rotatedHeight;
    int orientation = getOrientation(context, photoUri);

    if (orientation == 90 || orientation == 270) {
        rotatedWidth = dbo.outHeight;
        rotatedHeight = dbo.outWidth;
    } else {
        rotatedWidth = dbo.outWidth;
        rotatedHeight = dbo.outHeight;
    }

    Bitmap srcBitmap;
    is = context.getContentResolver().openInputStream(photoUri);
    if (rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION) {
        float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
        float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
        float maxRatio = Math.max(widthRatio, heightRatio);

        // Create the bitmap from file
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = (int) maxRatio;
        srcBitmap = BitmapFactory.decodeStream(is, null, options);
    } else {
        srcBitmap = BitmapFactory.decodeStream(is);
    }
    is.close();

    /*
     * if the orientation is not 0 (or -1, which means we don't know), we
     * have to do a rotation.
     */
    if (orientation > 0) {
        Matrix matrix = new Matrix();
        matrix.postRotate(orientation);

        srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
                srcBitmap.getHeight(), matrix, true);
    }

    return srcBitmap;
}

1
MAX_IMAGE_DIMENDION의 의미는 무엇입니까?
Sazzad Hissain Khan

3
얻는 이미지의 최대 너비 또는 높이입니다. 즉, 512x512 이미지 만 필요하다고 가정하십시오. 24 메가 픽셀 이미지를 열면 전체 샘플링을 열고 축소하는 것보다 이미 서브 샘플링 된 이미지를 여는 것이 훨씬 효율적입니다. 어쨌든 모든 메모리가 소모 될 수 있습니다.
Timmmm

내 프로그램에서 활동 / 조각의 Bitmap 변수를 개인 정적으로 정의하고 함수에서 null로 설정하는 것이 유용하다는 것을 알았습니다. 그때 메모리 문제가 줄었습니다.
Gunnar Bernstein

MAX_IMAGE_WIDTH 및 MAX_IMAGE_HEIGHT에 MAX_IMAGE_DIMENDION을 대체 똑똑
fnc12

내 시간을 많이 절약 :) 많은 감사합니다. 널 커서를 얻는 사람들을 위해, 당신은 시도 할 수 있습니다 ExifInterface exif = new ExifInterface(photoUri.getPath());다음과 exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1)방향을 얻기 위해 (예를 들어 ORIENTATION_ROTATE_90, ORIENTATION_ROTATE_180)
아툴

60

이 게시물의 도움을 받아이 코드로 내 경우에 해결했습니다.

            Bitmap myBitmap = getBitmap(imgFile.getAbsolutePath());

            try {
                ExifInterface exif = new ExifInterface(imgFile.getAbsolutePath());
                int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
                Log.d("EXIF", "Exif: " + orientation);
                Matrix matrix = new Matrix();
                if (orientation == 6) {
                    matrix.postRotate(90);
                }
                else if (orientation == 3) {
                    matrix.postRotate(180);
                }
                else if (orientation == 8) {
                    matrix.postRotate(270);
                }
                myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true); // rotating bitmap
            }
            catch (Exception e) {

            }
            ImageView img = (ImageView) findViewById(R.id.imgTakingPic);
            img.setImageBitmap(myBitmap);

누군가의 시간을 절약하기를 바랍니다!


제안 편집 : 방향 6, 3, 8에 대한 적절한 명명 된 상수가 있습니까? 회전이 필요하지 않은 경우 새 비트 맵을 건너 뛸 수 없습니까?
Cee McSharpface

@ d60402가 이전에 주석에서 말했듯이 명명 된 상수를 사용할 수 있습니다 : ExifInterface.ORIENTATION_NORMAL, ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_ROTATE_180, ExifInterface.ORIENTATION_ROTATE_270.
Adrian

42

유틸리티를 사용하여 헤비 리프팅을 수행하십시오.

9 는 EXIF ​​데이터를 처리하고 이미지를 올바른 방향으로 회전시키는 힘든 작업을 처리하는 간단한 유틸리티를 만들었습니다.

유틸리티 코드는 https://gist.github.com/9re/1990019 에서 찾을 수 있습니다.

간단히 이것을 다운로드하여 프로젝트 src디렉토리에 추가 ExifUtil.rotateBitmap()하고 올바른 방향을 얻는 데 사용하십시오.

String imagePath = photoFile.getAbsolutePath();             // photoFile is a File class.
Bitmap myBitmap  = BitmapFactory.decodeFile(imagePath);

Bitmap orientedBitmap = ExifUtil.rotateBitmap(imagePath, myBitmap);

2
나를 위해 작동합니다! OutOfMemoryError를 피하기 위해 ExifUtil.rotateBitmap ()에 전달하기 전에 비트 맵을 HD 형식으로 크기를 조정했습니다. Bitmap resized = Bitmap.createScaledBitmap (myBitmap, 720, 1280, true); 사진 = ExifUtil.rotateBitmap (picturePath, 크기 조정);
Phil

@ 필 니스 추가. 나는 그것에 빠져들지 않았다 (나는 더 오래된 똥 티어 안드로이드 장치를 사용하고있다). 그러나 그것은 정말로 알고있다.
Joshua Pinter

3
당신은 영웅 내 친구입니다 :)
klutch

@klutch 방금 내 하루를 보냈습니다. :) 공정하게, 9re는 유틸리티 코드를 작성하여 실제 영웅이되었습니다.
Joshua Pinter

1
@sreekanthKarumanaghat 대단한 질문! 나는 이것이 내가 이것에 깊었을 때 왜 이것이 의미가 있는지 알았지 만 지금은 나에게도 중복되는 것처럼 보인다. React Native에서 너무 많은 시간을 보냈습니다.
Joshua Pinter

8

갤러리가 회전 된 이미지를 올바르게 표시하지만 ImageView는 표시하지 않기 때문에 여기를보십시오.

                    myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(),optionss);
                    ExifInterface exif = new ExifInterface(selectedImagePath);
                    int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
                    int rotationInDegrees = exifToDegrees(rotation);
                    deg = rotationInDegrees;
                    Matrix matrix = new Matrix();
                    if (rotation != 0f) {
                        matrix.preRotate(rotationInDegrees);
                        myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true);
                    }

그리고 당신은 이것을 필요로합니다 :

private static int exifToDegrees(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;    
} 

5

더 이상 찾을 수없는 게시물 덕분에 많은 시도 후에 작동하도록했습니다.

Exif가 항상 작동하는 것 같지만 파일 경로를 얻는 것이 어려웠습니다. 내가 찾은 코드는 4.4 이전과 4.4 이후의 API를 다르게 만듭니다. 기본적으로 4.4+의 그림 URI에는 "com.android.providers"가 포함되어 있습니다. 이 유형의 URI의 경우 코드는 DocumentsContract를 사용하여 그림 ID를 가져온 다음 ContentResolver를 사용하여 쿼리를 실행하지만 이전 SDK의 경우 코드는 ContentResolver를 사용하여 URI를 쿼리합니다.

다음은 코드입니다 (죄송합니다 누가 게시했는지 신용 할 수 없습니다).

/**
 * Handles pre V19 uri's
 * @param context
 * @param contentUri
 * @return
 */
public static String getPathForPreV19(Context context, Uri contentUri) {
    String res = null;

    String[] proj = { MediaStore.Images.Media.DATA };
    Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
    if(cursor.moveToFirst()){;
        int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
        res = cursor.getString(column_index);
    }
    cursor.close();

    return res;
}

/**
 * Handles V19 and up uri's
 * @param context
 * @param contentUri
 * @return path
 */
@TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPathForV19AndUp(Context context, Uri contentUri) {
    String wholeID = DocumentsContract.getDocumentId(contentUri);

    // Split at colon, use second item in the array
    String id = wholeID.split(":")[1];
    String[] column = { MediaStore.Images.Media.DATA };

    // where id is equal to
    String sel = MediaStore.Images.Media._ID + "=?";
    Cursor cursor = context.getContentResolver().
            query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    column, sel, new String[]{ id }, null);

    String filePath = "";
    int columnIndex = cursor.getColumnIndex(column[0]);
    if (cursor.moveToFirst()) {
        filePath = cursor.getString(columnIndex);
    }

    cursor.close();
    return filePath;
}

public static String getRealPathFromURI(Context context,
        Uri contentUri) {
    String uriString = String.valueOf(contentUri);
    boolean goForKitKat= uriString.contains("com.android.providers");

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && goForKitKat) {
            Log.i("KIKAT","YES");
            return getPathForV19AndUp(context, contentUri);
        } else {

            return getPathForPreV19(context, contentUri);
        }
}

많은 감사합니다. 몇 시간 동안 커서와 exif를 사용한 후에는이 시간이 절약 될 수 있습니다. 당신이 말했듯이, 실제로 exif는 커서 반환 대신 진실되고 신뢰할 수있는 데이터를 가지고 있습니다. 작동하는 것보다 정확한 경로를 지정하십시오.
asozcan

3

당신은 그냥 SD 카드에서 경로를 읽고 다음 코드를 수행 할 수 있습니다 ... 그것은 회전 한 후 기존 사진을 대체합니다 ..

Not : Exif는 대부분의 장치에서 작동하지 않으므로 잘못된 데이터를 제공하므로 원하는 정도로 저장하기 전에 회전을 하드 코딩하는 것이 좋습니다. postRotate의 각도 값을 원하는 것으로 변경하면됩니다.

    String photopath = tempphoto.getPath().toString();
    Bitmap bmp = BitmapFactory.decodeFile(photopath);

    Matrix matrix = new Matrix();
    matrix.postRotate(90);
    bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);

    FileOutputStream fOut;
    try {
        fOut = new FileOutputStream(tempphoto);
        bmp.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
        fOut.flush();
        fOut.close();

    } catch (FileNotFoundException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

}

2
이것은 회전하지만 이미지 회전이 필요한지 여부는 알 수 없습니다.
MSaudi

3

코 틀린 코드 :

if (file.exists()){
    val bitmap = BitmapFactory.decodeFile(file.absolutePath)

    val exif = ExifInterface(file.absoluteFile.toString())
    val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
    val matrix = Matrix()

    when(orientation){
        ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90F)
        ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180F)
        ExifInterface.ORIENTATION_ROTATE_270 -> matrix.postRotate(270F)
    }

    val rotatedBitmap = Bitmap.createBitmap(bitmap, 0,0 , bitmap.width, bitmap.height, matrix, true)
    bitmap.recycle()
    iv_capture.setImageBitmap(rotatedBitmap)
}

2

Teo Inke의 답변을 개선했습니다. 실제로 필요하지 않으면 더 이상 이미지를 회전시키지 않습니다. 또한 읽기 쉽고, 더 빨리 실행됩니다.

// Load Image
Bitmap bitmap = BitmapFactory.decodeFile(filePath);

// Rotate Image if Needed
try
{
    // Determine Orientation
    ExifInterface exif = new ExifInterface(filePath);
    int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);

    // Determine Rotation
    int rotation = 0;
    if      (orientation == 6)      rotation = 90;
    else if (orientation == 3)      rotation = 180;
    else if (orientation == 8)      rotation = 270;

    // Rotate Image if Necessary
    if (rotation != 0)
    {
        // Create Matrix
        Matrix matrix = new Matrix();
        matrix.postRotate(rotation);

        // Rotate Bitmap
        Bitmap rotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); 

        // Pretend none of this ever happened!
        bitmap.recycle();
        bitmap = rotated;
        rotated = null;
     }
}
catch (Exception e)
{
    // TODO: Log Error Messages Here
}

// TODO: Use Result Here
xxx.setBitmap(bitmap);

2

가장 먼저 필요한 것은 실제 파일 경로입니다. 경로가 훌륭하다면 URI를 사용하는 경우이 방법을 사용하여 실제 경로를 얻으십시오.

 public static String getRealPathFromURI(Uri contentURI,Context context) {
    String path= contentURI.getPath();
    try {
        Cursor cursor = context.getContentResolver().query(contentURI, null, null, null, null);
        cursor.moveToFirst();
        String document_id = cursor.getString(0);
        document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
        cursor.close();

        cursor = context.getContentResolver().query(
                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
        cursor.moveToFirst();
        path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
        cursor.close();
    }
    catch(Exception e)
    {
        return path;
    }
    return path;
}

예를 들어 비트 맵을 추출하십시오.

  try {
                            Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImage);

                        }
                        catch (IOException e)
                        {
                            Log.e("IOException",e.toString());
                        }

원하는 경우 decodeFile ()을 대신 사용할 수 있습니다.

이제 비트 맵이 있고 실제 경로는 이미지의 방향을 얻습니다.

 private static int getExifOrientation(String src) throws IOException {
        int orientation = 1;

        ExifInterface exif = new ExifInterface(src);
        String orientationString=exif.getAttribute(ExifInterface.TAG_ORIENTATION);
        try {
            orientation = Integer.parseInt(orientationString);
        }
        catch(NumberFormatException e){}

        return orientation;
    }

마지막으로 다음과 같이 올바른 위치로 회전하십시오.

public static Bitmap rotateBitmap(String src, Bitmap bitmap) {
        try {
            int orientation = getExifOrientation(src);

            if (orientation == 1) {
                return bitmap;
            }

            Matrix matrix = new Matrix();
            switch (orientation) {
                case 2:
                    matrix.setScale(-1, 1);
                    break;
                case 3:
                    matrix.setRotate(180);
                    break;
                case 4:
                    matrix.setRotate(180);
                    matrix.postScale(-1, 1);
                    break;
                case 5:
                    matrix.setRotate(90);
                    matrix.postScale(-1, 1);
                    break;
                case 6:
                    matrix.setRotate(90);
                    break;
                case 7:
                    matrix.setRotate(-90);
                    matrix.postScale(-1, 1);
                    break;
                case 8:
                    matrix.setRotate(-90);
                    break;
                default:
                    return bitmap;
            }

            try {
                Bitmap oriented = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
                bitmap.recycle();
                return oriented;
            } catch (OutOfMemoryError e) {
                e.printStackTrace();
                return bitmap;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return bitmap;
    }

이제 비트 맵이 올바른 위치로 회전되었습니다.

건배.


1

이것은 효과가 있지만 최선의 방법은 아니지만 누군가에게 도움이 될 수 있습니다.

String imagepath = someUri.getAbsolutePath();
imageview = (ImageView)findViewById(R.id.imageview);
imageview.setImageBitmap(setImage(imagepath, 120, 120));    

public Bitmap setImage(String path, final int targetWidth, final int targetHeight) {
    Bitmap bitmap = null;
// Get exif orientation     
    try {
        ExifInterface exif = new ExifInterface(path);
        int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
        if (orientation == 6) {
            orientation_val = 90;
        }
        else if (orientation == 3) {
            orientation_val = 180;
        }
        else if (orientation == 8) {
            orientation_val = 270;
        }
    }
        catch (Exception e) {
        }

        try {
// First decode with inJustDecodeBounds=true to check dimensions
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(path, options);

// Adjust extents
            int sourceWidth, sourceHeight;
            if (orientation_val == 90 || orientation_val == 270) {
                sourceWidth = options.outHeight;
                sourceHeight = options.outWidth;
            } else {
                sourceWidth = options.outWidth;
                sourceHeight = options.outHeight;
            }

// Calculate the maximum required scaling ratio if required and load the bitmap
            if (sourceWidth > targetWidth || sourceHeight > targetHeight) {
                float widthRatio = (float)sourceWidth / (float)targetWidth;
                float heightRatio = (float)sourceHeight / (float)targetHeight;
                float maxRatio = Math.max(widthRatio, heightRatio);
                options.inJustDecodeBounds = false;
                options.inSampleSize = (int)maxRatio;
                bitmap = BitmapFactory.decodeFile(path, options);
            } else {
                bitmap = BitmapFactory.decodeFile(path);
            }

// Rotate the bitmap if required
            if (orientation_val > 0) {
                Matrix matrix = new Matrix();
                matrix.postRotate(orientation_val);
                bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            }

// Re-scale the bitmap if necessary
            sourceWidth = bitmap.getWidth();
            sourceHeight = bitmap.getHeight();
            if (sourceWidth != targetWidth || sourceHeight != targetHeight) {
                float widthRatio = (float)sourceWidth / (float)targetWidth;
                float heightRatio = (float)sourceHeight / (float)targetHeight;
                float maxRatio = Math.max(widthRatio, heightRatio);
                sourceWidth = (int)((float)sourceWidth / maxRatio);
                sourceHeight = (int)((float)sourceHeight / maxRatio);
                bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth,     sourceHeight, true);
            }
        } catch (Exception e) {
        }
        return bitmap;
    }

1

어쩌면 이것이 도움이 될 것입니다 (90도 회전) (이것은 나를 위해 일했습니다)

private Bitmap rotateBitmap(Bitmap image){
        int width=image.getHeight();
        int height=image.getWidth();

        Bitmap srcBitmap=Bitmap.createBitmap(width, height, image.getConfig());

        for (int y=width-1;y>=0;y--)
            for(int x=0;x<height;x++)
                srcBitmap.setPixel(width-y-1, x,image.getPixel(x, y));
        return srcBitmap;

    }

1

커서를 연 후에는 커서를 닫아야합니다.

다음은 예입니다.

 public static int getOrientation(Context context, Uri selectedImage)
{
    int orientation = -1;
    Cursor cursor = context.getContentResolver().query(selectedImage,
            new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
    if (cursor.getCount() != 1)
       return orientation;

    cursor.moveToFirst();
    orientation = cursor.getInt(0);
    cursor.close(); // ADD THIS LINE
   return orientation;
}

1

@Timmmm 답변과 @Manuel을 녹였습니다. 이 솔루션을 수행하면 메모리 부족 예외가 발생하지 않습니다.

이 방법은 이미지 방향을 검색합니다.

private static final int ROTATION_DEGREES = 90;
// This means 512 px
private static final Integer MAX_IMAGE_DIMENSION = 512;

public static int getOrientation(Uri photoUri) throws IOException {

    ExifInterface exif = new ExifInterface(photoUri.getPath());
    int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);

    switch (orientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            orientation = ROTATION_DEGREES;
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            orientation = ROTATION_DEGREES * 2;
            break;
        case ExifInterface.ORIENTATION_ROTATE_270:
            orientation = ROTATION_DEGREES * 3;
            break;
        default:
            // Default case, image is not rotated
            orientation = 0;
    }

    return orientation;
}

따라서이 방법을 사용하면 이미지를 메모리에로드하기 전에 이미지 크기를 조정할 수 있습니다. 그렇게하면 메모리 예외가 발생하지 않습니다.

public static Bitmap getCorrectlyOrientedImage(Context context, Uri photoUri) throws IOException {
    InputStream is = context.getContentResolver().openInputStream(photoUri);
    BitmapFactory.Options dbo = new BitmapFactory.Options();
    dbo.inJustDecodeBounds = true;
    BitmapFactory.decodeStream(is, null, dbo);
    is.close();

    int rotatedWidth, rotatedHeight;
    int orientation = getOrientation(photoUri);

    if (orientation == 90 || orientation == 270) {
        rotatedWidth = dbo.outHeight;
        rotatedHeight = dbo.outWidth;
    } else {
        rotatedWidth = dbo.outWidth;
        rotatedHeight = dbo.outHeight;
    }

    Bitmap srcBitmap;
    is = context.getContentResolver().openInputStream(photoUri);
    if (rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION) {
        float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
        float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
        float maxRatio = Math.max(widthRatio, heightRatio);

        // Create the bitmap from file
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = (int) maxRatio;
        srcBitmap = BitmapFactory.decodeStream(is, null, options);
    } else {
        srcBitmap = BitmapFactory.decodeStream(is);
    }
    is.close();

    // if the orientation is not 0, we have to do a rotation.
    if (orientation > 0) {
        Matrix matrix = new Matrix();
        matrix.postRotate(orientation);

        srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
                srcBitmap.getHeight(), matrix, true);
    }

    return srcBitmap;
}

이것은 나를 위해 완벽하게 작동합니다. 나는 이것이 다른 누군가를 돕기를 바랍니다.


0

Timmmm이 위의 솔루션을 개선하여 끝에 스케일링을 추가하여 이미지가 범위 내에 들어 오도록합니다.

public static Bitmap loadBitmap(String path, int orientation, final int targetWidth, final int targetHeight) {
    Bitmap bitmap = null;
    try {
        // First decode with inJustDecodeBounds=true to check dimensions
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        // Adjust extents
        int sourceWidth, sourceHeight;
        if (orientation == 90 || orientation == 270) {
            sourceWidth = options.outHeight;
            sourceHeight = options.outWidth;
        } else {
            sourceWidth = options.outWidth;
            sourceHeight = options.outHeight;
        }

        // Calculate the maximum required scaling ratio if required and load the bitmap
        if (sourceWidth > targetWidth || sourceHeight > targetHeight) {
            float widthRatio = (float)sourceWidth / (float)targetWidth;
            float heightRatio = (float)sourceHeight / (float)targetHeight;
            float maxRatio = Math.max(widthRatio, heightRatio);
            options.inJustDecodeBounds = false;
            options.inSampleSize = (int)maxRatio;
            bitmap = BitmapFactory.decodeFile(path, options);
        } else {
            bitmap = BitmapFactory.decodeFile(path);
        }

        // Rotate the bitmap if required
        if (orientation > 0) {
            Matrix matrix = new Matrix();
            matrix.postRotate(orientation);
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        }

        // Re-scale the bitmap if necessary
        sourceWidth = bitmap.getWidth();
        sourceHeight = bitmap.getHeight();
        if (sourceWidth != targetWidth || sourceHeight != targetHeight) {
            float widthRatio = (float)sourceWidth / (float)targetWidth;
            float heightRatio = (float)sourceHeight / (float)targetHeight;
            float maxRatio = Math.max(widthRatio, heightRatio);
            sourceWidth = (int)((float)sourceWidth / maxRatio);
            sourceHeight = (int)((float)sourceHeight / maxRatio);
            bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth, sourceHeight, true);
        }
    } catch (Exception e) {
    }
    return bitmap;
}

0

다음 코드를 사용하여 이미지를 올바르게 회전하십시오.

private Bitmap rotateImage(Bitmap bitmap, String filePath)
{
    Bitmap resultBitmap = bitmap;

    try
    {
        ExifInterface exifInterface = new ExifInterface(filePath);
        int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);

        Matrix matrix = new Matrix();

        if (orientation == ExifInterface.ORIENTATION_ROTATE_90)
        {
            matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_90);
        }
        else if (orientation == ExifInterface.ORIENTATION_ROTATE_180)
        {
            matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_180);
        }
        else if (orientation == ExifInterface.ORIENTATION_ROTATE_270)
        {
            matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_270);
        }

        // Rotate the bitmap
        resultBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
    }
    catch (Exception exception)
    {
        Logger.d("Could not rotate the image");
    }
    return resultBitmap;
}

모든 if 조건을 병합하여 더 작은 코드를 가질 수 있습니다.
Chandranshu

0

아래 방법은 방향에 따라 비트 맵의 ​​크기를 조정하고 회전합니다.

public Bitmap scaleAndRotateImage(String path, int orientation, final int targetWidth, final int targetHeight)
{
    Bitmap bitmap = null;

    try
    {
        // Check the dimensions of the Image
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);

        // Adjust the Width and Height
        int sourceWidth, sourceHeight;
        if (orientation == 90 || orientation == 270)
        {
            sourceWidth = options.outHeight;
            sourceHeight = options.outWidth;
        }
        else
        {
            sourceWidth = options.outWidth;
            sourceHeight = options.outHeight;
        }

        // Calculate the maximum required scaling ratio if required and load the bitmap
        if (sourceWidth > targetWidth || sourceHeight > targetHeight)
        {
            float widthRatio = (float)sourceWidth / (float)targetWidth;
            float heightRatio = (float)sourceHeight / (float)targetHeight;
            float maxRatio = Math.max(widthRatio, heightRatio);
            options.inJustDecodeBounds = false;
            options.inSampleSize = (int)maxRatio;
            bitmap = BitmapFactory.decodeFile(path, options);
        }
        else
        {
            bitmap = BitmapFactory.decodeFile(path);
        }

        // We need to rotate the bitmap (if required)
        int orientationInDegrees = exifToDegrees(orientation);
        if (orientation > 0)
        {
            Matrix matrix = new Matrix();
            if (orientation != 0f)
            {
                matrix.preRotate(orientationInDegrees);
            };

            bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        }

        // Re-scale the bitmap if necessary
        sourceWidth = bitmap.getWidth();
        sourceHeight = bitmap.getHeight();

        if (sourceWidth != targetWidth || sourceHeight != targetHeight)
        {
            float widthRatio = (float)sourceWidth / (float)targetWidth;
            float heightRatio = (float)sourceHeight / (float)targetHeight;
            float maxRatio = Math.max(widthRatio, heightRatio);
            sourceWidth = (int)((float)sourceWidth / maxRatio);
            sourceHeight = (int)((float)sourceHeight / maxRatio);
            bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth, sourceHeight, true);
        }
    }
    catch (Exception e)
    {
        Logger.d("Could not rotate the image");
        Logger.d(e.getMessage());
    }
    return bitmap;
}

예:

public void getPictureFromDevice(Uri Uri,ImageView imageView)
{
    try
    {
        ExifInterface exifInterface = new ExifInterface(Uri.getPath());
        int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

        Bitmap bitmap = scaleAndRotateImage(Uri.getPath(), orientation, imageView.getWidth(), imageView.getHeight());
        imageView.setImageBitmap(bitmap);
    }
    catch (OutOfMemoryError outOfMemoryError)
    {
        Logger.d(outOfMemoryError.getLocalizedMessage());
        Logger.d("Failed to load image from filePath (out of memory)");
        Logger.d(Uri.toString());
    }
    catch (Exception e)
    {
        Logger.d("Failed to load image from filePath");
        Logger.d(Uri.toString());
    }
}

-3

다음 해결 방법으로 문제를 해결했습니다. OutOfMemoryExceptions를 피하기 위해 필요한 이미지 크기도 조정 중입니다.

이 솔루션은 세로 이미지 나 반대쪽 이미지에서는 제대로 작동하지 않습니다 (Timmmm에게 감사합니다). 위의 Timmmm 솔루션이 필요하고 더 우아해 보이는 경우 더 나은 선택 일 수 있습니다 : https://stackoverflow.com/a/8914291/449918

File path = // ... location of your bitmap file
int w = 512; int h = 384; // size that does not lead to OutOfMemoryException on Nexus One
Bitmap b = BitmapFactory.decodeFile(path);


// Hack to determine whether the image is rotated
boolean rotated = b.getWidth() > b.getHeight();

Bitmap resultBmp = null;

// If not rotated, just scale it
if (!rotated) {
    resultBmp = Bitmap.createScaledBitmap(b, w, h, true);
    b.recycle();
    b = null;

// If rotated, scale it by switching width and height and then rotated it
} else {
    Bitmap scaledBmp = Bitmap.createScaledBitmap(b, h, w, true);
    b.recycle();
    b = null;

    Matrix mat = new Matrix();
    mat.postRotate(90);
    resultBmp = Bitmap.createBitmap(scaledBmp, 0, 0, h, w, mat, true);

    // Release image resources
    scaledBmp.recycle();
    scaledBmp = null;
}

// resultBmp now contains the scaled and rotated image

건배


제대로 작동하지 않습니다. 인물 이미지는 어떻습니까? 거꾸로 된 이미지? exif 데이터를 사용하는 것이 훨씬 좋습니다.
Timmmm

내 앱 중 하나에서 제대로 작동하지만 물론 모든 유형의 시나리오를 테스트하지는 않았습니다. @Timmmm 작동하지 않는 시나리오에 대해 더 구체적으로 설명해 주시겠습니까? 나는 또한 당신이 내 게시물을 투표하는 것에 대해 매우 당황합니다. 잠재적 인 해결책을 공유하려는 정직한 시도에 대한 매우 거친 반응 인 것 같습니다.
Martin

나는 가혹하다는 의미는 아니었다. 죄송합니다! 방금 솔루션이 작동하기를 바라고 아무도 복사하지 않기를 바랐습니다. 내가 말했듯이 세로 또는 거꾸로 된 이미지에는 작동하지 않습니다. 올바른 해결책을 답변으로 추가하겠습니다.
Timmmm

내가 참조. 위의 솔루션을 선호하는 솔루션으로 강조 표시하는 의견을 추가하겠습니다.
Martin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.