Browse Source

Merge pull request #511 from SixLabors/js/scaled-vectors

Add Scaled Vector Packing/Unpacking
af/merge-core
James Jackson-South 8 years ago
committed by GitHub
parent
commit
842d474a68
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 34
      src/ImageSharp/ImageFrame{TPixel}.cs
  2. 16
      src/ImageSharp/PixelFormats/Alpha8.cs
  3. 20
      src/ImageSharp/PixelFormats/Argb32.cs
  4. 18
      src/ImageSharp/PixelFormats/Bgr24.cs
  5. 16
      src/ImageSharp/PixelFormats/Bgr565.cs
  6. 17
      src/ImageSharp/PixelFormats/Bgra32.cs
  7. 16
      src/ImageSharp/PixelFormats/Bgra4444.cs
  8. 26
      src/ImageSharp/PixelFormats/Bgra5551.cs
  9. 28
      src/ImageSharp/PixelFormats/Byte4.cs
  10. 32
      src/ImageSharp/PixelFormats/HalfSingle.cs
  11. 4
      src/ImageSharp/PixelFormats/HalfTypeHelper.cs
  12. 35
      src/ImageSharp/PixelFormats/HalfVector2.cs
  13. 35
      src/ImageSharp/PixelFormats/HalfVector4.cs
  14. 14
      src/ImageSharp/PixelFormats/IPixel.cs
  15. 35
      src/ImageSharp/PixelFormats/NormalizedByte2.cs
  16. 35
      src/ImageSharp/PixelFormats/NormalizedByte4.cs
  17. 35
      src/ImageSharp/PixelFormats/NormalizedShort2.cs
  18. 35
      src/ImageSharp/PixelFormats/NormalizedShort4.cs
  19. 365
      src/ImageSharp/PixelFormats/PackedPixelConverterHelper.cs
  20. 42
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
  21. 26
      src/ImageSharp/PixelFormats/Rg32.cs
  22. 17
      src/ImageSharp/PixelFormats/Rgb24.cs
  23. 16
      src/ImageSharp/PixelFormats/Rgba1010102.cs
  24. 13
      src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs
  25. 18
      src/ImageSharp/PixelFormats/Rgba32.cs
  26. 16
      src/ImageSharp/PixelFormats/Rgba64.cs
  27. 26
      src/ImageSharp/PixelFormats/RgbaVector.cs
  28. 33
      src/ImageSharp/PixelFormats/Short2.cs
  29. 35
      src/ImageSharp/PixelFormats/Short4.cs
  30. 88
      tests/ImageSharp.Tests/Image/ImageCloneTests.cs
  31. 235
      tests/ImageSharp.Tests/PixelFormats/PackedPixelTests.cs
  32. 84
      tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs

34
src/ImageSharp/ImageFrame{TPixel}.cs

@ -246,27 +246,23 @@ namespace SixLabors.ImageSharp
return this.Clone() as ImageFrame<TPixel2>;
}
Func<Vector4, Vector4> scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction<TPixel, TPixel2>();
var target = new ImageFrame<TPixel2>(this.MemoryManager, this.Width, this.Height, this.MetaData.Clone());
using (PixelAccessor<TPixel> pixels = this.Lock())
using (PixelAccessor<TPixel2> targetPixels = target.Lock())
{
Parallel.For(
0,
target.Height,
Configuration.Default.ParallelOptions,
y =>
{
for (int x = 0; x < target.Width; x++)
{
var color = default(TPixel2);
color.PackFromVector4(scaleFunc(pixels[x, y].ToVector4()));
targetPixels[x, y] = color;
}
});
}
// TODO: ImageFrame has no visibility of the current configuration. It should have.
ParallelFor.WithTemporaryBuffer(
0,
this.Height,
Configuration.Default,
this.Width,
(int y, IBuffer<Vector4> tempRowBuffer) =>
{
Span<TPixel> sourceRow = this.GetPixelRowSpan(y);
Span<TPixel2> targetRow = target.GetPixelRowSpan(y);
Span<Vector4> tempRowSpan = tempRowBuffer.Span;
PixelOperations<TPixel>.Instance.ToScaledVector4(sourceRow, tempRowSpan, sourceRow.Length);
PixelOperations<TPixel2>.Instance.PackFromScaledVector4(tempRowSpan, targetRow, targetRow.Length);
});
return target;
}

16
src/ImageSharp/PixelFormats/Alpha8.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing a single 8 bit normalized W values.
/// <para>
/// Ranges from &lt;0, 0, 0, 0&gt; to &lt;0, 0, 0, 1&gt; in vector form.
/// Ranges from [0, 0, 0, 0] to [0, 0, 0, 1] in vector form.
/// </para>
/// </summary>
public struct Alpha8 : IPixel<Alpha8>, IPackedVector<byte>
@ -62,6 +62,20 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
public PixelOperations<Alpha8> CreatePixelOperations() => new PixelOperations<Alpha8>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)

20
src/ImageSharp/PixelFormats/Argb32.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// 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.
/// <para>
/// Ranges from &lt;0, 0, 0, 0&gt; to &lt;1, 1, 1, 1&gt; in vector form.
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
/// <remarks>
@ -237,6 +237,20 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
public PixelOperations<Argb32> CreatePixelOperations() => new PixelOperations<Argb32>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
@ -321,7 +335,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y, float z, float w)
{
Vector4 value = new Vector4(x, y, z, w);
var value = new Vector4(x, y, z, w);
return Pack(ref value);
}
@ -347,7 +361,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(ref Vector3 vector)
{
Vector4 value = new Vector4(vector, 1);
var value = new Vector4(vector, 1);
return Pack(ref value);
}

18
src/ImageSharp/PixelFormats/Bgr24.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -11,6 +10,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Pixel type containing three 8-bit unsigned normalized values ranging from 0 to 255.
/// The color components are stored in blue, green, red order.
/// <para>
/// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct Bgr24 : IPixel<Bgr24>
@ -80,6 +82,20 @@ namespace SixLabors.ImageSharp.PixelFormats
this = source.Bgr;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)

16
src/ImageSharp/PixelFormats/Bgr565.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x and z components use 5 bits, and the y component uses 6 bits.
/// <para>
/// Ranges from &lt;0, 0, 0, 1&gt; to &lt;1, 1, 1, 1&gt; in vector form.
/// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
public struct Bgr565 : IPixel<Bgr565>, IPackedVector<ushort>
@ -85,6 +85,20 @@ namespace SixLabors.ImageSharp.PixelFormats
(this.PackedValue & 0x1F) * (1F / 31F));
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)

17
src/ImageSharp/PixelFormats/Bgra32.cs

@ -11,6 +11,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
/// The color components are stored in blue, green, red, and alpha order.
/// <para>
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint>
@ -116,6 +119,20 @@ namespace SixLabors.ImageSharp.PixelFormats
}
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)

16
src/ImageSharp/PixelFormats/Bgra4444.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing unsigned normalized values, ranging from 0 to 1, using 4 bits each for x, y, z, and w.
/// <para>
/// Ranges from &lt;0, 0, 0, 0&gt; to &lt;1, 1, 1, 1&gt; in vector form.
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
public struct Bgra4444 : IPixel<Bgra4444>, IPackedVector<ushort>
@ -70,6 +70,20 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
public PixelOperations<Bgra4444> CreatePixelOperations() => new PixelOperations<Bgra4444>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()

26
src/ImageSharp/PixelFormats/Bgra5551.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x , y and z components use 5 bits, and the w component uses 1 bit.
/// <para>
/// Ranges from &lt;0, 0, 0, 0&gt; to &lt;1, 1, 1, 1&gt; in vector form.
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
public struct Bgra5551 : IPixel<Bgra5551>, IPackedVector<ushort>
@ -72,6 +72,20 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
public PixelOperations<Bgra5551> CreatePixelOperations() => new PixelOperations<Bgra5551>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
@ -101,7 +115,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -111,7 +125,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -122,7 +136,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -132,7 +146,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -190,6 +204,6 @@ namespace SixLabors.ImageSharp.PixelFormats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToScaledVector4() => this.ToVector4() * 255f;
private Vector4 ToByteScaledVector4() => this.ToVector4() * 255f;
}
}

28
src/ImageSharp/PixelFormats/Byte4.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing four 8-bit unsigned integer values, ranging from 0 to 255.
/// <para>
/// Ranges from &lt;0, 0, 0, 0&gt; to &lt;1, 1, 1, 1&gt; in vector form.
/// Ranges from [0, 0, 0, 0] to [255, 255, 255, 255] in vector form.
/// </para>
/// </summary>
public struct Byte4 : IPixel<Byte4>, IPackedVector<uint>
@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="w">The w-component</param>
public Byte4(float x, float y, float z, float w)
{
Vector4 vector = new Vector4(x, y, z, w);
var vector = new Vector4(x, y, z, w);
this.PackedValue = Pack(ref vector);
}
@ -73,6 +73,20 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
public PixelOperations<Byte4> CreatePixelOperations() => new PixelOperations<Byte4>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector * 255F);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4() / 255F;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
@ -95,14 +109,14 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.PackFromVector4(source.ToUnscaledVector4());
this.PackFromVector4(source.ToByteScaledVector4());
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToVector4();
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -112,7 +126,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToVector4();
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -123,7 +137,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToVector4();
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -133,7 +147,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToVector4();
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;

32
src/ImageSharp/PixelFormats/HalfSingle.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
@ -10,7 +9,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing a single 16 bit floating point value.
/// <para>
/// Ranges from &lt;0, 0, 0, 1&gt; to &lt;1, 0, 0, 1&gt; in vector form.
/// Ranges from [-1, 0, 0, 1] to [1, 0, 0, 1] in vector form.
/// </para>
/// </summary>
public struct HalfSingle : IPixel<HalfSingle>, IPackedVector<ushort>
@ -86,6 +85,25 @@ namespace SixLabors.ImageSharp.PixelFormats
return HalfTypeHelper.Unpack(this.PackedValue);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
float scaled = vector.X;
scaled *= 2F;
scaled -= 1F;
this.PackedValue = HalfTypeHelper.Pack(scaled);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
float single = this.ToSingle() + 1F;
single /= 2F;
return new Vector4(single, 0, 0, 1);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
@ -111,7 +129,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -121,7 +139,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -132,7 +150,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -142,7 +160,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -176,7 +194,7 @@ namespace SixLabors.ImageSharp.PixelFormats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToScaledVector4()
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= MaxBytes;

4
src/ImageSharp/PixelFormats/HalfTypeHelper.cs

@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ushort Pack(float value)
{
Uif uif = new Uif { F = value };
var uif = new Uif { F = value };
return Pack(uif.I);
}
@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.PixelFormats
result = ((((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23)) | (mantissa << 13);
}
Uif uif = new Uif { U = result };
var uif = new Uif { U = result };
return uif.F;
}

35
src/ImageSharp/PixelFormats/HalfVector2.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing two 16-bit floating-point values.
/// <para>
/// Ranges from &lt;0, 0, 0, 1&gt; to &lt;1, 0, 0, 1&gt; in vector form.
/// Ranges from [-1, -1, 0, 1] to [1, 1, 0, 1] in vector form.
/// </para>
/// </summary>
public struct HalfVector2 : IPixel<HalfVector2>, IPackedVector<uint>
@ -99,6 +99,25 @@ namespace SixLabors.ImageSharp.PixelFormats
return vector;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F;
scaled -= Vector2.One;
this.PackedValue = Pack(scaled.X, scaled.Y);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector2();
scaled += Vector2.One;
scaled /= 2F;
return new Vector4(scaled, 0F, 1F);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
@ -110,7 +129,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
Vector2 vector = this.ToVector2();
var vector = this.ToVector2();
return new Vector4(vector.X, vector.Y, 0F, 1F);
}
@ -125,7 +144,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
@ -135,7 +154,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
@ -146,7 +165,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
@ -156,7 +175,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
@ -204,9 +223,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToScaledVector4()
private Vector4 ToByteScaledVector4()
{
Vector4 vector = this.ToVector4();
var vector = this.ToVector4();
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);

35
src/ImageSharp/PixelFormats/HalfVector4.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing four 16-bit floating-point values.
/// <para>
/// Ranges from &lt;0, 0, 0, 0&gt; to &lt;1, 1, 1, 1&gt; in vector form.
/// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
public struct HalfVector4 : IPixel<HalfVector4>, IPackedVector<ulong>
@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="w">The w-component.</param>
public HalfVector4(float x, float y, float z, float w)
{
Vector4 vector = new Vector4(x, y, z, w);
var vector = new Vector4(x, y, z, w);
this.PackedValue = Pack(ref vector);
}
@ -89,6 +89,25 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
public PixelOperations<HalfVector4> CreatePixelOperations() => new PixelOperations<HalfVector4>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
vector *= 2F;
vector -= Vector4.One;
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector4();
scaled += Vector4.One;
scaled /= 2F;
return scaled;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
@ -118,7 +137,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -128,7 +147,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -139,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -149,7 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -198,9 +217,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToScaledVector4()
private Vector4 ToByteScaledVector4()
{
Vector4 vector = this.ToVector4();
var vector = this.ToVector4();
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);

14
src/ImageSharp/PixelFormats/IPixel.cs

@ -32,6 +32,20 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="vector">The vector to create the packed representation from.</param>
void PackFromVector4(Vector4 vector);
/// <summary>
/// Sets the packed representation from a scaled <see cref="Vector4"/>.
/// </summary>
/// <param name="vector">The vector to create the packed representation from.</param>
void PackFromScaledVector4(Vector4 vector);
/// <summary>
/// Expands the packed representation into a scaled <see cref="Vector4"/>
/// with values clamped between <value>0</value> and <value>1</value>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector4"/>.</returns>
Vector4 ToScaledVector4();
/// <summary>
/// Expands the packed representation into a <see cref="Vector4"/>.
/// The vector components are typically expanded in least to greatest significance order.

35
src/ImageSharp/PixelFormats/NormalizedByte2.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed packed pixel type containing two 8-bit signed normalized values, ranging from −1 to 1.
/// <para>
/// Ranges from &lt;-1, -1, 0, 1&gt; to &lt;1, 1, 0, 1&gt; in vector form.
/// Ranges from [-1, -1, 0, 1] to [1, 1, 0, 1] in vector form.
/// </para>
/// </summary>
public struct NormalizedByte2 : IPixel<NormalizedByte2>, IPackedVector<ushort>
@ -104,6 +104,25 @@ namespace SixLabors.ImageSharp.PixelFormats
(sbyte)((this.PackedValue >> 8) & 0xFF) / 127F);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F;
scaled -= Vector2.One;
this.PackedValue = Pack(scaled.X, scaled.Y);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector2();
scaled += Vector2.One;
scaled /= 2F;
return new Vector4(scaled, 0F, 1F);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
@ -122,7 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
Vector4 vector = source.ToUnscaledVector4();
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
@ -134,7 +153,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
@ -144,7 +163,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
@ -155,7 +174,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
@ -165,7 +184,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
@ -214,9 +233,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToScaledVector4()
private Vector4 ToByteScaledVector4()
{
Vector4 vector = this.ToVector4();
var vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;

35
src/ImageSharp/PixelFormats/NormalizedByte4.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing four 8-bit signed normalized values, ranging from −1 to 1.
/// <para>
/// Ranges from &lt;-1, -1, -1, -1&gt; to &lt;1, 1, 1, 1&gt; in vector form.
/// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
public struct NormalizedByte4 : IPixel<NormalizedByte4>, IPackedVector<uint>
@ -93,6 +93,25 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
public PixelOperations<NormalizedByte4> CreatePixelOperations() => new PixelOperations<NormalizedByte4>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
vector *= 2F;
vector -= Vector4.One;
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector4();
scaled += Vector4.One;
scaled /= 2F;
return scaled;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
@ -115,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
Vector4 vector = source.ToUnscaledVector4();
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
@ -127,7 +146,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -137,7 +156,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -148,7 +167,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -158,7 +177,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -211,9 +230,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToScaledVector4()
private Vector4 ToByteScaledVector4()
{
Vector4 vector = this.ToVector4();
var vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;

35
src/ImageSharp/PixelFormats/NormalizedShort2.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing two 16-bit signed normalized values, ranging from −1 to 1.
/// <para>
/// Ranges from &lt;-1, -1, 0, 1&gt; to &lt;1, 1, 0, 1&gt; in vector form.
/// Ranges from [-1, -1, 0, 1] to [1, 1, 0, 1] in vector form.
/// </para>
/// </summary>
public struct NormalizedShort2 : IPixel<NormalizedShort2>, IPackedVector<uint>
@ -91,6 +91,25 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
public PixelOperations<NormalizedShort2> CreatePixelOperations() => new PixelOperations<NormalizedShort2>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F;
scaled -= Vector2.One;
this.PackedValue = Pack(scaled.X, scaled.Y);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector2();
scaled += Vector2.One;
scaled /= 2F;
return new Vector4(scaled, 0F, 1F);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
@ -109,7 +128,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
Vector4 vector = source.ToUnscaledVector4();
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
@ -121,7 +140,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
@ -131,7 +150,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
@ -142,7 +161,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
@ -152,7 +171,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
@ -221,9 +240,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToScaledVector4()
private Vector4 ToByteScaledVector4()
{
Vector4 vector = this.ToVector4();
var vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;

35
src/ImageSharp/PixelFormats/NormalizedShort4.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing four 16-bit signed normalized values, ranging from −1 to 1.
/// <para>
/// Ranges from &lt;-1, -1, -1, -1&gt; to &lt;1, 1, 1, 1&gt; in vector form.
/// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
public struct NormalizedShort4 : IPixel<NormalizedShort4>, IPackedVector<ulong>
@ -93,6 +93,25 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
public PixelOperations<NormalizedShort4> CreatePixelOperations() => new PixelOperations<NormalizedShort4>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
vector *= 2F;
vector -= Vector4.One;
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector4();
scaled += Vector4.One;
scaled /= 2F;
return scaled;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
@ -117,7 +136,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
Vector4 vector = source.ToUnscaledVector4();
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
@ -129,7 +148,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
@ -139,7 +158,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
@ -150,7 +169,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
@ -160,7 +179,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
@ -217,9 +236,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToScaledVector4()
private Vector4 ToByteScaledVector4()
{
Vector4 vector = this.ToVector4();
var vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;

365
src/ImageSharp/PixelFormats/PackedPixelConverterHelper.cs

@ -1,365 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
namespace SixLabors.ImageSharp.PixelFormats
{
/// <summary>
/// Assists with the conversion of known packed pixel formats from one to another.
/// </summary>
internal static class PackedPixelConverterHelper
{
/// <summary>
/// A non operative function. Simply returns the original vector.
/// </summary>
private static readonly Func<Vector4, Vector4> Noop = vector4 => vector4;
/// <summary>
/// Returns the correct scaling function for the given types The compute scale function.
/// </summary>
/// <typeparam name="TPixel">The source pixel format.</typeparam>
/// <typeparam name="TPixel2">The target pixel format.</typeparam>
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
public static Func<Vector4, Vector4> ComputeScaleFunction<TPixel, TPixel2>()
{
Type source = typeof(TPixel);
Type target = typeof(TPixel2);
// Normalized standard
if (IsStandardNormalizedType(source))
{
return FromStandardNormalizedType(target);
}
// Standard
if (IsStandardType(source))
{
return FromStandardType(target);
}
// Normalized offsets. All four components.
if (IsOffsetNormalizedType(source))
{
return FromOffsetNormalizedType(target);
}
// Offset. All four components.
if (IsOffsetType(source))
{
return FromOffsetType(target);
}
// Normalized offsets. First component pair only.
if (IsOffsetTwoComponentNormalizedType(source))
{
return FromOffsetTwoComponentNormalizedType(target);
}
// Offsets. First component pair only.
if (IsOffsetTwoComponentType(source))
{
return FromOffsetTwoComponentType(target);
}
return Noop;
}
/// <summary>
/// Returns the correct conversion function to convert from types having vector values representing all four components
/// ranging from 0 to 1.
/// </summary>
/// <param name="target">The target type</param>
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
private static Func<Vector4, Vector4> FromStandardNormalizedType(Type target)
{
if (IsStandardType(target))
{
return vector4 => 255F * vector4;
}
if (IsOffsetNormalizedType(target) || IsOffsetTwoComponentNormalizedType(target))
{
// Expand the range then offset the center down.
return vector4 => (2F * vector4) - Vector4.One;
}
if (IsOffsetType(target) || IsOffsetTwoComponentType(target))
{
return vector4 => (65534F * vector4) - new Vector4(32767F);
}
return Noop;
}
/// <summary>
/// Returns the correct conversion function to convert from types having vector values representing all four components
/// ranging from 0 to 255.
/// </summary>
/// <param name="target">The target type</param>
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
private static Func<Vector4, Vector4> FromStandardType(Type target)
{
// Scale down
if (IsStandardNormalizedType(target))
{
return vector4 => vector4 / 255F;
}
if (IsOffsetNormalizedType(target) || IsOffsetTwoComponentNormalizedType(target))
{
// Expand the range, divide, then offset the center down.
return vector4 => ((2F * (vector4 / 255F)) - Vector4.One);
}
if (IsOffsetType(target) || IsOffsetTwoComponentType(target))
{
return vector4 => (65534F * (vector4 / 255F)) - new Vector4(32767F);
}
return Noop;
}
/// <summary>
/// Returns the correct conversion function to convert from types having vector values representing all four components
/// ranging from -1 to 1.
/// </summary>
/// <param name="target">The target type</param>
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
private static Func<Vector4, Vector4> FromOffsetNormalizedType(Type target)
{
if (IsStandardNormalizedType(target))
{
// Compress the range then offset the center up.
return vector4 => (vector4 / 2F) + new Vector4(.5F);
}
if (IsStandardType(target))
{
// Compress the range, multiply, then offset the center up.
return vector4 => ((vector4 / 2F) * 255F) + new Vector4(127.5F);
}
if (IsOffsetType(target) || IsOffsetTwoComponentType(target))
{
// Multiply out the range, two component won't read the last two values.
return vector4 => (vector4 * 32767F);
}
return Noop;
}
/// <summary>
/// Returns the correct conversion function to convert from types having vector values representing all four components
/// ranging from -32767 to 32767.
/// </summary>
/// <param name="target">The target type</param>
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
private static Func<Vector4, Vector4> FromOffsetType(Type target)
{
if (IsStandardNormalizedType(target))
{
// Compress the range then offset the center up.
return vector4 => (vector4 / 65534F) + new Vector4(.5F);
}
if (IsStandardType(target))
{
// Compress the range, multiply, then offset the center up.
return vector4 => ((vector4 / 65534F) * 255F) + new Vector4(127.5F);
}
if (IsOffsetNormalizedType(target) || IsOffsetTwoComponentNormalizedType(target))
{
// Compress the range. Two component won't read the last two values.
return vector4 => (vector4 / 32767F);
}
return Noop;
}
/// <summary>
/// Returns the correct conversion function to convert from types having vector with the first component pair ranging from -1 to 1.
/// and the second component pair ranging from 0 to 1.
/// </summary>
/// <param name="target">The target type</param>
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
private static Func<Vector4, Vector4> FromOffsetTwoComponentNormalizedType(Type target)
{
if (IsStandardNormalizedType(target))
{
return vector4 =>
{
// Compress the range then offset the center up for first pair.
Vector4 v = (vector4 / 2F) + new Vector4(.5F);
return new Vector4(v.X, v.Y, 0F, 1F);
};
}
if (IsStandardType(target))
{
return vector4 =>
{
// Compress the range, multiply, then offset the center up for first pair.
Vector4 v = ((vector4 / 2F) * 255F) + new Vector4(127.5F);
return new Vector4(v.X, v.Y, 0F, 255F);
};
}
if (IsOffsetNormalizedType(target))
{
// Copy the first two components and set second pair to 0 and 1 equivalent.
return vector4 => new Vector4(vector4.X, vector4.Y, -1F, 1F);
}
if (IsOffsetTwoComponentType(target))
{
// Multiply. Two component won't read the last two values.
return vector4 => (vector4 * 32767F);
}
if (IsOffsetType(target))
{
return vector4 =>
{
// Multiply the first two components and set second pair to 0 and 1 equivalent.
Vector4 v = vector4 * 32767F;
return new Vector4(v.X, v.Y, -32767F, 32767F);
};
}
return Noop;
}
/// <summary>
/// Returns the correct conversion function to convert from types having vector with the first component pair ranging from -32767 to 32767.
/// and the second component pair ranging from 0 to 1.
/// </summary>
/// <param name="target">The target type</param>
/// <returns>The <see cref="Func{Vector4,Vector4}"/></returns>
private static Func<Vector4, Vector4> FromOffsetTwoComponentType(Type target)
{
if (IsStandardNormalizedType(target))
{
return vector4 =>
{
Vector4 v = (vector4 / 65534F) + new Vector4(.5F);
return new Vector4(v.X, v.Y, 0, 1);
};
}
if (IsStandardType(target))
{
return vector4 =>
{
Vector4 v = ((vector4 / 65534F) * 255F) + new Vector4(127.5F);
return new Vector4(v.X, v.Y, 0, 255F);
};
}
if (IsOffsetType(target))
{
// Copy the first two components and set second pair to 0 and 1 equivalent.
return vector4 => new Vector4(vector4.X, vector4.Y, -32767F, 32767F);
}
if (IsOffsetNormalizedType(target))
{
return vector4 =>
{
// Divide the first two components and set second pair to 0 and 1 equivalent.
Vector4 v = vector4 / 32767F;
return new Vector4(v.X, v.Y, -1F, 1F);
};
}
if (IsOffsetTwoComponentNormalizedType(target))
{
// Divide. Two component won't read the last two values.
return vector4 => (vector4 / 32767F);
}
return Noop;
}
/// <summary>
/// Identifies the type as having vector component values ranging from 0 to 1.
/// </summary>
/// <param name="type">The type to test.</param>
/// <returns>The <see cref="bool"/></returns>
private static bool IsStandardNormalizedType(Type type)
{
return
type == typeof(Alpha8)
|| type == typeof(Argb32)
|| type == typeof(Bgr24)
|| type == typeof(Bgra32)
|| type == typeof(Bgr565)
|| type == typeof(Bgra4444)
|| type == typeof(Bgra5551)
|| type == typeof(HalfSingle)
|| type == typeof(HalfVector2)
|| type == typeof(HalfVector4)
|| type == typeof(Rg32)
|| type == typeof(Rgb24)
|| type == typeof(Rgba32)
|| type == typeof(Rgba64)
|| type == typeof(Rgba1010102);
}
/// <summary>
/// Identifies the type as having vector component values ranging from 0 to 255.
/// </summary>
/// <param name="type">The type to test.</param>
/// <returns>The <see cref="bool"/></returns>
private static bool IsStandardType(Type type)
{
return type == typeof(Byte4);
}
/// <summary>
/// Identifies the type as having vector values representing the first component pair ranging from -1 to 1.
/// and the second component pair ranging from 0 to 1.
/// </summary>
/// <param name="type">The type to test.</param>
/// <returns>The <see cref="bool"/></returns>
private static bool IsOffsetTwoComponentNormalizedType(Type type)
{
return type == typeof(NormalizedByte2)
|| type == typeof(NormalizedShort2);
}
/// <summary>
/// Identifies the type as having vector values representing all four components ranging from -1 to 1.
/// </summary>
/// <param name="type">The type to test.</param>
/// <returns>The <see cref="bool"/></returns>
private static bool IsOffsetNormalizedType(Type type)
{
return type == typeof(NormalizedByte4)
|| type == typeof(NormalizedShort4);
}
/// <summary>
/// Identifies the type as having vector values representing the first component pair ranging from -32767 to 32767.
/// and the second component pair ranging from 0 to 1.
/// </summary>
/// <param name="type">The type to test.</param>
/// <returns>The <see cref="bool"/></returns>
private static bool IsOffsetTwoComponentType(Type type)
{
return type == typeof(Short2);
}
/// <summary>
/// Identifies the type as having vector values representing all four components ranging from -32767 to 32767.
/// </summary>
/// <param name="type">The type to test.</param>
/// <returns>The <see cref="bool"/></returns>
private static bool IsOffsetType(Type type)
{
return type == typeof(Short4);
}
}
}

42
src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs

@ -63,6 +63,48 @@ namespace SixLabors.ImageSharp.PixelFormats
}
}
/// <summary>
/// Bulk version of <see cref="IPixel.PackFromScaledVector4(Vector4)"/>
/// </summary>
/// <param name="sourceVectors">The <see cref="Span{T}"/> to the source vectors.</param>
/// <param name="destinationColors">The <see cref="Span{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromScaledVector4(ReadOnlySpan<Vector4> sourceVectors, Span<TPixel> destinationColors, int count)
{
GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count);
ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors);
ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors);
for (int i = 0; i < count; i++)
{
ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i);
ref TPixel dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromScaledVector4(sp);
}
}
/// <summary>
/// Bulk version of <see cref="IPixel.ToScaledVector4()"/>.
/// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destinationVectors">The <see cref="Span{T}"/> to the destination vectors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToScaledVector4(ReadOnlySpan<TPixel> sourceColors, Span<Vector4> destinationVectors, int count)
{
GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count);
ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors);
ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors);
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
ref Vector4 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToScaledVector4();
}
}
/// <summary>
/// Verifies that the given 'source' and 'destination' spans are at least of 'minLength' size.
/// Throwing an <see cref="ArgumentException"/> if the condition is not met.

26
src/ImageSharp/PixelFormats/Rg32.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing two 16-bit unsigned normalized values ranging from 0 to 1.
/// <para>
/// Ranges from &lt;0, 0, 0, 1&gt; to &lt;1, 1, 0, 1&gt; in vector form.
/// Ranges from [0, 0, 0, 1] to [1, 1, 0, 1] in vector form.
/// </para>
/// </summary>
public struct Rg32 : IPixel<Rg32>, IPackedVector<uint>
@ -89,6 +89,20 @@ namespace SixLabors.ImageSharp.PixelFormats
((this.PackedValue >> 16) & 0xFFFF) / 65535F);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
@ -114,7 +128,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -124,7 +138,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -135,7 +149,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -145,7 +159,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
@ -193,6 +207,6 @@ namespace SixLabors.ImageSharp.PixelFormats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToScaledVector4() => this.ToVector4() * 255f;
private Vector4 ToByteScaledVector4() => this.ToVector4() * 255F;
}
}

17
src/ImageSharp/PixelFormats/Rgb24.cs

@ -11,6 +11,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Pixel type containing three 8-bit unsigned normalized values ranging from 0 to 255.
/// The color components are stored in red, green, blue order.
/// <para>
/// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct Rgb24 : IPixel<Rgb24>
@ -80,6 +83,20 @@ namespace SixLabors.ImageSharp.PixelFormats
this = Unsafe.As<Rgba32, Rgb24>(ref source);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)

16
src/ImageSharp/PixelFormats/Rgba1010102.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Packed vector type containing unsigned normalized values ranging from 0 to 1.
/// The x, y and z components use 10 bits, and the w component uses 2 bits.
/// <para>
/// Ranges from &lt;0, 0, 0, 0&gt; to &lt;1, 1, 1, 1&gt; in vector form.
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
public struct Rgba1010102 : IPixel<Rgba1010102>, IPackedVector<uint>
@ -79,6 +79,20 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
public PixelOperations<Rgba1010102> CreatePixelOperations() => new PixelOperations<Rgba1010102>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()

13
src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs

@ -115,6 +115,7 @@ namespace SixLabors.ImageSharp.PixelFormats
}
}
/// <inheritdoc />
internal override void PackFromVector4(ReadOnlySpan<Vector4> sourceVectors, Span<Rgba32> destColors, int count)
{
GuardSpans(sourceVectors, nameof(sourceVectors), destColors, nameof(destColors), count);
@ -144,6 +145,18 @@ namespace SixLabors.ImageSharp.PixelFormats
}
}
/// <inheritdoc />
internal override void ToScaledVector4(ReadOnlySpan<Rgba32> sourceColors, Span<Vector4> destinationVectors, int count)
{
this.ToVector4(sourceColors, destinationVectors, count);
}
/// <inheritdoc />
internal override void PackFromScaledVector4(ReadOnlySpan<Vector4> sourceVectors, Span<Rgba32> destinationColors, int count)
{
this.PackFromVector4(sourceVectors, destinationColors, count);
}
/// <inheritdoc />
internal override void PackFromRgba32(ReadOnlySpan<Rgba32> source, Span<Rgba32> destPixels, int count)
{

18
src/ImageSharp/PixelFormats/Rgba32.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Packed pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
/// The color components are stored in red, green, blue, and alpha order.
/// <para>
/// Ranges from &lt;0, 0, 0, 0&gt; to &lt;1, 1, 1, 1&gt; in vector form.
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
/// <remarks>
@ -318,6 +318,20 @@ namespace SixLabors.ImageSharp.PixelFormats
dest.A = this.A;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
@ -383,7 +397,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
/// <returns>A <see cref="Vector4"/> of values in [0, 255] </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Vector4 ToUnscaledVector4()
internal Vector4 ToByteScaledVector4()
{
return new Vector4(this.R, this.G, this.B, this.A);
}

16
src/ImageSharp/PixelFormats/Rgba64.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing four 16-bit unsigned normalized values ranging from 0 to 1.
/// <para>
/// Ranges from &lt;0, 0, 0, 0&gt; to &lt;1, 1, 1, 1&gt; in vector form.
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
public struct Rgba64 : IPixel<Rgba64>, IPackedVector<ulong>
@ -78,6 +78,20 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
public PixelOperations<Rgba64> CreatePixelOperations() => new PixelOperations<Rgba64>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()

26
src/ImageSharp/PixelFormats/RgbaVector.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Unpacked pixel type containing four 16-bit floating-point values typically ranging from 0 to 1.
/// The color components are stored in red, green, blue, and alpha order.
/// <para>
/// Ranges from &lt;0, 0, 0, 0&gt; to &lt;1, 1, 1, 1&gt; in vector form.
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
/// <remarks>
@ -235,7 +235,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
@ -245,7 +245,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
@ -256,7 +256,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
@ -266,13 +266,27 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
@ -316,6 +330,6 @@ namespace SixLabors.ImageSharp.PixelFormats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToScaledVector4() => Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes;
private Vector4 ToByteScaledVector4() => Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes;
}
}

33
src/ImageSharp/PixelFormats/Short2.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing two 16-bit signed integer values.
/// <para>
/// Ranges from &lt;-32767, -32767, 0, 1&gt; to &lt;32767, 32767, 0, 1&gt; in vector form.
/// Ranges from [-32767, -32767, 0, 1] to [32767, 32767, 0, 1] in vector form.
/// </para>
/// </summary>
public struct Short2 : IPixel<Short2>, IPackedVector<uint>
@ -91,6 +91,25 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
public PixelOperations<Short2> CreatePixelOperations() => new PixelOperations<Short2>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
Vector2 scaled = new Vector2(vector.X, vector.Y) * 65534F;
scaled -= new Vector2(32767F);
this.PackedValue = Pack(scaled.X, scaled.Y);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector2();
scaled += new Vector2(32767F);
scaled /= 65534F;
return new Vector4(scaled, 0F, 1F);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
@ -119,7 +138,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector2 vector = this.ToScaledVector2();
Vector2 vector = this.ToByteScaledVector2();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
@ -129,7 +148,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector2 vector = this.ToScaledVector2();
Vector2 vector = this.ToByteScaledVector2();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
@ -140,7 +159,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector2 vector = this.ToScaledVector2();
Vector2 vector = this.ToByteScaledVector2();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
@ -150,7 +169,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector2 vector = this.ToScaledVector2();
Vector2 vector = this.ToByteScaledVector2();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
@ -215,9 +234,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector2 ToScaledVector2()
private Vector2 ToByteScaledVector2()
{
Vector2 vector = this.ToVector2();
var vector = this.ToVector2();
vector /= 65534;
vector *= 255;
vector += Half;

35
src/ImageSharp/PixelFormats/Short4.cs

@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Packed pixel type containing four 16-bit signed integer values.
/// <para>
/// Ranges from &lt;-37267, -37267, -37267, -37267&gt; to &lt;37267, 37267, 37267, 37267&gt; in vector form.
/// Ranges from [-37267, -37267, -37267, -37267] to [37267, 37267, 37267, 37267] in vector form.
/// </para>
/// </summary>
public struct Short4 : IPixel<Short4>, IPackedVector<ulong>
@ -93,6 +93,25 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
public PixelOperations<Short4> CreatePixelOperations() => new PixelOperations<Short4>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
vector *= 65534F;
vector -= new Vector4(32767F);
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector4();
scaled += new Vector4(32767F);
scaled /= 65534F;
return scaled;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
@ -115,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
Vector4 vector = source.ToVector4();
var vector = source.ToVector4();
vector *= 65534;
vector -= new Vector4(32767);
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
@ -125,7 +144,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
@ -135,7 +154,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
@ -146,7 +165,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
@ -156,7 +175,7 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToScaledVector4();
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
@ -222,9 +241,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToScaledVector4()
private Vector4 ToByteScaledVector4()
{
Vector4 vector = this.ToVector4();
var vector = this.ToVector4();
vector /= 65534;
vector *= 255;
vector += Half;

88
tests/ImageSharp.Tests/Image/ImageCloneTests.cs

@ -21,13 +21,89 @@ namespace SixLabors.ImageSharp.Tests
for (int x = 0; x < image.Width; x++)
{
Rgba32 rgba = row[x];
Bgra32 bgra = rowClone[x];
Rgba32 expected = row[x];
Bgra32 actual = rowClone[x];
Assert.Equal(rgba.R, bgra.R);
Assert.Equal(rgba.G, bgra.G);
Assert.Equal(rgba.B, bgra.B);
Assert.Equal(rgba.A, bgra.A);
Assert.Equal(expected.R, actual.R);
Assert.Equal(expected.G, actual.G);
Assert.Equal(expected.B, actual.B);
Assert.Equal(expected.A, actual.A);
}
}
}
}
[Theory]
[WithTestPatternImages(9, 9, PixelTypes.Rgba32)]
public void CloneAs_ToBgr24(TestImageProvider<Rgba32> provider)
{
using (Image<Rgba32> image = provider.GetImage())
using (Image<Bgr24> clone = image.CloneAs<Bgr24>())
{
for (int y = 0; y < image.Height; y++)
{
Span<Rgba32> row = image.GetPixelRowSpan(y);
Span<Bgr24> rowClone = clone.GetPixelRowSpan(y);
for (int x = 0; x < image.Width; x++)
{
Rgba32 expected = row[x];
Bgr24 actual = rowClone[x];
Assert.Equal(expected.R, actual.R);
Assert.Equal(expected.G, actual.G);
Assert.Equal(expected.B, actual.B);
}
}
}
}
[Theory]
[WithTestPatternImages(9, 9, PixelTypes.Rgba32)]
public void CloneAs_ToArgb32(TestImageProvider<Rgba32> provider)
{
using (Image<Rgba32> image = provider.GetImage())
using (Image<Argb32> clone = image.CloneAs<Argb32>())
{
for (int y = 0; y < image.Height; y++)
{
Span<Rgba32> row = image.GetPixelRowSpan(y);
Span<Argb32> rowClone = clone.GetPixelRowSpan(y);
for (int x = 0; x < image.Width; x++)
{
Rgba32 expected = row[x];
Argb32 actual = rowClone[x];
Assert.Equal(expected.R, actual.R);
Assert.Equal(expected.G, actual.G);
Assert.Equal(expected.B, actual.B);
Assert.Equal(expected.A, actual.A);
}
}
}
}
[Theory]
[WithTestPatternImages(9, 9, PixelTypes.Rgba32)]
public void CloneAs_ToRgb24(TestImageProvider<Rgba32> provider)
{
using (Image<Rgba32> image = provider.GetImage())
using (Image<Rgb24> clone = image.CloneAs<Rgb24>())
{
for (int y = 0; y < image.Height; y++)
{
Span<Rgba32> row = image.GetPixelRowSpan(y);
Span<Rgb24> rowClone = clone.GetPixelRowSpan(y);
for (int x = 0; x < image.Width; x++)
{
Rgba32 expected = row[x];
Rgb24 actual = rowClone[x];
Assert.Equal(expected.R, actual.R);
Assert.Equal(expected.G, actual.G);
Assert.Equal(expected.B, actual.B);
}
}
}

235
tests/ImageSharp.Tests/PixelFormats/PackedPixelTests.cs

@ -32,14 +32,26 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.Equal(124, new Alpha8(124F / 0xFF).PackedValue);
Assert.Equal(26, new Alpha8(0.1F).PackedValue);
// Test ordering
// Test ToVector4.
var vector = new Alpha8(.5F).ToVector4();
Assert.Equal(0, vector.X);
Assert.Equal(0, vector.Y);
Assert.Equal(0, vector.Z);
Assert.Equal(.5F, vector.W, 2);
// Test ToScaledVector4.
Vector4 scaled = new Alpha8(.5F).ToScaledVector4();
Assert.Equal(0, scaled.X);
Assert.Equal(0, scaled.Y);
Assert.Equal(0, scaled.Z);
Assert.Equal(.5F, scaled.W, 2);
// Test PackFromScaledVector4.
var pixel = default(Alpha8);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(128, pixel.PackedValue);
// Test Rgb conversion
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
@ -73,6 +85,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(Vector4.UnitZ, new Argb32(Vector4.UnitZ).ToVector4()));
Assert.True(Equal(Vector4.UnitW, new Argb32(Vector4.UnitW).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new Argb32(Vector4.One).ToScaledVector4();
Assert.Equal(1, scaled.X);
Assert.Equal(1, scaled.Y);
Assert.Equal(1, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(Argb32);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(0xFFFFFFFF, pixel.PackedValue);
// Test clamping.
Assert.True(Equal(Vector4.Zero, new Argb32(Vector4.One * -1234.0f).ToVector4()));
Assert.True(Equal(Vector4.One, new Argb32(Vector4.One * +1234.0f).ToVector4()));
@ -90,6 +114,7 @@ namespace SixLabors.ImageSharp.Tests.Colors
var bgr = default(Bgr24);
var bgra = default(Bgra32);
argb.ToRgb24(ref rgb);
Assert.Equal(rgb, new Rgb24(0x1a, 0, 0x80));
@ -117,6 +142,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(Vector3.UnitY, new Bgr565(Vector3.UnitY).ToVector3()));
Assert.True(Equal(Vector3.UnitZ, new Bgr565(Vector3.UnitZ).ToVector3()));
// Test ToScaledVector4.
Vector4 scaled = new Bgr565(Vector3.One).ToScaledVector4();
Assert.Equal(1, scaled.X);
Assert.Equal(1, scaled.Y);
Assert.Equal(1, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(Bgr565);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(0xFFFF, pixel.PackedValue);
// Test clamping.
Assert.True(Equal(Vector3.Zero, new Bgr565(Vector3.One * -1234F).ToVector3()));
Assert.True(Equal(Vector3.One, new Bgr565(Vector3.One * 1234F).ToVector3()));
@ -165,6 +202,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(Vector4.UnitZ, new Bgra4444(Vector4.UnitZ).ToVector4()));
Assert.True(Equal(Vector4.UnitW, new Bgra4444(Vector4.UnitW).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new Bgra4444(Vector4.One).ToScaledVector4();
Assert.Equal(1, scaled.X);
Assert.Equal(1, scaled.Y);
Assert.Equal(1, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(Bgra4444);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(0xFFFF, pixel.PackedValue);
// Test clamping.
Assert.True(Equal(Vector4.Zero, new Bgra4444(Vector4.One * -1234.0f).ToVector4()));
Assert.True(Equal(Vector4.One, new Bgra4444(Vector4.One * 1234.0f).ToVector4()));
@ -211,6 +260,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(Vector4.Zero, new Bgra5551(Vector4.Zero).ToVector4()));
Assert.True(Equal(Vector4.One, new Bgra5551(Vector4.One).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new Bgra5551(Vector4.One).ToScaledVector4();
Assert.Equal(1, scaled.X);
Assert.Equal(1, scaled.Y);
Assert.Equal(1, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(Bgra5551);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(0xFFFF, pixel.PackedValue);
// Test clamping.
Assert.Equal(Vector4.Zero, new Bgra5551(Vector4.One * -1234.0f).ToVector4());
Assert.Equal(Vector4.One, new Bgra5551(Vector4.One * 1234.0f).ToVector4());
@ -261,6 +322,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(Vector4.UnitZ * 255, new Byte4(Vector4.UnitZ * 255).ToVector4()));
Assert.True(Equal(Vector4.UnitW * 255, new Byte4(Vector4.UnitW * 255).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new Byte4(Vector4.One * 255).ToScaledVector4();
Assert.Equal(1, scaled.X);
Assert.Equal(1, scaled.Y);
Assert.Equal(1, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(Byte4);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(0xFFFFFFFF, pixel.PackedValue);
// Test clamping.
Assert.True(Equal(Vector4.Zero, new Byte4(Vector4.One * -1234.0f).ToVector4()));
Assert.True(Equal(Vector4.One * 255, new Byte4(Vector4.One * 1234.0f).ToVector4()));
@ -318,6 +391,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
float x = .5F;
Assert.True(Equal(new Vector4(x, 0, 0, 1), new HalfSingle(x).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new HalfSingle(-1F).ToScaledVector4();
Assert.Equal(0, scaled.X);
Assert.Equal(0, scaled.Y);
Assert.Equal(0, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(HalfSingle);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(48128, pixel.PackedValue);
var rgb = default(Rgb24);
var rgba = default(Rgba32);
var bgr = default(Bgr24);
@ -350,6 +435,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(Vector2.UnitX, new HalfVector2(Vector2.UnitX).ToVector2()));
Assert.True(Equal(Vector2.UnitY, new HalfVector2(Vector2.UnitY).ToVector2()));
// Test ToScaledVector4.
Vector4 scaled = new HalfVector2(Vector2.One).ToScaledVector4();
Assert.Equal(1F, scaled.X);
Assert.Equal(1F, scaled.Y);
Assert.Equal(0, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(HalfVector2);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(1006648320u, pixel.PackedValue);
// Test ordering
float x = .5F;
float y = .25F;
@ -395,6 +492,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(Vector4.UnitZ, new HalfVector4(Vector4.UnitZ).ToVector4()));
Assert.True(Equal(Vector4.UnitW, new HalfVector4(Vector4.UnitW).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new HalfVector4(-Vector4.One).ToScaledVector4();
Assert.Equal(0, scaled.X);
Assert.Equal(0, scaled.Y);
Assert.Equal(0, scaled.Z);
Assert.Equal(0, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(HalfVector4);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(13547034390470638592uL, pixel.PackedValue);
// Test ordering
float x = .25F;
float y = .5F;
@ -438,6 +547,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(new Vector4(1, 1, 0, 1), new NormalizedByte2(Vector2.One).ToVector4()));
Assert.True(Equal(new Vector4(0, 0, 0, 1), new NormalizedByte2(Vector2.Zero).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new NormalizedByte2(-Vector2.One).ToScaledVector4();
Assert.Equal(0, scaled.X);
Assert.Equal(0, scaled.Y);
Assert.Equal(0, scaled.Z);
Assert.Equal(1F, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(NormalizedByte2);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(0x8181, pixel.PackedValue);
// Test Ordering
float x = 0.1f;
float y = -0.3f;
@ -479,6 +600,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(Vector4.One, new NormalizedByte4(Vector4.One * 1234.0f).ToVector4()));
Assert.True(Equal(-Vector4.One, new NormalizedByte4(Vector4.One * -1234.0f).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new NormalizedByte4(-Vector4.One).ToScaledVector4();
Assert.Equal(0, scaled.X);
Assert.Equal(0, scaled.Y);
Assert.Equal(0, scaled.Z);
Assert.Equal(0, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(NormalizedByte4);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(0x81818181, pixel.PackedValue);
// Test Ordering
float x = 0.1f;
float y = -0.3f;
@ -535,6 +668,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(new Vector4(1, 1, 0, 1), (new NormalizedShort2(Vector2.One)).ToVector4()));
Assert.True(Equal(new Vector4(0, 0, 0, 1), (new NormalizedShort2(Vector2.Zero)).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new NormalizedShort2(-Vector2.One).ToScaledVector4();
Assert.Equal(0, scaled.X);
Assert.Equal(0, scaled.Y);
Assert.Equal(0, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(NormalizedShort2);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(0x80018001, pixel.PackedValue);
// Test Ordering
float x = 0.35f;
float y = -0.2f;
@ -584,6 +729,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(Vector4.One, new NormalizedShort4(Vector4.One * 1234.0f).ToVector4()));
Assert.True(Equal(-Vector4.One, new NormalizedShort4(Vector4.One * -1234.0f).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new NormalizedShort4(Vector4.One).ToScaledVector4();
Assert.Equal(1, scaled.X);
Assert.Equal(1, scaled.Y);
Assert.Equal(1, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(NormalizedShort4);
pixel.PackFromScaledVector4(scaled);
Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, pixel.PackedValue);
// Test Ordering
float x = 0.1f;
float y = -0.3f;
@ -626,6 +783,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(Vector2.Zero, new Rg32(Vector2.Zero).ToVector2()));
Assert.True(Equal(Vector2.One, new Rg32(Vector2.One).ToVector2()));
// Test ToScaledVector4.
Vector4 scaled = new Rg32(Vector2.One).ToScaledVector4();
Assert.Equal(1, scaled.X);
Assert.Equal(1, scaled.Y);
Assert.Equal(0, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(Rg32);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(0xFFFFFFFF, pixel.PackedValue);
// Test clamping.
Assert.True(Equal(Vector2.Zero, new Rg32(Vector2.One * -1234.0f).ToVector2()));
Assert.True(Equal(Vector2.One, new Rg32(Vector2.One * 1234.0f).ToVector2()));
@ -668,6 +837,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(Vector4.Zero, new Rgba1010102(Vector4.Zero).ToVector4()));
Assert.True(Equal(Vector4.One, new Rgba1010102(Vector4.One).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new Rgba1010102(Vector4.One).ToScaledVector4();
Assert.Equal(1, scaled.X);
Assert.Equal(1, scaled.Y);
Assert.Equal(1, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(Rgba1010102);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(0xFFFFFFFF, pixel.PackedValue);
// Test clamping.
Assert.True(Equal(Vector4.Zero, new Rgba1010102(Vector4.One * -1234.0f).ToVector4()));
Assert.True(Equal(Vector4.One, new Rgba1010102(Vector4.One * 1234.0f).ToVector4()));
@ -709,7 +890,7 @@ namespace SixLabors.ImageSharp.Tests.Colors
}
[Fact]
public void Color()
public void Rgba32()
{
// Test the limits.
Assert.Equal((uint)0x0, new Rgba32(Vector4.Zero).PackedValue);
@ -723,6 +904,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(Vector4.UnitZ, new Rgba32(Vector4.UnitZ).ToVector4()));
Assert.True(Equal(Vector4.UnitW, new Rgba32(Vector4.UnitW).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new Rgba32(Vector4.One).ToScaledVector4();
Assert.Equal(1, scaled.X);
Assert.Equal(1, scaled.Y);
Assert.Equal(1, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(Rgba32);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(0xFFFFFFFF, pixel.PackedValue);
// Test clamping.
Assert.True(Equal(Vector4.Zero, new Rgba32(Vector4.One * -1234.0f).ToVector4()));
Assert.True(Equal(Vector4.One, new Rgba32(Vector4.One * +1234.0f).ToVector4()));
@ -772,6 +965,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(Vector4.Zero, new Rgba64(Vector4.Zero).ToVector4()));
Assert.True(Equal(Vector4.One, new Rgba64(Vector4.One).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new Rgba64(Vector4.One).ToScaledVector4();
Assert.Equal(1, scaled.X);
Assert.Equal(1, scaled.Y);
Assert.Equal(1, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(Rgba64);
pixel.PackFromScaledVector4(scaled);
Assert.Equal(0xFFFFFFFFFFFFFFFF, pixel.PackedValue);
// Test clamping.
Assert.True(Equal(Vector4.Zero, new Rgba64(Vector4.One * -1234.0f).ToVector4()));
Assert.True(Equal(Vector4.One, new Rgba64(Vector4.One * 1234.0f).ToVector4()));
@ -833,6 +1038,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.True(Equal(new Vector4(0, 0, 0, 1), (new Short2(Vector2.Zero)).ToVector4()));
Assert.True(Equal(new Vector4(-0x8000, -0x8000, 0, 1), (new Short2(Vector2.One * -0x8000)).ToVector4()));
// Test ToScaledVector4.
Vector4 scaled = new Short2(Vector2.One * 0x7FFF).ToScaledVector4();
Assert.Equal(1, scaled.X);
Assert.Equal(1, scaled.Y);
Assert.Equal(0, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(Short2);
pixel.PackFromScaledVector4(scaled);
Assert.Equal((uint)0x7FFF7FFF, pixel.PackedValue);
// Test ordering
float x = 0x2db1;
float y = 0x361d;
@ -881,6 +1098,18 @@ namespace SixLabors.ImageSharp.Tests.Colors
Assert.Equal(Vector4.UnitZ * 0x7FFF, new Short4(Vector4.UnitZ * 0x7FFF).ToVector4());
Assert.Equal(Vector4.UnitW * 0x7FFF, new Short4(Vector4.UnitW * 0x7FFF).ToVector4());
// Test ToScaledVector4.
Vector4 scaled = new Short4(Vector4.One * 0x7FFF).ToScaledVector4();
Assert.Equal(1, scaled.X);
Assert.Equal(1, scaled.Y);
Assert.Equal(1, scaled.Z);
Assert.Equal(1, scaled.W);
// Test PackFromScaledVector4.
var pixel = default(Short4);
pixel.PackFromScaledVector4(scaled);
Assert.Equal((ulong)0x7FFF7FFF7FFF7FFF, pixel.PackedValue);
// Test clamping.
Assert.Equal(Vector4.One * 0x7FFF, new Short4(Vector4.One * 1234567.0f).ToVector4());
Assert.Equal(Vector4.One * -0x8000, new Short4(Vector4.One * -1234567.0f).ToVector4());

84
tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs

@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
internal static TPixel[] CreateExpectedPixelData(Vector4[] source)
{
TPixel[] expected = new TPixel[source.Length];
var expected = new TPixel[source.Length];
for (int i = 0; i < expected.Length; i++)
{
@ -111,6 +111,17 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
return expected;
}
internal static TPixel[] CreateScaledExpectedPixelData(Vector4[] source)
{
var expected = new TPixel[source.Length];
for (int i = 0; i < expected.Length; i++)
{
expected[i].PackFromScaledVector4(source[i]);
}
return expected;
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void PackFromVector4(int count)
@ -125,9 +136,23 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void PackFromScaledVector4(int count)
{
Vector4[] source = CreateVector4TestData(count);
TPixel[] expected = CreateScaledExpectedPixelData(source);
TestOperation(
source,
expected,
(s, d) => Operations.PackFromScaledVector4(s, d.Span, count)
);
}
internal static Vector4[] CreateExpectedVector4Data(TPixel[] source)
{
Vector4[] expected = new Vector4[source.Length];
var expected = new Vector4[source.Length];
for (int i = 0; i < expected.Length; i++)
{
@ -136,6 +161,17 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
return expected;
}
internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source)
{
var expected = new Vector4[source.Length];
for (int i = 0; i < expected.Length; i++)
{
expected[i] = source[i].ToScaledVector4();
}
return expected;
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void ToVector4(int count)
@ -150,13 +186,26 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void ToScaledVector4(int count)
{
TPixel[] source = CreateScaledPixelTestData(count);
Vector4[] expected = CreateExpectedScaledVector4Data(source);
TestOperation(
source,
expected,
(s, d) => Operations.ToScaledVector4(s, d.Span, count)
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void PackFromXyzBytes(int count)
{
byte[] source = CreateByteTestData(count * 3);
TPixel[] expected = new TPixel[count];
var expected = new TPixel[count];
for (int i = 0; i < count; i++)
{
@ -201,7 +250,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
public void PackFromXyzwBytes(int count)
{
byte[] source = CreateByteTestData(count * 4);
TPixel[] expected = new TPixel[count];
var expected = new TPixel[count];
for (int i = 0; i < count; i++)
{
@ -247,7 +296,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
public void PackFromZyxBytes(int count)
{
byte[] source = CreateByteTestData(count * 3);
TPixel[] expected = new TPixel[count];
var expected = new TPixel[count];
for (int i = 0; i < count; i++)
{
@ -292,7 +341,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
public void PackFromZyxwBytes(int count)
{
byte[] source = CreateByteTestData(count * 4);
TPixel[] expected = new TPixel[count];
var expected = new TPixel[count];
for (int i = 0; i < count; i++)
{
@ -341,7 +390,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
public TSource[] SourceBuffer { get; }
public IBuffer<TDest> ActualDestBuffer { get; }
public TDest[] ExpectedDestBuffer { get; }
public TestBuffers(TSource[] source, TDest[] expectedDest)
{
this.SourceBuffer = source;
@ -362,7 +411,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
if (typeof(TDest) == typeof(Vector4))
{
Span<Vector4> expected = this.ExpectedDestBuffer.AsSpan().NonPortableCast<TDest, Vector4>();
Span<Vector4> actual = this.ActualDestBuffer.Span.NonPortableCast<TDest, Vector4>();
@ -401,7 +450,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
internal static Vector4[] CreateVector4TestData(int length)
{
Vector4[] result = new Vector4[length];
var result = new Vector4[length];
var rnd = new Random(42); // Deterministic random values
for (int i = 0; i < result.Length; i++)
@ -413,7 +462,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
internal static TPixel[] CreatePixelTestData(int length)
{
TPixel[] result = new TPixel[length];
var result = new TPixel[length];
var rnd = new Random(42); // Deterministic random values
@ -426,6 +475,21 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
return result;
}
internal static TPixel[] CreateScaledPixelTestData(int length)
{
var result = new TPixel[length];
var rnd = new Random(42); // Deterministic random values
for (int i = 0; i < result.Length; i++)
{
Vector4 v = GetVector(rnd);
result[i].PackFromScaledVector4(v);
}
return result;
}
internal static byte[] CreateByteTestData(int length)
{
byte[] result = new byte[length];

Loading…
Cancel
Save