diff --git a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs index 25e504831d..a6a02e133a 100644 --- a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs @@ -21,10 +21,11 @@ public static class DrawImageExtensions public static IImageProcessingContext DrawImage( this IImageProcessingContext source, Image foreground, - float opacity) + float opacity, + int repeatCount) { GraphicsOptions options = source.GetGraphicsOptions(); - return DrawImage(source, foreground, options.ColorBlendingMode, options.AlphaCompositionMode, opacity); + return DrawImage(source, foreground, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, repeatCount); } /// @@ -39,10 +40,11 @@ public static IImageProcessingContext DrawImage( this IImageProcessingContext source, Image foreground, Rectangle foregroundRectangle, - float opacity) + float opacity, + int repeatCount) { GraphicsOptions options = source.GetGraphicsOptions(); - return DrawImage(source, foreground, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity); + return DrawImage(source, foreground, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, repeatCount); } /// @@ -57,8 +59,9 @@ public static IImageProcessingContext DrawImage( this IImageProcessingContext source, Image foreground, PixelColorBlendingMode colorBlending, - float opacity) - => DrawImage(source, foreground, Point.Empty, colorBlending, opacity); + float opacity, + int repeatCount) + => DrawImage(source, foreground, Point.Empty, colorBlending, opacity, repeatCount); /// /// Draws the given image together with the currently processing image by blending their pixels. @@ -74,8 +77,9 @@ public static IImageProcessingContext DrawImage( Image foreground, Rectangle foregroundRectangle, PixelColorBlendingMode colorBlending, - float opacity) - => DrawImage(source, foreground, foregroundRectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity); + float opacity, + int repeatCount) + => DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, opacity, repeatCount); /// /// Draws the given image together with the currently processing image by blending their pixels. @@ -91,8 +95,9 @@ public static IImageProcessingContext DrawImage( Image foreground, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, - float opacity) - => DrawImage(source, foreground, Point.Empty, colorBlending, alphaComposition, opacity); + float opacity, + int repeatCount) + => DrawImage(source, foreground, Point.Empty, colorBlending, alphaComposition, opacity, repeatCount); /// /// Draws the given image together with the currently processing image by blending their pixels. @@ -110,8 +115,9 @@ public static IImageProcessingContext DrawImage( Rectangle foregroundRectangle, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, - float opacity) - => DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, alphaComposition, opacity); + float opacity, + int repeatCount) + => DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, alphaComposition, opacity, repeatCount); /// /// Draws the given image together with the currently processing image by blending their pixels. @@ -123,8 +129,9 @@ public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage( this IImageProcessingContext source, Image foreground, - GraphicsOptions options) - => DrawImage(source, foreground, Point.Empty, options); + GraphicsOptions options, + int repeatCount) + => DrawImage(source, foreground, Point.Empty, options, repeatCount); /// /// Draws the given image together with the currently processing image by blending their pixels. @@ -138,8 +145,9 @@ public static IImageProcessingContext DrawImage( this IImageProcessingContext source, Image foreground, Rectangle foregroundRectangle, - GraphicsOptions options) - => DrawImage(source, foreground, Point.Empty, foregroundRectangle, options); + GraphicsOptions options, + int repeatCount) + => DrawImage(source, foreground, Point.Empty, foregroundRectangle, options, repeatCount); /// /// Draws the given image together with the currently processing image by blending their pixels. @@ -153,10 +161,11 @@ public static IImageProcessingContext DrawImage( this IImageProcessingContext source, Image foreground, Point backgroundLocation, - float opacity) + float opacity, + int repeatCount) { GraphicsOptions options = source.GetGraphicsOptions(); - return DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, opacity); + return DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, repeatCount); } /// @@ -173,10 +182,11 @@ public static IImageProcessingContext DrawImage( Image foreground, Point backgroundLocation, Rectangle foregroundRectangle, - float opacity) + float opacity, + int repeatCount) { GraphicsOptions options = source.GetGraphicsOptions(); - return DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity); + return DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, repeatCount); } /// @@ -193,8 +203,9 @@ public static IImageProcessingContext DrawImage( Image foreground, Point backgroundLocation, PixelColorBlendingMode colorBlending, - float opacity) - => DrawImage(source, foreground, backgroundLocation, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity); + float opacity, + int repeatCount) + => DrawImage(source, foreground, backgroundLocation, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity, repeatCount); /// /// Draws the given image together with the currently processing image by blending their pixels. @@ -212,8 +223,9 @@ public static IImageProcessingContext DrawImage( Point backgroundLocation, Rectangle foregroundRectangle, PixelColorBlendingMode colorBlending, - float opacity) - => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity); + float opacity, + int repeatCount) + => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity, repeatCount); /// /// Draws the given image together with the currently processing image by blending their pixels. @@ -227,8 +239,9 @@ public static IImageProcessingContext DrawImage( this IImageProcessingContext source, Image foreground, Point backgroundLocation, - GraphicsOptions options) - => DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage); + GraphicsOptions options, + int repeatCount) + => DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage, repeatCount); /// /// Draws the given image together with the currently processing image by blending their pixels. @@ -244,8 +257,9 @@ public static IImageProcessingContext DrawImage( Image foreground, Point backgroundLocation, Rectangle foregroundRectangle, - GraphicsOptions options) - => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage); + GraphicsOptions options, + int repeatCount) + => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage, repeatCount); /// /// Draws the given image together with the currently processing image by blending their pixels. @@ -263,8 +277,9 @@ public static IImageProcessingContext DrawImage( Point backgroundLocation, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, - float opacity) - => source.ApplyProcessor(new DrawImageProcessor(foreground, backgroundLocation, foreground.Bounds, colorBlending, alphaComposition, opacity)); + float opacity, + int repeatCount) + => source.ApplyProcessor(new DrawImageProcessor(foreground, backgroundLocation, foreground.Bounds, colorBlending, alphaComposition, opacity, repeatCount)); /// /// Draws the given image together with the currently processing image by blending their pixels. @@ -284,8 +299,9 @@ public static IImageProcessingContext DrawImage( Rectangle foregroundRectangle, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, - float opacity) => + float opacity, + int repeatCount) => source.ApplyProcessor( - new DrawImageProcessor(foreground, backgroundLocation, foregroundRectangle, colorBlending, alphaComposition, opacity), + new DrawImageProcessor(foreground, backgroundLocation, foregroundRectangle, colorBlending, alphaComposition, opacity, repeatCount), foregroundRectangle); } diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs index 6ecf16fc6b..3e17dae517 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -19,13 +19,15 @@ public class DrawImageProcessor : IImageProcessor /// The blending mode to use when drawing the image. /// The Alpha blending mode to use when drawing the image. /// The opacity of the image to blend. + /// The loop count. The number of times to loop the animation. 0 means infinitely. public DrawImageProcessor( Image foreground, Point backgroundLocation, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, - float opacity) - : this(foreground, backgroundLocation, foreground.Bounds, colorBlendingMode, alphaCompositionMode, opacity) + float opacity, + int repeatCount) + : this(foreground, backgroundLocation, foreground.Bounds, colorBlendingMode, alphaCompositionMode, opacity, repeatCount) { } @@ -38,13 +40,15 @@ public DrawImageProcessor( /// The blending mode to use when drawing the image. /// The Alpha blending mode to use when drawing the image. /// The opacity of the image to blend. + /// The loop count. The number of times to loop the animation. 0 means infinitely. public DrawImageProcessor( Image foreground, Point backgroundLocation, Rectangle foregroundRectangle, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, - float opacity) + float opacity, + int repeatCount) { this.ForeGround = foreground; this.BackgroundLocation = backgroundLocation; @@ -52,6 +56,7 @@ public DrawImageProcessor( this.ColorBlendingMode = colorBlendingMode; this.AlphaCompositionMode = alphaCompositionMode; this.Opacity = opacity; + this.RepeatCount = repeatCount; } /// @@ -84,6 +89,11 @@ public DrawImageProcessor( /// public float Opacity { get; } + /// + /// Gets the loop count. The number of times to loop the animation. 0 means infinitely. + /// + public int RepeatCount { get; } + /// public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) where TPixelBg : unmanaged, IPixel @@ -122,6 +132,7 @@ public void Visit(Image image) this.definition.ForegroundRectangle, this.definition.ColorBlendingMode, this.definition.AlphaCompositionMode, - this.definition.Opacity); + this.definition.Opacity, + this.definition.RepeatCount); } } diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs index d2a99ce921..0018888653 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -17,6 +17,8 @@ internal class DrawImageProcessor : ImageProcessor where TPixelBg : unmanaged, IPixel where TPixelFg : unmanaged, IPixel { + private int currentFrameLoop; + /// /// Initializes a new instance of the class. /// @@ -28,6 +30,7 @@ internal class DrawImageProcessor : ImageProcessor /// The blending mode to use when drawing the image. /// The alpha blending mode to use when drawing the image. /// The opacity of the image to blend. Must be between 0 and 1. + /// The loop count. The number of times to loop the animation. 0 means infinitely. public DrawImageProcessor( Configuration configuration, Image foregroundImage, @@ -36,9 +39,11 @@ public DrawImageProcessor( Rectangle foregroundRectangle, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, - float opacity) + float opacity, + int repeatCount) : base(configuration, backgroundImage, backgroundImage.Bounds) { + Guard.MustBeGreaterThanOrEqualTo(repeatCount, 0, nameof(repeatCount)); Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); this.ForegroundImage = foregroundImage; @@ -73,6 +78,11 @@ public DrawImageProcessor( /// public Point BackgroundLocation { get; } + /// + /// Gets the loop count. The number of times to loop the animation. 0 means infinitely. + /// + public int RepeatCount { get; } + /// protected override void OnFrameApply(ImageFrame source) { @@ -114,12 +124,13 @@ protected override void OnFrameApply(ImageFrame source) // Sanitize the dimensions so that we don't try and sample outside the image. Rectangle backgroundRectangle = Rectangle.Intersect(new Rectangle(left, top, width, height), this.SourceRectangle); Configuration configuration = this.Configuration; + int currentFrameIndex = this.currentFrameLoop % this.ForegroundImage.Frames.Count; DrawImageProcessor.RowOperation operation = new( configuration, source.PixelBuffer, - this.ForegroundImage.Frames.RootFrame.PixelBuffer, + this.ForegroundImage.Frames[currentFrameIndex].PixelBuffer, backgroundRectangle, foregroundRectangle, this.Blender, @@ -129,6 +140,11 @@ protected override void OnFrameApply(ImageFrame source) configuration, new Rectangle(0, 0, foregroundRectangle.Width, foregroundRectangle.Height), in operation); + + if (this.RepeatCount is 0 || this.currentFrameLoop / this.ForegroundImage.Frames.Count < this.RepeatCount) + { + this.currentFrameLoop++; + } } ///