diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs
index c0064d1877..b1767101d4 100644
--- a/src/ImageSharp/Configuration.cs
+++ b/src/ImageSharp/Configuration.cs
@@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Processing;
+using SixLabors.ImageSharp.Processing.Processors.Transforms;
using SixLabors.Memory;
namespace SixLabors.ImageSharp
@@ -102,6 +103,15 @@ namespace SixLabors.ImageSharp
///
internal IFileSystem FileSystem { get; set; } = new LocalFileSystem();
+ ///
+ /// Gets or sets the working buffer size hint for image processors.
+ /// The default value is 1MB.
+ ///
+ ///
+ /// Currently only used by .
+ ///
+ internal int WorkingBufferSizeHintInBytes { get; set; } = 1 * 1024 * 1024;
+
///
/// Gets or sets the image operations provider factory.
///
@@ -130,7 +140,8 @@ namespace SixLabors.ImageSharp
MemoryAllocator = this.MemoryAllocator,
ImageOperationsProvider = this.ImageOperationsProvider,
ReadOrigin = this.ReadOrigin,
- FileSystem = this.FileSystem
+ FileSystem = this.FileSystem,
+ WorkingBufferSizeHintInBytes = this.WorkingBufferSizeHintInBytes,
};
}
diff --git a/src/ImageSharp/Processing/ResizeHelper.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs
similarity index 88%
rename from src/ImageSharp/Processing/ResizeHelper.cs
rename to src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs
index 3ae632162f..0bc8cfda02 100644
--- a/src/ImageSharp/Processing/ResizeHelper.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeHelper.cs
@@ -1,11 +1,13 @@
-// Copyright (c) Six Labors and contributors.
+// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Linq;
+using System.Numerics;
+
using SixLabors.Primitives;
-namespace SixLabors.ImageSharp.Processing
+namespace SixLabors.ImageSharp.Processing.Processors.Transforms
{
///
/// Provides methods to help calculate the target rectangle when resizing using the
@@ -13,6 +15,16 @@ namespace SixLabors.ImageSharp.Processing
///
internal static class ResizeHelper
{
+ public static unsafe int CalculateResizeWorkerWindowCount(
+ int windowDiameter,
+ int width,
+ int sizeLimitHintInBytes)
+ {
+ int sizeLimitHint = sizeLimitHintInBytes / sizeof(Vector4);
+ int sizeOfOneWindow = windowDiameter * width;
+ return Math.Max(2, sizeLimitHint / sizeOfOneWindow);
+ }
+
///
/// Calculates the target location and bounds to perform the resize operation against.
///
@@ -21,9 +33,13 @@ namespace SixLabors.ImageSharp.Processing
/// The target width
/// The target height
///
- /// The .
+ /// The tuple representing the location and the bounds
///
- public static (Size, Rectangle) CalculateTargetLocationAndBounds(Size sourceSize, ResizeOptions options, int width, int height)
+ public static (Size, Rectangle) CalculateTargetLocationAndBounds(
+ Size sourceSize,
+ ResizeOptions options,
+ int width,
+ int height)
{
switch (options.Mode)
{
@@ -44,7 +60,90 @@ namespace SixLabors.ImageSharp.Processing
}
}
- private static (Size, Rectangle) CalculateCropRectangle(Size source, ResizeOptions options, int width, int height)
+ private static (Size, Rectangle) CalculateBoxPadRectangle(
+ Size source,
+ ResizeOptions options,
+ int width,
+ int height)
+ {
+ if (width <= 0 || height <= 0)
+ {
+ return (new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height));
+ }
+
+ int sourceWidth = source.Width;
+ int sourceHeight = source.Height;
+
+ // Fractional variants for preserving aspect ratio.
+ float percentHeight = MathF.Abs(height / (float)sourceHeight);
+ float percentWidth = MathF.Abs(width / (float)sourceWidth);
+
+ int boxPadHeight = height > 0 ? height : (int)MathF.Round(sourceHeight * percentWidth);
+ int boxPadWidth = width > 0 ? width : (int)MathF.Round(sourceWidth * percentHeight);
+
+ // Only calculate if upscaling.
+ if (sourceWidth < boxPadWidth && sourceHeight < boxPadHeight)
+ {
+ int destinationX;
+ int destinationY;
+ int destinationWidth = sourceWidth;
+ int destinationHeight = sourceHeight;
+ width = boxPadWidth;
+ height = boxPadHeight;
+
+ switch (options.Position)
+ {
+ case AnchorPositionMode.Left:
+ destinationY = (height - sourceHeight) / 2;
+ destinationX = 0;
+ break;
+ case AnchorPositionMode.Right:
+ destinationY = (height - sourceHeight) / 2;
+ destinationX = width - sourceWidth;
+ break;
+ case AnchorPositionMode.TopRight:
+ destinationY = 0;
+ destinationX = width - sourceWidth;
+ break;
+ case AnchorPositionMode.Top:
+ destinationY = 0;
+ destinationX = (width - sourceWidth) / 2;
+ break;
+ case AnchorPositionMode.TopLeft:
+ destinationY = 0;
+ destinationX = 0;
+ break;
+ case AnchorPositionMode.BottomRight:
+ destinationY = height - sourceHeight;
+ destinationX = width - sourceWidth;
+ break;
+ case AnchorPositionMode.Bottom:
+ destinationY = height - sourceHeight;
+ destinationX = (width - sourceWidth) / 2;
+ break;
+ case AnchorPositionMode.BottomLeft:
+ destinationY = height - sourceHeight;
+ destinationX = 0;
+ break;
+ default:
+ destinationY = (height - sourceHeight) / 2;
+ destinationX = (width - sourceWidth) / 2;
+ break;
+ }
+
+ return (new Size(width, height),
+ new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight));
+ }
+
+ // Switch to pad mode to downscale and calculate from there.
+ return CalculatePadRectangle(source, options, width, height);
+ }
+
+ private static (Size, Rectangle) CalculateCropRectangle(
+ Size source,
+ ResizeOptions options,
+ int width,
+ int height)
{
if (width <= 0 || height <= 0)
{
@@ -147,152 +246,15 @@ namespace SixLabors.ImageSharp.Processing
destinationWidth = (int)MathF.Ceiling(sourceWidth * percentHeight);
}
- return (new Size(width, height), new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight));
- }
-
- private static (Size, Rectangle) CalculatePadRectangle(Size source, ResizeOptions options, int width, int height)
- {
- if (width <= 0 || height <= 0)
- {
- return (new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height));
- }
-
- float ratio;
- int sourceWidth = source.Width;
- int sourceHeight = source.Height;
-
- int destinationX = 0;
- int destinationY = 0;
- int destinationWidth = width;
- int destinationHeight = height;
-
- // Fractional variants for preserving aspect ratio.
- float percentHeight = MathF.Abs(height / (float)sourceHeight);
- float percentWidth = MathF.Abs(width / (float)sourceWidth);
-
- if (percentHeight < percentWidth)
- {
- ratio = percentHeight;
- destinationWidth = (int)MathF.Round(sourceWidth * percentHeight);
-
- switch (options.Position)
- {
- case AnchorPositionMode.Left:
- case AnchorPositionMode.TopLeft:
- case AnchorPositionMode.BottomLeft:
- destinationX = 0;
- break;
- case AnchorPositionMode.Right:
- case AnchorPositionMode.TopRight:
- case AnchorPositionMode.BottomRight:
- destinationX = (int)MathF.Round(width - (sourceWidth * ratio));
- break;
- default:
- destinationX = (int)MathF.Round((width - (sourceWidth * ratio)) / 2F);
- break;
- }
- }
- else
- {
- ratio = percentWidth;
- destinationHeight = (int)MathF.Round(sourceHeight * percentWidth);
-
- switch (options.Position)
- {
- case AnchorPositionMode.Top:
- case AnchorPositionMode.TopLeft:
- case AnchorPositionMode.TopRight:
- destinationY = 0;
- break;
- case AnchorPositionMode.Bottom:
- case AnchorPositionMode.BottomLeft:
- case AnchorPositionMode.BottomRight:
- destinationY = (int)MathF.Round(height - (sourceHeight * ratio));
- break;
- default:
- destinationY = (int)MathF.Round((height - (sourceHeight * ratio)) / 2F);
- break;
- }
- }
-
- return (new Size(width, height), new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight));
- }
-
- private static (Size, Rectangle) CalculateBoxPadRectangle(Size source, ResizeOptions options, int width, int height)
- {
- if (width <= 0 || height <= 0)
- {
- return (new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height));
- }
-
- int sourceWidth = source.Width;
- int sourceHeight = source.Height;
-
- // Fractional variants for preserving aspect ratio.
- float percentHeight = MathF.Abs(height / (float)sourceHeight);
- float percentWidth = MathF.Abs(width / (float)sourceWidth);
-
- int boxPadHeight = height > 0 ? height : (int)MathF.Round(sourceHeight * percentWidth);
- int boxPadWidth = width > 0 ? width : (int)MathF.Round(sourceWidth * percentHeight);
-
- // Only calculate if upscaling.
- if (sourceWidth < boxPadWidth && sourceHeight < boxPadHeight)
- {
- int destinationX;
- int destinationY;
- int destinationWidth = sourceWidth;
- int destinationHeight = sourceHeight;
- width = boxPadWidth;
- height = boxPadHeight;
-
- switch (options.Position)
- {
- case AnchorPositionMode.Left:
- destinationY = (height - sourceHeight) / 2;
- destinationX = 0;
- break;
- case AnchorPositionMode.Right:
- destinationY = (height - sourceHeight) / 2;
- destinationX = width - sourceWidth;
- break;
- case AnchorPositionMode.TopRight:
- destinationY = 0;
- destinationX = width - sourceWidth;
- break;
- case AnchorPositionMode.Top:
- destinationY = 0;
- destinationX = (width - sourceWidth) / 2;
- break;
- case AnchorPositionMode.TopLeft:
- destinationY = 0;
- destinationX = 0;
- break;
- case AnchorPositionMode.BottomRight:
- destinationY = height - sourceHeight;
- destinationX = width - sourceWidth;
- break;
- case AnchorPositionMode.Bottom:
- destinationY = height - sourceHeight;
- destinationX = (width - sourceWidth) / 2;
- break;
- case AnchorPositionMode.BottomLeft:
- destinationY = height - sourceHeight;
- destinationX = 0;
- break;
- default:
- destinationY = (height - sourceHeight) / 2;
- destinationX = (width - sourceWidth) / 2;
- break;
- }
-
- return (new Size(width, height), new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight));
- }
-
- // Switch to pad mode to downscale and calculate from there.
- return CalculatePadRectangle(source, options, width, height);
+ return (new Size(width, height),
+ new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight));
}
- private static (Size, Rectangle) CalculateMaxRectangle(Size source, ResizeOptions options, int width, int height)
+ private static (Size, Rectangle) CalculateMaxRectangle(
+ Size source,
+ ResizeOptions options,
+ int width,
+ int height)
{
int destinationWidth = width;
int destinationHeight = height;
@@ -320,7 +282,11 @@ namespace SixLabors.ImageSharp.Processing
return (new Size(width, height), new Rectangle(0, 0, destinationWidth, destinationHeight));
}
- private static (Size, Rectangle) CalculateMinRectangle(Size source, ResizeOptions options, int width, int height)
+ private static (Size, Rectangle) CalculateMinRectangle(
+ Size source,
+ ResizeOptions options,
+ int width,
+ int height)
{
int sourceWidth = source.Width;
int sourceHeight = source.Height;
@@ -372,5 +338,78 @@ namespace SixLabors.ImageSharp.Processing
// Replace the size to match the rectangle.
return (new Size(width, height), new Rectangle(0, 0, destinationWidth, destinationHeight));
}
+
+ private static (Size, Rectangle) CalculatePadRectangle(
+ Size source,
+ ResizeOptions options,
+ int width,
+ int height)
+ {
+ if (width <= 0 || height <= 0)
+ {
+ return (new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height));
+ }
+
+ float ratio;
+ int sourceWidth = source.Width;
+ int sourceHeight = source.Height;
+
+ int destinationX = 0;
+ int destinationY = 0;
+ int destinationWidth = width;
+ int destinationHeight = height;
+
+ // Fractional variants for preserving aspect ratio.
+ float percentHeight = MathF.Abs(height / (float)sourceHeight);
+ float percentWidth = MathF.Abs(width / (float)sourceWidth);
+
+ if (percentHeight < percentWidth)
+ {
+ ratio = percentHeight;
+ destinationWidth = (int)MathF.Round(sourceWidth * percentHeight);
+
+ switch (options.Position)
+ {
+ case AnchorPositionMode.Left:
+ case AnchorPositionMode.TopLeft:
+ case AnchorPositionMode.BottomLeft:
+ destinationX = 0;
+ break;
+ case AnchorPositionMode.Right:
+ case AnchorPositionMode.TopRight:
+ case AnchorPositionMode.BottomRight:
+ destinationX = (int)MathF.Round(width - (sourceWidth * ratio));
+ break;
+ default:
+ destinationX = (int)MathF.Round((width - (sourceWidth * ratio)) / 2F);
+ break;
+ }
+ }
+ else
+ {
+ ratio = percentWidth;
+ destinationHeight = (int)MathF.Round(sourceHeight * percentWidth);
+
+ switch (options.Position)
+ {
+ case AnchorPositionMode.Top:
+ case AnchorPositionMode.TopLeft:
+ case AnchorPositionMode.TopRight:
+ destinationY = 0;
+ break;
+ case AnchorPositionMode.Bottom:
+ case AnchorPositionMode.BottomLeft:
+ case AnchorPositionMode.BottomRight:
+ destinationY = (int)MathF.Round(height - (sourceHeight * ratio));
+ break;
+ default:
+ destinationY = (int)MathF.Round((height - (sourceHeight * ratio)) / 2F);
+ break;
+ }
+ }
+
+ return (new Size(width, height),
+ new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight));
+ }
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs
index 208387e6d1..6f68d04288 100644
--- a/tests/ImageSharp.Tests/ConfigurationTests.cs
+++ b/tests/ImageSharp.Tests/ConfigurationTests.cs
@@ -39,13 +39,13 @@ namespace SixLabors.ImageSharp.Tests
/// Test that the default configuration is not null.
///
[Fact]
- public void TestDefaultConfigurationIsNotNull() => Assert.True(Configuration.Default != null);
+ public void TestDefaultConfigurationIsNotNull() => Assert.True(this.DefaultConfiguration != null);
///
/// Test that the default configuration read origin options is set to begin.
///
[Fact]
- public void TestDefaultConfigurationReadOriginIsCurrent() => Assert.True(Configuration.Default.ReadOrigin == ReadOrigin.Current);
+ public void TestDefaultConfigurationReadOriginIsCurrent() => Assert.True(this.DefaultConfiguration.ReadOrigin == ReadOrigin.Current);
///
/// Test that the default configuration parallel options max degrees of parallelism matches the
@@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void TestDefaultConfigurationMaxDegreeOfParallelism()
{
- Assert.True(Configuration.Default.MaxDegreeOfParallelism == Environment.ProcessorCount);
+ Assert.True(this.DefaultConfiguration.MaxDegreeOfParallelism == Environment.ProcessorCount);
var cfg = new Configuration();
Assert.True(cfg.MaxDegreeOfParallelism == Environment.ProcessorCount);
@@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Tests
public void ConfigurationCannotAddDuplicates()
{
const int count = 4;
- Configuration config = Configuration.Default;
+ Configuration config = this.DefaultConfiguration;
Assert.Equal(count, config.ImageFormats.Count());
@@ -105,9 +105,16 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void DefaultConfigurationHasCorrectFormatCount()
{
- Configuration config = Configuration.Default;
+ Configuration config = Configuration.CreateDefaultInstance();
Assert.Equal(4, config.ImageFormats.Count());
}
+
+ [Fact]
+ public void WorkingBufferSizeHint_DefaultIsCorrect()
+ {
+ Configuration config = this.DefaultConfiguration;
+ Assert.True(config.WorkingBufferSizeHintInBytes > 1024);
+ }
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs
index 3d6f08a152..ec0092f340 100644
--- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs
+++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs
@@ -35,6 +35,25 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.07F);
+ [Theory]
+ [InlineData(20, 100, 1, 2)]
+ [InlineData(20, 100, 20*100*16, 2)]
+ [InlineData(20, 100, 40*100*16, 2)]
+ [InlineData(20, 100, 59*100*16, 2)]
+ [InlineData(20, 100, 60*100*16, 3)]
+ [InlineData(17, 63, 5*17*63*16, 5)]
+ [InlineData(17, 63, 5*17*63*16+1, 5)]
+ [InlineData(17, 63, 6*17*63*16-1, 5)]
+ public void CalculateResizeWorkerWindowCount(
+ int windowDiameter,
+ int width,
+ int sizeLimitHintInBytes,
+ int expectedCount)
+ {
+ int actualCount = ResizeHelper.CalculateResizeWorkerWindowCount(windowDiameter, width, sizeLimitHintInBytes);
+ Assert.Equal(expectedCount, actualCount);
+ }
+
[Theory]
[InlineData(-2, 0)]
[InlineData(-1, 0)]