Android getting an image from gallery comes rotated-ThrowExceptions

Exception or error:

I am trying to let users select a profile picture from gallery. My issue is that some pictures come as rotated to the right.

I start the image picker like so:

Intent photoPickerIntent = new Intent();
photoPickerIntent.setType("image/*");
photoPickerIntent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(photoPickerIntent, "Select profile picture"), Global.CODE_SELECT_PICTURE);

I get the image from onActivityResult like so:

Uri selectedPicture = data.getData();
profilePic = MediaStore.Images.Media.getBitmap(activity.getContentResolver(), selectedPicture);

How can i make have images not to be rotated?

UPDATE:

Following some of the helpful answers i have received, i managed to come up with the following working solution (It’s just a working code, not well written). I would love to get your feedback on how i can improve it!

public void onActivityResult(int requestCode, int resultCode, Intent data) {

    if (resultCode == Activity.RESULT_OK && requestCode == Global.CODE_SELECT_PICTURE) {

        // Get selected gallery image
        Uri selectedPicture = data.getData();
        // Get and resize profile image
        String[] filePathColumn = {MediaStore.Images.Media.DATA};
        Cursor cursor = activity.getContentResolver().query(selectedPicture, filePathColumn, null, null, null);
        cursor.moveToFirst();

        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        String picturePath = cursor.getString(columnIndex);
        cursor.close();

        Bitmap loadedBitmap = BitmapFactory.decodeFile(picturePath);

        ExifInterface exif = null;
        try {
            File pictureFile = new File(picturePath);
            exif = new ExifInterface(pictureFile.getAbsolutePath());
        } catch (IOException e) {
            e.printStackTrace();
        }

        int orientation = ExifInterface.ORIENTATION_NORMAL;

        if (exif != null)
            orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

        switch (orientation) {
            case ExifInterface.ORIENTATION_ROTATE_90:
                loadedBitmap = rotateBitmap(loadedBitmap, 90);
                break;
            case ExifInterface.ORIENTATION_ROTATE_180:
                loadedBitmap = rotateBitmap(loadedBitmap, 180);
                break;

            case ExifInterface.ORIENTATION_ROTATE_270:
                loadedBitmap = rotateBitmap(loadedBitmap, 270);
                break;
        }           
    }
}

public static Bitmap rotateBitmap(Bitmap bitmap, int degrees) {
    Matrix matrix = new Matrix();
    matrix.postRotate(degrees);
    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
How to solve:

You could use ExifInterface to modify the orientation:

public static Bitmap modifyOrientation(Bitmap bitmap, String image_absolute_path) throws IOException {
    ExifInterface ei = new ExifInterface(image_absolute_path);
    int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

    switch (orientation) {
    case ExifInterface.ORIENTATION_ROTATE_90:
        return rotate(bitmap, 90);

    case ExifInterface.ORIENTATION_ROTATE_180:
        return rotate(bitmap, 180);

    case ExifInterface.ORIENTATION_ROTATE_270:
        return rotate(bitmap, 270);

    case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
        return flip(bitmap, true, false);

    case ExifInterface.ORIENTATION_FLIP_VERTICAL:
        return flip(bitmap, false, true);

    default:
        return bitmap;
    }
}

public static Bitmap rotate(Bitmap bitmap, float degrees) {
    Matrix matrix = new Matrix();
    matrix.postRotate(degrees);
    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}

public static Bitmap flip(Bitmap bitmap, boolean horizontal, boolean vertical) {
    Matrix matrix = new Matrix();
    matrix.preScale(horizontal ? -1 : 1, vertical ? -1 : 1);
    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}

In order to get absolute path of your images from their uri, check this answer

###

2 One line solutions using Picasso and glide library

After spending a lot of time with a lot of solutions for image rotation problem I finally found two simple solutions. We don’t need to do any additional works.

Using Picasso library https://github.com/square/picasso

Picasso.with(context).load("http url or sdcard url").into(imageView);

Using glide library https://github.com/bumptech/glide

Glide.with(this).load("http url or sdcard url").into(imgageView);

Picasso and Glide are a very powerful library for handling images in your app includes. It will read image EXIF data and auto-rotates the images.

###

I use these static methods. The first determines the orientation and the second rotates the image shrinking it as needed.

public static int getOrientation(Context context, Uri photoUri) {

    Cursor cursor = context.getContentResolver().query(photoUri,
            new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);

    if (cursor == null || cursor.getCount() != 1) {
        return 90;  //Assuming it was taken portrait
    }

    cursor.moveToFirst();
    return cursor.getInt(0);
}

/**
* Rotates and shrinks as needed
*/
public static Bitmap getCorrectlyOrientedImage(Context context, Uri photoUri, int maxWidth)
                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) {
                Log.d("ImageUtil", "Will be rotated");
                rotatedWidth = dbo.outHeight;
                rotatedHeight = dbo.outWidth;
            } else {
                rotatedWidth = dbo.outWidth;
                rotatedHeight = dbo.outHeight;
            }

            Bitmap srcBitmap;
            is = context.getContentResolver().openInputStream(photoUri);
            Log.d("ImageUtil", String.format("rotatedWidth=%s, rotatedHeight=%s, maxWidth=%s",
                    rotatedWidth, rotatedHeight, maxWidth));
            if (rotatedWidth > maxWidth || rotatedHeight > maxWidth) {
                float widthRatio = ((float) rotatedWidth) / ((float) maxWidth);
                float heightRatio = ((float) rotatedHeight) / ((float) maxWidth);
                float maxRatio = Math.max(widthRatio, heightRatio);
                Log.d("ImageUtil", String.format("Shrinking. maxRatio=%s",
                        maxRatio));

                // Create the bitmap from file
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = (int) maxRatio;
                srcBitmap = BitmapFactory.decodeStream(is, null, options);
            } else {
                Log.d("ImageUtil", String.format("No need for Shrinking. maxRatio=%s",
                        1));

                srcBitmap = BitmapFactory.decodeStream(is);
                Log.d("ImageUtil", String.format("Decoded bitmap successful"));
            }
            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;
        }

###

I do it this way:

public void browseClick(View view) {
    view.startAnimation(AnimationUtils.loadAnimation(getApplicationContext(), R.anim.button_animation));
    Intent i = new Intent(
            Intent.ACTION_PICK,
            android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);

    startActivityForResult(i, RESULT_LOAD_IMAGE);
}

And the result where the orientation is checked will interest you most:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data) {
        Uri selectedImage = data.getData();
        String[] filePathColumn = { MediaStore.Images.Media.DATA };

        Cursor cursor = getContentResolver().query(selectedImage,
                filePathColumn, null, null, null);
        cursor.moveToFirst();

        int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
        String picturePath = cursor.getString(columnIndex);
        cursor.close();

        Bitmap loadedBitmap = BitmapFactory.decodeFile(picturePath);

        Matrix matrix = new Matrix();
        Bitmap scaledBitmap;
        if (loadedBitmap.getWidth() >= loadedBitmap.getHeight()){
            matrix.setRectToRect(new RectF(0, 0, loadedBitmap.getWidth(), loadedBitmap.getHeight()), new RectF(0, 0, 400, 300), Matrix.ScaleToFit.CENTER);
            scaledBitmap = Bitmap.createBitmap(loadedBitmap, 0, 0, loadedBitmap.getWidth(), loadedBitmap.getHeight(), matrix, true);
        } else{
            matrix.setRectToRect(new RectF(0, 0, loadedBitmap.getWidth(), loadedBitmap.getHeight()), new RectF(0, 0, 300, 400), Matrix.ScaleToFit.CENTER);
            scaledBitmap = Bitmap.createBitmap(loadedBitmap, 0, 0, loadedBitmap.getWidth(), loadedBitmap.getHeight(), matrix, true);
        }

        File file = new File(getExternalCacheDir(), "image.jpg");
        try {
            FileOutputStream out = new FileOutputStream(file);
            scaledBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
            out.flush();
            out.close();
        } catch (Exception e) {
            Log.e("Image", "Convert");
        }

        imageView.setImageBitmap(scaledBitmap);
    }
}

###

Here is the ExifInterface approach written in Kotlin:

fun modifyOrientation(bitmap: Bitmap, image_absolute_path: String): Bitmap {
    val ei = ExifInterface(image_absolute_path)
    val orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
    return when (orientation) {
        ExifInterface.ORIENTATION_ROTATE_90 -> rotateImage(bitmap, 90f)
        ExifInterface.ORIENTATION_ROTATE_180 -> rotateImage(bitmap, 180f)
        ExifInterface.ORIENTATION_ROTATE_270 -> rotateImage(bitmap, 270f)
        ExifInterface.ORIENTATION_FLIP_HORIZONTAL -> flipImage(bitmap, true, false)
        ExifInterface.ORIENTATION_FLIP_VERTICAL -> flipImage(bitmap, false, true)
        else -> bitmap
    }
}

private fun rotateImage(bitmap: Bitmap, degrees: Float): Bitmap {
    val matrix = Matrix()
    matrix.postRotate(degrees)
    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
}

private fun flipImage(bitmap: Bitmap, horizontal: Boolean, vertical: Boolean): Bitmap {
    val matrix = Matrix()
    matrix.preScale((if (horizontal) -1 else 1).toFloat(), (if (vertical) -1 else 1).toFloat())
    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
}

###

Using Picasso:

Picasso.get().load(“Your image path”).into(Imageview);

Picasso.with(this) is now replaced with

Picasso.get()

Picasso library : https://github.com/square/picasso

Add : implementation ‘com.squareup.picasso:picasso:2.71828’ in build.gradle file

Picasso will take care of image auto-rotation .

Leave a Reply

Your email address will not be published. Required fields are marked *