Skip to content
This repository has been archived by the owner on Dec 21, 2023. It is now read-only.

IImageLoadingService cannot load image on Windows #422

Open
janseris opened this issue May 6, 2022 · 10 comments
Open

IImageLoadingService cannot load image on Windows #422

janseris opened this issue May 6, 2022 · 10 comments

Comments

@janseris
Copy link

janseris commented May 6, 2022

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 dotnet/maui#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

@v-longmin
Copy link

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

@limefrogyank
Copy link

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?

@janseris
Copy link
Author

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

@limefrogyank
Copy link

limefrogyank commented May 26, 2022

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.

@janseris
Copy link
Author

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?

@limefrogyank
Copy link

limefrogyank commented May 26, 2022

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...)

@bitbound
Copy link

bitbound commented Mar 2, 2023

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

@mattleibow
Copy link
Member

Duplicate of dotnet/maui#12370

@mattleibow
Copy link
Member

Backported to net7 dotnet/maui#12690

@mattleibow
Copy link
Member

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

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants