├── Animators ├── AnimationStatus.cs └── Animator.cs ├── CodeProject_Url.txt ├── EasingFunctions.cs ├── Effects ├── Bounds │ ├── BottomAnchoredHeightEffect.cs │ ├── FoldEffect.cs │ ├── HorizontalFoldEffect.cs │ ├── LeftAnchoredWidthEffect.cs │ ├── RightAnchoredWidthEffect.cs │ ├── TopAnchoredHeightEffect.cs │ ├── VerticalFoldEffect.cs │ ├── XLocationEffect.cs │ └── YLocationEffect.cs ├── Color │ ├── ColorChannelShiftEffect.cs │ └── ColorShiftEffect.cs ├── EffectInteractions.cs ├── IAnimationEffect.cs ├── Opacity │ ├── ControlFadeEffect.cs │ └── FormFadeEffect.cs └── Other │ └── FontSizeEffect.cs ├── ExampleFoldAnimation.cs ├── Extensions ├── AnimationExtensions.cs ├── ControlExtensions.cs └── ImageExtensions.cs ├── Properties └── AssemblyInfo.cs ├── VisualEffects.csproj └── VisualEffects.sln /Animators/AnimationStatus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Diagnostics; 6 | using System.Threading; 7 | 8 | namespace VisualEffects.Animators 9 | { 10 | public class AnimationStatus : EventArgs 11 | { 12 | private Stopwatch _stopwatch; 13 | 14 | public long ElapsedMilliseconds 15 | { 16 | get { return _stopwatch.ElapsedMilliseconds; } 17 | } 18 | public CancellationTokenSource CancellationToken { get; private set; } 19 | public bool IsCompleted { get; set; } 20 | 21 | public AnimationStatus( CancellationTokenSource token, Stopwatch stopwatch ) 22 | { 23 | this.CancellationToken = token; 24 | _stopwatch = stopwatch; 25 | } 26 | public IEffect Effect { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Animators/Animator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Drawing; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Windows.Forms; 9 | using VisualEffects.Animations.Effects; 10 | using VisualEffects.Easing; 11 | using VisualEffects.Animators; 12 | 13 | namespace VisualEffects 14 | { 15 | public static class Animator 16 | { 17 | /*I decided to add no abstraction over animators and provide bare functionality. 18 | *I think nothing is better than a static method here.*/ 19 | 20 | public static event EventHandler Animated; 21 | 22 | /// 23 | /// Animate a control property from its present value to a target one 24 | /// 25 | /// Target control 26 | /// Effect to apply 27 | /// Easing function to apply 28 | /// Target value reached when animation completes 29 | /// Amount of time taken to reach the target value 30 | /// Amount of delay to apply before animation starts 31 | /// If set to true, animation reaches target value and animates back to initial value. It takes 2* 32 | /// If reverse is set to true, indicates how many loops to perform. Negatives or zero mean infinite loop 33 | /// 34 | public static AnimationStatus Animate(Control control, IEffect iEffect, EasingDelegate easing, int valueToReach, int duration, int delay, bool reverse = false, int loops = 1) 35 | { 36 | 37 | try 38 | { 39 | 40 | 41 | //used to calculate animation frame based on how much time has effectively passed 42 | var stopwatch = new Stopwatch(); 43 | 44 | //used to cancel animation 45 | var cancelTokenSource = new CancellationTokenSource(); 46 | 47 | //used to access animation progress 48 | var animationStatus = new AnimationStatus(cancelTokenSource, stopwatch); 49 | animationStatus.Effect = iEffect; 50 | 51 | //This timer allows delayed start. Control's state checks and evaluations are delayed too. 52 | new System.Threading.Timer((state) => 53 | { 54 | //is there anything to do here? 55 | int originalValue = iEffect.GetCurrentValue(control); 56 | if (originalValue == valueToReach) 57 | { 58 | animationStatus.IsCompleted = true; 59 | return; 60 | } 61 | 62 | //upper bound check 63 | int maxVal = iEffect.GetMaximumValue(control); 64 | if (valueToReach > maxVal) 65 | { 66 | string msg = String.Format("Value must be lesser than the maximum allowed. " + 67 | "Max: {0}, provided value: {1}", maxVal, valueToReach); 68 | 69 | throw new ArgumentException(msg, "valueToReach"); 70 | } 71 | 72 | //lower bound check 73 | int minVal = iEffect.GetMinimumValue(control); 74 | if (valueToReach < iEffect.GetMinimumValue(control)) 75 | { 76 | string msg = String.Format("Value must be greater than the minimum allowed. " + 77 | "Min: {0}, provided value: {1}", minVal, valueToReach); 78 | 79 | throw new ArgumentException(msg, "valueToReach"); 80 | } 81 | 82 | bool reversed = false; 83 | int performedLoops = 0; 84 | 85 | int actualValueChange = Math.Abs(originalValue - valueToReach); 86 | 87 | System.Timers.Timer animationTimer = new System.Timers.Timer(); 88 | //adjust interval (naive, edge cases can mess up) 89 | animationTimer.Interval = (duration > actualValueChange) ? 90 | (duration / actualValueChange) : actualValueChange; 91 | 92 | //because of naive interval calculation this is required 93 | if (iEffect.Interaction == EffectInteractions.COLOR) 94 | animationTimer.Interval = 10; 95 | 96 | if (!control.IsDisposed) 97 | { 98 | 99 | 100 | //main animation timer tick 101 | animationTimer.Elapsed += (o, e2) => 102 | { 103 | if (!control.IsDisposed) 104 | { 105 | //cancellation support 106 | if (cancelTokenSource.Token.IsCancellationRequested) 107 | { 108 | animationStatus.IsCompleted = true; 109 | animationTimer.Stop(); 110 | stopwatch.Stop(); 111 | 112 | return; 113 | } 114 | 115 | //main logic 116 | bool increasing = originalValue < valueToReach; 117 | 118 | int minValue = Math.Min(originalValue, valueToReach); 119 | int maxValue = Math.Abs(valueToReach - originalValue); 120 | int newValue = (int)easing(stopwatch.ElapsedMilliseconds, minValue, maxValue, duration); 121 | 122 | if (!increasing) 123 | newValue = (originalValue + valueToReach) - newValue - 1; 124 | 125 | 126 | 127 | 128 | control.BeginInvoke(new MethodInvoker(() => 129 | { 130 | if (!control.IsDisposed && control.IsHandleCreated) 131 | { 132 | iEffect.SetValue(control, originalValue, valueToReach, newValue); 133 | 134 | bool timeout = stopwatch.ElapsedMilliseconds >= duration; 135 | if (timeout) 136 | { 137 | if (reverse && (!reversed || loops <= 0 || performedLoops < loops)) 138 | { 139 | reversed = !reversed; 140 | if (reversed) 141 | performedLoops++; 142 | 143 | int initialValue = originalValue; 144 | int finalValue = valueToReach; 145 | 146 | valueToReach = valueToReach == finalValue ? initialValue : finalValue; 147 | originalValue = valueToReach == finalValue ? initialValue : finalValue; 148 | 149 | stopwatch.Restart(); 150 | animationTimer.Start(); 151 | } 152 | else 153 | { 154 | animationStatus.IsCompleted = true; 155 | animationTimer.Stop(); 156 | stopwatch.Stop(); 157 | 158 | if (Animated != null) 159 | Animated(control, animationStatus); 160 | } 161 | } 162 | } 163 | else 164 | { 165 | if (Animated != null) 166 | Animated(control, animationStatus); 167 | } 168 | })); 169 | } 170 | }; 171 | } 172 | 173 | //start 174 | stopwatch.Start(); 175 | animationTimer.Start(); 176 | 177 | }, null, delay, System.Threading.Timeout.Infinite); 178 | 179 | 180 | return animationStatus; 181 | } 182 | catch (Exception e) 183 | { 184 | if( Debugger.IsAttached) 185 | { 186 | Debug.Print(String.Format("Exception @ VisualEffects.Animator.Animate(). Message: {0}", e.Message)); 187 | Debug.Print(String.Format("Stack:\n{0}", e.Message)); 188 | } 189 | } 190 | return null; 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /CodeProject_Url.txt: -------------------------------------------------------------------------------- 1 | http://www.codeproject.com/Articles/827808/Control-Animation-in-Winforms -------------------------------------------------------------------------------- /EasingFunctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace VisualEffects.Easing 7 | { 8 | public delegate double EasingDelegate( double currentTime, 9 | double minValue, double maxValue, double duration ); 10 | 11 | public class EasingFunctions 12 | { 13 | #region Linear 14 | 15 | /// 16 | /// Easing equation function for a simple linear tweening, with no easing. 17 | /// 18 | public static double Linear( double currentTime, double minHeight, double maxHeight, double duration ) 19 | { 20 | return maxHeight * currentTime / duration + minHeight; 21 | } 22 | 23 | #endregion 24 | 25 | #region Expo 26 | 27 | /// 28 | /// Easing equation function for an exponential (2^currentTime) easing out: 29 | /// decelerating from zero velocity. 30 | /// 31 | public static double ExpoEaseOut( double currentTime, double minHeight, double maxHeight, double duration ) 32 | { 33 | return ( currentTime == duration ) ? minHeight + maxHeight : maxHeight * ( -Math.Pow( 2, -10 * currentTime / duration ) + 1 ) + minHeight; 34 | } 35 | 36 | /// 37 | /// Easing equation function for an exponential (2^currentTime) easing in: 38 | /// accelerating from zero velocity. 39 | /// 40 | public static double ExpoEaseIn( double currentTime, double minHeight, double maxHeight, double duration ) 41 | { 42 | return ( currentTime == 0 ) ? minHeight : maxHeight * Math.Pow( 2, 10 * ( currentTime / duration - 1 ) ) + minHeight; 43 | } 44 | 45 | /// 46 | /// Easing equation function for an exponential (2^currentTime) easing in/out: 47 | /// acceleration until halfway, then deceleration. 48 | /// 49 | public static double ExpoEaseInOut( double currentTime, double minHeight, double maxHeight, double duration ) 50 | { 51 | if( currentTime == 0 ) 52 | return minHeight; 53 | 54 | if( currentTime == duration ) 55 | return minHeight + maxHeight; 56 | 57 | if( ( currentTime /= duration / 2 ) < 1 ) 58 | return maxHeight / 2 * Math.Pow( 2, 10 * ( currentTime - 1 ) ) + minHeight; 59 | 60 | return maxHeight / 2 * ( -Math.Pow( 2, -10 * --currentTime ) + 2 ) + minHeight; 61 | } 62 | 63 | /// 64 | /// Easing equation function for an exponential (2^currentTime) easing out/in: 65 | /// deceleration until halfway, then acceleration. 66 | /// 67 | public static double ExpoEaseOutIn( double currentTime, double minHeight, double maxHeight, double duration ) 68 | { 69 | if( currentTime < duration / 2 ) 70 | return ExpoEaseOut( currentTime * 2, minHeight, maxHeight / 2, duration ); 71 | 72 | return ExpoEaseIn( ( currentTime * 2 ) - duration, minHeight + maxHeight / 2, maxHeight / 2, duration ); 73 | } 74 | 75 | #endregion 76 | 77 | #region Circular 78 | 79 | /// 80 | /// Easing equation function for a circular (sqrt(1-currentTime^2)) easing out: 81 | /// decelerating from zero velocity. 82 | /// 83 | public static double CircEaseOut( double currentTime, double minHeight, double maxHeight, double duration ) 84 | { 85 | return maxHeight * Math.Sqrt( 1 - ( currentTime = currentTime / duration - 1 ) * currentTime ) + minHeight; 86 | } 87 | 88 | /// 89 | /// Easing equation function for a circular (sqrt(1-currentTime^2)) easing in: 90 | /// accelerating from zero velocity. 91 | /// 92 | public static double CircEaseIn( double currentTime, double minHeight, double maxHeight, double duration ) 93 | { 94 | var sqrt = Math.Sqrt( 1 - ( currentTime /= duration ) * currentTime ); 95 | 96 | if( Double.IsNaN( sqrt ) ) 97 | sqrt = 0; 98 | 99 | return -maxHeight * (sqrt - 1 ) + minHeight; 100 | } 101 | 102 | /// 103 | /// Easing equation function for a circular (sqrt(1-currentTime^2)) easing in/out: 104 | /// acceleration until halfway, then deceleration. 105 | /// 106 | public static double CircEaseInOut( double currentTime, double minHeight, double maxHeight, double duration ) 107 | { 108 | if( ( currentTime /= duration / 2 ) < 1 ) 109 | return -maxHeight / 2 * ( Math.Sqrt( 1 - currentTime * currentTime ) - 1 ) + minHeight; 110 | 111 | return maxHeight / 2 * ( Math.Sqrt( 1 - ( currentTime -= 2 ) * currentTime ) + 1 ) + minHeight; 112 | } 113 | 114 | /// 115 | /// Easing equation function for a circular (sqrt(1-currentTime^2)) easing in/out: 116 | /// acceleration until halfway, then deceleration. 117 | /// 118 | public static double CircEaseOutIn( double currentTime, double minHeight, double maxHeight, double duration ) 119 | { 120 | if( currentTime < duration / 2 ) 121 | return CircEaseOut( currentTime * 2, minHeight, maxHeight / 2, duration ); 122 | 123 | return CircEaseIn( ( currentTime * 2 ) - duration, minHeight + maxHeight / 2, maxHeight / 2, duration ); 124 | } 125 | 126 | #endregion 127 | 128 | #region Quad 129 | 130 | /// 131 | /// Easing equation function for a quadratic (currentTime^2) easing out: 132 | /// decelerating from zero velocity. 133 | /// 134 | public static double QuadEaseOut( double currentTime, double minHeight, double maxHeight, double duration ) 135 | { 136 | return -maxHeight * ( currentTime /= duration ) * ( currentTime - 2 ) + minHeight; 137 | } 138 | 139 | /// 140 | /// Easing equation function for a quadratic (currentTime^2) easing in: 141 | /// accelerating from zero velocity. 142 | /// 143 | public static double QuadEaseIn( double currentTime, double minHeight, double maxHeight, double duration ) 144 | { 145 | return maxHeight * ( currentTime /= duration ) * currentTime + minHeight; 146 | } 147 | 148 | /// 149 | /// Easing equation function for a quadratic (currentTime^2) easing in/out: 150 | /// acceleration until halfway, then deceleration. 151 | /// 152 | public static double QuadEaseInOut( double currentTime, double minHeight, double maxHeight, double duration ) 153 | { 154 | if( ( currentTime /= duration / 2 ) < 1 ) 155 | return maxHeight / 2 * currentTime * currentTime + minHeight; 156 | 157 | return -maxHeight / 2 * ( ( --currentTime ) * ( currentTime - 2 ) - 1 ) + minHeight; 158 | } 159 | 160 | /// 161 | /// Easing equation function for a quadratic (currentTime^2) easing out/in: 162 | /// deceleration until halfway, then acceleration. 163 | /// 164 | public static double QuadEaseOutIn( double currentTime, double minHeight, double maxHeight, double duration ) 165 | { 166 | if( currentTime < duration / 2 ) 167 | return QuadEaseOut( currentTime * 2, minHeight, maxHeight / 2, duration ); 168 | 169 | return QuadEaseIn( ( currentTime * 2 ) - duration, minHeight + maxHeight / 2, maxHeight / 2, duration ); 170 | } 171 | 172 | #endregion 173 | 174 | #region Sine 175 | 176 | /// 177 | /// Easing equation function for a sinusoidal (sin(currentTime)) easing out: 178 | /// decelerating from zero velocity. 179 | /// 180 | public static double SineEaseOut( double currentTime, double minHeight, double maxHeight, double duration ) 181 | { 182 | return maxHeight * Math.Sin( currentTime / duration * ( Math.PI / 2 ) ) + minHeight; 183 | } 184 | 185 | /// 186 | /// Easing equation function for a sinusoidal (sin(currentTime)) easing in: 187 | /// accelerating from zero velocity. 188 | /// 189 | public static double SineEaseIn( double currentTime, double minHeight, double maxHeight, double duration ) 190 | { 191 | return -maxHeight * Math.Cos( currentTime / duration * ( Math.PI / 2 ) ) + maxHeight + minHeight; 192 | } 193 | 194 | /// 195 | /// Easing equation function for a sinusoidal (sin(currentTime)) easing in/out: 196 | /// acceleration until halfway, then deceleration. 197 | /// 198 | public static double SineEaseInOut( double currentTime, double minHeight, double maxHeight, double duration ) 199 | { 200 | if( ( currentTime /= duration / 2 ) < 1 ) 201 | return maxHeight / 2 * ( Math.Sin( Math.PI * currentTime / 2 ) ) + minHeight; 202 | 203 | return -maxHeight / 2 * ( Math.Cos( Math.PI * --currentTime / 2 ) - 2 ) + minHeight; 204 | } 205 | 206 | /// 207 | /// Easing equation function for a sinusoidal (sin(currentTime)) easing in/out: 208 | /// deceleration until halfway, then acceleration. 209 | /// 210 | public static double SineEaseOutIn( double currentTime, double minHeight, double maxHeight, double duration ) 211 | { 212 | if( currentTime < duration / 2 ) 213 | return SineEaseOut( currentTime * 2, minHeight, maxHeight / 2, duration ); 214 | 215 | return SineEaseIn( ( currentTime * 2 ) - duration, minHeight + maxHeight / 2, maxHeight / 2, duration ); 216 | } 217 | 218 | #endregion 219 | 220 | #region Cubic 221 | 222 | /// 223 | /// Easing equation function for a cubic (currentTime^3) easing out: 224 | /// decelerating from zero velocity. 225 | /// 226 | public static double CubicEaseOut( double currentTime, double minHeight, double maxHeight, double duration ) 227 | { 228 | return maxHeight * ( ( currentTime = currentTime / duration - 1 ) * currentTime * currentTime + 1 ) + minHeight; 229 | } 230 | 231 | /// 232 | /// Easing equation function for a cubic (currentTime^3) easing in: 233 | /// accelerating from zero velocity. 234 | /// 235 | public static double CubicEaseIn( double currentTime, double minHeight, double maxHeight, double duration ) 236 | { 237 | return maxHeight * ( currentTime /= duration ) * currentTime * currentTime + minHeight; 238 | } 239 | 240 | /// 241 | /// Easing equation function for a cubic (currentTime^3) easing in/out: 242 | /// acceleration until halfway, then deceleration. 243 | /// 244 | public static double CubicEaseInOut( double currentTime, double minHeight, double maxHeight, double duration ) 245 | { 246 | if( ( currentTime /= duration / 2 ) < 1 ) 247 | return maxHeight / 2 * currentTime * currentTime * currentTime + minHeight; 248 | 249 | return maxHeight / 2 * ( ( currentTime -= 2 ) * currentTime * currentTime + 2 ) + minHeight; 250 | } 251 | 252 | /// 253 | /// Easing equation function for a cubic (currentTime^3) easing out/in: 254 | /// deceleration until halfway, then acceleration. 255 | /// 256 | public static double CubicEaseOutIn( double currentTime, double minHeight, double maxHeight, double duration ) 257 | { 258 | if( currentTime < duration / 2 ) 259 | return CubicEaseOut( currentTime * 2, minHeight, maxHeight / 2, duration ); 260 | 261 | return CubicEaseIn( ( currentTime * 2 ) - duration, minHeight + maxHeight / 2, maxHeight / 2, duration ); 262 | } 263 | 264 | #endregion 265 | 266 | #region Quartic 267 | 268 | /// 269 | /// Easing equation function for a quartic (currentTime^4) easing out: 270 | /// decelerating from zero velocity. 271 | /// 272 | public static double QuartEaseOut( double currentTime, double minHeight, double maxHeight, double duration ) 273 | { 274 | return -maxHeight * ( ( currentTime = currentTime / duration - 1 ) * currentTime * currentTime * currentTime - 1 ) + minHeight; 275 | } 276 | 277 | /// 278 | /// Easing equation function for a quartic (currentTime^4) easing in: 279 | /// accelerating from zero velocity. 280 | /// 281 | public static double QuartEaseIn( double currentTime, double minHeight, double maxHeight, double duration ) 282 | { 283 | return maxHeight * ( currentTime /= duration ) * currentTime * currentTime * currentTime + minHeight; 284 | } 285 | 286 | /// 287 | /// Easing equation function for a quartic (currentTime^4) easing in/out: 288 | /// acceleration until halfway, then deceleration. 289 | /// 290 | public static double QuartEaseInOut( double currentTime, double minHeight, double maxHeight, double duration ) 291 | { 292 | if( ( currentTime /= duration / 2 ) < 1 ) 293 | return maxHeight / 2 * currentTime * currentTime * currentTime * currentTime + minHeight; 294 | 295 | return -maxHeight / 2 * ( ( currentTime -= 2 ) * currentTime * currentTime * currentTime - 2 ) + minHeight; 296 | } 297 | 298 | /// 299 | /// Easing equation function for a quartic (currentTime^4) easing out/in: 300 | /// deceleration until halfway, then acceleration. 301 | /// 302 | public static double QuartEaseOutIn( double currentTime, double minHeight, double maxHeight, double duration ) 303 | { 304 | if( currentTime < duration / 2 ) 305 | return QuartEaseOut( currentTime * 2, minHeight, maxHeight / 2, duration ); 306 | 307 | return QuartEaseIn( ( currentTime * 2 ) - duration, minHeight + maxHeight / 2, maxHeight / 2, duration ); 308 | } 309 | 310 | #endregion 311 | 312 | #region Quintic 313 | 314 | /// 315 | /// Easing equation function for a quintic (currentTime^5) easing out: 316 | /// decelerating from zero velocity. 317 | /// 318 | public static double QuintEaseOut( double currentTime, double minHeight, double maxHeight, double duration ) 319 | { 320 | return maxHeight * ( ( currentTime = currentTime / duration - 1 ) * currentTime * currentTime * currentTime * currentTime + 1 ) + minHeight; 321 | } 322 | 323 | /// 324 | /// Easing equation function for a quintic (currentTime^5) easing in: 325 | /// accelerating from zero velocity. 326 | /// 327 | public static double QuintEaseIn( double currentTime, double minHeight, double maxHeight, double duration ) 328 | { 329 | return maxHeight * ( currentTime /= duration ) * currentTime * currentTime * currentTime * currentTime + minHeight; 330 | } 331 | 332 | /// 333 | /// Easing equation function for a quintic (currentTime^5) easing in/out: 334 | /// acceleration until halfway, then deceleration. 335 | /// 336 | public static double QuintEaseInOut( double currentTime, double minHeight, double maxHeight, double duration ) 337 | { 338 | if( ( currentTime /= duration / 2 ) < 1 ) 339 | return maxHeight / 2 * currentTime * currentTime * currentTime * currentTime * currentTime + minHeight; 340 | return maxHeight / 2 * ( ( currentTime -= 2 ) * currentTime * currentTime * currentTime * currentTime + 2 ) + minHeight; 341 | } 342 | 343 | /// 344 | /// Easing equation function for a quintic (currentTime^5) easing in/out: 345 | /// acceleration until halfway, then deceleration. 346 | /// 347 | public static double QuintEaseOutIn( double currentTime, double minHeight, double maxHeight, double duration ) 348 | { 349 | if( currentTime < duration / 2 ) 350 | return QuintEaseOut( currentTime * 2, minHeight, maxHeight / 2, duration ); 351 | return QuintEaseIn( ( currentTime * 2 ) - duration, minHeight + maxHeight / 2, maxHeight / 2, duration ); 352 | } 353 | 354 | #endregion 355 | 356 | #region Elastic 357 | 358 | /// 359 | /// Easing equation function for an elastic (exponentially decaying sine wave) easing out: 360 | /// decelerating from zero velocity. 361 | /// 362 | public static double ElasticEaseOut( double currentTime, double minHeight, double maxHeight, double duration ) 363 | { 364 | if( ( currentTime /= duration ) == 1 ) 365 | return minHeight + maxHeight; 366 | 367 | double p = duration * .3; 368 | double s = p / 4; 369 | 370 | return ( maxHeight * Math.Pow( 2, -10 * currentTime ) * Math.Sin( ( currentTime * duration - s ) * ( 2 * Math.PI ) / p ) + maxHeight + minHeight ); 371 | } 372 | 373 | /// 374 | /// Easing equation function for an elastic (exponentially decaying sine wave) easing in: 375 | /// accelerating from zero velocity. 376 | /// 377 | public static double ElasticEaseIn( double currentTime, double minHeight, double maxHeight, double duration ) 378 | { 379 | if( ( currentTime /= duration ) == 1 ) 380 | return minHeight + maxHeight; 381 | 382 | double p = duration * .3; 383 | double s = p / 4; 384 | 385 | return -( maxHeight * Math.Pow( 2, 10 * ( currentTime -= 1 ) ) * Math.Sin( ( currentTime * duration - s ) * ( 2 * Math.PI ) / p ) ) + minHeight; 386 | } 387 | 388 | /// 389 | /// Easing equation function for an elastic (exponentially decaying sine wave) easing in/out: 390 | /// acceleration until halfway, then deceleration. 391 | /// 392 | public static double ElasticEaseInOut( double currentTime, double minHeight, double maxHeight, double duration ) 393 | { 394 | if( ( currentTime /= duration / 2 ) == 2 ) 395 | return minHeight + maxHeight; 396 | 397 | double p = duration * ( .3 * 1.5 ); 398 | double s = p / 4; 399 | 400 | if( currentTime < 1 ) 401 | return -.5 * ( maxHeight * Math.Pow( 2, 10 * ( currentTime -= 1 ) ) * Math.Sin( ( currentTime * duration - s ) * ( 2 * Math.PI ) / p ) ) + minHeight; 402 | return maxHeight * Math.Pow( 2, -10 * ( currentTime -= 1 ) ) * Math.Sin( ( currentTime * duration - s ) * ( 2 * Math.PI ) / p ) * .5 + maxHeight + minHeight; 403 | } 404 | 405 | /// 406 | /// Easing equation function for an elastic (exponentially decaying sine wave) easing out/in: 407 | /// deceleration until halfway, then acceleration. 408 | /// 409 | public static double ElasticEaseOutIn( double currentTime, double minHeight, double maxHeight, double duration ) 410 | { 411 | if( currentTime < duration / 2 ) 412 | return ElasticEaseOut( currentTime * 2, minHeight, maxHeight / 2, duration ); 413 | return ElasticEaseIn( ( currentTime * 2 ) - duration, minHeight + maxHeight / 2, maxHeight / 2, duration ); 414 | } 415 | 416 | #endregion 417 | 418 | #region Bounce 419 | 420 | /// 421 | /// Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out: 422 | /// decelerating from zero velocity. 423 | /// 424 | public static double BounceEaseOut( double currentTime, double minHeight, double maxHeight, double duration ) 425 | { 426 | if( ( currentTime /= duration ) < ( 1 / 2.75 ) ) 427 | return maxHeight * ( 7.5625 * currentTime * currentTime ) + minHeight; 428 | 429 | if( currentTime < ( 2 / 2.75 ) ) 430 | return maxHeight * ( 7.5625 * ( currentTime -= ( 1.5 / 2.75 ) ) * currentTime + .75 ) + minHeight; 431 | 432 | if( currentTime < ( 2.5 / 2.75 ) ) 433 | return maxHeight * ( 7.5625 * ( currentTime -= ( 2.25 / 2.75 ) ) * currentTime + .9375 ) + minHeight; 434 | 435 | return maxHeight * ( 7.5625 * ( currentTime -= ( 2.625 / 2.75 ) ) * currentTime + .984375 ) + minHeight; 436 | } 437 | 438 | /// 439 | /// Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in: 440 | /// accelerating from zero velocity. 441 | /// 442 | public static double BounceEaseIn( double currentTime, double minHeight, double maxHeight, double duration ) 443 | { 444 | return maxHeight - BounceEaseOut( duration - currentTime, 0, maxHeight, duration ) + minHeight; 445 | } 446 | 447 | /// 448 | /// Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in/out: 449 | /// acceleration until halfway, then deceleration. 450 | /// 451 | public static double BounceEaseInOut( double currentTime, double minHeight, double maxHeight, double duration ) 452 | { 453 | if( currentTime < duration / 2 ) 454 | return BounceEaseIn( currentTime * 2, 0, maxHeight, duration ) * .5 + minHeight; 455 | 456 | return BounceEaseOut( currentTime * 2 - duration, 0, maxHeight, duration ) * .5 + maxHeight * .5 + minHeight; 457 | } 458 | 459 | /// 460 | /// Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out/in: 461 | /// deceleration until halfway, then acceleration. 462 | /// 463 | public static double BounceEaseOutIn( double currentTime, double minHeight, double maxHeight, double duration ) 464 | { 465 | if( currentTime < duration / 2 ) 466 | return BounceEaseOut( currentTime * 2, minHeight, maxHeight / 2, duration ); 467 | 468 | return BounceEaseIn( ( currentTime * 2 ) - duration, minHeight + maxHeight / 2, maxHeight / 2, duration ); 469 | } 470 | 471 | #endregion 472 | 473 | #region Back 474 | 475 | /// 476 | /// Easing equation function for a back (overshooting cubic easing: (s+1)*currentTime^3 - s*currentTime^2) easing out: 477 | /// decelerating from zero velocity. 478 | /// 479 | public static double BackEaseOut( double currentTime, double minHeight, double maxHeight, double duration ) 480 | { 481 | return maxHeight * ( ( currentTime = currentTime / duration - 1 ) * currentTime * ( ( 1.70158 + 1 ) * currentTime + 1.70158 ) + 1 ) + minHeight; 482 | } 483 | 484 | /// 485 | /// Easing equation function for a back (overshooting cubic easing: (s+1)*currentTime^3 - s*currentTime^2) easing in: 486 | /// accelerating from zero velocity. 487 | /// 488 | public static double BackEaseIn( double currentTime, double minHeight, double maxHeight, double duration ) 489 | { 490 | return maxHeight * ( currentTime /= duration ) * currentTime * ( ( 1.70158 + 1 ) * currentTime - 1.70158 ) + minHeight; 491 | } 492 | 493 | /// 494 | /// Easing equation function for a back (overshooting cubic easing: (s+1)*currentTime^3 - s*currentTime^2) easing in/out: 495 | /// acceleration until halfway, then deceleration. 496 | /// 497 | public static double BackEaseInOut( double currentTime, double minHeight, double maxHeight, double duration ) 498 | { 499 | double s = 1.70158; 500 | if( ( currentTime /= duration / 2 ) < 1 ) 501 | return maxHeight / 2 * ( currentTime * currentTime * ( ( ( s *= ( 1.525 ) ) + 1 ) * currentTime - s ) ) + minHeight; 502 | return maxHeight / 2 * ( ( currentTime -= 2 ) * currentTime * ( ( ( s *= ( 1.525 ) ) + 1 ) * currentTime + s ) + 2 ) + minHeight; 503 | } 504 | 505 | /// 506 | /// Easing equation function for a back (overshooting cubic easing: (s+1)*currentTime^3 - s*currentTime^2) easing out/in: 507 | /// deceleration until halfway, then acceleration. 508 | /// 509 | public static double BackEaseOutIn( double currentTime, double minHeight, double maxHeight, double duration ) 510 | { 511 | if( currentTime < duration / 2 ) 512 | return BackEaseOut( currentTime * 2, minHeight, maxHeight / 2, duration ); 513 | return BackEaseIn( ( currentTime * 2 ) - duration, minHeight + maxHeight / 2, maxHeight / 2, duration ); 514 | } 515 | 516 | #endregion 517 | } 518 | } 519 | -------------------------------------------------------------------------------- /Effects/Bounds/BottomAnchoredHeightEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | using System.Drawing; 7 | 8 | namespace VisualEffects.Animations.Effects 9 | { 10 | public class BottomAnchoredHeightEffect : IEffect 11 | { 12 | public int GetCurrentValue( Control control ) 13 | { 14 | return control.Height; 15 | } 16 | 17 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 18 | { 19 | //changing location and size independently can cause flickering: 20 | //change bounds property instead. 21 | 22 | var size = new Size( control.Width, newValue ); 23 | var location = new Point( control.Left, control.Top + 24 | ( control.Height - newValue ) ); 25 | 26 | control.Bounds = new Rectangle( location, size ); 27 | } 28 | 29 | public int GetMinimumValue( Control control ) 30 | { 31 | if( control.MinimumSize.IsEmpty ) 32 | return Int32.MinValue; 33 | 34 | return control.MinimumSize.Height; 35 | } 36 | 37 | public int GetMaximumValue( Control control ) 38 | { 39 | if( control.MaximumSize.IsEmpty ) 40 | return Int32.MaxValue; 41 | 42 | return control.MaximumSize.Height; 43 | } 44 | 45 | public EffectInteractions Interaction 46 | { 47 | get { return EffectInteractions.BOUNDS; } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Effects/Bounds/FoldEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace VisualEffects.Effects.Bounds 7 | { 8 | public class FoldEffect : IEffect 9 | { 10 | public Animations.Effects.EffectInteractions Interaction 11 | { 12 | get { return Animations.Effects.EffectInteractions.BOUNDS; } 13 | } 14 | 15 | public int GetCurrentValue( System.Windows.Forms.Control control ) 16 | { 17 | return control.Width * control.Height; 18 | } 19 | 20 | public void SetValue( System.Windows.Forms.Control control, int originalValue, int valueToReach, int newValue ) 21 | { 22 | int actualValueChange = Math.Abs( originalValue - valueToReach ); 23 | int currentValue = this.GetCurrentValue( control ); 24 | 25 | double absoluteChangePerc = ( (double)( ( originalValue - newValue ) * 100 ) ) / actualValueChange; 26 | absoluteChangePerc = Math.Abs( absoluteChangePerc ); 27 | 28 | if( absoluteChangePerc > 100.0f ) 29 | return; 30 | } 31 | 32 | public int GetMinimumValue( System.Windows.Forms.Control control ) 33 | { 34 | if( control.MinimumSize.IsEmpty ) 35 | return 0; 36 | 37 | return control.MinimumSize.Width * control.MinimumSize.Height; 38 | } 39 | 40 | public int GetMaximumValue( System.Windows.Forms.Control control ) 41 | { 42 | if( control.MaximumSize.IsEmpty ) 43 | return Int32.MaxValue; 44 | 45 | return control.MaximumSize.Width * control.MaximumSize.Height; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Effects/Bounds/HorizontalFoldEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | using System.Drawing; 7 | 8 | namespace VisualEffects.Animations.Effects 9 | { 10 | public class HorizontalFoldEffect : IEffect 11 | { 12 | public int GetCurrentValue( Control control ) 13 | { 14 | return control.Height; 15 | } 16 | 17 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 18 | { 19 | //changing location and size independently can cause flickering: 20 | //change bounds property instead. 21 | 22 | var center = new Point( control.Left, 23 | (int)( ( control.Top + control.Bottom ) / 2 ) ); 24 | 25 | var size = new Size( control.Width, newValue ); 26 | var location = new Point( control.Left, 27 | center.Y - ( newValue / 2 ) ); 28 | 29 | control.Bounds = new Rectangle( location, size ); 30 | } 31 | 32 | public int GetMinimumValue( Control control ) 33 | { 34 | if( control.MinimumSize.IsEmpty ) 35 | return Int32.MinValue; 36 | 37 | return control.MinimumSize.Height; 38 | } 39 | 40 | public int GetMaximumValue( Control control ) 41 | { 42 | if( control.MaximumSize.IsEmpty ) 43 | return Int32.MaxValue; 44 | 45 | return control.MaximumSize.Height; 46 | } 47 | 48 | public EffectInteractions Interaction 49 | { 50 | get { return EffectInteractions.BOUNDS; } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Effects/Bounds/LeftAnchoredWidthEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | 7 | namespace VisualEffects.Animations.Effects 8 | { 9 | public class LeftAnchoredWidthEffect : IEffect 10 | { 11 | public int GetCurrentValue( Control control ) 12 | { 13 | return control.Width; 14 | } 15 | 16 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 17 | { 18 | control.Width = newValue; 19 | } 20 | 21 | public int GetMinimumValue( Control control ) 22 | { 23 | if( control.MinimumSize.IsEmpty ) 24 | return Int32.MinValue; 25 | 26 | return control.MinimumSize.Width; 27 | } 28 | 29 | public int GetMaximumValue( Control control ) 30 | { 31 | if( control.MaximumSize.IsEmpty ) 32 | return Int32.MaxValue; 33 | 34 | return control.MaximumSize.Width; 35 | } 36 | 37 | public EffectInteractions Interaction 38 | { 39 | get { return EffectInteractions.WIDTH; } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Effects/Bounds/RightAnchoredWidthEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | using System.Drawing; 7 | 8 | namespace VisualEffects.Animations.Effects 9 | { 10 | public class RightAnchoredWidthEffect : IEffect 11 | { 12 | public int GetCurrentValue( Control control ) 13 | { 14 | return control.Width; 15 | } 16 | 17 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 18 | { 19 | //changing location and size independently can cause flickering: 20 | //change bounds property instead. 21 | 22 | var size = new Size( newValue, control.Height ); 23 | var location = new Point( control.Left + 24 | ( control.Width - newValue ), control.Top ); 25 | 26 | control.Bounds = new Rectangle( location, size ); 27 | } 28 | 29 | public int GetMinimumValue( Control control ) 30 | { 31 | if( control.MinimumSize.IsEmpty ) 32 | return Int32.MinValue; 33 | 34 | return control.MinimumSize.Width; 35 | } 36 | 37 | public int GetMaximumValue( Control control ) 38 | { 39 | if( control.MaximumSize.IsEmpty ) 40 | return Int32.MaxValue; 41 | 42 | return control.MaximumSize.Width; 43 | } 44 | 45 | public EffectInteractions Interaction 46 | { 47 | get { return EffectInteractions.BOUNDS; } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Effects/Bounds/TopAnchoredHeightEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | 7 | namespace VisualEffects.Animations.Effects 8 | { 9 | public class TopAnchoredHeightEffect : IEffect 10 | { 11 | public int GetCurrentValue( Control control ) 12 | { 13 | return control.Height; 14 | } 15 | 16 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 17 | { 18 | control.Height = newValue; 19 | } 20 | 21 | public int GetMinimumValue( Control control ) 22 | { 23 | return control.MinimumSize.IsEmpty ? Int32.MinValue 24 | : control.MinimumSize.Height; 25 | } 26 | 27 | public int GetMaximumValue( Control control ) 28 | { 29 | return control.MaximumSize.IsEmpty ? Int32.MaxValue 30 | : control.MaximumSize.Height; 31 | } 32 | 33 | public EffectInteractions Interaction 34 | { 35 | get { return EffectInteractions.HEIGHT; } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Effects/Bounds/VerticalFoldEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | using System.Drawing; 7 | 8 | namespace VisualEffects.Animations.Effects 9 | { 10 | public class VerticalFoldEffect : IEffect 11 | { 12 | public int GetCurrentValue( Control control ) 13 | { 14 | return control.Width; 15 | } 16 | 17 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 18 | { 19 | //changing location and size independently can cause flickering: 20 | //change bounds property instead. 21 | 22 | var center = new Point( ( control.Left + control.Right ) / 2, control.Top ); 23 | 24 | var size = new Size( newValue, control.Height ); 25 | var location = new Point( center.X - ( newValue / 2 ), control.Top ); 26 | 27 | control.Bounds = new Rectangle( location, size ); 28 | } 29 | 30 | public int GetMinimumValue( Control control ) 31 | { 32 | if( control.MinimumSize.IsEmpty ) 33 | return Int32.MinValue; 34 | 35 | return control.MinimumSize.Width; 36 | } 37 | 38 | public int GetMaximumValue( Control control ) 39 | { 40 | if( control.MaximumSize.IsEmpty ) 41 | return Int32.MaxValue; 42 | 43 | return control.MaximumSize.Width; 44 | } 45 | 46 | public EffectInteractions Interaction 47 | { 48 | get { return EffectInteractions.BOUNDS; } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Effects/Bounds/XLocationEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | 7 | namespace VisualEffects.Animations.Effects 8 | { 9 | public class XLocationEffect : IEffect 10 | { 11 | public int GetCurrentValue( Control control ) 12 | { 13 | return control.Left; 14 | } 15 | 16 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 17 | { 18 | control.Left = newValue; 19 | } 20 | 21 | public int GetMinimumValue( Control control ) 22 | { 23 | return Int32.MinValue; 24 | } 25 | 26 | public int GetMaximumValue( Control control ) 27 | { 28 | return Int32.MaxValue; 29 | } 30 | 31 | public EffectInteractions Interaction 32 | { 33 | get { return EffectInteractions.X; } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Effects/Bounds/YLocationEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | 7 | namespace VisualEffects.Animations.Effects 8 | { 9 | public class YLocationEffect : IEffect 10 | { 11 | public int GetCurrentValue( Control control ) 12 | { 13 | return control.Top; 14 | } 15 | 16 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 17 | { 18 | control.Top = newValue; 19 | } 20 | 21 | public int GetMinimumValue( Control control ) 22 | { 23 | return Int32.MinValue; 24 | } 25 | 26 | public int GetMaximumValue( Control control ) 27 | { 28 | return Int32.MaxValue; 29 | } 30 | 31 | public EffectInteractions Interaction 32 | { 33 | get { return EffectInteractions.Y; } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Effects/Color/ColorChannelShiftEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Drawing; 6 | using System.Windows.Forms; 7 | 8 | namespace VisualEffects.Animations.Effects 9 | { 10 | public class ColorChannelShiftEffect : IEffect 11 | { 12 | public enum ColorChannels { A, R, G, B }; 13 | public ColorChannels ColorChannel; 14 | 15 | public ColorChannelShiftEffect( ColorChannels channel ) 16 | { 17 | this.ColorChannel = channel; 18 | } 19 | 20 | public EffectInteractions Interaction 21 | { 22 | get { return EffectInteractions.COLOR; } 23 | } 24 | 25 | public int GetCurrentValue( System.Windows.Forms.Control control ) 26 | { 27 | if( ColorChannel == ColorChannels.A ) 28 | return control.BackColor.A; 29 | 30 | if( ColorChannel == ColorChannels.R ) 31 | return control.BackColor.R; 32 | 33 | if( ColorChannel == ColorChannels.G ) 34 | return control.BackColor.G; 35 | 36 | return control.BackColor.B; 37 | } 38 | 39 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 40 | { 41 | if( newValue >= 0 && newValue <= 255 ) 42 | { 43 | int a = control.BackColor.A; 44 | int r = control.BackColor.R; 45 | int g = control.BackColor.G; 46 | int b = control.BackColor.B; 47 | 48 | switch( ColorChannel ) 49 | { 50 | case ColorChannels.A: a = newValue; break; 51 | case ColorChannels.R: r = newValue; break; 52 | case ColorChannels.G: g = newValue; break; 53 | case ColorChannels.B: b = newValue; break; 54 | } 55 | 56 | control.BackColor = Color.FromArgb( a, r, g, b ); 57 | } 58 | } 59 | 60 | public int GetMinimumValue( System.Windows.Forms.Control control ) 61 | { 62 | return 0; 63 | } 64 | 65 | public int GetMaximumValue( System.Windows.Forms.Control control ) 66 | { 67 | return 255; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Effects/Color/ColorShiftEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Drawing; 6 | using System.Windows.Forms; 7 | 8 | namespace VisualEffects.Animations.Effects 9 | { 10 | public class ColorShiftEffect : IEffect 11 | { 12 | public EffectInteractions Interaction 13 | { 14 | get { return EffectInteractions.COLOR; } 15 | } 16 | 17 | public int GetCurrentValue( Control control ) 18 | { 19 | return control.BackColor.ToArgb(); 20 | } 21 | 22 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 23 | { 24 | int actualValueChange = Math.Abs( originalValue - valueToReach ); 25 | int currentValue = this.GetCurrentValue( control ); 26 | 27 | double absoluteChangePerc = ( (double)( ( originalValue - newValue ) * 100 ) ) / actualValueChange; 28 | absoluteChangePerc = Math.Abs( absoluteChangePerc ); 29 | 30 | if( absoluteChangePerc > 100.0f ) 31 | return; 32 | 33 | Color originalColor = Color.FromArgb( originalValue ); 34 | Color newColor = Color.FromArgb( valueToReach ); 35 | 36 | int newA = (int)Interpolate( originalColor.A, newColor.A, absoluteChangePerc ); 37 | int newR = (int)Interpolate( originalColor.R, newColor.R, absoluteChangePerc ); 38 | int newG = (int)Interpolate( originalColor.G, newColor.G, absoluteChangePerc ); 39 | int newB = (int)Interpolate( originalColor.B, newColor.B, absoluteChangePerc ); 40 | 41 | control.BackColor = Color.FromArgb( newA, newR, newG, newB ); 42 | } 43 | 44 | public int GetMinimumValue( Control control ) 45 | { 46 | return Color.Black.ToArgb(); 47 | } 48 | 49 | public int GetMaximumValue( Control control ) 50 | { 51 | return Color.White.ToArgb(); 52 | } 53 | 54 | private int Interpolate( int val1, int val2, double changePerc ) 55 | { 56 | int difference = val2 - val1; 57 | int distance = (int)( difference * ( changePerc / 100 ) ); 58 | return (int)( val1 + distance ); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Effects/EffectInteractions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | using System.Drawing; 7 | 8 | namespace VisualEffects.Animations.Effects 9 | { 10 | [Flags] 11 | public enum EffectInteractions 12 | { 13 | X = 1, 14 | Y = 2, 15 | WIDTH = 8, 16 | HEIGHT = 4, 17 | COLOR = 16, 18 | TRANSPARENCY = 32, 19 | LOCATION = X | Y, 20 | SIZE = WIDTH | HEIGHT, 21 | BOUNDS = X | Y | WIDTH | HEIGHT 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Effects/IAnimationEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | using VisualEffects.Animations.Effects; 7 | 8 | namespace VisualEffects 9 | { 10 | /// 11 | /// By implementing this interface you define what property of your control 12 | /// is manipulated and the way you manipulate it. 13 | /// 14 | public interface IEffect 15 | { 16 | EffectInteractions Interaction { get; } 17 | 18 | int GetCurrentValue( Control control ); 19 | void SetValue( Control control, int originalValue, int valueToReach, int newValue ); 20 | 21 | int GetMinimumValue( Control control ); 22 | int GetMaximumValue( Control control ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Effects/Opacity/ControlFadeEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | using System.Drawing; 7 | using System.Drawing.Drawing2D; 8 | using System.Drawing.Imaging; 9 | using VisualEffects; 10 | 11 | namespace VisualEffects.Animations.Effects 12 | { 13 | public class ControlFadeEffect : IEffect 14 | { 15 | public const int MAX_OPACITY = 100; 16 | public const int MIN_OPACITY = 0; 17 | 18 | private class State 19 | { 20 | public int Opacity { get; set; } 21 | public Graphics ParentGraphics { get; set; } 22 | public Rectangle PreviousBounds { get; set; } 23 | public Bitmap Snapshot { get; set; } 24 | } 25 | 26 | private static Dictionary _controlCache 27 | = new Dictionary(); 28 | 29 | public ControlFadeEffect( Control control ) 30 | { 31 | if( !_controlCache.ContainsKey( control ) ) 32 | { 33 | var parentGraphics = control.Parent.CreateGraphics(); 34 | parentGraphics.CompositingQuality = CompositingQuality.HighSpeed; 35 | 36 | var state = new State() 37 | { 38 | ParentGraphics = parentGraphics, 39 | Opacity = control.Visible ? MAX_OPACITY : MIN_OPACITY, 40 | }; 41 | 42 | _controlCache.Add( control, state ); 43 | } 44 | } 45 | 46 | public int GetCurrentValue( Control control ) 47 | { 48 | return _controlCache[ control ].Opacity; 49 | } 50 | 51 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 52 | { 53 | var state = _controlCache[ control ]; 54 | 55 | //invalidate region no more in use 56 | var region = new Region( state.PreviousBounds ); 57 | region.Exclude( control.Bounds ); 58 | control.Parent.Invalidate( region ); 59 | 60 | //I get real-time snapshot (no cache) so i can mix animations 61 | var snapshot = control.GetSnapshot(); 62 | if( snapshot != null ) 63 | { 64 | snapshot = (Bitmap)snapshot.ChangeOpacity( newValue ); 65 | //avoid refresh and thus flickering: blend parent's background with snapshot 66 | var bgBlendedSnapshot = BlendWithBgColor( snapshot, control.Parent.BackColor ); 67 | state.Snapshot = bgBlendedSnapshot; 68 | } 69 | state.PreviousBounds = control.Bounds; 70 | 71 | if( newValue == MAX_OPACITY ) 72 | { 73 | control.Visible = true; 74 | return; 75 | } 76 | 77 | control.Visible = false; 78 | state.Opacity = newValue; 79 | 80 | if( newValue > 0 ) 81 | { 82 | var rect = control.Parent.RectangleToClient( 83 | control.RectangleToScreen( control.ClientRectangle ) ); 84 | 85 | if( state.Snapshot != null ) 86 | state.ParentGraphics.DrawImage( state.Snapshot, rect ); 87 | } 88 | else 89 | { 90 | control.Parent.Invalidate(); 91 | } 92 | } 93 | 94 | public int GetMinimumValue( Control control ) 95 | { 96 | return MIN_OPACITY; 97 | } 98 | 99 | public int GetMaximumValue( Control control ) 100 | { 101 | return MAX_OPACITY; 102 | } 103 | 104 | public EffectInteractions Interaction 105 | { 106 | get { return EffectInteractions.TRANSPARENCY; } 107 | } 108 | 109 | private Bitmap BlendWithBgColor( Image image1, Color bgColor ) 110 | { 111 | var finalImage = new Bitmap( image1.Width, image1.Height ); 112 | using( Graphics g = Graphics.FromImage( finalImage ) ) 113 | { 114 | g.Clear( Color.Black ); 115 | 116 | g.FillRectangle( new SolidBrush( bgColor ), new Rectangle( 0, 0, image1.Width, image1.Height ) ); 117 | g.DrawImage( image1, new Rectangle( 0, 0, image1.Width, image1.Height ) ); 118 | } 119 | 120 | return finalImage; 121 | } 122 | } 123 | 124 | /// 125 | /// tries to merge form snapshot and control snapshot 126 | /// 127 | public class ControlFadeEffect2 : IEffect 128 | { 129 | public const int MAX_OPACITY = 100; 130 | public const int MIN_OPACITY = 0; 131 | 132 | private class State 133 | { 134 | public int Opacity { get; set; } 135 | public Graphics ParentGraphics { get; set; } 136 | public Rectangle PreviousBounds { get; set; } 137 | public Bitmap Snapshot { get; set; } 138 | } 139 | 140 | private static Dictionary _controlCache 141 | = new Dictionary(); 142 | 143 | public ControlFadeEffect2( Control control ) 144 | { 145 | if( !_controlCache.ContainsKey( control ) ) 146 | { 147 | var parentGraphics = control.Parent.CreateGraphics(); 148 | parentGraphics.CompositingQuality = CompositingQuality.HighSpeed; 149 | 150 | var state = new State() 151 | { 152 | ParentGraphics = parentGraphics, 153 | Opacity = control.Visible ? MAX_OPACITY : MIN_OPACITY, 154 | }; 155 | 156 | _controlCache.Add( control, state ); 157 | } 158 | } 159 | 160 | public int GetCurrentValue( Control control ) 161 | { 162 | return _controlCache[ control ].Opacity; 163 | } 164 | 165 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 166 | { 167 | var state = _controlCache[ control ]; 168 | 169 | //invalidate region no more in use 170 | var region = new Region( state.PreviousBounds ); 171 | region.Exclude( control.Bounds ); 172 | control.Parent.Invalidate( region ); 173 | 174 | var form = control.FindForm(); 175 | var formRelativeCoords = form.RectangleToClient( control.RectangleToScreen( control.ClientRectangle ) ); 176 | 177 | //I get real-time snapshot (no cache) so i can mix animations 178 | var controlSnapshot = control.GetSnapshot(); 179 | if( controlSnapshot != null ) 180 | { 181 | controlSnapshot = (Bitmap)controlSnapshot.ChangeOpacity( newValue ); 182 | 183 | 184 | var formSnapshot = form.GetFormBorderlessSnapshot().Clone( formRelativeCoords, PixelFormat.DontCare ); 185 | 186 | //avoid refresh and thus flickering: blend parent form snapshot with control snapshot 187 | var bgBlendedSnapshot = this.BlendImages( formSnapshot, controlSnapshot ); 188 | //bgBlendedSnapshot.Save( @"C:\Users\Sampietro.Mauro\Documents\_root\bmp" + newValue + ".bmp" ); 189 | state.Snapshot = bgBlendedSnapshot; 190 | } 191 | state.PreviousBounds = control.Bounds; 192 | 193 | if( newValue == MAX_OPACITY ) 194 | { 195 | control.Visible = true; 196 | return; 197 | } 198 | 199 | control.Visible = false; 200 | state.Opacity = newValue; 201 | 202 | if( newValue > 0 ) 203 | { 204 | //var rect = control.Parent.RectangleToClient( 205 | // control.RectangleToScreen( control.ClientRectangle ) ); 206 | 207 | form.CreateGraphics().DrawImage( state.Snapshot, formRelativeCoords ); 208 | //if( state.Snapshot != null ) 209 | // state.ParentGraphics.DrawImage( state.Snapshot, rect ); 210 | } 211 | else 212 | { 213 | control.Parent.Invalidate(); 214 | } 215 | } 216 | 217 | public int GetMinimumValue( Control control ) 218 | { 219 | return MIN_OPACITY; 220 | } 221 | 222 | public int GetMaximumValue( Control control ) 223 | { 224 | return MAX_OPACITY; 225 | } 226 | 227 | public EffectInteractions Interaction 228 | { 229 | get { return EffectInteractions.TRANSPARENCY; } 230 | } 231 | 232 | private Bitmap BlendImages( Image image1, Image image2 ) 233 | { 234 | var finalImage = new Bitmap( image1.Width, image1.Height ); 235 | using( Graphics g = Graphics.FromImage( finalImage ) ) 236 | { 237 | g.Clear( Color.Black ); 238 | 239 | g.DrawImage( image1, new Rectangle( 0, 0, image1.Width, image1.Height ) ); 240 | g.DrawImage( image2, new Rectangle( 0, 0, image1.Width, image1.Height ) ); 241 | } 242 | 243 | return finalImage; 244 | } 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /Effects/Opacity/FormFadeEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | 7 | namespace VisualEffects.Animations.Effects 8 | { 9 | public class FormFadeEffect : IEffect 10 | { 11 | public int GetCurrentValue( Control control ) 12 | { 13 | if( !( control is Form ) ) 14 | throw new Exception( "Fading effect can be applied only on forms" ); 15 | 16 | var form = (Form)control; 17 | return (int)( form.Opacity * 100 ); 18 | } 19 | 20 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 21 | { 22 | if( !( control is Form ) ) 23 | throw new Exception( "Fading effect can be applied only on forms" ); 24 | 25 | var form = (Form)control; 26 | form.Opacity = ( (float)newValue ) / 100; 27 | } 28 | 29 | public int GetMinimumValue( Control control ) 30 | { 31 | return 0; 32 | } 33 | 34 | public int GetMaximumValue( Control control ) 35 | { 36 | return 100; 37 | } 38 | 39 | public EffectInteractions Interaction 40 | { 41 | get { return EffectInteractions.TRANSPARENCY; } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Effects/Other/FontSizeEffect.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | 7 | namespace VisualEffects.Animations.Effects 8 | { 9 | public class FontSizeEffect : IEffect 10 | { 11 | public EffectInteractions Interaction 12 | { 13 | get { return EffectInteractions.SIZE; } 14 | } 15 | 16 | public int GetCurrentValue( System.Windows.Forms.Control control ) 17 | { 18 | return (int)control.Font.SizeInPoints; 19 | } 20 | 21 | public void SetValue( Control control, int originalValue, int valueToReach, int newValue ) 22 | { 23 | control.Font = new System.Drawing.Font( control.Font.FontFamily, newValue ); 24 | } 25 | 26 | public int GetMinimumValue( System.Windows.Forms.Control control ) 27 | { 28 | return 0; 29 | } 30 | 31 | public int GetMaximumValue( System.Windows.Forms.Control control ) 32 | { 33 | return Int32.MaxValue; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ExampleFoldAnimation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | using VisualEffects.Animations.Effects; 7 | using System.Drawing; 8 | using System.Threading; 9 | using VisualEffects.Animations; 10 | using System.Collections.ObjectModel; 11 | using VisualEffects.Easing; 12 | using VisualEffects.Animators; 13 | 14 | namespace VisualEffects 15 | { 16 | public class ExampleFoldAnimation 17 | { 18 | private List _cancellationTokens; 19 | 20 | public Control Control { get; private set; } 21 | public Size MaxSize { get; set; } 22 | public Size MinSize { get; set; } 23 | public int Duration { get; set; } 24 | public int Delay { get; set; } 25 | 26 | public ExampleFoldAnimation( Control control ) 27 | { 28 | _cancellationTokens = new List(); 29 | 30 | this.Control = control; 31 | this.MaxSize = control.Size; 32 | this.MinSize = control.MinimumSize; 33 | this.Duration = 1000; 34 | this.Delay = 0; 35 | } 36 | 37 | public void Show() 38 | { 39 | int duration = this.Duration; 40 | if( _cancellationTokens.Any( animation => !animation.IsCompleted ) ) 41 | { 42 | var token = _cancellationTokens.First( animation => !animation.IsCompleted ); 43 | duration = (int)( token.ElapsedMilliseconds ); 44 | } 45 | 46 | //cancel hide animation if in progress 47 | this.Cancel(); 48 | 49 | var cT1 = this.Control.Animate( new HorizontalFoldEffect(), 50 | EasingFunctions.CircEaseIn, this.MaxSize.Height, duration, this.Delay ); 51 | 52 | var cT2 = this.Control.Animate( new VerticalFoldEffect(), 53 | EasingFunctions.CircEaseOut, this.MaxSize.Width, duration, this.Delay ); 54 | 55 | _cancellationTokens.Add( cT1 ); 56 | _cancellationTokens.Add( cT2 ); 57 | } 58 | 59 | public void Hide() 60 | { 61 | int duration = this.Duration; 62 | 63 | if( _cancellationTokens.Any( animation => !animation.IsCompleted ) ) 64 | { 65 | var token = _cancellationTokens.First( animation => !animation.IsCompleted ); 66 | duration = (int)( token.ElapsedMilliseconds ); 67 | } 68 | 69 | //cancel show animation if in progress 70 | this.Cancel(); 71 | 72 | var cT1 = this.Control.Animate( new HorizontalFoldEffect(), 73 | EasingFunctions.CircEaseOut, this.MinSize.Height, duration, this.Delay ); 74 | 75 | var cT2 = this.Control.Animate( new VerticalFoldEffect(), 76 | EasingFunctions.CircEaseIn, this.MinSize.Width, duration, this.Delay ); 77 | 78 | _cancellationTokens.Add( cT1 ); 79 | _cancellationTokens.Add( cT2 ); 80 | } 81 | 82 | public void Cancel() 83 | { 84 | foreach( var token in _cancellationTokens ) 85 | token.CancellationToken.Cancel(); 86 | 87 | _cancellationTokens.Clear(); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Extensions/AnimationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Forms; 6 | using System.Threading; 7 | using VisualEffects.Easing; 8 | using VisualEffects.Animators; 9 | 10 | namespace VisualEffects 11 | { 12 | public static class AnimationExtensions 13 | { 14 | public static AnimationStatus Animate( this Control control, IEffect iAnimation, 15 | EasingDelegate easing, int valueToReach, int duration, int delay, bool reverse = false, int loops = 1 ) 16 | { 17 | return Animator.Animate( control, iAnimation, easing, valueToReach, duration, delay, reverse, loops ); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Extensions/ControlExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Drawing; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Windows.Forms; 7 | 8 | namespace VisualEffects 9 | { 10 | public static class ControlExtensions 11 | { 12 | public static void SelectNextControl( this Control initialControl ) 13 | { 14 | if( initialControl != null ) 15 | { 16 | var ctrlSelected = initialControl.SelectNextControl( initialControl, true, true, false, false ); 17 | if( !ctrlSelected ) 18 | SelectNextControl( initialControl.Parent ); 19 | } 20 | } 21 | 22 | public static Bitmap GetSnapshot( this Control control ) 23 | { 24 | if( control.Width <= 0 || control.Height <= 0 ) 25 | return null; 26 | 27 | Bitmap image = new Bitmap( control.Width, control.Height ); 28 | Rectangle targetBounds = new Rectangle( 0, 0, control.Width, control.Height ); 29 | 30 | control.DrawToBitmap( image, targetBounds ); 31 | return image; 32 | } 33 | 34 | public static Bitmap GetFormBorderlessSnapshot( this Form window ) 35 | { 36 | using( var bmp = new Bitmap( window.Width, window.Height ) ) 37 | { 38 | window.DrawToBitmap( bmp, new Rectangle( 0, 0, window.Width, window.Height ) ); 39 | 40 | Point point = window.PointToScreen( Point.Empty ); 41 | 42 | Bitmap target = new Bitmap( window.ClientSize.Width, window.ClientSize.Height ); 43 | using( Graphics g = Graphics.FromImage( target ) ) 44 | { 45 | var srcRect = new Rectangle( point.X - window.Location.X, 46 | point.Y - window.Location.Y, target.Width, target.Height ); 47 | 48 | g.DrawImage( bmp, 0, 0, srcRect, GraphicsUnit.Pixel ); 49 | } 50 | 51 | return target; 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Extensions/ImageExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.Drawing.Drawing2D; 4 | using System.Drawing.Imaging; 5 | using System.IO; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace VisualEffects 9 | { 10 | public static class ImageExtensions 11 | { 12 | public static bool IsBlank( this Image img, int threshold, int checkOnePixelEveryN = 1 ) 13 | { 14 | if( checkOnePixelEveryN <= 0 ) 15 | throw new ArgumentException( "Must check at least one pixel every 1 pixel (every pixel)" ); 16 | 17 | return img.GetStandardDeviation() < threshold; 18 | } 19 | 20 | /// 21 | /// Get the standard deviation of pixel values. 22 | /// 23 | /// Name of the image file. 24 | /// Standard deviation. 25 | private static double GetStandardDeviation( this Image img, int checkOnePixelEveryN = 1 ) 26 | { 27 | if( checkOnePixelEveryN <= 0 ) 28 | throw new ArgumentException( "Must check at least one pixel every 1 pixel (every pixel)" ); 29 | 30 | double total = 0, totalVariance = 0; 31 | int count = 1; 32 | double stdDev = 0; 33 | 34 | // First get all the bytes 35 | using( Bitmap bmp = new Bitmap( img ) ) 36 | { 37 | BitmapData bmData = bmp.LockBits( new Rectangle( 0, 0, bmp.Width, bmp.Height ), ImageLockMode.ReadOnly, bmp.PixelFormat ); 38 | int stride = bmData.Stride; 39 | IntPtr Scan0 = bmData.Scan0; 40 | unsafe 41 | { 42 | byte* pointer = (byte*)Scan0; 43 | int nOffset = stride - bmp.Width * 3; 44 | 45 | for( int y = 0; y < bmp.Height; pointer += nOffset, y += checkOnePixelEveryN ) 46 | { 47 | for( int x = 0; x < bmp.Width; count++, pointer += 3, x += checkOnePixelEveryN ) 48 | { 49 | byte blue = pointer[ 0 ]; 50 | byte green = pointer[ 1 ]; 51 | byte red = pointer[ 2 ]; 52 | 53 | int pixelValue = Color.FromArgb( 0, red, green, blue ).ToArgb(); 54 | total += pixelValue; 55 | 56 | double avg = total / count; 57 | totalVariance += Math.Pow( pixelValue - avg, 2 ); 58 | stdDev = Math.Sqrt( totalVariance / count ); 59 | } 60 | } 61 | } 62 | 63 | bmp.UnlockBits( bmData ); 64 | } 65 | 66 | return stdDev; 67 | } 68 | 69 | /// 70 | /// Resize an image by a percentage factor 71 | /// 72 | /// Source image 73 | /// Scaled image 74 | public static Image ScaleByPercentage( this Image image, int percent ) 75 | { 76 | float nPercent = ( (float)percent / 100 ); 77 | 78 | int destWidth = (int)( image.Width - ( image.Width * nPercent ) ); 79 | int destHeight = (int)( image.Height - ( image.Height * nPercent ) ); 80 | 81 | Bitmap bmp = new Bitmap( destWidth, destHeight, PixelFormat.Format24bppRgb ); 82 | bmp.SetResolution( image.HorizontalResolution, image.VerticalResolution ); 83 | 84 | using( Graphics graphics = Graphics.FromImage( bmp ) ) 85 | { 86 | graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; 87 | 88 | var destRect = new Rectangle( 0, 0, destWidth, destHeight ); 89 | var srcRect = new Rectangle( 0, 0, image.Width, image.Height ); 90 | 91 | graphics.DrawImage( image, destRect, srcRect, GraphicsUnit.Pixel ); 92 | } 93 | 94 | return bmp; 95 | } 96 | 97 | public static Image Resize( this Image image, Size newSize ) 98 | { 99 | Bitmap bmp = new Bitmap( newSize.Width, newSize.Height ); 100 | using( var gx = Graphics.FromImage( (Image)bmp ) ) 101 | { 102 | gx.InterpolationMode = InterpolationMode.HighQualityBicubic; 103 | gx.DrawImage( image, 0, 0, newSize.Width, newSize.Height ); 104 | } 105 | 106 | return (Image)bmp; 107 | } 108 | 109 | public static Image ToGrayscale( this Image source ) 110 | { 111 | var bmp = new Bitmap( source.Width, source.Height ); 112 | 113 | using( var graphics = Graphics.FromImage( bmp ) ) 114 | { 115 | var colorMatrix = new ColorMatrix 116 | ( 117 | new float[][] 118 | { 119 | new float[] { 0.5f, 0.5f, 0.5f, 0, 0 }, 120 | new float[] { 0.5f, 0.5f, 0.5f, 0, 0 }, 121 | new float[] { 0.5f, 0.5f, 0.5f, 0, 0 }, 122 | new float[] { 0, 0, 0, 1, 0, 0 }, 123 | new float[] { 0, 0, 0, 0, 1, 0 }, 124 | new float[] { 0, 0, 0, 0, 0, 1 } 125 | } 126 | ); 127 | 128 | var imageAttrs = new ImageAttributes(); 129 | imageAttrs.SetColorMatrix( colorMatrix, ColorMatrixFlag.SkipGrays ); 130 | 131 | var destRect = new Rectangle( 0, 0, source.Width, source.Height ); 132 | graphics.DrawImage( source, destRect, 0, 0, source.Width, source.Height, GraphicsUnit.Pixel, imageAttrs ); 133 | } 134 | 135 | return bmp; 136 | } 137 | 138 | /// 139 | /// 140 | /// 141 | /// 142 | /// A value between 0 (full transparency) and 100 (full opacity) 143 | /// 144 | public static Image ChangeOpacity( this Image image, int opacity ) 145 | { 146 | opacity = opacity < 0 ? 0 : opacity; 147 | opacity = opacity > 100 ? 100 : opacity; 148 | 149 | //create a Bitmap the size of the image provided 150 | Bitmap bmp = new Bitmap( image.Width, image.Height ); 151 | 152 | //create a graphics object from the image 153 | using( Graphics gfx = Graphics.FromImage( bmp ) ) 154 | { 155 | //create a color matrix object 156 | ColorMatrix matrix = new ColorMatrix(); 157 | 158 | //set the opacity 159 | matrix.Matrix33 = ( (float)opacity ) / 100; 160 | 161 | //create image attributes 162 | ImageAttributes attributes = new ImageAttributes(); 163 | 164 | //set the color (opacity) of the image 165 | attributes.SetColorMatrix( matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap ); 166 | 167 | //now draw the image 168 | gfx.DrawImage( image, new Rectangle( 0, 0, bmp.Width, bmp.Height ), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes ); 169 | } 170 | 171 | return bmp; 172 | } 173 | 174 | public static Image ToBlackWhite( this Image image, float threshold = 0.7f ) 175 | { 176 | var outImage = new Bitmap( image.Width, image.Height, PixelFormat.Format32bppArgb ); 177 | using( Graphics gr = Graphics.FromImage( outImage ) ) 178 | { 179 | var grayMatrix = new ColorMatrix( new float[][] 180 | { 181 | new float[] { 0.299f, 0.299f, 0.299f, 0, 0 }, 182 | new float[] { 0.587f, 0.587f, 0.587f, 0, 0 }, 183 | new float[] { 0.114f, 0.114f, 0.114f, 0, 0 }, 184 | new float[] { 0, 0, 0, 1, 0 }, 185 | new float[] { 0, 0, 0, 0, 1 } 186 | } ); 187 | 188 | var ia = new ImageAttributes(); 189 | ia.SetColorMatrix( grayMatrix ); 190 | ia.SetThreshold( threshold ); 191 | 192 | var rc = new Rectangle( 0, 0, image.Width, image.Height ); 193 | gr.DrawImage( image, rc, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, ia ); 194 | 195 | return outImage; 196 | } 197 | } 198 | 199 | public static MemoryStream ToStream( this Image image, ImageFormat format ) 200 | { 201 | var stream = new MemoryStream(); 202 | image.Save( stream, format ); 203 | stream.Position = 0; 204 | 205 | return stream; 206 | } 207 | 208 | public static bool Equals( this Bitmap bmp1, Bitmap bmp2 ) 209 | { 210 | Rectangle rect = new Rectangle( 0, 0, bmp1.Width, bmp1.Height ); 211 | BitmapData bmpData1 = bmp1.LockBits( rect, ImageLockMode.ReadOnly, bmp1.PixelFormat ); 212 | BitmapData bmpData2 = bmp2.LockBits( rect, ImageLockMode.ReadOnly, bmp2.PixelFormat ); 213 | 214 | try 215 | { 216 | unsafe 217 | { 218 | byte* ptr1 = (byte*)bmpData1.Scan0.ToPointer(); 219 | byte* ptr2 = (byte*)bmpData2.Scan0.ToPointer(); 220 | int width = rect.Width * 3; // for 24bpp pixel data 221 | 222 | for( int y = 0; y < rect.Height; y++ ) 223 | { 224 | for( int x = 0; x < width; x++ ) 225 | { 226 | if( *ptr1 != *ptr2 ) 227 | return false; 228 | 229 | ptr1++; 230 | ptr2++; 231 | } 232 | ptr1 += bmpData1.Stride - width; 233 | ptr2 += bmpData2.Stride - width; 234 | } 235 | } 236 | } 237 | finally 238 | { 239 | bmp1.UnlockBits( bmpData1 ); 240 | bmp2.UnlockBits( bmpData2 ); 241 | } 242 | 243 | return true; 244 | } 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle( "VisualEffects" )] 9 | [assembly: AssemblyDescription( "" )] 10 | [assembly: AssemblyConfiguration( "" )] 11 | [assembly: AssemblyCompany( "" )] 12 | [assembly: AssemblyProduct( "VisualEffects" )] 13 | [assembly: AssemblyCopyright( "Copyright © 2014" )] 14 | [assembly: AssemblyTrademark( "" )] 15 | [assembly: AssemblyCulture( "" )] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible( false )] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid( "8e71ace0-a00a-469b-9fb0-978988f54a6c" )] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion( "1.0.0.0" )] 36 | [assembly: AssemblyFileVersion( "1.0.0.0" )] 37 | -------------------------------------------------------------------------------- /VisualEffects.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {88C2E4D2-1237-4616-9F74-2D0A4AF06009} 9 | Library 10 | Properties 11 | VisualEffects 12 | VisualEffects 13 | v4.5 14 | 512 15 | SAK 16 | SAK 17 | SAK 18 | SAK 19 | 20 | 21 | 22 | true 23 | full 24 | false 25 | bin\Debug\ 26 | DEBUG;TRACE 27 | prompt 28 | 4 29 | true 30 | false 31 | 32 | 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE 37 | prompt 38 | 4 39 | true 40 | false 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 90 | -------------------------------------------------------------------------------- /VisualEffects.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VisualEffects", "VisualEffects.csproj", "{88C2E4D2-1237-4616-9F74-2D0A4AF06009}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {88C2E4D2-1237-4616-9F74-2D0A4AF06009}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {88C2E4D2-1237-4616-9F74-2D0A4AF06009}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {88C2E4D2-1237-4616-9F74-2D0A4AF06009}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {88C2E4D2-1237-4616-9F74-2D0A4AF06009}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(TeamFoundationVersionControl) = preSolution 23 | SccNumberOfProjects = 2 24 | SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} 25 | SccTeamFoundationServer = https://slx.visualstudio.com/defaultcollection 26 | SccLocalPath0 = . 27 | SccProjectUniqueName1 = VisualEffects.csproj 28 | SccLocalPath1 = . 29 | EndGlobalSection 30 | EndGlobal 31 | --------------------------------------------------------------------------------