1

I have an android application that takes a photo and then displays the image. On my device, which I originally developed the app on, the image capture behaves as expected. However, when I have tried running it on other devices, on some devices it seems that the image is rotated 90 degrees. I have been able to determine that this is not an issue with the image preview, and that the image itself is rotated. The code for the image capture is here:

public void takePicture(){
    if(null == cameraDevice) {
        return;
    }
    try {
        System.out.println("Taking Picture");
        getCameraCharacteristics();

        ImageReader reader = ImageReader.newInstance(1920, 1440, ImageFormat.JPEG, 1);
        //ImageReader reader = ImageReader.newInstance(camera_width, camera_height, ImageFormat.RAW_SENSOR, 1);
        List<Surface> outputSurfaces = buildOutputSurfaces(reader);

        final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
        captureBuilder.addTarget(reader.getSurface());
        captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);

        // Orientation
        int rotation = parent.getWindowManager().getDefaultDisplay().getRotation();
        captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));

        ImageReader.OnImageAvailableListener readerListener = reader1 -> getImageFromBuffer(reader1);
        reader.setOnImageAvailableListener(readerListener, mBackgroundHandler);

        final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
            @Override
            public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
                super.onCaptureCompleted(session, request, result);
                createCameraPreview();
            }
        };

        cameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(CameraCaptureSession session) {
                try {
                    session.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }
            }
            @Override
            public void onConfigureFailed(CameraCaptureSession session) {
            }
        }, mBackgroundHandler);
    }
    catch (CameraAccessException e) {
        e.printStackTrace();
    }
}

Regardless of device, the value for rotation is always 0. I have tried manually setting the JPEG_ORIENTATION to different values, but it does not seem to make a difference.

I have seen other StackOverflow questions with similar issues, but the fixes in those questions did not seem to make a difference here.

Can anyone suggest what might be causing this?

EDIT: to add some more details to the requirements for the app. The issue isn't just with displaying the image but with handling it afterwards. The user has to select a point in the image and then pair of point and image are sent to a server for processing. As a result, I need to orientation of the underlying image to be consistent between devices, its not enough to simply compensate when displaying the image.

Unfortunately I cant switch my application over to using a CameraIntent for image capture, as the application needs to be able to observe behaviour during photo capture and provide continuous feedback.

Birdfriender
  • 343
  • 1
  • 7
  • 24
  • Have you tried examining the EXIF for the image? Some devices (Samsung notably) have the sensor *physically* rotated (And then compensated in SW). There was a way to check for this (I had to do it once) but I have long forgotten who I did this for... (here's a good [answer that will point you in the right direction](https://stackoverflow.com/a/14066265/2684)) – Martin Marconcini Mar 29 '21 at 15:07
  • @MartinMarconcini I am not using a CameraIntent to capture my image, I'm just getting the bitmap data straight from the buffer in ImageReader, is this data still accessible without using the filesystem? – Birdfriender Mar 30 '21 at 09:57
  • I don't know (but I don't think so). – Martin Marconcini Mar 30 '21 at 11:22
  • @Birdfriender You can try this: https://stackoverflow.com/a/62881788/3466808 – Sam Chen Mar 30 '21 at 12:27

2 Answers2

0

Use Glide to load and display your taken picture:

Glide.with(context).load(imageUri).into(imageView)

Demo: https://youtu.be/tPwr2yYxlA4


Helpful reading:

Sam Chen
  • 7,597
  • 2
  • 40
  • 73
  • This will help with displaying the image, but I also need to use the image in other parts of my application where I will need the orientation to be consistent. Would this let me determine the original orientation of the image? – Birdfriender Mar 30 '21 at 09:58
  • @Birdfriender `Glide` doesn't change the orientation of your image, it just read the EXIF data (which contains orientation info) from your image and display it properly into your `ImageView`. Displaying using `Glide`, processing using `Bitmap`, no conflict. – Sam Chen Mar 30 '21 at 12:33
  • what I mean is, I need to also rotate the bitmap so the orientation is consistent between devices, is there a way to also do this? – Birdfriender Mar 31 '21 at 10:47
  • @Birdfriender You can try this: https://futurestud.io/tutorials/glide-how-to-rotate-images or this: https://stackoverflow.com/a/50237879/3466808 – Sam Chen Mar 31 '21 at 14:14
0

Okay, I found a solution to this issue from a blogpost here. Essentially rather than relying on setting the JPEG rotation in the capture builder, you compute it yourself and incorporate the sensor data to determine how many degrees you have to rotate the image by.

// Orientation
int deviceRotation = parent.getWindowManager().getDefaultDisplay().getRotation();
int surfaceRotation = ORIENTATIONS.get(deviceRotation);
jpegOrientation = (surfaceRotation + sensorOrientation + 270) % 360;

I then decode the image into a bitmap, rotate it by the computed value, and then encoded it back into a ByteArray.

Birdfriender
  • 343
  • 1
  • 7
  • 24