From 2771f593f64bb88894e152d259853be1d6cbe189 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 30 May 2016 01:07:46 +1000 Subject: [PATCH] Fix Resizer Fix #394 Former-commit-id: 490723c7f33cbab80264901ad252541a44b1dc73 Former-commit-id: 60edb602bc6236d29495081697e2f385aaa84320 Former-commit-id: abf91473873cfad473325c0af36a7026f5e40709 --- src/ImageProcessorCore/Samplers/Resampler.cs | 2 +- src/ImageProcessorCore/Samplers/Resize.cs | 108 +++++++++--------- .../Samplers/ResizeHelper.cs | 4 +- .../Processors/Samplers/SamplerTests.cs | 47 ++++++-- 4 files changed, 96 insertions(+), 65 deletions(-) diff --git a/src/ImageProcessorCore/Samplers/Resampler.cs b/src/ImageProcessorCore/Samplers/Resampler.cs index ad30ad5af..a59c25644 100644 --- a/src/ImageProcessorCore/Samplers/Resampler.cs +++ b/src/ImageProcessorCore/Samplers/Resampler.cs @@ -151,7 +151,7 @@ namespace ImageProcessorCore.Samplers protected struct Weight { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the struct. /// /// The index. /// The value. diff --git a/src/ImageProcessorCore/Samplers/Resize.cs b/src/ImageProcessorCore/Samplers/Resize.cs index fa6eefca1..a9f528aad 100644 --- a/src/ImageProcessorCore/Samplers/Resize.cs +++ b/src/ImageProcessorCore/Samplers/Resize.cs @@ -47,7 +47,6 @@ namespace ImageProcessorCore.Samplers protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { // Jump out, we'll deal with that later. - // TODO: Add rectangle comparison. if (source.Bounds == target.Bounds && sourceRectangle == targetRectangle) { return; @@ -104,80 +103,77 @@ namespace ImageProcessorCore.Samplers // First process the columns. Since we are not using multiple threads startY and endY // are the upper and lower bounds of the source rectangle. Parallel.For( - startY, - endY, + 0, + sourceHeight, y => - { - // Ensure offsets are normalised for cropping and padding. - int offsetY = y - startY; - - for (int x = startX; x < endX; x++) { - int offsetX = x - startX; - - float sum = this.HorizontalWeights[offsetX].Sum; - Weight[] horizontalValues = this.HorizontalWeights[offsetX].Values; + for (int x = startX; x < endX; x++) + { + if (x >= 0 && x < width) + { + // Ensure offsets are normalised for cropping and padding. + int offsetX = x - startX; + float sum = this.HorizontalWeights[offsetX].Sum; + Weight[] horizontalValues = this.HorizontalWeights[offsetX].Values; - // Destination color components - Color destination = new Color(); + // Destination color components + Color destination = new Color(); - for (int i = 0; i < sum; i++) - { - Weight xw = horizontalValues[i]; - int originX = xw.Index; - Color sourceColor = compand ? Color.Expand(source[originX, offsetY]) : source[originX, offsetY]; - destination += sourceColor * xw.Value; - } + for (int i = 0; i < sum; i++) + { + Weight xw = horizontalValues[i]; + int originX = xw.Index; + Color sourceColor = compand ? Color.Expand(source[originX, y]) : source[originX, y]; + destination += sourceColor * xw.Value; + } - if (compand) - { - destination = Color.Compress(destination); - } + if (compand) + { + destination = Color.Compress(destination); + } - if (x >= 0 && x < width && offsetY >= 0 && offsetY < sourceHeight) - { - this.firstPass[x, offsetY] = destination; + this.firstPass[x, y] = destination; + } } - } - }); + }); // Now process the rows. Parallel.For( startY, endY, y => - { - // Ensure offsets are normalised for cropping and padding. - int offsetY = y - startY; - float sum = this.VerticalWeights[offsetY].Sum; - Weight[] verticalValues = this.VerticalWeights[offsetY].Values; - - for (int x = 0; x < width; x++) { - // Destination color components - Color destination = new Color(); - - for (int i = 0; i < sum; i++) + if (y >= 0 && y < height) { - Weight yw = verticalValues[i]; - int originY = yw.Index; - Color sourceColor = compand ? Color.Expand(this.firstPass[x, originY]) : this.firstPass[x, originY]; - destination += sourceColor * yw.Value; - } + // Ensure offsets are normalised for cropping and padding. + int offsetY = y - startY; + float sum = this.VerticalWeights[offsetY].Sum; + Weight[] verticalValues = this.VerticalWeights[offsetY].Values; - if (compand) - { - destination = Color.Compress(destination); - } + for (int x = 0; x < width; x++) + { + // Destination color components + Color destination = new Color(); - if (y >= 0 && y < height) - { - target[x, y] = destination; + for (int i = 0; i < sum; i++) + { + Weight yw = verticalValues[i]; + int originY = yw.Index; + Color sourceColor = compand ? Color.Expand(this.firstPass[x, originY]) : this.firstPass[x, originY]; + destination += sourceColor * yw.Value; + } + + if (compand) + { + destination = Color.Compress(destination); + } + + target[x, y] = destination; + } } - } - this.OnRowProcessed(); - }); + this.OnRowProcessed(); + }); } /// diff --git a/src/ImageProcessorCore/Samplers/ResizeHelper.cs b/src/ImageProcessorCore/Samplers/ResizeHelper.cs index 7a175a6fc..95ed97192 100644 --- a/src/ImageProcessorCore/Samplers/ResizeHelper.cs +++ b/src/ImageProcessorCore/Samplers/ResizeHelper.cs @@ -394,12 +394,14 @@ namespace ImageProcessorCore.Samplers if (widthDiff < heightDiff) { destinationHeight = Convert.ToInt32(width * sourceRatio); + height = destinationHeight; destinationWidth = width; } else if (widthDiff > heightDiff) { - destinationHeight = height; destinationWidth = Convert.ToInt32(height / sourceRatio); + destinationHeight = height; + width = destinationWidth; } else { diff --git a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs index 7b42c7791..2516cf62b 100644 --- a/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs +++ b/tests/ImageProcessorCore.Tests/Processors/Samplers/SamplerTests.cs @@ -182,7 +182,7 @@ { ResizeOptions options = new ResizeOptions() { - Size = new Size(image.Width , image.Height / 2) + Size = new Size(image.Width / 2, image.Height) }; image.Resize(options, this.ProgressUpdate) @@ -214,9 +214,8 @@ { ResizeOptions options = new ResizeOptions() { - Size = new Size(image.Width , image.Height + 200), - Mode = ResizeMode.Pad, - Sampler = new NearestNeighborResampler() + Size = new Size(image.Width + 200, image.Height), + Mode = ResizeMode.Pad }; image.Resize(options, this.ProgressUpdate) @@ -281,8 +280,9 @@ { ResizeOptions options = new ResizeOptions() { - Size = new Size(image.Width + 200, image.Height), - Mode = ResizeMode.Max + Size = new Size(300, 300), + Mode = ResizeMode.Max, + //Sampler = new NearestNeighborResampler() }; image.Resize(options, this.ProgressUpdate) @@ -314,7 +314,7 @@ { ResizeOptions options = new ResizeOptions() { - Size = new Size(image.Width + 200, image.Height), + Size = new Size(image.Width - 50, image.Height - 25), Mode = ResizeMode.Min }; @@ -327,6 +327,39 @@ } } + [Fact] + public void ImageShouldResizeWithStretchMode() + { + if (!Directory.Exists("TestOutput/ResizeStretch")) + { + Directory.CreateDirectory("TestOutput/ResizeStretch"); + } + + foreach (string file in Files) + { + using (FileStream stream = File.OpenRead(file)) + { + Stopwatch watch = Stopwatch.StartNew(); + string filename = Path.GetFileName(file); + + using (Image image = new Image(stream)) + using (FileStream output = File.OpenWrite($"TestOutput/ResizeStretch/{filename}")) + { + ResizeOptions options = new ResizeOptions() + { + Size = new Size(image.Width - 200, image.Height), + Mode = ResizeMode.Stretch + }; + + image.Resize(options, this.ProgressUpdate) + .Save(output); + } + + Trace.WriteLine($"{filename}: {watch.ElapsedMilliseconds}ms"); + } + } + } + [Theory] [MemberData("RotateFlips")] public void ImageShouldRotateFlip(RotateType rotateType, FlipType flipType)