From 74e8321cd551f4a1b23a7a51a4cc891b4bddbf1d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 20 Jan 2026 16:55:35 +1000 Subject: [PATCH] Update field names and fix assignment bug --- .../Extensions/Drawing/DrawImageExtensions.cs | 128 +++++++++++++----- .../Processors/Drawing/DrawImageProcessor.cs | 18 +-- .../DrawImageProcessor{TPixelBg,TPixelFg}.cs | 31 +++-- 3 files changed, 126 insertions(+), 51 deletions(-) diff --git a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs index a6a02e133..42051ca93 100644 --- a/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs @@ -17,15 +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, - int repeatCount) + int foregroundRepeatCount = 0) { GraphicsOptions options = source.GetGraphicsOptions(); - return DrawImage(source, foreground, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, repeatCount); + return DrawImage(source, foreground, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, foregroundRepeatCount); } /// @@ -35,16 +39,20 @@ public static class DrawImageExtensions /// 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 repeatCount) + int foregroundRepeatCount = 0) { GraphicsOptions options = source.GetGraphicsOptions(); - return DrawImage(source, foreground, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, repeatCount); + return DrawImage(source, foreground, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, foregroundRepeatCount); } /// @@ -54,14 +62,18 @@ public static class DrawImageExtensions /// 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 repeatCount) - => DrawImage(source, foreground, Point.Empty, colorBlending, opacity, repeatCount); + 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. @@ -71,6 +83,10 @@ public static class DrawImageExtensions /// 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, @@ -78,8 +94,8 @@ public static class DrawImageExtensions Rectangle foregroundRectangle, PixelColorBlendingMode colorBlending, float opacity, - int repeatCount) - => DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, opacity, repeatCount); + 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. @@ -89,6 +105,10 @@ public static class DrawImageExtensions /// 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, @@ -96,8 +116,8 @@ public static class DrawImageExtensions PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity, - int repeatCount) - => DrawImage(source, foreground, Point.Empty, colorBlending, alphaComposition, opacity, repeatCount); + 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. @@ -108,6 +128,10 @@ public static class DrawImageExtensions /// 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, @@ -116,8 +140,8 @@ public static class DrawImageExtensions PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity, - int repeatCount) - => DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, alphaComposition, opacity, repeatCount); + 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. @@ -125,13 +149,17 @@ public static class DrawImageExtensions /// 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 repeatCount) - => DrawImage(source, foreground, Point.Empty, options, repeatCount); + int foregroundRepeatCount = 0) + => DrawImage(source, foreground, Point.Empty, options, foregroundRepeatCount); /// /// Draws the given image together with the currently processing image by blending their pixels. @@ -140,14 +168,18 @@ public static class DrawImageExtensions /// 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 repeatCount) - => DrawImage(source, foreground, Point.Empty, foregroundRectangle, options, repeatCount); + 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. @@ -156,16 +188,20 @@ public static class DrawImageExtensions /// 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 repeatCount) + int foregroundRepeatCount = 0) { GraphicsOptions options = source.GetGraphicsOptions(); - return DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, repeatCount); + return DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, foregroundRepeatCount); } /// @@ -176,6 +212,10 @@ public static class DrawImageExtensions /// 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, @@ -183,10 +223,10 @@ public static class DrawImageExtensions Point backgroundLocation, Rectangle foregroundRectangle, float opacity, - int repeatCount) + int foregroundRepeatCount = 0) { GraphicsOptions options = source.GetGraphicsOptions(); - return DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, repeatCount); + return DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, foregroundRepeatCount); } /// @@ -197,6 +237,10 @@ public static class DrawImageExtensions /// 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, @@ -204,8 +248,8 @@ public static class DrawImageExtensions Point backgroundLocation, PixelColorBlendingMode colorBlending, float opacity, - int repeatCount) - => DrawImage(source, foreground, backgroundLocation, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity, repeatCount); + 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. @@ -216,6 +260,10 @@ public static class DrawImageExtensions /// 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, @@ -224,8 +272,8 @@ public static class DrawImageExtensions Rectangle foregroundRectangle, PixelColorBlendingMode colorBlending, float opacity, - int repeatCount) - => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity, repeatCount); + 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. @@ -234,14 +282,18 @@ public static class DrawImageExtensions /// 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 repeatCount) - => DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage, repeatCount); + 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. @@ -251,6 +303,10 @@ public static class DrawImageExtensions /// 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, @@ -258,8 +314,8 @@ public static class DrawImageExtensions Point backgroundLocation, Rectangle foregroundRectangle, GraphicsOptions options, - int repeatCount) - => DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage, repeatCount); + 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. @@ -270,6 +326,10 @@ public static class DrawImageExtensions /// 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, @@ -278,8 +338,8 @@ public static class DrawImageExtensions PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity, - int repeatCount) - => source.ApplyProcessor(new DrawImageProcessor(foreground, backgroundLocation, foreground.Bounds, colorBlending, alphaComposition, opacity, repeatCount)); + 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. @@ -291,6 +351,10 @@ public static class DrawImageExtensions /// 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, @@ -300,8 +364,8 @@ public static class DrawImageExtensions PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity, - int repeatCount) => + int foregroundRepeatCount = 0) => source.ApplyProcessor( - new DrawImageProcessor(foreground, backgroundLocation, foregroundRectangle, colorBlending, alphaComposition, opacity, repeatCount), + 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 3e17dae51..675d1a311 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -19,15 +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. + /// 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, - int repeatCount) - : this(foreground, backgroundLocation, foreground.Bounds, colorBlendingMode, alphaCompositionMode, opacity, repeatCount) + int foregroundRepeatCount) + : this(foreground, backgroundLocation, foreground.Bounds, colorBlendingMode, alphaCompositionMode, opacity, foregroundRepeatCount) { } @@ -40,7 +40,7 @@ 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. + /// The number of times the foreground frames are allowed to loop. 0 means infinitely. public DrawImageProcessor( Image foreground, Point backgroundLocation, @@ -48,7 +48,7 @@ public class DrawImageProcessor : IImageProcessor PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, float opacity, - int repeatCount) + int foregroundRepeatCount) { this.ForeGround = foreground; this.BackgroundLocation = backgroundLocation; @@ -56,7 +56,7 @@ public class DrawImageProcessor : IImageProcessor this.ColorBlendingMode = colorBlendingMode; this.AlphaCompositionMode = alphaCompositionMode; this.Opacity = opacity; - this.RepeatCount = repeatCount; + this.ForegroundRepeatCount = foregroundRepeatCount; } /// @@ -90,9 +90,9 @@ public class DrawImageProcessor : IImageProcessor public float Opacity { get; } /// - /// Gets the loop count. The number of times to loop the animation. 0 means infinitely. + /// Gets the number of times the foreground frames are allowed to loop. 0 means infinitely. /// - public int RepeatCount { get; } + public int ForegroundRepeatCount { get; } /// public IImageProcessor CreatePixelSpecificProcessor(Configuration configuration, Image source, Rectangle sourceRectangle) @@ -133,6 +133,6 @@ public class DrawImageProcessor : IImageProcessor this.definition.ColorBlendingMode, this.definition.AlphaCompositionMode, this.definition.Opacity, - this.definition.RepeatCount); + 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 001888865..7a1ffb85f 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -17,7 +17,11 @@ internal class DrawImageProcessor : ImageProcessor where TPixelBg : unmanaged, IPixel where TPixelFg : unmanaged, IPixel { - private int currentFrameLoop; + /// + /// 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. @@ -30,7 +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 loop count. The number of times to loop the animation. 0 means infinitely. + /// + /// 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, @@ -40,10 +47,10 @@ internal class DrawImageProcessor : ImageProcessor PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, float opacity, - int repeatCount) + int foregroundRepeatCount) : base(configuration, backgroundImage, backgroundImage.Bounds) { - Guard.MustBeGreaterThanOrEqualTo(repeatCount, 0, nameof(repeatCount)); + Guard.MustBeGreaterThanOrEqualTo(foregroundRepeatCount, 0, nameof(foregroundRepeatCount)); Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); this.ForegroundImage = foregroundImage; @@ -51,6 +58,7 @@ internal class DrawImageProcessor : ImageProcessor this.Opacity = opacity; this.Blender = PixelOperations.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode); this.BackgroundLocation = backgroundLocation; + this.ForegroundRepeatCount = foregroundRepeatCount; } /// @@ -79,9 +87,10 @@ internal class DrawImageProcessor : ImageProcessor public Point BackgroundLocation { get; } /// - /// Gets the loop count. The number of times to loop the animation. 0 means infinitely. + /// 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 RepeatCount { get; } + public int ForegroundRepeatCount { get; } /// protected override void OnFrameApply(ImageFrame source) @@ -124,9 +133,9 @@ internal class DrawImageProcessor : ImageProcessor // 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; + int currentFrameIndex = this.foregroundFrameCounter % this.ForegroundImage.Frames.Count; - DrawImageProcessor.RowOperation operation = + RowOperation operation = new( configuration, source.PixelBuffer, @@ -141,9 +150,11 @@ internal class DrawImageProcessor : ImageProcessor new Rectangle(0, 0, foregroundRectangle.Width, foregroundRectangle.Height), in operation); - if (this.RepeatCount is 0 || this.currentFrameLoop / this.ForegroundImage.Frames.Count < this.RepeatCount) + // 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.currentFrameLoop++; + this.foregroundFrameCounter++; } }