Shared ImageSource

Hello there,

I'm working on some kind of app that displays same images in single view. I'm using ImageSource.FromResource("resourceId") to load bitmap from resources:

var source = ImageSource.FromResource("img");

var img1 = new Image { Source = source };
var img2 = new Image { Source = source };

It seems that doesn't work. Is there any way to share same bitmap between many Image instances?

Best Answers

Answers

  • AndrewMobileAndrewMobile USMember ✭✭✭✭
    edited June 2015

    You must have an issue with the way you load the image.
    If you use FromResource then the filename must include the assembly name and extension, i.e. ImageSource.FromResource("MyApp.img.png");
    and the 'img.png' must have BuildAction = EmbeddedResource

    See http://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/images/

    If you still have issues, do a Rebuild on the assembly.

    I hope this helps you

  • In my case, loading images from resources works fine. An issue is that: every time when i create a new Image with the same ImageSource I can see a lazy async loading process. It's looks like there is no internal caching/sharing for bitmaps in Image class.

    I would like to cache collection of ImageSource and then display many Images based on that (to avoid lazy resource loading process) .

  • AndrewMobileAndrewMobile USMember ✭✭✭✭
    edited June 2015

    hope this helps

  • ylemsoulylemsoul RUMember ✭✭✭
    edited June 2015

    @MateuszMajchrzak, try this one (put this class in PCL project):
    `public static class ImageSourceEx
    {
    private static readonly Dictionary<string, WeakReference< ImageSource >> ImageSourceWrCache = new Dictionary<string, WeakReference< ImageSource >>();

    public static ImageSource FromResource(string resource)
    {
        ImageSource imageSource;
        WeakReference<ImageSource> imageSourceWr;
    
        if (!ImageSourceWrCache.TryGetValue(resource, out imageSourceWr) ||
            !imageSourceWr.TryGetTarget(out imageSource))
        {
            var imgArrayLazyTask = new Lazy<Task<byte[]>>(
                async () =>
                {
                    var assembly = typeof(ImageSourceEx).GetTypeInfo().Assembly;
    
                    using (var inputStream = assembly.GetManifestResourceStream(resource))
                    using (var outputStream = new MemoryStream())
                    {
                        await inputStream.CopyToAsync(outputStream);
                        return outputStream.ToArray();
                    }
                },
                isThreadSafe: true);
    
            imageSource = new StreamImageSource() { Stream = async _ => new MemoryStream(await imgArrayLazyTask.Value) };
            ImageSourceWrCache[resource] = new WeakReference<ImageSource>(imageSource);
        }
    
        return imageSource;
    }
    

    }`

    You don't need cache ImageSource's object. As long as you have same resource key you'll get the same ImageSource

  • JassimRahmaJassimRahma USMember ✭✭✭✭

    How can I convert the other way? from FFImageLoading's Source to Stream?

    **Here is my ViewModel:
    **

    public class ImageViewModel : INotifyPropertyChanged
    {
        private ImageSource image;
        public ImageSource Image
        {
            get { return image; }
            set
            {
                image = value;
    
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("Image"));
                }
            }
        }
    
        private string imageStream;
    
        public string ImageStream
        {
            get { return imageStream; }
            set
            {
                imageStream = value;
    
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("ImageStream"));
                }
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    }
    

    and this is what I want to pass:

    viewModel.Image = ImageSource.FromStream(() =>
    {
        // var stream = IMAGE.SOURCE.GETSTREAM();
        return stream;
    });
    
Sign In or Register to comment.