FFImageLoading Plugin - fast and memory friendly image loader (iOS/Android/Forms/Windows)

2

Posts

  • EdBarnesEdBarnes USMember ✭✭

    Hi Daniel,

    I have a iOS solution using FFImageLoading. And for the most part it works great. But I can't seem to get disk caching to work.

    Here is the scenario:

    1. Loading in BING map images via a URL when the device is online.

      ImageService.Instance.LoadUrl(uri, _oneYearTimeSpan)
      .LoadingPlaceholder(Loading3xImageAsset, ImageSource.CompiledResource)
      .ErrorPlaceholder(errorAsset, ImageSource.CompiledResource)
      .Into(imageView);

    2. When the device is taken offline, I am not getting the cached files even though I have enabled it in the configuration. I get the ErrorPlaceholder.

    Configuration config = new Configuration()
    {
    HttpReadTimeout = 10,
    HttpHeadersTimeout = 10,
    DiskCacheDuration = TimeSpan.FromDays(365),

    if DEBUG

                VerboseLogging = true,
                VerbosePerformanceLogging = true,
                VerboseMemoryCacheLogging = true,
                Logger = new ImageServiceLogger()
    

    endif

            };
    

    I am sure I am missing a step (or two) here but I can't find any clear simple example of this working.

    What am I missing?

  • EdBarnesEdBarnes USMember ✭✭

    One note I have added .CacheKey(url) to the above LoadUrl code. Still no dice

  • EdBarnesEdBarnes USMember ✭✭

    I figured this out please ignore.

  • AndyMartin.6838AndyMartin.6838 USMember ✭✭
    edited May 2017

    I am using FFImageLoading with Xamarin.Forms. I am using custom download tokens (in the form of a URI) as the source for my images. The uri will be different every time (even for the same remote image), so I have a custom cache key which works by hashing the BindingContext which is the same for the same remote image. I only want to query my server for a download uri if the cache key is not hit. Essentially, I would like to not have to set the Source parameter unless the custom cache key is not found. I tried using an ImageLoader but got really confused. Could someone please offer me some guidance?

  • AndyMartin.6838AndyMartin.6838 USMember ✭✭
    edited May 2017

    @DanielL I need a way to set the BindingContext, without setting the source, and trigger a call like TryLoadFromCacheAsync that returns a true or false of if that was successful. As it stands I had to implement my own file caching system in order to do something similar to this, which was a lot of extra work.

  • DanielLDanielL PLInsider ✭✭✭✭

    @AndyMartin.6838 It's already possible with this lib. You can just provide your custom implementation for download cache, and that's all. (or override it's methods).

  • Damian_LDamian_L NGMember

    Hi Daniel,

    I have been struggling with something all day and I"m hoping you could perhaps help me out. I have a PCL solution in which I use your plugin. I am trying to get it working on Android. I have added "CachedImageRenderer.Init();" to the activity and I am now creating the cached image as so:

    var cachedImage = new CachedImage()
    {
    HorizontalOptions = LayoutOptions.FillAndExpand,
    VerticalOptions = LayoutOptions.FillAndExpand,
    DownsampleToViewSize = true,
    Transformations = new System.Collections.Generic.List() {
    new ColorSpaceTransformation(FFColorMatrix.BlackAndWhiteColorMatrix)
    },
    Source = "http://loremflickr.com/600/600/nature?filename=simple.jpg"
    };
    My issue is that when I try to get the image created using:

    var cachedimg = await cachedImage.GetImageAsJpgAsync();

    I get an "object not set to an instance..." error. Am I supposed to initialize something else on the Core project? Sorry i'm a bit of a newbie. Could really use the help!

    Background: I am trying to convert an image into black and white. My aim is to create a CachedImage with the source set to the location/stream of the image i want to convert. Then get the transformed image back.

    Thanks!

  • A_SA_S INMember ✭✭

    @DanielL said:
    @Jacob_b

    ImageService.Initialize shouldn't be used multiple times.

    I didn't test it, but my idea is:

    • create a custom http handler which rewrites urls if it detects additional data in string (specified by you).
    • set FFImageLoading to use it with ImageService.Initialize
    • pass additional information in url (handler will parse and handle those info and remove it from url string after that and then call your logic with extracted data)

    Can we create custom loader for AcitvityIndicstor in xamarin forms

  • gdkgdk INMember ✭✭✭

    Hi All, I am strugling to include ffimageloading plugin in to my project. I have install 'FFImageLoading Plugin for xamarin ios/android' nuget package and try to write 'CatchedImageRenderer.Init()' line in main activity contain oncreate() method but it show's error. When I go to that sample they are using assembly references like 'using ffimageloading.forms.android' in main activity but when I write those assembly references in my main activity shows error, I am install ffimageloading package in both android and portable classes. Please suggest what the cause of it. Can you please suggest any idea.

  • DanielLDanielL PLInsider ✭✭✭✭

    @gdk

    • Be sure you have the same nuget package version in all projects
    • Delete all bin / obj folders
    • Close Visual Studio
    • Clean & Rebuild
  • Chr0m1ngChr0m1ng BRMember ✭✭

    Hi @DanielL, can I pass an ftp URL on source to create an image and use on you flowlistview gallery sample? Like, on Source, of each Item, instead of put an normal URL like you did "https://farm8.staticflickr.com/7423/8729135907_79599de8d8.jpg", can I put something like "ftp://user:pass@hostname/Images/SomeImage.jpg"?

  • DanielLDanielL PLInsider ✭✭✭✭

    @Chr0m1ng ftp protocol is not supported.

  • @DanielL
    There is an issue: if downloading image is of zero length, than such task" will never finish -> by default 2 such tasks will block working queue.

  • DanielLDanielL PLInsider ✭✭✭✭

    @SergeyLaschuk It should be fixed in the newest stable (2.2.13)

  • salmankaludisalmankaludi INMember ✭✭
    edited September 2017

    Hi Daniel,

    Unable to load svg file in IOS. It is working fine in android.
    Can you please help on this?

    Thanks
    Salman

  • DanielLDanielL PLInsider ✭✭✭✭

    @salmankaludi

    I won't be able to help you without details or sample project. Could you provide it?

  • salmankaludisalmankaludi INMember ✭✭
    edited September 2017

    Hi Daniel ,

    below is the code snippet

    i am trying to display svg image using SvgCachedImage, but the problem is , it is not working in IOS , but working well in android.
    var topBarRightButton = new SvgCachedImage
    {

                Source ="EQQO.images.heart.svg",
    
                HeightRequest = 40,
                WidthRequest =40,
        VerticalOptions = LayoutOptions.FillAndExpand,
                BackgroundColor = Color.Transparent,
    
        };
    

    Thanks
    Salman

  • DanielLDanielL PLInsider ✭✭✭✭
    edited September 2017

    Still not enough informations.

    If it's a PCL resource, you should probably use resource://EQQO.images.heart.svg
    If not, you're missing that file in a platform specific project.

    Read it here: https://github.com/luberda-molinet/FFImageLoading/wiki/Data-URL-&-Embedded-Resources-support-(including-base64)

    Is EQQO.images.heart.svg resource located in the same assembly as your app? If not you must use resource://{resourceName}?assembly={Uri.EscapeUriString(resourceAssembly.FullName)}" format as described in the wiki page.

  • salmankaludisalmankaludi INMember ✭✭
    edited September 2017

    Hi Daniel ,

    Yes it is an PCL resource
    So i have to specify Source = "resource://EQQO.images.heart.svg" ?

    var topBarRightButton = new SvgCachedImage
    {

            Source ="resource://EQQO.images.heart.svg",
    
            HeightRequest = 40,
            WidthRequest =40,
    VerticalOptions = LayoutOptions.FillAndExpand,
            BackgroundColor = Color.Transparent,
    
    }; 
    

    i have also tried by adding in IOS project also with below code
    var topBarRightButton = new SvgCachedImage
    {

            Source ="heart.svg",
    
            HeightRequest = 40,
            WidthRequest =40,
    VerticalOptions = LayoutOptions.FillAndExpand,
            BackgroundColor = Color.Transparent,
    
    }; 
    

    But both of them didn't work

    Thanks
    Salman

  • salmankaludisalmankaludi INMember ✭✭
    edited September 2017

    Hi Daniel,

    Yes it is an PCL resource

    So i have to set Source ="resource://EQQO.images.heart.svg" ?
    var topBarRightButton = new SvgCachedImage
    {

            Source ="resource://EQQO.images.heart.svg",
    
            HeightRequest = 40,
            WidthRequest =40,
    VerticalOptions = LayoutOptions.FillAndExpand,
            BackgroundColor = Color.Transparent,
    
    };
    

    I have tried with by adding file in IOS with below code, but didn't work
    var topBarRightButton = new SvgCachedImage
    {

            Source ="heart.svg",
    
            HeightRequest = 40,
            WidthRequest =40,
    VerticalOptions = LayoutOptions.FillAndExpand,
            BackgroundColor = Color.Transparent,
    
    };
    

    Thanks
    Salman

  • salmankaludisalmankaludi INMember ✭✭
    edited September 2017

    Hi Daniel,

    By setting Source ="resource://EQQO.images.heart.svg" , it is working in IOS.

    Can you please help me it is possible to change the color of svg file through code ? if yes.
    Can you please provide code snippet?

    Thanks
    Salman

  • DanielLDanielL PLInsider ✭✭✭✭

    You can use ReplaceStringMap property to replace SVG file content, or TintTransformation

    https://github.com/luberda-molinet/FFImageLoading/wiki/SVG-support#svg-string-replacement-including-colors

  • salmankaludisalmankaludi INMember ✭✭

    Thanks Daniel

    Can you provide some code snipper to change color?

  • Can I use SVG as Buttion.Image in Xamarin.Forms with FFImageLoading?
    Thank you in advance!

  • DanielLDanielL PLInsider ✭✭✭✭

    @salmankaludi Just set property which is a Dictionary, keys are parts of svg that need to be replaced, values are destination string

    @AdminAdmin.6078 Yes, just add TapGestureRecognizer to the CachedImage view, you can also add some behaviour to simulate button click effect.

  • KlaasvanSlagerenKlaasvanSlageren NLUniversity

    @DanielL , first of all, great library!

    A question, I have to create a UIImage which is downsampled with a circletransformation with a border of 4

    UIImage image = await ImageService.Instance.LoadUrl(user.ImageUrl) .DownSample(42, 42, false) .Transform(new CircleTransformation(4.0, "#FFFFFF")) .AsPImageAsync();

    However the border seems to be applied before the downsample, so in order to see it on the downsampled image, I have to put in a value around 40.0. How can I apply the border of 4.0 AFTER Downsampling? Am I missing out on something?

    Thanks in advance.

  • KornelisKornelis USMember ✭✭

    Hi,

    this might be quite trivial question but I haven't found a solution by now (neither with Trail & Error nor with Google).

    How do I load an Image from the IsolatedStorage?

    I use the following Code to write some Image Bytes to the User Storage:

    var fileName = "image1.png";
    byte[] data = new byte[0] ; // some image data
    using (var storage = IsolatedStorageFile.GetUserStoreForApplication())
    {
        using (var isf = storage.OpenFile(fileName, FileMode.OpenOrCreate, FileAccess.Write))
        {
            await isf.WriteAsync(data, 0, data.Length);
            isf.Flush();
        }
    }
    

    when I try to load Image like ImageService.Instance.LoadFile("image1.png").Into(imagecontrol);
    I get a file not found exception.

    Does anyone has hint for me how the get the correct image path? Neither the storage nor the isf object contains a Path Property.

    Thanks and Kind Regards

    Kai

  • DanielLDanielL PLInsider ✭✭✭✭

    @KlaasvanSlageren Thanks.

    However the border seems to be applied before the downsample, so in order to see it on the downsampled image, I have to put in a value around 40.0. How can I apply the border of 4.0 AFTER Downsampling? Am I missing out on something?

    Borders are always applied after downsampling, you can't change that, but their sizes should be relative to image size, see this: https://github.com/luberda-molinet/FFImageLoading/blob/master/source/FFImageLoading.Transformations.Touch/RoundedTransformation.cs#L97

    @Kornelis You just need to provide full file path

  • KornelisKornelis USMember ✭✭

    @DanielL said:
    @Kornelis You just need to provide full file path

    Actually this is my problem. How do I get the full file path?
    Haven't found any Method / Property that provides the full file path to a file in the UserStore

  • DanielLDanielL PLInsider ✭✭✭✭

    @Kornelis You'll need to google it.

  • Asaf70Asaf70 ILMember ✭✭

    Hi,
    Is there a way to use GetImageAsPngAsync from ViewModel at SuccessCommand?
    I am using XAML

    Thanks,
    AG

  • EvgeniyCEvgeniyC USMember ✭✭
    edited November 2017

    Is there a way to preload svg image before app start or while app starting? I have svg (40kb) image for background and it appears in 3-4 sec after app started.

    I have tried to use ImageService.Instance.LoadCompiledResource(svg_name_without_extension); for android, but get error System.BadImageFormatException: Bad image format at FFImageLoading.PlatformImageLoaderTask...

    Please help.
    Thanks in advance.

  • DanielLDanielL PLInsider ✭✭✭✭

    @EvgeniyC Yes:

    Eg:

    ImageService.Instance
                .LoadCompiledResource("file.svg") or LoadUrl, etc
                .WithCustomDataResolver(new SvgDataResolver(200, 0, true))
                // .CacheKey("") - sometimes it's useful
                .Preload();
    
  • EvgeniyCEvgeniyC USMember ✭✭

    @DanielL , thanks, error no longer occurs, but image still appears after 2-3 sec. I have this xaml.cs code

        public partial class PageName : ContentPage
        {
            public PageName()
            {
                InitializeComponent();
                var imageFile = "svgname";
                ImageService.Instance.LoadCompiledResource(imageFile).WithCustomDataResolver(new SvgDataResolver(500)).Preload();
            }
        }
    

    And xaml

    <ffilsvg:SvgCachedImage Source="svgname" Aspect="AspectFill"/>

    I suspect I'm using preload in the wrong place. Could you tell me please where should I paste it?
    Thanks.

  • DanielLDanielL PLInsider ✭✭✭✭
    edited November 2017
    • Enable verbose logging to see if memory cache keys of your preload match your other image cache key. Note: 500x size is included in the key!
    • also calling this code in PageName ctr is to late as I suppose this is the page which uses background. put it before your Xamarin.Forms.Init or something similar.
  • EvgeniyCEvgeniyC USMember ✭✭

    @DanielL , I put preload in MainActivity and now task completed before Page constructor fire, but this doesn't help.

        public class MainActivity : Xamarin.Forms.Platform.Android.FormsAppCompatActivity
        {
            protected override void OnCreate(Bundle bundle)
            {
                try
                {
                    TabLayoutResource = Resource.Layout.Tabbar;
                    ToolbarResource = Resource.Layout.Toolbar;
                    CachedImageRenderer.Init();
    
                    var imageTask = ImageService.Instance.LoadCompiledResource("svgname").WithCustomDataResolver(new SvgDataResolver(200, 100, true));
                    imageTask.Error((Exception obj) =>
                    {
                        Console.WriteLine($@"LoadFile Error: {obj}");
                    });
                    imageTask.Success((ImageInformation info, LoadingResult result) =>
                    {
                        Console.WriteLine($@"LoadFile Success: {info} : {result}");
                    });
                    imageTask.PreloadAsync().Wait();
    
                    base.OnCreate(bundle);
                    Xamarin.Forms.Forms.Init(this, bundle);
                    LoadApplication(new App());
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                    throw;
                }
            }
        }
    

    I tried to find info how to enable FFImageLoading logging, but didn't find it. Can you please explain how to enable verbose logging to see if memory cache keys of preload match other image cache key?

  • DanielLDanielL PLInsider ✭✭✭✭
    edited November 2017

    https://github.com/luberda-molinet/FFImageLoading/blob/master/samples/ImageLoading.Forms.Sample/Droid/MainActivity.cs#L29-L37

    Also CachedImage.Success event returns ImageInformation property which contains cachekey property.

  • EvgeniyCEvgeniyC USMember ✭✭

    @DanielL , you are right, cache keys are different

    svgname;(size=200x100,dip=True) //from MainActivity Success
    svgname.svg;(size=0x0,dip=True) //from xaml

    Could you please tell how to fix this?

  • DanielLDanielL PLInsider ✭✭✭✭
    edited November 2017

    var imageTask = ImageService.Instance.LoadCompiledResource("svgname.svg").WithCustomDataResolver(new SvgDataResolver(0, 0, true));

    OR

    set image source of you CachedImage to: SvgImageSource.FromFile("svgname.svg", 200, 100, true)

    OR

    use custom cache key for both CachedImage and Preload

  • EvgeniyCEvgeniyC USMember ✭✭

    @DanielL , now both have cache key svgname.svg;(size=0x0,dip=True), but delay still there. May be this delay cause SkiaSharp have slow rendering of complex svg?

    Here are output logs

    D/mali_winsys(13660): EGLint new_window_surface(egl_winsys_display*, void*, EGLSurface, EGLConfig, egl_winsys_surface**, egl_color_buffer_format*, EGLBoolean) returns 0x3000,  [1440x2960]-format:1
    11-30 16:12:19.571 D/Mono    (13660): DllImport searching in: '__Internal' ('(null)').
    11-30 16:12:19.571 D/Mono    (13660): Searching for 'java_interop_jnienv_call_nonvirtual_float_method_a'.
    11-30 16:12:19.571 D/Mono    (13660): Probing 'java_interop_jnienv_call_nonvirtual_float_method_a'.
    11-30 16:12:19.571 D/Mono    (13660): Found as 'java_interop_jnienv_call_nonvirtual_float_method_a'.
    11-30 16:12:19.579 D/ViewRootImpl@85161fd[SplashActivity](13660): mHardwareRenderer.destroy()#1
    11-30 16:12:19.598 D/ViewRootImpl@85161fd[SplashActivity](13660): Relayout returned: oldFrame=[0,0][1440,2768] newFrame=[0,0][1440,2768] result=0x1 surface={isValid=false 0} surfaceGenerationChanged=false
    11-30 16:12:19.790 D/ViewRootImpl@fc30247[MainActivity](13660): MSG_RESIZED_REPORT: frame=Rect(0, 0 - 1440, 2960) ci=Rect(0, 96 - 0, 192) vi=Rect(0, 96 - 0, 192) or=1
    11-30 16:12:19.790 D/ViewRootImpl@fc30247[MainActivity](13660): MSG_WINDOW_FOCUS_CHANGED 1
    11-30 16:12:19.790 D/ViewRootImpl@fc30247[MainActivity](13660): mHardwareRenderer.initializeIfNeeded()#2 mSurface={isValid=true -1180710912}
    11-30 16:12:19.792 V/InputMethodManager(13660): Starting input: tba=android.view.inputmethod.EditorInfo@6967499 nm : com.kornugle.Kornugle ic=null
    11-30 16:12:19.792 I/InputMethodManager(13660): [IMM] startInputInner - mService.startInputOrWindowGainedFocus
    11-30 16:12:19.849 D/InputTransport(13660): Input channel constructed: fd=78
    11-30 16:12:19.852 D/ViewRootImpl@85161fd[SplashActivity](13660): mHardwareRenderer.destroy()#4
    11-30 16:12:19.852 D/ViewRootImpl@85161fd[SplashActivity](13660): dispatchDetachedFromWindow
    11-30 16:12:19.860 D/InputTransport(13660): Input channel destroyed: fd=64
    11-30 16:12:19.862 I/SemDesktopModeManager(13660): unregisterListener: android.view.ViewRootImpl$3@f5b8e54
    11-30 16:12:19.862 V/InputMethodManager(13660): Starting input: tba=android.view.inputmethod.EditorInfo@cec735e nm : com.kornugle.Kornugle ic=null
    11-30 16:12:23.256 I/art     (13660): Starting a blocking GC Explicit
    11-30 16:12:23.328 I/art     (13660): Explicit concurrent mark sweep GC freed 16453(852KB) AllocSpace objects, 2(75MB) LOS objects, 40% free, 9MB/15MB, paused 453us total 71.164ms
    11-30 16:12:23.329 D/Mono    (13660): GC_TAR_BRIDGE bridges 119 objects 146 opaque 11 colors 119 colors-bridged 119 colors-visible 119 xref 8 cache-hit 0 cache-semihit 0 cache-miss 0 setup 0.16ms tarjan 0.38ms scc-setup 0.15ms gather-xref 0.01ms xref-setup 0.00ms cleanup 0.08ms
    11-30 16:12:23.329 D/Mono    (13660): GC_BRIDGE: Complete, was running for 74.44ms
    11-30 16:12:23.329 D/Mono    (13660): GC_MAJOR: (LOS overflow) time 35.20ms, stw 36.70ms los size: 5128K in use: 4168K
    11-30 16:12:23.329 D/Mono    (13660): GC_MAJOR_SWEEP: major size: 1312K in use: 407K
    11-30 16:12:23.350 D/Mono    (13660): DllImport searching in: 'libSkiaSharp.so' ('libSkiaSharp.so').
    11-30 16:12:23.350 D/Mono    (13660): Searching for 'sk_picture_unref'.
    11-30 16:12:23.350 D/Mono    (13660): Probing 'sk_picture_unref'.
    11-30 16:12:23.351 D/Mono    (13660): Found as 'sk_picture_unref'.
    
2
Sign In or Register to comment.