Microsoft.Maui.Graphics icon indicating copy to clipboard operation
Microsoft.Maui.Graphics copied to clipboard

IImageLoadingService cannot load image on Windows

Open janseris opened this issue 3 years ago • 10 comments

Description

What I was trying to achieve:

  • resize an image selected from PC using MAUI on Windows

Result:

  • I didn't get past loading the file as IImage

Sample application:

MauiApp2 Android IImage resized image disposed exception.zip (yes, the same as for https://github.com/dotnet/maui/issues/6909)

Description

Any attempt to load an image using IImageLoadingService on Windows results in this code being called: image

"No resource creator has been registered globally or for this thread."

Exception thrown: 'System.Exception' in Microsoft.Maui.Graphics.Win2D.WinUI.Desktop.dll
An exception of type 'System.Exception' occurred in Microsoft.Maui.Graphics.Win2D.WinUI.Desktop.dll but was not handled in user code
No resource creator has been registered globally or for this thread.

How I am calling it:

image

imageLoadingService.FromStream which is Microsoft.Maui.Graphics.Win2D.SkiaImageLoadingService which is the only IImageLoadingService implementation which works for me for Windows (during compile-time).

Win2DImage cannot be called directly because it is an internal class.

What I am doing in MauiProgram.cs:

#if WINDOWS
            services.AddSingleton<IImageLoadingService, Microsoft.Maui.Graphics.Win2D.SkiaImageLoadingService>();
#endif
#if ANDROID
            services.AddSingleton<IImageLoadingService, Microsoft.Maui.Graphics.Platform.PlatformImageLoadingService>();
#endif

Steps to Reproduce

Inject Microsoft.Maui.Graphics.Win2D.SkiaImageLoadingService for IImageLoadingService on Windows and try creating an IImage from file/stream with it.

Version with bug

Release Candidate 2 (current)

Last version that worked well

Unknown/Other

Affected platforms

Windows

Affected platform versions

I don't know.

Did you find any workaround?

No response

Relevant log output

No response

janseris avatar May 06 '22 22:05 janseris

Verified repro on VS 17.3.0 Preview 1.0 [32427.505.main]. Repro project: MauiApp2.Android.IImage.resized.image.disposed.exception.zip

v-longmin avatar May 07 '22 01:05 v-longmin

Are there any workarounds possible for this? Perhaps an alternative implementation of IImage for windows that would just get me to a point where I can display an image on a GraphicsView?

limefrogyank avatar May 25 '22 19:05 limefrogyank

@limefrogyank tag some MAUI people to receive any info on this

janseris avatar May 25 '22 20:05 janseris

I found a workaround. Put a dummy GraphicsView on the page somewhere where it loads first and handle the Loaded event with this:

private void dummy_Loaded(object sender, EventArgs e)
    {
#if WINDOWS
        Assembly assembly = typeof(Microsoft.Maui.Graphics.Win2D.W2DCanvas).Assembly;
        var type = assembly.GetType("Microsoft.Maui.Graphics.Win2D.W2DGraphicsService");
        var prop = type.GetProperty("GlobalCreator");

        var graphicsView = (GraphicsView)sender;
        var view = (Microsoft.Maui.Platform.PlatformTouchGraphicsView)graphicsView.Handler.PlatformView;
        var view2 = (Microsoft.Maui.Graphics.Win2D.W2DGraphicsView)view.Content;
        prop.SetValue(null, view2.Content);
#endif

    }

I actually get a COM error the first time I try to load an image, but after the first one (handled via try...catch) it works fine. All of the images load. Maybe there's a timing issue still, but it works for me... at least to get to the next stage of working on my app.

limefrogyank avatar May 26 '22 20:05 limefrogyank

I found a workaround. Put a dummy GraphicsView on the page somewhere where it loads first and handle the Loaded event with this:

private void dummy_Loaded(object sender, EventArgs e)
    {
#if WINDOWS
        Assembly assembly = typeof(Microsoft.Maui.Graphics.Win2D.W2DCanvas).Assembly;
        var type = assembly.GetType("Microsoft.Maui.Graphics.Win2D.W2DGraphicsService");
        var prop = type.GetProperty("GlobalCreator");

        var graphicsView = (GraphicsView)sender;
        var view = (Microsoft.Maui.Platform.PlatformTouchGraphicsView)graphicsView.Handler.PlatformView;
        var view2 = (Microsoft.Maui.Graphics.Win2D.W2DGraphicsView)view.Content;
        prop.SetValue(null, view2.Content);
#endif

    }

I actually get a COM error the first time I try to load an image, but after the first one (handled via try...catch) it works fine. All of the images load. Maybe there's a timing issue still, but it works for me... at least to get to the next stage of working on my app.

Is that a workaround only to display the image in UI or to allow loading it as IImage for further processing as well?

janseris avatar May 26 '22 21:05 janseris

This is just to load an stream into an IImage. The error you get comes from the GlobalCreator property being always null. Once you populate it with an actual CanvasControl from Win2D, then the loading a stream into an IImage works.

My dummy GraphicsView is 1 pixel by 1 pixel and it's covered by other controls. The windows version of GraphicsView uses a CanvasControl internally.

Somewhere later in my code, I'm doing this to load an image into an IImage:

var service = new Microsoft.Maui.Graphics.Win2D.W2DImageLoadingService();
IImage _image = service.FromStream(_ms.AsStream(), ImageFormat.Jpeg);

Again, I do get an initial COM error when trying the above code, but it works eventually. (My app is loading several pages from a pdf file as images and displaying them. If it can't get the image, it tries again at the next draw call when the GraphicsView is Invalidated. So this works for me...)

limefrogyank avatar May 26 '22 21:05 limefrogyank

Building on previous suggestions, and after looking at the source for W2DGraphicsService, this is what I came up with, and it's working for me.

You'd think that the getter on line 13 of W2DGraphicsService would have the same result.

#if WINDOWS
    builder.Services.AddSingleton<IImageLoadingService>(_ =>
    {
        var canvasDevice = CanvasDevice.GetSharedDevice();
        var assembly = typeof(Microsoft.Maui.Graphics.Win2D.W2DCanvas).Assembly;
        var type = assembly.GetType("Microsoft.Maui.Graphics.Win2D.W2DGraphicsService");
        var prop = type!.GetProperty("GlobalCreator");
        prop!.SetValue(null, canvasDevice);

        return new Microsoft.Maui.Graphics.Win2D.W2DImageLoadingService();
    });
#endif

bitbound avatar Mar 02 '23 14:03 bitbound

Duplicate of https://github.com/dotnet/maui/issues/12370

mattleibow avatar Aug 27 '23 12:08 mattleibow

Backported to net7 https://github.com/dotnet/maui/pull/12690

mattleibow avatar Aug 27 '23 12:08 mattleibow

This was backported to net7 7 months ago. What version are you on?

mattleibow avatar Aug 27 '23 12:08 mattleibow