dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.21k stars 1.75k forks source link

MediaPicker: Massive file size difference between "capturing" and "picking" an image in iOS #8251

Open rlasker-b2w opened 2 years ago

rlasker-b2w commented 2 years ago

Description

This problem is discovered in Xamarin Essentials but after tracing the problem down to the code level it appears the same issue is in the Maui version.

When using the Media Picker in iOS you have two options to either pick the image from the library or "capturing" the image directly from the camera. The difference in the file sizes of those images are by order of magnitudes of 5 or more. Using a test project I created if I take a picture and "pick" it I get a file size of 4.97 MB but if I "capture" the same image it is 24.8 MB. In Android, picking or capturing an image produces no discernible difference in file size.

Sample Project: https://github.com/rlasker-b2w/XamEssMediaPicker.git

I traced the issue to the FileSystem class that always calls the AsPNG when calling OpenReadAsync:

Xamarin Essentials: https://github.com/xamarin/Essentials/blob/e054b7e19b7fb8f1787af41c95ce4447660422ed/Xamarin.Essentials/FileSystem/FileSystem.ios.cs#L195

Maui Essentials: https://github.com/dotnet/maui/blob/0b6976ebd250ffc1669225951e40976e966d46e1/src/Essentials/src/FileSystem/FileSystem.ios.cs#L195

I couldn't find a way to reduce the size through Essentials. Reducing the file size required platform specific code passing the byte data:

public override byte[] GetPhotoContent(byte[] data)
{
  if (data == null)
    throw new ArgumentNullException(nameof(data), "Get photo content data cannot be null.");

  ObjCRuntime.Class.ThrowOnInitFailure = false;
  return UIImage.LoadFromData(NSData.FromArray(data))?.AsJPEG(0.5f)?.ToArray() ??
    throw new Exception("Unable to convert and compress photo data");
}

Steps to Reproduce

  1. add media picker to a project
  2. run in iOS
  3. measure the file size of between capture and pick options
  4. or run sample project

Version with bug

6.0.400 (current)

Last version that worked well

Unknown/Other

Affected platforms

iOS

Affected platform versions

All

Did you find any workaround?

public override byte[] GetPhotoContent(byte[] data)
{
  if (data == null)
    throw new ArgumentNullException(nameof(data), "Get photo content data cannot be null.");

  ObjCRuntime.Class.ThrowOnInitFailure = false;
  return UIImage.LoadFromData(NSData.FromArray(data))?.AsJPEG(0.5f)?.ToArray() ??
    throw new Exception("Unable to convert and compress photo data");
}

Relevant log output

No response

cdavidyoung commented 1 year ago

I am experiencing the same thing. The iPhone camera returns a huge file compared to the Android. In looking at the MediaPickerOptions there is no option for compression. Likewise, there is no option to copy the image to the gallery. Hopefully these options are in the works!

cdavidyoung commented 1 year ago

I just did a test taking a single photo with my app with the following results: Mac and Windows < 500K Android - 2M iPhone - 16M

BTW, I am using CustomMediaPicker : IMediaPicker with the MediaPicker.Default.CapturePhotoAsync(MediaPickerOptions options) for all platforms except Windows, which uses native controls. In the MediaPickerOptions the only option available right now is Title. We need compression and copy to gallery to be very useful. Thanks.

Kalyxt commented 1 year ago

Is there some compression toolkit available for MAUI ?

homeyf commented 1 year ago

Verified this issue with Visual Studio Enterprise 17.7.0 Preview 6.0. Can repro on iOS platform with sample project. sample project image

dotMorten commented 4 months ago

I'm assuming it's because it for some reason returns PNG:

https://github.com/dotnet/maui/blob/372c66ce0107599fe2b9f804492d91e3f99a3d1b/src/Essentials/src/FileSystem/FileSystem.ios.cs#L194-L198

That's a pretty bad format for photos. Should be JPEG or HEIC. I would also suggest to expose the UIImage that is returned, so we can choose how we want to work with it, or compress it however we want.

cvchris commented 2 months ago

Any updates on this? The package https://github.com/jamesmontemagno/MediaPlugin is deprecated and points to MediaPicker which doesn't implement compression functionality