Browse Source

Begin fitting packed vector with XNA etc

Former-commit-id: 929527d603ef214c2975e64fb43b6f9867ab2a4a
Former-commit-id: 476e47a8f3c03a02420b57fda0f7b0b70eab4bba
Former-commit-id: 0a9e0b6e26bfc736835bcc4cb9f02a2da246fa59
af/merge-core
James Jackson-South 10 years ago
parent
commit
482cba3768
  1. 150
      src/ImageProcessorCore/Colors/Color.cs
  2. 30
      src/ImageProcessorCore/Colors/PackedVector/IPackedVector.cs
  3. 24
      src/ImageProcessorCore/Common/Extensions/ComparableExtensions.cs
  4. 2
      src/ImageProcessorCore/Image/PixelAccessor.cs
  5. 4
      src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs
  6. 4
      tests/ImageProcessorCore.Benchmarks/Image/GetSetPixel.cs

150
src/ImageProcessorCore/Colors/Color.cs

@ -8,7 +8,6 @@ namespace ImageProcessorCore
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary>
/// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 255.
@ -18,38 +17,77 @@ namespace ImageProcessorCore
/// 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.
/// </remarks>
[StructLayout(LayoutKind.Explicit)]
public partial struct Color : IPackedVector<uint>, IEquatable<Color>
{
private const float Max = 255F;
private const float Min = 0F;
private uint packedValue;
/// <summary>
/// Gets or sets the blue component.
/// Gets or sets the red component.
/// </summary>
[FieldOffset(0)]
public byte R;
public byte R
{
get
{
return (byte)this.packedValue;
}
set
{
this.packedValue = (uint)(this.packedValue & -0x100 | value);
}
}
/// <summary>
/// Gets or sets the green component.
/// </summary>
[FieldOffset(1)]
public byte G;
public byte G
{
get
{
return (byte)(this.packedValue >> 8);
}
set
{
this.packedValue = (uint)(this.packedValue & -0xff01 | (uint)value << 8);
}
}
/// <summary>
/// Gets or sets the red component.
/// Gets or sets the blue component.
/// </summary>
[FieldOffset(2)]
public byte B;
public byte B
{
get
{
return (byte)(this.packedValue >> 16);
}
set
{
this.packedValue = (uint)(this.packedValue & -0xff0001 | (uint)(value << 16));
}
}
/// <summary>
/// Gets or sets the alpha component.
/// </summary>
[FieldOffset(3)]
public byte A;
public byte A
{
get
{
return (byte)(this.packedValue >> 24);
}
set
{
this.packedValue = this.packedValue & 0xffffff | (uint)value << 24;
}
}
/// <summary>
/// The packed value.
/// </summary>
[FieldOffset(0)]
private uint packedValue;
public uint PackedValue { get { return this.packedValue; } set { this.packedValue = value; } }
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
@ -61,10 +99,7 @@ namespace ImageProcessorCore
public Color(byte r, byte g, byte b, byte a = 255)
: this()
{
this.R = r;
this.G = g;
this.B = b;
this.A = a;
this.packedValue = (uint)(r | g << 8 | b << 16 | a << 24);
}
/// <summary>
@ -87,17 +122,19 @@ namespace ImageProcessorCore
if (hex.Length == 8)
{
this.R = Convert.ToByte(hex.Substring(2, 2), 16);
this.G = Convert.ToByte(hex.Substring(4, 2), 16);
this.B = Convert.ToByte(hex.Substring(6, 2), 16);
this.A = Convert.ToByte(hex.Substring(0, 2), 16);
this.packedValue =
(uint)(Convert.ToByte(hex.Substring(2, 2), 16)
| Convert.ToByte(hex.Substring(4, 2), 16) << 8
| Convert.ToByte(hex.Substring(6, 2), 16) << 16
| Convert.ToByte(hex.Substring(0, 2), 16) << 24);
}
else if (hex.Length == 6)
{
this.R = Convert.ToByte(hex.Substring(0, 2), 16);
this.G = Convert.ToByte(hex.Substring(2, 2), 16);
this.B = Convert.ToByte(hex.Substring(4, 2), 16);
this.A = 255;
this.packedValue =
(uint)(Convert.ToByte(hex.Substring(0, 2), 16)
| Convert.ToByte(hex.Substring(2, 2), 16) << 8
| Convert.ToByte(hex.Substring(4, 2), 16) << 16
| 255 << 24);
}
else
{
@ -105,10 +142,11 @@ namespace ImageProcessorCore
string gh = char.ToString(hex[1]);
string bh = char.ToString(hex[2]);
this.R = Convert.ToByte(rh + rh, 16);
this.G = Convert.ToByte(gh + gh, 16);
this.B = Convert.ToByte(bh + bh, 16);
this.A = 255;
this.packedValue =
(uint)(Convert.ToByte(rh + rh, 16)
| Convert.ToByte(gh + gh, 16) << 8
| Convert.ToByte(bh + bh, 16) << 16
| 255 << 24);
}
}
@ -122,11 +160,7 @@ namespace ImageProcessorCore
public Color(float r, float g, float b, float a = 1)
: this()
{
Vector4 clamped = Vector4.Clamp(new Vector4(r, g, b, a), Vector4.Zero, Vector4.One) * 255F;
this.R = (byte)Math.Round(clamped.X);
this.G = (byte)Math.Round(clamped.Y);
this.B = (byte)Math.Round(clamped.Z);
this.A = (byte)Math.Round(clamped.W);
Pack(ref r, ref g, ref b, ref a);
}
/// <summary>
@ -138,11 +172,8 @@ namespace ImageProcessorCore
public Color(Vector3 vector)
: this()
{
Vector3 clamped = Vector3.Clamp(vector, Vector3.Zero, Vector3.One) * 255F;
this.R = (byte)Math.Round(clamped.X);
this.G = (byte)Math.Round(clamped.Y);
this.B = (byte)Math.Round(clamped.Z);
this.A = 255;
float a = 1;
Pack(ref vector.X, ref vector.Y, ref vector.Z, ref a);
}
/// <summary>
@ -154,11 +185,7 @@ namespace ImageProcessorCore
public Color(Vector4 vector)
: this()
{
Vector4 clamped = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * 255F;
this.R = (byte)Math.Round(clamped.X);
this.G = (byte)Math.Round(clamped.Y);
this.B = (byte)Math.Round(clamped.Z);
this.A = (byte)Math.Round(clamped.W);
this.packedValue = Pack(ref vector);
}
/// <summary>
@ -206,20 +233,13 @@ namespace ImageProcessorCore
/// <inheritdoc/>
public void PackFromVector4(Vector4 vector)
{
Vector4 clamped = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * 255F;
this.R = (byte)Math.Round(clamped.X);
this.G = (byte)Math.Round(clamped.Y);
this.B = (byte)Math.Round(clamped.Z);
this.A = (byte)Math.Round(clamped.W);
this.packedValue = Pack(ref vector);
}
/// <inheritdoc/>
public void PackFromBytes(byte x, byte y, byte z, byte w)
{
this.R = x;
this.G = y;
this.B = z;
this.A = w;
this.packedValue = (uint)(x | y << 8 | z << 16 | w << 24);
}
/// <inheritdoc/>
@ -261,6 +281,28 @@ namespace ImageProcessorCore
return this.GetHashCode(this);
}
/// <summary>
/// Packs a vector into a uint.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
/// <returns>The ulong containing the packed values.</returns>
private static uint Pack(ref Vector4 vector)
{
// TODO: Maybe use Vector4.Clamp() instead.
return (uint)((byte)Math.Round(vector.X * Max).Clamp(Min, Max)
| ((byte)Math.Round(vector.Y * Max).Clamp(Min, Max) << 8)
| (byte)Math.Round(vector.Z * Max).Clamp(Min, Max) << 16
| (byte)Math.Round(vector.W * Max).Clamp(Min, Max) << 24);
}
private static uint Pack(ref float x, ref float y, ref float z, ref float w)
{
return (uint)((byte)Math.Round(x * Max).Clamp(Min, Max)
| ((byte)Math.Round(y * Max).Clamp(Min, Max) << 8)
| (byte)Math.Round(z * Max).Clamp(Min, Max) << 16
| (byte)Math.Round(w * Max).Clamp(Min, Max) << 24);
}
/// <summary>
/// Returns the hash code for this instance.
/// </summary>

30
src/ImageProcessorCore/Colors/PackedVector/IPackedVector.cs

@ -15,21 +15,23 @@ namespace ImageProcessorCore
public interface IPackedVector<TPacked> : IPackedVector
where TPacked : struct
{
/// <summary>
/// Directly gets the packed representation of the packed vector.
/// Typically packed in least to greatest significance order.
/// </summary>
/// <returns>
/// The <see cref="TPacked"/>.
/// </returns>
TPacked GetPackedValue();
TPacked PackedValue { get; set; }
/// <summary>
/// Directly sets the packed representation of the packed vector.
/// Typically packed in least to greatest significance order.
/// </summary>
/// <param name="value">The packed value.</param>
void SetPackedValue(TPacked value);
///// <summary>
///// Directly gets the packed representation of the packed vector.
///// Typically packed in least to greatest significance order.
///// </summary>
///// <returns>
///// The <see cref="TPacked"/>.
///// </returns>
//TPacked GetPackedValue();
///// <summary>
///// Directly sets the packed representation of the packed vector.
///// Typically packed in least to greatest significance order.
///// </summary>
///// <param name="value">The packed value.</param>
//void SetPackedValue(TPacked value);
}
/// <summary>

24
src/ImageProcessorCore/Common/Extensions/ComparableExtensions.cs

@ -37,6 +37,30 @@ namespace ImageProcessorCore
return value;
}
/// <summary>
/// Restricts a <see cref="uint"/> to be within a specified range.
/// </summary>
/// <param name="value">The The value to clamp.</param>
/// <param name="min">The minimum value. If value is less than min, min will be returned.</param>
/// <param name="max">The maximum value. If value is greater than max, max will be returned.</param>
/// <returns>
/// The <see cref="int"/> representing the clamped value.
/// </returns>
public static uint Clamp(this uint value, uint min, uint max)
{
if (value > max)
{
return max;
}
if (value < min)
{
return min;
}
return value;
}
/// <summary>
/// Restricts a <see cref="int"/> to be within a specified range.
/// </summary>

2
src/ImageProcessorCore/Image/PixelAccessor.cs

@ -10,7 +10,7 @@ namespace ImageProcessorCore
using System.Runtime.InteropServices;
/// <summary>
/// Encapsulates properties to provides per-pixel access to an images pixels.
/// Provides per-pixel access to generic <see cref="Image{TColor,TPacked}"/> pixels.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
/// <typeparam name="TPacked">The packed format. <example>uint, long, float.</example></typeparam>

4
src/ImageProcessorCore/Quantizers/Octree/OctreeQuantizer.cs

@ -193,11 +193,11 @@ namespace ImageProcessorCore.Quantizers
/// Add a given color value to the Octree
/// </summary>
/// <param name="pixel">
/// The <see cref="T"/>containing color information to add.
/// The <see cref="TColor"/>containing color information to add.
/// </param>
public void AddColor(TColor pixel)
{
TPacked packed = pixel.GetPackedValue();
TPacked packed = pixel.PackedValue; //.GetPackedValue();
// Check if this request is for the same color as the last
if (this.previousColor.Equals(packed))
{

4
tests/ImageProcessorCore.Benchmarks/Image/GetSetPixel.cs

@ -10,7 +10,7 @@
public class GetSetPixel
{
[Benchmark(Baseline = true, Description = "System.Drawing GetSeTColor pixel")]
[Benchmark(Baseline = true, Description = "System.Drawing GetSet pixel")]
public SystemColor ResizeSystemDrawing()
{
using (Bitmap source = new Bitmap(400, 400))
@ -20,7 +20,7 @@
}
}
[Benchmark(Description = "ImageProcessorCore GetSeTColor pixel")]
[Benchmark(Description = "ImageProcessorCore GetSet pixel")]
public CoreColor ResizeCore()
{
CoreImage image = new CoreImage(400, 400);

Loading…
Cancel
Save