Browse Source

A slightly better fix for rotation alpha bleeding.

Former-commit-id: 646bf9a47dd4ed4f9654584920323014128d9460
Former-commit-id: ec7c1edbcda7d5029dae26a5dd7ae629302bf633
Former-commit-id: db9785704051ea50c3ed9ea9f03f23c7289e1a6d
pull/17/head
James Jackson-South 10 years ago
parent
commit
4bad05e82b
  1. 3
      src/ImageProcessor/Filters/ImageFilterExtensions.cs
  2. 87
      src/ImageProcessor/Samplers/Resampler.cs

3
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.
/// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="percent">The opacity of the image image to blend. Must be between 0 and 100.</param>
/// <param name="color">The color to set as the background.</param>
/// <returns>The <see cref="Image"/>.</returns>
public static Image BackgroundColor(this Image source, Color color)
{

87
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
}
}
/// <summary>
/// Resamples the specified <see cref="ImageBase"/> at the specified location
/// and with the specified size.
/// </summary>
/// <param name="target">Target image to apply the process to.</param>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="targetRectangle">
/// The <see cref="Rectangle"/> structure that specifies the location and size of the drawn image.
/// The image is scaled to fit the rectangle.
/// </param>
/// <param name="startY">The index of the row within the source image to start processing.</param>
/// <param name="endY">The index of the row within the source image to end processing.</param>
/// <remarks>
/// The method keeps the source image unchanged and returns the
/// the result of image process as new image.
/// </remarks>
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<Weight> 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<Weight> 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
});
}
/// <summary>
/// Resamples and rotates the specified <see cref="ImageBase"/> at the specified location
/// and with the specified size.
/// </summary>
/// <param name="target">Target image to apply the process to.</param>
/// <param name="source">The source image. Cannot be null.</param>
/// <param name="targetRectangle">
/// The <see cref="Rectangle"/> structure that specifies the location and size of the drawn image.
/// The image is scaled to fit the rectangle.
/// </param>
/// <param name="sourceRectangle">
/// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
/// </param>
/// <param name="startY">The index of the row within the source image to start processing.</param>
/// <param name="endY">The index of the row within the source image to end processing.</param>
/// <remarks>
/// The method keeps the source image unchanged and returns the
/// the result of image process as new image.
/// </remarks>
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<Weight> 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<Weight> 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<Weight>.Builder builder = ImmutableArray.CreateBuilder<Weight>();
List<Weight> builder = new List<Weight>();
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
/// <summary>
/// Represents the weight to be added to a scaled pixel.
/// </summary>
protected struct Weight
protected class Weight
{
/// <summary>
/// The pixel index.
@ -288,12 +331,7 @@ namespace ImageProcessor.Samplers
public readonly int Index;
/// <summary>
/// The result of the interpolation algorithm.
/// </summary>
public readonly float Value;
/// <summary>
/// Initializes a new instance of the <see cref="Weight"/> struct.
/// Initializes a new instance of the <see cref="Weight"/> class.
/// </summary>
/// <param name="index">The index.</param>
/// <param name="value">The value.</param>
@ -302,6 +340,11 @@ namespace ImageProcessor.Samplers
this.Index = index;
this.Value = value;
}
/// <summary>
/// Gets or sets the result of the interpolation algorithm.
/// </summary>
public float Value { get; set; }
}
/// <summary>
@ -312,7 +355,7 @@ namespace ImageProcessor.Samplers
/// <summary>
/// Gets or sets the values.
/// </summary>
public ImmutableArray<Weight> Values { get; set; }
public Weight[] Values { get; set; }
/// <summary>
/// Gets or sets the sum.

Loading…
Cancel
Save