Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Wrong iOS photo exif data #2209

Open
1 of 3 tasks
sakonn opened this issue Oct 9, 2024 · 6 comments
Open
1 of 3 tasks

[Bug]: Wrong iOS photo exif data #2209

sakonn opened this issue Oct 9, 2024 · 6 comments

Comments

@sakonn
Copy link

sakonn commented Oct 9, 2024

Capacitor Version

💊 Capacitor Doctor 💊

Latest Dependencies:

@capacitor/cli: 6.1.2
@capacitor/core: 6.1.2
@capacitor/android: 6.1.2
@capacitor/ios: 6.1.2

Installed Dependencies:

@capacitor/cli: 6.1.2
@capacitor/core: 5.5.1
@capacitor/android: 5.5.1
@capacitor/ios: 5.5.1

[success] iOS looking great! 👌
[success] Android looking great! 👌

Other API Details

npm version: 10.8.2
node version: v20.17.0
pod version: 1.13.0
iOS version: 17.4.1
ios device: iPhone SE 2nd generation

Platforms Affected

  • iOS
  • Android
  • Web

Current Behavior

I am developing a data collection app where data is collected primarily in the form of photos which are later processed. To make postprocessing more straightforward it is required that they are taken in portrait mode (not in landscape). So, I am trying to figure out a way to restrict taking pictures which are landscape-oriented. I have not found any suitable setting for that, so now I am trying to disable saving photos that are wider than higher (landscape by this logic) based on the photo metadata. Photos are taken by the capacitor camera plugin when taking the photos I have found out that information about the photos taken in the iOS app is incorrect.

Portrait photo taken in the ios app:
20241009-080808_4780201379629_overviewImage

And the related exif metadata about this photo which are returned by the plugin:

{
    "Flash": 16,
    "SubsecTimeOriginal": "675",
    "PixelXDimension": 4032,
    "MeteringMode": 5,
    "ApertureValue": 1.6959938131099002,
    "BrightnessValue": -3.0617721648310905,
    "ColorSpace": 65535,
    "FocalLenIn35mmFilm": 28,
    "SceneType": 1,
    "ExposureBiasValue": 0,
    "PixelYDimension": 3024,
    "Orientation": 1,
    "ExposureTime": 0.06666666666666667,
    "CompositeImage": 2,
    "ExposureProgram": 2,
    "WhiteBalance": 0,
    "ShutterSpeedValue": 3.9085506496196545,
    "LensModel": "iPhone SE (2nd generation) back camera 3.99mm f/1.8",
    "ExifVersion": "0232",
    "ISOSpeedRatings": [
      800
    ],
    "LensSpecification": [
      3.99,
      3.99,
      1.8,
      1.8
    ],
    "LensMake": "Apple",
    "SensingMethod": 2,
    "DateTimeDigitized": "2024:10:09 08:08:04",
    "ExposureMode": 0,
    "FNumber": 1.8,
    "DateTimeOriginal": "2024:10:09 08:08:04",
    "FocalLength": 3.99,
    "SubsecTimeDigitized": "675",
    "OffsetTimeOriginal": "+02:00",
    "SubjectArea": [
      2013,
      1511,
      2116,
      1330
    ],
    "OffsetTimeDigitized": "+02:00",
    "OffsetTime": "+02:00"
  },

Landscape photo taken in the ios app:
20241009-080905_4780201379629_facingImage

And the related exif metadata about this photo which are returned by the plugin:

{
    "Flash": 16,
    "SubsecTimeOriginal": "524",
    "PixelXDimension": 4032,
    "MeteringMode": 5,
    "ApertureValue": 1.6959938131099002,
    "BrightnessValue": -3.343055762488874,
    "ColorSpace": 65535,
    "FocalLenIn35mmFilm": 28,
    "SceneType": 1,
    "ExposureBiasValue": 0,
    "PixelYDimension": 3024,
    "Orientation": 1,
    "ExposureTime": 0.06666666666666667,
    "CompositeImage": 2,
    "ExposureProgram": 2,
    "WhiteBalance": 0,
    "ShutterSpeedValue": 3.9085506496196545,
    "LensModel": "iPhone SE (2nd generation) back camera 3.99mm f/1.8",
    "ExifVersion": "0232",
    "ISOSpeedRatings": [
      1250
    ],
    "LensSpecification": [
      3.99,
      3.99,
      1.8,
      1.8
    ],
    "LensMake": "Apple",
    "SensingMethod": 2,
    "DateTimeDigitized": "2024:10:09 08:09:01",
    "ExposureMode": 0,
    "FNumber": 1.8,
    "DateTimeOriginal": "2024:10:09 08:09:01",
    "FocalLength": 3.99,
    "SubsecTimeDigitized": "524",
    "OffsetTimeOriginal": "+02:00",
    "SubjectArea": [
      2013,
      1511,
      2116,
      1330
    ],
    "OffsetTimeDigitized": "+02:00",
    "OffsetTime": "+02:00"
  }

In my code, I am trying to compare PixelXDimension and PixelYDimension from the metadata and calculate if the photo is landscape or portrait. The problem is that these values are the same for both photos although they have different orientations.

On the contrary, the same photos taken with the android app return the expected result.
Landscape photo metadata from an android app:

    "Orientation": "0",
    "PixelXDimension": "4624",
    "PixelYDimension": "3472",

Portrait photo metadata from an android app:

    "Orientation": "0",
    "PixelXDimension": "3472",
    "PixelYDimension": "4624",

Expected Behavior

I expect to get proper photo dimensions based on the photo orientation. So if the photo is taken landscape I expect to get the XDimension wider then the YDimension. And if the photo is taken as a portrait than the YDimension should be bigger than XDimension.

Project Reproduction

https://github.com/sakonn/probable-octo-invention

Additional Information

No response

@sakonn sakonn added the triage label Oct 9, 2024
@eric-horodyski eric-horodyski transferred this issue from ionic-team/capacitor Oct 11, 2024
@ionitron-bot ionitron-bot bot removed the triage label Oct 11, 2024
@eric-horodyski
Copy link
Member

This issue relates to Camera functionality, which is part of @capacitor/camera, and as such as been transferred to the appropriate repository.

@kettenbach-it
Copy link

Will there by a solution for this?

@OS-ricardomoreirasilva OS-ricardomoreirasilva added the type: bug A confirmed bug report label Dec 5, 2024
Copy link

ionitron-bot bot commented Dec 5, 2024

This issue has been labeled as type: bug. This label is added to issues that that have been reproduced and are being tracked in our internal issue tracker.

@OS-ricardomoreirasilva
Copy link
Collaborator

OS-ricardomoreirasilva commented Dec 6, 2024

Hey @sakonn,
Can you share the entire Android JSONs as you did for iOS?
BR.

@sakonn
Copy link
Author

sakonn commented Dec 6, 2024

Hello @OS-ricardomoreirasilva,
thanks for your interest. Here is the output from the Android phone. The photos were taken in the app build from the example repository which is linked in the issue description.

Here is the outcome of the photo taken as a portrait. The ImageLength and PixelYDimension are bigger as expected.

{
  "format": "jpeg",
  "exif": {
    "ApertureValue": "167/100",
    "BrightnessValue": "0/100",
    "ColorSpace": "1",
    "ComponentsConfiguration": "???",
    "Compression": "6",
    "DateTime": "2024:12:06 18:50:20",
    "DateTimeDigitized": "2024:12:06 18:50:20",
    "DateTimeOriginal": "2024:12:06 18:50:20",
    "ExifVersion": "0220",
    "ExposureBiasValue": "0/1",
    "ExposureMode": "0",
    "ExposureProgram": "0",
    "Flash": "16",
    "FlashpixVersion": "0100",
    "FocalLength": "4730/1000",
    "FocalLengthIn35mmFilm": "0",
    "FNumber": "1.79",
    "ImageLength": "4624",
    "ImageWidth": "3472",
    "InteroperabilityIndex": "R98",
    "JPEGInterchangeFormat": "812",
    "JPEGInterchangeFormatLength": "39323",
    "LightSource": "21",
    "Make": "XXXXX",
    "MaxApertureValue": "167/100",
    "MeteringMode": "2",
    "Model": "XXXXX",
    "Orientation": "0",
    "PhotographicSensitivity": "125",
    "PixelXDimension": "3472",
    "PixelYDimension": "4624",
    "ResolutionUnit": "2",
    "SceneCaptureType": "0",
    "SceneType": "0",
    "SensingMethod": "0",
    "ShutterSpeedValue": "5058/1000",
    "SubSecTime": "609213",
    "SubSecTimeDigitized": "609213",
    "SubSecTimeOriginal": "609213",
    "WhiteBalance": "0",
    "XResolution": "72/1",
    "YCbCrPositioning": "1",
    "YResolution": "72/1"
  },
  "path": "file:///storage/emulated/0/Android/data/io.ionic.starter/files/Pictures/JPEG_20241206_185014_2081679850067582195.jpg",
  "webPath": "http://192.168.1.7:8100/_capacitor_file_/storage/emulated/0/Android/data/io.ionic.starter/files/Pictures/JPEG_20241206_185014_2081679850067582195.jpg",
  "saved": false
}

And here is the outcome of the photo taken as a landscape. The ImageWidth and PixelXDimension are bigger as expected.

{
  "format": "jpeg",
  "exif": {
    "ApertureValue": "167/100",
    "BrightnessValue": "0/100",
    "ColorSpace": "1",
    "ComponentsConfiguration": "???",
    "Compression": "6",
    "DateTime": "2024:12:06 18:50:51",
    "DateTimeDigitized": "2024:12:06 18:50:51",
    "DateTimeOriginal": "2024:12:06 18:50:51",
    "ExifVersion": "0220",
    "ExposureBiasValue": "0/1",
    "ExposureMode": "0",
    "ExposureProgram": "0",
    "Flash": "16",
    "FlashpixVersion": "0100",
    "FocalLength": "4730/1000",
    "FocalLengthIn35mmFilm": "0",
    "FNumber": "1.79",
    "ImageLength": "3472",
    "ImageWidth": "4624",
    "InteroperabilityIndex": "R98",
    "JPEGInterchangeFormat": "812",
    "JPEGInterchangeFormatLength": "34979",
    "LightSource": "21",
    "Make": "XXXXXX",
    "MaxApertureValue": "167/100",
    "MeteringMode": "2",
    "Model": "XXXXX",
    "Orientation": "0",
    "PhotographicSensitivity": "125",
    "PixelXDimension": "4624",
    "PixelYDimension": "3472",
    "ResolutionUnit": "2",
    "SceneCaptureType": "0",
    "SceneType": "0",
    "SensingMethod": "0",
    "ShutterSpeedValue": "5058/1000",
    "SubSecTime": "467467",
    "SubSecTimeDigitized": "467467",
    "SubSecTimeOriginal": "467467",
    "WhiteBalance": "0",
    "XResolution": "72/1",
    "YCbCrPositioning": "1",
    "YResolution": "72/1"
  },
  "path": "file:///storage/emulated/0/Android/data/io.ionic.starter/files/Pictures/JPEG_20241206_185045_8653160463096438101.jpg",
  "webPath": "http://192.168.1.7:8100/_capacitor_file_/storage/emulated/0/Android/data/io.ionic.starter/files/Pictures/JPEG_20241206_185045_8653160463096438101.jpg",
  "saved": false
}

In this situation, the autorotate feature was disabled on my phone.

@OS-ricardomoreirasilva
Copy link
Collaborator

So I did a bit more digging into the issue itself and would like to share you with some findings.
Comparing the JSONs you share for both Android and iOS, my initial suspicions were confirmed: the issue is not a difference between Android and iOS but between the different EXIF versions those cameras use (as you can see by the ExifVersion fields, Android is using v0220 and iOS v0232). From what I found, the issue of swapped PixelXDimension and PixelYDimension in portrait pictures with EXIF 0232 compared to EXIF 0220 is likely due to the way EXIF 0232 handles image orientation metadata versus how EXIF 0220 does. Why?

  1. In EXIF 0220, the PixelXDimension and PixelYDimension fields often directly reflect the raw dimensions of the image data as stored in the file. The Orientation tag is included but is sometimes ignored or inconsistently used by older software. However, in EXIF 0232, the Orientation tag is more rigorously utilised, and modern software or devices often adjust metadata accordingly to reflect the image’s intended display orientation.
  2. Consequently, applications reading EXIF 0220 may treat the image as always in landscape mode, regardless of the Orientation tag. This ensures the dimensions remain unaltered. Opposite to this, in EXIF 0232, for portrait images, the Orientation tag specifies that the image should be rotated (e.g., 90° clockwise for portrait mode). Some software adjusts the PixelXDimension and PixelYDimension values to reflect how the image is meant to be displayed, rather than its raw storage orientation.

Considering all this, and regarding that the values are expected from an EXIF perspective, the presented values do make sense and changing them might lead to unexpected issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants