Rotate a Bitmap without using an ImageURI/ContentResolver? - android

I am trying to adapt Microsoft's projectOxford EmotionApi's image-auto rotater code. Each image taken by the device camera is analyzed for its angle, and then rotated to the correct landscape view to be analyzed by the emotion API.
My question is : how would I adapt the code below to take a Bitmap as an argument? I am also completely lost as to the role of the Content Resolver and ExitInterface in this case. Any help is well appreciated.
private static int getImageRotationAngle(
Uri imageUri, ContentResolver contentResolver) throws IOException {
int angle = 0;
Cursor cursor = contentResolver.query(imageUri,
new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
if (cursor != null) {
if (cursor.getCount() == 1) {
cursor.moveToFirst();
angle = cursor.getInt(0);
}
cursor.close();
} else {
ExifInterface exif = new ExifInterface(imageUri.getPath());
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_270:
angle = 270;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
angle = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_90:
angle = 90;
break;
default:
break;
}
}
return angle;
}
// Rotate the original bitmap according to the given orientation angle
private static Bitmap rotateBitmap(Bitmap bitmap, int angle) {
// If the rotate angle is 0, then return the original image, else return the rotated image
if (angle != 0) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(
bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
} else {
return bitmap;
}
}

how would I adapt the code below to take a Bitmap as an argument?
You can't.
I am also completely lost as to the role of the Content Resolver and ExitInterface in this case
The code in your question uses the EXIF Orientation tag to determine the orientation that should be applied to the image, as reported by the camera that took the photo (or whatever set that tag). ExifInterface is code to read EXIF tags. ExifInterface needs to work with the actual JPEG data, not a decoded Bitmap — a Bitmap no longer has the EXIF tags.
The ContentResolver code in there is bug-riddled and should not be used. The ExifInterface that comes in the com.android.support:exifinterface library has a constructor that takes an InputStream, from which it will read the JPEG. The correct way to use the Uri here is to pass it to openInputStream() on the ContentResolver, passing that stream to the ExifInterface constructor.

Related

Getting Orientation as 0 and still getting the rotated image in ImageView in android

I have tried most of the code on stackoverflow but none of them are working.
I am using moto x4 for uploading picture using camera. when I use back camera it gets rotated 90 degree left and when I use front camera it gets rotated 90 degree right. but in debug mode, in both case I found the orientation = 0;
else if (requestCode == CAMERA) {
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
String imagePath = saveImage(thumbnail);
File imageFile = new File(imagePath);
ExifInterface exif = null;
try {
exif = new ExifInterface(imageFile.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
}
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
bmap = GetandSetBitmap.rotateBitmap(thumbnail,orientation);
mImageView.setBackgroundResource(0);
mImageView.setImageBitmap(bmap);
}
This probably has to do with the fact that one camera is by default in landscape and the other in reverse landscape, so orientation = 0, as the orientation is detected to be the normal one in both cases. Unfortunately, I don't have a solution that wouldn't involve manually rotating the image to cover all cases. Personally I've used a switch to cater for the cases where my photo was saved with a 90 degrees rotation:
ExifInterface exifInterface = new ExifInterface(pictureFile.getPath());
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
Bitmap correctedBitmap;
switch(orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
correctedBitmap = bitmap;
capturedImageHolder.setImageBitmap(correctedBitmap);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
correctedBitmap = rotateImage(bitmap, 90);
capturedImageHolder.setImageBitmap(correctedBitmap);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
correctedBitmap = rotateImage(bitmap, 180);
capturedImageHolder.setImageBitmap(correctedBitmap);
break;
case ExifInterface.ORIENTATION_NORMAL:
default:
correctedBitmap = rotateImage(bitmap, 270);
capturedImageHolder.setImageBitmap(correctedBitmap);
break;
}
} catch (IOException e) {
}
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);
}
In your case, you would need to detect if the photo is taken from the front-facing camera or the back and adjust the values accordingly.

how to apply EXIF orientation on image uri without involving bitmap?

I know applying EXIF orientation on the bitmap object, doing this -
public static Bitmap getCorrectBitmap(Bitmap bitmap, String filePath) {
ExifInterface ei;
Bitmap rotatedBitmap =bitmap;
try {
ei = new ExifInterface(filePath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
Matrix matrix = new Matrix();
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
matrix.postRotate(90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.postRotate(180);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
matrix.postRotate(270);
break;
}
rotatedBitmap = Bitmap.createBitmap(bitmap , 0, 0, bitmap .getWidth(), bitmap .getHeight(), matrix, true);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return rotatedBitmap;
}
But, what I am having is - a few rotated images (camera images) uri and their corresponding file paths (of sd card).
It will be great, if someone suggests me a good way to apply similar EXIF orientation on the image uri and getting back the correctly oriented uri.
I do not want to involve bitmap object in this process as getting bitmap of the image consumes time (about 1 second per image).

how to automatically turn the picture in the right form (library cropper )?

I use library cropper here in my project.
Everything works cool, but if a photo was made in portrait mode, it flips and is displayed in landscape mode.
Here is an original photo - original
This is opened by the program - program
There is a method in the library cropImageView.rotateImage(90); I can add a button that rererses the picture when pressed. But what can I do to make it run once loaded in the right mode?
imageCrop = (CropImageView) v.findViewById(R.id.imageCrop);
String picturePath = getArguments().getString("image");
crudeImage = BitmapFactory.decodeFile(picturePath);
imageCrop.setImageBitmap(crudeImage);
You need to decode the original image into bitmap in its orientation. Detect image orientation using ExifInterface, then use Matrix to rotate your bitmap to image's original orientation:
crudeImage = BitmapFactory.decodeFile(picturePath);
float rotationDegrees = getRotationDegreesToOriginal(picturePath);
if (rotationDegrees != 0f) {
crudeImage = rotateImage(crudeImage, rotationDegrees);
}
/**
* Rotate a bitmap by given degrees
* #param bitmap original bitmap
* #param degrees rotation degrees
* #return rotated bitmap
*/
public static Bitmap rotateImage(Bitmap bitmap, float degrees) {
Matrix matrix = new Matrix();
matrix.postRotate(degrees);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
/**
* Get rotation degrees that need to be applied to rotate an image to its original orientation
* #param fileName full path to image
* #return rotation degrees, or 0 if file not found
*/
public static float getRotationDegreesToOriginal(String fileName) {
final ExifInterface exif;
try {
exif = new ExifInterface(fileName);
} catch (IOException e) {
return 0f;
}
// Detect original orientation to rotate back to
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_180:
return 180f;
case ExifInterface.ORIENTATION_ROTATE_90:
return 90f;
case ExifInterface.ORIENTATION_ROTATE_270:
return 270f;
default:
return 0f;
}
}

ImageView setRotation having an aliased or jagged edges

Hi currently I'm trying to display an image that is rotated by about 5 degrees on an imageview after I capture it and rotate the image into proper orientation (camera issues). Now the problem is after setting the image on an imageview which is rotated 5 degrees sing imageview.setRotation(5) the imageview itself becomes aliased. I'm pretty sure that the imageview is the one being aliased since my image has a padding of 5dp to have a white border on the sides but please do correct me if I'm wrong.
What solution I tried so far is this but the sample solution works for already set image on a custom view and I'm not that used to in configuring or further customizing a custom views to work based on what I need. though his problem is almost the same as mine.
I also tried this one which apply antialiasing on the fly but didn't work as well.
So far here is my code:
imageview = (ImageView) findViewById(R.id.img_preview);
imageview.setRotation(5);
Bundle extras = getIntent().getExtras();
if (extras != null) {
String img_path = extras.getString("img_path");
File image_file = new File(img_path);
try {
Bitmap captured_image = applyOrientation(BitmapFactory.decodeFile(img_path),resolveBitmapOrientation(image_file));
imageview.setImageBitmap(captured_image);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
And this is the code on where I rotate my image maybe someone can help fix it from here too so here it is:
private int resolveBitmapOrientation(File bitmapFile) throws IOException {
ExifInterface exif = null;
exif = new ExifInterface(bitmapFile.getAbsolutePath());
return exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
}
private Bitmap applyOrientation(Bitmap bitmap, int orientation) {
int rotate = 0;
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;
default:
return bitmap;
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
mtx.postRotate(rotate);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}

How to get the Correct orientation of the image selected from the Default Image gallery

I have gone through some of the links to get the correct image orientation of the image selected from the default image gallery to be worked standard in all devices the exif tag always returns 0.
EXIF orientation tag value always 0 for image taken with portrait camera app android
Exif orientation tag returns 0
Exif data TAG_ORIENTATION always 0
http://mobisocial.stanford.edu/news/2011/08/rotating-images-in-android/
How to get an exact solution that will work on all devices?
If the image(photo) was taken by a program made by you, you must set Parameters.setRotation with the correct rotation value.
This, depending of camera drive, rotates the image before save or save the rotation value to exif TAG_ORIENTATION.
Therefore, if TAG_ORIENTATION is null or zero, the image are in the correct orientation, otherwise you must rotate image according the value in TAG_ORIENTATION.
CODE
Get orientation from EXIF:
ExifInterface exif = null;
try {
exif = new ExifInterface(path);
} catch (IOException e) {
e.printStackTrace();
}
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_UNDEFINED);
Get bitmap rotated:
Bitmap bmRotated = rotateBitmap(bitmap, orientation);
Method to rotate bitmap:
public static Bitmap rotateBitmap(Bitmap bitmap, int orientation) {
Matrix matrix = new Matrix();
switch (orientation) {
case ExifInterface.ORIENTATION_NORMAL:
return bitmap;
case ExifInterface.ORIENTATION_FLIP_HORIZONTAL:
matrix.setScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
matrix.setRotate(180);
break;
case ExifInterface.ORIENTATION_FLIP_VERTICAL:
matrix.setRotate(180);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_TRANSPOSE:
matrix.setRotate(90);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_90:
matrix.setRotate(90);
break;
case ExifInterface.ORIENTATION_TRANSVERSE:
matrix.setRotate(-90);
matrix.postScale(-1, 1);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
matrix.setRotate(-90);
break;
default:
return bitmap;
}
try {
Bitmap bmRotated = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
bitmap.recycle();
return bmRotated;
}
catch (OutOfMemoryError e) {
e.printStackTrace();
return null;
}
}
For me ExifInterface worked quite well like this:
ExifInterface exifInterface = new ExifInterface(imagePath);
degree = Integer.parseInt(exifInterface.getAttribute(ExifInterface.TAG_ORIENTATION));
or you can try to get the details of image using MediaStore like this:
String[] orientationColumn = {MediaStore.Images.Media.ORIENTATION};
Cursor cur = managedQuery(imageUri, orientationColumn, null, null, null);
int orientation = -1;
if (cur != null && cur.moveToFirst()) {
orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
}
Similar Solution: ExifInterface always returns 1
Hope it helps.. :)
I followed last answer and 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. Answer is correct but it is difficult to manage Bitmaps in Android.
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);
For those who come along this post, make sure to use the exifinterface from the Android Support Library that was introduced in December 2016:
compile "com.android.support:exifinterface:25.1.0" // or newer
Details about this library can be found in the according Android Developers Blog post: Introducing the ExifInterface Support Library
They also included a sample code for dealing with rotation information stored in the exif interface:
int rotation = 0;
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotation = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotation = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotation = 270;
break;
}
The solution for me was to create the ExifInterface from the input stream. Do not try to create it from a path, which maybe a content provider path and will fail to give the correct result. Convert the orientation into degrees and rotate image if required. Below is the key code for the solution when using the support library (e.g androidx.exifinterface.media.ExifInterface).
int orientation = 0;
InputStream input = mContext.getContentResolver().openInputStream(uri);
if (input != null){
ExifInterface exif = new ExifInterface(input);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
input.close();
}
Here is my full code to obtain a correctly orientated bitmap selected from the Gallery, which also takes a maxsize. If using it make sure you check for the null return case.
public Bitmap getBitmapFromGalleryUri(Context mContext, Uri uri, Double maxSize)throws IOException {
int orientation = 0;
InputStream input = mContext.getContentResolver().openInputStream(uri);
if (input != null){
ExifInterface exif = new ExifInterface(input);
orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
//Log.d("Utils", "rotation value = " + orientation);
input.close();
}
input = mContext.getContentResolver().openInputStream(uri);
BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
onlyBoundsOptions.inJustDecodeBounds = true;
onlyBoundsOptions.inDither = true;//optional
onlyBoundsOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//optional
BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
try {
input.close();
} catch (NullPointerException e) {
e.printStackTrace();
}
if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1)) {
return null;
}
int originalSize = (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth) ? onlyBoundsOptions.outHeight : onlyBoundsOptions.outWidth;
double ratio = (originalSize > maxSize) ? (originalSize / maxSize) : 1.0;
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio);
bitmapOptions.inDither = true; //optional
bitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//
input = mContext.getContentResolver().openInputStream(uri);
Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
try {
input.close();
} catch (NullPointerException e) {
e.printStackTrace();
}
Matrix matrix = new Matrix();
//Log.d("Utils", "rotation value = " + orientation);
int rotationInDegrees = exifToDegrees(orientation);
//Log.d("Utils", "rotationInDegrees value = " + rotationInDegrees);
if (orientation != 0) {
matrix.preRotate(rotationInDegrees);
}
int bmpWidth = 0;
try {
bmpWidth = bitmap.getWidth();
} catch (NullPointerException e) {
e.printStackTrace();
}
Bitmap adjustedBitmap = bitmap;
if (bmpWidth > 0) {
adjustedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
return adjustedBitmap;
}
private static int getPowerOfTwoForSampleRatio(double ratio){
int k = Integer.highestOneBit((int)Math.floor(ratio));
if(k==0) return 1;
else return k;
}
public 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;
}

Categories

Resources