I am creating a camera app. The image when captured is shown in the grid view.
Now, the code is working completely fine on all the devices except for samsung devices.
I am facing the orientation issue. When I capture an image in a portrait mode, the image rotates when displayed in the gridview. I have not kept any rotate code.
Secondly, with the EXIF I achieved the proper image in the grid view but when the device orientation changes, again the image rotates in a wiered fashion.
Attaching images:
Sorry for the resolution of the image. Please lemme know if they are not visible properly. Will upload again. I know there are lot such help on SO. But I guess I am stuck up somewhere.
I am referring the following link:
http://blog.andolasoft.com/2013/06/how-to-show-captured-images-dynamically-in-gridview-layout.html
This is the code I've done this with (it is working for every device):
this part is where I set the taken photo to the imageview in the main activity:
try {
File imageFile = new File(cursor.getString(0));
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("", "Exif orientation: " + orientation);
} catch (Exception e) {
e.printStackTrace();
}
Matrix matrix = new Matrix();
matrix.postRotate(rotate);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
testImage.setImageBitmap(null);
testImage.setImageBitmap(bmp);
constant values in camera activity:
private static final int ORIENTATION_PORTRAIT_NORMAL = 1;
private static final int ORIENTATION_PORTRAIT_INVERTED = 2;
private static final int ORIENTATION_LANDSCAPE_NORMAL = 3;
private static final int ORIENTATION_LANDSCAPE_INVERTED = 4;
private OrientationEventListener mOrientationEventListener;
private int mOrientation = -1;
callback function in camera activity:
Camera.PictureCallback photoCallback=new Camera.PictureCallback(){
public void onPictureTaken(final byte[] data, final Camera camera){
dialog=ProgressDialog.show(CameraActivity.this,"","Please wait while the photo is being saved..");
new Thread(){
public void run(){
try{
Thread.sleep(1000);
}
catch(Exception ex){}
onPictureTake(data,camera);
}
}.start();
}
};
take photo function in camera activity:
public void onPictureTake(byte[] data, Camera camera){
switch (mOrientation) {
case ORIENTATION_PORTRAIT_NORMAL:
rotate = 90;
break;
case ORIENTATION_LANDSCAPE_NORMAL:
rotate = 0;
break;
case ORIENTATION_PORTRAIT_INVERTED:
rotate = 270;
break;
case ORIENTATION_LANDSCAPE_INVERTED:
rotate = 180;
break;
}
Matrix matrix = new Matrix();
matrix.postRotate(rotate);
bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
mutableBitmap = bmp.copy(Bitmap.Config.ARGB_8888, true);
savePhoto(mutableBitmap);
dialog.dismiss();
flag = 0;
finish();
}
orientation listenner which is called in onresume in camera activity:
mOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
#SuppressWarnings("deprecation")
#Override
public void onOrientationChanged(int orientation) {
// determine our orientation based on sensor response
int lastOrientation = mOrientation;
Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
int rotation = getWindowManager().getDefaultDisplay().getRotation();
System.out.println(rotation+"");
if (display.getOrientation() != Surface.ROTATION_0) { // landscape oriented devices
System.out.println("LANDSCAPE");
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
} else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
} else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
} else if (orientation <135 && orientation > 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
}
} else { // portrait oriented devices
System.out.println("PORTRAIT");
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
} else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
} else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
} else if (orientation <135 && orientation > 45) {
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
}
}
}
};
Here is the code that I used in my app to rotate and works in all devices:
private Bitmap adjustImageOrientation(Bitmap image) {
ExifInterface exif;
try {
exif = new ExifInterface(picturePath);
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 = image.getWidth();
int h = image.getHeight();
// Setting pre rotate
Matrix mtx = new Matrix();
mtx.preRotate(rotate);
// Rotating Bitmap & convert to ARGB_8888, required by tess
image = Bitmap.createBitmap(image, 0, 0, w, h, mtx, false);
}
} catch (IOException e) {
return null;
}
return image.copy(Bitmap.Config.ARGB_8888, true);
}
First you need to get the original file orientation--
try {
ExifInterface exif = new ExifInterface("File AbsolutePath");
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED);
Bitmap bm = rotateBitmap("Old Bitmap", orientation);
} catch (IOException e) {
e.printStackTrace();
}
You need to write a method which return the Bitmap after rotate it to the right direction.
public Bitmap rotateBitmap(Bitmap bitmap, int orientation) throws IOException {
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;
}
}
Related
I have the open sourced code for the Google Mobile Vision - CameraSource and this is the method I call to click a photo : cameraSource.takePicture();
In the open sourced version of CameraSource.java, the method for determining screen orientation is the stock one:
private void setRotation(Camera camera, Camera.Parameters parameters, int cameraId) {
WindowManager windowManager =
(WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
int degrees = 0;
int rotation = windowManager.getDefaultDisplay().getRotation();
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
default:
Log.e(TAG, "Bad rotation value: " + rotation);
}
CameraInfo cameraInfo = new CameraInfo();
Camera.getCameraInfo(cameraId, cameraInfo);
int angle;
int displayAngle;
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
angle = (cameraInfo.orientation + degrees) % 360;
displayAngle = (360 - angle) % 360; // compensate for it being mirrored
} else { // back-facing
angle = (cameraInfo.orientation - degrees + 360) % 360;
displayAngle = angle;
}
// This corresponds to the rotation constants in {#link Frame}.
mRotation = angle / 90;
camera.setDisplayOrientation(displayAngle);
parameters.setRotation(angle);
}
Here, the displayAngle and the angle are the same for Samsung, Lenovo and Yuntab H8. But the bitmap returned for backCamera is rotated differently in each of the device. I have to manually rotate the bitmap for each of the devices (Samsung : 90, Lenovo : 0 and Yuntab : 180)
My requirement is that onPictureTaken should return a bitmap which matches the current display orientation. I am looking into this, since a long time but yet have to figure a way to the solution. Here below is my onPicturetaken() (called after taking picture):
#Override
public void onPictureTaken(byte[] bytes) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, currentCameraId == 0 ? options : null);
}catch (Exception ex){
ex.printStackTrace();
Log.e("PictureTaken",ex.toString());
}
};
You should rotate the image when it is already saved in the device.
Then you can rotate it to match the position it was when the photo was taken.
Example code (It might need some cleanup and improvement, but it works...):
Method do calculate the rotation an image has:
private static int rotationNeeded(String path) {
try {
File file = new File(path);
if (!file.getName().contains(".jpg")) {
return 0;
}
ExifInterface exif = new ExifInterface(file.getAbsolutePath());
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
return 270;
}
if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
return 180;
}
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
return 90;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}
Apply the rotation needed to the image:
public static void rotateImage(String filePath) {
try {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeFile(filePath, options);
//check image rotation
int rotate = rotationNeeded(filePath);
if (rotate != 0) {
//rotate image if needed
Matrix matrix = new Matrix();
matrix.postRotate(rotate);
Bitmap rotatedImage = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
bitmap.getHeight(), matrix, true);
bitmap.recycle();
bitmap = rotatedImage;
//save image
byte[] dataPicture = bao.toByteArray();
FileOutputStream fos = new FileOutputStream(filePath);
fos.write(dataPicture);
fos.flush();
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
I captured image from camera and display image into imageview. It will display perfect but the captured image rotated 90 degrees automatically in some devices. I searched a lot about it but could not get proper solution. Please tell me the solution for it. Thanks in advance.
try this code
public Bitmap adjustImageOrientation(Bitmap image, File f) {
int rotate = 0;
try {
ExifInterface exif = new ExifInterface(f.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;
case ExifInterface.ORIENTATION_NORMAL:
rotate = 0;
break;
}
} catch (Exception e) {
e.printStackTrace();
}
if (rotate != 0) {
Matrix matrix = new Matrix();
matrix.postRotate(rotate);
image = Bitmap.createBitmap(image, 0, 0, image.getWidth(),
image.getHeight(), matrix, true);
}
return image;
}
Use this method to determine image rotation.
public int getCameraPhotoOrientation(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;
}
} catch (Exception e) {
}
return rotate;
}
And if the method wouldn't return Zero rotated the image.
int degree=getCameraPhotoOrientation(Uri.fromFile(tempFile), fPath);
if (degree!= 0) {
bitmap = tools.rotateOrientationCall(bitmap, degree);
}
Rotate your bitmap.
public Bitmap rotateOrientationCall(Bitmap src, float degree) {
Matrix matrix = new Matrix();
matrix.postRotate(degree);
return Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true);
}
I am implementing the custom camera. It's working fine but in some mobiles especially in few Samsung mobile we are facing some problems like saving the image as some rotation. Suppose we are taking the picture in portrait mode but the image is saved in landscape mode.
Here I have some doubts.
I set the Camera screen activity orientation as portrait. Is it create any problems. Which orientation is good for the activity which having the camera.
What's common solution for all mobiles for rotation of image and preview stretch issues.
I tried a lot. My solutions are working in few mobiles only like nexus , Moto G..It fails in Samsung S4 mini, Galaxy Grand Duos 2...
thanks,
I implemented one photo take activity which you can take the photo and set the orientation of the photo. It is supported by every device I tested including Samsung galaxy series, tablets, sony xperia series, tablets.
You can check out my accepted answer about rotation of images on this topic:
Camera capture orientation on samsung devices in android
this part is where I set the taken photo to the imageview in the main activity:
try {
File imageFile = new File(cursor.getString(0));
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("", "Exif orientation: " + orientation);
} catch (Exception e) {
e.printStackTrace();
}
Matrix matrix = new Matrix();
matrix.postRotate(rotate);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
testImage.setImageBitmap(null);
testImage.setImageBitmap(bmp);
constant values in camera activity:
private static final int ORIENTATION_PORTRAIT_NORMAL = 1;
private static final int ORIENTATION_PORTRAIT_INVERTED = 2;
private static final int ORIENTATION_LANDSCAPE_NORMAL = 3;
private static final int ORIENTATION_LANDSCAPE_INVERTED = 4;
private OrientationEventListener mOrientationEventListener;
private int mOrientation = -1;
callback function in camera activity:
Camera.PictureCallback photoCallback=new Camera.PictureCallback(){
public void onPictureTaken(final byte[] data, final Camera camera){
dialog=ProgressDialog.show(CameraActivity.this,"","Please wait while the photo is being saved..");
new Thread(){
public void run(){
try{
Thread.sleep(1000);
}
catch(Exception ex){}
onPictureTake(data,camera);
}
}.start();
}
};
take photo function in camera activity:
public void onPictureTake(byte[] data, Camera camera){
switch (mOrientation) {
case ORIENTATION_PORTRAIT_NORMAL:
rotate = 90;
break;
case ORIENTATION_LANDSCAPE_NORMAL:
rotate = 0;
break;
case ORIENTATION_PORTRAIT_INVERTED:
rotate = 270;
break;
case ORIENTATION_LANDSCAPE_INVERTED:
rotate = 180;
break;
}
Matrix matrix = new Matrix();
matrix.postRotate(rotate);
bmp = BitmapFactory.decodeByteArray(data, 0, data.length);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
mutableBitmap = bmp.copy(Bitmap.Config.ARGB_8888, true);
savePhoto(mutableBitmap);
dialog.dismiss();
flag = 0;
finish();
}
orientation listenner which is called in onresume in camera activity:
mOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
#SuppressWarnings("deprecation")
#Override
public void onOrientationChanged(int orientation) {
// determine our orientation based on sensor response
int lastOrientation = mOrientation;
Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
int rotation = getWindowManager().getDefaultDisplay().getRotation();
System.out.println(rotation+"");
if (display.getOrientation() != Surface.ROTATION_0) { // landscape oriented devices
System.out.println("LANDSCAPE");
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
} else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
} else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
} else if (orientation <135 && orientation > 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
}
} else { // portrait oriented devices
System.out.println("PORTRAIT");
if (orientation >= 315 || orientation < 45) {
if (mOrientation != ORIENTATION_PORTRAIT_NORMAL) {
mOrientation = ORIENTATION_PORTRAIT_NORMAL;
}
} else if (orientation < 315 && orientation >= 225) {
if (mOrientation != ORIENTATION_LANDSCAPE_NORMAL) {
mOrientation = ORIENTATION_LANDSCAPE_NORMAL;
}
} else if (orientation < 225 && orientation >= 135) {
if (mOrientation != ORIENTATION_PORTRAIT_INVERTED) {
mOrientation = ORIENTATION_PORTRAIT_INVERTED;
}
} else if (orientation <135 && orientation > 45) {
if (mOrientation != ORIENTATION_LANDSCAPE_INVERTED) {
mOrientation = ORIENTATION_LANDSCAPE_INVERTED;
}
}
}
}
};
If you also need to save and use that image that you have rotated, saving and using the photo functions additional to my answer I gave above:
savePhoto function:
public void savePhoto(Bitmap bmp) {
imageFileFolder = new File(Environment.getExternalStorageDirectory(),
cc.getDirectoryName());
imageFileFolder.mkdir();
FileOutputStream out = null;
Calendar c = Calendar.getInstance();
String date = fromInt(c.get(Calendar.MONTH))
+ fromInt(c.get(Calendar.DAY_OF_MONTH))
+ fromInt(c.get(Calendar.YEAR))
+ fromInt(c.get(Calendar.HOUR_OF_DAY))
+ fromInt(c.get(Calendar.MINUTE))
+ fromInt(c.get(Calendar.SECOND));
imageFileName = new File(imageFileFolder, date.toString() + ".jpg");
try {
out = new FileOutputStream(imageFileName);
bmp.compress(Bitmap.CompressFormat.JPEG, 70, out);
out.flush();
out.close();
scanPhoto(imageFileName.toString());
out = null;
} catch (Exception e) {
e.printStackTrace();
}
}
scanPhoto function:
public void scanPhoto(final String imageFileName) {
geniusPath = imageFileName;
msConn = new MediaScannerConnection(MyClass.this,
new MediaScannerConnectionClient() {
public void onMediaScannerConnected() {
msConn.scanFile(imageFileName, null);
}
#Override
public void onScanCompleted(String path, Uri uri) {
msConn.disconnect();
}
});
msConn.connect();
}
SavePhotoTask class:
class SavePhotoTask extends AsyncTask<byte[], String, String> {
#Override
protected String doInBackground(byte[]... jpeg) {
File photo = new File(Environment.getExternalStorageDirectory(),
"photo.jpg");
if (photo.exists()) {
photo.delete();
}
try {
FileOutputStream fos = new FileOutputStream(photo.getPath());
fos.write(jpeg[0]);
fos.close();
} catch (java.io.IOException e) {
}
return (null);
}
}
I am trying to capture image from the camera, it works fine with landscape mode, when I take the picture in portrait it is rotated. Below is the code I am using:
BitmapFactory.Options bounds = new BitmapFactory.Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(largeImagePath, bounds);
Bitmap bm = BitmapFactory.decodeFile(largeImagePath, opts);
ExifInterface exif = new ExifInterface(largeImagePath);
String orientString = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
System.out.println("Orientation camera:"+orientString);
int orientation = orientString != null ? Integer.parseInt(orientString) : ExifInterface.ORIENTATION_NORMAL;
int rotationAngle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90){
rotationAngle = 90;
System.out.println("In 90 degrees rotate");
}
if (orientation == ExifInterface.ORIENTATION_ROTATE_180){
rotationAngle = 180;
System.out.println("In 180 degrees rotate");
}
if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
rotationAngle = 270;
System.out.println("In 270 degrees rotate");
}
Matrix matrix = new Matrix();
System.out.println("Rotation Angle"+rotationAngle);
matrix.setRotate(rotationAngle, (float) thumbnail.getWidth() / 2, (float) thumbnail.getHeight() / 2);
bitmap = Bitmap.createBitmap(bm, 0, 0, bounds.outWidth, bounds.outHeight, matrix, true);
On Debug, the control enters the :
if (orientation == ExifInterface.ORIENTATION_ROTATE_90){
rotationAngle = 90;}
block, however no rotation to set the picture back to correct happens.
This is my XML:
<ImageView
android:id="#+id/imageView1"
android:layout_width="140dp"
android:layout_height="160dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="10dp"
android:layout_marginTop="30dp"
android:src="#drawable/btn_upload" />
UPDATE: I am getting the following exception:
02-27 13:51:55.126: I/System.out(16549): Exceptionjava.lang.IllegalArgumentException: x + width must be <= bitmap.width()
you can arrange your code as follow...
Bitmap bm = BitmapFactory.decodeFile(largeImagePath, opts);
ExifInterface ei;
try {
ei = new ExifInterface(largeImagePath);
int orientation = ei.getAttributeInt(ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
bitmap = rotateImage(bitmap, 90);
break;
case ExifInterface.ORIENTATION_ROTATE_180:
bitmap = rotateImage(bitmap, 180);
break;
case ExifInterface.ORIENTATION_ROTATE_270:
bitmap = rotateImage(bitmap, 270);
break;
}
} catch (IOException e) {
e.printStackTrace();
}
write rotateImage() method as follows....
private Bitmap rotateImage(Bitmap source, float angle) {
Bitmap bitmap = null;
Matrix matrix = new Matrix();
matrix.postRotate(angle);
try {
bitmap = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(),
matrix, true);
} catch (OutOfMemoryError err) {
err.printStackTrace();
}
return bitmap;
}
Use bm.getWidth() and bm.getHeight() instead bounds.outWidth and bounds.outHeight in createBitmap() method.
I'm finding in onPictureTaken that the bitmap saved is mirrored about the y-axis and rotated 90 degrees clockwise even though the camera preview was not. This is on my Nexus S that's running 2.3.6. The same program running on my Nexus 4 with 4.2 has the resulting bitmap mirrored about the y-axis and rotated 180 degrees clockwise.
This is the code I'm running in onPictureTaken:
#Override
public void onPictureTaken(final byte[] data, Camera camera) {
Bitmap picture = BitmapFactory.decodeByteArray(data, 0, data.length);
String path = MediaStore.Images.Media.insertImage(getContentResolver(), picture, "name" , "description");
Log.e("tag", "path: " + path); // prints something like "path: content://media/external/images/media/819"
try {
ExifInterface exif = new ExifInterface(path); // prints this error: "04-25 21:28:21.063: E/JHEAD(12201): can't open 'content://media/external/images/media/819'"
int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
Log.e("tag", "exif orientation: " + orientation); // this is outputting orientation unknown
} catch (IOException e) {
e.printStackTrace();
}
}
Can anyone show me how I rectify this given that I seem to be getting different results from different devices? How do I detect the orientation of the resulting bitmap so that I know to rotate it either 90 or 180 degrees counterclockwise?
[EDIT]
I added some more information using the ExifInterface stuff I've been reading about, but that information doesn't seem to pan out...
I have put a lot of work into this and thought, I'd share my solution.
It is tested on a Motorola Devy, Samsung Xcover 1 and Samsung XCover 2.
As I work with a custom camera preview, the solution basically has two
parts.
1. Take care of the camera preview and set rotation of the preview according
to device rotation.
2. Once a picture is taken, that is the 'onPictureTaken' callback is invoked
rotate the picture by the correct angle, such that it shows what the preview just
showed.
1
private void initPreview(int width, int height) {
if (camera != null && holder.getSurface() != null) {
try {
camera.setPreviewDisplay(holder);
} catch (Throwable t) {
Log.e("PreviewDemo-surfaceCallback",
"Exception in setPreviewDisplay()", t);
Toast.makeText(getContext(), t.getMessage(),
Toast.LENGTH_LONG).show();
}
try {
Camera.Parameters parameters=camera.getParameters();
Camera.Size size=getBestPreviewSize(width, height, parameters);
Camera.Size pictureSize=getSmallestPictureSize(parameters);
Display display = windowManager.getDefaultDisplay();
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) { // for 2.1 and before
if (isPortrait(display)) {
parameters.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_PORTRAIT);
} else {
parameters.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_LANDSCAPE);
}
} else { // for 2.2 and later
switch (display.getRotation()) {
case Surface.ROTATION_0: // This is display orientation
if (size.height > size.width) parameters.setPreviewSize(size.height, size.width);
else parameters.setPreviewSize(size.width, size.height);
camera.setDisplayOrientation(90);
break;
case Surface.ROTATION_90:
if (size.height > size.width) parameters.setPreviewSize(size.height, size.width);
else parameters.setPreviewSize(size.width, size.height);
camera.setDisplayOrientation(0);
break;
case Surface.ROTATION_180:
if (size.height > size.width) parameters.setPreviewSize(size.height, size.width);
else parameters.setPreviewSize(size.width, size.height);
camera.setDisplayOrientation(270);
break;
case Surface.ROTATION_270:
if (size.height > size.width) parameters.setPreviewSize(size.height, size.width);
else parameters.setPreviewSize(size.width, size.height);
camera.setDisplayOrientation(180);
break;
}
}
parameters.setPictureSize(pictureSize.width, pictureSize.height);
//parameters.setPictureFormat(ImageFormat.JPEG);
camera.setParameters(parameters);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Your 'surfaceChanged' method, in your camera preview (SurfaceView),
you should look like this:
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
stopPreview();
initPreview(w, h);
startPreview();
}
where
stopPreview:
private void stopPreview() {
if (camera != null) {
camera.stopPreview();
}
}
startPreview:
private void startPreview() {
if (camera != null) {
camera.startPreview();
}
}
2
In your 'onPictureTaken' callback rotate the picture, using the following code:
Display display = getWindowManager().getDefaultDisplay();
int rotation = 0;
switch (display.getRotation()) {
case Surface.ROTATION_0: // This is display orientation
rotation = 90;
break;
case Surface.ROTATION_90:
rotation = 0;
break;
case Surface.ROTATION_180:
rotation = 270;
break;
case Surface.ROTATION_270:
rotation = 180;
break;
}
Bitmap bitmap = BitmapTools.toBitmap(data);
bitmap = BitmapTools.rotate(bitmap, rotation);
BitmapTools.java
public class BitmapTools {
public static Bitmap toBitmap(byte[] data) {
return BitmapFactory.decodeByteArray(data , 0, data.length);
}
public static Bitmap rotate(Bitmap in, int angle) {
Matrix mat = new Matrix();
mat.postRotate(angle);
return Bitmap.createBitmap(in, 0, 0, in.getWidth(), in.getHeight(), mat, true);
}
}
here you go check this out, save the picture and maybe this will work and remember if(bitmap.getWidth > bitmap.getHeight()) as another check
public static int getExifRotation(String imgPath)
{
try
{
ExifInterface exif = new ExifInterface(imgPath);
String rotationAmount = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
if (!TextUtils.isEmpty(rotationAmount))
{
int rotationParam = Integer.parseInt(rotationAmount);
switch (rotationParam)
{
case ExifInterface.ORIENTATION_NORMAL:
return 0;
case ExifInterface.ORIENTATION_ROTATE_90:
return 90;
case ExifInterface.ORIENTATION_ROTATE_180:
return 180;
case ExifInterface.ORIENTATION_ROTATE_270:
return 270;
default:
return 0;
}
}
else
{
return 0;
}
}
catch (Exception ex)
{
return 0;
}
}
you must read about ExifInterface to resolve this issue.
i have this function in my application to check weather weather image taken from camera needs to be rotateed or not.
if(ExifNeedsRotate(GetPathFromUri(context, selectedImage))){
// Rotate your bitmap using the Matrix
}
public static boolean ExifNeedsRotate(String paramString){
if (android.os.Build.VERSION.SDK_INT >= 5){
try
{
Class localClass = Class.forName("android.media.ExifInterface");
Class[] arrayOfClass1 = new Class[1];
arrayOfClass1[0] = String.class;
Constructor localConstructor = localClass.getConstructor(arrayOfClass1);
Class[] arrayOfClass2 = new Class[1];
arrayOfClass2[0] = String.class;
Method localMethod = localClass.getMethod("getAttribute", arrayOfClass2);
Object[] arrayOfObject1 = new Object[1];
arrayOfObject1[0] = paramString;
Object localObject1 = localConstructor.newInstance(arrayOfObject1);
Object[] arrayOfObject2 = new Object[1];
arrayOfObject2[0] = "Orientation";
Object localObject2 = localMethod.invoke(localObject1, arrayOfObject2);
if (localObject2 != null){
boolean bool = localObject2.equals("6");
if (bool)
return true;
}
}
catch (Exception localException){
return false;
}
}
return false;
}
Pass the path of the ImageUri as a input.
public static String GetPathFromUri(Context paramContext, Uri paramUri)
{
String str;
try
{
if (paramUri.toString().startsWith("file:")){
str = paramUri.getPath();
}
else
{
str = null;
String[] arrayOfString = new String[1];
arrayOfString[0] = "_data";
Cursor localCursor = paramContext.getContentResolver().query(paramUri, arrayOfString, null, null, null);
if (localCursor != null)
{
localCursor.moveToFirst();
int i = localCursor.getColumnIndex(arrayOfString[0]);
if ((localCursor.getCount() >= 1) && (localCursor.getColumnCount() >= i + 1))
str = localCursor.getString(i);
localCursor.close();
}
}
}
catch (Exception localException){
str = null;
}
return str;
}
Instead of rotating the picture explicitly in the picture taken callback, you can configure the camera to have picture rotated for you when the picture is taken.
camera.SetDisplayOrientation(degrees) //sets the orientation in the preview
while
cameraParameters.SetRotation(degress) //rotates the actual captured image