Android image orientation issue with custom camera activity - android

I wrote a custom camera activity to handle some issues I've been having with certain android devices when calling intent image capture. The user is able to either select save image or just use the data returned back from the OnPictureTakenCallback.
The problem I'm having is displaying the image correctly with respect to the orientation it was taken. I force the activity to be displayed in portrait by calling SetRequestedOrientation.
How would I know the correct Orientation the camera was in when the user took the picture?
i.e. The user could take the picture at a rotation of 90 (portrait).
I've tried to get to use the getRotation() on the window manager's default display, but with setting the requested orientation to portrait that only returns Surface.ROTATION_0.
Update:
To clarify my other issue, how could I determine the orientation from just the byte[] data in the picture callback if the user were to not save the image?
Update: After trying the answers below with this code all I'm getting is ExifInterface.ORIENTATION_NORMAL. I've also changed my code to just save the file returned from the camera as I'm not sure there is an easy way to determine the orientation with just having the byte[] data.
private PictureCallback mPicture = new PictureCallback()
{
#Override
public void onPictureTaken(byte[] data, Camera camera)
{
File directory = new File(android.os.Environment.getExternalStoragePublicDirectory(android.os.Environment.DIRECTORY_PICTURES),
"MyApp");
if(!directory.exists())
{
if(!directory.mkdirs())
{
Log.d("CAMERA", "Unable to create directory to save photos.");
return;
}
}
File file = new File(directory.getPath() + file.separator + "IMG_" + SimpleDateFormat.getDateTimeInstance().toString() + ".jpg");
FileOutputStream fos = new FileOutputStream(file);
fos.write(data);
fos.close();
ExifInterface exif = new ExifInterface(file.getCanonicalPath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
int rotate = 0;
switch (orientation)
{
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
case default:
break;
}
}
};

SO you are facing some issue with the orientation of the camera.
This link shows an example app of a simple camera capture activity :
http://labs.makemachine.net/2010/03/simple-android-photo-capture/
Maybe you should try fixing the orientation by doing something like this :
ExifInterface exif = new ExifInterface(_path);
int exifOrientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
int rotate = 0;
switch (exifOrientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
}
if (rotate != 0) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
// Setting pre rotate
Matrix mtx = new Matrix();
mtx.preRotate(rotate);
// Rotating Bitmap & convert to ARGB_8888, required by tess
bitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, false);
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
}

You will need to read the Metadata from the original JPEG to verify the orientation in which the picture was taken.
ExifInterface exif = new ExifInterface(SourceFileName);
String exifOrientation = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
Source: How to determine orientation of picture without ExifInterface?
Edit: Answering your edit, have you tried using the getCameraInfo() method that is available with the Camera object passed in the callback? Does it have the info you require?
Source: http://developer.android.com/reference/android/hardware/Camera.html

Removing the setRequestedOrientation() allowed getWindowManager().getDefaultDisplay().getRotation() to give the correct rotation. I guess setting the requested orientation prevents the activity from redrawing itself when the configuration changes thus the device doesn't know any kind of rotation changed. My only issue now is switching from landscape mode at 0 degrees orientation to landscape mode 180 degrees rotation does not fire this:
#Override
public void onConfigurationChanged(Configuration newconfig)
{
super.onConfigurationChanged(newconfig);
}

public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
Camera.Parameters parameters = mCamera.getParameters();
if (this.getResources().getConfiguration().orientation !=
Configuration.ORIENTATION_LANDSCAPE)
{
parameters.set("orientation", "portrait"); <----THis gets the job done!!!
// For Android Version 2.2 and above
mCamera.setDisplayOrientation(90);
// For Android Version 2.0 and above
parameters.setRotation(90);
}
// End Effects for Android Version 2.0 and higher
mCamera.setParameters(parameters);
}
catch (IOException exception)
{
mCamera.release();
}
}

Related

Can I get the orientation of a photo taken in my app if I limit the activity's orientation to portrait only in my manifest?

I don't want to support landscape UI at all across my app, but I want to be able to automatically rotate the photos users take in landscape mode.
Currently if a user takes a photo in landscape mode, it remains on screen as if it was taken in portrait (the horizon in the photo is vertical).
I've tried to get the orientation from the system like this:
val display = (getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay
val screenOrientation = display.rotation
Log.d("orientation", screenOrientation.toString())
But it doesn't work and just gives back 0 every time.
I've tried a few other solutions but couldn't get them to work.
I am wondering, am I wasting my time trying to figure this out? Is it even possible to know the orientation in which the photo was captured if my activity only operates in portrait mode?
There are a few articles out there talking about camera orientation but they don't talk about whether the orientation in their activity is locked or not.
Thank you.
//Yes, find the Orientation Using ExifInterface
try{
File imageFile = new File(imagePath);
ExifInterface exif = new ExifInterface(imageFile.getAbsolutePath());
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
// dont know exactly but, orientation for landscape may be 180 or 270.
// From the orientation value you can convert image according to orientation and can be set it vertically, horrizentally as below
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;
}
Log.e(Common.TAG, "Exif orientation: " + orientation);
}
catch (Exception e) {
e.printStackTrace();
}
// Now Change image as your wish...
// Image rotation //
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
Bitmap cropped = Bitmap.createBitmap(scaled, x, y, width, height, matrix, true);

Using Android Camera API, snapped photo's orientation is always Undefined

I use the camera api and the photo taken is always rotated by 90 degree, and i would like to rotate it.
So first of all i would like to know the picture's orientation and this point im stuck.
I always getting UNDEFINDED orientation in both ways.
Here is the code:
#Override
public void onPictureTaken(byte[] data, Camera camera) {
//Bitmap Options for lowering quality the bitmap to save memory
Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
options.inPreferredConfig = Bitmap.Config.RGB_565;
//Make the bitmap
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
//Making the path, the root will be fine for tests
String path = Environment.getExternalStorageDirectory().toString();
//output stream
OutputStream outputStream = null;
//Making the file as a jpg
File file = new File(path, "tmp_pic" + ".jpg"); // the File to save to
try {
//Writing the file
outputStream = new FileOutputStream(file);
outputStream.flush();
outputStream.close(); // do not forget to close the stream
//Getting the orientation in both possible ways
int ori = getOrientationFromExif(file.getPath());
int ori2 = getOrientationFromUri(Uri.fromFile(file));
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
if (bitmap == null) {
Toast.makeText(getApplicationContext(), "Error: Cant make photo.", Toast.LENGTH_SHORT).show();
}
else {
PhotoTapView.photoViews.get(index).setPhotoImage(bitmap);
finish();
}
cameraObject.release();
}
The functions for orientation:
//Getting orientation from file URI
private int getOrientationFromUri(Uri imageUri) {
String[] orientationColumn = { MediaStore.Images.Media.ORIENTATION };
Cursor cur = getContentResolver().query(imageUri, orientationColumn, null, null, null);
int orientation = -1;
if (cur != null && cur.moveToFirst()) {
orientation = cur.getInt(cur.getColumnIndex(orientationColumn[0]));
}
Log.i("Orientation from Uri", orientation + "");
return orientation;
}
//Getting orientation from ExifInterface
private static int getOrientationFromExif(String imagePath) {
int orientation = -1;
try {
ExifInterface exif = new ExifInterface(imagePath);
int exifOrientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
Log.i("Orientation from Exif: ", exifOrientation + "");
switch (exifOrientation) {
case ExifInterface.ORIENTATION_ROTATE_270:
orientation = 270;
Log.i("Orientation from Exif", "270");
break;
case ExifInterface.ORIENTATION_ROTATE_180:
orientation = 180;
Log.i("Orientation from Exif", "180");
break;
case ExifInterface.ORIENTATION_ROTATE_90:
Log.i("Orientation from Exif", "90");
orientation = 90;
break;
case ExifInterface.ORIENTATION_NORMAL:
orientation = 0;
Log.i("Orientation from Exif", "0 - Normal");
break;
case ExifInterface.ORIENTATION_UNDEFINED:
orientation = -1;
Log.e("Orientation from Exif", "UNDEFINED");
}
}
catch (IOException e) {}
return orientation;
}
Log output:
01-14 19:46:09.468: E/Orientation from Exif(12411): UNDEFINED
01-14 19:46:09.468: I/Orientation from Uri(12411): -1
What could be the problem?
I have been decoding/observing Android JPEG images since early 2011 because I published an image viewing application. In the 'early' days, the images were encoded in the sensor's native orientation and the actual orientation of the device was written into the EXIF metadata. Starting about 2 years ago, I noticed that the orientation was no longer being written into the EXIF data and instead, the camera app was rotating the image pixels before encoding the JPEG files. My guess is that this occurred because some photo viewers (* cough * Windows * cough *) ignore the EXIF orientation when displaying JPEG files and instead of waiting for Microsoft to fix it and blaming Android for doing something wrong, they decided to make use of the faster CPU/memory and just rotate the image.
The result is that without knowing the EXIF orientation, one can only determine that a photo was captured in landscape or portrait orientation. This bit of info is only an assumption because the majority of camera sensors are wider than they are tall.
In this code
outputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream); // Add this line
outputStream.flush();
outputStream.close(); // do not forget to close the stream
You forgot to actually write the bytes to the output stream. So, the file is 0 length and naturally doesn't contain any EXIF information.
Also be careful as you are calling decodeByteArray and then saving it out again, this will also lose the EXIF information! You need to parse the EXIF from the original image bytes.

Android camera image orientation without sufaceView

I am having a service in which I have to capture image without a surfaceView, everything is working perfect except the result image orientation, which I found to be miss-angled. On small device like HTC, I found it having issue or rotation so set rotation manually to see it working and it worked.
if (camInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
parameters.setRotation(270);
} else if (camInfo.facing ==
Camera.CameraInfo.CAMERA_FACING_BACK) {
parameters.setRotation(90);
}
But when checking over samsung and HTC one (large devices) it creates problem with the angle. I found some posts where there I have to put the image path and then try to set the rotation, but that didn't work for me i.e. this as I am taking picture without serfaceview and then immediately posting it to the server. I also tried the google portion of code for setCameraOrientation() but it requires the activity view to work and so I am failed there too.
All I need is to fix the angle of the image before sent to the server without any surfaceview or activity thing.
setRotation() may only choose to play with the EXIF flags. The result is an image which is still rotated 90°, but with a "flag" that describes the correct orientation. Not all viewers correctly account for this flag. Specifically, BitmapFactory ignores it. You can draw the bitmap rotated on a canvas, or rotate the bitmap acquired from BitmapFactory.decodeFile(), or manipulate the JPEG data before writing it into outStream using a 3rd party lib, e.g. MediaUtil. The Android port is on GitHub.
You can have access to the image orientation information through the ExifInterface object. It will give you different values depending on the phone and if you capture the image in Landscape or Portrait mode. You can then use a matrix to rotate the image according to the ExifInterface information.And finally send it to your server.
Knowing the path of your image ( imagePath ), use the following code:
Matrix matrix = new Matrix();
try{
ExifInterface exif = new ExifInterface(imagePath);
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
// Change the image orientation
matrix.postRotate(90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
// Change the image orientation
matrix.postRotate(180);
break;
}catch (IOException e) {
e.printStackTrace();
}
Then you use your matrix object in order to rotate your bitmap using:
rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),matrix, true);
You would have to save the bitmap somewhere ( external or internal temp storage ) before sending it to the server.
Hope it helps you.
Your rotation-setting code is a bit too simple, so it's possible that on some devices it'll do the wrong thing. It's not guaranteed that these are the right rotations - the correct answer is a function of your device's current orientation, and the orientation of the sensor on the device.
Take a look at the sample code for Camera.Parameters.setRotation:
public void onOrientationChanged(int orientation) {
if (orientation == ORIENTATION_UNKNOWN) return;
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else { // back-facing camera
rotation = (info.orientation + orientation) % 360;
}
mParameters.setRotation(rotation);
}
If you don't have an activity, you'll have to figure out how to get the device's current orientation some other way, but you do need to include info.orientation in your calculation.

Image rotated when taking a photo in portrait mode

I have implemented a custom camera from which I take a picture,save it insert it into the media store and display it immediately after.I have been plagued by the problem of the saved image orientation,I have tried to fix this using ExifInterface using the filePath directly or by using the orientation from the Android Images content provider.
The orientation is always returned as 0.I have already used:
Android image selected from gallery Orientation is always 0 : Exif TAG
private int getExifOrientation(String pathName)
{
//for complete info on EXIF orientation visit: http://sylvana.net/jpegcrop/exif_orientation.html
ExifInterface exif=null;
try {
exif = new ExifInterface(pathName);
} catch (IOException e) {
// TODO Auto-generated catch block
Log.e("ImagePreviewActivity", "Exif data of the image could not be retreived");
}
int orientation=exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
return orientation;
}
private int getRotation(int orientation)
{
int rotation=0;
switch(orientation)
{
case ExifInterface.ORIENTATION_ROTATE_90:
//orientation values is 6
rotation=90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
//orientation value is 3
rotation=180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
//orientation value is 8
rotation=270;
break;
case -1:
Log.d("ImagePreviewActivity","Error getting orientation from Exif data.");
break;
case 1:
Log.d("ImagePreviewActivity", "Image is properly oriented");
default:
Log.d("ImagePreviewActivity", "The value of orientation is "+orientation);
}
return rotation;
}
private Bitmap rotateBitmap(String pathName,int rotation)
{
Bitmap bmp=BitmapFactory.decodeFile(pathName);
Matrix matrix=new Matrix();
matrix.postRotate(90);
//start from x=0,y=0 and filter=false
Bitmap rotatedBitmap=Bitmap.createBitmap(bmp,0,0,bmp.getWidth(),bmp.getHeight(),matrix,false);
return rotatedBitmap;
}
EDIT:
The output image has been displaying correctly when I take the picture in the Landscape mode,however it returns a rotated image(90 degrees) when taking a picture in portrait mode.
I am currently using the EXIF based method.
Make sure the pathname you are passing in does not have "file://" at the beginning of it. ExifInterface doesn't throw an error or anything if your path is prefixed with that, it just returns default for the orientation every time.

Picture orientation from gallery/camera intent [duplicate]

This question already has answers here:
Images taken with ACTION_IMAGE_CAPTURE always returns 1 for ExifInterface.TAG_ORIENTATION on some Gingerbread devices
(5 answers)
Closed 4 years ago.
I'm getting picture to my app from camera / gallery intent. In many phones picture that I read from the intent / Uri is already rotated to correct orientation. For example N1, Legend, Desire that is the case.
But then on some phones ( for example Milestone1, GalaxyS) the picture is always in landscape more no matter which way the picture was taken. This means that in my application portrait picture is presented wrong way to the user. I tried to read EXIF info of the picture but orientation tag is always 0. There has to be a way to find out the right orientation of the picture because in Milestone1 the gallery application shows the portrait pictures correctly.
How do I know if I need to rotate the picture myself before showing it to the user?
Thank you for you help!
Florian answer is working for gallery images.
The following code works for captured images, havn't tried with gallery images but i believe it should work. Hope this helps anybody.
Code :
public static int getCameraPhotoOrientation(Context context, Uri imageUri, String imagePath){
int rotate = 0;
try {
context.getContentResolver().notifyChange(imageUri, null);
File imageFile = new File(imagePath);
ExifInterface exif = new ExifInterface(
imageFile.getAbsolutePath());
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;
}
Log.v(TAG, "Exif orientation: " + orientation);
} catch (Exception e) {
e.printStackTrace();
}
return rotate;
}
EDIT:
As can be read in the comments, some devices do not support Exif information, havn't checked which but i think HTC doesn't. be sure to check what devices and create an alternative.
The following method returns the orientation of an image in degrees. It works with images from the gallery. Return values for:
normal landscape: 0
normal portrait: 90
upside-down landscape: 180
upside-down portrait: 270
image not found: -1
The code:
public static int getOrientation(Context context, Uri photoUri) {
Cursor cursor = context.getContentResolver().query(photoUri,
new String[] { MediaStore.Images.ImageColumns.ORIENTATION },
null, null, null);
try {
if (cursor.moveToFirst()) {
return cursor.getInt(0);
} else {
return -1;
}
} finally {
cursor.close();
}
}
int rotate = 0;
try {
File imageFile = new File(sourcepath);
ExifInterface exif = new ExifInterface(
imageFile.getAbsolutePath());
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 (Exception e) {
e.printStackTrace();
}
Matrix matrix = new Matrix();
matrix.postRotate(rotate);
bitmap = Bitmap.createBitmap(bitmap , 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
This is the best answer I have found, by ramaral. https://stackoverflow.com/a/20480741/2258389
Works great for gallery or camera
You have to create the gallery object using contentresolver first and then pass the uri created to the image capture intent. Then you can look at the exif data, NOT the gallery orientation data.
Matrix matrix = new Matrix();
ExifInterface exifReader = new ExifInterface(filePath);
int orientation = exifReader.getAttributeInt(ExifInterface.TAG_ORIENTATION, -1);
if (orientation ==ExifInterface.ORIENTATION_NORMAL) {
// Do nothing. The original image is fine.
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
matrix.postRotate(90);
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
matrix.postRotate(180);
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
matrix.postRotate(270);
}
I have the same problem with S1, and I noted even if you open the image using stock gallery app it will open in landscape mode(the phone doesn’t know the correct orientation for photo).
And if you rotate the phone to portrait in camera app the icons (take pic, focus and settings) will not rotated, try that in S2 or any device support landscape/portrait camera those icons will be rotated.
What I am sure the stock camera app doesn’t support taking photos in prorate mode.
I already did that for a project, because I had the same problem (Android thinking you'll only do a picture on landscape). What I did was detecting the phone orientation at the time, and then rotate the image. It supposes the orientation is still the same when the intent is received, though.
This looks like the same problem that was solved in this question:
Android: Bitmaps loaded from gallery are rotated in ImageView
Use it this way!
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;
}
And in the code,
Bitmap newImage = Bitmap.createBitmap(actualImage, 0, 0, width, height, matrix, true);
Simple!
What I am doing :
first check the orientation of image taken by camera using its meta data information , and If we found this in portrait then we have to rotate the image by 90 and display otherwise only display.
For getting the Information about orientation of image we can use Exif interface.
That's It!
The simple exiftodegree answers only consistently work when you have taken a photo and i use it for such. For those of you experiencing issues with choosing a photo and getting the correct orientation, see my answer here: Image Orientation - Android

Categories

Resources