Browse Source

Enhance DrawImage functionality by adding repeatCount parameter for animation control in DrawImageExtensions and DrawImageProcessor classes.

pull/2995/head
予纾 4 months ago
parent
commit
60149fc64f
  1. 80
      src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs
  2. 19
      src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs
  3. 20
      src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs

80
src/ImageSharp/Processing/Extensions/Drawing/DrawImageExtensions.cs

@ -21,10 +21,11 @@ public static class DrawImageExtensions
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image foreground, Image foreground,
float opacity) float opacity,
int repeatCount)
{ {
GraphicsOptions options = source.GetGraphicsOptions(); GraphicsOptions options = source.GetGraphicsOptions();
return DrawImage(source, foreground, options.ColorBlendingMode, options.AlphaCompositionMode, opacity); return DrawImage(source, foreground, options.ColorBlendingMode, options.AlphaCompositionMode, opacity, repeatCount);
} }
/// <summary> /// <summary>
@ -39,10 +40,11 @@ public static class DrawImageExtensions
this IImageProcessingContext source, this IImageProcessingContext source,
Image foreground, Image foreground,
Rectangle foregroundRectangle, Rectangle foregroundRectangle,
float opacity) float opacity,
int repeatCount)
{ {
GraphicsOptions options = source.GetGraphicsOptions(); 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);
} }
/// <summary> /// <summary>
@ -57,8 +59,9 @@ public static class DrawImageExtensions
this IImageProcessingContext source, this IImageProcessingContext source,
Image foreground, Image foreground,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
float opacity) float opacity,
=> DrawImage(source, foreground, Point.Empty, colorBlending, opacity); int repeatCount)
=> DrawImage(source, foreground, Point.Empty, colorBlending, opacity, repeatCount);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
@ -74,8 +77,9 @@ public static class DrawImageExtensions
Image foreground, Image foreground,
Rectangle foregroundRectangle, Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
float opacity) float opacity,
=> DrawImage(source, foreground, foregroundRectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity); int repeatCount)
=> DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, opacity, repeatCount);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
@ -91,8 +95,9 @@ public static class DrawImageExtensions
Image foreground, Image foreground,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition, PixelAlphaCompositionMode alphaComposition,
float opacity) float opacity,
=> DrawImage(source, foreground, Point.Empty, colorBlending, alphaComposition, opacity); int repeatCount)
=> DrawImage(source, foreground, Point.Empty, colorBlending, alphaComposition, opacity, repeatCount);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
@ -110,8 +115,9 @@ public static class DrawImageExtensions
Rectangle foregroundRectangle, Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition, PixelAlphaCompositionMode alphaComposition,
float opacity) float opacity,
=> DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, alphaComposition, opacity); int repeatCount)
=> DrawImage(source, foreground, Point.Empty, foregroundRectangle, colorBlending, alphaComposition, opacity, repeatCount);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
@ -123,8 +129,9 @@ public static class DrawImageExtensions
public static IImageProcessingContext DrawImage( public static IImageProcessingContext DrawImage(
this IImageProcessingContext source, this IImageProcessingContext source,
Image foreground, Image foreground,
GraphicsOptions options) GraphicsOptions options,
=> DrawImage(source, foreground, Point.Empty, options); int repeatCount)
=> DrawImage(source, foreground, Point.Empty, options, repeatCount);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
@ -138,8 +145,9 @@ public static class DrawImageExtensions
this IImageProcessingContext source, this IImageProcessingContext source,
Image foreground, Image foreground,
Rectangle foregroundRectangle, Rectangle foregroundRectangle,
GraphicsOptions options) GraphicsOptions options,
=> DrawImage(source, foreground, Point.Empty, foregroundRectangle, options); int repeatCount)
=> DrawImage(source, foreground, Point.Empty, foregroundRectangle, options, repeatCount);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
@ -153,10 +161,11 @@ public static class DrawImageExtensions
this IImageProcessingContext source, this IImageProcessingContext source,
Image foreground, Image foreground,
Point backgroundLocation, Point backgroundLocation,
float opacity) float opacity,
int repeatCount)
{ {
GraphicsOptions options = source.GetGraphicsOptions(); 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);
} }
/// <summary> /// <summary>
@ -173,10 +182,11 @@ public static class DrawImageExtensions
Image foreground, Image foreground,
Point backgroundLocation, Point backgroundLocation,
Rectangle foregroundRectangle, Rectangle foregroundRectangle,
float opacity) float opacity,
int repeatCount)
{ {
GraphicsOptions options = source.GetGraphicsOptions(); 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);
} }
/// <summary> /// <summary>
@ -193,8 +203,9 @@ public static class DrawImageExtensions
Image foreground, Image foreground,
Point backgroundLocation, Point backgroundLocation,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
float opacity) float opacity,
=> DrawImage(source, foreground, backgroundLocation, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity); int repeatCount)
=> DrawImage(source, foreground, backgroundLocation, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity, repeatCount);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
@ -212,8 +223,9 @@ public static class DrawImageExtensions
Point backgroundLocation, Point backgroundLocation,
Rectangle foregroundRectangle, Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
float opacity) float opacity,
=> DrawImage(source, foreground, backgroundLocation, foregroundRectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity); int repeatCount)
=> DrawImage(source, foreground, backgroundLocation, foregroundRectangle, colorBlending, source.GetGraphicsOptions().AlphaCompositionMode, opacity, repeatCount);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
@ -227,8 +239,9 @@ public static class DrawImageExtensions
this IImageProcessingContext source, this IImageProcessingContext source,
Image foreground, Image foreground,
Point backgroundLocation, Point backgroundLocation,
GraphicsOptions options) GraphicsOptions options,
=> DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage); int repeatCount)
=> DrawImage(source, foreground, backgroundLocation, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage, repeatCount);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
@ -244,8 +257,9 @@ public static class DrawImageExtensions
Image foreground, Image foreground,
Point backgroundLocation, Point backgroundLocation,
Rectangle foregroundRectangle, Rectangle foregroundRectangle,
GraphicsOptions options) GraphicsOptions options,
=> DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage); int repeatCount)
=> DrawImage(source, foreground, backgroundLocation, foregroundRectangle, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage, repeatCount);
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
@ -263,8 +277,9 @@ public static class DrawImageExtensions
Point backgroundLocation, Point backgroundLocation,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition, PixelAlphaCompositionMode alphaComposition,
float opacity) float opacity,
=> source.ApplyProcessor(new DrawImageProcessor(foreground, backgroundLocation, foreground.Bounds, colorBlending, alphaComposition, opacity)); int repeatCount)
=> source.ApplyProcessor(new DrawImageProcessor(foreground, backgroundLocation, foreground.Bounds, colorBlending, alphaComposition, opacity, repeatCount));
/// <summary> /// <summary>
/// Draws the given image together with the currently processing image by blending their pixels. /// Draws the given image together with the currently processing image by blending their pixels.
@ -284,8 +299,9 @@ public static class DrawImageExtensions
Rectangle foregroundRectangle, Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlending, PixelColorBlendingMode colorBlending,
PixelAlphaCompositionMode alphaComposition, PixelAlphaCompositionMode alphaComposition,
float opacity) => float opacity,
int repeatCount) =>
source.ApplyProcessor( source.ApplyProcessor(
new DrawImageProcessor(foreground, backgroundLocation, foregroundRectangle, colorBlending, alphaComposition, opacity), new DrawImageProcessor(foreground, backgroundLocation, foregroundRectangle, colorBlending, alphaComposition, opacity, repeatCount),
foregroundRectangle); foregroundRectangle);
} }

19
src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor.cs

@ -19,13 +19,15 @@ public class DrawImageProcessor : IImageProcessor
/// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param> /// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param>
/// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param> /// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param>
/// <param name="opacity">The opacity of the image to blend.</param> /// <param name="opacity">The opacity of the image to blend.</param>
/// <param name="repeatCount">The loop count. The number of times to loop the animation. 0 means infinitely.</param>
public DrawImageProcessor( public DrawImageProcessor(
Image foreground, Image foreground,
Point backgroundLocation, Point backgroundLocation,
PixelColorBlendingMode colorBlendingMode, PixelColorBlendingMode colorBlendingMode,
PixelAlphaCompositionMode alphaCompositionMode, PixelAlphaCompositionMode alphaCompositionMode,
float opacity) float opacity,
: this(foreground, backgroundLocation, foreground.Bounds, colorBlendingMode, alphaCompositionMode, opacity) int repeatCount)
: this(foreground, backgroundLocation, foreground.Bounds, colorBlendingMode, alphaCompositionMode, opacity, repeatCount)
{ {
} }
@ -38,13 +40,15 @@ public class DrawImageProcessor : IImageProcessor
/// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param> /// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param>
/// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param> /// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param>
/// <param name="opacity">The opacity of the image to blend.</param> /// <param name="opacity">The opacity of the image to blend.</param>
/// <param name="repeatCount">The loop count. The number of times to loop the animation. 0 means infinitely.</param>
public DrawImageProcessor( public DrawImageProcessor(
Image foreground, Image foreground,
Point backgroundLocation, Point backgroundLocation,
Rectangle foregroundRectangle, Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlendingMode, PixelColorBlendingMode colorBlendingMode,
PixelAlphaCompositionMode alphaCompositionMode, PixelAlphaCompositionMode alphaCompositionMode,
float opacity) float opacity,
int repeatCount)
{ {
this.ForeGround = foreground; this.ForeGround = foreground;
this.BackgroundLocation = backgroundLocation; this.BackgroundLocation = backgroundLocation;
@ -52,6 +56,7 @@ public class DrawImageProcessor : IImageProcessor
this.ColorBlendingMode = colorBlendingMode; this.ColorBlendingMode = colorBlendingMode;
this.AlphaCompositionMode = alphaCompositionMode; this.AlphaCompositionMode = alphaCompositionMode;
this.Opacity = opacity; this.Opacity = opacity;
this.RepeatCount = repeatCount;
} }
/// <summary> /// <summary>
@ -84,6 +89,11 @@ public class DrawImageProcessor : IImageProcessor
/// </summary> /// </summary>
public float Opacity { get; } public float Opacity { get; }
/// <summary>
/// Gets the loop count. The number of times to loop the animation. 0 means infinitely.
/// </summary>
public int RepeatCount { get; }
/// <inheritdoc /> /// <inheritdoc />
public IImageProcessor<TPixelBg> CreatePixelSpecificProcessor<TPixelBg>(Configuration configuration, Image<TPixelBg> source, Rectangle sourceRectangle) public IImageProcessor<TPixelBg> CreatePixelSpecificProcessor<TPixelBg>(Configuration configuration, Image<TPixelBg> source, Rectangle sourceRectangle)
where TPixelBg : unmanaged, IPixel<TPixelBg> where TPixelBg : unmanaged, IPixel<TPixelBg>
@ -122,6 +132,7 @@ public class DrawImageProcessor : IImageProcessor
this.definition.ForegroundRectangle, this.definition.ForegroundRectangle,
this.definition.ColorBlendingMode, this.definition.ColorBlendingMode,
this.definition.AlphaCompositionMode, this.definition.AlphaCompositionMode,
this.definition.Opacity); this.definition.Opacity,
this.definition.RepeatCount);
} }
} }

20
src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs

@ -17,6 +17,8 @@ internal class DrawImageProcessor<TPixelBg, TPixelFg> : ImageProcessor<TPixelBg>
where TPixelBg : unmanaged, IPixel<TPixelBg> where TPixelBg : unmanaged, IPixel<TPixelBg>
where TPixelFg : unmanaged, IPixel<TPixelFg> where TPixelFg : unmanaged, IPixel<TPixelFg>
{ {
private int currentFrameLoop;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixelBg, TPixelFg}"/> class. /// Initializes a new instance of the <see cref="DrawImageProcessor{TPixelBg, TPixelFg}"/> class.
/// </summary> /// </summary>
@ -28,6 +30,7 @@ internal class DrawImageProcessor<TPixelBg, TPixelFg> : ImageProcessor<TPixelBg>
/// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param> /// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param>
/// <param name="alphaCompositionMode">The alpha blending mode to use when drawing the image.</param> /// <param name="alphaCompositionMode">The alpha blending mode to use when drawing the image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <param name="repeatCount">The loop count. The number of times to loop the animation. 0 means infinitely.</param>
public DrawImageProcessor( public DrawImageProcessor(
Configuration configuration, Configuration configuration,
Image<TPixelFg> foregroundImage, Image<TPixelFg> foregroundImage,
@ -36,9 +39,11 @@ internal class DrawImageProcessor<TPixelBg, TPixelFg> : ImageProcessor<TPixelBg>
Rectangle foregroundRectangle, Rectangle foregroundRectangle,
PixelColorBlendingMode colorBlendingMode, PixelColorBlendingMode colorBlendingMode,
PixelAlphaCompositionMode alphaCompositionMode, PixelAlphaCompositionMode alphaCompositionMode,
float opacity) float opacity,
int repeatCount)
: base(configuration, backgroundImage, backgroundImage.Bounds) : base(configuration, backgroundImage, backgroundImage.Bounds)
{ {
Guard.MustBeGreaterThanOrEqualTo(repeatCount, 0, nameof(repeatCount));
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));
this.ForegroundImage = foregroundImage; this.ForegroundImage = foregroundImage;
@ -73,6 +78,11 @@ internal class DrawImageProcessor<TPixelBg, TPixelFg> : ImageProcessor<TPixelBg>
/// </summary> /// </summary>
public Point BackgroundLocation { get; } public Point BackgroundLocation { get; }
/// <summary>
/// Gets the loop count. The number of times to loop the animation. 0 means infinitely.
/// </summary>
public int RepeatCount { get; }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixelBg> source) protected override void OnFrameApply(ImageFrame<TPixelBg> source)
{ {
@ -114,12 +124,13 @@ internal class DrawImageProcessor<TPixelBg, TPixelFg> : ImageProcessor<TPixelBg>
// Sanitize the dimensions so that we don't try and sample outside the image. // 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); Rectangle backgroundRectangle = Rectangle.Intersect(new Rectangle(left, top, width, height), this.SourceRectangle);
Configuration configuration = this.Configuration; Configuration configuration = this.Configuration;
int currentFrameIndex = this.currentFrameLoop % this.ForegroundImage.Frames.Count;
DrawImageProcessor<TPixelBg, TPixelFg>.RowOperation operation = DrawImageProcessor<TPixelBg, TPixelFg>.RowOperation operation =
new( new(
configuration, configuration,
source.PixelBuffer, source.PixelBuffer,
this.ForegroundImage.Frames.RootFrame.PixelBuffer, this.ForegroundImage.Frames[currentFrameIndex].PixelBuffer,
backgroundRectangle, backgroundRectangle,
foregroundRectangle, foregroundRectangle,
this.Blender, this.Blender,
@ -129,6 +140,11 @@ internal class DrawImageProcessor<TPixelBg, TPixelFg> : ImageProcessor<TPixelBg>
configuration, configuration,
new Rectangle(0, 0, foregroundRectangle.Width, foregroundRectangle.Height), new Rectangle(0, 0, foregroundRectangle.Width, foregroundRectangle.Height),
in operation); in operation);
if (this.RepeatCount is 0 || this.currentFrameLoop / this.ForegroundImage.Frames.Count <= this.RepeatCount)
{
this.currentFrameLoop++;
}
} }
/// <summary> /// <summary>

Loading…
Cancel
Save