Browse Source

Merge branch 'main' into js/affine-bounds-fixes

pull/2795/head
James Jackson-South 2 years ago
committed by GitHub
parent
commit
fbce0fa218
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      .editorconfig
  2. 3
      .gitattributes
  3. 55
      .github/workflows/build-and-test.yml
  4. 16
      .github/workflows/code-coverage.yml
  5. 9
      ImageSharp.sln
  6. 4
      README.md
  7. 2
      shared-infrastructure
  8. 3
      src/ImageSharp.ruleset
  9. 4
      src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs
  10. 10
      src/ImageSharp/Advanced/ParallelRowIterator.cs
  11. 240
      src/ImageSharp/Color/Color.Conversions.cs
  12. 288
      src/ImageSharp/Color/Color.NamedColors.cs
  13. 182
      src/ImageSharp/Color/Color.cs
  14. 20
      src/ImageSharp/ColorProfiles/ChromaticAdaptionWhitePointSource.cs
  15. 8
      src/ImageSharp/ColorProfiles/CieConstants.cs
  16. 178
      src/ImageSharp/ColorProfiles/CieLab.cs
  17. 155
      src/ImageSharp/ColorProfiles/CieLch.cs
  18. 167
      src/ImageSharp/ColorProfiles/CieLchuv.cs
  19. 221
      src/ImageSharp/ColorProfiles/CieLuv.cs
  20. 14
      src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs
  21. 89
      src/ImageSharp/ColorProfiles/CieXyy.cs
  22. 59
      src/ImageSharp/ColorProfiles/CieXyz.cs
  23. 165
      src/ImageSharp/ColorProfiles/Cmyk.cs
  24. 63
      src/ImageSharp/ColorProfiles/ColorConversionOptions.cs
  25. 45
      src/ImageSharp/ColorProfiles/ColorProfileConverter.cs
  26. 57
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieLab.cs
  27. 54
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieXyz.cs
  28. 59
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs
  29. 54
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieLab.cs
  30. 46
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieXyz.cs
  31. 54
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzRgb.cs
  32. 59
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs
  33. 54
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieXyz.cs
  34. 57
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbRgb.cs
  35. 182
      src/ImageSharp/ColorProfiles/Companding/CompandingUtilities.cs
  36. 56
      src/ImageSharp/ColorProfiles/Companding/GammaCompanding.cs
  37. 71
      src/ImageSharp/ColorProfiles/Companding/LCompanding.cs
  38. 75
      src/ImageSharp/ColorProfiles/Companding/Rec2020Companding.cs
  39. 71
      src/ImageSharp/ColorProfiles/Companding/Rec709Companding.cs
  40. 71
      src/ImageSharp/ColorProfiles/Companding/SRgbCompanding.cs
  41. 245
      src/ImageSharp/ColorProfiles/Hsl.cs
  42. 231
      src/ImageSharp/ColorProfiles/Hsv.cs
  43. 200
      src/ImageSharp/ColorProfiles/HunterLab.cs
  44. 59
      src/ImageSharp/ColorProfiles/IColorProfile.cs
  45. 18
      src/ImageSharp/ColorProfiles/IProfileConnectingSpace.cs
  46. 24
      src/ImageSharp/ColorProfiles/KnownChromaticAdaptationMatrices.cs
  47. 71
      src/ImageSharp/ColorProfiles/KnownIlluminants.cs
  48. 113
      src/ImageSharp/ColorProfiles/KnownRgbWorkingSpaces.cs
  49. 75
      src/ImageSharp/ColorProfiles/Lms.cs
  50. 269
      src/ImageSharp/ColorProfiles/Rgb.cs
  51. 20
      src/ImageSharp/ColorProfiles/RgbPrimariesChromaticityCoordinates.cs
  52. 95
      src/ImageSharp/ColorProfiles/VonKriesChromaticAdaptation.cs
  53. 18
      src/ImageSharp/ColorProfiles/WorkingSpaces/GammaWorkingSpace.cs
  54. 18
      src/ImageSharp/ColorProfiles/WorkingSpaces/LWorkingSpace.cs
  55. 18
      src/ImageSharp/ColorProfiles/WorkingSpaces/Rec2020WorkingSpace.cs
  56. 18
      src/ImageSharp/ColorProfiles/WorkingSpaces/Rec709WorkingSpace.cs
  57. 40
      src/ImageSharp/ColorProfiles/WorkingSpaces/RgbWorkingSpace.cs
  58. 18
      src/ImageSharp/ColorProfiles/WorkingSpaces/SRgbWorkingSpace.cs
  59. 87
      src/ImageSharp/ColorProfiles/YCbCr.cs
  60. 135
      src/ImageSharp/ColorSpaces/CieLab.cs
  61. 156
      src/ImageSharp/ColorSpaces/CieLchuv.cs
  62. 136
      src/ImageSharp/ColorSpaces/CieLuv.cs
  63. 107
      src/ImageSharp/ColorSpaces/Cmyk.cs
  64. 34
      src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs
  65. 36
      src/ImageSharp/ColorSpaces/Companding/LCompanding.cs
  66. 39
      src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs
  67. 35
      src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs
  68. 230
      src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs
  69. 159
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs
  70. 441
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs
  71. 441
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs
  72. 441
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs
  73. 435
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs
  74. 437
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs
  75. 458
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs
  76. 437
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs
  77. 437
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs
  78. 437
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs
  79. 430
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs
  80. 429
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs
  81. 425
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs
  82. 419
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs
  83. 404
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs
  84. 59
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs
  85. 53
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs
  86. 31
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs
  87. 39
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs
  88. 43
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs
  89. 31
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs
  90. 39
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs
  91. 73
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs
  92. 52
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs
  93. 44
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs
  94. 69
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs
  95. 57
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs
  96. 86
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs
  97. 65
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs
  98. 55
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs
  99. 49
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs
  100. 158
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs

2
.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

3
.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

55
.github/workflows/build-and-test.yml

@ -20,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-13 # macos-latest runs on arm64 runners where libgdiplus is unavailable
framework: net7.0
sdk: 7.0.x
sdk-preview: true
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-13 # macos-latest runs on arm64 runners where libgdiplus is unavailable
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:
@ -87,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
@ -97,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
@ -109,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 }}
@ -152,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
@ -179,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

16
.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

9
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}"
@ -659,6 +661,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Qoi", "Qoi", "{E801B508-493
tests\Images\Input\Qoi\wikipedia_008.qoi = tests\Images\Input\Qoi\wikipedia_008.qoi
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Icon", "Icon", "{95E45DDE-A67D-48AD-BBA8-5FAA151B860D}"
ProjectSection(SolutionItems) = preProject
tests\Images\Input\Icon\aero_arrow.cur = tests\Images\Input\Icon\aero_arrow.cur
tests\Images\Input\Icon\flutter.ico = tests\Images\Input\Icon\flutter.ico
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -712,6 +720,7 @@ Global
{670DD46C-82E9-499A-B2D2-00A802ED0141} = {E1C42A6F-913B-4A7B-B1A8-2BB62843B254}
{5DFC394F-136F-4B76-9BCA-3BA786515EFC} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66}
{E801B508-4935-41CD-BA85-CF11BFF55A45} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66}
{95E45DDE-A67D-48AD-BBA8-5FAA151B860D} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5F8B9D1F-CD8B-4CC5-8216-D531E25BD795}

4
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**:

2
shared-infrastructure

@ -1 +1 @@
Subproject commit 353b9afe32a8000410312d17263407cd7bb82d19
Subproject commit 1dbfb576c83507645265c79e03369b66cdc0379f

3
src/ImageSharp.ruleset

@ -1,7 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="ImageSharp" ToolsVersion="17.0">
<Include Path="..\shared-infrastructure\sixlabors.ruleset" Action="Default" />
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="SA1011" Action="None" />
</Rules>
</RuleSet>

4
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);
}
}
}

10
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<TBuffer> buffer = allocator.Allocate<TBuffer>(bufferLength);
Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span);
Unsafe.AsRef(in operation).Invoke(in rows, buffer.Memory.Span);
return;
}

240
src/ImageSharp/Color/Color.Conversions.cs

@ -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;
/// <content>
/// Contains constructors and implicit conversion methods.
/// </content>
public readonly partial struct Color
{
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Rgba64"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Rgba64 pixel)
{
this.data = pixel;
this.boxedHighPrecisionPixel = null;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Rgb48"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Rgb48 pixel)
{
this.data = new Rgba64(pixel.R, pixel.G, pixel.B, ushort.MaxValue);
this.boxedHighPrecisionPixel = null;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="La32"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(La32 pixel)
{
this.data = new Rgba64(pixel.L, pixel.L, pixel.L, pixel.A);
this.boxedHighPrecisionPixel = null;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="L16"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(L16 pixel)
{
this.data = new Rgba64(pixel.PackedValue, pixel.PackedValue, pixel.PackedValue, ushort.MaxValue);
this.boxedHighPrecisionPixel = null;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Rgba32"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Rgba32 pixel)
{
this.data = new Rgba64(pixel);
this.boxedHighPrecisionPixel = null;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Argb32"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Argb32 pixel)
{
this.data = new Rgba64(pixel);
this.boxedHighPrecisionPixel = null;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Bgra32"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Bgra32 pixel)
{
this.data = new Rgba64(pixel);
this.boxedHighPrecisionPixel = null;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Abgr32"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Abgr32 pixel)
{
this.data = new Rgba64(pixel);
this.boxedHighPrecisionPixel = null;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Rgb24"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Rgb24 pixel)
{
this.data = new Rgba64(pixel);
this.boxedHighPrecisionPixel = null;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Bgr24"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Bgr24 pixel)
{
this.data = new Rgba64(pixel);
this.boxedHighPrecisionPixel = null;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="vector">The <see cref="Vector4"/> containing the color information.</param>
[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;
}
/// <summary>
/// Converts a <see cref="Color"/> to <see cref="Vector4"/>.
/// </summary>
/// <param name="color">The <see cref="Color"/>.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static explicit operator Vector4(Color color) => color.ToScaledVector4();
/// <summary>
/// Converts an <see cref="Vector4"/> to <see cref="Color"/>.
/// </summary>
/// <param name="source">The <see cref="Vector4"/>.</param>
/// <returns>The <see cref="Color"/>.</returns>
[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();
}
}

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

182
src/ImageSharp/Color/Color.cs

@ -18,34 +18,25 @@ namespace SixLabors.ImageSharp;
/// </remarks>
public readonly partial struct Color : IEquatable<Color>
{
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)
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="vector">The <see cref="Vector4"/> containing the color information.</param>
[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)]
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The pixel containing color information.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Color(IPixel pixel)
{
this.boxedHighPrecisionPixel = pixel;
@ -61,7 +52,7 @@ public readonly partial struct Color : IEquatable<Color>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter;
/// otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Color left, Color right) => left.Equals(right);
/// <summary>
@ -73,66 +64,64 @@ public readonly partial struct Color : IEquatable<Color>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter;
/// otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Color left, Color right) => !left.Equals(right);
/// <summary>
/// Creates a <see cref="Color"/> from RGBA bytes.
/// Creates a <see cref="Color"/> from the given <typeparamref name="TPixel"/>.
/// </summary>
/// <param name="r">The red component (0-255).</param>
/// <param name="g">The green component (0-255).</param>
/// <param name="b">The blue component (0-255).</param>
/// <param name="a">The alpha component (0-255).</param>
/// <param name="source">The pixel to convert from.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>The <see cref="Color"/>.</returns>
[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>(TPixel source)
where TPixel : unmanaged, IPixel<TPixel>
{
// 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);
}
/// <summary>
/// Creates a <see cref="Color"/> from RGB bytes.
/// Creates a <see cref="Color"/> from a generic scaled <see cref="Vector4"/>.
/// </summary>
/// <param name="r">The red component (0-255).</param>
/// <param name="g">The green component (0-255).</param>
/// <param name="b">The blue component (0-255).</param>
/// <param name="source">The vector to load the pixel from.</param>
/// <returns>The <see cref="Color"/>.</returns>
[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);
/// <summary>
/// Creates a <see cref="Color"/> from the given <typeparamref name="TPixel"/>.
/// Bulk converts a span of a specified <typeparamref name="TPixel"/> type to a span of <see cref="Color"/>.
/// </summary>
/// <param name="pixel">The pixel to convert from.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>The <see cref="Color"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Color FromPixel<TPixel>(TPixel pixel)
/// <typeparam name="TPixel">The pixel type to convert to.</typeparam>
/// <param name="source">The source pixel span.</param>
/// <param name="destination">The destination color span.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void FromPixel<TPixel>(ReadOnlySpan<TPixel> source, Span<Color> destination)
where TPixel : unmanaged, IPixel<TPixel>
{
// 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<TPixel>() <= Unsafe.SizeOf<Rgba32>())
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<Color>
/// <returns>
/// The <see cref="Color"/>.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Color ParseHex(string hex)
{
Rgba32 rgba = Rgba32.ParseHex(hex);
return new Color(rgba);
return FromPixel(rgba);
}
/// <summary>
@ -167,14 +155,14 @@ public readonly partial struct Color : IEquatable<Color>
/// <returns>
/// The <see cref="bool"/>.
/// </returns>
[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<Color>
/// <returns>The color having it's alpha channel altered.</returns>
public Color WithAlpha(float alpha)
{
Vector4 v = (Vector4)this;
Vector4 v = this.ToScaledVector4();
v.W = alpha;
return new Color(v);
return FromScaledVector(v);
}
/// <summary>
/// Gets the hexadecimal representation of the color instance in rrggbbaa form.
/// </summary>
/// <returns>A hexadecimal string representation of the value.</returns>
[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();
}
/// <inheritdoc />
@ -270,8 +256,8 @@ public readonly partial struct Color : IEquatable<Color>
/// Converts the color instance to a specified <typeparamref name="TPixel"/> type.
/// </summary>
/// <typeparam name="TPixel">The pixel type to convert to.</typeparam>
/// <returns>The pixel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
/// <returns>The <typeparamref name="TPixel"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TPixel ToPixel<TPixel>()
where TPixel : unmanaged, IPixel<TPixel>
{
@ -282,14 +268,27 @@ public readonly partial struct Color : IEquatable<Color>
if (this.boxedHighPrecisionPixel is null)
{
pixel = default;
pixel.FromRgba64(this.data);
return pixel;
return TPixel.FromScaledVector4(this.data);
}
return TPixel.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
}
/// <summary>
/// Expands the color into a generic ("scaled") <see cref="Vector4"/> representation
/// with values scaled and clamped between <value>0</value> and <value>1</value>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector4"/>.</returns>
[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();
}
/// <summary>
@ -298,11 +297,12 @@ public readonly partial struct Color : IEquatable<Color>
/// <typeparam name="TPixel">The pixel type to convert to.</typeparam>
/// <param name="source">The source color span.</param>
/// <param name="destination">The destination pixel span.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ToPixel<TPixel>(ReadOnlySpan<Color> source, Span<TPixel> destination)
where TPixel : unmanaged, IPixel<TPixel>
{
// 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<Color>
}
/// <inheritdoc />
[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<Color>
public override bool Equals(object? obj) => obj is Color other && this.Equals(other);
/// <inheritdoc />
[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();

20
src/ImageSharp/ColorProfiles/ChromaticAdaptionWhitePointSource.cs

@ -0,0 +1,20 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Enumerate the possible sources of the white point used in chromatic adaptation.
/// </summary>
public enum ChromaticAdaptionWhitePointSource
{
/// <summary>
/// The white point of the source color space.
/// </summary>
WhitePoint,
/// <summary>
/// The white point of the source working space.
/// </summary>
RgbWorkingSpace
}

8
src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs → src/ImageSharp/ColorProfiles/CieConstants.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Constants use for Cie conversion calculations
@ -12,10 +12,10 @@ internal static class CieConstants
/// <summary>
/// 216F / 24389F
/// </summary>
public const float Epsilon = 0.008856452F;
public const float Epsilon = 216f / 24389f;
/// <summary>
/// 24389F / 27F
/// </summary>
public const float Kappa = 903.2963F;
public const float Kappa = 24389f / 27f;
}

178
src/ImageSharp/ColorProfiles/CieLab.cs

@ -0,0 +1,178 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents a CIE L*a*b* 1976 color.
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieLab : IProfileConnectingSpace<CieLab, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="a">The a (green - magenta) component.</param>
/// <param name="b">The b (blue - yellow) component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLab(float l, float a, float b)
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.L = l;
this.A = a;
this.B = b;
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, a, b components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLab(Vector3 vector)
: this()
{
this.L = vector.X;
this.A = vector.Y;
this.B = vector.Z;
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public float L { get; }
/// <summary>
/// Gets the a color component.
/// <remarks>A value usually ranging from -100 to 100. Negative is green, positive magenta.</remarks>
/// </summary>
public float A { get; }
/// <summary>
/// Gets the b color component.
/// <remarks>A value usually ranging from -100 to 100. Negative is blue, positive is yellow</remarks>
/// </summary>
public float B { get; }
/// <summary>
/// Compares two <see cref="CieLab"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="CieLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(CieLab left, CieLab right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="CieLab"/> objects for inequality
/// </summary>
/// <param name="left">The <see cref="CieLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(CieLab left, CieLab right) => !left.Equals(right);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static CieLab FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
// Conversion algorithm described here:
// http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html
CieXyz whitePoint = options.TargetWhitePoint;
float wx = whitePoint.X, wy = whitePoint.Y, wz = whitePoint.Z;
float xr = source.X / wx, yr = source.Y / wy, zr = source.Z / wz;
const float inv116 = 1 / 116F;
float fx = xr > CieConstants.Epsilon ? MathF.Pow(xr, 0.3333333F) : ((CieConstants.Kappa * xr) + 16F) * inv116;
float fy = yr > CieConstants.Epsilon ? MathF.Pow(yr, 0.3333333F) : ((CieConstants.Kappa * yr) + 16F) * inv116;
float fz = zr > CieConstants.Epsilon ? MathF.Pow(zr, 0.3333333F) : ((CieConstants.Kappa * zr) + 16F) * inv116;
float l = (116F * fy) - 16F;
float a = 500F * (fx - fy);
float b = 200F * (fy - fz);
return new CieLab(l, a, b);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyz xyz = source[i];
destination[i] = FromProfileConnectingSpace(options, in xyz);
}
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
float l = this.L, a = this.A, b = this.B;
float fy = (l + 16) / 116F;
float fx = (a / 500F) + fy;
float fz = fy - (b / 200F);
float fx3 = Numerics.Pow3(fx);
float fz3 = Numerics.Pow3(fz);
float xr = fx3 > CieConstants.Epsilon ? fx3 : ((116F * fx) - 16F) / CieConstants.Kappa;
float yr = l > CieConstants.Kappa * CieConstants.Epsilon ? Numerics.Pow3((l + 16F) / 116F) : l / CieConstants.Kappa;
float zr = fz3 > CieConstants.Epsilon ? fz3 : ((116F * fz) - 16F) / CieConstants.Kappa;
CieXyz whitePoint = options.WhitePoint;
Vector3 wxyz = new(whitePoint.X, whitePoint.Y, whitePoint.Z);
Vector3 xyzr = new(xr, yr, zr);
return new(xyzr * wxyz);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieLab> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieLab lab = source[i];
destination[i] = lab.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is CieLab other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieLab other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<CieLab, Vector3>(ref Unsafe.AsRef(in this));
}

155
src/ImageSharp/ColorSpaces/CieLch.cs → src/ImageSharp/ColorProfiles/CieLch.cs

@ -3,21 +3,17 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents the CIE L*C*h°, cylindrical form of the CIE L*a*b* 1976 color.
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC"/>
/// </summary>
public readonly struct CieLch : IEquatable<CieLch>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieLch : IColorProfile<CieLch, CieLab>
{
/// <summary>
/// D50 standard illuminant.
/// Used when reference white is not specified explicitly.
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D50;
private static readonly Vector3 Min = new(0, -200, 0);
private static readonly Vector3 Max = new(100, 200, 360);
@ -27,23 +23,9 @@ public readonly struct CieLch : IEquatable<CieLch>
/// <param name="l">The lightness dimension.</param>
/// <param name="c">The chroma, relative saturation.</param>
/// <param name="h">The hue in degrees.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLch(float l, float c, float h)
: this(l, c, h, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLch"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="c">The chroma, relative saturation.</param>
/// <param name="h">The hue in degrees.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLch(float l, float c, float h, CieXyz whitePoint)
: this(new Vector3(l, c, h), whitePoint)
: this(new Vector3(l, c, h))
{
}
@ -51,50 +33,32 @@ public readonly struct CieLch : IEquatable<CieLch>
/// Initializes a new instance of the <see cref="CieLch"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, c, h components.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLch(Vector3 vector)
: this(vector, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLch"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, c, h components.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLch(Vector3 vector, CieXyz whitePoint)
{
vector = Vector3.Clamp(vector, Min, Max);
this.L = vector.X;
this.C = vector.Y;
this.H = vector.Z;
this.WhitePoint = whitePoint;
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public readonly float L { get; }
public float L { get; }
/// <summary>
/// Gets the a chroma component.
/// <remarks>A value ranging from 0 to 200.</remarks>
/// </summary>
public readonly float C { get; }
public float C { get; }
/// <summary>
/// Gets the h° hue component in degrees.
/// <remarks>A value ranging from 0 to 360.</remarks>
/// </summary>
public readonly float H { get; }
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public readonly CieXyz WhitePoint { get; }
public float H { get; }
/// <summary>
/// Compares two <see cref="CieLch"/> objects for equality.
@ -104,7 +68,7 @@ public readonly struct CieLch : IEquatable<CieLch>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(CieLch left, CieLch right) => left.Equals(right);
/// <summary>
@ -115,45 +79,88 @@ public readonly struct CieLch : IEquatable<CieLch>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(CieLch left, CieLch right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode()
=> HashCode.Combine(this.L, this.C, this.H, this.WhitePoint);
public static CieLch FromProfileConnectingSpace(ColorConversionOptions options, in CieLab source)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC
float l = source.L, a = source.A, b = source.B;
float c = MathF.Sqrt((a * a) + (b * b));
float hRadians = MathF.Atan2(b, a);
float hDegrees = GeometryUtilities.RadianToDegree(hRadians);
// Wrap the angle round at 360.
hDegrees %= 360;
// Make sure it's not negative.
while (hDegrees < 0)
{
hDegrees += 360;
}
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
return new CieLch(l, c, hDegrees);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override bool Equals(object? obj) => obj is CieLch other && this.Equals(other);
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieLab> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieLab lab = source[i];
destination[i] = FromProfileConnectingSpace(options, in lab);
}
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieLch other)
=> this.L.Equals(other.L)
&& this.C.Equals(other.C)
&& this.H.Equals(other.H)
&& this.WhitePoint.Equals(other.WhitePoint);
public CieLab ToProfileConnectingSpace(ColorConversionOptions options)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC
float l = this.L, c = this.C, hDegrees = this.H;
float hRadians = GeometryUtilities.DegreeToRadian(hDegrees);
/// <summary>
/// Computes the saturation of the color (chroma normalized by lightness)
/// </summary>
/// <remarks>
/// A value ranging from 0 to 100.
/// </remarks>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public float Saturation()
float a = c * MathF.Cos(hRadians);
float b = c * MathF.Sin(hRadians);
return new CieLab(l, a, b);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieLch> source, Span<CieLab> destination)
{
float result = 100 * (this.C / this.L);
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
if (float.IsNaN(result))
for (int i = 0; i < source.Length; i++)
{
return 0;
CieLch lch = source[i];
destination[i] = lch.ToProfileConnectingSpace(options);
}
return result;
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode()
=> HashCode.Combine(this.L, this.C, this.H);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object? obj) => obj is CieLch other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieLch other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<CieLch, Vector3>(ref Unsafe.AsRef(in this));
}

167
src/ImageSharp/ColorProfiles/CieLchuv.cs

@ -0,0 +1,167 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color.
/// <see href="https://en.wikipedia.org/wiki/CIELAB_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieLchuv : IColorProfile<CieLchuv, CieXyz>
{
private static readonly Vector3 Min = new(0, -200, 0);
private static readonly Vector3 Max = new(100, 200, 360);
/// <summary>
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="c">The chroma, relative saturation.</param>
/// <param name="h">The hue in degrees.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLchuv(float l, float c, float h)
: this(new Vector3(l, c, h))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, c, h components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLchuv(Vector3 vector)
: this()
{
vector = Vector3.Clamp(vector, Min, Max);
this.L = vector.X;
this.C = vector.Y;
this.H = vector.Z;
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public float L { get; }
/// <summary>
/// Gets the a chroma component.
/// <remarks>A value ranging from 0 to 200.</remarks>
/// </summary>
public float C { get; }
/// <summary>
/// Gets the h° hue component in degrees.
/// <remarks>A value ranging from 0 to 360.</remarks>
/// </summary>
public float H { get; }
/// <summary>
/// Compares two <see cref="CieLchuv"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="CieLchuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLchuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(CieLchuv left, CieLchuv right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="CieLchuv"/> objects for inequality
/// </summary>
/// <param name="left">The <see cref="CieLchuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLchuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(CieLchuv left, CieLchuv right) => !left.Equals(right);
/// <inheritdoc/>
public static CieLchuv FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
CieLuv luv = CieLuv.FromProfileConnectingSpace(options, source);
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
float l = luv.L, u = luv.U, v = luv.V;
float c = MathF.Sqrt((u * u) + (v * v));
float hRadians = MathF.Atan2(v, u);
float hDegrees = GeometryUtilities.RadianToDegree(hRadians);
// Wrap the angle round at 360.
hDegrees %= 360;
// Make sure it's not negative.
while (hDegrees < 0)
{
hDegrees += 360;
}
return new CieLchuv(l, c, hDegrees);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyz xyz = source[i];
destination[i] = FromProfileConnectingSpace(options, in xyz);
}
}
/// <inheritdoc/>
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
float l = this.L, c = this.C, hDegrees = this.H;
float hRadians = GeometryUtilities.DegreeToRadian(hDegrees);
float u = c * MathF.Cos(hRadians);
float v = c * MathF.Sin(hRadians);
CieLuv luv = new(l, u, v);
return luv.ToProfileConnectingSpace(options);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieLchuv> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieLchuv lch = source[i];
destination[i] = lch.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode()
=> HashCode.Combine(this.L, this.C, this.H);
/// <inheritdoc/>
public override string ToString()
=> FormattableString.Invariant($"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj)
=> obj is CieLchuv other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieLchuv other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<CieLchuv, Vector3>(ref Unsafe.AsRef(in this));
}

221
src/ImageSharp/ColorProfiles/CieLuv.cs

@ -0,0 +1,221 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// The CIE 1976 (L*, u*, v*) color space, commonly known by its abbreviation CIELUV, is a color space adopted by the International
/// Commission on Illumination (CIE) in 1976, as a simple-to-compute transformation of the 1931 CIE XYZ color space, but which
/// attempted perceptual uniformity
/// <see href="https://en.wikipedia.org/wiki/CIELUV"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieLuv : IColorProfile<CieLuv, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="u">The blue-yellow chromaticity coordinate of the given white point.</param>
/// <param name="v">The red-green chromaticity coordinate of the given white point.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLuv(float l, float u, float v)
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.L = l;
this.U = u;
this.V = v;
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, u, v components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLuv(Vector3 vector)
: this()
{
this.L = vector.X;
this.U = vector.Y;
this.V = vector.Z;
}
/// <summary>
/// Gets the lightness dimension
/// <remarks>A value usually ranging between 0 and 100.</remarks>
/// </summary>
public float L { get; }
/// <summary>
/// Gets the blue-yellow chromaticity coordinate of the given white point.
/// <remarks>A value usually ranging between -100 and 100.</remarks>
/// </summary>
public float U { get; }
/// <summary>
/// Gets the red-green chromaticity coordinate of the given white point.
/// <remarks>A value usually ranging between -100 and 100.</remarks>
/// </summary>
public float V { get; }
/// <summary>
/// Compares two <see cref="CieLuv"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="CieLuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(CieLuv left, CieLuv right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="CieLuv"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="CieLuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(CieLuv left, CieLuv right) => !left.Equals(right);
/// <inheritdoc/>
public static CieLuv FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
// Use doubles here for accuracy.
// Conversion algorithm described here:
// http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html
CieXyz whitePoint = options.TargetWhitePoint;
double yr = source.Y / whitePoint.Y;
double den = source.X + (15 * source.Y) + (3 * source.Z);
double up = den > 0 ? ComputeU(in source) : 0;
double vp = den > 0 ? ComputeV(in source) : 0;
double upr = ComputeU(in whitePoint);
double vpr = ComputeV(in whitePoint);
const double e = 1 / 3d;
double l = yr > CieConstants.Epsilon
? ((116 * Math.Pow(yr, e)) - 16d)
: (CieConstants.Kappa * yr);
if (double.IsNaN(l) || l == -0d)
{
l = 0;
}
double u = 13 * l * (up - upr);
double v = 13 * l * (vp - vpr);
if (double.IsNaN(u) || u == -0d)
{
u = 0;
}
if (double.IsNaN(v) || v == -0d)
{
v = 0;
}
return new CieLuv((float)l, (float)u, (float)v);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyz xyz = source[i];
destination[i] = FromProfileConnectingSpace(options, in xyz);
}
}
/// <inheritdoc/>
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
// Use doubles here for accuracy.
// Conversion algorithm described here:
// http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html
CieXyz whitePoint = options.WhitePoint;
double l = this.L, u = this.U, v = this.V;
double u0 = ComputeU(in whitePoint);
double v0 = ComputeV(in whitePoint);
double y = l > CieConstants.Kappa * CieConstants.Epsilon
? Numerics.Pow3((l + 16) / 116d)
: l / CieConstants.Kappa;
double a = ((52 * l / (u + (13 * l * u0))) - 1) / 3;
double b = -5 * y;
const double c = -1 / 3d;
double d = y * ((39 * l / (v + (13 * l * v0))) - 5);
double x = (d - b) / (a - c);
double z = (x * a) + b;
if (double.IsNaN(x) || x == -0d)
{
x = 0;
}
if (double.IsNaN(y) || y == -0d)
{
y = 0;
}
if (double.IsNaN(z) || z == -0d)
{
z = 0;
}
return new CieXyz((float)x, (float)y, (float)z);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieLuv> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieLuv luv = source[i];
destination[i] = luv.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.L, this.U, this.V);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is CieLuv other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieLuv other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<CieLuv, Vector3>(ref Unsafe.AsRef(in this));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double ComputeU(in CieXyz source)
=> (4 * source.X) / (source.X + (15 * source.Y) + (3 * source.Z));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double ComputeV(in CieXyz source)
=> (9 * source.Y) / (source.X + (15 * source.Y) + (3 * source.Z));
}

14
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs → src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs

@ -1,14 +1,16 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// ReSharper disable CompareOfFloatsByEqualityOperator
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents the coordinates of CIEXY chromaticity space.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromaticityCoordinates>
{
/// <summary>
@ -29,7 +31,7 @@ public readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromatici
/// <remarks>
/// Ranges usually from 0 to 1.
/// </remarks>
public readonly float X { get; }
public float X { get; }
/// <summary>
/// Gets the chromaticity Y-coordinate
@ -37,7 +39,7 @@ public readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromatici
/// <remarks>
/// Ranges usually from 0 to 1.
/// </remarks>
public readonly float Y { get; }
public float Y { get; }
/// <summary>
/// Compares two <see cref="CieXyChromaticityCoordinates"/> objects for equality.
@ -79,5 +81,7 @@ public readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromatici
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieXyChromaticityCoordinates other)
=> this.X.Equals(other.X) && this.Y.Equals(other.Y);
=> this.AsVector2Unsafe() == other.AsVector2Unsafe();
private Vector2 AsVector2Unsafe() => Unsafe.As<CieXyChromaticityCoordinates, Vector2>(ref Unsafe.AsRef(in this));
}

89
src/ImageSharp/ColorSpaces/CieXyy.cs → src/ImageSharp/ColorProfiles/CieXyy.cs

@ -3,14 +3,16 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents an CIE xyY 1931 color
/// <see href="https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space"/>
/// </summary>
public readonly struct CieXyy : IEquatable<CieXyy>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieXyy : IColorProfile<CieXyy, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="CieXyy"/> struct.
@ -18,7 +20,7 @@ public readonly struct CieXyy : IEquatable<CieXyy>
/// <param name="x">The x chroma component.</param>
/// <param name="y">The y chroma component.</param>
/// <param name="yl">The y luminance component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyy(float x, float y, float yl)
{
// Not clamping as documentation about this space only indicates "usual" ranges
@ -31,7 +33,7 @@ public readonly struct CieXyy : IEquatable<CieXyy>
/// Initializes a new instance of the <see cref="CieXyy"/> struct.
/// </summary>
/// <param name="vector">The vector representing the x, y, Y components.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyy(Vector3 vector)
: this()
{
@ -45,19 +47,19 @@ public readonly struct CieXyy : IEquatable<CieXyy>
/// Gets the X chrominance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float X { get; }
public float X { get; }
/// <summary>
/// Gets the Y chrominance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Y { get; }
public float Y { get; }
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Yl { get; }
public float Yl { get; }
/// <summary>
/// Compares two <see cref="CieXyy"/> objects for equality.
@ -67,7 +69,7 @@ public readonly struct CieXyy : IEquatable<CieXyy>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(CieXyy left, CieXyy right) => left.Equals(right);
/// <summary>
@ -78,22 +80,79 @@ public readonly struct CieXyy : IEquatable<CieXyy>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(CieXyy left, CieXyy right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Yl);
public static CieXyy FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
float x = source.X / (source.X + source.Y + source.Z);
float y = source.Y / (source.X + source.Y + source.Z);
if (float.IsNaN(x) || float.IsNaN(y))
{
return new CieXyy(0, 0, source.Y);
}
return new CieXyy(x, y, source.Y);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyz xyz = source[i];
destination[i] = FromProfileConnectingSpace(options, in xyz);
}
}
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})");
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
if (MathF.Abs(this.Y) < Constants.Epsilon)
{
return new CieXyz(0, 0, this.Yl);
}
float x = (this.X * this.Yl) / this.Y;
float y = this.Yl;
float z = ((1 - this.X - this.Y) * y) / this.Y;
return new CieXyz(x, y, z);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyy> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyy xyz = source[i];
destination[i] = xyz.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode()
=> HashCode.Combine(this.X, this.Y, this.Yl);
/// <inheritdoc/>
public override string ToString()
=> FormattableString.Invariant($"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is CieXyy other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieXyy other)
=> this.X.Equals(other.X)
&& this.Y.Equals(other.Y)
&& this.Yl.Equals(other.Yl);
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<CieXyy, Vector3>(ref Unsafe.AsRef(in this));
}

59
src/ImageSharp/ColorSpaces/CieXyz.cs → src/ImageSharp/ColorProfiles/CieXyz.cs

@ -3,14 +3,16 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents an CIE XYZ 1931 color
/// <see href="https://en.wikipedia.org/wiki/CIE_1931_color_space#Definition_of_the_CIE_XYZ_color_space"/>
/// </summary>
public readonly struct CieXyz : IEquatable<CieXyz>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieXyz : IProfileConnectingSpace<CieXyz, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="CieXyz"/> struct.
@ -18,10 +20,13 @@ public readonly struct CieXyz : IEquatable<CieXyz>
/// <param name="x">X is a mix (a linear combination) of cone response curves chosen to be nonnegative</param>
/// <param name="y">The y luminance component.</param>
/// <param name="z">Z is quasi-equal to blue stimulation, or the S cone of the human eye.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyz(float x, float y, float z)
: this(new Vector3(x, y, z))
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.X = x;
this.Y = y;
this.Z = z;
}
/// <summary>
@ -31,7 +36,6 @@ public readonly struct CieXyz : IEquatable<CieXyz>
public CieXyz(Vector3 vector)
: this()
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.X = vector.X;
this.Y = vector.Y;
this.Z = vector.Z;
@ -41,19 +45,19 @@ public readonly struct CieXyz : IEquatable<CieXyz>
/// Gets the X component. A mix (a linear combination) of cone response curves chosen to be nonnegative.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float X { get; }
public float X { get; }
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Y { get; }
public float Y { get; }
/// <summary>
/// Gets the Z component. Quasi-equal to blue stimulation, or the S cone response.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Z { get; }
public float Z { get; }
/// <summary>
/// Compares two <see cref="CieXyz"/> objects for equality.
@ -63,7 +67,7 @@ public readonly struct CieXyz : IEquatable<CieXyz>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(CieXyz left, CieXyz right) => left.Equals(right);
/// <summary>
@ -74,16 +78,41 @@ public readonly struct CieXyz : IEquatable<CieXyz>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(CieXyz left, CieXyz right) => !left.Equals(right);
/// <summary>
/// Returns a new <see cref="Vector3"/> representing this instance.
/// </summary>
/// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 ToVector3() => new(this.X, this.Y, this.Z);
/// <inheritdoc/>
public static CieXyz FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
=> new(source.X, source.Y, source.Z);
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
source.CopyTo(destination[..source.Length]);
}
/// <inheritdoc/>
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
=> new(this.X, this.Y, this.Z);
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
source.CopyTo(destination[..source.Length]);
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Z);
@ -94,9 +123,9 @@ public readonly struct CieXyz : IEquatable<CieXyz>
public override bool Equals(object? obj) => obj is CieXyz other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieXyz other)
=> this.X.Equals(other.X)
&& this.Y.Equals(other.Y)
&& this.Z.Equals(other.Z);
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<CieXyz, Vector3>(ref Unsafe.AsRef(in this));
}

165
src/ImageSharp/ColorProfiles/Cmyk.cs

@ -0,0 +1,165 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents an CMYK (cyan, magenta, yellow, keyline) color.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct Cmyk : IColorProfile<Cmyk, Rgb>
{
private static readonly Vector4 Min = Vector4.Zero;
private static readonly Vector4 Max = Vector4.One;
/// <summary>
/// Initializes a new instance of the <see cref="Cmyk"/> struct.
/// </summary>
/// <param name="c">The cyan component.</param>
/// <param name="m">The magenta component.</param>
/// <param name="y">The yellow component.</param>
/// <param name="k">The keyline black component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Cmyk(float c, float m, float y, float k)
: this(new Vector4(c, m, y, k))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Cmyk"/> struct.
/// </summary>
/// <param name="vector">The vector representing the c, m, y, k components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Cmyk(Vector4 vector)
{
vector = Numerics.Clamp(vector, Min, Max);
this.C = vector.X;
this.M = vector.Y;
this.Y = vector.Z;
this.K = vector.W;
}
/// <summary>
/// Gets the cyan color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float C { get; }
/// <summary>
/// Gets the magenta color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float M { get; }
/// <summary>
/// Gets the yellow color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float Y { get; }
/// <summary>
/// Gets the keyline black color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float K { get; }
/// <summary>
/// Compares two <see cref="Cmyk"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Cmyk"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Cmyk"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Cmyk left, Cmyk right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Cmyk"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="Cmyk"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Cmyk"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Cmyk left, Cmyk right) => !left.Equals(right);
/// <inheritdoc/>
public static Cmyk FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source)
{
// To CMY
Vector3 cmy = Vector3.One - source.ToScaledVector3();
// To CMYK
Vector3 k = new(MathF.Min(cmy.X, MathF.Min(cmy.Y, cmy.Z)));
if (MathF.Abs(k.X - 1F) < Constants.Epsilon)
{
return new Cmyk(0, 0, 0, 1F);
}
cmy = (cmy - k) / (Vector3.One - k);
return new Cmyk(cmy.X, cmy.Y, cmy.Z, k.X);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Rgb> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
// TODO: We can optimize this by using SIMD
for (int i = 0; i < source.Length; i++)
{
Rgb rgb = source[i];
destination[i] = FromProfileConnectingSpace(options, in rgb);
}
}
/// <inheritdoc/>
public Rgb ToProfileConnectingSpace(ColorConversionOptions options)
{
Vector3 rgb = (Vector3.One - new Vector3(this.C, this.M, this.Y)) * (Vector3.One - new Vector3(this.K));
return Rgb.FromScaledVector3(rgb);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Cmyk> source, Span<Rgb> destination)
{
// TODO: We can possibly optimize this by using SIMD
for (int i = 0; i < source.Length; i++)
{
Cmyk cmyk = source[i];
destination[i] = cmyk.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.RgbWorkingSpace;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
=> HashCode.Combine(this.C, this.M, this.Y, this.K);
/// <inheritdoc/>
public override string ToString()
=> FormattableString.Invariant($"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj)
=> obj is Cmyk other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Cmyk other)
=> this.AsVector4Unsafe() == other.AsVector4Unsafe();
private Vector4 AsVector4Unsafe() => Unsafe.As<Cmyk, Vector4>(ref Unsafe.AsRef(in this));
}

63
src/ImageSharp/ColorProfiles/ColorConversionOptions.cs

@ -0,0 +1,63 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Provides options for color profile conversion.
/// </summary>
public class ColorConversionOptions
{
private Matrix4x4 adaptationMatrix;
/// <summary>
/// Initializes a new instance of the <see cref="ColorConversionOptions"/> class.
/// </summary>
public ColorConversionOptions() => this.AdaptationMatrix = KnownChromaticAdaptationMatrices.Bradford;
/// <summary>
/// Gets the memory allocator.
/// </summary>
public MemoryAllocator MemoryAllocator { get; init; } = MemoryAllocator.Default;
/// <summary>
/// Gets the source white point used for chromatic adaptation in conversions from/to XYZ color space.
/// </summary>
public CieXyz WhitePoint { get; init; } = KnownIlluminants.D50;
/// <summary>
/// Gets the destination white point used for chromatic adaptation in conversions from/to XYZ color space.
/// </summary>
public CieXyz TargetWhitePoint { get; init; } = KnownIlluminants.D50;
/// <summary>
/// Gets the source working space used for companding in conversions from/to XYZ color space.
/// </summary>
public RgbWorkingSpace RgbWorkingSpace { get; init; } = KnownRgbWorkingSpaces.SRgb;
/// <summary>
/// Gets the destination working space used for companding in conversions from/to XYZ color space.
/// </summary>
public RgbWorkingSpace TargetRgbWorkingSpace { get; init; } = KnownRgbWorkingSpaces.SRgb;
/// <summary>
/// Gets the transformation matrix used in conversion to perform chromatic adaptation.
/// <see cref="KnownChromaticAdaptationMatrices"/> for further information. Default is Bradford.
/// </summary>
public Matrix4x4 AdaptationMatrix
{
get => this.adaptationMatrix;
init
{
this.adaptationMatrix = value;
Matrix4x4.Invert(value, out Matrix4x4 inverted);
this.InverseAdaptationMatrix = inverted;
}
}
internal Matrix4x4 InverseAdaptationMatrix { get; private set; }
}

45
src/ImageSharp/ColorProfiles/ColorProfileConverter.cs

@ -0,0 +1,45 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Allows the conversion of color profiles.
/// </summary>
public class ColorProfileConverter
{
/// <summary>
/// Initializes a new instance of the <see cref="ColorProfileConverter"/> class.
/// </summary>
public ColorProfileConverter()
: this(new())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ColorProfileConverter"/> class.
/// </summary>
/// <param name="options">The color profile conversion options.</param>
public ColorProfileConverter(ColorConversionOptions options)
=> this.Options = options;
/// <summary>
/// Gets the color profile conversion options.
/// </summary>
public ColorConversionOptions Options { get; }
internal (CieXyz From, CieXyz To) GetChromaticAdaptionWhitePoints<TFrom, TTo>()
where TFrom : struct, IColorProfile
where TTo : struct, IColorProfile
{
CieXyz sourceWhitePoint = TFrom.GetChromaticAdaptionWhitePointSource() == ChromaticAdaptionWhitePointSource.WhitePoint
? this.Options.WhitePoint
: this.Options.RgbWorkingSpace.WhitePoint;
CieXyz targetWhitePoint = TTo.GetChromaticAdaptionWhitePointSource() == ChromaticAdaptionWhitePointSource.WhitePoint
? this.Options.TargetWhitePoint
: this.Options.TargetRgbWorkingSpace.WhitePoint;
return (sourceWhitePoint, targetWhitePoint);
}
}

57
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieLab.cs

@ -0,0 +1,57 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsCieLabCieLab
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, CieLab>
where TTo : struct, IColorProfile<TTo, CieLab>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
CieLab pcsFromA = source.ToProfileConnectingSpace(options);
CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix);
// Convert between PCS
CieLab pcsTo = CieLab.FromProfileConnectingSpace(options, in pcsFromB);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, CieLab>
where TTo : struct, IColorProfile<TTo, CieLab>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<CieLab> pcsFromToOwner = options.MemoryAllocator.Allocate<CieLab>(source.Length);
Span<CieLab> pcsFromTo = pcsFromToOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFromTo);
using IMemoryOwner<CieXyz> pcsFromOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFrom = pcsFromOwner.GetSpan();
CieLab.ToProfileConnectionSpace(options, pcsFromTo, pcsFrom);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert between PCS.
CieLab.FromProfileConnectionSpace(options, pcsFrom, pcsFromTo);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsFromTo, destination);
}
}

54
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieXyz.cs

@ -0,0 +1,54 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsCieLabCieXyz
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, CieLab>
where TTo : struct, IColorProfile<TTo, CieXyz>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
CieLab pcsFrom = source.ToProfileConnectingSpace(options);
// Convert between PCS
CieXyz pcsTo = pcsFrom.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsTo = VonKriesChromaticAdaptation.Transform(in pcsTo, whitePoints, options.AdaptationMatrix);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, CieLab>
where TTo : struct, IColorProfile<TTo, CieXyz>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<CieLab> pcsFromOwner = options.MemoryAllocator.Allocate<CieLab>(source.Length);
Span<CieLab> pcsFrom = pcsFromOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFrom);
// Convert between PCS.
using IMemoryOwner<CieXyz> pcsToOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsTo = pcsToOwner.GetSpan();
CieLab.ToProfileConnectionSpace(options, pcsFrom, pcsTo);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsTo, pcsTo, whitePoints, options.AdaptationMatrix);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsTo, destination);
}
}

59
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs

@ -0,0 +1,59 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsCieLabRgb
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, CieLab>
where TTo : struct, IColorProfile<TTo, Rgb>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
CieLab pcsFromA = source.ToProfileConnectingSpace(options);
CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix);
// Convert between PCS
Rgb pcsTo = Rgb.FromProfileConnectingSpace(options, in pcsFromB);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, CieLab>
where TTo : struct, IColorProfile<TTo, Rgb>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<CieLab> pcsFromAOwner = options.MemoryAllocator.Allocate<CieLab>(source.Length);
Span<CieLab> pcsFromA = pcsFromAOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFromA);
using IMemoryOwner<CieXyz> pcsFromBOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFromB = pcsFromBOwner.GetSpan();
CieLab.ToProfileConnectionSpace(options, pcsFromA, pcsFromB);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFromB, pcsFromB, whitePoints, options.AdaptationMatrix);
// Convert between PCS.
using IMemoryOwner<Rgb> pcsToOwner = options.MemoryAllocator.Allocate<Rgb>(source.Length);
Span<Rgb> pcsTo = pcsToOwner.GetSpan();
Rgb.FromProfileConnectionSpace(options, pcsFromB, pcsTo);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsTo, destination);
}
}

54
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieLab.cs

@ -0,0 +1,54 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsCieXyzCieLab
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, CieXyz>
where TTo : struct, IColorProfile<TTo, CieLab>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
CieXyz pcsFrom = source.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFrom = VonKriesChromaticAdaptation.Transform(in pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert between PCS
CieLab pcsTo = CieLab.FromProfileConnectingSpace(options, in pcsFrom);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, CieXyz>
where TTo : struct, IColorProfile<TTo, CieLab>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<CieXyz> pcsFromOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFrom = pcsFromOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFrom);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert between PCS.
using IMemoryOwner<CieLab> pcsToOwner = options.MemoryAllocator.Allocate<CieLab>(source.Length);
Span<CieLab> pcsTo = pcsToOwner.GetSpan();
CieLab.FromProfileConnectionSpace(options, pcsFrom, pcsTo);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsTo, destination);
}
}

46
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieXyz.cs

@ -0,0 +1,46 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsCieXyzCieXyz
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, CieXyz>
where TTo : struct, IColorProfile<TTo, CieXyz>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
CieXyz pcsFrom = source.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFrom = VonKriesChromaticAdaptation.Transform(in pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsFrom);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, CieXyz>
where TTo : struct, IColorProfile<TTo, CieXyz>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<CieXyz> pcsFromOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFrom = pcsFromOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFrom);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsFrom, destination);
}
}

54
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzRgb.cs

@ -0,0 +1,54 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsCieXyzRgb
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, CieXyz>
where TTo : struct, IColorProfile<TTo, Rgb>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
CieXyz pcsFrom = source.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFrom = VonKriesChromaticAdaptation.Transform(in pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert between PCS
Rgb pcsTo = Rgb.FromProfileConnectingSpace(options, in pcsFrom);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, CieXyz>
where TTo : struct, IColorProfile<TTo, Rgb>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<CieXyz> pcsFromOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFrom = pcsFromOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFrom);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert between PCS.
using IMemoryOwner<Rgb> pcsToOwner = options.MemoryAllocator.Allocate<Rgb>(source.Length);
Span<Rgb> pcsTo = pcsToOwner.GetSpan();
Rgb.FromProfileConnectionSpace(options, pcsFrom, pcsTo);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsTo, destination);
}
}

59
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs

@ -0,0 +1,59 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsRgbCieLab
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, Rgb>
where TTo : struct, IColorProfile<TTo, CieLab>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
Rgb pcsFromA = source.ToProfileConnectingSpace(options);
CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix);
// Convert between PCS
CieLab pcsTo = CieLab.FromProfileConnectingSpace(options, in pcsFromB);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, Rgb>
where TTo : struct, IColorProfile<TTo, CieLab>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<Rgb> pcsFromAOwner = options.MemoryAllocator.Allocate<Rgb>(source.Length);
Span<Rgb> pcsFromA = pcsFromAOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFromA);
using IMemoryOwner<CieXyz> pcsFromBOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFromB = pcsFromBOwner.GetSpan();
Rgb.ToProfileConnectionSpace(options, pcsFromA, pcsFromB);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFromB, pcsFromB, whitePoints, options.AdaptationMatrix);
// Convert between PCS.
using IMemoryOwner<CieLab> pcsToOwner = options.MemoryAllocator.Allocate<CieLab>(source.Length);
Span<CieLab> pcsTo = pcsToOwner.GetSpan();
CieLab.FromProfileConnectionSpace(options, pcsFromB, pcsTo);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsTo, destination);
}
}

54
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieXyz.cs

@ -0,0 +1,54 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsRgbCieXyz
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, Rgb>
where TTo : struct, IColorProfile<TTo, CieXyz>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
Rgb pcsFrom = source.ToProfileConnectingSpace(options);
// Convert between PCS
CieXyz pcsTo = pcsFrom.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsTo = VonKriesChromaticAdaptation.Transform(in pcsTo, whitePoints, options.AdaptationMatrix);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, Rgb>
where TTo : struct, IColorProfile<TTo, CieXyz>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<Rgb> pcsFromOwner = options.MemoryAllocator.Allocate<Rgb>(source.Length);
Span<Rgb> pcsFrom = pcsFromOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFrom);
// Convert between PCS.
using IMemoryOwner<CieXyz> pcsToOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsTo = pcsToOwner.GetSpan();
Rgb.ToProfileConnectionSpace(options, pcsFrom, pcsTo);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsTo, pcsTo, whitePoints, options.AdaptationMatrix);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsTo, destination);
}
}

57
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbRgb.cs

@ -0,0 +1,57 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsRgbRgb
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, Rgb>
where TTo : struct, IColorProfile<TTo, Rgb>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
Rgb pcsFromA = source.ToProfileConnectingSpace(options);
CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix);
// Convert between PCS
Rgb pcsTo = Rgb.FromProfileConnectingSpace(options, in pcsFromB);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, Rgb>
where TTo : struct, IColorProfile<TTo, Rgb>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<Rgb> pcsFromToOwner = options.MemoryAllocator.Allocate<Rgb>(source.Length);
Span<Rgb> pcsFromTo = pcsFromToOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFromTo);
using IMemoryOwner<CieXyz> pcsFromOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFrom = pcsFromOwner.GetSpan();
Rgb.ToProfileConnectionSpace(options, pcsFromTo, pcsFrom);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert between PCS.
Rgb.FromProfileConnectionSpace(options, pcsFrom, pcsFromTo);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsFromTo, destination);
}
}

182
src/ImageSharp/ColorProfiles/Companding/CompandingUtilities.cs

@ -0,0 +1,182 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Collections.Concurrent;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace SixLabors.ImageSharp.ColorProfiles.Companding;
/// <summary>
/// Companding utilities that allow the accelerated compression-expansion of color channels.
/// </summary>
public static class CompandingUtilities
{
private const int Length = Scale + 2; // 256kb @ 16bit precision.
private const int Scale = (1 << 16) - 1;
private static readonly ConcurrentDictionary<(Type, double), float[]> CompressLookupTables = new();
private static readonly ConcurrentDictionary<(Type, double), float[]> ExpandLookupTables = new();
/// <summary>
/// Lazily creates and stores a companding compression lookup table using the given function and modifier.
/// </summary>
/// <typeparam name="T">The type of companding function.</typeparam>
/// <param name="compandingFunction">The companding function.</param>
/// <param name="modifier">A modifier to pass to the function.</param>
/// <returns>The <see cref="float"/> array.</returns>
public static float[] GetCompressLookupTable<T>(Func<double, double, double> compandingFunction, double modifier = 0)
=> CompressLookupTables.GetOrAdd((typeof(T), modifier), args => CreateLookupTableImpl(compandingFunction, args.Item2));
/// <summary>
/// Lazily creates and stores a companding expanding lookup table using the given function and modifier.
/// </summary>
/// <typeparam name="T">The type of companding function.</typeparam>
/// <param name="compandingFunction">The companding function.</param>
/// <param name="modifier">A modifier to pass to the function.</param>
/// <returns>The <see cref="float"/> array.</returns>
public static float[] GetExpandLookupTable<T>(Func<double, double, double> compandingFunction, double modifier = 0)
=> ExpandLookupTables.GetOrAdd((typeof(T), modifier), args => CreateLookupTableImpl(compandingFunction, args.Item2));
/// <summary>
/// Creates a companding lookup table using the given function.
/// </summary>
/// <param name="compandingFunction">The companding function.</param>
/// <param name="modifier">A modifier to pass to the function.</param>
/// <returns>The <see cref="float"/> array.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float[] CreateLookupTableImpl(Func<double, double, double> compandingFunction, double modifier = 0)
{
float[] result = new float[Length];
for (int i = 0; i < result.Length; i++)
{
double d = (double)i / Scale;
d = compandingFunction(d, modifier);
result[i] = (float)d;
}
return result;
}
/// <summary>
/// Performs the companding operation on the given vectors using the given table.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
/// <param name="table">The lookup table.</param>
public static void Compand(Span<Vector4> vectors, float[] table)
{
DebugGuard.MustBeGreaterThanOrEqualTo(table.Length, Length, nameof(table));
if (Avx2.IsSupported && vectors.Length >= 2)
{
CompandAvx2(vectors, table);
if (Numerics.Modulo2(vectors.Length) != 0)
{
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
ref Vector4 last = ref MemoryMarshal.GetReference(vectors[^1..]);
last = Compand(last, table);
}
}
else
{
CompandScalar(vectors, table);
}
}
/// <summary>
/// Performs the companding operation on the given vector using the given table.
/// </summary>
/// <param name="vector">The vector.</param>
/// <param name="table">The lookup table.</param>
/// <returns>The <see cref="Vector4"/></returns>
public static Vector4 Compand(Vector4 vector, float[] table)
{
DebugGuard.MustBeGreaterThanOrEqualTo(table.Length, Length, nameof(table));
Vector4 zero = Vector4.Zero;
Vector4 scale = new(Scale);
Vector4 multiplied = Numerics.Clamp(vector * Scale, zero, scale);
float f0 = multiplied.X;
float f1 = multiplied.Y;
float f2 = multiplied.Z;
uint i0 = (uint)f0;
uint i1 = (uint)f1;
uint i2 = (uint)f2;
// Alpha is already a linear representation of opacity so we do not want to convert it.
vector.X = Numerics.Lerp(table[i0], table[i0 + 1], f0 - (int)i0);
vector.Y = Numerics.Lerp(table[i1], table[i1 + 1], f1 - (int)i1);
vector.Z = Numerics.Lerp(table[i2], table[i2 + 1], f2 - (int)i2);
return vector;
}
private static unsafe void CompandAvx2(Span<Vector4> vectors, float[] table)
{
fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
{
Vector256<float> scale = Vector256.Create((float)Scale);
Vector256<float> zero = Vector256<float>.Zero;
Vector256<int> offset = Vector256.Create(1);
// Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float>
ref Vector256<float> vectorsBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(vectors));
ref Vector256<float> vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length / 2u);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
{
Vector256<float> multiplied = Avx.Multiply(scale, vectorsBase);
multiplied = Avx.Min(Avx.Max(zero, multiplied), scale);
Vector256<int> truncated = Avx.ConvertToVector256Int32WithTruncation(multiplied);
Vector256<float> truncatedF = Avx.ConvertToVector256Single(truncated);
Vector256<float> low = Avx2.GatherVector256(tablePointer, truncated, sizeof(float));
Vector256<float> high = Avx2.GatherVector256(tablePointer, Avx2.Add(truncated, offset), sizeof(float));
// Alpha is already a linear representation of opacity so we do not want to convert it.
Vector256<float> companded = Numerics.Lerp(low, high, Avx.Subtract(multiplied, truncatedF));
vectorsBase = Avx.Blend(companded, vectorsBase, Numerics.BlendAlphaControl);
vectorsBase = ref Unsafe.Add(ref vectorsBase, 1);
}
}
}
private static unsafe void CompandScalar(Span<Vector4> vectors, float[] table)
{
fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
{
Vector4 zero = Vector4.Zero;
Vector4 scale = new(Scale);
ref Vector4 vectorsBase = ref MemoryMarshal.GetReference(vectors);
ref Vector4 vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
{
Vector4 multiplied = Numerics.Clamp(vectorsBase * Scale, zero, scale);
float f0 = multiplied.X;
float f1 = multiplied.Y;
float f2 = multiplied.Z;
uint i0 = (uint)f0;
uint i1 = (uint)f1;
uint i2 = (uint)f2;
// Alpha is already a linear representation of opacity so we do not want to convert it.
vectorsBase.X = Numerics.Lerp(tablePointer[i0], tablePointer[i0 + 1], f0 - (int)i0);
vectorsBase.Y = Numerics.Lerp(tablePointer[i1], tablePointer[i1 + 1], f1 - (int)i1);
vectorsBase.Z = Numerics.Lerp(tablePointer[i2], tablePointer[i2 + 1], f2 - (int)i2);
vectorsBase = ref Unsafe.Add(ref vectorsBase, 1);
}
}
}
}

56
src/ImageSharp/ColorProfiles/Companding/GammaCompanding.cs

@ -0,0 +1,56 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorProfiles.Companding;
/// <summary>
/// Implements gamma companding.
/// </summary>
/// <remarks>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public static class GammaCompanding
{
private static Func<double, double, double> CompressFunction => (d, m) => Math.Pow(d, 1 / m);
private static Func<double, double, double> ExpandFunction => Math.Pow;
/// <summary>
/// Compresses the linear vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
/// <param name="gamma">The gamma value.</param>
public static void Compress(Span<Vector4> vectors, double gamma)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable<GammaCompandingKey>(CompressFunction, gamma));
/// <summary>
/// Expands the nonlinear vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
/// <param name="gamma">The gamma value.</param>
public static void Expand(Span<Vector4> vectors, double gamma)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable<GammaCompandingKey>(ExpandFunction, gamma));
/// <summary>
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <param name="gamma">The gamma value.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Compress(Vector4 vector, double gamma)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable<GammaCompandingKey>(CompressFunction, gamma));
/// <summary>
/// Expands the nonlinear vector to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <param name="gamma">The gamma value.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Expand(Vector4 vector, double gamma)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable<GammaCompandingKey>(ExpandFunction, gamma));
private class GammaCompandingKey;
}

71
src/ImageSharp/ColorProfiles/Companding/LCompanding.cs

@ -0,0 +1,71 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorProfiles.Companding;
/// <summary>
/// Implements L* companding.
/// </summary>
/// <remarks>
/// For more info see:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public static class LCompanding
{
private static Func<double, double, double> CompressFunction
=> (d, _) =>
{
if (d <= CieConstants.Epsilon)
{
return (d * CieConstants.Kappa) / 100;
}
return (1.16 * Math.Pow(d, 0.3333333)) - 0.16;
};
private static Func<double, double, double> ExpandFunction
=> (d, _) =>
{
if (d <= 0.08)
{
return (100 * d) / CieConstants.Kappa;
}
return Numerics.Pow3(((float)(d + 0.16f)) / 1.16f);
};
/// <summary>
/// Compresses the linear vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Compress(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable<LCompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Expand(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable<LCompandingKey>(ExpandFunction));
/// <summary>
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Compress(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable<LCompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vector to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Expand(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable<LCompandingKey>(ExpandFunction));
private class LCompandingKey;
}

75
src/ImageSharp/ColorProfiles/Companding/Rec2020Companding.cs

@ -0,0 +1,75 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorProfiles.Companding;
/// <summary>
/// Implements Rec. 2020 companding function.
/// </summary>
/// <remarks>
/// <see href="http://en.wikipedia.org/wiki/Rec._2020"/>
/// </remarks>
public static class Rec2020Companding
{
private const double Alpha = 1.09929682680944;
private const double AlphaMinusOne = Alpha - 1;
private const double Beta = 0.018053968510807;
private const double InverseBeta = Beta * 4.5;
private const double Epsilon = 1 / 0.45;
private static Func<double, double, double> CompressFunction
=> (d, _) =>
{
if (d < Beta)
{
return 4.5 * d;
}
return (Alpha * Math.Pow(d, 0.45)) - AlphaMinusOne;
};
private static Func<double, double, double> ExpandFunction
=> (d, _) =>
{
if (d < InverseBeta)
{
return d / 4.5;
}
return Math.Pow((d + AlphaMinusOne) / Alpha, Epsilon);
};
/// <summary>
/// Compresses the linear vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Compress(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable<Rec2020CompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Expand(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable<Rec2020CompandingKey>(ExpandFunction));
/// <summary>
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Compress(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable<Rec2020CompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vector to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Expand(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable<Rec2020CompandingKey>(ExpandFunction));
private class Rec2020CompandingKey;
}

71
src/ImageSharp/ColorProfiles/Companding/Rec709Companding.cs

@ -0,0 +1,71 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorProfiles.Companding;
/// <summary>
/// Implements the Rec. 709 companding function.
/// </summary>
/// <remarks>
/// http://en.wikipedia.org/wiki/Rec._709
/// </remarks>
public static class Rec709Companding
{
private const double Epsilon = 1 / 0.45;
private static Func<double, double, double> CompressFunction
=> (d, _) =>
{
if (d < 0.018)
{
return 4.5 * d;
}
return (1.099 * Math.Pow(d, 0.45)) - 0.099;
};
private static Func<double, double, double> ExpandFunction
=> (d, _) =>
{
if (d < 0.081)
{
return d / 4.5;
}
return Math.Pow((d + 0.099) / 1.099, Epsilon);
};
/// <summary>
/// Compresses the linear vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Compress(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable<Rec2020CompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Expand(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable<Rec2020CompandingKey>(ExpandFunction));
/// <summary>
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Compress(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable<Rec2020CompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vector to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Expand(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable<Rec2020CompandingKey>(ExpandFunction));
private class Rec2020CompandingKey;
}

71
src/ImageSharp/ColorProfiles/Companding/SRgbCompanding.cs

@ -0,0 +1,71 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorProfiles.Companding;
/// <summary>
/// Implements sRGB companding.
/// </summary>
/// <remarks>
/// For more info see:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public static class SRgbCompanding
{
private static Func<double, double, double> CompressFunction
=> (d, _) =>
{
if (d <= (0.04045 / 12.92))
{
return d * 12.92;
}
return (1.055 * Math.Pow(d, 1.0 / 2.4)) - 0.055;
};
private static Func<double, double, double> ExpandFunction
=> (d, _) =>
{
if (d <= 0.04045)
{
return d / 12.92;
}
return Math.Pow((d + 0.055) / 1.055, 2.4);
};
/// <summary>
/// Compresses the linear vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Compress(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable<SRgbCompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Expand(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable<SRgbCompandingKey>(ExpandFunction));
/// <summary>
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Compress(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable<SRgbCompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vector to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Expand(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable<SRgbCompandingKey>(ExpandFunction));
private class SRgbCompandingKey;
}

245
src/ImageSharp/ColorProfiles/Hsl.cs

@ -0,0 +1,245 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents a Hsl (hue, saturation, lightness) color.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct Hsl : IColorProfile<Hsl, Rgb>
{
private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = new(360, 1, 1);
/// <summary>
/// Initializes a new instance of the <see cref="Hsl"/> struct.
/// </summary>
/// <param name="h">The h hue component.</param>
/// <param name="s">The s saturation component.</param>
/// <param name="l">The l value (lightness) component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Hsl(float h, float s, float l)
: this(new Vector3(h, s, l))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Hsl"/> struct.
/// </summary>
/// <param name="vector">The vector representing the h, s, l components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Hsl(Vector3 vector)
{
vector = Vector3.Clamp(vector, Min, Max);
this.H = vector.X;
this.S = vector.Y;
this.L = vector.Z;
}
/// <summary>
/// Gets the hue component.
/// <remarks>A value ranging between 0 and 360.</remarks>
/// </summary>
public float H { get; }
/// <summary>
/// Gets the saturation component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float S { get; }
/// <summary>
/// Gets the lightness component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float L { get; }
/// <summary>
/// Compares two <see cref="Hsl"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Hsl"/> on the left side of the operand.
/// </param>
/// <param name="right">The <see cref="Hsl"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Hsl left, Hsl right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Hsl"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="Hsl"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Hsl"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Hsl left, Hsl right) => !left.Equals(right);
/// <inheritdoc/>
public static Hsl FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source)
{
float r = source.R;
float g = source.G;
float b = source.B;
float max = MathF.Max(r, MathF.Max(g, b));
float min = MathF.Min(r, MathF.Min(g, b));
float chroma = max - min;
float h = 0F;
float s = 0F;
float l = (max + min) / 2F;
if (MathF.Abs(chroma) < Constants.Epsilon)
{
return new Hsl(0F, s, l);
}
if (MathF.Abs(r - max) < Constants.Epsilon)
{
h = (g - b) / chroma;
}
else if (MathF.Abs(g - max) < Constants.Epsilon)
{
h = 2F + ((b - r) / chroma);
}
else if (MathF.Abs(b - max) < Constants.Epsilon)
{
h = 4F + ((r - g) / chroma);
}
h *= 60F;
if (h < -Constants.Epsilon)
{
h += 360F;
}
if (l <= .5F)
{
s = chroma / (max + min);
}
else
{
s = chroma / (2F - max - min);
}
return new Hsl(h, s, l);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Rgb> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
Rgb rgb = source[i];
destination[i] = FromProfileConnectingSpace(options, in rgb);
}
}
/// <inheritdoc/>
public Rgb ToProfileConnectingSpace(ColorConversionOptions options)
{
float rangedH = this.H / 360F;
float r = 0;
float g = 0;
float b = 0;
float s = this.S;
float l = this.L;
if (MathF.Abs(l) > Constants.Epsilon)
{
if (MathF.Abs(s) < Constants.Epsilon)
{
r = g = b = l;
}
else
{
float temp2 = (l < .5F) ? l * (1F + s) : l + s - (l * s);
float temp1 = (2F * l) - temp2;
r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F);
g = GetColorComponent(temp1, temp2, rangedH);
b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F);
}
}
return new Rgb(r, g, b);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Hsl> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
Hsl hsl = source[i];
destination[i] = hsl.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.RgbWorkingSpace;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.L);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is Hsl other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Hsl other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<Hsl, Vector3>(ref Unsafe.AsRef(in this));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float GetColorComponent(float first, float second, float third)
{
third = MoveIntoRange(third);
if (third < 0.1666667F)
{
return first + ((second - first) * 6F * third);
}
if (third < .5F)
{
return second;
}
if (third < 0.6666667F)
{
return first + ((second - first) * (0.6666667F - third) * 6F);
}
return first;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float MoveIntoRange(float value)
{
if (value < 0F)
{
value++;
}
else if (value > 1F)
{
value--;
}
return value;
}
}

231
src/ImageSharp/ColorProfiles/Hsv.cs

@ -0,0 +1,231 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness).
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct Hsv : IColorProfile<Hsv, Rgb>
{
private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = new(360, 1, 1);
/// <summary>
/// Initializes a new instance of the <see cref="Hsv"/> struct.
/// </summary>
/// <param name="h">The h hue component.</param>
/// <param name="s">The s saturation component.</param>
/// <param name="v">The v value (brightness) component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Hsv(float h, float s, float v)
: this(new Vector3(h, s, v))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Hsv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the h, s, v components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Hsv(Vector3 vector)
{
vector = Vector3.Clamp(vector, Min, Max);
this.H = vector.X;
this.S = vector.Y;
this.V = vector.Z;
}
/// <summary>
/// Gets the hue component.
/// <remarks>A value ranging between 0 and 360.</remarks>
/// </summary>
public float H { get; }
/// <summary>
/// Gets the saturation component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float S { get; }
/// <summary>
/// Gets the value (brightness) component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float V { get; }
/// <summary>
/// Compares two <see cref="Hsv"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Hsv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Hsv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Hsv left, Hsv right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Hsv"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="Hsv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Hsv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Hsv left, Hsv right) => !left.Equals(right);
/// <inheritdoc/>
public static Hsv FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source)
{
float r = source.R;
float g = source.G;
float b = source.B;
float max = MathF.Max(r, MathF.Max(g, b));
float min = MathF.Min(r, MathF.Min(g, b));
float chroma = max - min;
float h = 0;
float s = 0;
float v = max;
if (MathF.Abs(chroma) < Constants.Epsilon)
{
return new Hsv(0, s, v);
}
if (MathF.Abs(r - max) < Constants.Epsilon)
{
h = (g - b) / chroma;
}
else if (MathF.Abs(g - max) < Constants.Epsilon)
{
h = 2 + ((b - r) / chroma);
}
else if (MathF.Abs(b - max) < Constants.Epsilon)
{
h = 4 + ((r - g) / chroma);
}
h *= 60F;
if (h < -Constants.Epsilon)
{
h += 360F;
}
s = chroma / v;
return new Hsv(h, s, v);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Rgb> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
Rgb rgb = source[i];
destination[i] = FromProfileConnectingSpace(options, in rgb);
}
}
/// <inheritdoc/>
public Rgb ToProfileConnectingSpace(ColorConversionOptions options)
{
float s = this.S;
float v = this.V;
if (MathF.Abs(s) < Constants.Epsilon)
{
return new Rgb(v, v, v);
}
float h = (MathF.Abs(this.H - 360) < Constants.Epsilon) ? 0 : this.H / 60;
int i = (int)Math.Truncate(h);
float f = h - i;
float p = v * (1F - s);
float q = v * (1F - (s * f));
float t = v * (1F - (s * (1F - f)));
float r, g, b;
switch (i)
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
default:
r = v;
g = p;
b = q;
break;
}
return new Rgb(r, g, b);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Hsv> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
Hsv hsv = source[i];
destination[i] = hsv.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.RgbWorkingSpace;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.V);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is Hsv other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Hsv other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<Hsv, Vector3>(ref Unsafe.AsRef(in this));
}

200
src/ImageSharp/ColorProfiles/HunterLab.cs

@ -0,0 +1,200 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents an Hunter LAB color.
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space"/>.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct HunterLab : IColorProfile<HunterLab, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="HunterLab"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="a">The a (green - magenta) component.</param>
/// <param name="b">The b (blue - yellow) component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public HunterLab(float l, float a, float b)
{
this.L = l;
this.A = a;
this.B = b;
}
/// <summary>
/// Initializes a new instance of the <see cref="HunterLab"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l a b components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public HunterLab(Vector3 vector)
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.L = vector.X;
this.A = vector.Y;
this.B = vector.Z;
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public float L { get; }
/// <summary>
/// Gets the a color component.
/// <remarks>A value usually ranging from -100 to 100. Negative is green, positive magenta.</remarks>
/// </summary>
public float A { get; }
/// <summary>
/// Gets the b color component.
/// <remarks>A value usually ranging from -100 to 100. Negative is blue, positive is yellow</remarks>
/// </summary>
public float B { get; }
/// <summary>
/// Compares two <see cref="HunterLab"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="HunterLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="HunterLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(HunterLab left, HunterLab right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="HunterLab"/> objects for inequality
/// </summary>
/// <param name="left">The <see cref="HunterLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="HunterLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(HunterLab left, HunterLab right) => !left.Equals(right);
/// <inheritdoc/>
public static HunterLab FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
// Conversion algorithm described here:
// http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab
CieXyz whitePoint = options.TargetWhitePoint;
float x = source.X, y = source.Y, z = source.Z;
float xn = whitePoint.X, yn = whitePoint.Y, zn = whitePoint.Z;
float ka = ComputeKa(in whitePoint);
float kb = ComputeKb(in whitePoint);
float yByYn = y / yn;
float sqrtYbyYn = MathF.Sqrt(yByYn);
float l = 100 * sqrtYbyYn;
float a = ka * (((x / xn) - yByYn) / sqrtYbyYn);
float b = kb * ((yByYn - (z / zn)) / sqrtYbyYn);
if (float.IsNaN(a))
{
a = 0;
}
if (float.IsNaN(b))
{
b = 0;
}
return new HunterLab(l, a, b);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyz xyz = source[i];
destination[i] = FromProfileConnectingSpace(options, in xyz);
}
}
/// <inheritdoc/>
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
// Conversion algorithm described here:
// http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab
CieXyz whitePoint = options.WhitePoint;
float l = this.L, a = this.A, b = this.B;
float xn = whitePoint.X, yn = whitePoint.Y, zn = whitePoint.Z;
float ka = ComputeKa(in whitePoint);
float kb = ComputeKb(in whitePoint);
float pow = Numerics.Pow2(l / 100F);
float sqrtPow = MathF.Sqrt(pow);
float y = pow * yn;
float x = (((a / ka) * sqrtPow) + pow) * xn;
float z = (((b / kb) * sqrtPow) - pow) * (-zn);
return new CieXyz(x, y, z);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<HunterLab> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
HunterLab lab = source[i];
destination[i] = lab.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is HunterLab other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(HunterLab other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<HunterLab, Vector3>(ref Unsafe.AsRef(in this));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ComputeKa(in CieXyz whitePoint)
{
if (whitePoint.Equals(KnownIlluminants.C))
{
return 175F;
}
return 100F * (175F / 198.04F) * (whitePoint.X + whitePoint.Y);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ComputeKb(in CieXyz whitePoint)
{
if (whitePoint == KnownIlluminants.C)
{
return 70F;
}
return 100F * (70F / 218.11F) * (whitePoint.Y + whitePoint.Z);
}
}

59
src/ImageSharp/ColorProfiles/IColorProfile.cs

@ -0,0 +1,59 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Defines the contract for all color profiles.
/// </summary>
public interface IColorProfile
{
/// <summary>
/// Gets the chromatic adaption white point source.
/// </summary>
/// <returns>The <see cref="ChromaticAdaptionWhitePointSource"/>.</returns>
public static abstract ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource();
}
/// <summary>
/// Defines the contract for all color profiles.
/// </summary>
/// <typeparam name="TSelf">The type of color profile.</typeparam>
/// <typeparam name="TProfileSpace">The type of color profile connecting space.</typeparam>
public interface IColorProfile<TSelf, TProfileSpace> : IColorProfile, IEquatable<TSelf>
where TSelf : IColorProfile<TSelf, TProfileSpace>
where TProfileSpace : struct, IProfileConnectingSpace
{
#pragma warning disable CA1000 // Do not declare static members on generic types
/// <summary>
/// Converts the color from the profile connection space.
/// </summary>
/// <param name="options">The color profile conversion options.</param>
/// <param name="source">The color profile connecting space.</param>
/// <returns>The <typeparamref name="TSelf"/>.</returns>
public static abstract TSelf FromProfileConnectingSpace(ColorConversionOptions options, in TProfileSpace source);
/// <summary>
/// Converts the span of colors from the profile connection space.
/// </summary>
/// <param name="options">The color profile conversion options.</param>
/// <param name="source">The color profile span to convert from.</param>
/// <param name="destination">The color span to write the results to.</param>
public static abstract void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<TProfileSpace> source, Span<TSelf> destination);
/// <summary>
/// Converts the color to the profile connection space.
/// </summary>
/// <param name="options">The color profile conversion options.</param>
/// <returns>The <typeparamref name="TProfileSpace"/>.</returns>
public TProfileSpace ToProfileConnectingSpace(ColorConversionOptions options);
/// <summary>
/// Converts the span of colors to the profile connection space.
/// </summary>
/// <param name="options">The color profile conversion options.</param>
/// <param name="source">The color span to convert from.</param>
/// <param name="destination">The color profile span to write the results to.</param>
public static abstract void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<TSelf> source, Span<TProfileSpace> destination);
#pragma warning restore CA1000 // Do not declare static members on generic types
}

18
src/ImageSharp/ColorProfiles/IProfileConnectingSpace.cs

@ -0,0 +1,18 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Defines the contract for all color profile connection spaces.
/// </summary>
public interface IProfileConnectingSpace;
/// <summary>
/// Defines the contract for all color profile connection spaces.
/// </summary>
/// <typeparam name="TSelf">The type of color profile.</typeparam>
/// <typeparam name="TProfileSpace">The type of color profile connecting space.</typeparam>
public interface IProfileConnectingSpace<TSelf, TProfileSpace> : IColorProfile<TSelf, TProfileSpace>, IProfileConnectingSpace
where TSelf : struct, IColorProfile<TSelf, TProfileSpace>, IProfileConnectingSpace
where TProfileSpace : struct, IProfileConnectingSpace;

24
src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs → src/ImageSharp/ColorProfiles/KnownChromaticAdaptationMatrices.cs

@ -3,23 +3,25 @@
using System.Numerics;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Matrices used for transformation from <see cref="CieXyz"/> to <see cref="Lms"/>, defining the cone response domain.
/// Used in <see cref="IChromaticAdaptation"/>
/// Provides matrices for chromatic adaptation, facilitating the adjustment of color values
/// under different light sources to maintain color constancy. This class supports common
/// adaptation transforms based on the von Kries coefficient law, which assumes independent
/// scaling of the cone responses in the human eye. These matrices can be applied to convert
/// color coordinates between different illuminants, ensuring consistent color appearance
/// across various lighting conditions.
/// </summary>
/// <remarks>
/// Matrix data obtained from:
/// Two New von Kries Based Chromatic Adaptation Transforms Found by Numerical Optimization
/// S. Bianco, R. Schettini
/// DISCo, Department of Informatics, Systems and Communication, University of Milan-Bicocca, viale Sarca 336, 20126 Milan, Italy
/// https://web.stanford.edu/~sujason/ColorBalancing/Papers/Two%20New%20von%20Kries%20Based%20Chromatic%20Adaptation.pdf
/// Supported adaptation matrices include the Bradford, von Kries, and Sharp transforms.
/// These matrices are typically used in conjunction with color space conversions, such as from XYZ
/// to RGB, to achieve accurate color rendition in digital imaging applications.
/// </remarks>
public static class LmsAdaptationMatrix
public static class KnownChromaticAdaptationMatrices
{
/// <summary>
/// Von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez adjusted for D65)
/// von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez adjusted for D65)
/// </summary>
public static readonly Matrix4x4 VonKriesHPEAdjusted
= Matrix4x4.Transpose(new Matrix4x4
@ -37,7 +39,7 @@ public static class LmsAdaptationMatrix
});
/// <summary>
/// Von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez for equal energy)
/// von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez for equal energy)
/// </summary>
public static readonly Matrix4x4 VonKriesHPE
= Matrix4x4.Transpose(new Matrix4x4

71
src/ImageSharp/ColorProfiles/KnownIlluminants.cs

@ -0,0 +1,71 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// The well known standard illuminants.
/// Standard illuminants provide a basis for comparing images or colors recorded under different lighting
/// </summary>
/// <remarks>
/// Coefficients taken from: http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
/// <br />
/// Descriptions taken from: http://en.wikipedia.org/wiki/Standard_illuminant
/// </remarks>
public static class KnownIlluminants
{
/// <summary>
/// Gets the Incandescent / Tungsten illuminant.
/// </summary>
public static CieXyz A { get; } = new(1.09850F, 1F, 0.35585F);
/// <summary>
/// Gets the Direct sunlight at noon (obsoleteF) illuminant.
/// </summary>
public static CieXyz B { get; } = new(0.99072F, 1F, 0.85223F);
/// <summary>
/// Gets the Average / North sky Daylight (obsoleteF) illuminant.
/// </summary>
public static CieXyz C { get; } = new(0.98074F, 1F, 1.18232F);
/// <summary>
/// Gets the Horizon Light. ICC profile PCS illuminant.
/// </summary>
public static CieXyz D50 { get; } = new(0.96422F, 1F, 0.82521F);
/// <summary>
/// Gets the Mid-morning / Mid-afternoon Daylight illuminant.
/// </summary>
public static CieXyz D55 { get; } = new(0.95682F, 1F, 0.92149F);
/// <summary>
/// Gets the Noon Daylight: TelevisionF, sRGB color space illuminant.
/// </summary>
public static CieXyz D65 { get; } = new(0.95047F, 1F, 1.08883F);
/// <summary>
/// Gets the North sky Daylight illuminant.
/// </summary>
public static CieXyz D75 { get; } = new(0.94972F, 1F, 1.22638F);
/// <summary>
/// Gets the Equal energy illuminant.
/// </summary>
public static CieXyz E { get; } = new(1F, 1F, 1F);
/// <summary>
/// Gets the Cool White Fluorescent illuminant.
/// </summary>
public static CieXyz F2 { get; } = new(0.99186F, 1F, 0.67393F);
/// <summary>
/// Gets the D65 simulatorF, Daylight simulator illuminant.
/// </summary>
public static CieXyz F7 { get; } = new(0.95041F, 1F, 1.08747F);
/// <summary>
/// Gets the Philips TL84F, Ultralume 40 illuminant.
/// </summary>
public static CieXyz F11 { get; } = new(1.00962F, 1F, 0.64350F);
}

113
src/ImageSharp/ColorProfiles/KnownRgbWorkingSpaces.cs

@ -0,0 +1,113 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.ColorProfiles.Companding;
using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Chromaticity coordinates based on: <see href="http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html"/>
/// </summary>
public static class KnownRgbWorkingSpaces
{
/// <summary>
/// sRgb working space.
/// </summary>
/// <remarks>
/// Uses proper companding function, according to:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_Rgb_to_XYZ.html"/>
/// </remarks>
public static readonly RgbWorkingSpace SRgb = new SRgbWorkingSpace(KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
/// <summary>
/// Simplified sRgb working space (uses <see cref="GammaCompanding">gamma companding</see> instead of <see cref="SRgbCompanding"/>).
/// See also <see cref="SRgb"/>.
/// </summary>
public static readonly RgbWorkingSpace SRgbSimplified = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
/// <summary>
/// Rec. 709 (ITU-R Recommendation BT.709) working space.
/// </summary>
public static readonly RgbWorkingSpace Rec709 = new Rec709WorkingSpace(KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.64F, 0.33F), new CieXyChromaticityCoordinates(0.30F, 0.60F), new CieXyChromaticityCoordinates(0.15F, 0.06F)));
/// <summary>
/// Rec. 2020 (ITU-R Recommendation BT.2020F) working space.
/// </summary>
public static readonly RgbWorkingSpace Rec2020 = new Rec2020WorkingSpace(KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.708F, 0.292F), new CieXyChromaticityCoordinates(0.170F, 0.797F), new CieXyChromaticityCoordinates(0.131F, 0.046F)));
/// <summary>
/// ECI Rgb v2 working space.
/// </summary>
public static readonly RgbWorkingSpace ECIRgbv2 = new LWorkingSpace(KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F)));
/// <summary>
/// Adobe Rgb (1998) working space.
/// </summary>
public static readonly RgbWorkingSpace AdobeRgb1998 = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
/// <summary>
/// Apple sRgb working space.
/// </summary>
public static readonly RgbWorkingSpace ApplesRgb = new GammaWorkingSpace(1.8F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6250F, 0.3400F), new CieXyChromaticityCoordinates(0.2800F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F)));
/// <summary>
/// Best Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace BestRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.2150F, 0.7750F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F)));
/// <summary>
/// Beta Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace BetaRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6888F, 0.3112F), new CieXyChromaticityCoordinates(0.1986F, 0.7551F), new CieXyChromaticityCoordinates(0.1265F, 0.0352F)));
/// <summary>
/// Bruce Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace BruceRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2800F, 0.6500F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
/// <summary>
/// CIE Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace CIERgb = new GammaWorkingSpace(2.2F, KnownIlluminants.E, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.2740F, 0.7170F), new CieXyChromaticityCoordinates(0.1670F, 0.0090F)));
/// <summary>
/// ColorMatch Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace ColorMatchRgb = new GammaWorkingSpace(1.8F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.2950F, 0.6050F), new CieXyChromaticityCoordinates(0.1500F, 0.0750F)));
/// <summary>
/// Don Rgb 4 working space.
/// </summary>
public static readonly RgbWorkingSpace DonRgb4 = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6960F, 0.3000F), new CieXyChromaticityCoordinates(0.2150F, 0.7650F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F)));
/// <summary>
/// Ekta Space PS5 working space.
/// </summary>
public static readonly RgbWorkingSpace EktaSpacePS5 = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6950F, 0.3050F), new CieXyChromaticityCoordinates(0.2600F, 0.7000F), new CieXyChromaticityCoordinates(0.1100F, 0.0050F)));
/// <summary>
/// NTSC Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace NTSCRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.C, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F)));
/// <summary>
/// PAL/SECAM Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace PALSECAMRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2900F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
/// <summary>
/// ProPhoto Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace ProPhotoRgb = new GammaWorkingSpace(1.8F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.1596F, 0.8404F), new CieXyChromaticityCoordinates(0.0366F, 0.0001F)));
/// <summary>
/// SMPTE-C Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace SMPTECRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.3100F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F)));
/// <summary>
/// Wide Gamut Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace WideGamutRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.1150F, 0.8260F), new CieXyChromaticityCoordinates(0.1570F, 0.0180F)));
}

75
src/ImageSharp/ColorSpaces/Lms.cs → src/ImageSharp/ColorProfiles/Lms.cs

@ -3,15 +3,17 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// LMS is a color space represented by the response of the three types of cones of the human eye,
/// named after their responsivity (sensitivity) at long, medium and short wavelengths.
/// <see href="https://en.wikipedia.org/wiki/LMS_color_space"/>
/// </summary>
public readonly struct Lms : IEquatable<Lms>
[StructLayout(LayoutKind.Sequential)]
public readonly struct Lms : IColorProfile<Lms, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="Lms"/> struct.
@ -19,17 +21,19 @@ public readonly struct Lms : IEquatable<Lms>
/// <param name="l">L represents the responsivity at long wavelengths.</param>
/// <param name="m">M represents the responsivity at medium wavelengths.</param>
/// <param name="s">S represents the responsivity at short wavelengths.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Lms(float l, float m, float s)
: this(new Vector3(l, m, s))
{
this.L = l;
this.M = m;
this.S = s;
}
/// <summary>
/// Initializes a new instance of the <see cref="Lms"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, m, s components.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Lms(Vector3 vector)
{
// Not clamping as documentation about this space only indicates "usual" ranges
@ -42,19 +46,19 @@ public readonly struct Lms : IEquatable<Lms>
/// Gets the L long component.
/// <remarks>A value usually ranging between -1 and 1.</remarks>
/// </summary>
public readonly float L { get; }
public float L { get; }
/// <summary>
/// Gets the M medium component.
/// <remarks>A value usually ranging between -1 and 1.</remarks>
/// </summary>
public readonly float M { get; }
public float M { get; }
/// <summary>
/// Gets the S short component.
/// <remarks>A value usually ranging between -1 and 1.</remarks>
/// </summary>
public readonly float S { get; }
public float S { get; }
/// <summary>
/// Compares two <see cref="Lms"/> objects for equality.
@ -64,7 +68,7 @@ public readonly struct Lms : IEquatable<Lms>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Lms left, Lms right) => left.Equals(right);
/// <summary>
@ -75,16 +79,57 @@ public readonly struct Lms : IEquatable<Lms>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Lms left, Lms right) => !left.Equals(right);
/// <summary>
/// Returns a new <see cref="Vector3"/> representing this instance.
/// </summary>
/// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 ToVector3() => new(this.L, this.M, this.S);
/// <inheritdoc/>
public static Lms FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
Vector3 vector = Vector3.Transform(source.ToVector3(), options.AdaptationMatrix);
return new Lms(vector);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyz xyz = source[i];
destination[i] = FromProfileConnectingSpace(options, in xyz);
}
}
/// <inheritdoc/>
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
Vector3 vector = Vector3.Transform(this.ToVector3(), options.InverseAdaptationMatrix);
return new CieXyz(vector);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Lms> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
Lms lms = source[i];
destination[i] = lms.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.L, this.M, this.S);
@ -95,9 +140,9 @@ public readonly struct Lms : IEquatable<Lms>
public override bool Equals(object? obj) => obj is Lms other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Lms other)
=> this.L.Equals(other.L)
&& this.M.Equals(other.M)
&& this.S.Equals(other.S);
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<Lms, Vector3>(ref Unsafe.AsRef(in this));
}

269
src/ImageSharp/ColorProfiles/Rgb.cs

@ -0,0 +1,269 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents an RGB (red, green, blue) color profile.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct Rgb : IProfileConnectingSpace<Rgb, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="Rgb"/> struct.
/// </summary>
/// <param name="r">The red component usually ranging between 0 and 1.</param>
/// <param name="g">The green component usually ranging between 0 and 1.</param>
/// <param name="b">The blue component usually ranging between 0 and 1.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgb(float r, float g, float b)
{
// Not clamping as this space can exceed "usual" ranges
this.R = r;
this.G = g;
this.B = b;
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgb"/> struct.
/// </summary>
/// <param name="source">The vector representing the r, g, b components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgb(Vector3 source)
{
this.R = source.X;
this.G = source.Y;
this.B = source.Z;
}
/// <summary>
/// Gets the red component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public float R { get; }
/// <summary>
/// Gets the green component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public float G { get; }
/// <summary>
/// Gets the blue component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public float B { get; }
/// <summary>
/// Compares two <see cref="Rgb"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Rgb"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rgb"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Rgb left, Rgb right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Rgb"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="Rgb"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rgb"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Rgb left, Rgb right) => !left.Equals(right);
/// <inheritdoc/>
public static Rgb FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
// Convert to linear rgb then compress.
Rgb linear = new(Vector3.Transform(source.ToVector3(), GetCieXyzToRgbMatrix(options.TargetRgbWorkingSpace)));
return FromScaledVector4(options.TargetRgbWorkingSpace.Compress(linear.ToScaledVector4()));
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
Matrix4x4 matrix = GetCieXyzToRgbMatrix(options.TargetRgbWorkingSpace);
for (int i = 0; i < source.Length; i++)
{
// Convert to linear rgb then compress.
Rgb linear = new(Vector3.Transform(source[i].ToVector3(), matrix));
Vector4 nonlinear = options.TargetRgbWorkingSpace.Compress(linear.ToScaledVector4());
destination[i] = FromScaledVector4(nonlinear);
}
}
/// <inheritdoc/>
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
// First expand to linear rgb
Rgb linear = FromScaledVector4(options.RgbWorkingSpace.Expand(this.ToScaledVector4()));
// Then convert to xyz
return new CieXyz(Vector3.Transform(linear.ToScaledVector3(), GetRgbToCieXyzMatrix(options.RgbWorkingSpace)));
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Rgb> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
Matrix4x4 matrix = GetRgbToCieXyzMatrix(options.RgbWorkingSpace);
for (int i = 0; i < source.Length; i++)
{
Rgb rgb = source[i];
// First expand to linear rgb
Rgb linear = FromScaledVector4(options.RgbWorkingSpace.Expand(rgb.ToScaledVector4()));
// Then convert to xyz
destination[i] = new CieXyz(Vector3.Transform(linear.ToScaledVector3(), matrix));
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.RgbWorkingSpace;
/// <summary>
/// Initializes the color instance from a generic scaled <see cref="Vector3"/>.
/// </summary>
/// <param name="source">The vector to load the color from.</param>
/// <returns>The <see cref="Rgb"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Rgb FromScaledVector3(Vector3 source) => new(Vector3.Clamp(source, Vector3.Zero, Vector3.One));
/// <summary>
/// Initializes the color instance from a generic scaled <see cref="Vector4"/>.
/// </summary>
/// <param name="source">The vector to load the color from.</param>
/// <returns>The <see cref="Rgb"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Rgb FromScaledVector4(Vector4 source)
{
source = Vector4.Clamp(source, Vector4.Zero, Vector4.One);
return new(source.X, source.Y, source.Z);
}
/// <summary>
/// Initializes the color instance for a source clamped between <value>0</value> and <value>1</value>
/// </summary>
/// <param name="source">The source to load the color from.</param>
/// <returns>The <see cref="Rgb"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Rgb Clamp(Rgb source) => new(Vector3.Clamp(new(source.R, source.G, source.B), Vector3.Zero, Vector3.One));
/// <summary>
/// Expands the color into a generic ("scaled") <see cref="Vector3"/> representation
/// with values scaled and usually clamped between <value>0</value> and <value>1</value>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 ToScaledVector3() => Clamp(this).ToVector3();
/// <summary>
/// Expands the color into a generic <see cref="Vector3"/> representation.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 ToVector3() => new(this.R, this.G, this.B);
/// <summary>
/// Expands the color into a generic ("scaled") <see cref="Vector4"/> representation
/// with values scaled and usually clamped between <value>0</value> and <value>1</value>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector4"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4() => new(this.ToScaledVector3(), 1f);
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Rgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is Rgb other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Rgb other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<Rgb, Vector3>(ref Unsafe.AsRef(in this));
private static Matrix4x4 GetCieXyzToRgbMatrix(RgbWorkingSpace workingSpace)
{
Matrix4x4 matrix = GetRgbToCieXyzMatrix(workingSpace);
Matrix4x4.Invert(matrix, out Matrix4x4 inverseMatrix);
return inverseMatrix;
}
private static Matrix4x4 GetRgbToCieXyzMatrix(RgbWorkingSpace workingSpace)
{
DebugGuard.NotNull(workingSpace, nameof(workingSpace));
RgbPrimariesChromaticityCoordinates chromaticity = workingSpace.ChromaticityCoordinates;
float xr = chromaticity.R.X;
float xg = chromaticity.G.X;
float xb = chromaticity.B.X;
float yr = chromaticity.R.Y;
float yg = chromaticity.G.Y;
float yb = chromaticity.B.Y;
float mXr = xr / yr;
float mZr = (1 - xr - yr) / yr;
float mXg = xg / yg;
float mZg = (1 - xg - yg) / yg;
float mXb = xb / yb;
float mZb = (1 - xb - yb) / yb;
Matrix4x4 xyzMatrix = new()
{
M11 = mXr,
M21 = mXg,
M31 = mXb,
M12 = 1F,
M22 = 1F,
M32 = 1F,
M13 = mZr,
M23 = mZg,
M33 = mZb,
M44 = 1F
};
Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix);
Vector3 vector = Vector3.Transform(workingSpace.WhitePoint.ToVector3(), inverseXyzMatrix);
// Use transposed Rows/Columns
return new Matrix4x4
{
M11 = vector.X * mXr,
M21 = vector.Y * mXg,
M31 = vector.Z * mXb,
M12 = vector.X,
M22 = vector.Y,
M32 = vector.Z,
M13 = vector.X * mZr,
M23 = vector.Y * mZg,
M33 = vector.Z * mZb,
M44 = 1F
};
}
}

20
src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs → src/ImageSharp/ColorProfiles/RgbPrimariesChromaticityCoordinates.cs

@ -1,7 +1,9 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents the chromaticity coordinates of RGB primaries.
@ -50,9 +52,7 @@ public readonly struct RgbPrimariesChromaticityCoordinates : IEquatable<RgbPrima
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(RgbPrimariesChromaticityCoordinates left, RgbPrimariesChromaticityCoordinates right)
{
return left.Equals(right);
}
=> left.Equals(right);
/// <summary>
/// Compares two <see cref="RgbPrimariesChromaticityCoordinates"/> objects for inequality
@ -67,21 +67,15 @@ public readonly struct RgbPrimariesChromaticityCoordinates : IEquatable<RgbPrima
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(RgbPrimariesChromaticityCoordinates left, RgbPrimariesChromaticityCoordinates right)
{
return !left.Equals(right);
}
=> !left.Equals(right);
/// <inheritdoc/>
public override bool Equals(object? obj)
{
return obj is RgbPrimariesChromaticityCoordinates other && this.Equals(other);
}
=> obj is RgbPrimariesChromaticityCoordinates other && this.Equals(other);
/// <inheritdoc/>
public bool Equals(RgbPrimariesChromaticityCoordinates other)
{
return this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B);
}
=> this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B);
/// <inheritdoc />
public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B);

95
src/ImageSharp/ColorProfiles/VonKriesChromaticAdaptation.cs

@ -0,0 +1,95 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Implementation of the Von Kries chromatic adaptation model.
/// </summary>
/// <remarks>
/// Transformation described here:
/// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
/// </remarks>
public static class VonKriesChromaticAdaptation
{
/// <summary>
/// Performs a linear transformation of a source color in to the destination color.
/// </summary>
/// <remarks>Doesn't crop the resulting color space coordinates (e.g. allows negative values for XYZ coordinates).</remarks>
/// <param name="source">The source color.</param>
/// <param name="whitePoints">The conversion white points.</param>
/// <param name="matrix">The chromatic adaptation matrix.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public static CieXyz Transform(in CieXyz source, (CieXyz From, CieXyz To) whitePoints, Matrix4x4 matrix)
{
CieXyz from = whitePoints.From;
CieXyz to = whitePoints.To;
if (from.Equals(to))
{
return new(source.X, source.Y, source.Z);
}
Vector3 sourceColorLms = Vector3.Transform(source.ToVector3(), matrix);
Vector3 sourceWhitePointLms = Vector3.Transform(from.ToVector3(), matrix);
Vector3 targetWhitePointLms = Vector3.Transform(to.ToVector3(), matrix);
Vector3 vector = targetWhitePointLms / sourceWhitePointLms;
Vector3 targetColorLms = Vector3.Multiply(vector, sourceColorLms);
Matrix4x4.Invert(matrix, out Matrix4x4 inverseMatrix);
return new CieXyz(Vector3.Transform(targetColorLms, inverseMatrix));
}
/// <summary>
/// Performs a bulk linear transformation of a source color in to the destination color.
/// </summary>
/// <remarks>Doesn't crop the resulting color space coordinates (e. g. allows negative values for XYZ coordinates).</remarks>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
/// <param name="whitePoints">The conversion white points.</param>
/// <param name="matrix">The chromatic adaptation matrix.</param>
public static void Transform(
ReadOnlySpan<CieXyz> source,
Span<CieXyz> destination,
(CieXyz From, CieXyz To) whitePoints,
Matrix4x4 matrix)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
CieXyz from = whitePoints.From;
CieXyz to = whitePoints.To;
if (from.Equals(to))
{
source.CopyTo(destination[..count]);
return;
}
Matrix4x4.Invert(matrix, out Matrix4x4 inverseMatrix);
ref CieXyz sourceBase = ref MemoryMarshal.GetReference(source);
ref CieXyz destinationBase = ref MemoryMarshal.GetReference(destination);
Vector3 sourceWhitePointLms = Vector3.Transform(from.ToVector3(), matrix);
Vector3 targetWhitePointLms = Vector3.Transform(to.ToVector3(), matrix);
Vector3 vector = targetWhitePointLms / sourceWhitePointLms;
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceBase, i);
ref CieXyz dp = ref Unsafe.Add(ref destinationBase, i);
Vector3 sourceColorLms = Vector3.Transform(sp.ToVector3(), matrix);
Vector3 targetColorLms = Vector3.Multiply(vector, sourceColorLms);
dp = new CieXyz(Vector3.Transform(targetColorLms, inverseMatrix));
}
}
}

18
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs → src/ImageSharp/ColorProfiles/WorkingSpaces/GammaWorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
using System.Numerics;
using SixLabors.ImageSharp.ColorProfiles.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
/// <summary>
/// The gamma working space.
@ -26,12 +26,16 @@ public sealed class GammaWorkingSpace : RgbWorkingSpace
public float Gamma { get; }
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Compress(float channel) => GammaCompanding.Compress(channel, this.Gamma);
public override void Compress(Span<Vector4> vectors) => GammaCompanding.Compress(vectors, this.Gamma);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Expand(float channel) => GammaCompanding.Expand(channel, this.Gamma);
public override void Expand(Span<Vector4> vectors) => GammaCompanding.Expand(vectors, this.Gamma);
/// <inheritdoc/>
public override Vector4 Compress(Vector4 vector) => GammaCompanding.Compress(vector, this.Gamma);
/// <inheritdoc/>
public override Vector4 Expand(Vector4 vector) => GammaCompanding.Expand(vector, this.Gamma);
/// <inheritdoc/>
public override bool Equals(object? obj)

18
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs → src/ImageSharp/ColorProfiles/WorkingSpaces/LWorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
using System.Numerics;
using SixLabors.ImageSharp.ColorProfiles.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
/// <summary>
/// L* working space.
@ -22,10 +22,14 @@ public sealed class LWorkingSpace : RgbWorkingSpace
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Compress(float channel) => LCompanding.Compress(channel);
public override void Compress(Span<Vector4> vectors) => LCompanding.Compress(vectors);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Expand(float channel) => LCompanding.Expand(channel);
public override void Expand(Span<Vector4> vectors) => LCompanding.Expand(vectors);
/// <inheritdoc/>
public override Vector4 Compress(Vector4 vector) => LCompanding.Compress(vector);
/// <inheritdoc/>
public override Vector4 Expand(Vector4 vector) => LCompanding.Expand(vector);
}

18
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs → src/ImageSharp/ColorProfiles/WorkingSpaces/Rec2020WorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
using System.Numerics;
using SixLabors.ImageSharp.ColorProfiles.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
/// <summary>
/// Rec. 2020 (ITU-R Recommendation BT.2020F) working space.
@ -22,10 +22,14 @@ public sealed class Rec2020WorkingSpace : RgbWorkingSpace
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Compress(float channel) => Rec2020Companding.Compress(channel);
public override void Compress(Span<Vector4> vectors) => Rec2020Companding.Compress(vectors);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Expand(float channel) => Rec2020Companding.Expand(channel);
public override void Expand(Span<Vector4> vectors) => Rec2020Companding.Expand(vectors);
/// <inheritdoc/>
public override Vector4 Compress(Vector4 vector) => Rec2020Companding.Compress(vector);
/// <inheritdoc/>
public override Vector4 Expand(Vector4 vector) => Rec2020Companding.Expand(vector);
}

18
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs → src/ImageSharp/ColorProfiles/WorkingSpaces/Rec709WorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
using System.Numerics;
using SixLabors.ImageSharp.ColorProfiles.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
/// <summary>
/// Rec. 709 (ITU-R Recommendation BT.709) working space.
@ -22,10 +22,14 @@ public sealed class Rec709WorkingSpace : RgbWorkingSpace
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Compress(float channel) => Rec709Companding.Compress(channel);
public override void Compress(Span<Vector4> vectors) => Rec709Companding.Compress(vectors);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Expand(float channel) => Rec709Companding.Expand(channel);
public override void Expand(Span<Vector4> vectors) => Rec709Companding.Expand(vectors);
/// <inheritdoc/>
public override Vector4 Compress(Vector4 vector) => Rec709Companding.Compress(vector);
/// <inheritdoc/>
public override Vector4 Expand(Vector4 vector) => Rec709Companding.Expand(vector);
}

40
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs → src/ImageSharp/ColorProfiles/WorkingSpaces/RgbWorkingSpace.cs

@ -1,7 +1,9 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
using System.Numerics;
namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
/// <summary>
/// Base class for all implementations of <see cref="RgbWorkingSpace"/>.
@ -30,26 +32,30 @@ public abstract class RgbWorkingSpace
public RgbPrimariesChromaticityCoordinates ChromaticityCoordinates { get; }
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// Compresses the linear vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public abstract void Compress(Span<Vector4> vectors);
/// <summary>
/// Expands the nonlinear vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public abstract void Expand(Span<Vector4> vectors);
/// <summary>
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <remarks>
/// For more info see:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// </remarks>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
public abstract float Expand(float channel);
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public abstract Vector4 Compress(Vector4 vector);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent (depends on the RGB color system).
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <remarks>
/// For more info see:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
public abstract float Compress(float channel);
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public abstract Vector4 Expand(Vector4 vector);
/// <inheritdoc/>
public override bool Equals(object? obj)

18
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs → src/ImageSharp/ColorProfiles/WorkingSpaces/SRgbWorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
using System.Numerics;
using SixLabors.ImageSharp.ColorProfiles.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
/// <summary>
/// The sRgb working space.
@ -22,10 +22,14 @@ public sealed class SRgbWorkingSpace : RgbWorkingSpace
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Compress(float channel) => SRgbCompanding.Compress(channel);
public override void Compress(Span<Vector4> vectors) => SRgbCompanding.Compress(vectors);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Expand(float channel) => SRgbCompanding.Expand(channel);
public override void Expand(Span<Vector4> vectors) => SRgbCompanding.Expand(vectors);
/// <inheritdoc/>
public override Vector4 Compress(Vector4 vector) => SRgbCompanding.Compress(vector);
/// <inheritdoc/>
public override Vector4 Expand(Vector4 vector) => SRgbCompanding.Expand(vector);
}

87
src/ImageSharp/ColorSpaces/YCbCr.cs → src/ImageSharp/ColorProfiles/YCbCr.cs

@ -3,15 +3,17 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents an YCbCr (luminance, blue chroma, red chroma) color as defined in the ITU-T T.871 specification for the JFIF use with Jpeg.
/// <see href="http://en.wikipedia.org/wiki/YCbCr"/>
/// <see href="http://www.ijg.org/files/T-REC-T.871-201105-I!!PDF-E.pdf"/>
/// </summary>
public readonly struct YCbCr : IEquatable<YCbCr>
[StructLayout(LayoutKind.Sequential)]
public readonly struct YCbCr : IColorProfile<YCbCr, Rgb>
{
private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = new(255);
@ -22,7 +24,7 @@ public readonly struct YCbCr : IEquatable<YCbCr>
/// <param name="y">The y luminance component.</param>
/// <param name="cb">The cb chroma component.</param>
/// <param name="cr">The cr chroma component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public YCbCr(float y, float cb, float cr)
: this(new Vector3(y, cb, cr))
{
@ -32,7 +34,7 @@ public readonly struct YCbCr : IEquatable<YCbCr>
/// Initializes a new instance of the <see cref="YCbCr"/> struct.
/// </summary>
/// <param name="vector">The vector representing the y, cb, cr components.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public YCbCr(Vector3 vector)
{
vector = Vector3.Clamp(vector, Min, Max);
@ -45,19 +47,19 @@ public readonly struct YCbCr : IEquatable<YCbCr>
/// Gets the Y luminance component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public readonly float Y { get; }
public float Y { get; }
/// <summary>
/// Gets the Cb chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public readonly float Cb { get; }
public float Cb { get; }
/// <summary>
/// Gets the Cr chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public readonly float Cr { get; }
public float Cr { get; }
/// <summary>
/// Compares two <see cref="YCbCr"/> objects for equality.
@ -77,11 +79,70 @@ public readonly struct YCbCr : IEquatable<YCbCr>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(YCbCr left, YCbCr right) => !left.Equals(right);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public static YCbCr FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source)
{
Vector3 rgb = source.ToScaledVector3() * Max;
float r = rgb.X;
float g = rgb.Y;
float b = rgb.Z;
float y = (0.299F * r) + (0.587F * g) + (0.114F * b);
float cb = 128F + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b));
float cr = 128F + ((0.5F * r) - (0.418688F * g) - (0.081312F * b));
return new YCbCr(y, cb, cr);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Rgb> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
// TODO: We can optimize this by using SIMD
for (int i = 0; i < source.Length; i++)
{
Rgb rgb = source[i];
destination[i] = FromProfileConnectingSpace(options, in rgb);
}
}
/// <inheritdoc/>
public Rgb ToProfileConnectingSpace(ColorConversionOptions options)
{
float y = this.Y;
float cb = this.Cb - 128F;
float cr = this.Cr - 128F;
float r = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero);
float g = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero);
float b = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero);
return Rgb.FromScaledVector3(new Vector3(r, g, b) / Max);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<YCbCr> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
// TODO: We can optimize this by using SIMD
for (int i = 0; i < source.Length; i++)
{
YCbCr ycbcr = source[i];
destination[i] = ycbcr.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.RgbWorkingSpace;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => HashCode.Combine(this.Y, this.Cb, this.Cr);
/// <inheritdoc/>
@ -91,9 +152,9 @@ public readonly struct YCbCr : IEquatable<YCbCr>
public override bool Equals(object? obj) => obj is YCbCr other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(YCbCr other)
=> this.Y.Equals(other.Y)
&& this.Cb.Equals(other.Cb)
&& this.Cr.Equals(other.Cr);
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<YCbCr, Vector3>(ref Unsafe.AsRef(in this));
}

135
src/ImageSharp/ColorSpaces/CieLab.cs

@ -1,135 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces;
/// <summary>
/// Represents a CIE L*a*b* 1976 color.
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space"/>
/// </summary>
public readonly struct CieLab : IEquatable<CieLab>
{
/// <summary>
/// D50 standard illuminant.
/// Used when reference white is not specified explicitly.
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D50;
/// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="a">The a (green - magenta) component.</param>
/// <param name="b">The b (blue - yellow) component.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLab(float l, float a, float b)
: this(l, a, b, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="a">The a (green - magenta) component.</param>
/// <param name="b">The b (blue - yellow) component.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLab(float l, float a, float b, CieXyz whitePoint)
: this(new Vector3(l, a, b), whitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, a, b components.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLab(Vector3 vector)
: this(vector, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, a, b components.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLab(Vector3 vector, CieXyz whitePoint)
: this()
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.L = vector.X;
this.A = vector.Y;
this.B = vector.Z;
this.WhitePoint = whitePoint;
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public readonly float L { get; }
/// <summary>
/// Gets the a color component.
/// <remarks>A value usually ranging from -100 to 100. Negative is green, positive magenta.</remarks>
/// </summary>
public readonly float A { get; }
/// <summary>
/// Gets the b color component.
/// <remarks>A value usually ranging from -100 to 100. Negative is blue, positive is yellow</remarks>
/// </summary>
public readonly float B { get; }
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public readonly CieXyz WhitePoint { get; }
/// <summary>
/// Compares two <see cref="CieLab"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="CieLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(CieLab left, CieLab right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="CieLab"/> objects for inequality
/// </summary>
/// <param name="left">The <see cref="CieLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(CieLab left, CieLab right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B, this.WhitePoint);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is CieLab other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieLab other) =>
this.L.Equals(other.L)
&& this.A.Equals(other.A)
&& this.B.Equals(other.B)
&& this.WhitePoint.Equals(other.WhitePoint);
}

156
src/ImageSharp/ColorSpaces/CieLchuv.cs

@ -1,156 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces;
/// <summary>
/// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color.
/// <see href="https://en.wikipedia.org/wiki/CIELAB_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC"/>
/// </summary>
public readonly struct CieLchuv : IEquatable<CieLchuv>
{
private static readonly Vector3 Min = new(0, -200, 0);
private static readonly Vector3 Max = new(100, 200, 360);
/// <summary>
/// D50 standard illuminant.
/// Used when reference white is not specified explicitly.
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D65;
/// <summary>
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="c">The chroma, relative saturation.</param>
/// <param name="h">The hue in degrees.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLchuv(float l, float c, float h)
: this(l, c, h, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="c">The chroma, relative saturation.</param>
/// <param name="h">The hue in degrees.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLchuv(float l, float c, float h, CieXyz whitePoint)
: this(new Vector3(l, c, h), whitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, c, h components.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLchuv(Vector3 vector)
: this(vector, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, c, h components.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLchuv(Vector3 vector, CieXyz whitePoint)
: this()
{
vector = Vector3.Clamp(vector, Min, Max);
this.L = vector.X;
this.C = vector.Y;
this.H = vector.Z;
this.WhitePoint = whitePoint;
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public readonly float L { get; }
/// <summary>
/// Gets the a chroma component.
/// <remarks>A value ranging from 0 to 200.</remarks>
/// </summary>
public readonly float C { get; }
/// <summary>
/// Gets the h° hue component in degrees.
/// <remarks>A value ranging from 0 to 360.</remarks>
/// </summary>
public readonly float H { get; }
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public readonly CieXyz WhitePoint { get; }
/// <summary>
/// Compares two <see cref="CieLchuv"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="CieLchuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLchuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(CieLchuv left, CieLchuv right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="CieLchuv"/> objects for inequality
/// </summary>
/// <param name="left">The <see cref="CieLchuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLchuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(CieLchuv left, CieLchuv right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.L, this.C, this.H, this.WhitePoint);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is CieLchuv other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieLchuv other)
=> this.L.Equals(other.L)
&& this.C.Equals(other.C)
&& this.H.Equals(other.H)
&& this.WhitePoint.Equals(other.WhitePoint);
/// <summary>
/// Computes the saturation of the color (chroma normalized by lightness)
/// </summary>
/// <remarks>
/// A value ranging from 0 to 100.
/// </remarks>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public float Saturation()
{
float result = 100 * (this.C / this.L);
if (float.IsNaN(result))
{
return 0;
}
return result;
}
}

136
src/ImageSharp/ColorSpaces/CieLuv.cs

@ -1,136 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces;
/// <summary>
/// The CIE 1976 (L*, u*, v*) color space, commonly known by its abbreviation CIELUV, is a color space adopted by the International
/// Commission on Illumination (CIE) in 1976, as a simple-to-compute transformation of the 1931 CIE XYZ color space, but which
/// attempted perceptual uniformity
/// <see href="https://en.wikipedia.org/wiki/CIELUV"/>
/// </summary>
public readonly struct CieLuv : IEquatable<CieLuv>
{
/// <summary>
/// D65 standard illuminant.
/// Used when reference white is not specified explicitly.
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D65;
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="u">The blue-yellow chromaticity coordinate of the given whitepoint.</param>
/// <param name="v">The red-green chromaticity coordinate of the given whitepoint.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLuv(float l, float u, float v)
: this(l, u, v, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="u">The blue-yellow chromaticity coordinate of the given whitepoint.</param>
/// <param name="v">The red-green chromaticity coordinate of the given whitepoint.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLuv(float l, float u, float v, CieXyz whitePoint)
: this(new Vector3(l, u, v), whitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, u, v components.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLuv(Vector3 vector)
: this(vector, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, u, v components.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLuv(Vector3 vector, CieXyz whitePoint)
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.L = vector.X;
this.U = vector.Y;
this.V = vector.Z;
this.WhitePoint = whitePoint;
}
/// <summary>
/// Gets the lightness dimension
/// <remarks>A value usually ranging between 0 and 100.</remarks>
/// </summary>
public readonly float L { get; }
/// <summary>
/// Gets the blue-yellow chromaticity coordinate of the given whitepoint.
/// <remarks>A value usually ranging between -100 and 100.</remarks>
/// </summary>
public readonly float U { get; }
/// <summary>
/// Gets the red-green chromaticity coordinate of the given whitepoint.
/// <remarks>A value usually ranging between -100 and 100.</remarks>
/// </summary>
public readonly float V { get; }
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public readonly CieXyz WhitePoint { get; }
/// <summary>
/// Compares two <see cref="CieLuv"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="CieLuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(CieLuv left, CieLuv right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="CieLuv"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="CieLuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(CieLuv left, CieLuv right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.L, this.U, this.V, this.WhitePoint);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is CieLuv other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieLuv other)
=> this.L.Equals(other.L)
&& this.U.Equals(other.U)
&& this.V.Equals(other.V)
&& this.WhitePoint.Equals(other.WhitePoint);
}

107
src/ImageSharp/ColorSpaces/Cmyk.cs

@ -1,107 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces;
/// <summary>
/// Represents an CMYK (cyan, magenta, yellow, keyline) color.
/// </summary>
public readonly struct Cmyk : IEquatable<Cmyk>
{
private static readonly Vector4 Min = Vector4.Zero;
private static readonly Vector4 Max = Vector4.One;
/// <summary>
/// Initializes a new instance of the <see cref="Cmyk"/> struct.
/// </summary>
/// <param name="c">The cyan component.</param>
/// <param name="m">The magenta component.</param>
/// <param name="y">The yellow component.</param>
/// <param name="k">The keyline black component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Cmyk(float c, float m, float y, float k)
: this(new Vector4(c, m, y, k))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Cmyk"/> struct.
/// </summary>
/// <param name="vector">The vector representing the c, m, y, k components.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Cmyk(Vector4 vector)
{
vector = Numerics.Clamp(vector, Min, Max);
this.C = vector.X;
this.M = vector.Y;
this.Y = vector.Z;
this.K = vector.W;
}
/// <summary>
/// Gets the cyan color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float C { get; }
/// <summary>
/// Gets the magenta color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float M { get; }
/// <summary>
/// Gets the yellow color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Y { get; }
/// <summary>
/// Gets the keyline black color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float K { get; }
/// <summary>
/// Compares two <see cref="Cmyk"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Cmyk"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Cmyk"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Cmyk left, Cmyk right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Cmyk"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="Cmyk"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Cmyk"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Cmyk left, Cmyk right) => !left.Equals(right);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => HashCode.Combine(this.C, this.M, this.Y, this.K);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is Cmyk other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Cmyk other)
=> this.C.Equals(other.C)
&& this.M.Equals(other.M)
&& this.Y.Equals(other.Y)
&& this.K.Equals(other.K);
}

34
src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs

@ -1,34 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Companding;
/// <summary>
/// Implements gamma companding.
/// </summary>
/// <remarks>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public static class GammaCompanding
{
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <param name="gamma">The gamma value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel, float gamma) => MathF.Pow(channel, gamma);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <param name="gamma">The gamma value.</param>
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel, float gamma) => MathF.Pow(channel, 1 / gamma);
}

36
src/ImageSharp/ColorSpaces/Companding/LCompanding.cs

@ -1,36 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorSpaces.Companding;
/// <summary>
/// Implements L* companding.
/// </summary>
/// <remarks>
/// For more info see:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public static class LCompanding
{
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel)
=> channel <= 0.08F ? (100F * channel) / CieConstants.Kappa : Numerics.Pow3((channel + 0.16F) / 1.16F);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
/// </summary>
/// <param name="channel">The channel value</param>
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel)
=> channel <= CieConstants.Epsilon ? (channel * CieConstants.Kappa) / 100F : (1.16F * MathF.Pow(channel, 0.3333333F)) - 0.16F;
}

39
src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs

@ -1,39 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Companding;
/// <summary>
/// Implements Rec. 2020 companding function.
/// </summary>
/// <remarks>
/// <see href="http://en.wikipedia.org/wiki/Rec._2020"/>
/// </remarks>
public static class Rec2020Companding
{
private const float Alpha = 1.09929682680944F;
private const float AlphaMinusOne = Alpha - 1F;
private const float Beta = 0.018053968510807F;
private const float InverseBeta = Beta * 4.5F;
private const float Epsilon = 1 / 0.45F;
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel)
=> channel < InverseBeta ? channel / 4.5F : MathF.Pow((channel + AlphaMinusOne) / Alpha, Epsilon);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel)
=> channel < Beta ? 4.5F * channel : (Alpha * MathF.Pow(channel, 0.45F)) - AlphaMinusOne;
}

35
src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs

@ -1,35 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Companding;
/// <summary>
/// Implements the Rec. 709 companding function.
/// </summary>
/// <remarks>
/// http://en.wikipedia.org/wiki/Rec._709
/// </remarks>
public static class Rec709Companding
{
private const float Epsilon = 1 / 0.45F;
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel)
=> channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, Epsilon);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel)
=> channel < 0.018F ? 4.5F * channel : (1.099F * MathF.Pow(channel, 0.45F)) - 0.099F;
}

230
src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs

@ -1,230 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace SixLabors.ImageSharp.ColorSpaces.Companding;
/// <summary>
/// Implements sRGB companding.
/// </summary>
/// <remarks>
/// For more info see:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public static class SRgbCompanding
{
private const int Length = Scale + 2; // 256kb @ 16bit precision.
private const int Scale = (1 << 16) - 1;
private static readonly Lazy<float[]> LazyCompressTable = new(
() =>
{
float[] result = new float[Length];
for (int i = 0; i < result.Length; i++)
{
double d = (double)i / Scale;
if (d <= (0.04045 / 12.92))
{
d *= 12.92;
}
else
{
d = (1.055 * Math.Pow(d, 1.0 / 2.4)) - 0.055;
}
result[i] = (float)d;
}
return result;
},
true);
private static readonly Lazy<float[]> LazyExpandTable = new(
() =>
{
float[] result = new float[Length];
for (int i = 0; i < result.Length; i++)
{
double d = (double)i / Scale;
if (d <= 0.04045)
{
d /= 12.92;
}
else
{
d = Math.Pow((d + 0.055) / 1.055, 2.4);
}
result[i] = (float)d;
}
return result;
},
true);
private static float[] ExpandTable => LazyExpandTable.Value;
private static float[] CompressTable => LazyCompressTable.Value;
/// <summary>
/// Expands the companded vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Expand(Span<Vector4> vectors)
{
if (Avx2.IsSupported && vectors.Length >= 2)
{
CompandAvx2(vectors, ExpandTable);
if (Numerics.Modulo2(vectors.Length) != 0)
{
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
Expand(ref MemoryMarshal.GetReference(vectors[^1..]));
}
}
else
{
CompandScalar(vectors, ExpandTable);
}
}
/// <summary>
/// Compresses the uncompanded vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void Compress(Span<Vector4> vectors)
{
if (Avx2.IsSupported && vectors.Length >= 2)
{
CompandAvx2(vectors, CompressTable);
if (Numerics.Modulo2(vectors.Length) != 0)
{
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
Compress(ref MemoryMarshal.GetReference(vectors[^1..]));
}
}
else
{
CompandScalar(vectors, CompressTable);
}
}
/// <summary>
/// Expands a companded vector to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Expand(ref Vector4 vector)
{
// Alpha is already a linear representation of opacity so we do not want to convert it.
vector.X = Expand(vector.X);
vector.Y = Expand(vector.Y);
vector.Z = Expand(vector.Z);
}
/// <summary>
/// Compresses an uncompanded vector (linear) to its nonlinear equivalent.
/// </summary>
/// <param name="vector">The vector.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Compress(ref Vector4 vector)
{
// Alpha is already a linear representation of opacity so we do not want to convert it.
vector.X = Compress(vector.X);
vector.Y = Compress(vector.Y);
vector.Z = Compress(vector.Z);
}
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Expand(float channel)
=> channel <= 0.04045F ? channel / 12.92F : MathF.Pow((channel + 0.055F) / 1.055F, 2.4F);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Compress(float channel)
=> channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void CompandAvx2(Span<Vector4> vectors, float[] table)
{
fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
{
var scale = Vector256.Create((float)Scale);
Vector256<float> zero = Vector256<float>.Zero;
var offset = Vector256.Create(1);
// Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float>
ref Vector256<float> vectorsBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(vectors));
ref Vector256<float> vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length / 2u);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
{
Vector256<float> multiplied = Avx.Multiply(scale, vectorsBase);
multiplied = Avx.Min(Avx.Max(zero, multiplied), scale);
Vector256<int> truncated = Avx.ConvertToVector256Int32WithTruncation(multiplied);
Vector256<float> truncatedF = Avx.ConvertToVector256Single(truncated);
Vector256<float> low = Avx2.GatherVector256(tablePointer, truncated, sizeof(float));
Vector256<float> high = Avx2.GatherVector256(tablePointer, Avx2.Add(truncated, offset), sizeof(float));
// Alpha is already a linear representation of opacity so we do not want to convert it.
Vector256<float> companded = Numerics.Lerp(low, high, Avx.Subtract(multiplied, truncatedF));
vectorsBase = Avx.Blend(companded, vectorsBase, Numerics.BlendAlphaControl);
vectorsBase = ref Unsafe.Add(ref vectorsBase, 1);
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void CompandScalar(Span<Vector4> vectors, float[] table)
{
fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
{
Vector4 zero = Vector4.Zero;
var scale = new Vector4(Scale);
ref Vector4 vectorsBase = ref MemoryMarshal.GetReference(vectors);
ref Vector4 vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
{
Vector4 multiplied = Numerics.Clamp(vectorsBase * Scale, zero, scale);
float f0 = multiplied.X;
float f1 = multiplied.Y;
float f2 = multiplied.Z;
uint i0 = (uint)f0;
uint i1 = (uint)f1;
uint i2 = (uint)f2;
// Alpha is already a linear representation of opacity so we do not want to convert it.
vectorsBase.X = Numerics.Lerp(tablePointer[i0], tablePointer[i0 + 1], f0 - (int)i0);
vectorsBase.Y = Numerics.Lerp(tablePointer[i1], tablePointer[i1 + 1], f1 - (int)i1);
vectorsBase.Z = Numerics.Lerp(tablePointer[i2], tablePointer[i2 + 1], f2 - (int)i2);
vectorsBase = ref Unsafe.Add(ref vectorsBase, 1);
}
}
}
}

159
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs

@ -1,159 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Performs chromatic adaptation on the various color spaces.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Performs chromatic adaptation of given <see cref="CieXyz"/> color.
/// Target white point is <see cref="ColorSpaceConverterOptions.WhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <param name="sourceWhitePoint">The source white point.</param>
/// <returns>The adapted color</returns>
public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint) => this.Adapt(color, sourceWhitePoint, this.whitePoint);
/// <summary>
/// Performs chromatic adaptation of given <see cref="CieXyz"/> color.
/// Target white point is <see cref="ColorSpaceConverterOptions.WhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <param name="sourceWhitePoint">The source white point.</param>
/// <param name="targetWhitePoint">The target white point.</param>
/// <returns>The adapted color</returns>
public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint, in CieXyz targetWhitePoint)
{
if (!this.performChromaticAdaptation || sourceWhitePoint.Equals(targetWhitePoint))
{
return color;
}
// We know that chromaticAdaption is not null because performChromaticAdaption is checked
return this.chromaticAdaptation!.Transform(color, sourceWhitePoint, targetWhitePoint);
}
/// <summary>
/// Adapts <see cref="CieLab"/> color from the source white point to white point set in <see cref="ColorSpaceConverterOptions.TargetLabWhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public CieLab Adapt(in CieLab color)
{
if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint))
{
return color;
}
var xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Adapts <see cref="CieLch"/> color from the source white point to white point set in <see cref="ColorSpaceConverterOptions.TargetLabWhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public CieLch Adapt(in CieLch color)
{
if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint))
{
return color;
}
var labColor = this.ToCieLab(color);
return this.ToCieLch(labColor);
}
/// <summary>
/// Adapts <see cref="CieLchuv"/> color from the source white point to white point set in <see cref="ColorSpaceConverterOptions.TargetLabWhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public CieLchuv Adapt(in CieLchuv color)
{
if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint))
{
return color;
}
var luvColor = this.ToCieLuv(color);
return this.ToCieLchuv(luvColor);
}
/// <summary>
/// Adapts <see cref="CieLuv"/> color from the source white point to white point set in <see cref="ColorSpaceConverterOptions.TargetLuvWhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public CieLuv Adapt(in CieLuv color)
{
if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLuvWhitePoint))
{
return color;
}
var xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Adapts <see cref="HunterLab"/> color from the source white point to white point set in <see cref="ColorSpaceConverterOptions.TargetHunterLabWhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public HunterLab Adapt(in HunterLab color)
{
if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetHunterLabWhitePoint))
{
return color;
}
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Adapts a <see cref="LinearRgb"/> color from the source working space to working space set in <see cref="ColorSpaceConverterOptions.TargetRgbWorkingSpace"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public LinearRgb Adapt(in LinearRgb color)
{
if (!this.performChromaticAdaptation || color.WorkingSpace.Equals(this.targetRgbWorkingSpace))
{
return color;
}
// Conversion to XYZ
LinearRgbToCieXyzConverter converterToXYZ = GetLinearRgbToCieXyzConverter(color.WorkingSpace);
CieXyz unadapted = converterToXYZ.Convert(color);
// Adaptation
// We know that chromaticAdaption is not null because performChromaticAdaption is checked
CieXyz adapted = this.chromaticAdaptation!.Transform(unadapted, color.WorkingSpace.WhitePoint, this.targetRgbWorkingSpace.WhitePoint);
// Conversion back to RGB
return this.cieXyzToLinearRgbConverter.Convert(adapted);
}
/// <summary>
/// Adapts an <see cref="Rgb"/> color from the source working space to working space set in <see cref="ColorSpaceConverterOptions.TargetRgbWorkingSpace"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public Rgb Adapt(in Rgb color)
{
if (!this.performChromaticAdaptation)
{
return color;
}
var linearInput = ToLinearRgb(color);
LinearRgb linearOutput = this.Adapt(linearInput);
return ToRgb(linearOutput);
}
}

441
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs

@ -1,441 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="CieLab"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieLch color)
{
// Conversion (preserving white point)
CieLab unadapted = CieLchToCieLabConverter.Convert(color);
return this.Adapt(unadapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLab"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieXyz color)
{
CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetLabWhitePoint);
return this.cieXyzToCieLabConverter.Convert(adapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLab"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLab"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Cmyk color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Hsl color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Hsv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in LinearRgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Rgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLab"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in YCbCr color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
}

441
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs

@ -1,441 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="CieLch"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieLch"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in CieLab color)
{
CieLab adapted = this.Adapt(color);
return CieLabToCieLchConverter.Convert(adapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in CieLchuv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in CieLuv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in CieXyy color)
{
var xyzColor = ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLch"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in CieXyz color)
{
var labColor = this.ToCieLab(color);
return this.ToCieLch(labColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in Cmyk color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in Hsl color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in Hsv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in HunterLab color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in LinearRgb color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in Lms color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in Rgb color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in YCbCr color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
}

441
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs

@ -1,441 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="CieLchuv"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieLchuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieLuv color)
{
CieLuv adapted = this.Adapt(color);
return CieLuvToCieLchuvConverter.Convert(adapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieXyz color)
{
CieLuv luvColor = this.ToCieLuv(color);
return this.ToCieLchuv(luvColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Cmyk color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Hsl color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLchuv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Hsv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in LinearRgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Rgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in YCbCr color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
}

435
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs

@ -1,435 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="CieLuv"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLuv ToCieLuv(in CieLchuv color)
{
// Conversion (preserving white point)
CieLuv unadapted = CieLchuvToCieLuvConverter.Convert(color);
// Adaptation
return this.Adapt(unadapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in CieXyz color)
{
// Adaptation
CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetLuvWhitePoint);
// Conversion
return this.cieXyzToCieLuvConverter.Convert(adapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Cmyk color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Hsl color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Hsv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in LinearRgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Rgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in YCbCr color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
}

437
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs

@ -1,437 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="CieXyy"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public static CieXyy ToCieXyy(in CieXyz color) => CieXyzAndCieXyyConverter.Convert(color);
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<CieXyz> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in Cmyk color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(Hsl color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in Hsv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in LinearRgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in Rgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in YCbCr color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
}

458
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs

@ -1,458 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="CieXyz"/>.
/// </content>
public partial class ColorSpaceConverter
{
private static readonly ConcurrentDictionary<RgbWorkingSpace, LinearRgbToCieXyzConverter> ConverterCache = new();
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in CieLab color)
{
// Conversion
CieXyz unadapted = CieLabToCieXyzConverter.Convert(color);
// Adaptation
return this.Adapt(unadapted, color.WhitePoint);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in CieLch color)
{
// Conversion to Lab
CieLab labColor = CieLchToCieLabConverter.Convert(color);
// Conversion to XYZ (incl. adaptation)
return this.ToCieXyz(labColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in CieLchuv color)
{
// Conversion to Luv
CieLuv luvColor = CieLchuvToCieLuvConverter.Convert(color);
// Conversion to XYZ (incl. adaptation)
return this.ToCieXyz(luvColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieXyz"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in CieLuv color)
{
// Conversion
CieXyz unadapted = CieLuvToCieXyzConverter.Convert(color);
// Adaptation
return this.Adapt(unadapted, color.WhitePoint);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public static CieXyz ToCieXyz(in CieXyy color)
// Conversion
=> CieXyzAndCieXyyConverter.Convert(color);
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<CieXyy> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Cmyk color)
{
Rgb rgb = ToRgb(color);
return this.ToCieXyz(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Hsl color)
{
Rgb rgb = ToRgb(color);
return this.ToCieXyz(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Hsv color)
{
// Conversion
Rgb rgb = ToRgb(color);
return this.ToCieXyz(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in HunterLab color)
{
CieXyz unadapted = HunterLabToCieXyzConverter.Convert(color);
return this.Adapt(unadapted, color.WhitePoint);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in LinearRgb color)
{
// Conversion
LinearRgbToCieXyzConverter converter = GetLinearRgbToCieXyzConverter(color.WorkingSpace);
CieXyz unadapted = converter.Convert(color);
return this.Adapt(unadapted, color.WorkingSpace.WhitePoint);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Lms color)
=> this.cieXyzAndLmsConverter.Convert(color);
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieXyz"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Rgb color)
{
// Conversion
LinearRgb linear = RgbToLinearRgbConverter.Convert(color);
return this.ToCieXyz(linear);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieXyz"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieXyz"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in YCbCr color)
{
Rgb rgb = this.ToRgb(color);
return this.ToCieXyz(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieXyz"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Gets the correct converter for the given rgb working space.
/// </summary>
/// <param name="workingSpace">The source working space</param>
/// <returns>The <see cref="LinearRgbToCieXyzConverter"/></returns>
private static LinearRgbToCieXyzConverter GetLinearRgbToCieXyzConverter(RgbWorkingSpace workingSpace)
=> ConverterCache.GetOrAdd(workingSpace, (key) => new LinearRgbToCieXyzConverter(key));
}

437
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs

@ -1,437 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="Cmyk"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="Cmyk"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="Cmyk"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Cmyk"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="Cmyk"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieXyz color)
{
Rgb rgb = this.ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="Cmyk"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public static Cmyk ToCmyk(in Hsl color)
{
Rgb rgb = ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsl> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public static Cmyk ToCmyk(in Hsv color)
{
Rgb rgb = ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsv> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public static Cmyk ToCmyk(in LinearRgb color)
{
Rgb rgb = ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<LinearRgb> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors,</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public static Cmyk ToCmyk(in Rgb color) => CmykAndRgbConverter.Convert(color);
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Cmyk"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Rgb> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in YCbCr color)
{
Rgb rgb = this.ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
}

437
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs

@ -1,437 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="Hsl"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="Hsl"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="Hsl"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieXyz color)
{
Rgb rgb = this.ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="Hsl"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="Hsl"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public static Hsl ToHsl(in Cmyk color)
{
Rgb rgb = ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="Hsl"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Cmyk> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="Hsl"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public static Hsl ToHsl(in Hsv color)
{
Rgb rgb = ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="Hsl"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsv> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public static Hsl ToHsl(in LinearRgb color)
{
Rgb rgb = ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<LinearRgb> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="Hsl"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public static Hsl ToHsl(in Rgb color) => HslAndRgbConverter.Convert(color);
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Rgb> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in YCbCr color)
{
Rgb rgb = this.ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
}

437
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs

@ -1,437 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="Hsv"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieXyz color)
{
Rgb rgb = this.ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public static Hsv ToHsv(in Cmyk color)
{
Rgb rgb = ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Cmyk> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public static Hsv ToHsv(in Hsl color)
{
Rgb rgb = ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors.</param>
public static void Convert(ReadOnlySpan<Hsl> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public static Hsv ToHsv(in LinearRgb color)
{
Rgb rgb = ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<LinearRgb> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public static Hsv ToHsv(in Rgb color) => HsvAndRgbConverter.Convert(color);
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Rgb> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in YCbCr color)
{
Rgb rgb = this.ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
}

430
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs

@ -1,430 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="HunterLab"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="HunterLab"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieLab color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieLch color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieLchuv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieLuv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieXyy color)
{
var xyzColor = ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieXyz color)
{
CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetHunterLabWhitePoint);
return this.cieXyzToHunterLabConverter.Convert(adapted);
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in Cmyk color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in Hsl color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in Hsv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in LinearRgb color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in Lms color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="HunterLab"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in Rgb color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in YCbCr color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
}

429
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs

@ -1,429 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="LinearRgb"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public static void Convert(ReadOnlySpan<Cmyk> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public static void Convert(ReadOnlySpan<Hsl> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public static void Convert(ReadOnlySpan<Hsv> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Lms> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Rgb> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="LinearRgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieXyz color)
{
// Adaptation
CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetRgbWorkingSpace.WhitePoint);
// Conversion
return this.cieXyzToLinearRgbConverter.Convert(adapted);
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public static LinearRgb ToLinearRgb(in Cmyk color)
{
Rgb rgb = ToRgb(color);
return ToLinearRgb(rgb);
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public static LinearRgb ToLinearRgb(in Hsl color)
{
Rgb rgb = ToRgb(color);
return ToLinearRgb(rgb);
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public static LinearRgb ToLinearRgb(in Hsv color)
{
Rgb rgb = ToRgb(color);
return ToLinearRgb(rgb);
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="LinearRgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public static LinearRgb ToLinearRgb(in Rgb color)
=> RgbToLinearRgbConverter.Convert(color);
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in YCbCr color)
{
Rgb rgb = this.ToRgb(color);
return ToLinearRgb(rgb);
}
}

425
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs

@ -1,425 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="Lms"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in CieLab color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in CieLch color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in CieLchuv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in CieLuv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in CieXyy color)
{
var xyzColor = ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in CieXyz color) => this.cieXyzAndLmsConverter.Convert(color);
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in Cmyk color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in Hsl color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in Hsv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in HunterLab color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in LinearRgb color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in Rgb color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in YCbCr color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
}

419
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs

@ -1,419 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="Rgb"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Cmyk> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsv> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsl> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<LinearRgb> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieXyz color)
{
// Conversion
LinearRgb linear = this.ToLinearRgb(color);
// Compand
return ToRgb(linear);
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public static Rgb ToRgb(in Cmyk color) => CmykAndRgbConverter.Convert(color);
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public static Rgb ToRgb(in Hsv color) => HsvAndRgbConverter.Convert(color);
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public static Rgb ToRgb(in Hsl color) => HslAndRgbConverter.Convert(color);
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public static Rgb ToRgb(in LinearRgb color) => LinearRgbToRgbConverter.Convert(color);
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in YCbCr color)
{
// Conversion
Rgb rgb = YCbCrAndRgbConverter.Convert(color);
// Adaptation
return this.Adapt(rgb);
}
}

404
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs

@ -1,404 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="YCbCr"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="YCbCr"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Cmyk> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsl> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsv> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<LinearRgb> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Rgb> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = ToYCbCr(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieXyz color)
{
Rgb rgb = this.ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public static YCbCr ToYCbCr(in Cmyk color)
{
Rgb rgb = ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public static YCbCr ToYCbCr(in Hsl color)
{
Rgb rgb = ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public static YCbCr ToYCbCr(in Hsv color)
{
Rgb rgb = ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public static YCbCr ToYCbCr(in LinearRgb color)
{
Rgb rgb = ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public static YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color);
}

59
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs

@ -1,59 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Provides methods to allow the conversion of color values between different color spaces.
/// </summary>
public partial class ColorSpaceConverter
{
// Options.
private static readonly ColorSpaceConverterOptions DefaultOptions = new();
private readonly Matrix4x4 lmsAdaptationMatrix;
private readonly CieXyz whitePoint;
private readonly CieXyz targetLuvWhitePoint;
private readonly CieXyz targetLabWhitePoint;
private readonly CieXyz targetHunterLabWhitePoint;
private readonly RgbWorkingSpace targetRgbWorkingSpace;
private readonly IChromaticAdaptation? chromaticAdaptation;
private readonly bool performChromaticAdaptation;
private readonly CieXyzAndLmsConverter cieXyzAndLmsConverter;
private readonly CieXyzToCieLabConverter cieXyzToCieLabConverter;
private readonly CieXyzToCieLuvConverter cieXyzToCieLuvConverter;
private readonly CieXyzToHunterLabConverter cieXyzToHunterLabConverter;
private readonly CieXyzToLinearRgbConverter cieXyzToLinearRgbConverter;
/// <summary>
/// Initializes a new instance of the <see cref="ColorSpaceConverter"/> class.
/// </summary>
public ColorSpaceConverter()
: this(DefaultOptions)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ColorSpaceConverter"/> class.
/// </summary>
/// <param name="options">The configuration options.</param>
public ColorSpaceConverter(ColorSpaceConverterOptions options)
{
Guard.NotNull(options, nameof(options));
this.whitePoint = options.WhitePoint;
this.targetLuvWhitePoint = options.TargetLuvWhitePoint;
this.targetLabWhitePoint = options.TargetLabWhitePoint;
this.targetHunterLabWhitePoint = options.TargetHunterLabWhitePoint;
this.targetRgbWorkingSpace = options.TargetRgbWorkingSpace;
this.chromaticAdaptation = options.ChromaticAdaptation;
this.performChromaticAdaptation = this.chromaticAdaptation != null;
this.lmsAdaptationMatrix = options.LmsAdaptationMatrix;
this.cieXyzAndLmsConverter = new CieXyzAndLmsConverter(this.lmsAdaptationMatrix);
this.cieXyzToCieLabConverter = new CieXyzToCieLabConverter(this.targetLabWhitePoint);
this.cieXyzToCieLuvConverter = new CieXyzToCieLuvConverter(this.targetLuvWhitePoint);
this.cieXyzToHunterLabConverter = new CieXyzToHunterLabConverter(this.targetHunterLabWhitePoint);
this.cieXyzToLinearRgbConverter = new CieXyzToLinearRgbConverter(this.targetRgbWorkingSpace);
}
}

53
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs

@ -1,53 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Configuration options for the <see cref="ColorSpaceConverter"/> class.
/// </summary>
public class ColorSpaceConverterOptions
{
/// <summary>
/// Gets or sets the white point used for chromatic adaptation in conversions from/to XYZ color space.
/// When <value>default</value>, no adaptation will be performed.
/// Defaults to: <see cref="CieLuv.DefaultWhitePoint"/>.
/// </summary>
public CieXyz WhitePoint { get; set; } = CieLuv.DefaultWhitePoint;
/// <summary>
/// Gets or sets the white point used *when creating* Luv/LChuv colors. (Luv/LChuv colors on the input already contain the white point information)
/// Defaults to: <see cref="CieLuv.DefaultWhitePoint"/>.
/// </summary>
public CieXyz TargetLuvWhitePoint { get; set; } = CieLuv.DefaultWhitePoint;
/// <summary>
/// Gets or sets the white point used *when creating* Lab/LChab colors. (Lab/LChab colors on the input already contain the white point information)
/// Defaults to: <see cref="CieLab.DefaultWhitePoint"/>.
/// </summary>
public CieXyz TargetLabWhitePoint { get; set; } = CieLab.DefaultWhitePoint;
/// <summary>
/// Gets or sets the white point used *when creating* HunterLab colors. (HunterLab colors on the input already contain the white point information)
/// Defaults to: <see cref="HunterLab.DefaultWhitePoint"/>.
/// </summary>
public CieXyz TargetHunterLabWhitePoint { get; set; } = HunterLab.DefaultWhitePoint;
/// <summary>
/// Gets or sets the target working space used *when creating* RGB colors. (RGB colors on the input already contain the working space information)
/// Defaults to: <see cref="Rgb.DefaultWorkingSpace"/>.
/// </summary>
public RgbWorkingSpace TargetRgbWorkingSpace { get; set; } = Rgb.DefaultWorkingSpace;
/// <summary>
/// Gets or sets the chromatic adaptation method used. When <value>null</value>, no adaptation will be performed.
/// </summary>
public IChromaticAdaptation? ChromaticAdaptation { get; set; } = new VonKriesChromaticAdaptation();
/// <summary>
/// Gets or sets transformation matrix used in conversion to and from <see cref="Lms"/>.
/// </summary>
public Matrix4x4 LmsAdaptationMatrix { get; set; } = CieXyzAndLmsConverter.DefaultTransformationMatrix;
}

31
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs

@ -1,31 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieLch"/> to <see cref="CieLab"/>.
/// </summary>
internal static class CieLchToCieLabConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieLch"/> input to an instance of <see cref="CieLab"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieLab Convert(in CieLch input)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC
float l = input.L, c = input.C, hDegrees = input.H;
float hRadians = GeometryUtilities.DegreeToRadian(hDegrees);
float a = c * MathF.Cos(hRadians);
float b = c * MathF.Sin(hRadians);
return new CieLab(l, a, b, input.WhitePoint);
}
}

39
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs

@ -1,39 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieLab"/> to <see cref="CieLch"/>.
/// </summary>
internal static class CieLabToCieLchConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieLab"/> input to an instance of <see cref="CieLch"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieLch Convert(in CieLab input)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC
float l = input.L, a = input.A, b = input.B;
float c = MathF.Sqrt((a * a) + (b * b));
float hRadians = MathF.Atan2(b, a);
float hDegrees = GeometryUtilities.RadianToDegree(hRadians);
// Wrap the angle round at 360.
hDegrees %= 360;
// Make sure it's not negative.
while (hDegrees < 0)
{
hDegrees += 360;
}
return new CieLch(l, c, hDegrees, input.WhitePoint);
}
}

43
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs

@ -1,43 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieLab"/> to <see cref="CieXyz"/>.
/// </summary>
internal static class CieLabToCieXyzConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieLab"/> input to an instance of <see cref="CieXyz"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieXyz Convert(in CieLab input)
{
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
float l = input.L, a = input.A, b = input.B;
float fy = (l + 16) / 116F;
float fx = (a / 500F) + fy;
float fz = fy - (b / 200F);
float fx3 = Numerics.Pow3(fx);
float fz3 = Numerics.Pow3(fz);
float xr = fx3 > CieConstants.Epsilon ? fx3 : ((116F * fx) - 16F) / CieConstants.Kappa;
float yr = l > CieConstants.Kappa * CieConstants.Epsilon ? Numerics.Pow3((l + 16F) / 116F) : l / CieConstants.Kappa;
float zr = fz3 > CieConstants.Epsilon ? fz3 : ((116F * fz) - 16F) / CieConstants.Kappa;
Vector3 wxyz = new(input.WhitePoint.X, input.WhitePoint.Y, input.WhitePoint.Z);
// Avoids XYZ coordinates out range (restricted by 0 and XYZ reference white)
Vector3 xyzr = Vector3.Clamp(new Vector3(xr, yr, zr), Vector3.Zero, Vector3.One);
Vector3 xyz = xyzr * wxyz;
return new CieXyz(xyz);
}
}

31
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs

@ -1,31 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieLch"/> to <see cref="CieLab"/>.
/// </summary>
internal static class CieLchuvToCieLuvConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieLchuv"/> input to an instance of <see cref="CieLuv"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieLuv Convert(in CieLchuv input)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
float l = input.L, c = input.C, hDegrees = input.H;
float hRadians = GeometryUtilities.DegreeToRadian(hDegrees);
float u = c * MathF.Cos(hRadians);
float v = c * MathF.Sin(hRadians);
return new CieLuv(l, u, v, input.WhitePoint);
}
}

39
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs

@ -1,39 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieLab"/> to <see cref="CieLch"/>.
/// </summary>
internal static class CieLuvToCieLchuvConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieLuv"/> input to an instance of <see cref="CieLchuv"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieLchuv Convert(in CieLuv input)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
float l = input.L, a = input.U, b = input.V;
float c = MathF.Sqrt((a * a) + (b * b));
float hRadians = MathF.Atan2(b, a);
float hDegrees = GeometryUtilities.RadianToDegree(hRadians);
// Wrap the angle round at 360.
hDegrees %= 360;
// Make sure it's not negative.
while (hDegrees < 0)
{
hDegrees += 360;
}
return new CieLchuv(l, c, hDegrees, input.WhitePoint);
}
}

73
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs

@ -1,73 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieLuv"/> to <see cref="CieXyz"/>.
/// </summary>
internal static class CieLuvToCieXyzConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieLuv"/> input to an instance of <see cref="CieXyz"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
public static CieXyz Convert(in CieLuv input)
{
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html
float l = input.L, u = input.U, v = input.V;
float u0 = ComputeU0(input.WhitePoint);
float v0 = ComputeV0(input.WhitePoint);
float y = l > CieConstants.Kappa * CieConstants.Epsilon
? Numerics.Pow3((l + 16) / 116)
: l / CieConstants.Kappa;
float a = ((52 * l / (u + (13 * l * u0))) - 1) / 3;
float b = -5 * y;
const float c = -0.3333333F;
float d = y * ((39 * l / (v + (13 * l * v0))) - 5);
float x = (d - b) / (a - c);
float z = (x * a) + b;
if (float.IsNaN(x) || x < 0)
{
x = 0;
}
if (float.IsNaN(y) || y < 0)
{
y = 0;
}
if (float.IsNaN(z) || z < 0)
{
z = 0;
}
return new CieXyz(x, y, z);
}
/// <summary>
/// Calculates the blue-yellow chromacity based on the given whitepoint.
/// </summary>
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static float ComputeU0(in CieXyz input)
=> (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z));
/// <summary>
/// Calculates the red-green chromacity based on the given whitepoint.
/// </summary>
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static float ComputeV0(in CieXyz input)
=> (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z));
}

52
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs

@ -1,52 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between CIE XYZ and CIE xyY.
/// <see href="http://www.brucelindbloom.com/"/> for formulas.
/// </summary>
internal static class CieXyzAndCieXyyConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="CieXyy"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieXyy Convert(in CieXyz input)
{
float x = input.X / (input.X + input.Y + input.Z);
float y = input.Y / (input.X + input.Y + input.Z);
if (float.IsNaN(x) || float.IsNaN(y))
{
return new CieXyy(0, 0, input.Y);
}
return new CieXyy(x, y, input.Y);
}
/// <summary>
/// Performs the conversion from the <see cref="CieXyy"/> input to an instance of <see cref="CieXyz"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieXyz Convert(in CieXyy input)
{
if (MathF.Abs(input.Y) < Constants.Epsilon)
{
return new CieXyz(0, 0, input.Yl);
}
float x = (input.X * input.Yl) / input.Y;
float y = input.Yl;
float z = ((1 - input.X - input.Y) * y) / input.Y;
return new CieXyz(x, y, z);
}
}

44
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs

@ -1,44 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// The base class for converting between <see cref="HunterLab"/> and <see cref="CieXyz"/> color spaces.
/// </summary>
internal abstract class CieXyzAndHunterLabConverterBase
{
/// <summary>
/// Returns the Ka coefficient that depends upon the whitepoint illuminant.
/// </summary>
/// <param name="whitePoint">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float ComputeKa(CieXyz whitePoint)
{
if (whitePoint.Equals(Illuminants.C))
{
return 175F;
}
return 100F * (175F / 198.04F) * (whitePoint.X + whitePoint.Y);
}
/// <summary>
/// Returns the Kb coefficient that depends upon the whitepoint illuminant.
/// </summary>
/// <param name="whitePoint">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float ComputeKb(CieXyz whitePoint)
{
if (whitePoint == Illuminants.C)
{
return 70F;
}
return 100F * (70F / 218.11F) * (whitePoint.Y + whitePoint.Z);
}
}

69
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs

@ -1,69 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between <see cref="CieXyz"/> and <see cref="Lms"/>
/// </summary>
internal sealed class CieXyzAndLmsConverter
{
/// <summary>
/// Default transformation matrix used, when no other is set. (Bradford)
/// <see cref="LmsAdaptationMatrix"/>
/// </summary>
public static readonly Matrix4x4 DefaultTransformationMatrix = LmsAdaptationMatrix.Bradford;
private Matrix4x4 inverseTransformationMatrix;
private Matrix4x4 transformationMatrix;
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzAndLmsConverter"/> class.
/// </summary>
public CieXyzAndLmsConverter()
: this(DefaultTransformationMatrix)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzAndLmsConverter"/> class.
/// </summary>
/// <param name="transformationMatrix">
/// Definition of the cone response domain (see <see cref="LmsAdaptationMatrix"/>),
/// if not set <see cref="DefaultTransformationMatrix"/> will be used.
/// </param>
public CieXyzAndLmsConverter(Matrix4x4 transformationMatrix)
{
this.transformationMatrix = transformationMatrix;
Matrix4x4.Invert(this.transformationMatrix, out this.inverseTransformationMatrix);
}
/// <summary>
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="Lms"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Lms Convert(in CieXyz input)
{
Vector3 vector = Vector3.Transform(input.ToVector3(), this.transformationMatrix);
return new Lms(vector);
}
/// <summary>
/// Performs the conversion from the <see cref="Lms"/> input to an instance of <see cref="CieXyz"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public CieXyz Convert(in Lms input)
{
Vector3 vector = Vector3.Transform(input.ToVector3(), this.inverseTransformationMatrix);
return new CieXyz(vector);
}
}

57
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs

@ -1,57 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieXyz"/> to <see cref="CieLab"/>.
/// </summary>
internal sealed class CieXyzToCieLabConverter
{
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToCieLabConverter"/> class.
/// </summary>
public CieXyzToCieLabConverter()
: this(CieLab.DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToCieLabConverter"/> class.
/// </summary>
/// <param name="labWhitePoint">The target reference lab white point</param>
public CieXyzToCieLabConverter(CieXyz labWhitePoint) => this.LabWhitePoint = labWhitePoint;
/// <summary>
/// Gets the target reference whitepoint. When not set, <see cref="CieLab.DefaultWhitePoint"/> is used.
/// </summary>
public CieXyz LabWhitePoint { get; }
/// <summary>
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="CieLab"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLab Convert(in CieXyz input)
{
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html
float wx = this.LabWhitePoint.X, wy = this.LabWhitePoint.Y, wz = this.LabWhitePoint.Z;
float xr = input.X / wx, yr = input.Y / wy, zr = input.Z / wz;
const float inv116 = 1 / 116F;
float fx = xr > CieConstants.Epsilon ? MathF.Pow(xr, 0.3333333F) : ((CieConstants.Kappa * xr) + 16F) * inv116;
float fy = yr > CieConstants.Epsilon ? MathF.Pow(yr, 0.3333333F) : ((CieConstants.Kappa * yr) + 16F) * inv116;
float fz = zr > CieConstants.Epsilon ? MathF.Pow(zr, 0.3333333F) : ((CieConstants.Kappa * zr) + 16F) * inv116;
float l = (116F * fy) - 16F;
float a = 500F * (fx - fy);
float b = 200F * (fy - fz);
return new CieLab(l, a, b, this.LabWhitePoint);
}
}

86
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs

@ -1,86 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieXyz"/> to <see cref="CieLuv"/>.
/// </summary>
internal sealed class CieXyzToCieLuvConverter
{
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToCieLuvConverter"/> class.
/// </summary>
public CieXyzToCieLuvConverter()
: this(CieLuv.DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToCieLuvConverter"/> class.
/// </summary>
/// <param name="luvWhitePoint">The target reference luv white point</param>
public CieXyzToCieLuvConverter(CieXyz luvWhitePoint) => this.LuvWhitePoint = luvWhitePoint;
/// <summary>
/// Gets the target reference whitepoint. When not set, <see cref="CieLuv.DefaultWhitePoint"/> is used.
/// </summary>
public CieXyz LuvWhitePoint { get; }
/// <summary>
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="CieLuv"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
public CieLuv Convert(in CieXyz input)
{
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html
float yr = input.Y / this.LuvWhitePoint.Y;
float up = ComputeUp(input);
float vp = ComputeVp(input);
float upr = ComputeUp(this.LuvWhitePoint);
float vpr = ComputeVp(this.LuvWhitePoint);
float l = yr > CieConstants.Epsilon ? ((116 * MathF.Pow(yr, 0.3333333F)) - 16F) : (CieConstants.Kappa * yr);
if (float.IsNaN(l) || l < 0)
{
l = 0;
}
float u = 13 * l * (up - upr);
float v = 13 * l * (vp - vpr);
if (float.IsNaN(u))
{
u = 0;
}
if (float.IsNaN(v))
{
v = 0;
}
return new CieLuv(l, u, v, this.LuvWhitePoint);
}
/// <summary>
/// Calculates the blue-yellow chromacity based on the given whitepoint.
/// </summary>
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ComputeUp(in CieXyz input)
=> (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z));
/// <summary>
/// Calculates the red-green chromacity based on the given whitepoint.
/// </summary>
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static float ComputeVp(in CieXyz input)
=> (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z));
}

65
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs

@ -1,65 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between <see cref="CieXyz"/> and <see cref="HunterLab"/>
/// </summary>
internal sealed class CieXyzToHunterLabConverter : CieXyzAndHunterLabConverterBase
{
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToHunterLabConverter"/> class.
/// </summary>
public CieXyzToHunterLabConverter()
: this(HunterLab.DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToHunterLabConverter"/> class.
/// </summary>
/// <param name="labWhitePoint">The hunter Lab white point.</param>
public CieXyzToHunterLabConverter(CieXyz labWhitePoint) => this.HunterLabWhitePoint = labWhitePoint;
/// <summary>
/// Gets the target reference white. When not set, <see cref="HunterLab.DefaultWhitePoint"/> is used.
/// </summary>
public CieXyz HunterLabWhitePoint { get; }
/// <summary>
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="HunterLab"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public HunterLab Convert(in CieXyz input)
{
// Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab
float x = input.X, y = input.Y, z = input.Z;
float xn = this.HunterLabWhitePoint.X, yn = this.HunterLabWhitePoint.Y, zn = this.HunterLabWhitePoint.Z;
float ka = ComputeKa(this.HunterLabWhitePoint);
float kb = ComputeKb(this.HunterLabWhitePoint);
float yByYn = y / yn;
float sqrtYbyYn = MathF.Sqrt(yByYn);
float l = 100 * sqrtYbyYn;
float a = ka * (((x / xn) - yByYn) / sqrtYbyYn);
float b = kb * ((yByYn - (z / zn)) / sqrtYbyYn);
if (float.IsNaN(a))
{
a = 0;
}
if (float.IsNaN(b))
{
b = 0;
}
return new HunterLab(l, a, b, this.HunterLabWhitePoint);
}
}

55
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs

@ -1,55 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between <see cref="CieXyz"/> and <see cref="LinearRgb"/>
/// </summary>
internal sealed class CieXyzToLinearRgbConverter : LinearRgbAndCieXyzConverterBase
{
private readonly Matrix4x4 conversionMatrix;
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToLinearRgbConverter"/> class.
/// </summary>
public CieXyzToLinearRgbConverter()
: this(Rgb.DefaultWorkingSpace)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToLinearRgbConverter"/> class.
/// </summary>
/// <param name="workingSpace">The target working space.</param>
public CieXyzToLinearRgbConverter(RgbWorkingSpace workingSpace)
{
this.TargetWorkingSpace = workingSpace;
// Gets the inverted Rgb -> Xyz matrix
Matrix4x4.Invert(GetRgbToCieXyzMatrix(workingSpace), out Matrix4x4 inverted);
this.conversionMatrix = inverted;
}
/// <summary>
/// Gets the target working space.
/// </summary>
public RgbWorkingSpace TargetWorkingSpace { get; }
/// <summary>
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="LinearRgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public LinearRgb Convert(in CieXyz input)
{
var vector = Vector3.Transform(input.ToVector3(), this.conversionMatrix);
return new LinearRgb(vector, this.TargetWorkingSpace);
}
}

49
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs

@ -1,49 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between <see cref="Cmyk"/> and <see cref="Rgb"/>.
/// </summary>
internal static class CmykAndRgbConverter
{
/// <summary>
/// Performs the conversion from the <see cref="Cmyk"/> input to an instance of <see cref="Rgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Rgb Convert(in Cmyk input)
{
Vector3 rgb = (Vector3.One - new Vector3(input.C, input.M, input.Y)) * (Vector3.One - new Vector3(input.K));
return new Rgb(rgb);
}
/// <summary>
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="Cmyk"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Cmyk Convert(in Rgb input)
{
// To CMY
Vector3 cmy = Vector3.One - input.ToVector3();
// To CMYK
Vector3 k = new(MathF.Min(cmy.X, MathF.Min(cmy.Y, cmy.Z)));
if (MathF.Abs(k.X - 1F) < Constants.Epsilon)
{
return new Cmyk(0, 0, 0, 1F);
}
cmy = (cmy - k) / (Vector3.One - k);
return new Cmyk(cmy.X, cmy.Y, cmy.Z, k.X);
}
}

158
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs

@ -1,158 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between HSL and Rgb
/// See <see href="http://www.poynton.com/PDFs/coloureq.pdf"/> for formulas.
/// </summary>
internal static class HslAndRgbConverter
{
/// <summary>
/// Performs the conversion from the <see cref="Hsl"/> input to an instance of <see cref="Rgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Rgb Convert(in Hsl input)
{
float rangedH = input.H / 360F;
float r = 0;
float g = 0;
float b = 0;
float s = input.S;
float l = input.L;
if (MathF.Abs(l) > Constants.Epsilon)
{
if (MathF.Abs(s) < Constants.Epsilon)
{
r = g = b = l;
}
else
{
float temp2 = (l < .5F) ? l * (1F + s) : l + s - (l * s);
float temp1 = (2F * l) - temp2;
r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F);
g = GetColorComponent(temp1, temp2, rangedH);
b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F);
}
}
return new Rgb(r, g, b);
}
/// <summary>
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="Hsl"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Hsl Convert(in Rgb input)
{
float r = input.R;
float g = input.G;
float b = input.B;
float max = MathF.Max(r, MathF.Max(g, b));
float min = MathF.Min(r, MathF.Min(g, b));
float chroma = max - min;
float h = 0F;
float s = 0F;
float l = (max + min) / 2F;
if (MathF.Abs(chroma) < Constants.Epsilon)
{
return new Hsl(0F, s, l);
}
if (MathF.Abs(r - max) < Constants.Epsilon)
{
h = (g - b) / chroma;
}
else if (MathF.Abs(g - max) < Constants.Epsilon)
{
h = 2F + ((b - r) / chroma);
}
else if (MathF.Abs(b - max) < Constants.Epsilon)
{
h = 4F + ((r - g) / chroma);
}
h *= 60F;
if (h < 0F)
{
h += 360F;
}
if (l <= .5F)
{
s = chroma / (max + min);
}
else
{
s = chroma / (2F - max - min);
}
return new Hsl(h, s, l);
}
/// <summary>
/// Gets the color component from the given values.
/// </summary>
/// <param name="first">The first value.</param>
/// <param name="second">The second value.</param>
/// <param name="third">The third value.</param>
/// <returns>
/// The <see cref="float"/>.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static float GetColorComponent(float first, float second, float third)
{
third = MoveIntoRange(third);
if (third < 0.1666667F)
{
return first + ((second - first) * 6F * third);
}
if (third < .5F)
{
return second;
}
if (third < 0.6666667F)
{
return first + ((second - first) * (0.6666667F - third) * 6F);
}
return first;
}
/// <summary>
/// Moves the specific value within the acceptable range for
/// conversion.
/// <remarks>Used for converting <see cref="Hsl"/> colors to this type.</remarks>
/// </summary>
/// <param name="value">The value to shift.</param>
/// <returns>
/// The <see cref="float"/>.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static float MoveIntoRange(float value)
{
if (value < 0F)
{
value++;
}
else if (value > 1F)
{
value--;
}
return value;
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save