Search code examples
androidandroid-intentcameraandroid-cameraandroid-camera-intent

Android - Ensuring that photo orientation is preserved when taking photos via Camera Intent?


I am building an Android App where the user can take a photo and then it gets saved to a certain file path. I have no problems with using the camera intent and saving the result to a custom file path as well as showing it to the user in an ImageView. However, I've recently encountered a strange behaviour when I was testing it over several devices.

Whenever I take the photo in portrait, I get a landscape result.

Here is the code I use:

public void onTakePhoto(View view){


    //camera stuff
    Intent imageIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());

    //folder stuff
    File imagesFolder = new File(Environment.getExternalStorageDirectory(), "folderHere");
    imagesFolder.mkdirs();

    File image = new File(imagesFolder, timeStamp + ".png");
    Uri uriSavedImage = Uri.fromFile(image);

    imageIntent.putExtra(MediaStore.EXTRA_OUTPUT, uriSavedImage);
    startActivityForResult(imageIntent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);

}

This opens the camera and takes 1 shot. After the 1 shot, the user can choose to retry taking the photo. I've found out that for some devices, even if I take the photo portrait, the output turns landscape. I've set the orientation of the activity to portrait.

What I've done so far to get the result, determine the rotation using the Exif File, then rotate it accordingly (as so detailed in a handful of answers to the issue I'm having). However, the problem here is that it takes some time, I get 3-4 seconds of black screen before I get back to my activity where I see it in the ImageView.

Here's the rotation code I used:

File is the file path in String.

BitmapFactory.Options bounds = new BitmapFactory.Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeFile(file, bounds);

BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap bm = BitmapFactory.decodeFile(file, opts);
ExifInterface exif = null;

try {
    exif = new ExifInterface(file);
} catch (IOException e) {
    Log.e(TAG, "exception hit while making exif!", e);
}

String orientString = exif.getAttribute(ExifInterface.TAG_ORIENTATION);
int orientation = orientString != null ? Integer.parseInt(orientString) :  ExifInterface.ORIENTATION_NORMAL;

int rotationAngle = 0;
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) rotationAngle = 90;
if (orientation == ExifInterface.ORIENTATION_ROTATE_180) rotationAngle = 180;
if (orientation == ExifInterface.ORIENTATION_ROTATE_270) rotationAngle = 270;

Matrix matrix = new Matrix();
matrix.setRotate(rotationAngle, (float) bm.getWidth() / 2, (float) bm.getHeight() / 2);
Bitmap rotatedBitmap = Bitmap.createBitmap(bm, 0, 0, bounds.outWidth, bounds.outHeight, matrix, true);

FileOutputStream out = null;
try {
    out = new FileOutputStream(imagePath);
    rotatedBitmap.compress(Bitmap.CompressFormat.PNG, 100, out); // bmp is your Bitmap instance
    // PNG is a lossless format, the compression factor (100) is ignored
} catch (Exception e) {
    Log.e(TAG, "exception hit while exporting!", e);
    e.printStackTrace();
} finally {
    try {
        if (out != null) {
            out.close();
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Is there a reliable way of making sure that the orientation of the camera gets preserved when saving the photo? If the camera is on portrait then the result should be in portrait as well, the same case for landscape.

I've been looking around but I've had little luck. A solution I can think of is maybe we can pass something along with the camera intent, like a rotation constant or something, so that the output doesn't get messed with and we get the orientation we want.


Solution

  • Is there a reliable way of making sure that the orientation of the camera gets preserved when saving the photo?

    No.

    First, you are delegating the picture taking to a third-party app, one of thousands of possible camera apps. Those developers can do whatever they want.

    Second, the underlying cause of this comes from camera hardware and firmware. You have no means of telling some chipset to rotate the image instead of using the EXIF orientation header.