diff --git a/.editorconfig b/.editorconfig
index 2e3045fb17..c28089d720 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -172,6 +172,8 @@ dotnet_diagnostic.IDE0063.severity = suggestion
csharp_using_directive_placement = outside_namespace:warning
# Modifier preferences
csharp_prefer_static_local_function = true:warning
+# Primary constructor preferences
+csharp_style_prefer_primary_constructors = false:none
##########################################
# Unnecessary Code Rules
diff --git a/.gitattributes b/.gitattributes
index 3647a7063d..b5f742ab47 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -133,3 +133,6 @@
*.pnm filter=lfs diff=lfs merge=lfs -text
*.wbmp filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text
+*.ico filter=lfs diff=lfs merge=lfs -text
+*.cur filter=lfs diff=lfs merge=lfs -text
+*.ani filter=lfs diff=lfs merge=lfs -text
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index b375574018..a450aebf43 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -4,6 +4,7 @@ on:
push:
branches:
- main
+ - release/*
tags:
- "v*"
pull_request:
@@ -19,42 +20,23 @@ jobs:
- ${{ contains(github.event.pull_request.labels.*.name, 'arch:arm32') || contains(github.event.pull_request.labels.*.name, 'arch:arm64') }}
options:
- os: ubuntu-latest
- framework: net7.0
- sdk: 7.0.x
- sdk-preview: true
+ framework: net8.0
+ sdk: 8.0.x
runtime: -x64
codecov: false
- - os: macos-latest
- framework: net7.0
- sdk: 7.0.x
- sdk-preview: true
+ - os: macos-13 # macos-latest runs on arm64 runners where libgdiplus is unavailable
+ framework: net8.0
+ sdk: 8.0.x
runtime: -x64
codecov: false
- os: windows-latest
- framework: net7.0
- sdk: 7.0.x
- sdk-preview: true
+ framework: net8.0
+ sdk: 8.0.x
runtime: -x64
codecov: false
- os: buildjet-4vcpu-ubuntu-2204-arm
- framework: net7.0
- sdk: 7.0.x
- sdk-preview: true
- runtime: -x64
- codecov: false
- - os: ubuntu-latest
- framework: net6.0
- sdk: 6.0.x
- runtime: -x64
- codecov: false
- - os: macos-latest
- framework: net6.0
- sdk: 6.0.x
- runtime: -x64
- codecov: false
- - os: windows-latest
- framework: net6.0
- sdk: 6.0.x
+ framework: net8.0
+ sdk: 8.0.x
runtime: -x64
codecov: false
exclude:
@@ -86,7 +68,7 @@ jobs:
run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
- name: Git Setup LFS Cache
- uses: actions/cache@v3
+ uses: actions/cache@v4
id: lfs-cache
with:
path: .git/lfs
@@ -96,10 +78,10 @@ jobs:
run: git lfs pull
- name: NuGet Install
- uses: NuGet/setup-nuget@v1
+ uses: NuGet/setup-nuget@v2
- name: NuGet Setup Cache
- uses: actions/cache@v3
+ uses: actions/cache@v4
id: nuget-cache
with:
path: ~/.nuget
@@ -108,17 +90,17 @@ jobs:
- name: DotNet Setup
if: ${{ matrix.options.sdk-preview != true }}
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: |
- 6.0.x
+ 8.0.x
- name: DotNet Setup Preview
if: ${{ matrix.options.sdk-preview == true }}
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: |
- 7.0.x
+ 8.0.x
- name: DotNet Build
if: ${{ matrix.options.sdk-preview != true }}
@@ -151,7 +133,7 @@ jobs:
XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
- name: Export Failed Output
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: failure()
with:
name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip
@@ -178,10 +160,10 @@ jobs:
submodules: recursive
- name: NuGet Install
- uses: NuGet/setup-nuget@v1
+ uses: NuGet/setup-nuget@v2
- name: NuGet Setup Cache
- uses: actions/cache@v3
+ uses: actions/cache@v4
id: nuget-cache
with:
path: ~/.nuget
diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml
index e551afbd6d..cd22fe5e58 100644
--- a/.github/workflows/code-coverage.yml
+++ b/.github/workflows/code-coverage.yml
@@ -10,7 +10,7 @@ jobs:
matrix:
options:
- os: ubuntu-latest
- framework: net6.0
+ framework: net8.0
runtime: -x64
codecov: true
@@ -34,7 +34,7 @@ jobs:
run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id
- name: Git Setup LFS Cache
- uses: actions/cache@v3
+ uses: actions/cache@v4
id: lfs-cache
with:
path: .git/lfs
@@ -44,10 +44,10 @@ jobs:
run: git lfs pull
- name: NuGet Install
- uses: NuGet/setup-nuget@v1
+ uses: NuGet/setup-nuget@v2
- name: NuGet Setup Cache
- uses: actions/cache@v3
+ uses: actions/cache@v4
id: nuget-cache
with:
path: ~/.nuget
@@ -55,10 +55,10 @@ jobs:
restore-keys: ${{ runner.os }}-nuget-
- name: DotNet Setup
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
dotnet-version: |
- 6.0.x
+ 8.0.x
- name: DotNet Build
shell: pwsh
@@ -74,14 +74,14 @@ jobs:
XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit
- name: Export Failed Output
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
if: failure()
with:
name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip
path: tests/Images/ActualOutput/
- name: Codecov Update
- uses: codecov/codecov-action@v3
+ uses: codecov/codecov-action@v4
if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors')
with:
flags: unittests
diff --git a/ImageSharp.sln b/ImageSharp.sln
index 2967acb8ff..162de84168 100644
--- a/ImageSharp.sln
+++ b/ImageSharp.sln
@@ -38,6 +38,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{815C0625-CD3
src\Directory.Build.props = src\Directory.Build.props
src\Directory.Build.targets = src\Directory.Build.targets
src\README.md = src\README.md
+ src\ImageSharp.ruleset = src\ImageSharp.ruleset
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp", "src\ImageSharp\ImageSharp.csproj", "{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}"
@@ -237,6 +238,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "issues", "issues", "{5C9B68
tests\Images\Input\Jpg\issues\issue750-exif-tranform.jpg = tests\Images\Input\Jpg\issues\issue750-exif-tranform.jpg
tests\Images\Input\Jpg\issues\Issue845-Incorrect-Quality99.jpg = tests\Images\Input\Jpg\issues\Issue845-Incorrect-Quality99.jpg
tests\Images\Input\Jpg\issues\issue855-incorrect-colorspace.jpg = tests\Images\Input\Jpg\issues\issue855-incorrect-colorspace.jpg
+ tests\Images\Input\Jpg\issues\issue-2067-comment.jpg = tests\Images\Input\Jpg\issues\issue-2067-comment.jpg
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fuzz", "fuzz", "{516A3532-6AC2-417B-AD79-9BD5D0D378A0}"
diff --git a/README.md b/README.md
index fa51d57cdf..cf58b6b14b 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ Designed to simplify image processing, ImageSharp brings you an incredibly power
ImageSharp is designed from the ground up to be flexible and extensible. The library provides API endpoints for common image processing operations and the building blocks to allow for the development of additional operations.
-Built against [.NET 6](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios.
+Built against [.NET 8](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios.
## License
@@ -64,7 +64,7 @@ If you prefer, you can compile ImageSharp yourself (please do and help!)
- Using [Visual Studio 2022](https://visualstudio.microsoft.com/vs/)
- Make sure you have the latest version installed
- - Make sure you have [the .NET 7 SDK](https://www.microsoft.com/net/core#windows) installed
+ - Make sure you have [the .NET 8 SDK](https://www.microsoft.com/net/core#windows) installed
Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**:
diff --git a/shared-infrastructure b/shared-infrastructure
index 353b9afe32..1dbfb576c8 160000
--- a/shared-infrastructure
+++ b/shared-infrastructure
@@ -1 +1 @@
-Subproject commit 353b9afe32a8000410312d17263407cd7bb82d19
+Subproject commit 1dbfb576c83507645265c79e03369b66cdc0379f
diff --git a/src/ImageSharp.ruleset b/src/ImageSharp.ruleset
index e88c43f838..b609890200 100644
--- a/src/ImageSharp.ruleset
+++ b/src/ImageSharp.ruleset
@@ -1,7 +1,4 @@
-
-
-
\ No newline at end of file
diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs
index 9629b0097e..a959faa3b6 100644
--- a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs
+++ b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs
@@ -51,7 +51,7 @@ public static partial class ParallelRowIterator
for (int y = yMin; y < yMax; y++)
{
// Skip the safety copy when invoking a potentially impure method on a readonly field
- Unsafe.AsRef(this.action).Invoke(y);
+ Unsafe.AsRef(in this.action).Invoke(y);
}
}
}
@@ -102,7 +102,7 @@ public static partial class ParallelRowIterator
for (int y = yMin; y < yMax; y++)
{
- Unsafe.AsRef(this.action).Invoke(y, span);
+ Unsafe.AsRef(in this.action).Invoke(y, span);
}
}
}
diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.cs b/src/ImageSharp/Advanced/ParallelRowIterator.cs
index 657654a84b..1284a3a898 100644
--- a/src/ImageSharp/Advanced/ParallelRowIterator.cs
+++ b/src/ImageSharp/Advanced/ParallelRowIterator.cs
@@ -58,7 +58,7 @@ public static partial class ParallelRowIterator
{
for (int y = top; y < bottom; y++)
{
- Unsafe.AsRef(operation).Invoke(y);
+ Unsafe.AsRef(in operation).Invoke(y);
}
return;
@@ -118,7 +118,7 @@ public static partial class ParallelRowIterator
int maxSteps = DivideCeil(width * (long)height, parallelSettings.MinimumPixelsProcessedPerTask);
int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
MemoryAllocator allocator = parallelSettings.MemoryAllocator;
- int bufferLength = Unsafe.AsRef(operation).GetRequiredBufferLength(rectangle);
+ int bufferLength = Unsafe.AsRef(in operation).GetRequiredBufferLength(rectangle);
// Avoid TPL overhead in this trivial case:
if (numOfSteps == 1)
@@ -128,7 +128,7 @@ public static partial class ParallelRowIterator
for (int y = top; y < bottom; y++)
{
- Unsafe.AsRef(operation).Invoke(y, span);
+ Unsafe.AsRef(in operation).Invoke(y, span);
}
return;
@@ -245,7 +245,7 @@ public static partial class ParallelRowIterator
int maxSteps = DivideCeil(width * (long)height, parallelSettings.MinimumPixelsProcessedPerTask);
int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
MemoryAllocator allocator = parallelSettings.MemoryAllocator;
- int bufferLength = Unsafe.AsRef(operation).GetRequiredBufferLength(rectangle);
+ int bufferLength = Unsafe.AsRef(in operation).GetRequiredBufferLength(rectangle);
// Avoid TPL overhead in this trivial case:
if (numOfSteps == 1)
@@ -253,7 +253,7 @@ public static partial class ParallelRowIterator
var rows = new RowInterval(top, bottom);
using IMemoryOwner buffer = allocator.Allocate(bufferLength);
- Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span);
+ Unsafe.AsRef(in operation).Invoke(in rows, buffer.Memory.Span);
return;
}
diff --git a/src/ImageSharp/Color/Color.Conversions.cs b/src/ImageSharp/Color/Color.Conversions.cs
deleted file mode 100644
index 309ab83ec4..0000000000
--- a/src/ImageSharp/Color/Color.Conversions.cs
+++ /dev/null
@@ -1,240 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using SixLabors.ImageSharp.PixelFormats;
-
-namespace SixLabors.ImageSharp;
-
-///
-/// Contains constructors and implicit conversion methods.
-///
-public readonly partial struct Color
-{
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The containing the color information.
- [MethodImpl(InliningOptions.ShortMethod)]
- public Color(Rgba64 pixel)
- {
- this.data = pixel;
- this.boxedHighPrecisionPixel = null;
- }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The containing the color information.
- [MethodImpl(InliningOptions.ShortMethod)]
- public Color(Rgb48 pixel)
- {
- this.data = new Rgba64(pixel.R, pixel.G, pixel.B, ushort.MaxValue);
- this.boxedHighPrecisionPixel = null;
- }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The containing the color information.
- [MethodImpl(InliningOptions.ShortMethod)]
- public Color(La32 pixel)
- {
- this.data = new Rgba64(pixel.L, pixel.L, pixel.L, pixel.A);
- this.boxedHighPrecisionPixel = null;
- }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The containing the color information.
- [MethodImpl(InliningOptions.ShortMethod)]
- public Color(L16 pixel)
- {
- this.data = new Rgba64(pixel.PackedValue, pixel.PackedValue, pixel.PackedValue, ushort.MaxValue);
- this.boxedHighPrecisionPixel = null;
- }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The containing the color information.
- [MethodImpl(InliningOptions.ShortMethod)]
- public Color(Rgba32 pixel)
- {
- this.data = new Rgba64(pixel);
- this.boxedHighPrecisionPixel = null;
- }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The containing the color information.
- [MethodImpl(InliningOptions.ShortMethod)]
- public Color(Argb32 pixel)
- {
- this.data = new Rgba64(pixel);
- this.boxedHighPrecisionPixel = null;
- }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The containing the color information.
- [MethodImpl(InliningOptions.ShortMethod)]
- public Color(Bgra32 pixel)
- {
- this.data = new Rgba64(pixel);
- this.boxedHighPrecisionPixel = null;
- }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The containing the color information.
- [MethodImpl(InliningOptions.ShortMethod)]
- public Color(Abgr32 pixel)
- {
- this.data = new Rgba64(pixel);
- this.boxedHighPrecisionPixel = null;
- }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The containing the color information.
- [MethodImpl(InliningOptions.ShortMethod)]
- public Color(Rgb24 pixel)
- {
- this.data = new Rgba64(pixel);
- this.boxedHighPrecisionPixel = null;
- }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The containing the color information.
- [MethodImpl(InliningOptions.ShortMethod)]
- public Color(Bgr24 pixel)
- {
- this.data = new Rgba64(pixel);
- this.boxedHighPrecisionPixel = null;
- }
-
- ///
- /// Initializes a new instance of the struct.
- ///
- /// The containing the color information.
- [MethodImpl(InliningOptions.ShortMethod)]
- public Color(Vector4 vector)
- {
- vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One);
- this.boxedHighPrecisionPixel = new RgbaVector(vector.X, vector.Y, vector.Z, vector.W);
- this.data = default;
- }
-
- ///
- /// Converts a to .
- ///
- /// The .
- /// The .
- public static explicit operator Vector4(Color color) => color.ToScaledVector4();
-
- ///
- /// Converts an to .
- ///
- /// The .
- /// The .
- [MethodImpl(InliningOptions.ShortMethod)]
- public static explicit operator Color(Vector4 source) => new(source);
-
- [MethodImpl(InliningOptions.ShortMethod)]
- internal Rgba32 ToRgba32()
- {
- if (this.boxedHighPrecisionPixel is null)
- {
- return this.data.ToRgba32();
- }
-
- Rgba32 value = default;
- this.boxedHighPrecisionPixel.ToRgba32(ref value);
- return value;
- }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- internal Bgra32 ToBgra32()
- {
- if (this.boxedHighPrecisionPixel is null)
- {
- return this.data.ToBgra32();
- }
-
- Bgra32 value = default;
- value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
- return value;
- }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- internal Argb32 ToArgb32()
- {
- if (this.boxedHighPrecisionPixel is null)
- {
- return this.data.ToArgb32();
- }
-
- Argb32 value = default;
- value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
- return value;
- }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- internal Abgr32 ToAbgr32()
- {
- if (this.boxedHighPrecisionPixel is null)
- {
- return this.data.ToAbgr32();
- }
-
- Abgr32 value = default;
- value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
- return value;
- }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- internal Rgb24 ToRgb24()
- {
- if (this.boxedHighPrecisionPixel is null)
- {
- return this.data.ToRgb24();
- }
-
- Rgb24 value = default;
- value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
- return value;
- }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- internal Bgr24 ToBgr24()
- {
- if (this.boxedHighPrecisionPixel is null)
- {
- return this.data.ToBgr24();
- }
-
- Bgr24 value = default;
- value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
- return value;
- }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- internal Vector4 ToScaledVector4()
- {
- if (this.boxedHighPrecisionPixel is null)
- {
- return this.data.ToScaledVector4();
- }
-
- return this.boxedHighPrecisionPixel.ToScaledVector4();
- }
-}
diff --git a/src/ImageSharp/Color/Color.NamedColors.cs b/src/ImageSharp/Color/Color.NamedColors.cs
index f8b4c90fd6..00130dd904 100644
--- a/src/ImageSharp/Color/Color.NamedColors.cs
+++ b/src/ImageSharp/Color/Color.NamedColors.cs
@@ -1,6 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
+using SixLabors.ImageSharp.PixelFormats;
+
namespace SixLabors.ImageSharp;
///
@@ -9,107 +11,107 @@ namespace SixLabors.ImageSharp;
///
public readonly partial struct Color
{
- private static readonly Lazy> NamedColorsLookupLazy = new Lazy>(CreateNamedColorsLookup, true);
+ private static readonly Lazy> NamedColorsLookupLazy = new(CreateNamedColorsLookup, true);
///
/// Represents a matching the W3C definition that has an hex value of #F0F8FF.
///
- public static readonly Color AliceBlue = FromRgba(240, 248, 255, 255);
+ public static readonly Color AliceBlue = FromPixel(new Rgba32(240, 248, 255, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FAEBD7.
///
- public static readonly Color AntiqueWhite = FromRgba(250, 235, 215, 255);
+ public static readonly Color AntiqueWhite = FromPixel(new Rgba32(250, 235, 215, 255));
///
/// Represents a matching the W3C definition that has an hex value of #00FFFF.
///
- public static readonly Color Aqua = FromRgba(0, 255, 255, 255);
+ public static readonly Color Aqua = FromPixel(new Rgba32(0, 255, 255, 255));
///
/// Represents a matching the W3C definition that has an hex value of #7FFFD4.
///
- public static readonly Color Aquamarine = FromRgba(127, 255, 212, 255);
+ public static readonly Color Aquamarine = FromPixel(new Rgba32(127, 255, 212, 255));
///
/// Represents a matching the W3C definition that has an hex value of #F0FFFF.
///
- public static readonly Color Azure = FromRgba(240, 255, 255, 255);
+ public static readonly Color Azure = FromPixel(new Rgba32(240, 255, 255, 255));
///
/// Represents a matching the W3C definition that has an hex value of #F5F5DC.
///
- public static readonly Color Beige = FromRgba(245, 245, 220, 255);
+ public static readonly Color Beige = FromPixel(new Rgba32(245, 245, 220, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFE4C4.
///
- public static readonly Color Bisque = FromRgba(255, 228, 196, 255);
+ public static readonly Color Bisque = FromPixel(new Rgba32(255, 228, 196, 255));
///
/// Represents a matching the W3C definition that has an hex value of #000000.
///
- public static readonly Color Black = FromRgba(0, 0, 0, 255);
+ public static readonly Color Black = FromPixel(new Rgba32(0, 0, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFEBCD.
///
- public static readonly Color BlanchedAlmond = FromRgba(255, 235, 205, 255);
+ public static readonly Color BlanchedAlmond = FromPixel(new Rgba32(255, 235, 205, 255));
///
/// Represents a matching the W3C definition that has an hex value of #0000FF.
///
- public static readonly Color Blue = FromRgba(0, 0, 255, 255);
+ public static readonly Color Blue = FromPixel(new Rgba32(0, 0, 255, 255));
///
/// Represents a matching the W3C definition that has an hex value of #8A2BE2.
///
- public static readonly Color BlueViolet = FromRgba(138, 43, 226, 255);
+ public static readonly Color BlueViolet = FromPixel(new Rgba32(138, 43, 226, 255));
///
/// Represents a matching the W3C definition that has an hex value of #A52A2A.
///
- public static readonly Color Brown = FromRgba(165, 42, 42, 255);
+ public static readonly Color Brown = FromPixel(new Rgba32(165, 42, 42, 255));
///
/// Represents a matching the W3C definition that has an hex value of #DEB887.
///
- public static readonly Color BurlyWood = FromRgba(222, 184, 135, 255);
+ public static readonly Color BurlyWood = FromPixel(new Rgba32(222, 184, 135, 255));
///
/// Represents a matching the W3C definition that has an hex value of #5F9EA0.
///
- public static readonly Color CadetBlue = FromRgba(95, 158, 160, 255);
+ public static readonly Color CadetBlue = FromPixel(new Rgba32(95, 158, 160, 255));
///
/// Represents a matching the W3C definition that has an hex value of #7FFF00.
///
- public static readonly Color Chartreuse = FromRgba(127, 255, 0, 255);
+ public static readonly Color Chartreuse = FromPixel(new Rgba32(127, 255, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #D2691E.
///
- public static readonly Color Chocolate = FromRgba(210, 105, 30, 255);
+ public static readonly Color Chocolate = FromPixel(new Rgba32(210, 105, 30, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FF7F50.
///
- public static readonly Color Coral = FromRgba(255, 127, 80, 255);
+ public static readonly Color Coral = FromPixel(new Rgba32(255, 127, 80, 255));
///
/// Represents a matching the W3C definition that has an hex value of #6495ED.
///
- public static readonly Color CornflowerBlue = FromRgba(100, 149, 237, 255);
+ public static readonly Color CornflowerBlue = FromPixel(new Rgba32(100, 149, 237, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFF8DC.
///
- public static readonly Color Cornsilk = FromRgba(255, 248, 220, 255);
+ public static readonly Color Cornsilk = FromPixel(new Rgba32(255, 248, 220, 255));
///
/// Represents a matching the W3C definition that has an hex value of #DC143C.
///
- public static readonly Color Crimson = FromRgba(220, 20, 60, 255);
+ public static readonly Color Crimson = FromPixel(new Rgba32(220, 20, 60, 255));
///
/// Represents a matching the W3C definition that has an hex value of #00FFFF.
@@ -119,27 +121,27 @@ public readonly partial struct Color
///
/// Represents a matching the W3C definition that has an hex value of #00008B.
///
- public static readonly Color DarkBlue = FromRgba(0, 0, 139, 255);
+ public static readonly Color DarkBlue = FromPixel(new Rgba32(0, 0, 139, 255));
///
/// Represents a matching the W3C definition that has an hex value of #008B8B.
///
- public static readonly Color DarkCyan = FromRgba(0, 139, 139, 255);
+ public static readonly Color DarkCyan = FromPixel(new Rgba32(0, 139, 139, 255));
///
/// Represents a matching the W3C definition that has an hex value of #B8860B.
///
- public static readonly Color DarkGoldenrod = FromRgba(184, 134, 11, 255);
+ public static readonly Color DarkGoldenrod = FromPixel(new Rgba32(184, 134, 11, 255));
///
/// Represents a matching the W3C definition that has an hex value of #A9A9A9.
///
- public static readonly Color DarkGray = FromRgba(169, 169, 169, 255);
+ public static readonly Color DarkGray = FromPixel(new Rgba32(169, 169, 169, 255));
///
/// Represents a matching the W3C definition that has an hex value of #006400.
///
- public static readonly Color DarkGreen = FromRgba(0, 100, 0, 255);
+ public static readonly Color DarkGreen = FromPixel(new Rgba32(0, 100, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #A9A9A9.
@@ -149,52 +151,52 @@ public readonly partial struct Color
///
/// Represents a matching the W3C definition that has an hex value of #BDB76B.
///
- public static readonly Color DarkKhaki = FromRgba(189, 183, 107, 255);
+ public static readonly Color DarkKhaki = FromPixel(new Rgba32(189, 183, 107, 255));
///
/// Represents a matching the W3C definition that has an hex value of #8B008B.
///
- public static readonly Color DarkMagenta = FromRgba(139, 0, 139, 255);
+ public static readonly Color DarkMagenta = FromPixel(new Rgba32(139, 0, 139, 255));
///
/// Represents a matching the W3C definition that has an hex value of #556B2F.
///
- public static readonly Color DarkOliveGreen = FromRgba(85, 107, 47, 255);
+ public static readonly Color DarkOliveGreen = FromPixel(new Rgba32(85, 107, 47, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FF8C00.
///
- public static readonly Color DarkOrange = FromRgba(255, 140, 0, 255);
+ public static readonly Color DarkOrange = FromPixel(new Rgba32(255, 140, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #9932CC.
///
- public static readonly Color DarkOrchid = FromRgba(153, 50, 204, 255);
+ public static readonly Color DarkOrchid = FromPixel(new Rgba32(153, 50, 204, 255));
///
/// Represents a matching the W3C definition that has an hex value of #8B0000.
///
- public static readonly Color DarkRed = FromRgba(139, 0, 0, 255);
+ public static readonly Color DarkRed = FromPixel(new Rgba32(139, 0, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #E9967A.
///
- public static readonly Color DarkSalmon = FromRgba(233, 150, 122, 255);
+ public static readonly Color DarkSalmon = FromPixel(new Rgba32(233, 150, 122, 255));
///
/// Represents a matching the W3C definition that has an hex value of #8FBC8F.
///
- public static readonly Color DarkSeaGreen = FromRgba(143, 188, 143, 255);
+ public static readonly Color DarkSeaGreen = FromPixel(new Rgba32(143, 188, 143, 255));
///
/// Represents a matching the W3C definition that has an hex value of #483D8B.
///
- public static readonly Color DarkSlateBlue = FromRgba(72, 61, 139, 255);
+ public static readonly Color DarkSlateBlue = FromPixel(new Rgba32(72, 61, 139, 255));
///
/// Represents a matching the W3C definition that has an hex value of #2F4F4F.
///
- public static readonly Color DarkSlateGray = FromRgba(47, 79, 79, 255);
+ public static readonly Color DarkSlateGray = FromPixel(new Rgba32(47, 79, 79, 255));
///
/// Represents a matching the W3C definition that has an hex value of #2F4F4F.
@@ -204,27 +206,27 @@ public readonly partial struct Color
///
/// Represents a matching the W3C definition that has an hex value of #00CED1.
///
- public static readonly Color DarkTurquoise = FromRgba(0, 206, 209, 255);
+ public static readonly Color DarkTurquoise = FromPixel(new Rgba32(0, 206, 209, 255));
///
/// Represents a matching the W3C definition that has an hex value of #9400D3.
///
- public static readonly Color DarkViolet = FromRgba(148, 0, 211, 255);
+ public static readonly Color DarkViolet = FromPixel(new Rgba32(148, 0, 211, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FF1493.
///
- public static readonly Color DeepPink = FromRgba(255, 20, 147, 255);
+ public static readonly Color DeepPink = FromPixel(new Rgba32(255, 20, 147, 255));
///
/// Represents a matching the W3C definition that has an hex value of #00BFFF.
///
- public static readonly Color DeepSkyBlue = FromRgba(0, 191, 255, 255);
+ public static readonly Color DeepSkyBlue = FromPixel(new Rgba32(0, 191, 255, 255));
///
/// Represents a matching the W3C definition that has an hex value of #696969.
///
- public static readonly Color DimGray = FromRgba(105, 105, 105, 255);
+ public static readonly Color DimGray = FromPixel(new Rgba32(105, 105, 105, 255));
///
/// Represents a matching the W3C definition that has an hex value of #696969.
@@ -234,62 +236,62 @@ public readonly partial struct Color
///
/// Represents a matching the W3C definition that has an hex value of #1E90FF.
///
- public static readonly Color DodgerBlue = FromRgba(30, 144, 255, 255);
+ public static readonly Color DodgerBlue = FromPixel(new Rgba32(30, 144, 255, 255));
///
/// Represents a matching the W3C definition that has an hex value of #B22222.
///
- public static readonly Color Firebrick = FromRgba(178, 34, 34, 255);
+ public static readonly Color Firebrick = FromPixel(new Rgba32(178, 34, 34, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFFAF0.
///
- public static readonly Color FloralWhite = FromRgba(255, 250, 240, 255);
+ public static readonly Color FloralWhite = FromPixel(new Rgba32(255, 250, 240, 255));
///
/// Represents a matching the W3C definition that has an hex value of #228B22.
///
- public static readonly Color ForestGreen = FromRgba(34, 139, 34, 255);
+ public static readonly Color ForestGreen = FromPixel(new Rgba32(34, 139, 34, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FF00FF.
///
- public static readonly Color Fuchsia = FromRgba(255, 0, 255, 255);
+ public static readonly Color Fuchsia = FromPixel(new Rgba32(255, 0, 255, 255));
///
/// Represents a matching the W3C definition that has an hex value of #DCDCDC.
///
- public static readonly Color Gainsboro = FromRgba(220, 220, 220, 255);
+ public static readonly Color Gainsboro = FromPixel(new Rgba32(220, 220, 220, 255));
///
/// Represents a matching the W3C definition that has an hex value of #F8F8FF.
///
- public static readonly Color GhostWhite = FromRgba(248, 248, 255, 255);
+ public static readonly Color GhostWhite = FromPixel(new Rgba32(248, 248, 255, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFD700.
///
- public static readonly Color Gold = FromRgba(255, 215, 0, 255);
+ public static readonly Color Gold = FromPixel(new Rgba32(255, 215, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #DAA520.
///
- public static readonly Color Goldenrod = FromRgba(218, 165, 32, 255);
+ public static readonly Color Goldenrod = FromPixel(new Rgba32(218, 165, 32, 255));
///
/// Represents a matching the W3C definition that has an hex value of #808080.
///
- public static readonly Color Gray = FromRgba(128, 128, 128, 255);
+ public static readonly Color Gray = FromPixel(new Rgba32(128, 128, 128, 255));
///
/// Represents a matching the W3C definition that has an hex value of #008000.
///
- public static readonly Color Green = FromRgba(0, 128, 0, 255);
+ public static readonly Color Green = FromPixel(new Rgba32(0, 128, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #ADFF2F.
///
- public static readonly Color GreenYellow = FromRgba(173, 255, 47, 255);
+ public static readonly Color GreenYellow = FromPixel(new Rgba32(173, 255, 47, 255));
///
/// Represents a matching the W3C definition that has an hex value of #808080.
@@ -299,82 +301,82 @@ public readonly partial struct Color
///
/// Represents a matching the W3C definition that has an hex value of #F0FFF0.
///
- public static readonly Color Honeydew = FromRgba(240, 255, 240, 255);
+ public static readonly Color Honeydew = FromPixel(new Rgba32(240, 255, 240, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FF69B4.
///
- public static readonly Color HotPink = FromRgba(255, 105, 180, 255);
+ public static readonly Color HotPink = FromPixel(new Rgba32(255, 105, 180, 255));
///
/// Represents a matching the W3C definition that has an hex value of #CD5C5C.
///
- public static readonly Color IndianRed = FromRgba(205, 92, 92, 255);
+ public static readonly Color IndianRed = FromPixel(new Rgba32(205, 92, 92, 255));
///
/// Represents a matching the W3C definition that has an hex value of #4B0082.
///
- public static readonly Color Indigo = FromRgba(75, 0, 130, 255);
+ public static readonly Color Indigo = FromPixel(new Rgba32(75, 0, 130, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFFFF0.
///
- public static readonly Color Ivory = FromRgba(255, 255, 240, 255);
+ public static readonly Color Ivory = FromPixel(new Rgba32(255, 255, 240, 255));
///
/// Represents a matching the W3C definition that has an hex value of #F0E68C.
///
- public static readonly Color Khaki = FromRgba(240, 230, 140, 255);
+ public static readonly Color Khaki = FromPixel(new Rgba32(240, 230, 140, 255));
///
/// Represents a matching the W3C definition that has an hex value of #E6E6FA.
///
- public static readonly Color Lavender = FromRgba(230, 230, 250, 255);
+ public static readonly Color Lavender = FromPixel(new Rgba32(230, 230, 250, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFF0F5.
///
- public static readonly Color LavenderBlush = FromRgba(255, 240, 245, 255);
+ public static readonly Color LavenderBlush = FromPixel(new Rgba32(255, 240, 245, 255));
///
/// Represents a matching the W3C definition that has an hex value of #7CFC00.
///
- public static readonly Color LawnGreen = FromRgba(124, 252, 0, 255);
+ public static readonly Color LawnGreen = FromPixel(new Rgba32(124, 252, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFFACD.
///
- public static readonly Color LemonChiffon = FromRgba(255, 250, 205, 255);
+ public static readonly Color LemonChiffon = FromPixel(new Rgba32(255, 250, 205, 255));
///
/// Represents a matching the W3C definition that has an hex value of #ADD8E6.
///
- public static readonly Color LightBlue = FromRgba(173, 216, 230, 255);
+ public static readonly Color LightBlue = FromPixel(new Rgba32(173, 216, 230, 255));
///
/// Represents a matching the W3C definition that has an hex value of #F08080.
///
- public static readonly Color LightCoral = FromRgba(240, 128, 128, 255);
+ public static readonly Color LightCoral = FromPixel(new Rgba32(240, 128, 128, 255));
///
/// Represents a matching the W3C definition that has an hex value of #E0FFFF.
///
- public static readonly Color LightCyan = FromRgba(224, 255, 255, 255);
+ public static readonly Color LightCyan = FromPixel(new Rgba32(224, 255, 255, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FAFAD2.
///
- public static readonly Color LightGoldenrodYellow = FromRgba(250, 250, 210, 255);
+ public static readonly Color LightGoldenrodYellow = FromPixel(new Rgba32(250, 250, 210, 255));
///
/// Represents a matching the W3C definition that has an hex value of #D3D3D3.
///
- public static readonly Color LightGray = FromRgba(211, 211, 211, 255);
+ public static readonly Color LightGray = FromPixel(new Rgba32(211, 211, 211, 255));
///
/// Represents a matching the W3C definition that has an hex value of #90EE90.
///
- public static readonly Color LightGreen = FromRgba(144, 238, 144, 255);
+ public static readonly Color LightGreen = FromPixel(new Rgba32(144, 238, 144, 255));
///
/// Represents a matching the W3C definition that has an hex value of #D3D3D3.
@@ -384,27 +386,27 @@ public readonly partial struct Color
///
/// Represents a matching the W3C definition that has an hex value of #FFB6C1.
///
- public static readonly Color LightPink = FromRgba(255, 182, 193, 255);
+ public static readonly Color LightPink = FromPixel(new Rgba32(255, 182, 193, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFA07A.
///
- public static readonly Color LightSalmon = FromRgba(255, 160, 122, 255);
+ public static readonly Color LightSalmon = FromPixel(new Rgba32(255, 160, 122, 255));
///
/// Represents a matching the W3C definition that has an hex value of #20B2AA.
///
- public static readonly Color LightSeaGreen = FromRgba(32, 178, 170, 255);
+ public static readonly Color LightSeaGreen = FromPixel(new Rgba32(32, 178, 170, 255));
///
/// Represents a matching the W3C definition that has an hex value of #87CEFA.
///
- public static readonly Color LightSkyBlue = FromRgba(135, 206, 250, 255);
+ public static readonly Color LightSkyBlue = FromPixel(new Rgba32(135, 206, 250, 255));
///
/// Represents a matching the W3C definition that has an hex value of #778899.
///
- public static readonly Color LightSlateGray = FromRgba(119, 136, 153, 255);
+ public static readonly Color LightSlateGray = FromPixel(new Rgba32(119, 136, 153, 255));
///
/// Represents a matching the W3C definition that has an hex value of #778899.
@@ -414,27 +416,27 @@ public readonly partial struct Color
///
/// Represents a matching the W3C definition that has an hex value of #B0C4DE.
///
- public static readonly Color LightSteelBlue = FromRgba(176, 196, 222, 255);
+ public static readonly Color LightSteelBlue = FromPixel(new Rgba32(176, 196, 222, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFFFE0.
///
- public static readonly Color LightYellow = FromRgba(255, 255, 224, 255);
+ public static readonly Color LightYellow = FromPixel(new Rgba32(255, 255, 224, 255));
///
/// Represents a matching the W3C definition that has an hex value of #00FF00.
///
- public static readonly Color Lime = FromRgba(0, 255, 0, 255);
+ public static readonly Color Lime = FromPixel(new Rgba32(0, 255, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #32CD32.
///
- public static readonly Color LimeGreen = FromRgba(50, 205, 50, 255);
+ public static readonly Color LimeGreen = FromPixel(new Rgba32(50, 205, 50, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FAF0E6.
///
- public static readonly Color Linen = FromRgba(250, 240, 230, 255);
+ public static readonly Color Linen = FromPixel(new Rgba32(250, 240, 230, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FF00FF.
@@ -444,237 +446,237 @@ public readonly partial struct Color
///
/// Represents a matching the W3C definition that has an hex value of #800000.
///
- public static readonly Color Maroon = FromRgba(128, 0, 0, 255);
+ public static readonly Color Maroon = FromPixel(new Rgba32(128, 0, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #66CDAA.
///
- public static readonly Color MediumAquamarine = FromRgba(102, 205, 170, 255);
+ public static readonly Color MediumAquamarine = FromPixel(new Rgba32(102, 205, 170, 255));
///
/// Represents a matching the W3C definition that has an hex value of #0000CD.
///
- public static readonly Color MediumBlue = FromRgba(0, 0, 205, 255);
+ public static readonly Color MediumBlue = FromPixel(new Rgba32(0, 0, 205, 255));
///
/// Represents a matching the W3C definition that has an hex value of #BA55D3.
///
- public static readonly Color MediumOrchid = FromRgba(186, 85, 211, 255);
+ public static readonly Color MediumOrchid = FromPixel(new Rgba32(186, 85, 211, 255));
///
/// Represents a matching the W3C definition that has an hex value of #9370DB.
///
- public static readonly Color MediumPurple = FromRgba(147, 112, 219, 255);
+ public static readonly Color MediumPurple = FromPixel(new Rgba32(147, 112, 219, 255));
///
/// Represents a matching the W3C definition that has an hex value of #3CB371.
///
- public static readonly Color MediumSeaGreen = FromRgba(60, 179, 113, 255);
+ public static readonly Color MediumSeaGreen = FromPixel(new Rgba32(60, 179, 113, 255));
///
/// Represents a matching the W3C definition that has an hex value of #7B68EE.
///
- public static readonly Color MediumSlateBlue = FromRgba(123, 104, 238, 255);
+ public static readonly Color MediumSlateBlue = FromPixel(new Rgba32(123, 104, 238, 255));
///
/// Represents a matching the W3C definition that has an hex value of #00FA9A.
///
- public static readonly Color MediumSpringGreen = FromRgba(0, 250, 154, 255);
+ public static readonly Color MediumSpringGreen = FromPixel(new Rgba32(0, 250, 154, 255));
///
/// Represents a matching the W3C definition that has an hex value of #48D1CC.
///
- public static readonly Color MediumTurquoise = FromRgba(72, 209, 204, 255);
+ public static readonly Color MediumTurquoise = FromPixel(new Rgba32(72, 209, 204, 255));
///
/// Represents a matching the W3C definition that has an hex value of #C71585.
///
- public static readonly Color MediumVioletRed = FromRgba(199, 21, 133, 255);
+ public static readonly Color MediumVioletRed = FromPixel(new Rgba32(199, 21, 133, 255));
///
/// Represents a matching the W3C definition that has an hex value of #191970.
///
- public static readonly Color MidnightBlue = FromRgba(25, 25, 112, 255);
+ public static readonly Color MidnightBlue = FromPixel(new Rgba32(25, 25, 112, 255));
///
/// Represents a matching the W3C definition that has an hex value of #F5FFFA.
///
- public static readonly Color MintCream = FromRgba(245, 255, 250, 255);
+ public static readonly Color MintCream = FromPixel(new Rgba32(245, 255, 250, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFE4E1.
///
- public static readonly Color MistyRose = FromRgba(255, 228, 225, 255);
+ public static readonly Color MistyRose = FromPixel(new Rgba32(255, 228, 225, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFE4B5.
///
- public static readonly Color Moccasin = FromRgba(255, 228, 181, 255);
+ public static readonly Color Moccasin = FromPixel(new Rgba32(255, 228, 181, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFDEAD.
///
- public static readonly Color NavajoWhite = FromRgba(255, 222, 173, 255);
+ public static readonly Color NavajoWhite = FromPixel(new Rgba32(255, 222, 173, 255));
///
/// Represents a matching the W3C definition that has an hex value of #000080.
///
- public static readonly Color Navy = FromRgba(0, 0, 128, 255);
+ public static readonly Color Navy = FromPixel(new Rgba32(0, 0, 128, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FDF5E6.
///
- public static readonly Color OldLace = FromRgba(253, 245, 230, 255);
+ public static readonly Color OldLace = FromPixel(new Rgba32(253, 245, 230, 255));
///
/// Represents a matching the W3C definition that has an hex value of #808000.
///
- public static readonly Color Olive = FromRgba(128, 128, 0, 255);
+ public static readonly Color Olive = FromPixel(new Rgba32(128, 128, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #6B8E23.
///
- public static readonly Color OliveDrab = FromRgba(107, 142, 35, 255);
+ public static readonly Color OliveDrab = FromPixel(new Rgba32(107, 142, 35, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFA500.
///
- public static readonly Color Orange = FromRgba(255, 165, 0, 255);
+ public static readonly Color Orange = FromPixel(new Rgba32(255, 165, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FF4500.
///
- public static readonly Color OrangeRed = FromRgba(255, 69, 0, 255);
+ public static readonly Color OrangeRed = FromPixel(new Rgba32(255, 69, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #DA70D6.
///
- public static readonly Color Orchid = FromRgba(218, 112, 214, 255);
+ public static readonly Color Orchid = FromPixel(new Rgba32(218, 112, 214, 255));
///
/// Represents a matching the W3C definition that has an hex value of #EEE8AA.
///
- public static readonly Color PaleGoldenrod = FromRgba(238, 232, 170, 255);
+ public static readonly Color PaleGoldenrod = FromPixel(new Rgba32(238, 232, 170, 255));
///
/// Represents a matching the W3C definition that has an hex value of #98FB98.
///
- public static readonly Color PaleGreen = FromRgba(152, 251, 152, 255);
+ public static readonly Color PaleGreen = FromPixel(new Rgba32(152, 251, 152, 255));
///
/// Represents a matching the W3C definition that has an hex value of #AFEEEE.
///
- public static readonly Color PaleTurquoise = FromRgba(175, 238, 238, 255);
+ public static readonly Color PaleTurquoise = FromPixel(new Rgba32(175, 238, 238, 255));
///
/// Represents a matching the W3C definition that has an hex value of #DB7093.
///
- public static readonly Color PaleVioletRed = FromRgba(219, 112, 147, 255);
+ public static readonly Color PaleVioletRed = FromPixel(new Rgba32(219, 112, 147, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFEFD5.
///
- public static readonly Color PapayaWhip = FromRgba(255, 239, 213, 255);
+ public static readonly Color PapayaWhip = FromPixel(new Rgba32(255, 239, 213, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFDAB9.
///
- public static readonly Color PeachPuff = FromRgba(255, 218, 185, 255);
+ public static readonly Color PeachPuff = FromPixel(new Rgba32(255, 218, 185, 255));
///
/// Represents a matching the W3C definition that has an hex value of #CD853F.
///
- public static readonly Color Peru = FromRgba(205, 133, 63, 255);
+ public static readonly Color Peru = FromPixel(new Rgba32(205, 133, 63, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFC0CB.
///
- public static readonly Color Pink = FromRgba(255, 192, 203, 255);
+ public static readonly Color Pink = FromPixel(new Rgba32(255, 192, 203, 255));
///
/// Represents a matching the W3C definition that has an hex value of #DDA0DD.
///
- public static readonly Color Plum = FromRgba(221, 160, 221, 255);
+ public static readonly Color Plum = FromPixel(new Rgba32(221, 160, 221, 255));
///
/// Represents a matching the W3C definition that has an hex value of #B0E0E6.
///
- public static readonly Color PowderBlue = FromRgba(176, 224, 230, 255);
+ public static readonly Color PowderBlue = FromPixel(new Rgba32(176, 224, 230, 255));
///
/// Represents a matching the W3C definition that has an hex value of #800080.
///
- public static readonly Color Purple = FromRgba(128, 0, 128, 255);
+ public static readonly Color Purple = FromPixel(new Rgba32(128, 0, 128, 255));
///
/// Represents a matching the W3C definition that has an hex value of #663399.
///
- public static readonly Color RebeccaPurple = FromRgba(102, 51, 153, 255);
+ public static readonly Color RebeccaPurple = FromPixel(new Rgba32(102, 51, 153, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FF0000.
///
- public static readonly Color Red = FromRgba(255, 0, 0, 255);
+ public static readonly Color Red = FromPixel(new Rgba32(255, 0, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #BC8F8F.
///
- public static readonly Color RosyBrown = FromRgba(188, 143, 143, 255);
+ public static readonly Color RosyBrown = FromPixel(new Rgba32(188, 143, 143, 255));
///
/// Represents a matching the W3C definition that has an hex value of #4169E1.
///
- public static readonly Color RoyalBlue = FromRgba(65, 105, 225, 255);
+ public static readonly Color RoyalBlue = FromPixel(new Rgba32(65, 105, 225, 255));
///
/// Represents a matching the W3C definition that has an hex value of #8B4513.
///
- public static readonly Color SaddleBrown = FromRgba(139, 69, 19, 255);
+ public static readonly Color SaddleBrown = FromPixel(new Rgba32(139, 69, 19, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FA8072.
///
- public static readonly Color Salmon = FromRgba(250, 128, 114, 255);
+ public static readonly Color Salmon = FromPixel(new Rgba32(250, 128, 114, 255));
///
/// Represents a matching the W3C definition that has an hex value of #F4A460.
///
- public static readonly Color SandyBrown = FromRgba(244, 164, 96, 255);
+ public static readonly Color SandyBrown = FromPixel(new Rgba32(244, 164, 96, 255));
///
/// Represents a matching the W3C definition that has an hex value of #2E8B57.
///
- public static readonly Color SeaGreen = FromRgba(46, 139, 87, 255);
+ public static readonly Color SeaGreen = FromPixel(new Rgba32(46, 139, 87, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFF5EE.
///
- public static readonly Color SeaShell = FromRgba(255, 245, 238, 255);
+ public static readonly Color SeaShell = FromPixel(new Rgba32(255, 245, 238, 255));
///
/// Represents a matching the W3C definition that has an hex value of #A0522D.
///
- public static readonly Color Sienna = FromRgba(160, 82, 45, 255);
+ public static readonly Color Sienna = FromPixel(new Rgba32(160, 82, 45, 255));
///
/// Represents a matching the W3C definition that has an hex value of #C0C0C0.
///
- public static readonly Color Silver = FromRgba(192, 192, 192, 255);
+ public static readonly Color Silver = FromPixel(new Rgba32(192, 192, 192, 255));
///
/// Represents a matching the W3C definition that has an hex value of #87CEEB.
///
- public static readonly Color SkyBlue = FromRgba(135, 206, 235, 255);
+ public static readonly Color SkyBlue = FromPixel(new Rgba32(135, 206, 235, 255));
///
/// Represents a matching the W3C definition that has an hex value of #6A5ACD.
///
- public static readonly Color SlateBlue = FromRgba(106, 90, 205, 255);
+ public static readonly Color SlateBlue = FromPixel(new Rgba32(106, 90, 205, 255));
///
/// Represents a matching the W3C definition that has an hex value of #708090.
///
- public static readonly Color SlateGray = FromRgba(112, 128, 144, 255);
+ public static readonly Color SlateGray = FromPixel(new Rgba32(112, 128, 144, 255));
///
/// Represents a matching the W3C definition that has an hex value of #708090.
@@ -684,81 +686,80 @@ public readonly partial struct Color
///
/// Represents a matching the W3C definition that has an hex value of #FFFAFA.
///
- public static readonly Color Snow = FromRgba(255, 250, 250, 255);
+ public static readonly Color Snow = FromPixel(new Rgba32(255, 250, 250, 255));
///
/// Represents a matching the W3C definition that has an hex value of #00FF7F.
///
- public static readonly Color SpringGreen = FromRgba(0, 255, 127, 255);
+ public static readonly Color SpringGreen = FromPixel(new Rgba32(0, 255, 127, 255));
///
/// Represents a matching the W3C definition that has an hex value of #4682B4.
///
- public static readonly Color SteelBlue = FromRgba(70, 130, 180, 255);
+ public static readonly Color SteelBlue = FromPixel(new Rgba32(70, 130, 180, 255));
///
/// Represents a matching the W3C definition that has an hex value of #D2B48C.
///
- public static readonly Color Tan = FromRgba(210, 180, 140, 255);
+ public static readonly Color Tan = FromPixel(new Rgba32(210, 180, 140, 255));
///
/// Represents a matching the W3C definition that has an hex value of #008080.
///
- public static readonly Color Teal = FromRgba(0, 128, 128, 255);
+ public static readonly Color Teal = FromPixel(new Rgba32(0, 128, 128, 255));
///
/// Represents a matching the W3C definition that has an hex value of #D8BFD8.
///
- public static readonly Color Thistle = FromRgba(216, 191, 216, 255);
+ public static readonly Color Thistle = FromPixel(new Rgba32(216, 191, 216, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FF6347.
///
- public static readonly Color Tomato = FromRgba(255, 99, 71, 255);
+ public static readonly Color Tomato = FromPixel(new Rgba32(255, 99, 71, 255));
///
/// Represents a matching the W3C definition that has an hex value of #00000000.
///
- public static readonly Color Transparent = FromRgba(0, 0, 0, 0);
+ public static readonly Color Transparent = FromPixel(new Rgba32(0, 0, 0, 0));
///
/// Represents a matching the W3C definition that has an hex value of #40E0D0.
///
- public static readonly Color Turquoise = FromRgba(64, 224, 208, 255);
+ public static readonly Color Turquoise = FromPixel(new Rgba32(64, 224, 208, 255));
///
/// Represents a matching the W3C definition that has an hex value of #EE82EE.
///
- public static readonly Color Violet = FromRgba(238, 130, 238, 255);
+ public static readonly Color Violet = FromPixel(new Rgba32(238, 130, 238, 255));
///
/// Represents a matching the W3C definition that has an hex value of #F5DEB3.
///
- public static readonly Color Wheat = FromRgba(245, 222, 179, 255);
+ public static readonly Color Wheat = FromPixel(new Rgba32(245, 222, 179, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFFFFF.
///
- public static readonly Color White = FromRgba(255, 255, 255, 255);
+ public static readonly Color White = FromPixel(new Rgba32(255, 255, 255, 255));
///
/// Represents a matching the W3C definition that has an hex value of #F5F5F5.
///
- public static readonly Color WhiteSmoke = FromRgba(245, 245, 245, 255);
+ public static readonly Color WhiteSmoke = FromPixel(new Rgba32(245, 245, 245, 255));
///
/// Represents a matching the W3C definition that has an hex value of #FFFF00.
///
- public static readonly Color Yellow = FromRgba(255, 255, 0, 255);
+ public static readonly Color Yellow = FromPixel(new Rgba32(255, 255, 0, 255));
///
/// Represents a matching the W3C definition that has an hex value of #9ACD32.
///
- public static readonly Color YellowGreen = FromRgba(154, 205, 50, 255);
+ public static readonly Color YellowGreen = FromPixel(new Rgba32(154, 205, 50, 255));
private static Dictionary CreateNamedColorsLookup()
- {
- return new Dictionary(StringComparer.OrdinalIgnoreCase)
+ => new(StringComparer.OrdinalIgnoreCase)
{
{ nameof(AliceBlue), AliceBlue },
{ nameof(AntiqueWhite), AntiqueWhite },
@@ -910,5 +911,4 @@ public readonly partial struct Color
{ nameof(Yellow), Yellow },
{ nameof(YellowGreen), YellowGreen }
};
- }
}
diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs
index cebceabe09..8f54680ec4 100644
--- a/src/ImageSharp/Color/Color.cs
+++ b/src/ImageSharp/Color/Color.cs
@@ -18,34 +18,25 @@ namespace SixLabors.ImageSharp;
///
public readonly partial struct Color : IEquatable
{
- private readonly Rgba64 data;
+ private readonly Vector4 data;
private readonly IPixel? boxedHighPrecisionPixel;
- [MethodImpl(InliningOptions.ShortMethod)]
- private Color(byte r, byte g, byte b, byte a)
- {
- this.data = new Rgba64(
- ColorNumerics.UpscaleFrom8BitTo16Bit(r),
- ColorNumerics.UpscaleFrom8BitTo16Bit(g),
- ColorNumerics.UpscaleFrom8BitTo16Bit(b),
- ColorNumerics.UpscaleFrom8BitTo16Bit(a));
-
- this.boxedHighPrecisionPixel = null;
- }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- private Color(byte r, byte g, byte b)
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The containing the color information.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Color(Vector4 vector)
{
- this.data = new Rgba64(
- ColorNumerics.UpscaleFrom8BitTo16Bit(r),
- ColorNumerics.UpscaleFrom8BitTo16Bit(g),
- ColorNumerics.UpscaleFrom8BitTo16Bit(b),
- ushort.MaxValue);
-
+ this.data = Numerics.Clamp(vector, Vector4.Zero, Vector4.One);
this.boxedHighPrecisionPixel = null;
}
- [MethodImpl(InliningOptions.ShortMethod)]
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The pixel containing color information.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
private Color(IPixel pixel)
{
this.boxedHighPrecisionPixel = pixel;
@@ -61,7 +52,7 @@ public readonly partial struct Color : IEquatable
/// True if the parameter is equal to the parameter;
/// otherwise, false.
///
- [MethodImpl(InliningOptions.ShortMethod)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Color left, Color right) => left.Equals(right);
///
@@ -73,66 +64,64 @@ public readonly partial struct Color : IEquatable
/// True if the parameter is not equal to the parameter;
/// otherwise, false.
///
- [MethodImpl(InliningOptions.ShortMethod)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Color left, Color right) => !left.Equals(right);
///
- /// Creates a from RGBA bytes.
+ /// Creates a from the given .
///
- /// The red component (0-255).
- /// The green component (0-255).
- /// The blue component (0-255).
- /// The alpha component (0-255).
+ /// The pixel to convert from.
+ /// The pixel format.
/// The .
- [MethodImpl(InliningOptions.ShortMethod)]
- public static Color FromRgba(byte r, byte g, byte b, byte a) => new(r, g, b, a);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Color FromPixel(TPixel source)
+ where TPixel : unmanaged, IPixel
+ {
+ // Avoid boxing in case we can convert to Vector4 safely and efficiently
+ PixelTypeInfo info = TPixel.GetPixelTypeInfo();
+ if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentBitDepth.Bit32)
+ {
+ return new(source.ToScaledVector4());
+ }
+
+ return new(source);
+ }
///
- /// Creates a from RGB bytes.
+ /// Creates a from a generic scaled .
///
- /// The red component (0-255).
- /// The green component (0-255).
- /// The blue component (0-255).
+ /// The vector to load the pixel from.
/// The .
- [MethodImpl(InliningOptions.ShortMethod)]
- public static Color FromRgb(byte r, byte g, byte b) => new(r, g, b);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static Color FromScaledVector(Vector4 source) => new(source);
///
- /// Creates a from the given .
+ /// Bulk converts a span of a specified type to a span of .
///
- /// The pixel to convert from.
- /// The pixel format.
- /// The .
- [MethodImpl(InliningOptions.ShortMethod)]
- public static Color FromPixel(TPixel pixel)
+ /// The pixel type to convert to.
+ /// The source pixel span.
+ /// The destination color span.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static void FromPixel(ReadOnlySpan source, Span destination)
where TPixel : unmanaged, IPixel
{
- // Avoid boxing in case we can convert to Rgba64 safely and efficently
- if (typeof(TPixel) == typeof(Rgba64))
- {
- return new((Rgba64)(object)pixel);
- }
- else if (typeof(TPixel) == typeof(Rgb48))
- {
- return new((Rgb48)(object)pixel);
- }
- else if (typeof(TPixel) == typeof(La32))
- {
- return new((La32)(object)pixel);
- }
- else if (typeof(TPixel) == typeof(L16))
- {
- return new((L16)(object)pixel);
- }
- else if (Unsafe.SizeOf() <= Unsafe.SizeOf())
+ Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
+
+ // Avoid boxing in case we can convert to Vector4 safely and efficiently
+ PixelTypeInfo info = TPixel.GetPixelTypeInfo();
+ if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentBitDepth.Bit32)
{
- Rgba32 p = default;
- pixel.ToRgba32(ref p);
- return new(p);
+ for (int i = 0; i < destination.Length; i++)
+ {
+ destination[i] = FromScaledVector(source[i].ToScaledVector4());
+ }
}
else
{
- return new(pixel);
+ for (int i = 0; i < destination.Length; i++)
+ {
+ destination[i] = new(source[i]);
+ }
}
}
@@ -147,12 +136,11 @@ public readonly partial struct Color : IEquatable
///
/// The .
///
- [MethodImpl(InliningOptions.ShortMethod)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Color ParseHex(string hex)
{
Rgba32 rgba = Rgba32.ParseHex(hex);
-
- return new Color(rgba);
+ return FromPixel(rgba);
}
///
@@ -167,14 +155,14 @@ public readonly partial struct Color : IEquatable
///
/// The .
///
- [MethodImpl(InliningOptions.ShortMethod)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool TryParseHex(string hex, out Color result)
{
result = default;
if (Rgba32.TryParseHex(hex, out Rgba32 rgba))
{
- result = new Color(rgba);
+ result = FromPixel(rgba);
return true;
}
@@ -241,26 +229,24 @@ public readonly partial struct Color : IEquatable
/// The color having it's alpha channel altered.
public Color WithAlpha(float alpha)
{
- Vector4 v = (Vector4)this;
+ Vector4 v = this.ToScaledVector4();
v.W = alpha;
- return new Color(v);
+ return FromScaledVector(v);
}
///
/// Gets the hexadecimal representation of the color instance in rrggbbaa form.
///
/// A hexadecimal string representation of the value.
- [MethodImpl(InliningOptions.ShortMethod)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ToHex()
{
if (this.boxedHighPrecisionPixel is not null)
{
- Rgba32 rgba = default;
- this.boxedHighPrecisionPixel.ToRgba32(ref rgba);
- return rgba.ToHex();
+ return this.boxedHighPrecisionPixel.ToRgba32().ToHex();
}
- return this.data.ToRgba32().ToHex();
+ return Rgba32.FromScaledVector4(this.data).ToHex();
}
///
@@ -270,8 +256,8 @@ public readonly partial struct Color : IEquatable
/// Converts the color instance to a specified type.
///
/// The pixel type to convert to.
- /// The pixel value.
- [MethodImpl(InliningOptions.ShortMethod)]
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public TPixel ToPixel()
where TPixel : unmanaged, IPixel
{
@@ -282,14 +268,27 @@ public readonly partial struct Color : IEquatable
if (this.boxedHighPrecisionPixel is null)
{
- pixel = default;
- pixel.FromRgba64(this.data);
- return pixel;
+ return TPixel.FromScaledVector4(this.data);
+ }
+
+ return TPixel.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
+ }
+
+ ///
+ /// Expands the color into a generic ("scaled") representation
+ /// with values scaled and clamped between 0 and 1.
+ /// The vector components are typically expanded in least to greatest significance order.
+ ///
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public Vector4 ToScaledVector4()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data;
}
- pixel = default;
- pixel.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
- return pixel;
+ return this.boxedHighPrecisionPixel.ToScaledVector4();
}
///
@@ -298,11 +297,12 @@ public readonly partial struct Color : IEquatable
/// The pixel type to convert to.
/// The source color span.
/// The destination pixel span.
- [MethodImpl(InliningOptions.ShortMethod)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ToPixel(ReadOnlySpan source, Span destination)
where TPixel : unmanaged, IPixel
{
- // TODO: Investigate bulk operations utilizing configuration parameter here.
+ // We cannot use bulk pixel operations here as there is no guarantee that the source colors are
+ // created from pixel formats which fit into the unboxed vector data.
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
@@ -311,12 +311,12 @@ public readonly partial struct Color : IEquatable
}
///
- [MethodImpl(InliningOptions.ShortMethod)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Color other)
{
if (this.boxedHighPrecisionPixel is null && other.boxedHighPrecisionPixel is null)
{
- return this.data.PackedValue == other.data.PackedValue;
+ return this.data == other.data;
}
return this.boxedHighPrecisionPixel?.Equals(other.boxedHighPrecisionPixel) == true;
@@ -326,12 +326,12 @@ public readonly partial struct Color : IEquatable
public override bool Equals(object? obj) => obj is Color other && this.Equals(other);
///
- [MethodImpl(InliningOptions.ShortMethod)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
if (this.boxedHighPrecisionPixel is null)
{
- return this.data.PackedValue.GetHashCode();
+ return this.data.GetHashCode();
}
return this.boxedHighPrecisionPixel.GetHashCode();
diff --git a/src/ImageSharp/Common/Helpers/ColorNumerics.cs b/src/ImageSharp/Common/Helpers/ColorNumerics.cs
index 553a7c2e89..1c30d857f6 100644
--- a/src/ImageSharp/Common/Helpers/ColorNumerics.cs
+++ b/src/ImageSharp/Common/Helpers/ColorNumerics.cs
@@ -41,6 +41,34 @@ internal static class ColorNumerics
public static byte Get8BitBT709Luminance(byte r, byte g, byte b)
=> (byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5F);
+ ///
+ /// Gets the luminance from the rgb components using the formula
+ /// as specified by ITU-R Recommendation BT.709.
+ ///
+ /// The red component.
+ /// The green component.
+ /// The blue component.
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static byte Get8BitBT709Luminance(ushort r, ushort g, ushort b)
+ => (byte)((From16BitTo8Bit(r) * .2126F) +
+ (From16BitTo8Bit(g) * .7152F) +
+ (From16BitTo8Bit(b) * .0722F) + 0.5F);
+
+ ///
+ /// Gets the luminance from the rgb components using the formula as
+ /// specified by ITU-R Recommendation BT.709.
+ ///
+ /// The red component.
+ /// The green component.
+ /// The blue component.
+ /// The .
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static ushort Get16BitBT709Luminance(byte r, byte g, byte b)
+ => (ushort)((From8BitTo16Bit(r) * .2126F) +
+ (From8BitTo16Bit(g) * .7152F) +
+ (From8BitTo16Bit(b) * .0722F) + 0.5F);
+
///
/// Gets the luminance from the rgb components using the formula as
/// specified by ITU-R Recommendation BT.709.
@@ -72,8 +100,8 @@ internal static class ColorNumerics
/// The 8 bit component value.
/// The
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static byte DownScaleFrom16BitTo8Bit(ushort component)
- {
+ public static byte From16BitTo8Bit(ushort component) =>
+
// To scale to 8 bits From a 16-bit value V the required value (from the PNG specification) is:
//
// (V * 255) / 65535
@@ -102,8 +130,7 @@ internal static class ColorNumerics
// An alternative arithmetic calculation which also gives no errors is:
//
// (V * 255 + 32895) >> 16
- return (byte)(((component * 255) + 32895) >> 16);
- }
+ (byte)(((component * 255) + 32895) >> 16);
///
/// Scales a value from an 8 bit to
@@ -112,7 +139,7 @@ internal static class ColorNumerics
/// The 8 bit component value.
/// The
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static ushort UpscaleFrom8BitTo16Bit(byte component)
+ public static ushort From8BitTo16Bit(byte component)
=> (ushort)(component * 257);
///
diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs
index be2daa139e..990b21c99e 100644
--- a/src/ImageSharp/Common/Helpers/DebugGuard.cs
+++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs
@@ -33,10 +33,12 @@ internal static partial class DebugGuard
[Conditional("DEBUG")]
public static void NotDisposed(bool isDisposed, string objectName)
{
+#pragma warning disable CA1513
if (isDisposed)
{
throw new ObjectDisposedException(objectName);
}
+#pragma warning restore CA1513
}
///
diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs
index aba3c0abdc..777de2dc9f 100644
--- a/src/ImageSharp/Common/Helpers/Numerics.cs
+++ b/src/ImageSharp/Common/Helpers/Numerics.cs
@@ -5,7 +5,6 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
-using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
namespace SixLabors.ImageSharp;
@@ -61,6 +60,12 @@ internal static class Numerics
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static nint Modulo4(nint x) => x & 3;
+ ///
+ /// Calculates % 4
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static nuint Modulo4(nuint x) => x & 3;
+
///
/// Calculates % 8
///
@@ -908,25 +913,6 @@ internal static class Numerics
return Sse2.ConvertToInt32(vsum);
}
- ///
- /// Reduces elements of the vector into one sum.
- ///
- /// The accumulator to reduce.
- /// The sum of all elements.
- [MethodImpl(InliningOptions.ShortMethod)]
- public static int ReduceSumArm(Vector128 accumulator)
- {
- if (AdvSimd.Arm64.IsSupported)
- {
- Vector64 sum = AdvSimd.Arm64.AddAcross(accumulator);
- return (int)AdvSimd.Extract(sum, 0);
- }
-
- Vector128 sum2 = AdvSimd.AddPairwiseWidening(accumulator);
- Vector64 sum3 = AdvSimd.Add(sum2.GetLower().AsUInt32(), sum2.GetUpper().AsUInt32());
- return (int)AdvSimd.Extract(sum3, 0);
- }
-
///
/// Reduces even elements of the vector into one sum.
///
@@ -1024,6 +1010,26 @@ internal static class Numerics
where TVector : struct
=> (uint)span.Length / (uint)Vector256.Count;
+ ///
+ /// Gets the count of vectors that safely fit into the given span.
+ ///
+ /// The type of the vector.
+ /// The given span.
+ /// Count of vectors that safely fit into the span.
+ public static nuint Vector512Count(this Span span)
+ where TVector : struct
+ => (uint)span.Length / (uint)Vector512.Count;
+
+ ///
+ /// Gets the count of vectors that safely fit into the given span.
+ ///
+ /// The type of the vector.
+ /// The given span.
+ /// Count of vectors that safely fit into the span.
+ public static nuint Vector512Count(this ReadOnlySpan span)
+ where TVector : struct
+ => (uint)span.Length / (uint)Vector512.Count;
+
///
/// Gets the count of vectors that safely fit into the given span.
///
@@ -1063,4 +1069,24 @@ internal static class Numerics
public static nuint Vector256Count(int length)
where TVector : struct
=> (uint)length / (uint)Vector256.Count;
+
+ ///
+ /// Gets the count of vectors that safely fit into the given span.
+ ///
+ /// The type of the vector.
+ /// The given span.
+ /// Count of vectors that safely fit into the span.
+ public static nuint Vector512Count(this Span span)
+ where TVector : struct
+ => (uint)span.Length / (uint)Vector512.Count;
+
+ ///
+ /// Gets the count of vectors that safely fit into length.
+ ///
+ /// The type of the vector.
+ /// The given length.
+ /// Count of vectors that safely fit into the length.
+ public static nuint Vector512Count(int length)
+ where TVector : struct
+ => (uint)length / (uint)Vector512.Count;
}
diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
index 683ac518b8..c856267db2 100644
--- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
+++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
@@ -1,12 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
-using System.Buffers.Binary;
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using static SixLabors.ImageSharp.SimdUtils;
-
// The JIT can detect and optimize rotation idioms ROTL (Rotate Left)
// and ROTR (Rotate Right) emitting efficient CPU instructions:
// https://github.com/dotnet/coreclr/pull/1830
@@ -19,190 +13,24 @@ namespace SixLabors.ImageSharp;
internal interface IComponentShuffle
{
///
- /// Shuffles then slices 8-bit integers within 128-bit lanes in
- /// using the control and store the results in .
+ /// Shuffles then slices 8-bit integers in
+ /// using a byte control and store the results in .
+ /// If successful, this method will reduce the length of length
+ /// by the shuffle amount.
///
/// The source span of bytes.
- /// The destination span of bytes.
- void ShuffleReduce(ref ReadOnlySpan source, ref Span dest);
+ /// The destination span of bytes.
+ void ShuffleReduce(ref ReadOnlySpan source, ref Span destination);
///
- /// Shuffle 8-bit integers within 128-bit lanes in
- /// using the control and store the results in .
+ /// Shuffle 8-bit integers in
+ /// using the control and store the results in .
///
/// The source span of bytes.
- /// The destination span of bytes.
+ /// The destination span of bytes.
///
- /// Implementation can assume that source.Length is less or equal than dest.Length.
+ /// Implementation can assume that source.Length is less or equal than destination.Length.
/// Loops should iterate using source.Length.
///
- void RunFallbackShuffle(ReadOnlySpan source, Span dest);
-}
-
-///
-internal interface IShuffle4 : IComponentShuffle
-{
-}
-
-internal readonly struct DefaultShuffle4 : IShuffle4
-{
- public DefaultShuffle4(byte control)
- => this.Control = control;
-
- public byte Control { get; }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest)
- => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, this.Control);
-
- [MethodImpl(InliningOptions.ShortMethod)]
- public void RunFallbackShuffle(ReadOnlySpan source, Span dest)
- {
- ref byte sBase = ref MemoryMarshal.GetReference(source);
- ref byte dBase = ref MemoryMarshal.GetReference(dest);
-
- Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0);
-
- for (nuint i = 0; i < (uint)source.Length; i += 4)
- {
- Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + i);
- Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i);
- Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i);
- Unsafe.Add(ref dBase, i + 3) = Unsafe.Add(ref sBase, p3 + i);
- }
- }
-}
-
-internal readonly struct WXYZShuffle4 : IShuffle4
-{
- [MethodImpl(InliningOptions.ShortMethod)]
- public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest)
- => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle2103);
-
- [MethodImpl(InliningOptions.ShortMethod)]
- public void RunFallbackShuffle(ReadOnlySpan source, Span dest)
- {
- ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
- ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest));
- uint n = (uint)source.Length / 4;
-
- for (nuint i = 0; i < n; i++)
- {
- uint packed = Unsafe.Add(ref sBase, i);
-
- // packed = [W Z Y X]
- // ROTL(8, packed) = [Z Y X W]
- Unsafe.Add(ref dBase, i) = (packed << 8) | (packed >> 24);
- }
- }
-}
-
-internal readonly struct WZYXShuffle4 : IShuffle4
-{
- [MethodImpl(InliningOptions.ShortMethod)]
- public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest)
- => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle0123);
-
- [MethodImpl(InliningOptions.ShortMethod)]
- public void RunFallbackShuffle(ReadOnlySpan source, Span dest)
- {
- ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
- ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest));
- uint n = (uint)source.Length / 4;
-
- for (nuint i = 0; i < n; i++)
- {
- uint packed = Unsafe.Add(ref sBase, i);
-
- // packed = [W Z Y X]
- // REVERSE(packedArgb) = [X Y Z W]
- Unsafe.Add(ref dBase, i) = BinaryPrimitives.ReverseEndianness(packed);
- }
- }
-}
-
-internal readonly struct YZWXShuffle4 : IShuffle4
-{
- [MethodImpl(InliningOptions.ShortMethod)]
- public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest)
- => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle0321);
-
- [MethodImpl(InliningOptions.ShortMethod)]
- public void RunFallbackShuffle(ReadOnlySpan source, Span dest)
- {
- ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
- ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest));
- uint n = (uint)source.Length / 4;
-
- for (nuint i = 0; i < n; i++)
- {
- uint packed = Unsafe.Add(ref sBase, i);
-
- // packed = [W Z Y X]
- // ROTR(8, packedArgb) = [Y Z W X]
- Unsafe.Add(ref dBase, i) = BitOperations.RotateRight(packed, 8);
- }
- }
-}
-
-internal readonly struct ZYXWShuffle4 : IShuffle4
-{
- [MethodImpl(InliningOptions.ShortMethod)]
- public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest)
- => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle3012);
-
- [MethodImpl(InliningOptions.ShortMethod)]
- public void RunFallbackShuffle(ReadOnlySpan source, Span dest)
- {
- ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
- ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest));
- uint n = (uint)source.Length / 4;
-
- for (nuint i = 0; i < n; i++)
- {
- uint packed = Unsafe.Add(ref sBase, i);
-
- // packed = [W Z Y X]
- // tmp1 = [W 0 Y 0]
- // tmp2 = [0 Z 0 X]
- // tmp3=ROTL(16, tmp2) = [0 X 0 Z]
- // tmp1 + tmp3 = [W X Y Z]
- uint tmp1 = packed & 0xFF00FF00;
- uint tmp2 = packed & 0x00FF00FF;
- uint tmp3 = BitOperations.RotateLeft(tmp2, 16);
-
- Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
- }
- }
-}
-
-internal readonly struct XWZYShuffle4 : IShuffle4
-{
- [MethodImpl(InliningOptions.ShortMethod)]
- public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest)
- => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle1230);
-
- [MethodImpl(InliningOptions.ShortMethod)]
- public void RunFallbackShuffle(ReadOnlySpan source, Span dest)
- {
- ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
- ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest));
- uint n = (uint)source.Length / 4;
-
- for (nuint i = 0; i < n; i++)
- {
- uint packed = Unsafe.Add(ref sBase, i);
-
- // packed = [W Z Y X]
- // tmp1 = [0 Z 0 X]
- // tmp2 = [W 0 Y 0]
- // tmp3=ROTL(16, tmp2) = [Y 0 W 0]
- // tmp1 + tmp3 = [Y Z W X]
- uint tmp1 = packed & 0x00FF00FF;
- uint tmp2 = packed & 0xFF00FF00;
- uint tmp3 = BitOperations.RotateLeft(tmp2, 16);
-
- Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
- }
- }
+ void Shuffle(ReadOnlySpan source, Span destination);
}
diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs b/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs
index 6cf6eef08e..0f282c7f9a 100644
--- a/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs
+++ b/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static SixLabors.ImageSharp.SimdUtils;
@@ -12,24 +13,23 @@ internal interface IPad3Shuffle4 : IComponentShuffle
{
}
-internal readonly struct DefaultPad3Shuffle4 : IPad3Shuffle4
+internal readonly struct DefaultPad3Shuffle4([ConstantExpected] byte control) : IPad3Shuffle4
{
- public DefaultPad3Shuffle4(byte control)
- => this.Control = control;
-
- public byte Control { get; }
+ public byte Control { get; } = control;
[MethodImpl(InliningOptions.ShortMethod)]
- public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest)
- => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref dest, this.Control);
+ public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination)
+#pragma warning disable CA1857 // A constant is expected for the parameter
+ => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref destination, this.Control);
+#pragma warning restore CA1857 // A constant is expected for the parameter
[MethodImpl(InliningOptions.ShortMethod)]
- public void RunFallbackShuffle(ReadOnlySpan source, Span dest)
+ public void Shuffle(ReadOnlySpan source, Span destination)
{
ref byte sBase = ref MemoryMarshal.GetReference(source);
- ref byte dBase = ref MemoryMarshal.GetReference(dest);
+ ref byte dBase = ref MemoryMarshal.GetReference(destination);
- Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0);
+ SimdUtils.Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0);
Span temp = stackalloc byte[4];
ref byte t = ref MemoryMarshal.GetReference(temp);
@@ -51,14 +51,14 @@ internal readonly struct DefaultPad3Shuffle4 : IPad3Shuffle4
internal readonly struct XYZWPad3Shuffle4 : IPad3Shuffle4
{
[MethodImpl(InliningOptions.ShortMethod)]
- public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest)
- => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle3210);
+ public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination)
+ => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3210);
[MethodImpl(InliningOptions.ShortMethod)]
- public void RunFallbackShuffle(ReadOnlySpan source, Span dest)
+ public void Shuffle(ReadOnlySpan source, Span destination)
{
ref byte sBase = ref MemoryMarshal.GetReference(source);
- ref byte dBase = ref MemoryMarshal.GetReference(dest);
+ ref byte dBase = ref MemoryMarshal.GetReference(destination);
ref byte sEnd = ref Unsafe.Add(ref sBase, (uint)source.Length);
ref byte sLoopEnd = ref Unsafe.Subtract(ref sEnd, 4);
diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs
index 2cd586212e..3c0973ad69 100644
--- a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs
+++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static SixLabors.ImageSharp.SimdUtils;
@@ -12,24 +13,23 @@ internal interface IShuffle3 : IComponentShuffle
{
}
-internal readonly struct DefaultShuffle3 : IShuffle3
+internal readonly struct DefaultShuffle3([ConstantExpected] byte control) : IShuffle3
{
- public DefaultShuffle3(byte control)
- => this.Control = control;
-
- public byte Control { get; }
+ public byte Control { get; } = control;
[MethodImpl(InliningOptions.ShortMethod)]
- public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest)
- => HwIntrinsics.Shuffle3Reduce(ref source, ref dest, this.Control);
+ public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination)
+#pragma warning disable CA1857 // A constant is expected for the parameter
+ => HwIntrinsics.Shuffle3Reduce(ref source, ref destination, this.Control);
+#pragma warning restore CA1857 // A constant is expected for the parameter
[MethodImpl(InliningOptions.ShortMethod)]
- public void RunFallbackShuffle(ReadOnlySpan source, Span dest)
+ public void Shuffle(ReadOnlySpan source, Span destination)
{
ref byte sBase = ref MemoryMarshal.GetReference(source);
- ref byte dBase = ref MemoryMarshal.GetReference(dest);
+ ref byte dBase = ref MemoryMarshal.GetReference(destination);
- Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0);
+ SimdUtils.Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0);
for (nuint i = 0; i < (uint)source.Length; i += 3)
{
diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs
new file mode 100644
index 0000000000..d5c6df2c8b
--- /dev/null
+++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs
@@ -0,0 +1,178 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+using System.Buffers.Binary;
+using System.Diagnostics.CodeAnalysis;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using static SixLabors.ImageSharp.SimdUtils;
+
+namespace SixLabors.ImageSharp;
+
+///
+internal interface IShuffle4 : IComponentShuffle
+{
+}
+
+internal readonly struct DefaultShuffle4([ConstantExpected] byte control) : IShuffle4
+{
+ public byte Control { get; } = control;
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination)
+#pragma warning disable CA1857 // A constant is expected for the parameter
+ => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, this.Control);
+#pragma warning restore CA1857 // A constant is expected for the parameter
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Shuffle(ReadOnlySpan source, Span destination)
+ {
+ ref byte sBase = ref MemoryMarshal.GetReference(source);
+ ref byte dBase = ref MemoryMarshal.GetReference(destination);
+
+ SimdUtils.Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0);
+
+ for (nuint i = 0; i < (uint)source.Length; i += 4)
+ {
+ Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + i);
+ Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i);
+ Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i);
+ Unsafe.Add(ref dBase, i + 3) = Unsafe.Add(ref sBase, p3 + i);
+ }
+ }
+}
+
+internal readonly struct WXYZShuffle4 : IShuffle4
+{
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination)
+ => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle2103);
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Shuffle(ReadOnlySpan source, Span destination)
+ {
+ ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
+ ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination));
+ uint n = (uint)source.Length / 4;
+
+ for (nuint i = 0; i < n; i++)
+ {
+ uint packed = Unsafe.Add(ref sBase, i);
+
+ // packed = [W Z Y X]
+ // ROTL(8, packed) = [Z Y X W]
+ Unsafe.Add(ref dBase, i) = (packed << 8) | (packed >> 24);
+ }
+ }
+}
+
+internal readonly struct WZYXShuffle4 : IShuffle4
+{
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination)
+ => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle0123);
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Shuffle(ReadOnlySpan source, Span destination)
+ {
+ ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
+ ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination));
+ uint n = (uint)source.Length / 4;
+
+ for (nuint i = 0; i < n; i++)
+ {
+ uint packed = Unsafe.Add(ref sBase, i);
+
+ // packed = [W Z Y X]
+ // REVERSE(packedArgb) = [X Y Z W]
+ Unsafe.Add(ref dBase, i) = BinaryPrimitives.ReverseEndianness(packed);
+ }
+ }
+}
+
+internal readonly struct YZWXShuffle4 : IShuffle4
+{
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination)
+ => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle0321);
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Shuffle(ReadOnlySpan source, Span destination)
+ {
+ ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
+ ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination));
+ uint n = (uint)source.Length / 4;
+
+ for (nuint i = 0; i < n; i++)
+ {
+ uint packed = Unsafe.Add(ref sBase, i);
+
+ // packed = [W Z Y X]
+ // ROTR(8, packedArgb) = [Y Z W X]
+ Unsafe.Add(ref dBase, i) = BitOperations.RotateRight(packed, 8);
+ }
+ }
+}
+
+internal readonly struct ZYXWShuffle4 : IShuffle4
+{
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination)
+ => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3012);
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Shuffle(ReadOnlySpan source, Span destination)
+ {
+ ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
+ ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination));
+ uint n = (uint)source.Length / 4;
+
+ for (nuint i = 0; i < n; i++)
+ {
+ uint packed = Unsafe.Add(ref sBase, i);
+
+ // packed = [W Z Y X]
+ // tmp1 = [W 0 Y 0]
+ // tmp2 = [0 Z 0 X]
+ // tmp3=ROTL(16, tmp2) = [0 X 0 Z]
+ // tmp1 + tmp3 = [W X Y Z]
+ uint tmp1 = packed & 0xFF00FF00;
+ uint tmp2 = packed & 0x00FF00FF;
+ uint tmp3 = BitOperations.RotateLeft(tmp2, 16);
+
+ Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
+ }
+ }
+}
+
+internal readonly struct XWZYShuffle4 : IShuffle4
+{
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination)
+ => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle1230);
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void Shuffle(ReadOnlySpan source, Span destination)
+ {
+ ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
+ ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination));
+ uint n = (uint)source.Length / 4;
+
+ for (nuint i = 0; i < n; i++)
+ {
+ uint packed = Unsafe.Add(ref sBase, i);
+
+ // packed = [W Z Y X]
+ // tmp1 = [0 Z 0 X]
+ // tmp2 = [W 0 Y 0]
+ // tmp3=ROTL(16, tmp2) = [Y 0 W 0]
+ // tmp1 + tmp3 = [Y Z W X]
+ uint tmp1 = packed & 0x00FF00FF;
+ uint tmp2 = packed & 0xFF00FF00;
+ uint tmp3 = BitOperations.RotateLeft(tmp2, 16);
+
+ Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
+ }
+ }
+}
diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs
index 5e82973e33..3e7e440664 100644
--- a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs
+++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static SixLabors.ImageSharp.SimdUtils;
@@ -12,26 +13,25 @@ internal interface IShuffle4Slice3 : IComponentShuffle
{
}
-internal readonly struct DefaultShuffle4Slice3 : IShuffle4Slice3
+internal readonly struct DefaultShuffle4Slice3([ConstantExpected] byte control) : IShuffle4Slice3
{
- public DefaultShuffle4Slice3(byte control)
- => this.Control = control;
-
- public byte Control { get; }
+ public byte Control { get; } = control;
[MethodImpl(InliningOptions.ShortMethod)]
- public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest)
- => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref dest, this.Control);
+ public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination)
+#pragma warning disable CA1857 // A constant is expected for the parameter
+ => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref destination, this.Control);
+#pragma warning restore CA1857 // A constant is expected for the parameter
[MethodImpl(InliningOptions.ShortMethod)]
- public void RunFallbackShuffle(ReadOnlySpan source, Span dest)
+ public void Shuffle(ReadOnlySpan source, Span destination)
{
ref byte sBase = ref MemoryMarshal.GetReference(source);
- ref byte dBase = ref MemoryMarshal.GetReference(dest);
+ ref byte dBase = ref MemoryMarshal.GetReference(destination);
- Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0);
+ SimdUtils.Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0);
- for (nuint i = 0, j = 0; i < (uint)dest.Length; i += 3, j += 4)
+ for (nuint i = 0, j = 0; i < (uint)destination.Length; i += 3, j += 4)
{
Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + j);
Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + j);
@@ -43,14 +43,14 @@ internal readonly struct DefaultShuffle4Slice3 : IShuffle4Slice3
internal readonly struct XYZWShuffle4Slice3 : IShuffle4Slice3
{
[MethodImpl(InliningOptions.ShortMethod)]
- public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest)
- => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref dest, Shuffle.MMShuffle3210);
+ public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination)
+ => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3210);
[MethodImpl(InliningOptions.ShortMethod)]
- public void RunFallbackShuffle(ReadOnlySpan source, Span dest)
+ public void Shuffle(ReadOnlySpan source, Span destination)
{
ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
- ref Byte3 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest));
+ ref Byte3 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination));
nint n = (nint)(uint)source.Length / 4;
nint m = Numerics.Modulo4(n);
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs
new file mode 100644
index 0000000000..5318ad0497
--- /dev/null
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs
@@ -0,0 +1,78 @@
+// Copyright (c) Six Labors.
+// Licensed under the Six Labors Split License.
+
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace SixLabors.ImageSharp;
+
+internal static partial class SimdUtils
+{
+ ///
+ /// Converts all input -s to -s normalized into [0..1].
+ /// should be the of the same size as ,
+ /// but there are no restrictions on the span's length.
+ ///
+ /// The source span of bytes
+ /// The destination span of floats
+ [MethodImpl(InliningOptions.ShortMethod)]
+ internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span destination)
+ {
+ DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!");
+
+ HwIntrinsics.ByteToNormalizedFloatReduce(ref source, ref destination);
+
+ if (source.Length > 0)
+ {
+ ConvertByteToNormalizedFloatRemainder(source, destination);
+ }
+ }
+
+ ///
+ /// Convert all values normalized into [0..1] from 'source' into 'destination' buffer of .
+ /// The values are scaled up into [0-255] and rounded, overflows are clamped.
+ /// should be the of the same size as ,
+ /// but there are no restrictions on the span's length.
+ ///
+ /// The source span of floats
+ /// The destination span of bytes
+ [MethodImpl(InliningOptions.ShortMethod)]
+ internal static void NormalizedFloatToByteSaturate(ReadOnlySpan source, Span destination)
+ {
+ DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!");
+
+ HwIntrinsics.NormalizedFloatToByteSaturateReduce(ref source, ref destination);
+
+ if (source.Length > 0)
+ {
+ ConvertNormalizedFloatToByteRemainder(source, destination);
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void ConvertByteToNormalizedFloatRemainder(ReadOnlySpan source, Span destination)
+ {
+ ref byte sBase = ref MemoryMarshal.GetReference(source);
+ ref float dBase = ref MemoryMarshal.GetReference(destination);
+
+ for (int i = 0; i < source.Length; i++)
+ {
+ Unsafe.Add(ref dBase, (uint)i) = Unsafe.Add(ref sBase, (uint)i) / 255f;
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static void ConvertNormalizedFloatToByteRemainder(ReadOnlySpan source, Span destination)
+ {
+ ref float sBase = ref MemoryMarshal.GetReference(source);
+ ref byte dBase = ref MemoryMarshal.GetReference(destination);
+
+ for (int i = 0; i < source.Length; i++)
+ {
+ Unsafe.Add(ref dBase, (uint)i) = ConvertToByte(Unsafe.Add(ref sBase, (uint)i));
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static byte ConvertToByte(float f) => (byte)Numerics.Clamp((f * 255f) + 0.5f, 0, 255f);
+}
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs
deleted file mode 100644
index ac122fc7d4..0000000000
--- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// ReSharper disable MemberHidesStaticFromOuterClass
-namespace SixLabors.ImageSharp;
-
-internal static partial class SimdUtils
-{
- ///
- /// Implementation methods based on newer API-s (Vector.Widen, Vector.Narrow, Vector.ConvertTo*).
- /// Only accelerated only on RyuJIT having dotnet/coreclr#10662 merged (.NET Core 2.1+ .NET 4.7.2+)
- /// See:
- /// https://github.com/dotnet/coreclr/pull/10662
- /// API Proposal:
- /// https://github.com/dotnet/corefx/issues/15957
- ///
- public static class ExtendedIntrinsics
- {
- public static bool IsAvailable { get; } = Vector.IsHardwareAccelerated;
-
- ///
- /// Widen and convert a vector of values into 2 vectors of -s.
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void ConvertToSingle(
- Vector source,
- out Vector dest1,
- out Vector dest2)
- {
- Vector.Widen(source, out Vector i1, out Vector i2);
- dest1 = Vector.ConvertToSingle(i1);
- dest2 = Vector.ConvertToSingle(i2);
- }
-
- ///
- /// as many elements as possible, slicing them down (keeping the remainder).
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- internal static void ByteToNormalizedFloatReduce(
- ref ReadOnlySpan source,
- ref Span dest)
- {
- DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
-
- if (!IsAvailable)
- {
- return;
- }
-
- int remainder = Numerics.ModuloP2(source.Length, Vector.Count);
- int adjustedCount = source.Length - remainder;
-
- if (adjustedCount > 0)
- {
- ByteToNormalizedFloat(source[..adjustedCount], dest[..adjustedCount]);
-
- source = source[adjustedCount..];
- dest = dest[adjustedCount..];
- }
- }
-
- ///
- /// as many elements as possible, slicing them down (keeping the remainder).
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- internal static void NormalizedFloatToByteSaturateReduce(
- ref ReadOnlySpan source,
- ref Span dest)
- {
- DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
-
- if (!IsAvailable)
- {
- return;
- }
-
- int remainder = Numerics.ModuloP2(source.Length, Vector.Count);
- int adjustedCount = source.Length - remainder;
-
- if (adjustedCount > 0)
- {
- NormalizedFloatToByteSaturate(source[..adjustedCount], dest[..adjustedCount]);
-
- source = source[adjustedCount..];
- dest = dest[adjustedCount..];
- }
- }
-
- ///
- /// Implementation , which is faster on new RyuJIT runtime.
- ///
- internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest)
- {
- VerifySpanInput(source, dest, Vector.Count);
-
- nuint n = dest.VectorCount();
-
- ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source));
- ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest));
-
- for (nuint i = 0; i < n; i++)
- {
- Vector b = Unsafe.Add(ref sourceBase, i);
-
- Vector.Widen(b, out Vector s0, out Vector s1);
- Vector.Widen(s0, out Vector w0, out Vector w1);
- Vector.Widen(s1, out Vector w2, out Vector w3);
-
- Vector f0 = ConvertToSingle(w0);
- Vector f1 = ConvertToSingle(w1);
- Vector f2 = ConvertToSingle(w2);
- Vector f3 = ConvertToSingle(w3);
-
- ref Vector d = ref Unsafe.Add(ref destBase, i * 4);
- d = f0;
- Unsafe.Add(ref d, 1) = f1;
- Unsafe.Add(ref d, 2) = f2;
- Unsafe.Add(ref d, 3) = f3;
- }
- }
-
- ///
- /// Implementation of , which is faster on new .NET runtime.
- ///
- internal static void NormalizedFloatToByteSaturate(
- ReadOnlySpan source,
- Span dest)
- {
- VerifySpanInput(source, dest, Vector.Count);
-
- nuint n = dest.VectorCount();
-
- ref Vector sourceBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(source));
- ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest));
-
- for (nuint i = 0; i < n; i++)
- {
- ref Vector s = ref Unsafe.Add(ref sourceBase, i * 4);
-
- Vector f0 = s;
- Vector f1 = Unsafe.Add(ref s, 1);
- Vector f2 = Unsafe.Add(ref s, 2);
- Vector f3 = Unsafe.Add(ref s, 3);
-
- Vector w0 = ConvertToUInt32(f0);
- Vector w1 = ConvertToUInt32(f1);
- Vector w2 = ConvertToUInt32(f2);
- Vector w3 = ConvertToUInt32(f3);
-
- var u0 = Vector.Narrow(w0, w1);
- var u1 = Vector.Narrow(w2, w3);
-
- Unsafe.Add(ref destBase, i) = Vector.Narrow(u0, u1);
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static Vector ConvertToUInt32(Vector vf)
- {
- var maxBytes = new Vector(255f);
- vf *= maxBytes;
- vf += new Vector(0.5f);
- vf = Vector.Min(Vector.Max(vf, Vector.Zero), maxBytes);
- var vi = Vector.ConvertToInt32(vf);
- return Vector.AsVectorUInt32(vi);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static Vector ConvertToSingle(Vector u)
- {
- var vi = Vector.AsVectorInt32(u);
- var v = Vector.ConvertToSingle(vi);
- v *= new Vector(1f / 255f);
- return v;
- }
- }
-}
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs
deleted file mode 100644
index a551cebd05..0000000000
--- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs
+++ /dev/null
@@ -1,144 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Six Labors Split License.
-
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// ReSharper disable MemberHidesStaticFromOuterClass
-namespace SixLabors.ImageSharp;
-
-internal static partial class SimdUtils
-{
- ///
- /// Fallback implementation based on (128bit).
- /// For , efficient software fallback implementations are present,
- /// and we hope that even mono's JIT is able to emit SIMD instructions for that type :P
- ///
- public static class FallbackIntrinsics128
- {
- ///
- /// as many elements as possible, slicing them down (keeping the remainder).
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- internal static void ByteToNormalizedFloatReduce(
- ref ReadOnlySpan source,
- ref Span dest)
- {
- DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
-
- int remainder = Numerics.Modulo4(source.Length);
- int adjustedCount = source.Length - remainder;
-
- if (adjustedCount > 0)
- {
- ByteToNormalizedFloat(source[..adjustedCount], dest[..adjustedCount]);
-
- source = source[adjustedCount..];
- dest = dest[adjustedCount..];
- }
- }
-
- ///
- /// as many elements as possible, slicing them down (keeping the remainder).
- ///
- [MethodImpl(InliningOptions.ShortMethod)]
- internal static void NormalizedFloatToByteSaturateReduce(
- ref ReadOnlySpan source,
- ref Span dest)
- {
- DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
-
- int remainder = Numerics.Modulo4(source.Length);
- int adjustedCount = source.Length - remainder;
-
- if (adjustedCount > 0)
- {
- NormalizedFloatToByteSaturate(
- source[..adjustedCount],
- dest[..adjustedCount]);
-
- source = source[adjustedCount..];
- dest = dest[adjustedCount..];
- }
- }
-
- ///
- /// Implementation of using .
- ///
- [MethodImpl(InliningOptions.ColdPath)]
- internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest)
- {
- VerifySpanInput(source, dest, 4);
-
- uint count = (uint)dest.Length / 4;
- if (count == 0)
- {
- return;
- }
-
- ref ByteVector4 sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
- ref Vector4 dBase = ref Unsafe.As