diff --git a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs
index 25e504831d..79fe68c20c 100644
--- a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs
+++ b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs
@@ -22,9 +22,27 @@ public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image foreground,
float opacity)
+ => DrawImage(source, foreground, opacity, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// 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,
+ int foregroundRepeatCount)
{
GraphicsOptions options = source.GetGraphicsOptions();
- return DrawImage(source, foreground, options.ColorBlendingMode, options.AlphaCompositionMode, opacity);
+ return DrawImage(source, foreground, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, foregroundRepeatCount);
}
///
@@ -40,9 +58,29 @@ public static IImageProcessingContext DrawImage(
Image foreground,
Rectangle foregroundRectangle,
float opacity)
+ => DrawImage(source, foreground, foregroundRectangle, opacity, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// The current image processing context.
+ /// 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,
+ int foregroundRepeatCount)
{
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);
}
///
@@ -58,7 +96,27 @@ public static IImageProcessingContext DrawImage(
Image foreground,
PixelColorBlendingMode colorBlending,
float opacity)
- => DrawImage(source, foreground, Point.Empty, colorBlending, opacity);
+ => DrawImage(source, foreground, colorBlending, opacity, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// The current image processing context.
+ /// 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,
+ int foregroundRepeatCount)
+ => DrawImage(source, foreground, Point.Empty, colorBlending, opacity, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -75,7 +133,29 @@ public static IImageProcessingContext DrawImage(
Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlending,
float opacity)
- => DrawImage(source, foreground, foregroundRectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity);
+ => DrawImage(source, foreground, foregroundRectangle, colorBlending, opacity, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// The current image processing context.
+ /// The image to draw on the currently processing image.
+ /// 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,
+ int foregroundRepeatCount)
+ => DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, opacity, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -92,7 +172,29 @@ public static IImageProcessingContext DrawImage(
PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition,
float opacity)
- => DrawImage(source, foreground, Point.Empty, colorBlending, alphaComposition, opacity);
+ => DrawImage(source, foreground, colorBlending, alphaComposition, opacity, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// The current image processing context.
+ /// The image to draw on the currently processing image.
+ /// 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,
+ int foregroundRepeatCount)
+ => DrawImage(source, foreground, Point.Empty, colorBlending, alphaComposition, opacity, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -111,7 +213,31 @@ public static IImageProcessingContext DrawImage(
PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition,
float opacity)
- => DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, alphaComposition, opacity);
+ => DrawImage(source, foreground, foregroundRectangle, colorBlending, alphaComposition, opacity, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// The current image processing context.
+ /// The image to draw on the currently processing image.
+ /// The rectangle structure that specifies the portion of the image to draw.
+ /// 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,
+ Rectangle foregroundRectangle,
+ PixelColorBlendingMode colorBlending,
+ PixelAlphaCompositionMode alphaComposition,
+ float opacity,
+ int foregroundRepeatCount)
+ => DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, alphaComposition, opacity, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -124,7 +250,25 @@ public static IImageProcessingContext DrawImage(
this IImageProcessingContext source,
Image foreground,
GraphicsOptions options)
- => DrawImage(source, foreground, Point.Empty, options);
+ => DrawImage(source, foreground, options, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// 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,
+ int foregroundRepeatCount)
+ => DrawImage(source, foreground, Point.Empty, options, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -139,7 +283,27 @@ public static IImageProcessingContext DrawImage(
Image foreground,
Rectangle foregroundRectangle,
GraphicsOptions options)
- => DrawImage(source, foreground, Point.Empty, foregroundRectangle, options);
+ => DrawImage(source, foreground, foregroundRectangle, options, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// The current image processing context.
+ /// 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,
+ int foregroundRepeatCount)
+ => DrawImage(source, foreground, Point.Empty, foregroundRectangle, options, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -154,9 +318,29 @@ public static IImageProcessingContext DrawImage(
Image foreground,
Point backgroundLocation,
float opacity)
+ => DrawImage(source, foreground, backgroundLocation, opacity, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// The current image processing context.
+ /// 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,
+ int foregroundRepeatCount)
{
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);
}
///
@@ -174,9 +358,31 @@ public static IImageProcessingContext DrawImage(
Point backgroundLocation,
Rectangle foregroundRectangle,
float opacity)
+ => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, opacity, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// The current image processing context.
+ /// The image to draw on the currently processing image.
+ /// 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,
+ int foregroundRepeatCount)
{
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);
}
///
@@ -194,7 +400,29 @@ public static IImageProcessingContext DrawImage(
Point backgroundLocation,
PixelColorBlendingMode colorBlending,
float opacity)
- => DrawImage(source, foreground, backgroundLocation, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity);
+ => DrawImage(source, foreground, backgroundLocation, colorBlending, opacity, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// The current image processing context.
+ /// The image to draw on the currently processing image.
+ /// 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,
+ int foregroundRepeatCount)
+ => DrawImage(source, foreground, backgroundLocation, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity, foregroundRepeatCount);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -213,7 +441,31 @@ public static IImageProcessingContext DrawImage(
Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlending,
float opacity)
- => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity);
+ => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, colorBlending, opacity, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// The current image processing context.
+ /// The image to draw on the currently processing image.
+ /// The location on the currently processing image at which to draw.
+ /// 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,
+ Image foreground,
+ Point backgroundLocation,
+ Rectangle foregroundRectangle,
+ PixelColorBlendingMode colorBlending,
+ float opacity,
+ int foregroundRepeatCount)
+ => 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.
@@ -228,7 +480,27 @@ public static IImageProcessingContext DrawImage(
Image foreground,
Point backgroundLocation,
GraphicsOptions options)
- => DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage);
+ => DrawImage(source, foreground, backgroundLocation, options, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// The current image processing context.
+ /// 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,
+ int foregroundRepeatCount)
+ => 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.
@@ -245,7 +517,48 @@ public static IImageProcessingContext DrawImage(
Point backgroundLocation,
Rectangle foregroundRectangle,
GraphicsOptions options)
- => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage);
+ => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options, 0);
+
+ ///
+ /// Draws the given image together with the currently processing image by blending their pixels.
+ ///
+ /// The current image processing context.
+ /// The image to draw on the currently processing image.
+ /// 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,
+ int foregroundRepeatCount)
+ => 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.
+ ///
+ /// The current image processing context.
+ /// The image to draw on the currently processing image.
+ /// The location on the currently processing image at which to draw.
+ /// The color blending to apply.
+ /// The alpha composition mode.
+ /// The opacity of the image to draw. Must be between 0 and 1.
+ /// The .
+ public static IImageProcessingContext DrawImage(
+ this IImageProcessingContext source,
+ Image foreground,
+ Point backgroundLocation,
+ PixelColorBlendingMode colorBlending,
+ PixelAlphaCompositionMode alphaComposition,
+ float opacity)
+ => DrawImage(source, foreground, backgroundLocation, colorBlending, alphaComposition, opacity, 0);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -256,6 +569,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 +580,30 @@ public static IImageProcessingContext DrawImage(
Point backgroundLocation,
PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition,
+ float opacity,
+ int foregroundRepeatCount)
+ => 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.
+ ///
+ /// The current image processing context.
+ /// The image to draw on the currently processing image.
+ /// The location on the currently processing image at which to draw.
+ /// The rectangle structure that specifies the portion of the image to draw.
+ /// The color blending to apply.
+ /// The alpha composition mode.
+ /// The opacity of the image to draw. Must be between 0 and 1.
+ /// The .
+ public static IImageProcessingContext DrawImage(
+ this IImageProcessingContext source,
+ Image foreground,
+ Point backgroundLocation,
+ Rectangle foregroundRectangle,
+ PixelColorBlendingMode colorBlending,
+ PixelAlphaCompositionMode alphaComposition,
float opacity)
- => source.ApplyProcessor(new DrawImageProcessor(foreground, backgroundLocation, foreground.Bounds, colorBlending, alphaComposition, opacity));
+ => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, colorBlending, alphaComposition, opacity, 0);
///
/// Draws the given image together with the currently processing image by blending their pixels.
@@ -276,6 +615,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 +627,9 @@ public static IImageProcessingContext DrawImage(
Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition,
- float opacity) =>
+ float opacity,
+ int foregroundRepeatCount) =>
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++;
+ }
}
///
diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs
index 1d0fdf62d3..7f87111e80 100644
--- a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs
+++ b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs
@@ -293,4 +293,21 @@ public void Issue2603(TestImageProvider provider)
appendPixelTypeToFileName: false,
appendSourceFileOrDescription: false);
}
+
+ [Theory]
+ [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32)]
+ public void DrawImageAnimatedForegroundRepeatCount(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ using Image background = provider.GetImage();
+ using Image foreground = Image.Load(TestFile.Create(TestImages.Gif.Giphy).Bytes);
+
+ Size size = new(foreground.Width / 4, foreground.Height / 4);
+ foreground.Mutate(x => x.Resize(size.Width, size.Height, KnownResamplers.Bicubic));
+
+ background.Mutate(x => x.DrawImage(foreground, Point.Empty, 1F, 0));
+
+ background.DebugSaveMultiFrame(provider);
+ background.CompareToReferenceOutputMultiFrame(provider, ImageComparer.TolerantPercentage(0.01f));
+ }
}
diff --git a/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/00.png b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/00.png
new file mode 100644
index 0000000000..9e3e48a528
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/00.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:003d5986b66f90e0841c3fdfa8c595563c8e237467b8218c6fd7fa283ba28b1d
+size 21154
diff --git a/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/01.png b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/01.png
new file mode 100644
index 0000000000..7d8babf99f
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/01.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e1d148bd561f33c2435226c533dea539e1b21567d8f985a4059d501846e0bf30
+size 21761
diff --git a/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/02.png b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/02.png
new file mode 100644
index 0000000000..108ccd1f52
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/02.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:38519ad5d1d50548fada577d2bd4a8be7f76d1c3071f07bb98f1227c4bc5d303
+size 20522
diff --git a/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/03.png b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/03.png
new file mode 100644
index 0000000000..28c79f8c2f
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/03.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e922f83fd719ba961b8720417befa119000f2c8f3956d3ac8df60c79ff56fe59
+size 21291
diff --git a/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/04.png b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/04.png
new file mode 100644
index 0000000000..401939430d
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/DrawImageAnimatedForegroundRepeatCount_Rgba32_giphy.gif/04.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:8b7b904032ff6c142632e8c1efffe3d71c28a89d5824d9fe13dbf4ceeddcf5e8
+size 21367