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

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

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

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

@ -48,7 +48,8 @@ namespace ImageSharp.Drawing
/// <summary> /// <summary>
/// Begins the glyph. /// Begins the glyph.
/// </summary> /// </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(); this.builder.Clear();
} }

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

@ -10,9 +10,14 @@ namespace ImageSharp
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
/// <content> /// <summary>
/// Conains the definition of <see cref="BulkOperations"/> /// Unpacked pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
/// </content> /// 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 public partial struct Color
{ {
/// <summary> /// <summary>
@ -37,15 +42,12 @@ namespace ImageSharp
/// <cref>https://github.com/dotnet/corefx/issues/15957</cref> /// <cref>https://github.com/dotnet/corefx/issues/15957</cref>
/// </see> /// </see>
/// </remarks> /// </remarks>
internal static unsafe void ToVector4SimdAligned( internal static unsafe void ToVector4SimdAligned(BufferSpan<Color> sourceColors, BufferSpan<Vector4> destVectors, int count)
BufferSpan<Color> sourceColors,
BufferSpan<Vector4> destVectors,
int count)
{ {
if (!Vector.IsHardwareAccelerated) if (!Vector.IsHardwareAccelerated)
{ {
throw new InvalidOperationException( 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; int vecSize = Vector<uint>.Count;
@ -62,21 +64,23 @@ namespace ImageSharp
int unpackedRawCount = count * 4; int unpackedRawCount = count * 4;
uint* src = (uint*)sourceColors.PointerAtOffset; ref uint src = ref Unsafe.As<Color, uint>(ref sourceColors.DangerousGetPinnableReference());
uint* srcEnd = src + count;
using (PinnedBuffer<uint> tempBuf = new PinnedBuffer<uint>( using (Buffer<uint> tempBuf = new Buffer<uint>(
unpackedRawCount + Vector<uint>.Count)) unpackedRawCount + Vector<uint>.Count))
{ {
uint* tPtr = (uint*)tempBuf.Pointer;
uint[] temp = tempBuf.Array; uint[] temp = tempBuf.Array;
float[] fTemp = Unsafe.As<float[]>(temp); 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: // This call is the bottleneck now:
dst->Load(*src); dst.Load(sVal);
} }
for (int i = 0; i < unpackedRawCount; i += vecSize) for (int i = 0; i < unpackedRawCount; i += vecSize)
@ -91,7 +95,7 @@ namespace ImageSharp
vf.CopyTo(fTemp, i); 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 /> /// <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; ref RGB24 sourceRef = ref Unsafe.As<byte, RGB24>(ref sourceBytes.DangerousGetPinnableReference());
byte* destination = (byte*)destColors; 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; Unsafe.As<Color, RGB24>(ref dp) = sp;
destination += 4; dp.A = 255;
} }
} }
/// <inheritdoc /> /// <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; ref Color sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte* destination = (byte*)destBytes; 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); ref Color sp = ref Unsafe.Add(ref sourceRef, i);
*(destination + 1) = *(source + 1); ref RGB24 dp = ref Unsafe.Add(ref destRef, i);
*(destination + 2) = *(source + 2);
source += 4; dp = Unsafe.As<Color, RGB24>(ref sp);
destination += 3;
} }
} }
/// <inheritdoc /> /// <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 /> /// <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 /> /// <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; ref RGB24 sourceRef = ref Unsafe.As<byte, RGB24>(ref sourceBytes.DangerousGetPinnableReference());
byte* destination = (byte*)destColors; 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; Unsafe.As<Color, RGB24>(ref dp) = sp.ToZyx();
destination += 4; dp.A = 255;
} }
} }
/// <inheritdoc /> /// <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; ref Color sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte* destination = (byte*)destBytes; 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); ref Color sp = ref Unsafe.Add(ref sourceRef, i);
*(destination + 1) = *(source + 1); ref RGB24 dp = ref Unsafe.Add(ref destRef, i);
*(destination + 2) = *(source + 0);
source += 4; dp = Unsafe.As<Color, RGB24>(ref sp).ToZyx();
destination += 3;
} }
} }
/// <inheritdoc /> /// <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; ref RGBA32 sourceRef = ref Unsafe.As<byte, RGBA32>(ref sourceBytes.DangerousGetPinnableReference());
byte* destination = (byte*)destColors; 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)); ref RGBA32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Color dp = ref Unsafe.Add(ref destRef, i);
source += 4; RGBA32 zyxw = sp.ToZyxw();
destination += 4; dp = Unsafe.As<RGBA32, Color>(ref zyxw);
} }
} }
/// <inheritdoc /> /// <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; ref Color sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte* destination = (byte*)destBytes; 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); ref RGBA32 sp = ref Unsafe.As<Color, RGBA32>(ref Unsafe.Add(ref sourceRef, i));
*(destination + 1) = *(source + 1); ref RGBA32 dp = ref Unsafe.Add(ref destRef, i);
*(destination + 2) = *(source + 0); dp = sp.ToZyxw();
*(destination + 3) = *(source + 3);
source += 4;
destination += 4;
} }
} }
/// <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> /// <summary>
/// Value type to store <see cref="Color"/>-s unpacked into multiple <see cref="uint"/>-s. /// Value type to store <see cref="Color"/>-s unpacked into multiple <see cref="uint"/>-s.
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct UnpackedRGBA private struct UnpackedRGBA
{ {
private uint r; private uint r;
private uint g; private uint g;
private uint b; private uint b;
private uint a; private uint a;
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Load(uint p) public void Load(uint p)
{ {
this.r = p; this.r = p;
this.g = p >> Color.GreenShift; this.g = p >> GreenShift;
this.b = p >> Color.BlueShift; this.b = p >> BlueShift;
this.a = p >> Color.AlphaShift; 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. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </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. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
@ -6,9 +6,10 @@
namespace ImageSharp namespace ImageSharp
{ {
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices;
/// <summary> /// <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. /// The color components are stored in red, green, blue, and alpha order.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
@ -25,10 +26,11 @@ namespace ImageSharp
/// <returns> /// <returns>
/// The <see cref="Color"/>. /// The <see cref="Color"/>.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Color operator +(Color left, Color right) public static Color operator +(Color left, Color right)
{ {
Vector4 add = left.ToVector4() + right.ToVector4(); Vector4 add = left.ToVector4() + right.ToVector4();
return new Color(Pack(ref add)); return PackNew(ref add);
} }
/// <summary> /// <summary>
@ -39,10 +41,11 @@ namespace ImageSharp
/// <returns> /// <returns>
/// The <see cref="Color"/>. /// The <see cref="Color"/>.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Color operator -(Color left, Color right) public static Color operator -(Color left, Color right)
{ {
Vector4 sub = left.ToVector4() - right.ToVector4(); Vector4 sub = left.ToVector4() - right.ToVector4();
return new Color(Pack(ref sub)); return PackNew(ref sub);
} }
/// <summary> /// <summary>
@ -56,7 +59,7 @@ namespace ImageSharp
public static Color Normal(Color backdrop, Color source) public static Color Normal(Color backdrop, Color source)
{ {
Vector4 normal = Vector4BlendTransforms.Normal(backdrop.ToVector4(), source.ToVector4()); Vector4 normal = Vector4BlendTransforms.Normal(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref normal)); return PackNew(ref normal);
} }
/// <summary> /// <summary>
@ -76,7 +79,7 @@ namespace ImageSharp
public static Color Multiply(Color backdrop, Color source) public static Color Multiply(Color backdrop, Color source)
{ {
Vector4 multiply = Vector4BlendTransforms.Multiply(backdrop.ToVector4(), source.ToVector4()); Vector4 multiply = Vector4BlendTransforms.Multiply(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref multiply)); return PackNew(ref multiply);
} }
/// <summary> /// <summary>
@ -95,7 +98,7 @@ namespace ImageSharp
public static Color Screen(Color backdrop, Color source) public static Color Screen(Color backdrop, Color source)
{ {
Vector4 subtract = Vector4BlendTransforms.Screen(backdrop.ToVector4(), source.ToVector4()); Vector4 subtract = Vector4BlendTransforms.Screen(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref subtract)); return PackNew(ref subtract);
} }
/// <summary> /// <summary>
@ -110,7 +113,7 @@ namespace ImageSharp
public static Color HardLight(Color backdrop, Color source) public static Color HardLight(Color backdrop, Color source)
{ {
Vector4 hardlight = Vector4BlendTransforms.HardLight(backdrop.ToVector4(), source.ToVector4()); Vector4 hardlight = Vector4BlendTransforms.HardLight(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref hardlight)); return PackNew(ref hardlight);
} }
/// <summary> /// <summary>
@ -129,7 +132,7 @@ namespace ImageSharp
public static Color Overlay(Color backdrop, Color source) public static Color Overlay(Color backdrop, Color source)
{ {
Vector4 overlay = Vector4BlendTransforms.Overlay(backdrop.ToVector4(), source.ToVector4()); Vector4 overlay = Vector4BlendTransforms.Overlay(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref overlay)); return PackNew(ref overlay);
} }
/// <summary> /// <summary>
@ -144,7 +147,7 @@ namespace ImageSharp
public static Color Darken(Color backdrop, Color source) public static Color Darken(Color backdrop, Color source)
{ {
Vector4 darken = Vector4BlendTransforms.Darken(backdrop.ToVector4(), source.ToVector4()); Vector4 darken = Vector4BlendTransforms.Darken(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref darken)); return PackNew(ref darken);
} }
/// <summary> /// <summary>
@ -159,7 +162,7 @@ namespace ImageSharp
public static Color Lighten(Color backdrop, Color source) public static Color Lighten(Color backdrop, Color source)
{ {
Vector4 lighten = Vector4BlendTransforms.Lighten(backdrop.ToVector4(), source.ToVector4()); Vector4 lighten = Vector4BlendTransforms.Lighten(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref lighten)); return PackNew(ref lighten);
} }
/// <summary> /// <summary>
@ -174,7 +177,7 @@ namespace ImageSharp
public static Color SoftLight(Color backdrop, Color source) public static Color SoftLight(Color backdrop, Color source)
{ {
Vector4 softlight = Vector4BlendTransforms.SoftLight(backdrop.ToVector4(), source.ToVector4()); Vector4 softlight = Vector4BlendTransforms.SoftLight(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref softlight)); return PackNew(ref softlight);
} }
/// <summary> /// <summary>
@ -188,7 +191,7 @@ namespace ImageSharp
public static Color ColorDodge(Color backdrop, Color source) public static Color ColorDodge(Color backdrop, Color source)
{ {
Vector4 dodge = Vector4BlendTransforms.Dodge(backdrop.ToVector4(), source.ToVector4()); Vector4 dodge = Vector4BlendTransforms.Dodge(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref dodge)); return PackNew(ref dodge);
} }
/// <summary> /// <summary>
@ -202,7 +205,7 @@ namespace ImageSharp
public static Color ColorBurn(Color backdrop, Color source) public static Color ColorBurn(Color backdrop, Color source)
{ {
Vector4 burn = Vector4BlendTransforms.Burn(backdrop.ToVector4(), source.ToVector4()); Vector4 burn = Vector4BlendTransforms.Burn(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref burn)); return PackNew(ref burn);
} }
/// <summary> /// <summary>
@ -217,7 +220,7 @@ namespace ImageSharp
public static Color Difference(Color backdrop, Color source) public static Color Difference(Color backdrop, Color source)
{ {
Vector4 difference = Vector4BlendTransforms.Difference(backdrop.ToVector4(), source.ToVector4()); Vector4 difference = Vector4BlendTransforms.Difference(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref difference)); return PackNew(ref difference);
} }
/// <summary> /// <summary>
@ -232,7 +235,7 @@ namespace ImageSharp
public static Color Exclusion(Color backdrop, Color source) public static Color Exclusion(Color backdrop, Color source)
{ {
Vector4 exclusion = Vector4BlendTransforms.Exclusion(backdrop.ToVector4(), source.ToVector4()); Vector4 exclusion = Vector4BlendTransforms.Exclusion(backdrop.ToVector4(), source.ToVector4());
return new Color(Pack(ref exclusion)); return PackNew(ref exclusion);
} }
/// <summary> /// <summary>
@ -249,7 +252,8 @@ namespace ImageSharp
/// </returns> /// </returns>
public static Color Lerp(Color from, Color to, float amount) 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 namespace ImageSharp
{ {
using System;
using System.Globalization;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary> /// <summary>
/// Packed pixel 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.
@ -18,8 +17,39 @@ namespace ImageSharp
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, /// 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. /// as it avoids the need to create new values for modification operations.
/// </remarks> /// </remarks>
[StructLayout(LayoutKind.Explicit)]
public partial struct Color : IPixel<Color>, IPackedVector<uint> 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> /// <summary>
/// The shift count for the red component /// The shift count for the red component
/// </summary> /// </summary>
@ -50,11 +80,6 @@ namespace ImageSharp
/// </summary> /// </summary>
private static readonly Vector4 Half = new Vector4(0.5F); private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary>
/// The packed value.
/// </summary>
private uint packedValue;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct. /// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary> /// </summary>
@ -62,9 +87,14 @@ namespace ImageSharp
/// <param name="g">The green component.</param> /// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param> /// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param> /// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Color(byte r, byte g, byte b, byte a = 255) 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> /// <summary>
@ -74,9 +104,11 @@ namespace ImageSharp
/// <param name="g">The green component.</param> /// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param> /// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param> /// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Color(float r, float g, float b, float a = 1) 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> /// <summary>
@ -85,9 +117,11 @@ namespace ImageSharp
/// <param name="vector"> /// <param name="vector">
/// The vector containing the components for the packed vector. /// The vector containing the components for the packed vector.
/// </param> /// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Color(Vector3 vector) public Color(Vector3 vector)
: this()
{ {
this.packedValue = Pack(ref vector); this.Pack(ref vector);
} }
/// <summary> /// <summary>
@ -96,9 +130,11 @@ namespace ImageSharp
/// <param name="vector"> /// <param name="vector">
/// The vector containing the components for the packed vector. /// The vector containing the components for the packed vector.
/// </param> /// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Color(Vector4 vector) public Color(Vector4 vector)
: this()
{ {
this.packedValue = Pack(ref vector); this = PackNew(ref vector);
} }
/// <summary> /// <summary>
@ -107,96 +143,15 @@ namespace ImageSharp
/// <param name="packed"> /// <param name="packed">
/// The packed value. /// The packed value.
/// </param> /// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Color(uint packed) public Color(uint packed)
: this()
{ {
this.packedValue = packed; this.Rgba = 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;
}
} }
/// <inheritdoc/> /// <inheritdoc/>
public uint PackedValue public uint PackedValue { get => this.Rgba; set => this.Rgba = value; }
{
get
{
return this.packedValue;
}
set
{
this.packedValue = value;
}
}
/// <summary> /// <summary>
/// Compares two <see cref="Color"/> objects for equality. /// Compares two <see cref="Color"/> objects for equality.
@ -213,7 +168,7 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Color left, Color right) public static bool operator ==(Color left, Color right)
{ {
return left.packedValue == right.packedValue; return left.Rgba == right.Rgba;
} }
/// <summary> /// <summary>
@ -227,7 +182,7 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Color left, Color right) public static bool operator !=(Color left, Color right)
{ {
return left.packedValue != right.packedValue; return left.Rgba != right.Rgba;
} }
/// <summary> /// <summary>
@ -246,13 +201,16 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public BulkPixelOperations<Color> CreateBulkOperations() => new Color.BulkOperations(); public BulkPixelOperations<Color> CreateBulkOperations() => new BulkOperations();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBytes(byte x, byte y, byte z, byte w) 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> /// <summary>
@ -307,7 +265,7 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector)
{ {
this.packedValue = Pack(ref vector); this.Pack(ref vector);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -327,7 +285,7 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Color other) public bool Equals(Color other)
{ {
return this.packedValue == other.packedValue; return this.Rgba == other.Rgba;
} }
/// <summary> /// <summary>
@ -342,65 +300,85 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() 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> /// <summary>
/// Packs a <see cref="Vector4"/> into a uint. /// Packs the four floats into a <see cref="uint"/>.
/// </summary> /// </summary>
/// <param name="vector">The vector containing the values to pack.</param> /// <param name="x">The x-component</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns> /// <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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(ref Vector4 vector) private static uint Pack(byte x, byte y, byte z, byte w)
{ {
vector *= MaxBytes; return (uint)(x << RedShift | y << GreenShift | z << BlueShift | w << AlphaShift);
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);
} }
/// <summary> /// <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> /// </summary>
/// <param name="vector">The vector containing the values to pack.</param> /// <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)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(ref Vector3 vector) private static Color PackNew(ref Vector4 vector)
{ {
Vector4 value = new Vector4(vector, 1); vector *= MaxBytes;
return Pack(ref value); 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> /// <summary>
/// Packs the four floats into a <see cref="uint"/>. /// Packs the four floats into a color.
/// </summary> /// </summary>
/// <param name="x">The x-component</param> /// <param name="x">The x-component</param>
/// <param name="y">The y-component</param> /// <param name="y">The y-component</param>
/// <param name="z">The z-component</param> /// <param name="z">The z-component</param>
/// <param name="w">The w-component</param> /// <param name="w">The w-component</param>
/// <returns>The <see cref="uint"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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); Vector4 value = new Vector4(x, y, z, w);
return Pack(ref value); this.Pack(ref value);
} }
/// <summary> /// <summary>
/// Packs the four floats into a <see cref="uint"/>. /// Packs a <see cref="Vector3"/> into a uint.
/// </summary> /// </summary>
/// <param name="x">The x-component</param> /// <param name="vector">The vector containing the values to pack.</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)] [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; using System;
/// <summary> /// <summary>
/// A set of named colors mapped to the provided Color space. /// A set of named colors mapped to the provided color space.
/// </summary> /// </summary>
/// <typeparam name="TColor">The type of the color.</typeparam> /// <typeparam name="TColor">The type of the color.</typeparam>
public static class NamedColors<TColor> public static class NamedColors<TColor>
where TColor : struct, IPixel<TColor> where TColor : struct, IPixel<TColor>
{ {
/// <summary> /// <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> /// </summary>
public static readonly TColor AliceBlue = ColorBuilder<TColor>.FromRGBA(240, 248, 255, 255); public static readonly TColor AliceBlue = ColorBuilder<TColor>.FromRGBA(240, 248, 255, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor AntiqueWhite = ColorBuilder<TColor>.FromRGBA(250, 235, 215, 255); public static readonly TColor AntiqueWhite = ColorBuilder<TColor>.FromRGBA(250, 235, 215, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Aqua = ColorBuilder<TColor>.FromRGBA(0, 255, 255, 255); public static readonly TColor Aqua = ColorBuilder<TColor>.FromRGBA(0, 255, 255, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Aquamarine = ColorBuilder<TColor>.FromRGBA(127, 255, 212, 255); public static readonly TColor Aquamarine = ColorBuilder<TColor>.FromRGBA(127, 255, 212, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Azure = ColorBuilder<TColor>.FromRGBA(240, 255, 255, 255); public static readonly TColor Azure = ColorBuilder<TColor>.FromRGBA(240, 255, 255, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Beige = ColorBuilder<TColor>.FromRGBA(245, 245, 220, 255); public static readonly TColor Beige = ColorBuilder<TColor>.FromRGBA(245, 245, 220, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Bisque = ColorBuilder<TColor>.FromRGBA(255, 228, 196, 255); public static readonly TColor Bisque = ColorBuilder<TColor>.FromRGBA(255, 228, 196, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Black = ColorBuilder<TColor>.FromRGBA(0, 0, 0, 255); public static readonly TColor Black = ColorBuilder<TColor>.FromRGBA(0, 0, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor BlanchedAlmond = ColorBuilder<TColor>.FromRGBA(255, 235, 205, 255); public static readonly TColor BlanchedAlmond = ColorBuilder<TColor>.FromRGBA(255, 235, 205, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Blue = ColorBuilder<TColor>.FromRGBA(0, 0, 255, 255); public static readonly TColor Blue = ColorBuilder<TColor>.FromRGBA(0, 0, 255, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor BlueViolet = ColorBuilder<TColor>.FromRGBA(138, 43, 226, 255); public static readonly TColor BlueViolet = ColorBuilder<TColor>.FromRGBA(138, 43, 226, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Brown = ColorBuilder<TColor>.FromRGBA(165, 42, 42, 255); public static readonly TColor Brown = ColorBuilder<TColor>.FromRGBA(165, 42, 42, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor BurlyWood = ColorBuilder<TColor>.FromRGBA(222, 184, 135, 255); public static readonly TColor BurlyWood = ColorBuilder<TColor>.FromRGBA(222, 184, 135, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor CadetBlue = ColorBuilder<TColor>.FromRGBA(95, 158, 160, 255); public static readonly TColor CadetBlue = ColorBuilder<TColor>.FromRGBA(95, 158, 160, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Chartreuse = ColorBuilder<TColor>.FromRGBA(127, 255, 0, 255); public static readonly TColor Chartreuse = ColorBuilder<TColor>.FromRGBA(127, 255, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Chocolate = ColorBuilder<TColor>.FromRGBA(210, 105, 30, 255); public static readonly TColor Chocolate = ColorBuilder<TColor>.FromRGBA(210, 105, 30, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Coral = ColorBuilder<TColor>.FromRGBA(255, 127, 80, 255); public static readonly TColor Coral = ColorBuilder<TColor>.FromRGBA(255, 127, 80, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor CornflowerBlue = ColorBuilder<TColor>.FromRGBA(100, 149, 237, 255); public static readonly TColor CornflowerBlue = ColorBuilder<TColor>.FromRGBA(100, 149, 237, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Cornsilk = ColorBuilder<TColor>.FromRGBA(255, 248, 220, 255); public static readonly TColor Cornsilk = ColorBuilder<TColor>.FromRGBA(255, 248, 220, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Crimson = ColorBuilder<TColor>.FromRGBA(220, 20, 60, 255); public static readonly TColor Crimson = ColorBuilder<TColor>.FromRGBA(220, 20, 60, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Cyan = ColorBuilder<TColor>.FromRGBA(0, 255, 255, 255); public static readonly TColor Cyan = ColorBuilder<TColor>.FromRGBA(0, 255, 255, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkBlue = ColorBuilder<TColor>.FromRGBA(0, 0, 139, 255); public static readonly TColor DarkBlue = ColorBuilder<TColor>.FromRGBA(0, 0, 139, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkCyan = ColorBuilder<TColor>.FromRGBA(0, 139, 139, 255); public static readonly TColor DarkCyan = ColorBuilder<TColor>.FromRGBA(0, 139, 139, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkGoldenrod = ColorBuilder<TColor>.FromRGBA(184, 134, 11, 255); public static readonly TColor DarkGoldenrod = ColorBuilder<TColor>.FromRGBA(184, 134, 11, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkGray = ColorBuilder<TColor>.FromRGBA(169, 169, 169, 255); public static readonly TColor DarkGray = ColorBuilder<TColor>.FromRGBA(169, 169, 169, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkGreen = ColorBuilder<TColor>.FromRGBA(0, 100, 0, 255); public static readonly TColor DarkGreen = ColorBuilder<TColor>.FromRGBA(0, 100, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkKhaki = ColorBuilder<TColor>.FromRGBA(189, 183, 107, 255); public static readonly TColor DarkKhaki = ColorBuilder<TColor>.FromRGBA(189, 183, 107, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkMagenta = ColorBuilder<TColor>.FromRGBA(139, 0, 139, 255); public static readonly TColor DarkMagenta = ColorBuilder<TColor>.FromRGBA(139, 0, 139, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkOliveGreen = ColorBuilder<TColor>.FromRGBA(85, 107, 47, 255); public static readonly TColor DarkOliveGreen = ColorBuilder<TColor>.FromRGBA(85, 107, 47, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkOrange = ColorBuilder<TColor>.FromRGBA(255, 140, 0, 255); public static readonly TColor DarkOrange = ColorBuilder<TColor>.FromRGBA(255, 140, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkOrchid = ColorBuilder<TColor>.FromRGBA(153, 50, 204, 255); public static readonly TColor DarkOrchid = ColorBuilder<TColor>.FromRGBA(153, 50, 204, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkRed = ColorBuilder<TColor>.FromRGBA(139, 0, 0, 255); public static readonly TColor DarkRed = ColorBuilder<TColor>.FromRGBA(139, 0, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkSalmon = ColorBuilder<TColor>.FromRGBA(233, 150, 122, 255); public static readonly TColor DarkSalmon = ColorBuilder<TColor>.FromRGBA(233, 150, 122, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkSeaGreen = ColorBuilder<TColor>.FromRGBA(143, 188, 139, 255); public static readonly TColor DarkSeaGreen = ColorBuilder<TColor>.FromRGBA(143, 188, 139, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkSlateBlue = ColorBuilder<TColor>.FromRGBA(72, 61, 139, 255); public static readonly TColor DarkSlateBlue = ColorBuilder<TColor>.FromRGBA(72, 61, 139, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkSlateGray = ColorBuilder<TColor>.FromRGBA(47, 79, 79, 255); public static readonly TColor DarkSlateGray = ColorBuilder<TColor>.FromRGBA(47, 79, 79, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkTurquoise = ColorBuilder<TColor>.FromRGBA(0, 206, 209, 255); public static readonly TColor DarkTurquoise = ColorBuilder<TColor>.FromRGBA(0, 206, 209, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DarkViolet = ColorBuilder<TColor>.FromRGBA(148, 0, 211, 255); public static readonly TColor DarkViolet = ColorBuilder<TColor>.FromRGBA(148, 0, 211, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DeepPink = ColorBuilder<TColor>.FromRGBA(255, 20, 147, 255); public static readonly TColor DeepPink = ColorBuilder<TColor>.FromRGBA(255, 20, 147, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DeepSkyBlue = ColorBuilder<TColor>.FromRGBA(0, 191, 255, 255); public static readonly TColor DeepSkyBlue = ColorBuilder<TColor>.FromRGBA(0, 191, 255, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DimGray = ColorBuilder<TColor>.FromRGBA(105, 105, 105, 255); public static readonly TColor DimGray = ColorBuilder<TColor>.FromRGBA(105, 105, 105, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor DodgerBlue = ColorBuilder<TColor>.FromRGBA(30, 144, 255, 255); public static readonly TColor DodgerBlue = ColorBuilder<TColor>.FromRGBA(30, 144, 255, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Firebrick = ColorBuilder<TColor>.FromRGBA(178, 34, 34, 255); public static readonly TColor Firebrick = ColorBuilder<TColor>.FromRGBA(178, 34, 34, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor FloralWhite = ColorBuilder<TColor>.FromRGBA(255, 250, 240, 255); public static readonly TColor FloralWhite = ColorBuilder<TColor>.FromRGBA(255, 250, 240, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor ForestGreen = ColorBuilder<TColor>.FromRGBA(34, 139, 34, 255); public static readonly TColor ForestGreen = ColorBuilder<TColor>.FromRGBA(34, 139, 34, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Fuchsia = ColorBuilder<TColor>.FromRGBA(255, 0, 255, 255); public static readonly TColor Fuchsia = ColorBuilder<TColor>.FromRGBA(255, 0, 255, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Gainsboro = ColorBuilder<TColor>.FromRGBA(220, 220, 220, 255); public static readonly TColor Gainsboro = ColorBuilder<TColor>.FromRGBA(220, 220, 220, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor GhostWhite = ColorBuilder<TColor>.FromRGBA(248, 248, 255, 255); public static readonly TColor GhostWhite = ColorBuilder<TColor>.FromRGBA(248, 248, 255, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Gold = ColorBuilder<TColor>.FromRGBA(255, 215, 0, 255); public static readonly TColor Gold = ColorBuilder<TColor>.FromRGBA(255, 215, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Goldenrod = ColorBuilder<TColor>.FromRGBA(218, 165, 32, 255); public static readonly TColor Goldenrod = ColorBuilder<TColor>.FromRGBA(218, 165, 32, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Gray = ColorBuilder<TColor>.FromRGBA(128, 128, 128, 255); public static readonly TColor Gray = ColorBuilder<TColor>.FromRGBA(128, 128, 128, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Green = ColorBuilder<TColor>.FromRGBA(0, 128, 0, 255); public static readonly TColor Green = ColorBuilder<TColor>.FromRGBA(0, 128, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor GreenYellow = ColorBuilder<TColor>.FromRGBA(173, 255, 47, 255); public static readonly TColor GreenYellow = ColorBuilder<TColor>.FromRGBA(173, 255, 47, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Honeydew = ColorBuilder<TColor>.FromRGBA(240, 255, 240, 255); public static readonly TColor Honeydew = ColorBuilder<TColor>.FromRGBA(240, 255, 240, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor HotPink = ColorBuilder<TColor>.FromRGBA(255, 105, 180, 255); public static readonly TColor HotPink = ColorBuilder<TColor>.FromRGBA(255, 105, 180, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor IndianRed = ColorBuilder<TColor>.FromRGBA(205, 92, 92, 255); public static readonly TColor IndianRed = ColorBuilder<TColor>.FromRGBA(205, 92, 92, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Indigo = ColorBuilder<TColor>.FromRGBA(75, 0, 130, 255); public static readonly TColor Indigo = ColorBuilder<TColor>.FromRGBA(75, 0, 130, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Ivory = ColorBuilder<TColor>.FromRGBA(255, 255, 240, 255); public static readonly TColor Ivory = ColorBuilder<TColor>.FromRGBA(255, 255, 240, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Khaki = ColorBuilder<TColor>.FromRGBA(240, 230, 140, 255); public static readonly TColor Khaki = ColorBuilder<TColor>.FromRGBA(240, 230, 140, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Lavender = ColorBuilder<TColor>.FromRGBA(230, 230, 250, 255); public static readonly TColor Lavender = ColorBuilder<TColor>.FromRGBA(230, 230, 250, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LavenderBlush = ColorBuilder<TColor>.FromRGBA(255, 240, 245, 255); public static readonly TColor LavenderBlush = ColorBuilder<TColor>.FromRGBA(255, 240, 245, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LawnGreen = ColorBuilder<TColor>.FromRGBA(124, 252, 0, 255); public static readonly TColor LawnGreen = ColorBuilder<TColor>.FromRGBA(124, 252, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LemonChiffon = ColorBuilder<TColor>.FromRGBA(255, 250, 205, 255); public static readonly TColor LemonChiffon = ColorBuilder<TColor>.FromRGBA(255, 250, 205, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LightBlue = ColorBuilder<TColor>.FromRGBA(173, 216, 230, 255); public static readonly TColor LightBlue = ColorBuilder<TColor>.FromRGBA(173, 216, 230, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LightCoral = ColorBuilder<TColor>.FromRGBA(240, 128, 128, 255); public static readonly TColor LightCoral = ColorBuilder<TColor>.FromRGBA(240, 128, 128, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LightCyan = ColorBuilder<TColor>.FromRGBA(224, 255, 255, 255); public static readonly TColor LightCyan = ColorBuilder<TColor>.FromRGBA(224, 255, 255, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LightGoldenrodYellow = ColorBuilder<TColor>.FromRGBA(250, 250, 210, 255); public static readonly TColor LightGoldenrodYellow = ColorBuilder<TColor>.FromRGBA(250, 250, 210, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LightGray = ColorBuilder<TColor>.FromRGBA(211, 211, 211, 255); public static readonly TColor LightGray = ColorBuilder<TColor>.FromRGBA(211, 211, 211, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LightGreen = ColorBuilder<TColor>.FromRGBA(144, 238, 144, 255); public static readonly TColor LightGreen = ColorBuilder<TColor>.FromRGBA(144, 238, 144, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LightPink = ColorBuilder<TColor>.FromRGBA(255, 182, 193, 255); public static readonly TColor LightPink = ColorBuilder<TColor>.FromRGBA(255, 182, 193, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LightSalmon = ColorBuilder<TColor>.FromRGBA(255, 160, 122, 255); public static readonly TColor LightSalmon = ColorBuilder<TColor>.FromRGBA(255, 160, 122, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LightSeaGreen = ColorBuilder<TColor>.FromRGBA(32, 178, 170, 255); public static readonly TColor LightSeaGreen = ColorBuilder<TColor>.FromRGBA(32, 178, 170, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LightSkyBlue = ColorBuilder<TColor>.FromRGBA(135, 206, 250, 255); public static readonly TColor LightSkyBlue = ColorBuilder<TColor>.FromRGBA(135, 206, 250, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LightSlateGray = ColorBuilder<TColor>.FromRGBA(119, 136, 153, 255); public static readonly TColor LightSlateGray = ColorBuilder<TColor>.FromRGBA(119, 136, 153, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LightSteelBlue = ColorBuilder<TColor>.FromRGBA(176, 196, 222, 255); public static readonly TColor LightSteelBlue = ColorBuilder<TColor>.FromRGBA(176, 196, 222, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LightYellow = ColorBuilder<TColor>.FromRGBA(255, 255, 224, 255); public static readonly TColor LightYellow = ColorBuilder<TColor>.FromRGBA(255, 255, 224, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Lime = ColorBuilder<TColor>.FromRGBA(0, 255, 0, 255); public static readonly TColor Lime = ColorBuilder<TColor>.FromRGBA(0, 255, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor LimeGreen = ColorBuilder<TColor>.FromRGBA(50, 205, 50, 255); public static readonly TColor LimeGreen = ColorBuilder<TColor>.FromRGBA(50, 205, 50, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Linen = ColorBuilder<TColor>.FromRGBA(250, 240, 230, 255); public static readonly TColor Linen = ColorBuilder<TColor>.FromRGBA(250, 240, 230, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Magenta = ColorBuilder<TColor>.FromRGBA(255, 0, 255, 255); public static readonly TColor Magenta = ColorBuilder<TColor>.FromRGBA(255, 0, 255, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Maroon = ColorBuilder<TColor>.FromRGBA(128, 0, 0, 255); public static readonly TColor Maroon = ColorBuilder<TColor>.FromRGBA(128, 0, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor MediumAquamarine = ColorBuilder<TColor>.FromRGBA(102, 205, 170, 255); public static readonly TColor MediumAquamarine = ColorBuilder<TColor>.FromRGBA(102, 205, 170, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor MediumBlue = ColorBuilder<TColor>.FromRGBA(0, 0, 205, 255); public static readonly TColor MediumBlue = ColorBuilder<TColor>.FromRGBA(0, 0, 205, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor MediumOrchid = ColorBuilder<TColor>.FromRGBA(186, 85, 211, 255); public static readonly TColor MediumOrchid = ColorBuilder<TColor>.FromRGBA(186, 85, 211, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor MediumPurple = ColorBuilder<TColor>.FromRGBA(147, 112, 219, 255); public static readonly TColor MediumPurple = ColorBuilder<TColor>.FromRGBA(147, 112, 219, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor MediumSeaGreen = ColorBuilder<TColor>.FromRGBA(60, 179, 113, 255); public static readonly TColor MediumSeaGreen = ColorBuilder<TColor>.FromRGBA(60, 179, 113, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor MediumSlateBlue = ColorBuilder<TColor>.FromRGBA(123, 104, 238, 255); public static readonly TColor MediumSlateBlue = ColorBuilder<TColor>.FromRGBA(123, 104, 238, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor MediumSpringGreen = ColorBuilder<TColor>.FromRGBA(0, 250, 154, 255); public static readonly TColor MediumSpringGreen = ColorBuilder<TColor>.FromRGBA(0, 250, 154, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor MediumTurquoise = ColorBuilder<TColor>.FromRGBA(72, 209, 204, 255); public static readonly TColor MediumTurquoise = ColorBuilder<TColor>.FromRGBA(72, 209, 204, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor MediumVioletRed = ColorBuilder<TColor>.FromRGBA(199, 21, 133, 255); public static readonly TColor MediumVioletRed = ColorBuilder<TColor>.FromRGBA(199, 21, 133, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor MidnightBlue = ColorBuilder<TColor>.FromRGBA(25, 25, 112, 255); public static readonly TColor MidnightBlue = ColorBuilder<TColor>.FromRGBA(25, 25, 112, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor MintCream = ColorBuilder<TColor>.FromRGBA(245, 255, 250, 255); public static readonly TColor MintCream = ColorBuilder<TColor>.FromRGBA(245, 255, 250, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor MistyRose = ColorBuilder<TColor>.FromRGBA(255, 228, 225, 255); public static readonly TColor MistyRose = ColorBuilder<TColor>.FromRGBA(255, 228, 225, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Moccasin = ColorBuilder<TColor>.FromRGBA(255, 228, 181, 255); public static readonly TColor Moccasin = ColorBuilder<TColor>.FromRGBA(255, 228, 181, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor NavajoWhite = ColorBuilder<TColor>.FromRGBA(255, 222, 173, 255); public static readonly TColor NavajoWhite = ColorBuilder<TColor>.FromRGBA(255, 222, 173, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Navy = ColorBuilder<TColor>.FromRGBA(0, 0, 128, 255); public static readonly TColor Navy = ColorBuilder<TColor>.FromRGBA(0, 0, 128, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor OldLace = ColorBuilder<TColor>.FromRGBA(253, 245, 230, 255); public static readonly TColor OldLace = ColorBuilder<TColor>.FromRGBA(253, 245, 230, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Olive = ColorBuilder<TColor>.FromRGBA(128, 128, 0, 255); public static readonly TColor Olive = ColorBuilder<TColor>.FromRGBA(128, 128, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor OliveDrab = ColorBuilder<TColor>.FromRGBA(107, 142, 35, 255); public static readonly TColor OliveDrab = ColorBuilder<TColor>.FromRGBA(107, 142, 35, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Orange = ColorBuilder<TColor>.FromRGBA(255, 165, 0, 255); public static readonly TColor Orange = ColorBuilder<TColor>.FromRGBA(255, 165, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor OrangeRed = ColorBuilder<TColor>.FromRGBA(255, 69, 0, 255); public static readonly TColor OrangeRed = ColorBuilder<TColor>.FromRGBA(255, 69, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Orchid = ColorBuilder<TColor>.FromRGBA(218, 112, 214, 255); public static readonly TColor Orchid = ColorBuilder<TColor>.FromRGBA(218, 112, 214, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor PaleGoldenrod = ColorBuilder<TColor>.FromRGBA(238, 232, 170, 255); public static readonly TColor PaleGoldenrod = ColorBuilder<TColor>.FromRGBA(238, 232, 170, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor PaleGreen = ColorBuilder<TColor>.FromRGBA(152, 251, 152, 255); public static readonly TColor PaleGreen = ColorBuilder<TColor>.FromRGBA(152, 251, 152, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor PaleTurquoise = ColorBuilder<TColor>.FromRGBA(175, 238, 238, 255); public static readonly TColor PaleTurquoise = ColorBuilder<TColor>.FromRGBA(175, 238, 238, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor PaleVioletRed = ColorBuilder<TColor>.FromRGBA(219, 112, 147, 255); public static readonly TColor PaleVioletRed = ColorBuilder<TColor>.FromRGBA(219, 112, 147, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor PapayaWhip = ColorBuilder<TColor>.FromRGBA(255, 239, 213, 255); public static readonly TColor PapayaWhip = ColorBuilder<TColor>.FromRGBA(255, 239, 213, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor PeachPuff = ColorBuilder<TColor>.FromRGBA(255, 218, 185, 255); public static readonly TColor PeachPuff = ColorBuilder<TColor>.FromRGBA(255, 218, 185, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Peru = ColorBuilder<TColor>.FromRGBA(205, 133, 63, 255); public static readonly TColor Peru = ColorBuilder<TColor>.FromRGBA(205, 133, 63, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Pink = ColorBuilder<TColor>.FromRGBA(255, 192, 203, 255); public static readonly TColor Pink = ColorBuilder<TColor>.FromRGBA(255, 192, 203, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Plum = ColorBuilder<TColor>.FromRGBA(221, 160, 221, 255); public static readonly TColor Plum = ColorBuilder<TColor>.FromRGBA(221, 160, 221, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor PowderBlue = ColorBuilder<TColor>.FromRGBA(176, 224, 230, 255); public static readonly TColor PowderBlue = ColorBuilder<TColor>.FromRGBA(176, 224, 230, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Purple = ColorBuilder<TColor>.FromRGBA(128, 0, 128, 255); public static readonly TColor Purple = ColorBuilder<TColor>.FromRGBA(128, 0, 128, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor RebeccaPurple = ColorBuilder<TColor>.FromRGBA(102, 51, 153, 255); public static readonly TColor RebeccaPurple = ColorBuilder<TColor>.FromRGBA(102, 51, 153, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Red = ColorBuilder<TColor>.FromRGBA(255, 0, 0, 255); public static readonly TColor Red = ColorBuilder<TColor>.FromRGBA(255, 0, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor RosyBrown = ColorBuilder<TColor>.FromRGBA(188, 143, 143, 255); public static readonly TColor RosyBrown = ColorBuilder<TColor>.FromRGBA(188, 143, 143, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor RoyalBlue = ColorBuilder<TColor>.FromRGBA(65, 105, 225, 255); public static readonly TColor RoyalBlue = ColorBuilder<TColor>.FromRGBA(65, 105, 225, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor SaddleBrown = ColorBuilder<TColor>.FromRGBA(139, 69, 19, 255); public static readonly TColor SaddleBrown = ColorBuilder<TColor>.FromRGBA(139, 69, 19, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Salmon = ColorBuilder<TColor>.FromRGBA(250, 128, 114, 255); public static readonly TColor Salmon = ColorBuilder<TColor>.FromRGBA(250, 128, 114, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor SandyBrown = ColorBuilder<TColor>.FromRGBA(244, 164, 96, 255); public static readonly TColor SandyBrown = ColorBuilder<TColor>.FromRGBA(244, 164, 96, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor SeaGreen = ColorBuilder<TColor>.FromRGBA(46, 139, 87, 255); public static readonly TColor SeaGreen = ColorBuilder<TColor>.FromRGBA(46, 139, 87, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor SeaShell = ColorBuilder<TColor>.FromRGBA(255, 245, 238, 255); public static readonly TColor SeaShell = ColorBuilder<TColor>.FromRGBA(255, 245, 238, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Sienna = ColorBuilder<TColor>.FromRGBA(160, 82, 45, 255); public static readonly TColor Sienna = ColorBuilder<TColor>.FromRGBA(160, 82, 45, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Silver = ColorBuilder<TColor>.FromRGBA(192, 192, 192, 255); public static readonly TColor Silver = ColorBuilder<TColor>.FromRGBA(192, 192, 192, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor SkyBlue = ColorBuilder<TColor>.FromRGBA(135, 206, 235, 255); public static readonly TColor SkyBlue = ColorBuilder<TColor>.FromRGBA(135, 206, 235, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor SlateBlue = ColorBuilder<TColor>.FromRGBA(106, 90, 205, 255); public static readonly TColor SlateBlue = ColorBuilder<TColor>.FromRGBA(106, 90, 205, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor SlateGray = ColorBuilder<TColor>.FromRGBA(112, 128, 144, 255); public static readonly TColor SlateGray = ColorBuilder<TColor>.FromRGBA(112, 128, 144, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Snow = ColorBuilder<TColor>.FromRGBA(255, 250, 250, 255); public static readonly TColor Snow = ColorBuilder<TColor>.FromRGBA(255, 250, 250, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor SpringGreen = ColorBuilder<TColor>.FromRGBA(0, 255, 127, 255); public static readonly TColor SpringGreen = ColorBuilder<TColor>.FromRGBA(0, 255, 127, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor SteelBlue = ColorBuilder<TColor>.FromRGBA(70, 130, 180, 255); public static readonly TColor SteelBlue = ColorBuilder<TColor>.FromRGBA(70, 130, 180, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Tan = ColorBuilder<TColor>.FromRGBA(210, 180, 140, 255); public static readonly TColor Tan = ColorBuilder<TColor>.FromRGBA(210, 180, 140, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Teal = ColorBuilder<TColor>.FromRGBA(0, 128, 128, 255); public static readonly TColor Teal = ColorBuilder<TColor>.FromRGBA(0, 128, 128, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Thistle = ColorBuilder<TColor>.FromRGBA(216, 191, 216, 255); public static readonly TColor Thistle = ColorBuilder<TColor>.FromRGBA(216, 191, 216, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Tomato = ColorBuilder<TColor>.FromRGBA(255, 99, 71, 255); public static readonly TColor Tomato = ColorBuilder<TColor>.FromRGBA(255, 99, 71, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Transparent = ColorBuilder<TColor>.FromRGBA(255, 255, 255, 0); public static readonly TColor Transparent = ColorBuilder<TColor>.FromRGBA(255, 255, 255, 0);
/// <summary> /// <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> /// </summary>
public static readonly TColor Turquoise = ColorBuilder<TColor>.FromRGBA(64, 224, 208, 255); public static readonly TColor Turquoise = ColorBuilder<TColor>.FromRGBA(64, 224, 208, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Violet = ColorBuilder<TColor>.FromRGBA(238, 130, 238, 255); public static readonly TColor Violet = ColorBuilder<TColor>.FromRGBA(238, 130, 238, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Wheat = ColorBuilder<TColor>.FromRGBA(245, 222, 179, 255); public static readonly TColor Wheat = ColorBuilder<TColor>.FromRGBA(245, 222, 179, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor White = ColorBuilder<TColor>.FromRGBA(255, 255, 255, 255); public static readonly TColor White = ColorBuilder<TColor>.FromRGBA(255, 255, 255, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor WhiteSmoke = ColorBuilder<TColor>.FromRGBA(245, 245, 245, 255); public static readonly TColor WhiteSmoke = ColorBuilder<TColor>.FromRGBA(245, 245, 245, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor Yellow = ColorBuilder<TColor>.FromRGBA(255, 255, 0, 255); public static readonly TColor Yellow = ColorBuilder<TColor>.FromRGBA(255, 255, 0, 255);
/// <summary> /// <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> /// </summary>
public static readonly TColor YellowGreen = ColorBuilder<TColor>.FromRGBA(154, 205, 50, 255); 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. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
@ -17,7 +17,7 @@ namespace ImageSharp
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, /// 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. /// as it avoids the need to create new values for modification operations.
/// </remarks> /// </remarks>
public struct Argb : IPixel<Argb>, IPackedVector<uint> public struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
{ {
/// <summary> /// <summary>
/// The shift count for the blue component /// The shift count for the blue component
@ -50,58 +50,58 @@ namespace ImageSharp
private static readonly Vector4 Half = new Vector4(0.5F); private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Argb"/> struct. /// Initializes a new instance of the <see cref="Argb32"/> struct.
/// </summary> /// </summary>
/// <param name="r">The red component.</param> /// <param name="r">The red component.</param>
/// <param name="g">The green component.</param> /// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param> /// <param name="b">The blue component.</param>
/// <param name="a">The alpha 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); this.PackedValue = Pack(r, g, b, a);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Argb"/> struct. /// Initializes a new instance of the <see cref="Argb32"/> struct.
/// </summary> /// </summary>
/// <param name="r">The red component.</param> /// <param name="r">The red component.</param>
/// <param name="g">The green component.</param> /// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param> /// <param name="b">The blue component.</param>
/// <param name="a">The alpha 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); this.PackedValue = Pack(r, g, b, a);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Argb"/> struct. /// Initializes a new instance of the <see cref="Argb32"/> struct.
/// </summary> /// </summary>
/// <param name="vector"> /// <param name="vector">
/// The vector containing the components for the packed vector. /// The vector containing the components for the packed vector.
/// </param> /// </param>
public Argb(Vector3 vector) public Argb32(Vector3 vector)
{ {
this.PackedValue = Pack(ref vector); this.PackedValue = Pack(ref vector);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Argb"/> struct. /// Initializes a new instance of the <see cref="Argb32"/> struct.
/// </summary> /// </summary>
/// <param name="vector"> /// <param name="vector">
/// The vector containing the components for the packed vector. /// The vector containing the components for the packed vector.
/// </param> /// </param>
public Argb(Vector4 vector) public Argb32(Vector4 vector)
{ {
this.PackedValue = Pack(ref vector); this.PackedValue = Pack(ref vector);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Argb"/> struct. /// Initializes a new instance of the <see cref="Argb32"/> struct.
/// </summary> /// </summary>
/// <param name="packed"> /// <param name="packed">
/// The packed value. /// The packed value.
/// </param> /// </param>
public Argb(uint packed = 0) public Argb32(uint packed = 0)
{ {
this.PackedValue = packed; this.PackedValue = packed;
} }
@ -182,33 +182,33 @@ namespace ImageSharp
} }
/// <summary> /// <summary>
/// Compares two <see cref="Argb"/> objects for equality. /// Compares two <see cref="Argb32"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <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>
/// <param name="right"> /// <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> /// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Argb left, Argb right) public static bool operator ==(Argb32 left, Argb32 right)
{ {
return left.PackedValue == right.PackedValue; return left.PackedValue == right.PackedValue;
} }
/// <summary> /// <summary>
/// Compares two <see cref="Argb"/> objects for equality. /// Compares two <see cref="Argb32"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left">The <see cref="Argb"/> on the left 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="Argb"/> on the right side of the operand.</param> /// <param name="right">The <see cref="Argb32"/> on the right side of the operand.</param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Argb left, Argb right) public static bool operator !=(Argb32 left, Argb32 right)
{ {
return left.PackedValue != right.PackedValue; return left.PackedValue != right.PackedValue;
} }
@ -221,7 +221,7 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public BulkPixelOperations<Argb> CreateBulkOperations() => new BulkPixelOperations<Argb>(); public BulkPixelOperations<Argb32> CreateBulkOperations() => new BulkPixelOperations<Argb32>();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -278,12 +278,12 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
return obj is Argb && this.Equals((Argb)obj); return obj is Argb32 && this.Equals((Argb32)obj);
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Argb other) public bool Equals(Argb32 other)
{ {
return this.PackedValue == other.PackedValue; 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"/>. /// for pixel buffers of type <typeparamref name="TColor"/>.
/// </summary> /// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam> /// <typeparam name="TColor">The pixel format.</typeparam>
public unsafe class BulkPixelOperations<TColor> public class BulkPixelOperations<TColor>
where TColor : struct, IPixel<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> /// <summary>
/// Gets the global <see cref="BulkPixelOperations{TColor}"/> instance for the pixel type <typeparamref name="TColor"/> /// Gets the global <see cref="BulkPixelOperations{TColor}"/> instance for the pixel type <typeparamref name="TColor"/>
/// </summary> /// </summary>
@ -32,23 +27,16 @@ namespace ImageSharp
/// <param name="sourceVectors">The <see cref="BufferSpan{T}"/> to the source vectors.</param> /// <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="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromVector4( internal virtual void PackFromVector4(BufferSpan<Vector4> sourceVectors, BufferSpan<TColor> destColors, int count)
BufferSpan<Vector4> sourceVectors,
BufferSpan<TColor> destColors,
int count)
{ {
Vector4* sp = (Vector4*)sourceVectors.PointerAtOffset; ref Vector4 sourceRef = ref sourceVectors.DangerousGetPinnableReference();
byte* dp = (byte*)destColors; ref TColor destRef = ref destColors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
Vector4 v = Unsafe.Read<Vector4>(sp); ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i);
TColor c = default(TColor); ref TColor dp = ref Unsafe.Add(ref destRef, i);
c.PackFromVector4(v); dp.PackFromVector4(sp);
Unsafe.Write(dp, c);
sp++;
dp += ColorSize;
} }
} }
@ -58,20 +46,16 @@ namespace ImageSharp
/// <param name="sourceColors">The <see cref="BufferSpan{T}"/> to the source colors.</param> /// <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="destVectors">The <see cref="BufferSpan{T}"/> to the destination vectors.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToVector4( internal virtual void ToVector4(BufferSpan<TColor> sourceColors, BufferSpan<Vector4> destVectors, int count)
BufferSpan<TColor> sourceColors,
BufferSpan<Vector4> destVectors,
int count)
{ {
byte* sp = (byte*)sourceColors; ref TColor sourceRef = ref sourceColors.DangerousGetPinnableReference();
Vector4* dp = (Vector4*)destVectors.PointerAtOffset; ref Vector4 destRef = ref destVectors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
TColor c = Unsafe.Read<TColor>(sp); ref TColor sp = ref Unsafe.Add(ref sourceRef, i);
*dp = c.ToVector4(); ref Vector4 dp = ref Unsafe.Add(ref destRef, i);
sp += ColorSize; dp = sp.ToVector4();
dp++;
} }
} }
@ -81,21 +65,20 @@ namespace ImageSharp
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param> /// <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="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromXyzBytes( internal virtual void PackFromXyzBytes(BufferSpan<byte> sourceBytes, BufferSpan<TColor> destColors, int count)
BufferSpan<byte> sourceBytes,
BufferSpan<TColor> destColors,
int count)
{ {
byte* sp = (byte*)sourceBytes; ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
byte* dp = (byte*)destColors.PointerAtOffset; ref TColor destRef = ref destColors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
TColor c = default(TColor); int i3 = i * 3;
c.PackFromBytes(sp[0], sp[1], sp[2], 255); ref TColor dp = ref Unsafe.Add(ref destRef, i);
Unsafe.Write(dp, c); dp.PackFromBytes(
sp += 3; Unsafe.Add(ref sourceRef, i3),
dp += ColorSize; 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> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToXyzBytes(BufferSpan<TColor> sourceColors, BufferSpan<byte> destBytes, int count) 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; 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); ref TColor sp = ref Unsafe.Add(ref sourceRef, i);
c.ToXyzBytes(dest, i); sp.ToXyzBytes(dest, destBytes.Start + (i * 3));
sp += ColorSize;
} }
} }
@ -124,21 +106,20 @@ namespace ImageSharp
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param> /// <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="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromXyzwBytes( internal virtual void PackFromXyzwBytes(BufferSpan<byte> sourceBytes, BufferSpan<TColor> destColors, int count)
BufferSpan<byte> sourceBytes,
BufferSpan<TColor> destColors,
int count)
{ {
byte* sp = (byte*)sourceBytes; ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
byte* dp = (byte*)destColors.PointerAtOffset; ref TColor destRef = ref destColors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
TColor c = default(TColor); int i4 = i * 4;
c.PackFromBytes(sp[0], sp[1], sp[2], sp[3]); ref TColor dp = ref Unsafe.Add(ref destRef, i);
Unsafe.Write(dp, c); dp.PackFromBytes(
sp += 4; Unsafe.Add(ref sourceRef, i4),
dp += ColorSize; 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="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="destBytes">The <see cref="BufferSpan{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToXyzwBytes( internal virtual void ToXyzwBytes(BufferSpan<TColor> sourceColors, BufferSpan<byte> destBytes, int count)
BufferSpan<TColor> sourceColors,
BufferSpan<byte> destBytes,
int count)
{ {
byte* sp = (byte*)sourceColors; ref TColor sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte[] dest = destBytes.Array; 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); ref TColor sp = ref Unsafe.Add(ref sourceRef, i);
c.ToXyzwBytes(dest, i); sp.ToXyzwBytes(dest, destBytes.Start + (i * 4));
sp += ColorSize;
} }
} }
@ -170,21 +147,20 @@ namespace ImageSharp
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param> /// <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="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromZyxBytes( internal virtual void PackFromZyxBytes(BufferSpan<byte> sourceBytes, BufferSpan<TColor> destColors, int count)
BufferSpan<byte> sourceBytes,
BufferSpan<TColor> destColors,
int count)
{ {
byte* sp = (byte*)sourceBytes; ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
byte* dp = (byte*)destColors.PointerAtOffset; ref TColor destRef = ref destColors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
TColor c = default(TColor); int i3 = i * 3;
c.PackFromBytes(sp[2], sp[1], sp[0], 255); ref TColor dp = ref Unsafe.Add(ref destRef, i);
Unsafe.Write(dp, c); dp.PackFromBytes(
sp += 3; Unsafe.Add(ref sourceRef, i3 + 2),
dp += ColorSize; 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> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToZyxBytes(BufferSpan<TColor> sourceColors, BufferSpan<byte> destBytes, int count) 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; 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); ref TColor sp = ref Unsafe.Add(ref sourceRef, i);
c.ToZyxBytes(dest, i); sp.ToZyxBytes(dest, destBytes.Start + (i * 3));
sp += ColorSize;
} }
} }
@ -213,21 +188,20 @@ namespace ImageSharp
/// <param name="sourceBytes">The <see cref="BufferSpan{T}"/> to the source bytes.</param> /// <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="destColors">The <see cref="BufferSpan{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromZyxwBytes( internal virtual void PackFromZyxwBytes(BufferSpan<byte> sourceBytes, BufferSpan<TColor> destColors, int count)
BufferSpan<byte> sourceBytes,
BufferSpan<TColor> destColors,
int count)
{ {
byte* sp = (byte*)sourceBytes; ref byte sourceRef = ref sourceBytes.DangerousGetPinnableReference();
byte* dp = (byte*)destColors.PointerAtOffset; ref TColor destRef = ref destColors.DangerousGetPinnableReference();
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
TColor c = default(TColor); int i4 = i * 4;
c.PackFromBytes(sp[2], sp[1], sp[0], sp[3]); ref TColor dp = ref Unsafe.Add(ref destRef, i);
Unsafe.Write(dp, c); dp.PackFromBytes(
sp += 4; Unsafe.Add(ref sourceRef, i4 + 2),
dp += ColorSize; 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="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="destBytes">The <see cref="BufferSpan{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToZyxwBytes( internal virtual void ToZyxwBytes(BufferSpan<TColor> sourceColors, BufferSpan<byte> destBytes, int count)
BufferSpan<TColor> sourceColors,
BufferSpan<byte> destBytes,
int count)
{ {
byte* sp = (byte*)sourceColors; ref TColor sourceRef = ref sourceColors.DangerousGetPinnableReference();
byte[] dest = destBytes.Array; 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); ref TColor sp = ref Unsafe.Add(ref sourceRef, i);
c.ToZyxwBytes(dest, i); sp.ToZyxwBytes(dest, destBytes.Start + (i * 4));
sp += ColorSize;
} }
} }
} }

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

@ -300,7 +300,7 @@ namespace ImageSharp
private static bool IsStandardNormalizedType(Type type) private static bool IsStandardNormalizedType(Type type)
{ {
return type == typeof(Color) return type == typeof(Color)
|| type == typeof(Argb) || type == typeof(Argb32)
|| type == typeof(Alpha8) || type == typeof(Alpha8)
|| type == typeof(Bgr565) || type == typeof(Bgr565)
|| type == typeof(Bgra4444) || 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. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
@ -11,13 +11,18 @@ namespace ImageSharp
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
/// <summary> /// <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. /// The backing array is either pooled or comes from the outside.
/// </summary> /// </summary>
/// <typeparam name="T">The value type.</typeparam> /// <typeparam name="T">The value type.</typeparam>
internal class PinnedBuffer<T> : IDisposable internal class Buffer<T> : IDisposable
where T : struct where T : struct
{ {
/// <summary>
/// A pointer to the first element of <see cref="Array"/> when pinned.
/// </summary>
private IntPtr pointer;
/// <summary> /// <summary>
/// A handle that allows to access the managed <see cref="Array"/> as an unmanaged memory by pinning. /// A handle that allows to access the managed <see cref="Array"/> as an unmanaged memory by pinning.
/// </summary> /// </summary>
@ -25,40 +30,38 @@ namespace ImageSharp
/// <summary> /// <summary>
/// A value indicating wheter <see cref="Array"/> should be returned to <see cref="PixelDataPool{T}"/> /// 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> /// </summary>
private bool isPoolingOwner; private bool isPoolingOwner;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PinnedBuffer{T}"/> class. /// Initializes a new instance of the <see cref="Buffer{T}"/> class.
/// </summary> /// </summary>
/// <param name="length">The desired count of elements. (Minimum size for <see cref="Array"/>)</param> /// <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.Length = length;
this.Array = PixelDataPool<T>.Rent(length); this.Array = PixelDataPool<T>.Rent(length);
this.isPoolingOwner = true; this.isPoolingOwner = true;
this.Pin();
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PinnedBuffer{T}"/> class. /// Initializes a new instance of the <see cref="Buffer{T}"/> class.
/// </summary> /// </summary>
/// <param name="array">The array to pin.</param> /// <param name="array">The array to pin.</param>
public PinnedBuffer(T[] array) public Buffer(T[] array)
{ {
this.Length = array.Length; this.Length = array.Length;
this.Array = array; this.Array = array;
this.isPoolingOwner = false; this.isPoolingOwner = false;
this.Pin();
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PinnedBuffer{T}"/> class. /// Initializes a new instance of the <see cref="Buffer{T}"/> class.
/// </summary> /// </summary>
/// <param name="array">The array to pin.</param> /// <param name="array">The array to pin.</param>
/// <param name="length">The count of "relevant" elements in 'array'.</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) if (array.Length < length)
{ {
@ -68,19 +71,18 @@ namespace ImageSharp
this.Length = length; this.Length = length;
this.Array = array; this.Array = array;
this.isPoolingOwner = false; this.isPoolingOwner = false;
this.Pin();
} }
/// <summary> /// <summary>
/// Finalizes an instance of the <see cref="PinnedBuffer{T}"/> class. /// Finalizes an instance of the <see cref="Buffer{T}"/> class.
/// </summary> /// </summary>
~PinnedBuffer() ~Buffer()
{ {
this.UnPin(); this.UnPin();
} }
/// <summary> /// <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> /// </summary>
public bool IsDisposedOrLostArrayOwnership { get; private set; } public bool IsDisposedOrLostArrayOwnership { get; private set; }
@ -94,11 +96,6 @@ namespace ImageSharp
/// </summary> /// </summary>
public T[] Array { get; private set; } public T[] Array { get; private set; }
/// <summary>
/// Gets a pointer to the pinned <see cref="Array"/>.
/// </summary>
public IntPtr Pointer { get; private set; }
/// <summary> /// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the backing buffer. /// Gets a <see cref="BufferSpan{T}"/> to the backing buffer.
/// </summary> /// </summary>
@ -109,37 +106,35 @@ namespace ImageSharp
/// </summary> /// </summary>
/// <param name="index">The index</param> /// <param name="index">The index</param>
/// <returns>The reference to the specified element</returns> /// <returns>The reference to the specified element</returns>
public unsafe ref T this[int index] public ref T this[int index]
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get get
{ {
DebugGuard.MustBeLessThan(index, this.Length, nameof(index)); DebugGuard.MustBeLessThan(index, this.Length, nameof(index));
return ref this.Array[index];
byte* ptr = (byte*)this.Pointer + BufferSpan.SizeOf<T>(index);
return ref Unsafe.AsRef<T>(ptr);
} }
} }
/// <summary> /// <summary>
/// Converts <see cref="PinnedBuffer{T}"/> to an <see cref="BufferSpan{T}"/>. /// Converts <see cref="Buffer{T}"/> to an <see cref="BufferSpan{T}"/>.
/// </summary> /// </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)] [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> /// <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> /// </summary>
/// <param name="count">The desired count of elements. (Minimum size for <see cref="Array"/>)</param> /// <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)] [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(); buffer.Clear();
return buffer; return buffer;
} }
@ -150,9 +145,9 @@ namespace ImageSharp
/// <param name="start">The start</param> /// <param name="start">The start</param>
/// <returns>The <see cref="BufferSpan{T}"/></returns> /// <returns>The <see cref="BufferSpan{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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> /// <summary>
@ -162,13 +157,13 @@ namespace ImageSharp
/// <param name="length">The length of the slice</param> /// <param name="length">The length of the slice</param>
/// <returns>The <see cref="BufferSpan{T}"/></returns> /// <returns>The <see cref="BufferSpan{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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> /// <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> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose() public void Dispose()
@ -199,11 +194,11 @@ namespace ImageSharp
/// </summary> /// </summary>
/// <returns>The unpinned <see cref="Array"/></returns> /// <returns>The unpinned <see cref="Array"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public T[] UnPinAndTakeArrayOwnership() public T[] TakeArrayOwnership()
{ {
if (this.IsDisposedOrLostArrayOwnership) 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; this.IsDisposedOrLostArrayOwnership = true;
@ -220,17 +215,29 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Clear() public void Clear()
{ {
((BufferSpan<T>)this).Clear(); this.Span.Clear();
} }
/// <summary> /// <summary>
/// Pins <see cref="Array"/>. /// Pins <see cref="Array"/>.
/// </summary> /// </summary>
/// <returns>The pinned pointer</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void Pin() public IntPtr Pin()
{ {
this.handle = GCHandle.Alloc(this.Array, GCHandleType.Pinned); if (this.IsDisposedOrLostArrayOwnership)
this.Pointer = this.handle.AddrOfPinnedObject(); {
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> /// <summary>
@ -239,13 +246,13 @@ namespace ImageSharp
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void UnPin() private void UnPin()
{ {
if (this.Pointer == IntPtr.Zero || !this.handle.IsAllocated) if (this.pointer == IntPtr.Zero || !this.handle.IsAllocated)
{ {
return; return;
} }
this.handle.Free(); 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. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
@ -9,19 +9,19 @@ namespace ImageSharp
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
/// <summary> /// <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. /// interpreted as a 2D region of <see cref="Width"/> x <see cref="Height"/> elements.
/// </summary> /// </summary>
/// <typeparam name="T">The value type.</typeparam> /// <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 where T : struct
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PinnedImageBuffer{T}"/> class. /// Initializes a new instance of the <see cref="Buffer2D{T}"/> class.
/// </summary> /// </summary>
/// <param name="width">The number of elements in a row</param> /// <param name="width">The number of elements in a row</param>
/// <param name="height">The number of rows</param> /// <param name="height">The number of rows</param>
public PinnedImageBuffer(int width, int height) public Buffer2D(int width, int height)
: base(width * height) : base(width * height)
{ {
this.Width = width; this.Width = width;
@ -29,12 +29,12 @@ namespace ImageSharp
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PinnedImageBuffer{T}"/> class. /// Initializes a new instance of the <see cref="Buffer2D{T}"/> class.
/// </summary> /// </summary>
/// <param name="array">The array to pin</param> /// <param name="array">The array to pin</param>
/// <param name="width">The number of elements in a row</param> /// <param name="width">The number of elements in a row</param>
/// <param name="height">The number of rows</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) : base(array, width * height)
{ {
this.Width = width; this.Width = width;
@ -63,14 +63,14 @@ namespace ImageSharp
} }
/// <summary> /// <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> /// </summary>
/// <param name="width">The number of elements in a row</param> /// <param name="width">The number of elements in a row</param>
/// <param name="height">The number of rows</param> /// <param name="height">The number of rows</param>
/// <returns>The <see cref="PinnedBuffer{T}"/> instance</returns> /// <returns>The <see cref="Buffer{T}"/> instance</returns>
public static PinnedImageBuffer<T> CreateClean(int width, int height) 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(); buffer.Clear();
return buffer; 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. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
@ -9,9 +9,9 @@ namespace ImageSharp
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
/// <summary> /// <summary>
/// Defines extension methods for <see cref="IPinnedImageBuffer{T}"/>. /// Defines extension methods for <see cref="IBuffer2D{T}"/>.
/// </summary> /// </summary>
internal static class PinnedImageBufferExtensions internal static class Buffer2DExtensions
{ {
/// <summary> /// <summary>
/// Gets a <see cref="BufferSpan{T}"/> to the row 'y' beginning from the pixel at 'x'. /// 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> /// <typeparam name="T">The element type</typeparam>
/// <returns>The <see cref="BufferSpan{T}"/></returns> /// <returns>The <see cref="BufferSpan{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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 where T : struct
{ {
return buffer.Span.Slice((y * buffer.Width) + x, buffer.Width - x); return buffer.Span.Slice((y * buffer.Width) + x, buffer.Width - x);
@ -36,7 +36,7 @@ namespace ImageSharp
/// <typeparam name="T">The element type</typeparam> /// <typeparam name="T">The element type</typeparam>
/// <returns>The <see cref="BufferSpan{T}"/></returns> /// <returns>The <see cref="BufferSpan{T}"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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 where T : struct
{ {
return buffer.Span.Slice(y * buffer.Width, buffer.Width); return buffer.Span.Slice(y * buffer.Width, buffer.Width);

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

@ -6,7 +6,6 @@
namespace ImageSharp namespace ImageSharp
{ {
using System; using System;
using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -15,60 +14,49 @@ namespace ImageSharp
/// </summary> /// </summary>
internal static class BufferSpan 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> /// <summary>
/// Copy 'count' number of elements of the same type from 'source' to 'dest' /// Copy 'count' number of elements of the same type from 'source' to 'dest'
/// </summary> /// </summary>
/// <typeparam name="T">The element type.</typeparam> /// <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="destination">The destination <see cref="BufferSpan{T}"/>.</param>
/// <param name="count">The number of elements to copy</param> /// <param name="count">The number of elements to copy</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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 where T : struct
{ {
CopyImpl(source, destination, count); DebugGuard.MustBeLessThanOrEqualTo(count, source.Length, nameof(count));
} DebugGuard.MustBeLessThanOrEqualTo(count, destination.Length, nameof(count));
/// <summary> ref byte srcRef = ref Unsafe.As<T, byte>(ref source.DangerousGetPinnableReference());
/// Copy 'countInSource' elements of <typeparamref name="T"/> from 'source' into the raw byte buffer 'destination'. ref byte destRef = ref Unsafe.As<T, byte>(ref destination.DangerousGetPinnableReference());
/// </summary>
/// <typeparam name="T">The element type.</typeparam> int byteCount = Unsafe.SizeOf<T>() * count;
/// <param name="source">The source buffer of <typeparamref name="T"/> elements to copy from.</param>
/// <param name="destination">The destination buffer.</param> // TODO: Use unfixed Unsafe.CopyBlock(ref T, ref T, int) for small blocks, when it gets available!
/// <param name="countInSource">The number of elements to copy from 'source'</param> fixed (byte* pSrc = &srcRef)
[MethodImpl(MethodImplOptions.AggressiveInlining)] fixed (byte* pDest = &destRef)
public static void Copy<T>(BufferSpan<T> source, BufferSpan<byte> destination, int countInSource) {
where T : struct #if NETSTANDARD1_1
{ Unsafe.CopyBlock(pDest, pSrc, (uint)byteCount);
CopyImpl(source, destination, countInSource); #else
int destLength = destination.Length * Unsafe.SizeOf<T>();
Buffer.MemoryCopy(pSrc, pDest, destLength, byteCount);
#endif
}
} }
/// <summary> /// <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> /// </summary>
/// <typeparam name="T">The element type.</typeparam> /// <typeparam name="T">The element type.</typeparam>
/// <param name="source">The raw source buffer to copy from"/></param> /// <param name="source">The <see cref="BufferSpan{T}"/> to copy elements from.</param>
/// <param name="destination">The destination buffer"/></param> /// <param name="destination">The destination <see cref="BufferSpan{T}"/>.</param>
/// <param name="countInDest">The number of <typeparamref name="T"/> elements to copy.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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 where T : struct
{ {
int byteCount = SizeOf<T>(countInDest); Copy(source, destination, source.Length);
if (byteCount > (int)ByteCountThreshold)
{
Marshal.Copy(source.Array, source.Start, destination.PointerAtOffset, byteCount);
}
else
{
Unsafe.CopyBlock((void*)destination.PointerAtOffset, (void*)source.PointerAtOffset, (uint)byteCount);
}
} }
/// <summary> /// <summary>
@ -91,39 +79,5 @@ namespace ImageSharp
public static uint USizeOf<T>(int count) public static uint USizeOf<T>(int count)
where T : struct where T : struct
=> (uint)SizeOf<T>(count); => (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> /// <summary>
/// Represents a contiguous region of a pinned managed array. /// 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> /// </summary>
/// <remarks> /// <remarks>
/// <see cref="BufferSpan{T}"/> is very similar to corefx System.Span&lt;T&gt;, and we try to maintain a compatible API. /// <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. /// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array and an start.
/// </summary> /// </summary>
/// <param name="array">The pinned array</param> /// <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="start">The index at which to begin the span.</param>
/// <param name="length">The length</param> /// <param name="length">The length</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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(start, array.Length, nameof(start));
DebugGuard.MustBeLessThanOrEqualTo(length, array.Length - start, nameof(length)); DebugGuard.MustBeLessThanOrEqualTo(length, array.Length - start, nameof(length));
@ -44,45 +43,40 @@ namespace ImageSharp
this.Array = array; this.Array = array;
this.Length = length; this.Length = length;
this.Start = start; this.Start = start;
this.PointerAtOffset = (IntPtr)pointerToArray + (Unsafe.SizeOf<T>() * start);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array and an start. /// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array and an start.
/// </summary> /// </summary>
/// <param name="array">The pinned array</param> /// <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="start">The index at which to begin the span.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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)); DebugGuard.MustBeLessThanOrEqualTo(start, array.Length, nameof(start));
this.Array = array; this.Array = array;
this.Length = array.Length - start; this.Length = array.Length - start;
this.Start = start; this.Start = start;
this.PointerAtOffset = (IntPtr)pointerToArray + (Unsafe.SizeOf<T>() * start);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array. /// Initializes a new instance of the <see cref="BufferSpan{T}"/> struct from a pinned array.
/// </summary> /// </summary>
/// <param name="array">The pinned array</param> /// <param name="array">The pinned array</param>
/// <param name="pointerToArray">Pointer to the start of 'array'</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferSpan(T[] array, void* pointerToArray) public BufferSpan(T[] array)
{ {
GuardArrayAndPointer(array, pointerToArray); GuardArray(array);
this.Array = array; this.Array = array;
this.Start = 0; this.Start = 0;
this.Length = array.Length; this.Length = array.Length;
this.PointerAtOffset = (IntPtr)pointerToArray;
} }
/// <summary> /// <summary>
/// Gets the backing array /// Gets the backing array.
/// </summary> /// </summary>
public T[] Array { get; private set; } public T[] Array { get; private set; }
@ -101,11 +95,6 @@ namespace ImageSharp
/// </summary> /// </summary>
public int ByteOffset => this.Start * Unsafe.SizeOf<T>(); 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> /// <summary>
/// Returns a reference to specified element of the span. /// Returns a reference to specified element of the span.
/// </summary> /// </summary>
@ -117,45 +106,36 @@ namespace ImageSharp
get get
{ {
DebugGuard.MustBeLessThan(index, this.Length, nameof(index)); DebugGuard.MustBeLessThan(index, this.Length, nameof(index));
ref T startRef = ref this.DangerousGetPinnableReference();
byte* ptr = (byte*)this.PointerAtOffset + BufferSpan.SizeOf<T>(index); return ref Unsafe.Add(ref startRef, index);
return ref Unsafe.AsRef<T>(ptr);
} }
} }
/// <summary> /// <summary>
/// Convertes <see cref="BufferSpan{T}"/> instance to a raw 'void*' pointer /// Converts generic <see cref="BufferSpan{T}"/> to a <see cref="BufferSpan{T}"/> of bytes
/// </summary> /// setting it's <see cref="Start"/> and <see cref="Length"/> to correct values.
/// <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
/// </summary> /// </summary>
/// <param name="bufferSpan">The <see cref="BufferSpan{T}"/> to convert</param> /// <returns>The span of bytes</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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> /// <summary>
/// Converts generic <see cref="BufferSpan{T}"/> to a <see cref="BufferSpan{T}"/> of bytes /// 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
/// setting it's <see cref="Start"/> and <see cref="PointerAtOffset"/> to correct values. /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
/// </summary> /// </summary>
/// <param name="source">The <see cref="BufferSpan{T}"/> to convert</param> /// <returns>The reference to the 0th element</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator BufferSpan<byte>(BufferSpan<T> source) public ref T DangerousGetPinnableReference()
{ {
BufferSpan<byte> result = default(BufferSpan<byte>); ref T origin = ref this.Array[0];
result.Array = Unsafe.As<byte[]>(source.Array); return ref Unsafe.Add(ref origin, this.Start);
result.Start = source.Start * Unsafe.SizeOf<T>();
result.PointerAtOffset = source.PointerAtOffset;
return result;
} }
/// <summary> /// <summary>
@ -171,7 +151,6 @@ namespace ImageSharp
BufferSpan<T> result = default(BufferSpan<T>); BufferSpan<T> result = default(BufferSpan<T>);
result.Array = this.Array; result.Array = this.Array;
result.Start = this.Start + start; result.Start = this.Start + start;
result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf<T>() * start);
result.Length = this.Length - start; result.Length = this.Length - start;
return result; return result;
} }
@ -191,7 +170,6 @@ namespace ImageSharp
BufferSpan<T> result = default(BufferSpan<T>); BufferSpan<T> result = default(BufferSpan<T>);
result.Array = this.Array; result.Array = this.Array;
result.Start = this.Start + start; result.Start = this.Start + start;
result.PointerAtOffset = this.PointerAtOffset + (Unsafe.SizeOf<T>() * start);
result.Length = length; result.Length = length;
return result; return result;
} }
@ -205,14 +183,8 @@ namespace ImageSharp
{ {
DebugGuard.MustBeLessThanOrEqualTo(count, this.Length, nameof(count)); DebugGuard.MustBeLessThanOrEqualTo(count, this.Length, nameof(count));
if (count < 256) // TODO: Use Unsafe.InitBlock(ref T) for small arrays, when it get's official
{ System.Array.Clear(this.Array, this.Start, count);
Unsafe.InitBlock((void*)this.PointerAtOffset, 0, BufferSpan.USizeOf<T>(count));
}
else
{
System.Array.Clear(this.Array, this.Start, count);
}
} }
/// <summary> /// <summary>
@ -225,13 +197,9 @@ namespace ImageSharp
} }
[Conditional("DEBUG")] [Conditional("DEBUG")]
private static void GuardArrayAndPointer(T[] array, void* pointerToArray) private static void GuardArray(T[] array)
{ {
DebugGuard.NotNull(array, nameof(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. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
@ -10,7 +10,7 @@ namespace ImageSharp
/// interpreted as a 2D region of <see cref="Width"/> x <see cref="Height"/> elements. /// interpreted as a 2D region of <see cref="Width"/> x <see cref="Height"/> elements.
/// </summary> /// </summary>
/// <typeparam name="T">The value type.</typeparam> /// <typeparam name="T">The value type.</typeparam>
internal interface IPinnedImageBuffer<T> internal interface IBuffer2D<T>
where T : struct where T : struct
{ {
/// <summary> /// <summary>

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

@ -307,7 +307,8 @@ namespace ImageSharp.Formats
rgbBytes.Reset(); rgbBytes.Reset();
pixels.CopyRGBBytesStretchedTo(rgbBytes, y, x); 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++) for (int j = 0; j < 8; j++)
{ {
@ -315,9 +316,9 @@ namespace ImageSharp.Formats
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
{ {
// Convert returned bytes into the YCbCr color space. Assume RGBA // Convert returned bytes into the YCbCr color space. Assume RGBA
int r = data[0]; int r = Unsafe.Add(ref data0, dataIdx);
int g = data[1]; int g = Unsafe.Add(ref data0, dataIdx + 1);
int b = data[2]; int b = Unsafe.Add(ref data0, dataIdx + 2);
// Speed up the algorithm by removing floating point calculation // 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 // 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; cbBlockRaw[index] = cb;
crBlockRaw[index] = cr; 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;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <summary> /// <summary>
/// Jpeg specific utilities and extension methods /// Jpeg specific utilities and extension methods
@ -33,19 +34,6 @@ namespace ImageSharp.Formats.Jpg
StretchPixels(dest, stretchFromX, stretchFromY); 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) // Nothing to stretch if (fromX, fromY) is outside the area, or is at (0,0)
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsInvalidStretchStartingPosition<TColor>(PixelArea<TColor> area, int fromX, int fromY) 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++) 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++) for (int x = fromX; x < area.Width; x++)
{ {
byte* prevPtr = ptrBase + ((x - 1) * 3); // Copy the left neighbour pixel to the current one
byte* currPtr = ptrBase + (x * 3); Unsafe.Add(ref ptrBase, x) = Unsafe.Add(ref ptrBase, x - 1);
CopyRgb(prevPtr, currPtr);
} }
} }
for (int y = fromY; y < area.Height; y++) for (int y = fromY; y < area.Height; y++)
{ {
byte* currBase = (byte*)area.DataPointer + (y * area.RowStride); ref RGB24 currBase = ref GetRowStart(area, y);
byte* prevBase = (byte*)area.DataPointer + ((y - 1) * area.RowStride); ref RGB24 prevBase = ref GetRowStart(area, y - 1);
for (int x = 0; x < area.Width; x++) for (int x = 0; x < area.Width; x++)
{ {
int x3 = 3 * x; // Copy the top neighbour pixel to the current one
byte* currPtr = currBase + x3; Unsafe.Add(ref currBase, x) = Unsafe.Add(ref prevBase, x);
byte* prevPtr = prevBase + x3;
CopyRgb(prevPtr, currPtr);
} }
} }
} }
[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. /// Provides per-pixel access to generic <see cref="Image{TColor}"/> pixels.
/// </summary> /// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam> /// <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> where TColor : struct, IPixel<TColor>
{ {
/// <summary>
/// The position of the first pixel in the image.
/// </summary>
private byte* pixelsBase;
/// <summary> /// <summary>
/// A value indicating whether this instance of the given entity has been disposed. /// A value indicating whether this instance of the given entity has been disposed.
/// </summary> /// </summary>
@ -35,9 +30,9 @@ namespace ImageSharp
private bool isDisposed; private bool isDisposed;
/// <summary> /// <summary>
/// The <see cref="PinnedBuffer{T}"/> containing the pixel data. /// The <see cref="Buffer{T}"/> containing the pixel data.
/// </summary> /// </summary>
private PinnedImageBuffer<TColor> pixelBuffer; private Buffer2D<TColor> pixelBuffer;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PixelAccessor{TColor}"/> class. /// 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="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="height">The height of the image represented by the pixel buffer.</param>
public PixelAccessor(int width, int height) 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="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="height">The height of the image represented by the pixel buffer.</param>
/// <param name="pixels">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.NotNull(pixels, nameof(pixels));
Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(width, 0, nameof(width));
@ -93,11 +88,6 @@ namespace ImageSharp
/// </summary> /// </summary>
public TColor[] PixelArray => this.pixelBuffer.Array; public TColor[] PixelArray => this.pixelBuffer.Array;
/// <summary>
/// Gets the pointer to the pixel buffer.
/// </summary>
public IntPtr DataPointer => this.pixelBuffer.Pointer;
/// <summary> /// <summary>
/// Gets the size of a single pixel in the number of bytes. /// Gets the size of a single pixel in the number of bytes.
/// </summary> /// </summary>
@ -124,7 +114,7 @@ namespace ImageSharp
public ParallelOptions ParallelOptions { get; } public ParallelOptions ParallelOptions { get; }
/// <inheritdoc /> /// <inheritdoc />
BufferSpan<TColor> IPinnedImageBuffer<TColor>.Span => this.pixelBuffer; BufferSpan<TColor> IBuffer2D<TColor>.Span => this.pixelBuffer;
private static BulkPixelOperations<TColor> Operations => BulkPixelOperations<TColor>.Instance; private static BulkPixelOperations<TColor> Operations => BulkPixelOperations<TColor>.Instance;
@ -139,15 +129,13 @@ namespace ImageSharp
get get
{ {
this.CheckCoordinates(x, y); this.CheckCoordinates(x, y);
return this.PixelArray[(y * this.Width) + x];
return Unsafe.Read<TColor>(this.pixelsBase + (((y * this.Width) + x) * Unsafe.SizeOf<TColor>()));
} }
set set
{ {
this.CheckCoordinates(x, y); this.CheckCoordinates(x, y);
this.PixelArray[(y * this.Width) + x] = value;
Unsafe.Write(this.pixelsBase + (((y * this.Width) + x) * Unsafe.SizeOf<TColor>()), value);
} }
} }
@ -179,7 +167,7 @@ namespace ImageSharp
/// </summary> /// </summary>
public void Reset() public void Reset()
{ {
Unsafe.InitBlock(this.pixelsBase, 0, (uint)(this.RowStride * this.Height)); this.pixelBuffer.Clear();
} }
/// <summary> /// <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> /// <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) internal TColor[] ReturnCurrentPixelsAndReplaceThemInternally(int width, int height, TColor[] pixels)
{ {
TColor[] oldPixels = this.pixelBuffer.UnPinAndTakeArrayOwnership(); TColor[] oldPixels = this.pixelBuffer.TakeArrayOwnership();
this.SetPixelBufferUnsafe(width, height, pixels); this.SetPixelBufferUnsafe(width, height, pixels);
return oldPixels; return oldPixels;
} }
@ -262,9 +250,7 @@ namespace ImageSharp
/// <param name="target">The target pixel buffer accessor.</param> /// <param name="target">The target pixel buffer accessor.</param>
internal void CopyTo(PixelAccessor<TColor> target) internal void CopyTo(PixelAccessor<TColor> target)
{ {
uint byteCount = (uint)(this.Width * this.Height * Unsafe.SizeOf<TColor>()); BufferSpan.Copy(this.pixelBuffer.Span, target.pixelBuffer.Span);
Unsafe.CopyBlock(target.pixelsBase, this.pixelsBase, byteCount);
} }
/// <summary> /// <summary>
@ -424,7 +410,7 @@ namespace ImageSharp
private void SetPixelBufferUnsafe(int width, int height, TColor[] pixels) 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> /// <summary>
@ -433,10 +419,9 @@ namespace ImageSharp
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
/// <param name="pixels">The pixel buffer</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.pixelBuffer = pixels;
this.pixelsBase = (byte*)pixels.Pointer;
this.Width = width; this.Width = width;
this.Height = height; 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. /// Represents an area of generic <see cref="Image{TColor}"/> pixels.
/// </summary> /// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam> /// <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> where TColor : struct, IPixel<TColor>
{ {
/// <summary> /// <summary>
@ -30,7 +30,7 @@ namespace ImageSharp
/// <summary> /// <summary>
/// The underlying buffer containing the raw pixel data. /// The underlying buffer containing the raw pixel data.
/// </summary> /// </summary>
private PinnedBuffer<byte> byteBuffer; private Buffer<byte> byteBuffer;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PixelArea{TColor}"/> class. /// Initializes a new instance of the <see cref="PixelArea{TColor}"/> class.
@ -66,8 +66,7 @@ namespace ImageSharp
this.RowStride = width * GetComponentCount(componentOrder); this.RowStride = width * GetComponentCount(componentOrder);
this.Length = bytes.Length; // TODO: Is this the right value for Length? this.Length = bytes.Length; // TODO: Is this the right value for Length?
this.byteBuffer = new PinnedBuffer<byte>(bytes); this.byteBuffer = new Buffer<byte>(bytes);
this.PixelBase = (byte*)this.byteBuffer.Pointer;
} }
/// <summary> /// <summary>
@ -117,8 +116,7 @@ namespace ImageSharp
this.RowStride = (width * GetComponentCount(componentOrder)) + padding; this.RowStride = (width * GetComponentCount(componentOrder)) + padding;
this.Length = this.RowStride * height; this.Length = this.RowStride * height;
this.byteBuffer = new PinnedBuffer<byte>(this.Length); this.byteBuffer = new Buffer<byte>(this.Length);
this.PixelBase = (byte*)this.byteBuffer.Pointer;
} }
/// <summary> /// <summary>
@ -136,21 +134,11 @@ namespace ImageSharp
/// </summary> /// </summary>
public ComponentOrder ComponentOrder { get; } public ComponentOrder ComponentOrder { get; }
/// <summary>
/// Gets the pointer to the pixel buffer.
/// </summary>
public IntPtr DataPointer => this.byteBuffer.Pointer;
/// <summary> /// <summary>
/// Gets the height. /// Gets the height.
/// </summary> /// </summary>
public int Height { get; } public int Height { get; }
/// <summary>
/// Gets the data pointer.
/// </summary>
public byte* PixelBase { get; private set; }
/// <summary> /// <summary>
/// Gets the width of one row in the number of bytes. /// Gets the width of one row in the number of bytes.
/// </summary> /// </summary>
@ -198,7 +186,7 @@ namespace ImageSharp
/// </summary> /// </summary>
public void Reset() public void Reset()
{ {
Unsafe.InitBlock(this.PixelBase, 0, (uint)(this.RowStride * this.Height)); this.byteBuffer.Clear();
} }
/// <summary> /// <summary>

2
src/ImageSharp/ImageSharp.csproj

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

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

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

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

@ -41,7 +41,7 @@ namespace ImageSharp.Processing.Processors
/// <summary> /// <summary>
/// Gets an unsafe float* pointer to the beginning of <see cref="Span"/>. /// Gets an unsafe float* pointer to the beginning of <see cref="Span"/>.
/// </summary> /// </summary>
public float* Ptr => (float*)this.Span.PointerAtOffset; public ref float Ptr => ref this.Span.DangerousGetPinnableReference();
/// <summary> /// <summary>
/// Gets the lenghth of the weights window /// Gets the lenghth of the weights window
@ -56,19 +56,18 @@ namespace ImageSharp.Processing.Processors
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ComputeWeightedRowSum(BufferSpan<Vector4> rowSpan) public Vector4 ComputeWeightedRowSum(BufferSpan<Vector4> rowSpan)
{ {
float* horizontalValues = this.Ptr; ref float horizontalValues = ref this.Ptr;
int left = this.Left; int left = this.Left;
Vector4* vecPtr = (Vector4*)rowSpan.PointerAtOffset; ref Vector4 vecPtr = ref Unsafe.Add(ref rowSpan.DangerousGetPinnableReference(), left);
vecPtr += left;
// Destination color components // Destination color components
Vector4 result = Vector4.Zero; Vector4 result = Vector4.Zero;
for (int i = 0; i < this.Length; i++) for (int i = 0; i < this.Length; i++)
{ {
float weight = horizontalValues[i]; float weight = Unsafe.Add(ref horizontalValues, i);
result += (*vecPtr) * weight; Vector4 v = Unsafe.Add(ref vecPtr, i);
vecPtr++; result += v * weight;
} }
return result; return result;
@ -83,19 +82,18 @@ namespace ImageSharp.Processing.Processors
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ComputeExpandedWeightedRowSum(BufferSpan<Vector4> rowSpan) public Vector4 ComputeExpandedWeightedRowSum(BufferSpan<Vector4> rowSpan)
{ {
float* horizontalValues = this.Ptr; ref float horizontalValues = ref this.Ptr;
int left = this.Left; int left = this.Left;
Vector4* vecPtr = (Vector4*)rowSpan.PointerAtOffset; ref Vector4 vecPtr = ref Unsafe.Add(ref rowSpan.DangerousGetPinnableReference(), left);
vecPtr += left;
// Destination color components // Destination color components
Vector4 result = Vector4.Zero; Vector4 result = Vector4.Zero;
for (int i = 0; i < this.Length; i++) for (int i = 0; i < this.Length; i++)
{ {
float weight = horizontalValues[i]; float weight = Unsafe.Add(ref horizontalValues, i);
result += (*vecPtr).Expand() * weight; Vector4 v = Unsafe.Add(ref vecPtr, i);
vecPtr++; result += v.Expand() * weight;
} }
return result; return result;
@ -109,9 +107,9 @@ namespace ImageSharp.Processing.Processors
/// <param name="x">The column position</param> /// <param name="x">The column position</param>
/// <returns>The weighted sum</returns> /// <returns>The weighted sum</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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; int left = this.Left;
// Destination color components // Destination color components
@ -119,7 +117,7 @@ namespace ImageSharp.Processing.Processors
for (int i = 0; i < this.Length; i++) for (int i = 0; i < this.Length; i++)
{ {
float yw = verticalValues[i]; float yw = Unsafe.Add(ref verticalValues, i);
int index = left + i; int index = left + i;
result += firstPassPixels[x, index] * yw; result += firstPassPixels[x, index] * yw;
} }
@ -133,7 +131,7 @@ namespace ImageSharp.Processing.Processors
/// </summary> /// </summary>
internal class WeightsBuffer : IDisposable internal class WeightsBuffer : IDisposable
{ {
private PinnedImageBuffer<float> dataBuffer; private Buffer2D<float> dataBuffer;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="WeightsBuffer"/> class. /// 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> /// <param name="destinationSize">The size of the destination window</param>
public WeightsBuffer(int sourceSize, int destinationSize) 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]; 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;
using System.Buffers; using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
/// <summary> /// <summary>
@ -111,13 +112,15 @@ namespace ImageSharp.Processing.Processors
WeightsWindow ws = result.GetWeightsWindow(i, left, right); WeightsWindow ws = result.GetWeightsWindow(i, left, right);
result.Weights[i] = ws; result.Weights[i] = ws;
float* weights = ws.Ptr; ref float weights = ref ws.Ptr;
for (int j = left; j <= right; j++) for (int j = left; j <= right; j++)
{ {
float weight = sampler.GetValue((j - center) / scale); float weight = sampler.GetValue((j - center) / scale);
sum += weight; 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. // 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++) 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> targetPixels = new PixelAccessor<TColor>(width, height))
{ {
using (PixelAccessor<TColor> sourcePixels = source.Lock()) 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(); firstPassPixels.Clear();
@ -117,7 +117,7 @@ namespace ImageSharp.Processing.Processors
y => y =>
{ {
// TODO: Without Parallel.For() this buffer object could be reused: // 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); 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. // Collect the palette. Required before the second pass runs.
colorPalette = this.GetPalette(); 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); 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)); Guard.NotNull(image, nameof(image));
this.colors = maxColors.Clamp(1, 256); this.colors = maxColors.Clamp(1, 255);
try try
{ {

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

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

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

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

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

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

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

@ -13,9 +13,9 @@ namespace ImageSharp.Benchmarks.Color.Bulk
public abstract class ToXyzw<TColor> public abstract class ToXyzw<TColor>
where TColor : struct, IPixel<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)] [Params(16, 128, 1024)]
public int Count { get; set; } public int Count { get; set; }
@ -23,8 +23,8 @@ namespace ImageSharp.Benchmarks.Color.Bulk
[Setup] [Setup]
public void Setup() public void Setup()
{ {
this.source = new PinnedBuffer<TColor>(this.Count); this.source = new Buffer<TColor>(this.Count);
this.destination = new PinnedBuffer<byte>(this.Count * 4); this.destination = new Buffer<byte>(this.Count * 4);
} }
[Cleanup] [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 System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
[Config(typeof(Config.Short))] [Config(typeof(Config.Short))]
public class ArrayCopy public class ArrayCopy
{ {
@ -58,8 +58,7 @@ namespace ImageSharp.Benchmarks.General
Buffer.MemoryCopy(pinnedSource, pinnedDestination, this.Count, this.Count); Buffer.MemoryCopy(pinnedSource, pinnedDestination, this.Count, this.Count);
} }
} }
[Benchmark(Description = "Copy using Marshal.Copy<T>")] [Benchmark(Description = "Copy using Marshal.Copy<T>")]
public unsafe void CopyUsingMarshalCopy() public unsafe void CopyUsingMarshalCopy()
{ {
@ -68,5 +67,37 @@ namespace ImageSharp.Benchmarks.General
Marshal.Copy(this.source, 0, (IntPtr)pinnedDestination, this.Count); 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 public unsafe class ClearBuffer
{ {
private PinnedBuffer<Color> buffer; private Buffer<Color> buffer;
[Params(32, 128, 512)] [Params(32, 128, 512)]
public int Count { get; set; } public int Count { get; set; }
[Setup] [Setup]
public void Setup() public void Setup()
{ {
this.buffer = new PinnedBuffer<ImageSharp.Color>(this.Count); this.buffer = new Buffer<ImageSharp.Color>(this.Count);
} }
[Cleanup] [Cleanup]
@ -37,7 +37,7 @@ namespace ImageSharp.Benchmarks.General
[Benchmark] [Benchmark]
public void Unsafe_InitBlock() 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 public class IterateArray
{ {
// Usual pinned stuff // Usual pinned stuff
private PinnedBuffer<Vector4> buffer; private Buffer<Vector4> buffer;
// An array that's not pinned by intent! // An array that's not pinned by intent!
private Vector4[] array; private Vector4[] array;
@ -19,7 +19,8 @@ namespace ImageSharp.Benchmarks.General
[Setup] [Setup]
public void 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]; this.array = new Vector4[this.Length];
} }
@ -41,7 +42,7 @@ namespace ImageSharp.Benchmarks.General
{ {
Vector4 sum = new Vector4(); Vector4 sum = new Vector4();
Vector4* ptr = (Vector4*) this.buffer.Pointer; Vector4* ptr = (Vector4*) this.buffer.Pin();
Vector4* end = ptr + this.Length; Vector4* end = ptr + this.Length;
for (; ptr < end; ptr++) 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 BenchmarkDotNet.Attributes;
using CoreSize = ImageSharp.Size; using CoreSize = ImageSharp.Size;
using CoreImage = ImageSharp.Image; using CoreImage = ImageSharp.Image;
using CoreVectorImage = ImageSharp.Image<ImageSharp.ColorVector>;
public class Resize : BenchmarkBase 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")] [Benchmark(Description = "ImageSharp Compand Resize")]
public CoreSize ResizeCoreCompand() public CoreSize ResizeCoreCompand()
{ {
@ -53,5 +64,15 @@ namespace ImageSharp.Benchmarks
return new CoreSize(image.Width, image.Height); 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;
using System.Runtime.DesignerServices; using System.Runtime.DesignerServices;
using ImageSharp.Tests; using ImageSharp.Tests;
using ImageSharp.Tests.Colors; using ImageSharp.Tests.Colors;
@ -53,10 +53,10 @@ namespace ImageSharp.Sandbox46
private static void RunToVector4ProfilingTest() private static void RunToVector4ProfilingTest()
{ {
BulkPixelOperationsTests.Color tests = new BulkPixelOperationsTests.Color(new ConsoleOutput()); BulkPixelOperationsTests.Color32 tests = new BulkPixelOperationsTests.Color32(new ConsoleOutput());
tests.Benchmark_ToVector4(); tests.Benchmark_ToVector4();
} }
private static void RunDecodeJpegProfilingTests() private static void RunDecodeJpegProfilingTests()
{ {
Console.WriteLine("RunDecodeJpegProfilingTests..."); Console.WriteLine("RunDecodeJpegProfilingTests...");

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

@ -10,22 +10,22 @@ namespace ImageSharp.Tests.Colors
public class BulkPixelOperationsTests 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) : base(output)
{ {
} }
// For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class: // 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] [Fact]
public void IsSpecialImplementation() public void IsSpecialImplementation()
{ {
Assert.IsType<ImageSharp.Color.BulkOperations>(BulkPixelOperations<ImageSharp.Color>.Instance); Assert.IsType<ImageSharp.Color.BulkOperations>(BulkPixelOperations<ImageSharp.Color>.Instance);
} }
[Fact] [Fact]
public void ToVector4SimdAligned() public void ToVector4SimdAligned()
{ {
@ -36,7 +36,7 @@ namespace ImageSharp.Tests.Colors
source, source,
expected, expected,
(s, d) => ImageSharp.Color.BulkOperations.ToVector4SimdAligned(s, d, 64) (s, d) => ImageSharp.Color.BulkOperations.ToVector4SimdAligned(s, d, 64)
); );
} }
// [Fact] // Profiling benchmark - enable manually! // [Fact] // Profiling benchmark - enable manually!
@ -45,8 +45,8 @@ namespace ImageSharp.Tests.Colors
int times = 200000; int times = 200000;
int count = 1024; int count = 1024;
using (PinnedBuffer<ImageSharp.Color> source = new PinnedBuffer<ImageSharp.Color>(count)) using (Buffer<ImageSharp.Color> source = new Buffer<ImageSharp.Color>(count))
using (PinnedBuffer<Vector4> dest = new PinnedBuffer<Vector4>(count)) using (Buffer<Vector4> dest = new Buffer<Vector4>(count))
{ {
this.Measure( this.Measure(
times, 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: // For 4.6 test runner MemberData does not work without redeclaring the public field in the derived test class:
public Argb(ITestOutputHelper output) 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] [Theory]
[WithBlankImages(1, 1, PixelTypes.All)] [WithBlankImages(1, 1, PixelTypes.All)]
public void GetGlobalInstance<TColor>(TestImageProvider<TColor> dummy) public void GetGlobalInstance<TColor>(TestImageProvider<TColor> dummy)
where TColor:struct, IPixel<TColor> where TColor : struct, IPixel<TColor>
{ {
Assert.NotNull(BulkPixelOperations<TColor>.Instance); Assert.NotNull(BulkPixelOperations<TColor>.Instance);
} }
@ -112,7 +112,7 @@ namespace ImageSharp.Tests.Colors
source, source,
expected, expected,
(s, d) => Operations.PackFromVector4(s, d, count) (s, d) => Operations.PackFromVector4(s, d, count)
); );
} }
internal static Vector4[] CreateExpectedVector4Data(TColor[] source) internal static Vector4[] CreateExpectedVector4Data(TColor[] source)
@ -137,7 +137,7 @@ namespace ImageSharp.Tests.Colors
source, source,
expected, expected,
(s, d) => Operations.ToVector4(s, d, count) (s, d) => Operations.ToVector4(s, d, count)
); );
} }
@ -156,10 +156,10 @@ namespace ImageSharp.Tests.Colors
} }
TestOperation( TestOperation(
source, source,
expected, expected,
(s, d) => Operations.PackFromXyzBytes(s, d, count) (s, d) => Operations.PackFromXyzBytes(s, d, count)
); );
} }
[Theory] [Theory]
@ -179,7 +179,7 @@ namespace ImageSharp.Tests.Colors
source, source,
expected, expected,
(s, d) => Operations.ToXyzBytes(s, d, count) (s, d) => Operations.ToXyzBytes(s, d, count)
); );
} }
[Theory] [Theory]
@ -200,7 +200,7 @@ namespace ImageSharp.Tests.Colors
source, source,
expected, expected,
(s, d) => Operations.PackFromXyzwBytes(s, d, count) (s, d) => Operations.PackFromXyzwBytes(s, d, count)
); );
} }
[Theory] [Theory]
@ -220,7 +220,7 @@ namespace ImageSharp.Tests.Colors
source, source,
expected, expected,
(s, d) => Operations.ToXyzwBytes(s, d, count) (s, d) => Operations.ToXyzwBytes(s, d, count)
); );
} }
[Theory] [Theory]
@ -241,7 +241,7 @@ namespace ImageSharp.Tests.Colors
source, source,
expected, expected,
(s, d) => Operations.PackFromZyxBytes(s, d, count) (s, d) => Operations.PackFromZyxBytes(s, d, count)
); );
} }
[Theory] [Theory]
@ -261,7 +261,7 @@ namespace ImageSharp.Tests.Colors
source, source,
expected, expected,
(s, d) => Operations.ToZyxBytes(s, d, count) (s, d) => Operations.ToZyxBytes(s, d, count)
); );
} }
[Theory] [Theory]
@ -282,7 +282,7 @@ namespace ImageSharp.Tests.Colors
source, source,
expected, expected,
(s, d) => Operations.PackFromZyxwBytes(s, d, count) (s, d) => Operations.PackFromZyxwBytes(s, d, count)
); );
} }
[Theory] [Theory]
@ -302,26 +302,26 @@ namespace ImageSharp.Tests.Colors
source, source,
expected, expected,
(s, d) => Operations.ToZyxwBytes(s, d, count) (s, d) => Operations.ToZyxwBytes(s, d, count)
); );
} }
private class TestBuffers<TSource, TDest> : IDisposable private class TestBuffers<TSource, TDest> : IDisposable
where TSource : struct where TSource : struct
where TDest : struct where TDest : struct
{ {
public PinnedBuffer<TSource> SourceBuffer { get; } public Buffer<TSource> SourceBuffer { get; }
public PinnedBuffer<TDest> ActualDestBuffer { get; } public Buffer<TDest> ActualDestBuffer { get; }
public PinnedBuffer<TDest> ExpectedDestBuffer { get; } public Buffer<TDest> ExpectedDestBuffer { get; }
public BufferSpan<TSource> Source => this.SourceBuffer; public BufferSpan<TSource> Source => this.SourceBuffer;
public BufferSpan<TDest> ActualDest => this.ActualDestBuffer; public BufferSpan<TDest> ActualDest => this.ActualDestBuffer;
public TestBuffers(TSource[] source, TDest[] expectedDest) public TestBuffers(TSource[] source, TDest[] expectedDest)
{ {
this.SourceBuffer = new PinnedBuffer<TSource>(source); this.SourceBuffer = new Buffer<TSource>(source);
this.ExpectedDestBuffer = new PinnedBuffer<TDest>(expectedDest); this.ExpectedDestBuffer = new Buffer<TDest>(expectedDest);
this.ActualDestBuffer = new PinnedBuffer<TDest>(expectedDest.Length); this.ActualDestBuffer = new Buffer<TDest>(expectedDest.Length);
} }
public void Dispose() 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 // 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 }; 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 Bgra4444(vector4), vector4Components };
yield return new object[] { new Bgra5551(vector4), vector4Components }; yield return new object[] { new Bgra5551(vector4), vector4Components };
yield return new object[] { new Byte4(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 // 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 }; 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 }; 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 // 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 }; 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 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 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 }; 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 // 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 }; 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 }; 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 TheoryData<object, object, Type>()
{ {
{ new Alpha8(.5F), new Alpha8(.5F), typeof(Alpha8) }, { 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 Bgr565(Vector3.One), new Bgr565(Vector3.One), typeof(Bgr565) },
{ new Bgra4444(Vector4.One), new Bgra4444(Vector4.One), typeof(Bgra4444) }, { new Bgra4444(Vector4.One), new Bgra4444(Vector4.One), typeof(Bgra4444) },
{ new Bgra5551(Vector4.One), new Bgra5551(Vector4.One), typeof(Bgra5551) }, { 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 NormalizedShort4(Vector4.One), new NormalizedShort4(Vector4.One), typeof(NormalizedShort4) },
{ new Rg32(Vector2.One), new Rg32(Vector2.One), typeof(Rg32) }, { new Rg32(Vector2.One), new Rg32(Vector2.One), typeof(Rg32) },
{ new Rgba1010102(Vector4.One), new Rgba1010102(Vector4.One), typeof(Rgba1010102) }, { 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 Rgba64(Vector4.One), new Rgba64(Vector4.One), typeof(Rgba64) },
{ new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.One * 0x7FFF), typeof(Short2) }, { new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.One * 0x7FFF), typeof(Short2) },
{ new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.One * 0x7FFF), typeof(Short4) }, { new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.One * 0x7FFF), typeof(Short4) },
@ -42,7 +43,7 @@ namespace ImageSharp.Tests.Colors
{ {
// Valid object against null // Valid object against null
{ new Alpha8(.5F), null, typeof(Alpha8) }, { 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 Bgr565(Vector3.One), null, typeof(Bgr565) },
{ new Bgra4444(Vector4.One), null, typeof(Bgra4444) }, { new Bgra4444(Vector4.One), null, typeof(Bgra4444) },
{ new Bgra5551(Vector4.One), null, typeof(Bgra5551) }, { new Bgra5551(Vector4.One), null, typeof(Bgra5551) },
@ -65,7 +66,7 @@ namespace ImageSharp.Tests.Colors
new TheoryData<object, object, Type>() new TheoryData<object, object, Type>()
{ {
// Valid objects of different types but not equal // 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 HalfSingle(-1F), new NormalizedShort2(Vector2.Zero), null },
{ new Rgba1010102(Vector4.One), new Bgra5551(Vector4.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 // Valid objects of the same type but not equal
{ new Alpha8(.5F), new Alpha8(.8F), typeof(Alpha8) }, { 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 Bgr565(Vector3.One), new Bgr565(Vector3.Zero), typeof(Bgr565) },
{ new Bgra4444(Vector4.One), new Bgra4444(Vector4.Zero), typeof(Bgra4444) }, { new Bgra4444(Vector4.One), new Bgra4444(Vector4.Zero), typeof(Bgra4444) },
{ new Bgra5551(Vector4.One), new Bgra5551(Vector4.Zero), typeof(Bgra5551) }, { 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 NormalizedShort4(Vector4.One), new NormalizedShort4(Vector4.Zero), typeof(NormalizedShort4) },
{ new Rg32(Vector2.One), new Rg32(Vector2.Zero), typeof(Rg32) }, { new Rg32(Vector2.One), new Rg32(Vector2.Zero), typeof(Rg32) },
{ new Rgba1010102(Vector4.One), new Rgba1010102(Vector4.Zero), typeof(Rgba1010102) }, { 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 Rgba64(Vector4.One), new Rgba64(Vector4.Zero), typeof(Rgba64) },
{ new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.Zero), typeof(Short2) }, { new Short2(Vector2.One * 0x7FFF), new Short2(Vector2.Zero), typeof(Short2) },
{ new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.Zero), typeof(Short4) }, { new Short4(Vector4.One * 0x7FFF), new Short4(Vector4.Zero), typeof(Short4) },
@ -211,5 +213,41 @@ namespace ImageSharp.Tests.Colors
// Assert // Assert
Assert.True(notEqual); 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 }; 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 Bgra4444(), vector4Components };
yield return new object[] { new Bgra5551(), vector4Components }; yield return new object[] { new Bgra5551(), vector4Components };
yield return new object[] { new Byte4(), 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 }; 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 }; 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(2, colorBase[1]);
Assert.Equal(3, colorBase[2]); Assert.Equal(3, colorBase[2]);
Assert.Equal(4, colorBase[3]); 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] [Fact]
public void Argb() public void Argb32()
{ {
// Test the limits. // Test the limits.
Assert.Equal((uint)0x0, new Argb(Vector4.Zero).PackedValue); Assert.Equal((uint)0x0, new Argb32(Vector4.Zero).PackedValue);
Assert.Equal(0xFFFFFFFF, new Argb(Vector4.One).PackedValue); Assert.Equal(0xFFFFFFFF, new Argb32(Vector4.One).PackedValue);
// Test ToVector4. // Test ToVector4.
Assert.True(Equal(Vector4.One, new Argb(Vector4.One).ToVector4())); Assert.True(Equal(Vector4.One, new Argb32(Vector4.One).ToVector4()));
Assert.True(Equal(Vector4.Zero, new Argb(Vector4.Zero).ToVector4())); Assert.True(Equal(Vector4.Zero, new Argb32(Vector4.Zero).ToVector4()));
Assert.True(Equal(Vector4.UnitX, new Argb(Vector4.UnitX).ToVector4())); Assert.True(Equal(Vector4.UnitX, new Argb32(Vector4.UnitX).ToVector4()));
Assert.True(Equal(Vector4.UnitY, new Argb(Vector4.UnitY).ToVector4())); Assert.True(Equal(Vector4.UnitY, new Argb32(Vector4.UnitY).ToVector4()));
Assert.True(Equal(Vector4.UnitZ, new Argb(Vector4.UnitZ).ToVector4())); Assert.True(Equal(Vector4.UnitZ, new Argb32(Vector4.UnitZ).ToVector4()));
Assert.True(Equal(Vector4.UnitW, new Argb(Vector4.UnitW).ToVector4())); Assert.True(Equal(Vector4.UnitW, new Argb32(Vector4.UnitW).ToVector4()));
// Test clamping. // Test clamping.
Assert.True(Equal(Vector4.Zero, 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 Argb(Vector4.One * +1234.0f).ToVector4())); Assert.True(Equal(Vector4.One, new Argb32(Vector4.One * +1234.0f).ToVector4()));
float x = +0.1f; float x = +0.1f;
float y = -0.3f; float y = -0.3f;
float z = +0.5f; float z = +0.5f;
float w = -0.7f; 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); Assert.Equal(0x001a0080u, argb.PackedValue);
// Test ordering // Test ordering
@ -711,6 +711,51 @@ namespace ImageSharp.Tests.Colors
Assert.Equal(rgba, new byte[] { 25, 0, 128, 0 }); 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] [Fact]
public void Rgba64() 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 // ReSharper disable InconsistentNaming
namespace ImageSharp.Tests.Common namespace ImageSharp.Tests.Common
{ {
using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Xunit; using Xunit;
using static TestStructs; 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] [Theory]
[InlineData(7, 42)] [InlineData(7, 42)]
[InlineData(1025, 17)] [InlineData(1025, 17)]
public void Construct(int width, int height) 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(width, buffer.Width);
Assert.Equal(height, buffer.Height); Assert.Equal(height, buffer.Height);
@ -28,7 +42,7 @@ namespace ImageSharp.Tests.Common
public void Construct_FromExternalArray(int width, int height) public void Construct_FromExternalArray(int width, int height)
{ {
Foo[] array = new Foo[width * height + 10]; 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(width, buffer.Width);
Assert.Equal(height, buffer.Height); Assert.Equal(height, buffer.Height);
@ -42,7 +56,7 @@ namespace ImageSharp.Tests.Common
{ {
for (int i = 0; i < 100; i++) 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++) for (int j = 0; j < buffer.Length; j++)
{ {
@ -59,13 +73,13 @@ namespace ImageSharp.Tests.Common
[InlineData(17, 42, 41)] [InlineData(17, 42, 41)]
public void GetRowSpanY(int width, int height, int y) 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); BufferSpan<Foo> span = buffer.GetRowSpan(y);
Assert.Equal(width * y, span.Start); Assert.Equal(width * y, span.Start);
Assert.Equal(width, span.Length); 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)] [InlineData(17, 42, 0, 41)]
public void GetRowSpanXY(int width, int height, int x, int y) 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); BufferSpan<Foo> span = buffer.GetRowSpan(x, y);
Assert.Equal(width * y + x, span.Start); Assert.Equal(width * y + x, span.Start);
Assert.Equal(width - x, span.Length); 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)] [InlineData(99, 88, 98, 87)]
public void Indexer(int width, int height, int x, int y) 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; Foo[] array = buffer.Array;

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

@ -1,5 +1,6 @@
// ReSharper disable ObjectCreationAsStatement // ReSharper disable ObjectCreationAsStatement
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace ImageSharp.Tests.Common namespace ImageSharp.Tests.Common
{ {
using System; using System;
@ -11,18 +12,30 @@ namespace ImageSharp.Tests.Common
public unsafe class BufferSpanTests 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] [Fact]
public void AsBytes() public void AsBytes()
{ {
Foo[] fooz = { new Foo(1, 2), new Foo(3, 4), new Foo(5, 6) }; 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<Foo> orig = colorBuf.Slice(1);
BufferSpan<byte> asBytes = (BufferSpan < byte > )orig; BufferSpan<byte> asBytes = orig.AsBytes();
Assert.Equal(asBytes.Start, sizeof(Foo)); 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() public void Basic()
{ {
Foo[] array = Foo.CreateArray(3); Foo[] array = Foo.CreateArray(3);
fixed (Foo* p = array)
{
// Act:
BufferSpan<Foo> span = new BufferSpan<Foo>(array, p);
// Assert: // Act:
Assert.Equal(array, span.Array); BufferSpan<Foo> span = new BufferSpan<Foo>(array);
Assert.Equal((IntPtr)p, span.PointerAtOffset);
Assert.Equal(3, span.Length); // Assert:
} Assert.Equal(array, span.Array);
Assert.Equal(3, span.Length);
Assert.SameRefs(ref array[0], ref span.DangerousGetPinnableReference());
} }
[Fact] [Fact]
@ -49,17 +60,15 @@ namespace ImageSharp.Tests.Common
{ {
Foo[] array = Foo.CreateArray(4); Foo[] array = Foo.CreateArray(4);
int start = 2; int start = 2;
fixed (Foo* p = array)
{ // Act:
// Act: BufferSpan<Foo> span = new BufferSpan<Foo>(array, start);
BufferSpan<Foo> span = new BufferSpan<Foo>(array, p, start);
// Assert:
// Assert: Assert.Equal(array, span.Array);
Assert.Equal(array, span.Array); Assert.Equal(start, span.Start);
Assert.Equal(start, span.Start); Assert.SameRefs(ref array[start], ref span.DangerousGetPinnableReference());
Assert.Equal((IntPtr)(p + start), span.PointerAtOffset); Assert.Equal(array.Length - start, span.Length);
Assert.Equal(array.Length - start, span.Length);
}
} }
[Fact] [Fact]
@ -68,17 +77,14 @@ namespace ImageSharp.Tests.Common
Foo[] array = Foo.CreateArray(10); Foo[] array = Foo.CreateArray(10);
int start = 2; int start = 2;
int length = 3; int length = 3;
fixed (Foo* p = array) // Act:
{ BufferSpan<Foo> span = new BufferSpan<Foo>(array, start, length);
// Act:
BufferSpan<Foo> span = new BufferSpan<Foo>(array, p, start, length); // Assert:
Assert.Equal(array, span.Array);
// Assert: Assert.Equal(start, span.Start);
Assert.Equal(array, span.Array); Assert.SameRefs(ref array[start], ref span.DangerousGetPinnableReference());
Assert.Equal(start, span.Start); Assert.Equal(length, span.Length);
Assert.Equal((IntPtr)(p + start), span.PointerAtOffset);
Assert.Equal(length, span.Length);
}
} }
} }
@ -92,19 +98,16 @@ namespace ImageSharp.Tests.Common
int start1 = 2; int start1 = 2;
int totalOffset = start0 + start1; int totalOffset = start0 + start1;
fixed (Foo* p = array) BufferSpan<Foo> span = new BufferSpan<Foo>(array, start0);
{
BufferSpan<Foo> span = new BufferSpan<Foo>(array, p, start0);
// Act: // Act:
span = span.Slice(start1); span = span.Slice(start1);
// Assert: // Assert:
Assert.Equal(array, span.Array); Assert.Equal(array, span.Array);
Assert.Equal(totalOffset, span.Start); Assert.Equal(totalOffset, span.Start);
Assert.Equal((IntPtr)(p + totalOffset), span.PointerAtOffset); Assert.SameRefs(ref array[totalOffset], ref span.DangerousGetPinnableReference());
Assert.Equal(array.Length - totalOffset, span.Length); Assert.Equal(array.Length - totalOffset, span.Length);
}
} }
[Fact] [Fact]
@ -116,24 +119,19 @@ namespace ImageSharp.Tests.Common
int totalOffset = start0 + start1; int totalOffset = start0 + start1;
int sliceLength = 3; int sliceLength = 3;
fixed (Foo* p = array) BufferSpan<Foo> span = new BufferSpan<Foo>(array, start0);
{
BufferSpan<Foo> span = new BufferSpan<Foo>(array, p, start0);
// Act: // Act:
span = span.Slice(start1, sliceLength); span = span.Slice(start1, sliceLength);
// Assert: // Assert:
Assert.Equal(array, span.Array); Assert.Equal(array, span.Array);
Assert.Equal(totalOffset, span.Start); Assert.Equal(totalOffset, span.Start);
Assert.Equal((IntPtr)(p + totalOffset), span.PointerAtOffset); Assert.SameRefs(ref array[totalOffset], ref span.DangerousGetPinnableReference());
Assert.Equal(sliceLength, span.Length); Assert.Equal(sliceLength, span.Length);
}
} }
} }
[Theory] [Theory]
[InlineData(4)] [InlineData(4)]
[InlineData(1500)] [InlineData(1500)]
@ -142,21 +140,17 @@ namespace ImageSharp.Tests.Common
Foo[] array = Foo.CreateArray(count + 42); Foo[] array = Foo.CreateArray(count + 42);
int offset = 2; int offset = 2;
fixed (Foo* p = array) BufferSpan<Foo> ap = new BufferSpan<Foo>(array, offset);
{
BufferSpan<Foo> ap = new BufferSpan<Foo>(array, p, offset);
// Act: // Act:
ap.Clear(count); ap.Clear(count);
Assert.NotEqual(default(Foo), array[offset-1]); Assert.NotEqual(default(Foo), array[offset - 1]);
Assert.Equal(default(Foo), array[offset]); Assert.Equal(default(Foo), array[offset]);
Assert.Equal(default(Foo), array[offset + count-1]); Assert.Equal(default(Foo), array[offset + count - 1]);
Assert.NotEqual(default(Foo), array[offset + count]); Assert.NotEqual(default(Foo), array[offset + count]);
}
} }
public class Indexer public class Indexer
{ {
public static readonly TheoryData<int, int, int> IndexerData = 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) public void Read(int length, int start, int index)
{ {
Foo[] a = Foo.CreateArray(length); Foo[] a = Foo.CreateArray(length);
fixed (Foo* p = a) BufferSpan<Foo> span = new BufferSpan<Foo>(a, start);
{
BufferSpan<Foo> span = new BufferSpan<Foo>(a, p, start);
Foo element = span[index]; Foo element = span[index];
Assert.Equal(a[start + index], element); Assert.Equal(a[start + index], element);
}
} }
[Theory] [Theory]
@ -190,17 +181,46 @@ namespace ImageSharp.Tests.Common
public void Write(int length, int start, int index) public void Write(int length, int start, int index)
{ {
Foo[] a = Foo.CreateArray(length); Foo[] a = Foo.CreateArray(length);
fixed (Foo* p = a) BufferSpan<Foo> span = new BufferSpan<Foo>(a, start);
{
BufferSpan<Foo> span = new BufferSpan<Foo>(a, p, 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 public class Copy
{ {
@ -238,14 +258,10 @@ namespace ImageSharp.Tests.Common
Foo[] source = Foo.CreateArray(count + 2); Foo[] source = Foo.CreateArray(count + 2);
Foo[] dest = new Foo[count + 5]; Foo[] dest = new Foo[count + 5];
fixed (Foo* pSource = source) BufferSpan<Foo> apSource = new BufferSpan<Foo>(source, 1);
fixed (Foo* pDest = dest) BufferSpan<Foo> apDest = new BufferSpan<Foo>(dest, 1);
{
BufferSpan<Foo> apSource = new BufferSpan<Foo>(source, pSource, 1);
BufferSpan<Foo> apDest = new BufferSpan<Foo>(dest, pDest, 1);
BufferSpan.Copy(apSource, apDest, count-1); BufferSpan.Copy(apSource, apDest, count - 1);
}
AssertNotDefault(source, 1); AssertNotDefault(source, 1);
AssertNotDefault(dest, 1); AssertNotDefault(dest, 1);
@ -253,7 +269,7 @@ namespace ImageSharp.Tests.Common
Assert.NotEqual(source[0], dest[0]); Assert.NotEqual(source[0], dest[0]);
Assert.Equal(source[1], dest[1]); Assert.Equal(source[1], dest[1]);
Assert.Equal(source[2], dest[2]); 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]); Assert.NotEqual(source[count], dest[count]);
} }
@ -265,14 +281,10 @@ namespace ImageSharp.Tests.Common
AlignedFoo[] source = AlignedFoo.CreateArray(count + 2); AlignedFoo[] source = AlignedFoo.CreateArray(count + 2);
AlignedFoo[] dest = new AlignedFoo[count + 5]; AlignedFoo[] dest = new AlignedFoo[count + 5];
fixed (AlignedFoo* pSource = source) BufferSpan<AlignedFoo> apSource = new BufferSpan<AlignedFoo>(source, 1);
fixed (AlignedFoo* pDest = dest) BufferSpan<AlignedFoo> apDest = new BufferSpan<AlignedFoo>(dest, 1);
{
BufferSpan<AlignedFoo> apSource = new BufferSpan<AlignedFoo>(source, pSource, 1);
BufferSpan<AlignedFoo> apDest = new BufferSpan<AlignedFoo>(dest, pDest, 1);
BufferSpan.Copy(apSource, apDest, count - 1); BufferSpan.Copy(apSource, apDest, count - 1);
}
AssertNotDefault(source, 1); AssertNotDefault(source, 1);
AssertNotDefault(dest, 1); AssertNotDefault(dest, 1);
@ -289,17 +301,13 @@ namespace ImageSharp.Tests.Common
[InlineData(1500)] [InlineData(1500)]
public void IntToInt(int count) public void IntToInt(int count)
{ {
int[] source = CreateTestInts(count+2); int[] source = CreateTestInts(count + 2);
int[] dest = new int[count + 5]; int[] dest = new int[count + 5];
fixed (int* pSource = source) BufferSpan<int> apSource = new BufferSpan<int>(source, 1);
fixed (int* pDest = dest) BufferSpan<int> apDest = new BufferSpan<int>(dest, 1);
{
BufferSpan<int> apSource = new BufferSpan<int>(source, pSource, 1);
BufferSpan<int> apDest = new BufferSpan<int>(dest, pDest, 1);
BufferSpan.Copy(apSource, apDest, count -1); BufferSpan.Copy(apSource, apDest, count - 1);
}
AssertNotDefault(source, 1); AssertNotDefault(source, 1);
AssertNotDefault(dest, 1); AssertNotDefault(dest, 1);
@ -317,17 +325,13 @@ namespace ImageSharp.Tests.Common
public void GenericToBytes(int count) public void GenericToBytes(int count)
{ {
int destCount = count * sizeof(Foo); int destCount = count * sizeof(Foo);
Foo[] source = Foo.CreateArray(count+2); Foo[] source = Foo.CreateArray(count + 2);
byte[] dest = new byte[destCount + sizeof(Foo)*2]; byte[] dest = new byte[destCount + sizeof(Foo) * 2];
fixed (Foo* pSource = source) BufferSpan<Foo> apSource = new BufferSpan<Foo>(source, 1);
fixed (byte* pDest = dest) BufferSpan<byte> apDest = new BufferSpan<byte>(dest, sizeof(Foo));
{
BufferSpan<Foo> apSource = new BufferSpan<Foo>(source, pSource, 1);
BufferSpan<byte> apDest = new BufferSpan<byte>(dest, pDest, sizeof(Foo));
BufferSpan.Copy(apSource, apDest, count - 1); BufferSpan.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(Foo));
}
AssertNotDefault(source, 1); AssertNotDefault(source, 1);
@ -347,14 +351,10 @@ namespace ImageSharp.Tests.Common
AlignedFoo[] source = AlignedFoo.CreateArray(count + 2); AlignedFoo[] source = AlignedFoo.CreateArray(count + 2);
byte[] dest = new byte[destCount + sizeof(AlignedFoo) * 2]; byte[] dest = new byte[destCount + sizeof(AlignedFoo) * 2];
fixed (AlignedFoo* pSource = source) BufferSpan<AlignedFoo> apSource = new BufferSpan<AlignedFoo>(source, 1);
fixed (byte* pDest = dest) BufferSpan<byte> apDest = new BufferSpan<byte>(dest, sizeof(AlignedFoo));
{
BufferSpan<AlignedFoo> apSource = new BufferSpan<AlignedFoo>(source, pSource, 1);
BufferSpan<byte> apDest = new BufferSpan<byte>(dest, pDest, sizeof(AlignedFoo));
BufferSpan.Copy(apSource, apDest, count - 1); BufferSpan.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(AlignedFoo));
}
AssertNotDefault(source, 1); AssertNotDefault(source, 1);
@ -371,17 +371,13 @@ namespace ImageSharp.Tests.Common
public void IntToBytes(int count) public void IntToBytes(int count)
{ {
int destCount = count * sizeof(int); int destCount = count * sizeof(int);
int[] source = CreateTestInts(count+2); int[] source = CreateTestInts(count + 2);
byte[] dest = new byte[destCount + sizeof(int) + 1]; byte[] dest = new byte[destCount + sizeof(int) + 1];
fixed (int* pSource = source) BufferSpan<int> apSource = new BufferSpan<int>(source);
fixed (byte* pDest = dest) BufferSpan<byte> apDest = new BufferSpan<byte>(dest);
{
BufferSpan<int> apSource = new BufferSpan<int>(source, pSource);
BufferSpan<byte> apDest = new BufferSpan<byte>(dest, pDest);
BufferSpan.Copy(apSource, apDest, count); BufferSpan.Copy(apSource.AsBytes(), apDest, count * sizeof(int));
}
AssertNotDefault(source, 1); AssertNotDefault(source, 1);
@ -398,15 +394,11 @@ namespace ImageSharp.Tests.Common
int srcCount = count * sizeof(Foo); int srcCount = count * sizeof(Foo);
byte[] source = CreateTestBytes(srcCount); byte[] source = CreateTestBytes(srcCount);
Foo[] dest = new Foo[count + 2]; 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(source, sizeof(Foo) + 1);
AssertNotDefault(dest, 1); AssertNotDefault(dest, 1);
@ -418,14 +410,14 @@ namespace ImageSharp.Tests.Common
} }
[Fact] [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), }; 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 (Buffer<Color> colorBuf = new Buffer<Color>(colors))
using (PinnedBuffer<byte> byteBuf = new PinnedBuffer<byte>(colors.Length*4)) 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; byte[] a = byteBuf.Array;
@ -436,7 +428,6 @@ namespace ImageSharp.Tests.Common
} }
} }
internal static bool ElementsAreEqual(Foo[] array, byte[] rawArray, int index) internal static bool ElementsAreEqual(Foo[] array, byte[] rawArray, int index)
{ {
fixed (Foo* pArray = array) 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;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -9,21 +10,37 @@
using static TestStructs; 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] [Theory]
[InlineData(42)] [InlineData(42)]
[InlineData(1111)] [InlineData(1111)]
public void ConstructWithOwnArray(int count) 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.False(buffer.IsDisposedOrLostArrayOwnership);
Assert.NotNull(buffer.Array); Assert.NotNull(buffer.Array);
Assert.Equal(count, buffer.Length); Assert.Equal(count, buffer.Length);
Assert.True(buffer.Array.Length >= count); Assert.True(buffer.Array.Length >= count);
VerifyPointer(buffer);
} }
} }
@ -33,13 +50,11 @@
public void ConstructWithExistingArray(int count) public void ConstructWithExistingArray(int count)
{ {
Foo[] array = new Foo[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.False(buffer.IsDisposedOrLostArrayOwnership);
Assert.Equal(array, buffer.Array); Assert.Equal(array, buffer.Array);
Assert.Equal(count, buffer.Length); Assert.Equal(count, buffer.Length);
VerifyPointer(buffer);
} }
} }
@ -49,7 +64,7 @@
public void Clear(int count) public void Clear(int count)
{ {
Foo[] a = { new Foo() { A = 1, B = 2 }, new Foo() { A = 3, B = 4 } }; 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(); buffer.Clear();
@ -63,7 +78,7 @@
{ {
for (int i = 0; i < 100; i++) 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++) for (int j = 0; j < buffer.Length; j++)
{ {
@ -90,7 +105,7 @@
{ {
Foo[] a = Foo.CreateArray(length); 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]; Foo element = buffer[index];
@ -104,7 +119,7 @@
{ {
Foo[] a = Foo.CreateArray(length); 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); buffer[index] = new Foo(666, 666);
@ -116,24 +131,24 @@
[Fact] [Fact]
public void Dispose() public void Dispose()
{ {
PinnedBuffer<Foo> buffer = new PinnedBuffer<Foo>(42); Buffer<Foo> buffer = new Buffer<Foo>(42);
buffer.Dispose(); buffer.Dispose();
Assert.True(buffer.IsDisposedOrLostArrayOwnership); Assert.True(buffer.IsDisposedOrLostArrayOwnership);
} }
[Theory] [Theory]
[InlineData(7)] [InlineData(7)]
[InlineData(123)] [InlineData(123)]
public void CastToSpan(int bufferLength) 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; BufferSpan<Foo> span = buffer;
Assert.Equal(buffer.Array, span.Array); Assert.Equal(buffer.Array, span.Array);
Assert.Equal(0, span.Start); Assert.Equal(0, span.Start);
Assert.Equal(buffer.Pointer, span.PointerAtOffset); Assert.SpanPointsTo(span, buffer);
Assert.Equal(span.Length, bufferLength); Assert.Equal(span.Length, bufferLength);
} }
} }
@ -141,13 +156,13 @@
[Fact] [Fact]
public void Span() public void Span()
{ {
using (PinnedBuffer<Foo> buffer = new PinnedBuffer<Foo>(42)) using (Buffer<Foo> buffer = new Buffer<Foo>(42))
{ {
BufferSpan<Foo> span = buffer.Span; BufferSpan<Foo> span = buffer.Span;
Assert.Equal(buffer.Array, span.Array); Assert.Equal(buffer.Array, span.Array);
Assert.Equal(0, span.Start); Assert.Equal(0, span.Start);
Assert.Equal(buffer.Pointer, span.PointerAtOffset); Assert.SpanPointsTo(span, buffer);
Assert.Equal(span.Length, 42); Assert.Equal(span.Length, 42);
} }
} }
@ -160,13 +175,13 @@
[InlineData(123, 17)] [InlineData(123, 17)]
public void WithStartOnly(int bufferLength, int start) 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); BufferSpan<Foo> span = buffer.Slice(start);
Assert.Equal(buffer.Array, span.Array); Assert.Equal(buffer.Array, span.Array);
Assert.Equal(start, span.Start); 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); Assert.Equal(span.Length, bufferLength - start);
} }
} }
@ -176,13 +191,13 @@
[InlineData(123, 17, 42)] [InlineData(123, 17, 42)]
public void WithStartAndLength(int bufferLength, int start, int spanLength) 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); BufferSpan<Foo> span = buffer.Slice(start, spanLength);
Assert.Equal(buffer.Array, span.Array); Assert.Equal(buffer.Array, span.Array);
Assert.Equal(start, span.Start); 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); Assert.Equal(span.Length, spanLength);
} }
} }
@ -192,9 +207,9 @@
public void UnPinAndTakeArrayOwnership() public void UnPinAndTakeArrayOwnership()
{ {
Foo[] data = null; 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); Assert.True(buffer.IsDisposedOrLostArrayOwnership);
} }
@ -202,10 +217,41 @@
Assert.True(data.Length >= 42); Assert.True(data.Length >= 42);
} }
private static void VerifyPointer(PinnedBuffer<Foo> buffer) public class Pin
{ {
IntPtr ptr = (IntPtr)Unsafe.AsPointer(ref buffer.Array[0]); [Fact]
Assert.Equal(ptr, buffer.Pointer); 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; 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)); GlyphBuilder fullBuilder = new GlyphBuilder(new System.Numerics.Vector2(10, 99));
IGlyphRenderer builder = fullBuilder; IGlyphRenderer builder = fullBuilder;
builder.BeginGlyph(); builder.BeginGlyph(Vector2.Zero);
builder.BeginFigure(); builder.BeginFigure();
builder.MoveTo(new Vector2(0, 0)); builder.MoveTo(new Vector2(0, 0));
builder.LineTo(new Vector2(0, 10)); // becomes 0, -10 builder.LineTo(new Vector2(0, 10)); // becomes 0, -10
@ -52,7 +52,7 @@ namespace ImageSharp.Tests.Drawing.Text
IGlyphRenderer builder = fullBuilder; IGlyphRenderer builder = fullBuilder;
for (int i = 0; i < 10; i++) for (int i = 0; i < 10; i++)
{ {
builder.BeginGlyph(); builder.BeginGlyph(Vector2.Zero);
builder.BeginFigure(); builder.BeginFigure();
builder.MoveTo(new Vector2(0, 0)); builder.MoveTo(new Vector2(0, 0));
builder.LineTo(new Vector2(0, 10)); // becomes 0, -10 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; public static string[] ProgressiveTestJpegs = TestImages.Jpeg.Progressive.All;
[Theory] [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) public void OpenBaselineJpeg_SaveBmp<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPixel<TColor> where TColor : struct, IPixel<TColor>
{ {
@ -36,7 +36,7 @@ namespace ImageSharp.Tests
} }
[Theory] [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) public void OpenProgressiveJpeg_SaveBmp<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPixel<TColor> where TColor : struct, IPixel<TColor>
{ {

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

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

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

@ -39,7 +39,7 @@ namespace ImageSharp.Tests
} }
[Theory] [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) public void CopyStretchedRGBTo_FromOrigo<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPixel<TColor> where TColor : struct, IPixel<TColor>
{ {
@ -61,7 +61,7 @@ namespace ImageSharp.Tests
} }
[Theory] [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) public void CopyStretchedRGBTo_WithOffset<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPixel<TColor> 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 BlackWhiteChecker(pixels); // top left
VirticalBars(pixels); // top right VirticalBars(pixels); // top right
TransparentGradients(pixels); // bottom left TransparentGradients(pixels); // bottom left
Rainbow(pixels); // bottom right Rainbow(pixels); // bottom right
} }
} }
/// <summary> /// <summary>
@ -70,7 +70,7 @@ namespace ImageSharp.Tests
/// <param name="pixels"></param> /// <param name="pixels"></param>
private static void VirticalBars(PixelAccessor<TColor> pixels) private static void VirticalBars(PixelAccessor<TColor> pixels)
{ {
// topLeft // topLeft
int left = pixels.Width / 2; int left = pixels.Width / 2;
int right = pixels.Width; int right = pixels.Width;
int top = 0; int top = 0;
@ -101,7 +101,7 @@ namespace ImageSharp.Tests
/// <param name="pixels"></param> /// <param name="pixels"></param>
private static void BlackWhiteChecker(PixelAccessor<TColor> pixels) private static void BlackWhiteChecker(PixelAccessor<TColor> pixels)
{ {
// topLeft // topLeft
int left = 0; int left = 0;
int right = pixels.Width / 2; int right = pixels.Width / 2;
int top = 0; int top = 0;
@ -140,7 +140,7 @@ namespace ImageSharp.Tests
/// <param name="pixels"></param> /// <param name="pixels"></param>
private static void TransparentGradients(PixelAccessor<TColor> pixels) private static void TransparentGradients(PixelAccessor<TColor> pixels)
{ {
// topLeft // topLeft
int left = 0; int left = 0;
int right = pixels.Width / 2; int right = pixels.Width / 2;
int top = pixels.Height / 2; int top = pixels.Height / 2;

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

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

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

@ -20,7 +20,7 @@ namespace ImageSharp.Tests
private ITestOutputHelper Output { get; } private ITestOutputHelper Output { get; }
[Theory] [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) public void Use_WithEmptyImageAttribute<TColor>(TestImageProvider<TColor> provider, string message)
where TColor : struct, IPixel<TColor> where TColor : struct, IPixel<TColor>
{ {
@ -86,7 +86,7 @@ namespace ImageSharp.Tests
public static string[] AllBmpFiles => TestImages.Bmp.All; public static string[] AllBmpFiles => TestImages.Bmp.All;
[Theory] [Theory]
[WithFileCollection(nameof(AllBmpFiles), PixelTypes.Color | PixelTypes.Argb)] [WithFileCollection(nameof(AllBmpFiles), PixelTypes.Color | PixelTypes.Argb32)]
public void Use_WithFileCollection<TColor>(TestImageProvider<TColor> provider) public void Use_WithFileCollection<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPixel<TColor> where TColor : struct, IPixel<TColor>
{ {
@ -96,7 +96,7 @@ namespace ImageSharp.Tests
} }
[Theory] [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) public void Use_WithSolidFilledImagesAttribute<TColor>(TestImageProvider<TColor> provider)
where TColor : struct, IPixel<TColor> where TColor : struct, IPixel<TColor>
{ {

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

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

Loading…
Cancel
Save