0

This question has been asked countless times, but none of them actually fix the rotation issue when saving a Bitmap.

This is how I initially saved a Bitmap to my device:

FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever();
mmr.setDataSource(mStringFilePath);
//Time is us
int mPresentationTime = mPlayer.getPresentationTime();
Bitmap mBitmap = mmr.getFrameAtTime(mPresentationTime, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);

File mFileBitmap = new File(directoryToStore, "test.png");
try {
    FileOutputStream outputStream = new FileOutputStream(mFileBitmap);
    mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
    outputStream.close();
} catch (Exception e) {
    e.printStackTrace();
}

The above saves the .png with the wrong orientation.

I then saw this answer, but the problem is that it rotates the, already saved, Bitmap to the correct orientation. This is fine if you want to set the Bitmap to a ImageView, for example. But, what if I want to share the Bitmap, or want to open it in the devices Gallery, the orientation would then still be incorrect. I would then have to do the same process as above - FileOutputStream etc. This will then just cause the same issue.

How can I save a Bitmap to the device with the correct orientation?

Edit 1

Trying the answer provided by Long.

I created a new class called RotateBit, with the 2 method you provided. I then changed my code to this:

FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever();
mmr.setDataSource(mStringFilePath);
//Time is us
int mPresentationTime = mPlayer.getPresentationTime();
Bitmap mBitmapBeforeRotation = mmr.getFrameAtTime(mPresentationTime, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);

int rotatingInt = RotateBit.getBitmapOriention(mStringFilePath);
Bitmap mBitmap = RotateBit.rotateBitmap(mBitmapBeforeRotation, rotatingInt);

File mFileBitmap = new File(directoryToStore, "test.png");
try {
    FileOutputStream outputStream = new FileOutputStream(mFileBitmap);
    mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
    outputStream.close();
} catch (Exception e) {
    e.printStackTrace();
}

But still the rotation is incorrect.

Edit 2

I noticed that this issue is related to FFmpegMediaMetadataRetriever, when using MediaMetadataRetriever this issue doesn't happen.

halfer
  • 19,824
  • 17
  • 99
  • 186
ClassA
  • 2,480
  • 1
  • 26
  • 57

3 Answers3

0
public static int getBitmapOriention(String path){
    ExifInterface exif = null;
    int orientation = 0;
    try {
        exif = new ExifInterface(path);
        orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
                ExifInterface.ORIENTATION_UNDEFINED);
        //Log.e("getBitmapOriention", "getBitmapOriention: "+orientation );
    } catch (Exception e) {
        e.printStackTrace();
    }
    return orientation;
}
/**
 * @param bitmap bitmap from path
 * @param orientation ExifInterface
 * @return oriention flag
 */
public static Bitmap rotateBitmap(Bitmap bitmap, int orientation) {

    Matrix matrix = new Matrix();
    switch (orientation) {
        case ExifInterface.ORIENTATION_NORMAL:
            return bitmap;
        case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
            matrix.setScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_ROTATE_180:
            matrix.setRotate(180);
            break;
        case ExifInterface.ORIENTATION_FLIP_VERTICAL:
            matrix.setRotate(180);
            matrix.postScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_TRANSPOSE:
            matrix.setRotate(90);
            matrix.postScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_ROTATE_90:
            matrix.setRotate(90);
            break;
        case ExifInterface.ORIENTATION_TRANSVERSE:
            matrix.setRotate(-90);
            matrix.postScale(-1, 1);
            break;
        case ExifInterface.ORIENTATION_ROTATE_270:
            matrix.setRotate(-90);
            break;
        default:
            return bitmap;
    }
    try {
        Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
        bitmap.recycle();
        return bmRotated;
    }
    catch (OutOfMemoryError e) {
        e.printStackTrace();
        return null;
    }
}

it worked for me

rotateBitmap(mBitmap,getBitmapOriention(mPath));
Long
  • 16
  • 2
0

You need to use ExifInterface for rotation.

public static void normalizeImageForUri(Context context, Uri uri, ImageView imgImageView) {
        try {
//            Log.d(TAG, "URI value = " + uri.getPath());
            ExifInterface exif = new ExifInterface(getRealPathFromURI(context, uri));
//            Log.d(TAG, "Exif value = " + exif);
            int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
            Bitmap bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), uri);
            Bitmap rotatedBitmap = rotateBitmap(bitmap, orientation);
            imgImageView.setImageBitmap(rotatedBitmap);
        } catch (IOException e) {
            e.printStackTrace();
        }
}

For checking rotation of bitmap:

private static Bitmap rotateBitmap(Bitmap bitmap, int orientation) {
        Matrix matrix = new Matrix();
        switch (orientation) {
            case ExifInterface.ORIENTATION_NORMAL:
                return bitmap;
            case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
                matrix.setScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                matrix.setRotate(180);
                break;
            case ExifInterface.ORIENTATION_FLIP_VERTICAL:
                matrix.setRotate(180);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_TRANSPOSE:
                matrix.setRotate(90);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_90:
                matrix.setRotate(90);
                break;
            case ExifInterface.ORIENTATION_TRANSVERSE:
                matrix.setRotate(-90);
                matrix.postScale(-1, 1);
                break;
            case ExifInterface.ORIENTATION_ROTATE_270:
                matrix.setRotate(-90);
                break;
            default:
                return bitmap;
        }
        try {
            Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
            bitmap.recycle();

            return bmRotated;
        } catch (OutOfMemoryError e) {
            e.printStackTrace();
            return null;
        }
    }

More details you refer this links :

How to get the Correct orientation of the image selected from the Default Image gallery

https://github.com/google/cameraview/issues/22#issuecomment-269321811

Mayur Patel
  • 2,300
  • 11
  • 30
0

I've managed to create a work-around. This is probably not how it should be done, but for now, it works.


My Activity is set to portrait/landscape depending on the rotation of the video that I'm playing. So, I can use this to determine whether or not to rotate the Bitmap.

I first create a Bitmap like I previously did:

Bitmap mBitmapBeforeRotation = mmr.getFrameAtTime(mPresentationTime, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);

Then I get the rotation of the screen, the width/hight of the Bitmap and rotate the Bitmap accordingly:

int mBitW = Integer.parseInt(String.valueOf(mBitmapBeforeRotation.getWidth()));
int mBitH = Integer.parseInt(String.valueOf(mBitmapBeforeRotation.getHeight()));

int orientation = getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
// Do nothing because Landscape doesn't give wrong Bitmap rotation
} else {
    if (mBitW>mBitH){
    Matrix matrix = new Matrix();
    matrix.postRotate(90);
    Bitmap fixedBitmapRotation = Bitmap.createBitmap(mBitmapBeforeRotation, 0, 0, mBitmapBeforeRotation.getWidth(), mBitmapBeforeRotation.getHeight(), matrix, true);

    String nameOfImage = "nameOfImage" + ".jpeg";
    final File mFile = new File(directoryyToStore, nameOfImage);

    try {
        FileOutputStream outputStream = new FileOutputStream(mFile);
        fixedBitmapRotation.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
        outputStream.close();

    } catch (Exception e) {
        e.printStackTrace();
    }
    texeBit = mp.getPath();

}

Just a side note. I don't have to use the rotation of the screen to determine if I should rotate the Bitmap. I could first create a Bitmap with MediaMetadataRetriever (Because MediaMetadataRetriever gives my the correct rotation of the Bitmap) and then do it as below:

int videoWidth;
int videoHeight;

MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(this, mVideoUri);

Bitmap bmp = retriever.getFrameAtTime();

videoWidth = bmp.getWidth();
videoHeight = bmp.getHeight();

The I could do the same as above.


I will not be accepting my own answer because I haven't tested on multiple device, plus this is a very "hack-ish" way of resolving this issue.

ClassA
  • 2,480
  • 1
  • 26
  • 57