diff --git a/.editorconfig b/.editorconfig
index e69de29bb2..f39b267256 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -0,0 +1,3 @@
+[*.cs]
+indent_style = space
+indent_size = 4
diff --git a/src/ImageSharp/Colors/PackedPixel/Argb.cs b/src/ImageSharp/Colors/PackedPixel/Argb.cs
new file mode 100644
index 0000000000..75150873a2
--- /dev/null
+++ b/src/ImageSharp/Colors/PackedPixel/Argb.cs
@@ -0,0 +1,280 @@
+using System;
+using System.Numerics;
+
+namespace ImageSharp
+{
+ ///
+ /// Packed pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
+ /// The color components are stored in alpha, red, green, and blue order.
+ ///
+ ///
+ /// 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 class Argb : IPackedPixel, IEquatable
+ {
+ const int BlueShift = 0;
+ const uint BlueMask = 0xFFFFFF00;
+ const int GreenShift = 8;
+ const uint GreenMask = 0xFFFF00FF;
+ const int RedShift = 16;
+ const uint RedMask = 0xFF00FFFF;
+ const int AlphaShift = 24;
+ const uint AlphaMask = 0x00FFFFFF;
+
+ ///
+ /// The maximum byte value.
+ ///
+ readonly static Vector4 MaxBytes = new Vector4(255);
+
+ ///
+ /// The half vector value.
+ ///
+ readonly static Vector4 Half = new Vector4(0.5F);
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The red component.
+ /// The green component.
+ /// The blue component.
+ /// The alpha component.
+ public Argb(byte r, byte g, byte b, byte a = 255)
+ {
+ PackedValue = Pack(r, g, b, a);
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The red component.
+ /// The green component.
+ /// The blue component.
+ /// The alpha component.
+ public Argb(float r, float g, float b, float a = 1)
+ {
+ PackedValue = Pack(r, g, b, a);
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ ///
+ /// The vector containing the components for the packed vector.
+ ///
+ public Argb(Vector3 vector)
+ {
+ PackedValue = Pack(ref vector);
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ ///
+ /// The vector containing the components for the packed vector.
+ ///
+ public Argb(Vector4 vector)
+ {
+ PackedValue = Pack(ref vector);
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ ///
+ /// The packed value.
+ ///
+ public Argb(uint packed = 0)
+ {
+ PackedValue = packed;
+ }
+ ///
+ /// Gets or sets the red component.
+ ///
+ public byte R
+ {
+ get
+ {
+ return (byte)(PackedValue >> RedShift);
+ }
+
+ set
+ {
+ PackedValue = PackedValue & RedMask | (uint)value << RedShift;
+ }
+ }
+
+ ///
+ /// Gets or sets the green component.
+ ///
+ public byte G
+ {
+ get
+ {
+ return (byte)(PackedValue >> GreenShift);
+ }
+
+ set
+ {
+ PackedValue = PackedValue & GreenMask | (uint)value << GreenShift;
+ }
+ }
+
+ ///
+ /// Gets or sets the blue component.
+ ///
+ public byte B
+ {
+ get
+ {
+ return (byte)(PackedValue >> BlueShift);
+ }
+
+ set
+ {
+ PackedValue = PackedValue & BlueMask | (uint)value << BlueShift;
+ }
+ }
+
+ ///
+ /// Gets or sets the alpha component.
+ ///
+ public byte A
+ {
+ get
+ {
+ return (byte)(PackedValue >> AlphaShift);
+ }
+
+ set
+ {
+ PackedValue = PackedValue & AlphaMask | (uint)value << AlphaShift;
+ }
+ }
+
+ ///
+ public void PackFromVector4(Vector4 vector)
+ {
+ PackedValue = Pack(ref vector);
+ }
+
+ ///
+ public Vector4 ToVector4()
+ {
+ return new Vector4(R, G, B, A) / MaxBytes;
+ }
+
+ ///
+ public uint PackedValue { get; set; }
+
+ ///
+ public void PackFromBytes(byte x, byte y, byte z, byte w)
+ {
+ PackedValue = Pack(x, y, z, w);
+ }
+
+ ///
+ /// Packs the four floats into a .
+ ///
+ /// The x-component
+ /// The y-component
+ /// The z-component
+ /// The w-component
+ /// The
+ static uint Pack(float x, float y, float z, float w)
+ {
+ var value = new Vector4(x, y, z, w);
+ return Pack(ref value);
+ }
+ ///
+ /// Packs the four floats into a .
+ ///
+ /// The x-component
+ /// The y-component
+ /// The z-component
+ /// The w-component
+ /// The
+ static uint Pack(byte x, byte y, byte z, byte w)
+ {
+ return (uint)(x << RedShift | y << GreenShift | z << BlueShift | w << AlphaShift);
+ }
+
+ ///
+ /// Packs a into a uint.
+ ///
+ /// The vector containing the values to pack.
+ /// The containing the packed values.
+ static uint Pack(ref Vector3 vector)
+ {
+ var value = new Vector4(vector, 1);
+ return Pack(ref value);
+ }
+
+ ///
+ /// Packs a into a uint.
+ ///
+ /// The vector containing the values to pack.
+ /// The containing the packed values.
+ static uint Pack(ref Vector4 vector)
+ {
+ vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One);
+ vector *= MaxBytes;
+ vector += Half;
+ return (uint)(((byte)vector.X << RedShift)
+ | ((byte)vector.Y << GreenShift)
+ | ((byte)vector.Z << BlueShift)
+ | (byte)vector.W << AlphaShift);
+ }
+
+ ///
+ public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder)
+ {
+ switch(componentOrder) {
+ case ComponentOrder.ZYX:
+ bytes[startIndex] = B;
+ bytes[startIndex + 1] = G;
+ bytes[startIndex + 2] = R;
+ break;
+ case ComponentOrder.ZYXW:
+ bytes[startIndex] = B;
+ bytes[startIndex + 1] = G;
+ bytes[startIndex + 2] = R;
+ bytes[startIndex + 3] = A;
+ break;
+ case ComponentOrder.XYZ:
+ bytes[startIndex] = R;
+ bytes[startIndex + 1] = G;
+ bytes[startIndex + 2] = B;
+ break;
+ case ComponentOrder.XYZW:
+ bytes[startIndex] = R;
+ bytes[startIndex + 1] = G;
+ bytes[startIndex + 2] = B;
+ bytes[startIndex + 3] = A;
+ break;
+ default:
+ throw new NotSupportedException();
+ }
+ }
+
+ ///
+ public override bool Equals(object obj)
+ {
+ var a = obj as Argb;
+ return (a != null) && Equals(a);
+ }
+
+ ///
+ public bool Equals(Argb other)
+ {
+ return PackedValue == other.PackedValue;
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ // ReSharper disable once NonReadonlyMemberInGetHashCode
+ return PackedValue.GetHashCode();
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Colors/PackedPixelTests.cs b/tests/ImageSharp.Tests/Colors/PackedPixelTests.cs
index 14f43b8e69..e16fe4f6f5 100644
--- a/tests/ImageSharp.Tests/Colors/PackedPixelTests.cs
+++ b/tests/ImageSharp.Tests/Colors/PackedPixelTests.cs
@@ -56,6 +56,51 @@ namespace ImageSharp.Tests.Colors
Assert.Equal(bgra, new byte[] { 0, 0, 0, 128 });
}
+ [Fact]
+ public void Argb()
+ {
+ // Test the limits.
+ Assert.Equal((uint)0x0, new Argb(Vector4.Zero).PackedValue);
+ Assert.Equal(0xFFFFFFFF, new Argb(Vector4.One).PackedValue);
+
+ // Test ToVector4.
+ Assert.True(Equal(Vector4.One, new Argb(Vector4.One ).ToVector4()));
+ Assert.True(Equal(Vector4.Zero, new Argb(Vector4.Zero ).ToVector4()));
+ Assert.True(Equal(Vector4.UnitX, new Argb(Vector4.UnitX).ToVector4()));
+ Assert.True(Equal(Vector4.UnitY, new Argb(Vector4.UnitY).ToVector4()));
+ Assert.True(Equal(Vector4.UnitZ, new Argb(Vector4.UnitZ).ToVector4()));
+ Assert.True(Equal(Vector4.UnitW, new Argb(Vector4.UnitW).ToVector4()));
+
+ // Test clamping.
+ Assert.True(Equal(Vector4.Zero, new Argb(Vector4.One * -1234.0f).ToVector4()));
+ Assert.True(Equal(Vector4.One, new Argb(Vector4.One * +1234.0f).ToVector4()));
+
+ var x = +0.1f;
+ var y = -0.3f;
+ var z = +0.5f;
+ var w = -0.7f;
+ var argb = new Argb(x, y, z, w);
+ Assert.Equal(0x001a0080u, argb.PackedValue);
+
+ // Test ordering
+ byte[] rgb = new byte[3];
+ byte[] rgba = new byte[4];
+ byte[] bgr = new byte[3];
+ byte[] bgra = new byte[4];
+
+ argb.ToBytes(rgb, 0, ComponentOrder.XYZ);
+ Assert.Equal(rgb, new byte[] { 0x1a, 0, 0x80 });
+
+ argb.ToBytes(rgba, 0, ComponentOrder.XYZW);
+ Assert.Equal(rgba, new byte[] { 0x1a, 0, 0x80, 0 });
+
+ argb.ToBytes(bgr, 0, ComponentOrder.ZYX);
+ Assert.Equal(bgr, new byte[] { 0x80, 0, 0x1a });
+
+ argb.ToBytes(bgra, 0, ComponentOrder.ZYXW);
+ Assert.Equal(bgra, new byte[] { 0x80, 0, 0x1a, 0 });
+ }
+
[Fact]
public void Bgr565()
{