diff --git a/src/ImageProcessor/Colors/Color.cs b/src/ImageProcessor/Colors/Color.cs
index abd3e8620..44ed036e3 100644
--- a/src/ImageProcessor/Colors/Color.cs
+++ b/src/ImageProcessor/Colors/Color.cs
@@ -325,30 +325,6 @@ namespace ImageProcessor
return new Color((first.backingVector + second.backingVector) * .5f);
}
- ///
- /// Linearly interpolates from one color to another based on the given amount.
- ///
- /// The first color value.
- /// The second color value.
- ///
- /// The weight value. At amount = 0, "from" is returned, at amount = 1, "to" is returned.
- ///
- ///
- /// The
- ///
- public static Color Lerp(Color from, Color to, float amount)
- {
- amount = amount.Clamp(0f, 1f);
-
- if (Math.Abs(from.A - 1) < Epsilon && Math.Abs(to.A - 1) < Epsilon)
- {
- return from + (to - from) * amount;
- }
-
- // Premultiplied.
- return from * (1 - amount) + to;
- }
-
///
/// Compresses a linear color signal to its sRGB equivalent.
///
diff --git a/src/ImageProcessor/Colors/ColorSpacialTransforms.cs b/src/ImageProcessor/Colors/ColorSpacialTransforms.cs
deleted file mode 100644
index 6a49708bf..000000000
--- a/src/ImageProcessor/Colors/ColorSpacialTransforms.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageProcessor
-{
- using System.Numerics;
-
- public partial struct Color
- {
- public static Color Multiply(Color source, Color destination)
- {
- if (destination == Color.Black)
- {
- return Color.Black;
- }
- if (destination == Color.White)
- {
- return source;
- }
- return
- new Color(
- new Vector4(
- source.backingVector.X * destination.backingVector.X,
- source.backingVector.Y * destination.backingVector.Y,
- source.backingVector.Z * destination.backingVector.Z,
- source.backingVector.W * destination.backingVector.W));
- }
- }
-}
diff --git a/src/ImageProcessor/Colors/ColorTransforms.cs b/src/ImageProcessor/Colors/ColorTransforms.cs
index 6bd42c254..43bc03251 100644
--- a/src/ImageProcessor/Colors/ColorTransforms.cs
+++ b/src/ImageProcessor/Colors/ColorTransforms.cs
@@ -18,268 +18,56 @@ namespace ImageProcessor
public partial struct Color
{
///
- /// Allows the implicit conversion of an instance of to a
- /// .
+ /// Blends two colors by multiplication.
+ ///
+ /// The source color is multiplied by the destination color and replaces the destination.
+ /// The resultant color is always at least as dark as either the source or destination color.
+ /// Multiplying any color with black results in black. Multiplying any color with white preserves the
+ /// original color.
+ ///
///
- /// The instance of to convert.
+ /// The source color.
+ /// The destination color.
///
- /// An instance of .
+ /// The .
///
- public static implicit operator Color(Bgra32 color)
+ public static Color Multiply(Color source, Color destination)
{
- return new Color(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f);
- }
-
- ///
- /// Allows the implicit conversion of an instance of to a
- /// .
- ///
- /// The instance of to convert.
- ///
- /// An instance of .
- ///
- public static implicit operator Color(Cmyk cmykColor)
- {
- float r = (1 - cmykColor.C) * (1 - cmykColor.K);
- float g = (1 - cmykColor.M) * (1 - cmykColor.K);
- float b = (1 - cmykColor.Y) * (1 - cmykColor.K);
- return new Color(r, g, b);
- }
-
- ///
- /// Allows the implicit conversion of an instance of to a
- /// .
- ///
- /// The instance of to convert.
- ///
- /// An instance of .
- ///
- public static implicit operator Color(YCbCr color)
- {
- float y = color.Y;
- float cb = color.Cb - 128;
- float cr = color.Cr - 128;
-
- float r = (float)(y + (1.402 * cr)) / 255f;
- float g = (float)(y - (0.34414 * cb) - (0.71414 * cr)) / 255f;
- float b = (float)(y + (1.772 * cb)) / 255f;
-
- return new Color(r, g, b);
- }
-
- ///
- /// Allows the implicit conversion of an instance of to a
- /// .
- ///
- /// The instance of to convert.
- ///
- /// An instance of .
- ///
- public static implicit operator Color(CieXyz color)
- {
- float x = color.X / 100F;
- float y = color.Y / 100F;
- float z = color.Z / 100F;
-
- // Then XYZ to RGB (multiplication by 100 was done above already)
- float r = (x * 3.2406F) + (y * -1.5372F) + (z * -0.4986F);
- float g = (x * -0.9689F) + (y * 1.8758F) + (z * 0.0415F);
- float b = (x * 0.0557F) + (y * -0.2040F) + (z * 1.0570F);
-
- return Color.Compress(new Color(r, g, b));
- }
-
- ///
- /// Allows the implicit conversion of an instance of to a
- /// .
- ///
- /// The instance of to convert.
- ///
- /// An instance of .
- ///
- public static implicit operator Color(Hsv color)
- {
- float s = color.S;
- float v = color.V;
-
- if (Math.Abs(s) < Epsilon)
+ if (destination == Color.Black)
{
- return new Color(v, v, v, 1);
+ return Color.Black;
}
- float h = (Math.Abs(color.H - 360) < Epsilon) ? 0 : color.H / 60;
- int i = (int)Math.Truncate(h);
- float f = h - i;
-
- float p = v * (1.0f - s);
- float q = v * (1.0f - (s * f));
- float t = v * (1.0f - (s * (1.0f - f)));
-
- float r, g, b;
- switch (i)
+ if (destination == Color.White)
{
- case 0:
- r = v;
- g = t;
- b = p;
- break;
-
- case 1:
- r = q;
- g = v;
- b = p;
- break;
-
- case 2:
- r = p;
- g = v;
- b = t;
- break;
-
- case 3:
- r = p;
- g = q;
- b = v;
- break;
-
- case 4:
- r = t;
- g = p;
- b = v;
- break;
-
- default:
- r = v;
- g = p;
- b = q;
- break;
+ return source;
}
- return new Color(r, g, b);
+ return new Color(source.backingVector * destination.backingVector);
}
///
- /// Allows the implicit conversion of an instance of to a
- /// .
+ /// Linearly interpolates from one color to another based on the given amount.
///
- /// The instance of to convert.
+ /// The first color value.
+ /// The second color value.
+ ///
+ /// The weight value. At amount = 0, "from" is returned, at amount = 1, "to" is returned.
+ ///
///
- /// An instance of .
+ /// The
///
- public static implicit operator Color(Hsl color)
+ public static Color Lerp(Color source, Color destination, float amount)
{
- float rangedH = color.H / 360f;
- float r = 0;
- float g = 0;
- float b = 0;
- float s = color.S;
- float l = color.L;
+ amount = amount.Clamp(0f, 1f);
- if (Math.Abs(l) > Epsilon)
- {
- if (Math.Abs(s) < Epsilon)
- {
- r = g = b = l;
- }
- else
- {
- float temp2 = (l < 0.5f) ? l * (1f + s) : l + s - (l * s);
- float temp1 = (2f * l) - temp2;
-
- r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F);
- g = GetColorComponent(temp1, temp2, rangedH);
- b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F);
- }
- }
-
- return new Color(r, g, b);
- }
-
- ///
- /// Allows the implicit conversion of an instance of to a
- /// .
- ///
- /// The instance of to convert.
- ///
- /// An instance of .
- ///
- public static implicit operator Color(CieLab cieLabColor)
- {
- // First convert back to XYZ...
- float y = (cieLabColor.L + 16F) / 116F;
- float x = (cieLabColor.A / 500F) + y;
- float z = y - (cieLabColor.B / 200F);
-
- float x3 = x * x * x;
- float y3 = y * y * y;
- float z3 = z * z * z;
-
- x = x3 > 0.008856F ? x3 : (x - 0.137931F) / 7.787F;
- y = (cieLabColor.L > 7.999625F) ? y3 : (cieLabColor.L / 903.3F);
- z = (z3 > 0.008856F) ? z3 : (z - 0.137931F) / 7.787F;
-
- x *= 0.95047F;
- z *= 1.08883F;
-
- // Then XYZ to RGB (multiplication by 100 was done above already)
- float r = (x * 3.2406F) + (y * -1.5372F) + (z * -0.4986F);
- float g = (x * -0.9689F) + (y * 1.8758F) + (z * 0.0415F);
- float b = (x * 0.0557F) + (y * -0.2040F) + (z * 1.0570F);
-
- return Color.Compress(new Color(r, g, b));
- }
-
- ///
- /// Gets the color component from the given values.
- ///
- /// The first value.
- /// The second value.
- /// The third value.
- ///
- /// The .
- ///
- private static float GetColorComponent(float first, float second, float third)
- {
- third = MoveIntoRange(third);
- if (third < 0.1666667F)
- {
- return first + ((second - first) * 6.0f * third);
- }
-
- if (third < 0.5)
- {
- return second;
- }
-
- if (third < 0.6666667F)
- {
- return first + ((second - first) * (0.6666667F - third) * 6.0f);
- }
-
- return first;
- }
-
- ///
- /// Moves the specific value within the acceptable range for
- /// conversion.
- /// Used for converting colors to this type.
- ///
- /// The value to shift.
- ///
- /// The .
- ///
- private static float MoveIntoRange(float value)
- {
- if (value < 0.0)
- {
- value += 1.0f;
- }
- else if (value > 1.0)
+ if (Math.Abs(source.A - 1) < Epsilon && Math.Abs(destination.A - 1) < Epsilon)
{
- value -= 1.0f;
+ return source + ((destination - source) * amount);
}
- return value;
+ // Premultiplied.
+ return (source * (1 - amount)) + destination;
}
}
}
diff --git a/src/ImageProcessor/Colors/ColorspaceTransforms.cs b/src/ImageProcessor/Colors/ColorspaceTransforms.cs
new file mode 100644
index 000000000..334c967fb
--- /dev/null
+++ b/src/ImageProcessor/Colors/ColorspaceTransforms.cs
@@ -0,0 +1,285 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageProcessor
+{
+ using System;
+
+ ///
+ /// Represents a four-component color using red, green, blue, and alpha data.
+ /// Each component is stored in premultiplied format multiplied by the alpha component.
+ ///
+ ///
+ /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
+ /// as it avoids the need to create new values for modification operations.
+ ///
+ public partial struct Color
+ {
+ ///
+ /// Allows the implicit conversion of an instance of to a
+ /// .
+ ///
+ /// The instance of to convert.
+ ///
+ /// An instance of .
+ ///
+ public static implicit operator Color(Bgra32 color)
+ {
+ return new Color(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f);
+ }
+
+ ///
+ /// Allows the implicit conversion of an instance of to a
+ /// .
+ ///
+ /// The instance of to convert.
+ ///
+ /// An instance of .
+ ///
+ public static implicit operator Color(Cmyk cmykColor)
+ {
+ float r = (1 - cmykColor.C) * (1 - cmykColor.K);
+ float g = (1 - cmykColor.M) * (1 - cmykColor.K);
+ float b = (1 - cmykColor.Y) * (1 - cmykColor.K);
+ return new Color(r, g, b);
+ }
+
+ ///
+ /// Allows the implicit conversion of an instance of to a
+ /// .
+ ///
+ /// The instance of to convert.
+ ///
+ /// An instance of .
+ ///
+ public static implicit operator Color(YCbCr color)
+ {
+ float y = color.Y;
+ float cb = color.Cb - 128;
+ float cr = color.Cr - 128;
+
+ float r = (float)(y + (1.402 * cr)) / 255f;
+ float g = (float)(y - (0.34414 * cb) - (0.71414 * cr)) / 255f;
+ float b = (float)(y + (1.772 * cb)) / 255f;
+
+ return new Color(r, g, b);
+ }
+
+ ///
+ /// Allows the implicit conversion of an instance of to a
+ /// .
+ ///
+ /// The instance of to convert.
+ ///
+ /// An instance of .
+ ///
+ public static implicit operator Color(CieXyz color)
+ {
+ float x = color.X / 100F;
+ float y = color.Y / 100F;
+ float z = color.Z / 100F;
+
+ // Then XYZ to RGB (multiplication by 100 was done above already)
+ float r = (x * 3.2406F) + (y * -1.5372F) + (z * -0.4986F);
+ float g = (x * -0.9689F) + (y * 1.8758F) + (z * 0.0415F);
+ float b = (x * 0.0557F) + (y * -0.2040F) + (z * 1.0570F);
+
+ return Color.Compress(new Color(r, g, b));
+ }
+
+ ///
+ /// Allows the implicit conversion of an instance of to a
+ /// .
+ ///
+ /// The instance of to convert.
+ ///
+ /// An instance of .
+ ///
+ public static implicit operator Color(Hsv color)
+ {
+ float s = color.S;
+ float v = color.V;
+
+ if (Math.Abs(s) < Epsilon)
+ {
+ return new Color(v, v, v, 1);
+ }
+
+ float h = (Math.Abs(color.H - 360) < Epsilon) ? 0 : color.H / 60;
+ int i = (int)Math.Truncate(h);
+ float f = h - i;
+
+ float p = v * (1.0f - s);
+ float q = v * (1.0f - (s * f));
+ float t = v * (1.0f - (s * (1.0f - f)));
+
+ float r, g, b;
+ switch (i)
+ {
+ case 0:
+ r = v;
+ g = t;
+ b = p;
+ break;
+
+ case 1:
+ r = q;
+ g = v;
+ b = p;
+ break;
+
+ case 2:
+ r = p;
+ g = v;
+ b = t;
+ break;
+
+ case 3:
+ r = p;
+ g = q;
+ b = v;
+ break;
+
+ case 4:
+ r = t;
+ g = p;
+ b = v;
+ break;
+
+ default:
+ r = v;
+ g = p;
+ b = q;
+ break;
+ }
+
+ return new Color(r, g, b);
+ }
+
+ ///
+ /// Allows the implicit conversion of an instance of to a
+ /// .
+ ///
+ /// The instance of to convert.
+ ///
+ /// An instance of .
+ ///
+ public static implicit operator Color(Hsl color)
+ {
+ float rangedH = color.H / 360f;
+ float r = 0;
+ float g = 0;
+ float b = 0;
+ float s = color.S;
+ float l = color.L;
+
+ if (Math.Abs(l) > Epsilon)
+ {
+ if (Math.Abs(s) < Epsilon)
+ {
+ r = g = b = l;
+ }
+ else
+ {
+ float temp2 = (l < 0.5f) ? l * (1f + s) : l + s - (l * s);
+ float temp1 = (2f * l) - temp2;
+
+ r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F);
+ g = GetColorComponent(temp1, temp2, rangedH);
+ b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F);
+ }
+ }
+
+ return new Color(r, g, b);
+ }
+
+ ///
+ /// Allows the implicit conversion of an instance of to a
+ /// .
+ ///
+ /// The instance of to convert.
+ ///
+ /// An instance of .
+ ///
+ public static implicit operator Color(CieLab cieLabColor)
+ {
+ // First convert back to XYZ...
+ float y = (cieLabColor.L + 16F) / 116F;
+ float x = (cieLabColor.A / 500F) + y;
+ float z = y - (cieLabColor.B / 200F);
+
+ float x3 = x * x * x;
+ float y3 = y * y * y;
+ float z3 = z * z * z;
+
+ x = x3 > 0.008856F ? x3 : (x - 0.137931F) / 7.787F;
+ y = (cieLabColor.L > 7.999625F) ? y3 : (cieLabColor.L / 903.3F);
+ z = (z3 > 0.008856F) ? z3 : (z - 0.137931F) / 7.787F;
+
+ x *= 0.95047F;
+ z *= 1.08883F;
+
+ // Then XYZ to RGB (multiplication by 100 was done above already)
+ float r = (x * 3.2406F) + (y * -1.5372F) + (z * -0.4986F);
+ float g = (x * -0.9689F) + (y * 1.8758F) + (z * 0.0415F);
+ float b = (x * 0.0557F) + (y * -0.2040F) + (z * 1.0570F);
+
+ return Color.Compress(new Color(r, g, b));
+ }
+
+ ///
+ /// Gets the color component from the given values.
+ ///
+ /// The first value.
+ /// The second value.
+ /// The third value.
+ ///
+ /// The .
+ ///
+ private static float GetColorComponent(float first, float second, float third)
+ {
+ third = MoveIntoRange(third);
+ if (third < 0.1666667F)
+ {
+ return first + ((second - first) * 6.0f * third);
+ }
+
+ if (third < 0.5)
+ {
+ return second;
+ }
+
+ if (third < 0.6666667F)
+ {
+ return first + ((second - first) * (0.6666667F - third) * 6.0f);
+ }
+
+ return first;
+ }
+
+ ///
+ /// Moves the specific value within the acceptable range for
+ /// conversion.
+ /// Used for converting colors to this type.
+ ///
+ /// The value to shift.
+ ///
+ /// The .
+ ///
+ private static float MoveIntoRange(float value)
+ {
+ if (value < 0.0)
+ {
+ value += 1.0f;
+ }
+ else if (value > 1.0)
+ {
+ value -= 1.0f;
+ }
+
+ return value;
+ }
+ }
+}
diff --git a/src/ImageProcessor/Samplers/Resampler.cs b/src/ImageProcessor/Samplers/Resampler.cs
index a36d68b36..4fd105f16 100644
--- a/src/ImageProcessor/Samplers/Resampler.cs
+++ b/src/ImageProcessor/Samplers/Resampler.cs
@@ -7,11 +7,8 @@ namespace ImageProcessor.Samplers
{
using System;
using System.Collections.Generic;
- using System.Numerics;
using System.Threading.Tasks;
- using ImageProcessor.Filters;
-
///
/// Provides methods that allow the resampling of images using various algorithms.
///