Search code examples
xamarinxamarin.formsfilepickerxamarin-essentials

Xamarin FilePicker ImageSource


I have an application that the user can add photos through the gallery using the FilePicker.PickMultipleAsync. And also user can take a picture this functionality is using CrossMedia plugin.

If the user takes a photo (CrossMedia) in portrait format, the photo is converted into ImageSource to be displayed. If the user selects the images, it does the same conversion process to ImageSource, but in this case the photos are automatically rotated to the right.

This happens with photos that were taken by the camera's native app. If the user downloads any image and selects it from the gallery, the problem does not happen. The problem started after switching the plugin to FilePicker.

What can I do to display the original image?

Versions: Xamarin.Forms: 5.0.0.2401 Xamarin.Essentials: 1.7.3

Code of the plugin

var result = await FilePicker.PickMultipleAsync(new PickOptions
{
    PickerTitle = "Choose Images",
    FileTypes = FilePickerFileType.Images
});

if (result != null)
{
    foreach (var item in result)
    {
        AttachedFiles.Add(new AttachmentFiles(item));
    }
}

public AttachmentFiles(FileResult imgSource)
{
    var imageAsBytes = ImageHelper.ConvertStreamToByteArray(Task.Run(async () => await imgSource.OpenReadAsync()).Result);
    var resizer = DependencyService.Get<IImageResize>();

    this.ImageId = Guid.NewGuid();
    this.Source = ImageSource.FromStream(() => new MemoryStream(imageAsBytes));
    this.SourceT = ImageSource.FromStream(() => new MemoryStream(resizer.ResizeImage(imageAsBytes, 70, 70)));
}

enter image description here

The image on the left I downloaded from the internet and it appears correctly. The image on the right I took by the camera and chose from the gallery


Solution

  • I solved this problem with code

     public class PhotoPickerService : IPhotoPickerService
        {
            public async Task<byte[]> ImageToArrayAsync(string path)
            {
                try
                {
                    var exif = new Android.Media.ExifInterface(path);
                    string orientation = exif.GetAttribute(Android.Media.ExifInterface.TagOrientation);
    
                    //Get the bitmap.
                    var originalImage = BitmapFactory.DecodeFile(path);
    
                    //Set imageSize and imageCompression parameters.
                    var imageSize = .40;
                    var imageCompression = 45;
    
                    //Resize it and then compress it to Jpeg.
                    var width = originalImage.Width * imageSize;
                    var height = originalImage.Height * imageSize;
                    var scaledImage = Bitmap.CreateScaledBitmap(originalImage, (int)width, (int)height, true);
    
                    var matrix = new Matrix();
    
                    switch (orientation)
                    {
                        case "1": // landscape
                            break;
                        case "3":
                            matrix.PreRotate(180);
                            scaledImage = Bitmap.CreateBitmap(scaledImage, 0, 0, scaledImage.Width, scaledImage.Height, matrix, true);
                            matrix.Dispose();
                            matrix = null;
                            break;
                        case "4":
                            matrix.PreRotate(180);
                            scaledImage = Bitmap.CreateBitmap(scaledImage, 0, 0, scaledImage.Width, scaledImage.Height, matrix, true);
                            matrix.Dispose();
                            matrix = null;
                            break;
                        case "5":
                            matrix.PreRotate(90);
                            scaledImage = Bitmap.CreateBitmap(scaledImage, 0, 0, scaledImage.Width, scaledImage.Height, matrix, true);
                            matrix.Dispose();
                            matrix = null;
                            break;
                        case "6": // portrait
                            matrix.PreRotate(90);
                            scaledImage = Bitmap.CreateBitmap(scaledImage, 0, 0, scaledImage.Width, scaledImage.Height, matrix, true);
                            matrix.Dispose();
                            matrix = null;
                            break;
                        case "7":
                            matrix.PreRotate(-90);
                            scaledImage = Bitmap.CreateBitmap(scaledImage, 0, 0, scaledImage.Width, scaledImage.Height, matrix, true);
                            matrix.Dispose();
                            matrix = null;
                            break;
                        case "8":
                            matrix.PreRotate(-90);
                            scaledImage = Bitmap.CreateBitmap(scaledImage, 0, 0, scaledImage.Width, scaledImage.Height, matrix, true);
                            matrix.Dispose();
                            matrix = null;
                            break;
                    }
    
                    byte[] imageBytes;
    
                    using (MemoryStream ms = new MemoryStream())
                    {
                        scaledImage.Compress(Bitmap.CompressFormat.Jpeg, imageCompression, ms);
                        imageBytes = ms.ToArray();
                        await File.WriteAllBytesAsync(path, imageBytes);
                    }
    
                    originalImage.Recycle();
                    scaledImage.Recycle();
                    originalImage.Dispose();
                    scaledImage.Dispose();
    
                    return imageBytes;
                }
    
                catch (IOException ex)
                {
                    _ = ex.Message;
                    return null;
                }
            }
        }
    

    Source: https://github.com/xamarin/Essentials/issues/1514#issuecomment-922233449