This question already has answers here:
Why does an image captured using camera intent gets rotated on some devices on Android?
(23 answers)
Closed 4 years ago.
I have had a look around but there doesn't seem to be a solid answer/solution to the, very irritating, problem.
I take a picture in portrait orientation and when I hit save/discard the buttons are in the correct orientation also. The problem is when I then retrieve the image later on it is in landscape orientation (the picture has been rotated 90 degrees anti-clockwise)
I don' want to force the user to use the camera in a certain orientation.
Is there a way to maybe detect whether the photo was taken in portrait mode and then decode the bitmap and flip it the correct way up?
The picture is always taken in the orientation the camera is built into the device. To get your image rotated correctly you'll have to read the orientation information that is stored into the picture (EXIF meta data). There it is stored how the device was oriented, when the image was taken.
Here is some code that reads the EXIF data and rotates the image accordingly:
file is the name of the image file.
BitmapFactory.Options bounds = new BitmapFactory.Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file, bounds);
BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap bm = BitmapFactory.decodeFile(file, opts);
ExifInterface exif = new ExifInterface(file);
String orientString = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
int orientation = orientString != null ? Integer.parseInt(orientString) : ExifInterface.ORIENTATION_NORMAL;
int rotationAngle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) rotationAngle = 90;
if (orientation == ExifInterface.ORIENTATION_ROTATE_180) rotationAngle = 180;
if (orientation == ExifInterface.ORIENTATION_ROTATE_270) rotationAngle = 270;
Matrix matrix = new Matrix();
matrix.setRotate(rotationAngle, (float) bm.getWidth() / 2, (float) bm.getHeight() / 2);
Bitmap rotatedBitmap = Bitmap.createBitmap(bm, 0, 0, bounds.outWidth, bounds.outHeight, matrix, true);
UPDATE 2017-01-16
With the release of the 25.1.0 Support Library, an ExifInterface Support Library was introduced, which should perhaps make the access to the Exif attributes easier. See the Android Developer's Blog for an article about it.
The selected answer uses the most common method answered to this and similar questions. However, it did not work for me with both front and back cameras on Samsung. For those needing another solution which works across both front and back cameras for Samsung and other major manufacturers, this answer by nvhausid is awesome:
https://stackoverflow.com/a/18915443/6080472
For those who don't want to click through, the relevant magic is to use the CameraInfo rather then relying on EXIF or a Cursor over the media files.
Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(mCurrentCameraId, info);
Bitmap bitmap = rotate(realImage, info.orientation);
Full code in the link.
Related
I'm loading the camera as an intent and saving to a local file:
Intent capturePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
capturePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, uriPhoto);
startActivityForResult(capturePhotoIntent, REQUEST_IMAGE_CAPTURE);
Some mobile phones are saving the image in the incorrect orientation. Where a photo is captured with the mobile phone held in portrait, the saved image is rotated 90 degrees to landscape.
Most phone cameras are landscape, therefore I understand this is why the rotation occurs. The camera application should populate the image file with the correct orientation within the EXIF data.
I understand that I could use Glide to display the captured image within the application and this will automatically handle the rotation for me.
Glide.with(myContext).load(photoFilePaths.get(iPosition)).into(myViewHolder.getPhotoImageView());
However, I believe that this rotates the image in the ImageView each time it is loaded - could Glide be used to rotate and save the image within the correct orientation onActivityResult?
I've seen the following could be an alternative, however this relies on the correct orientation being set within the EXIF data:
ExifInterface ei = new ExifInterface(photoPath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
Bitmap rotatedBitmap = null;
switch(orientation)
{
case ExifInterface.ORIENTATION_ROTATE_90:
rotatedBitmap = rotateImage(bitmap, 90);
break;
...
}
public static Bitmap rotateImage(Bitmap source, float angle)
{
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), matrix, true);
}
Glide appears to be more consistent at displaying an image in the correct orientation, so I'm guessing it follows a different approach that could provide better results when saving the image. The image needs to be uploaded to a web server in the correct orientation, rather than just displaying within the Android application.
BitmapFactory.Options bounds = new BitmapFactory.Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(Common.getRealPathFromURI(selectedImage,rootView.getContext()), bounds);
BitmapFactory.Options opts = new BitmapFactory.Options();
Common.setBitmap(null);
Bitmap bm = BitmapFactory.decodeFile(Common.getRealPathFromURI(selectedImage, rootView.getContext()), opts);
saveToInternalSorage(bm);
ExifInterface exif = new ExifInterface(Common.getRealPathFromURI(selectedImage,rootView.getContext()));
String orientString = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
int orientation = orientString != null ? Integer.parseInt(orientString) : ExifInterface.ORIENTATION_NORMAL;
int rotationAngle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) rotationAngle = 90;
if (orientation == ExifInterface.ORIENTATION_ROTATE_180) rotationAngle = 180;
if (orientation == ExifInterface.ORIENTATION_ROTATE_270) rotationAngle = 270;
Matrix matrix = new Matrix();
matrix.postRotate(rotationAngle);
try
{
Bitmap rotatedBitmap = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
bitmap2 = rotatedBitmap;//BitmapFactory.decodeStream(imageStream);
}
catch(OutOfMemoryError e)
{
}
Basically at times, i get my image rotated. So I have implemented that function, the problem lies on createbitmap i get outofmemory error. I want to avoid that error , without modifying the size of the image... and the quality. i want to keep same size and quality.
If you want to use large heap, you should write in AndroidManifest.xml.
android:largeHeap="true"
If you want to check heap size on your device, call ActivityManager.getLargeMemoryClass().
ActivityManager am = ((ActivityManager)getSystemService(Activity.ACTIVITY_SERVICE));
int largeMemory = am.getLargeMemoryClass();
You have far bigger problems, such as the fact that your app will not work on most Android devices. Use your Uri properly and get rid of getRealPathFromURI().
That being said, there is no guarantee that you can allocate a bitmap of the size needed to rotate the image. Whether you can or not will be based on the state of your heap and the resolution of the image. Your choices are:
Switch to using native code via the NDK for the image rotation. This too is not guaranteed to work, but the odds are a lot higher, because you have all system RAM to work with.
Switch to using android:largeHeap="true". This will have no effect on many devices. However, on some, it will increase your heap limit and make it somewhat more likely that your bitmap allocation will succeed.
Settle for resizing the image.
Tell the user "sorry, we do not have enough memory to rotate the image".
So i got this simple app, open the camera (either front or back), take a picture, post it.
I managed to get a straight preview, despite the display orientation.
The problem is when I get the picture. If for example I take a photo with different devices in portrait mode, the resulting pictures are rotated of different angles, depending which device was used.
All I'm asking is simple: do you know how I can get straight pictures (either portrait or landscape, according to the rotation) and make sure it works on every device?
Well' if any of you has a solution,please share it,I'll be eternally grateful!
Different devices use different orientations on their pictures by default. This can be annoying. What you need to do is find that orientation, and flip the image correspondingly.
Here's some code that I use in my application:
Note: I'm sure this isn't perfect. If anyone has suggestions on how to improve this, please feel free to comment/edit!
private int getOrientation(String pathToYourImage) throws IOException{
ExifInterface exif = new ExifInterface(path);
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
if (rotation == ExifInterface.ORIENTATION_ROTATE_90){
return 90;
} else if (rotation == ExifInterface.ORIENTATION_ROTATE_180){
return 180;
} else if (rotation == ExifInterface.ORIENTATION_ROTATE_270){
return 270;
}
return 0;
}
then something like
if (orientation > 0){
originalImage = rotateBitmap(originalImage, orientation);
}
private Bitmap rotateBitmap(Bitmap srcBitmap, int angle){
Matrix matrix = new Matrix();
matrix.postRotate(angle);
Bitmap rotatedBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(), srcBitmap.getHeight(), matrix, true);
srcBitmap.recycle();
return rotatedBitmap;
}
This might not completely suit your needs, but it works well enough for me. Ask if you have any more questions!
I am working on a application in which I have given facility to user that he can take a picture using his mobile camera and then I am displaying the image in a Imageview.
Now the problem is that if I am capturing the image in a portrait mode or in landscape mode it is always setting the image in landscape mode in ImageView, but I want the image to be set in portrait mode only. Please help me out with this problem.
Any help would be appreciable...
Thank you
Matrix mat = new Matrix();
ExifInterface exif = new ExifInterface(yourimagepath);
String orientstring = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
int orientation = orientstring != null ? Integer.parseInt(orientstring) : ExifInterface.ORIENTATION_NORMAL;
int rotateangle = 0;
if(orientation == ExifInterface.ORIENTATION_ROTATE_90)
rotateangle = 90;
if(orientation == ExifInterface.ORIENTATION_ROTATE_180)
rotateangle = 180;
if(orientation == ExifInterface.ORIENTATION_ROTATE_270)
rotateangle = 270;
mat.setRotate(rotateangle, (float) bmpPic.getWidth() / 2, (float) bmpPic.getHeight() / 2);
File f = new File(yourimagepath);
Bitmap bmpPic = BitmapFactory.decodeStream(new FileInputStream(f), null, null);
Bitmap bmpPic1 = Bitmap.createBitmap(bmpPic, 0, 0, bmpPic.getWidth(), bmpPic.getHeight(), mat, true);
use like that
Matrix matrix=new Matrix();
imageView.setScaleType(ScaleType.MATRIX); //required
matrix.postRotate((float) angle, pivX, pivY);
imageView.setImageMatrix(matrix);
for exp:
matrix.postRotate( 90f, imageView.getDrawable().getBounds().width()/2, imageView.getDrawable().getBounds().height()/2)
Here is a great solution I came across for this:
https://stackoverflow.com/a/34241250/8033090
One line solution:
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
or
Picasso.with(context).load("file:" + photoPath).into(imageView);
This will autodetect rotation and place image in correct orientation
Picasso is a very powerful library for handling images in your app includes: Complex image transformations with minimal memory use. It can take a second to load but I just put some text behind the image view that says "Loading image" and when the image loads it covers the text.
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?
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:
Read Exif information in a JPEG file.
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
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);