Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ImageAnimator to render the correct frames #52236

Merged
merged 11 commits into from
May 6, 2021
Merged

Fix ImageAnimator to render the correct frames #52236

merged 11 commits into from
May 6, 2021

Conversation

jeffhandley
Copy link
Member

Fixes #52144 with an update to how the animation timing is handled. Also fixes #39405 by using the same implementation across both Windows and Unix.

This PR will remain a draft until #51981 is merged, as the animation assets used by the tests in this PR should flow through runtime-assets instead of being merged into runtime.

Here's what I found from the current implementation:

  1. The animation is relying on Thread.Sleep(50) to be very accurate; it's not
  2. Once a frame's time has elapsed, the animation very naively progresses 1 frame and sets the next frame's timer to 0
    • This does not account for the scenario of the thread having slept longer than a frame's duration
    • It also causes any leftover elapsed time to be lost
  3. When animation begins, it immediately progresses instead of initially sleeping
    • This results in the initial frame being skipped if its duration is less than 50ms

The new implementation converts frame delay times into frame "end times" so that we know at what time each frame's time is up. Then, as animation progresses, we can accurately determine which frame should be rendered at that time, preventing drift.

This PR also adds a manual test for image animator that captures the frames of the animation for visual verification. From those tests, I was able to discover that animation on Linux (Ubuntu 20.04) is corrupting the rendered images in a couple of ways. Those seem to be issues down at the libgdiplus level though, so I didn't want to block this PR on those.

ImageAnimator wasn't respecting a GIF's animation repeat count either, but I decided to also consider that out of scope for this PR. I'll file an issue for that too, but I imagine we will close it until we receive customer reports of it.

@ghost
Copy link

ghost commented May 4, 2021

Tagging subscribers to this area: @safern, @tarekgh
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #52144 with an update to how the animation timing is handled. Also fixes #39405 by using the same implementation across both Windows and Unix.

This PR will remain a draft until #51981 is merged, as the animation assets used by the tests in this PR should flow through runtime-assets instead of being merged into runtime.

Here's what I found from the current implementation:

  1. The animation is relying on Thread.Sleep(50) to be very accurate; it's not
  2. Once a frame's time has elapsed, the animation very naively progresses 1 frame and sets the next frame's timer to 0
    • This does not account for the scenario of the thread having slept longer than a frame's duration
    • It also causes any leftover elapsed time to be lost
  3. When animation begins, it immediately progresses instead of initially sleeping
    • This results in the initial frame being skipped if its duration is less than 50ms

The new implementation converts frame delay times into frame "end times" so that we know at what time each frame's time is up. Then, as animation progresses, we can accurately determine which frame should be rendered at that time, preventing drift.

This PR also adds a manual test for image animator that captures the frames of the animation for visual verification. From those tests, I was able to discover that animation on Linux (Ubuntu 20.04) is corrupting the rendered images in a couple of ways. Those seem to be issues down at the libgdiplus level though, so I didn't want to block this PR on those.

ImageAnimator wasn't respecting a GIF's animation repeat count either, but I decided to also consider that out of scope for this PR. I'll file an issue for that too, but I imagine we will close it until we receive customer reports of it.

Author: jeffhandley
Assignees: -
Labels:

area-System.Drawing

Milestone: -

@jeffhandley
Copy link
Member Author

I couldn't resist the urge to respect the animation loop limit too; it's straightforward enough. Another commit will be soon pushed with that added in.

@jeffhandley jeffhandley marked this pull request as ready for review May 5, 2021 19:14
Copy link
Member

@safern safern left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks 🎉

@jeffhandley jeffhandley merged commit 3ffc4fc into dotnet:main May 6, 2021
@jeffhandley jeffhandley deleted the jeffhandley/imageanimator branch May 6, 2021 00:37
@karelz karelz added this to the 6.0.0 milestone May 20, 2021
Comment on lines +385 to +386
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:

Stopwatch stopwatch = Stopwatch.StartNew();

@ghost ghost locked as resolved and limited conversation to collaborators Jun 25, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ImageAnimator's animation timing drifts ImageAnimator.StopAnimate (on Unix) could throw PNSE
6 participants