Browse Source

Fix blending on #14

ALso impove glow, vignette and background color.
af/merge-core
James Jackson-South 10 years ago
parent
commit
128a0f24b6
  1. 37
      src/ImageSharp/Colors/Vector4BlendTransforms.cs
  2. 2
      src/ImageSharp/Filters/Processors/Effects/BackgroundColorProcessor.cs
  3. 13
      src/ImageSharp/Filters/Processors/Overlays/BlendProcessor.cs
  4. 14
      src/ImageSharp/Filters/Processors/Overlays/GlowProcessor.cs
  5. 2
      src/ImageSharp/Filters/Processors/Overlays/VignetteProcessor.cs

37
src/ImageSharp/Colors/Vector4BlendTransforms.cs

@ -17,7 +17,7 @@ namespace ImageSharp
/// <summary>
/// The epsilon for comparing floating point numbers.
/// </summary>
private const float Epsilon = 0.001F;
private const float Epsilon = 0.0001F;
/// <summary>
/// The blending formula simply selects the source vector.
@ -187,7 +187,7 @@ namespace ImageSharp
/// <summary>
/// Linearly interpolates from one vector to another based on the given weighting.
/// The two vectors are premultiplied by their W component before operating.
/// The two vectors are premultiplied before operating.
/// </summary>
/// <param name="backdrop">The backdrop vector.</param>
/// <param name="source">The source vector.</param>
@ -195,20 +195,43 @@ namespace ImageSharp
/// A value between 0 and 1 indicating the weight of the second source vector.
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
/// </param>
/// <returns>
/// <returns>
/// The <see cref="Vector4"/>
/// </returns>
public static Vector4 PremultipliedLerp(Vector4 backdrop, Vector4 source, float amount)
{
amount = amount.Clamp(0, 1);
backdrop = backdrop * new Vector4(backdrop.X, backdrop.Y, backdrop.Z, 1) * backdrop.W;
source = source * new Vector4(source.X, source.Y, source.Z, 1) * source.W;
return Vector4.Lerp(backdrop, source, amount) / new Vector4(source.W, source.W, source.W, 1);
// Santize on zero alpha
if (Math.Abs(backdrop.W) < Epsilon)
{
source.W *= amount;
return source;
}
if (Math.Abs(source.W) < Epsilon)
{
return backdrop;
}
// Premultiply the source vector.
// Oddly premultiplying the background vector creates dark outlines when pixels
// Have low alpha values.
source = new Vector4(source.X, source.Y, source.Z, 1) * (source.W * amount);
// This should be implementing the following formula
// https://en.wikipedia.org/wiki/Alpha_compositing
// Vout = Vs + Vb (1 - Vsa)
// Aout = Vsa + Vsb (1 - Vsa)
Vector3 inverseW = new Vector3(1 - source.W);
Vector3 xyzB = new Vector3(backdrop.X, backdrop.Y, backdrop.Z);
Vector3 xyzS = new Vector3(source.X, source.Y, source.Z);
return new Vector4(xyzS + (xyzB * inverseW), source.W + (backdrop.W * (1 - source.W)));
}
/// <summary>
/// Multiplies or screens the color component, depending on the component value.
/// Multiplies or screens the backdrop component, depending on the component value.
/// </summary>
/// <param name="b">The backdrop component.</param>
/// <param name="s">The source component.</param>

2
src/ImageSharp/Filters/Processors/Effects/BackgroundColorProcessor.cs

@ -79,7 +79,7 @@ namespace ImageSharp.Processors
if (a < 1 && a > 0)
{
color = Vector4.Lerp(color, backgroundColor, .5F);
color = Vector4BlendTransforms.PremultipliedLerp(backgroundColor, color, .5F);
}
if (Math.Abs(a) < Epsilon)

13
src/ImageSharp/Filters/Processors/Overlays/BlendProcessor.cs

@ -82,17 +82,14 @@ namespace ImageSharp.Processors
{
for (int x = minX; x < maxX; x++)
{
Vector4 color = sourcePixels[x, y].ToVector4();
Vector4 blendedColor = toBlendPixels[x - minX, y - minY].ToVector4();
Vector4 backgroundVector = sourcePixels[x, y].ToVector4();
Vector4 sourceVector = toBlendPixels[x - minX, y - minY].ToVector4();
if (blendedColor.W > 0)
{
// Lerping colors is dependent on the alpha of the blended color
color = Vector4BlendTransforms.PremultipliedLerp(color, blendedColor, alpha);
}
// Lerping colors is dependent on the alpha of the blended color
backgroundVector = Vector4BlendTransforms.PremultipliedLerp(backgroundVector, sourceVector, alpha);
TColor packed = default(TColor);
packed.PackFromVector4(color);
packed.PackFromVector4(backgroundVector);
sourcePixels[x, y] = packed;
}
});

14
src/ImageSharp/Filters/Processors/Overlays/GlowProcessor.cs

@ -77,15 +77,11 @@ namespace ImageSharp.Processors
for (int x = minX; x < maxX; x++)
{
int offsetX = x - startX;
if (ellipse.Contains(offsetX, offsetY))
{
// TODO: Premultiply?
float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY));
Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4();
TColor packed = default(TColor);
packed.PackFromVector4(Vector4.Lerp(glowColor.ToVector4(), sourceColor, distance / maxDistance));
sourcePixels[offsetX, offsetY] = packed;
}
float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY));
Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4();
TColor packed = default(TColor);
packed.PackFromVector4(Vector4BlendTransforms.PremultipliedLerp(sourceColor, glowColor.ToVector4(), 1 - (.95F * (distance / maxDistance))));
sourcePixels[offsetX, offsetY] = packed;
}
});
}

2
src/ImageSharp/Filters/Processors/Overlays/VignetteProcessor.cs

@ -86,7 +86,7 @@ namespace ImageSharp.Processors
float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY));
Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4();
TColor packed = default(TColor);
packed.PackFromVector4(Vector4.Lerp(vignetteColor.ToVector4(), sourceColor, 1 - (.9F * (distance / maxDistance))));
packed.PackFromVector4(Vector4BlendTransforms.PremultipliedLerp(sourceColor, vignetteColor.ToVector4(), .9F * (distance / maxDistance)));
sourcePixels[offsetX, offsetY] = packed;
}
});

Loading…
Cancel
Save