Browse Source

Optimize color transforms

Former-commit-id: 1a4e60efcbbd808458de430eb0c9c97c3c43d3e3
Former-commit-id: 873233f36b1496b8d4dfa05785db88e63eff7bf7
Former-commit-id: 6958707f80b777c1daa04047b14480da56d1d73c
af/merge-core
James Jackson-South 10 years ago
parent
commit
af3ad14a11
  1. 20
      src/ImageProcessor/Colors/ColorTransforms.cs
  2. 9
      src/ImageProcessor/Colors/Colorspaces/Bgra32.cs
  3. 36
      src/ImageProcessor/Colors/Colorspaces/CieLab.cs
  4. 6
      src/ImageProcessor/Colors/Colorspaces/CieXyz.cs
  5. 27
      src/ImageProcessor/Colors/Colorspaces/Cmyk.cs
  6. 4
      src/ImageProcessor/Colors/Colorspaces/Hsl.cs
  7. 4
      src/ImageProcessor/Colors/Colorspaces/Hsv.cs
  8. 12
      src/ImageProcessor/Colors/Colorspaces/YCbCr.cs

20
src/ImageProcessor/Colors/ColorTransforms.cs

@ -186,9 +186,9 @@ namespace ImageProcessor
float temp2 = (l < 0.5f) ? l * (1f + s) : l + s - (l * s); float temp2 = (l < 0.5f) ? l * (1f + s) : l + s - (l * s);
float temp1 = (2f * l) - temp2; float temp1 = (2f * l) - temp2;
r = GetColorComponent(temp1, temp2, rangedH + (1 / 3f)); r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F);
g = GetColorComponent(temp1, temp2, rangedH); g = GetColorComponent(temp1, temp2, rangedH);
b = GetColorComponent(temp1, temp2, rangedH - (1 / 3f)); b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F);
} }
} }
@ -207,16 +207,16 @@ namespace ImageProcessor
{ {
// First convert back to XYZ... // First convert back to XYZ...
float y = (cieLabColor.L + 16F) / 116F; float y = (cieLabColor.L + 16F) / 116F;
float x = cieLabColor.A / 500F + y; float x = (cieLabColor.A / 500F) + y;
float z = y - cieLabColor.B / 200F; float z = y - (cieLabColor.B / 200F);
float x3 = x * x * x; float x3 = x * x * x;
float y3 = y * y * y; float y3 = y * y * y;
float z3 = z * z * z; float z3 = z * z * z;
x = x3 > 0.008856F ? x3 : (x - 16F / 116F) / 7.787F; x = x3 > 0.008856F ? x3 : (x - 0.137931F) / 7.787F;
y = (cieLabColor.L > 0.008856F * 903.3F) ? y3 : (cieLabColor.L / 903.3F); y = (cieLabColor.L > 7.999625F) ? y3 : (cieLabColor.L / 903.3F);
z = (z3 > 0.008856F) ? z3 : (z - 16F / 116F) / 7.787F; z = (z3 > 0.008856F) ? z3 : (z - 0.137931F) / 7.787F;
x *= 0.95047F; x *= 0.95047F;
z *= 1.08883F; z *= 1.08883F;
@ -241,7 +241,7 @@ namespace ImageProcessor
private static float GetColorComponent(float first, float second, float third) private static float GetColorComponent(float first, float second, float third)
{ {
third = MoveIntoRange(third); third = MoveIntoRange(third);
if (third < 1.0 / 6.0) if (third < 0.1666667F)
{ {
return first + ((second - first) * 6.0f * third); return first + ((second - first) * 6.0f * third);
} }
@ -251,9 +251,9 @@ namespace ImageProcessor
return second; return second;
} }
if (third < 2.0 / 3.0) if (third < 0.6666667F)
{ {
return first + ((second - first) * ((2.0f / 3.0f) - third) * 6.0f); return first + ((second - first) * (0.6666667F - third) * 6.0f);
} }
return first; return first;

9
src/ImageProcessor/Colors/Colorspaces/Bgra32.cs

@ -45,10 +45,7 @@ namespace ImageProcessor
public Bgra32(byte b, byte g, byte r, byte a) public Bgra32(byte b, byte g, byte r, byte a)
: this() : this()
{ {
this.backingVector.X = b.Clamp(0, 255); this.backingVector = Vector4.Clamp(new Vector4(b, g, r, a), Vector4.Zero, new Vector4(255));
this.backingVector.Y = g.Clamp(0, 255);
this.backingVector.Z = r.Clamp(0, 255);
this.backingVector.W = a.Clamp(0, 255);
} }
/// <summary> /// <summary>
@ -94,8 +91,8 @@ namespace ImageProcessor
/// </returns> /// </returns>
public static implicit operator Bgra32(Color color) public static implicit operator Bgra32(Color color)
{ {
color = color.Limited; color = color.Limited * 255f;
return new Bgra32((255f * color.B).ToByte(), (255f * color.G).ToByte(), (255f * color.R).ToByte(), (255f * color.A).ToByte()); return new Bgra32((byte)color.B, (byte)color.G, (byte)color.R, (byte)color.A);
} }
/// <summary> /// <summary>

36
src/ImageProcessor/Colors/Colorspaces/CieLab.cs

@ -39,9 +39,7 @@ namespace ImageProcessor
public CieLab(float l, float a, float b) public CieLab(float l, float a, float b)
: this() : this()
{ {
this.backingVector.X = ClampL(l); this.backingVector = Vector3.Clamp(new Vector3(l, a, b), new Vector3(0, -100, -100), new Vector3(100));
this.backingVector.Y = ClampAB(a);
this.backingVector.Z = ClampAB(b);
} }
/// <summary> /// <summary>
@ -81,7 +79,7 @@ namespace ImageProcessor
public static implicit operator CieLab(Color color) public static implicit operator CieLab(Color color)
{ {
// First convert to CIE XYZ // First convert to CIE XYZ
color = Color.Expand(color.Limited); color = Color.Expand(color);
float x = (color.R * 0.4124F) + (color.G * 0.3576F) + (color.B * 0.1805F); float x = (color.R * 0.4124F) + (color.G * 0.3576F) + (color.B * 0.1805F);
float y = (color.R * 0.2126F) + (color.G * 0.7152F) + (color.B * 0.0722F); float y = (color.R * 0.2126F) + (color.G * 0.7152F) + (color.B * 0.0722F);
@ -92,9 +90,9 @@ namespace ImageProcessor
//y /= 1F; //y /= 1F;
z /= 1.08883F; z /= 1.08883F;
x = x > 0.008856F ? (float)Math.Pow(x, 1F / 3F) : (903.3F * x + 16F) / 116F; x = x > 0.008856F ? (float)Math.Pow(x, 0.3333333F) : (903.3F * x + 16F) / 116F;
y = y > 0.008856F ? (float)Math.Pow(y, 1F / 3F) : (903.3F * y + 16F) / 116F; y = y > 0.008856F ? (float)Math.Pow(y, 0.3333333F) : (903.3F * y + 16F) / 116F;
z = z > 0.008856F ? (float)Math.Pow(z, 1F / 3F) : (903.3F * z + 16F) / 116F; z = z > 0.008856F ? (float)Math.Pow(z, 0.3333333F) : (903.3F * z + 16F) / 116F;
float l = Math.Max(0, (116F * y) - 16F); float l = Math.Max(0, (116F * y) - 16F);
float a = 500F * (x - y); float a = 500F * (x - y);
@ -179,30 +177,6 @@ namespace ImageProcessor
&& Math.Abs(this.B - other.B) < precision; && Math.Abs(this.B - other.B) < precision;
} }
/// <summary>
/// Checks the range for lightness.
/// </summary>
/// <param name="value">The value to check.</param>
/// <returns>
/// The sanitized <see cref="float"/>.
/// </returns>
private static float ClampL(float value)
{
return value.Clamp(0, 100);
}
/// <summary>
/// Checks the range for components A or B.
/// </summary>
/// <param name="value">The value to check.</param>
/// <returns>
/// The sanitized <see cref="float"/>.
/// </returns>
private static float ClampAB(float value)
{
return value.Clamp(-100, 100);
}
/// <summary> /// <summary>
/// Returns the hash code for this instance. /// Returns the hash code for this instance.
/// </summary> /// </summary>

6
src/ImageProcessor/Colors/Colorspaces/CieXyz.cs

@ -40,9 +40,7 @@ namespace ImageProcessor
: this() : this()
{ {
// Not clamping as documentation about this space seems to indicate "usual" ranges // Not clamping as documentation about this space seems to indicate "usual" ranges
this.backingVector.X = x; this.backingVector = new Vector3(x, y, z);
this.backingVector.Y = y;
this.backingVector.Z = z;
} }
/// <summary> /// <summary>
@ -81,7 +79,7 @@ namespace ImageProcessor
/// </returns> /// </returns>
public static implicit operator CieXyz(Color color) public static implicit operator CieXyz(Color color)
{ {
color = Color.Expand(color.Limited); color = Color.Expand(color);
float x = (color.R * 0.4124F) + (color.G * 0.3576F) + (color.B * 0.1805F); float x = (color.R * 0.4124F) + (color.G * 0.3576F) + (color.B * 0.1805F);
float y = (color.R * 0.2126F) + (color.G * 0.7152F) + (color.B * 0.0722F); float y = (color.R * 0.2126F) + (color.G * 0.7152F) + (color.B * 0.0722F);

27
src/ImageProcessor/Colors/Colorspaces/Cmyk.cs

@ -32,17 +32,14 @@ namespace ImageProcessor
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Cmyk"/> struct. /// Initializes a new instance of the <see cref="Cmyk"/> struct.
/// </summary> /// </summary>
/// <param name="cyan">The cyan component.</param> /// <param name="c">The cyan component.</param>
/// <param name="magenta">The magenta component.</param> /// <param name="m">The magenta component.</param>
/// <param name="yellow">The yellow component.</param> /// <param name="y">The yellow component.</param>
/// <param name="keyline">The keyline black component.</param> /// <param name="k">The keyline black component.</param>
public Cmyk(float cyan, float magenta, float yellow, float keyline) public Cmyk(float c, float m, float y, float k)
: this() : this()
{ {
this.backingVector.X = Clamp(cyan); this.backingVector = Vector4.Clamp(new Vector4(c, m, y, k), Vector4.Zero, Vector4.One);
this.backingVector.Y = Clamp(magenta);
this.backingVector.Z = Clamp(yellow);
this.backingVector.W = Clamp(keyline);
} }
/// <summary> /// <summary>
@ -184,18 +181,6 @@ namespace ImageProcessor
&& Math.Abs(this.K - other.K) < precision; && Math.Abs(this.K - other.K) < precision;
} }
/// <summary>
/// Checks the range of the given value to ensure that it remains within the acceptable boundaries.
/// </summary>
/// <param name="value">The value to check.</param>
/// <returns>
/// The sanitized <see cref="float"/>.
/// </returns>
private static float Clamp(float value)
{
return value.Clamp(0, 1);
}
/// <summary> /// <summary>
/// Returns the hash code for this instance. /// Returns the hash code for this instance.
/// </summary> /// </summary>

4
src/ImageProcessor/Colors/Colorspaces/Hsl.cs

@ -37,9 +37,7 @@ namespace ImageProcessor
/// <param name="l">The l value (lightness) component.</param> /// <param name="l">The l value (lightness) component.</param>
public Hsl(float h, float s, float l) public Hsl(float h, float s, float l)
{ {
this.backingVector.X = h.Clamp(0, 360); this.backingVector = Vector3.Clamp(new Vector3(h, s, l), Vector3.Zero, new Vector3(360, 1, 1));
this.backingVector.Y = s.Clamp(0, 1);
this.backingVector.Z = l.Clamp(0, 1);
} }
/// <summary> /// <summary>

4
src/ImageProcessor/Colors/Colorspaces/Hsv.cs

@ -37,9 +37,7 @@ namespace ImageProcessor
/// <param name="v">The v value (brightness) component.</param> /// <param name="v">The v value (brightness) component.</param>
public Hsv(float h, float s, float v) public Hsv(float h, float s, float v)
{ {
this.backingVector.X = h.Clamp(0, 360); this.backingVector = Vector3.Clamp(new Vector3(h, s, v), Vector3.Zero, new Vector3(360, 1, 1));
this.backingVector.Y = s.Clamp(0, 1);
this.backingVector.Z = v.Clamp(0, 1);
} }
/// <summary> /// <summary>

12
src/ImageProcessor/Colors/Colorspaces/YCbCr.cs

@ -40,9 +40,7 @@ namespace ImageProcessor
public YCbCr(float y, float cb, float cr) public YCbCr(float y, float cb, float cr)
: this() : this()
{ {
this.backingVector.X = y.Clamp(0, 255); this.backingVector = Vector3.Clamp(new Vector3(y, cb, cr), Vector3.Zero, new Vector3(255));
this.backingVector.Y = cb.Clamp(0, 255);
this.backingVector.Z = cr.Clamp(0, 255);
} }
/// <summary> /// <summary>
@ -81,10 +79,10 @@ namespace ImageProcessor
/// </returns> /// </returns>
public static implicit operator YCbCr(Color color) public static implicit operator YCbCr(Color color)
{ {
color = Color.ToNonPremultiplied(color.Limited); color = Color.ToNonPremultiplied(color.Limited) * 255f;
float r = color.R * 255f; float r = color.R;
float g = color.G * 255f; float g = color.G;
float b = color.B * 255f; float b = color.B;
float y = (float)((0.299 * r) + (0.587 * g) + (0.114 * b)); float y = (float)((0.299 * r) + (0.587 * g) + (0.114 * b));
float cb = 128 + (float)((-0.168736 * r) - (0.331264 * g) + (0.5 * b)); float cb = 128 + (float)((-0.168736 * r) - (0.331264 * g) + (0.5 * b));

Loading…
Cancel
Save