I am working on an image converter for android and using .net maui for application development. One of the image conversion options is converting multiple images to animated gif. When I install the application in debug mode, everything works fine and the animated gif runs without problems. But when I install the application that is on Google Play under internal testing, the animated gif does not work. The image viewer I created is completely white and does not perform the animation. If I navigate to my application's files folder and select the gif created by the application, it runs without problems.
This is the code for my ViewImage.
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewmodel="clr-namespace:ImageConvert.ViewModel"
xmlns:model="clr-namespace:ImageConvert.Models"
x:Class="ImageConvert.Views.ViewImage"
x:DataType="model:ViewImageModel"
Title="Image View">
<Grid BackgroundColor="WhiteSmoke"
Padding="2"
Margin="2">
<Image Grid.Row="0" Source="{Binding PathImage}" IsAnimationPlaying="{Binding IsAnimationGif, Mode=TwoWay}" Aspect="AspectFit" Margin="2,3,2,3"/>
</Grid>
</ContentPage>
This is the model code that activates the gif animation.
public class ViewImageModel : BasePageImageModel, INotifyPropertyChanged
{
IDispatcherTimer timer = Application.Current.Dispatcher.CreateTimer();
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private bool _isAnimationGif = false;
private int Count = 0;
public bool IsAnimationGif
{
get
{
if (PathImage.PegaExtensao().Contains("gif"))
{
if (Count == 0)
{
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += (s, e) => DoSomething();
timer.Start();
}
return _isAnimationGif;
}
else
{
return _isAnimationGif;
}
}
set
{
_isAnimationGif = value;
OnPropertyChanged(nameof(IsAnimationGif));
}
}
private void DoSomething()
{
IsAnimationGif = true;
timer.Stop();
}
}
Can you help me understand and solve this problem?
As an option to solve the bug problem that does not show the animated gif in the .Net Maui Image control, I decided to create a custom control using the SkiaSharp library. It is important to highlight that this solution has been tested on Windows and Android. Another point is that it was made to display gifs from local system folders, so if you want to display gif images online, you must make changes to the solution.
The implementation code for this custom control is below in order to help other developers work around this problem, while the solution for this bug is not enough.
To create this control, I used the libraries "SkiaSharp.Views.Maui.Controls" and "SkiaSharp.Views.Maui.Core"
First I created a new .Net Maui class library project for my solution, and named it ImageView.Maui. Then I imported the two packages mentioned above.
In this new project I created 3 classes.
See the code for the 3 classes below.
--Custon Control--
GifView.cs
using SkiaSharp.Views.Maui;
using SkiaSharp;
using SkiaSharp.Views.Maui.Controls;
using Common.Maui;
namespace ImageView.Maui
{
public class GifView : SKCanvasView
{
private SKCanvas _canvas;
private SKImageInfo _info;
private SKBitmap _bitmap;
private SKCodec _codec;
private int _frameIndex;
public string GifSource
{
get => (string)GetValue(GifSourceProperty);
set => SetValue(GifSourceProperty, value);
}
public static readonly BindableProperty GifSourceProperty = BindableProperty.Create(nameof(GifSource), typeof(string), typeof(GifView), null, propertyChanged: OnBindablePropertyChanged);
private static void OnBindablePropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
((GifView)bindable).InvalidateSurface();
}
public GifView()
{
IgnorePixelScaling = false;
PaintSurface += OnPaintSurface;
StartAnimation();
}
protected void OnPaintSurface(object sender, SKPaintSurfaceEventArgs e)
{
_canvas = e.Surface.Canvas;
_canvas.Clear();
_info = e.Info;
DrawGif();
}
private async void DrawGif()
{
if (!string.IsNullOrEmpty(GifSource))
{
using (var stream = new SKManagedStream(File.OpenRead(GifSource)))
{
_codec = SKCodec.Create(stream);
_bitmap = new SKBitmap(_codec.Info.Width, _codec.Info.Height);
var result = _codec.GetPixels(_bitmap.Info, _bitmap.GetPixels(), new SKCodecOptions(_frameIndex));
if (result == SKCodecResult.Success || result == SKCodecResult.IncompleteInput)
{
float scale = Math.Min(_info.Width / _bitmap.Width, _info.Height / _bitmap.Height);
var width = scale * _bitmap.Width;
var height = scale * _bitmap.Height;
var rect = SKRect.Create((_info.Width - width) / 2, (_info.Height - height) / 2, width, height);
_canvas.DrawBitmap(_bitmap, rect);
}
}
}
}
private void StartAnimation()
{
Device.StartTimer(TimeSpan.FromMilliseconds(50), () =>
{
_frameIndex = (_frameIndex + 1) % (_codec?.FrameCount ?? 1);
InvalidateSurface();
return true;
});
}
}
}
Registration.cs
namespace ImageView.Maui
{
public static class Registration
{
public static MauiAppBuilder UseGifView(this MauiAppBuilder builder)
{
builder.ConfigureMauiHandlers(h =>
{
h.AddHandler<GifView, GifViewHandler>();
});
return builder;
}
}
}
GifViewHandler.cs
using SkiaSharp.Views.Maui.Handlers;
namespace ImageView.Maui
{
public class GifViewHandler : SKCanvasViewHandler
{
}
}
--Using the controller--
Then in the .net maui project, I imported the reference into the custom control project that I created. I made the following change to the MauiProgram class, adding .UseGifView().
MauiProgram.cs
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseMauiCommunityToolkit()
.UseGifView()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
On the content page that displays the animated gif I did the following:
MyContentPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:maui="clr-namespace:ImageView.Maui;assembly=ImageView.Maui"
x:Class="MyProject.Views.ViewImage"
Title="Image View">
<Grid BackgroundColor="WhiteSmoke"
Padding="2"
Margin="2">
<maui:GifView x:Name="GifVewImage" Grid.Row="0" GifSource="**Path-your-gif-local-image**" Margin="2,3,2,3" AbsoluteLayout.LayoutFlags="All"/>
</Grid>
</ContentPage>
This solved my problem. I hope this solution can help other people. Thanks!