dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
21.97k stars 1.71k forks source link

Image is flickering after ImageSource change #23172

Open MAtt5816 opened 2 months ago

MAtt5816 commented 2 months ago

Description

Hello, I've got a problem with MAUI on Android. I wrote an application to process digital data from an external USB device. I'm creating an ImageSource from a bytes array and binding it to an Image in XAML. New ImageSources are being created very quickly (c.a. 13 per second). Unfortunately, the image is still flickering. At Windows, problems don't occur - the image is displaying almost statically.

My MAUI version: image

Problem on Android: https://github.com/dotnet/maui/assets/24682622/0821abd8-17c3-4663-a4cc-6379a8c5c29e

Correctly working on Windows: Animation

My code: Page.xaml

<ContentPage.BindingContext>
    <viewModel:UsbTestViewModel />
</ContentPage.BindingContext>

<ScrollView>
    <VerticalStackLayout
        Padding="30,0"
        Spacing="25">
        <Border StrokeThickness="1" Stroke="Blue" HeightRequest="258" WidthRequest="258">
            <Image Source="{Binding ImageSource}" HeightRequest="256" WidthRequest="256" />
        </Border>
    </VerticalStackLayout>
</ScrollView>

UsbTestViewModel.cs


public ImageSource? ImageSource
{
    get => _imageSource;
    set
    {
        _imageSource = value;
        OnPropertyChanged(nameof(ImageSource));
    }
}

//...

// Timer 13 Hz
 private void ImageRenderTimerTick(object? sender, EventArgs e)
 {
     if (RenderTaskManager.RenderedImageSource != null)
     {
         ImageSource = RenderTaskManager.RenderedImageSource;
     }
 }

RenderTaskManager.cs

 using SkiaSharp;
//...

  public static ImageSource CreateImageSourceFromByteArray(byte[] bytes)
   {
       var bitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Opaque);

       ConvertBytesToPixelArray(bytes);

       unsafe
       {
           fixed (byte* p = _pixels)
           {
               bitmap.SetPixels((IntPtr)p);
           }
       }

       SKData encoded = bitmap.Encode(SKEncodedImageFormat.Png, 100);
       Stream stream = encoded.AsStream();
       return ImageSource.FromStream(() => stream);
   }

Steps to Reproduce

  1. Create IDispatcherTimer with TimeSpan 77 milliseconds.
    var myTimer = Application.Current?.Dispatcher.CreateTimer();
    myTimer.Interval = TimeSpan.FromMilliseconds(77);
    timer.Tick += ImageRenderTimerTick;
  2. Create ImageRenderTimerTick method where you will be creating ImageSource. You can create image from JPG file - problem still occur.

Link to public reproduction project repository

No response

Version with bug

Unknown/Other

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

Minium target Android 5.0 (API lvl 21)

Did you find any workaround?

No response

Relevant log output

No response

github-actions[bot] commented 2 months ago

Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!

Open similar issues:

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

MAtt5816 commented 2 months ago

ADDITIONAL INFO: A similar problem can be reproduced on Windows. Just (re)set the image source from the file in IDispatcherTimer and the image will flicker. It is the same bug as #6962.

namespace MauiApp1
{
    public partial class MainPage : ContentPage
    {
        IDispatcherTimer? timer;

        public MainPage()
        {
            InitializeComponent();
            timer = App.Current?.Dispatcher.CreateTimer();
            if (timer != null)
            {
                timer.Interval = TimeSpan.FromMilliseconds(77);
                timer.Tick += SetImage;
                timer.Start();
            }
        }

        private void SetImage(object? sender, EventArgs e)
        {
            imageContent.Source = "dotnet_bot.png";
        }
    }
}
Zhanglirong-Winnie commented 2 months ago

According to the sample project in #6962 , we can reproduce this issue in 17.11.0 Preview 2.1 (8.0.60 & 8.0.40).