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.
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();
}
}
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With