Browse Source

Remove Clone from DrawImage to reduce memory consumption

af/merge-core
James Jackson-South 8 years ago
parent
commit
1157dbe5be
  1. 25
      src/ImageSharp.Drawing/DrawImage.cs
  2. 77
      src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs

25
src/ImageSharp.Drawing/DrawImage.cs

@ -16,7 +16,10 @@ namespace SixLabors.ImageSharp
/// Draws the given image together with the current one by blending their pixels.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="image">
/// The image to blend with the currently processing image.
/// If the image dimensions do not match the given <paramref name="size"/> then the image will be resized to match.
/// </param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="size">The size to draw the blended image.</param>
/// <param name="location">The location to draw the blended image.</param>
@ -45,7 +48,7 @@ namespace SixLabors.ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="percent">The opacity of the image image to blend. Must be between 0 and 1.</param>
/// <param name="percent">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Blend<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, float percent)
where TPixel : struct, IPixel<TPixel>
@ -62,7 +65,7 @@ namespace SixLabors.ImageSharp
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="blender">The blending mode.</param>
/// <param name="percent">The opacity of the image image to blend. Must be between 0 and 1.</param>
/// <param name="percent">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Blend<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, PixelBlenderMode blender, float percent)
where TPixel : struct, IPixel<TPixel>
@ -79,7 +82,7 @@ namespace SixLabors.ImageSharp
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="options">The options, including the blending type and belnding amount.</param>
/// <param name="options">The options, including the blending type and blending amount.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> Blend<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
@ -91,9 +94,12 @@ namespace SixLabors.ImageSharp
/// Draws the given image together with the current one by blending their pixels.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="image">
/// The image to blend with the currently processing image.
/// If the image dimensions do not match the given <paramref name="size"/> then the image will be resized to match.
/// </param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="percent">The opacity of the image image to blend. Must be between 0 and 1.</param>
/// <param name="percent">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <param name="size">The size to draw the blended image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
@ -109,10 +115,13 @@ namespace SixLabors.ImageSharp
/// Draws the given image together with the current one by blending their pixels.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="image">
/// The image to blend with the currently processing image.
/// If the image dimensions do not match the given <paramref name="size"/> then the image will be resized to match.
/// </param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="blender">The type of bending to apply.</param>
/// <param name="percent">The opacity of the image image to blend. Must be between 0 and 1.</param>
/// <param name="percent">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <param name="size">The size to draw the blended image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>

77
src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs

@ -24,15 +24,25 @@ namespace SixLabors.ImageSharp.Drawing.Processors
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="image">
/// The image to blend with the currently processing image.
/// If the image dimensions do not match the given <paramref name="size"/> then the image will be resized to match.
/// </param>
/// <param name="size">The size to draw the blended image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="options">The opacity of the image to blend. Between 0 and 100.</param>
public DrawImageProcessor(Image<TPixel> image, Size size, Point location, GraphicsOptions options)
{
Guard.MustBeBetweenOrEqualTo(options.BlendPercentage, 0, 1, nameof(options.BlendPercentage));
this.Image = image;
this.Size = size;
if (image.Size() != size)
{
image.Mutate(x => x.Resize(size.Width, size.Height));
}
this.Image = image;
this.Alpha = options.BlendPercentage;
this.blender = PixelOperations<TPixel>.Instance.GetPixelBlender(options.BlenderMode);
this.Location = location;
@ -61,51 +71,38 @@ namespace SixLabors.ImageSharp.Drawing.Processors
/// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
Image<TPixel> disposableImage = null;
Image<TPixel> targetImage = this.Image;
try
{
if (targetImage.Size() != this.Size)
{
targetImage = disposableImage = this.Image.Clone(x => x.Resize(this.Size.Width, this.Size.Height));
}
// Align start/end positions.
Rectangle bounds = targetImage.Bounds();
int minX = Math.Max(this.Location.X, sourceRectangle.X);
int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width);
maxX = Math.Min(this.Location.X + this.Size.Width, maxX);
int targetX = minX - this.Location.X;
// Align start/end positions.
Rectangle bounds = targetImage.Bounds();
int minX = Math.Max(this.Location.X, sourceRectangle.X);
int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width);
maxX = Math.Min(this.Location.X + this.Size.Width, maxX);
int targetX = minX - this.Location.X;
int minY = Math.Max(this.Location.Y, sourceRectangle.Y);
int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom);
int minY = Math.Max(this.Location.Y, sourceRectangle.Y);
int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom);
maxY = Math.Min(this.Location.Y + this.Size.Height, maxY);
maxY = Math.Min(this.Location.Y + this.Size.Height, maxY);
int width = maxX - minX;
using (var amount = new Buffer<float>(width))
int width = maxX - minX;
using (var amount = new Buffer<float>(width))
{
for (int i = 0; i < width; i++)
{
for (int i = 0; i < width; i++)
{
amount[i] = this.Alpha;
}
Parallel.For(
minY,
maxY,
configuration.ParallelOptions,
y =>
{
Span<TPixel> background = source.GetPixelRowSpan(y).Slice(minX, width);
Span<TPixel> foreground = targetImage.GetPixelRowSpan(y - this.Location.Y).Slice(targetX, width);
this.blender.Blend(background, background, foreground, amount);
});
amount[i] = this.Alpha;
}
}
finally
{
disposableImage?.Dispose();
Parallel.For(
minY,
maxY,
configuration.ParallelOptions,
y =>
{
Span<TPixel> background = source.GetPixelRowSpan(y).Slice(minX, width);
Span<TPixel> foreground = targetImage.GetPixelRowSpan(y - this.Location.Y).Slice(targetX, width);
this.blender.Blend(background, background, foreground, amount);
});
}
}
}

Loading…
Cancel
Save