diff --git a/src/ImageSharp.Drawing/DrawImage.cs b/src/ImageSharp.Drawing/DrawImage.cs
index d55e22416..f1db72db6 100644
--- a/src/ImageSharp.Drawing/DrawImage.cs
+++ b/src/ImageSharp.Drawing/DrawImage.cs
@@ -18,24 +18,13 @@ namespace SixLabors.ImageSharp
/// The image this method extends.
/// The image to blend with the currently processing image.
/// The pixel format.
- /// The size to draw the blended image.
/// The location to draw the blended image.
/// The options.
/// The .
- public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Size size, Point location, GraphicsOptions options)
+ public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, GraphicsOptions options)
where TPixel : struct, IPixel
{
- if (size == default(Size))
- {
- size = new Size(image.Width, image.Height);
- }
-
- if (location == default(Point))
- {
- location = Point.Empty;
- }
-
- source.ApplyProcessor(new DrawImageProcessor(image, size, location, options));
+ source.ApplyProcessor(new DrawImageProcessor(image, location, options));
return source;
}
@@ -45,14 +34,14 @@ namespace SixLabors.ImageSharp
/// The pixel format.
/// The image this method extends.
/// The image to blend with the currently processing image.
- /// The opacity of the image image to blend. Must be between 0 and 1.
+ /// The opacity of the image to blend. Must be between 0 and 1.
/// The .
- public static IImageProcessingContext Blend(this IImageProcessingContext source, Image image, float percent)
+ public static IImageProcessingContext Blend(this IImageProcessingContext source, Image image, float opacity)
where TPixel : struct, IPixel
{
GraphicsOptions options = GraphicsOptions.Default;
- options.BlendPercentage = percent;
- return DrawImage(source, image, default(Size), default(Point), options);
+ options.BlendPercentage = opacity;
+ return DrawImage(source, image, Point.Empty, options);
}
///
@@ -62,15 +51,15 @@ namespace SixLabors.ImageSharp
/// The image this method extends.
/// The image to blend with the currently processing image.
/// The blending mode.
- /// The opacity of the image image to blend. Must be between 0 and 1.
+ /// The opacity of the image to blend. Must be between 0 and 1.
/// The .
- public static IImageProcessingContext Blend(this IImageProcessingContext source, Image image, PixelBlenderMode blender, float percent)
+ public static IImageProcessingContext Blend(this IImageProcessingContext source, Image image, PixelBlenderMode blender, float opacity)
where TPixel : struct, IPixel
{
GraphicsOptions options = GraphicsOptions.Default;
- options.BlendPercentage = percent;
+ options.BlendPercentage = opacity;
options.BlenderMode = blender;
- return DrawImage(source, image, default(Size), default(Point), options);
+ return DrawImage(source, image, Point.Empty, options);
}
///
@@ -79,12 +68,12 @@ namespace SixLabors.ImageSharp
/// The pixel format.
/// The image this method extends.
/// The image to blend with the currently processing image.
- /// The options, including the blending type and belnding amount.
+ /// The options, including the blending type and blending amount.
/// The .
public static IImageProcessingContext Blend(this IImageProcessingContext source, Image image, GraphicsOptions options)
where TPixel : struct, IPixel
{
- return DrawImage(source, image, default(Size), default(Point), options);
+ return DrawImage(source, image, Point.Empty, options);
}
///
@@ -93,16 +82,15 @@ namespace SixLabors.ImageSharp
/// The image this method extends.
/// The image to blend with the currently processing image.
/// The pixel format.
- /// The opacity of the image image to blend. Must be between 0 and 1.
- /// The size to draw the blended image.
+ /// The opacity of the image to blend. Must be between 0 and 1.
/// The location to draw the blended image.
/// The .
- public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, float percent, Size size, Point location)
+ public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, float opacity, Point location)
where TPixel : struct, IPixel
{
GraphicsOptions options = GraphicsOptions.Default;
- options.BlendPercentage = percent;
- return source.DrawImage(image, size, location, options);
+ options.BlendPercentage = opacity;
+ return source.DrawImage(image, location, options);
}
///
@@ -112,17 +100,16 @@ namespace SixLabors.ImageSharp
/// The image to blend with the currently processing image.
/// The pixel format.
/// The type of bending to apply.
- /// The opacity of the image image to blend. Must be between 0 and 1.
- /// The size to draw the blended image.
+ /// The opacity of the image to blend. Must be between 0 and 1.
/// The location to draw the blended image.
/// The .
- public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelBlenderMode blender, float percent, Size size, Point location)
+ public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelBlenderMode blender, float opacity, Point location)
where TPixel : struct, IPixel
{
GraphicsOptions options = GraphicsOptions.Default;
options.BlenderMode = blender;
- options.BlendPercentage = percent;
- return source.DrawImage(image, size, location, options);
+ options.BlendPercentage = opacity;
+ return source.DrawImage(image, location, options);
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
index 54fb38ee9..880098088 100644
--- a/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
+++ b/src/ImageSharp.Drawing/Processors/DrawImageProcessor.cs
@@ -19,71 +19,60 @@ namespace SixLabors.ImageSharp.Drawing.Processors
internal class DrawImageProcessor : ImageProcessor
where TPixel : struct, IPixel
{
- private readonly PixelBlender blender;
-
///
/// Initializes a new instance of the class.
///
/// The image to blend with the currently processing image.
- /// The size to draw the blended image.
/// The location to draw the blended image.
- /// The opacity of the image to blend. Between 0 and 100.
- public DrawImageProcessor(Image image, Size size, Point location, GraphicsOptions options)
+ /// The opacity of the image to blend. Between 0 and 1.
+ public DrawImageProcessor(Image image, Point location, GraphicsOptions options)
{
Guard.MustBeBetweenOrEqualTo(options.BlendPercentage, 0, 1, nameof(options.BlendPercentage));
+
this.Image = image;
- this.Size = size;
- this.Alpha = options.BlendPercentage;
- this.blender = PixelOperations.Instance.GetPixelBlender(options.BlenderMode);
+ this.Opacity = options.BlendPercentage;
+ this.Blender = PixelOperations.Instance.GetPixelBlender(options.BlenderMode);
this.Location = location;
}
///
- /// Gets the image to blend.
+ /// Gets the image to blend
///
public Image Image { get; }
///
- /// Gets the alpha percentage value.
+ /// Gets the opacity of the image to blend
///
- public float Alpha { get; }
+ public float Opacity { get; }
///
- /// Gets the size to draw the blended image.
+ /// Gets the pixel blender
///
- public Size Size { get; }
+ public PixelBlender Blender { get; }
///
- /// Gets the location to draw the blended image.
+ /// Gets the location to draw the blended image
///
public Point Location { get; }
///
protected override void OnApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration)
{
- Image disposableImage = null;
Image targetImage = this.Image;
+ PixelBlender blender = this.Blender;
+ int locationY = this.Location.Y;
- 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();
- // 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 minX = Math.Max(this.Location.X, sourceRectangle.X);
+ int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width);
+ 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);
-
- int width = maxX - minX;
+ int width = maxX - minX;
MemoryManager memoryManager = this.Image.GetConfiguration().MemoryManager;
@@ -91,21 +80,16 @@ namespace SixLabors.ImageSharp.Drawing.Processors
{
amount.Span.Fill(this.Alpha);
- Parallel.For(
- minY,
- maxY,
- configuration.ParallelOptions,
- y =>
- {
- Span background = source.GetPixelRowSpan(y).Slice(minX, width);
- Span foreground = targetImage.GetPixelRowSpan(y - this.Location.Y).Slice(targetX, width);
+ Parallel.For(
+ minY,
+ maxY,
+ configuration.ParallelOptions,
+ y =>
+ {
+ Span background = source.GetPixelRowSpan(y).Slice(minX, width);
+ Span foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
this.blender.Blend(memoryManager, background, background, foreground, amount.Span);
- });
- }
- }
- finally
- {
- disposableImage?.Dispose();
+ });
}
}
}
diff --git a/src/ImageSharp/GraphicsOptions.cs b/src/ImageSharp/GraphicsOptions.cs
index 114eaab2a..a094abacb 100644
--- a/src/ImageSharp/GraphicsOptions.cs
+++ b/src/ImageSharp/GraphicsOptions.cs
@@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp
// some API thought post V1.
///
- /// Gets or sets a value indicating the blending percentage to apply to the drawing operation
+ /// Gets or sets a value indicating the blending mode to apply to the drawing operation
///
public PixelBlenderMode BlenderMode
{
diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs
index 9a5b000de..287ce9d41 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs
@@ -51,8 +51,6 @@ namespace SixLabors.ImageSharp.Processing.Processors
public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size targetDimensions)
: base(sampler)
{
- // Transforms are inverted else the output is the opposite of the expected.
- Matrix3x2.Invert(matrix, out matrix);
this.TransformMatrix = matrix;
this.targetDimensions = targetDimensions;
}
@@ -95,6 +93,9 @@ namespace SixLabors.ImageSharp.Processing.Processors
// Since could potentially be resizing the canvas we might need to re-calculate the matrix
Matrix3x2 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds);
+ // Convert from screen to world space.
+ Matrix3x2.Invert(matrix, out matrix);
+
if (this.Sampler is NearestNeighborResampler)
{
Parallel.For(
diff --git a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs
index 34a086661..1e24b7c28 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/CenteredAffineTransformProcessor.cs
@@ -27,23 +27,14 @@ namespace SixLabors.ImageSharp.Processing.Processors
///
protected override Matrix3x2 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle)
{
- var translationToTargetCenter = Matrix3x2.CreateTranslation(-destinationRectangle.Width * .5F, -destinationRectangle.Height * .5F);
- var translateToSourceCenter = Matrix3x2.CreateTranslation(sourceRectangle.Width * .5F, sourceRectangle.Height * .5F);
- return translationToTargetCenter * this.TransformMatrix * translateToSourceCenter;
+ return TransformHelpers.GetCenteredTransformMatrix(sourceRectangle, destinationRectangle, this.TransformMatrix);
}
///
protected override Size GetTransformedDimensions(Size sourceDimensions, Matrix3x2 matrix)
{
var sourceRectangle = new Rectangle(0, 0, sourceDimensions.Width, sourceDimensions.Height);
-
- if (!Matrix3x2.Invert(this.TransformMatrix, out Matrix3x2 sizeMatrix))
- {
- // TODO: Shouldn't we throw an exception instead?
- return sourceDimensions;
- }
-
- return TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, sizeMatrix).Size;
+ return TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, this.TransformMatrix).Size;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs
index dc2dd28ab..92a008d7a 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/CenteredProjectiveTransformProcessor.cs
@@ -27,17 +27,14 @@ namespace SixLabors.ImageSharp.Processing.Processors
///
protected override Matrix4x4 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle)
{
- var translationToTargetCenter = Matrix4x4.CreateTranslation(-destinationRectangle.Width * .5F, -destinationRectangle.Height * .5F, 0);
- var translateToSourceCenter = Matrix4x4.CreateTranslation(sourceRectangle.Width * .5F, sourceRectangle.Height * .5F, 0);
- return translationToTargetCenter * this.TransformMatrix * translateToSourceCenter;
+ return TransformHelpers.GetCenteredTransformMatrix(sourceRectangle, destinationRectangle, this.TransformMatrix);
}
///
- protected override Rectangle GetTransformedBoundingRectangle(Rectangle sourceRectangle, Matrix4x4 matrix)
+ protected override Size GetTransformedDimensions(Size sourceDimensions, Matrix4x4 matrix)
{
- return Matrix4x4.Invert(this.TransformMatrix, out Matrix4x4 sizeMatrix)
- ? TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, sizeMatrix)
- : sourceRectangle;
+ var sourceRectangle = new Rectangle(0, 0, sourceDimensions.Width, sourceDimensions.Height);
+ return TransformHelpers.GetTransformedBoundingRectangle(sourceRectangle, this.TransformMatrix).Size;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs
index 3c04c2722..63ef3bfe2 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs
@@ -22,8 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
internal class ProjectiveTransformProcessor : InterpolatedTransformProcessorBase
where TPixel : struct, IPixel
{
- // TODO: We should use a Size instead! (See AffineTransformProcessor)
- private Rectangle targetRectangle;
+ private Size targetDimensions;
///
/// Initializes a new instance of the class.
@@ -40,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
/// The transform matrix
/// The sampler to perform the transform operation.
public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler)
- : this(matrix, sampler, Rectangle.Empty)
+ : this(matrix, sampler, Size.Empty)
{
}
@@ -49,27 +48,26 @@ namespace SixLabors.ImageSharp.Processing.Processors
///
/// The transform matrix
/// The sampler to perform the transform operation.
- /// The rectangle to constrain the transformed image to.
- public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Rectangle rectangle)
+ /// The target dimensions to constrain the transformed image to.
+ public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size targetDimensions)
: base(sampler)
{
- // Transforms are inverted else the output is the opposite of the expected.
- Matrix4x4.Invert(matrix, out matrix);
this.TransformMatrix = matrix;
- this.targetRectangle = rectangle;
+ this.targetDimensions = targetDimensions;
}
///
- /// Gets the matrix used to supply the non-affine transform
+ /// Gets the matrix used to supply the projective transform
///
public Matrix4x4 TransformMatrix { get; }
///
protected override Image CreateDestination(Image source, Rectangle sourceRectangle)
{
- if (this.targetRectangle == Rectangle.Empty)
+ if (this.targetDimensions == Size.Empty)
{
- this.targetRectangle = this.GetTransformedBoundingRectangle(sourceRectangle, this.TransformMatrix);
+ // TODO: CreateDestination() should not modify the processors state! (kinda CQRS)
+ this.targetDimensions = this.GetTransformedDimensions(sourceRectangle.Size, this.TransformMatrix);
}
// We will always be creating the clone even for mutate because we may need to resize the canvas
@@ -86,12 +84,17 @@ namespace SixLabors.ImageSharp.Processing.Processors
///
protected override void OnApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration)
{
- int height = this.targetRectangle.Height;
- int width = this.targetRectangle.Width;
+ int height = this.targetDimensions.Height;
+ int width = this.targetDimensions.Width;
+
Rectangle sourceBounds = source.Bounds();
+ var targetBounds = new Rectangle(0, 0, width, height);
// Since could potentially be resizing the canvas we might need to re-calculate the matrix
- Matrix4x4 matrix = this.GetProcessingMatrix(sourceBounds, this.targetRectangle);
+ Matrix4x4 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds);
+
+ // Convert from screen to world space.
+ Matrix4x4.Invert(matrix, out matrix);
if (this.Sampler is NearestNeighborResampler)
{
@@ -234,12 +237,12 @@ namespace SixLabors.ImageSharp.Processing.Processors
///
/// Gets the bounding relative to the source for the given transformation matrix.
///
- /// The source rectangle.
+ /// The source rectangle.
/// The transformation matrix.
/// The
- protected virtual Rectangle GetTransformedBoundingRectangle(Rectangle sourceRectangle, Matrix4x4 matrix)
+ protected virtual Size GetTransformedDimensions(Size sourceDimensions, Matrix4x4 matrix)
{
- return sourceRectangle;
+ return sourceDimensions;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Transforms/Transform.cs b/src/ImageSharp/Processing/Transforms/Transform.cs
index e39da8dc0..326ed7586 100644
--- a/src/ImageSharp/Processing/Transforms/Transform.cs
+++ b/src/ImageSharp/Processing/Transforms/Transform.cs
@@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp
/// The
public static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix3x2 matrix)
where TPixel : struct, IPixel
- => Transform(source, matrix, KnownResamplers.NearestNeighbor);
+ => Transform(source, matrix, KnownResamplers.Bicubic);
///
/// Transforms an image by the given matrix using the specified sampling algorithm.
@@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp
/// The
internal static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix4x4 matrix)
where TPixel : struct, IPixel
- => Transform(source, matrix, KnownResamplers.NearestNeighbor);
+ => Transform(source, matrix, KnownResamplers.Bicubic);
///
/// Applies a projective transform to the image by the given matrix using the specified sampling algorithm.
@@ -117,6 +117,10 @@ namespace SixLabors.ImageSharp
/// The
internal static IImageProcessingContext Transform(this IImageProcessingContext source, Matrix4x4 matrix, IResampler sampler, Rectangle rectangle)
where TPixel : struct, IPixel
- => source.ApplyProcessor(new ProjectiveTransformProcessor(matrix, sampler, rectangle));
+ {
+ var t = Matrix4x4.CreateTranslation(new Vector3(-rectangle.Location, 0));
+ Matrix4x4 combinedMatrix = t * matrix;
+ return source.ApplyProcessor(new ProjectiveTransformProcessor(combinedMatrix, sampler, rectangle.Size));
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Transforms/TransformHelpers.cs b/src/ImageSharp/Processing/Transforms/TransformHelpers.cs
index bfb06c470..1567c1161 100644
--- a/src/ImageSharp/Processing/Transforms/TransformHelpers.cs
+++ b/src/ImageSharp/Processing/Transforms/TransformHelpers.cs
@@ -59,7 +59,51 @@ namespace SixLabors.ImageSharp
}
///
- /// Returns the bounding relative to the source for the given transformation matrix.
+ /// Gets the centered transform matrix based upon the source and destination rectangles
+ ///
+ /// The source image bounds.
+ /// The destination image bounds.
+ /// The transformation matrix.
+ /// The
+ public static Matrix3x2 GetCenteredTransformMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle, Matrix3x2 matrix)
+ {
+ // We invert the matrix to handle the transformation from screen to world space.
+ // This ensures scaling matrices are correct.
+ Matrix3x2.Invert(matrix, out Matrix3x2 inverted);
+
+ var translationToTargetCenter = Matrix3x2.CreateTranslation(-destinationRectangle.Width * .5F, -destinationRectangle.Height * .5F);
+ var translateToSourceCenter = Matrix3x2.CreateTranslation(sourceRectangle.Width * .5F, sourceRectangle.Height * .5F);
+
+ Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered);
+
+ // Translate back to world to pass to the Transform method.
+ return centered;
+ }
+
+ ///
+ /// Gets the centered transform matrix based upon the source and destination rectangles
+ ///
+ /// The source image bounds.
+ /// The destination image bounds.
+ /// The transformation matrix.
+ /// The
+ public static Matrix4x4 GetCenteredTransformMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle, Matrix4x4 matrix)
+ {
+ // We invert the matrix to handle the transformation from screen to world space.
+ // This ensures scaling matrices are correct.
+ Matrix4x4.Invert(matrix, out Matrix4x4 inverted);
+
+ var translationToTargetCenter = Matrix4x4.CreateTranslation(-destinationRectangle.Width * .5F, -destinationRectangle.Height * .5F, 0);
+ var translateToSourceCenter = Matrix4x4.CreateTranslation(sourceRectangle.Width * .5F, sourceRectangle.Height * .5F, 0);
+
+ Matrix4x4.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix4x4 centered);
+
+ // Translate back to world to pass to the Transform method.
+ return centered;
+ }
+
+ ///
+ /// Returns the bounding rectangle relative to the source for the given transformation matrix.
///
/// The source rectangle.
/// The transformation matrix.
@@ -79,7 +123,7 @@ namespace SixLabors.ImageSharp
}
///
- /// Returns the bounding relative to the source for the given transformation matrix.
+ /// Returns the bounding rectangle relative to the source for the given transformation matrix.
///
/// The source rectangle.
/// The transformation matrix.
diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs
index 6a55d8a56..5fcb860be 100644
--- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs
+++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs
@@ -1,17 +1,16 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-using System.IO;
-using System.Linq;
+using System;
+using System.Numerics;
+using SixLabors.ImageSharp.Helpers;
+using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
using Xunit;
namespace SixLabors.ImageSharp.Tests
{
- using System;
- using System.Numerics;
-
public class DrawImageTest : FileTestBase
{
private const PixelTypes PixelTypes = Tests.PixelTypes.Rgba32;
@@ -23,8 +22,6 @@ namespace SixLabors.ImageSharp.Tests
TestImages.Gif.Rings
};
- object[][] Modes = System.Enum.GetValues(typeof(PixelBlenderMode)).Cast().Select(x => new object[] { x }).ToArray();
-
[Theory]
[WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Normal)]
[WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Multiply)]
@@ -39,9 +36,10 @@ namespace SixLabors.ImageSharp.Tests
where TPixel : struct, IPixel
{
using (Image image = provider.GetImage())
- using (Image blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes))
+ using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes))
{
- image.Mutate(x => x.DrawImage(blend, mode, .75f, new Size(image.Width / 2, image.Height / 2), new Point(image.Width / 4, image.Height / 4)));
+ blend.Mutate(x => x.Resize(image.Width / 2, image.Height / 2));
+ image.Mutate(x => x.DrawImage(blend, mode, .75f, new Point(image.Width / 4, image.Height / 4)));
image.DebugSave(provider, new { mode });
}
}
@@ -52,15 +50,25 @@ namespace SixLabors.ImageSharp.Tests
where TPixel : struct, IPixel
{
using (Image image = provider.GetImage())
- using (Image blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes))
+ using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes))
{
Matrix3x2 rotate = Matrix3x2Extensions.CreateRotationDegrees(45F);
Matrix3x2 scale = Matrix3x2Extensions.CreateScale(new SizeF(.25F, .25F));
+ Matrix3x2 matrix = rotate * scale;
+
+ // Lets center the matrix so we can tell whether any cut-off issues we may have belong to the drawing processor
+ Rectangle srcBounds = blend.Bounds();
+ Rectangle destBounds = TransformHelpers.GetTransformedBoundingRectangle(srcBounds, matrix);
+ Matrix3x2 centeredMatrix = TransformHelpers.GetCenteredTransformMatrix(srcBounds, destBounds, matrix);
- blend.Mutate(x => x.Transform(rotate * scale));
+ // We pass a new rectangle here based on the dest bounds since we've offset the matrix
+ blend.Mutate(x => x.Transform(
+ centeredMatrix,
+ KnownResamplers.Bicubic,
+ new Rectangle(0, 0, destBounds.Width, destBounds.Height)));
var position = new Point((image.Width - blend.Width) / 2, (image.Height - blend.Height) / 2);
- image.Mutate(x => x.DrawImage(blend, mode, .75F, new Size(blend.Width, blend.Height), position));
+ image.Mutate(x => x.DrawImage(blend, mode, .75F, position));
image.DebugSave(provider, new[] { "Transformed" });
}
}
@@ -78,7 +86,7 @@ namespace SixLabors.ImageSharp.Tests
Rgba32 backgroundPixel = background[0, 0];
Rgba32 overlayPixel = overlay[Math.Abs(xy) + 1, Math.Abs(xy) + 1];
- background.Mutate(x => x.DrawImage(overlay, PixelBlenderMode.Normal, 1F, new Size(overlay.Width, overlay.Height), new Point(xy, xy)));
+ background.Mutate(x => x.DrawImage(overlay, PixelBlenderMode.Normal, 1F, new Point(xy, xy)));
Assert.Equal(Rgba32.White, backgroundPixel);
Assert.Equal(overlayPixel, background[0, 0]);
@@ -100,7 +108,7 @@ namespace SixLabors.ImageSharp.Tests
Rgba32 backgroundPixel = background[xy - 1, xy - 1];
Rgba32 overlayPixel = overlay[0, 0];
- background.Mutate(x => x.DrawImage(overlay, PixelBlenderMode.Normal, 1F, new Size(overlay.Width, overlay.Height), new Point(xy, xy)));
+ background.Mutate(x => x.DrawImage(overlay, PixelBlenderMode.Normal, 1F, new Point(xy, xy)));
Assert.Equal(Rgba32.White, backgroundPixel);
Assert.Equal(overlayPixel, background[xy, xy]);
@@ -109,4 +117,4 @@ namespace SixLabors.ImageSharp.Tests
}
}
}
-}
+}
\ No newline at end of file