react-native-vision-camera icon indicating copy to clipboard operation
react-native-vision-camera copied to clipboard

🐛 Wrong Orientation on `takePhoto` (`takeSnapshot` is working properly)

Open frodriguez-hu opened this issue 1 year ago • 12 comments

What's happening?

I am doing the processing listed below to the photo taken by takePhoto or takeSnapshot.

When I use takePhoto I have to invert the height and width of the photo in order to make the calculations of the scale factors, that is happening on Android and IOS as well. Then in IOS it works fine, the x represents the X axis and the Y represents the y axis. But in android when I am going to crop the image, the X is modifying the Y axis and the Y modifying the X axis, I think that is an issue on how the photo that is coming from takePhoto.

But let's say it is okey and you handle that axis rotation, the Y axis is coming on a different proportion cause the cropping is cropping it in the middle of the face, which it should not happen like that. (Those are not issues from Image Editor cause it is working fine on other pictures).

The code below it is working since it is using takeSnapshot, shouldn't work the same for takePhoto?

I think it is the same issue detailed here:

https://github.com/mrousavy/react-native-vision-camera/issues/2994

Reproduceable Code

const {x, y, height, width} = FACE_BOUNDS;
    const takenPhoto = await cameraRef?.current?.takeSnapshot({quality: 100});
    if (takenPhoto) {
      const scaleFactorY = takenPhoto.height / windowDimensions.height;
      const scaleFactorX = takenPhoto.width / windowDimensions.width;
      const croppedPhotoResult = await ImageEditor.cropImage(
        `file://${takenPhoto.path}`,
        {
          offset: {
            x: x * scaleFactorX,
            y: y * scaleFactorY,
          },
          size: {
            width: width * scaleFactorX,
            height: height * scaleFactorY,
          },
          displaySize: {
            width: 192,
            height: 192,
          },
        },
      );


### Relevant log output

```shell
i do not have significant logs here.

Camera Device

{
  "formats": [],
  "sensorOrientation": "landscape-right",
  "hardwareLevel": "limited",
  "maxZoom": 4,
  "minZoom": 1,
  "maxExposure": 20,
  "supportsLowLightBoost": true,
  "neutralZoom": 1,
  "physicalDevices": [
    "wide-angle-camera"
  ],
  "supportsFocus": true,
  "supportsRawCapture": false,
  "isMultiCam": false,
  "minFocusDistance": 10,
  "minExposure": -20,
  "name": "1 (FRONT) androidx.camera.camera2",
  "hasFlash": false,
  "hasTorch": false,
  "position": "front",
  "id": "1"
}

Device

Samsung S21 plus

VisionCamera Version

4.5.0

Can you reproduce this issue in the VisionCamera Example app?

No, I cannot reproduce the issue in the Example app

Additional information

frodriguez-hu avatar Aug 15 '24 13:08 frodriguez-hu

Guten Tag, Hans here! 🍻

Thanks for raising this issue. I see you have some concerns with the takePhoto function. However, it seems that you did not provide relevant logs or specific reproduction steps that could help mrousavy diagnose the problem. Logs from adb logcat or specific errors will give much better insight.

Please share those logs, and be sure to check if the issue persists when you use the example app. If this issue remains after that and you gather more information, feel free to reopen it!

Also, if you find this project helpful, consider sponsoring mrousavy here to ensure continued support and updates!

Note: If you think I made a mistake, please ping @mrousavy to take a look.

maintenance-hans[bot] avatar Aug 15 '24 13:08 maintenance-hans[bot]

@mrousavy Sorry to tag you I know it bothers you but the bot is asking me to do it

frodriguez-hu avatar Aug 15 '24 13:08 frodriguez-hu

Another thing to mention is that when I set isMirrored on false. the crop works but with the image inverted

frodriguez-hu avatar Aug 15 '24 14:08 frodriguez-hu

The code below it is working since it is using takeSnapshot, shouldn't work the same for takePhoto?

Those two funcs are implemented very differently - takeSnapshot uses the preview stream on Android and the video stream on iOS, and takePhoto uses a photo queue.

Did you examine the EXIF values? Maybe width and height represent physical pixel width/height of the image, and if it is using EXIF flags to rotate the image then the physical pixel width/height is represented before any EXIF orientations are considered.

mrousavy avatar Aug 20 '24 21:08 mrousavy

@mrousavy I am also getting same issue with the takePhoto function

chandanpradhanin avatar Aug 21 '24 12:08 chandanpradhanin

Also facing the same on Android

rsainiWin avatar Aug 22 '24 19:08 rsainiWin

I'm having the same issue on Android.

It's a bit strange though as it works correctly on one Android device, but not the other. So on one device (Samsung A54), it is captured in landscape, and the final image is landscape. The other (Pixel 3) is captured in landscape, but the final image is portrait.

Using: outputOrientation: 'preview'

stewartiee avatar Aug 28 '24 13:08 stewartiee

any updates im facing the same issue

dorakadri avatar Aug 30 '24 08:08 dorakadri

same here

mannoeu avatar Aug 30 '24 13:08 mannoeu

On our side, we have issues when we process the picture on our backend using Skia. We create a Thumbnail version of the picture taken right after we upload it to our backend. The original picture has the proper orientation, but the scaled thumbnail has the wrong orientation. Any idea why?

Asiratlan avatar Sep 18 '24 14:09 Asiratlan

Depending on how you process the thumbnail you might also need to handle orienation yourself.

mrousavy avatar Sep 23 '24 09:09 mrousavy

Maybe of some use to anyone. I had the same problem with take photo. On some android devices it would work on others the images are rotated 90 degrees. Looking the response from takePhoto I found that for a Lenovo tablet a landscape photo came back with orientation 'portrait' and a height bigger that width but on Samsung the width would be bigger that the height. Both oriented landscape right. Switching the numbers didn't do much for the displayed images but what ended up fixing the issue for me was adding a correction to the exif orientation prop.

     const response = await cameraRef.current?.takePhoto(takePhotoOptions);

     const getOrientation = ({ height, width, orientation }: PhotoFile) => {
        if (orientation === 'portrait' && width > height) {
          return 1;
        } else {
          return 8;
        }
      };
      // edit the EXIF according the the documentation:
     // import { writeAsync } from '@lodev09/react-native-exify';
      await writeAsync(getImagePath({ uri: response.path, ...response }), {
        ...(Platform.OS === 'android' ? { Orientation: getOrientation(response) } : {}),
      });

This solved the display issues I had with the photo's for me. Hope that helps

nojas01 avatar Oct 03 '24 17:10 nojas01

@nojas01 what is getImagePath doing? Adding the file://? Cause I tried your code and I am still experiencing the issue

felire avatar Nov 05 '24 17:11 felire