70

I have this code:

//choosed a picture
public void onActivityResult(int requestCode, int resultCode, Intent data) {

    if (resultCode == RESULT_OK) {
        if (requestCode == ImageHelper.SELECT_PICTURE) {

            String picture           = "";

            Uri selectedImageUri     = data.getData();
            //OI FILE Manager
            String filemanagerstring = selectedImageUri.getPath();
            //MEDIA GALLERY
            String selectedImagePath = ImageHelper.getPath(mycontext, selectedImageUri);

            picture=(selectedImagePath!=null)?selectedImagePath:filemanagerstring;

...

This is only a picture chooser, from gallery. This is nice, but when I open this picture on an ImageView, the images when took on "PORTRAIT MODE" with the camera look nice, but the images that took "LANDSCAPE MODE" with the camera, opening in -90 degrees.

How can i rotate those pictures back?

    Bitmap output       = Bitmap.createBitmap(newwidth, newheight, Config.ARGB_8888);
    Canvas canvas       = new Canvas(output);

I tried this:

Log.e("w h", bitmap.getWidth()+" "+bitmap.getHeight());
if (bitmap.getWidth()<bitmap.getHeight()) canvas.rotate(-90);

But this is not working, all image size is: *2560 1920 pixel (PORTRAIT, and LANDSCAPE mode all)

What can I do to rotate back the LANDSCAPE pictures?

Janusz
  • 187,060
  • 113
  • 301
  • 369
lacas
  • 13,928
  • 30
  • 109
  • 183

3 Answers3

241

If a photo is taken with a digital camera or smartphone, rotation is often stored in the photo's Exif data, as part of the image file. You can read an image's Exif meta-data using the Android ExifInterface.

First, create the ExifInterface:

ExifInterface exif = new ExifInterface(uri.getPath());

Next, find the current rotation:

int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);  

Convert exif rotation to degrees:

int rotationInDegrees = exifToDegrees(rotation);

where

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

Then use the image's actual rotation as a reference point to rotate the image using a Matrix.

Matrix matrix = new Matrix();
if (rotation != 0) {matrix.preRotate(rotationInDegrees);}

You create the new rotated image with the Bitmap.createBitmap method that take a Matrix as a parameter:

Bitmap.createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)

where Matrix m holds the new rotation:

Bitmap adjustedBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, width, height, matrix, true);

See this tutorial for a useful source code example:

Gunnar Karlsson
  • 28,350
  • 10
  • 68
  • 71
  • This is a correct answer, but I want to add a note. Sometimes your cameras/phone orientation is not 'aligned' with the image, so you might need more than just the 3 options he has there. For example, for my app I needed to add this: `else if(exifOrientation == ExifInterface.ORIENTATION_NORMAL) { return 90; }` For all the options you can look here: http://developer.android.com/reference/android/media/ExifInterface.html#ORIENTATION_FLIP_HORIZONTAL – Aggressor May 21 '15 at 17:42
  • @GunnarKarlsson what is sourceBitmap here? - Bitmap adjustedBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, width, height, matrix, true); as I have source Uri, not Bitmap – Narendra Singh Jul 02 '15 at 13:40
  • @DroidWormNarendra See: http://stackoverflow.com/questions/3879992/get-bitmap-from-an-uri-android – Gunnar Karlsson Jul 02 '15 at 23:35
  • 3
    i get an error referring to it not being a document E/JHEAD: can't open '/document/image:82297' – Martin Seal May 28 '16 at 22:11
  • No need to read Exif data and rotate manually. Glide does everything.... – Brijesh Kumar Feb 16 '17 at 11:26
  • 2
    Great answer, thanks. @JamesTan If you get FILE NOT FOUND exception, use " private String getPath(Uri uri) { String[] data = { MediaStore.Images.Media.DATA }; CursorLoader loader = new CursorLoader(this, uri, data, null, null, null); Cursor cursor = loader.loadInBackground(); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); return cursor.getString(column_index); }" – s0i1 Jul 07 '17 at 11:50
  • For a better code solution then only rotation please see this code: https://stackoverflow.com/a/20480741/2195518 it also includes flip etc – Kapitein Witbaard Oct 19 '17 at 15:08
  • How to check orientation position using bitmap notlike from file – Kalanidhi Sep 17 '19 at 11:06
  • Exif data is always 0 when used on Google Pixel with Google camera – nayan dhabarde Dec 21 '19 at 06:53
6

if you are Using Jetpack CameraX, inside onImageCaptured method you can access rotation degree provided by EXIF data from the imageProxy like this:

image.imageInfo.rotationDegrees

then while setting your image you can rotate your image according to this degree

Ege Kuzubasioglu
  • 5,991
  • 12
  • 49
  • 85
  • You can do it better through getter. `imageProxy.getImageInfo().getRotationDegrees()`. Plus, if you are using the `ImageAnalysis` is the same way for the proxy image – BCJuan Dec 30 '20 at 16:39
4

Last answer was technically perfect, but I tried hard to create a system to manage pictures, rotate, resize, cache and load into ImageViews and I can tell it is a hell. Even when all it was done it crashes sometimes cause OutOfMemory in some devices.

My point is do not reinvent the wheel, it has a perfect design. Google itself encourage you to use Glide. It works in one line, super easy to use, lightweight in size and functions number, it manage EXIF by default, and it use memory like a charm.. It is simply black magic coded ;)

I'm not sure if Picasso also manages EXIF, but there is a quick intro to both of them:

https://inthecheesefactory.com/blog/get-to-know-glide-recommended-by-google/en

My Advice: do not waste your time and use them. You can solve your problem in one line:

Glide.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Santi Iglesias
  • 454
  • 4
  • 11
  • 4
    Yes but the problem is, if you've decoded/down sampled a bit for example or compressed using the jpeg format. EXIF is not preserved, so you need to reset the attributes to the new file. – ngatirauks Feb 02 '17 at 02:29
  • 1
    This does not work with Google pixel with Google camera – nayan dhabarde Dec 21 '19 at 06:54
  • I cannot recommend using glide enough. Ive been having substantial delay in scrolling with a single image in a recyclerview, and as soon as I switched to using glide instead of handling myself the difference was night and day. Of course you could achieve the same doing it yourself, but the one liner as above is invaluable – Tokens94 Mar 21 '21 at 11:44