Android: Bitmap được tải từ thư viện được xoay trong ImageView


138

Khi tôi tải hình ảnh từ thư viện phương tiện vào Bitmap, mọi thứ đều hoạt động tốt, ngoại trừ những hình ảnh được chụp bằng máy ảnh trong khi cầm điện thoại theo chiều dọc, được xoay để tôi luôn có được hình ảnh nằm ngang mặc dù nó xuất hiện theo chiều dọc bộ sưu tập. Tại sao lại như vậy và làm thế nào tôi có thể tải nó một cách chính xác?


Câu trả lời:


40

Bạn đã xem dữ liệu EXIF ​​của hình ảnh chưa? Nó có thể biết hướng của máy ảnh khi chụp ảnh.


2
Bạn nói đúng, đó tất nhiên là giải pháp. Sau này tôi sẽ đăng mã của mình làm ví dụ trong một câu trả lời riêng biệt, nhưng tôi đánh dấu mã này là được chấp nhận vì nó giúp tôi đi đúng hướng.
Manuel

182

Vì vậy, như một ví dụ ...

Trước tiên, bạn cần tạo ExifInterface:

ExifInterface exif = new ExifInterface(filename);

Sau đó, bạn có thể lấy hướng của hình ảnh:

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

Dưới đây là ý nghĩa của các giá trị định hướng: http://sylvana.net/jpegcrop/exif_orientation.html

Vì vậy, các giá trị quan trọng nhất là 3, 6 và 8. Nếu định hướng là ExifInterface.ORIENTATION_ROTATE_90(đó là 6), chẳng hạn, bạn có thể xoay hình ảnh như thế này:

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

Đó chỉ là một ví dụ nhanh chóng. Tôi chắc chắn có nhiều cách khác để thực hiện xoay vòng thực tế. Nhưng bạn cũng sẽ tìm thấy những thứ đó trên StackOverflow.


5
Dưới đây là tất cả các giá trị xoay cho các hướng khác nhau: 3: 180, 6: 90, 8: 270
Tên hiển thị

103
Không sử dụng số ma thuật khi bạn có thể sử dụng các hằng số có tên: ExifInterface.ORIENTATION_NORMAL, ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_ROTATE_180, ExifInterface.ORIENTATION_R70.
d60402

29
Cảnh giác OutOfMemoryErrorkhi sử dụng phương pháp này khi bạn giữ hai bitmap trong bộ nhớ cùng một lúc.
Alex Bonel

Một ví dụ hoàn chỉnh khác ... stackoverflow.com/questions/14066038/
Ấn

64

Đây là một giải pháp đầy đủ (được tìm thấy trong ví dụ về Hackbook từ SDK Facebook). Nó có lợi thế là không cần truy cập vào tập tin. Điều này cực kỳ hữu ích nếu bạn đang tải một hình ảnh từ bộ giải quyết nội dung (ví dụ: nếu ứng dụng của bạn phản ứng với mục đích chia sẻ ảnh).

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);
}

Và sau đó bạn có thể nhận được một Bitmap xoay như sau. Mã này cũng thu nhỏ hình ảnh (thật không may) thành MAX_IMAGE_DIMENSION. Nếu không bạn có thể hết bộ nhớ.

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 có nghĩa là gì?
Sazzad Hissain Khan

3
Đó là chiều rộng hoặc chiều cao tối đa của hình ảnh bạn nhận được. Tức là bạn chỉ cần một hình ảnh 512x512, nếu bạn mở một hình ảnh 24 megapixel thì việc mở nó đã được ghép lại sẽ hiệu quả hơn nhiều so với việc mở toàn bộ và sau đó thu nhỏ lại - dù sao thì điều đó có thể sẽ làm cạn kiệt bộ nhớ của bạn.
Timmmm

Trong các chương trình của tôi, tôi thấy hữu ích khi xác định biến Bitmap trong hoạt động / đoạn là tĩnh riêng và đặt nó thành null trong các hàm. Đã có ít rắc rối bộ nhớ rồi.
Gunnar Bernstein

Sẽ thông minh hơn khi thay thế MAX_IMAGE_DIMENDION thành MAX_IMAGE_WIDTH và MAX_IMAGE_HEIGHT
fnc12

Tiết kiệm rất nhiều thời gian của tôi :) Rất cám ơn. Đối với những người nhận được vô con trỏ, bạn có thể thử ExifInterface exif = new ExifInterface(photoUri.getPath());và sau đó exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1)để có được định hướng (ví dụ ORIENTATION_ROTATE_90, ORIENTATION_ROTATE_180)
Atul

60

Đã giải quyết nó trong trường hợp của tôi với mã này bằng cách sử dụng trợ giúp của bài đăng này:

            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);

Hy vọng nó sẽ tiết kiệm thời gian của ai đó!


chỉnh sửa đề xuất: không có hằng số được đặt tên thích hợp cho các định hướng 6, 3, 8? chúng ta không thể bỏ qua bitmap mới nếu không yêu cầu xoay vòng?
Cee McSharpface

Như @ d60402 đã nói trước đây trong một nhận xét, bạn có thể sử dụng các hằng số có tên: ExifInterface.ORIENTATION_NORMAL, ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_ROTATE_180, ExifInterface.
Adrian

42

Sử dụng Tiện ích để thực hiện Nâng vật nặng.

9re đã tạo ra một tiện ích đơn giản để xử lý việc xử lý dữ liệu EXIF ​​và xoay hình ảnh theo hướng chính xác.

Bạn có thể tìm thấy mã tiện ích tại đây: https://gist.github.com/9re/1990019

Chỉ cần tải xuống cái này, thêm nó vào thư mục dự án của bạn srcvà sử dụng ExifUtil.rotateBitmap()để có được định hướng chính xác, như vậy:

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

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

2
Làm việc cho tôi! Tôi chỉ thay đổi kích thước bitmap thành định dạng HD trước khi chuyển nó sang ExifUtil.rotateBitmap () để tránh OutOfMemoryError như thế: Bitmap đã thay đổi kích thước = Bitmap.createScaledBitmap (myBitmap, 720, 1280, true); ảnh = ExifUtil.rotateBitmap (imagePath, đã thay đổi kích thước);
Phil

@Phil Bổ sung đẹp. Tôi chưa gặp phải điều đó (tôi đang sử dụng các thiết bị Android cũ hơn, nhỏ hơn) nhưng điều đó thực sự tốt để biết.
Joshua Pinter

3
bạn là một anh hùng, bạn của tôi :)
klutch

@klutch Bạn vừa làm cho ngày của tôi. :) Công bằng mà nói, 9re đã viết mã tiện ích để anh ta trở thành anh hùng thực sự.
Joshua Pinter

1
@SaletanthKarumanaghat Câu hỏi tuyệt vời! Tôi có thể biết tại sao điều này có ý nghĩa khi tôi đi sâu vào vấn đề này nhưng ngay bây giờ nó cũng có vẻ dư thừa đối với tôi. Có lẽ đã dành quá nhiều thời gian trong React Native.
Joshua Pinter

8

bởi vì bộ sưu tập của nó hiển thị chính xác các hình ảnh được xoay nhưng không xem ImageView ở đây:

                    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);
                    }

và bạn cần điều này:

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

Làm cho nó hoạt động sau nhiều lần thử nhờ một bài đăng mà tôi không còn tìm thấy :-(

Exif dường như luôn luôn làm việc, khó khăn là để có được filepath. Mã tôi tìm thấy tạo ra sự khác biệt giữa API cũ hơn 4.4 và sau 4.4. Về cơ bản, URI hình ảnh cho 4.4+ chứa "com.android.providers". Đối với loại URI này, mã sử dụng DocumentsContract để lấy id hình ảnh và sau đó chạy truy vấn bằng ContentResolver, trong khi đối với SDK cũ hơn, mã đi thẳng để truy vấn URI bằng ContentResolver.

Đây là mã (xin lỗi tôi không thể ghi nhận ai đã đăng nó):

/**
 * 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);
        }
}

Cám ơn bạn rất nhiều. Sau nhiều giờ làm việc với con trỏ và exifs, việc lưu này có thể ngày. Như bạn đã nói, trên thực tế exif có dữ liệu đúng và đáng tin cậy thay vì trả về con trỏ. Chỉ cần cho nó đường dẫn chính xác hơn nó hoạt động.
asozcan

3

Bạn chỉ có thể đọc đường dẫn từ thẻ sd và thực hiện mã sau đây ... nó sẽ Thay thế ảnh hiện có sau khi xoay nó ..

Không phải: Exif không hoạt động trên hầu hết các thiết bị, nó cung cấp dữ liệu sai, do đó, tốt để mã cứng quay trước khi lưu ở bất kỳ mức độ nào bạn muốn, Bạn chỉ cần thay đổi giá trị góc trong postRotate thành bất kỳ bạn muốn.

    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
Điều này là để xoay nhưng chúng tôi không biết nếu hình ảnh cần xoay.
MSaudi

3

Mã Kotlin:

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

Tôi đã cải thiện câu trả lời của Teo Inke. Nó không còn xoay hình ảnh trừ khi nó thực sự cần thiết. Nó cũng dễ đọc hơn và nên chạy nhanh hơn.

// 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

Điều đầu tiên bạn cần là đường dẫn Tệp thực Nếu bạn có nó tuyệt vời, nếu bạn đang sử dụng URI thì hãy sử dụng phương pháp này để có được Đường dẫn thực:

 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;
}

trích xuất Bitmap của bạn chẳng hạn:

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

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

thay vào đó, bạn có thể sử dụng decodeFile () nếu muốn.

Bây giờ bạn đã có Bitmap và Đường dẫn thực sự có được Định hướng của Hình ảnh:

 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;
    }

và cuối cùng xoay nó sang đúng vị trí như vậy:

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;
    }

Thế là xong, giờ bạn đã có bitmap được xoay sang đúng vị trí.

chúc mừng


1

Điều này hoạt động, nhưng có lẽ không phải là cách tốt nhất để làm điều đó, nhưng nó có thể giúp một ai đó.

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

có lẽ điều này sẽ giúp (xoay 90 độ) (điều này làm việc cho tôi)

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

Con trỏ phải được đóng lại sau khi mở nó.

Đây là một ví dụ.

 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

Tôi đã làm tan chảy câu trả lời @Timmmm và @Manuel. Nếu bạn thực hiện giải pháp này, bạn sẽ không bị Ngoại lệ bộ nhớ.

Phương pháp này lấy hướng hình ảnh:

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;
}

Do đó, bạn sẽ sử dụng phương pháp này để thay đổi kích thước hình ảnh trước khi tải nó vào bộ nhớ. Theo cách đó, bạn sẽ không nhận được Ngoại lệ bộ nhớ.

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;
}

Điều này làm việc hoàn hảo cho tôi. Tôi hy vọng điều này sẽ giúp người khác


0

Cải thiện giải pháp trên của Timmmm để thêm một số tỷ lệ bổ sung ở cuối để đảm bảo rằng hình ảnh phù hợp trong giới hạn:

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

Sử dụng mã sau đây để xoay một hình ảnh chính xác:

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;
}

Bạn có thể hợp nhất tất cả các điều kiện if với nhau để có mã nhỏ hơn.
Chandranshu

0

Các phương pháp bên dưới chia tỷ lệ VÀ xoay bitmap theo hướng:

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;
}

Thí dụ:

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

Tôi đã giải quyết vấn đề với cách giải quyết sau. Lưu ý rằng tôi cũng đang thu nhỏ hình ảnh, điều cần thiết để tránh OutOfMemoryExceptions.

Xin lưu ý rằng giải pháp này sẽ không hoạt động đúng với hình ảnh chân dung hoặc hình ảnh ngược (cảm ơn bạn Timmmm đã lưu ý). Giải pháp của Timmmm ở trên có thể là lựa chọn tốt hơn nếu điều đó là bắt buộc và nó cũng có vẻ thanh lịch hơn: 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

Chúc mừng


Điều này sẽ không hoạt động đúng. Còn ảnh chân dung thì sao? Hình ảnh lộn ngược? Sử dụng dữ liệu exif tốt hơn nhiều.
Timmmm

Nó hoạt động chính xác trong một trong các ứng dụng của tôi, nhưng tất nhiên tôi chưa thử nghiệm tất cả các loại kịch bản. @Timmmm bạn có thể vui lòng cụ thể hơn trong trường hợp nào nó không hoạt động không? Tôi cũng khá bối rối về việc bạn bỏ phiếu cho bài viết của tôi. Nó dường như là một phản ứng khá khắc nghiệt đối với một cố gắng trung thực để chia sẻ một giải pháp tiềm năng.
Martin

Tôi không có ý là khắc nghiệt; lấy làm tiếc! Tôi chỉ không muốn bất cứ ai sao chép giải pháp của bạn với hy vọng nó sẽ hoạt động. Như tôi đã nói, nó sẽ không hoạt động đối với ảnh chân dung hoặc lộn ngược. Tôi sẽ thêm giải pháp chính xác như một câu trả lời.
Timmmm

Tôi hiểu rồi. Tôi sẽ thêm một bình luận nêu bật giải pháp của bạn ở trên như một giải pháp ưa thích.
Martin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.