From afe23fc305f68240f7843377fff288e3b6b261d1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 23 May 2016 23:31:27 +1000 Subject: [PATCH] Finish ResizeModes proper Former-commit-id: 4582848b6fb5eee5c57c3a087ebd754015afe7b0 Former-commit-id: 79bf4fed23de01d328004558b9d1389ededc6192 Former-commit-id: 0ffc0e8c7fb9b123b251123f1aeb66612a09d089 --- .../Samplers/IImageSampler.cs | 3 +- src/ImageProcessorCore/Samplers/Resize.cs | 23 +++++++----- .../Samplers/ResizeHelper.cs | 37 +++++++++++++++---- src/ImageProcessorCore/Samplers/ResizeMode.cs | 14 ++++--- .../Samplers/ResizeOptions.cs | 7 ++++ .../Processors/Samplers/SamplerTests.cs | 3 +- 6 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/ImageProcessorCore/Samplers/IImageSampler.cs b/src/ImageProcessorCore/Samplers/IImageSampler.cs index e826db95f2..ba18b9788c 100644 --- a/src/ImageProcessorCore/Samplers/IImageSampler.cs +++ b/src/ImageProcessorCore/Samplers/IImageSampler.cs @@ -11,7 +11,8 @@ namespace ImageProcessorCore.Samplers public interface IImageSampler : IImageProcessor { /// - /// Gets or sets a value indicating whether to compand the value on processing. + /// Gets or sets a value indicating whether to compress + /// or expand individual pixel colors the value on processing. /// bool Compand { get; set; } } diff --git a/src/ImageProcessorCore/Samplers/Resize.cs b/src/ImageProcessorCore/Samplers/Resize.cs index 7ee290edfd..fa6eefca13 100644 --- a/src/ImageProcessorCore/Samplers/Resize.cs +++ b/src/ImageProcessorCore/Samplers/Resize.cs @@ -56,8 +56,10 @@ namespace ImageProcessorCore.Samplers int width = target.Width; int height = target.Height; int sourceHeight = sourceRectangle.Height; - int targetY = targetRectangle.Y; - int targetBottom = targetRectangle.Bottom; + int targetX = target.Bounds.X; + int targetY = target.Bounds.Y; + int targetRight = target.Bounds.Right; + int targetBottom = target.Bounds.Bottom; int startX = targetRectangle.X; int endX = targetRectangle.Right; bool compand = this.Compand; @@ -65,25 +67,28 @@ namespace ImageProcessorCore.Samplers if (this.Sampler is NearestNeighborResampler) { // Scaling factors - float widthFactor = source.Width / (float)target.Width; - float heightFactor = source.Height / (float)target.Height; + float widthFactor = sourceRectangle.Width / (float)targetRectangle.Width; + float heightFactor = sourceRectangle.Height / (float)targetRectangle.Height; Parallel.For( startY, endY, y => { - if (y >= targetY && y < targetBottom) + if (targetY <= y && y < targetBottom) { // Y coordinates of source points - int originY = (int)((y - targetY) * heightFactor); + int originY = (int)((y - startY) * heightFactor); for (int x = startX; x < endX; x++) { - // X coordinates of source points - int originX = (int)((x - startX) * widthFactor); + if (targetX <= x && x < targetRight) + { + // X coordinates of source points + int originX = (int)((x - startX) * widthFactor); - target[x, y] = source[originX, originY]; + target[x, y] = source[originX, originY]; + } } this.OnRowProcessed(); diff --git a/src/ImageProcessorCore/Samplers/ResizeHelper.cs b/src/ImageProcessorCore/Samplers/ResizeHelper.cs index 005b43c3fd..7a175a6fcc 100644 --- a/src/ImageProcessorCore/Samplers/ResizeHelper.cs +++ b/src/ImageProcessorCore/Samplers/ResizeHelper.cs @@ -26,6 +26,8 @@ namespace ImageProcessorCore.Samplers { switch (options.Mode) { + case ResizeMode.Crop: + return CalculateCropRectangle(source, options); case ResizeMode.Pad: return CalculatePadRectangle(source, options); case ResizeMode.BoxPad: @@ -35,9 +37,9 @@ namespace ImageProcessorCore.Samplers case ResizeMode.Min: return CalculateMinRectangle(source, options); - // Default case ResizeMode.Crop + // Last case ResizeMode.Stretch: default: - return CalculateCropRectangle(source, options); + return CalculateStretchRectangle(source, options); } } @@ -348,12 +350,16 @@ namespace ImageProcessorCore.Samplers if (sourceRatio < ratio) { destinationHeight = Convert.ToInt32(source.Height * percentWidth); + height = destinationHeight; } else { destinationWidth = Convert.ToInt32(source.Width * percentHeight); + width = destinationWidth; } + // Replace the size to match the rectangle. + options.Size = new Size(width, height); return new Rectangle(0, 0, destinationWidth, destinationHeight); } @@ -372,12 +378,12 @@ namespace ImageProcessorCore.Samplers int destinationWidth; int destinationHeight; - // Fractional variants for preserving aspect ratio. - double percentHeight = Math.Abs(height / (double)source.Height); - double percentWidth = Math.Abs(width / (double)source.Width); - - height = height > 0 ? height : Convert.ToInt32(source.Height * percentWidth); - width = width > 0 ? width : Convert.ToInt32(source.Width * percentHeight); + // Don't upscale + if (width > source.Width || height > source.Height) + { + options.Size = new Size(source.Width, source.Height); + return new Rectangle(0, 0, source.Width, source.Height); + } double sourceRatio = (double)source.Height / source.Width; @@ -401,7 +407,22 @@ namespace ImageProcessorCore.Samplers destinationHeight = height; } + // Replace the size to match the rectangle. + options.Size = new Size(width, height); return new Rectangle(0, 0, destinationWidth, destinationHeight); } + + /// + /// Calculates the target rectangle for stretch mode. + /// + /// The source image. + /// The resize options. + /// + /// The . + /// + private static Rectangle CalculateStretchRectangle(ImageBase source, ResizeOptions options) + { + return new Rectangle(0, 0, options.Size.Width, options.Size.Height); + } } } diff --git a/src/ImageProcessorCore/Samplers/ResizeMode.cs b/src/ImageProcessorCore/Samplers/ResizeMode.cs index d5c30ca842..15dc0a71c5 100644 --- a/src/ImageProcessorCore/Samplers/ResizeMode.cs +++ b/src/ImageProcessorCore/Samplers/ResizeMode.cs @@ -22,9 +22,11 @@ namespace ImageProcessorCore.Samplers Pad, /// - /// Stretches the resized image to fit the bounds of its container. + /// Pads the image to fit the bound of the container without resizing the + /// original source. + /// When downscaling, performs the same functionality as /// - Stretch, + BoxPad, /// /// Constrains the resized image to fit the bounds of its container maintaining @@ -34,14 +36,14 @@ namespace ImageProcessorCore.Samplers /// /// Resizes the image until the shortest side reaches the set given dimension. + /// Upscaling is disabled in this mode and the original image will be returned + /// if attempted. /// Min, /// - /// Pads the image to fit the bound of the container without resizing the - /// original source. - /// When downscaling, performs the same functionality as + /// Stretches the resized image to fit the bounds of its container. /// - BoxPad + Stretch } } diff --git a/src/ImageProcessorCore/Samplers/ResizeOptions.cs b/src/ImageProcessorCore/Samplers/ResizeOptions.cs index 66f262c632..01923a0cfe 100644 --- a/src/ImageProcessorCore/Samplers/ResizeOptions.cs +++ b/src/ImageProcessorCore/Samplers/ResizeOptions.cs @@ -33,8 +33,15 @@ namespace ImageProcessorCore.Samplers /// public Size Size { get; set; } + /// + /// Gets or sets the sampler to perform the resize operation. + /// public IResampler Sampler { get; set; } = new BicubicResampler(); + /// + /// Gets or sets a value indicating whether to compress + /// or expand individual pixel colors the value on processing. + /// public bool Compand { get; set; } } } diff --git a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs index ef09530fa1..7b42c77912 100644 --- a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs +++ b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs @@ -215,7 +215,8 @@ ResizeOptions options = new ResizeOptions() { Size = new Size(image.Width , image.Height + 200), - Mode = ResizeMode.Pad + Mode = ResizeMode.Pad, + Sampler = new NearestNeighborResampler() }; image.Resize(options, this.ProgressUpdate)