androidiosimagemauiandroid-gallery

How to fetch images from gallery in CollectionView iOS 16 and Android 33 in NET MAUI?


I have a question regarding the possibility of fetching photos from the gallery for both iOS and Android and displaying them in a CollectionView. I dont want to use the FIle Picker or Media picker that gives the user the ability to select and pick the photos I want to load them directly. From what I have researched online targeting Android 30+ makes it almost impossible to do so. I am not even sure how to even start when tackling this task, whenver I try to acces Environment.GetExternalDirectories I get a storage permission error stating I dont have access to it, but I have granted both read and write permissions in the manifest file and checked if they are granted. In terms of Ios I am not sure how to access the native paths to the gallery or in general how to tackle it. Any ideas would be really appreciated. Furthermore I would have to implement a gallery watcher to track when new images are added.

 var path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures).AbsolutePath;
            try
            {
                string[] files = Directory.GetFiles(path);
                
                foreach (var file in files)
                {
                    try
                    {
                        var image = new Image
                        {
                            Source = ImageSource.FromFile(file)
                        };

                        var media = new MediaAsset
                        {
                            Path = file
                        };
                        MediaAssets.Add(media);
                    }
                    catch (Exception e)
                    {
                        // remove this if you don't want to see the exception message
                        continue;
                    }
                }
            }
            catch (Exception)
            {

                return;
            }


Solution

  • you wrote a comment on one of my posts, it got deleted so i'll just answer you here :

    I only did it on Android, but i guess it'll be similar for IOS, so i used the same Plateform specific code that you'll use in Xamarin.Forms

    you get the path of the Image via [Android.App.Application.Context.ContentResolver.Query], then you load the image or thumbnail into a MemoryStream, wich you'll use to create an ImageSource that you return via an interface to your main code to display in an Image viewer

    it worked, but i remember i had some problems with MAUI stability (don't remember what they were) that led me to just get back to Xamarin.Forms ..

    This is what i used for the Picture/Thumbnail via the path :

        public async Task<MemoryStream> LoadThumbnail(string Path, int SizeX, int SizeY) {
            var mem = new MemoryStream();
            var bmp = Android.App.Application.Context.ContentResolver.LoadThumbnail(Android.Net.Uri.Parse(Path), new Android.Util.Size(SizeX, SizeY), null);
            bmp.Compress(Android.Graphics.Bitmap.CompressFormat.Jpeg, 100, mem); bmp.Recycle();
            mem.Seek(0, SeekOrigin.Begin);
            return mem;
        }
    
        public async Task<MemoryStream> LoadPicture(string Path) {
            var mem = new MemoryStream();
            Android.App.Application.Context.ContentResolver.OpenInputStream(Android.Net.Uri.Parse(Path)).CopyTo(mem);
            mem.Seek(0, SeekOrigin.Begin);
            return mem;
        }
    

    then you use something like this : ImageSource.FromStream(() => Stream); to get the imageSource

    PS : (just to help you in future problems, when you use an ImageSource from stream, each time you load it the stream get's closed, and that's why it uses a lambda instead of a direct value, it's so that you can reload the stream)

    Edit : so this is how you get gallery paths :

    var uriExternal = MediaStore.Images.Media.ExternalContentUri; //Since Android 12
    
    string[] projection = { (MediaStore.Images.Media.InterfaceConsts.Id), (MediaStore.Images.Media.InterfaceConsts.DateAdded), (MediaStore.Images.Media.InterfaceConsts.RelativePath) };
    var cursor = Android.App.Application.Context.ContentResolver.Query(uriExternal, projection, null, null, MediaStore.Images.Media.InterfaceConsts.DateAdded);
    
    
    if (cursor != null) {
        int columnIndexID = cursor.GetColumnIndexOrThrow(MediaStore.Images.Media.InterfaceConsts.Id);
        int RelativePathID = cursor.GetColumnIndexOrThrow(MediaStore.Images.Media.InterfaceConsts.RelativePath);
        
        
        while (cursor.MoveToNext()) {
    
            //This is the image path on the Device
            string RelativePath = cursor.GetString(RelativePathID); 
            
            //This is the path you'll use to load the Image
            string ExternalSrcPath = uriExternal + "/" + cursor.GetLong(columnIndexID); 
            
            ...
    
        }
    }