diff --git a/src/ImageSharp/Color/Color.Conversions.cs b/src/ImageSharp/Color/Color.Conversions.cs
index 0455fd26a4..424b7dcdfe 100644
--- a/src/ImageSharp/Color/Color.Conversions.cs
+++ b/src/ImageSharp/Color/Color.Conversions.cs
@@ -17,56 +17,85 @@ namespace SixLabors.ImageSharp
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Rgba64 pixel) => this.data = pixel;
+ public Color(Rgba64 pixel)
+ {
+ this.data = pixel;
+ this.boxedHighPrecisionPixel = null;
+ }
///
/// Initializes a new instance of the struct.
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Rgba32 pixel) => this.data = new Rgba64(pixel);
+ public Color(Rgba32 pixel)
+ {
+ this.data = new Rgba64(pixel);
+ this.boxedHighPrecisionPixel = null;
+ }
///
/// Initializes a new instance of the struct.
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Argb32 pixel) => this.data = new Rgba64(pixel);
+ public Color(Argb32 pixel)
+ {
+ this.data = new Rgba64(pixel);
+ this.boxedHighPrecisionPixel = null;
+ }
///
/// Initializes a new instance of the struct.
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Bgra32 pixel) => this.data = new Rgba64(pixel);
+ public Color(Bgra32 pixel)
+ {
+ this.data = new Rgba64(pixel);
+ this.boxedHighPrecisionPixel = null;
+ }
///
/// Initializes a new instance of the struct.
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Rgb24 pixel) => this.data = new Rgba64(pixel);
+ public Color(Rgb24 pixel)
+ {
+ this.data = new Rgba64(pixel);
+ this.boxedHighPrecisionPixel = null;
+ }
///
/// Initializes a new instance of the struct.
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Bgr24 pixel) => this.data = new Rgba64(pixel);
+ public Color(Bgr24 pixel)
+ {
+ this.data = new Rgba64(pixel);
+ this.boxedHighPrecisionPixel = null;
+ }
///
/// Initializes a new instance of the struct.
///
/// The containing the color information.
[MethodImpl(InliningOptions.ShortMethod)]
- public Color(Vector4 vector) => this.data = new Rgba64(vector);
+ public Color(Vector4 vector)
+ {
+ vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One);
+ this.boxedHighPrecisionPixel = new RgbaVector(vector.X, vector.Y, vector.Z, vector.W);
+ this.data = default;
+ }
///
/// Converts a to .
///
/// The .
/// The .
- public static explicit operator Vector4(Color color) => color.data.ToVector4();
+ public static explicit operator Vector4(Color color) => color.ToVector4();
///
/// Converts an to .
@@ -74,24 +103,82 @@ namespace SixLabors.ImageSharp
/// The .
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public static explicit operator Color(Vector4 source) => new Color(source);
+ public static explicit operator Color(Vector4 source) => new(source);
[MethodImpl(InliningOptions.ShortMethod)]
- internal Rgba32 ToRgba32() => this.data.ToRgba32();
+ internal Rgba32 ToRgba32()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToRgba32();
+ }
+
+ Rgba32 value = default;
+ this.boxedHighPrecisionPixel.ToRgba32(ref value);
+ return value;
+ }
[MethodImpl(InliningOptions.ShortMethod)]
- internal Bgra32 ToBgra32() => this.data.ToBgra32();
+ internal Bgra32 ToBgra32()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToBgra32();
+ }
+
+ Bgra32 value = default;
+ value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
+ return value;
+ }
[MethodImpl(InliningOptions.ShortMethod)]
- internal Argb32 ToArgb32() => this.data.ToArgb32();
+ internal Argb32 ToArgb32()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToArgb32();
+ }
+
+ Argb32 value = default;
+ value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
+ return value;
+ }
[MethodImpl(InliningOptions.ShortMethod)]
- internal Rgb24 ToRgb24() => this.data.ToRgb24();
+ internal Rgb24 ToRgb24()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToRgb24();
+ }
+
+ Rgb24 value = default;
+ value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
+ return value;
+ }
[MethodImpl(InliningOptions.ShortMethod)]
- internal Bgr24 ToBgr24() => this.data.ToBgr24();
+ internal Bgr24 ToBgr24()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToBgr24();
+ }
+
+ Bgr24 value = default;
+ value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
+ return value;
+ }
[MethodImpl(InliningOptions.ShortMethod)]
- internal Vector4 ToVector4() => this.data.ToVector4();
+ internal Vector4 ToVector4()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToScaledVector4();
+ }
+
+ return this.boxedHighPrecisionPixel.ToScaledVector4();
+ }
}
}
diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs
index d5eedc160b..fe66efcfb5 100644
--- a/src/ImageSharp/Color/Color.cs
+++ b/src/ImageSharp/Color/Color.cs
@@ -4,7 +4,6 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp
@@ -21,6 +20,7 @@ namespace SixLabors.ImageSharp
public readonly partial struct Color : IEquatable
{
private readonly Rgba64 data;
+ private readonly IPixel boxedHighPrecisionPixel;
[MethodImpl(InliningOptions.ShortMethod)]
private Color(byte r, byte g, byte b, byte a)
@@ -30,6 +30,8 @@ namespace SixLabors.ImageSharp
ColorNumerics.UpscaleFrom8BitTo16Bit(g),
ColorNumerics.UpscaleFrom8BitTo16Bit(b),
ColorNumerics.UpscaleFrom8BitTo16Bit(a));
+
+ this.boxedHighPrecisionPixel = null;
}
[MethodImpl(InliningOptions.ShortMethod)]
@@ -40,6 +42,15 @@ namespace SixLabors.ImageSharp
ColorNumerics.UpscaleFrom8BitTo16Bit(g),
ColorNumerics.UpscaleFrom8BitTo16Bit(b),
ushort.MaxValue);
+
+ this.boxedHighPrecisionPixel = null;
+ }
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ private Color(IPixel pixel)
+ {
+ this.boxedHighPrecisionPixel = pixel;
+ this.data = default;
}
///
@@ -52,13 +63,10 @@ namespace SixLabors.ImageSharp
/// otherwise, false.
///
[MethodImpl(InliningOptions.ShortMethod)]
- public static bool operator ==(Color left, Color right)
- {
- return left.Equals(right);
- }
+ public static bool operator ==(Color left, Color right) => left.Equals(right);
///
- /// Checks whether two structures are equal.
+ /// Checks whether two structures are not equal.
///
/// The left hand operand.
/// The right hand operand.
@@ -67,10 +75,7 @@ namespace SixLabors.ImageSharp
/// otherwise, false.
///
[MethodImpl(InliningOptions.ShortMethod)]
- public static bool operator !=(Color left, Color right)
- {
- return !left.Equals(right);
- }
+ public static bool operator !=(Color left, Color right) => !left.Equals(right);
///
/// Creates a from RGBA bytes.
@@ -81,7 +86,7 @@ namespace SixLabors.ImageSharp
/// The alpha component (0-255).
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public static Color FromRgba(byte r, byte g, byte b, byte a) => new Color(r, g, b, a);
+ public static Color FromRgba(byte r, byte g, byte b, byte a) => new(r, g, b, a);
///
/// Creates a from RGB bytes.
@@ -91,7 +96,18 @@ namespace SixLabors.ImageSharp
/// The blue component (0-255).
/// The .
[MethodImpl(InliningOptions.ShortMethod)]
- public static Color FromRgb(byte r, byte g, byte b) => new Color(r, g, b);
+ public static Color FromRgb(byte r, byte g, byte b) => new(r, g, b);
+
+ ///
+ /// Creates a from the given .
+ ///
+ /// The pixel to convert from.
+ /// The pixel format.
+ /// The .
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static Color FromPixel(TPixel pixel)
+ where TPixel : unmanaged, IPixel
+ => new(pixel);
///
/// Creates a new instance of the struct
@@ -213,7 +229,7 @@ namespace SixLabors.ImageSharp
public override string ToString() => this.ToHex();
///
- /// Converts the color instance to a specified type.
+ /// Converts the color instance to a specified type.
///
/// The pixel type to convert to.
/// The pixel value.
@@ -221,13 +237,18 @@ namespace SixLabors.ImageSharp
public TPixel ToPixel()
where TPixel : unmanaged, IPixel
{
- TPixel pixel = default;
+ if (this.boxedHighPrecisionPixel is TPixel pixel)
+ {
+ return pixel;
+ }
+
+ pixel = default;
pixel.FromRgba64(this.data);
return pixel;
}
///
- /// Bulk converts a span of to a span of a specified type.
+ /// Bulk converts a span of to a span of a specified type.
///
/// The pixel type to convert to.
/// The configuration.
@@ -240,28 +261,38 @@ namespace SixLabors.ImageSharp
Span destination)
where TPixel : unmanaged, IPixel
{
- ReadOnlySpan rgba64Span = MemoryMarshal.Cast(source);
- PixelOperations.Instance.FromRgba64(configuration, rgba64Span, destination);
+ Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
+ for (int i = 0; i < source.Length; i++)
+ {
+ destination[i] = source[i].ToPixel();
+ }
}
///
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Color other)
{
- return this.data.PackedValue == other.data.PackedValue;
+ if (this.boxedHighPrecisionPixel is null && other.boxedHighPrecisionPixel is null)
+ {
+ return this.data.PackedValue == other.data.PackedValue;
+ }
+
+ return this.ToVector4().Equals(other.ToVector4());
}
///
- public override bool Equals(object obj)
- {
- return obj is Color other && this.Equals(other);
- }
+ public override bool Equals(object obj) => obj is Color other && this.Equals(other);
///
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode()
{
- return this.data.PackedValue.GetHashCode();
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.PackedValue.GetHashCode();
+ }
+
+ return this.boxedHighPrecisionPixel.GetHashCode();
}
}
}
diff --git a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs
index ee1820de77..d3f3cf126e 100644
--- a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs
+++ b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs
@@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void Rgb24()
{
- var source = new Rgb24(1, 22, 231);
+ var source = new Rgb24(1, 22, 231);
// Act:
var color = new Color(source);
@@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.Tests
[Fact]
public void Bgr24()
{
- var source = new Bgr24(1, 22, 231);
+ var source = new Bgr24(1, 22, 231);
// Act:
var color = new Color(source);
@@ -88,6 +88,19 @@ namespace SixLabors.ImageSharp.Tests
Bgr24 data = color;
Assert.Equal(source, data);
}
+
+ [Fact]
+ public void TPixel()
+ {
+ var source = new RgbaVector(1, .1F, .133F, .864F);
+
+ // Act:
+ var color = Color.FromPixel(source);
+
+ // Assert:
+ RgbaVector data = color.ToPixel();
+ Assert.Equal(source, data);
+ }
}
}
}