diff --git a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs
index 25e504831d..42051ca939 100644
--- a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs
@@ -17,14 +17,19 @@ public static class DrawImageExtensions
/// The current image processing context.
/// The image to draw on the currently processing image.
/// The opacity of the image to draw. Must be between 0 and 1.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image foreground,
- float opacity)
+ float opacity,
+ int foregroundRepeatCount = 0)
{
GraphicsOptions options = source.GetGraphicsOptions();
- return DrawImage(source, foreground, options.ColorBlendingMode, options.AlphaCompositionMode, opacity);
+ return DrawImage(source, foreground, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, foregroundRepeatCount);
}
///
@@ -34,15 +39,20 @@ public static IImageProcessingContext DrawImage(
/// The image to draw on the currently processing image.
/// The rectangle structure that specifies the portion of the image to draw.
/// The opacity of the image to draw. Must be between 0 and 1.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image foreground,
Rectangle foregroundRectangle,
- float opacity)
+ float opacity,
+ int foregroundRepeatCount = 0)
{
GraphicsOptions options = source.GetGraphicsOptions();
- return DrawImage(source, foreground, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity);
+ return DrawImage(source, foreground, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, foregroundRepeatCount);
}
///
@@ -52,13 +62,18 @@ public static IImageProcessingContext DrawImage(
/// The image to draw on the currently processing image.
/// The color blending mode.
/// The opacity of the image to draw. Must be between 0 and 1.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image foreground,
PixelColorBlendingMode colorBlending,
- float opacity)
- => DrawImage(source, foreground, Point.Empty, colorBlending, opacity);
+ float opacity,
+ int foregroundRepeatCount = 0)
+ => DrawImage(source, foreground, Point.Empty, colorBlending, opacity, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -68,14 +83,19 @@ public static IImageProcessingContext DrawImage(
/// The rectangle structure that specifies the portion of the image to draw.
/// The color blending mode.
/// The opacity of the image to draw. Must be between 0 and 1.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image foreground,
Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlending,
- float opacity)
- => DrawImage(source, foreground, foregroundRectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity);
+ float opacity,
+ int foregroundRepeatCount = 0)
+ => DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, opacity, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -85,14 +105,19 @@ public static IImageProcessingContext DrawImage(
/// The color blending mode.
/// The alpha composition mode.
/// The opacity of the image to draw. Must be between 0 and 1.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image foreground,
PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition,
- float opacity)
- => DrawImage(source, foreground, Point.Empty, colorBlending, alphaComposition, opacity);
+ float opacity,
+ int foregroundRepeatCount = 0)
+ => DrawImage(source, foreground, Point.Empty, colorBlending, alphaComposition, opacity, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -103,6 +128,10 @@ public static IImageProcessingContext DrawImage(
/// The color blending mode.
/// The alpha composition mode.
/// The opacity of the image to draw. Must be between 0 and 1.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
@@ -110,8 +139,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 foregroundRepeatCount = 0)
+ => DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, alphaComposition, opacity, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -119,12 +149,17 @@ public static IImageProcessingContext DrawImage(
/// The current image processing context.
/// The image to draw on the currently processing image.
/// The options, including the blending type and blending amount.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image foreground,
- GraphicsOptions options)
- => DrawImage(source, foreground, Point.Empty, options);
+ GraphicsOptions options,
+ int foregroundRepeatCount = 0)
+ => DrawImage(source, foreground, Point.Empty, options, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -133,13 +168,18 @@ public static IImageProcessingContext DrawImage(
/// The image to draw on the currently processing image.
/// The rectangle structure that specifies the portion of the image to draw.
/// The options, including the blending type and blending amount.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image foreground,
Rectangle foregroundRectangle,
- GraphicsOptions options)
- => DrawImage(source, foreground, Point.Empty, foregroundRectangle, options);
+ GraphicsOptions options,
+ int foregroundRepeatCount = 0)
+ => DrawImage(source, foreground, Point.Empty, foregroundRectangle, options, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -148,15 +188,20 @@ public static IImageProcessingContext DrawImage(
/// The image to draw on the currently processing image.
/// The location on the currently processing image at which to draw.
/// The opacity of the image to draw. Must be between 0 and 1.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image foreground,
Point backgroundLocation,
- float opacity)
+ float opacity,
+ int foregroundRepeatCount = 0)
{
GraphicsOptions options = source.GetGraphicsOptions();
- return DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, opacity);
+ return DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, foregroundRepeatCount);
}
///
@@ -167,16 +212,21 @@ public static IImageProcessingContext DrawImage(
/// The location on the currently processing image at which to draw.
/// The rectangle structure that specifies the portion of the image to draw.
/// The opacity of the image to draw. Must be between 0 and 1.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image foreground,
Point backgroundLocation,
Rectangle foregroundRectangle,
- float opacity)
+ float opacity,
+ int foregroundRepeatCount = 0)
{
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, foregroundRepeatCount);
}
///
@@ -187,14 +237,19 @@ public static IImageProcessingContext DrawImage(
/// The location on the currently processing image at which to draw.
/// The color blending to apply.
/// The opacity of the image to draw. Must be between 0 and 1.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image foreground,
Point backgroundLocation,
PixelColorBlendingMode colorBlending,
- float opacity)
- => DrawImage(source, foreground, backgroundLocation, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity);
+ float opacity,
+ int foregroundRepeatCount = 0)
+ => DrawImage(source, foreground, backgroundLocation, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -205,6 +260,10 @@ public static IImageProcessingContext DrawImage(
/// The rectangle structure that specifies the portion of the image to draw.
/// The color blending to apply.
/// The opacity of the image to draw. Must be between 0 and 1.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
@@ -212,8 +271,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 foregroundRepeatCount = 0)
+ => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -222,13 +282,18 @@ public static IImageProcessingContext DrawImage(
/// The image to draw on the currently processing image.
/// The location on the currently processing image at which to draw.
/// The options containing the blend mode and opacity.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
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 foregroundRepeatCount = 0)
+ => DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -238,14 +303,19 @@ public static IImageProcessingContext DrawImage(
/// The location on the currently processing image at which to draw.
/// The rectangle structure that specifies the portion of the image to draw.
/// The options containing the blend mode and opacity.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image foreground,
Point backgroundLocation,
Rectangle foregroundRectangle,
- GraphicsOptions options)
- => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage);
+ GraphicsOptions options,
+ int foregroundRepeatCount = 0)
+ => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -256,6 +326,10 @@ public static IImageProcessingContext DrawImage(
/// The color blending to apply.
/// The alpha composition mode.
/// The opacity of the image to draw. Must be between 0 and 1.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
@@ -263,8 +337,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 foregroundRepeatCount = 0)
+ => source.ApplyProcessor(new DrawImageProcessor(foreground, backgroundLocation, foreground.Bounds, colorBlending, alphaComposition, opacity, foregroundRepeatCount));
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -276,6 +351,10 @@ public static IImageProcessingContext DrawImage(
/// The color blending to apply.
/// The alpha composition mode.
/// The opacity of the image to draw. Must be between 0 and 1.
+ ///
+ /// The number of times the foreground frames are allowed to loop while applying this operation across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
/// The .
public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
@@ -284,8 +363,9 @@ public static IImageProcessingContext DrawImage(
Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition,
- float opacity) =>
+ float opacity,
+ int foregroundRepeatCount = 0) =>
source.ApplyProcessor(
- new DrawImageProcessor(foreground, backgroundLocation, foregroundRectangle, colorBlending, alphaComposition, opacity),
+ new DrawImageProcessor(foreground, backgroundLocation, foregroundRectangle, colorBlending, alphaComposition, opacity, foregroundRepeatCount),
foregroundRectangle);
}
diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs
index 6ecf16fc6b..675d1a3119 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 number of times the foreground frames are allowed to loop. 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 foregroundRepeatCount)
+ : this(foreground, backgroundLocation, foreground.Bounds, colorBlendingMode, alphaCompositionMode, opacity, foregroundRepeatCount)
{
}
@@ -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 number of times the foreground frames are allowed to loop. 0 means infinitely.
public DrawImageProcessor(
Image foreground,
Point backgroundLocation,
Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlendingMode,
PixelAlphaCompositionMode alphaCompositionMode,
- float opacity)
+ float opacity,
+ int foregroundRepeatCount)
{
this.ForeGround = foreground;
this.BackgroundLocation = backgroundLocation;
@@ -52,6 +56,7 @@ public DrawImageProcessor(
this.ColorBlendingMode = colorBlendingMode;
this.AlphaCompositionMode = alphaCompositionMode;
this.Opacity = opacity;
+ this.ForegroundRepeatCount = foregroundRepeatCount;
}
///
@@ -84,6 +89,11 @@ public DrawImageProcessor(
///
public float Opacity { get; }
+ ///
+ /// Gets the number of times the foreground frames are allowed to loop. 0 means infinitely.
+ ///
+ public int ForegroundRepeatCount { 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.ForegroundRepeatCount);
}
}
diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
index d2a99ce921..7a1ffb85f9 100644
--- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
+++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
@@ -17,6 +17,12 @@ internal class DrawImageProcessor : ImageProcessor
where TPixelBg : unmanaged, IPixel
where TPixelFg : unmanaged, IPixel
{
+ ///
+ /// Counts how many times has been called for this processor instance.
+ /// Used to select the current foreground frame.
+ ///
+ private int foregroundFrameCounter;
+
///
/// Initializes a new instance of the class.
///
@@ -28,6 +34,10 @@ 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 number of times the foreground frames are allowed to loop while applying this processor across successive frames.
+ /// A value of 0 means loop indefinitely.
+ ///
public DrawImageProcessor(
Configuration configuration,
Image foregroundImage,
@@ -36,9 +46,11 @@ public DrawImageProcessor(
Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlendingMode,
PixelAlphaCompositionMode alphaCompositionMode,
- float opacity)
+ float opacity,
+ int foregroundRepeatCount)
: base(configuration, backgroundImage, backgroundImage.Bounds)
{
+ Guard.MustBeGreaterThanOrEqualTo(foregroundRepeatCount, 0, nameof(foregroundRepeatCount));
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));
this.ForegroundImage = foregroundImage;
@@ -46,6 +58,7 @@ public DrawImageProcessor(
this.Opacity = opacity;
this.Blender = PixelOperations.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode);
this.BackgroundLocation = backgroundLocation;
+ this.ForegroundRepeatCount = foregroundRepeatCount;
}
///
@@ -73,6 +86,12 @@ public DrawImageProcessor(
///
public Point BackgroundLocation { get; }
+ ///
+ /// Gets the number of times the foreground frames are allowed to loop while applying this processor across
+ /// successive frames. A value of 0 means loop indefinitely.
+ ///
+ public int ForegroundRepeatCount { get; }
+
///
protected override void OnFrameApply(ImageFrame source)
{
@@ -114,12 +133,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.foregroundFrameCounter % this.ForegroundImage.Frames.Count;
- DrawImageProcessor.RowOperation operation =
+ RowOperation operation =
new(
configuration,
source.PixelBuffer,
- this.ForegroundImage.Frames.RootFrame.PixelBuffer,
+ this.ForegroundImage.Frames[currentFrameIndex].PixelBuffer,
backgroundRectangle,
foregroundRectangle,
this.Blender,
@@ -129,6 +149,13 @@ protected override void OnFrameApply(ImageFrame source)
configuration,
new Rectangle(0, 0, foregroundRectangle.Width, foregroundRectangle.Height),
in operation);
+
+ // The repeat count only affects how the foreground frame advances across successive background frames.
+ // When exhausted, the selected foreground frame stops advancing.
+ if (this.ForegroundRepeatCount is 0 || this.foregroundFrameCounter / this.ForegroundImage.Frames.Count < this.ForegroundRepeatCount)
+ {
+ this.foregroundFrameCounter++;
+ }
}
///