Episodex
Episodex

Reputation: 4559

Set Image.Source to file in external storage in Xamarin.Forms

I have a picture of item in external storage (that was saved by intent in my app). I want to display this picture in Image view in my shared project.

Image.Source takes object of ImageSource type. I tried ImageSource.FromFile, ImageSource.FromStream and even ImageSource.FromUri. The result is always that image is not displayed (no error or exception). I validated that the path to file is correct by first opening it with File.Open one line above.

What is the correct way of displaying pictures from normal storage, not from assets/resources/etc?

This code does not work:

var path = "/storage/emulated/0/Pictures/6afbd8c6-bb1e-49d3-838c-0fa809e97cf1.jpg" //in real app the path is taken from DB
var image = new Image() {Aspect = Aspect.AspectFit, WidthRequest = 200, HeightRequest = 200};
image.Source = ImageSource.FromFile(path);

Upvotes: 5

Views: 10199

Answers (1)

jzeferino
jzeferino

Reputation: 7840

Your Xamarin Forms PCL don't know what its a URI from Android beacuse its platform specific, so:

ImageSource.FromFile(path);

won't work.

In that case you are handling platform specific features, that is loading an image from Android. I suggest this approach:

Create an interface on Xamarin Forms PCL like:

public interface IPhoto
{
    Task<Stream> GetPhoto ();
}

Then in Android you implement that interface and register the implementation in DependencyService:

[assembly: Xamarin.Forms.Dependency(typeof(PhotoImplementation))]
    namespace xpto
    {
        public class PhotoImplementation : Java.Lang.Object, IPhoto
        {
            public async Task<Stream> GetPhoto()
            {
                // Open the photo and put it in a Stream to return       
                var memoryStream = new MemoryStream();

                using (var source = System.IO.File.OpenRead(path))
                {
                    await source.CopyToAsync(memoryStream);
                }

                return memoryStream;
            }
        }
    }

In the Xamarin Forms PCL code get the image:

var image = ImageSource.FromStream ( () => await DependencyService.Get<IPhoto>().GetPhoto());

For more detail you can consult this.

NOTE1: This will work on iOS if you implement the interface IPhoto too.

NOTE2: There exist a helpful library for this kind of features from Xamarin-Forms-Labs called Camera.


UPDATE (Shared Project solution)

As requested in the comments, to use this in a Shared Project instead of PCL we could do this.

1 - Place the IPhotoInterface in the Shared Project.

2 - Implement the interface in Android/iOS project:

public class PhotoImplementation : IPhoto
{
    public async Task<Stream> GetPhoto()
    {
        // Open the photo and put it in a Stream to return. 
    }
}

3 - Use it in the Shared Project:

IPhoto iPhotoImplementation;

#if __ANDROID__
iPhotoImplementation = new shared_native.Droid.GetPicture();

#elif __IOS__
iPhotoImplementation = new shared_native.iOS.GetPicture();

#endif

var image = ImageSource.FromStream ( () => await iPhotoImplementation.GetPhoto());

NOTE: shared_native is the namespace of my solution and Droid/iOS are the projects for Android and iOS.

Upvotes: 5

Related Questions