Browse Source

Merge remote-tracking branch 'refs/remotes/origin/master' into feature/icc

# Conflicts:
#	src/ImageSharp/Colors/ColorspaceTransforms.cs
#	tests/ImageSharp.Tests/Colors/ColorEqualityTests.cs
pull/181/head
James Jackson-South 9 years ago
parent
commit
3d7bb40608
  1. 7
      ImageSharp.sln
  2. 2
      src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs
  3. 2
      src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs
  4. 2
      src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs
  5. 2
      src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs
  6. 2
      src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs
  7. 6
      src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
  8. 3
      src/ImageSharp.Drawing/Text/GlyphBuilder.cs
  9. 186
      src/ImageSharp/Colors/Color.BulkOperations.cs
  10. 2
      src/ImageSharp/Colors/Color.Definitions.cs
  11. 38
      src/ImageSharp/Colors/Color.Transforms.cs
  12. 240
      src/ImageSharp/Colors/Color.cs
  13. 27
      src/ImageSharp/Colors/ColorVector.BulkOperations.cs
  14. 728
      src/ImageSharp/Colors/ColorVector.Definitions.cs
  15. 256
      src/ImageSharp/Colors/ColorVector.Transforms.cs
  16. 320
      src/ImageSharp/Colors/ColorVector.cs
  17. 286
      src/ImageSharp/Colors/NamedColors{TColor}.cs
  18. 46
      src/ImageSharp/Colors/PackedPixel/Argb32.cs
  19. 172
      src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs
  20. 2
      src/ImageSharp/Colors/PackedPixel/PackedPixelConverterHelper.cs
  21. 99
      src/ImageSharp/Common/Memory/Buffer.cs
  22. 22
      src/ImageSharp/Common/Memory/Buffer2D.cs
  23. 10
      src/ImageSharp/Common/Memory/Buffer2DExtensions.cs
  24. 96
      src/ImageSharp/Common/Memory/BufferSpan.cs
  25. 88
      src/ImageSharp/Common/Memory/BufferSpan{T}.cs
  26. 4
      src/ImageSharp/Common/Memory/IBuffer2D.cs
  27. 11
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
  28. 45
      src/ImageSharp/Formats/Jpeg/Utils/JpegUtils.cs
  29. 41
      src/ImageSharp/Image/PixelAccessor{TColor}.cs
  30. 22
      src/ImageSharp/Image/PixelArea{TColor}.cs
  31. 2
      src/ImageSharp/ImageSharp.csproj
  32. 10
      src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs
  33. 34
      src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs
  34. 11
      src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs
  35. 4
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
  36. 15
      src/ImageSharp/Quantizers/Quantizer.cs
  37. 2
      src/ImageSharp/Quantizers/WuQuantizer.cs
  38. 16
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4ReferenceVsPointer.cs
  39. 8
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs
  40. 8
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs
  41. 8
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs
  42. 10
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs
  43. 37
      tests/ImageSharp.Benchmarks/General/ArrayCopy.cs
  44. 8
      tests/ImageSharp.Benchmarks/General/ClearBuffer.cs
  45. 7
      tests/ImageSharp.Benchmarks/General/IterateArray.cs
  46. 360
      tests/ImageSharp.Benchmarks/General/PixelIndexing.cs
  47. 21
      tests/ImageSharp.Benchmarks/Samplers/Resize.cs
  48. 6
      tests/ImageSharp.Sandbox46/Program.cs
  49. 60
      tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs
  50. 8
      tests/ImageSharp.Tests/Colors/ColorConstructorTests.cs
  51. 46
      tests/ImageSharp.Tests/Colors/ColorEqualityTests.cs
  52. 4
      tests/ImageSharp.Tests/Colors/ColorPackingTests.cs
  53. 2
      tests/ImageSharp.Tests/Colors/ColorTests.cs
  54. 132
      tests/ImageSharp.Tests/Colors/ColorVectorTests.cs
  55. 118
      tests/ImageSharp.Tests/Colors/ColorVectorTransformTests.cs
  56. 69
      tests/ImageSharp.Tests/Colors/PackedPixelTests.cs
  57. 148
      tests/ImageSharp.Tests/Colors/UnPackedPixelTests.cs
  58. 32
      tests/ImageSharp.Tests/Common/Buffer2DTests.cs
  59. 273
      tests/ImageSharp.Tests/Common/BufferSpanTests.cs
  60. 100
      tests/ImageSharp.Tests/Common/BufferTests.cs
  61. 2
      tests/ImageSharp.Tests/Common/TestStructs.cs
  62. 4
      tests/ImageSharp.Tests/Drawing/Text/GlyphBuilder.cs
  63. 4
      tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs
  64. 4
      tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs
  65. 4
      tests/ImageSharp.Tests/Formats/Jpg/JpegUtilsTests.cs
  66. 35
      tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifReaderTests.cs
  67. 8
      tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs
  68. 2
      tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs
  69. 6
      tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs
  70. 4
      tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs

7
ImageSharp.sln

@ -1,18 +1,17 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26228.9
VisualStudioVersion = 15.0.26403.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.travis.yml = .travis.yml
appveyor.yml = appveyor.yml
codecov.yml = codecov.yml
CodeCoverage.runsettings = CodeCoverage.runsettings
contributing.md = contributing.md
dotnet-latest.ps1 = dotnet-latest.ps1
.github\CONTRIBUTING.md = .github\CONTRIBUTING.md
features.md = features.md
global.json = global.json
ImageSharp.ruleset = ImageSharp.ruleset
ImageSharp.sln.DotSettings = ImageSharp.sln.DotSettings
NuGet.config = NuGet.config

2
src/ImageSharp.Drawing/Brushes/ImageBrush{TColor}.cs

@ -117,7 +117,7 @@ namespace ImageSharp.Drawing.Brushes
{
Guard.MustBeGreaterThanOrEqualTo(scanlineBuffer.Length, offset + scanlineWidth, nameof(scanlineWidth));
using (PinnedBuffer<float> buffer = new PinnedBuffer<float>(scanlineBuffer))
using (Buffer<float> buffer = new Buffer<float>(scanlineBuffer))
{
BufferSpan<float> slice = buffer.Slice(offset);

2
src/ImageSharp.Drawing/Brushes/PatternBrush{TColor}.cs

@ -150,7 +150,7 @@ namespace ImageSharp.Drawing.Brushes
{
Guard.MustBeGreaterThanOrEqualTo(scanlineBuffer.Length, offset + scanlineWidth, nameof(scanlineWidth));
using (PinnedBuffer<float> buffer = new PinnedBuffer<float>(scanlineBuffer))
using (Buffer<float> buffer = new Buffer<float>(scanlineBuffer))
{
BufferSpan<float> slice = buffer.Slice(offset);

2
src/ImageSharp.Drawing/Brushes/Processors/BrushApplicator.cs

@ -55,7 +55,7 @@ namespace ImageSharp.Drawing.Processors
{
DebugGuard.MustBeGreaterThanOrEqualTo(scanlineBuffer.Length, offset + scanlineWidth, nameof(scanlineWidth));
using (PinnedBuffer<float> buffer = new PinnedBuffer<float>(scanlineBuffer))
using (Buffer<float> buffer = new Buffer<float>(scanlineBuffer))
{
BufferSpan<float> slice = buffer.Slice(offset);

2
src/ImageSharp.Drawing/Brushes/RecolorBrush{TColor}.cs

@ -141,7 +141,7 @@ namespace ImageSharp.Drawing.Brushes
{
Guard.MustBeGreaterThanOrEqualTo(scanlineBuffer.Length, offset + scanlineWidth, nameof(scanlineWidth));
using (PinnedBuffer<float> buffer = new PinnedBuffer<float>(scanlineBuffer))
using (Buffer<float> buffer = new Buffer<float>(scanlineBuffer))
{
BufferSpan<float> slice = buffer.Slice(offset);

2
src/ImageSharp.Drawing/Brushes/SolidBrush{TColor}.cs

@ -89,7 +89,7 @@ namespace ImageSharp.Drawing.Brushes
{
Guard.MustBeGreaterThanOrEqualTo(scanlineBuffer.Length, offset + scanlineWidth, nameof(scanlineWidth));
using (PinnedBuffer<float> buffer = new PinnedBuffer<float>(scanlineBuffer))
using (Buffer<float> buffer = new Buffer<float>(scanlineBuffer))
{
BufferSpan<float> slice = buffer.Slice(offset);

6
src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>An extension to ImageSharp that allows the drawing of images, paths, and text.</Description>
<AssemblyTitle>ImageSharp.Drawing</AssemblyTitle>
<VersionPrefix>1.0.0-alpha5</VersionPrefix>
<VersionPrefix>1.0.0-alpha6</VersionPrefix>
<Authors>James Jackson-South and contributors</Authors>
<TargetFramework>netstandard1.1</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
@ -39,8 +39,8 @@
<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta001">
<PrivateAssets>All</PrivateAssets>
</PackageReference>
<PackageReference Include="SixLabors.Fonts" Version="0.1.0-alpha0005" />
<PackageReference Include="SixLabors.Shapes" Version="0.1.0-alpha0010" />
<PackageReference Include="SixLabors.Fonts" Version="0.1.0-alpha0008" />
<PackageReference Include="SixLabors.Shapes" Version="0.1.0-alpha0011" />
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\ImageSharp.ruleset</CodeAnalysisRuleSet>

3
src/ImageSharp.Drawing/Text/GlyphBuilder.cs

@ -48,7 +48,8 @@ namespace ImageSharp.Drawing
/// <summary>
/// Begins the glyph.
/// </summary>
void IGlyphRenderer.BeginGlyph()
/// <param name="location">The offset that the glyph will be rendered at.</param>
void IGlyphRenderer.BeginGlyph(Vector2 location)
{
this.builder.Clear();
}

186
src/ImageSharp/Colors/Color.BulkOperations.cs

@ -10,9 +10,14 @@ namespace ImageSharp
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Conains the definition of <see cref="BulkOperations"/>
/// </content>
/// <summary>
/// Unpacked 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.
/// </summary>
/// <remarks>
/// 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>
public partial struct Color
{
/// <summary>
@ -37,15 +42,12 @@ namespace ImageSharp
/// <cref>https://github.com/dotnet/corefx/issues/15957</cref>
/// </see>
/// </remarks>
internal static unsafe void ToVector4SimdAligned(
BufferSpan<Color> sourceColors,
BufferSpan<Vector4> destVectors,
int count)
internal static unsafe void ToVector4SimdAligned(BufferSpan<Color> sourceColors, BufferSpan<Vector4> destVectors, int count)
{
if (!Vector.IsHardwareAccelerated)
{
throw new InvalidOperationException(
"Color.BulkOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!");
"Color32.BulkOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!");
}
int vecSize = Vector<uint>.Count;
@ -62,21 +64,23 @@ namespace ImageSharp
int unpackedRawCount = count * 4;
uint* src = (uint*)sourceColors.PointerAtOffset;
uint* srcEnd = src + count;
ref uint src = ref Unsafe.As<Color, uint>(ref sourceColors.DangerousGetPinnableReference());
using (PinnedBuffer<uint> tempBuf = new PinnedBuffer<uint>(
unpackedRawCount + Vector<uint>.Count))
using (Buffer<uint> tempBuf = new Buffer<uint>(
unpackedRawCount + Vector<uint>.Count))
{
uint* tPtr = (uint*)tempBuf.Pointer;
uint[] temp = tempBuf.Array;
float[] fTemp = Unsafe.As<float[]>(temp);
UnpackedRGBA* dst = (UnpackedRGBA*)tPtr;
for (; src < srcEnd; src++, dst++)
ref UnpackedRGBA tempBase = ref Unsafe.As<uint, UnpackedRGBA>(ref tempBuf[0]);
for (int i = 0; i < count; i++)
{
uint sVal = Unsafe.Add(ref src, i);
ref UnpackedRGBA dst = ref Unsafe.Add(ref tempBase, i);
// This call is the bottleneck now:
dst->Load(*src);
dst.Load(sVal);
}
for (int i = 0; i < unpackedRawCount; i += vecSize)
@ -91,7 +95,7 @@ namespace ImageSharp
vf.CopyTo(fTemp, i);
}
BufferSpan.Copy<uint>(tempBuf, (BufferSpan<byte>)destVectors, unpackedRawCount);
BufferSpan.Copy(tempBuf.Span.AsBytes(), destVectors.AsBytes(), unpackedRawCount * sizeof(uint));
}
}
@ -123,131 +127,163 @@ namespace ImageSharp
}
/// <inheritdoc />
internal override unsafe void PackFromXyzBytes(BufferSpan<byte> sourceBytes, BufferSpan<Color> destColors, int count)
internal override void PackFromXyzBytes(BufferSpan<byte> sourceBytes, BufferSpan<Color> destColors, int count)
{
byte* source = (byte*)sourceBytes;
byte* destination = (byte*)destColors;
ref RGB24 sourceRef = ref Unsafe.As<byte, RGB24>(ref sourceBytes.DangerousGetPinnableReference());
ref Color destRef = ref destColors.DangerousGetPinnableReference();
for (int x = 0; x < count; x++)
for (int i = 0; i < count; i++)
{
Unsafe.Write(destination, (uint)(*source << 0 | *(source + 1) << 8 | *(source + 2) << 16 | 255 << 24));
ref RGB24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Color dp = ref Unsafe.Add(ref destRef, i);
source += 3;
destination += 4;
Unsafe.As<Color, RGB24>(ref dp) = sp;
dp.A = 255;
}
}
/// <inheritdoc />
internal override unsafe void ToXyzBytes(BufferSpan<Color> sourceColors, BufferSpan<byte> destBytes, int count)
internal override void ToXyzBytes(BufferSpan<Color> sourceColors, BufferSpan<byte> destBytes, int count)
{
byte* source = (byte*)sourceColors;
byte* destination = (byte*)destBytes;
ref Color sourceRef = ref sourceColors.DangerousGetPinnableReference();
ref RGB24 destRef = ref Unsafe.As<byte, RGB24>(ref destBytes.DangerousGetPinnableReference());
for (int x = 0; x < count; x++)
for (int i = 0; i < count; i++)
{
*destination = *(source + 0);
*(destination + 1) = *(source + 1);
*(destination + 2) = *(source + 2);
ref Color sp = ref Unsafe.Add(ref sourceRef, i);
ref RGB24 dp = ref Unsafe.Add(ref destRef, i);
source += 4;
destination += 3;
dp = Unsafe.As<Color, RGB24>(ref sp);
}
}
/// <inheritdoc />
internal override void PackFromXyzwBytes(BufferSpan<byte> sourceBytes, BufferSpan<Color> destColors, int count)
internal override unsafe void PackFromXyzwBytes(BufferSpan<byte> sourceBytes, BufferSpan<Color> destColors, int count)
{
BufferSpan.Copy(sourceBytes, destColors, count);
BufferSpan.Copy(sourceBytes, destColors.AsBytes(), count * sizeof(Color));
}
/// <inheritdoc />
internal override void ToXyzwBytes(BufferSpan<Color> sourceColors, BufferSpan<byte> destBytes, int count)
internal override unsafe void ToXyzwBytes(BufferSpan<Color> sourceColors, BufferSpan<byte> destBytes, int count)
{
BufferSpan.Copy(sourceColors, destBytes, count);
BufferSpan.Copy(sourceColors.AsBytes(), destBytes, count * sizeof(Color));
}
/// <inheritdoc />
internal override unsafe void PackFromZyxBytes(BufferSpan<byte> sourceBytes, BufferSpan<Color> destColors, int count)
internal override void PackFromZyxBytes(BufferSpan<byte> sourceBytes, BufferSpan<Color> destColors, int count)
{
byte* source = (byte*)sourceBytes;
byte* destination = (byte*)destColors;
ref RGB24 sourceRef = ref Unsafe.As<byte, RGB24>(ref sourceBytes.DangerousGetPinnableReference());
ref Color destRef = ref destColors.DangerousGetPinnableReference();
for (int x = 0; x < count; x++)
for (int i = 0; i < count; i++)
{
Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | 255 << 24));
ref RGB24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Color dp = ref Unsafe.Add(ref destRef, i);
source += 3;
destination += 4;
Unsafe.As<Color, RGB24>(ref dp) = sp.ToZyx();
dp.A = 255;
}
}
/// <inheritdoc />
internal override unsafe void ToZyxBytes(BufferSpan<Color> sourceColors, BufferSpan<byte> destBytes, int count)
internal override void ToZyxBytes(BufferSpan<Color> sourceColors, BufferSpan<byte> destBytes, int count)
{
byte* source = (byte*)sourceColors;
byte* destination = (byte*)destBytes;
ref Color sourceRef = ref sourceColors.DangerousGetPinnableReference();
ref RGB24 destRef = ref Unsafe.As<byte, RGB24>(ref destBytes.DangerousGetPinnableReference());
for (int x = 0; x < count; x++)
for (int i = 0; i < count; i++)
{
*destination = *(source + 2);
*(destination + 1) = *(source + 1);
*(destination + 2) = *(source + 0);
ref Color sp = ref Unsafe.Add(ref sourceRef, i);
ref RGB24 dp = ref Unsafe.Add(ref destRef, i);
source += 4;
destination += 3;
dp = Unsafe.As<Color, RGB24>(ref sp).ToZyx();
}
}
/// <inheritdoc />
internal override unsafe void PackFromZyxwBytes(BufferSpan<byte> sourceBytes, BufferSpan<Color> destColors, int count)
internal override void PackFromZyxwBytes(BufferSpan<byte> sourceBytes, BufferSpan<Color> destColors, int count)
{
byte* source = (byte*)sourceBytes;
byte* destination = (byte*)destColors;
ref RGBA32 sourceRef = ref Unsafe.As<byte, RGBA32>(ref sourceBytes.DangerousGetPinnableReference());
ref Color destRef = ref destColors.DangerousGetPinnableReference();
for (int x = 0; x < count; x++)
for (int i = 0; i < count; i++)
{
Unsafe.Write(destination, (uint)(*(source + 2) << 0 | *(source + 1) << 8 | *source << 16 | *(source + 3) << 24));
source += 4;
destination += 4;
ref RGBA32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Color dp = ref Unsafe.Add(ref destRef, i);
RGBA32 zyxw = sp.ToZyxw();
dp = Unsafe.As<RGBA32, Color>(ref zyxw);
}
}
/// <inheritdoc />
internal override unsafe void ToZyxwBytes(BufferSpan<Color> sourceColors, BufferSpan<byte> destBytes, int count)
internal override void ToZyxwBytes(BufferSpan<Color> sourceColors, BufferSpan<byte> destBytes, int count)
{
byte* source = (byte*)sourceColors;
byte* destination = (byte*)destBytes;
ref Color sourceRef = ref sourceColors.DangerousGetPinnableReference();
ref RGBA32 destRef = ref Unsafe.As<byte, RGBA32>(ref destBytes.DangerousGetPinnableReference());
for (int x = 0; x < count; x++)
for (int i = 0; i < count; i++)
{
*destination = *(source + 2);
*(destination + 1) = *(source + 1);
*(destination + 2) = *(source + 0);
*(destination + 3) = *(source + 3);
source += 4;
destination += 4;
ref RGBA32 sp = ref Unsafe.As<Color, RGBA32>(ref Unsafe.Add(ref sourceRef, i));
ref RGBA32 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToZyxw();
}
}
/// <summary>
/// Helper struct to manipulate 3-byte RGB data.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct RGB24
{
private byte x;
private byte y;
private byte z;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public RGB24 ToZyx() => new RGB24 { x = this.z, y = this.y, z = this.x };
}
/// <summary>
/// Helper struct to manipulate 4-byte RGBA data.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct RGBA32
{
private byte x;
private byte y;
private byte z;
private byte w;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public RGBA32 ToZyxw() => new RGBA32 { x = this.z, y = this.y, z = this.x, w = this.w };
}
/// <summary>
/// Value type to store <see cref="Color"/>-s unpacked into multiple <see cref="uint"/>-s.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct UnpackedRGBA
{
private uint r;
private uint g;
private uint b;
private uint a;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Load(uint p)
{
this.r = p;
this.g = p >> Color.GreenShift;
this.b = p >> Color.BlueShift;
this.a = p >> Color.AlphaShift;
this.g = p >> GreenShift;
this.b = p >> BlueShift;
this.a = p >> AlphaShift;
}
}
}

2
src/ImageSharp/Colors/ColorDefinitions.cs → src/ImageSharp/Colors/Color.Definitions.cs

@ -1,4 +1,4 @@
// <copyright file="ColorDefinitions.cs" company="James Jackson-South">
// <copyright file="Color.Definitions.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>

38
src/ImageSharp/Colors/ColorTransforms.cs → src/ImageSharp/Colors/Color.Transforms.cs

@ -1,4 +1,4 @@
// <copyright file="ColorTransforms.cs" company="James Jackson-South">
// <copyright file="Color.Transforms.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -6,9 +6,10 @@
namespace ImageSharp
{
using System.Numerics;
using System.Runtime.CompilerServices;
/// <summary>
/// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 255.
/// 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.
/// </summary>
/// <remarks>
@ -25,10 +26,11 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Color"/>.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Color operator +(Color left, Color right)
{
Vector4 add = left.ToVector4() + right.ToVector4();
return new Color(Pack(ref add));
return PackNew(ref add);
}
/// <summary>
@ -39,10 +41,11 @@ namespace ImageSharp
/// <returns>
/// The <see cref="Color"/>.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Color operator -(Color left, Color right)
{
Vector4 sub = left.ToVector4() - right.ToVector4();
return new Color(Pack(ref sub));
return PackNew(ref sub);
}
/// <summary>
@ -56,7 +59,7 @@ namespace ImageSharp
public static Color Normal(Color backdrop, Color source)
{
Vector4 normal = Vector4BlendTransforms.Normal(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref normal));
return PackNew(ref normal);
}
/// <summary>
@ -76,7 +79,7 @@ namespace ImageSharp
public static Color Multiply(Color backdrop, Color source)
{
Vector4 multiply = Vector4BlendTransforms.Multiply(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref multiply));
return PackNew(ref multiply);
}
/// <summary>
@ -95,7 +98,7 @@ namespace ImageSharp
public static Color Screen(Color backdrop, Color source)
{
Vector4 subtract = Vector4BlendTransforms.Screen(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref subtract));
return PackNew(ref subtract);
}
/// <summary>
@ -110,7 +113,7 @@ namespace ImageSharp
public static Color HardLight(Color backdrop, Color source)
{
Vector4 hardlight = Vector4BlendTransforms.HardLight(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref hardlight));
return PackNew(ref hardlight);
}
/// <summary>
@ -129,7 +132,7 @@ namespace ImageSharp
public static Color Overlay(Color backdrop, Color source)
{
Vector4 overlay = Vector4BlendTransforms.Overlay(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref overlay));
return PackNew(ref overlay);
}
/// <summary>
@ -144,7 +147,7 @@ namespace ImageSharp
public static Color Darken(Color backdrop, Color source)
{
Vector4 darken = Vector4BlendTransforms.Darken(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref darken));
return PackNew(ref darken);
}
/// <summary>
@ -159,7 +162,7 @@ namespace ImageSharp
public static Color Lighten(Color backdrop, Color source)
{
Vector4 lighten = Vector4BlendTransforms.Lighten(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref lighten));
return PackNew(ref lighten);
}
/// <summary>
@ -174,7 +177,7 @@ namespace ImageSharp
public static Color SoftLight(Color backdrop, Color source)
{
Vector4 softlight = Vector4BlendTransforms.SoftLight(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref softlight));
return PackNew(ref softlight);
}
/// <summary>
@ -188,7 +191,7 @@ namespace ImageSharp
public static Color ColorDodge(Color backdrop, Color source)
{
Vector4 dodge = Vector4BlendTransforms.Dodge(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref dodge));
return PackNew(ref dodge);
}
/// <summary>
@ -202,7 +205,7 @@ namespace ImageSharp
public static Color ColorBurn(Color backdrop, Color source)
{
Vector4 burn = Vector4BlendTransforms.Burn(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref burn));
return PackNew(ref burn);
}
/// <summary>
@ -217,7 +220,7 @@ namespace ImageSharp
public static Color Difference(Color backdrop, Color source)
{
Vector4 difference = Vector4BlendTransforms.Difference(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref difference));
return PackNew(ref difference);
}
/// <summary>
@ -232,7 +235,7 @@ namespace ImageSharp
public static Color Exclusion(Color backdrop, Color source)
{
Vector4 exclusion = Vector4BlendTransforms.Exclusion(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref exclusion));
return PackNew(ref exclusion);
}
/// <summary>
@ -249,7 +252,8 @@ namespace ImageSharp
/// </returns>
public static Color Lerp(Color from, Color to, float amount)
{
return new Color(Vector4.Lerp(from.ToVector4(), to.ToVector4(), amount));
Vector4 lerp = Vector4.Lerp(from.ToVector4(), to.ToVector4(), amount);
return PackNew(ref lerp);
}
}
}

240
src/ImageSharp/Colors/Color.cs

@ -5,10 +5,9 @@
namespace ImageSharp
{
using System;
using System.Globalization;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary>
/// Packed pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
@ -18,8 +17,39 @@ namespace ImageSharp
/// 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 : IPixel<Color>, IPackedVector<uint>
{
/// <summary>
/// Gets or sets the red component.
/// </summary>
[FieldOffset(0)]
public byte R;
/// <summary>
/// Gets or sets the green component.
/// </summary>
[FieldOffset(1)]
public byte G;
/// <summary>
/// Gets or sets the blue component.
/// </summary>
[FieldOffset(2)]
public byte B;
/// <summary>
/// Gets or sets the alpha component.
/// </summary>
[FieldOffset(3)]
public byte A;
/// <summary>
/// The packed representation of the value.
/// </summary>
[FieldOffset(0)]
public uint Rgba;
/// <summary>
/// The shift count for the red component
/// </summary>
@ -50,11 +80,6 @@ namespace ImageSharp
/// </summary>
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary>
/// The packed value.
/// </summary>
private uint packedValue;
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
@ -62,9 +87,14 @@ namespace ImageSharp
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Color(byte r, byte g, byte b, byte a = 255)
: this()
{
this.packedValue = Pack(r, g, b, a);
this.R = r;
this.G = g;
this.B = b;
this.A = a;
}
/// <summary>
@ -74,9 +104,11 @@ namespace ImageSharp
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Color(float r, float g, float b, float a = 1)
: this()
{
this.packedValue = Pack(r, g, b, a);
this.Pack(r, g, b, a);
}
/// <summary>
@ -85,9 +117,11 @@ namespace ImageSharp
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Color(Vector3 vector)
: this()
{
this.packedValue = Pack(ref vector);
this.Pack(ref vector);
}
/// <summary>
@ -96,9 +130,11 @@ namespace ImageSharp
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Color(Vector4 vector)
: this()
{
this.packedValue = Pack(ref vector);
this = PackNew(ref vector);
}
/// <summary>
@ -107,96 +143,15 @@ namespace ImageSharp
/// <param name="packed">
/// The packed value.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Color(uint packed)
: this()
{
this.packedValue = packed;
}
/// <summary>
/// Gets or sets the red component.
/// </summary>
public byte R
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return (byte)(this.packedValue >> RedShift);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.packedValue = this.packedValue & 0xFFFFFF00 | (uint)value << RedShift;
}
}
/// <summary>
/// Gets or sets the green component.
/// </summary>
public byte G
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return (byte)(this.packedValue >> GreenShift);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.packedValue = this.packedValue & 0xFFFF00FF | (uint)value << GreenShift;
}
}
/// <summary>
/// Gets or sets the blue component.
/// </summary>
public byte B
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return (byte)(this.packedValue >> BlueShift);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.packedValue = this.packedValue & 0xFF00FFFF | (uint)value << BlueShift;
}
}
/// <summary>
/// Gets or sets the alpha component.
/// </summary>
public byte A
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return (byte)(this.packedValue >> AlphaShift);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.packedValue = this.packedValue & 0x00FFFFFF | (uint)value << AlphaShift;
}
this.Rgba = packed;
}
/// <inheritdoc/>
public uint PackedValue
{
get
{
return this.packedValue;
}
set
{
this.packedValue = value;
}
}
public uint PackedValue { get => this.Rgba; set => this.Rgba = value; }
/// <summary>
/// Compares two <see cref="Color"/> objects for equality.
@ -213,7 +168,7 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Color left, Color right)
{
return left.packedValue == right.packedValue;
return left.Rgba == right.Rgba;
}
/// <summary>
@ -227,7 +182,7 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Color left, Color right)
{
return left.packedValue != right.packedValue;
return left.Rgba != right.Rgba;
}
/// <summary>
@ -246,13 +201,16 @@ namespace ImageSharp
}
/// <inheritdoc />
public BulkPixelOperations<Color> CreateBulkOperations() => new Color.BulkOperations();
public BulkPixelOperations<Color> CreateBulkOperations() => new BulkOperations();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBytes(byte x, byte y, byte z, byte w)
{
this.packedValue = Pack(x, y, z, w);
this.R = x;
this.G = y;
this.B = z;
this.A = w;
}
/// <summary>
@ -307,7 +265,7 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.packedValue = Pack(ref vector);
this.Pack(ref vector);
}
/// <inheritdoc/>
@ -327,7 +285,7 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Color other)
{
return this.packedValue == other.packedValue;
return this.Rgba == other.Rgba;
}
/// <summary>
@ -342,65 +300,85 @@ namespace ImageSharp
/// <inheritdoc/>
public override int GetHashCode()
{
return this.packedValue.GetHashCode();
unchecked
{
int hashCode = this.R.GetHashCode();
hashCode = (hashCode * 397) ^ this.G.GetHashCode();
hashCode = (hashCode * 397) ^ this.B.GetHashCode();
hashCode = (hashCode * 397) ^ this.A.GetHashCode();
return hashCode;
}
}
/// <summary>
/// Packs a <see cref="Vector4"/> into a uint.
/// Packs the four floats into a <see cref="uint"/>.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
/// <returns>The <see cref="uint"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(ref Vector4 vector)
private static uint Pack(byte x, byte y, byte z, byte w)
{
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return (uint)(((byte)vector.X << RedShift)
| ((byte)vector.Y << GreenShift)
| ((byte)vector.Z << BlueShift)
| (byte)vector.W << AlphaShift);
return (uint)(x << RedShift | y << GreenShift | z << BlueShift | w << AlphaShift);
}
/// <summary>
/// Packs a <see cref="Vector3"/> into a uint.
/// Packs a <see cref="Vector4"/> into a color returning a new instance as a result.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
/// <returns>The <see cref="Color"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(ref Vector3 vector)
private static Color PackNew(ref Vector4 vector)
{
Vector4 value = new Vector4(vector, 1);
return Pack(ref value);
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return new Color((byte)vector.X, (byte)vector.Y, (byte)vector.Z, (byte)vector.W);
}
/// <summary>
/// Packs the four floats into a <see cref="uint"/>.
/// Packs the four floats into a color.
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
/// <returns>The <see cref="uint"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y, float z, float w)
private void Pack(float x, float y, float z, float w)
{
Vector4 value = new Vector4(x, y, z, w);
return Pack(ref value);
this.Pack(ref value);
}
/// <summary>
/// Packs the four floats into a <see cref="uint"/>.
/// Packs a <see cref="Vector3"/> into a uint.
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
/// <returns>The <see cref="uint"/></returns>
/// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(byte x, byte y, byte z, byte w)
private void Pack(ref Vector3 vector)
{
return (uint)(x << RedShift | y << GreenShift | z << BlueShift | w << AlphaShift);
Vector4 value = new Vector4(vector, 1);
this.Pack(ref value);
}
/// <summary>
/// Packs a <see cref="Vector4"/> into a color.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Pack(ref Vector4 vector)
{
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
this.R = (byte)vector.X;
this.G = (byte)vector.Y;
this.B = (byte)vector.Z;
this.A = (byte)vector.W;
}
}
}

27
src/ImageSharp/Colors/ColorVector.BulkOperations.cs

@ -0,0 +1,27 @@
namespace ImageSharp
{
using System.Numerics;
/// <summary>
/// Unpacked pixel type containing four 16-bit unsigned normalized values typically ranging from 0 to 1.
/// The color components are stored in red, green, blue, and alpha order.
/// </summary>
/// <remarks>
/// 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>
public partial struct ColorVector
{
/// <summary>
/// <see cref="BulkPixelOperations{TColor}"/> implementation optimized for <see cref="ColorVector"/>.
/// </summary>
internal class BulkOperations : BulkPixelOperations<ColorVector>
{
/// <inheritdoc />
internal override unsafe void ToVector4(BufferSpan<ColorVector> sourceColors, BufferSpan<Vector4> destVectors, int count)
{
BufferSpan.Copy(sourceColors.AsBytes(), destVectors.AsBytes(), count * sizeof(Vector4));
}
}
}
}

728
src/ImageSharp/Colors/ColorVector.Definitions.cs

@ -0,0 +1,728 @@
// <copyright file="ColorVector.Definitions.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// 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>
public partial struct ColorVector
{
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #F0F8FF.
/// </summary>
public static readonly ColorVector AliceBlue = NamedColors<ColorVector>.AliceBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FAEBD7.
/// </summary>
public static readonly ColorVector AntiqueWhite = NamedColors<ColorVector>.AntiqueWhite;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #00FFFF.
/// </summary>
public static readonly ColorVector Aqua = NamedColors<ColorVector>.Aqua;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #7FFFD4.
/// </summary>
public static readonly ColorVector Aquamarine = NamedColors<ColorVector>.Aquamarine;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #F0FFFF.
/// </summary>
public static readonly ColorVector Azure = NamedColors<ColorVector>.Azure;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #F5F5DC.
/// </summary>
public static readonly ColorVector Beige = NamedColors<ColorVector>.Beige;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFE4C4.
/// </summary>
public static readonly ColorVector Bisque = NamedColors<ColorVector>.Bisque;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #000000.
/// </summary>
public static readonly ColorVector Black = NamedColors<ColorVector>.Black;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFEBCD.
/// </summary>
public static readonly ColorVector BlanchedAlmond = NamedColors<ColorVector>.BlanchedAlmond;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #0000FF.
/// </summary>
public static readonly ColorVector Blue = NamedColors<ColorVector>.Blue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #8A2BE2.
/// </summary>
public static readonly ColorVector BlueViolet = NamedColors<ColorVector>.BlueViolet;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #A52A2A.
/// </summary>
public static readonly ColorVector Brown = NamedColors<ColorVector>.Brown;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #DEB887.
/// </summary>
public static readonly ColorVector BurlyWood = NamedColors<ColorVector>.BurlyWood;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #5F9EA0.
/// </summary>
public static readonly ColorVector CadetBlue = NamedColors<ColorVector>.CadetBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #7FFF00.
/// </summary>
public static readonly ColorVector Chartreuse = NamedColors<ColorVector>.Chartreuse;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #D2691E.
/// </summary>
public static readonly ColorVector Chocolate = NamedColors<ColorVector>.Chocolate;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FF7F50.
/// </summary>
public static readonly ColorVector Coral = NamedColors<ColorVector>.Coral;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #6495ED.
/// </summary>
public static readonly ColorVector CornflowerBlue = NamedColors<ColorVector>.CornflowerBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFF8DC.
/// </summary>
public static readonly ColorVector Cornsilk = NamedColors<ColorVector>.Cornsilk;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #DC143C.
/// </summary>
public static readonly ColorVector Crimson = NamedColors<ColorVector>.Crimson;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #00FFFF.
/// </summary>
public static readonly ColorVector Cyan = NamedColors<ColorVector>.Cyan;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #00008B.
/// </summary>
public static readonly ColorVector DarkBlue = NamedColors<ColorVector>.DarkBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #008B8B.
/// </summary>
public static readonly ColorVector DarkCyan = NamedColors<ColorVector>.DarkCyan;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #B8860B.
/// </summary>
public static readonly ColorVector DarkGoldenrod = NamedColors<ColorVector>.DarkGoldenrod;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #A9A9A9.
/// </summary>
public static readonly ColorVector DarkGray = NamedColors<ColorVector>.DarkGray;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #006400.
/// </summary>
public static readonly ColorVector DarkGreen = NamedColors<ColorVector>.DarkGreen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #BDB76B.
/// </summary>
public static readonly ColorVector DarkKhaki = NamedColors<ColorVector>.DarkKhaki;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #8B008B.
/// </summary>
public static readonly ColorVector DarkMagenta = NamedColors<ColorVector>.DarkMagenta;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #556B2F.
/// </summary>
public static readonly ColorVector DarkOliveGreen = NamedColors<ColorVector>.DarkOliveGreen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FF8C00.
/// </summary>
public static readonly ColorVector DarkOrange = NamedColors<ColorVector>.DarkOrange;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #9932CC.
/// </summary>
public static readonly ColorVector DarkOrchid = NamedColors<ColorVector>.DarkOrchid;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #8B0000.
/// </summary>
public static readonly ColorVector DarkRed = NamedColors<ColorVector>.DarkRed;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #E9967A.
/// </summary>
public static readonly ColorVector DarkSalmon = NamedColors<ColorVector>.DarkSalmon;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #8FBC8B.
/// </summary>
public static readonly ColorVector DarkSeaGreen = NamedColors<ColorVector>.DarkSeaGreen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #483D8B.
/// </summary>
public static readonly ColorVector DarkSlateBlue = NamedColors<ColorVector>.DarkSlateBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #2F4F4F.
/// </summary>
public static readonly ColorVector DarkSlateGray = NamedColors<ColorVector>.DarkSlateGray;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #00CED1.
/// </summary>
public static readonly ColorVector DarkTurquoise = NamedColors<ColorVector>.DarkTurquoise;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #9400D3.
/// </summary>
public static readonly ColorVector DarkViolet = NamedColors<ColorVector>.DarkViolet;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FF1493.
/// </summary>
public static readonly ColorVector DeepPink = NamedColors<ColorVector>.DeepPink;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #00BFFF.
/// </summary>
public static readonly ColorVector DeepSkyBlue = NamedColors<ColorVector>.DeepSkyBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #696969.
/// </summary>
public static readonly ColorVector DimGray = NamedColors<ColorVector>.DimGray;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #1E90FF.
/// </summary>
public static readonly ColorVector DodgerBlue = NamedColors<ColorVector>.DodgerBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #B22222.
/// </summary>
public static readonly ColorVector Firebrick = NamedColors<ColorVector>.Firebrick;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFFAF0.
/// </summary>
public static readonly ColorVector FloralWhite = NamedColors<ColorVector>.FloralWhite;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #228B22.
/// </summary>
public static readonly ColorVector ForestGreen = NamedColors<ColorVector>.ForestGreen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FF00FF.
/// </summary>
public static readonly ColorVector Fuchsia = NamedColors<ColorVector>.Fuchsia;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #DCDCDC.
/// </summary>
public static readonly ColorVector Gainsboro = NamedColors<ColorVector>.Gainsboro;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #F8F8FF.
/// </summary>
public static readonly ColorVector GhostWhite = NamedColors<ColorVector>.GhostWhite;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFD700.
/// </summary>
public static readonly ColorVector Gold = NamedColors<ColorVector>.Gold;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #DAA520.
/// </summary>
public static readonly ColorVector Goldenrod = NamedColors<ColorVector>.Goldenrod;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #808080.
/// </summary>
public static readonly ColorVector Gray = NamedColors<ColorVector>.Gray;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #008000.
/// </summary>
public static readonly ColorVector Green = NamedColors<ColorVector>.Green;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #ADFF2F.
/// </summary>
public static readonly ColorVector GreenYellow = NamedColors<ColorVector>.GreenYellow;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #F0FFF0.
/// </summary>
public static readonly ColorVector Honeydew = NamedColors<ColorVector>.Honeydew;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FF69B4.
/// </summary>
public static readonly ColorVector HotPink = NamedColors<ColorVector>.HotPink;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #CD5C5C.
/// </summary>
public static readonly ColorVector IndianRed = NamedColors<ColorVector>.IndianRed;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #4B0082.
/// </summary>
public static readonly ColorVector Indigo = NamedColors<ColorVector>.Indigo;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFFFF0.
/// </summary>
public static readonly ColorVector Ivory = NamedColors<ColorVector>.Ivory;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #F0E68C.
/// </summary>
public static readonly ColorVector Khaki = NamedColors<ColorVector>.Khaki;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #E6E6FA.
/// </summary>
public static readonly ColorVector Lavender = NamedColors<ColorVector>.Lavender;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFF0F5.
/// </summary>
public static readonly ColorVector LavenderBlush = NamedColors<ColorVector>.LavenderBlush;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #7CFC00.
/// </summary>
public static readonly ColorVector LawnGreen = NamedColors<ColorVector>.LawnGreen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFFACD.
/// </summary>
public static readonly ColorVector LemonChiffon = NamedColors<ColorVector>.LemonChiffon;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #ADD8E6.
/// </summary>
public static readonly ColorVector LightBlue = NamedColors<ColorVector>.LightBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #F08080.
/// </summary>
public static readonly ColorVector LightCoral = NamedColors<ColorVector>.LightCoral;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #E0FFFF.
/// </summary>
public static readonly ColorVector LightCyan = NamedColors<ColorVector>.LightCyan;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FAFAD2.
/// </summary>
public static readonly ColorVector LightGoldenrodYellow = NamedColors<ColorVector>.LightGoldenrodYellow;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #D3D3D3.
/// </summary>
public static readonly ColorVector LightGray = NamedColors<ColorVector>.LightGray;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #90EE90.
/// </summary>
public static readonly ColorVector LightGreen = NamedColors<ColorVector>.LightGreen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFB6C1.
/// </summary>
public static readonly ColorVector LightPink = NamedColors<ColorVector>.LightPink;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFA07A.
/// </summary>
public static readonly ColorVector LightSalmon = NamedColors<ColorVector>.LightSalmon;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #20B2AA.
/// </summary>
public static readonly ColorVector LightSeaGreen = NamedColors<ColorVector>.LightSeaGreen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #87CEFA.
/// </summary>
public static readonly ColorVector LightSkyBlue = NamedColors<ColorVector>.LightSkyBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #778899.
/// </summary>
public static readonly ColorVector LightSlateGray = NamedColors<ColorVector>.LightSlateGray;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #B0C4DE.
/// </summary>
public static readonly ColorVector LightSteelBlue = NamedColors<ColorVector>.LightSteelBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFFFE0.
/// </summary>
public static readonly ColorVector LightYellow = NamedColors<ColorVector>.LightYellow;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #00FF00.
/// </summary>
public static readonly ColorVector Lime = NamedColors<ColorVector>.Lime;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #32CD32.
/// </summary>
public static readonly ColorVector LimeGreen = NamedColors<ColorVector>.LimeGreen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FAF0E6.
/// </summary>
public static readonly ColorVector Linen = NamedColors<ColorVector>.Linen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FF00FF.
/// </summary>
public static readonly ColorVector Magenta = NamedColors<ColorVector>.Magenta;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #800000.
/// </summary>
public static readonly ColorVector Maroon = NamedColors<ColorVector>.Maroon;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #66CDAA.
/// </summary>
public static readonly ColorVector MediumAquamarine = NamedColors<ColorVector>.MediumAquamarine;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #0000CD.
/// </summary>
public static readonly ColorVector MediumBlue = NamedColors<ColorVector>.MediumBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #BA55D3.
/// </summary>
public static readonly ColorVector MediumOrchid = NamedColors<ColorVector>.MediumOrchid;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #9370DB.
/// </summary>
public static readonly ColorVector MediumPurple = NamedColors<ColorVector>.MediumPurple;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #3CB371.
/// </summary>
public static readonly ColorVector MediumSeaGreen = NamedColors<ColorVector>.MediumSeaGreen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #7B68EE.
/// </summary>
public static readonly ColorVector MediumSlateBlue = NamedColors<ColorVector>.MediumSlateBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #00FA9A.
/// </summary>
public static readonly ColorVector MediumSpringGreen = NamedColors<ColorVector>.MediumSpringGreen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #48D1CC.
/// </summary>
public static readonly ColorVector MediumTurquoise = NamedColors<ColorVector>.MediumTurquoise;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #C71585.
/// </summary>
public static readonly ColorVector MediumVioletRed = NamedColors<ColorVector>.MediumVioletRed;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #191970.
/// </summary>
public static readonly ColorVector MidnightBlue = NamedColors<ColorVector>.MidnightBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #F5FFFA.
/// </summary>
public static readonly ColorVector MintCream = NamedColors<ColorVector>.MintCream;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFE4E1.
/// </summary>
public static readonly ColorVector MistyRose = NamedColors<ColorVector>.MistyRose;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFE4B5.
/// </summary>
public static readonly ColorVector Moccasin = NamedColors<ColorVector>.Moccasin;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFDEAD.
/// </summary>
public static readonly ColorVector NavajoWhite = NamedColors<ColorVector>.NavajoWhite;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #000080.
/// </summary>
public static readonly ColorVector Navy = NamedColors<ColorVector>.Navy;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FDF5E6.
/// </summary>
public static readonly ColorVector OldLace = NamedColors<ColorVector>.OldLace;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #808000.
/// </summary>
public static readonly ColorVector Olive = NamedColors<ColorVector>.Olive;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #6B8E23.
/// </summary>
public static readonly ColorVector OliveDrab = NamedColors<ColorVector>.OliveDrab;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFA500.
/// </summary>
public static readonly ColorVector Orange = NamedColors<ColorVector>.Orange;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FF4500.
/// </summary>
public static readonly ColorVector OrangeRed = NamedColors<ColorVector>.OrangeRed;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #DA70D6.
/// </summary>
public static readonly ColorVector Orchid = NamedColors<ColorVector>.Orchid;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #EEE8AA.
/// </summary>
public static readonly ColorVector PaleGoldenrod = NamedColors<ColorVector>.PaleGoldenrod;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #98FB98.
/// </summary>
public static readonly ColorVector PaleGreen = NamedColors<ColorVector>.PaleGreen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #AFEEEE.
/// </summary>
public static readonly ColorVector PaleTurquoise = NamedColors<ColorVector>.PaleTurquoise;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #DB7093.
/// </summary>
public static readonly ColorVector PaleVioletRed = NamedColors<ColorVector>.PaleVioletRed;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFEFD5.
/// </summary>
public static readonly ColorVector PapayaWhip = NamedColors<ColorVector>.PapayaWhip;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFDAB9.
/// </summary>
public static readonly ColorVector PeachPuff = NamedColors<ColorVector>.PeachPuff;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #CD853F.
/// </summary>
public static readonly ColorVector Peru = NamedColors<ColorVector>.Peru;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFC0CB.
/// </summary>
public static readonly ColorVector Pink = NamedColors<ColorVector>.Pink;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #DDA0DD.
/// </summary>
public static readonly ColorVector Plum = NamedColors<ColorVector>.Plum;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #B0E0E6.
/// </summary>
public static readonly ColorVector PowderBlue = NamedColors<ColorVector>.PowderBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #800080.
/// </summary>
public static readonly ColorVector Purple = NamedColors<ColorVector>.Purple;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #663399.
/// </summary>
public static readonly ColorVector RebeccaPurple = NamedColors<ColorVector>.RebeccaPurple;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FF0000.
/// </summary>
public static readonly ColorVector Red = NamedColors<ColorVector>.Red;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #BC8F8F.
/// </summary>
public static readonly ColorVector RosyBrown = NamedColors<ColorVector>.RosyBrown;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #4169E1.
/// </summary>
public static readonly ColorVector RoyalBlue = NamedColors<ColorVector>.RoyalBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #8B4513.
/// </summary>
public static readonly ColorVector SaddleBrown = NamedColors<ColorVector>.SaddleBrown;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FA8072.
/// </summary>
public static readonly ColorVector Salmon = NamedColors<ColorVector>.Salmon;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #F4A460.
/// </summary>
public static readonly ColorVector SandyBrown = NamedColors<ColorVector>.SandyBrown;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #2E8B57.
/// </summary>
public static readonly ColorVector SeaGreen = NamedColors<ColorVector>.SeaGreen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFF5EE.
/// </summary>
public static readonly ColorVector SeaShell = NamedColors<ColorVector>.SeaShell;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #A0522D.
/// </summary>
public static readonly ColorVector Sienna = NamedColors<ColorVector>.Sienna;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #C0C0C0.
/// </summary>
public static readonly ColorVector Silver = NamedColors<ColorVector>.Silver;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #87CEEB.
/// </summary>
public static readonly ColorVector SkyBlue = NamedColors<ColorVector>.SkyBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #6A5ACD.
/// </summary>
public static readonly ColorVector SlateBlue = NamedColors<ColorVector>.SlateBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #708090.
/// </summary>
public static readonly ColorVector SlateGray = NamedColors<ColorVector>.SlateGray;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFFAFA.
/// </summary>
public static readonly ColorVector Snow = NamedColors<ColorVector>.Snow;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #00FF7F.
/// </summary>
public static readonly ColorVector SpringGreen = NamedColors<ColorVector>.SpringGreen;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #4682B4.
/// </summary>
public static readonly ColorVector SteelBlue = NamedColors<ColorVector>.SteelBlue;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #D2B48C.
/// </summary>
public static readonly ColorVector Tan = NamedColors<ColorVector>.Tan;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #008080.
/// </summary>
public static readonly ColorVector Teal = NamedColors<ColorVector>.Teal;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #D8BFD8.
/// </summary>
public static readonly ColorVector Thistle = NamedColors<ColorVector>.Thistle;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FF6347.
/// </summary>
public static readonly ColorVector Tomato = NamedColors<ColorVector>.Tomato;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFFFFF.
/// </summary>
public static readonly ColorVector Transparent = NamedColors<ColorVector>.Transparent;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #40E0D0.
/// </summary>
public static readonly ColorVector Turquoise = NamedColors<ColorVector>.Turquoise;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #EE82EE.
/// </summary>
public static readonly ColorVector Violet = NamedColors<ColorVector>.Violet;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #F5DEB3.
/// </summary>
public static readonly ColorVector Wheat = NamedColors<ColorVector>.Wheat;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFFFFF.
/// </summary>
public static readonly ColorVector White = NamedColors<ColorVector>.White;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #F5F5F5.
/// </summary>
public static readonly ColorVector WhiteSmoke = NamedColors<ColorVector>.WhiteSmoke;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #FFFF00.
/// </summary>
public static readonly ColorVector Yellow = NamedColors<ColorVector>.Yellow;
/// <summary>
/// Represents a <see cref="ColorVector"/> matching the W3C definition that has an hex value of #9ACD32.
/// </summary>
public static readonly ColorVector YellowGreen = NamedColors<ColorVector>.YellowGreen;
}
}

256
src/ImageSharp/Colors/ColorVector.Transforms.cs

@ -0,0 +1,256 @@
// <copyright file="ColorVector.Transforms.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Numerics;
using System.Runtime.CompilerServices;
/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// 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>
public partial struct ColorVector
{
/// <summary>
/// Adds the second color to the first.
/// </summary>
/// <param name="left">The first source color.</param>
/// <param name="right">The second source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ColorVector operator +(ColorVector left, ColorVector right)
{
return new ColorVector(left.backingVector + right.backingVector);
}
/// <summary>
/// Subtracts the second color from the first.
/// </summary>
/// <param name="left">The first source color.</param>
/// <param name="right">The second source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ColorVector operator -(ColorVector left, ColorVector right)
{
return new ColorVector(left.backingVector - right.backingVector);
}
/// <summary>
/// The blending formula simply selects the source color.
/// </summary>
/// <param name="backdrop">The backdrop color.</param>
/// <param name="source">The source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
public static ColorVector Normal(ColorVector backdrop, ColorVector source)
{
Vector4 normal = Vector4BlendTransforms.Normal(backdrop.backingVector, source.backingVector);
return new ColorVector(normal);
}
/// <summary>
/// Blends two colors by multiplication.
/// <remarks>
/// The source color is multiplied by the destination color and replaces the destination.
/// The resultant color is always at least as dark as either the source or destination color.
/// Multiplying any color with black results in black. Multiplying any color with white preserves the
/// original color.
/// </remarks>
/// </summary>
/// <param name="backdrop">The backdrop color.</param>
/// <param name="source">The source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
public static ColorVector Multiply(ColorVector backdrop, ColorVector source)
{
Vector4 multiply = Vector4BlendTransforms.Multiply(backdrop.backingVector, source.backingVector);
return new ColorVector(multiply);
}
/// <summary>
/// Multiplies the complements of the backdrop and source color values, then complements the result.
/// <remarks>
/// The result color is always at least as light as either of the two constituent colors. Screening any
/// color with white produces white; screening with black leaves the original color unchanged.
/// The effect is similar to projecting multiple photographic slides simultaneously onto a single screen.
/// </remarks>
/// </summary>
/// <param name="backdrop">The backdrop color.</param>
/// <param name="source">The source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
public static ColorVector Screen(ColorVector backdrop, ColorVector source)
{
Vector4 subtract = Vector4BlendTransforms.Screen(backdrop.backingVector, source.backingVector);
return new ColorVector(subtract);
}
/// <summary>
/// Multiplies or screens the colors, depending on the source color value. The effect is similar to
/// shining a harsh spotlight on the backdrop.
/// </summary>
/// <param name="backdrop">The backdrop color.</param>
/// <param name="source">The source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
public static ColorVector HardLight(ColorVector backdrop, ColorVector source)
{
Vector4 hardlight = Vector4BlendTransforms.HardLight(backdrop.backingVector, source.backingVector);
return new ColorVector(hardlight);
}
/// <summary>
/// Multiplies or screens the colors, depending on the backdrop color value.
/// <remarks>
/// Source colors overlay the backdrop while preserving its highlights and shadows.
/// The backdrop color is not replaced but is mixed with the source color to reflect the lightness or darkness
/// of the backdrop.
/// </remarks>
/// </summary>
/// <param name="backdrop">The backdrop color.</param>
/// <param name="source">The source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
public static ColorVector Overlay(ColorVector backdrop, ColorVector source)
{
Vector4 overlay = Vector4BlendTransforms.Overlay(backdrop.backingVector, source.backingVector);
return new ColorVector(overlay);
}
/// <summary>
/// Selects the darker of the backdrop and source colors.
/// The backdrop is replaced with the source where the source is darker; otherwise, it is left unchanged.
/// </summary>
/// <param name="backdrop">The backdrop color.</param>
/// <param name="source">The source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
public static ColorVector Darken(ColorVector backdrop, ColorVector source)
{
Vector4 darken = Vector4BlendTransforms.Darken(backdrop.backingVector, source.backingVector);
return new ColorVector(darken);
}
/// <summary>
/// Selects the lighter of the backdrop and source colors.
/// The backdrop is replaced with the source where the source is lighter; otherwise, it is left unchanged.
/// </summary>
/// <param name="backdrop">The backdrop color.</param>
/// <param name="source">The source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
public static ColorVector Lighten(ColorVector backdrop, ColorVector source)
{
Vector4 lighten = Vector4BlendTransforms.Lighten(backdrop.backingVector, source.backingVector);
return new ColorVector(lighten);
}
/// <summary>
/// Darkens or lightens the colors, depending on the source color value. The effect is similar to shining
/// a diffused spotlight on the backdrop.
/// </summary>
/// <param name="backdrop">The backdrop color.</param>
/// <param name="source">The source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
public static ColorVector SoftLight(ColorVector backdrop, ColorVector source)
{
Vector4 softlight = Vector4BlendTransforms.SoftLight(backdrop.backingVector, source.backingVector);
return new ColorVector(softlight);
}
/// <summary>
/// Brightens the backdrop color to reflect the source color. Painting with black produces no changes.
/// </summary>
/// <param name="backdrop">The backdrop color.</param>
/// <param name="source">The source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
public static ColorVector ColorDodge(ColorVector backdrop, ColorVector source)
{
Vector4 dodge = Vector4BlendTransforms.Dodge(backdrop.backingVector, source.backingVector);
return new ColorVector(dodge);
}
/// <summary>
/// Darkens the backdrop color to reflect the source color. Painting with white produces no change.
/// </summary>
/// <param name="backdrop">The backdrop color.</param>
/// <param name="source">The source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
public static ColorVector ColorBurn(ColorVector backdrop, ColorVector source)
{
Vector4 burn = Vector4BlendTransforms.Burn(backdrop.backingVector, source.backingVector);
return new ColorVector(burn);
}
/// <summary>
/// Subtracts the darker of the two constituent colors from the lighter color.
/// Painting with white inverts the backdrop color; painting with black produces no change.
/// </summary>
/// <param name="backdrop">The backdrop color.</param>
/// <param name="source">The source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
public static ColorVector Difference(ColorVector backdrop, ColorVector source)
{
Vector4 difference = Vector4BlendTransforms.Difference(backdrop.backingVector, source.backingVector);
return new ColorVector(difference);
}
/// <summary>
/// Produces an effect similar to that of the <see cref="Difference"/> mode but lower in contrast. Painting with white
/// inverts the backdrop color; painting with black produces no change
/// </summary>
/// <param name="backdrop">The backdrop color.</param>
/// <param name="source">The source color.</param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
public static ColorVector Exclusion(ColorVector backdrop, ColorVector source)
{
Vector4 exclusion = Vector4BlendTransforms.Exclusion(backdrop.backingVector, source.backingVector);
return new ColorVector(exclusion);
}
/// <summary>
/// Linearly interpolates from one color to another based on the given weighting.
/// </summary>
/// <param name="from">The first color value.</param>
/// <param name="to">The second color value.</param>
/// <param name="amount">
/// A value between 0 and 1 indicating the weight of the second source vector.
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
/// </param>
/// <returns>
/// The <see cref="ColorVector"/>
/// </returns>
public static ColorVector Lerp(ColorVector from, ColorVector to, float amount)
{
return new ColorVector(Vector4.Lerp(from.backingVector, to.backingVector, amount));
}
}
}

320
src/ImageSharp/Colors/ColorVector.cs

@ -0,0 +1,320 @@
// <copyright file="ColorVector.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Numerics;
using System.Runtime.CompilerServices;
/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// 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>
public partial struct ColorVector : IPixel<ColorVector>
{
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half vector value.
/// </summary>
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private Vector4 backingVector;
/// <summary>
/// Initializes a new instance of the <see cref="ColorVector"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ColorVector(byte r, byte g, byte b, byte a = 255)
: this()
{
this.backingVector = new Vector4(r, g, b, a) / MaxBytes;
}
/// <summary>
/// Initializes a new instance of the <see cref="ColorVector"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ColorVector(float r, float g, float b, float a = 1)
: this()
{
this.backingVector = new Vector4(r, g, b, a);
}
/// <summary>
/// Initializes a new instance of the <see cref="ColorVector"/> struct.
/// </summary>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ColorVector(Vector3 vector)
: this()
{
this.backingVector = new Vector4(vector, 1);
}
/// <summary>
/// Initializes a new instance of the <see cref="ColorVector"/> struct.
/// </summary>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ColorVector(Vector4 vector)
: this()
{
this.backingVector = vector;
}
/// <summary>
/// Gets or sets the red component.
/// </summary>
public float R
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.backingVector.X;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.backingVector.X = value;
}
}
/// <summary>
/// Gets or sets the green component.
/// </summary>
public float G
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.backingVector.Y;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.backingVector.Y = value;
}
}
/// <summary>
/// Gets or sets the blue component.
/// </summary>
public float B
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.backingVector.Z;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.backingVector.Z = value;
}
}
/// <summary>
/// Gets or sets the alpha component.
/// </summary>
public float A
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.backingVector.W;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.backingVector.W = value;
}
}
/// <summary>
/// Compares two <see cref="ColorVector"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="ColorVector"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="ColorVector"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(ColorVector left, ColorVector right)
{
return left.backingVector == right.backingVector;
}
/// <summary>
/// Compares two <see cref="ColorVector"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="ColorVector"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="ColorVector"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(ColorVector left, ColorVector right)
{
return left.backingVector != right.backingVector;
}
/// <summary>
/// Creates a new instance of the <see cref="ColorVector"/> struct.
/// </summary>
/// <param name="hex">
/// The hexadecimal representation of the combined color components arranged
/// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax.
/// </param>
/// <returns>
/// The <see cref="ColorVector"/>.
/// </returns>
public static ColorVector FromHex(string hex)
{
return ColorBuilder<ColorVector>.FromHex(hex);
}
/// <inheritdoc />
public BulkPixelOperations<ColorVector> CreateBulkOperations() => new ColorVector.BulkOperations();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBytes(byte x, byte y, byte z, byte w)
{
this.backingVector = new Vector4(x, y, z, w) / MaxBytes;
}
/// <summary>
/// Converts the value of this instance to a hexadecimal string.
/// </summary>
/// <returns>A hexadecimal string representation of the value.</returns>
public string ToHex()
{
// Hex is RRGGBBAA
Vector4 vector = this.backingVector * MaxBytes;
vector += Half;
uint hexOrder = (uint)((byte)vector.W | (byte)vector.Z << 8 | (byte)vector.Y << 16 | (byte)vector.X << 24);
return hexOrder.ToString("X8");
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzBytes(byte[] bytes, int startIndex)
{
Vector4 vector = Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes;
vector += Half;
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToXyzwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes;
vector += Half;
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex + 3] = (byte)vector.W;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxBytes(byte[] bytes, int startIndex)
{
Vector4 vector = Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes;
vector += Half;
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes;
vector += Half;
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
bytes[startIndex + 3] = (byte)vector.W;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.backingVector = vector;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return this.backingVector;
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
return (obj is ColorVector) && this.Equals((ColorVector)obj);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(ColorVector other)
{
return this.backingVector == other.backingVector;
}
/// <summary>
/// Gets a string representation of the packed vector.
/// </summary>
/// <returns>A string representation of the packed vector.</returns>
public override string ToString()
{
return this.ToVector4().ToString();
}
/// <inheritdoc/>
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
}
}
}

286
src/ImageSharp/Colors/NamedColors{TColor}.cs

@ -8,719 +8,719 @@ namespace ImageSharp
using System;
/// <summary>
/// A set of named colors mapped to the provided Color space.
/// A set of named colors mapped to the provided color space.
/// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam>
public static class NamedColors<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F0F8FF.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #F0F8FF.
/// </summary>
public static readonly TColor AliceBlue = ColorBuilder<TColor>.FromRGBA(240, 248, 255, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FAEBD7.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FAEBD7.
/// </summary>
public static readonly TColor AntiqueWhite = ColorBuilder<TColor>.FromRGBA(250, 235, 215, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00FFFF.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #00FFFF.
/// </summary>
public static readonly TColor Aqua = ColorBuilder<TColor>.FromRGBA(0, 255, 255, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #7FFFD4.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #7FFFD4.
/// </summary>
public static readonly TColor Aquamarine = ColorBuilder<TColor>.FromRGBA(127, 255, 212, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F0FFFF.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #F0FFFF.
/// </summary>
public static readonly TColor Azure = ColorBuilder<TColor>.FromRGBA(240, 255, 255, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F5F5DC.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #F5F5DC.
/// </summary>
public static readonly TColor Beige = ColorBuilder<TColor>.FromRGBA(245, 245, 220, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFE4C4.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFE4C4.
/// </summary>
public static readonly TColor Bisque = ColorBuilder<TColor>.FromRGBA(255, 228, 196, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #000000.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #000000.
/// </summary>
public static readonly TColor Black = ColorBuilder<TColor>.FromRGBA(0, 0, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFEBCD.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFEBCD.
/// </summary>
public static readonly TColor BlanchedAlmond = ColorBuilder<TColor>.FromRGBA(255, 235, 205, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #0000FF.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #0000FF.
/// </summary>
public static readonly TColor Blue = ColorBuilder<TColor>.FromRGBA(0, 0, 255, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #8A2BE2.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #8A2BE2.
/// </summary>
public static readonly TColor BlueViolet = ColorBuilder<TColor>.FromRGBA(138, 43, 226, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #A52A2A.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #A52A2A.
/// </summary>
public static readonly TColor Brown = ColorBuilder<TColor>.FromRGBA(165, 42, 42, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DEB887.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #DEB887.
/// </summary>
public static readonly TColor BurlyWood = ColorBuilder<TColor>.FromRGBA(222, 184, 135, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #5F9EA0.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #5F9EA0.
/// </summary>
public static readonly TColor CadetBlue = ColorBuilder<TColor>.FromRGBA(95, 158, 160, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #7FFF00.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #7FFF00.
/// </summary>
public static readonly TColor Chartreuse = ColorBuilder<TColor>.FromRGBA(127, 255, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #D2691E.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #D2691E.
/// </summary>
public static readonly TColor Chocolate = ColorBuilder<TColor>.FromRGBA(210, 105, 30, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF7F50.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FF7F50.
/// </summary>
public static readonly TColor Coral = ColorBuilder<TColor>.FromRGBA(255, 127, 80, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #6495ED.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #6495ED.
/// </summary>
public static readonly TColor CornflowerBlue = ColorBuilder<TColor>.FromRGBA(100, 149, 237, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFF8DC.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFF8DC.
/// </summary>
public static readonly TColor Cornsilk = ColorBuilder<TColor>.FromRGBA(255, 248, 220, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DC143C.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #DC143C.
/// </summary>
public static readonly TColor Crimson = ColorBuilder<TColor>.FromRGBA(220, 20, 60, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00FFFF.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #00FFFF.
/// </summary>
public static readonly TColor Cyan = ColorBuilder<TColor>.FromRGBA(0, 255, 255, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00008B.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #00008B.
/// </summary>
public static readonly TColor DarkBlue = ColorBuilder<TColor>.FromRGBA(0, 0, 139, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #008B8B.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #008B8B.
/// </summary>
public static readonly TColor DarkCyan = ColorBuilder<TColor>.FromRGBA(0, 139, 139, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #B8860B.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #B8860B.
/// </summary>
public static readonly TColor DarkGoldenrod = ColorBuilder<TColor>.FromRGBA(184, 134, 11, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #A9A9A9.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #A9A9A9.
/// </summary>
public static readonly TColor DarkGray = ColorBuilder<TColor>.FromRGBA(169, 169, 169, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #006400.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #006400.
/// </summary>
public static readonly TColor DarkGreen = ColorBuilder<TColor>.FromRGBA(0, 100, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #BDB76B.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #BDB76B.
/// </summary>
public static readonly TColor DarkKhaki = ColorBuilder<TColor>.FromRGBA(189, 183, 107, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #8B008B.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #8B008B.
/// </summary>
public static readonly TColor DarkMagenta = ColorBuilder<TColor>.FromRGBA(139, 0, 139, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #556B2F.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #556B2F.
/// </summary>
public static readonly TColor DarkOliveGreen = ColorBuilder<TColor>.FromRGBA(85, 107, 47, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF8C00.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FF8C00.
/// </summary>
public static readonly TColor DarkOrange = ColorBuilder<TColor>.FromRGBA(255, 140, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #9932CC.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #9932CC.
/// </summary>
public static readonly TColor DarkOrchid = ColorBuilder<TColor>.FromRGBA(153, 50, 204, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #8B0000.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #8B0000.
/// </summary>
public static readonly TColor DarkRed = ColorBuilder<TColor>.FromRGBA(139, 0, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #E9967A.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #E9967A.
/// </summary>
public static readonly TColor DarkSalmon = ColorBuilder<TColor>.FromRGBA(233, 150, 122, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #8FBC8B.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #8FBC8B.
/// </summary>
public static readonly TColor DarkSeaGreen = ColorBuilder<TColor>.FromRGBA(143, 188, 139, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #483D8B.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #483D8B.
/// </summary>
public static readonly TColor DarkSlateBlue = ColorBuilder<TColor>.FromRGBA(72, 61, 139, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #2F4F4F.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #2F4F4F.
/// </summary>
public static readonly TColor DarkSlateGray = ColorBuilder<TColor>.FromRGBA(47, 79, 79, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00CED1.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #00CED1.
/// </summary>
public static readonly TColor DarkTurquoise = ColorBuilder<TColor>.FromRGBA(0, 206, 209, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #9400D3.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #9400D3.
/// </summary>
public static readonly TColor DarkViolet = ColorBuilder<TColor>.FromRGBA(148, 0, 211, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF1493.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FF1493.
/// </summary>
public static readonly TColor DeepPink = ColorBuilder<TColor>.FromRGBA(255, 20, 147, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00BFFF.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #00BFFF.
/// </summary>
public static readonly TColor DeepSkyBlue = ColorBuilder<TColor>.FromRGBA(0, 191, 255, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #696969.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #696969.
/// </summary>
public static readonly TColor DimGray = ColorBuilder<TColor>.FromRGBA(105, 105, 105, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #1E90FF.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #1E90FF.
/// </summary>
public static readonly TColor DodgerBlue = ColorBuilder<TColor>.FromRGBA(30, 144, 255, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #B22222.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #B22222.
/// </summary>
public static readonly TColor Firebrick = ColorBuilder<TColor>.FromRGBA(178, 34, 34, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFAF0.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFFAF0.
/// </summary>
public static readonly TColor FloralWhite = ColorBuilder<TColor>.FromRGBA(255, 250, 240, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #228B22.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #228B22.
/// </summary>
public static readonly TColor ForestGreen = ColorBuilder<TColor>.FromRGBA(34, 139, 34, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF00FF.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FF00FF.
/// </summary>
public static readonly TColor Fuchsia = ColorBuilder<TColor>.FromRGBA(255, 0, 255, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DCDCDC.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #DCDCDC.
/// </summary>
public static readonly TColor Gainsboro = ColorBuilder<TColor>.FromRGBA(220, 220, 220, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F8F8FF.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #F8F8FF.
/// </summary>
public static readonly TColor GhostWhite = ColorBuilder<TColor>.FromRGBA(248, 248, 255, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFD700.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFD700.
/// </summary>
public static readonly TColor Gold = ColorBuilder<TColor>.FromRGBA(255, 215, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DAA520.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #DAA520.
/// </summary>
public static readonly TColor Goldenrod = ColorBuilder<TColor>.FromRGBA(218, 165, 32, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #808080.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #808080.
/// </summary>
public static readonly TColor Gray = ColorBuilder<TColor>.FromRGBA(128, 128, 128, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #008000.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #008000.
/// </summary>
public static readonly TColor Green = ColorBuilder<TColor>.FromRGBA(0, 128, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #ADFF2F.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #ADFF2F.
/// </summary>
public static readonly TColor GreenYellow = ColorBuilder<TColor>.FromRGBA(173, 255, 47, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F0FFF0.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #F0FFF0.
/// </summary>
public static readonly TColor Honeydew = ColorBuilder<TColor>.FromRGBA(240, 255, 240, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF69B4.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FF69B4.
/// </summary>
public static readonly TColor HotPink = ColorBuilder<TColor>.FromRGBA(255, 105, 180, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #CD5C5C.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #CD5C5C.
/// </summary>
public static readonly TColor IndianRed = ColorBuilder<TColor>.FromRGBA(205, 92, 92, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #4B0082.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #4B0082.
/// </summary>
public static readonly TColor Indigo = ColorBuilder<TColor>.FromRGBA(75, 0, 130, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFFF0.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFFFF0.
/// </summary>
public static readonly TColor Ivory = ColorBuilder<TColor>.FromRGBA(255, 255, 240, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F0E68C.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #F0E68C.
/// </summary>
public static readonly TColor Khaki = ColorBuilder<TColor>.FromRGBA(240, 230, 140, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #E6E6FA.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #E6E6FA.
/// </summary>
public static readonly TColor Lavender = ColorBuilder<TColor>.FromRGBA(230, 230, 250, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFF0F5.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFF0F5.
/// </summary>
public static readonly TColor LavenderBlush = ColorBuilder<TColor>.FromRGBA(255, 240, 245, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #7CFC00.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #7CFC00.
/// </summary>
public static readonly TColor LawnGreen = ColorBuilder<TColor>.FromRGBA(124, 252, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFACD.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFFACD.
/// </summary>
public static readonly TColor LemonChiffon = ColorBuilder<TColor>.FromRGBA(255, 250, 205, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #ADD8E6.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #ADD8E6.
/// </summary>
public static readonly TColor LightBlue = ColorBuilder<TColor>.FromRGBA(173, 216, 230, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F08080.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #F08080.
/// </summary>
public static readonly TColor LightCoral = ColorBuilder<TColor>.FromRGBA(240, 128, 128, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #E0FFFF.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #E0FFFF.
/// </summary>
public static readonly TColor LightCyan = ColorBuilder<TColor>.FromRGBA(224, 255, 255, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FAFAD2.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FAFAD2.
/// </summary>
public static readonly TColor LightGoldenrodYellow = ColorBuilder<TColor>.FromRGBA(250, 250, 210, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #D3D3D3.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #D3D3D3.
/// </summary>
public static readonly TColor LightGray = ColorBuilder<TColor>.FromRGBA(211, 211, 211, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #90EE90.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #90EE90.
/// </summary>
public static readonly TColor LightGreen = ColorBuilder<TColor>.FromRGBA(144, 238, 144, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFB6C1.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFB6C1.
/// </summary>
public static readonly TColor LightPink = ColorBuilder<TColor>.FromRGBA(255, 182, 193, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFA07A.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFA07A.
/// </summary>
public static readonly TColor LightSalmon = ColorBuilder<TColor>.FromRGBA(255, 160, 122, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #20B2AA.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #20B2AA.
/// </summary>
public static readonly TColor LightSeaGreen = ColorBuilder<TColor>.FromRGBA(32, 178, 170, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #87CEFA.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #87CEFA.
/// </summary>
public static readonly TColor LightSkyBlue = ColorBuilder<TColor>.FromRGBA(135, 206, 250, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #778899.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #778899.
/// </summary>
public static readonly TColor LightSlateGray = ColorBuilder<TColor>.FromRGBA(119, 136, 153, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #B0C4DE.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #B0C4DE.
/// </summary>
public static readonly TColor LightSteelBlue = ColorBuilder<TColor>.FromRGBA(176, 196, 222, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFFE0.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFFFE0.
/// </summary>
public static readonly TColor LightYellow = ColorBuilder<TColor>.FromRGBA(255, 255, 224, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00FF00.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #00FF00.
/// </summary>
public static readonly TColor Lime = ColorBuilder<TColor>.FromRGBA(0, 255, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #32CD32.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #32CD32.
/// </summary>
public static readonly TColor LimeGreen = ColorBuilder<TColor>.FromRGBA(50, 205, 50, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FAF0E6.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FAF0E6.
/// </summary>
public static readonly TColor Linen = ColorBuilder<TColor>.FromRGBA(250, 240, 230, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF00FF.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FF00FF.
/// </summary>
public static readonly TColor Magenta = ColorBuilder<TColor>.FromRGBA(255, 0, 255, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #800000.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #800000.
/// </summary>
public static readonly TColor Maroon = ColorBuilder<TColor>.FromRGBA(128, 0, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #66CDAA.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #66CDAA.
/// </summary>
public static readonly TColor MediumAquamarine = ColorBuilder<TColor>.FromRGBA(102, 205, 170, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #0000CD.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #0000CD.
/// </summary>
public static readonly TColor MediumBlue = ColorBuilder<TColor>.FromRGBA(0, 0, 205, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #BA55D3.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #BA55D3.
/// </summary>
public static readonly TColor MediumOrchid = ColorBuilder<TColor>.FromRGBA(186, 85, 211, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #9370DB.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #9370DB.
/// </summary>
public static readonly TColor MediumPurple = ColorBuilder<TColor>.FromRGBA(147, 112, 219, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #3CB371.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #3CB371.
/// </summary>
public static readonly TColor MediumSeaGreen = ColorBuilder<TColor>.FromRGBA(60, 179, 113, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #7B68EE.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #7B68EE.
/// </summary>
public static readonly TColor MediumSlateBlue = ColorBuilder<TColor>.FromRGBA(123, 104, 238, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00FA9A.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #00FA9A.
/// </summary>
public static readonly TColor MediumSpringGreen = ColorBuilder<TColor>.FromRGBA(0, 250, 154, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #48D1CC.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #48D1CC.
/// </summary>
public static readonly TColor MediumTurquoise = ColorBuilder<TColor>.FromRGBA(72, 209, 204, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #C71585.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #C71585.
/// </summary>
public static readonly TColor MediumVioletRed = ColorBuilder<TColor>.FromRGBA(199, 21, 133, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #191970.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #191970.
/// </summary>
public static readonly TColor MidnightBlue = ColorBuilder<TColor>.FromRGBA(25, 25, 112, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F5FFFA.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #F5FFFA.
/// </summary>
public static readonly TColor MintCream = ColorBuilder<TColor>.FromRGBA(245, 255, 250, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFE4E1.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFE4E1.
/// </summary>
public static readonly TColor MistyRose = ColorBuilder<TColor>.FromRGBA(255, 228, 225, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFE4B5.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFE4B5.
/// </summary>
public static readonly TColor Moccasin = ColorBuilder<TColor>.FromRGBA(255, 228, 181, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFDEAD.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFDEAD.
/// </summary>
public static readonly TColor NavajoWhite = ColorBuilder<TColor>.FromRGBA(255, 222, 173, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #000080.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #000080.
/// </summary>
public static readonly TColor Navy = ColorBuilder<TColor>.FromRGBA(0, 0, 128, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FDF5E6.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FDF5E6.
/// </summary>
public static readonly TColor OldLace = ColorBuilder<TColor>.FromRGBA(253, 245, 230, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #808000.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #808000.
/// </summary>
public static readonly TColor Olive = ColorBuilder<TColor>.FromRGBA(128, 128, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #6B8E23.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #6B8E23.
/// </summary>
public static readonly TColor OliveDrab = ColorBuilder<TColor>.FromRGBA(107, 142, 35, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFA500.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFA500.
/// </summary>
public static readonly TColor Orange = ColorBuilder<TColor>.FromRGBA(255, 165, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF4500.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FF4500.
/// </summary>
public static readonly TColor OrangeRed = ColorBuilder<TColor>.FromRGBA(255, 69, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DA70D6.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #DA70D6.
/// </summary>
public static readonly TColor Orchid = ColorBuilder<TColor>.FromRGBA(218, 112, 214, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #EEE8AA.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #EEE8AA.
/// </summary>
public static readonly TColor PaleGoldenrod = ColorBuilder<TColor>.FromRGBA(238, 232, 170, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #98FB98.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #98FB98.
/// </summary>
public static readonly TColor PaleGreen = ColorBuilder<TColor>.FromRGBA(152, 251, 152, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #AFEEEE.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #AFEEEE.
/// </summary>
public static readonly TColor PaleTurquoise = ColorBuilder<TColor>.FromRGBA(175, 238, 238, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DB7093.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #DB7093.
/// </summary>
public static readonly TColor PaleVioletRed = ColorBuilder<TColor>.FromRGBA(219, 112, 147, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFEFD5.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFEFD5.
/// </summary>
public static readonly TColor PapayaWhip = ColorBuilder<TColor>.FromRGBA(255, 239, 213, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFDAB9.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFDAB9.
/// </summary>
public static readonly TColor PeachPuff = ColorBuilder<TColor>.FromRGBA(255, 218, 185, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #CD853F.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #CD853F.
/// </summary>
public static readonly TColor Peru = ColorBuilder<TColor>.FromRGBA(205, 133, 63, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFC0CB.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFC0CB.
/// </summary>
public static readonly TColor Pink = ColorBuilder<TColor>.FromRGBA(255, 192, 203, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #DDA0DD.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #DDA0DD.
/// </summary>
public static readonly TColor Plum = ColorBuilder<TColor>.FromRGBA(221, 160, 221, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #B0E0E6.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #B0E0E6.
/// </summary>
public static readonly TColor PowderBlue = ColorBuilder<TColor>.FromRGBA(176, 224, 230, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #800080.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #800080.
/// </summary>
public static readonly TColor Purple = ColorBuilder<TColor>.FromRGBA(128, 0, 128, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #663399.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #663399.
/// </summary>
public static readonly TColor RebeccaPurple = ColorBuilder<TColor>.FromRGBA(102, 51, 153, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF0000.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FF0000.
/// </summary>
public static readonly TColor Red = ColorBuilder<TColor>.FromRGBA(255, 0, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #BC8F8F.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #BC8F8F.
/// </summary>
public static readonly TColor RosyBrown = ColorBuilder<TColor>.FromRGBA(188, 143, 143, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #4169E1.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #4169E1.
/// </summary>
public static readonly TColor RoyalBlue = ColorBuilder<TColor>.FromRGBA(65, 105, 225, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #8B4513.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #8B4513.
/// </summary>
public static readonly TColor SaddleBrown = ColorBuilder<TColor>.FromRGBA(139, 69, 19, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FA8072.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FA8072.
/// </summary>
public static readonly TColor Salmon = ColorBuilder<TColor>.FromRGBA(250, 128, 114, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F4A460.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #F4A460.
/// </summary>
public static readonly TColor SandyBrown = ColorBuilder<TColor>.FromRGBA(244, 164, 96, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #2E8B57.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #2E8B57.
/// </summary>
public static readonly TColor SeaGreen = ColorBuilder<TColor>.FromRGBA(46, 139, 87, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFF5EE.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFF5EE.
/// </summary>
public static readonly TColor SeaShell = ColorBuilder<TColor>.FromRGBA(255, 245, 238, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #A0522D.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #A0522D.
/// </summary>
public static readonly TColor Sienna = ColorBuilder<TColor>.FromRGBA(160, 82, 45, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #C0C0C0.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #C0C0C0.
/// </summary>
public static readonly TColor Silver = ColorBuilder<TColor>.FromRGBA(192, 192, 192, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #87CEEB.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #87CEEB.
/// </summary>
public static readonly TColor SkyBlue = ColorBuilder<TColor>.FromRGBA(135, 206, 235, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #6A5ACD.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #6A5ACD.
/// </summary>
public static readonly TColor SlateBlue = ColorBuilder<TColor>.FromRGBA(106, 90, 205, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #708090.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #708090.
/// </summary>
public static readonly TColor SlateGray = ColorBuilder<TColor>.FromRGBA(112, 128, 144, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFAFA.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFFAFA.
/// </summary>
public static readonly TColor Snow = ColorBuilder<TColor>.FromRGBA(255, 250, 250, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #00FF7F.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #00FF7F.
/// </summary>
public static readonly TColor SpringGreen = ColorBuilder<TColor>.FromRGBA(0, 255, 127, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #4682B4.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #4682B4.
/// </summary>
public static readonly TColor SteelBlue = ColorBuilder<TColor>.FromRGBA(70, 130, 180, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #D2B48C.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #D2B48C.
/// </summary>
public static readonly TColor Tan = ColorBuilder<TColor>.FromRGBA(210, 180, 140, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #008080.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #008080.
/// </summary>
public static readonly TColor Teal = ColorBuilder<TColor>.FromRGBA(0, 128, 128, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #D8BFD8.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #D8BFD8.
/// </summary>
public static readonly TColor Thistle = ColorBuilder<TColor>.FromRGBA(216, 191, 216, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FF6347.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FF6347.
/// </summary>
public static readonly TColor Tomato = ColorBuilder<TColor>.FromRGBA(255, 99, 71, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFFFF.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFFFFF.
/// </summary>
public static readonly TColor Transparent = ColorBuilder<TColor>.FromRGBA(255, 255, 255, 0);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #40E0D0.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #40E0D0.
/// </summary>
public static readonly TColor Turquoise = ColorBuilder<TColor>.FromRGBA(64, 224, 208, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #EE82EE.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #EE82EE.
/// </summary>
public static readonly TColor Violet = ColorBuilder<TColor>.FromRGBA(238, 130, 238, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F5DEB3.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #F5DEB3.
/// </summary>
public static readonly TColor Wheat = ColorBuilder<TColor>.FromRGBA(245, 222, 179, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFFFF.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFFFFF.
/// </summary>
public static readonly TColor White = ColorBuilder<TColor>.FromRGBA(255, 255, 255, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #F5F5F5.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #F5F5F5.
/// </summary>
public static readonly TColor WhiteSmoke = ColorBuilder<TColor>.FromRGBA(245, 245, 245, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #FFFF00.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #FFFF00.
/// </summary>
public static readonly TColor Yellow = ColorBuilder<TColor>.FromRGBA(255, 255, 0, 255);
/// <summary>
/// Represents a <see cref="Color"/> matching the W3C definition that has an hex value of #9ACD32.
/// Represents a <see paramref="TColor"/> matching the W3C definition that has an hex value of #9ACD32.
/// </summary>
public static readonly TColor YellowGreen = ColorBuilder<TColor>.FromRGBA(154, 205, 50, 255);
}

46
src/ImageSharp/Colors/PackedPixel/Argb.cs → src/ImageSharp/Colors/PackedPixel/Argb32.cs

@ -1,4 +1,4 @@
// <copyright file="Argb.cs" company="James Jackson-South">
// <copyright file="Argb32.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -17,7 +17,7 @@ namespace ImageSharp
/// 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>
public struct Argb : IPixel<Argb>, IPackedVector<uint>
public struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
{
/// <summary>
/// The shift count for the blue component
@ -50,58 +50,58 @@ namespace ImageSharp
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary>
/// Initializes a new instance of the <see cref="Argb"/> struct.
/// Initializes a new instance of the <see cref="Argb32"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
public Argb(byte r, byte g, byte b, byte a = 255)
public Argb32(byte r, byte g, byte b, byte a = 255)
{
this.PackedValue = Pack(r, g, b, a);
}
/// <summary>
/// Initializes a new instance of the <see cref="Argb"/> struct.
/// Initializes a new instance of the <see cref="Argb32"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
public Argb(float r, float g, float b, float a = 1)
public Argb32(float r, float g, float b, float a = 1)
{
this.PackedValue = Pack(r, g, b, a);
}
/// <summary>
/// Initializes a new instance of the <see cref="Argb"/> struct.
/// Initializes a new instance of the <see cref="Argb32"/> struct.
/// </summary>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
public Argb(Vector3 vector)
public Argb32(Vector3 vector)
{
this.PackedValue = Pack(ref vector);
}
/// <summary>
/// Initializes a new instance of the <see cref="Argb"/> struct.
/// Initializes a new instance of the <see cref="Argb32"/> struct.
/// </summary>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
public Argb(Vector4 vector)
public Argb32(Vector4 vector)
{
this.PackedValue = Pack(ref vector);
}
/// <summary>
/// Initializes a new instance of the <see cref="Argb"/> struct.
/// Initializes a new instance of the <see cref="Argb32"/> struct.
/// </summary>
/// <param name="packed">
/// The packed value.
/// </param>
public Argb(uint packed = 0)
public Argb32(uint packed = 0)
{
this.PackedValue = packed;
}
@ -182,33 +182,33 @@ namespace ImageSharp
}
/// <summary>
/// Compares two <see cref="Argb"/> objects for equality.
/// Compares two <see cref="Argb32"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Argb"/> on the left side of the operand.
/// The <see cref="Argb32"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Argb"/> on the right side of the operand.
/// The <see cref="Argb32"/> on the right side of the operand.
/// </param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Argb left, Argb right)
public static bool operator ==(Argb32 left, Argb32 right)
{
return left.PackedValue == right.PackedValue;
}
/// <summary>
/// Compares two <see cref="Argb"/> objects for equality.
/// Compares two <see cref="Argb32"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Argb"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Argb"/> on the right side of the operand.</param>
/// <param name="left">The <see cref="Argb32"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Argb32"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Argb left, Argb right)
public static bool operator !=(Argb32 left, Argb32 right)
{
return left.PackedValue != right.PackedValue;
}
@ -221,7 +221,7 @@ namespace ImageSharp
}
/// <inheritdoc />
public BulkPixelOperations<Argb> CreateBulkOperations() => new BulkPixelOperations<Argb>();
public BulkPixelOperations<Argb32> CreateBulkOperations() => new BulkPixelOperations<Argb32>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -278,12 +278,12 @@ namespace ImageSharp
/// <inheritdoc/>
public override bool Equals(object obj)
{
return obj is Argb && this.Equals((Argb)obj);
return obj is Argb32 && this.Equals((Argb32)obj);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Argb other)
public bool Equals(Argb32 other)
{
return this.PackedValue == other.PackedValue;
}

172
src/ImageSharp/Colors/PackedPixel/BulkPixelOperations{TColor}.cs

@ -13,14 +13,9 @@ namespace ImageSharp
/// for pixel buffers of type <typeparamref name="TColor"/>.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
public unsafe class BulkPixelOperations<TColor>
public class BulkPixelOperations<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// The size of <typeparamref name="TColor"/> in bytes
/// </summary>
private static readonly int ColorSize = Unsafe.SizeOf<TColor>();
/// <summary>
/// Gets the global <see cref="BulkPixelOperations{TColor}"/> instance for the pixel type <typeparamref name="TColor"/>
/// </summary>
@ -32,23 +27,16 @@ namespace ImageSharp
/// <param name="sourceVectors">The <see cref="BufferSpan{T}"/> to the source vectors.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromVector4(
BufferSpan<Vector4> sourceVectors,
BufferSpan<TColor> destColors,
int count)
internal virtual void PackFromVector4(BufferSpan<Vector4> sourceVectors, BufferSpan<TColor> destColors, int count)
{
Vector4* sp = (Vector4*)sourceVectors.PointerAtOffset;
byte* dp = (byte*)destColors;
ref Vector4 sourceRef = ref sourceVectors.DangerousGetPinnableReference();
ref TColor destRef = ref destColors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++)
{
Vector4 v = Unsafe.Read<Vector4>(sp);
TColor c = default(TColor);
c.PackFromVector4(v);
Unsafe.Write(dp, c);
sp++;
dp += ColorSize;
ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i);
ref TColor dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromVector4(sp);
}
}
@ -58,20 +46,16 @@ namespace ImageSharp
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destVectors">The <see cref="BufferSpan{T}"/> to the destination vectors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToVector4(
BufferSpan<TColor> sourceColors,
BufferSpan<Vector4> destVectors,
int count)
internal virtual void ToVector4(BufferSpan<TColor> sourceColors, BufferSpan<Vector4> destVectors, int count)
{
byte* sp = (byte*)sourceColors;
Vector4* dp = (Vector4*)destVectors.PointerAtOffset;
ref TColor sourceRef = ref sourceColors.DangerousGetPinnableReference();
ref Vector4 destRef = ref destVectors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++)
{
TColor c = Unsafe.Read<TColor>(sp);
*dp = c.ToVector4();
sp += ColorSize;
dp++;
ref TColor sp = ref Unsafe.Add(ref sourceRef, i);
ref Vector4 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToVector4();
}
}
@ -81,21 +65,20 @@ namespace ImageSharp
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromXyzBytes(
BufferSpan<byte> sourceBytes,
BufferSpan<TColor> destColors,
int count)
internal virtual void PackFromXyzBytes(BufferSpan<byte> sourceBytes, BufferSpan<TColor> destColors, int count)
{
byte* sp = (byte*)sourceBytes;
byte* dp = (byte*)destColors.PointerAtOffset;
ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
ref TColor destRef = ref destColors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++)
{
TColor c = default(TColor);
c.PackFromBytes(sp[0], sp[1], sp[2], 255);
Unsafe.Write(dp, c);
sp += 3;
dp += ColorSize;
int i3 = i * 3;
ref TColor dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBytes(
Unsafe.Add(ref sourceRef, i3),
Unsafe.Add(ref sourceRef, i3 + 1),
Unsafe.Add(ref sourceRef, i3 + 2),
255);
}
}
@ -107,14 +90,13 @@ namespace ImageSharp
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToXyzBytes(BufferSpan<TColor> sourceColors, BufferSpan<byte> destBytes, int count)
{
byte* sp = (byte*)sourceColors;
ref TColor sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte[] dest = destBytes.Array;
for (int i = destBytes.Start; i < destBytes.Start + (count * 3); i += 3)
for (int i = 0; i < count; i++)
{
TColor c = Unsafe.Read<TColor>(sp);
c.ToXyzBytes(dest, i);
sp += ColorSize;
ref TColor sp = ref Unsafe.Add(ref sourceRef, i);
sp.ToXyzBytes(dest, destBytes.Start + (i * 3));
}
}
@ -124,21 +106,20 @@ namespace ImageSharp
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromXyzwBytes(
BufferSpan<byte> sourceBytes,
BufferSpan<TColor> destColors,
int count)
internal virtual void PackFromXyzwBytes(BufferSpan<byte> sourceBytes, BufferSpan<TColor> destColors, int count)
{
byte* sp = (byte*)sourceBytes;
byte* dp = (byte*)destColors.PointerAtOffset;
ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
ref TColor destRef = ref destColors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++)
{
TColor c = default(TColor);
c.PackFromBytes(sp[0], sp[1], sp[2], sp[3]);
Unsafe.Write(dp, c);
sp += 4;
dp += ColorSize;
int i4 = i * 4;
ref TColor dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBytes(
Unsafe.Add(ref sourceRef, i4),
Unsafe.Add(ref sourceRef, i4 + 1),
Unsafe.Add(ref sourceRef, i4 + 2),
Unsafe.Add(ref sourceRef, i4 + 3));
}
}
@ -148,19 +129,15 @@ namespace ImageSharp
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="BufferSpan{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToXyzwBytes(
BufferSpan<TColor> sourceColors,
BufferSpan<byte> destBytes,
int count)
internal virtual void ToXyzwBytes(BufferSpan<TColor> sourceColors, BufferSpan<byte> destBytes, int count)
{
byte* sp = (byte*)sourceColors;
ref TColor sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte[] dest = destBytes.Array;
for (int i = destBytes.Start; i < destBytes.Start + (count * 4); i += 4)
for (int i = 0; i < count; i++)
{
TColor c = Unsafe.Read<TColor>(sp);
c.ToXyzwBytes(dest, i);
sp += ColorSize;
ref TColor sp = ref Unsafe.Add(ref sourceRef, i);
sp.ToXyzwBytes(dest, destBytes.Start + (i * 4));
}
}
@ -170,21 +147,20 @@ namespace ImageSharp
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromZyxBytes(
BufferSpan<byte> sourceBytes,
BufferSpan<TColor> destColors,
int count)
internal virtual void PackFromZyxBytes(BufferSpan<byte> sourceBytes, BufferSpan<TColor> destColors, int count)
{
byte* sp = (byte*)sourceBytes;
byte* dp = (byte*)destColors.PointerAtOffset;
ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
ref TColor destRef = ref destColors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++)
{
TColor c = default(TColor);
c.PackFromBytes(sp[2], sp[1], sp[0], 255);
Unsafe.Write(dp, c);
sp += 3;
dp += ColorSize;
int i3 = i * 3;
ref TColor dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBytes(
Unsafe.Add(ref sourceRef, i3 + 2),
Unsafe.Add(ref sourceRef, i3 + 1),
Unsafe.Add(ref sourceRef, i3),
255);
}
}
@ -196,14 +172,13 @@ namespace ImageSharp
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToZyxBytes(BufferSpan<TColor> sourceColors, BufferSpan<byte> destBytes, int count)
{
byte* sp = (byte*)sourceColors;
ref TColor sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte[] dest = destBytes.Array;
for (int i = destBytes.Start; i < destBytes.Start + (count * 3); i += 3)
for (int i = 0; i < count; i++)
{
TColor c = Unsafe.Read<TColor>(sp);
c.ToZyxBytes(dest, i);
sp += ColorSize;
ref TColor sp = ref Unsafe.Add(ref sourceRef, i);
sp.ToZyxBytes(dest, destBytes.Start + (i * 3));
}
}
@ -213,21 +188,20 @@ namespace ImageSharp
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param>
/// <param name="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromZyxwBytes(
BufferSpan<byte> sourceBytes,
BufferSpan<TColor> destColors,
int count)
internal virtual void PackFromZyxwBytes(BufferSpan<byte> sourceBytes, BufferSpan<TColor> destColors, int count)
{
byte* sp = (byte*)sourceBytes;
byte* dp = (byte*)destColors.PointerAtOffset;
ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
ref TColor destRef = ref destColors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++)
{
TColor c = default(TColor);
c.PackFromBytes(sp[2], sp[1], sp[0], sp[3]);
Unsafe.Write(dp, c);
sp += 4;
dp += ColorSize;
int i4 = i * 4;
ref TColor dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBytes(
Unsafe.Add(ref sourceRef, i4 + 2),
Unsafe.Add(ref sourceRef, i4 + 1),
Unsafe.Add(ref sourceRef, i4),
Unsafe.Add(ref sourceRef, i4 + 3));
}
}
@ -237,19 +211,15 @@ namespace ImageSharp
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param>
/// <param name="destBytes">The <see cref="BufferSpan{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToZyxwBytes(
BufferSpan<TColor> sourceColors,
BufferSpan<byte> destBytes,
int count)
internal virtual void ToZyxwBytes(BufferSpan<TColor> sourceColors, BufferSpan<byte> destBytes, int count)
{
byte* sp = (byte*)sourceColors;
ref TColor sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte[] dest = destBytes.Array;
for (int i = destBytes.Start; i < destBytes.Start + (count * 4); i += 4)
for (int i = 0; i < count; i++)
{
TColor c = Unsafe.Read<TColor>(sp);
c.ToZyxwBytes(dest, i);
sp += ColorSize;
ref TColor sp = ref Unsafe.Add(ref sourceRef, i);
sp.ToZyxwBytes(dest, destBytes.Start + (i * 4));
}
}
}

2
src/ImageSharp/Colors/PackedPixel/PackedPixelConverterHelper.cs

@ -300,7 +300,7 @@ namespace ImageSharp
private static bool IsStandardNormalizedType(Type type)
{
return type == typeof(Color)
|| type == typeof(Argb)
|| type == typeof(Argb32)
|| type == typeof(Alpha8)
|| type == typeof(Bgr565)
|| type == typeof(Bgra4444)

99
src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs → src/ImageSharp/Common/Memory/Buffer.cs

@ -1,4 +1,4 @@
// <copyright file="PinnedBuffer{T}.cs" company="James Jackson-South">
// <copyright file="Buffer{T}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -11,13 +11,18 @@ namespace ImageSharp
using System.Runtime.InteropServices;
/// <summary>
/// Manages a pinned buffer of value type objects as a Disposable resource.
/// Manages a buffer of value type objects as a Disposable resource.
/// The backing array is either pooled or comes from the outside.
/// </summary>
/// <typeparam name="T">The value type.</typeparam>
internal class PinnedBuffer<T> : IDisposable
internal class Buffer<T> : IDisposable
where T : struct
{
/// <summary>
/// A pointer to the first element of <see cref="Array"/> when pinned.
/// </summary>
private IntPtr pointer;
/// <summary>
/// A handle that allows to access the managed <see cref="Array"/> as an unmanaged memory by pinning.
/// </summary>
@ -25,40 +30,38 @@ namespace ImageSharp
/// <summary>
/// A value indicating wheter <see cref="Array"/> should be returned to <see cref="PixelDataPool{T}"/>
/// when disposing this <see cref="PinnedBuffer{T}"/> instance.
/// when disposing this <see cref="Buffer{T}"/> instance.
/// </summary>
private bool isPoolingOwner;
/// <summary>
/// Initializes a new instance of the <see cref="PinnedBuffer{T}"/> class.
/// Initializes a new instance of the <see cref="Buffer{T}"/> class.
/// </summary>
/// <param name="length">The desired count of elements. (Minimum size for <see cref="Array"/>)</param>
public PinnedBuffer(int length)
public Buffer(int length)
{
this.Length = length;
this.Array = PixelDataPool<T>.Rent(length);
this.isPoolingOwner = true;
this.Pin();
}
/// <summary>
/// Initializes a new instance of the <see cref="PinnedBuffer{T}"/> class.
/// Initializes a new instance of the <see cref="Buffer{T}"/> class.
/// </summary>
/// <param name="array">The array to pin.</param>
public PinnedBuffer(T[] array)
public Buffer(T[] array)
{
this.Length = array.Length;
this.Array = array;
this.isPoolingOwner = false;
this.Pin();
}
/// <summary>
/// Initializes a new instance of the <see cref="PinnedBuffer{T}"/> class.
/// Initializes a new instance of the <see cref="Buffer{T}"/> class.
/// </summary>
/// <param name="array">The array to pin.</param>
/// <param name="length">The count of "relevant" elements in 'array'.</param>
public PinnedBuffer(T[] array, int length)
public Buffer(T[] array, int length)
{
if (array.Length < length)
{
@ -68,19 +71,18 @@ namespace ImageSharp
this.Length = length;
this.Array = array;
this.isPoolingOwner = false;
this.Pin();
}
/// <summary>
/// Finalizes an instance of the <see cref="PinnedBuffer{T}"/> class.
/// Finalizes an instance of the <see cref="Buffer{T}"/> class.
/// </summary>
~PinnedBuffer()
~Buffer()
{
this.UnPin();
}
/// <summary>
/// Gets a value indicating whether this <see cref="PinnedBuffer{T}"/> instance is disposed, or has lost ownership of <see cref="Array"/>.
/// Gets a value indicating whether this <see cref="Buffer{T}"/> instance is disposed, or has lost ownership of <see cref="Array"/>.
/// </summary>
public bool IsDisposedOrLostArrayOwnership { get; private set; }
@ -94,11 +96,6 @@ namespace ImageSharp
/// </summary>
public T[] Array { get; private set; }
/// <summary>
/// Gets a pointer to the pinned <see cref="Array"/>.
/// </summary>
public IntPtr Pointer { get; private set; }
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the backing buffer.
/// </summary>
@ -109,37 +106,35 @@ namespace ImageSharp
/// </summary>
/// <param name="index">The index</param>
/// <returns>The reference to the specified element</returns>
public unsafe ref T this[int index]
public ref T this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
DebugGuard.MustBeLessThan(index, this.Length, nameof(index));
byte* ptr = (byte*)this.Pointer + BufferSpan.SizeOf<T>(index);
return ref Unsafe.AsRef<T>(ptr);
return ref this.Array[index];
}
}
/// <summary>
/// Converts <see cref="PinnedBuffer{T}"/> to an <see cref="BufferSpan{T}"/>.
/// Converts <see cref="Buffer{T}"/> to an <see cref="BufferSpan{T}"/>.
/// </summary>
/// <param name="buffer">The <see cref="PinnedBuffer{T}"/> to convert.</param>
/// <param name="buffer">The <see cref="Buffer{T}"/> to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe implicit operator BufferSpan<T>(PinnedBuffer<T> buffer)
public static implicit operator BufferSpan<T>(Buffer<T> buffer)
{
return new BufferSpan<T>(buffer.Array, (void*)buffer.Pointer, 0, buffer.Length);
return new BufferSpan<T>(buffer.Array, 0, buffer.Length);
}
/// <summary>
/// Creates a clean instance of <see cref="PinnedBuffer{T}"/> initializing it's elements with 'default(T)'.
/// Creates a clean instance of <see cref="Buffer{T}"/> initializing it's elements with 'default(T)'.
/// </summary>
/// <param name="count">The desired count of elements. (Minimum size for <see cref="Array"/>)</param>
/// <returns>The <see cref="PinnedBuffer{T}"/> instance</returns>
/// <returns>The <see cref="Buffer{T}"/> instance</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PinnedBuffer<T> CreateClean(int count)
public static Buffer<T> CreateClean(int count)
{
PinnedBuffer<T> buffer = new PinnedBuffer<T>(count);
Buffer<T> buffer = new Buffer<T>(count);
buffer.Clear();
return buffer;
}
@ -150,9 +145,9 @@ namespace ImageSharp
/// <param name="start">The start</param>
/// <returns>The <see cref="BufferSpan{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe BufferSpan<T> Slice(int start)
public BufferSpan<T> Slice(int start)
{
return new BufferSpan<T>(this.Array, (void*)this.Pointer, start, this.Length - start);
return new BufferSpan<T>(this.Array, start, this.Length - start);
}
/// <summary>
@ -162,13 +157,13 @@ namespace ImageSharp
/// <param name="length">The length of the slice</param>
/// <returns>The <see cref="BufferSpan{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe BufferSpan<T> Slice(int start, int length)
public BufferSpan<T> Slice(int start, int length)
{
return new BufferSpan<T>(this.Array, (void*)this.Pointer, start, length);
return new BufferSpan<T>(this.Array, start, length);
}
/// <summary>
/// Disposes the <see cref="PinnedBuffer{T}"/> instance by unpinning the array, and returning the pooled buffer when necessary.
/// Disposes the <see cref="Buffer{T}"/> instance by unpinning the array, and returning the pooled buffer when necessary.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
@ -199,11 +194,11 @@ namespace ImageSharp
/// </summary>
/// <returns>The unpinned <see cref="Array"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T[] UnPinAndTakeArrayOwnership()
public T[] TakeArrayOwnership()
{
if (this.IsDisposedOrLostArrayOwnership)
{
throw new InvalidOperationException("UnPinAndTakeArrayOwnership() is invalid: either PinnedBuffer<T> is disposed or UnPinAndTakeArrayOwnership() has been called multiple times!");
throw new InvalidOperationException("TakeArrayOwnership() is invalid: either Buffer<T> is disposed or TakeArrayOwnership() has been called multiple times!");
}
this.IsDisposedOrLostArrayOwnership = true;
@ -220,17 +215,29 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear()
{
((BufferSpan<T>)this).Clear();
this.Span.Clear();
}
/// <summary>
/// Pins <see cref="Array"/>.
/// </summary>
/// <returns>The pinned pointer</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Pin()
public IntPtr Pin()
{
this.handle = GCHandle.Alloc(this.Array, GCHandleType.Pinned);
this.Pointer = this.handle.AddrOfPinnedObject();
if (this.IsDisposedOrLostArrayOwnership)
{
throw new InvalidOperationException(
"Pin() is invalid on a buffer with IsDisposedOrLostArrayOwnership == true!");
}
if (this.pointer == IntPtr.Zero)
{
this.handle = GCHandle.Alloc(this.Array, GCHandleType.Pinned);
this.pointer = this.handle.AddrOfPinnedObject();
}
return this.pointer;
}
/// <summary>
@ -239,13 +246,13 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UnPin()
{
if (this.Pointer == IntPtr.Zero || !this.handle.IsAllocated)
if (this.pointer == IntPtr.Zero || !this.handle.IsAllocated)
{
return;
}
this.handle.Free();
this.Pointer = IntPtr.Zero;
this.pointer = IntPtr.Zero;
}
}
}

22
src/ImageSharp/Common/Memory/PinnedImageBuffer{T}.cs → src/ImageSharp/Common/Memory/Buffer2D.cs

@ -1,4 +1,4 @@
// <copyright file="PinnedImageBuffer{T}.cs" company="James Jackson-South">
// <copyright file="Buffer2D{T}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -9,19 +9,19 @@ namespace ImageSharp
using System.Runtime.CompilerServices;
/// <summary>
/// Represents a pinned buffer of value type objects
/// Represents a buffer of value type objects
/// interpreted as a 2D region of <see cref="Width"/> x <see cref="Height"/> elements.
/// </summary>
/// <typeparam name="T">The value type.</typeparam>
internal class PinnedImageBuffer<T> : PinnedBuffer<T>, IPinnedImageBuffer<T>
internal class Buffer2D<T> : Buffer<T>, IBuffer2D<T>
where T : struct
{
/// <summary>
/// Initializes a new instance of the <see cref="PinnedImageBuffer{T}"/> class.
/// Initializes a new instance of the <see cref="Buffer2D{T}"/> class.
/// </summary>
/// <param name="width">The number of elements in a row</param>
/// <param name="height">The number of rows</param>
public PinnedImageBuffer(int width, int height)
public Buffer2D(int width, int height)
: base(width * height)
{
this.Width = width;
@ -29,12 +29,12 @@ namespace ImageSharp
}
/// <summary>
/// Initializes a new instance of the <see cref="PinnedImageBuffer{T}"/> class.
/// Initializes a new instance of the <see cref="Buffer2D{T}"/> class.
/// </summary>
/// <param name="array">The array to pin</param>
/// <param name="width">The number of elements in a row</param>
/// <param name="height">The number of rows</param>
public PinnedImageBuffer(T[] array, int width, int height)
public Buffer2D(T[] array, int width, int height)
: base(array, width * height)
{
this.Width = width;
@ -63,14 +63,14 @@ namespace ImageSharp
}
/// <summary>
/// Creates a clean instance of <see cref="PinnedImageBuffer{T}"/> initializing it's elements with 'default(T)'.
/// Creates a clean instance of <see cref="Buffer2D{T}"/> initializing it's elements with 'default(T)'.
/// </summary>
/// <param name="width">The number of elements in a row</param>
/// <param name="height">The number of rows</param>
/// <returns>The <see cref="PinnedBuffer{T}"/> instance</returns>
public static PinnedImageBuffer<T> CreateClean(int width, int height)
/// <returns>The <see cref="Buffer{T}"/> instance</returns>
public static Buffer2D<T> CreateClean(int width, int height)
{
PinnedImageBuffer<T> buffer = new PinnedImageBuffer<T>(width, height);
Buffer2D<T> buffer = new Buffer2D<T>(width, height);
buffer.Clear();
return buffer;
}

10
src/ImageSharp/Common/Memory/PinnedImageBufferExtensions.cs → src/ImageSharp/Common/Memory/Buffer2DExtensions.cs

@ -1,4 +1,4 @@
// <copyright file="PinnedImageBufferExtensions{T}.cs" company="James Jackson-South">
// <copyright file="Buffer2DExtensions{T}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -9,9 +9,9 @@ namespace ImageSharp
using System.Runtime.CompilerServices;
/// <summary>
/// Defines extension methods for <see cref="IPinnedImageBuffer{T}"/>.
/// Defines extension methods for <see cref="IBuffer2D{T}"/>.
/// </summary>
internal static class PinnedImageBufferExtensions
internal static class Buffer2DExtensions
{
/// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the row 'y' beginning from the pixel at 'x'.
@ -22,7 +22,7 @@ namespace ImageSharp
/// <typeparam name="T">The element type</typeparam>
/// <returns>The <see cref="BufferSpan{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static BufferSpan<T> GetRowSpan<T>(this IPinnedImageBuffer<T> buffer, int x, int y)
public static BufferSpan<T> GetRowSpan<T>(this IBuffer2D<T> buffer, int x, int y)
where T : struct
{
return buffer.Span.Slice((y * buffer.Width) + x, buffer.Width - x);
@ -36,7 +36,7 @@ namespace ImageSharp
/// <typeparam name="T">The element type</typeparam>
/// <returns>The <see cref="BufferSpan{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static BufferSpan<T> GetRowSpan<T>(this IPinnedImageBuffer<T> buffer, int y)
public static BufferSpan<T> GetRowSpan<T>(this IBuffer2D<T> buffer, int y)
where T : struct
{
return buffer.Span.Slice(y * buffer.Width, buffer.Width);

96
src/ImageSharp/Common/Memory/BufferSpan.cs

@ -6,7 +6,6 @@
namespace ImageSharp
{
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -15,60 +14,49 @@ namespace ImageSharp
/// </summary>
internal static class BufferSpan
{
/// <summary>
/// It's worth to use Marshal.Copy() or Buffer.BlockCopy() over this size.
/// </summary>
private const int ByteCountThreshold = 1024;
/// <summary>
/// Copy 'count' number of elements of the same type from 'source' to 'dest'
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="source">The input <see cref="BufferSpan{T}"/></param>
/// <param name="source">The <see cref="BufferSpan{T}"/> to copy elements from.</param>
/// <param name="destination">The destination <see cref="BufferSpan{T}"/>.</param>
/// <param name="count">The number of elements to copy</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Copy<T>(BufferSpan<T> source, BufferSpan<T> destination, int count)
public static unsafe void Copy<T>(BufferSpan<T> source, BufferSpan<T> destination, int count)
where T : struct
{
CopyImpl(source, destination, count);
}
DebugGuard.MustBeLessThanOrEqualTo(count, source.Length, nameof(count));
DebugGuard.MustBeLessThanOrEqualTo(count, destination.Length, nameof(count));
/// <summary>
/// Copy 'countInSource' elements of <typeparamref name="T"/> from 'source' into the raw byte buffer 'destination'.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="source">The source buffer of <typeparamref name="T"/> elements to copy from.</param>
/// <param name="destination">The destination buffer.</param>
/// <param name="countInSource">The number of elements to copy from 'source'</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Copy<T>(BufferSpan<T> source, BufferSpan<byte> destination, int countInSource)
where T : struct
{
CopyImpl(source, destination, countInSource);
ref byte srcRef = ref Unsafe.As<T, byte>(ref source.DangerousGetPinnableReference());
ref byte destRef = ref Unsafe.As<T, byte>(ref destination.DangerousGetPinnableReference());
int byteCount = Unsafe.SizeOf<T>() * count;
// TODO: Use unfixed Unsafe.CopyBlock(ref T, ref T, int) for small blocks, when it gets available!
fixed (byte* pSrc = &srcRef)
fixed (byte* pDest = &destRef)
{
#if NETSTANDARD1_1
Unsafe.CopyBlock(pDest, pSrc, (uint)byteCount);
#else
int destLength = destination.Length * Unsafe.SizeOf<T>();
Buffer.MemoryCopy(pSrc, pDest, destLength, byteCount);
#endif
}
}
/// <summary>
/// Copy 'countInDest' number of <typeparamref name="T"/> elements into 'dest' from a raw byte buffer defined by 'source'.
/// Copy all elements of 'source' into 'destination'.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="source">The raw source buffer to copy from"/></param>
/// <param name="destination">The destination buffer"/></param>
/// <param name="countInDest">The number of <typeparamref name="T"/> elements to copy.</param>
/// <param name="source">The <see cref="BufferSpan{T}"/> to copy elements from.</param>
/// <param name="destination">The destination <see cref="BufferSpan{T}"/>.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void Copy<T>(BufferSpan<byte> source, BufferSpan<T> destination, int countInDest)
public static void Copy<T>(BufferSpan<T> source, BufferSpan<T> destination)
where T : struct
{
int byteCount = SizeOf<T>(countInDest);
if (byteCount > (int)ByteCountThreshold)
{
Marshal.Copy(source.Array, source.Start, destination.PointerAtOffset, byteCount);
}
else
{
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, (uint)byteCount);
}
Copy(source, destination, source.Length);
}
/// <summary>
@ -91,39 +79,5 @@ namespace ImageSharp
public static uint USizeOf<T>(int count)
where T : struct
=> (uint)SizeOf<T>(count);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void CopyImpl<T, TDest>(BufferSpan<T> source, BufferSpan<TDest> destination, int count)
where T : struct
where TDest : struct
{
int byteCount = SizeOf<T>(count);
if (byteCount > ByteCountThreshold)
{
if (Unsafe.SizeOf<T>() == sizeof(long))
{
Marshal.Copy(Unsafe.As<long[]>(source.Array), source.Start, destination.PointerAtOffset, count);
return;
}
else if (Unsafe.SizeOf<T>() == sizeof(int))
{
Marshal.Copy(Unsafe.As<int[]>(source.Array), source.Start, destination.PointerAtOffset, count);
return;
}
else if (Unsafe.SizeOf<T>() == sizeof(short))
{
Marshal.Copy(Unsafe.As<short[]>(source.Array), source.Start, destination.PointerAtOffset, count);
return;
}
else if (Unsafe.SizeOf<T>() == sizeof(byte))
{
Marshal.Copy(Unsafe.As<byte[]>(source.Array), source.Start, destination.PointerAtOffset, count);
return;
}
}
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, (uint)byteCount);
}
}
}

88
src/ImageSharp/Common/Memory/BufferSpan{T}.cs

@ -12,7 +12,7 @@ namespace ImageSharp
/// <summary>
/// Represents a contiguous region of a pinned managed array.
/// The array is usually owned by a <see cref="PinnedBuffer{T}"/> instance.
/// The array is usually owned by a <see cref="Buffer{T}"/> instance.
/// </summary>
/// <remarks>
/// <see cref="BufferSpan{T}"/> is very similar to corefx System.Span&lt;T&gt;, and we try to maintain a compatible API.
@ -30,13 +30,12 @@ namespace ImageSharp
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array and an start.
/// </summary>
/// <param name="array">The pinned array</param>
/// <param name="pointerToArray">Pointer to the beginning of the array</param>
/// <param name="start">The index at which to begin the span.</param>
/// <param name="length">The length</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan(T[] array, void* pointerToArray, int start, int length)
public BufferSpan(T[] array, int start, int length)
{
GuardArrayAndPointer(array, pointerToArray);
GuardArray(array);
DebugGuard.MustBeLessThanOrEqualTo(start, array.Length, nameof(start));
DebugGuard.MustBeLessThanOrEqualTo(length, array.Length - start, nameof(length));
@ -44,45 +43,40 @@ namespace ImageSharp
this.Array = array;
this.Length = length;
this.Start = start;
this.PointerAtOffset = (IntPtr)pointerToArray + (Unsafe.SizeOf<T>() * start);
}
/// <summary>
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array and an start.
/// </summary>
/// <param name="array">The pinned array</param>
/// <param name="pointerToArray">Pointer to the beginning of the array</param>
/// <param name="start">The index at which to begin the span.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan(T[] array, void* pointerToArray, int start)
public BufferSpan(T[] array, int start)
{
GuardArrayAndPointer(array, pointerToArray);
GuardArray(array);
DebugGuard.MustBeLessThanOrEqualTo(start, array.Length, nameof(start));
this.Array = array;
this.Length = array.Length - start;
this.Start = start;
this.PointerAtOffset = (IntPtr)pointerToArray + (Unsafe.SizeOf<T>() * start);
}
/// <summary>
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array.
/// </summary>
/// <param name="array">The pinned array</param>
/// <param name="pointerToArray">Pointer to the start of 'array'</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan(T[] array, void* pointerToArray)
public BufferSpan(T[] array)
{
GuardArrayAndPointer(array, pointerToArray);
GuardArray(array);
this.Array = array;
this.Start = 0;
this.Length = array.Length;
this.PointerAtOffset = (IntPtr)pointerToArray;
}
/// <summary>
/// Gets the backing array
/// Gets the backing array.
/// </summary>
public T[] Array { get; private set; }
@ -101,11 +95,6 @@ namespace ImageSharp
/// </summary>
public int ByteOffset => this.Start * Unsafe.SizeOf<T>();
/// <summary>
/// Gets the pointer to the offseted array position
/// </summary>
public IntPtr PointerAtOffset { get; private set; }
/// <summary>
/// Returns a reference to specified element of the span.
/// </summary>
@ -117,45 +106,36 @@ namespace ImageSharp
get
{
DebugGuard.MustBeLessThan(index, this.Length, nameof(index));
byte* ptr = (byte*)this.PointerAtOffset + BufferSpan.SizeOf<T>(index);
return ref Unsafe.AsRef<T>(ptr);
ref T startRef = ref this.DangerousGetPinnableReference();
return ref Unsafe.Add(ref startRef, index);
}
}
/// <summary>
/// Convertes <see cref="BufferSpan{T}"/> instance to a raw 'void*' pointer
/// </summary>
/// <param name="bufferSpan">The <see cref="BufferSpan{T}"/> to convert</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator void*(BufferSpan<T> bufferSpan)
{
return (void*)bufferSpan.PointerAtOffset;
}
/// <summary>
/// Converts <see cref="BufferSpan{T}"/> instance to a raw 'byte*' pointer
/// Converts generic <see cref="BufferSpan{T}"/> to a <see cref="BufferSpan{T}"/> of bytes
/// setting it's <see cref="Start"/> and <see cref="Length"/> to correct values.
/// </summary>
/// <param name="bufferSpan">The <see cref="BufferSpan{T}"/> to convert</param>
/// <returns>The span of bytes</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator byte*(BufferSpan<T> bufferSpan)
public BufferSpan<byte> AsBytes()
{
return (byte*)bufferSpan.PointerAtOffset;
BufferSpan<byte> result = default(BufferSpan<byte>);
result.Array = Unsafe.As<byte[]>(this.Array);
result.Start = this.Start * Unsafe.SizeOf<T>();
result.Length = this.Length * Unsafe.SizeOf<T>();
return result;
}
/// <summary>
/// Converts generic <see cref="BufferSpan{T}"/> to a <see cref="BufferSpan{T}"/> of bytes
/// setting it's <see cref="Start"/> and <see cref="PointerAtOffset"/> to correct values.
/// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
/// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
/// </summary>
/// <param name="source">The <see cref="BufferSpan{T}"/> to convert</param>
/// <returns>The reference to the 0th element</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator BufferSpan<byte>(BufferSpan<T> source)
public ref T DangerousGetPinnableReference()
{
BufferSpan<byte> result = default(BufferSpan<byte>);
result.Array = Unsafe.As<byte[]>(source.Array);
result.Start = source.Start * Unsafe.SizeOf<T>();
result.PointerAtOffset = source.PointerAtOffset;
return result;
ref T origin = ref this.Array[0];
return ref Unsafe.Add(ref origin, this.Start);
}
/// <summary>
@ -171,7 +151,6 @@ namespace ImageSharp
BufferSpan<T> result = default(BufferSpan<T>);
result.Array = this.Array;
result.Start = this.Start + start;
result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf<T>() * start);
result.Length = this.Length - start;
return result;
}
@ -191,7 +170,6 @@ namespace ImageSharp
BufferSpan<T> result = default(BufferSpan<T>);
result.Array = this.Array;
result.Start = this.Start + start;
result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf<T>() * start);
result.Length = length;
return result;
}
@ -205,14 +183,8 @@ namespace ImageSharp
{
DebugGuard.MustBeLessThanOrEqualTo(count, this.Length, nameof(count));
if (count < 256)
{
Unsafe.InitBlock((void*)this.PointerAtOffset, 0, BufferSpan.USizeOf<T>(count));
}
else
{
System.Array.Clear(this.Array, this.Start, count);
}
// TODO: Use Unsafe.InitBlock(ref T) for small arrays, when it get's official
System.Array.Clear(this.Array, this.Start, count);
}
/// <summary>
@ -225,13 +197,9 @@ namespace ImageSharp
}
[Conditional("DEBUG")]
private static void GuardArrayAndPointer(T[] array, void* pointerToArray)
private static void GuardArray(T[] array)
{
DebugGuard.NotNull(array, nameof(array));
DebugGuard.IsFalse(
pointerToArray == (void*)0,
nameof(pointerToArray),
"pointerToArray should not be null pointer!");
}
}
}

4
src/ImageSharp/Common/Memory/IPinnedImageBuffer{T}.cs → src/ImageSharp/Common/Memory/IBuffer2D.cs

@ -1,4 +1,4 @@
// <copyright file="IPinnedImageBuffer{T}.cs" company="James Jackson-South">
// <copyright file="IBuffer2D{T}.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
@ -10,7 +10,7 @@ namespace ImageSharp
/// interpreted as a 2D region of <see cref="Width"/> x <see cref="Height"/> elements.
/// </summary>
/// <typeparam name="T">The value type.</typeparam>
internal interface IPinnedImageBuffer<T>
internal interface IBuffer2D<T>
where T : struct
{
/// <summary>

11
src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

@ -307,7 +307,8 @@ namespace ImageSharp.Formats
rgbBytes.Reset();
pixels.CopyRGBBytesStretchedTo(rgbBytes, y, x);
byte* data = (byte*)rgbBytes.DataPointer;
ref byte data0 = ref rgbBytes.Bytes[0];
int dataIdx = 0;
for (int j = 0; j < 8; j++)
{
@ -315,9 +316,9 @@ namespace ImageSharp.Formats
for (int i = 0; i < 8; i++)
{
// Convert returned bytes into the YCbCr color space. Assume RGBA
int r = data[0];
int g = data[1];
int b = data[2];
int r = Unsafe.Add(ref data0, dataIdx);
int g = Unsafe.Add(ref data0, dataIdx + 1);
int b = Unsafe.Add(ref data0, dataIdx + 2);
// Speed up the algorithm by removing floating point calculation
// Scale by 65536, add .5F and truncate value. We use bit shifting to divide the result
@ -343,7 +344,7 @@ namespace ImageSharp.Formats
cbBlockRaw[index] = cb;
crBlockRaw[index] = cr;
data += 3;
dataIdx += 3;
}
}
}

45
src/ImageSharp/Formats/Jpeg/Utils/JpegUtils.cs

@ -6,6 +6,7 @@ namespace ImageSharp.Formats.Jpg
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary>
/// Jpeg specific utilities and extension methods
@ -33,19 +34,6 @@ namespace ImageSharp.Formats.Jpg
StretchPixels(dest, stretchFromX, stretchFromY);
}
/// <summary>
/// Copy an RGB value
/// </summary>
/// <param name="source">Source pointer</param>
/// <param name="dest">Destination pointer</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void CopyRgb(byte* source, byte* dest)
{
*dest++ = *source++; // R
*dest++ = *source++; // G
*dest = *source; // B
}
// Nothing to stretch if (fromX, fromY) is outside the area, or is at (0,0)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsInvalidStretchStartingPosition<TColor>(PixelArea<TColor> area, int fromX, int fromY)
@ -64,31 +52,38 @@ namespace ImageSharp.Formats.Jpg
for (int y = 0; y < fromY; y++)
{
byte* ptrBase = (byte*)area.DataPointer + (y * area.RowStride);
ref RGB24 ptrBase = ref GetRowStart(area, y);
for (int x = fromX; x < area.Width; x++)
{
byte* prevPtr = ptrBase + ((x - 1) * 3);
byte* currPtr = ptrBase + (x * 3);
CopyRgb(prevPtr, currPtr);
// Copy the left neighbour pixel to the current one
Unsafe.Add(ref ptrBase, x) = Unsafe.Add(ref ptrBase, x - 1);
}
}
for (int y = fromY; y < area.Height; y++)
{
byte* currBase = (byte*)area.DataPointer + (y * area.RowStride);
byte* prevBase = (byte*)area.DataPointer + ((y - 1) * area.RowStride);
ref RGB24 currBase = ref GetRowStart(area, y);
ref RGB24 prevBase = ref GetRowStart(area, y - 1);
for (int x = 0; x < area.Width; x++)
{
int x3 = 3 * x;
byte* currPtr = currBase + x3;
byte* prevPtr = prevBase + x3;
CopyRgb(prevPtr, currPtr);
// Copy the top neighbour pixel to the current one
Unsafe.Add(ref currBase, x) = Unsafe.Add(ref prevBase, x);
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ref RGB24 GetRowStart<TColor>(PixelArea<TColor> area, int y)
where TColor : struct, IPixel<TColor>
{
return ref Unsafe.As<byte, RGB24>(ref area.GetRowSpan(y).DangerousGetPinnableReference());
}
[StructLayout(LayoutKind.Sequential, Size = 3)]
private struct RGB24
{
}
}
}

41
src/ImageSharp/Image/PixelAccessor{TColor}.cs

@ -15,14 +15,9 @@ namespace ImageSharp
/// Provides per-pixel access to generic <see cref="Image{TColor}"/> pixels.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
public sealed unsafe class PixelAccessor<TColor> : IDisposable, IPinnedImageBuffer<TColor>
public sealed class PixelAccessor<TColor> : IDisposable, IBuffer2D<TColor>
where TColor : struct, IPixel<TColor>
{
/// <summary>
/// The position of the first pixel in the image.
/// </summary>
private byte* pixelsBase;
/// <summary>
/// A value indicating whether this instance of the given entity has been disposed.
/// </summary>
@ -35,9 +30,9 @@ namespace ImageSharp
private bool isDisposed;
/// <summary>
/// The <see cref="PinnedBuffer{T}"/> containing the pixel data.
/// The <see cref="Buffer{T}"/> containing the pixel data.
/// </summary>
private PinnedImageBuffer<TColor> pixelBuffer;
private Buffer2D<TColor> pixelBuffer;
/// <summary>
/// Initializes a new instance of the <see cref="PixelAccessor{TColor}"/> class.
@ -59,7 +54,7 @@ namespace ImageSharp
/// <param name="width">The width of the image represented by the pixel buffer.</param>
/// <param name="height">The height of the image represented by the pixel buffer.</param>
public PixelAccessor(int width, int height)
: this(width, height, PinnedImageBuffer<TColor>.CreateClean(width, height))
: this(width, height, Buffer2D<TColor>.CreateClean(width, height))
{
}
@ -69,7 +64,7 @@ namespace ImageSharp
/// <param name="width">The width of the image represented by the pixel buffer.</param>
/// <param name="height">The height of the image represented by the pixel buffer.</param>
/// <param name="pixels">The pixel buffer.</param>
private PixelAccessor(int width, int height, PinnedImageBuffer<TColor> pixels)
private PixelAccessor(int width, int height, Buffer2D<TColor> pixels)
{
Guard.NotNull(pixels, nameof(pixels));
Guard.MustBeGreaterThan(width, 0, nameof(width));
@ -93,11 +88,6 @@ namespace ImageSharp
/// </summary>
public TColor[] PixelArray => this.pixelBuffer.Array;
/// <summary>
/// Gets the pointer to the pixel buffer.
/// </summary>
public IntPtr DataPointer => this.pixelBuffer.Pointer;
/// <summary>
/// Gets the size of a single pixel in the number of bytes.
/// </summary>
@ -124,7 +114,7 @@ namespace ImageSharp
public ParallelOptions ParallelOptions { get; }
/// <inheritdoc />
BufferSpan<TColor> IPinnedImageBuffer<TColor>.Span => this.pixelBuffer;
BufferSpan<TColor> IBuffer2D<TColor>.Span => this.pixelBuffer;
private static BulkPixelOperations<TColor> Operations => BulkPixelOperations<TColor>.Instance;
@ -139,15 +129,13 @@ namespace ImageSharp
get
{
this.CheckCoordinates(x, y);
return Unsafe.Read<TColor>(this.pixelsBase + (((y * this.Width) + x) * Unsafe.SizeOf<TColor>()));
return this.PixelArray[(y * this.Width) + x];
}
set
{
this.CheckCoordinates(x, y);
Unsafe.Write(this.pixelsBase + (((y * this.Width) + x) * Unsafe.SizeOf<TColor>()), value);
this.PixelArray[(y * this.Width) + x] = value;
}
}
@ -179,7 +167,7 @@ namespace ImageSharp
/// </summary>
public void Reset()
{
Unsafe.InitBlock(this.pixelsBase, 0, (uint)(this.RowStride * this.Height));
this.pixelBuffer.Clear();
}
/// <summary>
@ -251,7 +239,7 @@ namespace ImageSharp
/// <remarks>If <see cref="M:PixelAccessor.PooledMemory"/> is true then caller is responsible for ensuring <see cref="M:PixelDataPool.Return()"/> is called.</remarks>
internal TColor[] ReturnCurrentPixelsAndReplaceThemInternally(int width, int height, TColor[] pixels)
{
TColor[] oldPixels = this.pixelBuffer.UnPinAndTakeArrayOwnership();
TColor[] oldPixels = this.pixelBuffer.TakeArrayOwnership();
this.SetPixelBufferUnsafe(width, height, pixels);
return oldPixels;
}
@ -262,9 +250,7 @@ namespace ImageSharp
/// <param name="target">The target pixel buffer accessor.</param>
internal void CopyTo(PixelAccessor<TColor> target)
{
uint byteCount = (uint)(this.Width * this.Height * Unsafe.SizeOf<TColor>());
Unsafe.CopyBlock(target.pixelsBase, this.pixelsBase, byteCount);
BufferSpan.Copy(this.pixelBuffer.Span, target.pixelBuffer.Span);
}
/// <summary>
@ -424,7 +410,7 @@ namespace ImageSharp
private void SetPixelBufferUnsafe(int width, int height, TColor[] pixels)
{
this.SetPixelBufferUnsafe(width, height, new PinnedImageBuffer<TColor>(pixels, width, height));
this.SetPixelBufferUnsafe(width, height, new Buffer2D<TColor>(pixels, width, height));
}
/// <summary>
@ -433,10 +419,9 @@ namespace ImageSharp
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="pixels">The pixel buffer</param>
private void SetPixelBufferUnsafe(int width, int height, PinnedImageBuffer<TColor> pixels)
private void SetPixelBufferUnsafe(int width, int height, Buffer2D<TColor> pixels)
{
this.pixelBuffer = pixels;
this.pixelsBase = (byte*)pixels.Pointer;
this.Width = width;
this.Height = height;

22
src/ImageSharp/Image/PixelArea{TColor}.cs

@ -13,7 +13,7 @@ namespace ImageSharp
/// Represents an area of generic <see cref="Image{TColor}"/> pixels.
/// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam>
internal sealed unsafe class PixelArea<TColor> : IDisposable
internal sealed class PixelArea<TColor> : IDisposable
where TColor : struct, IPixel<TColor>
{
/// <summary>
@ -30,7 +30,7 @@ namespace ImageSharp
/// <summary>
/// The underlying buffer containing the raw pixel data.
/// </summary>
private PinnedBuffer<byte> byteBuffer;
private Buffer<byte> byteBuffer;
/// <summary>
/// Initializes a new instance of the <see cref="PixelArea{TColor}"/> class.
@ -66,8 +66,7 @@ namespace ImageSharp
this.RowStride = width * GetComponentCount(componentOrder);
this.Length = bytes.Length; // TODO: Is this the right value for Length?
this.byteBuffer = new PinnedBuffer<byte>(bytes);
this.PixelBase = (byte*)this.byteBuffer.Pointer;
this.byteBuffer = new Buffer<byte>(bytes);
}
/// <summary>
@ -117,8 +116,7 @@ namespace ImageSharp
this.RowStride = (width * GetComponentCount(componentOrder)) + padding;
this.Length = this.RowStride * height;
this.byteBuffer = new PinnedBuffer<byte>(this.Length);
this.PixelBase = (byte*)this.byteBuffer.Pointer;
this.byteBuffer = new Buffer<byte>(this.Length);
}
/// <summary>
@ -136,21 +134,11 @@ namespace ImageSharp
/// </summary>
public ComponentOrder ComponentOrder { get; }
/// <summary>
/// Gets the pointer to the pixel buffer.
/// </summary>
public IntPtr DataPointer => this.byteBuffer.Pointer;
/// <summary>
/// Gets the height.
/// </summary>
public int Height { get; }
/// <summary>
/// Gets the data pointer.
/// </summary>
public byte* PixelBase { get; private set; }
/// <summary>
/// Gets the width of one row in the number of bytes.
/// </summary>
@ -198,7 +186,7 @@ namespace ImageSharp
/// </summary>
public void Reset()
{
Unsafe.InitBlock(this.PixelBase, 0, (uint)(this.RowStride * this.Height));
this.byteBuffer.Clear();
}
/// <summary>

2
src/ImageSharp/ImageSharp.csproj

@ -2,7 +2,7 @@
<PropertyGroup>
<Description>A cross-platform library for the processing of image files; written in C#</Description>
<AssemblyTitle>ImageSharp</AssemblyTitle>
<VersionPrefix>1.0.0-alpha5</VersionPrefix>
<VersionPrefix>1.0.0-alpha6</VersionPrefix>
<Authors>James Jackson-South and contributors</Authors>
<TargetFrameworks>netstandard1.3;netstandard1.1</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>

10
src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs

@ -73,6 +73,8 @@ namespace ImageSharp
/// </returns>
public Collection<ExifValue> Read(byte[] data)
{
DebugGuard.NotNull(data, nameof(data));
Collection<ExifValue> result = new Collection<ExifValue>();
this.exifData = data;
@ -390,7 +392,13 @@ namespace ImageSharp
private string GetString(uint length)
{
return ToString(this.GetBytes(length));
byte[] data = this.GetBytes(length);
if (data == null || data.Length == 0)
{
return null;
}
return ToString(data);
}
private void GetThumbnail(uint offset)

34
src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.Weights.cs

@ -41,7 +41,7 @@ namespace ImageSharp.Processing.Processors
/// <summary>
/// Gets an unsafe float* pointer to the beginning of <see cref="Span"/>.
/// </summary>
public float* Ptr => (float*)this.Span.PointerAtOffset;
public ref float Ptr => ref this.Span.DangerousGetPinnableReference();
/// <summary>
/// Gets the lenghth of the weights window
@ -56,19 +56,18 @@ namespace ImageSharp.Processing.Processors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ComputeWeightedRowSum(BufferSpan<Vector4> rowSpan)
{
float* horizontalValues = this.Ptr;
ref float horizontalValues = ref this.Ptr;
int left = this.Left;
Vector4* vecPtr = (Vector4*)rowSpan.PointerAtOffset;
vecPtr += left;
ref Vector4 vecPtr = ref Unsafe.Add(ref rowSpan.DangerousGetPinnableReference(), left);
// Destination color components
Vector4 result = Vector4.Zero;
for (int i = 0; i < this.Length; i++)
{
float weight = horizontalValues[i];
result += (*vecPtr) * weight;
vecPtr++;
float weight = Unsafe.Add(ref horizontalValues, i);
Vector4 v = Unsafe.Add(ref vecPtr, i);
result += v * weight;
}
return result;
@ -83,19 +82,18 @@ namespace ImageSharp.Processing.Processors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ComputeExpandedWeightedRowSum(BufferSpan<Vector4> rowSpan)
{
float* horizontalValues = this.Ptr;
ref float horizontalValues = ref this.Ptr;
int left = this.Left;
Vector4* vecPtr = (Vector4*)rowSpan.PointerAtOffset;
vecPtr += left;
ref Vector4 vecPtr = ref Unsafe.Add(ref rowSpan.DangerousGetPinnableReference(), left);
// Destination color components
Vector4 result = Vector4.Zero;
for (int i = 0; i < this.Length; i++)
{
float weight = horizontalValues[i];
result += (*vecPtr).Expand() * weight;
vecPtr++;
float weight = Unsafe.Add(ref horizontalValues, i);
Vector4 v = Unsafe.Add(ref vecPtr, i);
result += v.Expand() * weight;
}
return result;
@ -109,9 +107,9 @@ namespace ImageSharp.Processing.Processors
/// <param name="x">The column position</param>
/// <returns>The weighted sum</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ComputeWeightedColumnSum(PinnedImageBuffer<Vector4> firstPassPixels, int x)
public Vector4 ComputeWeightedColumnSum(Buffer2D<Vector4> firstPassPixels, int x)
{
float* verticalValues = this.Ptr;
ref float verticalValues = ref this.Ptr;
int left = this.Left;
// Destination color components
@ -119,7 +117,7 @@ namespace ImageSharp.Processing.Processors
for (int i = 0; i < this.Length; i++)
{
float yw = verticalValues[i];
float yw = Unsafe.Add(ref verticalValues, i);
int index = left + i;
result += firstPassPixels[x, index] * yw;
}
@ -133,7 +131,7 @@ namespace ImageSharp.Processing.Processors
/// </summary>
internal class WeightsBuffer : IDisposable
{
private PinnedImageBuffer<float> dataBuffer;
private Buffer2D<float> dataBuffer;
/// <summary>
/// Initializes a new instance of the <see cref="WeightsBuffer"/> class.
@ -142,7 +140,7 @@ namespace ImageSharp.Processing.Processors
/// <param name="destinationSize">The size of the destination window</param>
public WeightsBuffer(int sourceSize, int destinationSize)
{
this.dataBuffer = PinnedImageBuffer<float>.CreateClean(sourceSize, destinationSize);
this.dataBuffer = Buffer2D<float>.CreateClean(sourceSize, destinationSize);
this.Weights = new WeightsWindow[destinationSize];
}

11
src/ImageSharp/Processing/Processors/Transforms/ResamplingWeightedProcessor.cs

@ -7,6 +7,7 @@ namespace ImageSharp.Processing.Processors
{
using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary>
@ -111,13 +112,15 @@ namespace ImageSharp.Processing.Processors
WeightsWindow ws = result.GetWeightsWindow(i, left, right);
result.Weights[i] = ws;
float* weights = ws.Ptr;
ref float weights = ref ws.Ptr;
for (int j = left; j <= right; j++)
{
float weight = sampler.GetValue((j - center) / scale);
sum += weight;
weights[j - left] = weight;
// weights[j - left] = weight:
Unsafe.Add(ref weights, j - left) = weight;
}
// Normalise, best to do it here rather than in the pixel loop later on.
@ -125,7 +128,9 @@ namespace ImageSharp.Processing.Processors
{
for (int w = 0; w < ws.Length; w++)
{
weights[w] = weights[w] / sum;
// weights[w] = weights[w] / sum:
ref float wRef = ref Unsafe.Add(ref weights, w);
wRef = wRef / sum;
}
}
}

4
src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs

@ -106,7 +106,7 @@ namespace ImageSharp.Processing.Processors
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height))
{
using (PixelAccessor<TColor> sourcePixels = source.Lock())
using (PinnedImageBuffer<Vector4> firstPassPixels = new PinnedImageBuffer<Vector4>(width, source.Height))
using (Buffer2D<Vector4> firstPassPixels = new Buffer2D<Vector4>(width, source.Height))
{
firstPassPixels.Clear();
@ -117,7 +117,7 @@ namespace ImageSharp.Processing.Processors
y =>
{
// TODO: Without Parallel.For() this buffer object could be reused:
using (PinnedBuffer<Vector4> tempRowBuffer = new PinnedBuffer<Vector4>(sourcePixels.Width))
using (Buffer<Vector4> tempRowBuffer = new Buffer<Vector4>(sourcePixels.Width))
{
BufferSpan<TColor> sourceRow = sourcePixels.GetRowSpan(y);

15
src/ImageSharp/Quantizers/Quantizer.cs

@ -68,7 +68,20 @@ namespace ImageSharp.Quantizers
// Collect the palette. Required before the second pass runs.
colorPalette = this.GetPalette();
this.SecondPass(pixels, quantizedPixels, width, height);
if (this.Dither)
{
// We clone the image as we don't want to alter the original.
using (Image<TColor> clone = new Image<TColor>(image))
using (PixelAccessor<TColor> clonedPixels = clone.Lock())
{
this.SecondPass(clonedPixels, quantizedPixels, width, height);
}
}
else
{
this.SecondPass(pixels, quantizedPixels, width, height);
}
}
return new QuantizedImage<TColor>(width, height, colorPalette, quantizedPixels);

2
src/ImageSharp/Quantizers/WuQuantizer.cs

@ -136,7 +136,7 @@ namespace ImageSharp.Quantizers
{
Guard.NotNull(image, nameof(image));
this.colors = maxColors.Clamp(1, 256);
this.colors = maxColors.Clamp(1, 255);
try
{

16
tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4ReferenceVsPointer.cs

@ -6,7 +6,7 @@
using BenchmarkDotNet.Attributes;
using ImageSharp;
/// <summary>
/// Compares two implementation candidates for general BulkPixelOperations.ToVector4():
/// - One iterating with pointers
@ -14,9 +14,9 @@
/// </summary>
public unsafe class PackFromVector4ReferenceVsPointer
{
private PinnedBuffer<ImageSharp.Color> destination;
private Buffer<ImageSharp.Color> destination;
private PinnedBuffer<Vector4> source;
private Buffer<Vector4> source;
[Params(16, 128, 1024)]
public int Count { get; set; }
@ -24,8 +24,10 @@
[Setup]
public void Setup()
{
this.destination = new PinnedBuffer<ImageSharp.Color>(this.Count);
this.source = new PinnedBuffer<Vector4>(this.Count * 4);
this.destination = new Buffer<ImageSharp.Color>(this.Count);
this.source = new Buffer<Vector4>(this.Count * 4);
this.source.Pin();
this.destination.Pin();
}
[Cleanup]
@ -38,8 +40,8 @@
[Benchmark(Baseline = true)]
public void PackUsingPointers()
{
Vector4* sp = (Vector4*)this.source.Pointer;
byte* dp = (byte*)this.destination.Pointer;
Vector4* sp = (Vector4*)this.source.Pin();
byte* dp = (byte*)this.destination.Pin();
int count = this.Count;
int size = sizeof(ImageSharp.Color);

8
tests/ImageSharp.Benchmarks/Color/Bulk/PackFromXyzw.cs

@ -8,9 +8,9 @@ namespace ImageSharp.Benchmarks.Color.Bulk
public abstract class PackFromXyzw<TColor>
where TColor : struct, IPixel<TColor>
{
private PinnedBuffer<TColor> destination;
private Buffer<TColor> destination;
private PinnedBuffer<byte> source;
private Buffer<byte> source;
[Params(16, 128, 1024)]
public int Count { get; set; }
@ -18,8 +18,8 @@ namespace ImageSharp.Benchmarks.Color.Bulk
[Setup]
public void Setup()
{
this.destination = new PinnedBuffer<TColor>(this.Count);
this.source = new PinnedBuffer<byte>(this.Count * 4);
this.destination = new Buffer<TColor>(this.Count);
this.source = new Buffer<byte>(this.Count * 4);
}
[Cleanup]

8
tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs

@ -8,9 +8,9 @@ namespace ImageSharp.Benchmarks.Color.Bulk
public abstract class ToVector4<TColor>
where TColor : struct, IPixel<TColor>
{
private PinnedBuffer<TColor> source;
private Buffer<TColor> source;
private PinnedBuffer<Vector4> destination;
private Buffer<Vector4> destination;
[Params(64, 300, 1024)]
public int Count { get; set; }
@ -18,8 +18,8 @@ namespace ImageSharp.Benchmarks.Color.Bulk
[Setup]
public void Setup()
{
this.source = new PinnedBuffer<TColor>(this.Count);
this.destination = new PinnedBuffer<Vector4>(this.Count);
this.source = new Buffer<TColor>(this.Count);
this.destination = new Buffer<Vector4>(this.Count);
}
[Cleanup]

8
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs

@ -8,9 +8,9 @@ namespace ImageSharp.Benchmarks.Color.Bulk
public abstract class ToXyz<TColor>
where TColor : struct, IPixel<TColor>
{
private PinnedBuffer<TColor> source;
private Buffer<TColor> source;
private PinnedBuffer<byte> destination;
private Buffer<byte> destination;
[Params(16, 128, 1024)]
public int Count { get; set; }
@ -18,8 +18,8 @@ namespace ImageSharp.Benchmarks.Color.Bulk
[Setup]
public void Setup()
{
this.source = new PinnedBuffer<TColor>(this.Count);
this.destination = new PinnedBuffer<byte>(this.Count * 3);
this.source = new Buffer<TColor>(this.Count);
this.destination = new Buffer<byte>(this.Count * 3);
}
[Cleanup]

10
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs

@ -13,9 +13,9 @@ namespace ImageSharp.Benchmarks.Color.Bulk
public abstract class ToXyzw<TColor>
where TColor : struct, IPixel<TColor>
{
private PinnedBuffer<TColor> source;
private Buffer<TColor> source;
private PinnedBuffer<byte> destination;
private Buffer<byte> destination;
[Params(16, 128, 1024)]
public int Count { get; set; }
@ -23,8 +23,8 @@ namespace ImageSharp.Benchmarks.Color.Bulk
[Setup]
public void Setup()
{
this.source = new PinnedBuffer<TColor>(this.Count);
this.destination = new PinnedBuffer<byte>(this.Count * 4);
this.source = new Buffer<TColor>(this.Count);
this.destination = new Buffer<byte>(this.Count * 4);
}
[Cleanup]
@ -64,7 +64,7 @@ namespace ImageSharp.Benchmarks.Color.Bulk
{
}
public class ToXyzw_Argb : ToXyzw<Argb>
public class ToXyzw_Argb : ToXyzw<Argb32>
{
}
}

37
tests/ImageSharp.Benchmarks/General/ArrayCopy.cs

@ -9,7 +9,7 @@ namespace ImageSharp.Benchmarks.General
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
[Config(typeof(Config.Short))]
public class ArrayCopy
{
@ -58,8 +58,7 @@ namespace ImageSharp.Benchmarks.General
Buffer.MemoryCopy(pinnedSource, pinnedDestination, this.Count, this.Count);
}
}
[Benchmark(Description = "Copy using Marshal.Copy<T>")]
public unsafe void CopyUsingMarshalCopy()
{
@ -68,5 +67,37 @@ namespace ImageSharp.Benchmarks.General
Marshal.Copy(this.source, 0, (IntPtr)pinnedDestination, this.Count);
}
}
/*****************************************************************************************************************
*************** RESULTS on i7-4810MQ 2.80GHz + Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1085.0 ********************
*****************************************************************************************************************
*
* Method | Count | Mean | StdErr | StdDev | Scaled | Scaled-StdDev |
* ---------------------------------- |------ |------------ |----------- |----------- |------- |-------------- |
* 'Copy using Array.Copy()' | 10 | 20.3074 ns | 0.1194 ns | 0.2068 ns | 1.00 | 0.00 |
* 'Copy using Unsafe<T>' | 10 | 6.1002 ns | 0.1981 ns | 0.3432 ns | 0.30 | 0.01 |
* 'Copy using Buffer.BlockCopy()' | 10 | 10.7879 ns | 0.0984 ns | 0.1705 ns | 0.53 | 0.01 |
* 'Copy using Buffer.MemoryCopy<T>' | 10 | 4.9625 ns | 0.0200 ns | 0.0347 ns | 0.24 | 0.00 |
* 'Copy using Marshal.Copy<T>' | 10 | 16.1782 ns | 0.0919 ns | 0.1592 ns | 0.80 | 0.01 |
*
* 'Copy using Array.Copy()' | 100 | 31.5945 ns | 0.2908 ns | 0.5037 ns | 1.00 | 0.00 |
* 'Copy using Unsafe<T>' | 100 | 10.2722 ns | 0.5202 ns | 0.9010 ns | 0.33 | 0.02 |
* 'Copy using Buffer.BlockCopy()' | 100 | 22.0322 ns | 0.0284 ns | 0.0493 ns | 0.70 | 0.01 |
* 'Copy using Buffer.MemoryCopy<T>' | 100 | 10.2472 ns | 0.0359 ns | 0.0622 ns | 0.32 | 0.00 |
* 'Copy using Marshal.Copy<T>' | 100 | 34.3820 ns | 1.1868 ns | 2.0555 ns | 1.09 | 0.05 |
*
* 'Copy using Array.Copy()' | 1000 | 40.9743 ns | 0.0521 ns | 0.0902 ns | 1.00 | 0.00 |
* 'Copy using Unsafe<T>' | 1000 | 42.7840 ns | 2.0139 ns | 3.4882 ns | 1.04 | 0.07 |
* 'Copy using Buffer.BlockCopy()' | 1000 | 33.7361 ns | 0.0751 ns | 0.1300 ns | 0.82 | 0.00 |
* 'Copy using Buffer.MemoryCopy<T>' | 1000 | 35.7541 ns | 0.0480 ns | 0.0832 ns | 0.87 | 0.00 |
* 'Copy using Marshal.Copy<T>' | 1000 | 42.2028 ns | 0.2769 ns | 0.4795 ns | 1.03 | 0.01 |
*
* 'Copy using Array.Copy()' | 10000 | 200.0438 ns | 0.2251 ns | 0.3899 ns | 1.00 | 0.00 |
* 'Copy using Unsafe<T>' | 10000 | 389.6957 ns | 13.2770 ns | 22.9964 ns | 1.95 | 0.09 |
* 'Copy using Buffer.BlockCopy()' | 10000 | 191.3478 ns | 0.1557 ns | 0.2697 ns | 0.96 | 0.00 |
* 'Copy using Buffer.MemoryCopy<T>' | 10000 | 196.4679 ns | 0.2731 ns | 0.4730 ns | 0.98 | 0.00 |
* 'Copy using Marshal.Copy<T>' | 10000 | 202.5392 ns | 0.5561 ns | 0.9631 ns | 1.01 | 0.00 |
*
*/
}
}

8
tests/ImageSharp.Benchmarks/General/ClearBuffer.cs

@ -11,15 +11,15 @@ namespace ImageSharp.Benchmarks.General
public unsafe class ClearBuffer
{
private PinnedBuffer<Color> buffer;
private Buffer<Color> buffer;
[Params(32, 128, 512)]
public int Count { get; set; }
[Setup]
public void Setup()
{
this.buffer = new PinnedBuffer<ImageSharp.Color>(this.Count);
this.buffer = new Buffer<ImageSharp.Color>(this.Count);
}
[Cleanup]
@ -37,7 +37,7 @@ namespace ImageSharp.Benchmarks.General
[Benchmark]
public void Unsafe_InitBlock()
{
Unsafe.InitBlock((void*)this.buffer.Pointer, default(byte), (uint)this.Count*sizeof(uint));
Unsafe.InitBlock((void*)this.buffer.Pin(), default(byte), (uint)this.Count * sizeof(uint));
}
}
}

7
tests/ImageSharp.Benchmarks/General/IterateArray.cs

@ -8,7 +8,7 @@ namespace ImageSharp.Benchmarks.General
public class IterateArray
{
// Usual pinned stuff
private PinnedBuffer<Vector4> buffer;
private Buffer<Vector4> buffer;
// An array that's not pinned by intent!
private Vector4[] array;
@ -19,7 +19,8 @@ namespace ImageSharp.Benchmarks.General
[Setup]
public void Setup()
{
this.buffer = new PinnedBuffer<Vector4>(this.Length);
this.buffer = new Buffer<Vector4>(this.Length);
this.buffer.Pin();
this.array = new Vector4[this.Length];
}
@ -41,7 +42,7 @@ namespace ImageSharp.Benchmarks.General
{
Vector4 sum = new Vector4();
Vector4* ptr = (Vector4*) this.buffer.Pointer;
Vector4* ptr = (Vector4*) this.buffer.Pin();
Vector4* end = ptr + this.Length;
for (; ptr < end; ptr++)

360
tests/ImageSharp.Benchmarks/General/PixelIndexing.cs

@ -0,0 +1,360 @@
namespace ImageSharp.Benchmarks.General
{
using System.Numerics;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
// Pixel indexing benchmarks compare different methods for getting/setting all pixel values in a subsegment of a single pixel row.
public abstract unsafe class PixelIndexing
{
/// <summary>
/// https://github.com/dotnet/corefx/blob/master/src/System.Memory/src/System/Pinnable.cs
/// </summary>
protected class Pinnable<T>
{
public T Data;
}
/// <summary>
/// The indexer methods are encapsulated into a struct to make sure everything is inlined.
/// </summary>
internal struct Data
{
private Vector4* pointer;
private Pinnable<Vector4> pinnable;
private Vector4[] array;
private int width;
public Data(Buffer2D<Vector4> buffer)
{
this.pointer = (Vector4*)buffer.Pin();
this.pinnable = Unsafe.As<Pinnable<Vector4>>(buffer.Array);
this.array = buffer.Array;
this.width = buffer.Width;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 GetPointersBasicImpl(int x, int y)
{
return this.pointer[y * this.width + x];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 GetPointersSrcsUnsafeImpl(int x, int y)
{
// This is the original solution in PixelAccessor:
return Unsafe.Read<Vector4>((byte*)this.pointer + (((y * this.width) + x) * Unsafe.SizeOf<Vector4>()));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 GetReferencesImpl(int x, int y)
{
int elementOffset = (y * this.width) + x;
return Unsafe.Add(ref this.pinnable.Data, elementOffset);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref Vector4 GetReferencesRefReturnsImpl(int x, int y)
{
int elementOffset = (y * this.width) + x;
return ref Unsafe.Add(ref this.pinnable.Data, elementOffset);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void IndexWithPointersBasicImpl(int x, int y, Vector4 v)
{
this.pointer[y * this.width + x] = v;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void IndexWithPointersSrcsUnsafeImpl(int x, int y, Vector4 v)
{
Unsafe.Write((byte*)this.pointer + (((y * this.width) + x) * Unsafe.SizeOf<Vector4>()), v);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void IndexWithReferencesOnPinnableIncorrectImpl(int x, int y, Vector4 v)
{
int elementOffset = (y * this.width) + x;
// Incorrect, because also should add a runtime-specific byte offset here. See https://github.com/dotnet/corefx/blob/master/src/System.Memory/src/System/Span.cs#L68
Unsafe.Add(ref this.pinnable.Data, elementOffset) = v;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref Vector4 IndexWithReferencesOnPinnableIncorrectRefReturnImpl(int x, int y)
{
int elementOffset = (y * this.width) + x;
// Incorrect, because also should add a runtime-specific byte offset here. See https://github.com/dotnet/corefx/blob/master/src/System.Memory/src/System/Span.cs#L68
return ref Unsafe.Add(ref this.pinnable.Data, elementOffset);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void IndexWithUnsafeReferenceArithmeticsOnArray0Impl(int x, int y, Vector4 v)
{
int elementOffset = (y * this.width) + x;
Unsafe.Add(ref this.array[0], elementOffset) = v;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref Vector4 IndexWithUnsafeReferenceArithmeticsOnArray0RefReturnImpl(int x, int y)
{
int elementOffset = (y * this.width) + x;
return ref Unsafe.Add(ref this.array[0], elementOffset);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void IndexSetArrayStraightforward(int x, int y, Vector4 v)
{
// No magic.
// We just index right into the array as normal people do.
// And it looks like this is the fastest way!
this.array[(y * this.width) + x] = v;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref Vector4 IndexWithReferencesOnArrayStraightforwardRefReturnImpl(int x, int y)
{
// No magic.
// We just index right into the array as normal people do.
// And it looks like this is the fastest way!
return ref this.array[(y * this.width) + x];
}
}
internal Buffer2D<Vector4> buffer;
protected int width;
protected int startIndex;
protected int endIndex;
protected Vector4* pointer;
protected Vector4[] array;
protected Pinnable<Vector4> pinnable;
// [Params(1024)]
public int Count { get; set; } = 1024;
[Setup]
public void Setup()
{
this.width = 2048;
this.buffer = new Buffer2D<Vector4>(2048, 2048);
this.pointer = (Vector4*)this.buffer.Pin();
this.array = this.buffer.Array;
this.pinnable = Unsafe.As<Pinnable<Vector4>>(this.array);
this.startIndex = 2048 / 2 - (this.Count / 2);
this.endIndex = 2048 / 2 + (this.Count / 2);
}
[Cleanup]
public void Cleanup()
{
this.buffer.Dispose();
}
}
public class PixelIndexingGetter : PixelIndexing
{
[Benchmark(Description = "Index.Get: Pointers+arithmetics", Baseline = true)]
public Vector4 IndexWithPointersBasic()
{
Vector4 sum = Vector4.Zero;
Data data = new Data(this.buffer);
int y = this.startIndex;
for (int x = this.startIndex; x < this.endIndex; x++)
{
sum += data.GetPointersBasicImpl(x, y);
}
return sum;
}
[Benchmark(Description = "Index.Get: Pointers+SRCS.Unsafe")]
public Vector4 IndexWithPointersSrcsUnsafe()
{
Vector4 sum = Vector4.Zero;
Data data = new Data(this.buffer);
int y = this.startIndex;
for (int x = this.startIndex; x < this.endIndex; x++)
{
sum += data.GetPointersSrcsUnsafeImpl(x, y);
}
return sum;
}
[Benchmark(Description = "Index.Get: References")]
public Vector4 IndexWithReferences()
{
Vector4 sum = Vector4.Zero;
Data data = new Data(this.buffer);
int y = this.startIndex;
for (int x = this.startIndex; x < this.endIndex; x++)
{
sum += data.GetReferencesImpl(x, y);
}
return sum;
}
[Benchmark(Description = "Index.Get: References|refreturns")]
public Vector4 IndexWithReferencesRefReturns()
{
Vector4 sum = Vector4.Zero;
Data data = new Data(this.buffer);
int y = this.startIndex;
for (int x = this.startIndex; x < this.endIndex; x++)
{
sum += data.GetReferencesRefReturnsImpl(x, y);
}
return sum;
}
}
public class PixelIndexingSetter : PixelIndexing
{
[Benchmark(Description = "!!! Index.Set: Pointers|arithmetics", Baseline = true)]
public void IndexWithPointersBasic()
{
Vector4 v = new Vector4(1, 2, 3, 4);
Data data = new Data(this.buffer);
int y = this.startIndex;
for (int x = this.startIndex; x < this.endIndex; x++)
{
data.IndexWithPointersBasicImpl(x, y, v);
}
}
[Benchmark(Description = "Index.Set: Pointers|SRCS.Unsafe")]
public void IndexWithPointersSrcsUnsafe()
{
Vector4 v = new Vector4(1, 2, 3, 4);
Data data = new Data(this.buffer);
int y = this.startIndex;
for (int x = this.startIndex; x < this.endIndex; x++)
{
data.IndexWithPointersSrcsUnsafeImpl(x, y, v);
}
}
[Benchmark(Description = "Index.Set: References|IncorrectPinnable")]
public void IndexWithReferencesPinnableBasic()
{
Vector4 v = new Vector4(1, 2, 3, 4);
Data data = new Data(this.buffer);
int y = this.startIndex;
for (int x = this.startIndex; x < this.endIndex; x++)
{
data.IndexWithReferencesOnPinnableIncorrectImpl(x, y, v);
}
}
[Benchmark(Description = "Index.Set: References|IncorrectPinnable|refreturn")]
public void IndexWithReferencesPinnableRefReturn()
{
Vector4 v = new Vector4(1, 2, 3, 4);
Data data = new Data(this.buffer);
int y = this.startIndex;
for (int x = this.startIndex; x < this.endIndex; x++)
{
data.IndexWithReferencesOnPinnableIncorrectRefReturnImpl(x, y) = v;
}
}
[Benchmark(Description = "Index.Set: References|Array[0]Unsafe")]
public void IndexWithReferencesArrayBasic()
{
Vector4 v = new Vector4(1, 2, 3, 4);
Data data = new Data(this.buffer);
int y = this.startIndex;
for (int x = this.startIndex; x < this.endIndex; x++)
{
data.IndexWithUnsafeReferenceArithmeticsOnArray0Impl(x, y, v);
}
}
[Benchmark(Description = "Index.Set: References|Array[0]Unsafe|refreturn")]
public void IndexWithReferencesArrayRefReturn()
{
Vector4 v = new Vector4(1, 2, 3, 4);
Data data = new Data(this.buffer);
int y = this.startIndex;
for (int x = this.startIndex; x < this.endIndex; x++)
{
data.IndexWithUnsafeReferenceArithmeticsOnArray0RefReturnImpl(x, y) = v;
}
}
[Benchmark(Description = "!!! Index.Set: References|Array+Straight")]
public void IndexWithReferencesArrayStraightforward()
{
Vector4 v = new Vector4(1, 2, 3, 4);
Data data = new Data(this.buffer);
int y = this.startIndex;
for (int x = this.startIndex; x < this.endIndex; x++)
{
// No magic.
// We just index right into the array as normal people do.
// And it looks like this is the fastest way!
data.IndexSetArrayStraightforward(x, y, v);
}
}
[Benchmark(Description = "!!! Index.Set: References|Array+Straight|refreturn")]
public void IndexWithReferencesArrayStraightforwardRefReturn()
{
Vector4 v = new Vector4(1, 2, 3, 4);
Data data = new Data(this.buffer);
int y = this.startIndex;
for (int x = this.startIndex; x < this.endIndex; x++)
{
// No magic.
// We just index right into the array as normal people do.
// And it looks like this is the fastest way!
data.IndexWithReferencesOnArrayStraightforwardRefReturnImpl(x, y) = v;
}
}
[Benchmark(Description = "!!! Index.Set: SmartUnsafe")]
public void SmartUnsafe()
{
Vector4 v = new Vector4(1, 2, 3, 4);
Data data = new Data(this.buffer);
// This method is basically an unsafe variant of .GetRowSpan(y) + indexing individual pixels in the row.
// If a user seriously needs by-pixel manipulation to be performant, we should provide this option.
ref Vector4 rowStart = ref data.IndexWithReferencesOnArrayStraightforwardRefReturnImpl(this.startIndex, this.startIndex);
for (int i = 0; i < this.Count; i++)
{
// We don't have to add 'Width * y' here!
Unsafe.Add(ref rowStart, i) = v;
}
}
}
}

21
tests/ImageSharp.Benchmarks/Samplers/Resize.cs

@ -11,6 +11,7 @@ namespace ImageSharp.Benchmarks
using BenchmarkDotNet.Attributes;
using CoreSize = ImageSharp.Size;
using CoreImage = ImageSharp.Image;
using CoreVectorImage = ImageSharp.Image<ImageSharp.ColorVector>;
public class Resize : BenchmarkBase
{
@ -44,6 +45,16 @@ namespace ImageSharp.Benchmarks
}
}
[Benchmark(Description = "ImageSharp Vector Resize")]
public CoreSize ResizeCoreVector()
{
using (CoreVectorImage image = new CoreVectorImage(2000, 2000))
{
image.Resize(400, 400);
return new CoreSize(image.Width, image.Height);
}
}
[Benchmark(Description = "ImageSharp Compand Resize")]
public CoreSize ResizeCoreCompand()
{
@ -53,5 +64,15 @@ namespace ImageSharp.Benchmarks
return new CoreSize(image.Width, image.Height);
}
}
[Benchmark(Description = "ImageSharp Vector Compand Resize")]
public CoreSize ResizeCoreVectorCompand()
{
using (CoreVectorImage image = new CoreVectorImage(2000, 2000))
{
image.Resize(400, 400, true);
return new CoreSize(image.Width, image.Height);
}
}
}
}

6
tests/ImageSharp.Sandbox46/Program.cs

@ -7,7 +7,7 @@ namespace ImageSharp.Sandbox46
{
using System;
using System.Runtime.DesignerServices;
using ImageSharp.Tests;
using ImageSharp.Tests.Colors;
@ -53,10 +53,10 @@ namespace ImageSharp.Sandbox46
private static void RunToVector4ProfilingTest()
{
BulkPixelOperationsTests.Color tests = new BulkPixelOperationsTests.Color(new ConsoleOutput());
BulkPixelOperationsTests.Color32 tests = new BulkPixelOperationsTests.Color32(new ConsoleOutput());
tests.Benchmark_ToVector4();
}
private static void RunDecodeJpegProfilingTests()
{
Console.WriteLine("RunDecodeJpegProfilingTests...");

60
tests/ImageSharp.Tests/Colors/BulkPixelOperationsTests.cs

@ -10,22 +10,22 @@ namespace ImageSharp.Tests.Colors
public class BulkPixelOperationsTests
{
public class Color : BulkPixelOperationsTests<ImageSharp.Color>
public class Color32 : BulkPixelOperationsTests<ImageSharp.Color>
{
public Color(ITestOutputHelper output)
public Color32(ITestOutputHelper output)
: base(output)
{
}
// For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class:
public static new TheoryData<int> ArraySizesData => new TheoryData<int> { 7, 16, 1111 };
//public static new TheoryData<int> ArraySizesData => new TheoryData<int> { 7, 16, 1111 };
[Fact]
public void IsSpecialImplementation()
{
Assert.IsType<ImageSharp.Color.BulkOperations>(BulkPixelOperations<ImageSharp.Color>.Instance);
}
[Fact]
public void ToVector4SimdAligned()
{
@ -36,7 +36,7 @@ namespace ImageSharp.Tests.Colors
source,
expected,
(s, d) => ImageSharp.Color.BulkOperations.ToVector4SimdAligned(s, d, 64)
);
);
}
// [Fact] // Profiling benchmark - enable manually!
@ -45,8 +45,8 @@ namespace ImageSharp.Tests.Colors
int times = 200000;
int count = 1024;
using (PinnedBuffer<ImageSharp.Color> source = new PinnedBuffer<ImageSharp.Color>(count))
using (PinnedBuffer<Vector4> dest = new PinnedBuffer<Vector4>(count))
using (Buffer<ImageSharp.Color> source = new Buffer<ImageSharp.Color>(count))
using (Buffer<Vector4> dest = new Buffer<Vector4>(count))
{
this.Measure(
times,
@ -58,7 +58,7 @@ namespace ImageSharp.Tests.Colors
}
}
public class Argb : BulkPixelOperationsTests<ImageSharp.Argb>
public class Argb : BulkPixelOperationsTests<ImageSharp.Argb32>
{
// For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class:
public Argb(ITestOutputHelper output)
@ -66,13 +66,13 @@ namespace ImageSharp.Tests.Colors
{
}
public static new TheoryData<int> ArraySizesData => new TheoryData<int> { 7, 16, 1111 };
//public static new TheoryData<int> ArraySizesData => new TheoryData<int> { 7, 16, 1111 };
}
[Theory]
[WithBlankImages(1, 1, PixelTypes.All)]
public void GetGlobalInstance<TColor>(TestImageProvider<TColor> dummy)
where TColor:struct, IPixel<TColor>
where TColor : struct, IPixel<TColor>
{
Assert.NotNull(BulkPixelOperations<TColor>.Instance);
}
@ -112,7 +112,7 @@ namespace ImageSharp.Tests.Colors
source,
expected,
(s, d) => Operations.PackFromVector4(s, d, count)
);
);
}
internal static Vector4[] CreateExpectedVector4Data(TColor[] source)
@ -137,7 +137,7 @@ namespace ImageSharp.Tests.Colors
source,
expected,
(s, d) => Operations.ToVector4(s, d, count)
);
);
}
@ -156,10 +156,10 @@ namespace ImageSharp.Tests.Colors
}
TestOperation(
source,
expected,
source,
expected,
(s, d) => Operations.PackFromXyzBytes(s, d, count)
);
);
}
[Theory]
@ -179,7 +179,7 @@ namespace ImageSharp.Tests.Colors
source,
expected,
(s, d) => Operations.ToXyzBytes(s, d, count)
);
);
}
[Theory]
@ -200,7 +200,7 @@ namespace ImageSharp.Tests.Colors
source,
expected,
(s, d) => Operations.PackFromXyzwBytes(s, d, count)
);
);
}
[Theory]
@ -220,7 +220,7 @@ namespace ImageSharp.Tests.Colors
source,
expected,
(s, d) => Operations.ToXyzwBytes(s, d, count)
);
);
}
[Theory]
@ -241,7 +241,7 @@ namespace ImageSharp.Tests.Colors
source,
expected,
(s, d) => Operations.PackFromZyxBytes(s, d, count)
);
);
}
[Theory]
@ -261,7 +261,7 @@ namespace ImageSharp.Tests.Colors
source,
expected,
(s, d) => Operations.ToZyxBytes(s, d, count)
);
);
}
[Theory]
@ -282,7 +282,7 @@ namespace ImageSharp.Tests.Colors
source,
expected,
(s, d) => Operations.PackFromZyxwBytes(s, d, count)
);
);
}
[Theory]
@ -302,26 +302,26 @@ namespace ImageSharp.Tests.Colors
source,
expected,
(s, d) => Operations.ToZyxwBytes(s, d, count)
);
);
}
private class TestBuffers<TSource, TDest> : IDisposable
where TSource : struct
where TDest : struct
{
public PinnedBuffer<TSource> SourceBuffer { get; }
public PinnedBuffer<TDest> ActualDestBuffer { get; }
public PinnedBuffer<TDest> ExpectedDestBuffer { get; }
public Buffer<TSource> SourceBuffer { get; }
public Buffer<TDest> ActualDestBuffer { get; }
public Buffer<TDest> ExpectedDestBuffer { get; }
public BufferSpan<TSource> Source => this.SourceBuffer;
public BufferSpan<TDest> ActualDest => this.ActualDestBuffer;
public TestBuffers(TSource[] source, TDest[] expectedDest)
{
this.SourceBuffer = new PinnedBuffer<TSource>(source);
this.ExpectedDestBuffer = new PinnedBuffer<TDest>(expectedDest);
this.ActualDestBuffer = new PinnedBuffer<TDest>(expectedDest.Length);
this.SourceBuffer = new Buffer<TSource>(source);
this.ExpectedDestBuffer = new Buffer<TDest>(expectedDest);
this.ActualDestBuffer = new Buffer<TDest>(expectedDest.Length);
}
public void Dispose()

8
tests/ImageSharp.Tests/Colors/ColorConstructorTests.cs

@ -30,7 +30,7 @@ namespace ImageSharp.Tests.Colors
// using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData
float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W };
yield return new object[] { new Argb(vector4), vector4Components };
yield return new object[] { new Argb32(vector4), vector4Components };
yield return new object[] { new Bgra4444(vector4), vector4Components };
yield return new object[] { new Bgra5551(vector4), vector4Components };
yield return new object[] { new Byte4(vector4), vector4Components };
@ -63,7 +63,7 @@ namespace ImageSharp.Tests.Colors
// using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData
float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W };
yield return new object[] { new Argb(vector3), vector4Components };
yield return new object[] { new Argb32(vector3), vector4Components };
yield return new object[] { new Bgr565(vector3), vector4Components };
}
}
@ -88,7 +88,7 @@ namespace ImageSharp.Tests.Colors
// using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData
float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W };
yield return new object[] { new Argb(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components };
yield return new object[] { new Argb32(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components };
yield return new object[] { new Bgra4444(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components };
yield return new object[] { new Bgra5551(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components };
yield return new object[] { new Byte4(vector4.X, vector4.Y, vector4.Z, vector4.W), vector4Components };
@ -121,7 +121,7 @@ namespace ImageSharp.Tests.Colors
// using float array to work around a bug in xunit corruptint the state of any Vector4 passed as MemberData
float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W };
yield return new object[] { new Argb(vector3.X, vector3.Y, vector3.Z), vector4Components };
yield return new object[] { new Argb32(vector3.X, vector3.Y, vector3.Z), vector4Components };
yield return new object[] { new Bgr565(vector3.X, vector3.Y, vector3.Z), vector4Components };
}
}

46
tests/ImageSharp.Tests/Colors/ColorEqualityTests.cs

@ -18,7 +18,7 @@ namespace ImageSharp.Tests.Colors
new TheoryData<object, object, Type>()
{
{ new Alpha8(.5F), new Alpha8(.5F), typeof(Alpha8) },
{ new Argb(Vector4.One), new Argb(Vector4.One), typeof(Argb) },
{ new Argb32(Vector4.One), new Argb32(Vector4.One), typeof(Argb32) },
{ new Bgr565(Vector3.One), new Bgr565(Vector3.One), typeof(Bgr565) },
{ new Bgra4444(Vector4.One), new Bgra4444(Vector4.One), typeof(Bgra4444) },
{ new Bgra5551(Vector4.One), new Bgra5551(Vector4.One), typeof(Bgra5551) },
@ -32,6 +32,7 @@ namespace ImageSharp.Tests.Colors
{ new NormalizedShort4(Vector4.One), new NormalizedShort4(Vector4.One), typeof(NormalizedShort4) },
{ new Rg32(Vector2.One), new Rg32(Vector2.One), typeof(Rg32) },
{ new Rgba1010102(Vector4.One), new Rgba1010102(Vector4.One), typeof(Rgba1010102) },
{ new Color(Vector4.One), new Color(Vector4.One), typeof(Color) },
{ new Rgba64(Vector4.One), new Rgba64(Vector4.One), typeof(Rgba64) },
{ new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.One * 0x7FFF), typeof(Short2) },
{ new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.One * 0x7FFF), typeof(Short4) },
@ -42,7 +43,7 @@ namespace ImageSharp.Tests.Colors
{
// Valid object against null
{ new Alpha8(.5F), null, typeof(Alpha8) },
{ new Argb(Vector4.One), null, typeof(Argb) },
{ new Argb32(Vector4.One), null, typeof(Argb32) },
{ new Bgr565(Vector3.One), null, typeof(Bgr565) },
{ new Bgra4444(Vector4.One), null, typeof(Bgra4444) },
{ new Bgra5551(Vector4.One), null, typeof(Bgra5551) },
@ -65,7 +66,7 @@ namespace ImageSharp.Tests.Colors
new TheoryData<object, object, Type>()
{
// Valid objects of different types but not equal
{ new Alpha8(.5F), new Argb(Vector4.Zero), null },
{ new Alpha8(.5F), new Argb32(Vector4.Zero), null },
{ new HalfSingle(-1F), new NormalizedShort2(Vector2.Zero), null },
{ new Rgba1010102(Vector4.One), new Bgra5551(Vector4.Zero), null },
};
@ -75,7 +76,7 @@ namespace ImageSharp.Tests.Colors
{
// Valid objects of the same type but not equal
{ new Alpha8(.5F), new Alpha8(.8F), typeof(Alpha8) },
{ new Argb(Vector4.One), new Argb(Vector4.Zero), typeof(Argb) },
{ new Argb32(Vector4.One), new Argb32(Vector4.Zero), typeof(Argb32) },
{ new Bgr565(Vector3.One), new Bgr565(Vector3.Zero), typeof(Bgr565) },
{ new Bgra4444(Vector4.One), new Bgra4444(Vector4.Zero), typeof(Bgra4444) },
{ new Bgra5551(Vector4.One), new Bgra5551(Vector4.Zero), typeof(Bgra5551) },
@ -89,6 +90,7 @@ namespace ImageSharp.Tests.Colors
{ new NormalizedShort4(Vector4.One), new NormalizedShort4(Vector4.Zero), typeof(NormalizedShort4) },
{ new Rg32(Vector2.One), new Rg32(Vector2.Zero), typeof(Rg32) },
{ new Rgba1010102(Vector4.One), new Rgba1010102(Vector4.Zero), typeof(Rgba1010102) },
{ new Color(Vector4.One), new Color(Vector4.Zero), typeof(Color) },
{ new Rgba64(Vector4.One), new Rgba64(Vector4.Zero), typeof(Rgba64) },
{ new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.Zero), typeof(Short2) },
{ new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.Zero), typeof(Short4) },
@ -211,5 +213,41 @@ namespace ImageSharp.Tests.Colors
// Assert
Assert.True(notEqual);
}
[Theory]
[MemberData(nameof(AlmostEqualsData))]
public void AlmostEquals(object first, object second, Type type, float precision)
{
// Arrange
// Cast to the known object types, this is so that we can hit the
// equality operator on the concrete type, otherwise it goes to the
// default "object" one :)
dynamic firstObject = Convert.ChangeType(first, type);
dynamic secondObject = Convert.ChangeType(second, type);
// Act
dynamic almostEqual = firstObject.AlmostEquals(secondObject, precision);
// Assert
Assert.True(almostEqual);
}
[Theory]
[MemberData(nameof(AlmostNotEqualsData))]
public void AlmostNotEquals(object first, object second, Type type, float precision)
{
// Arrange
// Cast to the known object types, this is so that we can hit the
// equality operator on the concrete type, otherwise it goes to the
// default "object" one :)
dynamic firstObject = Convert.ChangeType(first, type);
dynamic secondObject = Convert.ChangeType(second, type);
// Act
dynamic almostEqual = firstObject.AlmostEquals(secondObject, precision);
// Assert
Assert.False(almostEqual);
}
}
}

4
tests/ImageSharp.Tests/Colors/ColorPackingTests.cs

@ -29,7 +29,7 @@ namespace ImageSharp.Tests.Colors
{
float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W };
yield return new object[] { new Argb(), vector4Components };
yield return new object[] { new Argb32(), vector4Components };
yield return new object[] { new Bgra4444(), vector4Components };
yield return new object[] { new Bgra5551(), vector4Components };
yield return new object[] { new Byte4(), vector4Components };
@ -60,7 +60,7 @@ namespace ImageSharp.Tests.Colors
{
float[] vector4Components = new float[] { vector4.X, vector4.Y, vector4.Z, vector4.W };
yield return new object[] { new Argb(), vector4Components };
yield return new object[] { new Argb32(), vector4Components };
yield return new object[] { new Bgr565(), vector4Components };
}
}

2
tests/ImageSharp.Tests/Colors/ColorTests.cs

@ -124,6 +124,8 @@ namespace ImageSharp.Tests
Assert.Equal(2, colorBase[1]);
Assert.Equal(3, colorBase[2]);
Assert.Equal(4, colorBase[3]);
Assert.Equal(4, sizeof(Color));
}
}
}

132
tests/ImageSharp.Tests/Colors/ColorVectorTests.cs

@ -0,0 +1,132 @@
// <copyright file="ColorVectorTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Tests
{
using System.Numerics;
using System.Runtime.CompilerServices;
using Xunit;
/// <summary>
/// Tests the <see cref="ColorVector"/> struct.
/// </summary>
public class ColorVectorTests
{
/// <summary>
/// Tests the equality operators for equality.
/// </summary>
[Fact]
public void AreEqual()
{
ColorVector color1 = new ColorVector(0, 0, 0F);
ColorVector color2 = new ColorVector(0, 0, 0, 1F);
ColorVector color3 = ColorVector.FromHex("#000");
ColorVector color4 = ColorVector.FromHex("#000F");
ColorVector color5 = ColorVector.FromHex("#000000");
ColorVector color6 = ColorVector.FromHex("#000000FF");
Assert.Equal(color1, color2);
Assert.Equal(color1, color3);
Assert.Equal(color1, color4);
Assert.Equal(color1, color5);
Assert.Equal(color1, color6);
}
/// <summary>
/// Tests the equality operators for inequality.
/// </summary>
[Fact]
public void AreNotEqual()
{
ColorVector color1 = new ColorVector(1, 0, 0, 1);
ColorVector color2 = new ColorVector(0, 0, 0, 1);
ColorVector color3 = ColorVector.FromHex("#000");
ColorVector color4 = ColorVector.FromHex("#000000");
ColorVector color5 = ColorVector.FromHex("#FF000000");
Assert.NotEqual(color1, color2);
Assert.NotEqual(color1, color3);
Assert.NotEqual(color1, color4);
Assert.NotEqual(color1, color5);
}
/// <summary>
/// Tests whether the color constructor correctly assign properties.
/// </summary>
[Fact]
public void ConstructorAssignsProperties()
{
ColorVector color1 = new ColorVector(1, .1F, .133F, .864F);
Assert.Equal(1F, color1.R);
Assert.Equal(.1F, color1.G);
Assert.Equal(.133F, color1.B);
Assert.Equal(.864F, color1.A);
ColorVector color2 = new ColorVector(1, .1f, .133f);
Assert.Equal(1F, color2.R);
Assert.Equal(.1F, color2.G);
Assert.Equal(.133F, color2.B);
Assert.Equal(1F, color2.A);
ColorVector color4 = new ColorVector(new Vector3(1, .1f, .133f));
Assert.Equal(1F, color4.R);
Assert.Equal(.1F, color4.G);
Assert.Equal(.133F, color4.B);
Assert.Equal(1F, color4.A);
ColorVector color5 = new ColorVector(new Vector4(1, .1f, .133f, .5f));
Assert.Equal(1F, color5.R);
Assert.Equal(.1F, color5.G);
Assert.Equal(.133F, color5.B);
Assert.Equal(.5F, color5.A);
}
/// <summary>
/// Tests whether FromHex and ToHex work correctly.
/// </summary>
[Fact]
public void FromAndToHex()
{
ColorVector color = ColorVector.FromHex("#AABBCCDD");
Assert.Equal(170 / 255F, color.R);
Assert.Equal(187 / 255F, color.G);
Assert.Equal(204 / 255F, color.B);
Assert.Equal(221 / 255F, color.A);
color.A = 170 / 255F;
color.B = 187 / 255F;
color.G = 204 / 255F;
color.R = 221 / 255F;
Assert.Equal("DDCCBBAA", color.ToHex());
color.R = 0;
Assert.Equal("00CCBBAA", color.ToHex());
color.A = 255 / 255F;
Assert.Equal("00CCBBFF", color.ToHex());
}
/// <summary>
/// Tests that the individual float elements are layed out in RGBA order.
/// </summary>
[Fact]
public void FloatLayout()
{
ColorVector color = new ColorVector(1F, 2, 3, 4);
Vector4 colorBase = Unsafe.As<ColorVector, Vector4>(ref Unsafe.Add(ref color, 0));
float[] ordered = new float[4];
colorBase.CopyTo(ordered);
Assert.Equal(1, ordered[0]);
Assert.Equal(2, ordered[1]);
Assert.Equal(3, ordered[2]);
Assert.Equal(4, ordered[3]);
}
}
}

118
tests/ImageSharp.Tests/Colors/ColorVectorTransformTests.cs

@ -0,0 +1,118 @@
// <copyright file="ColorVectorTransformTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Tests.Colors
{
using Xunit;
/// <summary>
/// Tests the color transform algorithms. Test results match the output of CSS equivalents.
/// <see href="https://jsfiddle.net/jamessouth/L1v8r6kh/"/>
/// </summary>
public class ColorVectorTransformTests
{
private static readonly ApproximateFloatComparer FloatComparer = new ApproximateFloatComparer(0.01F);
/// <summary>
/// Orange backdrop
/// </summary>
private static readonly ColorVector Backdrop = new ColorVector(204, 102, 0);
/// <summary>
/// Blue source
/// </summary>
private static readonly ColorVector Source = new ColorVector(0, 102, 153);
[Fact]
public void Normal()
{
ColorVector normal = ColorVector.Normal(Backdrop, Source);
Assert.True(normal == Source);
}
[Fact]
public void Multiply()
{
Assert.Equal(ColorVector.Multiply(Backdrop, ColorVector.Black).ToVector4(), Color.Black.ToVector4(), FloatComparer);
Assert.Equal(ColorVector.Multiply(Backdrop, ColorVector.White).ToVector4(), Backdrop.ToVector4(), FloatComparer);
ColorVector multiply = ColorVector.Multiply(Backdrop, Source);
Assert.Equal(multiply.ToVector4(), new ColorVector(0, 41, 0).ToVector4(), FloatComparer);
}
[Fact]
public void Screen()
{
Assert.Equal(ColorVector.Screen(Backdrop, ColorVector.Black).ToVector4(), Backdrop.ToVector4(), FloatComparer);
Assert.Equal(ColorVector.Screen(Backdrop, ColorVector.White).ToVector4(), ColorVector.White.ToVector4(), FloatComparer);
ColorVector screen = ColorVector.Screen(Backdrop, Source);
Assert.Equal(screen.ToVector4(), new ColorVector(204, 163, 153).ToVector4(), FloatComparer);
}
[Fact]
public void HardLight()
{
ColorVector hardLight = ColorVector.HardLight(Backdrop, Source);
Assert.Equal(hardLight.ToVector4(), new ColorVector(0, 82, 51).ToVector4(), FloatComparer);
}
[Fact]
public void Overlay()
{
ColorVector overlay = ColorVector.Overlay(Backdrop, Source);
Assert.Equal(overlay.ToVector4(), new ColorVector(153, 82, 0).ToVector4(), FloatComparer);
}
[Fact]
public void Darken()
{
ColorVector darken = ColorVector.Darken(Backdrop, Source);
Assert.Equal(darken.ToVector4(), new ColorVector(0, 102, 0).ToVector4(), FloatComparer);
}
[Fact]
public void Lighten()
{
ColorVector lighten = ColorVector.Lighten(Backdrop, Source);
Assert.Equal(lighten.ToVector4(), new ColorVector(204, 102, 153).ToVector4(), FloatComparer);
}
[Fact]
public void SoftLight()
{
ColorVector softLight = ColorVector.SoftLight(Backdrop, Source);
Assert.Equal(softLight.ToVector4(), new ColorVector(163, 90, 0).ToVector4(), FloatComparer);
}
[Fact]
public void ColorDodge()
{
ColorVector colorDodge = ColorVector.ColorDodge(Backdrop, Source);
Assert.Equal(colorDodge.ToVector4(), new ColorVector(204, 170, 0).ToVector4(), FloatComparer);
}
[Fact]
public void ColorBurn()
{
ColorVector colorBurn = ColorVector.ColorBurn(Backdrop, Source);
Assert.Equal(colorBurn.ToVector4(), new ColorVector(0, 0, 0).ToVector4(), FloatComparer);
}
[Fact]
public void Difference()
{
ColorVector difference = ColorVector.Difference(Backdrop, Source);
Assert.Equal(difference.ToVector4(), new ColorVector(204, 0, 153).ToVector4(), FloatComparer);
}
[Fact]
public void Exclusion()
{
ColorVector exclusion = ColorVector.Exclusion(Backdrop, Source);
Assert.Equal(exclusion.ToVector4(), new ColorVector(204, 122, 153).ToVector4(), FloatComparer);
}
}
}

69
tests/ImageSharp.Tests/Colors/PackedPixelTests.cs

@ -62,29 +62,29 @@ namespace ImageSharp.Tests.Colors
}
[Fact]
public void Argb()
public void Argb32()
{
// Test the limits.
Assert.Equal((uint)0x0, new Argb(Vector4.Zero).PackedValue);
Assert.Equal(0xFFFFFFFF, new Argb(Vector4.One).PackedValue);
Assert.Equal((uint)0x0, new Argb32(Vector4.Zero).PackedValue);
Assert.Equal(0xFFFFFFFF, new Argb32(Vector4.One).PackedValue);
// Test ToVector4.
Assert.True(Equal(Vector4.One, new Argb(Vector4.One).ToVector4()));
Assert.True(Equal(Vector4.Zero, new Argb(Vector4.Zero).ToVector4()));
Assert.True(Equal(Vector4.UnitX, new Argb(Vector4.UnitX).ToVector4()));
Assert.True(Equal(Vector4.UnitY, new Argb(Vector4.UnitY).ToVector4()));
Assert.True(Equal(Vector4.UnitZ, new Argb(Vector4.UnitZ).ToVector4()));
Assert.True(Equal(Vector4.UnitW, new Argb(Vector4.UnitW).ToVector4()));
Assert.True(Equal(Vector4.One, new Argb32(Vector4.One).ToVector4()));
Assert.True(Equal(Vector4.Zero, new Argb32(Vector4.Zero).ToVector4()));
Assert.True(Equal(Vector4.UnitX, new Argb32(Vector4.UnitX).ToVector4()));
Assert.True(Equal(Vector4.UnitY, new Argb32(Vector4.UnitY).ToVector4()));
Assert.True(Equal(Vector4.UnitZ, new Argb32(Vector4.UnitZ).ToVector4()));
Assert.True(Equal(Vector4.UnitW, new Argb32(Vector4.UnitW).ToVector4()));
// Test clamping.
Assert.True(Equal(Vector4.Zero, new Argb(Vector4.One * -1234.0f).ToVector4()));
Assert.True(Equal(Vector4.One, new Argb(Vector4.One * +1234.0f).ToVector4()));
Assert.True(Equal(Vector4.Zero, new Argb32(Vector4.One * -1234.0f).ToVector4()));
Assert.True(Equal(Vector4.One, new Argb32(Vector4.One * +1234.0f).ToVector4()));
float x = +0.1f;
float y = -0.3f;
float z = +0.5f;
float w = -0.7f;
Argb argb = new Argb(x, y, z, w);
Argb32 argb = new Argb32(x, y, z, w);
Assert.Equal(0x001a0080u, argb.PackedValue);
// Test ordering
@ -711,6 +711,51 @@ namespace ImageSharp.Tests.Colors
Assert.Equal(rgba, new byte[] { 25, 0, 128, 0 });
}
[Fact]
public void Color()
{
// Test the limits.
Assert.Equal((uint)0x0, new Color(Vector4.Zero).PackedValue);
Assert.Equal(0xFFFFFFFF, new Color(Vector4.One).PackedValue);
// Test ToVector4.
Assert.True(Equal(Vector4.One, new Color(Vector4.One).ToVector4()));
Assert.True(Equal(Vector4.Zero, new Color(Vector4.Zero).ToVector4()));
Assert.True(Equal(Vector4.UnitX, new Color(Vector4.UnitX).ToVector4()));
Assert.True(Equal(Vector4.UnitY, new Color(Vector4.UnitY).ToVector4()));
Assert.True(Equal(Vector4.UnitZ, new Color(Vector4.UnitZ).ToVector4()));
Assert.True(Equal(Vector4.UnitW, new Color(Vector4.UnitW).ToVector4()));
// Test clamping.
Assert.True(Equal(Vector4.Zero, new Color(Vector4.One * -1234.0f).ToVector4()));
Assert.True(Equal(Vector4.One, new Color(Vector4.One * +1234.0f).ToVector4()));
float x = +0.1f;
float y = -0.3f;
float z = +0.5f;
float w = -0.7f;
Color rgba32 = new Color(x, y, z, w);
Assert.Equal(0x80001Au, rgba32.PackedValue);
// Test ordering
byte[] rgb = new byte[3];
byte[] rgba = new byte[4];
byte[] bgr = new byte[3];
byte[] bgra = new byte[4];
rgba32.ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 0x1a, 0, 0x80 });
rgba32.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 0x1a, 0, 0x80, 0 });
rgba32.ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0x80, 0, 0x1a });
rgba32.ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0x80, 0, 0x1a, 0 });
}
[Fact]
public void Rgba64()
{

148
tests/ImageSharp.Tests/Colors/UnPackedPixelTests.cs

@ -0,0 +1,148 @@
namespace ImageSharp.Tests.Colors
{
using System.Numerics;
using Xunit;
public class UnPackedPixelTests
{
[Fact]
public void Color_Types_From_Bytes_Produce_Equal_Scaled_Component_OutPut()
{
Color color = new Color(24, 48, 96, 192);
ColorVector colorVector = new ColorVector(24, 48, 96, 192);
Assert.Equal(color.R, (byte)(colorVector.R * 255));
Assert.Equal(color.G, (byte)(colorVector.G * 255));
Assert.Equal(color.B, (byte)(colorVector.B * 255));
Assert.Equal(color.A, (byte)(colorVector.A * 255));
}
[Fact]
public void Color_Types_From_Floats_Produce_Equal_Scaled_Component_OutPut()
{
Color color = new Color(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F);
ColorVector colorVector = new ColorVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F);
Assert.Equal(color.R, (byte)(colorVector.R * 255));
Assert.Equal(color.G, (byte)(colorVector.G * 255));
Assert.Equal(color.B, (byte)(colorVector.B * 255));
Assert.Equal(color.A, (byte)(colorVector.A * 255));
}
[Fact]
public void Color_Types_From_Vector4_Produce_Equal_Scaled_Component_OutPut()
{
Color color = new Color(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F));
ColorVector colorVector = new ColorVector(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F));
Assert.Equal(color.R, (byte)(colorVector.R * 255));
Assert.Equal(color.G, (byte)(colorVector.G * 255));
Assert.Equal(color.B, (byte)(colorVector.B * 255));
Assert.Equal(color.A, (byte)(colorVector.A * 255));
}
[Fact]
public void Color_Types_From_Vector3_Produce_Equal_Scaled_Component_OutPut()
{
Color color = new Color(new Vector3(24 / 255F, 48 / 255F, 96 / 255F));
ColorVector colorVector = new ColorVector(new Vector3(24 / 255F, 48 / 255F, 96 / 255F));
Assert.Equal(color.R, (byte)(colorVector.R * 255));
Assert.Equal(color.G, (byte)(colorVector.G * 255));
Assert.Equal(color.B, (byte)(colorVector.B * 255));
Assert.Equal(color.A, (byte)(colorVector.A * 255));
}
[Fact]
public void Color_Types_From_Hex_Produce_Equal_Scaled_Component_OutPut()
{
Color color = Color.FromHex("183060C0");
ColorVector colorVector = ColorVector.FromHex("183060C0");
Assert.Equal(color.R, (byte)(colorVector.R * 255));
Assert.Equal(color.G, (byte)(colorVector.G * 255));
Assert.Equal(color.B, (byte)(colorVector.B * 255));
Assert.Equal(color.A, (byte)(colorVector.A * 255));
}
[Fact]
public void Color_Types_To_Vector4_Produce_Equal_OutPut()
{
Color color = new Color(24, 48, 96, 192);
ColorVector colorVector = new ColorVector(24, 48, 96, 192);
Assert.Equal(color.ToVector4(), colorVector.ToVector4());
}
[Fact]
public void Color_Types_To_RgbBytes_Produce_Equal_OutPut()
{
Color color = new Color(24, 48, 96, 192);
ColorVector colorVector = new ColorVector(24, 48, 96, 192);
byte[] rgb = new byte[3];
byte[] rgbVector = new byte[3];
color.ToXyzBytes(rgb, 0);
colorVector.ToXyzBytes(rgbVector, 0);
Assert.Equal(rgb, rgbVector);
}
[Fact]
public void Color_Types_To_RgbaBytes_Produce_Equal_OutPut()
{
Color color = new Color(24, 48, 96, 192);
ColorVector colorVector = new ColorVector(24, 48, 96, 192);
byte[] rgba = new byte[4];
byte[] rgbaVector = new byte[4];
color.ToXyzwBytes(rgba, 0);
colorVector.ToXyzwBytes(rgbaVector, 0);
Assert.Equal(rgba, rgbaVector);
}
[Fact]
public void Color_Types_To_BgrBytes_Produce_Equal_OutPut()
{
Color color = new Color(24, 48, 96, 192);
ColorVector colorVector = new ColorVector(24, 48, 96, 192);
byte[] bgr = new byte[3];
byte[] bgrVector = new byte[3];
color.ToZyxBytes(bgr, 0);
colorVector.ToZyxBytes(bgrVector, 0);
Assert.Equal(bgr, bgrVector);
}
[Fact]
public void Color_Types_To_BgraBytes_Produce_Equal_OutPut()
{
Color color = new Color(24, 48, 96, 192);
ColorVector colorVector = new ColorVector(24, 48, 96, 192);
byte[] bgra = new byte[4];
byte[] bgraVector = new byte[4];
color.ToZyxwBytes(bgra, 0);
colorVector.ToZyxwBytes(bgraVector, 0);
Assert.Equal(bgra, bgraVector);
}
[Fact]
public void Color_Types_To_Hex_Produce_Equal_OutPut()
{
Color color = new Color(24, 48, 96, 192);
ColorVector colorVector = new ColorVector(24, 48, 96, 192);
// 183060C0
Assert.Equal(color.ToHex(), colorVector.ToHex());
}
}
}

32
tests/ImageSharp.Tests/Common/PinnedImageBufferTests.cs → tests/ImageSharp.Tests/Common/Buffer2DTests.cs

@ -1,20 +1,34 @@
// ReSharper disable InconsistentNaming
namespace ImageSharp.Tests.Common
{
using System;
using System.Runtime.CompilerServices;
using Xunit;
using static TestStructs;
public unsafe class PinnedImageBufferTests
public unsafe class Buffer2DTests
{
// ReSharper disable once ClassNeverInstantiated.Local
private class Assert : Xunit.Assert
{
public static void SpanPointsTo<T>(BufferSpan<T> span, Buffer<T> buffer, int bufferOffset = 0)
where T : struct
{
ref T actual = ref span.DangerousGetPinnableReference();
ref T expected = ref Unsafe.Add(ref buffer[0], bufferOffset);
Assert.True(Unsafe.AreSame(ref expected, ref actual), "span does not point to the expected position");
}
}
[Theory]
[InlineData(7, 42)]
[InlineData(1025, 17)]
public void Construct(int width, int height)
{
using (PinnedImageBuffer<Foo> buffer = new PinnedImageBuffer<Foo>(width, height))
using (Buffer2D<Foo> buffer = new Buffer2D<Foo>(width, height))
{
Assert.Equal(width, buffer.Width);
Assert.Equal(height, buffer.Height);
@ -28,7 +42,7 @@ namespace ImageSharp.Tests.Common
public void Construct_FromExternalArray(int width, int height)
{
Foo[] array = new Foo[width * height + 10];
using (PinnedImageBuffer<Foo> buffer = new PinnedImageBuffer<Foo>(array, width, height))
using (Buffer2D<Foo> buffer = new Buffer2D<Foo>(array, width, height))
{
Assert.Equal(width, buffer.Width);
Assert.Equal(height, buffer.Height);
@ -42,7 +56,7 @@ namespace ImageSharp.Tests.Common
{
for (int i = 0; i < 100; i++)
{
using (PinnedImageBuffer<int> buffer = PinnedImageBuffer<int>.CreateClean(42, 42))
using (Buffer2D<int> buffer = Buffer2D<int>.CreateClean(42, 42))
{
for (int j = 0; j < buffer.Length; j++)
{
@ -59,13 +73,13 @@ namespace ImageSharp.Tests.Common
[InlineData(17, 42, 41)]
public void GetRowSpanY(int width, int height, int y)
{
using (PinnedImageBuffer<Foo> buffer = new PinnedImageBuffer<Foo>(width, height))
using (Buffer2D<Foo> buffer = new Buffer2D<Foo>(width, height))
{
BufferSpan<Foo> span = buffer.GetRowSpan(y);
Assert.Equal(width * y, span.Start);
Assert.Equal(width, span.Length);
Assert.Equal(buffer.Pointer + sizeof(Foo) * width * y, span.PointerAtOffset);
Assert.SpanPointsTo(span, buffer, width * y);
}
}
@ -75,13 +89,13 @@ namespace ImageSharp.Tests.Common
[InlineData(17, 42, 0, 41)]
public void GetRowSpanXY(int width, int height, int x, int y)
{
using (PinnedImageBuffer<Foo> buffer = new PinnedImageBuffer<Foo>(width, height))
using (Buffer2D<Foo> buffer = new Buffer2D<Foo>(width, height))
{
BufferSpan<Foo> span = buffer.GetRowSpan(x, y);
Assert.Equal(width * y + x, span.Start);
Assert.Equal(width - x, span.Length);
Assert.Equal(buffer.Pointer + sizeof(Foo) * (width * y + x), span.PointerAtOffset);
Assert.SpanPointsTo(span, buffer, width * y + x);
}
}
@ -91,7 +105,7 @@ namespace ImageSharp.Tests.Common
[InlineData(99, 88, 98, 87)]
public void Indexer(int width, int height, int x, int y)
{
using (PinnedImageBuffer<Foo> buffer = new PinnedImageBuffer<Foo>(width, height))
using (Buffer2D<Foo> buffer = new Buffer2D<Foo>(width, height))
{
Foo[] array = buffer.Array;

273
tests/ImageSharp.Tests/Common/BufferSpanTests.cs

@ -1,5 +1,6 @@
// ReSharper disable ObjectCreationAsStatement
// ReSharper disable InconsistentNaming
namespace ImageSharp.Tests.Common
{
using System;
@ -11,18 +12,30 @@ namespace ImageSharp.Tests.Common
public unsafe class BufferSpanTests
{
// ReSharper disable once ClassNeverInstantiated.Local
private class Assert : Xunit.Assert
{
public static void SameRefs<T1, T2>(ref T1 a, ref T2 b)
{
ref T1 bb = ref Unsafe.As<T2, T1>(ref b);
True(Unsafe.AreSame(ref a, ref bb), "References are not same!");
}
}
[Fact]
public void AsBytes()
{
Foo[] fooz = { new Foo(1, 2), new Foo(3, 4), new Foo(5, 6) };
using (PinnedBuffer<Foo> colorBuf = new PinnedBuffer<Foo>(fooz))
using (Buffer<Foo> colorBuf = new Buffer<Foo>(fooz))
{
BufferSpan<Foo> orig = colorBuf.Slice(1);
BufferSpan<byte> asBytes = (BufferSpan < byte > )orig;
BufferSpan<byte> asBytes = orig.AsBytes();
Assert.Equal(asBytes.Start, sizeof(Foo));
Assert.Equal(orig.PointerAtOffset, asBytes.PointerAtOffset);
Assert.Equal(orig.Length * Unsafe.SizeOf<Foo>(), asBytes.Length);
Assert.SameRefs(ref orig.DangerousGetPinnableReference(), ref asBytes.DangerousGetPinnableReference());
}
}
@ -32,16 +45,14 @@ namespace ImageSharp.Tests.Common
public void Basic()
{
Foo[] array = Foo.CreateArray(3);
fixed (Foo* p = array)
{
// Act:
BufferSpan<Foo> span = new BufferSpan<Foo>(array, p);
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal((IntPtr)p, span.PointerAtOffset);
Assert.Equal(3, span.Length);
}
// Act:
BufferSpan<Foo> span = new BufferSpan<Foo>(array);
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(3, span.Length);
Assert.SameRefs(ref array[0], ref span.DangerousGetPinnableReference());
}
[Fact]
@ -49,17 +60,15 @@ namespace ImageSharp.Tests.Common
{
Foo[] array = Foo.CreateArray(4);
int start = 2;
fixed (Foo* p = array)
{
// Act:
BufferSpan<Foo> span = new BufferSpan<Foo>(array, p, start);
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(start, span.Start);
Assert.Equal((IntPtr)(p + start), span.PointerAtOffset);
Assert.Equal(array.Length - start, span.Length);
}
// Act:
BufferSpan<Foo> span = new BufferSpan<Foo>(array, start);
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(start, span.Start);
Assert.SameRefs(ref array[start], ref span.DangerousGetPinnableReference());
Assert.Equal(array.Length - start, span.Length);
}
[Fact]
@ -68,17 +77,14 @@ namespace ImageSharp.Tests.Common
Foo[] array = Foo.CreateArray(10);
int start = 2;
int length = 3;
fixed (Foo* p = array)
{
// Act:
BufferSpan<Foo> span = new BufferSpan<Foo>(array, p, start, length);
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(start, span.Start);
Assert.Equal((IntPtr)(p + start), span.PointerAtOffset);
Assert.Equal(length, span.Length);
}
// Act:
BufferSpan<Foo> span = new BufferSpan<Foo>(array, start, length);
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(start, span.Start);
Assert.SameRefs(ref array[start], ref span.DangerousGetPinnableReference());
Assert.Equal(length, span.Length);
}
}
@ -92,19 +98,16 @@ namespace ImageSharp.Tests.Common
int start1 = 2;
int totalOffset = start0 + start1;
fixed (Foo* p = array)
{
BufferSpan<Foo> span = new BufferSpan<Foo>(array, p, start0);
BufferSpan<Foo> span = new BufferSpan<Foo>(array, start0);
// Act:
span = span.Slice(start1);
// Act:
span = span.Slice(start1);
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(totalOffset, span.Start);
Assert.Equal((IntPtr)(p + totalOffset), span.PointerAtOffset);
Assert.Equal(array.Length - totalOffset, span.Length);
}
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(totalOffset, span.Start);
Assert.SameRefs(ref array[totalOffset], ref span.DangerousGetPinnableReference());
Assert.Equal(array.Length - totalOffset, span.Length);
}
[Fact]
@ -116,24 +119,19 @@ namespace ImageSharp.Tests.Common
int totalOffset = start0 + start1;
int sliceLength = 3;
fixed (Foo* p = array)
{
BufferSpan<Foo> span = new BufferSpan<Foo>(array, p, start0);
BufferSpan<Foo> span = new BufferSpan<Foo>(array, start0);
// Act:
span = span.Slice(start1, sliceLength);
// Act:
span = span.Slice(start1, sliceLength);
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(totalOffset, span.Start);
Assert.Equal((IntPtr)(p + totalOffset), span.PointerAtOffset);
Assert.Equal(sliceLength, span.Length);
}
// Assert:
Assert.Equal(array, span.Array);
Assert.Equal(totalOffset, span.Start);
Assert.SameRefs(ref array[totalOffset], ref span.DangerousGetPinnableReference());
Assert.Equal(sliceLength, span.Length);
}
}
[Theory]
[InlineData(4)]
[InlineData(1500)]
@ -142,21 +140,17 @@ namespace ImageSharp.Tests.Common
Foo[] array = Foo.CreateArray(count + 42);
int offset = 2;
fixed (Foo* p = array)
{
BufferSpan<Foo> ap = new BufferSpan<Foo>(array, p, offset);
BufferSpan<Foo> ap = new BufferSpan<Foo>(array, offset);
// Act:
ap.Clear(count);
// Act:
ap.Clear(count);
Assert.NotEqual(default(Foo), array[offset-1]);
Assert.Equal(default(Foo), array[offset]);
Assert.Equal(default(Foo), array[offset + count-1]);
Assert.NotEqual(default(Foo), array[offset + count]);
}
Assert.NotEqual(default(Foo), array[offset - 1]);
Assert.Equal(default(Foo), array[offset]);
Assert.Equal(default(Foo), array[offset + count - 1]);
Assert.NotEqual(default(Foo), array[offset + count]);
}
public class Indexer
{
public static readonly TheoryData<int, int, int> IndexerData =
@ -175,14 +169,11 @@ namespace ImageSharp.Tests.Common
public void Read(int length, int start, int index)
{
Foo[] a = Foo.CreateArray(length);
fixed (Foo* p = a)
{
BufferSpan<Foo> span = new BufferSpan<Foo>(a, p, start);
BufferSpan<Foo> span = new BufferSpan<Foo>(a, start);
Foo element = span[index];
Foo element = span[index];
Assert.Equal(a[start + index], element);
}
Assert.Equal(a[start + index], element);
}
[Theory]
@ -190,17 +181,46 @@ namespace ImageSharp.Tests.Common
public void Write(int length, int start, int index)
{
Foo[] a = Foo.CreateArray(length);
fixed (Foo* p = a)
{
BufferSpan<Foo> span = new BufferSpan<Foo>(a, p, start);
BufferSpan<Foo> span = new BufferSpan<Foo>(a, start);
span[index] = new Foo(666, 666);
span[index] = new Foo(666, 666);
Assert.Equal(new Foo(666, 666), a[start + index]);
}
Assert.Equal(new Foo(666, 666), a[start + index]);
}
[Theory]
[InlineData(10, 0, 0, 5)]
[InlineData(10, 1, 1, 5)]
[InlineData(10, 1, 1, 6)]
[InlineData(10, 1, 1, 7)]
public void AsBytes_Read(int length, int start, int index, int byteOffset)
{
Foo[] a = Foo.CreateArray(length);
BufferSpan<Foo> span = new BufferSpan<Foo>(a, start);
BufferSpan<byte> bytes = span.AsBytes();
byte actual = bytes[index * Unsafe.SizeOf<Foo>() + byteOffset];
ref byte baseRef = ref Unsafe.As<Foo, byte>(ref a[0]);
byte expected = Unsafe.Add(ref baseRef, (start + index) * Unsafe.SizeOf<Foo>() + byteOffset);
Assert.Equal(expected, actual);
}
}
[Theory]
[InlineData(0, 4)]
[InlineData(2, 4)]
[InlineData(3, 4)]
public void DangerousGetPinnableReference(int start, int length)
{
Foo[] a = Foo.CreateArray(length);
BufferSpan<Foo> span = new BufferSpan<Foo>(a, start);
ref Foo r = ref span.DangerousGetPinnableReference();
Assert.True(Unsafe.AreSame(ref a[start], ref r));
}
public class Copy
{
@ -238,14 +258,10 @@ namespace ImageSharp.Tests.Common
Foo[] source = Foo.CreateArray(count + 2);
Foo[] dest = new Foo[count + 5];
fixed (Foo* pSource = source)
fixed (Foo* pDest = dest)
{
BufferSpan<Foo> apSource = new BufferSpan<Foo>(source, pSource, 1);
BufferSpan<Foo> apDest = new BufferSpan<Foo>(dest, pDest, 1);
BufferSpan<Foo> apSource = new BufferSpan<Foo>(source, 1);
BufferSpan<Foo> apDest = new BufferSpan<Foo>(dest, 1);
BufferSpan.Copy(apSource, apDest, count-1);
}
BufferSpan.Copy(apSource, apDest, count - 1);
AssertNotDefault(source, 1);
AssertNotDefault(dest, 1);
@ -253,7 +269,7 @@ namespace ImageSharp.Tests.Common
Assert.NotEqual(source[0], dest[0]);
Assert.Equal(source[1], dest[1]);
Assert.Equal(source[2], dest[2]);
Assert.Equal(source[count-1], dest[count-1]);
Assert.Equal(source[count - 1], dest[count - 1]);
Assert.NotEqual(source[count], dest[count]);
}
@ -265,14 +281,10 @@ namespace ImageSharp.Tests.Common
AlignedFoo[] source = AlignedFoo.CreateArray(count + 2);
AlignedFoo[] dest = new AlignedFoo[count + 5];
fixed (AlignedFoo* pSource = source)
fixed (AlignedFoo* pDest = dest)
{
BufferSpan<AlignedFoo> apSource = new BufferSpan<AlignedFoo>(source, pSource, 1);
BufferSpan<AlignedFoo> apDest = new BufferSpan<AlignedFoo>(dest, pDest, 1);
BufferSpan<AlignedFoo> apSource = new BufferSpan<AlignedFoo>(source, 1);
BufferSpan<AlignedFoo> apDest = new BufferSpan<AlignedFoo>(dest, 1);
BufferSpan.Copy(apSource, apDest, count - 1);
}
BufferSpan.Copy(apSource, apDest, count - 1);
AssertNotDefault(source, 1);
AssertNotDefault(dest, 1);
@ -289,17 +301,13 @@ namespace ImageSharp.Tests.Common
[InlineData(1500)]
public void IntToInt(int count)
{
int[] source = CreateTestInts(count+2);
int[] source = CreateTestInts(count + 2);
int[] dest = new int[count + 5];
fixed (int* pSource = source)
fixed (int* pDest = dest)
{
BufferSpan<int> apSource = new BufferSpan<int>(source, pSource, 1);
BufferSpan<int> apDest = new BufferSpan<int>(dest, pDest, 1);
BufferSpan<int> apSource = new BufferSpan<int>(source, 1);
BufferSpan<int> apDest = new BufferSpan<int>(dest, 1);
BufferSpan.Copy(apSource, apDest, count -1);
}
BufferSpan.Copy(apSource, apDest, count - 1);
AssertNotDefault(source, 1);
AssertNotDefault(dest, 1);
@ -317,17 +325,13 @@ namespace ImageSharp.Tests.Common
public void GenericToBytes(int count)
{
int destCount = count * sizeof(Foo);
Foo[] source = Foo.CreateArray(count+2);
byte[] dest = new byte[destCount + sizeof(Foo)*2];
Foo[] source = Foo.CreateArray(count + 2);
byte[] dest = new byte[destCount + sizeof(Foo) * 2];
fixed (Foo* pSource = source)
fixed (byte* pDest = dest)
{
BufferSpan<Foo> apSource = new BufferSpan<Foo>(source, pSource, 1);
BufferSpan<byte> apDest = new BufferSpan<byte>(dest, pDest, sizeof(Foo));
BufferSpan<Foo> apSource = new BufferSpan<Foo>(source, 1);
BufferSpan<byte> apDest = new BufferSpan<byte>(dest, sizeof(Foo));
BufferSpan.Copy(apSource, apDest, count - 1);
}
BufferSpan.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(Foo));
AssertNotDefault(source, 1);
@ -347,14 +351,10 @@ namespace ImageSharp.Tests.Common
AlignedFoo[] source = AlignedFoo.CreateArray(count + 2);
byte[] dest = new byte[destCount + sizeof(AlignedFoo) * 2];
fixed (AlignedFoo* pSource = source)
fixed (byte* pDest = dest)
{
BufferSpan<AlignedFoo> apSource = new BufferSpan<AlignedFoo>(source, pSource, 1);
BufferSpan<byte> apDest = new BufferSpan<byte>(dest, pDest, sizeof(AlignedFoo));
BufferSpan<AlignedFoo> apSource = new BufferSpan<AlignedFoo>(source, 1);
BufferSpan<byte> apDest = new BufferSpan<byte>(dest, sizeof(AlignedFoo));
BufferSpan.Copy(apSource, apDest, count - 1);
}
BufferSpan.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(AlignedFoo));
AssertNotDefault(source, 1);
@ -371,17 +371,13 @@ namespace ImageSharp.Tests.Common
public void IntToBytes(int count)
{
int destCount = count * sizeof(int);
int[] source = CreateTestInts(count+2);
int[] source = CreateTestInts(count + 2);
byte[] dest = new byte[destCount + sizeof(int) + 1];
fixed (int* pSource = source)
fixed (byte* pDest = dest)
{
BufferSpan<int> apSource = new BufferSpan<int>(source, pSource);
BufferSpan<byte> apDest = new BufferSpan<byte>(dest, pDest);
BufferSpan<int> apSource = new BufferSpan<int>(source);
BufferSpan<byte> apDest = new BufferSpan<byte>(dest);
BufferSpan.Copy(apSource, apDest, count);
}
BufferSpan.Copy(apSource.AsBytes(), apDest, count * sizeof(int));
AssertNotDefault(source, 1);
@ -398,15 +394,11 @@ namespace ImageSharp.Tests.Common
int srcCount = count * sizeof(Foo);
byte[] source = CreateTestBytes(srcCount);
Foo[] dest = new Foo[count + 2];
fixed(byte* pSource = source)
fixed (Foo* pDest = dest)
{
BufferSpan<byte> apSource = new BufferSpan<byte>(source, pSource);
BufferSpan<Foo> apDest = new BufferSpan<Foo>(dest, pDest);
BufferSpan.Copy(apSource, apDest, count);
}
BufferSpan<byte> apSource = new BufferSpan<byte>(source);
BufferSpan<Foo> apDest = new BufferSpan<Foo>(dest);
BufferSpan.Copy(apSource, apDest.AsBytes(), count * sizeof(Foo));
AssertNotDefault(source, sizeof(Foo) + 1);
AssertNotDefault(dest, 1);
@ -418,14 +410,14 @@ namespace ImageSharp.Tests.Common
}
[Fact]
public void ColorToBytes()
public void Color32ToBytes()
{
Color[] colors = { new Color(0, 1, 2, 3), new Color(4, 5, 6, 7), new Color(8, 9, 10, 11), };
using (PinnedBuffer<Color> colorBuf = new PinnedBuffer<Color>(colors))
using (PinnedBuffer<byte> byteBuf = new PinnedBuffer<byte>(colors.Length*4))
using (Buffer<Color> colorBuf = new Buffer<Color>(colors))
using (Buffer<byte> byteBuf = new Buffer<byte>(colors.Length * 4))
{
BufferSpan.Copy<Color>(colorBuf, byteBuf, colorBuf.Length);
BufferSpan.Copy(colorBuf.Span.AsBytes(), byteBuf, colorBuf.Length * sizeof(Color));
byte[] a = byteBuf.Array;
@ -436,7 +428,6 @@ namespace ImageSharp.Tests.Common
}
}
internal static bool ElementsAreEqual(Foo[] array, byte[] rawArray, int index)
{
fixed (Foo* pArray = array)

100
tests/ImageSharp.Tests/Common/PinnedBufferTests.cs → tests/ImageSharp.Tests/Common/BufferTests.cs

@ -1,4 +1,5 @@
namespace ImageSharp.Tests.Common
// ReSharper disable InconsistentNaming
namespace ImageSharp.Tests.Common
{
using System;
using System.Runtime.CompilerServices;
@ -9,21 +10,37 @@
using static TestStructs;
public unsafe class PinnedBufferTests
public unsafe class BufferTests
{
// ReSharper disable once ClassNeverInstantiated.Local
private class Assert : Xunit.Assert
{
public static void SpanPointsTo<T>(BufferSpan<T> span, Buffer<T> buffer, int bufferOffset = 0)
where T : struct
{
ref T actual = ref span.DangerousGetPinnableReference();
ref T expected = ref Unsafe.Add(ref buffer[0], bufferOffset);
Assert.True(Unsafe.AreSame(ref expected, ref actual), "span does not point to the expected position");
}
public static void Equal(void* expected, void* actual)
{
Assert.Equal((IntPtr)expected, (IntPtr)actual);
}
}
[Theory]
[InlineData(42)]
[InlineData(1111)]
public void ConstructWithOwnArray(int count)
{
using (PinnedBuffer<Foo> buffer = new PinnedBuffer<Foo>(count))
using (Buffer<Foo> buffer = new Buffer<Foo>(count))
{
Assert.False(buffer.IsDisposedOrLostArrayOwnership);
Assert.NotNull(buffer.Array);
Assert.Equal(count, buffer.Length);
Assert.True(buffer.Array.Length >= count);
VerifyPointer(buffer);
}
}
@ -33,13 +50,11 @@
public void ConstructWithExistingArray(int count)
{
Foo[] array = new Foo[count];
using (PinnedBuffer<Foo> buffer = new PinnedBuffer<Foo>(array))
using (Buffer<Foo> buffer = new Buffer<Foo>(array))
{
Assert.False(buffer.IsDisposedOrLostArrayOwnership);
Assert.Equal(array, buffer.Array);
Assert.Equal(count, buffer.Length);
VerifyPointer(buffer);
}
}
@ -49,7 +64,7 @@
public void Clear(int count)
{
Foo[] a = { new Foo() { A = 1, B = 2 }, new Foo() { A = 3, B = 4 } };
using (PinnedBuffer<Foo> buffer = new PinnedBuffer<Foo>(a))
using (Buffer<Foo> buffer = new Buffer<Foo>(a))
{
buffer.Clear();
@ -63,7 +78,7 @@
{
for (int i = 0; i < 100; i++)
{
using (PinnedBuffer<int> buffer = PinnedBuffer<int>.CreateClean(42))
using (Buffer<int> buffer = Buffer<int>.CreateClean(42))
{
for (int j = 0; j < buffer.Length; j++)
{
@ -90,7 +105,7 @@
{
Foo[] a = Foo.CreateArray(length);
using (PinnedBuffer<Foo> buffer = new PinnedBuffer<Foo>(a))
using (Buffer<Foo> buffer = new Buffer<Foo>(a))
{
Foo element = buffer[index];
@ -104,7 +119,7 @@
{
Foo[] a = Foo.CreateArray(length);
using (PinnedBuffer<Foo> buffer = new PinnedBuffer<Foo>(a))
using (Buffer<Foo> buffer = new Buffer<Foo>(a))
{
buffer[index] = new Foo(666, 666);
@ -116,24 +131,24 @@
[Fact]
public void Dispose()
{
PinnedBuffer<Foo> buffer = new PinnedBuffer<Foo>(42);
Buffer<Foo> buffer = new Buffer<Foo>(42);
buffer.Dispose();
Assert.True(buffer.IsDisposedOrLostArrayOwnership);
}
[Theory]
[InlineData(7)]
[InlineData(123)]
public void CastToSpan(int bufferLength)
{
using (PinnedBuffer<Foo> buffer = new PinnedBuffer<Foo>(bufferLength))
using (Buffer<Foo> buffer = new Buffer<Foo>(bufferLength))
{
BufferSpan<Foo> span = buffer;
Assert.Equal(buffer.Array, span.Array);
Assert.Equal(0, span.Start);
Assert.Equal(buffer.Pointer, span.PointerAtOffset);
Assert.SpanPointsTo(span, buffer);
Assert.Equal(span.Length, bufferLength);
}
}
@ -141,13 +156,13 @@
[Fact]
public void Span()
{
using (PinnedBuffer<Foo> buffer = new PinnedBuffer<Foo>(42))
using (Buffer<Foo> buffer = new Buffer<Foo>(42))
{
BufferSpan<Foo> span = buffer.Span;
Assert.Equal(buffer.Array, span.Array);
Assert.Equal(0, span.Start);
Assert.Equal(buffer.Pointer, span.PointerAtOffset);
Assert.SpanPointsTo(span, buffer);
Assert.Equal(span.Length, 42);
}
}
@ -160,13 +175,13 @@
[InlineData(123, 17)]
public void WithStartOnly(int bufferLength, int start)
{
using (PinnedBuffer<Foo> buffer = new PinnedBuffer<Foo>(bufferLength))
using (Buffer<Foo> buffer = new Buffer<Foo>(bufferLength))
{
BufferSpan<Foo> span = buffer.Slice(start);
Assert.Equal(buffer.Array, span.Array);
Assert.Equal(start, span.Start);
Assert.Equal(buffer.Pointer + start * Unsafe.SizeOf<Foo>(), span.PointerAtOffset);
Assert.SpanPointsTo(span, buffer, start);
Assert.Equal(span.Length, bufferLength - start);
}
}
@ -176,13 +191,13 @@
[InlineData(123, 17, 42)]
public void WithStartAndLength(int bufferLength, int start, int spanLength)
{
using (PinnedBuffer<Foo> buffer = new PinnedBuffer<Foo>(bufferLength))
using (Buffer<Foo> buffer = new Buffer<Foo>(bufferLength))
{
BufferSpan<Foo> span = buffer.Slice(start, spanLength);
Assert.Equal(buffer.Array, span.Array);
Assert.Equal(start, span.Start);
Assert.Equal(buffer.Pointer + start * Unsafe.SizeOf<Foo>(), span.PointerAtOffset);
Assert.SpanPointsTo(span, buffer, start);
Assert.Equal(span.Length, spanLength);
}
}
@ -192,9 +207,9 @@
public void UnPinAndTakeArrayOwnership()
{
Foo[] data = null;
using (PinnedBuffer<Foo> buffer = new PinnedBuffer<Foo>(42))
using (Buffer<Foo> buffer = new Buffer<Foo>(42))
{
data = buffer.UnPinAndTakeArrayOwnership();
data = buffer.TakeArrayOwnership();
Assert.True(buffer.IsDisposedOrLostArrayOwnership);
}
@ -202,10 +217,41 @@
Assert.True(data.Length >= 42);
}
private static void VerifyPointer(PinnedBuffer<Foo> buffer)
public class Pin
{
IntPtr ptr = (IntPtr)Unsafe.AsPointer(ref buffer.Array[0]);
Assert.Equal(ptr, buffer.Pointer);
[Fact]
public void ReturnsPinnedPointerToTheBeginningOfArray()
{
using (Buffer<Foo> buffer = new Buffer<Foo>(42))
{
Foo* actual = (Foo*)buffer.Pin();
fixed (Foo* expected = buffer.Array)
{
Assert.Equal(expected, actual);
}
}
}
[Fact]
public void SecondCallReturnsTheSamePointer()
{
using (Buffer<Foo> buffer = new Buffer<Foo>(42))
{
IntPtr ptr1 = buffer.Pin();
IntPtr ptr2 = buffer.Pin();
Assert.Equal(ptr1, ptr2);
}
}
[Fact]
public void WhenCalledOnDisposedBuffer_ThrowsInvalidOperationException()
{
Buffer<Foo> buffer = new Buffer<Foo>(42);
buffer.Dispose();
Assert.Throws<InvalidOperationException>(() => buffer.Pin());
}
}
}
}

2
tests/ImageSharp.Tests/Common/TestStructs.cs

@ -25,6 +25,8 @@ namespace ImageSharp.Tests.Common
}
return result;
}
public override string ToString() => $"({this.A},{this.B})";
}

4
tests/ImageSharp.Tests/Drawing/Text/GlyphBuilder.cs

@ -19,7 +19,7 @@ namespace ImageSharp.Tests.Drawing.Text
GlyphBuilder fullBuilder = new GlyphBuilder(new System.Numerics.Vector2(10, 99));
IGlyphRenderer builder = fullBuilder;
builder.BeginGlyph();
builder.BeginGlyph(Vector2.Zero);
builder.BeginFigure();
builder.MoveTo(new Vector2(0, 0));
builder.LineTo(new Vector2(0, 10)); // becomes 0, -10
@ -52,7 +52,7 @@ namespace ImageSharp.Tests.Drawing.Text
IGlyphRenderer builder = fullBuilder;
for (int i = 0; i < 10; i++)
{
builder.BeginGlyph();
builder.BeginGlyph(Vector2.Zero);
builder.BeginFigure();
builder.MoveTo(new Vector2(0, 0));
builder.LineTo(new Vector2(0, 10)); // becomes 0, -10

4
tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs

@ -25,7 +25,7 @@ namespace ImageSharp.Tests
public static string[] ProgressiveTestJpegs = TestImages.Jpeg.Progressive.All;
[Theory]
[WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb)]
[WithFileCollection(nameof(BaselineTestJpegs), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb32)]
public void OpenBaselineJpeg_SaveBmp<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPixel<TColor>
{
@ -36,7 +36,7 @@ namespace ImageSharp.Tests
}
[Theory]
[WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb)]
[WithFileCollection(nameof(ProgressiveTestJpegs), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb32)]
public void OpenProgressiveJpeg_SaveBmp<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPixel<TColor>
{

4
tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs

@ -48,8 +48,8 @@ namespace ImageSharp.Tests
}
[Theory]
[WithFileCollection(nameof(AllBmpFiles), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb, JpegSubsample.Ratio420, 75)]
[WithFileCollection(nameof(AllBmpFiles), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb, JpegSubsample.Ratio444, 75)]
[WithFileCollection(nameof(AllBmpFiles), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb32, JpegSubsample.Ratio420, 75)]
[WithFileCollection(nameof(AllBmpFiles), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb32, JpegSubsample.Ratio444, 75)]
public void OpenBmp_SaveJpeg<TColor>(TestImageProvider<TColor> provider, JpegSubsample subSample, int quality)
where TColor : struct, IPixel<TColor>
{

4
tests/ImageSharp.Tests/Formats/Jpg/JpegUtilsTests.cs

@ -39,7 +39,7 @@ namespace ImageSharp.Tests
}
[Theory]
[WithMemberFactory(nameof(CreateTestImage), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb)]
[WithMemberFactory(nameof(CreateTestImage), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb32)]
public void CopyStretchedRGBTo_FromOrigo<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPixel<TColor>
{
@ -61,7 +61,7 @@ namespace ImageSharp.Tests
}
[Theory]
[WithMemberFactory(nameof(CreateTestImage), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb)]
[WithMemberFactory(nameof(CreateTestImage), PixelTypes.Color | PixelTypes.StandardImageClass | PixelTypes.Argb32)]
public void CopyStretchedRGBTo_WithOffset<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPixel<TColor>
{

35
tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifReaderTests.cs

@ -0,0 +1,35 @@
// <copyright file="ExifReaderTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Tests
{
using System.Collections.ObjectModel;
using Xunit;
public class ExifReaderTests
{
[Fact]
public void Read_DataIsEmpty_ReturnsEmptyCollection()
{
ExifReader reader = new ExifReader();
byte[] data = new byte[] { };
Collection<ExifValue> result = reader.Read(data);
Assert.Equal(0, result.Count);
}
[Fact]
public void Read_DataIsMinimal_ReturnsEmptyCollection()
{
ExifReader reader = new ExifReader();
byte[] data = new byte[] { 69, 120, 105, 102, 0, 0 };
Collection<ExifValue> result = reader.Read(data);
Assert.Equal(0, result.Count);
}
}
}

8
tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs

@ -61,7 +61,7 @@ namespace ImageSharp.Tests
BlackWhiteChecker(pixels); // top left
VirticalBars(pixels); // top right
TransparentGradients(pixels); // bottom left
Rainbow(pixels); // bottom right
Rainbow(pixels); // bottom right
}
}
/// <summary>
@ -70,7 +70,7 @@ namespace ImageSharp.Tests
/// <param name="pixels"></param>
private static void VirticalBars(PixelAccessor<TColor> pixels)
{
// topLeft
// topLeft
int left = pixels.Width / 2;
int right = pixels.Width;
int top = 0;
@ -101,7 +101,7 @@ namespace ImageSharp.Tests
/// <param name="pixels"></param>
private static void BlackWhiteChecker(PixelAccessor<TColor> pixels)
{
// topLeft
// topLeft
int left = 0;
int right = pixels.Width / 2;
int top = 0;
@ -140,7 +140,7 @@ namespace ImageSharp.Tests
/// <param name="pixels"></param>
private static void TransparentGradients(PixelAccessor<TColor> pixels)
{
// topLeft
// topLeft
int left = 0;
int right = pixels.Width / 2;
int top = pixels.Height / 2;

2
tests/ImageSharp.Tests/TestUtilities/PixelTypes.cs

@ -18,7 +18,7 @@ namespace ImageSharp.Tests
Alpha8 = 1 << 0,
Argb = 1 << 1,
Argb32 = 1 << 1,
Bgr565 = 1 << 2,

6
tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs

@ -20,7 +20,7 @@ namespace ImageSharp.Tests
private ITestOutputHelper Output { get; }
[Theory]
[WithBlankImages(42, 666, PixelTypes.Color | PixelTypes.Argb | PixelTypes.HalfSingle, "hello")]
[WithBlankImages(42, 666, PixelTypes.Color | PixelTypes.Argb32 | PixelTypes.HalfSingle, "hello")]
public void Use_WithEmptyImageAttribute<TColor>(TestImageProvider<TColor> provider, string message)
where TColor : struct, IPixel<TColor>
{
@ -86,7 +86,7 @@ namespace ImageSharp.Tests
public static string[] AllBmpFiles => TestImages.Bmp.All;
[Theory]
[WithFileCollection(nameof(AllBmpFiles), PixelTypes.Color | PixelTypes.Argb)]
[WithFileCollection(nameof(AllBmpFiles), PixelTypes.Color | PixelTypes.Argb32)]
public void Use_WithFileCollection<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPixel<TColor>
{
@ -96,7 +96,7 @@ namespace ImageSharp.Tests
}
[Theory]
[WithSolidFilledImages(10, 20, 255, 100, 50, 200, PixelTypes.Color | PixelTypes.Argb)]
[WithSolidFilledImages(10, 20, 255, 100, 50, 200, PixelTypes.Color | PixelTypes.Argb32)]
public void Use_WithSolidFilledImagesAttribute<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPixel<TColor>
{

4
tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs

@ -85,7 +85,7 @@ namespace ImageSharp.Tests
[Theory]
[InlineData(PixelTypes.Color, typeof(Color))]
[InlineData(PixelTypes.Argb, typeof(Argb))]
[InlineData(PixelTypes.Argb32, typeof(Argb32))]
[InlineData(PixelTypes.HalfVector4, typeof(HalfVector4))]
[InlineData(PixelTypes.StandardImageClass, typeof(Color))]
public void ToType(PixelTypes pt, Type expectedType)
@ -95,7 +95,7 @@ namespace ImageSharp.Tests
[Theory]
[InlineData(typeof(Color), PixelTypes.Color)]
[InlineData(typeof(Argb), PixelTypes.Argb)]
[InlineData(typeof(Argb32), PixelTypes.Argb32)]
public void GetPixelType(Type clrType, PixelTypes expectedPixelType)
{
Assert.Equal(expectedPixelType, clrType.GetPixelType());

Loading…
Cancel
Save