Controlling the camera to take pictures in portrait doesn't rotate the final images

AndroidAndroid CameraAndroid Orientation

Android Problem Overview


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());
	}
}

Android Solutions


Solution 1 - Android

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);
}

Solution 2 - Android

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.

Solution 3 - Android

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.

Solution 4 - Android

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);
}

Solution 5 - Android

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

Solution 6 - Android

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);
}

Solution 7 - Android

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:)

Solution 8 - Android

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();
    }
  }

Solution 9 - Android

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()
    }
})

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbeniView Question on Stackoverflow
Solution 1 - AndroidbeniView Answer on Stackoverflow
Solution 2 - AndroidNimrod DayanView Answer on Stackoverflow
Solution 3 - AndroidSheraz Ahmad KhiljiView Answer on Stackoverflow
Solution 4 - AndroidnvhausidView Answer on Stackoverflow
Solution 5 - AndroidKD_View Answer on Stackoverflow
Solution 6 - AndroidD. ScottView Answer on Stackoverflow
Solution 7 - AndroidYueh-Ming ChienView Answer on Stackoverflow
Solution 8 - AndroidRushi M ThakkerView Answer on Stackoverflow
Solution 9 - AndroidAlbertoView Answer on Stackoverflow