From 4bad05e82b150474b8c2ed55b101db91ec810acd Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 27 Nov 2015 18:13:04 +1100 Subject: [PATCH] A slightly better fix for rotation alpha bleeding. Former-commit-id: 646bf9a47dd4ed4f9654584920323014128d9460 Former-commit-id: ec7c1edbcda7d5029dae26a5dd7ae629302bf633 Former-commit-id: db9785704051ea50c3ed9ea9f03f23c7289e1a6d --- .../Filters/ImageFilterExtensions.cs | 3 +- src/ImageProcessor/Samplers/Resampler.cs | 87 ++++++++++++++----- 2 files changed, 66 insertions(+), 24 deletions(-) diff --git a/src/ImageProcessor/Filters/ImageFilterExtensions.cs b/src/ImageProcessor/Filters/ImageFilterExtensions.cs index f435829b2..81b096c85 100644 --- a/src/ImageProcessor/Filters/ImageFilterExtensions.cs +++ b/src/ImageProcessor/Filters/ImageFilterExtensions.cs @@ -39,8 +39,7 @@ namespace ImageProcessor.Filters /// Combines the given image together with the current one by blending their pixels. /// /// 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 100. + /// The color to set as the background. /// The . public static Image BackgroundColor(this Image source, Color color) { diff --git a/src/ImageProcessor/Samplers/Resampler.cs b/src/ImageProcessor/Samplers/Resampler.cs index 401e4f451..2b81db34e 100644 --- a/src/ImageProcessor/Samplers/Resampler.cs +++ b/src/ImageProcessor/Samplers/Resampler.cs @@ -6,7 +6,7 @@ namespace ImageProcessor.Samplers { using System; - using System.Collections.Immutable; + using System.Collections.Generic; using System.Numerics; using System.Threading.Tasks; @@ -97,6 +97,22 @@ namespace ImageProcessor.Samplers } } + /// + /// Resamples the specified at the specified location + /// and with the specified size. + /// + /// Target image to apply the process to. + /// The source image. Cannot be null. + /// + /// The structure that specifies the location and size of the drawn image. + /// The image is scaled to fit the rectangle. + /// + /// The index of the row within the source image to start processing. + /// The index of the row within the source image to end processing. + /// + /// The method keeps the source image unchanged and returns the + /// the result of image process as new image. + /// private void ApplyResizeOnly(ImageBase target, ImageBase source, Rectangle targetRectangle, int startY, int endY) { int targetY = targetRectangle.Y; @@ -111,13 +127,11 @@ namespace ImageProcessor.Samplers { if (y >= targetY && y < targetBottom) { - ImmutableArray verticalValues = this.verticalWeights[y].Values; - float verticalSum = this.verticalWeights[y].Sum; + Weight[] verticalValues = this.verticalWeights[y].Values; for (int x = startX; x < endX; x++) { - ImmutableArray horizontalValues = this.horizontalWeights[x].Values; - float horizontalSum = this.horizontalWeights[x].Sum; + Weight[] horizontalValues = this.horizontalWeights[x].Values; // Destination color components Color destination = new Color(0, 0, 0, 0); @@ -130,7 +144,7 @@ namespace ImageProcessor.Samplers { int originX = xw.Index; Color sourceColor = Color.InverseCompand(source[originX, originY]); - float weight = (yw.Value / verticalSum) * (xw.Value / horizontalSum); + float weight = yw.Value * xw.Value; destination.R += sourceColor.R * weight; destination.G += sourceColor.G * weight; @@ -150,6 +164,25 @@ namespace ImageProcessor.Samplers }); } + /// + /// Resamples and rotates the specified at the specified location + /// and with the specified size. + /// + /// Target image to apply the process to. + /// The source image. Cannot be null. + /// + /// The structure that specifies the location and size of the drawn image. + /// The image is scaled to fit the rectangle. + /// + /// + /// The structure that specifies the portion of the image object to draw. + /// + /// The index of the row within the source image to start processing. + /// The index of the row within the source image to end processing. + /// + /// The method keeps the source image unchanged and returns the + /// the result of image process as new image. + /// private void ApplyResizeAndRotate(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) { int targetY = targetRectangle.Y; @@ -166,13 +199,11 @@ namespace ImageProcessor.Samplers { if (y >= targetY && y < targetBottom) { - ImmutableArray verticalValues = this.verticalWeights[y].Values; - float verticalSum = this.verticalWeights[y].Sum; + Weight[] verticalValues = this.verticalWeights[y].Values; for (int x = startX; x < endX; x++) { - ImmutableArray horizontalValues = this.horizontalWeights[x].Values; - float horizontalSum = this.horizontalWeights[x].Sum; + Weight[] horizontalValues = this.horizontalWeights[x].Values; // Destination color components Color destination = new Color(0, 0, 0, 0); @@ -193,13 +224,19 @@ namespace ImageProcessor.Samplers if (sourceRectangle.Contains(rotatedX, rotatedY)) { Color sourceColor = Color.InverseCompand(source[rotatedX, rotatedY]); - float weight = (yw.Value / verticalSum) * (xw.Value / horizontalSum); - + float weight = yw.Value * xw.Value; destination.R += sourceColor.R * weight; destination.G += sourceColor.G * weight; destination.B += sourceColor.B * weight; destination.A += sourceColor.A * weight; } + else + { + // This is well hacky but clears up most of the + // Alpha bleeding issues present in rotated images. + float weight = yw.Value * xw.Value; + destination.A += .9f * weight; + } } } @@ -258,7 +295,7 @@ namespace ImageProcessor.Samplers float sum = 0; result[i] = new Weights(); - ImmutableArray.Builder builder = ImmutableArray.CreateBuilder(); + List builder = new List(); for (int a = startU; a <= endU; a++) { float w = sampler.GetValue((a - fu) / scale); @@ -270,7 +307,13 @@ namespace ImageProcessor.Samplers } } - result[i].Values = builder.ToImmutable(); + // Normalise the values + if (Math.Abs(sum) > 0.00001f) + { + builder.ForEach(w => w.Value /= sum); + } + + result[i].Values = builder.ToArray(); result[i].Sum = sum; }); @@ -280,7 +323,7 @@ namespace ImageProcessor.Samplers /// /// Represents the weight to be added to a scaled pixel. /// - protected struct Weight + protected class Weight { /// /// The pixel index. @@ -288,12 +331,7 @@ namespace ImageProcessor.Samplers public readonly int Index; /// - /// The result of the interpolation algorithm. - /// - public readonly float Value; - - /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the class. /// /// The index. /// The value. @@ -302,6 +340,11 @@ namespace ImageProcessor.Samplers this.Index = index; this.Value = value; } + + /// + /// Gets or sets the result of the interpolation algorithm. + /// + public float Value { get; set; } } /// @@ -312,7 +355,7 @@ namespace ImageProcessor.Samplers /// /// Gets or sets the values. /// - public ImmutableArray Values { get; set; } + public Weight[] Values { get; set; } /// /// Gets or sets the sum.