1

After taking a photo while the device is in portrait using the Camera API and a preview SurfaceView, the image that is created is rotated 90 degrees. I understand this is an issue affecting some android phones including the Samsung Galaxy S5 I'm developing on - there are several stack overflow questions about that - see here and here. It was suggested the image file will contain EXIF metadata that will state the orientation it was rotated by so you can use that to rotate the image back to obtain the correct orientation. I've done just that, but for some reason the ExifInterface.TAG_ORIENTATION is 1 - ORIENTATION_NORMAL. Therefore I cannot determine how much the image needs to be rotated to ensure it will work on all devices. Even though that solution seems to have worked for others. What have I done wrong, or how else could this issue be resolved?

Some pseudocode:

//in onCreate
camera = getCameraInstance();
setCameraDisplayOrientation(this, cameraID, camera);

//in OnClickListener
camera.takePicture(null, null, picCallback);

//callback:
onPictureTaken {
    //create a File using getExternalStoragePublicDirectory(PICTURES) + "appname" - create directory if doesn't exist
    //write file to disk via FileOutputStream

    //attempt to correct the image orientation if needed
    Bitmap correctBitmap = getCorrectOrientationBitmap(picFile.getAbsolutePath());
}

public Bitmap getCorrectOrientationBitmap(String photoFilePath) {
    // Read EXIF Data
    ExifInterface exif = null;
    try {
        exif = new ExifInterface(photoFilePath);
    } catch (IOException e) {
        e.printStackTrace();
        return null;
    }
    String orientation = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
    //problem: orientation is 1 - ORIENTATION_NORMAL despite the fact the image is rotated to the right 90 degrees
    //rotate the image based on EXIF orientation
}

//later on
myImageView.setImageBitmap(correctBitmap); 
//shows image rotated to the right because getCorrectOrientationBitmap didn't rotate it
Community
  • 1
  • 1
Jordan H
  • 52,571
  • 37
  • 201
  • 351
  • http://stackoverflow.com/questions/14066038/why-image-captured-using-camera-intent-gets-rotated-on-some-devices-in-android closely read all answers.. u are not getting correct bmp.ORIENT .. see the content query on the "mediaStore" at the link.. this is samsung only issue AFAIK – Robert Rowntree Mar 10 '15 at 21:41
  • @RobertRowntree I'm not using `MediaStore` – Jordan H Mar 10 '15 at 22:02
  • @JordanH Were you able to resolve this issue. I too am stuck at the same point. Images are being saved as rotated. Can you post a solution for this? – Shivam Pokhriyal Apr 25 '19 at 10:59

4 Answers4

0

--EDIT-- in my code...

matrix.postRotate(rotation);

uses the value for "rotation" that felix's code returns from his cursor.

i think your photos got a URI.... look at the interface vs the use of a static attr value for type....

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(null == cursor){
        return -1;
    }
    if (cursor.getCount() != 1) {
        return -1;
    }

.....

if (getOrientation(mctx, mURI) != 0 && != -1) doRotate();


public doRotate(){
    Bitmap lbit =   
    BitmapFactory.decodeStream(                                               getContentResolver().openInputStream(_uri),null,options);
    Log.i(TAG, "Rotating... " + rotation);
    lbit = lbit.copy(Bitmap.Config.ARGB_8888, true);
    Matrix matrix = new Matrix();
    matrix.postRotate(rotation);
    lbit = Bitmap.createBitmap(lbit, 0, 0, lbit.getWidth(),
    lbit.getHeight(), matrix, true);
    Picture.setBmp(lbit);

    cursor.moveToFirst();
    return cursor.getInt(0);
    }
}
Robert Rowntree
  • 6,230
  • 2
  • 24
  • 43
  • `cursor` is `null` when I try that. If I use the `getRotation` method from Felix's answer, it returns `0` - but `mediaCursor` is not null. – Jordan H Mar 11 '15 at 17:32
  • Felix=good possible solution for u. if the mediaCursor not null then try to use the return value to drive a rotation as in code from Felix. Note the solution i got was built on code from felix i think. I could not find any other explain for rotation on new samsung tablets and felix code solved that issue. My code may be usable verbatim but i tried to package up something that would make sense. Understand what felix was getting at. – Robert Rowntree Mar 11 '15 at 18:13
  • His `getRotation` code never uses the `selectedImage` `Uri` - this always returns the orientation of the last photo in gallery not the photo taken in the app – Jordan H Mar 11 '15 at 20:19
  • try using the Uri of the context in you picCallback. When it returns from camera, the implied intent's "getData()" should have the last photo's uri...my orig. code examples' Uri was set by doing an Intent selection on media type photos and used the Uri returned from that action. – Robert Rowntree Mar 11 '15 at 21:48
0

I was playing with this issue a while ago and posted some camera code on GitHub here. The issue was that you deal with 3 different entities:

  • surface orientation - depends on the device orientation at the moment
  • preview width / height you get from 'surfaceChanged'
  • final picture orientation as you get from 'takePicture'

In the example mentioned, I rotate the final image the same amount as I rotated the preview at the beginning. I haven't tested it on S5, so if you go this way, please let me know if it works there.

One more thing, there is also an issue with some tablets (see readme.md), where some have 'natural' orientation landscape (Nex7 1Gen) where others (Nex7 2Gen) have it portrait- same as phones.

Good Luck

seanpj
  • 6,735
  • 2
  • 33
  • 54
0

When you use picture callback instead of camera capture intent, EXIF orientation is not set. But on the other hand, you can know exactly the device orientation when the user clicked the "capture" button or its equivalent.

It becomes even easier if your activity is locked into Portrait orientation - you can unconditionally apply rotation by 90°.

Bitmap rotation may be pretty expensive in terms of both memory and performance, therefore if your use case is satisfied by setting the correct TAG_ORIENTATION, then simply apply this change to the image you save. Note that ExifInterface works with files, not byte[], therefore counterintuitively you should first save the buffer, then apply rotation, and save again.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • It would be fantastic if I could always ensure every phone will rotate the image 90 to the right when taking a photo in an activity that's locked in portrait. Can you confirm that will be the case - from my research it sounds like this behavior (bug?) only exists in a few phones (Samsung especially). – Jordan H Mar 11 '15 at 19:55
  • The answer is negative, unfortunately. Consider tablets that have "natural" orientation landscape, while other tablets (usually 7" ones) default to portrait. Not setting `TAG_ORIENTATION` in the callback is legitimate, but setting it according the current device orientation is legitimate, too. – Alex Cohn Mar 11 '15 at 20:09
-1

Before taking picture it is required to setDisplayOrientation() according to the current device orientation. This is not done automatically and by default is always set to 0 degrees that usually corresponds to landscape orientation.

This is not Galaxy s5 issue

Kirill K
  • 771
  • 6
  • 17
  • I've already called `setDisplayOrientation`. Will update code to show that. – Jordan H Mar 10 '15 at 21:47
  • and still got the issue? – Kirill K Mar 10 '15 at 21:47
  • Yes, I had that in my code before posting the question – Jordan H Mar 10 '15 at 21:49
  • setDisplayOrientation is only for the preview you are showing while using camera. It has no effect on the actual picture that is taken. The issue is regarding the image that is taken by camera.takePicture which comes rotated. @JordanH If you find the solution please post it here. – Shivam Pokhriyal Apr 25 '19 at 11:01