Android: Galeriden yüklenen bitmapler ImageView'da döndürülür


138

Medya galerisinden bir görüntüyü bir Bitmap'e yüklediğimde, telefonu dikey tutarken kamerayla çekilen resimlerin döndürülmesi, her zaman dikey görünse bile her zaman yatay bir resim elde edebilmem için her şey iyi çalışıyor galeri. Bu neden ve nasıl doğru şekilde yükleyebilirim?


Yanıtlar:


40

Görüntülerin EXIF ​​verilerine baktınız mı? Fotoğraf çekilirken kameranın yönünü biliyor olabilir.


2
Haklısın, elbette çözüm buydu. Kodumu ayrı bir cevapta örnek olarak göndereceğim, ancak bunu kabul edilmiş olarak işaretliyorum çünkü beni doğru yolda tutuyor.
Manuel

182

Yani, örnek olarak ...

İlk önce bir ExifInterface oluşturmanız gerekir:

ExifInterface exif = new ExifInterface(filename);

Daha sonra görüntünün yönünü yakalayabilirsiniz:

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

Yönlendirme değerlerinin anlamı şudur: http://sylvana.net/jpegcrop/exif_orientation.html

Yani, en önemli değerler 3, 6 ve 8'dir. Yön ExifInterface.ORIENTATION_ROTATE_90(örneğin 6'dır) ise, görüntüyü şu şekilde döndürebilirsiniz:

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

Yine de bu sadece kısa bir örnek. Eminim gerçek rotasyonu yapmanın başka yolları da vardır. Ancak bunları StackOverflow'da da bulacaksınız.


5
Farklı yönler için tüm dönüş değerleri şunlardır: 3: 180, 6: 90, 8: 270
Görünen ad

103
Adlandırılmış sabitleri kullanabileceğinizde sihirli sayılar kullanmayın: ExifInterface.ORIENTATION_NORMAL, ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_ROTATE_180, ExifInterface.ORIENTATION_ROTATE_270.
d60402

29
Dışarı İzle OutOfMemoryErroraynı anda bellekte iki bitmap tutarken bu yaklaşımı kullandığınızda.
Alex Bonel

Başka bir tam örnek ... stackoverflow.com/questions/14066038/…
CGR

64

Bu tam bir çözümdür (Facebook SDK'nın Hackbook örneğinde bulunur). Dosyanın kendisine erişmesi gerekmemesi avantajına sahiptir. İçerik çözücü öğesinden bir resim yüklüyorsanız bu çok kullanışlıdır (örneğin, uygulamanız bir paylaşım fotoğrafı amacına yanıt veriyorsa).

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

Ve sonra aşağıdaki gibi döndürülmüş bir Bitmap alabilirsiniz. Bu kod ayrıca görüntüyü (ne yazık ki maalesef) MAX_IMAGE_DIMENSION olarak ölçeklendirir. Aksi takdirde, bellek yetersiz olabilir.

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 anlamı ne?
Sazzad Hissain Khan

3
Aldığınız görüntünün maksimum genişliği veya yüksekliği. Yani sadece 512x512 bir görüntüye ihtiyacınız olduğunu varsayalım, 24 megapiksel bir görüntüyü açarsanız, zaten örneklenmiş olanı açmak her şeyi açıp ölçeklendirmekten çok daha etkilidir - muhtemelen tüm belleğinizi tüketir.
Timmmm

Programlarımda etkinlik / parçadaki Bitmap değişkenini özel statik olarak tanımlamayı ve işlevlerde null olarak ayarlamayı yararlı buldum. O zamandan daha az hafıza sorunu vardı.
Gunnar Bernstein

MAX_IMAGE_DIMENDION değerini MAX_IMAGE_WIDTH ve MAX_IMAGE_HEIGHT
fnc12 ile

Çok zamanımı kurtardım :) Çok teşekkürler. Boş imleç alanlar için, ExifInterface exif = new ExifInterface(photoUri.getPath());sonradan exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1)yönlendirme yapmayı deneyebilirsiniz (örn ORIENTATION_ROTATE_90. ORIENTATION_ROTATE_180)
Atul

60

Bu yazının yardımıyla bu kodla benim durumumda çözüldü:

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

Umarım birinin zamanından tasarruf sağlar!


önerileri düzenle: 6, 3, 8 yönelimleri için uygun adlandırılmış sabitler yok mu? döndürme gerekmiyorsa yeni bitmap'i atlayamaz mıydık?
Cee McSharpface

@ D60402'nin daha önce bir yorumda belirttiği gibi, adlandırılmış sabitleri kullanabilirsiniz: ExifInterface.ORIENTATION_NORMAL, ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_ROTATE_180, ExifInterface.ORIENTATION_ROTATE_270.
Adrian

42

Ağır Kaldırma yapmak için bir Yardımcı Program kullanın.

9re , EXIF ​​verileriyle uğraşmanın ve görüntülerin doğru yönlerine döndürülmesinin ağır kaldırılması için basit bir yardımcı program oluşturdu.

Yardımcı program kodunu burada bulabilirsiniz: https://gist.github.com/9re/1990019

Bunu indirin, projenizin srcdizinine ekleyin ve aşağıdaki ExifUtil.rotateBitmap()gibi doğru yönlendirmeyi almak için kullanın :

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

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

2
Benim için çalışıyor ! Bu şekilde OutOfMemoryError'ı önlemek için ExifUtil.rotateBitmap () 'e geçmeden önce bitmap'i HD formatına yeniden boyutlandırdım: Bitmap resized = Bitmap.createScaledBitmap (myBitmap, 720, 1280, true); photo = ExifUtil.rotateBitmap (picturePath, yeniden boyutlandırıldı);
Phil

@Phil Güzel ek. Buna girmedim (daha eski, boktan Android cihazlar kullanıyorum) ama bunu bilmek gerçekten çok iyi.
Joshua Pinter

3
sen bir kahramansın arkadaşım :)
klutch

@klutch Az önce benim günümü yaptın. :) Adil olmak gerekirse, 9re yarar kodunu yazdı, bu yüzden o gerçek kahraman.
Joshua Pinter

1
@SreekanthKarumanaghat Harika bir soru! Muhtemelen bunun derinliklerinde olduğumda neden mantıklı olduğunu biliyordum ama şu anda benim için de gereksiz görünüyor. React Native'da belki de çok fazla zaman geçiriyorsunuz.
Joshua Pinter

8

çünkü galeri doğru döndürülmüş görüntüleri gösteriyor ancak ImageView değil şuraya bakın:

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

ve buna ihtiyacınız var:

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

Artık bulamadığım bir yazı sayesinde birçok denemeden sonra çalıştım :-(

Exif her zaman çalışıyor gibi görünüyor, zorluk dosya yolunu almaktı. Bulduğum kod, 4.4'ten daha eski ve 4.4'ten sonra API arasında farklı bir şey yapıyor. Temel olarak 4.4+ için resim URI'si "com.android.providers" içerir. Bu URI türü için, kod resim kimliğini almak için DocumentsContract kullanır ve daha sonra ContentResolver'ı kullanarak bir sorgu çalıştırırken, eski SDK için kod doğrudan URI'yi ContentResolver ile sorgulamak için gider.

İşte kod (özür dilerim kim gönderdi kredi olamaz):

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

Sana çok teşekkürler. İmleçler ve exifs ile saatlerce çalıştıktan sonra, bu gün kurtarılabilir. Söylediğiniz gibi, aslında exif imleç dönüşleri yerine gerçek ve güvenilir verilere sahiptir. Sadece işe yaradığından daha doğru bir yol verin.
asozcan

3

Sadece sd karttan yolu okuyabilir ve aşağıdaki kodu yapabilirsiniz ... Döndükten sonra mevcut fotoğrafı değiştirirsiniz.

Not: Exif cihazların çoğunda çalışmaz, yanlış verileri verir, bu nedenle istediğiniz herhangi bir dereceye kaydetmeden önce döndürmeyi zor kodlamak iyidir, sadece postRotate'deki açı değerini istediğiniz herhangi bir değere değiştirmeniz gerekir.

    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
Bu döndürmek için ama görüntünün döndürülmesi gerekip gerekmediğini bilmiyoruz.
MSaudi

3

Kotlin kodu:

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'nin cevabı üzerine geliştim. Gerçekten gerekli olmadıkça görüntüyü artık döndürmez. Ayrıca okunması daha kolaydır ve daha hızlı çalışmalıdır.

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

İhtiyacınız olan ilk şey, gerçek Dosya yoludur Eğer harika bir şey varsa, URI kullanıyorsanız, gerçek Yolu almak için bu yöntemi kullanın:

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

Bitmap'inizi çıkarın:

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

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

isterseniz decodeFile () kullanabilirsiniz.

Artık Bitmap'e ve gerçek Yol'a sahip olduğunuza göre, Görüntünün Yönünü elde edin:

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

ve son olarak şu şekilde doğru konuma döndürün:

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

İşte bu, bitmap'i doğru konuma döndürdünüz.

şerefe.


1

Bu işe yarıyor, ama muhtemelen bunu yapmanın en iyi yolu değil, ama birine yardımcı olabilir.

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

belki bu yardımcı olacaktır (90 derece döndür) (bu benim için çalıştı)

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

İmleç açıldıktan sonra kapatılmalıdır.

İşte bir örnek.

 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 cevabını ve @Manuel'i erittim. Bu çözümü yaparsanız, bellek tükenmesi özel durumu almazsınız.

Bu yöntem görüntü yönlendirmesini alır:

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

Bu nedenle, görüntüyü belleğe yüklemeden önce yeniden boyutlandırmak için bu yöntemi kullanırsınız. Bu şekilde, bir Bellek İstisnası alamazsınız.

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

Bu benim için mükemmel çalışıyor. Umarım bu başka birine yardım eder


0

Resmin sınırlara sığmasını sağlamak için sonuna ekstra ölçeklendirme eklemek için Timmmm tarafından yukarıdaki çözüm üzerinde iyileştirme:

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

Görüntüyü doğru döndürmek için aşağıdaki kodu kullanın:

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

Daha küçük bir koda sahip olmak için tüm if koşullarını birleştirebilirsiniz.
Chandranshu

0

Aşağıdaki yöntemler, bitmap'i yönlendirmeye göre ölçeklendirir VE döndürür:

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

Misal:

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

Aşağıdaki geçici çözümle sorunu çözdüm. Ayrıca OutOfMemoryExceptions önlemek için gerekli olan görüntüyü ölçeklendirme unutmayın.

Bu çözümün portre görüntüleri veya aşağı yönlü görüntülerle düzgün çalışmadığına dikkat edin (not ettiğiniz için teşekkür ederiz Timmmm). Timmmm'in yukarıdaki çözümü gerekirse daha iyi bir seçim olabilir ve daha zarif görünüyor: 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

Şerefe


Bu düzgün çalışmaz. Portre görüntüleri ne olacak? Baş aşağı görüntüler? Exif verilerini kullanmak çok daha iyidir.
Timmmm

Uygulamalarımdan birinde düzgün çalışıyor, ancak elbette her türlü senaryoyu test etmedim. @Timmmm, çalışmadığı senaryolarda lütfen daha spesifik olabilir misiniz? Ayrıca görevimi oylama konusunda oldukça şaşkınım. Potansiyel bir çözümü paylaşmaya yönelik dürüst bir denemeye oldukça sert bir yanıt gibi görünüyor.
Martin

Sert olmak istememiştim; afedersiniz! Hiç kimsenin çözümünüzü çalışmasını umarak kopyalamasını istemedim. Dediğim gibi, portre veya baş aşağı görüntüler için işe yaramaz. Cevap olarak doğru çözümü ekleyeceğim.
Timmmm

Anlıyorum. Yukarıda çözümünüzü tercih ettiğiniz şekilde vurgulayan bir yorum ekleyeceğim.
Martin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.