-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Prevent divide-by-zero in ImageAnimator for images with 0 delay between frames #56223
Prevent divide-by-zero in ImageAnimator for images with 0 delay between frames #56223
Conversation
Tagging subscribers to this area: @safern, @tarekgh Issue DetailsFixes #55972 Per the GIF spec, a frame delay can have a value of 0. That was historically used for 2 purposes:
While the latter of those features is archaic, we still need to handle 0-delay frames. We assign them our animation delay speed to be "1 tick". It's possible the frame could get skipped if a tick takes longer than the tick time, but this gives a uniform speed for GIFs where all frame delays are 0. To prevent the divide-by-zero:
|
|
||
/// <summary> | ||
/// Whether animation should progress, respecting the image's animation support | ||
/// and if there are animation frames or loops remaining. | ||
/// </summary> | ||
private bool ShouldAnimate => Animated ? (_loopCount == 0 || _loop <= _loopCount) : false; | ||
private bool ShouldAnimate => TotalAnimationTime > 0 ? (_loopCount == 0 || _loop <= _loopCount) : false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This changes the behavior at line 160, preventing animation from occurring if the total animation time is <= 0.
lastEndTime += delay > 0 ? delay : ImageAnimator.AnimationDelayMS; | ||
|
||
// Guard against overflows | ||
if (lastEndTime < _totalAnimationTime) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is for cases where delay is negative? does that ever happen/is it legal or are you just being careful?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if just being careful, could you instead simply force delay to be no less than zero? then I think you wouldn't need _totalAnimationTime?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm being careful mostly. Here's how it comes together though.
- If the delay is <= 0, then apply the default animation delay
- If the accumulated last end time overflows, then collapse all of the remaining frames into that instant (essentially skipping any frames beyond the overflow of animation time)
- Ensure that TotalAnimationTime is a non-zero value if any frames are to be animated
- Eliminate the array access from TotalAnimationTime, replacing that with _totalAnimationTime
Speaking of animated images, I wonder when System.Drawing.Common's ImageAnimator can pick up png images with multiple frames as animated? I guess I could try to see if I can propose an api to help provide support for animated png's if possible on the .NET side of things in .NET 7 if that is required then somehow get the image animator to actually check for it all. And yes this is a known issue with people trying to manually hack in their own "Image animator" for their picture boxes as well. |
Unrelated failures. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for fixing so quickly!
Fixes #55972
Per the GIF spec, a frame delay can have a value of 0. That was historically used for 2 purposes:
While the latter of those features is archaic, we still need to handle 0-delay frames. We assign them our animation delay speed to be "1 tick". It's possible the frame could get skipped if a tick takes longer than the tick time, but this gives a uniform speed for GIFs where all frame delays are 0.
To prevent the divide-by-zero:
ShouldAnimate
property to check that the total animation time is > 0