XamarinCommunityToolkit: [Bug] [CameraView] [Android] Taken photos are rotated incorrectly
Description
When taking a photo with CameraView on Android, photos are rotated incorrectly.
Previously reported in #297, #751, #779. PRs #307, #886 claim to fix this but they don’t.
Stack Trace
Link to Reproduction Sample
Steps to Reproduce
Confirmed on Pixel 3a XL Android 12 and Xiaomi Redmi 3s Android 6.0.
-
Open the attached project and run.
-
Press the Capture button which invokes the
Shutter()method:
- The app saves the captured image data into a new file and sets that file as a source of the
ImageView(right below the camera view):
Expected Behavior
ImageData of MediaCapturedEventArgs contains a JPEG image with correct orientation applied.
Actual Behavior
ImageData is an incorrectly rotated JPEG and additional manual transformations are required.
Basic Information
- Version with issue: 1.3.0-pre2
- Last known good version: None
- IDE:
- Platform Target Frameworks:
- iOS:
- Android:
- UWP:
- Android Support Library Version:
- Nuget Packages:
- Affected Devices: Pixel 3a XL (Android 12), Xiaomi Redmi 3s (Android 6)
Workaround
A workaround is to use ImageSharp where you can manually rotate the image according to MediaCapturedEventArgs.Rotation property. It works pathetically slow though.
public static class MediaCapturedEventArgsExtensions
{
public static byte[] GetRotatedData(this MediaCapturedEventArgs self)
=> TransformOrientation(self.ImageData, self.Rotation);
private static byte[] TransformOrientation(byte[] imageInBytes, double rotation)
{
using var image = Image.Load(imageInBytes, out IImageFormat imageFormat);
RotateMode mode = rotation switch
{
90d => RotateMode.Rotate90,
180d => RotateMode.Rotate180,
270d => RotateMode.Rotate270,
_ => RotateMode.None,
};
image.Mutate(x => x.Rotate(mode));
return ImageToByteArray(image, imageFormat);
}
private static byte[] ImageToByteArray(Image image, IImageFormat imageFormat)
{
using var ms = new MemoryStream();
image.Save(ms, imageFormat);
return ms.ToArray();
}
}
Reproduction imagery
About this issue
- Original URL
- State: open
- Created 3 years ago
- Comments: 18 (5 by maintainers)
Hey everyone! Thank you for your patience here! Would you maybe be able to test version 2.1.0-build-64069.1871 from this NuGet feed: https://pkgs.dev.azure.com/xamarin/public/_packaging/XamarinCommunityToolkit-PullRequests/nuget/v3/index.json
That is the result of a PR I just made to fix this rotation thing. Let me know if this works!
Yep that’s what my workaround does, but the question is why would you have to to deal with additional properties at all? Isn’t it the library’s job to generate a properly rotated image so developers wouldn’t have to copy-paste the same workaround? I guess rotating the whole image might be quite time-consuming, but writing the EXIF data works rather quickly. BTW it seems it’s been planned at some point but left as a to-do:
https://github.com/xamarin/XamarinCommunityToolkit/blob/02884f5db0bb3169be37647744a32a3784f46c7f/src/CommunityToolkit/Xamarin.CommunityToolkit/Views/CameraView/Android/CameraFragment.android.cs#L380-L388
It certainly can be treated as the following behavior change: make the CameraView behave on Android just like it does on iOS, because the described issue does not happen on iOS. However, the image has to be stored as a file in order to use AndroidX ExifInterface, so
CameraView.SavePhotoToFilemight have to be implemented first.@pictos @bijington could you please add
CameraViewlabel to this issue? ThanksA better workaround is to write EXIF data into the image using AndroidX ExifInterface: