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

Slow gif animation (#114) #180

Merged
merged 1 commit into from
Apr 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 45 additions & 1 deletion Source/Components/ImageGlass.ImageBox/DefaultGifAnimator.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,67 @@
using System;
/*
ImageGlass Project - Image viewer for Windows
Copyright (C) 2017 DUONG DIEU PHAP
Project homepage: http://imageglass.org

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/


/******************************************
* THANKS [Meowski] FOR THIS CONTRIBUTION
*******************************************/

using System;
using System.Drawing;

namespace ImageGlass {
/// <summary>
/// This is a wrapper for the original System.Drawing animator. See <see cref="ImageAnimator"/>.
/// </summary>
public class DefaultGifAnimator : GifAnimator {

/// <summary>
/// Updates the time frame for this image.
/// </summary>
/// <param name="image"></param>
public void UpdateFrames(Image image) {
ImageAnimator.UpdateFrames(image);
}

/// <summary>
/// Stops updating frames for the given image.
/// </summary>
/// <param name="image"></param>
/// <param name="eventHandler"></param>
public void StopAnimate(Image image, EventHandler eventHandler) {
ImageAnimator.StopAnimate(image, eventHandler);
}

/// <summary>
/// Animates the given image.
/// </summary>
/// <param name="image"></param>
/// <param name="eventHandler"></param>
public void Animate(Image image, EventHandler eventHandler) {
ImageAnimator.Animate(image, eventHandler);
}

/// <summary>
/// Determines whether an image can be animated.
/// </summary>
/// <param name="image"></param>
/// <returns></returns>
public bool CanAnimate(Image image) {
return ImageAnimator.CanAnimate(image);
}
Expand Down
29 changes: 27 additions & 2 deletions Source/Components/ImageGlass.ImageBox/GifAnimator.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
using System;
/*
ImageGlass Project - Image viewer for Windows
Copyright (C) 2017 DUONG DIEU PHAP
Project homepage: http://imageglass.org

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/


/******************************************
* THANKS [Meowski] FOR THIS CONTRIBUTION
*******************************************/

using System;
using System.Drawing;

namespace ImageGlass {
namespace ImageGlass
{
/// <summary>
/// Used to animate gifs.
/// </summary>
Expand Down
79 changes: 61 additions & 18 deletions Source/Components/ImageGlass.ImageBox/HighResolutionGifAnimator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@
using System;
/*
ImageGlass Project - Image viewer for Windows
Copyright (C) 2017 DUONG DIEU PHAP
Project homepage: http://imageglass.org

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/


/******************************************
* THANKS [Meowski] FOR THIS CONTRIBUTION
*******************************************/

using System;
using System.Collections.Concurrent;
using System.Drawing;
using System.Drawing.Imaging;
Expand Down Expand Up @@ -26,15 +50,15 @@ public class HighResolutionGifAnimator : GifAnimator {
/// </summary>
/// <param name="value"> Ideally should be a multiple of 10. </param>
/// <returns>The actual tick value that will be used</returns>
public static int setTickTimeInMilliseconds(int value) {
public static int SetTickTimeInMilliseconds(int value) {
// 10 is the minimum value, as a GIF's lowest tick rate is 10ms
//
int newTickValue = Math.Max(10, (value / 10) * 10);
ourMinTickTimeInMilliseconds = newTickValue;
return newTickValue;
}

public static int getTickTimeInMilliseconds() {
public static int GetTickTimeInMilliseconds() {
return ourMinTickTimeInMilliseconds;
}

Expand All @@ -52,6 +76,11 @@ public class HighResolutionGifAnimator : GifAnimator {
}
#endregion

/// <summary>
/// Animates the given image.
/// </summary>
/// <param name="image"></param>
/// <param name="onFrameChangedHandler"></param>
public void Animate(Image image, EventHandler onFrameChangedHandler) {

if (!CanAnimate(image))
Expand All @@ -65,23 +94,23 @@ public class HighResolutionGifAnimator : GifAnimator {
// we manually try to add entries ourself, and if it fails we
// kill the thread.
//
GifImageData toAdd = addFactory(image, onFrameChangedHandler);
GifImageData toAdd = AddFactory(image, onFrameChangedHandler);
if (!ourImageState.TryAdd(image, toAdd))
Interlocked.Exchange(ref toAdd.myIsThreadDead, 1);
}

private GifImageData addFactory(Image image, EventHandler eventHandler) {
private GifImageData AddFactory(Image image, EventHandler eventHandler) {
GifImageData data;
lock (image) {
data = new GifImageData(image, eventHandler);
}

Thread heartbeat = new Thread(() => {
int sleepTime = getSleepAmountInMilliseconds(data.getCurrentDelayInMilliseconds());
int sleepTime = getSleepAmountInMilliseconds(data.GetCurrentDelayInMilliseconds());
Thread.Sleep(sleepTime);
while (data.threadIsNotDead()) {
data.handleUpdateTick();
sleepTime = getSleepAmountInMilliseconds(data.getCurrentDelayInMilliseconds());
while (data.ThreadIsNotDead()) {
data.HandleUpdateTick();
sleepTime = getSleepAmountInMilliseconds(data.GetCurrentDelayInMilliseconds());
Thread.Sleep(sleepTime);
}
});
Expand All @@ -91,6 +120,10 @@ public class HighResolutionGifAnimator : GifAnimator {
return data;
}

/// <summary>
/// Updates the time frame for this image.
/// </summary>
/// <param name="image"></param>
public void UpdateFrames(Image image) {
if (image == null)
return;
Expand All @@ -103,10 +136,15 @@ public class HighResolutionGifAnimator : GifAnimator {
return;

lock (image) {
outData.updateFrame();
outData.UpdateFrame();
}
}

/// <summary>
/// Stops updating frames for the given image.
/// </summary>
/// <param name="image"></param>
/// <param name="eventHandler"></param>
public void StopAnimate(Image image, EventHandler eventHandler) {
if (image == null)
return;
Expand All @@ -118,18 +156,23 @@ public class HighResolutionGifAnimator : GifAnimator {

// See if we have more than one frame in the time dimension.
//
/// <summary>
/// Determines whether an image can be animated.
/// </summary>
/// <param name="image"></param>
/// <returns></returns>
public bool CanAnimate(Image image) {
if (image == null)
return false;

lock (image) {
return imageHasTimeFrames(image);
return ImageHasTimeFrames(image);
}
}

// image lock should be held
//
private bool imageHasTimeFrames(Image image) {
private bool ImageHasTimeFrames(Image image) {
foreach (Guid guid in image.FrameDimensionsList) {
FrameDimension dimension = new FrameDimension(guid);
if (dimension.Equals(FrameDimension.Time))
Expand Down Expand Up @@ -163,31 +206,31 @@ private class GifImageData {
//
myNumFrames = image.GetFrameCount(FrameDimension.Time);
myFrameDelaysInCentiseconds = new int[myNumFrames];
populateFrameDelays(image);
PopulateFrameDelays(image);
myCurrentFrame = 0;
myIsDirty = false;
myOnFrameChangedHandler = onFrameChangedHandler;
}

public bool threadIsNotDead() {
public bool ThreadIsNotDead() {
return myIsThreadDead == 0;
}

public void handleUpdateTick() {
public void HandleUpdateTick() {
myCurrentFrame = (myCurrentFrame + 1) % myNumFrames;
myIsDirty = true;
myOnFrameChangedHandler(myImage, EventArgs.Empty);
}

public int getCurrentDelayInMilliseconds() {
public int GetCurrentDelayInMilliseconds() {
return myFrameDelaysInCentiseconds[myCurrentFrame] * 10;
}

public void updateFrame() {
public void UpdateFrame() {
myImage.SelectActiveFrame(FrameDimension.Time, myCurrentFrame);
}

private void populateFrameDelays(Image image) {
private void PopulateFrameDelays(Image image) {
byte[] frameDelays = image.GetPropertyItem(FrameDelayTag).Value;
for (int i = 0; i < myNumFrames; i++) {
myFrameDelaysInCentiseconds[i] = BitConverter.ToInt32(frameDelays, i * 4);
Expand Down
11 changes: 8 additions & 3 deletions Source/Components/ImageGlass.ImageBox/ImageBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public virtual BorderStyle BorderStyle
}

/// <summary>
/// Gets value whether the image can animate or not
/// [PHAP] Gets value whether the image can animate or not
/// </summary>
public bool CanAnimate
{
Expand Down Expand Up @@ -125,6 +125,7 @@ protected virtual void OnBorderStyleChanged(EventArgs e)
}

#endregion

#region Constants

private const int MaxZoom = 3500;
Expand All @@ -143,6 +144,9 @@ protected virtual void OnBorderStyleChanged(EventArgs e)

private bool _allowZoom;

/// <summary>
/// [PHAP]
/// </summary>
private GifAnimator _animator;

private bool _autoCenter;
Expand Down Expand Up @@ -224,13 +228,14 @@ protected virtual void OnBorderStyleChanged(EventArgs e)
#region Public Constructors

/// <summary>
/// Initializes a new instance of the <see cref="ImageBox" /> class.
/// [PHAP] Initializes a new instance of the <see cref="ImageBox" /> class.
/// </summary>
public ImageBox()
{
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.StandardDoubleClick, false);

//[PHAP]
_animator = new DefaultGifAnimator();

_vScrollBar = new VScrollBar
Expand Down Expand Up @@ -1129,7 +1134,7 @@ public virtual bool AllowZoom
}

/// <summary>
/// Handles animating gif images
/// [PHAP] Handles animating gif images
/// </summary>
public GifAnimator Animator {
set {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<Optimize>false</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
Expand Down
10 changes: 5 additions & 5 deletions Source/Components/ImageGlass.ImageBox/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
using System.Runtime.InteropServices;

[assembly: AssemblyTitle("ImageGlass.ImageBox")]
[assembly: AssemblyDescription("A customization ImageBox from Cyotek ImageBox Control")]
[assembly: AssemblyDescription("A customization ImageBox base on Cyotek ImageBox Control of Cyotek Ltd")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Cyotek Ltd")]
[assembly: AssemblyProduct("Cyotek ImageBox Control")]
[assembly: AssemblyCompany("Duong Dieu Phap")]
[assembly: AssemblyProduct("ImageGlass ImageBox Control")]
[assembly: AssemblyCopyright("Copyright © 2010-2015 Cyotek Ltd.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("d812a438-008c-47f9-926f-8415490cdda1")]
[assembly: CLSCompliant(true)]
[assembly: AssemblyVersion("2.0.0.0")]
[assembly: AssemblyFileVersion("2.0.0.0")]
[assembly: AssemblyVersion("4.0.0.0")]
[assembly: AssemblyFileVersion("4.0.0.0")]
26 changes: 25 additions & 1 deletion Source/Components/ImageGlass.Library/WinAPI/TimerAPI.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@
using System.Collections.Generic;
/*
ImageGlass Project - Image viewer for Windows
Copyright (C) 2017 DUONG DIEU PHAP
Project homepage: http://imageglass.org

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/


/******************************************
* THANKS [Meowski] FOR THIS CONTRIBUTION
*******************************************/

using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace ImageGlass.Library.WinAPI {
Expand Down
Loading