In my app, I let the user the chance to get a photo and set it as profile pic. There are 2 ways for getting the photo, from the gallery, and directly taken with the camera.
I have wrote code that works with booth methods, and I have tested on a Galaxy S5 with lollipop 5.0. When testing it with a KitKat 4.4.4, it is throwing a NPE. But is throwing this NPE just when taking the photo directly from the camera.
In booth cases, this is the structure I follow:
Get the Uri from the onActivityResult call data.
Get pic orientation value (in some cases the portrait image appears rotated in the imageview).
Decode the bitmap to downsize it mantaining the aspect ratio.
Rotate the image if it has the wrong orientation.
Save the bitmap in the internal app data.
An this is the code for the "take photo from camera" request:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case TAKE_PHOTO_REQUEST_FRAG:
if (resultCode == getActivity().RESULT_OK && data != null) {
Uri selectedImageUri = data.getData();
Bitmap srcBmp = null;
/*Get image orientation*/
int orientation = getImageOrientation(getActivity(), selectedImageUri);
Log.d("IMAGE_ORIENTATION", String.valueOf(orientation));
/*Downsize bitmap mantaining aspect ratio*/
srcBmp = decodeSampledBitmapFromUri(
selectedImageUri,
pic_view.getWidth(), pic_view.getHeight());
/*Rotate image if needed*/
if (orientation == 90) {
Matrix matrix = new Matrix();
matrix.postRotate(90);
srcBmp = Bitmap.createBitmap(srcBmp, 0, 0,
srcBmp.getWidth(), srcBmp.getHeight(), matrix,
true);
}
else if (orientation == 180) {
Matrix matrix = new Matrix();
matrix.postRotate(180);
srcBmp = Bitmap.createBitmap(srcBmp, 0, 0,
srcBmp.getWidth(), srcBmp.getHeight(), matrix,
true);
}
else if (orientation == 270) {
Matrix matrix = new Matrix();
matrix.postRotate(270);
srcBmp = Bitmap.createBitmap(srcBmp, 0, 0,
srcBmp.getWidth(), srcBmp.getHeight(), matrix,
true);
}
/*Save bitmap in internal memory*/
ContextWrapper cw1 = new ContextWrapper(getActivity().getApplicationContext());
File directory1 = cw1.getDir("profile", Context.MODE_PRIVATE);
if (!directory1.exists()) {
directory1.mkdir();
}
File filepath1 = new File(directory1, "profile_pic.png");
FileOutputStream fos1 = null;
try {
fos1 = new FileOutputStream(filepath1);
srcBmp.compress(Bitmap.CompressFormat.JPEG, 90, fos1);
fos1.close();
} catch (Exception e) {
Log.e("SAVE_FULL_IMAGE", e.getMessage(), e);
}
/*Show image in imageview*/
pic_view.setImageBitmap(srcBmp);
}
break;
}
}
-
/*Downsize the bitmap from uri*/
public Bitmap decodeSampledBitmapFromUri(Uri uri, int reqWidth, int reqHeight) {
Bitmap bm = null;
try{
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(getActivity().getContentResolver().openInputStream(uri), null, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeStream(getActivity().getContentResolver().openInputStream(uri), null, options);
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(getActivity().getApplicationContext(), e.toString(), Toast.LENGTH_LONG).show();
}
return bm;
}
public int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
-
/*Get image orientation first from Exif info*/
public int getImageOrientation(Context context, Uri photoUri) {
int orientation = getOrientationFromExif(photoUri);
if(orientation <= 0) {
orientation = getOrientationFromMediaStore(context, photoUri);
}
return orientation;
}
private int getOrientationFromExif(Uri photoUri) {
int orientation = -1;
try {
ExifInterface exif = new ExifInterface(photoUri.getPath());
int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (exifOrientation) {
case ExifInterface.ORIENTATION_ROTATE_270:
orientation = 270;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
orientation = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
orientation = 90;
break;
case ExifInterface.ORIENTATION_NORMAL:
orientation = 0;
break;
default:
break;
}
} catch (IOException e) {
Log.e("EXIF_ORIENTATION", "Unable to get image exif orientation", e);
}
return orientation;
}
/* normal landscape: 0
* normal portrait: 90
* upside-down landscape: 180
* upside-down portrait: 270
* image not found: -1
*/
private static int getOrientationFromMediaStore(Context context, Uri photoUri) {
String[] projection = {MediaStore.Images.ImageColumns.ORIENTATION};
Cursor cursor = context.getContentResolver().query(photoUri, projection, null, null, null);
try {
if (cursor.moveToFirst()) {
return cursor.getInt(0);
} else {
return -1;
}
} finally {
cursor.close();
}
}
It is throwing the NPE in the line where I want to get the image orientation from the exif data, exactly where I get the Path from the uri:
ExifInterface exif = new ExifInterface(photoUri.getPath());
So I know that it must be something with the path. I have readed several posts about that kitkat returns the path in a diferent format. I have tried diferent custom getPath() methods, but always throws NPE when calling the Cursor.
So I know that it must be something with the path.
That's because it's not a filesystem path. A Uri is not a file, and while you are handling that properly elsewhere, you are not doing so here.
You need to switch to EXIF logic that can handle an InputStream, such as this code culled from the AOSP Mms app.
I've seen several questions regarding this topic, but none that address my problem.
I dynamically create ImageViews and allow the user to take/add photos of items for an inventory. The following code exists to generate the Bitmap and populate the ImageView:
protected void addPhotosToView(ArrayList<String> uris) {
for (String uriString : uris) {
try {
Uri uri = Uri.parse(uriString);
File imageFile = new File(uri.getPath());
int orientation = resolveBitmapOrientation(imageFile);
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
bitmap = applyOrientation(bitmap, orientation);
ImageView image = new ImageView(ItemActivity.this);
int h = 100; // height in pixels
int w = 100; // width in pixels
Bitmap scaled = Bitmap.createScaledBitmap(bitmap, h, w, true);
image.setImageBitmap(scaled);
LinearLayout photoLayout = (LinearLayout) findViewById(R.id.itemPhotoLayout);
photoLayout.addView(image);
addClickListener(image, uri);
} catch (Exception e) {
e.printStackTrace();
}
}
}
But once the image is added or taken, some images appear with the wrong orientation. Some of the photos stored in the phone in portrait are displayed in portrait, while others appear to be in landscape. Landscape photos are equally arbitrary.
This does not appear to be happening on all devices (the device that I'm seeing this on is a Samsung S4)
As you can see in the code, I have tried getting/applying orientation changes using Exif tags, but I'm always getting 0 for the orientation with this device and have not seen any answers for questions that ask for a solution when orientation is always 0.
I'm looking to ship this software soon and need some sort of workaround or solution, so I'm willing to accept some other way of going from Uris/strings to a dynamic, horizontally scrollable list of properly oriented images if this can't be resolved any other way.
you need to decode the bitmap that's all try this tutorial you can download the source.
that application dose exactly what you want maybe it will help you i hope because it worked fine with my application
Please use this method to show/decode your bitmap. It is taken from another SO post I cant remember which and is modified for my use. This method returns bitmap according to the exif orientation data if present on the image:
public Bitmap decodeFile(String path) {// you can provide file path here
int orientation;
try {
if (path == null) {
return null;
}
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
// Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 70;
// final int REQUIRED_SIZE = 20;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 0;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE
|| height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale++;
}
// decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap bm = BitmapFactory.decodeFile(path, o2);
Bitmap bitmap = bm;
ExifInterface exif = new ExifInterface(path);
orientation = exif
.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Matrix m = new Matrix();
if ((orientation == ExifInterface.ORIENTATION_ROTATE_180)) {
m.postRotate(180);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
bm.getHeight(), m, true);
photo(bitmap, path);
return bitmap;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
m.postRotate(90);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
bm.getHeight(), m, true);
photo(bitmap, path);
return bitmap;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
m.postRotate(270);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
bm.getHeight(), m, true);
photo(bitmap, path);
return bitmap;
}
return bitmap;
} catch (Exception e) {
return null;
}
}
Photo is rotating 90 degree while capturing from camera in samsung mobile rest of other mobiles(HTC) its working fine. Please help me for this.
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(cameraIntent, IMAGE_CAPTURE);
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
try
{
if (requestCode == IMAGE_CAPTURE) {
if (resultCode == RESULT_OK){
Uri contentUri = data.getData();
if(contentUri!=null)
{
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
imageUri = Uri.parse(cursor.getString(column_index));
}
tempBitmap = (Bitmap) data.getExtras().get("data");
mainImageView.setImageBitmap(tempBitmap);
isCaptureFromCamera = true;
}
}
Some device rotate image according to device orientation .
here i have write one common method to get orientation and get image in right scale
public Bitmap decodeFile(String path) {//you can provide file path here
int orientation;
try {
if (path == null) {
return null;
}
// decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
// Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE = 70;
int width_tmp = o.outWidth, height_tmp = o.outHeight;
int scale = 0;
while (true) {
if (width_tmp / 2 < REQUIRED_SIZE
|| height_tmp / 2 < REQUIRED_SIZE)
break;
width_tmp /= 2;
height_tmp /= 2;
scale++;
}
// decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap bm = BitmapFactory.decodeFile(path, o2);
Bitmap bitmap = bm;
ExifInterface exif = new ExifInterface(path);
orientation = exif
.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Log.e("ExifInteface .........", "rotation ="+orientation);
// exif.setAttribute(ExifInterface.ORIENTATION_ROTATE_90, 90);
Log.e("orientation", "" + orientation);
Matrix m = new Matrix();
if ((orientation == ExifInterface.ORIENTATION_ROTATE_180)) {
m.postRotate(180);
// m.postScale((float) bm.getWidth(), (float) bm.getHeight());
// if(m.preRotate(90)){
Log.e("in orientation", "" + orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
bm.getHeight(), m, true);
return bitmap;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
m.postRotate(90);
Log.e("in orientation", "" + orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
bm.getHeight(), m, true);
return bitmap;
}
else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
m.postRotate(270);
Log.e("in orientation", "" + orientation);
bitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
bm.getHeight(), m, true);
return bitmap;
}
return bitmap;
} catch (Exception e) {
return null;
}
}
EDIT:
This code is not optimized , i just show the logic code from my one of the test project.
Another thing you can add to the above solutions is "samsung".contentEquals(Build.MANUFACTURER). If you know that your problem is only with Samsung devices you could be reasonably sure that you need to rotate the image returned (only) if ("samsung".contentEquals(Build.MANUFACTURER) && getActivity().getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT // && width > height//) // here you know you need to rotate
You could be "reasonably" confident that the rotation is warranted then.
public static Bitmap rotateBitmap(Bitmap b, float degrees) {
Matrix m = new Matrix();
if (degrees != 0) {
// clockwise
m.postRotate(degrees, (float) b.getWidth() / 2,
(float) b.getHeight() / 2);
}
try {
Bitmap b2 = Bitmap.createBitmap(b, 0, 0, b.getWidth(),
b.getHeight(), m, true);
if (b != b2) {
b.recycle();
b = b2;
}
} catch (OutOfMemoryError ex) {
// We have no memory to rotate. Return the original bitmap.
}
return b;
}
If it's really a bug then you may have to manually rotate it back to landscape. Bitmap data always has a width and a height, just take a look at the numbers and if the width is less than the height rotate the image as per alistair3408's answer.
Basically I'm trying to rotate a Bitmap (from an image) in an Android App. The reason why I want to do this is that a picture taken from the camera (through an intent) is displayed horizontally even if it's captured vertically, and the orientation is kept as metadata on the image. Correct me if in wrong. The problem is, however, that the image will take up a lot of memory when loaded in, if taken on a phone with a reasonably good camera, and I haven't found a way to rotate and save it without the risk of getting OutOfMemoryError. The code below is where i:
Load in the image
Check if it needs to be rotated
Loads a scaled-down version for display in an ImageView
Rotates the small image if necessary
In a seperate thread; load, rotate and save the image, so it doesn't need to in the future
It is important for the application to keep the images in the resolution, but any tricks with encodings are welcome. I have searched the internet for a few days, unable to find anything more than what i already have implemented. There is another thread on the subject here, but there doesn't seem to be any solutions. Hope you can help.
public Bitmap getBitmap(final Context c) {
if (bitmap != null)
return bitmap;
final int rotate = necessaryRotation(c, file);
// if(rotate != 0) rotateImageFile(c, rotate);
try {
// Get scaled version
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file, options);
options.inSampleSize = calcInSampleSize(options, 1024, 1024);
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(file, options);
// rotate?
bitmap = rotateImage(c,bitmap,rotate);
System.out.println("Bitmap loaded from file: size="
+ bitmap.getWidth() + "," + bitmap.getHeight());
System.gc();
} catch (Exception e) {
System.err.println("Unable to load image file: "
+ this.getFilename());
}
// if rotation is needed, do it in worker thread for next time
if(rotate != 0){
Thread t = new Thread(new Runnable(){
public void run() {
// load entire image
try{
File imageFile = new File(getFilename());
Bitmap huge = Media.getBitmap(c.getContentResolver(),
Uri.fromFile(imageFile));
huge = rotateImage(c,huge,rotate);
// save bitmap properly
FileOutputStream out = new FileOutputStream(imageFile);
huge.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
huge.recycle();
huge = null;
out = null;
System.gc();
}catch(IOException e){
e.printStackTrace();
}
}
});
t.start();
}
return bitmap;
}
private Bitmap rotateImage(Context c, Bitmap bitmap, int rotate) {
if (rotate != 0) {
// rotate
Matrix m = new Matrix();
m.postRotate(rotate);
Bitmap rotImage = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), m, true);
bitmap.recycle();
System.out.println("Image (id=" + getId()
+ ") rotated successfully");
System.gc();
return rotImage;
}
return bitmap;
}
private int necessaryRotation(Context c, String imageFile) {
int rotate = 0;
ExifInterface exif;
try {
exif = new ExifInterface(imageFile);
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rotate;
}
private int calcInSampleSize(BitmapFactory.Options options, int reqWidth,
int reqHeight) {
int height = options.outHeight;
int width = options.outWidth;
int inSampleSize = 1;
while (height > reqHeight || width > reqWidth) {
height /= 2;
width /= 2;
inSampleSize *= 2;
}
return inSampleSize;
}
If there is anything you need to know or have any optimizations i might be able to use to reduce memory usage, please write :) Thanks
Try this snippet:
private Bitmap rotateImage(Context c, Bitmap bitmap, int rotate) {
....
// reduce byte per pixel
bitmap = bitmap.copy(Bitmap.Config.RGB_565, false);
Bitmap.createBitmap(bitmap,...
}
When I load an image from the media gallery into a Bitmap, everything is working fine, except that pictures that were shot with the camera while holding the phone vertically, are rotated so that I always get a horizontal picture even though it appears vertical in the gallery.
Why is that and how can I load it correctly?
So, as an example...
First you need to create an ExifInterface:
ExifInterface exif = new ExifInterface(filename);
You can then grab the orientation of the image:
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Here's what the orientation values mean:
http://sylvana.net/jpegcrop/exif_orientation.html
So, the most important values are 3, 6 and 8.
If the orientation is ExifInterface.ORIENTATION_ROTATE_90 (which is 6), for example, you can rotate the image like this:
Matrix matrix = new Matrix();
matrix.postRotate(90);
rotatedBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, sourceBitmap.getWidth(), sourceBitmap.getHeight(), matrix, true);
That's just a quick example, though. I'm sure there are other ways of performing the actual rotation. But you will find those on StackOverflow as well.
Solved it in my case with this code using help of this post:
Bitmap myBitmap = getBitmap(imgFile.getAbsolutePath());
try {
ExifInterface exif = new ExifInterface(imgFile.getAbsolutePath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Log.d("EXIF", "Exif: " + orientation);
Matrix matrix = new Matrix();
if (orientation == 6) {
matrix.postRotate(90);
}
else if (orientation == 3) {
matrix.postRotate(180);
}
else if (orientation == 8) {
matrix.postRotate(270);
}
myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true); // rotating bitmap
}
catch (Exception e) {
}
ImageView img = (ImageView) findViewById(R.id.imgTakingPic);
img.setImageBitmap(myBitmap);
Hope it saves someone's time!
This is a full solution (found in the Hackbook example from the Facebook SDK). It has the advantage of not needing access to the file itself. This is extremely useful if you are loading an image from the content resolver thingy (e.g. if your app is responding to a share-photo intent).
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 (cursor.getCount() != 1) {
return -1;
}
cursor.moveToFirst();
return cursor.getInt(0);
}
And then you can get a rotated Bitmap as follows. This code also scales down the image (badly unfortunately) to MAX_IMAGE_DIMENSION. Otherwise you may run out of memory.
public static Bitmap getCorrectlyOrientedImage(Context context, Uri photoUri) 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) {
rotatedWidth = dbo.outHeight;
rotatedHeight = dbo.outWidth;
} else {
rotatedWidth = dbo.outWidth;
rotatedHeight = dbo.outHeight;
}
Bitmap srcBitmap;
is = context.getContentResolver().openInputStream(photoUri);
if (rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION) {
float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
float maxRatio = Math.max(widthRatio, heightRatio);
// Create the bitmap from file
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = (int) maxRatio;
srcBitmap = BitmapFactory.decodeStream(is, null, options);
} else {
srcBitmap = BitmapFactory.decodeStream(is);
}
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;
}
Use a Utility to do the Heavy Lifting.
9re created a simple utility to handle the heavy lifting of dealing with EXIF data and rotating images to their correct orientation.
You can find the utility code here: https://gist.github.com/9re/1990019
Simply download this, add it to your project's src directory and use ExifUtil.rotateBitmap() to get the correct orientation, like so:
String imagePath = photoFile.getAbsolutePath(); // photoFile is a File class.
Bitmap myBitmap = BitmapFactory.decodeFile(imagePath);
Bitmap orientedBitmap = ExifUtil.rotateBitmap(imagePath, myBitmap);
Have you looked at the EXIF data of the images? It may know the orientation of the camera when the picture was taken.
Kotlin code:
if (file.exists()){
val bitmap = BitmapFactory.decodeFile(file.absolutePath)
val exif = ExifInterface(file.absoluteFile.toString())
val orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL)
val matrix = Matrix()
when(orientation){
ExifInterface.ORIENTATION_ROTATE_90 -> matrix.postRotate(90F)
ExifInterface.ORIENTATION_ROTATE_180 -> matrix.postRotate(180F)
ExifInterface.ORIENTATION_ROTATE_270 -> matrix.postRotate(270F)
}
val rotatedBitmap = Bitmap.createBitmap(bitmap, 0,0 , bitmap.width, bitmap.height, matrix, true)
bitmap.recycle()
iv_capture.setImageBitmap(rotatedBitmap)
}
its because gallery correct displaying rotated images but not ImageView
look at here:
myBitmap = BitmapFactory.decodeFile(imgFile.getAbsolutePath(),optionss);
ExifInterface exif = new ExifInterface(selectedImagePath);
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int rotationInDegrees = exifToDegrees(rotation);
deg = rotationInDegrees;
Matrix matrix = new Matrix();
if (rotation != 0f) {
matrix.preRotate(rotationInDegrees);
myBitmap = Bitmap.createBitmap(myBitmap, 0, 0, myBitmap.getWidth(), myBitmap.getHeight(), matrix, true);
}
and you need this:
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;
}
Got it to work after many attempts thanks to a post I can no longer find :-(
Exif seems to work always, the difficulty was to get the filepath. The code I found makes a different between API older than 4.4 and after 4.4. Basically the picture URI for 4.4+ contains "com.android.providers". For this type of URI, the code uses DocumentsContract to get the picture id and then runs a query using the ContentResolver, while for older SDK, the code goes straight to query the URI with the ContentResolver.
Here is the code (sorry I cannot credit who posted it):
/**
* Handles pre V19 uri's
* #param context
* #param contentUri
* #return
*/
public static String getPathForPreV19(Context context, Uri contentUri) {
String res = null;
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
if(cursor.moveToFirst()){;
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
res = cursor.getString(column_index);
}
cursor.close();
return res;
}
/**
* Handles V19 and up uri's
* #param context
* #param contentUri
* #return path
*/
#TargetApi(Build.VERSION_CODES.KITKAT)
public static String getPathForV19AndUp(Context context, Uri contentUri) {
String wholeID = DocumentsContract.getDocumentId(contentUri);
// Split at colon, use second item in the array
String id = wholeID.split(":")[1];
String[] column = { MediaStore.Images.Media.DATA };
// where id is equal to
String sel = MediaStore.Images.Media._ID + "=?";
Cursor cursor = context.getContentResolver().
query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
column, sel, new String[]{ id }, null);
String filePath = "";
int columnIndex = cursor.getColumnIndex(column[0]);
if (cursor.moveToFirst()) {
filePath = cursor.getString(columnIndex);
}
cursor.close();
return filePath;
}
public static String getRealPathFromURI(Context context,
Uri contentUri) {
String uriString = String.valueOf(contentUri);
boolean goForKitKat= uriString.contains("com.android.providers");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && goForKitKat) {
Log.i("KIKAT","YES");
return getPathForV19AndUp(context, contentUri);
} else {
return getPathForPreV19(context, contentUri);
}
}
You can just read the path from sd card and do the following code...it'll Replace the existing photo after rotating it..
Not: Exif doesnt work on most of the devices, it gives the wrong data so it's good to hard code the rotating before saving to any degree you want to,You just have to change the angle value in postRotate to any you want to.
String photopath = tempphoto.getPath().toString();
Bitmap bmp = BitmapFactory.decodeFile(photopath);
Matrix matrix = new Matrix();
matrix.postRotate(90);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
FileOutputStream fOut;
try {
fOut = new FileOutputStream(tempphoto);
bmp.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
fOut.flush();
fOut.close();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I improved upon the answer by Teo Inke. It no longer rotates the image unless it is actually necessary. It is also easier to read, and should run faster.
// Load Image
Bitmap bitmap = BitmapFactory.decodeFile(filePath);
// Rotate Image if Needed
try
{
// Determine Orientation
ExifInterface exif = new ExifInterface(filePath);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
// Determine Rotation
int rotation = 0;
if (orientation == 6) rotation = 90;
else if (orientation == 3) rotation = 180;
else if (orientation == 8) rotation = 270;
// Rotate Image if Necessary
if (rotation != 0)
{
// Create Matrix
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
// Rotate Bitmap
Bitmap rotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
// Pretend none of this ever happened!
bitmap.recycle();
bitmap = rotated;
rotated = null;
}
}
catch (Exception e)
{
// TODO: Log Error Messages Here
}
// TODO: Use Result Here
xxx.setBitmap(bitmap);
The first thing you need is the real File path
If you have it great, if you are using URI then use this method to
get the real Path:
public static String getRealPathFromURI(Uri contentURI,Context context) {
String path= contentURI.getPath();
try {
Cursor cursor = context.getContentResolver().query(contentURI, null, null, null, null);
cursor.moveToFirst();
String document_id = cursor.getString(0);
document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
cursor.close();
cursor = context.getContentResolver().query(
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
cursor.moveToFirst();
path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
cursor.close();
}
catch(Exception e)
{
return path;
}
return path;
}
extract your Bitmap for example:
try {
Bitmap bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImage);
}
catch (IOException e)
{
Log.e("IOException",e.toString());
}
you can use decodeFile() instead if you wish.
Now that you have the Bitmap and the real Path get the Orientation of the Image:
private static int getExifOrientation(String src) throws IOException {
int orientation = 1;
ExifInterface exif = new ExifInterface(src);
String orientationString=exif.getAttribute(ExifInterface.TAG_ORIENTATION);
try {
orientation = Integer.parseInt(orientationString);
}
catch(NumberFormatException e){}
return orientation;
}
and finally rotate it to the right position like so:
public static Bitmap rotateBitmap(String src, Bitmap bitmap) {
try {
int orientation = getExifOrientation(src);
if (orientation == 1) {
return bitmap;
}
Matrix matrix = new Matrix();
switch (orientation) {
case 2:
matrix.setScale(-1, 1);
break;
case 3:
matrix.setRotate(180);
break;
case 4:
matrix.setRotate(180);
matrix.postScale(-1, 1);
break;
case 5:
matrix.setRotate(90);
matrix.postScale(-1, 1);
break;
case 6:
matrix.setRotate(90);
break;
case 7:
matrix.setRotate(-90);
matrix.postScale(-1, 1);
break;
case 8:
matrix.setRotate(-90);
break;
default:
return bitmap;
}
try {
Bitmap oriented = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
bitmap.recycle();
return oriented;
} catch (OutOfMemoryError e) {
e.printStackTrace();
return bitmap;
}
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
That's it , you now have the bitmap rotated to the right position.
cheers.
This works, but probably not the best way to do it, but it might help someone.
String imagepath = someUri.getAbsolutePath();
imageview = (ImageView)findViewById(R.id.imageview);
imageview.setImageBitmap(setImage(imagepath, 120, 120));
public Bitmap setImage(String path, final int targetWidth, final int targetHeight) {
Bitmap bitmap = null;
// Get exif orientation
try {
ExifInterface exif = new ExifInterface(path);
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
if (orientation == 6) {
orientation_val = 90;
}
else if (orientation == 3) {
orientation_val = 180;
}
else if (orientation == 8) {
orientation_val = 270;
}
}
catch (Exception e) {
}
try {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Adjust extents
int sourceWidth, sourceHeight;
if (orientation_val == 90 || orientation_val == 270) {
sourceWidth = options.outHeight;
sourceHeight = options.outWidth;
} else {
sourceWidth = options.outWidth;
sourceHeight = options.outHeight;
}
// Calculate the maximum required scaling ratio if required and load the bitmap
if (sourceWidth > targetWidth || sourceHeight > targetHeight) {
float widthRatio = (float)sourceWidth / (float)targetWidth;
float heightRatio = (float)sourceHeight / (float)targetHeight;
float maxRatio = Math.max(widthRatio, heightRatio);
options.inJustDecodeBounds = false;
options.inSampleSize = (int)maxRatio;
bitmap = BitmapFactory.decodeFile(path, options);
} else {
bitmap = BitmapFactory.decodeFile(path);
}
// Rotate the bitmap if required
if (orientation_val > 0) {
Matrix matrix = new Matrix();
matrix.postRotate(orientation_val);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
// Re-scale the bitmap if necessary
sourceWidth = bitmap.getWidth();
sourceHeight = bitmap.getHeight();
if (sourceWidth != targetWidth || sourceHeight != targetHeight) {
float widthRatio = (float)sourceWidth / (float)targetWidth;
float heightRatio = (float)sourceHeight / (float)targetHeight;
float maxRatio = Math.max(widthRatio, heightRatio);
sourceWidth = (int)((float)sourceWidth / maxRatio);
sourceHeight = (int)((float)sourceHeight / maxRatio);
bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth, sourceHeight, true);
}
} catch (Exception e) {
}
return bitmap;
}
maybe this will help (rotate 90 degree)(this worked for me)
private Bitmap rotateBitmap(Bitmap image){
int width=image.getHeight();
int height=image.getWidth();
Bitmap srcBitmap=Bitmap.createBitmap(width, height, image.getConfig());
for (int y=width-1;y>=0;y--)
for(int x=0;x<height;x++)
srcBitmap.setPixel(width-y-1, x,image.getPixel(x, y));
return srcBitmap;
}
The methods below scales AND rotates the bitmap according to the orientation:
public Bitmap scaleAndRotateImage(String path, int orientation, final int targetWidth, final int targetHeight)
{
Bitmap bitmap = null;
try
{
// Check the dimensions of the Image
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Adjust the Width and Height
int sourceWidth, sourceHeight;
if (orientation == 90 || orientation == 270)
{
sourceWidth = options.outHeight;
sourceHeight = options.outWidth;
}
else
{
sourceWidth = options.outWidth;
sourceHeight = options.outHeight;
}
// Calculate the maximum required scaling ratio if required and load the bitmap
if (sourceWidth > targetWidth || sourceHeight > targetHeight)
{
float widthRatio = (float)sourceWidth / (float)targetWidth;
float heightRatio = (float)sourceHeight / (float)targetHeight;
float maxRatio = Math.max(widthRatio, heightRatio);
options.inJustDecodeBounds = false;
options.inSampleSize = (int)maxRatio;
bitmap = BitmapFactory.decodeFile(path, options);
}
else
{
bitmap = BitmapFactory.decodeFile(path);
}
// We need to rotate the bitmap (if required)
int orientationInDegrees = exifToDegrees(orientation);
if (orientation > 0)
{
Matrix matrix = new Matrix();
if (orientation != 0f)
{
matrix.preRotate(orientationInDegrees);
};
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
// Re-scale the bitmap if necessary
sourceWidth = bitmap.getWidth();
sourceHeight = bitmap.getHeight();
if (sourceWidth != targetWidth || sourceHeight != targetHeight)
{
float widthRatio = (float)sourceWidth / (float)targetWidth;
float heightRatio = (float)sourceHeight / (float)targetHeight;
float maxRatio = Math.max(widthRatio, heightRatio);
sourceWidth = (int)((float)sourceWidth / maxRatio);
sourceHeight = (int)((float)sourceHeight / maxRatio);
bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth, sourceHeight, true);
}
}
catch (Exception e)
{
Logger.d("Could not rotate the image");
Logger.d(e.getMessage());
}
return bitmap;
}
Example:
public void getPictureFromDevice(Uri Uri,ImageView imageView)
{
try
{
ExifInterface exifInterface = new ExifInterface(Uri.getPath());
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
Bitmap bitmap = scaleAndRotateImage(Uri.getPath(), orientation, imageView.getWidth(), imageView.getHeight());
imageView.setImageBitmap(bitmap);
}
catch (OutOfMemoryError outOfMemoryError)
{
Logger.d(outOfMemoryError.getLocalizedMessage());
Logger.d("Failed to load image from filePath (out of memory)");
Logger.d(Uri.toString());
}
catch (Exception e)
{
Logger.d("Failed to load image from filePath");
Logger.d(Uri.toString());
}
}
The cursor should be closed after opening it.
Here is an example.
public static int getOrientation(Context context, Uri selectedImage)
{
int orientation = -1;
Cursor cursor = context.getContentResolver().query(selectedImage,
new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
if (cursor.getCount() != 1)
return orientation;
cursor.moveToFirst();
orientation = cursor.getInt(0);
cursor.close(); // ADD THIS LINE
return orientation;
}
I have melted #Timmmm answer and #Manuel. If you do this solution, you will not get a Run Out Of Memory Exception.
This method retrieves the image orientation:
private static final int ROTATION_DEGREES = 90;
// This means 512 px
private static final Integer MAX_IMAGE_DIMENSION = 512;
public static int getOrientation(Uri photoUri) throws IOException {
ExifInterface exif = new ExifInterface(photoUri.getPath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
orientation = ROTATION_DEGREES;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
orientation = ROTATION_DEGREES * 2;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
orientation = ROTATION_DEGREES * 3;
break;
default:
// Default case, image is not rotated
orientation = 0;
}
return orientation;
}
Therefore, you would use this method to resize image before load it on memory. In that way, you will not get a Memory Exception.
public static Bitmap getCorrectlyOrientedImage(Context context, Uri photoUri) 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(photoUri);
if (orientation == 90 || orientation == 270) {
rotatedWidth = dbo.outHeight;
rotatedHeight = dbo.outWidth;
} else {
rotatedWidth = dbo.outWidth;
rotatedHeight = dbo.outHeight;
}
Bitmap srcBitmap;
is = context.getContentResolver().openInputStream(photoUri);
if (rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION) {
float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
float maxRatio = Math.max(widthRatio, heightRatio);
// Create the bitmap from file
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = (int) maxRatio;
srcBitmap = BitmapFactory.decodeStream(is, null, options);
} else {
srcBitmap = BitmapFactory.decodeStream(is);
}
is.close();
// if the orientation is not 0, 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;
}
This works perfectly for me. I hope this helps somebody else
Improving on the solution above by Timmmm to add some extra scaling at the end to ensure that the image fits within the bounds:
public static Bitmap loadBitmap(String path, int orientation, final int targetWidth, final int targetHeight) {
Bitmap bitmap = null;
try {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
// Adjust extents
int sourceWidth, sourceHeight;
if (orientation == 90 || orientation == 270) {
sourceWidth = options.outHeight;
sourceHeight = options.outWidth;
} else {
sourceWidth = options.outWidth;
sourceHeight = options.outHeight;
}
// Calculate the maximum required scaling ratio if required and load the bitmap
if (sourceWidth > targetWidth || sourceHeight > targetHeight) {
float widthRatio = (float)sourceWidth / (float)targetWidth;
float heightRatio = (float)sourceHeight / (float)targetHeight;
float maxRatio = Math.max(widthRatio, heightRatio);
options.inJustDecodeBounds = false;
options.inSampleSize = (int)maxRatio;
bitmap = BitmapFactory.decodeFile(path, options);
} else {
bitmap = BitmapFactory.decodeFile(path);
}
// Rotate the bitmap if required
if (orientation > 0) {
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
// Re-scale the bitmap if necessary
sourceWidth = bitmap.getWidth();
sourceHeight = bitmap.getHeight();
if (sourceWidth != targetWidth || sourceHeight != targetHeight) {
float widthRatio = (float)sourceWidth / (float)targetWidth;
float heightRatio = (float)sourceHeight / (float)targetHeight;
float maxRatio = Math.max(widthRatio, heightRatio);
sourceWidth = (int)((float)sourceWidth / maxRatio);
sourceHeight = (int)((float)sourceHeight / maxRatio);
bitmap = Bitmap.createScaledBitmap(bitmap, sourceWidth, sourceHeight, true);
}
} catch (Exception e) {
}
return bitmap;
}
Use the following code to rotate an image correctly:
private Bitmap rotateImage(Bitmap bitmap, String filePath)
{
Bitmap resultBitmap = bitmap;
try
{
ExifInterface exifInterface = new ExifInterface(filePath);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
Matrix matrix = new Matrix();
if (orientation == ExifInterface.ORIENTATION_ROTATE_90)
{
matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_90);
}
else if (orientation == ExifInterface.ORIENTATION_ROTATE_180)
{
matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_180);
}
else if (orientation == ExifInterface.ORIENTATION_ROTATE_270)
{
matrix.postRotate(ExifInterface.ORIENTATION_ROTATE_270);
}
// Rotate the bitmap
resultBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
catch (Exception exception)
{
Logger.d("Could not rotate the image");
}
return resultBitmap;
}
I solved the problem with the following workaround. Note that I am also scaling the image, which was necessary to avoid OutOfMemoryExceptions.
Beware that this solution will not work properly with portrait images or opside-down images (thank you Timmmm for noting). Timmmm's solution above might be the better choice if that is required and it looks more elegant, too: https://stackoverflow.com/a/8914291/449918
File path = // ... location of your bitmap file
int w = 512; int h = 384; // size that does not lead to OutOfMemoryException on Nexus One
Bitmap b = BitmapFactory.decodeFile(path);
// Hack to determine whether the image is rotated
boolean rotated = b.getWidth() > b.getHeight();
Bitmap resultBmp = null;
// If not rotated, just scale it
if (!rotated) {
resultBmp = Bitmap.createScaledBitmap(b, w, h, true);
b.recycle();
b = null;
// If rotated, scale it by switching width and height and then rotated it
} else {
Bitmap scaledBmp = Bitmap.createScaledBitmap(b, h, w, true);
b.recycle();
b = null;
Matrix mat = new Matrix();
mat.postRotate(90);
resultBmp = Bitmap.createBitmap(scaledBmp, 0, 0, h, w, mat, true);
// Release image resources
scaledBmp.recycle();
scaledBmp = null;
}
// resultBmp now contains the scaled and rotated image
Cheers