xamarin / Xamarin.Forms

Xamarin.Forms is no longer supported. Migrate your apps to .NET MAUI.
https://aka.ms/xamarin-upgrade
Other
5.64k stars 1.88k forks source link

[Bug] ImageSource.FromStream() causes Android to crash with animated .gif files. #10895

Open bakerhillpins opened 4 years ago

bakerhillpins commented 4 years ago

Description

I started with the following working example code that loads using a string in Xaml.

I've tried to modify his example to load an animated gif that is an EmbeddedResource in the NetStandard shared library of the project but have been unsuccessful. I'm using the ImageSource.FromStream( () => assembly.GetManifestResourceStream( resourcePath ) ); method to create the ImageSource from a stream in a binding converter. I can load static gif images without problems this way. I can even load the animated image, as a static image without issue (the IsAnimationPlaying property must be absent from the xaml), but when I add/set the IsAnimationPlaying property in xaml the Android app crashes.

Steps to Reproduce

  1. Download example solution included.
  2. Comment in/out the Crash/No Crash sections of xaml in the MainPage.xaml file.
  3. Execute on an emulator. I've used 2 different emulators, A Nougat 7.1-API 25/Base Device:None/Processor:x86 and a Pie 9.0-API 28/Base Device:Phone M-DPI5.4/Processor:x86. Both show same results.

Expected Behavior

No crash

Actual Behavior

=================================================================
    Native Crash Reporting
=================================================================
Got a SEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

No native Android stacktrace (see debuggerd output).

=================================================================
    Basic Fault Address Reporting
=================================================================
Memory around native instruction pointer (0x8c83a896):
0x8c83a886  10 8d 4d e4 8b 4d 10 89 4d e4 8d 4d e4 8b 4d e4  ..M..M..M..M..M.
0x8c83a896  89 4c 24 08 89 44 24 04 89 3c 24 8b c0 e8 c0 fe  .L$..D$..<$.....
0x8c83a8a6  ff ff 89 45 c4 8b 4d f0 8d 64 24 00 90 90 90 8b  ...E..M..d$.....
0x8c83a8b6  45 c4 e9 77 00 00 00 8b 4d f0 8d 64 24 00 90 90  E..w....M..d$...

=================================================================
    Managed Stacktrace:
=================================================================
      at Xamarin.Forms.Platform.Android.FormsAnimationDrawable:LoadImageAnimationAsync <0x0012e>
      at Xamarin.Forms.Platform.Android.FormsAnimationDrawable:LoadImageAnimationAsync <0x0013f>
      at Xamarin.Forms.Platform.Android.FormsAnimationDrawable:LoadImageAnimationAsync <0x0013f>
      at Xamarin.Forms.Platform.Android.FormsAnimationDrawable:LoadImageAnimationAsync <0x0013f>
      at Xamarin.Forms.Platform.Android.FormsAnimationDrawable:LoadImageAnimationAsync <0x0013f>
      at Xamarin.Forms.Platform.Android.FormsAnimationDrawable:LoadImageAnimationAsync <0x0

Continues ad nauseam for pages and then it just dies.

      at Xamarin.Forms.Platform.Android.FormsAnimationDrawable:LoadImageAnimationAsync <0x0013f>
      at Xamarin.Forms.Platform.Android.FormsAnimationDrawable:LoadImageAnimationAsync <0x0013f>
      at Xamarin.Forms.Platform
.Android.FormsAnimationDrawable:LoadImageAnimationAsync <0x0013f>
      at Xamarin.Forms.Platform.Android.StreamImagesourceHandler:LoadImageAnimationAsync <0x0005b>
      at <UpdateBitmap>d__2:MoveNext <0x00768>
      at System.Runtime.CompilerServices.AsyncTaskMethodBuilder:Start <0x00127>
      at Xamarin.Forms.Platform.Android.ImageViewExtensions:UpdateBitmap <0x001bf>
      at Xamarin.Forms.Platform.Android.ImageViewExtensions:UpdateBitmap <0x00067>
      at <TryUpdateBitmap>d__6:MoveNext <0x0028f>
      at System.Runtime.CompilerServices.AsyncTaskMethodBuilder:Start <0x00147>
      at Xamarin.Forms.Platform.Android.FastRenderers.ImageElementManager:TryUpdateBitmap <0x0019b>
      at <OnElementChanged>d__3:MoveNext <0x004b7>
      at System.Runtime.CompilerServices.AsyncVoidMethodBuilder:Start <0x00127>
      at Xamarin.Forms.Platform.Android.FastRenderers.ImageElementManager:OnElementChanged <0x0015f>
      at System.EventHandler`1:invoke_void_object_TEventArgs <0x00143>
      at Xamarin.Forms.Platform.Android.FastRenderers.ImageRenderer:OnEl
ementChanged <0x0011b>
      at Xamarin.Forms.Platform.Android.FastRenderers.ImageRenderer:Xamarin.Forms.Platform.Android.IVisualElementRenderer.SetElement <0x005d7>
      at Xamarin.Forms.Platform.Android.Platform:CreateRenderer <0x0013f>
      at Xamarin.Forms.Platform.Android.VisualElementPackager:AddChild <0x00487>
      at Xamarin.Forms.Platform.Android.VisualElementPackager:SetElement <0x00837>
      at Xamarin.Forms.Platform.Android.VisualElementPackager:Load <0x00057>
      at Xamarin.Forms.Platform.Android.VisualElementRenderer`1:SetPackager <0x00077>
      at Xamarin.Forms.Platform.Android.VisualElementRenderer`1:SetElement <0x007b7>
      at Xamarin.Forms.Platform.Android.VisualElementRenderer`1:Xamarin.Forms.Platform.Android.IVisualElementRenderer.SetElement <0x00187>
      at Xamarin.Forms.Platform.Android.Platform:CreateRenderer <0x0013f>
      at Xamarin.Forms.Platform.Android.VisualElementPackager:AddChild <0x00487>
      at Xamarin.Forms.Platform.Android.VisualElementPackager:SetElement <0x00837>
      at Xamarin.Forms.Platform
.Android.VisualElementPackager:Load <0x00057>
      at Xamarin.Forms.Platform.Android.VisualElementRenderer`1:SetPackager <0x00077>
      at Xamarin.Forms.Platform.Android.VisualElementRenderer`1:SetElement <0x007b7>
      at Xamarin.Forms.Platform.Android.VisualElementRenderer`1:Xamarin.Forms.Platform.Android.IVisualElementRenderer.SetElement <0x00187>
      at Xamarin.Forms.Platform.Android.Platform:CreateRenderer <0x0013f>
      at Xamarin.Forms.Platform.Android.AppCompat.Platform:AddChild <0x000b3>
      at Xamarin.Forms.Platform.Android.AppCompat.Platform:SetPageInternal <0x00297>
      at Xamarin.Forms.Platform.Android.AppCompat.Platform:SetPage <0x0067f>
      at Xamarin.Forms.Platform.Android.FormsAppCompatActivity:InternalSetPage <0x001b7>
      at Xamarin.Forms.Platform.Android.FormsAppCompatActivity:SetMainPage <0x00077>
      at Xamarin.Forms.Platform.Android.FormsAppCompatActivity:LoadApplication <0x0067b>
      at AnimatedGifForms.Droid.MainActivity:OnCreate <0x00143>
      at Android.App.Activity:n_OnCreate_Landroid_os_Bundle_ <0
x000ab>
      at Android.Runtime.DynamicMethodNameCounter:8 <0x000c3>
      at Android.Runtime.DynamicMethodNameCounter:8 <0x000b3>
=================================================================
[HotReload] (2020-05-29 10:24:00.4): ERROR: Caught exception in AgentStatusChangedHandler at 212: Xamarin.HotReload.DebuggerTimeoutException: Failed to Inject Assembly
   at Microsoft.VisualStudio.Telemetry.WindowsErrorReporting.WatsonReport.GetClrWatsonExceptionInfo(Exception exceptionObject)
   at Microsoft.VisualStudio.Telemetry.WindowsErrorReporting.WatsonReport.GetClrWatsonExceptionInfo(Exception exceptionObject)

Basic Information

Screenshots

None

Reproduction Link

Uploaded a zip solution. AnimatedGifAndroidCrash.zip

Workaround

Could not determine a workaround.

bakerhillpins commented 4 years ago

So I've been playing around with this in my production application (not the example I've uploaded) and noted the following:

If I load a .png Image and the IsAnimationPlaying property is present in xaml I see the same crash. True or False makes no difference. Simply present in the .xaml file and load an image using the ImageSource.FromStream( () => assembly.GetManifestResourceStream( resourcePath ) ); method and it crashes.

CliffAgius commented 4 years ago

I am seeing the same thing of needing a .png and .gif depending on what is loaded but can't have the IsAnimationPlaying bound as it crashes but without it I can't get the .gif files to animate...

ognamala commented 4 years ago

Observing the same behaviour.

Attempting to load a gif which is an embedded resources within the NetStandard shared library. If the IsAnimationPlaying is false then the gif is rendered but not animated. As soon as this value is switched to true, the crash occurs.

xamiell commented 4 years ago

I'm seeing the same error. Time before was working but now is crashing the app. On Android the app is crashing when the following code is loading in a content page:

<Image IsAnimationPlaying="True"
             Source="{extentions:EmbeddedResourceExtention Source=AppTest.Images.Test.gif}"
             WidthRequest="300"
             HeightRequest="300"/>

EmbeddedResourceExtention code works with others images like .png or .jpg but not with gif

[ContentProperty(nameof(Source))] // This property is used as a parameter in XAML.
    public class EmbeddedResourceExtention : IMarkupExtension
    {
        public string Source { get; set; }

        public object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Source == null)
            {
                return null;
            }

            // Search for the image resource and return and object that
            // represents the image path.
            var imageSource = ImageSource.FromResource(Source,
                            typeof(EmbeddedResourceExtention).GetTypeInfo().Assembly);
            return imageSource;
        }
    }

On iOS is not rendering. Is very frustrating because I'm working this requirement for a Enterprise Application.

Xamarin.Forms 4.8.0.1269 VS for Mac 8.7 Build 2037

ognamala commented 4 years ago

I'm seeing the same error. Time before was working but now is crashing the app. On Android the app is crashing when the following code is loading in a content page:

<Image IsAnimationPlaying="True"
             Source="{extentions:EmbeddedResourceExtention Source=AppTest.Images.Test.gif}"
             WidthRequest="300"
             HeightRequest="300"/>

EmbeddedResourceExtention code works with others images like .png or .jpg but not with gif

[ContentProperty(nameof(Source))] // This property is used as a parameter in XAML.
    public class EmbeddedResourceExtention : IMarkupExtension
    {
        public string Source { get; set; }

        public object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Source == null)
            {
                return null;
            }

            // Search for the image resource and return and object that
            // represents the image path.
            var imageSource = ImageSource.FromResource(Source,
                            typeof(EmbeddedResourceExtention).GetTypeInfo().Assembly);
            return imageSource;
        }
    }

On iOS is not rendering. Is very frustrating because I'm working this requirement for a Enterprise Application.

Xamarin.Forms 4.8.0.1269 VS for Mac 8.7 Build 2037

Hey @xamiell if you want you can still render the gif but you cannot use this method

For android put your gif in the resources/drawable folder and for iOS put it in the resources folder, then use a normal image component in XAML and set IsAnimationPlaying = true

This issue seems to happen if we use the gifs from within the .NET shared library as embedded resources .. Hope this helps .. let me know if you manage ☺️ I worked around this issue in this way

xamiell commented 4 years ago

I'm seeing the same error. Time before was working but now is crashing the app. On Android the app is crashing when the following code is loading in a content page:

<Image IsAnimationPlaying="True"
             Source="{extentions:EmbeddedResourceExtention Source=AppTest.Images.Test.gif}"
             WidthRequest="300"
             HeightRequest="300"/>

EmbeddedResourceExtention code works with others images like .png or .jpg but not with gif

[ContentProperty(nameof(Source))] // This property is used as a parameter in XAML.
    public class EmbeddedResourceExtention : IMarkupExtension
    {
        public string Source { get; set; }

        public object ProvideValue(IServiceProvider serviceProvider)
        {
            if (Source == null)
            {
                return null;
            }

            // Search for the image resource and return and object that
            // represents the image path.
            var imageSource = ImageSource.FromResource(Source,
                            typeof(EmbeddedResourceExtention).GetTypeInfo().Assembly);
            return imageSource;
        }
    }

On iOS is not rendering. Is very frustrating because I'm working this requirement for a Enterprise Application.

Xamarin.Forms 4.8.0.1269 VS for Mac 8.7 Build 2037

Hey @xamiell if you want you can still render the gif but you cannot use this method

For android put your gif in the resources/drawable folder and for iOS put it in the resources folder, then use a normal image component in XAML and set IsAnimationPlaying = true

This issue seems to happen if we use the gifs from within the .NET shared library as embedded resources .. Hope this helps .. let me know if you manager ☺️ i worked around this issue in this way

Hi, @ognamala thanks for the reply! I will try and let you know

xamiell commented 4 years ago

I try it, works but on Android took more seconds to be rendered. On iOS the gif is rendered as soon y open the page but on Android took more seconds to be rendered.

mduchev commented 4 years ago

@xamiell The gifs are notoriously slow on Android. The larger the gif, the sower the initial load will be. Just to keep that in mind. If it is very large, I am using the new Media element and I'm playing them as a mp4 file.

xamiell commented 4 years ago

Hi, @mduchev thanks for the reply, yes but some time dealing with Dark mode a video can be complicated.

I made a gif with less size, now is working perfectly with resources/drawable. I'm wonder that gif are not working with Embedded Resource. Thanks for the quick and precise replies, that help me a lot! :)

mondayuk commented 3 years ago

Just to say thanks, this thread really helped. I was getting a mysterious crash, which turned out to be this. I was creating an Image in code behind and setting IsAnimationPlaying = False. On iOS the Image often was blank (seems like a race condition as it was intermittent) and on Android it crashed. Removing any reference to IsAnimationPlaying solved the problem.

aleks42 commented 3 years ago

I am seeing the same error. Spent half a day to debug. I am getting png from webservice. If there is no png, I am trying to show animated gif from resources. When IsAnimationPlaying is in xaml, both cases cause "[libc] Fatal signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0xff1b5ffc in tid 1579 (tipass.MyApp), pid 1579 (tipass.MyApp)". I probably will have to save all files to disk, because animated gif works fine from drawable folder with IsAnimationPlaying="True". Xamarin.Forms 5.0.0.2012

mondayuk commented 3 years ago

I was fortunate that I was not using binding, but have you tried perhaps wrapping the Image view in a custom control, and only setting the IsAnimationPlaying property in code behind?

aleks42 commented 3 years ago

I was fortunate that I was not using binding, but have you tried perhaps wrapping the Image view in a custom control, and only setting the IsAnimationPlaying property in code behind?

Moving IsAnimationPlaying = true to code behind didn't help.

mondayuk commented 3 years ago

Sorry, bad explanation on my part. The issue I had was that if I set IsAnimationPlaying = false on a file that had no animation (like a jpeg) I had the problem you are having. My workaround was just simply not to set IsAnimationPlaying at all. For binding, that's obviously not easy which is why i'm suggesting doing it in code behind.

Someting like...

if (imageLoaded) {
    image.Source = ImageSource.FromStream(...);
} else {
    image.Source = ImageSource.FromFile("loading.gif");
    image.IsAnimationPlaying = true;
}
aleks42 commented 3 years ago

Finally I managed to get this to work. Files from webservice are saved to storage first. IsAnimationPlaying="True"

in viewModel:

public ImageSource MyImageSource{ get; set; }
...
if (imageLoaded) {
  string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
  string localFilename = "img2.jpg";
  string localPath = Path.Combine(documentsPath, localFilename);
  File.WriteAllBytes(localPath, bytes);
  MyImageSource = ImageSource.FromFile(localPath); // file from webservice
} else {
  MyImageSource = "img.gif"; // default file, stored in drawable folder on android
}

in XAML:

<Image Source="{Binding MyImageSource}" IsAnimationPlaying="True" Aspect="AspectFill"/>
Syed-Esqimo commented 2 years ago

The alternative is 🥁...



































































































































Convert yo gif's to mp4 and use MediaElement from XCT: https://github.com/xamarin/XamarinCommunityToolkit

Like so:

 <xct:MediaElement WidthRequest="310"
                              HeightRequest="345"
                              BackgroundColor="Transparent"
                              AutoPlay="True"
                              ShowsPlaybackControls="False"
                              HorizontalOptions="Center"
                              IsLooping="True"
                              Source="ms-appx:///house.mp4" />

Read more about Source here: https://docs.microsoft.com/en-us/xamarin/community-toolkit/views/mediaelement#play-media-embedded-in-the-app-package

g4mb10r commented 1 year ago

@samhouts This bug has been open for over 2 years. Any updates?

solomonfried commented 1 year ago

@samhouts This bug has been open for over 2 years. Any updates?

Ran into this today (forgot that I had the same issue years ago). Still not fixed. Maybe in MAUI.

I used the suggestion by aleks42 to copy the Resource bytes to a file and load that into the ImageSource.

Copying the file into each application folder was not an option because I am displaying a gif from an included project.

Thanks to all here for your posts.