diff --git a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs
index 7cb193e82..64ebeb1f3 100644
--- a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs
+++ b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs
@@ -12,6 +12,32 @@ namespace SixLabors.ImageSharp
///
internal static class Vector4Extensions
{
+ ///
+ /// Premultiplies the "x", "y", "z" components of a vector by its "w" component leaving the "w" component intact.
+ ///
+ /// The to premultiply
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector4 Premultiply(this Vector4 source)
+ {
+ float w = source.W;
+ Vector4 premultiplied = source * w;
+ return new Vector4(premultiplied.X, premultiplied.Y, premultiplied.Z, w);
+ }
+
+ ///
+ /// Reverses the result of premultiplying a vector via .
+ ///
+ /// The to premultiply
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Vector4 UnPremultiply(this Vector4 source)
+ {
+ float w = source.W;
+ Vector4 unpremultiplied = source / w;
+ return new Vector4(unpremultiplied.X, unpremultiplied.Y, unpremultiplied.Z, w);
+ }
+
///
/// Compresses a linear color signal to its sRGB equivalent.
///
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
index b85432ac5..cf9b7be9c 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
@@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
int offsetX = x + fxr;
offsetX = offsetX.Clamp(0, maxX);
- var currentColor = sourceOffsetRow[offsetX].ToVector4();
+ Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply();
if (fy < kernelXHeight)
{
@@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
float blue = MathF.Sqrt((bX * bX) + (bY * bY));
ref TPixel pixel = ref targetRow[x];
- pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W));
+ pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply());
}
});
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
index 362fa5c50..57f434ee0 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
@@ -113,13 +113,13 @@ namespace SixLabors.ImageSharp.Processing.Processors
offsetX = offsetX.Clamp(0, maxX);
- var currentColor = row[offsetX].ToVector4();
+ Vector4 currentColor = row[offsetX].ToVector4().Premultiply();
destination += kernel[fy, fx] * currentColor;
}
}
ref TPixel pixel = ref targetRow[x];
- pixel.PackFromVector4(destination);
+ pixel.PackFromVector4(destination.UnPremultiply());
}
});
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs
index c0d3fdcfe..96db9a4ce 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs
@@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
offsetX = offsetX.Clamp(0, maxX);
- var currentColor = sourceOffsetRow[offsetX].ToVector4();
+ Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply();
currentColor *= this.KernelXY[fy, fx];
red += currentColor.X;
@@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Processors
}
ref TPixel pixel = ref targetRow[x];
- pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W));
+ pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply());
}
});