V.Bhat
V.Bhat

Reputation: 63

Camera Source (Google Mobile Vision) returns rotated image on some devices

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

Upvotes: 4

Views: 1597

Answers (1)

Eduardo Herzer
Eduardo Herzer

Reputation: 2123

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

Upvotes: 2

Related Questions