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 am using the following code to take a picture and then display it on screen to the user using an ImageView. I want the picture to be displayed fullscreen (like on snapchat). However, the picture is always displayed like this horizontally with a white screen everywhere else:
This is my layout:
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/camera_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
android:id="#+id/picturedisplay"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/imgClose"
android:layout_gravity="right|bottom"
android:text="Flip Cam"
android:padding="20dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/snap"
android:text="Capture"
android:layout_gravity="center|bottom"
android:padding="20dp"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Flash"
android:id="#+id/imgOpen"
android:layout_gravity="left|bottom"
android:padding="20dp"/>
and the code:
public class CameraScreen extends Activity {
private Camera mCamera = null;
private SessionManager session;
private String rand_img;
private ImageView preview_pic;
private Bitmap bitmap;
private CameraPreview mCameraView = null;
private byte[] photo;
static final int CAM_REQUEST = 1;
private RandomString randomString = new RandomString(10);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_screen);
session = new SessionManager(getApplicationContext());
try {
mCamera = Camera.open();//you can use open(int) to use different cameras
} catch (Exception e) {
Log.d("ERROR", "Failed to get camera: " + e.getMessage());
}
if (mCamera != null) {
mCameraView = new CameraPreview(this, mCamera);//create a SurfaceView to show camera data
FrameLayout camera_view = (FrameLayout) findViewById(R.id.camera_view);
camera_view.addView(mCameraView);//add the SurfaceView to the layout
}
//btn to close the application
Button imgClose = (Button) findViewById(R.id.imgClose);
imgClose.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
System.exit(0);
}
});
//btn to close the application
Button logout = (Button) findViewById(R.id.imgOpen);
logout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
session.logOut();
Intent a = new Intent(CameraScreen.this, MainActivity.class);
startActivity(a);
finish();
}
});
Button snap = (Button) findViewById(R.id.snap);
snap.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCamera.takePicture(shutterCallback, rawCallback, jpegCallback);
}
});
}
#Override
protected void onPause() {
super.onPause();
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCameraView.getHolder().removeCallback(mCameraView);
mCamera.release();
}
}
#Override
public void onResume() {
super.onResume();
// Get the Camera instance as the activity achieves full user focus
if (mCamera == null) {
initializeCamera(); // Local method to handle camera initialization
}
}
protected void initializeCamera(){
// Get an instance of Camera Object
try{
mCamera = Camera.open();//you can use open(int) to use different cameras
} catch (Exception e){
Log.d("ERROR", "Failed to get camera: " + e.getMessage());
}
if(mCamera != null) {
mCameraView = new CameraPreview(this, mCamera);//create a SurfaceView to show camera data
FrameLayout camera_view = (FrameLayout)findViewById(R.id.camera_view);
camera_view.addView(mCameraView);//add the SurfaceView to the layout
}
}
private File getFile() {
File sdCard = Environment.getExternalStorageDirectory();
File folder = new File(sdCard.getAbsolutePath() +"/city_life_pic");
if (!folder.exists()) {
folder.mkdir();
}
rand_img = randomString.nextString() + ".jpg";
File image = new File(folder,rand_img);
return image;
}
Camera.ShutterCallback shutterCallback = new Camera.ShutterCallback() {
public void onShutter() {
Log.d("ON SHUTTER", "onShutter'd");
}
};
Camera.PictureCallback rawCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
Log.d("ON PICTURE RAW", "onPictureTaken - raw");
}
};
Camera.PictureCallback jpegCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
photo = data;
new SaveImageTask().execute(data);
Log.d("ON PICTURE JPEG", "onPictureTaken - jpeg");
}
};
private class SaveImageTask extends AsyncTask<byte[], Void, Void> {
#Override
protected Void doInBackground(byte[]... data) {
FileOutputStream outStream = null;
// Write to SD Card
try {
bitmap = decodeByteArray(photo, 0, photo.length);
File outFile = getFile();
outStream = new FileOutputStream(outFile);
outStream.write(data[0]);
ExifInterface exif=new ExifInterface(outFile.toString());
Log.d("EXIF value", exif.getAttribute(ExifInterface.TAG_ORIENTATION));
if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("6")){
bitmap= rotate(bitmap, 90);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("8")){
bitmap= rotate(bitmap, 270);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("3")){
bitmap= rotate(bitmap, 180);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("0")){
bitmap= rotate(bitmap, 90);
}
boolean bo = bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
outStream.flush();
outStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
return null;
}
#Override
protected void onPostExecute(Void aVoid) {
FrameLayout camera_view = (FrameLayout)findViewById(R.id.camera_view);
preview_pic = (ImageView) findViewById(R.id.picturedisplay);
camera_view.setVisibility(View.GONE);
preview_pic.setVisibility(View.VISIBLE);
preview_pic.setImageBitmap(bitmap);
}
}
public static Bitmap rotate(Bitmap bitmap, int degree) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
// mtx.postRotate(degree);
mtx.setRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
}
EDIT ROTATION CODE:
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;
}
if (currentCamInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
//switch camera to back camera
mCamera = Camera.open(camBackId);
result = (currentCamInfo.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else {
//switch camera to front camera
mCamera = Camera.open(camFrontId);
result = (currentCamInfo.orientation - degrees + 360) % 360;
}
if (mCamera != null) {
mCamera.setDisplayOrientation(result);
//rotate camera
mCameraView = new CameraPreview(this, mCamera);//create a SurfaceView to show camera data
camera_view.addView(mCameraView);//add the SurfaceView to the layout
Camera.Parameters p = mCamera.getParameters();
p.setRotation(90);
mCamera.setParameters(p);
}
Try adding mCamera.setDisplayOrientation(90) to your initializeCamera() method. You can also calculate the right orientation settings based on this code.
public static int getCameraDisplayOrientation(int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = Session.currentActivity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
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;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
Code set Orientation of Camera:
public static void setCameraDisplayOrientation(Activity activity,
int cameraId, android.hardware.Camera camera) {
try {
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
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;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
} catch (Exception e) {
// TODO: handle exception
}
}
Code display result file video to imageview:
Bitmap bm = ThumbnailUtils.createVideoThumbnail(dt.FileName,
MediaStore.Images.Thumbnails.MINI_KIND);
img.setScaleType(ImageView.ScaleType.CENTER_CROP);
img.setImageBitmap(bm);
How display thumbnail of video the same view of camera?
Use Matrix:
Bitmap bmp = ThumbnailUtils.createVideoThumbnail(dt.FileName,
MediaStore.Images.Thumbnails.MINI_KIND);
img.setScaleType(ImageView.ScaleType.CENTER_CROP);
Matrix matrix = new Matrix();
matrix.postRotate(90);
bmp = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(),
bmp.getHeight(), matrix, true);
img.setImageBitmap(bmp);
I'm trying to controlling the Android camera to take pictures in a portrait app, but when I save the picture, it's in landscape. I've rotated the image 90 grades with setCameraDisplayOrientation() method, but doesn't work.
Then I've found this post but the TAG_ORIENTATION is 0 (undefined). If I catch this value and apply a rotation value, doesn't work either.
How I can take a photo in portrait and save it with a good orientation?
/** Initializes the back/front camera */
private boolean initPhotoCamera() {
try {
camera = getCameraInstance(selected_camera);
Camera.Parameters parameters = camera.getParameters();
// parameters.setPreviewSize(width_video, height_video);
// parameters.set("orientation", "portrait");
// parameters.set("rotation", 1);
// camera.setParameters(parameters);
checkCameraFlash(parameters);
// camera.setDisplayOrientation( 0);
setCameraDisplayOrientation(selected_camera, camera);
surface_view.getHolder().setFixedSize(width_video, height_video);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(width_video, height_video);
surface_view.setLayoutParams(lp);
camera.lock();
surface_holder = surface_view.getHolder();
surface_holder.addCallback(this);
surface_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
setPreviewCamera();
} catch (Exception e) {
Log.v("RecordVideo", "Could not initialize the Camera");
return false;
}
return true;
}
public void setCameraDisplayOrientation(int cameraId, Camera camera) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
int rotation = getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
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;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
public static Bitmap rotate(Bitmap bitmap, int degree) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
// mtx.postRotate(degree);
mtx.setRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
#Override
public void onPictureTaken(byte[] data, Camera camera) {
String timeStamp = Calendar.getInstance().getTime().toString();
output_file_name = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + File.separator + timeStamp + ".jpeg";
File pictureFile = new File(output_file_name);
if (pictureFile.exists()) {
pictureFile.delete();
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
Bitmap realImage = BitmapFactory.decodeFile(output_file_name);
ExifInterface exif=new ExifInterface(pictureFile.toString());
Log.d("EXIF value", exif.getAttribute(ExifInterface.TAG_ORIENTATION));
if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("6")){
realImage= rotate(realImage, 90);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("8")){
realImage= rotate(realImage, 270);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("3")){
realImage= rotate(realImage, 180);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("0")){
realImage= rotate(realImage, 45);
}
boolean bo = realImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
Log.d("Info", bo + "");
} catch (FileNotFoundException e) {
Log.d("Info", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("TAG", "Error accessing file: " + e.getMessage());
}
}
The problem is when I saved the image I didn't do well.
#Override
public void onPictureTaken(byte[] data, Camera camera) {
String timeStamp = new SimpleDateFormat( "yyyyMMdd_HHmmss").format( new Date( ));
output_file_name = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + File.separator + timeStamp + ".jpeg";
File pictureFile = new File(output_file_name);
if (pictureFile.exists()) {
pictureFile.delete();
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
Bitmap realImage = BitmapFactory.decodeByteArray(data, 0, data.length);
ExifInterface exif=new ExifInterface(pictureFile.toString());
Log.d("EXIF value", exif.getAttribute(ExifInterface.TAG_ORIENTATION));
if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("6")){
realImage= rotate(realImage, 90);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("8")){
realImage= rotate(realImage, 270);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("3")){
realImage= rotate(realImage, 180);
} else if(exif.getAttribute(ExifInterface.TAG_ORIENTATION).equalsIgnoreCase("0")){
realImage= rotate(realImage, 90);
}
boolean bo = realImage.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
((ImageView) findViewById(R.id.imageview)).setImageBitmap(realImage);
Log.d("Info", bo + "");
} catch (FileNotFoundException e) {
Log.d("Info", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("TAG", "Error accessing file: " + e.getMessage());
}
}
public static Bitmap rotate(Bitmap bitmap, int degree) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
// mtx.postRotate(degree);
mtx.setRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
The setCameraDisplayOrientation() method lets you change how the preview is displayed without affecting how the image is recorded (source).
In order to change the actual recorded image you need to set the rotation parameter of the Camera. You do it like this:
//STEP #1: Get rotation degrees
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, info);
int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break; //Natural orientation
case Surface.ROTATION_90: degrees = 90; break; //Landscape left
case Surface.ROTATION_180: degrees = 180; break;//Upside down
case Surface.ROTATION_270: degrees = 270; break;//Landscape right
}
int rotate = (info.orientation - degrees + 360) % 360;
//STEP #2: Set the 'rotation' parameter
Camera.Parameters params = mCamera.getParameters();
params.setRotation(rotate);
mCamera.setParameters(params);
Your solution is kind of a workaround since you modify the image AFTER it was already recorded. This solution is cleaner and doesn't require all these 'if' statements before saving the image.
You can use the method below to generate preview correctly when your using front camera.
This code goes into surfaceChanged Method of your camera preview
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
int angleToRotate=CommonMethods.getRoatationAngle(mActivity, Camera.CameraInfo.CAMERA_FACING_FRONT);
mCamera.setDisplayOrientation(angleToRotate);
}
This code can be put into a static class
/**
* Get Rotation Angle
*
* #param mContext
* #param cameraId
* probably front cam
* #return angel to rotate
*/
public static int getRoatationAngle(Activity mContext, int cameraId) {
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = mContext.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
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;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
You can Rotate image this way.This is used only when image is taken and we are about to save the image
public static Bitmap rotate(Bitmap bitmap, int degree) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
mtx.postRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
The Method that will be used for taking picture
#Override
public void onPictureTaken(byte[] data, Camera camera) {
int angleToRotate = getRoatationAngle(MainActivity.this, Camera.CameraInfo.CAMERA_FACING_FRONT);
// Solve image inverting problem
angleToRotate = angleToRotate + 180;
Bitmap orignalImage = BitmapFactory.decodeByteArray(data, 0, data.length);
Bitmap bitmapImage = rotate(orignalImage, angleToRotate);
}
The bitmapImage contains the correct image.
this one should work, ExifInterface doesn't work with all manufactures so use CameraInfo instead, just let camera capture image with it's default rotation and then rotate the result data on PictureCallback
private PictureCallback mPicture = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File dir = new File(Constant.SDCARD_CACHE_PREFIX);
if (!dir.exists()) {
dir.mkdirs();
}
File pictureFile = new File(Constant.SDCARD_TAKE_PHOTO_CACHE_PREFIX);
try {
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);
FileOutputStream fos = new FileOutputStream(pictureFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
resultFileUri = Uri.fromFile(pictureFile);
startEffectFragment();
}
};
public static Bitmap rotate(Bitmap bitmap, int degree) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
mtx.postRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
This is the best method to use (Mentioned Below) when your layout is fixed in portrait mode.
#Override
protected void onResume() {
super.onResume();
if (!openCamera(CameraInfo.CAMERA_FACING_BACK)) {
alertCameraDialog();
}
if (cOrientationEventListener == null) {
cOrientationEventListener = new OrientationEventListener(this, SensorManager.SENSOR_DELAY_NORMAL) {
public void onOrientationChanged(int orientation) {
// determine our orientation based on sensor response
int lastOrientation = mOrientation;
if (orientation == ORIENTATION_UNKNOWN) return;
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;
}
Parameters params = camera.getParameters();
params.setRotation(rotation);
camera.setParameters(params);
}
};
}
if (cOrientationEventListener.canDetectOrientation()) {
cOrientationEventListener.enable();
}
}
You will be using OrientEventListener and implement this call back method.
onOrientationChanged is called whenever there is change in orientation thus your camera rotation will be set and Picture will be rotated when you will save it.
private PictureCallback myPictureCallback_JPG = new PictureCallback()
{
#Override
public void onPictureTaken(byte[] arg0, Camera arg1) {
try {
File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
return;
}
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(arg0);
fos.close();
camera.startPreview();
} catch (Exception e) {
e.printStackTrace();
}
}
};
getOutputMediaFile
private static File getOutputMediaFile() {
File mediaStorageDir = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
"MyCameraApp");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
.format(new Date());
File mediaFile;
mediaFile = new File(mediaStorageDir.getPath() + File.separator
+ "IMG_" + timeStamp + ".jpg");
return mediaFile;
}
Source Here
I don't have the rep to leave a comment, so I have to leave another answer instead, although Nvhausid answer is awesome and deserves the credit. Simple, elegant and it works for both front and back cameras on a Samsung device where Exif and Media Cursor doesn't.
The only thing the answer was missing for me was handling the mirror image from the camera facing the user.
Here is the the code changes for that:
Bitmap bitmap = rotate(realImage, info.orientation, info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT);
And the new rotate method:
public static Bitmap rotate(Bitmap bitmap, int degree, boolean mirror) {
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
if(mirror)mtx.setScale(1,-1);
mtx.postRotate(degree);
return Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
}
I find the powerful answer for you, i just meet the same problem and solve it without saving file.The solution is to register an OrientationEventListener to get the orientation whenever it changes.http://www.androidzeitgeist.com/2013/01/fixing-rotation-camera-picture.html here give the details.My code is as below:
private CameraOrientationListener myOrientationListener;
private int rotation;
protected void onCreate(Bundle savedInstanceState) {
setListeners();
rotation = setCameraDisplayOrientation(CameraActivity.this, Camera.getNumberOfCameras()-1, mCamera);
}
public void setListeners(){
myOrientationListener = new CameraOrientationListener(this);
if(myOrientationListener.canDetectOrientation())
myOrientationListener.enable();
}
public static int setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) {
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
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;
}
int result;
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
return result;
}
/*
* record the rotation when take photo
*/
public void takePhoto(){
myOrientationListener.rememberOrientation();
rotation += myOrientationListener.getRememberedOrientation();
rotation = rotation % 360;
mCamera.takePicture(null, null, mPicture);
}
class CameraOrientationListener extends OrientationEventListener {
private int currentNormalizedOrientation;
private int rememberedNormalizedOrientation;
public CameraOrientationListener(Context context) {
super(context, SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
public void onOrientationChanged(int orientation) {
// TODO Auto-generated method stub
if (orientation != ORIENTATION_UNKNOWN) {
currentNormalizedOrientation = normalize(orientation);
}
}
private int normalize(int degrees) {
if (degrees > 315 || degrees <= 45) {
return 0;
}
if (degrees > 45 && degrees <= 135) {
return 90;
}
if (degrees > 135 && degrees <= 225) {
return 180;
}
if (degrees > 225 && degrees <= 315) {
return 270;
}
throw new RuntimeException("The physics as we know them are no more. Watch out for anomalies.");
}
public void rememberOrientation() {
rememberedNormalizedOrientation = currentNormalizedOrientation;
}
public int getRememberedOrientation() {
return rememberedNormalizedOrientation;
}
}
hope it helps:)
I used the new camera2 api to get sensor orientation and then rotate it accordingly:
private void detectSensorOrientation()
{
CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
try
{
for (String cameraId : manager.getCameraIdList())
{
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
// We don't use a front facing camera in this sample.
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT)
{
continue;
}
cameraOrientaion = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
}
} catch (CameraAccessException e)
{
e.printStackTrace();
}
}
Then with the help of cameraOrientation parameter, I rotated my cameraPhoto:
private void generateRotatedBitmap()
{
if (cameraOrientaion != 0)
{
Matrix matrix = new Matrix();
matrix.postRotate(cameraOrientaion);
rotatedPhoto =
Bitmap.createBitmap(cameraPhoto, 0, 0, cameraPhoto.getWidth(), cameraPhoto.getHeight(),
matrix, true);
cameraPhoto.recycle();
}
}
I have come up with this solution based on some previous ideas and my own research. If you only need the rotated image for display or storage, I think this extension function can be useful:
fun ImageProxy.toBitmap(): Bitmap {
val buffer = planes[0].buffer.apply { rewind() }
val bytes = ByteArray(buffer.capacity())
// Get bitmap
buffer.get(bytes)
val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
// Fix rotation if needed
val angle = imageInfo.rotationDegrees.toFloat()
val matrix = Matrix().apply { postRotate(angle) }
// Return rotated bitmap
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
}
You can get the ImageProxy by calling takePicture from the android camerax library:
imageCapture.takePicture(cameraExecutor, object : ImageCapture.OnImageCapturedCallback() {
override fun onCaptureSuccess(imageProxy: ImageProxy) {
val bitmap = imageProxy.toBitmap()
imageProxy.close()
}
})
I'm writing an Android application that uses the camera.
I'm setting camera display orientation to 90, my activity is in a portrait orientation:
camera.setDisplayOrientation(90);
I'm getting a well oriented preview picture, but the resulting image is rotated to -90 degrees (counter clockwise) and
exif.getAttribute(ExifInterface.TAG_ORIENTATION)
returns ORIENTATION_NORMAL
Is it expected behavior? Should I rotate resulted image after the capture?
Device - Nexus S, API - 10
Try this
try {
File f = new File(imagePath);
ExifInterface exif = new ExifInterface(f.getPath());
int orientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
int angle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
angle = 90;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
angle = 180;
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
angle = 270;
}
Matrix mat = new Matrix();
mat.postRotate(angle);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bmp = BitmapFactory.decodeStream(new FileInputStream(f),
null, options);
bitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(),
bmp.getHeight(), mat, true);
ByteArrayOutputStream outstudentstreamOutputStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100,
outstudentstreamOutputStream);
imageView.setImageBitmap(bitmap);
} catch (IOException e) {
Log.w("TAG", "-- Error in setting image");
} catch (OutOfMemoryError oom) {
Log.w("TAG", "-- OOM Error in setting image");
}
It will work
Problem is the camera orientation is a complete disaster (as is capturing an image) because OEMs do not adhere to the standard. HTC phones do things one way, Samsung phones do it a different way, the Nexus line seems to adhere no matter which vendor, CM7 based ROMs I think follow the standard no matter which hardware, but you get the idea. You sort of have to determine what to do based on the phone/ROM. See discussion here: Android camera unexplainable rotation on capture for some devices (not in EXIF)
I had the same problem like you, but i've fix it.
You should use the same code:
Camera.Parameters parameters = camera.getParameters();
parameters.setRotation(90);
camera.setParameters(parameters);
I hope you can use this code too.
camera.setDisplayOrientation(90);
I have coded the app for only Portrait Mode.
Will make the Camera to rotate to 90 degree and This may result in not suitable for all devices in android
In order to get the Correct Preview for all android devices use the following code which is refereed in developers site.
Below you have to send your activity, cameraId = back is 0 and for Front camera is 1
public static void setCameraDisplayOrientation(Activity activity, int cameraId, android.hardware.Camera camera) {
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
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;
}
int result;
//int currentapiVersion = android.os.Build.VERSION.SDK_INT;
// do something for phones running an SDK before lollipop
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
camera.setDisplayOrientation(result);
}
This is how to set the setDisplayOrientation for camera
Now you may have trouble is saving the captured Image in Correct Orientation, which is bug in Camera API to support all devices in android .you can overcome using the Steps below
PLS NOTE EXIF VALUE WILL NOT GIVE YOU CORRECT VALUE IN ALL DEVICES , So this would help you
int CameraEyeValue = setPhotoOrientation(CameraActivity.this, cameraFront==true ? 1:0); // CameraID = 1 : front 0:back
By using the same concept we used before for DisplayOrientation
public int setPhotoOrientation(Activity activity, int cameraId) {
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
int degrees = 0;
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;
}
int result;
// do something for phones running an SDK before lollipop
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
return result;
}
So your final PictureCallBack method should look like
private PictureCallback getPictureCallback() {
PictureCallback picture = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
//make a new picture file
File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
return;
}
try {
//write the file
FileOutputStream fos = new FileOutputStream(pictureFile);
Bitmap bm=null;
// COnverting ByteArray to Bitmap - >Rotate and Convert back to Data
if (data != null) {
int screenWidth = getResources().getDisplayMetrics().widthPixels;
int screenHeight = getResources().getDisplayMetrics().heightPixels;
bm = BitmapFactory.decodeByteArray(data, 0, (data != null) ? data.length : 0);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
// Notice that width and height are reversed
Bitmap scaled = Bitmap.createScaledBitmap(bm, screenHeight, screenWidth, true);
int w = scaled.getWidth();
int h = scaled.getHeight();
// Setting post rotate to 90
Matrix mtx = new Matrix();
int CameraEyeValue = setPhotoOrientation(AndroidCameraExample.this, cameraFront==true ? 1:0); // CameraID = 1 : front 0:back
if(cameraFront) { // As Front camera is Mirrored so Fliping the Orientation
if (CameraEyeValue == 270) {
mtx.postRotate(90);
} else if (CameraEyeValue == 90) {
mtx.postRotate(270);
}
}else{
mtx.postRotate(CameraEyeValue); // CameraEyeValue is default to Display Rotation
}
bm = Bitmap.createBitmap(scaled, 0, 0, w, h, mtx, true);
}else{// LANDSCAPE MODE
//No need to reverse width and height
Bitmap scaled = Bitmap.createScaledBitmap(bm, screenWidth, screenHeight, true);
bm=scaled;
}
}
// COnverting the Die photo to Bitmap
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byte[] byteArray = stream.toByteArray();
fos.write(byteArray);
//fos.write(data);
fos.close();
Toast toast = Toast.makeText(myContext, "Picture saved: " + pictureFile.getName(), Toast.LENGTH_LONG);
toast.show();
} catch (FileNotFoundException e) {
} catch (IOException e) {
}
//refresh camera to continue preview
mPreview.refreshCamera(mCamera);
mPreview.setCameraDisplayOrientation(CameraActivity.this,GlobalCameraId,mCamera);
}
};
return picture;
}
As the Works only for Portrait mode using Front and Back camera The Picture is rotated to only portrait mode with correct portrait Orientation in all android devices .
For LandScape you can Make this as reference and make changes in the below block
if(cameraFront) { // As Front camera is Mirrored so Fliping the Orientation
if (CameraEyeValue == 270) {
mtx.postRotate(90); //change Here
} else if (CameraEyeValue == 90) {
mtx.postRotate(270);//change Here
}
}else{
mtx.postRotate(CameraEyeValue); // CameraEyeValue is default to Display Rotation //change Here
}