Photo taken from iphone gets rotated 90 degrees on Android phone - android

Scenario :
The photo rotated 90 degrees when the picture was taken from the iPhone camera and uploaded on the server and trying to load the same photo on android device.
What I found so far is Meta information(EXIF data) is ignored by the Android system before downloading the image. When photo uploaded from iPhone, the EXIF information of that particular photo is something like this: orientation 6 Rotated 90 CCW, but when it comes to android this value becomes: orientation 0(UNDEFINED)
I tried a couple of approaches but did not work, let me know if anyone faced similar issue or any solution or work around for this, Thanks in advance.
Sample snippet code :
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
bmOptions.inSampleSize = 4;
resultBitmap = decodeStream(inputStream, null, bmOptions);
ExifInterface exif = new ExifInterface(inputStream);
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;
else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) rotationAngle = 180;
else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) rotationAngle = 270;
Matrix matrix = new Matrix();
matrix.setRotate(rotationAngle);
Bitmap rotated = Bitmap.createBitmap(resultBitmap,0,0,resultBitmap.getWidth(),resultBitmap.getHeight(),matrix,true);
if(rotated != null){
resultBitmap = rotated;
}
enter code here

Related

Out of Memory error on createbitmap

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".

Bitmap getWith() and getHeighth() always return same size?

I want to rotate bitmap when the picture taken as potrait .
I want to understand image is potrait or lanscape?
I use this code :
Bitmap photo = BitmapFactory.decodeFile(path_img,options);
int imageHeight = photo.getHeight();
int imageWidth = photo.getWidth();
When I take image as portroit and lanscape it does not matter it is always like this :
imageHeight =390; imageWidth =520;
How can I understand a picture is taken lanscape or portrait.
Thanks
Code taken from nigels link and altered it for the provided code snippet
Bitmap photo = BitmapFactory.decodeFile(path_img,options);
ExifInterface exif = new ExifInterface(path_img);
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int rotationInDegrees = exifToDegrees(rotation);
Matrix matrix = new Matrix();
if (rotation != 0f) {
matrix.preRotate(rotationInDegrees);
}
Bitmap adjustedBitmap = Bitmap.createBitmap(photo, 0, 0, width, height, matrix, true);
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;
}
from what i understood, this code snippet and the 2 methods should do all the work by themselfs.
How can I understand a picture is taken lanscape or portrait?
assuming the image is currently stored on file, you can get it orientation from the Exif metadata object:
File f = new File(capturedImageFilePath);
ExifInterface exif = new ExifInterface(f.getPath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
note that this information not necessarily available - it's up to the application which captured the image to store this metadata on the file.
in case this information not exists, getAttributeInt would return ExifInterface.ORIENTATION_NORMAL
the orientation can can be one of the following: ExifInterface.ORIENTATION_ROTATE_90 / ExifInterface.ORIENTATION_ROTATE_180 / ExifInterface.ORIENTATION_ROTATE_270

How to set captured images in portrait mode

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.

Android Camera Intent Saving Image Landscape When Taken Portrait [duplicate]

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.

Android get Orientation of a camera Bitmap? And rotate back -90 degrees

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

Categories

Resources