Android: Aus der Galerie geladene Bitmaps werden in ImageView gedreht

138

Wenn ich ein Bild aus der Mediengalerie in eine Bitmap lade, funktioniert alles einwandfrei, außer dass Bilder, die mit der Kamera aufgenommen wurden, während das Telefon vertikal gehalten wurde, so gedreht werden, dass ich immer ein horizontales Bild erhalte, obwohl es vertikal in der angezeigt wird Galerie. Warum ist das so und wie kann ich es richtig laden?

Manuel
quelle

Antworten:

40

Haben Sie sich die EXIF-Daten der Bilder angesehen? Möglicherweise kennt es die Ausrichtung der Kamera, als das Bild aufgenommen wurde.

James
quelle
2
Du hast recht, das war natürlich die Lösung. Ich werde meinen Code später als Beispiel in einer separaten Antwort veröffentlichen, aber ich markiere diesen als akzeptiert, weil er mich auf den richtigen Weg gebracht hat.
Manuel
182

Also als Beispiel ...

Zuerst müssen Sie ein ExifInterface erstellen:

ExifInterface exif = new ExifInterface(filename);

Sie können dann die Ausrichtung des Bildes erfassen:

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

Die Orientierungswerte bedeuten Folgendes : http://sylvana.net/jpegcrop/exif_orientation.html

Die wichtigsten Werte sind also 3, 6 und 8. Wenn die Ausrichtung beispielsweise ExifInterface.ORIENTATION_ROTATE_90(6) ist, können Sie das Bild wie folgt drehen:

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

Das ist jedoch nur ein kurzes Beispiel. Ich bin sicher, es gibt andere Möglichkeiten, die eigentliche Rotation durchzuführen. Aber Sie finden diese auch auf StackOverflow.

Manuel
quelle
5
Hier sind alle Rotationswerte für die verschiedenen Ausrichtungen: 3: 180, 6: 90, 8: 270
Anzeigename
102
Verwenden Sie keine magischen Zahlen, wenn Sie benannte Konstanten verwenden können: ExifInterface.ORIENTATION_NORMAL, ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_ROTATE_180, ExifInterface.ORIENTATION_ROTATE_270.
d60402
29
Achten Sie darauf, OutOfMemoryErrorwann Sie diesen Ansatz verwenden, da Sie zwei Bitmaps gleichzeitig im Speicher halten.
Alex Bonel
Ein weiteres vollständiges Beispiel ... stackoverflow.com/questions/14066038/…
CGR
64

Dies ist eine vollständige Lösung (im Hackbook-Beispiel des Facebook SDK enthalten). Es hat den Vorteil, dass kein Zugriff auf die Datei selbst erforderlich ist. Dies ist äußerst nützlich, wenn Sie ein Bild vom Content Resolver-Ding laden (z. B. wenn Ihre App auf eine Absicht zum Teilen von Fotos reagiert).

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

Und dann können Sie eine gedrehte Bitmap wie folgt erhalten. Dieser Code verkleinert das Bild (leider) auf MAX_IMAGE_DIMENSION. Andernfalls kann der Speicherplatz knapp werden.

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
quelle
1
Was bedeutet das MAX_IMAGE_DIMENDION?
Sazzad Hissain Khan
3
Dies ist die maximale Breite oder Höhe des Bildes, das Sie erhalten. Das heißt, Sie benötigen nur ein 512 x 512-Bild. Wenn Sie ein 24-Megapixel-Bild öffnen, ist es viel effizienter, es bereits unterabgetastet zu öffnen, als das Ganze zu öffnen und dann zu verkleinern - das würde wahrscheinlich ohnehin Ihren gesamten Speicher erschöpfen.
Timmmm
In meinen Programmen fand ich es nützlich, die Bitmap-Variable in der Aktivität / dem Fragment als private statische zu definieren und sie in den Funktionen auf null zu setzen. Hatte dann weniger Speicherprobleme.
Gunnar Bernstein
Es ist klüger, MAX_IMAGE_DIMENDION durch MAX_IMAGE_WIDTH und MAX_IMAGE_HEIGHT zu ersetzen
fnc12
Viel Zeit gespart :) Vielen Dank. Für diejenigen , null Cursor bekommen, können Sie versuchen, ExifInterface exif = new ExifInterface(photoUri.getPath());und dann exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1)Orientierung zu erhalten (zB ORIENTATION_ROTATE_90, ORIENTATION_ROTATE_180)
Atul
60

In meinem Fall wurde es mit diesem Code mithilfe dieses Beitrags gelöst:

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

Hoffe, es spart jemandem Zeit!

Teo Inke
quelle
Bearbeitungsvorschläge: Gibt es keine richtig benannten Konstanten für die Orientierungen 6, 3, 8? Können wir die neue Bitmap nicht überspringen, wenn keine Drehung erforderlich ist?
Cee McSharpface
Wie bereits in einem Kommentar unter @ d60402 erwähnt, können Sie benannte Konstanten verwenden: ExifInterface.ORIENTATION_NORMAL, ExifInterface.ORIENTATION_ROTATE_90, ExifInterface.ORIENTATION_ROTATE_180, ExifInterface.ORIENTATION_ROTATE_270.
Adrian
42

Verwenden Sie ein Dienstprogramm, um das schwere Heben durchzuführen.

9re hat ein einfaches Dienstprogramm entwickelt, um das schwere Aufheben des Umgangs mit EXIF-Daten und das Drehen von Bildern in die richtige Ausrichtung zu bewältigen.

Den Dienstprogrammcode finden Sie hier: https://gist.github.com/9re/1990019

Laden Sie dies einfach herunter, fügen Sie es dem srcVerzeichnis Ihres Projekts hinzu und verwenden Sie es ExifUtil.rotateBitmap(), um die richtige Ausrichtung zu erhalten, wie folgt:

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

Bitmap orientedBitmap = ExifUtil.rotateBitmap(imagePath, myBitmap);
Joshua Pinter
quelle
2
Funktioniert bei mir ! Ich habe gerade die Größe der Bitmap in das HD-Format geändert, bevor ich sie an ExifUtil.rotateBitmap () übergeben habe, um OutOfMemoryError wie folgt zu vermeiden: Bitmap resized = Bitmap.createScaledBitmap (myBitmap, 720, 1280, true); photo = ExifUtil.rotateBitmap (picturePath, Größe geändert);
Phil
@Phil Schöne Ergänzung. Ich bin nicht darauf gestoßen (ich verwende ältere, beschissenere Android-Geräte), aber das ist wirklich gut zu wissen.
Joshua Pinter
3
Du bist ein Held, mein Freund :)
Klutch
@klutch Du hast gerade meinen Tag gemacht. :) Um fair zu sein, hat 9re made den Utility-Code geschrieben, damit er der wahre Held ist.
Joshua Pinter
1
@SreekanthKarumanaghat Gute Frage! Ich wusste wahrscheinlich, warum dies Sinn machte, als ich tief in dieses Thema vertieft war, aber im Moment scheint es auch für mich überflüssig zu sein. Ich habe vielleicht zu viel Zeit in React Native verbracht.
Joshua Pinter
8

Es liegt daran, dass die Galerie korrekt gedrehte Bilder anzeigt, aber nicht ImageView.

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

und du brauchst das:

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
quelle
5

Habe es nach vielen Versuchen dank eines Beitrags zum Laufen gebracht, den ich nicht mehr finden kann :-(

Exif scheint immer zu funktionieren, die Schwierigkeit bestand darin, den Dateipfad zu erhalten. Der Code, den ich gefunden habe, unterscheidet zwischen API älter als 4.4 und nach 4.4. Grundsätzlich enthält der Bild-URI für 4.4+ "com.android.providers". Für diesen URI-Typ verwendet der Code DocumentsContract, um die Bild-ID abzurufen, und führt dann eine Abfrage mit dem ContentResolver aus, während der Code für ältere SDKs direkt den URI mit dem ContentResolver abfragt.

Hier ist der Code (leider kann ich nicht gutschreiben, wer ihn gepostet hat):

/**
 * 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
quelle
Vielen Dank an dich. Nach stundenlanger Arbeit mit Cursorn und Exifs kann dieser Tag gespeichert werden. Wie Sie sagten, hat exif tatsächlich echte und zuverlässige Daten anstelle von Cursor-Rückgaben. Geben Sie einfach den richtigen Pfad ein, als es funktioniert.
Asozcan
3

Sie können einfach den Pfad von der SD-Karte lesen und den folgenden Code ausführen ... das vorhandene Foto wird nach dem Drehen ersetzt.

Nicht: Exif funktioniert auf den meisten Geräten nicht, es gibt die falschen Daten aus, daher ist es gut, die Drehung vor dem Speichern in einem beliebigen Grad hart zu codieren. Sie müssen nur den Winkelwert in postRotate in einen beliebigen Wert ändern.

    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
quelle
2
Dies ist zu drehen, aber wir wissen nicht, ob das Bild gedreht werden muss.
MSaudi
3

Kotlin-Code:

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
quelle
2

Ich habe die Antwort von Teo Inke verbessert. Das Bild wird nicht mehr gedreht, es sei denn, dies ist tatsächlich erforderlich. Es ist auch einfacher zu lesen und sollte schneller laufen.

// 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);
user2820531
quelle
2

Das erste, was Sie brauchen, ist der echte Dateipfad. Wenn Sie es gut haben und URI verwenden, verwenden Sie diese Methode, um den echten Pfad zu erhalten:

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

Extrahieren Sie Ihre Bitmap zum Beispiel:

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

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

Sie können stattdessen decodeFile () verwenden, wenn Sie möchten.

Nachdem Sie die Bitmap und den realen Pfad haben, erhalten Sie die Ausrichtung des Bildes:

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

und schließlich drehen Sie es wie folgt in die richtige Position:

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

Jetzt haben Sie die Bitmap in die richtige Position gedreht.

Prost.

Gal Rom
quelle
1

Dies funktioniert, ist aber wahrscheinlich nicht der beste Weg, aber es könnte jemandem helfen.

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
quelle
1

Vielleicht hilft das (um 90 Grad drehen) (das hat bei mir funktioniert)

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
quelle
1

Der Cursor sollte nach dem Öffnen geschlossen werden.

Hier ist ein Beispiel.

 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
quelle
1

Ich habe @Timmmm Antwort und @Manuel geschmolzen. Wenn Sie diese Lösung ausführen, wird keine Ausnahme für "Nicht genügend Speicher" angezeigt.

Diese Methode ruft die Bildausrichtung ab:

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

Daher würden Sie diese Methode verwenden, um die Größe des Bilds zu ändern, bevor Sie es in den Speicher laden. Auf diese Weise erhalten Sie keine Speicherausnahme.

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

Das funktioniert perfekt für mich. Ich hoffe das hilft jemand anderem

Antonio
quelle
0

Verbesserung der obigen Lösung durch Timmmm, um am Ende eine zusätzliche Skalierung hinzuzufügen, um sicherzustellen, dass das Bild innerhalb der Grenzen passt:

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;
}
Gemeiner Mann
quelle
0

Verwenden Sie den folgenden Code, um ein Bild richtig zu drehen:

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
quelle
Sie können alle if-Bedingungen zusammenführen, um einen kleineren Code zu erhalten.
Chandranshu
0

Die folgenden Methoden skalieren UND drehen die Bitmap entsprechend der Ausrichtung:

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

Beispiel:

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
quelle
-3

Ich habe das Problem mit der folgenden Problemumgehung gelöst. Beachten Sie, dass ich auch das Bild skaliere, was erforderlich war, um OutOfMemoryExceptions zu vermeiden.

Beachten Sie, dass diese Lösung mit Porträtbildern oder verkehrten Bildern nicht ordnungsgemäß funktioniert (danke Timmmm für die Notiz). Die obige Lösung von Timmmm ist möglicherweise die bessere Wahl, wenn dies erforderlich ist, und sie sieht auch eleganter aus: 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

Prost

Martin
quelle
Das wird nicht richtig funktionieren. Was ist mit Porträtbildern? Umgedrehte Bilder? Die Verwendung der Exif-Daten ist viel besser.
Timmmm
Es funktioniert ordnungsgemäß in einer meiner Apps, aber ich habe natürlich nicht alle Arten von Szenarien getestet. @Timmmm Könnten Sie bitte genauer angeben, in welchen Szenarien es nicht funktioniert? Ich bin auch ziemlich verwirrt darüber, dass Sie meinen Beitrag abgelehnt haben. Es scheint eine ziemlich harte Reaktion auf einen ehrlichen Versuch zu sein, eine mögliche Lösung zu teilen.
Martin
Ich wollte nicht hart sein; Es tut uns leid! Ich wollte nur nicht, dass jemand Ihre Lösung kopiert, in der Hoffnung, dass sie funktionieren würde. Wie gesagt, es funktioniert nicht für Porträt- oder verkehrte Bilder. Ich werde die richtige Lösung als Antwort hinzufügen.
Timmmm
Aha. Ich werde einen Kommentar hinzufügen, in dem Ihre oben genannte Lösung als die bevorzugte hervorgehoben wird.
Martin