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;
}
CodePudding user response:
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);
...
}
}