Android Camera Intent Saving Image Landscape When Taken Portrait

34,821

Solution 1

The picture is always taken in the orientation the camera is built into the device. To get your image rotated correctly you'll have to read the orientation information that is stored into the picture (EXIF meta data). There it is stored how the device was oriented, when the image was taken.

Here is some code that reads the EXIF data and rotates the image accordingly: file is the name of the image file.

BitmapFactory.Options bounds = new BitmapFactory.Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file, bounds);

BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap bm = BitmapFactory.decodeFile(file, opts);
ExifInterface exif = new ExifInterface(file);
String orientString = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
int orientation = orientString != null ? Integer.parseInt(orientString) :  ExifInterface.ORIENTATION_NORMAL;

int rotationAngle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) rotationAngle = 90;
if (orientation == ExifInterface.ORIENTATION_ROTATE_180) rotationAngle = 180;
if (orientation == ExifInterface.ORIENTATION_ROTATE_270) rotationAngle = 270;

Matrix matrix = new Matrix();
matrix.setRotate(rotationAngle, (float) bm.getWidth() / 2, (float) bm.getHeight() / 2);
Bitmap rotatedBitmap = Bitmap.createBitmap(bm, 0, 0, bounds.outWidth, bounds.outHeight, matrix, true);

UPDATE 2017-01-16

With the release of the 25.1.0 Support Library, an ExifInterface Support Library was introduced, which should perhaps make the access to the Exif attributes easier. See the Android Developer's Blog for an article about it.

Solution 2

The selected answer uses the most common method answered to this and similar questions. However, it did not work for me with both front and back cameras on Samsung. For those needing another solution which works across both front and back cameras for Samsung and other major manufacturers, this answer by nvhausid is awesome:

https://stackoverflow.com/a/18915443/6080472

For those who don't want to click through, the relevant magic is to use the CameraInfo rather then relying on EXIF or a Cursor over the media files.

Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(mCurrentCameraId, info);
Bitmap bitmap = rotate(realImage, info.orientation);

Full code in the link.

Share:
34,821
StuStirling
Author by

StuStirling

Updated on January 17, 2020

Comments

  • StuStirling
    StuStirling over 4 years

    I have had a look around but there doesn't seem to be a solid answer/solution to the, very irritating, problem.

    I take a picture in portrait orientation and when I hit save/discard the buttons are in the correct orientation also. The problem is when I then retrieve the image later on it is in landscape orientation (the picture has been rotated 90 degrees anti-clockwise)

    I don' want to force the user to use the camera in a certain orientation.

    Is there a way to maybe detect whether the photo was taken in portrait mode and then decode the bitmap and flip it the correct way up?

  • Dori
    Dori about 11 years
    +1 many thanks! Shame no way to do without the (sometimes) creation of second bitmap. Damn Android and its tiny VMs
  • lschlessinger
    lschlessinger almost 10 years
    Where do you initialize opts and resizedBitmap?
  • Ridcully
    Ridcully almost 10 years
    @lschessinger, good catch (after 2 years). I've updated the code.
  • Admin
    Admin over 8 years
    please see here
  • Admin
    Admin over 8 years
    rotatedBitmap is never used..
  • Ridcully
    Ridcully over 8 years
    rotatedBitmap is the result of the whole operation. It contains the corrected image (rotated according to EXIF information)
  • Srujan Barai
    Srujan Barai about 8 years
    setRotate seems to be removed by Android. This code does not work anymore
  • Ridcully
    Ridcully about 8 years
  • Sudip Bhandari
    Sudip Bhandari over 7 years
    what is the first decode doing here? It is not returning any bitmap but as per documentation "the out... fields will still be set" with bounds.inJustDecodeBounds = true; What does this mean?
  • Ridcully
    Ridcully over 7 years
    @SudipBhandari the first decode() just reads the size of the bitmap into the bounds variable. It is used later on.
  • Sudip Bhandari
    Sudip Bhandari over 7 years
    can we get exif from bitmap directly without writing it to a file? @Ridicully
  • Ridcully
    Ridcully over 7 years
    @SudipBhandari No you can't. EXIF is part of the JPEG file, not part of the bitmap. The bitmap is just raw, uncompressed image data.
  • AKSHAY MANAGOOLI
    AKSHAY MANAGOOLI over 6 years
    hey its taking too much time any solution on that?,
  • lacas
    lacas over 6 years
    this code not working at all on my samsung galaxy s7. can you help me? it makes me so crazy
  • Ridcully
    Ridcully over 6 years
    @lacas try to run in debugger and see what orientation you read from the file. Also, if possible try the ExifInterface Support Library I mentioned.
  • Ridcully
    Ridcully over 6 years
    @lacas also see answer by D. Scott below, about Samsung devices
  • lacas
    lacas over 6 years
    It is not working too.............
  • User
    User about 6 years
    Where does mCurrentCameraId come from?