Android: Bitmap yang dimuat dari galeri diputar di ImageView

138

Saat saya memuat gambar dari galeri media ke dalam Bitmap, semuanya berfungsi dengan baik, kecuali gambar yang diambil dengan kamera sambil memegang telepon secara vertikal, diputar sehingga saya selalu mendapatkan gambar horizontal meskipun tampak vertikal di galeri. Mengapa demikian dan bagaimana cara memuatnya dengan benar?

Manuel
sumber
Saya memiliki jawaban sebenarnya stackoverflow.com/questions/29971319/image-orientation-android/…
A.Sanchez.SD

Jawaban:

40

Sudahkah Anda melihat data EXIF ​​dari gambar? Mungkin mengetahui orientasi kamera saat gambar diambil.

James
sumber
2
Anda benar, tentu saja itu solusinya. Saya akan memposting kode saya sebagai contoh dalam jawaban terpisah, nanti, tetapi saya tandai yang ini sebagai diterima karena itu membuat saya berada di jalur yang benar.
Manuel
184

Jadi, sebagai contoh ...

Pertama, Anda perlu membuat ExifInterface:

ExifInterface exif = new ExifInterface(filename);

Anda kemudian dapat mengambil orientasi gambar:

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

Inilah arti dari nilai orientasi: http://sylvana.net/jpegcrop/exif_orientation.html

Jadi, nilai yang paling penting adalah 3, 6 dan 8. Jika orientasinya ExifInterface.ORIENTATION_ROTATE_90(yaitu 6), misalnya, Anda dapat memutar gambar seperti ini:

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

Itu hanya contoh singkat. Saya yakin ada cara lain untuk melakukan rotasi sebenarnya. Tetapi Anda juga akan menemukannya di StackOverflow.

Manuel
sumber
5
Berikut adalah semua nilai rotasi untuk orientasi yang berbeda: 3: 180, 6: 90, 8: 270
Nama tampilan
103
Jangan gunakan angka ajaib ketika Anda dapat menggunakan konstanta bernama: ExifInterface.ORIENTATION_NORMAL, ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_ROTATE_180, ExifInterface.ORIENTATION_ROTATE_270.
d60402
29
Berhati-hatilah OutOfMemoryErrorsaat menggunakan pendekatan ini saat Anda menyimpan dua bitmap dalam memori pada saat yang bersamaan.
Alex Bonel
Contoh lengkap lainnya ... stackoverflow.com/questions/14066038/…
CGR
66

Ini adalah solusi lengkap (ditemukan dalam contoh Hackbook dari Facebook SDK). Ini memiliki keuntungan karena tidak membutuhkan akses ke file itu sendiri. Ini sangat berguna jika Anda memuat gambar dari pemecah konten (misalnya jika aplikasi Anda merespons maksud berbagi foto).

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

Dan kemudian Anda bisa mendapatkan Bitmap yang dirotasi sebagai berikut. Kode ini juga menurunkan ukuran gambar (sayangnya) menjadi MAX_IMAGE_DIMENSION. Jika tidak, Anda mungkin kehabisan memori.

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;
}
Timmmm
sumber
1
apa maksud MAX_IMAGE_DIMENDION itu?
Sazzad Hissain Khan
3
Ini adalah lebar atau tinggi maksimum gambar yang Anda dapatkan. Yaitu Katakanlah Anda hanya membutuhkan gambar 512x512, jika Anda membuka gambar 24 megapiksel, akan jauh lebih efisien untuk membukanya yang sudah di-sub-sampel daripada membuka semuanya dan kemudian menurunkannya - itu mungkin akan menghabiskan semua memori Anda.
Timmmm
Dalam program saya, saya merasa berguna untuk mendefinisikan variabel Bitmap di activity / fragment sebagai private static dan mengaturnya ke null dalam fungsi. Memiliki lebih sedikit masalah memori.
Gunnar Bernstein
Lebih cerdas mengganti MAX_IMAGE_DIMENDION menjadi MAX_IMAGE_WIDTH dan MAX_IMAGE_HEIGHT
fnc12
Menghemat banyak waktu saya :) Terima kasih banyak. Bagi mereka yang mendapatkan kursor nol, Anda dapat mencoba ExifInterface exif = new ExifInterface(photoUri.getPath());dan kemudian exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1)mendapatkan orientasi (misalnya ORIENTATION_ROTATE_90, ORIENTATION_ROTATE_180)
Atul
61

Selesaikan dalam kasus saya dengan kode ini menggunakan bantuan posting ini:

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

Semoga dapat menghemat waktu seseorang!

Teo Inke
sumber
sunting saran: apakah tidak ada konstanta bernama yang tepat untuk orientasi 6, 3, 8? Bisakah kita melewatkan bitmap baru jika tidak diperlukan rotasi?
Cee McSharpface
Seperti yang dikatakan @ d60402 sebelumnya dalam sebuah komentar, Anda dapat menggunakan konstanta bernama: ExifInterface.ORIENTATION_NORMAL, ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_ROTATE_180, ExifInterface.ORIENTATION_ROTATE_270.
Adrian
42

Gunakan Utilitas untuk melakukan Pengangkatan Berat.

9re membuat utilitas sederhana untuk menangani pekerjaan berat menangani data EXIF ​​dan memutar gambar ke orientasi yang benar.

Anda dapat menemukan kode utilitas di sini: https://gist.github.com/9re/1990019

Cukup unduh ini, tambahkan ke srcdirektori proyek Anda dan gunakan ExifUtil.rotateBitmap()untuk mendapatkan orientasi yang benar, seperti:

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

Bitmap orientedBitmap = ExifUtil.rotateBitmap(imagePath, myBitmap);
Joshua Pinter
sumber
2
Bekerja untuk saya! Saya baru saja mengubah ukuran bitmap ke format HD sebelum meneruskannya ke ExifUtil.rotateBitmap () untuk menghindari OutOfMemoryError seperti itu: Bitmap resized = Bitmap.createScaledBitmap (myBitmap, 720, 1280, true); foto = ExifUtil.rotateBitmap (picturePath, diubah ukurannya);
Phil
@Phil Tambahan yang bagus. Saya belum pernah mengalami itu (saya menggunakan perangkat Android yang lebih lama dan lebih buruk) tetapi itu sangat bagus untuk diketahui.
Joshua Pinter
3
Anda adalah pahlawan teman saya :)
klutch
@klutch Anda baru saja membuat hari saya. :) Agar adil, 9re dibuat aja kode utilitasnya jadi dia pahlawan yang sebenarnya.
Joshua Pinter
1
@SreekanthKarumanaghat Pertanyaan bagus! Saya mungkin tahu mengapa ini masuk akal ketika saya jauh ke dalam ini, tetapi saat ini tampaknya berlebihan juga bagi saya. Mungkin menghabiskan terlalu banyak waktu di React Native.
Joshua Pinter
8

Itu karena galeri benar menampilkan gambar yang diputar tetapi tidak tampilan ImageView di sini:

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

dan Anda membutuhkan ini:

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;    
} 
farhad.kargaran
sumber
6

Berhasil setelah banyak upaya berkat pos yang tidak dapat saya temukan lagi :-(

Exif tampaknya selalu berfungsi, kesulitannya adalah mendapatkan jalur file. Kode yang saya temukan membuat perbedaan antara API yang lebih lama dari 4.4 dan setelah 4.4. Pada dasarnya gambar URI untuk 4.4+ berisi "com.android.providers". Untuk jenis URI ini, kode tersebut menggunakan DocumentsContract untuk mendapatkan id gambar dan kemudian menjalankan kueri menggunakan ContentResolver, sedangkan untuk SDK yang lebih lama, kode tersebut langsung meminta URI dengan ContentResolver.

Ini kodenya (maaf saya tidak bisa memberi kredit siapa yang mempostingnya):

/**
 * 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);
        }
}
Georges
sumber
Terima kasih banyak untukmu. Setelah berjam-jam bekerja dengan kursor dan exifs, hari ini dapat disimpan. Seperti yang Anda katakan, sebenarnya exif memiliki data yang benar dan dapat diandalkan, bukan pengembalian kursor. Berikan saja jalur yang benar daripada yang berhasil.
asozcan
3

Anda tinggal membaca jalur dari kartu sd dan melakukan kode berikut ... itu akan Mengganti foto yang ada setelah memutarnya ..

Catatan: Exif tidak berfungsi pada sebagian besar perangkat, ini memberikan data yang salah sehingga sebaiknya kode keras berputar sebelum menyimpan ke tingkat apa pun yang Anda inginkan, Anda hanya perlu mengubah nilai sudut di postRotate ke nilai yang Anda inginkan.

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

}
Mayank Saini
sumber
2
Ini untuk memutar tetapi kami tidak tahu apakah gambar perlu rotasi.
MSaudi
3

Kode 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)
}
Rahul Khatri
sumber
2

Saya memperbaiki jawaban dari Teo Inke. Itu tidak lagi memutar gambar kecuali itu benar-benar diperlukan. Ini juga lebih mudah dibaca, dan seharusnya berjalan lebih cepat.

// 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);
pengguna2820531
sumber
2

Hal pertama yang Anda butuhkan adalah jalur File yang sebenarnya. Jika Anda memilikinya, jika Anda menggunakan URI, gunakan metode ini untuk mendapatkan Path yang sebenarnya:

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

ekstrak Bitmap Anda misalnya:

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

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

Anda dapat menggunakan decodeFile () sebagai gantinya jika Anda mau.

Sekarang setelah Anda memiliki Bitmap dan Path yang sebenarnya, dapatkan Orientation of the Image:

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

dan terakhir putar ke posisi yang benar seperti ini:

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

Itu saja, Anda sekarang memiliki bitmap yang diputar ke posisi yang benar.

Bersulang.

Gal Rom
sumber
1

Ini berhasil, tetapi mungkin bukan cara terbaik untuk melakukannya, tetapi mungkin membantu seseorang.

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;
    }
erebos
sumber
1

mungkin ini akan membantu (putar 90 derajat) (ini berhasil untuk saya)

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;

    }
tzahibs.dll
sumber
Bitmap.createBitmap (…, matrix,…) adalah cara yang jauh lebih cepat untuk membuat bitmap yang dirotasi
Alex Cohn
1

Metode di bawah menskalakan DAN memutar bitmap sesuai dengan orientasi:

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

Contoh:

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());
    }
}
NightBits
sumber
1

Kursor harus ditutup setelah membukanya.

Berikut ini contohnya.

 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;
}
GuillaumeAgis
sumber
1

Saya telah mencairkan jawaban @Timmmm dan @Manuel. Jika Anda melakukan solusi ini, Anda tidak akan mendapatkan Pengecualian Kehabisan Memori.

Metode ini mengambil orientasi gambar:

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

Oleh karena itu, Anda akan menggunakan metode ini untuk mengubah ukuran gambar sebelum memuatnya ke memori. Dengan demikian, Anda tidak akan mendapatkan Pengecualian Memori.

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

Ini bekerja dengan sempurna untuk saya. Saya harap ini membantu orang lain

Antonio
sumber
0

Memperbaiki solusi di atas oleh Timmmm untuk menambahkan beberapa penskalaan ekstra di bagian akhir untuk memastikan bahwa gambar sesuai dengan batasan:

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;
}
Jahat
sumber
0

Gunakan kode berikut untuk memutar gambar dengan benar:

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;
}
NightBits
sumber
Anda dapat menggabungkan semua kondisi if untuk mendapatkan kode yang lebih kecil.
Chandranshu
-3

Saya memecahkan masalah dengan solusi berikut. Perhatikan bahwa saya juga menskalakan gambar, yang diperlukan untuk menghindari OutOfMemoryExceptions.

Berhati-hatilah karena solusi ini tidak akan berfungsi dengan baik dengan gambar potret atau gambar terbalik (terima kasih Timmmm untuk catatannya). Solusi Timmmm di atas mungkin menjadi pilihan yang lebih baik jika diperlukan dan terlihat lebih elegan juga: 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

Bersulang

Martin
sumber
Ini tidak akan bekerja dengan baik. Bagaimana dengan gambar potret? Gambar terbalik? Menggunakan data exif jauh lebih baik.
Timmmm
Ini berfungsi dengan baik di salah satu aplikasi saya, tetapi tentu saja saya belum menguji semua jenis skenario. @Timmmm bisakah Anda lebih spesifik dalam skenario apa itu tidak berhasil? Saya juga cukup bingung tentang Anda yang memberikan suara untuk postingan saya. Tampaknya respons yang cukup keras terhadap upaya jujur ​​untuk membagikan solusi potensial.
Martin
Saya tidak bermaksud kasar; Maaf! Saya hanya tidak ingin ada yang menyalin solusi Anda dengan harapan itu akan berhasil. Seperti yang saya katakan, ini tidak akan berfungsi untuk potret atau gambar terbalik. Saya akan menambahkan solusi yang benar sebagai jawaban.
Timmmm
Saya melihat. Saya akan menambahkan komentar yang menyoroti solusi Anda di atas sebagai yang disukai.
Martin