From dd0b2a7154169b22c29ce6aca4e3263fda3254c1 Mon Sep 17 00:00:00 2001 From: Anthony Truskinger Date: Sun, 7 Apr 2019 15:18:58 +1000 Subject: [PATCH] No longer throws when DrawImage source does not overlap target Previously, when DrawImage was used to overlay an image, in cases where the source image did not overlap the target image, a very confusing error was reported: "System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: MaxDegreeOfParallelism" Now, when this case happens, the DrawImage method will simply not affect the target image, which is the same way FillRegionProcessor handles such cases. ParallelHelper.IterRows also now does more validation of the input rectangle so that any further cases of this kind of problem throw a more relvant exception. Note I switched from DebugGuard to Guard because IterRows is a public API and thus should always validate its inputs. Fixes #875 --- .../Processors/Drawing/DrawImageProcessor.cs | 6 ++++++ .../Common/ParallelUtils/ParallelHelper.cs | 3 ++- .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 20 +++++++++++++++++++ .../Helpers/ParallelHelperTests.cs | 15 ++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index 0957904c62..5cb331b685 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -81,6 +81,12 @@ protected override void OnFrameApply(ImageFrame source, Rectangle sou var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); + if (workingRect.Width < 0 || workingRect.Height < 0) + { + // no effect because rectangle does not overlap with this image. + return; + } + ParallelHelper.IterateRows( workingRect, configuration, diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs index a930b8390f..d5ac85ec80 100644 --- a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs +++ b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs @@ -45,7 +45,8 @@ public static void IterateRows( in ParallelExecutionSettings parallelSettings, Action body) { - DebugGuard.MustBeGreaterThan(rectangle.Width, 0, nameof(rectangle)); + Guard.MustBeGreaterThan(rectangle.Width, 0, nameof(rectangle)); + Guard.MustBeGreaterThan(rectangle.Height, 0, nameof(rectangle)); int maxSteps = DivideCeil(rectangle.Width * rectangle.Height, parallelSettings.MinimumPixelsProcessedPerTask); diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index 374454afba..bb02b714ef 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -132,6 +132,26 @@ public void ImageShouldHandlePositiveLocation(TestImageProvider provider } } + [Theory] + [WithSolidFilledImages(100, 100, 255, 255, 255, PixelTypes.Rgba32, -30, -30)] + [WithSolidFilledImages(100, 100, 255, 255, 255, PixelTypes.Rgba32, 130, -30)] + [WithSolidFilledImages(100, 100, 255, 255, 255, PixelTypes.Rgba32, 130, 130)] + [WithSolidFilledImages(100, 100, 255, 255, 255, PixelTypes.Rgba32, -30, 130)] + public void NonOverlappingImageHasNoEffect(TestImageProvider provider, int x, int y) + { + using (Image original = provider.GetImage()) + using (Image background = provider.GetImage()) + using (var overlay = new Image(Configuration.Default, 10, 10, Rgba32.Black)) + { + background.Mutate(context => context.DrawImage(overlay, new Point(x, y), GraphicsOptions.Default)); + + // background image should be unmodified + ImageComparer.Exact.CompareImagesOrFrames(original, background); + + background.DebugSave(provider, testOutputDetails: "NonOverlapping"); + } + } + private static void VerifyImage( TestImageProvider provider, PixelColorBlendingMode mode, diff --git a/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs b/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs index ef6b133f75..32a36268f8 100644 --- a/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs @@ -334,5 +334,20 @@ void FillRow(int y, Buffer2D buffer) TestImageExtensions.CompareBuffers(expected.Span, actual.Span); } } + + [Theory] + [InlineData(0, 10)] + [InlineData(10, 0)] + [InlineData(-10, 10)] + [InlineData(10, -10)] + public void IterateRowsRequiresValidRectangle(int width, int height) + { + var parallelSettings = new ParallelExecutionSettings(); + + var rect = new Rectangle(0, 0, width, height); + + Assert.Throws( + () => { ParallelHelper.IterateRows(rect, parallelSettings, (rows) => { }); }); + } } } \ No newline at end of file