diff --git a/Dashboard/ImageProperties.cs b/Dashboard/ImageProperties.cs
new file mode 100644
index 0000000..a7be347
--- /dev/null
+++ b/Dashboard/ImageProperties.cs
@@ -0,0 +1,196 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Dashboard
+{
+ ///
+ /// Pixel format for images.
+ ///
+ public enum PixelFormat
+ {
+ R8I,
+ Rg8I,
+ Rgb8I,
+ Rgba8I,
+ R16F,
+ Rg816F,
+ Rgb16F,
+ Rgba16F,
+ }
+
+ ///
+ /// Color channels for images.
+ ///
+ public enum ColorChannel
+ {
+ ///
+ /// The zero channel. Used for swizzle masks.
+ ///
+ Zero = 0,
+
+ ///
+ /// The one channel. Used for swizzle masks.
+ ///
+ One = 1,
+
+ ///
+ /// An invalid swizzle mask.
+ ///
+ Unknown = 2,
+
+ ///
+ /// The red channel.
+ ///
+ Red = 4,
+
+ ///
+ /// The green channel.
+ ///
+ Green = 5,
+
+ ///
+ /// The blue channel.
+ ///
+ Blue = 6,
+
+ ///
+ /// The alpha channel.
+ ///
+ Alpha = 7,
+ }
+
+ ///
+ /// Defines a image swizzle mask.
+ ///
+ public struct ColorSwizzle : IEquatable
+ {
+ public short Mask;
+
+ private const int MASK = 7;
+ private const int RBIT = 0;
+ private const int GBIT = 3;
+ private const int BBIT = 6;
+ private const int ABIT = 9;
+
+ ///
+ /// Swizzle the red channel.
+ ///
+ public ColorChannel R
+ {
+ get => (ColorChannel)((Mask >> RBIT) & MASK);
+ set => Mask = (short)(((int)value << RBIT) | (Mask & ~(MASK << RBIT)));
+ }
+
+ ///
+ /// Swizzle the green channel.
+ ///
+ public ColorChannel G
+ {
+ get => (ColorChannel)((Mask >> GBIT) & MASK);
+ set => Mask = (short)(((int)value << GBIT) | (Mask & ~(MASK << GBIT)));
+ }
+
+ ///
+ /// Swizzle the blue channel.
+ ///
+ public ColorChannel B
+ {
+ get => (ColorChannel)((Mask >> BBIT) & MASK);
+ set => Mask = (short)(((int)value << BBIT) | (Mask & ~(MASK << BBIT)));
+ }
+
+ ///
+ /// Swizzle the alpha channel.
+ ///
+ public ColorChannel A
+ {
+ get => (ColorChannel)((Mask >> ABIT) & MASK);
+ set => Mask = (short)(((int)value << ABIT) | (Mask & ~(MASK << ABIT)));
+ }
+
+ public ColorSwizzle(short mask)
+ {
+ Mask = mask;
+ }
+
+ public ColorSwizzle(ColorChannel r, ColorChannel g, ColorChannel b, ColorChannel a)
+ {
+ Mask = (short)(((int)r << RBIT) | ((int)g << GBIT) | ((int)b << BBIT) | ((int)a << ABIT));
+ }
+
+ public override string ToString()
+ {
+ return $"{GetChannelChar(R)}{GetChannelChar(G)}{GetChannelChar(B)}{GetChannelChar(A)}";
+
+ char GetChannelChar(ColorChannel channel) => channel switch
+ {
+ ColorChannel.Zero => '0',
+ ColorChannel.Red => 'R',
+ ColorChannel.Green => 'G',
+ ColorChannel.Blue => 'B',
+ ColorChannel.Alpha => 'A',
+ ColorChannel.One => '1',
+ _ => '?',
+ };
+ }
+
+ public override int GetHashCode()
+ {
+ return Mask.GetHashCode();
+ }
+
+ public override bool Equals([NotNullWhen(true)] object? obj)
+ {
+ return obj is ColorSwizzle other && Equals(other);
+ }
+
+ public bool Equals(ColorSwizzle other)
+ {
+ return Mask == other.Mask;
+ }
+
+ public static readonly ColorSwizzle Default = Parse("RGBA");
+ public static readonly ColorSwizzle White = Parse("1111");
+ public static readonly ColorSwizzle Black = Parse("0001");
+ public static readonly ColorSwizzle Transparent = Parse("0000");
+ public static readonly ColorSwizzle RedToGrayscale = Parse("RRR1");
+ public static readonly ColorSwizzle RedToWhiteAlpha = Parse("111A");
+
+ public static bool TryParse(ReadOnlySpan str, out ColorSwizzle value)
+ {
+ if (str.Length < 4)
+ {
+ value = default;
+ return false;
+ }
+
+ ColorChannel r = GetChannelFromChar(str[0]);
+ ColorChannel g = GetChannelFromChar(str[1]);
+ ColorChannel b = GetChannelFromChar(str[2]);
+ ColorChannel a = GetChannelFromChar(str[3]);
+
+ value = new ColorSwizzle(r, g, b, a);
+ return true;
+
+ ColorChannel GetChannelFromChar(char chr) => chr switch
+ {
+ '0' => ColorChannel.Zero,
+ 'R' => ColorChannel.Red,
+ 'G' => ColorChannel.Green,
+ 'B' => ColorChannel.Blue,
+ 'A' => ColorChannel.Alpha,
+ '1' => ColorChannel.One,
+ _ => ColorChannel.Unknown,
+ };
+ }
+
+ public static ColorSwizzle Parse(ReadOnlySpan str) =>
+ TryParse(str, out ColorSwizzle value) ? value : throw new FormatException(nameof(str));
+
+ public static bool operator ==(ColorSwizzle left, ColorSwizzle right) =>
+ left.Mask == right.Mask;
+
+ public static bool operator !=(ColorSwizzle left, ColorSwizzle right) =>
+ left.Mask != right.Mask;
+ }
+}