Android Camera Saving Pictures in Portrait Mode

2019-05-15 22:51发布

问题:

I'm trying to use a camera in my app and I want to be able to use it in landscape and portrait mode. I'm having no difficulty creating pictures in landscape mode, but I haven't found a good way to save pictures in portrait mode.

When I want to make a picture in portrait mode I need to set the displayorientation to portrait first, like this:

switch (windowManager.getDefaultDisplay().getRotation()) {
    case android.view.Surface.ROTATION_0:
        mCamera.setDisplayOrientation(90);
        break;
    case android.view.Surface.ROTATION_90:
        mCamera.setDisplayOrientation(0);
        break;
    case android.view.Surface.ROTATION_180:
        mCamera.setDisplayOrientation(270);
        break;
    case android.view.Surface.ROTATION_270:
        mCamera.setDisplayOrientation(180);
        break;
}

But then the picture is still saved in landscape mode. One solution I found was to change the rotation parameter of the camera like this:

public void onOrientationChanged(int orientation) {
    if (orientation == ORIENTATION_UNKNOWN) return;
    android.hardware.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;
    }
    mParameters.setRotation(rotation);
}

The problem with this approach is that it may just set the orientation in the EXIF header and not actually rotate the picture (which is the case with the device I'm using).

Another approach was rotating the actual data after the picture is taken like this:

Bitmap bitmap = BitmapFactory.decodeByteArray(data,0,data.length);
int w = bitmap.getWidth();
int h = bitmap.getHeight();
Matrix mtx = new Matrix();
mtx.postRotate(rotate);
bitmap=  Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, true);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
currentData = stream.toByteArray();

But this approach takes 10 seconds (which is too long) and while I could put this code in an AsyncTask, I need the data one to a few seconds later, so then I'd still need to wait.

So far I haven't found a better solution.

回答1:

I have found a solution that makes me still need to wait for a second or two, but that's fast enough for me. It's a pretty simple fix, just use the Matrix.postRotate method, but change:

bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);

to:

bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);

For me this is a pretty good solution, especially because everywhere else I already used .jpg images so it didn't make much sense compressing the Bitmap to a .png anyway.