1

I have the following code to open gallery.

var imageIntent = new Intent(
Intent.ActionPick);
imageIntent.SetType("image/*");
mageIntent.PutExtra(Intent.ExtraAllowMultiple, true);
imageIntent.SetAction(Intent.ActionGetContent);
StartActivityForResult(
Intent.CreateChooser(imageIntent, "Select photo"), 1);

And I stuck at the following code which is the OnActivityResult in my MainActivity.cs

protected override void OnActivityResult(int requestCode, Android.App.Result resultCode, Intent data)
    {
        base.OnActivityResult(requestCode, resultCode, data);

        if((requestCode==1)&&(resultCode==Result.Ok))
        {
            if(data!=null)
            {
                ClipData clipData = data.ClipData;
                if(clipData!=null)
                {
                    for (int i = 0; i < clipData.ItemCount; i++)
                    {
                        ClipData.Item item = clipData.GetItemAt(i);
                        Android.Net.Uri selectedImage = item.Uri;

                        //How to convert Android.Net.Uri to a image file?


                    }
                }
            }
        }
    }

The Android.Net.Uri is something that I never seen before, the path is just like content/android/document/documents/31857. Yes, I can select multiple photo from the gallery, but I just don't know how to convert Android.Net.Uri to an legal image file? My final goal is to save the selected image to my desired file path like storage/emulated/0... Or is there any better way to select multiple images and save to the desired file? Thank you.

Sheng Jie
  • 141
  • 2
  • 12
  • You dont have to convert that content scheme to a classic file path. Use it as it is. If you had file path you would open a FileInputStream on it and read from it. Now open an InputStream like InputStream is = getContentResolver().openInputStream(uri); and read from the stream just like you always did. – blackapps Jan 22 '20 at 10:18
  • `My final goal is to save the selected image to my desired file path` No. What you want is just copying files. – blackapps Jan 22 '20 at 10:19
  • Have you checked this out? https://medium.com/swlh/select-multiple-images-from-the-gallery-in-xamarin-forms-df2e037be572 – FreakyAli Jan 22 '20 at 10:24

2 Answers2

0

You could use Dependency Service

Creating the interface in forms

namespace xxx
{
    public interface IPhotoPickerService
    {
        Task<Dictionary<string,Stream>> GetImageStreamAsync();
    }
}

in iOS

[assembly: Dependency (typeof (PhotoPickerService))]
namespace xxx.iOS
{
    public class PhotoPickerService : IPhotoPickerService
    {
        TaskCompletionSource<Dictionary<string, Stream>> taskCompletionSource;
        UIImagePickerController imagePicker;

        Task<Dictionary<string, Stream>> IPhotoPickerService.GetImageStreamAsync()
        {
            // Create and define UIImagePickerController
            imagePicker = new UIImagePickerController
            {
                SourceType = UIImagePickerControllerSourceType.PhotoLibrary,
                MediaTypes = UIImagePickerController.AvailableMediaTypes(UIImagePickerControllerSourceType.PhotoLibrary)
            };

            // Set event handlers
            imagePicker.FinishedPickingMedia += OnImagePickerFinishedPickingMedia;
            imagePicker.Canceled += OnImagePickerCancelled;

            // Present UIImagePickerController;
            UIWindow window = UIApplication.SharedApplication.KeyWindow;
            var viewController = window.RootViewController;
            viewController.PresentModalViewController(imagePicker, true);

            // Return Task object
            taskCompletionSource = new TaskCompletionSource<Dictionary<string, Stream>>();
            return taskCompletionSource.Task;
        }

       

        void OnImagePickerFinishedPickingMedia(object sender, UIImagePickerMediaPickedEventArgs args)
        {
            UIImage image = args.EditedImage ?? args.OriginalImage;

            if (image != null)
            {
                // Convert UIImage to .NET Stream object
                NSData data;
                if (args.ReferenceUrl.PathExtension.Equals("PNG") || args.ReferenceUrl.PathExtension.Equals("png"))
                {
                    data = image.AsPNG();
                }
                else
                {
                    data = image.AsJPEG(1);
                }
                Stream stream = data.AsStream();

                UnregisterEventHandlers();

                Dictionary<string, Stream> dic = new Dictionary<string, Stream>();
                dic.Add(args.ImageUrl.ToString(), stream);

                // Set the Stream as the completion of the Task
                taskCompletionSource.SetResult(dic);
            }
            else
            {
                UnregisterEventHandlers();
                taskCompletionSource.SetResult(null);
            }
            imagePicker.DismissModalViewController(true);
        }

        void OnImagePickerCancelled(object sender, EventArgs args)
        {
            UnregisterEventHandlers();
            taskCompletionSource.SetResult(null);
            imagePicker.DismissModalViewController(true);
        }

        void UnregisterEventHandlers()
        {
            imagePicker.FinishedPickingMedia -= OnImagePickerFinishedPickingMedia;
            imagePicker.Canceled -= OnImagePickerCancelled;
        }

        
    }
}

in Android

in MainActivity

public class MainActivity : FormsAppCompatActivity
{
    ...
    // Field, property, and method for Picture Picker
    public static readonly int PickImageId = 1000;

    public TaskCompletionSource<Dictionary<string,Stream>> PickImageTaskCompletionSource { set; get; }

    protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)
    {
        base.OnActivityResult(requestCode, resultCode, intent);

        if (requestCode == PickImageId)
        {
            if ((resultCode == Result.Ok) && (intent != null))
            {
                Android.Net.Uri uri = intent.Data;
                Stream stream = ContentResolver.OpenInputStream(uri);

                Dictionary<string, Stream> dic = new Dictionary<string, Stream>();
                dic.Add(uri.ToString(), stream);
                // Set the Stream as the completion of the Task
                PickImageTaskCompletionSource.SetResult(dic);
            }
            else
            {
                PickImageTaskCompletionSource.SetResult(null);
            }
        }
    }
}
[assembly: Dependency(typeof(PhotoPickerService))]
namespace xxx.Droid
{
    public class PhotoPickerService : IPhotoPickerService
    {
        public Task<Dictionary<string,Stream>> GetImageStreamAsync()
        {
            // Define the Intent for getting images
            Intent intent = new Intent();
            intent.SetType("image/*");
            intent.SetAction(Intent.ActionGetContent);

            // Start the picture-picker activity (resumes in MainActivity.cs)
            MainActivity.Instance.StartActivityForResult(
                Intent.CreateChooser(intent, "Select Picture"),
                MainActivity.PickImageId);

            // Save the TaskCompletionSource object as a MainActivity property
            MainActivity.Instance.PickImageTaskCompletionSource = new TaskCompletionSource<Dictionary<string,Stream>>();

            // Return Task object
            return MainActivity.Instance.PickImageTaskCompletionSource.Task;
        }
    }
}

invoke it

Dictionary<string, Stream> dic = await DependencyService.Get<IPhotoPickerService>().GetImageStreamAsync();

Stream stream;
string path;

foreach ( KeyValuePair<string, Stream> currentImage in dic )
{
   stream = currentImage.Value;

   // save it    

}
Community
  • 1
  • 1
Lucas Zhang
  • 17,851
  • 3
  • 9
  • 20
0

thanks for you help. Below is my final solution for those who need help.

private string GetPathToImage(Android.Net.Uri uri)
    {
        string doc_id = "";
        using (var c1 = ContentResolver.Query(uri, null, null, null, null))
        {
            c1.MoveToFirst();
            string document_id = c1.GetString(0);
            doc_id = document_id.Substring(document_id.LastIndexOf(":") + 1);
        }

        string path = null;

        // The projection contains the columns we want to return in our query.
        string selection = Android.Provider.MediaStore.Images.Media.InterfaceConsts.Id + " =? ";
        using (var cursor = ContentResolver.Query(Android.Provider.MediaStore.Images.Media.ExternalContentUri, null, selection, new string[] { doc_id }, null))
        {
            if (cursor == null) return path;
            var columnIndex = cursor.GetColumnIndexOrThrow(Android.Provider.MediaStore.Images.Media.InterfaceConsts.Data);
            cursor.MoveToFirst();
            path = cursor.GetString(columnIndex);
        }
        return path;
    }

After that you can do whatever you want, cheers! Taken from:Get Path of Gallery Image Xamarin?

Sheng Jie
  • 141
  • 2
  • 12