0

In my project, I want to play a GIF in a PictureBox.
I need to play all Frames the GIF animation contains, then stop the animation.

I'm using the ImageAnimator class to animate a GIF Image, I just don't know how to stop it.

Private image As Image = My.Resources.icon_confirmation
'Private frames As Integer
Dim FDimensions As System.Drawing.Imaging.FrameDimension = New System.Drawing.Imaging.FrameDimension(image.FrameDimensionsList(0))
Dim frames As Integer = image.GetFrameCount(FDimensions)

Private Sub paintFrame(ByVal sender As Object, ByVal e As EventArgs)
    If frames < 33 Then PictureBox1.Image = image Else ImageAnimator.StopAnimate(image, AddressOf StopAnim)
End Sub

Private Sub StopAnim(ByVal sender As Object, ByVal e As EventArgs)
    PictureBox1.Dispose()
End Sub

Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    If frames = 12 Then
        ImageAnimator.UpdateFrames()
        e.Graphics.DrawImage(image, Point.Empty)
        frames -= 1
    End If
End Sub

GIF

Jimi
  • 29,621
  • 8
  • 43
  • 61
Mugisha
  • 11
  • 6
  • I'm not familiar with `ImageAnimator` but this could probably help: https://stackoverflow.com/questions/15647901/c-sharp-how-to-stop-animated-gif-from-continually-looping – MatSnow Apr 28 '21 at 13:24
  • Does this answer your question? [C# How to stop animated gif from continually looping](https://stackoverflow.com/questions/15647901/c-sharp-how-to-stop-animated-gif-from-continually-looping) – Peter Duniho Apr 28 '21 at 21:12

1 Answers1

1

To keep track of the current Frame that's being drawn on your PictureBox, you need a Field to store the current progress and compare it with the number of Frames that the animation contains.

When the progress reaches the last Frame (or any other Frame before the last, whatever is needed), you stop the animation calling ImageAnimator.StopAnimate().

To start the animation, you first check whether ImageAnimator.CanAnimate() (it may not be able to animate the Image you specified). If it can, then you call ImageAnimator.Animate(), passing to the method the Image object and the address of the method that handles the FrameChanged event.

This handler is used to check whether the animation should continue. If all conditions are met (not all Frames have been drawn), Invalidate() the Control used to show the animation and, in its Paint event handler, call ImageAnimator.UpdateFrames() to change the current Frame, then e.Graphics.DrawImage() to draw the Image (drawing the Frame that is now the current).

▶ As you can see in the visual example, I'm using a Button (btnAnimate) to start the animation. You can move that code to the Form.Shown event handler, if you prefer.
▶ I've added a loop counter, in case the animation should loop more than once.

This is how it visually works:

ImageAnimator Animate GIF

Imports System.Drawing.Imaging
' [...]

Private animation As Image = My.Resources.icon_confirmation
Private animationFrames As Integer = 0
Private currentFrame As Integer = 0
Private animationMaxLoops As Integer = 1
Private loops As Integer = 0

Private Sub btnAnimate_Click(sender As Object, e As EventArgs) Handles btnAnimate.Click
    animationFrames = animation.GetFrameCount(New FrameDimension(animation.FrameDimensionsList(0)))
    AnimateImage()
End Sub

Public Sub AnimateImage()
    If ImageAnimator.CanAnimate(animation) Then
        ImageAnimator.Animate(animation, AddressOf OnFrameChanged)
    End If
End Sub

Private Sub OnFrameChanged(o As Object, e As EventArgs)
    If currentFrame >= animationFrames Then
        currentFrame = 0
        loops += 1
        If loops >= animationMaxLoops Then
            animationFrames = 0
            loops = 0
            ImageAnimator.StopAnimate(animation, AddressOf OnFrameChanged)
        End If
    Else
        pictureBox1.Invalidate()
        currentFrame += 1
    End If
End Sub

Private Sub pictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles pictureBox1.Paint
    If animationFrames > 0 Then
        ImageAnimator.UpdateFrames()
        e.Graphics.DrawImage(animation, Point.Empty)
    End If
End Sub

C# Version

private Image animation = Properties.Resources.Some_GIF_Image;
private int animationFrames = 0;
private int currentFrame = 0;
private int animationMaxLoops = 1;
private int loops = 0;


private void btnAnimate_Click(object sender, EventArgs e)
{
    animationFrames = animation.GetFrameCount(new FrameDimension(animation.FrameDimensionsList[0]));
    AnimateImage();
}

private void AnimateImage()
{
    if (ImageAnimator.CanAnimate(animation)) {
        ImageAnimator.Animate(animation, OnFrameChanged);
    }
}

private void OnFrameChanged(object sender, EventArgs e)
{
    if (currentFrame >= animationFrames) {
        currentFrame = 0;
        loops += 1;
        if (loops >= animationMaxLoops) {
            animationFrames = 0;
            loops = 0;
            ImageAnimator.StopAnimate(animation, OnFrameChanged);
        }
    }
    else {
        pictureBox1.Invalidate();
        currentFrame += 1;
    }
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    if (animationFrames > 0)  {
        ImageAnimator.UpdateFrames();
        e.Graphics.DrawImage(animation, Point.Empty);
    }
}

A PasteBin of a complete Form that performs the animation using an Image from the Project's Resources.

Jimi
  • 29,621
  • 8
  • 43
  • 61
  • Sir, What is giving me a headache is to know which comes first, picture_paint event or animate() [that i putted in form_show event] method? – Mugisha Apr 30 '21 at 17:27
  • It doesn't matter. The Paint event of your PictureBox can be raised at any time. The point is, it only draws the Image after you have set `animationFrames` to a value > 0 and called `AnimateImage()` -- As mentioned, if you have a problem with the code you added to your Form, you need to post that code, with a clear description of what you get now and what you'd like to get instead. – Jimi Apr 30 '21 at 17:32
  • Sir since today in morning am very few to get crazy, is it possible to please connect to my pc and show me how to do? – Mugisha Apr 30 '21 at 18:37
  • Please have mercy for me am near to be crazy – Mugisha Apr 30 '21 at 18:42
  • Why don't you simply update your question, showing what code you have implemented, so I can fix it. For sure I cannot *connect to your Computer*. – Jimi Apr 30 '21 at 19:42
  • thank you for your patient one me, i did put the code but when a run the form the picturebox is acting as they was no code to tell how to paint like when you put a gif normally just animating the gif indefinitively, like picturebox paint event doesn't exist, i tried move the code in btn to form_show still the same, i tried in form_load still the same i even created new btn and put the code in the newbtn still the same the picturebox just playing the gif like none of animation code behind maters – Mugisha Apr 30 '21 at 21:18
  • i even tried to change some of value of loops nada! still the same( just looping image like as the picturebox doesn't know that there is a code to tell what to do) i tried even remove the image in picture in form design view to see if it will load when i start the form nope nothing i tried to put a label to see if the code that read the total number of frame it showed 33 nber of frame but the code that say animate() doesn't do any thing – Mugisha Apr 30 '21 at 21:24
  • thank you very much my friend Iam going to do so – Mugisha May 01 '21 at 13:33
  • i will come back with a result – Mugisha May 01 '21 at 13:34
  • Sir @Jimi thank you very much for your patience and kindness but better Me.exit this because i am not succeeding unless you accept to take look inside my pc there is no hope i will succed so thank you for all but me on my own, I won't make it – Mugisha May 01 '21 at 16:01
  • OKE thank you What is the contraly of picture.dispose? i want to try to dispose a picture then restart again at a given moment? – Mugisha May 01 '21 at 16:31
  • Do you mean `[Bitmap].Dispose()`? The current code doesn't need it (the Bitmap is assigned once from Resources, it's disposed of automatically when the Form closes). If you want to pass a Bitmap object to this Form from another class / methods, you can add a Constructor (`Public Sub New()`) that accepts a Bitmap object, the assign this object to a Field that references the Bitmap object passed to the Form. This Bitmap object needs to be disposed of by the calling method, not the Form that shows it. – Jimi May 01 '21 at 16:45